View | Details | Raw Unified | Return to bug 240685 | Differences between
and this patch

Collapse All | Expand All

(-)share/man/man4/Makefile (working copy) (+1 lines)
Lines 381-386 Link Here
381
       ng_uni.4 \
381
       ng_uni.4 \
382
       ng_vjc.4 \
382
       ng_vjc.4 \
383
       ng_vlan.4 \
383
       ng_vlan.4 \
384
       ng_vlan_rotate.4 \
384
       nmdm.4 \
385
       nmdm.4 \
385
       nsp.4 \
386
       nsp.4 \
386
       ${_ntb.4} \
387
       ${_ntb.4} \
(-)share/man/man4/ng_vlan_rotate.4 (working copy) (+253 lines)
Line 0 Link Here
1
.\" SPDX-License-Identifier: BSD-2-Clause-FreeBSD
2
.\"
3
.\" Copyright (c) 2019 IKS Service GmbH
4
.\" All rights reserved.
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
.\" 1. Redistributions of source code must retain the above copyright
10
.\"    notice, this list of conditions and the following disclaimer.
11
.\" 2. Redistributions in binary form must reproduce the above copyright
12
.\"    notice, this list of conditions and the following disclaimer in the
13
.\"    documentation and/or other materials provided with the distribution.
14
.\"
15
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
.\" SUCH DAMAGE.
26
.\"
27
.\" Author: Lutz Donnerhacke <lutz@donnerhacke.de>
28
.\"
29
.\" $FreeBSD$
30
.\"
31
.Dd September 19, 2019
32
.Dt NG_VLAN_ROTATE 4
33
.Os
34
.Sh NAME
35
.Nm ng_vlan_rotate
36
.Nd IEEE 802.1ad VLAN manipulation netgraph node type
37
.Sh SYNOPSIS
38
.In sys/types.h
39
.In netgraph.h
40
.In netgraph/ng_vlan_rotate.h
41
.Sh DESCRIPTION
42
The
43
.Nm vlan_rotate
44
node type manipulates the order of VLAN tags of frames tagged according to
45
the IEEE 802.1ad (an extension of IEEE 802.1Q) standard between different hooks.
46
.Pp
47
Each node has four special hooks,
48
.Va original ,
49
.Va ordered ,
50
.Va excessive ,
51
and
52
.Va incomplete .
53
.Pp
54
A frame tagged with an arbitrary number of
55
.Dv ETHERTYPE_VLAN ,
56
.Dv ETHERTYPE_QINQ ,
57
and
58
.Dv 0x9100
59
tags received on the
60
.Va original
61
hook will be rearranged to a new order of those tags and
62
is sent out the
63
.Dq ordered
64
hook.
65
After successful processing the
66
.Va histogram
67
counter for the observed stack size increments.
68
.Pp
69
If it contains fewer VLANs in the stack, than the configured
70
.Va min
71
limit, the frame is send out to the
72
.Va incomplete
73
hook and the
74
.Va incomplete
75
counter increments.
76
.Pp
77
If it contains more VLANs in the stack, than the configured
78
.Va max
79
limit, the frame is send out to the
80
.Va excessive
81
hook and the
82
.Va excessive
83
counter increments.
84
.Pp
85
If any destination hook is not connected, the frame is dropped and the
86
.Va drops
87
counter increments.
88
.Pp
89
For Ethernet frames received on the
90
.Va ordered
91
hook, the transformation is reversed and is passed to the
92
.Va original
93
hook. Please note, that this process is identical to the one described
94
above, besides the ordered/original hooks and the transformation are
95
swapped.
96
.Pp
97
An Ethernet frame received on
98
.Va incomplede
99
or
100
.Va excessive
101
hook is forwarded to the
102
.Va original
103
hook without any modification.
104
.Pp
105
This node supports only one operation at the moment: Rotation of the
106
VLANs in the stack. Setting the configuration parameter
107
.Va rot
108
to a positive value, the stack will roll up by this amount. Negative
109
values will roll down. A typical scenario is setting the value to 1
110
in order to bring the innermost VLAN tag to the outmost level.
111
Rotation includes the VLAN id and the ethertype, but the QOS
112
paramenters pcp and cfi stay in place. Typical QOS handling refers to
113
the outmost setting, so this scheme keeps QOS intact.
114
.Sh HOOKS
115
This node type supports the following hooks:
116
.Bl -tag -width incomplete
117
.It Va original
118
Typically this hook would be connected to a
119
.Xr ng_ether 4
120
node, using the
121
.Va lower
122
hook connected to a carrier network.
123
.It Va ordered
124
Typically this hook would be connected to a
125
.Xr ng_vlan 4
126
type node using the
127
.Va downstream
128
hook in order to seperate services.
129
.It Va excessive
130
see below.
131
.It Va incomplete
132
Typically those hooks would be attached to an
133
.Xr ng_eiface 4
134
type node using the
135
.Va ether
136
hook for anomaly monitoring purposes.
137
.El
138
.Sh CONTROL MESSAGES
139
This node type supports the generic control messages, plus the following:
140
.Bl -tag -width foo
141
.It Dv NGM_VLANROTATE_GET_CONF Pq Ic getconf
142
Read the current configuration.
143
.It Dv NGM_VLANROTATE_SET_CONF Pq Ic setconf
144
Set the current configuration.
145
.It Dv NGM_VLANROTATE_GET_STAT Pq Ic getstat
146
Read the current statistics.
147
.It Dv NGM_VLANROTATE_CLR_STAT Pq Ic clrstat
148
Zeroize the statistics.
149
.It Dv NGM_VLANROTATE_GETCLR_STAT Pq Ic getclrstat
150
Read the current statistics and zeroize it in one step.
151
.El
152
.Sh EXAMPLES
153
The first example demonstrates how to rotate double or triple tagged
154
frames so, that the innermost C-VLAN can be used as service
155
discriminator. The single or double tagged frames (C-VLAN
156
removed) are send out the an interface pointing to different
157
infrastucture.
158
.Bd -literal
159
#!/bin/sh
160
161
BNG_IF=ixl3
162
VOIP_IF=bge2
163
164
ngctl -f- <<EOF
165
mkpeer ${BNG_IF}: vlan_rotate lower original
166
name ${BNG_IF}:lower rotate
167
msg rotate: setconf { min=2 max=3 rot=1 }
168
mkpeer rotate: vlan ordered downstream
169
name rotate:ordered services
170
connect services: ${VOIP_IF} voip lower
171
msg services: addfilter { vlan=123 hook="voip" }
172
EOF
173
.Ed
174
175
Let's inject the following sample frame on the
176
.Dv BNG_IF
177
interface:
178
.Bd -literal
179
00:00:00:00:01:01 > 00:01:02:03:04:05,
180
 ethertype 802.1Q-9100 (0x9100), length 110: vlan 2, p 1,
