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