u32.c revision 44d362409d5469aed47d19e7908d19bd194493a4
1/* 2 * lib/route/cls/u32.c u32 classifier 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation version 2.1 7 * of the License. 8 * 9 * Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch> 10 * Copyright (c) 2005-2006 Petr Gotthard <petr.gotthard@siemens.com> 11 * Copyright (c) 2005-2006 Siemens AG Oesterreich 12 */ 13 14/** 15 * @ingroup cls_api 16 * @defgroup u32 Universal 32-bit Classifier 17 * 18 * @{ 19 */ 20 21#include <netlink-local.h> 22#include <netlink-tc.h> 23#include <netlink/netlink.h> 24#include <netlink/attr.h> 25#include <netlink/utils.h> 26#include <netlink/route/tc.h> 27#include <netlink/route/classifier.h> 28#include <netlink/route/classifier-modules.h> 29#include <netlink/route/cls/u32.h> 30 31/** @cond SKIP */ 32#define U32_ATTR_DIVISOR 0x001 33#define U32_ATTR_HASH 0x002 34#define U32_ATTR_CLASSID 0x004 35#define U32_ATTR_LINK 0x008 36#define U32_ATTR_PCNT 0x010 37#define U32_ATTR_SELECTOR 0x020 38#define U32_ATTR_ACTION 0x040 39#define U32_ATTR_POLICE 0x080 40#define U32_ATTR_INDEV 0x100 41/** @endcond */ 42 43static inline struct rtnl_u32 *u32_cls(struct rtnl_cls *cls) 44{ 45 return (struct rtnl_u32 *) cls->c_subdata; 46} 47 48static inline struct rtnl_u32 *u32_alloc(struct rtnl_cls *cls) 49{ 50 if (!cls->c_subdata) 51 cls->c_subdata = calloc(1, sizeof(struct rtnl_u32)); 52 53 return u32_cls(cls); 54} 55 56static inline struct tc_u32_sel *u32_selector(struct rtnl_u32 *u) 57{ 58 return (struct tc_u32_sel *) u->cu_selector->d_data; 59} 60 61static inline struct tc_u32_sel *u32_selector_alloc(struct rtnl_u32 *u) 62{ 63 if (!u->cu_selector) 64 u->cu_selector = nl_data_alloc(NULL, sizeof(struct tc_u32_sel)); 65 66 return u32_selector(u); 67} 68 69static struct nla_policy u32_policy[TCA_U32_MAX+1] = { 70 [TCA_U32_DIVISOR] = { .type = NLA_U32 }, 71 [TCA_U32_HASH] = { .type = NLA_U32 }, 72 [TCA_U32_CLASSID] = { .type = NLA_U32 }, 73 [TCA_U32_LINK] = { .type = NLA_U32 }, 74 [TCA_U32_INDEV] = { .type = NLA_STRING, 75 .maxlen = IFNAMSIZ }, 76 [TCA_U32_SEL] = { .minlen = sizeof(struct tc_u32_sel) }, 77 [TCA_U32_PCNT] = { .minlen = sizeof(struct tc_u32_pcnt) }, 78}; 79 80static int u32_msg_parser(struct rtnl_cls *cls) 81{ 82 int err; 83 struct nlattr *tb[TCA_U32_MAX + 1]; 84 struct rtnl_u32 *u; 85 86 err = tca_parse(tb, TCA_U32_MAX, (struct rtnl_tca *) cls, u32_policy); 87 if (err < 0) 88 return err; 89 90 u = u32_alloc(cls); 91 if (!u) 92 goto errout_nomem; 93 94 if (tb[TCA_U32_DIVISOR]) { 95 u->cu_divisor = nla_get_u32(tb[TCA_U32_DIVISOR]); 96 u->cu_mask |= U32_ATTR_DIVISOR; 97 } 98 99 if (tb[TCA_U32_SEL]) { 100 u->cu_selector = nla_get_data(tb[TCA_U32_SEL]); 101 if (!u->cu_selector) 102 goto errout_nomem; 103 u->cu_mask |= U32_ATTR_SELECTOR; 104 } 105 106 if (tb[TCA_U32_HASH]) { 107 u->cu_hash = nla_get_u32(tb[TCA_U32_HASH]); 108 u->cu_mask |= U32_ATTR_HASH; 109 } 110 111 if (tb[TCA_U32_CLASSID]) { 112 u->cu_classid = nla_get_u32(tb[TCA_U32_CLASSID]); 113 u->cu_mask |= U32_ATTR_CLASSID; 114 } 115 116 if (tb[TCA_U32_LINK]) { 117 u->cu_link = nla_get_u32(tb[TCA_U32_LINK]); 118 u->cu_mask |= U32_ATTR_LINK; 119 } 120 121 if (tb[TCA_U32_ACT]) { 122 u->cu_act = nla_get_data(tb[TCA_U32_ACT]); 123 if (!u->cu_act) 124 goto errout_nomem; 125 u->cu_mask |= U32_ATTR_ACTION; 126 } 127 128 if (tb[TCA_U32_POLICE]) { 129 u->cu_police = nla_get_data(tb[TCA_U32_POLICE]); 130 if (!u->cu_police) 131 goto errout_nomem; 132 u->cu_mask |= U32_ATTR_POLICE; 133 } 134 135 if (tb[TCA_U32_PCNT]) { 136 struct tc_u32_sel *sel; 137 int pcnt_size; 138 139 if (!tb[TCA_U32_SEL]) { 140 err = nl_error(EINVAL, "Missing TCA_U32_SEL required " 141 "for TCA_U32_PCNT"); 142 goto errout; 143 } 144 145 sel = u->cu_selector->d_data; 146 pcnt_size = sizeof(struct tc_u32_pcnt) + 147 (sel->nkeys * sizeof(uint64_t)); 148 if (nla_len(tb[TCA_U32_PCNT]) < pcnt_size) { 149 err = nl_error(EINVAL, "Invalid size for TCA_U32_PCNT"); 150 goto errout; 151 } 152 153 u->cu_pcnt = nla_get_data(tb[TCA_U32_PCNT]); 154 if (!u->cu_pcnt) 155 goto errout_nomem; 156 u->cu_mask |= U32_ATTR_PCNT; 157 } 158 159 if (tb[TCA_U32_INDEV]) { 160 nla_strlcpy(u->cu_indev, tb[TCA_U32_INDEV], IFNAMSIZ); 161 u->cu_mask |= U32_ATTR_INDEV; 162 } 163 164 return 0; 165 166errout_nomem: 167 err = nl_errno(ENOMEM); 168errout: 169 return err; 170} 171 172static void u32_free_data(struct rtnl_cls *cls) 173{ 174 struct rtnl_u32 *u = u32_cls(cls); 175 176 if (!u) 177 return; 178 179 nl_data_free(u->cu_selector); 180 nl_data_free(u->cu_act); 181 nl_data_free(u->cu_police); 182 nl_data_free(u->cu_pcnt); 183 184 free(cls->c_subdata); 185} 186 187static int u32_clone(struct rtnl_cls *_dst, struct rtnl_cls *_src) 188{ 189 struct rtnl_u32 *dst, *src = u32_cls(_src); 190 191 if (!src) 192 return 0; 193 194 dst = u32_alloc(_dst); 195 if (!dst) 196 return nl_errno(ENOMEM); 197 198 if (src->cu_selector) 199 if (!(dst->cu_selector = nl_data_clone(src->cu_selector))) 200 goto errout; 201 202 if (src->cu_act) 203 if (!(dst->cu_act = nl_data_clone(src->cu_act))) 204 goto errout; 205 206 if (src->cu_police) 207 if (!(dst->cu_police = nl_data_clone(src->cu_police))) 208 goto errout; 209 210 if (src->cu_pcnt) 211 if (!(dst->cu_pcnt = nl_data_clone(src->cu_pcnt))) 212 goto errout; 213 214 return 0; 215errout: 216 return nl_get_errno(); 217} 218 219static int u32_dump_brief(struct rtnl_cls *cls, struct nl_dump_params *p, 220 int line) 221{ 222 struct rtnl_u32 *u = u32_cls(cls); 223 char buf[32]; 224 225 if (!u) 226 goto ignore; 227 228 if (u->cu_mask & U32_ATTR_DIVISOR) 229 dp_dump(p, " divisor %u", u->cu_divisor); 230 else if (u->cu_mask & U32_ATTR_CLASSID) 231 dp_dump(p, " target %s", 232 rtnl_tc_handle2str(u->cu_classid, buf, sizeof(buf))); 233 234ignore: 235 return line; 236} 237 238static int print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel, 239 struct rtnl_cls *cls, struct rtnl_u32 *u, int line) 240{ 241 int i; 242 struct tc_u32_key *key; 243 244 if (sel->hmask || sel->hoff) { 245 /* I guess this will never be used since the kernel only 246 * exports the selector if no divisor is set but hash offset 247 * and hash mask make only sense in hash filters with divisor 248 * set */ 249 dp_dump(p, " hash at %u & 0x%x", sel->hoff, sel->hmask); 250 } 251 252 if (sel->flags & (TC_U32_OFFSET | TC_U32_VAROFFSET)) { 253 dp_dump(p, " offset at %u", sel->off); 254 255 if (sel->flags & TC_U32_VAROFFSET) 256 dp_dump(p, " variable (at %u & 0x%x) >> %u", 257 sel->offoff, ntohs(sel->offmask), sel->offshift); 258 } 259 260 if (sel->flags) { 261 int flags = sel->flags; 262 dp_dump(p, " <"); 263 264#define PRINT_FLAG(f) if (flags & TC_U32_##f) { \ 265 flags &= ~TC_U32_##f; dp_dump(p, #f "%s", flags ? "," : ""); } 266 267 PRINT_FLAG(TERMINAL); 268 PRINT_FLAG(OFFSET); 269 PRINT_FLAG(VAROFFSET); 270 PRINT_FLAG(EAT); 271#undef PRINT_FLAG 272 273 dp_dump(p, ">"); 274 } 275 276 277 for (i = 0; i < sel->nkeys; i++) { 278 key = (struct tc_u32_key *) ((char *) sel + sizeof(*sel)) + i; 279 280 dp_dump(p, "\n"); 281 dp_dump_line(p, line++, " match key at %s%u ", 282 key->offmask ? "nexthdr+" : "", key->off); 283 284 if (key->offmask) 285 dp_dump(p, "[0x%u] ", key->offmask); 286 287 dp_dump(p, "& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val)); 288 289 if (p->dp_type == NL_DUMP_STATS && 290 (u->cu_mask & U32_ATTR_PCNT)) { 291 struct tc_u32_pcnt *pcnt = u->cu_pcnt->d_data; 292 dp_dump(p, " successful %" PRIu64, pcnt->kcnts[i]); 293 } 294 } 295 296 return line; 297} 298 299 300static int u32_dump_full(struct rtnl_cls *cls, struct nl_dump_params *p, 301 int line) 302{ 303 struct rtnl_u32 *u = u32_cls(cls); 304 struct tc_u32_sel *s; 305 306 if (!u) 307 goto ignore; 308 309 if (!(u->cu_mask & U32_ATTR_SELECTOR)) { 310 dp_dump(p, "no-selector\n"); 311 return line; 312 } 313 314 s = u->cu_selector->d_data; 315 316 dp_dump(p, "nkeys %u ", s->nkeys); 317 318 if (u->cu_mask & U32_ATTR_HASH) 319 dp_dump(p, "ht key 0x%x hash 0x%u", 320 TC_U32_USERHTID(u->cu_hash), TC_U32_HASH(u->cu_hash)); 321 322 if (u->cu_mask & U32_ATTR_LINK) 323 dp_dump(p, "link %u ", u->cu_link); 324 325 if (u->cu_mask & U32_ATTR_INDEV) 326 dp_dump(p, "indev %s ", u->cu_indev); 327 328 line = print_selector(p, s, cls, u, line); 329 dp_dump(p, "\n"); 330 331ignore: 332 return line; 333 334#if 0 335#define U32_ATTR_ACTION 0x040 336#define U32_ATTR_POLICE 0x080 337 338 struct nl_data act; 339 struct nl_data police; 340#endif 341} 342 343static int u32_dump_stats(struct rtnl_cls *cls, struct nl_dump_params *p, 344 int line) 345{ 346 struct rtnl_u32 *u = u32_cls(cls); 347 348 if (!u) 349 goto ignore; 350 351 if (u->cu_mask & U32_ATTR_PCNT) { 352 struct tc_u32_pcnt *pc = u->cu_pcnt->d_data; 353 dp_dump(p, "\n"); 354 dp_dump_line(p, line++, "%s successful hits\n"); 355 dp_dump_line(p, line++, "%s %8llu %8llu\n", 356 pc->rhit, pc->rcnt); 357 } 358 359ignore: 360 return line; 361} 362 363static struct nl_msg *u32_get_opts(struct rtnl_cls *cls) 364{ 365 struct rtnl_u32 *u; 366 struct nl_msg *msg; 367 368 u = u32_cls(cls); 369 if (!u) 370 return NULL; 371 372 msg = nlmsg_alloc(); 373 if (!msg) 374 return NULL; 375 376 if (u->cu_mask & U32_ATTR_DIVISOR) 377 nla_put_u32(msg, TCA_U32_DIVISOR, u->cu_divisor); 378 379 if (u->cu_mask & U32_ATTR_HASH) 380 nla_put_u32(msg, TCA_U32_HASH, u->cu_hash); 381 382 if (u->cu_mask & U32_ATTR_CLASSID) 383 nla_put_u32(msg, TCA_U32_CLASSID, u->cu_classid); 384 385 if (u->cu_mask & U32_ATTR_LINK) 386 nla_put_u32(msg, TCA_U32_LINK, u->cu_link); 387 388 if (u->cu_mask & U32_ATTR_SELECTOR) 389 nla_put_data(msg, TCA_U32_SEL, u->cu_selector); 390 391 if (u->cu_mask & U32_ATTR_ACTION) 392 nla_put_data(msg, TCA_U32_ACT, u->cu_act); 393 394 if (u->cu_mask & U32_ATTR_POLICE) 395 nla_put_data(msg, TCA_U32_POLICE, u->cu_police); 396 397 if (u->cu_mask & U32_ATTR_INDEV) 398 nla_put_string(msg, TCA_U32_INDEV, u->cu_indev); 399 400 return msg; 401} 402 403/** 404 * @name Attribute Modifications 405 * @{ 406 */ 407 408void rtnl_u32_set_handle(struct rtnl_cls *cls, int htid, int hash, 409 int nodeid) 410{ 411 uint32_t handle = (htid << 20) | (hash << 12) | nodeid; 412 413 tca_set_handle((struct rtnl_tca *) cls, handle ); 414} 415 416int rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid) 417{ 418 struct rtnl_u32 *u; 419 420 u = u32_alloc(cls); 421 if (!u) 422 return nl_errno(ENOMEM); 423 424 u->cu_classid = classid; 425 u->cu_mask |= U32_ATTR_CLASSID; 426 427 return 0; 428} 429 430/** @} */ 431 432/** 433 * @name Selector Modifications 434 * @{ 435 */ 436 437int rtnl_u32_set_flags(struct rtnl_cls *cls, int flags) 438{ 439 struct tc_u32_sel *sel; 440 struct rtnl_u32 *u; 441 442 u = u32_alloc(cls); 443 if (!u) 444 return nl_errno(ENOMEM); 445 446 sel = u32_selector_alloc(u); 447 if (!sel) 448 return nl_errno(ENOMEM); 449 450 sel->flags |= flags; 451 u->cu_mask |= U32_ATTR_SELECTOR; 452 453 return 0; 454} 455 456/** 457 * Append new 32-bit key to the selector 458 * 459 * @arg cls classifier to be modifier 460 * @arg val value to be matched (network byte-order) 461 * @arg mask mask to be applied before matching (network byte-order) 462 * @arg off offset, in bytes, to start matching 463 * @arg offmask offset mask 464 * 465 * General selectors define the pattern, mask and offset the pattern will be 466 * matched to the packet contents. Using the general selectors you can match 467 * virtually any single bit in the IP (or upper layer) header. 468 * 469*/ 470int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask, 471 int off, int offmask) 472{ 473 struct tc_u32_sel *sel; 474 struct rtnl_u32 *u; 475 int err; 476 477 u = u32_alloc(cls); 478 if (!u) 479 return nl_errno(ENOMEM); 480 481 sel = u32_selector_alloc(u); 482 if (!sel) 483 return nl_errno(ENOMEM); 484 485 err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key)); 486 if (err < 0) 487 return err; 488 489 /* the selector might have been moved by realloc */ 490 sel = u32_selector(u); 491 492 sel->keys[sel->nkeys].mask = mask; 493 sel->keys[sel->nkeys].val = val & mask; 494 sel->keys[sel->nkeys].off = off; 495 sel->keys[sel->nkeys].offmask = offmask; 496 sel->nkeys++; 497 u->cu_mask |= U32_ATTR_SELECTOR; 498 499 return 0; 500} 501 502int rtnl_u32_add_key_uint8(struct rtnl_cls *cls, uint8_t val, uint8_t mask, 503 int off, int offmask) 504{ 505 int shift = 24 - 8 * (off & 3); 506 507 return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift), 508 htonl((uint32_t)mask << shift), 509 off & ~3, offmask); 510} 511 512/** 513 * Append new selector key to match a 16-bit number 514 * 515 * @arg cls classifier to be modified 516 * @arg val value to be matched (host byte-order) 517 * @arg mask mask to be applied before matching (host byte-order) 518 * @arg off offset, in bytes, to start matching 519 * @arg offmask offset mask 520*/ 521int rtnl_u32_add_key_uint16(struct rtnl_cls *cls, uint16_t val, uint16_t mask, 522 int off, int offmask) 523{ 524 int shift = ((off & 3) == 0 ? 16 : 0); 525 if (off % 2) 526 return nl_error(EINVAL, "Invalid offset alignment"); 527 528 return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift), 529 htonl((uint32_t)mask << shift), 530 off & ~3, offmask); 531} 532 533/** 534 * Append new selector key to match a 32-bit number 535 * 536 * @arg cls classifier to be modified 537 * @arg val value to be matched (host byte-order) 538 * @arg mask mask to be applied before matching (host byte-order) 539 * @arg off offset, in bytes, to start matching 540 * @arg offmask offset mask 541*/ 542int rtnl_u32_add_key_uint32(struct rtnl_cls *cls, uint32_t val, uint32_t mask, 543 int off, int offmask) 544{ 545 return rtnl_u32_add_key(cls, htonl(val), htonl(mask), 546 off & ~3, offmask); 547} 548 549int rtnl_u32_add_key_in_addr(struct rtnl_cls *cls, struct in_addr *addr, 550 uint8_t bitmask, int off, int offmask) 551{ 552 uint32_t mask = 0xFFFFFFFF << (32 - bitmask); 553 return rtnl_u32_add_key(cls, addr->s_addr, htonl(mask), off, offmask); 554} 555 556int rtnl_u32_add_key_in6_addr(struct rtnl_cls *cls, struct in6_addr *addr, 557 uint8_t bitmask, int off, int offmask) 558{ 559 int i, err; 560 561 for (i = 1; i <= 4; i++) { 562 if (32 * i - bitmask <= 0) { 563 if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1], 564 0xFFFFFFFF, off+4*(i-1), offmask)) < 0) 565 return err; 566 } 567 else if (32 * i - bitmask < 32) { 568 uint32_t mask = 0xFFFFFFFF << (32 * i - bitmask); 569 if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1], 570 htonl(mask), off+4*(i-1), offmask)) < 0) 571 return err; 572 } 573 /* otherwise, if (32*i - bitmask >= 32) no key is generated */ 574 } 575 576 return 0; 577} 578 579/** @} */ 580 581static struct rtnl_cls_ops u32_ops = { 582 .co_kind = "u32", 583 .co_msg_parser = u32_msg_parser, 584 .co_free_data = u32_free_data, 585 .co_clone = u32_clone, 586 .co_get_opts = u32_get_opts, 587 .co_dump[NL_DUMP_BRIEF] = u32_dump_brief, 588 .co_dump[NL_DUMP_FULL] = u32_dump_full, 589 .co_dump[NL_DUMP_STATS] = u32_dump_stats, 590}; 591 592static void __init u32_init(void) 593{ 594 rtnl_cls_register(&u32_ops); 595} 596 597static void __exit u32_exit(void) 598{ 599 rtnl_cls_unregister(&u32_ops); 600} 601 602/** @} */ 603