1 /* brctl.c - ethernet bridge control
3 * Copyright 2013 Ashwini Kumar <ak.ashwini1981@gmail.com>
4 * Copyright 2013 Kyungwan Han <asura321@gmail.com>
8 USE_BRCTL(NEWTOY(brctl, "<1", TOYFLAG_USR|TOYFLAG_SBIN))
14 usage: brctl COMMAND [BRIDGE [INTERFACE]]
16 Manage ethernet bridges
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
36 #include <linux/if_bridge.h>
41 #define MAX_BRIDGES 1024 //same is no of ports supported
43 static void get_ports(char *bridge, int *indices)
46 int ifindices[MAX_BRIDGES];
47 unsigned long args[4] = { BRCTL_GET_PORT_LIST,
48 (unsigned long) ifindices, MAX_BRIDGES, 0 };
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));
58 void get_br_info(char *bridge, struct __bridge_info *info)
61 unsigned long args[4] = { BRCTL_GET_BRIDGE_INFO,
62 (unsigned long) info, 0, 0 };
64 memset(info, 0, sizeof(*info));
65 xstrncpy(ifr.ifr_name, bridge, IFNAMSIZ);
66 ifr.ifr_data = (char *)args;
68 if (ioctl(TT.sockfd, SIOCDEVPRIVATE, &ifr) < 0) {
69 perror_msg("%s: can't get info %s\n", bridge, strerror(errno));
74 void br_show(char **argv)
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];
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");
86 for (i = 0; i < num; i++) {
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);
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");
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]);
105 if (cnt) printf("\n\t\t\t\t\t\t\t");
113 void br_addbr(char **argv)
116 unsigned long args[4] = {BRCTL_ADD_BRIDGE, (unsigned long) br, 0, 0};
119 xioctl(TT.sockfd, SIOCBRADDBR, argv[0]);
121 xstrncpy(br, argv[0], IFNAMSIZ);
122 xioctl(TT.sockfd, SIOCSIFBR, args);
126 void br_delbr(char **argv)
129 unsigned long args[4] = {BRCTL_DEL_BRIDGE, (unsigned long) br, 0, 0};
132 xioctl(TT.sockfd, SIOCBRDELBR, argv[0]);
134 xstrncpy(br, argv[0], IFNAMSIZ);
135 xioctl(TT.sockfd, SIOCSIFBR, args);
139 void br_addif(char **argv)
143 unsigned long args[4] = {BRCTL_ADD_IF, 0, 0, 0};
145 if (!(index = if_nametoindex(argv[1]))) perror_exit("interface %s", argv[1]);
147 ifr.ifr_ifindex = index;
148 xioctl(TT.sockfd, SIOCBRADDIF, &ifr);
151 xstrncpy(ifr.ifr_name, argv[0], IFNAMSIZ);
152 ifr.ifr_data = (char *)args;
153 xioctl(TT.sockfd, SIOCDEVPRIVATE, &ifr);
157 void br_delif(char **argv)
161 unsigned long args[4] = {BRCTL_DEL_IF, 0, 0, 0};
163 if (!(index = if_nametoindex(argv[1]))) perror_exit("interface %s",argv[1]);
165 ifr.ifr_ifindex = ifindex;
166 xioctl(TT.sockfd, SIOCBRDELIF, &ifr);
169 xstrncpy(ifr.ifr_name, argv[0], IFNAMSIZ);
170 ifr.ifr_data = (char *)args;
171 xioctl(TT.sockfd, SIOCDEVPRIVATE, &ifr);
175 static void strtotimeval(struct timeval *tv, char *time)
179 if (sscanf(time, "%lf", &secs) != 1) error_exit("time format not proper");
181 tv->tv_usec = 1000000 * (secs - tv->tv_sec);
184 static unsigned long tv_to_jify(struct timeval *tv)
186 unsigned long long jify;
188 jify = 1000000ULL * tv->tv_sec + tv->tv_usec;
192 void set_time(char *br, unsigned long cmd, unsigned long val)
195 unsigned long args[4] = {cmd, val, 0, 0};
197 xstrncpy(ifr.ifr_name, br, IFNAMSIZ);
198 ifr.ifr_data = (char *)args;
199 xioctl(TT.sockfd, SIOCDEVPRIVATE, &ifr);
202 void br_set_ageing_time(char **argv)
206 strtotimeval(&tv, argv[1]);
207 set_time(argv[0], BRCTL_SET_AGEING_TIME, tv_to_jify(&tv));
210 void br_set_fwd_delay(char **argv)
214 strtotimeval(&tv, argv[1]);
215 set_time(argv[0], BRCTL_SET_BRIDGE_FORWARD_DELAY, tv_to_jify(&tv));
218 void br_set_hello_time(char **argv)
222 strtotimeval(&tv, argv[1]);
223 set_time(argv[0], BRCTL_SET_BRIDGE_HELLO_TIME, tv_to_jify(&tv));
226 void br_set_max_age(char **argv)
230 strtotimeval(&tv, argv[1]);
231 set_time(argv[0], BRCTL_SET_BRIDGE_MAX_AGE, tv_to_jify(&tv));
234 void br_set_bridge_prio(char **argv)
238 if (sscanf(argv[1], "%i", &prio) != 1) error_exit("prio not proper");
239 set_time(argv[0], BRCTL_SET_BRIDGE_PRIORITY, prio);
242 void br_set_stp(char **argv)
248 } ss[] = {{"1", 1}, {"yes", 1},{"on", 1},
249 {"0", 0}, {"no", 0},{"off", 0}};
251 for (i = 0; i < ARRAY_LEN(ss); i++) {
252 if (!strcmp(ss[i].n, argv[1])) break;
254 if (i >= ARRAY_LEN(ss)) error_exit("invalid stp state");
255 set_time(argv[0], BRCTL_SET_BRIDGE_STP_STATE, ss[i].set);
258 void set_cost_prio(char *br, char *port, unsigned long cmd, unsigned long val)
261 int i, index, pindices[MAX_BRIDGES];
262 unsigned long args[4] = {cmd, 0, val, 0};
264 if (!(index = if_nametoindex(port))) error_exit("invalid port");
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;
271 if (i >= MAX_BRIDGES) error_exit("%s not in bridge", port);
273 xstrncpy(ifr.ifr_name, br, IFNAMSIZ);
274 ifr.ifr_data = (char *)args;
275 xioctl(TT.sockfd, SIOCDEVPRIVATE, &ifr);
278 void br_set_path_cost(char **argv)
282 cost = atolx_range(argv[2], 0, INT_MAX);
283 set_cost_prio(argv[0], argv[1], BRCTL_SET_PATH_COST, cost);
286 void br_set_port_prio(char **argv)
290 prio = atolx_range(argv[2], 0, INT_MAX);
291 set_cost_prio(argv[0], argv[1], BRCTL_SET_PORT_PRIORITY, prio);
295 void brctl_main(void)
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},
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;
320 if (strcmp(t->cmd, *toys.optargs)) continue;
322 toys.optargs++, toys.optc--;
323 if (toys.optc < t->nargs) help_exit("check args");
325 toys.optargs += t->nargs;
326 toys.optc -= t->nargs;
330 if (i == ARRAY_LEN(cc)) help_exit("invalid option '%s'", *toys.optargs);