xref: /aosp_15_r20/external/iproute2/bridge/vlan.c (revision de1e4e894b0c224df933550f0afdecc354b238c4)
1*de1e4e89SAndroid Build Coastguard Worker #include <stdio.h>
2*de1e4e89SAndroid Build Coastguard Worker #include <stdlib.h>
3*de1e4e89SAndroid Build Coastguard Worker #include <unistd.h>
4*de1e4e89SAndroid Build Coastguard Worker #include <fcntl.h>
5*de1e4e89SAndroid Build Coastguard Worker #include <sys/socket.h>
6*de1e4e89SAndroid Build Coastguard Worker #include <net/if.h>
7*de1e4e89SAndroid Build Coastguard Worker #include <netinet/in.h>
8*de1e4e89SAndroid Build Coastguard Worker #include <linux/if_bridge.h>
9*de1e4e89SAndroid Build Coastguard Worker #include <linux/if_ether.h>
10*de1e4e89SAndroid Build Coastguard Worker #include <json_writer.h>
11*de1e4e89SAndroid Build Coastguard Worker #include <string.h>
12*de1e4e89SAndroid Build Coastguard Worker 
13*de1e4e89SAndroid Build Coastguard Worker #include "libnetlink.h"
14*de1e4e89SAndroid Build Coastguard Worker #include "br_common.h"
15*de1e4e89SAndroid Build Coastguard Worker #include "utils.h"
16*de1e4e89SAndroid Build Coastguard Worker 
17*de1e4e89SAndroid Build Coastguard Worker static unsigned int filter_index, filter_vlan;
18*de1e4e89SAndroid Build Coastguard Worker static int last_ifidx = -1;
19*de1e4e89SAndroid Build Coastguard Worker 
20*de1e4e89SAndroid Build Coastguard Worker json_writer_t *jw_global;
21*de1e4e89SAndroid Build Coastguard Worker 
usage(void)22*de1e4e89SAndroid Build Coastguard Worker static void usage(void)
23*de1e4e89SAndroid Build Coastguard Worker {
24*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr,
25*de1e4e89SAndroid Build Coastguard Worker 		"Usage: bridge vlan { add | del } vid VLAN_ID dev DEV [ pvid ] [ untagged ]\n"
26*de1e4e89SAndroid Build Coastguard Worker 		"                                                     [ self ] [ master ]\n"
27*de1e4e89SAndroid Build Coastguard Worker 		"       bridge vlan { show } [ dev DEV ] [ vid VLAN_ID ]\n");
28*de1e4e89SAndroid Build Coastguard Worker 	exit(-1);
29*de1e4e89SAndroid Build Coastguard Worker }
30*de1e4e89SAndroid Build Coastguard Worker 
vlan_modify(int cmd,int argc,char ** argv)31*de1e4e89SAndroid Build Coastguard Worker static int vlan_modify(int cmd, int argc, char **argv)
32*de1e4e89SAndroid Build Coastguard Worker {
33*de1e4e89SAndroid Build Coastguard Worker 	struct {
34*de1e4e89SAndroid Build Coastguard Worker 		struct nlmsghdr	n;
35*de1e4e89SAndroid Build Coastguard Worker 		struct ifinfomsg	ifm;
36*de1e4e89SAndroid Build Coastguard Worker 		char			buf[1024];
37*de1e4e89SAndroid Build Coastguard Worker 	} req = {
38*de1e4e89SAndroid Build Coastguard Worker 		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
39*de1e4e89SAndroid Build Coastguard Worker 		.n.nlmsg_flags = NLM_F_REQUEST,
40*de1e4e89SAndroid Build Coastguard Worker 		.n.nlmsg_type = cmd,
41*de1e4e89SAndroid Build Coastguard Worker 		.ifm.ifi_family = PF_BRIDGE,
42*de1e4e89SAndroid Build Coastguard Worker 	};
43*de1e4e89SAndroid Build Coastguard Worker 	char *d = NULL;
44*de1e4e89SAndroid Build Coastguard Worker 	short vid = -1;
45*de1e4e89SAndroid Build Coastguard Worker 	short vid_end = -1;
46*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *afspec;
47*de1e4e89SAndroid Build Coastguard Worker 	struct bridge_vlan_info vinfo = {};
48*de1e4e89SAndroid Build Coastguard Worker 	unsigned short flags = 0;
49*de1e4e89SAndroid Build Coastguard Worker 
50*de1e4e89SAndroid Build Coastguard Worker 	while (argc > 0) {
51*de1e4e89SAndroid Build Coastguard Worker 		if (strcmp(*argv, "dev") == 0) {
52*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
53*de1e4e89SAndroid Build Coastguard Worker 			d = *argv;
54*de1e4e89SAndroid Build Coastguard Worker 		} else if (strcmp(*argv, "vid") == 0) {
55*de1e4e89SAndroid Build Coastguard Worker 			char *p;
56*de1e4e89SAndroid Build Coastguard Worker 
57*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
58*de1e4e89SAndroid Build Coastguard Worker 			p = strchr(*argv, '-');
59*de1e4e89SAndroid Build Coastguard Worker 			if (p) {
60*de1e4e89SAndroid Build Coastguard Worker 				*p = '\0';
61*de1e4e89SAndroid Build Coastguard Worker 				p++;
62*de1e4e89SAndroid Build Coastguard Worker 				vid = atoi(*argv);
63*de1e4e89SAndroid Build Coastguard Worker 				vid_end = atoi(p);
64*de1e4e89SAndroid Build Coastguard Worker 				vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_BEGIN;
65*de1e4e89SAndroid Build Coastguard Worker 			} else {
66*de1e4e89SAndroid Build Coastguard Worker 				vid = atoi(*argv);
67*de1e4e89SAndroid Build Coastguard Worker 			}
68*de1e4e89SAndroid Build Coastguard Worker 		} else if (strcmp(*argv, "self") == 0) {
69*de1e4e89SAndroid Build Coastguard Worker 			flags |= BRIDGE_FLAGS_SELF;
70*de1e4e89SAndroid Build Coastguard Worker 		} else if (strcmp(*argv, "master") == 0) {
71*de1e4e89SAndroid Build Coastguard Worker 			flags |= BRIDGE_FLAGS_MASTER;
72*de1e4e89SAndroid Build Coastguard Worker 		} else if (strcmp(*argv, "pvid") == 0) {
73*de1e4e89SAndroid Build Coastguard Worker 			vinfo.flags |= BRIDGE_VLAN_INFO_PVID;
74*de1e4e89SAndroid Build Coastguard Worker 		} else if (strcmp(*argv, "untagged") == 0) {
75*de1e4e89SAndroid Build Coastguard Worker 			vinfo.flags |= BRIDGE_VLAN_INFO_UNTAGGED;
76*de1e4e89SAndroid Build Coastguard Worker 		} else {
77*de1e4e89SAndroid Build Coastguard Worker 			if (matches(*argv, "help") == 0)
78*de1e4e89SAndroid Build Coastguard Worker 				NEXT_ARG();
79*de1e4e89SAndroid Build Coastguard Worker 		}
80*de1e4e89SAndroid Build Coastguard Worker 		argc--; argv++;
81*de1e4e89SAndroid Build Coastguard Worker 	}
82*de1e4e89SAndroid Build Coastguard Worker 
83*de1e4e89SAndroid Build Coastguard Worker 	if (d == NULL || vid == -1) {
84*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Device and VLAN ID are required arguments.\n");
85*de1e4e89SAndroid Build Coastguard Worker 		return -1;
86*de1e4e89SAndroid Build Coastguard Worker 	}
87*de1e4e89SAndroid Build Coastguard Worker 
88*de1e4e89SAndroid Build Coastguard Worker 	req.ifm.ifi_index = ll_name_to_index(d);
89*de1e4e89SAndroid Build Coastguard Worker 	if (req.ifm.ifi_index == 0) {
90*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Cannot find bridge device \"%s\"\n", d);
91*de1e4e89SAndroid Build Coastguard Worker 		return -1;
92*de1e4e89SAndroid Build Coastguard Worker 	}
93*de1e4e89SAndroid Build Coastguard Worker 
94*de1e4e89SAndroid Build Coastguard Worker 	if (vid >= 4096) {
95*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Invalid VLAN ID \"%hu\"\n", vid);
96*de1e4e89SAndroid Build Coastguard Worker 		return -1;
97*de1e4e89SAndroid Build Coastguard Worker 	}
98*de1e4e89SAndroid Build Coastguard Worker 
99*de1e4e89SAndroid Build Coastguard Worker 	if (vinfo.flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
100*de1e4e89SAndroid Build Coastguard Worker 		if (vid_end == -1 || vid_end >= 4096 || vid >= vid_end) {
101*de1e4e89SAndroid Build Coastguard Worker 			fprintf(stderr, "Invalid VLAN range \"%hu-%hu\"\n",
102*de1e4e89SAndroid Build Coastguard Worker 				vid, vid_end);
103*de1e4e89SAndroid Build Coastguard Worker 			return -1;
104*de1e4e89SAndroid Build Coastguard Worker 		}
105*de1e4e89SAndroid Build Coastguard Worker 		if (vinfo.flags & BRIDGE_VLAN_INFO_PVID) {
106*de1e4e89SAndroid Build Coastguard Worker 			fprintf(stderr,
107*de1e4e89SAndroid Build Coastguard Worker 				"pvid cannot be configured for a vlan range\n");
108*de1e4e89SAndroid Build Coastguard Worker 			return -1;
109*de1e4e89SAndroid Build Coastguard Worker 		}
110*de1e4e89SAndroid Build Coastguard Worker 	}
111*de1e4e89SAndroid Build Coastguard Worker 
112*de1e4e89SAndroid Build Coastguard Worker 	afspec = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC);
113*de1e4e89SAndroid Build Coastguard Worker 
114*de1e4e89SAndroid Build Coastguard Worker 	if (flags)
115*de1e4e89SAndroid Build Coastguard Worker 		addattr16(&req.n, sizeof(req), IFLA_BRIDGE_FLAGS, flags);
116*de1e4e89SAndroid Build Coastguard Worker 
117*de1e4e89SAndroid Build Coastguard Worker 	vinfo.vid = vid;
118*de1e4e89SAndroid Build Coastguard Worker 	if (vid_end != -1) {
119*de1e4e89SAndroid Build Coastguard Worker 		/* send vlan range start */
120*de1e4e89SAndroid Build Coastguard Worker 		addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo,
121*de1e4e89SAndroid Build Coastguard Worker 			  sizeof(vinfo));
122*de1e4e89SAndroid Build Coastguard Worker 		vinfo.flags &= ~BRIDGE_VLAN_INFO_RANGE_BEGIN;
123*de1e4e89SAndroid Build Coastguard Worker 
124*de1e4e89SAndroid Build Coastguard Worker 		/* Now send the vlan range end */
125*de1e4e89SAndroid Build Coastguard Worker 		vinfo.flags |= BRIDGE_VLAN_INFO_RANGE_END;
126*de1e4e89SAndroid Build Coastguard Worker 		vinfo.vid = vid_end;
127*de1e4e89SAndroid Build Coastguard Worker 		addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo,
128*de1e4e89SAndroid Build Coastguard Worker 			  sizeof(vinfo));
129*de1e4e89SAndroid Build Coastguard Worker 	} else {
130*de1e4e89SAndroid Build Coastguard Worker 		addattr_l(&req.n, sizeof(req), IFLA_BRIDGE_VLAN_INFO, &vinfo,
131*de1e4e89SAndroid Build Coastguard Worker 			  sizeof(vinfo));
132*de1e4e89SAndroid Build Coastguard Worker 	}
133*de1e4e89SAndroid Build Coastguard Worker 
134*de1e4e89SAndroid Build Coastguard Worker 	addattr_nest_end(&req.n, afspec);
135*de1e4e89SAndroid Build Coastguard Worker 
136*de1e4e89SAndroid Build Coastguard Worker 	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
137*de1e4e89SAndroid Build Coastguard Worker 		return -1;
138*de1e4e89SAndroid Build Coastguard Worker 
139*de1e4e89SAndroid Build Coastguard Worker 	return 0;
140*de1e4e89SAndroid Build Coastguard Worker }
141*de1e4e89SAndroid Build Coastguard Worker 
142*de1e4e89SAndroid Build Coastguard Worker /* In order to use this function for both filtering and non-filtering cases
143*de1e4e89SAndroid Build Coastguard Worker  * we need to make it a tristate:
144*de1e4e89SAndroid Build Coastguard Worker  * return -1 - if filtering we've gone over so don't continue
145*de1e4e89SAndroid Build Coastguard Worker  * return  0 - skip entry and continue (applies to range start or to entries
146*de1e4e89SAndroid Build Coastguard Worker  *             which are less than filter_vlan)
147*de1e4e89SAndroid Build Coastguard Worker  * return  1 - print the entry and continue
148*de1e4e89SAndroid Build Coastguard Worker  */
filter_vlan_check(struct bridge_vlan_info * vinfo)149*de1e4e89SAndroid Build Coastguard Worker static int filter_vlan_check(struct bridge_vlan_info *vinfo)
150*de1e4e89SAndroid Build Coastguard Worker {
151*de1e4e89SAndroid Build Coastguard Worker 	/* if we're filtering we should stop on the first greater entry */
152*de1e4e89SAndroid Build Coastguard Worker 	if (filter_vlan && vinfo->vid > filter_vlan &&
153*de1e4e89SAndroid Build Coastguard Worker 	    !(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END))
154*de1e4e89SAndroid Build Coastguard Worker 		return -1;
155*de1e4e89SAndroid Build Coastguard Worker 	if ((vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) ||
156*de1e4e89SAndroid Build Coastguard Worker 	    vinfo->vid < filter_vlan)
157*de1e4e89SAndroid Build Coastguard Worker 		return 0;
158*de1e4e89SAndroid Build Coastguard Worker 
159*de1e4e89SAndroid Build Coastguard Worker 	return 1;
160*de1e4e89SAndroid Build Coastguard Worker }
161*de1e4e89SAndroid Build Coastguard Worker 
print_vlan_port(FILE * fp,int ifi_index)162*de1e4e89SAndroid Build Coastguard Worker static void print_vlan_port(FILE *fp, int ifi_index)
163*de1e4e89SAndroid Build Coastguard Worker {
164*de1e4e89SAndroid Build Coastguard Worker 	if (jw_global) {
165*de1e4e89SAndroid Build Coastguard Worker 		jsonw_pretty(jw_global, 1);
166*de1e4e89SAndroid Build Coastguard Worker 		jsonw_name(jw_global,
167*de1e4e89SAndroid Build Coastguard Worker 			   ll_index_to_name(ifi_index));
168*de1e4e89SAndroid Build Coastguard Worker 		jsonw_start_array(jw_global);
169*de1e4e89SAndroid Build Coastguard Worker 	} else {
170*de1e4e89SAndroid Build Coastguard Worker 		fprintf(fp, "%s",
171*de1e4e89SAndroid Build Coastguard Worker 			ll_index_to_name(ifi_index));
172*de1e4e89SAndroid Build Coastguard Worker 	}
173*de1e4e89SAndroid Build Coastguard Worker }
174*de1e4e89SAndroid Build Coastguard Worker 
start_json_vlan_flags_array(bool * vlan_flags)175*de1e4e89SAndroid Build Coastguard Worker static void start_json_vlan_flags_array(bool *vlan_flags)
176*de1e4e89SAndroid Build Coastguard Worker {
177*de1e4e89SAndroid Build Coastguard Worker 	if (*vlan_flags)
178*de1e4e89SAndroid Build Coastguard Worker 		return;
179*de1e4e89SAndroid Build Coastguard Worker 	jsonw_name(jw_global, "flags");
180*de1e4e89SAndroid Build Coastguard Worker 	jsonw_start_array(jw_global);
181*de1e4e89SAndroid Build Coastguard Worker 	*vlan_flags = true;
182*de1e4e89SAndroid Build Coastguard Worker }
183*de1e4e89SAndroid Build Coastguard Worker 
print_vlan(const struct sockaddr_nl * who,struct nlmsghdr * n,void * arg)184*de1e4e89SAndroid Build Coastguard Worker static int print_vlan(const struct sockaddr_nl *who,
185*de1e4e89SAndroid Build Coastguard Worker 		      struct nlmsghdr *n,
186*de1e4e89SAndroid Build Coastguard Worker 		      void *arg)
187*de1e4e89SAndroid Build Coastguard Worker {
188*de1e4e89SAndroid Build Coastguard Worker 	FILE *fp = arg;
189*de1e4e89SAndroid Build Coastguard Worker 	struct ifinfomsg *ifm = NLMSG_DATA(n);
190*de1e4e89SAndroid Build Coastguard Worker 	int len = n->nlmsg_len;
191*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *tb[IFLA_MAX+1];
192*de1e4e89SAndroid Build Coastguard Worker 
193*de1e4e89SAndroid Build Coastguard Worker 	if (n->nlmsg_type != RTM_NEWLINK) {
194*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "Not RTM_NEWLINK: %08x %08x %08x\n",
195*de1e4e89SAndroid Build Coastguard Worker 			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
196*de1e4e89SAndroid Build Coastguard Worker 		return 0;
197*de1e4e89SAndroid Build Coastguard Worker 	}
198*de1e4e89SAndroid Build Coastguard Worker 
199*de1e4e89SAndroid Build Coastguard Worker 	len -= NLMSG_LENGTH(sizeof(*ifm));
200*de1e4e89SAndroid Build Coastguard Worker 	if (len < 0) {
201*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
202*de1e4e89SAndroid Build Coastguard Worker 		return -1;
203*de1e4e89SAndroid Build Coastguard Worker 	}
204*de1e4e89SAndroid Build Coastguard Worker 
205*de1e4e89SAndroid Build Coastguard Worker 	if (ifm->ifi_family != AF_BRIDGE)
206*de1e4e89SAndroid Build Coastguard Worker 		return 0;
207*de1e4e89SAndroid Build Coastguard Worker 
208*de1e4e89SAndroid Build Coastguard Worker 	if (filter_index && filter_index != ifm->ifi_index)
209*de1e4e89SAndroid Build Coastguard Worker 		return 0;
210*de1e4e89SAndroid Build Coastguard Worker 
211*de1e4e89SAndroid Build Coastguard Worker 	parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifm), len);
212*de1e4e89SAndroid Build Coastguard Worker 
213*de1e4e89SAndroid Build Coastguard Worker 	/* if AF_SPEC isn't there, vlan table is not preset for this port */
214*de1e4e89SAndroid Build Coastguard Worker 	if (!tb[IFLA_AF_SPEC]) {
215*de1e4e89SAndroid Build Coastguard Worker 		if (!filter_vlan && !jw_global)
216*de1e4e89SAndroid Build Coastguard Worker 			fprintf(fp, "%s\tNone\n",
217*de1e4e89SAndroid Build Coastguard Worker 				ll_index_to_name(ifm->ifi_index));
218*de1e4e89SAndroid Build Coastguard Worker 		return 0;
219*de1e4e89SAndroid Build Coastguard Worker 	}
220*de1e4e89SAndroid Build Coastguard Worker 
221*de1e4e89SAndroid Build Coastguard Worker 	print_vlan_info(fp, tb[IFLA_AF_SPEC], ifm->ifi_index);
222*de1e4e89SAndroid Build Coastguard Worker 	if (!filter_vlan) {
223*de1e4e89SAndroid Build Coastguard Worker 		if (jw_global)
224*de1e4e89SAndroid Build Coastguard Worker 			jsonw_end_array(jw_global);
225*de1e4e89SAndroid Build Coastguard Worker 		else
226*de1e4e89SAndroid Build Coastguard Worker 			fprintf(fp, "\n");
227*de1e4e89SAndroid Build Coastguard Worker 
228*de1e4e89SAndroid Build Coastguard Worker 	}
229*de1e4e89SAndroid Build Coastguard Worker 	fflush(fp);
230*de1e4e89SAndroid Build Coastguard Worker 	return 0;
231*de1e4e89SAndroid Build Coastguard Worker }
232*de1e4e89SAndroid Build Coastguard Worker 
print_one_vlan_stats(FILE * fp,const struct bridge_vlan_xstats * vstats,int ifindex)233*de1e4e89SAndroid Build Coastguard Worker static void print_one_vlan_stats(FILE *fp,
234*de1e4e89SAndroid Build Coastguard Worker 				 const struct bridge_vlan_xstats *vstats,
235*de1e4e89SAndroid Build Coastguard Worker 				 int ifindex)
236*de1e4e89SAndroid Build Coastguard Worker {
237*de1e4e89SAndroid Build Coastguard Worker 	const char *ifname = "";
238*de1e4e89SAndroid Build Coastguard Worker 
239*de1e4e89SAndroid Build Coastguard Worker 	if (filter_vlan && filter_vlan != vstats->vid)
240*de1e4e89SAndroid Build Coastguard Worker 		return;
241*de1e4e89SAndroid Build Coastguard Worker 	/* skip pure port entries, they'll be dumped via the slave stats call */
242*de1e4e89SAndroid Build Coastguard Worker 	if ((vstats->flags & BRIDGE_VLAN_INFO_MASTER) &&
243*de1e4e89SAndroid Build Coastguard Worker 	    !(vstats->flags & BRIDGE_VLAN_INFO_BRENTRY))
244*de1e4e89SAndroid Build Coastguard Worker 		return;
245*de1e4e89SAndroid Build Coastguard Worker 
246*de1e4e89SAndroid Build Coastguard Worker 	if (last_ifidx != ifindex) {
247*de1e4e89SAndroid Build Coastguard Worker 		ifname = ll_index_to_name(ifindex);
248*de1e4e89SAndroid Build Coastguard Worker 		last_ifidx = ifindex;
249*de1e4e89SAndroid Build Coastguard Worker 	}
250*de1e4e89SAndroid Build Coastguard Worker 	fprintf(fp, "%-16s  %hu", ifname, vstats->vid);
251*de1e4e89SAndroid Build Coastguard Worker 	if (vstats->flags & BRIDGE_VLAN_INFO_PVID)
252*de1e4e89SAndroid Build Coastguard Worker 		fprintf(fp, " PVID");
253*de1e4e89SAndroid Build Coastguard Worker 	if (vstats->flags & BRIDGE_VLAN_INFO_UNTAGGED)
254*de1e4e89SAndroid Build Coastguard Worker 		fprintf(fp, " Egress Untagged");
255*de1e4e89SAndroid Build Coastguard Worker 	fprintf(fp, "\n");
256*de1e4e89SAndroid Build Coastguard Worker 	fprintf(fp, "%-16s    RX: %llu bytes %llu packets\n",
257*de1e4e89SAndroid Build Coastguard Worker 		"", vstats->rx_bytes, vstats->rx_packets);
258*de1e4e89SAndroid Build Coastguard Worker 	fprintf(fp, "%-16s    TX: %llu bytes %llu packets\n",
259*de1e4e89SAndroid Build Coastguard Worker 		"", vstats->tx_bytes, vstats->tx_packets);
260*de1e4e89SAndroid Build Coastguard Worker }
261*de1e4e89SAndroid Build Coastguard Worker 
print_vlan_stats_attr(FILE * fp,struct rtattr * attr,int ifindex)262*de1e4e89SAndroid Build Coastguard Worker static void print_vlan_stats_attr(FILE *fp, struct rtattr *attr, int ifindex)
263*de1e4e89SAndroid Build Coastguard Worker {
264*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *brtb[LINK_XSTATS_TYPE_MAX+1];
265*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *i, *list;
266*de1e4e89SAndroid Build Coastguard Worker 	int rem;
267*de1e4e89SAndroid Build Coastguard Worker 
268*de1e4e89SAndroid Build Coastguard Worker 	parse_rtattr(brtb, LINK_XSTATS_TYPE_MAX, RTA_DATA(attr),
269*de1e4e89SAndroid Build Coastguard Worker 		     RTA_PAYLOAD(attr));
270*de1e4e89SAndroid Build Coastguard Worker 	if (!brtb[LINK_XSTATS_TYPE_BRIDGE])
271*de1e4e89SAndroid Build Coastguard Worker 		return;
272*de1e4e89SAndroid Build Coastguard Worker 
273*de1e4e89SAndroid Build Coastguard Worker 	list = brtb[LINK_XSTATS_TYPE_BRIDGE];
274*de1e4e89SAndroid Build Coastguard Worker 	rem = RTA_PAYLOAD(list);
275*de1e4e89SAndroid Build Coastguard Worker 	for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
276*de1e4e89SAndroid Build Coastguard Worker 		if (i->rta_type != BRIDGE_XSTATS_VLAN)
277*de1e4e89SAndroid Build Coastguard Worker 			continue;
278*de1e4e89SAndroid Build Coastguard Worker 		print_one_vlan_stats(fp, RTA_DATA(i), ifindex);
279*de1e4e89SAndroid Build Coastguard Worker 	}
280*de1e4e89SAndroid Build Coastguard Worker }
281*de1e4e89SAndroid Build Coastguard Worker 
print_vlan_stats(const struct sockaddr_nl * who,struct nlmsghdr * n,void * arg)282*de1e4e89SAndroid Build Coastguard Worker static int print_vlan_stats(const struct sockaddr_nl *who,
283*de1e4e89SAndroid Build Coastguard Worker 			    struct nlmsghdr *n,
284*de1e4e89SAndroid Build Coastguard Worker 			    void *arg)
285*de1e4e89SAndroid Build Coastguard Worker {
286*de1e4e89SAndroid Build Coastguard Worker 	struct if_stats_msg *ifsm = NLMSG_DATA(n);
287*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *tb[IFLA_STATS_MAX+1];
288*de1e4e89SAndroid Build Coastguard Worker 	int len = n->nlmsg_len;
289*de1e4e89SAndroid Build Coastguard Worker 	FILE *fp = arg;
290*de1e4e89SAndroid Build Coastguard Worker 
291*de1e4e89SAndroid Build Coastguard Worker 	len -= NLMSG_LENGTH(sizeof(*ifsm));
292*de1e4e89SAndroid Build Coastguard Worker 	if (len < 0) {
293*de1e4e89SAndroid Build Coastguard Worker 		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
294*de1e4e89SAndroid Build Coastguard Worker 		return -1;
295*de1e4e89SAndroid Build Coastguard Worker 	}
296*de1e4e89SAndroid Build Coastguard Worker 
297*de1e4e89SAndroid Build Coastguard Worker 	if (filter_index && filter_index != ifsm->ifindex)
298*de1e4e89SAndroid Build Coastguard Worker 		return 0;
299*de1e4e89SAndroid Build Coastguard Worker 
300*de1e4e89SAndroid Build Coastguard Worker 	parse_rtattr(tb, IFLA_STATS_MAX, IFLA_STATS_RTA(ifsm), len);
301*de1e4e89SAndroid Build Coastguard Worker 
302*de1e4e89SAndroid Build Coastguard Worker 	/* We have to check if any of the two attrs are usable */
303*de1e4e89SAndroid Build Coastguard Worker 	if (tb[IFLA_STATS_LINK_XSTATS])
304*de1e4e89SAndroid Build Coastguard Worker 		print_vlan_stats_attr(fp, tb[IFLA_STATS_LINK_XSTATS],
305*de1e4e89SAndroid Build Coastguard Worker 				      ifsm->ifindex);
306*de1e4e89SAndroid Build Coastguard Worker 
307*de1e4e89SAndroid Build Coastguard Worker 	if (tb[IFLA_STATS_LINK_XSTATS_SLAVE])
308*de1e4e89SAndroid Build Coastguard Worker 		print_vlan_stats_attr(fp, tb[IFLA_STATS_LINK_XSTATS_SLAVE],
309*de1e4e89SAndroid Build Coastguard Worker 				      ifsm->ifindex);
310*de1e4e89SAndroid Build Coastguard Worker 
311*de1e4e89SAndroid Build Coastguard Worker 	fflush(fp);
312*de1e4e89SAndroid Build Coastguard Worker 	return 0;
313*de1e4e89SAndroid Build Coastguard Worker }
314*de1e4e89SAndroid Build Coastguard Worker 
vlan_show(int argc,char ** argv)315*de1e4e89SAndroid Build Coastguard Worker static int vlan_show(int argc, char **argv)
316*de1e4e89SAndroid Build Coastguard Worker {
317*de1e4e89SAndroid Build Coastguard Worker 	char *filter_dev = NULL;
318*de1e4e89SAndroid Build Coastguard Worker 
319*de1e4e89SAndroid Build Coastguard Worker 	while (argc > 0) {
320*de1e4e89SAndroid Build Coastguard Worker 		if (strcmp(*argv, "dev") == 0) {
321*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
322*de1e4e89SAndroid Build Coastguard Worker 			if (filter_dev)
323*de1e4e89SAndroid Build Coastguard Worker 				duparg("dev", *argv);
324*de1e4e89SAndroid Build Coastguard Worker 			filter_dev = *argv;
325*de1e4e89SAndroid Build Coastguard Worker 		} else if (strcmp(*argv, "vid") == 0) {
326*de1e4e89SAndroid Build Coastguard Worker 			NEXT_ARG();
327*de1e4e89SAndroid Build Coastguard Worker 			if (filter_vlan)
328*de1e4e89SAndroid Build Coastguard Worker 				duparg("vid", *argv);
329*de1e4e89SAndroid Build Coastguard Worker 			filter_vlan = atoi(*argv);
330*de1e4e89SAndroid Build Coastguard Worker 		}
331*de1e4e89SAndroid Build Coastguard Worker 		argc--; argv++;
332*de1e4e89SAndroid Build Coastguard Worker 	}
333*de1e4e89SAndroid Build Coastguard Worker 
334*de1e4e89SAndroid Build Coastguard Worker 	if (filter_dev) {
335*de1e4e89SAndroid Build Coastguard Worker 		filter_index = if_nametoindex(filter_dev);
336*de1e4e89SAndroid Build Coastguard Worker 		if (filter_index == 0) {
337*de1e4e89SAndroid Build Coastguard Worker 			fprintf(stderr, "Cannot find device \"%s\"\n",
338*de1e4e89SAndroid Build Coastguard Worker 				filter_dev);
339*de1e4e89SAndroid Build Coastguard Worker 			return -1;
340*de1e4e89SAndroid Build Coastguard Worker 		}
341*de1e4e89SAndroid Build Coastguard Worker 	}
342*de1e4e89SAndroid Build Coastguard Worker 
343*de1e4e89SAndroid Build Coastguard Worker 	if (!show_stats) {
344*de1e4e89SAndroid Build Coastguard Worker 		if (rtnl_wilddump_req_filter(&rth, PF_BRIDGE, RTM_GETLINK,
345*de1e4e89SAndroid Build Coastguard Worker 					     (compress_vlans ?
346*de1e4e89SAndroid Build Coastguard Worker 						RTEXT_FILTER_BRVLAN_COMPRESSED :
347*de1e4e89SAndroid Build Coastguard Worker 						RTEXT_FILTER_BRVLAN)) < 0) {
348*de1e4e89SAndroid Build Coastguard Worker 			perror("Cannont send dump request");
349*de1e4e89SAndroid Build Coastguard Worker 			exit(1);
350*de1e4e89SAndroid Build Coastguard Worker 		}
351*de1e4e89SAndroid Build Coastguard Worker 		if (json_output) {
352*de1e4e89SAndroid Build Coastguard Worker 			jw_global = jsonw_new(stdout);
353*de1e4e89SAndroid Build Coastguard Worker 			if (!jw_global) {
354*de1e4e89SAndroid Build Coastguard Worker 				fprintf(stderr, "Error allocation json object\n");
355*de1e4e89SAndroid Build Coastguard Worker 				exit(1);
356*de1e4e89SAndroid Build Coastguard Worker 			}
357*de1e4e89SAndroid Build Coastguard Worker 			jsonw_start_object(jw_global);
358*de1e4e89SAndroid Build Coastguard Worker 		} else {
359*de1e4e89SAndroid Build Coastguard Worker 			printf("port\tvlan ids\n");
360*de1e4e89SAndroid Build Coastguard Worker 		}
361*de1e4e89SAndroid Build Coastguard Worker 
362*de1e4e89SAndroid Build Coastguard Worker 		if (rtnl_dump_filter(&rth, print_vlan, stdout) < 0) {
363*de1e4e89SAndroid Build Coastguard Worker 			fprintf(stderr, "Dump ternminated\n");
364*de1e4e89SAndroid Build Coastguard Worker 			exit(1);
365*de1e4e89SAndroid Build Coastguard Worker 		}
366*de1e4e89SAndroid Build Coastguard Worker 	} else {
367*de1e4e89SAndroid Build Coastguard Worker 		__u32 filt_mask;
368*de1e4e89SAndroid Build Coastguard Worker 
369*de1e4e89SAndroid Build Coastguard Worker 		filt_mask = IFLA_STATS_FILTER_BIT(IFLA_STATS_LINK_XSTATS);
370*de1e4e89SAndroid Build Coastguard Worker 		if (rtnl_wilddump_stats_req_filter(&rth, AF_UNSPEC,
371*de1e4e89SAndroid Build Coastguard Worker 						   RTM_GETSTATS,
372*de1e4e89SAndroid Build Coastguard Worker 						   filt_mask) < 0) {
373*de1e4e89SAndroid Build Coastguard Worker 			perror("Cannont send dump request");
374*de1e4e89SAndroid Build Coastguard Worker 			exit(1);
375*de1e4e89SAndroid Build Coastguard Worker 		}
376*de1e4e89SAndroid Build Coastguard Worker 
377*de1e4e89SAndroid Build Coastguard Worker 		printf("%-16s vlan id\n", "port");
378*de1e4e89SAndroid Build Coastguard Worker 		if (rtnl_dump_filter(&rth, print_vlan_stats, stdout) < 0) {
379*de1e4e89SAndroid Build Coastguard Worker 			fprintf(stderr, "Dump terminated\n");
380*de1e4e89SAndroid Build Coastguard Worker 			exit(1);
381*de1e4e89SAndroid Build Coastguard Worker 		}
382*de1e4e89SAndroid Build Coastguard Worker 
383*de1e4e89SAndroid Build Coastguard Worker 		filt_mask = IFLA_STATS_FILTER_BIT(IFLA_STATS_LINK_XSTATS_SLAVE);
384*de1e4e89SAndroid Build Coastguard Worker 		if (rtnl_wilddump_stats_req_filter(&rth, AF_UNSPEC,
385*de1e4e89SAndroid Build Coastguard Worker 						   RTM_GETSTATS,
386*de1e4e89SAndroid Build Coastguard Worker 						   filt_mask) < 0) {
387*de1e4e89SAndroid Build Coastguard Worker 			perror("Cannont send slave dump request");
388*de1e4e89SAndroid Build Coastguard Worker 			exit(1);
389*de1e4e89SAndroid Build Coastguard Worker 		}
390*de1e4e89SAndroid Build Coastguard Worker 
391*de1e4e89SAndroid Build Coastguard Worker 		if (rtnl_dump_filter(&rth, print_vlan_stats, stdout) < 0) {
392*de1e4e89SAndroid Build Coastguard Worker 			fprintf(stderr, "Dump terminated\n");
393*de1e4e89SAndroid Build Coastguard Worker 			exit(1);
394*de1e4e89SAndroid Build Coastguard Worker 		}
395*de1e4e89SAndroid Build Coastguard Worker 	}
396*de1e4e89SAndroid Build Coastguard Worker 
397*de1e4e89SAndroid Build Coastguard Worker 	if (jw_global) {
398*de1e4e89SAndroid Build Coastguard Worker 		jsonw_end_object(jw_global);
399*de1e4e89SAndroid Build Coastguard Worker 		jsonw_destroy(&jw_global);
400*de1e4e89SAndroid Build Coastguard Worker 	}
401*de1e4e89SAndroid Build Coastguard Worker 
402*de1e4e89SAndroid Build Coastguard Worker 	return 0;
403*de1e4e89SAndroid Build Coastguard Worker }
404*de1e4e89SAndroid Build Coastguard Worker 
print_vlan_info(FILE * fp,struct rtattr * tb,int ifindex)405*de1e4e89SAndroid Build Coastguard Worker void print_vlan_info(FILE *fp, struct rtattr *tb, int ifindex)
406*de1e4e89SAndroid Build Coastguard Worker {
407*de1e4e89SAndroid Build Coastguard Worker 	struct rtattr *i, *list = tb;
408*de1e4e89SAndroid Build Coastguard Worker 	int rem = RTA_PAYLOAD(list);
409*de1e4e89SAndroid Build Coastguard Worker 	__u16 last_vid_start = 0;
410*de1e4e89SAndroid Build Coastguard Worker 	bool vlan_flags = false;
411*de1e4e89SAndroid Build Coastguard Worker 
412*de1e4e89SAndroid Build Coastguard Worker 	if (!filter_vlan)
413*de1e4e89SAndroid Build Coastguard Worker 		print_vlan_port(fp, ifindex);
414*de1e4e89SAndroid Build Coastguard Worker 
415*de1e4e89SAndroid Build Coastguard Worker 	for (i = RTA_DATA(list); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
416*de1e4e89SAndroid Build Coastguard Worker 		struct bridge_vlan_info *vinfo;
417*de1e4e89SAndroid Build Coastguard Worker 		int vcheck_ret;
418*de1e4e89SAndroid Build Coastguard Worker 
419*de1e4e89SAndroid Build Coastguard Worker 		if (i->rta_type != IFLA_BRIDGE_VLAN_INFO)
420*de1e4e89SAndroid Build Coastguard Worker 			continue;
421*de1e4e89SAndroid Build Coastguard Worker 
422*de1e4e89SAndroid Build Coastguard Worker 		vinfo = RTA_DATA(i);
423*de1e4e89SAndroid Build Coastguard Worker 
424*de1e4e89SAndroid Build Coastguard Worker 		if (!(vinfo->flags & BRIDGE_VLAN_INFO_RANGE_END))
425*de1e4e89SAndroid Build Coastguard Worker 			last_vid_start = vinfo->vid;
426*de1e4e89SAndroid Build Coastguard Worker 		vcheck_ret = filter_vlan_check(vinfo);
427*de1e4e89SAndroid Build Coastguard Worker 		if (vcheck_ret == -1)
428*de1e4e89SAndroid Build Coastguard Worker 			break;
429*de1e4e89SAndroid Build Coastguard Worker 		else if (vcheck_ret == 0)
430*de1e4e89SAndroid Build Coastguard Worker 			continue;
431*de1e4e89SAndroid Build Coastguard Worker 
432*de1e4e89SAndroid Build Coastguard Worker 		if (filter_vlan)
433*de1e4e89SAndroid Build Coastguard Worker 			print_vlan_port(fp, ifindex);
434*de1e4e89SAndroid Build Coastguard Worker 		if (jw_global) {
435*de1e4e89SAndroid Build Coastguard Worker 			jsonw_start_object(jw_global);
436*de1e4e89SAndroid Build Coastguard Worker 			jsonw_uint_field(jw_global, "vlan",
437*de1e4e89SAndroid Build Coastguard Worker 					 last_vid_start);
438*de1e4e89SAndroid Build Coastguard Worker 			if (vinfo->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN)
439*de1e4e89SAndroid Build Coastguard Worker 				continue;
440*de1e4e89SAndroid Build Coastguard Worker 		} else {
441*de1e4e89SAndroid Build Coastguard Worker 			fprintf(fp, "\t %hu", last_vid_start);
442*de1e4e89SAndroid Build Coastguard Worker 		}
443*de1e4e89SAndroid Build Coastguard Worker 		if (last_vid_start != vinfo->vid) {
444*de1e4e89SAndroid Build Coastguard Worker 			if (jw_global)
445*de1e4e89SAndroid Build Coastguard Worker 				jsonw_uint_field(jw_global, "vlanEnd",
446*de1e4e89SAndroid Build Coastguard Worker 						 vinfo->vid);
447*de1e4e89SAndroid Build Coastguard Worker 			else
448*de1e4e89SAndroid Build Coastguard Worker 				fprintf(fp, "-%hu", vinfo->vid);
449*de1e4e89SAndroid Build Coastguard Worker 		}
450*de1e4e89SAndroid Build Coastguard Worker 		if (vinfo->flags & BRIDGE_VLAN_INFO_PVID) {
451*de1e4e89SAndroid Build Coastguard Worker 			if (jw_global) {
452*de1e4e89SAndroid Build Coastguard Worker 				start_json_vlan_flags_array(&vlan_flags);
453*de1e4e89SAndroid Build Coastguard Worker 				jsonw_string(jw_global, "PVID");
454*de1e4e89SAndroid Build Coastguard Worker 			} else {
455*de1e4e89SAndroid Build Coastguard Worker 				fprintf(fp, " PVID");
456*de1e4e89SAndroid Build Coastguard Worker 			}
457*de1e4e89SAndroid Build Coastguard Worker 		}
458*de1e4e89SAndroid Build Coastguard Worker 		if (vinfo->flags & BRIDGE_VLAN_INFO_UNTAGGED) {
459*de1e4e89SAndroid Build Coastguard Worker 			if (jw_global) {
460*de1e4e89SAndroid Build Coastguard Worker 				start_json_vlan_flags_array(&vlan_flags);
461*de1e4e89SAndroid Build Coastguard Worker 				jsonw_string(jw_global,
462*de1e4e89SAndroid Build Coastguard Worker 					     "Egress Untagged");
463*de1e4e89SAndroid Build Coastguard Worker 			} else {
464*de1e4e89SAndroid Build Coastguard Worker 				fprintf(fp, " Egress Untagged");
465*de1e4e89SAndroid Build Coastguard Worker 			}
466*de1e4e89SAndroid Build Coastguard Worker 		}
467*de1e4e89SAndroid Build Coastguard Worker 		if (jw_global && vlan_flags) {
468*de1e4e89SAndroid Build Coastguard Worker 			jsonw_end_array(jw_global);
469*de1e4e89SAndroid Build Coastguard Worker 			vlan_flags = false;
470*de1e4e89SAndroid Build Coastguard Worker 		}
471*de1e4e89SAndroid Build Coastguard Worker 
472*de1e4e89SAndroid Build Coastguard Worker 		if (jw_global)
473*de1e4e89SAndroid Build Coastguard Worker 			jsonw_end_object(jw_global);
474*de1e4e89SAndroid Build Coastguard Worker 		else
475*de1e4e89SAndroid Build Coastguard Worker 			fprintf(fp, "\n");
476*de1e4e89SAndroid Build Coastguard Worker 	}
477*de1e4e89SAndroid Build Coastguard Worker }
478*de1e4e89SAndroid Build Coastguard Worker 
do_vlan(int argc,char ** argv)479*de1e4e89SAndroid Build Coastguard Worker int do_vlan(int argc, char **argv)
480*de1e4e89SAndroid Build Coastguard Worker {
481*de1e4e89SAndroid Build Coastguard Worker 	ll_init_map(&rth);
482*de1e4e89SAndroid Build Coastguard Worker 
483*de1e4e89SAndroid Build Coastguard Worker 	if (argc > 0) {
484*de1e4e89SAndroid Build Coastguard Worker 		if (matches(*argv, "add") == 0)
485*de1e4e89SAndroid Build Coastguard Worker 			return vlan_modify(RTM_SETLINK, argc-1, argv+1);
486*de1e4e89SAndroid Build Coastguard Worker 		if (matches(*argv, "delete") == 0)
487*de1e4e89SAndroid Build Coastguard Worker 			return vlan_modify(RTM_DELLINK, argc-1, argv+1);
488*de1e4e89SAndroid Build Coastguard Worker 		if (matches(*argv, "show") == 0 ||
489*de1e4e89SAndroid Build Coastguard Worker 		    matches(*argv, "lst") == 0 ||
490*de1e4e89SAndroid Build Coastguard Worker 		    matches(*argv, "list") == 0)
491*de1e4e89SAndroid Build Coastguard Worker 			return vlan_show(argc-1, argv+1);
492*de1e4e89SAndroid Build Coastguard Worker 		if (matches(*argv, "help") == 0)
493*de1e4e89SAndroid Build Coastguard Worker 			usage();
494*de1e4e89SAndroid Build Coastguard Worker 	} else {
495*de1e4e89SAndroid Build Coastguard Worker 		return vlan_show(0, NULL);
496*de1e4e89SAndroid Build Coastguard Worker 	}
497*de1e4e89SAndroid Build Coastguard Worker 
498*de1e4e89SAndroid Build Coastguard Worker 	fprintf(stderr, "Command \"%s\" is unknown, try \"bridge vlan help\".\n", *argv);
499*de1e4e89SAndroid Build Coastguard Worker 	exit(-1);
500*de1e4e89SAndroid Build Coastguard Worker }
501