]> git.proxmox.com Git - mirror_iproute2.git/blame - tc/m_pedit.c
pedit: Introduce ipv6 support
[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"
3cd5149e 31#include "rt_names.h"
7e7c7372 32
7e7c7372 33static struct m_pedit_util *pedit_list;
1c9af050 34static int pedit_debug;
7e7c7372 35
d8694a30 36static void explain(void)
7e7c7372 37{
7c71a40c 38 fprintf(stderr, "Usage: ... pedit munge [ex] <MUNGE> [CONTROL]\n");
7e7c7372 39 fprintf(stderr,
ae665a52 40 "Where: MUNGE := <RAW>|<LAYERED>\n"
8b625177
SH
41 "\t<RAW>:= <OFFSETC>[ATC]<CMD>\n \t\tOFFSETC:= offset <offval> <u8|u16|u32>\n"
42 "\t\tATC:= at <atval> offmask <maskval> shift <shiftval>\n"
43 "\t\tNOTE: offval is byte offset, must be multiple of 4\n"
51536ebb 44 "\t\tNOTE: maskval is a 32 bit hex number\n \t\tNOTE: shiftval is a shift value\n"
c05ddaf9 45 "\t\tCMD:= clear | invert | set <setval>| add <addval> | retain\n"
8b625177 46 "\t<LAYERED>:= ip <ipdata> | ip6 <ip6data>\n"
32a121cb 47 " \t\t| udp <udpdata> | tcp <tcpdata> | icmp <icmpdata>\n"
1672f421 48 "\tCONTROL:= reclassify | pipe | drop | continue | pass\n"
7c71a40c 49 "\tNOTE: if 'ex' is set, extended functionality will be supported (kernel >= 4.11)\n"
ebf32083 50 "For Example usage look at the examples directory\n");
7e7c7372 51
52}
53
d8694a30 54static void usage(void)
ebf32083
JHS
55{
56 explain();
57 exit(-1);
58}
7e7c7372 59
d8694a30 60static int pedit_parse_nopopt(int *argc_p, char ***argv_p,
7c71a40c
AV
61 struct m_pedit_sel *sel,
62 struct m_pedit_key *tkey)
7e7c7372 63{
64 int argc = *argc_p;
65 char **argv = *argv_p;
66
67 if (argc) {
d8694a30
JHS
68 fprintf(stderr,
69 "Unknown action hence option \"%s\" is unparsable\n",
70 *argv);
71 return -1;
7e7c7372 72 }
73
74 return 0;
75
76}
77
d1f28cf1 78static struct m_pedit_util *get_pedit_kind(const char *str)
7e7c7372 79{
fe102f61 80 static void *pBODY;
7e7c7372 81 void *dlh;
82 char buf[256];
d8694a30 83 struct m_pedit_util *p;
7e7c7372 84
85 for (p = pedit_list; p; p = p->next) {
86 if (strcmp(p->id, str) == 0)
87 return p;
88 }
89
90 snprintf(buf, sizeof(buf), "p_%s.so", str);
91 dlh = dlopen(buf, RTLD_LAZY);
92 if (dlh == NULL) {
93 dlh = pBODY;
94 if (dlh == NULL) {
95 dlh = pBODY = dlopen(NULL, RTLD_LAZY);
96 if (dlh == NULL)
97 goto noexist;
98 }
99 }
100
101 snprintf(buf, sizeof(buf), "p_pedit_%s", str);
102 p = dlsym(dlh, buf);
103 if (p == NULL)
104 goto noexist;
105
106reg:
107 p->next = pedit_list;
108 pedit_list = p;
109 return p;
110
111noexist:
f89bb021 112 p = calloc(1, sizeof(*p));
7e7c7372 113 if (p) {
d8694a30 114 strncpy(p->id, str, sizeof(p->id) - 1);
7e7c7372 115 p->parse_peopt = pedit_parse_nopopt;
116 goto reg;
117 }
118 return p;
119}
120
7c71a40c 121int pack_key(struct m_pedit_sel *_sel, struct m_pedit_key *tkey)
7e7c7372 122{
7c71a40c
AV
123 struct tc_pedit_sel *sel = &_sel->sel;
124 struct m_pedit_key_ex *keys_ex = _sel->keys_ex;
7e7c7372 125 int hwm = sel->nkeys;
126
127 if (hwm >= MAX_OFFS)
128 return -1;
129
130 if (tkey->off % 4) {
131 fprintf(stderr, "offsets MUST be in 32 bit boundaries\n");
132 return -1;
133 }
134
135 sel->keys[hwm].val = tkey->val;
136 sel->keys[hwm].mask = tkey->mask;
137 sel->keys[hwm].off = tkey->off;
138 sel->keys[hwm].at = tkey->at;
139 sel->keys[hwm].offmask = tkey->offmask;
140 sel->keys[hwm].shift = tkey->shift;
7c71a40c
AV
141
142 if (_sel->extended) {
143 keys_ex[hwm].htype = tkey->htype;
144 keys_ex[hwm].cmd = tkey->cmd;
145 } else {
146 if (tkey->htype != TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK ||
147 tkey->cmd != TCA_PEDIT_KEY_EX_CMD_SET) {
1e600da0 148 fprintf(stderr,
290cdc05 149 "Munge parameters not supported. Use 'pedit ex munge ...'.\n");
7c71a40c
AV
150 return -1;
151 }
152 }
153
7e7c7372 154 sel->nkeys++;
155 return 0;
156}
157
7c71a40c
AV
158int pack_key32(__u32 retain, struct m_pedit_sel *sel,
159 struct m_pedit_key *tkey)
7e7c7372 160{
161 if (tkey->off > (tkey->off & ~3)) {
162 fprintf(stderr,
163 "pack_key32: 32 bit offsets must begin in 32bit boundaries\n");
164 return -1;
165 }
166
167 tkey->val = htonl(tkey->val & retain);
168 tkey->mask = htonl(tkey->mask | ~retain);
32a121cb 169 return pack_key(sel, tkey);
7e7c7372 170}
171
7c71a40c
AV
172int pack_key16(__u32 retain, struct m_pedit_sel *sel,
173 struct m_pedit_key *tkey)
7e7c7372 174{
0bbca042 175 int ind, stride;
d8694a30 176 __u32 m[4] = { 0x0000FFFF, 0xFF0000FF, 0xFFFF0000 };
7e7c7372 177
7e7c7372 178 if (tkey->val > 0xFFFF || tkey->mask > 0xFFFF) {
179 fprintf(stderr, "pack_key16 bad value\n");
180 return -1;
181 }
182
183 ind = tkey->off & 3;
184
0bbca042 185 if (ind == 3) {
32a121cb 186 fprintf(stderr, "pack_key16 bad index value %d\n", ind);
7e7c7372 187 return -1;
188 }
189
77bed404
PS
190 stride = 8 * (2 - ind);
191 tkey->val = htonl((tkey->val & retain) << stride);
192 tkey->mask = htonl(((tkey->mask | ~retain) << stride) | m[ind]);
7e7c7372 193
194 tkey->off &= ~3;
195
196 if (pedit_debug)
d8694a30
JHS
197 printf("pack_key16: Final val %08x mask %08x\n",
198 tkey->val, tkey->mask);
32a121cb 199 return pack_key(sel, tkey);
7e7c7372 200
201}
202
7c71a40c 203int pack_key8(__u32 retain, struct m_pedit_sel *sel, struct m_pedit_key *tkey)
7e7c7372 204{
0bbca042 205 int ind, stride;
d8694a30 206 __u32 m[4] = { 0x00FFFFFF, 0xFF00FFFF, 0xFFFF00FF, 0xFFFFFF00 };
7e7c7372 207
7e7c7372 208 if (tkey->val > 0xFF || tkey->mask > 0xFF) {
d8694a30
JHS
209 fprintf(stderr, "pack_key8 bad value (val %x mask %x\n",
210 tkey->val, tkey->mask);
7e7c7372 211 return -1;
212 }
213
214 ind = tkey->off & 3;
0bbca042 215
77bed404
PS
216 stride = 8 * (3 - ind);
217 tkey->val = htonl((tkey->val & retain) << stride);
218 tkey->mask = htonl(((tkey->mask | ~retain) << stride) | m[ind]);
0bbca042 219
7e7c7372 220 tkey->off &= ~3;
ae665a52 221
7e7c7372 222 if (pedit_debug)
d8694a30
JHS
223 printf("pack_key8: Final word off %d val %08x mask %08x\n",
224 tkey->off, tkey->val, tkey->mask);
32a121cb 225 return pack_key(sel, tkey);
7e7c7372 226}
227
3cd5149e
AV
228static int pack_mac(struct m_pedit_sel *sel, struct m_pedit_key *tkey,
229 __u8 *mac)
230{
231 int ret = 0;
232
233 if (!(tkey->off & 0x3)) {
234 tkey->mask = 0;
235 tkey->val = ntohl(*((__u32 *)mac));
236 ret |= pack_key32(~0, sel, tkey);
237
238 tkey->off += 4;
239 tkey->mask = 0;
240 tkey->val = ntohs(*((__u16 *)&mac[4]));
241 ret |= pack_key16(~0, sel, tkey);
242 } else if (!(tkey->off & 0x1)) {
243 tkey->mask = 0;
244 tkey->val = ntohs(*((__u16 *)mac));
245 ret |= pack_key16(~0, sel, tkey);
246
247 tkey->off += 4;
248 tkey->mask = 0;
249 tkey->val = ntohl(*((__u32 *)(mac + 2)));
250 ret |= pack_key32(~0, sel, tkey);
251 } else {
252 fprintf(stderr,
253 "pack_mac: mac offsets must begin in 32bit or 16bit boundaries\n");
254 return -1;
255 }
256
257 return ret;
258}
259
f3e1b244
AV
260static int pack_ipv6(struct m_pedit_sel *sel, struct m_pedit_key *tkey,
261 __u32 *ipv6)
262{
263 int ret = 0;
264 int i;
265
266 if (tkey->off & 0x3) {
267 fprintf(stderr,
268 "pack_ipv6: IPv6 offsets must begin in 32bit boundaries\n");
269 return -1;
270 }
271
272 for (i = 0; i < 4; i++) {
273 tkey->mask = 0;
274 tkey->val = ntohl(ipv6[i]);
275
276 ret = pack_key32(~0, sel, tkey);
277 if (ret)
278 return ret;
279
280 tkey->off += 4;
281 }
282
283 return 0;
284}
285
8b625177 286int parse_val(int *argc_p, char ***argv_p, __u32 *val, int type)
7e7c7372 287{
288 int argc = *argc_p;
289 char **argv = *argv_p;
290
291 if (argc <= 0)
292 return -1;
293
32a121cb 294 if (type == TINT)
d8694a30 295 return get_integer((int *)val, *argv, 0);
f332d169 296
32a121cb 297 if (type == TU32)
7e7c7372 298 return get_u32(val, *argv, 0);
f332d169 299
32a121cb 300 if (type == TIPV4) {
7e7c7372 301 inet_prefix addr;
32a121cb 302
8b625177 303 if (get_prefix_1(&addr, *argv, AF_INET))
7e7c7372 304 return -1;
8b625177 305
32a121cb 306 *val = addr.data[0];
7e7c7372 307 return 0;
308 }
8b625177 309
f3e1b244
AV
310 if (type == TIPV6) {
311 inet_prefix addr;
312
313 if (get_prefix_1(&addr, *argv, AF_INET6))
314 return -1;
315
316 memcpy(val, addr.data, addr.bytelen);
317
318 return 0;
319 }
7e7c7372 320
3cd5149e
AV
321 if (type == TMAC) {
322#define MAC_ALEN 6
323 int ret = ll_addr_a2n((char *)val, MAC_ALEN, *argv);
324
325 if (ret == MAC_ALEN)
326 return 0;
327 }
328
7e7c7372 329 return -1;
330}
331
d8694a30 332int parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type, __u32 retain,
7c71a40c 333 struct m_pedit_sel *sel, struct m_pedit_key *tkey)
7e7c7372 334{
fa4652ff
AV
335 __u32 mask[4] = { 0 };
336 __u32 val[4] = { 0 };
337 __u32 *m = &mask[0];
338 __u32 *v = &val[0];
7e7c7372 339 __u32 o = 0xFF;
340 int res = -1;
341 int argc = *argc_p;
342 char **argv = *argv_p;
343
344 if (argc <= 0)
345 return -1;
346
347 if (pedit_debug)
d8694a30
JHS
348 printf("parse_cmd argc %d %s offset %d length %d\n",
349 argc, *argv, tkey->off, len);
7e7c7372 350
351 if (len == 2)
352 o = 0xFFFF;
353 if (len == 4)
354 o = 0xFFFFFFFF;
355
356 if (matches(*argv, "invert") == 0) {
fa4652ff 357 *v = *m = o;
c05ddaf9
AV
358 } else if (matches(*argv, "set") == 0 ||
359 matches(*argv, "add") == 0) {
360 if (matches(*argv, "add") == 0)
361 tkey->cmd = TCA_PEDIT_KEY_EX_CMD_ADD;
362
363 if (!sel->extended && tkey->cmd) {
1e600da0
SH
364 fprintf(stderr,
365 "Non extended mode. only 'set' command is supported\n");
c05ddaf9
AV
366 return -1;
367 }
368
7e7c7372 369 NEXT_ARG();
fa4652ff 370 if (parse_val(&argc, &argv, val, type))
7e7c7372 371 return -1;
372 } else if (matches(*argv, "preserve") == 0) {
f440e9d8 373 retain = 0;
7e7c7372 374 } else {
ae665a52 375 if (matches(*argv, "clear") != 0)
7e7c7372 376 return -1;
377 }
378
d8694a30
JHS
379 argc--;
380 argv++;
7e7c7372 381
382 if (argc && matches(*argv, "retain") == 0) {
383 NEXT_ARG();
384 if (parse_val(&argc, &argv, &retain, TU32))
385 return -1;
d8694a30
JHS
386 argc--;
387 argv++;
7e7c7372 388 }
389
cdca1918
AV
390 if (len > 4 && retain != ~0) {
391 fprintf(stderr,
392 "retain is not supported for fields longer the 32 bits\n");
393 return -1;
394 }
395
3cd5149e
AV
396 if (type == TMAC) {
397 res = pack_mac(sel, tkey, (__u8 *)val);
398 goto done;
399 }
400
f3e1b244
AV
401 if (type == TIPV6) {
402 res = pack_ipv6(sel, tkey, val);
403 goto done;
404 }
405
fa4652ff
AV
406 tkey->val = *v;
407 tkey->mask = *m;
7e7c7372 408
77bed404
PS
409 if (type == TIPV4)
410 tkey->val = ntohl(tkey->val);
411
7e7c7372 412 if (len == 1) {
32a121cb 413 res = pack_key8(retain, sel, tkey);
7e7c7372 414 goto done;
415 }
416 if (len == 2) {
32a121cb 417 res = pack_key16(retain, sel, tkey);
7e7c7372 418 goto done;
419 }
420 if (len == 4) {
32a121cb 421 res = pack_key32(retain, sel, tkey);
7e7c7372 422 goto done;
423 }
424
425 return -1;
426done:
427 if (pedit_debug)
d8694a30
JHS
428 printf("parse_cmd done argc %d %s offset %d length %d\n",
429 argc, *argv, tkey->off, len);
7e7c7372 430 *argc_p = argc;
431 *argv_p = argv;
432 return res;
433
434}
435
7c71a40c
AV
436int parse_offset(int *argc_p, char ***argv_p, struct m_pedit_sel *sel,
437 struct m_pedit_key *tkey)
7e7c7372 438{
439 int off;
440 __u32 len, retain;
441 int argc = *argc_p;
442 char **argv = *argv_p;
443 int res = -1;
444
445 if (argc <= 0)
446 return -1;
447
448 if (get_integer(&off, *argv, 0))
449 return -1;
450 tkey->off = off;
451
452 argc--;
453 argv++;
454
455 if (argc <= 0)
456 return -1;
457
7e7c7372 458 if (matches(*argv, "u32") == 0) {
459 len = 4;
460 retain = 0xFFFFFFFF;
461 goto done;
462 }
463 if (matches(*argv, "u16") == 0) {
464 len = 2;
a33786b5 465 retain = 0xffff;
7e7c7372 466 goto done;
467 }
468 if (matches(*argv, "u8") == 0) {
469 len = 1;
a33786b5 470 retain = 0xff;
7e7c7372 471 goto done;
472 }
473
474 return -1;
475
476done:
477
478 NEXT_ARG();
479
480 /* [at <someval> offmask <maskval> shift <shiftval>] */
481 if (matches(*argv, "at") == 0) {
482
32a121cb 483 __u32 atv = 0, offmask = 0x0, shift = 0;
7e7c7372 484
485 NEXT_ARG();
486 if (get_u32(&atv, *argv, 0))
487 return -1;
488 tkey->at = atv;
489
490 NEXT_ARG();
ae665a52 491
7e7c7372 492 if (get_u32(&offmask, *argv, 16))
493 return -1;
494 tkey->offmask = offmask;
495
496 NEXT_ARG();
497
498 if (get_u32(&shift, *argv, 0))
499 return -1;
500 tkey->shift = shift;
501
502 NEXT_ARG();
503 }
504
32a121cb 505 res = parse_cmd(&argc, &argv, len, TU32, retain, sel, tkey);
7e7c7372 506
507 *argc_p = argc;
508 *argv_p = argv;
509 return res;
510}
511
7c71a40c 512static int parse_munge(int *argc_p, char ***argv_p, struct m_pedit_sel *sel)
7e7c7372 513{
7c71a40c 514 struct m_pedit_key tkey = {};
7e7c7372 515 int argc = *argc_p;
516 char **argv = *argv_p;
517 int res = -1;
518
519 if (argc <= 0)
520 return -1;
521
7e7c7372 522 if (matches(*argv, "offset") == 0) {
523 NEXT_ARG();
32a121cb 524 res = parse_offset(&argc, &argv, sel, &tkey);
7e7c7372 525 goto done;
7e7c7372 526 } else {
527 char k[16];
528 struct m_pedit_util *p = NULL;
529
32a121cb 530 strncpy(k, *argv, sizeof(k) - 1);
7e7c7372 531
32a121cb 532 if (argc > 0) {
7e7c7372 533 p = get_pedit_kind(k);
32a121cb 534 if (p == NULL)
7e7c7372 535 goto bad_val;
ec0ceeec 536 NEXT_ARG();
32a121cb 537 res = p->parse_peopt(&argc, &argv, sel, &tkey);
7e7c7372 538 if (res < 0) {
32a121cb 539 fprintf(stderr, "bad pedit parsing\n");
7e7c7372 540 goto bad_val;
541 }
542 goto done;
543 }
544 }
545
546bad_val:
547 return -1;
548
549done:
550
551 *argc_p = argc;
552 *argv_p = argv;
553 return res;
554}
555
7c71a40c
AV
556static int pedit_keys_ex_getattr(struct rtattr *attr,
557 struct m_pedit_key_ex *keys_ex, int n)
558{
559 struct rtattr *i;
560 int rem = RTA_PAYLOAD(attr);
561 struct rtattr *tb[TCA_PEDIT_KEY_EX_MAX + 1];
562 struct m_pedit_key_ex *k = keys_ex;
563
564 for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
565 if (!n)
566 return -1;
567
568 if (i->rta_type != TCA_PEDIT_KEY_EX)
569 return -1;
570
571 parse_rtattr_nested(tb, TCA_PEDIT_KEY_EX_MAX, i);
572
573 k->htype = rta_getattr_u16(tb[TCA_PEDIT_KEY_EX_HTYPE]);
574 k->cmd = rta_getattr_u16(tb[TCA_PEDIT_KEY_EX_CMD]);
575
576 k++;
577 n--;
578 }
579
580 return !!n;
581}
582
583static int pedit_keys_ex_addattr(struct m_pedit_sel *sel, struct nlmsghdr *n)
584{
585 struct m_pedit_key_ex *k = sel->keys_ex;
586 struct rtattr *keys_start;
587 int i;
588
589 if (!sel->extended)
590 return 0;
591
592 keys_start = addattr_nest(n, MAX_MSG, TCA_PEDIT_KEYS_EX | NLA_F_NESTED);
593
594 for (i = 0; i < sel->sel.nkeys; i++) {
595 struct rtattr *key_start;
596
597 key_start = addattr_nest(n, MAX_MSG,
598 TCA_PEDIT_KEY_EX | NLA_F_NESTED);
599
600 if (addattr16(n, MAX_MSG, TCA_PEDIT_KEY_EX_HTYPE, k->htype) ||
601 addattr16(n, MAX_MSG, TCA_PEDIT_KEY_EX_CMD, k->cmd)) {
602 return -1;
603 }
604
605 addattr_nest_end(n, key_start);
606
607 k++;
608 }
609
610 addattr_nest_end(n, keys_start);
611
612 return 0;
613}
614
d8694a30
JHS
615int parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
616 struct nlmsghdr *n)
7e7c7372 617{
7c71a40c 618 struct m_pedit_sel sel = {};
7e7c7372 619
620 int argc = *argc_p;
621 char **argv = *argv_p;
622 int ok = 0, iok = 0;
623 struct rtattr *tail;
624
7e7c7372 625 while (argc > 0) {
626 if (pedit_debug > 1)
32a121cb 627 fprintf(stderr, "while pedit (%d:%s)\n", argc, *argv);
7e7c7372 628 if (matches(*argv, "pedit") == 0) {
629 NEXT_ARG();
630 ok++;
7c71a40c
AV
631
632 if (matches(*argv, "ex") == 0) {
633 if (ok > 1) {
1e600da0
SH
634 fprintf(stderr,
635 "'ex' must be before first 'munge'\n");
7c71a40c
AV
636 explain();
637 return -1;
638 }
639 sel.extended = true;
640 NEXT_ARG();
641 }
642
7e7c7372 643 continue;
ebf32083
JHS
644 } else if (matches(*argv, "help") == 0) {
645 usage();
7e7c7372 646 } else if (matches(*argv, "munge") == 0) {
647 if (!ok) {
d8694a30
JHS
648 fprintf(stderr, "Bad pedit construct (%s)\n",
649 *argv);
ebf32083 650 explain();
7e7c7372 651 return -1;
652 }
653 NEXT_ARG();
7c71a40c
AV
654
655 if (parse_munge(&argc, &argv, &sel)) {
d8694a30
JHS
656 fprintf(stderr, "Bad pedit construct (%s)\n",
657 *argv);
ebf32083 658 explain();
7e7c7372 659 return -1;
660 }
661 ok++;
662 } else {
663 break;
664 }
665
666 }
667
668 if (!ok) {
ebf32083 669 explain();
7e7c7372 670 return -1;
671 }
672
69f5aff6
PS
673 if (argc && !action_a2n(*argv, &sel.sel.action, false))
674 NEXT_ARG();
7e7c7372 675
676 if (argc) {
677 if (matches(*argv, "index") == 0) {
678 NEXT_ARG();
679 if (get_u32(&sel.sel.index, *argv, 10)) {
680 fprintf(stderr, "Pedit: Illegal \"index\"\n");
681 return -1;
682 }
683 argc--;
684 argv++;
685 iok++;
686 }
687 }
688
fc78a8e9 689 tail = NLMSG_TAIL(n);
7e7c7372 690 addattr_l(n, MAX_MSG, tca_id, NULL, 0);
7c71a40c
AV
691 if (!sel.extended) {
692 addattr_l(n, MAX_MSG, TCA_PEDIT_PARMS, &sel,
693 sizeof(sel.sel) +
694 sel.sel.nkeys * sizeof(struct tc_pedit_key));
695 } else {
696 addattr_l(n, MAX_MSG, TCA_PEDIT_PARMS_EX, &sel,
697 sizeof(sel.sel) +
698 sel.sel.nkeys * sizeof(struct tc_pedit_key));
699
700 pedit_keys_ex_addattr(&sel, n);
701 }
702
d8694a30 703 tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail;
7e7c7372 704
705 *argc_p = argc;
706 *argv_p = argv;
707 return 0;
708}
709
7c71a40c
AV
710const char *pedit_htype_str[] = {
711 [TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK] = "",
712 [TCA_PEDIT_KEY_EX_HDR_TYPE_ETH] = "eth",
713 [TCA_PEDIT_KEY_EX_HDR_TYPE_IP4] = "ipv4",
714 [TCA_PEDIT_KEY_EX_HDR_TYPE_IP6] = "ipv6",
715 [TCA_PEDIT_KEY_EX_HDR_TYPE_TCP] = "tcp",
716 [TCA_PEDIT_KEY_EX_HDR_TYPE_UDP] = "udp",
717};
718
719static void print_pedit_location(FILE *f,
720 enum pedit_header_type htype, __u32 off)
721{
722 if (htype == TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK) {
723 fprintf(f, "%d", (unsigned int)off);
724 return;
725 }
726
727 if (htype < ARRAY_SIZE(pedit_htype_str))
728 fprintf(f, "%s", pedit_htype_str[htype]);
729 else
730 fprintf(f, "unknown(%d)", htype);
731
732 fprintf(f, "%c%d", (int)off >= 0 ? '+' : '-', abs((int)off));
733}
734
d8694a30 735int print_pedit(struct action_util *au, FILE *f, struct rtattr *arg)
7e7c7372 736{
737 struct tc_pedit_sel *sel;
738 struct rtattr *tb[TCA_PEDIT_MAX + 1];
7c71a40c 739 struct m_pedit_key_ex *keys_ex = NULL;
32a121cb 740
7e7c7372 741 if (arg == NULL)
742 return -1;
743
78934000 744 parse_rtattr_nested(tb, TCA_PEDIT_MAX, arg);
7e7c7372 745
7c71a40c 746 if (!tb[TCA_PEDIT_PARMS] && !tb[TCA_PEDIT_PARMS_EX]) {
7e7c7372 747 fprintf(f, "[NULL pedit parameters]");
748 return -1;
749 }
7c71a40c
AV
750
751 if (tb[TCA_PEDIT_PARMS]) {
752 sel = RTA_DATA(tb[TCA_PEDIT_PARMS]);
753 } else {
754 int err;
755
756 sel = RTA_DATA(tb[TCA_PEDIT_PARMS_EX]);
757
758 if (!tb[TCA_PEDIT_KEYS_EX]) {
759 fprintf(f, "Netlink error\n");
760 return -1;
761 }
762
763 keys_ex = calloc(sel->nkeys, sizeof(*keys_ex));
764 if (!keys_ex) {
765 fprintf(f, "Out of memory\n");
766 return -1;
767 }
768
769 err = pedit_keys_ex_getattr(tb[TCA_PEDIT_KEYS_EX], keys_ex,
770 sel->nkeys);
771 if (err) {
772 fprintf(f, "Netlink error\n");
773
774 free(keys_ex);
775 return -1;
776 }
777 }
7e7c7372 778
d8694a30 779 fprintf(f, " pedit action %s keys %d\n ",
70932006 780 action_n2a(sel->action), sel->nkeys);
53075318 781 fprintf(f, "\t index %u ref %d bind %d", sel->index, sel->refcnt,
d8694a30 782 sel->bindcnt);
7e7c7372 783
784 if (show_stats) {
785 if (tb[TCA_PEDIT_TM]) {
786 struct tcf_t *tm = RTA_DATA(tb[TCA_PEDIT_TM]);
32a121cb
SH
787
788 print_tm(f, tm);
7e7c7372 789 }
790 }
791 if (sel->nkeys) {
792 int i;
793 struct tc_pedit_key *key = sel->keys;
7c71a40c 794 struct m_pedit_key_ex *key_ex = keys_ex;
7e7c7372 795
32a121cb 796 for (i = 0; i < sel->nkeys; i++, key++) {
7c71a40c
AV
797 enum pedit_header_type htype =
798 TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK;
c05ddaf9 799 enum pedit_cmd cmd = TCA_PEDIT_KEY_EX_CMD_SET;
7c71a40c
AV
800
801 if (keys_ex) {
802 htype = key_ex->htype;
c05ddaf9 803 cmd = key_ex->cmd;
7c71a40c
AV
804
805 key_ex++;
806 }
807
32a121cb 808 fprintf(f, "\n\t key #%d", i);
7c71a40c
AV
809
810 fprintf(f, " at ");
811
812 print_pedit_location(f, htype, key->off);
813
c05ddaf9
AV
814 fprintf(f, ": %s %08x mask %08x",
815 cmd ? "add" : "val",
d8694a30
JHS
816 (unsigned int)ntohl(key->val),
817 (unsigned int)ntohl(key->mask));
7e7c7372 818 }
819 } else {
d8694a30
JHS
820 fprintf(f, "\npedit %x keys %d is not LEGIT", sel->index,
821 sel->nkeys);
7e7c7372 822 }
823
7e7c7372 824 fprintf(f, "\n ");
7c71a40c
AV
825
826 free(keys_ex);
7e7c7372 827 return 0;
828}
829
d8694a30 830int pedit_print_xstats(struct action_util *au, FILE *f, struct rtattr *xstats)
7e7c7372 831{
832 return 0;
833}
834
835struct action_util pedit_action_util = {
836 .id = "pedit",
837 .parse_aopt = parse_pedit,
838 .print_aopt = print_pedit,
839};