• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Get/set/delete fdb table with netlink
3  *
4  * TODO: merge/replace this with ip neighbour
5  *
6  * Authors:	Stephen Hemminger <shemminger@vyatta.com>
7  */
8 
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <unistd.h>
12 #include <netdb.h>
13 #include <time.h>
14 #include <fcntl.h>
15 #include <sys/socket.h>
16 #include <sys/time.h>
17 #include <net/if.h>
18 #include <netinet/in.h>
19 #include <linux/if_bridge.h>
20 #include <linux/if_ether.h>
21 #include <linux/neighbour.h>
22 #include <string.h>
23 #include <limits.h>
24 
25 #include "libnetlink.h"
26 #include "br_common.h"
27 #include "rt_names.h"
28 #include "utils.h"
29 
30 static unsigned int filter_index;
31 
usage(void)32 static void usage(void)
33 {
34 	fprintf(stderr, "Usage: bridge fdb { add | append | del | replace } ADDR dev DEV\n"
35 			"              [ self ] [ master ] [ use ] [ router ]\n"
36 			"              [ local | temp ] [ dst IPADDR ] [ vlan VID ]\n"
37 		        "              [ port PORT] [ vni VNI ] [ via DEV ]\n");
38 	fprintf(stderr, "       bridge fdb [ show [ br BRDEV ] [ brport DEV ] ]\n");
39 	exit(-1);
40 }
41 
state_n2a(unsigned s)42 static const char *state_n2a(unsigned s)
43 {
44 	static char buf[32];
45 
46 	if (s & NUD_PERMANENT)
47 		return "permanent";
48 
49 	if (s & NUD_NOARP)
50 		return "static";
51 
52 	if (s & NUD_STALE)
53 		return "stale";
54 
55 	if (s & NUD_REACHABLE)
56 		return "";
57 
58 	sprintf(buf, "state=%#x", s);
59 	return buf;
60 }
61 
print_fdb(const struct sockaddr_nl * who,struct nlmsghdr * n,void * arg)62 int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
63 {
64 	FILE *fp = arg;
65 	struct ndmsg *r = NLMSG_DATA(n);
66 	int len = n->nlmsg_len;
67 	struct rtattr * tb[NDA_MAX+1];
68 
69 	if (n->nlmsg_type != RTM_NEWNEIGH && n->nlmsg_type != RTM_DELNEIGH) {
70 		fprintf(stderr, "Not RTM_NEWNEIGH: %08x %08x %08x\n",
71 			n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
72 
73 		return 0;
74 	}
75 
76 	len -= NLMSG_LENGTH(sizeof(*r));
77 	if (len < 0) {
78 		fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
79 		return -1;
80 	}
81 
82 	if (r->ndm_family != AF_BRIDGE)
83 		return 0;
84 
85 	if (filter_index && filter_index != r->ndm_ifindex)
86 		return 0;
87 
88 	parse_rtattr(tb, NDA_MAX, NDA_RTA(r),
89 		     n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
90 
91 	if (n->nlmsg_type == RTM_DELNEIGH)
92 		fprintf(fp, "Deleted ");
93 
94 	if (tb[NDA_LLADDR]) {
95 		SPRINT_BUF(b1);
96 		fprintf(fp, "%s ",
97 			ll_addr_n2a(RTA_DATA(tb[NDA_LLADDR]),
98 				    RTA_PAYLOAD(tb[NDA_LLADDR]),
99 				    ll_index_to_type(r->ndm_ifindex),
100 				    b1, sizeof(b1)));
101 	}
102 
103 	if (!filter_index && r->ndm_ifindex)
104 		fprintf(fp, "dev %s ", ll_index_to_name(r->ndm_ifindex));
105 
106 	if (tb[NDA_DST]) {
107 		SPRINT_BUF(abuf);
108 		int family = AF_INET;
109 
110 		if (RTA_PAYLOAD(tb[NDA_DST]) == sizeof(struct in6_addr))
111 			family = AF_INET6;
112 
113 		fprintf(fp, "dst %s ",
114 			format_host(family,
115 				    RTA_PAYLOAD(tb[NDA_DST]),
116 				    RTA_DATA(tb[NDA_DST]),
117 				    abuf, sizeof(abuf)));
118 	}
119 
120 	if (tb[NDA_VLAN]) {
121 		__u16 vid = rta_getattr_u16(tb[NDA_VLAN]);
122 		fprintf(fp, "vlan %hu ", vid);
123 	}
124 
125 	if (tb[NDA_PORT])
126 		fprintf(fp, "port %d ", ntohs(rta_getattr_u16(tb[NDA_PORT])));
127 	if (tb[NDA_VNI])
128 		fprintf(fp, "vni %d ", rta_getattr_u32(tb[NDA_VNI]));
129 	if (tb[NDA_IFINDEX]) {
130 		unsigned int ifindex = rta_getattr_u32(tb[NDA_IFINDEX]);
131 
132 		if (ifindex) {
133 			char ifname[IF_NAMESIZE];
134 
135 			if (!tb[NDA_LINK_NETNSID] &&
136 			    if_indextoname(ifindex, ifname))
137 				fprintf(fp, "via %s ", ifname);
138 			else
139 				fprintf(fp, "via ifindex %u ", ifindex);
140 		}
141 	}
142 	if (tb[NDA_LINK_NETNSID])
143 		fprintf(fp, "link-netnsid %d ",
144 			rta_getattr_u32(tb[NDA_LINK_NETNSID]));
145 
146 	if (show_stats && tb[NDA_CACHEINFO]) {
147 		struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]);
148 		int hz = get_user_hz();
149 
150 		fprintf(fp, "used %d/%d ", ci->ndm_used/hz,
151 		       ci->ndm_updated/hz);
152 	}
153 	if (r->ndm_flags & NTF_SELF)
154 		fprintf(fp, "self ");
155 	if (tb[NDA_MASTER])
156 		fprintf(fp, "master %s ",
157 			ll_index_to_name(rta_getattr_u32(tb[NDA_MASTER])));
158 	else if (r->ndm_flags & NTF_MASTER)
159 		fprintf(fp, "master ");
160 	if (r->ndm_flags & NTF_ROUTER)
161 		fprintf(fp, "router ");
162 	if (r->ndm_flags & NTF_EXT_LEARNED)
163 		fprintf(fp, "offload ");
164 
165 	fprintf(fp, "%s\n", state_n2a(r->ndm_state));
166 	fflush(fp);
167 
168 	return 0;
169 }
170 
fdb_show(int argc,char ** argv)171 static int fdb_show(int argc, char **argv)
172 {
173 	struct {
174 		struct nlmsghdr 	n;
175 		struct ifinfomsg	ifm;
176 		char   			buf[256];
177 	} req;
178 
179 	char *filter_dev = NULL;
180 	char *br = NULL;
181 	int msg_size = sizeof(struct ifinfomsg);
182 
183 	memset(&req, 0, sizeof(req));
184 	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
185 	req.ifm.ifi_family = PF_BRIDGE;
186 
187 	while (argc > 0) {
188 		if ((strcmp(*argv, "brport") == 0) || strcmp(*argv, "dev") == 0) {
189 			NEXT_ARG();
190 			filter_dev = *argv;
191 		} else if (strcmp(*argv, "br") == 0) {
192 			NEXT_ARG();
193 			br = *argv;
194 		} else {
195 			if (matches(*argv, "help") == 0)
196 				usage();
197 		}
198 		argc--; argv++;
199 	}
200 
201 	if (br) {
202 		int br_ifindex = ll_name_to_index(br);
203 		if (br_ifindex == 0) {
204 			fprintf(stderr, "Cannot find bridge device \"%s\"\n", br);
205 			return -1;
206 		}
207 		addattr32(&req.n, sizeof(req), IFLA_MASTER, br_ifindex);
208 		msg_size += RTA_LENGTH(4);
209 	}
210 
211 	/*we'll keep around filter_dev for older kernels */
212 	if (filter_dev) {
213 		filter_index = if_nametoindex(filter_dev);
214 		if (filter_index == 0) {
215 			fprintf(stderr, "Cannot find device \"%s\"\n",
216 				filter_dev);
217 			return -1;
218 		}
219 		req.ifm.ifi_index = filter_index;
220 	}
221 
222 	if (rtnl_dump_request(&rth, RTM_GETNEIGH, &req.ifm, msg_size) < 0) {
223 		perror("Cannot send dump request");
224 		exit(1);
225 	}
226 
227 	if (rtnl_dump_filter(&rth, print_fdb, stdout) < 0) {
228 		fprintf(stderr, "Dump terminated\n");
229 		exit(1);
230 	}
231 
232 	return 0;
233 }
234 
fdb_modify(int cmd,int flags,int argc,char ** argv)235 static int fdb_modify(int cmd, int flags, int argc, char **argv)
236 {
237 	struct {
238 		struct nlmsghdr 	n;
239 		struct ndmsg 		ndm;
240 		char   			buf[256];
241 	} req;
242 	char *addr = NULL;
243 	char *d = NULL;
244 	char abuf[ETH_ALEN];
245 	int dst_ok = 0;
246 	inet_prefix dst;
247 	unsigned long port = 0;
248 	unsigned long vni = ~0;
249 	unsigned int via = 0;
250 	char *endptr;
251 	short vid = -1;
252 
253 	memset(&req, 0, sizeof(req));
254 
255 	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
256 	req.n.nlmsg_flags = NLM_F_REQUEST|flags;
257 	req.n.nlmsg_type = cmd;
258 	req.ndm.ndm_family = PF_BRIDGE;
259 	req.ndm.ndm_state = NUD_NOARP;
260 
261 	while (argc > 0) {
262 		if (strcmp(*argv, "dev") == 0) {
263 			NEXT_ARG();
264 			d = *argv;
265 		} else if (strcmp(*argv, "dst") == 0) {
266 			NEXT_ARG();
267 			if (dst_ok)
268 				duparg2("dst", *argv);
269 			get_addr(&dst, *argv, preferred_family);
270 			dst_ok = 1;
271 		} else if (strcmp(*argv, "port") == 0) {
272 
273 			NEXT_ARG();
274 			port = strtoul(*argv, &endptr, 0);
275 			if (endptr && *endptr) {
276 				struct servent *pse;
277 
278 				pse = getservbyname(*argv, "udp");
279 				if (!pse)
280 					invarg("invalid port\n", *argv);
281 				port = ntohs(pse->s_port);
282 			} else if (port > 0xffff)
283 				invarg("invalid port\n", *argv);
284 		} else if (strcmp(*argv, "vni") == 0) {
285 			NEXT_ARG();
286 			vni = strtoul(*argv, &endptr, 0);
287 			if ((endptr && *endptr) ||
288 			    (vni >> 24) || vni == ULONG_MAX)
289 				invarg("invalid VNI\n", *argv);
290 		} else if (strcmp(*argv, "via") == 0) {
291 			NEXT_ARG();
292 			via = if_nametoindex(*argv);
293 			if (via == 0)
294 				invarg("invalid device\n", *argv);
295 		} else if (strcmp(*argv, "self") == 0) {
296 			req.ndm.ndm_flags |= NTF_SELF;
297 		} else if (matches(*argv, "master") == 0) {
298 			req.ndm.ndm_flags |= NTF_MASTER;
299 		} else if (matches(*argv, "router") == 0) {
300 			req.ndm.ndm_flags |= NTF_ROUTER;
301 		} else if (matches(*argv, "local") == 0||
302 			   matches(*argv, "permanent") == 0) {
303 			req.ndm.ndm_state |= NUD_PERMANENT;
304 		} else if (matches(*argv, "temp") == 0) {
305 			req.ndm.ndm_state |= NUD_REACHABLE;
306 		} else if (matches(*argv, "vlan") == 0) {
307 			if (vid >= 0)
308 				duparg2("vlan", *argv);
309 			NEXT_ARG();
310 			vid = atoi(*argv);
311 		} else if (matches(*argv, "use") == 0) {
312 			req.ndm.ndm_flags |= NTF_USE;
313 		} else {
314 			if (strcmp(*argv, "to") == 0) {
315 				NEXT_ARG();
316 			}
317 			if (matches(*argv, "help") == 0)
318 				usage();
319 			if (addr)
320 				duparg2("to", *argv);
321 			addr = *argv;
322 		}
323 		argc--; argv++;
324 	}
325 
326 	if (d == NULL || addr == NULL) {
327 		fprintf(stderr, "Device and address are required arguments.\n");
328 		return -1;
329 	}
330 
331 	/* Assume self */
332 	if (!(req.ndm.ndm_flags&(NTF_SELF|NTF_MASTER)))
333 		req.ndm.ndm_flags |= NTF_SELF;
334 
335 	/* Assume permanent */
336 	if (!(req.ndm.ndm_state&(NUD_PERMANENT|NUD_REACHABLE)))
337 		req.ndm.ndm_state |= NUD_PERMANENT;
338 
339 	if (sscanf(addr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
340 		   abuf, abuf+1, abuf+2,
341 		   abuf+3, abuf+4, abuf+5) != 6) {
342 		fprintf(stderr, "Invalid mac address %s\n", addr);
343 		return -1;
344 	}
345 
346 	addattr_l(&req.n, sizeof(req), NDA_LLADDR, abuf, ETH_ALEN);
347 	if (dst_ok)
348 		addattr_l(&req.n, sizeof(req), NDA_DST, &dst.data, dst.bytelen);
349 
350 	if (vid >= 0)
351 		addattr16(&req.n, sizeof(req), NDA_VLAN, vid);
352 
353 	if (port) {
354 		unsigned short dport;
355 
356 		dport = htons((unsigned short)port);
357 		addattr16(&req.n, sizeof(req), NDA_PORT, dport);
358 	}
359 	if (vni != ~0)
360 		addattr32(&req.n, sizeof(req), NDA_VNI, vni);
361 	if (via)
362 		addattr32(&req.n, sizeof(req), NDA_IFINDEX, via);
363 
364 	req.ndm.ndm_ifindex = ll_name_to_index(d);
365 	if (req.ndm.ndm_ifindex == 0) {
366 		fprintf(stderr, "Cannot find device \"%s\"\n", d);
367 		return -1;
368 	}
369 
370 	if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
371 		return -1;
372 
373 	return 0;
374 }
375 
do_fdb(int argc,char ** argv)376 int do_fdb(int argc, char **argv)
377 {
378 	ll_init_map(&rth);
379 
380 	if (argc > 0) {
381 		if (matches(*argv, "add") == 0)
382 			return fdb_modify(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_EXCL, argc-1, argv+1);
383 		if (matches(*argv, "append") == 0)
384 			return fdb_modify(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_APPEND, argc-1, argv+1);
385 		if (matches(*argv, "replace") == 0)
386 			return fdb_modify(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_REPLACE, argc-1, argv+1);
387 		if (matches(*argv, "delete") == 0)
388 			return fdb_modify(RTM_DELNEIGH, 0, argc-1, argv+1);
389 		if (matches(*argv, "show") == 0 ||
390 		    matches(*argv, "lst") == 0 ||
391 		    matches(*argv, "list") == 0)
392 			return fdb_show(argc-1, argv+1);
393 		if (matches(*argv, "help") == 0)
394 			usage();
395 	} else
396 		return fdb_show(0, NULL);
397 
398 	fprintf(stderr, "Command \"%s\" is unknown, try \"bridge fdb help\".\n", *argv);
399 	exit(-1);
400 }
401