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