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) 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