1
2
3#include <errno.h>
4#include <inttypes.h>
5#include <stdio.h>
6#include <libmnl/libmnl.h>
7#include <linux/dcbnl.h>
8
9#include "dcb.h"
10#include "utils.h"
11#include "rt_names.h"
12
13static const char *const pcp_names[DCB_APP_PCP_MAX + 1] = {
14 "0nd", "1nd", "2nd", "3nd", "4nd", "5nd", "6nd", "7nd",
15 "0de", "1de", "2de", "3de", "4de", "5de", "6de", "7de"
16};
17
18static const char *const ieee_attrs_app_names[__DCB_ATTR_IEEE_APP_MAX] = {
19 [DCB_ATTR_IEEE_APP] = "DCB_ATTR_IEEE_APP",
20 [DCB_ATTR_DCB_APP] = "DCB_ATTR_DCB_APP"
21};
22
23static void dcb_app_help_add(void)
24{
25 fprintf(stderr,
26 "Usage: dcb app { add | del | replace } dev STRING\n"
27 " [ default-prio PRIO ]\n"
28 " [ ethtype-prio ET:PRIO ]\n"
29 " [ stream-port-prio PORT:PRIO ]\n"
30 " [ dgram-port-prio PORT:PRIO ]\n"
31 " [ port-prio PORT:PRIO ]\n"
32 " [ dscp-prio INTEGER:PRIO ]\n"
33 " [ pcp-prio PCP:PRIO ]\n"
34 "\n"
35 " where PRIO := { 0 .. 7 }\n"
36 " ET := { 0x600 .. 0xffff }\n"
37 " PORT := { 1 .. 65535 }\n"
38 " DSCP := { 0 .. 63 }\n"
39 " PCP := { 0(nd/de) .. 7(nd/de) }\n"
40 "\n"
41 );
42}
43
44static void dcb_app_help_show_flush(void)
45{
46 fprintf(stderr,
47 "Usage: dcb app { show | flush } dev STRING\n"
48 " [ default-prio ]\n"
49 " [ ethtype-prio ]\n"
50 " [ stream-port-prio ]\n"
51 " [ dgram-port-prio ]\n"
52 " [ port-prio ]\n"
53 " [ dscp-prio ]\n"
54 " [ pcp-prio ]\n"
55 "\n"
56 );
57}
58
59static void dcb_app_help(void)
60{
61 fprintf(stderr,
62 "Usage: dcb app help\n"
63 "\n"
64 );
65 dcb_app_help_show_flush();
66 dcb_app_help_add();
67}
68
69enum ieee_attrs_app dcb_app_attr_type_get(__u8 selector)
70{
71 switch (selector) {
72 case IEEE_8021QAZ_APP_SEL_ETHERTYPE:
73 case IEEE_8021QAZ_APP_SEL_STREAM:
74 case IEEE_8021QAZ_APP_SEL_DGRAM:
75 case IEEE_8021QAZ_APP_SEL_ANY:
76 case IEEE_8021QAZ_APP_SEL_DSCP:
77 return DCB_ATTR_IEEE_APP;
78 case DCB_APP_SEL_PCP:
79 return DCB_ATTR_DCB_APP;
80 default:
81 return DCB_ATTR_IEEE_APP_UNSPEC;
82 }
83}
84
85bool dcb_app_attr_type_validate(enum ieee_attrs_app type)
86{
87 switch (type) {
88 case DCB_ATTR_IEEE_APP:
89 case DCB_ATTR_DCB_APP:
90 return true;
91 default:
92 return false;
93 }
94}
95
96bool dcb_app_selector_validate(enum ieee_attrs_app type, __u8 selector)
97{
98 return dcb_app_attr_type_get(selector) == type;
99}
100
101void dcb_app_table_fini(struct dcb_app_table *tab)
102{
103 free(tab->apps);
104}
105
106int dcb_app_table_push(struct dcb_app_table *tab, struct dcb_app *app)
107{
108 struct dcb_app *apps = realloc(tab->apps, (tab->n_apps + 1) * sizeof(*tab->apps));
109
110 if (apps == NULL) {
111 perror("Cannot allocate APP table");
112 return -ENOMEM;
113 }
114
115 tab->apps = apps;
116 tab->apps[tab->n_apps++] = *app;
117 return 0;
118}
119
120void dcb_app_table_remove_existing(struct dcb_app_table *a,
121 const struct dcb_app_table *b)
122{
123 size_t ia, ja;
124 size_t ib;
125
126 for (ia = 0, ja = 0; ia < a->n_apps; ia++) {
127 struct dcb_app *aa = &a->apps[ia];
128 bool found = false;
129
130 for (ib = 0; ib < b->n_apps; ib++) {
131 const struct dcb_app *ab = &b->apps[ib];
132
133 if (aa->selector == ab->selector &&
134 aa->protocol == ab->protocol &&
135 aa->priority == ab->priority) {
136 found = true;
137 break;
138 }
139 }
140
141 if (!found)
142 a->apps[ja++] = *aa;
143 }
144
145 a->n_apps = ja;
146}
147
148static bool dcb_app_pid_eq(const struct dcb_app *aa, const struct dcb_app *ab)
149{
150 return aa->selector == ab->selector &&
151 aa->protocol == ab->protocol;
152}
153
154void dcb_app_table_remove_replaced(struct dcb_app_table *a,
155 const struct dcb_app_table *b,
156 bool (*key_eq)(const struct dcb_app *aa,
157 const struct dcb_app *ab))
158{
159 size_t ia, ja;
160 size_t ib;
161
162 for (ia = 0, ja = 0; ia < a->n_apps; ia++) {
163 struct dcb_app *aa = &a->apps[ia];
164 bool present = false;
165 bool found = false;
166
167 for (ib = 0; ib < b->n_apps; ib++) {
168 const struct dcb_app *ab = &b->apps[ib];
169
170 if (key_eq(aa, ab))
171 present = true;
172 else
173 continue;
174
175 if (aa->protocol == ab->protocol &&
176 aa->priority == ab->priority) {
177 found = true;
178 break;
179 }
180 }
181
182
183
184
185
186 if (present && !found)
187 a->apps[ja++] = *aa;
188 }
189
190 a->n_apps = ja;
191}
192
193int dcb_app_table_copy(struct dcb_app_table *a,
194 const struct dcb_app_table *b)
195{
196 size_t i;
197 int ret;
198
199 for (i = 0; i < b->n_apps; i++) {
200 ret = dcb_app_table_push(a, &b->apps[i]);
201 if (ret != 0)
202 return ret;
203 }
204 return 0;
205}
206
207static int dcb_app_cmp(const struct dcb_app *a, const struct dcb_app *b)
208{
209 if (a->protocol < b->protocol)
210 return -1;
211 if (a->protocol > b->protocol)
212 return 1;
213 return a->priority - b->priority;
214}
215
216static int dcb_app_cmp_cb(const void *a, const void *b)
217{
218 return dcb_app_cmp(a, b);
219}
220
221void dcb_app_table_sort(struct dcb_app_table *tab)
222{
223 qsort(tab->apps, tab->n_apps, sizeof(*tab->apps), dcb_app_cmp_cb);
224}
225
226static void dcb_app_parse_mapping_cb(__u32 key, __u64 value, void *data)
227{
228 struct dcb_app_parse_mapping *pm = data;
229 struct dcb_app app = {
230 .selector = pm->selector,
231 .priority = value,
232 .protocol = key,
233 };
234
235 if (pm->err)
236 return;
237
238 pm->err = dcb_app_table_push(pm->tab, &app);
239}
240
241static int dcb_app_parse_mapping_ethtype_prio(__u32 key, char *value, void *data)
242{
243 __u8 prio;
244
245 if (key < 0x600) {
246 fprintf(stderr, "Protocol IDs < 0x600 are reserved for EtherType\n");
247 return -EINVAL;
248 }
249
250 if (get_u8(&prio, value, 0))
251 return -EINVAL;
252
253 return dcb_parse_mapping("ETHTYPE", key, 0xffff,
254 "PRIO", prio, IEEE_8021QAZ_MAX_TCS - 1,
255 dcb_app_parse_mapping_cb, data);
256}
257
258int dcb_app_parse_pcp(__u32 *key, const char *arg)
259{
260 int i;
261
262 for (i = 0; i < ARRAY_SIZE(pcp_names); i++) {
263 if (pcp_names[i] && strcmp(arg, pcp_names[i]) == 0) {
264 *key = i;
265 return 0;
266 }
267 }
268
269 return -EINVAL;
270}
271
272static int dcb_app_parse_mapping_pcp_prio(__u32 key, char *value, void *data)
273{
274 __u8 prio;
275
276 if (get_u8(&prio, value, 0))
277 return -EINVAL;
278
279 return dcb_parse_mapping("PCP", key, DCB_APP_PCP_MAX,
280 "PRIO", prio, IEEE_8021QAZ_MAX_TCS - 1,
281 dcb_app_parse_mapping_cb, data);
282}
283
284int dcb_app_parse_dscp(__u32 *key, const char *arg)
285{
286 if (parse_mapping_num_all(key, arg) == 0)
287 return 0;
288
289 if (rtnl_dsfield_a2n(key, arg) != 0)
290 return -1;
291
292 if (*key & 0x03) {
293 fprintf(stderr, "The values `%s' uses non-DSCP bits.\n", arg);
294 return -1;
295 }
296
297
298 *key >>= 2;
299 return 0;
300}
301
302static int dcb_app_parse_mapping_dscp_prio(__u32 key, char *value, void *data)
303{
304 __u8 prio;
305
306 if (get_u8(&prio, value, 0))
307 return -EINVAL;
308
309 return dcb_parse_mapping("DSCP", key, DCB_APP_DSCP_MAX,
310 "PRIO", prio, IEEE_8021QAZ_MAX_TCS - 1,
311 dcb_app_parse_mapping_cb, data);
312}
313
314static int dcb_app_parse_mapping_port_prio(__u32 key, char *value, void *data)
315{
316 __u8 prio;
317
318 if (key == 0) {
319 fprintf(stderr, "Port ID of 0 is invalid\n");
320 return -EINVAL;
321 }
322
323 if (get_u8(&prio, value, 0))
324 return -EINVAL;
325
326 return dcb_parse_mapping("PORT", key, 0xffff,
327 "PRIO", prio, IEEE_8021QAZ_MAX_TCS - 1,
328 dcb_app_parse_mapping_cb, data);
329}
330
331static int dcb_app_parse_default_prio(int *argcp, char ***argvp, struct dcb_app_table *tab)
332{
333 int argc = *argcp;
334 char **argv = *argvp;
335 int ret = 0;
336
337 while (argc > 0) {
338 struct dcb_app app;
339 __u8 prio;
340
341 if (get_u8(&prio, *argv, 0)) {
342 ret = 1;
343 break;
344 }
345
346 app = (struct dcb_app){
347 .selector = IEEE_8021QAZ_APP_SEL_ETHERTYPE,
348 .protocol = 0,
349 .priority = prio,
350 };
351 ret = dcb_app_table_push(tab, &app);
352 if (ret != 0)
353 break;
354
355 argc--, argv++;
356 }
357
358 *argcp = argc;
359 *argvp = argv;
360 return ret;
361}
362
363static bool dcb_app_is_ethtype(const struct dcb_app *app)
364{
365 return app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
366 app->protocol != 0;
367}
368
369static bool dcb_app_is_default(const struct dcb_app *app)
370{
371 return app->selector == IEEE_8021QAZ_APP_SEL_ETHERTYPE &&
372 app->protocol == 0;
373}
374
375bool dcb_app_is_dscp(const struct dcb_app *app)
376{
377 return app->selector == IEEE_8021QAZ_APP_SEL_DSCP;
378}
379
380bool dcb_app_is_pcp(const struct dcb_app *app)
381{
382 return app->selector == DCB_APP_SEL_PCP;
383}
384
385static bool dcb_app_is_stream_port(const struct dcb_app *app)
386{
387 return app->selector == IEEE_8021QAZ_APP_SEL_STREAM;
388}
389
390static bool dcb_app_is_dgram_port(const struct dcb_app *app)
391{
392 return app->selector == IEEE_8021QAZ_APP_SEL_DGRAM;
393}
394
395static bool dcb_app_is_port(const struct dcb_app *app)
396{
397 return app->selector == IEEE_8021QAZ_APP_SEL_ANY;
398}
399
400int dcb_app_print_pid_dec(__u16 protocol)
401{
402 return print_uint(PRINT_ANY, NULL, "%u", protocol);
403}
404
405static int dcb_app_print_pid_hex(__u16 protocol)
406{
407 return print_uint(PRINT_ANY, NULL, "%x", protocol);
408}
409
410int dcb_app_print_pid_dscp(__u16 protocol)
411{
412 const char *name = rtnl_dsfield_get_name(protocol << 2);
413
414
415 if (!is_json_context() && name != NULL)
416 return print_string(PRINT_FP, NULL, "%s", name);
417 return print_uint(PRINT_ANY, NULL, "%u", protocol);
418}
419
420int dcb_app_print_pid_pcp(__u16 protocol)
421{
422
423 if (protocol > DCB_APP_PCP_MAX)
424 return print_uint(PRINT_ANY, NULL, "%u", protocol);
425
426 return print_string(PRINT_ANY, NULL, "%s", pcp_names[protocol]);
427}
428
429void dcb_app_print_filtered(const struct dcb_app_table *tab,
430 bool (*filter)(const struct dcb_app *),
431 void (*print_pid_prio)(int (*print_pid)(__u16),
432 const struct dcb_app *),
433 int (*print_pid)(__u16 protocol),
434 const char *json_name,
435 const char *fp_name)
436{
437 bool first = true;
438 size_t i;
439
440 for (i = 0; i < tab->n_apps; i++) {
441 struct dcb_app *app = &tab->apps[i];
442
443 if (!filter(app))
444 continue;
445 if (first) {
446 open_json_array(PRINT_JSON, json_name);
447 print_string(PRINT_FP, NULL, "%s ", fp_name);
448 first = false;
449 }
450
451 open_json_array(PRINT_JSON, NULL);
452 print_pid_prio(print_pid, app);
453 print_string(PRINT_ANY, NULL, "%s", " ");
454 close_json_array(PRINT_JSON, NULL);
455 }
456
457 if (!first) {
458 close_json_array(PRINT_JSON, json_name);
459 print_nl();
460 }
461}
462
463static void dcb_app_print_pid_prio(int (*print_pid)(__u16 protocol),
464 const struct dcb_app *app)
465{
466 print_pid(app->protocol);
467 print_uint(PRINT_ANY, NULL, ":%u", app->priority);
468}
469
470static void dcb_app_print_ethtype_prio(const struct dcb_app_table *tab)
471{
472 dcb_app_print_filtered(tab, dcb_app_is_ethtype,
473 dcb_app_print_pid_prio, dcb_app_print_pid_hex,
474 "ethtype_prio", "ethtype-prio");
475}
476
477static void dcb_app_print_pcp_prio(const struct dcb *dcb,
478 const struct dcb_app_table *tab)
479{
480 dcb_app_print_filtered(tab, dcb_app_is_pcp,
481 dcb_app_print_pid_prio,
482 dcb->numeric ? dcb_app_print_pid_dec :
483 dcb_app_print_pid_pcp,
484 "pcp_prio", "pcp-prio");
485}
486
487static void dcb_app_print_dscp_prio(const struct dcb *dcb,
488 const struct dcb_app_table *tab)
489{
490 dcb_app_print_filtered(tab, dcb_app_is_dscp,
491 dcb_app_print_pid_prio,
492 dcb->numeric ? dcb_app_print_pid_dec :
493 dcb_app_print_pid_dscp,
494 "dscp_prio", "dscp-prio");
495}
496
497static void dcb_app_print_stream_port_prio(const struct dcb_app_table *tab)
498{
499 dcb_app_print_filtered(tab, dcb_app_is_stream_port,
500 dcb_app_print_pid_prio, dcb_app_print_pid_dec,
501 "stream_port_prio", "stream-port-prio");
502}
503
504static void dcb_app_print_dgram_port_prio(const struct dcb_app_table *tab)
505{
506 dcb_app_print_filtered(tab, dcb_app_is_dgram_port,
507 dcb_app_print_pid_prio, dcb_app_print_pid_dec,
508 "dgram_port_prio", "dgram-port-prio");
509}
510
511static void dcb_app_print_port_prio(const struct dcb_app_table *tab)
512{
513 dcb_app_print_filtered(tab, dcb_app_is_port,
514 dcb_app_print_pid_prio, dcb_app_print_pid_dec,
515 "port_prio", "port-prio");
516}
517
518static void dcb_app_print_default_prio(const struct dcb_app_table *tab)
519{
520 bool first = true;
521 size_t i;
522
523 for (i = 0; i < tab->n_apps; i++) {
524 if (!dcb_app_is_default(&tab->apps[i]))
525 continue;
526 if (first) {
527 open_json_array(PRINT_JSON, "default_prio");
528 print_string(PRINT_FP, NULL, "default-prio ", NULL);
529 first = false;
530 }
531 print_uint(PRINT_ANY, NULL, "%u ", tab->apps[i].priority);
532 }
533
534 if (!first) {
535 close_json_array(PRINT_JSON, "default_prio");
536 print_nl();
537 }
538}
539
540static void dcb_app_print(const struct dcb *dcb, const struct dcb_app_table *tab)
541{
542 dcb_app_print_ethtype_prio(tab);
543 dcb_app_print_default_prio(tab);
544 dcb_app_print_dscp_prio(dcb, tab);
545 dcb_app_print_stream_port_prio(tab);
546 dcb_app_print_dgram_port_prio(tab);
547 dcb_app_print_port_prio(tab);
548 dcb_app_print_pcp_prio(dcb, tab);
549}
550
551static int dcb_app_get_table_attr_cb(const struct nlattr *attr, void *data)
552{
553 struct dcb_app_table *tab = data;
554 struct dcb_app *app;
555 uint16_t type;
556 int ret;
557
558 type = mnl_attr_get_type(attr);
559
560 if (!dcb_app_attr_type_validate(type)) {
561 fprintf(stderr,
562 "Unknown attribute in DCB_ATTR_IEEE_APP_TABLE: %u\n",
563 type);
564 return MNL_CB_OK;
565 }
566 if (mnl_attr_get_payload_len(attr) < sizeof(struct dcb_app)) {
567 fprintf(stderr,
568 "%s payload expected to have size %zu, not %u\n",
569 ieee_attrs_app_names[type], sizeof(struct dcb_app),
570 mnl_attr_get_payload_len(attr));
571 return MNL_CB_OK;
572 }
573
574 app = mnl_attr_get_payload(attr);
575
576
577 if (!dcb_app_selector_validate(type, app->selector)) {
578 fprintf(stderr, "Wrong selector for type: %s\n",
579 ieee_attrs_app_names[type]);
580 return MNL_CB_OK;
581 }
582
583 ret = dcb_app_table_push(tab, app);
584 if (ret != 0)
585 return MNL_CB_ERROR;
586
587 return MNL_CB_OK;
588}
589
590int dcb_app_get(struct dcb *dcb, const char *dev, struct dcb_app_table *tab)
591{
592 uint16_t payload_len;
593 void *payload;
594 int ret;
595
596 ret = dcb_get_attribute_va(dcb, dev, tab->attr, &payload, &payload_len);
597 if (ret != 0)
598 return ret;
599
600 ret = mnl_attr_parse_payload(payload, payload_len, dcb_app_get_table_attr_cb, tab);
601 if (ret != MNL_CB_OK)
602 return -EINVAL;
603
604 return 0;
605}
606
607struct dcb_app_add_del {
608 const struct dcb_app_table *tab;
609 bool (*filter)(const struct dcb_app *app);
610};
611
612static int dcb_app_add_del_cb(struct dcb *dcb, struct nlmsghdr *nlh, void *data)
613{
614 struct dcb_app_add_del *add_del = data;
615 enum ieee_attrs_app type;
616 struct nlattr *nest;
617 size_t i;
618
619 nest = mnl_attr_nest_start(nlh, add_del->tab->attr);
620
621 for (i = 0; i < add_del->tab->n_apps; i++) {
622 const struct dcb_app *app = &add_del->tab->apps[i];
623 type = dcb_app_attr_type_get(app->selector);
624
625 if (add_del->filter == NULL || add_del->filter(app))
626 mnl_attr_put(nlh, type, sizeof(*app), app);
627 }
628
629 mnl_attr_nest_end(nlh, nest);
630 return 0;
631}
632
633int dcb_app_add_del(struct dcb *dcb, const char *dev, int command,
634 const struct dcb_app_table *tab,
635 bool (*filter)(const struct dcb_app *))
636{
637 struct dcb_app_add_del add_del = {
638 .tab = tab,
639 .filter = filter,
640 };
641
642 if (tab->n_apps == 0)
643 return 0;
644
645 return dcb_set_attribute_va(dcb, command, dev, dcb_app_add_del_cb, &add_del);
646}
647
648static int dcb_cmd_app_parse_add_del(struct dcb *dcb, const char *dev,
649 int argc, char **argv, struct dcb_app_table *tab)
650{
651 struct dcb_app_parse_mapping pm = {
652 .tab = tab,
653 };
654 int ret;
655
656 if (!argc) {
657 dcb_app_help_add();
658 return 0;
659 }
660
661 do {
662 if (matches(*argv, "help") == 0) {
663 dcb_app_help_add();
664 return 0;
665 } else if (matches(*argv, "ethtype-prio") == 0) {
666 NEXT_ARG();
667 pm.selector = IEEE_8021QAZ_APP_SEL_ETHERTYPE;
668 ret = parse_mapping(&argc, &argv, false,
669 &dcb_app_parse_mapping_ethtype_prio,
670 &pm);
671 } else if (matches(*argv, "default-prio") == 0) {
672 NEXT_ARG();
673 ret = dcb_app_parse_default_prio(&argc, &argv, pm.tab);
674 if (ret != 0) {
675 fprintf(stderr, "Invalid default priority %s\n", *argv);
676 return ret;
677 }
678 } else if (matches(*argv, "dscp-prio") == 0) {
679 NEXT_ARG();
680 pm.selector = IEEE_8021QAZ_APP_SEL_DSCP;
681 ret = parse_mapping_gen(&argc, &argv,
682 &dcb_app_parse_dscp,
683 &dcb_app_parse_mapping_dscp_prio,
684 &pm);
685 } else if (matches(*argv, "stream-port-prio") == 0) {
686 NEXT_ARG();
687 pm.selector = IEEE_8021QAZ_APP_SEL_STREAM;
688 ret = parse_mapping(&argc, &argv, false,
689 &dcb_app_parse_mapping_port_prio,
690 &pm);
691 } else if (matches(*argv, "dgram-port-prio") == 0) {
692 NEXT_ARG();
693 pm.selector = IEEE_8021QAZ_APP_SEL_DGRAM;
694 ret = parse_mapping(&argc, &argv, false,
695 &dcb_app_parse_mapping_port_prio,
696 &pm);
697 } else if (matches(*argv, "port-prio") == 0) {
698 NEXT_ARG();
699 pm.selector = IEEE_8021QAZ_APP_SEL_ANY;
700 ret = parse_mapping(&argc, &argv, false,
701 &dcb_app_parse_mapping_port_prio,
702 &pm);
703 } else if (strcmp(*argv, "pcp-prio") == 0) {
704 NEXT_ARG();
705 pm.selector = DCB_APP_SEL_PCP;
706 ret = parse_mapping_gen(&argc, &argv, &dcb_app_parse_pcp,
707 &dcb_app_parse_mapping_pcp_prio,
708 &pm);
709 } else {
710 fprintf(stderr, "What is \"%s\"?\n", *argv);
711 dcb_app_help_add();
712 return -EINVAL;
713 }
714
715 if (ret != 0) {
716 fprintf(stderr, "Invalid mapping %s\n", *argv);
717 return ret;
718 }
719 if (pm.err)
720 return pm.err;
721 } while (argc > 0);
722
723 return 0;
724}
725
726static int dcb_cmd_app_add(struct dcb *dcb, const char *dev, int argc, char **argv)
727{
728 struct dcb_app_table tab = { .attr = DCB_ATTR_IEEE_APP_TABLE };
729 int ret;
730
731 ret = dcb_cmd_app_parse_add_del(dcb, dev, argc, argv, &tab);
732 if (ret != 0)
733 return ret;
734
735 ret = dcb_app_add_del(dcb, dev, DCB_CMD_IEEE_SET, &tab, NULL);
736 dcb_app_table_fini(&tab);
737 return ret;
738}
739
740static int dcb_cmd_app_del(struct dcb *dcb, const char *dev, int argc, char **argv)
741{
742 struct dcb_app_table tab = { .attr = DCB_ATTR_IEEE_APP_TABLE };
743 int ret;
744
745 ret = dcb_cmd_app_parse_add_del(dcb, dev, argc, argv, &tab);
746 if (ret != 0)
747 return ret;
748
749 ret = dcb_app_add_del(dcb, dev, DCB_CMD_IEEE_DEL, &tab, NULL);
750 dcb_app_table_fini(&tab);
751 return ret;
752}
753
754static int dcb_cmd_app_show(struct dcb *dcb, const char *dev, int argc, char **argv)
755{
756 struct dcb_app_table tab = { .attr = DCB_ATTR_IEEE_APP_TABLE };
757 int ret;
758
759 ret = dcb_app_get(dcb, dev, &tab);
760 if (ret != 0)
761 return ret;
762
763 dcb_app_table_sort(&tab);
764
765 open_json_object(NULL);
766
767 if (!argc) {
768 dcb_app_print(dcb, &tab);
769 goto out;
770 }
771
772 do {
773 if (matches(*argv, "help") == 0) {
774 dcb_app_help_show_flush();
775 goto out;
776 } else if (matches(*argv, "ethtype-prio") == 0) {
777 dcb_app_print_ethtype_prio(&tab);
778 } else if (matches(*argv, "dscp-prio") == 0) {
779 dcb_app_print_dscp_prio(dcb, &tab);
780 } else if (matches(*argv, "stream-port-prio") == 0) {
781 dcb_app_print_stream_port_prio(&tab);
782 } else if (matches(*argv, "dgram-port-prio") == 0) {
783 dcb_app_print_dgram_port_prio(&tab);
784 } else if (matches(*argv, "port-prio") == 0) {
785 dcb_app_print_port_prio(&tab);
786 } else if (matches(*argv, "default-prio") == 0) {
787 dcb_app_print_default_prio(&tab);
788 } else if (strcmp(*argv, "pcp-prio") == 0) {
789 dcb_app_print_pcp_prio(dcb, &tab);
790 } else {
791 fprintf(stderr, "What is \"%s\"?\n", *argv);
792 dcb_app_help_show_flush();
793 ret = -EINVAL;
794 goto out;
795 }
796
797 NEXT_ARG_FWD();
798 } while (argc > 0);
799
800out:
801 close_json_object();
802 dcb_app_table_fini(&tab);
803 return ret;
804}
805
806static int dcb_cmd_app_flush(struct dcb *dcb, const char *dev, int argc, char **argv)
807{
808 struct dcb_app_table tab = { .attr = DCB_ATTR_IEEE_APP_TABLE };
809 int ret;
810
811 ret = dcb_app_get(dcb, dev, &tab);
812 if (ret != 0)
813 return ret;
814
815 if (!argc) {
816 ret = dcb_app_add_del(dcb, dev, DCB_CMD_IEEE_DEL, &tab, NULL);
817 goto out;
818 }
819
820 do {
821 if (matches(*argv, "help") == 0) {
822 dcb_app_help_show_flush();
823 goto out;
824 } else if (matches(*argv, "ethtype-prio") == 0) {
825 ret = dcb_app_add_del(dcb, dev, DCB_CMD_IEEE_DEL, &tab,
826 &dcb_app_is_ethtype);
827 if (ret != 0)
828 goto out;
829 } else if (matches(*argv, "default-prio") == 0) {
830 ret = dcb_app_add_del(dcb, dev, DCB_CMD_IEEE_DEL, &tab,
831 &dcb_app_is_default);
832 if (ret != 0)
833 goto out;
834 } else if (matches(*argv, "dscp-prio") == 0) {
835 ret = dcb_app_add_del(dcb, dev, DCB_CMD_IEEE_DEL, &tab,
836 &dcb_app_is_dscp);
837 if (ret != 0)
838 goto out;
839 } else if (strcmp(*argv, "pcp-prio") == 0) {
840 ret = dcb_app_add_del(dcb, dev, DCB_CMD_IEEE_DEL, &tab,
841 &dcb_app_is_pcp);
842 if (ret != 0)
843 goto out;
844 } else {
845 fprintf(stderr, "What is \"%s\"?\n", *argv);
846 dcb_app_help_show_flush();
847 ret = -EINVAL;
848 goto out;
849 }
850
851 NEXT_ARG_FWD();
852 } while (argc > 0);
853
854out:
855 dcb_app_table_fini(&tab);
856 return ret;
857}
858
859static int dcb_cmd_app_replace(struct dcb *dcb, const char *dev, int argc, char **argv)
860{
861 struct dcb_app_table orig = { .attr = DCB_ATTR_IEEE_APP_TABLE };
862 struct dcb_app_table tab = { .attr = DCB_ATTR_IEEE_APP_TABLE };
863 struct dcb_app_table new = { .attr = DCB_ATTR_IEEE_APP_TABLE };
864 int ret;
865
866 ret = dcb_app_get(dcb, dev, &orig);
867 if (ret != 0)
868 return ret;
869
870 ret = dcb_cmd_app_parse_add_del(dcb, dev, argc, argv, &tab);
871 if (ret != 0)
872 goto out;
873
874
875
876
877 ret = dcb_app_table_copy(&new, &tab);
878 if (ret != 0)
879 goto out;
880 dcb_app_table_remove_existing(&new, &orig);
881
882 ret = dcb_app_add_del(dcb, dev, DCB_CMD_IEEE_SET, &new, NULL);
883 if (ret != 0) {
884 fprintf(stderr, "Could not add new APP entries\n");
885 goto out;
886 }
887
888
889 dcb_app_table_remove_replaced(&orig, &tab, dcb_app_pid_eq);
890 ret = dcb_app_add_del(dcb, dev, DCB_CMD_IEEE_DEL, &orig, NULL);
891 if (ret != 0) {
892 fprintf(stderr, "Could not remove replaced APP entries\n");
893 goto out;
894 }
895
896out:
897 dcb_app_table_fini(&new);
898 dcb_app_table_fini(&tab);
899 dcb_app_table_fini(&orig);
900 return 0;
901}
902
903int dcb_cmd_app(struct dcb *dcb, int argc, char **argv)
904{
905 if (!argc || matches(*argv, "help") == 0) {
906 dcb_app_help();
907 return 0;
908 } else if (matches(*argv, "show") == 0) {
909 NEXT_ARG_FWD();
910 return dcb_cmd_parse_dev(dcb, argc, argv,
911 dcb_cmd_app_show, dcb_app_help_show_flush);
912 } else if (matches(*argv, "flush") == 0) {
913 NEXT_ARG_FWD();
914 return dcb_cmd_parse_dev(dcb, argc, argv,
915 dcb_cmd_app_flush, dcb_app_help_show_flush);
916 } else if (matches(*argv, "add") == 0) {
917 NEXT_ARG_FWD();
918 return dcb_cmd_parse_dev(dcb, argc, argv,
919 dcb_cmd_app_add, dcb_app_help_add);
920 } else if (matches(*argv, "del") == 0) {
921 NEXT_ARG_FWD();
922 return dcb_cmd_parse_dev(dcb, argc, argv,
923 dcb_cmd_app_del, dcb_app_help_add);
924 } else if (matches(*argv, "replace") == 0) {
925 NEXT_ARG_FWD();
926 return dcb_cmd_parse_dev(dcb, argc, argv,
927 dcb_cmd_app_replace, dcb_app_help_add);
928 } else {
929 fprintf(stderr, "What is \"%s\"?\n", *argv);
930 dcb_app_help();
931 return -EINVAL;
932 }
933}
934