mdb.c revision 6aac8617139a96a124d63aeae843b73c38f88fc5
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] [vid VID]\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 const void *src; 55 int af; 56 57 af = e->addr.proto == htons(ETH_P_IP) ? AF_INET : AF_INET6; 58 src = af == AF_INET ? (const void *)&e->addr.u.ip4 : 59 (const void *)&e->addr.u.ip6; 60 fprintf(f, "dev %s port %s grp %s %s", ll_index_to_name(ifindex), 61 ll_index_to_name(e->ifindex), 62 inet_ntop(af, src, abuf, sizeof(abuf)), 63 (e->state & MDB_PERMANENT) ? "permanent" : "temp"); 64 if (e->vid) 65 fprintf(f, " vid %hu", e->vid); 66 fprintf(f, "\n"); 67} 68 69static void br_print_mdb_entry(FILE *f, int ifindex, struct rtattr *attr) 70{ 71 struct rtattr *i; 72 int rem; 73 struct br_mdb_entry *e; 74 75 rem = RTA_PAYLOAD(attr); 76 for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) { 77 e = RTA_DATA(i); 78 print_mdb_entry(f, ifindex, e); 79 } 80} 81 82int print_mdb(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) 83{ 84 FILE *fp = arg; 85 struct br_port_msg *r = NLMSG_DATA(n); 86 int len = n->nlmsg_len; 87 struct rtattr *tb[MDBA_MAX+1], *i; 88 89 if (n->nlmsg_type != RTM_GETMDB && n->nlmsg_type != RTM_NEWMDB && n->nlmsg_type != RTM_DELMDB) { 90 fprintf(stderr, "Not RTM_GETMDB, RTM_NEWMDB or RTM_DELMDB: %08x %08x %08x\n", 91 n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); 92 93 return 0; 94 } 95 96 len -= NLMSG_LENGTH(sizeof(*r)); 97 if (len < 0) { 98 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); 99 return -1; 100 } 101 102 if (filter_index && filter_index != r->ifindex) 103 return 0; 104 105 parse_rtattr(tb, MDBA_MAX, MDBA_RTA(r), n->nlmsg_len - NLMSG_LENGTH(sizeof(*r))); 106 107 if (tb[MDBA_MDB]) { 108 int rem = RTA_PAYLOAD(tb[MDBA_MDB]); 109 110 for (i = RTA_DATA(tb[MDBA_MDB]); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) 111 br_print_mdb_entry(fp, r->ifindex, i); 112 } 113 114 if (tb[MDBA_ROUTER]) { 115 if (n->nlmsg_type == RTM_GETMDB) { 116 if (show_details) { 117 fprintf(fp, "router ports on %s: ", 118 ll_index_to_name(r->ifindex)); 119 br_print_router_ports(fp, tb[MDBA_ROUTER]); 120 } 121 } else { 122 uint32_t *port_ifindex; 123 124 i = RTA_DATA(tb[MDBA_ROUTER]); 125 port_ifindex = RTA_DATA(i); 126 if (n->nlmsg_type == RTM_DELMDB) 127 fprintf(fp, "Deleted "); 128 fprintf(fp, "router port dev %s master %s\n", 129 ll_index_to_name(*port_ifindex), 130 ll_index_to_name(r->ifindex)); 131 } 132 } 133 134 return 0; 135} 136 137static int mdb_show(int argc, char **argv) 138{ 139 char *filter_dev = NULL; 140 141 while (argc > 0) { 142 if (strcmp(*argv, "dev") == 0) { 143 NEXT_ARG(); 144 if (filter_dev) 145 duparg("dev", *argv); 146 filter_dev = *argv; 147 } 148 argc--; argv++; 149 } 150 151 if (filter_dev) { 152 filter_index = if_nametoindex(filter_dev); 153 if (filter_index == 0) { 154 fprintf(stderr, "Cannot find device \"%s\"\n", 155 filter_dev); 156 return -1; 157 } 158 } 159 160 if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETMDB) < 0) { 161 perror("Cannot send dump request"); 162 return -1; 163 } 164 165 if (rtnl_dump_filter(&rth, print_mdb, stdout) < 0) { 166 fprintf(stderr, "Dump terminated\n"); 167 return -1; 168 } 169 170 return 0; 171} 172 173static int mdb_modify(int cmd, int flags, int argc, char **argv) 174{ 175 struct { 176 struct nlmsghdr n; 177 struct br_port_msg bpm; 178 char buf[1024]; 179 } req; 180 struct br_mdb_entry entry; 181 char *d = NULL, *p = NULL, *grp = NULL; 182 short vid = 0; 183 184 memset(&req, 0, sizeof(req)); 185 memset(&entry, 0, sizeof(entry)); 186 187 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct br_port_msg)); 188 req.n.nlmsg_flags = NLM_F_REQUEST|flags; 189 req.n.nlmsg_type = cmd; 190 req.bpm.family = PF_BRIDGE; 191 192 while (argc > 0) { 193 if (strcmp(*argv, "dev") == 0) { 194 NEXT_ARG(); 195 d = *argv; 196 } else if (strcmp(*argv, "grp") == 0) { 197 NEXT_ARG(); 198 grp = *argv; 199 } else if (strcmp(*argv, "port") == 0) { 200 NEXT_ARG(); 201 p = *argv; 202 } else if (strcmp(*argv, "permanent") == 0) { 203 if (cmd == RTM_NEWMDB) 204 entry.state |= MDB_PERMANENT; 205 } else if (strcmp(*argv, "temp") == 0) { 206 ;/* nothing */ 207 } else if (strcmp(*argv, "vid") == 0) { 208 NEXT_ARG(); 209 vid = atoi(*argv); 210 } else { 211 if (matches(*argv, "help") == 0) 212 usage(); 213 } 214 argc--; argv++; 215 } 216 217 if (d == NULL || grp == NULL || p == NULL) { 218 fprintf(stderr, "Device, group address and port name are required arguments.\n"); 219 return -1; 220 } 221 222 req.bpm.ifindex = ll_name_to_index(d); 223 if (req.bpm.ifindex == 0) { 224 fprintf(stderr, "Cannot find device \"%s\"\n", d); 225 return -1; 226 } 227 228 entry.ifindex = ll_name_to_index(p); 229 if (entry.ifindex == 0) { 230 fprintf(stderr, "Cannot find device \"%s\"\n", p); 231 return -1; 232 } 233 234 if (!inet_pton(AF_INET, grp, &entry.addr.u.ip4)) { 235 if (!inet_pton(AF_INET6, grp, &entry.addr.u.ip6)) { 236 fprintf(stderr, "Invalid address \"%s\"\n", grp); 237 return -1; 238 } else 239 entry.addr.proto = htons(ETH_P_IPV6); 240 } else 241 entry.addr.proto = htons(ETH_P_IP); 242 243 entry.vid = vid; 244 addattr_l(&req.n, sizeof(req), MDBA_SET_ENTRY, &entry, sizeof(entry)); 245 246 if (rtnl_talk(&rth, &req.n, NULL, 0) < 0) 247 return -1; 248 249 return 0; 250} 251 252int do_mdb(int argc, char **argv) 253{ 254 ll_init_map(&rth); 255 256 if (argc > 0) { 257 if (matches(*argv, "add") == 0) 258 return mdb_modify(RTM_NEWMDB, NLM_F_CREATE|NLM_F_EXCL, argc-1, argv+1); 259 if (matches(*argv, "delete") == 0) 260 return mdb_modify(RTM_DELMDB, 0, argc-1, argv+1); 261 262 if (matches(*argv, "show") == 0 || 263 matches(*argv, "lst") == 0 || 264 matches(*argv, "list") == 0) 265 return mdb_show(argc-1, argv+1); 266 if (matches(*argv, "help") == 0) 267 usage(); 268 } else 269 return mdb_show(0, NULL); 270 271 fprintf(stderr, "Command \"%s\" is unknown, try \"bridge mdb help\".\n", *argv); 272 exit(-1); 273} 274