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