181
 ethertype 802.1Q-QinQ, vlan 101, p 0,
182
 ethertype 802.1Q, vlan 123, p 7,
183
 ethertype IPv4, (tos 0x0, ttl 64, id 15994, offset 0, flags [none],
184
  proto ICMP (1), length 84) 192.168.140.101 > 192.168.140.1:
185
  ICMP echo request, id 40234, seq 0, length 64
186
.Ed
187
188
The frame ejected on the
189
.Va ordered
190
hook will look like this:
191
.Bd -literal
192
00:00:00:00:01:01 > 00:01:02:03:04:05,
193
 ethertype 802.1Q (0x8100), length 110: vlan 123, p 1,
194
 ethertype 802.1Q-9100, vlan 2, p 0,
195
 ethertype 802.1Q-QinQ, vlan 101, p 7,
196
 ethertype IPv4, (tos 0x0, ttl 64, id 15994, offset 0, flags [none],
197
  proto ICMP (1), length 84) 192.168.140.101 > 192.168.140.1:
198
  ICMP echo request, id 40234, seq 0, length 64
199
.Ed
200
201
Hence the frame pushed out to the
202
.Dv VOIP_IF
203
will have this form:
204
.Bd -literal
205
00:00:00:00:01:01 > 00:01:02:03:04:05,
206
 ethertype 802.1Q-9100, vlan 2, p 0,
