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