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