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_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
00214
00215
00216
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
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
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
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
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
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
00482
00483
00484
00485
00486
00487
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
00503
00504
00505
00506
00507
00508
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
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