207
 ethertype 802.1Q-QinQ, vlan 101, p 7,
208
 ethertype IPv4, (tos 0x0, ttl 64, id 15994, offset 0, flags [none],
209
  proto ICMP (1), length 84) 192.168.140.101 > 192.168.140.1:
210
  ICMP echo request, id 40234, seq 0, length 64
211
.Ed
212
213
.Pp
214
The second example distinguish between double tagged and single tagged
215
frames. Frames with more VLAN tags are dropped.
216
.Bd -literal
217
#!/bin/sh
218
219
IN_IF=bge1
220
221
ngctl -f- <<EOF
222
mkpeer ${IN_IF}: vlan_rotate lower original
223
name ${IN_IF}:lower separate
224
msg separate: setconf { min=1 max=1 rot=0 }
225
mkpeer separate: eiface incomplete ether
226
name separate:incomplete untagged
227
mkpeer separate: eiface ordered ether
228
name separate:ordered tagged
229
EOF
230
.Ed
231
232
Setting the
233
.Va rot
234
parameter to zero (or omitting it) does not change
235
the order of the tags within the frame.
236
237
.Sh SHUTDOWN
238
This node shuts down upon receipt of a
239
.Dv NGM_SHUTDOWN
240
control message, or when all hooks have been disconnected.
241
.Sh SEE ALSO
242
.Xr netgraph 4 ,
243
.Xr ng_eiface 4 ,
244
.Xr ng_ether 4 ,
245
.Xr ng_vlan 4 ,
246
.Xr ngctl 8
247
.Sh HISTORY
248
The
249
.Nm
250
node type appeared in
251
.Fx 12.1-PRERELEASE .
252
.Sh AUTHORS
253
.An Lutz Donnerhacke Aq Mt lutz@donnerhacke.de
(-)sys/conf/files (working copy) (+1 lines)
Lines 4299-4304 Link Here
4299
netgraph/ng_tty.c              optional netgraph_tty
4299
netgraph/ng_tty.c              optional netgraph_tty
4300
netgraph/ng_vjc.c              optional netgraph_vjc
4300
netgraph/ng_vjc.c              optional netgraph_vjc
4301
netgraph/ng_vlan.c             optional netgraph_vlan
4301
netgraph/ng_vlan.c             optional netgraph_vlan
4302
netgraph/ng_vlan_rotate.c      optional netgraph_vlan_rotate
4302
netinet/accf_data.c            optional accept_filter_data inet
4303
netinet/accf_data.c            optional accept_filter_data inet
4303
netinet/accf_dns.c             optional accept_filter_dns inet
4304
netinet/accf_dns.c             optional accept_filter_dns inet
4304
netinet/accf_http.c            optional accept_filter_http inet
4305
netinet/accf_http.c            optional accept_filter_http inet
(-)sys/modules/netgraph/Makefile (working copy) (-1 / +2 lines)
Lines 52-58 Link Here
52
       tty \
52
       tty \
53
       UI \
53
       UI \
54
       vjc \
54
       vjc \
55
       vlan
55
       vlan \
56
       vlan_rotate
56
57
57
.if ${MK_BLUETOOTH} != "no" || defined(ALL_MODULES)
58
.if ${MK_BLUETOOTH} != "no" || defined(ALL_MODULES)
58
_bluetooth=    bluetooth
59
_bluetooth=    bluetooth
(-)sys/netgraph/ng_vlan_rotate.c (working copy) (+483 lines)
Line 0 Link Here
1
/*
2
 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3
 *
4
 * Copyright (c) 2019 IKS Service GmbH
5
 * All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
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 copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
 * SUCH DAMAGE.
27
 *
28
 * Author: Lutz Donnerhacke <lutz@donnerhacke.de>
29
 *
30
 * $FreeBSD$
31
 */
