blob: 92c1fcd4512c0794bda91d67b1330d9a17621623 [file] [log] [blame]
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001/*
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>
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +000010 * Match mark added by Catalin(ux aka Dino) BOIE <catab at umbrella.ro> [5 nov 2004]
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000011 *
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>
osdl.net!shemminger2373fde2004-08-13 23:54:55 +000023#include <linux/if.h>
jamal1750abe2008-04-20 10:49:24 -040024#include <linux/if_ether.h>
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000025
26#include "utils.h"
27#include "tc_util.h"
28
Stephen Hemminger44dcfe82008-05-09 15:42:34 -070029extern int show_pretty;
30
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000031static void explain(void)
32{
Stephen Hemminger62281202016-06-08 16:45:26 -070033 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");
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000045}
46
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -080047static int get_u32_handle(__u32 *handle, const char *str)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000048{
Luca Lemmodd0c8d12016-03-16 17:56:12 +010049 __u32 htid = 0, hash = 0, nodeid = 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000050 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;
Luca Lemmodd0c8d12016-03-16 17:56:12 +010060 if (htid >= 0x1000)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000061 return -1;
62 if (*tmp) {
Phil Sutter40eb7372015-10-23 19:21:23 +020063 str = tmp + 1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000064 hash = strtoul(str, &tmp, 16);
65 if (tmp == str && *str != ':' && *str != 0)
66 return -1;
Luca Lemmodd0c8d12016-03-16 17:56:12 +010067 if (hash >= 0x100)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000068 return -1;
69 if (*tmp) {
Phil Sutter40eb7372015-10-23 19:21:23 +020070 str = tmp + 1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000071 nodeid = strtoul(str, &tmp, 16);
72 if (tmp == str && *str != 0)
73 return -1;
Luca Lemmodd0c8d12016-03-16 17:56:12 +010074 if (nodeid >= 0x1000)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000075 return -1;
76 }
77 }
78 *handle = (htid<<20)|(hash<<12)|nodeid;
79 return 0;
80}
81
Luca Lemmo725f2a82016-03-16 17:56:13 +010082static char *sprint_u32_handle(__u32 handle, char *buf)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000083{
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);
Stephen Hemminger32a121c2016-03-21 11:48:36 -070096
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000097 bsize -= l;
98 b += l;
99 }
100 if (nodeid|hash) {
101 if (hash) {
102 int l = snprintf(b, bsize, "%x", hash);
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700103
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000104 bsize -= l;
105 b += l;
106 }
107 if (nodeid) {
108 int l = snprintf(b, bsize, ":%x", nodeid);
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700109
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000110 bsize -= l;
111 b += l;
112 }
113 }
114 if (show_raw)
115 snprintf(b, bsize, "[%08x] ", handle);
116 return buf;
117}
118
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800119static int pack_key(struct tc_u32_sel *sel, __u32 key, __u32 mask,
120 int off, int offmask)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000121{
122 int i;
123 int hwm = sel->nkeys;
124
125 key &= mask;
126
Luca Lemmodd0c8d12016-03-16 17:56:12 +0100127 for (i = 0; i < hwm; i++) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000128 if (sel->keys[i].off == off && sel->keys[i].offmask == offmask) {
Phil Sutter40eb7372015-10-23 19:21:23 +0200129 __u32 intersect = mask & sel->keys[i].mask;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000130
Phil Sutter40eb7372015-10-23 19:21:23 +0200131 if ((key ^ sel->keys[i].val) & intersect)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000132 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
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800151static int pack_key32(struct tc_u32_sel *sel, __u32 key, __u32 mask,
152 int off, int offmask)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000153{
154 key = htonl(key);
155 mask = htonl(mask);
156 return pack_key(sel, key, mask, off, offmask);
157}
158
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800159static int pack_key16(struct tc_u32_sel *sel, __u32 key, __u32 mask,
160 int off, int offmask)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000161{
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
Jamal Hadi Salim82e6efe2016-05-25 06:11:55 -0400176static int pack_key8(struct tc_u32_sel *sel, __u32 key, __u32 mask, int off,
177 int offmask)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000178{
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
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -0800200static int parse_at(int *argc_p, char ***argv_p, int *off, int *offmask)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000201{
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
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800229static int parse_u32(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
230 int off, int offmask)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000231{
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
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800261static int parse_u16(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
262 int off, int offmask)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000263{
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
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800292static int parse_u8(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
293 int off, int offmask)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000294{
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
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800327static int parse_ip_addr(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
328 int off)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000329{
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)
Phil Sutter40eb7372015-10-23 19:21:23 +0200352 mask = htonl(0xFFFFFFFF << (32 - addr.bitlen));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000353 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
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800362static int parse_ip6_addr(int *argc_p, char ***argv_p,
363 struct tc_u32_sel *sel, int off)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000364{
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;
Phil Sutter40eb7372015-10-23 19:21:23 +0200387 for (i = 0; i < plen; i += 32) {
Luca Lemmo725f2a82016-03-16 17:56:13 +0100388 /* if (((i + 31) & ~0x1F) <= plen) { */
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800389 if (i + 31 <= plen) {
Phil Sutter40eb7372015-10-23 19:21:23 +0200390 res = pack_key(sel, addr.data[i / 32],
391 0xFFFFFFFF, off + 4 * (i / 32), offmask);
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800392 if (res < 0)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000393 return -1;
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800394 } else if (i < plen) {
Phil Sutter40eb7372015-10-23 19:21:23 +0200395 __u32 mask = htonl(0xFFFFFFFF << (32 - (plen - i)));
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700396
Phil Sutter40eb7372015-10-23 19:21:23 +0200397 res = pack_key(sel, addr.data[i / 32],
398 mask, off + 4 * (i / 32), offmask);
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800399 if (res < 0)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000400 return -1;
401 }
402 }
403 res = 0;
404
405 *argc_p = argc;
406 *argv_p = argv;
407 return res;
408}
409
Petr Lautrbach01564122010-06-14 03:36:28 +0000410static int parse_ip6_class(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
411{
412 int res = -1;
413 int argc = *argc_p;
414 char **argv = *argv_p;
415 __u32 key;
416 __u32 mask;
417 int off = 0;
418 int offmask = 0;
419
420 if (argc < 2)
421 return -1;
422
423 if (get_u32(&key, *argv, 0))
424 return -1;
425 argc--; argv++;
426
427 if (get_u32(&mask, *argv, 16))
428 return -1;
429 argc--; argv++;
430
431 if (key > 0xFF || mask > 0xFF)
432 return -1;
433
434 key <<= 20;
435 mask <<= 20;
436 key = htonl(key);
437 mask = htonl(mask);
438
Stephen Hemmingerd7ac9ad2011-03-09 10:42:35 -0800439 res = pack_key(sel, key, mask, off, offmask);
440 if (res < 0)
Petr Lautrbach01564122010-06-14 03:36:28 +0000441 return -1;
442
443 *argc_p = argc;
444 *argv_p = argv;
445 return 0;
446}
447
Stephen Hemmingerb4d41f42009-04-15 15:39:34 -0700448static int parse_ether_addr(int *argc_p, char ***argv_p,
449 struct tc_u32_sel *sel, int off)
450{
451 int res = -1;
452 int argc = *argc_p;
453 char **argv = *argv_p;
454 __u8 addr[6];
455 int offmask = 0;
Stephen Hemmingerb4d41f42009-04-15 15:39:34 -0700456 int i;
457
458 if (argc < 1)
459 return -1;
460
461 if (sscanf(*argv, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
462 addr + 0, addr + 1, addr + 2,
463 addr + 3, addr + 4, addr + 5) != 6) {
464 fprintf(stderr, "parse_ether_addr: improperly formed address '%s'\n",
465 *argv);
466 return -1;
467 }
468
469 argc--; argv++;
470 if (argc > 0 && strcmp(argv[0], "at") == 0) {
471 NEXT_ARG();
472 if (parse_at(&argc, &argv, &off, &offmask))
473 return -1;
474 }
475
Stephen Hemmingere3d153c2010-08-02 11:55:30 -0700476 for (i = 0; i < 6; i++) {
477 res = pack_key8(sel, addr[i], 0xFF, off + i, offmask);
Stephen Hemmingerb4d41f42009-04-15 15:39:34 -0700478 if (res < 0)
479 return -1;
480 }
481
482 *argc_p = argc;
483 *argv_p = argv;
484 return res;
485}
486
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000487static int parse_ip(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
488{
489 int res = -1;
490 int argc = *argc_p;
491 char **argv = *argv_p;
492
493 if (argc < 2)
494 return -1;
495
496 if (strcmp(*argv, "src") == 0) {
497 NEXT_ARG();
498 res = parse_ip_addr(&argc, &argv, sel, 12);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700499 } else if (strcmp(*argv, "dst") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000500 NEXT_ARG();
501 res = parse_ip_addr(&argc, &argv, sel, 16);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700502 } else if (strcmp(*argv, "tos") == 0 ||
Phil Sutter40eb7372015-10-23 19:21:23 +0200503 matches(*argv, "dsfield") == 0 ||
504 matches(*argv, "precedence") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000505 NEXT_ARG();
506 res = parse_u8(&argc, &argv, sel, 1, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700507 } else if (strcmp(*argv, "ihl") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000508 NEXT_ARG();
509 res = parse_u8(&argc, &argv, sel, 0, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700510 } else if (strcmp(*argv, "protocol") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000511 NEXT_ARG();
512 res = parse_u8(&argc, &argv, sel, 9, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700513 } else if (strcmp(*argv, "nofrag") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000514 argc--; argv++;
515 res = pack_key16(sel, 0, 0x3FFF, 6, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700516 } else if (strcmp(*argv, "firstfrag") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000517 argc--; argv++;
Hiroaki SHIMODA690b11f2012-07-10 19:44:16 +0900518 res = pack_key16(sel, 0x2000, 0x3FFF, 6, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700519 } else if (strcmp(*argv, "df") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000520 argc--; argv++;
521 res = pack_key16(sel, 0x4000, 0x4000, 6, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700522 } else if (strcmp(*argv, "mf") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000523 argc--; argv++;
524 res = pack_key16(sel, 0x2000, 0x2000, 6, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700525 } else if (strcmp(*argv, "dport") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000526 NEXT_ARG();
527 res = parse_u16(&argc, &argv, sel, 22, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700528 } else if (strcmp(*argv, "sport") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000529 NEXT_ARG();
530 res = parse_u16(&argc, &argv, sel, 20, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700531 } else if (strcmp(*argv, "icmp_type") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000532 NEXT_ARG();
533 res = parse_u8(&argc, &argv, sel, 20, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700534 } else if (strcmp(*argv, "icmp_code") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000535 NEXT_ARG();
Hiroaki SHIMODA1d62f992012-07-10 18:53:18 +0900536 res = parse_u8(&argc, &argv, sel, 21, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700537 } else
538 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000539
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000540 *argc_p = argc;
541 *argv_p = argv;
542 return res;
543}
Stephen Hemminger3d0b7432014-12-20 15:47:17 -0800544
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000545static int parse_ip6(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
546{
547 int res = -1;
548 int argc = *argc_p;
549 char **argv = *argv_p;
550
551 if (argc < 2)
552 return -1;
553
554 if (strcmp(*argv, "src") == 0) {
555 NEXT_ARG();
556 res = parse_ip6_addr(&argc, &argv, sel, 8);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700557 } else if (strcmp(*argv, "dst") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000558 NEXT_ARG();
559 res = parse_ip6_addr(&argc, &argv, sel, 24);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700560 } else if (strcmp(*argv, "priority") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000561 NEXT_ARG();
Petr Lautrbach01564122010-06-14 03:36:28 +0000562 res = parse_ip6_class(&argc, &argv, sel);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700563 } else if (strcmp(*argv, "protocol") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000564 NEXT_ARG();
565 res = parse_u8(&argc, &argv, sel, 6, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700566 } else if (strcmp(*argv, "flowlabel") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000567 NEXT_ARG();
568 res = parse_u32(&argc, &argv, sel, 0, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700569 } else if (strcmp(*argv, "dport") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000570 NEXT_ARG();
571 res = parse_u16(&argc, &argv, sel, 42, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700572 } else if (strcmp(*argv, "sport") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000573 NEXT_ARG();
574 res = parse_u16(&argc, &argv, sel, 40, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700575 } else if (strcmp(*argv, "icmp_type") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000576 NEXT_ARG();
577 res = parse_u8(&argc, &argv, sel, 40, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700578 } else if (strcmp(*argv, "icmp_code") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000579 NEXT_ARG();
580 res = parse_u8(&argc, &argv, sel, 41, 1);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700581 } else
582 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000583
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000584 *argc_p = argc;
585 *argv_p = argv;
586 return res;
587}
588
Stephen Hemmingerb4d41f42009-04-15 15:39:34 -0700589static int parse_ether(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
590{
591 int res = -1;
592 int argc = *argc_p;
593 char **argv = *argv_p;
594
595 if (argc < 2)
596 return -1;
597
598 if (strcmp(*argv, "src") == 0) {
599 NEXT_ARG();
600 res = parse_ether_addr(&argc, &argv, sel, -8);
601 } else if (strcmp(*argv, "dst") == 0) {
602 NEXT_ARG();
603 res = parse_ether_addr(&argc, &argv, sel, -14);
604 } else {
605 fprintf(stderr, "Unknown match: ether %s\n", *argv);
606 return -1;
607 }
608
609 *argc_p = argc;
610 *argv_p = argv;
611 return res;
612}
613
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000614#define parse_tcp parse_udp
615static int parse_udp(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
616{
617 int res = -1;
618 int argc = *argc_p;
619 char **argv = *argv_p;
620
621 if (argc < 2)
622 return -1;
623
624 if (strcmp(*argv, "src") == 0) {
625 NEXT_ARG();
626 res = parse_u16(&argc, &argv, sel, 0, -1);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700627 } else if (strcmp(*argv, "dst") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000628 NEXT_ARG();
629 res = parse_u16(&argc, &argv, sel, 2, -1);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700630 } else
631 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000632
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000633 *argc_p = argc;
634 *argv_p = argv;
635 return res;
636}
637
Stephen Hemminger6b1ac652007-12-31 10:29:52 -0800638
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000639static int parse_icmp(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
640{
641 int res = -1;
642 int argc = *argc_p;
643 char **argv = *argv_p;
644
645 if (argc < 2)
646 return -1;
647
648 if (strcmp(*argv, "type") == 0) {
649 NEXT_ARG();
650 res = parse_u8(&argc, &argv, sel, 0, -1);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700651 } else if (strcmp(*argv, "code") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000652 NEXT_ARG();
653 res = parse_u8(&argc, &argv, sel, 1, -1);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700654 } else
655 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000656
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000657 *argc_p = argc;
658 *argv_p = argv;
659 return res;
660}
661
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +0000662static int parse_mark(int *argc_p, char ***argv_p, struct nlmsghdr *n)
663{
664 int res = -1;
665 int argc = *argc_p;
666 char **argv = *argv_p;
667 struct tc_u32_mark mark;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000668
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +0000669 if (argc <= 1)
670 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000671
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +0000672 if (get_u32(&mark.val, *argv, 0)) {
673 fprintf(stderr, "Illegal \"mark\" value\n");
674 return -1;
675 }
676 NEXT_ARG();
677
678 if (get_u32(&mark.mask, *argv, 0)) {
679 fprintf(stderr, "Illegal \"mark\" mask\n");
680 return -1;
681 }
682 NEXT_ARG();
683
684 if ((mark.val & mark.mask) != mark.val) {
685 fprintf(stderr, "Illegal \"mark\" (impossible combination)\n");
686 return -1;
687 }
688
689 addattr_l(n, MAX_MSG, TCA_U32_MARK, &mark, sizeof(mark));
690 res = 0;
691
692 *argc_p = argc;
693 *argv_p = argv;
694 return res;
695}
696
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800697static int parse_selector(int *argc_p, char ***argv_p,
698 struct tc_u32_sel *sel, struct nlmsghdr *n)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000699{
700 int argc = *argc_p;
701 char **argv = *argv_p;
702 int res = -1;
703
704 if (argc <= 0)
705 return -1;
706
707 if (matches(*argv, "u32") == 0) {
708 NEXT_ARG();
709 res = parse_u32(&argc, &argv, sel, 0, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700710 } else if (matches(*argv, "u16") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000711 NEXT_ARG();
712 res = parse_u16(&argc, &argv, sel, 0, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700713 } else if (matches(*argv, "u8") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000714 NEXT_ARG();
715 res = parse_u8(&argc, &argv, sel, 0, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700716 } else if (matches(*argv, "ip") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000717 NEXT_ARG();
718 res = parse_ip(&argc, &argv, sel);
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700719 } else if (matches(*argv, "ip6") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000720 NEXT_ARG();
721 res = parse_ip6(&argc, &argv, sel);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700722 } else if (matches(*argv, "udp") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000723 NEXT_ARG();
724 res = parse_udp(&argc, &argv, sel);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700725 } else if (matches(*argv, "tcp") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000726 NEXT_ARG();
727 res = parse_tcp(&argc, &argv, sel);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700728 } else if (matches(*argv, "icmp") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000729 NEXT_ARG();
730 res = parse_icmp(&argc, &argv, sel);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700731 } else if (matches(*argv, "mark") == 0) {
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +0000732 NEXT_ARG();
733 res = parse_mark(&argc, &argv, n);
Stephen Hemmingerb4d41f42009-04-15 15:39:34 -0700734 } else if (matches(*argv, "ether") == 0) {
735 NEXT_ARG();
736 res = parse_ether(&argc, &argv, sel);
Stephen Hemminger3d0b7432014-12-20 15:47:17 -0800737 } else
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700738 return -1;
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +0000739
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000740 *argc_p = argc;
741 *argv_p = argv;
742 return res;
743}
744
745static int parse_offset(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
746{
747 int argc = *argc_p;
748 char **argv = *argv_p;
749
750 while (argc > 0) {
751 if (matches(*argv, "plus") == 0) {
752 int off;
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700753
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000754 NEXT_ARG();
755 if (get_integer(&off, *argv, 0))
756 return -1;
757 sel->off = off;
758 sel->flags |= TC_U32_OFFSET;
759 } else if (matches(*argv, "at") == 0) {
760 int off;
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700761
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000762 NEXT_ARG();
763 if (get_integer(&off, *argv, 0))
764 return -1;
765 sel->offoff = off;
766 if (off%2) {
767 fprintf(stderr, "offset \"at\" must be even\n");
768 return -1;
769 }
770 sel->flags |= TC_U32_VAROFFSET;
771 } else if (matches(*argv, "mask") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000772 NEXT_ARG();
Sabrina Dubroca9f7401f2016-06-03 16:45:46 +0200773 if (get_be16(&sel->offmask, *argv, 16))
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000774 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000775 sel->flags |= TC_U32_VAROFFSET;
776 } else if (matches(*argv, "shift") == 0) {
777 int shift;
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700778
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000779 NEXT_ARG();
780 if (get_integer(&shift, *argv, 0))
781 return -1;
782 sel->offshift = shift;
783 sel->flags |= TC_U32_VAROFFSET;
784 } else if (matches(*argv, "eat") == 0) {
785 sel->flags |= TC_U32_EAT;
786 } else {
787 break;
788 }
789 argc--; argv++;
790 }
791
792 *argc_p = argc;
793 *argv_p = argv;
794 return 0;
795}
796
797static int parse_hashkey(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
798{
799 int argc = *argc_p;
800 char **argv = *argv_p;
801
802 while (argc > 0) {
803 if (matches(*argv, "mask") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000804 NEXT_ARG();
Sabrina Dubroca9f7401f2016-06-03 16:45:46 +0200805 if (get_be32(&sel->hmask, *argv, 16))
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000806 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000807 } else if (matches(*argv, "at") == 0) {
808 int num;
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700809
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000810 NEXT_ARG();
811 if (get_integer(&num, *argv, 0))
812 return -1;
813 if (num%4)
814 return -1;
815 sel->hoff = num;
816 } else {
817 break;
818 }
819 argc--; argv++;
820 }
821
822 *argc_p = argc;
823 *argv_p = argv;
824 return 0;
825}
826
jamal1750abe2008-04-20 10:49:24 -0400827static void print_ipv4(FILE *f, const struct tc_u32_key *key)
Stephen Hemminger6b1ac652007-12-31 10:29:52 -0800828{
829 char abuf[256];
830
Stephen Hemminger6b1ac652007-12-31 10:29:52 -0800831 switch (key->off) {
Stephen Hemminger4c9ffc22008-02-18 11:35:29 -0800832 case 0:
833 switch (ntohl(key->mask)) {
834 case 0x0f000000:
Jamal Hadi Salim82e6efe2016-05-25 06:11:55 -0400835 fprintf(f, "\n match IP ihl %u",
836 ntohl(key->val) >> 24);
Stephen Hemminger4c9ffc22008-02-18 11:35:29 -0800837 return;
838 case 0x00ff0000:
Jamal Hadi Salim82e6efe2016-05-25 06:11:55 -0400839 fprintf(f, "\n match IP dsfield %#x",
840 ntohl(key->val) >> 16);
Stephen Hemminger4c9ffc22008-02-18 11:35:29 -0800841 return;
842 }
843 break;
844 case 8:
845 if (ntohl(key->mask) == 0x00ff0000) {
Jamal Hadi Salim82e6efe2016-05-25 06:11:55 -0400846 fprintf(f, "\n match IP protocol %d",
847 ntohl(key->val) >> 16);
Stephen Hemminger4c9ffc22008-02-18 11:35:29 -0800848 return;
849 }
850 break;
Stephen Hemminger6b1ac652007-12-31 10:29:52 -0800851 case 12:
852 case 16: {
853 int bits = mask2bits(key->mask);
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700854
Stephen Hemminger6b1ac652007-12-31 10:29:52 -0800855 if (bits >= 0) {
Stephen Hemminger3d0b7432014-12-20 15:47:17 -0800856 fprintf(f, "\n %s %s/%d",
jamal1750abe2008-04-20 10:49:24 -0400857 key->off == 12 ? "match IP src" : "match IP dst",
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800858 inet_ntop(AF_INET, &key->val,
859 abuf, sizeof(abuf)),
Stephen Hemminger6b1ac652007-12-31 10:29:52 -0800860 bits);
861 return;
862 }
863 }
864 break;
865
866 case 20:
Stephen Hemminger4c9ffc22008-02-18 11:35:29 -0800867 switch (ntohl(key->mask)) {
868 case 0x0000ffff:
Stephen Hemmingerbcd7abd2011-05-19 09:19:17 -0700869 fprintf(f, "\n match dport %u",
Stephen Hemminger4c9ffc22008-02-18 11:35:29 -0800870 ntohl(key->val) & 0xffff);
871 return;
872 case 0xffff0000:
Stephen Hemmingerbcd7abd2011-05-19 09:19:17 -0700873 fprintf(f, "\n match sport %u",
Stephen Hemminger4c9ffc22008-02-18 11:35:29 -0800874 ntohl(key->val) >> 16);
875 return;
876 case 0xffffffff:
Stephen Hemmingerbcd7abd2011-05-19 09:19:17 -0700877 fprintf(f, "\n match dport %u, match sport %u",
Stephen Hemminger4c9ffc22008-02-18 11:35:29 -0800878 ntohl(key->val) & 0xffff,
879 ntohl(key->val) >> 16);
880
Stephen Hemminger6b1ac652007-12-31 10:29:52 -0800881 return;
882 }
jamal1750abe2008-04-20 10:49:24 -0400883 /* XXX: Default print_raw */
Stephen Hemminger6b1ac652007-12-31 10:29:52 -0800884 }
jamal1750abe2008-04-20 10:49:24 -0400885}
Stephen Hemminger6b1ac652007-12-31 10:29:52 -0800886
Stephen Hemmingerd13cee62009-05-26 15:14:29 -0700887static void print_ipv6(FILE *f, const struct tc_u32_key *key)
888{
889 char abuf[256];
890
891 switch (key->off) {
892 case 0:
893 switch (ntohl(key->mask)) {
894 case 0x0f000000:
Jamal Hadi Salim82e6efe2016-05-25 06:11:55 -0400895 fprintf(f, "\n match IP ihl %u",
896 ntohl(key->val) >> 24);
Stephen Hemmingerd13cee62009-05-26 15:14:29 -0700897 return;
898 case 0x00ff0000:
Jamal Hadi Salim82e6efe2016-05-25 06:11:55 -0400899 fprintf(f, "\n match IP dsfield %#x",
900 ntohl(key->val) >> 16);
Stephen Hemmingerd13cee62009-05-26 15:14:29 -0700901 return;
902 }
903 break;
904 case 8:
905 if (ntohl(key->mask) == 0x00ff0000) {
Jamal Hadi Salim82e6efe2016-05-25 06:11:55 -0400906 fprintf(f, "\n match IP protocol %d",
907 ntohl(key->val) >> 16);
Stephen Hemmingerd13cee62009-05-26 15:14:29 -0700908 return;
909 }
910 break;
911 case 12:
912 case 16: {
913 int bits = mask2bits(key->mask);
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700914
Stephen Hemmingerd13cee62009-05-26 15:14:29 -0700915 if (bits >= 0) {
Stephen Hemminger3d0b7432014-12-20 15:47:17 -0800916 fprintf(f, "\n %s %s/%d",
Stephen Hemmingerd13cee62009-05-26 15:14:29 -0700917 key->off == 12 ? "match IP src" : "match IP dst",
918 inet_ntop(AF_INET, &key->val,
919 abuf, sizeof(abuf)),
920 bits);
921 return;
922 }
923 }
924 break;
925
926 case 20:
927 switch (ntohl(key->mask)) {
928 case 0x0000ffff:
929 fprintf(f, "\n match sport %u",
930 ntohl(key->val) & 0xffff);
931 return;
932 case 0xffff0000:
933 fprintf(f, "\n match dport %u",
934 ntohl(key->val) >> 16);
935 return;
936 case 0xffffffff:
937 fprintf(f, "\n match sport %u, match dport %u",
938 ntohl(key->val) & 0xffff,
939 ntohl(key->val) >> 16);
940
941 return;
942 }
943 /* XXX: Default print_raw */
944 }
945}
946
jamal1750abe2008-04-20 10:49:24 -0400947static void print_raw(FILE *f, const struct tc_u32_key *key)
948{
Stephen Hemminger3d0b7432014-12-20 15:47:17 -0800949 fprintf(f, "\n match %08x/%08x at %s%d",
Stephen Hemminger6b1ac652007-12-31 10:29:52 -0800950 (unsigned int)ntohl(key->val),
951 (unsigned int)ntohl(key->mask),
952 key->offmask ? "nexthdr+" : "",
953 key->off);
954}
955
jamal1750abe2008-04-20 10:49:24 -0400956static const struct {
957 __u16 proto;
958 __u16 pad;
959 void (*pprinter)(FILE *f, const struct tc_u32_key *key);
960} u32_pprinters[] = {
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700961 {0, 0, print_raw},
jamal1750abe2008-04-20 10:49:24 -0400962 {ETH_P_IP, 0, print_ipv4},
Stephen Hemmingerd13cee62009-05-26 15:14:29 -0700963 {ETH_P_IPV6, 0, print_ipv6},
jamal1750abe2008-04-20 10:49:24 -0400964};
965
966static void show_keys(FILE *f, const struct tc_u32_key *key)
967{
968 int i = 0;
969
970 if (!show_pretty)
971 goto show_k;
972
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700973 for (i = 0; i < ARRAY_SIZE(u32_pprinters); i++) {
jamal1750abe2008-04-20 10:49:24 -0400974 if (u32_pprinters[i].proto == ntohs(f_proto)) {
975show_k:
976 u32_pprinters[i].pprinter(f, key);
977 return;
978 }
979 }
980
981 i = 0;
982 goto show_k;
983}
984
985static int u32_parse_opt(struct filter_util *qu, char *handle,
Stephen Hemminger6b1ac652007-12-31 10:29:52 -0800986 int argc, char **argv, struct nlmsghdr *n)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000987{
988 struct {
989 struct tc_u32_sel sel;
990 struct tc_u32_key keys[128];
Phil Sutterd17b1362016-07-18 16:48:42 +0200991 } sel = {};
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000992 struct tcmsg *t = NLMSG_DATA(n);
993 struct rtattr *tail;
jamaldcf13492006-12-07 11:07:07 -0500994 int sel_ok = 0, terminal_ok = 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000995 int sample_ok = 0;
996 __u32 htid = 0;
997 __u32 order = 0;
Samudrala, Sridhar5e5b3002016-06-08 16:16:01 -0700998 __u32 flags = 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000999
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001000 if (handle && get_u32_handle(&t->tcm_handle, handle)) {
1001 fprintf(stderr, "Illegal filter ID\n");
1002 return -1;
1003 }
1004
1005 if (argc == 0)
1006 return 0;
1007
8!tgraf4a86fe12005-01-18 01:24:18 +00001008 tail = NLMSG_TAIL(n);
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001009 addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001010
1011 while (argc > 0) {
1012 if (matches(*argv, "match") == 0) {
1013 NEXT_ARG();
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +00001014 if (parse_selector(&argc, &argv, &sel.sel, n)) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001015 fprintf(stderr, "Illegal \"match\"\n");
1016 return -1;
1017 }
1018 sel_ok++;
1019 continue;
1020 } else if (matches(*argv, "offset") == 0) {
1021 NEXT_ARG();
1022 if (parse_offset(&argc, &argv, &sel.sel)) {
1023 fprintf(stderr, "Illegal \"offset\"\n");
1024 return -1;
1025 }
1026 continue;
1027 } else if (matches(*argv, "hashkey") == 0) {
1028 NEXT_ARG();
1029 if (parse_hashkey(&argc, &argv, &sel.sel)) {
1030 fprintf(stderr, "Illegal \"hashkey\"\n");
1031 return -1;
1032 }
1033 continue;
1034 } else if (matches(*argv, "classid") == 0 ||
1035 strcmp(*argv, "flowid") == 0) {
Jamal Hadi Salim82e6efe2016-05-25 06:11:55 -04001036 unsigned int flowid;
Stephen Hemminger32a121c2016-03-21 11:48:36 -07001037
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001038 NEXT_ARG();
Jamal Hadi Salim82e6efe2016-05-25 06:11:55 -04001039 if (get_tc_classid(&flowid, *argv)) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001040 fprintf(stderr, "Illegal \"classid\"\n");
1041 return -1;
1042 }
Jamal Hadi Salim82e6efe2016-05-25 06:11:55 -04001043 addattr_l(n, MAX_MSG, TCA_U32_CLASSID, &flowid, 4);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001044 sel.sel.flags |= TC_U32_TERMINAL;
1045 } else if (matches(*argv, "divisor") == 0) {
Stephen Hemminger32a121c2016-03-21 11:48:36 -07001046 unsigned int divisor;
1047
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001048 NEXT_ARG();
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001049 if (get_unsigned(&divisor, *argv, 0) ||
shemminger46b67da2006-03-14 19:38:34 +00001050 divisor == 0 ||
1051 divisor > 0x100 || ((divisor - 1) & divisor)) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001052 fprintf(stderr, "Illegal \"divisor\"\n");
1053 return -1;
1054 }
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001055 addattr_l(n, MAX_MSG, TCA_U32_DIVISOR, &divisor, 4);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001056 } else if (matches(*argv, "order") == 0) {
1057 NEXT_ARG();
1058 if (get_u32(&order, *argv, 0)) {
1059 fprintf(stderr, "Illegal \"order\"\n");
1060 return -1;
1061 }
1062 } else if (strcmp(*argv, "link") == 0) {
Jamal Hadi Salim82e6efe2016-05-25 06:11:55 -04001063 unsigned int linkid;
Stephen Hemminger32a121c2016-03-21 11:48:36 -07001064
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001065 NEXT_ARG();
Jamal Hadi Salim82e6efe2016-05-25 06:11:55 -04001066 if (get_u32_handle(&linkid, *argv)) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001067 fprintf(stderr, "Illegal \"link\"\n");
1068 return -1;
1069 }
Jamal Hadi Salim82e6efe2016-05-25 06:11:55 -04001070 if (linkid && TC_U32_NODE(linkid)) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001071 fprintf(stderr, "\"link\" must be a hash table.\n");
1072 return -1;
1073 }
Sushma Sitaram58d93d02016-09-28 11:30:16 -07001074 addattr_l(n, MAX_MSG, TCA_U32_LINK, &linkid, 4);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001075 } else if (strcmp(*argv, "ht") == 0) {
Jamal Hadi Salim82e6efe2016-05-25 06:11:55 -04001076 unsigned int ht;
Stephen Hemminger32a121c2016-03-21 11:48:36 -07001077
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001078 NEXT_ARG();
Jamal Hadi Salim82e6efe2016-05-25 06:11:55 -04001079 if (get_u32_handle(&ht, *argv)) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001080 fprintf(stderr, "Illegal \"ht\"\n");
1081 return -1;
1082 }
Jamal Hadi Salim82e6efe2016-05-25 06:11:55 -04001083 if (handle && TC_U32_NODE(ht)) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001084 fprintf(stderr, "\"ht\" must be a hash table.\n");
1085 return -1;
1086 }
1087 if (sample_ok)
Jamal Hadi Salim82e6efe2016-05-25 06:11:55 -04001088 htid = (htid & 0xFF000) | (ht & 0xFFF00000);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001089 else
Jamal Hadi Salim82e6efe2016-05-25 06:11:55 -04001090 htid = (ht & 0xFFFFF000);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001091 } else if (strcmp(*argv, "sample") == 0) {
1092 __u32 hash;
Stephen Hemminger32a121c2016-03-21 11:48:36 -07001093 unsigned int divisor = 0x100;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001094 struct {
1095 struct tc_u32_sel sel;
1096 struct tc_u32_key keys[4];
Phil Sutterd17b1362016-07-18 16:48:42 +02001097 } sel2 = {};
1098
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001099 NEXT_ARG();
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +00001100 if (parse_selector(&argc, &argv, &sel2.sel, n)) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001101 fprintf(stderr, "Illegal \"sample\"\n");
1102 return -1;
1103 }
1104 if (sel2.sel.nkeys != 1) {
Stephen Hemminger32a121c2016-03-21 11:48:36 -07001105 fprintf(stderr, "\"sample\" must contain exactly ONE key.\n");
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001106 return -1;
1107 }
shemminger3925ad82006-03-14 19:36:31 +00001108 if (*argv != 0 && strcmp(*argv, "divisor") == 0) {
1109 NEXT_ARG();
Jamal Hadi Salim82e6efe2016-05-25 06:11:55 -04001110 if (get_unsigned(&divisor, *argv, 0) ||
1111 divisor == 0 || divisor > 0x100 ||
1112 ((divisor - 1) & divisor)) {
shemminger3925ad82006-03-14 19:36:31 +00001113 fprintf(stderr, "Illegal sample \"divisor\"\n");
1114 return -1;
1115 }
1116 NEXT_ARG();
1117 }
Phil Sutter40eb7372015-10-23 19:21:23 +02001118 hash = sel2.sel.keys[0].val & sel2.sel.keys[0].mask;
1119 hash ^= hash >> 16;
1120 hash ^= hash >> 8;
1121 htid = ((hash % divisor) << 12) | (htid & 0xFFF00000);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001122 sample_ok = 1;
1123 continue;
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001124 } else if (strcmp(*argv, "indev") == 0) {
Phil Sutterd17b1362016-07-18 16:48:42 +02001125 char ind[IFNAMSIZ + 1] = {};
Stephen Hemminger32a121c2016-03-21 11:48:36 -07001126
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001127 argc--;
1128 argv++;
1129 if (argc < 1) {
1130 fprintf(stderr, "Illegal indev\n");
1131 return -1;
1132 }
Luca Lemmo725f2a82016-03-16 17:56:13 +01001133 strncpy(ind, *argv, sizeof(ind) - 1);
Jamal Hadi Salim82e6efe2016-05-25 06:11:55 -04001134 addattr_l(n, MAX_MSG, TCA_U32_INDEV, ind,
1135 strlen(ind) + 1);
net[shemminger]!shemmingerd81b1352004-08-23 20:20:41 +00001136
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001137 } else if (matches(*argv, "action") == 0) {
1138 NEXT_ARG();
1139 if (parse_action(&argc, &argv, TCA_U32_ACT, n)) {
1140 fprintf(stderr, "Illegal \"action\"\n");
1141 return -1;
1142 }
jamaldcf13492006-12-07 11:07:07 -05001143 terminal_ok++;
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001144 continue;
net[shemminger]!shemmingerd81b1352004-08-23 20:20:41 +00001145
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001146 } else if (matches(*argv, "police") == 0) {
1147 NEXT_ARG();
1148 if (parse_police(&argc, &argv, TCA_U32_POLICE, n)) {
1149 fprintf(stderr, "Illegal \"police\"\n");
1150 return -1;
1151 }
jamaldcf13492006-12-07 11:07:07 -05001152 terminal_ok++;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001153 continue;
Samudrala, Sridhar5e5b3002016-06-08 16:16:01 -07001154 } else if (strcmp(*argv, "skip_hw") == 0) {
1155 NEXT_ARG();
1156 flags |= TCA_CLS_FLAGS_SKIP_HW;
1157 continue;
1158 } else if (strcmp(*argv, "skip_sw") == 0) {
1159 NEXT_ARG();
1160 flags |= TCA_CLS_FLAGS_SKIP_SW;
1161 continue;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001162 } else if (strcmp(*argv, "help") == 0) {
1163 explain();
1164 return -1;
1165 } else {
1166 fprintf(stderr, "What is \"%s\"?\n", *argv);
1167 explain();
1168 return -1;
1169 }
1170 argc--; argv++;
1171 }
1172
jamaldcf13492006-12-07 11:07:07 -05001173 /* We dont necessarily need class/flowids */
Stephen Hemminger81c61792006-12-13 17:05:50 -08001174 if (terminal_ok)
jamaldcf13492006-12-07 11:07:07 -05001175 sel.sel.flags |= TC_U32_TERMINAL;
Stephen Hemminger3d0b7432014-12-20 15:47:17 -08001176
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001177 if (order) {
Jamal Hadi Salim82e6efe2016-05-25 06:11:55 -04001178 if (TC_U32_NODE(t->tcm_handle) &&
1179 order != TC_U32_NODE(t->tcm_handle)) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001180 fprintf(stderr, "\"order\" contradicts \"handle\"\n");
1181 return -1;
1182 }
1183 t->tcm_handle |= order;
1184 }
1185
1186 if (htid)
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001187 addattr_l(n, MAX_MSG, TCA_U32_HASH, &htid, 4);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001188 if (sel_ok)
Stephen Hemminger3d0b7432014-12-20 15:47:17 -08001189 addattr_l(n, MAX_MSG, TCA_U32_SEL, &sel,
Jamal Hadi Salim82e6efe2016-05-25 06:11:55 -04001190 sizeof(sel.sel) +
1191 sel.sel.nkeys * sizeof(struct tc_u32_key));
Samudrala, Sridhar5e5b3002016-06-08 16:16:01 -07001192 if (flags) {
Stephen Hemminger62281202016-06-08 16:45:26 -07001193 if (!(flags ^ (TCA_CLS_FLAGS_SKIP_HW |
1194 TCA_CLS_FLAGS_SKIP_SW))) {
1195 fprintf(stderr,
1196 "skip_hw and skip_sw are mutually exclusive\n");
Samudrala, Sridhar5e5b3002016-06-08 16:16:01 -07001197 return -1;
1198 }
1199 addattr_l(n, MAX_MSG, TCA_U32_FLAGS, &flags, 4);
1200 }
1201
8!tgraf4a86fe12005-01-18 01:24:18 +00001202 tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001203 return 0;
1204}
1205
Stephen Hemminger6b1ac652007-12-31 10:29:52 -08001206static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt,
1207 __u32 handle)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001208{
Phil Sutter40eb7372015-10-23 19:21:23 +02001209 struct rtattr *tb[TCA_U32_MAX + 1];
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001210 struct tc_u32_sel *sel = NULL;
net[shemminger]!shemmingerd81b1352004-08-23 20:20:41 +00001211 struct tc_u32_pcnt *pf = NULL;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001212
1213 if (opt == NULL)
1214 return 0;
1215
8!tgrafac2fc2d2005-01-18 22:11:58 +00001216 parse_rtattr_nested(tb, TCA_U32_MAX, opt);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001217
1218 if (handle) {
1219 SPRINT_BUF(b1);
1220 fprintf(f, "fh %s ", sprint_u32_handle(handle, b1));
1221 }
Stephen Hemminger62281202016-06-08 16:45:26 -07001222
1223 if (TC_U32_NODE(handle))
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001224 fprintf(f, "order %d ", TC_U32_NODE(handle));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001225
1226 if (tb[TCA_U32_SEL]) {
1227 if (RTA_PAYLOAD(tb[TCA_U32_SEL]) < sizeof(*sel))
1228 return -1;
1229
1230 sel = RTA_DATA(tb[TCA_U32_SEL]);
1231 }
1232
1233 if (tb[TCA_U32_DIVISOR]) {
Jamal Hadi Salim82e6efe2016-05-25 06:11:55 -04001234 fprintf(f, "ht divisor %d ",
1235 rta_getattr_u32(tb[TCA_U32_DIVISOR]));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001236 } else if (tb[TCA_U32_HASH]) {
Stephen Hemmingerff247462012-04-10 08:47:55 -07001237 __u32 htid = rta_getattr_u32(tb[TCA_U32_HASH]);
Stephen Hemminger32a121c2016-03-21 11:48:36 -07001238
Stephen Hemmingere62077d2008-02-18 10:51:42 -08001239 fprintf(f, "key ht %x bkt %x ", TC_U32_USERHTID(htid),
1240 TC_U32_HASH(htid));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001241 } else {
1242 fprintf(f, "??? ");
1243 }
1244 if (tb[TCA_U32_CLASSID]) {
1245 SPRINT_BUF(b1);
1246 fprintf(f, "%sflowid %s ",
Phil Sutter40eb7372015-10-23 19:21:23 +02001247 !sel || !(sel->flags & TC_U32_TERMINAL) ? "*" : "",
Jamal Hadi Salim82e6efe2016-05-25 06:11:55 -04001248 sprint_tc_classid(rta_getattr_u32(tb[TCA_U32_CLASSID]),
1249 b1));
Phil Sutter40eb7372015-10-23 19:21:23 +02001250 } else if (sel && sel->flags & TC_U32_TERMINAL) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001251 fprintf(f, "terminal flowid ??? ");
1252 }
1253 if (tb[TCA_U32_LINK]) {
1254 SPRINT_BUF(b1);
Stephen Hemmingere62077d2008-02-18 10:51:42 -08001255 fprintf(f, "link %s ",
Jamal Hadi Salim82e6efe2016-05-25 06:11:55 -04001256 sprint_u32_handle(rta_getattr_u32(tb[TCA_U32_LINK]),
1257 b1));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001258 }
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001259
Samudrala, Sridhar5e5b3002016-06-08 16:16:01 -07001260 if (tb[TCA_U32_FLAGS]) {
1261 __u32 flags = rta_getattr_u32(tb[TCA_U32_FLAGS]);
1262
1263 if (flags & TCA_CLS_FLAGS_SKIP_HW)
1264 fprintf(f, "skip_hw ");
1265 if (flags & TCA_CLS_FLAGS_SKIP_SW)
1266 fprintf(f, "skip_sw ");
1267 }
1268
net[shemminger]!shemmingerd81b1352004-08-23 20:20:41 +00001269 if (tb[TCA_U32_PCNT]) {
1270 if (RTA_PAYLOAD(tb[TCA_U32_PCNT]) < sizeof(*pf)) {
Stephen Hemminger32a121c2016-03-21 11:48:36 -07001271 fprintf(f, "Broken perf counters\n");
net[shemminger]!shemmingerd81b1352004-08-23 20:20:41 +00001272 return -1;
1273 }
1274 pf = RTA_DATA(tb[TCA_U32_PCNT]);
1275 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001276
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +00001277 if (sel && show_stats && NULL != pf)
net[shemminger]!shemmingerb9062432005-01-17 23:28:16 +00001278 fprintf(f, " (rule hit %llu success %llu)",
1279 (unsigned long long) pf->rcnt,
1280 (unsigned long long) pf->rhit);
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +00001281
1282 if (tb[TCA_U32_MARK]) {
1283 struct tc_u32_mark *mark = RTA_DATA(tb[TCA_U32_MARK]);
Stephen Hemminger32a121c2016-03-21 11:48:36 -07001284
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +00001285 if (RTA_PAYLOAD(tb[TCA_U32_MARK]) < sizeof(*mark)) {
1286 fprintf(f, "\n Invalid mark (kernel&iproute2 mismatch)\n");
1287 } else {
1288 fprintf(f, "\n mark 0x%04x 0x%04x (success %d)",
1289 mark->val, mark->mask, mark->success);
1290 }
1291 }
1292
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001293 if (sel) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001294 if (sel->nkeys) {
Stephen Hemminger6b1ac652007-12-31 10:29:52 -08001295 int i;
Stephen Hemminger32a121c2016-03-21 11:48:36 -07001296
Luca Lemmodd0c8d12016-03-16 17:56:12 +01001297 for (i = 0; i < sel->nkeys; i++) {
jamal1750abe2008-04-20 10:49:24 -04001298 show_keys(f, sel->keys + i);
net[shemminger]!shemmingerd81b1352004-08-23 20:20:41 +00001299 if (show_stats && NULL != pf)
Stephen Hemminger6b1ac652007-12-31 10:29:52 -08001300 fprintf(f, " (success %llu ) ",
net[shemminger]!shemmingerb9062432005-01-17 23:28:16 +00001301 (unsigned long long) pf->kcnts[i]);
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001302 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001303 }
1304
Phil Sutter40eb7372015-10-23 19:21:23 +02001305 if (sel->flags & (TC_U32_VAROFFSET | TC_U32_OFFSET)) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001306 fprintf(f, "\n offset ");
Phil Sutter40eb7372015-10-23 19:21:23 +02001307 if (sel->flags & TC_U32_VAROFFSET)
Stephen Hemmingere62077d2008-02-18 10:51:42 -08001308 fprintf(f, "%04x>>%d at %d ",
1309 ntohs(sel->offmask),
1310 sel->offshift, sel->offoff);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001311 if (sel->off)
1312 fprintf(f, "plus %d ", sel->off);
1313 }
Phil Sutter40eb7372015-10-23 19:21:23 +02001314 if (sel->flags & TC_U32_EAT)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001315 fprintf(f, " eat ");
1316
1317 if (sel->hmask) {
1318 fprintf(f, "\n hash mask %08x at %d ",
1319 (unsigned int)htonl(sel->hmask), sel->hoff);
1320 }
1321 }
1322
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001323 if (tb[TCA_U32_POLICE]) {
1324 fprintf(f, "\n");
1325 tc_print_police(f, tb[TCA_U32_POLICE]);
1326 }
Stephen Hemminger62281202016-06-08 16:45:26 -07001327
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001328 if (tb[TCA_U32_INDEV]) {
1329 struct rtattr *idev = tb[TCA_U32_INDEV];
Stephen Hemminger32a121c2016-03-21 11:48:36 -07001330
Stephen Hemmingerff247462012-04-10 08:47:55 -07001331 fprintf(f, "\n input dev %s\n", rta_getattr_str(idev));
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001332 }
Stephen Hemminger62281202016-06-08 16:45:26 -07001333
1334 if (tb[TCA_U32_ACT])
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001335 tc_print_action(f, tb[TCA_U32_ACT]);
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001336
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001337 return 0;
1338}
1339
osdl.net!shemminger6b7dff12004-09-28 18:35:49 +00001340struct filter_util u32_filter_util = {
1341 .id = "u32",
1342 .parse_fopt = u32_parse_opt,
1343 .print_fopt = u32_print_opt,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001344};