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