]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tests/sys/netgraph/vlan_rotate.c
sqlite3: Vendor import of sqlite3 3.43.1
[FreeBSD/FreeBSD.git] / tests / sys / netgraph / vlan_rotate.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright 2021 Lutz Donnerhacke
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
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.
19  *
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
32  * SUCH DAMAGE.
33  */
34 #include <atf-c.h>
35 #include <errno.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38
39 #include <net/ethernet.h>
40 #include <netinet/in.h>
41
42 #include "util.h"
43 #include <netgraph/ng_bridge.h>
44
45 struct vlan
46 {
47         uint16_t        proto;
48         uint16_t        tag;
49 }               __packed;
50
51 struct frame
52 {
53         u_char          dst[ETHER_ADDR_LEN];
54         u_char          src[ETHER_ADDR_LEN];
55         struct vlan     vlan[10];
56 }               __packed;
57
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))},
70         .vlan[9] = {0}
71 };
72
73 static void     _basic(int);
74 static void     get_vlan(void *data, size_t len, void *ctx);
75
76 static void
77 get_vlan(void *data, size_t len, void *ctx)
78 {
79         int            *v = ctx, i;
80         struct frame   *f = data;
81
82         (void)len;
83         for (i = 0; i < 10; i++)
84                 v[i] = EVL_VLANOFTAG(ntohs(f->vlan[i].tag));
85 }
86
87 static void
88 _basic(int direction)
89 {
90         int             r[10];
91         int             i, rot, len;
92
93         ng_init();
94         ng_errors(PASS);
95         ng_shutdown("vr:");
96         ng_errors(FAIL);
97
98         ng_mkpeer(".", "a", "vlan_rotate", direction > 0 ? "original" : "ordered");
99         ng_name("a", "vr");
100         ng_connect(".", "b", "vr:", direction > 0 ? "ordered" : "original");
101         ng_register_data("b", get_vlan);
102
103         for (len = 9; len > 0; len--)
104         {
105                 /* reduce the number of vlans */
106                 msg.vlan[len].proto = htons(ETHERTYPE_IP);
107
108                 for (rot = -len + 1; rot < len; rot++)
109                 {
110                         char            cmd[40];
111
112                         /* set rotation offset */
113                         snprintf(cmd, sizeof(cmd), "setconf { min=0 max=9 rot=%d }", rot);
114                         ng_send_msg("vr:", cmd);
115
116                         ng_send_data("a", &msg, sizeof(msg));
117                         ng_handle_events(50, &r);
118
119                         /* check rotation */
120                         for (i = 0; i < len; i++)
121                         {
122                                 int             expect = (2 * len + i - direction * rot) % len + 1;
123                                 int             vlan = r[i];
124
125                                 ATF_CHECK_MSG(vlan == expect,
126                                  "len=%d rot=%d i=%d -> vlan=%d, expect=%d",
127                                               len, rot, i, r[i], expect);
128                         }
129                 }
130         }
131
132         ng_shutdown("vr:");
133 }
134
135 ATF_TC(basic);
136 ATF_TC_HEAD(basic, conf)
137 {
138         atf_tc_set_md_var(conf, "require.user", "root");
139 }
140
141 ATF_TC_BODY(basic, dummy)
142 {
143         _basic(1);
144 }
145
146 ATF_TC(reverse);
147 ATF_TC_HEAD(reverse, conf)
148 {
149         atf_tc_set_md_var(conf, "require.user", "root");
150 }
151
152 ATF_TC_BODY(reverse, dummy)
153 {
154         _basic(-1);
155 }
156
157 static void     _ethertype(int);
158 static void     get_ethertype(void *data, size_t len, void *ctx);
159
160 static void
161 get_ethertype(void *data, size_t len, void *ctx)
162 {
163         int            *v = ctx, i;
164         struct frame   *f = data;
165
166         (void)len;
167         for (i = 0; i < 10; i++)
168                 v[i] = ntohs(f->vlan[i].proto);
169 }
170
171 static void
172 _ethertype(int direction)
173 {
174         int             r[10];
175         int             i, rounds = 20;
176
177         ng_init();
178         ng_errors(PASS);
179         ng_shutdown("vr:");
180         ng_errors(FAIL);
181
182         ng_mkpeer(".", "a", "vlan_rotate", direction > 0 ? "original" : "ordered");
183         ng_name("a", "vr");
184         ng_connect(".", "b", "vr:", direction > 0 ? "ordered" : "original");
185         ng_register_data("b", get_ethertype);
186
187         while (rounds-- > 0)
188         {
189                 char            cmd[40];
190                 int             len = 9;
191                 int             rot = rand() % (2 * len - 1) - len + 1;
192                 int             vlan[10];
193
194                 for (i = 0; i < len; i++)
195                 {
196                         switch (rand() % 3)
197                         {
198                         default:
199                                 msg.vlan[i].proto = htons(ETHERTYPE_VLAN);
200                                 break;
201                         case 1:
202                                 msg.vlan[i].proto = htons(ETHERTYPE_QINQ);
203                                 break;
204                         case 2:
205                                 msg.vlan[i].proto = htons(ETHERTYPE_8021Q9100);
206                                 break;
207                         }
208                 }
209                 msg.vlan[i].proto = htons(ETHERTYPE_IP);
210
211                 for (i = 0; i < len; i++)
212                         vlan[i] = msg.vlan[i].proto;
213
214                 snprintf(cmd, sizeof(cmd), "setconf { min=0 max=9 rot=%d }", rot);
215                 ng_send_msg("vr:", cmd);
216
217                 bzero(r, sizeof(r));
218                 ng_send_data("a", &msg, sizeof(msg));
219                 ng_handle_events(50, &r);
220
221                 /* check rotation */
222                 for (i = 0; i < len; i++)
223                 {
224                         int             expect = (2 * len + i - direction * rot) % len;
225
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]);
229                 }
230         }
231
232         ng_shutdown("vr:");
233 }
234
235 ATF_TC(ethertype);
236 ATF_TC_HEAD(ethertype, conf)
237 {
238         atf_tc_set_md_var(conf, "require.user", "root");
239 }
240
241 ATF_TC_BODY(ethertype, dummy)
242 {
243         _ethertype(1);
244 }
245
246 ATF_TC(typeether);
247 ATF_TC_HEAD(typeether, conf)
248 {
249         atf_tc_set_md_var(conf, "require.user", "root");
250 }
251
252 ATF_TC_BODY(typeether, dummy)
253 {
254         _ethertype(-1);
255 }
256
257 ATF_TC(minmax);
258 ATF_TC_HEAD(minmax, conf)
259 {
260         atf_tc_set_md_var(conf, "require.user", "root");
261 }
262
263 ATF_TC_BODY(minmax, dummy)
264 {
265         ng_counter_t    r;
266         int             len;
267
268         ng_init();
269         ng_errors(PASS);
270         ng_shutdown("vr:");
271         ng_errors(FAIL);
272
273         ng_mkpeer(".", "a", "vlan_rotate", "original");
274         ng_name("a", "vr");
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);
282
283         ng_send_msg("vr:", "setconf { min=3 max=7 rot=0 }");
284         for (len = 9; len > 0; len--)
285         {
286                 /* reduce the number of vlans */
287                 msg.vlan[len].proto = htons(ETHERTYPE_IP);
288
289                 ng_counter_clear(r);
290                 ng_send_data("a", &msg, sizeof(msg));
291                 ng_handle_events(50, &r);
292                 if (len < 3)
293                         ATF_CHECK(r[0] == 0 && r[1] == 0 && r[2] == 0 && r[3] == 1);
294                 else if (len > 7)
295                         ATF_CHECK(r[0] == 0 && r[1] == 0 && r[2] == 1 && r[3] == 0);
296                 else
297                         ATF_CHECK(r[0] == 0 && r[1] == 1 && r[2] == 0 && r[3] == 0);
298
299                 ng_counter_clear(r);
300                 ng_send_data("b", &msg, sizeof(msg));
301                 ng_handle_events(50, &r);
302                 if (len < 3)
303                         ATF_CHECK(r[0] == 0 && r[1] == 0 && r[2] == 0 && r[3] == 1);
304                 else if (len > 7)
305                         ATF_CHECK(r[0] == 0 && r[1] == 0 && r[2] == 1 && r[3] == 0);
306                 else
307                         ATF_CHECK(r[0] == 1 && r[1] == 0 && r[2] == 0 && r[3] == 0);
308
309                 ng_counter_clear(r);
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);
313
314                 ng_counter_clear(r);
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);
318         }
319
320         ng_shutdown("vr:");
321 }
322
323 ATF_TP_ADD_TCS(vlan_rotate)
324 {
325         /* Use "dd if=/dev/random bs=2 count=1 | od -x" to reproduce */
326         srand(0xb93b);
327
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);
333
334         return atf_no_error();
335 }