1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <stdio.h>
19#include <stdlib.h>
20#include <unistd.h>
21#include <fcntl.h>
22#include <sys/socket.h>
23#include <netinet/in.h>
24#include <arpa/inet.h>
25#include <string.h>
26#include <dlfcn.h>
27#include "utils.h"
28#include "tc_util.h"
29#include "m_pedit.h"
30#include "rt_names.h"
31
32static struct m_pedit_util *pedit_list;
33static int pedit_debug;
34
35static void explain(void)
36{
37 fprintf(stderr,
38 "Usage: ... pedit munge [ex] <MUNGE> [CONTROL]\n"
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 shift value\n"
44 "\t\tCMD:= clear | invert | set <setval> | add <addval> | decrement | 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 "\t goto chain <CHAIN_INDEX>\n"
49 "\tNOTE: if 'ex' is set, extended functionality will be supported (kernel >= 4.11)\n"
50 "For Example usage look at the examples directory\n");
51
52}
53
54static void usage(void)
55{
56 explain();
57 exit(-1);
58}
59
60static int pedit_parse_nopopt(int *argc_p, char ***argv_p,
61 struct m_pedit_sel *sel,
62 struct m_pedit_key *tkey)
63{
64 int argc = *argc_p;
65 char **argv = *argv_p;
66
67 if (argc) {
68 fprintf(stderr,
69 "Unknown action hence option \"%s\" is unparsable\n",
70 *argv);
71 return -1;
72 }
73
74 return 0;
75
76}
77
78static struct m_pedit_util *get_pedit_kind(const char *str)
79{
80 static void *pBODY;
81 void *dlh;
82 char buf[256];
83 struct m_pedit_util *p;
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:
112 p = calloc(1, sizeof(*p));
113 if (p) {
114 strlcpy(p->id, str, sizeof(p->id));
115 p->parse_peopt = pedit_parse_nopopt;
116 goto reg;
117 }
118 return p;
119}
120
121static int pack_key(struct m_pedit_sel *_sel, struct m_pedit_key *tkey)
122{
123 struct tc_pedit_sel *sel = &_sel->sel;
124 struct m_pedit_key_ex *keys_ex = _sel->keys_ex;
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;
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) {
148 fprintf(stderr,
149 "Munge parameters not supported. Use 'pedit ex munge ...'.\n");
150 return -1;
151 }
152 }
153
154 sel->nkeys++;
155 return 0;
156}
157
158static int pack_key32(__u32 retain, struct m_pedit_sel *sel,
159 struct m_pedit_key *tkey)
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);
169 return pack_key(sel, tkey);
170}
171
172static int pack_key16(__u32 retain, struct m_pedit_sel *sel,
173 struct m_pedit_key *tkey)
174{
175 int ind, stride;
176 __u32 m[4] = { 0x0000FFFF, 0xFF0000FF, 0xFFFF0000 };
177
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
185 if (ind == 3) {
186 fprintf(stderr, "pack_key16 bad index value %d\n", ind);
187 return -1;
188 }
189
190 stride = 8 * (2 - ind);
191 tkey->val = htonl((tkey->val & retain) << stride);
192 tkey->mask = htonl(((tkey->mask | ~retain) << stride) | m[ind]);
193
194 tkey->off &= ~3;
195
196 if (pedit_debug)
197 printf("pack_key16: Final val %08x mask %08x\n",
198 tkey->val, tkey->mask);
199 return pack_key(sel, tkey);
200}
201
202static int pack_key8(__u32 retain, struct m_pedit_sel *sel,
203 struct m_pedit_key *tkey)
204{
205 int ind, stride;
206 __u32 m[4] = { 0x00FFFFFF, 0xFF00FFFF, 0xFFFF00FF, 0xFFFFFF00 };
207
208 if (tkey->val > 0xFF || tkey->mask > 0xFF) {
209 fprintf(stderr, "pack_key8 bad value (val %x mask %x\n",
210 tkey->val, tkey->mask);
211 return -1;
212 }
213
214 ind = tkey->off & 3;
215
216 stride = 8 * (3 - ind);
217 tkey->val = htonl((tkey->val & retain) << stride);
218 tkey->mask = htonl(((tkey->mask | ~retain) << stride) | m[ind]);
219
220 tkey->off &= ~3;
221
222 if (pedit_debug)
223 printf("pack_key8: Final word off %d val %08x mask %08x\n",
224 tkey->off, tkey->val, tkey->mask);
225 return pack_key(sel, tkey);
226}
227
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
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
286static int parse_val(int *argc_p, char ***argv_p, __u32 *val, int type)
287{
288 int argc = *argc_p;
289 char **argv = *argv_p;
290
291 if (argc <= 0)
292 return -1;
293
294 if (type == TINT)
295 return get_integer((int *)val, *argv, 0);
296
297 if (type == TU32)
298 return get_u32(val, *argv, 0);
299
300 if (type == TIPV4) {
301 inet_prefix addr;
302
303 if (get_prefix_1(&addr, *argv, AF_INET))
304 return -1;
305
306 *val = addr.data[0];
307 return 0;
308 }
309
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 }
320
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
329 return -1;
330}
331
332int parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type, __u32 retain,
333 struct m_pedit_sel *sel, struct m_pedit_key *tkey, int flags)
334{
335 __u32 mask[4] = { 0 };
336 __u32 val[4] = { 0 };
337 __u32 *m = &mask[0];
338 __u32 *v = &val[0];
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)
348 printf("parse_cmd argc %d %s offset %d length %d\n",
349 argc, *argv, tkey->off, len);
350
351 if (len == 2)
352 o = 0xFFFF;
353 if (len == 4)
354 o = 0xFFFFFFFF;
355
356 if (matches(*argv, "invert") == 0) {
357 *v = *m = o;
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)
364 goto non_ext_only_set_cmd;
365
366 NEXT_ARG();
367 if (parse_val(&argc, &argv, val, type))
368 return -1;
369 } else if (matches(*argv, "decrement") == 0) {
370 if ((flags & PEDIT_ALLOW_DEC) == 0) {
371 fprintf(stderr,
372 "decrement command is not supported for this field\n");
373 return -1;
374 }
375
376 if (!sel->extended)
377 goto non_ext_only_set_cmd;
378
379 tkey->cmd = TCA_PEDIT_KEY_EX_CMD_ADD;
380 *v = retain;
381 } else if (matches(*argv, "preserve") == 0) {
382 retain = 0;
383 } else {
384 if (matches(*argv, "clear") != 0)
385 return -1;
386 }
387
388 argc--;
389 argv++;
390
391 if (argc && matches(*argv, "retain") == 0) {
392 NEXT_ARG();
393 if (parse_val(&argc, &argv, &retain, TU32))
394 return -1;
395 argc--;
396 argv++;
397 }
398
399 if (len > 4 && retain != ~0) {
400 fprintf(stderr,
401 "retain is not supported for fields longer the 32 bits\n");
402 return -1;
403 }
404
405 if (type == TMAC) {
406 res = pack_mac(sel, tkey, (__u8 *)val);
407 goto done;
408 }
409
410 if (type == TIPV6) {
411 res = pack_ipv6(sel, tkey, val);
412 goto done;
413 }
414
415 tkey->val = *v;
416 tkey->mask = *m;
417
418 if (type == TIPV4)
419 tkey->val = ntohl(tkey->val);
420
421 if (len == 1) {
422 res = pack_key8(retain, sel, tkey);
423 goto done;
424 }
425 if (len == 2) {
426 res = pack_key16(retain, sel, tkey);
427 goto done;
428 }
429 if (len == 4) {
430 res = pack_key32(retain, sel, tkey);
431 goto done;
432 }
433
434 return -1;
435done:
436 if (pedit_debug)
437 printf("parse_cmd done argc %d %s offset %d length %d\n",
438 argc, *argv, tkey->off, len);
439 *argc_p = argc;
440 *argv_p = argv;
441 return res;
442
443non_ext_only_set_cmd:
444 fprintf(stderr,
445 "Non extended mode. only 'set' command is supported\n");
446 return -1;
447}
448
449static int parse_offset(int *argc_p, char ***argv_p, struct m_pedit_sel *sel,
450 struct m_pedit_key *tkey)
451{
452 int off;
453 __u32 len, retain;
454 int argc = *argc_p;
455 char **argv = *argv_p;
456 int res = -1;
457
458 if (argc <= 0)
459 return -1;
460
461 if (get_integer(&off, *argv, 0))
462 return -1;
463 tkey->off = off;
464
465 argc--;
466 argv++;
467
468 if (argc <= 0)
469 return -1;
470
471 if (matches(*argv, "u32") == 0) {
472 len = 4;
473 retain = 0xFFFFFFFF;
474 goto done;
475 }
476 if (matches(*argv, "u16") == 0) {
477 len = 2;
478 retain = 0xffff;
479 goto done;
480 }
481 if (matches(*argv, "u8") == 0) {
482 len = 1;
483 retain = 0xff;
484 goto done;
485 }
486
487 return -1;
488
489done:
490
491 NEXT_ARG();
492
493
494 if (matches(*argv, "at") == 0) {
495
496 __u32 atv = 0, offmask = 0x0, shift = 0;
497
498 NEXT_ARG();
499 if (get_u32(&atv, *argv, 0))
500 return -1;
501 tkey->at = atv;
502
503 NEXT_ARG();
504
505 if (get_u32(&offmask, *argv, 16))
506 return -1;
507 tkey->offmask = offmask;
508
509 NEXT_ARG();
510
511 if (get_u32(&shift, *argv, 0))
512 return -1;
513 tkey->shift = shift;
514
515 NEXT_ARG();
516 }
517
518 res = parse_cmd(&argc, &argv, len, TU32, retain, sel, tkey, 0);
519
520 *argc_p = argc;
521 *argv_p = argv;
522 return res;
523}
524
525static int parse_munge(int *argc_p, char ***argv_p, struct m_pedit_sel *sel)
526{
527 struct m_pedit_key tkey = {};
528 int argc = *argc_p;
529 char **argv = *argv_p;
530 int res = -1;
531
532 if (argc <= 0)
533 return -1;
534
535 if (matches(*argv, "offset") == 0) {
536 NEXT_ARG();
537 res = parse_offset(&argc, &argv, sel, &tkey);
538 goto done;
539 } else {
540 char k[FILTER_NAMESZ];
541 struct m_pedit_util *p = NULL;
542
543 strncpy(k, *argv, sizeof(k) - 1);
544
545 if (argc > 0) {
546 p = get_pedit_kind(k);
547 if (p == NULL)
548 goto bad_val;
549 NEXT_ARG();
550 res = p->parse_peopt(&argc, &argv, sel, &tkey);
551 if (res < 0) {
552 fprintf(stderr, "bad pedit parsing\n");
553 goto bad_val;
554 }
555 goto done;
556 }
557 }
558
559bad_val:
560 return -1;
561
562done:
563
564 *argc_p = argc;
565 *argv_p = argv;
566 return res;
567}
568
569static int pedit_keys_ex_getattr(struct rtattr *attr,
570 struct m_pedit_key_ex *keys_ex, int n)
571{
572 struct rtattr *i;
573 int rem = RTA_PAYLOAD(attr);
574 struct rtattr *tb[TCA_PEDIT_KEY_EX_MAX + 1];
575 struct m_pedit_key_ex *k = keys_ex;
576
577 for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
578 if (!n)
579 return -1;
580
581 if (i->rta_type != TCA_PEDIT_KEY_EX)
582 return -1;
583
584 parse_rtattr_nested(tb, TCA_PEDIT_KEY_EX_MAX, i);
585
586 k->htype = rta_getattr_u16(tb[TCA_PEDIT_KEY_EX_HTYPE]);
587 k->cmd = rta_getattr_u16(tb[TCA_PEDIT_KEY_EX_CMD]);
588
589 k++;
590 n--;
591 }
592
593 return !!n;
594}
595
596static int pedit_keys_ex_addattr(struct m_pedit_sel *sel, struct nlmsghdr *n)
597{
598 struct m_pedit_key_ex *k = sel->keys_ex;
599 struct rtattr *keys_start;
600 int i;
601
602 if (!sel->extended)
603 return 0;
604
605 keys_start = addattr_nest(n, MAX_MSG, TCA_PEDIT_KEYS_EX | NLA_F_NESTED);
606
607 for (i = 0; i < sel->sel.nkeys; i++) {
608 struct rtattr *key_start;
609
610 key_start = addattr_nest(n, MAX_MSG,
611 TCA_PEDIT_KEY_EX | NLA_F_NESTED);
612
613 if (addattr16(n, MAX_MSG, TCA_PEDIT_KEY_EX_HTYPE, k->htype) ||
614 addattr16(n, MAX_MSG, TCA_PEDIT_KEY_EX_CMD, k->cmd)) {
615 return -1;
616 }
617
618 addattr_nest_end(n, key_start);
619
620 k++;
621 }
622
623 addattr_nest_end(n, keys_start);
624
625 return 0;
626}
627
628static int parse_pedit(struct action_util *a, int *argc_p, char ***argv_p,
629 int tca_id, struct nlmsghdr *n)
630{
631 struct m_pedit_sel sel = {};
632
633 int argc = *argc_p;
634 char **argv = *argv_p;
635 int ok = 0, iok = 0;
636 struct rtattr *tail;
637
638 while (argc > 0) {
639 if (pedit_debug > 1)
640 fprintf(stderr, "while pedit (%d:%s)\n", argc, *argv);
641 if (matches(*argv, "pedit") == 0) {
642 NEXT_ARG();
643 ok++;
644
645 if (matches(*argv, "ex") == 0) {
646 if (ok > 1) {
647 fprintf(stderr,
648 "'ex' must be before first 'munge'\n");
649 explain();
650 return -1;
651 }
652 sel.extended = true;
653 NEXT_ARG();
654 }
655
656 continue;
657 } else if (matches(*argv, "help") == 0) {
658 usage();
659 } else if (matches(*argv, "munge") == 0) {
660 if (!ok) {
661 fprintf(stderr, "Bad pedit construct (%s)\n",
662 *argv);
663 explain();
664 return -1;
665 }
666 NEXT_ARG();
667
668 if (parse_munge(&argc, &argv, &sel)) {
669 fprintf(stderr, "Bad pedit construct (%s)\n",
670 *argv);
671 explain();
672 return -1;
673 }
674 ok++;
675 } else {
676 break;
677 }
678
679 }
680
681 if (!ok) {
682 explain();
683 return -1;
684 }
685
686 parse_action_control_dflt(&argc, &argv, &sel.sel.action, false, TC_ACT_OK);
687
688 if (argc) {
689 if (matches(*argv, "index") == 0) {
690 NEXT_ARG();
691 if (get_u32(&sel.sel.index, *argv, 10)) {
692 fprintf(stderr, "Pedit: Illegal \"index\"\n");
693 return -1;
694 }
695 argc--;
696 argv++;
697 iok++;
698 }
699 }
700
701 tail = addattr_nest(n, MAX_MSG, tca_id);
702 if (!sel.extended) {
703 addattr_l(n, MAX_MSG, TCA_PEDIT_PARMS, &sel,
704 sizeof(sel.sel) +
705 sel.sel.nkeys * sizeof(struct tc_pedit_key));
706 } else {
707 addattr_l(n, MAX_MSG, TCA_PEDIT_PARMS_EX, &sel,
708 sizeof(sel.sel) +
709 sel.sel.nkeys * sizeof(struct tc_pedit_key));
710
711 pedit_keys_ex_addattr(&sel, n);
712 }
713
714 addattr_nest_end(n, tail);
715
716 *argc_p = argc;
717 *argv_p = argv;
718 return 0;
719}
720
721static const char * const pedit_htype_str[] = {
722 [TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK] = "",
723 [TCA_PEDIT_KEY_EX_HDR_TYPE_ETH] = "eth",
724 [TCA_PEDIT_KEY_EX_HDR_TYPE_IP4] = "ipv4",
725 [TCA_PEDIT_KEY_EX_HDR_TYPE_IP6] = "ipv6",
726 [TCA_PEDIT_KEY_EX_HDR_TYPE_TCP] = "tcp",
727 [TCA_PEDIT_KEY_EX_HDR_TYPE_UDP] = "udp",
728};
729
730static int print_pedit_location(FILE *f,
731 enum pedit_header_type htype, __u32 off)
732{
733 char *buf = NULL;
734 int rc;
735
736 if (htype != TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK) {
737 if (htype < ARRAY_SIZE(pedit_htype_str))
738 rc = asprintf(&buf, "%s", pedit_htype_str[htype]);
739 else
740 rc = asprintf(&buf, "unknown(%d)", htype);
741 if (rc < 0)
742 return rc;
743 print_string(PRINT_ANY, "htype", "%s", buf);
744 print_int(PRINT_ANY, "offset", "%+d", off);
745 } else {
746 print_string(PRINT_JSON, "htype", NULL, "network");
747 print_int(PRINT_ANY, "offset", "%d", off);
748 }
749
750 free(buf);
751 return 0;
752}
753
754static int print_pedit(struct action_util *au, FILE *f, struct rtattr *arg)
755{
756 struct tc_pedit_sel *sel;
757 struct rtattr *tb[TCA_PEDIT_MAX + 1];
758 struct m_pedit_key_ex *keys_ex = NULL;
759 int err;
760
761 print_string(PRINT_ANY, "kind", " %s ", "pedit");
762 if (arg == NULL)
763 return 0;
764
765 parse_rtattr_nested(tb, TCA_PEDIT_MAX, arg);
766
767 if (!tb[TCA_PEDIT_PARMS] && !tb[TCA_PEDIT_PARMS_EX]) {
768 fprintf(stderr, "Missing pedit parameters\n");
769 return -1;
770 }
771
772 if (tb[TCA_PEDIT_PARMS]) {
773 sel = RTA_DATA(tb[TCA_PEDIT_PARMS]);
774 } else {
775 int err;
776
777 sel = RTA_DATA(tb[TCA_PEDIT_PARMS_EX]);
778
779 if (!tb[TCA_PEDIT_KEYS_EX]) {
780 fprintf(f, "Netlink error\n");
781 return -1;
782 }
783
784 keys_ex = calloc(sel->nkeys, sizeof(*keys_ex));
785 if (!keys_ex) {
786 fprintf(f, "Out of memory\n");
787 return -1;
788 }
789
790 err = pedit_keys_ex_getattr(tb[TCA_PEDIT_KEYS_EX], keys_ex,
791 sel->nkeys);
792 if (err) {
793 fprintf(f, "Netlink error\n");
794
795 free(keys_ex);
796 return -1;
797 }
798 }
799
800 print_action_control(f, "action ", sel->action, " ");
801 print_uint(PRINT_ANY, "nkeys", "keys %d\n", sel->nkeys);
802 print_uint(PRINT_ANY, "index", " \t index %u", sel->index);
803 print_int(PRINT_ANY, "ref", " ref %d", sel->refcnt);
804 print_int(PRINT_ANY, "bind", " bind %d", sel->bindcnt);
805
806 if (show_stats) {
807 if (tb[TCA_PEDIT_TM]) {
808 struct tcf_t *tm = RTA_DATA(tb[TCA_PEDIT_TM]);
809
810 print_tm(f, tm);
811 }
812 }
813 open_json_array(PRINT_JSON, "keys");
814 if (sel->nkeys) {
815 int i;
816 struct tc_pedit_key *key = sel->keys;
817 struct m_pedit_key_ex *key_ex = keys_ex;
818
819 for (i = 0; i < sel->nkeys; i++, key++) {
820 enum pedit_header_type htype =
821 TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK;
822 enum pedit_cmd cmd = TCA_PEDIT_KEY_EX_CMD_SET;
823
824 if (keys_ex) {
825 htype = key_ex->htype;
826 cmd = key_ex->cmd;
827
828 key_ex++;
829 }
830
831 open_json_object(NULL);
832 print_uint(PRINT_FP, NULL, "\n\t key #%d at ", i);
833
834 err = print_pedit_location(f, htype, key->off);
835 if (err) {
836 free(keys_ex);
837 return err;
838 }
839
840
841
842
843 print_string(PRINT_FP, NULL, ": %s",
844 cmd ? "add" : "val");
845 print_string(PRINT_JSON, "cmd", NULL,
846 cmd ? "add" : "set");
847 print_hex(PRINT_ANY, "val", " %08x",
848 (unsigned int)ntohl(key->val));
849 print_hex(PRINT_ANY, "mask", " mask %08x",
850 (unsigned int)ntohl(key->mask));
851 close_json_object();
852 }
853 } else {
854 fprintf(f, "\npedit %x keys %d is not LEGIT", sel->index,
855 sel->nkeys);
856 }
857 close_json_array(PRINT_JSON, " ");
858
859 print_nl();
860
861 free(keys_ex);
862 return 0;
863}
864
865struct action_util pedit_action_util = {
866 .id = "pedit",
867 .parse_aopt = parse_pedit,
868 .print_aopt = print_pedit,
869};
870