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