1
2#include <stdio.h>
3#include <stdlib.h>
4#include <unistd.h>
5#include <fcntl.h>
6#include <sys/socket.h>
7#include <sys/time.h>
8#include <net/if.h>
9#include <netinet/in.h>
10#include <linux/if_bridge.h>
11#include <linux/if_ether.h>
12#include <string.h>
13#include <errno.h>
14
15#include "json_print.h"
16#include "libnetlink.h"
17#include "br_common.h"
18#include "bridge.h"
19#include "utils.h"
20
21static unsigned int filter_index, filter_vlan;
22static int vlan_rtm_cur_ifidx = -1;
23static void print_vlan_info(struct rtattr *tb, int ifindex);
24
25enum vlan_show_subject {
26 VLAN_SHOW_VLAN,
27 VLAN_SHOW_TUNNELINFO,
28};
29
30#define VLAN_ID_LEN 9
31
32static void usage(void)
33{
34 fprintf(stderr,
35 "Usage: bridge vlan { add | del } vid VLAN_ID dev DEV [ tunnel_info id TUNNEL_ID ]\n"
36 " [ pvid ] [ untagged ]\n"
37 " [ self ] [ master ]\n"
38 " bridge vlan { set } vid VLAN_ID dev DEV [ state STP_STATE ]\n"
39 " [ mcast_router MULTICAST_ROUTER ]\n"
40 " [ mcast_max_groups MAX_GROUPS ]\n"
41 " [ neigh_suppress {on | off} ]\n"
42 " bridge vlan { show } [ dev DEV ] [ vid VLAN_ID ]\n"
43 " bridge vlan { tunnelshow } [ dev DEV ] [ vid VLAN_ID ]\n"
44 " bridge vlan global { set } vid VLAN_ID dev DEV\n"
45 " [ mcast_snooping MULTICAST_SNOOPING ]\n"
46 " [ mcast_querier MULTICAST_QUERIER ]\n"
47 " [ mcast_igmp_version IGMP_VERSION ]\n"
48 " [ mcast_mld_version MLD_VERSION ]\n"
49 " [ mcast_last_member_count LAST_MEMBER_COUNT ]\n"
50 " [ mcast_last_member_interval LAST_MEMBER_INTERVAL ]\n"
51 " [ mcast_startup_query_count STARTUP_QUERY_COUNT ]\n"
52 " [ mcast_startup_query_interval STARTUP_QUERY_INTERVAL ]\n"
53 " [ mcast_membership_interval MEMBERSHIP_INTERVAL ]\n"
54 " [ mcast_querier_interval QUERIER_INTERVAL ]\n"
55 " [ mcast_query_interval QUERY_INTERVAL ]\n"
56 " [ mcast_query_response_interval QUERY_RESPONSE_INTERVAL ]\n"
57 " [ msti MSTI ]\n"
58 " bridge vlan global { show } [ dev DEV ] [ vid VLAN_ID ]\n");
59 exit(-1);
60}
61
62static int parse_tunnel_info(int *argcp, char ***argvp, __u32 *tun_id_start,
63 __u32 *tun_id_end)
64{
65 char **argv = *argvp;
66 int argc = *argcp;
67 char *t;
68
69 NEXT_ARG();
70 if (!matches(*argv, "id")) {
71 NEXT_ARG();
72 t = strchr(*argv, '-');
73 if (t) {
74 *t = '\0';
75 if (get_u32(tun_id_start, *argv, 0) ||
76 *tun_id_start >= 1u << 24)
77 invarg("invalid tun id", *argv);
78 if (get_u32(tun_id_end, t + 1, 0) ||
79 *tun_id_end >= 1u << 24)
80 invarg("invalid tun id", *argv);
81
82 } else {
83 if (get_u32(tun_id_start, *argv, 0) ||
84 *tun_id_start >= 1u << 24)
85 invarg("invalid tun id", *argv);
86 }
87 } else {
88 invarg("tunnel id expected", *argv);
89 }
90
91 *argcp = argc;
92 *argvp = argv;
93
94 return 0;
95}
96
97static int add_tunnel_info(struct nlmsghdr *n, int reqsize,
98 __u16 vid, __u32 tun_id, __u16 flags)
99{
100 struct rtattr *tinfo;
101
102 tinfo = addattr_nest(n, reqsize, IFLA_BRIDGE_VLAN_TUNNEL_INFO);
103 addattr32(n, reqsize, IFLA_BRIDGE_VLAN_TUNNEL_ID, tun_id);
104 addattr16(n, reqsize, IFLA_BRIDGE_VLAN_TUNNEL_VID, vid);
105 addattr16(n, reqsize, IFLA_BRIDGE_VLAN_TUNNEL_FLAGS, flags);
106
107 addattr_nest_end(n, tinfo);
108
109 return 0;
110}
111
112static int add_tunnel_info_range(struct nlmsghdr *n, int reqsize,
113 __u16 vid_start, int16_t vid_end,
114 __u32 tun_id_start, __u32 tun_id_end)
115{
116 if (vid_end != -1 && (vid_end - vid_start) > 0) {
117 add_tunnel_info(n, reqsize, vid_start, tun_id_start,
118 BRIDGE_VLAN_INFO_RANGE_BEGIN);
119
120 add_tunnel_info(n, reqsize, vid_end, tun_id_end,
121 BRIDGE_VLAN_INFO_RANGE_END);
122 } else {
123 add_tunnel_info(n, reqsize, vid_start, tun_id_start, 0);
124 }
125
126 return 0;
127}
128
129static int add_vlan_info_range(struct nlmsghdr *n, int reqsize, __u16 vid_start,
130 int16_t vid_end, __u16 flags)
131{
132 struct bridge_vlan_info vinfo = {};
133
134 vinfo.flags = flags;
135 vinfo.vid = vid_start;
136 if (vid_end != -1) {
137
138 addattr_l(n, reqsize, IFLA_BRIDGE_VLAN_INFO, &vinfo,
139 sizeof(vinfo));
140 vinfo.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN;
141
142
143 vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_END;
144 vinfo.vid = vid_end;
145 addattr_l(n, reqsize, IFLA_BRIDGE_VLAN_INFO, &vinfo,
146 sizeof(vinfo));
147 } else {
148 addattr_l(n, reqsize, IFLA_BRIDGE_VLAN_INFO, &vinfo,
149 sizeof(vinfo));
150 }
151
152 return 0;
153}
154
155static int vlan_modify(int cmd, int argc, char **argv)
156{
157 struct {
158 struct nlmsghdr n;
159 struct ifinfomsg ifm;
160 char buf[1024];
161 } req = {
162 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
163 .n.nlmsg_flags = NLM_F_REQUEST,
164 .n.nlmsg_type = cmd,
165 .ifm.ifi_family = PF_BRIDGE,
166 };
167 char *d = NULL;
168 short vid = -1;
169 short vid_end = -1;
170 struct rtattr *afspec;
171 struct bridge_vlan_info vinfo = {};
172 bool tunnel_info_set = false;
173 unsigned short flags = 0;
174 __u32 tun_id_start = 0;
175 __u32 tun_id_end = 0;
176
177 while (argc > 0) {
178 if (strcmp(*argv, "dev") == 0) {
179 NEXT_ARG();
180 d = *argv;
181 } else if (strcmp(*argv, "vid") == 0) {
182 char *p;
183
184 NEXT_ARG();
185 p = strchr(*argv, '-');
186 if (p) {
187 *p = '\0';
188 p++;
189 vid = atoi(*argv);
190 vid_end = atoi(p);
191 vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN;
192 } else {
193 vid = atoi(*argv);
194 }
195 } else if (strcmp(*argv, "self") == 0) {
196 flags |= BRIDGE_FLAGS_SELF;
197 } else if (strcmp(*argv, "master") == 0) {
198 flags |= BRIDGE_FLAGS_MASTER;
199 } else if (strcmp(*argv, "pvid") == 0) {
200 vinfo.flags |= BRIDGE_VLAN_INFO_PVID;
201 } else if (strcmp(*argv, "untagged") == 0) {
202 vinfo.flags |= BRIDGE_VLAN_INFO_UNTAGGED;
203 } else if (strcmp(*argv, "tunnel_info") == 0) {
204 if (parse_tunnel_info(&argc, &argv,
205 &tun_id_start,
206 &tun_id_end))
207 return -1;
208 tunnel_info_set = true;
209 } else {
210 if (matches(*argv, "help") == 0)
211 NEXT_ARG();
212 }
213 argc--; argv++;
214 }
215
216 if (d == NULL || vid == -1) {
217 fprintf(stderr, "Device and VLAN ID are required arguments.\n");
218 return -1;
219 }
220
221 req.ifm.ifi_index = ll_name_to_index(d);
222 if (req.ifm.ifi_index == 0) {
223 fprintf(stderr, "Cannot find bridge device \"%s\"\n", d);
224 return -1;
225 }
226
227 if (vid >= 4096) {
228 fprintf(stderr, "Invalid VLAN ID \"%hu\"\n", vid);
229 return -1;
230 }
231
232 if (vinfo.flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
233 if (vid_end == -1 || vid_end >= 4096 || vid >= vid_end) {
234 fprintf(stderr, "Invalid VLAN range \"%hu-%hu\"\n",
235 vid, vid_end);
236 return -1;
237 }
238 if (vinfo.flags & BRIDGE_VLAN_INFO_PVID) {
239 fprintf(stderr,
240 "pvid cannot be configured for a vlan range\n");
241 return -1;
242 }
243 }
244
245 afspec = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC);
246
247 if (flags)
248 addattr16(&req.n, sizeof(req), IFLA_BRIDGE_FLAGS, flags);
249
250 if (tunnel_info_set)
251 add_tunnel_info_range(&req.n, sizeof(req), vid, vid_end,
252 tun_id_start, tun_id_end);
253 else
254 add_vlan_info_range(&req.n, sizeof(req), vid, vid_end,
255 vinfo.flags);
256
257 addattr_nest_end(&req.n, afspec);
258
259 if (rtnl_talk(&rth, &req.n, NULL) < 0)
260 return -1;
261
262 return 0;
263}
264
265static int vlan_option_set(int argc, char **argv)
266{
267 struct {
268 struct nlmsghdr n;
269 struct br_vlan_msg bvm;
270 char buf[1024];
271 } req = {
272 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_vlan_msg)),
273 .n.nlmsg_flags = NLM_F_REQUEST,
274 .n.nlmsg_type = RTM_NEWVLAN,
275 .bvm.family = PF_BRIDGE,
276 };
277 struct bridge_vlan_info vinfo = {};
278 struct rtattr *afspec;
279 char *d = NULL;
280 short vid = -1;
281
282 afspec = addattr_nest(&req.n, sizeof(req), BRIDGE_VLANDB_ENTRY);
283 afspec->rta_type |= NLA_F_NESTED;
284 while (argc > 0) {
285 if (strcmp(*argv, "dev") == 0) {
286 NEXT_ARG();
287 d = *argv;
288 req.bvm.ifindex = ll_name_to_index(d);
289 if (req.bvm.ifindex == 0) {
290 fprintf(stderr,
291 "Cannot find network device \"%s\"\n",
292 d);
293 return -1;
294 }
295 } else if (strcmp(*argv, "vid") == 0) {
296 short vid_end = -1;
297 char *p;
298
299 NEXT_ARG();
300 p = strchr(*argv, '-');
301 if (p) {
302 *p = '\0';
303 p++;
304 vid = atoi(*argv);
305 vid_end = atoi(p);
306 if (vid >= vid_end || vid_end >= 4096) {
307 fprintf(stderr, "Invalid VLAN range \"%hu-%hu\"\n",
308 vid, vid_end);
309 return -1;
310 }
311 } else {
312 vid = atoi(*argv);
313 }
314 if (vid >= 4096) {
315 fprintf(stderr, "Invalid VLAN ID \"%hu\"\n",
316 vid);
317 return -1;
318 }
319
320 vinfo.flags = BRIDGE_VLAN_INFO_ONLY_OPTS;
321 vinfo.vid = vid;
322 addattr_l(&req.n, sizeof(req), BRIDGE_VLANDB_ENTRY_INFO,
323 &vinfo, sizeof(vinfo));
324 if (vid_end != -1)
325 addattr16(&req.n, sizeof(req),
326 BRIDGE_VLANDB_ENTRY_RANGE, vid_end);
327 } else if (strcmp(*argv, "state") == 0) {
328 char *endptr;
329 int state;
330
331 NEXT_ARG();
332 state = strtol(*argv, &endptr, 10);
333 if (!(**argv != '\0' && *endptr == '\0'))
334 state = parse_stp_state(*argv);
335 if (state == -1) {
336 fprintf(stderr, "Error: invalid STP state\n");
337 return -1;
338 }
339 addattr8(&req.n, sizeof(req), BRIDGE_VLANDB_ENTRY_STATE,
340 state);
341 } else if (strcmp(*argv, "mcast_router") == 0) {
342 __u8 mcast_router;
343
344 NEXT_ARG();
345 if (get_u8(&mcast_router, *argv, 0))
346 invarg("invalid mcast_router", *argv);
347 addattr8(&req.n, sizeof(req),
348 BRIDGE_VLANDB_ENTRY_MCAST_ROUTER,
349 mcast_router);
350 } else if (strcmp(*argv, "mcast_max_groups") == 0) {
351 __u32 max_groups;
352
353 NEXT_ARG();
354 if (get_u32(&max_groups, *argv, 0))
355 invarg("invalid mcast_max_groups", *argv);
356 addattr32(&req.n, sizeof(req),
357 BRIDGE_VLANDB_ENTRY_MCAST_MAX_GROUPS,
358 max_groups);
359 } else if (strcmp(*argv, "neigh_suppress") == 0) {
360 bool neigh_suppress;
361 int ret;
362
363 NEXT_ARG();
364 neigh_suppress = parse_on_off("neigh_suppress", *argv,
365 &ret);
366 if (ret)
367 return ret;
368 addattr8(&req.n, sizeof(req),
369 BRIDGE_VLANDB_ENTRY_NEIGH_SUPPRESS,
370 neigh_suppress);
371 } else {
372 if (matches(*argv, "help") == 0)
373 NEXT_ARG();
374 }
375 argc--; argv++;
376 }
377 addattr_nest_end(&req.n, afspec);
378
379 if (d == NULL || vid == -1) {
380 fprintf(stderr, "Device and VLAN ID are required arguments.\n");
381 return -1;
382 }
383
384 if (rtnl_talk(&rth, &req.n, NULL) < 0)
385 return -1;
386
387 return 0;
388}
389
390static int vlan_global_option_set(int argc, char **argv)
391{
392 struct {
393 struct nlmsghdr n;
394 struct br_vlan_msg bvm;
395 char buf[1024];
396 } req = {
397 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_vlan_msg)),
398 .n.nlmsg_flags = NLM_F_REQUEST,
399 .n.nlmsg_type = RTM_NEWVLAN,
400 .bvm.family = PF_BRIDGE,
401 };
402 struct rtattr *afspec;
403 short vid_end = -1;
404 char *d = NULL;
405 short vid = -1;
406 __u64 val64;
407 __u32 val32;
408 __u16 val16;
409 __u8 val8;
410
411 afspec = addattr_nest(&req.n, sizeof(req),
412 BRIDGE_VLANDB_GLOBAL_OPTIONS);
413 afspec->rta_type |= NLA_F_NESTED;
414 while (argc > 0) {
415 if (strcmp(*argv, "dev") == 0) {
416 NEXT_ARG();
417 d = *argv;
418 req.bvm.ifindex = ll_name_to_index(d);
419 if (req.bvm.ifindex == 0) {
420 fprintf(stderr, "Cannot find network device \"%s\"\n",
421 d);
422 return -1;
423 }
424 } else if (strcmp(*argv, "vid") == 0) {
425 char *p;
426
427 NEXT_ARG();
428 p = strchr(*argv, '-');
429 if (p) {
430 *p = '\0';
431 p++;
432 vid = atoi(*argv);
433 vid_end = atoi(p);
434 if (vid >= vid_end || vid_end >= 4096) {
435 fprintf(stderr, "Invalid VLAN range \"%hu-%hu\"\n",
436 vid, vid_end);
437 return -1;
438 }
439 } else {
440 vid = atoi(*argv);
441 }
442 if (vid >= 4096) {
443 fprintf(stderr, "Invalid VLAN ID \"%hu\"\n",
444 vid);
445 return -1;
446 }
447 addattr16(&req.n, sizeof(req), BRIDGE_VLANDB_GOPTS_ID,
448 vid);
449 if (vid_end != -1)
450 addattr16(&req.n, sizeof(req),
451 BRIDGE_VLANDB_GOPTS_RANGE, vid_end);
452 } else if (strcmp(*argv, "mcast_snooping") == 0) {
453 NEXT_ARG();
454 if (get_u8(&val8, *argv, 0))
455 invarg("invalid mcast_snooping", *argv);
456 addattr8(&req.n, 1024,
457 BRIDGE_VLANDB_GOPTS_MCAST_SNOOPING, val8);
458 } else if (strcmp(*argv, "mcast_querier") == 0) {
459 NEXT_ARG();
460 if (get_u8(&val8, *argv, 0))
461 invarg("invalid mcast_querier", *argv);
462 addattr8(&req.n, 1024,
463 BRIDGE_VLANDB_GOPTS_MCAST_QUERIER, val8);
464 } else if (strcmp(*argv, "mcast_igmp_version") == 0) {
465 NEXT_ARG();
466 if (get_u8(&val8, *argv, 0))
467 invarg("invalid mcast_igmp_version", *argv);
468 addattr8(&req.n, 1024,
469 BRIDGE_VLANDB_GOPTS_MCAST_IGMP_VERSION, val8);
470 } else if (strcmp(*argv, "mcast_mld_version") == 0) {
471 NEXT_ARG();
472 if (get_u8(&val8, *argv, 0))
473 invarg("invalid mcast_mld_version", *argv);
474 addattr8(&req.n, 1024,
475 BRIDGE_VLANDB_GOPTS_MCAST_MLD_VERSION, val8);
476 } else if (strcmp(*argv, "mcast_last_member_count") == 0) {
477 NEXT_ARG();
478 if (get_u32(&val32, *argv, 0))
479 invarg("invalid mcast_last_member_count", *argv);
480 addattr32(&req.n, 1024,
481 BRIDGE_VLANDB_GOPTS_MCAST_LAST_MEMBER_CNT,
482 val32);
483 } else if (strcmp(*argv, "mcast_startup_query_count") == 0) {
484 NEXT_ARG();
485 if (get_u32(&val32, *argv, 0))
486 invarg("invalid mcast_startup_query_count",
487 *argv);
488 addattr32(&req.n, 1024,
489 BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_CNT,
490 val32);
491 } else if (strcmp(*argv, "mcast_last_member_interval") == 0) {
492 NEXT_ARG();
493 if (get_u64(&val64, *argv, 0))
494 invarg("invalid mcast_last_member_interval",
495 *argv);
496 addattr64(&req.n, 1024,
497 BRIDGE_VLANDB_GOPTS_MCAST_LAST_MEMBER_INTVL,
498 val64);
499 } else if (strcmp(*argv, "mcast_membership_interval") == 0) {
500 NEXT_ARG();
501 if (get_u64(&val64, *argv, 0))
502 invarg("invalid mcast_membership_interval",
503 *argv);
504 addattr64(&req.n, 1024,
505 BRIDGE_VLANDB_GOPTS_MCAST_MEMBERSHIP_INTVL,
506 val64);
507 } else if (strcmp(*argv, "mcast_querier_interval") == 0) {
508 NEXT_ARG();
509 if (get_u64(&val64, *argv, 0))
510 invarg("invalid mcast_querier_interval",
511 *argv);
512 addattr64(&req.n, 1024,
513 BRIDGE_VLANDB_GOPTS_MCAST_QUERIER_INTVL,
514 val64);
515 } else if (strcmp(*argv, "mcast_query_interval") == 0) {
516 NEXT_ARG();
517 if (get_u64(&val64, *argv, 0))
518 invarg("invalid mcast_query_interval",
519 *argv);
520 addattr64(&req.n, 1024,
521 BRIDGE_VLANDB_GOPTS_MCAST_QUERY_INTVL,
522 val64);
523 } else if (strcmp(*argv, "mcast_query_response_interval") == 0) {
524 NEXT_ARG();
525 if (get_u64(&val64, *argv, 0))
526 invarg("invalid mcast_query_response_interval",
527 *argv);
528 addattr64(&req.n, 1024,
529 BRIDGE_VLANDB_GOPTS_MCAST_QUERY_RESPONSE_INTVL,
530 val64);
531 } else if (strcmp(*argv, "mcast_startup_query_interval") == 0) {
532 NEXT_ARG();
533 if (get_u64(&val64, *argv, 0))
534 invarg("invalid mcast_startup_query_interval",
535 *argv);
536 addattr64(&req.n, 1024,
537 BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_INTVL,
538 val64);
539 } else if (strcmp(*argv, "msti") == 0) {
540 NEXT_ARG();
541 if (get_u16(&val16, *argv, 0))
542 invarg("invalid msti", *argv);
543 addattr16(&req.n, 1024,
544 BRIDGE_VLANDB_GOPTS_MSTI, val16);
545 } else {
546 if (strcmp(*argv, "help") == 0)
547 NEXT_ARG();
548 }
549 argc--; argv++;
550 }
551 addattr_nest_end(&req.n, afspec);
552
553 if (d == NULL || vid == -1) {
554 fprintf(stderr, "Device and VLAN ID are required arguments.\n");
555 return -1;
556 }
557
558 if (rtnl_talk(&rth, &req.n, NULL) < 0)
559 return -1;
560
561 return 0;
562}
563
564
565
566
567
568
569
570
571static int filter_vlan_check(__u16 vid, __u16 flags)
572{
573
574 if (filter_vlan && vid > filter_vlan &&
575 !(flags & BRIDGE_VLAN_INFO_RANGE_END))
576 return -1;
577 if ((flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) ||
578 vid < filter_vlan)
579 return 0;
580
581 return 1;
582}
583
584static void open_vlan_port(int ifi_index, enum vlan_show_subject subject)
585{
586 open_json_object(NULL);
587 print_color_string(PRINT_ANY, COLOR_IFNAME, "ifname",
588 "%-" textify(IFNAMSIZ) "s ",
589 ll_index_to_name(ifi_index));
590 open_json_array(PRINT_JSON,
591 subject == VLAN_SHOW_VLAN ? "vlans": "tunnels");
592}
593
594static void close_vlan_port(void)
595{
596 close_json_array(PRINT_JSON, NULL);
597 close_json_object();
598}
599
600static void print_vlan_tunnel_info(struct rtattr *tb, int ifindex)
601{
602 struct rtattr *i, *list = tb;
603 int rem = RTA_PAYLOAD(list);
604 __u16 last_vid_start = 0;
605 __u32 last_tunid_start = 0;
606 bool opened = false;
607
608 for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
609 struct rtattr *ttb[IFLA_BRIDGE_VLAN_TUNNEL_MAX+1];
610 __u32 tunnel_id = 0;
611 __u16 tunnel_vid = 0;
612 __u16 tunnel_flags = 0;
613 unsigned int width;
614 int vcheck_ret;
615
616 if (i->rta_type != IFLA_BRIDGE_VLAN_TUNNEL_INFO)
617 continue;
618
619 parse_rtattr(ttb, IFLA_BRIDGE_VLAN_TUNNEL_MAX,
620 RTA_DATA(i), RTA_PAYLOAD(i));
621
622 if (ttb[IFLA_BRIDGE_VLAN_TUNNEL_VID])
623 tunnel_vid =
624 rta_getattr_u16(ttb[IFLA_BRIDGE_VLAN_TUNNEL_VID]);
625 else
626 continue;
627
628 if (ttb[IFLA_BRIDGE_VLAN_TUNNEL_ID])
629 tunnel_id =
630 rta_getattr_u32(ttb[IFLA_BRIDGE_VLAN_TUNNEL_ID]);
631
632 if (ttb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS])
633 tunnel_flags =
634 rta_getattr_u16(ttb[IFLA_BRIDGE_VLAN_TUNNEL_FLAGS]);
635
636 if (!(tunnel_flags & BRIDGE_VLAN_INFO_RANGE_END)) {
637 last_vid_start = tunnel_vid;
638 last_tunid_start = tunnel_id;
639 }
640
641 vcheck_ret = filter_vlan_check(tunnel_vid, tunnel_flags);
642 if (vcheck_ret == -1)
643 break;
644 else if (vcheck_ret == 0)
645 continue;
646
647 if (!opened) {
648 open_vlan_port(ifindex, VLAN_SHOW_TUNNELINFO);
649 opened = true;
650 } else {
651 print_string(PRINT_FP, NULL,
652 "%-" textify(IFNAMSIZ) "s ", "");
653 }
654
655 open_json_object(NULL);
656 width = print_range("vlan", last_vid_start, tunnel_vid);
657 if (!is_json_context())
658 printf("%-*s ", VLAN_ID_LEN - width, "");
659 print_range("tunid", last_tunid_start, tunnel_id);
660 close_json_object();
661 print_nl();
662 }
663
664 if (opened)
665 close_vlan_port();
666}
667
668static int print_vlan(struct nlmsghdr *n, void *arg)
669{
670 enum vlan_show_subject *subject = arg;
671 struct ifinfomsg *ifm = NLMSG_DATA(n);
672 int len = n->nlmsg_len;
673 struct rtattr *tb[IFLA_MAX+1];
674
675 if (n->nlmsg_type != RTM_NEWLINK) {
676 fprintf(stderr, "Not RTM_NEWLINK: %08x %08x %08x\n",
677 n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
678 return 0;
679 }
680
681 len -= NLMSG_LENGTH(sizeof(*ifm));
682 if (len < 0) {
683 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
684 return -1;
685 }
686
687 if (ifm->ifi_family != AF_BRIDGE)
688 return 0;
689
690 if (filter_index && filter_index != ifm->ifi_index)
691 return 0;
692
693 parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifm), len);
694 if (!tb[IFLA_AF_SPEC])
695 return 0;
696
697 switch (*subject) {
698 case VLAN_SHOW_VLAN:
699 print_vlan_info(tb[IFLA_AF_SPEC], ifm->ifi_index);
700 break;
701 case VLAN_SHOW_TUNNELINFO:
702 print_vlan_tunnel_info(tb[IFLA_AF_SPEC], ifm->ifi_index);
703 break;
704 }
705
706 return 0;
707}
708
709static void print_vlan_stats_attr(struct rtattr *attr, int ifindex)
710{
711 struct rtattr *brtb[LINK_XSTATS_TYPE_MAX+1];
712 struct rtattr *i, *list;
713 bool found_vlan = false;
714 int rem;
715
716 parse_rtattr(brtb, LINK_XSTATS_TYPE_MAX, RTA_DATA(attr),
717 RTA_PAYLOAD(attr));
718 if (!brtb[LINK_XSTATS_TYPE_BRIDGE])
719 return;
720
721 list = brtb[LINK_XSTATS_TYPE_BRIDGE];
722 rem = RTA_PAYLOAD(list);
723
724 for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
725 const struct bridge_vlan_xstats *vstats = RTA_DATA(i);
726
727 if (i->rta_type != BRIDGE_XSTATS_VLAN)
728 continue;
729
730 if (filter_vlan && filter_vlan != vstats->vid)
731 continue;
732
733
734 if ((vstats->flags & BRIDGE_VLAN_INFO_MASTER) &&
735 !(vstats->flags & BRIDGE_VLAN_INFO_BRENTRY))
736 continue;
737
738
739 if (!found_vlan) {
740 open_vlan_port(ifindex, VLAN_SHOW_VLAN);
741 found_vlan = true;
742 } else {
743 print_string(PRINT_FP, NULL,
744 "%-" textify(IFNAMSIZ) "s ", "");
745 }
746 bridge_print_vlan_stats(vstats);
747 }
748
749
750 if (found_vlan)
751 close_vlan_port();
752}
753
754static int print_vlan_stats(struct nlmsghdr *n, void *arg)
755{
756 struct if_stats_msg *ifsm = NLMSG_DATA(n);
757 struct rtattr *tb[IFLA_STATS_MAX+1];
758 int len = n->nlmsg_len;
759 FILE *fp = arg;
760
761 len -= NLMSG_LENGTH(sizeof(*ifsm));
762 if (len < 0) {
763 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
764 return -1;
765 }
766
767 if (filter_index && filter_index != ifsm->ifindex)
768 return 0;
769
770 parse_rtattr(tb, IFLA_STATS_MAX, IFLA_STATS_RTA(ifsm), len);
771
772
773 if (tb[IFLA_STATS_LINK_XSTATS])
774 print_vlan_stats_attr(tb[IFLA_STATS_LINK_XSTATS],
775 ifsm->ifindex);
776
777 if (tb[IFLA_STATS_LINK_XSTATS_SLAVE])
778 print_vlan_stats_attr(tb[IFLA_STATS_LINK_XSTATS_SLAVE],
779 ifsm->ifindex);
780
781 fflush(fp);
782 return 0;
783}
784
785static void print_vlan_router_ports(struct rtattr *rattr)
786{
787 int rem = RTA_PAYLOAD(rattr);
788 struct rtattr *i;
789
790 print_string(PRINT_FP, NULL, "%-" textify(IFNAMSIZ) "s ", "");
791 open_json_array(PRINT_ANY, is_json_context() ? "router_ports" :
792 "router ports: ");
793 for (i = RTA_DATA(rattr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
794 uint32_t *port_ifindex = RTA_DATA(i);
795 const char *port_ifname = ll_index_to_name(*port_ifindex);
796
797 open_json_object(NULL);
798 if (show_stats && i != RTA_DATA(rattr)) {
799 print_nl();
800
801 print_string(PRINT_FP, NULL,
802 "%-" textify(IFNAMSIZ) "s "
803 " ",
804 "");
805 }
806 print_string(PRINT_ANY, "port", "%s ", port_ifname);
807 if (show_stats)
808 br_print_router_port_stats(i);
809 close_json_object();
810 }
811 close_json_array(PRINT_JSON, NULL);
812 print_nl();
813}
814
815static void print_vlan_global_opts(struct rtattr *a, int ifindex)
816{
817 struct rtattr *vtb[BRIDGE_VLANDB_GOPTS_MAX + 1], *vattr;
818 __u16 vid, vrange = 0;
819
820 if (rta_type(a) != BRIDGE_VLANDB_GLOBAL_OPTIONS)
821 return;
822
823 parse_rtattr_flags(vtb, BRIDGE_VLANDB_GOPTS_MAX, RTA_DATA(a),
824 RTA_PAYLOAD(a), NLA_F_NESTED);
825 vid = rta_getattr_u16(vtb[BRIDGE_VLANDB_GOPTS_ID]);
826 if (vtb[BRIDGE_VLANDB_GOPTS_RANGE])
827 vrange = rta_getattr_u16(vtb[BRIDGE_VLANDB_GOPTS_RANGE]);
828 else
829 vrange = vid;
830
831 if (filter_vlan && (filter_vlan < vid || filter_vlan > vrange))
832 return;
833
834 if (vlan_rtm_cur_ifidx != ifindex) {
835 open_vlan_port(ifindex, VLAN_SHOW_VLAN);
836 open_json_object(NULL);
837 vlan_rtm_cur_ifidx = ifindex;
838 } else {
839 open_json_object(NULL);
840 print_string(PRINT_FP, NULL, "%-" textify(IFNAMSIZ) "s ", "");
841 }
842 print_range("vlan", vid, vrange);
843 print_nl();
844 print_string(PRINT_FP, NULL, "%-" textify(IFNAMSIZ) "s ", "");
845 if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_SNOOPING]) {
846 vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_SNOOPING];
847 print_uint(PRINT_ANY, "mcast_snooping", "mcast_snooping %u ",
848 rta_getattr_u8(vattr));
849 }
850 if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_QUERIER]) {
851 vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_QUERIER];
852 print_uint(PRINT_ANY, "mcast_querier", "mcast_querier %u ",
853 rta_getattr_u8(vattr));
854 }
855 if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_QUERIER_STATE]) {
856 struct rtattr *attr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_QUERIER_STATE];
857
858 bridge_print_mcast_querier_state(attr);
859 }
860 if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_IGMP_VERSION]) {
861 vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_IGMP_VERSION];
862 print_uint(PRINT_ANY, "mcast_igmp_version",
863 "mcast_igmp_version %u ", rta_getattr_u8(vattr));
864 }
865 if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_MLD_VERSION]) {
866 vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_MLD_VERSION];
867 print_uint(PRINT_ANY, "mcast_mld_version",
868 "mcast_mld_version %u ", rta_getattr_u8(vattr));
869 }
870 if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_MLD_VERSION]) {
871 vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_LAST_MEMBER_CNT];
872 print_uint(PRINT_ANY, "mcast_last_member_count",
873 "mcast_last_member_count %u ",
874 rta_getattr_u32(vattr));
875 }
876 if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_LAST_MEMBER_INTVL]) {
877 vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_LAST_MEMBER_INTVL];
878 print_lluint(PRINT_ANY, "mcast_last_member_interval",
879 "mcast_last_member_interval %llu ",
880 rta_getattr_u64(vattr));
881 }
882 if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_CNT]) {
883 vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_CNT];
884 print_uint(PRINT_ANY, "mcast_startup_query_count",
885 "mcast_startup_query_count %u ",
886 rta_getattr_u32(vattr));
887 }
888 if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_INTVL]) {
889 vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_STARTUP_QUERY_INTVL];
890 print_lluint(PRINT_ANY, "mcast_startup_query_interval",
891 "mcast_startup_query_interval %llu ",
892 rta_getattr_u64(vattr));
893 }
894 if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_MEMBERSHIP_INTVL]) {
895 vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_MEMBERSHIP_INTVL];
896 print_lluint(PRINT_ANY, "mcast_membership_interval",
897 "mcast_membership_interval %llu ",
898 rta_getattr_u64(vattr));
899 }
900 if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_QUERIER_INTVL]) {
901 vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_QUERIER_INTVL];
902 print_lluint(PRINT_ANY, "mcast_querier_interval",
903 "mcast_querier_interval %llu ",
904 rta_getattr_u64(vattr));
905 }
906 if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_QUERY_INTVL]) {
907 vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_QUERY_INTVL];
908 print_lluint(PRINT_ANY, "mcast_query_interval",
909 "mcast_query_interval %llu ",
910 rta_getattr_u64(vattr));
911 }
912 if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_QUERY_RESPONSE_INTVL]) {
913 vattr = vtb[BRIDGE_VLANDB_GOPTS_MCAST_QUERY_RESPONSE_INTVL];
914 print_lluint(PRINT_ANY, "mcast_query_response_interval",
915 "mcast_query_response_interval %llu ",
916 rta_getattr_u64(vattr));
917 }
918 if (vtb[BRIDGE_VLANDB_GOPTS_MSTI]) {
919 vattr = vtb[BRIDGE_VLANDB_GOPTS_MSTI];
920 print_uint(PRINT_ANY, "msti", "msti %u ",
921 rta_getattr_u16(vattr));
922 }
923 print_nl();
924 if (vtb[BRIDGE_VLANDB_GOPTS_MCAST_ROUTER_PORTS]) {
925 vattr = RTA_DATA(vtb[BRIDGE_VLANDB_GOPTS_MCAST_ROUTER_PORTS]);
926 print_vlan_router_ports(vattr);
927 }
928 close_json_object();
929}
930
931static void print_vlan_opts(struct rtattr *a, int ifindex)
932{
933 struct rtattr *vtb[BRIDGE_VLANDB_ENTRY_MAX + 1], *vattr;
934 struct bridge_vlan_xstats vstats;
935 struct bridge_vlan_info *vinfo;
936 __u16 vrange = 0;
937 __u8 state = 0;
938
939 if (rta_type(a) != BRIDGE_VLANDB_ENTRY)
940 return;
941
942 parse_rtattr_flags(vtb, BRIDGE_VLANDB_ENTRY_MAX, RTA_DATA(a),
943 RTA_PAYLOAD(a), NLA_F_NESTED);
944 vinfo = RTA_DATA(vtb[BRIDGE_VLANDB_ENTRY_INFO]);
945
946 memset(&vstats, 0, sizeof(vstats));
947 if (vtb[BRIDGE_VLANDB_ENTRY_RANGE])
948 vrange = rta_getattr_u16(vtb[BRIDGE_VLANDB_ENTRY_RANGE]);
949 else
950 vrange = vinfo->vid;
951
952 if (filter_vlan && (filter_vlan < vinfo->vid || filter_vlan > vrange))
953 return;
954
955 if (vtb[BRIDGE_VLANDB_ENTRY_STATE])
956 state = rta_getattr_u8(vtb[BRIDGE_VLANDB_ENTRY_STATE]);
957
958 if (vtb[BRIDGE_VLANDB_ENTRY_STATS]) {
959 struct rtattr *stb[BRIDGE_VLANDB_STATS_MAX+1];
960 struct rtattr *attr;
961
962 attr = vtb[BRIDGE_VLANDB_ENTRY_STATS];
963 parse_rtattr(stb, BRIDGE_VLANDB_STATS_MAX, RTA_DATA(attr),
964 RTA_PAYLOAD(attr));
965
966 if (stb[BRIDGE_VLANDB_STATS_RX_BYTES]) {
967 attr = stb[BRIDGE_VLANDB_STATS_RX_BYTES];
968 vstats.rx_bytes = rta_getattr_u64(attr);
969 }
970 if (stb[BRIDGE_VLANDB_STATS_RX_PACKETS]) {
971 attr = stb[BRIDGE_VLANDB_STATS_RX_PACKETS];
972 vstats.rx_packets = rta_getattr_u64(attr);
973 }
974 if (stb[BRIDGE_VLANDB_STATS_TX_PACKETS]) {
975 attr = stb[BRIDGE_VLANDB_STATS_TX_PACKETS];
976 vstats.tx_packets = rta_getattr_u64(attr);
977 }
978 if (stb[BRIDGE_VLANDB_STATS_TX_BYTES]) {
979 attr = stb[BRIDGE_VLANDB_STATS_TX_BYTES];
980 vstats.tx_bytes = rta_getattr_u64(attr);
981 }
982 }
983
984 if (vlan_rtm_cur_ifidx != ifindex) {
985 open_vlan_port(ifindex, VLAN_SHOW_VLAN);
986 open_json_object(NULL);
987 vlan_rtm_cur_ifidx = ifindex;
988 } else {
989 open_json_object(NULL);
990 print_string(PRINT_FP, NULL, "%-" textify(IFNAMSIZ) "s ", "");
991 }
992 print_range("vlan", vinfo->vid, vrange);
993 bridge_print_vlan_flags(vinfo->flags);
994 print_nl();
995 print_string(PRINT_FP, NULL, "%-" textify(IFNAMSIZ) "s ", "");
996 print_stp_state(state);
997 if (vtb[BRIDGE_VLANDB_ENTRY_MCAST_ROUTER]) {
998 vattr = vtb[BRIDGE_VLANDB_ENTRY_MCAST_ROUTER];
999 print_uint(PRINT_ANY, "mcast_router", "mcast_router %u ",
1000 rta_getattr_u8(vattr));
1001 }
1002 if (vtb[BRIDGE_VLANDB_ENTRY_MCAST_N_GROUPS]) {
1003 vattr = vtb[BRIDGE_VLANDB_ENTRY_MCAST_N_GROUPS];
1004 print_uint(PRINT_ANY, "mcast_n_groups", "mcast_n_groups %u ",
1005 rta_getattr_u32(vattr));
1006 }
1007 if (vtb[BRIDGE_VLANDB_ENTRY_MCAST_MAX_GROUPS]) {
1008 vattr = vtb[BRIDGE_VLANDB_ENTRY_MCAST_MAX_GROUPS];
1009 print_uint(PRINT_ANY, "mcast_max_groups", "mcast_max_groups %u ",
1010 rta_getattr_u32(vattr));
1011 }
1012 if (vtb[BRIDGE_VLANDB_ENTRY_NEIGH_SUPPRESS]) {
1013 vattr = vtb[BRIDGE_VLANDB_ENTRY_NEIGH_SUPPRESS];
1014 print_on_off(PRINT_ANY, "neigh_suppress", "neigh_suppress %s ",
1015 rta_getattr_u8(vattr));
1016 }
1017 print_nl();
1018 if (show_stats)
1019 bridge_print_vlan_stats_only(&vstats);
1020 close_json_object();
1021}
1022
1023int print_vlan_rtm(struct nlmsghdr *n, void *arg, bool monitor, bool global_only)
1024{
1025 struct br_vlan_msg *bvm = NLMSG_DATA(n);
1026 int len = n->nlmsg_len;
1027 struct rtattr *a;
1028 FILE *fp = arg;
1029 int rem;
1030
1031 if (n->nlmsg_type != RTM_NEWVLAN && n->nlmsg_type != RTM_DELVLAN &&
1032 n->nlmsg_type != RTM_GETVLAN) {
1033 fprintf(stderr, "Unknown vlan rtm message: %08x %08x %08x\n",
1034 n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
1035 return 0;
1036 }
1037
1038 len -= NLMSG_LENGTH(sizeof(*bvm));
1039 if (len < 0) {
1040 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
1041 return -1;
1042 }
1043
1044 if (bvm->family != AF_BRIDGE)
1045 return 0;
1046
1047 if (filter_index && filter_index != bvm->ifindex)
1048 return 0;
1049
1050 print_headers(fp, "[VLAN]");
1051
1052 if (n->nlmsg_type == RTM_DELVLAN)
1053 print_bool(PRINT_ANY, "deleted", "Deleted ", true);
1054
1055 if (monitor)
1056 vlan_rtm_cur_ifidx = -1;
1057
1058 if (vlan_rtm_cur_ifidx != -1 && vlan_rtm_cur_ifidx != bvm->ifindex) {
1059 close_vlan_port();
1060 vlan_rtm_cur_ifidx = -1;
1061 }
1062
1063 rem = len;
1064 for (a = BRVLAN_RTA(bvm); RTA_OK(a, rem); a = RTA_NEXT(a, rem)) {
1065 unsigned short attr_type = rta_type(a);
1066
1067
1068 if (attr_type > BRIDGE_VLANDB_MAX ||
1069 (global_only && attr_type != BRIDGE_VLANDB_GLOBAL_OPTIONS))
1070 continue;
1071
1072 switch (attr_type) {
1073 case BRIDGE_VLANDB_ENTRY:
1074 print_vlan_opts(a, bvm->ifindex);
1075 break;
1076 case BRIDGE_VLANDB_GLOBAL_OPTIONS:
1077 print_vlan_global_opts(a, bvm->ifindex);
1078 break;
1079 }
1080 }
1081
1082 return 0;
1083}
1084
1085static int print_vlan_rtm_filter(struct nlmsghdr *n, void *arg)
1086{
1087 return print_vlan_rtm(n, arg, false, false);
1088}
1089
1090static int print_vlan_rtm_global_filter(struct nlmsghdr *n, void *arg)
1091{
1092 return print_vlan_rtm(n, arg, false, true);
1093}
1094
1095static int vlan_show(int argc, char **argv, int subject)
1096{
1097 char *filter_dev = NULL;
1098 int ret = 0;
1099
1100 while (argc > 0) {
1101 if (strcmp(*argv, "dev") == 0) {
1102 NEXT_ARG();
1103 if (filter_dev)
1104 duparg("dev", *argv);
1105 filter_dev = *argv;
1106 } else if (strcmp(*argv, "vid") == 0) {
1107 NEXT_ARG();
1108 if (filter_vlan)
1109 duparg("vid", *argv);
1110 filter_vlan = atoi(*argv);
1111 }
1112 argc--; argv++;
1113 }
1114
1115 if (filter_dev) {
1116 filter_index = ll_name_to_index(filter_dev);
1117 if (!filter_index)
1118 return nodev(filter_dev);
1119 }
1120
1121 new_json_obj(json);
1122
1123
1124 if (show_details && subject == VLAN_SHOW_VLAN) {
1125 __u32 dump_flags = show_stats ? BRIDGE_VLANDB_DUMPF_STATS : 0;
1126
1127 if (rtnl_brvlandump_req(&rth, PF_BRIDGE, dump_flags) < 0) {
1128 perror("Cannot send dump request");
1129 exit(1);
1130 }
1131
1132 if (!is_json_context()) {
1133 printf("%-" textify(IFNAMSIZ) "s %-"
1134 textify(VLAN_ID_LEN) "s", "port",
1135 "vlan-id");
1136 printf("\n");
1137 }
1138
1139 ret = rtnl_dump_filter(&rth, print_vlan_rtm_filter, &subject);
1140 if (ret < 0) {
1141 fprintf(stderr, "Dump terminated\n");
1142 exit(1);
1143 }
1144
1145 if (vlan_rtm_cur_ifidx != -1)
1146 close_vlan_port();
1147
1148 goto out;
1149 }
1150
1151 if (!show_stats) {
1152 if (rtnl_linkdump_req_filter(&rth, PF_BRIDGE,
1153 (compress_vlans ?
1154 RTEXT_FILTER_BRVLAN_COMPRESSED :
1155 RTEXT_FILTER_BRVLAN)) < 0) {
1156 perror("Cannot send dump request");
1157 exit(1);
1158 }
1159
1160 if (!is_json_context()) {
1161 printf("%-" textify(IFNAMSIZ) "s %-"
1162 textify(VLAN_ID_LEN) "s", "port",
1163 "vlan-id");
1164 if (subject == VLAN_SHOW_TUNNELINFO)
1165 printf(" tunnel-id");
1166 printf("\n");
1167 }
1168
1169 ret = rtnl_dump_filter(&rth, print_vlan, &subject);
1170 if (ret < 0) {
1171 fprintf(stderr, "Dump terminated\n");
1172 exit(1);
1173 }
1174 } else {
1175 __u32 filt_mask;
1176
1177 filt_mask = IFLA_STATS_FILTER_BIT(IFLA_STATS_LINK_XSTATS);
1178 if (rtnl_statsdump_req_filter(&rth, AF_UNSPEC, filt_mask,
1179 NULL, NULL) < 0) {
1180 perror("Cannot send dump request");
1181 exit(1);
1182 }
1183
1184 if (!is_json_context())
1185 printf("%-" textify(IFNAMSIZ) "s vlan-id\n",
1186 "port");
1187
1188 if (rtnl_dump_filter(&rth, print_vlan_stats, stdout) < 0) {
1189 fprintf(stderr, "Dump terminated\n");
1190 exit(1);
1191 }
1192
1193 filt_mask = IFLA_STATS_FILTER_BIT(IFLA_STATS_LINK_XSTATS_SLAVE);
1194 if (rtnl_statsdump_req_filter(&rth, AF_UNSPEC, filt_mask,
1195 NULL, NULL) < 0) {
1196 perror("Cannot send slave dump request");
1197 exit(1);
1198 }
1199
1200 if (rtnl_dump_filter(&rth, print_vlan_stats, stdout) < 0) {
1201 fprintf(stderr, "Dump terminated\n");
1202 exit(1);
1203 }
1204 }
1205
1206out:
1207 delete_json_obj();
1208 fflush(stdout);
1209 return 0;
1210}
1211
1212static int vlan_global_show(int argc, char **argv)
1213{
1214 __u32 dump_flags = BRIDGE_VLANDB_DUMPF_GLOBAL;
1215 int ret = 0, subject = VLAN_SHOW_VLAN;
1216 char *filter_dev = NULL;
1217
1218 while (argc > 0) {
1219 if (strcmp(*argv, "dev") == 0) {
1220 NEXT_ARG();
1221 if (filter_dev)
1222 duparg("dev", *argv);
1223 filter_dev = *argv;
1224 } else if (strcmp(*argv, "vid") == 0) {
1225 NEXT_ARG();
1226 if (filter_vlan)
1227 duparg("vid", *argv);
1228 filter_vlan = atoi(*argv);
1229 }
1230 argc--; argv++;
1231 }
1232
1233 if (filter_dev) {
1234 filter_index = ll_name_to_index(filter_dev);
1235 if (!filter_index)
1236 return nodev(filter_dev);
1237 }
1238
1239 new_json_obj(json);
1240
1241 if (rtnl_brvlandump_req(&rth, PF_BRIDGE, dump_flags) < 0) {
1242 perror("Cannot send dump request");
1243 exit(1);
1244 }
1245
1246 if (!is_json_context()) {
1247 printf("%-" textify(IFNAMSIZ) "s %-"
1248 textify(VLAN_ID_LEN) "s", "port",
1249 "vlan-id");
1250 printf("\n");
1251 }
1252
1253 ret = rtnl_dump_filter(&rth, print_vlan_rtm_global_filter, &subject);
1254 if (ret < 0) {
1255 fprintf(stderr, "Dump terminated\n");
1256 exit(1);
1257 }
1258
1259 if (vlan_rtm_cur_ifidx != -1)
1260 close_vlan_port();
1261
1262 delete_json_obj();
1263 fflush(stdout);
1264 return 0;
1265}
1266
1267static void print_vlan_info(struct rtattr *tb, int ifindex)
1268{
1269 struct rtattr *i, *list = tb;
1270 int rem = RTA_PAYLOAD(list);
1271 __u16 last_vid_start = 0;
1272 bool opened = false;
1273
1274 for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
1275 struct bridge_vlan_info *vinfo;
1276 int vcheck_ret;
1277
1278 if (i->rta_type != IFLA_BRIDGE_VLAN_INFO)
1279 continue;
1280
1281 vinfo = RTA_DATA(i);
1282
1283 if (!(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END))
1284 last_vid_start = vinfo->vid;
1285 vcheck_ret = filter_vlan_check(vinfo->vid, vinfo->flags);
1286 if (vcheck_ret == -1)
1287 break;
1288 else if (vcheck_ret == 0)
1289 continue;
1290
1291 if (!opened) {
1292 open_vlan_port(ifindex, VLAN_SHOW_VLAN);
1293 opened = true;
1294 } else {
1295 print_string(PRINT_FP, NULL, "%-"
1296 textify(IFNAMSIZ) "s ", "");
1297 }
1298
1299 open_json_object(NULL);
1300 print_range("vlan", last_vid_start, vinfo->vid);
1301
1302 bridge_print_vlan_flags(vinfo->flags);
1303 close_json_object();
1304 print_nl();
1305 }
1306
1307 if (opened)
1308 close_vlan_port();
1309}
1310
1311static int vlan_global(int argc, char **argv)
1312{
1313 if (argc > 0) {
1314 if (strcmp(*argv, "show") == 0 ||
1315 strcmp(*argv, "lst") == 0 ||
1316 strcmp(*argv, "list") == 0)
1317 return vlan_global_show(argc-1, argv+1);
1318 else if (strcmp(*argv, "set") == 0)
1319 return vlan_global_option_set(argc-1, argv+1);
1320 else
1321 usage();
1322 } else {
1323 return vlan_global_show(0, NULL);
1324 }
1325
1326 return 0;
1327}
1328
1329int do_vlan(int argc, char **argv)
1330{
1331 ll_init_map(&rth);
1332 timestamp = 0;
1333
1334 if (argc > 0) {
1335 if (matches(*argv, "add") == 0)
1336 return vlan_modify(RTM_SETLINK, argc-1, argv+1);
1337 if (matches(*argv, "delete") == 0)
1338 return vlan_modify(RTM_DELLINK, argc-1, argv+1);
1339 if (matches(*argv, "show") == 0 ||
1340 matches(*argv, "lst") == 0 ||
1341 matches(*argv, "list") == 0)
1342 return vlan_show(argc-1, argv+1, VLAN_SHOW_VLAN);
1343 if (matches(*argv, "tunnelshow") == 0) {
1344 return vlan_show(argc-1, argv+1, VLAN_SHOW_TUNNELINFO);
1345 }
1346 if (matches(*argv, "set") == 0)
1347 return vlan_option_set(argc-1, argv+1);
1348 if (strcmp(*argv, "global") == 0)
1349 return vlan_global(argc-1, argv+1);
1350 if (matches(*argv, "help") == 0)
1351 usage();
1352 } else {
1353 return vlan_show(0, NULL, VLAN_SHOW_VLAN);
1354 }
1355
1356 fprintf(stderr, "Command \"%s\" is unknown, try \"bridge vlan help\".\n", *argv);
1357 exit(-1);
1358}
1359