2 * Copyright (c) 2019 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
)
2261 struct in_addr ip_dst
= { INADDR_BROADCAST
};
2262 struct in_addr ip_src
= { INADDR_ANY
};
2265 for (i
= 0, port
= port_list
->list
; i
< port_list
->count
; i
++, port
++) {
2267 dhcp_min_payload payload
;
2270 if (port
->mac_nat
) {
2273 set_ethernet_address(&eaddr
, port
->unit
, 0);
2274 payload_len
= make_dhcp_payload(&payload
, &eaddr
);
2276 T_LOG("%s: transmit DHCP packet (member %s)",
2277 port
->ifname
, port
->member_ifname
);
2279 switch_port_send_udp(port
,
2282 (union ifbrip
*)&ip_src
,
2285 (union ifbrip
*)&ip_dst
,
2290 switch_port_list_check_receive(port_list
, AF_INET
, NULL
, 0,
2291 validate_mac_nat_dhcp
,
2294 check_received_count(port_list
, port
, 1);
2296 T_PASS("%s", __func__
);
2301 validate_mac_nat_nd6(switch_port_t port
,
2302 const struct icmp6_hdr
* icmp6
,
2306 switch_port_t send_port
)
2308 const uint8_t * linkaddr
;
2309 const uint8_t * ptr
;
2310 const struct nd_opt_hdr
* nd_opt
;
2313 ptr
= (const uint8_t *)icmp6
;
2314 nd_size
= nd_hdr_size
+ LINKADDR_OPT_LEN
;
2315 if (icmp6_len
< nd_size
) {
2316 /* no LINKADDR option */
2319 nd_opt
= (const struct nd_opt_hdr
*)(const void *)(ptr
+ nd_hdr_size
);
2321 T_ASSERT_EQ(nd_opt
->nd_opt_type
, opt_type
, NULL
);
2323 T_ASSERT_EQ(GET_ND_OPT_LEN(nd_opt
->nd_opt_len
), LINKADDR_OPT_LEN
, NULL
);
2324 linkaddr
= (const uint8_t *)(nd_opt
+ 1);
2325 if (port
->mac_nat
) {
2328 equal
= (bcmp(linkaddr
, &port
->member_mac
,
2329 sizeof(port
->member_mac
)) == 0);
2331 T_ASSERT_TRUE(equal
, "%s -> %s sender hardware translated",
2332 send_port
->member_ifname
,
2333 port
->member_ifname
);
2335 /* source hw must match the sender */
2337 T_ASSERT_EQ(linkaddr
[EA_UNIT_INDEX
], send_port
->unit
,
2338 "%s -> %s unit %u expected %u",
2339 send_port
->member_ifname
,
2340 port
->member_ifname
,
2341 linkaddr
[EA_UNIT_INDEX
], send_port
->unit
);
2346 validate_mac_nat_icmp6_out(switch_port_t port
, const struct icmp6_hdr
* icmp6
,
2347 u_int icmp6_len
, switch_port_t send_port
)
2349 switch (icmp6
->icmp6_type
) {
2350 case ND_NEIGHBOR_ADVERT
:
2351 validate_mac_nat_nd6(port
, icmp6
, icmp6_len
,
2352 ND_OPT_TARGET_LINKADDR
,
2353 sizeof(struct nd_neighbor_advert
),
2356 case ND_NEIGHBOR_SOLICIT
:
2357 validate_mac_nat_nd6(port
, icmp6
, icmp6_len
,
2358 ND_OPT_SOURCE_LINKADDR
,
2359 sizeof(struct nd_neighbor_solicit
),
2362 case ND_ROUTER_SOLICIT
:
2363 validate_mac_nat_nd6(port
, icmp6
, icmp6_len
,
2364 ND_OPT_SOURCE_LINKADDR
,
2365 sizeof(struct nd_router_solicit
),
2369 T_FAIL("Unsupported icmp6 type %d", icmp6
->icmp6_type
);
2375 validate_mac_nat_nd6_out(switch_port_t port
, const ether_header_t
* eh_p
,
2376 u_int pkt_len
, void * context
)
2378 const struct icmp6_hdr
* icmp6
;
2379 const struct ip6_hdr
* ip6
;
2380 switch_port_t send_port
= (switch_port_t
)context
;
2383 T_LOG("%s received %u bytes", port
->member_ifname
, pkt_len
);
2384 ethernet_frame_validate(eh_p
, pkt_len
, true);
2387 T_ASSERT_EQ(ntohs(eh_p
->ether_type
), (u_short
)ETHERTYPE_IPV6
, NULL
);
2388 ip6
= (const struct ip6_hdr
*)(const void *)(eh_p
+ 1);
2389 icmp6
= (const struct icmp6_hdr
*)(const void *)(ip6
+ 1);
2391 T_ASSERT_GE(pkt_len
, (u_int
)MIN_ICMP6_LEN
, NULL
);
2393 T_ASSERT_EQ(ip6
->ip6_nxt
, IPPROTO_ICMPV6
, NULL
);
2395 /* validate the ethernet header */
2396 if (port
->mac_nat
) {
2399 /* source ethernet must match MAC-NAT interface */
2400 equal
= (bcmp(eh_p
->ether_shost
, &port
->member_mac
,
2401 sizeof(port
->member_mac
)) == 0);
2403 ethernet_frame_validate(eh_p
, pkt_len
, true);
2406 T_ASSERT_TRUE(equal
, "%s -> %s source address translated",
2407 send_port
->member_ifname
,
2408 port
->member_ifname
);
2410 /* source ethernet must match the sender */
2412 T_ASSERT_EQ(eh_p
->ether_shost
[EA_UNIT_INDEX
], send_port
->unit
,
2413 "%s -> %s unit %u expected %u",
2414 send_port
->member_ifname
,
2415 port
->member_ifname
,
2416 eh_p
->ether_shost
[EA_UNIT_INDEX
], send_port
->unit
);
2418 /* validate the icmp6 payload */
2419 validate_mac_nat_icmp6_out(port
, icmp6
,
2420 pkt_len
- ETHER_IPV6_LEN
,
2426 mac_nat_test_nd6_out(switch_port_list_t port_list
)
2428 ether_addr_t
* ext_mac
;
2429 switch_port_t ext_port
;
2431 union ifbrip ip_dst
;
2434 get_external_ip_address(AF_INET6
, &ip_dst
);
2435 ext_port
= port_list
->list
;
2437 T_ASSERT_TRUE(ext_port
->mac_nat
, NULL
);
2438 ext_mac
= &ext_port
->member_mac
;
2439 for (i
= 0, port
= port_list
->list
; i
< port_list
->count
; i
++, port
++) {
2440 if (port
->mac_nat
) {
2443 /* neighbor solicit */
2444 for (u_int j
= 0; j
< port
->num_addrs
; j
++) {
2446 union ifbrip ip_src
;
2448 set_ethernet_address(&eaddr
, port
->unit
, j
);
2449 get_ip_address(AF_INET6
, port
->unit
, j
, &ip_src
);
2450 switch_port_send_nd6(port
,
2451 ND_NEIGHBOR_SOLICIT
,
2453 &ip_src
.ifbrip_addr6
,
2456 &ip_dst
.ifbrip_addr6
);
2457 switch_port_list_check_receive(port_list
, AF_INET
,
2459 validate_mac_nat_nd6_out
,
2461 check_received_count(port_list
, port
, 1);
2463 /* neighbor advert */
2464 for (u_int j
= 0; j
< port
->num_addrs
; j
++) {
2466 union ifbrip ip_src
;
2468 set_ethernet_address(&eaddr
, port
->unit
, j
);
2469 get_ip_address(AF_INET6
, port
->unit
, j
, &ip_src
);
2470 switch_port_send_nd6(port
,
2473 &ip_src
.ifbrip_addr6
,
2476 &ip_src
.ifbrip_addr6
);
2477 switch_port_list_check_receive(port_list
, AF_INET
,
2479 validate_mac_nat_nd6_out
,
2481 check_received_count(port_list
, port
, 1);
2483 /* router solicit */
2484 for (u_int j
= 0; j
< port
->num_addrs
; j
++) {
2486 union ifbrip ip_src
;
2488 set_ethernet_address(&eaddr
, port
->unit
, j
);
2489 get_ip_address(AF_INET6
, port
->unit
, j
, &ip_src
);
2490 //get_ipv6ll_address(port->unit, j, &ip_src.ifbrip_addr6);
2491 switch_port_send_nd6(port
,
2494 &ip_src
.ifbrip_addr6
,
2498 switch_port_list_check_receive(port_list
, AF_INET
,
2500 validate_mac_nat_nd6_out
,
2502 check_received_count(port_list
, port
, 1);
2505 T_PASS("%s", __func__
);
2509 mac_nat_send_response(switch_port_t ext_port
, uint8_t af
, switch_port_t port
)
2511 union ifbrip src_ip
;
2514 T_ASSERT_TRUE(ext_port
->mac_nat
, "%s is MAC-NAT interface",
2515 ext_port
->member_ifname
);
2517 T_LOG("Generating UDP traffic destined to %s", port
->ifname
);
2519 get_external_ip_address(af
, &src_ip
);
2520 for (u_int j
= 0; j
< port
->num_addrs
; j
++) {
2523 get_ip_address(af
, port
->unit
, j
, &ip
);
2524 switch_port_send_udp(ext_port
,
2529 &ext_port
->member_mac
,
2538 mac_nat_test_ip_once(switch_port_list_t port_list
, uint8_t af
, bool retry
)
2540 union ifbrip dst_ip
;
2544 get_external_ip_address(af
, &dst_ip
);
2545 for (i
= 0, port
= port_list
->list
; i
< port_list
->count
; i
++, port
++) {
2546 if (port
->test_address_count
== port
->num_addrs
) {
2547 /* already populated */
2551 T_LOG("Sending on %s", port
->ifname
);
2553 for (u_int j
= 0; j
< port
->num_addrs
; j
++) {
2554 uint32_t generation
;
2560 if ((port
->test_address_present
& addr_bit
)
2562 /* already present */
2565 T_LOG("Retry port %s unit %u address %u",
2566 port
->ifname
, port
->unit
, j
);
2569 generation
= next_generation();
2570 send_generation(port
,
2577 /* receive across all ports */
2578 check_receive_generation(port_list
,
2584 /* ensure that every port saw the packet */
2585 check_received_count(port_list
, port
, 1);
2592 mac_nat_test_ip(switch_port_list_t port_list
, uint8_t af
)
2596 bool verified
= false;
2599 * Send a packet from every port in the list so that the bridge
2600 * learns the MAC addresses and IP addresses.
2602 #define MAC_NAT_MAX_TRIES 20
2603 for (int try = 1; try < BROADCAST_MAX_TRIES
; try++) {
2604 bool retry
= (try > 1);
2607 T_LOG("%s: #ports %u #addrs %u",
2609 port_list
->count
, port_list
->list
->num_addrs
);
2611 T_LOG("%s: #ports %u #addrs %u destination (TRY=%d)",
2613 port_list
->count
, port_list
->list
->num_addrs
,
2616 mac_nat_test_ip_once(port_list
, af
, retry
);
2618 * In the event of a memory allocation failure, it's possible
2619 * that the address was not learned. Figure out whether
2620 * all addresses are present, and if not, we'll retry on
2621 * those that are not present.
2623 verified
= switch_port_list_verify_mac_nat(port_list
, false);
2627 /* wait a short time to allow the system to recover */
2631 T_ASSERT_TRUE(verified
, "All addresses present");
2634 * The bridge now has an IP address <-> MAC address binding for every
2635 * address on each internal interface.
2637 * Generate an inbound packet on the MAC-NAT interface targeting
2638 * each interface address. Verify that the packet appears on
2639 * the appropriate internal address with appropriate translation.
2641 for (i
= 0, port
= port_list
->list
; i
< port_list
->count
; i
++, port
++) {
2642 if (port
->mac_nat
) {
2645 mac_nat_send_response(port_list
->list
, af
, port
);
2647 /* receive the generated traffic */
2648 switch_port_list_check_receive(port_list
, AF_INET
, NULL
, 0,
2649 validate_mac_nat_in
,
2652 /* verify that only the single port got the packet */
2653 mac_nat_check_received_count(port_list
, port
);
2655 T_PASS("%s", __func__
);
2659 ** interface management
2663 ifnet_get_lladdr(int s
, const char * ifname
, ether_addr_t
* eaddr
)
2668 bzero(&ifr
, sizeof(ifr
));
2669 strlcpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
2670 ifr
.ifr_addr
.sa_family
= AF_LINK
;
2671 ifr
.ifr_addr
.sa_len
= ETHER_ADDR_LEN
;
2672 err
= ioctl(s
, SIOCGIFLLADDR
, &ifr
);
2674 T_ASSERT_POSIX_SUCCESS(err
, "SIOCGIFLLADDR %s", ifname
);
2675 bcopy(ifr
.ifr_addr
.sa_data
, eaddr
->octet
, ETHER_ADDR_LEN
);
2681 ifnet_attach_ip(int s
, char * name
)
2686 bzero(&ifr
, sizeof(ifr
));
2687 strncpy(ifr
.ifr_name
, name
, sizeof(ifr
.ifr_name
));
2688 err
= ioctl(s
, SIOCPROTOATTACH
, &ifr
);
2690 T_ASSERT_POSIX_SUCCESS(err
, "SIOCPROTOATTACH %s", ifr
.ifr_name
);
2696 ifnet_detach_ip(int s
, char * name
)
2701 bzero(&ifr
, sizeof(ifr
));
2702 strncpy(ifr
.ifr_name
, name
, sizeof(ifr
.ifr_name
));
2703 err
= ioctl(s
, SIOCPROTODETACH
, &ifr
);
2705 T_ASSERT_POSIX_SUCCESS(err
, "SIOCPROTODETACH %s", ifr
.ifr_name
);
2711 ifnet_destroy(int s
, const char * ifname
, bool fail_on_error
)
2716 bzero(&ifr
, sizeof(ifr
));
2717 strlcpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
2718 err
= ioctl(s
, SIOCIFDESTROY
, &ifr
);
2719 if (fail_on_error
) {
2721 T_ASSERT_POSIX_SUCCESS(err
, "SIOCSIFDESTROY %s", ifr
.ifr_name
);
2724 T_LOG("SIOCSIFDESTROY %s", ifr
.ifr_name
);
2730 ifnet_set_flags(int s
, const char * ifname
,
2731 uint16_t flags_set
, uint16_t flags_clear
)
2733 uint16_t flags_after
;
2734 uint16_t flags_before
;
2738 bzero(&ifr
, sizeof(ifr
));
2739 strncpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
2740 ret
= ioctl(s
, SIOCGIFFLAGS
, (caddr_t
)&ifr
);
2742 T_LOG("SIOCGIFFLAGS %s", ifr
.ifr_name
);
2745 flags_before
= (uint16_t)ifr
.ifr_flags
;
2746 ifr
.ifr_flags
|= flags_set
;
2747 ifr
.ifr_flags
&= ~(flags_clear
);
2748 flags_after
= (uint16_t)ifr
.ifr_flags
;
2749 if (flags_before
== flags_after
) {
2753 /* issue the ioctl */
2755 T_ASSERT_POSIX_SUCCESS(ioctl(s
, SIOCSIFFLAGS
, &ifr
),
2756 "SIOCSIFFLAGS %s 0x%x",
2757 ifr
.ifr_name
, (uint16_t)ifr
.ifr_flags
);
2759 T_LOG("setflags(%s set 0x%x clear 0x%x) 0x%x => 0x%x",
2760 ifr
.ifr_name
, flags_set
, flags_clear
,
2761 flags_before
, flags_after
);
2767 #define BRIDGE_NAME "bridge"
2768 #define BRIDGE200 BRIDGE_NAME "200"
2770 #define FETH_NAME "feth"
2772 /* On some platforms with DEBUG kernel, we need to wait a while */
2773 #define SIFCREATE_RETRY 600
2776 ifnet_create(int s
, const char * ifname
)
2781 bzero(&ifr
, sizeof(ifr
));
2782 strlcpy(ifr
.ifr_name
, ifname
, sizeof(ifr
.ifr_name
));
2784 for (int i
= 0; i
< SIFCREATE_RETRY
; i
++) {
2785 if (ioctl(s
, SIOCIFCREATE
, &ifr
) < 0) {
2787 T_LOG("SIOCSIFCREATE %s: %s", ifname
,
2789 if (error
== EBUSY
) {
2790 /* interface is tearing down, try again */
2792 } else if (error
== EEXIST
) {
2793 /* interface exists, try destroying it */
2794 (void)ifnet_destroy(s
, ifname
, false);
2796 /* unexpected failure */
2805 error
= ifnet_set_flags(s
, ifname
, IFF_UP
, 0);
2811 siocdrvspec(int s
, const char * ifname
,
2812 u_long op
, void *arg
, size_t argsize
, bool set
)
2816 memset(&ifd
, 0, sizeof(ifd
));
2817 strlcpy(ifd
.ifd_name
, ifname
, sizeof(ifd
.ifd_name
));
2819 ifd
.ifd_len
= argsize
;
2821 return ioctl(s
, set
? SIOCSDRVSPEC
: SIOCGDRVSPEC
, &ifd
);
2826 fake_set_peer(int s
, const char * feth
, const char * feth_peer
)
2828 struct if_fake_request iffr
;
2831 bzero((char *)&iffr
, sizeof(iffr
));
2832 if (feth_peer
!= NULL
) {
2833 strlcpy(iffr
.iffr_peer_name
, feth_peer
,
2834 sizeof(iffr
.iffr_peer_name
));
2836 ret
= siocdrvspec(s
, feth
, IF_FAKE_S_CMD_SET_PEER
,
2837 &iffr
, sizeof(iffr
), true);
2839 T_ASSERT_POSIX_SUCCESS(ret
,
2840 "SIOCDRVSPEC(%s, IF_FAKE_S_CMD_SET_PEER, %s)",
2841 feth
, (feth_peer
!= NULL
) ? feth_peer
: "<none>");
2846 bridge_add_member(int s
, const char * bridge
, const char * member
)
2851 memset(&req
, 0, sizeof(req
));
2852 strlcpy(req
.ifbr_ifsname
, member
, sizeof(req
.ifbr_ifsname
));
2853 ret
= siocdrvspec(s
, bridge
, BRDGADD
, &req
, sizeof(req
), true);
2855 T_ASSERT_POSIX_SUCCESS(ret
, "%s %s %s", __func__
, bridge
, member
);
2861 bridge_set_mac_nat(int s
, const char * bridge
, const char * member
, bool enable
)
2864 bool need_set
= false;
2868 memset(&req
, 0, sizeof(req
));
2869 strlcpy(req
.ifbr_ifsname
, member
, sizeof(req
.ifbr_ifsname
));
2870 ret
= siocdrvspec(s
, bridge
, BRDGGIFFLGS
, &req
, sizeof(req
), false);
2872 T_ASSERT_POSIX_SUCCESS(ret
, "BRDGGIFFLGS %s %s", bridge
, member
);
2873 flags
= req
.ifbr_ifsflags
;
2875 if ((flags
& IFBIF_MAC_NAT
) == 0) {
2877 req
.ifbr_ifsflags
|= IFBIF_MAC_NAT
;
2879 /* need to set it */
2880 } else if ((flags
& IFBIF_MAC_NAT
) != 0) {
2881 /* need to clear it */
2883 req
.ifbr_ifsflags
&= ~(uint32_t)IFBIF_MAC_NAT
;
2886 ret
= siocdrvspec(s
, bridge
, BRDGSIFFLGS
,
2887 &req
, sizeof(req
), true);
2889 T_ASSERT_POSIX_SUCCESS(ret
, "BRDGSIFFLGS %s %s 0x%x => 0x%x",
2891 flags
, req
.ifbr_ifsflags
);
2896 static struct ifbareq
*
2897 bridge_rt_table_copy_common(const char * bridge
, u_int
* ret_count
)
2899 struct ifbaconf ifbac
;
2900 u_int len
= 8 * 1024;
2901 char * inbuf
= NULL
;
2904 struct ifbareq
* rt_table
= NULL
;
2907 s
= inet_dgram_socket();
2910 * BRDGRTS should work like other ioctl's where passing in NULL
2911 * for the buffer says "tell me how many there are". Unfortunately,
2912 * it doesn't so we have to pass in a buffer, then check that it
2916 ninbuf
= realloc(inbuf
, len
);
2918 T_ASSERT_NOTNULL((void *)ninbuf
, "realloc %u", len
);
2919 ifbac
.ifbac_len
= len
;
2920 ifbac
.ifbac_buf
= inbuf
= ninbuf
;
2921 ret
= siocdrvspec(s
, bridge
, BRDGRTS
,
2922 &ifbac
, sizeof(ifbac
), false);
2924 T_ASSERT_POSIX_SUCCESS(ret
, "%s %s", __func__
, bridge
);
2925 if ((ifbac
.ifbac_len
+ sizeof(*rt_table
)) < len
) {
2926 /* we passed a buffer larger than what was required */
2931 if (ifbac
.ifbac_len
== 0) {
2933 T_LOG("No bridge routing entries");
2936 *ret_count
= ifbac
.ifbac_len
/ sizeof(*rt_table
);
2937 rt_table
= (struct ifbareq
*)(void *)ninbuf
;
2939 if (rt_table
== NULL
) {
2948 static struct ifbareq
*
2949 bridge_rt_table_copy(u_int
* ret_count
)
2951 return bridge_rt_table_copy_common(BRIDGE200
, ret_count
);
2955 bridge_rt_table_log(struct ifbareq
*rt_table
, u_int count
)
2958 char ntoabuf
[ETHER_NTOA_BUFSIZE
];
2959 struct ifbareq
* ifba
;
2961 for (i
= 0, ifba
= rt_table
; i
< count
; i
++, ifba
++) {
2962 ether_ntoa_buf((const ether_addr_t
*)&ifba
->ifba_dst
,
2963 ntoabuf
, sizeof(ntoabuf
));
2964 T_LOG("%s %s %lu", ifba
->ifba_ifsname
, ntoabuf
,
2970 static struct ifbrmne
*
2971 bridge_mac_nat_entries_copy_common(const char * bridge
, u_int
* ret_count
)
2977 struct ifbrmnelist mnl
;
2978 struct ifbrmne
* ret_list
= NULL
;
2983 s
= inet_dgram_socket();
2985 /* find out how many there are */
2986 bzero(&mnl
, sizeof(mnl
));
2987 err
= siocdrvspec(s
, bridge
, BRDGGMACNATLIST
, &mnl
, sizeof(mnl
), false);
2988 if (err
!= 0 && S_cleaning_up
) {
2989 T_LOG("BRDGGMACNATLIST %s failed %d", bridge
, errno
);
2993 T_ASSERT_POSIX_SUCCESS(err
, "BRDGGMACNATLIST %s", bridge
);
2995 T_ASSERT_GE(mnl
.ifbml_elsize
, (uint16_t)sizeof(struct ifbrmne
),
2996 "mac nat entry size %u minsize %u",
2997 mnl
.ifbml_elsize
, (u_int
)sizeof(struct ifbrmne
));
2998 if (mnl
.ifbml_len
== 0) {
3002 /* call again with a buffer large enough to hold them */
3003 buf
= malloc(mnl
.ifbml_len
);
3005 T_ASSERT_NOTNULL(buf
, "mac nat entries buffer");
3006 mnl
.ifbml_buf
= buf
;
3007 err
= siocdrvspec(s
, bridge
, BRDGGMACNATLIST
, &mnl
, sizeof(mnl
), false);
3009 T_ASSERT_POSIX_SUCCESS(err
, "BRDGGMACNATLIST %s", bridge
);
3010 count
= mnl
.ifbml_len
/ mnl
.ifbml_elsize
;
3014 if (mnl
.ifbml_elsize
== sizeof(struct ifbrmne
)) {
3015 /* element size is expected size, no need to "right-size" it */
3016 ret_list
= (struct ifbrmne
*)(void *)buf
;
3020 /* element size is larger than we expect, create a "right-sized" array */
3021 ret_list
= malloc(count
* sizeof(*ret_list
));
3023 T_ASSERT_NOTNULL(ret_list
, "mac nat entries list");
3024 for (i
= 0, scan
= buf
; i
< count
; i
++, scan
+= mnl
.ifbml_elsize
) {
3025 struct ifbrmne
* ifbmne
;
3027 ifbmne
= (struct ifbrmne
*)(void *)scan
;
3028 ret_list
[i
] = *ifbmne
;
3041 static struct ifbrmne
*
3042 bridge_mac_nat_entries_copy(u_int
* ret_count
)
3044 return bridge_mac_nat_entries_copy_common(BRIDGE200
, ret_count
);
3048 bridge_mac_nat_entries_log(struct ifbrmne
* entries
, u_int count
)
3051 char ntoabuf
[ETHER_NTOA_BUFSIZE
];
3052 char ntopbuf
[INET6_ADDRSTRLEN
];
3053 struct ifbrmne
* scan
;
3055 for (i
= 0, scan
= entries
; i
< count
; i
++, scan
++) {
3056 ether_ntoa_buf((const ether_addr_t
*)&scan
->ifbmne_mac
,
3057 ntoabuf
, sizeof(ntoabuf
));
3058 inet_ntop(scan
->ifbmne_af
, &scan
->ifbmne_ip
,
3059 ntopbuf
, sizeof(ntopbuf
));
3060 printf("%s %s %s %lu\n",
3061 scan
->ifbmne_ifname
, ntopbuf
, ntoabuf
,
3062 (unsigned long)scan
->ifbmne_expire
);
3070 static u_int S_n_ports
;
3071 static switch_port_list_t S_port_list
;
3074 bridge_cleanup(const char * bridge
, u_int n_ports
, bool fail_on_error
);
3077 cleanup_common(bool dump_table
)
3079 if (S_n_ports
== 0) {
3082 S_cleaning_up
= true;
3083 if ((S_port_list
!= NULL
&& S_port_list
->mac_nat
)
3084 || (dump_table
&& S_port_list
!= NULL
)) {
3085 switch_port_list_log(S_port_list
);
3086 if (S_port_list
->mac_nat
) {
3087 switch_port_list_verify_mac_nat(S_port_list
, true);
3089 (void)switch_port_list_verify_rt_table(S_port_list
, true);
3092 T_LOG("sleeping for 5 seconds\n");
3095 bridge_cleanup(BRIDGE200
, S_n_ports
, false);
3102 cleanup_common(true);
3107 sigint_handler(__unused
int sig
)
3109 cleanup_common(false);
3110 signal(SIGINT
, SIG_DFL
);
3113 static switch_port_list_t
3114 bridge_setup(char * bridge
, u_int n_ports
, u_int num_addrs
, bool mac_nat
)
3117 switch_port_list_t list
= NULL
;
3120 S_n_ports
= n_ports
;
3123 s
= inet_dgram_socket();
3124 err
= ifnet_create(s
, bridge
);
3128 list
= switch_port_list_alloc(n_ports
, mac_nat
);
3129 for (u_int i
= 0; i
< n_ports
; i
++) {
3131 char ifname
[IFNAMSIZ
];
3132 char member_ifname
[IFNAMSIZ
];
3133 ether_addr_t member_mac
;
3135 snprintf(ifname
, sizeof(ifname
), "%s%d",
3137 snprintf(member_ifname
, sizeof(member_ifname
), "%s%d",
3138 FETH_NAME
, i
+ n_ports
);
3139 err
= ifnet_create(s
, ifname
);
3143 ifnet_attach_ip(s
, ifname
);
3144 err
= ifnet_create(s
, member_ifname
);
3148 err
= ifnet_get_lladdr(s
, member_ifname
, &member_mac
);
3152 err
= fake_set_peer(s
, ifname
, member_ifname
);
3156 /* add the interface's peer to the bridge */
3157 err
= bridge_add_member(s
, bridge
, member_ifname
);
3162 do_mac_nat
= (i
== 0 && mac_nat
);
3164 /* enable MAC NAT on unit 0 */
3165 err
= bridge_set_mac_nat(s
, bridge
, member_ifname
,
3171 /* we'll send/receive on the interface */
3172 err
= switch_port_list_add_port(list
, i
, ifname
, member_ifname
,
3173 &member_mac
, num_addrs
,
3183 if (err
!= 0 && list
!= NULL
) {
3184 switch_port_list_dealloc(list
);
3192 bridge_cleanup(const char * bridge
, u_int n_ports
, bool fail_on_error
)
3196 s
= inet_dgram_socket();
3197 ifnet_destroy(s
, bridge
, fail_on_error
);
3198 for (u_int i
= 0; i
< n_ports
; i
++) {
3199 char ifname
[IFNAMSIZ
];
3200 char member_ifname
[IFNAMSIZ
];
3202 snprintf(ifname
, sizeof(ifname
), "%s%d",
3204 snprintf(member_ifname
, sizeof(member_ifname
), "%s%d",
3205 FETH_NAME
, i
+ n_ports
);
3206 ifnet_destroy(s
, ifname
, fail_on_error
);
3207 ifnet_destroy(s
, member_ifname
, fail_on_error
);
3217 * Basic Bridge Tests
3220 * - two cases: actual broadcast, unknown ethernet
3221 * - send broadcast packets
3222 * - verify all received
3223 * - check bridge rt list contains all expected MAC addresses
3224 * - send unicast ARP packets
3225 * - verify packets received only on expected port
3228 * - verify ARP translation
3229 * - verify IPv4 translation
3230 * - verify DHCP broadcast bit conversion
3231 * - verify IPv6 translation
3232 * - verify ND6 translation (Neighbor, Router)
3236 bridge_test(packet_validator_t validator
,
3238 const ether_addr_t
* dst_eaddr
,
3239 uint8_t af
, u_int n_ports
, u_int num_addrs
)
3241 #if TARGET_OS_BRIDGE
3242 T_SKIP("Test uses too much memory");
3243 #else /* TARGET_OS_BRIDGE */
3244 switch_port_list_t port_list
;
3246 signal(SIGINT
, sigint_handler
);
3247 port_list
= bridge_setup(BRIDGE200
, n_ports
, num_addrs
, false);
3248 if (port_list
== NULL
) {
3249 T_FAIL("bridge_setup");
3252 S_port_list
= port_list
;
3253 bridge_learning_test(port_list
, af
, validator
, context
, dst_eaddr
);
3255 //T_LOG("Sleeping for 5 seconds");
3257 bridge_cleanup(BRIDGE200
, n_ports
, true);
3258 switch_port_list_dealloc(port_list
);
3260 #endif /* TARGET_OS_BRIDGE */
3264 bridge_test_mac_nat_ipv4(u_int n_ports
, u_int num_addrs
)
3266 #if TARGET_OS_BRIDGE
3267 T_SKIP("Test uses too much memory");
3268 #else /* TARGET_OS_BRIDGE */
3269 switch_port_list_t port_list
;
3271 signal(SIGINT
, sigint_handler
);
3272 port_list
= bridge_setup(BRIDGE200
, n_ports
, num_addrs
, true);
3273 if (port_list
== NULL
) {
3274 T_FAIL("bridge_setup");
3277 S_port_list
= port_list
;
3279 /* verify that IPv4 packets get translated when necessary */
3280 mac_nat_test_ip(port_list
, AF_INET
);
3282 /* verify the DHCP broadcast bit gets set appropriately */
3283 mac_nat_test_dhcp(port_list
);
3285 /* verify that ARP packet gets translated when necessary */
3286 mac_nat_test_arp_out(port_list
);
3287 mac_nat_test_arp_in(port_list
);
3290 T_LOG("Sleeping for 5 seconds");
3293 bridge_cleanup(BRIDGE200
, n_ports
, true);
3294 switch_port_list_dealloc(port_list
);
3296 #endif /* TARGET_OS_BRIDGE */
3300 bridge_test_mac_nat_ipv6(u_int n_ports
, u_int num_addrs
)
3302 #if TARGET_OS_BRIDGE
3303 T_SKIP("Test uses too much memory");
3304 #else /* TARGET_OS_BRIDGE */
3305 switch_port_list_t port_list
;
3307 signal(SIGINT
, sigint_handler
);
3308 port_list
= bridge_setup(BRIDGE200
, n_ports
, num_addrs
, true);
3309 if (port_list
== NULL
) {
3310 T_FAIL("bridge_setup");
3313 S_port_list
= port_list
;
3315 /* verify that IPv6 packets get translated when necessary */
3316 mac_nat_test_ip(port_list
, AF_INET6
);
3318 /* verify that ND6 packet gets translated when necessary */
3319 mac_nat_test_nd6_out(port_list
);
3321 T_LOG("Sleeping for 5 seconds");
3324 bridge_cleanup(BRIDGE200
, n_ports
, true);
3325 switch_port_list_dealloc(port_list
);
3327 #endif /* TARGET_OS_BRIDGE */
3331 system_cmd(const char *cmd
, bool fail_on_error
)
3334 int exit_status
= 0;
3335 const char *argv
[] = {
3336 "/usr/local/bin/bash",
3342 int rc
= dt_launch_tool(&pid
, (char **)(void *)argv
, false, NULL
, NULL
);
3344 T_ASSERT_EQ(rc
, 0, "dt_launch_tool(%s) failed", cmd
);
3346 if (dt_waitpid(pid
, &exit_status
, NULL
, 30)) {
3348 T_ASSERT_MACH_SUCCESS(exit_status
, "command(%s)", cmd
);
3350 if (fail_on_error
) {
3351 T_FAIL("dt_waitpid(%s) failed", cmd
);
3359 struct ifbrparam param
;
3360 int s
= inet_dgram_socket();
3362 system_cmd("pfctl -d", false);
3363 system_cmd("pfctl -F all", false);
3365 param
.ifbrp_filter
= 0;
3366 siocdrvspec(s
, BRIDGE200
, BRDGSFILT
,
3367 ¶m
, sizeof(param
), true);
3372 block_all_traffic(bool input
, const char* infname1
, const char* infname2
)
3374 int s
= inet_dgram_socket();
3376 struct ifbrparam param
;
3378 char *dir
= input
? "in" : "out";
3380 snprintf(command
, sizeof(command
), "echo \"block %s on %s all\nblock %s on %s all\n\" | pfctl -vvv -f -",
3381 dir
, infname1
, dir
, infname2
);
3382 /* enable block all filter */
3383 param
.ifbrp_filter
= IFBF_FILT_MEMBER
| IFBF_FILT_ONLYIP
;
3384 ret
= siocdrvspec(s
, BRIDGE200
, BRDGSFILT
,
3385 ¶m
, sizeof(param
), true);
3386 T_ASSERT_POSIX_SUCCESS(ret
,
3387 "SIOCDRVSPEC(BRDGSFILT %s, 0x%x)",
3388 BRIDGE200
, param
.ifbrp_filter
);
3389 // ignore errors such that not having pf.os doesn't raise any issues
3390 system_cmd(command
, false);
3391 system_cmd("pfctl -e", true);
3392 system_cmd("pfctl -s all", true);
3396 * Basic bridge filter test
3398 * For both broadcast and unicast transfers ensure that data can
3399 * be blocked using pf on the bridge
3403 filter_test(uint8_t af
)
3405 #if TARGET_OS_BRIDGE
3406 T_SKIP("pfctl isn't valid on this platform");
3407 #else /* TARGET_OS_BRIDGE */
3408 switch_port_list_t port_list
;
3410 const u_int n_ports
= 2;
3411 u_int num_addrs
= 1;
3413 char ntoabuf
[ETHER_NTOA_BUFSIZE
];
3414 union ifbrip dst_ip
;
3415 bool blocked
= true;
3417 const char* ifnames
[2];
3419 signal(SIGINT
, sigint_handler
);
3422 T_ATEND(cleanup_pf
);
3424 port_list
= bridge_setup(BRIDGE200
, n_ports
, num_addrs
, false);
3425 if (port_list
== NULL
) {
3426 T_FAIL("bridge_setup");
3430 ether_ntoa_buf(ðer_broadcast
, ntoabuf
, sizeof(ntoabuf
));
3432 S_port_list
= port_list
;
3433 for (i
= 0, port
= port_list
->list
; i
< port_list
->count
; i
++, port
++) {
3434 ifnames
[i
] = port
->member_ifname
;
3437 get_broadcast_ip_address(af
, &dst_ip
);
3441 block_all_traffic(input
, ifnames
[0], ifnames
[1]);
3443 for (i
= 0, port
= port_list
->list
; i
< port_list
->count
; i
++, port
++) {
3445 T_LOG("Sending on %s", port
->ifname
);
3447 for (u_int j
= 0; j
< port
->num_addrs
; j
++) {
3448 uint32_t generation
;
3450 generation
= next_generation();
3451 send_generation(port
,
3458 /* receive across all ports */
3459 check_receive_generation(port_list
,
3462 validate_broadcast_dhost
,
3465 /* ensure that every port saw the right amount of packets*/
3467 check_received_count(port_list
, port
, 0);
3469 check_received_count(port_list
, port
, 1);
3473 T_PASS("%s broadcast %s %s", __func__
, blocked
? "blocked" : "not blocked", input
? "input" : "output");
3476 } while (input
== false && blocked
);
3478 } while (blocked
== false);
3483 block_all_traffic(input
, ifnames
[0], ifnames
[1]);
3485 for (i
= 0, port
= port_list
->list
; i
< port_list
->count
; i
++, port
++) {
3486 /* send unicast packets to every other port's MAC addresses */
3487 unicast_send_all(port_list
, af
, port
);
3489 /* receive all of that generated traffic */
3490 switch_port_list_check_receive(port_list
, af
, NULL
, 0,
3491 validate_port_dhost
, NULL
);
3493 /* ensure that every port saw the right amount of packets*/
3495 check_received_count(port_list
, port
, 0);
3497 check_received_count(port_list
, port
, 1);
3500 T_PASS("%s unicast %s %s", __func__
, blocked
? "blocked" : "not blocked", input
? "input" : "output");
3503 } while (input
== false && blocked
);
3505 } while (blocked
== false);
3507 bridge_cleanup(BRIDGE200
, n_ports
, true);
3508 switch_port_list_dealloc(port_list
);
3510 #endif /* TARGET_OS_BRIDGE */
3513 T_DECL(if_bridge_bcast
,
3514 "bridge broadcast IPv4",
3515 T_META_ASROOT(true))
3517 bridge_test(validate_broadcast_dhost
, NULL
, ðer_broadcast
,
3521 T_DECL(if_bridge_bcast_many
,
3522 "bridge broadcast many IPv4",
3523 T_META_ASROOT(true))
3525 bridge_test(validate_broadcast_dhost
, NULL
, ðer_broadcast
,
3529 T_DECL(if_bridge_unknown
,
3530 "bridge unknown host IPv4",
3531 T_META_ASROOT(true))
3533 bridge_test(validate_not_present_dhost
, NULL
, ðer_external
,
3537 T_DECL(if_bridge_bcast_v6
,
3538 "bridge broadcast IPv6",
3539 T_META_ASROOT(true))
3541 bridge_test(validate_broadcast_dhost
, NULL
, ðer_broadcast
,
3545 T_DECL(if_bridge_bcast_many_v6
,
3546 "bridge broadcast many IPv6",
3547 T_META_ASROOT(true))
3549 bridge_test(validate_broadcast_dhost
, NULL
, ðer_broadcast
,
3553 T_DECL(if_bridge_unknown_v6
,
3554 "bridge unknown host IPv6",
3555 T_META_ASROOT(true))
3557 bridge_test(validate_not_present_dhost
, NULL
, ðer_external
,
3561 T_DECL(if_bridge_mac_nat_ipv4
,
3562 "bridge mac nat ipv4",
3563 T_META_ASROOT(true))
3565 bridge_test_mac_nat_ipv4(5, 10);
3568 T_DECL(if_bridge_mac_nat_ipv6
,
3569 "bridge mac nat ipv6",
3570 T_META_ASROOT(true))
3572 bridge_test_mac_nat_ipv6(5, 10);
3575 T_DECL(if_bridge_filter_ipv4
,
3576 "bridge filter ipv4",
3577 T_META_ASROOT(true))
3579 filter_test(AF_INET
);
3582 T_DECL(if_bridge_filter_ipv6
,
3583 "bridge filter ipv6",
3584 T_META_ASROOT(true))
3586 filter_test(AF_INET6
);