]> git.proxmox.com Git - mirror_iproute2.git/blob - tc/m_pedit.c
16dd27764048398d8af8ba0a1adc5db8b50e31c0
[mirror_iproute2.git] / tc / m_pedit.c
1 /*
2 * m_pedit.c generic packet editor actions module
3 *
4 * This program is free software; you can distribute 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: J Hadi Salim (hadi@cyberus.ca)
10 *
11 * TODO:
12 * 1) Big endian broken in some spots
13 * 2) A lot of this stuff was added on the fly; get a big double-double
14 * and clean it up at some point.
15 *
16 */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <syslog.h>
22 #include <fcntl.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <string.h>
27 #include <dlfcn.h>
28 #include "utils.h"
29 #include "tc_util.h"
30 #include "m_pedit.h"
31
32 static struct m_pedit_util *pedit_list;
33 static int pedit_debug;
34
35 static void
36 explain(void)
37 {
38 fprintf(stderr, "Usage: ... pedit munge <MUNGE>\n");
39 fprintf(stderr,
40 "Where: MUNGE := <RAW>|<LAYERED>\n"
41 "\t<RAW>:= <OFFSETC>[ATC]<CMD>\n "
42 "\t\tOFFSETC:= offset <offval> <u8|u16|u32>\n "
43 "\t\tATC:= at <atval> offmask <maskval> shift <shiftval>\n "
44 "\t\tNOTE: offval is byte offset, must be multiple of 4\n "
45 "\t\tNOTE: maskval is a 32 bit hex number\n "
46 "\t\tNOTE: shiftval is a is a shift value\n "
47 "\t\tCMD:= clear | invert | set <setval>| retain\n "
48 "\t<LAYERED>:= ip <ipdata> | ip6 <ip6data> \n "
49 " \t\t| udp <udpdata> | tcp <tcpdata> | icmp <icmpdata> \n"
50 "For Example usage look at the examples directory\n");
51
52 }
53
54 static void
55 usage(void)
56 {
57 explain();
58 exit(-1);
59 }
60
61 static int
62 pedit_parse_nopopt (int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey)
63 {
64 int argc = *argc_p;
65 char **argv = *argv_p;
66
67 if (argc) {
68 fprintf(stderr, "Unknown action hence option \"%s\" is unparsable\n", *argv);
69 return -1;
70 }
71
72 return 0;
73
74 }
75
76 static struct m_pedit_util *get_pedit_kind(const char *str)
77 {
78 static void *pBODY;
79 void *dlh;
80 char buf[256];
81 struct m_pedit_util *p;
82
83 for (p = pedit_list; p; p = p->next) {
84 if (strcmp(p->id, str) == 0)
85 return p;
86 }
87
88 snprintf(buf, sizeof(buf), "p_%s.so", str);
89 dlh = dlopen(buf, RTLD_LAZY);
90 if (dlh == NULL) {
91 dlh = pBODY;
92 if (dlh == NULL) {
93 dlh = pBODY = dlopen(NULL, RTLD_LAZY);
94 if (dlh == NULL)
95 goto noexist;
96 }
97 }
98
99 snprintf(buf, sizeof(buf), "p_pedit_%s", str);
100 p = dlsym(dlh, buf);
101 if (p == NULL)
102 goto noexist;
103
104 reg:
105 p->next = pedit_list;
106 pedit_list = p;
107 return p;
108
109 noexist:
110 p = malloc(sizeof(*p));
111 if (p) {
112 memset(p, 0, sizeof(*p));
113 strncpy(p->id, str, sizeof(p->id)-1);
114 p->parse_peopt = pedit_parse_nopopt;
115 goto reg;
116 }
117 return p;
118 }
119
120 int
121 pack_key(struct tc_pedit_sel *sel,struct tc_pedit_key *tkey)
122 {
123 int hwm = sel->nkeys;
124
125 if (hwm >= MAX_OFFS)
126 return -1;
127
128 if (tkey->off % 4) {
129 fprintf(stderr, "offsets MUST be in 32 bit boundaries\n");
130 return -1;
131 }
132
133 sel->keys[hwm].val = tkey->val;
134 sel->keys[hwm].mask = tkey->mask;
135 sel->keys[hwm].off = tkey->off;
136 sel->keys[hwm].at = tkey->at;
137 sel->keys[hwm].offmask = tkey->offmask;
138 sel->keys[hwm].shift = tkey->shift;
139 sel->nkeys++;
140 return 0;
141 }
142
143
144 int
145 pack_key32(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey)
146 {
147 if (tkey->off > (tkey->off & ~3)) {
148 fprintf(stderr,
149 "pack_key32: 32 bit offsets must begin in 32bit boundaries\n");
150 return -1;
151 }
152
153 tkey->val = htonl(tkey->val & retain);
154 tkey->mask = htonl(tkey->mask | ~retain);
155 /* jamal remove this - it is not necessary given the if check above */
156 tkey->off &= ~3;
157 return pack_key(sel,tkey);
158 }
159
160 int
161 pack_key16(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey)
162 {
163 int ind = 0, stride = 0;
164 __u32 m[4] = {0xFFFF0000,0xFF0000FF,0x0000FFFF};
165
166 if (0 > tkey->off) {
167 ind = tkey->off + 1;
168 if (0 > ind)
169 ind = -1*ind;
170 } else {
171 ind = tkey->off;
172 }
173
174 if (tkey->val > 0xFFFF || tkey->mask > 0xFFFF) {
175 fprintf(stderr, "pack_key16 bad value\n");
176 return -1;
177 }
178
179 ind = tkey->off & 3;
180
181 if (0 > ind || 2 < ind) {
182 fprintf(stderr, "pack_key16 bad index value %d\n",ind);
183 return -1;
184 }
185
186 stride = 8 * ind;
187 tkey->val = htons(tkey->val);
188 if (stride > 0) {
189 tkey->val <<= stride;
190 tkey->mask <<= stride;
191 retain <<= stride;
192 }
193 tkey->mask = retain|m[ind];
194
195 tkey->off &= ~3;
196
197 if (pedit_debug)
198 printf("pack_key16: Final val %08x mask %08x \n",tkey->val,tkey->mask);
199 return pack_key(sel,tkey);
200
201 }
202
203 int
204 pack_key8(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey)
205 {
206 int ind = 0, stride = 0;
207 __u32 m[4] = {0xFFFFFF00,0xFFFF00FF,0xFF00FFFF,0x00FFFFFF};
208
209 if (0 > tkey->off) {
210 ind = tkey->off + 1;
211 if (0 > ind)
212 ind = -1*ind;
213 } else {
214 ind = tkey->off;
215 }
216
217 if (tkey->val > 0xFF || tkey->mask > 0xFF) {
218 fprintf(stderr, "pack_key8 bad value (val %x mask %x\n", tkey->val, tkey->mask);
219 return -1;
220 }
221
222 ind = tkey->off & 3;
223 stride = 8 * ind;
224 tkey->val <<= stride;
225 tkey->mask <<= stride;
226 retain <<= stride;
227 tkey->mask = retain|m[ind];
228 tkey->off &= ~3;
229
230 if (pedit_debug)
231 printf("pack_key8: Final word off %d val %08x mask %08x \n",tkey->off , tkey->val,tkey->mask);
232 return pack_key(sel,tkey);
233 }
234
235 int
236 parse_val(int *argc_p, char ***argv_p, __u32 * val, int type)
237 {
238 int argc = *argc_p;
239 char **argv = *argv_p;
240
241 if (argc <= 0)
242 return -1;
243
244 if (TINT == type)
245 return get_integer((int *) val, *argv, 0);
246
247 if (TU32 == type)
248 return get_u32(val, *argv, 0);
249
250 if (TIPV4 == type) {
251 inet_prefix addr;
252 if (get_prefix_1(&addr, *argv, AF_INET)) {
253 return -1;
254 }
255 *val=addr.data[0];
256 return 0;
257 }
258 if (TIPV6 == type) {
259 /* not implemented yet */
260 return -1;
261 }
262
263 return -1;
264 }
265
266 int
267 parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type,__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey)
268 {
269 __u32 mask = 0, val = 0;
270 __u32 o = 0xFF;
271 int res = -1;
272 int argc = *argc_p;
273 char **argv = *argv_p;
274
275 if (argc <= 0)
276 return -1;
277
278 if (pedit_debug)
279 printf("parse_cmd argc %d %s offset %d length %d\n",argc,*argv,tkey->off,len);
280
281 if (len == 2)
282 o = 0xFFFF;
283 if (len == 4)
284 o = 0xFFFFFFFF;
285
286 if (matches(*argv, "invert") == 0) {
287 retain = val = mask = o;
288 } else if (matches(*argv, "set") == 0) {
289 NEXT_ARG();
290 if (parse_val(&argc, &argv, &val, type))
291 return -1;
292 } else if (matches(*argv, "preserve") == 0) {
293 retain = mask = o;
294 } else {
295 if (matches(*argv, "clear") != 0)
296 return -1;
297 }
298
299 argc--; argv++;
300
301 if (argc && matches(*argv, "retain") == 0) {
302 NEXT_ARG();
303 if (parse_val(&argc, &argv, &retain, TU32))
304 return -1;
305 argc--; argv++;
306 }
307
308 tkey->val = val;
309
310 if (len == 1) {
311 tkey->mask = 0xFF;
312 res = pack_key8(retain,sel,tkey);
313 goto done;
314 }
315 if (len == 2) {
316 tkey->mask = mask;
317 res = pack_key16(retain,sel,tkey);
318 goto done;
319 }
320 if (len == 4) {
321 tkey->mask = mask;
322 res = pack_key32(retain,sel,tkey);
323 goto done;
324 }
325
326 return -1;
327 done:
328 if (pedit_debug)
329 printf("parse_cmd done argc %d %s offset %d length %d\n",argc,*argv,tkey->off,len);
330 *argc_p = argc;
331 *argv_p = argv;
332 return res;
333
334 }
335
336 int
337 parse_offset(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey)
338 {
339 int off;
340 __u32 len, retain;
341 int argc = *argc_p;
342 char **argv = *argv_p;
343 int res = -1;
344
345 if (argc <= 0)
346 return -1;
347
348 if (get_integer(&off, *argv, 0))
349 return -1;
350 tkey->off = off;
351
352 argc--;
353 argv++;
354
355 if (argc <= 0)
356 return -1;
357
358
359 if (matches(*argv, "u32") == 0) {
360 len = 4;
361 retain = 0xFFFFFFFF;
362 goto done;
363 }
364 if (matches(*argv, "u16") == 0) {
365 len = 2;
366 retain = 0x0;
367 goto done;
368 }
369 if (matches(*argv, "u8") == 0) {
370 len = 1;
371 retain = 0x0;
372 goto done;
373 }
374
375 return -1;
376
377 done:
378
379 NEXT_ARG();
380
381 /* [at <someval> offmask <maskval> shift <shiftval>] */
382 if (matches(*argv, "at") == 0) {
383
384 __u32 atv=0,offmask=0x0,shift=0;
385
386 NEXT_ARG();
387 if (get_u32(&atv, *argv, 0))
388 return -1;
389 tkey->at = atv;
390
391 NEXT_ARG();
392
393 if (get_u32(&offmask, *argv, 16))
394 return -1;
395 tkey->offmask = offmask;
396
397 NEXT_ARG();
398
399 if (get_u32(&shift, *argv, 0))
400 return -1;
401 tkey->shift = shift;
402
403 NEXT_ARG();
404 }
405
406 res = parse_cmd(&argc, &argv, len, TU32,retain,sel,tkey);
407
408 *argc_p = argc;
409 *argv_p = argv;
410 return res;
411 }
412
413 static int
414 parse_munge(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel)
415 {
416 struct tc_pedit_key tkey;
417 int argc = *argc_p;
418 char **argv = *argv_p;
419 int res = -1;
420
421 if (argc <= 0)
422 return -1;
423
424 memset(&tkey, 0, sizeof(tkey));
425
426 if (matches(*argv, "offset") == 0) {
427 NEXT_ARG();
428 res = parse_offset(&argc, &argv,sel,&tkey);
429 goto done;
430 } else {
431 char k[16];
432 struct m_pedit_util *p = NULL;
433
434 strncpy(k, *argv, sizeof (k) - 1);
435
436 if (argc > 0 ) {
437 p = get_pedit_kind(k);
438 if (NULL == p)
439 goto bad_val;
440 res = p->parse_peopt(&argc, &argv, sel,&tkey);
441 if (res < 0) {
442 fprintf(stderr,"bad pedit parsing\n");
443 goto bad_val;
444 }
445 goto done;
446 }
447 }
448
449 bad_val:
450 return -1;
451
452 done:
453
454 *argc_p = argc;
455 *argv_p = argv;
456 return res;
457 }
458
459 int
460 parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
461 {
462 struct {
463 struct tc_pedit_sel sel;
464 struct tc_pedit_key keys[MAX_OFFS];
465 } sel;
466
467 int argc = *argc_p;
468 char **argv = *argv_p;
469 int ok = 0, iok = 0;
470 struct rtattr *tail;
471
472 memset(&sel, 0, sizeof(sel));
473
474 while (argc > 0) {
475 if (pedit_debug > 1)
476 fprintf(stderr, "while pedit (%d:%s)\n",argc, *argv);
477 if (matches(*argv, "pedit") == 0) {
478 NEXT_ARG();
479 ok++;
480 continue;
481 } else if (matches(*argv, "help") == 0) {
482 usage();
483 } else if (matches(*argv, "munge") == 0) {
484 if (!ok) {
485 fprintf(stderr, "Illegal pedit construct (%s) \n", *argv);
486 explain();
487 return -1;
488 }
489 NEXT_ARG();
490 if (parse_munge(&argc, &argv,&sel.sel)) {
491 fprintf(stderr, "Illegal pedit construct (%s) \n", *argv);
492 explain();
493 return -1;
494 }
495 ok++;
496 } else {
497 break;
498 }
499
500 }
501
502 if (!ok) {
503 explain();
504 return -1;
505 }
506
507 if (argc) {
508 if (matches(*argv, "reclassify") == 0) {
509 sel.sel.action = TC_ACT_RECLASSIFY;
510 NEXT_ARG();
511 } else if (matches(*argv, "pipe") == 0) {
512 sel.sel.action = TC_ACT_PIPE;
513 NEXT_ARG();
514 } else if (matches(*argv, "drop") == 0 ||
515 matches(*argv, "shot") == 0) {
516 sel.sel.action = TC_ACT_SHOT;
517 NEXT_ARG();
518 } else if (matches(*argv, "continue") == 0) {
519 sel.sel.action = TC_ACT_UNSPEC;
520 NEXT_ARG();
521 } else if (matches(*argv, "pass") == 0) {
522 sel.sel.action = TC_ACT_OK;
523 NEXT_ARG();
524 }
525 }
526
527 if (argc) {
528 if (matches(*argv, "index") == 0) {
529 NEXT_ARG();
530 if (get_u32(&sel.sel.index, *argv, 10)) {
531 fprintf(stderr, "Pedit: Illegal \"index\"\n");
532 return -1;
533 }
534 argc--;
535 argv++;
536 iok++;
537 }
538 }
539
540 tail = NLMSG_TAIL(n);
541 addattr_l(n, MAX_MSG, tca_id, NULL, 0);
542 addattr_l(n, MAX_MSG, TCA_PEDIT_PARMS,&sel, sizeof(sel.sel)+sel.sel.nkeys*sizeof(struct tc_pedit_key));
543 tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
544
545 *argc_p = argc;
546 *argv_p = argv;
547 return 0;
548 }
549
550 int
551 print_pedit(struct action_util *au,FILE * f, struct rtattr *arg)
552 {
553 struct tc_pedit_sel *sel;
554 struct rtattr *tb[TCA_PEDIT_MAX + 1];
555 SPRINT_BUF(b1);
556
557 if (arg == NULL)
558 return -1;
559
560 parse_rtattr_nested(tb, TCA_PEDIT_MAX, arg);
561
562 if (tb[TCA_PEDIT_PARMS] == NULL) {
563 fprintf(f, "[NULL pedit parameters]");
564 return -1;
565 }
566 sel = RTA_DATA(tb[TCA_PEDIT_PARMS]);
567
568 fprintf(f, " pedit action %s keys %d\n ", action_n2a(sel->action, b1, sizeof (b1)),sel->nkeys);
569 fprintf(f, "\t index %d ref %d bind %d", sel->index,sel->refcnt, sel->bindcnt);
570
571 if (show_stats) {
572 if (tb[TCA_PEDIT_TM]) {
573 struct tcf_t *tm = RTA_DATA(tb[TCA_PEDIT_TM]);
574 print_tm(f,tm);
575 }
576 }
577 if (sel->nkeys) {
578 int i;
579 struct tc_pedit_key *key = sel->keys;
580
581 for (i=0; i<sel->nkeys; i++, key++) {
582 fprintf(f, "\n\t key #%d",i);
583 fprintf(f, " at %d: val %08x mask %08x",
584 (unsigned int)key->off,
585 (unsigned int)ntohl(key->val),
586 (unsigned int)ntohl(key->mask));
587 }
588 } else {
589 fprintf(f, "\npedit %x keys %d is not LEGIT", sel->index,sel->nkeys);
590 }
591
592
593 fprintf(f, "\n ");
594 return 0;
595 }
596
597 int
598 pedit_print_xstats(struct action_util *au, FILE *f, struct rtattr *xstats)
599 {
600 return 0;
601 }
602
603 struct action_util pedit_action_util = {
604 .id = "pedit",
605 .parse_aopt = parse_pedit,
606 .print_aopt = print_pedit,
607 };