/build/buildd/libnl-1.0~pre6/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
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_dump_brief(struct rtnl_cls *cls, struct nl_dump_params *p,
00188                           int line)
00189 {
00190         struct rtnl_u32 *u = u32_cls(cls);
00191         char buf[32];
00192 
00193         if (!u)
00194                 goto ignore;
00195 
00196         if (u->cu_mask & U32_ATTR_DIVISOR)
00197                 dp_dump(p, " divisor %u", u->cu_divisor);
00198         else if (u->cu_mask & U32_ATTR_CLASSID)
00199                 dp_dump(p, " target %s",
00200                         rtnl_tc_handle2str(u->cu_classid, buf, sizeof(buf)));
00201 
00202 ignore:
00203         return line;
00204 }
00205 
00206 static int print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel,
00207                           struct rtnl_cls *cls, struct rtnl_u32 *u, int line)
00208 {
00209         int i;
00210         struct tc_u32_key *key;
00211 
00212         if (sel->hmask || sel->hoff) {
00213                 /* I guess this will never be used since the kernel only
00214                  * exports the selector if no divisor is set but hash offset
00215                  * and hash mask make only sense in hash filters with divisor
00216                  * set */
00217                 dp_dump(p, " hash at %u & 0x%x", sel->hoff, sel->hmask);
00218         }
00219 
00220         if (sel->flags & (TC_U32_OFFSET | TC_U32_VAROFFSET)) {
00221                 dp_dump(p, " offset at %u", sel->off);
00222 
00223                 if (sel->flags & TC_U32_VAROFFSET)
00224                         dp_dump(p, " variable (at %u & 0x%x) >> %u",
00225                                 sel->offoff, ntohs(sel->offmask), sel->offshift);
00226         }
00227 
00228         if (sel->flags) {
00229                 int flags = sel->flags;
00230                 dp_dump(p, " <");
00231 
00232 #define PRINT_FLAG(f) if (flags & TC_U32_##f) { \
00233         flags &= ~TC_U32_##f; dp_dump(p, #f "%s", flags ? "," : ""); }
00234 
00235                 PRINT_FLAG(TERMINAL);
00236                 PRINT_FLAG(OFFSET);
00237                 PRINT_FLAG(VAROFFSET);
00238                 PRINT_FLAG(EAT);
00239 #undef PRINT_FLAG
00240 
00241                 dp_dump(p, ">");
00242         }
00243                 
00244         
00245         for (i = 0; i < sel->nkeys; i++) {
00246                 key = (struct tc_u32_key *) ((char *) sel + sizeof(*sel));
00247 
00248                 dp_dump(p, "\n");
00249                 dp_dump_line(p, line++, "      match key at %s%u ",
00250                 key->offmask ? "nexthdr+" : "", key->off);
00251 
00252                 if (key->offmask)
00253                         dp_dump(p, "[0x%u] ", key->offmask);
00254 
00255                 dp_dump(p, "& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val));
00256 
00257                 if (p->dp_type == NL_DUMP_STATS &&
00258                     (u->cu_mask & U32_ATTR_PCNT)) {
00259                         struct tc_u32_pcnt *pcnt = u->cu_pcnt->d_data;
00260                         dp_dump(p, " successful %" PRIu64, pcnt->kcnts[i]);
00261                 }
00262         }
00263 
00264         return line;
00265 }
00266 
00267 
00268 static int u32_dump_full(struct rtnl_cls *cls, struct nl_dump_params *p,
00269                          int line)
00270 {
00271         struct rtnl_u32 *u = u32_cls(cls);
00272         struct tc_u32_sel *s;
00273 
00274         if (!u)
00275                 goto ignore;
00276 
00277         if (!(u->cu_mask & U32_ATTR_SELECTOR)) {
00278                 dp_dump(p, "no-selector\n");
00279                 return line;
00280         }
00281         
00282         s = u->cu_selector->d_data;
00283 
00284         dp_dump(p, "nkeys %u ", s->nkeys);
00285 
00286         if (u->cu_mask & U32_ATTR_HASH)
00287                 dp_dump(p, "ht key 0x%x hash 0x%u",
00288                         TC_U32_USERHTID(u->cu_hash), TC_U32_HASH(u->cu_hash));
00289 
00290         if (u->cu_mask & U32_ATTR_LINK)
00291                 dp_dump(p, "link %u ", u->cu_link);
00292 
00293         if (u->cu_mask & U32_ATTR_INDEV)
00294                 dp_dump(p, "indev %s ", u->cu_indev);
00295 
00296         line = print_selector(p, s, cls, u, line);
00297         dp_dump(p, "\n");
00298 
00299 ignore:
00300         return line;
00301 
00302 #if 0   
00303 #define U32_ATTR_ACTION       0x040
00304 #define U32_ATTR_POLICE       0x080
00305 
00306         struct nl_data   act;
00307         struct nl_data   police;
00308 #endif
00309 }
00310 
00311 static int u32_dump_stats(struct rtnl_cls *cls, struct nl_dump_params *p,
00312                           int line)
00313 {
00314         struct rtnl_u32 *u = u32_cls(cls);
00315 
00316         if (!u)
00317                 goto ignore;
00318 
00319         if (u->cu_mask & U32_ATTR_PCNT) {
00320                 struct tc_u32_pcnt *pc = u->cu_pcnt->d_data;
00321                 dp_dump(p, "\n");
00322                 dp_dump_line(p, line++, "%s         successful       hits\n");
00323                 dp_dump_line(p, line++, "%s           %8llu   %8llu\n",
00324                              pc->rhit, pc->rcnt);
00325         }
00326 
00327 ignore:
00328         return line;
00329 }
00330 
00331 static struct nl_msg *u32_get_opts(struct rtnl_cls *cls)
00332 {
00333         struct rtnl_u32 *u;
00334         struct nl_msg *msg;
00335         
00336         u = u32_cls(cls);
00337         if (!u)
00338                 return NULL;
00339 
00340         msg = nlmsg_build_no_hdr();
00341         if (!msg)
00342                 return NULL;
00343 
00344         if (u->cu_mask & U32_ATTR_DIVISOR)
00345                 nla_put_u32(msg, TCA_U32_DIVISOR, u->cu_divisor);
00346 
00347         if (u->cu_mask & U32_ATTR_HASH)
00348                 nla_put_u32(msg, TCA_U32_HASH, u->cu_hash);
00349 
00350         if (u->cu_mask & U32_ATTR_CLASSID)
00351                 nla_put_u32(msg, TCA_U32_CLASSID, u->cu_classid);
00352 
00353         if (u->cu_mask & U32_ATTR_LINK)
00354                 nla_put_u32(msg, TCA_U32_LINK, u->cu_link);
00355 
00356         if (u->cu_mask & U32_ATTR_SELECTOR)
00357                 nla_put_data(msg, TCA_U32_SEL, u->cu_selector);
00358 
00359         if (u->cu_mask & U32_ATTR_ACTION)
00360                 nla_put_data(msg, TCA_U32_ACT, u->cu_act);
00361 
00362         if (u->cu_mask & U32_ATTR_POLICE)
00363                 nla_put_data(msg, TCA_U32_POLICE, u->cu_police);
00364 
00365         if (u->cu_mask & U32_ATTR_INDEV)
00366                 nla_put_string(msg, TCA_U32_INDEV, u->cu_indev);
00367 
00368         return msg;
00369 }
00370 
00371 /**
00372  * @name Attribute Modifications
00373  * @{
00374  */
00375 
00376 void rtnl_u32_set_handle(struct rtnl_cls *cls, int htid, int hash,
00377                          int nodeid)
00378 {
00379         uint32_t handle = (htid << 20) | (hash << 12) | nodeid;
00380 
00381         tca_set_handle((struct rtnl_tca *) cls, handle );
00382 }
00383  
00384 int rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid)
00385 {
00386         struct rtnl_u32 *u;
00387         
00388         u = u32_alloc(cls);
00389         if (!u)
00390                 return nl_errno(ENOMEM);
00391 
00392         u->cu_classid = classid;
00393         u->cu_mask |= U32_ATTR_CLASSID;
00394 
00395         return 0;
00396 }
00397 
00398 /** @} */
00399 
00400 /**
00401  * @name Selector Modifications
00402  * @{
00403  */
00404 
00405 int rtnl_u32_set_flags(struct rtnl_cls *cls, int flags)
00406 {
00407         struct tc_u32_sel *sel;
00408         struct rtnl_u32 *u;
00409 
00410         u = u32_alloc(cls);
00411         if (!u)
00412                 return nl_errno(ENOMEM);
00413 
00414         sel = u32_selector_alloc(u);
00415         if (!sel)
00416                 return nl_errno(ENOMEM);
00417 
00418         sel->flags |= flags;
00419         u->cu_mask |= U32_ATTR_SELECTOR;
00420 
00421         return 0;
00422 }
00423 
00424 /**
00425  * Append new 32-bit key to the selector
00426  *
00427  * @arg cls     classifier to be modifier
00428  * @arg val     value to be matched (network byte-order)
00429  * @arg mask    mask to be applied before matching (network byte-order)
00430  * @arg off     offset, in bytes, to start matching
00431  * @arg offmask offset mask
00432  *
00433  * General selectors define the pattern, mask and offset the pattern will be
00434  * matched to the packet contents. Using the general selectors you can match
00435  * virtually any single bit in the IP (or upper layer) header.
00436  *
00437 */
00438 int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
00439                      int off, int offmask)
00440 {
00441         struct tc_u32_sel *sel;
00442         struct rtnl_u32 *u;
00443         int err;
00444 
00445         u = u32_alloc(cls);
00446         if (!u)
00447                 return nl_errno(ENOMEM);
00448 
00449         sel = u32_selector_alloc(u);
00450         if (!sel)
00451                 return nl_errno(ENOMEM);
00452 
00453         err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
00454         if (err < 0)
00455                 return err;
00456 
00457         /* the selector might have been moved by realloc */
00458         sel = u32_selector(u);
00459 
00460         sel->keys[sel->nkeys].mask = mask;
00461         sel->keys[sel->nkeys].val = val & mask;
00462         sel->keys[sel->nkeys].off = off;
00463         sel->keys[sel->nkeys].offmask = offmask;
00464         sel->nkeys++;
00465         u->cu_mask |= U32_ATTR_SELECTOR;
00466 
00467         return 0;
00468 }
00469 
00470 int rtnl_u32_add_key_uint8(struct rtnl_cls *cls, uint8_t val, uint8_t mask,
00471                            int off, int offmask)
00472 {
00473         int shift = 24 - 8 * (off & 3);
00474 
00475         return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
00476                                 htonl((uint32_t)mask << shift),
00477                                 off & ~3, offmask);
00478 }
00479 
00480 /**
00481  * Append new selector key to match a 16-bit number
00482  *
00483  * @arg cls     classifier to be modified
00484  * @arg val     value to be matched (host byte-order)
00485  * @arg mask    mask to be applied before matching (host byte-order)
00486  * @arg off     offset, in bytes, to start matching
00487  * @arg offmask offset mask
00488 */
00489 int rtnl_u32_add_key_uint16(struct rtnl_cls *cls, uint16_t val, uint16_t mask,
00490                             int off, int offmask)
00491 {
00492         int shift = ((off & 3) == 0 ? 16 : 0);
00493         if (off % 2)
00494                 return nl_error(EINVAL, "Invalid offset alignment");
00495 
00496         return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
00497                                 htonl((uint32_t)mask << shift),
00498                                 off & ~3, offmask);
00499 }
00500 
00501 /**
00502  * Append new selector key to match a 32-bit number
00503  *
00504  * @arg cls     classifier to be modified
00505  * @arg val     value to be matched (host byte-order)
00506  * @arg mask    mask to be applied before matching (host byte-order)
00507  * @arg off     offset, in bytes, to start matching
00508  * @arg offmask offset mask
00509 */
00510 int rtnl_u32_add_key_uint32(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
00511                             int off, int offmask)
00512 {
00513         return rtnl_u32_add_key(cls, htonl(val), htonl(mask),
00514                                 off & ~3, offmask);
00515 }
00516 
00517 int rtnl_u32_add_key_in_addr(struct rtnl_cls *cls, struct in_addr *addr,
00518                              uint8_t bitmask, int off, int offmask)
00519 {
00520         uint32_t mask = 0xFFFFFFFF << (32 - bitmask);
00521         return rtnl_u32_add_key(cls, addr->s_addr, htonl(mask), off, offmask);
00522 }
00523 
00524 int rtnl_u32_add_key_in6_addr(struct rtnl_cls *cls, struct in6_addr *addr,
00525                               uint8_t bitmask, int off, int offmask)
00526 {
00527         int i;
00528 
00529         for (i = 1; i <= 4; i++) {
00530                 if (32 * i - bitmask <= 0)
00531                         return rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
00532                                                 0xFFFFFFFF, off, offmask );
00533                 else if (32 * i - bitmask < 32) {
00534                         uint32_t mask = 0xFFFFFFFF << (32 * i - bitmask);
00535                         return rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
00536                                                 htonl(mask), off, offmask );
00537                 }
00538                 /* otherwise, if (32*i - bitmask >= 32) no key is generated */
00539         }
00540 
00541         return 0;
00542 }
00543 
00544 /** @} */
00545 
00546 static struct rtnl_cls_ops u32_ops = {
00547         .co_kind                = "u32",
00548         .co_msg_parser          = u32_msg_parser,
00549         .co_free_data           = u32_free_data,
00550         .co_get_opts            = u32_get_opts,
00551         .co_dump[NL_DUMP_BRIEF] = u32_dump_brief,
00552         .co_dump[NL_DUMP_FULL]  = u32_dump_full,
00553         .co_dump[NL_DUMP_STATS] = u32_dump_stats,
00554 };
00555 
00556 static void __init u32_init(void)
00557 {
00558         rtnl_cls_register(&u32_ops);
00559 }
00560 
00561 static void __exit u32_exit(void)
00562 {
00563         rtnl_cls_unregister(&u32_ops);
00564 }
00565 
00566 /** @} */

Generated on Fri Apr 27 14:14:07 2007 for libnl by  doxygen 1.5.1