• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * lib/route/cls/mall.c		match-all 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) 2017 Volodymyr Bendiuga <volodymyr.bendiuga@gmail.com>
10  */
11 
12 /**
13  * @ingroup cls
14  * @defgroup cls_mall Match-all Classifier
15  *
16  * @{
17  */
18 
19 #include <netlink-private/netlink.h>
20 #include <netlink-private/tc.h>
21 #include <netlink/netlink.h>
22 #include <netlink/attr.h>
23 #include <netlink/utils.h>
24 #include <netlink-private/route/tc-api.h>
25 #include <netlink/route/classifier.h>
26 #include <netlink/route/cls/matchall.h>
27 #include <netlink/route/action.h>
28 
29 
30 #define MALL_ATTR_CLASSID 0x01
31 #define MALL_ATTR_FLAGS   0x02
32 #define MALL_ATTR_ACTION  0x03
33 
34 
35 static struct nla_policy mall_policy[TCA_MATCHALL_MAX + 1] = {
36 	[TCA_MATCHALL_CLASSID]	= { .type = NLA_U32 },
37 	[TCA_MATCHALL_FLAGS]	= { .type = NLA_U32 },
38 };
39 
40 /**
41  * @name Attribute Modifications
42  * @{
43  */
44 
rtnl_mall_set_classid(struct rtnl_cls * cls,uint32_t classid)45 int rtnl_mall_set_classid(struct rtnl_cls *cls, uint32_t classid)
46 {
47 	struct rtnl_mall *mall;
48 	if (!(mall = rtnl_tc_data(TC_CAST(cls))))
49 		return -NLE_NOMEM;
50 
51 	mall->m_classid = classid;
52 	mall->m_mask |= MALL_ATTR_CLASSID;
53 
54 	return 0;
55 }
56 
rtnl_mall_get_classid(struct rtnl_cls * cls,uint32_t * classid)57 int rtnl_mall_get_classid(struct rtnl_cls *cls, uint32_t *classid)
58 {
59 	struct rtnl_mall *mall;
60 
61 	if (!(mall = rtnl_tc_data_peek(TC_CAST(cls))))
62 		return -NLE_INVAL;
63 
64 	if (!(mall->m_mask & MALL_ATTR_CLASSID))
65 		return -NLE_INVAL;
66 
67 	*classid = mall->m_classid;
68 	return 0;
69 }
70 
rtnl_mall_set_flags(struct rtnl_cls * cls,uint32_t flags)71 int rtnl_mall_set_flags(struct rtnl_cls *cls, uint32_t flags)
72 {
73 	struct rtnl_mall *mall;
74 
75 	if (!(mall = rtnl_tc_data(TC_CAST(cls))))
76 		return -NLE_NOMEM;
77 
78 	mall->m_flags = flags;
79 	mall->m_mask |= MALL_ATTR_FLAGS;
80 
81 	return 0;
82 }
83 
rtnl_mall_get_flags(struct rtnl_cls * cls,uint32_t * flags)84 int rtnl_mall_get_flags(struct rtnl_cls *cls, uint32_t *flags)
85 {
86 	struct rtnl_mall *mall;
87 
88 	if (!(mall = rtnl_tc_data_peek(TC_CAST(cls))))
89 		return -NLE_INVAL;
90 
91 	if (!(mall->m_mask & MALL_ATTR_FLAGS))
92 		return -NLE_INVAL;
93 
94 	*flags = mall->m_flags;
95 	return 0;
96 }
97 
rtnl_mall_append_action(struct rtnl_cls * cls,struct rtnl_act * act)98 int rtnl_mall_append_action(struct rtnl_cls *cls, struct rtnl_act *act)
99 {
100 	struct rtnl_mall *mall;
101 	int err;
102 
103 	if (!act)
104 		return 0;
105 
106 	if (!(mall = rtnl_tc_data(TC_CAST(cls))))
107 		return -NLE_NOMEM;
108 
109 	mall->m_mask |= MALL_ATTR_ACTION;
110 	err = rtnl_act_append(&mall->m_act, act);
111 	if (err)
112 	        return err;
113 
114 	rtnl_act_get(act);
115 	return 0;
116 }
117 
rtnl_mall_get_first_action(struct rtnl_cls * cls)118 struct rtnl_act *rtnl_mall_get_first_action(struct rtnl_cls *cls)
119 {
120 	struct rtnl_mall *mall;
121 	struct rtnl_act *act;
122 
123 	if (!(mall = rtnl_tc_data(TC_CAST(cls))))
124 		return NULL;
125 
126 	if (!(mall->m_mask & MALL_ATTR_ACTION))
127 		return NULL;
128 
129 	act = mall->m_act;
130 	rtnl_act_get(act);
131 
132 	return act;
133 }
134 
rtnl_mall_del_action(struct rtnl_cls * cls,struct rtnl_act * act)135 int rtnl_mall_del_action(struct rtnl_cls *cls, struct rtnl_act *act)
136 {
137 	struct rtnl_mall *mall;
138 	int ret;
139 
140 	if (!act)
141 		return 0;
142 
143 	if (!(mall = rtnl_tc_data(TC_CAST(cls))))
144 		return -NLE_NOMEM;
145 
146 	if (!(mall->m_mask & MALL_ATTR_ACTION))
147 		return -NLE_INVAL;
148 
149 	ret = rtnl_act_remove(&mall->m_act, act);
150 	if (ret < 0)
151 		return ret;
152 
153 	rtnl_act_put(act);
154 
155 	return 0;
156 }
157 
158 /** @} */
159 
mall_free_data(struct rtnl_tc * tc,void * data)160 static void mall_free_data(struct rtnl_tc *tc, void *data)
161 {
162 	struct rtnl_mall *mall = data;
163 
164 	if (mall->m_act)
165 		rtnl_act_put_all(&mall->m_act);
166 }
167 
mall_msg_parser(struct rtnl_tc * tc,void * data)168 static int mall_msg_parser(struct rtnl_tc *tc, void *data)
169 {
170 	struct rtnl_mall *mall = data;
171 	struct nlattr *tb[TCA_MATCHALL_MAX + 1];
172 	int err;
173 
174 	err = tca_parse(tb, TCA_MATCHALL_MAX, tc, mall_policy);
175 	if (err < 0)
176 		return err;
177 
178 	if (tb[TCA_MATCHALL_CLASSID]) {
179 		mall->m_classid = nla_get_u32(tb[TCA_MATCHALL_CLASSID]);
180 		mall->m_mask |= MALL_ATTR_CLASSID;
181 	}
182 
183 	if (tb[TCA_MATCHALL_FLAGS]) {
184 		mall->m_flags = nla_get_u32(tb[TCA_MATCHALL_FLAGS]);
185 		mall->m_mask |= MALL_ATTR_FLAGS;
186 	}
187 
188 	if (tb[TCA_MATCHALL_ACT]) {
189 		mall->m_mask |= MALL_ATTR_ACTION;
190 		err = rtnl_act_parse(&mall->m_act, tb[TCA_MATCHALL_ACT]);
191 		if (err)
192 			return err;
193 	}
194 
195 	return 0;
196 }
197 
mall_msg_fill(struct rtnl_tc * tc,void * data,struct nl_msg * msg)198 static int mall_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
199 {
200 	struct rtnl_mall *mall = data;
201 
202 	if (!mall)
203 		return 0;
204 
205 	if (mall->m_mask & MALL_ATTR_CLASSID)
206 		NLA_PUT_U32(msg, TCA_MATCHALL_CLASSID, mall->m_classid);
207 
208 	if (mall->m_mask & MALL_ATTR_FLAGS)
209 		NLA_PUT_U32(msg, TCA_MATCHALL_FLAGS, mall->m_flags);
210 
211 	if (mall->m_mask & MALL_ATTR_ACTION) {
212 		int err;
213 
214 		err = rtnl_act_fill(msg, TCA_MATCHALL_ACT, mall->m_act);
215 		if (err)
216 			return err;
217 	}
218 
219 	return 0;
220 
221  nla_put_failure:
222 	return -NLE_NOMEM;
223 }
224 
mall_clone(void * _dst,void * _src)225 static int mall_clone(void *_dst, void *_src)
226 {
227 	struct rtnl_mall *dst = _dst, *src = _src;
228 	struct rtnl_act *next, *new;
229 	int err;
230 
231 	if (src->m_act) {
232 		if (!(dst->m_act = rtnl_act_alloc()))
233 			return -NLE_NOMEM;
234 
235 		/* action nl list next and prev pointers must be updated */
236 		nl_init_list_head(&dst->m_act->ce_list);
237 
238 		memcpy(dst->m_act, src->m_act, sizeof(struct rtnl_act));
239 		next = rtnl_act_next(src->m_act);
240 		while (next) {
241 			new = (struct rtnl_act *) nl_object_clone((struct nl_object *) next);
242 			if (!new)
243 				return -NLE_NOMEM;
244 
245 			err = rtnl_act_append(&dst->m_act, new);
246 			if (err < 0)
247 				return err;
248 
249 			next = rtnl_act_next(next);
250 		}
251 	}
252 
253 	return 0;
254 }
255 
mall_dump_line(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)256 static void mall_dump_line(struct rtnl_tc *tc, void *data,
257 			   struct nl_dump_params *p)
258 {
259 	struct rtnl_mall *mall = data;
260 	char buf[32];
261 
262 	if (!mall)
263 		return;
264 
265 	if (mall->m_mask & MALL_ATTR_CLASSID)
266 		nl_dump(p, " target %s",
267 			rtnl_tc_handle2str(mall->m_classid, buf, sizeof(buf)));
268 }
269 
mall_dump_details(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)270 static void mall_dump_details(struct rtnl_tc *tc, void *data,
271 			      struct nl_dump_params *p)
272 {
273 	struct rtnl_mall *mall = data;
274 
275 	if (!mall)
276 		return;
277 
278 	nl_dump(p, "no details for match-all");
279 }
280 
281 static struct rtnl_tc_ops mall_ops = {
282 	.to_kind		= "matchall",
283 	.to_type		= RTNL_TC_TYPE_CLS,
284 	.to_size		= sizeof(struct rtnl_mall),
285 	.to_msg_parser		= mall_msg_parser,
286 	.to_free_data		= mall_free_data,
287 	.to_clone		= mall_clone,
288 	.to_msg_fill		= mall_msg_fill,
289 	.to_dump = {
290 	    [NL_DUMP_LINE]	= mall_dump_line,
291 	    [NL_DUMP_DETAILS]	= mall_dump_details,
292 	},
293 };
294 
mall_init(void)295 static void __init mall_init(void)
296 {
297 	rtnl_tc_register(&mall_ops);
298 }
299 
mall_exit(void)300 static void __exit mall_exit(void)
301 {
302 	rtnl_tc_unregister(&mall_ops);
303 }
304 
305 /** @} */
306