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-2009 Thomas Graf <tgraf (at) suug.ch> 10 * Copyright (c) 2005-2006 Petr Gotthard <petr.gotthard (at) 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 43 static inline struct tc_u32_sel *u32_selector(struct rtnl_u32 *u) 44 { 45 return (struct tc_u32_sel *) u->cu_selector->d_data; 46 } 47 48 static inline struct tc_u32_sel *u32_selector_alloc(struct rtnl_u32 *u) 49 { 50 if (!u->cu_selector) 51 u->cu_selector = nl_data_alloc(NULL, sizeof(struct tc_u32_sel)); 52 53 return u32_selector(u); 54 } 55 56 static struct nla_policy u32_policy[TCA_U32_MAX+1] = { 57 [TCA_U32_DIVISOR] = { .type = NLA_U32 }, 58 [TCA_U32_HASH] = { .type = NLA_U32 }, 59 [TCA_U32_CLASSID] = { .type = NLA_U32 }, 60 [TCA_U32_LINK] = { .type = NLA_U32 }, 61 [TCA_U32_INDEV] = { .type = NLA_STRING, 62 .maxlen = IFNAMSIZ }, 63 [TCA_U32_SEL] = { .minlen = sizeof(struct tc_u32_sel) }, 64 [TCA_U32_PCNT] = { .minlen = sizeof(struct tc_u32_pcnt) }, 65 }; 66 67 static int u32_msg_parser(struct rtnl_cls *cls) 68 { 69 struct rtnl_u32 *u = rtnl_cls_data(cls); 70 struct nlattr *tb[TCA_U32_MAX + 1]; 71 int err; 72 73 err = tca_parse(tb, TCA_U32_MAX, (struct rtnl_tca *) cls, u32_policy); 74 if (err < 0) 75 return err; 76 77 if (tb[TCA_U32_DIVISOR]) { 78 u->cu_divisor = nla_get_u32(tb[TCA_U32_DIVISOR]); 79 u->cu_mask |= U32_ATTR_DIVISOR; 80 } 81 82 if (tb[TCA_U32_SEL]) { 83 u->cu_selector = nl_data_alloc_attr(tb[TCA_U32_SEL]); 84 if (!u->cu_selector) 85 goto errout_nomem; 86 u->cu_mask |= U32_ATTR_SELECTOR; 87 } 88 89 if (tb[TCA_U32_HASH]) { 90 u->cu_hash = nla_get_u32(tb[TCA_U32_HASH]); 91 u->cu_mask |= U32_ATTR_HASH; 92 } 93 94 if (tb[TCA_U32_CLASSID]) { 95 u->cu_classid = nla_get_u32(tb[TCA_U32_CLASSID]); 96 u->cu_mask |= U32_ATTR_CLASSID; 97 } 98 99 if (tb[TCA_U32_LINK]) { 100 u->cu_link = nla_get_u32(tb[TCA_U32_LINK]); 101 u->cu_mask |= U32_ATTR_LINK; 102 } 103 104 if (tb[TCA_U32_ACT]) { 105 u->cu_act = nl_data_alloc_attr(tb[TCA_U32_ACT]); 106 if (!u->cu_act) 107 goto errout_nomem; 108 u->cu_mask |= U32_ATTR_ACTION; 109 } 110 111 if (tb[TCA_U32_POLICE]) { 112 u->cu_police = nl_data_alloc_attr(tb[TCA_U32_POLICE]); 113 if (!u->cu_police) 114 goto errout_nomem; 115 u->cu_mask |= U32_ATTR_POLICE; 116 } 117 118 if (tb[TCA_U32_PCNT]) { 119 struct tc_u32_sel *sel; 120 int pcnt_size; 121 122 if (!tb[TCA_U32_SEL]) { 123 err = -NLE_MISSING_ATTR; 124 goto errout; 125 } 126 127 sel = u->cu_selector->d_data; 128 pcnt_size = sizeof(struct tc_u32_pcnt) + 129 (sel->nkeys * sizeof(uint64_t)); 130 if (nla_len(tb[TCA_U32_PCNT]) < pcnt_size) { 131 err = -NLE_INVAL; 132 goto errout; 133 } 134 135 u->cu_pcnt = nl_data_alloc_attr(tb[TCA_U32_PCNT]); 136 if (!u->cu_pcnt) 137 goto errout_nomem; 138 u->cu_mask |= U32_ATTR_PCNT; 139 } 140 141 if (tb[TCA_U32_INDEV]) { 142 nla_strlcpy(u->cu_indev, tb[TCA_U32_INDEV], IFNAMSIZ); 143 u->cu_mask |= U32_ATTR_INDEV; 144 } 145 146 return 0; 147 148 errout_nomem: 149 err = -NLE_NOMEM; 150 errout: 151 return err; 152 } 153 154 static void u32_free_data(struct rtnl_cls *cls) 155 { 156 struct rtnl_u32 *u = rtnl_cls_data(cls); 157 158 nl_data_free(u->cu_selector); 159 nl_data_free(u->cu_act); 160 nl_data_free(u->cu_police); 161 nl_data_free(u->cu_pcnt); 162 } 163 164 static int u32_clone(struct rtnl_cls *_dst, struct rtnl_cls *_src) 165 { 166 struct rtnl_u32 *dst = rtnl_cls_data(_dst); 167 struct rtnl_u32 *src = rtnl_cls_data(_src); 168 169 if (src->cu_selector && 170 !(dst->cu_selector = nl_data_clone(src->cu_selector))) 171 return -NLE_NOMEM; 172 173 if (src->cu_act && !(dst->cu_act = nl_data_clone(src->cu_act))) 174 return -NLE_NOMEM; 175 176 if (src->cu_police && !(dst->cu_police = nl_data_clone(src->cu_police))) 177 return -NLE_NOMEM; 178 179 if (src->cu_pcnt && !(dst->cu_pcnt = nl_data_clone(src->cu_pcnt))) 180 return -NLE_NOMEM; 181 182 return 0; 183 } 184 185 static void u32_dump_line(struct rtnl_cls *cls, struct nl_dump_params *p) 186 { 187 struct rtnl_u32 *u = rtnl_cls_data(cls); 188 char buf[32]; 189 190 if (u->cu_mask & U32_ATTR_DIVISOR) 191 nl_dump(p, " divisor %u", u->cu_divisor); 192 else if (u->cu_mask & U32_ATTR_CLASSID) 193 nl_dump(p, " target %s", 194 rtnl_tc_handle2str(u->cu_classid, buf, sizeof(buf))); 195 } 196 197 static void print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel, 198 struct rtnl_cls *cls, struct rtnl_u32 *u) 199 { 200 int i; 201 struct tc_u32_key *key; 202 203 if (sel->hmask || sel->hoff) { 204 /* I guess this will never be used since the kernel only 205 * exports the selector if no divisor is set but hash offset 206 * and hash mask make only sense in hash filters with divisor 207 * set */ 208 nl_dump(p, " hash at %u & 0x%x", sel->hoff, sel->hmask); 209 } 210 211 if (sel->flags & (TC_U32_OFFSET | TC_U32_VAROFFSET)) { 212 nl_dump(p, " offset at %u", sel->off); 213 214 if (sel->flags & TC_U32_VAROFFSET) 215 nl_dump(p, " variable (at %u & 0x%x) >> %u", 216 sel->offoff, ntohs(sel->offmask), sel->offshift); 217 } 218 219 if (sel->flags) { 220 int flags = sel->flags; 221 nl_dump(p, " <"); 222 223 #define PRINT_FLAG(f) if (flags & TC_U32_##f) { \ 224 flags &= ~TC_U32_##f; nl_dump(p, #f "%s", flags ? "," : ""); } 225 226 PRINT_FLAG(TERMINAL); 227 PRINT_FLAG(OFFSET); 228 PRINT_FLAG(VAROFFSET); 229 PRINT_FLAG(EAT); 230 #undef PRINT_FLAG 231 232 nl_dump(p, ">"); 233 } 234 235 236 for (i = 0; i < sel->nkeys; i++) { 237 key = (struct tc_u32_key *) ((char *) sel + sizeof(*sel)) + i; 238 239 nl_dump(p, "\n"); 240 nl_dump_line(p, " match key at %s%u ", 241 key->offmask ? "nexthdr+" : "", key->off); 242 243 if (key->offmask) 244 nl_dump(p, "[0x%u] ", key->offmask); 245 246 nl_dump(p, "& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val)); 247 248 if (p->dp_type == NL_DUMP_STATS && 249 (u->cu_mask & U32_ATTR_PCNT)) { 250 struct tc_u32_pcnt *pcnt = u->cu_pcnt->d_data; 251 nl_dump(p, " successful %" PRIu64, pcnt->kcnts[i]); 252 } 253 } 254 } 255 256 static void u32_dump_details(struct rtnl_cls *cls, struct nl_dump_params *p) 257 { 258 struct rtnl_u32 *u = rtnl_cls_data(cls); 259 struct tc_u32_sel *s; 260 261 if (!(u->cu_mask & U32_ATTR_SELECTOR)) { 262 nl_dump(p, "no-selector\n"); 263 return; 264 } 265 266 s = u->cu_selector->d_data; 267 268 nl_dump(p, "nkeys %u ", s->nkeys); 269 270 if (u->cu_mask & U32_ATTR_HASH) 271 nl_dump(p, "ht key 0x%x hash 0x%u", 272 TC_U32_USERHTID(u->cu_hash), TC_U32_HASH(u->cu_hash)); 273 274 if (u->cu_mask & U32_ATTR_LINK) 275 nl_dump(p, "link %u ", u->cu_link); 276 277 if (u->cu_mask & U32_ATTR_INDEV) 278 nl_dump(p, "indev %s ", u->cu_indev); 279 280 print_selector(p, s, cls, u); 281 nl_dump(p, "\n"); 282 283 #if 0 284 #define U32_ATTR_ACTION 0x040 285 #define U32_ATTR_POLICE 0x080 286 287 struct nl_data act; 288 struct nl_data police; 289 #endif 290 } 291 292 static void u32_dump_stats(struct rtnl_cls *cls, struct nl_dump_params *p) 293 { 294 struct rtnl_u32 *u = rtnl_cls_data(cls); 295 296 if (u->cu_mask & U32_ATTR_PCNT) { 297 struct tc_u32_pcnt *pc = u->cu_pcnt->d_data; 298 nl_dump(p, "\n"); 299 nl_dump_line(p, " hit %8llu count %8llu\n", 300 pc->rhit, pc->rcnt); 301 } 302 } 303 304 static int u32_get_opts(struct rtnl_cls *cls, struct nl_msg *msg) 305 { 306 struct rtnl_u32 *u = rtnl_cls_data(cls); 307 308 if (u->cu_mask & U32_ATTR_DIVISOR) 309 NLA_PUT_U32(msg, TCA_U32_DIVISOR, u->cu_divisor); 310 311 if (u->cu_mask & U32_ATTR_HASH) 312 NLA_PUT_U32(msg, TCA_U32_HASH, u->cu_hash); 313 314 if (u->cu_mask & U32_ATTR_CLASSID) 315 NLA_PUT_U32(msg, TCA_U32_CLASSID, u->cu_classid); 316 317 if (u->cu_mask & U32_ATTR_LINK) 318 NLA_PUT_U32(msg, TCA_U32_LINK, u->cu_link); 319 320 if (u->cu_mask & U32_ATTR_SELECTOR) 321 NLA_PUT_DATA(msg, TCA_U32_SEL, u->cu_selector); 322 323 if (u->cu_mask & U32_ATTR_ACTION) 324 NLA_PUT_DATA(msg, TCA_U32_ACT, u->cu_act); 325 326 if (u->cu_mask & U32_ATTR_POLICE) 327 NLA_PUT_DATA(msg, TCA_U32_POLICE, u->cu_police); 328 329 if (u->cu_mask & U32_ATTR_INDEV) 330 NLA_PUT_STRING(msg, TCA_U32_INDEV, u->cu_indev); 331 332 return 0; 333 334 nla_put_failure: 335 return -NLE_NOMEM; 336 } 337 338 /** 339 * @name Attribute Modifications 340 * @{ 341 */ 342 343 void rtnl_u32_set_handle(struct rtnl_cls *cls, int htid, int hash, 344 int nodeid) 345 { 346 uint32_t handle = (htid << 20) | (hash << 12) | nodeid; 347 348 tca_set_handle((struct rtnl_tca *) cls, handle ); 349 } 350 351 int rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid) 352 { 353 struct rtnl_u32 *u = rtnl_cls_data(cls); 354 355 u->cu_classid = classid; 356 u->cu_mask |= U32_ATTR_CLASSID; 357 358 return 0; 359 } 360 361 /** @} */ 362 363 /** 364 * @name Selector Modifications 365 * @{ 366 */ 367 368 int rtnl_u32_set_flags(struct rtnl_cls *cls, int flags) 369 { 370 struct tc_u32_sel *sel; 371 struct rtnl_u32 *u = rtnl_cls_data(cls); 372 373 sel = u32_selector_alloc(u); 374 if (!sel) 375 return -NLE_NOMEM; 376 377 sel->flags |= flags; 378 u->cu_mask |= U32_ATTR_SELECTOR; 379 380 return 0; 381 } 382 383 /** 384 * Append new 32-bit key to the selector 385 * 386 * @arg cls classifier to be modifier 387 * @arg val value to be matched (network byte-order) 388 * @arg mask mask to be applied before matching (network byte-order) 389 * @arg off offset, in bytes, to start matching 390 * @arg offmask offset mask 391 * 392 * General selectors define the pattern, mask and offset the pattern will be 393 * matched to the packet contents. Using the general selectors you can match 394 * virtually any single bit in the IP (or upper layer) header. 395 * 396 */ 397 int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask, 398 int off, int offmask) 399 { 400 struct tc_u32_sel *sel; 401 struct rtnl_u32 *u = rtnl_cls_data(cls); 402 int err; 403 404 sel = u32_selector_alloc(u); 405 if (!sel) 406 return -NLE_NOMEM; 407 408 err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key)); 409 if (err < 0) 410 return err; 411 412 /* the selector might have been moved by realloc */ 413 sel = u32_selector(u); 414 415 sel->keys[sel->nkeys].mask = mask; 416 sel->keys[sel->nkeys].val = val & mask; 417 sel->keys[sel->nkeys].off = off; 418 sel->keys[sel->nkeys].offmask = offmask; 419 sel->nkeys++; 420 u->cu_mask |= U32_ATTR_SELECTOR; 421 422 return 0; 423 } 424 425 int rtnl_u32_add_key_uint8(struct rtnl_cls *cls, uint8_t val, uint8_t mask, 426 int off, int offmask) 427 { 428 int shift = 24 - 8 * (off & 3); 429 430 return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift), 431 htonl((uint32_t)mask << shift), 432 off & ~3, offmask); 433 } 434 435 /** 436 * Append new selector key to match a 16-bit number 437 * 438 * @arg cls classifier to be modified 439 * @arg val value to be matched (host byte-order) 440 * @arg mask mask to be applied before matching (host byte-order) 441 * @arg off offset, in bytes, to start matching 442 * @arg offmask offset mask 443 */ 444 int rtnl_u32_add_key_uint16(struct rtnl_cls *cls, uint16_t val, uint16_t mask, 445 int off, int offmask) 446 { 447 int shift = ((off & 3) == 0 ? 16 : 0); 448 if (off % 2) 449 return -NLE_INVAL; 450 451 return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift), 452 htonl((uint32_t)mask << shift), 453 off & ~3, offmask); 454 } 455 456 /** 457 * Append new selector key to match a 32-bit number 458 * 459 * @arg cls classifier to be modified 460 * @arg val value to be matched (host byte-order) 461 * @arg mask mask to be applied before matching (host byte-order) 462 * @arg off offset, in bytes, to start matching 463 * @arg offmask offset mask 464 */ 465 int rtnl_u32_add_key_uint32(struct rtnl_cls *cls, uint32_t val, uint32_t mask, 466 int off, int offmask) 467 { 468 return rtnl_u32_add_key(cls, htonl(val), htonl(mask), 469 off & ~3, offmask); 470 } 471 472 int rtnl_u32_add_key_in_addr(struct rtnl_cls *cls, struct in_addr *addr, 473 uint8_t bitmask, int off, int offmask) 474 { 475 uint32_t mask = 0xFFFFFFFF << (32 - bitmask); 476 return rtnl_u32_add_key(cls, addr->s_addr, htonl(mask), off, offmask); 477 } 478 479 int rtnl_u32_add_key_in6_addr(struct rtnl_cls *cls, struct in6_addr *addr, 480 uint8_t bitmask, int off, int offmask) 481 { 482 int i, err; 483 484 for (i = 1; i <= 4; i++) { 485 if (32 * i - bitmask <= 0) { 486 if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1], 487 0xFFFFFFFF, off+4*(i-1), offmask)) < 0) 488 return err; 489 } 490 else if (32 * i - bitmask < 32) { 491 uint32_t mask = 0xFFFFFFFF << (32 * i - bitmask); 492 if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1], 493 htonl(mask), off+4*(i-1), offmask)) < 0) 494 return err; 495 } 496 /* otherwise, if (32*i - bitmask >= 32) no key is generated */ 497 } 498 499 return 0; 500 } 501 502 /** @} */ 503 504 static struct rtnl_cls_ops u32_ops = { 505 .co_kind = "u32", 506 .co_size = sizeof(struct rtnl_u32), 507 .co_msg_parser = u32_msg_parser, 508 .co_free_data = u32_free_data, 509 .co_clone = u32_clone, 510 .co_get_opts = u32_get_opts, 511 .co_dump = { 512 [NL_DUMP_LINE] = u32_dump_line, 513 [NL_DUMP_DETAILS] = u32_dump_details, 514 [NL_DUMP_STATS] = u32_dump_stats, 515 }, 516 }; 517 518 static void __init u32_init(void) 519 { 520 rtnl_cls_register(&u32_ops); 521 } 522 523 static void __exit u32_exit(void) 524 { 525 rtnl_cls_unregister(&u32_ops); 526 } 527 528 /** @} */ 529