1*de1e4e89SAndroid Build Coastguard Worker /*
2*de1e4e89SAndroid Build Coastguard Worker * Get mdb table with netlink
3*de1e4e89SAndroid Build Coastguard Worker */
4*de1e4e89SAndroid Build Coastguard Worker
5*de1e4e89SAndroid Build Coastguard Worker #include <stdio.h>
6*de1e4e89SAndroid Build Coastguard Worker #include <stdlib.h>
7*de1e4e89SAndroid Build Coastguard Worker #include <unistd.h>
8*de1e4e89SAndroid Build Coastguard Worker #include <fcntl.h>
9*de1e4e89SAndroid Build Coastguard Worker #include <sys/socket.h>
10*de1e4e89SAndroid Build Coastguard Worker #include <net/if.h>
11*de1e4e89SAndroid Build Coastguard Worker #include <netinet/in.h>
12*de1e4e89SAndroid Build Coastguard Worker #include <linux/if_bridge.h>
13*de1e4e89SAndroid Build Coastguard Worker #include <linux/if_ether.h>
14*de1e4e89SAndroid Build Coastguard Worker #include <string.h>
15*de1e4e89SAndroid Build Coastguard Worker #include <arpa/inet.h>
16*de1e4e89SAndroid Build Coastguard Worker #include <json_writer.h>
17*de1e4e89SAndroid Build Coastguard Worker
18*de1e4e89SAndroid Build Coastguard Worker #include "libnetlink.h"
19*de1e4e89SAndroid Build Coastguard Worker #include "br_common.h"
20*de1e4e89SAndroid Build Coastguard Worker #include "rt_names.h"
21*de1e4e89SAndroid Build Coastguard Worker #include "utils.h"
22*de1e4e89SAndroid Build Coastguard Worker
23*de1e4e89SAndroid Build Coastguard Worker #ifndef MDBA_RTA
24*de1e4e89SAndroid Build Coastguard Worker #define MDBA_RTA(r) \
25*de1e4e89SAndroid Build Coastguard Worker ((struct rtattr *)(((char *)(r)) + NLMSG_ALIGN(sizeof(struct br_port_msg))))
26*de1e4e89SAndroid Build Coastguard Worker #endif
27*de1e4e89SAndroid Build Coastguard Worker
28*de1e4e89SAndroid Build Coastguard Worker static unsigned int filter_index, filter_vlan;
29*de1e4e89SAndroid Build Coastguard Worker json_writer_t *jw_global;
30*de1e4e89SAndroid Build Coastguard Worker static bool print_mdb_entries = true;
31*de1e4e89SAndroid Build Coastguard Worker static bool print_mdb_router = true;
32*de1e4e89SAndroid Build Coastguard Worker
usage(void)33*de1e4e89SAndroid Build Coastguard Worker static void usage(void)
34*de1e4e89SAndroid Build Coastguard Worker {
35*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Usage: bridge mdb { add | del } dev DEV port PORT grp GROUP [permanent | temp] [vid VID]\n");
36*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, " bridge mdb {show} [ dev DEV ] [ vid VID ]\n");
37*de1e4e89SAndroid Build Coastguard Worker exit(-1);
38*de1e4e89SAndroid Build Coastguard Worker }
39*de1e4e89SAndroid Build Coastguard Worker
is_temp_mcast_rtr(__u8 type)40*de1e4e89SAndroid Build Coastguard Worker static bool is_temp_mcast_rtr(__u8 type)
41*de1e4e89SAndroid Build Coastguard Worker {
42*de1e4e89SAndroid Build Coastguard Worker return type == MDB_RTR_TYPE_TEMP_QUERY || type == MDB_RTR_TYPE_TEMP;
43*de1e4e89SAndroid Build Coastguard Worker }
44*de1e4e89SAndroid Build Coastguard Worker
__print_router_port_stats(FILE * f,struct rtattr * pattr)45*de1e4e89SAndroid Build Coastguard Worker static void __print_router_port_stats(FILE *f, struct rtattr *pattr)
46*de1e4e89SAndroid Build Coastguard Worker {
47*de1e4e89SAndroid Build Coastguard Worker struct rtattr *tb[MDBA_ROUTER_PATTR_MAX + 1];
48*de1e4e89SAndroid Build Coastguard Worker struct timeval tv;
49*de1e4e89SAndroid Build Coastguard Worker __u8 type;
50*de1e4e89SAndroid Build Coastguard Worker
51*de1e4e89SAndroid Build Coastguard Worker parse_rtattr(tb, MDBA_ROUTER_PATTR_MAX, MDB_RTR_RTA(RTA_DATA(pattr)),
52*de1e4e89SAndroid Build Coastguard Worker RTA_PAYLOAD(pattr) - RTA_ALIGN(sizeof(uint32_t)));
53*de1e4e89SAndroid Build Coastguard Worker if (tb[MDBA_ROUTER_PATTR_TIMER]) {
54*de1e4e89SAndroid Build Coastguard Worker __jiffies_to_tv(&tv,
55*de1e4e89SAndroid Build Coastguard Worker rta_getattr_u32(tb[MDBA_ROUTER_PATTR_TIMER]));
56*de1e4e89SAndroid Build Coastguard Worker if (jw_global) {
57*de1e4e89SAndroid Build Coastguard Worker char formatted_time[9];
58*de1e4e89SAndroid Build Coastguard Worker
59*de1e4e89SAndroid Build Coastguard Worker snprintf(formatted_time, sizeof(formatted_time),
60*de1e4e89SAndroid Build Coastguard Worker "%4i.%.2i", (int)tv.tv_sec,
61*de1e4e89SAndroid Build Coastguard Worker (int)tv.tv_usec/10000);
62*de1e4e89SAndroid Build Coastguard Worker jsonw_string_field(jw_global, "timer", formatted_time);
63*de1e4e89SAndroid Build Coastguard Worker } else {
64*de1e4e89SAndroid Build Coastguard Worker fprintf(f, " %4i.%.2i",
65*de1e4e89SAndroid Build Coastguard Worker (int)tv.tv_sec, (int)tv.tv_usec/10000);
66*de1e4e89SAndroid Build Coastguard Worker }
67*de1e4e89SAndroid Build Coastguard Worker }
68*de1e4e89SAndroid Build Coastguard Worker if (tb[MDBA_ROUTER_PATTR_TYPE]) {
69*de1e4e89SAndroid Build Coastguard Worker type = rta_getattr_u8(tb[MDBA_ROUTER_PATTR_TYPE]);
70*de1e4e89SAndroid Build Coastguard Worker if (jw_global)
71*de1e4e89SAndroid Build Coastguard Worker jsonw_string_field(jw_global, "type",
72*de1e4e89SAndroid Build Coastguard Worker is_temp_mcast_rtr(type) ? "temp" : "permanent");
73*de1e4e89SAndroid Build Coastguard Worker else
74*de1e4e89SAndroid Build Coastguard Worker fprintf(f, " %s",
75*de1e4e89SAndroid Build Coastguard Worker is_temp_mcast_rtr(type) ? "temp" : "permanent");
76*de1e4e89SAndroid Build Coastguard Worker }
77*de1e4e89SAndroid Build Coastguard Worker }
78*de1e4e89SAndroid Build Coastguard Worker
br_print_router_ports(FILE * f,struct rtattr * attr,__u32 brifidx)79*de1e4e89SAndroid Build Coastguard Worker static void br_print_router_ports(FILE *f, struct rtattr *attr, __u32 brifidx)
80*de1e4e89SAndroid Build Coastguard Worker {
81*de1e4e89SAndroid Build Coastguard Worker uint32_t *port_ifindex;
82*de1e4e89SAndroid Build Coastguard Worker struct rtattr *i;
83*de1e4e89SAndroid Build Coastguard Worker int rem;
84*de1e4e89SAndroid Build Coastguard Worker
85*de1e4e89SAndroid Build Coastguard Worker rem = RTA_PAYLOAD(attr);
86*de1e4e89SAndroid Build Coastguard Worker if (jw_global) {
87*de1e4e89SAndroid Build Coastguard Worker jsonw_name(jw_global, ll_index_to_name(brifidx));
88*de1e4e89SAndroid Build Coastguard Worker jsonw_start_array(jw_global);
89*de1e4e89SAndroid Build Coastguard Worker for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
90*de1e4e89SAndroid Build Coastguard Worker port_ifindex = RTA_DATA(i);
91*de1e4e89SAndroid Build Coastguard Worker jsonw_start_object(jw_global);
92*de1e4e89SAndroid Build Coastguard Worker jsonw_string_field(jw_global,
93*de1e4e89SAndroid Build Coastguard Worker "port",
94*de1e4e89SAndroid Build Coastguard Worker ll_index_to_name(*port_ifindex));
95*de1e4e89SAndroid Build Coastguard Worker if (show_stats)
96*de1e4e89SAndroid Build Coastguard Worker __print_router_port_stats(f, i);
97*de1e4e89SAndroid Build Coastguard Worker jsonw_end_object(jw_global);
98*de1e4e89SAndroid Build Coastguard Worker }
99*de1e4e89SAndroid Build Coastguard Worker jsonw_end_array(jw_global);
100*de1e4e89SAndroid Build Coastguard Worker } else {
101*de1e4e89SAndroid Build Coastguard Worker if (!show_stats)
102*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "router ports on %s: ",
103*de1e4e89SAndroid Build Coastguard Worker ll_index_to_name(brifidx));
104*de1e4e89SAndroid Build Coastguard Worker for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
105*de1e4e89SAndroid Build Coastguard Worker port_ifindex = RTA_DATA(i);
106*de1e4e89SAndroid Build Coastguard Worker if (show_stats) {
107*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "router ports on %s: %s",
108*de1e4e89SAndroid Build Coastguard Worker ll_index_to_name(brifidx),
109*de1e4e89SAndroid Build Coastguard Worker ll_index_to_name(*port_ifindex));
110*de1e4e89SAndroid Build Coastguard Worker __print_router_port_stats(f, i);
111*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "\n");
112*de1e4e89SAndroid Build Coastguard Worker } else{
113*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "%s ",
114*de1e4e89SAndroid Build Coastguard Worker ll_index_to_name(*port_ifindex));
115*de1e4e89SAndroid Build Coastguard Worker }
116*de1e4e89SAndroid Build Coastguard Worker }
117*de1e4e89SAndroid Build Coastguard Worker if (!show_stats)
118*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "\n");
119*de1e4e89SAndroid Build Coastguard Worker }
120*de1e4e89SAndroid Build Coastguard Worker }
121*de1e4e89SAndroid Build Coastguard Worker
start_json_mdb_flags_array(bool * mdb_flags)122*de1e4e89SAndroid Build Coastguard Worker static void start_json_mdb_flags_array(bool *mdb_flags)
123*de1e4e89SAndroid Build Coastguard Worker {
124*de1e4e89SAndroid Build Coastguard Worker if (*mdb_flags)
125*de1e4e89SAndroid Build Coastguard Worker return;
126*de1e4e89SAndroid Build Coastguard Worker jsonw_name(jw_global, "flags");
127*de1e4e89SAndroid Build Coastguard Worker jsonw_start_array(jw_global);
128*de1e4e89SAndroid Build Coastguard Worker *mdb_flags = true;
129*de1e4e89SAndroid Build Coastguard Worker }
130*de1e4e89SAndroid Build Coastguard Worker
print_mdb_entry(FILE * f,int ifindex,struct br_mdb_entry * e,struct nlmsghdr * n,struct rtattr ** tb)131*de1e4e89SAndroid Build Coastguard Worker static void print_mdb_entry(FILE *f, int ifindex, struct br_mdb_entry *e,
132*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr *n, struct rtattr **tb)
133*de1e4e89SAndroid Build Coastguard Worker {
134*de1e4e89SAndroid Build Coastguard Worker SPRINT_BUF(abuf);
135*de1e4e89SAndroid Build Coastguard Worker const void *src;
136*de1e4e89SAndroid Build Coastguard Worker int af;
137*de1e4e89SAndroid Build Coastguard Worker bool mdb_flags = false;
138*de1e4e89SAndroid Build Coastguard Worker
139*de1e4e89SAndroid Build Coastguard Worker if (filter_vlan && e->vid != filter_vlan)
140*de1e4e89SAndroid Build Coastguard Worker return;
141*de1e4e89SAndroid Build Coastguard Worker af = e->addr.proto == htons(ETH_P_IP) ? AF_INET : AF_INET6;
142*de1e4e89SAndroid Build Coastguard Worker src = af == AF_INET ? (const void *)&e->addr.u.ip4 :
143*de1e4e89SAndroid Build Coastguard Worker (const void *)&e->addr.u.ip6;
144*de1e4e89SAndroid Build Coastguard Worker if (jw_global)
145*de1e4e89SAndroid Build Coastguard Worker jsonw_start_object(jw_global);
146*de1e4e89SAndroid Build Coastguard Worker if (n->nlmsg_type == RTM_DELMDB) {
147*de1e4e89SAndroid Build Coastguard Worker if (jw_global)
148*de1e4e89SAndroid Build Coastguard Worker jsonw_string_field(jw_global, "opCode", "deleted");
149*de1e4e89SAndroid Build Coastguard Worker else
150*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "Deleted ");
151*de1e4e89SAndroid Build Coastguard Worker }
152*de1e4e89SAndroid Build Coastguard Worker if (jw_global) {
153*de1e4e89SAndroid Build Coastguard Worker jsonw_string_field(jw_global, "dev", ll_index_to_name(ifindex));
154*de1e4e89SAndroid Build Coastguard Worker jsonw_string_field(jw_global,
155*de1e4e89SAndroid Build Coastguard Worker "port",
156*de1e4e89SAndroid Build Coastguard Worker ll_index_to_name(e->ifindex));
157*de1e4e89SAndroid Build Coastguard Worker jsonw_string_field(jw_global, "grp", inet_ntop(af, src,
158*de1e4e89SAndroid Build Coastguard Worker abuf, sizeof(abuf)));
159*de1e4e89SAndroid Build Coastguard Worker jsonw_string_field(jw_global, "state",
160*de1e4e89SAndroid Build Coastguard Worker (e->state & MDB_PERMANENT) ? "permanent" : "temp");
161*de1e4e89SAndroid Build Coastguard Worker if (e->flags & MDB_FLAGS_OFFLOAD) {
162*de1e4e89SAndroid Build Coastguard Worker start_json_mdb_flags_array(&mdb_flags);
163*de1e4e89SAndroid Build Coastguard Worker jsonw_string(jw_global, "offload");
164*de1e4e89SAndroid Build Coastguard Worker }
165*de1e4e89SAndroid Build Coastguard Worker if (mdb_flags)
166*de1e4e89SAndroid Build Coastguard Worker jsonw_end_array(jw_global);
167*de1e4e89SAndroid Build Coastguard Worker } else{
168*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "dev %s port %s grp %s %s %s",
169*de1e4e89SAndroid Build Coastguard Worker ll_index_to_name(ifindex),
170*de1e4e89SAndroid Build Coastguard Worker ll_index_to_name(e->ifindex),
171*de1e4e89SAndroid Build Coastguard Worker inet_ntop(af, src, abuf, sizeof(abuf)),
172*de1e4e89SAndroid Build Coastguard Worker (e->state & MDB_PERMANENT) ? "permanent" : "temp",
173*de1e4e89SAndroid Build Coastguard Worker (e->flags & MDB_FLAGS_OFFLOAD) ? "offload" : "");
174*de1e4e89SAndroid Build Coastguard Worker }
175*de1e4e89SAndroid Build Coastguard Worker if (e->vid) {
176*de1e4e89SAndroid Build Coastguard Worker if (jw_global)
177*de1e4e89SAndroid Build Coastguard Worker jsonw_uint_field(jw_global, "vid", e->vid);
178*de1e4e89SAndroid Build Coastguard Worker else
179*de1e4e89SAndroid Build Coastguard Worker fprintf(f, " vid %hu", e->vid);
180*de1e4e89SAndroid Build Coastguard Worker }
181*de1e4e89SAndroid Build Coastguard Worker if (show_stats && tb && tb[MDBA_MDB_EATTR_TIMER]) {
182*de1e4e89SAndroid Build Coastguard Worker struct timeval tv;
183*de1e4e89SAndroid Build Coastguard Worker
184*de1e4e89SAndroid Build Coastguard Worker __jiffies_to_tv(&tv, rta_getattr_u32(tb[MDBA_MDB_EATTR_TIMER]));
185*de1e4e89SAndroid Build Coastguard Worker if (jw_global) {
186*de1e4e89SAndroid Build Coastguard Worker char formatted_time[9];
187*de1e4e89SAndroid Build Coastguard Worker
188*de1e4e89SAndroid Build Coastguard Worker snprintf(formatted_time, sizeof(formatted_time),
189*de1e4e89SAndroid Build Coastguard Worker "%4i.%.2i", (int)tv.tv_sec,
190*de1e4e89SAndroid Build Coastguard Worker (int)tv.tv_usec/10000);
191*de1e4e89SAndroid Build Coastguard Worker jsonw_string_field(jw_global, "timer", formatted_time);
192*de1e4e89SAndroid Build Coastguard Worker } else {
193*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "%4i.%.2i", (int)tv.tv_sec,
194*de1e4e89SAndroid Build Coastguard Worker (int)tv.tv_usec/10000);
195*de1e4e89SAndroid Build Coastguard Worker }
196*de1e4e89SAndroid Build Coastguard Worker }
197*de1e4e89SAndroid Build Coastguard Worker if (jw_global)
198*de1e4e89SAndroid Build Coastguard Worker jsonw_end_object(jw_global);
199*de1e4e89SAndroid Build Coastguard Worker else
200*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "\n");
201*de1e4e89SAndroid Build Coastguard Worker }
202*de1e4e89SAndroid Build Coastguard Worker
br_print_mdb_entry(FILE * f,int ifindex,struct rtattr * attr,struct nlmsghdr * n)203*de1e4e89SAndroid Build Coastguard Worker static void br_print_mdb_entry(FILE *f, int ifindex, struct rtattr *attr,
204*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr *n)
205*de1e4e89SAndroid Build Coastguard Worker {
206*de1e4e89SAndroid Build Coastguard Worker struct rtattr *etb[MDBA_MDB_EATTR_MAX + 1];
207*de1e4e89SAndroid Build Coastguard Worker struct br_mdb_entry *e;
208*de1e4e89SAndroid Build Coastguard Worker struct rtattr *i;
209*de1e4e89SAndroid Build Coastguard Worker int rem;
210*de1e4e89SAndroid Build Coastguard Worker
211*de1e4e89SAndroid Build Coastguard Worker rem = RTA_PAYLOAD(attr);
212*de1e4e89SAndroid Build Coastguard Worker for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
213*de1e4e89SAndroid Build Coastguard Worker e = RTA_DATA(i);
214*de1e4e89SAndroid Build Coastguard Worker parse_rtattr(etb, MDBA_MDB_EATTR_MAX, MDB_RTA(RTA_DATA(i)),
215*de1e4e89SAndroid Build Coastguard Worker RTA_PAYLOAD(i) - RTA_ALIGN(sizeof(*e)));
216*de1e4e89SAndroid Build Coastguard Worker print_mdb_entry(f, ifindex, e, n, etb);
217*de1e4e89SAndroid Build Coastguard Worker }
218*de1e4e89SAndroid Build Coastguard Worker }
219*de1e4e89SAndroid Build Coastguard Worker
print_mdb(const struct sockaddr_nl * who,struct nlmsghdr * n,void * arg)220*de1e4e89SAndroid Build Coastguard Worker int print_mdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
221*de1e4e89SAndroid Build Coastguard Worker {
222*de1e4e89SAndroid Build Coastguard Worker FILE *fp = arg;
223*de1e4e89SAndroid Build Coastguard Worker struct br_port_msg *r = NLMSG_DATA(n);
224*de1e4e89SAndroid Build Coastguard Worker int len = n->nlmsg_len;
225*de1e4e89SAndroid Build Coastguard Worker struct rtattr *tb[MDBA_MAX+1], *i;
226*de1e4e89SAndroid Build Coastguard Worker
227*de1e4e89SAndroid Build Coastguard Worker if (n->nlmsg_type != RTM_GETMDB && n->nlmsg_type != RTM_NEWMDB && n->nlmsg_type != RTM_DELMDB) {
228*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Not RTM_GETMDB, RTM_NEWMDB or RTM_DELMDB: %08x %08x %08x\n",
229*de1e4e89SAndroid Build Coastguard Worker n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
230*de1e4e89SAndroid Build Coastguard Worker
231*de1e4e89SAndroid Build Coastguard Worker return 0;
232*de1e4e89SAndroid Build Coastguard Worker }
233*de1e4e89SAndroid Build Coastguard Worker
234*de1e4e89SAndroid Build Coastguard Worker len -= NLMSG_LENGTH(sizeof(*r));
235*de1e4e89SAndroid Build Coastguard Worker if (len < 0) {
236*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
237*de1e4e89SAndroid Build Coastguard Worker return -1;
238*de1e4e89SAndroid Build Coastguard Worker }
239*de1e4e89SAndroid Build Coastguard Worker
240*de1e4e89SAndroid Build Coastguard Worker if (filter_index && filter_index != r->ifindex)
241*de1e4e89SAndroid Build Coastguard Worker return 0;
242*de1e4e89SAndroid Build Coastguard Worker
243*de1e4e89SAndroid Build Coastguard Worker parse_rtattr(tb, MDBA_MAX, MDBA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
244*de1e4e89SAndroid Build Coastguard Worker
245*de1e4e89SAndroid Build Coastguard Worker if (tb[MDBA_MDB] && print_mdb_entries) {
246*de1e4e89SAndroid Build Coastguard Worker int rem = RTA_PAYLOAD(tb[MDBA_MDB]);
247*de1e4e89SAndroid Build Coastguard Worker
248*de1e4e89SAndroid Build Coastguard Worker for (i = RTA_DATA(tb[MDBA_MDB]); RTA_OK(i, rem); i = RTA_NEXT(i, rem))
249*de1e4e89SAndroid Build Coastguard Worker br_print_mdb_entry(fp, r->ifindex, i, n);
250*de1e4e89SAndroid Build Coastguard Worker }
251*de1e4e89SAndroid Build Coastguard Worker
252*de1e4e89SAndroid Build Coastguard Worker if (tb[MDBA_ROUTER] && print_mdb_router) {
253*de1e4e89SAndroid Build Coastguard Worker if (n->nlmsg_type == RTM_GETMDB) {
254*de1e4e89SAndroid Build Coastguard Worker if (show_details)
255*de1e4e89SAndroid Build Coastguard Worker br_print_router_ports(fp, tb[MDBA_ROUTER],
256*de1e4e89SAndroid Build Coastguard Worker r->ifindex);
257*de1e4e89SAndroid Build Coastguard Worker } else {
258*de1e4e89SAndroid Build Coastguard Worker uint32_t *port_ifindex;
259*de1e4e89SAndroid Build Coastguard Worker
260*de1e4e89SAndroid Build Coastguard Worker i = RTA_DATA(tb[MDBA_ROUTER]);
261*de1e4e89SAndroid Build Coastguard Worker port_ifindex = RTA_DATA(i);
262*de1e4e89SAndroid Build Coastguard Worker if (n->nlmsg_type == RTM_DELMDB) {
263*de1e4e89SAndroid Build Coastguard Worker if (jw_global)
264*de1e4e89SAndroid Build Coastguard Worker jsonw_string_field(jw_global,
265*de1e4e89SAndroid Build Coastguard Worker "opCode",
266*de1e4e89SAndroid Build Coastguard Worker "deleted");
267*de1e4e89SAndroid Build Coastguard Worker else
268*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, "Deleted ");
269*de1e4e89SAndroid Build Coastguard Worker }
270*de1e4e89SAndroid Build Coastguard Worker if (jw_global) {
271*de1e4e89SAndroid Build Coastguard Worker jsonw_name(jw_global,
272*de1e4e89SAndroid Build Coastguard Worker ll_index_to_name(r->ifindex));
273*de1e4e89SAndroid Build Coastguard Worker jsonw_start_array(jw_global);
274*de1e4e89SAndroid Build Coastguard Worker jsonw_start_object(jw_global);
275*de1e4e89SAndroid Build Coastguard Worker jsonw_string_field(jw_global, "port",
276*de1e4e89SAndroid Build Coastguard Worker ll_index_to_name(*port_ifindex));
277*de1e4e89SAndroid Build Coastguard Worker jsonw_end_object(jw_global);
278*de1e4e89SAndroid Build Coastguard Worker jsonw_end_array(jw_global);
279*de1e4e89SAndroid Build Coastguard Worker } else {
280*de1e4e89SAndroid Build Coastguard Worker fprintf(fp, "router port dev %s master %s\n",
281*de1e4e89SAndroid Build Coastguard Worker ll_index_to_name(*port_ifindex),
282*de1e4e89SAndroid Build Coastguard Worker ll_index_to_name(r->ifindex));
283*de1e4e89SAndroid Build Coastguard Worker }
284*de1e4e89SAndroid Build Coastguard Worker }
285*de1e4e89SAndroid Build Coastguard Worker }
286*de1e4e89SAndroid Build Coastguard Worker
287*de1e4e89SAndroid Build Coastguard Worker if (!jw_global)
288*de1e4e89SAndroid Build Coastguard Worker fflush(fp);
289*de1e4e89SAndroid Build Coastguard Worker
290*de1e4e89SAndroid Build Coastguard Worker return 0;
291*de1e4e89SAndroid Build Coastguard Worker }
292*de1e4e89SAndroid Build Coastguard Worker
mdb_show(int argc,char ** argv)293*de1e4e89SAndroid Build Coastguard Worker static int mdb_show(int argc, char **argv)
294*de1e4e89SAndroid Build Coastguard Worker {
295*de1e4e89SAndroid Build Coastguard Worker char *filter_dev = NULL;
296*de1e4e89SAndroid Build Coastguard Worker
297*de1e4e89SAndroid Build Coastguard Worker while (argc > 0) {
298*de1e4e89SAndroid Build Coastguard Worker if (strcmp(*argv, "dev") == 0) {
299*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
300*de1e4e89SAndroid Build Coastguard Worker if (filter_dev)
301*de1e4e89SAndroid Build Coastguard Worker duparg("dev", *argv);
302*de1e4e89SAndroid Build Coastguard Worker filter_dev = *argv;
303*de1e4e89SAndroid Build Coastguard Worker } else if (strcmp(*argv, "vid") == 0) {
304*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
305*de1e4e89SAndroid Build Coastguard Worker if (filter_vlan)
306*de1e4e89SAndroid Build Coastguard Worker duparg("vid", *argv);
307*de1e4e89SAndroid Build Coastguard Worker filter_vlan = atoi(*argv);
308*de1e4e89SAndroid Build Coastguard Worker }
309*de1e4e89SAndroid Build Coastguard Worker argc--; argv++;
310*de1e4e89SAndroid Build Coastguard Worker }
311*de1e4e89SAndroid Build Coastguard Worker
312*de1e4e89SAndroid Build Coastguard Worker if (filter_dev) {
313*de1e4e89SAndroid Build Coastguard Worker filter_index = if_nametoindex(filter_dev);
314*de1e4e89SAndroid Build Coastguard Worker if (filter_index == 0) {
315*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Cannot find device \"%s\"\n",
316*de1e4e89SAndroid Build Coastguard Worker filter_dev);
317*de1e4e89SAndroid Build Coastguard Worker return -1;
318*de1e4e89SAndroid Build Coastguard Worker }
319*de1e4e89SAndroid Build Coastguard Worker }
320*de1e4e89SAndroid Build Coastguard Worker
321*de1e4e89SAndroid Build Coastguard Worker /* get mdb entries*/
322*de1e4e89SAndroid Build Coastguard Worker if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETMDB) < 0) {
323*de1e4e89SAndroid Build Coastguard Worker perror("Cannot send dump request");
324*de1e4e89SAndroid Build Coastguard Worker return -1;
325*de1e4e89SAndroid Build Coastguard Worker }
326*de1e4e89SAndroid Build Coastguard Worker
327*de1e4e89SAndroid Build Coastguard Worker if (!json_output) {
328*de1e4e89SAndroid Build Coastguard Worker /* Normal output */
329*de1e4e89SAndroid Build Coastguard Worker if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) {
330*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Dump terminated\n");
331*de1e4e89SAndroid Build Coastguard Worker return -1;
332*de1e4e89SAndroid Build Coastguard Worker }
333*de1e4e89SAndroid Build Coastguard Worker return 0;
334*de1e4e89SAndroid Build Coastguard Worker }
335*de1e4e89SAndroid Build Coastguard Worker /* Json output */
336*de1e4e89SAndroid Build Coastguard Worker jw_global = jsonw_new(stdout);
337*de1e4e89SAndroid Build Coastguard Worker jsonw_pretty(jw_global, 1);
338*de1e4e89SAndroid Build Coastguard Worker jsonw_start_object(jw_global);
339*de1e4e89SAndroid Build Coastguard Worker jsonw_name(jw_global, "mdb");
340*de1e4e89SAndroid Build Coastguard Worker jsonw_start_array(jw_global);
341*de1e4e89SAndroid Build Coastguard Worker
342*de1e4e89SAndroid Build Coastguard Worker /* print mdb entries */
343*de1e4e89SAndroid Build Coastguard Worker print_mdb_entries = true;
344*de1e4e89SAndroid Build Coastguard Worker print_mdb_router = false;
345*de1e4e89SAndroid Build Coastguard Worker if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) {
346*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Dump terminated\n");
347*de1e4e89SAndroid Build Coastguard Worker return -1;
348*de1e4e89SAndroid Build Coastguard Worker }
349*de1e4e89SAndroid Build Coastguard Worker jsonw_end_array(jw_global);
350*de1e4e89SAndroid Build Coastguard Worker
351*de1e4e89SAndroid Build Coastguard Worker /* get router ports */
352*de1e4e89SAndroid Build Coastguard Worker if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETMDB) < 0) {
353*de1e4e89SAndroid Build Coastguard Worker perror("Cannot send dump request");
354*de1e4e89SAndroid Build Coastguard Worker return -1;
355*de1e4e89SAndroid Build Coastguard Worker }
356*de1e4e89SAndroid Build Coastguard Worker jsonw_name(jw_global, "router");
357*de1e4e89SAndroid Build Coastguard Worker jsonw_start_object(jw_global);
358*de1e4e89SAndroid Build Coastguard Worker
359*de1e4e89SAndroid Build Coastguard Worker /* print router ports */
360*de1e4e89SAndroid Build Coastguard Worker print_mdb_entries = false;
361*de1e4e89SAndroid Build Coastguard Worker print_mdb_router = true;
362*de1e4e89SAndroid Build Coastguard Worker if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) {
363*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Dump terminated\n");
364*de1e4e89SAndroid Build Coastguard Worker return -1;
365*de1e4e89SAndroid Build Coastguard Worker }
366*de1e4e89SAndroid Build Coastguard Worker jsonw_end_object(jw_global);
367*de1e4e89SAndroid Build Coastguard Worker jsonw_end_object(jw_global);
368*de1e4e89SAndroid Build Coastguard Worker jsonw_destroy(&jw_global);
369*de1e4e89SAndroid Build Coastguard Worker
370*de1e4e89SAndroid Build Coastguard Worker return 0;
371*de1e4e89SAndroid Build Coastguard Worker }
372*de1e4e89SAndroid Build Coastguard Worker
mdb_modify(int cmd,int flags,int argc,char ** argv)373*de1e4e89SAndroid Build Coastguard Worker static int mdb_modify(int cmd, int flags, int argc, char **argv)
374*de1e4e89SAndroid Build Coastguard Worker {
375*de1e4e89SAndroid Build Coastguard Worker struct {
376*de1e4e89SAndroid Build Coastguard Worker struct nlmsghdr n;
377*de1e4e89SAndroid Build Coastguard Worker struct br_port_msg bpm;
378*de1e4e89SAndroid Build Coastguard Worker char buf[1024];
379*de1e4e89SAndroid Build Coastguard Worker } req = {
380*de1e4e89SAndroid Build Coastguard Worker .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_port_msg)),
381*de1e4e89SAndroid Build Coastguard Worker .n.nlmsg_flags = NLM_F_REQUEST | flags,
382*de1e4e89SAndroid Build Coastguard Worker .n.nlmsg_type = cmd,
383*de1e4e89SAndroid Build Coastguard Worker .bpm.family = PF_BRIDGE,
384*de1e4e89SAndroid Build Coastguard Worker };
385*de1e4e89SAndroid Build Coastguard Worker struct br_mdb_entry entry = {};
386*de1e4e89SAndroid Build Coastguard Worker char *d = NULL, *p = NULL, *grp = NULL;
387*de1e4e89SAndroid Build Coastguard Worker short vid = 0;
388*de1e4e89SAndroid Build Coastguard Worker
389*de1e4e89SAndroid Build Coastguard Worker while (argc > 0) {
390*de1e4e89SAndroid Build Coastguard Worker if (strcmp(*argv, "dev") == 0) {
391*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
392*de1e4e89SAndroid Build Coastguard Worker d = *argv;
393*de1e4e89SAndroid Build Coastguard Worker } else if (strcmp(*argv, "grp") == 0) {
394*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
395*de1e4e89SAndroid Build Coastguard Worker grp = *argv;
396*de1e4e89SAndroid Build Coastguard Worker } else if (strcmp(*argv, "port") == 0) {
397*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
398*de1e4e89SAndroid Build Coastguard Worker p = *argv;
399*de1e4e89SAndroid Build Coastguard Worker } else if (strcmp(*argv, "permanent") == 0) {
400*de1e4e89SAndroid Build Coastguard Worker if (cmd == RTM_NEWMDB)
401*de1e4e89SAndroid Build Coastguard Worker entry.state |= MDB_PERMANENT;
402*de1e4e89SAndroid Build Coastguard Worker } else if (strcmp(*argv, "temp") == 0) {
403*de1e4e89SAndroid Build Coastguard Worker ;/* nothing */
404*de1e4e89SAndroid Build Coastguard Worker } else if (strcmp(*argv, "vid") == 0) {
405*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
406*de1e4e89SAndroid Build Coastguard Worker vid = atoi(*argv);
407*de1e4e89SAndroid Build Coastguard Worker } else {
408*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "help") == 0)
409*de1e4e89SAndroid Build Coastguard Worker usage();
410*de1e4e89SAndroid Build Coastguard Worker }
411*de1e4e89SAndroid Build Coastguard Worker argc--; argv++;
412*de1e4e89SAndroid Build Coastguard Worker }
413*de1e4e89SAndroid Build Coastguard Worker
414*de1e4e89SAndroid Build Coastguard Worker if (d == NULL || grp == NULL || p == NULL) {
415*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Device, group address and port name are required arguments.\n");
416*de1e4e89SAndroid Build Coastguard Worker return -1;
417*de1e4e89SAndroid Build Coastguard Worker }
418*de1e4e89SAndroid Build Coastguard Worker
419*de1e4e89SAndroid Build Coastguard Worker req.bpm.ifindex = ll_name_to_index(d);
420*de1e4e89SAndroid Build Coastguard Worker if (req.bpm.ifindex == 0) {
421*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Cannot find device \"%s\"\n", d);
422*de1e4e89SAndroid Build Coastguard Worker return -1;
423*de1e4e89SAndroid Build Coastguard Worker }
424*de1e4e89SAndroid Build Coastguard Worker
425*de1e4e89SAndroid Build Coastguard Worker entry.ifindex = ll_name_to_index(p);
426*de1e4e89SAndroid Build Coastguard Worker if (entry.ifindex == 0) {
427*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Cannot find device \"%s\"\n", p);
428*de1e4e89SAndroid Build Coastguard Worker return -1;
429*de1e4e89SAndroid Build Coastguard Worker }
430*de1e4e89SAndroid Build Coastguard Worker
431*de1e4e89SAndroid Build Coastguard Worker if (!inet_pton(AF_INET, grp, &entry.addr.u.ip4)) {
432*de1e4e89SAndroid Build Coastguard Worker if (!inet_pton(AF_INET6, grp, &entry.addr.u.ip6)) {
433*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Invalid address \"%s\"\n", grp);
434*de1e4e89SAndroid Build Coastguard Worker return -1;
435*de1e4e89SAndroid Build Coastguard Worker } else
436*de1e4e89SAndroid Build Coastguard Worker entry.addr.proto = htons(ETH_P_IPV6);
437*de1e4e89SAndroid Build Coastguard Worker } else
438*de1e4e89SAndroid Build Coastguard Worker entry.addr.proto = htons(ETH_P_IP);
439*de1e4e89SAndroid Build Coastguard Worker
440*de1e4e89SAndroid Build Coastguard Worker entry.vid = vid;
441*de1e4e89SAndroid Build Coastguard Worker addattr_l(&req.n, sizeof(req), MDBA_SET_ENTRY, &entry, sizeof(entry));
442*de1e4e89SAndroid Build Coastguard Worker
443*de1e4e89SAndroid Build Coastguard Worker if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
444*de1e4e89SAndroid Build Coastguard Worker return -1;
445*de1e4e89SAndroid Build Coastguard Worker
446*de1e4e89SAndroid Build Coastguard Worker return 0;
447*de1e4e89SAndroid Build Coastguard Worker }
448*de1e4e89SAndroid Build Coastguard Worker
do_mdb(int argc,char ** argv)449*de1e4e89SAndroid Build Coastguard Worker int do_mdb(int argc, char **argv)
450*de1e4e89SAndroid Build Coastguard Worker {
451*de1e4e89SAndroid Build Coastguard Worker ll_init_map(&rth);
452*de1e4e89SAndroid Build Coastguard Worker
453*de1e4e89SAndroid Build Coastguard Worker if (argc > 0) {
454*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "add") == 0)
455*de1e4e89SAndroid Build Coastguard Worker return mdb_modify(RTM_NEWMDB, NLM_F_CREATE|NLM_F_EXCL, argc-1, argv+1);
456*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "delete") == 0)
457*de1e4e89SAndroid Build Coastguard Worker return mdb_modify(RTM_DELMDB, 0, argc-1, argv+1);
458*de1e4e89SAndroid Build Coastguard Worker
459*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "show") == 0 ||
460*de1e4e89SAndroid Build Coastguard Worker matches(*argv, "lst") == 0 ||
461*de1e4e89SAndroid Build Coastguard Worker matches(*argv, "list") == 0)
462*de1e4e89SAndroid Build Coastguard Worker return mdb_show(argc-1, argv+1);
463*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "help") == 0)
464*de1e4e89SAndroid Build Coastguard Worker usage();
465*de1e4e89SAndroid Build Coastguard Worker } else
466*de1e4e89SAndroid Build Coastguard Worker return mdb_show(0, NULL);
467*de1e4e89SAndroid Build Coastguard Worker
468*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Command \"%s\" is unknown, try \"bridge mdb help\".\n", *argv);
469*de1e4e89SAndroid Build Coastguard Worker exit(-1);
470*de1e4e89SAndroid Build Coastguard Worker }
471