32
33
#include <sys/param.h>
34
#include <sys/systm.h>
35
#include <sys/kernel.h>
36
#include <sys/mbuf.h>
37
#include <sys/malloc.h>
38
#include <sys/ctype.h>
39
#include <sys/errno.h>
40
#include <sys/syslog.h>
41
42
#include <net/ethernet.h>
43
44
#include <netgraph/ng_message.h>
45
#include <netgraph/ng_parse.h>
46
#include <netgraph/ng_vlan_rotate.h>
47
#include <netgraph/netgraph.h>
48
49
/*
50
 * This section contains the netgraph method declarations for the
51
 * sample node. These methods define the netgraph 'type'.
52
 */
53
54
static ng_constructor_t        ng_vlanrotate_constructor;
55
static ng_rcvmsg_t     ng_vlanrotate_rcvmsg;
56
static ng_shutdown_t   ng_vlanrotate_shutdown;
57
static ng_newhook_t    ng_vlanrotate_newhook;
58
static ng_rcvdata_t    ng_vlanrotate_rcvdata;
59
static ng_disconnect_t ng_vlanrotate_disconnect;
60
61
/* Parse type for struct ng_vlanrotate_conf. */
62
static const struct ng_parse_struct_field ng_vlanrotate_conf_fields[] = {
63
       { "rot", &ng_parse_int8_type  },
64
       { "min", &ng_parse_uint8_type },
65
       { "max", &ng_parse_uint8_type },
66
       { NULL }
67
};
68
static const struct ng_parse_type ng_vlanrotate_conf_type = {
69
       &ng_parse_struct_type,
70
       &ng_vlanrotate_conf_fields
71
};
72
73
/* Parse type for struct ng_vlanrotate_stat. */
74
static struct ng_parse_fixedarray_info ng_vlanrotate_stat_hist_info = {
75
       &ng_parse_uint64_type,
76
       NG_VLANROTATE_MAX_VLANS
77
};
78
static struct ng_parse_type ng_vlanrotate_stat_hist = {
79
       &ng_parse_fixedarray_type,
80
       &ng_vlanrotate_stat_hist_info
81
};
82
static const struct ng_parse_struct_field ng_vlanrotate_stat_fields[] = {
83
       { "drops",      &ng_parse_uint64_type    },
84
       { "excessive",  &ng_parse_uint64_type    },
85
       { "incomplete", &ng_parse_uint64_type    },
86
       { "histogram",  &ng_vlanrotate_stat_hist },
87
       { NULL }
88
};
89
static struct ng_parse_type ng_vlanrotate_stat_type = {
90
       &ng_parse_struct_type,
91
       &ng_vlanrotate_stat_fields
92
};
93
94
95
/* List of commands and how to convert arguments to/from ASCII */
96
static const struct ng_cmdlist ng_vlanrotate_cmdlist[] = {
97
       {
98
               NGM_VLANROTATE_COOKIE,
99
                 NGM_VLANROTATE_GET_CONF,
100
                 "getconf",
101
                 NULL,
102
                 &ng_vlanrotate_conf_type,
103
       },
104
       {
105
               NGM_VLANROTATE_COOKIE,
106
                 NGM_VLANROTATE_SET_CONF,
107
                 "setconf",
108
                 &ng_vlanrotate_conf_type,
109
                 NULL
110
       },
111
       {
112
               NGM_VLANROTATE_COOKIE,
113
                 NGM_VLANROTATE_GET_STAT,
114
                 "getstat",
115
                 NULL,
116
                 &ng_vlanrotate_stat_type
117
       },
118
       {
119
               NGM_VLANROTATE_COOKIE,
120
                 NGM_VLANROTATE_CLR_STAT,
121
                 "clrstat",
122
                 NULL,
123
                 &ng_vlanrotate_stat_type
124
       },
125
       {
126
               NGM_VLANROTATE_COOKIE,
127
                 NGM_VLANROTATE_GETCLR_STAT,
128
                 "getclrstat",
129
                 NULL,
130
                 &ng_vlanrotate_stat_type
131
       },
132
       { 0 }
133
};
134
135
/* Netgraph node type descriptor */
136
static struct ng_type typestruct = {
137
       .version =      NG_ABI_VERSION,
138
       .name =         NG_VLANROTATE_NODE_TYPE,
139
       .constructor =  ng_vlanrotate_constructor,
140
       .rcvmsg =       ng_vlanrotate_rcvmsg,
141
       .shutdown =     ng_vlanrotate_shutdown,
142
       .newhook =      ng_vlanrotate_newhook,
143
       .rcvdata =      ng_vlanrotate_rcvdata,
144
       .disconnect =   ng_vlanrotate_disconnect,
145
       .cmdlist =      ng_vlanrotate_cmdlist,
146
};
147
NETGRAPH_INIT(vlanrotate, &typestruct);
148
149
/* Information we store for each node */
150
struct vlanrotate {
151
       hook_p                          original_hook;
152
       hook_p                          ordered_hook;
153
       hook_p                          excessive_hook;
154
       hook_p                          incomplete_hook;
155
       struct ng_vlanrotate_conf       conf;
156
       struct ng_vlanrotate_stat       stat;
157
};
158
typedef struct vlanrotate *vlanrotate_p;
159
160
/*
161
 * Set up the private data structure.
162
 */
