Changeset View
Changeset View
Standalone View
Standalone View
tests/sys/netgraph/bridge.c
- This file was added.
/* | |||||
* SPDX-License-Identifier: BSD-3-Clause | |||||
* | |||||
* Copyright 2021 Lutz Donnerhacke | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | |||||
* modification, are permitted provided that the following conditions | |||||
* are met: | |||||
* | |||||
* 1. Redistributions of source code must retain the above copyright | |||||
* notice, this list of conditions and the following disclaimer. | |||||
* 2. Redistributions in binary form must reproduce the above | |||||
* copyright notice, this list of conditions and the following | |||||
* disclaimer in the documentation and/or other materials provided | |||||
* with the distribution. | |||||
* 3. Neither the name of the copyright holder nor the names of its | |||||
* contributors may be used to endorse or promote products derived | |||||
* from this software without specific prior written permission. | |||||
* | |||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND | |||||
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, | |||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS | |||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED | |||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON | |||||
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR | |||||
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF | |||||
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||||
* SUCH DAMAGE. | |||||
*/ | |||||
#include <atf-c.h> | |||||
#include <errno.h> | |||||
#include <stdio.h> | |||||
#include <net/ethernet.h> | |||||
#include <netinet/in.h> | |||||
#include <netinet/ip.h> | |||||
#include <netinet/ip6.h> | |||||
#include "util.h" | |||||
static void get_data0(void *data, size_t len, void *ctx); | |||||
static void get_data1(void *data, size_t len, void *ctx); | |||||
static void get_data2(void *data, size_t len, void *ctx); | |||||
static void get_data3(void *data, size_t len, void *ctx); | |||||
struct frame4 { | |||||
struct ether_header eh; | |||||
struct ip ip; | |||||
char data[64]; | |||||
}; | |||||
struct frame6 { | |||||
struct ether_header eh; | |||||
struct ip6_hdr ip; | |||||
char data[64]; | |||||
}; | |||||
static struct frame4 msg4 = { | |||||
.ip.ip_v = 4, | |||||
.ip.ip_hl = 5, | |||||
.ip.ip_ttl = 1, | |||||
.ip.ip_p = 254, | |||||
.ip.ip_src = { htonl(0x0a00dead) }, | |||||
.ip.ip_dst = { htonl(0x0a00beef) }, | |||||
.ip.ip_len = 32, | |||||
.eh.ether_type = ETHERTYPE_IP, | |||||
.eh.ether_shost = { 2,4,6 }, | |||||
.eh.ether_dhost = { 2,4,6 }, | |||||
}; | |||||
ATF_TC(basic); | |||||
ATF_TC_HEAD(basic, conf) | |||||
{ | |||||
atf_tc_set_md_var(conf, "require.user", "root"); | |||||
} | |||||
ATF_TC_BODY(basic, dummy) | |||||
{ | |||||
int r[4]; | |||||
ng_init(); | |||||
ng_errors(PASS); | |||||
ng_shutdown("bridge:"); | |||||
ng_errors(FAIL); | |||||
ng_mkpeer(".", "a", "bridge", "link0"); | |||||
ng_name("a", "bridge"); | |||||
ng_connect(".", "b", "bridge:", "link1"); | |||||
ng_connect(".", "c", "bridge:", "link2"); | |||||
/* do not bounce back */ | |||||
ng_register_data("a", get_data0); | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[5] = 1; | |||||
ng_send_data("a", &msg4, sizeof(msg4)); | |||||
ng_handle_events(50, &r); | |||||
ATF_CHECK(r[0] == 0); | |||||
/* send to others */ | |||||
ng_register_data("b", get_data1); | |||||
ng_register_data("c", get_data2); | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[5] = 1; | |||||
ng_send_data("a", &msg4, sizeof(msg4)); | |||||
ng_handle_events(50, &r); | |||||
ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 1); | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[5] = 2; | |||||
ng_send_data("b", &msg4, sizeof(msg4)); | |||||
ng_handle_events(50, &r); | |||||
ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 1); | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[5] = 3; | |||||
ng_send_data("c", &msg4, sizeof(msg4)); | |||||
ng_handle_events(50, &r); | |||||
ATF_CHECK(r[0] == 1 && r[1] == 1 && r[2] == 0); | |||||
/* send to learned unicast */ | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[5] = 1; | |||||
msg4.eh.ether_dhost[5] = 3; | |||||
ng_send_data("a", &msg4, sizeof(msg4)); | |||||
ng_handle_events(50, &r); | |||||
ATF_CHECK(r[0] == 0 && r[1] == 0 && r[2] == 1); | |||||
/* remove a link */ | |||||
ng_rmhook(".", "b"); | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[5] = 1; | |||||
msg4.eh.ether_dhost[5] = 0; | |||||
ng_send_data("a", &msg4, sizeof(msg4)); | |||||
ng_handle_events(50, &r); | |||||
ATF_CHECK(r[0] == 0 && r[1] == 0 && r[2] == 1); | |||||
ng_shutdown("bridge:"); | |||||
} | |||||
ATF_TC(persistence); | |||||
ATF_TC_HEAD(persistence, conf) | |||||
{ | |||||
atf_tc_set_md_var(conf, "require.user", "root"); | |||||
} | |||||
ATF_TC_BODY(persistence, dummy) | |||||
{ | |||||
ng_init(); | |||||
ng_errors(PASS); | |||||
ng_shutdown("bridge:"); | |||||
ng_errors(FAIL); | |||||
ng_mkpeer(".", "a", "bridge", "link0"); | |||||
ng_name("a", "bridge"); | |||||
ng_send_msg("bridge:", "setpersistent"); | |||||
ng_rmhook(".", "a"); | |||||
ng_shutdown("bridge:"); | |||||
} | |||||
ATF_TC(loop); | |||||
ATF_TC_HEAD(loop, conf) | |||||
{ | |||||
atf_tc_set_md_var(conf, "require.user", "root"); | |||||
} | |||||
ATF_TC_BODY(loop, dummy) | |||||
{ | |||||
int r[4], i; | |||||
ng_init(); | |||||
ng_errors(PASS); | |||||
ng_shutdown("bridge1:"); | |||||
ng_shutdown("bridge2:"); | |||||
ng_errors(FAIL); | |||||
ng_mkpeer(".", "a", "bridge", "link0"); | |||||
ng_name("a", "bridge1"); | |||||
ng_mkpeer(".", "b", "bridge", "link1"); | |||||
ng_name("b", "bridge2"); | |||||
ng_register_data("a", get_data0); | |||||
ng_register_data("b", get_data1); | |||||
/* | |||||
* Open loop | |||||
* | |||||
* /-- bridge1 | |||||
* . < | | |||||
* \-- bridge2 | |||||
*/ | |||||
ng_connect("bridge1:", "link11", "bridge2:", "link11"); | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[5] = 1; | |||||
ng_send_data("a", &msg4, sizeof(msg4)); | |||||
ng_handle_events(50, &r); | |||||
ATF_CHECK(r[0] == 0 && r[1] == 1); | |||||
/* | |||||
* Closed loop, DANGEROUS! | |||||
* | |||||
* /-- bridge1 -\ | |||||
* . < | | | |||||
* \-- bridge2 -/ | |||||
*/ | |||||
ng_connect("bridge1:", "link12", "bridge2:", "link12"); | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[5] = 1; | |||||
ng_errors(PASS); | |||||
ng_send_data("a", &msg4, sizeof(msg4)); | |||||
ATF_CHECK_ERRNO(ELOOP, errno != 0); /* loop might be detected */ | |||||
ng_errors(FAIL); | |||||
for(i = 0; i < 10; i++) /* don't run forever */ | |||||
if (!ng_handle_event(50, &r)) | |||||
break; | |||||
ATF_CHECK(r[0] == 0 && r[1] == 1); | |||||
ng_shutdown("bridge1:"); | |||||
ng_shutdown("bridge2:"); | |||||
} | |||||
ATF_TC(many_unicasts); | |||||
ATF_TC_HEAD(many_unicasts, conf) | |||||
{ | |||||
atf_tc_set_md_var(conf, "require.user", "root"); | |||||
} | |||||
ATF_TC_BODY(many_unicasts, dummy) | |||||
{ | |||||
int r[4], i; | |||||
const int HOOKS = 1000; | |||||
ng_init(); | |||||
ng_errors(PASS); | |||||
ng_shutdown("bridge:"); | |||||
ng_errors(FAIL); | |||||
ng_mkpeer(".", "a", "bridge", "link0"); | |||||
ng_name("a", "bridge"); | |||||
ng_register_data("a", get_data0); | |||||
/* learn MAC */ | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[3] = 0xff; | |||||
ng_send_data("a", &msg4, sizeof(msg4)); | |||||
ng_handle_events(50, &r); | |||||
ATF_CHECK(r[0] == 0); | |||||
/* use learned MAC as destination */ | |||||
msg4.eh.ether_shost[3] = 0; | |||||
msg4.eh.ether_dhost[3] = 0xff; | |||||
/* now send */ | |||||
bzero(r, sizeof(r)); | |||||
for (i = 1; i <= HOOKS; i++) { | |||||
char hook[20]; | |||||
snprintf(hook, sizeof(hook), "link%d", i); | |||||
ng_connect(".", hook, "bridge:", hook); | |||||
ng_register_data(hook, get_data2); | |||||
msg4.eh.ether_shost[4] = i >> 8; | |||||
msg4.eh.ether_shost[5] = i & 0xff; | |||||
ng_errors(PASS); | |||||
ng_send_data(hook, &msg4, sizeof(msg4)); | |||||
ng_errors(FAIL); | |||||
if (errno != 0) | |||||
break; | |||||
ng_handle_events(50, &r); | |||||
} | |||||
ATF_CHECK(r[0] == HOOKS && r[2] == 0); | |||||
ng_shutdown("bridge:"); | |||||
} | |||||
ATF_TC(many_broadcasts); | |||||
ATF_TC_HEAD(many_broadcasts, conf) | |||||
{ | |||||
atf_tc_set_md_var(conf, "require.user", "root"); | |||||
} | |||||
ATF_TC_BODY(many_broadcasts, dummy) | |||||
{ | |||||
int r[4], i; | |||||
const int HOOKS = 1000; | |||||
ng_init(); | |||||
ng_errors(PASS); | |||||
ng_shutdown("bridge:"); | |||||
ng_errors(FAIL); | |||||
ng_mkpeer(".", "a", "bridge", "link0"); | |||||
ng_name("a", "bridge"); | |||||
ng_register_data("a", get_data0); | |||||
/* learn MAC */ | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[3] = 0xff; | |||||
ng_send_data("a", &msg4, sizeof(msg4)); | |||||
ng_handle_events(50, &r); | |||||
ATF_CHECK(r[0] == 0); | |||||
/* use broadcast MAC */ | |||||
msg4.eh.ether_shost[3] = 0; | |||||
memset(msg4.eh.ether_dhost, 0xff, sizeof(msg4.eh.ether_dhost)); | |||||
/* now send */ | |||||
bzero(r, sizeof(r)); | |||||
for (i = 1; i <= HOOKS; i++) { | |||||
char hook[20]; | |||||
snprintf(hook, sizeof(hook), "link%d", i); | |||||
ng_connect(".", hook, "bridge:", hook); | |||||
ng_register_data(hook, get_data3); | |||||
msg4.eh.ether_shost[4] = i >> 8; | |||||
msg4.eh.ether_shost[5] = i & 0xff; | |||||
ng_errors(PASS); | |||||
ng_send_data(hook, &msg4, sizeof(msg4)); | |||||
ng_errors(FAIL); | |||||
if (errno != 0) | |||||
break; | |||||
ng_handle_events(50, &r); | |||||
} | |||||
ATF_CHECK(r[0] > 100 && r[3] > 100); | |||||
atf_tc_expect_fail("netgraph queue full (%d)", i); | |||||
ATF_CHECK(r[0] == HOOKS); | |||||
atf_tc_expect_pass(); | |||||
ng_shutdown("bridge:"); | |||||
} | |||||
ATF_TC(uplink_private); | |||||
ATF_TC_HEAD(uplink_private, conf) | |||||
{ | |||||
atf_tc_set_md_var(conf, "require.user", "root"); | |||||
} | |||||
ATF_TC_BODY(uplink_private, dummy) | |||||
{ | |||||
int r[4]; | |||||
ng_init(); | |||||
ng_errors(PASS); | |||||
ng_shutdown("bridge:"); | |||||
ng_mkpeer(".", "u1", "bridge", "uplink1"); | |||||
if(errno > 0) | |||||
atf_tc_skip("uplinks are not supported."); | |||||
ng_errors(FAIL); | |||||
ng_name("u1", "bridge"); | |||||
ng_register_data("u1", get_data1); | |||||
ng_connect(".", "u2", "bridge:", "uplink2"); | |||||
ng_register_data("u2", get_data2); | |||||
ng_connect(".", "l0", "bridge:", "link0"); | |||||
ng_register_data("l0", get_data0); | |||||
ng_connect(".", "l3", "bridge:", "link3"); | |||||
ng_register_data("l3", get_data3); | |||||
/* unknown unicast 0 from uplink1 */ | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[5] = 1; | |||||
ng_send_data("u1", &msg4, sizeof(msg4)); | |||||
ng_handle_events(50, &r); | |||||
ATF_CHECK(r[0] == 0 && r[1] == 0 && r[2] == 1 && r[3] == 0); | |||||
/* unknown unicast 2 from link0 */ | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[5] = 0; | |||||
msg4.eh.ether_dhost[5] = 2; | |||||
ng_send_data("l0", &msg4, sizeof(msg4)); | |||||
ng_handle_events(50, &r); | |||||
ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 1 && r[3] == 0); | |||||
/* known unicast 0 from uplink2 */ | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[5] = 2; | |||||
msg4.eh.ether_dhost[5] = 0; | |||||
ng_send_data("u2", &msg4, sizeof(msg4)); | |||||
ng_handle_events(50, &r); | |||||
ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 0 && r[3] == 0); | |||||
/* known unicast 0 from link3 */ | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[5] = 3; | |||||
msg4.eh.ether_dhost[5] = 0; | |||||
ng_send_data("l3", &msg4, sizeof(msg4)); | |||||
ng_handle_events(50, &r); | |||||
ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 0 && r[3] == 0); | |||||
/* (un)known unicast 2 from uplink1 */ | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[5] = 1; | |||||
msg4.eh.ether_dhost[5] = 2; | |||||
ng_send_data("u1", &msg4, sizeof(msg4)); | |||||
ng_handle_events(50, &r); | |||||
ATF_CHECK(r[0] == 0 && r[1] == 0 && r[2] == 1 && r[3] == 0); | |||||
/* (un)known unicast 2 from link0 */ | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[5] = 0; | |||||
ng_send_data("l0", &msg4, sizeof(msg4)); | |||||
ng_handle_events(50, &r); | |||||
ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 1 && r[3] == 0); | |||||
/* unknown multicast 2 from uplink1 */ | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[5] = 1; | |||||
msg4.eh.ether_dhost[0] = 0xff; | |||||
ng_send_data("u1", &msg4, sizeof(msg4)); | |||||
ng_handle_events(50, &r); | |||||
ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 1 && r[3] == 1); | |||||
/* unknown multicast 2 from link0 */ | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[5] = 0; | |||||
ng_send_data("l0", &msg4, sizeof(msg4)); | |||||
ng_handle_events(50, &r); | |||||
ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 1 && r[3] == 1); | |||||
/* broadcast from uplink1 */ | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[5] = 1; | |||||
memset(msg4.eh.ether_dhost, 0xff, sizeof(msg4.eh.ether_dhost)); | |||||
ng_send_data("u1", &msg4, sizeof(msg4)); | |||||
ng_handle_events(50, &r); | |||||
ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 1 && r[3] == 1); | |||||
/* broadcast from link0 */ | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[5] = 0; | |||||
ng_send_data("l0", &msg4, sizeof(msg4)); | |||||
ng_handle_events(50, &r); | |||||
ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 1 && r[3] == 1); | |||||
ng_shutdown("bridge:"); | |||||
} | |||||
ATF_TC(uplink_classic); | |||||
ATF_TC_HEAD(uplink_classic, conf) | |||||
{ | |||||
atf_tc_set_md_var(conf, "require.user", "root"); | |||||
} | |||||
ATF_TC_BODY(uplink_classic, dummy) | |||||
{ | |||||
int r[4]; | |||||
ng_init(); | |||||
ng_errors(PASS); | |||||
ng_shutdown("bridge:"); | |||||
ng_mkpeer(".", "l0", "bridge", "link0"); | |||||
if(errno > 0) | |||||
atf_tc_skip("uplinks are not supported."); | |||||
ng_errors(FAIL); | |||||
ng_name("l0", "bridge"); | |||||
ng_register_data("l0", get_data0); | |||||
ng_connect(".", "u1", "bridge:", "uplink1"); | |||||
ng_register_data("u1", get_data1); | |||||
ng_connect(".", "u2", "bridge:", "uplink2"); | |||||
ng_register_data("u2", get_data2); | |||||
ng_connect(".", "l3", "bridge:", "link3"); | |||||
ng_register_data("l3", get_data3); | |||||
/* unknown unicast 0 from uplink1 */ | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[5] = 1; | |||||
ng_send_data("u1", &msg4, sizeof(msg4)); | |||||
ng_handle_events(50, &r); | |||||
ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 1 && r[3] == 1); | |||||
/* unknown unicast 2 from link0 */ | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[5] = 0; | |||||
msg4.eh.ether_dhost[5] = 2; | |||||
ng_send_data("l0", &msg4, sizeof(msg4)); | |||||
ng_handle_events(50, &r); | |||||
ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 1 && r[3] == 1); | |||||
/* known unicast 0 from uplink2 */ | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[5] = 2; | |||||
msg4.eh.ether_dhost[5] = 0; | |||||
ng_send_data("u2", &msg4, sizeof(msg4)); | |||||
ng_handle_events(50, &r); | |||||
ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 0 && r[3] == 0); | |||||
/* known unicast 0 from link3 */ | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[5] = 3; | |||||
msg4.eh.ether_dhost[5] = 0; | |||||
ng_send_data("l3", &msg4, sizeof(msg4)); | |||||
ng_handle_events(50, &r); | |||||
ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 0 && r[3] == 0); | |||||
/* (un)known unicast 2 from uplink1 */ | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[5] = 1; | |||||
msg4.eh.ether_dhost[5] = 2; | |||||
ng_send_data("u1", &msg4, sizeof(msg4)); | |||||
ng_handle_events(50, &r); | |||||
ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 1 && r[3] == 1); | |||||
/* (un)known unicast 2 from link0 */ | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[5] = 0; | |||||
ng_send_data("l0", &msg4, sizeof(msg4)); | |||||
ng_handle_events(50, &r); | |||||
ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 1 && r[3] == 1); | |||||
/* unknown multicast 2 from uplink1 */ | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[5] = 1; | |||||
msg4.eh.ether_dhost[0] = 0xff; | |||||
ng_send_data("u1", &msg4, sizeof(msg4)); | |||||
ng_handle_events(50, &r); | |||||
ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 1 && r[3] == 1); | |||||
/* unknown multicast 2 from link0 */ | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[5] = 0; | |||||
ng_send_data("l0", &msg4, sizeof(msg4)); | |||||
ng_handle_events(50, &r); | |||||
ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 1 && r[3] == 1); | |||||
/* broadcast from uplink1 */ | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[5] = 1; | |||||
memset(msg4.eh.ether_dhost, 0xff, sizeof(msg4.eh.ether_dhost)); | |||||
ng_send_data("u1", &msg4, sizeof(msg4)); | |||||
ng_handle_events(50, &r); | |||||
ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 1 && r[3] == 1); | |||||
/* broadcast from link0 */ | |||||
bzero(r, sizeof(r)); | |||||
msg4.eh.ether_shost[5] = 0; | |||||
ng_send_data("l0", &msg4, sizeof(msg4)); | |||||
ng_handle_events(50, &r); | |||||
ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 1 && r[3] == 1); | |||||
ng_shutdown("bridge:"); | |||||
} | |||||
ATF_TP_ADD_TCS(bridge) | |||||
{ | |||||
ATF_TP_ADD_TC(bridge, basic); | |||||
ATF_TP_ADD_TC(bridge, loop); | |||||
ATF_TP_ADD_TC(bridge, persistence); | |||||
ATF_TP_ADD_TC(bridge, many_unicasts); | |||||
ATF_TP_ADD_TC(bridge, many_broadcasts); | |||||
ATF_TP_ADD_TC(bridge, uplink_private); | |||||
ATF_TP_ADD_TC(bridge, uplink_classic); | |||||
return atf_no_error(); | |||||
} | |||||
static inline void | |||||
_get_data(void *data, size_t len, void *ctx, int i) | |||||
{ | |||||
int *cnt = ctx; | |||||
(void)data; | |||||
fprintf(stderr, "[%d] Got %zu bytes of data.\n", i, len); | |||||
cnt[i]++; | |||||
} | |||||
#define GD(x) static void \ | |||||
get_data##x(void *data, size_t len, void *ctx) {\ | |||||
_get_data(data, len, ctx, x); \ | |||||
} | |||||
GD(0) | |||||
GD(1) | |||||
GD(2) | |||||
GD(3) |