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
GLOBALS(int sockfd;)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
get_br_info(char * bridge,struct __bridge_info * info)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
br_show(char ** argv)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
br_addbr(char ** argv)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
br_delbr(char ** argv)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
br_addif(char ** argv)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
br_delif(char ** argv)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
strtotimeval(struct timeval * tv,char * time)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
tv_to_jify(struct timeval * tv)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
set_time(char * br,unsigned long cmd,unsigned long val)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
br_set_ageing_time(char ** argv)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
br_set_fwd_delay(char ** argv)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
br_set_hello_time(char ** argv)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
br_set_max_age(char ** argv)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
br_set_bridge_prio(char ** argv)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
br_set_stp(char ** argv)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
set_cost_prio(char * br,char * port,unsigned long cmd,unsigned long val)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
br_set_path_cost(char ** argv)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
br_set_port_prio(char ** argv)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
brctl_main(void)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) {
324 toys.exithelp++;
325 error_exit("check args");
326 }
327 t->f(toys.optargs);
328 toys.optargs += t->nargs;
329 toys.optc -= t->nargs;
330 break;
331 }
332
333 if (i == ARRAY_LEN(cc)) {
334 toys.exithelp++;
335 error_exit("invalid option '%s'", *toys.optargs);
336 }
337 }
338 xclose(TT.sockfd);
339 }
340