libnl 2.0

/build/buildd/libnl2-2.0/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-2009 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 tc_u32_sel *u32_selector(struct rtnl_u32 *u)
00044 {
00045         return (struct tc_u32_sel *) u->cu_selector->d_data;
00046 }
00047 
00048 static inline struct tc_u32_sel *u32_selector_alloc(struct rtnl_u32 *u)
00049 {
00050         if (!u->cu_selector)
00051                 u->cu_selector = nl_data_alloc(NULL, sizeof(struct tc_u32_sel));
00052 
00053         return u32_selector(u);
00054 }
00055 
00056 static struct nla_policy u32_policy[TCA_U32_MAX+1] = {
00057         [TCA_U32_DIVISOR]       = { .type = NLA_U32 },
00058         [TCA_U32_HASH]          = { .type = NLA_U32 },
00059         [TCA_U32_CLASSID]       = { .type = NLA_U32 },
00060         [TCA_U32_LINK]          = { .type = NLA_U32 },
00061         [TCA_U32_INDEV]         = { .type = NLA_STRING,
00062                                     .maxlen = IFNAMSIZ },
00063         [TCA_U32_SEL]           = { .minlen = sizeof(struct tc_u32_sel) },
00064         [TCA_U32_PCNT]          = { .minlen = sizeof(struct tc_u32_pcnt) },
00065 };
00066 
00067 static int u32_msg_parser(struct rtnl_cls *cls)
00068 {
00069         struct rtnl_u32 *u = rtnl_cls_data(cls);
00070         struct nlattr *tb[TCA_U32_MAX + 1];
00071         int err;
00072 
00073         err = tca_parse(tb, TCA_U32_MAX, (struct rtnl_tca *) cls, u32_policy);
00074         if (err < 0)
00075                 return err;
00076 
00077         if (tb[TCA_U32_DIVISOR]) {
00078                 u->cu_divisor = nla_get_u32(tb[TCA_U32_DIVISOR]);
00079                 u->cu_mask |= U32_ATTR_DIVISOR;
00080         }
00081 
00082         if (tb[TCA_U32_SEL]) {
00083                 u->cu_selector = nl_data_alloc_attr(tb[TCA_U32_SEL]);
00084                 if (!u->cu_selector)
00085                         goto errout_nomem;
00086                 u->cu_mask |= U32_ATTR_SELECTOR;
00087         }
00088 
00089         if (tb[TCA_U32_HASH]) {
00090                 u->cu_hash = nla_get_u32(tb[TCA_U32_HASH]);
00091                 u->cu_mask |= U32_ATTR_HASH;
00092         }
00093 
00094         if (tb[TCA_U32_CLASSID]) {
00095                 u->cu_classid = nla_get_u32(tb[TCA_U32_CLASSID]);
00096                 u->cu_mask |= U32_ATTR_CLASSID;
00097         }
00098 
00099         if (tb[TCA_U32_LINK]) {
00100                 u->cu_link = nla_get_u32(tb[TCA_U32_LINK]);
00101                 u->cu_mask |= U32_ATTR_LINK;
00102         }
00103 
00104         if (tb[TCA_U32_ACT]) {
00105                 u->cu_act = nl_data_alloc_attr(tb[TCA_U32_ACT]);
00106                 if (!u->cu_act)
00107                         goto errout_nomem;
00108                 u->cu_mask |= U32_ATTR_ACTION;
00109         }
00110 
00111         if (tb[TCA_U32_POLICE]) {
00112                 u->cu_police = nl_data_alloc_attr(tb[TCA_U32_POLICE]);
00113                 if (!u->cu_police)
00114                         goto errout_nomem;
00115                 u->cu_mask |= U32_ATTR_POLICE;
00116         }
00117 
00118         if (tb[TCA_U32_PCNT]) {
00119                 struct tc_u32_sel *sel;
00120                 int pcnt_size;
00121 
00122                 if (!tb[TCA_U32_SEL]) {
00123                         err = -NLE_MISSING_ATTR;
00124                         goto errout;
00125                 }
00126                 
00127                 sel = u->cu_selector->d_data;
00128                 pcnt_size = sizeof(struct tc_u32_pcnt) +
00129                                 (sel->nkeys * sizeof(uint64_t));
00130                 if (nla_len(tb[TCA_U32_PCNT]) < pcnt_size) {
00131                         err = -NLE_INVAL;
00132                         goto errout;
00133                 }
00134 
00135                 u->cu_pcnt = nl_data_alloc_attr(tb[TCA_U32_PCNT]);
00136                 if (!u->cu_pcnt)
00137                         goto errout_nomem;
00138                 u->cu_mask |= U32_ATTR_PCNT;
00139         }
00140 
00141         if (tb[TCA_U32_INDEV]) {
00142                 nla_strlcpy(u->cu_indev, tb[TCA_U32_INDEV], IFNAMSIZ);
00143                 u->cu_mask |= U32_ATTR_INDEV;
00144         }
00145 
00146         return 0;
00147 
00148 errout_nomem:
00149         err = -NLE_NOMEM;
00150 errout:
00151         return err;
00152 }
00153 
00154 static void u32_free_data(struct rtnl_cls *cls)
00155 {
00156         struct rtnl_u32 *u = rtnl_cls_data(cls);
00157 
00158         nl_data_free(u->cu_selector);
00159         nl_data_free(u->cu_act);
00160         nl_data_free(u->cu_police);
00161         nl_data_free(u->cu_pcnt);
00162 }
00163 
00164 static int u32_clone(struct rtnl_cls *_dst, struct rtnl_cls *_src)
00165 {
00166         struct rtnl_u32 *dst = rtnl_cls_data(_dst);
00167         struct rtnl_u32 *src = rtnl_cls_data(_src);
00168 
00169         if (src->cu_selector &&
00170             !(dst->cu_selector = nl_data_clone(src->cu_selector)))
00171                 return -NLE_NOMEM;
00172 
00173         if (src->cu_act && !(dst->cu_act = nl_data_clone(src->cu_act)))
00174                 return -NLE_NOMEM;
00175 
00176         if (src->cu_police && !(dst->cu_police = nl_data_clone(src->cu_police)))
00177                 return -NLE_NOMEM;
00178 
00179         if (src->cu_pcnt && !(dst->cu_pcnt = nl_data_clone(src->cu_pcnt)))
00180                 return -NLE_NOMEM;
00181 
00182         return 0;
00183 }
00184 
00185 static void u32_dump_line(struct rtnl_cls *cls, struct nl_dump_params *p)
00186 {
00187         struct rtnl_u32 *u = rtnl_cls_data(cls);
00188         char buf[32];
00189 
00190         if (u->cu_mask & U32_ATTR_DIVISOR)
00191                 nl_dump(p, " divisor %u", u->cu_divisor);
00192         else if (u->cu_mask & U32_ATTR_CLASSID)
00193                 nl_dump(p, " target %s",
00194                         rtnl_tc_handle2str(u->cu_classid, buf, sizeof(buf)));
00195 }
00196 
00197 static void print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel,
00198                            struct rtnl_cls *cls, struct rtnl_u32 *u)
00199 {
00200         int i;
00201         struct tc_u32_key *key;
00202 
00203         if (sel->hmask || sel->hoff) {
00204                 /* I guess this will never be used since the kernel only
00205                  * exports the selector if no divisor is set but hash offset
00206                  * and hash mask make only sense in hash filters with divisor
00207                  * set */
00208                 nl_dump(p, " hash at %u & 0x%x", sel->hoff, sel->hmask);
00209         }
00210 
00211         if (sel->flags & (TC_U32_OFFSET | TC_U32_VAROFFSET)) {
00212                 nl_dump(p, " offset at %u", sel->off);
00213 
00214                 if (sel->flags & TC_U32_VAROFFSET)
00215                         nl_dump(p, " variable (at %u & 0x%x) >> %u",
00216                                 sel->offoff, ntohs(sel->offmask), sel->offshift);
00217         }
00218 
00219         if (sel->flags) {
00220                 int flags = sel->flags;
00221                 nl_dump(p, " <");
00222 
00223 #define PRINT_FLAG(f) if (flags & TC_U32_##f) { \
00224         flags &= ~TC_U32_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
00225 
00226                 PRINT_FLAG(TERMINAL);
00227                 PRINT_FLAG(OFFSET);
00228                 PRINT_FLAG(VAROFFSET);
00229                 PRINT_FLAG(EAT);
00230 #undef PRINT_FLAG
00231 
00232                 nl_dump(p, ">");
00233         }
00234                 
00235         
00236         for (i = 0; i < sel->nkeys; i++) {
00237                 key = (struct tc_u32_key *) ((char *) sel + sizeof(*sel)) + i;
00238 
00239                 nl_dump(p, "\n");
00240                 nl_dump_line(p, "      match key at %s%u ",
00241                         key->offmask ? "nexthdr+" : "", key->off);
00242 
00243                 if (key->offmask)
00244                         nl_dump(p, "[0x%u] ", key->offmask);
00245 
00246                 nl_dump(p, "& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val));
00247 
00248                 if (p->dp_type == NL_DUMP_STATS &&
00249                     (u->cu_mask & U32_ATTR_PCNT)) {
00250                         struct tc_u32_pcnt *pcnt = u->cu_pcnt->d_data;
00251                         nl_dump(p, " successful %" PRIu64, pcnt->kcnts[i]);
00252                 }
00253         }
00254 }
00255 
00256 static void u32_dump_details(struct rtnl_cls *cls, struct nl_dump_params *p)
00257 {
00258         struct rtnl_u32 *u = rtnl_cls_data(cls);
00259         struct tc_u32_sel *s;
00260 
00261         if (!(u->cu_mask & U32_ATTR_SELECTOR)) {
00262                 nl_dump(p, "no-selector\n");
00263                 return;
00264         }
00265         
00266         s = u->cu_selector->d_data;
00267 
00268         nl_dump(p, "nkeys %u ", s->nkeys);
00269 
00270         if (u->cu_mask & U32_ATTR_HASH)
00271                 nl_dump(p, "ht key 0x%x hash 0x%u",
00272                         TC_U32_USERHTID(u->cu_hash), TC_U32_HASH(u->cu_hash));
00273 
00274         if (u->cu_mask & U32_ATTR_LINK)
00275                 nl_dump(p, "link %u ", u->cu_link);
00276 
00277         if (u->cu_mask & U32_ATTR_INDEV)
00278                 nl_dump(p, "indev %s ", u->cu_indev);
00279 
00280         print_selector(p, s, cls, u);
00281         nl_dump(p, "\n");
00282 
00283 #if 0   
00284 #define U32_ATTR_ACTION       0x040
00285 #define U32_ATTR_POLICE       0x080
00286 
00287         struct nl_data   act;
00288         struct nl_data   police;
00289 #endif
00290 }
00291 
00292 static void u32_dump_stats(struct rtnl_cls *cls, struct nl_dump_params *p)
00293 {
00294         struct rtnl_u32 *u = rtnl_cls_data(cls);
00295 
00296         if (u->cu_mask & U32_ATTR_PCNT) {
00297                 struct tc_u32_pcnt *pc = u->cu_pcnt->d_data;
00298                 nl_dump(p, "\n");
00299                 nl_dump_line(p, "    hit %8llu count %8llu\n",
00300                              pc->rhit, pc->rcnt);
00301         }
00302 }
00303 
00304 static int u32_get_opts(struct rtnl_cls *cls, struct nl_msg *msg)
00305 {
00306         struct rtnl_u32 *u = rtnl_cls_data(cls);
00307         
00308         if (u->cu_mask & U32_ATTR_DIVISOR)
00309                 NLA_PUT_U32(msg, TCA_U32_DIVISOR, u->cu_divisor);
00310 
00311         if (u->cu_mask & U32_ATTR_HASH)
00312                 NLA_PUT_U32(msg, TCA_U32_HASH, u->cu_hash);
00313 
00314         if (u->cu_mask & U32_ATTR_CLASSID)
00315                 NLA_PUT_U32(msg, TCA_U32_CLASSID, u->cu_classid);
00316 
00317         if (u->cu_mask & U32_ATTR_LINK)
00318                 NLA_PUT_U32(msg, TCA_U32_LINK, u->cu_link);
00319 
00320         if (u->cu_mask & U32_ATTR_SELECTOR)
00321                 NLA_PUT_DATA(msg, TCA_U32_SEL, u->cu_selector);
00322 
00323         if (u->cu_mask & U32_ATTR_ACTION)
00324                 NLA_PUT_DATA(msg, TCA_U32_ACT, u->cu_act);
00325 
00326         if (u->cu_mask & U32_ATTR_POLICE)
00327                 NLA_PUT_DATA(msg, TCA_U32_POLICE, u->cu_police);
00328 
00329         if (u->cu_mask & U32_ATTR_INDEV)
00330                 NLA_PUT_STRING(msg, TCA_U32_INDEV, u->cu_indev);
00331 
00332         return 0;
00333 
00334 nla_put_failure:
00335         return -NLE_NOMEM;
00336 }
00337 
00338 /**
00339  * @name Attribute Modifications
00340  * @{
00341  */
00342 
00343 void rtnl_u32_set_handle(struct rtnl_cls *cls, int htid, int hash,
00344                          int nodeid)
00345 {
00346         uint32_t handle = (htid << 20) | (hash << 12) | nodeid;
00347 
00348         tca_set_handle((struct rtnl_tca *) cls, handle );
00349 }
00350  
00351 int rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid)
00352 {
00353         struct rtnl_u32 *u = rtnl_cls_data(cls);
00354         
00355         u->cu_classid = classid;
00356         u->cu_mask |= U32_ATTR_CLASSID;
00357 
00358         return 0;
00359 }
00360 
00361 /** @} */
00362 
00363 /**
00364  * @name Selector Modifications
00365  * @{
00366  */
00367 
00368 int rtnl_u32_set_flags(struct rtnl_cls *cls, int flags)
00369 {
00370         struct tc_u32_sel *sel;
00371         struct rtnl_u32 *u = rtnl_cls_data(cls);
00372 
00373         sel = u32_selector_alloc(u);
00374         if (!sel)
00375                 return -NLE_NOMEM;
00376 
00377         sel->flags |= flags;
00378         u->cu_mask |= U32_ATTR_SELECTOR;
00379 
00380         return 0;
00381 }
00382 
00383 /**
00384  * Append new 32-bit key to the selector
00385  *
00386  * @arg cls     classifier to be modifier
00387  * @arg val     value to be matched (network byte-order)
00388  * @arg mask    mask to be applied before matching (network byte-order)
00389  * @arg off     offset, in bytes, to start matching
00390  * @arg offmask offset mask
00391  *
00392  * General selectors define the pattern, mask and offset the pattern will be
00393  * matched to the packet contents. Using the general selectors you can match
00394  * virtually any single bit in the IP (or upper layer) header.
00395  *
00396 */
00397 int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
00398                      int off, int offmask)
00399 {
00400         struct tc_u32_sel *sel;
00401         struct rtnl_u32 *u = rtnl_cls_data(cls);
00402         int err;
00403 
00404         sel = u32_selector_alloc(u);
00405         if (!sel)
00406                 return -NLE_NOMEM;
00407 
00408         err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
00409         if (err < 0)
00410                 return err;
00411 
00412         /* the selector might have been moved by realloc */
00413         sel = u32_selector(u);
00414 
00415         sel->keys[sel->nkeys].mask = mask;
00416         sel->keys[sel->nkeys].val = val & mask;
00417         sel->keys[sel->nkeys].off = off;
00418         sel->keys[sel->nkeys].offmask = offmask;
00419         sel->nkeys++;
00420         u->cu_mask |= U32_ATTR_SELECTOR;
00421 
00422         return 0;
00423 }
00424 
00425 int rtnl_u32_add_key_uint8(struct rtnl_cls *cls, uint8_t val, uint8_t mask,
00426                            int off, int offmask)
00427 {
00428         int shift = 24 - 8 * (off & 3);
00429 
00430         return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
00431                                 htonl((uint32_t)mask << shift),
00432                                 off & ~3, offmask);
00433 }
00434 
00435 /**
00436  * Append new selector key to match a 16-bit number
00437  *
00438  * @arg cls     classifier to be modified
00439  * @arg val     value to be matched (host byte-order)
00440  * @arg mask    mask to be applied before matching (host byte-order)
00441  * @arg off     offset, in bytes, to start matching
00442  * @arg offmask offset mask
00443 */
00444 int rtnl_u32_add_key_uint16(struct rtnl_cls *cls, uint16_t val, uint16_t mask,
00445                             int off, int offmask)
00446 {
00447         int shift = ((off & 3) == 0 ? 16 : 0);
00448         if (off % 2)
00449                 return -NLE_INVAL;
00450 
00451         return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
00452                                 htonl((uint32_t)mask << shift),
00453                                 off & ~3, offmask);
00454 }
00455 
00456 /**
00457  * Append new selector key to match a 32-bit number
00458  *
00459  * @arg cls     classifier to be modified
00460  * @arg val     value to be matched (host byte-order)
00461  * @arg mask    mask to be applied before matching (host byte-order)
00462  * @arg off     offset, in bytes, to start matching
00463  * @arg offmask offset mask
00464 */
00465 int rtnl_u32_add_key_uint32(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
00466                             int off, int offmask)
00467 {
00468         return rtnl_u32_add_key(cls, htonl(val), htonl(mask),
00469                                 off & ~3, offmask);
00470 }
00471 
00472 int rtnl_u32_add_key_in_addr(struct rtnl_cls *cls, struct in_addr *addr,
00473                              uint8_t bitmask, int off, int offmask)
00474 {
00475         uint32_t mask = 0xFFFFFFFF << (32 - bitmask);
00476         return rtnl_u32_add_key(cls, addr->s_addr, htonl(mask), off, offmask);
00477 }
00478 
00479 int rtnl_u32_add_key_in6_addr(struct rtnl_cls *cls, struct in6_addr *addr,
00480                               uint8_t bitmask, int off, int offmask)
00481 {
00482         int i, err;
00483 
00484         for (i = 1; i <= 4; i++) {
00485                 if (32 * i - bitmask <= 0) {
00486                         if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
00487                                                 0xFFFFFFFF, off+4*(i-1), offmask)) < 0)
00488                                 return err;
00489                 }
00490                 else if (32 * i - bitmask < 32) {
00491                         uint32_t mask = 0xFFFFFFFF << (32 * i - bitmask);
00492                         if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
00493                                                 htonl(mask), off+4*(i-1), offmask)) < 0)
00494                                 return err;
00495                 }
00496                 /* otherwise, if (32*i - bitmask >= 32) no key is generated */
00497         }
00498 
00499         return 0;
00500 }
00501 
00502 /** @} */
00503 
00504 static struct rtnl_cls_ops u32_ops = {
00505         .co_kind                = "u32",
00506         .co_size                = sizeof(struct rtnl_u32),
00507         .co_msg_parser          = u32_msg_parser,
00508         .co_free_data           = u32_free_data,
00509         .co_clone               = u32_clone,
00510         .co_get_opts            = u32_get_opts,
00511         .co_dump = {
00512             [NL_DUMP_LINE]      = u32_dump_line,
00513             [NL_DUMP_DETAILS]   = u32_dump_details,
00514             [NL_DUMP_STATS]     = u32_dump_stats,
00515         },
00516 };
00517 
00518 static void __init u32_init(void)
00519 {
00520         rtnl_cls_register(&u32_ops);
00521 }
00522 
00523 static void __exit u32_exit(void)
00524 {
00525         rtnl_cls_unregister(&u32_ops);
00526 }
00527 
00528 /** @} */