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