1
2#include <stdio.h>
3#include <stdlib.h>
4#include <unistd.h>
5#include <fcntl.h>
6#include <sys/socket.h>
7#include <net/if.h>
8#include <netinet/in.h>
9#include <linux/if_bridge.h>
10#include <linux/if_ether.h>
11#include <string.h>
12
13#include "json_print.h"
14#include "libnetlink.h"
15#include "br_common.h"
16#include "utils.h"
17
18static unsigned int filter_index, filter_vlan;
19static int vlan_rtm_cur_ifidx = -1;
20
21enum vlan_show_subject {
22 VLAN_SHOW_VLAN,
23 VLAN_SHOW_TUNNELINFO,
24};
25
26#define VLAN_ID_LEN 9
27
28#define __stringify_1(x...) #x
29#define __stringify(x...) __stringify_1(x)
30
31static void usage(void)
32{
33 fprintf(stderr,
34 "Usage: bridge vlan { add | del } vid VLAN_ID dev DEV [ tunnel_info id TUNNEL_ID ]\n"
35 " [ pvid ] [ untagged ]\n"
36 " [ self ] [ master ]\n"
37 " bridge vlan { set } vid VLAN_ID dev DEV [ state STP_STATE ]\n"
38 " bridge vlan { show } [ dev DEV ] [ vid VLAN_ID ]\n"
39 " bridge vlan { tunnelshow } [ dev DEV ] [ vid VLAN_ID ]\n");
40 exit(-1);
41}
42
43static int parse_tunnel_info(int *argcp, char ***argvp, __u32 *tun_id_start,
44 __u32 *tun_id_end)
45{
46 char **argv = *argvp;
47 int argc = *argcp;
48 char *t;
49
50 NEXT_ARG();
51 if (!matches(*argv, "id")) {
52 NEXT_ARG();
53 t = strchr(*argv, '-');
54 if (t) {
55 *t = '\0';
56 if (get_u32(tun_id_start, *argv, 0) ||
57 *tun_id_start >= 1u << 24)
58 invarg("invalid tun id", *argv);
59 if (get_u32(tun_id_end, t + 1, 0) ||
60 *tun_id_end >= 1u << 24)
61 invarg("invalid tun id", *argv);
62
63 } else {
64 if (get_u32(tun_id_start, *argv, 0) ||
65 *tun_id_start >= 1u << 24)
66 invarg("invalid tun id", *argv);
67 }
68 } else {
69 invarg("tunnel id expected", *argv);
70 }
71
72 *argcp = argc;
73 *argvp = argv;
74
75 return 0;
76}
77
78static int add_tunnel_info(struct nlmsghdr *n, int reqsize,
79 __u16 vid, __u32 tun_id, __u16 flags)
80{
81 struct rtattr *tinfo;
82
83 tinfo = addattr_nest(n, reqsize, IFLA_BRIDGE_VLAN_TUNNEL_INFO);
84 addattr32(n, reqsize, IFLA_BRIDGE_VLAN_TUNNEL_ID, tun_id);
85 addattr16(n, reqsize, IFLA_BRIDGE_VLAN_TUNNEL_VID, vid);
86 addattr16(n, reqsize, IFLA_BRIDGE_VLAN_TUNNEL_FLAGS, flags);
87
88 addattr_nest_end(n, tinfo);
89
90 return 0;
91}
92
93static int add_tunnel_info_range(struct nlmsghdr *n, int reqsize,
94 __u16 vid_start, int16_t vid_end,
95 __u32 tun_id_start, __u32 tun_id_end)
96{
97 if (vid_end != -1 && (vid_end - vid_start) > 0) {
98 add_tunnel_info(n, reqsize, vid_start, tun_id_start,
99 BRIDGE_VLAN_INFO_RANGE_BEGIN);
100
101 add_tunnel_info(n, reqsize, vid_end, tun_id_end,
102 BRIDGE_VLAN_INFO_RANGE_END);
103 } else {
104 add_tunnel_info(n, reqsize, vid_start, tun_id_start, 0);
105 }
106
107 return 0;
108}
109
110static int add_vlan_info_range(struct nlmsghdr *n, int reqsize, __u16 vid_start,
111 int16_t vid_end, __u16 flags)
112{
113 struct bridge_vlan_info vinfo = {};
114
115 vinfo.flags = flags;
116 vinfo.vid = vid_start;
117 if (vid_end != -1) {
118
119 addattr_l(n, reqsize, IFLA_BRIDGE_VLAN_INFO, &vinfo,
120 sizeof(vinfo));
121 vinfo.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN;
122
123
124 vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_END;
125 vinfo.vid = vid_end;
126 addattr_l(n, reqsize, IFLA_BRIDGE_VLAN_INFO, &vinfo,
127 sizeof(vinfo));
128 } else {
129 addattr_l(n, reqsize, IFLA_BRIDGE_VLAN_INFO, &vinfo,
130 sizeof(vinfo));
131 }
132
133 return 0;
134}
135
136static int vlan_modify(int cmd, int argc, char **argv)
137{
138 struct {
139 struct nlmsghdr n;
140 struct ifinfomsg ifm;
141 char buf[1024];
142 } req = {
143 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
144 .n.nlmsg_flags = NLM_F_REQUEST,
145 .n.nlmsg_type = cmd,
146 .ifm.ifi_family = PF_BRIDGE,
147 };
148 char *d = NULL;
149 short vid = -1;
150 short vid_end = -1;
151 struct rtattr *afspec;
152 struct bridge_vlan_info vinfo = {};
153 bool tunnel_info_set = false;
154 unsigned short flags = 0;
155 __u32 tun_id_start = 0;
156 __u32 tun_id_end = 0;
157
158 while (argc > 0) {
159 if (strcmp(*argv, "dev") == 0) {
160 NEXT_ARG();
161 d = *argv;
162 } else if (strcmp(*argv, "vid") == 0) {
163 char *p;
164
165 NEXT_ARG();
166 p = strchr(*argv, '-');
167 if (p) {
168 *p = '\0';
169 p++;
170 vid = atoi(*argv);
171 vid_end = atoi(p);
172 vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN;
173 } else {
174 vid = atoi(*argv);
175 }
176 } else if (strcmp(*argv, "self") == 0) {
177 flags |= BRIDGE_FLAGS_SELF;
178 } else if (strcmp(*argv, "master") == 0) {
179 flags |= BRIDGE_FLAGS_MASTER;
180 } else if (strcmp(*argv, "pvid") == 0) {
181 vinfo.flags |= BRIDGE_VLAN_INFO_PVID;
182 } else if (strcmp(*argv, "untagged") == 0) {
183 vinfo.flags |= BRIDGE_VLAN_INFO_UNTAGGED;
184 } else if (strcmp(*argv, "tunnel_info") == 0) {
185 if (parse_tunnel_info(&argc, &argv,
186 &tun_id_start,
187 &tun_id_end))
188 return -1;
189 tunnel_info_set = true;
190 } else {
191 if (matches(*argv, "help") == 0)
192 NEXT_ARG();
193 }
194 argc--; argv++;
195 }
196
197 if (d == NULL || vid == -1) {
198 fprintf(stderr, "Device and VLAN ID are required arguments.\n");
199 return -1;
200 }
201
202 req.ifm.ifi_index = ll_name_to_index(d);
203 if (req.ifm.ifi_index == 0) {
204 fprintf(stderr, "Cannot find bridge device \"%s\"\n", d);
205 return -1;
206 }
207
208 if (vid >= 4096) {
209 fprintf(stderr, "Invalid VLAN ID \"%hu\"\n", vid);
210 return -1;
211 }
212
213 if (vinfo.flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
214 if (vid_end == -1 || vid_end >= 4096 || vid >= vid_end) {
215 fprintf(stderr, "Invalid VLAN range \"%hu-%hu\"\n",
216 vid, vid_end);
217 return -1;
218 }
219 if (vinfo.flags & BRIDGE_VLAN_INFO_PVID) {
220 fprintf(stderr,
221 "pvid cannot be configured for a vlan range\n");
222 return -1;
223 }
224 }
225
226 afspec = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC);
227
228 if (flags)
229 addattr16(&req.n, sizeof(req), IFLA_BRIDGE_FLAGS, flags);
230
231 if (tunnel_info_set)
232 add_tunnel_info_range(&req.n, sizeof(req), vid, vid_end,
233 tun_id_start, tun_id_end);
234 else
235 add_vlan_info_range(&req.n, sizeof(req), vid, vid_end,
236 vinfo.flags);
237
238 addattr_nest_end(&req.n, afspec);
239
240 if (rtnl_talk(&rth, &req.n, NULL) < 0)
241 return -1;
242
243 return 0;
244}
245
246static int vlan_option_set(int argc, char **argv)
247{
248 struct {
249 struct nlmsghdr n;
250 struct br_vlan_msg bvm;
251 char buf[1024];
252 } req = {
253 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_vlan_msg)),
254 .n.nlmsg_flags = NLM_F_REQUEST,
255 .n.nlmsg_type = RTM_NEWVLAN,
256 .bvm.family = PF_BRIDGE,
257 };
258 struct bridge_vlan_info vinfo = {};
259 struct rtattr *afspec;
260 short vid_end = -1;
261 char *d = NULL;
262 short vid = -1;
263 int state = -1;
264
265 while (argc > 0) {
266 if (strcmp(*argv, "dev") == 0) {
267 NEXT_ARG();
268 d = *argv;
269 } else if (strcmp(*argv, "vid") == 0) {
270 char *p;
271
272 NEXT_ARG();
273 p = strchr(*argv, '-');
274 if (p) {
275 *p = '\0';
276 p++;
277 vid = atoi(*argv);
278 vid_end = atoi(p);
279 if (vid >= vid_end || vid_end >= 4096) {
280 fprintf(stderr, "Invalid VLAN range \"%hu-%hu\"\n",
281 vid, vid_end);
282 return -1;
283 }
284 } else {
285 vid = atoi(*argv);
286 }
287 } else if (strcmp(*argv, "state") == 0) {
288 char *endptr;
289
290 NEXT_ARG();
291 state = strtol(*argv, &endptr, 10);
292 if (!(**argv != '\0' && *endptr == '\0'))
293 state = parse_stp_state(*argv);
294 if (state == -1) {
295 fprintf(stderr, "Error: invalid STP state\n");
296 return -1;
297 }
298 } else {
299 if (matches(*argv, "help") == 0)
300 NEXT_ARG();
301 }
302 argc--; argv++;
303 }
304
305 if (d == NULL || vid == -1) {
306 fprintf(stderr, "Device and VLAN ID are required arguments.\n");
307 return -1;
308 }
309
310 req.bvm.ifindex = ll_name_to_index(d);
311 if (req.bvm.ifindex == 0) {
312 fprintf(stderr, "Cannot find network device \"%s\"\n", d);
313 return -1;
314 }
315
316 if (vid >= 4096) {
317 fprintf(stderr, "Invalid VLAN ID \"%hu\"\n", vid);
318 return -1;
319 }
320 afspec = addattr_nest(&req.n, sizeof(req), BRIDGE_VLANDB_ENTRY);
321 afspec->rta_type |= NLA_F_NESTED;
322
323 vinfo.flags = BRIDGE_VLAN_INFO_ONLY_OPTS;
324 vinfo.vid = vid;
325 addattr_l(&req.n, sizeof(req), BRIDGE_VLANDB_ENTRY_INFO, &vinfo,
326 sizeof(vinfo));
327 if (vid_end != -1)
328 addattr16(&req.n, sizeof(req), BRIDGE_VLANDB_ENTRY_RANGE,
329 vid_end);
330 if (state >= 0)
331 addattr8(&req.n, sizeof(req), BRIDGE_VLANDB_ENTRY_STATE, state);
332 addattr_nest_end(&req.n, afspec);
333
334 if (rtnl_talk(&rth, &req.n, NULL) < 0)
335 return -1;
336
337 return 0;
338}
339
340
341
342
343
344
345
346
347static int filter_vlan_check(__u16 vid, __u16 flags)
348{
349
350 if (filter_vlan && vid > filter_vlan &&
351 !(flags & BRIDGE_VLAN_INFO_RANGE_END))
352 return -1;
353 if ((flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) ||
354 vid < filter_vlan)
355 return 0;
356
357 return 1;
358}
359
360static void open_vlan_port(int ifi_index, enum vlan_show_subject subject)
361{
362 open_json_object(NULL);
363 print_color_string(PRINT_ANY, COLOR_IFNAME, "ifname",
364 "%-" __stringify(IFNAMSIZ) "s ",
365 ll_index_to_name(ifi_index));
366 open_json_array(PRINT_JSON,
367 subject == VLAN_SHOW_VLAN ? "vlans": "tunnels");
368}
369
370static void close_vlan_port(void)
371{
372 close_json_array(PRINT_JSON, NULL);
373 close_json_object();
374}
375
376static unsigned int print_range(const char *name, __u32 start, __u32 id)
377{
378 char end[64];
379 int width;
380
381 snprintf(end, sizeof(end), "%sEnd", name);
382
383 width = print_uint(PRINT_ANY, name, "%u", start);
384 if (start != id)
385 width += print_uint(PRINT_ANY, end, "-%u", id);
386
387 return width;
388}
389
390static void print_vlan_tunnel_info(struct rtattr *tb, int ifindex)
391{
392 struct rtattr *i, *list = tb;
393 int rem = RTA_PAYLOAD(list);
394 __u16 last_vid_start = 0;
395 __u32 last_tunid_start = 0;
396 bool opened = false;
397
398 for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
399 struct rtattr *ttb[IFLA_BRIDGE_VLAN_TUNNEL_MAX+1];
400 __u32 tunnel_id = 0;
401 __u16 tunnel_vid = 0;
402 __u16 tunnel_flags = 0;
403 unsigned int width;
404 int vcheck_ret;
405
406 if (i->rta_type != IFLA_BRIDGE_VLAN_TUNNEL_INFO)
407 continue;
408
409 parse_rtattr(ttb, IFLA_BRIDGE_VLAN_TUNNEL_MAX,
410 RTA_DATA(i), RTA_PAYLOAD(i));
411
412 if (ttb[IFLA_BRIDGE_VLAN_TUNNEL_VID])
413 tunnel_vid =
414 rta_getattr_u16(ttb[IFLA_BRIDGE_VLAN_TUNNEL_VID]);
415 else
416 continue;
417
418 if (ttb[IFLA_BRIDGE_VLAN_TUNNEL_ID])
419 tunnel_id =
420 rta_getattr_u32(ttb[IFLA_BRIDGE_VLAN_TUNNEL_ID]);
421
422 if (ttb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS])
423 tunnel_flags =
424 rta_getattr_u16(ttb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS]);
425
426 if (!(tunnel_flags & BRIDGE_VLAN_INFO_RANGE_END)) {
427 last_vid_start = tunnel_vid;
428 last_tunid_start = tunnel_id;
429 }
430
431 vcheck_ret = filter_vlan_check(tunnel_vid, tunnel_flags);
432 if (vcheck_ret == -1)
433 break;
434 else if (vcheck_ret == 0)
435 continue;
436
437 if (!opened) {
438 open_vlan_port(ifindex, VLAN_SHOW_TUNNELINFO);
439 opened = true;
440 } else {
441 print_string(PRINT_FP, NULL,
442 "%-" __stringify(IFNAMSIZ) "s ", "");
443 }
444
445 open_json_object(NULL);
446 width = print_range("vlan", last_vid_start, tunnel_vid);
447 if (width <= VLAN_ID_LEN) {
448 char buf[VLAN_ID_LEN + 1];
449
450 snprintf(buf, sizeof(buf), "%-*s",
451 VLAN_ID_LEN - width, "");
452 print_string(PRINT_FP, NULL, "%s ", buf);
453 } else {
454 fprintf(stderr, "BUG: vlan range too wide, %u\n",
455 width);
456 }
457 print_range("tunid", last_tunid_start, tunnel_id);
458 close_json_object();
459 print_nl();
460 }
461
462 if (opened)
463 close_vlan_port();
464}
465
466static int print_vlan(struct nlmsghdr *n, void *arg)
467{
468 enum vlan_show_subject *subject = arg;
469 struct ifinfomsg *ifm = NLMSG_DATA(n);
470 int len = n->nlmsg_len;
471 struct rtattr *tb[IFLA_MAX+1];
472
473 if (n->nlmsg_type != RTM_NEWLINK) {
474 fprintf(stderr, "Not RTM_NEWLINK: %08x %08x %08x\n",
475 n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
476 return 0;
477 }
478
479 len -= NLMSG_LENGTH(sizeof(*ifm));
480 if (len < 0) {
481 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
482 return -1;
483 }
484
485 if (ifm->ifi_family != AF_BRIDGE)
486 return 0;
487
488 if (filter_index && filter_index != ifm->ifi_index)
489 return 0;
490
491 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifm), len);
492 if (!tb[IFLA_AF_SPEC])
493 return 0;
494
495 switch (*subject) {
496 case VLAN_SHOW_VLAN:
497 print_vlan_info(tb[IFLA_AF_SPEC], ifm->ifi_index);
498 break;
499 case VLAN_SHOW_TUNNELINFO:
500 print_vlan_tunnel_info(tb[IFLA_AF_SPEC], ifm->ifi_index);
501 break;
502 }
503
504 return 0;
505}
506
507static void print_vlan_flags(__u16 flags)
508{
509 if (flags == 0)
510 return;
511
512 open_json_array(PRINT_JSON, "flags");
513 if (flags & BRIDGE_VLAN_INFO_PVID)
514 print_string(PRINT_ANY, NULL, " %s", "PVID");
515
516 if (flags & BRIDGE_VLAN_INFO_UNTAGGED)
517 print_string(PRINT_ANY, NULL, " %s", "Egress Untagged");
518 close_json_array(PRINT_JSON, NULL);
519}
520
521static void __print_one_vlan_stats(const struct bridge_vlan_xstats *vstats)
522{
523 print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s ", "");
524 print_lluint(PRINT_ANY, "rx_bytes", "RX: %llu bytes",
525 vstats->rx_bytes);
526 print_lluint(PRINT_ANY, "rx_packets", " %llu packets\n",
527 vstats->rx_packets);
528
529 print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s ", "");
530 print_lluint(PRINT_ANY, "tx_bytes", "TX: %llu bytes",
531 vstats->tx_bytes);
532 print_lluint(PRINT_ANY, "tx_packets", " %llu packets\n",
533 vstats->tx_packets);
534}
535
536static void print_one_vlan_stats(const struct bridge_vlan_xstats *vstats)
537{
538 open_json_object(NULL);
539
540 print_hu(PRINT_ANY, "vid", "%hu", vstats->vid);
541 print_vlan_flags(vstats->flags);
542 print_nl();
543 __print_one_vlan_stats(vstats);
544
545 close_json_object();
546}
547
548static void print_vlan_stats_attr(struct rtattr *attr, int ifindex)
549{
550 struct rtattr *brtb[LINK_XSTATS_TYPE_MAX+1];
551 struct rtattr *i, *list;
552 bool found_vlan = false;
553 int rem;
554
555 parse_rtattr(brtb, LINK_XSTATS_TYPE_MAX, RTA_DATA(attr),
556 RTA_PAYLOAD(attr));
557 if (!brtb[LINK_XSTATS_TYPE_BRIDGE])
558 return;
559
560 list = brtb[LINK_XSTATS_TYPE_BRIDGE];
561 rem = RTA_PAYLOAD(list);
562
563 for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
564 const struct bridge_vlan_xstats *vstats = RTA_DATA(i);
565
566 if (i->rta_type != BRIDGE_XSTATS_VLAN)
567 continue;
568
569 if (filter_vlan && filter_vlan != vstats->vid)
570 continue;
571
572
573 if ((vstats->flags & BRIDGE_VLAN_INFO_MASTER) &&
574 !(vstats->flags & BRIDGE_VLAN_INFO_BRENTRY))
575 continue;
576
577
578 if (!found_vlan) {
579 open_vlan_port(ifindex, VLAN_SHOW_VLAN);
580 found_vlan = true;
581 } else {
582 print_string(PRINT_FP, NULL,
583 "%-" __stringify(IFNAMSIZ) "s ", "");
584 }
585 print_one_vlan_stats(vstats);
586 }
587
588
589 if (found_vlan)
590 close_vlan_port();
591}
592
593static int print_vlan_stats(struct nlmsghdr *n, void *arg)
594{
595 struct if_stats_msg *ifsm = NLMSG_DATA(n);
596 struct rtattr *tb[IFLA_STATS_MAX+1];
597 int len = n->nlmsg_len;
598 FILE *fp = arg;
599
600 len -= NLMSG_LENGTH(sizeof(*ifsm));
601 if (len < 0) {
602 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
603 return -1;
604 }
605
606 if (filter_index && filter_index != ifsm->ifindex)
607 return 0;
608
609 parse_rtattr(tb, IFLA_STATS_MAX, IFLA_STATS_RTA(ifsm), len);
610
611
612 if (tb[IFLA_STATS_LINK_XSTATS])
613 print_vlan_stats_attr(tb[IFLA_STATS_LINK_XSTATS],
614 ifsm->ifindex);
615
616 if (tb[IFLA_STATS_LINK_XSTATS_SLAVE])
617 print_vlan_stats_attr(tb[IFLA_STATS_LINK_XSTATS_SLAVE],
618 ifsm->ifindex);
619
620 fflush(fp);
621 return 0;
622}
623
624int print_vlan_rtm(struct nlmsghdr *n, void *arg, bool monitor)
625{
626 struct rtattr *vtb[BRIDGE_VLANDB_ENTRY_MAX + 1], *a;
627 struct br_vlan_msg *bvm = NLMSG_DATA(n);
628 int len = n->nlmsg_len;
629 int rem;
630
631 if (n->nlmsg_type != RTM_NEWVLAN && n->nlmsg_type != RTM_DELVLAN &&
632 n->nlmsg_type != RTM_GETVLAN) {
633 fprintf(stderr, "Unknown vlan rtm message: %08x %08x %08x\n",
634 n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
635 return 0;
636 }
637
638 len -= NLMSG_LENGTH(sizeof(*bvm));
639 if (len < 0) {
640 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
641 return -1;
642 }
643
644 if (bvm->family != AF_BRIDGE)
645 return 0;
646
647 if (filter_index && filter_index != bvm->ifindex)
648 return 0;
649
650 if (n->nlmsg_type == RTM_DELVLAN)
651 print_bool(PRINT_ANY, "deleted", "Deleted ", true);
652
653 if (monitor)
654 vlan_rtm_cur_ifidx = -1;
655
656 if (vlan_rtm_cur_ifidx != -1 && vlan_rtm_cur_ifidx != bvm->ifindex) {
657 close_vlan_port();
658 vlan_rtm_cur_ifidx = -1;
659 }
660
661 rem = len;
662 for (a = BRVLAN_RTA(bvm); RTA_OK(a, rem); a = RTA_NEXT(a, rem)) {
663 struct bridge_vlan_xstats vstats;
664 struct bridge_vlan_info *vinfo;
665 __u32 vrange = 0;
666 __u8 state = 0;
667
668 parse_rtattr_flags(vtb, BRIDGE_VLANDB_ENTRY_MAX, RTA_DATA(a),
669 RTA_PAYLOAD(a), NLA_F_NESTED);
670 vinfo = RTA_DATA(vtb[BRIDGE_VLANDB_ENTRY_INFO]);
671
672 memset(&vstats, 0, sizeof(vstats));
673 if (vtb[BRIDGE_VLANDB_ENTRY_RANGE])
674 vrange = rta_getattr_u16(vtb[BRIDGE_VLANDB_ENTRY_RANGE]);
675 else
676 vrange = vinfo->vid;
677
678 if (vtb[BRIDGE_VLANDB_ENTRY_STATE])
679 state = rta_getattr_u8(vtb[BRIDGE_VLANDB_ENTRY_STATE]);
680
681 if (vtb[BRIDGE_VLANDB_ENTRY_STATS]) {
682 struct rtattr *stb[BRIDGE_VLANDB_STATS_MAX+1];
683 struct rtattr *attr;
684
685 attr = vtb[BRIDGE_VLANDB_ENTRY_STATS];
686 parse_rtattr(stb, BRIDGE_VLANDB_STATS_MAX, RTA_DATA(attr),
687 RTA_PAYLOAD(attr));
688
689 if (stb[BRIDGE_VLANDB_STATS_RX_BYTES]) {
690 attr = stb[BRIDGE_VLANDB_STATS_RX_BYTES];
691 vstats.rx_bytes = rta_getattr_u64(attr);
692 }
693 if (stb[BRIDGE_VLANDB_STATS_RX_PACKETS]) {
694 attr = stb[BRIDGE_VLANDB_STATS_RX_PACKETS];
695 vstats.rx_packets = rta_getattr_u64(attr);
696 }
697 if (stb[BRIDGE_VLANDB_STATS_TX_PACKETS]) {
698 attr = stb[BRIDGE_VLANDB_STATS_TX_PACKETS];
699 vstats.tx_packets = rta_getattr_u64(attr);
700 }
701 if (stb[BRIDGE_VLANDB_STATS_TX_BYTES]) {
702 attr = stb[BRIDGE_VLANDB_STATS_TX_BYTES];
703 vstats.tx_bytes = rta_getattr_u64(attr);
704 }
705 }
706 if (vlan_rtm_cur_ifidx != bvm->ifindex) {
707 open_vlan_port(bvm->ifindex, VLAN_SHOW_VLAN);
708 open_json_object(NULL);
709 vlan_rtm_cur_ifidx = bvm->ifindex;
710 } else {
711 open_json_object(NULL);
712 print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s ", "");
713 }
714 print_range("vlan", vinfo->vid, vrange);
715 print_vlan_flags(vinfo->flags);
716 print_nl();
717 print_string(PRINT_FP, NULL, "%-" __stringify(IFNAMSIZ) "s ", "");
718 print_stp_state(state);
719 print_nl();
720 if (show_stats)
721 __print_one_vlan_stats(&vstats);
722 close_json_object();
723 }
724
725 return 0;
726}
727
728static int print_vlan_rtm_filter(struct nlmsghdr *n, void *arg)
729{
730 return print_vlan_rtm(n, arg, false);
731}
732
733static int vlan_show(int argc, char **argv, int subject)
734{
735 char *filter_dev = NULL;
736 int ret = 0;
737
738 while (argc > 0) {
739 if (strcmp(*argv, "dev") == 0) {
740 NEXT_ARG();
741 if (filter_dev)
742 duparg("dev", *argv);
743 filter_dev = *argv;
744 } else if (strcmp(*argv, "vid") == 0) {
745 NEXT_ARG();
746 if (filter_vlan)
747 duparg("vid", *argv);
748 filter_vlan = atoi(*argv);
749 }
750 argc--; argv++;
751 }
752
753 if (filter_dev) {
754 filter_index = ll_name_to_index(filter_dev);
755 if (!filter_index)
756 return nodev(filter_dev);
757 }
758
759 new_json_obj(json);
760
761
762 if (show_details && subject == VLAN_SHOW_VLAN) {
763 __u32 dump_flags = show_stats ? BRIDGE_VLANDB_DUMPF_STATS : 0;
764
765 if (rtnl_brvlandump_req(&rth, PF_BRIDGE, dump_flags) < 0) {
766 perror("Cannot send dump request");
767 exit(1);
768 }
769
770 if (!is_json_context()) {
771 printf("%-" __stringify(IFNAMSIZ) "s %-"
772 __stringify(VLAN_ID_LEN) "s", "port",
773 "vlan-id");
774 printf("\n");
775 }
776
777 ret = rtnl_dump_filter(&rth, print_vlan_rtm_filter, &subject);
778 if (ret < 0) {
779 fprintf(stderr, "Dump terminated\n");
780 exit(1);
781 }
782
783 if (vlan_rtm_cur_ifidx != -1)
784 close_vlan_port();
785
786 goto out;
787 }
788
789 if (!show_stats) {
790 if (rtnl_linkdump_req_filter(&rth, PF_BRIDGE,
791 (compress_vlans ?
792 RTEXT_FILTER_BRVLAN_COMPRESSED :
793 RTEXT_FILTER_BRVLAN)) < 0) {
794 perror("Cannot send dump request");
795 exit(1);
796 }
797
798 if (!is_json_context()) {
799 printf("%-" __stringify(IFNAMSIZ) "s %-"
800 __stringify(VLAN_ID_LEN) "s", "port",
801 "vlan-id");
802 if (subject == VLAN_SHOW_TUNNELINFO)
803 printf(" tunnel-id");
804 printf("\n");
805 }
806
807 ret = rtnl_dump_filter(&rth, print_vlan, &subject);
808 if (ret < 0) {
809 fprintf(stderr, "Dump terminated\n");
810 exit(1);
811 }
812 } else {
813 __u32 filt_mask;
814
815 filt_mask = IFLA_STATS_FILTER_BIT(IFLA_STATS_LINK_XSTATS);
816 if (rtnl_statsdump_req_filter(&rth, AF_UNSPEC, filt_mask) < 0) {
817 perror("Cannot send dump request");
818 exit(1);
819 }
820
821 if (!is_json_context())
822 printf("%-" __stringify(IFNAMSIZ) "s vlan-id\n",
823 "port");
824
825 if (rtnl_dump_filter(&rth, print_vlan_stats, stdout) < 0) {
826 fprintf(stderr, "Dump terminated\n");
827 exit(1);
828 }
829
830 filt_mask = IFLA_STATS_FILTER_BIT(IFLA_STATS_LINK_XSTATS_SLAVE);
831 if (rtnl_statsdump_req_filter(&rth, AF_UNSPEC, filt_mask) < 0) {
832 perror("Cannot send slave dump request");
833 exit(1);
834 }
835
836 if (rtnl_dump_filter(&rth, print_vlan_stats, stdout) < 0) {
837 fprintf(stderr, "Dump terminated\n");
838 exit(1);
839 }
840 }
841
842out:
843 delete_json_obj();
844 fflush(stdout);
845 return 0;
846}
847
848void print_vlan_info(struct rtattr *tb, int ifindex)
849{
850 struct rtattr *i, *list = tb;
851 int rem = RTA_PAYLOAD(list);
852 __u16 last_vid_start = 0;
853 bool opened = false;
854
855 for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
856 struct bridge_vlan_info *vinfo;
857 int vcheck_ret;
858
859 if (i->rta_type != IFLA_BRIDGE_VLAN_INFO)
860 continue;
861
862 vinfo = RTA_DATA(i);
863
864 if (!(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END))
865 last_vid_start = vinfo->vid;
866 vcheck_ret = filter_vlan_check(vinfo->vid, vinfo->flags);
867 if (vcheck_ret == -1)
868 break;
869 else if (vcheck_ret == 0)
870 continue;
871
872 if (!opened) {
873 open_vlan_port(ifindex, VLAN_SHOW_VLAN);
874 opened = true;
875 } else {
876 print_string(PRINT_FP, NULL, "%-"
877 __stringify(IFNAMSIZ) "s ", "");
878 }
879
880 open_json_object(NULL);
881 print_range("vlan", last_vid_start, vinfo->vid);
882
883 print_vlan_flags(vinfo->flags);
884 close_json_object();
885 print_nl();
886 }
887
888 if (opened)
889 close_vlan_port();
890}
891
892int do_vlan(int argc, char **argv)
893{
894 ll_init_map(&rth);
895
896 if (argc > 0) {
897 if (matches(*argv, "add") == 0)
898 return vlan_modify(RTM_SETLINK, argc-1, argv+1);
899 if (matches(*argv, "delete") == 0)
900 return vlan_modify(RTM_DELLINK, argc-1, argv+1);
901 if (matches(*argv, "show") == 0 ||
902 matches(*argv, "lst") == 0 ||
903 matches(*argv, "list") == 0)
904 return vlan_show(argc-1, argv+1, VLAN_SHOW_VLAN);
905 if (matches(*argv, "tunnelshow") == 0) {
906 return vlan_show(argc-1, argv+1, VLAN_SHOW_TUNNELINFO);
907 }
908 if (matches(*argv, "set") == 0)
909 return vlan_option_set(argc-1, argv+1);
910 if (matches(*argv, "help") == 0)
911 usage();
912 } else {
913 return vlan_show(0, NULL, VLAN_SHOW_VLAN);
914 }
915
916 fprintf(stderr, "Command \"%s\" is unknown, try \"bridge vlan help\".\n", *argv);
917 exit(-1);
918}
919