1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3 * Copyright (c) 2003-2013 Thomas Graf <[email protected]>
4 * Copyright (c) 2005-2006 Petr Gotthard <[email protected]>
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 */
28 struct 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
u32_selector(struct rtnl_u32 * u)54 static 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
u32_selector_alloc(struct rtnl_u32 * u)59 static 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
u32_mark_alloc(struct rtnl_u32 * u)67 static 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
75 static 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
u32_msg_parser(struct rtnl_tc * tc,void * data)87 static 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
175 errout_nomem:
176 err = -NLE_NOMEM;
177 errout:
178 return err;
179 }
180
u32_free_data(struct rtnl_tc * tc,void * data)181 static 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
u32_clone(void * _dst,void * _src)193 static 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
u32_dump_line(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)290 static 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
print_selector(struct nl_dump_params * p,struct tc_u32_sel * sel,struct rtnl_u32 * u)306 static 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
u32_dump_details(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)367 static 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
u32_dump_stats(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)407 static 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
u32_msg_fill(struct rtnl_tc * tc,void * data,struct nl_msg * msg)425 static 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
466 nla_put_failure:
467 return -NLE_NOMEM;
468 }
469
470 /**
471 * @name Attribute Modifications
472 * @{
473 */
474
rtnl_u32_set_handle(struct rtnl_cls * cls,int htid,int hash,int nodeid)475 void 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
rtnl_u32_set_classid(struct rtnl_cls * cls,uint32_t classid)483 int 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
rtnl_u32_get_classid(struct rtnl_cls * cls,uint32_t * classid)496 int 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
rtnl_u32_set_divisor(struct rtnl_cls * cls,uint32_t divisor)510 int 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
rtnl_u32_set_link(struct rtnl_cls * cls,uint32_t link)522 int 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
rtnl_u32_set_hashtable(struct rtnl_cls * cls,uint32_t ht)534 int 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
rtnl_u32_set_hashmask(struct rtnl_cls * cls,uint32_t hashmask,uint32_t offset)546 int 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
rtnl_u32_set_selector(struct rtnl_cls * cls,int offoff,uint32_t offmask,char offshift,uint16_t off,char flags)565 int 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
rtnl_u32_set_cls_terminal(struct rtnl_cls * cls)588 int 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
rtnl_u32_add_action(struct rtnl_cls * cls,struct rtnl_act * act)604 int 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
rtnl_u32_get_action(struct rtnl_cls * cls)622 struct 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
rtnl_u32_del_action(struct rtnl_cls * cls,struct rtnl_act * act)635 int 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
rtnl_u32_set_flags(struct rtnl_cls * cls,int flags)665 int 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 */
rtnl_u32_add_key(struct rtnl_cls * cls,uint32_t val,uint32_t mask,int off,int offmask)697 int 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
rtnl_u32_add_mark(struct rtnl_cls * cls,uint32_t val,uint32_t mask)731 int 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
rtnl_u32_del_mark(struct rtnl_cls * cls)751 int 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 */
rtnl_u32_get_key(struct rtnl_cls * cls,uint8_t index,uint32_t * val,uint32_t * mask,int * off,int * offmask)782 int 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
rtnl_u32_add_key_uint8(struct rtnl_cls * cls,uint8_t val,uint8_t mask,int off,int offmask)806 int 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 */
rtnl_u32_add_key_uint16(struct rtnl_cls * cls,uint16_t val,uint16_t mask,int off,int offmask)825 int 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 */
rtnl_u32_add_key_uint32(struct rtnl_cls * cls,uint32_t val,uint32_t mask,int off,int offmask)846 int 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
rtnl_u32_add_key_in_addr(struct rtnl_cls * cls,const struct in_addr * addr,uint8_t bitmask,int off,int offmask)853 int 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
rtnl_u32_add_key_in6_addr(struct rtnl_cls * cls,const struct in6_addr * addr,uint8_t bitmask,int off,int offmask)860 int 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
885 static 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
u32_init(void)900 static void _nl_init u32_init(void)
901 {
902 rtnl_tc_register(&u32_ops);
903 }
904
u32_exit(void)905 static void _nl_exit u32_exit(void)
906 {
907 rtnl_tc_unregister(&u32_ops);
908 }
909
910 /** @} */
911