]> git.proxmox.com Git - mirror_iproute2.git/blame - tc/m_pedit.c
Use C99 style initializers everywhere
[mirror_iproute2.git] / tc / m_pedit.c
CommitLineData
7e7c7372 1/*
ae665a52 2 * m_pedit.c generic packet editor actions module
7e7c7372 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 *
ae665a52
SH
9 * Authors: J Hadi Salim (hadi@cyberus.ca)
10 *
11 * TODO:
3d0b7439
SH
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.
ae665a52 15 *
7e7c7372 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
7e7c7372 32static struct m_pedit_util *pedit_list;
1c9af050 33static int pedit_debug;
7e7c7372 34
d8694a30 35static void explain(void)
7e7c7372 36{
1672f421 37 fprintf(stderr, "Usage: ... pedit munge <MUNGE> [CONTROL]\n");
7e7c7372 38 fprintf(stderr,
ae665a52 39 "Where: MUNGE := <RAW>|<LAYERED>\n"
8b625177
SH
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"
32a121cb 46 " \t\t| udp <udpdata> | tcp <tcpdata> | icmp <icmpdata>\n"
1672f421 47 "\tCONTROL:= reclassify | pipe | drop | continue | pass\n"
ebf32083 48 "For Example usage look at the examples directory\n");
7e7c7372 49
50}
51
d8694a30 52static void usage(void)
ebf32083
JHS
53{
54 explain();
55 exit(-1);
56}
7e7c7372 57
d8694a30
JHS
58static int pedit_parse_nopopt(int *argc_p, char ***argv_p,
59 struct tc_pedit_sel *sel,
60 struct tc_pedit_key *tkey)
7e7c7372 61{
62 int argc = *argc_p;
63 char **argv = *argv_p;
64
65 if (argc) {
d8694a30
JHS
66 fprintf(stderr,
67 "Unknown action hence option \"%s\" is unparsable\n",
68 *argv);
69 return -1;
7e7c7372 70 }
71
72 return 0;
73
74}
75
d1f28cf1 76static struct m_pedit_util *get_pedit_kind(const char *str)
7e7c7372 77{
fe102f61 78 static void *pBODY;
7e7c7372 79 void *dlh;
80 char buf[256];
d8694a30 81 struct m_pedit_util *p;
7e7c7372 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
104reg:
105 p->next = pedit_list;
106 pedit_list = p;
107 return p;
108
109noexist:
110 p = malloc(sizeof(*p));
111 if (p) {
112 memset(p, 0, sizeof(*p));
d8694a30 113 strncpy(p->id, str, sizeof(p->id) - 1);
7e7c7372 114 p->parse_peopt = pedit_parse_nopopt;
115 goto reg;
116 }
117 return p;
118}
119
d8694a30 120int pack_key(struct tc_pedit_sel *sel, struct tc_pedit_key *tkey)
7e7c7372 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
d8694a30
JHS
142int pack_key32(__u32 retain, struct tc_pedit_sel *sel,
143 struct tc_pedit_key *tkey)
7e7c7372 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);
32a121cb 153 return pack_key(sel, tkey);
7e7c7372 154}
155
d8694a30
JHS
156int pack_key16(__u32 retain, struct tc_pedit_sel *sel,
157 struct tc_pedit_key *tkey)
7e7c7372 158{
0bbca042 159 int ind, stride;
d8694a30 160 __u32 m[4] = { 0x0000FFFF, 0xFF0000FF, 0xFFFF0000 };
7e7c7372 161
7e7c7372 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
0bbca042 169 if (ind == 3) {
32a121cb 170 fprintf(stderr, "pack_key16 bad index value %d\n", ind);
7e7c7372 171 return -1;
172 }
173
77bed404
PS
174 stride = 8 * (2 - ind);
175 tkey->val = htonl((tkey->val & retain) << stride);
176 tkey->mask = htonl(((tkey->mask | ~retain) << stride) | m[ind]);
7e7c7372 177
178 tkey->off &= ~3;
179
180 if (pedit_debug)
d8694a30
JHS
181 printf("pack_key16: Final val %08x mask %08x\n",
182 tkey->val, tkey->mask);
32a121cb 183 return pack_key(sel, tkey);
7e7c7372 184
185}
186
d8694a30 187int pack_key8(__u32 retain, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey)
7e7c7372 188{
0bbca042 189 int ind, stride;
d8694a30 190 __u32 m[4] = { 0x00FFFFFF, 0xFF00FFFF, 0xFFFF00FF, 0xFFFFFF00 };
7e7c7372 191
7e7c7372 192 if (tkey->val > 0xFF || tkey->mask > 0xFF) {
d8694a30
JHS
193 fprintf(stderr, "pack_key8 bad value (val %x mask %x\n",
194 tkey->val, tkey->mask);
7e7c7372 195 return -1;
196 }
197
198 ind = tkey->off & 3;
0bbca042 199
77bed404
PS
200 stride = 8 * (3 - ind);
201 tkey->val = htonl((tkey->val & retain) << stride);
202 tkey->mask = htonl(((tkey->mask | ~retain) << stride) | m[ind]);
0bbca042 203
7e7c7372 204 tkey->off &= ~3;
ae665a52 205
7e7c7372 206 if (pedit_debug)
d8694a30
JHS
207 printf("pack_key8: Final word off %d val %08x mask %08x\n",
208 tkey->off, tkey->val, tkey->mask);
32a121cb 209 return pack_key(sel, tkey);
7e7c7372 210}
211
8b625177 212int parse_val(int *argc_p, char ***argv_p, __u32 *val, int type)
7e7c7372 213{
214 int argc = *argc_p;
215 char **argv = *argv_p;
216
217 if (argc <= 0)
218 return -1;
219
32a121cb 220 if (type == TINT)
d8694a30 221 return get_integer((int *)val, *argv, 0);
f332d169 222
32a121cb 223 if (type == TU32)
7e7c7372 224 return get_u32(val, *argv, 0);
f332d169 225
32a121cb 226 if (type == TIPV4) {
7e7c7372 227 inet_prefix addr;
32a121cb 228
8b625177 229 if (get_prefix_1(&addr, *argv, AF_INET))
7e7c7372 230 return -1;
8b625177 231
32a121cb 232 *val = addr.data[0];
7e7c7372 233 return 0;
234 }
8b625177
SH
235
236 if (type == TIPV6)
237 return -1; /* not implemented yet */
7e7c7372 238
239 return -1;
240}
241
d8694a30
JHS
242int 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)
7e7c7372 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)
d8694a30
JHS
255 printf("parse_cmd argc %d %s offset %d length %d\n",
256 argc, *argv, tkey->off, len);
7e7c7372 257
258 if (len == 2)
259 o = 0xFFFF;
260 if (len == 4)
261 o = 0xFFFFFFFF;
262
263 if (matches(*argv, "invert") == 0) {
f440e9d8 264 val = mask = o;
7e7c7372 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) {
f440e9d8 270 retain = 0;
7e7c7372 271 } else {
ae665a52 272 if (matches(*argv, "clear") != 0)
7e7c7372 273 return -1;
274 }
275
d8694a30
JHS
276 argc--;
277 argv++;
7e7c7372 278
279 if (argc && matches(*argv, "retain") == 0) {
280 NEXT_ARG();
281 if (parse_val(&argc, &argv, &retain, TU32))
282 return -1;
d8694a30
JHS
283 argc--;
284 argv++;
7e7c7372 285 }
286
287 tkey->val = val;
f440e9d8 288 tkey->mask = mask;
7e7c7372 289
77bed404
PS
290 if (type == TIPV4)
291 tkey->val = ntohl(tkey->val);
292
7e7c7372 293 if (len == 1) {
32a121cb 294 res = pack_key8(retain, sel, tkey);
7e7c7372 295 goto done;
296 }
297 if (len == 2) {
32a121cb 298 res = pack_key16(retain, sel, tkey);
7e7c7372 299 goto done;
300 }
301 if (len == 4) {
32a121cb 302 res = pack_key32(retain, sel, tkey);
7e7c7372 303 goto done;
304 }
305
306 return -1;
307done:
308 if (pedit_debug)
d8694a30
JHS
309 printf("parse_cmd done argc %d %s offset %d length %d\n",
310 argc, *argv, tkey->off, len);
7e7c7372 311 *argc_p = argc;
312 *argv_p = argv;
313 return res;
314
315}
316
d8694a30
JHS
317int parse_offset(int *argc_p, char ***argv_p, struct tc_pedit_sel *sel,
318 struct tc_pedit_key *tkey)
7e7c7372 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
7e7c7372 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;
a33786b5 346 retain = 0xffff;
7e7c7372 347 goto done;
348 }
349 if (matches(*argv, "u8") == 0) {
350 len = 1;
a33786b5 351 retain = 0xff;
7e7c7372 352 goto done;
353 }
354
355 return -1;
356
357done:
358
359 NEXT_ARG();
360
361 /* [at <someval> offmask <maskval> shift <shiftval>] */
362 if (matches(*argv, "at") == 0) {
363
32a121cb 364 __u32 atv = 0, offmask = 0x0, shift = 0;
7e7c7372 365
366 NEXT_ARG();
367 if (get_u32(&atv, *argv, 0))
368 return -1;
369 tkey->at = atv;
370
371 NEXT_ARG();
ae665a52 372
7e7c7372 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
32a121cb 386 res = parse_cmd(&argc, &argv, len, TU32, retain, sel, tkey);
7e7c7372 387
388 *argc_p = argc;
389 *argv_p = argv;
390 return res;
391}
392
d8694a30 393static int parse_munge(int *argc_p, char ***argv_p, struct tc_pedit_sel *sel)
7e7c7372 394{
d17b136f 395 struct tc_pedit_key tkey = {};
7e7c7372 396 int argc = *argc_p;
397 char **argv = *argv_p;
398 int res = -1;
399
400 if (argc <= 0)
401 return -1;
402
7e7c7372 403 if (matches(*argv, "offset") == 0) {
404 NEXT_ARG();
32a121cb 405 res = parse_offset(&argc, &argv, sel, &tkey);
7e7c7372 406 goto done;
7e7c7372 407 } else {
408 char k[16];
409 struct m_pedit_util *p = NULL;
410
32a121cb 411 strncpy(k, *argv, sizeof(k) - 1);
7e7c7372 412
32a121cb 413 if (argc > 0) {
7e7c7372 414 p = get_pedit_kind(k);
32a121cb 415 if (p == NULL)
7e7c7372 416 goto bad_val;
ec0ceeec 417 NEXT_ARG();
32a121cb 418 res = p->parse_peopt(&argc, &argv, sel, &tkey);
7e7c7372 419 if (res < 0) {
32a121cb 420 fprintf(stderr, "bad pedit parsing\n");
7e7c7372 421 goto bad_val;
422 }
423 goto done;
424 }
425 }
426
427bad_val:
428 return -1;
429
430done:
431
432 *argc_p = argc;
433 *argv_p = argv;
434 return res;
435}
436
d8694a30
JHS
437int parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
438 struct nlmsghdr *n)
7e7c7372 439{
440 struct {
441 struct tc_pedit_sel sel;
442 struct tc_pedit_key keys[MAX_OFFS];
d17b136f 443 } sel = {};
7e7c7372 444
445 int argc = *argc_p;
446 char **argv = *argv_p;
447 int ok = 0, iok = 0;
448 struct rtattr *tail;
449
7e7c7372 450 while (argc > 0) {
451 if (pedit_debug > 1)
32a121cb 452 fprintf(stderr, "while pedit (%d:%s)\n", argc, *argv);
7e7c7372 453 if (matches(*argv, "pedit") == 0) {
454 NEXT_ARG();
455 ok++;
456 continue;
ebf32083
JHS
457 } else if (matches(*argv, "help") == 0) {
458 usage();
7e7c7372 459 } else if (matches(*argv, "munge") == 0) {
460 if (!ok) {
d8694a30
JHS
461 fprintf(stderr, "Bad pedit construct (%s)\n",
462 *argv);
ebf32083 463 explain();
7e7c7372 464 return -1;
465 }
466 NEXT_ARG();
32a121cb 467 if (parse_munge(&argc, &argv, &sel.sel)) {
d8694a30
JHS
468 fprintf(stderr, "Bad pedit construct (%s)\n",
469 *argv);
ebf32083 470 explain();
7e7c7372 471 return -1;
472 }
473 ok++;
474 } else {
475 break;
476 }
477
478 }
479
480 if (!ok) {
ebf32083 481 explain();
7e7c7372 482 return -1;
483 }
484
485 if (argc) {
486 if (matches(*argv, "reclassify") == 0) {
487 sel.sel.action = TC_ACT_RECLASSIFY;
488 NEXT_ARG();
489 } else if (matches(*argv, "pipe") == 0) {
490 sel.sel.action = TC_ACT_PIPE;
491 NEXT_ARG();
492 } else if (matches(*argv, "drop") == 0 ||
d8694a30 493 matches(*argv, "shot") == 0) {
7e7c7372 494 sel.sel.action = TC_ACT_SHOT;
495 NEXT_ARG();
496 } else if (matches(*argv, "continue") == 0) {
497 sel.sel.action = TC_ACT_UNSPEC;
498 NEXT_ARG();
43726b75
JHS
499 } else if (matches(*argv, "pass") == 0 ||
500 matches(*argv, "ok") == 0) {
7e7c7372 501 sel.sel.action = TC_ACT_OK;
502 NEXT_ARG();
503 }
504 }
505
506 if (argc) {
507 if (matches(*argv, "index") == 0) {
508 NEXT_ARG();
509 if (get_u32(&sel.sel.index, *argv, 10)) {
510 fprintf(stderr, "Pedit: Illegal \"index\"\n");
511 return -1;
512 }
513 argc--;
514 argv++;
515 iok++;
516 }
517 }
518
fc78a8e9 519 tail = NLMSG_TAIL(n);
7e7c7372 520 addattr_l(n, MAX_MSG, tca_id, NULL, 0);
d8694a30
JHS
521 addattr_l(n, MAX_MSG, TCA_PEDIT_PARMS, &sel,
522 sizeof(sel.sel) +
523 sel.sel.nkeys * sizeof(struct tc_pedit_key));
524 tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail;
7e7c7372 525
526 *argc_p = argc;
527 *argv_p = argv;
528 return 0;
529}
530
d8694a30 531int print_pedit(struct action_util *au, FILE *f, struct rtattr *arg)
7e7c7372 532{
533 struct tc_pedit_sel *sel;
534 struct rtattr *tb[TCA_PEDIT_MAX + 1];
32a121cb 535
7e7c7372 536 SPRINT_BUF(b1);
537
538 if (arg == NULL)
539 return -1;
540
78934000 541 parse_rtattr_nested(tb, TCA_PEDIT_MAX, arg);
7e7c7372 542
543 if (tb[TCA_PEDIT_PARMS] == NULL) {
544 fprintf(f, "[NULL pedit parameters]");
545 return -1;
546 }
547 sel = RTA_DATA(tb[TCA_PEDIT_PARMS]);
548
d8694a30
JHS
549 fprintf(f, " pedit action %s keys %d\n ",
550 action_n2a(sel->action, b1, sizeof(b1)), sel->nkeys);
551 fprintf(f, "\t index %d ref %d bind %d", sel->index, sel->refcnt,
552 sel->bindcnt);
7e7c7372 553
554 if (show_stats) {
555 if (tb[TCA_PEDIT_TM]) {
556 struct tcf_t *tm = RTA_DATA(tb[TCA_PEDIT_TM]);
32a121cb
SH
557
558 print_tm(f, tm);
7e7c7372 559 }
560 }
561 if (sel->nkeys) {
562 int i;
563 struct tc_pedit_key *key = sel->keys;
564
32a121cb
SH
565 for (i = 0; i < sel->nkeys; i++, key++) {
566 fprintf(f, "\n\t key #%d", i);
7e7c7372 567 fprintf(f, " at %d: val %08x mask %08x",
d8694a30
JHS
568 (unsigned int)key->off,
569 (unsigned int)ntohl(key->val),
570 (unsigned int)ntohl(key->mask));
7e7c7372 571 }
572 } else {
d8694a30
JHS
573 fprintf(f, "\npedit %x keys %d is not LEGIT", sel->index,
574 sel->nkeys);
7e7c7372 575 }
576
7e7c7372 577 fprintf(f, "\n ");
578 return 0;
579}
580
d8694a30 581int pedit_print_xstats(struct action_util *au, FILE *f, struct rtattr *xstats)
7e7c7372 582{
583 return 0;
584}
585
586struct action_util pedit_action_util = {
587 .id = "pedit",
588 .parse_aopt = parse_pedit,
589 .print_aopt = print_pedit,
590};