163
static int
164
ng_vlanrotate_constructor(node_p node)
165
{
166
       vlanrotate_p vrp = malloc(sizeof(*vrp), M_NETGRAPH, M_WAITOK | M_ZERO);
167
       
168
       vrp->conf.max = NG_VLANROTATE_MAX_VLANS;
169
170
       NG_NODE_SET_PRIVATE(node, vrp);
171
       return (0);
172
}
173
174
/*
175
 * Give our ok for a hook to be added.
176
 */
177
static int
178
ng_vlanrotate_newhook(node_p node, hook_p hook, const char *name)
179
{
180
       const vlanrotate_p vrp = NG_NODE_PRIVATE(node);
181
       hook_p *dst = NULL;
182
       
183
       if (strcmp(name, NG_VLANROTATE_HOOK_ORDERED) == 0) {
184
               dst = &vrp->ordered_hook;
185
       } else if (strcmp(name, NG_VLANROTATE_HOOK_ORIGINAL) == 0) {
186
               dst = &vrp->original_hook;
187
       } else if (strcmp(name, NG_VLANROTATE_HOOK_EXCESSIVE) == 0) {
188
               dst = &vrp->excessive_hook;
189
       } else if (strcmp(name, NG_VLANROTATE_HOOK_INCOMPLETE) == 0) {
190
               dst = &vrp->incomplete_hook;
191
       }
192
       
193
       if(dst == NULL)
194
         return (EINVAL);             /* not a hook we know about */
195
       
196
       if(*dst != NULL)
197
         return (EADDRINUSE);         /* don't override */
198
199
       *dst = hook;
200
       return (0);
201
}
202
203
/*
204
 * Get a netgraph control message.
205
 * We actually receive a queue item that has a pointer to the message.
206
 * If we free the item, the message will be freed too, unless we remove
207
 * it from the item using NGI_GET_MSG();
208
 * The return address is also stored in the item, as an ng_ID_t,
209
 * accessible as NGI_RETADDR(item);
210
 * Check it is one we understand. If needed, send a response.
211
 * We could save the address for an async action later, but don't here.
212
 * Always free the message.
213
 * The response should be in a malloc'd region that the caller can 'free'.
214
 * A response is not required.
215
 */
