2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright 2021 Lutz Donnerhacke
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials provided
15 * with the distribution.
16 * 3. Neither the name of the copyright holder nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
21 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
22 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
29 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
30 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
31 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 #include <net/ethernet.h>
40 #include <netinet/in.h>
43 #include <netgraph/ng_bridge.h>
53 u_char dst[ETHER_ADDR_LEN];
54 u_char src[ETHER_ADDR_LEN];
58 static struct frame msg = {
59 .src = {2, 4, 6, 1, 3, 5},
60 .dst = {2, 4, 6, 1, 3, 7},
61 .vlan[0] = {htons(ETHERTYPE_VLAN), htons(EVL_MAKETAG(1, 0, 0))},
62 .vlan[1] = {htons(ETHERTYPE_VLAN), htons(EVL_MAKETAG(2, 0, 0))},
63 .vlan[2] = {htons(ETHERTYPE_VLAN), htons(EVL_MAKETAG(3, 0, 0))},
64 .vlan[3] = {htons(ETHERTYPE_VLAN), htons(EVL_MAKETAG(4, 0, 0))},
65 .vlan[4] = {htons(ETHERTYPE_VLAN), htons(EVL_MAKETAG(5, 0, 0))},
66 .vlan[5] = {htons(ETHERTYPE_VLAN), htons(EVL_MAKETAG(6, 0, 0))},
67 .vlan[6] = {htons(ETHERTYPE_VLAN), htons(EVL_MAKETAG(7, 0, 0))},
68 .vlan[7] = {htons(ETHERTYPE_VLAN), htons(EVL_MAKETAG(8, 0, 0))},
69 .vlan[8] = {htons(ETHERTYPE_VLAN), htons(EVL_MAKETAG(9, 0, 0))},
73 static void _basic(int);
74 static void get_vlan(void *data, size_t len, void *ctx);
77 get_vlan(void *data, size_t len, void *ctx)
80 struct frame *f = data;
83 for (i = 0; i < 10; i++)
84 v[i] = EVL_VLANOFTAG(ntohs(f->vlan[i].tag));
98 ng_mkpeer(".", "a", "vlan_rotate", direction > 0 ? "original" : "ordered");
100 ng_connect(".", "b", "vr:", direction > 0 ? "ordered" : "original");
101 ng_register_data("b", get_vlan);
103 for (len = 9; len > 0; len--)
105 /* reduce the number of vlans */
106 msg.vlan[len].proto = htons(ETHERTYPE_IP);
108 for (rot = -len + 1; rot < len; rot++)
112 /* set rotation offset */
113 snprintf(cmd, sizeof(cmd), "setconf { min=0 max=9 rot=%d }", rot);
114 ng_send_msg("vr:", cmd);
116 ng_send_data("a", &msg, sizeof(msg));
117 ng_handle_events(50, &r);
120 for (i = 0; i < len; i++)
122 int expect = (2 * len + i - direction * rot) % len + 1;
125 ATF_CHECK_MSG(vlan == expect,
126 "len=%d rot=%d i=%d -> vlan=%d, expect=%d",
127 len, rot, i, r[i], expect);
136 ATF_TC_HEAD(basic, conf)
138 atf_tc_set_md_var(conf, "require.user", "root");
141 ATF_TC_BODY(basic, dummy)
147 ATF_TC_HEAD(reverse, conf)
149 atf_tc_set_md_var(conf, "require.user", "root");
152 ATF_TC_BODY(reverse, dummy)
157 static void _ethertype(int);
158 static void get_ethertype(void *data, size_t len, void *ctx);
161 get_ethertype(void *data, size_t len, void *ctx)
164 struct frame *f = data;
167 for (i = 0; i < 10; i++)
168 v[i] = ntohs(f->vlan[i].proto);
172 _ethertype(int direction)
182 ng_mkpeer(".", "a", "vlan_rotate", direction > 0 ? "original" : "ordered");
184 ng_connect(".", "b", "vr:", direction > 0 ? "ordered" : "original");
185 ng_register_data("b", get_ethertype);
191 int rot = rand() % (2 * len - 1) - len + 1;
194 for (i = 0; i < len; i++)
199 msg.vlan[i].proto = htons(ETHERTYPE_VLAN);
202 msg.vlan[i].proto = htons(ETHERTYPE_QINQ);
205 msg.vlan[i].proto = htons(ETHERTYPE_8021Q9100);
209 msg.vlan[i].proto = htons(ETHERTYPE_IP);
211 for (i = 0; i < len; i++)
212 vlan[i] = msg.vlan[i].proto;
214 snprintf(cmd, sizeof(cmd), "setconf { min=0 max=9 rot=%d }", rot);
215 ng_send_msg("vr:", cmd);
218 ng_send_data("a", &msg, sizeof(msg));
219 ng_handle_events(50, &r);
222 for (i = 0; i < len; i++)
224 int expect = (2 * len + i - direction * rot) % len;
226 ATF_CHECK_MSG(r[i] == ntohs(vlan[expect]),
227 "len=%d rot=%d i=%d -> vlan=%04x, expect(%d)=%04x",
228 len, rot, i, ntohs(r[i]), expect, vlan[expect]);
236 ATF_TC_HEAD(ethertype, conf)
238 atf_tc_set_md_var(conf, "require.user", "root");
241 ATF_TC_BODY(ethertype, dummy)
247 ATF_TC_HEAD(typeether, conf)
249 atf_tc_set_md_var(conf, "require.user", "root");
252 ATF_TC_BODY(typeether, dummy)
258 ATF_TC_HEAD(minmax, conf)
260 atf_tc_set_md_var(conf, "require.user", "root");
263 ATF_TC_BODY(minmax, dummy)
273 ng_mkpeer(".", "a", "vlan_rotate", "original");
275 ng_connect(".", "b", "vr:", "ordered");
276 ng_connect(".", "c", "vr:", "excessive");
277 ng_connect(".", "d", "vr:", "incomplete");
278 ng_register_data("a", get_data0);
279 ng_register_data("b", get_data1);
280 ng_register_data("c", get_data2);
281 ng_register_data("d", get_data3);
283 ng_send_msg("vr:", "setconf { min=3 max=7 rot=0 }");
284 for (len = 9; len > 0; len--)
286 /* reduce the number of vlans */
287 msg.vlan[len].proto = htons(ETHERTYPE_IP);
290 ng_send_data("a", &msg, sizeof(msg));
291 ng_handle_events(50, &r);
293 ATF_CHECK(r[0] == 0 && r[1] == 0 && r[2] == 0 && r[3] == 1);
295 ATF_CHECK(r[0] == 0 && r[1] == 0 && r[2] == 1 && r[3] == 0);
297 ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 0 && r[3] == 0);
300 ng_send_data("b", &msg, sizeof(msg));
301 ng_handle_events(50, &r);
303 ATF_CHECK(r[0] == 0 && r[1] == 0 && r[2] == 0 && r[3] == 1);
305 ATF_CHECK(r[0] == 0 && r[1] == 0 && r[2] == 1 && r[3] == 0);
307 ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 0 && r[3] == 0);
310 ng_send_data("c", &msg, sizeof(msg));
311 ng_handle_events(50, &r);
312 ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 0 && r[3] == 0);
315 ng_send_data("d", &msg, sizeof(msg));
316 ng_handle_events(50, &r);
317 ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 0 && r[3] == 0);
323 ATF_TP_ADD_TCS(vlan_rotate)
325 /* Use "dd if=/dev/random bs=2 count=1 | od -x" to reproduce */
328 ATF_TP_ADD_TC(vlan_rotate, basic);
329 ATF_TP_ADD_TC(vlan_rotate, ethertype);
330 ATF_TP_ADD_TC(vlan_rotate, reverse);
331 ATF_TP_ADD_TC(vlan_rotate, typeether);
332 ATF_TP_ADD_TC(vlan_rotate, minmax);
334 return atf_no_error();