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