/* * lib/route/cls/basic.c Basic Classifier * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation version 2.1 * of the License. * * Copyright (c) 2008-2013 Thomas Graf <tgraf@suug.ch> */ /** * @ingroup cls * @defgroup cls_basic Basic Classifier * * @par Introduction * The basic classifier is the simplest form of a classifier. It does * not have any special classification capabilities, instead it can be * used to classify exclusively based on extended matches or to * create a "catch-all" filter. * * @{ */ #include <netlink-private/netlink.h> #include <netlink-private/tc.h> #include <netlink/netlink.h> #include <netlink-private/route/tc-api.h> #include <netlink/route/classifier.h> #include <netlink/route/action.h> #include <netlink/route/cls/basic.h> #include <netlink/route/cls/ematch.h> struct rtnl_basic { uint32_t b_target; struct rtnl_ematch_tree * b_ematch; int b_mask; struct rtnl_act * b_act; }; /** @cond SKIP */ #define BASIC_ATTR_TARGET 0x001 #define BASIC_ATTR_EMATCH 0x002 #define BASIC_ATTR_ACTION 0x004 /** @endcond */ static struct nla_policy basic_policy[TCA_BASIC_MAX+1] = { [TCA_BASIC_CLASSID] = { .type = NLA_U32 }, [TCA_BASIC_EMATCHES] = { .type = NLA_NESTED }, }; static int basic_clone(void *_dst, void *_src) { return -NLE_OPNOTSUPP; } static void basic_free_data(struct rtnl_tc *tc, void *data) { struct rtnl_basic *b = data; if (!b) return; if (b->b_act) rtnl_act_put_all(&b->b_act); rtnl_ematch_tree_free(b->b_ematch); } static int basic_msg_parser(struct rtnl_tc *tc, void *data) { struct nlattr *tb[TCA_BASIC_MAX + 1]; struct rtnl_basic *b = data; int err; err = tca_parse(tb, TCA_BASIC_MAX, tc, basic_policy); if (err < 0) return err; if (tb[TCA_BASIC_CLASSID]) { b->b_target = nla_get_u32(tb[TCA_BASIC_CLASSID]); b->b_mask |= BASIC_ATTR_TARGET; } if (tb[TCA_BASIC_EMATCHES]) { if ((err = rtnl_ematch_parse_attr(tb[TCA_BASIC_EMATCHES], &b->b_ematch)) < 0) return err; if (b->b_ematch) b->b_mask |= BASIC_ATTR_EMATCH; } if (tb[TCA_BASIC_ACT]) { b->b_mask |= BASIC_ATTR_ACTION; err = rtnl_act_parse(&b->b_act, tb[TCA_BASIC_ACT]); if (err) return err; } return 0; } static void basic_dump_line(struct rtnl_tc *tc, void *data, struct nl_dump_params *p) { struct rtnl_basic *b = data; char buf[32]; if (!b) return; if (b->b_mask & BASIC_ATTR_EMATCH) nl_dump(p, " ematch"); else nl_dump(p, " match-all"); if (b->b_mask & BASIC_ATTR_TARGET) nl_dump(p, " target %s", rtnl_tc_handle2str(b->b_target, buf, sizeof(buf))); } static void basic_dump_details(struct rtnl_tc *tc, void *data, struct nl_dump_params *p) { struct rtnl_basic *b = data; if (!b) return; if (b->b_mask & BASIC_ATTR_EMATCH) { nl_dump_line(p, " ematch "); rtnl_ematch_tree_dump(b->b_ematch, p); } else nl_dump(p, "no options.\n"); } static int basic_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) { struct rtnl_basic *b = data; if (!b) return 0; if (b->b_mask & BASIC_ATTR_TARGET) NLA_PUT_U32(msg, TCA_BASIC_CLASSID, b->b_target); if (b->b_mask & BASIC_ATTR_EMATCH && rtnl_ematch_fill_attr(msg, TCA_BASIC_EMATCHES, b->b_ematch) < 0) goto nla_put_failure; if (b->b_mask & BASIC_ATTR_ACTION) { int err; err = rtnl_act_fill(msg, TCA_BASIC_ACT, b->b_act); if (err) return err; } return 0; nla_put_failure: return -NLE_NOMEM; } /** * @name Attribute Modifications * @{ */ void rtnl_basic_set_target(struct rtnl_cls *cls, uint32_t target) { struct rtnl_basic *b; if (!(b = rtnl_tc_data(TC_CAST(cls)))) return; b->b_target = target; b->b_mask |= BASIC_ATTR_TARGET; } uint32_t rtnl_basic_get_target(struct rtnl_cls *cls) { struct rtnl_basic *b; if (!(b = rtnl_tc_data(TC_CAST(cls)))) return 0; return b->b_target; } void rtnl_basic_set_ematch(struct rtnl_cls *cls, struct rtnl_ematch_tree *tree) { struct rtnl_basic *b; if (!(b = rtnl_tc_data(TC_CAST(cls)))) return; if (b->b_ematch) { rtnl_ematch_tree_free(b->b_ematch); b->b_mask &= ~BASIC_ATTR_EMATCH; } b->b_ematch = tree; if (tree) b->b_mask |= BASIC_ATTR_EMATCH; } struct rtnl_ematch_tree *rtnl_basic_get_ematch(struct rtnl_cls *cls) { struct rtnl_basic *b; if (!(b = rtnl_tc_data(TC_CAST(cls)))) return NULL; return b->b_ematch; } int rtnl_basic_add_action(struct rtnl_cls *cls, struct rtnl_act *act) { struct rtnl_basic *b; if (!act) return 0; if (!(b = rtnl_tc_data(TC_CAST(cls)))) return -NLE_NOMEM; b->b_mask |= BASIC_ATTR_ACTION; /* In case user frees it */ rtnl_act_get(act); return rtnl_act_append(&b->b_act, act); } int rtnl_basic_del_action(struct rtnl_cls *cls, struct rtnl_act *act) { struct rtnl_basic *b; int ret; if (!act) return 0; if (!(b = rtnl_tc_data(TC_CAST(cls)))) return -NLE_NOMEM; if (!(b->b_mask & BASIC_ATTR_ACTION)) return -NLE_INVAL; ret = rtnl_act_remove(&b->b_act, act); if (ret) return ret; if (!b->b_act) b->b_mask &= ~BASIC_ATTR_ACTION; rtnl_act_put(act); return 0; } /** @} */ static struct rtnl_tc_ops basic_ops = { .to_kind = "basic", .to_type = RTNL_TC_TYPE_CLS, .to_size = sizeof(struct rtnl_basic), .to_msg_parser = basic_msg_parser, .to_clone = basic_clone, .to_free_data = basic_free_data, .to_msg_fill = basic_msg_fill, .to_dump = { [NL_DUMP_LINE] = basic_dump_line, [NL_DUMP_DETAILS] = basic_dump_details, }, }; static void __init basic_init(void) { rtnl_tc_register(&basic_ops); } static void __exit basic_exit(void) { rtnl_tc_unregister(&basic_ops); } /** @} */