]> git.proxmox.com Git - mirror_iproute2.git/blame - bridge/fdb.c
Fix formatting of ip.8 family man page
[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{
90698170
CW
29 fprintf(stderr, "Usage: bridge fdb { add | del | replace } ADDR dev DEV\n");
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
98 printf("%s\t%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\t%s",
99 ll_index_to_name(r->ndm_ifindex),
100 addr[0], addr[1], addr[2],
101 addr[3], addr[4], addr[5],
102 state_n2a(r->ndm_state));
103
104 if (show_stats && tb[NDA_CACHEINFO]) {
105 struct nda_cacheinfo *ci = RTA_DATA(tb[NDA_CACHEINFO]);
106
107 printf("\t%8s", fmt_time(b1, sizeof(b1), ci->ndm_updated));
108 printf(" %8s", fmt_time(b1, sizeof(b1), ci->ndm_used));
109 }
110 printf("\n");
111
112 return 0;
113}
114
115static int fdb_show(int argc, char **argv)
116{
117 char *filter_dev = NULL;
118
119 while (argc > 0) {
120 if (strcmp(*argv, "dev") == 0) {
121 NEXT_ARG();
122 if (filter_dev)
123 duparg("dev", *argv);
124 filter_dev = *argv;
125 }
126 argc--; argv++;
127 }
128
129 if (filter_dev) {
130 if ((filter_index = if_nametoindex(filter_dev)) == 0) {
131 fprintf(stderr, "Cannot find device \"%s\"\n", filter_dev);
132 return -1;
133 }
134 }
135
136 if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETNEIGH) < 0) {
137 perror("Cannot send dump request");
138 exit(1);
139 }
140
141 printf("port\tmac addr\t\tflags%s\n",
142 show_stats ? "\t updated used" : "");
143
144 if (rtnl_dump_filter(&rth, print_fdb, NULL) < 0) {
145 fprintf(stderr, "Dump terminated\n");
146 exit(1);
147 }
148
149 return 0;
150}
151
152static int fdb_modify(int cmd, int flags, int argc, char **argv)
153{
154 struct {
155 struct nlmsghdr n;
156 struct ndmsg ndm;
157 char buf[256];
158 } req;
159 char *addr = NULL;
160 char *d = NULL;
161 char abuf[ETH_ALEN];
162
163 memset(&req, 0, sizeof(req));
164
165 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg));
166 req.n.nlmsg_flags = NLM_F_REQUEST|flags;
167 req.n.nlmsg_type = cmd;
168 req.ndm.ndm_family = PF_BRIDGE;
169 req.ndm.ndm_state = NUD_NOARP;
170
171 while (argc > 0) {
172 if (strcmp(*argv, "dev") == 0) {
173 NEXT_ARG();
174 d = *argv;
175 } else if (strcmp(*argv, "local") == 0) {
176 req.ndm.ndm_state = NUD_PERMANENT;
177 } else if (strcmp(*argv, "temp") == 0) {
178 req.ndm.ndm_state = NUD_REACHABLE;
179 } else {
180 if (strcmp(*argv, "to") == 0) {
181 NEXT_ARG();
182 }
183 if (matches(*argv, "help") == 0) {
184 NEXT_ARG();
185 }
186 if (addr)
187 duparg2("to", *argv);
188 addr = *argv;
189 }
190 argc--; argv++;
191 }
192
193 if (d == NULL || addr == NULL) {
194 fprintf(stderr, "Device and address are required arguments.\n");
195 exit(-1);
196 }
197
198 if (sscanf(addr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
199 abuf, abuf+1, abuf+2,
200 abuf+3, abuf+4, abuf+5) != 6) {
201 fprintf(stderr, "Invalid mac address %s\n", addr);
202 exit(-1);
203 }
204
205 addattr_l(&req.n, sizeof(req), NDA_LLADDR, abuf, ETH_ALEN);
206
207 req.ndm.ndm_ifindex = ll_name_to_index(d);
208 if (req.ndm.ndm_ifindex == 0) {
209 fprintf(stderr, "Cannot find device \"%s\"\n", d);
210 return -1;
211 }
212
213 if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
214 exit(2);
215
216 return 0;
217}
218
219int do_fdb(int argc, char **argv)
220{
221 ll_init_map(&rth);
222
223 if (argc > 0) {
224 if (matches(*argv, "add") == 0)
225 return fdb_modify(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_EXCL, argc-1, argv+1);
226 if (matches(*argv, "change") == 0)
227 return fdb_modify(RTM_NEWNEIGH, NLM_F_REPLACE, argc-1, argv+1);
228
229 if (matches(*argv, "replace") == 0)
230 return fdb_modify(RTM_NEWNEIGH, NLM_F_CREATE|NLM_F_REPLACE, argc-1, argv+1);
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
242 fprintf(stderr, "Command \"%s\" is unknown, try \"ip neigh help\".\n", *argv);
243 exit(-1);
244}