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