• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * lib/route/act/vlan.c        vlan action
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation version 2.1
7  * of the License.
8  *
9  * Copyright (c) 2018 Volodymyr Bendiuga <volodymyr.bendiuga@gmail.com>
10  */
11 
12 /**
13  * @ingroup act
14  * @defgroup act_vlan VLAN Manipulation
15  *
16  * @{
17  */
18 
19 #include <netlink-private/netlink.h>
20 #include <netlink-private/tc.h>
21 #include <netlink/netlink.h>
22 #include <netlink/attr.h>
23 #include <netlink/utils.h>
24 #include <netlink-private/route/tc-api.h>
25 #include <netlink/route/act/vlan.h>
26 
27 
28 #define VLAN_F_VID   (1 << 0)
29 #define VLAN_F_PROTO (1 << 1)
30 #define VLAN_F_PRIO  (1 << 2)
31 #define VLAN_F_ACT   (1 << 3)
32 #define VLAN_F_MODE  (1 << 4)
33 
34 static struct nla_policy vlan_policy[TCA_VLAN_MAX + 1] = {
35 	[TCA_VLAN_PARMS]                = { .minlen = sizeof(struct tc_vlan) },
36 	[TCA_VLAN_PUSH_VLAN_ID]         = { .type = NLA_U16 },
37 	[TCA_VLAN_PUSH_VLAN_PROTOCOL]   = { .type = NLA_U16 },
38 	[TCA_VLAN_PUSH_VLAN_PRIORITY]   = { .type = NLA_U8 },
39 };
40 
vlan_msg_parser(struct rtnl_tc * tc,void * data)41 static int vlan_msg_parser(struct rtnl_tc *tc, void *data)
42 {
43 	struct rtnl_vlan *v = data;
44 	struct nlattr *tb[TCA_VLAN_MAX + 1];
45 	int err;
46 
47 	err = tca_parse(tb, TCA_VLAN_MAX, tc, vlan_policy);
48 	if (err < 0)
49 		return err;
50 
51 	v->v_flags = 0;
52 	if (!tb[TCA_VLAN_PARMS])
53 		return -NLE_MISSING_ATTR;
54 	else {
55 		nla_memcpy(&v->v_parm, tb[TCA_VLAN_PARMS], sizeof(v->v_parm));
56 		v->v_flags |= VLAN_F_ACT;
57 		v->v_flags |= VLAN_F_MODE;
58 	}
59 
60 	if (tb[TCA_VLAN_PUSH_VLAN_ID]) {
61 		v->v_vid = nla_get_u16(tb[TCA_VLAN_PUSH_VLAN_ID]);
62 		v->v_flags |= VLAN_F_VID;
63 	}
64 
65 	if (tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]) {
66 		v->v_proto = nla_get_u16(tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]);
67 		v->v_flags |= VLAN_F_PROTO;
68 	}
69 
70 	if (tb[TCA_VLAN_PUSH_VLAN_PRIORITY]) {
71 		v->v_prio = nla_get_u8(tb[TCA_VLAN_PUSH_VLAN_PRIORITY]);
72 		v->v_flags |= VLAN_F_PRIO;
73 	}
74 
75 	return 0;
76 }
77 
vlan_msg_fill(struct rtnl_tc * tc,void * data,struct nl_msg * msg)78 static int vlan_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
79 {
80 	struct rtnl_vlan *v = data;
81 
82 	if (!v)
83 		return 0;
84 	if (!(v->v_flags & VLAN_F_MODE))
85 		return -NLE_MISSING_ATTR;
86 
87 	NLA_PUT(msg, TCA_VLAN_PARMS, sizeof(v->v_parm), &v->v_parm);
88 
89 	/* vid is required for PUSH & MODIFY modes */
90 	if ((v->v_parm.v_action != TCA_VLAN_ACT_POP) && !(v->v_flags & VLAN_F_VID))
91 		return -NLE_MISSING_ATTR;
92 
93 	if (v->v_flags & VLAN_F_VID)
94 		NLA_PUT_U16(msg, TCA_VLAN_PUSH_VLAN_ID, v->v_vid);
95 
96 	if (v->v_flags & VLAN_F_PROTO)
97 		NLA_PUT_U16(msg, TCA_VLAN_PUSH_VLAN_PROTOCOL, v->v_proto);
98 
99 	if (v->v_flags & VLAN_F_PRIO)
100 		NLA_PUT_U8(msg, TCA_VLAN_PUSH_VLAN_PRIORITY, v->v_prio);
101 
102 	return 0;
103 
104 nla_put_failure:
105 	return -NLE_NOMEM;
106 }
107 
vlan_free_data(struct rtnl_tc * tc,void * data)108 static void vlan_free_data(struct rtnl_tc *tc, void *data)
109 {
110 }
111 
vlan_clone(void * _dst,void * _src)112 static int vlan_clone(void *_dst, void *_src)
113 {
114 	struct rtnl_vlan *dst = _dst, *src = _src;
115 
116 	memcpy(&dst->v_parm, &src->v_parm, sizeof(src->v_parm));
117 	return 0;
118 }
119 
vlan_dump_line(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)120 static void vlan_dump_line(struct rtnl_tc *tc, void *data,
121                            struct nl_dump_params *p)
122 {
123 	struct rtnl_vlan *v = data;
124 
125 	if (!v)
126 		return;
127 
128 	if (!(v->v_flags & VLAN_F_ACT))
129 		return;
130 
131 	if (TC_ACT_EXT_CMP(v->v_parm.action, TC_ACT_GOTO_CHAIN))
132 		nl_dump(p, " goto chain %u", v->v_parm.action & TC_ACT_EXT_VAL_MASK);
133 
134 	if (TC_ACT_EXT_CMP(v->v_parm.action, TC_ACT_JUMP))
135 		nl_dump(p, " jump %u", v->v_parm.action & TC_ACT_EXT_VAL_MASK);
136 
137 	switch(v->v_parm.action){
138 	case TC_ACT_UNSPEC:
139 		nl_dump(p, " unspecified");
140 		break;
141 	case TC_ACT_PIPE:
142 		nl_dump(p, " pipe");
143 		break;
144 	case TC_ACT_STOLEN:
145 		nl_dump(p, " stolen");
146 		break;
147 	case TC_ACT_SHOT:
148 		nl_dump(p, " shot");
149 		break;
150 	case TC_ACT_QUEUED:
151 		nl_dump(p, " queued");
152 		break;
153 	case TC_ACT_REPEAT:
154 		nl_dump(p, " repeat");
155 		break;
156 	}
157 }
158 
vlan_dump_details(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)159 static void vlan_dump_details(struct rtnl_tc *tc, void *data,
160                               struct nl_dump_params *p)
161 {
162 	struct rtnl_vlan *v = data;
163 
164 	if (!v)
165 		return;
166 
167 	if (v->v_flags & VLAN_F_MODE) {
168 		switch (v->v_parm.v_action) {
169 		case TCA_VLAN_ACT_POP:
170 			nl_dump(p, " mode POP");
171 			break;
172 		case TCA_VLAN_ACT_PUSH:
173 			nl_dump(p, " mode PUSH");
174 			break;
175 		case TCA_VLAN_ACT_MODIFY:
176 			nl_dump(p, " mode MODIFY");
177 			break;
178 		}
179 	}
180 
181 	if (v->v_flags & VLAN_F_VID)
182 		nl_dump(p, " vlan id %u", v->v_vid);
183 
184 	if (v->v_flags & VLAN_F_PRIO)
185 		nl_dump(p, " priority %u", v->v_prio);
186 
187 	if (v->v_flags & VLAN_F_PROTO)
188 		nl_dump(p, " protocol %u", v->v_proto);
189 }
190 
191 /**
192  * @name Attribute Modifications
193  * @{
194  */
195 
196 /**
197  * Set vlan mode
198  * @arg act             vlan action
199  * @arg mode            one of (TCA_VLAN_ACT_*: POP, PUSH, MODIFY)
200  * @return 0 on success or a negative error code.
201  */
rtnl_vlan_set_mode(struct rtnl_act * act,int mode)202 int rtnl_vlan_set_mode(struct rtnl_act *act, int mode)
203 {
204 	struct rtnl_vlan *v;
205 
206 	if (!(v = (struct rtnl_vlan *) rtnl_tc_data(TC_CAST(act))))
207 		return -NLE_NOMEM;
208 
209 	if (mode > TCA_VLAN_ACT_MODIFY)
210 		return -NLE_RANGE;
211 
212 	v->v_parm.v_action = mode;
213 	v->v_flags |= VLAN_F_MODE;
214 
215 	return 0;
216 }
217 
218 /**
219  * Get vlan mode
220  * @arg act             vlan action
221  * @arg out_mode        vlan mode output paramter
222  * @return 0 on success if the vlan mode was returned or a negative error code.
223 */
rtnl_vlan_get_mode(struct rtnl_act * act,int * out_mode)224 int rtnl_vlan_get_mode(struct rtnl_act *act, int *out_mode)
225 {
226 	struct rtnl_vlan *v;
227 
228 	if (!(v = (struct rtnl_vlan *) rtnl_tc_data_peek(TC_CAST(act))))
229 		return -NLE_INVAL;
230 
231 	if (!(v->v_flags & VLAN_F_MODE))
232 		return -NLE_MISSING_ATTR;
233 
234 	*out_mode = v->v_parm.v_action;
235 	return 0;
236 }
237 
238 /**
239  * Set general action
240  * @arg act             vlan action
241  * @arg action          one of (TCA_ACT_*: PIPE, SHOT, GOTO_CHAIN, etc)
242  * @return 0 on success or a negative error code.
243  */
rtnl_vlan_set_action(struct rtnl_act * act,int action)244 int rtnl_vlan_set_action(struct rtnl_act *act, int action)
245 {
246 	struct rtnl_vlan *v;
247 
248 	if (!(v = (struct rtnl_vlan *) rtnl_tc_data(TC_CAST(act))))
249 		return -NLE_NOMEM;
250 
251 	v->v_parm.action = action;
252 	v->v_flags |= VLAN_F_ACT;
253 
254 	return 0;
255 }
256 
257 /**
258  * Get general action
259  * @arg act             vlan action
260  * @arg out_action      output parameter
261  * @return general 0 if out_action was set or a negative error code.
262 */
rtnl_vlan_get_action(struct rtnl_act * act,int * out_action)263 int rtnl_vlan_get_action(struct rtnl_act *act, int *out_action)
264 {
265 	struct rtnl_vlan *v;
266 
267 	if (!(v = (struct rtnl_vlan *) rtnl_tc_data_peek(TC_CAST(act))))
268 		return -NLE_INVAL;
269 
270 	if (!(v->v_flags & VLAN_F_ACT))
271 		return -NLE_MISSING_ATTR;
272 
273 	*out_action = v->v_parm.action;
274 	return 0;
275 }
276 
277 /**
278  * Set protocol
279  * @arg act             vlan action
280  * @arg protocol        one of (ETH_P_8021Q || ETH_P_8021AD)
281  * @return 0 on success or a negative error code.
282  */
rtnl_vlan_set_protocol(struct rtnl_act * act,uint16_t protocol)283 int rtnl_vlan_set_protocol(struct rtnl_act *act, uint16_t protocol)
284 {
285 	struct rtnl_vlan *v;
286 
287 	if (!(v = (struct rtnl_vlan *) rtnl_tc_data(TC_CAST(act))))
288 		return -NLE_NOMEM;
289 
290 	v->v_proto = protocol;
291 	v->v_flags |= VLAN_F_PROTO;
292 
293 	return 0;
294 }
295 
296 /**
297  * Get protocol
298  * @arg act             vlan action
299  * @arg out_protocol    protocol output argument
300  * @return 0 if the protocol was returned or a negative error code.
301 */
rtnl_vlan_get_protocol(struct rtnl_act * act,uint16_t * out_protocol)302 int rtnl_vlan_get_protocol(struct rtnl_act *act, uint16_t *out_protocol)
303 {
304 	struct rtnl_vlan *v;
305 
306 	if (!(v = (struct rtnl_vlan *) rtnl_tc_data_peek(TC_CAST(act))))
307 		return -NLE_INVAL;
308 
309 	if (!(v->v_flags & VLAN_F_PROTO))
310 		return -NLE_MISSING_ATTR;
311 
312 	*out_protocol = v->v_proto;
313 	return 0;
314 }
315 
316 /**
317  * Set vlan id
318  * @arg act             vlan action
319  * @arg vid             vlan id
320  * @return 0 on success or a negative error code.
321  */
rtnl_vlan_set_vlan_id(struct rtnl_act * act,uint16_t vid)322 int rtnl_vlan_set_vlan_id(struct rtnl_act *act, uint16_t vid)
323 {
324 	struct rtnl_vlan *v;
325 
326 	if (!(v = (struct rtnl_vlan *) rtnl_tc_data(TC_CAST(act))))
327 		return -NLE_NOMEM;
328 
329 	if (vid > 4095)
330 		return -NLE_RANGE;
331 
332 	v->v_vid = vid;
333 	v->v_flags |= VLAN_F_VID;
334 
335 	return 0;
336 }
337 
338 /**
339  * Get vlan id
340  * @arg act             vlan action
341  * @arg out_vid         output vlan id
342  * @return 0 if the vlan id was returned or a negative error code.
343 */
rtnl_vlan_get_vlan_id(struct rtnl_act * act,uint16_t * out_vid)344 int rtnl_vlan_get_vlan_id(struct rtnl_act *act, uint16_t *out_vid)
345 {
346 	struct rtnl_vlan *v;
347 
348 	if (!(v = (struct rtnl_vlan *) rtnl_tc_data_peek(TC_CAST(act))))
349 		return -NLE_INVAL;
350 
351 	if (!(v->v_flags & VLAN_F_VID))
352 		return -NLE_MISSING_ATTR;
353 
354 	*out_vid = v->v_vid;
355 	return 0;
356 }
357 
358 /**
359  * Set vlan prio
360  * @arg act             vlan action
361  * @arg prio            vlan priority (0 - 7)
362  * @return 0 on success or a negative error code.
363  */
rtnl_vlan_set_vlan_prio(struct rtnl_act * act,uint8_t prio)364 int rtnl_vlan_set_vlan_prio(struct rtnl_act *act, uint8_t prio)
365 {
366 	struct rtnl_vlan *v;
367 
368 	if (!(v = (struct rtnl_vlan *) rtnl_tc_data(TC_CAST(act))))
369 		return -NLE_NOMEM;
370 
371 	if (prio > 7)
372 		return -NLE_RANGE;
373 
374 	v->v_prio = prio;
375 	v->v_flags |= VLAN_F_PRIO;
376 
377 	return 0;
378 }
379 
380 /**
381  * Get vlan prio
382  * @arg act             vlan action
383  * @arg out_prio        the output vlan prio
384  * @return 0 if the vlan prio was returned or a negative error code.
385 */
rtnl_vlan_get_vlan_prio(struct rtnl_act * act,uint8_t * out_prio)386 int rtnl_vlan_get_vlan_prio(struct rtnl_act *act, uint8_t *out_prio)
387 {
388 	struct rtnl_vlan *v;
389 
390 	if (!(v = (struct rtnl_vlan *) rtnl_tc_data_peek(TC_CAST(act))))
391 		return -NLE_INVAL;
392 
393 	if (!(v->v_flags & VLAN_F_PRIO))
394 		return -NLE_MISSING_ATTR;
395 
396 	*out_prio = v->v_prio;
397 	return 0;
398 }
399 
400 /** @} */
401 
402 static struct rtnl_tc_ops vlan_ops = {
403 	.to_kind                = "vlan",
404 	.to_type                = RTNL_TC_TYPE_ACT,
405 	.to_size                = sizeof(struct rtnl_vlan),
406 	.to_msg_parser          = vlan_msg_parser,
407 	.to_free_data           = vlan_free_data,
408 	.to_clone               = vlan_clone,
409 	.to_msg_fill            = vlan_msg_fill,
410 	.to_dump = {
411 	    [NL_DUMP_LINE]      = vlan_dump_line,
412 	    [NL_DUMP_DETAILS]   = vlan_dump_details,
413 	},
414 };
415 
vlan_init(void)416 static void __init vlan_init(void)
417 {
418 	rtnl_tc_register(&vlan_ops);
419 }
420 
vlan_exit(void)421 static void __exit vlan_exit(void)
422 {
423 	rtnl_tc_unregister(&vlan_ops);
424 }
425 
426 /** @} */
427