libnl 3.10.0
u32.c
1/* SPDX-License-Identifier: LGPL-2.1-only */
2/*
3 * Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch>
4 * Copyright (c) 2005-2006 Petr Gotthard <petr.gotthard@siemens.com>
5 * Copyright (c) 2005-2006 Siemens AG Oesterreich
6 */
7
8/**
9 * @ingroup cls
10 * @defgroup cls_u32 Universal 32-bit Classifier
11 *
12 * @{
13 */
14
15#include "nl-default.h"
16
17#include <netlink/netlink.h>
18#include <netlink/attr.h>
19#include <netlink/utils.h>
20#include <netlink/route/classifier.h>
21#include <netlink/route/cls/u32.h>
22#include <netlink/route/action.h>
23
24#include "tc-api.h"
25#include "nl-aux-route/nl-route.h"
26
27/** @cond SKIP */
28struct rtnl_u32 {
29 uint32_t cu_divisor;
30 uint32_t cu_hash;
31 uint32_t cu_classid;
32 uint32_t cu_link;
33 struct nl_data *cu_pcnt;
34 struct nl_data *cu_selector;
35 struct nl_data *cu_mark;
36 struct rtnl_act *cu_act;
37 struct nl_data *cu_police;
38 char cu_indev[IFNAMSIZ];
39 int cu_mask;
40};
41
42#define U32_ATTR_DIVISOR 0x001
43#define U32_ATTR_HASH 0x002
44#define U32_ATTR_CLASSID 0x004
45#define U32_ATTR_LINK 0x008
46#define U32_ATTR_PCNT 0x010
47#define U32_ATTR_SELECTOR 0x020
48#define U32_ATTR_ACTION 0x040
49#define U32_ATTR_POLICE 0x080
50#define U32_ATTR_INDEV 0x100
51#define U32_ATTR_MARK 0x200
52/** @endcond */
53
54static inline struct tc_u32_sel *u32_selector(struct rtnl_u32 *u)
55{
56 return (struct tc_u32_sel *) u->cu_selector->d_data;
57}
58
59static inline struct tc_u32_sel *u32_selector_alloc(struct rtnl_u32 *u)
60{
61 if (!u->cu_selector)
62 u->cu_selector = nl_data_alloc(NULL, sizeof(struct tc_u32_sel));
63
64 return u32_selector(u);
65}
66
67static inline struct tc_u32_mark *u32_mark_alloc(struct rtnl_u32 *u)
68{
69 if (!u->cu_mark)
70 u->cu_mark = nl_data_alloc(NULL, sizeof(struct tc_u32_mark));
71
72 return (struct tc_u32_mark *) u->cu_mark->d_data;
73}
74
75static struct nla_policy u32_policy[TCA_U32_MAX+1] = {
76 [TCA_U32_DIVISOR] = { .type = NLA_U32 },
77 [TCA_U32_HASH] = { .type = NLA_U32 },
78 [TCA_U32_CLASSID] = { .type = NLA_U32 },
79 [TCA_U32_LINK] = { .type = NLA_U32 },
80 [TCA_U32_INDEV] = { .type = NLA_STRING,
81 .maxlen = IFNAMSIZ },
82 [TCA_U32_SEL] = { .minlen = sizeof(struct tc_u32_sel) },
83 [TCA_U32_PCNT] = { .minlen = sizeof(struct tc_u32_pcnt) },
84 [TCA_U32_MARK] = { .minlen = sizeof(struct tc_u32_mark) }
85};
86
87static int u32_msg_parser(struct rtnl_tc *tc, void *data)
88{
89 struct rtnl_u32 *u = data;
90 struct nlattr *tb[TCA_U32_MAX + 1];
91 int err;
92
93 err = tca_parse(tb, TCA_U32_MAX, tc, u32_policy);
94 if (err < 0)
95 return err;
96
97 if (tb[TCA_U32_DIVISOR]) {
98 u->cu_divisor = nla_get_u32(tb[TCA_U32_DIVISOR]);
99 u->cu_mask |= U32_ATTR_DIVISOR;
100 }
101
102 if (tb[TCA_U32_SEL]) {
103 u->cu_selector = nl_data_alloc_attr(tb[TCA_U32_SEL]);
104 if (!u->cu_selector)
105 goto errout_nomem;
106 u->cu_mask |= U32_ATTR_SELECTOR;
107 }
108
109 if (tb[TCA_U32_MARK]) {
110 u->cu_mark = nl_data_alloc_attr(tb[TCA_U32_MARK]);
111 if (!u->cu_mark)
112 goto errout_nomem;
113 u->cu_mask |= U32_ATTR_MARK;
114 }
115
116 if (tb[TCA_U32_HASH]) {
117 u->cu_hash = nla_get_u32(tb[TCA_U32_HASH]);
118 u->cu_mask |= U32_ATTR_HASH;
119 }
120
121 if (tb[TCA_U32_CLASSID]) {
122 u->cu_classid = nla_get_u32(tb[TCA_U32_CLASSID]);
123 u->cu_mask |= U32_ATTR_CLASSID;
124 }
125
126 if (tb[TCA_U32_LINK]) {
127 u->cu_link = nla_get_u32(tb[TCA_U32_LINK]);
128 u->cu_mask |= U32_ATTR_LINK;
129 }
130
131 if (tb[TCA_U32_ACT]) {
132 u->cu_mask |= U32_ATTR_ACTION;
133 err = rtnl_act_parse(&u->cu_act, tb[TCA_U32_ACT]);
134 if (err < 0)
135 return err;
136 }
137
138 if (tb[TCA_U32_POLICE]) {
139 u->cu_police = nl_data_alloc_attr(tb[TCA_U32_POLICE]);
140 if (!u->cu_police)
141 goto errout_nomem;
142 u->cu_mask |= U32_ATTR_POLICE;
143 }
144
145 if (tb[TCA_U32_PCNT]) {
146 struct tc_u32_sel *sel;
147 size_t pcnt_size;
148
149 if (!tb[TCA_U32_SEL]) {
150 err = -NLE_MISSING_ATTR;
151 goto errout;
152 }
153
154 sel = u->cu_selector->d_data;
155 pcnt_size = sizeof(struct tc_u32_pcnt) +
156 (sel->nkeys * sizeof(uint64_t));
157 if (_nla_len(tb[TCA_U32_PCNT]) < pcnt_size) {
158 err = -NLE_INVAL;
159 goto errout;
160 }
161
162 u->cu_pcnt = nl_data_alloc_attr(tb[TCA_U32_PCNT]);
163 if (!u->cu_pcnt)
164 goto errout_nomem;
165 u->cu_mask |= U32_ATTR_PCNT;
166 }
167
168 if (tb[TCA_U32_INDEV]) {
169 nla_strlcpy(u->cu_indev, tb[TCA_U32_INDEV], IFNAMSIZ);
170 u->cu_mask |= U32_ATTR_INDEV;
171 }
172
173 return 0;
174
175errout_nomem:
176 err = -NLE_NOMEM;
177errout:
178 return err;
179}
180
181static void u32_free_data(struct rtnl_tc *tc, void *data)
182{
183 struct rtnl_u32 *u = data;
184
185 if (u->cu_act)
186 rtnl_act_put_all(&u->cu_act);
187 nl_data_free(u->cu_mark);
188 nl_data_free(u->cu_selector);
189 nl_data_free(u->cu_police);
190 nl_data_free(u->cu_pcnt);
191}
192
193static int u32_clone(void *_dst, void *_src)
194{
195 struct rtnl_u32 *dst = _dst, *src = _src;
196 _nl_auto_nl_data struct nl_data *selector = NULL;
197 _nl_auto_nl_data struct nl_data *mark = NULL;
198 _nl_auto_nl_data struct nl_data *police = NULL;
199 _nl_auto_nl_data struct nl_data *pcnt = NULL;
200 _nl_auto_nl_data struct nl_data *opts = NULL;
201 _nl_auto_nl_data struct nl_data *xstats = NULL;
202 _nl_auto_nl_data struct nl_data *subdata = NULL;
203 _nl_auto_rtnl_act struct rtnl_act *act = NULL;
204
205 dst->cu_pcnt = NULL;
206 dst->cu_selector = NULL;
207 dst->cu_mark = NULL;
208 dst->cu_act = NULL;
209 dst->cu_police = NULL;
210
211 if (src->cu_selector) {
212 if (!(selector = nl_data_clone(src->cu_selector)))
213 return -NLE_NOMEM;
214 }
215
216 if (src->cu_mark) {
217 if (!(mark = nl_data_clone(src->cu_mark)))
218 return -NLE_NOMEM;
219 }
220
221 if (src->cu_act) {
222 if (!(act = rtnl_act_alloc()))
223 return -NLE_NOMEM;
224
225 if (src->cu_act->c_opts) {
226 if (!(opts = nl_data_clone(src->cu_act->c_opts)))
227 return -NLE_NOMEM;
228 }
229
230 if (src->cu_act->c_xstats) {
231 if (!(xstats = nl_data_clone(src->cu_act->c_xstats)))
232 return -NLE_NOMEM;
233 }
234
235 if (src->cu_act->c_subdata) {
236 if (!(subdata = nl_data_clone(src->cu_act->c_subdata)))
237 return -NLE_NOMEM;
238 }
239 }
240
241 if (src->cu_police) {
242 if (!(police = nl_data_clone(src->cu_police)))
243 return -NLE_NOMEM;
244 }
245
246 if (src->cu_pcnt) {
247 if (!(pcnt = nl_data_clone(src->cu_pcnt)))
248 return -NLE_NOMEM;
249 }
250
251 /* we've passed the critical point and its safe to proceed */
252
253 if (selector)
254 dst->cu_selector = _nl_steal_pointer(&selector);
255
256 if (mark)
257 dst->cu_mark = _nl_steal_pointer(&mark);
258
259 if (police)
260 dst->cu_police = _nl_steal_pointer(&police);
261
262 if (pcnt)
263 dst->cu_pcnt = _nl_steal_pointer(&pcnt);
264
265 if (act) {
266 dst->cu_act = _nl_steal_pointer(&act);
267
268 /* action nl list next and prev pointers must be updated */
269 nl_init_list_head(&dst->cu_act->ce_list);
270
271 if (opts)
272 dst->cu_act->c_opts = _nl_steal_pointer(&opts);
273
274 if (xstats)
275 dst->cu_act->c_xstats = _nl_steal_pointer(&xstats);
276
277 if (subdata)
278 dst->cu_act->c_subdata = _nl_steal_pointer(&subdata);
279
280 if (dst->cu_act->c_link) {
281 nl_object_get(OBJ_CAST(dst->cu_act->c_link));
282 }
283
284 dst->cu_act->a_next = NULL; /* Only clone first in chain */
285 }
286
287 return 0;
288}
289
290static void u32_dump_line(struct rtnl_tc *tc, void *data,
291 struct nl_dump_params *p)
292{
293 struct rtnl_u32 *u = data;
294 char buf[32];
295
296 if (!u)
297 return;
298
299 if (u->cu_mask & U32_ATTR_DIVISOR)
300 nl_dump(p, " divisor %u", u->cu_divisor);
301 else if (u->cu_mask & U32_ATTR_CLASSID)
302 nl_dump(p, " target %s",
303 rtnl_tc_handle2str(u->cu_classid, buf, sizeof(buf)));
304}
305
306static void print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel,
307 struct rtnl_u32 *u)
308{
309 int i;
310 struct tc_u32_key *key;
311
312 if (sel->hmask || sel->hoff) {
313 /* I guess this will never be used since the kernel only
314 * exports the selector if no divisor is set but hash offset
315 * and hash mask make only sense in hash filters with divisor
316 * set */
317 nl_dump(p, " hash at %u & 0x%x", sel->hoff, sel->hmask);
318 }
319
320 if (sel->flags & (TC_U32_OFFSET | TC_U32_VAROFFSET)) {
321 nl_dump(p, " offset at %u", sel->off);
322
323 if (sel->flags & TC_U32_VAROFFSET)
324 nl_dump(p, " variable (at %u & 0x%x) >> %u",
325 sel->offoff, ntohs(sel->offmask), sel->offshift);
326 }
327
328 if (sel->flags) {
329 int flags = sel->flags;
330 nl_dump(p, " <");
331
332#define PRINT_FLAG(f) if (flags & TC_U32_##f) { \
333 flags &= ~TC_U32_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
334
335 PRINT_FLAG(TERMINAL);
336 PRINT_FLAG(OFFSET);
337 PRINT_FLAG(VAROFFSET);
338 PRINT_FLAG(EAT);
339#undef PRINT_FLAG
340
341 nl_dump(p, ">");
342 }
343
344
345 for (i = 0; i < sel->nkeys; i++) {
346 key = &sel->keys[i];
347
348 nl_dump(p, "\n");
349 nl_dump_line(p, " match key at %s%u ",
350 key->offmask ? "nexthdr+" : "", key->off);
351
352 if (key->offmask)
353 nl_dump(p, "[0x%u] ", key->offmask);
354
355 nl_dump(p, "& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val));
356
357 if (p->dp_type == NL_DUMP_STATS &&
358 (u->cu_mask & U32_ATTR_PCNT)) {
359 struct tc_u32_pcnt *pcnt = u->cu_pcnt->d_data;
360
361 nl_dump(p, " successful %llu",
362 (long long unsigned)pcnt->kcnts[i]);
363 }
364 }
365}
366
367static void u32_dump_details(struct rtnl_tc *tc, void *data,
368 struct nl_dump_params *p)
369{
370 struct rtnl_u32 *u = data;
371 struct tc_u32_sel *s = NULL;
372 struct tc_u32_mark *m;
373
374 if (!u)
375 return;
376
377 if (!(u->cu_mask & U32_ATTR_SELECTOR)) {
378 nl_dump(p, "no-selector");
379 } else {
380 s = u->cu_selector->d_data;
381 nl_dump(p, "nkeys %u", s->nkeys);
382 }
383
384 if (!(u->cu_mask & U32_ATTR_MARK)) {
385 nl_dump(p, " no-mark");
386 } else {
387 m = u->cu_mark->d_data;
388 nl_dump(p, " mark 0x%u 0x%u", m->val, m->mask);
389 }
390
391 if (u->cu_mask & U32_ATTR_HASH)
392 nl_dump(p, " ht key 0x%x hash 0x%u",
393 TC_U32_USERHTID(u->cu_hash), TC_U32_HASH(u->cu_hash));
394
395 if (u->cu_mask & U32_ATTR_LINK)
396 nl_dump(p, " link %u", u->cu_link);
397
398 if (u->cu_mask & U32_ATTR_INDEV)
399 nl_dump(p, " indev %s", u->cu_indev);
400
401 if (u->cu_mask & U32_ATTR_SELECTOR)
402 print_selector(p, s, u);
403
404 nl_dump(p, "\n");
405}
406
407static void u32_dump_stats(struct rtnl_tc *tc, void *data,
408 struct nl_dump_params *p)
409{
410 struct rtnl_u32 *u = data;
411
412 if (!u)
413 return;
414
415 if (u->cu_mask & U32_ATTR_PCNT) {
416 struct tc_u32_pcnt *pc = u->cu_pcnt->d_data;
417
418 nl_dump(p, "\n");
419 nl_dump_line(p, " hit %8llu count %8llu\n",
420 (long long unsigned)pc->rhit,
421 (long long unsigned)pc->rcnt);
422 }
423}
424
425static int u32_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
426{
427 struct rtnl_u32 *u = data;
428
429 if (!u)
430 return 0;
431
432 if (u->cu_mask & U32_ATTR_DIVISOR)
433 NLA_PUT_U32(msg, TCA_U32_DIVISOR, u->cu_divisor);
434
435 if (u->cu_mask & U32_ATTR_HASH)
436 NLA_PUT_U32(msg, TCA_U32_HASH, u->cu_hash);
437
438 if (u->cu_mask & U32_ATTR_CLASSID)
439 NLA_PUT_U32(msg, TCA_U32_CLASSID, u->cu_classid);
440
441 if (u->cu_mask & U32_ATTR_LINK)
442 NLA_PUT_U32(msg, TCA_U32_LINK, u->cu_link);
443
444 if (u->cu_mask & U32_ATTR_SELECTOR)
445 NLA_PUT_DATA(msg, TCA_U32_SEL, u->cu_selector);
446
447 if (u->cu_mask & U32_ATTR_MARK)
448 NLA_PUT_DATA(msg, TCA_U32_MARK, u->cu_mark);
449
450 if (u->cu_mask & U32_ATTR_ACTION) {
451 int err;
452
453 err = rtnl_act_fill(msg, TCA_U32_ACT, u->cu_act);
454 if (err < 0)
455 return err;
456 }
457
458 if (u->cu_mask & U32_ATTR_POLICE)
459 NLA_PUT_DATA(msg, TCA_U32_POLICE, u->cu_police);
460
461 if (u->cu_mask & U32_ATTR_INDEV)
462 NLA_PUT_STRING(msg, TCA_U32_INDEV, u->cu_indev);
463
464 return 0;
465
466nla_put_failure:
467 return -NLE_NOMEM;
468}
469
470/**
471 * @name Attribute Modifications
472 * @{
473 */
474
475void rtnl_u32_set_handle(struct rtnl_cls *cls, int htid, int hash,
476 int nodeid)
477{
478 uint32_t handle = (htid << 20) | (hash << 12) | nodeid;
479
480 rtnl_tc_set_handle((struct rtnl_tc *) cls, handle );
481}
482
483int rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid)
484{
485 struct rtnl_u32 *u;
486
487 if (!(u = rtnl_tc_data(TC_CAST(cls))))
488 return -NLE_NOMEM;
489
490 u->cu_classid = classid;
491 u->cu_mask |= U32_ATTR_CLASSID;
492
493 return 0;
494}
495
496int rtnl_u32_get_classid(struct rtnl_cls *cls, uint32_t *classid)
497{
498 struct rtnl_u32 *u;
499
500 if (!(u = rtnl_tc_data_peek(TC_CAST(cls))))
501 return -NLE_INVAL;
502
503 if (!(u->cu_mask & U32_ATTR_CLASSID))
504 return -NLE_INVAL;
505
506 *classid = u->cu_classid;
507 return 0;
508}
509
510int rtnl_u32_set_divisor(struct rtnl_cls *cls, uint32_t divisor)
511{
512 struct rtnl_u32 *u;
513
514 if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
515 return -NLE_NOMEM;
516
517 u->cu_divisor = divisor;
518 u->cu_mask |= U32_ATTR_DIVISOR;
519 return 0;
520}
521
522int rtnl_u32_set_link(struct rtnl_cls *cls, uint32_t link)
523{
524 struct rtnl_u32 *u;
525
526 if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
527 return -NLE_NOMEM;
528
529 u->cu_link = link;
530 u->cu_mask |= U32_ATTR_LINK;
531 return 0;
532}
533
534int rtnl_u32_set_hashtable(struct rtnl_cls *cls, uint32_t ht)
535{
536 struct rtnl_u32 *u;
537
538 if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
539 return -NLE_NOMEM;
540
541 u->cu_hash = ht;
542 u->cu_mask |= U32_ATTR_HASH;
543 return 0;
544}
545
546int rtnl_u32_set_hashmask(struct rtnl_cls *cls, uint32_t hashmask, uint32_t offset)
547{
548 struct rtnl_u32 *u;
549 struct tc_u32_sel *sel;
550
551 hashmask = htonl(hashmask);
552
553 if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
554 return -NLE_NOMEM;
555
556 sel = u32_selector_alloc(u);
557 if (!sel)
558 return -NLE_NOMEM;
559
560 sel->hmask = hashmask;
561 sel->hoff = offset;
562 return 0;
563}
564
565int rtnl_u32_set_selector(struct rtnl_cls *cls, int offoff, uint32_t offmask, char offshift, uint16_t off, char flags)
566{
567 struct rtnl_u32 *u;
568 struct tc_u32_sel *sel;
569
570 offmask = ntohs(offmask);
571
572 if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
573 return -NLE_NOMEM;
574
575 sel = u32_selector_alloc(u);
576 if (!sel)
577 return -NLE_NOMEM;
578
579 sel->offoff = offoff;
580 sel->offmask = offmask;
581 sel->offshift = offshift;
582 sel->flags |= TC_U32_VAROFFSET;
583 sel->off = off;
584 sel->flags |= flags;
585 return 0;
586}
587
588int rtnl_u32_set_cls_terminal(struct rtnl_cls *cls)
589{
590 struct rtnl_u32 *u;
591 struct tc_u32_sel *sel;
592
593 if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
594 return -NLE_NOMEM;
595
596 sel = u32_selector_alloc(u);
597 if (!sel)
598 return -NLE_NOMEM;
599
600 sel->flags |= TC_U32_TERMINAL;
601 return 0;
602}
603
604int rtnl_u32_add_action(struct rtnl_cls *cls, struct rtnl_act *act)
605{
606 struct rtnl_u32 *u;
607 int err;
608
609 if (!act)
610 return 0;
611
612 if (!(u = rtnl_tc_data(TC_CAST(cls))))
613 return -NLE_NOMEM;
614
615 if ((err = _rtnl_act_append_get(&u->cu_act, act)) < 0)
616 return err;
617
618 u->cu_mask |= U32_ATTR_ACTION;
619 return 0;
620}
621
622struct rtnl_act* rtnl_u32_get_action(struct rtnl_cls *cls)
623{
624 struct rtnl_u32 *u;
625
626 if (!(u = rtnl_tc_data_peek(TC_CAST(cls))))
627 return NULL;
628
629 if (!(u->cu_mask & U32_ATTR_ACTION))
630 return NULL;
631
632 return u->cu_act;
633}
634
635int rtnl_u32_del_action(struct rtnl_cls *cls, struct rtnl_act *act)
636{
637 struct rtnl_u32 *u;
638 int ret;
639
640 if (!act)
641 return 0;
642
643 if (!(u = rtnl_tc_data(TC_CAST(cls))))
644 return -NLE_NOMEM;
645
646 if (!(u->cu_mask & U32_ATTR_ACTION))
647 return -NLE_INVAL;
648
649 ret = rtnl_act_remove(&u->cu_act, act);
650 if (ret)
651 return ret;
652
653 if (!u->cu_act)
654 u->cu_mask &= ~U32_ATTR_ACTION;
655 rtnl_act_put(act);
656 return 0;
657}
658/** @} */
659
660/**
661 * @name Selector Modifications
662 * @{
663 */
664
665int rtnl_u32_set_flags(struct rtnl_cls *cls, int flags)
666{
667 struct tc_u32_sel *sel;
668 struct rtnl_u32 *u;
669
670 if (!(u = rtnl_tc_data(TC_CAST(cls))))
671 return -NLE_NOMEM;
672
673 sel = u32_selector_alloc(u);
674 if (!sel)
675 return -NLE_NOMEM;
676
677 sel->flags |= flags;
678 u->cu_mask |= U32_ATTR_SELECTOR;
679
680 return 0;
681}
682
683/**
684 * Append new 32-bit key to the selector
685 *
686 * @arg cls classifier to be modifier
687 * @arg val value to be matched (network byte-order)
688 * @arg mask mask to be applied before matching (network byte-order)
689 * @arg off offset, in bytes, to start matching
690 * @arg offmask offset mask
691 *
692 * General selectors define the pattern, mask and offset the pattern will be
693 * matched to the packet contents. Using the general selectors you can match
694 * virtually any single bit in the IP (or upper layer) header.
695 *
696*/
697int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
698 int off, int offmask)
699{
700 struct tc_u32_sel *sel;
701 struct rtnl_u32 *u;
702 int err;
703
704 if (!(u = rtnl_tc_data(TC_CAST(cls))))
705 return -NLE_NOMEM;
706
707 sel = u32_selector_alloc(u);
708 if (!sel)
709 return -NLE_NOMEM;
710
711 if (sel->nkeys == UCHAR_MAX)
712 return -NLE_NOMEM;
713
714 err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
715 if (err < 0)
716 return err;
717
718 /* the selector might have been moved by realloc */
719 sel = u32_selector(u);
720
721 sel->keys[sel->nkeys].mask = mask;
722 sel->keys[sel->nkeys].val = val & mask;
723 sel->keys[sel->nkeys].off = off;
724 sel->keys[sel->nkeys].offmask = offmask;
725 sel->nkeys++;
726 u->cu_mask |= U32_ATTR_SELECTOR;
727
728 return 0;
729}
730
731int rtnl_u32_add_mark(struct rtnl_cls *cls, uint32_t val, uint32_t mask)
732{
733 struct tc_u32_mark *mark;
734 struct rtnl_u32 *u;
735
736 if (!(u = rtnl_tc_data(TC_CAST(cls))))
737 return -NLE_NOMEM;
738
739 mark = u32_mark_alloc(u);
740 if (!mark)
741 return -NLE_NOMEM;
742
743 mark->mask = mask;
744 mark->val = val;
745
746 u->cu_mask |= U32_ATTR_MARK;
747
748 return 0;
749}
750
751int rtnl_u32_del_mark(struct rtnl_cls *cls)
752{
753 struct rtnl_u32 *u;
754
755 if (!(u = rtnl_tc_data(TC_CAST(cls))))
756 return -NLE_NOMEM;
757
758 if (!(u->cu_mask))
759 return -NLE_INVAL;
760
761 if (!(u->cu_mask & U32_ATTR_MARK))
762 return -NLE_INVAL;
763
764 nl_data_free(u->cu_mark);
765 u->cu_mark = NULL;
766 u->cu_mask &= ~U32_ATTR_MARK;
767
768 return 0;
769}
770
771/**
772 * Get the 32-bit key from the selector
773 *
774 * @arg cls classifier to be retrieve
775 * @arg index the index of the array of keys, start with 0
776 * @arg val pointer to store value after masked (network byte-order)
777 * @arg mask pointer to store the mask (network byte-order)
778 * @arg off pointer to store the offset
779 * @arg offmask pointer to store offset mask
780 *
781*/
782int rtnl_u32_get_key(struct rtnl_cls *cls, uint8_t index,
783 uint32_t *val, uint32_t *mask, int *off, int *offmask)
784{
785 struct tc_u32_sel *sel;
786 struct rtnl_u32 *u;
787
788 if (!(u = rtnl_tc_data(TC_CAST(cls))))
789 return -NLE_NOMEM;
790
791 if (!(u->cu_mask & U32_ATTR_SELECTOR))
792 return -NLE_INVAL;
793
794 sel = u32_selector(u);
795 if (index >= sel->nkeys)
796 return -NLE_RANGE;
797
798 *mask = sel->keys[index].mask;
799 *val = sel->keys[index].val;
800 *off = sel->keys[index].off;
801 *offmask = sel->keys[index].offmask;
802 return 0;
803}
804
805
806int rtnl_u32_add_key_uint8(struct rtnl_cls *cls, uint8_t val, uint8_t mask,
807 int off, int offmask)
808{
809 int shift = 24 - 8 * (off & 3);
810
811 return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
812 htonl((uint32_t)mask << shift),
813 off & ~3, offmask);
814}
815
816/**
817 * Append new selector key to match a 16-bit number
818 *
819 * @arg cls classifier to be modified
820 * @arg val value to be matched (host byte-order)
821 * @arg mask mask to be applied before matching (host byte-order)
822 * @arg off offset, in bytes, to start matching
823 * @arg offmask offset mask
824*/
825int rtnl_u32_add_key_uint16(struct rtnl_cls *cls, uint16_t val, uint16_t mask,
826 int off, int offmask)
827{
828 int shift = ((off & 3) == 0 ? 16 : 0);
829 if (off % 2)
830 return -NLE_INVAL;
831
832 return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
833 htonl((uint32_t)mask << shift),
834 off & ~3, offmask);
835}
836
837/**
838 * Append new selector key to match a 32-bit number
839 *
840 * @arg cls classifier to be modified
841 * @arg val value to be matched (host byte-order)
842 * @arg mask mask to be applied before matching (host byte-order)
843 * @arg off offset, in bytes, to start matching
844 * @arg offmask offset mask
845*/
846int rtnl_u32_add_key_uint32(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
847 int off, int offmask)
848{
849 return rtnl_u32_add_key(cls, htonl(val), htonl(mask),
850 off & ~3, offmask);
851}
852
853int rtnl_u32_add_key_in_addr(struct rtnl_cls *cls, const struct in_addr *addr,
854 uint8_t bitmask, int off, int offmask)
855{
856 uint32_t mask = 0xFFFFFFFF << (32 - bitmask);
857 return rtnl_u32_add_key(cls, addr->s_addr, htonl(mask), off, offmask);
858}
859
860int rtnl_u32_add_key_in6_addr(struct rtnl_cls *cls, const struct in6_addr *addr,
861 uint8_t bitmask, int off, int offmask)
862{
863 int i, err;
864
865 for (i = 1; i <= 4; i++) {
866 if (32 * i - bitmask <= 0) {
867 if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
868 0xFFFFFFFF, off+4*(i-1), offmask)) < 0)
869 return err;
870 }
871 else if (32 * i - bitmask < 32) {
872 uint32_t mask = 0xFFFFFFFF << (32 * i - bitmask);
873 if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
874 htonl(mask), off+4*(i-1), offmask)) < 0)
875 return err;
876 }
877 /* otherwise, if (32*i - bitmask >= 32) no key is generated */
878 }
879
880 return 0;
881}
882
883/** @} */
884
885static struct rtnl_tc_ops u32_ops = {
886 .to_kind = "u32",
887 .to_type = RTNL_TC_TYPE_CLS,
888 .to_size = sizeof(struct rtnl_u32),
889 .to_msg_parser = u32_msg_parser,
890 .to_free_data = u32_free_data,
891 .to_clone = u32_clone,
892 .to_msg_fill = u32_msg_fill,
893 .to_dump = {
894 [NL_DUMP_LINE] = u32_dump_line,
895 [NL_DUMP_DETAILS] = u32_dump_details,
896 [NL_DUMP_STATS] = u32_dump_stats,
897 },
898};
899
900static void _nl_init u32_init(void)
901{
902 rtnl_tc_register(&u32_ops);
903}
904
905static void _nl_exit u32_exit(void)
906{
907 rtnl_tc_unregister(&u32_ops);
908}
909
910/** @} */
uint32_t nla_get_u32(const struct nlattr *nla)
Return payload of 32 bit integer attribute.
Definition attr.c:712
#define NLA_PUT_DATA(msg, attrtype, data)
Add abstract data attribute to netlink message.
Definition attr.h:293
#define NLA_PUT_U32(msg, attrtype, value)
Add 32 bit integer attribute to netlink message.
Definition attr.h:230
size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize)
Copy string attribute payload to a buffer.
Definition attr.c:381
#define NLA_PUT_STRING(msg, attrtype, value)
Add string attribute to netlink message.
Definition attr.h:257
@ NLA_STRING
NUL terminated character string.
Definition attr.h:39
@ NLA_U32
32 bit integer
Definition attr.h:37
char * rtnl_tc_handle2str(uint32_t handle, char *buf, size_t len)
Convert a traffic control handle to a character string (Reentrant).
Definition classid.c:109
int rtnl_u32_get_key(struct rtnl_cls *cls, uint8_t index, uint32_t *val, uint32_t *mask, int *off, int *offmask)
Get the 32-bit key from the selector.
Definition u32.c:782
int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask, int off, int offmask)
Append new 32-bit key to the selector.
Definition u32.c:697
int rtnl_u32_add_key_uint32(struct rtnl_cls *cls, uint32_t val, uint32_t mask, int off, int offmask)
Append new selector key to match a 32-bit number.
Definition u32.c:846
int rtnl_u32_add_key_uint16(struct rtnl_cls *cls, uint16_t val, uint16_t mask, int off, int offmask)
Append new selector key to match a 16-bit number.
Definition u32.c:825
struct nl_data * nl_data_clone(const struct nl_data *src)
Clone an abstract data object.
Definition data.c:95
void nl_data_free(struct nl_data *data)
Free an abstract data object.
Definition data.c:134
int nl_data_append(struct nl_data *data, const void *buf, size_t size)
Append data to an abstract data object.
Definition data.c:111
struct nl_data * nl_data_alloc(const void *buf, size_t size)
Allocate a new abstract data object.
Definition data.c:50
struct nl_data * nl_data_alloc_attr(const struct nlattr *nla)
Allocate abstract data object based on netlink attribute.
Definition data.c:84
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_set_handle(struct rtnl_tc *tc, uint32_t id)
Set identifier of traffic control object.
Definition tc.c:485
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:1015
@ NL_DUMP_STATS
Dump all attributes including statistics.
Definition types.h:22
@ NL_DUMP_LINE
Dump object briefly on one line.
Definition types.h:20
@ NL_DUMP_DETAILS
Dump all attributes but no statistics.
Definition types.h:21
Dumping parameters.
Definition types.h:32
enum nl_dump_type dp_type
Specifies the type of dump that is requested.
Definition types.h:36
Attribute validation policy.
Definition attr.h:63
uint16_t type
Type of attribute or NLA_UNSPEC.
Definition attr.h:65