1 /* brctl.c - ethernet bridge control 2 * 3 * Copyright 2013 Ashwini Kumar <ak.ashwini1981@gmail.com> 4 * Copyright 2013 Kyungwan Han <asura321@gmail.com> 5 * 6 * No Standard 7 8 USE_BRCTL(NEWTOY(brctl, "<1", TOYFLAG_USR|TOYFLAG_SBIN)) 9 10 config BRCTL 11 bool "brctl" 12 default n 13 help 14 usage: brctl COMMAND [BRIDGE [INTERFACE]] 15 16 Manage ethernet bridges 17 18 Commands: 19 show Show a list of bridges 20 addbr BRIDGE Create BRIDGE 21 delbr BRIDGE Delete BRIDGE 22 addif BRIDGE IFACE Add IFACE to BRIDGE 23 delif BRIDGE IFACE Delete IFACE from BRIDGE 24 setageing BRIDGE TIME Set ageing time 25 setfd BRIDGE TIME Set bridge forward delay 26 sethello BRIDGE TIME Set hello time 27 setmaxage BRIDGE TIME Set max message age 28 setpathcost BRIDGE PORT COST Set path cost 29 setportprio BRIDGE PORT PRIO Set port priority 30 setbridgeprio BRIDGE PRIO Set bridge priority 31 stp BRIDGE [1/yes/on|0/no/off] STP on/off 32 */ 33 34 #define FOR_brctl 35 #include "toys.h" 36 #include <linux/if_bridge.h> 37 38 GLOBALS( 39 int sockfd; 40 ) 41 #define MAX_BRIDGES 1024 //same is no of ports supported 42 43 static void get_ports(char *bridge, int *indices) 44 { 45 struct ifreq ifr; 46 int ifindices[MAX_BRIDGES]; 47 unsigned long args[4] = { BRCTL_GET_PORT_LIST, 48 (unsigned long) ifindices, MAX_BRIDGES, 0 }; 49 50 memset(ifindices, 0, MAX_BRIDGES); 51 args[1] = (unsigned long)ifindices; 52 xstrncpy(ifr.ifr_name, bridge, IFNAMSIZ); 53 ifr.ifr_data = (char *)args; 54 xioctl(TT.sockfd, SIOCDEVPRIVATE, &ifr); 55 if (indices) memcpy(indices, ifindices, sizeof(ifindices)); 56 } 57 58 void get_br_info(char *bridge, struct __bridge_info *info) 59 { 60 struct ifreq ifr; 61 unsigned long args[4] = { BRCTL_GET_BRIDGE_INFO, 62 (unsigned long) info, 0, 0 }; 63 64 memset(info, 0, sizeof(*info)); 65 xstrncpy(ifr.ifr_name, bridge, IFNAMSIZ); 66 ifr.ifr_data = (char *)args; 67 68 if (ioctl(TT.sockfd, SIOCDEVPRIVATE, &ifr) < 0) { 69 perror_msg("%s: can't get info %s\n", bridge, strerror(errno)); 70 return; 71 } 72 } 73 74 void br_show(char **argv) 75 { 76 struct __bridge_info info; 77 int num, cnt, i, j, ifindices[MAX_BRIDGES], pindices[MAX_BRIDGES]; 78 unsigned long args[4] = { BRCTL_GET_BRIDGES, 79 (unsigned long)ifindices, MAX_BRIDGES,0 }; 80 char br[IF_NAMESIZE], ifn[IF_NAMESIZE]; 81 82 num = ioctl(TT.sockfd, SIOCGIFBR, args); //ret is num of bridges found 83 if (num < 0) error_exit("get bridges fail"); 84 printf("bridge name\tbridge id\t\tSTP enabled\tinterfaces\n"); 85 86 for (i = 0; i < num; i++) { 87 unsigned char *id; 88 89 if (!if_indextoname(ifindices[i], br)) perror_exit("interface not found"); 90 get_br_info(br, &info); 91 id = (unsigned char*)&(info.bridge_id); 92 printf("%s\t\t",br); 93 printf("%.2x%.2x.%.2x%.2x%.2x%.2x%.2x%.2x", id[0], id[1], 94 id[2], id[3], id[4], id[5], id[6], id[7]); 95 printf("\t%s\t\t",(info.stp_enabled)?"yes" : "no"); 96 97 memset(pindices, 0, sizeof(pindices)); 98 get_ports(br, pindices); 99 for (j = 0, cnt = 0; j < MAX_BRIDGES; j++) { 100 if (!pindices[j]) continue; 101 if (!if_indextoname(pindices[j], ifn)) { 102 error_msg("no name for index :%d", pindices[j]); 103 continue; 104 } 105 if (cnt) printf("\n\t\t\t\t\t\t\t"); 106 printf("%s", ifn); 107 cnt++; 108 } 109 xputc('\n'); 110 } 111 } 112 113 void br_addbr(char **argv) 114 { 115 char br[IFNAMSIZ]; 116 unsigned long args[4] = {BRCTL_ADD_BRIDGE, (unsigned long) br, 0, 0}; 117 118 #ifdef SIOCBRADDBR 119 xioctl(TT.sockfd, SIOCBRADDBR, argv[0]); 120 #else 121 xstrncpy(br, argv[0], IFNAMSIZ); 122 xioctl(TT.sockfd, SIOCSIFBR, args); 123 #endif 124 } 125 126 void br_delbr(char **argv) 127 { 128 char br[IFNAMSIZ]; 129 unsigned long args[4] = {BRCTL_DEL_BRIDGE, (unsigned long) br, 0, 0}; 130 131 #ifdef SIOCBRDELBR 132 xioctl(TT.sockfd, SIOCBRDELBR, argv[0]); 133 #else 134 xstrncpy(br, argv[0], IFNAMSIZ); 135 xioctl(TT.sockfd, SIOCSIFBR, args); 136 #endif 137 } 138 139 void br_addif(char **argv) 140 { 141 int index; 142 struct ifreq ifr; 143 unsigned long args[4] = {BRCTL_ADD_IF, 0, 0, 0}; 144 145 if (!(index = if_nametoindex(argv[1]))) perror_exit("interface %s", argv[1]); 146 #ifdef SIOCBRADDIF 147 ifr.ifr_ifindex = index; 148 xioctl(TT.sockfd, SIOCBRADDIF, &ifr); 149 #else 150 args[1] = index; 151 xstrncpy(ifr.ifr_name, argv[0], IFNAMSIZ); 152 ifr.ifr_data = (char *)args; 153 xioctl(TT.sockfd, SIOCDEVPRIVATE, &ifr); 154 #endif 155 } 156 157 void br_delif(char **argv) 158 { 159 int index; 160 struct ifreq ifr; 161 unsigned long args[4] = {BRCTL_DEL_IF, 0, 0, 0}; 162 163 if (!(index = if_nametoindex(argv[1]))) perror_exit("interface %s",argv[1]); 164 #ifdef SIOCBRDELIF 165 ifr.ifr_ifindex = ifindex; 166 xioctl(TT.sockfd, SIOCBRDELIF, &ifr); 167 #else 168 args[1] = index; 169 xstrncpy(ifr.ifr_name, argv[0], IFNAMSIZ); 170 ifr.ifr_data = (char *)args; 171 xioctl(TT.sockfd, SIOCDEVPRIVATE, &ifr); 172 #endif 173 } 174 175 static void strtotimeval(struct timeval *tv, char *time) 176 { 177 double secs; 178 179 if (sscanf(time, "%lf", &secs) != 1) error_exit("time format not proper"); 180 tv->tv_sec = secs; 181 tv->tv_usec = 1000000 * (secs - tv->tv_sec); 182 } 183 184 static unsigned long tv_to_jify(struct timeval *tv) 185 { 186 unsigned long long jify; 187 188 jify = 1000000ULL * tv->tv_sec + tv->tv_usec; 189 return (jify/10000); 190 } 191 192 void set_time(char *br, unsigned long cmd, unsigned long val) 193 { 194 struct ifreq ifr; 195 unsigned long args[4] = {cmd, val, 0, 0}; 196 197 xstrncpy(ifr.ifr_name, br, IFNAMSIZ); 198 ifr.ifr_data = (char *)args; 199 xioctl(TT.sockfd, SIOCDEVPRIVATE, &ifr); 200 } 201 202 void br_set_ageing_time(char **argv) 203 { 204 struct timeval tv; 205 206 strtotimeval(&tv, argv[1]); 207 set_time(argv[0], BRCTL_SET_AGEING_TIME, tv_to_jify(&tv)); 208 } 209 210 void br_set_fwd_delay(char **argv) 211 { 212 struct timeval tv; 213 214 strtotimeval(&tv, argv[1]); 215 set_time(argv[0], BRCTL_SET_BRIDGE_FORWARD_DELAY, tv_to_jify(&tv)); 216 } 217 218 void br_set_hello_time(char **argv) 219 { 220 struct timeval tv; 221 222 strtotimeval(&tv, argv[1]); 223 set_time(argv[0], BRCTL_SET_BRIDGE_HELLO_TIME, tv_to_jify(&tv)); 224 } 225 226 void br_set_max_age(char **argv) 227 { 228 struct timeval tv; 229 230 strtotimeval(&tv, argv[1]); 231 set_time(argv[0], BRCTL_SET_BRIDGE_MAX_AGE, tv_to_jify(&tv)); 232 } 233 234 void br_set_bridge_prio(char **argv) 235 { 236 int prio; 237 238 if (sscanf(argv[1], "%i", &prio) != 1) error_exit("prio not proper"); 239 set_time(argv[0], BRCTL_SET_BRIDGE_PRIORITY, prio); 240 } 241 242 void br_set_stp(char **argv) 243 { 244 int i; 245 struct stp { 246 char *n; 247 int set; 248 } ss[] = {{"1", 1}, {"yes", 1},{"on", 1}, 249 {"0", 0}, {"no", 0},{"off", 0}}; 250 251 for (i = 0; i < ARRAY_LEN(ss); i++) { 252 if (!strcmp(ss[i].n, argv[1])) break; 253 } 254 if (i >= ARRAY_LEN(ss)) error_exit("invalid stp state"); 255 set_time(argv[0], BRCTL_SET_BRIDGE_STP_STATE, ss[i].set); 256 } 257 258 void set_cost_prio(char *br, char *port, unsigned long cmd, unsigned long val) 259 { 260 struct ifreq ifr; 261 int i, index, pindices[MAX_BRIDGES]; 262 unsigned long args[4] = {cmd, 0, val, 0}; 263 264 if (!(index = if_nametoindex(port))) error_exit("invalid port"); 265 266 memset(pindices, 0, sizeof(pindices)); 267 get_ports(br, pindices); 268 for (i = 0; i < MAX_BRIDGES; i++) { 269 if (index == pindices[i]) break; 270 } 271 if (i >= MAX_BRIDGES) error_exit("%s not in bridge", port); 272 args[1] = i; 273 xstrncpy(ifr.ifr_name, br, IFNAMSIZ); 274 ifr.ifr_data = (char *)args; 275 xioctl(TT.sockfd, SIOCDEVPRIVATE, &ifr); 276 } 277 278 void br_set_path_cost(char **argv) 279 { 280 int cost; 281 282 cost = atolx_range(argv[2], 0, INT_MAX); 283 set_cost_prio(argv[0], argv[1], BRCTL_SET_PATH_COST, cost); 284 } 285 286 void br_set_port_prio(char **argv) 287 { 288 int prio; 289 290 prio = atolx_range(argv[2], 0, INT_MAX); 291 set_cost_prio(argv[0], argv[1], BRCTL_SET_PORT_PRIORITY, prio); 292 293 } 294 295 void brctl_main(void) 296 { 297 int i; 298 struct cmds { 299 char *cmd; 300 int nargs; 301 void (*f)(char **argv); 302 } cc[] = {{"show", 0, br_show}, 303 {"addbr", 1, br_addbr}, {"delbr", 1, br_delbr}, 304 {"addif", 2, br_addif}, {"delif", 2, br_delif}, 305 {"setageing", 2, br_set_ageing_time}, 306 {"setfd", 2, br_set_fwd_delay}, 307 {"sethello", 2, br_set_hello_time}, 308 {"setmaxage", 2, br_set_max_age}, 309 {"setpathcost", 3, br_set_path_cost}, 310 {"setportprio", 3, br_set_port_prio}, 311 {"setbridgeprio", 2, br_set_bridge_prio}, 312 {"stp", 2, br_set_stp}, 313 }; 314 315 TT.sockfd = xsocket(AF_INET, SOCK_STREAM, 0); 316 while (*toys.optargs) { 317 for (i = 0; i < ARRAY_LEN(cc); i++) { 318 struct cmds *t = cc + i; 319 320 if (strcmp(t->cmd, *toys.optargs)) continue; 321 322 toys.optargs++, toys.optc--; 323 if (toys.optc < t->nargs) help_exit("check args"); 324 t->f(toys.optargs); 325 toys.optargs += t->nargs; 326 toys.optc -= t->nargs; 327 break; 328 } 329 330 if (i == ARRAY_LEN(cc)) help_exit("invalid option '%s'", *toys.optargs); 331 } 332 xclose(TT.sockfd); 333 } 334