Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tests/sys/netgraph/vlan_rotate.c
39536 views
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
}
336
337