Imported Upstream version 1.1
[platform/upstream/libnl1.git] / lib / route / cls / u32.c
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-2006 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_api
16  * @defgroup u32 Universal 32-bit Classifier
17  *
18  * @{
19  */
20
21 #include <netlink-local.h>
22 #include <netlink-tc.h>
23 #include <netlink/netlink.h>
24 #include <netlink/attr.h>
25 #include <netlink/utils.h>
26 #include <netlink/route/tc.h>
27 #include <netlink/route/classifier.h>
28 #include <netlink/route/classifier-modules.h>
29 #include <netlink/route/cls/u32.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
43 static inline struct rtnl_u32 *u32_cls(struct rtnl_cls *cls)
44 {
45         return (struct rtnl_u32 *) cls->c_subdata;
46 }
47
48 static inline struct rtnl_u32 *u32_alloc(struct rtnl_cls *cls)
49 {
50         if (!cls->c_subdata)
51                 cls->c_subdata = calloc(1, sizeof(struct rtnl_u32));
52
53         return u32_cls(cls);
54 }
55
56 static inline struct tc_u32_sel *u32_selector(struct rtnl_u32 *u)
57 {
58         return (struct tc_u32_sel *) u->cu_selector->d_data;
59 }
60
61 static inline struct tc_u32_sel *u32_selector_alloc(struct rtnl_u32 *u)
62 {
63         if (!u->cu_selector)
64                 u->cu_selector = nl_data_alloc(NULL, sizeof(struct tc_u32_sel));
65
66         return u32_selector(u);
67 }
68
69 static struct nla_policy u32_policy[TCA_U32_MAX+1] = {
70         [TCA_U32_DIVISOR]       = { .type = NLA_U32 },
71         [TCA_U32_HASH]          = { .type = NLA_U32 },
72         [TCA_U32_CLASSID]       = { .type = NLA_U32 },
73         [TCA_U32_LINK]          = { .type = NLA_U32 },
74         [TCA_U32_INDEV]         = { .type = NLA_STRING,
75                                     .maxlen = IFNAMSIZ },
76         [TCA_U32_SEL]           = { .minlen = sizeof(struct tc_u32_sel) },
77         [TCA_U32_PCNT]          = { .minlen = sizeof(struct tc_u32_pcnt) },
78 };
79
80 static int u32_msg_parser(struct rtnl_cls *cls)
81 {
82         int err;
83         struct nlattr *tb[TCA_U32_MAX + 1];
84         struct rtnl_u32 *u;
85
86         err = tca_parse(tb, TCA_U32_MAX, (struct rtnl_tca *) cls, u32_policy);
87         if (err < 0)
88                 return err;
89
90         u = u32_alloc(cls);
91         if (!u)
92                 goto errout_nomem;
93
94         if (tb[TCA_U32_DIVISOR]) {
95                 u->cu_divisor = nla_get_u32(tb[TCA_U32_DIVISOR]);
96                 u->cu_mask |= U32_ATTR_DIVISOR;
97         }
98
99         if (tb[TCA_U32_SEL]) {
100                 u->cu_selector = nla_get_data(tb[TCA_U32_SEL]);
101                 if (!u->cu_selector)
102                         goto errout_nomem;
103                 u->cu_mask |= U32_ATTR_SELECTOR;
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_act = nla_get_data(tb[TCA_U32_ACT]);
123                 if (!u->cu_act)
124                         goto errout_nomem;
125                 u->cu_mask |= U32_ATTR_ACTION;
126         }
127
128         if (tb[TCA_U32_POLICE]) {
129                 u->cu_police = nla_get_data(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                 int pcnt_size;
138
139                 if (!tb[TCA_U32_SEL]) {
140                         err = nl_error(EINVAL, "Missing TCA_U32_SEL required "
141                                                "for TCA_U32_PCNT");
142                         goto errout;
143                 }
144                 
145                 sel = u->cu_selector->d_data;
146                 pcnt_size = sizeof(struct tc_u32_pcnt) +
147                                 (sel->nkeys * sizeof(uint64_t));
148                 if (nla_len(tb[TCA_U32_PCNT]) < pcnt_size) {
149                         err = nl_error(EINVAL, "Invalid size for TCA_U32_PCNT");
150                         goto errout;
151                 }
152
153                 u->cu_pcnt = nla_get_data(tb[TCA_U32_PCNT]);
154                 if (!u->cu_pcnt)
155                         goto errout_nomem;
156                 u->cu_mask |= U32_ATTR_PCNT;
157         }
158
159         if (tb[TCA_U32_INDEV]) {
160                 nla_strlcpy(u->cu_indev, tb[TCA_U32_INDEV], IFNAMSIZ);
161                 u->cu_mask |= U32_ATTR_INDEV;
162         }
163
164         return 0;
165
166 errout_nomem:
167         err = nl_errno(ENOMEM);
168 errout:
169         return err;
170 }
171
172 static void u32_free_data(struct rtnl_cls *cls)
173 {
174         struct rtnl_u32 *u = u32_cls(cls);
175
176         if (!u)
177                 return;
178
179         nl_data_free(u->cu_selector);
180         nl_data_free(u->cu_act);
181         nl_data_free(u->cu_police);
182         nl_data_free(u->cu_pcnt);
183
184         free(cls->c_subdata);
185 }
186
187 static int u32_clone(struct rtnl_cls *_dst, struct rtnl_cls *_src)
188 {
189         struct rtnl_u32 *dst, *src = u32_cls(_src);
190
191         if (!src)
192                 return 0;
193
194         dst = u32_alloc(_dst);
195         if (!dst)
196                 return nl_errno(ENOMEM);
197
198         if (src->cu_selector)
199                 if (!(dst->cu_selector = nl_data_clone(src->cu_selector)))
200                         goto errout;
201
202         if (src->cu_act)
203                 if (!(dst->cu_act = nl_data_clone(src->cu_act)))
204                         goto errout;
205
206         if (src->cu_police)
207                 if (!(dst->cu_police = nl_data_clone(src->cu_police)))
208                         goto errout;
209
210         if (src->cu_pcnt)
211                 if (!(dst->cu_pcnt = nl_data_clone(src->cu_pcnt)))
212                         goto errout;
213
214         return 0;
215 errout:
216         return nl_get_errno();
217 }
218
219 static int u32_dump_brief(struct rtnl_cls *cls, struct nl_dump_params *p,
220                           int line)
221 {
222         struct rtnl_u32 *u = u32_cls(cls);
223         char buf[32];
224
225         if (!u)
226                 goto ignore;
227
228         if (u->cu_mask & U32_ATTR_DIVISOR)
229                 dp_dump(p, " divisor %u", u->cu_divisor);
230         else if (u->cu_mask & U32_ATTR_CLASSID)
231                 dp_dump(p, " target %s",
232                         rtnl_tc_handle2str(u->cu_classid, buf, sizeof(buf)));
233
234 ignore:
235         return line;
236 }
237
238 static int print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel,
239                           struct rtnl_cls *cls, struct rtnl_u32 *u, int line)
240 {
241         int i;
242         struct tc_u32_key *key;
243
244         if (sel->hmask || sel->hoff) {
245                 /* I guess this will never be used since the kernel only
246                  * exports the selector if no divisor is set but hash offset
247                  * and hash mask make only sense in hash filters with divisor
248                  * set */
249                 dp_dump(p, " hash at %u & 0x%x", sel->hoff, sel->hmask);
250         }
251
252         if (sel->flags & (TC_U32_OFFSET | TC_U32_VAROFFSET)) {
253                 dp_dump(p, " offset at %u", sel->off);
254
255                 if (sel->flags & TC_U32_VAROFFSET)
256                         dp_dump(p, " variable (at %u & 0x%x) >> %u",
257                                 sel->offoff, ntohs(sel->offmask), sel->offshift);
258         }
259
260         if (sel->flags) {
261                 int flags = sel->flags;
262                 dp_dump(p, " <");
263
264 #define PRINT_FLAG(f) if (flags & TC_U32_##f) { \
265         flags &= ~TC_U32_##f; dp_dump(p, #f "%s", flags ? "," : ""); }
266
267                 PRINT_FLAG(TERMINAL);
268                 PRINT_FLAG(OFFSET);
269                 PRINT_FLAG(VAROFFSET);
270                 PRINT_FLAG(EAT);
271 #undef PRINT_FLAG
272
273                 dp_dump(p, ">");
274         }
275                 
276         
277         for (i = 0; i < sel->nkeys; i++) {
278                 key = (struct tc_u32_key *) ((char *) sel + sizeof(*sel)) + i;
279
280                 dp_dump(p, "\n");
281                 dp_dump_line(p, line++, "      match key at %s%u ",
282                 key->offmask ? "nexthdr+" : "", key->off);
283
284                 if (key->offmask)
285                         dp_dump(p, "[0x%u] ", key->offmask);
286
287                 dp_dump(p, "& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val));
288
289                 if (p->dp_type == NL_DUMP_STATS &&
290                     (u->cu_mask & U32_ATTR_PCNT)) {
291                         struct tc_u32_pcnt *pcnt = u->cu_pcnt->d_data;
292                         dp_dump(p, " successful %" PRIu64, pcnt->kcnts[i]);
293                 }
294         }
295
296         return line;
297 }
298
299
300 static int u32_dump_full(struct rtnl_cls *cls, struct nl_dump_params *p,
301                          int line)
302 {
303         struct rtnl_u32 *u = u32_cls(cls);
304         struct tc_u32_sel *s;
305
306         if (!u)
307                 goto ignore;
308
309         if (!(u->cu_mask & U32_ATTR_SELECTOR)) {
310                 dp_dump(p, "no-selector\n");
311                 return line;
312         }
313         
314         s = u->cu_selector->d_data;
315
316         dp_dump(p, "nkeys %u ", s->nkeys);
317
318         if (u->cu_mask & U32_ATTR_HASH)
319                 dp_dump(p, "ht key 0x%x hash 0x%u",
320                         TC_U32_USERHTID(u->cu_hash), TC_U32_HASH(u->cu_hash));
321
322         if (u->cu_mask & U32_ATTR_LINK)
323                 dp_dump(p, "link %u ", u->cu_link);
324
325         if (u->cu_mask & U32_ATTR_INDEV)
326                 dp_dump(p, "indev %s ", u->cu_indev);
327
328         line = print_selector(p, s, cls, u, line);
329         dp_dump(p, "\n");
330
331 ignore:
332         return line;
333
334 #if 0   
335 #define U32_ATTR_ACTION       0x040
336 #define U32_ATTR_POLICE       0x080
337
338         struct nl_data   act;
339         struct nl_data   police;
340 #endif
341 }
342
343 static int u32_dump_stats(struct rtnl_cls *cls, struct nl_dump_params *p,
344                           int line)
345 {
346         struct rtnl_u32 *u = u32_cls(cls);
347
348         if (!u)
349                 goto ignore;
350
351         if (u->cu_mask & U32_ATTR_PCNT) {
352                 struct tc_u32_pcnt *pc = u->cu_pcnt->d_data;
353                 dp_dump(p, "\n");
354                 dp_dump_line(p, line++, "%s         successful       hits\n");
355                 dp_dump_line(p, line++, "%s           %8llu   %8llu\n",
356                              pc->rhit, pc->rcnt);
357         }
358
359 ignore:
360         return line;
361 }
362
363 static struct nl_msg *u32_get_opts(struct rtnl_cls *cls)
364 {
365         struct rtnl_u32 *u;
366         struct nl_msg *msg;
367         
368         u = u32_cls(cls);
369         if (!u)
370                 return NULL;
371
372         msg = nlmsg_alloc();
373         if (!msg)
374                 return NULL;
375
376         if (u->cu_mask & U32_ATTR_DIVISOR)
377                 nla_put_u32(msg, TCA_U32_DIVISOR, u->cu_divisor);
378
379         if (u->cu_mask & U32_ATTR_HASH)
380                 nla_put_u32(msg, TCA_U32_HASH, u->cu_hash);
381
382         if (u->cu_mask & U32_ATTR_CLASSID)
383                 nla_put_u32(msg, TCA_U32_CLASSID, u->cu_classid);
384
385         if (u->cu_mask & U32_ATTR_LINK)
386                 nla_put_u32(msg, TCA_U32_LINK, u->cu_link);
387
388         if (u->cu_mask & U32_ATTR_SELECTOR)
389                 nla_put_data(msg, TCA_U32_SEL, u->cu_selector);
390
391         if (u->cu_mask & U32_ATTR_ACTION)
392                 nla_put_data(msg, TCA_U32_ACT, u->cu_act);
393
394         if (u->cu_mask & U32_ATTR_POLICE)
395                 nla_put_data(msg, TCA_U32_POLICE, u->cu_police);
396
397         if (u->cu_mask & U32_ATTR_INDEV)
398                 nla_put_string(msg, TCA_U32_INDEV, u->cu_indev);
399
400         return msg;
401 }
402
403 /**
404  * @name Attribute Modifications
405  * @{
406  */
407
408 void rtnl_u32_set_handle(struct rtnl_cls *cls, int htid, int hash,
409                          int nodeid)
410 {
411         uint32_t handle = (htid << 20) | (hash << 12) | nodeid;
412
413         tca_set_handle((struct rtnl_tca *) cls, handle );
414 }
415  
416 int rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid)
417 {
418         struct rtnl_u32 *u;
419         
420         u = u32_alloc(cls);
421         if (!u)
422                 return nl_errno(ENOMEM);
423
424         u->cu_classid = classid;
425         u->cu_mask |= U32_ATTR_CLASSID;
426
427         return 0;
428 }
429
430 /** @} */
431
432 /**
433  * @name Selector Modifications
434  * @{
435  */
436
437 int rtnl_u32_set_flags(struct rtnl_cls *cls, int flags)
438 {
439         struct tc_u32_sel *sel;
440         struct rtnl_u32 *u;
441
442         u = u32_alloc(cls);
443         if (!u)
444                 return nl_errno(ENOMEM);
445
446         sel = u32_selector_alloc(u);
447         if (!sel)
448                 return nl_errno(ENOMEM);
449
450         sel->flags |= flags;
451         u->cu_mask |= U32_ATTR_SELECTOR;
452
453         return 0;
454 }
455
456 /**
457  * Append new 32-bit key to the selector
458  *
459  * @arg cls     classifier to be modifier
460  * @arg val     value to be matched (network byte-order)
461  * @arg mask    mask to be applied before matching (network byte-order)
462  * @arg off     offset, in bytes, to start matching
463  * @arg offmask offset mask
464  *
465  * General selectors define the pattern, mask and offset the pattern will be
466  * matched to the packet contents. Using the general selectors you can match
467  * virtually any single bit in the IP (or upper layer) header.
468  *
469 */
470 int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
471                      int off, int offmask)
472 {
473         struct tc_u32_sel *sel;
474         struct rtnl_u32 *u;
475         int err;
476
477         u = u32_alloc(cls);
478         if (!u)
479                 return nl_errno(ENOMEM);
480
481         sel = u32_selector_alloc(u);
482         if (!sel)
483                 return nl_errno(ENOMEM);
484
485         err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
486         if (err < 0)
487                 return err;
488
489         /* the selector might have been moved by realloc */
490         sel = u32_selector(u);
491
492         sel->keys[sel->nkeys].mask = mask;
493         sel->keys[sel->nkeys].val = val & mask;
494         sel->keys[sel->nkeys].off = off;
495         sel->keys[sel->nkeys].offmask = offmask;
496         sel->nkeys++;
497         u->cu_mask |= U32_ATTR_SELECTOR;
498
499         return 0;
500 }
501
502 int rtnl_u32_add_key_uint8(struct rtnl_cls *cls, uint8_t val, uint8_t mask,
503                            int off, int offmask)
504 {
505         int shift = 24 - 8 * (off & 3);
506
507         return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
508                                 htonl((uint32_t)mask << shift),
509                                 off & ~3, offmask);
510 }
511
512 /**
513  * Append new selector key to match a 16-bit number
514  *
515  * @arg cls     classifier to be modified
516  * @arg val     value to be matched (host byte-order)
517  * @arg mask    mask to be applied before matching (host byte-order)
518  * @arg off     offset, in bytes, to start matching
519  * @arg offmask offset mask
520 */
521 int rtnl_u32_add_key_uint16(struct rtnl_cls *cls, uint16_t val, uint16_t mask,
522                             int off, int offmask)
523 {
524         int shift = ((off & 3) == 0 ? 16 : 0);
525         if (off % 2)
526                 return nl_error(EINVAL, "Invalid offset alignment");
527
528         return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
529                                 htonl((uint32_t)mask << shift),
530                                 off & ~3, offmask);
531 }
532
533 /**
534  * Append new selector key to match a 32-bit number
535  *
536  * @arg cls     classifier to be modified
537  * @arg val     value to be matched (host byte-order)
538  * @arg mask    mask to be applied before matching (host byte-order)
539  * @arg off     offset, in bytes, to start matching
540  * @arg offmask offset mask
541 */
542 int rtnl_u32_add_key_uint32(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
543                             int off, int offmask)
544 {
545         return rtnl_u32_add_key(cls, htonl(val), htonl(mask),
546                                 off & ~3, offmask);
547 }
548
549 int rtnl_u32_add_key_in_addr(struct rtnl_cls *cls, struct in_addr *addr,
550                              uint8_t bitmask, int off, int offmask)
551 {
552         uint32_t mask = 0xFFFFFFFF << (32 - bitmask);
553         return rtnl_u32_add_key(cls, addr->s_addr, htonl(mask), off, offmask);
554 }
555
556 int rtnl_u32_add_key_in6_addr(struct rtnl_cls *cls, struct in6_addr *addr,
557                               uint8_t bitmask, int off, int offmask)
558 {
559         int i, err;
560
561         for (i = 1; i <= 4; i++) {
562                 if (32 * i - bitmask <= 0) {
563                         if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
564                                                 0xFFFFFFFF, off+4*(i-1), offmask)) < 0)
565                                 return err;
566                 }
567                 else if (32 * i - bitmask < 32) {
568                         uint32_t mask = 0xFFFFFFFF << (32 * i - bitmask);
569                         if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
570                                                 htonl(mask), off+4*(i-1), offmask)) < 0)
571                                 return err;
572                 }
573                 /* otherwise, if (32*i - bitmask >= 32) no key is generated */
574         }
575
576         return 0;
577 }
578
579 /** @} */
580
581 static struct rtnl_cls_ops u32_ops = {
582         .co_kind                = "u32",
583         .co_msg_parser          = u32_msg_parser,
584         .co_free_data           = u32_free_data,
585         .co_clone               = u32_clone,
586         .co_get_opts            = u32_get_opts,
587         .co_dump[NL_DUMP_BRIEF] = u32_dump_brief,
588         .co_dump[NL_DUMP_FULL]  = u32_dump_full,
589         .co_dump[NL_DUMP_STATS] = u32_dump_stats,
590 };
591
592 static void __init u32_init(void)
593 {
594         rtnl_cls_register(&u32_ops);
595 }
596
597 static void __exit u32_exit(void)
598 {
599         rtnl_cls_unregister(&u32_ops);
600 }
601
602 /** @} */