libnl  3.5.0
vlan.c
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 
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 
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 
108 static void vlan_free_data(struct rtnl_tc *tc, void *data)
109 {
110 }
111 
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 
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 
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  */
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 */
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  */
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 */
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  */
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 */
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  */
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 */
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  */
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 */
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 
416 static void __init vlan_init(void)
417 {
418  rtnl_tc_register(&vlan_ops);
419 }
420 
421 static void __exit vlan_exit(void)
422 {
423  rtnl_tc_unregister(&vlan_ops);
424 }
425 
426 /** @} */
Dump object briefly on one line.
Definition: types.h:22
int rtnl_tc_register(struct rtnl_tc_ops *ops)
Register a traffic control module.
Definition: tc.c:1021
8 bit integer
Definition: attr.h:41
int rtnl_vlan_get_action(struct rtnl_act *act, int *out_action)
Get general action.
Definition: vlan.c:263
int rtnl_vlan_get_protocol(struct rtnl_act *act, uint16_t *out_protocol)
Get protocol.
Definition: vlan.c:302
Attribute validation policy.
Definition: attr.h:69
uint8_t nla_get_u8(const struct nlattr *nla)
Return value of 8 bit integer attribute.
Definition: attr.c:607
int rtnl_vlan_set_action(struct rtnl_act *act, int action)
Set general action.
Definition: vlan.c:244
int rtnl_vlan_get_vlan_prio(struct rtnl_act *act, uint8_t *out_prio)
Get vlan prio.
Definition: vlan.c:386
#define NLA_PUT_U8(msg, attrtype, value)
Add 8 bit integer attribute to netlink message.
Definition: attr.h:200
Dump all attributes but no statistics.
Definition: types.h:23
int rtnl_vlan_set_protocol(struct rtnl_act *act, uint16_t protocol)
Set protocol.
Definition: vlan.c:283
int rtnl_vlan_set_vlan_id(struct rtnl_act *act, uint16_t vid)
Set vlan id.
Definition: vlan.c:322
void rtnl_tc_unregister(struct rtnl_tc_ops *ops)
Unregister a traffic control module.
Definition: tc.c:1055
int rtnl_vlan_get_vlan_id(struct rtnl_act *act, uint16_t *out_vid)
Get vlan id.
Definition: vlan.c:344
int nla_memcpy(void *dest, const struct nlattr *src, int count)
Copy attribute payload to another memory area.
Definition: attr.c:354
#define TC_CAST(ptr)
Macro to cast qdisc/class/classifier to tc object.
Definition: tc.h:56
#define NLA_PUT(msg, attrtype, attrlen, data)
Add unspecific attribute to netlink message.
Definition: attr.h:165
16 bit integer
Definition: attr.h:42
int rtnl_vlan_set_mode(struct rtnl_act *act, int mode)
Set vlan mode.
Definition: vlan.c:202
uint16_t minlen
Minimal length of payload required.
Definition: attr.h:74
void * rtnl_tc_data(struct rtnl_tc *tc)
Return pointer to private data of traffic control object.
Definition: tc.c:1082
uint16_t nla_get_u16(const struct nlattr *nla)
Return payload of 16 bit integer attribute.
Definition: attr.c:657
Dumping parameters.
Definition: types.h:33
#define NLA_PUT_U16(msg, attrtype, value)
Add 16 bit integer attribute to netlink message.
Definition: attr.h:218
int rtnl_vlan_set_vlan_prio(struct rtnl_act *act, uint8_t prio)
Set vlan prio.
Definition: vlan.c:364
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
Definition: utils.c:962
void * rtnl_tc_data_peek(struct rtnl_tc *tc)
Returns the private data of the traffic control object.
Definition: tc.c:1068
int rtnl_vlan_get_mode(struct rtnl_act *act, int *out_mode)
Get vlan mode.
Definition: vlan.c:224