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