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