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
41static 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
59static 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
157static 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
220nla_put_failure:
221 return -NLE_NOMEM;
222}
223
224static 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
232static 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
267static 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 */
346int 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*/
365int 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 */
386int 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*/
408int 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 */
429int 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*/
451int 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 */
472int 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 */
498int 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*/
528int 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 */
555int 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*/
585int 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 */
612int 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*/
643int 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 */
666int 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 */
696int 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 */
727int 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 */
757int 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 */
787int 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 */
809int 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 */
839struct 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 */
860int 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
875static 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
888static void __init flower_init(void)
889{
890 rtnl_tc_register(&flower_ops);
891}
892
893static 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:702
uint16_t nla_get_u16(const struct nlattr *nla)
Return payload of 16 bit integer attribute.
Definition: attr.c:652
#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:602
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_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
void * rtnl_tc_data(struct rtnl_tc *tc)
Return pointer to private data of traffic control object.
Definition: tc.c:1076
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