xref: /freebsd-src/tests/sys/netgraph/bridge.c (revision 5554abd9cc9702af30af90925b33c5efff4e7d88)
161814702SLutz Donnerhacke /*-
261814702SLutz Donnerhacke  * SPDX-License-Identifier: BSD-3-Clause
361814702SLutz Donnerhacke  *
461814702SLutz Donnerhacke  * Copyright 2021 Lutz Donnerhacke
561814702SLutz Donnerhacke  *
661814702SLutz Donnerhacke  * Redistribution and use in source and binary forms, with or without
761814702SLutz Donnerhacke  * modification, are permitted provided that the following conditions
861814702SLutz Donnerhacke  * are met:
961814702SLutz Donnerhacke  *
1061814702SLutz Donnerhacke  * 1. Redistributions of source code must retain the above copyright
1161814702SLutz Donnerhacke  *    notice, this list of conditions and the following disclaimer.
1261814702SLutz Donnerhacke  * 2. Redistributions in binary form must reproduce the above
1361814702SLutz Donnerhacke  *    copyright notice, this list of conditions and the following
1461814702SLutz Donnerhacke  *    disclaimer in the documentation and/or other materials provided
1561814702SLutz Donnerhacke  *    with the distribution.
1661814702SLutz Donnerhacke  * 3. Neither the name of the copyright holder nor the names of its
1761814702SLutz Donnerhacke  *    contributors may be used to endorse or promote products derived
1861814702SLutz Donnerhacke  *    from this software without specific prior written permission.
1961814702SLutz Donnerhacke  *
2061814702SLutz Donnerhacke  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
2161814702SLutz Donnerhacke  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
2261814702SLutz Donnerhacke  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
2361814702SLutz Donnerhacke  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
2461814702SLutz Donnerhacke  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
2561814702SLutz Donnerhacke  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
2661814702SLutz Donnerhacke  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
2761814702SLutz Donnerhacke  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2861814702SLutz Donnerhacke  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
2961814702SLutz Donnerhacke  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
3061814702SLutz Donnerhacke  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
3161814702SLutz Donnerhacke  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3261814702SLutz Donnerhacke  * SUCH DAMAGE.
3361814702SLutz Donnerhacke  */
3461814702SLutz Donnerhacke #include <atf-c.h>
3561814702SLutz Donnerhacke #include <errno.h>
3661814702SLutz Donnerhacke #include <stdio.h>
3761814702SLutz Donnerhacke 
3861814702SLutz Donnerhacke #include <net/ethernet.h>
3961814702SLutz Donnerhacke #include <netinet/in.h>
4061814702SLutz Donnerhacke #include <netinet/ip.h>
4161814702SLutz Donnerhacke #include <netinet/ip6.h>
4261814702SLutz Donnerhacke 
4361814702SLutz Donnerhacke #include "util.h"
4461814702SLutz Donnerhacke #include <netgraph/ng_bridge.h>
4561814702SLutz Donnerhacke 
4661814702SLutz Donnerhacke static void	get_tablesize(char const *source, struct ng_mesg *msg, void *ctx);
4761814702SLutz Donnerhacke struct gettable
4861814702SLutz Donnerhacke {
4961814702SLutz Donnerhacke 	u_int32_t	tok;
5061814702SLutz Donnerhacke 	int		cnt;
5161814702SLutz Donnerhacke };
5261814702SLutz Donnerhacke 
5361814702SLutz Donnerhacke struct frame4
5461814702SLutz Donnerhacke {
5561814702SLutz Donnerhacke 	struct ether_header eh;
5661814702SLutz Donnerhacke 	struct ip	ip;
5761814702SLutz Donnerhacke 	char		data[64];
5861814702SLutz Donnerhacke };
5961814702SLutz Donnerhacke struct frame6
6061814702SLutz Donnerhacke {
6161814702SLutz Donnerhacke 	struct ether_header eh;
6261814702SLutz Donnerhacke 	struct ip6_hdr	ip;
6361814702SLutz Donnerhacke 	char		data[64];
6461814702SLutz Donnerhacke };
6561814702SLutz Donnerhacke 
6661814702SLutz Donnerhacke static struct frame4 msg4 = {
6761814702SLutz Donnerhacke 	.ip.ip_v = 4,
6861814702SLutz Donnerhacke 	.ip.ip_hl = 5,
6961814702SLutz Donnerhacke 	.ip.ip_ttl = 1,
7061814702SLutz Donnerhacke 	.ip.ip_p = 254,
7161814702SLutz Donnerhacke 	.ip.ip_src = {htonl(0x0a00dead)},
7261814702SLutz Donnerhacke 	.ip.ip_dst = {htonl(0x0a00beef)},
7361814702SLutz Donnerhacke 	.ip.ip_len = 32,
7461814702SLutz Donnerhacke 	.eh.ether_type = ETHERTYPE_IP,
7561814702SLutz Donnerhacke 	.eh.ether_shost = {2, 4, 6},
7661814702SLutz Donnerhacke 	.eh.ether_dhost = {2, 4, 6},
7761814702SLutz Donnerhacke };
7861814702SLutz Donnerhacke 
7961814702SLutz Donnerhacke 
8061814702SLutz Donnerhacke ATF_TC(basic);
ATF_TC_HEAD(basic,conf)8161814702SLutz Donnerhacke ATF_TC_HEAD(basic, conf)
8261814702SLutz Donnerhacke {
8361814702SLutz Donnerhacke 	atf_tc_set_md_var(conf, "require.user", "root");
8461814702SLutz Donnerhacke }
8561814702SLutz Donnerhacke 
ATF_TC_BODY(basic,dummy)8661814702SLutz Donnerhacke ATF_TC_BODY(basic, dummy)
8761814702SLutz Donnerhacke {
88*5554abd9SLutz Donnerhacke 	ng_counter_t	r;
8961814702SLutz Donnerhacke 	struct gettable	rm;
9061814702SLutz Donnerhacke 
9161814702SLutz Donnerhacke 	ng_init();
9261814702SLutz Donnerhacke 	ng_errors(PASS);
9361814702SLutz Donnerhacke 	ng_shutdown("bridge:");
9461814702SLutz Donnerhacke 	ng_errors(FAIL);
9561814702SLutz Donnerhacke 
9661814702SLutz Donnerhacke 	ng_mkpeer(".", "a", "bridge", "link0");
9761814702SLutz Donnerhacke 	ng_name("a", "bridge");
9861814702SLutz Donnerhacke 	ng_connect(".", "b", "bridge:", "link1");
9961814702SLutz Donnerhacke 	ng_connect(".", "c", "bridge:", "link2");
10061814702SLutz Donnerhacke 
10161814702SLutz Donnerhacke 	/* do not bounce back */
10261814702SLutz Donnerhacke 	ng_register_data("a", get_data0);
103*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
10461814702SLutz Donnerhacke 	msg4.eh.ether_shost[5] = 1;
10561814702SLutz Donnerhacke 	ng_send_data("a", &msg4, sizeof(msg4));
10661814702SLutz Donnerhacke 	ng_handle_events(50, &r);
10761814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 0);
10861814702SLutz Donnerhacke 
10961814702SLutz Donnerhacke 	/* send to others */
11061814702SLutz Donnerhacke 	ng_register_data("b", get_data1);
11161814702SLutz Donnerhacke 	ng_register_data("c", get_data2);
112*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
11361814702SLutz Donnerhacke 	msg4.eh.ether_shost[5] = 1;
11461814702SLutz Donnerhacke 	ng_send_data("a", &msg4, sizeof(msg4));
11561814702SLutz Donnerhacke 	ng_handle_events(50, &r);
11661814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 1);
11761814702SLutz Donnerhacke 
118*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
11961814702SLutz Donnerhacke 	msg4.eh.ether_shost[5] = 2;
12061814702SLutz Donnerhacke 	ng_send_data("b", &msg4, sizeof(msg4));
12161814702SLutz Donnerhacke 	ng_handle_events(50, &r);
12261814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 1);
12361814702SLutz Donnerhacke 
124*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
12561814702SLutz Donnerhacke 	msg4.eh.ether_shost[5] = 3;
12661814702SLutz Donnerhacke 	ng_send_data("c", &msg4, sizeof(msg4));
12761814702SLutz Donnerhacke 	ng_handle_events(50, &r);
12861814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 1 && r[1] == 1 && r[2] == 0);
12961814702SLutz Donnerhacke 
13061814702SLutz Donnerhacke 	/* send to learned unicast */
131*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
13261814702SLutz Donnerhacke 	msg4.eh.ether_shost[5] = 1;
13361814702SLutz Donnerhacke 	msg4.eh.ether_dhost[5] = 3;
13461814702SLutz Donnerhacke 	ng_send_data("a", &msg4, sizeof(msg4));
13561814702SLutz Donnerhacke 	ng_handle_events(50, &r);
13661814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 0 && r[1] == 0 && r[2] == 1);
13761814702SLutz Donnerhacke 
13861814702SLutz Donnerhacke 	/* inspect mac table */
13961814702SLutz Donnerhacke 	ng_register_msg(get_tablesize);
14061814702SLutz Donnerhacke 	rm.tok = ng_send_msg("bridge:", "gettable");
14161814702SLutz Donnerhacke 	rm.cnt = 0;
14261814702SLutz Donnerhacke 	ng_handle_events(50, &rm);
14361814702SLutz Donnerhacke 	ATF_CHECK(rm.cnt == 3);
14461814702SLutz Donnerhacke 
14561814702SLutz Donnerhacke 	/* remove a link */
14661814702SLutz Donnerhacke 	ng_rmhook(".", "b");
147*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
14861814702SLutz Donnerhacke 	msg4.eh.ether_shost[5] = 1;
14961814702SLutz Donnerhacke 	msg4.eh.ether_dhost[5] = 0;
15061814702SLutz Donnerhacke 	ng_send_data("a", &msg4, sizeof(msg4));
15161814702SLutz Donnerhacke 	ng_handle_events(50, &r);
15261814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 0 && r[1] == 0 && r[2] == 1);
15361814702SLutz Donnerhacke 
15461814702SLutz Donnerhacke 	/* inspect mac table */
15561814702SLutz Donnerhacke 	ng_register_msg(get_tablesize);
15661814702SLutz Donnerhacke 	rm.tok = ng_send_msg("bridge:", "gettable");
15761814702SLutz Donnerhacke 	rm.cnt = 0;
15861814702SLutz Donnerhacke 	ng_handle_events(50, &rm);
15961814702SLutz Donnerhacke 	ATF_CHECK(rm.cnt == 2);
16061814702SLutz Donnerhacke 
16161814702SLutz Donnerhacke 	ng_shutdown("bridge:");
16261814702SLutz Donnerhacke }
16361814702SLutz Donnerhacke 
16461814702SLutz Donnerhacke ATF_TC(persistence);
ATF_TC_HEAD(persistence,conf)16561814702SLutz Donnerhacke ATF_TC_HEAD(persistence, conf)
16661814702SLutz Donnerhacke {
16761814702SLutz Donnerhacke 	atf_tc_set_md_var(conf, "require.user", "root");
16861814702SLutz Donnerhacke }
16961814702SLutz Donnerhacke 
ATF_TC_BODY(persistence,dummy)17061814702SLutz Donnerhacke ATF_TC_BODY(persistence, dummy)
17161814702SLutz Donnerhacke {
17261814702SLutz Donnerhacke 	ng_init();
17361814702SLutz Donnerhacke 	ng_errors(PASS);
17461814702SLutz Donnerhacke 	ng_shutdown("bridge:");
17561814702SLutz Donnerhacke 	ng_errors(FAIL);
17661814702SLutz Donnerhacke 
17761814702SLutz Donnerhacke 	ng_mkpeer(".", "a", "bridge", "link0");
17861814702SLutz Donnerhacke 	ng_name("a", "bridge");
17961814702SLutz Donnerhacke 
18061814702SLutz Donnerhacke 	ng_send_msg("bridge:", "setpersistent");
18161814702SLutz Donnerhacke 	ng_rmhook(".", "a");
18261814702SLutz Donnerhacke 
18361814702SLutz Donnerhacke 	ng_shutdown("bridge:");
18461814702SLutz Donnerhacke }
18561814702SLutz Donnerhacke 
18661814702SLutz Donnerhacke ATF_TC(loop);
ATF_TC_HEAD(loop,conf)18761814702SLutz Donnerhacke ATF_TC_HEAD(loop, conf)
18861814702SLutz Donnerhacke {
18961814702SLutz Donnerhacke 	atf_tc_set_md_var(conf, "require.user", "root");
19061814702SLutz Donnerhacke }
19161814702SLutz Donnerhacke 
ATF_TC_BODY(loop,dummy)19261814702SLutz Donnerhacke ATF_TC_BODY(loop, dummy)
19361814702SLutz Donnerhacke {
194*5554abd9SLutz Donnerhacke 	ng_counter_t	r;
195*5554abd9SLutz Donnerhacke 	int		i;
19661814702SLutz Donnerhacke 
19761814702SLutz Donnerhacke 	ng_init();
19861814702SLutz Donnerhacke 	ng_errors(PASS);
19961814702SLutz Donnerhacke 	ng_shutdown("bridge1:");
20061814702SLutz Donnerhacke 	ng_shutdown("bridge2:");
20161814702SLutz Donnerhacke 	ng_errors(FAIL);
20261814702SLutz Donnerhacke 
20361814702SLutz Donnerhacke 	ng_mkpeer(".", "a", "bridge", "link0");
20461814702SLutz Donnerhacke 	ng_name("a", "bridge1");
20561814702SLutz Donnerhacke 	ng_mkpeer(".", "b", "bridge", "link1");
20661814702SLutz Donnerhacke 	ng_name("b", "bridge2");
20761814702SLutz Donnerhacke 
20861814702SLutz Donnerhacke 	ng_register_data("a", get_data0);
20961814702SLutz Donnerhacke 	ng_register_data("b", get_data1);
21061814702SLutz Donnerhacke 
21161814702SLutz Donnerhacke 	/*-
21261814702SLutz Donnerhacke 	 * Open loop
21361814702SLutz Donnerhacke 	 *
21461814702SLutz Donnerhacke 	 *    /-- bridge1
21561814702SLutz Donnerhacke 	 * . <    |
21661814702SLutz Donnerhacke 	 *    \-- bridge2
21761814702SLutz Donnerhacke 	 */
21861814702SLutz Donnerhacke 	ng_connect("bridge1:", "link11", "bridge2:", "link11");
21961814702SLutz Donnerhacke 
220*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
22161814702SLutz Donnerhacke 	msg4.eh.ether_shost[5] = 1;
22261814702SLutz Donnerhacke 	ng_send_data("a", &msg4, sizeof(msg4));
22361814702SLutz Donnerhacke 	ng_handle_events(50, &r);
22461814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 0 && r[1] == 1);
22561814702SLutz Donnerhacke 
22661814702SLutz Donnerhacke 	/*-
22761814702SLutz Donnerhacke 	 * Closed loop, DANGEROUS!
22861814702SLutz Donnerhacke 	 *
22961814702SLutz Donnerhacke 	 *    /-- bridge1 -\
23061814702SLutz Donnerhacke 	 * . <     |       |
23161814702SLutz Donnerhacke 	 *    \-- bridge2 -/
23261814702SLutz Donnerhacke 	 */
23361814702SLutz Donnerhacke 	ng_connect("bridge1:", "link12", "bridge2:", "link12");
23461814702SLutz Donnerhacke 
235*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
23661814702SLutz Donnerhacke 	msg4.eh.ether_shost[5] = 1;
23761814702SLutz Donnerhacke 	ng_errors(PASS);
23861814702SLutz Donnerhacke 	ng_send_data("a", &msg4, sizeof(msg4));
23961814702SLutz Donnerhacke 	ATF_CHECK_ERRNO(ELOOP, errno != 0);	/* loop might be detected */
24061814702SLutz Donnerhacke 	ng_errors(FAIL);
24161814702SLutz Donnerhacke 	for (i = 0; i < 10; i++)	/* don't run forever */
24261814702SLutz Donnerhacke 		if (!ng_handle_event(50, &r))
24361814702SLutz Donnerhacke 			break;
24461814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 0 && r[1] == 1);
24561814702SLutz Donnerhacke 
24661814702SLutz Donnerhacke 	ng_shutdown("bridge1:");
24761814702SLutz Donnerhacke 	ng_shutdown("bridge2:");
24861814702SLutz Donnerhacke }
24961814702SLutz Donnerhacke 
25061814702SLutz Donnerhacke ATF_TC(many_unicasts);
ATF_TC_HEAD(many_unicasts,conf)25161814702SLutz Donnerhacke ATF_TC_HEAD(many_unicasts, conf)
25261814702SLutz Donnerhacke {
25361814702SLutz Donnerhacke 	atf_tc_set_md_var(conf, "require.user", "root");
25461814702SLutz Donnerhacke }
25561814702SLutz Donnerhacke 
ATF_TC_BODY(many_unicasts,dummy)25661814702SLutz Donnerhacke ATF_TC_BODY(many_unicasts, dummy)
25761814702SLutz Donnerhacke {
258*5554abd9SLutz Donnerhacke 	ng_counter_t	r;
259*5554abd9SLutz Donnerhacke 	int		i;
26061814702SLutz Donnerhacke 	const int	HOOKS = 1000;
26161814702SLutz Donnerhacke 	struct gettable	rm;
26261814702SLutz Donnerhacke 
26361814702SLutz Donnerhacke 	ng_init();
26461814702SLutz Donnerhacke 	ng_errors(PASS);
26561814702SLutz Donnerhacke 	ng_shutdown("bridge:");
26661814702SLutz Donnerhacke 	ng_errors(FAIL);
26761814702SLutz Donnerhacke 
26861814702SLutz Donnerhacke 	ng_mkpeer(".", "a", "bridge", "link0");
26961814702SLutz Donnerhacke 	ng_name("a", "bridge");
27061814702SLutz Donnerhacke 	ng_register_data("a", get_data0);
27161814702SLutz Donnerhacke 
27261814702SLutz Donnerhacke 	/* learn MAC */
273*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
27461814702SLutz Donnerhacke 	msg4.eh.ether_shost[3] = 0xff;
27561814702SLutz Donnerhacke 	ng_send_data("a", &msg4, sizeof(msg4));
27661814702SLutz Donnerhacke 	ng_handle_events(50, &r);
27761814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 0);
27861814702SLutz Donnerhacke 
27961814702SLutz Donnerhacke 	/* use learned MAC as destination */
28061814702SLutz Donnerhacke 	msg4.eh.ether_shost[3] = 0;
28161814702SLutz Donnerhacke 	msg4.eh.ether_dhost[3] = 0xff;
28261814702SLutz Donnerhacke 
28361814702SLutz Donnerhacke 	/* now send */
284*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
28561814702SLutz Donnerhacke 	for (i = 1; i <= HOOKS; i++)
28661814702SLutz Donnerhacke 	{
28761814702SLutz Donnerhacke 		char		hook[20];
28861814702SLutz Donnerhacke 
28961814702SLutz Donnerhacke 		snprintf(hook, sizeof(hook), "link%d", i);
29061814702SLutz Donnerhacke 		ng_connect(".", hook, "bridge:", hook);
29161814702SLutz Donnerhacke 		ng_register_data(hook, get_data2);
29261814702SLutz Donnerhacke 
29361814702SLutz Donnerhacke 		msg4.eh.ether_shost[4] = i >> 8;
29461814702SLutz Donnerhacke 		msg4.eh.ether_shost[5] = i & 0xff;
29561814702SLutz Donnerhacke 		ng_errors(PASS);
29661814702SLutz Donnerhacke 		ng_send_data(hook, &msg4, sizeof(msg4));
29761814702SLutz Donnerhacke 		ng_errors(FAIL);
29861814702SLutz Donnerhacke 		if (errno != 0)
29961814702SLutz Donnerhacke 			break;
30061814702SLutz Donnerhacke 		ng_handle_events(50, &r);
30161814702SLutz Donnerhacke 	}
30261814702SLutz Donnerhacke 	ATF_CHECK(r[0] == HOOKS && r[2] == 0);
30361814702SLutz Donnerhacke 
30461814702SLutz Donnerhacke 	/* inspect mac table */
30561814702SLutz Donnerhacke 	ng_register_msg(get_tablesize);
30661814702SLutz Donnerhacke 	rm.cnt = 0;
30761814702SLutz Donnerhacke 	ng_errors(PASS);
30861814702SLutz Donnerhacke 	rm.tok = ng_send_msg("bridge:", "gettable");
30961814702SLutz Donnerhacke 	ng_errors(FAIL);
31061814702SLutz Donnerhacke 	if (rm.tok == (u_int32_t)-1)
31161814702SLutz Donnerhacke 	{
31261814702SLutz Donnerhacke 		ATF_CHECK_ERRNO(ENOBUFS, 1);
31361814702SLutz Donnerhacke 		atf_tc_expect_fail("response too large");
31461814702SLutz Donnerhacke 	}
31561814702SLutz Donnerhacke 	ng_handle_events(50, &rm);
31661814702SLutz Donnerhacke 	ATF_CHECK(rm.cnt == HOOKS + 1);
31761814702SLutz Donnerhacke 	atf_tc_expect_pass();
31861814702SLutz Donnerhacke 
31961814702SLutz Donnerhacke 	ng_shutdown("bridge:");
32061814702SLutz Donnerhacke }
32161814702SLutz Donnerhacke 
32261814702SLutz Donnerhacke ATF_TC(many_broadcasts);
ATF_TC_HEAD(many_broadcasts,conf)32361814702SLutz Donnerhacke ATF_TC_HEAD(many_broadcasts, conf)
32461814702SLutz Donnerhacke {
32561814702SLutz Donnerhacke 	atf_tc_set_md_var(conf, "require.user", "root");
32661814702SLutz Donnerhacke }
32761814702SLutz Donnerhacke 
ATF_TC_BODY(many_broadcasts,dummy)32861814702SLutz Donnerhacke ATF_TC_BODY(many_broadcasts, dummy)
32961814702SLutz Donnerhacke {
330*5554abd9SLutz Donnerhacke 	ng_counter_t	r;
331*5554abd9SLutz Donnerhacke 	int		i;
33261814702SLutz Donnerhacke 	const int	HOOKS = 1000;
33361814702SLutz Donnerhacke 
33461814702SLutz Donnerhacke 	ng_init();
33561814702SLutz Donnerhacke 	ng_errors(PASS);
33661814702SLutz Donnerhacke 	ng_shutdown("bridge:");
33761814702SLutz Donnerhacke 	ng_errors(FAIL);
33861814702SLutz Donnerhacke 
33961814702SLutz Donnerhacke 	ng_mkpeer(".", "a", "bridge", "link0");
34061814702SLutz Donnerhacke 	ng_name("a", "bridge");
34161814702SLutz Donnerhacke 	ng_register_data("a", get_data0);
34261814702SLutz Donnerhacke 
34361814702SLutz Donnerhacke 	/* learn MAC */
344*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
34561814702SLutz Donnerhacke 	msg4.eh.ether_shost[3] = 0xff;
34661814702SLutz Donnerhacke 	ng_send_data("a", &msg4, sizeof(msg4));
34761814702SLutz Donnerhacke 	ng_handle_events(50, &r);
34861814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 0);
34961814702SLutz Donnerhacke 
35061814702SLutz Donnerhacke 	/* use broadcast MAC */
35161814702SLutz Donnerhacke 	msg4.eh.ether_shost[3] = 0;
35261814702SLutz Donnerhacke 	memset(msg4.eh.ether_dhost, 0xff, sizeof(msg4.eh.ether_dhost));
35361814702SLutz Donnerhacke 
35461814702SLutz Donnerhacke 	/* now send */
355*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
35661814702SLutz Donnerhacke 	for (i = 1; i <= HOOKS; i++)
35761814702SLutz Donnerhacke 	{
35861814702SLutz Donnerhacke 		char		hook[20];
35961814702SLutz Donnerhacke 
36061814702SLutz Donnerhacke 		snprintf(hook, sizeof(hook), "link%d", i);
36161814702SLutz Donnerhacke 		ng_connect(".", hook, "bridge:", hook);
36261814702SLutz Donnerhacke 		ng_register_data(hook, get_data3);
36361814702SLutz Donnerhacke 
36461814702SLutz Donnerhacke 		msg4.eh.ether_shost[4] = i >> 8;
36561814702SLutz Donnerhacke 		msg4.eh.ether_shost[5] = i & 0xff;
36661814702SLutz Donnerhacke 		ng_errors(PASS);
36761814702SLutz Donnerhacke 		ng_send_data(hook, &msg4, sizeof(msg4));
36861814702SLutz Donnerhacke 		ng_errors(FAIL);
36961814702SLutz Donnerhacke 		if (errno != 0)
37061814702SLutz Donnerhacke 			break;
37161814702SLutz Donnerhacke 		ng_handle_events(50, &r);
37261814702SLutz Donnerhacke 	}
37361814702SLutz Donnerhacke 	ATF_CHECK(r[0] > 100 && r[3] > 100);
37461814702SLutz Donnerhacke 	if (i < HOOKS)
37561814702SLutz Donnerhacke 		atf_tc_expect_fail("netgraph queue full (%d)", i);
37661814702SLutz Donnerhacke 	ATF_CHECK(r[0] == HOOKS);
37761814702SLutz Donnerhacke 	atf_tc_expect_pass();
37861814702SLutz Donnerhacke 
37961814702SLutz Donnerhacke 	ng_shutdown("bridge:");
38061814702SLutz Donnerhacke }
38161814702SLutz Donnerhacke 
38261814702SLutz Donnerhacke ATF_TC(uplink_private);
ATF_TC_HEAD(uplink_private,conf)38361814702SLutz Donnerhacke ATF_TC_HEAD(uplink_private, conf)
38461814702SLutz Donnerhacke {
38561814702SLutz Donnerhacke 	atf_tc_set_md_var(conf, "require.user", "root");
38661814702SLutz Donnerhacke }
38761814702SLutz Donnerhacke 
ATF_TC_BODY(uplink_private,dummy)38861814702SLutz Donnerhacke ATF_TC_BODY(uplink_private, dummy)
38961814702SLutz Donnerhacke {
390*5554abd9SLutz Donnerhacke 	ng_counter_t	r;
39161814702SLutz Donnerhacke 	struct gettable	rm;
39261814702SLutz Donnerhacke 
39361814702SLutz Donnerhacke 	ng_init();
39461814702SLutz Donnerhacke 	ng_errors(PASS);
39561814702SLutz Donnerhacke 	ng_shutdown("bridge:");
39661814702SLutz Donnerhacke 
39761814702SLutz Donnerhacke 	ng_mkpeer(".", "u1", "bridge", "uplink1");
39861814702SLutz Donnerhacke 	if (errno > 0)
39961814702SLutz Donnerhacke 		atf_tc_skip("uplinks are not supported.");
40061814702SLutz Donnerhacke 	ng_errors(FAIL);
40161814702SLutz Donnerhacke 	ng_name("u1", "bridge");
40261814702SLutz Donnerhacke 	ng_register_data("u1", get_data1);
40361814702SLutz Donnerhacke 	ng_connect(".", "u2", "bridge:", "uplink2");
40461814702SLutz Donnerhacke 	ng_register_data("u2", get_data2);
40561814702SLutz Donnerhacke 	ng_connect(".", "l0", "bridge:", "link0");
40661814702SLutz Donnerhacke 	ng_register_data("l0", get_data0);
40761814702SLutz Donnerhacke 	ng_connect(".", "l3", "bridge:", "link3");
40861814702SLutz Donnerhacke 	ng_register_data("l3", get_data3);
40961814702SLutz Donnerhacke 
41061814702SLutz Donnerhacke 	/* unknown unicast 0 from uplink1 */
411*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
41261814702SLutz Donnerhacke 	msg4.eh.ether_shost[5] = 1;
41361814702SLutz Donnerhacke 	ng_send_data("u1", &msg4, sizeof(msg4));
41461814702SLutz Donnerhacke 	ng_handle_events(50, &r);
41561814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 0 && r[1] == 0 && r[2] == 1 && r[3] == 0);
41661814702SLutz Donnerhacke 
41761814702SLutz Donnerhacke 	/* unknown unicast 2 from link0 */
418*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
41961814702SLutz Donnerhacke 	msg4.eh.ether_shost[5] = 0;
42061814702SLutz Donnerhacke 	msg4.eh.ether_dhost[5] = 2;
42161814702SLutz Donnerhacke 	ng_send_data("l0", &msg4, sizeof(msg4));
42261814702SLutz Donnerhacke 	ng_handle_events(50, &r);
42361814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 1 && r[3] == 0);
42461814702SLutz Donnerhacke 
42561814702SLutz Donnerhacke 	/* known unicast 0 from uplink2 */
426*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
42761814702SLutz Donnerhacke 	msg4.eh.ether_shost[5] = 2;
42861814702SLutz Donnerhacke 	msg4.eh.ether_dhost[5] = 0;
42961814702SLutz Donnerhacke 	ng_send_data("u2", &msg4, sizeof(msg4));
43061814702SLutz Donnerhacke 	ng_handle_events(50, &r);
43161814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 0 && r[3] == 0);
43261814702SLutz Donnerhacke 
43361814702SLutz Donnerhacke 	/* known unicast 0 from link3 */
434*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
43561814702SLutz Donnerhacke 	msg4.eh.ether_shost[5] = 3;
43661814702SLutz Donnerhacke 	msg4.eh.ether_dhost[5] = 0;
43761814702SLutz Donnerhacke 	ng_send_data("l3", &msg4, sizeof(msg4));
43861814702SLutz Donnerhacke 	ng_handle_events(50, &r);
43961814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 0 && r[3] == 0);
44061814702SLutz Donnerhacke 
44161814702SLutz Donnerhacke 	/* (un)known unicast 2 from uplink1 */
442*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
44361814702SLutz Donnerhacke 	msg4.eh.ether_shost[5] = 1;
44461814702SLutz Donnerhacke 	msg4.eh.ether_dhost[5] = 2;
44561814702SLutz Donnerhacke 	ng_send_data("u1", &msg4, sizeof(msg4));
44661814702SLutz Donnerhacke 	ng_handle_events(50, &r);
44761814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 0 && r[1] == 0 && r[2] == 1 && r[3] == 0);
44861814702SLutz Donnerhacke 
44961814702SLutz Donnerhacke 	/* (un)known unicast 2 from link0 */
450*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
45161814702SLutz Donnerhacke 	msg4.eh.ether_shost[5] = 0;
45261814702SLutz Donnerhacke 	ng_send_data("l0", &msg4, sizeof(msg4));
45361814702SLutz Donnerhacke 	ng_handle_events(50, &r);
45461814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 1 && r[3] == 0);
45561814702SLutz Donnerhacke 
45661814702SLutz Donnerhacke 	/* unknown multicast 2 from uplink1 */
457*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
45861814702SLutz Donnerhacke 	msg4.eh.ether_shost[5] = 1;
45961814702SLutz Donnerhacke 	msg4.eh.ether_dhost[0] = 0xff;
46061814702SLutz Donnerhacke 	ng_send_data("u1", &msg4, sizeof(msg4));
46161814702SLutz Donnerhacke 	ng_handle_events(50, &r);
46261814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 1 && r[3] == 1);
46361814702SLutz Donnerhacke 
46461814702SLutz Donnerhacke 	/* unknown multicast 2 from link0 */
465*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
46661814702SLutz Donnerhacke 	msg4.eh.ether_shost[5] = 0;
46761814702SLutz Donnerhacke 	ng_send_data("l0", &msg4, sizeof(msg4));
46861814702SLutz Donnerhacke 	ng_handle_events(50, &r);
46961814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 1 && r[3] == 1);
47061814702SLutz Donnerhacke 
47161814702SLutz Donnerhacke 	/* broadcast from uplink1 */
472*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
47361814702SLutz Donnerhacke 	msg4.eh.ether_shost[5] = 1;
47461814702SLutz Donnerhacke 	memset(msg4.eh.ether_dhost, 0xff, sizeof(msg4.eh.ether_dhost));
47561814702SLutz Donnerhacke 	ng_send_data("u1", &msg4, sizeof(msg4));
47661814702SLutz Donnerhacke 	ng_handle_events(50, &r);
47761814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 1 && r[3] == 1);
47861814702SLutz Donnerhacke 
47961814702SLutz Donnerhacke 	/* broadcast from link0 */
480*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
48161814702SLutz Donnerhacke 	msg4.eh.ether_shost[5] = 0;
48261814702SLutz Donnerhacke 	ng_send_data("l0", &msg4, sizeof(msg4));
48361814702SLutz Donnerhacke 	ng_handle_events(50, &r);
48461814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 1 && r[3] == 1);
48561814702SLutz Donnerhacke 
48661814702SLutz Donnerhacke 	/* inspect mac table */
48761814702SLutz Donnerhacke 	ng_register_msg(get_tablesize);
48861814702SLutz Donnerhacke 	rm.tok = ng_send_msg("bridge:", "gettable");
48961814702SLutz Donnerhacke 	rm.cnt = 0;
49061814702SLutz Donnerhacke 	ng_handle_events(50, &rm);
49161814702SLutz Donnerhacke 	ATF_CHECK(rm.cnt == 2);
49261814702SLutz Donnerhacke 
49361814702SLutz Donnerhacke 	ng_shutdown("bridge:");
49461814702SLutz Donnerhacke }
49561814702SLutz Donnerhacke 
49661814702SLutz Donnerhacke ATF_TC(uplink_classic);
ATF_TC_HEAD(uplink_classic,conf)49761814702SLutz Donnerhacke ATF_TC_HEAD(uplink_classic, conf)
49861814702SLutz Donnerhacke {
49961814702SLutz Donnerhacke 	atf_tc_set_md_var(conf, "require.user", "root");
50061814702SLutz Donnerhacke }
50161814702SLutz Donnerhacke 
ATF_TC_BODY(uplink_classic,dummy)50261814702SLutz Donnerhacke ATF_TC_BODY(uplink_classic, dummy)
50361814702SLutz Donnerhacke {
504*5554abd9SLutz Donnerhacke 	ng_counter_t	r;
50561814702SLutz Donnerhacke 	struct gettable	rm;
50661814702SLutz Donnerhacke 
50761814702SLutz Donnerhacke 	ng_init();
50861814702SLutz Donnerhacke 	ng_errors(PASS);
50961814702SLutz Donnerhacke 	ng_shutdown("bridge:");
51061814702SLutz Donnerhacke 
51161814702SLutz Donnerhacke 	ng_mkpeer(".", "l0", "bridge", "link0");
51261814702SLutz Donnerhacke 	if (errno > 0)
51361814702SLutz Donnerhacke 		atf_tc_skip("uplinks are not supported.");
51461814702SLutz Donnerhacke 	ng_errors(FAIL);
51561814702SLutz Donnerhacke 	ng_name("l0", "bridge");
51661814702SLutz Donnerhacke 	ng_register_data("l0", get_data0);
51761814702SLutz Donnerhacke 	ng_connect(".", "u1", "bridge:", "uplink1");
51861814702SLutz Donnerhacke 	ng_register_data("u1", get_data1);
51961814702SLutz Donnerhacke 	ng_connect(".", "u2", "bridge:", "uplink2");
52061814702SLutz Donnerhacke 	ng_register_data("u2", get_data2);
52161814702SLutz Donnerhacke 	ng_connect(".", "l3", "bridge:", "link3");
52261814702SLutz Donnerhacke 	ng_register_data("l3", get_data3);
52361814702SLutz Donnerhacke 
52461814702SLutz Donnerhacke 	/* unknown unicast 0 from uplink1 */
525*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
52661814702SLutz Donnerhacke 	msg4.eh.ether_shost[5] = 1;
52761814702SLutz Donnerhacke 	ng_send_data("u1", &msg4, sizeof(msg4));
52861814702SLutz Donnerhacke 	ng_handle_events(50, &r);
52961814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 1 && r[3] == 1);
53061814702SLutz Donnerhacke 
53161814702SLutz Donnerhacke 	/* unknown unicast 2 from link0 */
532*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
53361814702SLutz Donnerhacke 	msg4.eh.ether_shost[5] = 0;
53461814702SLutz Donnerhacke 	msg4.eh.ether_dhost[5] = 2;
53561814702SLutz Donnerhacke 	ng_send_data("l0", &msg4, sizeof(msg4));
53661814702SLutz Donnerhacke 	ng_handle_events(50, &r);
53761814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 1 && r[3] == 1);
53861814702SLutz Donnerhacke 
53961814702SLutz Donnerhacke 	/* known unicast 0 from uplink2 */
540*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
54161814702SLutz Donnerhacke 	msg4.eh.ether_shost[5] = 2;
54261814702SLutz Donnerhacke 	msg4.eh.ether_dhost[5] = 0;
54361814702SLutz Donnerhacke 	ng_send_data("u2", &msg4, sizeof(msg4));
54461814702SLutz Donnerhacke 	ng_handle_events(50, &r);
54561814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 0 && r[3] == 0);
54661814702SLutz Donnerhacke 
54761814702SLutz Donnerhacke 	/* known unicast 0 from link3 */
548*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
54961814702SLutz Donnerhacke 	msg4.eh.ether_shost[5] = 3;
55061814702SLutz Donnerhacke 	msg4.eh.ether_dhost[5] = 0;
55161814702SLutz Donnerhacke 	ng_send_data("l3", &msg4, sizeof(msg4));
55261814702SLutz Donnerhacke 	ng_handle_events(50, &r);
55361814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 0 && r[3] == 0);
55461814702SLutz Donnerhacke 
55561814702SLutz Donnerhacke 	/* (un)known unicast 2 from uplink1 */
556*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
55761814702SLutz Donnerhacke 	msg4.eh.ether_shost[5] = 1;
55861814702SLutz Donnerhacke 	msg4.eh.ether_dhost[5] = 2;
55961814702SLutz Donnerhacke 	ng_send_data("u1", &msg4, sizeof(msg4));
56061814702SLutz Donnerhacke 	ng_handle_events(50, &r);
56161814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 1 && r[3] == 1);
56261814702SLutz Donnerhacke 
56361814702SLutz Donnerhacke 	/* (un)known unicast 2 from link0 */
564*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
56561814702SLutz Donnerhacke 	msg4.eh.ether_shost[5] = 0;
56661814702SLutz Donnerhacke 	ng_send_data("l0", &msg4, sizeof(msg4));
56761814702SLutz Donnerhacke 	ng_handle_events(50, &r);
56861814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 1 && r[3] == 1);
56961814702SLutz Donnerhacke 
57061814702SLutz Donnerhacke 	/* unknown multicast 2 from uplink1 */
571*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
57261814702SLutz Donnerhacke 	msg4.eh.ether_shost[5] = 1;
57361814702SLutz Donnerhacke 	msg4.eh.ether_dhost[0] = 0xff;
57461814702SLutz Donnerhacke 	ng_send_data("u1", &msg4, sizeof(msg4));
57561814702SLutz Donnerhacke 	ng_handle_events(50, &r);
57661814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 1 && r[3] == 1);
57761814702SLutz Donnerhacke 
57861814702SLutz Donnerhacke 	/* unknown multicast 2 from link0 */
579*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
58061814702SLutz Donnerhacke 	msg4.eh.ether_shost[5] = 0;
58161814702SLutz Donnerhacke 	ng_send_data("l0", &msg4, sizeof(msg4));
58261814702SLutz Donnerhacke 	ng_handle_events(50, &r);
58361814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 1 && r[3] == 1);
58461814702SLutz Donnerhacke 
58561814702SLutz Donnerhacke 	/* broadcast from uplink1 */
586*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
58761814702SLutz Donnerhacke 	msg4.eh.ether_shost[5] = 1;
58861814702SLutz Donnerhacke 	memset(msg4.eh.ether_dhost, 0xff, sizeof(msg4.eh.ether_dhost));
58961814702SLutz Donnerhacke 	ng_send_data("u1", &msg4, sizeof(msg4));
59061814702SLutz Donnerhacke 	ng_handle_events(50, &r);
59161814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 1 && r[3] == 1);
59261814702SLutz Donnerhacke 
59361814702SLutz Donnerhacke 	/* broadcast from link0 */
594*5554abd9SLutz Donnerhacke 	ng_counter_clear(r);
59561814702SLutz Donnerhacke 	msg4.eh.ether_shost[5] = 0;
59661814702SLutz Donnerhacke 	ng_send_data("l0", &msg4, sizeof(msg4));
59761814702SLutz Donnerhacke 	ng_handle_events(50, &r);
59861814702SLutz Donnerhacke 	ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 1 && r[3] == 1);
59961814702SLutz Donnerhacke 
60061814702SLutz Donnerhacke 	/* inspect mac table */
60161814702SLutz Donnerhacke 	ng_register_msg(get_tablesize);
60261814702SLutz Donnerhacke 	rm.tok = ng_send_msg("bridge:", "gettable");
60361814702SLutz Donnerhacke 	rm.cnt = 0;
60461814702SLutz Donnerhacke 	ng_handle_events(50, &rm);
60561814702SLutz Donnerhacke 	ATF_CHECK(rm.cnt == 2);
60661814702SLutz Donnerhacke 
60761814702SLutz Donnerhacke 	ng_shutdown("bridge:");
60861814702SLutz Donnerhacke }
60961814702SLutz Donnerhacke 
ATF_TP_ADD_TCS(bridge)61061814702SLutz Donnerhacke ATF_TP_ADD_TCS(bridge)
61161814702SLutz Donnerhacke {
61261814702SLutz Donnerhacke 	ATF_TP_ADD_TC(bridge, basic);
61361814702SLutz Donnerhacke 	ATF_TP_ADD_TC(bridge, loop);
61461814702SLutz Donnerhacke 	ATF_TP_ADD_TC(bridge, persistence);
61561814702SLutz Donnerhacke 	ATF_TP_ADD_TC(bridge, many_unicasts);
61661814702SLutz Donnerhacke 	ATF_TP_ADD_TC(bridge, many_broadcasts);
61761814702SLutz Donnerhacke 	ATF_TP_ADD_TC(bridge, uplink_private);
61861814702SLutz Donnerhacke 	ATF_TP_ADD_TC(bridge, uplink_classic);
61961814702SLutz Donnerhacke 
62061814702SLutz Donnerhacke 	return atf_no_error();
62161814702SLutz Donnerhacke }
62261814702SLutz Donnerhacke 
62361814702SLutz Donnerhacke static void
get_tablesize(char const * source,struct ng_mesg * msg,void * ctx)62461814702SLutz Donnerhacke get_tablesize(char const *source, struct ng_mesg *msg, void *ctx)
62561814702SLutz Donnerhacke {
62661814702SLutz Donnerhacke 	struct gettable *rm = ctx;
62761814702SLutz Donnerhacke 	struct ng_bridge_host_ary *gt = (void *)msg->data;
62861814702SLutz Donnerhacke 
62961814702SLutz Donnerhacke 	fprintf(stderr, "Response from %s to query %d\n", source, msg->header.token);
63061814702SLutz Donnerhacke 	if (rm->tok == msg->header.token)
63161814702SLutz Donnerhacke 		rm->cnt = gt->numHosts;
63261814702SLutz Donnerhacke }
633