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