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/classifier-modules.h>
00024 #include <netlink/route/cls/ematch.h>
00025
00026
00027
00028
00029
00030
00031 static NL_LIST_HEAD(ematch_ops_list);
00032
00033
00034
00035
00036
00037
00038
00039 int rtnl_ematch_register(struct rtnl_ematch_ops *ops)
00040 {
00041 if (rtnl_ematch_lookup_ops(ops->eo_kind))
00042 return -NLE_EXIST;
00043
00044 nl_list_add_tail(&ops->eo_list, &ematch_ops_list);
00045
00046 return 0;
00047 }
00048
00049
00050
00051
00052
00053
00054
00055 int rtnl_ematch_unregister(struct rtnl_ematch_ops *ops)
00056 {
00057 struct rtnl_ematch_ops *o;
00058
00059 nl_list_for_each_entry(o, &ematch_ops_list, eo_list) {
00060 if (ops->eo_kind == o->eo_kind) {
00061 nl_list_del(&o->eo_list);
00062 return 0;
00063 }
00064 }
00065
00066 return -NLE_OBJ_NOTFOUND;
00067 }
00068
00069
00070
00071
00072
00073
00074
00075 struct rtnl_ematch_ops *rtnl_ematch_lookup_ops(int kind)
00076 {
00077 struct rtnl_ematch_ops *ops;
00078
00079 nl_list_for_each_entry(ops, &ematch_ops_list, eo_list)
00080 if (ops->eo_kind == kind)
00081 return ops;
00082
00083 return NULL;
00084 }
00085
00086
00087
00088
00089
00090
00091
00092 struct rtnl_ematch_ops *rtnl_ematch_lookup_ops_name(const char *name)
00093 {
00094 struct rtnl_ematch_ops *ops;
00095
00096 nl_list_for_each_entry(ops, &ematch_ops_list, eo_list)
00097 if (!strcasecmp(ops->eo_name, name))
00098 return ops;
00099
00100 return NULL;
00101 }
00102
00103
00104
00105
00106
00107
00108
00109 struct rtnl_ematch *rtnl_ematch_alloc(struct rtnl_ematch_ops *ops)
00110 {
00111 struct rtnl_ematch *e;
00112 size_t len = sizeof(*e) + (ops ? ops->eo_datalen : 0);
00113
00114 if (!(e = calloc(1, len)))
00115 return NULL;
00116
00117 NL_INIT_LIST_HEAD(&e->e_list);
00118 NL_INIT_LIST_HEAD(&e->e_childs);
00119
00120 if (ops) {
00121 e->e_ops = ops;
00122 e->e_kind = ops->eo_kind;
00123 }
00124
00125 return e;
00126 }
00127
00128
00129
00130
00131
00132
00133 void rtnl_ematch_add_child(struct rtnl_ematch *parent,
00134 struct rtnl_ematch *child)
00135 {
00136 nl_list_add_tail(&child->e_list, &parent->e_childs);
00137 }
00138
00139
00140
00141
00142
00143 void rtnl_ematch_unlink(struct rtnl_ematch *ematch)
00144 {
00145 nl_list_del(&ematch->e_list);
00146 }
00147
00148 void rtnl_ematch_free(struct rtnl_ematch *ematch)
00149 {
00150 if (!ematch)
00151 return;
00152
00153 free(ematch);
00154 }
00155
00156 void rtnl_ematch_set_flags(struct rtnl_ematch *ematch, uint16_t flags)
00157 {
00158 ematch->e_flags |= flags;
00159 }
00160
00161 void rtnl_ematch_unset_flags(struct rtnl_ematch *ematch, uint16_t flags)
00162 {
00163 ematch->e_flags &= ~flags;
00164 }
00165
00166 uint16_t rtnl_ematch_get_flags(struct rtnl_ematch *ematch)
00167 {
00168 return ematch->e_flags;
00169 }
00170
00171 void *rtnl_ematch_data(struct rtnl_ematch *ematch)
00172 {
00173 return ematch->e_data;
00174 }
00175
00176
00177
00178
00179
00180
00181
00182 struct rtnl_ematch_tree *rtnl_ematch_tree_alloc(uint16_t progid)
00183 {
00184 struct rtnl_ematch_tree *tree;
00185
00186 if (!(tree = calloc(1, sizeof(*tree))))
00187 return NULL;
00188
00189 NL_INIT_LIST_HEAD(&tree->et_list);
00190 tree->et_progid = progid;
00191
00192 return tree;
00193 }
00194
00195 static void free_ematch_list(struct nl_list_head *head)
00196 {
00197 struct rtnl_ematch *pos, *next;
00198
00199 nl_list_for_each_entry_safe(pos, next, head, e_list) {
00200 if (!nl_list_empty(&pos->e_childs))
00201 free_ematch_list(&pos->e_childs);
00202 rtnl_ematch_free(pos);
00203 }
00204 }
00205
00206 void rtnl_ematch_tree_free(struct rtnl_ematch_tree *tree)
00207 {
00208 if (!tree)
00209 return;
00210
00211 free_ematch_list(&tree->et_list);
00212 free(tree);
00213 }
00214
00215 void rtnl_ematch_tree_add_tail(struct rtnl_ematch_tree *tree,
00216 struct rtnl_ematch *ematch)
00217 {
00218 nl_list_add_tail(&ematch->e_list, &tree->et_list);
00219 }
00220
00221 static inline uint32_t container_ref(struct rtnl_ematch *ematch)
00222 {
00223 return *((uint32_t *) rtnl_ematch_data(ematch));
00224 }
00225
00226 static int link_tree(struct rtnl_ematch *index[], int nmatches, int pos,
00227 struct nl_list_head *root)
00228 {
00229 struct rtnl_ematch *ematch;
00230 int i;
00231
00232 for (i = pos; i < nmatches; i++) {
00233 ematch = index[i];
00234
00235 nl_list_add_tail(&ematch->e_list, root);
00236
00237 if (ematch->e_kind == TCF_EM_CONTAINER)
00238 link_tree(index, nmatches, container_ref(ematch),
00239 &ematch->e_childs);
00240
00241 if (!(ematch->e_flags & TCF_EM_REL_MASK))
00242 return 0;
00243 }
00244
00245
00246 return -NLE_INVAL;
00247 }
00248
00249 static struct nla_policy tree_policy[TCA_EMATCH_TREE_MAX+1] = {
00250 [TCA_EMATCH_TREE_HDR] = { .minlen=sizeof(struct tcf_ematch_tree_hdr) },
00251 [TCA_EMATCH_TREE_LIST] = { .type = NLA_NESTED },
00252 };
00253
00254
00255
00256
00257
00258
00259 int rtnl_ematch_parse(struct nlattr *attr, struct rtnl_ematch_tree **result)
00260 {
00261 struct nlattr *a, *tb[TCA_EMATCH_TREE_MAX+1];
00262 struct tcf_ematch_tree_hdr *thdr;
00263 struct rtnl_ematch_tree *tree;
00264 struct rtnl_ematch **index;
00265 int nmatches = 0, err, remaining;
00266
00267 err = nla_parse_nested(tb, TCA_EMATCH_TREE_MAX, attr, tree_policy);
00268 if (err < 0)
00269 return err;
00270
00271 if (!tb[TCA_EMATCH_TREE_HDR])
00272 return -NLE_MISSING_ATTR;
00273
00274 thdr = nla_data(tb[TCA_EMATCH_TREE_HDR]);
00275
00276
00277 if (thdr->nmatches == 0)
00278 return 0;
00279
00280 if (!tb[TCA_EMATCH_TREE_LIST])
00281 return -NLE_MISSING_ATTR;
00282
00283 if (thdr->nmatches > (nla_len(tb[TCA_EMATCH_TREE_LIST]) /
00284 nla_total_size(sizeof(struct tcf_ematch_hdr))))
00285 return -NLE_INVAL;
00286
00287 if (!(index = calloc(thdr->nmatches, sizeof(struct rtnl_ematch *))))
00288 return -NLE_NOMEM;
00289
00290 if (!(tree = rtnl_ematch_tree_alloc(thdr->progid))) {
00291 err = -NLE_NOMEM;
00292 goto errout;
00293 }
00294
00295 nla_for_each_nested(a, tb[TCA_EMATCH_TREE_LIST], remaining) {
00296 struct rtnl_ematch_ops *ops;
00297 struct tcf_ematch_hdr *hdr;
00298 struct rtnl_ematch *ematch;
00299 void *data;
00300 size_t len;
00301
00302 if (nla_len(a) < sizeof(*hdr)) {
00303 err = -NLE_INVAL;
00304 goto errout;
00305 }
00306
00307 if (nmatches >= thdr->nmatches) {
00308 err = -NLE_RANGE;
00309 goto errout;
00310 }
00311
00312 hdr = nla_data(a);
00313 data = nla_data(a) + NLA_ALIGN(sizeof(*hdr));
00314 len = nla_len(a) - NLA_ALIGN(sizeof(*hdr));
00315
00316 ops = rtnl_ematch_lookup_ops(hdr->kind);
00317 if (ops && ops->eo_datalen && len < ops->eo_datalen) {
00318 err = -NLE_INVAL;
00319 goto errout;
00320 }
00321
00322 if (!(ematch = rtnl_ematch_alloc(ops))) {
00323 err = -NLE_NOMEM;
00324 goto errout;
00325 }
00326
00327 ematch->e_id = hdr->matchid;
00328 ematch->e_kind = hdr->kind;
00329 ematch->e_flags = hdr->flags;
00330
00331 if (ops && (err = ops->eo_parse(ematch, data, len)) < 0)
00332 goto errout;
00333
00334 if (hdr->kind == TCF_EM_CONTAINER &&
00335 container_ref(ematch) >= thdr->nmatches) {
00336 err = -NLE_INVAL;
00337 goto errout;
00338 }
00339
00340 index[nmatches++] = ematch;
00341 }
00342
00343 if (nmatches != thdr->nmatches) {
00344 err = -NLE_INVAL;
00345 goto errout;
00346 }
00347
00348 err = link_tree(index, nmatches, 0, &tree->et_list);
00349 if (err < 0)
00350 goto errout;
00351
00352 free(index);
00353 *result = tree;
00354
00355 return 0;
00356
00357 errout:
00358 rtnl_ematch_tree_free(tree);
00359 free(index);
00360 return err;
00361 }
00362
00363 static void dump_ematch_sequence(struct nl_list_head *head,
00364 struct nl_dump_params *p)
00365 {
00366 struct rtnl_ematch *match;
00367
00368 nl_list_for_each_entry(match, head, e_list) {
00369 if (match->e_flags & TCF_EM_INVERT)
00370 nl_dump(p, "NOT ");
00371
00372 if (match->e_kind == TCF_EM_CONTAINER) {
00373 nl_dump(p, "(");
00374 dump_ematch_sequence(&match->e_childs, p);
00375 nl_dump(p, ")");
00376 } else if (!match->e_ops) {
00377 nl_dump(p, "[unknown ematch %d]", match->e_kind);
00378 } else {
00379 nl_dump(p, "%s(", match->e_ops->eo_name);
00380
00381 if (match->e_ops->eo_dump)
00382 match->e_ops->eo_dump(match, p);
00383
00384 nl_dump(p, ")");
00385 }
00386
00387 switch (match->e_flags & TCF_EM_REL_MASK) {
00388 case TCF_EM_REL_AND:
00389 nl_dump(p, " AND ");
00390 break;
00391 case TCF_EM_REL_OR:
00392 nl_dump(p, " OR ");
00393 break;
00394 default:
00395
00396 return;
00397 }
00398 }
00399 }
00400
00401 void rtnl_ematch_tree_dump(struct rtnl_ematch_tree *tree,
00402 struct nl_dump_params *p)
00403 {
00404 dump_ematch_sequence(&tree->et_list, p);
00405 nl_dump(p, "\n");
00406 }
00407
00408
00409
00410