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