1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3 * Copyright (c) 2017 Volodymyr Bendiuga <[email protected]>
4 */
5
6 /**
7 * @ingroup cls
8 * @defgroup cls_mall Match-all Classifier
9 *
10 * @{
11 */
12
13 #include "nl-default.h"
14
15 #include <netlink/netlink.h>
16 #include <netlink/attr.h>
17 #include <netlink/utils.h>
18 #include <netlink/route/classifier.h>
19 #include <netlink/route/cls/matchall.h>
20 #include <netlink/route/action.h>
21
22 #include "tc-api.h"
23 #include "nl-aux-route/nl-route.h"
24
25 struct rtnl_mall {
26 uint32_t m_classid;
27 uint32_t m_flags;
28 struct rtnl_act *m_act;
29 int m_mask;
30 };
31
32 #define MALL_ATTR_CLASSID 0x01
33 #define MALL_ATTR_FLAGS 0x02
34 #define MALL_ATTR_ACTION 0x03
35
36
37 static struct nla_policy mall_policy[TCA_MATCHALL_MAX + 1] = {
38 [TCA_MATCHALL_CLASSID] = { .type = NLA_U32 },
39 [TCA_MATCHALL_FLAGS] = { .type = NLA_U32 },
40 };
41
42 /**
43 * @name Attribute Modifications
44 * @{
45 */
46
rtnl_mall_set_classid(struct rtnl_cls * cls,uint32_t classid)47 int rtnl_mall_set_classid(struct rtnl_cls *cls, uint32_t classid)
48 {
49 struct rtnl_mall *mall;
50 if (!(mall = rtnl_tc_data(TC_CAST(cls))))
51 return -NLE_NOMEM;
52
53 mall->m_classid = classid;
54 mall->m_mask |= MALL_ATTR_CLASSID;
55
56 return 0;
57 }
58
rtnl_mall_get_classid(struct rtnl_cls * cls,uint32_t * classid)59 int rtnl_mall_get_classid(struct rtnl_cls *cls, uint32_t *classid)
60 {
61 struct rtnl_mall *mall;
62
63 if (!(mall = rtnl_tc_data_peek(TC_CAST(cls))))
64 return -NLE_INVAL;
65
66 if (!(mall->m_mask & MALL_ATTR_CLASSID))
67 return -NLE_INVAL;
68
69 *classid = mall->m_classid;
70 return 0;
71 }
72
rtnl_mall_set_flags(struct rtnl_cls * cls,uint32_t flags)73 int rtnl_mall_set_flags(struct rtnl_cls *cls, uint32_t flags)
74 {
75 struct rtnl_mall *mall;
76
77 if (!(mall = rtnl_tc_data(TC_CAST(cls))))
78 return -NLE_NOMEM;
79
80 mall->m_flags = flags;
81 mall->m_mask |= MALL_ATTR_FLAGS;
82
83 return 0;
84 }
85
rtnl_mall_get_flags(struct rtnl_cls * cls,uint32_t * flags)86 int rtnl_mall_get_flags(struct rtnl_cls *cls, uint32_t *flags)
87 {
88 struct rtnl_mall *mall;
89
90 if (!(mall = rtnl_tc_data_peek(TC_CAST(cls))))
91 return -NLE_INVAL;
92
93 if (!(mall->m_mask & MALL_ATTR_FLAGS))
94 return -NLE_INVAL;
95
96 *flags = mall->m_flags;
97 return 0;
98 }
99
rtnl_mall_append_action(struct rtnl_cls * cls,struct rtnl_act * act)100 int rtnl_mall_append_action(struct rtnl_cls *cls, struct rtnl_act *act)
101 {
102 struct rtnl_mall *mall;
103 int err;
104
105 if (!act)
106 return 0;
107
108 if (!(mall = rtnl_tc_data(TC_CAST(cls))))
109 return -NLE_NOMEM;
110
111 if ((err = _rtnl_act_append_get(&mall->m_act, act)) < 0)
112 return err;
113
114 mall->m_mask |= MALL_ATTR_ACTION;
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 < 0)
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 < 0)
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 dst->m_act = NULL;
232
233 if (src->m_act) {
234 if (!(dst->m_act = rtnl_act_alloc()))
235 return -NLE_NOMEM;
236
237 /* action nl list next and prev pointers must be updated */
238 nl_init_list_head(&dst->m_act->ce_list);
239
240 memcpy(dst->m_act, src->m_act, sizeof(struct rtnl_act));
241 next = rtnl_act_next(src->m_act);
242 while (next) {
243 new = (struct rtnl_act *) nl_object_clone((struct nl_object *) next);
244 if (!new)
245 return -NLE_NOMEM;
246
247 err = _rtnl_act_append_take(&dst->m_act, new);
248 if (err < 0)
249 return err;
250
251 next = rtnl_act_next(next);
252 }
253 }
254
255 return 0;
256 }
257
mall_dump_line(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)258 static void mall_dump_line(struct rtnl_tc *tc, void *data,
259 struct nl_dump_params *p)
260 {
261 struct rtnl_mall *mall = data;
262 char buf[32];
263
264 if (!mall)
265 return;
266
267 if (mall->m_mask & MALL_ATTR_CLASSID)
268 nl_dump(p, " target %s",
269 rtnl_tc_handle2str(mall->m_classid, buf, sizeof(buf)));
270 }
271
mall_dump_details(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)272 static void mall_dump_details(struct rtnl_tc *tc, void *data,
273 struct nl_dump_params *p)
274 {
275 struct rtnl_mall *mall = data;
276
277 if (!mall)
278 return;
279
280 nl_dump(p, "no details for match-all");
281 }
282
283 static struct rtnl_tc_ops mall_ops = {
284 .to_kind = "matchall",
285 .to_type = RTNL_TC_TYPE_CLS,
286 .to_size = sizeof(struct rtnl_mall),
287 .to_msg_parser = mall_msg_parser,
288 .to_free_data = mall_free_data,
289 .to_clone = mall_clone,
290 .to_msg_fill = mall_msg_fill,
291 .to_dump = {
292 [NL_DUMP_LINE] = mall_dump_line,
293 [NL_DUMP_DETAILS] = mall_dump_details,
294 },
295 };
296
mall_init(void)297 static void _nl_init mall_init(void)
298 {
299 rtnl_tc_register(&mall_ops);
300 }
301
mall_exit(void)302 static void _nl_exit mall_exit(void)
303 {
304 rtnl_tc_unregister(&mall_ops);
305 }
306
307 /** @} */
308