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