libnl
3.2.3
|
00001 /* 00002 * lib/route/cls/ematch.c Extended Matches 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) 2008-2010 Thomas Graf <tgraf@suug.ch> 00010 */ 00011 00012 /** 00013 * @ingroup cls 00014 * @defgroup ematch Extended Match 00015 * 00016 * @{ 00017 */ 00018 00019 #include <netlink-local.h> 00020 #include <netlink-tc.h> 00021 #include <netlink/netlink.h> 00022 #include <netlink/route/classifier.h> 00023 #include <netlink/route/cls/ematch.h> 00024 #include <netlink/route/cls/ematch/cmp.h> 00025 00026 #include "ematch_syntax.h" 00027 #include "ematch_grammar.h" 00028 00029 /** 00030 * @name Module API 00031 * @{ 00032 */ 00033 00034 static NL_LIST_HEAD(ematch_ops_list); 00035 00036 /** 00037 * Register ematch module 00038 * @arg ops Module operations. 00039 * 00040 * This function must be called by each ematch module at initialization 00041 * time. It registers the calling module as available module. 00042 * 00043 * @return 0 on success or a negative error code. 00044 */ 00045 int rtnl_ematch_register(struct rtnl_ematch_ops *ops) 00046 { 00047 if (rtnl_ematch_lookup_ops(ops->eo_kind)) 00048 return -NLE_EXIST; 00049 00050 NL_DBG(1, "ematch module \"%s\" registered\n", ops->eo_name); 00051 00052 nl_list_add_tail(&ops->eo_list, &ematch_ops_list); 00053 00054 return 0; 00055 } 00056 00057 /** 00058 * Lookup ematch module by identification number. 00059 * @arg kind Module kind. 00060 * 00061 * Searches the list of registered ematch modules for match and returns it. 00062 * 00063 * @return Module operations or NULL if not found. 00064 */ 00065 struct rtnl_ematch_ops *rtnl_ematch_lookup_ops(int kind) 00066 { 00067 struct rtnl_ematch_ops *ops; 00068 00069 nl_list_for_each_entry(ops, &ematch_ops_list, eo_list) 00070 if (ops->eo_kind == kind) 00071 return ops; 00072 00073 return NULL; 00074 } 00075 00076 /** 00077 * Lookup ematch module by name 00078 * @arg name Name of ematch module. 00079 * 00080 * Searches the list of registered ematch modules for a match and returns it. 00081 * 00082 * @return Module operations or NULL if not fuond. 00083 */ 00084 struct rtnl_ematch_ops *rtnl_ematch_lookup_ops_by_name(const char *name) 00085 { 00086 struct rtnl_ematch_ops *ops; 00087 00088 nl_list_for_each_entry(ops, &ematch_ops_list, eo_list) 00089 if (!strcasecmp(ops->eo_name, name)) 00090 return ops; 00091 00092 return NULL; 00093 } 00094 00095 /** @} */ 00096 00097 /** 00098 * @name Match 00099 */ 00100 00101 /** 00102 * Allocate ematch object. 00103 * 00104 * Allocates and initializes an ematch object. 00105 * 00106 * @return New ematch object or NULL. 00107 */ 00108 struct rtnl_ematch *rtnl_ematch_alloc(void) 00109 { 00110 struct rtnl_ematch *e; 00111 00112 if (!(e = calloc(1, sizeof(*e)))) 00113 return NULL; 00114 00115 NL_DBG(2, "allocated ematch %p\n", e); 00116 00117 NL_INIT_LIST_HEAD(&e->e_list); 00118 NL_INIT_LIST_HEAD(&e->e_childs); 00119 00120 return e; 00121 } 00122 00123 /** 00124 * Add ematch to the end of the parent's list of children. 00125 * @arg parent parent ematch object 00126 * @arg child ematch object to be added to parent 00127 * 00128 * The parent must be a container ematch. 00129 */ 00130 int rtnl_ematch_add_child(struct rtnl_ematch *parent, 00131 struct rtnl_ematch *child) 00132 { 00133 if (parent->e_kind != TCF_EM_CONTAINER) 00134 return -NLE_OPNOTSUPP; 00135 00136 NL_DBG(2, "added ematch %p \"%s\" to container %p\n", 00137 child, child->e_ops->eo_name, parent); 00138 00139 nl_list_add_tail(&child->e_list, &parent->e_childs); 00140 00141 return 0; 00142 } 00143 00144 /** 00145 * Remove ematch from the list of ematches it is linked to. 00146 * @arg ematch ematch object 00147 */ 00148 void rtnl_ematch_unlink(struct rtnl_ematch *ematch) 00149 { 00150 NL_DBG(2, "unlinked ematch %p from any lists\n", ematch); 00151 00152 if (!nl_list_empty(&ematch->e_childs)) 00153 NL_DBG(1, "warning: ematch %p with childs was unlinked\n", 00154 ematch); 00155 00156 nl_list_del(&ematch->e_list); 00157 nl_init_list_head(&ematch->e_list); 00158 } 00159 00160 void rtnl_ematch_free(struct rtnl_ematch *ematch) 00161 { 00162 NL_DBG(2, "freed ematch %p\n", ematch); 00163 rtnl_ematch_unlink(ematch); 00164 free(ematch->e_data); 00165 free(ematch); 00166 } 00167 00168 int rtnl_ematch_set_ops(struct rtnl_ematch *ematch, struct rtnl_ematch_ops *ops) 00169 { 00170 if (ematch->e_ops) 00171 return -NLE_EXIST; 00172 00173 ematch->e_ops = ops; 00174 ematch->e_kind = ops->eo_kind; 00175 00176 if (ops->eo_datalen) { 00177 ematch->e_data = calloc(1, ops->eo_datalen); 00178 if (!ematch->e_data) 00179 return -NLE_NOMEM; 00180 00181 ematch->e_datalen = ops->eo_datalen; 00182 } 00183 00184 return 0; 00185 } 00186 00187 int rtnl_ematch_set_kind(struct rtnl_ematch *ematch, uint16_t kind) 00188 { 00189 struct rtnl_ematch_ops *ops; 00190 00191 if (ematch->e_kind) 00192 return -NLE_EXIST; 00193 00194 ematch->e_kind = kind; 00195 00196 if ((ops = rtnl_ematch_lookup_ops(kind))) 00197 rtnl_ematch_set_ops(ematch, ops); 00198 00199 return 0; 00200 } 00201 00202 int rtnl_ematch_set_name(struct rtnl_ematch *ematch, const char *name) 00203 { 00204 struct rtnl_ematch_ops *ops; 00205 00206 if (ematch->e_kind) 00207 return -NLE_EXIST; 00208 00209 if (!(ops = rtnl_ematch_lookup_ops_by_name(name))) 00210 return -NLE_OPNOTSUPP; 00211 00212 rtnl_ematch_set_ops(ematch, ops); 00213 00214 return 0; 00215 } 00216 00217 void rtnl_ematch_set_flags(struct rtnl_ematch *ematch, uint16_t flags) 00218 { 00219 ematch->e_flags |= flags; 00220 } 00221 00222 void rtnl_ematch_unset_flags(struct rtnl_ematch *ematch, uint16_t flags) 00223 { 00224 ematch->e_flags &= ~flags; 00225 } 00226 00227 uint16_t rtnl_ematch_get_flags(struct rtnl_ematch *ematch) 00228 { 00229 return ematch->e_flags; 00230 } 00231 00232 void *rtnl_ematch_data(struct rtnl_ematch *ematch) 00233 { 00234 return ematch->e_data; 00235 } 00236 00237 /** @} */ 00238 00239 /** 00240 * @name Tree 00241 */ 00242 00243 /** 00244 * Allocate ematch tree object 00245 * @arg progid program id 00246 */ 00247 struct rtnl_ematch_tree *rtnl_ematch_tree_alloc(uint16_t progid) 00248 { 00249 struct rtnl_ematch_tree *tree; 00250 00251 if (!(tree = calloc(1, sizeof(*tree)))) 00252 return NULL; 00253 00254 NL_INIT_LIST_HEAD(&tree->et_list); 00255 tree->et_progid = progid; 00256 00257 NL_DBG(2, "allocated new ematch tree %p, progid=%u\n", tree, progid); 00258 00259 return tree; 00260 } 00261 00262 static void free_ematch_list(struct nl_list_head *head) 00263 { 00264 struct rtnl_ematch *pos, *next; 00265 00266 nl_list_for_each_entry_safe(pos, next, head, e_list) { 00267 if (!nl_list_empty(&pos->e_childs)) 00268 free_ematch_list(&pos->e_childs); 00269 rtnl_ematch_free(pos); 00270 } 00271 } 00272 00273 /** 00274 * Free ematch tree object 00275 * @arg tree ematch tree object 00276 * 00277 * This function frees the ematch tree and all ematches attached to it. 00278 */ 00279 void rtnl_ematch_tree_free(struct rtnl_ematch_tree *tree) 00280 { 00281 if (!tree) 00282 return; 00283 00284 free_ematch_list(&tree->et_list); 00285 free(tree); 00286 00287 NL_DBG(2, "Freed ematch tree %p\n", tree); 00288 } 00289 00290 /** 00291 * Add ematch object to the end of the ematch tree 00292 * @arg tree ematch tree object 00293 * @arg ematch ematch object to add 00294 */ 00295 void rtnl_ematch_tree_add(struct rtnl_ematch_tree *tree, 00296 struct rtnl_ematch *ematch) 00297 { 00298 nl_list_add_tail(&ematch->e_list, &tree->et_list); 00299 } 00300 00301 static inline uint32_t container_ref(struct rtnl_ematch *ematch) 00302 { 00303 return *((uint32_t *) rtnl_ematch_data(ematch)); 00304 } 00305 00306 static int link_tree(struct rtnl_ematch *index[], int nmatches, int pos, 00307 struct nl_list_head *root) 00308 { 00309 struct rtnl_ematch *ematch; 00310 int i; 00311 00312 for (i = pos; i < nmatches; i++) { 00313 ematch = index[i]; 00314 00315 nl_list_add_tail(&ematch->e_list, root); 00316 00317 if (ematch->e_kind == TCF_EM_CONTAINER) 00318 link_tree(index, nmatches, container_ref(ematch), 00319 &ematch->e_childs); 00320 00321 if (!(ematch->e_flags & TCF_EM_REL_MASK)) 00322 return 0; 00323 } 00324 00325 /* Last entry in chain can't possibly have no relation */ 00326 return -NLE_INVAL; 00327 } 00328 00329 static struct nla_policy tree_policy[TCA_EMATCH_TREE_MAX+1] = { 00330 [TCA_EMATCH_TREE_HDR] = { .minlen=sizeof(struct tcf_ematch_tree_hdr) }, 00331 [TCA_EMATCH_TREE_LIST] = { .type = NLA_NESTED }, 00332 }; 00333 00334 /** 00335 * Parse ematch netlink attributes 00336 * 00337 * @return 0 on success or a negative error code. 00338 */ 00339 int rtnl_ematch_parse_attr(struct nlattr *attr, struct rtnl_ematch_tree **result) 00340 { 00341 struct nlattr *a, *tb[TCA_EMATCH_TREE_MAX+1]; 00342 struct tcf_ematch_tree_hdr *thdr; 00343 struct rtnl_ematch_tree *tree; 00344 struct rtnl_ematch **index; 00345 int nmatches = 0, err, remaining; 00346 00347 NL_DBG(2, "Parsing attribute %p as ematch tree\n", attr); 00348 00349 err = nla_parse_nested(tb, TCA_EMATCH_TREE_MAX, attr, tree_policy); 00350 if (err < 0) 00351 return err; 00352 00353 if (!tb[TCA_EMATCH_TREE_HDR]) 00354 return -NLE_MISSING_ATTR; 00355 00356 thdr = nla_data(tb[TCA_EMATCH_TREE_HDR]); 00357 00358 /* Ignore empty trees */ 00359 if (thdr->nmatches == 0) { 00360 NL_DBG(2, "Ignoring empty ematch configuration\n"); 00361 return 0; 00362 } 00363 00364 if (!tb[TCA_EMATCH_TREE_LIST]) 00365 return -NLE_MISSING_ATTR; 00366 00367 NL_DBG(2, "ematch tree found with nmatches=%u, progid=%u\n", 00368 thdr->nmatches, thdr->progid); 00369 00370 /* 00371 * Do some basic sanity checking since we will allocate 00372 * index[thdr->nmatches]. Calculate how many ematch headers fit into 00373 * the provided data and make sure nmatches does not exceed it. 00374 */ 00375 if (thdr->nmatches > (nla_len(tb[TCA_EMATCH_TREE_LIST]) / 00376 nla_total_size(sizeof(struct tcf_ematch_hdr)))) 00377 return -NLE_INVAL; 00378 00379 if (!(index = calloc(thdr->nmatches, sizeof(struct rtnl_ematch *)))) 00380 return -NLE_NOMEM; 00381 00382 if (!(tree = rtnl_ematch_tree_alloc(thdr->progid))) { 00383 err = -NLE_NOMEM; 00384 goto errout; 00385 } 00386 00387 nla_for_each_nested(a, tb[TCA_EMATCH_TREE_LIST], remaining) { 00388 struct rtnl_ematch_ops *ops; 00389 struct tcf_ematch_hdr *hdr; 00390 struct rtnl_ematch *ematch; 00391 void *data; 00392 size_t len; 00393 00394 NL_DBG(3, "parsing ematch attribute %d, len=%u\n", 00395 nmatches+1, nla_len(a)); 00396 00397 if (nla_len(a) < sizeof(*hdr)) { 00398 err = -NLE_INVAL; 00399 goto errout; 00400 } 00401 00402 /* Quit as soon as we've parsed more matches than expected */ 00403 if (nmatches >= thdr->nmatches) { 00404 err = -NLE_RANGE; 00405 goto errout; 00406 } 00407 00408 hdr = nla_data(a); 00409 data = nla_data(a) + NLA_ALIGN(sizeof(*hdr)); 00410 len = nla_len(a) - NLA_ALIGN(sizeof(*hdr)); 00411 00412 NL_DBG(3, "ematch attribute matchid=%u, kind=%u, flags=%u\n", 00413 hdr->matchid, hdr->kind, hdr->flags); 00414 00415 /* 00416 * Container matches contain a reference to another sequence 00417 * of matches. Ensure that the reference is within boundries. 00418 */ 00419 if (hdr->kind == TCF_EM_CONTAINER && 00420 *((uint32_t *) data) >= thdr->nmatches) { 00421 err = -NLE_INVAL; 00422 goto errout; 00423 } 00424 00425 if (!(ematch = rtnl_ematch_alloc())) { 00426 err = -NLE_NOMEM; 00427 goto errout; 00428 } 00429 00430 ematch->e_id = hdr->matchid; 00431 ematch->e_kind = hdr->kind; 00432 ematch->e_flags = hdr->flags; 00433 00434 if ((ops = rtnl_ematch_lookup_ops(hdr->kind))) { 00435 if (ops->eo_minlen && len < ops->eo_minlen) { 00436 rtnl_ematch_free(ematch); 00437 err = -NLE_INVAL; 00438 goto errout; 00439 } 00440 00441 rtnl_ematch_set_ops(ematch, ops); 00442 00443 if (ops->eo_parse && 00444 (err = ops->eo_parse(ematch, data, len)) < 0) { 00445 rtnl_ematch_free(ematch); 00446 goto errout; 00447 } 00448 } 00449 00450 NL_DBG(3, "index[%d] = %p\n", nmatches, ematch); 00451 index[nmatches++] = ematch; 00452 } 00453 00454 if (nmatches != thdr->nmatches) { 00455 err = -NLE_INVAL; 00456 goto errout; 00457 } 00458 00459 err = link_tree(index, nmatches, 0, &tree->et_list); 00460 if (err < 0) 00461 goto errout; 00462 00463 free(index); 00464 *result = tree; 00465 00466 return 0; 00467 00468 errout: 00469 rtnl_ematch_tree_free(tree); 00470 free(index); 00471 return err; 00472 } 00473 00474 static void dump_ematch_sequence(struct nl_list_head *head, 00475 struct nl_dump_params *p) 00476 { 00477 struct rtnl_ematch *match; 00478 00479 nl_list_for_each_entry(match, head, e_list) { 00480 if (match->e_flags & TCF_EM_INVERT) 00481 nl_dump(p, "!"); 00482 00483 if (match->e_kind == TCF_EM_CONTAINER) { 00484 nl_dump(p, "("); 00485 dump_ematch_sequence(&match->e_childs, p); 00486 nl_dump(p, ")"); 00487 } else if (!match->e_ops) { 00488 nl_dump(p, "[unknown ematch %d]", match->e_kind); 00489 } else { 00490 if (match->e_ops->eo_dump) 00491 match->e_ops->eo_dump(match, p); 00492 else 00493 nl_dump(p, "[data]"); 00494 } 00495 00496 switch (match->e_flags & TCF_EM_REL_MASK) { 00497 case TCF_EM_REL_AND: 00498 nl_dump(p, " AND "); 00499 break; 00500 case TCF_EM_REL_OR: 00501 nl_dump(p, " OR "); 00502 break; 00503 default: 00504 /* end of first level ematch sequence */ 00505 return; 00506 } 00507 } 00508 } 00509 00510 void rtnl_ematch_tree_dump(struct rtnl_ematch_tree *tree, 00511 struct nl_dump_params *p) 00512 { 00513 if (!tree) 00514 BUG(); 00515 00516 dump_ematch_sequence(&tree->et_list, p); 00517 nl_dump(p, "\n"); 00518 } 00519 00520 static int update_container_index(struct nl_list_head *list, int *index) 00521 { 00522 struct rtnl_ematch *e; 00523 00524 nl_list_for_each_entry(e, list, e_list) 00525 e->e_index = (*index)++; 00526 00527 nl_list_for_each_entry(e, list, e_list) { 00528 if (e->e_kind == TCF_EM_CONTAINER) { 00529 int err; 00530 00531 if (nl_list_empty(&e->e_childs)) 00532 return -NLE_OBJ_NOTFOUND; 00533 00534 *((uint32_t *) e->e_data) = *index; 00535 00536 err = update_container_index(&e->e_childs, index); 00537 if (err < 0) 00538 return err; 00539 } 00540 } 00541 00542 return 0; 00543 } 00544 00545 static int fill_ematch_sequence(struct nl_msg *msg, struct nl_list_head *list) 00546 { 00547 struct rtnl_ematch *e; 00548 00549 nl_list_for_each_entry(e, list, e_list) { 00550 struct tcf_ematch_hdr match = { 00551 .matchid = e->e_id, 00552 .kind = e->e_kind, 00553 .flags = e->e_flags, 00554 }; 00555 struct nlattr *attr; 00556 int err = 0; 00557 00558 if (!(attr = nla_nest_start(msg, e->e_index + 1))) 00559 return -NLE_NOMEM; 00560 00561 if (nlmsg_append(msg, &match, sizeof(match), 0) < 0) 00562 return -NLE_NOMEM; 00563 00564 if (e->e_ops->eo_fill) 00565 err = e->e_ops->eo_fill(e, msg); 00566 else if (e->e_flags & TCF_EM_SIMPLE) 00567 err = nlmsg_append(msg, e->e_data, 4, 0); 00568 else if (e->e_datalen > 0) 00569 err = nlmsg_append(msg, e->e_data, e->e_datalen, 0); 00570 00571 NL_DBG(3, "msg %p: added ematch [%d] id=%d kind=%d flags=%d\n", 00572 msg, e->e_index, match.matchid, match.kind, match.flags); 00573 00574 if (err < 0) 00575 return -NLE_NOMEM; 00576 00577 nla_nest_end(msg, attr); 00578 } 00579 00580 nl_list_for_each_entry(e, list, e_list) { 00581 if (e->e_kind == TCF_EM_CONTAINER && 00582 fill_ematch_sequence(msg, &e->e_childs) < 0) 00583 return -NLE_NOMEM; 00584 } 00585 00586 return 0; 00587 } 00588 00589 int rtnl_ematch_fill_attr(struct nl_msg *msg, int attrid, 00590 struct rtnl_ematch_tree *tree) 00591 { 00592 struct tcf_ematch_tree_hdr thdr = { 00593 .progid = tree->et_progid, 00594 }; 00595 struct nlattr *list, *topattr; 00596 int err, index = 0; 00597 00598 /* Assign index number to each ematch to allow for references 00599 * to be made while constructing the sequence of matches. */ 00600 err = update_container_index(&tree->et_list, &index); 00601 if (err < 0) 00602 return err; 00603 00604 if (!(topattr = nla_nest_start(msg, attrid))) 00605 goto nla_put_failure; 00606 00607 thdr.nmatches = index; 00608 NLA_PUT(msg, TCA_EMATCH_TREE_HDR, sizeof(thdr), &thdr); 00609 00610 if (!(list = nla_nest_start(msg, TCA_EMATCH_TREE_LIST))) 00611 goto nla_put_failure; 00612 00613 if (fill_ematch_sequence(msg, &tree->et_list) < 0) 00614 goto nla_put_failure; 00615 00616 nla_nest_end(msg, list); 00617 00618 nla_nest_end(msg, topattr); 00619 00620 return 0; 00621 00622 nla_put_failure: 00623 return -NLE_NOMEM; 00624 } 00625 00626 /** @} */ 00627 00628 extern int ematch_parse(void *, char **, struct nl_list_head *); 00629 00630 int rtnl_ematch_parse_expr(const char *expr, char **errp, 00631 struct rtnl_ematch_tree **result) 00632 { 00633 struct rtnl_ematch_tree *tree; 00634 YY_BUFFER_STATE buf = NULL; 00635 yyscan_t scanner = NULL; 00636 int err; 00637 00638 NL_DBG(2, "Parsing ematch expression \"%s\"\n", expr); 00639 00640 if (!(tree = rtnl_ematch_tree_alloc(RTNL_EMATCH_PROGID))) 00641 return -NLE_FAILURE; 00642 00643 if ((err = ematch_lex_init(&scanner)) < 0) { 00644 err = -NLE_FAILURE; 00645 goto errout; 00646 } 00647 00648 buf = ematch__scan_string(expr, scanner); 00649 00650 if ((err = ematch_parse(scanner, errp, &tree->et_list)) != 0) { 00651 ematch__delete_buffer(buf, scanner); 00652 err = -NLE_PARSE_ERR; 00653 goto errout; 00654 } 00655 00656 if (scanner) 00657 ematch_lex_destroy(scanner); 00658 00659 *result = tree; 00660 00661 return 0; 00662 00663 errout: 00664 if (scanner) 00665 ematch_lex_destroy(scanner); 00666 00667 rtnl_ematch_tree_free(tree); 00668 00669 return err; 00670 } 00671 00672 static const char *layer_txt[] = { 00673 [TCF_LAYER_LINK] = "eth", 00674 [TCF_LAYER_NETWORK] = "ip", 00675 [TCF_LAYER_TRANSPORT] = "tcp", 00676 }; 00677 00678 char *rtnl_ematch_offset2txt(uint8_t layer, uint16_t offset, char *buf, size_t len) 00679 { 00680 snprintf(buf, len, "%s+%u", 00681 (layer <= TCF_LAYER_MAX) ? layer_txt[layer] : "?", 00682 offset); 00683 00684 return buf; 00685 } 00686 00687 static const char *operand_txt[] = { 00688 [TCF_EM_OPND_EQ] = "=", 00689 [TCF_EM_OPND_LT] = "<", 00690 [TCF_EM_OPND_GT] = ">", 00691 }; 00692 00693 char *rtnl_ematch_opnd2txt(uint8_t opnd, char *buf, size_t len) 00694 { 00695 snprintf(buf, len, "%s", 00696 opnd <= ARRAY_SIZE(operand_txt) ? operand_txt[opnd] : "?"); 00697 00698 return buf; 00699 } 00700 00701 /** @} */