mdb.c revision 9dca899b2d97163f18b66c21b5e7acec893b0fa4
1/*
2 * Get mdb table with netlink
3 */
4
5#include <stdio.h>
6#include <stdlib.h>
7#include <unistd.h>
8#include <fcntl.h>
9#include <sys/socket.h>
10#include <net/if.h>
11#include <netinet/in.h>
12#include <linux/if_bridge.h>
13#include <linux/if_ether.h>
14#include <string.h>
15#include <arpa/inet.h>
16
17#include "libnetlink.h"
18#include "br_common.h"
19#include "rt_names.h"
20#include "utils.h"
21
22#ifndef MDBA_RTA
23#define MDBA_RTA(r) \
24	((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct br_port_msg))))
25#endif
26
27static unsigned int filter_index;
28
29static void usage(void)
30{
31	fprintf(stderr, "Usage: bridge mdb { add | del } dev DEV port PORT grp GROUP [permanent | temp]\n");
32	fprintf(stderr, "       bridge mdb {show} [ dev DEV ]\n");
33	exit(-1);
34}
35
36static void br_print_router_ports(FILE *f, struct rtattr *attr)
37{
38	uint32_t *port_ifindex;
39	struct rtattr *i;
40	int rem;
41
42	rem = RTA_PAYLOAD(attr);
43	for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
44		port_ifindex = RTA_DATA(i);
45		fprintf(f, "%s ", ll_index_to_name(*port_ifindex));
46	}
47
48	fprintf(f, "\n");
49}
50
51static void print_mdb_entry(FILE *f, int ifindex, struct br_mdb_entry *e)
52{
53	SPRINT_BUF(abuf);
54
55	if (e->addr.proto == htons(ETH_P_IP))
56		fprintf(f, "dev %s port %s grp %s %s\n", ll_index_to_name(ifindex),
57			ll_index_to_name(e->ifindex),
58			inet_ntop(AF_INET, &e->addr.u.ip4, abuf, sizeof(abuf)),
59			(e->state & MDB_PERMANENT) ? "permanent" : "temp");
60	else
61		fprintf(f, "dev %s port %s grp %s %s\n", ll_index_to_name(ifindex),
62			ll_index_to_name(e->ifindex),
63			inet_ntop(AF_INET6, &e->addr.u.ip6, abuf, sizeof(abuf)),
64			(e->state & MDB_PERMANENT) ? "permanent" : "temp");
65}
66
67static void br_print_mdb_entry(FILE *f, int ifindex, struct rtattr *attr)
68{
69	struct rtattr *i;
70	int rem;
71	struct br_mdb_entry *e;
72
73	rem = RTA_PAYLOAD(attr);
74	for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
75		e = RTA_DATA(i);
76		print_mdb_entry(f, ifindex, e);
77	}
78}
79
80int print_mdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
81{
82	FILE *fp = arg;
83	struct br_port_msg *r = NLMSG_DATA(n);
84	int len = n->nlmsg_len;
85	struct rtattr * tb[MDBA_MAX+1];
86
87	if (n->nlmsg_type != RTM_GETMDB && n->nlmsg_type != RTM_NEWMDB && n->nlmsg_type != RTM_DELMDB) {
88		fprintf(stderr, "Not RTM_GETMDB, RTM_NEWMDB or RTM_DELMDB: %08x %08x %08x\n",
89			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
90
91		return 0;
92	}
93
94	len -= NLMSG_LENGTH(sizeof(*r));
95	if (len < 0) {
96		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
97		return -1;
98	}
99
100	if (filter_index && filter_index != r->ifindex)
101		return 0;
102
103	parse_rtattr(tb, MDBA_MAX, MDBA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
104
105	if (tb[MDBA_MDB]) {
106		struct rtattr *i;
107		int rem = RTA_PAYLOAD(tb[MDBA_MDB]);
108
109		for (i = RTA_DATA(tb[MDBA_MDB]); RTA_OK(i, rem); i = RTA_NEXT(i, rem))
110			br_print_mdb_entry(fp, r->ifindex, i);
111	}
112
113	if (tb[MDBA_ROUTER]) {
114		if (show_details) {
115			fprintf(fp, "router ports on %s: ", ll_index_to_name(r->ifindex));
116			br_print_router_ports(fp, tb[MDBA_ROUTER]);
117		}
118	}
119
120	return 0;
121}
122
123static int mdb_show(int argc, char **argv)
124{
125	char *filter_dev = NULL;
126
127	while (argc > 0) {
128		if (strcmp(*argv, "dev") == 0) {
129			NEXT_ARG();
130			if (filter_dev)
131				duparg("dev", *argv);
132			filter_dev = *argv;
133		}
134		argc--; argv++;
135	}
136
137	if (filter_dev) {
138		filter_index = if_nametoindex(filter_dev);
139		if (filter_index == 0) {
140			fprintf(stderr, "Cannot find device \"%s\"\n",
141				filter_dev);
142			return -1;
143		}
144	}
145
146	if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETMDB) < 0) {
147		perror("Cannot send dump request");
148		exit(1);
149	}
150
151	if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) {
152		fprintf(stderr, "Dump terminated\n");
153		exit(1);
154	}
155
156	return 0;
157}
158
159static int mdb_modify(int cmd, int flags, int argc, char **argv)
160{
161	struct {
162		struct nlmsghdr 	n;
163		struct br_port_msg	bpm;
164		char   			buf[1024];
165	} req;
166	struct br_mdb_entry entry;
167	char *d = NULL, *p = NULL, *grp = NULL;
168
169	memset(&req, 0, sizeof(req));
170	memset(&entry, 0, sizeof(entry));
171
172	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_port_msg));
173	req.n.nlmsg_flags = NLM_F_REQUEST|flags;
174	req.n.nlmsg_type = cmd;
175	req.bpm.family = PF_BRIDGE;
176
177	while (argc > 0) {
178		if (strcmp(*argv, "dev") == 0) {
179			NEXT_ARG();
180			d = *argv;
181		} else if (strcmp(*argv, "grp") == 0) {
182			NEXT_ARG();
183			grp = *argv;
184		} else if (strcmp(*argv, "port") == 0) {
185			NEXT_ARG();
186			p = *argv;
187		} else if (strcmp(*argv, "permanent") == 0) {
188			if (cmd == RTM_NEWMDB)
189				entry.state |= MDB_PERMANENT;
190		} else if (strcmp(*argv, "temp") == 0) {
191			;/* nothing */
192		} else {
193			if (matches(*argv, "help") == 0)
194				usage();
195		}
196		argc--; argv++;
197	}
198
199	if (d == NULL || grp == NULL || p == NULL) {
200		fprintf(stderr, "Device, group address and port name are required arguments.\n");
201		exit(-1);
202	}
203
204	req.bpm.ifindex = ll_name_to_index(d);
205	if (req.bpm.ifindex == 0) {
206		fprintf(stderr, "Cannot find device \"%s\"\n", d);
207		return -1;
208	}
209
210	entry.ifindex = ll_name_to_index(p);
211	if (entry.ifindex == 0) {
212		fprintf(stderr, "Cannot find device \"%s\"\n", p);
213		return -1;
214	}
215
216	if (!inet_pton(AF_INET, grp, &entry.addr.u.ip4)) {
217		if (!inet_pton(AF_INET6, grp, &entry.addr.u.ip6)) {
218			fprintf(stderr, "Invalid address \"%s\"\n", grp);
219			return -1;
220		} else
221			entry.addr.proto = htons(ETH_P_IPV6);
222	} else
223		entry.addr.proto = htons(ETH_P_IP);
224
225	addattr_l(&req.n, sizeof(req), MDBA_SET_ENTRY, &entry, sizeof(entry));
226
227	if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
228		exit(2);
229
230	return 0;
231}
232
233int do_mdb(int argc, char **argv)
234{
235	ll_init_map(&rth);
236
237	if (argc > 0) {
238		if (matches(*argv, "add") == 0)
239			return mdb_modify(RTM_NEWMDB, NLM_F_CREATE|NLM_F_EXCL, argc-1, argv+1);
240		if (matches(*argv, "delete") == 0)
241			return mdb_modify(RTM_DELMDB, 0, argc-1, argv+1);
242
243		if (matches(*argv, "show") == 0 ||
244		    matches(*argv, "lst") == 0 ||
245		    matches(*argv, "list") == 0)
246			return mdb_show(argc-1, argv+1);
247		if (matches(*argv, "help") == 0)
248			usage();
249	} else
250		return mdb_show(0, NULL);
251
252	fprintf(stderr, "Command \"%s\" is unknown, try \"bridge mdb help\".\n", *argv);
253	exit(-1);
254}
255