blob: 62995153923a9589daf711bfb8c490de2e897494 [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 Hemminger32a121c2016-03-21 11:48:36 -070033 fprintf(stderr, "Usage: ... u32 [ match SELECTOR ... ] [ link HTID ] [ classid CLASSID ]\n");
34 fprintf(stderr, " [ action ACTION_SPEC ] [ offset OFFSET_SPEC ]\n");
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000035 fprintf(stderr, " [ ht HTID ] [ hashkey HASHKEY_SPEC ]\n");
36 fprintf(stderr, " [ sample SAMPLE ]\n");
37 fprintf(stderr, "or u32 divisor DIVISOR\n");
38 fprintf(stderr, "\n");
39 fprintf(stderr, "Where: SELECTOR := SAMPLE SAMPLE ...\n");
Stephen Hemminger32a121c2016-03-21 11:48:36 -070040 fprintf(stderr, " SAMPLE := { ip | ip6 | udp | tcp | icmp | u{32|16|8} | mark } SAMPLE_ARGS [divisor DIVISOR]\n");
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000041 fprintf(stderr, " FILTERID := X:Y:Z\n");
PJ Waskiewicze9acc242008-02-13 03:49:09 -080042 fprintf(stderr, "\nNOTE: CLASSID is parsed at hexadecimal input.\n");
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000043}
44
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -080045static int get_u32_handle(__u32 *handle, const char *str)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000046{
Luca Lemmodd0c8d12016-03-16 17:56:12 +010047 __u32 htid = 0, hash = 0, nodeid = 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000048 char *tmp = strchr(str, ':');
49
50 if (tmp == NULL) {
51 if (memcmp("0x", str, 2) == 0)
52 return get_u32(handle, str, 16);
53 return -1;
54 }
55 htid = strtoul(str, &tmp, 16);
56 if (tmp == str && *str != ':' && *str != 0)
57 return -1;
Luca Lemmodd0c8d12016-03-16 17:56:12 +010058 if (htid >= 0x1000)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000059 return -1;
60 if (*tmp) {
Phil Sutter40eb7372015-10-23 19:21:23 +020061 str = tmp + 1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000062 hash = strtoul(str, &tmp, 16);
63 if (tmp == str && *str != ':' && *str != 0)
64 return -1;
Luca Lemmodd0c8d12016-03-16 17:56:12 +010065 if (hash >= 0x100)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000066 return -1;
67 if (*tmp) {
Phil Sutter40eb7372015-10-23 19:21:23 +020068 str = tmp + 1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000069 nodeid = strtoul(str, &tmp, 16);
70 if (tmp == str && *str != 0)
71 return -1;
Luca Lemmodd0c8d12016-03-16 17:56:12 +010072 if (nodeid >= 0x1000)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000073 return -1;
74 }
75 }
76 *handle = (htid<<20)|(hash<<12)|nodeid;
77 return 0;
78}
79
Luca Lemmo725f2a82016-03-16 17:56:13 +010080static char *sprint_u32_handle(__u32 handle, char *buf)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000081{
82 int bsize = SPRINT_BSIZE-1;
83 __u32 htid = TC_U32_HTID(handle);
84 __u32 hash = TC_U32_HASH(handle);
85 __u32 nodeid = TC_U32_NODE(handle);
86 char *b = buf;
87
88 if (handle == 0) {
89 snprintf(b, bsize, "none");
90 return b;
91 }
92 if (htid) {
93 int l = snprintf(b, bsize, "%x:", htid>>20);
Stephen Hemminger32a121c2016-03-21 11:48:36 -070094
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000095 bsize -= l;
96 b += l;
97 }
98 if (nodeid|hash) {
99 if (hash) {
100 int l = snprintf(b, bsize, "%x", hash);
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700101
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000102 bsize -= l;
103 b += l;
104 }
105 if (nodeid) {
106 int l = snprintf(b, bsize, ":%x", nodeid);
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700107
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000108 bsize -= l;
109 b += l;
110 }
111 }
112 if (show_raw)
113 snprintf(b, bsize, "[%08x] ", handle);
114 return buf;
115}
116
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800117static int pack_key(struct tc_u32_sel *sel, __u32 key, __u32 mask,
118 int off, int offmask)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000119{
120 int i;
121 int hwm = sel->nkeys;
122
123 key &= mask;
124
Luca Lemmodd0c8d12016-03-16 17:56:12 +0100125 for (i = 0; i < hwm; i++) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000126 if (sel->keys[i].off == off && sel->keys[i].offmask == offmask) {
Phil Sutter40eb7372015-10-23 19:21:23 +0200127 __u32 intersect = mask & sel->keys[i].mask;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000128
Phil Sutter40eb7372015-10-23 19:21:23 +0200129 if ((key ^ sel->keys[i].val) & intersect)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000130 return -1;
131 sel->keys[i].val |= key;
132 sel->keys[i].mask |= mask;
133 return 0;
134 }
135 }
136
137 if (hwm >= 128)
138 return -1;
139 if (off % 4)
140 return -1;
141 sel->keys[hwm].val = key;
142 sel->keys[hwm].mask = mask;
143 sel->keys[hwm].off = off;
144 sel->keys[hwm].offmask = offmask;
145 sel->nkeys++;
146 return 0;
147}
148
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800149static int pack_key32(struct tc_u32_sel *sel, __u32 key, __u32 mask,
150 int off, int offmask)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000151{
152 key = htonl(key);
153 mask = htonl(mask);
154 return pack_key(sel, key, mask, off, offmask);
155}
156
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800157static int pack_key16(struct tc_u32_sel *sel, __u32 key, __u32 mask,
158 int off, int offmask)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000159{
160 if (key > 0xFFFF || mask > 0xFFFF)
161 return -1;
162
163 if ((off & 3) == 0) {
164 key <<= 16;
165 mask <<= 16;
166 }
167 off &= ~3;
168 key = htonl(key);
169 mask = htonl(mask);
170
171 return pack_key(sel, key, mask, off, offmask);
172}
173
174static int pack_key8(struct tc_u32_sel *sel, __u32 key, __u32 mask, int off, int offmask)
175{
176 if (key > 0xFF || mask > 0xFF)
177 return -1;
178
179 if ((off & 3) == 0) {
180 key <<= 24;
181 mask <<= 24;
182 } else if ((off & 3) == 1) {
183 key <<= 16;
184 mask <<= 16;
185 } else if ((off & 3) == 2) {
186 key <<= 8;
187 mask <<= 8;
188 }
189 off &= ~3;
190 key = htonl(key);
191 mask = htonl(mask);
192
193 return pack_key(sel, key, mask, off, offmask);
194}
195
196
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -0800197static int parse_at(int *argc_p, char ***argv_p, int *off, int *offmask)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000198{
199 int argc = *argc_p;
200 char **argv = *argv_p;
201 char *p = *argv;
202
203 if (argc <= 0)
204 return -1;
205
206 if (strlen(p) > strlen("nexthdr+") &&
207 memcmp(p, "nexthdr+", strlen("nexthdr+")) == 0) {
208 *offmask = -1;
209 p += strlen("nexthdr+");
210 } else if (matches(*argv, "nexthdr+") == 0) {
211 NEXT_ARG();
212 *offmask = -1;
213 p = *argv;
214 }
215
216 if (get_integer(off, p, 0))
217 return -1;
218 argc--; argv++;
219
220 *argc_p = argc;
221 *argv_p = argv;
222 return 0;
223}
224
225
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800226static int parse_u32(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
227 int off, int offmask)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000228{
229 int res = -1;
230 int argc = *argc_p;
231 char **argv = *argv_p;
232 __u32 key;
233 __u32 mask;
234
235 if (argc < 2)
236 return -1;
237
238 if (get_u32(&key, *argv, 0))
239 return -1;
240 argc--; argv++;
241
242 if (get_u32(&mask, *argv, 16))
243 return -1;
244 argc--; argv++;
245
246 if (argc > 0 && strcmp(argv[0], "at") == 0) {
247 NEXT_ARG();
248 if (parse_at(&argc, &argv, &off, &offmask))
249 return -1;
250 }
251
252 res = pack_key32(sel, key, mask, off, offmask);
253 *argc_p = argc;
254 *argv_p = argv;
255 return res;
256}
257
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800258static int parse_u16(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
259 int off, int offmask)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000260{
261 int res = -1;
262 int argc = *argc_p;
263 char **argv = *argv_p;
264 __u32 key;
265 __u32 mask;
266
267 if (argc < 2)
268 return -1;
269
270 if (get_u32(&key, *argv, 0))
271 return -1;
272 argc--; argv++;
273
274 if (get_u32(&mask, *argv, 16))
275 return -1;
276 argc--; argv++;
277
278 if (argc > 0 && strcmp(argv[0], "at") == 0) {
279 NEXT_ARG();
280 if (parse_at(&argc, &argv, &off, &offmask))
281 return -1;
282 }
283 res = pack_key16(sel, key, mask, off, offmask);
284 *argc_p = argc;
285 *argv_p = argv;
286 return res;
287}
288
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800289static int parse_u8(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
290 int off, int offmask)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000291{
292 int res = -1;
293 int argc = *argc_p;
294 char **argv = *argv_p;
295 __u32 key;
296 __u32 mask;
297
298 if (argc < 2)
299 return -1;
300
301 if (get_u32(&key, *argv, 0))
302 return -1;
303 argc--; argv++;
304
305 if (get_u32(&mask, *argv, 16))
306 return -1;
307 argc--; argv++;
308
309 if (key > 0xFF || mask > 0xFF)
310 return -1;
311
312 if (argc > 0 && strcmp(argv[0], "at") == 0) {
313 NEXT_ARG();
314 if (parse_at(&argc, &argv, &off, &offmask))
315 return -1;
316 }
317
318 res = pack_key8(sel, key, mask, off, offmask);
319 *argc_p = argc;
320 *argv_p = argv;
321 return res;
322}
323
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800324static int parse_ip_addr(int *argc_p, char ***argv_p, struct tc_u32_sel *sel,
325 int off)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000326{
327 int res = -1;
328 int argc = *argc_p;
329 char **argv = *argv_p;
330 inet_prefix addr;
331 __u32 mask;
332 int offmask = 0;
333
334 if (argc < 1)
335 return -1;
336
337 if (get_prefix_1(&addr, *argv, AF_INET))
338 return -1;
339 argc--; argv++;
340
341 if (argc > 0 && strcmp(argv[0], "at") == 0) {
342 NEXT_ARG();
343 if (parse_at(&argc, &argv, &off, &offmask))
344 return -1;
345 }
346
347 mask = 0;
348 if (addr.bitlen)
Phil Sutter40eb7372015-10-23 19:21:23 +0200349 mask = htonl(0xFFFFFFFF << (32 - addr.bitlen));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000350 if (pack_key(sel, addr.data[0], mask, off, offmask) < 0)
351 return -1;
352 res = 0;
353
354 *argc_p = argc;
355 *argv_p = argv;
356 return res;
357}
358
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800359static int parse_ip6_addr(int *argc_p, char ***argv_p,
360 struct tc_u32_sel *sel, int off)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000361{
362 int res = -1;
363 int argc = *argc_p;
364 char **argv = *argv_p;
365 int plen = 128;
366 int i;
367 inet_prefix addr;
368 int offmask = 0;
369
370 if (argc < 1)
371 return -1;
372
373 if (get_prefix_1(&addr, *argv, AF_INET6))
374 return -1;
375 argc--; argv++;
376
377 if (argc > 0 && strcmp(argv[0], "at") == 0) {
378 NEXT_ARG();
379 if (parse_at(&argc, &argv, &off, &offmask))
380 return -1;
381 }
382
383 plen = addr.bitlen;
Phil Sutter40eb7372015-10-23 19:21:23 +0200384 for (i = 0; i < plen; i += 32) {
Luca Lemmo725f2a82016-03-16 17:56:13 +0100385 /* if (((i + 31) & ~0x1F) <= plen) { */
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800386 if (i + 31 <= plen) {
Phil Sutter40eb7372015-10-23 19:21:23 +0200387 res = pack_key(sel, addr.data[i / 32],
388 0xFFFFFFFF, off + 4 * (i / 32), offmask);
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800389 if (res < 0)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000390 return -1;
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800391 } else if (i < plen) {
Phil Sutter40eb7372015-10-23 19:21:23 +0200392 __u32 mask = htonl(0xFFFFFFFF << (32 - (plen - i)));
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700393
Phil Sutter40eb7372015-10-23 19:21:23 +0200394 res = pack_key(sel, addr.data[i / 32],
395 mask, off + 4 * (i / 32), offmask);
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800396 if (res < 0)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000397 return -1;
398 }
399 }
400 res = 0;
401
402 *argc_p = argc;
403 *argv_p = argv;
404 return res;
405}
406
Petr Lautrbach01564122010-06-14 03:36:28 +0000407static int parse_ip6_class(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
408{
409 int res = -1;
410 int argc = *argc_p;
411 char **argv = *argv_p;
412 __u32 key;
413 __u32 mask;
414 int off = 0;
415 int offmask = 0;
416
417 if (argc < 2)
418 return -1;
419
420 if (get_u32(&key, *argv, 0))
421 return -1;
422 argc--; argv++;
423
424 if (get_u32(&mask, *argv, 16))
425 return -1;
426 argc--; argv++;
427
428 if (key > 0xFF || mask > 0xFF)
429 return -1;
430
431 key <<= 20;
432 mask <<= 20;
433 key = htonl(key);
434 mask = htonl(mask);
435
Stephen Hemmingerd7ac9ad2011-03-09 10:42:35 -0800436 res = pack_key(sel, key, mask, off, offmask);
437 if (res < 0)
Petr Lautrbach01564122010-06-14 03:36:28 +0000438 return -1;
439
440 *argc_p = argc;
441 *argv_p = argv;
442 return 0;
443}
444
Stephen Hemmingerb4d41f42009-04-15 15:39:34 -0700445static int parse_ether_addr(int *argc_p, char ***argv_p,
446 struct tc_u32_sel *sel, int off)
447{
448 int res = -1;
449 int argc = *argc_p;
450 char **argv = *argv_p;
451 __u8 addr[6];
452 int offmask = 0;
Stephen Hemmingerb4d41f42009-04-15 15:39:34 -0700453 int i;
454
455 if (argc < 1)
456 return -1;
457
458 if (sscanf(*argv, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
459 addr + 0, addr + 1, addr + 2,
460 addr + 3, addr + 4, addr + 5) != 6) {
461 fprintf(stderr, "parse_ether_addr: improperly formed address '%s'\n",
462 *argv);
463 return -1;
464 }
465
466 argc--; argv++;
467 if (argc > 0 && strcmp(argv[0], "at") == 0) {
468 NEXT_ARG();
469 if (parse_at(&argc, &argv, &off, &offmask))
470 return -1;
471 }
472
Stephen Hemmingere3d153c2010-08-02 11:55:30 -0700473 for (i = 0; i < 6; i++) {
474 res = pack_key8(sel, addr[i], 0xFF, off + i, offmask);
Stephen Hemmingerb4d41f42009-04-15 15:39:34 -0700475 if (res < 0)
476 return -1;
477 }
478
479 *argc_p = argc;
480 *argv_p = argv;
481 return res;
482}
483
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000484static int parse_ip(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
485{
486 int res = -1;
487 int argc = *argc_p;
488 char **argv = *argv_p;
489
490 if (argc < 2)
491 return -1;
492
493 if (strcmp(*argv, "src") == 0) {
494 NEXT_ARG();
495 res = parse_ip_addr(&argc, &argv, sel, 12);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700496 } else if (strcmp(*argv, "dst") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000497 NEXT_ARG();
498 res = parse_ip_addr(&argc, &argv, sel, 16);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700499 } else if (strcmp(*argv, "tos") == 0 ||
Phil Sutter40eb7372015-10-23 19:21:23 +0200500 matches(*argv, "dsfield") == 0 ||
501 matches(*argv, "precedence") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000502 NEXT_ARG();
503 res = parse_u8(&argc, &argv, sel, 1, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700504 } else if (strcmp(*argv, "ihl") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000505 NEXT_ARG();
506 res = parse_u8(&argc, &argv, sel, 0, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700507 } else if (strcmp(*argv, "protocol") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000508 NEXT_ARG();
509 res = parse_u8(&argc, &argv, sel, 9, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700510 } else if (strcmp(*argv, "nofrag") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000511 argc--; argv++;
512 res = pack_key16(sel, 0, 0x3FFF, 6, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700513 } else if (strcmp(*argv, "firstfrag") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000514 argc--; argv++;
Hiroaki SHIMODA690b11f2012-07-10 19:44:16 +0900515 res = pack_key16(sel, 0x2000, 0x3FFF, 6, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700516 } else if (strcmp(*argv, "df") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000517 argc--; argv++;
518 res = pack_key16(sel, 0x4000, 0x4000, 6, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700519 } else if (strcmp(*argv, "mf") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000520 argc--; argv++;
521 res = pack_key16(sel, 0x2000, 0x2000, 6, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700522 } else if (strcmp(*argv, "dport") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000523 NEXT_ARG();
524 res = parse_u16(&argc, &argv, sel, 22, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700525 } else if (strcmp(*argv, "sport") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000526 NEXT_ARG();
527 res = parse_u16(&argc, &argv, sel, 20, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700528 } else if (strcmp(*argv, "icmp_type") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000529 NEXT_ARG();
530 res = parse_u8(&argc, &argv, sel, 20, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700531 } else if (strcmp(*argv, "icmp_code") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000532 NEXT_ARG();
Hiroaki SHIMODA1d62f992012-07-10 18:53:18 +0900533 res = parse_u8(&argc, &argv, sel, 21, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700534 } else
535 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000536
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000537 *argc_p = argc;
538 *argv_p = argv;
539 return res;
540}
Stephen Hemminger3d0b7432014-12-20 15:47:17 -0800541
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000542static int parse_ip6(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
543{
544 int res = -1;
545 int argc = *argc_p;
546 char **argv = *argv_p;
547
548 if (argc < 2)
549 return -1;
550
551 if (strcmp(*argv, "src") == 0) {
552 NEXT_ARG();
553 res = parse_ip6_addr(&argc, &argv, sel, 8);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700554 } else if (strcmp(*argv, "dst") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000555 NEXT_ARG();
556 res = parse_ip6_addr(&argc, &argv, sel, 24);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700557 } else if (strcmp(*argv, "priority") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000558 NEXT_ARG();
Petr Lautrbach01564122010-06-14 03:36:28 +0000559 res = parse_ip6_class(&argc, &argv, sel);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700560 } else if (strcmp(*argv, "protocol") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000561 NEXT_ARG();
562 res = parse_u8(&argc, &argv, sel, 6, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700563 } else if (strcmp(*argv, "flowlabel") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000564 NEXT_ARG();
565 res = parse_u32(&argc, &argv, sel, 0, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700566 } else if (strcmp(*argv, "dport") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000567 NEXT_ARG();
568 res = parse_u16(&argc, &argv, sel, 42, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700569 } else if (strcmp(*argv, "sport") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000570 NEXT_ARG();
571 res = parse_u16(&argc, &argv, sel, 40, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700572 } else if (strcmp(*argv, "icmp_type") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000573 NEXT_ARG();
574 res = parse_u8(&argc, &argv, sel, 40, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700575 } else if (strcmp(*argv, "icmp_code") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000576 NEXT_ARG();
577 res = parse_u8(&argc, &argv, sel, 41, 1);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700578 } else
579 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000580
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000581 *argc_p = argc;
582 *argv_p = argv;
583 return res;
584}
585
Stephen Hemmingerb4d41f42009-04-15 15:39:34 -0700586static int parse_ether(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
587{
588 int res = -1;
589 int argc = *argc_p;
590 char **argv = *argv_p;
591
592 if (argc < 2)
593 return -1;
594
595 if (strcmp(*argv, "src") == 0) {
596 NEXT_ARG();
597 res = parse_ether_addr(&argc, &argv, sel, -8);
598 } else if (strcmp(*argv, "dst") == 0) {
599 NEXT_ARG();
600 res = parse_ether_addr(&argc, &argv, sel, -14);
601 } else {
602 fprintf(stderr, "Unknown match: ether %s\n", *argv);
603 return -1;
604 }
605
606 *argc_p = argc;
607 *argv_p = argv;
608 return res;
609}
610
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000611#define parse_tcp parse_udp
612static int parse_udp(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
613{
614 int res = -1;
615 int argc = *argc_p;
616 char **argv = *argv_p;
617
618 if (argc < 2)
619 return -1;
620
621 if (strcmp(*argv, "src") == 0) {
622 NEXT_ARG();
623 res = parse_u16(&argc, &argv, sel, 0, -1);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700624 } else if (strcmp(*argv, "dst") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000625 NEXT_ARG();
626 res = parse_u16(&argc, &argv, sel, 2, -1);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700627 } else
628 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000629
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000630 *argc_p = argc;
631 *argv_p = argv;
632 return res;
633}
634
Stephen Hemminger6b1ac652007-12-31 10:29:52 -0800635
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000636static int parse_icmp(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
637{
638 int res = -1;
639 int argc = *argc_p;
640 char **argv = *argv_p;
641
642 if (argc < 2)
643 return -1;
644
645 if (strcmp(*argv, "type") == 0) {
646 NEXT_ARG();
647 res = parse_u8(&argc, &argv, sel, 0, -1);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700648 } else if (strcmp(*argv, "code") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000649 NEXT_ARG();
650 res = parse_u8(&argc, &argv, sel, 1, -1);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700651 } else
652 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000653
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000654 *argc_p = argc;
655 *argv_p = argv;
656 return res;
657}
658
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +0000659static int parse_mark(int *argc_p, char ***argv_p, struct nlmsghdr *n)
660{
661 int res = -1;
662 int argc = *argc_p;
663 char **argv = *argv_p;
664 struct tc_u32_mark mark;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000665
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +0000666 if (argc <= 1)
667 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000668
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +0000669 if (get_u32(&mark.val, *argv, 0)) {
670 fprintf(stderr, "Illegal \"mark\" value\n");
671 return -1;
672 }
673 NEXT_ARG();
674
675 if (get_u32(&mark.mask, *argv, 0)) {
676 fprintf(stderr, "Illegal \"mark\" mask\n");
677 return -1;
678 }
679 NEXT_ARG();
680
681 if ((mark.val & mark.mask) != mark.val) {
682 fprintf(stderr, "Illegal \"mark\" (impossible combination)\n");
683 return -1;
684 }
685
686 addattr_l(n, MAX_MSG, TCA_U32_MARK, &mark, sizeof(mark));
687 res = 0;
688
689 *argc_p = argc;
690 *argv_p = argv;
691 return res;
692}
693
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800694static int parse_selector(int *argc_p, char ***argv_p,
695 struct tc_u32_sel *sel, struct nlmsghdr *n)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000696{
697 int argc = *argc_p;
698 char **argv = *argv_p;
699 int res = -1;
700
701 if (argc <= 0)
702 return -1;
703
704 if (matches(*argv, "u32") == 0) {
705 NEXT_ARG();
706 res = parse_u32(&argc, &argv, sel, 0, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700707 } else if (matches(*argv, "u16") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000708 NEXT_ARG();
709 res = parse_u16(&argc, &argv, sel, 0, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700710 } else if (matches(*argv, "u8") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000711 NEXT_ARG();
712 res = parse_u8(&argc, &argv, sel, 0, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700713 } else if (matches(*argv, "ip") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000714 NEXT_ARG();
715 res = parse_ip(&argc, &argv, sel);
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700716 } else if (matches(*argv, "ip6") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000717 NEXT_ARG();
718 res = parse_ip6(&argc, &argv, sel);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700719 } else if (matches(*argv, "udp") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000720 NEXT_ARG();
721 res = parse_udp(&argc, &argv, sel);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700722 } else if (matches(*argv, "tcp") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000723 NEXT_ARG();
724 res = parse_tcp(&argc, &argv, sel);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700725 } else if (matches(*argv, "icmp") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000726 NEXT_ARG();
727 res = parse_icmp(&argc, &argv, sel);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700728 } else if (matches(*argv, "mark") == 0) {
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +0000729 NEXT_ARG();
730 res = parse_mark(&argc, &argv, n);
Stephen Hemmingerb4d41f42009-04-15 15:39:34 -0700731 } else if (matches(*argv, "ether") == 0) {
732 NEXT_ARG();
733 res = parse_ether(&argc, &argv, sel);
Stephen Hemminger3d0b7432014-12-20 15:47:17 -0800734 } else
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700735 return -1;
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +0000736
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000737 *argc_p = argc;
738 *argv_p = argv;
739 return res;
740}
741
742static int parse_offset(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
743{
744 int argc = *argc_p;
745 char **argv = *argv_p;
746
747 while (argc > 0) {
748 if (matches(*argv, "plus") == 0) {
749 int off;
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700750
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000751 NEXT_ARG();
752 if (get_integer(&off, *argv, 0))
753 return -1;
754 sel->off = off;
755 sel->flags |= TC_U32_OFFSET;
756 } else if (matches(*argv, "at") == 0) {
757 int off;
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700758
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000759 NEXT_ARG();
760 if (get_integer(&off, *argv, 0))
761 return -1;
762 sel->offoff = off;
763 if (off%2) {
764 fprintf(stderr, "offset \"at\" must be even\n");
765 return -1;
766 }
767 sel->flags |= TC_U32_VAROFFSET;
768 } else if (matches(*argv, "mask") == 0) {
769 __u16 mask;
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700770
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000771 NEXT_ARG();
772 if (get_u16(&mask, *argv, 16))
773 return -1;
774 sel->offmask = htons(mask);
775 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) {
804 __u32 mask;
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700805
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000806 NEXT_ARG();
807 if (get_u32(&mask, *argv, 16))
808 return -1;
809 sel->hmask = htonl(mask);
810 } else if (matches(*argv, "at") == 0) {
811 int num;
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700812
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000813 NEXT_ARG();
814 if (get_integer(&num, *argv, 0))
815 return -1;
816 if (num%4)
817 return -1;
818 sel->hoff = num;
819 } else {
820 break;
821 }
822 argc--; argv++;
823 }
824
825 *argc_p = argc;
826 *argv_p = argv;
827 return 0;
828}
829
jamal1750abe2008-04-20 10:49:24 -0400830static void print_ipv4(FILE *f, const struct tc_u32_key *key)
Stephen Hemminger6b1ac652007-12-31 10:29:52 -0800831{
832 char abuf[256];
833
Stephen Hemminger6b1ac652007-12-31 10:29:52 -0800834 switch (key->off) {
Stephen Hemminger4c9ffc22008-02-18 11:35:29 -0800835 case 0:
836 switch (ntohl(key->mask)) {
837 case 0x0f000000:
jamal1750abe2008-04-20 10:49:24 -0400838 fprintf(f, "\n match IP ihl %u", ntohl(key->val) >> 24);
Stephen Hemminger4c9ffc22008-02-18 11:35:29 -0800839 return;
840 case 0x00ff0000:
jamal1750abe2008-04-20 10:49:24 -0400841 fprintf(f, "\n match IP dsfield %#x", ntohl(key->val) >> 16);
Stephen Hemminger4c9ffc22008-02-18 11:35:29 -0800842 return;
843 }
844 break;
845 case 8:
846 if (ntohl(key->mask) == 0x00ff0000) {
jamal1750abe2008-04-20 10:49:24 -0400847 fprintf(f, "\n match IP protocol %d", 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:
895 fprintf(f, "\n match IP ihl %u", ntohl(key->val) >> 24);
896 return;
897 case 0x00ff0000:
898 fprintf(f, "\n match IP dsfield %#x", ntohl(key->val) >> 16);
899 return;
900 }
901 break;
902 case 8:
903 if (ntohl(key->mask) == 0x00ff0000) {
904 fprintf(f, "\n match IP protocol %d", ntohl(key->val) >> 16);
905 return;
906 }
907 break;
908 case 12:
909 case 16: {
910 int bits = mask2bits(key->mask);
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700911
Stephen Hemmingerd13cee62009-05-26 15:14:29 -0700912 if (bits >= 0) {
Stephen Hemminger3d0b7432014-12-20 15:47:17 -0800913 fprintf(f, "\n %s %s/%d",
Stephen Hemmingerd13cee62009-05-26 15:14:29 -0700914 key->off == 12 ? "match IP src" : "match IP dst",
915 inet_ntop(AF_INET, &key->val,
916 abuf, sizeof(abuf)),
917 bits);
918 return;
919 }
920 }
921 break;
922
923 case 20:
924 switch (ntohl(key->mask)) {
925 case 0x0000ffff:
926 fprintf(f, "\n match sport %u",
927 ntohl(key->val) & 0xffff);
928 return;
929 case 0xffff0000:
930 fprintf(f, "\n match dport %u",
931 ntohl(key->val) >> 16);
932 return;
933 case 0xffffffff:
934 fprintf(f, "\n match sport %u, match dport %u",
935 ntohl(key->val) & 0xffff,
936 ntohl(key->val) >> 16);
937
938 return;
939 }
940 /* XXX: Default print_raw */
941 }
942}
943
jamal1750abe2008-04-20 10:49:24 -0400944static void print_raw(FILE *f, const struct tc_u32_key *key)
945{
Stephen Hemminger3d0b7432014-12-20 15:47:17 -0800946 fprintf(f, "\n match %08x/%08x at %s%d",
Stephen Hemminger6b1ac652007-12-31 10:29:52 -0800947 (unsigned int)ntohl(key->val),
948 (unsigned int)ntohl(key->mask),
949 key->offmask ? "nexthdr+" : "",
950 key->off);
951}
952
jamal1750abe2008-04-20 10:49:24 -0400953static const struct {
954 __u16 proto;
955 __u16 pad;
956 void (*pprinter)(FILE *f, const struct tc_u32_key *key);
957} u32_pprinters[] = {
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700958 {0, 0, print_raw},
jamal1750abe2008-04-20 10:49:24 -0400959 {ETH_P_IP, 0, print_ipv4},
Stephen Hemmingerd13cee62009-05-26 15:14:29 -0700960 {ETH_P_IPV6, 0, print_ipv6},
jamal1750abe2008-04-20 10:49:24 -0400961};
962
963static void show_keys(FILE *f, const struct tc_u32_key *key)
964{
965 int i = 0;
966
967 if (!show_pretty)
968 goto show_k;
969
Stephen Hemminger32a121c2016-03-21 11:48:36 -0700970 for (i = 0; i < ARRAY_SIZE(u32_pprinters); i++) {
jamal1750abe2008-04-20 10:49:24 -0400971 if (u32_pprinters[i].proto == ntohs(f_proto)) {
972show_k:
973 u32_pprinters[i].pprinter(f, key);
974 return;
975 }
976 }
977
978 i = 0;
979 goto show_k;
980}
981
982static int u32_parse_opt(struct filter_util *qu, char *handle,
Stephen Hemminger6b1ac652007-12-31 10:29:52 -0800983 int argc, char **argv, struct nlmsghdr *n)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000984{
985 struct {
986 struct tc_u32_sel sel;
987 struct tc_u32_key keys[128];
988 } sel;
989 struct tcmsg *t = NLMSG_DATA(n);
990 struct rtattr *tail;
jamaldcf13492006-12-07 11:07:07 -0500991 int sel_ok = 0, terminal_ok = 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000992 int sample_ok = 0;
993 __u32 htid = 0;
994 __u32 order = 0;
995
996 memset(&sel, 0, sizeof(sel));
997
998 if (handle && get_u32_handle(&t->tcm_handle, handle)) {
999 fprintf(stderr, "Illegal filter ID\n");
1000 return -1;
1001 }
1002
1003 if (argc == 0)
1004 return 0;
1005
8!tgraf4a86fe12005-01-18 01:24:18 +00001006 tail = NLMSG_TAIL(n);
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001007 addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001008
1009 while (argc > 0) {
1010 if (matches(*argv, "match") == 0) {
1011 NEXT_ARG();
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +00001012 if (parse_selector(&argc, &argv, &sel.sel, n)) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001013 fprintf(stderr, "Illegal \"match\"\n");
1014 return -1;
1015 }
1016 sel_ok++;
1017 continue;
1018 } else if (matches(*argv, "offset") == 0) {
1019 NEXT_ARG();
1020 if (parse_offset(&argc, &argv, &sel.sel)) {
1021 fprintf(stderr, "Illegal \"offset\"\n");
1022 return -1;
1023 }
1024 continue;
1025 } else if (matches(*argv, "hashkey") == 0) {
1026 NEXT_ARG();
1027 if (parse_hashkey(&argc, &argv, &sel.sel)) {
1028 fprintf(stderr, "Illegal \"hashkey\"\n");
1029 return -1;
1030 }
1031 continue;
1032 } else if (matches(*argv, "classid") == 0 ||
1033 strcmp(*argv, "flowid") == 0) {
Stephen Hemminger32a121c2016-03-21 11:48:36 -07001034 unsigned int handle;
1035
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001036 NEXT_ARG();
1037 if (get_tc_classid(&handle, *argv)) {
1038 fprintf(stderr, "Illegal \"classid\"\n");
1039 return -1;
1040 }
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001041 addattr_l(n, MAX_MSG, TCA_U32_CLASSID, &handle, 4);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001042 sel.sel.flags |= TC_U32_TERMINAL;
1043 } else if (matches(*argv, "divisor") == 0) {
Stephen Hemminger32a121c2016-03-21 11:48:36 -07001044 unsigned int divisor;
1045
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001046 NEXT_ARG();
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001047 if (get_unsigned(&divisor, *argv, 0) ||
shemminger46b67da2006-03-14 19:38:34 +00001048 divisor == 0 ||
1049 divisor > 0x100 || ((divisor - 1) & divisor)) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001050 fprintf(stderr, "Illegal \"divisor\"\n");
1051 return -1;
1052 }
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001053 addattr_l(n, MAX_MSG, TCA_U32_DIVISOR, &divisor, 4);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001054 } else if (matches(*argv, "order") == 0) {
1055 NEXT_ARG();
1056 if (get_u32(&order, *argv, 0)) {
1057 fprintf(stderr, "Illegal \"order\"\n");
1058 return -1;
1059 }
1060 } else if (strcmp(*argv, "link") == 0) {
Stephen Hemminger32a121c2016-03-21 11:48:36 -07001061 unsigned int handle;
1062
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001063 NEXT_ARG();
1064 if (get_u32_handle(&handle, *argv)) {
1065 fprintf(stderr, "Illegal \"link\"\n");
1066 return -1;
1067 }
1068 if (handle && TC_U32_NODE(handle)) {
1069 fprintf(stderr, "\"link\" must be a hash table.\n");
1070 return -1;
1071 }
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001072 addattr_l(n, MAX_MSG, TCA_U32_LINK, &handle, 4);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001073 } else if (strcmp(*argv, "ht") == 0) {
Stephen Hemminger32a121c2016-03-21 11:48:36 -07001074 unsigned int handle;
1075
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001076 NEXT_ARG();
1077 if (get_u32_handle(&handle, *argv)) {
1078 fprintf(stderr, "Illegal \"ht\"\n");
1079 return -1;
1080 }
1081 if (handle && TC_U32_NODE(handle)) {
1082 fprintf(stderr, "\"ht\" must be a hash table.\n");
1083 return -1;
1084 }
1085 if (sample_ok)
Phil Sutter40eb7372015-10-23 19:21:23 +02001086 htid = (htid & 0xFF000) | (handle & 0xFFF00000);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001087 else
Phil Sutter40eb7372015-10-23 19:21:23 +02001088 htid = (handle & 0xFFFFF000);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001089 } else if (strcmp(*argv, "sample") == 0) {
1090 __u32 hash;
Stephen Hemminger32a121c2016-03-21 11:48:36 -07001091 unsigned int divisor = 0x100;
shemminger267480f2006-03-22 00:07:49 +00001092
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001093 struct {
1094 struct tc_u32_sel sel;
1095 struct tc_u32_key keys[4];
1096 } sel2;
shemminger46b67da2006-03-14 19:38:34 +00001097 memset(&sel2, 0, sizeof(sel2));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001098 NEXT_ARG();
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +00001099 if (parse_selector(&argc, &argv, &sel2.sel, n)) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001100 fprintf(stderr, "Illegal \"sample\"\n");
1101 return -1;
1102 }
1103 if (sel2.sel.nkeys != 1) {
Stephen Hemminger32a121c2016-03-21 11:48:36 -07001104 fprintf(stderr, "\"sample\" must contain exactly ONE key.\n");
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001105 return -1;
1106 }
shemminger3925ad82006-03-14 19:36:31 +00001107 if (*argv != 0 && strcmp(*argv, "divisor") == 0) {
1108 NEXT_ARG();
1109 if (get_unsigned(&divisor, *argv, 0) || divisor == 0 ||
shemminger46b67da2006-03-14 19:38:34 +00001110 divisor > 0x100 || ((divisor - 1) & divisor)) {
shemminger3925ad82006-03-14 19:36:31 +00001111 fprintf(stderr, "Illegal sample \"divisor\"\n");
1112 return -1;
1113 }
1114 NEXT_ARG();
1115 }
Phil Sutter40eb7372015-10-23 19:21:23 +02001116 hash = sel2.sel.keys[0].val & sel2.sel.keys[0].mask;
1117 hash ^= hash >> 16;
1118 hash ^= hash >> 8;
1119 htid = ((hash % divisor) << 12) | (htid & 0xFFF00000);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001120 sample_ok = 1;
1121 continue;
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001122 } else if (strcmp(*argv, "indev") == 0) {
1123 char ind[IFNAMSIZ + 1];
Stephen Hemminger32a121c2016-03-21 11:48:36 -07001124
Luca Lemmo725f2a82016-03-16 17:56:13 +01001125 memset(ind, 0, sizeof(ind));
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001126 argc--;
1127 argv++;
1128 if (argc < 1) {
1129 fprintf(stderr, "Illegal indev\n");
1130 return -1;
1131 }
Luca Lemmo725f2a82016-03-16 17:56:13 +01001132 strncpy(ind, *argv, sizeof(ind) - 1);
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001133 addattr_l(n, MAX_MSG, TCA_U32_INDEV, ind, strlen(ind) + 1);
net[shemminger]!shemmingerd81b1352004-08-23 20:20:41 +00001134
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001135 } else if (matches(*argv, "action") == 0) {
1136 NEXT_ARG();
1137 if (parse_action(&argc, &argv, TCA_U32_ACT, n)) {
1138 fprintf(stderr, "Illegal \"action\"\n");
1139 return -1;
1140 }
jamaldcf13492006-12-07 11:07:07 -05001141 terminal_ok++;
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001142 continue;
net[shemminger]!shemmingerd81b1352004-08-23 20:20:41 +00001143
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001144 } else if (matches(*argv, "police") == 0) {
1145 NEXT_ARG();
1146 if (parse_police(&argc, &argv, TCA_U32_POLICE, n)) {
1147 fprintf(stderr, "Illegal \"police\"\n");
1148 return -1;
1149 }
jamaldcf13492006-12-07 11:07:07 -05001150 terminal_ok++;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001151 continue;
1152 } else if (strcmp(*argv, "help") == 0) {
1153 explain();
1154 return -1;
1155 } else {
1156 fprintf(stderr, "What is \"%s\"?\n", *argv);
1157 explain();
1158 return -1;
1159 }
1160 argc--; argv++;
1161 }
1162
jamaldcf13492006-12-07 11:07:07 -05001163 /* We dont necessarily need class/flowids */
Stephen Hemminger81c61792006-12-13 17:05:50 -08001164 if (terminal_ok)
jamaldcf13492006-12-07 11:07:07 -05001165 sel.sel.flags |= TC_U32_TERMINAL;
Stephen Hemminger3d0b7432014-12-20 15:47:17 -08001166
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001167 if (order) {
1168 if (TC_U32_NODE(t->tcm_handle) && order != TC_U32_NODE(t->tcm_handle)) {
1169 fprintf(stderr, "\"order\" contradicts \"handle\"\n");
1170 return -1;
1171 }
1172 t->tcm_handle |= order;
1173 }
1174
1175 if (htid)
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001176 addattr_l(n, MAX_MSG, TCA_U32_HASH, &htid, 4);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001177 if (sel_ok)
Stephen Hemminger3d0b7432014-12-20 15:47:17 -08001178 addattr_l(n, MAX_MSG, TCA_U32_SEL, &sel,
Phil Sutter40eb7372015-10-23 19:21:23 +02001179 sizeof(sel.sel) + sel.sel.nkeys * sizeof(struct tc_u32_key));
8!tgraf4a86fe12005-01-18 01:24:18 +00001180 tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001181 return 0;
1182}
1183
Stephen Hemminger6b1ac652007-12-31 10:29:52 -08001184static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt,
1185 __u32 handle)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001186{
Phil Sutter40eb7372015-10-23 19:21:23 +02001187 struct rtattr *tb[TCA_U32_MAX + 1];
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001188 struct tc_u32_sel *sel = NULL;
net[shemminger]!shemmingerd81b1352004-08-23 20:20:41 +00001189 struct tc_u32_pcnt *pf = NULL;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001190
1191 if (opt == NULL)
1192 return 0;
1193
8!tgrafac2fc2d2005-01-18 22:11:58 +00001194 parse_rtattr_nested(tb, TCA_U32_MAX, opt);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001195
1196 if (handle) {
1197 SPRINT_BUF(b1);
1198 fprintf(f, "fh %s ", sprint_u32_handle(handle, b1));
1199 }
1200 if (TC_U32_NODE(handle)) {
1201 fprintf(f, "order %d ", TC_U32_NODE(handle));
1202 }
1203
1204 if (tb[TCA_U32_SEL]) {
1205 if (RTA_PAYLOAD(tb[TCA_U32_SEL]) < sizeof(*sel))
1206 return -1;
1207
1208 sel = RTA_DATA(tb[TCA_U32_SEL]);
1209 }
1210
1211 if (tb[TCA_U32_DIVISOR]) {
Stephen Hemmingerff247462012-04-10 08:47:55 -07001212 fprintf(f, "ht divisor %d ", rta_getattr_u32(tb[TCA_U32_DIVISOR]));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001213 } else if (tb[TCA_U32_HASH]) {
Stephen Hemmingerff247462012-04-10 08:47:55 -07001214 __u32 htid = rta_getattr_u32(tb[TCA_U32_HASH]);
Stephen Hemminger32a121c2016-03-21 11:48:36 -07001215
Stephen Hemmingere62077d2008-02-18 10:51:42 -08001216 fprintf(f, "key ht %x bkt %x ", TC_U32_USERHTID(htid),
1217 TC_U32_HASH(htid));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001218 } else {
1219 fprintf(f, "??? ");
1220 }
1221 if (tb[TCA_U32_CLASSID]) {
1222 SPRINT_BUF(b1);
1223 fprintf(f, "%sflowid %s ",
Phil Sutter40eb7372015-10-23 19:21:23 +02001224 !sel || !(sel->flags & TC_U32_TERMINAL) ? "*" : "",
Stephen Hemmingerff247462012-04-10 08:47:55 -07001225 sprint_tc_classid(rta_getattr_u32(tb[TCA_U32_CLASSID]), b1));
Phil Sutter40eb7372015-10-23 19:21:23 +02001226 } else if (sel && sel->flags & TC_U32_TERMINAL) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001227 fprintf(f, "terminal flowid ??? ");
1228 }
1229 if (tb[TCA_U32_LINK]) {
1230 SPRINT_BUF(b1);
Stephen Hemmingere62077d2008-02-18 10:51:42 -08001231 fprintf(f, "link %s ",
Stephen Hemmingerff247462012-04-10 08:47:55 -07001232 sprint_u32_handle(rta_getattr_u32(tb[TCA_U32_LINK]), b1));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001233 }
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001234
net[shemminger]!shemmingerd81b1352004-08-23 20:20:41 +00001235 if (tb[TCA_U32_PCNT]) {
1236 if (RTA_PAYLOAD(tb[TCA_U32_PCNT]) < sizeof(*pf)) {
Stephen Hemminger32a121c2016-03-21 11:48:36 -07001237 fprintf(f, "Broken perf counters\n");
net[shemminger]!shemmingerd81b1352004-08-23 20:20:41 +00001238 return -1;
1239 }
1240 pf = RTA_DATA(tb[TCA_U32_PCNT]);
1241 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001242
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +00001243 if (sel && show_stats && NULL != pf)
net[shemminger]!shemmingerb9062432005-01-17 23:28:16 +00001244 fprintf(f, " (rule hit %llu success %llu)",
1245 (unsigned long long) pf->rcnt,
1246 (unsigned long long) pf->rhit);
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +00001247
1248 if (tb[TCA_U32_MARK]) {
1249 struct tc_u32_mark *mark = RTA_DATA(tb[TCA_U32_MARK]);
Stephen Hemminger32a121c2016-03-21 11:48:36 -07001250
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +00001251 if (RTA_PAYLOAD(tb[TCA_U32_MARK]) < sizeof(*mark)) {
1252 fprintf(f, "\n Invalid mark (kernel&iproute2 mismatch)\n");
1253 } else {
1254 fprintf(f, "\n mark 0x%04x 0x%04x (success %d)",
1255 mark->val, mark->mask, mark->success);
1256 }
1257 }
1258
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001259 if (sel) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001260 if (sel->nkeys) {
Stephen Hemminger6b1ac652007-12-31 10:29:52 -08001261 int i;
Stephen Hemminger32a121c2016-03-21 11:48:36 -07001262
Luca Lemmodd0c8d12016-03-16 17:56:12 +01001263 for (i = 0; i < sel->nkeys; i++) {
jamal1750abe2008-04-20 10:49:24 -04001264 show_keys(f, sel->keys + i);
net[shemminger]!shemmingerd81b1352004-08-23 20:20:41 +00001265 if (show_stats && NULL != pf)
Stephen Hemminger6b1ac652007-12-31 10:29:52 -08001266 fprintf(f, " (success %llu ) ",
net[shemminger]!shemmingerb9062432005-01-17 23:28:16 +00001267 (unsigned long long) pf->kcnts[i]);
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001268 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001269 }
1270
Phil Sutter40eb7372015-10-23 19:21:23 +02001271 if (sel->flags & (TC_U32_VAROFFSET | TC_U32_OFFSET)) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001272 fprintf(f, "\n offset ");
Phil Sutter40eb7372015-10-23 19:21:23 +02001273 if (sel->flags & TC_U32_VAROFFSET)
Stephen Hemmingere62077d2008-02-18 10:51:42 -08001274 fprintf(f, "%04x>>%d at %d ",
1275 ntohs(sel->offmask),
1276 sel->offshift, sel->offoff);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001277 if (sel->off)
1278 fprintf(f, "plus %d ", sel->off);
1279 }
Phil Sutter40eb7372015-10-23 19:21:23 +02001280 if (sel->flags & TC_U32_EAT)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001281 fprintf(f, " eat ");
1282
1283 if (sel->hmask) {
1284 fprintf(f, "\n hash mask %08x at %d ",
1285 (unsigned int)htonl(sel->hmask), sel->hoff);
1286 }
1287 }
1288
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001289 if (tb[TCA_U32_POLICE]) {
1290 fprintf(f, "\n");
1291 tc_print_police(f, tb[TCA_U32_POLICE]);
1292 }
1293 if (tb[TCA_U32_INDEV]) {
1294 struct rtattr *idev = tb[TCA_U32_INDEV];
Stephen Hemminger32a121c2016-03-21 11:48:36 -07001295
Stephen Hemmingerff247462012-04-10 08:47:55 -07001296 fprintf(f, "\n input dev %s\n", rta_getattr_str(idev));
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001297 }
1298 if (tb[TCA_U32_ACT]) {
1299 tc_print_action(f, tb[TCA_U32_ACT]);
1300 }
1301
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001302 return 0;
1303}
1304
osdl.net!shemminger6b7dff12004-09-28 18:35:49 +00001305struct filter_util u32_filter_util = {
1306 .id = "u32",
1307 .parse_fopt = u32_parse_opt,
1308 .print_fopt = u32_print_opt,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001309};