blob: 479b3f1bb8587b256b81816773e7f763e8b9c3a7 [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 Hemmingere62077d2008-02-18 10:51:42 -080033 fprintf(stderr, "Usage: ... u32 [ match SELECTOR ... ] [ link HTID ]"
34 " [ classid CLASSID ]\n");
35 fprintf(stderr, " [ police POLICE_SPEC ]"
36 " [ offset OFFSET_SPEC ]\n");
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000037 fprintf(stderr, " [ ht HTID ] [ hashkey HASHKEY_SPEC ]\n");
38 fprintf(stderr, " [ sample SAMPLE ]\n");
39 fprintf(stderr, "or u32 divisor DIVISOR\n");
40 fprintf(stderr, "\n");
41 fprintf(stderr, "Where: SELECTOR := SAMPLE SAMPLE ...\n");
Stephen Hemmingere62077d2008-02-18 10:51:42 -080042 fprintf(stderr, " SAMPLE := { ip | ip6 | udp | tcp | icmp |"
43 " u{32|16|8} | mark } SAMPLE_ARGS [divisor DIVISOR]\n");
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000044 fprintf(stderr, " FILTERID := X:Y:Z\n");
PJ Waskiewicze9acc242008-02-13 03:49:09 -080045 fprintf(stderr, "\nNOTE: CLASSID is parsed at hexadecimal input.\n");
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000046}
47
Stephen Hemminger9fce67d2009-04-03 09:38:56 -070048int get_u32_handle(__u32 *handle, const char *str)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000049{
50 __u32 htid=0, hash=0, nodeid=0;
51 char *tmp = strchr(str, ':');
52
53 if (tmp == NULL) {
54 if (memcmp("0x", str, 2) == 0)
55 return get_u32(handle, str, 16);
56 return -1;
57 }
58 htid = strtoul(str, &tmp, 16);
59 if (tmp == str && *str != ':' && *str != 0)
60 return -1;
61 if (htid>=0x1000)
62 return -1;
63 if (*tmp) {
64 str = tmp+1;
65 hash = strtoul(str, &tmp, 16);
66 if (tmp == str && *str != ':' && *str != 0)
67 return -1;
68 if (hash>=0x100)
69 return -1;
70 if (*tmp) {
71 str = tmp+1;
72 nodeid = strtoul(str, &tmp, 16);
73 if (tmp == str && *str != 0)
74 return -1;
75 if (nodeid>=0x1000)
76 return -1;
77 }
78 }
79 *handle = (htid<<20)|(hash<<12)|nodeid;
80 return 0;
81}
82
83char * sprint_u32_handle(__u32 handle, char *buf)
84{
85 int bsize = SPRINT_BSIZE-1;
86 __u32 htid = TC_U32_HTID(handle);
87 __u32 hash = TC_U32_HASH(handle);
88 __u32 nodeid = TC_U32_NODE(handle);
89 char *b = buf;
90
91 if (handle == 0) {
92 snprintf(b, bsize, "none");
93 return b;
94 }
95 if (htid) {
96 int l = snprintf(b, bsize, "%x:", htid>>20);
97 bsize -= l;
98 b += l;
99 }
100 if (nodeid|hash) {
101 if (hash) {
102 int l = snprintf(b, bsize, "%x", hash);
103 bsize -= l;
104 b += l;
105 }
106 if (nodeid) {
107 int l = snprintf(b, bsize, ":%x", nodeid);
108 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
125 for (i=0; i<hwm; i++) {
126 if (sel->keys[i].off == off && sel->keys[i].offmask == offmask) {
127 __u32 intersect = mask&sel->keys[i].mask;
128
129 if ((key^sel->keys[i].val) & intersect)
130 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
197int parse_at(int *argc_p, char ***argv_p, int *off, int *offmask)
198{
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)
349 mask = htonl(0xFFFFFFFF<<(32-addr.bitlen));
350 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;
384 for (i=0; i<plen; i+=32) {
osdl.net!shemminger2373fde2004-08-13 23:54:55 +0000385// if (((i+31)&~0x1F)<=plen) {
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800386 if (i + 31 <= plen) {
387 res = pack_key(sel, addr.data[i/32],
388 0xFFFFFFFF, off+4*(i/32), offmask);
389 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) {
392 __u32 mask = htonl(0xFFFFFFFF << (32 - (plen -i )));
393 res = pack_key(sel, addr.data[i/32],
394 mask, off+4*(i/32), offmask);
395 if (res < 0)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000396 return -1;
397 }
398 }
399 res = 0;
400
401 *argc_p = argc;
402 *argv_p = argv;
403 return res;
404}
405
Petr Lautrbach01564122010-06-14 03:36:28 +0000406static int parse_ip6_class(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
407{
408 int res = -1;
409 int argc = *argc_p;
410 char **argv = *argv_p;
411 __u32 key;
412 __u32 mask;
413 int off = 0;
414 int offmask = 0;
415
416 if (argc < 2)
417 return -1;
418
419 if (get_u32(&key, *argv, 0))
420 return -1;
421 argc--; argv++;
422
423 if (get_u32(&mask, *argv, 16))
424 return -1;
425 argc--; argv++;
426
427 if (key > 0xFF || mask > 0xFF)
428 return -1;
429
430 key <<= 20;
431 mask <<= 20;
432 key = htonl(key);
433 mask = htonl(mask);
434
Stephen Hemmingerd7ac9ad2011-03-09 10:42:35 -0800435 res = pack_key(sel, key, mask, off, offmask);
436 if (res < 0)
Petr Lautrbach01564122010-06-14 03:36:28 +0000437 return -1;
438
439 *argc_p = argc;
440 *argv_p = argv;
441 return 0;
442}
443
Stephen Hemmingerb4d41f42009-04-15 15:39:34 -0700444static int parse_ether_addr(int *argc_p, char ***argv_p,
445 struct tc_u32_sel *sel, int off)
446{
447 int res = -1;
448 int argc = *argc_p;
449 char **argv = *argv_p;
450 __u8 addr[6];
451 int offmask = 0;
Stephen Hemmingerb4d41f42009-04-15 15:39:34 -0700452 int i;
453
454 if (argc < 1)
455 return -1;
456
457 if (sscanf(*argv, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
458 addr + 0, addr + 1, addr + 2,
459 addr + 3, addr + 4, addr + 5) != 6) {
460 fprintf(stderr, "parse_ether_addr: improperly formed address '%s'\n",
461 *argv);
462 return -1;
463 }
464
465 argc--; argv++;
466 if (argc > 0 && strcmp(argv[0], "at") == 0) {
467 NEXT_ARG();
468 if (parse_at(&argc, &argv, &off, &offmask))
469 return -1;
470 }
471
Stephen Hemmingere3d153c2010-08-02 11:55:30 -0700472 for (i = 0; i < 6; i++) {
473 res = pack_key8(sel, addr[i], 0xFF, off + i, offmask);
Stephen Hemmingerb4d41f42009-04-15 15:39:34 -0700474 if (res < 0)
475 return -1;
476 }
477
478 *argc_p = argc;
479 *argv_p = argv;
480 return res;
481}
482
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000483static int parse_ip(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
484{
485 int res = -1;
486 int argc = *argc_p;
487 char **argv = *argv_p;
488
489 if (argc < 2)
490 return -1;
491
492 if (strcmp(*argv, "src") == 0) {
493 NEXT_ARG();
494 res = parse_ip_addr(&argc, &argv, sel, 12);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700495 } else if (strcmp(*argv, "dst") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000496 NEXT_ARG();
497 res = parse_ip_addr(&argc, &argv, sel, 16);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700498 } else if (strcmp(*argv, "tos") == 0 ||
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000499 matches(*argv, "dsfield") == 0) {
500 NEXT_ARG();
501 res = parse_u8(&argc, &argv, sel, 1, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700502 } else if (strcmp(*argv, "ihl") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000503 NEXT_ARG();
504 res = parse_u8(&argc, &argv, sel, 0, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700505 } else if (strcmp(*argv, "protocol") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000506 NEXT_ARG();
507 res = parse_u8(&argc, &argv, sel, 9, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700508 } else if (matches(*argv, "precedence") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000509 NEXT_ARG();
510 res = parse_u8(&argc, &argv, sel, 1, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700511 } else if (strcmp(*argv, "nofrag") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000512 argc--; argv++;
513 res = pack_key16(sel, 0, 0x3FFF, 6, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700514 } else if (strcmp(*argv, "firstfrag") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000515 argc--; argv++;
516 res = pack_key16(sel, 0, 0x1FFF, 6, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700517 } else if (strcmp(*argv, "df") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000518 argc--; argv++;
519 res = pack_key16(sel, 0x4000, 0x4000, 6, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700520 } else if (strcmp(*argv, "mf") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000521 argc--; argv++;
522 res = pack_key16(sel, 0x2000, 0x2000, 6, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700523 } else if (strcmp(*argv, "dport") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000524 NEXT_ARG();
525 res = parse_u16(&argc, &argv, sel, 22, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700526 } else if (strcmp(*argv, "sport") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000527 NEXT_ARG();
528 res = parse_u16(&argc, &argv, sel, 20, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700529 } else if (strcmp(*argv, "icmp_type") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000530 NEXT_ARG();
531 res = parse_u8(&argc, &argv, sel, 20, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700532 } else if (strcmp(*argv, "icmp_code") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000533 NEXT_ARG();
534 res = parse_u8(&argc, &argv, sel, 20, 1);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700535 } else
536 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000537
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000538 *argc_p = argc;
539 *argv_p = argv;
540 return res;
541}
Stephen Hemminger6b1ac652007-12-31 10:29:52 -0800542
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000543static int parse_ip6(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
544{
545 int res = -1;
546 int argc = *argc_p;
547 char **argv = *argv_p;
548
549 if (argc < 2)
550 return -1;
551
552 if (strcmp(*argv, "src") == 0) {
553 NEXT_ARG();
554 res = parse_ip6_addr(&argc, &argv, sel, 8);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700555 } else if (strcmp(*argv, "dst") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000556 NEXT_ARG();
557 res = parse_ip6_addr(&argc, &argv, sel, 24);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700558 } else if (strcmp(*argv, "priority") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000559 NEXT_ARG();
Petr Lautrbach01564122010-06-14 03:36:28 +0000560 res = parse_ip6_class(&argc, &argv, sel);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700561 } else if (strcmp(*argv, "protocol") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000562 NEXT_ARG();
563 res = parse_u8(&argc, &argv, sel, 6, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700564 } else if (strcmp(*argv, "flowlabel") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000565 NEXT_ARG();
566 res = parse_u32(&argc, &argv, sel, 0, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700567 } else if (strcmp(*argv, "dport") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000568 NEXT_ARG();
569 res = parse_u16(&argc, &argv, sel, 42, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700570 } else if (strcmp(*argv, "sport") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000571 NEXT_ARG();
572 res = parse_u16(&argc, &argv, sel, 40, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700573 } else if (strcmp(*argv, "icmp_type") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000574 NEXT_ARG();
575 res = parse_u8(&argc, &argv, sel, 40, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700576 } else if (strcmp(*argv, "icmp_code") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000577 NEXT_ARG();
578 res = parse_u8(&argc, &argv, sel, 41, 1);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700579 } else
580 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000581
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000582 *argc_p = argc;
583 *argv_p = argv;
584 return res;
585}
586
Stephen Hemmingerb4d41f42009-04-15 15:39:34 -0700587static int parse_ether(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
588{
589 int res = -1;
590 int argc = *argc_p;
591 char **argv = *argv_p;
592
593 if (argc < 2)
594 return -1;
595
596 if (strcmp(*argv, "src") == 0) {
597 NEXT_ARG();
598 res = parse_ether_addr(&argc, &argv, sel, -8);
599 } else if (strcmp(*argv, "dst") == 0) {
600 NEXT_ARG();
601 res = parse_ether_addr(&argc, &argv, sel, -14);
602 } else {
603 fprintf(stderr, "Unknown match: ether %s\n", *argv);
604 return -1;
605 }
606
607 *argc_p = argc;
608 *argv_p = argv;
609 return res;
610}
611
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000612#define parse_tcp parse_udp
613static int parse_udp(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
614{
615 int res = -1;
616 int argc = *argc_p;
617 char **argv = *argv_p;
618
619 if (argc < 2)
620 return -1;
621
622 if (strcmp(*argv, "src") == 0) {
623 NEXT_ARG();
624 res = parse_u16(&argc, &argv, sel, 0, -1);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700625 } else if (strcmp(*argv, "dst") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000626 NEXT_ARG();
627 res = parse_u16(&argc, &argv, sel, 2, -1);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700628 } else
629 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000630
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000631 *argc_p = argc;
632 *argv_p = argv;
633 return res;
634}
635
Stephen Hemminger6b1ac652007-12-31 10:29:52 -0800636
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000637static int parse_icmp(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
638{
639 int res = -1;
640 int argc = *argc_p;
641 char **argv = *argv_p;
642
643 if (argc < 2)
644 return -1;
645
646 if (strcmp(*argv, "type") == 0) {
647 NEXT_ARG();
648 res = parse_u8(&argc, &argv, sel, 0, -1);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700649 } else if (strcmp(*argv, "code") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000650 NEXT_ARG();
651 res = parse_u8(&argc, &argv, sel, 1, -1);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700652 } else
653 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000654
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000655 *argc_p = argc;
656 *argv_p = argv;
657 return res;
658}
659
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +0000660static int parse_mark(int *argc_p, char ***argv_p, struct nlmsghdr *n)
661{
662 int res = -1;
663 int argc = *argc_p;
664 char **argv = *argv_p;
665 struct tc_u32_mark mark;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000666
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +0000667 if (argc <= 1)
668 return -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000669
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +0000670 if (get_u32(&mark.val, *argv, 0)) {
671 fprintf(stderr, "Illegal \"mark\" value\n");
672 return -1;
673 }
674 NEXT_ARG();
675
676 if (get_u32(&mark.mask, *argv, 0)) {
677 fprintf(stderr, "Illegal \"mark\" mask\n");
678 return -1;
679 }
680 NEXT_ARG();
681
682 if ((mark.val & mark.mask) != mark.val) {
683 fprintf(stderr, "Illegal \"mark\" (impossible combination)\n");
684 return -1;
685 }
686
687 addattr_l(n, MAX_MSG, TCA_U32_MARK, &mark, sizeof(mark));
688 res = 0;
689
690 *argc_p = argc;
691 *argv_p = argv;
692 return res;
693}
694
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800695static int parse_selector(int *argc_p, char ***argv_p,
696 struct tc_u32_sel *sel, struct nlmsghdr *n)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000697{
698 int argc = *argc_p;
699 char **argv = *argv_p;
700 int res = -1;
701
702 if (argc <= 0)
703 return -1;
704
705 if (matches(*argv, "u32") == 0) {
706 NEXT_ARG();
707 res = parse_u32(&argc, &argv, sel, 0, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700708 } else if (matches(*argv, "u16") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000709 NEXT_ARG();
710 res = parse_u16(&argc, &argv, sel, 0, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700711 } else if (matches(*argv, "u8") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000712 NEXT_ARG();
713 res = parse_u8(&argc, &argv, sel, 0, 0);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700714 } else if (matches(*argv, "ip") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000715 NEXT_ARG();
716 res = parse_ip(&argc, &argv, sel);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700717 } else if (matches(*argv, "ip6") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000718 NEXT_ARG();
719 res = parse_ip6(&argc, &argv, sel);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700720 } else if (matches(*argv, "udp") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000721 NEXT_ARG();
722 res = parse_udp(&argc, &argv, sel);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700723 } else if (matches(*argv, "tcp") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000724 NEXT_ARG();
725 res = parse_tcp(&argc, &argv, sel);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700726 } else if (matches(*argv, "icmp") == 0) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000727 NEXT_ARG();
728 res = parse_icmp(&argc, &argv, sel);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700729 } else if (matches(*argv, "mark") == 0) {
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +0000730 NEXT_ARG();
731 res = parse_mark(&argc, &argv, n);
Stephen Hemmingerb4d41f42009-04-15 15:39:34 -0700732 } else if (matches(*argv, "ether") == 0) {
733 NEXT_ARG();
734 res = parse_ether(&argc, &argv, sel);
Stephen Hemminger9fce67d2009-04-03 09:38:56 -0700735 } else
736 return -1;
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +0000737
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000738 *argc_p = argc;
739 *argv_p = argv;
740 return res;
741}
742
743static int parse_offset(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
744{
745 int argc = *argc_p;
746 char **argv = *argv_p;
747
748 while (argc > 0) {
749 if (matches(*argv, "plus") == 0) {
750 int off;
751 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;
758 NEXT_ARG();
759 if (get_integer(&off, *argv, 0))
760 return -1;
761 sel->offoff = off;
762 if (off%2) {
763 fprintf(stderr, "offset \"at\" must be even\n");
764 return -1;
765 }
766 sel->flags |= TC_U32_VAROFFSET;
767 } else if (matches(*argv, "mask") == 0) {
768 __u16 mask;
769 NEXT_ARG();
770 if (get_u16(&mask, *argv, 16))
771 return -1;
772 sel->offmask = htons(mask);
773 sel->flags |= TC_U32_VAROFFSET;
774 } else if (matches(*argv, "shift") == 0) {
775 int shift;
776 NEXT_ARG();
777 if (get_integer(&shift, *argv, 0))
778 return -1;
779 sel->offshift = shift;
780 sel->flags |= TC_U32_VAROFFSET;
781 } else if (matches(*argv, "eat") == 0) {
782 sel->flags |= TC_U32_EAT;
783 } else {
784 break;
785 }
786 argc--; argv++;
787 }
788
789 *argc_p = argc;
790 *argv_p = argv;
791 return 0;
792}
793
794static int parse_hashkey(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
795{
796 int argc = *argc_p;
797 char **argv = *argv_p;
798
799 while (argc > 0) {
800 if (matches(*argv, "mask") == 0) {
801 __u32 mask;
802 NEXT_ARG();
803 if (get_u32(&mask, *argv, 16))
804 return -1;
805 sel->hmask = htonl(mask);
806 } else if (matches(*argv, "at") == 0) {
807 int num;
808 NEXT_ARG();
809 if (get_integer(&num, *argv, 0))
810 return -1;
811 if (num%4)
812 return -1;
813 sel->hoff = num;
814 } else {
815 break;
816 }
817 argc--; argv++;
818 }
819
820 *argc_p = argc;
821 *argv_p = argv;
822 return 0;
823}
824
jamal1750abe2008-04-20 10:49:24 -0400825static void print_ipv4(FILE *f, const struct tc_u32_key *key)
Stephen Hemminger6b1ac652007-12-31 10:29:52 -0800826{
827 char abuf[256];
828
Stephen Hemminger6b1ac652007-12-31 10:29:52 -0800829 switch (key->off) {
Stephen Hemminger4c9ffc22008-02-18 11:35:29 -0800830 case 0:
831 switch (ntohl(key->mask)) {
832 case 0x0f000000:
jamal1750abe2008-04-20 10:49:24 -0400833 fprintf(f, "\n match IP ihl %u", ntohl(key->val) >> 24);
Stephen Hemminger4c9ffc22008-02-18 11:35:29 -0800834 return;
835 case 0x00ff0000:
jamal1750abe2008-04-20 10:49:24 -0400836 fprintf(f, "\n match IP dsfield %#x", ntohl(key->val) >> 16);
Stephen Hemminger4c9ffc22008-02-18 11:35:29 -0800837 return;
838 }
839 break;
840 case 8:
841 if (ntohl(key->mask) == 0x00ff0000) {
jamal1750abe2008-04-20 10:49:24 -0400842 fprintf(f, "\n match IP protocol %d", ntohl(key->val) >> 16);
Stephen Hemminger4c9ffc22008-02-18 11:35:29 -0800843 return;
844 }
845 break;
Stephen Hemminger6b1ac652007-12-31 10:29:52 -0800846 case 12:
847 case 16: {
848 int bits = mask2bits(key->mask);
849 if (bits >= 0) {
Stephen Hemminger4c9ffc22008-02-18 11:35:29 -0800850 fprintf(f, "\n %s %s/%d",
jamal1750abe2008-04-20 10:49:24 -0400851 key->off == 12 ? "match IP src" : "match IP dst",
Stephen Hemmingere62077d2008-02-18 10:51:42 -0800852 inet_ntop(AF_INET, &key->val,
853 abuf, sizeof(abuf)),
Stephen Hemminger6b1ac652007-12-31 10:29:52 -0800854 bits);
855 return;
856 }
857 }
858 break;
859
860 case 20:
Stephen Hemminger4c9ffc22008-02-18 11:35:29 -0800861 switch (ntohl(key->mask)) {
862 case 0x0000ffff:
Stephen Hemmingerbcd7abd2011-05-19 09:19:17 -0700863 fprintf(f, "\n match dport %u",
Stephen Hemminger4c9ffc22008-02-18 11:35:29 -0800864 ntohl(key->val) & 0xffff);
865 return;
866 case 0xffff0000:
Stephen Hemmingerbcd7abd2011-05-19 09:19:17 -0700867 fprintf(f, "\n match sport %u",
Stephen Hemminger4c9ffc22008-02-18 11:35:29 -0800868 ntohl(key->val) >> 16);
869 return;
870 case 0xffffffff:
Stephen Hemmingerbcd7abd2011-05-19 09:19:17 -0700871 fprintf(f, "\n match dport %u, match sport %u",
Stephen Hemminger4c9ffc22008-02-18 11:35:29 -0800872 ntohl(key->val) & 0xffff,
873 ntohl(key->val) >> 16);
874
Stephen Hemminger6b1ac652007-12-31 10:29:52 -0800875 return;
876 }
jamal1750abe2008-04-20 10:49:24 -0400877 /* XXX: Default print_raw */
Stephen Hemminger6b1ac652007-12-31 10:29:52 -0800878 }
jamal1750abe2008-04-20 10:49:24 -0400879}
Stephen Hemminger6b1ac652007-12-31 10:29:52 -0800880
Stephen Hemmingerd13cee62009-05-26 15:14:29 -0700881static void print_ipv6(FILE *f, const struct tc_u32_key *key)
882{
883 char abuf[256];
884
885 switch (key->off) {
886 case 0:
887 switch (ntohl(key->mask)) {
888 case 0x0f000000:
889 fprintf(f, "\n match IP ihl %u", ntohl(key->val) >> 24);
890 return;
891 case 0x00ff0000:
892 fprintf(f, "\n match IP dsfield %#x", ntohl(key->val) >> 16);
893 return;
894 }
895 break;
896 case 8:
897 if (ntohl(key->mask) == 0x00ff0000) {
898 fprintf(f, "\n match IP protocol %d", ntohl(key->val) >> 16);
899 return;
900 }
901 break;
902 case 12:
903 case 16: {
904 int bits = mask2bits(key->mask);
905 if (bits >= 0) {
906 fprintf(f, "\n %s %s/%d",
907 key->off == 12 ? "match IP src" : "match IP dst",
908 inet_ntop(AF_INET, &key->val,
909 abuf, sizeof(abuf)),
910 bits);
911 return;
912 }
913 }
914 break;
915
916 case 20:
917 switch (ntohl(key->mask)) {
918 case 0x0000ffff:
919 fprintf(f, "\n match sport %u",
920 ntohl(key->val) & 0xffff);
921 return;
922 case 0xffff0000:
923 fprintf(f, "\n match dport %u",
924 ntohl(key->val) >> 16);
925 return;
926 case 0xffffffff:
927 fprintf(f, "\n match sport %u, match dport %u",
928 ntohl(key->val) & 0xffff,
929 ntohl(key->val) >> 16);
930
931 return;
932 }
933 /* XXX: Default print_raw */
934 }
935}
936
jamal1750abe2008-04-20 10:49:24 -0400937static void print_raw(FILE *f, const struct tc_u32_key *key)
938{
939 fprintf(f, "\n match %08x/%08x at %s%d",
Stephen Hemminger6b1ac652007-12-31 10:29:52 -0800940 (unsigned int)ntohl(key->val),
941 (unsigned int)ntohl(key->mask),
942 key->offmask ? "nexthdr+" : "",
943 key->off);
944}
945
jamal1750abe2008-04-20 10:49:24 -0400946static const struct {
947 __u16 proto;
948 __u16 pad;
949 void (*pprinter)(FILE *f, const struct tc_u32_key *key);
950} u32_pprinters[] = {
951 {0, 0, print_raw},
952 {ETH_P_IP, 0, print_ipv4},
Stephen Hemmingerd13cee62009-05-26 15:14:29 -0700953 {ETH_P_IPV6, 0, print_ipv6},
jamal1750abe2008-04-20 10:49:24 -0400954};
955
956static void show_keys(FILE *f, const struct tc_u32_key *key)
957{
958 int i = 0;
959
960 if (!show_pretty)
961 goto show_k;
962
963 for (i = 0; i < sizeof(u32_pprinters) / sizeof(u32_pprinters[0]); i++) {
964 if (u32_pprinters[i].proto == ntohs(f_proto)) {
965show_k:
966 u32_pprinters[i].pprinter(f, key);
967 return;
968 }
969 }
970
971 i = 0;
972 goto show_k;
973}
974
975static int u32_parse_opt(struct filter_util *qu, char *handle,
Stephen Hemminger6b1ac652007-12-31 10:29:52 -0800976 int argc, char **argv, struct nlmsghdr *n)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000977{
978 struct {
979 struct tc_u32_sel sel;
980 struct tc_u32_key keys[128];
981 } sel;
982 struct tcmsg *t = NLMSG_DATA(n);
983 struct rtattr *tail;
jamaldcf13492006-12-07 11:07:07 -0500984 int sel_ok = 0, terminal_ok = 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000985 int sample_ok = 0;
986 __u32 htid = 0;
987 __u32 order = 0;
988
989 memset(&sel, 0, sizeof(sel));
990
991 if (handle && get_u32_handle(&t->tcm_handle, handle)) {
992 fprintf(stderr, "Illegal filter ID\n");
993 return -1;
994 }
995
996 if (argc == 0)
997 return 0;
998
8!tgraf4a86fe12005-01-18 01:24:18 +0000999 tail = NLMSG_TAIL(n);
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001000 addattr_l(n, MAX_MSG, TCA_OPTIONS, NULL, 0);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001001
1002 while (argc > 0) {
1003 if (matches(*argv, "match") == 0) {
1004 NEXT_ARG();
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +00001005 if (parse_selector(&argc, &argv, &sel.sel, n)) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001006 fprintf(stderr, "Illegal \"match\"\n");
1007 return -1;
1008 }
1009 sel_ok++;
1010 continue;
1011 } else if (matches(*argv, "offset") == 0) {
1012 NEXT_ARG();
1013 if (parse_offset(&argc, &argv, &sel.sel)) {
1014 fprintf(stderr, "Illegal \"offset\"\n");
1015 return -1;
1016 }
1017 continue;
1018 } else if (matches(*argv, "hashkey") == 0) {
1019 NEXT_ARG();
1020 if (parse_hashkey(&argc, &argv, &sel.sel)) {
1021 fprintf(stderr, "Illegal \"hashkey\"\n");
1022 return -1;
1023 }
1024 continue;
1025 } else if (matches(*argv, "classid") == 0 ||
1026 strcmp(*argv, "flowid") == 0) {
1027 unsigned handle;
1028 NEXT_ARG();
1029 if (get_tc_classid(&handle, *argv)) {
1030 fprintf(stderr, "Illegal \"classid\"\n");
1031 return -1;
1032 }
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001033 addattr_l(n, MAX_MSG, TCA_U32_CLASSID, &handle, 4);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001034 sel.sel.flags |= TC_U32_TERMINAL;
1035 } else if (matches(*argv, "divisor") == 0) {
1036 unsigned divisor;
1037 NEXT_ARG();
Stephen Hemmingerae665a52006-12-05 10:10:22 -08001038 if (get_unsigned(&divisor, *argv, 0) ||
shemminger46b67da2006-03-14 19:38:34 +00001039 divisor == 0 ||
1040 divisor > 0x100 || ((divisor - 1) & divisor)) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001041 fprintf(stderr, "Illegal \"divisor\"\n");
1042 return -1;
1043 }
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001044 addattr_l(n, MAX_MSG, TCA_U32_DIVISOR, &divisor, 4);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001045 } else if (matches(*argv, "order") == 0) {
1046 NEXT_ARG();
1047 if (get_u32(&order, *argv, 0)) {
1048 fprintf(stderr, "Illegal \"order\"\n");
1049 return -1;
1050 }
1051 } else if (strcmp(*argv, "link") == 0) {
1052 unsigned handle;
1053 NEXT_ARG();
1054 if (get_u32_handle(&handle, *argv)) {
1055 fprintf(stderr, "Illegal \"link\"\n");
1056 return -1;
1057 }
1058 if (handle && TC_U32_NODE(handle)) {
1059 fprintf(stderr, "\"link\" must be a hash table.\n");
1060 return -1;
1061 }
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001062 addattr_l(n, MAX_MSG, TCA_U32_LINK, &handle, 4);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001063 } else if (strcmp(*argv, "ht") == 0) {
1064 unsigned handle;
1065 NEXT_ARG();
1066 if (get_u32_handle(&handle, *argv)) {
1067 fprintf(stderr, "Illegal \"ht\"\n");
1068 return -1;
1069 }
1070 if (handle && TC_U32_NODE(handle)) {
1071 fprintf(stderr, "\"ht\" must be a hash table.\n");
1072 return -1;
1073 }
1074 if (sample_ok)
1075 htid = (htid&0xFF000)|(handle&0xFFF00000);
1076 else
1077 htid = (handle&0xFFFFF000);
1078 } else if (strcmp(*argv, "sample") == 0) {
1079 __u32 hash;
shemminger3925ad82006-03-14 19:36:31 +00001080 unsigned divisor = 0x100;
shemminger267480f2006-03-22 00:07:49 +00001081
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001082 struct {
1083 struct tc_u32_sel sel;
1084 struct tc_u32_key keys[4];
1085 } sel2;
shemminger46b67da2006-03-14 19:38:34 +00001086 memset(&sel2, 0, sizeof(sel2));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001087 NEXT_ARG();
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +00001088 if (parse_selector(&argc, &argv, &sel2.sel, n)) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001089 fprintf(stderr, "Illegal \"sample\"\n");
1090 return -1;
1091 }
1092 if (sel2.sel.nkeys != 1) {
Stephen Hemmingere62077d2008-02-18 10:51:42 -08001093 fprintf(stderr, "\"sample\" must contain"
1094 " exactly ONE key.\n");
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001095 return -1;
1096 }
shemminger3925ad82006-03-14 19:36:31 +00001097 if (*argv != 0 && strcmp(*argv, "divisor") == 0) {
1098 NEXT_ARG();
1099 if (get_unsigned(&divisor, *argv, 0) || divisor == 0 ||
shemminger46b67da2006-03-14 19:38:34 +00001100 divisor > 0x100 || ((divisor - 1) & divisor)) {
shemminger3925ad82006-03-14 19:36:31 +00001101 fprintf(stderr, "Illegal sample \"divisor\"\n");
1102 return -1;
1103 }
1104 NEXT_ARG();
1105 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001106 hash = sel2.sel.keys[0].val&sel2.sel.keys[0].mask;
shemminger267480f2006-03-22 00:07:49 +00001107 hash ^= hash>>16;
1108 hash ^= hash>>8;
shemminger3925ad82006-03-14 19:36:31 +00001109 htid = ((hash%divisor)<<12)|(htid&0xFFF00000);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001110 sample_ok = 1;
1111 continue;
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001112 } else if (strcmp(*argv, "indev") == 0) {
1113 char ind[IFNAMSIZ + 1];
1114 memset(ind, 0, sizeof (ind));
1115 argc--;
1116 argv++;
1117 if (argc < 1) {
1118 fprintf(stderr, "Illegal indev\n");
1119 return -1;
1120 }
1121 strncpy(ind, *argv, sizeof (ind) - 1);
1122 addattr_l(n, MAX_MSG, TCA_U32_INDEV, ind, strlen(ind) + 1);
net[shemminger]!shemmingerd81b1352004-08-23 20:20:41 +00001123
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001124 } else if (matches(*argv, "action") == 0) {
1125 NEXT_ARG();
1126 if (parse_action(&argc, &argv, TCA_U32_ACT, n)) {
1127 fprintf(stderr, "Illegal \"action\"\n");
1128 return -1;
1129 }
jamaldcf13492006-12-07 11:07:07 -05001130 terminal_ok++;
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001131 continue;
net[shemminger]!shemmingerd81b1352004-08-23 20:20:41 +00001132
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001133 } else if (matches(*argv, "police") == 0) {
1134 NEXT_ARG();
1135 if (parse_police(&argc, &argv, TCA_U32_POLICE, n)) {
1136 fprintf(stderr, "Illegal \"police\"\n");
1137 return -1;
1138 }
jamaldcf13492006-12-07 11:07:07 -05001139 terminal_ok++;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001140 continue;
1141 } else if (strcmp(*argv, "help") == 0) {
1142 explain();
1143 return -1;
1144 } else {
1145 fprintf(stderr, "What is \"%s\"?\n", *argv);
1146 explain();
1147 return -1;
1148 }
1149 argc--; argv++;
1150 }
1151
jamaldcf13492006-12-07 11:07:07 -05001152 /* We dont necessarily need class/flowids */
Stephen Hemminger81c61792006-12-13 17:05:50 -08001153 if (terminal_ok)
jamaldcf13492006-12-07 11:07:07 -05001154 sel.sel.flags |= TC_U32_TERMINAL;
1155
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001156 if (order) {
1157 if (TC_U32_NODE(t->tcm_handle) && order != TC_U32_NODE(t->tcm_handle)) {
1158 fprintf(stderr, "\"order\" contradicts \"handle\"\n");
1159 return -1;
1160 }
1161 t->tcm_handle |= order;
1162 }
1163
1164 if (htid)
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001165 addattr_l(n, MAX_MSG, TCA_U32_HASH, &htid, 4);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001166 if (sel_ok)
Stephen Hemmingere62077d2008-02-18 10:51:42 -08001167 addattr_l(n, MAX_MSG, TCA_U32_SEL, &sel,
1168 sizeof(sel.sel)+sel.sel.nkeys*sizeof(struct tc_u32_key));
8!tgraf4a86fe12005-01-18 01:24:18 +00001169 tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001170 return 0;
1171}
1172
Stephen Hemminger6b1ac652007-12-31 10:29:52 -08001173static int u32_print_opt(struct filter_util *qu, FILE *f, struct rtattr *opt,
1174 __u32 handle)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001175{
1176 struct rtattr *tb[TCA_U32_MAX+1];
1177 struct tc_u32_sel *sel = NULL;
net[shemminger]!shemmingerd81b1352004-08-23 20:20:41 +00001178 struct tc_u32_pcnt *pf = NULL;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001179
1180 if (opt == NULL)
1181 return 0;
1182
8!tgrafac2fc2d2005-01-18 22:11:58 +00001183 parse_rtattr_nested(tb, TCA_U32_MAX, opt);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001184
1185 if (handle) {
1186 SPRINT_BUF(b1);
1187 fprintf(f, "fh %s ", sprint_u32_handle(handle, b1));
1188 }
1189 if (TC_U32_NODE(handle)) {
1190 fprintf(f, "order %d ", TC_U32_NODE(handle));
1191 }
1192
1193 if (tb[TCA_U32_SEL]) {
1194 if (RTA_PAYLOAD(tb[TCA_U32_SEL]) < sizeof(*sel))
1195 return -1;
1196
1197 sel = RTA_DATA(tb[TCA_U32_SEL]);
1198 }
1199
1200 if (tb[TCA_U32_DIVISOR]) {
1201 fprintf(f, "ht divisor %d ", *(__u32*)RTA_DATA(tb[TCA_U32_DIVISOR]));
1202 } else if (tb[TCA_U32_HASH]) {
1203 __u32 htid = *(__u32*)RTA_DATA(tb[TCA_U32_HASH]);
Stephen Hemmingere62077d2008-02-18 10:51:42 -08001204 fprintf(f, "key ht %x bkt %x ", TC_U32_USERHTID(htid),
1205 TC_U32_HASH(htid));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001206 } else {
1207 fprintf(f, "??? ");
1208 }
1209 if (tb[TCA_U32_CLASSID]) {
1210 SPRINT_BUF(b1);
1211 fprintf(f, "%sflowid %s ",
1212 !sel || !(sel->flags&TC_U32_TERMINAL) ? "*" : "",
1213 sprint_tc_classid(*(__u32*)RTA_DATA(tb[TCA_U32_CLASSID]), b1));
1214 } else if (sel && sel->flags&TC_U32_TERMINAL) {
1215 fprintf(f, "terminal flowid ??? ");
1216 }
1217 if (tb[TCA_U32_LINK]) {
1218 SPRINT_BUF(b1);
Stephen Hemmingere62077d2008-02-18 10:51:42 -08001219 fprintf(f, "link %s ",
1220 sprint_u32_handle(*(__u32*)RTA_DATA(tb[TCA_U32_LINK]), b1));
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001221 }
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001222
net[shemminger]!shemmingerd81b1352004-08-23 20:20:41 +00001223 if (tb[TCA_U32_PCNT]) {
1224 if (RTA_PAYLOAD(tb[TCA_U32_PCNT]) < sizeof(*pf)) {
1225 fprintf(f, "Broken perf counters \n");
1226 return -1;
1227 }
1228 pf = RTA_DATA(tb[TCA_U32_PCNT]);
1229 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001230
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +00001231 if (sel && show_stats && NULL != pf)
net[shemminger]!shemmingerb9062432005-01-17 23:28:16 +00001232 fprintf(f, " (rule hit %llu success %llu)",
1233 (unsigned long long) pf->rcnt,
1234 (unsigned long long) pf->rhit);
net[shemminger]!shemminger6f0ba882005-01-17 23:27:56 +00001235
1236 if (tb[TCA_U32_MARK]) {
1237 struct tc_u32_mark *mark = RTA_DATA(tb[TCA_U32_MARK]);
1238 if (RTA_PAYLOAD(tb[TCA_U32_MARK]) < sizeof(*mark)) {
1239 fprintf(f, "\n Invalid mark (kernel&iproute2 mismatch)\n");
1240 } else {
1241 fprintf(f, "\n mark 0x%04x 0x%04x (success %d)",
1242 mark->val, mark->mask, mark->success);
1243 }
1244 }
1245
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001246 if (sel) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001247 if (sel->nkeys) {
Stephen Hemminger6b1ac652007-12-31 10:29:52 -08001248 int i;
1249 for (i=0; i<sel->nkeys; i++) {
jamal1750abe2008-04-20 10:49:24 -04001250 show_keys(f, sel->keys + i);
net[shemminger]!shemmingerd81b1352004-08-23 20:20:41 +00001251 if (show_stats && NULL != pf)
Stephen Hemminger6b1ac652007-12-31 10:29:52 -08001252 fprintf(f, " (success %llu ) ",
net[shemminger]!shemmingerb9062432005-01-17 23:28:16 +00001253 (unsigned long long) pf->kcnts[i]);
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001254 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001255 }
1256
1257 if (sel->flags&(TC_U32_VAROFFSET|TC_U32_OFFSET)) {
1258 fprintf(f, "\n offset ");
1259 if (sel->flags&TC_U32_VAROFFSET)
Stephen Hemmingere62077d2008-02-18 10:51:42 -08001260 fprintf(f, "%04x>>%d at %d ",
1261 ntohs(sel->offmask),
1262 sel->offshift, sel->offoff);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001263 if (sel->off)
1264 fprintf(f, "plus %d ", sel->off);
1265 }
1266 if (sel->flags&TC_U32_EAT)
1267 fprintf(f, " eat ");
1268
1269 if (sel->hmask) {
1270 fprintf(f, "\n hash mask %08x at %d ",
1271 (unsigned int)htonl(sel->hmask), sel->hoff);
1272 }
1273 }
1274
osdl.net!shemminger2373fde2004-08-13 23:54:55 +00001275 if (tb[TCA_U32_POLICE]) {
1276 fprintf(f, "\n");
1277 tc_print_police(f, tb[TCA_U32_POLICE]);
1278 }
1279 if (tb[TCA_U32_INDEV]) {
1280 struct rtattr *idev = tb[TCA_U32_INDEV];
1281 fprintf(f, "\n input dev %s\n", (char *) RTA_DATA(idev));
1282 }
1283 if (tb[TCA_U32_ACT]) {
1284 tc_print_action(f, tb[TCA_U32_ACT]);
1285 }
1286
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001287 return 0;
1288}
1289
osdl.net!shemminger6b7dff12004-09-28 18:35:49 +00001290struct filter_util u32_filter_util = {
1291 .id = "u32",
1292 .parse_fopt = u32_parse_opt,
1293 .print_fopt = u32_print_opt,
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001294};