libnl  3.7.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 #define FLOWER_ATTR_IPV4_SRC (1 << 12)
31 #define FLOWER_ATTR_IPV4_SRC_MASK (1 << 13)
32 #define FLOWER_ATTR_IPV4_DST (1 << 14)
33 #define FLOWER_ATTR_IPV4_DST_MASK (1 << 15)
34 /** @endcond */
35 
36 #define FLOWER_DSCP_MAX 0xe0
37 #define FLOWER_DSCP_MASK_MAX 0xe0
38 #define FLOWER_VID_MAX 4095
39 #define FLOWER_VLAN_PRIO_MAX 7
40 
41 static struct nla_policy flower_policy[TCA_FLOWER_MAX + 1] = {
42  [TCA_FLOWER_FLAGS] = { .type = NLA_U32 },
43  [TCA_FLOWER_KEY_ETH_TYPE] = { .type = NLA_U16 },
44  [TCA_FLOWER_KEY_ETH_DST] = { .maxlen = ETH_ALEN },
45  [TCA_FLOWER_KEY_ETH_DST_MASK] = { .maxlen = ETH_ALEN },
46  [TCA_FLOWER_KEY_ETH_SRC] = { .maxlen = ETH_ALEN },
47  [TCA_FLOWER_KEY_ETH_SRC_MASK] = { .maxlen = ETH_ALEN },
48  [TCA_FLOWER_KEY_VLAN_ID] = { .type = NLA_U16 },
49  [TCA_FLOWER_KEY_VLAN_PRIO] = { .type = NLA_U8 },
50  [TCA_FLOWER_KEY_IP_TOS] = { .type = NLA_U8 },
51  [TCA_FLOWER_KEY_IP_TOS_MASK] = { .type = NLA_U8 },
52  [TCA_FLOWER_KEY_VLAN_ETH_TYPE] = { .type = NLA_U16 },
53  [TCA_FLOWER_KEY_IPV4_SRC] = { .type = NLA_U32 },
54  [TCA_FLOWER_KEY_IPV4_SRC_MASK] = { .type = NLA_U32 },
55  [TCA_FLOWER_KEY_IPV4_DST] = { .type = NLA_U32 },
56  [TCA_FLOWER_KEY_IPV4_DST_MASK] = { .type = NLA_U32 },
57 };
58 
59 static int flower_msg_parser(struct rtnl_tc *tc, void *data)
60 {
61  struct rtnl_flower *f = data;
62  struct nlattr *tb[TCA_FLOWER_MAX + 1];
63  int err;
64 
65  err = tca_parse(tb, TCA_FLOWER_MAX, tc, flower_policy);
66  if (err < 0)
67  return err;
68 
69  if (tb[TCA_FLOWER_FLAGS]) {
70  f->cf_flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]);
71  f->cf_mask |= FLOWER_ATTR_FLAGS;
72  }
73 
74  if (tb[TCA_FLOWER_ACT]) {
75  err = rtnl_act_parse(&f->cf_act, tb[TCA_FLOWER_ACT]);
76  if (err)
77  return err;
78 
79  f->cf_mask |= FLOWER_ATTR_ACTION;
80  }
81 
82  if (tb[TCA_FLOWER_KEY_ETH_TYPE]) {
83  f->cf_proto = nla_get_u16(tb[TCA_FLOWER_KEY_ETH_TYPE]);
84  f->cf_mask |= FLOWER_ATTR_PROTO;
85  }
86 
87  if (tb[TCA_FLOWER_KEY_VLAN_ID]) {
88  f->cf_vlan_id = nla_get_u16(tb[TCA_FLOWER_KEY_VLAN_ID]);
89  f->cf_mask |= FLOWER_ATTR_VLAN_ID;
90  }
91 
92  if (tb[TCA_FLOWER_KEY_VLAN_PRIO]) {
93  f->cf_vlan_prio = nla_get_u8(tb[TCA_FLOWER_KEY_VLAN_PRIO]);
94  f->cf_mask |= FLOWER_ATTR_VLAN_PRIO;
95  }
96 
97  if (tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]) {
98  f->cf_vlan_ethtype = nla_get_u16(tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]);
99  f->cf_mask |= FLOWER_ATTR_VLAN_ETH_TYPE;
100  }
101 
102  if (tb[TCA_FLOWER_KEY_ETH_DST]) {
103  nla_memcpy(f->cf_dst_mac, tb[TCA_FLOWER_KEY_ETH_DST], ETH_ALEN);
104  f->cf_mask |= FLOWER_ATTR_DST_MAC;
105  }
106 
107  if (tb[TCA_FLOWER_KEY_ETH_DST_MASK]) {
108  nla_memcpy(f->cf_dst_mac_mask, tb[TCA_FLOWER_KEY_ETH_DST_MASK], ETH_ALEN);
109  f->cf_mask |= FLOWER_ATTR_DST_MAC_MASK;
110  }
111 
112  if (tb[TCA_FLOWER_KEY_ETH_SRC]) {
113  nla_memcpy(f->cf_src_mac, tb[TCA_FLOWER_KEY_ETH_SRC], ETH_ALEN);
114  f->cf_mask |= FLOWER_ATTR_SRC_MAC;
115  }
116 
117  if (tb[TCA_FLOWER_KEY_ETH_SRC_MASK]) {
118  nla_memcpy(f->cf_src_mac_mask, tb[TCA_FLOWER_KEY_ETH_SRC_MASK], ETH_ALEN);
119  f->cf_mask |= FLOWER_ATTR_SRC_MAC_MASK;
120  }
121 
122  if (tb[TCA_FLOWER_KEY_IP_TOS]) {
123  f->cf_ip_dscp = nla_get_u8(tb[TCA_FLOWER_KEY_IP_TOS]);
124  f->cf_mask |= FLOWER_ATTR_IP_DSCP;
125  }
126 
127  if (tb[TCA_FLOWER_KEY_IP_TOS_MASK]) {
128  f->cf_ip_dscp_mask = nla_get_u8(tb[TCA_FLOWER_KEY_IP_TOS_MASK]);
129  f->cf_mask |= FLOWER_ATTR_IP_DSCP_MASK;
130  }
131 
132  if (tb[TCA_FLOWER_KEY_IPV4_SRC]) {
133  f->cf_ipv4_src = nla_get_u32(tb[TCA_FLOWER_KEY_IPV4_SRC]);
134  f->cf_mask |= FLOWER_ATTR_IPV4_SRC;
135  }
136 
137  if (tb[TCA_FLOWER_KEY_IPV4_SRC_MASK]) {
138  f->cf_ipv4_src_mask =
139  nla_get_u32(tb[TCA_FLOWER_KEY_IPV4_SRC_MASK]);
140  f->cf_mask |= FLOWER_ATTR_IPV4_SRC_MASK;
141  }
142 
143  if (tb[TCA_FLOWER_KEY_IPV4_DST]) {
144  f->cf_ipv4_dst = nla_get_u32(tb[TCA_FLOWER_KEY_IPV4_DST]);
145  f->cf_mask |= FLOWER_ATTR_IPV4_DST;
146  }
147 
148  if (tb[TCA_FLOWER_KEY_IPV4_DST_MASK]) {
149  f->cf_ipv4_dst_mask =
150  nla_get_u32(tb[TCA_FLOWER_KEY_IPV4_DST_MASK]);
151  f->cf_mask |= FLOWER_ATTR_IPV4_DST_MASK;
152  }
153 
154  return 0;
155 }
156 
157 static int flower_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
158 {
159  struct rtnl_flower *f = data;
160  int err;
161 
162  if (!f)
163  return 0;
164 
165  if (f->cf_mask & FLOWER_ATTR_FLAGS)
166  NLA_PUT_U32(msg, TCA_FLOWER_FLAGS, f->cf_flags);
167 
168  if (f->cf_mask & FLOWER_ATTR_ACTION) {
169  err = rtnl_act_fill(msg, TCA_FLOWER_ACT, f->cf_act);
170  if (err)
171  return err;
172  }
173 
174  if (f->cf_mask & FLOWER_ATTR_PROTO)
175  NLA_PUT_U16(msg, TCA_FLOWER_KEY_ETH_TYPE, f->cf_proto);
176 
177  if (f->cf_mask & FLOWER_ATTR_VLAN_ID)
178  NLA_PUT_U16(msg, TCA_FLOWER_KEY_VLAN_ID, f->cf_vlan_id);
179 
180  if (f->cf_mask & FLOWER_ATTR_VLAN_PRIO)
181  NLA_PUT_U8(msg, TCA_FLOWER_KEY_VLAN_PRIO, f->cf_vlan_prio);
182 
183  if (f->cf_mask & FLOWER_ATTR_VLAN_ETH_TYPE)
184  NLA_PUT_U16(msg, TCA_FLOWER_KEY_VLAN_ETH_TYPE, f->cf_vlan_ethtype);
185 
186  if (f->cf_mask & FLOWER_ATTR_DST_MAC)
187  NLA_PUT(msg, TCA_FLOWER_KEY_ETH_DST, ETH_ALEN, f->cf_dst_mac);
188 
189  if (f->cf_mask & FLOWER_ATTR_DST_MAC_MASK)
190  NLA_PUT(msg, TCA_FLOWER_KEY_ETH_DST_MASK, ETH_ALEN, f->cf_dst_mac_mask);
191 
192  if (f->cf_mask & FLOWER_ATTR_SRC_MAC)
193  NLA_PUT(msg, TCA_FLOWER_KEY_ETH_SRC, ETH_ALEN, f->cf_src_mac);
194 
195  if (f->cf_mask & FLOWER_ATTR_SRC_MAC_MASK)
196  NLA_PUT(msg, TCA_FLOWER_KEY_ETH_SRC_MASK, ETH_ALEN, f->cf_src_mac_mask);
197 
198  if (f->cf_mask & FLOWER_ATTR_IP_DSCP)
199  NLA_PUT_U8(msg, TCA_FLOWER_KEY_IP_TOS, f->cf_ip_dscp);
200 
201  if (f->cf_mask & FLOWER_ATTR_IP_DSCP_MASK)
202  NLA_PUT_U8(msg, TCA_FLOWER_KEY_IP_TOS_MASK, f->cf_ip_dscp_mask);
203 
204  if (f->cf_mask & FLOWER_ATTR_IPV4_SRC)
205  NLA_PUT_U32(msg, TCA_FLOWER_KEY_IPV4_SRC, f->cf_ipv4_src);
206 
207  if (f->cf_mask & FLOWER_ATTR_IPV4_SRC_MASK)
208  NLA_PUT_U32(msg, TCA_FLOWER_KEY_IPV4_SRC_MASK,
209  f->cf_ipv4_src_mask);
210 
211  if (f->cf_mask & FLOWER_ATTR_IPV4_DST)
212  NLA_PUT_U32(msg, TCA_FLOWER_KEY_IPV4_DST, f->cf_ipv4_dst);
213 
214  if (f->cf_mask & FLOWER_ATTR_IPV4_DST_MASK)
215  NLA_PUT_U32(msg, TCA_FLOWER_KEY_IPV4_DST_MASK,
216  f->cf_ipv4_dst_mask);
217 
218  return 0;
219 
220 nla_put_failure:
221  return -NLE_NOMEM;
222 }
223 
224 static void flower_free_data(struct rtnl_tc *tc, void *data)
225 {
226  struct rtnl_flower *f = data;
227 
228  if (f->cf_act)
229  rtnl_act_put_all(&f->cf_act);
230 }
231 
232 static int flower_clone(void *_dst, void *_src)
233 {
234  struct rtnl_flower *dst = _dst, *src = _src;
235 
236  if (src->cf_act) {
237  if (!(dst->cf_act = rtnl_act_alloc()))
238  return -NLE_NOMEM;
239 
240  memcpy(dst->cf_act, src->cf_act, sizeof(struct rtnl_act));
241 
242  /* action nl list next and prev pointers must be updated */
243  nl_init_list_head(&dst->cf_act->ce_list);
244 
245  if ( src->cf_act->c_opts
246  && !(dst->cf_act->c_opts = nl_data_clone(src->cf_act->c_opts)))
247  return -NLE_NOMEM;
248 
249  if ( src->cf_act->c_xstats
250  && !(dst->cf_act->c_xstats = nl_data_clone(src->cf_act->c_xstats)))
251  return -NLE_NOMEM;
252 
253  if ( src->cf_act->c_subdata
254  && !(dst->cf_act->c_subdata = nl_data_clone(src->cf_act->c_subdata)))
255  return -NLE_NOMEM;
256 
257  if (dst->cf_act->c_link) {
258  nl_object_get(OBJ_CAST(dst->cf_act->c_link));
259  }
260 
261  dst->cf_act->a_next = NULL; /* Only clone first in chain */
262  }
263 
264  return 0;
265 }
266 
267 static void flower_dump_details(struct rtnl_tc *tc, void *data,
268  struct nl_dump_params *p)
269 {
270  struct rtnl_flower *f = data;
271  char addr_str[INET_ADDRSTRLEN];
272  char mask_str[INET_ADDRSTRLEN];
273 
274  if (!f)
275  return;
276 
277  if (f->cf_mask & FLOWER_ATTR_FLAGS)
278  nl_dump(p, " flags %u", f->cf_flags);
279 
280  if (f->cf_mask & FLOWER_ATTR_PROTO)
281  nl_dump(p, " protocol %u", f->cf_proto);
282 
283  if (f->cf_mask & FLOWER_ATTR_VLAN_ID)
284  nl_dump(p, " vlan_id %u", f->cf_vlan_id);
285 
286  if (f->cf_mask & FLOWER_ATTR_VLAN_PRIO)
287  nl_dump(p, " vlan_prio %u", f->cf_vlan_prio);
288 
289  if (f->cf_mask & FLOWER_ATTR_VLAN_ETH_TYPE)
290  nl_dump(p, " vlan_ethtype %u", f->cf_vlan_ethtype);
291 
292  if (f->cf_mask & FLOWER_ATTR_DST_MAC)
293  nl_dump(p, " dst_mac %02x:%02x:%02x:%02x:%02x:%02x",
294  f->cf_dst_mac[0], f->cf_dst_mac[1],
295  f->cf_dst_mac[2], f->cf_dst_mac[3],
296  f->cf_dst_mac[4], f->cf_dst_mac[5]);
297 
298  if (f->cf_mask & FLOWER_ATTR_DST_MAC_MASK)
299  nl_dump(p, " dst_mac_mask %02x:%02x:%02x:%02x:%02x:%02x",
300  f->cf_dst_mac_mask[0], f->cf_dst_mac_mask[1],
301  f->cf_dst_mac_mask[2], f->cf_dst_mac_mask[3],
302  f->cf_dst_mac_mask[4], f->cf_dst_mac_mask[5]);
303 
304  if (f->cf_mask & FLOWER_ATTR_SRC_MAC)
305  nl_dump(p, " src_mac %02x:%02x:%02x:%02x:%02x:%02x",
306  f->cf_src_mac[0], f->cf_src_mac[1],
307  f->cf_src_mac[2], f->cf_src_mac[3],
308  f->cf_src_mac[4], f->cf_src_mac[5]);
309 
310  if (f->cf_mask & FLOWER_ATTR_SRC_MAC_MASK)
311  nl_dump(p, " src_mac_mask %02x:%02x:%02x:%02x:%02x:%02x",
312  f->cf_src_mac_mask[0], f->cf_src_mac_mask[1],
313  f->cf_src_mac_mask[2], f->cf_src_mac_mask[3],
314  f->cf_src_mac_mask[4], f->cf_src_mac_mask[5]);
315 
316  if (f->cf_mask & FLOWER_ATTR_IP_DSCP)
317  nl_dump(p, " dscp %u", f->cf_ip_dscp);
318 
319  if (f->cf_mask & FLOWER_ATTR_IP_DSCP_MASK)
320  nl_dump(p, " dscp_mask %u", f->cf_ip_dscp_mask);
321 
322  if (f->cf_mask & FLOWER_ATTR_IPV4_SRC) {
323  inet_ntop(AF_INET, &f->cf_ipv4_src, addr_str, sizeof(addr_str));
324  inet_ntop(AF_INET, &f->cf_ipv4_src_mask, mask_str, sizeof(mask_str));
325  nl_dump(p, "IPv4 src %s mask %s\n", addr_str, mask_str);
326  }
327 
328  if (f->cf_mask & FLOWER_ATTR_IPV4_DST) {
329  inet_ntop(AF_INET, &f->cf_ipv4_dst, addr_str, sizeof(addr_str));
330  inet_ntop(AF_INET, &f->cf_ipv4_dst_mask, mask_str, sizeof(mask_str));
331  nl_dump(p, "IPv4 dst %s mask %s\n", addr_str, mask_str);
332  }
333 }
334 
335 /**
336  * @name Attribute Modification
337  * @{
338  */
339 
340 /**
341  * Set protocol for flower classifier
342  * @arg cls Flower classifier.
343  * @arg proto protocol (ETH_P_*)
344  * @return 0 on success or a negative error code.
345  */
346 int rtnl_flower_set_proto(struct rtnl_cls *cls, uint16_t proto)
347 {
348  struct rtnl_flower *f;
349 
350  if (!(f = rtnl_tc_data(TC_CAST(cls))))
351  return -NLE_NOMEM;
352 
353  f->cf_proto = htons(proto);
354  f->cf_mask |= FLOWER_ATTR_PROTO;
355 
356  return 0;
357 }
358 
359 /**
360  * Get protocol for flower classifier
361  * @arg cls Flower classifier.
362  * @arg proto protocol
363  * @return 0 on success or a negative error code.
364 */
365 int rtnl_flower_get_proto(struct rtnl_cls *cls, uint16_t *proto)
366 {
367  struct rtnl_flower *f;
368 
369  if (!(f = rtnl_tc_data_peek(TC_CAST(cls))))
370  return -NLE_INVAL;
371 
372  if (!(f->cf_mask & FLOWER_ATTR_PROTO))
373  return -NLE_MISSING_ATTR;
374 
375  *proto = ntohs(f->cf_proto);
376 
377  return 0;
378 }
379 
380 /**
381  * Set vlan id for flower classifier
382  * @arg cls Flower classifier.
383  * @arg vid vlan id
384  * @return 0 on success or a negative error code.
385  */
386 int rtnl_flower_set_vlan_id(struct rtnl_cls *cls, uint16_t vid)
387 {
388  struct rtnl_flower *f;
389 
390  if (!(f = rtnl_tc_data(TC_CAST(cls))))
391  return -NLE_NOMEM;
392 
393  if (vid > FLOWER_VID_MAX)
394  return -NLE_RANGE;
395 
396  f->cf_vlan_id = vid;
397  f->cf_mask |= FLOWER_ATTR_VLAN_ID;
398 
399  return 0;
400 }
401 
402 /**
403  * Get vlan id for flower classifier
404  * @arg cls Flower classifier.
405  * @arg vid vlan id
406  * @return 0 on success or a negative error code.
407 */
408 int rtnl_flower_get_vlan_id(struct rtnl_cls *cls, uint16_t *vid)
409 {
410  struct rtnl_flower *f;
411 
412  if (!(f = rtnl_tc_data_peek(TC_CAST(cls))))
413  return -NLE_INVAL;
414 
415  if (!(f->cf_mask & FLOWER_ATTR_VLAN_ID))
416  return -NLE_MISSING_ATTR;
417 
418  *vid = f->cf_vlan_id;
419 
420  return 0;
421 }
422 
423 /**
424  * Set vlan priority for flower classifier
425  * @arg cls Flower classifier.
426  * @arg prio vlan priority
427  * @return 0 on success or a negative error code.
428  */
429 int rtnl_flower_set_vlan_prio(struct rtnl_cls *cls, uint8_t prio)
430 {
431  struct rtnl_flower *f;
432 
433  if (!(f = rtnl_tc_data(TC_CAST(cls))))
434  return -NLE_NOMEM;
435 
436  if (prio > FLOWER_VLAN_PRIO_MAX)
437  return -NLE_RANGE;
438 
439  f->cf_vlan_prio = prio;
440  f->cf_mask |= FLOWER_ATTR_VLAN_PRIO;
441 
442  return 0;
443 }
444 
445 /**
446  * Get vlan prio for flower classifier
447  * @arg cls Flower classifier.
448  * @arg prio vlan priority
449  * @return 0 on success or a negative error code.
450 */
451 int rtnl_flower_get_vlan_prio(struct rtnl_cls *cls, uint8_t *prio)
452 {
453  struct rtnl_flower *f;
454 
455  if (!(f = rtnl_tc_data_peek(TC_CAST(cls))))
456  return -NLE_INVAL;
457 
458  if (!(f->cf_mask & FLOWER_ATTR_VLAN_PRIO))
459  return -NLE_MISSING_ATTR;
460 
461  *prio = f->cf_vlan_prio;
462 
463  return 0;
464 }
465 
466 /**
467  * Set vlan ethertype for flower classifier
468  * @arg cls Flower classifier.
469  * @arg ethtype vlan ethertype
470  * @return 0 on success or a negative error code.
471  */
472 int rtnl_flower_set_vlan_ethtype(struct rtnl_cls *cls, uint16_t ethtype)
473 {
474  struct rtnl_flower *f;
475 
476  if (!(f = rtnl_tc_data(TC_CAST(cls))))
477  return -NLE_NOMEM;
478 
479  if (!(f->cf_mask & FLOWER_ATTR_PROTO))
480  return -NLE_MISSING_ATTR;
481 
482  if (f->cf_proto != htons(ETH_P_8021Q))
483  return -NLE_INVAL;
484 
485  f->cf_vlan_ethtype = htons(ethtype);
486  f->cf_mask |= FLOWER_ATTR_VLAN_ETH_TYPE;
487 
488  return 0;
489 }
490 
491 /**
492  * Set destination mac address for flower classifier
493  * @arg cls Flower classifier.
494  * @arg mac destination mac address
495  * @arg mask mask for mac address
496  * @return 0 on success or a negative error code.
497  */
498 int rtnl_flower_set_dst_mac(struct rtnl_cls *cls, unsigned char *mac,
499  unsigned char *mask)
500 {
501  struct rtnl_flower *f;
502 
503  if (!(f = rtnl_tc_data(TC_CAST(cls))))
504  return -NLE_NOMEM;
505 
506  if (mac) {
507  memcpy(f->cf_dst_mac, mac, ETH_ALEN);
508  f->cf_mask |= FLOWER_ATTR_DST_MAC;
509 
510  if (mask) {
511  memcpy(f->cf_dst_mac_mask, mask, ETH_ALEN);
512  f->cf_mask |= FLOWER_ATTR_DST_MAC_MASK;
513  }
514 
515  return 0;
516  }
517 
518  return -NLE_FAILURE;
519 }
520 
521 /**
522  * Get destination mac address for flower classifier
523  * @arg cls Flower classifier.
524  * @arg mac destination mac address
525  * @arg mask mask for mac address
526  * @return 0 on success or a negative error code.
527 */
528 int rtnl_flower_get_dst_mac(struct rtnl_cls *cls, unsigned char *mac,
529  unsigned char *mask)
530 {
531  struct rtnl_flower *f;
532 
533  if (!(f = rtnl_tc_data_peek(TC_CAST(cls))))
534  return -NLE_INVAL;
535 
536  if (!(f->cf_mask & FLOWER_ATTR_DST_MAC))
537  return -NLE_MISSING_ATTR;
538 
539  if (mac)
540  memcpy(mac, f->cf_dst_mac, ETH_ALEN);
541 
542  if (mask)
543  memcpy(mask, f->cf_dst_mac_mask, ETH_ALEN);
544 
545  return 0;
546 }
547 
548 /**
549  * Set source mac address for flower classifier
550  * @arg cls Flower classifier.
551  * @arg mac source mac address
552  * @arg mask mask for mac address
553  * @return 0 on success or a negative error code.
554  */
555 int rtnl_flower_set_src_mac(struct rtnl_cls *cls, unsigned char *mac,
556  unsigned char *mask)
557 {
558  struct rtnl_flower *f;
559 
560  if (!(f = rtnl_tc_data(TC_CAST(cls))))
561  return -NLE_NOMEM;
562 
563  if (mac) {
564  memcpy(f->cf_src_mac, mac, ETH_ALEN);
565  f->cf_mask |= FLOWER_ATTR_SRC_MAC;
566 
567  if (mask) {
568  memcpy(f->cf_src_mac_mask, mask, ETH_ALEN);
569  f->cf_mask |= FLOWER_ATTR_SRC_MAC_MASK;
570  }
571 
572  return 0;
573  }
574 
575  return -NLE_FAILURE;
576 }
577 
578 /**
579  * Get source mac address for flower classifier
580  * @arg cls Flower classifier.
581  * @arg mac source mac address
582  * @arg mask mask for mac address
583  * @return 0 on success or a negative error code.
584 */
585 int rtnl_flower_get_src_mac(struct rtnl_cls *cls, unsigned char *mac,
586  unsigned char *mask)
587 {
588  struct rtnl_flower *f;
589 
590  if (!(f = rtnl_tc_data_peek(TC_CAST(cls))))
591  return -NLE_INVAL;
592 
593  if (!(f->cf_mask & FLOWER_ATTR_SRC_MAC))
594  return -NLE_MISSING_ATTR;
595 
596  if (mac)
597  memcpy(mac, f->cf_src_mac, ETH_ALEN);
598 
599  if (mask)
600  memcpy(mask, f->cf_src_mac_mask, ETH_ALEN);
601 
602  return 0;
603 }
604 
605 /**
606  * Set dscp value for flower classifier
607  * @arg cls Flower classifier.
608  * @arg dscp dscp value
609  * @arg mask mask for dscp value
610  * @return 0 on success or a negative error code.
611  */
612 int rtnl_flower_set_ip_dscp(struct rtnl_cls *cls, uint8_t dscp, uint8_t mask)
613 {
614  struct rtnl_flower *f;
615 
616  if (!(f = rtnl_tc_data(TC_CAST(cls))))
617  return -NLE_NOMEM;
618 
619  if (dscp > FLOWER_DSCP_MAX)
620  return -NLE_RANGE;
621 
622  if (mask > FLOWER_DSCP_MASK_MAX)
623  return -NLE_RANGE;
624 
625  f->cf_ip_dscp = dscp;
626  f->cf_mask |= FLOWER_ATTR_IP_DSCP;
627 
628  if (mask) {
629  f->cf_ip_dscp_mask = mask;
630  f->cf_mask |= FLOWER_ATTR_IP_DSCP_MASK;
631  }
632 
633  return 0;
634 }
635 
636 /**
637  * Get dscp value for flower classifier
638  * @arg cls Flower classifier.
639  * @arg dscp dscp value
640  * @arg mask mask for dscp value
641  * @return 0 on success or a negative error code.
642 */
643 int rtnl_flower_get_ip_dscp(struct rtnl_cls *cls, uint8_t *dscp, uint8_t *mask)
644 {
645  struct rtnl_flower *f;
646 
647  if (!(f = rtnl_tc_data_peek(TC_CAST(cls))))
648  return -NLE_INVAL;
649 
650  if (!(f->cf_mask & FLOWER_ATTR_IP_DSCP))
651  return -NLE_MISSING_ATTR;
652 
653  *dscp = f->cf_ip_dscp;
654  *mask = f->cf_ip_dscp_mask;
655 
656  return 0;
657 }
658 
659 /**
660  * Set IPv4 source address for flower classifier
661  * @arg cls Flower classifier.
662  * @arg addr IPv4 source address
663  * @arg mask mask for IPv4 source address
664  * @return 0 on success or a negative error code.
665  */
666 int rtnl_flower_set_ipv4_src(struct rtnl_cls *cls, in_addr_t addr,
667  in_addr_t mask)
668 {
669  struct rtnl_flower *f;
670 
671  if (!(f = rtnl_tc_data(TC_CAST(cls))))
672  return -NLE_NOMEM;
673 
674  if (addr) {
675  f->cf_ipv4_src = addr;
676  f->cf_mask |= FLOWER_ATTR_IPV4_SRC;
677 
678  if (mask) {
679  f->cf_ipv4_src_mask = mask;
680  f->cf_mask |= FLOWER_ATTR_IPV4_SRC_MASK;
681  }
682 
683  return 0;
684  }
685 
686  return -NLE_FAILURE;
687 }
688 
689 /**
690  * Get IPv4 source address for flower classifier
691  * @arg cls Flower classifier.
692  * @arg addr IPv4 source address
693  * @arg mask mask for IPv4 source address
694  * @return 0 on success or a negative error code.
695  */
696 int rtnl_flower_get_ipv4_src(struct rtnl_cls *cls, in_addr_t *out_addr,
697  in_addr_t *out_mask)
698 {
699  struct rtnl_flower *f;
700 
701  if (!(f = rtnl_tc_data_peek(TC_CAST(cls))))
702  return -NLE_INVAL;
703 
704  if (!(f->cf_mask & FLOWER_ATTR_IPV4_SRC))
705  return -NLE_MISSING_ATTR;
706 
707  if (out_addr)
708  *out_addr = f->cf_ipv4_src;
709 
710  if (out_mask) {
711  if (f->cf_mask & FLOWER_ATTR_IPV4_SRC_MASK)
712  *out_mask = f->cf_ipv4_src_mask;
713  else
714  *out_mask = 0xffffffff;
715  }
716 
717  return 0;
718 }
719 
720 /**
721  * Set IPv4 destination address for flower classifier
722  * @arg cls Flower classifier.
723  * @arg addr IPv4 destination address
724  * @arg mask mask for IPv4 destination address
725  * @return 0 on success or a negative error code.
726  */
727 int rtnl_flower_set_ipv4_dst(struct rtnl_cls *cls, in_addr_t addr,
728  in_addr_t mask)
729 {
730  struct rtnl_flower *f;
731 
732  if (!(f = rtnl_tc_data(TC_CAST(cls))))
733  return -NLE_NOMEM;
734 
735  if (addr) {
736  f->cf_ipv4_dst = addr;
737  f->cf_mask |= FLOWER_ATTR_IPV4_DST;
738 
739  if (mask) {
740  f->cf_ipv4_dst_mask = mask;
741  f->cf_mask |= FLOWER_ATTR_IPV4_DST_MASK;
742  }
743 
744  return 0;
745  }
746 
747  return -NLE_FAILURE;
748 }
749 
750 /**
751  * Get IPv4 destination address for flower classifier
752  * @arg cls Flower classifier.
753  * @arg addr IPv4 destination address
754  * @arg mask mask for IPv4 destination address
755  * @return 0 on success or a negative error code.
756  */
757 int rtnl_flower_get_ipv4_dst(struct rtnl_cls *cls, in_addr_t *out_addr,
758  in_addr_t *out_mask)
759 {
760  struct rtnl_flower *f;
761 
762  if (!(f = rtnl_tc_data_peek(TC_CAST(cls))))
763  return -NLE_INVAL;
764 
765  if (!(f->cf_mask & FLOWER_ATTR_IPV4_DST))
766  return -NLE_MISSING_ATTR;
767 
768  if (out_addr)
769  *out_addr = f->cf_ipv4_dst;
770 
771  if (out_mask) {
772  if (f->cf_mask & FLOWER_ATTR_IPV4_DST_MASK)
773  *out_mask = f->cf_ipv4_dst_mask;
774  else
775  *out_mask = 0xffffffff;
776  }
777 
778  return 0;
779 }
780 
781 /**
782  * Append action for flower classifier
783  * @arg cls Flower classifier.
784  * @arg act action to append
785  * @return 0 on success or a negative error code.
786  */
787 int rtnl_flower_append_action(struct rtnl_cls *cls, struct rtnl_act *act)
788 {
789  struct rtnl_flower *f;
790 
791  if (!act)
792  return 0;
793 
794  if (!(f = rtnl_tc_data(TC_CAST(cls))))
795  return -NLE_NOMEM;
796 
797  f->cf_mask |= FLOWER_ATTR_ACTION;
798 
799  rtnl_act_get(act);
800  return rtnl_act_append(&f->cf_act, act);
801 }
802 
803 /**
804  * Delete action from flower classifier
805  * @arg cls Flower classifier.
806  * @arg act action to delete
807  * @return 0 on success or a negative error code.
808  */
809 int rtnl_flower_del_action(struct rtnl_cls *cls, struct rtnl_act *act)
810 {
811  struct rtnl_flower *f;
812  int ret;
813 
814  if (!act)
815  return 0;
816 
817  if (!(f = rtnl_tc_data(TC_CAST(cls))))
818  return -NLE_NOMEM;
819 
820  if (!(f->cf_mask & FLOWER_ATTR_ACTION))
821  return -NLE_INVAL;
822 
823  ret = rtnl_act_remove(&f->cf_act, act);
824  if (ret)
825  return ret;
826 
827  if (!f->cf_act)
828  f->cf_mask &= ~FLOWER_ATTR_ACTION;
829  rtnl_act_put(act);
830 
831  return 0;
832 }
833 
834 /**
835  * Get action from flower classifier
836  * @arg cls Flower classifier.
837  * @return action on success or NULL on error.
838  */
839 struct rtnl_act* rtnl_flower_get_action(struct rtnl_cls *cls)
840 {
841  struct rtnl_flower *f;
842 
843  if (!(f = rtnl_tc_data_peek(TC_CAST(cls))))
844  return NULL;
845 
846  if (!(f->cf_mask & FLOWER_ATTR_ACTION))
847  return NULL;
848 
849  rtnl_act_get(f->cf_act);
850 
851  return f->cf_act;
852 }
853 
854 /**
855  * Set flags for flower classifier
856  * @arg cls Flower classifier.
857  * @arg flags (TCA_CLS_FLAGS_SKIP_HW | TCA_CLS_FLAGS_SKIP_SW)
858  * @return 0 on success or a negative error code.
859  */
860 int rtnl_flower_set_flags(struct rtnl_cls *cls, int flags)
861 {
862  struct rtnl_flower *f;
863 
864  if (!(f = rtnl_tc_data(TC_CAST(cls))))
865  return -NLE_NOMEM;
866 
867  f->cf_flags = flags;
868  f->cf_mask |= FLOWER_ATTR_FLAGS;
869 
870  return 0;
871 }
872 
873 /** @} */
874 
875 static struct rtnl_tc_ops flower_ops = {
876  .to_kind = "flower",
877  .to_type = RTNL_TC_TYPE_CLS,
878  .to_size = sizeof(struct rtnl_flower),
879  .to_msg_parser = flower_msg_parser,
880  .to_free_data = flower_free_data,
881  .to_clone = flower_clone,
882  .to_msg_fill = flower_msg_fill,
883  .to_dump = {
884  [NL_DUMP_DETAILS] = flower_dump_details,
885  },
886 };
887 
888 static void __init flower_init(void)
889 {
890  rtnl_tc_register(&flower_ops);
891 }
892 
893 static void __exit flower_exit(void)
894 {
895  rtnl_tc_unregister(&flower_ops);
896 }
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:1076
void * rtnl_tc_data_peek(struct rtnl_tc *tc)
Returns the private data of the traffic control object.
Definition: tc.c:1062
#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:1015
void rtnl_tc_unregister(struct rtnl_tc_ops *ops)
Unregister a traffic control module.
Definition: tc.c:1049
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