00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
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
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
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
00205
00206
00207
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
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
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
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
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
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
00437
00438
00439
00440
00441
00442
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
00458
00459
00460
00461
00462
00463
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
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