xref: /aosp_15_r20/external/iproute2/bridge/mdb.c (revision de1e4e894b0c224df933550f0afdecc354b238c4)
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