xref: /aosp_15_r20/external/libnl/lib/route/cls/flower.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * Copyright (c) 2018 Volodymyr Bendiuga <[email protected]>
4  */
5 
6 #include "nl-default.h"
7 
8 #include <linux/ethtool.h>
9 
10 #include <netlink/netlink.h>
11 #include <netlink/attr.h>
12 #include <netlink/utils.h>
13 #include <netlink/route/classifier.h>
14 #include <netlink/route/action.h>
15 #include <netlink/route/cls/flower.h>
16 
17 #include "tc-api.h"
18 #include "nl-aux-route/nl-route.h"
19 
20 /** @cond SKIP */
21 struct rtnl_flower {
22 	struct rtnl_act *cf_act;
23 	int cf_mask;
24 	uint32_t cf_flags;
25 	uint16_t cf_proto;
26 	uint16_t cf_vlan_id;
27 	uint16_t cf_vlan_ethtype;
28 	uint8_t cf_vlan_prio;
29 	uint8_t cf_src_mac[ETH_ALEN];
30 	uint8_t cf_src_mac_mask[ETH_ALEN];
31 	uint8_t cf_dst_mac[ETH_ALEN];
32 	uint8_t cf_dst_mac_mask[ETH_ALEN];
33 	in_addr_t cf_ipv4_src;
34 	in_addr_t cf_ipv4_src_mask;
35 	in_addr_t cf_ipv4_dst;
36 	in_addr_t cf_ipv4_dst_mask;
37 	uint8_t cf_ip_dscp;
38 	uint8_t cf_ip_dscp_mask;
39 };
40 
41 #define FLOWER_ATTR_FLAGS         (1 << 0)
42 #define FLOWER_ATTR_ACTION        (1 << 1)
43 #define FLOWER_ATTR_VLAN_ID       (1 << 2)
44 #define FLOWER_ATTR_VLAN_PRIO     (1 << 3)
45 #define FLOWER_ATTR_VLAN_ETH_TYPE (1 << 4)
46 #define FLOWER_ATTR_DST_MAC       (1 << 5)
47 #define FLOWER_ATTR_DST_MAC_MASK  (1 << 6)
48 #define FLOWER_ATTR_SRC_MAC       (1 << 7)
49 #define FLOWER_ATTR_SRC_MAC_MASK  (1 << 8)
50 #define FLOWER_ATTR_IP_DSCP       (1 << 9)
51 #define FLOWER_ATTR_IP_DSCP_MASK  (1 << 10)
52 #define FLOWER_ATTR_PROTO         (1 << 11)
53 #define FLOWER_ATTR_IPV4_SRC      (1 << 12)
54 #define FLOWER_ATTR_IPV4_SRC_MASK (1 << 13)
55 #define FLOWER_ATTR_IPV4_DST      (1 << 14)
56 #define FLOWER_ATTR_IPV4_DST_MASK (1 << 15)
57 /** @endcond */
58 
59 #define FLOWER_DSCP_MAX             0xe0
60 #define FLOWER_DSCP_MASK_MAX        0xe0
61 #define FLOWER_VID_MAX              4095
62 #define FLOWER_VLAN_PRIO_MAX        7
63 
64 static struct nla_policy flower_policy[TCA_FLOWER_MAX + 1] = {
65 	[TCA_FLOWER_FLAGS]             = { .type = NLA_U32 },
66 	[TCA_FLOWER_KEY_ETH_TYPE]      = { .type = NLA_U16 },
67 	[TCA_FLOWER_KEY_ETH_DST]       = { .maxlen = ETH_ALEN },
68 	[TCA_FLOWER_KEY_ETH_DST_MASK]  = { .maxlen = ETH_ALEN },
69 	[TCA_FLOWER_KEY_ETH_SRC]       = { .maxlen = ETH_ALEN },
70 	[TCA_FLOWER_KEY_ETH_SRC_MASK]  = { .maxlen = ETH_ALEN },
71 	[TCA_FLOWER_KEY_VLAN_ID]       = { .type = NLA_U16 },
72 	[TCA_FLOWER_KEY_VLAN_PRIO]     = { .type = NLA_U8 },
73 	[TCA_FLOWER_KEY_IP_TOS]        = { .type = NLA_U8 },
74 	[TCA_FLOWER_KEY_IP_TOS_MASK]   = { .type = NLA_U8 },
75 	[TCA_FLOWER_KEY_VLAN_ETH_TYPE] = { .type = NLA_U16 },
76 	[TCA_FLOWER_KEY_IPV4_SRC]      = { .type = NLA_U32 },
77 	[TCA_FLOWER_KEY_IPV4_SRC_MASK] = { .type = NLA_U32 },
78 	[TCA_FLOWER_KEY_IPV4_DST]      = { .type = NLA_U32 },
79 	[TCA_FLOWER_KEY_IPV4_DST_MASK] = { .type = NLA_U32 },
80 };
81 
flower_msg_parser(struct rtnl_tc * tc,void * data)82 static int flower_msg_parser(struct rtnl_tc *tc, void *data)
83 {
84 	struct rtnl_flower *f = data;
85 	struct nlattr *tb[TCA_FLOWER_MAX + 1];
86 	int err;
87 
88 	err = tca_parse(tb, TCA_FLOWER_MAX, tc, flower_policy);
89 	if (err < 0)
90 		return err;
91 
92 	if (tb[TCA_FLOWER_FLAGS]) {
93 		f->cf_flags = nla_get_u32(tb[TCA_FLOWER_FLAGS]);
94 		f->cf_mask |= FLOWER_ATTR_FLAGS;
95 	}
96 
97 	if (tb[TCA_FLOWER_ACT]) {
98 		err = rtnl_act_parse(&f->cf_act, tb[TCA_FLOWER_ACT]);
99 		if (err)
100 			return err;
101 
102 		f->cf_mask |= FLOWER_ATTR_ACTION;
103 	}
104 
105 	if (tb[TCA_FLOWER_KEY_ETH_TYPE]) {
106 		f->cf_proto = nla_get_u16(tb[TCA_FLOWER_KEY_ETH_TYPE]);
107 		f->cf_mask |= FLOWER_ATTR_PROTO;
108 	}
109 
110 	if (tb[TCA_FLOWER_KEY_VLAN_ID]) {
111 		f->cf_vlan_id = nla_get_u16(tb[TCA_FLOWER_KEY_VLAN_ID]);
112 		f->cf_mask |= FLOWER_ATTR_VLAN_ID;
113 	}
114 
115 	if (tb[TCA_FLOWER_KEY_VLAN_PRIO]) {
116 		f->cf_vlan_prio = nla_get_u8(tb[TCA_FLOWER_KEY_VLAN_PRIO]);
117 		f->cf_mask |= FLOWER_ATTR_VLAN_PRIO;
118 	}
119 
120 	if (tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]) {
121 		f->cf_vlan_ethtype = nla_get_u16(tb[TCA_FLOWER_KEY_VLAN_ETH_TYPE]);
122 		f->cf_mask |= FLOWER_ATTR_VLAN_ETH_TYPE;
123 	}
124 
125 	if (tb[TCA_FLOWER_KEY_ETH_DST]) {
126 		nla_memcpy(f->cf_dst_mac, tb[TCA_FLOWER_KEY_ETH_DST], ETH_ALEN);
127 		f->cf_mask |= FLOWER_ATTR_DST_MAC;
128 	}
129 
130 	if (tb[TCA_FLOWER_KEY_ETH_DST_MASK]) {
131 		nla_memcpy(f->cf_dst_mac_mask, tb[TCA_FLOWER_KEY_ETH_DST_MASK], ETH_ALEN);
132 		f->cf_mask |= FLOWER_ATTR_DST_MAC_MASK;
133 	}
134 
135 	if (tb[TCA_FLOWER_KEY_ETH_SRC]) {
136 		nla_memcpy(f->cf_src_mac, tb[TCA_FLOWER_KEY_ETH_SRC], ETH_ALEN);
137 		f->cf_mask |= FLOWER_ATTR_SRC_MAC;
138 	}
139 
140 	if (tb[TCA_FLOWER_KEY_ETH_SRC_MASK]) {
141 		nla_memcpy(f->cf_src_mac_mask, tb[TCA_FLOWER_KEY_ETH_SRC_MASK], ETH_ALEN);
142 		f->cf_mask |= FLOWER_ATTR_SRC_MAC_MASK;
143 	}
144 
145 	if (tb[TCA_FLOWER_KEY_IP_TOS]) {
146 		f->cf_ip_dscp = nla_get_u8(tb[TCA_FLOWER_KEY_IP_TOS]);
147 		f->cf_mask |= FLOWER_ATTR_IP_DSCP;
148 	}
149 
150 	if (tb[TCA_FLOWER_KEY_IP_TOS_MASK]) {
151 		f->cf_ip_dscp_mask = nla_get_u8(tb[TCA_FLOWER_KEY_IP_TOS_MASK]);
152 		f->cf_mask |= FLOWER_ATTR_IP_DSCP_MASK;
153 	}
154 
155 	if (tb[TCA_FLOWER_KEY_IPV4_SRC]) {
156 		f->cf_ipv4_src = nla_get_u32(tb[TCA_FLOWER_KEY_IPV4_SRC]);
157 		f->cf_mask |= FLOWER_ATTR_IPV4_SRC;
158 	}
159 
160 	if (tb[TCA_FLOWER_KEY_IPV4_SRC_MASK]) {
161 		f->cf_ipv4_src_mask =
162 			nla_get_u32(tb[TCA_FLOWER_KEY_IPV4_SRC_MASK]);
163 		f->cf_mask |= FLOWER_ATTR_IPV4_SRC_MASK;
164 	}
165 
166 	if (tb[TCA_FLOWER_KEY_IPV4_DST]) {
167 		f->cf_ipv4_dst = nla_get_u32(tb[TCA_FLOWER_KEY_IPV4_DST]);
168 		f->cf_mask |= FLOWER_ATTR_IPV4_DST;
169 	}
170 
171 	if (tb[TCA_FLOWER_KEY_IPV4_DST_MASK]) {
172 		f->cf_ipv4_dst_mask =
173 			nla_get_u32(tb[TCA_FLOWER_KEY_IPV4_DST_MASK]);
174 		f->cf_mask |= FLOWER_ATTR_IPV4_DST_MASK;
175 	}
176 
177 	return 0;
178 }
179 
flower_msg_fill(struct rtnl_tc * tc,void * data,struct nl_msg * msg)180 static int flower_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
181 {
182 	struct rtnl_flower *f = data;
183 	int err;
184 
185 	if (!f)
186 		return 0;
187 
188 	if (f->cf_mask & FLOWER_ATTR_FLAGS)
189 		NLA_PUT_U32(msg, TCA_FLOWER_FLAGS, f->cf_flags);
190 
191 	if (f->cf_mask & FLOWER_ATTR_ACTION) {
192 		err = rtnl_act_fill(msg, TCA_FLOWER_ACT, f->cf_act);
193 		if (err)
194 			return err;
195 	}
196 
197 	if (f->cf_mask & FLOWER_ATTR_PROTO)
198 		NLA_PUT_U16(msg, TCA_FLOWER_KEY_ETH_TYPE, f->cf_proto);
199 
200 	if (f->cf_mask & FLOWER_ATTR_VLAN_ID)
201 		NLA_PUT_U16(msg, TCA_FLOWER_KEY_VLAN_ID, f->cf_vlan_id);
202 
203 	if (f->cf_mask & FLOWER_ATTR_VLAN_PRIO)
204 		NLA_PUT_U8(msg, TCA_FLOWER_KEY_VLAN_PRIO, f->cf_vlan_prio);
205 
206 	if (f->cf_mask & FLOWER_ATTR_VLAN_ETH_TYPE)
207 		NLA_PUT_U16(msg, TCA_FLOWER_KEY_VLAN_ETH_TYPE, f->cf_vlan_ethtype);
208 
209 	if (f->cf_mask & FLOWER_ATTR_DST_MAC)
210 		NLA_PUT(msg, TCA_FLOWER_KEY_ETH_DST, ETH_ALEN, f->cf_dst_mac);
211 
212 	if (f->cf_mask & FLOWER_ATTR_DST_MAC_MASK)
213 		NLA_PUT(msg, TCA_FLOWER_KEY_ETH_DST_MASK, ETH_ALEN, f->cf_dst_mac_mask);
214 
215 	if (f->cf_mask & FLOWER_ATTR_SRC_MAC)
216 		NLA_PUT(msg, TCA_FLOWER_KEY_ETH_SRC, ETH_ALEN, f->cf_src_mac);
217 
218 	if (f->cf_mask & FLOWER_ATTR_SRC_MAC_MASK)
219 		NLA_PUT(msg, TCA_FLOWER_KEY_ETH_SRC_MASK, ETH_ALEN, f->cf_src_mac_mask);
220 
221 	if (f->cf_mask & FLOWER_ATTR_IP_DSCP)
222 		NLA_PUT_U8(msg, TCA_FLOWER_KEY_IP_TOS, f->cf_ip_dscp);
223 
224 	if (f->cf_mask & FLOWER_ATTR_IP_DSCP_MASK)
225 		NLA_PUT_U8(msg, TCA_FLOWER_KEY_IP_TOS_MASK, f->cf_ip_dscp_mask);
226 
227 	if (f->cf_mask & FLOWER_ATTR_IPV4_SRC)
228 		NLA_PUT_U32(msg, TCA_FLOWER_KEY_IPV4_SRC, f->cf_ipv4_src);
229 
230 	if (f->cf_mask & FLOWER_ATTR_IPV4_SRC_MASK)
231 		NLA_PUT_U32(msg, TCA_FLOWER_KEY_IPV4_SRC_MASK,
232 			    f->cf_ipv4_src_mask);
233 
234 	if (f->cf_mask & FLOWER_ATTR_IPV4_DST)
235 		NLA_PUT_U32(msg, TCA_FLOWER_KEY_IPV4_DST, f->cf_ipv4_dst);
236 
237 	if (f->cf_mask & FLOWER_ATTR_IPV4_DST_MASK)
238 		NLA_PUT_U32(msg, TCA_FLOWER_KEY_IPV4_DST_MASK,
239 			    f->cf_ipv4_dst_mask);
240 
241 	return 0;
242 
243 nla_put_failure:
244 	return -NLE_NOMEM;
245 }
246 
flower_free_data(struct rtnl_tc * tc,void * data)247 static void flower_free_data(struct rtnl_tc *tc, void *data)
248 {
249 	struct rtnl_flower *f = data;
250 
251 	if (f->cf_act)
252 		rtnl_act_put_all(&f->cf_act);
253 }
254 
flower_clone(void * _dst,void * _src)255 static int flower_clone(void *_dst, void *_src)
256 {
257 	struct rtnl_flower *dst = _dst, *src = _src;
258 
259 	if (src->cf_act) {
260 		if (!(dst->cf_act = rtnl_act_alloc()))
261 			return -NLE_NOMEM;
262 
263 		memcpy(dst->cf_act, src->cf_act, sizeof(struct rtnl_act));
264 
265 		/* action nl list next and prev pointers must be updated */
266 		nl_init_list_head(&dst->cf_act->ce_list);
267 
268 		if (   src->cf_act->c_opts
269 		    && !(dst->cf_act->c_opts = nl_data_clone(src->cf_act->c_opts)))
270 			return -NLE_NOMEM;
271 
272 		if (   src->cf_act->c_xstats
273 		    && !(dst->cf_act->c_xstats = nl_data_clone(src->cf_act->c_xstats)))
274 			return -NLE_NOMEM;
275 
276 		if (   src->cf_act->c_subdata
277 		    && !(dst->cf_act->c_subdata = nl_data_clone(src->cf_act->c_subdata)))
278 			return -NLE_NOMEM;
279 
280 		if (dst->cf_act->c_link) {
281 			nl_object_get(OBJ_CAST(dst->cf_act->c_link));
282 		}
283 
284 		dst->cf_act->a_next = NULL;   /* Only clone first in chain */
285 	}
286 
287 	return 0;
288 }
289 
flower_dump_details(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)290 static void flower_dump_details(struct rtnl_tc *tc, void *data,
291                                 struct nl_dump_params *p)
292 {
293 	struct rtnl_flower *f = data;
294 	char addr_str[INET_ADDRSTRLEN];
295 	char mask_str[INET_ADDRSTRLEN];
296 
297 	if (!f)
298 		return;
299 
300 	if (f->cf_mask & FLOWER_ATTR_FLAGS)
301 		nl_dump(p, " flags %u", f->cf_flags);
302 
303 	if (f->cf_mask & FLOWER_ATTR_PROTO)
304 		nl_dump(p, " protocol %u", f->cf_proto);
305 
306 	if (f->cf_mask & FLOWER_ATTR_VLAN_ID)
307 		nl_dump(p, " vlan_id %u", f->cf_vlan_id);
308 
309 	if (f->cf_mask & FLOWER_ATTR_VLAN_PRIO)
310 		nl_dump(p, " vlan_prio %u", f->cf_vlan_prio);
311 
312 	if (f->cf_mask & FLOWER_ATTR_VLAN_ETH_TYPE)
313 		nl_dump(p, " vlan_ethtype %u", f->cf_vlan_ethtype);
314 
315 	if (f->cf_mask & FLOWER_ATTR_DST_MAC)
316 		nl_dump(p, " dst_mac %02x:%02x:%02x:%02x:%02x:%02x",
317 		        f->cf_dst_mac[0], f->cf_dst_mac[1],
318 		        f->cf_dst_mac[2], f->cf_dst_mac[3],
319 		        f->cf_dst_mac[4], f->cf_dst_mac[5]);
320 
321 	if (f->cf_mask & FLOWER_ATTR_DST_MAC_MASK)
322 		nl_dump(p, " dst_mac_mask %02x:%02x:%02x:%02x:%02x:%02x",
323 		        f->cf_dst_mac_mask[0], f->cf_dst_mac_mask[1],
324 		        f->cf_dst_mac_mask[2], f->cf_dst_mac_mask[3],
325 		        f->cf_dst_mac_mask[4], f->cf_dst_mac_mask[5]);
326 
327 	if (f->cf_mask & FLOWER_ATTR_SRC_MAC)
328 		nl_dump(p, " src_mac %02x:%02x:%02x:%02x:%02x:%02x",
329 		        f->cf_src_mac[0], f->cf_src_mac[1],
330 		        f->cf_src_mac[2], f->cf_src_mac[3],
331 		        f->cf_src_mac[4], f->cf_src_mac[5]);
332 
333 	if (f->cf_mask & FLOWER_ATTR_SRC_MAC_MASK)
334 		nl_dump(p, " src_mac_mask %02x:%02x:%02x:%02x:%02x:%02x",
335 		        f->cf_src_mac_mask[0], f->cf_src_mac_mask[1],
336 		        f->cf_src_mac_mask[2], f->cf_src_mac_mask[3],
337 		        f->cf_src_mac_mask[4], f->cf_src_mac_mask[5]);
338 
339 	if (f->cf_mask & FLOWER_ATTR_IP_DSCP)
340 		nl_dump(p, " dscp %u", f->cf_ip_dscp);
341 
342 	if (f->cf_mask & FLOWER_ATTR_IP_DSCP_MASK)
343 		nl_dump(p, " dscp_mask %u", f->cf_ip_dscp_mask);
344 
345 	if (f->cf_mask & FLOWER_ATTR_IPV4_SRC) {
346 		inet_ntop(AF_INET, &f->cf_ipv4_src, addr_str, sizeof(addr_str));
347 		inet_ntop(AF_INET, &f->cf_ipv4_src_mask, mask_str, sizeof(mask_str));
348 		nl_dump(p, "IPv4 src %s mask %s\n", addr_str, mask_str);
349 	}
350 
351 	if (f->cf_mask & FLOWER_ATTR_IPV4_DST) {
352 		inet_ntop(AF_INET, &f->cf_ipv4_dst, addr_str, sizeof(addr_str));
353 		inet_ntop(AF_INET, &f->cf_ipv4_dst_mask, mask_str, sizeof(mask_str));
354 		nl_dump(p, "IPv4 dst %s mask %s\n", addr_str, mask_str);
355 	}
356 }
357 
358 /**
359  * @name Attribute Modification
360  * @{
361  */
362 
363 /**
364  * Set protocol for flower classifier
365  * @arg cls		Flower classifier.
366  * @arg proto		protocol (ETH_P_*)
367  * @return 0 on success or a negative error code.
368  */
rtnl_flower_set_proto(struct rtnl_cls * cls,uint16_t proto)369 int rtnl_flower_set_proto(struct rtnl_cls *cls, uint16_t proto)
370 {
371 	struct rtnl_flower *f;
372 
373 	if (!(f = rtnl_tc_data(TC_CAST(cls))))
374 		return -NLE_NOMEM;
375 
376 	f->cf_proto = htons(proto);
377 	f->cf_mask |= FLOWER_ATTR_PROTO;
378 
379 	return 0;
380 }
381 
382 /**
383  * Get protocol for flower classifier
384  * @arg cls		Flower classifier.
385  * @arg proto		protocol
386  * @return 0 on success or a negative error code.
387 */
rtnl_flower_get_proto(struct rtnl_cls * cls,uint16_t * proto)388 int rtnl_flower_get_proto(struct rtnl_cls *cls, uint16_t *proto)
389 {
390 	struct rtnl_flower *f;
391 
392 	if (!(f = rtnl_tc_data_peek(TC_CAST(cls))))
393 		return -NLE_INVAL;
394 
395 	if (!(f->cf_mask & FLOWER_ATTR_PROTO))
396 		return -NLE_MISSING_ATTR;
397 
398 	*proto = ntohs(f->cf_proto);
399 
400 	return 0;
401 }
402 
403 /**
404  * Set vlan id for flower classifier
405  * @arg cls		Flower classifier.
406  * @arg vid		vlan id
407  * @return 0 on success or a negative error code.
408  */
rtnl_flower_set_vlan_id(struct rtnl_cls * cls,uint16_t vid)409 int rtnl_flower_set_vlan_id(struct rtnl_cls *cls, uint16_t vid)
410 {
411 	struct rtnl_flower *f;
412 
413 	if (!(f = rtnl_tc_data(TC_CAST(cls))))
414 		return -NLE_NOMEM;
415 
416 	if (vid > FLOWER_VID_MAX)
417 		return -NLE_RANGE;
418 
419 	f->cf_vlan_id = vid;
420 	f->cf_mask |= FLOWER_ATTR_VLAN_ID;
421 
422 	return 0;
423 }
424 
425 /**
426  * Get vlan id for flower classifier
427  * @arg cls		Flower classifier.
428  * @arg vid		vlan id
429  * @return 0 on success or a negative error code.
430 */
rtnl_flower_get_vlan_id(struct rtnl_cls * cls,uint16_t * vid)431 int rtnl_flower_get_vlan_id(struct rtnl_cls *cls, uint16_t *vid)
432 {
433 	struct rtnl_flower *f;
434 
435 	if (!(f = rtnl_tc_data_peek(TC_CAST(cls))))
436 		return -NLE_INVAL;
437 
438 	if (!(f->cf_mask & FLOWER_ATTR_VLAN_ID))
439 		return -NLE_MISSING_ATTR;
440 
441 	*vid = f->cf_vlan_id;
442 
443 	return 0;
444 }
445 
446 /**
447  * Set vlan priority for flower classifier
448  * @arg cls		Flower classifier.
449  * @arg prio		vlan priority
450  * @return 0 on success or a negative error code.
451  */
rtnl_flower_set_vlan_prio(struct rtnl_cls * cls,uint8_t prio)452 int rtnl_flower_set_vlan_prio(struct rtnl_cls *cls, uint8_t prio)
453 {
454 	struct rtnl_flower *f;
455 
456 	if (!(f = rtnl_tc_data(TC_CAST(cls))))
457 		return -NLE_NOMEM;
458 
459 	if (prio > FLOWER_VLAN_PRIO_MAX)
460 		return -NLE_RANGE;
461 
462 	f->cf_vlan_prio = prio;
463 	f->cf_mask |= FLOWER_ATTR_VLAN_PRIO;
464 
465 	return 0;
466 }
467 
468 /**
469  * Get vlan prio for flower classifier
470  * @arg cls		Flower classifier.
471  * @arg prio		vlan priority
472  * @return 0 on success or a negative error code.
473 */
rtnl_flower_get_vlan_prio(struct rtnl_cls * cls,uint8_t * prio)474 int rtnl_flower_get_vlan_prio(struct rtnl_cls *cls, uint8_t *prio)
475 {
476 	struct rtnl_flower *f;
477 
478 	if (!(f = rtnl_tc_data_peek(TC_CAST(cls))))
479 		return -NLE_INVAL;
480 
481 	if (!(f->cf_mask & FLOWER_ATTR_VLAN_PRIO))
482 		return -NLE_MISSING_ATTR;
483 
484 	*prio = f->cf_vlan_prio;
485 
486 	return 0;
487 }
488 
489 /**
490  * Set vlan ethertype for flower classifier
491  * @arg cls		Flower classifier.
492  * @arg ethtype		vlan ethertype
493  * @return 0 on success or a negative error code.
494  */
rtnl_flower_set_vlan_ethtype(struct rtnl_cls * cls,uint16_t ethtype)495 int rtnl_flower_set_vlan_ethtype(struct rtnl_cls *cls, uint16_t ethtype)
496 {
497 	struct rtnl_flower *f;
498 
499 	if (!(f = rtnl_tc_data(TC_CAST(cls))))
500 		return -NLE_NOMEM;
501 
502 	if (!(f->cf_mask & FLOWER_ATTR_PROTO))
503 		return -NLE_MISSING_ATTR;
504 
505 	if (f->cf_proto != htons(ETH_P_8021Q))
506 		return -NLE_INVAL;
507 
508 	f->cf_vlan_ethtype = htons(ethtype);
509 	f->cf_mask |= FLOWER_ATTR_VLAN_ETH_TYPE;
510 
511 	return 0;
512 }
513 
514 /**
515  * Set destination mac address for flower classifier
516  * @arg cls		Flower classifier.
517  * @arg mac		destination mac address
518  * @arg mask		mask for mac address
519  * @return 0 on success or a negative error code.
520  */
rtnl_flower_set_dst_mac(struct rtnl_cls * cls,unsigned char * mac,unsigned char * mask)521 int rtnl_flower_set_dst_mac(struct rtnl_cls *cls, unsigned char *mac,
522                             unsigned char *mask)
523 {
524 	struct rtnl_flower *f;
525 
526 	if (!(f = rtnl_tc_data(TC_CAST(cls))))
527 		return -NLE_NOMEM;
528 
529 	if (mac) {
530 		memcpy(f->cf_dst_mac, mac, ETH_ALEN);
531 		f->cf_mask |= FLOWER_ATTR_DST_MAC;
532 
533 		if (mask) {
534 			memcpy(f->cf_dst_mac_mask, mask, ETH_ALEN);
535 			f->cf_mask |= FLOWER_ATTR_DST_MAC_MASK;
536 		}
537 
538 		return 0;
539 	}
540 
541 	return -NLE_FAILURE;
542 }
543 
544 /**
545  * Get destination mac address for flower classifier
546  * @arg cls		Flower classifier.
547  * @arg mac		destination mac address
548  * @arg mask		mask for mac address
549  * @return 0 on success or a negative error code.
550 */
rtnl_flower_get_dst_mac(struct rtnl_cls * cls,unsigned char * mac,unsigned char * mask)551 int rtnl_flower_get_dst_mac(struct rtnl_cls *cls, unsigned char *mac,
552                             unsigned char *mask)
553 {
554 	struct rtnl_flower *f;
555 
556 	if (!(f = rtnl_tc_data_peek(TC_CAST(cls))))
557 		return -NLE_INVAL;
558 
559 	if (!(f->cf_mask & FLOWER_ATTR_DST_MAC))
560 		return -NLE_MISSING_ATTR;
561 
562 	if (mac)
563 		memcpy(mac, f->cf_dst_mac, ETH_ALEN);
564 
565 	if (mask)
566 		memcpy(mask, f->cf_dst_mac_mask, ETH_ALEN);
567 
568 	return 0;
569 }
570 
571 /**
572  * Set source mac address for flower classifier
573  * @arg cls		Flower classifier.
574  * @arg mac		source mac address
575  * @arg mask		mask for mac address
576  * @return 0 on success or a negative error code.
577  */
rtnl_flower_set_src_mac(struct rtnl_cls * cls,unsigned char * mac,unsigned char * mask)578 int rtnl_flower_set_src_mac(struct rtnl_cls *cls, unsigned char *mac,
579                             unsigned char *mask)
580 {
581 	struct rtnl_flower *f;
582 
583 	if (!(f = rtnl_tc_data(TC_CAST(cls))))
584 		return -NLE_NOMEM;
585 
586 	if (mac) {
587 		memcpy(f->cf_src_mac, mac, ETH_ALEN);
588 		f->cf_mask |= FLOWER_ATTR_SRC_MAC;
589 
590 		if (mask) {
591 			memcpy(f->cf_src_mac_mask, mask, ETH_ALEN);
592 			f->cf_mask |= FLOWER_ATTR_SRC_MAC_MASK;
593 		}
594 
595 		return 0;
596 	}
597 
598 	return -NLE_FAILURE;
599 }
600 
601 /**
602  * Get source mac address for flower classifier
603  * @arg cls		Flower classifier.
604  * @arg mac		source mac address
605  * @arg mask		mask for mac address
606  * @return 0 on success or a negative error code.
607 */
rtnl_flower_get_src_mac(struct rtnl_cls * cls,unsigned char * mac,unsigned char * mask)608 int rtnl_flower_get_src_mac(struct rtnl_cls *cls, unsigned char *mac,
609                             unsigned char *mask)
610 {
611 	struct rtnl_flower *f;
612 
613 	if (!(f = rtnl_tc_data_peek(TC_CAST(cls))))
614 		return -NLE_INVAL;
615 
616 	if (!(f->cf_mask & FLOWER_ATTR_SRC_MAC))
617 		return -NLE_MISSING_ATTR;
618 
619 	if (mac)
620 		memcpy(mac, f->cf_src_mac, ETH_ALEN);
621 
622 	if (mask)
623 		memcpy(mask, f->cf_src_mac_mask, ETH_ALEN);
624 
625 	return 0;
626 }
627 
628 /**
629  * Set dscp value for flower classifier
630  * @arg cls		Flower classifier.
631  * @arg dscp		dscp value
632  * @arg mask		mask for dscp value
633  * @return 0 on success or a negative error code.
634  */
rtnl_flower_set_ip_dscp(struct rtnl_cls * cls,uint8_t dscp,uint8_t mask)635 int rtnl_flower_set_ip_dscp(struct rtnl_cls *cls, uint8_t dscp, uint8_t mask)
636 {
637 	struct rtnl_flower *f;
638 
639 	if (!(f = rtnl_tc_data(TC_CAST(cls))))
640 		return -NLE_NOMEM;
641 
642 	if (dscp > FLOWER_DSCP_MAX)
643 		return -NLE_RANGE;
644 
645 	if (mask > FLOWER_DSCP_MASK_MAX)
646 		return -NLE_RANGE;
647 
648 	f->cf_ip_dscp = dscp;
649 	f->cf_mask |= FLOWER_ATTR_IP_DSCP;
650 
651 	if (mask) {
652 		f->cf_ip_dscp_mask = mask;
653 		f->cf_mask |= FLOWER_ATTR_IP_DSCP_MASK;
654 	}
655 
656 	return 0;
657 }
658 
659 /**
660  * Get dscp value for flower classifier
661  * @arg cls		Flower classifier.
662  * @arg dscp		dscp value
663  * @arg mask		mask for dscp value
664  * @return 0 on success or a negative error code.
665 */
rtnl_flower_get_ip_dscp(struct rtnl_cls * cls,uint8_t * dscp,uint8_t * mask)666 int rtnl_flower_get_ip_dscp(struct rtnl_cls *cls, uint8_t *dscp, uint8_t *mask)
667 {
668 	struct rtnl_flower *f;
669 
670 	if (!(f = rtnl_tc_data_peek(TC_CAST(cls))))
671 		return -NLE_INVAL;
672 
673 	if (!(f->cf_mask & FLOWER_ATTR_IP_DSCP))
674 		return -NLE_MISSING_ATTR;
675 
676 	*dscp = f->cf_ip_dscp;
677 	*mask = f->cf_ip_dscp_mask;
678 
679 	return 0;
680 }
681 
682 /**
683  * Set IPv4 source address for flower classifier
684  * @arg cls		Flower classifier.
685  * @arg addr		IPv4 source address
686  * @arg mask		mask for IPv4 source address
687  * @return 0 on success or a negative error code.
688  */
rtnl_flower_set_ipv4_src(struct rtnl_cls * cls,in_addr_t addr,in_addr_t mask)689 int rtnl_flower_set_ipv4_src(struct rtnl_cls *cls, in_addr_t addr,
690 			     in_addr_t mask)
691 {
692 	struct rtnl_flower *f;
693 
694 	if (!(f = rtnl_tc_data(TC_CAST(cls))))
695 		return -NLE_NOMEM;
696 
697 	if (addr) {
698 		f->cf_ipv4_src = addr;
699 		f->cf_mask |= FLOWER_ATTR_IPV4_SRC;
700 
701 		if (mask) {
702 			f->cf_ipv4_src_mask = mask;
703 			f->cf_mask |= FLOWER_ATTR_IPV4_SRC_MASK;
704 		}
705 
706 		return 0;
707 	}
708 
709 	return -NLE_FAILURE;
710 }
711 
712 /**
713  * Get IPv4 source address for flower classifier
714  * @arg cls		Flower classifier.
715  * @arg addr		IPv4 source address
716  * @arg mask		mask for IPv4 source address
717  * @return 0 on success or a negative error code.
718  */
rtnl_flower_get_ipv4_src(struct rtnl_cls * cls,in_addr_t * out_addr,in_addr_t * out_mask)719 int rtnl_flower_get_ipv4_src(struct rtnl_cls *cls, in_addr_t *out_addr,
720 			     in_addr_t *out_mask)
721 {
722 	struct rtnl_flower *f;
723 
724 	if (!(f = rtnl_tc_data_peek(TC_CAST(cls))))
725 		return -NLE_INVAL;
726 
727 	if (!(f->cf_mask & FLOWER_ATTR_IPV4_SRC))
728 		return -NLE_MISSING_ATTR;
729 
730 	if (out_addr)
731 		*out_addr = f->cf_ipv4_src;
732 
733 	if (out_mask) {
734 		if (f->cf_mask & FLOWER_ATTR_IPV4_SRC_MASK)
735 			*out_mask = f->cf_ipv4_src_mask;
736 		else
737 			*out_mask = 0xffffffff;
738 	}
739 
740 	return 0;
741 }
742 
743 /**
744  * Set IPv4 destination address for flower classifier
745  * @arg cls		Flower classifier.
746  * @arg addr		IPv4 destination address
747  * @arg mask		mask for IPv4 destination address
748  * @return 0 on success or a negative error code.
749  */
rtnl_flower_set_ipv4_dst(struct rtnl_cls * cls,in_addr_t addr,in_addr_t mask)750 int rtnl_flower_set_ipv4_dst(struct rtnl_cls *cls, in_addr_t addr,
751 			     in_addr_t mask)
752 {
753 	struct rtnl_flower *f;
754 
755 	if (!(f = rtnl_tc_data(TC_CAST(cls))))
756 		return -NLE_NOMEM;
757 
758 	if (addr) {
759 		f->cf_ipv4_dst = addr;
760 		f->cf_mask |= FLOWER_ATTR_IPV4_DST;
761 
762 		if (mask) {
763 			f->cf_ipv4_dst_mask = mask;
764 			f->cf_mask |= FLOWER_ATTR_IPV4_DST_MASK;
765 		}
766 
767 		return 0;
768 	}
769 
770 	return -NLE_FAILURE;
771 }
772 
773 /**
774  * Get IPv4 destination address for flower classifier
775  * @arg cls		Flower classifier.
776  * @arg addr		IPv4 destination address
777  * @arg mask		mask for IPv4 destination address
778  * @return 0 on success or a negative error code.
779  */
rtnl_flower_get_ipv4_dst(struct rtnl_cls * cls,in_addr_t * out_addr,in_addr_t * out_mask)780 int rtnl_flower_get_ipv4_dst(struct rtnl_cls *cls, in_addr_t *out_addr,
781 			     in_addr_t *out_mask)
782 {
783 	struct rtnl_flower *f;
784 
785 	if (!(f = rtnl_tc_data_peek(TC_CAST(cls))))
786 		return -NLE_INVAL;
787 
788 	if (!(f->cf_mask & FLOWER_ATTR_IPV4_DST))
789 		return -NLE_MISSING_ATTR;
790 
791 	if (out_addr)
792 		*out_addr = f->cf_ipv4_dst;
793 
794 	if (out_mask) {
795 		if (f->cf_mask & FLOWER_ATTR_IPV4_DST_MASK)
796 			*out_mask = f->cf_ipv4_dst_mask;
797 		else
798 			*out_mask = 0xffffffff;
799 	}
800 
801 	return 0;
802 }
803 
804 /**
805  * Append action for flower classifier
806  * @arg cls		Flower classifier.
807  * @arg act		action to append
808  * @return 0 on success or a negative error code.
809  */
rtnl_flower_append_action(struct rtnl_cls * cls,struct rtnl_act * act)810 int rtnl_flower_append_action(struct rtnl_cls *cls, struct rtnl_act *act)
811 {
812 	struct rtnl_flower *f;
813 	int err;
814 
815 	if (!act)
816 		return 0;
817 
818 	if (!(f = rtnl_tc_data(TC_CAST(cls))))
819 		return -NLE_NOMEM;
820 
821 	if ((err = _rtnl_act_append_get(&f->cf_act, act)) < 0)
822 		return err;
823 
824 	f->cf_mask |= FLOWER_ATTR_ACTION;
825 	return 0;
826 }
827 
828 /**
829  * Delete action from flower classifier
830  * @arg cls		Flower classifier.
831  * @arg act		action to delete
832  * @return 0 on success or a negative error code.
833  */
rtnl_flower_del_action(struct rtnl_cls * cls,struct rtnl_act * act)834 int rtnl_flower_del_action(struct rtnl_cls *cls, struct rtnl_act *act)
835 {
836 	struct rtnl_flower *f;
837 	int ret;
838 
839 	if (!act)
840 		return 0;
841 
842 	if (!(f = rtnl_tc_data(TC_CAST(cls))))
843 		return -NLE_NOMEM;
844 
845 	if (!(f->cf_mask & FLOWER_ATTR_ACTION))
846 		return -NLE_INVAL;
847 
848 	ret = rtnl_act_remove(&f->cf_act, act);
849 	if (ret)
850 		return ret;
851 
852 	if (!f->cf_act)
853 		f->cf_mask &= ~FLOWER_ATTR_ACTION;
854 	rtnl_act_put(act);
855 
856 	return 0;
857 }
858 
859 /**
860  * Get action from flower classifier
861  * @arg cls		Flower classifier.
862  * @return action on success or NULL on error.
863  */
rtnl_flower_get_action(struct rtnl_cls * cls)864 struct rtnl_act* rtnl_flower_get_action(struct rtnl_cls *cls)
865 {
866 	struct rtnl_flower *f;
867 
868 	if (!(f = rtnl_tc_data_peek(TC_CAST(cls))))
869 		return NULL;
870 
871 	if (!(f->cf_mask & FLOWER_ATTR_ACTION))
872 		return NULL;
873 
874 	rtnl_act_get(f->cf_act);
875 
876 	return f->cf_act;
877 }
878 
879 /**
880  * Set flags for flower classifier
881  * @arg cls		Flower classifier.
882  * @arg flags		(TCA_CLS_FLAGS_SKIP_HW | TCA_CLS_FLAGS_SKIP_SW)
883  * @return 0 on success or a negative error code.
884  */
rtnl_flower_set_flags(struct rtnl_cls * cls,int flags)885 int rtnl_flower_set_flags(struct rtnl_cls *cls, int flags)
886 {
887 	struct rtnl_flower *f;
888 
889 	if (!(f = rtnl_tc_data(TC_CAST(cls))))
890 		return -NLE_NOMEM;
891 
892 	f->cf_flags = flags;
893 	f->cf_mask |= FLOWER_ATTR_FLAGS;
894 
895 	return 0;
896 }
897 
898 /** @} */
899 
900 static struct rtnl_tc_ops flower_ops = {
901 	.to_kind                = "flower",
902 	.to_type                = RTNL_TC_TYPE_CLS,
903 	.to_size                = sizeof(struct rtnl_flower),
904 	.to_msg_parser          = flower_msg_parser,
905 	.to_free_data           = flower_free_data,
906 	.to_clone               = flower_clone,
907 	.to_msg_fill            = flower_msg_fill,
908 	.to_dump = {
909 	    [NL_DUMP_DETAILS]   = flower_dump_details,
910 	},
911 };
912 
flower_init(void)913 static void _nl_init flower_init(void)
914 {
915 	rtnl_tc_register(&flower_ops);
916 }
917 
flower_exit(void)918 static void _nl_exit flower_exit(void)
919 {
920 	rtnl_tc_unregister(&flower_ops);
921 }
922