1 /* 2 * Get/set/delete fdb table with netlink 3 * 4 * TODO: merge/replace this with ip neighbour 5 * 6 * Authors: Stephen Hemminger <shemminger (at) 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 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 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 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 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 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 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