]> git.saurik.com Git - apple/xnu.git/blame - tests/net_bridge.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / tests / net_bridge.c
CommitLineData
ea3f0419 1/*
f427ee49 2 * Copyright (c) 2019-2020 Apple Inc. All rights reserved.
ea3f0419
A
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
67static bool S_debug;
68static 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
75typedef 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)
82typedef 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
88typedef struct {
89 struct ip ip;
90 struct udphdr udp;
91} ip_udp_header_t;
92
93typedef 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
101typedef struct {
102 struct ip ip;
103 struct tcphdr tcp;
104} ip_tcp_header_t;
105
106typedef union {
107 ip_udp_header_t udp;
108 ip_tcp_header_t tcp;
109} ip_udp_tcp_header_u;
110
111typedef 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
119typedef struct {
120 struct ip6_hdr ip6;
121 struct udphdr udp;
122} ip6_udp_header_t;
123
124typedef 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
132typedef 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
148typedef 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
155static struct ifbareq *
156bridge_rt_table_copy(u_int * ret_count);
157
158static void
159bridge_rt_table_log(struct ifbareq *rt_table, u_int count);
160
161static struct ifbrmne *
162bridge_mac_nat_entries_copy(u_int * ret_count);
163
164static void
165bridge_mac_nat_entries_log(struct ifbrmne * entries, u_int count);
166
167static void
168system_cmd(const char *cmd, bool fail_on_error);
169
170static int
171inet_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
194static void
195set_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
210static void
211get_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
222static struct in6_addr ula_address = IN6ADDR_ULA_INIT;
223
224#define ULA_UNIT_INDEX 14
225#define ULA_ADDR_INDEX 15
226
227static void
228get_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
237static void
238get_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
253static bool
254ip_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
274static ether_addr_t ether_broadcast = {
275 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
276};
277
278static ether_addr_t ether_external = {
279 { 0x80, 0x00, 0x00, 0x00, 0x00, 0x01 }
280};
281
282static inline struct in_addr
283get_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
292static inline void
293get_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
312static inline void
313get_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)
333static const char *
334ether_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
343static const char *
344inet_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
364static __inline__ char *
365arpop_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
382static void
383arp_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
422static void
423ip_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
472static void
473ip6_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
556static void
557ethernet_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
596static u_int
597ethernet_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
666static u_int
667ethernet_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
728static u_int
729ethernet_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
770static u_int
771ethernet_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
820static uint32_t G_generation;
821
822static uint32_t
823next_generation(void)
824{
825 return G_generation++;
826}
827
828static const void *
829ethernet_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
876static const void *
877ethernet_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
922static const void *
923ethernet_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
958static u_int
959ethernet_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**/
1088static void
1089switch_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
1113static void
1114switch_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
1153static void
1154switch_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
1195static void
1196switch_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
1246static void
1247switch_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
1266typedef void
1267(packet_validator)(switch_port_t port, const ether_header_t * eh_p,
1268 u_int pkt_len, void * context);
1269typedef packet_validator * packet_validator_t;
1270
1271static void
1272switch_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
1346static void
1347switch_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
1359static switch_port_list_t
1360switch_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
1371static void
1372switch_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
1385static errno_t
1386switch_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
1439failed:
1440 if (fd >= 0) {
1441 close(fd);
1442 }
1443 return err;
1444}
1445
1446static switch_port_t
1447switch_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
1460static void
1461switch_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
1472static switch_port_t
1473switch_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
1486static void
1487switch_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
1532static bool
1533switch_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
1597static bool
1598switch_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**/
1689static void
1690send_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
1701static void
1702check_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
1713static void
1714validate_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
1722static void
1723validate_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
1735static void
1736validate_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
1747static void
1748validate_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
1761static void
1762check_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
1786static void
1787unicast_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
1809static void
1810bridge_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
1867static inline const char *
1868af_get_str(uint8_t af)
1869{
1870 return (af == AF_INET) ? "IPv4" : "IPv6";
1871}
1872
1873static void
1874bridge_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**/
1948static void
1949mac_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
1969static void
1970validate_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
1991static void
1992validate_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
2006static void
2007validate_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
2064static void
2065validate_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
2100static void
2101mac_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
2134static void
2135mac_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
2160static void
2161mac_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
2185static void
2186validate_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
2240static u_int
2241make_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
2257static void
f427ee49 2258mac_nat_test_dhcp(switch_port_list_t port_list, bool link_layer_unicast)
ea3f0419
A
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;
f427ee49 2264 ether_addr_t * ether_dst;
ea3f0419 2265
f427ee49
A
2266 if (link_layer_unicast) {
2267 /* use link-layer address of MAC-NAT interface */
2268 ether_dst = &port_list->list[0].member_mac;
2269 } else {
2270 /* use link-layer broadcast address */
2271 ether_dst = &ether_broadcast;
2272 }
ea3f0419
A
2273 for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
2274 ether_addr_t eaddr;
2275 dhcp_min_payload payload;
2276 u_int payload_len;
2277
f427ee49
A
2278 if (!link_layer_unicast && port->mac_nat) {
2279 /* only send through non-MAC-NAT ports */
ea3f0419
A
2280 continue;
2281 }
2282 set_ethernet_address(&eaddr, port->unit, 0);
2283 payload_len = make_dhcp_payload(&payload, &eaddr);
2284 if (S_debug) {
2285 T_LOG("%s: transmit DHCP packet (member %s)",
2286 port->ifname, port->member_ifname);
2287 }
2288 switch_port_send_udp(port,
2289 AF_INET,
2290 &eaddr,
2291 (union ifbrip *)&ip_src,
2292 BOOTP_CLIENT_PORT,
f427ee49 2293 ether_dst,
ea3f0419
A
2294 (union ifbrip *)&ip_dst,
2295 BOOTP_SERVER_PORT,
2296 &payload,
2297 payload_len);
2298
2299 switch_port_list_check_receive(port_list, AF_INET, NULL, 0,
2300 validate_mac_nat_dhcp,
2301 port);
2302
2303 check_received_count(port_list, port, 1);
f427ee49
A
2304 if (link_layer_unicast) {
2305 /* send a single unicast to MAC-NAT interface */
2306 break;
2307 }
ea3f0419 2308 }
f427ee49
A
2309 T_PASS("%s %s", __func__,
2310 link_layer_unicast ? "unicast" : "broadcast");
ea3f0419
A
2311}
2312
2313
2314static void
2315validate_mac_nat_nd6(switch_port_t port,
2316 const struct icmp6_hdr * icmp6,
2317 u_int icmp6_len,
2318 uint8_t opt_type,
2319 u_int nd_hdr_size,
2320 switch_port_t send_port)
2321{
2322 const uint8_t * linkaddr;
2323 const uint8_t * ptr;
2324 const struct nd_opt_hdr * nd_opt;
2325 u_int nd_size;
2326
2327 ptr = (const uint8_t *)icmp6;
2328 nd_size = nd_hdr_size + LINKADDR_OPT_LEN;
2329 if (icmp6_len < nd_size) {
2330 /* no LINKADDR option */
2331 return;
2332 }
2333 nd_opt = (const struct nd_opt_hdr *)(const void *)(ptr + nd_hdr_size);
2334 T_QUIET;
2335 T_ASSERT_EQ(nd_opt->nd_opt_type, opt_type, NULL);
2336 T_QUIET;
2337 T_ASSERT_EQ(GET_ND_OPT_LEN(nd_opt->nd_opt_len), LINKADDR_OPT_LEN, NULL);
2338 linkaddr = (const uint8_t *)(nd_opt + 1);
2339 if (port->mac_nat) {
2340 bool equal;
2341
2342 equal = (bcmp(linkaddr, &port->member_mac,
2343 sizeof(port->member_mac)) == 0);
2344 T_QUIET;
2345 T_ASSERT_TRUE(equal, "%s -> %s sender hardware translated",
2346 send_port->member_ifname,
2347 port->member_ifname);
2348 } else {
2349 /* source hw must match the sender */
2350 T_QUIET;
2351 T_ASSERT_EQ(linkaddr[EA_UNIT_INDEX], send_port->unit,
2352 "%s -> %s unit %u expected %u",
2353 send_port->member_ifname,
2354 port->member_ifname,
2355 linkaddr[EA_UNIT_INDEX], send_port->unit);
2356 }
2357}
2358
2359static void
2360validate_mac_nat_icmp6_out(switch_port_t port, const struct icmp6_hdr * icmp6,
2361 u_int icmp6_len, switch_port_t send_port)
2362{
2363 switch (icmp6->icmp6_type) {
2364 case ND_NEIGHBOR_ADVERT:
2365 validate_mac_nat_nd6(port, icmp6, icmp6_len,
2366 ND_OPT_TARGET_LINKADDR,
2367 sizeof(struct nd_neighbor_advert),
2368 send_port);
2369 break;
2370 case ND_NEIGHBOR_SOLICIT:
2371 validate_mac_nat_nd6(port, icmp6, icmp6_len,
2372 ND_OPT_SOURCE_LINKADDR,
2373 sizeof(struct nd_neighbor_solicit),
2374 send_port);
2375 break;
2376 case ND_ROUTER_SOLICIT:
2377 validate_mac_nat_nd6(port, icmp6, icmp6_len,
2378 ND_OPT_SOURCE_LINKADDR,
2379 sizeof(struct nd_router_solicit),
2380 send_port);
2381 break;
2382 default:
2383 T_FAIL("Unsupported icmp6 type %d", icmp6->icmp6_type);
2384 break;
2385 }
2386}
2387
2388static void
2389validate_mac_nat_nd6_out(switch_port_t port, const ether_header_t * eh_p,
2390 u_int pkt_len, void * context)
2391{
2392 const struct icmp6_hdr * icmp6;
2393 const struct ip6_hdr * ip6;
2394 switch_port_t send_port = (switch_port_t)context;
2395
2396 if (S_debug) {
2397 T_LOG("%s received %u bytes", port->member_ifname, pkt_len);
2398 ethernet_frame_validate(eh_p, pkt_len, true);
2399 }
2400 T_QUIET;
2401 T_ASSERT_EQ(ntohs(eh_p->ether_type), (u_short)ETHERTYPE_IPV6, NULL);
2402 ip6 = (const struct ip6_hdr *)(const void *)(eh_p + 1);
2403 icmp6 = (const struct icmp6_hdr *)(const void *)(ip6 + 1);
2404 T_QUIET;
2405 T_ASSERT_GE(pkt_len, (u_int)MIN_ICMP6_LEN, NULL);
2406 T_QUIET;
2407 T_ASSERT_EQ(ip6->ip6_nxt, IPPROTO_ICMPV6, NULL);
2408
2409 /* validate the ethernet header */
2410 if (port->mac_nat) {
2411 bool equal;
2412
2413 /* source ethernet must match MAC-NAT interface */
2414 equal = (bcmp(eh_p->ether_shost, &port->member_mac,
2415 sizeof(port->member_mac)) == 0);
2416 if (!equal) {
2417 ethernet_frame_validate(eh_p, pkt_len, true);
2418 }
2419 T_QUIET;
2420 T_ASSERT_TRUE(equal, "%s -> %s source address translated",
2421 send_port->member_ifname,
2422 port->member_ifname);
2423 } else {
2424 /* source ethernet must match the sender */
2425 T_QUIET;
2426 T_ASSERT_EQ(eh_p->ether_shost[EA_UNIT_INDEX], send_port->unit,
2427 "%s -> %s unit %u expected %u",
2428 send_port->member_ifname,
2429 port->member_ifname,
2430 eh_p->ether_shost[EA_UNIT_INDEX], send_port->unit);
2431 }
2432 /* validate the icmp6 payload */
2433 validate_mac_nat_icmp6_out(port, icmp6,
2434 pkt_len - ETHER_IPV6_LEN,
2435 send_port);
2436 port->test_count++;
2437}
2438
2439static void
2440mac_nat_test_nd6_out(switch_port_list_t port_list)
2441{
2442 ether_addr_t * ext_mac;
2443 switch_port_t ext_port;
2444 u_int i;
2445 union ifbrip ip_dst;
2446 switch_port_t port;
2447
2448 get_external_ip_address(AF_INET6, &ip_dst);
2449 ext_port = port_list->list;
2450 T_QUIET;
2451 T_ASSERT_TRUE(ext_port->mac_nat, NULL);
2452 ext_mac = &ext_port->member_mac;
2453 for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
2454 if (port->mac_nat) {
2455 continue;
2456 }
2457 /* neighbor solicit */
2458 for (u_int j = 0; j < port->num_addrs; j++) {
2459 ether_addr_t eaddr;
2460 union ifbrip ip_src;
2461
2462 set_ethernet_address(&eaddr, port->unit, j);
2463 get_ip_address(AF_INET6, port->unit, j, &ip_src);
2464 switch_port_send_nd6(port,
2465 ND_NEIGHBOR_SOLICIT,
2466 &eaddr,
2467 &ip_src.ifbrip_addr6,
2468 NULL,
2469 NULL,
2470 &ip_dst.ifbrip_addr6);
2471 switch_port_list_check_receive(port_list, AF_INET,
2472 NULL, 0,
2473 validate_mac_nat_nd6_out,
2474 port);
2475 check_received_count(port_list, port, 1);
2476 }
2477 /* neighbor advert */
2478 for (u_int j = 0; j < port->num_addrs; j++) {
2479 ether_addr_t eaddr;
2480 union ifbrip ip_src;
2481
2482 set_ethernet_address(&eaddr, port->unit, j);
2483 get_ip_address(AF_INET6, port->unit, j, &ip_src);
2484 switch_port_send_nd6(port,
2485 ND_NEIGHBOR_ADVERT,
2486 &eaddr,
2487 &ip_src.ifbrip_addr6,
2488 NULL,
2489 &eaddr,
2490 &ip_src.ifbrip_addr6);
2491 switch_port_list_check_receive(port_list, AF_INET,
2492 NULL, 0,
2493 validate_mac_nat_nd6_out,
2494 port);
2495 check_received_count(port_list, port, 1);
2496 }
2497 /* router solicit */
2498 for (u_int j = 0; j < port->num_addrs; j++) {
2499 ether_addr_t eaddr;
2500 union ifbrip ip_src;
2501
2502 set_ethernet_address(&eaddr, port->unit, j);
2503 get_ip_address(AF_INET6, port->unit, j, &ip_src);
2504 //get_ipv6ll_address(port->unit, j, &ip_src.ifbrip_addr6);
2505 switch_port_send_nd6(port,
2506 ND_ROUTER_SOLICIT,
2507 &eaddr,
2508 &ip_src.ifbrip_addr6,
2509 NULL,
2510 NULL,
2511 NULL);
2512 switch_port_list_check_receive(port_list, AF_INET,
2513 NULL, 0,
2514 validate_mac_nat_nd6_out,
2515 port);
2516 check_received_count(port_list, port, 1);
2517 }
2518 }
2519 T_PASS("%s", __func__);
2520}
2521
2522static void
2523mac_nat_send_response(switch_port_t ext_port, uint8_t af, switch_port_t port)
2524{
2525 union ifbrip src_ip;
2526
2527 T_QUIET;
2528 T_ASSERT_TRUE(ext_port->mac_nat, "%s is MAC-NAT interface",
2529 ext_port->member_ifname);
2530 if (S_debug) {
2531 T_LOG("Generating UDP traffic destined to %s", port->ifname);
2532 }
2533 get_external_ip_address(af, &src_ip);
2534 for (u_int j = 0; j < port->num_addrs; j++) {
2535 union ifbrip ip;
2536
2537 get_ip_address(af, port->unit, j, &ip);
2538 switch_port_send_udp(ext_port,
2539 af,
2540 &ether_external,
2541 &src_ip,
2542 TEST_DEST_PORT,
2543 &ext_port->member_mac,
2544 &ip,
2545 TEST_SOURCE_PORT,
2546 NULL, 0);
2547 }
2548}
2549
2550
2551static void
2552mac_nat_test_ip_once(switch_port_list_t port_list, uint8_t af, bool retry)
2553{
2554 union ifbrip dst_ip;
2555 u_int i;
2556 switch_port_t port;
2557
2558 get_external_ip_address(af, &dst_ip);
2559 for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
2560 if (port->test_address_count == port->num_addrs) {
2561 /* already populated */
2562 continue;
2563 }
2564 if (S_debug) {
2565 T_LOG("Sending on %s", port->ifname);
2566 }
2567 for (u_int j = 0; j < port->num_addrs; j++) {
2568 uint32_t generation;
2569
2570 if (retry) {
2571 uint64_t addr_bit;
2572
2573 addr_bit = 1 << j;
2574 if ((port->test_address_present & addr_bit)
2575 != 0) {
2576 /* already present */
2577 continue;
2578 }
2579 T_LOG("Retry port %s unit %u address %u",
2580 port->ifname, port->unit, j);
2581 }
2582
2583 generation = next_generation();
2584 send_generation(port,
2585 af,
2586 j,
2587 &ether_external,
2588 &dst_ip,
2589 generation);
2590
2591 /* receive across all ports */
2592 check_receive_generation(port_list,
2593 af,
2594 generation,
2595 validate_mac_nat,
2596 NULL);
2597
2598 /* ensure that every port saw the packet */
2599 check_received_count(port_list, port, 1);
2600 }
2601 }
2602 return;
2603}
2604
2605static void
2606mac_nat_test_ip(switch_port_list_t port_list, uint8_t af)
2607{
2608 u_int i;
2609 switch_port_t port;
2610 bool verified = false;
2611
2612 /*
2613 * Send a packet from every port in the list so that the bridge
2614 * learns the MAC addresses and IP addresses.
2615 */
2616#define MAC_NAT_MAX_TRIES 20
2617 for (int try = 1; try < BROADCAST_MAX_TRIES; try++) {
2618 bool retry = (try > 1);
2619
2620 if (!retry) {
2621 T_LOG("%s: #ports %u #addrs %u",
2622 __func__,
2623 port_list->count, port_list->list->num_addrs);
2624 } else {
2625 T_LOG("%s: #ports %u #addrs %u destination (TRY=%d)",
2626 __func__,
2627 port_list->count, port_list->list->num_addrs,
2628 try);
2629 }
2630 mac_nat_test_ip_once(port_list, af, retry);
2631 /*
2632 * In the event of a memory allocation failure, it's possible
2633 * that the address was not learned. Figure out whether
2634 * all addresses are present, and if not, we'll retry on
2635 * those that are not present.
2636 */
2637 verified = switch_port_list_verify_mac_nat(port_list, false);
2638 if (verified) {
2639 break;
2640 }
2641 /* wait a short time to allow the system to recover */
2642 usleep(100 * 1000);
2643 }
2644 T_QUIET;
2645 T_ASSERT_TRUE(verified, "All addresses present");
2646
2647 /*
2648 * The bridge now has an IP address <-> MAC address binding for every
2649 * address on each internal interface.
2650 *
2651 * Generate an inbound packet on the MAC-NAT interface targeting
2652 * each interface address. Verify that the packet appears on
2653 * the appropriate internal address with appropriate translation.
2654 */
2655 for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
2656 if (port->mac_nat) {
2657 continue;
2658 }
2659 mac_nat_send_response(port_list->list, af, port);
2660
2661 /* receive the generated traffic */
2662 switch_port_list_check_receive(port_list, AF_INET, NULL, 0,
2663 validate_mac_nat_in,
2664 NULL);
2665
2666 /* verify that only the single port got the packet */
2667 mac_nat_check_received_count(port_list, port);
2668 }
2669 T_PASS("%s", __func__);
2670}
2671
2672/**
2673** interface management
2674**/
2675
2676static int
2677ifnet_get_lladdr(int s, const char * ifname, ether_addr_t * eaddr)
2678{
2679 int err;
2680 struct ifreq ifr;
2681
2682 bzero(&ifr, sizeof(ifr));
2683 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
2684 ifr.ifr_addr.sa_family = AF_LINK;
2685 ifr.ifr_addr.sa_len = ETHER_ADDR_LEN;
2686 err = ioctl(s, SIOCGIFLLADDR, &ifr);
2687 T_QUIET;
2688 T_ASSERT_POSIX_SUCCESS(err, "SIOCGIFLLADDR %s", ifname);
2689 bcopy(ifr.ifr_addr.sa_data, eaddr->octet, ETHER_ADDR_LEN);
2690 return err;
2691}
2692
2693
2694static int
2695ifnet_attach_ip(int s, char * name)
2696{
2697 int err;
2698 struct ifreq ifr;
2699
2700 bzero(&ifr, sizeof(ifr));
2701 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
2702 err = ioctl(s, SIOCPROTOATTACH, &ifr);
2703 T_QUIET;
2704 T_ASSERT_POSIX_SUCCESS(err, "SIOCPROTOATTACH %s", ifr.ifr_name);
2705 return err;
2706}
2707
2708#if 0
2709static int
2710ifnet_detach_ip(int s, char * name)
2711{
2712 int err;
2713 struct ifreq ifr;
2714
2715 bzero(&ifr, sizeof(ifr));
2716 strncpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
2717 err = ioctl(s, SIOCPROTODETACH, &ifr);
2718 T_QUIET;
2719 T_ASSERT_POSIX_SUCCESS(err, "SIOCPROTODETACH %s", ifr.ifr_name);
2720 return err;
2721}
2722#endif
2723
2724static int
2725ifnet_destroy(int s, const char * ifname, bool fail_on_error)
2726{
2727 int err;
2728 struct ifreq ifr;
2729
2730 bzero(&ifr, sizeof(ifr));
2731 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
2732 err = ioctl(s, SIOCIFDESTROY, &ifr);
2733 if (fail_on_error) {
2734 T_QUIET;
2735 T_ASSERT_POSIX_SUCCESS(err, "SIOCSIFDESTROY %s", ifr.ifr_name);
2736 }
2737 if (err < 0) {
2738 T_LOG("SIOCSIFDESTROY %s", ifr.ifr_name);
2739 }
2740 return err;
2741}
2742
2743static int
2744ifnet_set_flags(int s, const char * ifname,
2745 uint16_t flags_set, uint16_t flags_clear)
2746{
2747 uint16_t flags_after;
2748 uint16_t flags_before;
2749 struct ifreq ifr;
2750 int ret;
2751
2752 bzero(&ifr, sizeof(ifr));
2753 strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
2754 ret = ioctl(s, SIOCGIFFLAGS, (caddr_t)&ifr);
2755 if (ret != 0) {
2756 T_LOG("SIOCGIFFLAGS %s", ifr.ifr_name);
2757 return ret;
2758 }
2759 flags_before = (uint16_t)ifr.ifr_flags;
2760 ifr.ifr_flags |= flags_set;
2761 ifr.ifr_flags &= ~(flags_clear);
2762 flags_after = (uint16_t)ifr.ifr_flags;
2763 if (flags_before == flags_after) {
2764 /* nothing to do */
2765 ret = 0;
2766 } else {
2767 /* issue the ioctl */
2768 T_QUIET;
2769 T_ASSERT_POSIX_SUCCESS(ioctl(s, SIOCSIFFLAGS, &ifr),
2770 "SIOCSIFFLAGS %s 0x%x",
2771 ifr.ifr_name, (uint16_t)ifr.ifr_flags);
2772 if (S_debug) {
2773 T_LOG("setflags(%s set 0x%x clear 0x%x) 0x%x => 0x%x",
2774 ifr.ifr_name, flags_set, flags_clear,
2775 flags_before, flags_after);
2776 }
2777 }
2778 return ret;
2779}
2780
2781#define BRIDGE_NAME "bridge"
2782#define BRIDGE200 BRIDGE_NAME "200"
2783
2784#define FETH_NAME "feth"
2785
2786/* On some platforms with DEBUG kernel, we need to wait a while */
2787#define SIFCREATE_RETRY 600
2788
2789static int
2790ifnet_create(int s, const char * ifname)
2791{
2792 int error = 0;
2793 struct ifreq ifr;
2794
2795 bzero(&ifr, sizeof(ifr));
2796 strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
2797
2798 for (int i = 0; i < SIFCREATE_RETRY; i++) {
2799 if (ioctl(s, SIOCIFCREATE, &ifr) < 0) {
2800 error = errno;
2801 T_LOG("SIOCSIFCREATE %s: %s", ifname,
2802 strerror(error));
2803 if (error == EBUSY) {
2804 /* interface is tearing down, try again */
2805 usleep(10000);
2806 } else if (error == EEXIST) {
2807 /* interface exists, try destroying it */
2808 (void)ifnet_destroy(s, ifname, false);
2809 } else {
2810 /* unexpected failure */
2811 break;
2812 }
2813 } else {
2814 error = 0;
2815 break;
2816 }
2817 }
2818 if (error == 0) {
2819 error = ifnet_set_flags(s, ifname, IFF_UP, 0);
2820 }
2821 return error;
2822}
2823
2824static int
2825siocdrvspec(int s, const char * ifname,
2826 u_long op, void *arg, size_t argsize, bool set)
2827{
2828 struct ifdrv ifd;
2829
2830 memset(&ifd, 0, sizeof(ifd));
2831 strlcpy(ifd.ifd_name, ifname, sizeof(ifd.ifd_name));
2832 ifd.ifd_cmd = op;
2833 ifd.ifd_len = argsize;
2834 ifd.ifd_data = arg;
2835 return ioctl(s, set ? SIOCSDRVSPEC : SIOCGDRVSPEC, &ifd);
2836}
2837
2838
2839static int
2840fake_set_peer(int s, const char * feth, const char * feth_peer)
2841{
2842 struct if_fake_request iffr;
2843 int ret;
2844
2845 bzero((char *)&iffr, sizeof(iffr));
2846 if (feth_peer != NULL) {
2847 strlcpy(iffr.iffr_peer_name, feth_peer,
2848 sizeof(iffr.iffr_peer_name));
2849 }
2850 ret = siocdrvspec(s, feth, IF_FAKE_S_CMD_SET_PEER,
2851 &iffr, sizeof(iffr), true);
2852 T_QUIET;
2853 T_ASSERT_POSIX_SUCCESS(ret,
2854 "SIOCDRVSPEC(%s, IF_FAKE_S_CMD_SET_PEER, %s)",
2855 feth, (feth_peer != NULL) ? feth_peer : "<none>");
2856 return ret;
2857}
2858
2859static int
2860bridge_add_member(int s, const char * bridge, const char * member)
2861{
2862 struct ifbreq req;
2863 int ret;
2864
2865 memset(&req, 0, sizeof(req));
2866 strlcpy(req.ifbr_ifsname, member, sizeof(req.ifbr_ifsname));
2867 ret = siocdrvspec(s, bridge, BRDGADD, &req, sizeof(req), true);
2868 T_QUIET;
2869 T_ASSERT_POSIX_SUCCESS(ret, "%s %s %s", __func__, bridge, member);
2870 return ret;
2871}
2872
2873
2874static int
2875bridge_set_mac_nat(int s, const char * bridge, const char * member, bool enable)
2876{
2877 uint32_t flags;
2878 bool need_set = false;
2879 struct ifbreq req;
2880 int ret;
2881
2882 memset(&req, 0, sizeof(req));
2883 strlcpy(req.ifbr_ifsname, member, sizeof(req.ifbr_ifsname));
2884 ret = siocdrvspec(s, bridge, BRDGGIFFLGS, &req, sizeof(req), false);
2885 T_QUIET;
2886 T_ASSERT_POSIX_SUCCESS(ret, "BRDGGIFFLGS %s %s", bridge, member);
2887 flags = req.ifbr_ifsflags;
2888 if (enable) {
2889 if ((flags & IFBIF_MAC_NAT) == 0) {
2890 need_set = true;
2891 req.ifbr_ifsflags |= IFBIF_MAC_NAT;
2892 }
2893 /* need to set it */
2894 } else if ((flags & IFBIF_MAC_NAT) != 0) {
2895 /* need to clear it */
2896 need_set = true;
2897 req.ifbr_ifsflags &= ~(uint32_t)IFBIF_MAC_NAT;
2898 }
2899 if (need_set) {
2900 ret = siocdrvspec(s, bridge, BRDGSIFFLGS,
2901 &req, sizeof(req), true);
2902 T_QUIET;
2903 T_ASSERT_POSIX_SUCCESS(ret, "BRDGSIFFLGS %s %s 0x%x => 0x%x",
2904 bridge, member,
2905 flags, req.ifbr_ifsflags);
2906 }
2907 return ret;
2908}
2909
2910static struct ifbareq *
2911bridge_rt_table_copy_common(const char * bridge, u_int * ret_count)
2912{
2913 struct ifbaconf ifbac;
2914 u_int len = 8 * 1024;
2915 char * inbuf = NULL;
2916 char * ninbuf;
2917 int ret;
2918 struct ifbareq * rt_table = NULL;
2919 int s;
2920
2921 s = inet_dgram_socket();
2922
2923 /*
2924 * BRDGRTS should work like other ioctl's where passing in NULL
2925 * for the buffer says "tell me how many there are". Unfortunately,
2926 * it doesn't so we have to pass in a buffer, then check that it
2927 * was too big.
2928 */
2929 for (;;) {
2930 ninbuf = realloc(inbuf, len);
2931 T_QUIET;
2932 T_ASSERT_NOTNULL((void *)ninbuf, "realloc %u", len);
2933 ifbac.ifbac_len = len;
2934 ifbac.ifbac_buf = inbuf = ninbuf;
2935 ret = siocdrvspec(s, bridge, BRDGRTS,
2936 &ifbac, sizeof(ifbac), false);
2937 T_QUIET;
2938 T_ASSERT_POSIX_SUCCESS(ret, "%s %s", __func__, bridge);
2939 if ((ifbac.ifbac_len + sizeof(*rt_table)) < len) {
2940 /* we passed a buffer larger than what was required */
2941 break;
2942 }
2943 len *= 2;
2944 }
2945 if (ifbac.ifbac_len == 0) {
2946 free(ninbuf);
2947 T_LOG("No bridge routing entries");
2948 goto done;
2949 }
2950 *ret_count = ifbac.ifbac_len / sizeof(*rt_table);
2951 rt_table = (struct ifbareq *)(void *)ninbuf;
2952done:
2953 if (rt_table == NULL) {
2954 *ret_count = 0;
2955 }
2956 if (s >= 0) {
2957 close(s);
2958 }
2959 return rt_table;
2960}
2961
2962static struct ifbareq *
2963bridge_rt_table_copy(u_int * ret_count)
2964{
2965 return bridge_rt_table_copy_common(BRIDGE200, ret_count);
2966}
2967
2968static void
2969bridge_rt_table_log(struct ifbareq *rt_table, u_int count)
2970{
2971 u_int i;
2972 char ntoabuf[ETHER_NTOA_BUFSIZE];
2973 struct ifbareq * ifba;
2974
2975 for (i = 0, ifba = rt_table; i < count; i++, ifba++) {
2976 ether_ntoa_buf((const ether_addr_t *)&ifba->ifba_dst,
2977 ntoabuf, sizeof(ntoabuf));
2978 T_LOG("%s %s %lu", ifba->ifba_ifsname, ntoabuf,
2979 ifba->ifba_expire);
2980 }
2981 return;
2982}
2983
2984static struct ifbrmne *
2985bridge_mac_nat_entries_copy_common(const char * bridge, u_int * ret_count)
2986{
2987 char * buf = NULL;
2988 u_int count = 0;
2989 int err;
2990 u_int i;
2991 struct ifbrmnelist mnl;
2992 struct ifbrmne * ret_list = NULL;
2993 int s;
2994 char * scan;
2995
2996
2997 s = inet_dgram_socket();
2998
2999 /* find out how many there are */
3000 bzero(&mnl, sizeof(mnl));
3001 err = siocdrvspec(s, bridge, BRDGGMACNATLIST, &mnl, sizeof(mnl), false);
3002 if (err != 0 && S_cleaning_up) {
3003 T_LOG("BRDGGMACNATLIST %s failed %d", bridge, errno);
3004 goto done;
3005 }
3006 T_QUIET;
3007 T_ASSERT_POSIX_SUCCESS(err, "BRDGGMACNATLIST %s", bridge);
3008 T_QUIET;
3009 T_ASSERT_GE(mnl.ifbml_elsize, (uint16_t)sizeof(struct ifbrmne),
3010 "mac nat entry size %u minsize %u",
3011 mnl.ifbml_elsize, (u_int)sizeof(struct ifbrmne));
3012 if (mnl.ifbml_len == 0) {
3013 goto done;
3014 }
3015
3016 /* call again with a buffer large enough to hold them */
3017 buf = malloc(mnl.ifbml_len);
3018 T_QUIET;
3019 T_ASSERT_NOTNULL(buf, "mac nat entries buffer");
3020 mnl.ifbml_buf = buf;
3021 err = siocdrvspec(s, bridge, BRDGGMACNATLIST, &mnl, sizeof(mnl), false);
3022 T_QUIET;
3023 T_ASSERT_POSIX_SUCCESS(err, "BRDGGMACNATLIST %s", bridge);
3024 count = mnl.ifbml_len / mnl.ifbml_elsize;
3025 if (count == 0) {
3026 goto done;
3027 }
3028 if (mnl.ifbml_elsize == sizeof(struct ifbrmne)) {
3029 /* element size is expected size, no need to "right-size" it */
3030 ret_list = (struct ifbrmne *)(void *)buf;
3031 buf = NULL;
3032 goto done;
3033 }
3034 /* element size is larger than we expect, create a "right-sized" array */
3035 ret_list = malloc(count * sizeof(*ret_list));
3036 T_QUIET;
3037 T_ASSERT_NOTNULL(ret_list, "mac nat entries list");
3038 for (i = 0, scan = buf; i < count; i++, scan += mnl.ifbml_elsize) {
3039 struct ifbrmne * ifbmne;
3040
3041 ifbmne = (struct ifbrmne *)(void *)scan;
3042 ret_list[i] = *ifbmne;
3043 }
3044done:
3045 if (s >= 0) {
3046 close(s);
3047 }
3048 if (buf != NULL) {
3049 free(buf);
3050 }
3051 *ret_count = count;
3052 return ret_list;
3053}
3054
3055static struct ifbrmne *
3056bridge_mac_nat_entries_copy(u_int * ret_count)
3057{
3058 return bridge_mac_nat_entries_copy_common(BRIDGE200, ret_count);
3059}
3060
3061static void
3062bridge_mac_nat_entries_log(struct ifbrmne * entries, u_int count)
3063{
3064 u_int i;
3065 char ntoabuf[ETHER_NTOA_BUFSIZE];
3066 char ntopbuf[INET6_ADDRSTRLEN];
3067 struct ifbrmne * scan;
3068
3069 for (i = 0, scan = entries; i < count; i++, scan++) {
3070 ether_ntoa_buf((const ether_addr_t *)&scan->ifbmne_mac,
3071 ntoabuf, sizeof(ntoabuf));
3072 inet_ntop(scan->ifbmne_af, &scan->ifbmne_ip,
3073 ntopbuf, sizeof(ntopbuf));
3074 printf("%s %s %s %lu\n",
3075 scan->ifbmne_ifname, ntopbuf, ntoabuf,
3076 (unsigned long)scan->ifbmne_expire);
3077 }
3078 return;
3079}
3080
3081/**
3082** Test Main
3083**/
3084static u_int S_n_ports;
3085static switch_port_list_t S_port_list;
3086
3087static void
3088bridge_cleanup(const char * bridge, u_int n_ports, bool fail_on_error);
3089
3090static void
3091cleanup_common(bool dump_table)
3092{
3093 if (S_n_ports == 0) {
3094 return;
3095 }
3096 S_cleaning_up = true;
3097 if ((S_port_list != NULL && S_port_list->mac_nat)
3098 || (dump_table && S_port_list != NULL)) {
3099 switch_port_list_log(S_port_list);
3100 if (S_port_list->mac_nat) {
3101 switch_port_list_verify_mac_nat(S_port_list, true);
3102 }
3103 (void)switch_port_list_verify_rt_table(S_port_list, true);
3104 }
3105 if (S_debug) {
3106 T_LOG("sleeping for 5 seconds\n");
3107 sleep(5);
3108 }
3109 bridge_cleanup(BRIDGE200, S_n_ports, false);
3110 return;
3111}
3112
3113static void
3114cleanup(void)
3115{
3116 cleanup_common(true);
3117 return;
3118}
3119
3120static void
3121sigint_handler(__unused int sig)
3122{
3123 cleanup_common(false);
3124 signal(SIGINT, SIG_DFL);
3125}
3126
3127static switch_port_list_t
3128bridge_setup(char * bridge, u_int n_ports, u_int num_addrs, bool mac_nat)
3129{
3130 errno_t err;
3131 switch_port_list_t list = NULL;
3132 int s;
3133
3134 S_n_ports = n_ports;
3135 T_ATEND(cleanup);
3136 T_SETUPBEGIN;
3137 s = inet_dgram_socket();
3138 err = ifnet_create(s, bridge);
3139 if (err != 0) {
3140 goto done;
3141 }
3142 list = switch_port_list_alloc(n_ports, mac_nat);
3143 for (u_int i = 0; i < n_ports; i++) {
3144 bool do_mac_nat;
3145 char ifname[IFNAMSIZ];
3146 char member_ifname[IFNAMSIZ];
3147 ether_addr_t member_mac;
3148
3149 snprintf(ifname, sizeof(ifname), "%s%d",
3150 FETH_NAME, i);
3151 snprintf(member_ifname, sizeof(member_ifname), "%s%d",
3152 FETH_NAME, i + n_ports);
3153 err = ifnet_create(s, ifname);
3154 if (err != 0) {
3155 goto done;
3156 }
3157 ifnet_attach_ip(s, ifname);
3158 err = ifnet_create(s, member_ifname);
3159 if (err != 0) {
3160 goto done;
3161 }
3162 err = ifnet_get_lladdr(s, member_ifname, &member_mac);
3163 if (err != 0) {
3164 goto done;
3165 }
3166 err = fake_set_peer(s, ifname, member_ifname);
3167 if (err != 0) {
3168 goto done;
3169 }
3170 /* add the interface's peer to the bridge */
3171 err = bridge_add_member(s, bridge, member_ifname);
3172 if (err != 0) {
3173 goto done;
3174 }
3175
3176 do_mac_nat = (i == 0 && mac_nat);
3177 if (do_mac_nat) {
3178 /* enable MAC NAT on unit 0 */
3179 err = bridge_set_mac_nat(s, bridge, member_ifname,
3180 true);
3181 if (err != 0) {
3182 goto done;
3183 }
3184 }
3185 /* we'll send/receive on the interface */
3186 err = switch_port_list_add_port(list, i, ifname, member_ifname,
3187 &member_mac, num_addrs,
3188 do_mac_nat);
3189 if (err != 0) {
3190 goto done;
3191 }
3192 }
3193done:
3194 if (s >= 0) {
3195 close(s);
3196 }
3197 if (err != 0 && list != NULL) {
3198 switch_port_list_dealloc(list);
3199 list = NULL;
3200 }
3201 T_SETUPEND;
3202 return list;
3203}
3204
3205static void
3206bridge_cleanup(const char * bridge, u_int n_ports, bool fail_on_error)
3207{
3208 int s;
3209
3210 s = inet_dgram_socket();
3211 ifnet_destroy(s, bridge, fail_on_error);
3212 for (u_int i = 0; i < n_ports; i++) {
3213 char ifname[IFNAMSIZ];
3214 char member_ifname[IFNAMSIZ];
3215
3216 snprintf(ifname, sizeof(ifname), "%s%d",
3217 FETH_NAME, i);
3218 snprintf(member_ifname, sizeof(member_ifname), "%s%d",
3219 FETH_NAME, i + n_ports);
3220 ifnet_destroy(s, ifname, fail_on_error);
3221 ifnet_destroy(s, member_ifname, fail_on_error);
3222 }
3223 if (s >= 0) {
3224 close(s);
3225 }
3226 S_n_ports = 0;
3227 return;
3228}
3229
3230/*
3231 * Basic Bridge Tests
3232 *
3233 * Broadcast
3234 * - two cases: actual broadcast, unknown ethernet
3235 * - send broadcast packets
3236 * - verify all received
3237 * - check bridge rt list contains all expected MAC addresses
3238 * - send unicast ARP packets
3239 * - verify packets received only on expected port
3240 *
3241 * MAC-NAT
3242 * - verify ARP translation
3243 * - verify IPv4 translation
3244 * - verify DHCP broadcast bit conversion
3245 * - verify IPv6 translation
3246 * - verify ND6 translation (Neighbor, Router)
f427ee49
A
3247 * - verify IPv4 subnet-local broadcast to MAC-NAT interface link-layer
3248 * address arrives on all member links
ea3f0419
A
3249 */
3250
3251static void
3252bridge_test(packet_validator_t validator,
3253 void * context,
3254 const ether_addr_t * dst_eaddr,
3255 uint8_t af, u_int n_ports, u_int num_addrs)
3256{
3257#if TARGET_OS_BRIDGE
3258 T_SKIP("Test uses too much memory");
3259#else /* TARGET_OS_BRIDGE */
3260 switch_port_list_t port_list;
3261
3262 signal(SIGINT, sigint_handler);
3263 port_list = bridge_setup(BRIDGE200, n_ports, num_addrs, false);
3264 if (port_list == NULL) {
3265 T_FAIL("bridge_setup");
3266 return;
3267 }
3268 S_port_list = port_list;
3269 bridge_learning_test(port_list, af, validator, context, dst_eaddr);
3270
3271 //T_LOG("Sleeping for 5 seconds");
3272 //sleep(5);
3273 bridge_cleanup(BRIDGE200, n_ports, true);
3274 switch_port_list_dealloc(port_list);
3275 return;
3276#endif /* TARGET_OS_BRIDGE */
3277}
3278
3279static void
3280bridge_test_mac_nat_ipv4(u_int n_ports, u_int num_addrs)
3281{
3282#if TARGET_OS_BRIDGE
3283 T_SKIP("Test uses too much memory");
3284#else /* TARGET_OS_BRIDGE */
3285 switch_port_list_t port_list;
3286
3287 signal(SIGINT, sigint_handler);
3288 port_list = bridge_setup(BRIDGE200, n_ports, num_addrs, true);
3289 if (port_list == NULL) {
3290 T_FAIL("bridge_setup");
3291 return;
3292 }
3293 S_port_list = port_list;
3294
3295 /* verify that IPv4 packets get translated when necessary */
3296 mac_nat_test_ip(port_list, AF_INET);
3297
3298 /* verify the DHCP broadcast bit gets set appropriately */
f427ee49 3299 mac_nat_test_dhcp(port_list, false);
ea3f0419
A
3300
3301 /* verify that ARP packet gets translated when necessary */
3302 mac_nat_test_arp_out(port_list);
3303 mac_nat_test_arp_in(port_list);
3304
f427ee49
A
3305 /* verify IP broadcast to MAC-NAT interface link layer address */
3306 mac_nat_test_dhcp(port_list, true);
3307
ea3f0419
A
3308 if (S_debug) {
3309 T_LOG("Sleeping for 5 seconds");
3310 sleep(5);
3311 }
3312 bridge_cleanup(BRIDGE200, n_ports, true);
3313 switch_port_list_dealloc(port_list);
3314 return;
3315#endif /* TARGET_OS_BRIDGE */
3316}
3317
3318static void
3319bridge_test_mac_nat_ipv6(u_int n_ports, u_int num_addrs)
3320{
3321#if TARGET_OS_BRIDGE
3322 T_SKIP("Test uses too much memory");
3323#else /* TARGET_OS_BRIDGE */
3324 switch_port_list_t port_list;
3325
3326 signal(SIGINT, sigint_handler);
3327 port_list = bridge_setup(BRIDGE200, n_ports, num_addrs, true);
3328 if (port_list == NULL) {
3329 T_FAIL("bridge_setup");
3330 return;
3331 }
3332 S_port_list = port_list;
3333
3334 /* verify that IPv6 packets get translated when necessary */
3335 mac_nat_test_ip(port_list, AF_INET6);
3336
3337 /* verify that ND6 packet gets translated when necessary */
3338 mac_nat_test_nd6_out(port_list);
3339 if (S_debug) {
3340 T_LOG("Sleeping for 5 seconds");
3341 sleep(5);
3342 }
3343 bridge_cleanup(BRIDGE200, n_ports, true);
3344 switch_port_list_dealloc(port_list);
3345 return;
3346#endif /* TARGET_OS_BRIDGE */
3347}
3348
3349static void
3350system_cmd(const char *cmd, bool fail_on_error)
3351{
3352 pid_t pid = -1;
3353 int exit_status = 0;
3354 const char *argv[] = {
3355 "/usr/local/bin/bash",
3356 "-c",
3357 cmd,
3358 NULL
3359 };
3360
3361 int rc = dt_launch_tool(&pid, (char **)(void *)argv, false, NULL, NULL);
3362 T_QUIET;
3363 T_ASSERT_EQ(rc, 0, "dt_launch_tool(%s) failed", cmd);
3364
3365 if (dt_waitpid(pid, &exit_status, NULL, 30)) {
3366 T_QUIET;
3367 T_ASSERT_MACH_SUCCESS(exit_status, "command(%s)", cmd);
3368 } else {
3369 if (fail_on_error) {
3370 T_FAIL("dt_waitpid(%s) failed", cmd);
3371 }
3372 }
3373}
3374
3375static void
3376cleanup_pf(void)
3377{
3378 struct ifbrparam param;
3379 int s = inet_dgram_socket();
3380
3381 system_cmd("pfctl -d", false);
3382 system_cmd("pfctl -F all", false);
3383
3384 param.ifbrp_filter = 0;
3385 siocdrvspec(s, BRIDGE200, BRDGSFILT,
3386 &param, sizeof(param), true);
3387 return;
3388}
3389
3390static void
3391block_all_traffic(bool input, const char* infname1, const char* infname2)
3392{
3393 int s = inet_dgram_socket();
3394 int ret;
3395 struct ifbrparam param;
3396 char command[512];
3397 char *dir = input ? "in" : "out";
3398
3399 snprintf(command, sizeof(command), "echo \"block %s on %s all\nblock %s on %s all\n\" | pfctl -vvv -f -",
3400 dir, infname1, dir, infname2);
3401 /* enable block all filter */
3402 param.ifbrp_filter = IFBF_FILT_MEMBER | IFBF_FILT_ONLYIP;
3403 ret = siocdrvspec(s, BRIDGE200, BRDGSFILT,
3404 &param, sizeof(param), true);
3405 T_ASSERT_POSIX_SUCCESS(ret,
3406 "SIOCDRVSPEC(BRDGSFILT %s, 0x%x)",
3407 BRIDGE200, param.ifbrp_filter);
3408 // ignore errors such that not having pf.os doesn't raise any issues
3409 system_cmd(command, false);
3410 system_cmd("pfctl -e", true);
3411 system_cmd("pfctl -s all", true);
3412}
3413
3414/*
3415 * Basic bridge filter test
3416 *
3417 * For both broadcast and unicast transfers ensure that data can
3418 * be blocked using pf on the bridge
3419 */
3420
3421static void
3422filter_test(uint8_t af)
3423{
3424#if TARGET_OS_BRIDGE
3425 T_SKIP("pfctl isn't valid on this platform");
3426#else /* TARGET_OS_BRIDGE */
3427 switch_port_list_t port_list;
3428 switch_port_t port;
3429 const u_int n_ports = 2;
3430 u_int num_addrs = 1;
3431 u_int i;
3432 char ntoabuf[ETHER_NTOA_BUFSIZE];
3433 union ifbrip dst_ip;
3434 bool blocked = true;
3435 bool input = true;
3436 const char* ifnames[2];
3437
3438 signal(SIGINT, sigint_handler);
3439
3440 T_ATEND(cleanup);
3441 T_ATEND(cleanup_pf);
3442
3443 port_list = bridge_setup(BRIDGE200, n_ports, num_addrs, false);
3444 if (port_list == NULL) {
3445 T_FAIL("bridge_setup");
3446 return;
3447 }
3448
3449 ether_ntoa_buf(&ether_broadcast, ntoabuf, sizeof(ntoabuf));
3450
3451 S_port_list = port_list;
3452 for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
3453 ifnames[i] = port->member_ifname;
3454 }
3455
3456 get_broadcast_ip_address(af, &dst_ip);
3457 do {
3458 do {
3459 if (blocked) {
3460 block_all_traffic(input, ifnames[0], ifnames[1]);
3461 }
3462 for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
3463 if (S_debug) {
3464 T_LOG("Sending on %s", port->ifname);
3465 }
3466 for (u_int j = 0; j < port->num_addrs; j++) {
3467 uint32_t generation;
3468
3469 generation = next_generation();
3470 send_generation(port,
3471 af,
3472 j,
3473 &ether_broadcast,
3474 &dst_ip,
3475 generation);
3476
3477 /* receive across all ports */
3478 check_receive_generation(port_list,
3479 af,
3480 generation,
3481 validate_broadcast_dhost,
3482 NULL);
3483
3484 /* ensure that every port saw the right amount of packets*/
3485 if (blocked) {
3486 check_received_count(port_list, port, 0);
3487 } else {
3488 check_received_count(port_list, port, 1);
3489 }
3490 }
3491 }
3492 T_PASS("%s broadcast %s %s", __func__, blocked ? "blocked" : "not blocked", input ? "input" : "output");
3493 input = !input;
3494 cleanup_pf();
3495 } while (input == false && blocked);
3496 blocked = !blocked;
3497 } while (blocked == false);
3498
3499 do {
3500 do {
3501 if (blocked) {
3502 block_all_traffic(input, ifnames[0], ifnames[1]);
3503 }
3504 for (i = 0, port = port_list->list; i < port_list->count; i++, port++) {
3505 /* send unicast packets to every other port's MAC addresses */
3506 unicast_send_all(port_list, af, port);
3507
3508 /* receive all of that generated traffic */
3509 switch_port_list_check_receive(port_list, af, NULL, 0,
3510 validate_port_dhost, NULL);
3511
3512 /* ensure that every port saw the right amount of packets*/
3513 if (blocked) {
3514 check_received_count(port_list, port, 0);
3515 } else {
3516 check_received_count(port_list, port, 1);
3517 }
3518 }
3519 T_PASS("%s unicast %s %s", __func__, blocked ? "blocked" : "not blocked", input ? "input" : "output");
3520 input = !input;
3521 cleanup_pf();
3522 } while (input == false && blocked);
3523 blocked = !blocked;
3524 } while (blocked == false);
3525
3526 bridge_cleanup(BRIDGE200, n_ports, true);
3527 switch_port_list_dealloc(port_list);
3528 return;
3529#endif /* TARGET_OS_BRIDGE */
3530}
3531
3532T_DECL(if_bridge_bcast,
3533 "bridge broadcast IPv4",
3534 T_META_ASROOT(true))
3535{
3536 bridge_test(validate_broadcast_dhost, NULL, &ether_broadcast,
3537 AF_INET, 5, 1);
3538}
3539
3540T_DECL(if_bridge_bcast_many,
3541 "bridge broadcast many IPv4",
3542 T_META_ASROOT(true))
3543{
3544 bridge_test(validate_broadcast_dhost, NULL, &ether_broadcast,
3545 AF_INET, 5, 20);
3546}
3547
3548T_DECL(if_bridge_unknown,
3549 "bridge unknown host IPv4",
3550 T_META_ASROOT(true))
3551{
3552 bridge_test(validate_not_present_dhost, NULL, &ether_external,
3553 AF_INET, 5, 1);
3554}
3555
3556T_DECL(if_bridge_bcast_v6,
3557 "bridge broadcast IPv6",
3558 T_META_ASROOT(true))
3559{
3560 bridge_test(validate_broadcast_dhost, NULL, &ether_broadcast,
3561 AF_INET6, 5, 1);
3562}
3563
3564T_DECL(if_bridge_bcast_many_v6,
3565 "bridge broadcast many IPv6",
3566 T_META_ASROOT(true))
3567{
3568 bridge_test(validate_broadcast_dhost, NULL, &ether_broadcast,
3569 AF_INET6, 5, 20);
3570}
3571
3572T_DECL(if_bridge_unknown_v6,
3573 "bridge unknown host IPv6",
3574 T_META_ASROOT(true))
3575{
3576 bridge_test(validate_not_present_dhost, NULL, &ether_external,
3577 AF_INET6, 5, 1);
3578}
3579
3580T_DECL(if_bridge_mac_nat_ipv4,
3581 "bridge mac nat ipv4",
3582 T_META_ASROOT(true))
3583{
3584 bridge_test_mac_nat_ipv4(5, 10);
3585}
3586
3587T_DECL(if_bridge_mac_nat_ipv6,
3588 "bridge mac nat ipv6",
3589 T_META_ASROOT(true))
3590{
3591 bridge_test_mac_nat_ipv6(5, 10);
3592}
3593
3594T_DECL(if_bridge_filter_ipv4,
3595 "bridge filter ipv4",
3596 T_META_ASROOT(true))
3597{
3598 filter_test(AF_INET);
3599}
3600
3601T_DECL(if_bridge_filter_ipv6,
3602 "bridge filter ipv6",
3603 T_META_ASROOT(true))
3604{
3605 filter_test(AF_INET6);
3606}