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