2 * Copyright (c) 2019-2020 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
31 * - test if_bridge.c functionality
34 #include <darwintest.h>
40 #include <sys/socket.h>
41 #include <netinet/in.h>
42 #include <arpa/inet.h>
43 #include <sys/event.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>
55 #include <net/if_bridgevar.h>
56 #include <net/if_fake_var.h>
57 #include <sys/ioctl.h>
58 #include <sys/types.h>
62 #include <TargetConditionals.h>
63 #include <darwintest_utils.h>
68 static bool S_cleaning_up
;
70 #define ALL_ADDRS (uint32_t)(-1)
72 #define DHCP_PAYLOAD_MIN sizeof(struct bootp)
73 #define DHCP_FLAGS_BROADCAST ((u_short)0x8000)
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
;
81 #define ETHER_PKT_LEN (ETHER_HDR_LEN + ETHERMTU)
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
;
94 struct in_addr src_ip
;
95 struct in_addr dst_ip
;
98 unsigned short length
;
109 } ip_udp_tcp_header_u
;
112 struct in_addr src_ip
;
113 struct in_addr dst_ip
;
116 unsigned short length
;
125 struct in6_addr src_ip
;
126 struct in6_addr dst_ip
;
129 unsigned short length
;
133 char ifname
[IFNAMSIZ
];
134 char member_ifname
[IFNAMSIZ
]; /* member of bridge */
135 ether_addr_t member_mac
;
144 u_int test_address_count
;
145 uint64_t test_address_present
;
146 } switch_port
, *switch_port_t
;
153 } switch_port_list
, * switch_port_list_t
;
155 static struct ifbareq
*
156 bridge_rt_table_copy(u_int
* ret_count
);
159 bridge_rt_table_log(struct ifbareq
*rt_table
, u_int count
);
161 static struct ifbrmne
*
162 bridge_mac_nat_entries_copy(u_int
* ret_count
);
165 bridge_mac_nat_entries_log(struct ifbrmne
* entries
, u_int count
);
168 system_cmd(const char *cmd
, bool fail_on_error
);
171 inet_dgram_socket(void)
175 s
= socket(AF_INET
, SOCK_DGRAM
, 0);
177 T_ASSERT_POSIX_SUCCESS(s
, "socket(AF_INET, SOCK_DGRAM, 0)");
183 ** Packet creation/display
185 #define BOOTP_SERVER_PORT 67
186 #define BOOTP_CLIENT_PORT 68
188 #define TEST_SOURCE_PORT 14
189 #define TEST_DEST_PORT 15
191 #define EA_UNIT_INDEX 4
192 #define EA_ADDR_INDEX 5
195 set_ethernet_address(ether_addr_t
*eaddr
, u_int unit
, u_int addr_index
)
197 u_char
*a
= eaddr
->octet
;
203 a
[EA_UNIT_INDEX
] = (u_char
)unit
;
204 a
[EA_ADDR_INDEX
] = (u_char
)addr_index
;
207 #define TEN_NET 0x0a000000
208 #define TEN_1_NET (TEN_NET | 0x010000)
211 get_ipv4_address(u_int unit
, u_int addr_index
, struct in_addr
*ip
)
213 /* up to 255 units, 255 addresses */
214 ip
->s_addr
= htonl(TEN_1_NET
| (unit
<< 8) | addr_index
);
218 #define IN6ADDR_ULA_INIT \
219 {{{ 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
220 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}}
222 static struct in6_addr ula_address
= IN6ADDR_ULA_INIT
;
224 #define ULA_UNIT_INDEX 14
225 #define ULA_ADDR_INDEX 15
228 get_ipv6_address(u_int unit
, u_int addr_index
, struct in6_addr
*ip
)
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
;
238 get_ip_address(uint8_t af
, u_int unit
, u_int addr_index
, union ifbrip
*ip
)
242 get_ipv4_address(unit
, addr_index
, &ip
->ifbrip_addr
);
245 get_ipv6_address(unit
, addr_index
, &ip
->ifbrip_addr6
);
248 T_FAIL("unrecognized address family %u", af
);
254 ip_addresses_are_equal(uint8_t af
, union ifbrip
* ip1
, union ifbrip
* ip2
)
260 equal
= (ip1
->ifbrip_addr
.s_addr
== ip2
->ifbrip_addr
.s_addr
);
263 equal
= IN6_ARE_ADDR_EQUAL(&ip1
->ifbrip_addr6
,
267 T_FAIL("unrecognized address family %u", af
);
274 static ether_addr_t ether_broadcast
= {
275 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
278 static ether_addr_t ether_external
= {
279 { 0x80, 0x00, 0x00, 0x00, 0x00, 0x01 }
282 static inline struct in_addr
283 get_external_ipv4_address(void)
288 ip
.s_addr
= htonl(TEN_1_NET
| 0xff01);
293 get_external_ip_address(uint8_t af
, union ifbrip
* ip
)
298 ip
->ifbrip_addr
= get_external_ipv4_address();
302 ip
->ifbrip_addr6
= ula_address
;
303 ip
->ifbrip_addr6
.s6_addr
[1] = 0x80;
304 ip
->ifbrip_addr6
.s6_addr
[15] = 0x01;
307 T_FAIL("unrecognized address family %u", af
);
313 get_broadcast_ip_address(uint8_t af
, union ifbrip
* ip
)
317 ip
->ifbrip_addr
.s_addr
= INADDR_BROADCAST
;
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
;
326 T_FAIL("unrecognized address family %u", af
);
332 #define ETHER_NTOA_BUFSIZE (ETHER_ADDR_LEN * 3)
334 ether_ntoa_buf(const ether_addr_t
*n
, char * buf
, int buf_size
)
339 strlcpy(buf
, str
, buf_size
);
344 inet_ptrtop(int af
, const void * ptr
, char * buf
, socklen_t buf_size
)
353 bcopy(ptr
, &u
.ip
, sizeof(u
.ip
));
356 bcopy(ptr
, &u
.ip6
, sizeof(u
.ip6
));
361 return inet_ntop(af
, &u
, buf
, buf_size
);
364 static __inline__
char *
365 arpop_name(u_int16_t op
)
369 return "ARP REQUEST";
372 case ARPOP_REVREQUEST
:
373 return "REVARP REQUEST";
375 return "REVARP REPLY";
383 arp_frame_validate(const struct ether_arp
* earp
, u_int len
, bool dump
)
385 const struct arphdr
* arp_p
;
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
];
393 T_ASSERT_GE(len
, (u_int
)sizeof(*earp
),
394 "%s ARP packet size %u need %u",
395 __func__
, len
, (u_int
)sizeof(*earp
));
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
,
406 sizeof(buf_sender_ether
));
407 ether_ntoa_buf((const ether_addr_t
*)earp
->arp_tha
,
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
);
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
);
423 ip_frame_validate(const void * buf
, u_int buf_len
, bool dump
)
425 char buf_dst
[INET_ADDRSTRLEN
];
426 char buf_src
[INET_ADDRSTRLEN
];
427 const ip_udp_header_t
* ip_udp
;
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
));
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
));
444 T_ASSERT_GE(buf_len
, ip_len
, NULL
);
446 T_ASSERT_EQ(ip_udp
->ip
.ip_v
, IPVERSION
, NULL
);
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
) {
455 T_ASSERT_GE(buf_len
, (u_int
)sizeof(*ip_udp
), NULL
);
456 udp_len
= ntohs(ip_udp
->udp
.uh_ulen
);
458 T_ASSERT_GE(udp_len
, (u_int
)sizeof(ip_udp
->udp
), NULL
);
459 data_len
= udp_len
- (u_int
)sizeof(ip_udp
->udp
);
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
),
466 ntohs(ip_udp
->udp
.uh_sum
),
473 ip6_frame_validate(const void * buf
, u_int buf_len
, bool dump
)
475 char buf_dst
[INET6_ADDRSTRLEN
];
476 char buf_src
[INET6_ADDRSTRLEN
];
477 const struct ip6_hdr
* ip6
;
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
));
487 T_LOG("ip6 src %s dst %s len %u", buf_src
, buf_dst
, ip6_len
);
490 T_ASSERT_GE(buf_len
, ip6_len
+ (u_int
)sizeof(struct ip6_hdr
), NULL
);
492 T_ASSERT_EQ((ip6
->ip6_vfc
& IPV6_VERSION_MASK
),
495 switch (ip6
->ip6_nxt
) {
498 const ip6_udp_header_t
*ip6_udp
;
501 ip6_udp
= (const ip6_udp_header_t
*)buf
;
503 T_ASSERT_GE(buf_len
, (u_int
)sizeof(*ip6_udp
), NULL
);
504 udp_len
= ntohs(ip6_udp
->udp
.uh_ulen
);
506 T_ASSERT_GE(udp_len
, (u_int
)sizeof(ip6_udp
->udp
), NULL
);
507 data_len
= udp_len
- (u_int
)sizeof(ip6_udp
->udp
);
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
),
514 ntohs(ip6_udp
->udp
.uh_sum
),
519 case IPPROTO_ICMPV6
: {
520 const struct icmp6_hdr
*icmp6
;
523 icmp6_len
= buf_len
- sizeof(*ip6
);
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
:
530 T_LOG("neighbor solicit");
533 case ND_NEIGHBOR_ADVERT
:
535 T_LOG("neighbor advert");
538 case ND_ROUTER_SOLICIT
:
540 T_LOG("router solicit");
545 T_LOG("icmp6 code 0x%x", icmp6
->icmp6_type
);
557 ethernet_frame_validate(const void * buf
, u_int buf_len
, bool dump
)
559 char ether_dst
[ETHER_NTOA_BUFSIZE
];
560 char ether_src
[ETHER_NTOA_BUFSIZE
];
562 const ether_header_t
* eh_p
;
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
));
573 T_LOG("ether dst %s src %s type 0x%x",
574 ether_dst
, ether_src
, ether_type
);
576 switch (ether_type
) {
578 ip_frame_validate(eh_p
+ 1, (u_int
)(buf_len
- sizeof(*eh_p
)),
582 arp_frame_validate((const struct ether_arp
*)(eh_p
+ 1),
583 (u_int
)(buf_len
- sizeof(*eh_p
)),
587 ip6_frame_validate(eh_p
+ 1, (u_int
)(buf_len
- sizeof(*eh_p
)),
591 T_FAIL("unrecognized ethertype 0x%x", ether_type
);
597 ethernet_udp4_frame_populate(void * buf
, size_t buf_len
,
598 const ether_addr_t
* src
,
599 struct in_addr src_ip
,
601 const ether_addr_t
* dst
,
602 struct in_addr dst_ip
,
604 const void * data
, u_int data_len
)
606 ether_header_t
* eh_p
;
609 ip_udp_header_t
* ip_udp
;
611 udp_pseudo_hdr_t
* udp_pseudo
;
613 frame_length
= (u_int
)(sizeof(*eh_p
) + sizeof(*ip_udp
)) + data_len
;
614 if (buf_len
< frame_length
) {
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
);
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
);
631 bcopy(data
, payload
, data_len
);
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
);
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
));
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
++);
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
));
667 ethernet_udp6_frame_populate(void * buf
, size_t buf_len
,
668 const ether_addr_t
* src
,
669 struct in6_addr
*src_ip
,
671 const ether_addr_t
* dst
,
672 struct in6_addr
* dst_ip
,
674 const void * data
, u_int data_len
)
676 ether_header_t
* eh_p
;
678 ip6_udp_header_t
* ip6_udp
;
680 udp6_pseudo_hdr_t
* udp6_pseudo
;
682 frame_length
= (u_int
)(sizeof(*eh_p
) + sizeof(*ip6_udp
)) + data_len
;
683 if (buf_len
< frame_length
) {
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
);
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
);
700 bcopy(data
, payload
, data_len
);
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
);
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
));
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 = ? */
729 ethernet_udp_frame_populate(void * buf
, size_t buf_len
,
731 const ether_addr_t
* src
,
732 union ifbrip
* src_ip
,
734 const ether_addr_t
* dst
,
735 union ifbrip
* dst_ip
,
737 const void * data
, u_int data_len
)
743 len
= ethernet_udp4_frame_populate(buf
, buf_len
,
753 len
= ethernet_udp6_frame_populate(buf
, buf_len
,
755 &src_ip
->ifbrip_addr6
,
758 &dst_ip
->ifbrip_addr6
,
763 T_FAIL("unrecognized address family %u", af
);
771 ethernet_arp_frame_populate(void * buf
, u_int buf_len
,
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
)
778 ether_header_t
* eh_p
;
779 struct ether_arp
* earp
;
780 struct arphdr
* arp_p
;
783 frame_length
= sizeof(*earp
) + sizeof(*eh_p
);
785 T_ASSERT_GE(buf_len
, frame_length
,
786 "%s buffer size %u needed %u",
787 __func__
, buf_len
, frame_length
);
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
));
796 bcopy(ðer_broadcast
, eh_p
->ether_dhost
,
797 sizeof(eh_p
->ether_dhost
));
799 eh_p
->ether_type
= htons(ETHERTYPE_ARP
);
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
));
814 bzero(earp
->arp_tha
, sizeof(earp
->arp_tha
));
816 bcopy(&target_ip
, earp
->arp_tpa
, sizeof(earp
->arp_tpa
));
820 static uint32_t G_generation
;
823 next_generation(void)
825 return G_generation
++;
829 ethernet_frame_get_udp4_payload(void * buf
, u_int buf_len
,
830 u_int
* ret_payload_length
)
832 ether_header_t
* eh_p
;
834 ip_udp_header_t
* ip_udp
;
837 const void * payload
= NULL
;
838 u_int payload_length
= 0;
842 T_ASSERT_GE(buf_len
, (u_int
)(sizeof(*eh_p
) + sizeof(*ip_udp
)), NULL
);
844 eh_p
= (ether_header_t
*)buf
;
845 ether_type
= ntohs(eh_p
->ether_type
);
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
);
852 T_ASSERT_GE(left
, ip_len
, NULL
);
854 T_ASSERT_EQ((int)ip_udp
->ip
.ip_v
, IPVERSION
, NULL
);
856 T_ASSERT_EQ((u_int
)ip_udp
->ip
.ip_hl
<< 2, (u_int
)sizeof(struct ip
),
859 T_ASSERT_EQ((int)ip_udp
->ip
.ip_p
, IPPROTO_UDP
, NULL
);
861 T_ASSERT_GE(buf_len
, (u_int
)sizeof(*ip_udp
), NULL
);
862 udp_len
= ntohs(ip_udp
->udp
.uh_ulen
);
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);
869 if (payload
== NULL
) {
872 *ret_payload_length
= payload_length
;
877 ethernet_frame_get_udp6_payload(void * buf
, u_int buf_len
,
878 u_int
* ret_payload_length
)
880 ether_header_t
* eh_p
;
882 ip6_udp_header_t
* ip6_udp
;
885 const void * payload
= NULL
;
886 u_int payload_length
= 0;
890 T_ASSERT_GE(buf_len
, (u_int
)(sizeof(*eh_p
) + sizeof(*ip6_udp
)), NULL
);
892 eh_p
= (ether_header_t
*)buf
;
893 ether_type
= ntohs(eh_p
->ether_type
);
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
);
900 T_ASSERT_GE(left
, ip6_len
+ (u_int
)sizeof(struct ip6_hdr
), NULL
);
902 T_ASSERT_EQ((int)(ip6_udp
->ip6
.ip6_vfc
& IPV6_VERSION_MASK
),
905 T_ASSERT_EQ((int)ip6_udp
->ip6
.ip6_nxt
, IPPROTO_UDP
, NULL
);
907 T_ASSERT_GE(buf_len
, (u_int
)sizeof(*ip6_udp
), NULL
);
908 udp_len
= ntohs(ip6_udp
->udp
.uh_ulen
);
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);
915 if (payload
== NULL
) {
918 *ret_payload_length
= payload_length
;
923 ethernet_frame_get_udp_payload(uint8_t af
, void * buf
, u_int buf_len
,
924 u_int
* ret_payload_length
)
926 const void * payload
;
930 payload
= ethernet_frame_get_udp4_payload(buf
, buf_len
,
934 payload
= ethernet_frame_get_udp6_payload(buf
, buf_len
,
938 T_FAIL("unrecognized address family %u", af
);
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))
959 ethernet_nd6_frame_populate(void * buf
, u_int buf_len
,
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
)
968 ether_header_t
* eh_p
;
970 struct icmp6_hdr
* icmp6
;
971 struct ip6_hdr
* ip6
;
972 struct nd_opt_hdr
* nd_opt
;
975 case ND_ROUTER_SOLICIT
:
976 case ND_NEIGHBOR_ADVERT
:
977 case ND_NEIGHBOR_SOLICIT
:
980 T_FAIL("%s: unsupported type %u", __func__
, type
);
985 T_ASSERT_GE(buf_len
, MIN_ICMP6_LEN
, NULL
);
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
);
992 case ND_NEIGHBOR_SOLICIT
: {
993 struct nd_neighbor_solicit
* nd_ns
;
994 bool sender_is_specified
;
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
;
1001 frame_length
+= data_len
;
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
));
1012 bcopy(target_ip
, &nd_ns
->nd_ns_target
,
1013 sizeof(nd_ns
->nd_ns_target
));
1016 case ND_NEIGHBOR_ADVERT
: {
1017 struct nd_neighbor_advert
* nd_na
;
1019 data_len
= sizeof(*nd_na
) + LINKADDR_OPT_LEN
;
1020 frame_length
+= data_len
;
1022 T_ASSERT_GE(buf_len
, frame_length
, NULL
);
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
));
1034 case ND_ROUTER_SOLICIT
: {
1035 struct nd_router_solicit
* nd_rs
;
1037 data_len
= sizeof(*nd_rs
) + LINKADDR_OPT_LEN
;
1038 frame_length
+= data_len
;
1040 T_ASSERT_GE(buf_len
, frame_length
, NULL
);
1042 nd_rs
= (struct nd_router_solicit
*)(void *)icmp6
;
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
));
1052 T_FAIL("%s: unsupported type %u", __func__
, type
);
1056 icmp6
->icmp6_type
= type
;
1057 icmp6
->icmp6_code
= 0;
1058 icmp6
->icmp6_cksum
= 0;
1059 icmp6
->icmp6_data32
[0] = 0;
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
));
1067 /* XXX ether_dhost should be multicast */
1068 bcopy(ðer_broadcast
, eh_p
->ether_dhost
,
1069 sizeof(eh_p
->ether_dhost
));
1071 eh_p
->ether_type
= htons(ETHERTYPE_IPV6
);
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
);
1082 return frame_length
;
1089 switch_port_check_tx(switch_port_t port
)
1094 struct timespec ts
= { .tv_sec
= 0, .tv_nsec
= 1000 * 1000};
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
);
1102 T_ASSERT_EQ(error
, 1, "kevent");
1104 T_ASSERT_EQ((int)kev
.filter
, EVFILT_WRITE
, NULL
);
1106 T_ASSERT_EQ((int)kev
.ident
, port
->fd
, NULL
);
1108 T_ASSERT_NULL(kev
.udata
, NULL
);
1114 switch_port_send_arp(switch_port_t port
,
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
)
1125 /* make sure we can send */
1126 switch_port_check_tx(port
);
1127 frame_length
= ethernet_arp_frame_populate(&pkt
, sizeof(pkt
),
1134 T_ASSERT_GT(frame_length
, 0, "%s: frame_length %u",
1135 __func__
, frame_length
);
1137 T_LOG("Port %s -> %s transmitting %u bytes",
1138 port
->ifname
, port
->member_ifname
, frame_length
);
1140 ethernet_frame_validate(&pkt
, frame_length
, S_debug
);
1141 n
= write(port
->fd
, &pkt
, frame_length
);
1143 T_ASSERT_POSIX_SUCCESS(n
, "%s write fd %d failed %ld",
1144 port
->ifname
, port
->fd
, n
);
1147 T_ASSERT_EQ((u_int
)n
, frame_length
,
1148 "%s fd %d wrote %ld",
1149 port
->ifname
, port
->fd
, n
);
1154 switch_port_send_nd6(switch_port_t port
,
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
)
1166 /* make sure we can send */
1167 switch_port_check_tx(port
);
1168 frame_length
= ethernet_nd6_frame_populate(&pkt
, sizeof(pkt
),
1176 T_ASSERT_GT(frame_length
, 0, "%s: frame_length %u",
1177 __func__
, frame_length
);
1179 T_LOG("Port %s -> %s transmitting %u bytes",
1180 port
->ifname
, port
->member_ifname
, frame_length
);
1182 ethernet_frame_validate(&pkt
, frame_length
, S_debug
);
1183 n
= write(port
->fd
, &pkt
, frame_length
);
1185 T_ASSERT_POSIX_SUCCESS(n
, "%s write fd %d failed %ld",
1186 port
->ifname
, port
->fd
, n
);
1189 T_ASSERT_EQ((u_int
)n
, frame_length
,
1190 "%s fd %d wrote %ld",
1191 port
->ifname
, port
->fd
, n
);
1196 switch_port_send_udp(switch_port_t port
,
1198 const ether_addr_t
* src_eaddr
,
1199 union ifbrip
* src_ip
,
1201 const ether_addr_t
* dst_eaddr
,
1202 union ifbrip
* dst_ip
,
1204 const void * payload
, u_int payload_length
)
1210 /* make sure we can send */
1211 switch_port_check_tx(port
);
1213 /* generate the packet */
1215 = ethernet_udp_frame_populate((void *)&pkt
,
1227 T_ASSERT_GT(frame_length
, 0, NULL
);
1229 T_LOG("Port %s transmitting %u bytes",
1230 port
->ifname
, frame_length
);
1232 ethernet_frame_validate(&pkt
, frame_length
, S_debug
);
1233 n
= write(port
->fd
, &pkt
, frame_length
);
1235 T_ASSERT_POSIX_SUCCESS(n
, "%s write fd %d failed %ld",
1236 port
->ifname
, port
->fd
, n
);
1239 T_ASSERT_EQ((u_int
)n
, frame_length
,
1240 "%s fd %d wrote %ld",
1241 port
->ifname
, port
->fd
, n
);
1247 switch_port_send_udp_addr_index(switch_port_t port
,
1250 const ether_addr_t
* dst_eaddr
,
1251 union ifbrip
* dst_ip
,
1252 const void * payload
, u_int payload_length
)
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
);
1267 (packet_validator
)(switch_port_t port
, const ether_header_t
* eh_p
,
1268 u_int pkt_len
, void * context
);
1269 typedef packet_validator
* packet_validator_t
;
1272 switch_port_receive(switch_port_t port
,
1274 const void * payload
, u_int payload_length
,
1275 packet_validator_t validator
,
1278 ether_header_t
* eh_p
;
1282 n
= read(port
->fd
, port
->rx_buf
, (unsigned)port
->rx_buf_size
);
1284 if (errno
== EAGAIN
) {
1288 T_ASSERT_POSIX_SUCCESS(n
, "read %s port %d fd %d",
1289 port
->ifname
, port
->unit
, port
->fd
);
1292 for (offset
= port
->rx_buf
; n
> 0;) {
1293 struct bpf_hdr
* bpf
= (struct bpf_hdr
*)(void *)offset
;
1298 pkt
= offset
+ bpf
->bh_hdrlen
;
1299 pkt_len
= bpf
->bh_caplen
;
1301 eh_p
= (ether_header_t
*)(void *)pkt
;
1303 T_ASSERT_GE(pkt_len
, (u_int
)sizeof(*eh_p
),
1304 "short packet %ld", n
);
1306 /* source shouldn't be broadcast/multicast */
1308 T_ASSERT_EQ(eh_p
->ether_shost
[0] & 0x01, 0,
1309 "broadcast/multicast source");
1312 T_LOG("Port %s [unit %d] [fd %d] Received %u bytes",
1313 port
->ifname
, port
->unit
, port
->fd
, pkt_len
);
1315 ethernet_frame_validate(pkt
, pkt_len
, S_debug
);
1317 /* call the validation function */
1318 (*validator
)(port
, eh_p
, pkt_len
, context
);
1320 if (payload
!= NULL
) {
1324 p
= ethernet_frame_get_udp_payload(af
, pkt
, pkt_len
,
1327 T_ASSERT_NOTNULL(p
, "ethernet_frame_get_udp_payload");
1329 T_ASSERT_EQ(p_len
, payload_length
,
1330 "payload length %u < expected %u",
1331 p_len
, payload_length
);
1333 T_ASSERT_EQ(bcmp(payload
, p
, payload_length
), 0,
1334 "unexpected payload");
1336 skip
= BPF_WORDALIGN(pkt_len
+ bpf
->bh_hdrlen
);
1347 switch_port_log(switch_port_t port
)
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
);
1356 #define switch_port_list_size(port_count) \
1357 offsetof(switch_port_list, list[port_count])
1359 static switch_port_list_t
1360 switch_port_list_alloc(u_int port_count
, bool mac_nat
)
1362 switch_port_list_t list
;
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
;
1372 switch_port_list_dealloc(switch_port_list_t list
)
1377 for (i
= 0, port
= list
->list
; i
< list
->count
; i
++, port
++) {
1386 switch_port_list_add_port(switch_port_list_t port_list
, u_int unit
,
1387 const char * ifname
, const char * member_ifname
,
1388 ether_addr_t
* member_mac
,
1389 u_int num_addrs
, bool mac_nat
)
1392 errno_t err
= EINVAL
;
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
);
1410 T_ASSERT_POSIX_SUCCESS(ioctl(fd
, FIONBIO
, &opt
), NULL
);
1412 T_ASSERT_POSIX_SUCCESS(bpf_set_immediate(fd
, 1), NULL
);
1414 T_ASSERT_POSIX_SUCCESS(bpf_setif(fd
, ifname
), "bpf set if %s",
1417 T_ASSERT_POSIX_SUCCESS(bpf_set_see_sent(fd
, 0), NULL
);
1419 T_ASSERT_POSIX_SUCCESS(bpf_set_header_complete(fd
, 1), NULL
);
1421 T_ASSERT_POSIX_SUCCESS(bpf_get_blen(fd
, &buf_size
), NULL
);
1423 T_LOG("%s [unit %d] [member %s] bpf fd %d bufsize %d\n",
1425 member_ifname
, fd
, buf_size
);
1427 p
= port_list
->list
+ port_list
->count
++;
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
;
1446 static switch_port_t
1447 switch_port_list_find_fd(switch_port_list_t ports
, int fd
)
1452 for (i
= 0, port
= ports
->list
; i
< ports
->count
; i
++, port
++) {
1453 if (port
->fd
== fd
) {
1461 switch_port_list_log(switch_port_list_t port_list
)
1466 for (i
= 0, port
= port_list
->list
; i
< port_list
->count
; i
++, port
++) {
1467 switch_port_log(port
);
1472 static switch_port_t
1473 switch_port_list_find_member(switch_port_list_t ports
, const char * member_ifname
)
1478 for (i
= 0, port
= ports
->list
; i
< ports
->count
; i
++, port
++) {
1479 if (strcmp(port
->member_ifname
, member_ifname
) == 0) {
1487 switch_port_list_check_receive(switch_port_list_t ports
, uint8_t af
,
1488 const void * payload
, u_int payload_length
,
1489 packet_validator_t validator
,
1494 struct kevent kev
[ports
->count
];
1497 struct timespec ts
= { .tv_sec
= 0, .tv_nsec
= 10 * 1000 * 1000};
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
);
1510 n_events
= kevent(kq
, kev
, (int)ports
->count
, kev
,
1511 (int)ports
->count
, &ts
);
1513 T_ASSERT_POSIX_SUCCESS(n_events
, "kevent receive %d", n_events
);
1514 for (i
= 0; i
< n_events
; i
++) {
1516 T_ASSERT_EQ((int)kev
[i
].filter
, EVFILT_READ
, NULL
);
1518 T_ASSERT_NULL(kev
[i
].udata
, NULL
);
1519 port
= switch_port_list_find_fd(ports
,
1522 T_ASSERT_NE(port
, NULL
,
1523 "port %p fd %d", (void *)port
,
1525 switch_port_receive(port
, af
, payload
, payload_length
,
1526 validator
, context
);
1528 } while (n_events
!= 0);
1533 switch_port_list_verify_rt_table(switch_port_list_t port_list
, bool log
)
1535 bool all_present
= true;
1538 struct ifbareq
*ifba
;
1539 struct ifbareq
*rt_table
;
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;
1547 rt_table
= bridge_rt_table_copy(&count
);
1548 if (rt_table
== NULL
) {
1552 bridge_rt_table_log(rt_table
, count
);
1554 for (i
= 0, ifba
= rt_table
; i
< count
; i
++, ifba
++) {
1559 ether_addr_t
* eaddr
;
1561 eaddr
= (ether_addr_t
*)&ifba
->ifba_dst
;
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
);
1568 T_ASSERT_NOTNULL(port
, "switch_port_list_find_member %s",
1569 ifba
->ifba_ifsname
);
1570 if (!S_cleaning_up
) {
1572 T_ASSERT_EQ(unit_index
, port
->unit
, NULL
);
1573 addr_bit
= 1 << addr_index
;
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
++;
1582 for (i
= 0, port
= port_list
->list
; i
< port_list
->count
; i
++, port
++) {
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
);
1588 if (port
->test_address_count
!= port
->num_addrs
) {
1589 all_present
= false;
1598 switch_port_list_verify_mac_nat(switch_port_list_t port_list
, bool log
)
1600 bool all_present
= true;
1603 static struct ifbrmne
* entries
;
1605 struct ifbrmne
* scan
;
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;
1613 entries
= bridge_mac_nat_entries_copy(&count
);
1614 if (entries
== NULL
) {
1618 bridge_mac_nat_entries_log(entries
, count
);
1620 for (i
= 0, scan
= entries
; i
< count
; i
++, scan
++) {
1624 char buf_ip1
[INET6_ADDRSTRLEN
];
1625 char buf_ip2
[INET6_ADDRSTRLEN
];
1627 ether_addr_t
* eaddr
;
1631 eaddr
= (ether_addr_t
*)&scan
->ifbmne_mac
;
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
);
1638 T_ASSERT_NOTNULL(port
,
1639 "switch_port_list_find_member %s",
1640 scan
->ifbmne_ifname
);
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
;
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
)),
1652 buf_ip2
, sizeof(buf_ip2
)));
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
++;
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 */
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
);
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
);
1675 if (port
->test_address_count
!= port
->num_addrs
) {
1676 all_present
= false;
1687 ** Basic Bridge Tests
1690 send_generation(switch_port_t port
, uint8_t af
, u_int addr_index
,
1691 const ether_addr_t
* dst_eaddr
, union ifbrip
* dst_ip
,
1692 uint32_t generation
)
1696 payload
= htonl(generation
);
1697 switch_port_send_udp_addr_index(port
, af
, addr_index
, dst_eaddr
, dst_ip
,
1698 &payload
, sizeof(payload
));
1702 check_receive_generation(switch_port_list_t ports
, uint8_t af
,
1703 uint32_t generation
, packet_validator_t validator
,
1704 __unused
void * context
)
1708 payload
= htonl(generation
);
1709 switch_port_list_check_receive(ports
, af
, &payload
, sizeof(payload
),
1710 validator
, context
);
1714 validate_source_ether_mismatch(switch_port_t port
, const ether_header_t
* eh_p
)
1716 /* source shouldn't be our own MAC addresses */
1718 T_ASSERT_NE(eh_p
->ether_shost
[EA_UNIT_INDEX
], port
->unit
,
1719 "ether source matches unit %d", port
->unit
);
1723 validate_not_present_dhost(switch_port_t port
, const ether_header_t
* eh_p
,
1724 __unused u_int pkt_len
,
1725 __unused
void * context
)
1727 validate_source_ether_mismatch(port
, eh_p
);
1729 T_ASSERT_EQ(bcmp(eh_p
->ether_dhost
, ðer_external
,
1730 sizeof(eh_p
->ether_dhost
)), 0,
1736 validate_broadcast_dhost(switch_port_t port
, const ether_header_t
* eh_p
,
1737 __unused u_int pkt_len
,
1738 __unused
void * context
)
1740 validate_source_ether_mismatch(port
, eh_p
);
1742 T_ASSERT_NE((eh_p
->ether_dhost
[0] & 0x01), 0,
1748 validate_port_dhost(switch_port_t port
, const ether_header_t
* eh_p
,
1749 __unused u_int pkt_len
,
1750 __unused
void * context
)
1752 validate_source_ether_mismatch(port
, eh_p
);
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
);
1762 check_received_count(switch_port_list_t port_list
,
1763 switch_port_t port
, uint32_t expected_packets
)
1768 for (i
= 0, scan
= port_list
->list
; i
< port_list
->count
; i
++, scan
++) {
1771 T_ASSERT_EQ(port
->test_count
, 0,
1772 "unexpected receive on port %d",
1774 } else if (expected_packets
== ALL_ADDRS
) {
1776 T_ASSERT_EQ(scan
->test_count
, scan
->num_addrs
,
1777 "didn't receive on all addrs");
1780 T_ASSERT_EQ(scan
->test_count
, expected_packets
,
1781 "wrong receive count on port %s", scan
->member_ifname
);
1787 unicast_send_all(switch_port_list_t port_list
, uint8_t af
, switch_port_t port
)
1792 for (i
= 0, scan
= port_list
->list
; i
< port_list
->count
; i
++, scan
++) {
1794 T_LOG("Unicast send on %s", port
->ifname
);
1796 for (u_int j
= 0; j
< scan
->num_addrs
; j
++) {
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
,
1810 bridge_learning_test_once(switch_port_list_t port_list
,
1812 packet_validator_t validator
,
1814 const ether_addr_t
* dst_eaddr
,
1818 union ifbrip dst_ip
;
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 */
1828 T_LOG("Sending on %s", port
->ifname
);
1830 for (u_int j
= 0; j
< port
->num_addrs
; j
++) {
1831 uint32_t generation
;
1837 if ((port
->test_address_present
& addr_bit
)
1839 /* already present */
1842 T_LOG("Retry port %s unit %u address %u",
1843 port
->ifname
, port
->unit
, j
);
1845 generation
= next_generation();
1846 send_generation(port
,
1853 /* receive across all ports */
1854 check_receive_generation(port_list
,
1860 /* ensure that every port saw the packet */
1861 check_received_count(port_list
, port
, 1);
1867 static inline const char *
1868 af_get_str(uint8_t af
)
1870 return (af
== AF_INET
) ? "IPv4" : "IPv6";
1874 bridge_learning_test(switch_port_list_t port_list
,
1876 packet_validator_t validator
,
1878 const ether_addr_t
* dst_eaddr
)
1880 char ntoabuf
[ETHER_NTOA_BUFSIZE
];
1883 bool verified
= false;
1885 ether_ntoa_buf(dst_eaddr
, ntoabuf
, sizeof(ntoabuf
));
1888 * Send a broadcast frame from every port in the list so that the bridge
1889 * learns our MAC address.
1891 #define BROADCAST_MAX_TRIES 20
1892 for (int try = 1; try < BROADCAST_MAX_TRIES
; try++) {
1893 bool retry
= (try > 1);
1896 T_LOG("%s: %s #ports %u #addrs %u dest %s",
1899 port_list
->count
, port_list
->list
->num_addrs
,
1902 T_LOG("%s: %s #ports %u #addrs %u dest %s (TRY=%d)",
1905 port_list
->count
, port_list
->list
->num_addrs
,
1908 bridge_learning_test_once(port_list
, af
, validator
, context
,
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.
1916 verified
= switch_port_list_verify_rt_table(port_list
, false);
1920 /* wait a short time to allow the system to recover */
1924 T_ASSERT_TRUE(verified
, "All addresses present");
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.
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
);
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
);
1942 T_PASS("%s", __func__
);
1949 mac_nat_check_received_count(switch_port_list_t port_list
, switch_port_t port
)
1954 for (i
= 0, scan
= port_list
->list
; i
< port_list
->count
; i
++, scan
++) {
1958 expected
= scan
->num_addrs
;
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
);
1970 validate_mac_nat(switch_port_t port
, const ether_header_t
* eh_p
,
1971 __unused u_int pkt_len
,
1972 __unused
void * context
)
1974 if (port
->mac_nat
) {
1977 /* source must match MAC-NAT interface */
1978 equal
= (bcmp(eh_p
->ether_shost
, &port
->member_mac
,
1979 sizeof(port
->member_mac
)) == 0);
1981 ethernet_frame_validate(eh_p
, pkt_len
, true);
1984 T_ASSERT_TRUE(equal
, "source address match");
1987 validate_not_present_dhost(port
, eh_p
, pkt_len
, NULL
);
1992 validate_mac_nat_in(switch_port_t port
, const ether_header_t
* eh_p
,
1993 u_int pkt_len
, __unused
void * context
)
1996 T_LOG("%s received %u bytes", port
->member_ifname
, pkt_len
);
1997 ethernet_frame_validate(eh_p
, pkt_len
, true);
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
);
2007 validate_mac_nat_arp_out(switch_port_t port
, const ether_header_t
* eh_p
,
2008 u_int pkt_len
, void * context
)
2010 const struct ether_arp
* earp
;
2011 switch_port_t send_port
= (switch_port_t
)context
;
2014 T_LOG("%s received %u bytes", port
->member_ifname
, pkt_len
);
2015 ethernet_frame_validate(eh_p
, pkt_len
, true);
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);
2021 T_ASSERT_GE(pkt_len
, (u_int
)(sizeof(*eh_p
) + sizeof(*earp
)), NULL
);
2022 if (port
->mac_nat
) {
2025 /* source ethernet must match MAC-NAT interface */
2026 equal
= (bcmp(eh_p
->ether_shost
, &port
->member_mac
,
2027 sizeof(port
->member_mac
)) == 0);
2029 ethernet_frame_validate(eh_p
, pkt_len
, true);
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);
2039 ethernet_frame_validate(eh_p
, pkt_len
, true);
2042 T_ASSERT_TRUE(equal
, "%s -> %s sender hardware translated",
2043 send_port
->member_ifname
,
2044 port
->member_ifname
);
2046 /* source ethernet must match the sender */
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 */
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
);
2065 validate_mac_nat_arp_in(switch_port_t port
, const ether_header_t
* eh_p
,
2066 u_int pkt_len
, void * context
)
2068 const struct ether_arp
* earp
;
2069 switch_port_t send_port
= (switch_port_t
)context
;
2072 T_LOG("%s received %u bytes", port
->member_ifname
, pkt_len
);
2073 ethernet_frame_validate(eh_p
, pkt_len
, true);
2075 earp
= (const struct ether_arp
*)(const void *)(eh_p
+ 1);
2077 T_ASSERT_EQ((int)ntohs(eh_p
->ether_type
), (int)ETHERTYPE_ARP
, NULL
);
2079 T_ASSERT_GE(pkt_len
, (u_int
)(sizeof(*eh_p
) + sizeof(*earp
)), NULL
);
2081 T_ASSERT_FALSE(port
->mac_nat
, NULL
);
2083 /* destination ethernet must match the unit */
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 */
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
);
2101 mac_nat_test_arp_out(switch_port_list_t port_list
)
2104 struct in_addr ip_dst
;
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
) {
2112 for (u_int j
= 0; j
< port
->num_addrs
; j
++) {
2114 struct in_addr ip_src
;
2116 set_ethernet_address(&eaddr
, port
->unit
, j
);
2117 get_ipv4_address(port
->unit
, j
, &ip_src
);
2118 switch_port_send_arp(port
,
2124 switch_port_list_check_receive(port_list
, AF_INET
,
2126 validate_mac_nat_arp_out
,
2128 check_received_count(port_list
, port
, 1);
2131 T_PASS("%s", __func__
);
2135 mac_nat_send_arp_response(switch_port_t ext_port
, switch_port_t port
)
2137 struct in_addr ip_src
;
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
;
2146 get_ipv4_address(port
->unit
, j
, &ip_dst
);
2148 T_LOG("Generating ARP destined to %s %s",
2149 port
->ifname
, inet_ntoa(ip_dst
));
2151 switch_port_send_arp(ext_port
,
2155 &ext_port
->member_mac
,
2161 mac_nat_test_arp_in(switch_port_list_t port_list
)
2164 struct in_addr ip_src
;
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
) {
2172 mac_nat_send_arp_response(port_list
->list
, port
);
2174 /* receive the generated traffic */
2175 switch_port_list_check_receive(port_list
, AF_INET
, NULL
, 0,
2176 validate_mac_nat_arp_in
,
2179 /* verify that only the single port got the packet */
2180 mac_nat_check_received_count(port_list
, port
);
2182 T_PASS("%s", __func__
);
2186 validate_mac_nat_dhcp(switch_port_t port
, const ether_header_t
* eh_p
,
2187 u_int pkt_len
, void * context
)
2190 const struct bootp_packet
* pkt
;
2191 switch_port_t send_port
= (switch_port_t
)context
;
2195 T_ASSERT_GE(pkt_len
, (u_int
)sizeof(*pkt
), NULL
);
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);
2200 dp_flags
= ntohs(pkt
->bp_bootp
.bp_unused
);
2201 if (port
->mac_nat
) {
2204 /* Broadcast bit must be set */
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
);
2212 /* source must match MAC-NAT interface */
2213 equal
= (bcmp(eh_p
->ether_shost
, &port
->member_mac
,
2214 sizeof(port
->member_mac
)) == 0);
2216 ethernet_frame_validate(eh_p
, pkt_len
, true);
2219 T_ASSERT_TRUE(equal
, "%s -> %s source address translated",
2220 send_port
->member_ifname
,
2221 port
->member_ifname
);
2223 /* Broadcast bit must not be set */
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
);
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
);
2241 make_dhcp_payload(dhcp_min_payload_t payload
, ether_addr_t
*eaddr
)
2243 struct bootp
* dhcp
;
2244 u_int payload_length
;
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
;
2258 mac_nat_test_dhcp(switch_port_list_t port_list
, bool link_layer_unicast
)
2261 struct in_addr ip_dst
= { INADDR_BROADCAST
};
2262 struct in_addr ip_src
= { INADDR_ANY
};
2264 ether_addr_t
* ether_dst
;
2266 if (link_layer_unicast
) {
2267 /* use link-layer address of MAC-NAT interface */
2268 ether_dst
= &port_list
->list
[0].member_mac
;
2270 /* use link-layer broadcast address */
2271 ether_dst
= ðer_broadcast
;
2273 for (i
= 0, port
= port_list
->list
; i
< port_list
->count
; i
++, port
++) {
2275 dhcp_min_payload payload
;
2278 if (!link_layer_unicast
&& port
->mac_nat
) {
2279 /* only send through non-MAC-NAT ports */
2282 set_ethernet_address(&eaddr
, port
->unit
, 0);
2283 payload_len
= make_dhcp_payload(&payload
, &eaddr
);
2285 T_LOG("%s: transmit DHCP packet (member %s)",
2286 port
->ifname
, port
->member_ifname
);
2288 switch_port_send_udp(port
,
2291 (union ifbrip
*)&ip_src
,
2294 (union ifbrip
*)&ip_dst
,
2299 switch_port_list_check_receive(port_list
, AF_INET
, NULL
, 0,
2300 validate_mac_nat_dhcp
,
2303 check_received_count(port_list
, port
, 1);
2304 if (link_layer_unicast
) {
2305 /* send a single unicast to MAC-NAT interface */
2309 T_PASS("%s %s", __func__
,
2310 link_layer_unicast
? "unicast" : "broadcast");
2315 validate_mac_nat_nd6(switch_port_t port
,
2316 const struct icmp6_hdr
* icmp6
,
2320 switch_port_t send_port
)
2322 const uint8_t * linkaddr
;
2323 const uint8_t * ptr
;
2324 const struct nd_opt_hdr
* nd_opt
;
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 */
2333 nd_opt
= (const struct nd_opt_hdr
*)(const void *)(ptr
+ nd_hdr_size
);
2335 T_ASSERT_EQ(nd_opt
->nd_opt_type
, opt_type
, NULL
);
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
) {
2342 equal
= (bcmp(linkaddr
, &port
->member_mac
,
2343 sizeof(port
->member_mac
)) == 0);
2345 T_ASSERT_TRUE(equal
, "%s -> %s sender hardware translated",
2346 send_port
->member_ifname
,
2347 port
->member_ifname
);
2349 /* source hw must match the sender */
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
);
2360 validate_mac_nat_icmp6_out(switch_port_t port
, const struct icmp6_hdr
* icmp6
,
2361 u_int icmp6_len
, switch_port_t send_port
)
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
),
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
),
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
),
2383 T_FAIL("Unsupported icmp6 type %d", icmp6
->icmp6_type
);
2389 validate_mac_nat_nd6_out(switch_port_t port
, const ether_header_t
* eh_p
,
2390 u_int pkt_len
, void * context
)
2392 const struct icmp6_hdr
* icmp6
;
2393 const struct ip6_hdr
* ip6
;
2394 switch_port_t send_port
= (switch_port_t
)context
;
2397 T_LOG("%s received %u bytes", port
->member_ifname
, pkt_len
);
2398 ethernet_frame_validate(eh_p
, pkt_len
, true);
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);
2405 T_ASSERT_GE(pkt_len
, (u_int
)MIN_ICMP6_LEN
, NULL
);
2407 T_ASSERT_EQ(ip6
->ip6_nxt
, IPPROTO_ICMPV6
, NULL
);
2409 /* validate the ethernet header */
2410 if (port
->mac_nat
) {
2413 /* source ethernet must match MAC-NAT interface */
2414 equal
= (bcmp(eh_p
->ether_shost
, &port
->member_mac
,
2415 sizeof(port
->member_mac
)) == 0);
2417 ethernet_frame_validate(eh_p
, pkt_len
, true);
2420 T_ASSERT_TRUE(equal
, "%s -> %s source address translated",
2421 send_port
->member_ifname
,
2422 port
->member_ifname
);
2424 /* source ethernet must match the sender */
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
);
2432 /* validate the icmp6 payload */
2433 validate_mac_nat_icmp6_out(port
, icmp6
,
2434 pkt_len
- ETHER_IPV6_LEN
,
2440 mac_nat_test_nd6_out(switch_port_list_t port_list
)
2442 ether_addr_t
* ext_mac
;
2443 switch_port_t ext_port
;
2445 union ifbrip ip_dst
;
2448 get_external_ip_address(AF_INET6
, &ip_dst
);
2449 ext_port
= port_list
->list
;
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
) {
2457 /* neighbor solicit */
2458 for (u_int j
= 0; j
< port
->num_addrs
; j
++) {
2460 union ifbrip ip_src
;
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
,
2467 &ip_src
.ifbrip_addr6
,
2470 &ip_dst
.ifbrip_addr6
);
2471 switch_port_list_check_receive(port_list
, AF_INET
,
2473 validate_mac_nat_nd6_out
,
2475 check_received_count(port_list
, port
, 1);
2477 /* neighbor advert */
2478 for (u_int j
= 0; j
< port
->num_addrs
; j
++) {
2480 union ifbrip ip_src
;
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
,
2487 &ip_src
.ifbrip_addr6
,
2490 &ip_src
.ifbrip_addr6
);
2491 switch_port_list_check_receive(port_list
, AF_INET
,
2493 validate_mac_nat_nd6_out
,
2495 check_received_count(port_list
, port
, 1);
2497 /* router solicit */
2498 for (u_int j
= 0; j
< port
->num_addrs
; j
++) {
2500 union ifbrip ip_src
;
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
,
2508 &ip_src
.ifbrip_addr6
,
2512 switch_port_list_check_receive(port_list
, AF_INET
,
2514 validate_mac_nat_nd6_out
,
2516 check_received_count(port_list
, port
, 1);
2519 T_PASS("%s", __func__
);
2523 mac_nat_send_response(switch_port_t ext_port
, uint8_t af
, switch_port_t port
)
2525 union ifbrip src_ip
;
2528 T_ASSERT_TRUE(ext_port
->mac_nat
, "%s is MAC-NAT interface",
2529 ext_port
->member_ifname
);
2531 T_LOG("Generating UDP traffic destined to %s", port
->ifname
);
2533 get_external_ip_address(af
, &src_ip
);
2534 for (u_int j
= 0; j
< port
->num_addrs
; j
++) {
2537 get_ip_address(af
, port
->unit
, j
, &ip
);
2538 switch_port_send_udp(ext_port
,
2543 &ext_port
->member_mac
,
2552 mac_nat_test_ip_once(switch_port_list_t port_list
, uint8_t af
, bool retry
)
2554 union ifbrip dst_ip
;
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 */
2565 T_LOG("Sending on %s", port
->ifname
);
2567 for (u_int j
= 0; j
< port
->num_addrs
; j
++) {
2568 uint32_t generation
;
2574 if ((port
->test_address_present
& addr_bit
)
2576 /* already present */
2579 T_LOG("Retry port %s unit %u address %u",
2580 port
->ifname
, port
->unit
, j
);
2583 generation
= next_generation();
2584 send_generation(port
,
2591 /* receive across all ports */
2592 check_receive_generation(port_list
,
2598 /* ensure that every port saw the packet */
2599 check_received_count(port_list
, port
, 1);
2606 mac_nat_test_ip(switch_port_list_t port_list
, uint8_t af
)
2610 bool verified
= false;
2613 * Send a packet from every port in the list so that the bridge
2614 * learns the MAC addresses and IP addresses.
2616 #define MAC_NAT_MAX_TRIES 20
2617 for (int try = 1; try < BROADCAST_MAX_TRIES
; try++) {
2618 bool retry
= (try > 1);
2621 T_LOG("%s: #ports %u #addrs %u",
2623 port_list
->count
, port_list
->list
->num_addrs
);
2625 T_LOG("%s: #ports %u #addrs %u destination (TRY=%d)",
2627 port_list
->count
, port_list
->list
->num_addrs
,
2630 mac_nat_test_ip_once(port_list
, af
, retry
);
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.
2637 verified
= switch_port_list_verify_mac_nat(port_list
, false);
2641 /* wait a short time to allow the system to recover */
2645 T_ASSERT_TRUE(verified
, "All addresses present");
2648 * The bridge now has an IP address <-> MAC address binding for every
2649 * address on each internal interface.
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.
2655 for (i
= 0, port
= port_list
->list
; i
< port_list
->count
; i
++, port
++) {
2656 if (port
->mac_nat
) {
2659 mac_nat_send_response(port_list
->list
, af
, port
);
2661 /* receive the generated traffic */
2662 switch_port_list_check_receive(port_list
, AF_INET
, NULL
, 0,
2663 validate_mac_nat_in
,
2666 /* verify that only the single port got the packet */
2667 mac_nat_check_received_count(port_list
, port
);
2669 T_PASS("%s", __func__
);
2673 ** interface management
2677 ifnet_get_lladdr(int s
, const char * ifname
, ether_addr_t
* eaddr
)
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
);
2688 T_ASSERT_POSIX_SUCCESS(err
, "SIOCGIFLLADDR %s", ifname
);
2689 bcopy(ifr
.ifr_addr
.sa_data
, eaddr
->octet
, ETHER_ADDR_LEN
);
2695 ifnet_attach_ip(int s
, char * name
)
2700 bzero(&ifr
, sizeof(ifr
));
2701 strncpy(ifr
.ifr_name
, name
, sizeof(ifr
.ifr_name
));
2702 err
= ioctl(s
, SIOCPROTOATTACH
, &ifr
);
2704 T_ASSERT_POSIX_SUCCESS(err
, "SIOCPROTOATTACH %s", ifr
.ifr_name
);
2710 ifnet_detach_ip(int s
, char * name
)
2715 bzero(&ifr
, sizeof(ifr
));
2716 strncpy(ifr
.ifr_name
, name
, sizeof(ifr
.ifr_name
));
2717 err
= ioctl(s
, SIOCPROTODETACH
, &ifr
);
2719 T_ASSERT_POSIX_SUCCESS(err
, "SIOCPROTODETACH %s", ifr
.ifr_name
);
2725 ifnet_destroy(int s
, const char * ifname
, bool fail_on_error
)
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
) {
2735 T_ASSERT_POSIX_SUCCESS(err
, "SIOCSIFDESTROY %s", ifr
.ifr_name
);
2738 T_LOG("SIOCSIFDESTROY %s", ifr
.ifr_name
);
2744 ifnet_set_flags(int s
, const char * ifname
,
2745 uint16_t flags_set
, uint16_t flags_clear
)
2747 uint16_t flags_after
;
2748 uint16_t flags_before
;
2752 bzero(&ifr
, sizeof(ifr
));
2753 strncpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
2754 ret
= ioctl(s
, SIOCGIFFLAGS
, (caddr_t
)&ifr
);
2756 T_LOG("SIOCGIFFLAGS %s", ifr
.ifr_name
);
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
) {
2767 /* issue the ioctl */
2769 T_ASSERT_POSIX_SUCCESS(ioctl(s
, SIOCSIFFLAGS
, &ifr
),
2770 "SIOCSIFFLAGS %s 0x%x",
2771 ifr
.ifr_name
, (uint16_t)ifr
.ifr_flags
);
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
);
2781 #define BRIDGE_NAME "bridge"
2782 #define BRIDGE200 BRIDGE_NAME "200"
2784 #define FETH_NAME "feth"
2786 /* On some platforms with DEBUG kernel, we need to wait a while */
2787 #define SIFCREATE_RETRY 600
2790 ifnet_create(int s
, const char * ifname
)
2795 bzero(&ifr
, sizeof(ifr
));
2796 strlcpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
2798 for (int i
= 0; i
< SIFCREATE_RETRY
; i
++) {
2799 if (ioctl(s
, SIOCIFCREATE
, &ifr
) < 0) {
2801 T_LOG("SIOCSIFCREATE %s: %s", ifname
,
2803 if (error
== EBUSY
) {
2804 /* interface is tearing down, try again */
2806 } else if (error
== EEXIST
) {
2807 /* interface exists, try destroying it */
2808 (void)ifnet_destroy(s
, ifname
, false);
2810 /* unexpected failure */
2819 error
= ifnet_set_flags(s
, ifname
, IFF_UP
, 0);
2825 siocdrvspec(int s
, const char * ifname
,
2826 u_long op
, void *arg
, size_t argsize
, bool set
)
2830 memset(&ifd
, 0, sizeof(ifd
));
2831 strlcpy(ifd
.ifd_name
, ifname
, sizeof(ifd
.ifd_name
));
2833 ifd
.ifd_len
= argsize
;
2835 return ioctl(s
, set
? SIOCSDRVSPEC
: SIOCGDRVSPEC
, &ifd
);
2840 fake_set_peer(int s
, const char * feth
, const char * feth_peer
)
2842 struct if_fake_request iffr
;
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
));
2850 ret
= siocdrvspec(s
, feth
, IF_FAKE_S_CMD_SET_PEER
,
2851 &iffr
, sizeof(iffr
), true);
2853 T_ASSERT_POSIX_SUCCESS(ret
,
2854 "SIOCDRVSPEC(%s, IF_FAKE_S_CMD_SET_PEER, %s)",
2855 feth
, (feth_peer
!= NULL
) ? feth_peer
: "<none>");
2860 bridge_add_member(int s
, const char * bridge
, const char * member
)
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);
2869 T_ASSERT_POSIX_SUCCESS(ret
, "%s %s %s", __func__
, bridge
, member
);
2875 bridge_set_mac_nat(int s
, const char * bridge
, const char * member
, bool enable
)
2878 bool need_set
= false;
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);
2886 T_ASSERT_POSIX_SUCCESS(ret
, "BRDGGIFFLGS %s %s", bridge
, member
);
2887 flags
= req
.ifbr_ifsflags
;
2889 if ((flags
& IFBIF_MAC_NAT
) == 0) {
2891 req
.ifbr_ifsflags
|= IFBIF_MAC_NAT
;
2893 /* need to set it */
2894 } else if ((flags
& IFBIF_MAC_NAT
) != 0) {
2895 /* need to clear it */
2897 req
.ifbr_ifsflags
&= ~(uint32_t)IFBIF_MAC_NAT
;
2900 ret
= siocdrvspec(s
, bridge
, BRDGSIFFLGS
,
2901 &req
, sizeof(req
), true);
2903 T_ASSERT_POSIX_SUCCESS(ret
, "BRDGSIFFLGS %s %s 0x%x => 0x%x",
2905 flags
, req
.ifbr_ifsflags
);
2910 static struct ifbareq
*
2911 bridge_rt_table_copy_common(const char * bridge
, u_int
* ret_count
)
2913 struct ifbaconf ifbac
;
2914 u_int len
= 8 * 1024;
2915 char * inbuf
= NULL
;
2918 struct ifbareq
* rt_table
= NULL
;
2921 s
= inet_dgram_socket();
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
2930 ninbuf
= realloc(inbuf
, len
);
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);
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 */
2945 if (ifbac
.ifbac_len
== 0) {
2947 T_LOG("No bridge routing entries");
2950 *ret_count
= ifbac
.ifbac_len
/ sizeof(*rt_table
);
2951 rt_table
= (struct ifbareq
*)(void *)ninbuf
;
2953 if (rt_table
== NULL
) {
2962 static struct ifbareq
*
2963 bridge_rt_table_copy(u_int
* ret_count
)
2965 return bridge_rt_table_copy_common(BRIDGE200
, ret_count
);
2969 bridge_rt_table_log(struct ifbareq
*rt_table
, u_int count
)
2972 char ntoabuf
[ETHER_NTOA_BUFSIZE
];
2973 struct ifbareq
* ifba
;
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
,
2984 static struct ifbrmne
*
2985 bridge_mac_nat_entries_copy_common(const char * bridge
, u_int
* ret_count
)
2991 struct ifbrmnelist mnl
;
2992 struct ifbrmne
* ret_list
= NULL
;
2997 s
= inet_dgram_socket();
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
);
3007 T_ASSERT_POSIX_SUCCESS(err
, "BRDGGMACNATLIST %s", bridge
);
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) {
3016 /* call again with a buffer large enough to hold them */
3017 buf
= malloc(mnl
.ifbml_len
);
3019 T_ASSERT_NOTNULL(buf
, "mac nat entries buffer");
3020 mnl
.ifbml_buf
= buf
;
3021 err
= siocdrvspec(s
, bridge
, BRDGGMACNATLIST
, &mnl
, sizeof(mnl
), false);
3023 T_ASSERT_POSIX_SUCCESS(err
, "BRDGGMACNATLIST %s", bridge
);
3024 count
= mnl
.ifbml_len
/ mnl
.ifbml_elsize
;
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
;
3034 /* element size is larger than we expect, create a "right-sized" array */
3035 ret_list
= malloc(count
* sizeof(*ret_list
));
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
;
3041 ifbmne
= (struct ifbrmne
*)(void *)scan
;
3042 ret_list
[i
] = *ifbmne
;
3055 static struct ifbrmne
*
3056 bridge_mac_nat_entries_copy(u_int
* ret_count
)
3058 return bridge_mac_nat_entries_copy_common(BRIDGE200
, ret_count
);
3062 bridge_mac_nat_entries_log(struct ifbrmne
* entries
, u_int count
)
3065 char ntoabuf
[ETHER_NTOA_BUFSIZE
];
3066 char ntopbuf
[INET6_ADDRSTRLEN
];
3067 struct ifbrmne
* scan
;
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
);
3084 static u_int S_n_ports
;
3085 static switch_port_list_t S_port_list
;
3088 bridge_cleanup(const char * bridge
, u_int n_ports
, bool fail_on_error
);
3091 cleanup_common(bool dump_table
)
3093 if (S_n_ports
== 0) {
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);
3103 (void)switch_port_list_verify_rt_table(S_port_list
, true);
3106 T_LOG("sleeping for 5 seconds\n");
3109 bridge_cleanup(BRIDGE200
, S_n_ports
, false);
3116 cleanup_common(true);
3121 sigint_handler(__unused
int sig
)
3123 cleanup_common(false);
3124 signal(SIGINT
, SIG_DFL
);
3127 static switch_port_list_t
3128 bridge_setup(char * bridge
, u_int n_ports
, u_int num_addrs
, bool mac_nat
)
3131 switch_port_list_t list
= NULL
;
3134 S_n_ports
= n_ports
;
3137 s
= inet_dgram_socket();
3138 err
= ifnet_create(s
, bridge
);
3142 list
= switch_port_list_alloc(n_ports
, mac_nat
);
3143 for (u_int i
= 0; i
< n_ports
; i
++) {
3145 char ifname
[IFNAMSIZ
];
3146 char member_ifname
[IFNAMSIZ
];
3147 ether_addr_t member_mac
;
3149 snprintf(ifname
, sizeof(ifname
), "%s%d",
3151 snprintf(member_ifname
, sizeof(member_ifname
), "%s%d",
3152 FETH_NAME
, i
+ n_ports
);
3153 err
= ifnet_create(s
, ifname
);
3157 ifnet_attach_ip(s
, ifname
);
3158 err
= ifnet_create(s
, member_ifname
);
3162 err
= ifnet_get_lladdr(s
, member_ifname
, &member_mac
);
3166 err
= fake_set_peer(s
, ifname
, member_ifname
);
3170 /* add the interface's peer to the bridge */
3171 err
= bridge_add_member(s
, bridge
, member_ifname
);
3176 do_mac_nat
= (i
== 0 && mac_nat
);
3178 /* enable MAC NAT on unit 0 */
3179 err
= bridge_set_mac_nat(s
, bridge
, member_ifname
,
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
,
3197 if (err
!= 0 && list
!= NULL
) {
3198 switch_port_list_dealloc(list
);
3206 bridge_cleanup(const char * bridge
, u_int n_ports
, bool fail_on_error
)
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
];
3216 snprintf(ifname
, sizeof(ifname
), "%s%d",
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
);
3231 * Basic Bridge Tests
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
3242 * - verify ARP translation
3243 * - verify IPv4 translation
3244 * - verify DHCP broadcast bit conversion
3245 * - verify IPv6 translation
3246 * - verify ND6 translation (Neighbor, Router)
3247 * - verify IPv4 subnet-local broadcast to MAC-NAT interface link-layer
3248 * address arrives on all member links
3252 bridge_test(packet_validator_t validator
,
3254 const ether_addr_t
* dst_eaddr
,
3255 uint8_t af
, u_int n_ports
, u_int num_addrs
)
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
;
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");
3268 S_port_list
= port_list
;
3269 bridge_learning_test(port_list
, af
, validator
, context
, dst_eaddr
);
3271 //T_LOG("Sleeping for 5 seconds");
3273 bridge_cleanup(BRIDGE200
, n_ports
, true);
3274 switch_port_list_dealloc(port_list
);
3276 #endif /* TARGET_OS_BRIDGE */
3280 bridge_test_mac_nat_ipv4(u_int n_ports
, u_int num_addrs
)
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
;
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");
3293 S_port_list
= port_list
;
3295 /* verify that IPv4 packets get translated when necessary */
3296 mac_nat_test_ip(port_list
, AF_INET
);
3298 /* verify the DHCP broadcast bit gets set appropriately */
3299 mac_nat_test_dhcp(port_list
, false);
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
);
3305 /* verify IP broadcast to MAC-NAT interface link layer address */
3306 mac_nat_test_dhcp(port_list
, true);
3309 T_LOG("Sleeping for 5 seconds");
3312 bridge_cleanup(BRIDGE200
, n_ports
, true);
3313 switch_port_list_dealloc(port_list
);
3315 #endif /* TARGET_OS_BRIDGE */
3319 bridge_test_mac_nat_ipv6(u_int n_ports
, u_int num_addrs
)
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
;
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");
3332 S_port_list
= port_list
;
3334 /* verify that IPv6 packets get translated when necessary */
3335 mac_nat_test_ip(port_list
, AF_INET6
);
3337 /* verify that ND6 packet gets translated when necessary */
3338 mac_nat_test_nd6_out(port_list
);
3340 T_LOG("Sleeping for 5 seconds");
3343 bridge_cleanup(BRIDGE200
, n_ports
, true);
3344 switch_port_list_dealloc(port_list
);
3346 #endif /* TARGET_OS_BRIDGE */
3350 system_cmd(const char *cmd
, bool fail_on_error
)
3353 int exit_status
= 0;
3354 const char *argv
[] = {
3355 "/usr/local/bin/bash",
3361 int rc
= dt_launch_tool(&pid
, (char **)(void *)argv
, false, NULL
, NULL
);
3363 T_ASSERT_EQ(rc
, 0, "dt_launch_tool(%s) failed", cmd
);
3365 if (dt_waitpid(pid
, &exit_status
, NULL
, 30)) {
3367 T_ASSERT_MACH_SUCCESS(exit_status
, "command(%s)", cmd
);
3369 if (fail_on_error
) {
3370 T_FAIL("dt_waitpid(%s) failed", cmd
);
3378 struct ifbrparam param
;
3379 int s
= inet_dgram_socket();
3381 system_cmd("pfctl -d", false);
3382 system_cmd("pfctl -F all", false);
3384 param
.ifbrp_filter
= 0;
3385 siocdrvspec(s
, BRIDGE200
, BRDGSFILT
,
3386 ¶m
, sizeof(param
), true);
3391 block_all_traffic(bool input
, const char* infname1
, const char* infname2
)
3393 int s
= inet_dgram_socket();
3395 struct ifbrparam param
;
3397 char *dir
= input
? "in" : "out";
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 ¶m
, 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);
3415 * Basic bridge filter test
3417 * For both broadcast and unicast transfers ensure that data can
3418 * be blocked using pf on the bridge
3422 filter_test(uint8_t af
)
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
;
3429 const u_int n_ports
= 2;
3430 u_int num_addrs
= 1;
3432 char ntoabuf
[ETHER_NTOA_BUFSIZE
];
3433 union ifbrip dst_ip
;
3434 bool blocked
= true;
3436 const char* ifnames
[2];
3438 signal(SIGINT
, sigint_handler
);
3441 T_ATEND(cleanup_pf
);
3443 port_list
= bridge_setup(BRIDGE200
, n_ports
, num_addrs
, false);
3444 if (port_list
== NULL
) {
3445 T_FAIL("bridge_setup");
3449 ether_ntoa_buf(ðer_broadcast
, ntoabuf
, sizeof(ntoabuf
));
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
;
3456 get_broadcast_ip_address(af
, &dst_ip
);
3460 block_all_traffic(input
, ifnames
[0], ifnames
[1]);
3462 for (i
= 0, port
= port_list
->list
; i
< port_list
->count
; i
++, port
++) {
3464 T_LOG("Sending on %s", port
->ifname
);
3466 for (u_int j
= 0; j
< port
->num_addrs
; j
++) {
3467 uint32_t generation
;
3469 generation
= next_generation();
3470 send_generation(port
,
3477 /* receive across all ports */
3478 check_receive_generation(port_list
,
3481 validate_broadcast_dhost
,
3484 /* ensure that every port saw the right amount of packets*/
3486 check_received_count(port_list
, port
, 0);
3488 check_received_count(port_list
, port
, 1);
3492 T_PASS("%s broadcast %s %s", __func__
, blocked
? "blocked" : "not blocked", input
? "input" : "output");
3495 } while (input
== false && blocked
);
3497 } while (blocked
== false);
3502 block_all_traffic(input
, ifnames
[0], ifnames
[1]);
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
);
3508 /* receive all of that generated traffic */
3509 switch_port_list_check_receive(port_list
, af
, NULL
, 0,
3510 validate_port_dhost
, NULL
);
3512 /* ensure that every port saw the right amount of packets*/
3514 check_received_count(port_list
, port
, 0);
3516 check_received_count(port_list
, port
, 1);
3519 T_PASS("%s unicast %s %s", __func__
, blocked
? "blocked" : "not blocked", input
? "input" : "output");
3522 } while (input
== false && blocked
);
3524 } while (blocked
== false);
3526 bridge_cleanup(BRIDGE200
, n_ports
, true);
3527 switch_port_list_dealloc(port_list
);
3529 #endif /* TARGET_OS_BRIDGE */
3532 T_DECL(if_bridge_bcast
,
3533 "bridge broadcast IPv4",
3534 T_META_ASROOT(true))
3536 bridge_test(validate_broadcast_dhost
, NULL
, ðer_broadcast
,
3540 T_DECL(if_bridge_bcast_many
,
3541 "bridge broadcast many IPv4",
3542 T_META_ASROOT(true))
3544 bridge_test(validate_broadcast_dhost
, NULL
, ðer_broadcast
,
3548 T_DECL(if_bridge_unknown
,
3549 "bridge unknown host IPv4",
3550 T_META_ASROOT(true))
3552 bridge_test(validate_not_present_dhost
, NULL
, ðer_external
,
3556 T_DECL(if_bridge_bcast_v6
,
3557 "bridge broadcast IPv6",
3558 T_META_ASROOT(true))
3560 bridge_test(validate_broadcast_dhost
, NULL
, ðer_broadcast
,
3564 T_DECL(if_bridge_bcast_many_v6
,
3565 "bridge broadcast many IPv6",
3566 T_META_ASROOT(true))
3568 bridge_test(validate_broadcast_dhost
, NULL
, ðer_broadcast
,
3572 T_DECL(if_bridge_unknown_v6
,
3573 "bridge unknown host IPv6",
3574 T_META_ASROOT(true))
3576 bridge_test(validate_not_present_dhost
, NULL
, ðer_external
,
3580 T_DECL(if_bridge_mac_nat_ipv4
,
3581 "bridge mac nat ipv4",
3582 T_META_ASROOT(true))
3584 bridge_test_mac_nat_ipv4(5, 10);
3587 T_DECL(if_bridge_mac_nat_ipv6
,
3588 "bridge mac nat ipv6",
3589 T_META_ASROOT(true))
3591 bridge_test_mac_nat_ipv6(5, 10);
3594 T_DECL(if_bridge_filter_ipv4
,
3595 "bridge filter ipv4",
3596 T_META_ASROOT(true))
3598 filter_test(AF_INET
);
3601 T_DECL(if_bridge_filter_ipv6
,
3602 "bridge filter ipv6",
3603 T_META_ASROOT(true))
3605 filter_test(AF_INET6
);