1 /* 2 * lib/route/cls/ematch.c Extended Matches 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) 2008-2013 Thomas Graf <tgraf (at) suug.ch> 10 */ 11 12 /** 13 * @ingroup cls 14 * @defgroup ematch Extended Match 15 * 16 * @{ 17 */ 18 19 #include <netlink-private/netlink.h> 20 #include <netlink-private/tc.h> 21 #include <netlink/netlink.h> 22 #include <netlink/route/classifier.h> 23 #include <netlink/route/cls/ematch.h> 24 #include <netlink/route/cls/ematch/cmp.h> 25 26 #include "ematch_syntax.h" 27 #include "ematch_grammar.h" 28 29 /** 30 * @name Module API 31 * @{ 32 */ 33 34 static NL_LIST_HEAD(ematch_ops_list); 35 36 /** 37 * Register ematch module 38 * @arg ops Module operations. 39 * 40 * This function must be called by each ematch module at initialization 41 * time. It registers the calling module as available module. 42 * 43 * @return 0 on success or a negative error code. 44 */ 45 int rtnl_ematch_register(struct rtnl_ematch_ops *ops) 46 { 47 if (rtnl_ematch_lookup_ops(ops->eo_kind)) 48 return -NLE_EXIST; 49 50 NL_DBG(1, "ematch module \"%s\" registered\n", ops->eo_name); 51 52 nl_list_add_tail(&ops->eo_list, &ematch_ops_list); 53 54 return 0; 55 } 56 57 /** 58 * Lookup ematch module by identification number. 59 * @arg kind Module kind. 60 * 61 * Searches the list of registered ematch modules for match and returns it. 62 * 63 * @return Module operations or NULL if not found. 64 */ 65 struct rtnl_ematch_ops *rtnl_ematch_lookup_ops(int kind) 66 { 67 struct rtnl_ematch_ops *ops; 68 69 nl_list_for_each_entry(ops, &ematch_ops_list, eo_list) 70 if (ops->eo_kind == kind) 71 return ops; 72 73 return NULL; 74 } 75 76 /** 77 * Lookup ematch module by name 78 * @arg name Name of ematch module. 79 * 80 * Searches the list of registered ematch modules for a match and returns it. 81 * 82 * @return Module operations or NULL if not fuond. 83 */ 84 struct rtnl_ematch_ops *rtnl_ematch_lookup_ops_by_name(const char *name) 85 { 86 struct rtnl_ematch_ops *ops; 87 88 nl_list_for_each_entry(ops, &ematch_ops_list, eo_list) 89 if (!strcasecmp(ops->eo_name, name)) 90 return ops; 91 92 return NULL; 93 } 94 95 /** @} */ 96 97 /** 98 * @name Match 99 */ 100 101 /** 102 * Allocate ematch object. 103 * 104 * Allocates and initializes an ematch object. 105 * 106 * @return New ematch object or NULL. 107 */ 108 struct rtnl_ematch *rtnl_ematch_alloc(void) 109 { 110 struct rtnl_ematch *e; 111 112 if (!(e = calloc(1, sizeof(*e)))) 113 return NULL; 114 115 NL_DBG(2, "allocated ematch %p\n", e); 116 117 NL_INIT_LIST_HEAD(&e->e_list); 118 NL_INIT_LIST_HEAD(&e->e_childs); 119 120 return e; 121 } 122 123 /** 124 * Add ematch to the end of the parent's list of children. 125 * @arg parent parent ematch object 126 * @arg child ematch object to be added to parent 127 * 128 * The parent must be a container ematch. 129 */ 130 int rtnl_ematch_add_child(struct rtnl_ematch *parent, 131 struct rtnl_ematch *child) 132 { 133 if (parent->e_kind != TCF_EM_CONTAINER) 134 return -NLE_OPNOTSUPP; 135 136 NL_DBG(2, "added ematch %p \"%s\" to container %p\n", 137 child, child->e_ops->eo_name, parent); 138 139 nl_list_add_tail(&child->e_list, &parent->e_childs); 140 141 return 0; 142 } 143 144 /** 145 * Remove ematch from the list of ematches it is linked to. 146 * @arg ematch ematch object 147 */ 148 void rtnl_ematch_unlink(struct rtnl_ematch *ematch) 149 { 150 NL_DBG(2, "unlinked ematch %p from any lists\n", ematch); 151 152 if (!nl_list_empty(&ematch->e_childs)) 153 NL_DBG(1, "warning: ematch %p with childs was unlinked\n", 154 ematch); 155 156 nl_list_del(&ematch->e_list); 157 nl_init_list_head(&ematch->e_list); 158 } 159 160 void rtnl_ematch_free(struct rtnl_ematch *ematch) 161 { 162 NL_DBG(2, "freed ematch %p\n", ematch); 163 rtnl_ematch_unlink(ematch); 164 free(ematch->e_data); 165 free(ematch); 166 } 167 168 int rtnl_ematch_set_ops(struct rtnl_ematch *ematch, struct rtnl_ematch_ops *ops) 169 { 170 if (ematch->e_ops) 171 return -NLE_EXIST; 172 173 ematch->e_ops = ops; 174 ematch->e_kind = ops->eo_kind; 175 176 if (ops->eo_datalen) { 177 ematch->e_data = calloc(1, ops->eo_datalen); 178 if (!ematch->e_data) 179 return -NLE_NOMEM; 180 181 ematch->e_datalen = ops->eo_datalen; 182 } 183 184 return 0; 185 } 186 187 int rtnl_ematch_set_kind(struct rtnl_ematch *ematch, uint16_t kind) 188 { 189 struct rtnl_ematch_ops *ops; 190 191 if (ematch->e_kind) 192 return -NLE_EXIST; 193 194 ematch->e_kind = kind; 195 196 if ((ops = rtnl_ematch_lookup_ops(kind))) 197 rtnl_ematch_set_ops(ematch, ops); 198 199 return 0; 200 } 201 202 int rtnl_ematch_set_name(struct rtnl_ematch *ematch, const char *name) 203 { 204 struct rtnl_ematch_ops *ops; 205 206 if (ematch->e_kind) 207 return -NLE_EXIST; 208 209 if (!(ops = rtnl_ematch_lookup_ops_by_name(name))) 210 return -NLE_OPNOTSUPP; 211 212 rtnl_ematch_set_ops(ematch, ops); 213 214 return 0; 215 } 216 217 void rtnl_ematch_set_flags(struct rtnl_ematch *ematch, uint16_t flags) 218 { 219 ematch->e_flags |= flags; 220 } 221 222 void rtnl_ematch_unset_flags(struct rtnl_ematch *ematch, uint16_t flags) 223 { 224 ematch->e_flags &= ~flags; 225 } 226 227 uint16_t rtnl_ematch_get_flags(struct rtnl_ematch *ematch) 228 { 229 return ematch->e_flags; 230 } 231 232 void *rtnl_ematch_data(struct rtnl_ematch *ematch) 233 { 234 return ematch->e_data; 235 } 236 237 /** @} */ 238 239 /** 240 * @name Tree 241 */ 242 243 /** 244 * Allocate ematch tree object 245 * @arg progid program id 246 */ 247 struct rtnl_ematch_tree *rtnl_ematch_tree_alloc(uint16_t progid) 248 { 249 struct rtnl_ematch_tree *tree; 250 251 if (!(tree = calloc(1, sizeof(*tree)))) 252 return NULL; 253 254 NL_INIT_LIST_HEAD(&tree->et_list); 255 tree->et_progid = progid; 256 257 NL_DBG(2, "allocated new ematch tree %p, progid=%u\n", tree, progid); 258 259 return tree; 260 } 261 262 static void free_ematch_list(struct nl_list_head *head) 263 { 264 struct rtnl_ematch *pos, *next; 265 266 nl_list_for_each_entry_safe(pos, next, head, e_list) { 267 if (!nl_list_empty(&pos->e_childs)) 268 free_ematch_list(&pos->e_childs); 269 rtnl_ematch_free(pos); 270 } 271 } 272 273 /** 274 * Free ematch tree object 275 * @arg tree ematch tree object 276 * 277 * This function frees the ematch tree and all ematches attached to it. 278 */ 279 void rtnl_ematch_tree_free(struct rtnl_ematch_tree *tree) 280 { 281 if (!tree) 282 return; 283 284 free_ematch_list(&tree->et_list); 285 286 NL_DBG(2, "Freed ematch tree %p\n", tree); 287 288 free(tree); 289 } 290 291 /** 292 * Add ematch object to the end of the ematch tree 293 * @arg tree ematch tree object 294 * @arg ematch ematch object to add 295 */ 296 void rtnl_ematch_tree_add(struct rtnl_ematch_tree *tree, 297 struct rtnl_ematch *ematch) 298 { 299 nl_list_add_tail(&ematch->e_list, &tree->et_list); 300 } 301 302 static inline uint32_t container_ref(struct rtnl_ematch *ematch) 303 { 304 return *((uint32_t *) rtnl_ematch_data(ematch)); 305 } 306 307 static int link_tree(struct rtnl_ematch *index[], int nmatches, int pos, 308 struct nl_list_head *root) 309 { 310 struct rtnl_ematch *ematch; 311 int i; 312 313 for (i = pos; i < nmatches; i++) { 314 ematch = index[i]; 315 316 nl_list_add_tail(&ematch->e_list, root); 317 318 if (ematch->e_kind == TCF_EM_CONTAINER) 319 link_tree(index, nmatches, container_ref(ematch), 320 &ematch->e_childs); 321 322 if (!(ematch->e_flags & TCF_EM_REL_MASK)) 323 return 0; 324 } 325 326 /* Last entry in chain can't possibly have no relation */ 327 return -NLE_INVAL; 328 } 329 330 static struct nla_policy tree_policy[TCA_EMATCH_TREE_MAX+1] = { 331 [TCA_EMATCH_TREE_HDR] = { .minlen=sizeof(struct tcf_ematch_tree_hdr) }, 332 [TCA_EMATCH_TREE_LIST] = { .type = NLA_NESTED }, 333 }; 334 335 /** 336 * Parse ematch netlink attributes 337 * 338 * @return 0 on success or a negative error code. 339 */ 340 int rtnl_ematch_parse_attr(struct nlattr *attr, struct rtnl_ematch_tree **result) 341 { 342 struct nlattr *a, *tb[TCA_EMATCH_TREE_MAX+1]; 343 struct tcf_ematch_tree_hdr *thdr; 344 struct rtnl_ematch_tree *tree; 345 struct rtnl_ematch **index; 346 int nmatches = 0, err, remaining; 347 348 NL_DBG(2, "Parsing attribute %p as ematch tree\n", attr); 349 350 err = nla_parse_nested(tb, TCA_EMATCH_TREE_MAX, attr, tree_policy); 351 if (err < 0) 352 return err; 353 354 if (!tb[TCA_EMATCH_TREE_HDR]) 355 return -NLE_MISSING_ATTR; 356 357 thdr = nla_data(tb[TCA_EMATCH_TREE_HDR]); 358 359 /* Ignore empty trees */ 360 if (thdr->nmatches == 0) { 361 NL_DBG(2, "Ignoring empty ematch configuration\n"); 362 return 0; 363 } 364 365 if (!tb[TCA_EMATCH_TREE_LIST]) 366 return -NLE_MISSING_ATTR; 367 368 NL_DBG(2, "ematch tree found with nmatches=%u, progid=%u\n", 369 thdr->nmatches, thdr->progid); 370 371 /* 372 * Do some basic sanity checking since we will allocate 373 * index[thdr->nmatches]. Calculate how many ematch headers fit into 374 * the provided data and make sure nmatches does not exceed it. 375 */ 376 if (thdr->nmatches > (nla_len(tb[TCA_EMATCH_TREE_LIST]) / 377 nla_total_size(sizeof(struct tcf_ematch_hdr)))) 378 return -NLE_INVAL; 379 380 if (!(index = calloc(thdr->nmatches, sizeof(struct rtnl_ematch *)))) 381 return -NLE_NOMEM; 382 383 if (!(tree = rtnl_ematch_tree_alloc(thdr->progid))) { 384 err = -NLE_NOMEM; 385 goto errout; 386 } 387 388 nla_for_each_nested(a, tb[TCA_EMATCH_TREE_LIST], remaining) { 389 struct rtnl_ematch_ops *ops; 390 struct tcf_ematch_hdr *hdr; 391 struct rtnl_ematch *ematch; 392 void *data; 393 size_t len; 394 395 NL_DBG(3, "parsing ematch attribute %d, len=%u\n", 396 nmatches+1, nla_len(a)); 397 398 if (nla_len(a) < sizeof(*hdr)) { 399 err = -NLE_INVAL; 400 goto errout; 401 } 402 403 /* Quit as soon as we've parsed more matches than expected */ 404 if (nmatches >= thdr->nmatches) { 405 err = -NLE_RANGE; 406 goto errout; 407 } 408 409 hdr = nla_data(a); 410 data = nla_data(a) + NLA_ALIGN(sizeof(*hdr)); 411 len = nla_len(a) - NLA_ALIGN(sizeof(*hdr)); 412 413 NL_DBG(3, "ematch attribute matchid=%u, kind=%u, flags=%u\n", 414 hdr->matchid, hdr->kind, hdr->flags); 415 416 /* 417 * Container matches contain a reference to another sequence 418 * of matches. Ensure that the reference is within boundries. 419 */ 420 if (hdr->kind == TCF_EM_CONTAINER && 421 *((uint32_t *) data) >= thdr->nmatches) { 422 err = -NLE_INVAL; 423 goto errout; 424 } 425 426 if (!(ematch = rtnl_ematch_alloc())) { 427 err = -NLE_NOMEM; 428 goto errout; 429 } 430 431 ematch->e_id = hdr->matchid; 432 ematch->e_kind = hdr->kind; 433 ematch->e_flags = hdr->flags; 434 435 if ((ops = rtnl_ematch_lookup_ops(hdr->kind))) { 436 if (ops->eo_minlen && len < ops->eo_minlen) { 437 rtnl_ematch_free(ematch); 438 err = -NLE_INVAL; 439 goto errout; 440 } 441 442 rtnl_ematch_set_ops(ematch, ops); 443 444 if (ops->eo_parse && 445 (err = ops->eo_parse(ematch, data, len)) < 0) { 446 rtnl_ematch_free(ematch); 447 goto errout; 448 } 449 } 450 451 NL_DBG(3, "index[%d] = %p\n", nmatches, ematch); 452 index[nmatches++] = ematch; 453 } 454 455 if (nmatches != thdr->nmatches) { 456 err = -NLE_INVAL; 457 goto errout; 458 } 459 460 err = link_tree(index, nmatches, 0, &tree->et_list); 461 if (err < 0) 462 goto errout; 463 464 free(index); 465 *result = tree; 466 467 return 0; 468 469 errout: 470 rtnl_ematch_tree_free(tree); 471 free(index); 472 return err; 473 } 474 475 static void dump_ematch_sequence(struct nl_list_head *head, 476 struct nl_dump_params *p) 477 { 478 struct rtnl_ematch *match; 479 480 nl_list_for_each_entry(match, head, e_list) { 481 if (match->e_flags & TCF_EM_INVERT) 482 nl_dump(p, "!"); 483 484 if (match->e_kind == TCF_EM_CONTAINER) { 485 nl_dump(p, "("); 486 dump_ematch_sequence(&match->e_childs, p); 487 nl_dump(p, ")"); 488 } else if (!match->e_ops) { 489 nl_dump(p, "[unknown ematch %d]", match->e_kind); 490 } else { 491 if (match->e_ops->eo_dump) 492 match->e_ops->eo_dump(match, p); 493 else 494 nl_dump(p, "[data]"); 495 } 496 497 switch (match->e_flags & TCF_EM_REL_MASK) { 498 case TCF_EM_REL_AND: 499 nl_dump(p, " AND "); 500 break; 501 case TCF_EM_REL_OR: 502 nl_dump(p, " OR "); 503 break; 504 default: 505 /* end of first level ematch sequence */ 506 return; 507 } 508 } 509 } 510 511 void rtnl_ematch_tree_dump(struct rtnl_ematch_tree *tree, 512 struct nl_dump_params *p) 513 { 514 if (!tree) 515 BUG(); 516 517 dump_ematch_sequence(&tree->et_list, p); 518 nl_dump(p, "\n"); 519 } 520 521 static int update_container_index(struct nl_list_head *list, int *index) 522 { 523 struct rtnl_ematch *e; 524 525 nl_list_for_each_entry(e, list, e_list) 526 e->e_index = (*index)++; 527 528 nl_list_for_each_entry(e, list, e_list) { 529 if (e->e_kind == TCF_EM_CONTAINER) { 530 int err; 531 532 if (nl_list_empty(&e->e_childs)) 533 return -NLE_OBJ_NOTFOUND; 534 535 *((uint32_t *) e->e_data) = *index; 536 537 err = update_container_index(&e->e_childs, index); 538 if (err < 0) 539 return err; 540 } 541 } 542 543 return 0; 544 } 545 546 static int fill_ematch_sequence(struct nl_msg *msg, struct nl_list_head *list) 547 { 548 struct rtnl_ematch *e; 549 550 nl_list_for_each_entry(e, list, e_list) { 551 struct tcf_ematch_hdr match = { 552 .matchid = e->e_id, 553 .kind = e->e_kind, 554 .flags = e->e_flags, 555 }; 556 struct nlattr *attr; 557 int err = 0; 558 559 if (!(attr = nla_nest_start(msg, e->e_index + 1))) 560 return -NLE_NOMEM; 561 562 if (nlmsg_append(msg, &match, sizeof(match), 0) < 0) 563 return -NLE_NOMEM; 564 565 if (e->e_ops->eo_fill) 566 err = e->e_ops->eo_fill(e, msg); 567 else if (e->e_flags & TCF_EM_SIMPLE) 568 err = nlmsg_append(msg, e->e_data, 4, 0); 569 else if (e->e_datalen > 0) 570 err = nlmsg_append(msg, e->e_data, e->e_datalen, 0); 571 572 NL_DBG(3, "msg %p: added ematch [%d] id=%d kind=%d flags=%d\n", 573 msg, e->e_index, match.matchid, match.kind, match.flags); 574 575 if (err < 0) 576 return -NLE_NOMEM; 577 578 nla_nest_end(msg, attr); 579 } 580 581 nl_list_for_each_entry(e, list, e_list) { 582 if (e->e_kind == TCF_EM_CONTAINER && 583 fill_ematch_sequence(msg, &e->e_childs) < 0) 584 return -NLE_NOMEM; 585 } 586 587 return 0; 588 } 589 590 int rtnl_ematch_fill_attr(struct nl_msg *msg, int attrid, 591 struct rtnl_ematch_tree *tree) 592 { 593 struct tcf_ematch_tree_hdr thdr = { 594 .progid = tree->et_progid, 595 }; 596 struct nlattr *list, *topattr; 597 int err, index = 0; 598 599 /* Assign index number to each ematch to allow for references 600 * to be made while constructing the sequence of matches. */ 601 err = update_container_index(&tree->et_list, &index); 602 if (err < 0) 603 return err; 604 605 if (!(topattr = nla_nest_start(msg, attrid))) 606 goto nla_put_failure; 607 608 thdr.nmatches = index; 609 NLA_PUT(msg, TCA_EMATCH_TREE_HDR, sizeof(thdr), &thdr); 610 611 if (!(list = nla_nest_start(msg, TCA_EMATCH_TREE_LIST))) 612 goto nla_put_failure; 613 614 if (fill_ematch_sequence(msg, &tree->et_list) < 0) 615 goto nla_put_failure; 616 617 nla_nest_end(msg, list); 618 619 nla_nest_end(msg, topattr); 620 621 return 0; 622 623 nla_put_failure: 624 return -NLE_NOMEM; 625 } 626 627 /** @} */ 628 629 extern int ematch_parse(void *, char **, struct nl_list_head *); 630 631 int rtnl_ematch_parse_expr(const char *expr, char **errp, 632 struct rtnl_ematch_tree **result) 633 { 634 struct rtnl_ematch_tree *tree; 635 YY_BUFFER_STATE buf = NULL; 636 yyscan_t scanner = NULL; 637 int err; 638 639 NL_DBG(2, "Parsing ematch expression \"%s\"\n", expr); 640 641 if (!(tree = rtnl_ematch_tree_alloc(RTNL_EMATCH_PROGID))) 642 return -NLE_FAILURE; 643 644 if ((err = ematch_lex_init(&scanner)) < 0) { 645 err = -NLE_FAILURE; 646 goto errout; 647 } 648 649 buf = ematch__scan_string(expr, scanner); 650 651 if ((err = ematch_parse(scanner, errp, &tree->et_list)) != 0) { 652 ematch__delete_buffer(buf, scanner); 653 err = -NLE_PARSE_ERR; 654 goto errout; 655 } 656 657 ematch_lex_destroy(scanner); 658 *result = tree; 659 660 return 0; 661 662 errout: 663 if (scanner) 664 ematch_lex_destroy(scanner); 665 666 rtnl_ematch_tree_free(tree); 667 668 return err; 669 } 670 671 static const char *layer_txt[] = { 672 [TCF_LAYER_LINK] = "eth", 673 [TCF_LAYER_NETWORK] = "ip", 674 [TCF_LAYER_TRANSPORT] = "tcp", 675 }; 676 677 char *rtnl_ematch_offset2txt(uint8_t layer, uint16_t offset, char *buf, size_t len) 678 { 679 snprintf(buf, len, "%s+%u", 680 (layer <= TCF_LAYER_MAX) ? layer_txt[layer] : "?", 681 offset); 682 683 return buf; 684 } 685 686 static const char *operand_txt[] = { 687 [TCF_EM_OPND_EQ] = "=", 688 [TCF_EM_OPND_LT] = "<", 689 [TCF_EM_OPND_GT] = ">", 690 }; 691 692 char *rtnl_ematch_opnd2txt(uint8_t opnd, char *buf, size_t len) 693 { 694 snprintf(buf, len, "%s", 695 opnd < ARRAY_SIZE(operand_txt) ? operand_txt[opnd] : "?"); 696 697 return buf; 698 } 699 700 /** @} */ 701