1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34#define FOR_brctl
35#include "toys.h"
36#include <linux/if_bridge.h>
37
38GLOBALS(
39 int sockfd;
40)
41#define MAX_BRIDGES 1024
42
43static 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
58void 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
74void 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);
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
113void 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
126void 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
139void 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
157void 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
175static 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
184static 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
192void 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
202void 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
210void 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
218void 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
226void 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
234void 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
242void 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
258void 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
278void 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
286void 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
295void 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