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 18 static unsigned int filter_index; 19 20 static 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 28 extern char *if_indextoname(unsigned int __ifindex, char *__ifname); 29 30 static void print_link_flags(FILE *fp, unsigned int 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 63 static const char *oper_states[] = { 64 "UNKNOWN", "NOTPRESENT", "DOWN", "LOWERLAYERDOWN", 65 "TESTING", "DORMANT", "UP" 66 }; 67 68 static const char *hw_mode[] = {"VEB", "VEPA"}; 69 70 static void print_operstate(FILE *f, __u8 state) 71 { 72 if (state >= ARRAY_SIZE(oper_states)) 73 fprintf(f, "state %#x ", state); 74 else 75 fprintf(f, "state %s ", oper_states[state]); 76 } 77 78 static 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 86 static void print_onoff(FILE *f, char *flag, __u8 val) 87 { 88 fprintf(f, "%s %s ", flag, val ? "on" : "off"); 89 } 90 91 static void print_hwmode(FILE *f, __u16 mode) 92 { 93 if (mode >= ARRAY_SIZE(hw_mode)) 94 fprintf(f, "hwmode %#hx ", mode); 95 else 96 fprintf(f, "hwmode %s ", hw_mode[mode]); 97 } 98 99 int 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 140 if (iflink == 0) 141 fprintf(fp, "@NONE: "); 142 else 143 fprintf(fp, "@%s: ", 144 if_indextoname(iflink, b1)); 145 } else 146 fprintf(fp, ": "); 147 148 print_link_flags(fp, ifi->ifi_flags); 149 150 if (tb[IFLA_MTU]) 151 fprintf(fp, "mtu %u ", rta_getattr_u32(tb[IFLA_MTU])); 152 153 if (tb[IFLA_MASTER]) 154 fprintf(fp, "master %s ", 155 if_indextoname(rta_getattr_u32(tb[IFLA_MASTER]), b1)); 156 157 if (tb[IFLA_PROTINFO]) { 158 if (tb[IFLA_PROTINFO]->rta_type & NLA_F_NESTED) { 159 struct rtattr *prtb[IFLA_BRPORT_MAX+1]; 160 161 parse_rtattr_nested(prtb, IFLA_BRPORT_MAX, 162 tb[IFLA_PROTINFO]); 163 164 if (prtb[IFLA_BRPORT_STATE]) 165 print_portstate(fp, 166 rta_getattr_u8(prtb[IFLA_BRPORT_STATE])); 167 if (prtb[IFLA_BRPORT_PRIORITY]) 168 fprintf(fp, "priority %hu ", 169 rta_getattr_u16(prtb[IFLA_BRPORT_PRIORITY])); 170 if (prtb[IFLA_BRPORT_COST]) 171 fprintf(fp, "cost %u ", 172 rta_getattr_u32(prtb[IFLA_BRPORT_COST])); 173 174 if (show_details) { 175 fprintf(fp, "%s ", _SL_); 176 177 if (prtb[IFLA_BRPORT_MODE]) 178 print_onoff(fp, "hairpin", 179 rta_getattr_u8(prtb[IFLA_BRPORT_MODE])); 180 if (prtb[IFLA_BRPORT_GUARD]) 181 print_onoff(fp, "guard", 182 rta_getattr_u8(prtb[IFLA_BRPORT_GUARD])); 183 if (prtb[IFLA_BRPORT_PROTECT]) 184 print_onoff(fp, "root_block", 185 rta_getattr_u8(prtb[IFLA_BRPORT_PROTECT])); 186 if (prtb[IFLA_BRPORT_FAST_LEAVE]) 187 print_onoff(fp, "fastleave", 188 rta_getattr_u8(prtb[IFLA_BRPORT_FAST_LEAVE])); 189 if (prtb[IFLA_BRPORT_LEARNING]) 190 print_onoff(fp, "learning", 191 rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING])); 192 if (prtb[IFLA_BRPORT_LEARNING_SYNC]) 193 print_onoff(fp, "learning_sync", 194 rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING_SYNC])); 195 if (prtb[IFLA_BRPORT_UNICAST_FLOOD]) 196 print_onoff(fp, "flood", 197 rta_getattr_u8(prtb[IFLA_BRPORT_UNICAST_FLOOD])); 198 if (prtb[IFLA_BRPORT_MCAST_FLOOD]) 199 print_onoff(fp, "mcast_flood", 200 rta_getattr_u8(prtb[IFLA_BRPORT_MCAST_FLOOD])); 201 } 202 } else 203 print_portstate(fp, rta_getattr_u8(tb[IFLA_PROTINFO])); 204 } 205 206 if (tb[IFLA_AF_SPEC]) { 207 /* This is reported by HW devices that have some bridging 208 * capabilities. 209 */ 210 struct rtattr *aftb[IFLA_BRIDGE_MAX+1]; 211 212 parse_rtattr_nested(aftb, IFLA_BRIDGE_MAX, tb[IFLA_AF_SPEC]); 213 214 if (aftb[IFLA_BRIDGE_MODE]) 215 print_hwmode(fp, rta_getattr_u16(aftb[IFLA_BRIDGE_MODE])); 216 if (show_details) { 217 if (aftb[IFLA_BRIDGE_VLAN_INFO]) { 218 fprintf(fp, "\n"); 219 print_vlan_info(fp, tb[IFLA_AF_SPEC], 220 ifi->ifi_index); 221 } 222 } 223 } 224 225 fprintf(fp, "\n"); 226 fflush(fp); 227 return 0; 228 } 229 230 static void usage(void) 231 { 232 fprintf(stderr, "Usage: bridge link set dev DEV [ cost COST ] [ priority PRIO ] [ state STATE ]\n"); 233 fprintf(stderr, " [ guard {on | off} ]\n"); 234 fprintf(stderr, " [ hairpin {on | off} ]\n"); 235 fprintf(stderr, " [ fastleave {on | off} ]\n"); 236 fprintf(stderr, " [ root_block {on | off} ]\n"); 237 fprintf(stderr, " [ learning {on | off} ]\n"); 238 fprintf(stderr, " [ learning_sync {on | off} ]\n"); 239 fprintf(stderr, " [ flood {on | off} ]\n"); 240 fprintf(stderr, " [ mcast_flood {on | off} ]\n"); 241 fprintf(stderr, " [ hwmode {vepa | veb} ]\n"); 242 fprintf(stderr, " [ self ] [ master ]\n"); 243 fprintf(stderr, " bridge link show [dev DEV]\n"); 244 exit(-1); 245 } 246 247 static bool on_off(char *arg, __s8 *attr, char *val) 248 { 249 if (strcmp(val, "on") == 0) 250 *attr = 1; 251 else if (strcmp(val, "off") == 0) 252 *attr = 0; 253 else { 254 fprintf(stderr, 255 "Error: argument of \"%s\" must be \"on\" or \"off\"\n", 256 arg); 257 return false; 258 } 259 260 return true; 261 } 262 263 static int brlink_modify(int argc, char **argv) 264 { 265 struct { 266 struct nlmsghdr n; 267 struct ifinfomsg ifm; 268 char buf[512]; 269 } req = { 270 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)), 271 .n.nlmsg_flags = NLM_F_REQUEST, 272 .n.nlmsg_type = RTM_SETLINK, 273 .ifm.ifi_family = PF_BRIDGE, 274 }; 275 char *d = NULL; 276 __s8 learning = -1; 277 __s8 learning_sync = -1; 278 __s8 flood = -1; 279 __s8 mcast_flood = -1; 280 __s8 hairpin = -1; 281 __s8 bpdu_guard = -1; 282 __s8 fast_leave = -1; 283 __s8 root_block = -1; 284 __u32 cost = 0; 285 __s16 priority = -1; 286 __s8 state = -1; 287 __s16 mode = -1; 288 __u16 flags = 0; 289 struct rtattr *nest; 290 291 while (argc > 0) { 292 if (strcmp(*argv, "dev") == 0) { 293 NEXT_ARG(); 294 d = *argv; 295 } else if (strcmp(*argv, "guard") == 0) { 296 NEXT_ARG(); 297 if (!on_off("guard", &bpdu_guard, *argv)) 298 return -1; 299 } else if (strcmp(*argv, "hairpin") == 0) { 300 NEXT_ARG(); 301 if (!on_off("hairping", &hairpin, *argv)) 302 return -1; 303 } else if (strcmp(*argv, "fastleave") == 0) { 304 NEXT_ARG(); 305 if (!on_off("fastleave", &fast_leave, *argv)) 306 return -1; 307 } else if (strcmp(*argv, "root_block") == 0) { 308 NEXT_ARG(); 309 if (!on_off("root_block", &root_block, *argv)) 310 return -1; 311 } else if (strcmp(*argv, "learning") == 0) { 312 NEXT_ARG(); 313 if (!on_off("learning", &learning, *argv)) 314 return -1; 315 } else if (strcmp(*argv, "learning_sync") == 0) { 316 NEXT_ARG(); 317 if (!on_off("learning_sync", &learning_sync, *argv)) 318 return -1; 319 } else if (strcmp(*argv, "flood") == 0) { 320 NEXT_ARG(); 321 if (!on_off("flood", &flood, *argv)) 322 return -1; 323 } else if (strcmp(*argv, "mcast_flood") == 0) { 324 NEXT_ARG(); 325 if (!on_off("mcast_flood", &mcast_flood, *argv)) 326 return -1; 327 } else if (strcmp(*argv, "cost") == 0) { 328 NEXT_ARG(); 329 cost = atoi(*argv); 330 } else if (strcmp(*argv, "priority") == 0) { 331 NEXT_ARG(); 332 priority = atoi(*argv); 333 } else if (strcmp(*argv, "state") == 0) { 334 NEXT_ARG(); 335 char *endptr; 336 size_t nstates = ARRAY_SIZE(port_states); 337 338 state = strtol(*argv, &endptr, 10); 339 if (!(**argv != '\0' && *endptr == '\0')) { 340 for (state = 0; state < nstates; state++) 341 if (strcmp(port_states[state], *argv) == 0) 342 break; 343 if (state == nstates) { 344 fprintf(stderr, 345 "Error: invalid STP port state\n"); 346 return -1; 347 } 348 } 349 } else if (strcmp(*argv, "hwmode") == 0) { 350 NEXT_ARG(); 351 flags = BRIDGE_FLAGS_SELF; 352 if (strcmp(*argv, "vepa") == 0) 353 mode = BRIDGE_MODE_VEPA; 354 else if (strcmp(*argv, "veb") == 0) 355 mode = BRIDGE_MODE_VEB; 356 else { 357 fprintf(stderr, 358 "Mode argument must be \"vepa\" or \"veb\".\n"); 359 return -1; 360 } 361 } else if (strcmp(*argv, "self") == 0) { 362 flags |= BRIDGE_FLAGS_SELF; 363 } else if (strcmp(*argv, "master") == 0) { 364 flags |= BRIDGE_FLAGS_MASTER; 365 } else { 366 usage(); 367 } 368 argc--; argv++; 369 } 370 if (d == NULL) { 371 fprintf(stderr, "Device is a required argument.\n"); 372 return -1; 373 } 374 375 376 req.ifm.ifi_index = ll_name_to_index(d); 377 if (req.ifm.ifi_index == 0) { 378 fprintf(stderr, "Cannot find bridge device \"%s\"\n", d); 379 return -1; 380 } 381 382 /* Nested PROTINFO attribute. Contains: port flags, cost, priority and 383 * state. 384 */ 385 nest = addattr_nest(&req.n, sizeof(req), 386 IFLA_PROTINFO | NLA_F_NESTED); 387 /* Flags first */ 388 if (bpdu_guard >= 0) 389 addattr8(&req.n, sizeof(req), IFLA_BRPORT_GUARD, bpdu_guard); 390 if (hairpin >= 0) 391 addattr8(&req.n, sizeof(req), IFLA_BRPORT_MODE, hairpin); 392 if (fast_leave >= 0) 393 addattr8(&req.n, sizeof(req), IFLA_BRPORT_FAST_LEAVE, 394 fast_leave); 395 if (root_block >= 0) 396 addattr8(&req.n, sizeof(req), IFLA_BRPORT_PROTECT, root_block); 397 if (flood >= 0) 398 addattr8(&req.n, sizeof(req), IFLA_BRPORT_UNICAST_FLOOD, flood); 399 if (mcast_flood >= 0) 400 addattr8(&req.n, sizeof(req), IFLA_BRPORT_MCAST_FLOOD, 401 mcast_flood); 402 if (learning >= 0) 403 addattr8(&req.n, sizeof(req), IFLA_BRPORT_LEARNING, learning); 404 if (learning_sync >= 0) 405 addattr8(&req.n, sizeof(req), IFLA_BRPORT_LEARNING_SYNC, 406 learning_sync); 407 408 if (cost > 0) 409 addattr32(&req.n, sizeof(req), IFLA_BRPORT_COST, cost); 410 411 if (priority >= 0) 412 addattr16(&req.n, sizeof(req), IFLA_BRPORT_PRIORITY, priority); 413 414 if (state >= 0) 415 addattr8(&req.n, sizeof(req), IFLA_BRPORT_STATE, state); 416 417 addattr_nest_end(&req.n, nest); 418 419 /* IFLA_AF_SPEC nested attribute. Contains IFLA_BRIDGE_FLAGS that 420 * designates master or self operation and IFLA_BRIDGE_MODE 421 * for hw 'vepa' or 'veb' operation modes. The hwmodes are 422 * only valid in 'self' mode on some devices so far. 423 */ 424 if (mode >= 0 || flags > 0) { 425 nest = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC); 426 427 if (flags > 0) 428 addattr16(&req.n, sizeof(req), IFLA_BRIDGE_FLAGS, flags); 429 430 if (mode >= 0) 431 addattr16(&req.n, sizeof(req), IFLA_BRIDGE_MODE, mode); 432 433 addattr_nest_end(&req.n, nest); 434 } 435 436 if (rtnl_talk(&rth, &req.n, NULL, 0) < 0) 437 return -1; 438 439 return 0; 440 } 441 442 static int brlink_show(int argc, char **argv) 443 { 444 char *filter_dev = NULL; 445 446 while (argc > 0) { 447 if (strcmp(*argv, "dev") == 0) { 448 NEXT_ARG(); 449 if (filter_dev) 450 duparg("dev", *argv); 451 filter_dev = *argv; 452 } 453 argc--; argv++; 454 } 455 456 if (filter_dev) { 457 if ((filter_index = ll_name_to_index(filter_dev)) == 0) { 458 fprintf(stderr, "Cannot find device \"%s\"\n", 459 filter_dev); 460 return -1; 461 } 462 } 463 464 if (show_details) { 465 if (rtnl_wilddump_req_filter(&rth, PF_BRIDGE, RTM_GETLINK, 466 (compress_vlans ? 467 RTEXT_FILTER_BRVLAN_COMPRESSED : 468 RTEXT_FILTER_BRVLAN)) < 0) { 469 perror("Cannon send dump request"); 470 exit(1); 471 } 472 } else { 473 if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETLINK) < 0) { 474 perror("Cannon send dump request"); 475 exit(1); 476 } 477 } 478 479 if (rtnl_dump_filter(&rth, print_linkinfo, stdout) < 0) { 480 fprintf(stderr, "Dump terminated\n"); 481 exit(1); 482 } 483 return 0; 484 } 485 486 int do_link(int argc, char **argv) 487 { 488 ll_init_map(&rth); 489 if (argc > 0) { 490 if (matches(*argv, "set") == 0 || 491 matches(*argv, "change") == 0) 492 return brlink_modify(argc-1, argv+1); 493 if (matches(*argv, "show") == 0 || 494 matches(*argv, "lst") == 0 || 495 matches(*argv, "list") == 0) 496 return brlink_show(argc-1, argv+1); 497 if (matches(*argv, "help") == 0) 498 usage(); 499 } else 500 return brlink_show(0, NULL); 501 502 fprintf(stderr, "Command \"%s\" is unknown, try \"bridge link help\".\n", *argv); 503 exit(-1); 504 } 505