tests/netgraph: Tests for ng_vlan_rotate
Test functionality of ng_vlan_rotate(4): - Rotate 1 to 9 stagged vlans in any possible direction and length - Rotate random combinations of ethertypes (8100, 88a8, 9100) - Automatic reverse rotating for backward data flow - Test too many and to few vlans Reviewed by: kp (earlier version) MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D30670
This commit is contained in:
parent
7863faa78a
commit
6b08e68be1
@ -10,13 +10,15 @@ TAP_TESTS_SH+= ng_macfilter_test
|
||||
TEST_METADATA.ng_macfilter_test+= required_user="root"
|
||||
TEST_METADATA.ng_macfilter_test+= required_programs="perl"
|
||||
|
||||
ATF_TESTS_C+= basic \
|
||||
bridge \
|
||||
hub \
|
||||
ATF_TESTS_C+= basic \
|
||||
bridge \
|
||||
hub \
|
||||
vlan_rotate \
|
||||
|
||||
SRCS.basic= basic.c util.c
|
||||
SRCS.bridge= bridge.c util.c
|
||||
SRCS.hub= hub.c util.c
|
||||
SRCS.vlan_rotate=vlan_rotate.c util.c
|
||||
|
||||
LIBADD+= netgraph
|
||||
|
||||
|
335
tests/sys/netgraph/vlan_rotate.c
Normal file
335
tests/sys/netgraph/vlan_rotate.c
Normal file
@ -0,0 +1,335 @@
|
||||
/*-
|
||||
* 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "util.h"
|
||||
#include <netgraph/ng_bridge.h>
|
||||
|
||||
struct vlan
|
||||
{
|
||||
uint16_t proto;
|
||||
uint16_t tag;
|
||||
} __packed;
|
||||
|
||||
struct frame
|
||||
{
|
||||
u_char dst[ETHER_ADDR_LEN];
|
||||
u_char src[ETHER_ADDR_LEN];
|
||||
struct vlan vlan[10];
|
||||
} __packed;
|
||||
|
||||
static struct frame msg = {
|
||||
.src = {2, 4, 6, 1, 3, 5},
|
||||
.dst = {2, 4, 6, 1, 3, 7},
|
||||
.vlan[0] = {htons(ETHERTYPE_VLAN), htons(EVL_MAKETAG(1, 0, 0))},
|
||||
.vlan[1] = {htons(ETHERTYPE_VLAN), htons(EVL_MAKETAG(2, 0, 0))},
|
||||
.vlan[2] = {htons(ETHERTYPE_VLAN), htons(EVL_MAKETAG(3, 0, 0))},
|
||||
.vlan[3] = {htons(ETHERTYPE_VLAN), htons(EVL_MAKETAG(4, 0, 0))},
|
||||
.vlan[4] = {htons(ETHERTYPE_VLAN), htons(EVL_MAKETAG(5, 0, 0))},
|
||||
.vlan[5] = {htons(ETHERTYPE_VLAN), htons(EVL_MAKETAG(6, 0, 0))},
|
||||
.vlan[6] = {htons(ETHERTYPE_VLAN), htons(EVL_MAKETAG(7, 0, 0))},
|
||||
.vlan[7] = {htons(ETHERTYPE_VLAN), htons(EVL_MAKETAG(8, 0, 0))},
|
||||
.vlan[8] = {htons(ETHERTYPE_VLAN), htons(EVL_MAKETAG(9, 0, 0))},
|
||||
.vlan[9] = {0}
|
||||
};
|
||||
|
||||
static void _basic(int);
|
||||
static void get_vlan(void *data, size_t len, void *ctx);
|
||||
|
||||
static void
|
||||
get_vlan(void *data, size_t len, void *ctx)
|
||||
{
|
||||
int *v = ctx, i;
|
||||
struct frame *f = data;
|
||||
|
||||
(void)len;
|
||||
for (i = 0; i < 10; i++)
|
||||
v[i] = EVL_VLANOFTAG(ntohs(f->vlan[i].tag));
|
||||
}
|
||||
|
||||
static void
|
||||
_basic(int direction)
|
||||
{
|
||||
int r[10];
|
||||
int i, rot, len;
|
||||
|
||||
ng_init();
|
||||
ng_errors(PASS);
|
||||
ng_shutdown("vr:");
|
||||
ng_errors(FAIL);
|
||||
|
||||
ng_mkpeer(".", "a", "vlan_rotate", direction > 0 ? "original" : "ordered");
|
||||
ng_name("a", "vr");
|
||||
ng_connect(".", "b", "vr:", direction > 0 ? "ordered" : "original");
|
||||
ng_register_data("b", get_vlan);
|
||||
|
||||
for (len = 9; len > 0; len--)
|
||||
{
|
||||
/* reduce the number of vlans */
|
||||
msg.vlan[len].proto = htons(ETHERTYPE_IP);
|
||||
|
||||
for (rot = -len + 1; rot < len; rot++)
|
||||
{
|
||||
char cmd[40];
|
||||
|
||||
/* set rotation offset */
|
||||
snprintf(cmd, sizeof(cmd), "setconf { min=0 max=9 rot=%d }", rot);
|
||||
ng_send_msg("vr:", cmd);
|
||||
|
||||
ng_send_data("a", &msg, sizeof(msg));
|
||||
ng_handle_events(50, &r);
|
||||
|
||||
/* check rotation */
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
int expect = (2 * len + i - direction * rot) % len + 1;
|
||||
int vlan = r[i];
|
||||
|
||||
ATF_CHECK_MSG(vlan == expect,
|
||||
"len=%d rot=%d i=%d -> vlan=%d, expect=%d",
|
||||
len, rot, i, r[i], expect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ng_shutdown("vr:");
|
||||
}
|
||||
|
||||
ATF_TC(basic);
|
||||
ATF_TC_HEAD(basic, conf)
|
||||
{
|
||||
atf_tc_set_md_var(conf, "require.user", "root");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(basic, dummy)
|
||||
{
|
||||
_basic(1);
|
||||
}
|
||||
|
||||
ATF_TC(reverse);
|
||||
ATF_TC_HEAD(reverse, conf)
|
||||
{
|
||||
atf_tc_set_md_var(conf, "require.user", "root");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(reverse, dummy)
|
||||
{
|
||||
_basic(-1);
|
||||
}
|
||||
|
||||
static void _ethertype(int);
|
||||
static void get_ethertype(void *data, size_t len, void *ctx);
|
||||
|
||||
static void
|
||||
get_ethertype(void *data, size_t len, void *ctx)
|
||||
{
|
||||
int *v = ctx, i;
|
||||
struct frame *f = data;
|
||||
|
||||
(void)len;
|
||||
for (i = 0; i < 10; i++)
|
||||
v[i] = ntohs(f->vlan[i].proto);
|
||||
}
|
||||
|
||||
static void
|
||||
_ethertype(int direction)
|
||||
{
|
||||
int r[10];
|
||||
int i, rounds = 20;
|
||||
|
||||
ng_init();
|
||||
ng_errors(PASS);
|
||||
ng_shutdown("vr:");
|
||||
ng_errors(FAIL);
|
||||
|
||||
ng_mkpeer(".", "a", "vlan_rotate", direction > 0 ? "original" : "ordered");
|
||||
ng_name("a", "vr");
|
||||
ng_connect(".", "b", "vr:", direction > 0 ? "ordered" : "original");
|
||||
ng_register_data("b", get_ethertype);
|
||||
|
||||
while (rounds-- > 0)
|
||||
{
|
||||
char cmd[40];
|
||||
int len = 9;
|
||||
int rot = rand() % (2 * len - 1) - len + 1;
|
||||
int vlan[10];
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
switch (rand() % 3)
|
||||
{
|
||||
default:
|
||||
msg.vlan[i].proto = htons(ETHERTYPE_VLAN);
|
||||
break;
|
||||
case 1:
|
||||
msg.vlan[i].proto = htons(ETHERTYPE_QINQ);
|
||||
break;
|
||||
case 2:
|
||||
msg.vlan[i].proto = htons(ETHERTYPE_8021Q9100);
|
||||
break;
|
||||
}
|
||||
}
|
||||
msg.vlan[i].proto = htons(ETHERTYPE_IP);
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
vlan[i] = msg.vlan[i].proto;
|
||||
|
||||
snprintf(cmd, sizeof(cmd), "setconf { min=0 max=9 rot=%d }", rot);
|
||||
ng_send_msg("vr:", cmd);
|
||||
|
||||
bzero(r, sizeof(r));
|
||||
ng_send_data("a", &msg, sizeof(msg));
|
||||
ng_handle_events(50, &r);
|
||||
|
||||
/* check rotation */
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
int expect = (2 * len + i - direction * rot) % len;
|
||||
|
||||
ATF_CHECK_MSG(r[i] == ntohs(vlan[expect]),
|
||||
"len=%d rot=%d i=%d -> vlan=%04x, expect(%d)=%04x",
|
||||
len, rot, i, ntohs(r[i]), expect, vlan[expect]);
|
||||
}
|
||||
}
|
||||
|
||||
ng_shutdown("vr:");
|
||||
}
|
||||
|
||||
ATF_TC(ethertype);
|
||||
ATF_TC_HEAD(ethertype, conf)
|
||||
{
|
||||
atf_tc_set_md_var(conf, "require.user", "root");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(ethertype, dummy)
|
||||
{
|
||||
_ethertype(1);
|
||||
}
|
||||
|
||||
ATF_TC(typeether);
|
||||
ATF_TC_HEAD(typeether, conf)
|
||||
{
|
||||
atf_tc_set_md_var(conf, "require.user", "root");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(typeether, dummy)
|
||||
{
|
||||
_ethertype(-1);
|
||||
}
|
||||
|
||||
ATF_TC(minmax);
|
||||
ATF_TC_HEAD(minmax, conf)
|
||||
{
|
||||
atf_tc_set_md_var(conf, "require.user", "root");
|
||||
}
|
||||
|
||||
ATF_TC_BODY(minmax, dummy)
|
||||
{
|
||||
ng_counter_t r;
|
||||
int len;
|
||||
|
||||
ng_init();
|
||||
ng_errors(PASS);
|
||||
ng_shutdown("vr:");
|
||||
ng_errors(FAIL);
|
||||
|
||||
ng_mkpeer(".", "a", "vlan_rotate", "original");
|
||||
ng_name("a", "vr");
|
||||
ng_connect(".", "b", "vr:", "ordered");
|
||||
ng_connect(".", "c", "vr:", "excessive");
|
||||
ng_connect(".", "d", "vr:", "incomplete");
|
||||
ng_register_data("a", get_data0);
|
||||
ng_register_data("b", get_data1);
|
||||
ng_register_data("c", get_data2);
|
||||
ng_register_data("d", get_data3);
|
||||
|
||||
ng_send_msg("vr:", "setconf { min=3 max=7 rot=0 }");
|
||||
for (len = 9; len > 0; len--)
|
||||
{
|
||||
/* reduce the number of vlans */
|
||||
msg.vlan[len].proto = htons(ETHERTYPE_IP);
|
||||
|
||||
ng_counter_clear(r);
|
||||
ng_send_data("a", &msg, sizeof(msg));
|
||||
ng_handle_events(50, &r);
|
||||
if (len < 3)
|
||||
ATF_CHECK(r[0] == 0 && r[1] == 0 && r[2] == 0 && r[3] == 1);
|
||||
else if (len > 7)
|
||||
ATF_CHECK(r[0] == 0 && r[1] == 0 && r[2] == 1 && r[3] == 0);
|
||||
else
|
||||
ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 0 && r[3] == 0);
|
||||
|
||||
ng_counter_clear(r);
|
||||
ng_send_data("b", &msg, sizeof(msg));
|
||||
ng_handle_events(50, &r);
|
||||
if (len < 3)
|
||||
ATF_CHECK(r[0] == 0 && r[1] == 0 && r[2] == 0 && r[3] == 1);
|
||||
else if (len > 7)
|
||||
ATF_CHECK(r[0] == 0 && r[1] == 0 && r[2] == 1 && r[3] == 0);
|
||||
else
|
||||
ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 0 && r[3] == 0);
|
||||
|
||||
ng_counter_clear(r);
|
||||
ng_send_data("c", &msg, sizeof(msg));
|
||||
ng_handle_events(50, &r);
|
||||
ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 0 && r[3] == 0);
|
||||
|
||||
ng_counter_clear(r);
|
||||
ng_send_data("d", &msg, sizeof(msg));
|
||||
ng_handle_events(50, &r);
|
||||
ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 0 && r[3] == 0);
|
||||
}
|
||||
|
||||
ng_shutdown("vr:");
|
||||
}
|
||||
|
||||
ATF_TP_ADD_TCS(vlan_rotate)
|
||||
{
|
||||
/* Use "dd if=/dev/random bs=2 count=1 | od -x" to reproduce */
|
||||
srand(0xb93b);
|
||||
|
||||
ATF_TP_ADD_TC(vlan_rotate, basic);
|
||||
ATF_TP_ADD_TC(vlan_rotate, ethertype);
|
||||
ATF_TP_ADD_TC(vlan_rotate, reverse);
|
||||
ATF_TP_ADD_TC(vlan_rotate, typeether);
|
||||
ATF_TP_ADD_TC(vlan_rotate, minmax);
|
||||
|
||||
return atf_no_error();
|
||||
}
|
Loading…
Reference in New Issue
Block a user