Home | History | Annotate | Download | only in cls
      1 /*
      2  * lib/route/cls/basic.c	Basic Classifier
      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 cls_basic Basic Classifier
     15  *
     16  * @par Introduction
     17  * The basic classifier is the simplest form of a classifier. It does
     18  * not have any special classification capabilities, instead it can be
     19  * used to classify exclusively based on extended matches or to
     20  * create a "catch-all" filter.
     21  *
     22  * @{
     23  */
     24 
     25 #include <netlink-private/netlink.h>
     26 #include <netlink-private/tc.h>
     27 #include <netlink/netlink.h>
     28 #include <netlink-private/route/tc-api.h>
     29 #include <netlink/route/classifier.h>
     30 #include <netlink/route/action.h>
     31 #include <netlink/route/cls/basic.h>
     32 #include <netlink/route/cls/ematch.h>
     33 
     34 struct rtnl_basic
     35 {
     36 	uint32_t			b_target;
     37 	struct rtnl_ematch_tree *	b_ematch;
     38 	int				b_mask;
     39 	struct rtnl_act *		b_act;
     40 };
     41 
     42 /** @cond SKIP */
     43 #define BASIC_ATTR_TARGET	0x001
     44 #define BASIC_ATTR_EMATCH	0x002
     45 #define BASIC_ATTR_ACTION	0x004
     46 /** @endcond */
     47 
     48 static struct nla_policy basic_policy[TCA_BASIC_MAX+1] = {
     49 	[TCA_BASIC_CLASSID]	= { .type = NLA_U32 },
     50 	[TCA_BASIC_EMATCHES]	= { .type = NLA_NESTED },
     51 };
     52 
     53 static int basic_clone(void *_dst, void *_src)
     54 {
     55 	return -NLE_OPNOTSUPP;
     56 }
     57 
     58 static void basic_free_data(struct rtnl_tc *tc, void *data)
     59 {
     60 	struct rtnl_basic *b = data;
     61 
     62 	if (!b)
     63 		return;
     64 
     65 	if (b->b_act)
     66 		rtnl_act_put_all(&b->b_act);
     67 	rtnl_ematch_tree_free(b->b_ematch);
     68 }
     69 
     70 static int basic_msg_parser(struct rtnl_tc *tc, void *data)
     71 {
     72 	struct nlattr *tb[TCA_BASIC_MAX + 1];
     73 	struct rtnl_basic *b = data;
     74 	int err;
     75 
     76 	err = tca_parse(tb, TCA_BASIC_MAX, tc, basic_policy);
     77 	if (err < 0)
     78 		return err;
     79 
     80 	if (tb[TCA_BASIC_CLASSID]) {
     81 		b->b_target = nla_get_u32(tb[TCA_BASIC_CLASSID]);
     82 		b->b_mask |= BASIC_ATTR_TARGET;
     83 	}
     84 
     85 	if (tb[TCA_BASIC_EMATCHES]) {
     86 		if ((err = rtnl_ematch_parse_attr(tb[TCA_BASIC_EMATCHES],
     87 					     &b->b_ematch)) < 0)
     88 			return err;
     89 
     90 		if (b->b_ematch)
     91 			b->b_mask |= BASIC_ATTR_EMATCH;
     92 	}
     93 	if (tb[TCA_BASIC_ACT]) {
     94 		b->b_mask |= BASIC_ATTR_ACTION;
     95 		err = rtnl_act_parse(&b->b_act, tb[TCA_BASIC_ACT]);
     96 		if (err)
     97 			return err;
     98 	}
     99 
    100 	return 0;
    101 }
    102 
    103 static void basic_dump_line(struct rtnl_tc *tc, void *data,
    104 			    struct nl_dump_params *p)
    105 {
    106 	struct rtnl_basic *b = data;
    107 	char buf[32];
    108 
    109 	if (!b)
    110 		return;
    111 
    112 	if (b->b_mask & BASIC_ATTR_EMATCH)
    113 		nl_dump(p, " ematch");
    114 	else
    115 		nl_dump(p, " match-all");
    116 
    117 	if (b->b_mask & BASIC_ATTR_TARGET)
    118 		nl_dump(p, " target %s",
    119 			rtnl_tc_handle2str(b->b_target, buf, sizeof(buf)));
    120 }
    121 
    122 static void basic_dump_details(struct rtnl_tc *tc, void *data,
    123 			       struct nl_dump_params *p)
    124 {
    125 	struct rtnl_basic *b = data;
    126 
    127 	if (!b)
    128 		return;
    129 
    130 	if (b->b_mask & BASIC_ATTR_EMATCH) {
    131 		nl_dump_line(p, "    ematch ");
    132 		rtnl_ematch_tree_dump(b->b_ematch, p);
    133 	} else
    134 		nl_dump(p, "no options.\n");
    135 }
    136 
    137 static int basic_msg_fill(struct rtnl_tc *tc, void *data,
    138 			  struct nl_msg *msg)
    139 {
    140 	struct rtnl_basic *b = data;
    141 
    142 	if (!b)
    143 		return 0;
    144 
    145 	if (b->b_mask & BASIC_ATTR_TARGET)
    146 		NLA_PUT_U32(msg, TCA_BASIC_CLASSID, b->b_target);
    147 
    148 	if (b->b_mask & BASIC_ATTR_EMATCH &&
    149 	    rtnl_ematch_fill_attr(msg, TCA_BASIC_EMATCHES, b->b_ematch) < 0)
    150 		goto nla_put_failure;
    151 
    152 	if (b->b_mask & BASIC_ATTR_ACTION) {
    153 		int err;
    154 
    155 		err = rtnl_act_fill(msg, TCA_BASIC_ACT, b->b_act);
    156 		if (err)
    157 			return err;
    158 	}
    159 
    160 	return 0;
    161 
    162 nla_put_failure:
    163 	return -NLE_NOMEM;
    164 }
    165 
    166 /**
    167  * @name Attribute Modifications
    168  * @{
    169  */
    170 
    171 void rtnl_basic_set_target(struct rtnl_cls *cls, uint32_t target)
    172 {
    173 	struct rtnl_basic *b;
    174 
    175 	if (!(b = rtnl_tc_data(TC_CAST(cls))))
    176 		return;
    177 
    178 	b->b_target = target;
    179 	b->b_mask |= BASIC_ATTR_TARGET;
    180 }
    181 
    182 uint32_t rtnl_basic_get_target(struct rtnl_cls *cls)
    183 {
    184 	struct rtnl_basic *b;
    185 
    186 	if (!(b = rtnl_tc_data(TC_CAST(cls))))
    187 		return 0;
    188 
    189 	return b->b_target;
    190 }
    191 
    192 void rtnl_basic_set_ematch(struct rtnl_cls *cls, struct rtnl_ematch_tree *tree)
    193 {
    194 	struct rtnl_basic *b;
    195 
    196 	if (!(b = rtnl_tc_data(TC_CAST(cls))))
    197 		return;
    198 
    199 	if (b->b_ematch) {
    200 		rtnl_ematch_tree_free(b->b_ematch);
    201 		b->b_mask &= ~BASIC_ATTR_EMATCH;
    202 	}
    203 
    204 	b->b_ematch = tree;
    205 
    206 	if (tree)
    207 		b->b_mask |= BASIC_ATTR_EMATCH;
    208 }
    209 
    210 struct rtnl_ematch_tree *rtnl_basic_get_ematch(struct rtnl_cls *cls)
    211 {
    212 	struct rtnl_basic *b;
    213 
    214 	if (!(b = rtnl_tc_data(TC_CAST(cls))))
    215 		return NULL;
    216 
    217 	return b->b_ematch;
    218 }
    219 
    220 int rtnl_basic_add_action(struct rtnl_cls *cls, struct rtnl_act *act)
    221 {
    222 	struct rtnl_basic *b;
    223 
    224 	if (!act)
    225 		return 0;
    226 
    227 	if (!(b = rtnl_tc_data(TC_CAST(cls))))
    228 		return -NLE_NOMEM;
    229 
    230 	b->b_mask |= BASIC_ATTR_ACTION;
    231 	/* In case user frees it */
    232 	rtnl_act_get(act);
    233 	return rtnl_act_append(&b->b_act, act);
    234 }
    235 
    236 int rtnl_basic_del_action(struct rtnl_cls *cls, struct rtnl_act *act)
    237 {
    238 	struct rtnl_basic *b;
    239 	int ret;
    240 
    241 	if (!act)
    242 		return 0;
    243 
    244 	if (!(b = rtnl_tc_data(TC_CAST(cls))))
    245 		return -NLE_NOMEM;
    246 
    247 	if (!(b->b_mask & BASIC_ATTR_ACTION))
    248 		return -NLE_INVAL;
    249 	ret = rtnl_act_remove(&b->b_act, act);
    250 	if (ret)
    251 		return ret;
    252 
    253 	if (!b->b_act)
    254 		b->b_mask &= ~BASIC_ATTR_ACTION;
    255 	rtnl_act_put(act);
    256 	return 0;
    257 }
    258 /** @} */
    259 
    260 static struct rtnl_tc_ops basic_ops = {
    261 	.to_kind		= "basic",
    262 	.to_type		= RTNL_TC_TYPE_CLS,
    263 	.to_size		= sizeof(struct rtnl_basic),
    264 	.to_msg_parser		= basic_msg_parser,
    265 	.to_clone		= basic_clone,
    266 	.to_free_data		= basic_free_data,
    267 	.to_msg_fill		= basic_msg_fill,
    268 	.to_dump = {
    269 	    [NL_DUMP_LINE]	= basic_dump_line,
    270 	    [NL_DUMP_DETAILS]	= basic_dump_details,
    271 	},
    272 };
    273 
    274 static void __init basic_init(void)
    275 {
    276 	rtnl_tc_register(&basic_ops);
    277 }
    278 
    279 static void __exit basic_exit(void)
    280 {
    281 	rtnl_tc_unregister(&basic_ops);
    282 }
    283 
    284 /** @} */
    285