libnl  3.6.0
flower.c
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * Copyright (c) 2018 Volodymyr Bendiuga <volodymyr.bendiuga@gmail.com>
4  */
5 
6 #include <netlink-private/netlink.h>
7 #include <netlink-private/tc.h>
8 #include <netlink/netlink.h>
9 #include <netlink/attr.h>
10 #include <netlink/utils.h>
11 #include <netlink-private/route/tc-api.h>
12 #include <netlink/route/classifier.h>
13 #include <netlink/route/action.h>
14 #include <netlink/route/cls/flower.h>
15 
16 
17 /** @cond SKIP */
18 #define FLOWER_ATTR_FLAGS (1 << 0)
19 #define FLOWER_ATTR_ACTION (1 << 1)
20 #define FLOWER_ATTR_VLAN_ID (1 << 2)
21 #define FLOWER_ATTR_VLAN_PRIO (1 << 3)
22 #define FLOWER_ATTR_VLAN_ETH_TYPE (1 << 4)
23 #define FLOWER_ATTR_DST_MAC (1 << 5)
24 #define FLOWER_ATTR_DST_MAC_MASK (1 << 6)
25 #define FLOWER_ATTR_SRC_MAC (1 << 7)
26 #define FLOWER_ATTR_SRC_MAC_MASK (1 << 8)
27 #define FLOWER_ATTR_IP_DSCP (1 << 9)
28 #define FLOWER_ATTR_IP_DSCP_MASK (1 << 10)
29 #define FLOWER_ATTR_PROTO (1 << 11)
30 /** @endcond */
31 
32 #define FLOWER_DSCP_MAX 0xe0
33 #define FLOWER_DSCP_MASK_MAX 0xe0
34 #define FLOWER_VID_MAX 4095
35 #define FLOWER_VLAN_PRIO_MAX 7
36 
37 static struct nla_policy flower_policy[TCA_FLOWER_MAX + 1] = {
38  [TCA_FLOWER_FLAGS] = { .type = NLA_U32 },
39  [TCA_FLOWER_KEY_ETH_TYPE] = { .type = NLA_U16 },
40  [TCA_FLOWER_KEY_ETH_DST] = { .maxlen = ETH_ALEN },
41  [TCA_FLOWER_KEY_ETH_DST_MASK] = { .maxlen = ETH_ALEN },
42  [TCA_FLOWER_KEY_ETH_SRC] = { .maxlen = ETH_ALEN },
43  [TCA_FLOWER_KEY_ETH_SRC_MASK] = { .maxlen = ETH_ALEN },
44  [TCA_FLOWER_KEY_VLAN_ID] = { .type = NLA_U16 },
45  [TCA_FLOWER_KEY_VLAN_PRIO] = { .type = NLA_U8 },
46  [TCA_FLOWER_KEY_IP_TOS] = { .type = NLA_U8 },
47  [TCA_FLOWER_KEY_IP_TOS_MASK] = { .type = NLA_U8 },
48  [TCA_FLOWER_KEY_VLAN_ETH_TYPE] = { .type = NLA_U16 },
49 };
50 
51 static int flower_msg_parser(struct rtnl_tc *tc, void *data)
52 {
53  struct rtnl_flower *f = data;
54  struct nlattr *tb[TCA_FLOWER_MAX + 1];
55  int err;
56 
57  err = tca_parse(tb, TCA_FLOWER_MAX, tc, flower_policy);
58  if (err < 0)
59  return err;
60 
61  if (tb[TCA_FLOWER_FLAGS]) {
62  f->cf_flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]);
63  f->cf_mask |= FLOWER_ATTR_FLAGS;
64  }
65 
66  if (tb[TCA_FLOWER_ACT]) {
67  err = rtnl_act_parse(&f->cf_act, tb[TCA_FLOWER_ACT]);
68  if (err)
69  return err;
70 
71  f->cf_mask |= FLOWER_ATTR_ACTION;
72  }
73 
74  if (tb[TCA_FLOWER_KEY_ETH_TYPE]) {
75  f->cf_proto = nla_get_u16(tb[TCA_FLOWER_KEY_ETH_TYPE]);
76  f->cf_mask |= FLOWER_ATTR_PROTO;
77  }
78 
79  if (tb[TCA_FLOWER_KEY_VLAN_ID]) {
80  f->cf_vlan_id = nla_get_u16(tb[TCA_FLOWER_KEY_VLAN_ID]);
81  f->cf_mask |= FLOWER_ATTR_VLAN_ID;
82  }
83 
84  if (tb[TCA_FLOWER_KEY_VLAN_PRIO]) {
85  f->cf_vlan_prio = nla_get_u8(tb[TCA_FLOWER_KEY_VLAN_PRIO]);
86  f->cf_mask |= FLOWER_ATTR_VLAN_PRIO;
87  }
88 
89  if (tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]) {
90  f->cf_vlan_ethtype = nla_get_u16(tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]);
91  f->cf_mask |= FLOWER_ATTR_VLAN_ETH_TYPE;
92  }
93 
94  if (tb[TCA_FLOWER_KEY_ETH_DST]) {
95  nla_memcpy(f->cf_dst_mac, tb[TCA_FLOWER_KEY_ETH_DST], ETH_ALEN);
96  f->cf_mask |= FLOWER_ATTR_DST_MAC;
97  }
98 
99  if (tb[TCA_FLOWER_KEY_ETH_DST_MASK]) {
100  nla_memcpy(f->cf_dst_mac_mask, tb[TCA_FLOWER_KEY_ETH_DST_MASK], ETH_ALEN);
101  f->cf_mask |= FLOWER_ATTR_DST_MAC_MASK;
102  }
103 
104  if (tb[TCA_FLOWER_KEY_ETH_SRC]) {
105  nla_memcpy(f->cf_src_mac, tb[TCA_FLOWER_KEY_ETH_SRC], ETH_ALEN);
106  f->cf_mask |= FLOWER_ATTR_SRC_MAC;
107  }
108 
109  if (tb[TCA_FLOWER_KEY_ETH_SRC_MASK]) {
110  nla_memcpy(f->cf_src_mac_mask, tb[TCA_FLOWER_KEY_ETH_SRC_MASK], ETH_ALEN);
111  f->cf_mask |= FLOWER_ATTR_SRC_MAC_MASK;
112  }
113 
114  if (tb[TCA_FLOWER_KEY_IP_TOS]) {
115  f->cf_ip_dscp = nla_get_u8(tb[TCA_FLOWER_KEY_IP_TOS]);
116  f->cf_mask |= FLOWER_ATTR_IP_DSCP;
117  }
118 
119  if (tb[TCA_FLOWER_KEY_IP_TOS_MASK]) {
120  f->cf_ip_dscp_mask = nla_get_u8(tb[TCA_FLOWER_KEY_IP_TOS_MASK]);
121  f->cf_mask |= FLOWER_ATTR_IP_DSCP_MASK;
122  }
123 
124  return 0;
125 }
126 
127 static int flower_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
128 {
129  struct rtnl_flower *f = data;
130  int err;
131 
132  if (!f)
133  return 0;
134 
135  if (f->cf_mask & FLOWER_ATTR_FLAGS)
136  NLA_PUT_U32(msg, TCA_FLOWER_FLAGS, f->cf_mask);
137 
138  if (f->cf_mask & FLOWER_ATTR_ACTION) {
139  err = rtnl_act_fill(msg, TCA_FLOWER_ACT, f->cf_act);
140  if (err)
141  return err;
142  }
143 
144  if (f->cf_mask & FLOWER_ATTR_PROTO)
145  NLA_PUT_U16(msg, TCA_FLOWER_KEY_ETH_TYPE, f->cf_proto);
146 
147  if (f->cf_mask & FLOWER_ATTR_VLAN_ID)
148  NLA_PUT_U16(msg, TCA_FLOWER_KEY_VLAN_ID, f->cf_vlan_id);
149 
150  if (f->cf_mask & FLOWER_ATTR_VLAN_PRIO)
151  NLA_PUT_U8(msg, TCA_FLOWER_KEY_VLAN_PRIO, f->cf_vlan_prio);
152 
153  if (f->cf_mask & FLOWER_ATTR_VLAN_ETH_TYPE)
154  NLA_PUT_U16(msg, TCA_FLOWER_KEY_VLAN_ETH_TYPE, f->cf_vlan_ethtype);
155 
156  if (f->cf_mask & FLOWER_ATTR_DST_MAC)
157  NLA_PUT(msg, TCA_FLOWER_KEY_ETH_DST, ETH_ALEN, f->cf_dst_mac);
158 
159  if (f->cf_mask & FLOWER_ATTR_DST_MAC_MASK)
160  NLA_PUT(msg, TCA_FLOWER_KEY_ETH_DST_MASK, ETH_ALEN, f->cf_dst_mac_mask);
161 
162  if (f->cf_mask & FLOWER_ATTR_SRC_MAC)
163  NLA_PUT(msg, TCA_FLOWER_KEY_ETH_SRC, ETH_ALEN, f->cf_src_mac);
164 
165  if (f->cf_mask & FLOWER_ATTR_SRC_MAC_MASK)
166  NLA_PUT(msg, TCA_FLOWER_KEY_ETH_SRC_MASK, ETH_ALEN, f->cf_src_mac_mask);
167 
168  if (f->cf_mask & FLOWER_ATTR_IP_DSCP)
169  NLA_PUT_U8(msg, TCA_FLOWER_KEY_IP_TOS, f->cf_ip_dscp);
170 
171  if (f->cf_mask & FLOWER_ATTR_IP_DSCP_MASK)
172  NLA_PUT_U8(msg, TCA_FLOWER_KEY_IP_TOS_MASK, f->cf_ip_dscp_mask);
173 
174  return 0;
175 
176 nla_put_failure:
177  return -NLE_NOMEM;
178 }
179 
180 static void flower_free_data(struct rtnl_tc *tc, void *data)
181 {
182  struct rtnl_flower *f = data;
183 
184  if (f->cf_act)
185  rtnl_act_put_all(&f->cf_act);
186 }
187 
188 static int flower_clone(void *_dst, void *_src)
189 {
190  struct rtnl_flower *dst = _dst, *src = _src;
191 
192  if (src->cf_act) {
193  if (!(dst->cf_act = rtnl_act_alloc()))
194  return -NLE_NOMEM;
195 
196  memcpy(dst->cf_act, src->cf_act, sizeof(struct rtnl_act));
197 
198  /* action nl list next and prev pointers must be updated */
199  nl_init_list_head(&dst->cf_act->ce_list);
200 
201  if ( src->cf_act->c_opts
202  && !(dst->cf_act->c_opts = nl_data_clone(src->cf_act->c_opts)))
203  return -NLE_NOMEM;
204 
205  if ( src->cf_act->c_xstats
206  && !(dst->cf_act->c_xstats = nl_data_clone(src->cf_act->c_xstats)))
207  return -NLE_NOMEM;
208 
209  if ( src->cf_act->c_subdata
210  && !(dst->cf_act->c_subdata = nl_data_clone(src->cf_act->c_subdata)))
211  return -NLE_NOMEM;
212 
213  if (dst->cf_act->c_link) {
214  nl_object_get(OBJ_CAST(dst->cf_act->c_link));
215  }
216 
217  dst->cf_act->a_next = NULL; /* Only clone first in chain */
218  }
219 
220  return 0;
221 }
222 
223 static void flower_dump_details(struct rtnl_tc *tc, void *data,
224  struct nl_dump_params *p)
225 {
226  struct rtnl_flower *f = data;
227 
228  if (!f)
229  return;
230 
231  if (f->cf_mask & FLOWER_ATTR_FLAGS)
232  nl_dump(p, " flags %u", f->cf_flags);
233 
234  if (f->cf_mask & FLOWER_ATTR_PROTO)
235  nl_dump(p, " protocol %u", f->cf_proto);
236 
237  if (f->cf_mask & FLOWER_ATTR_VLAN_ID)
238  nl_dump(p, " vlan_id %u", f->cf_vlan_id);
239 
240  if (f->cf_mask & FLOWER_ATTR_VLAN_PRIO)
241  nl_dump(p, " vlan_prio %u", f->cf_vlan_prio);
242 
243  if (f->cf_mask & FLOWER_ATTR_VLAN_ETH_TYPE)
244  nl_dump(p, " vlan_ethtype %u", f->cf_vlan_ethtype);
245 
246  if (f->cf_mask & FLOWER_ATTR_DST_MAC)
247  nl_dump(p, " dst_mac %02x:%02x:%02x:%02x:%02x:%02x",
248  f->cf_dst_mac[0], f->cf_dst_mac[1],
249  f->cf_dst_mac[2], f->cf_dst_mac[3],
250  f->cf_dst_mac[4], f->cf_dst_mac[5]);
251 
252  if (f->cf_mask & FLOWER_ATTR_DST_MAC_MASK)
253  nl_dump(p, " dst_mac_mask %02x:%02x:%02x:%02x:%02x:%02x",
254  f->cf_dst_mac_mask[0], f->cf_dst_mac_mask[1],
255  f->cf_dst_mac_mask[2], f->cf_dst_mac_mask[3],
256  f->cf_dst_mac_mask[4], f->cf_dst_mac_mask[5]);
257 
258  if (f->cf_mask & FLOWER_ATTR_SRC_MAC)
259  nl_dump(p, " src_mac %02x:%02x:%02x:%02x:%02x:%02x",
260  f->cf_src_mac[0], f->cf_src_mac[1],
261  f->cf_src_mac[2], f->cf_src_mac[3],
262  f->cf_src_mac[4], f->cf_src_mac[5]);
263 
264  if (f->cf_mask & FLOWER_ATTR_SRC_MAC_MASK)
265  nl_dump(p, " src_mac_mask %02x:%02x:%02x:%02x:%02x:%02x",
266  f->cf_src_mac_mask[0], f->cf_src_mac_mask[1],
267  f->cf_src_mac_mask[2], f->cf_src_mac_mask[3],
268  f->cf_src_mac_mask[4], f->cf_src_mac_mask[5]);
269 
270  if (f->cf_mask & FLOWER_ATTR_IP_DSCP)
271  nl_dump(p, " dscp %u", f->cf_ip_dscp);
272 
273  if (f->cf_mask & FLOWER_ATTR_IP_DSCP_MASK)
274  nl_dump(p, " dscp_mask %u", f->cf_ip_dscp_mask);
275 }
276 
277 /**
278  * @name Attribute Modification
279  * @{
280  */
281 
282 /**
283  * Set protocol for flower classifier
284  * @arg cls Flower classifier.
285  * @arg proto protocol (ETH_P_*)
286  * @return 0 on success or a negative error code.
287  */
288 int rtnl_flower_set_proto(struct rtnl_cls *cls, uint16_t proto)
289 {
290  struct rtnl_flower *f;
291 
292  if (!(f = rtnl_tc_data(TC_CAST(cls))))
293  return -NLE_NOMEM;
294 
295  f->cf_proto = htons(proto);
296  f->cf_mask |= FLOWER_ATTR_PROTO;
297 
298  return 0;
299 }
300 
301 /**
302  * Get protocol for flower classifier
303  * @arg cls Flower classifier.
304  * @arg proto protocol
305  * @return 0 on success or a negative error code.
306 */
307 int rtnl_flower_get_proto(struct rtnl_cls *cls, uint16_t *proto)
308 {
309  struct rtnl_flower *f;
310 
311  if (!(f = rtnl_tc_data_peek(TC_CAST(cls))))
312  return -NLE_INVAL;
313 
314  if (!(f->cf_mask & FLOWER_ATTR_PROTO))
315  return -NLE_MISSING_ATTR;
316 
317  *proto = ntohs(f->cf_proto);
318 
319  return 0;
320 }
321 
322 /**
323  * Set vlan id for flower classifier
324  * @arg cls Flower classifier.
325  * @arg vid vlan id
326  * @return 0 on success or a negative error code.
327  */
328 int rtnl_flower_set_vlan_id(struct rtnl_cls *cls, uint16_t vid)
329 {
330  struct rtnl_flower *f;
331 
332  if (!(f = rtnl_tc_data(TC_CAST(cls))))
333  return -NLE_NOMEM;
334 
335  if (vid > FLOWER_VID_MAX)
336  return -NLE_RANGE;
337 
338  f->cf_vlan_id = vid;
339  f->cf_mask |= FLOWER_ATTR_VLAN_ID;
340 
341  return 0;
342 }
343 
344 /**
345  * Get vlan id for flower classifier
346  * @arg cls Flower classifier.
347  * @arg vid vlan id
348  * @return 0 on success or a negative error code.
349 */
350 int rtnl_flower_get_vlan_id(struct rtnl_cls *cls, uint16_t *vid)
351 {
352  struct rtnl_flower *f;
353 
354  if (!(f = rtnl_tc_data_peek(TC_CAST(cls))))
355  return -NLE_INVAL;
356 
357  if (!(f->cf_mask & FLOWER_ATTR_VLAN_ID))
358  return -NLE_MISSING_ATTR;
359 
360  *vid = f->cf_vlan_id;
361 
362  return 0;
363 }
364 
365 /**
366  * Set vlan priority for flower classifier
367  * @arg cls Flower classifier.
368  * @arg prio vlan priority
369  * @return 0 on success or a negative error code.
370  */
371 int rtnl_flower_set_vlan_prio(struct rtnl_cls *cls, uint8_t prio)
372 {
373  struct rtnl_flower *f;
374 
375  if (!(f = rtnl_tc_data(TC_CAST(cls))))
376  return -NLE_NOMEM;
377 
378  if (prio > FLOWER_VLAN_PRIO_MAX)
379  return -NLE_RANGE;
380 
381  f->cf_vlan_prio = prio;
382  f->cf_mask |= FLOWER_ATTR_VLAN_PRIO;
383 
384  return 0;
385 }
386 
387 /**
388  * Get vlan prio for flower classifier
389  * @arg cls Flower classifier.
390  * @arg prio vlan priority
391  * @return 0 on success or a negative error code.
392 */
393 int rtnl_flower_get_vlan_prio(struct rtnl_cls *cls, uint8_t *prio)
394 {
395  struct rtnl_flower *f;
396 
397  if (!(f = rtnl_tc_data_peek(TC_CAST(cls))))
398  return -NLE_INVAL;
399 
400  if (!(f->cf_mask & FLOWER_ATTR_VLAN_PRIO))
401  return -NLE_MISSING_ATTR;
402 
403  *prio = f->cf_vlan_prio;
404 
405  return 0;
406 }
407 
408 /**
409  * Set vlan ethertype for flower classifier
410  * @arg cls Flower classifier.
411  * @arg ethtype vlan ethertype
412  * @return 0 on success or a negative error code.
413  */
414 int rtnl_flower_set_vlan_ethtype(struct rtnl_cls *cls, uint16_t ethtype)
415 {
416  struct rtnl_flower *f;
417 
418  if (!(f = rtnl_tc_data(TC_CAST(cls))))
419  return -NLE_NOMEM;
420 
421  if (!(f->cf_mask & FLOWER_ATTR_PROTO))
422  return -NLE_MISSING_ATTR;
423 
424  if (f->cf_proto != htons(ETH_P_8021Q))
425  return -NLE_INVAL;
426 
427  f->cf_vlan_ethtype = htons(ethtype);
428  f->cf_mask |= FLOWER_ATTR_VLAN_ETH_TYPE;
429 
430  return 0;
431 }
432 
433 /**
434  * Set destination mac address for flower classifier
435  * @arg cls Flower classifier.
436  * @arg mac destination mac address
437  * @arg mask mask for mac address
438  * @return 0 on success or a negative error code.
439  */
440 int rtnl_flower_set_dst_mac(struct rtnl_cls *cls, unsigned char *mac,
441  unsigned char *mask)
442 {
443  struct rtnl_flower *f;
444 
445  if (!(f = rtnl_tc_data(TC_CAST(cls))))
446  return -NLE_NOMEM;
447 
448  if (mac) {
449  memcpy(f->cf_dst_mac, mac, ETH_ALEN);
450  f->cf_mask |= FLOWER_ATTR_DST_MAC;
451 
452  if (mask) {
453  memcpy(f->cf_dst_mac_mask, mask, ETH_ALEN);
454  f->cf_mask |= FLOWER_ATTR_DST_MAC_MASK;
455  }
456 
457  return 0;
458  }
459 
460  return -NLE_FAILURE;
461 }
462 
463 /**
464  * Get destination mac address for flower classifier
465  * @arg cls Flower classifier.
466  * @arg mac destination mac address
467  * @arg mask mask for mac address
468  * @return 0 on success or a negative error code.
469 */
470 int rtnl_flower_get_dst_mac(struct rtnl_cls *cls, unsigned char *mac,
471  unsigned char *mask)
472 {
473  struct rtnl_flower *f;
474 
475  if (!(f = rtnl_tc_data_peek(TC_CAST(cls))))
476  return -NLE_INVAL;
477 
478  if (!(f->cf_mask & FLOWER_ATTR_DST_MAC))
479  return -NLE_MISSING_ATTR;
480 
481  if (mac)
482  memcpy(mac, f->cf_dst_mac, ETH_ALEN);
483 
484  if (mask)
485  memcpy(mask, f->cf_dst_mac_mask, ETH_ALEN);
486 
487  return 0;
488 }
489 
490 /**
491  * Set source mac address for flower classifier
492  * @arg cls Flower classifier.
493  * @arg mac source mac address
494  * @arg mask mask for mac address
495  * @return 0 on success or a negative error code.
496  */
497 int rtnl_flower_set_src_mac(struct rtnl_cls *cls, unsigned char *mac,
498  unsigned char *mask)
499 {
500  struct rtnl_flower *f;
501 
502  if (!(f = rtnl_tc_data(TC_CAST(cls))))
503  return -NLE_NOMEM;
504 
505  if (mac) {
506  memcpy(f->cf_src_mac, mac, ETH_ALEN);
507  f->cf_mask |= FLOWER_ATTR_SRC_MAC;
508 
509  if (mask) {
510  memcpy(f->cf_src_mac_mask, mask, ETH_ALEN);
511  f->cf_mask |= FLOWER_ATTR_SRC_MAC_MASK;
512  }
513 
514  return 0;
515  }
516 
517  return -NLE_FAILURE;
518 }
519 
520 /**
521  * Get source mac address for flower classifier
522  * @arg cls Flower classifier.
523  * @arg mac source mac address
524  * @arg mask mask for mac address
525  * @return 0 on success or a negative error code.
526 */
527 int rtnl_flower_get_src_mac(struct rtnl_cls *cls, unsigned char *mac,
528  unsigned char *mask)
529 {
530  struct rtnl_flower *f;
531 
532  if (!(f = rtnl_tc_data_peek(TC_CAST(cls))))
533  return -NLE_INVAL;
534 
535  if (!(f->cf_mask & FLOWER_ATTR_SRC_MAC))
536  return -NLE_MISSING_ATTR;
537 
538  if (mac)
539  memcpy(mac, f->cf_src_mac, ETH_ALEN);
540 
541  if (mask)
542  memcpy(mask, f->cf_src_mac_mask, ETH_ALEN);
543 
544  return 0;
545 }
546 
547 /**
548  * Set dscp value for flower classifier
549  * @arg cls Flower classifier.
550  * @arg dscp dscp value
551  * @arg mask mask for dscp value
552  * @return 0 on success or a negative error code.
553  */
554 int rtnl_flower_set_ip_dscp(struct rtnl_cls *cls, uint8_t dscp, uint8_t mask)
555 {
556  struct rtnl_flower *f;
557 
558  if (!(f = rtnl_tc_data(TC_CAST(cls))))
559  return -NLE_NOMEM;
560 
561  if (dscp > FLOWER_DSCP_MAX)
562  return -NLE_RANGE;
563 
564  if (mask > FLOWER_DSCP_MASK_MAX)
565  return -NLE_RANGE;
566 
567  f->cf_ip_dscp = dscp;
568  f->cf_mask |= FLOWER_ATTR_IP_DSCP;
569 
570  if (mask) {
571  f->cf_ip_dscp_mask = mask;
572  f->cf_mask |= FLOWER_ATTR_IP_DSCP_MASK;
573  }
574 
575  return 0;
576 }
577 
578 /**
579  * Get dscp value for flower classifier
580  * @arg cls Flower classifier.
581  * @arg dscp dscp value
582  * @arg mask mask for dscp value
583  * @return 0 on success or a negative error code.
584 */
585 int rtnl_flower_get_ip_dscp(struct rtnl_cls *cls, uint8_t *dscp, uint8_t *mask)
586 {
587  struct rtnl_flower *f;
588 
589  if (!(f = rtnl_tc_data_peek(TC_CAST(cls))))
590  return -NLE_INVAL;
591 
592  if (!(f->cf_mask & FLOWER_ATTR_IP_DSCP))
593  return -NLE_MISSING_ATTR;
594 
595  *dscp = f->cf_ip_dscp;
596  *mask = f->cf_ip_dscp_mask;
597 
598  return 0;
599 }
600 
601 /**
602  * Append action for flower classifier
603  * @arg cls Flower classifier.
604  * @arg act action to append
605  * @return 0 on success or a negative error code.
606  */
607 int rtnl_flower_append_action(struct rtnl_cls *cls, struct rtnl_act *act)
608 {
609  struct rtnl_flower *f;
610 
611  if (!act)
612  return 0;
613 
614  if (!(f = rtnl_tc_data(TC_CAST(cls))))
615  return -NLE_NOMEM;
616 
617  f->cf_mask |= FLOWER_ATTR_ACTION;
618 
619  rtnl_act_get(act);
620  return rtnl_act_append(&f->cf_act, act);
621 }
622 
623 /**
624  * Delete action from flower classifier
625  * @arg cls Flower classifier.
626  * @arg act action to delete
627  * @return 0 on success or a negative error code.
628  */
629 int rtnl_flower_del_action(struct rtnl_cls *cls, struct rtnl_act *act)
630 {
631  struct rtnl_flower *f;
632  int ret;
633 
634  if (!act)
635  return 0;
636 
637  if (!(f = rtnl_tc_data(TC_CAST(cls))))
638  return -NLE_NOMEM;
639 
640  if (!(f->cf_mask & FLOWER_ATTR_ACTION))
641  return -NLE_INVAL;
642 
643  ret = rtnl_act_remove(&f->cf_act, act);
644  if (ret)
645  return ret;
646 
647  if (!f->cf_act)
648  f->cf_mask &= ~FLOWER_ATTR_ACTION;
649  rtnl_act_put(act);
650 
651  return 0;
652 }
653 
654 /**
655  * Get action from flower classifier
656  * @arg cls Flower classifier.
657  * @return action on success or NULL on error.
658  */
659 struct rtnl_act* rtnl_flower_get_action(struct rtnl_cls *cls)
660 {
661  struct rtnl_flower *f;
662 
663  if (!(f = rtnl_tc_data_peek(TC_CAST(cls))))
664  return NULL;
665 
666  if (!(f->cf_mask & FLOWER_ATTR_ACTION))
667  return NULL;
668 
669  rtnl_act_get(f->cf_act);
670 
671  return f->cf_act;
672 }
673 
674 /**
675  * Set flags for flower classifier
676  * @arg cls Flower classifier.
677  * @arg flags (TCA_CLS_FLAGS_SKIP_HW | TCA_CLS_FLAGS_SKIP_SW)
678  * @return 0 on success or a negative error code.
679  */
680 int rtnl_flower_set_flags(struct rtnl_cls *cls, int flags)
681 {
682  struct rtnl_flower *f;
683 
684  if (!(f = rtnl_tc_data(TC_CAST(cls))))
685  return -NLE_NOMEM;
686 
687  f->cf_flags = flags;
688  f->cf_mask |= FLOWER_ATTR_FLAGS;
689 
690  return 0;
691 }
692 
693 /** @} */
694 
695 static struct rtnl_tc_ops flower_ops = {
696  .to_kind = "flower",
697  .to_type = RTNL_TC_TYPE_CLS,
698  .to_size = sizeof(struct rtnl_flower),
699  .to_msg_parser = flower_msg_parser,
700  .to_free_data = flower_free_data,
701  .to_clone = flower_clone,
702  .to_msg_fill = flower_msg_fill,
703  .to_dump = {
704  [NL_DUMP_DETAILS] = flower_dump_details,
705  },
706 };
707 
708 static void __init flower_init(void)
709 {
710  rtnl_tc_register(&flower_ops);
711 }
712 
713 static void __exit flower_exit(void)
714 {
715  rtnl_tc_unregister(&flower_ops);
716 }
uint32_t nla_get_u32(const struct nlattr *nla)
Return payload of 32 bit integer attribute.
Definition: attr.c:699
uint16_t nla_get_u16(const struct nlattr *nla)
Return payload of 16 bit integer attribute.
Definition: attr.c:649
#define NLA_PUT_U16(msg, attrtype, value)
Add 16 bit integer attribute to netlink message.
Definition: attr.h:212
#define NLA_PUT_U8(msg, attrtype, value)
Add 8 bit integer attribute to netlink message.
Definition: attr.h:194
#define NLA_PUT(msg, attrtype, attrlen, data)
Add unspecific attribute to netlink message.
Definition: attr.h:159
#define NLA_PUT_U32(msg, attrtype, value)
Add 32 bit integer attribute to netlink message.
Definition: attr.h:230
uint8_t nla_get_u8(const struct nlattr *nla)
Return value of 8 bit integer attribute.
Definition: attr.c:599
int nla_memcpy(void *dest, const struct nlattr *src, int count)
Copy attribute payload to another memory area.
Definition: attr.c:346
@ NLA_U8
8 bit integer
Definition: attr.h:35
@ NLA_U16
16 bit integer
Definition: attr.h:36
@ NLA_U32
32 bit integer
Definition: attr.h:37
struct nl_data * nl_data_clone(const struct nl_data *src)
Clone an abstract data object.
Definition: data.c:89
void nl_object_get(struct nl_object *obj)
Acquire a reference on a object.
Definition: object.c:203
void * rtnl_tc_data(struct rtnl_tc *tc)
Return pointer to private data of traffic control object.
Definition: tc.c:1079
void * rtnl_tc_data_peek(struct rtnl_tc *tc)
Returns the private data of the traffic control object.
Definition: tc.c:1065
#define TC_CAST(ptr)
Macro to cast qdisc/class/classifier to tc object.
Definition: tc.h:50
int rtnl_tc_register(struct rtnl_tc_ops *ops)
Register a traffic control module.
Definition: tc.c:1018
void rtnl_tc_unregister(struct rtnl_tc_ops *ops)
Unregister a traffic control module.
Definition: tc.c:1052
void nl_dump(struct nl_dump_params *params, const char *fmt,...)
Dump a formatted character string.
Definition: utils.c:955
@ NL_DUMP_DETAILS
Dump all attributes but no statistics.
Definition: types.h:17
Dumping parameters.
Definition: types.h:28
Attribute validation policy.
Definition: attr.h:63
uint16_t type
Type of attribute or NLA_UNSPEC.
Definition: attr.h:65