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