216
static int
217
ng_vlanrotate_rcvmsg(node_p node, item_p item, hook_p lasthook)
218
{
219
       const vlanrotate_p vrp = NG_NODE_PRIVATE(node);
220
       struct ng_mesg *resp = NULL;
221
       int error = 0;
222
       struct ng_mesg *msg;
223
       struct ng_vlanrotate_conf * pcf;
224
       
225
       NGI_GET_MSG(item, msg);
226
       /* Deal with message according to cookie and command */
227
       switch (msg->header.typecookie) {
228
        case NGM_VLANROTATE_COOKIE:
229
               switch (msg->header.cmd) {
230
                case NGM_VLANROTATE_GET_CONF:
231
                       NG_MKRESPONSE(resp, msg, sizeof(vrp->conf), M_NOWAIT);
232
                       if (!resp) {
233
                               error = ENOMEM;
234
                               break;
235
                       }
236
                       *((struct ng_vlanrotate_conf *) resp->data) = vrp->conf;
237
                       break;
238
                case NGM_VLANROTATE_SET_CONF:
239
                       if (msg->header.arglen != sizeof(*pcf)) {
240
                               error = EINVAL;
241
                               break;
242
                       }
243
244
                       pcf = (struct ng_vlanrotate_conf *) msg->data;
245
                       
246
                       if(pcf->max == 0)  pcf->max = vrp->conf.max;   /* keep current value */
247
248
                       if(pcf->max > NG_VLANROTATE_MAX_VLANS)  error = EINVAL;
249
                       if(pcf->min > pcf->max)                 error = EINVAL;
250
                       if(abs(pcf->rot) >= pcf->max)           error = EINVAL;
251
252
                       if(error == 0) /* okay */
253
                         vrp->conf = *pcf;
254
                       
255
                       break;
256
                case NGM_VLANROTATE_GET_STAT:
257
                case NGM_VLANROTATE_GETCLR_STAT:
258
                       NG_MKRESPONSE(resp, msg, sizeof(vrp->stat), M_NOWAIT);
259
                       if (!resp) {
260
                               error = ENOMEM;
261
                               break;
262
                       }
263
                       *(struct ng_vlanrotate_stat *)resp->data = vrp->stat;
264
                       if(msg->header.cmd != NGM_VLANROTATE_GETCLR_STAT)
265
                         break;
266
                case NGM_VLANROTATE_CLR_STAT:
267
                       bzero(&(vrp->stat), sizeof(vrp->stat));
268
                       break;
269
                default:
270
                       error = EINVAL;         /* unknown command */
271
                       break;
272
               }
273
               break;
274
        default:
275
               error = EINVAL;                 /* unknown cookie type */
276
               break;
277
       }
278
279
       /* Take care of synchronous response, if any */
280
       NG_RESPOND_MSG(error, node, item, resp);
281
       /* Free the message and return */
282
       NG_FREE_MSG(msg);
283
       return(error);
284
}
285
286
/*
287
 * Receive data, and do something with it.
288
 * Actually we receive a queue item which holds the data.
289
 * If we free the item it will also free the data unless we have
290
 * previously disassociated it using the NGI_GET_M() macro.
291
 * Possibly send it out on another link after processing.
292
 * Possibly do something different if it comes from different
293
 * hooks. The caller will never free m, so if we use up this data or
294
 * abort we must free it.
295
 *
296
 * If we want, we may decide to force this data to be queued and reprocessed
297
 * at the netgraph NETISR time.
298
 * We would do that by setting the HK_QUEUE flag on our hook. We would do that
299
 * in the connect() method.
300
 */
301
302
struct ether_vlan_stack_entry {
303
       uint16_t proto;
304
       uint16_t tag;
305
} __packed;
306
307
struct ether_vlan_stack_header {
308
       uint8_t dst[ETHER_ADDR_LEN];
309
       uint8_t src[ETHER_ADDR_LEN];
310
       struct ether_vlan_stack_entry vlan_stack[1];
311
} __packed;
312
313
static int
314
ng_vlanrotate_gcd(int a, int b)
315
{
316
       if (b == 0) 
317
         return a; 
318
       else
319
         return ng_vlanrotate_gcd(b, a % b); 
320
}
321
322
#define COPY_VLAN_KEEP_QOS(dst,src)    {              \
323
       (dst).proto = (src).proto;                     \
