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
u32_selector(struct rtnl_u32 * u)40 static 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
u32_selector_alloc(struct rtnl_u32 * u)45 static 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
u32_mark_alloc(struct rtnl_u32 * u)53 static 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
61 static 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
u32_msg_parser(struct rtnl_tc * tc,void * data)73 static 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
161 errout_nomem:
162 err = -NLE_NOMEM;
163 errout:
164 return err;
165 }
166
u32_free_data(struct rtnl_tc * tc,void * data)167 static 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
u32_clone(void * _dst,void * _src)179 static 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
u32_dump_line(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)276 static 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
print_selector(struct nl_dump_params * p,struct tc_u32_sel * sel,struct rtnl_u32 * u)292 static 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
u32_dump_details(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)353 static 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
u32_dump_stats(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)393 static 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
u32_msg_fill(struct rtnl_tc * tc,void * data,struct nl_msg * msg)411 static 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
452 nla_put_failure:
453 return -NLE_NOMEM;
454 }
455
456 /**
457 * @name Attribute Modifications
458 * @{
459 */
460
rtnl_u32_set_handle(struct rtnl_cls * cls,int htid,int hash,int nodeid)461 void 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
rtnl_u32_set_classid(struct rtnl_cls * cls,uint32_t classid)469 int 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
rtnl_u32_get_classid(struct rtnl_cls * cls,uint32_t * classid)482 int 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
rtnl_u32_set_divisor(struct rtnl_cls * cls,uint32_t divisor)496 int 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
rtnl_u32_set_link(struct rtnl_cls * cls,uint32_t link)508 int 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
rtnl_u32_set_hashtable(struct rtnl_cls * cls,uint32_t ht)520 int 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
rtnl_u32_set_hashmask(struct rtnl_cls * cls,uint32_t hashmask,uint32_t offset)532 int 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
rtnl_u32_set_selector(struct rtnl_cls * cls,int offoff,uint32_t offmask,char offshift,uint16_t off,char flags)551 int 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
rtnl_u32_set_cls_terminal(struct rtnl_cls * cls)574 int 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
rtnl_u32_add_action(struct rtnl_cls * cls,struct rtnl_act * act)590 int 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
rtnl_u32_get_action(struct rtnl_cls * cls)610 struct 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
rtnl_u32_del_action(struct rtnl_cls * cls,struct rtnl_act * act)623 int 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
rtnl_u32_set_flags(struct rtnl_cls * cls,int flags)653 int 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 */
rtnl_u32_add_key(struct rtnl_cls * cls,uint32_t val,uint32_t mask,int off,int offmask)685 int 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
rtnl_u32_add_mark(struct rtnl_cls * cls,uint32_t val,uint32_t mask)719 int 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
rtnl_u32_del_mark(struct rtnl_cls * cls)739 int 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 */
rtnl_u32_get_key(struct rtnl_cls * cls,uint8_t index,uint32_t * val,uint32_t * mask,int * off,int * offmask)770 int 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
rtnl_u32_add_key_uint8(struct rtnl_cls * cls,uint8_t val,uint8_t mask,int off,int offmask)794 int 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 */
rtnl_u32_add_key_uint16(struct rtnl_cls * cls,uint16_t val,uint16_t mask,int off,int offmask)813 int 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 */
rtnl_u32_add_key_uint32(struct rtnl_cls * cls,uint32_t val,uint32_t mask,int off,int offmask)834 int 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
rtnl_u32_add_key_in_addr(struct rtnl_cls * cls,const struct in_addr * addr,uint8_t bitmask,int off,int offmask)841 int 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
rtnl_u32_add_key_in6_addr(struct rtnl_cls * cls,const struct in6_addr * addr,uint8_t bitmask,int off,int offmask)848 int 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
873 static 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
u32_init(void)888 static void __init u32_init(void)
889 {
890 rtnl_tc_register(&u32_ops);
891 }
892
u32_exit(void)893 static void __exit u32_exit(void)
894 {
895 rtnl_tc_unregister(&u32_ops);
896 }
897
898 /** @} */
899