1 /*
2 * Copyright (c) 2019-2022 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 /*
30 * net_bridge.c
31 * - test if_bridge.c functionality
32 */
33
34 #include <darwintest.h>
35 #include <stdio.h>
36 #include <unistd.h>
37 #include <stddef.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <sys/socket.h>
41 #include <arpa/inet.h>
42 #include <sys/event.h>
43 #include <net/if.h>
44 #include <netinet/in.h>
45 #include <netinet6/in6_var.h>
46 #include <netinet6/nd6.h>
47 #include <netinet/in.h>
48 #include <netinet/ip.h>
49 #include <netinet/udp.h>
50 #include <netinet/bootp.h>
51 #include <netinet/tcp.h>
52 #include <netinet/if_ether.h>
53 #include <netinet/ip6.h>
54 #include <netinet/icmp6.h>
55 #include <net/if_arp.h>
56 #include <net/bpf.h>
57 #include <net/if_bridgevar.h>
58 #include <net/if_fake_var.h>
59 #include <sys/ioctl.h>
60 #include <sys/types.h>
61 #include <sys/stat.h>
62 #include <errno.h>
63 #include <pthread.h>
64 #include <stdbool.h>
65 #include <TargetConditionals.h>
66 #include <darwintest_utils.h>
67 #include "inet_transfer.h"
68 #include "bpflib.h"
69 #include "in_cksum.h"
70
71 static bool S_debug;
72 static bool S_cleaning_up;
73
74 #define ALL_ADDRS (uint32_t)(-1)
75
76 #define DHCP_PAYLOAD_MIN sizeof(struct bootp)
77 #define DHCP_FLAGS_BROADCAST ((u_short)0x8000)
78
79 typedef union {
80 char bytes[DHCP_PAYLOAD_MIN];
81 /* force 4-byte alignment */
82 uint32_t words[DHCP_PAYLOAD_MIN / sizeof(uint32_t)];
83 } dhcp_min_payload, *dhcp_min_payload_t;
84
85 #define ETHER_PKT_LEN (ETHER_HDR_LEN + ETHERMTU)
86 typedef union {
87 char bytes[ETHER_PKT_LEN];
88 /* force 4-byte aligment */
89 uint32_t words[ETHER_PKT_LEN / sizeof(uint32_t)];
90 } ether_packet, *ether_packet_t;
91
92 typedef struct {
93 struct ip ip;
94 struct udphdr udp;
95 } ip_udp_header_t;
96
97 typedef struct {
98 struct in_addr src_ip;
99 struct in_addr dst_ip;
100 char zero;
101 char proto;
102 unsigned short length;
103 } udp_pseudo_hdr_t;
104
105 typedef struct {
106 struct ip ip;
107 struct tcphdr tcp;
108 } ip_tcp_header_t;
109
110 typedef union {
111 ip_udp_header_t udp;
112 ip_tcp_header_t tcp;
113 } ip_udp_tcp_header_u;
114
115 typedef struct {
116 struct in_addr src_ip;
117 struct in_addr dst_ip;
118 char zero;
119 char proto;
120 unsigned short length;
121 } tcp_pseudo_hdr_t;
122
123 typedef struct {
124 struct ip6_hdr ip6;
125 struct udphdr udp;
126 } ip6_udp_header_t;
127
128 typedef struct {
129 struct in6_addr src_ip;
130 struct in6_addr dst_ip;
131 char zero;
132 char proto;
133 unsigned short length;
134 } udp6_pseudo_hdr_t;
135
136 typedef struct {
137 char ifname[IFNAMSIZ]; /* port we do I/O on */
138 ether_addr_t mac;
139 char member_ifname[IFNAMSIZ]; /* member of bridge */
140 ether_addr_t member_mac;
141 int fd;
142 u_int unit;
143 u_int num_addrs;
144 void * rx_buf;
145 int rx_buf_size;
146 bool mac_nat;
147 struct in_addr ip;
148 struct in6_addr ip6;
149 u_short if_index;
150
151 u_int test_count;
152 u_int test_address_count;
153 uint64_t test_address_present;
154 } switch_port, *switch_port_t;
155
156 typedef struct {
157 u_int size;
158 u_int count;
159 bool mac_nat;
160 switch_port list[1];
161 } switch_port_list, * switch_port_list_t;
162
163 static struct in_addr bridge_ip_addr;
164 static struct in6_addr bridge_ipv6_addr;
165 static u_short bridge_if_index;
166
167 static struct ifbareq *
168 bridge_rt_table_copy(u_int * ret_count);
169
170 static void
171 bridge_rt_table_log(struct ifbareq *rt_table, u_int count);
172
173 static struct ifbrmne *
174 bridge_mac_nat_entries_copy(u_int * ret_count);
175
176 static void
177 bridge_mac_nat_entries_log(struct ifbrmne * entries, u_int count);
178
179 static void
180 ifnet_get_lladdr(int s, const char * ifname, ether_addr_t * eaddr);
181
182 #define SETUP_FLAGS_MAC_NAT 0x1
183 #define SETUP_FLAGS_CHECKSUM_OFFLOAD 0x2
184 #define SETUP_FLAGS_ATTACH_STACK 0x4
185 #define SETUP_FLAGS_TRAILERS 0x8
186
187 #define s6_addr16 __u6_addr.__u6_addr16
188
189 static int
inet_dgram_socket(void)190 inet_dgram_socket(void)
191 {
192 int s;
193
194 s = socket(AF_INET, SOCK_DGRAM, 0);
195 T_QUIET;
196 T_ASSERT_POSIX_SUCCESS(s, "socket(AF_INET, SOCK_DGRAM, 0)");
197 return s;
198 }
199
200 static int
inet6_dgram_socket(void)201 inet6_dgram_socket(void)
202 {
203 int s;
204
205 s = socket(AF_INET6, SOCK_DGRAM, 0);
206 T_QUIET;
207 T_ASSERT_POSIX_SUCCESS(s, "socket(AF_INET6, SOCK_DGRAM, 0)");
208 return s;
209 }
210
211 static int
routing_socket(void)212 routing_socket(void)
213 {
214 int s;
215
216 s = socket(PF_ROUTE, SOCK_RAW, PF_ROUTE);
217 T_QUIET;
218 T_ASSERT_POSIX_SUCCESS(s, "socket(PF_ROUTE, SOCK_RAW, PF_ROUTE)");
219 return s;
220 }
221
222
223 /**
224 ** Packet creation/display
225 **/
226 #define BOOTP_SERVER_PORT 67
227 #define BOOTP_CLIENT_PORT 68
228
229 #define TEST_SOURCE_PORT 14
230 #define TEST_DEST_PORT 15
231
232 #define EA_UNIT_INDEX 4
233 #define EA_ADDR_INDEX 5
234
235 static void
set_ethernet_address(ether_addr_t * eaddr,u_int unit,u_int addr_index)236 set_ethernet_address(ether_addr_t *eaddr, u_int unit, u_int addr_index)
237 {
238 u_char *a = eaddr->octet;
239
240 a[0] = 0x02;
241 a[2] = 0x00;
242 a[3] = 0x00;
243 a[1] = 0x00;
244 a[EA_UNIT_INDEX] = (u_char)unit;
245 a[EA_ADDR_INDEX] = (u_char)addr_index;
246 }
247
248 #define TEN_NET 0x0a000000
249 #define TEN_1_NET (TEN_NET | 0x010000)
250
251 static void
get_ipv4_address(u_int unit,u_int addr_index,struct in_addr * ip)252 get_ipv4_address(u_int unit, u_int addr_index, struct in_addr *ip)
253 {
254 /* up to 255 units, 255 addresses */
255 ip->s_addr = htonl(TEN_1_NET | (unit << 8) | addr_index);
256 return;
257 }
258
259 #define IN6ADDR_ULA_INIT \
260 {{{ 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
261 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}}
262
263 static struct in6_addr ula_address = IN6ADDR_ULA_INIT;
264
265 #define ULA_UNIT_INDEX 14
266 #define ULA_ADDR_INDEX 15
267
268 static void
get_ipv6_ula_address(u_int unit,u_int addr_index,struct in6_addr * ip)269 get_ipv6_ula_address(u_int unit, u_int addr_index, struct in6_addr *ip)
270 {
271 *ip = ula_address;
272 /* up to 255 units, 255 addresses */
273 ip->s6_addr[ULA_UNIT_INDEX] = (uint8_t)unit;
274 ip->s6_addr[ULA_ADDR_INDEX] = (uint8_t)addr_index;
275 }
276
277 #define ND6_EUI64_GBIT 0x01
278 #define ND6_EUI64_UBIT 0x02
279
280 #define ND6_EUI64_TO_IFID(in6) \
281 do {(in6)->s6_addr[8] ^= ND6_EUI64_UBIT; } while (0)
282 static void
get_ipv6_ll_address(const ether_addr_t * mac,struct in6_addr * in6)283 get_ipv6_ll_address(const ether_addr_t *mac, struct in6_addr * in6)
284 {
285 const u_char * addr = mac->octet;
286
287 bzero(in6, sizeof(*in6));
288 in6->s6_addr16[0] = htons(0xfe80);
289 in6->s6_addr[8] = addr[0];
290 in6->s6_addr[9] = addr[1];
291 in6->s6_addr[10] = addr[2];
292 in6->s6_addr[11] = 0xff;
293 in6->s6_addr[12] = 0xfe;
294 in6->s6_addr[13] = addr[3];
295 in6->s6_addr[14] = addr[4];
296 in6->s6_addr[15] = addr[5];
297 ND6_EUI64_TO_IFID(in6);
298 return;
299 }
300
301 static void
get_ip_address(uint8_t af,u_int unit,u_int addr_index,union ifbrip * ip)302 get_ip_address(uint8_t af, u_int unit, u_int addr_index, union ifbrip *ip)
303 {
304 switch (af) {
305 case AF_INET:
306 get_ipv4_address(unit, addr_index, &ip->ifbrip_addr);
307 break;
308 case AF_INET6:
309 get_ipv6_ula_address(unit, addr_index, &ip->ifbrip_addr6);
310 break;
311 default:
312 T_FAIL("unrecognized address family %u", af);
313 break;
314 }
315 }
316
317 static bool
ip_addresses_are_equal(uint8_t af,union ifbrip * ip1,union ifbrip * ip2)318 ip_addresses_are_equal(uint8_t af, union ifbrip * ip1, union ifbrip * ip2)
319 {
320 bool equal;
321
322 switch (af) {
323 case AF_INET:
324 equal = (ip1->ifbrip_addr.s_addr == ip2->ifbrip_addr.s_addr);
325 break;
326 case AF_INET6:
327 equal = IN6_ARE_ADDR_EQUAL(&ip1->ifbrip_addr6,
328 &ip2->ifbrip_addr6);
329 break;
330 default:
331 T_FAIL("unrecognized address family %u", af);
332 equal = false;
333 break;
334 }
335 return equal;
336 }
337
338 static ether_addr_t ether_broadcast = {
339 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
340 };
341
342 static ether_addr_t ether_external = {
343 { 0x80, 0x00, 0x00, 0x00, 0x00, 0x01 }
344 };
345
346 static inline struct in_addr
get_external_ipv4_address(void)347 get_external_ipv4_address(void)
348 {
349 struct in_addr ip;
350
351 /* IP 10.1.255.1 */
352 ip.s_addr = htonl(TEN_1_NET | 0xff01);
353 return ip;
354 }
355
356 static inline void
get_external_ip_address(uint8_t af,union ifbrip * ip)357 get_external_ip_address(uint8_t af, union ifbrip * ip)
358 {
359 switch (af) {
360 case AF_INET:
361 /* IP 10.1.255.1 */
362 ip->ifbrip_addr = get_external_ipv4_address();
363 break;
364 case AF_INET6:
365 /* fd80::1 */
366 ip->ifbrip_addr6 = ula_address;
367 ip->ifbrip_addr6.s6_addr[1] = 0x80;
368 ip->ifbrip_addr6.s6_addr[15] = 0x01;
369 break;
370 default:
371 T_FAIL("unrecognized address family %u", af);
372 break;
373 }
374 }
375
376 static inline void
get_broadcast_ip_address(uint8_t af,union ifbrip * ip)377 get_broadcast_ip_address(uint8_t af, union ifbrip * ip)
378 {
379 switch (af) {
380 case AF_INET:
381 ip->ifbrip_addr.s_addr = INADDR_BROADCAST;
382 break;
383 case AF_INET6:
384 /* 0xff0e::0 linklocal scope multicast */
385 ip->ifbrip_addr6 = in6addr_any;
386 ip->ifbrip_addr6.s6_addr[0] = 0xff;
387 ip->ifbrip_addr6.s6_addr[1] = __IPV6_ADDR_SCOPE_LINKLOCAL;
388 break;
389 default:
390 T_FAIL("unrecognized address family %u", af);
391 break;
392 }
393 }
394 static void
siocaifaddr(int s,char * ifname,struct in_addr addr)395 siocaifaddr(int s, char *ifname, struct in_addr addr)
396 {
397 struct ifaliasreq ifra;
398 char ntopbuf_ip[INET_ADDRSTRLEN];
399 char ntopbuf_mask[INET_ADDRSTRLEN];
400 int ret;
401 struct sockaddr_in * sin;
402
403 bzero(&ifra, sizeof(ifra));
404 strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
405
406 sin = (struct sockaddr_in *)(void *)&ifra.ifra_addr;
407 sin->sin_len = sizeof(*sin);
408 sin->sin_family = AF_INET;
409 sin->sin_addr = addr;
410
411 sin = (struct sockaddr_in *)(void *)&ifra.ifra_mask;
412 sin->sin_len = sizeof(*sin);
413 sin->sin_family = AF_INET;
414 sin->sin_addr.s_addr = htonl(IN_CLASSC_NET);
415
416 ret = ioctl(s, SIOCAIFADDR, &ifra);
417 inet_ntop(AF_INET, &addr, ntopbuf_ip, sizeof(ntopbuf_ip));
418 inet_ntop(AF_INET, &sin->sin_addr, ntopbuf_mask, sizeof(ntopbuf_mask));
419 T_ASSERT_POSIX_SUCCESS(ret, "SIOCAIFADDR %s %s %s",
420 ifname, ntopbuf_ip, ntopbuf_mask);
421 return;
422 }
423
424 #if 0
425 static void
426 in6_len2mask(struct in6_addr * mask, int len)
427 {
428 int i;
429
430 bzero(mask, sizeof(*mask));
431 for (i = 0; i < len / 8; i++) {
432 mask->s6_addr[i] = 0xff;
433 }
434 if (len % 8) {
435 mask->s6_addr[i] = (0xff00 >> (len % 8)) & 0xff;
436 }
437 }
438
439 static void
440 siocaifaddr_in6(int s, char *ifname, struct in6_addr *addr)
441 {
442 struct in6_aliasreq ifra;
443 char ntopbuf_ip[INET6_ADDRSTRLEN];
444 int result;
445 struct sockaddr_in6 * sin;
446
447 bzero(&ifra, sizeof(ifra));
448 (void) strncpy(ifra.ifra_name, ifname, sizeof(ifra.ifra_name));
449
450 sin = (struct sockaddr_in6 *)(&ifra.ifra_addr);
451 sin->sin6_family = AF_INET6;
452 sin->sin6_len = sizeof(*sin);
453 sin->sin6_addr = *addr;
454 #define _PREFIX_LEN_64 64
455 sin = (struct sockaddr_in6 *)&ifra.ifra_prefixmask;
456 sin->sin6_family = AF_INET6;
457 sin->sin6_len = sizeof(*sin);
458 in6_len2mask(&sin->sin6_addr, _PREFIX_LEN_64);
459 ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
460 ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
461
462 result = ioctl(s, SIOCAIFADDR_IN6, &ifra);
463 inet_ntop(AF_INET6, addr, ntopbuf_ip, sizeof(ntopbuf_ip));
464 T_ASSERT_POSIX_SUCCESS(result, "SIOCAIFADDR_IN6 %s %s/64",
465 ifname, ntopbuf_ip);
466 return;
467 }
468 #endif
469
470 static void
siocll_start(int s,const char * ifname)471 siocll_start(int s, const char * ifname)
472 {
473 struct in6_aliasreq ifra_in6;
474 int result;
475
476 bzero(&ifra_in6, sizeof(ifra_in6));
477 strncpy(ifra_in6.ifra_name, ifname, sizeof(ifra_in6.ifra_name));
478 result = ioctl(s, SIOCLL_START, &ifra_in6);
479 T_QUIET;
480 T_ASSERT_POSIX_SUCCESS(result, "SIOCLL_START %s", ifname);
481 return;
482 }
483
484 static void
nd_flags_set(int s,const char * if_name,uint32_t set_flags,uint32_t clear_flags)485 nd_flags_set(int s, const char * if_name,
486 uint32_t set_flags, uint32_t clear_flags)
487 {
488 uint32_t new_flags;
489 struct in6_ndireq nd;
490 int result;
491
492 bzero(&nd, sizeof(nd));
493 strncpy(nd.ifname, if_name, sizeof(nd.ifname));
494 result = ioctl(s, SIOCGIFINFO_IN6, &nd);
495 T_ASSERT_POSIX_SUCCESS(result, "SIOCGIFINFO_IN6(%s)", if_name);
496 new_flags = nd.ndi.flags;
497 if (set_flags) {
498 new_flags |= set_flags;
499 }
500 if (clear_flags) {
501 new_flags &= ~clear_flags;
502 }
503 if (new_flags != nd.ndi.flags) {
504 nd.ndi.flags = new_flags;
505 result = ioctl(s, SIOCSIFINFO_FLAGS, (caddr_t)&nd);
506 T_ASSERT_POSIX_SUCCESS(result,
507 "SIOCSIFINFO_FLAGS(%s) 0x%x",
508 if_name, nd.ndi.flags);
509 }
510 return;
511 }
512
513
514 static void
siocprotoattach_in6(int s,const char * name)515 siocprotoattach_in6(int s, const char * name)
516 {
517 struct in6_aliasreq ifra;
518 int result;
519
520 bzero(&ifra, sizeof(ifra));
521 strncpy(ifra.ifra_name, name, sizeof(ifra.ifra_name));
522 result = ioctl(s, SIOCPROTOATTACH_IN6, &ifra);
523 T_ASSERT_POSIX_SUCCESS(result, "SIOCPROTOATTACH_IN6(%s)", name);
524 return;
525 }
526
527
528 static void
start_ipv6(int s,const char * ifname)529 start_ipv6(int s, const char * ifname)
530 {
531 /* attach IPv6 */
532 siocprotoattach_in6(s, ifname);
533
534 /* disable DAD to avoid 1 second delay (rdar://problem/73270401) */
535 nd_flags_set(s, ifname, 0, ND6_IFF_DAD);
536
537 /* start IPv6LL */
538 siocll_start(s, ifname);
539
540 return;
541 }
542
543 /*
544 * Stolen/modified from IPMonitor/ip_plugin.c
545 */
546 /*
547 * Define: ROUTE_MSG_ADDRS_SPACE
548 * Purpose:
549 * Since sizeof(sockaddr_dl) > sizeof(sockaddr_in), we need space for
550 * 3 sockaddr_in's and 2 sockaddr_dl's, but pad it just in case
551 * someone changes the code and doesn't think to modify this.
552 */
553 #define ROUTE_MSG_ADDRS_SPACE (3 * sizeof(struct sockaddr_in) \
554 + 2 * sizeof(struct sockaddr_dl) \
555 + 128)
556 typedef struct {
557 struct rt_msghdr hdr;
558 char addrs[ROUTE_MSG_ADDRS_SPACE];
559 } route_msg;
560
561 typedef unsigned short IFIndex;
562
563 typedef enum {
564 kRouteFlagsIsScoped = 0x0001,
565 kRouteFlagsHasGateway = 0x0002,
566 kRouteFlagsIsHost = 0x0004,
567 } RouteFlags;
568
569 typedef struct {
570 IFIndex ifindex;
571 RouteFlags flags;
572 struct in_addr dest;
573 struct in_addr mask;
574 struct in_addr gateway;
575 struct in_addr ifa;
576 } IPv4Route, * IPv4RouteRef;
577
578 /*
579 * Function: IPv4RouteApply
580 * Purpose:
581 * Add or remove the specified route to/from the kernel routing table.
582 */
583 static int
IPv4RouteApply(IPv4RouteRef route,uint8_t cmd,int s)584 IPv4RouteApply(IPv4RouteRef route, uint8_t cmd, int s)
585 {
586 size_t len;
587 int ret = 0;
588 route_msg rtmsg;
589 union {
590 struct sockaddr_in * in_p;
591 struct sockaddr_dl * dl_p;
592 char * ptr;
593 } rtaddr;
594 static int rtm_seq;
595 static bool rtm_seq_inited;
596
597 if (!rtm_seq_inited) {
598 rtm_seq_inited = true;
599 rtm_seq = (int)arc4random();
600 }
601 if (route->ifindex == 0) {
602 T_LOG("no interface specified, ignoring %s",
603 inet_ntoa(route->dest));
604 return ENXIO;
605 }
606 if (s < 0) {
607 T_LOG("invalid routing socket");
608 return EBADF;
609 }
610 memset(&rtmsg, 0, sizeof(rtmsg));
611 rtmsg.hdr.rtm_type = cmd;
612 rtmsg.hdr.rtm_version = RTM_VERSION;
613 rtmsg.hdr.rtm_seq = rtm_seq++;
614 rtmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_IFP;
615 if (route->ifa.s_addr != 0) {
616 rtmsg.hdr.rtm_addrs |= RTA_IFA;
617 }
618 rtmsg.hdr.rtm_flags = RTF_UP | RTF_STATIC;
619 if ((route->flags & kRouteFlagsIsHost) != 0) {
620 rtmsg.hdr.rtm_flags |= RTF_HOST;
621 } else {
622 rtmsg.hdr.rtm_addrs |= RTA_NETMASK;
623 if ((route->flags & kRouteFlagsHasGateway) == 0) {
624 rtmsg.hdr.rtm_flags |= RTF_CLONING;
625 }
626 }
627 if ((route->flags & kRouteFlagsHasGateway) != 0) {
628 rtmsg.hdr.rtm_flags |= RTF_GATEWAY;
629 }
630 if ((route->flags & kRouteFlagsIsScoped) != 0) {
631 rtmsg.hdr.rtm_index = route->ifindex;
632 rtmsg.hdr.rtm_flags |= RTF_IFSCOPE;
633 }
634
635 rtaddr.ptr = rtmsg.addrs;
636
637 /* dest */
638 rtaddr.in_p->sin_len = sizeof(*rtaddr.in_p);
639 rtaddr.in_p->sin_family = AF_INET;
640 rtaddr.in_p->sin_addr = route->dest;
641 rtaddr.ptr += sizeof(*rtaddr.in_p);
642
643 /* gateway */
644 if ((rtmsg.hdr.rtm_flags & RTF_GATEWAY) != 0) {
645 /* gateway is an IP address */
646 rtaddr.in_p->sin_len = sizeof(*rtaddr.in_p);
647 rtaddr.in_p->sin_family = AF_INET;
648 rtaddr.in_p->sin_addr = route->gateway;
649 rtaddr.ptr += sizeof(*rtaddr.in_p);
650 } else {
651 /* gateway is the interface itself */
652 rtaddr.dl_p->sdl_len = sizeof(*rtaddr.dl_p);
653 rtaddr.dl_p->sdl_family = AF_LINK;
654 rtaddr.dl_p->sdl_index = route->ifindex;
655 rtaddr.ptr += sizeof(*rtaddr.dl_p);
656 }
657
658 /* mask */
659 if ((rtmsg.hdr.rtm_addrs & RTA_NETMASK) != 0) {
660 rtaddr.in_p->sin_len = sizeof(*rtaddr.in_p);
661 rtaddr.in_p->sin_family = AF_INET;
662 rtaddr.in_p->sin_addr = route->mask;
663 rtaddr.ptr += sizeof(*rtaddr.in_p);
664 }
665
666 /* interface */
667 if ((rtmsg.hdr.rtm_addrs & RTA_IFP) != 0) {
668 rtaddr.dl_p->sdl_len = sizeof(*rtaddr.dl_p);
669 rtaddr.dl_p->sdl_family = AF_LINK;
670 rtaddr.dl_p->sdl_index = route->ifindex;
671 rtaddr.ptr += sizeof(*rtaddr.dl_p);
672 }
673 /* interface address */
674 if ((rtmsg.hdr.rtm_addrs & RTA_IFA) != 0) {
675 rtaddr.in_p->sin_len = sizeof(*rtaddr.in_p);
676 rtaddr.in_p->sin_family = AF_INET;
677 rtaddr.in_p->sin_addr = route->ifa;
678 rtaddr.ptr += sizeof(*rtaddr.in_p);
679 }
680
681 /* apply the route */
682 len = (sizeof(rtmsg.hdr)
683 + (unsigned long)(rtaddr.ptr - (char *)rtmsg.addrs));
684 rtmsg.hdr.rtm_msglen = (u_short)len;
685 if (write(s, &rtmsg, len) == -1) {
686 ret = errno;
687 T_LOG("write routing socket failed, (%d) %s",
688 errno, strerror(errno));
689 }
690 return ret;
691 }
692
693 static void
add_scoped_subnet_route(int s,char * ifname,u_short if_index,struct in_addr ifa)694 add_scoped_subnet_route(int s, char * ifname, u_short if_index,
695 struct in_addr ifa)
696 {
697 int error;
698 IPv4Route route;
699
700 bzero(&route, sizeof(route));
701 route.flags |= kRouteFlagsIsScoped;
702 route.ifa = ifa;
703 route.ifindex = if_index;
704 route.mask.s_addr = htonl(IN_CLASSC_NET);
705 route.dest.s_addr = route.ifa.s_addr & route.mask.s_addr;
706 T_QUIET;
707 T_ASSERT_NE((int)route.ifindex, 0, "if_nametoindex(%s)", ifname);
708 error = IPv4RouteApply(&route, RTM_ADD, s);
709 T_QUIET;
710 T_ASSERT_EQ(error, 0, "add scoped subnet route %s %s/24", ifname,
711 inet_ntoa(route.dest));
712 return;
713 }
714
715 #define ETHER_NTOA_BUFSIZE (ETHER_ADDR_LEN * 3)
716 static const char *
ether_ntoa_buf(const ether_addr_t * n,char * buf,int buf_size)717 ether_ntoa_buf(const ether_addr_t *n, char * buf, int buf_size)
718 {
719 char * str;
720
721 str = ether_ntoa(n);
722 strlcpy(buf, str, buf_size);
723 return buf;
724 }
725
726 static const char *
inet_ptrtop(int af,const void * ptr,char * buf,socklen_t buf_size)727 inet_ptrtop(int af, const void * ptr, char * buf, socklen_t buf_size)
728 {
729 union {
730 struct in_addr ip;
731 struct in6_addr ip6;
732 } u;
733
734 switch (af) {
735 case AF_INET:
736 bcopy(ptr, &u.ip, sizeof(u.ip));
737 break;
738 case AF_INET6:
739 bcopy(ptr, &u.ip6, sizeof(u.ip6));
740 break;
741 default:
742 return NULL;
743 }
744 return inet_ntop(af, &u, buf, buf_size);
745 }
746
747 static __inline__ char *
arpop_name(u_int16_t op)748 arpop_name(u_int16_t op)
749 {
750 switch (op) {
751 case ARPOP_REQUEST:
752 return "ARP REQUEST";
753 case ARPOP_REPLY:
754 return "ARP REPLY";
755 case ARPOP_REVREQUEST:
756 return "REVARP REQUEST";
757 case ARPOP_REVREPLY:
758 return "REVARP REPLY";
759 default:
760 break;
761 }
762 return "<unknown>";
763 }
764
765 static void
arp_frame_validate(const struct ether_arp * earp,u_int len,bool dump)766 arp_frame_validate(const struct ether_arp * earp, u_int len, bool dump)
767 {
768 const struct arphdr * arp_p;
769 int arphrd;
770 char buf_sender_ether[ETHER_NTOA_BUFSIZE];
771 char buf_sender_ip[INET_ADDRSTRLEN];
772 char buf_target_ether[ETHER_NTOA_BUFSIZE];
773 char buf_target_ip[INET_ADDRSTRLEN];
774
775 T_QUIET;
776 T_ASSERT_GE(len, (u_int)sizeof(*earp),
777 "%s ARP packet size %u need %u",
778 __func__, len, (u_int)sizeof(*earp));
779 if (!dump) {
780 return;
781 }
782 arp_p = &earp->ea_hdr;
783 arphrd = ntohs(arp_p->ar_hrd);
784 T_LOG("%s type=0x%x proto=0x%x", arpop_name(ntohs(arp_p->ar_op)),
785 arphrd, ntohs(arp_p->ar_pro));
786 if (arp_p->ar_hln == sizeof(earp->arp_sha)) {
787 ether_ntoa_buf((const ether_addr_t *)earp->arp_sha,
788 buf_sender_ether,
789 sizeof(buf_sender_ether));
790 ether_ntoa_buf((const ether_addr_t *)earp->arp_tha,
791 buf_target_ether,
792 sizeof(buf_target_ether));
793 T_LOG("Sender H/W\t%s", buf_sender_ether);
794 T_LOG("Target H/W\t%s", buf_target_ether);
795 }
796 inet_ptrtop(AF_INET, earp->arp_spa,
797 buf_sender_ip, sizeof(buf_sender_ip));
798 inet_ptrtop(AF_INET, earp->arp_tpa,
799 buf_target_ip, sizeof(buf_target_ip));
800 T_LOG("Sender IP\t%s", buf_sender_ip);
801 T_LOG("Target IP\t%s", buf_target_ip);
802 return;
803 }
804
805 static void
ip_frame_validate(const void * buf,u_int buf_len,bool dump)806 ip_frame_validate(const void * buf, u_int buf_len, bool dump)
807 {
808 char buf_dst[INET_ADDRSTRLEN];
809 char buf_src[INET_ADDRSTRLEN];
810 const ip_udp_header_t * ip_udp;
811 u_int ip_len;
812
813 T_QUIET;
814 T_ASSERT_GE(buf_len, (u_int)sizeof(struct ip), NULL);
815 ip_udp = (const ip_udp_header_t *)buf;
816 ip_len = ntohs(ip_udp->ip.ip_len);
817 inet_ptrtop(AF_INET, &ip_udp->ip.ip_src,
818 buf_src, sizeof(buf_src));
819 inet_ptrtop(AF_INET, &ip_udp->ip.ip_dst,
820 buf_dst, sizeof(buf_dst));
821 if (dump) {
822 T_LOG("ip src %s dst %s len %u id %d",
823 buf_src, buf_dst, ip_len,
824 ntohs(ip_udp->ip.ip_id));
825 }
826 T_QUIET;
827 T_ASSERT_GE(buf_len, ip_len, NULL);
828 T_QUIET;
829 T_ASSERT_EQ(ip_udp->ip.ip_v, IPVERSION, NULL);
830 T_QUIET;
831 T_ASSERT_EQ((u_int)(ip_udp->ip.ip_hl << 2),
832 (u_int)sizeof(struct ip), NULL);
833 if (ip_udp->ip.ip_p == IPPROTO_UDP) {
834 u_int udp_len;
835 u_int data_len;
836
837 T_QUIET;
838 T_ASSERT_GE(buf_len, (u_int)sizeof(*ip_udp), NULL);
839 udp_len = ntohs(ip_udp->udp.uh_ulen);
840 T_QUIET;
841 T_ASSERT_GE(udp_len, (u_int)sizeof(ip_udp->udp), NULL);
842 data_len = udp_len - (u_int)sizeof(ip_udp->udp);
843 if (dump) {
844 T_LOG("udp src 0x%x dst 0x%x len %u"
845 " csum 0x%x datalen %u",
846 ntohs(ip_udp->udp.uh_sport),
847 ntohs(ip_udp->udp.uh_dport),
848 udp_len,
849 ntohs(ip_udp->udp.uh_sum),
850 data_len);
851 }
852 }
853 }
854
855 static void
ip6_frame_validate(const void * buf,u_int buf_len,bool dump)856 ip6_frame_validate(const void * buf, u_int buf_len, bool dump)
857 {
858 char buf_dst[INET6_ADDRSTRLEN];
859 char buf_src[INET6_ADDRSTRLEN];
860 const struct ip6_hdr * ip6;
861 u_int ip6_len;
862
863 T_QUIET;
864 T_ASSERT_GE(buf_len, (u_int)sizeof(struct ip6_hdr), NULL);
865 ip6 = (const struct ip6_hdr *)buf;
866 ip6_len = ntohs(ip6->ip6_plen);
867 inet_ptrtop(AF_INET6, &ip6->ip6_src, buf_src, sizeof(buf_src));
868 inet_ptrtop(AF_INET6, &ip6->ip6_dst, buf_dst, sizeof(buf_dst));
869 if (dump) {
870 T_LOG("ip6 src %s dst %s len %u", buf_src, buf_dst, ip6_len);
871 }
872 T_QUIET;
873 T_ASSERT_GE(buf_len, ip6_len + (u_int)sizeof(struct ip6_hdr), NULL);
874 T_QUIET;
875 T_ASSERT_EQ((ip6->ip6_vfc & IPV6_VERSION_MASK),
876 IPV6_VERSION, NULL);
877 T_QUIET;
878 switch (ip6->ip6_nxt) {
879 case IPPROTO_UDP: {
880 u_int data_len;
881 const ip6_udp_header_t *ip6_udp;
882 u_int udp_len;
883
884 ip6_udp = (const ip6_udp_header_t *)buf;
885 T_QUIET;
886 T_ASSERT_GE(buf_len, (u_int)sizeof(*ip6_udp), NULL);
887 udp_len = ntohs(ip6_udp->udp.uh_ulen);
888 T_QUIET;
889 T_ASSERT_GE(udp_len, (u_int)sizeof(ip6_udp->udp), NULL);
890 data_len = udp_len - (u_int)sizeof(ip6_udp->udp);
891 if (dump) {
892 T_LOG("udp src 0x%x dst 0x%x len %u"
893 " csum 0x%x datalen %u",
894 ntohs(ip6_udp->udp.uh_sport),
895 ntohs(ip6_udp->udp.uh_dport),
896 udp_len,
897 ntohs(ip6_udp->udp.uh_sum),
898 data_len);
899 }
900 break;
901 }
902 case IPPROTO_ICMPV6: {
903 const struct icmp6_hdr *icmp6;
904 u_int icmp6_len;
905
906 icmp6_len = buf_len - sizeof(*ip6);
907 T_QUIET;
908 T_ASSERT_GE(buf_len, icmp6_len, NULL);
909 icmp6 = (const struct icmp6_hdr *)(ip6 + 1);
910 switch (icmp6->icmp6_type) {
911 case ND_NEIGHBOR_SOLICIT:
912 if (dump) {
913 T_LOG("neighbor solicit");
914 }
915 break;
916 case ND_NEIGHBOR_ADVERT:
917 if (dump) {
918 T_LOG("neighbor advert");
919 }
920 break;
921 case ND_ROUTER_SOLICIT:
922 if (dump) {
923 T_LOG("router solicit");
924 }
925 break;
926 default:
927 if (dump) {
928 T_LOG("icmp6 code 0x%x", icmp6->icmp6_type);
929 }
930 break;
931 }
932 break;
933 }
934 default:
935 break;
936 }
937 }
938
939 static void
ethernet_frame_validate(const void * buf,u_int buf_len,bool dump)940 ethernet_frame_validate(const void * buf, u_int buf_len, bool dump)
941 {
942 char ether_dst[ETHER_NTOA_BUFSIZE];
943 char ether_src[ETHER_NTOA_BUFSIZE];
944 uint16_t ether_type;
945 const ether_header_t * eh_p;
946
947 T_QUIET;
948 T_ASSERT_GE(buf_len, (u_int)sizeof(*eh_p), NULL);
949 eh_p = (const ether_header_t *)buf;
950 ether_type = ntohs(eh_p->ether_type);
951 ether_ntoa_buf((const ether_addr_t *)&eh_p->ether_dhost,
952 ether_dst, sizeof(ether_dst));
953 ether_ntoa_buf((const ether_addr_t *)&eh_p->ether_shost,
954 ether_src, sizeof(ether_src));
955 if (dump) {
956 T_LOG("ether dst %s src %s type 0x%x",
957 ether_dst, ether_src, ether_type);
958 }
959 switch (ether_type) {
960 case ETHERTYPE_IP:
961 ip_frame_validate(eh_p + 1, (u_int)(buf_len - sizeof(*eh_p)),
962 dump);
963 break;
964 case ETHERTYPE_ARP:
965 arp_frame_validate((const struct ether_arp *)(eh_p + 1),
966 (u_int)(buf_len - sizeof(*eh_p)),
967 dump);
968 break;
969 case ETHERTYPE_IPV6:
970 ip6_frame_validate(eh_p + 1, (u_int)(buf_len - sizeof(*eh_p)),
971 dump);
972 break;
973 default:
974 T_FAIL("unrecognized ethertype 0x%x", ether_type);
975 break;
976 }
977 }
978
979 static u_int
ethernet_udp4_frame_populate(void * buf,size_t buf_len,const ether_addr_t * src,struct in_addr src_ip,uint16_t src_port,const ether_addr_t * dst,struct in_addr dst_ip,uint16_t dst_port,const void * data,u_int data_len)980 ethernet_udp4_frame_populate(void * buf, size_t buf_len,
981 const ether_addr_t * src,
982 struct in_addr src_ip,
983 uint16_t src_port,
984 const ether_addr_t * dst,
985 struct in_addr dst_ip,
986 uint16_t dst_port,
987 const void * data, u_int data_len)
988 {
989 ether_header_t * eh_p;
990 u_int frame_length;
991 static int ip_id;
992 ip_udp_header_t * ip_udp;
993 char * payload;
994 udp_pseudo_hdr_t * udp_pseudo;
995
996 frame_length = (u_int)(sizeof(*eh_p) + sizeof(*ip_udp)) + data_len;
997 if (buf_len < frame_length) {
998 return 0;
999 }
1000
1001 /* determine frame offsets */
1002 eh_p = (ether_header_t *)buf;
1003 ip_udp = (ip_udp_header_t *)(void *)(eh_p + 1);
1004 udp_pseudo = (udp_pseudo_hdr_t *)(void *)
1005 (((char *)&ip_udp->udp) - sizeof(*udp_pseudo));
1006 payload = (char *)(eh_p + 1) + sizeof(*ip_udp);
1007
1008 /* ethernet_header */
1009 bcopy(src, eh_p->ether_shost, ETHER_ADDR_LEN);
1010 bcopy(dst, eh_p->ether_dhost, ETHER_ADDR_LEN);
1011 eh_p->ether_type = htons(ETHERTYPE_IP);
1012
1013 /* copy the data */
1014 bcopy(data, payload, data_len);
1015
1016 /* fill in UDP pseudo header (gets overwritten by IP header below) */
1017 bcopy(&src_ip, &udp_pseudo->src_ip, sizeof(src_ip));
1018 bcopy(&dst_ip, &udp_pseudo->dst_ip, sizeof(dst_ip));
1019 udp_pseudo->zero = 0;
1020 udp_pseudo->proto = IPPROTO_UDP;
1021 udp_pseudo->length = htons(sizeof(ip_udp->udp) + data_len);
1022
1023 /* fill in UDP header */
1024 ip_udp->udp.uh_sport = htons(src_port);
1025 ip_udp->udp.uh_dport = htons(dst_port);
1026 ip_udp->udp.uh_ulen = htons(sizeof(ip_udp->udp) + data_len);
1027 ip_udp->udp.uh_sum = 0;
1028 ip_udp->udp.uh_sum = in_cksum(udp_pseudo, (int)(sizeof(*udp_pseudo)
1029 + sizeof(ip_udp->udp) + data_len));
1030
1031 /* fill in IP header */
1032 bzero(ip_udp, sizeof(ip_udp->ip));
1033 ip_udp->ip.ip_v = IPVERSION;
1034 ip_udp->ip.ip_hl = sizeof(struct ip) >> 2;
1035 ip_udp->ip.ip_ttl = MAXTTL;
1036 ip_udp->ip.ip_p = IPPROTO_UDP;
1037 bcopy(&src_ip, &ip_udp->ip.ip_src, sizeof(src_ip));
1038 bcopy(&dst_ip, &ip_udp->ip.ip_dst, sizeof(dst_ip));
1039 ip_udp->ip.ip_len = htons(sizeof(*ip_udp) + data_len);
1040 ip_udp->ip.ip_id = htons(ip_id++);
1041
1042 /* compute the IP checksum */
1043 ip_udp->ip.ip_sum = 0; /* needs to be zero for checksum */
1044 ip_udp->ip.ip_sum = in_cksum(&ip_udp->ip, sizeof(ip_udp->ip));
1045
1046 return frame_length;
1047 }
1048
1049 static u_int
ethernet_udp6_frame_populate(void * buf,size_t buf_len,const ether_addr_t * src,struct in6_addr * src_ip,uint16_t src_port,const ether_addr_t * dst,struct in6_addr * dst_ip,uint16_t dst_port,const void * data,u_int data_len)1050 ethernet_udp6_frame_populate(void * buf, size_t buf_len,
1051 const ether_addr_t * src,
1052 struct in6_addr *src_ip,
1053 uint16_t src_port,
1054 const ether_addr_t * dst,
1055 struct in6_addr * dst_ip,
1056 uint16_t dst_port,
1057 const void * data, u_int data_len)
1058 {
1059 ether_header_t * eh_p;
1060 u_int frame_length;
1061 ip6_udp_header_t * ip6_udp;
1062 char * payload;
1063 udp6_pseudo_hdr_t * udp6_pseudo;
1064
1065 frame_length = (u_int)(sizeof(*eh_p) + sizeof(*ip6_udp)) + data_len;
1066 if (buf_len < frame_length) {
1067 return 0;
1068 }
1069
1070 /* determine frame offsets */
1071 eh_p = (ether_header_t *)buf;
1072 ip6_udp = (ip6_udp_header_t *)(void *)(eh_p + 1);
1073 udp6_pseudo = (udp6_pseudo_hdr_t *)(void *)
1074 (((char *)&ip6_udp->udp) - sizeof(*udp6_pseudo));
1075 payload = (char *)(eh_p + 1) + sizeof(*ip6_udp);
1076
1077 /* ethernet_header */
1078 bcopy(src, eh_p->ether_shost, ETHER_ADDR_LEN);
1079 bcopy(dst, eh_p->ether_dhost, ETHER_ADDR_LEN);
1080 eh_p->ether_type = htons(ETHERTYPE_IPV6);
1081
1082 /* copy the data */
1083 bcopy(data, payload, data_len);
1084
1085 /* fill in UDP pseudo header (gets overwritten by IP header below) */
1086 bcopy(src_ip, &udp6_pseudo->src_ip, sizeof(*src_ip));
1087 bcopy(dst_ip, &udp6_pseudo->dst_ip, sizeof(*dst_ip));
1088 udp6_pseudo->zero = 0;
1089 udp6_pseudo->proto = IPPROTO_UDP;
1090 udp6_pseudo->length = htons(sizeof(ip6_udp->udp) + data_len);
1091
1092 /* fill in UDP header */
1093 ip6_udp->udp.uh_sport = htons(src_port);
1094 ip6_udp->udp.uh_dport = htons(dst_port);
1095 ip6_udp->udp.uh_ulen = htons(sizeof(ip6_udp->udp) + data_len);
1096 ip6_udp->udp.uh_sum = 0;
1097 ip6_udp->udp.uh_sum = in_cksum(udp6_pseudo, (int)(sizeof(*udp6_pseudo)
1098 + sizeof(ip6_udp->udp) + data_len));
1099
1100 /* fill in IP header */
1101 bzero(&ip6_udp->ip6, sizeof(ip6_udp->ip6));
1102 ip6_udp->ip6.ip6_vfc = IPV6_VERSION;
1103 ip6_udp->ip6.ip6_nxt = IPPROTO_UDP;
1104 bcopy(src_ip, &ip6_udp->ip6.ip6_src, sizeof(*src_ip));
1105 bcopy(dst_ip, &ip6_udp->ip6.ip6_dst, sizeof(*dst_ip));
1106 ip6_udp->ip6.ip6_plen = htons(sizeof(struct udphdr) + data_len);
1107 /* ip6_udp->ip6.ip6_flow = ? */
1108 return frame_length;
1109 }
1110
1111 static u_int
ethernet_udp_frame_populate(void * buf,size_t buf_len,uint8_t af,const ether_addr_t * src,union ifbrip * src_ip,uint16_t src_port,const ether_addr_t * dst,union ifbrip * dst_ip,uint16_t dst_port,const void * data,u_int data_len)1112 ethernet_udp_frame_populate(void * buf, size_t buf_len,
1113 uint8_t af,
1114 const ether_addr_t * src,
1115 union ifbrip * src_ip,
1116 uint16_t src_port,
1117 const ether_addr_t * dst,
1118 union ifbrip * dst_ip,
1119 uint16_t dst_port,
1120 const void * data, u_int data_len)
1121 {
1122 u_int len;
1123
1124 switch (af) {
1125 case AF_INET:
1126 len = ethernet_udp4_frame_populate(buf, buf_len,
1127 src,
1128 src_ip->ifbrip_addr,
1129 src_port,
1130 dst,
1131 dst_ip->ifbrip_addr,
1132 dst_port,
1133 data, data_len);
1134 break;
1135 case AF_INET6:
1136 len = ethernet_udp6_frame_populate(buf, buf_len,
1137 src,
1138 &src_ip->ifbrip_addr6,
1139 src_port,
1140 dst,
1141 &dst_ip->ifbrip_addr6,
1142 dst_port,
1143 data, data_len);
1144 break;
1145 default:
1146 T_FAIL("unrecognized address family %u", af);
1147 len = 0;
1148 break;
1149 }
1150 return len;
1151 }
1152
1153 static u_int
ethernet_arp_frame_populate(void * buf,u_int buf_len,uint16_t op,const ether_addr_t * sender_hw,struct in_addr sender_ip,const ether_addr_t * target_hw,struct in_addr target_ip)1154 ethernet_arp_frame_populate(void * buf, u_int buf_len,
1155 uint16_t op,
1156 const ether_addr_t * sender_hw,
1157 struct in_addr sender_ip,
1158 const ether_addr_t * target_hw,
1159 struct in_addr target_ip)
1160 {
1161 ether_header_t * eh_p;
1162 struct ether_arp * earp;
1163 struct arphdr * arp_p;
1164 u_int frame_length;
1165
1166 frame_length = sizeof(*earp) + sizeof(*eh_p);
1167 T_QUIET;
1168 T_ASSERT_GE(buf_len, frame_length,
1169 "%s buffer size %u needed %u",
1170 __func__, buf_len, frame_length);
1171
1172 /* ethernet_header */
1173 eh_p = (ether_header_t *)buf;
1174 bcopy(sender_hw, eh_p->ether_shost, ETHER_ADDR_LEN);
1175 if (target_hw != NULL) {
1176 bcopy(target_hw, eh_p->ether_dhost,
1177 sizeof(eh_p->ether_dhost));
1178 } else {
1179 bcopy(ðer_broadcast, eh_p->ether_dhost,
1180 sizeof(eh_p->ether_dhost));
1181 }
1182 eh_p->ether_type = htons(ETHERTYPE_ARP);
1183
1184 /* ARP payload */
1185 earp = (struct ether_arp *)(void *)(eh_p + 1);
1186 arp_p = &earp->ea_hdr;
1187 arp_p->ar_hrd = htons(ARPHRD_ETHER);
1188 arp_p->ar_pro = htons(ETHERTYPE_IP);
1189 arp_p->ar_hln = sizeof(earp->arp_sha);
1190 arp_p->ar_pln = sizeof(struct in_addr);
1191 arp_p->ar_op = htons(op);
1192 bcopy(sender_hw, earp->arp_sha, sizeof(earp->arp_sha));
1193 bcopy(&sender_ip, earp->arp_spa, sizeof(earp->arp_spa));
1194 if (target_hw != NULL) {
1195 bcopy(target_hw, earp->arp_tha, sizeof(earp->arp_tha));
1196 } else {
1197 bzero(earp->arp_tha, sizeof(earp->arp_tha));
1198 }
1199 bcopy(&target_ip, earp->arp_tpa, sizeof(earp->arp_tpa));
1200 return frame_length;
1201 }
1202
1203 static uint32_t G_generation;
1204
1205 static uint32_t
next_generation(void)1206 next_generation(void)
1207 {
1208 return G_generation++;
1209 }
1210
1211 static const void *
ethernet_frame_get_udp4_payload(void * buf,u_int buf_len,u_int * ret_payload_length)1212 ethernet_frame_get_udp4_payload(void * buf, u_int buf_len,
1213 u_int * ret_payload_length)
1214 {
1215 ether_header_t * eh_p;
1216 uint16_t ether_type;
1217 ip_udp_header_t * ip_udp;
1218 u_int ip_len;
1219 u_int left;
1220 const void * payload = NULL;
1221 u_int payload_length = 0;
1222 u_int udp_len;
1223
1224 T_QUIET;
1225 T_ASSERT_GE(buf_len, (u_int)(sizeof(*eh_p) + sizeof(*ip_udp)), NULL);
1226 left = buf_len;
1227 eh_p = (ether_header_t *)buf;
1228 ether_type = ntohs(eh_p->ether_type);
1229 T_QUIET;
1230 T_ASSERT_EQ((int)ether_type, ETHERTYPE_IP, NULL);
1231 ip_udp = (ip_udp_header_t *)(void *)(eh_p + 1);
1232 left -= sizeof(*eh_p);
1233 ip_len = ntohs(ip_udp->ip.ip_len);
1234 T_QUIET;
1235 T_ASSERT_GE(left, ip_len, NULL);
1236 T_QUIET;
1237 T_ASSERT_EQ((int)ip_udp->ip.ip_v, IPVERSION, NULL);
1238 T_QUIET;
1239 T_ASSERT_EQ((u_int)ip_udp->ip.ip_hl << 2, (u_int)sizeof(struct ip),
1240 NULL);
1241 T_QUIET;
1242 T_ASSERT_EQ((int)ip_udp->ip.ip_p, IPPROTO_UDP, NULL);
1243 T_QUIET;
1244 T_ASSERT_GE(buf_len, (u_int)sizeof(*ip_udp), NULL);
1245 udp_len = ntohs(ip_udp->udp.uh_ulen);
1246 T_QUIET;
1247 T_ASSERT_GE(udp_len, (u_int)sizeof(ip_udp->udp), NULL);
1248 payload_length = udp_len - (int)sizeof(ip_udp->udp);
1249 if (payload_length > 0) {
1250 payload = (ip_udp + 1);
1251 }
1252 if (payload == NULL) {
1253 payload_length = 0;
1254 }
1255 *ret_payload_length = payload_length;
1256 return payload;
1257 }
1258
1259 static const void *
ethernet_frame_get_udp6_payload(void * buf,u_int buf_len,u_int * ret_payload_length)1260 ethernet_frame_get_udp6_payload(void * buf, u_int buf_len,
1261 u_int * ret_payload_length)
1262 {
1263 ether_header_t * eh_p;
1264 uint16_t ether_type;
1265 ip6_udp_header_t * ip6_udp;
1266 u_int ip6_len;
1267 u_int left;
1268 const void * payload = NULL;
1269 u_int payload_length = 0;
1270 u_int udp_len;
1271
1272 T_QUIET;
1273 T_ASSERT_GE(buf_len, (u_int)(sizeof(*eh_p) + sizeof(*ip6_udp)), NULL);
1274 left = buf_len;
1275 eh_p = (ether_header_t *)buf;
1276 ether_type = ntohs(eh_p->ether_type);
1277 T_QUIET;
1278 T_ASSERT_EQ((int)ether_type, ETHERTYPE_IPV6, NULL);
1279 ip6_udp = (ip6_udp_header_t *)(void *)(eh_p + 1);
1280 left -= sizeof(*eh_p);
1281 ip6_len = ntohs(ip6_udp->ip6.ip6_plen);
1282 T_QUIET;
1283 T_ASSERT_GE(left, ip6_len + (u_int)sizeof(struct ip6_hdr), NULL);
1284 T_QUIET;
1285 T_ASSERT_EQ((int)(ip6_udp->ip6.ip6_vfc & IPV6_VERSION_MASK),
1286 IPV6_VERSION, NULL);
1287 T_QUIET;
1288 T_ASSERT_EQ((int)ip6_udp->ip6.ip6_nxt, IPPROTO_UDP, NULL);
1289 T_QUIET;
1290 T_ASSERT_GE(buf_len, (u_int)sizeof(*ip6_udp), NULL);
1291 udp_len = ntohs(ip6_udp->udp.uh_ulen);
1292 T_QUIET;
1293 T_ASSERT_GE(udp_len, (u_int)sizeof(ip6_udp->udp), NULL);
1294 payload_length = udp_len - (int)sizeof(ip6_udp->udp);
1295 if (payload_length > 0) {
1296 payload = (ip6_udp + 1);
1297 }
1298 if (payload == NULL) {
1299 payload_length = 0;
1300 }
1301 *ret_payload_length = payload_length;
1302 return payload;
1303 }
1304
1305 static const void *
ethernet_frame_get_udp_payload(uint8_t af,void * buf,u_int buf_len,u_int * ret_payload_length)1306 ethernet_frame_get_udp_payload(uint8_t af, void * buf, u_int buf_len,
1307 u_int * ret_payload_length)
1308 {
1309 const void * payload;
1310
1311 switch (af) {
1312 case AF_INET:
1313 payload = ethernet_frame_get_udp4_payload(buf, buf_len,
1314 ret_payload_length);
1315 break;
1316 case AF_INET6:
1317 payload = ethernet_frame_get_udp6_payload(buf, buf_len,
1318 ret_payload_length);
1319 break;
1320 default:
1321 T_FAIL("unrecognized address family %u", af);
1322 payload = NULL;
1323 break;
1324 }
1325 return payload;
1326 }
1327
1328 #define MIN_ICMP6_LEN ((u_int)(sizeof(ether_header_t) + \
1329 sizeof(struct ip6_hdr) + \
1330 sizeof(struct icmp6_hdr)))
1331 #define ALIGNED_ND_OPT_LEN 8
1332 #define SET_ND_OPT_LEN(a) (u_int)((a) >> 3)
1333 #define GET_ND_OPT_LEN(a) (u_int)((a) << 3)
1334 #define ALIGN_ND_OPT(a) (u_int)roundup(a, ALIGNED_ND_OPT_LEN)
1335 #define LINKADDR_OPT_LEN (ALIGN_ND_OPT(sizeof(struct nd_opt_hdr) + \
1336 sizeof(ether_addr_t)))
1337 #define ETHER_IPV6_LEN (sizeof(*eh_p) + sizeof(*ip6))
1338
1339
1340
1341 static u_int
ethernet_nd6_frame_populate(void * buf,u_int buf_len,uint8_t type,const ether_addr_t * sender_hw,struct in6_addr * sender_ip,const ether_addr_t * dest_ether,const ether_addr_t * target_hw,struct in6_addr * target_ip)1342 ethernet_nd6_frame_populate(void * buf, u_int buf_len,
1343 uint8_t type,
1344 const ether_addr_t * sender_hw,
1345 struct in6_addr * sender_ip,
1346 const ether_addr_t * dest_ether,
1347 const ether_addr_t * target_hw,
1348 struct in6_addr * target_ip)
1349 {
1350 u_int data_len = 0;
1351 ether_header_t * eh_p;
1352 u_int frame_length;
1353 struct icmp6_hdr * icmp6;
1354 struct ip6_hdr * ip6;
1355 struct nd_opt_hdr * nd_opt;
1356
1357 switch (type) {
1358 case ND_ROUTER_SOLICIT:
1359 case ND_NEIGHBOR_ADVERT:
1360 case ND_NEIGHBOR_SOLICIT:
1361 break;
1362 default:
1363 T_FAIL("%s: unsupported type %u", __func__, type);
1364 return 0;
1365 }
1366
1367 T_QUIET;
1368 T_ASSERT_GE(buf_len, MIN_ICMP6_LEN, NULL);
1369
1370 eh_p = (ether_header_t *)buf;
1371 ip6 = (struct ip6_hdr *)(void *)(eh_p + 1);
1372 icmp6 = (struct icmp6_hdr *)(void *)(ip6 + 1);
1373 frame_length = sizeof(*eh_p) + sizeof(*ip6);
1374 switch (type) {
1375 case ND_NEIGHBOR_SOLICIT: {
1376 struct nd_neighbor_solicit * nd_ns;
1377 bool sender_is_specified;
1378
1379 sender_is_specified = !IN6_IS_ADDR_UNSPECIFIED(sender_ip);
1380 data_len = sizeof(*nd_ns);
1381 if (sender_is_specified) {
1382 data_len += LINKADDR_OPT_LEN;
1383 }
1384 frame_length += data_len;
1385 T_QUIET;
1386 T_ASSERT_GE(buf_len, frame_length, NULL);
1387 nd_ns = (struct nd_neighbor_solicit *)(void *)icmp6;
1388 if (sender_is_specified) {
1389 /* add the source lladdr option */
1390 nd_opt = (struct nd_opt_hdr *)(nd_ns + 1);
1391 nd_opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
1392 nd_opt->nd_opt_len = SET_ND_OPT_LEN(LINKADDR_OPT_LEN);
1393 bcopy(sender_hw, (nd_opt + 1), sizeof(*sender_hw));
1394 }
1395 bcopy(target_ip, &nd_ns->nd_ns_target,
1396 sizeof(nd_ns->nd_ns_target));
1397 break;
1398 }
1399 case ND_NEIGHBOR_ADVERT: {
1400 struct nd_neighbor_advert * nd_na;
1401
1402 data_len = sizeof(*nd_na) + LINKADDR_OPT_LEN;
1403 frame_length += data_len;
1404 T_QUIET;
1405 T_ASSERT_GE(buf_len, frame_length, NULL);
1406
1407 nd_na = (struct nd_neighbor_advert *)(void *)icmp6;
1408 bcopy(target_ip, &nd_na->nd_na_target,
1409 sizeof(nd_na->nd_na_target));
1410 /* add the target lladdr option */
1411 nd_opt = (struct nd_opt_hdr *)(nd_na + 1);
1412 nd_opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
1413 nd_opt->nd_opt_len = SET_ND_OPT_LEN(LINKADDR_OPT_LEN);
1414 bcopy(target_hw, (nd_opt + 1), sizeof(*target_hw));
1415 break;
1416 }
1417 case ND_ROUTER_SOLICIT: {
1418 struct nd_router_solicit * nd_rs;
1419
1420 data_len = sizeof(*nd_rs) + LINKADDR_OPT_LEN;
1421 frame_length += data_len;
1422 T_QUIET;
1423 T_ASSERT_GE(buf_len, frame_length, NULL);
1424
1425 nd_rs = (struct nd_router_solicit *)(void *)icmp6;
1426
1427 /* add the source lladdr option */
1428 nd_opt = (struct nd_opt_hdr *)(nd_rs + 1);
1429 nd_opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
1430 nd_opt->nd_opt_len = SET_ND_OPT_LEN(LINKADDR_OPT_LEN);
1431 bcopy(sender_hw, (nd_opt + 1), sizeof(*sender_hw));
1432 break;
1433 }
1434 default:
1435 T_FAIL("%s: unsupported type %u", __func__, type);
1436 return 0;
1437 }
1438 /* icmp6 header */
1439 icmp6->icmp6_type = type;
1440 icmp6->icmp6_code = 0;
1441 icmp6->icmp6_cksum = 0;
1442 icmp6->icmp6_data32[0] = 0;
1443
1444 /* ethernet_header */
1445 bcopy(sender_hw, eh_p->ether_shost, ETHER_ADDR_LEN);
1446 if (dest_ether != NULL) {
1447 bcopy(dest_ether, eh_p->ether_dhost,
1448 sizeof(eh_p->ether_dhost));
1449 } else {
1450 /* XXX ether_dhost should be multicast */
1451 bcopy(ðer_broadcast, eh_p->ether_dhost,
1452 sizeof(eh_p->ether_dhost));
1453 }
1454 eh_p->ether_type = htons(ETHERTYPE_IPV6);
1455
1456 /* IPv6 header */
1457 bzero(ip6, sizeof(*ip6));
1458 ip6->ip6_nxt = IPPROTO_ICMPV6;
1459 ip6->ip6_vfc = IPV6_VERSION;
1460 bcopy(sender_ip, &ip6->ip6_src, sizeof(ip6->ip6_src));
1461 /* XXX ip6_dst should be specific multicast */
1462 bcopy(&in6addr_linklocal_allnodes, &ip6->ip6_dst, sizeof(ip6->ip6_dst));
1463 ip6->ip6_plen = htons(data_len);
1464
1465 return frame_length;
1466 }
1467
1468 /**
1469 ** Switch port
1470 **/
1471 static void
switch_port_check_tx(switch_port_t port)1472 switch_port_check_tx(switch_port_t port)
1473 {
1474 int error;
1475 struct kevent kev;
1476 int kq;
1477 struct timespec ts = { .tv_sec = 0, .tv_nsec = 1000 * 1000};
1478
1479 kq = kqueue();
1480 T_QUIET;
1481 T_ASSERT_POSIX_SUCCESS(kq, "kqueue check_tx");
1482 EV_SET(&kev, port->fd, EVFILT_WRITE, EV_ADD | EV_ENABLE, 0, 0, NULL);
1483 error = kevent(kq, &kev, 1, &kev, 1, &ts);
1484 T_QUIET;
1485 T_ASSERT_EQ(error, 1, "kevent");
1486 T_QUIET;
1487 T_ASSERT_EQ((int)kev.filter, EVFILT_WRITE, NULL);
1488 T_QUIET;
1489 T_ASSERT_EQ((int)kev.ident, port->fd, NULL);
1490 T_QUIET;
1491 T_ASSERT_NULL(kev.udata, NULL);
1492 close(kq);
1493 return;
1494 }
1495
1496 static void
switch_port_send_arp(switch_port_t port,uint16_t op,const ether_addr_t * sender_hw,struct in_addr sender_ip,const ether_addr_t * target_hw,struct in_addr target_ip)1497 switch_port_send_arp(switch_port_t port,
1498 uint16_t op,
1499 const ether_addr_t * sender_hw,
1500 struct in_addr sender_ip,
1501 const ether_addr_t * target_hw,
1502 struct in_addr target_ip)
1503 {
1504 u_int frame_length;
1505 ether_packet pkt;
1506 ssize_t n;
1507
1508 /* make sure we can send */
1509 switch_port_check_tx(port);
1510 frame_length = ethernet_arp_frame_populate(&pkt, sizeof(pkt),
1511 op,
1512 sender_hw,
1513 sender_ip,
1514 target_hw,
1515 target_ip);
1516 T_QUIET;
1517 T_ASSERT_GT(frame_length, 0, "%s: frame_length %u",
1518 __func__, frame_length);
1519 if (S_debug) {
1520 T_LOG("Port %s -> %s transmitting %u bytes",
1521 port->ifname, port->member_ifname, frame_length);
1522 }
1523 ethernet_frame_validate(&pkt, frame_length, S_debug);
1524 n = write(port->fd, &pkt, frame_length);
1525 if (n < 0) {
1526 T_ASSERT_POSIX_SUCCESS(n, "%s write fd %d failed %ld",
1527 port->ifname, port->fd, n);
1528 }
1529 T_QUIET;
1530 T_ASSERT_EQ((u_int)n, frame_length,
1531 "%s fd %d wrote %ld",
1532 port->ifname, port->fd, n);
1533 }
1534
1535
1536 static void
switch_port_send_nd6(switch_port_t port,uint8_t type,const ether_addr_t * sender_hw,struct in6_addr * sender_ip,const ether_addr_t * dest_ether,const ether_addr_t * target_hw,struct in6_addr * target_ip)1537 switch_port_send_nd6(switch_port_t port,
1538 uint8_t type,
1539 const ether_addr_t * sender_hw,
1540 struct in6_addr * sender_ip,
1541 const ether_addr_t * dest_ether,
1542 const ether_addr_t * target_hw,
1543 struct in6_addr * target_ip)
1544 {
1545 u_int frame_length;
1546 ether_packet pkt;
1547 ssize_t n;
1548
1549 /* make sure we can send */
1550 switch_port_check_tx(port);
1551 frame_length = ethernet_nd6_frame_populate(&pkt, sizeof(pkt),
1552 type,
1553 sender_hw,
1554 sender_ip,
1555 dest_ether,
1556 target_hw,
1557 target_ip);
1558 T_QUIET;
1559 T_ASSERT_GT(frame_length, 0, "%s: frame_length %u",
1560 __func__, frame_length);
1561 if (S_debug) {
1562 T_LOG("Port %s -> %s transmitting %u bytes",
1563 port->ifname, port->member_ifname, frame_length);
1564 }
1565 ethernet_frame_validate(&pkt, frame_length, S_debug);
1566 n = write(port->fd, &pkt, frame_length);
1567 if (n < 0) {
1568 T_ASSERT_POSIX_SUCCESS(n, "%s write fd %d failed %ld",
1569 port->ifname, port->fd, n);
1570 }
1571 T_QUIET;
1572 T_ASSERT_EQ((u_int)n, frame_length,
1573 "%s fd %d wrote %ld",
1574 port->ifname, port->fd, n);
1575 }
1576
1577
1578 static void
switch_port_send_udp(switch_port_t port,uint8_t af,const ether_addr_t * src_eaddr,union ifbrip * src_ip,uint16_t src_port,const ether_addr_t * dst_eaddr,union ifbrip * dst_ip,uint16_t dst_port,const void * payload,u_int payload_length)1579 switch_port_send_udp(switch_port_t port,
1580 uint8_t af,
1581 const ether_addr_t * src_eaddr,
1582 union ifbrip * src_ip,
1583 uint16_t src_port,
1584 const ether_addr_t * dst_eaddr,
1585 union ifbrip * dst_ip,
1586 uint16_t dst_port,
1587 const void * payload, u_int payload_length)
1588 {
1589 u_int frame_length;
1590 ether_packet pkt;
1591 ssize_t n;
1592
1593 /* make sure we can send */
1594 switch_port_check_tx(port);
1595
1596 /* generate the packet */
1597 frame_length
1598 = ethernet_udp_frame_populate((void *)&pkt,
1599 (u_int)sizeof(pkt),
1600 af,
1601 src_eaddr,
1602 src_ip,
1603 src_port,
1604 dst_eaddr,
1605 dst_ip,
1606 dst_port,
1607 payload,
1608 payload_length);
1609 T_QUIET;
1610 T_ASSERT_GT(frame_length, 0, NULL);
1611 if (S_debug) {
1612 T_LOG("Port %s transmitting %u bytes",
1613 port->ifname, frame_length);
1614 }
1615 ethernet_frame_validate(&pkt, frame_length, S_debug);
1616 n = write(port->fd, &pkt, frame_length);
1617 if (n < 0) {
1618 T_ASSERT_POSIX_SUCCESS(n, "%s write fd %d failed %ld",
1619 port->ifname, port->fd, n);
1620 }
1621 T_QUIET;
1622 T_ASSERT_EQ((u_int)n, frame_length,
1623 "%s fd %d wrote %ld",
1624 port->ifname, port->fd, n);
1625 }
1626
1627
1628
1629 static void
switch_port_send_udp_addr_index(switch_port_t port,uint8_t af,u_int addr_index,const ether_addr_t * dst_eaddr,union ifbrip * dst_ip,const void * payload,u_int payload_length)1630 switch_port_send_udp_addr_index(switch_port_t port,
1631 uint8_t af,
1632 u_int addr_index,
1633 const ether_addr_t * dst_eaddr,
1634 union ifbrip * dst_ip,
1635 const void * payload, u_int payload_length)
1636 {
1637 ether_addr_t eaddr;
1638 union ifbrip ip;
1639
1640 /* generate traffic for the unit and address */
1641 set_ethernet_address(&eaddr, port->unit, addr_index);
1642 get_ip_address(af, port->unit, addr_index, &ip);
1643 switch_port_send_udp(port, af,
1644 &eaddr, &ip, TEST_SOURCE_PORT,
1645 dst_eaddr, dst_ip, TEST_DEST_PORT,
1646 payload, payload_length);
1647 }
1648
1649 typedef void
1650 (packet_validator)(switch_port_t port, const ether_header_t * eh_p,
1651 u_int pkt_len, void * context);
1652 typedef packet_validator * packet_validator_t;
1653
1654 static void
switch_port_receive(switch_port_t port,uint8_t af,const void * payload,u_int payload_length,packet_validator_t validator,void * context)1655 switch_port_receive(switch_port_t port,
1656 uint8_t af,
1657 const void * payload, u_int payload_length,
1658 packet_validator_t validator,
1659 void * context)
1660 {
1661 ether_header_t * eh_p;
1662 ssize_t n;
1663 char * offset;
1664
1665 n = read(port->fd, port->rx_buf, (unsigned)port->rx_buf_size);
1666 if (n < 0) {
1667 if (errno == EAGAIN) {
1668 return;
1669 }
1670 T_QUIET;
1671 T_ASSERT_POSIX_SUCCESS(n, "read %s port %d fd %d",
1672 port->ifname, port->unit, port->fd);
1673 return;
1674 }
1675 for (offset = port->rx_buf; n > 0;) {
1676 struct bpf_hdr * bpf = (struct bpf_hdr *)(void *)offset;
1677 u_int pkt_len;
1678 char * pkt;
1679 u_int skip;
1680
1681 pkt = offset + bpf->bh_hdrlen;
1682 pkt_len = bpf->bh_caplen;
1683
1684 eh_p = (ether_header_t *)(void *)pkt;
1685 T_QUIET;
1686 T_ASSERT_GE(pkt_len, (u_int)sizeof(*eh_p),
1687 "short packet %ld", n);
1688
1689 /* source shouldn't be broadcast/multicast */
1690 T_QUIET;
1691 T_ASSERT_EQ(eh_p->ether_shost[0] & 0x01, 0,
1692 "broadcast/multicast source");
1693
1694 if (S_debug) {
1695 T_LOG("Port %s [unit %d] [fd %d] Received %u bytes",
1696 port->ifname, port->unit, port->fd, pkt_len);
1697 }
1698 ethernet_frame_validate(pkt, pkt_len, S_debug);
1699
1700 /* call the validation function */
1701 (*validator)(port, eh_p, pkt_len, context);
1702
1703 if (payload != NULL) {
1704 const void * p;
1705 u_int p_len;
1706
1707 p = ethernet_frame_get_udp_payload(af, pkt, pkt_len,
1708 &p_len);
1709 T_QUIET;
1710 T_ASSERT_NOTNULL(p, "ethernet_frame_get_udp_payload");
1711 T_QUIET;
1712 T_ASSERT_EQ(p_len, payload_length,
1713 "payload length %u < expected %u",
1714 p_len, payload_length);
1715 T_QUIET;
1716 T_ASSERT_EQ(bcmp(payload, p, payload_length), 0,
1717 "unexpected payload");
1718 }
1719 skip = BPF_WORDALIGN(pkt_len + bpf->bh_hdrlen);
1720 if (skip == 0) {
1721 break;
1722 }
1723 offset += skip;
1724 n -= skip;
1725 }
1726 return;
1727 }
1728
1729 static void
switch_port_log(switch_port_t port)1730 switch_port_log(switch_port_t port)
1731 {
1732 T_LOG("%s [unit %d] [member %s]%s bpf fd %d bufsize %d\n",
1733 port->ifname, port->unit,
1734 port->member_ifname,
1735 port->mac_nat ? " [mac-nat]" : "",
1736 port->fd, port->rx_buf_size);
1737 }
1738
1739 #define switch_port_list_size(port_count) \
1740 offsetof(switch_port_list, list[port_count])
1741
1742 static switch_port_list_t
switch_port_list_alloc(u_int port_count,bool mac_nat)1743 switch_port_list_alloc(u_int port_count, bool mac_nat)
1744 {
1745 switch_port_list_t list;
1746
1747 list = (switch_port_list_t)
1748 calloc(1, switch_port_list_size(port_count));;
1749 list->size = port_count;
1750 list->mac_nat = mac_nat;
1751 return list;
1752 }
1753
1754 static void
switch_port_list_dealloc(switch_port_list_t list)1755 switch_port_list_dealloc(switch_port_list_t list)
1756 {
1757 u_int i;
1758 switch_port_t port;
1759
1760 for (i = 0, port = list->list; i < list->count; i++, port++) {
1761 close(port->fd);
1762 free(port->rx_buf);
1763 }
1764 free(list);
1765 return;
1766 }
1767
1768 static errno_t
switch_port_list_add_port(int s,switch_port_list_t port_list,u_int unit,const char * ifname,u_short if_index,const char * member_ifname,u_int num_addrs,bool mac_nat,struct in_addr * ip)1769 switch_port_list_add_port(int s, switch_port_list_t port_list, u_int unit,
1770 const char * ifname, u_short if_index, const char * member_ifname,
1771 u_int num_addrs, bool mac_nat, struct in_addr * ip)
1772 {
1773 int buf_size;
1774 errno_t err = EINVAL;
1775 int fd = -1;
1776 char ntopbuf_ip[INET6_ADDRSTRLEN];
1777 int opt;
1778 switch_port_t p;
1779
1780 if (port_list->count >= port_list->size) {
1781 T_LOG("Internal error: port_list count %u >= size %u\n",
1782 port_list->count, port_list->size);
1783 goto failed;
1784 }
1785 fd = bpf_new();
1786 if (fd < 0) {
1787 err = errno;
1788 T_LOG("bpf_new");
1789 goto failed;
1790 }
1791 opt = 1;
1792 T_QUIET;
1793 T_ASSERT_POSIX_SUCCESS(ioctl(fd, FIONBIO, &opt), NULL);
1794 T_QUIET;
1795 T_ASSERT_POSIX_SUCCESS(bpf_set_immediate(fd, 1), NULL);
1796 T_QUIET;
1797 T_ASSERT_POSIX_SUCCESS(bpf_setif(fd, ifname), "bpf set if %s",
1798 ifname);
1799 T_QUIET;
1800 T_ASSERT_POSIX_SUCCESS(bpf_set_see_sent(fd, 0), NULL);
1801 T_QUIET;
1802 T_ASSERT_POSIX_SUCCESS(bpf_set_header_complete(fd, 1), NULL);
1803 T_QUIET;
1804 T_ASSERT_POSIX_SUCCESS(bpf_get_blen(fd, &buf_size), NULL);
1805 if (S_debug) {
1806 T_LOG("%s [unit %d] [member %s] bpf fd %d bufsize %d\n",
1807 ifname, unit,
1808 member_ifname, fd, buf_size);
1809 }
1810 p = port_list->list + port_list->count++;
1811 p->fd = fd;
1812 p->unit = unit;
1813 strlcpy(p->ifname, ifname, sizeof(p->ifname));
1814 strlcpy(p->member_ifname, member_ifname, sizeof(p->member_ifname));
1815 p->num_addrs = num_addrs;
1816 p->rx_buf_size = buf_size;
1817 p->rx_buf = malloc((unsigned)buf_size);
1818 p->mac_nat = mac_nat;
1819 ifnet_get_lladdr(s, ifname, &p->mac);
1820 ifnet_get_lladdr(s, member_ifname, &p->member_mac);
1821 p->ip = *ip;
1822 p->if_index = if_index;
1823 get_ipv6_ll_address(&p->mac, &p->ip6);
1824 inet_ntop(AF_INET6, &p->ip6, ntopbuf_ip, sizeof(ntopbuf_ip));
1825 T_LOG("%s %s", ifname, ntopbuf_ip);
1826 return 0;
1827
1828 failed:
1829 if (fd >= 0) {
1830 close(fd);
1831 }
1832 return err;
1833 }
1834
1835 static switch_port_t
switch_port_list_find_fd(switch_port_list_t ports,int fd)1836 switch_port_list_find_fd(switch_port_list_t ports, int fd)
1837 {
1838 u_int i;
1839 switch_port_t port;
1840
1841 for (i = 0, port = ports->list; i < ports->count; i++, port++) {
1842 if (port->fd == fd) {
1843 return port;
1844 }
1845 }
1846 return NULL;
1847 }
1848
1849 static void
switch_port_list_log(switch_port_list_t port_list)1850 switch_port_list_log(switch_port_list_t port_list)
1851 {
1852 u_int i;
1853 switch_port_t port;
1854
1855 for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
1856 switch_port_log(port);
1857 }
1858 return;
1859 }
1860
1861 static switch_port_t
switch_port_list_find_member(switch_port_list_t ports,const char * member_ifname)1862 switch_port_list_find_member(switch_port_list_t ports, const char * member_ifname)
1863 {
1864 u_int i;
1865 switch_port_t port;
1866
1867 for (i = 0, port = ports->list; i < ports->count; i++, port++) {
1868 if (strcmp(port->member_ifname, member_ifname) == 0) {
1869 return port;
1870 }
1871 }
1872 return NULL;
1873 }
1874
1875 static void
switch_port_list_check_receive(switch_port_list_t ports,uint8_t af,const void * payload,u_int payload_length,packet_validator_t validator,void * context)1876 switch_port_list_check_receive(switch_port_list_t ports, uint8_t af,
1877 const void * payload, u_int payload_length,
1878 packet_validator_t validator,
1879 void * context)
1880 {
1881 int i;
1882 int n_events;
1883 struct kevent kev[ports->count];
1884 int kq;
1885 switch_port_t port;
1886 struct timespec ts = { .tv_sec = 0, .tv_nsec = 10 * 1000 * 1000};
1887 u_int u;
1888
1889 kq = kqueue();
1890 T_QUIET;
1891 T_ASSERT_POSIX_SUCCESS(kq, "kqueue check_receive");
1892 for (u = 0, port = ports->list; u < ports->count; u++, port++) {
1893 port->test_count = 0;
1894 EV_SET(kev + u, port->fd,
1895 EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL);
1896 }
1897
1898 do {
1899 n_events = kevent(kq, kev, (int)ports->count, kev,
1900 (int)ports->count, &ts);
1901 T_QUIET;
1902 T_ASSERT_POSIX_SUCCESS(n_events, "kevent receive %d", n_events);
1903 for (i = 0; i < n_events; i++) {
1904 T_QUIET;
1905 T_ASSERT_EQ((int)kev[i].filter, EVFILT_READ, NULL);
1906 T_QUIET;
1907 T_ASSERT_NULL(kev[i].udata, NULL);
1908 port = switch_port_list_find_fd(ports,
1909 (int)kev[i].ident);
1910 T_QUIET;
1911 T_ASSERT_NE(port, NULL,
1912 "port %p fd %d", (void *)port,
1913 (int)kev[i].ident);
1914 switch_port_receive(port, af, payload, payload_length,
1915 validator, context);
1916 }
1917 } while (n_events != 0);
1918 close(kq);
1919 }
1920
1921 static bool
switch_port_list_verify_rt_table(switch_port_list_t port_list,bool log)1922 switch_port_list_verify_rt_table(switch_port_list_t port_list, bool log)
1923 {
1924 bool all_present = true;
1925 u_int i;
1926 u_int count;
1927 struct ifbareq *ifba;
1928 struct ifbareq *rt_table;
1929 switch_port_t port;
1930
1931 /* clear out current notion of how many addresses are present */
1932 for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
1933 port->test_address_count = 0;
1934 port->test_address_present = 0;
1935 }
1936 rt_table = bridge_rt_table_copy(&count);
1937 if (rt_table == NULL) {
1938 return false;
1939 }
1940 if (log) {
1941 bridge_rt_table_log(rt_table, count);
1942 }
1943 for (i = 0, ifba = rt_table; i < count; i++, ifba++) {
1944 uint64_t addr_bit;
1945 u_int addr_index;
1946 u_int unit_index;
1947 u_char * ea;
1948 ether_addr_t * eaddr;
1949
1950 eaddr = (ether_addr_t *)&ifba->ifba_dst;
1951 ea = eaddr->octet;
1952 addr_index = ea[EA_ADDR_INDEX];
1953 unit_index = ea[EA_UNIT_INDEX];
1954 port = switch_port_list_find_member(port_list,
1955 ifba->ifba_ifsname);
1956 T_QUIET;
1957 T_ASSERT_NOTNULL(port, "switch_port_list_find_member %s",
1958 ifba->ifba_ifsname);
1959 if (!S_cleaning_up) {
1960 T_QUIET;
1961 T_ASSERT_EQ(unit_index, port->unit, NULL);
1962 addr_bit = 1 << addr_index;
1963 T_QUIET;
1964 T_ASSERT_BITS_NOTSET(port->test_address_present,
1965 addr_bit, "%s address %u",
1966 ifba->ifba_ifsname, addr_index);
1967 port->test_address_present |= addr_bit;
1968 port->test_address_count++;
1969 }
1970 }
1971 for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
1972 if (S_debug) {
1973 T_LOG("%s unit %d [member %s] %u expect %u",
1974 port->ifname, port->unit, port->member_ifname,
1975 port->test_address_count, port->num_addrs);
1976 }
1977 if (port->test_address_count != port->num_addrs) {
1978 all_present = false;
1979 }
1980 }
1981
1982 free(rt_table);
1983 return all_present;
1984 }
1985
1986 static bool
switch_port_list_verify_mac_nat(switch_port_list_t port_list,bool log)1987 switch_port_list_verify_mac_nat(switch_port_list_t port_list, bool log)
1988 {
1989 bool all_present = true;
1990 u_int i;
1991 u_int count;
1992 static struct ifbrmne * entries;
1993 switch_port_t port;
1994 struct ifbrmne * scan;
1995
1996
1997 /* clear out current notion of how many addresses are present */
1998 for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
1999 port->test_address_count = 0;
2000 port->test_address_present = 0;
2001 }
2002 entries = bridge_mac_nat_entries_copy(&count);
2003 if (entries == NULL) {
2004 return false;
2005 }
2006 if (log) {
2007 bridge_mac_nat_entries_log(entries, count);
2008 }
2009 for (i = 0, scan = entries; i < count; i++, scan++) {
2010 uint8_t af;
2011 uint64_t addr_bit;
2012 u_int addr_index;
2013 char buf_ip1[INET6_ADDRSTRLEN];
2014 char buf_ip2[INET6_ADDRSTRLEN];
2015 u_char * ea;
2016 ether_addr_t * eaddr;
2017 union ifbrip ip;
2018 u_int unit_index;
2019
2020 eaddr = (ether_addr_t *)&scan->ifbmne_mac;
2021 ea = eaddr->octet;
2022 addr_index = ea[EA_ADDR_INDEX];
2023 unit_index = ea[EA_UNIT_INDEX];
2024 port = switch_port_list_find_member(port_list,
2025 scan->ifbmne_ifname);
2026 T_QUIET;
2027 T_ASSERT_NOTNULL(port,
2028 "switch_port_list_find_member %s",
2029 scan->ifbmne_ifname);
2030 T_QUIET;
2031 T_ASSERT_EQ(unit_index, port->unit, NULL);
2032 af = scan->ifbmne_af;
2033 get_ip_address(af, port->unit, addr_index, &ip);
2034 addr_bit = 1 << addr_index;
2035 T_QUIET;
2036 T_ASSERT_TRUE(ip_addresses_are_equal(af, &ip, &scan->ifbmne_ip),
2037 "mac nat entry IP address %s expected %s",
2038 inet_ntop(af, &scan->ifbmne_ip_addr,
2039 buf_ip1, sizeof(buf_ip1)),
2040 inet_ntop(af, &ip,
2041 buf_ip2, sizeof(buf_ip2)));
2042 T_QUIET;
2043 T_ASSERT_BITS_NOTSET(port->test_address_present,
2044 addr_bit, "%s address %u",
2045 scan->ifbmne_ifname, addr_index);
2046 port->test_address_present |= addr_bit;
2047 port->test_address_count++;
2048 }
2049 for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
2050 if (port->mac_nat) {
2051 /* MAC-NAT interface should have no entries */
2052 T_QUIET;
2053 T_ASSERT_EQ(port->test_address_count, 0,
2054 "mac nat interface %s has %u entries",
2055 port->member_ifname,
2056 port->test_address_count);
2057 } else {
2058 if (S_debug) {
2059 T_LOG("%s unit %d [member %s] %u expect %u",
2060 port->ifname, port->unit,
2061 port->member_ifname,
2062 port->test_address_count, port->num_addrs);
2063 }
2064 if (port->test_address_count != port->num_addrs) {
2065 all_present = false;
2066 }
2067 }
2068 }
2069
2070 free(entries);
2071
2072 return all_present;
2073 }
2074
2075 /**
2076 ** Basic Bridge Tests
2077 **/
2078 static void
send_generation(switch_port_t port,uint8_t af,u_int addr_index,const ether_addr_t * dst_eaddr,union ifbrip * dst_ip,uint32_t generation)2079 send_generation(switch_port_t port, uint8_t af, u_int addr_index,
2080 const ether_addr_t * dst_eaddr, union ifbrip * dst_ip,
2081 uint32_t generation)
2082 {
2083 uint32_t payload;
2084
2085 payload = htonl(generation);
2086 switch_port_send_udp_addr_index(port, af, addr_index, dst_eaddr, dst_ip,
2087 &payload, sizeof(payload));
2088 }
2089
2090 static void
check_receive_generation(switch_port_list_t ports,uint8_t af,uint32_t generation,packet_validator_t validator,__unused void * context)2091 check_receive_generation(switch_port_list_t ports, uint8_t af,
2092 uint32_t generation, packet_validator_t validator,
2093 __unused void * context)
2094 {
2095 uint32_t payload;
2096
2097 payload = htonl(generation);
2098 switch_port_list_check_receive(ports, af, &payload, sizeof(payload),
2099 validator, context);
2100 }
2101
2102 static void
validate_source_ether_mismatch(switch_port_t port,const ether_header_t * eh_p)2103 validate_source_ether_mismatch(switch_port_t port, const ether_header_t * eh_p)
2104 {
2105 /* source shouldn't be our own MAC addresses */
2106 T_QUIET;
2107 T_ASSERT_NE(eh_p->ether_shost[EA_UNIT_INDEX], port->unit,
2108 "ether source matches unit %d", port->unit);
2109 }
2110
2111 static void
validate_not_present_dhost(switch_port_t port,const ether_header_t * eh_p,__unused u_int pkt_len,__unused void * context)2112 validate_not_present_dhost(switch_port_t port, const ether_header_t * eh_p,
2113 __unused u_int pkt_len,
2114 __unused void * context)
2115 {
2116 validate_source_ether_mismatch(port, eh_p);
2117 T_QUIET;
2118 T_ASSERT_EQ(bcmp(eh_p->ether_dhost, ðer_external,
2119 sizeof(eh_p->ether_dhost)), 0,
2120 "%s", __func__);
2121 port->test_count++;
2122 }
2123
2124 static void
validate_broadcast_dhost(switch_port_t port,const ether_header_t * eh_p,__unused u_int pkt_len,__unused void * context)2125 validate_broadcast_dhost(switch_port_t port, const ether_header_t * eh_p,
2126 __unused u_int pkt_len,
2127 __unused void * context)
2128 {
2129 validate_source_ether_mismatch(port, eh_p);
2130 T_QUIET;
2131 T_ASSERT_NE((eh_p->ether_dhost[0] & 0x01), 0,
2132 "%s", __func__);
2133 port->test_count++;
2134 }
2135
2136 static void
validate_port_dhost(switch_port_t port,const ether_header_t * eh_p,__unused u_int pkt_len,__unused void * context)2137 validate_port_dhost(switch_port_t port, const ether_header_t * eh_p,
2138 __unused u_int pkt_len,
2139 __unused void * context)
2140 {
2141 validate_source_ether_mismatch(port, eh_p);
2142 T_QUIET;
2143 T_ASSERT_EQ(eh_p->ether_dhost[EA_UNIT_INDEX], port->unit,
2144 "wrong dhost unit %d != %d",
2145 eh_p->ether_dhost[EA_UNIT_INDEX], port->unit);
2146 port->test_count++;
2147 }
2148
2149
2150 static void
check_received_count(switch_port_list_t port_list,switch_port_t port,uint32_t expected_packets)2151 check_received_count(switch_port_list_t port_list,
2152 switch_port_t port, uint32_t expected_packets)
2153 {
2154 u_int i;
2155 switch_port_t scan;
2156
2157 for (i = 0, scan = port_list->list; i < port_list->count; i++, scan++) {
2158 if (scan == port) {
2159 T_QUIET;
2160 T_ASSERT_EQ(port->test_count, 0,
2161 "unexpected receive on port %d",
2162 port->unit);
2163 } else if (expected_packets == ALL_ADDRS) {
2164 T_QUIET;
2165 T_ASSERT_EQ(scan->test_count, scan->num_addrs,
2166 "didn't receive on all addrs");
2167 } else {
2168 T_QUIET;
2169 T_ASSERT_EQ(scan->test_count, expected_packets,
2170 "wrong receive count on port %s", scan->member_ifname);
2171 }
2172 }
2173 }
2174
2175 static void
unicast_send_all(switch_port_list_t port_list,uint8_t af,switch_port_t port)2176 unicast_send_all(switch_port_list_t port_list, uint8_t af, switch_port_t port)
2177 {
2178 u_int i;
2179 switch_port_t scan;
2180
2181 for (i = 0, scan = port_list->list; i < port_list->count; i++, scan++) {
2182 if (S_debug) {
2183 T_LOG("Unicast send on %s", port->ifname);
2184 }
2185 for (u_int j = 0; j < scan->num_addrs; j++) {
2186 ether_addr_t eaddr;
2187 union ifbrip ip;
2188
2189 set_ethernet_address(&eaddr, scan->unit, j);
2190 get_ip_address(af, scan->unit, j, &ip);
2191 switch_port_send_udp_addr_index(port, af, 0, &eaddr, &ip,
2192 NULL, 0);
2193 }
2194 }
2195 }
2196
2197
2198 static void
bridge_learning_test_once(switch_port_list_t port_list,uint8_t af,packet_validator_t validator,void * context,const ether_addr_t * dst_eaddr,bool retry)2199 bridge_learning_test_once(switch_port_list_t port_list,
2200 uint8_t af,
2201 packet_validator_t validator,
2202 void * context,
2203 const ether_addr_t * dst_eaddr,
2204 bool retry)
2205 {
2206 u_int i;
2207 union ifbrip dst_ip;
2208 switch_port_t port;
2209
2210 get_broadcast_ip_address(af, &dst_ip);
2211 for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
2212 if (port->test_address_count == port->num_addrs) {
2213 /* already populated */
2214 continue;
2215 }
2216 if (S_debug) {
2217 T_LOG("Sending on %s", port->ifname);
2218 }
2219 for (u_int j = 0; j < port->num_addrs; j++) {
2220 uint32_t generation;
2221
2222 if (retry) {
2223 uint64_t addr_bit;
2224
2225 addr_bit = 1 << j;
2226 if ((port->test_address_present & addr_bit)
2227 != 0) {
2228 /* already present */
2229 continue;
2230 }
2231 T_LOG("Retry port %s unit %u address %u",
2232 port->ifname, port->unit, j);
2233 }
2234 generation = next_generation();
2235 send_generation(port,
2236 af,
2237 j,
2238 dst_eaddr,
2239 &dst_ip,
2240 generation);
2241
2242 /* receive across all ports */
2243 check_receive_generation(port_list,
2244 af,
2245 generation,
2246 validator,
2247 context);
2248
2249 /* ensure that every port saw the packet */
2250 check_received_count(port_list, port, 1);
2251 }
2252 }
2253 return;
2254 }
2255
2256 static inline const char *
af_get_str(uint8_t af)2257 af_get_str(uint8_t af)
2258 {
2259 return (af == AF_INET) ? "IPv4" : "IPv6";
2260 }
2261
2262 static void
bridge_learning_test(switch_port_list_t port_list,uint8_t af,packet_validator_t validator,void * context,const ether_addr_t * dst_eaddr)2263 bridge_learning_test(switch_port_list_t port_list,
2264 uint8_t af,
2265 packet_validator_t validator,
2266 void * context,
2267 const ether_addr_t * dst_eaddr)
2268 {
2269 char ntoabuf[ETHER_NTOA_BUFSIZE];
2270 u_int i;
2271 switch_port_t port;
2272 bool verified = false;
2273
2274 ether_ntoa_buf(dst_eaddr, ntoabuf, sizeof(ntoabuf));
2275
2276 /*
2277 * Send a broadcast frame from every port in the list so that the bridge
2278 * learns our MAC address.
2279 */
2280 #define BROADCAST_MAX_TRIES 20
2281 for (int try = 1; try < BROADCAST_MAX_TRIES; try++) {
2282 bool retry = (try > 1);
2283
2284 if (!retry) {
2285 T_LOG("%s: %s #ports %u #addrs %u dest %s",
2286 __func__,
2287 af_get_str(af),
2288 port_list->count, port_list->list->num_addrs,
2289 ntoabuf);
2290 } else {
2291 T_LOG("%s: %s #ports %u #addrs %u dest %s (TRY=%d)",
2292 __func__,
2293 af_get_str(af),
2294 port_list->count, port_list->list->num_addrs,
2295 ntoabuf, try);
2296 }
2297 bridge_learning_test_once(port_list, af, validator, context,
2298 dst_eaddr, retry);
2299 /*
2300 * In the event of a memory allocation failure, it's possible
2301 * that the address was not learned. Figure out whether
2302 * all addresses are present, and if not, we'll retry on
2303 * those that are not present.
2304 */
2305 verified = switch_port_list_verify_rt_table(port_list, false);
2306 if (verified) {
2307 break;
2308 }
2309 /* wait a short time to allow the system to recover */
2310 usleep(100 * 1000);
2311 }
2312 T_QUIET;
2313 T_ASSERT_TRUE(verified, "All addresses present");
2314
2315 /*
2316 * Since we just broadcast on every port in the switch, the bridge knows
2317 * the port's MAC addresses. The bridge should not need to broadcast the
2318 * packet to learn, which means the unicast traffic should only arrive
2319 * on the intended port.
2320 */
2321 for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
2322 /* send unicast packets to every other port's MAC addresses */
2323 unicast_send_all(port_list, af, port);
2324
2325 /* receive all of that generated traffic */
2326 switch_port_list_check_receive(port_list, af, NULL, 0,
2327 validate_port_dhost, NULL);
2328 /* check that we saw all of the unicast packets */
2329 check_received_count(port_list, port, ALL_ADDRS);
2330 }
2331 T_PASS("%s", __func__);
2332 }
2333
2334 /**
2335 ** MAC-NAT tests
2336 **/
2337 static void
mac_nat_check_received_count(switch_port_list_t port_list,switch_port_t port)2338 mac_nat_check_received_count(switch_port_list_t port_list, switch_port_t port)
2339 {
2340 u_int i;
2341 switch_port_t scan;
2342
2343 for (i = 0, scan = port_list->list; i < port_list->count; i++, scan++) {
2344 u_int expected = 0;
2345
2346 if (scan == port) {
2347 expected = scan->num_addrs;
2348 }
2349 T_QUIET;
2350 T_ASSERT_EQ(scan->test_count, expected,
2351 "%s [member %s]%s expected %u actual %u",
2352 scan->ifname, scan->member_ifname,
2353 scan->mac_nat ? " [mac-nat]" : "",
2354 expected, scan->test_count);
2355 }
2356 }
2357
2358 static void
validate_mac_nat(switch_port_t port,const ether_header_t * eh_p,__unused u_int pkt_len,__unused void * context)2359 validate_mac_nat(switch_port_t port, const ether_header_t * eh_p,
2360 __unused u_int pkt_len,
2361 __unused void * context)
2362 {
2363 if (port->mac_nat) {
2364 bool equal;
2365
2366 /* source must match MAC-NAT interface */
2367 equal = (bcmp(eh_p->ether_shost, &port->member_mac,
2368 sizeof(port->member_mac)) == 0);
2369 if (!equal) {
2370 ethernet_frame_validate(eh_p, pkt_len, true);
2371 }
2372 T_QUIET;
2373 T_ASSERT_TRUE(equal, "source address match");
2374 port->test_count++;
2375 } else {
2376 validate_not_present_dhost(port, eh_p, pkt_len, NULL);
2377 }
2378 }
2379
2380 static void
validate_mac_nat_in(switch_port_t port,const ether_header_t * eh_p,u_int pkt_len,__unused void * context)2381 validate_mac_nat_in(switch_port_t port, const ether_header_t * eh_p,
2382 u_int pkt_len, __unused void * context)
2383 {
2384 if (S_debug) {
2385 T_LOG("%s received %u bytes", port->member_ifname, pkt_len);
2386 ethernet_frame_validate(eh_p, pkt_len, true);
2387 }
2388 T_QUIET;
2389 T_ASSERT_EQ(eh_p->ether_dhost[EA_UNIT_INDEX], port->unit,
2390 "dhost unit %u expected %u",
2391 eh_p->ether_dhost[EA_UNIT_INDEX], port->unit);
2392 port->test_count++;
2393 }
2394
2395 static void
validate_mac_nat_arp_out(switch_port_t port,const ether_header_t * eh_p,u_int pkt_len,void * context)2396 validate_mac_nat_arp_out(switch_port_t port, const ether_header_t * eh_p,
2397 u_int pkt_len, void * context)
2398 {
2399 const struct ether_arp * earp;
2400 switch_port_t send_port = (switch_port_t)context;
2401
2402 if (S_debug) {
2403 T_LOG("%s received %u bytes", port->member_ifname, pkt_len);
2404 ethernet_frame_validate(eh_p, pkt_len, true);
2405 }
2406 T_QUIET;
2407 T_ASSERT_EQ((int)ntohs(eh_p->ether_type), (int)ETHERTYPE_ARP, NULL);
2408 earp = (const struct ether_arp *)(const void *)(eh_p + 1);
2409 T_QUIET;
2410 T_ASSERT_GE(pkt_len, (u_int)(sizeof(*eh_p) + sizeof(*earp)), NULL);
2411 if (port->mac_nat) {
2412 bool equal;
2413
2414 /* source ethernet must match MAC-NAT interface */
2415 equal = (bcmp(eh_p->ether_shost, &port->member_mac,
2416 sizeof(port->member_mac)) == 0);
2417 if (!equal) {
2418 ethernet_frame_validate(eh_p, pkt_len, true);
2419 }
2420 T_QUIET;
2421 T_ASSERT_TRUE(equal, "%s -> %s source address translated",
2422 send_port->member_ifname,
2423 port->member_ifname);
2424 /* sender hw must match MAC-NAT interface */
2425 equal = (bcmp(earp->arp_sha, &port->member_mac,
2426 sizeof(port->member_mac)) == 0);
2427 if (!equal) {
2428 ethernet_frame_validate(eh_p, pkt_len, true);
2429 }
2430 T_QUIET;
2431 T_ASSERT_TRUE(equal, "%s -> %s sender hardware translated",
2432 send_port->member_ifname,
2433 port->member_ifname);
2434 } else {
2435 /* source ethernet must match the sender */
2436 T_QUIET;
2437 T_ASSERT_EQ(eh_p->ether_shost[EA_UNIT_INDEX], send_port->unit,
2438 "%s -> %s unit %u expected %u",
2439 send_port->member_ifname,
2440 port->member_ifname,
2441 eh_p->ether_shost[EA_UNIT_INDEX], send_port->unit);
2442 /* source hw must match the sender */
2443 T_QUIET;
2444 T_ASSERT_EQ(earp->arp_sha[EA_UNIT_INDEX], send_port->unit,
2445 "%s -> %s unit %u expected %u",
2446 send_port->member_ifname,
2447 port->member_ifname,
2448 earp->arp_sha[EA_UNIT_INDEX], send_port->unit);
2449 }
2450 port->test_count++;
2451 }
2452
2453 static void
validate_mac_nat_arp_in(switch_port_t port,const ether_header_t * eh_p,u_int pkt_len,void * context)2454 validate_mac_nat_arp_in(switch_port_t port, const ether_header_t * eh_p,
2455 u_int pkt_len, void * context)
2456 {
2457 const struct ether_arp * earp;
2458 switch_port_t send_port = (switch_port_t)context;
2459
2460 if (S_debug) {
2461 T_LOG("%s received %u bytes", port->member_ifname, pkt_len);
2462 ethernet_frame_validate(eh_p, pkt_len, true);
2463 }
2464 earp = (const struct ether_arp *)(const void *)(eh_p + 1);
2465 T_QUIET;
2466 T_ASSERT_EQ((int)ntohs(eh_p->ether_type), (int)ETHERTYPE_ARP, NULL);
2467 T_QUIET;
2468 T_ASSERT_GE(pkt_len, (u_int)(sizeof(*eh_p) + sizeof(*earp)), NULL);
2469 T_QUIET;
2470 T_ASSERT_FALSE(port->mac_nat, NULL);
2471
2472 /* destination ethernet must match the unit */
2473 T_QUIET;
2474 T_ASSERT_EQ(eh_p->ether_dhost[EA_UNIT_INDEX], port->unit,
2475 "%s -> %s unit %u expected %u",
2476 send_port->member_ifname,
2477 port->member_ifname,
2478 eh_p->ether_dhost[EA_UNIT_INDEX], port->unit);
2479 /* source hw must match the sender */
2480 T_QUIET;
2481 T_ASSERT_EQ(earp->arp_tha[EA_UNIT_INDEX], port->unit,
2482 "%s -> %s unit %u expected %u",
2483 send_port->member_ifname,
2484 port->member_ifname,
2485 earp->arp_tha[EA_UNIT_INDEX], port->unit);
2486 port->test_count++;
2487 }
2488
2489 static void
mac_nat_test_arp_out(switch_port_list_t port_list)2490 mac_nat_test_arp_out(switch_port_list_t port_list)
2491 {
2492 u_int i;
2493 struct in_addr ip_dst;
2494 switch_port_t port;
2495
2496 ip_dst = get_external_ipv4_address();
2497 for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
2498 if (port->mac_nat) {
2499 continue;
2500 }
2501 for (u_int j = 0; j < port->num_addrs; j++) {
2502 ether_addr_t eaddr;
2503 struct in_addr ip_src;
2504
2505 set_ethernet_address(&eaddr, port->unit, j);
2506 get_ipv4_address(port->unit, j, &ip_src);
2507 switch_port_send_arp(port,
2508 ARPOP_REQUEST,
2509 &eaddr,
2510 ip_src,
2511 NULL,
2512 ip_dst);
2513 switch_port_list_check_receive(port_list, AF_INET,
2514 NULL, 0,
2515 validate_mac_nat_arp_out,
2516 port);
2517 check_received_count(port_list, port, 1);
2518 }
2519 }
2520 T_PASS("%s", __func__);
2521 }
2522
2523 static void
mac_nat_send_arp_response(switch_port_t ext_port,switch_port_t port)2524 mac_nat_send_arp_response(switch_port_t ext_port, switch_port_t port)
2525 {
2526 struct in_addr ip_src;
2527
2528 T_QUIET;
2529 T_ASSERT_TRUE(ext_port->mac_nat, "%s is MAC-NAT interface",
2530 ext_port->member_ifname);
2531 ip_src = get_external_ipv4_address();
2532 for (u_int j = 0; j < port->num_addrs; j++) {
2533 struct in_addr ip_dst;
2534
2535 get_ipv4_address(port->unit, j, &ip_dst);
2536 if (S_debug) {
2537 T_LOG("Generating ARP destined to %s %s",
2538 port->ifname, inet_ntoa(ip_dst));
2539 }
2540 switch_port_send_arp(ext_port,
2541 ARPOP_REPLY,
2542 ðer_external,
2543 ip_src,
2544 &ext_port->member_mac,
2545 ip_dst);
2546 }
2547 }
2548
2549 static void
mac_nat_test_arp_in(switch_port_list_t port_list)2550 mac_nat_test_arp_in(switch_port_list_t port_list)
2551 {
2552 u_int i;
2553 struct in_addr ip_src;
2554 switch_port_t port;
2555
2556 ip_src = get_external_ipv4_address();
2557 for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
2558 if (port->mac_nat) {
2559 continue;
2560 }
2561 mac_nat_send_arp_response(port_list->list, port);
2562
2563 /* receive the generated traffic */
2564 switch_port_list_check_receive(port_list, AF_INET, NULL, 0,
2565 validate_mac_nat_arp_in,
2566 port_list->list);
2567
2568 /* verify that only the single port got the packet */
2569 mac_nat_check_received_count(port_list, port);
2570 }
2571 T_PASS("%s", __func__);
2572 }
2573
2574 static void
validate_mac_nat_dhcp(switch_port_t port,const ether_header_t * eh_p,u_int pkt_len,void * context)2575 validate_mac_nat_dhcp(switch_port_t port, const ether_header_t * eh_p,
2576 u_int pkt_len, void * context)
2577 {
2578 u_int dp_flags;
2579 const struct bootp_packet * pkt;
2580 switch_port_t send_port = (switch_port_t)context;
2581
2582
2583 T_QUIET;
2584 T_ASSERT_GE(pkt_len, (u_int)sizeof(*pkt), NULL);
2585 T_QUIET;
2586 T_ASSERT_EQ((int)ntohs(eh_p->ether_type), (int)ETHERTYPE_IP, NULL);
2587 pkt = (const struct bootp_packet *)(const void *)(eh_p + 1);
2588
2589 dp_flags = ntohs(pkt->bp_bootp.bp_unused);
2590 if (port->mac_nat) {
2591 bool equal;
2592
2593 /* Broadcast bit must be set */
2594 T_QUIET;
2595 T_ASSERT_BITS_SET(dp_flags, (u_int)DHCP_FLAGS_BROADCAST,
2596 "%s -> %s: flags 0x%x must have 0x%x",
2597 send_port->member_ifname,
2598 port->member_ifname,
2599 dp_flags, DHCP_FLAGS_BROADCAST);
2600
2601 /* source must match MAC-NAT interface */
2602 equal = (bcmp(eh_p->ether_shost, &port->member_mac,
2603 sizeof(port->member_mac)) == 0);
2604 if (!equal) {
2605 ethernet_frame_validate(eh_p, pkt_len, true);
2606 }
2607 T_QUIET;
2608 T_ASSERT_TRUE(equal, "%s -> %s source address translated",
2609 send_port->member_ifname,
2610 port->member_ifname);
2611 } else {
2612 /* Broadcast bit must not be set */
2613 T_QUIET;
2614 T_ASSERT_BITS_NOTSET(dp_flags, DHCP_FLAGS_BROADCAST,
2615 "%s -> %s flags 0x%x must not have 0x%x",
2616 send_port->member_ifname,
2617 port->member_ifname,
2618 dp_flags, DHCP_FLAGS_BROADCAST);
2619 T_QUIET;
2620 T_ASSERT_EQ(eh_p->ether_shost[EA_UNIT_INDEX], send_port->unit,
2621 "%s -> %s unit %u expected %u",
2622 send_port->member_ifname,
2623 port->member_ifname,
2624 eh_p->ether_shost[EA_UNIT_INDEX], send_port->unit);
2625 }
2626 port->test_count++;
2627 }
2628
2629 static u_int
make_dhcp_payload(dhcp_min_payload_t payload,ether_addr_t * eaddr)2630 make_dhcp_payload(dhcp_min_payload_t payload, ether_addr_t *eaddr)
2631 {
2632 struct bootp * dhcp;
2633 u_int payload_length;
2634
2635 /* create a minimal BOOTP packet */
2636 payload_length = sizeof(*payload);
2637 dhcp = (struct bootp *)payload;
2638 bzero(dhcp, payload_length);
2639 dhcp->bp_op = BOOTREQUEST;
2640 dhcp->bp_htype = ARPHRD_ETHER;
2641 dhcp->bp_hlen = sizeof(*eaddr);
2642 bcopy(eaddr->octet, dhcp->bp_chaddr, sizeof(eaddr->octet));
2643 return payload_length;
2644 }
2645
2646 static void
mac_nat_test_dhcp(switch_port_list_t port_list,bool link_layer_unicast)2647 mac_nat_test_dhcp(switch_port_list_t port_list, bool link_layer_unicast)
2648 {
2649 u_int i;
2650 struct in_addr ip_dst = { INADDR_BROADCAST };
2651 struct in_addr ip_src = { INADDR_ANY };
2652 switch_port_t port;
2653 ether_addr_t * ether_dst;
2654
2655 if (link_layer_unicast) {
2656 /* use link-layer address of MAC-NAT interface */
2657 ether_dst = &port_list->list[0].member_mac;
2658 } else {
2659 /* use link-layer broadcast address */
2660 ether_dst = ðer_broadcast;
2661 }
2662 for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
2663 ether_addr_t eaddr;
2664 dhcp_min_payload payload;
2665 u_int payload_len;
2666
2667 if (!link_layer_unicast && port->mac_nat) {
2668 /* only send through non-MAC-NAT ports */
2669 continue;
2670 }
2671 set_ethernet_address(&eaddr, port->unit, 0);
2672 payload_len = make_dhcp_payload(&payload, &eaddr);
2673 if (S_debug) {
2674 T_LOG("%s: transmit DHCP packet (member %s)",
2675 port->ifname, port->member_ifname);
2676 }
2677 switch_port_send_udp(port,
2678 AF_INET,
2679 &eaddr,
2680 (union ifbrip *)&ip_src,
2681 BOOTP_CLIENT_PORT,
2682 ether_dst,
2683 (union ifbrip *)&ip_dst,
2684 BOOTP_SERVER_PORT,
2685 &payload,
2686 payload_len);
2687
2688 switch_port_list_check_receive(port_list, AF_INET, NULL, 0,
2689 validate_mac_nat_dhcp,
2690 port);
2691
2692 check_received_count(port_list, port, 1);
2693 if (link_layer_unicast) {
2694 /* send a single unicast to MAC-NAT interface */
2695 break;
2696 }
2697 }
2698 T_PASS("%s %s", __func__,
2699 link_layer_unicast ? "unicast" : "broadcast");
2700 }
2701
2702
2703 static void
validate_mac_nat_nd6(switch_port_t port,const struct icmp6_hdr * icmp6,u_int icmp6_len,uint8_t opt_type,u_int nd_hdr_size,switch_port_t send_port)2704 validate_mac_nat_nd6(switch_port_t port,
2705 const struct icmp6_hdr * icmp6,
2706 u_int icmp6_len,
2707 uint8_t opt_type,
2708 u_int nd_hdr_size,
2709 switch_port_t send_port)
2710 {
2711 const uint8_t * linkaddr;
2712 const uint8_t * ptr;
2713 const struct nd_opt_hdr * nd_opt;
2714 u_int nd_size;
2715
2716 ptr = (const uint8_t *)icmp6;
2717 nd_size = nd_hdr_size + LINKADDR_OPT_LEN;
2718 if (icmp6_len < nd_size) {
2719 /* no LINKADDR option */
2720 return;
2721 }
2722 nd_opt = (const struct nd_opt_hdr *)(const void *)(ptr + nd_hdr_size);
2723 T_QUIET;
2724 T_ASSERT_EQ(nd_opt->nd_opt_type, opt_type, NULL);
2725 T_QUIET;
2726 T_ASSERT_EQ(GET_ND_OPT_LEN(nd_opt->nd_opt_len), LINKADDR_OPT_LEN, NULL);
2727 linkaddr = (const uint8_t *)(nd_opt + 1);
2728 if (port->mac_nat) {
2729 bool equal;
2730
2731 equal = (bcmp(linkaddr, &port->member_mac,
2732 sizeof(port->member_mac)) == 0);
2733 T_QUIET;
2734 T_ASSERT_TRUE(equal, "%s -> %s sender hardware translated",
2735 send_port->member_ifname,
2736 port->member_ifname);
2737 } else {
2738 /* source hw must match the sender */
2739 T_QUIET;
2740 T_ASSERT_EQ(linkaddr[EA_UNIT_INDEX], send_port->unit,
2741 "%s -> %s unit %u expected %u",
2742 send_port->member_ifname,
2743 port->member_ifname,
2744 linkaddr[EA_UNIT_INDEX], send_port->unit);
2745 }
2746 }
2747
2748 static void
validate_mac_nat_icmp6_out(switch_port_t port,const struct icmp6_hdr * icmp6,u_int icmp6_len,switch_port_t send_port)2749 validate_mac_nat_icmp6_out(switch_port_t port, const struct icmp6_hdr * icmp6,
2750 u_int icmp6_len, switch_port_t send_port)
2751 {
2752 switch (icmp6->icmp6_type) {
2753 case ND_NEIGHBOR_ADVERT:
2754 validate_mac_nat_nd6(port, icmp6, icmp6_len,
2755 ND_OPT_TARGET_LINKADDR,
2756 sizeof(struct nd_neighbor_advert),
2757 send_port);
2758 break;
2759 case ND_NEIGHBOR_SOLICIT:
2760 validate_mac_nat_nd6(port, icmp6, icmp6_len,
2761 ND_OPT_SOURCE_LINKADDR,
2762 sizeof(struct nd_neighbor_solicit),
2763 send_port);
2764 break;
2765 case ND_ROUTER_SOLICIT:
2766 validate_mac_nat_nd6(port, icmp6, icmp6_len,
2767 ND_OPT_SOURCE_LINKADDR,
2768 sizeof(struct nd_router_solicit),
2769 send_port);
2770 break;
2771 default:
2772 T_FAIL("Unsupported icmp6 type %d", icmp6->icmp6_type);
2773 break;
2774 }
2775 }
2776
2777 static void
validate_mac_nat_nd6_out(switch_port_t port,const ether_header_t * eh_p,u_int pkt_len,void * context)2778 validate_mac_nat_nd6_out(switch_port_t port, const ether_header_t * eh_p,
2779 u_int pkt_len, void * context)
2780 {
2781 const struct icmp6_hdr * icmp6;
2782 const struct ip6_hdr * ip6;
2783 switch_port_t send_port = (switch_port_t)context;
2784
2785 if (S_debug) {
2786 T_LOG("%s received %u bytes", port->member_ifname, pkt_len);
2787 ethernet_frame_validate(eh_p, pkt_len, true);
2788 }
2789 T_QUIET;
2790 T_ASSERT_EQ(ntohs(eh_p->ether_type), (u_short)ETHERTYPE_IPV6, NULL);
2791 ip6 = (const struct ip6_hdr *)(const void *)(eh_p + 1);
2792 icmp6 = (const struct icmp6_hdr *)(const void *)(ip6 + 1);
2793 T_QUIET;
2794 T_ASSERT_GE(pkt_len, (u_int)MIN_ICMP6_LEN, NULL);
2795 T_QUIET;
2796 T_ASSERT_EQ(ip6->ip6_nxt, IPPROTO_ICMPV6, NULL);
2797
2798 /* validate the ethernet header */
2799 if (port->mac_nat) {
2800 bool equal;
2801
2802 /* source ethernet must match MAC-NAT interface */
2803 equal = (bcmp(eh_p->ether_shost, &port->member_mac,
2804 sizeof(port->member_mac)) == 0);
2805 if (!equal) {
2806 ethernet_frame_validate(eh_p, pkt_len, true);
2807 }
2808 T_QUIET;
2809 T_ASSERT_TRUE(equal, "%s -> %s source address translated",
2810 send_port->member_ifname,
2811 port->member_ifname);
2812 } else {
2813 /* source ethernet must match the sender */
2814 T_QUIET;
2815 T_ASSERT_EQ(eh_p->ether_shost[EA_UNIT_INDEX], send_port->unit,
2816 "%s -> %s unit %u expected %u",
2817 send_port->member_ifname,
2818 port->member_ifname,
2819 eh_p->ether_shost[EA_UNIT_INDEX], send_port->unit);
2820 }
2821 /* validate the icmp6 payload */
2822 validate_mac_nat_icmp6_out(port, icmp6,
2823 pkt_len - ETHER_IPV6_LEN,
2824 send_port);
2825 port->test_count++;
2826 }
2827
2828 static void
mac_nat_test_nd6_out(switch_port_list_t port_list)2829 mac_nat_test_nd6_out(switch_port_list_t port_list)
2830 {
2831 ether_addr_t * ext_mac;
2832 switch_port_t ext_port;
2833 u_int i;
2834 union ifbrip ip_dst;
2835 switch_port_t port;
2836
2837 get_external_ip_address(AF_INET6, &ip_dst);
2838 ext_port = port_list->list;
2839 T_QUIET;
2840 T_ASSERT_TRUE(ext_port->mac_nat, NULL);
2841 ext_mac = &ext_port->member_mac;
2842 for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
2843 if (port->mac_nat) {
2844 continue;
2845 }
2846 /* neighbor solicit */
2847 for (u_int j = 0; j < port->num_addrs; j++) {
2848 ether_addr_t eaddr;
2849 union ifbrip ip_src;
2850
2851 set_ethernet_address(&eaddr, port->unit, j);
2852 get_ip_address(AF_INET6, port->unit, j, &ip_src);
2853 switch_port_send_nd6(port,
2854 ND_NEIGHBOR_SOLICIT,
2855 &eaddr,
2856 &ip_src.ifbrip_addr6,
2857 NULL,
2858 NULL,
2859 &ip_dst.ifbrip_addr6);
2860 switch_port_list_check_receive(port_list, AF_INET,
2861 NULL, 0,
2862 validate_mac_nat_nd6_out,
2863 port);
2864 check_received_count(port_list, port, 1);
2865 }
2866 /* neighbor advert */
2867 for (u_int j = 0; j < port->num_addrs; j++) {
2868 ether_addr_t eaddr;
2869 union ifbrip ip_src;
2870
2871 set_ethernet_address(&eaddr, port->unit, j);
2872 get_ip_address(AF_INET6, port->unit, j, &ip_src);
2873 switch_port_send_nd6(port,
2874 ND_NEIGHBOR_ADVERT,
2875 &eaddr,
2876 &ip_src.ifbrip_addr6,
2877 NULL,
2878 &eaddr,
2879 &ip_src.ifbrip_addr6);
2880 switch_port_list_check_receive(port_list, AF_INET,
2881 NULL, 0,
2882 validate_mac_nat_nd6_out,
2883 port);
2884 check_received_count(port_list, port, 1);
2885 }
2886 /* router solicit */
2887 for (u_int j = 0; j < port->num_addrs; j++) {
2888 ether_addr_t eaddr;
2889 union ifbrip ip_src;
2890
2891 set_ethernet_address(&eaddr, port->unit, j);
2892 get_ip_address(AF_INET6, port->unit, j, &ip_src);
2893 //get_ipv6ll_address(port->unit, j, &ip_src.ifbrip_addr6);
2894 switch_port_send_nd6(port,
2895 ND_ROUTER_SOLICIT,
2896 &eaddr,
2897 &ip_src.ifbrip_addr6,
2898 NULL,
2899 NULL,
2900 NULL);
2901 switch_port_list_check_receive(port_list, AF_INET,
2902 NULL, 0,
2903 validate_mac_nat_nd6_out,
2904 port);
2905 check_received_count(port_list, port, 1);
2906 }
2907 }
2908 T_PASS("%s", __func__);
2909 }
2910
2911 static void
mac_nat_send_response(switch_port_t ext_port,uint8_t af,switch_port_t port)2912 mac_nat_send_response(switch_port_t ext_port, uint8_t af, switch_port_t port)
2913 {
2914 union ifbrip src_ip;
2915
2916 T_QUIET;
2917 T_ASSERT_TRUE(ext_port->mac_nat, "%s is MAC-NAT interface",
2918 ext_port->member_ifname);
2919 if (S_debug) {
2920 T_LOG("Generating UDP traffic destined to %s", port->ifname);
2921 }
2922 get_external_ip_address(af, &src_ip);
2923 for (u_int j = 0; j < port->num_addrs; j++) {
2924 union ifbrip ip;
2925
2926 get_ip_address(af, port->unit, j, &ip);
2927 switch_port_send_udp(ext_port,
2928 af,
2929 ðer_external,
2930 &src_ip,
2931 TEST_DEST_PORT,
2932 &ext_port->member_mac,
2933 &ip,
2934 TEST_SOURCE_PORT,
2935 NULL, 0);
2936 }
2937 }
2938
2939
2940 static void
mac_nat_test_ip_once(switch_port_list_t port_list,uint8_t af,bool retry)2941 mac_nat_test_ip_once(switch_port_list_t port_list, uint8_t af, bool retry)
2942 {
2943 union ifbrip dst_ip;
2944 u_int i;
2945 switch_port_t port;
2946
2947 get_external_ip_address(af, &dst_ip);
2948 for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
2949 if (port->test_address_count == port->num_addrs) {
2950 /* already populated */
2951 continue;
2952 }
2953 if (S_debug) {
2954 T_LOG("Sending on %s", port->ifname);
2955 }
2956 for (u_int j = 0; j < port->num_addrs; j++) {
2957 uint32_t generation;
2958
2959 if (retry) {
2960 uint64_t addr_bit;
2961
2962 addr_bit = 1 << j;
2963 if ((port->test_address_present & addr_bit)
2964 != 0) {
2965 /* already present */
2966 continue;
2967 }
2968 T_LOG("Retry port %s unit %u address %u",
2969 port->ifname, port->unit, j);
2970 }
2971
2972 generation = next_generation();
2973 send_generation(port,
2974 af,
2975 j,
2976 ðer_external,
2977 &dst_ip,
2978 generation);
2979
2980 /* receive across all ports */
2981 check_receive_generation(port_list,
2982 af,
2983 generation,
2984 validate_mac_nat,
2985 NULL);
2986
2987 /* ensure that every port saw the packet */
2988 check_received_count(port_list, port, 1);
2989 }
2990 }
2991 return;
2992 }
2993
2994 static void
mac_nat_test_ip(switch_port_list_t port_list,uint8_t af)2995 mac_nat_test_ip(switch_port_list_t port_list, uint8_t af)
2996 {
2997 u_int i;
2998 switch_port_t port;
2999 bool verified = false;
3000
3001 /*
3002 * Send a packet from every port in the list so that the bridge
3003 * learns the MAC addresses and IP addresses.
3004 */
3005 #define MAC_NAT_MAX_TRIES 20
3006 for (int try = 1; try < BROADCAST_MAX_TRIES; try++) {
3007 bool retry = (try > 1);
3008
3009 if (!retry) {
3010 T_LOG("%s: #ports %u #addrs %u",
3011 __func__,
3012 port_list->count, port_list->list->num_addrs);
3013 } else {
3014 T_LOG("%s: #ports %u #addrs %u destination (TRY=%d)",
3015 __func__,
3016 port_list->count, port_list->list->num_addrs,
3017 try);
3018 }
3019 mac_nat_test_ip_once(port_list, af, retry);
3020 /*
3021 * In the event of a memory allocation failure, it's possible
3022 * that the address was not learned. Figure out whether
3023 * all addresses are present, and if not, we'll retry on
3024 * those that are not present.
3025 */
3026 verified = switch_port_list_verify_mac_nat(port_list, false);
3027 if (verified) {
3028 break;
3029 }
3030 /* wait a short time to allow the system to recover */
3031 usleep(100 * 1000);
3032 }
3033 T_QUIET;
3034 T_ASSERT_TRUE(verified, "All addresses present");
3035
3036 /*
3037 * The bridge now has an IP address <-> MAC address binding for every
3038 * address on each internal interface.
3039 *
3040 * Generate an inbound packet on the MAC-NAT interface targeting
3041 * each interface address. Verify that the packet appears on
3042 * the appropriate internal address with appropriate translation.
3043 */
3044 for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
3045 if (port->mac_nat) {
3046 continue;
3047 }
3048 mac_nat_send_response(port_list->list, af, port);
3049
3050 /* receive the generated traffic */
3051 switch_port_list_check_receive(port_list, AF_INET, NULL, 0,
3052 validate_mac_nat_in,
3053 NULL);
3054
3055 /* verify that only the single port got the packet */
3056 mac_nat_check_received_count(port_list, port);
3057 }
3058 T_PASS("%s", __func__);
3059 }
3060
3061 /**
3062 ** interface management
3063 **/
3064
3065 static void
ifnet_get_lladdr(int s,const char * ifname,ether_addr_t * eaddr)3066 ifnet_get_lladdr(int s, const char * ifname, ether_addr_t * eaddr)
3067 {
3068 int err;
3069 struct ifreq ifr;
3070
3071 bzero(&ifr, sizeof(ifr));
3072 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
3073 ifr.ifr_addr.sa_family = AF_LINK;
3074 ifr.ifr_addr.sa_len = ETHER_ADDR_LEN;
3075 err = ioctl(s, SIOCGIFLLADDR, &ifr);
3076 T_QUIET;
3077 T_ASSERT_POSIX_SUCCESS(err, "SIOCGIFLLADDR %s", ifname);
3078 bcopy(ifr.ifr_addr.sa_data, eaddr->octet, ETHER_ADDR_LEN);
3079 return;
3080 }
3081
3082
3083 static int
ifnet_attach_ip(int s,char * name)3084 ifnet_attach_ip(int s, char * name)
3085 {
3086 int err;
3087 struct ifreq ifr;
3088
3089 bzero(&ifr, sizeof(ifr));
3090 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
3091 err = ioctl(s, SIOCPROTOATTACH, &ifr);
3092 T_QUIET;
3093 T_ASSERT_POSIX_SUCCESS(err, "SIOCPROTOATTACH %s", ifr.ifr_name);
3094 return err;
3095 }
3096
3097 #if 0
3098 static int
3099 ifnet_detach_ip(int s, char * name)
3100 {
3101 int err;
3102 struct ifreq ifr;
3103
3104 bzero(&ifr, sizeof(ifr));
3105 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
3106 err = ioctl(s, SIOCPROTODETACH, &ifr);
3107 T_QUIET;
3108 T_ASSERT_POSIX_SUCCESS(err, "SIOCPROTODETACH %s", ifr.ifr_name);
3109 return err;
3110 }
3111 #endif
3112
3113 static int
ifnet_destroy(int s,const char * ifname,bool fail_on_error)3114 ifnet_destroy(int s, const char * ifname, bool fail_on_error)
3115 {
3116 int err;
3117 struct ifreq ifr;
3118
3119 bzero(&ifr, sizeof(ifr));
3120 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
3121 err = ioctl(s, SIOCIFDESTROY, &ifr);
3122 if (fail_on_error) {
3123 T_QUIET;
3124 T_ASSERT_POSIX_SUCCESS(err, "SIOCSIFDESTROY %s", ifr.ifr_name);
3125 }
3126 if (err < 0) {
3127 T_LOG("SIOCSIFDESTROY %s", ifr.ifr_name);
3128 }
3129 return err;
3130 }
3131
3132 static int
ifnet_set_flags(int s,const char * ifname,uint16_t flags_set,uint16_t flags_clear)3133 ifnet_set_flags(int s, const char * ifname,
3134 uint16_t flags_set, uint16_t flags_clear)
3135 {
3136 uint16_t flags_after;
3137 uint16_t flags_before;
3138 struct ifreq ifr;
3139 int ret;
3140
3141 bzero(&ifr, sizeof(ifr));
3142 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
3143 ret = ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr);
3144 if (ret != 0) {
3145 T_LOG("SIOCGIFFLAGS %s", ifr.ifr_name);
3146 return ret;
3147 }
3148 flags_before = (uint16_t)ifr.ifr_flags;
3149 ifr.ifr_flags |= flags_set;
3150 ifr.ifr_flags &= ~(flags_clear);
3151 flags_after = (uint16_t)ifr.ifr_flags;
3152 if (flags_before == flags_after) {
3153 /* nothing to do */
3154 ret = 0;
3155 } else {
3156 /* issue the ioctl */
3157 T_QUIET;
3158 T_ASSERT_POSIX_SUCCESS(ioctl(s, SIOCSIFFLAGS, &ifr),
3159 "SIOCSIFFLAGS %s 0x%x",
3160 ifr.ifr_name, (uint16_t)ifr.ifr_flags);
3161 if (S_debug) {
3162 T_LOG("setflags(%s set 0x%x clear 0x%x) 0x%x => 0x%x",
3163 ifr.ifr_name, flags_set, flags_clear,
3164 flags_before, flags_after);
3165 }
3166 }
3167 return ret;
3168 }
3169
3170 #define BRIDGE_NAME "bridge"
3171 #define BRIDGE200 BRIDGE_NAME "200"
3172
3173 #define FETH_NAME "feth"
3174
3175 /* On some platforms with DEBUG kernel, we need to wait a while */
3176 #define SIFCREATE_RETRY 600
3177
3178 static int
ifnet_create(int s,const char * ifname)3179 ifnet_create(int s, const char * ifname)
3180 {
3181 int error = 0;
3182 struct ifreq ifr;
3183
3184 bzero(&ifr, sizeof(ifr));
3185 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
3186
3187 for (int i = 0; i < SIFCREATE_RETRY; i++) {
3188 if (ioctl(s, SIOCIFCREATE, &ifr) < 0) {
3189 error = errno;
3190 T_LOG("SIOCSIFCREATE %s: %s", ifname,
3191 strerror(error));
3192 if (error == EBUSY) {
3193 /* interface is tearing down, try again */
3194 usleep(10000);
3195 } else if (error == EEXIST) {
3196 /* interface exists, try destroying it */
3197 (void)ifnet_destroy(s, ifname, false);
3198 } else {
3199 /* unexpected failure */
3200 break;
3201 }
3202 } else {
3203 error = 0;
3204 break;
3205 }
3206 }
3207 if (error == 0) {
3208 error = ifnet_set_flags(s, ifname, IFF_UP, 0);
3209 }
3210 return error;
3211 }
3212
3213 static int
siocdrvspec(int s,const char * ifname,u_long op,void * arg,size_t argsize,bool set)3214 siocdrvspec(int s, const char * ifname,
3215 u_long op, void *arg, size_t argsize, bool set)
3216 {
3217 struct ifdrv ifd;
3218
3219 memset(&ifd, 0, sizeof(ifd));
3220 strlcpy(ifd.ifd_name, ifname, sizeof(ifd.ifd_name));
3221 ifd.ifd_cmd = op;
3222 ifd.ifd_len = argsize;
3223 ifd.ifd_data = arg;
3224 return ioctl(s, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd);
3225 }
3226
3227
3228 static int
fake_set_peer(int s,const char * feth,const char * feth_peer)3229 fake_set_peer(int s, const char * feth, const char * feth_peer)
3230 {
3231 struct if_fake_request iffr;
3232 int ret;
3233
3234 bzero((char *)&iffr, sizeof(iffr));
3235 if (feth_peer != NULL) {
3236 strlcpy(iffr.iffr_peer_name, feth_peer,
3237 sizeof(iffr.iffr_peer_name));
3238 }
3239 ret = siocdrvspec(s, feth, IF_FAKE_S_CMD_SET_PEER,
3240 &iffr, sizeof(iffr), true);
3241 T_QUIET;
3242 T_ASSERT_POSIX_SUCCESS(ret,
3243 "SIOCDRVSPEC(%s, IF_FAKE_S_CMD_SET_PEER, %s)",
3244 feth, (feth_peer != NULL) ? feth_peer : "<none>");
3245 return ret;
3246 }
3247
3248 static int
bridge_add_member(int s,const char * bridge,const char * member)3249 bridge_add_member(int s, const char * bridge, const char * member)
3250 {
3251 struct ifbreq req;
3252 int ret;
3253
3254 memset(&req, 0, sizeof(req));
3255 strlcpy(req.ifbr_ifsname, member, sizeof(req.ifbr_ifsname));
3256 ret = siocdrvspec(s, bridge, BRDGADD, &req, sizeof(req), true);
3257 T_QUIET;
3258 T_ASSERT_POSIX_SUCCESS(ret, "%s %s %s", __func__, bridge, member);
3259 return ret;
3260 }
3261
3262
3263 static int
bridge_member_modify_ifflags(int s,const char * bridge,const char * member,uint32_t flags_to_modify,bool set)3264 bridge_member_modify_ifflags(int s, const char * bridge, const char * member,
3265 uint32_t flags_to_modify, bool set)
3266 {
3267 uint32_t flags;
3268 bool need_set = false;
3269 struct ifbreq req;
3270 int ret;
3271
3272 memset(&req, 0, sizeof(req));
3273 strlcpy(req.ifbr_ifsname, member, sizeof(req.ifbr_ifsname));
3274 ret = siocdrvspec(s, bridge, BRDGGIFFLGS, &req, sizeof(req), false);
3275 T_QUIET;
3276 T_ASSERT_POSIX_SUCCESS(ret, "BRDGGIFFLGS %s %s", bridge, member);
3277 flags = req.ifbr_ifsflags;
3278 if (set) {
3279 if ((flags & flags_to_modify) != flags_to_modify) {
3280 need_set = true;
3281 req.ifbr_ifsflags |= flags_to_modify;
3282 }
3283 /* need to set it */
3284 } else if ((flags & flags_to_modify) != 0) {
3285 /* need to clear it */
3286 need_set = true;
3287 req.ifbr_ifsflags &= ~flags_to_modify;
3288 }
3289 if (need_set) {
3290 ret = siocdrvspec(s, bridge, BRDGSIFFLGS,
3291 &req, sizeof(req), true);
3292 T_QUIET;
3293 T_ASSERT_POSIX_SUCCESS(ret, "BRDGSIFFLGS %s %s 0x%x => 0x%x",
3294 bridge, member,
3295 flags, req.ifbr_ifsflags);
3296 }
3297 return ret;
3298 }
3299
3300 static int
bridge_member_modify_mac_nat(int s,const char * bridge,const char * member,bool enable)3301 bridge_member_modify_mac_nat(int s, const char * bridge,
3302 const char * member, bool enable)
3303 {
3304 return bridge_member_modify_ifflags(s, bridge, member,
3305 IFBIF_MAC_NAT,
3306 enable);
3307 }
3308
3309 static int
bridge_member_modify_checksum_offload(int s,const char * bridge,const char * member,bool enable)3310 bridge_member_modify_checksum_offload(int s, const char * bridge,
3311 const char * member, bool enable)
3312 {
3313 #ifndef IFBIF_CHECKSUM_OFFLOAD
3314 #define IFBIF_CHECKSUM_OFFLOAD 0x10000 /* checksum inbound packets,
3315 * drop outbound packets with
3316 * bad checksum
3317 */
3318 #endif
3319 return bridge_member_modify_ifflags(s, bridge, member,
3320 IFBIF_CHECKSUM_OFFLOAD,
3321 enable);
3322 }
3323
3324 static struct ifbareq *
bridge_rt_table_copy_common(const char * bridge,u_int * ret_count)3325 bridge_rt_table_copy_common(const char * bridge, u_int * ret_count)
3326 {
3327 struct ifbaconf ifbac;
3328 u_int len = 8 * 1024;
3329 char * inbuf = NULL;
3330 char * ninbuf;
3331 int ret;
3332 struct ifbareq * rt_table = NULL;
3333 int s;
3334
3335 s = inet_dgram_socket();
3336
3337 /*
3338 * BRDGRTS should work like other ioctl's where passing in NULL
3339 * for the buffer says "tell me how many there are". Unfortunately,
3340 * it doesn't so we have to pass in a buffer, then check that it
3341 * was too big.
3342 */
3343 for (;;) {
3344 ninbuf = realloc(inbuf, len);
3345 T_QUIET;
3346 T_ASSERT_NOTNULL((void *)ninbuf, "realloc %u", len);
3347 ifbac.ifbac_len = len;
3348 ifbac.ifbac_buf = inbuf = ninbuf;
3349 ret = siocdrvspec(s, bridge, BRDGRTS,
3350 &ifbac, sizeof(ifbac), false);
3351 T_QUIET;
3352 T_ASSERT_POSIX_SUCCESS(ret, "%s %s", __func__, bridge);
3353 if ((ifbac.ifbac_len + sizeof(*rt_table)) < len) {
3354 /* we passed a buffer larger than what was required */
3355 break;
3356 }
3357 len *= 2;
3358 }
3359 if (ifbac.ifbac_len == 0) {
3360 free(ninbuf);
3361 T_LOG("No bridge routing entries");
3362 goto done;
3363 }
3364 *ret_count = ifbac.ifbac_len / sizeof(*rt_table);
3365 rt_table = (struct ifbareq *)(void *)ninbuf;
3366 done:
3367 if (rt_table == NULL) {
3368 *ret_count = 0;
3369 }
3370 if (s >= 0) {
3371 close(s);
3372 }
3373 return rt_table;
3374 }
3375
3376 static struct ifbareq *
bridge_rt_table_copy(u_int * ret_count)3377 bridge_rt_table_copy(u_int * ret_count)
3378 {
3379 return bridge_rt_table_copy_common(BRIDGE200, ret_count);
3380 }
3381
3382 static void
bridge_rt_table_log(struct ifbareq * rt_table,u_int count)3383 bridge_rt_table_log(struct ifbareq *rt_table, u_int count)
3384 {
3385 u_int i;
3386 char ntoabuf[ETHER_NTOA_BUFSIZE];
3387 struct ifbareq * ifba;
3388
3389 for (i = 0, ifba = rt_table; i < count; i++, ifba++) {
3390 ether_ntoa_buf((const ether_addr_t *)&ifba->ifba_dst,
3391 ntoabuf, sizeof(ntoabuf));
3392 T_LOG("%s %s %lu", ifba->ifba_ifsname, ntoabuf,
3393 ifba->ifba_expire);
3394 }
3395 return;
3396 }
3397
3398 static struct ifbrmne *
bridge_mac_nat_entries_copy_common(const char * bridge,u_int * ret_count)3399 bridge_mac_nat_entries_copy_common(const char * bridge, u_int * ret_count)
3400 {
3401 char * buf = NULL;
3402 u_int count = 0;
3403 int err;
3404 u_int i;
3405 struct ifbrmnelist mnl;
3406 struct ifbrmne * ret_list = NULL;
3407 int s;
3408 char * scan;
3409
3410
3411 s = inet_dgram_socket();
3412
3413 /* find out how many there are */
3414 bzero(&mnl, sizeof(mnl));
3415 err = siocdrvspec(s, bridge, BRDGGMACNATLIST, &mnl, sizeof(mnl), false);
3416 if (err != 0 && S_cleaning_up) {
3417 T_LOG("BRDGGMACNATLIST %s failed %d", bridge, errno);
3418 goto done;
3419 }
3420 T_QUIET;
3421 T_ASSERT_POSIX_SUCCESS(err, "BRDGGMACNATLIST %s", bridge);
3422 T_QUIET;
3423 T_ASSERT_GE(mnl.ifbml_elsize, (uint16_t)sizeof(struct ifbrmne),
3424 "mac nat entry size %u minsize %u",
3425 mnl.ifbml_elsize, (u_int)sizeof(struct ifbrmne));
3426 if (mnl.ifbml_len == 0) {
3427 goto done;
3428 }
3429
3430 /* call again with a buffer large enough to hold them */
3431 buf = malloc(mnl.ifbml_len);
3432 T_QUIET;
3433 T_ASSERT_NOTNULL(buf, "mac nat entries buffer");
3434 mnl.ifbml_buf = buf;
3435 err = siocdrvspec(s, bridge, BRDGGMACNATLIST, &mnl, sizeof(mnl), false);
3436 T_QUIET;
3437 T_ASSERT_POSIX_SUCCESS(err, "BRDGGMACNATLIST %s", bridge);
3438 count = mnl.ifbml_len / mnl.ifbml_elsize;
3439 if (count == 0) {
3440 goto done;
3441 }
3442 if (mnl.ifbml_elsize == sizeof(struct ifbrmne)) {
3443 /* element size is expected size, no need to "right-size" it */
3444 ret_list = (struct ifbrmne *)(void *)buf;
3445 buf = NULL;
3446 goto done;
3447 }
3448 /* element size is larger than we expect, create a "right-sized" array */
3449 ret_list = malloc(count * sizeof(*ret_list));
3450 T_QUIET;
3451 T_ASSERT_NOTNULL(ret_list, "mac nat entries list");
3452 for (i = 0, scan = buf; i < count; i++, scan += mnl.ifbml_elsize) {
3453 struct ifbrmne * ifbmne;
3454
3455 ifbmne = (struct ifbrmne *)(void *)scan;
3456 ret_list[i] = *ifbmne;
3457 }
3458 done:
3459 if (s >= 0) {
3460 close(s);
3461 }
3462 if (buf != NULL) {
3463 free(buf);
3464 }
3465 *ret_count = count;
3466 return ret_list;
3467 }
3468
3469 static struct ifbrmne *
bridge_mac_nat_entries_copy(u_int * ret_count)3470 bridge_mac_nat_entries_copy(u_int * ret_count)
3471 {
3472 return bridge_mac_nat_entries_copy_common(BRIDGE200, ret_count);
3473 }
3474
3475 static void
bridge_mac_nat_entries_log(struct ifbrmne * entries,u_int count)3476 bridge_mac_nat_entries_log(struct ifbrmne * entries, u_int count)
3477 {
3478 u_int i;
3479 char ntoabuf[ETHER_NTOA_BUFSIZE];
3480 char ntopbuf[INET6_ADDRSTRLEN];
3481 struct ifbrmne * scan;
3482
3483 for (i = 0, scan = entries; i < count; i++, scan++) {
3484 ether_ntoa_buf((const ether_addr_t *)&scan->ifbmne_mac,
3485 ntoabuf, sizeof(ntoabuf));
3486 inet_ntop(scan->ifbmne_af, &scan->ifbmne_ip,
3487 ntopbuf, sizeof(ntopbuf));
3488 printf("%s %s %s %lu\n",
3489 scan->ifbmne_ifname, ntopbuf, ntoabuf,
3490 (unsigned long)scan->ifbmne_expire);
3491 }
3492 return;
3493 }
3494
3495 /**
3496 ** Test Main
3497 **/
3498 static u_int S_n_ports;
3499 static switch_port_list_t S_port_list;
3500
3501 static void
3502 bridge_cleanup(const char * bridge, u_int n_ports, bool fail_on_error);
3503
3504 static int fake_bsd_mode;
3505 static int fake_fcs;
3506 static int fake_trailer_length;
3507
3508 static void
fake_set_trailers_fcs(bool enable)3509 fake_set_trailers_fcs(bool enable)
3510 {
3511 int error;
3512 int fcs;
3513 size_t len;
3514 int trailer_length;
3515
3516 if (enable) {
3517 fcs = 1;
3518 trailer_length = 28;
3519 } else {
3520 fcs = 0;
3521 trailer_length = 0;
3522 }
3523
3524 /* set fcs */
3525 len = sizeof(fake_fcs);
3526 error = sysctlbyname("net.link.fake.fcs",
3527 &fake_fcs, &len,
3528 &fcs, sizeof(fcs));
3529 T_ASSERT_EQ(error, 0, "sysctl net.link.fake.fcs %d", fcs);
3530
3531 /* set trailer_length */
3532 len = sizeof(fake_trailer_length);
3533 error = sysctlbyname("net.link.fake.trailer_length",
3534 &fake_trailer_length, &len,
3535 &trailer_length, sizeof(trailer_length));
3536 T_ASSERT_EQ(error, 0, "sysctl net.link.fake.trailer_length %d",
3537 trailer_length);
3538 }
3539
3540 static void
fake_restore_trailers_fcs(void)3541 fake_restore_trailers_fcs(void)
3542 {
3543 int error;
3544
3545 error = sysctlbyname("net.link.fake.fcs",
3546 NULL, 0, &fake_fcs, sizeof(fake_fcs));
3547 T_LOG("sysctl net.link.fake.fcs=%d returned %d", fake_fcs, error);
3548 error = sysctlbyname("net.link.fake.trailer_length",
3549 NULL, 0, &fake_trailer_length, sizeof(fake_trailer_length));
3550 T_LOG("sysctl net.link.fake.trailer_length=%d returned %d",
3551 fake_trailer_length, error);
3552 }
3553
3554 static void
fake_set_bsd_mode(bool enable)3555 fake_set_bsd_mode(bool enable)
3556 {
3557 int error;
3558 int bsd_mode;
3559 size_t len;
3560
3561 bsd_mode = (enable) ? 1 : 0;
3562 len = sizeof(fake_bsd_mode);
3563 error = sysctlbyname("net.link.fake.bsd_mode",
3564 &fake_bsd_mode, &len,
3565 &bsd_mode, sizeof(bsd_mode));
3566 T_ASSERT_EQ(error, 0, "sysctl net.link.fake.bsd_mode %d", bsd_mode);
3567 }
3568
3569 static void
fake_restore_bsd_mode(void)3570 fake_restore_bsd_mode(void)
3571 {
3572 int error;
3573
3574 error = sysctlbyname("net.link.fake.bsd_mode",
3575 NULL, 0, &fake_bsd_mode, sizeof(fake_bsd_mode));
3576 T_LOG("sysctl net.link.fake.bsd_mode=%d returned %d",
3577 fake_bsd_mode, error);
3578 }
3579
3580 static void
cleanup_common(bool dump_table)3581 cleanup_common(bool dump_table)
3582 {
3583 if (S_n_ports == 0) {
3584 return;
3585 }
3586 S_cleaning_up = true;
3587 if (S_port_list != NULL &&
3588 (S_port_list->mac_nat || dump_table)) {
3589 switch_port_list_log(S_port_list);
3590 if (S_port_list->mac_nat) {
3591 switch_port_list_verify_mac_nat(S_port_list, true);
3592 }
3593 (void)switch_port_list_verify_rt_table(S_port_list, true);
3594 }
3595 if (S_debug) {
3596 T_LOG("sleeping for 5 seconds\n");
3597 sleep(5);
3598 }
3599 bridge_cleanup(BRIDGE200, S_n_ports, false);
3600 return;
3601 }
3602
3603 static void
cleanup(void)3604 cleanup(void)
3605 {
3606 cleanup_common(true);
3607 return;
3608 }
3609
3610 static void
sigint_handler(__unused int sig)3611 sigint_handler(__unused int sig)
3612 {
3613 cleanup_common(false);
3614 signal(SIGINT, SIG_DFL);
3615 }
3616
3617 static switch_port_list_t
bridge_setup(char * bridge,u_int n_ports,u_int num_addrs,uint8_t setup_flags)3618 bridge_setup(char * bridge, u_int n_ports, u_int num_addrs,
3619 uint8_t setup_flags)
3620 {
3621 u_int addr_index = 1;
3622 bool attach_stack;
3623 bool checksum_offload;
3624 errno_t err;
3625 struct in_addr ip;
3626 switch_port_list_t list = NULL;
3627 bool mac_nat;
3628 int rs = -1;
3629 int s;
3630 int s6 = -1;
3631 uint8_t trailers;
3632
3633 attach_stack = (setup_flags & SETUP_FLAGS_ATTACH_STACK) != 0;
3634 checksum_offload = (setup_flags & SETUP_FLAGS_CHECKSUM_OFFLOAD) != 0;
3635 mac_nat = (setup_flags & SETUP_FLAGS_MAC_NAT) != 0;
3636 trailers = (setup_flags & SETUP_FLAGS_TRAILERS) != 0;
3637
3638 S_n_ports = n_ports;
3639 T_ATEND(cleanup);
3640 T_SETUPBEGIN;
3641 s = inet_dgram_socket();
3642 if (attach_stack) {
3643 rs = routing_socket();
3644 s6 = inet6_dgram_socket();
3645 }
3646 err = ifnet_create(s, bridge);
3647 if (err != 0) {
3648 goto done;
3649 }
3650 bridge_if_index = (u_short)if_nametoindex(bridge);
3651 if (attach_stack) {
3652 ether_addr_t bridge_mac;
3653 char ntopbuf_ip[INET6_ADDRSTRLEN];
3654
3655 ifnet_get_lladdr(s, bridge, &bridge_mac);
3656
3657 /* bridge gets .1 */
3658 get_ipv4_address(0, addr_index, &bridge_ip_addr);
3659 addr_index++;
3660 siocaifaddr(s, bridge, bridge_ip_addr);
3661 start_ipv6(s6, bridge);
3662 get_ipv6_ll_address(&bridge_mac, &bridge_ipv6_addr);
3663 inet_ntop(AF_INET6, &bridge_ipv6_addr, ntopbuf_ip,
3664 sizeof(ntopbuf_ip));
3665 T_LOG("%s %s", bridge, ntopbuf_ip);
3666 }
3667 list = switch_port_list_alloc(n_ports, mac_nat);
3668 fake_set_bsd_mode(true);
3669 fake_set_trailers_fcs(trailers);
3670 for (u_int i = 0; i < n_ports; i++) {
3671 bool do_mac_nat;
3672 char ifname[IFNAMSIZ];
3673 u_short if_index = 0;
3674 char member_ifname[IFNAMSIZ];
3675
3676 snprintf(ifname, sizeof(ifname), "%s%d",
3677 FETH_NAME, i);
3678 snprintf(member_ifname, sizeof(member_ifname), "%s%d",
3679 FETH_NAME, i + n_ports);
3680 err = ifnet_create(s, ifname);
3681 if (err != 0) {
3682 goto done;
3683 }
3684 ifnet_attach_ip(s, ifname);
3685 err = ifnet_create(s, member_ifname);
3686 if (err != 0) {
3687 goto done;
3688 }
3689 err = fake_set_peer(s, ifname, member_ifname);
3690 if (err != 0) {
3691 goto done;
3692 }
3693 if (attach_stack) {
3694 /* members get .2, .3, etc. */
3695 if_index = (u_short)if_nametoindex(ifname);
3696 get_ipv4_address(0, addr_index, &ip);
3697 siocaifaddr(s, ifname, ip);
3698 add_scoped_subnet_route(rs, ifname, if_index, ip);
3699 addr_index++;
3700 start_ipv6(s6, ifname);
3701 }
3702 /* add the interface's peer to the bridge */
3703 err = bridge_add_member(s, bridge, member_ifname);
3704 if (err != 0) {
3705 goto done;
3706 }
3707
3708 do_mac_nat = (i == 0 && mac_nat);
3709 if (do_mac_nat) {
3710 /* enable MAC NAT on unit 0 */
3711 err = bridge_member_modify_mac_nat(s, bridge,
3712 member_ifname,
3713 true);
3714 if (err != 0) {
3715 goto done;
3716 }
3717 } else if (checksum_offload) {
3718 err = bridge_member_modify_checksum_offload(s, bridge,
3719 member_ifname,
3720 true);
3721 if (err != 0) {
3722 goto done;
3723 }
3724 }
3725 /* we'll send/receive on the interface */
3726 err = switch_port_list_add_port(s, list, i, ifname, if_index,
3727 member_ifname, num_addrs, do_mac_nat, &ip);
3728 if (err != 0) {
3729 goto done;
3730 }
3731 }
3732 done:
3733 if (s >= 0) {
3734 close(s);
3735 }
3736 if (s6 >= 0) {
3737 close(s6);
3738 }
3739 if (err != 0 && list != NULL) {
3740 switch_port_list_dealloc(list);
3741 list = NULL;
3742 }
3743 T_SETUPEND;
3744 return list;
3745 }
3746
3747 static void
bridge_cleanup(const char * bridge,u_int n_ports,bool fail_on_error)3748 bridge_cleanup(const char * bridge, u_int n_ports, bool fail_on_error)
3749 {
3750 int s;
3751
3752 s = inet_dgram_socket();
3753 ifnet_destroy(s, bridge, fail_on_error);
3754 for (u_int i = 0; i < n_ports; i++) {
3755 char ifname[IFNAMSIZ];
3756 char member_ifname[IFNAMSIZ];
3757
3758 snprintf(ifname, sizeof(ifname), "%s%d",
3759 FETH_NAME, i);
3760 snprintf(member_ifname, sizeof(member_ifname), "%s%d",
3761 FETH_NAME, i + n_ports);
3762 ifnet_destroy(s, ifname, fail_on_error);
3763 ifnet_destroy(s, member_ifname, fail_on_error);
3764 }
3765 if (s >= 0) {
3766 close(s);
3767 }
3768 S_n_ports = 0;
3769 fake_restore_trailers_fcs();
3770 fake_restore_bsd_mode();
3771 return;
3772 }
3773
3774 /*
3775 * Basic Bridge Tests
3776 *
3777 * Broadcast
3778 * - two cases: actual broadcast, unknown ethernet
3779 * - send broadcast packets
3780 * - verify all received
3781 * - check bridge rt list contains all expected MAC addresses
3782 * - send unicast ARP packets
3783 * - verify packets received only on expected port
3784 *
3785 * MAC-NAT
3786 * - verify ARP translation
3787 * - verify IPv4 translation
3788 * - verify DHCP broadcast bit conversion
3789 * - verify IPv6 translation
3790 * - verify ND6 translation (Neighbor, Router)
3791 * - verify IPv4 subnet-local broadcast to MAC-NAT interface link-layer
3792 * address arrives on all member links
3793 */
3794
3795 static void
bridge_test(packet_validator_t validator,void * context,const ether_addr_t * dst_eaddr,uint8_t af,u_int n_ports,u_int num_addrs)3796 bridge_test(packet_validator_t validator,
3797 void * context,
3798 const ether_addr_t * dst_eaddr,
3799 uint8_t af, u_int n_ports, u_int num_addrs)
3800 {
3801 #if TARGET_OS_BRIDGE
3802 T_SKIP("Test uses too much memory");
3803 #else /* TARGET_OS_BRIDGE */
3804 switch_port_list_t port_list;
3805
3806 signal(SIGINT, sigint_handler);
3807 port_list = bridge_setup(BRIDGE200, n_ports, num_addrs, 0);
3808 if (port_list == NULL) {
3809 T_FAIL("bridge_setup");
3810 return;
3811 }
3812 S_port_list = port_list;
3813 bridge_learning_test(port_list, af, validator, context, dst_eaddr);
3814
3815 //T_LOG("Sleeping for 5 seconds");
3816 //sleep(5);
3817 bridge_cleanup(BRIDGE200, n_ports, true);
3818 switch_port_list_dealloc(port_list);
3819 return;
3820 #endif /* TARGET_OS_BRIDGE */
3821 }
3822
3823 static void
bridge_test_mac_nat_ipv4(u_int n_ports,u_int num_addrs)3824 bridge_test_mac_nat_ipv4(u_int n_ports, u_int num_addrs)
3825 {
3826 #if TARGET_OS_BRIDGE
3827 T_SKIP("Test uses too much memory");
3828 #else /* TARGET_OS_BRIDGE */
3829 switch_port_list_t port_list;
3830
3831 signal(SIGINT, sigint_handler);
3832 port_list = bridge_setup(BRIDGE200, n_ports, num_addrs,
3833 SETUP_FLAGS_MAC_NAT);
3834 if (port_list == NULL) {
3835 T_FAIL("bridge_setup");
3836 return;
3837 }
3838 S_port_list = port_list;
3839
3840 /* verify that IPv4 packets get translated when necessary */
3841 mac_nat_test_ip(port_list, AF_INET);
3842
3843 /* verify the DHCP broadcast bit gets set appropriately */
3844 mac_nat_test_dhcp(port_list, false);
3845
3846 /* verify that ARP packet gets translated when necessary */
3847 mac_nat_test_arp_out(port_list);
3848 mac_nat_test_arp_in(port_list);
3849
3850 /* verify IP broadcast to MAC-NAT interface link layer address */
3851 mac_nat_test_dhcp(port_list, true);
3852
3853 if (S_debug) {
3854 T_LOG("Sleeping for 5 seconds");
3855 sleep(5);
3856 }
3857 bridge_cleanup(BRIDGE200, n_ports, true);
3858 switch_port_list_dealloc(port_list);
3859 return;
3860 #endif /* TARGET_OS_BRIDGE */
3861 }
3862
3863 static void
bridge_test_mac_nat_ipv6(u_int n_ports,u_int num_addrs)3864 bridge_test_mac_nat_ipv6(u_int n_ports, u_int num_addrs)
3865 {
3866 #if TARGET_OS_BRIDGE
3867 T_SKIP("Test uses too much memory");
3868 #else /* TARGET_OS_BRIDGE */
3869 switch_port_list_t port_list;
3870
3871 signal(SIGINT, sigint_handler);
3872 port_list = bridge_setup(BRIDGE200, n_ports, num_addrs,
3873 SETUP_FLAGS_MAC_NAT);
3874 if (port_list == NULL) {
3875 T_FAIL("bridge_setup");
3876 return;
3877 }
3878 S_port_list = port_list;
3879
3880 /* verify that IPv6 packets get translated when necessary */
3881 mac_nat_test_ip(port_list, AF_INET6);
3882
3883 /* verify that ND6 packet gets translated when necessary */
3884 mac_nat_test_nd6_out(port_list);
3885 if (S_debug) {
3886 T_LOG("Sleeping for 5 seconds");
3887 sleep(5);
3888 }
3889 bridge_cleanup(BRIDGE200, n_ports, true);
3890 switch_port_list_dealloc(port_list);
3891 return;
3892 #endif /* TARGET_OS_BRIDGE */
3893 }
3894
3895 /*
3896 * Filter test utilities
3897 */
3898 static void
system_cmd(const char * cmd,bool fail_on_error)3899 system_cmd(const char *cmd, bool fail_on_error)
3900 {
3901 pid_t pid = -1;
3902 int exit_status = 0;
3903 const char *argv[] = {
3904 "/usr/local/bin/bash",
3905 "-c",
3906 cmd,
3907 NULL
3908 };
3909
3910 int rc = dt_launch_tool(&pid, (char **)(void *)argv, false, NULL, NULL);
3911 T_QUIET;
3912 T_ASSERT_EQ(rc, 0, "dt_launch_tool(%s) failed", cmd);
3913
3914 if (dt_waitpid(pid, &exit_status, NULL, 30)) {
3915 T_QUIET;
3916 T_ASSERT_MACH_SUCCESS(exit_status, "command(%s)", cmd);
3917 } else {
3918 if (fail_on_error) {
3919 T_FAIL("dt_waitpid(%s) failed", cmd);
3920 }
3921 }
3922 }
3923
3924 static bool
executable_is_present(const char * path)3925 executable_is_present(const char * path)
3926 {
3927 struct stat statb = {};
3928
3929 return stat(path, &statb) == 0 && (statb.st_mode & S_IXUSR) != 0;
3930 }
3931
3932 static void
cleanup_pf(void)3933 cleanup_pf(void)
3934 {
3935 struct ifbrparam param;
3936 int s = inet_dgram_socket();
3937
3938 system_cmd("pfctl -d", false);
3939 system_cmd("pfctl -F all", false);
3940
3941 param.ifbrp_filter = 0;
3942 siocdrvspec(s, BRIDGE200, BRDGSFILT,
3943 ¶m, sizeof(param), true);
3944 return;
3945 }
3946
3947 static void
block_all_traffic(bool input,const char * infname1,const char * infname2)3948 block_all_traffic(bool input, const char* infname1, const char* infname2)
3949 {
3950 int s = inet_dgram_socket();
3951 int ret;
3952 struct ifbrparam param;
3953 char command[512];
3954 char *dir = input ? "in" : "out";
3955
3956 snprintf(command, sizeof(command), "echo \"block %s on %s all\nblock %s on %s all\n\" | pfctl -vvv -f -",
3957 dir, infname1, dir, infname2);
3958 /* enable block all filter */
3959 param.ifbrp_filter = IFBF_FILT_MEMBER | IFBF_FILT_ONLYIP;
3960 ret = siocdrvspec(s, BRIDGE200, BRDGSFILT,
3961 ¶m, sizeof(param), true);
3962 T_ASSERT_POSIX_SUCCESS(ret,
3963 "SIOCDRVSPEC(BRDGSFILT %s, 0x%x)",
3964 BRIDGE200, param.ifbrp_filter);
3965 // ignore errors such that not having pf.os doesn't raise any issues
3966 system_cmd(command, false);
3967 system_cmd("pfctl -e", true);
3968 system_cmd("pfctl -s all", true);
3969 }
3970
3971 /*
3972 * Basic bridge filter test
3973 *
3974 * For both broadcast and unicast transfers ensure that data can
3975 * be blocked using pf on the bridge
3976 */
3977
3978 static void
filter_test(uint8_t af)3979 filter_test(uint8_t af)
3980 {
3981 #if TARGET_OS_BRIDGE
3982 T_SKIP("pfctl isn't valid on this platform");
3983 #else /* TARGET_OS_BRIDGE */
3984 switch_port_list_t port_list;
3985 switch_port_t port;
3986 const u_int n_ports = 2;
3987 u_int num_addrs = 1;
3988 u_int i;
3989 char ntoabuf[ETHER_NTOA_BUFSIZE];
3990 union ifbrip dst_ip;
3991 bool blocked = true;
3992 bool input = true;
3993 const char* ifnames[2];
3994
3995 #define PFCTL_PATH "/sbin/pfctl"
3996 if (!executable_is_present(PFCTL_PATH)) {
3997 T_SKIP("%s not present", PFCTL_PATH);
3998 return;
3999 }
4000 signal(SIGINT, sigint_handler);
4001
4002 T_ATEND(cleanup);
4003 T_ATEND(cleanup_pf);
4004
4005 port_list = bridge_setup(BRIDGE200, n_ports, num_addrs, 0);
4006 if (port_list == NULL) {
4007 T_FAIL("bridge_setup");
4008 return;
4009 }
4010
4011 ether_ntoa_buf(ðer_broadcast, ntoabuf, sizeof(ntoabuf));
4012
4013 S_port_list = port_list;
4014 for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
4015 ifnames[i] = port->member_ifname;
4016 }
4017
4018 get_broadcast_ip_address(af, &dst_ip);
4019 do {
4020 do {
4021 if (blocked) {
4022 block_all_traffic(input, ifnames[0], ifnames[1]);
4023 }
4024 for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
4025 if (S_debug) {
4026 T_LOG("Sending on %s", port->ifname);
4027 }
4028 for (u_int j = 0; j < port->num_addrs; j++) {
4029 uint32_t generation;
4030
4031 generation = next_generation();
4032 send_generation(port,
4033 af,
4034 j,
4035 ðer_broadcast,
4036 &dst_ip,
4037 generation);
4038
4039 /* receive across all ports */
4040 check_receive_generation(port_list,
4041 af,
4042 generation,
4043 validate_broadcast_dhost,
4044 NULL);
4045
4046 /* ensure that every port saw the right amount of packets*/
4047 if (blocked) {
4048 check_received_count(port_list, port, 0);
4049 } else {
4050 check_received_count(port_list, port, 1);
4051 }
4052 }
4053 }
4054 T_PASS("%s broadcast %s %s", __func__, blocked ? "blocked" : "not blocked", input ? "input" : "output");
4055 input = !input;
4056 cleanup_pf();
4057 } while (input == false && blocked);
4058 blocked = !blocked;
4059 } while (blocked == false);
4060
4061 do {
4062 do {
4063 if (blocked) {
4064 block_all_traffic(input, ifnames[0], ifnames[1]);
4065 }
4066 for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
4067 /* send unicast packets to every other port's MAC addresses */
4068 unicast_send_all(port_list, af, port);
4069
4070 /* receive all of that generated traffic */
4071 switch_port_list_check_receive(port_list, af, NULL, 0,
4072 validate_port_dhost, NULL);
4073
4074 /* ensure that every port saw the right amount of packets*/
4075 if (blocked) {
4076 check_received_count(port_list, port, 0);
4077 } else {
4078 check_received_count(port_list, port, 1);
4079 }
4080 }
4081 T_PASS("%s unicast %s %s", __func__, blocked ? "blocked" : "not blocked", input ? "input" : "output");
4082 input = !input;
4083 cleanup_pf();
4084 } while (input == false && blocked);
4085 blocked = !blocked;
4086 } while (blocked == false);
4087
4088 bridge_cleanup(BRIDGE200, n_ports, true);
4089 switch_port_list_dealloc(port_list);
4090 return;
4091 #endif /* TARGET_OS_BRIDGE */
4092 }
4093
4094 /*
4095 * Bridge checksum offload tests
4096 */
4097
4098 static const char *
ipproto_get_str(uint8_t proto)4099 ipproto_get_str(uint8_t proto)
4100 {
4101 const char * str;
4102
4103 switch (proto) {
4104 case IPPROTO_UDP:
4105 str = "UDP";
4106 break;
4107 case IPPROTO_TCP:
4108 str = "TCP";
4109 break;
4110 default:
4111 str = "<?>";
4112 break;
4113 }
4114 return str;
4115 }
4116
4117 static void
test_traffic(uint8_t af,inet_address_t server,const char * server_ifname,int server_if_index,const char * client_ifname,int client_if_index)4118 test_traffic(uint8_t af, inet_address_t server,
4119 const char * server_ifname, int server_if_index,
4120 const char * client_ifname, int client_if_index)
4121 {
4122 inet_endpoint endpoint;
4123 /* do TCP first because TCP is reliable and will populate ND cache */
4124 uint8_t protos[] = { IPPROTO_TCP, IPPROTO_UDP, 0 };
4125
4126 bzero(&endpoint, sizeof(endpoint));
4127 endpoint.af = af;
4128 endpoint.addr = *server;
4129 endpoint.port = 1;
4130 for (uint8_t * proto = protos; *proto != 0; proto++) {
4131 bool success;
4132
4133 T_LOG("%s: %s %s server %s client %s",
4134 __func__, af_get_str(af),
4135 ipproto_get_str(*proto),
4136 server_ifname, client_ifname);
4137 endpoint.proto = *proto;
4138 success = inet_transfer_local(&endpoint, server_if_index,
4139 client_if_index);
4140 T_ASSERT_TRUE(success,
4141 "inet_transfer_local(): %s",
4142 inet_transfer_error_string());
4143 }
4144 return;
4145 }
4146
4147 static void
test_traffic_for_af(switch_port_list_t ports,uint8_t af)4148 test_traffic_for_af(switch_port_list_t ports, uint8_t af)
4149 {
4150 u_int i;
4151 inet_address server;
4152 int server_if_index;
4153 const char * server_name;
4154 switch_port_t server_port;
4155 switch_port_t port;
4156
4157 /* bridge as server, each peer as client */
4158 server_if_index = bridge_if_index;
4159 server_name = BRIDGE200;
4160 if (af == AF_INET) {
4161 server.v4 = bridge_ip_addr;
4162 } else {
4163 server.v6 = bridge_ipv6_addr;
4164 }
4165 for (i = 0, port = ports->list; i < ports->count; i++, port++) {
4166 test_traffic(af, &server, server_name,
4167 server_if_index, port->ifname, port->if_index);
4168 }
4169
4170 /* peer 0 as server, other peers as client */
4171 assert(ports->count > 0);
4172 server_port = ports->list;
4173 server_name = server_port->ifname;
4174 server_if_index = server_port->if_index;
4175 if (af == AF_INET) {
4176 server.v4 = server_port->ip;
4177 } else {
4178 server.v6 = server_port->ip6;
4179 }
4180 for (i = 1, port = ports->list + 1; i < ports->count; i++, port++) {
4181 test_traffic(af, &server, server_name,
4182 server_if_index, port->ifname, port->if_index);
4183 }
4184 }
4185
4186 static void
bridge_test_checksum_offload(u_int n_ports,uint8_t setup_flags)4187 bridge_test_checksum_offload(u_int n_ports, uint8_t setup_flags)
4188 {
4189 #if TARGET_OS_BRIDGE
4190 T_SKIP("Test uses too much memory");
4191 #else /* TARGET_OS_BRIDGE */
4192 switch_port_list_t port_list;
4193
4194 signal(SIGINT, sigint_handler);
4195 port_list = bridge_setup(BRIDGE200, n_ports, 0,
4196 SETUP_FLAGS_CHECKSUM_OFFLOAD |
4197 SETUP_FLAGS_ATTACH_STACK | setup_flags);
4198 if (port_list == NULL) {
4199 T_FAIL("bridge_setup");
4200 return;
4201 }
4202 test_traffic_for_af(port_list, AF_INET);
4203 test_traffic_for_af(port_list, AF_INET6);
4204 if (S_debug) {
4205 T_LOG("Sleeping for 5 seconds");
4206 sleep(5);
4207 }
4208 bridge_cleanup(BRIDGE200, n_ports, true);
4209 switch_port_list_dealloc(port_list);
4210 return;
4211 #endif /* TARGET_OS_BRIDGE */
4212 }
4213
4214 T_DECL(if_bridge_bcast,
4215 "bridge broadcast IPv4",
4216 T_META_ASROOT(true))
4217 {
4218 bridge_test(validate_broadcast_dhost, NULL, ðer_broadcast,
4219 AF_INET, 5, 1);
4220 }
4221
4222 T_DECL(if_bridge_bcast_many,
4223 "bridge broadcast many IPv4",
4224 T_META_ASROOT(true))
4225 {
4226 bridge_test(validate_broadcast_dhost, NULL, ðer_broadcast,
4227 AF_INET, 5, 20);
4228 }
4229
4230 T_DECL(if_bridge_unknown,
4231 "bridge unknown host IPv4",
4232 T_META_ASROOT(true))
4233 {
4234 bridge_test(validate_not_present_dhost, NULL, ðer_external,
4235 AF_INET, 5, 1);
4236 }
4237
4238 T_DECL(if_bridge_bcast_v6,
4239 "bridge broadcast IPv6",
4240 T_META_ASROOT(true))
4241 {
4242 bridge_test(validate_broadcast_dhost, NULL, ðer_broadcast,
4243 AF_INET6, 5, 1);
4244 }
4245
4246 T_DECL(if_bridge_bcast_many_v6,
4247 "bridge broadcast many IPv6",
4248 T_META_ASROOT(true))
4249 {
4250 bridge_test(validate_broadcast_dhost, NULL, ðer_broadcast,
4251 AF_INET6, 5, 20);
4252 }
4253
4254 T_DECL(if_bridge_unknown_v6,
4255 "bridge unknown host IPv6",
4256 T_META_ASROOT(true))
4257 {
4258 bridge_test(validate_not_present_dhost, NULL, ðer_external,
4259 AF_INET6, 5, 1);
4260 }
4261
4262 T_DECL(if_bridge_mac_nat_ipv4,
4263 "bridge mac nat ipv4",
4264 T_META_ASROOT(true))
4265 {
4266 bridge_test_mac_nat_ipv4(5, 10);
4267 }
4268
4269 T_DECL(if_bridge_mac_nat_ipv6,
4270 "bridge mac nat ipv6",
4271 T_META_ASROOT(true))
4272 {
4273 bridge_test_mac_nat_ipv6(5, 10);
4274 }
4275
4276 T_DECL(if_bridge_filter_ipv4,
4277 "bridge filter ipv4",
4278 T_META_ASROOT(true))
4279 {
4280 filter_test(AF_INET);
4281 }
4282
4283 T_DECL(if_bridge_filter_ipv6,
4284 "bridge filter ipv6",
4285 T_META_ASROOT(true))
4286 {
4287 filter_test(AF_INET6);
4288 }
4289
4290 T_DECL(if_bridge_checksum_offload,
4291 "bridge checksum offload",
4292 T_META_ASROOT(true))
4293 {
4294 bridge_test_checksum_offload(2, 0);
4295 }
4296
4297 T_DECL(if_bridge_checksum_offload_trailers,
4298 "bridge checksum offload with trailers+fcs",
4299 T_META_ASROOT(true))
4300 {
4301 bridge_test_checksum_offload(2, SETUP_FLAGS_TRAILERS);
4302 }
4303