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