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