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