00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
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
00031
00032
00033
00034 static NL_LIST_HEAD(ematch_ops_list);
00035
00036
00037
00038
00039
00040
00041
00042
00043
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
00059
00060
00061
00062
00063
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
00078
00079
00080
00081
00082
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
00099
00100
00101
00102
00103
00104
00105
00106
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
00125
00126
00127
00128
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
00146
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
00241
00242
00243
00244
00245
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
00275
00276
00277
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
00292
00293
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
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
00336
00337
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
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
00372
00373
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
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
00417
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
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
00599
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