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