324
       (dst).tag &= ~htons(EVL_VLID_MASK);            \
325
       (dst).tag |= (src).tag & htons(EVL_VLID_MASK); \
326
  } while(0)
327
328
static void
329
ng_vlanrotate_rotate(struct ether_vlan_stack_entry arr[], int d, int n)
330
{
331
       int i, j, k;
332
       struct ether_vlan_stack_entry temp;
333
       
334
       /* for each comensurable slice */
335
       for (i = ng_vlanrotate_gcd(d, n); i-- > 0;) {
336
               /* rotate left aka downwards */
337
               COPY_VLAN_KEEP_QOS(temp, arr[i]);
338
               j = i;
339
               
340
               while (1) {
341
                       k = j + d; 
342
                       if (k >= n) 
343
                         k = k - n; 
344
                       if (k == i) 
345
                         break; 
346
                       COPY_VLAN_KEEP_QOS(arr[j], arr[k]);
347
                       j = k; 
348
               }
349
               
350
               COPY_VLAN_KEEP_QOS(arr[j], temp);
351
       }
352
}
353
354
#undef COPY_VLAN_KEEP_QOS
355
356
static int
357
ng_vlanrotate_rcvdata(hook_p hook, item_p item)
358
{
359
       const vlanrotate_p vrp = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
360
       struct mbuf *m = NULL;
361
       hook_p dst_hook;
362
       int8_t rotate;
363
       int8_t vlans = 0;
364
       int error = ENOSYS;
365
       struct ether_vlan_stack_header *evsh;
366
       
367
       NGI_GET_M(item, m);
368
       
369
       if(hook == vrp->ordered_hook) {
370
               rotate   = + vrp->conf.rot;
371
               dst_hook =   vrp->original_hook;
372
       } else  if(hook == vrp->original_hook) {
373
               rotate   = - vrp->conf.rot;
374
               dst_hook =   vrp->ordered_hook;
375
       } else {
376
               dst_hook =   vrp->original_hook;
377
               goto send;                     /* everything else goes out unmodified */
378
       }
379
       
380
       if(dst_hook == NULL) {
381
               error = ENETDOWN;
382
               goto fail;
383
       }
384
       
385
       /* count the vlans */
386
       for(vlans = 0; vlans <= NG_VLANROTATE_MAX_VLANS; vlans++) {
387
               size_t expected_len = sizeof(struct ether_vlan_stack_header) + vlans * sizeof(struct ether_vlan_stack_entry);
388
               
389
               if (m->m_len < expected_len) {
390
                       m = m_pullup(m, expected_len);
391
                       if (m == NULL) {
392
                               error = EINVAL;
393
                               goto fail;
394
                       }
395
               }
396
               
397
               evsh = mtod(m, struct ether_vlan_stack_header *);
398
               switch(ntohs(evsh->vlan_stack[vlans].proto)) {
399
                case ETHERTYPE_VLAN:
400
                case ETHERTYPE_QINQ:
401
                case 0x9100:
402
                       break;
403
                default:
404
                       goto out;
405
               }
406
       }
407
out:
408
       if(vlans > vrp->conf.max || vlans >= NG_VLANROTATE_MAX_VLANS) {
409
               vrp->stat.excessive++;
410
               dst_hook = vrp->excessive_hook;
411
               goto send;
412
       }
413
414
       if((vlans < vrp->conf.min) || (vlans <= abs(rotate))) {
415
               vrp->stat.incomplete++;
416
               dst_hook = vrp->incomplete_hook;
417
               goto send;
418
       }
419
       vrp->stat.histogram[vlans]++;
420
421
       /* 01234   5 vlans
422
        * -----
423
        * 34012  +2 rotate
424
        * 12340  +4 rotate
425
        * 12340  -1 rotate
426
        */
427
       if(rotate == 0) {
428
               /* do nothing */
429
       } else if(rotate > 0) {
430
               ng_vlanrotate_rotate(evsh->vlan_stack,         rotate, vlans);
431
       } else {
432
               ng_vlanrotate_rotate(evsh->vlan_stack, vlans + rotate, vlans);
433
       }
434
435
send:
436
       if(dst_hook == NULL) goto fail;
437
       NG_FWD_NEW_DATA(error, item, dst_hook, m);
438
       return 0;
439
440
fail:
441
       vrp->stat.drops ++;
442
       if(m != NULL) m_freem(m);
443
       NG_FREE_ITEM(item);
444
       return (error);
445
}
446
447
/*
448
 * Do local shutdown processing..
449
 * All our links and the name have already been removed.
450
 */
