xref: /aosp_15_r20/external/libnl/lib/route/cls/u32.c (revision 4dc78e53d49367fa8e61b07018507c90983a077d)
1 /* SPDX-License-Identifier: LGPL-2.1-only */
2 /*
3  * Copyright (c) 2003-2013 Thomas Graf <[email protected]>
4  * Copyright (c) 2005-2006 Petr Gotthard <[email protected]>
5  * Copyright (c) 2005-2006 Siemens AG Oesterreich
6  */
7 
8 /**
9  * @ingroup cls
10  * @defgroup cls_u32 Universal 32-bit Classifier
11  *
12  * @{
13  */
14 
15 #include "nl-default.h"
16 
17 #include <netlink/netlink.h>
18 #include <netlink/attr.h>
19 #include <netlink/utils.h>
20 #include <netlink/route/classifier.h>
21 #include <netlink/route/cls/u32.h>
22 #include <netlink/route/action.h>
23 
24 #include "tc-api.h"
25 #include "nl-aux-route/nl-route.h"
26 
27 /** @cond SKIP */
28 struct rtnl_u32 {
29 	uint32_t cu_divisor;
30 	uint32_t cu_hash;
31 	uint32_t cu_classid;
32 	uint32_t cu_link;
33 	struct nl_data *cu_pcnt;
34 	struct nl_data *cu_selector;
35 	struct nl_data *cu_mark;
36 	struct rtnl_act *cu_act;
37 	struct nl_data *cu_police;
38 	char cu_indev[IFNAMSIZ];
39 	int cu_mask;
40 };
41 
42 #define U32_ATTR_DIVISOR      0x001
43 #define U32_ATTR_HASH         0x002
44 #define U32_ATTR_CLASSID      0x004
45 #define U32_ATTR_LINK         0x008
46 #define U32_ATTR_PCNT         0x010
47 #define U32_ATTR_SELECTOR     0x020
48 #define U32_ATTR_ACTION       0x040
49 #define U32_ATTR_POLICE       0x080
50 #define U32_ATTR_INDEV        0x100
51 #define U32_ATTR_MARK	      0x200
52 /** @endcond */
53 
u32_selector(struct rtnl_u32 * u)54 static inline struct tc_u32_sel *u32_selector(struct rtnl_u32 *u)
55 {
56 	return (struct tc_u32_sel *) u->cu_selector->d_data;
57 }
58 
u32_selector_alloc(struct rtnl_u32 * u)59 static inline struct tc_u32_sel *u32_selector_alloc(struct rtnl_u32 *u)
60 {
61 	if (!u->cu_selector)
62 		u->cu_selector = nl_data_alloc(NULL, sizeof(struct tc_u32_sel));
63 
64 	return u32_selector(u);
65 }
66 
u32_mark_alloc(struct rtnl_u32 * u)67 static inline struct tc_u32_mark *u32_mark_alloc(struct rtnl_u32 *u)
68 {
69 	if (!u->cu_mark)
70 		u->cu_mark = nl_data_alloc(NULL, sizeof(struct tc_u32_mark));
71 
72 	return (struct tc_u32_mark *) u->cu_mark->d_data;
73 }
74 
75 static struct nla_policy u32_policy[TCA_U32_MAX+1] = {
76 	[TCA_U32_DIVISOR]	= { .type = NLA_U32 },
77 	[TCA_U32_HASH]		= { .type = NLA_U32 },
78 	[TCA_U32_CLASSID]	= { .type = NLA_U32 },
79 	[TCA_U32_LINK]		= { .type = NLA_U32 },
80 	[TCA_U32_INDEV]		= { .type = NLA_STRING,
81 				    .maxlen = IFNAMSIZ },
82 	[TCA_U32_SEL]		= { .minlen = sizeof(struct tc_u32_sel) },
83 	[TCA_U32_PCNT]		= { .minlen = sizeof(struct tc_u32_pcnt) },
84 	[TCA_U32_MARK]		= { .minlen = sizeof(struct tc_u32_mark) }
85 };
86 
u32_msg_parser(struct rtnl_tc * tc,void * data)87 static int u32_msg_parser(struct rtnl_tc *tc, void *data)
88 {
89 	struct rtnl_u32 *u = data;
90 	struct nlattr *tb[TCA_U32_MAX + 1];
91 	int err;
92 
93 	err = tca_parse(tb, TCA_U32_MAX, tc, u32_policy);
94 	if (err < 0)
95 		return err;
96 
97 	if (tb[TCA_U32_DIVISOR]) {
98 		u->cu_divisor = nla_get_u32(tb[TCA_U32_DIVISOR]);
99 		u->cu_mask |= U32_ATTR_DIVISOR;
100 	}
101 
102 	if (tb[TCA_U32_SEL]) {
103 		u->cu_selector = nl_data_alloc_attr(tb[TCA_U32_SEL]);
104 		if (!u->cu_selector)
105 			goto errout_nomem;
106 		u->cu_mask |= U32_ATTR_SELECTOR;
107 	}
108 
109 	if (tb[TCA_U32_MARK]) {
110 		u->cu_mark = nl_data_alloc_attr(tb[TCA_U32_MARK]);
111 		if (!u->cu_mark)
112 			goto errout_nomem;
113 		u->cu_mask |= U32_ATTR_MARK;
114 	}
115 
116 	if (tb[TCA_U32_HASH]) {
117 		u->cu_hash = nla_get_u32(tb[TCA_U32_HASH]);
118 		u->cu_mask |= U32_ATTR_HASH;
119 	}
120 
121 	if (tb[TCA_U32_CLASSID]) {
122 		u->cu_classid = nla_get_u32(tb[TCA_U32_CLASSID]);
123 		u->cu_mask |= U32_ATTR_CLASSID;
124 	}
125 
126 	if (tb[TCA_U32_LINK]) {
127 		u->cu_link = nla_get_u32(tb[TCA_U32_LINK]);
128 		u->cu_mask |= U32_ATTR_LINK;
129 	}
130 
131 	if (tb[TCA_U32_ACT]) {
132 		u->cu_mask |= U32_ATTR_ACTION;
133 		err = rtnl_act_parse(&u->cu_act, tb[TCA_U32_ACT]);
134 		if (err < 0)
135 			return err;
136 	}
137 
138 	if (tb[TCA_U32_POLICE]) {
139 		u->cu_police = nl_data_alloc_attr(tb[TCA_U32_POLICE]);
140 		if (!u->cu_police)
141 			goto errout_nomem;
142 		u->cu_mask |= U32_ATTR_POLICE;
143 	}
144 
145 	if (tb[TCA_U32_PCNT]) {
146 		struct tc_u32_sel *sel;
147 		size_t pcnt_size;
148 
149 		if (!tb[TCA_U32_SEL]) {
150 			err = -NLE_MISSING_ATTR;
151 			goto errout;
152 		}
153 
154 		sel = u->cu_selector->d_data;
155 		pcnt_size = sizeof(struct tc_u32_pcnt) +
156 				(sel->nkeys * sizeof(uint64_t));
157 		if (_nla_len(tb[TCA_U32_PCNT]) < pcnt_size) {
158 			err = -NLE_INVAL;
159 			goto errout;
160 		}
161 
162 		u->cu_pcnt = nl_data_alloc_attr(tb[TCA_U32_PCNT]);
163 		if (!u->cu_pcnt)
164 			goto errout_nomem;
165 		u->cu_mask |= U32_ATTR_PCNT;
166 	}
167 
168 	if (tb[TCA_U32_INDEV]) {
169 		nla_strlcpy(u->cu_indev, tb[TCA_U32_INDEV], IFNAMSIZ);
170 		u->cu_mask |= U32_ATTR_INDEV;
171 	}
172 
173 	return 0;
174 
175 errout_nomem:
176 	err = -NLE_NOMEM;
177 errout:
178 	return err;
179 }
180 
u32_free_data(struct rtnl_tc * tc,void * data)181 static void u32_free_data(struct rtnl_tc *tc, void *data)
182 {
183 	struct rtnl_u32 *u = data;
184 
185 	if (u->cu_act)
186 		rtnl_act_put_all(&u->cu_act);
187 	nl_data_free(u->cu_mark);
188 	nl_data_free(u->cu_selector);
189 	nl_data_free(u->cu_police);
190 	nl_data_free(u->cu_pcnt);
191 }
192 
u32_clone(void * _dst,void * _src)193 static int u32_clone(void *_dst, void *_src)
194 {
195 	struct rtnl_u32 *dst = _dst, *src = _src;
196 	_nl_auto_nl_data struct nl_data *selector = NULL;
197 	_nl_auto_nl_data struct nl_data *mark = NULL;
198 	_nl_auto_nl_data struct nl_data *police = NULL;
199 	_nl_auto_nl_data struct nl_data *pcnt = NULL;
200 	_nl_auto_nl_data struct nl_data *opts = NULL;
201 	_nl_auto_nl_data struct nl_data *xstats = NULL;
202 	_nl_auto_nl_data struct nl_data *subdata = NULL;
203 	_nl_auto_rtnl_act struct rtnl_act *act = NULL;
204 
205 	dst->cu_pcnt = NULL;
206 	dst->cu_selector = NULL;
207 	dst->cu_mark = NULL;
208 	dst->cu_act = NULL;
209 	dst->cu_police = NULL;
210 
211 	if (src->cu_selector) {
212 		if (!(selector = nl_data_clone(src->cu_selector)))
213 			return -NLE_NOMEM;
214 	}
215 
216 	if (src->cu_mark) {
217 		if (!(mark = nl_data_clone(src->cu_mark)))
218 			return -NLE_NOMEM;
219 	}
220 
221 	if (src->cu_act) {
222 		if (!(act = rtnl_act_alloc()))
223 			return -NLE_NOMEM;
224 
225 		if (src->cu_act->c_opts) {
226 			if (!(opts = nl_data_clone(src->cu_act->c_opts)))
227 				return -NLE_NOMEM;
228 		}
229 
230 		if (src->cu_act->c_xstats) {
231 			if (!(xstats = nl_data_clone(src->cu_act->c_xstats)))
232 				return -NLE_NOMEM;
233 		}
234 
235 		if (src->cu_act->c_subdata) {
236 			if (!(subdata = nl_data_clone(src->cu_act->c_subdata)))
237 				return -NLE_NOMEM;
238 		}
239 	}
240 
241 	if (src->cu_police) {
242 		if (!(police = nl_data_clone(src->cu_police)))
243 			return -NLE_NOMEM;
244 	}
245 
246 	if (src->cu_pcnt) {
247 		if (!(pcnt = nl_data_clone(src->cu_pcnt)))
248 			return -NLE_NOMEM;
249 	}
250 
251 	/* we've passed the critical point and its safe to proceed */
252 
253 	if (selector)
254 		dst->cu_selector = _nl_steal_pointer(&selector);
255 
256 	if (mark)
257 		dst->cu_mark = _nl_steal_pointer(&mark);
258 
259 	if (police)
260 		dst->cu_police = _nl_steal_pointer(&police);
261 
262 	if (pcnt)
263 		dst->cu_pcnt = _nl_steal_pointer(&pcnt);
264 
265 	if (act) {
266 		dst->cu_act = _nl_steal_pointer(&act);
267 
268 		/* action nl list next and prev pointers must be updated */
269 		nl_init_list_head(&dst->cu_act->ce_list);
270 
271 		if (opts)
272 			dst->cu_act->c_opts = _nl_steal_pointer(&opts);
273 
274 		if (xstats)
275 			dst->cu_act->c_xstats = _nl_steal_pointer(&xstats);
276 
277 		if (subdata)
278 			dst->cu_act->c_subdata = _nl_steal_pointer(&subdata);
279 
280 		if (dst->cu_act->c_link) {
281 			nl_object_get(OBJ_CAST(dst->cu_act->c_link));
282 		}
283 
284 		dst->cu_act->a_next = NULL;   /* Only clone first in chain */
285 	}
286 
287 	return 0;
288 }
289 
u32_dump_line(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)290 static void u32_dump_line(struct rtnl_tc *tc, void *data,
291 			  struct nl_dump_params *p)
292 {
293 	struct rtnl_u32 *u = data;
294 	char buf[32];
295 
296 	if (!u)
297 		return;
298 
299 	if (u->cu_mask & U32_ATTR_DIVISOR)
300 		nl_dump(p, " divisor %u", u->cu_divisor);
301 	else if (u->cu_mask & U32_ATTR_CLASSID)
302 		nl_dump(p, " target %s",
303 			rtnl_tc_handle2str(u->cu_classid, buf, sizeof(buf)));
304 }
305 
print_selector(struct nl_dump_params * p,struct tc_u32_sel * sel,struct rtnl_u32 * u)306 static void print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel,
307 			   struct rtnl_u32 *u)
308 {
309 	int i;
310 	struct tc_u32_key *key;
311 
312 	if (sel->hmask || sel->hoff) {
313 		/* I guess this will never be used since the kernel only
314 		 * exports the selector if no divisor is set but hash offset
315 		 * and hash mask make only sense in hash filters with divisor
316 		 * set */
317 		nl_dump(p, " hash at %u & 0x%x", sel->hoff, sel->hmask);
318 	}
319 
320 	if (sel->flags & (TC_U32_OFFSET | TC_U32_VAROFFSET)) {
321 		nl_dump(p, " offset at %u", sel->off);
322 
323 		if (sel->flags & TC_U32_VAROFFSET)
324 			nl_dump(p, " variable (at %u & 0x%x) >> %u",
325 				sel->offoff, ntohs(sel->offmask), sel->offshift);
326 	}
327 
328 	if (sel->flags) {
329 		int flags = sel->flags;
330 		nl_dump(p, " <");
331 
332 #define PRINT_FLAG(f) if (flags & TC_U32_##f) { \
333 	flags &= ~TC_U32_##f; nl_dump(p, #f "%s", flags ? "," : ""); }
334 
335 		PRINT_FLAG(TERMINAL);
336 		PRINT_FLAG(OFFSET);
337 		PRINT_FLAG(VAROFFSET);
338 		PRINT_FLAG(EAT);
339 #undef PRINT_FLAG
340 
341 		nl_dump(p, ">");
342 	}
343 
344 
345 	for (i = 0; i < sel->nkeys; i++) {
346 		key = &sel->keys[i];
347 
348 		nl_dump(p, "\n");
349 		nl_dump_line(p, "      match key at %s%u ",
350 			key->offmask ? "nexthdr+" : "", key->off);
351 
352 		if (key->offmask)
353 			nl_dump(p, "[0x%u] ", key->offmask);
354 
355 		nl_dump(p, "& 0x%08x == 0x%08x", ntohl(key->mask), ntohl(key->val));
356 
357 		if (p->dp_type == NL_DUMP_STATS &&
358 		    (u->cu_mask & U32_ATTR_PCNT)) {
359 			struct tc_u32_pcnt *pcnt = u->cu_pcnt->d_data;
360 
361 			nl_dump(p, " successful %llu",
362 				(long long unsigned)pcnt->kcnts[i]);
363 		}
364 	}
365 }
366 
u32_dump_details(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)367 static void u32_dump_details(struct rtnl_tc *tc, void *data,
368 			     struct nl_dump_params *p)
369 {
370 	struct rtnl_u32 *u = data;
371 	struct tc_u32_sel *s = NULL;
372 	struct tc_u32_mark *m;
373 
374 	if (!u)
375 		return;
376 
377 	if (!(u->cu_mask & U32_ATTR_SELECTOR)) {
378 		nl_dump(p, "no-selector");
379 	} else {
380 		s = u->cu_selector->d_data;
381 		nl_dump(p, "nkeys %u", s->nkeys);
382 	}
383 
384 	if (!(u->cu_mask & U32_ATTR_MARK)) {
385 		nl_dump(p, " no-mark");
386 	} else {
387 		m = u->cu_mark->d_data;
388 		nl_dump(p, " mark 0x%u 0x%u", m->val, m->mask);
389 	}
390 
391 	if (u->cu_mask & U32_ATTR_HASH)
392 		nl_dump(p, " ht key 0x%x hash 0x%u",
393 			TC_U32_USERHTID(u->cu_hash), TC_U32_HASH(u->cu_hash));
394 
395 	if (u->cu_mask & U32_ATTR_LINK)
396 		nl_dump(p, " link %u", u->cu_link);
397 
398 	if (u->cu_mask & U32_ATTR_INDEV)
399 		nl_dump(p, " indev %s", u->cu_indev);
400 
401 	if (u->cu_mask & U32_ATTR_SELECTOR)
402 		print_selector(p, s, u);
403 
404 	nl_dump(p, "\n");
405 }
406 
u32_dump_stats(struct rtnl_tc * tc,void * data,struct nl_dump_params * p)407 static void u32_dump_stats(struct rtnl_tc *tc, void *data,
408 			   struct nl_dump_params *p)
409 {
410 	struct rtnl_u32 *u = data;
411 
412 	if (!u)
413 		return;
414 
415 	if (u->cu_mask & U32_ATTR_PCNT) {
416 		struct tc_u32_pcnt *pc = u->cu_pcnt->d_data;
417 
418 		nl_dump(p, "\n");
419 		nl_dump_line(p, "    hit %8llu count %8llu\n",
420 			     (long long unsigned)pc->rhit,
421 			     (long long unsigned)pc->rcnt);
422 	}
423 }
424 
u32_msg_fill(struct rtnl_tc * tc,void * data,struct nl_msg * msg)425 static int u32_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg)
426 {
427 	struct rtnl_u32 *u = data;
428 
429 	if (!u)
430 		return 0;
431 
432 	if (u->cu_mask & U32_ATTR_DIVISOR)
433 		NLA_PUT_U32(msg, TCA_U32_DIVISOR, u->cu_divisor);
434 
435 	if (u->cu_mask & U32_ATTR_HASH)
436 		NLA_PUT_U32(msg, TCA_U32_HASH, u->cu_hash);
437 
438 	if (u->cu_mask & U32_ATTR_CLASSID)
439 		NLA_PUT_U32(msg, TCA_U32_CLASSID, u->cu_classid);
440 
441 	if (u->cu_mask & U32_ATTR_LINK)
442 		NLA_PUT_U32(msg, TCA_U32_LINK, u->cu_link);
443 
444 	if (u->cu_mask & U32_ATTR_SELECTOR)
445 		NLA_PUT_DATA(msg, TCA_U32_SEL, u->cu_selector);
446 
447 	if (u->cu_mask & U32_ATTR_MARK)
448 		NLA_PUT_DATA(msg, TCA_U32_MARK, u->cu_mark);
449 
450 	if (u->cu_mask & U32_ATTR_ACTION) {
451 		int err;
452 
453 		err = rtnl_act_fill(msg, TCA_U32_ACT, u->cu_act);
454 		if (err < 0)
455 			return err;
456 	}
457 
458 	if (u->cu_mask & U32_ATTR_POLICE)
459 		NLA_PUT_DATA(msg, TCA_U32_POLICE, u->cu_police);
460 
461 	if (u->cu_mask & U32_ATTR_INDEV)
462 		NLA_PUT_STRING(msg, TCA_U32_INDEV, u->cu_indev);
463 
464 	return 0;
465 
466 nla_put_failure:
467 	return -NLE_NOMEM;
468 }
469 
470 /**
471  * @name Attribute Modifications
472  * @{
473  */
474 
rtnl_u32_set_handle(struct rtnl_cls * cls,int htid,int hash,int nodeid)475 void rtnl_u32_set_handle(struct rtnl_cls *cls, int htid, int hash,
476 			 int nodeid)
477 {
478 	uint32_t handle = (htid << 20) | (hash << 12) | nodeid;
479 
480 	rtnl_tc_set_handle((struct rtnl_tc *) cls, handle );
481 }
482 
rtnl_u32_set_classid(struct rtnl_cls * cls,uint32_t classid)483 int rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid)
484 {
485 	struct rtnl_u32 *u;
486 
487 	if (!(u = rtnl_tc_data(TC_CAST(cls))))
488 		return -NLE_NOMEM;
489 
490 	u->cu_classid = classid;
491 	u->cu_mask |= U32_ATTR_CLASSID;
492 
493 	return 0;
494 }
495 
rtnl_u32_get_classid(struct rtnl_cls * cls,uint32_t * classid)496 int rtnl_u32_get_classid(struct rtnl_cls *cls, uint32_t *classid)
497 {
498 	struct rtnl_u32 *u;
499 
500 	if (!(u = rtnl_tc_data_peek(TC_CAST(cls))))
501 		return -NLE_INVAL;
502 
503 	if (!(u->cu_mask & U32_ATTR_CLASSID))
504 		return -NLE_INVAL;
505 
506 	*classid = u->cu_classid;
507 	return 0;
508 }
509 
rtnl_u32_set_divisor(struct rtnl_cls * cls,uint32_t divisor)510 int rtnl_u32_set_divisor(struct rtnl_cls *cls, uint32_t divisor)
511 {
512 	struct rtnl_u32 *u;
513 
514 	if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
515 		return -NLE_NOMEM;
516 
517 	u->cu_divisor = divisor;
518 	u->cu_mask |= U32_ATTR_DIVISOR;
519 	return 0;
520 }
521 
rtnl_u32_set_link(struct rtnl_cls * cls,uint32_t link)522 int rtnl_u32_set_link(struct rtnl_cls *cls, uint32_t link)
523 {
524 	struct rtnl_u32 *u;
525 
526 	if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
527 		return -NLE_NOMEM;
528 
529 	u->cu_link = link;
530 	u->cu_mask |= U32_ATTR_LINK;
531 	return 0;
532 }
533 
rtnl_u32_set_hashtable(struct rtnl_cls * cls,uint32_t ht)534 int rtnl_u32_set_hashtable(struct rtnl_cls *cls, uint32_t ht)
535 {
536 	struct rtnl_u32 *u;
537 
538 	if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
539 		return -NLE_NOMEM;
540 
541 	u->cu_hash = ht;
542 	u->cu_mask |= U32_ATTR_HASH;
543 	return 0;
544 }
545 
rtnl_u32_set_hashmask(struct rtnl_cls * cls,uint32_t hashmask,uint32_t offset)546 int rtnl_u32_set_hashmask(struct rtnl_cls *cls, uint32_t hashmask, uint32_t offset)
547 {
548 	struct rtnl_u32 *u;
549 	struct tc_u32_sel *sel;
550 
551 	hashmask = htonl(hashmask);
552 
553 	if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
554 		return -NLE_NOMEM;
555 
556 	sel = u32_selector_alloc(u);
557 	if (!sel)
558 		return -NLE_NOMEM;
559 
560 	sel->hmask = hashmask;
561 	sel->hoff = offset;
562 	return 0;
563 }
564 
rtnl_u32_set_selector(struct rtnl_cls * cls,int offoff,uint32_t offmask,char offshift,uint16_t off,char flags)565 int rtnl_u32_set_selector(struct rtnl_cls *cls, int offoff, uint32_t offmask, char offshift, uint16_t off, char flags)
566 {
567 	struct rtnl_u32 *u;
568 	struct tc_u32_sel *sel;
569 
570 	offmask = ntohs(offmask);
571 
572 	if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
573 		return -NLE_NOMEM;
574 
575 	sel = u32_selector_alloc(u);
576 	if (!sel)
577 		return -NLE_NOMEM;
578 
579 	sel->offoff = offoff;
580 	sel->offmask = offmask;
581 	sel->offshift = offshift;
582 	sel->flags |= TC_U32_VAROFFSET;
583 	sel->off = off;
584 	sel->flags |= flags;
585 	return 0;
586 }
587 
rtnl_u32_set_cls_terminal(struct rtnl_cls * cls)588 int rtnl_u32_set_cls_terminal(struct rtnl_cls *cls)
589 {
590 	struct rtnl_u32 *u;
591 	struct tc_u32_sel *sel;
592 
593 	if (!(u = (struct rtnl_u32 *) rtnl_tc_data(TC_CAST(cls))))
594 		return -NLE_NOMEM;
595 
596 	sel = u32_selector_alloc(u);
597 	if (!sel)
598 		return -NLE_NOMEM;
599 
600 	sel->flags |= TC_U32_TERMINAL;
601 	return 0;
602 }
603 
rtnl_u32_add_action(struct rtnl_cls * cls,struct rtnl_act * act)604 int rtnl_u32_add_action(struct rtnl_cls *cls, struct rtnl_act *act)
605 {
606 	struct rtnl_u32 *u;
607 	int err;
608 
609 	if (!act)
610 		return 0;
611 
612 	if (!(u = rtnl_tc_data(TC_CAST(cls))))
613 		return -NLE_NOMEM;
614 
615 	if ((err = _rtnl_act_append_get(&u->cu_act, act)) < 0)
616 		return err;
617 
618 	u->cu_mask |= U32_ATTR_ACTION;
619 	return 0;
620 }
621 
rtnl_u32_get_action(struct rtnl_cls * cls)622 struct rtnl_act* rtnl_u32_get_action(struct rtnl_cls *cls)
623 {
624     struct rtnl_u32 *u;
625 
626     if (!(u = rtnl_tc_data_peek(TC_CAST(cls))))
627         return NULL;
628 
629     if (!(u->cu_mask & U32_ATTR_ACTION))
630         return NULL;
631 
632     return u->cu_act;
633 }
634 
rtnl_u32_del_action(struct rtnl_cls * cls,struct rtnl_act * act)635 int rtnl_u32_del_action(struct rtnl_cls *cls, struct rtnl_act *act)
636 {
637 	struct rtnl_u32 *u;
638 	int ret;
639 
640 	if (!act)
641 		return 0;
642 
643 	if (!(u = rtnl_tc_data(TC_CAST(cls))))
644 		return -NLE_NOMEM;
645 
646 	if (!(u->cu_mask & U32_ATTR_ACTION))
647 		return -NLE_INVAL;
648 
649 	ret = rtnl_act_remove(&u->cu_act, act);
650 	if (ret)
651 		return ret;
652 
653 	if (!u->cu_act)
654 		u->cu_mask &= ~U32_ATTR_ACTION;
655 	rtnl_act_put(act);
656 	return 0;
657 }
658 /** @} */
659 
660 /**
661  * @name Selector Modifications
662  * @{
663  */
664 
rtnl_u32_set_flags(struct rtnl_cls * cls,int flags)665 int rtnl_u32_set_flags(struct rtnl_cls *cls, int flags)
666 {
667 	struct tc_u32_sel *sel;
668 	struct rtnl_u32 *u;
669 
670 	if (!(u = rtnl_tc_data(TC_CAST(cls))))
671 		return -NLE_NOMEM;
672 
673 	sel = u32_selector_alloc(u);
674 	if (!sel)
675 		return -NLE_NOMEM;
676 
677 	sel->flags |= flags;
678 	u->cu_mask |= U32_ATTR_SELECTOR;
679 
680 	return 0;
681 }
682 
683 /**
684  * Append new 32-bit key to the selector
685  *
686  * @arg cls	classifier to be modifier
687  * @arg val	value to be matched (network byte-order)
688  * @arg mask	mask to be applied before matching (network byte-order)
689  * @arg off	offset, in bytes, to start matching
690  * @arg offmask	offset mask
691  *
692  * General selectors define the pattern, mask and offset the pattern will be
693  * matched to the packet contents. Using the general selectors you can match
694  * virtually any single bit in the IP (or upper layer) header.
695  *
696 */
rtnl_u32_add_key(struct rtnl_cls * cls,uint32_t val,uint32_t mask,int off,int offmask)697 int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
698 		     int off, int offmask)
699 {
700 	struct tc_u32_sel *sel;
701 	struct rtnl_u32 *u;
702 	int err;
703 
704 	if (!(u = rtnl_tc_data(TC_CAST(cls))))
705 		return -NLE_NOMEM;
706 
707 	sel = u32_selector_alloc(u);
708 	if (!sel)
709 		return -NLE_NOMEM;
710 
711 	if (sel->nkeys == UCHAR_MAX)
712 		return -NLE_NOMEM;
713 
714 	err = nl_data_append(u->cu_selector, NULL, sizeof(struct tc_u32_key));
715 	if (err < 0)
716 		return err;
717 
718 	/* the selector might have been moved by realloc */
719 	sel = u32_selector(u);
720 
721 	sel->keys[sel->nkeys].mask = mask;
722 	sel->keys[sel->nkeys].val = val & mask;
723 	sel->keys[sel->nkeys].off = off;
724 	sel->keys[sel->nkeys].offmask = offmask;
725 	sel->nkeys++;
726 	u->cu_mask |= U32_ATTR_SELECTOR;
727 
728 	return 0;
729 }
730 
rtnl_u32_add_mark(struct rtnl_cls * cls,uint32_t val,uint32_t mask)731 int rtnl_u32_add_mark(struct rtnl_cls *cls, uint32_t val, uint32_t mask)
732 {
733 	struct tc_u32_mark *mark;
734 	struct rtnl_u32 *u;
735 
736 	if (!(u = rtnl_tc_data(TC_CAST(cls))))
737 		return -NLE_NOMEM;
738 
739 	mark = u32_mark_alloc(u);
740 	if (!mark)
741 		return -NLE_NOMEM;
742 
743 	mark->mask = mask;
744 	mark->val = val;
745 
746 	u->cu_mask |= U32_ATTR_MARK;
747 
748 	return 0;
749 }
750 
rtnl_u32_del_mark(struct rtnl_cls * cls)751 int rtnl_u32_del_mark(struct rtnl_cls *cls)
752 {
753 	struct rtnl_u32 *u;
754 
755 	if (!(u = rtnl_tc_data(TC_CAST(cls))))
756 		return -NLE_NOMEM;
757 
758 	if (!(u->cu_mask))
759 		return -NLE_INVAL;
760 
761 	if (!(u->cu_mask & U32_ATTR_MARK))
762 		return -NLE_INVAL;
763 
764 	nl_data_free(u->cu_mark);
765 	u->cu_mark = NULL;
766 	u->cu_mask &= ~U32_ATTR_MARK;
767 
768 	return 0;
769 }
770 
771 /**
772  * Get the 32-bit key from the selector
773  *
774  * @arg cls	classifier to be retrieve
775  * @arg index	the index of the array of keys, start with 0
776  * @arg val	pointer to store value after masked (network byte-order)
777  * @arg mask	pointer to store the mask (network byte-order)
778  * @arg off	pointer to store the offset
779  * @arg offmask	pointer to store offset mask
780  *
781 */
rtnl_u32_get_key(struct rtnl_cls * cls,uint8_t index,uint32_t * val,uint32_t * mask,int * off,int * offmask)782 int rtnl_u32_get_key(struct rtnl_cls *cls, uint8_t index,
783 		     uint32_t *val, uint32_t *mask, int *off, int *offmask)
784 {
785 	struct tc_u32_sel *sel;
786 	struct rtnl_u32 *u;
787 
788 	if (!(u = rtnl_tc_data(TC_CAST(cls))))
789 		return -NLE_NOMEM;
790 
791 	if (!(u->cu_mask & U32_ATTR_SELECTOR))
792 		return -NLE_INVAL;
793 
794 	sel = u32_selector(u);
795 	if (index >= sel->nkeys)
796 		return -NLE_RANGE;
797 
798 	*mask = sel->keys[index].mask;
799 	*val = sel->keys[index].val;
800 	*off = sel->keys[index].off;
801 	*offmask = sel->keys[index].offmask;
802 	return 0;
803 }
804 
805 
rtnl_u32_add_key_uint8(struct rtnl_cls * cls,uint8_t val,uint8_t mask,int off,int offmask)806 int rtnl_u32_add_key_uint8(struct rtnl_cls *cls, uint8_t val, uint8_t mask,
807 			   int off, int offmask)
808 {
809 	int shift = 24 - 8 * (off & 3);
810 
811 	return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
812 				htonl((uint32_t)mask << shift),
813 				off & ~3, offmask);
814 }
815 
816 /**
817  * Append new selector key to match a 16-bit number
818  *
819  * @arg cls	classifier to be modified
820  * @arg val	value to be matched (host byte-order)
821  * @arg mask	mask to be applied before matching (host byte-order)
822  * @arg off	offset, in bytes, to start matching
823  * @arg offmask	offset mask
824 */
rtnl_u32_add_key_uint16(struct rtnl_cls * cls,uint16_t val,uint16_t mask,int off,int offmask)825 int rtnl_u32_add_key_uint16(struct rtnl_cls *cls, uint16_t val, uint16_t mask,
826 			    int off, int offmask)
827 {
828 	int shift = ((off & 3) == 0 ? 16 : 0);
829 	if (off % 2)
830 		return -NLE_INVAL;
831 
832 	return rtnl_u32_add_key(cls, htonl((uint32_t)val << shift),
833 				htonl((uint32_t)mask << shift),
834 				off & ~3, offmask);
835 }
836 
837 /**
838  * Append new selector key to match a 32-bit number
839  *
840  * @arg cls	classifier to be modified
841  * @arg val	value to be matched (host byte-order)
842  * @arg mask	mask to be applied before matching (host byte-order)
843  * @arg off	offset, in bytes, to start matching
844  * @arg offmask	offset mask
845 */
rtnl_u32_add_key_uint32(struct rtnl_cls * cls,uint32_t val,uint32_t mask,int off,int offmask)846 int rtnl_u32_add_key_uint32(struct rtnl_cls *cls, uint32_t val, uint32_t mask,
847 			    int off, int offmask)
848 {
849 	return rtnl_u32_add_key(cls, htonl(val), htonl(mask),
850 				off & ~3, offmask);
851 }
852 
rtnl_u32_add_key_in_addr(struct rtnl_cls * cls,const struct in_addr * addr,uint8_t bitmask,int off,int offmask)853 int rtnl_u32_add_key_in_addr(struct rtnl_cls *cls, const struct in_addr *addr,
854 			     uint8_t bitmask, int off, int offmask)
855 {
856 	uint32_t mask = 0xFFFFFFFF << (32 - bitmask);
857 	return rtnl_u32_add_key(cls, addr->s_addr, htonl(mask), off, offmask);
858 }
859 
rtnl_u32_add_key_in6_addr(struct rtnl_cls * cls,const struct in6_addr * addr,uint8_t bitmask,int off,int offmask)860 int rtnl_u32_add_key_in6_addr(struct rtnl_cls *cls, const struct in6_addr *addr,
861 			      uint8_t bitmask, int off, int offmask)
862 {
863 	int i, err;
864 
865 	for (i = 1; i <= 4; i++) {
866 		if (32 * i - bitmask <= 0) {
867 			if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
868 						0xFFFFFFFF, off+4*(i-1), offmask)) < 0)
869 				return err;
870 		}
871 		else if (32 * i - bitmask < 32) {
872 			uint32_t mask = 0xFFFFFFFF << (32 * i - bitmask);
873 			if ((err = rtnl_u32_add_key(cls, addr->s6_addr32[i-1],
874 						htonl(mask), off+4*(i-1), offmask)) < 0)
875 				return err;
876 		}
877 		/* otherwise, if (32*i - bitmask >= 32) no key is generated */
878 	}
879 
880 	return 0;
881 }
882 
883 /** @} */
884 
885 static struct rtnl_tc_ops u32_ops = {
886 	.to_kind		= "u32",
887 	.to_type		= RTNL_TC_TYPE_CLS,
888 	.to_size		= sizeof(struct rtnl_u32),
889 	.to_msg_parser		= u32_msg_parser,
890 	.to_free_data		= u32_free_data,
891 	.to_clone		= u32_clone,
892 	.to_msg_fill		= u32_msg_fill,
893 	.to_dump = {
894 	    [NL_DUMP_LINE]	= u32_dump_line,
895 	    [NL_DUMP_DETAILS]	= u32_dump_details,
896 	    [NL_DUMP_STATS]	= u32_dump_stats,
897 	},
898 };
899 
u32_init(void)900 static void _nl_init u32_init(void)
901 {
902 	rtnl_tc_register(&u32_ops);
903 }
904 
u32_exit(void)905 static void _nl_exit u32_exit(void)
906 {
907 	rtnl_tc_unregister(&u32_ops);
908 }
909 
910 /** @} */
911