libnl
3.2.3
|
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-2011 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 00016 * @defgroup cls_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-api.h> 00027 #include <netlink/route/classifier.h> 00028 #include <netlink/route/cls/u32.h> 00029 00030 /** @cond SKIP */ 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 /** @endcond */ 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 /* I guess this will never be used since the kernel only 00207 * exports the selector if no divisor is set but hash offset 00208 * and hash mask make only sense in hash filters with divisor 00209 * set */ 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 * @name Attribute Modifications 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 * @name Selector Modifications 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 * Append new 32-bit key to the selector 00404 * 00405 * @arg cls classifier to be modifier 00406 * @arg val value to be matched (network byte-order) 00407 * @arg mask mask to be applied before matching (network byte-order) 00408 * @arg off offset, in bytes, to start matching 00409 * @arg offmask offset mask 00410 * 00411 * General selectors define the pattern, mask and offset the pattern will be 00412 * matched to the packet contents. Using the general selectors you can match 00413 * virtually any single bit in the IP (or upper layer) header. 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 /* the selector might have been moved by realloc */ 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 * Append new selector key to match a 16-bit number 00459 * 00460 * @arg cls classifier to be modified 00461 * @arg val value to be matched (host byte-order) 00462 * @arg mask mask to be applied before matching (host byte-order) 00463 * @arg off offset, in bytes, to start matching 00464 * @arg offmask offset mask 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 * Append new selector key to match a 32-bit number 00480 * 00481 * @arg cls classifier to be modified 00482 * @arg val value to be matched (host byte-order) 00483 * @arg mask mask to be applied before matching (host byte-order) 00484 * @arg off offset, in bytes, to start matching 00485 * @arg offmask offset mask 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 /* otherwise, if (32*i - bitmask >= 32) no key is generated */ 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 /** @} */