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