libnl 1.1

lib/route/cls/u32.c

00001 /*
00002  * lib/route/cls/u32.c          u32 classifier
00003  *
00004  *      This library is free software; you can redistribute it and/or
00005  *      modify it under the terms of the GNU Lesser General Public
00006  *      License as published by the Free Software Foundation version 2.1
00007  *      of the License.
00008  *
00009  * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
00010  * Copyright (c) 2005-2006 Petr Gotthard <petr.gotthard@siemens.com>
00011  * Copyright (c) 2005-2006 Siemens AG Oesterreich
00012  */
00013 
00014 /**
00015  * @ingroup cls_api
00016  * @defgroup u32 Universal 32-bit Classifier
00017  *
00018  * @{
00019  */
00020 
00021 #include <netlink-local.h>
00022 #include <netlink-tc.h>
00023 #include <netlink/netlink.h>
00024 #include <netlink/attr.h>
00025 #include <netlink/utils.h>
00026 #include <netlink/route/tc.h>
00027 #include <netlink/route/classifier.h>
00028 #include <netlink/route/classifier-modules.h>
00029 #include <netlink/route/cls/u32.h>
00030 
00031 /** @cond SKIP */
00032 #define U32_ATTR_DIVISOR      0x001
00033 #define U32_ATTR_HASH         0x002
00034 #define U32_ATTR_CLASSID      0x004
00035 #define U32_ATTR_LINK         0x008
00036 #define U32_ATTR_PCNT         0x010
00037 #define U32_ATTR_SELECTOR     0x020
00038 #define U32_ATTR_ACTION       0x040
00039 #define U32_ATTR_POLICE       0x080
00040 #define U32_ATTR_INDEV        0x100
00041 /** @endcond */
00042 
00043 static inline struct rtnl_u32 *u32_cls(struct rtnl_cls *cls)
00044 {
00045         return (struct rtnl_u32 *) cls->c_subdata;
00046 }
00047 
00048 static inline struct rtnl_u32 *u32_alloc(struct rtnl_cls *cls)
00049 {
00050         if (!cls->c_subdata)
00051                 cls->c_subdata = calloc(1, sizeof(struct rtnl_u32));
00052 
00053         return u32_cls(cls);
00054 }
00055 
00056 static inline struct tc_u32_sel *u32_selector(struct rtnl_u32 *u)
00057 {
00058         return (struct tc_u32_sel *) u->cu_selector->d_data;
00059 }
00060 
00061 static inline struct tc_u32_sel *u32_selector_alloc(struct rtnl_u32 *u)
00062 {
00063         if (!u->cu_selector)
00064                 u->cu_selector = nl_data_alloc(NULL, sizeof(struct tc_u32_sel));
00065 
00066         return u32_selector(u);
00067 }
00068 
00069 static struct nla_policy u32_policy[TCA_U32_MAX+1] = {
00070         [TCA_U32_DIVISOR]       = { .type = NLA_U32 },
00071         [TCA_U32_HASH]          = { .type = NLA_U32 },
00072         [TCA_U32_CLASSID]       = { .type = NLA_U32 },
00073         [TCA_U32_LINK]          = { .type = NLA_U32 },
00074         [TCA_U32_INDEV]         = { .type = NLA_STRING,
00075                                     .maxlen = IFNAMSIZ },
00076         [TCA_U32_SEL]           = { .minlen = sizeof(struct tc_u32_sel) },
00077         [TCA_U32_PCNT]          = { .minlen = sizeof(struct tc_u32_pcnt) },
00078 };
00079 
00080 static int u32_msg_parser(struct rtnl_cls *cls)
00081 {
00082         int err;
00083         struct nlattr *tb[TCA_U32_MAX + 1];
00084         struct rtnl_u32 *u;
00085 
00086         err = tca_parse(tb, TCA_U32_MAX, (struct rtnl_tca *) cls, u32_policy);
00087         if (err < 0)
00088                 return err;
00089 
00090         u = u32_alloc(cls);
00091         if (!u)
00092                 goto errout_nomem;
00093 
00094         if (tb[TCA_U32_DIVISOR]) {
00095                 u->cu_divisor = nla_get_u32(tb[TCA_U32_DIVISOR]);
00096                 u->cu_mask |= U32_ATTR_DIVISOR;
00097         }
00098 
00099         if (tb[TCA_U32_SEL]) {
00100                 u->cu_selector = nla_get_data(tb[TCA_U32_SEL]);
00101                 if (!u->cu_selector)
00102                         goto errout_nomem;
00103                 u->cu_mask |= U32_ATTR_SELECTOR;
00104         }
00105 
00106         if (tb[TCA_U32_HASH]) {
00107                 u->cu_hash = nla_get_u32(tb[TCA_U32_HASH]);
00108                 u->cu_mask |= U32_ATTR_HASH;
00109         }
00110 
00111         if (tb[TCA_U32_CLASSID]) {
00112                 u->cu_classid = nla_get_u32(tb[TCA_U32_CLASSID]);
00113                 u->cu_mask |= U32_ATTR_CLASSID;
00114         }
00115 
00116         if (tb[TCA_U32_LINK]) {
00117                 u->cu_link = nla_get_u32(tb[TCA_U32_LINK]);
00118                 u->cu_mask |= U32_ATTR_LINK;
00119         }
00120 
00121         if (tb[TCA_U32_ACT]) {
00122                 u->cu_act = nla_get_data(tb[TCA_U32_ACT]);
00123                 if (!u->cu_act)
00124                         goto errout_nomem;
00125                 u->cu_mask |= U32_ATTR_ACTION;
00126         }
00127 
00128         if (tb[TCA_U32_POLICE]) {
00129                 u->cu_police = nla_get_data(tb[TCA_U32_POLICE]);
00130                 if (!u->cu_police)
00131                         goto errout_nomem;
00132                 u->cu_mask |= U32_ATTR_POLICE;
00133         }
00134 
00135         if (tb[TCA_U32_PCNT]) {
00136                 struct tc_u32_sel *sel;
00137                 int pcnt_size;
00138 
00139                 if (!tb[TCA_U32_SEL]) {
00140                         err = nl_error(EINVAL, "Missing TCA_U32_SEL required "
00141                                                "for TCA_U32_PCNT");
00142                         goto errout;
00143                 }
00144                 
00145                 sel = u->cu_selector->d_data;
00146                 pcnt_size = sizeof(struct tc_u32_pcnt) +
00147                                 (sel->nkeys * sizeof(uint64_t));
00148                 if (nla_len(tb[TCA_U32_PCNT]) < pcnt_size) {
00149                         err = nl_error(EINVAL, "Invalid size for TCA_U32_PCNT");
00150                         goto errout;
00151                 }
00152 
00153                 u->cu_pcnt = nla_get_data(tb[TCA_U32_PCNT]);
00154                 if (!u->cu_pcnt)
00155                         goto errout_nomem;
00156                 u->cu_mask |= U32_ATTR_PCNT;
00157         }
00158 
00159         if (tb[TCA_U32_INDEV]) {
00160                 nla_strlcpy(u->cu_indev, tb[TCA_U32_INDEV], IFNAMSIZ);
00161                 u->cu_mask |= U32_ATTR_INDEV;
00162         }
00163 
00164         return 0;
00165 
00166 errout_nomem:
00167         err = nl_errno(ENOMEM);
00168 errout:
00169         return err;
00170 }
00171 
00172 static void u32_free_data(struct rtnl_cls *cls)
00173 {
00174         struct rtnl_u32 *u = u32_cls(cls);
00175 
00176         if (!u)
00177                 return;
00178 
00179         nl_data_free(u->cu_selector);
00180         nl_data_free(u->cu_act);
00181         nl_data_free(u->cu_police);
00182         nl_data_free(u->cu_pcnt);
00183 
00184         free(cls->c_subdata);
00185 }
00186 
00187 static int u32_clone(struct rtnl_cls *_dst, struct rtnl_cls *_src)
00188 {
00189         struct rtnl_u32 *dst, *src = u32_cls(_src);
00190 
00191         if (!src)
00192                 return 0;
00193 
00194         dst = u32_alloc(_dst);
00195         if (!dst)
00196                 return nl_errno(ENOMEM);
00197 
00198         if (src->cu_selector)
00199                 if (!(dst->cu_selector = nl_data_clone(src->cu_selector)))
00200                         goto errout;
00201 
00202         if (src->cu_act)
00203                 if (!(dst->cu_act = nl_data_clone(src->cu_act)))
00204                         goto errout;
00205 
00206         if (src->cu_police)
00207                 if (!(dst->cu_police = nl_data_clone(src->cu_police)))
00208                         goto errout;
00209 
00210         if (src->cu_pcnt)
00211                 if (!(dst->cu_pcnt = nl_data_clone(src->cu_pcnt)))
00212                         goto errout;
00213 
00214         return 0;
00215 errout:
00216         return nl_get_errno();
00217 }
00218 
00219 static int u32_dump_brief(struct rtnl_cls *cls, struct nl_dump_params *p,
00220                           int line)
00221 {
00222         struct rtnl_u32 *u = u32_cls(cls);
00223         char buf[32];
00224 
00225         if (!u)
00226                 goto ignore;
00227 
00228         if (u->cu_mask & U32_ATTR_DIVISOR)
00229                 dp_dump(p, " divisor %u", u->cu_divisor);
00230         else if (u->cu_mask & U32_ATTR_CLASSID)
00231                 dp_dump(p, " target %s",
00232                         rtnl_tc_handle2str(u->cu_classid, buf, sizeof(buf)));
00233 
00234 ignore:
00235         return line;
00236 }
00237 
00238 static int print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel,
00239                           struct rtnl_cls *cls, struct rtnl_u32 *u, int line)
00240 {
00241         int i;
00242         struct tc_u32_key *key;
00243 
00244         if (sel->hmask || sel->hoff) {
00245                 /* I guess this will never be used since the kernel only
00246                  * exports the selector if no divisor is set but hash offset
00247                  * and hash mask make only sense in hash filters with divisor
00248                  * set */
00249                 dp_dump(p, " hash at %u & 0x%x", sel->hoff, sel->hmask);
00250         }
00251 
00252         if (sel->flags & (TC_U32_OFFSET | TC_U32_VAROFFSET)) {
00253                 dp_dump(p, " offset at %u", sel->off);
00254 
00255                 if (sel->flags & TC_U32_VAROFFSET)
00256                         dp_dump(p, " variable (at %u & 0x%x) >> %u",
00257                                 sel->offoff, ntohs(sel->offmask), sel->offshift);
00258         }
00259 
00260         if (sel->flags) {
00261                 int flags = sel->flags;
00262                 dp_dump(p, " <");
00263 
00264 #define PRINT_FLAG(f) if (flags & TC_U32_##f) { \
00265         flags &= ~TC_U32_##f; dp_dump(p, #f "%s", flags ? "," : ""); }
00266 
00267                 PRINT_FLAG(TERMINAL);
00268                 PRINT_FLAG(OFFSET);
00269                 PRINT_FLAG(VAROFFSET);
00270                 PRINT_FLAG(EAT);
00271 #undef PRINT_FLAG
00272 
00273                 dp_dump(p, ">");
00274         }
00275                 
00276         
00277         for (i = 0; i < sel->nkeys; i++) {
00278                 key = (struct tc_u32_key *) ((char *) sel + sizeof(*sel)) + i;
00279 
00280                 dp_dump(p, "\n");
00281                 dp_dump_line(p, line++, "      match key at %s%u ",
00282                 key->offmask ? "nexthdr+" : "", key->off);
00283 
00284                 if (key->offmask)
00285                         dp_dump(p, "[0x%u] ", key->offmask);
00286 
00287                 dp_dump(p, "& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val));
00288 
00289                 if (p->dp_type == NL_DUMP_STATS &&
00290                     (u->cu_mask & U32_ATTR_PCNT)) {
00291                         struct tc_u32_pcnt *pcnt = u->cu_pcnt->d_data;
00292                         dp_dump(p, " successful %" PRIu64, pcnt->kcnts[i]);
00293                 }
00294         }
00295 
00296         return line;
00297 }
00298 
00299 
00300 static int u32_dump_full(struct rtnl_cls *cls, struct nl_dump_params *p,
00301                          int line)
00302 {
00303         struct rtnl_u32 *u = u32_cls(cls);
00304         struct tc_u32_sel *s;
00305 
00306         if (!u)
00307                 goto ignore;
00308 
00309         if (!(u->cu_mask & U32_ATTR_SELECTOR)) {
00310                 dp_dump(p, "no-selector\n");
00311                 return line;
00312         }
00313         
00314         s = u->cu_selector->d_data;
00315 
00316         dp_dump(p, "nkeys %u ", s->nkeys);
00317 
00318         if (u->cu_mask & U32_ATTR_HASH)
00319                 dp_dump(p, "ht key 0x%x hash 0x%u",
00320                         TC_U32_USERHTID(u->cu_hash), TC_U32_HASH(u->cu_hash));
00321 
00322         if (u->cu_mask & U32_ATTR_LINK)
00323                 dp_dump(p, "link %u ", u->cu_link);
00324 
00325         if (u->cu_mask & U32_ATTR_INDEV)
00326                 dp_dump(p, "indev %s ", u->cu_indev);
00327 
00328         line = print_selector(p, s, cls, u, line);
00329         dp_dump(p, "\n");
00330 
00331 ignore:
00332         return line;
00333 
00334 #if 0   
00335 #define U32_ATTR_ACTION       0x040
00336 #define U32_ATTR_POLICE       0x080
00337 
00338         struct nl_data   act;
00339         struct nl_data   police;
00340 #endif
00341 }
00342 
00343 static int u32_dump_stats(struct rtnl_cls *cls, struct nl_dump_params *p,
00344                           int line)
00345 {
00346         struct rtnl_u32 *u = u32_cls(cls);
00347 
00348         if (!u)
00349                 goto ignore;
00350 
00351         if (u->cu_mask & U32_ATTR_PCNT) {
00352                 struct tc_u32_pcnt *pc = u->cu_pcnt->d_data;
00353                 dp_dump(p, "\n");
00354                 dp_dump_line(p, line++, "%s         successful       hits\n");
00355                 dp_dump_line(p, line++, "%s           %8llu   %8llu\n",
00356                              pc->rhit, pc->rcnt);
00357         }
00358 
00359 ignore:
00360         return line;
00361 }
00362 
00363 static struct nl_msg *u32_get_opts(struct rtnl_cls *cls)
00364 {
00365         struct rtnl_u32 *u;
00366         struct nl_msg *msg;
00367         
00368         u = u32_cls(cls);
00369         if (!u)
00370                 return NULL;
00371 
00372         msg = nlmsg_alloc();
00373         if (!msg)
00374                 return NULL;
00375 
00376         if (u->cu_mask & U32_ATTR_DIVISOR)
00377                 nla_put_u32(msg, TCA_U32_DIVISOR, u->cu_divisor);
00378 
00379         if (u->cu_mask & U32_ATTR_HASH)
00380                 nla_put_u32(msg, TCA_U32_HASH, u->cu_hash);
00381 
00382         if (u->cu_mask & U32_ATTR_CLASSID)
00383                 nla_put_u32(msg, TCA_U32_CLASSID, u->cu_classid);
00384 
00385         if (u->cu_mask & U32_ATTR_LINK)
00386                 nla_put_u32(msg, TCA_U32_LINK, u->cu_link);
00387 
00388         if (u->cu_mask & U32_ATTR_SELECTOR)
00389                 nla_put_data(msg, TCA_U32_SEL, u->cu_selector);
00390 
00391         if (u->cu_mask & U32_ATTR_ACTION)
00392                 nla_put_data(msg, TCA_U32_ACT, u->cu_act);
00393 
00394         if (u->cu_mask & U32_ATTR_POLICE)
00395                 nla_put_data(msg, TCA_U32_POLICE, u->cu_police);
00396 
00397         if (u->cu_mask & U32_ATTR_INDEV)
00398                 nla_put_string(msg, TCA_U32_INDEV, u->cu_indev);
00399 
00400         return msg;
00401 }
00402 
00403 /**
00404  * @name Attribute Modifications
00405  * @{
00406  */
00407 
00408 void rtnl_u32_set_handle(struct rtnl_cls *cls, int htid, int hash,
00409                          int nodeid)
00410 {
00411         uint32_t handle = (htid << 20) | (hash << 12) | nodeid;
00412 
00413         tca_set_handle((struct rtnl_tca *) cls, handle );
00414 }
00415  
00416 int rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid)
00417 {
00418         struct rtnl_u32 *u;
00419         
00420         u = u32_alloc(cls);
00421         if (!u)
00422                 return nl_errno(ENOMEM);
00423 
00424         u->cu_classid = classid;
00425         u->cu_mask |= U32_ATTR_CLASSID;
00426 
00427         return 0;
00428 }
00429 
00430 /** @} */
00431 
00432 /**
00433  * @name Selector Modifications
00434  * @{
00435  */
00436 
00437 int rtnl_u32_set_flags(struct rtnl_cls *cls, int flags)
00438 {
00439         struct tc_u32_sel *sel;
00440         struct rtnl_u32 *u;
00441 
00442         u = u32_alloc(cls);
00443         if (!u)
00444                 return nl_errno(ENOMEM);
00445 
00446         sel = u32_selector_alloc(u);
00447         if (!sel)
00448                 return nl_errno(ENOMEM);
00449 
00450         sel->flags |= flags;
00451         u->cu_mask |= U32_ATTR_SELECTOR;
00452 
00453         return 0;
00454 }
00455 
00456 /**
00457  * Append new 32-bit key to the selector
00458  *
00459  * @arg cls     classifier to be modifier
00460  * @arg val     value to be matched (network byte-order)
00461  * @arg mask    mask to be applied before matching (network byte-order)
00462  * @arg off     offset, in bytes, to start matching
00463  * @arg offmask offset mask
00464  *
00465  * General selectors define the pattern, mask and offset the pattern will be
00466  * matched to the packet contents. Using the general selectors you can match
00467  * virtually any single bit in the IP (or upper layer) header.
00468  *
00469 */
00470 int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
00471                      int off, int offmask)
00472 {
00473         struct tc_u32_sel *sel;
00474         struct rtnl_u32 *u;
00475         int err;
00476 
00477         u = u32_alloc(cls);
00478         if (!u)
00479                 return nl_errno(ENOMEM);
00480 
00481         sel = u32_selector_alloc(u);
00482         if (!sel)
00483                 return nl_errno(ENOMEM);
00484 
00485         err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
00486         if (err < 0)
00487                 return err;
00488 
00489         /* the selector might have been moved by realloc */
00490         sel = u32_selector(u);
00491 
00492         sel->keys[sel->nkeys].mask = mask;
00493         sel->keys[sel->nkeys].val = val & mask;
00494         sel->keys[sel->nkeys].off = off;
00495         sel->keys[sel->nkeys].offmask = offmask;
00496         sel->nkeys++;
00497         u->cu_mask |= U32_ATTR_SELECTOR;
00498 
00499         return 0;
00500 }
00501 
00502 int rtnl_u32_add_key_uint8(struct rtnl_cls *cls, uint8_t val, uint8_t mask,
00503                            int off, int offmask)
00504 {
00505         int shift = 24 - 8 * (off & 3);
00506 
00507         return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
00508                                 htonl((uint32_t)mask << shift),
00509                                 off & ~3, offmask);
00510 }
00511 
00512 /**
00513  * Append new selector key to match a 16-bit number
00514  *
00515  * @arg cls     classifier to be modified
00516  * @arg val     value to be matched (host byte-order)
00517  * @arg mask    mask to be applied before matching (host byte-order)
00518  * @arg off     offset, in bytes, to start matching
00519  * @arg offmask offset mask
00520 */
00521 int rtnl_u32_add_key_uint16(struct rtnl_cls *cls, uint16_t val, uint16_t mask,
00522                             int off, int offmask)
00523 {
00524         int shift = ((off & 3) == 0 ? 16 : 0);
00525         if (off % 2)
00526                 return nl_error(EINVAL, "Invalid offset alignment");
00527 
00528         return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
00529                                 htonl((uint32_t)mask << shift),
00530                                 off & ~3, offmask);
00531 }
00532 
00533 /**
00534  * Append new selector key to match a 32-bit number
00535  *
00536  * @arg cls     classifier to be modified
00537  * @arg val     value to be matched (host byte-order)
00538  * @arg mask    mask to be applied before matching (host byte-order)
00539  * @arg off     offset, in bytes, to start matching
00540  * @arg offmask offset mask
00541 */
00542 int rtnl_u32_add_key_uint32(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
00543                             int off, int offmask)
00544 {
00545         return rtnl_u32_add_key(cls, htonl(val), htonl(mask),
00546                                 off & ~3, offmask);
00547 }
00548 
00549 int rtnl_u32_add_key_in_addr(struct rtnl_cls *cls, struct in_addr *addr,
00550                              uint8_t bitmask, int off, int offmask)
00551 {
00552         uint32_t mask = 0xFFFFFFFF << (32 - bitmask);
00553         return rtnl_u32_add_key(cls, addr->s_addr, htonl(mask), off, offmask);
00554 }
00555 
00556 int rtnl_u32_add_key_in6_addr(struct rtnl_cls *cls, struct in6_addr *addr,
00557                               uint8_t bitmask, int off, int offmask)
00558 {
00559         int i, err;
00560 
00561         for (i = 1; i <= 4; i++) {
00562                 if (32 * i - bitmask <= 0) {
00563                         if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
00564                                                 0xFFFFFFFF, off+4*(i-1), offmask)) < 0)
00565                                 return err;
00566                 }
00567                 else if (32 * i - bitmask < 32) {
00568                         uint32_t mask = 0xFFFFFFFF << (32 * i - bitmask);
00569                         if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
00570                                                 htonl(mask), off+4*(i-1), offmask)) < 0)
00571                                 return err;
00572                 }
00573                 /* otherwise, if (32*i - bitmask >= 32) no key is generated */
00574         }
00575 
00576         return 0;
00577 }
00578 
00579 /** @} */
00580 
00581 static struct rtnl_cls_ops u32_ops = {
00582         .co_kind                = "u32",
00583         .co_msg_parser          = u32_msg_parser,
00584         .co_free_data           = u32_free_data,
00585         .co_clone               = u32_clone,
00586         .co_get_opts            = u32_get_opts,
00587         .co_dump[NL_DUMP_BRIEF] = u32_dump_brief,
00588         .co_dump[NL_DUMP_FULL]  = u32_dump_full,
00589         .co_dump[NL_DUMP_STATS] = u32_dump_stats,
00590 };
00591 
00592 static void __init u32_init(void)
00593 {
00594         rtnl_cls_register(&u32_ops);
00595 }
00596 
00597 static void __exit u32_exit(void)
00598 {
00599         rtnl_cls_unregister(&u32_ops);
00600 }
00601 
00602 /** @} */