1/* 2 * Copyright (C) 2000 Lennert Buytenhek 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License as 6 * published by the Free Software Foundation; either version 2 of the 7 * License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 */ 18 19#include <stdio.h> 20#include <stdlib.h> 21#include <string.h> 22#include <sys/time.h> 23#include <sys/select.h> 24#include <unistd.h> 25#include <errno.h> 26#include <asm/param.h> 27#include "libbridge.h" 28#include "brctl.h" 29 30static int strtotimeval(struct timeval *tv, const char *time) 31{ 32 double secs; 33 if (sscanf(time, "%lf", &secs) != 1) 34 return -1; 35 tv->tv_sec = secs; 36 tv->tv_usec = 1000000 * (secs - tv->tv_sec); 37 return 0; 38} 39 40static int br_cmd_addbr(int argc, char*const* argv) 41{ 42 int err; 43 44 switch (err = br_add_bridge(argv[1])) { 45 case 0: 46 return 0; 47 48 case EEXIST: 49 fprintf(stderr, "device %s already exists; can't create " 50 "bridge with the same name\n", argv[1]); 51 return 1; 52 default: 53 fprintf(stderr, "add bridge failed: %s\n", 54 strerror(err)); 55 return 1; 56 } 57} 58 59static int br_cmd_delbr(int argc, char*const* argv) 60{ 61 int err; 62 63 switch (err = br_del_bridge(argv[1])){ 64 case 0: 65 return 0; 66 67 case ENXIO: 68 fprintf(stderr, "bridge %s doesn't exist; can't delete it\n", 69 argv[1]); 70 return 1; 71 72 case EBUSY: 73 fprintf(stderr, "bridge %s is still up; can't delete it\n", 74 argv[1]); 75 return 1; 76 77 default: 78 fprintf(stderr, "can't delete bridge %s: %s\n", 79 argv[1], strerror(err)); 80 return 1; 81 } 82} 83 84static int wait_to_forward_state(const char *br_ifname, const char *ifname) 85{ 86 int err; 87 struct port_info info; 88 struct timeval now, later, tout; 89 90 if ((err = br_refresh())) { 91 fprintf(stderr, "Unable to refresh bridge info:%d\n", err); 92 return 1; 93 } 94 95 if ((err = br_get_port_info(br_ifname, ifname, &info))) { 96 fprintf(stderr, "Unable to get port info:%d\n", err); 97 return 1; 98 } 99 100 /* Wait for this port transition to FORWARDING state. */ 101 gettimeofday(&now, NULL); 102 later = now; 103 while (info.state != BR_STATE_FORWARDING) { 104 if ((later.tv_sec - now.tv_sec) > 5) { 105 printf("device %s timedout changing to" 106 "BR_STATE_FORWARDING\n", ifname); 107 return 1; 108 } 109 tout.tv_sec = 0; 110 tout.tv_usec = 200000; /* 200 milli secs */ 111 select(0, NULL, NULL, NULL, &tout); 112 if ((err = br_get_port_info(br_ifname, ifname, &info))) { 113 fprintf(stderr, "Unable to get port info:%d\n", err); 114 return 1; 115 } 116 gettimeofday(&later, NULL); 117 } 118 119 return 0; 120} 121 122static int br_cmd_addif(int argc, char *const* argv) 123{ 124 const char *brname; 125 int err; 126 int waitarg = 0; 127 128 argc -= 2; 129 brname = *++argv; 130 131 /* is last argv "wait" */ 132 if (!strcmp(*(argv+argc), "wait")) { 133 waitarg = 1; 134 argc -= 1; /* skip last wait argv */ 135 } 136 137 while (argc-- > 0) { 138 const char *ifname = *++argv; 139 err = br_add_interface(brname, ifname); 140 141 switch(err) { 142 case 0: 143 if (waitarg && wait_to_forward_state(brname, ifname)) 144 break; 145 continue; 146 147 case ENODEV: 148 fprintf(stderr, "interface %s does not exist!\n", ifname); 149 break; 150 151 case EBUSY: 152 fprintf(stderr, "device %s is already a member of a bridge; " 153 "can't enslave it to bridge %s.\n", ifname, 154 brname); 155 break; 156 157 case ELOOP: 158 fprintf(stderr, "device %s is a bridge device itself; " 159 "can't enslave a bridge device to a bridge device.\n", 160 ifname); 161 break; 162 163 default: 164 fprintf(stderr, "can't add %s to bridge %s: %s\n", 165 ifname, brname, strerror(err)); 166 } 167 return 1; 168 } 169 return 0; 170} 171 172static int br_cmd_delif(int argc, char *const* argv) 173{ 174 const char *brname; 175 int err; 176 177 argc -= 2; 178 brname = *++argv; 179 180 while (argc-- > 0) { 181 const char *ifname = *++argv; 182 err = br_del_interface(brname, ifname); 183 switch (err) { 184 case 0: 185 continue; 186 187 case ENODEV: 188 fprintf(stderr, "interface %s does not exist!\n", 189 ifname); 190 break; 191 192 case EINVAL: 193 fprintf(stderr, "device %s is not a slave of %s\n", 194 ifname, brname); 195 break; 196 197 default: 198 fprintf(stderr, "can't delete %s from %s: %s\n", 199 ifname, brname, strerror(err)); 200 } 201 return 1; 202 } 203 return 0; 204} 205 206static int br_cmd_setageing(int argc, char *const* argv) 207{ 208 int err; 209 struct timeval tv; 210 211 if (strtotimeval(&tv, argv[2])) { 212 fprintf(stderr, "bad ageing time value\n"); 213 return 1; 214 } 215 216 err = br_set_ageing_time(argv[1], &tv); 217 if (err) 218 fprintf(stderr, "set ageing time failed: %s\n", 219 strerror(err)); 220 221 return err != 0; 222} 223 224static int br_cmd_setbridgeprio(int argc, char *const* argv) 225{ 226 int prio; 227 int err; 228 229 if (sscanf(argv[2], "%i", &prio) != 1) { 230 fprintf(stderr,"bad priority\n"); 231 return 1; 232 } 233 234 err = br_set_bridge_priority(argv[1], prio); 235 if (err) 236 fprintf(stderr, "set bridge priority failed: %s\n", 237 strerror(err)); 238 return err != 0; 239} 240 241static int br_cmd_setfd(int argc, char *const* argv) 242{ 243 struct timeval tv; 244 int err; 245 246 if (strtotimeval(&tv, argv[2])) { 247 fprintf(stderr, "bad forward delay value\n"); 248 return 1; 249 } 250 251 err = br_set_bridge_forward_delay(argv[1], &tv); 252 if (err) 253 fprintf(stderr, "set forward delay failed: %s\n", 254 strerror(err)); 255 256 return err != 0; 257} 258 259static int br_cmd_sethello(int argc, char *const* argv) 260{ 261 struct timeval tv; 262 int err; 263 264 if (strtotimeval(&tv, argv[2])) { 265 fprintf(stderr, "bad hello timer value\n"); 266 return 1; 267 } 268 269 err = br_set_bridge_hello_time(argv[1], &tv); 270 if (err) 271 fprintf(stderr, "set hello timer failed: %s\n", 272 strerror(err)); 273 274 return err != 0; 275} 276 277static int br_cmd_setmaxage(int argc, char *const* argv) 278{ 279 struct timeval tv; 280 int err; 281 282 if (strtotimeval(&tv, argv[2])) { 283 fprintf(stderr, "bad max age value\n"); 284 return 1; 285 } 286 err = br_set_bridge_max_age(argv[1], &tv); 287 if (err) 288 fprintf(stderr, "set max age failed: %s\n", 289 strerror(err)); 290 291 return err != 0; 292} 293 294static int br_cmd_setpathcost(int argc, char *const* argv) 295{ 296 int cost, err; 297 298 if (sscanf(argv[3], "%i", &cost) != 1) { 299 fprintf(stderr, "bad path cost value\n"); 300 return 1; 301 } 302 303 err = br_set_path_cost(argv[1], argv[2], cost); 304 if (err) 305 fprintf(stderr, "set path cost failed: %s\n", 306 strerror(err)); 307 return err != 0; 308} 309 310static int br_cmd_setportprio(int argc, char *const* argv) 311{ 312 int cost, err; 313 314 if (sscanf(argv[3], "%i", &cost) != 1) { 315 fprintf(stderr, "bad path priority value\n"); 316 return 1; 317 } 318 319 err = br_set_path_cost(argv[1], argv[2], cost); 320 if (err) 321 fprintf(stderr, "set port priority failed: %s\n", 322 strerror(errno)); 323 324 return err != 0; 325} 326 327static int br_cmd_stp(int argc, char *const* argv) 328{ 329 int stp, err; 330 331 if (!strcmp(argv[2], "on") || !strcmp(argv[2], "yes") 332 || !strcmp(argv[2], "1")) 333 stp = 1; 334 else if (!strcmp(argv[2], "off") || !strcmp(argv[2], "no") 335 || !strcmp(argv[2], "0")) 336 stp = 0; 337 else { 338 fprintf(stderr, "expect on/off for argument\n"); 339 return 1; 340 } 341 342 err = br_set_stp_state(argv[1], stp); 343 if (err) 344 fprintf(stderr, "set stp status failed: %s\n", 345 strerror(errno)); 346 return err != 0; 347} 348 349static int br_cmd_showstp(int argc, char *const* argv) 350{ 351 struct bridge_info info; 352 353 if (br_get_bridge_info(argv[1], &info)) { 354 fprintf(stderr, "%s: can't get info %s\n", argv[1], 355 strerror(errno)); 356 return 1; 357 } 358 359 br_dump_info(argv[1], &info); 360 return 0; 361} 362 363static int show_bridge(const char *name, void *arg) 364{ 365 struct bridge_info info; 366 367 printf("%s\t\t", name); 368 fflush(stdout); 369 370 if (br_get_bridge_info(name, &info)) { 371 fprintf(stderr, "can't get info %s\n", 372 strerror(errno)); 373 return 1; 374 } 375 376 br_dump_bridge_id((unsigned char *)&info.bridge_id); 377 printf("\t%s\t\t", info.stp_enabled?"yes":"no"); 378 379 br_dump_interface_list(name); 380 return 0; 381} 382 383static int br_cmd_show(int argc, char *const* argv) 384{ 385 printf("bridge name\tbridge id\t\tSTP enabled\tinterfaces\n"); 386 br_foreach_bridge(show_bridge, NULL); 387 return 0; 388} 389 390static int compare_fdbs(const void *_f0, const void *_f1) 391{ 392 const struct fdb_entry *f0 = _f0; 393 const struct fdb_entry *f1 = _f1; 394 395 return memcmp(f0->mac_addr, f1->mac_addr, 6); 396} 397 398static int br_cmd_showmacs(int argc, char *const* argv) 399{ 400 const char *brname = argv[1]; 401#define CHUNK 128 402 int i, n; 403 struct fdb_entry *fdb = NULL; 404 int offset = 0; 405 406 for(;;) { 407 fdb = realloc(fdb, (offset + CHUNK) * sizeof(struct fdb_entry)); 408 if (!fdb) { 409 fprintf(stderr, "Out of memory\n"); 410 return 1; 411 } 412 413 n = br_read_fdb(brname, fdb+offset, offset, CHUNK); 414 if (n == 0) 415 break; 416 417 if (n < 0) { 418 fprintf(stderr, "read of forward table failed: %s\n", 419 strerror(errno)); 420 return 1; 421 } 422 423 offset += n; 424 } 425 426 qsort(fdb, offset, sizeof(struct fdb_entry), compare_fdbs); 427 428 printf("port no\tmac addr\t\tis local?\tageing timer\n"); 429 for (i = 0; i < offset; i++) { 430 const struct fdb_entry *f = fdb + i; 431 printf("%3i\t", f->port_no); 432 printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\t", 433 f->mac_addr[0], f->mac_addr[1], f->mac_addr[2], 434 f->mac_addr[3], f->mac_addr[4], f->mac_addr[5]); 435 printf("%s\t\t", f->is_local?"yes":"no"); 436 br_show_timer(&f->ageing_timer_value); 437 printf("\n"); 438 } 439 return 0; 440} 441 442static const struct command commands[] = { 443 { 1, "addbr", br_cmd_addbr, "<bridge>\t\tadd bridge" }, 444 { 1, "delbr", br_cmd_delbr, "<bridge>\t\tdelete bridge" }, 445 { 2, "addif", br_cmd_addif, 446 "<bridge> <device>\tadd interface to bridge" }, 447 { 2, "delif", br_cmd_delif, 448 "<bridge> <device>\tdelete interface from bridge" }, 449 { 2, "setageing", br_cmd_setageing, 450 "<bridge> <time>\t\tset ageing time" }, 451 { 2, "setbridgeprio", br_cmd_setbridgeprio, 452 "<bridge> <prio>\t\tset bridge priority" }, 453 { 2, "setfd", br_cmd_setfd, 454 "<bridge> <time>\t\tset bridge forward delay" }, 455 { 2, "sethello", br_cmd_sethello, 456 "<bridge> <time>\t\tset hello time" }, 457 { 2, "setmaxage", br_cmd_setmaxage, 458 "<bridge> <time>\t\tset max message age" }, 459 { 3, "setpathcost", br_cmd_setpathcost, 460 "<bridge> <port> <cost>\tset path cost" }, 461 { 3, "setportprio", br_cmd_setportprio, 462 "<bridge> <port> <prio>\tset port priority" }, 463 { 0, "show", br_cmd_show, "\t\t\tshow a list of bridges" }, 464 { 1, "showmacs", br_cmd_showmacs, 465 "<bridge>\t\tshow a list of mac addrs"}, 466 { 1, "showstp", br_cmd_showstp, 467 "<bridge>\t\tshow bridge stp info"}, 468 { 2, "stp", br_cmd_stp, 469 "<bridge> {on|off}\tturn stp on/off" }, 470}; 471 472const struct command *command_lookup(const char *cmd) 473{ 474 int i; 475 476 for (i = 0; i < sizeof(commands)/sizeof(commands[0]); i++) { 477 if (!strcmp(cmd, commands[i].name)) 478 return &commands[i]; 479 } 480 481 return NULL; 482} 483 484void command_helpall(void) 485{ 486 int i; 487 488 for (i = 0; i < sizeof(commands)/sizeof(commands[0]); i++) { 489 printf("\t%-10s\t%s\n", commands[i].name, commands[i].help); 490 } 491} 492