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 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
00246
00247
00248
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
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
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
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
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
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
00514
00515
00516
00517
00518
00519
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
00535
00536
00537
00538
00539
00540
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
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