• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * q_u32.c		U32 filter.
3  *
4  *		This program is free software; you can u32istribute it and/or
5  *		modify it under the terms of the GNU General Public License
6  *		as published by the Free Software Foundation; either version
7  *		2 of the License, or (at your option) any later version.
8  *
9  * Authors:	Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10  *		Match mark added by Catalin(ux aka Dino) BOIE <catab at umbrella.ro> [5 nov 2004]
11  *
12  */
13 
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <syslog.h>
18 #include <fcntl.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
22 #include <string.h>
23 #include <linux/if.h>
24 #include <linux/if_ether.h>
25 
26 #include "utils.h"
27 #include "tc_util.h"
28 
29 extern int show_pretty;
30 
explain(void)31 static void explain(void)
32 {
33 	fprintf(stderr,
34 		"Usage: ... u32 [ match SELECTOR ... ] [ link HTID ] [ classid CLASSID ]\n"
35 		"               [ action ACTION_SPEC ] [ offset OFFSET_SPEC ]\n"
36 		"               [ ht HTID ] [ hashkey HASHKEY_SPEC ]\n"
37 		"               [ sample SAMPLE ] [skip_hw | skip_sw]\n"
38 		"or         u32 divisor DIVISOR\n"
39 		"\n"
40 		"Where: SELECTOR := SAMPLE SAMPLE ...\n"
41 		"       SAMPLE := { ip | ip6 | udp | tcp | icmp | u{32|16|8} | mark }\n"
42 		"                 SAMPLE_ARGS [ divisor DIVISOR ]\n"
43 		"       FILTERID := X:Y:Z\n"
44 		"\nNOTE: CLASSID is parsed at hexadecimal input.\n");
45 }
46 
get_u32_handle(__u32 * handle,const char * str)47 static int get_u32_handle(__u32 *handle, const char *str)
48 {
49 	__u32 htid = 0, hash = 0, nodeid = 0;
50 	char *tmp = strchr(str, ':');
51 
52 	if (tmp == NULL) {
53 		if (memcmp("0x", str, 2) == 0)
54 			return get_u32(handle, str, 16);
55 		return -1;
56 	}
57 	htid = strtoul(str, &tmp, 16);
58 	if (tmp == str && *str != ':' && *str != 0)
59 		return -1;
60 	if (htid >= 0x1000)
61 		return -1;
62 	if (*tmp) {
63 		str = tmp + 1;
64 		hash = strtoul(str, &tmp, 16);
65 		if (tmp == str && *str != ':' && *str != 0)
66 			return -1;
67 		if (hash >= 0x100)
68 			return -1;
69 		if (*tmp) {
70 			str = tmp + 1;
71 			nodeid = strtoul(str, &tmp, 16);
72 			if (tmp == str && *str != 0)
73 				return -1;
74 			if (nodeid >= 0x1000)
75 				return -1;
76 		}
77 	}
78 	*handle = (htid<<20)|(hash<<12)|nodeid;
79 	return 0;
80 }
81 
sprint_u32_handle(__u32 handle,char * buf)82 static char *sprint_u32_handle(__u32 handle, char *buf)
83 {
84 	int bsize = SPRINT_BSIZE-1;
85 	__u32 htid = TC_U32_HTID(handle);
86 	__u32 hash = TC_U32_HASH(handle);
87 	__u32 nodeid = TC_U32_NODE(handle);
88 	char *b = buf;
89 
90 	if (handle == 0) {
91 		snprintf(b, bsize, "none");
92 		return b;
93 	}
94 	if (htid) {
95 		int l = snprintf(b, bsize, "%x:", htid>>20);
96 
97 		bsize -= l;
98 		b += l;
99 	}
100 	if (nodeid|hash) {
101 		if (hash) {
102 			int l = snprintf(b, bsize, "%x", hash);
103 
104 			bsize -= l;
105 			b += l;
106 		}
107 		if (nodeid) {
108 			int l = snprintf(b, bsize, ":%x", nodeid);
109 
110 			bsize -= l;
111 			b += l;
112 		}
113 	}
114 	if (show_raw)
115 		snprintf(b, bsize, "[%08x] ", handle);
116 	return buf;
117 }
118 
pack_key(struct tc_u32_sel * sel,__u32 key,__u32 mask,int off,int offmask)119 static int pack_key(struct tc_u32_sel *sel, __u32 key, __u32 mask,
120 		    int off, int offmask)
121 {
122 	int i;
123 	int hwm = sel->nkeys;
124 
125 	key &= mask;
126 
127 	for (i = 0; i < hwm; i++) {
128 		if (sel->keys[i].off == off && sel->keys[i].offmask == offmask) {
129 			__u32 intersect = mask & sel->keys[i].mask;
130 
131 			if ((key ^ sel->keys[i].val) & intersect)
132 				return -1;
133 			sel->keys[i].val |= key;
134 			sel->keys[i].mask |= mask;
135 			return 0;
136 		}
137 	}
138 
139 	if (hwm >= 128)
140 		return -1;
141 	if (off % 4)
142 		return -1;
143 	sel->keys[hwm].val = key;
144 	sel->keys[hwm].mask = mask;
145 	sel->keys[hwm].off = off;
146 	sel->keys[hwm].offmask = offmask;
147 	sel->nkeys++;
148 	return 0;
149 }
150 
pack_key32(struct tc_u32_sel * sel,__u32 key,__u32 mask,int off,int offmask)151 static int pack_key32(struct tc_u32_sel *sel, __u32 key, __u32 mask,
152 		      int off, int offmask)
153 {
154 	key = htonl(key);
155 	mask = htonl(mask);
156 	return pack_key(sel, key, mask, off, offmask);
157 }
158 
pack_key16(struct tc_u32_sel * sel,__u32 key,__u32 mask,int off,int offmask)159 static int pack_key16(struct tc_u32_sel *sel, __u32 key, __u32 mask,
160 		      int off, int offmask)
161 {
162 	if (key > 0xFFFF || mask > 0xFFFF)
163 		return -1;
164 
165 	if ((off & 3) == 0) {
166 		key <<= 16;
167 		mask <<= 16;
168 	}
169 	off &= ~3;
170 	key = htonl(key);
171 	mask = htonl(mask);
172 
173 	return pack_key(sel, key, mask, off, offmask);
174 }
175 
pack_key8(struct tc_u32_sel * sel,__u32 key,__u32 mask,int off,int offmask)176 static int pack_key8(struct tc_u32_sel *sel, __u32 key, __u32 mask, int off,
177 		     int offmask)
178 {
179 	if (key > 0xFF || mask > 0xFF)
180 		return -1;
181 
182 	if ((off & 3) == 0) {
183 		key <<= 24;
184 		mask <<= 24;
185 	} else if ((off & 3) == 1) {
186 		key <<= 16;
187 		mask <<= 16;
188 	} else if ((off & 3) == 2) {
189 		key <<= 8;
190 		mask <<= 8;
191 	}
192 	off &= ~3;
193 	key = htonl(key);
194 	mask = htonl(mask);
195 
196 	return pack_key(sel, key, mask, off, offmask);
197 }
198 
199 
parse_at(int * argc_p,char *** argv_p,int * off,int * offmask)200 static int parse_at(int *argc_p, char ***argv_p, int *off, int *offmask)
201 {
202 	int argc = *argc_p;
203 	char **argv = *argv_p;
204 	char *p = *argv;
205 
206 	if (argc <= 0)
207 		return -1;
208 
209 	if (strlen(p) > strlen("nexthdr+") &&
210 	    memcmp(p, "nexthdr+", strlen("nexthdr+")) == 0) {
211 		*offmask = -1;
212 		p += strlen("nexthdr+");
213 	} else if (matches(*argv, "nexthdr+") == 0) {
214 		NEXT_ARG();
215 		*offmask = -1;
216 		p = *argv;
217 	}
218 
219 	if (get_integer(off, p, 0))
220 		return -1;
221 	argc--; argv++;
222 
223 	*argc_p = argc;
224 	*argv_p = argv;
225 	return 0;
226 }
227 
228 
parse_u32(int * argc_p,char *** argv_p,struct tc_u32_sel * sel,int off,int offmask)229 static int parse_u32(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
230 		     int off, int offmask)
231 {
232 	int res = -1;
233 	int argc = *argc_p;
234 	char **argv = *argv_p;
235 	__u32 key;
236 	__u32 mask;
237 
238 	if (argc < 2)
239 		return -1;
240 
241 	if (get_u32(&key, *argv, 0))
242 		return -1;
243 	argc--; argv++;
244 
245 	if (get_u32(&mask, *argv, 16))
246 		return -1;
247 	argc--; argv++;
248 
249 	if (argc > 0 && strcmp(argv[0], "at") == 0) {
250 		NEXT_ARG();
251 		if (parse_at(&argc, &argv, &off, &offmask))
252 			return -1;
253 	}
254 
255 	res = pack_key32(sel, key, mask, off, offmask);
256 	*argc_p = argc;
257 	*argv_p = argv;
258 	return res;
259 }
260 
parse_u16(int * argc_p,char *** argv_p,struct tc_u32_sel * sel,int off,int offmask)261 static int parse_u16(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
262 		     int off, int offmask)
263 {
264 	int res = -1;
265 	int argc = *argc_p;
266 	char **argv = *argv_p;
267 	__u32 key;
268 	__u32 mask;
269 
270 	if (argc < 2)
271 		return -1;
272 
273 	if (get_u32(&key, *argv, 0))
274 		return -1;
275 	argc--; argv++;
276 
277 	if (get_u32(&mask, *argv, 16))
278 		return -1;
279 	argc--; argv++;
280 
281 	if (argc > 0 && strcmp(argv[0], "at") == 0) {
282 		NEXT_ARG();
283 		if (parse_at(&argc, &argv, &off, &offmask))
284 			return -1;
285 	}
286 	res = pack_key16(sel, key, mask, off, offmask);
287 	*argc_p = argc;
288 	*argv_p = argv;
289 	return res;
290 }
291 
parse_u8(int * argc_p,char *** argv_p,struct tc_u32_sel * sel,int off,int offmask)292 static int parse_u8(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
293 		    int off, int offmask)
294 {
295 	int res = -1;
296 	int argc = *argc_p;
297 	char **argv = *argv_p;
298 	__u32 key;
299 	__u32 mask;
300 
301 	if (argc < 2)
302 		return -1;
303 
304 	if (get_u32(&key, *argv, 0))
305 		return -1;
306 	argc--; argv++;
307 
308 	if (get_u32(&mask, *argv, 16))
309 		return -1;
310 	argc--; argv++;
311 
312 	if (key > 0xFF || mask > 0xFF)
313 		return -1;
314 
315 	if (argc > 0 && strcmp(argv[0], "at") == 0) {
316 		NEXT_ARG();
317 		if (parse_at(&argc, &argv, &off, &offmask))
318 			return -1;
319 	}
320 
321 	res = pack_key8(sel, key, mask, off, offmask);
322 	*argc_p = argc;
323 	*argv_p = argv;
324 	return res;
325 }
326 
parse_ip_addr(int * argc_p,char *** argv_p,struct tc_u32_sel * sel,int off)327 static int parse_ip_addr(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
328 			 int off)
329 {
330 	int res = -1;
331 	int argc = *argc_p;
332 	char **argv = *argv_p;
333 	inet_prefix addr;
334 	__u32 mask;
335 	int offmask = 0;
336 
337 	if (argc < 1)
338 		return -1;
339 
340 	if (get_prefix_1(&addr, *argv, AF_INET))
341 		return -1;
342 	argc--; argv++;
343 
344 	if (argc > 0 && strcmp(argv[0], "at") == 0) {
345 		NEXT_ARG();
346 		if (parse_at(&argc, &argv, &off, &offmask))
347 			return -1;
348 	}
349 
350 	mask = 0;
351 	if (addr.bitlen)
352 		mask = htonl(0xFFFFFFFF << (32 - addr.bitlen));
353 	if (pack_key(sel, addr.data[0], mask, off, offmask) < 0)
354 		return -1;
355 	res = 0;
356 
357 	*argc_p = argc;
358 	*argv_p = argv;
359 	return res;
360 }
361 
parse_ip6_addr(int * argc_p,char *** argv_p,struct tc_u32_sel * sel,int off)362 static int parse_ip6_addr(int *argc_p, char ***argv_p,
363 			  struct tc_u32_sel *sel, int off)
364 {
365 	int res = -1;
366 	int argc = *argc_p;
367 	char **argv = *argv_p;
368 	int plen = 128;
369 	int i;
370 	inet_prefix addr;
371 	int offmask = 0;
372 
373 	if (argc < 1)
374 		return -1;
375 
376 	if (get_prefix_1(&addr, *argv, AF_INET6))
377 		return -1;
378 	argc--; argv++;
379 
380 	if (argc > 0 && strcmp(argv[0], "at") == 0) {
381 		NEXT_ARG();
382 		if (parse_at(&argc, &argv, &off, &offmask))
383 			return -1;
384 	}
385 
386 	plen = addr.bitlen;
387 	for (i = 0; i < plen; i += 32) {
388 		if (i + 31 < plen) {
389 			res = pack_key(sel, addr.data[i / 32],
390 				       0xFFFFFFFF, off + 4 * (i / 32), offmask);
391 			if (res < 0)
392 				return -1;
393 		} else if (i < plen) {
394 			__u32 mask = htonl(0xFFFFFFFF << (32 - (plen - i)));
395 
396 			res = pack_key(sel, addr.data[i / 32],
397 				       mask, off + 4 * (i / 32), offmask);
398 			if (res < 0)
399 				return -1;
400 		}
401 	}
402 	res = 0;
403 
404 	*argc_p = argc;
405 	*argv_p = argv;
406 	return res;
407 }
408 
parse_ip6_class(int * argc_p,char *** argv_p,struct tc_u32_sel * sel)409 static int parse_ip6_class(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
410 {
411 	int res = -1;
412 	int argc = *argc_p;
413 	char **argv = *argv_p;
414 	__u32 key;
415 	__u32 mask;
416 	int off = 0;
417 	int offmask = 0;
418 
419 	if (argc < 2)
420 		return -1;
421 
422 	if (get_u32(&key, *argv, 0))
423 		return -1;
424 	argc--; argv++;
425 
426 	if (get_u32(&mask, *argv, 16))
427 		return -1;
428 	argc--; argv++;
429 
430 	if (key > 0xFF || mask > 0xFF)
431 		return -1;
432 
433 	key <<= 20;
434 	mask <<= 20;
435 	key = htonl(key);
436 	mask = htonl(mask);
437 
438 	res = pack_key(sel, key, mask, off, offmask);
439 	if (res < 0)
440 		return -1;
441 
442 	*argc_p = argc;
443 	*argv_p = argv;
444 	return 0;
445 }
446 
parse_ether_addr(int * argc_p,char *** argv_p,struct tc_u32_sel * sel,int off)447 static int parse_ether_addr(int *argc_p, char ***argv_p,
448 			    struct tc_u32_sel *sel, int off)
449 {
450 	int res = -1;
451 	int argc = *argc_p;
452 	char **argv = *argv_p;
453 	__u8 addr[6];
454 	int offmask = 0;
455 	int i;
456 
457 	if (argc < 1)
458 		return -1;
459 
460 	if (sscanf(*argv, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
461 		   addr + 0, addr + 1, addr + 2,
462 		   addr + 3, addr + 4, addr + 5) != 6) {
463 		fprintf(stderr, "parse_ether_addr: improperly formed address '%s'\n",
464 			*argv);
465 		return -1;
466 	}
467 
468 	argc--; argv++;
469 	if (argc > 0 && strcmp(argv[0], "at") == 0) {
470 		NEXT_ARG();
471 		if (parse_at(&argc, &argv, &off, &offmask))
472 			return -1;
473 	}
474 
475 	for (i = 0; i < 6; i++) {
476 		res = pack_key8(sel, addr[i], 0xFF, off + i, offmask);
477 		if (res < 0)
478 			return -1;
479 	}
480 
481 	*argc_p = argc;
482 	*argv_p = argv;
483 	return res;
484 }
485 
parse_ip(int * argc_p,char *** argv_p,struct tc_u32_sel * sel)486 static int parse_ip(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
487 {
488 	int res = -1;
489 	int argc = *argc_p;
490 	char **argv = *argv_p;
491 
492 	if (argc < 2)
493 		return -1;
494 
495 	if (strcmp(*argv, "src") == 0) {
496 		NEXT_ARG();
497 		res = parse_ip_addr(&argc, &argv, sel, 12);
498 	} else if (strcmp(*argv, "dst") == 0) {
499 		NEXT_ARG();
500 		res = parse_ip_addr(&argc, &argv, sel, 16);
501 	} else if (strcmp(*argv, "tos") == 0 ||
502 	    matches(*argv, "dsfield") == 0 ||
503 	    matches(*argv, "precedence") == 0) {
504 		NEXT_ARG();
505 		res = parse_u8(&argc, &argv, sel, 1, 0);
506 	} else if (strcmp(*argv, "ihl") == 0) {
507 		NEXT_ARG();
508 		res = parse_u8(&argc, &argv, sel, 0, 0);
509 	} else if (strcmp(*argv, "protocol") == 0) {
510 		NEXT_ARG();
511 		res = parse_u8(&argc, &argv, sel, 9, 0);
512 	} else if (strcmp(*argv, "nofrag") == 0) {
513 		argc--; argv++;
514 		res = pack_key16(sel, 0, 0x3FFF, 6, 0);
515 	} else if (strcmp(*argv, "firstfrag") == 0) {
516 		argc--; argv++;
517 		res = pack_key16(sel, 0x2000, 0x3FFF, 6, 0);
518 	} else if (strcmp(*argv, "df") == 0) {
519 		argc--; argv++;
520 		res = pack_key16(sel, 0x4000, 0x4000, 6, 0);
521 	} else if (strcmp(*argv, "mf") == 0) {
522 		argc--; argv++;
523 		res = pack_key16(sel, 0x2000, 0x2000, 6, 0);
524 	} else if (strcmp(*argv, "dport") == 0) {
525 		NEXT_ARG();
526 		res = parse_u16(&argc, &argv, sel, 22, 0);
527 	} else if (strcmp(*argv, "sport") == 0) {
528 		NEXT_ARG();
529 		res = parse_u16(&argc, &argv, sel, 20, 0);
530 	} else if (strcmp(*argv, "icmp_type") == 0) {
531 		NEXT_ARG();
532 		res = parse_u8(&argc, &argv, sel, 20, 0);
533 	} else if (strcmp(*argv, "icmp_code") == 0) {
534 		NEXT_ARG();
535 		res = parse_u8(&argc, &argv, sel, 21, 0);
536 	} else
537 		return -1;
538 
539 	*argc_p = argc;
540 	*argv_p = argv;
541 	return res;
542 }
543 
parse_ip6(int * argc_p,char *** argv_p,struct tc_u32_sel * sel)544 static int parse_ip6(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
545 {
546 	int res = -1;
547 	int argc = *argc_p;
548 	char **argv = *argv_p;
549 
550 	if (argc < 2)
551 		return -1;
552 
553 	if (strcmp(*argv, "src") == 0) {
554 		NEXT_ARG();
555 		res = parse_ip6_addr(&argc, &argv, sel, 8);
556 	} else if (strcmp(*argv, "dst") == 0) {
557 		NEXT_ARG();
558 		res = parse_ip6_addr(&argc, &argv, sel, 24);
559 	} else if (strcmp(*argv, "priority") == 0) {
560 		NEXT_ARG();
561 		res = parse_ip6_class(&argc, &argv, sel);
562 	} else if (strcmp(*argv, "protocol") == 0) {
563 		NEXT_ARG();
564 		res = parse_u8(&argc, &argv, sel, 6, 0);
565 	} else if (strcmp(*argv, "flowlabel") == 0) {
566 		NEXT_ARG();
567 		res = parse_u32(&argc, &argv, sel, 0, 0);
568 	} else if (strcmp(*argv, "dport") == 0) {
569 		NEXT_ARG();
570 		res = parse_u16(&argc, &argv, sel, 42, 0);
571 	} else if (strcmp(*argv, "sport") == 0) {
572 		NEXT_ARG();
573 		res = parse_u16(&argc, &argv, sel, 40, 0);
574 	} else if (strcmp(*argv, "icmp_type") == 0) {
575 		NEXT_ARG();
576 		res = parse_u8(&argc, &argv, sel, 40, 0);
577 	} else if (strcmp(*argv, "icmp_code") == 0) {
578 		NEXT_ARG();
579 		res = parse_u8(&argc, &argv, sel, 41, 1);
580 	} else
581 		return -1;
582 
583 	*argc_p = argc;
584 	*argv_p = argv;
585 	return res;
586 }
587 
parse_ether(int * argc_p,char *** argv_p,struct tc_u32_sel * sel)588 static int parse_ether(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
589 {
590 	int res = -1;
591 	int argc = *argc_p;
592 	char **argv = *argv_p;
593 
594 	if (argc < 2)
595 		return -1;
596 
597 	if (strcmp(*argv, "src") == 0) {
598 		NEXT_ARG();
599 		res = parse_ether_addr(&argc, &argv, sel, -8);
600 	} else if (strcmp(*argv, "dst") == 0) {
601 		NEXT_ARG();
602 		res = parse_ether_addr(&argc, &argv, sel, -14);
603 	} else {
604 		fprintf(stderr, "Unknown match: ether %s\n", *argv);
605 		return -1;
606 	}
607 
608 	*argc_p = argc;
609 	*argv_p = argv;
610 	return res;
611 }
612 
613 #define parse_tcp parse_udp
parse_udp(int * argc_p,char *** argv_p,struct tc_u32_sel * sel)614 static int parse_udp(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
615 {
616 	int res = -1;
617 	int argc = *argc_p;
618 	char **argv = *argv_p;
619 
620 	if (argc < 2)
621 		return -1;
622 
623 	if (strcmp(*argv, "src") == 0) {
624 		NEXT_ARG();
625 		res = parse_u16(&argc, &argv, sel, 0, -1);
626 	} else if (strcmp(*argv, "dst") == 0) {
627 		NEXT_ARG();
628 		res = parse_u16(&argc, &argv, sel, 2, -1);
629 	} else
630 		return -1;
631 
632 	*argc_p = argc;
633 	*argv_p = argv;
634 	return res;
635 }
636 
637 
parse_icmp(int * argc_p,char *** argv_p,struct tc_u32_sel * sel)638 static int parse_icmp(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
639 {
640 	int res = -1;
641 	int argc = *argc_p;
642 	char **argv = *argv_p;
643 
644 	if (argc < 2)
645 		return -1;
646 
647 	if (strcmp(*argv, "type") == 0) {
648 		NEXT_ARG();
649 		res = parse_u8(&argc, &argv, sel, 0, -1);
650 	} else if (strcmp(*argv, "code") == 0) {
651 		NEXT_ARG();
652 		res = parse_u8(&argc, &argv, sel, 1, -1);
653 	} else
654 		return -1;
655 
656 	*argc_p = argc;
657 	*argv_p = argv;
658 	return res;
659 }
660 
parse_mark(int * argc_p,char *** argv_p,struct nlmsghdr * n)661 static int parse_mark(int *argc_p, char ***argv_p, struct nlmsghdr *n)
662 {
663 	int res = -1;
664 	int argc = *argc_p;
665 	char **argv = *argv_p;
666 	struct tc_u32_mark mark;
667 
668 	if (argc <= 1)
669 		return -1;
670 
671 	if (get_u32(&mark.val, *argv, 0)) {
672 		fprintf(stderr, "Illegal \"mark\" value\n");
673 		return -1;
674 	}
675 	NEXT_ARG();
676 
677 	if (get_u32(&mark.mask, *argv, 0)) {
678 		fprintf(stderr, "Illegal \"mark\" mask\n");
679 		return -1;
680 	}
681 	NEXT_ARG();
682 
683 	if ((mark.val & mark.mask) != mark.val) {
684 		fprintf(stderr, "Illegal \"mark\" (impossible combination)\n");
685 		return -1;
686 	}
687 
688 	addattr_l(n, MAX_MSG, TCA_U32_MARK, &mark, sizeof(mark));
689 	res = 0;
690 
691 	*argc_p = argc;
692 	*argv_p = argv;
693 	return res;
694 }
695 
parse_selector(int * argc_p,char *** argv_p,struct tc_u32_sel * sel,struct nlmsghdr * n)696 static int parse_selector(int *argc_p, char ***argv_p,
697 			  struct tc_u32_sel *sel, struct nlmsghdr *n)
698 {
699 	int argc = *argc_p;
700 	char **argv = *argv_p;
701 	int res = -1;
702 
703 	if (argc <= 0)
704 		return -1;
705 
706 	if (matches(*argv, "u32") == 0) {
707 		NEXT_ARG();
708 		res = parse_u32(&argc, &argv, sel, 0, 0);
709 	} else if (matches(*argv, "u16") == 0) {
710 		NEXT_ARG();
711 		res = parse_u16(&argc, &argv, sel, 0, 0);
712 	} else if (matches(*argv, "u8") == 0) {
713 		NEXT_ARG();
714 		res = parse_u8(&argc, &argv, sel, 0, 0);
715 	} else if (matches(*argv, "ip") == 0) {
716 		NEXT_ARG();
717 		res = parse_ip(&argc, &argv, sel);
718 	} else	if (matches(*argv, "ip6") == 0) {
719 		NEXT_ARG();
720 		res = parse_ip6(&argc, &argv, sel);
721 	} else if (matches(*argv, "udp") == 0) {
722 		NEXT_ARG();
723 		res = parse_udp(&argc, &argv, sel);
724 	} else if (matches(*argv, "tcp") == 0) {
725 		NEXT_ARG();
726 		res = parse_tcp(&argc, &argv, sel);
727 	} else if (matches(*argv, "icmp") == 0) {
728 		NEXT_ARG();
729 		res = parse_icmp(&argc, &argv, sel);
730 	} else if (matches(*argv, "mark") == 0) {
731 		NEXT_ARG();
732 		res = parse_mark(&argc, &argv, n);
733 	} else if (matches(*argv, "ether") == 0) {
734 		NEXT_ARG();
735 		res = parse_ether(&argc, &argv, sel);
736 	} else
737 		return -1;
738 
739 	*argc_p = argc;
740 	*argv_p = argv;
741 	return res;
742 }
743 
parse_offset(int * argc_p,char *** argv_p,struct tc_u32_sel * sel)744 static int parse_offset(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
745 {
746 	int argc = *argc_p;
747 	char **argv = *argv_p;
748 
749 	while (argc > 0) {
750 		if (matches(*argv, "plus") == 0) {
751 			int off;
752 
753 			NEXT_ARG();
754 			if (get_integer(&off, *argv, 0))
755 				return -1;
756 			sel->off = off;
757 			sel->flags |= TC_U32_OFFSET;
758 		} else if (matches(*argv, "at") == 0) {
759 			int off;
760 
761 			NEXT_ARG();
762 			if (get_integer(&off, *argv, 0))
763 				return -1;
764 			sel->offoff = off;
765 			if (off%2) {
766 				fprintf(stderr, "offset \"at\" must be even\n");
767 				return -1;
768 			}
769 			sel->flags |= TC_U32_VAROFFSET;
770 		} else if (matches(*argv, "mask") == 0) {
771 			NEXT_ARG();
772 			if (get_be16(&sel->offmask, *argv, 16))
773 				return -1;
774 			sel->flags |= TC_U32_VAROFFSET;
775 		} else if (matches(*argv, "shift") == 0) {
776 			int shift;
777 
778 			NEXT_ARG();
779 			if (get_integer(&shift, *argv, 0))
780 				return -1;
781 			sel->offshift = shift;
782 			sel->flags |= TC_U32_VAROFFSET;
783 		} else if (matches(*argv, "eat") == 0) {
784 			sel->flags |= TC_U32_EAT;
785 		} else {
786 			break;
787 		}
788 		argc--; argv++;
789 	}
790 
791 	*argc_p = argc;
792 	*argv_p = argv;
793 	return 0;
794 }
795 
parse_hashkey(int * argc_p,char *** argv_p,struct tc_u32_sel * sel)796 static int parse_hashkey(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
797 {
798 	int argc = *argc_p;
799 	char **argv = *argv_p;
800 
801 	while (argc > 0) {
802 		if (matches(*argv, "mask") == 0) {
803 			NEXT_ARG();
804 			if (get_be32(&sel->hmask, *argv, 16))
805 				return -1;
806 		} else if (matches(*argv, "at") == 0) {
807 			int num;
808 
809 			NEXT_ARG();
810 			if (get_integer(&num, *argv, 0))
811 				return -1;
812 			if (num%4)
813 				return -1;
814 			sel->hoff = num;
815 		} else {
816 			break;
817 		}
818 		argc--; argv++;
819 	}
820 
821 	*argc_p = argc;
822 	*argv_p = argv;
823 	return 0;
824 }
825 
print_ipv4(FILE * f,const struct tc_u32_key * key)826 static void print_ipv4(FILE *f, const struct tc_u32_key *key)
827 {
828 	char abuf[256];
829 
830 	switch (key->off) {
831 	case 0:
832 		switch (ntohl(key->mask)) {
833 		case 0x0f000000:
834 			fprintf(f, "\n  match IP ihl %u",
835 				ntohl(key->val) >> 24);
836 			return;
837 		case 0x00ff0000:
838 			fprintf(f, "\n  match IP dsfield %#x",
839 				ntohl(key->val) >> 16);
840 			return;
841 		}
842 		break;
843 	case 8:
844 		if (ntohl(key->mask) == 0x00ff0000) {
845 			fprintf(f, "\n  match IP protocol %d",
846 				ntohl(key->val) >> 16);
847 			return;
848 		}
849 		break;
850 	case 12:
851 	case 16: {
852 			int bits = mask2bits(key->mask);
853 
854 			if (bits >= 0) {
855 				fprintf(f, "\n  %s %s/%d",
856 					key->off == 12 ? "match IP src" : "match IP dst",
857 					inet_ntop(AF_INET, &key->val,
858 						  abuf, sizeof(abuf)),
859 					bits);
860 				return;
861 			}
862 		}
863 		break;
864 
865 	case 20:
866 		switch (ntohl(key->mask)) {
867 		case 0x0000ffff:
868 			fprintf(f, "\n  match dport %u",
869 				ntohl(key->val) & 0xffff);
870 			return;
871 		case 0xffff0000:
872 			fprintf(f, "\n  match sport %u",
873 				ntohl(key->val) >> 16);
874 			return;
875 		case 0xffffffff:
876 			fprintf(f, "\n  match dport %u, match sport %u",
877 				ntohl(key->val) & 0xffff,
878 				ntohl(key->val) >> 16);
879 
880 			return;
881 		}
882 		/* XXX: Default print_raw */
883 	}
884 }
885 
print_ipv6(FILE * f,const struct tc_u32_key * key)886 static void print_ipv6(FILE *f, const struct tc_u32_key *key)
887 {
888 	char abuf[256];
889 
890 	switch (key->off) {
891 	case 0:
892 		switch (ntohl(key->mask)) {
893 		case 0x0f000000:
894 			fprintf(f, "\n  match IP ihl %u",
895 				ntohl(key->val) >> 24);
896 			return;
897 		case 0x00ff0000:
898 			fprintf(f, "\n  match IP dsfield %#x",
899 				ntohl(key->val) >> 16);
900 			return;
901 		}
902 		break;
903 	case 8:
904 		if (ntohl(key->mask) == 0x00ff0000) {
905 			fprintf(f, "\n  match IP protocol %d",
906 				ntohl(key->val) >> 16);
907 			return;
908 		}
909 		break;
910 	case 12:
911 	case 16: {
912 			int bits = mask2bits(key->mask);
913 
914 			if (bits >= 0) {
915 				fprintf(f, "\n  %s %s/%d",
916 					key->off == 12 ? "match IP src" : "match IP dst",
917 					inet_ntop(AF_INET, &key->val,
918 						  abuf, sizeof(abuf)),
919 					bits);
920 				return;
921 			}
922 		}
923 		break;
924 
925 	case 20:
926 		switch (ntohl(key->mask)) {
927 		case 0x0000ffff:
928 			fprintf(f, "\n  match sport %u",
929 				ntohl(key->val) & 0xffff);
930 			return;
931 		case 0xffff0000:
932 			fprintf(f, "\n  match dport %u",
933 				ntohl(key->val) >> 16);
934 			return;
935 		case 0xffffffff:
936 			fprintf(f, "\n  match sport %u, match dport %u",
937 				ntohl(key->val) & 0xffff,
938 				ntohl(key->val) >> 16);
939 
940 			return;
941 		}
942 		/* XXX: Default print_raw */
943 	}
944 }
945 
print_raw(FILE * f,const struct tc_u32_key * key)946 static void print_raw(FILE *f, const struct tc_u32_key *key)
947 {
948 	fprintf(f, "\n  match %08x/%08x at %s%d",
949 		(unsigned int)ntohl(key->val),
950 		(unsigned int)ntohl(key->mask),
951 		key->offmask ? "nexthdr+" : "",
952 		key->off);
953 }
954 
955 static const struct {
956 	__u16 proto;
957 	__u16 pad;
958 	void (*pprinter)(FILE *f, const struct tc_u32_key *key);
959 } u32_pprinters[] = {
960 	{0,	   0, print_raw},
961 	{ETH_P_IP, 0, print_ipv4},
962 	{ETH_P_IPV6, 0, print_ipv6},
963 };
964 
show_keys(FILE * f,const struct tc_u32_key * key)965 static void show_keys(FILE *f, const struct tc_u32_key *key)
966 {
967 	int i = 0;
968 
969 	if (!show_pretty)
970 		goto show_k;
971 
972 	for (i = 0; i < ARRAY_SIZE(u32_pprinters); i++) {
973 		if (u32_pprinters[i].proto == ntohs(f_proto)) {
974 show_k:
975 			u32_pprinters[i].pprinter(f, key);
976 			return;
977 		}
978 	}
979 
980 	i = 0;
981 	goto show_k;
982 }
983 
u32_parse_opt(struct filter_util * qu,char * handle,int argc,char ** argv,struct nlmsghdr * n)984 static int u32_parse_opt(struct filter_util *qu, char *handle,
985 			 int argc, char **argv, struct nlmsghdr *n)
986 {
987 	struct {
988 		struct tc_u32_sel sel;
989 		struct tc_u32_key keys[128];
990 	} sel = {};
991 	struct tcmsg *t = NLMSG_DATA(n);
992 	struct rtattr *tail;
993 	int sel_ok = 0, terminal_ok = 0;
994 	int sample_ok = 0;
995 	__u32 htid = 0;
996 	__u32 order = 0;
997 	__u32 flags = 0;
998 
999 	if (handle && get_u32_handle(&t->tcm_handle, handle)) {
1000 		fprintf(stderr, "Illegal filter ID\n");
1001 		return -1;
1002 	}
1003 
1004 	if (argc == 0)
1005 		return 0;
1006 
1007 	tail = NLMSG_TAIL(n);
1008 	addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0);
1009 
1010 	while (argc > 0) {
1011 		if (matches(*argv, "match") == 0) {
1012 			NEXT_ARG();
1013 			if (parse_selector(&argc, &argv, &sel.sel, n)) {
1014 				fprintf(stderr, "Illegal \"match\"\n");
1015 				return -1;
1016 			}
1017 			sel_ok++;
1018 			continue;
1019 		} else if (matches(*argv, "offset") == 0) {
1020 			NEXT_ARG();
1021 			if (parse_offset(&argc, &argv, &sel.sel)) {
1022 				fprintf(stderr, "Illegal \"offset\"\n");
1023 				return -1;
1024 			}
1025 			continue;
1026 		} else if (matches(*argv, "hashkey") == 0) {
1027 			NEXT_ARG();
1028 			if (parse_hashkey(&argc, &argv, &sel.sel)) {
1029 				fprintf(stderr, "Illegal \"hashkey\"\n");
1030 				return -1;
1031 			}
1032 			continue;
1033 		} else if (matches(*argv, "classid") == 0 ||
1034 			   strcmp(*argv, "flowid") == 0) {
1035 			unsigned int flowid;
1036 
1037 			NEXT_ARG();
1038 			if (get_tc_classid(&flowid, *argv)) {
1039 				fprintf(stderr, "Illegal \"classid\"\n");
1040 				return -1;
1041 			}
1042 			addattr_l(n, MAX_MSG, TCA_U32_CLASSID, &flowid, 4);
1043 			sel.sel.flags |= TC_U32_TERMINAL;
1044 		} else if (matches(*argv, "divisor") == 0) {
1045 			unsigned int divisor;
1046 
1047 			NEXT_ARG();
1048 			if (get_unsigned(&divisor, *argv, 0) ||
1049 			    divisor == 0 ||
1050 			    divisor > 0x100 || ((divisor - 1) & divisor)) {
1051 				fprintf(stderr, "Illegal \"divisor\"\n");
1052 				return -1;
1053 			}
1054 			addattr_l(n, MAX_MSG, TCA_U32_DIVISOR, &divisor, 4);
1055 		} else if (matches(*argv, "order") == 0) {
1056 			NEXT_ARG();
1057 			if (get_u32(&order, *argv, 0)) {
1058 				fprintf(stderr, "Illegal \"order\"\n");
1059 				return -1;
1060 			}
1061 		} else if (strcmp(*argv, "link") == 0) {
1062 			unsigned int linkid;
1063 
1064 			NEXT_ARG();
1065 			if (get_u32_handle(&linkid, *argv)) {
1066 				fprintf(stderr, "Illegal \"link\"\n");
1067 				return -1;
1068 			}
1069 			if (linkid && TC_U32_NODE(linkid)) {
1070 				fprintf(stderr, "\"link\" must be a hash table.\n");
1071 				return -1;
1072 			}
1073 			addattr_l(n, MAX_MSG, TCA_U32_LINK, &linkid, 4);
1074 		} else if (strcmp(*argv, "ht") == 0) {
1075 			unsigned int ht;
1076 
1077 			NEXT_ARG();
1078 			if (get_u32_handle(&ht, *argv)) {
1079 				fprintf(stderr, "Illegal \"ht\"\n");
1080 				return -1;
1081 			}
1082 			if (handle && TC_U32_NODE(ht)) {
1083 				fprintf(stderr, "\"ht\" must be a hash table.\n");
1084 				return -1;
1085 			}
1086 			if (sample_ok)
1087 				htid = (htid & 0xFF000) | (ht & 0xFFF00000);
1088 			else
1089 				htid = (ht & 0xFFFFF000);
1090 		} else if (strcmp(*argv, "sample") == 0) {
1091 			__u32 hash;
1092 			unsigned int divisor = 0x100;
1093 			struct {
1094 				struct tc_u32_sel sel;
1095 				struct tc_u32_key keys[4];
1096 			} sel2 = {};
1097 
1098 			NEXT_ARG();
1099 			if (parse_selector(&argc, &argv, &sel2.sel, n)) {
1100 				fprintf(stderr, "Illegal \"sample\"\n");
1101 				return -1;
1102 			}
1103 			if (sel2.sel.nkeys != 1) {
1104 				fprintf(stderr, "\"sample\" must contain exactly ONE key.\n");
1105 				return -1;
1106 			}
1107 			if (*argv != 0 && strcmp(*argv, "divisor") == 0) {
1108 				NEXT_ARG();
1109 				if (get_unsigned(&divisor, *argv, 0) ||
1110 				    divisor == 0 || divisor > 0x100 ||
1111 				    ((divisor - 1) & divisor)) {
1112 					fprintf(stderr, "Illegal sample \"divisor\"\n");
1113 					return -1;
1114 				}
1115 				NEXT_ARG();
1116 			}
1117 			hash = sel2.sel.keys[0].val & sel2.sel.keys[0].mask;
1118 			hash ^= hash >> 16;
1119 			hash ^= hash >> 8;
1120 			htid = ((hash % divisor) << 12) | (htid & 0xFFF00000);
1121 			sample_ok = 1;
1122 			continue;
1123 		} else if (strcmp(*argv, "indev") == 0) {
1124 			char ind[IFNAMSIZ + 1] = {};
1125 
1126 			argc--;
1127 			argv++;
1128 			if (argc < 1) {
1129 				fprintf(stderr, "Illegal indev\n");
1130 				return -1;
1131 			}
1132 			strncpy(ind, *argv, sizeof(ind) - 1);
1133 			addattr_l(n, MAX_MSG, TCA_U32_INDEV, ind,
1134 				  strlen(ind) + 1);
1135 
1136 		} else if (matches(*argv, "action") == 0) {
1137 			NEXT_ARG();
1138 			if (parse_action(&argc, &argv, TCA_U32_ACT, n)) {
1139 				fprintf(stderr, "Illegal \"action\"\n");
1140 				return -1;
1141 			}
1142 			terminal_ok++;
1143 			continue;
1144 
1145 		} else if (matches(*argv, "police") == 0) {
1146 			NEXT_ARG();
1147 			if (parse_police(&argc, &argv, TCA_U32_POLICE, n)) {
1148 				fprintf(stderr, "Illegal \"police\"\n");
1149 				return -1;
1150 			}
1151 			terminal_ok++;
1152 			continue;
1153 		} else if (strcmp(*argv, "skip_hw") == 0) {
1154 			NEXT_ARG();
1155 			flags |= TCA_CLS_FLAGS_SKIP_HW;
1156 			continue;
1157 		} else if (strcmp(*argv, "skip_sw") == 0) {
1158 			NEXT_ARG();
1159 			flags |= TCA_CLS_FLAGS_SKIP_SW;
1160 			continue;
1161 		} else if (strcmp(*argv, "help") == 0) {
1162 			explain();
1163 			return -1;
1164 		} else {
1165 			fprintf(stderr, "What is \"%s\"?\n", *argv);
1166 			explain();
1167 			return -1;
1168 		}
1169 		argc--; argv++;
1170 	}
1171 
1172 	/* We dont necessarily need class/flowids */
1173 	if (terminal_ok)
1174 		sel.sel.flags |= TC_U32_TERMINAL;
1175 
1176 	if (order) {
1177 		if (TC_U32_NODE(t->tcm_handle) &&
1178 		    order != TC_U32_NODE(t->tcm_handle)) {
1179 			fprintf(stderr, "\"order\" contradicts \"handle\"\n");
1180 			return -1;
1181 		}
1182 		t->tcm_handle |= order;
1183 	}
1184 
1185 	if (htid)
1186 		addattr_l(n, MAX_MSG, TCA_U32_HASH, &htid, 4);
1187 	if (sel_ok)
1188 		addattr_l(n, MAX_MSG, TCA_U32_SEL, &sel,
1189 			  sizeof(sel.sel) +
1190 			  sel.sel.nkeys * sizeof(struct tc_u32_key));
1191 	if (flags) {
1192 		if (!(flags ^ (TCA_CLS_FLAGS_SKIP_HW |
1193 			       TCA_CLS_FLAGS_SKIP_SW))) {
1194 			fprintf(stderr,
1195 				"skip_hw and skip_sw are mutually exclusive\n");
1196 			return -1;
1197 		}
1198 		addattr_l(n, MAX_MSG, TCA_U32_FLAGS, &flags, 4);
1199 	}
1200 
1201 	tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
1202 	return 0;
1203 }
1204 
u32_print_opt(struct filter_util * qu,FILE * f,struct rtattr * opt,__u32 handle)1205 static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt,
1206 			 __u32 handle)
1207 {
1208 	struct rtattr *tb[TCA_U32_MAX + 1];
1209 	struct tc_u32_sel *sel = NULL;
1210 	struct tc_u32_pcnt *pf = NULL;
1211 
1212 	if (opt == NULL)
1213 		return 0;
1214 
1215 	parse_rtattr_nested(tb, TCA_U32_MAX, opt);
1216 
1217 	if (handle) {
1218 		SPRINT_BUF(b1);
1219 		fprintf(f, "fh %s ", sprint_u32_handle(handle, b1));
1220 	}
1221 
1222 	if (TC_U32_NODE(handle))
1223 		fprintf(f, "order %d ", TC_U32_NODE(handle));
1224 
1225 	if (tb[TCA_U32_SEL]) {
1226 		if (RTA_PAYLOAD(tb[TCA_U32_SEL])  < sizeof(*sel))
1227 			return -1;
1228 
1229 		sel = RTA_DATA(tb[TCA_U32_SEL]);
1230 	}
1231 
1232 	if (tb[TCA_U32_DIVISOR]) {
1233 		fprintf(f, "ht divisor %d ",
1234 			rta_getattr_u32(tb[TCA_U32_DIVISOR]));
1235 	} else if (tb[TCA_U32_HASH]) {
1236 		__u32 htid = rta_getattr_u32(tb[TCA_U32_HASH]);
1237 
1238 		fprintf(f, "key ht %x bkt %x ", TC_U32_USERHTID(htid),
1239 			TC_U32_HASH(htid));
1240 	} else {
1241 		fprintf(f, "??? ");
1242 	}
1243 	if (tb[TCA_U32_CLASSID]) {
1244 		SPRINT_BUF(b1);
1245 		fprintf(f, "%sflowid %s ",
1246 			!sel || !(sel->flags & TC_U32_TERMINAL) ? "*" : "",
1247 			sprint_tc_classid(rta_getattr_u32(tb[TCA_U32_CLASSID]),
1248 					  b1));
1249 	} else if (sel && sel->flags & TC_U32_TERMINAL) {
1250 		fprintf(f, "terminal flowid ??? ");
1251 	}
1252 	if (tb[TCA_U32_LINK]) {
1253 		SPRINT_BUF(b1);
1254 		fprintf(f, "link %s ",
1255 			sprint_u32_handle(rta_getattr_u32(tb[TCA_U32_LINK]),
1256 					  b1));
1257 	}
1258 
1259 	if (tb[TCA_U32_FLAGS]) {
1260 		__u32 flags = rta_getattr_u32(tb[TCA_U32_FLAGS]);
1261 
1262 		if (flags & TCA_CLS_FLAGS_SKIP_HW)
1263 			fprintf(f, "skip_hw ");
1264 		if (flags & TCA_CLS_FLAGS_SKIP_SW)
1265 			fprintf(f, "skip_sw ");
1266 
1267 		if (flags & TCA_CLS_FLAGS_IN_HW)
1268 			fprintf(f, "in_hw ");
1269 		else if (flags & TCA_CLS_FLAGS_NOT_IN_HW)
1270 			fprintf(f, "not_in_hw ");
1271 	}
1272 
1273 	if (tb[TCA_U32_PCNT]) {
1274 		if (RTA_PAYLOAD(tb[TCA_U32_PCNT])  < sizeof(*pf)) {
1275 			fprintf(f, "Broken perf counters\n");
1276 			return -1;
1277 		}
1278 		pf = RTA_DATA(tb[TCA_U32_PCNT]);
1279 	}
1280 
1281 	if (sel && show_stats && NULL != pf)
1282 		fprintf(f, " (rule hit %llu success %llu)",
1283 			(unsigned long long) pf->rcnt,
1284 			(unsigned long long) pf->rhit);
1285 
1286 	if (tb[TCA_U32_MARK]) {
1287 		struct tc_u32_mark *mark = RTA_DATA(tb[TCA_U32_MARK]);
1288 
1289 		if (RTA_PAYLOAD(tb[TCA_U32_MARK]) < sizeof(*mark)) {
1290 			fprintf(f, "\n  Invalid mark (kernel&iproute2 mismatch)\n");
1291 		} else {
1292 			fprintf(f, "\n  mark 0x%04x 0x%04x (success %d)",
1293 				mark->val, mark->mask, mark->success);
1294 		}
1295 	}
1296 
1297 	if (sel) {
1298 		if (sel->nkeys) {
1299 			int i;
1300 
1301 			for (i = 0; i < sel->nkeys; i++) {
1302 				show_keys(f, sel->keys + i);
1303 				if (show_stats && NULL != pf)
1304 					fprintf(f, " (success %llu ) ",
1305 						(unsigned long long) pf->kcnts[i]);
1306 			}
1307 		}
1308 
1309 		if (sel->flags & (TC_U32_VAROFFSET | TC_U32_OFFSET)) {
1310 			fprintf(f, "\n    offset ");
1311 			if (sel->flags & TC_U32_VAROFFSET)
1312 				fprintf(f, "%04x>>%d at %d ",
1313 					ntohs(sel->offmask),
1314 					sel->offshift,  sel->offoff);
1315 			if (sel->off)
1316 				fprintf(f, "plus %d ", sel->off);
1317 		}
1318 		if (sel->flags & TC_U32_EAT)
1319 			fprintf(f, " eat ");
1320 
1321 		if (sel->hmask) {
1322 			fprintf(f, "\n    hash mask %08x at %d ",
1323 				(unsigned int)htonl(sel->hmask), sel->hoff);
1324 		}
1325 	}
1326 
1327 	if (tb[TCA_U32_POLICE]) {
1328 		fprintf(f, "\n");
1329 		tc_print_police(f, tb[TCA_U32_POLICE]);
1330 	}
1331 
1332 	if (tb[TCA_U32_INDEV]) {
1333 		struct rtattr *idev = tb[TCA_U32_INDEV];
1334 
1335 		fprintf(f, "\n  input dev %s\n", rta_getattr_str(idev));
1336 	}
1337 
1338 	if (tb[TCA_U32_ACT])
1339 		tc_print_action(f, tb[TCA_U32_ACT], 0);
1340 
1341 	return 0;
1342 }
1343 
1344 struct filter_util u32_filter_util = {
1345 	.id = "u32",
1346 	.parse_fopt = u32_parse_opt,
1347 	.print_fopt = u32_print_opt,
1348 };
1349