]> git.proxmox.com Git - mirror_iproute2.git/blame - bridge/fdb.c
Merge branch 'master' into vxlan
[mirror_iproute2.git] / bridge / fdb.c
CommitLineData
d04bc300
SH
1/*
2 * Get/set/delete fdb table with netlink
3 *
4 * Authors: Stephen Hemminger <shemminger@vyatta.com>
5 */
6
7#include <stdio.h>
8#include <stdlib.h>
9#include <unistd.h>
10#include <time.h>
11#include <fcntl.h>
12#include <sys/socket.h>
13#include <sys/time.h>
14#include <net/if.h>
15#include <netinet/in.h>
16#include <linux/if_bridge.h>
17#include <linux/if_ether.h>
18#include <linux/neighbour.h>
19#include <string.h>
20
21#include "libnetlink.h"
22#include "br_common.h"
23#include "utils.h"
24
25int filter_index;
26
27static void usage(void)
28{
57b9785d 29 fprintf(stderr, "Usage: bridge fdb { add | del } ADDR dev DEV {self|master}\n");
90698170 30 fprintf(stderr, " bridge fdb {show} [ dev DEV ]\n");
d04bc300
SH
31 exit(-1);
32}
33
34static const char *state_n2a(unsigned s)
35{
36 static char buf[32];
37
38 if (s & NUD_PERMANENT)
39 return "local";
40
41 if (s & NUD_NOARP)
42 return "static";
43
44 if (s & NUD_STALE)
45 return "stale";
46
47 if (s & NUD_REACHABLE)
48 return "";
49
50 sprintf(buf, "state=%#x", s);
51 return buf;
52}
53
54static char *fmt_time(char *b, size_t l, unsigned long tick)
55{
56 static int hz;
57
58 if (hz == 0)
59 hz = __get_user_hz();
60
61 snprintf(b, l, "%lu.%02lu", tick / hz, ((tick % hz) * hz) / 100);
62 return b;
63}
64
65int print_fdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
66{
67 struct ndmsg *r = NLMSG_DATA(n);
68 int len = n->nlmsg_len;
69 struct rtattr * tb[NDA_MAX+1];
70 const __u8 *addr = NULL;
71 char b1[32];
72
73 len -= NLMSG_LENGTH(sizeof(*r));
74 if (len < 0) {
75 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
76 return -1;
77 }
78
79 if (r->ndm_family != AF_BRIDGE)
80 return 0;
81
82 if (filter_index && filter_index != r->ndm_ifindex)
83 return 0;
84
85 parse_rtattr(tb, NDA_MAX, NDA_RTA(r),
86 n->nlmsg_len - NLMSG_LENGTH(sizeof(*r)));
87
88 if (n->nlmsg_type == RTM_DELNEIGH)
89 printf("Deleted ");
90
91 if (tb[NDA_LLADDR])
92 addr = RTA_DATA(tb[NDA_LLADDR]);
93 else {
94 fprintf(stderr, "missing lladdr\n");
95 return -1;
96 }
97
dc6a6a25 98 printf("%s\t%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\t%s %s",
d04bc300
SH
99 ll_index_to_name(r->ndm_ifindex),
100 addr[0], addr[1], addr[2],
101 addr[3], addr[4], addr[5],
dc6a6a25
JF
102 state_n2a(r->ndm_state),
103 (r->ndm_flags & NTF_SELF) ? "self" : "master");
d04bc300
SH
104
105 if (show_stats && tb[NDA_CACHEINFO]) {
106 struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]);
107
108 printf("\t%8s", fmt_time(b1, sizeof(b1), ci->ndm_updated));
109 printf(" %8s", fmt_time(b1, sizeof(b1), ci->ndm_used));
110 }
111 printf("\n");
112
113 return 0;
114}
115
116static int fdb_show(int argc, char **argv)
117{
118 char *filter_dev = NULL;
119
120 while (argc > 0) {
121 if (strcmp(*argv, "dev") == 0) {
122 NEXT_ARG();
123 if (filter_dev)
124 duparg("dev", *argv);
125 filter_dev = *argv;
126 }
127 argc--; argv++;
128 }
129
130 if (filter_dev) {
131 if ((filter_index = if_nametoindex(filter_dev)) == 0) {
132 fprintf(stderr, "Cannot find device \"%s\"\n", filter_dev);
133 return -1;
134 }
135 }
136
137 if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETNEIGH) < 0) {
138 perror("Cannot send dump request");
139 exit(1);
140 }
141
142 printf("port\tmac addr\t\tflags%s\n",
143 show_stats ? "\t updated used" : "");
144
145 if (rtnl_dump_filter(&rth, print_fdb, NULL) < 0) {
146 fprintf(stderr, "Dump terminated\n");
147 exit(1);
148 }
149
150 return 0;
151}
152
153static int fdb_modify(int cmd, int flags, int argc, char **argv)
154{
155 struct {
156 struct nlmsghdr n;
157 struct ndmsg ndm;
158 char buf[256];
159 } req;
160 char *addr = NULL;
161 char *d = NULL;
162 char abuf[ETH_ALEN];
163
164 memset(&req, 0, sizeof(req));
165
166 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
167 req.n.nlmsg_flags = NLM_F_REQUEST|flags;
168 req.n.nlmsg_type = cmd;
169 req.ndm.ndm_family = PF_BRIDGE;
170 req.ndm.ndm_state = NUD_NOARP;
171
172 while (argc > 0) {
173 if (strcmp(*argv, "dev") == 0) {
174 NEXT_ARG();
175 d = *argv;
176 } else if (strcmp(*argv, "local") == 0) {
177 req.ndm.ndm_state = NUD_PERMANENT;
178 } else if (strcmp(*argv, "temp") == 0) {
179 req.ndm.ndm_state = NUD_REACHABLE;
dc6a6a25
JF
180 } else if (strcmp(*argv, "self") == 0) {
181 req.ndm.ndm_flags |= NTF_SELF;
182 } else if (strcmp(*argv, "master") == 0) {
183 req.ndm.ndm_flags |= NTF_MASTER;
d04bc300
SH
184 } else {
185 if (strcmp(*argv, "to") == 0) {
186 NEXT_ARG();
187 }
188 if (matches(*argv, "help") == 0) {
189 NEXT_ARG();
190 }
191 if (addr)
192 duparg2("to", *argv);
193 addr = *argv;
194 }
195 argc--; argv++;
196 }
197
198 if (d == NULL || addr == NULL) {
199 fprintf(stderr, "Device and address are required arguments.\n");
200 exit(-1);
201 }
202
203 if (sscanf(addr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
204 abuf, abuf+1, abuf+2,
205 abuf+3, abuf+4, abuf+5) != 6) {
206 fprintf(stderr, "Invalid mac address %s\n", addr);
207 exit(-1);
208 }
209
210 addattr_l(&req.n, sizeof(req), NDA_LLADDR, abuf, ETH_ALEN);
211
212 req.ndm.ndm_ifindex = ll_name_to_index(d);
213 if (req.ndm.ndm_ifindex == 0) {
214 fprintf(stderr, "Cannot find device \"%s\"\n", d);
215 return -1;
216 }
217
218 if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
219 exit(2);
220
221 return 0;
222}
223
224int do_fdb(int argc, char **argv)
225{
226 ll_init_map(&rth);
227
228 if (argc > 0) {
229 if (matches(*argv, "add") == 0)
230 return fdb_modify(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_EXCL, argc-1, argv+1);
d04bc300
SH
231 if (matches(*argv, "delete") == 0)
232 return fdb_modify(RTM_DELNEIGH, 0, argc-1, argv+1);
233 if (matches(*argv, "show") == 0 ||
234 matches(*argv, "lst") == 0 ||
235 matches(*argv, "list") == 0)
236 return fdb_show(argc-1, argv+1);
237 if (matches(*argv, "help") == 0)
238 usage();
239 } else
240 return fdb_show(0, NULL);
241
083b46bb 242 fprintf(stderr, "Command \"%s\" is unknown, try \"bridge fdb help\".\n", *argv);
d04bc300
SH
243 exit(-1);
244}