xref: /aosp_15_r20/external/libnl/lib/route/act/vlan.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * Copyright (c) 2018 Volodymyr Bendiuga <[email protected]>
4  */
5 
6 /**
7  * @ingroup act
8  * @defgroup act_vlan VLAN Manipulation
9  *
10  * @{
11  */
12 
13 #include "nl-default.h"
14 
15 #include <linux/tc_act/tc_vlan.h>
16 
17 #include <netlink/netlink.h>
18 #include <netlink/attr.h>
19 #include <netlink/utils.h>
20 #include <netlink/route/act/vlan.h>
21 
22 #include "tc-api.h"
23 
24 struct rtnl_vlan
25 {
26 	struct tc_vlan v_parm;
27 	uint16_t       v_vid;
28 	uint16_t       v_proto;
29 	uint8_t        v_prio;
30 	uint32_t       v_flags;
31 };
32 
33 #define VLAN_F_VID   (1 << 0)
34 #define VLAN_F_PROTO (1 << 1)
35 #define VLAN_F_PRIO  (1 << 2)
36 #define VLAN_F_ACT   (1 << 3)
37 #define VLAN_F_MODE  (1 << 4)
38 
39 static struct nla_policy vlan_policy[TCA_VLAN_MAX + 1] = {
40 	[TCA_VLAN_PARMS]                = { .minlen = sizeof(struct tc_vlan) },
41 	[TCA_VLAN_PUSH_VLAN_ID]         = { .type = NLA_U16 },
42 	[TCA_VLAN_PUSH_VLAN_PROTOCOL]   = { .type = NLA_U16 },
43 	[TCA_VLAN_PUSH_VLAN_PRIORITY]   = { .type = NLA_U8 },
44 };
45 
vlan_msg_parser(struct rtnl_tc * tc,void * data)46 static int vlan_msg_parser(struct rtnl_tc *tc, void *data)
47 {
48 	struct rtnl_vlan *v = data;
49 	struct nlattr *tb[TCA_VLAN_MAX + 1];
50 	int err;
51 
52 	err = tca_parse(tb, TCA_VLAN_MAX, tc, vlan_policy);
53 	if (err < 0)
54 		return err;
55 
56 	v->v_flags = 0;
57 	if (!tb[TCA_VLAN_PARMS])
58 		return -NLE_MISSING_ATTR;
59 	else {
60 		nla_memcpy(&v->v_parm, tb[TCA_VLAN_PARMS], sizeof(v->v_parm));
61 		v->v_flags |= VLAN_F_ACT;
62 		v->v_flags |= VLAN_F_MODE;
63 	}
64 
65 	if (tb[TCA_VLAN_PUSH_VLAN_ID]) {
66 		v->v_vid = nla_get_u16(tb[TCA_VLAN_PUSH_VLAN_ID]);
67 		v->v_flags |= VLAN_F_VID;
68 	}
69 
70 	if (tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]) {
71 		v->v_proto = nla_get_u16(tb[TCA_VLAN_PUSH_VLAN_PROTOCOL]);
72 		v->v_flags |= VLAN_F_PROTO;
73 	}
74 
75 	if (tb[TCA_VLAN_PUSH_VLAN_PRIORITY]) {
76 		v->v_prio = nla_get_u8(tb[TCA_VLAN_PUSH_VLAN_PRIORITY]);
77 		v->v_flags |= VLAN_F_PRIO;
78 	}
79 
80 	return 0;
81 }
82 
vlan_msg_fill(struct rtnl_tc * tc,void * data,struct nl_msg * msg)83 static int vlan_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
84 {
85 	struct rtnl_vlan *v = data;
86 
87 	if (!v)
88 		return 0;
89 	if (!(v->v_flags & VLAN_F_MODE))
90 		return -NLE_MISSING_ATTR;
91 
92 	NLA_PUT(msg, TCA_VLAN_PARMS, sizeof(v->v_parm), &v->v_parm);
93 
94 	/* vid is required for PUSH & MODIFY modes */
95 	if ((v->v_parm.v_action != TCA_VLAN_ACT_POP) && !(v->v_flags & VLAN_F_VID))
96 		return -NLE_MISSING_ATTR;
97 
98 	if (v->v_flags & VLAN_F_VID)
99 		NLA_PUT_U16(msg, TCA_VLAN_PUSH_VLAN_ID, v->v_vid);
100 
101 	if (v->v_flags & VLAN_F_PROTO)
102 		NLA_PUT_U16(msg, TCA_VLAN_PUSH_VLAN_PROTOCOL, v->v_proto);
103 
104 	if (v->v_flags & VLAN_F_PRIO)
105 		NLA_PUT_U8(msg, TCA_VLAN_PUSH_VLAN_PRIORITY, v->v_prio);
106 
107 	return 0;
108 
109 nla_put_failure:
110 	return -NLE_NOMEM;
111 }
112 
vlan_free_data(struct rtnl_tc * tc,void * data)113 static void vlan_free_data(struct rtnl_tc *tc, void *data)
114 {
115 }
116 
vlan_dump_line(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)117 static void vlan_dump_line(struct rtnl_tc *tc, void *data,
118                            struct nl_dump_params *p)
119 {
120 	struct rtnl_vlan *v = data;
121 
122 	if (!v)
123 		return;
124 
125 	if (!(v->v_flags & VLAN_F_ACT))
126 		return;
127 
128 	if (TC_ACT_EXT_CMP(v->v_parm.action, TC_ACT_GOTO_CHAIN))
129 		nl_dump(p, " goto chain %u", v->v_parm.action & TC_ACT_EXT_VAL_MASK);
130 
131 	if (TC_ACT_EXT_CMP(v->v_parm.action, TC_ACT_JUMP))
132 		nl_dump(p, " jump %u", v->v_parm.action & TC_ACT_EXT_VAL_MASK);
133 
134 	switch(v->v_parm.action){
135 	case TC_ACT_UNSPEC:
136 		nl_dump(p, " unspecified");
137 		break;
138 	case TC_ACT_PIPE:
139 		nl_dump(p, " pipe");
140 		break;
141 	case TC_ACT_STOLEN:
142 		nl_dump(p, " stolen");
143 		break;
144 	case TC_ACT_SHOT:
145 		nl_dump(p, " shot");
146 		break;
147 	case TC_ACT_QUEUED:
148 		nl_dump(p, " queued");
149 		break;
150 	case TC_ACT_REPEAT:
151 		nl_dump(p, " repeat");
152 		break;
153 	}
154 }
155 
vlan_dump_details(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)156 static void vlan_dump_details(struct rtnl_tc *tc, void *data,
157                               struct nl_dump_params *p)
158 {
159 	struct rtnl_vlan *v = data;
160 
161 	if (!v)
162 		return;
163 
164 	if (v->v_flags & VLAN_F_MODE) {
165 		switch (v->v_parm.v_action) {
166 		case TCA_VLAN_ACT_POP:
167 			nl_dump(p, " mode POP");
168 			break;
169 		case TCA_VLAN_ACT_PUSH:
170 			nl_dump(p, " mode PUSH");
171 			break;
172 		case TCA_VLAN_ACT_MODIFY:
173 			nl_dump(p, " mode MODIFY");
174 			break;
175 		}
176 	}
177 
178 	if (v->v_flags & VLAN_F_VID)
179 		nl_dump(p, " vlan id %u", v->v_vid);
180 
181 	if (v->v_flags & VLAN_F_PRIO)
182 		nl_dump(p, " priority %u", v->v_prio);
183 
184 	if (v->v_flags & VLAN_F_PROTO)
185 		nl_dump(p, " protocol %u", v->v_proto);
186 }
187 
188 /**
189  * @name Attribute Modifications
190  * @{
191  */
192 
193 /**
194  * Set vlan mode
195  * @arg act             vlan action
196  * @arg mode            one of (TCA_VLAN_ACT_*: POP, PUSH, MODIFY)
197  * @return 0 on success or a negative error code.
198  */
rtnl_vlan_set_mode(struct rtnl_act * act,int mode)199 int rtnl_vlan_set_mode(struct rtnl_act *act, int mode)
200 {
201 	struct rtnl_vlan *v;
202 
203 	if (!(v = (struct rtnl_vlan *) rtnl_tc_data(TC_CAST(act))))
204 		return -NLE_NOMEM;
205 
206 	if (mode > TCA_VLAN_ACT_MODIFY)
207 		return -NLE_RANGE;
208 
209 	v->v_parm.v_action = mode;
210 	v->v_flags |= VLAN_F_MODE;
211 
212 	return 0;
213 }
214 
215 /**
216  * Get vlan mode
217  * @arg act             vlan action
218  * @arg out_mode        vlan mode output paramter
219  * @return 0 on success if the vlan mode was returned or a negative error code.
220 */
rtnl_vlan_get_mode(struct rtnl_act * act,int * out_mode)221 int rtnl_vlan_get_mode(struct rtnl_act *act, int *out_mode)
222 {
223 	struct rtnl_vlan *v;
224 
225 	if (!(v = (struct rtnl_vlan *) rtnl_tc_data_peek(TC_CAST(act))))
226 		return -NLE_INVAL;
227 
228 	if (!(v->v_flags & VLAN_F_MODE))
229 		return -NLE_MISSING_ATTR;
230 
231 	*out_mode = v->v_parm.v_action;
232 	return 0;
233 }
234 
235 /**
236  * Set general action
237  * @arg act             vlan action
238  * @arg action          one of (TCA_ACT_*: PIPE, SHOT, GOTO_CHAIN, etc)
239  * @return 0 on success or a negative error code.
240  */
rtnl_vlan_set_action(struct rtnl_act * act,int action)241 int rtnl_vlan_set_action(struct rtnl_act *act, int action)
242 {
243 	struct rtnl_vlan *v;
244 
245 	if (!(v = (struct rtnl_vlan *) rtnl_tc_data(TC_CAST(act))))
246 		return -NLE_NOMEM;
247 
248 	v->v_parm.action = action;
249 	v->v_flags |= VLAN_F_ACT;
250 
251 	return 0;
252 }
253 
254 /**
255  * Get general action
256  * @arg act             vlan action
257  * @arg out_action      output parameter
258  * @return general 0 if out_action was set or a negative error code.
259 */
rtnl_vlan_get_action(struct rtnl_act * act,int * out_action)260 int rtnl_vlan_get_action(struct rtnl_act *act, int *out_action)
261 {
262 	struct rtnl_vlan *v;
263 
264 	if (!(v = (struct rtnl_vlan *) rtnl_tc_data_peek(TC_CAST(act))))
265 		return -NLE_INVAL;
266 
267 	if (!(v->v_flags & VLAN_F_ACT))
268 		return -NLE_MISSING_ATTR;
269 
270 	*out_action = v->v_parm.action;
271 	return 0;
272 }
273 
274 /**
275  * Set protocol
276  * @arg act             vlan action
277  * @arg protocol        one of (ETH_P_8021Q || ETH_P_8021AD)
278  * @return 0 on success or a negative error code.
279  */
rtnl_vlan_set_protocol(struct rtnl_act * act,uint16_t protocol)280 int rtnl_vlan_set_protocol(struct rtnl_act *act, uint16_t protocol)
281 {
282 	struct rtnl_vlan *v;
283 
284 	if (!(v = (struct rtnl_vlan *) rtnl_tc_data(TC_CAST(act))))
285 		return -NLE_NOMEM;
286 
287 	v->v_proto = protocol;
288 	v->v_flags |= VLAN_F_PROTO;
289 
290 	return 0;
291 }
292 
293 /**
294  * Get protocol
295  * @arg act             vlan action
296  * @arg out_protocol    protocol output argument
297  * @return 0 if the protocol was returned or a negative error code.
298 */
rtnl_vlan_get_protocol(struct rtnl_act * act,uint16_t * out_protocol)299 int rtnl_vlan_get_protocol(struct rtnl_act *act, uint16_t *out_protocol)
300 {
301 	struct rtnl_vlan *v;
302 
303 	if (!(v = (struct rtnl_vlan *) rtnl_tc_data_peek(TC_CAST(act))))
304 		return -NLE_INVAL;
305 
306 	if (!(v->v_flags & VLAN_F_PROTO))
307 		return -NLE_MISSING_ATTR;
308 
309 	*out_protocol = v->v_proto;
310 	return 0;
311 }
312 
313 /**
314  * Set vlan id
315  * @arg act             vlan action
316  * @arg vid             vlan id
317  * @return 0 on success or a negative error code.
318  */
rtnl_vlan_set_vlan_id(struct rtnl_act * act,uint16_t vid)319 int rtnl_vlan_set_vlan_id(struct rtnl_act *act, uint16_t vid)
320 {
321 	struct rtnl_vlan *v;
322 
323 	if (!(v = (struct rtnl_vlan *) rtnl_tc_data(TC_CAST(act))))
324 		return -NLE_NOMEM;
325 
326 	if (vid > 4095)
327 		return -NLE_RANGE;
328 
329 	v->v_vid = vid;
330 	v->v_flags |= VLAN_F_VID;
331 
332 	return 0;
333 }
334 
335 /**
336  * Get vlan id
337  * @arg act             vlan action
338  * @arg out_vid         output vlan id
339  * @return 0 if the vlan id was returned or a negative error code.
340 */
rtnl_vlan_get_vlan_id(struct rtnl_act * act,uint16_t * out_vid)341 int rtnl_vlan_get_vlan_id(struct rtnl_act *act, uint16_t *out_vid)
342 {
343 	struct rtnl_vlan *v;
344 
345 	if (!(v = (struct rtnl_vlan *) rtnl_tc_data_peek(TC_CAST(act))))
346 		return -NLE_INVAL;
347 
348 	if (!(v->v_flags & VLAN_F_VID))
349 		return -NLE_MISSING_ATTR;
350 
351 	*out_vid = v->v_vid;
352 	return 0;
353 }
354 
355 /**
356  * Set vlan prio
357  * @arg act             vlan action
358  * @arg prio            vlan priority (0 - 7)
359  * @return 0 on success or a negative error code.
360  */
rtnl_vlan_set_vlan_prio(struct rtnl_act * act,uint8_t prio)361 int rtnl_vlan_set_vlan_prio(struct rtnl_act *act, uint8_t prio)
362 {
363 	struct rtnl_vlan *v;
364 
365 	if (!(v = (struct rtnl_vlan *) rtnl_tc_data(TC_CAST(act))))
366 		return -NLE_NOMEM;
367 
368 	if (prio > 7)
369 		return -NLE_RANGE;
370 
371 	v->v_prio = prio;
372 	v->v_flags |= VLAN_F_PRIO;
373 
374 	return 0;
375 }
376 
377 /**
378  * Get vlan prio
379  * @arg act             vlan action
380  * @arg out_prio        the output vlan prio
381  * @return 0 if the vlan prio was returned or a negative error code.
382 */
rtnl_vlan_get_vlan_prio(struct rtnl_act * act,uint8_t * out_prio)383 int rtnl_vlan_get_vlan_prio(struct rtnl_act *act, uint8_t *out_prio)
384 {
385 	struct rtnl_vlan *v;
386 
387 	if (!(v = (struct rtnl_vlan *) rtnl_tc_data_peek(TC_CAST(act))))
388 		return -NLE_INVAL;
389 
390 	if (!(v->v_flags & VLAN_F_PRIO))
391 		return -NLE_MISSING_ATTR;
392 
393 	*out_prio = v->v_prio;
394 	return 0;
395 }
396 
397 /** @} */
398 
399 static struct rtnl_tc_ops vlan_ops = {
400 	.to_kind                = "vlan",
401 	.to_type                = RTNL_TC_TYPE_ACT,
402 	.to_size                = sizeof(struct rtnl_vlan),
403 	.to_msg_parser          = vlan_msg_parser,
404 	.to_free_data           = vlan_free_data,
405 	.to_clone               = NULL,
406 	.to_msg_fill            = vlan_msg_fill,
407 	.to_dump = {
408 	    [NL_DUMP_LINE]      = vlan_dump_line,
409 	    [NL_DUMP_DETAILS]   = vlan_dump_details,
410 	},
411 };
412 
vlan_init(void)413 static void _nl_init vlan_init(void)
414 {
415 	rtnl_tc_register(&vlan_ops);
416 }
417 
vlan_exit(void)418 static void _nl_exit vlan_exit(void)
419 {
420 	rtnl_tc_unregister(&vlan_ops);
421 }
422 
423 /** @} */
424