• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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 
basic_clone(void * _dst,void * _src)53 static int basic_clone(void *_dst, void *_src)
54 {
55 	return -NLE_OPNOTSUPP;
56 }
57 
basic_free_data(struct rtnl_tc * tc,void * data)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 
basic_msg_parser(struct rtnl_tc * tc,void * data)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 
basic_dump_line(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)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 
basic_dump_details(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)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 
basic_msg_fill(struct rtnl_tc * tc,void * data,struct nl_msg * msg)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 
rtnl_basic_set_target(struct rtnl_cls * cls,uint32_t target)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 
rtnl_basic_get_target(struct rtnl_cls * cls)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 
rtnl_basic_set_ematch(struct rtnl_cls * cls,struct rtnl_ematch_tree * tree)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 
rtnl_basic_get_ematch(struct rtnl_cls * cls)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 
rtnl_basic_add_action(struct rtnl_cls * cls,struct rtnl_act * act)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 
rtnl_basic_del_action(struct rtnl_cls * cls,struct rtnl_act * act)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 
basic_init(void)274 static void __init basic_init(void)
275 {
276 	rtnl_tc_register(&basic_ops);
277 }
278 
basic_exit(void)279 static void __exit basic_exit(void)
280 {
281 	rtnl_tc_unregister(&basic_ops);
282 }
283 
284 /** @} */
285