1 2#include <stdio.h> 3#include <stdlib.h> 4#include <unistd.h> 5#include <time.h> 6#include <sys/socket.h> 7#include <sys/time.h> 8#include <netinet/in.h> 9#include <linux/if.h> 10#include <linux/if_bridge.h> 11#include <string.h> 12#include <stdbool.h> 13 14#include "libnetlink.h" 15#include "utils.h" 16#include "br_common.h" 17 18static unsigned int filter_index; 19 20static const char *port_states[] = { 21 [BR_STATE_DISABLED] = "disabled", 22 [BR_STATE_LISTENING] = "listening", 23 [BR_STATE_LEARNING] = "learning", 24 [BR_STATE_FORWARDING] = "forwarding", 25 [BR_STATE_BLOCKING] = "blocking", 26}; 27 28extern char *if_indextoname (unsigned int __ifindex, char *__ifname); 29 30static void print_link_flags(FILE *fp, unsigned flags) 31{ 32 fprintf(fp, "<"); 33 if (flags & IFF_UP && !(flags & IFF_RUNNING)) 34 fprintf(fp, "NO-CARRIER%s", flags ? "," : ""); 35 flags &= ~IFF_RUNNING; 36#define _PF(f) if (flags&IFF_##f) { \ 37 flags &= ~IFF_##f ; \ 38 fprintf(fp, #f "%s", flags ? "," : ""); } 39 _PF(LOOPBACK); 40 _PF(BROADCAST); 41 _PF(POINTOPOINT); 42 _PF(MULTICAST); 43 _PF(NOARP); 44 _PF(ALLMULTI); 45 _PF(PROMISC); 46 _PF(MASTER); 47 _PF(SLAVE); 48 _PF(DEBUG); 49 _PF(DYNAMIC); 50 _PF(AUTOMEDIA); 51 _PF(PORTSEL); 52 _PF(NOTRAILERS); 53 _PF(UP); 54 _PF(LOWER_UP); 55 _PF(DORMANT); 56 _PF(ECHO); 57#undef _PF 58 if (flags) 59 fprintf(fp, "%x", flags); 60 fprintf(fp, "> "); 61} 62 63static const char *oper_states[] = { 64 "UNKNOWN", "NOTPRESENT", "DOWN", "LOWERLAYERDOWN", 65 "TESTING", "DORMANT", "UP" 66}; 67 68static const char *hw_mode[] = {"VEB", "VEPA"}; 69 70static void print_operstate(FILE *f, __u8 state) 71{ 72 if (state >= sizeof(oper_states)/sizeof(oper_states[0])) 73 fprintf(f, "state %#x ", state); 74 else 75 fprintf(f, "state %s ", oper_states[state]); 76} 77 78static void print_portstate(FILE *f, __u8 state) 79{ 80 if (state <= BR_STATE_BLOCKING) 81 fprintf(f, "state %s ", port_states[state]); 82 else 83 fprintf(f, "state (%d) ", state); 84} 85 86static void print_onoff(FILE *f, char *flag, __u8 val) 87{ 88 fprintf(f, "%s %s ", flag, val ? "on" : "off"); 89} 90 91static void print_hwmode(FILE *f, __u16 mode) 92{ 93 if (mode >= sizeof(hw_mode)/sizeof(hw_mode[0])) 94 fprintf(f, "hwmode %#hx ", mode); 95 else 96 fprintf(f, "hwmode %s ", hw_mode[mode]); 97} 98 99int print_linkinfo(const struct sockaddr_nl *who, 100 struct nlmsghdr *n, void *arg) 101{ 102 FILE *fp = arg; 103 int len = n->nlmsg_len; 104 struct ifinfomsg *ifi = NLMSG_DATA(n); 105 struct rtattr * tb[IFLA_MAX+1]; 106 char b1[IFNAMSIZ]; 107 108 len -= NLMSG_LENGTH(sizeof(*ifi)); 109 if (len < 0) { 110 fprintf(stderr, "Message too short!\n"); 111 return -1; 112 } 113 114 if (!(ifi->ifi_family == AF_BRIDGE || ifi->ifi_family == AF_UNSPEC)) 115 return 0; 116 117 if (filter_index && filter_index != ifi->ifi_index) 118 return 0; 119 120 parse_rtattr_flags(tb, IFLA_MAX, IFLA_RTA(ifi), len, NLA_F_NESTED); 121 122 if (tb[IFLA_IFNAME] == NULL) { 123 fprintf(stderr, "BUG: nil ifname\n"); 124 return -1; 125 } 126 127 if (n->nlmsg_type == RTM_DELLINK) 128 fprintf(fp, "Deleted "); 129 130 fprintf(fp, "%d: %s ", ifi->ifi_index, 131 tb[IFLA_IFNAME] ? rta_getattr_str(tb[IFLA_IFNAME]) : "<nil>"); 132 133 if (tb[IFLA_OPERSTATE]) 134 print_operstate(fp, rta_getattr_u8(tb[IFLA_OPERSTATE])); 135 136 if (tb[IFLA_LINK]) { 137 SPRINT_BUF(b1); 138 int iflink = rta_getattr_u32(tb[IFLA_LINK]); 139 if (iflink == 0) 140 fprintf(fp, "@NONE: "); 141 else 142 fprintf(fp, "@%s: ", 143 if_indextoname(iflink, b1)); 144 } else 145 fprintf(fp, ": "); 146 147 print_link_flags(fp, ifi->ifi_flags); 148 149 if (tb[IFLA_MTU]) 150 fprintf(fp, "mtu %u ", rta_getattr_u32(tb[IFLA_MTU])); 151 152 if (tb[IFLA_MASTER]) 153 fprintf(fp, "master %s ", 154 if_indextoname(rta_getattr_u32(tb[IFLA_MASTER]), b1)); 155 156 if (tb[IFLA_PROTINFO]) { 157 if (tb[IFLA_PROTINFO]->rta_type & NLA_F_NESTED) { 158 struct rtattr *prtb[IFLA_BRPORT_MAX+1]; 159 160 parse_rtattr_nested(prtb, IFLA_BRPORT_MAX, 161 tb[IFLA_PROTINFO]); 162 163 if (prtb[IFLA_BRPORT_STATE]) 164 print_portstate(fp, 165 rta_getattr_u8(prtb[IFLA_BRPORT_STATE])); 166 if (prtb[IFLA_BRPORT_PRIORITY]) 167 fprintf(fp, "priority %hu ", 168 rta_getattr_u16(prtb[IFLA_BRPORT_PRIORITY])); 169 if (prtb[IFLA_BRPORT_COST]) 170 fprintf(fp, "cost %u ", 171 rta_getattr_u32(prtb[IFLA_BRPORT_COST])); 172 173 if (show_details) { 174 fprintf(fp, "%s ", _SL_); 175 176 if (prtb[IFLA_BRPORT_MODE]) 177 print_onoff(fp, "hairpin", 178 rta_getattr_u8(prtb[IFLA_BRPORT_MODE])); 179 if (prtb[IFLA_BRPORT_GUARD]) 180 print_onoff(fp, "guard", 181 rta_getattr_u8(prtb[IFLA_BRPORT_GUARD])); 182 if (prtb[IFLA_BRPORT_PROTECT]) 183 print_onoff(fp, "root_block", 184 rta_getattr_u8(prtb[IFLA_BRPORT_PROTECT])); 185 if (prtb[IFLA_BRPORT_FAST_LEAVE]) 186 print_onoff(fp, "fastleave", 187 rta_getattr_u8(prtb[IFLA_BRPORT_FAST_LEAVE])); 188 if (prtb[IFLA_BRPORT_LEARNING]) 189 print_onoff(fp, "learning", 190 rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING])); 191 if (prtb[IFLA_BRPORT_LEARNING_SYNC]) 192 print_onoff(fp, "learning_sync", 193 rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING_SYNC])); 194 if (prtb[IFLA_BRPORT_UNICAST_FLOOD]) 195 print_onoff(fp, "flood", 196 rta_getattr_u8(prtb[IFLA_BRPORT_UNICAST_FLOOD])); 197 } 198 } else 199 print_portstate(fp, rta_getattr_u8(tb[IFLA_PROTINFO])); 200 } 201 202 if (tb[IFLA_AF_SPEC]) { 203 /* This is reported by HW devices that have some bridging 204 * capabilities. 205 */ 206 struct rtattr *aftb[IFLA_BRIDGE_MAX+1]; 207 208 parse_rtattr_nested(aftb, IFLA_BRIDGE_MAX, tb[IFLA_AF_SPEC]); 209 210 if (aftb[IFLA_BRIDGE_MODE]) 211 print_hwmode(fp, rta_getattr_u16(aftb[IFLA_BRIDGE_MODE])); 212 } 213 214 fprintf(fp, "\n"); 215 fflush(fp); 216 return 0; 217} 218 219static void usage(void) 220{ 221 fprintf(stderr, "Usage: bridge link set dev DEV [ cost COST ] [ priority PRIO ] [ state STATE ]\n"); 222 fprintf(stderr, " [ guard {on | off} ]\n"); 223 fprintf(stderr, " [ hairpin {on | off} ] \n"); 224 fprintf(stderr, " [ fastleave {on | off} ]\n"); 225 fprintf(stderr, " [ root_block {on | off} ]\n"); 226 fprintf(stderr, " [ learning {on | off} ]\n"); 227 fprintf(stderr, " [ learning_sync {on | off} ]\n"); 228 fprintf(stderr, " [ flood {on | off} ]\n"); 229 fprintf(stderr, " [ hwmode {vepa | veb} ]\n"); 230 fprintf(stderr, " [ self ] [ master ]\n"); 231 fprintf(stderr, " bridge link show [dev DEV]\n"); 232 exit(-1); 233} 234 235static bool on_off(char *arg, __s8 *attr, char *val) 236{ 237 if (strcmp(val, "on") == 0) 238 *attr = 1; 239 else if (strcmp(val, "off") == 0) 240 *attr = 0; 241 else { 242 fprintf(stderr, 243 "Error: argument of \"%s\" must be \"on\" or \"off\"\n", 244 arg); 245 return false; 246 } 247 248 return true; 249} 250 251static int brlink_modify(int argc, char **argv) 252{ 253 struct { 254 struct nlmsghdr n; 255 struct ifinfomsg ifm; 256 char buf[512]; 257 } req; 258 char *d = NULL; 259 __s8 learning = -1; 260 __s8 learning_sync = -1; 261 __s8 flood = -1; 262 __s8 hairpin = -1; 263 __s8 bpdu_guard = -1; 264 __s8 fast_leave = -1; 265 __s8 root_block = -1; 266 __u32 cost = 0; 267 __s16 priority = -1; 268 __s8 state = -1; 269 __s16 mode = -1; 270 __u16 flags = 0; 271 struct rtattr *nest; 272 273 memset(&req, 0, sizeof(req)); 274 275 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); 276 req.n.nlmsg_flags = NLM_F_REQUEST; 277 req.n.nlmsg_type = RTM_SETLINK; 278 req.ifm.ifi_family = PF_BRIDGE; 279 280 while (argc > 0) { 281 if (strcmp(*argv, "dev") == 0) { 282 NEXT_ARG(); 283 d = *argv; 284 } else if (strcmp(*argv, "guard") == 0) { 285 NEXT_ARG(); 286 if (!on_off("guard", &bpdu_guard, *argv)) 287 return -1; 288 } else if (strcmp(*argv, "hairpin") == 0) { 289 NEXT_ARG(); 290 if (!on_off("hairping", &hairpin, *argv)) 291 return -1; 292 } else if (strcmp(*argv, "fastleave") == 0) { 293 NEXT_ARG(); 294 if (!on_off("fastleave", &fast_leave, *argv)) 295 return -1; 296 } else if (strcmp(*argv, "root_block") == 0) { 297 NEXT_ARG(); 298 if (!on_off("root_block", &root_block, *argv)) 299 return -1; 300 } else if (strcmp(*argv, "learning") == 0) { 301 NEXT_ARG(); 302 if (!on_off("learning", &learning, *argv)) 303 return -1; 304 } else if (strcmp(*argv, "learning_sync") == 0) { 305 NEXT_ARG(); 306 if (!on_off("learning_sync", &learning_sync, *argv)) 307 return -1; 308 } else if (strcmp(*argv, "flood") == 0) { 309 NEXT_ARG(); 310 if (!on_off("flood", &flood, *argv)) 311 return -1; 312 } else if (strcmp(*argv, "cost") == 0) { 313 NEXT_ARG(); 314 cost = atoi(*argv); 315 } else if (strcmp(*argv, "priority") == 0) { 316 NEXT_ARG(); 317 priority = atoi(*argv); 318 } else if (strcmp(*argv, "state") == 0) { 319 NEXT_ARG(); 320 char *endptr; 321 size_t nstates = sizeof(port_states) / sizeof(*port_states); 322 state = strtol(*argv, &endptr, 10); 323 if (!(**argv != '\0' && *endptr == '\0')) { 324 for (state = 0; state < nstates; state++) 325 if (strcmp(port_states[state], *argv) == 0) 326 break; 327 if (state == nstates) { 328 fprintf(stderr, 329 "Error: invalid STP port state\n"); 330 return -1; 331 } 332 } 333 } else if (strcmp(*argv, "hwmode") == 0) { 334 NEXT_ARG(); 335 flags = BRIDGE_FLAGS_SELF; 336 if (strcmp(*argv, "vepa") == 0) 337 mode = BRIDGE_MODE_VEPA; 338 else if (strcmp(*argv, "veb") == 0) 339 mode = BRIDGE_MODE_VEB; 340 else { 341 fprintf(stderr, 342 "Mode argument must be \"vepa\" or " 343 "\"veb\".\n"); 344 return -1; 345 } 346 } else if (strcmp(*argv, "self") == 0) { 347 flags |= BRIDGE_FLAGS_SELF; 348 } else if (strcmp(*argv, "master") == 0) { 349 flags |= BRIDGE_FLAGS_MASTER; 350 } else { 351 usage(); 352 } 353 argc--; argv++; 354 } 355 if (d == NULL) { 356 fprintf(stderr, "Device is a required argument.\n"); 357 return -1; 358 } 359 360 361 req.ifm.ifi_index = ll_name_to_index(d); 362 if (req.ifm.ifi_index == 0) { 363 fprintf(stderr, "Cannot find bridge device \"%s\"\n", d); 364 return -1; 365 } 366 367 /* Nested PROTINFO attribute. Contains: port flags, cost, priority and 368 * state. 369 */ 370 nest = addattr_nest(&req.n, sizeof(req), 371 IFLA_PROTINFO | NLA_F_NESTED); 372 /* Flags first */ 373 if (bpdu_guard >= 0) 374 addattr8(&req.n, sizeof(req), IFLA_BRPORT_GUARD, bpdu_guard); 375 if (hairpin >= 0) 376 addattr8(&req.n, sizeof(req), IFLA_BRPORT_MODE, hairpin); 377 if (fast_leave >= 0) 378 addattr8(&req.n, sizeof(req), IFLA_BRPORT_FAST_LEAVE, 379 fast_leave); 380 if (root_block >= 0) 381 addattr8(&req.n, sizeof(req), IFLA_BRPORT_PROTECT, root_block); 382 if (flood >= 0) 383 addattr8(&req.n, sizeof(req), IFLA_BRPORT_UNICAST_FLOOD, flood); 384 if (learning >= 0) 385 addattr8(&req.n, sizeof(req), IFLA_BRPORT_LEARNING, learning); 386 if (learning_sync >= 0) 387 addattr8(&req.n, sizeof(req), IFLA_BRPORT_LEARNING_SYNC, 388 learning_sync); 389 390 if (cost > 0) 391 addattr32(&req.n, sizeof(req), IFLA_BRPORT_COST, cost); 392 393 if (priority >= 0) 394 addattr16(&req.n, sizeof(req), IFLA_BRPORT_PRIORITY, priority); 395 396 if (state >= 0) 397 addattr8(&req.n, sizeof(req), IFLA_BRPORT_STATE, state); 398 399 addattr_nest_end(&req.n, nest); 400 401 /* IFLA_AF_SPEC nested attribute. Contains IFLA_BRIDGE_FLAGS that 402 * designates master or self operation and IFLA_BRIDGE_MODE 403 * for hw 'vepa' or 'veb' operation modes. The hwmodes are 404 * only valid in 'self' mode on some devices so far. 405 */ 406 if (mode >= 0 || flags > 0) { 407 nest = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC); 408 409 if (flags > 0) 410 addattr16(&req.n, sizeof(req), IFLA_BRIDGE_FLAGS, flags); 411 412 if (mode >= 0) 413 addattr16(&req.n, sizeof(req), IFLA_BRIDGE_MODE, mode); 414 415 addattr_nest_end(&req.n, nest); 416 } 417 418 if (rtnl_talk(&rth, &req.n, NULL, 0) < 0) 419 return -1; 420 421 return 0; 422} 423 424static int brlink_show(int argc, char **argv) 425{ 426 char *filter_dev = NULL; 427 428 while (argc > 0) { 429 if (strcmp(*argv, "dev") == 0) { 430 NEXT_ARG(); 431 if (filter_dev) 432 duparg("dev", *argv); 433 filter_dev = *argv; 434 } 435 argc--; argv++; 436 } 437 438 if (filter_dev) { 439 if ((filter_index = ll_name_to_index(filter_dev)) == 0) { 440 fprintf(stderr, "Cannot find device \"%s\"\n", 441 filter_dev); 442 return -1; 443 } 444 } 445 446 if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETLINK) < 0) { 447 perror("Cannon send dump request"); 448 exit(1); 449 } 450 451 if (rtnl_dump_filter(&rth, print_linkinfo, stdout) < 0) { 452 fprintf(stderr, "Dump terminated\n"); 453 exit(1); 454 } 455 return 0; 456} 457 458int do_link(int argc, char **argv) 459{ 460 ll_init_map(&rth); 461 if (argc > 0) { 462 if (matches(*argv, "set") == 0 || 463 matches(*argv, "change") == 0) 464 return brlink_modify(argc-1, argv+1); 465 if (matches(*argv, "show") == 0 || 466 matches(*argv, "lst") == 0 || 467 matches(*argv, "list") == 0) 468 return brlink_show(argc-1, argv+1); 469 if (matches(*argv, "help") == 0) 470 usage(); 471 } else 472 return brlink_show(0, NULL); 473 474 fprintf(stderr, "Command \"%s\" is unknown, try \"bridge link help\".\n", *argv); 475 exit(-1); 476} 477