libnl 1.1
|
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_api 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_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 /* I guess this will never be used since the kernel only 00246 * exports the selector if no divisor is set but hash offset 00247 * and hash mask make only sense in hash filters with divisor 00248 * set */ 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 * @name Attribute Modifications 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 * @name Selector Modifications 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 * Append new 32-bit key to the selector 00458 * 00459 * @arg cls classifier to be modifier 00460 * @arg val value to be matched (network byte-order) 00461 * @arg mask mask to be applied before matching (network byte-order) 00462 * @arg off offset, in bytes, to start matching 00463 * @arg offmask offset mask 00464 * 00465 * General selectors define the pattern, mask and offset the pattern will be 00466 * matched to the packet contents. Using the general selectors you can match 00467 * virtually any single bit in the IP (or upper layer) header. 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 /* the selector might have been moved by realloc */ 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 * Append new selector key to match a 16-bit number 00514 * 00515 * @arg cls classifier to be modified 00516 * @arg val value to be matched (host byte-order) 00517 * @arg mask mask to be applied before matching (host byte-order) 00518 * @arg off offset, in bytes, to start matching 00519 * @arg offmask offset mask 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 * Append new selector key to match a 32-bit number 00535 * 00536 * @arg cls classifier to be modified 00537 * @arg val value to be matched (host byte-order) 00538 * @arg mask mask to be applied before matching (host byte-order) 00539 * @arg off offset, in bytes, to start matching 00540 * @arg offmask offset mask 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 /* otherwise, if (32*i - bitmask >= 32) no key is generated */ 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 /** @} */