451
static int
452
ng_vlanrotate_shutdown(node_p node)
453
{
454
       const vlanrotate_p vrp = NG_NODE_PRIVATE(node);
455
456
       NG_NODE_SET_PRIVATE(node, NULL);
457
       NG_NODE_UNREF(node);
458
       free(vrp, M_NETGRAPH);
459
460
       return (0);
461
}
462
463
/*
464
 * Hook disconnection
465
 *
466
 * For this type, removal of the last link destroys the node
467
 */
468
static int
469
ng_vlanrotate_disconnect(hook_p hook)
470
{
471
       const vlanrotate_p vrp = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
472
       
473
       if(vrp->original_hook   == hook) vrp->original_hook   = NULL;
474
       if(vrp->ordered_hook    == hook) vrp->ordered_hook    = NULL;
475
       if(vrp->excessive_hook  == hook) vrp->excessive_hook  = NULL;
476
       if(vrp->incomplete_hook == hook) vrp->incomplete_hook = NULL;
477
                 
478
       if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
479
        && (NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) /* already shutting down? */
480
               ng_rmnode_self(NG_HOOK_NODE(hook));
481
       return (0);
482
}
483
(-)sys/netgraph/ng_vlan_rotate.h (working copy) (+68 lines)
Line 0 Link Here
1
/*
2
 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3
 *
4
 * Copyright (c) 2019 IKS Service GmbH
5
 * All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
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 copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
 * SUCH DAMAGE.
27
 *
28
 * Author: Lutz Donnerhacke <lutz@donnerhacke.de>
29
 *
30
 * $FreeBSD$
31
 */
32
33
#ifndef _NETGRAPH_NG_VLAN_ROTATE_H_
34
#define _NETGRAPH_NG_VLAN_ROTATE_H_
35
36
#define NG_VLANROTATE_NODE_TYPE                "vlan_rotate"
37
#define NGM_VLANROTATE_COOKIE          1568378766
38
39
/* Hook names */
40
#define NG_VLANROTATE_HOOK_ORDERED     "ordered"
41
#define NG_VLANROTATE_HOOK_ORIGINAL    "original"
42
#define NG_VLANROTATE_HOOK_EXCESSIVE   "excessive"
43
#define NG_VLANROTATE_HOOK_INCOMPLETE  "incomplete"
44
45
/* Limits */
46
#define NG_VLANROTATE_MAX_VLANS                10
47
48
/* Datastructures for netgraph commands */
49
struct ng_vlanrotate_conf {
50
       int8_t  rot;
51
       uint8_t min, max;
52
};
53
54
struct ng_vlanrotate_stat {
55
       uint64_t drops, excessive, incomplete;
56
       uint64_t histogram[NG_VLANROTATE_MAX_VLANS];
57
};
58
59
/* Netgraph commands understood by this node type */
60
enum {
61
       NGM_VLANROTATE_GET_CONF = 1,
62
       NGM_VLANROTATE_SET_CONF,
63
       NGM_VLANROTATE_GET_STAT,
64
       NGM_VLANROTATE_CLR_STAT,
65
       NGM_VLANROTATE_GETCLR_STAT
66
};
67
68
#endif /* _NETGRAPH_NG_VLAN_ROTATE_H_ */

Return to bug 240685