xref: /aosp_15_r20/external/libnl/lib/route/cls/basic.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
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