source: MondoRescue/branches/3.3/mindi-busybox/networking/brctl.c@ 3734

Last change on this file since 3734 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

  • Property svn:eol-style set to native
File size: 10.1 KB
Line 
1/* vi: set sw=4 ts=4: */
2/*
3 * Small implementation of brctl for busybox.
4 *
5 * Copyright (C) 2008 by Bernhard Reutner-Fischer
6 *
7 * Some helper functions from bridge-utils are
8 * Copyright (C) 2000 Lennert Buytenhek
9 *
10 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
11 */
12/* This applet currently uses only the ioctl interface and no sysfs at all.
13 * At the time of this writing this was considered a feature.
14 */
15
16//usage:#define brctl_trivial_usage
17//usage: "COMMAND [BRIDGE [INTERFACE]]"
18//usage:#define brctl_full_usage "\n\n"
19//usage: "Manage ethernet bridges\n"
20//usage: "\nCommands:"
21//usage: IF_FEATURE_BRCTL_SHOW(
22//usage: "\n show Show a list of bridges"
23//usage: )
24//usage: "\n addbr BRIDGE Create BRIDGE"
25//usage: "\n delbr BRIDGE Delete BRIDGE"
26//usage: "\n addif BRIDGE IFACE Add IFACE to BRIDGE"
27//usage: "\n delif BRIDGE IFACE Delete IFACE from BRIDGE"
28//usage: IF_FEATURE_BRCTL_FANCY(
29//usage: "\n setageing BRIDGE TIME Set ageing time"
30//usage: "\n setfd BRIDGE TIME Set bridge forward delay"
31//usage: "\n sethello BRIDGE TIME Set hello time"
32//usage: "\n setmaxage BRIDGE TIME Set max message age"
33//usage: "\n setpathcost BRIDGE COST Set path cost"
34//usage: "\n setportprio BRIDGE PRIO Set port priority"
35//usage: "\n setbridgeprio BRIDGE PRIO Set bridge priority"
36//usage: "\n stp BRIDGE [1/yes/on|0/no/off] STP on/off"
37//usage: )
38
39#include "libbb.h"
40#include <linux/sockios.h>
41#include <net/if.h>
42
43#ifndef SIOCBRADDBR
44# define SIOCBRADDBR BRCTL_ADD_BRIDGE
45#endif
46#ifndef SIOCBRDELBR
47# define SIOCBRDELBR BRCTL_DEL_BRIDGE
48#endif
49#ifndef SIOCBRADDIF
50# define SIOCBRADDIF BRCTL_ADD_IF
51#endif
52#ifndef SIOCBRDELIF
53# define SIOCBRDELIF BRCTL_DEL_IF
54#endif
55
56
57/* Maximum number of ports supported per bridge interface. */
58#ifndef MAX_PORTS
59# define MAX_PORTS 32
60#endif
61
62/* Use internal number parsing and not the "exact" conversion. */
63/* #define BRCTL_USE_INTERNAL 0 */ /* use exact conversion */
64#define BRCTL_USE_INTERNAL 1
65
66#if ENABLE_FEATURE_BRCTL_FANCY
67/* #include <linux/if_bridge.h>
68 * breaks on musl: we already included netinet/in.h in libbb.h,
69 * if we include <linux/if_bridge.h> here, we get this:
70 * In file included from /usr/include/linux/if_bridge.h:18,
71 * from networking/brctl.c:67:
72 * /usr/include/linux/in6.h:32: error: redefinition of 'struct in6_addr'
73 * /usr/include/linux/in6.h:49: error: redefinition of 'struct sockaddr_in6'
74 * /usr/include/linux/in6.h:59: error: redefinition of 'struct ipv6_mreq'
75 */
76/* From <linux/if_bridge.h> */
77#define BRCTL_GET_VERSION 0
78#define BRCTL_GET_BRIDGES 1
79#define BRCTL_ADD_BRIDGE 2
80#define BRCTL_DEL_BRIDGE 3
81#define BRCTL_ADD_IF 4
82#define BRCTL_DEL_IF 5
83#define BRCTL_GET_BRIDGE_INFO 6
84#define BRCTL_GET_PORT_LIST 7
85#define BRCTL_SET_BRIDGE_FORWARD_DELAY 8
86#define BRCTL_SET_BRIDGE_HELLO_TIME 9
87#define BRCTL_SET_BRIDGE_MAX_AGE 10
88#define BRCTL_SET_AGEING_TIME 11
89#define BRCTL_SET_GC_INTERVAL 12
90#define BRCTL_GET_PORT_INFO 13
91#define BRCTL_SET_BRIDGE_STP_STATE 14
92#define BRCTL_SET_BRIDGE_PRIORITY 15
93#define BRCTL_SET_PORT_PRIORITY 16
94#define BRCTL_SET_PATH_COST 17
95#define BRCTL_GET_FDB_ENTRIES 18
96struct __bridge_info {
97 uint64_t designated_root;
98 uint64_t bridge_id;
99 uint32_t root_path_cost;
100 uint32_t max_age;
101 uint32_t hello_time;
102 uint32_t forward_delay;
103 uint32_t bridge_max_age;
104 uint32_t bridge_hello_time;
105 uint32_t bridge_forward_delay;
106 uint8_t topology_change;
107 uint8_t topology_change_detected;
108 uint8_t root_port;
109 uint8_t stp_enabled;
110 uint32_t ageing_time;
111 uint32_t gc_interval;
112 uint32_t hello_timer_value;
113 uint32_t tcn_timer_value;
114 uint32_t topology_change_timer_value;
115 uint32_t gc_timer_value;
116};
117/* end <linux/if_bridge.h> */
118
119/* FIXME: These 4 funcs are not really clean and could be improved */
120static ALWAYS_INLINE void bb_strtotimeval(struct timeval *tv,
121 const char *time_str)
122{
123 double secs;
124# if BRCTL_USE_INTERNAL
125 char *endptr;
126 secs = /*bb_*/strtod(time_str, &endptr);
127 if (endptr == time_str)
128# else
129 if (sscanf(time_str, "%lf", &secs) != 1)
130# endif
131 bb_error_msg_and_die(bb_msg_invalid_arg_to, time_str, "timespec");
132 tv->tv_sec = secs;
133 tv->tv_usec = 1000000 * (secs - tv->tv_sec);
134}
135
136static ALWAYS_INLINE unsigned long tv_to_jiffies(const struct timeval *tv)
137{
138 unsigned long long jif;
139
140 jif = 1000000ULL * tv->tv_sec + tv->tv_usec;
141
142 return jif/10000;
143}
144# if 0
145static void jiffies_to_tv(struct timeval *tv, unsigned long jiffies)
146{
147 unsigned long long tvusec;
148
149 tvusec = 10000ULL*jiffies;
150 tv->tv_sec = tvusec/1000000;
151 tv->tv_usec = tvusec - 1000000 * tv->tv_sec;
152}
153# endif
154static unsigned long str_to_jiffies(const char *time_str)
155{
156 struct timeval tv;
157 bb_strtotimeval(&tv, time_str);
158 return tv_to_jiffies(&tv);
159}
160
161static void arm_ioctl(unsigned long *args,
162 unsigned long arg0, unsigned long arg1, unsigned long arg2)
163{
164 args[0] = arg0;
165 args[1] = arg1;
166 args[2] = arg2;
167 args[3] = 0;
168}
169#endif
170
171
172int brctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
173int brctl_main(int argc UNUSED_PARAM, char **argv)
174{
175 static const char keywords[] ALIGN1 =
176 "addbr\0" "delbr\0" "addif\0" "delif\0"
177 IF_FEATURE_BRCTL_FANCY(
178 "stp\0"
179 "setageing\0" "setfd\0" "sethello\0" "setmaxage\0"
180 "setpathcost\0" "setportprio\0" "setbridgeprio\0"
181 )
182 IF_FEATURE_BRCTL_SHOW("show\0");
183
184 enum { ARG_addbr = 0, ARG_delbr, ARG_addif, ARG_delif
185 IF_FEATURE_BRCTL_FANCY(,
186 ARG_stp,
187 ARG_setageing, ARG_setfd, ARG_sethello, ARG_setmaxage,
188 ARG_setpathcost, ARG_setportprio, ARG_setbridgeprio
189 )
190 IF_FEATURE_BRCTL_SHOW(, ARG_show)
191 };
192
193 int fd;
194 smallint key;
195 struct ifreq ifr;
196 char *br, *brif;
197
198 argv++;
199 while (*argv) {
200#if ENABLE_FEATURE_BRCTL_FANCY
201 int ifidx[MAX_PORTS];
202 unsigned long args[4];
203 ifr.ifr_data = (char *) &args;
204#endif
205
206 key = index_in_strings(keywords, *argv);
207 if (key == -1) /* no match found in keywords array, bail out. */
208 bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name);
209 argv++;
210 fd = xsocket(AF_INET, SOCK_STREAM, 0);
211
212#if ENABLE_FEATURE_BRCTL_SHOW
213 if (key == ARG_show) { /* show */
214 char brname[IFNAMSIZ];
215 int bridx[MAX_PORTS];
216 int i, num;
217 arm_ioctl(args, BRCTL_GET_BRIDGES,
218 (unsigned long) bridx, MAX_PORTS);
219 num = xioctl(fd, SIOCGIFBR, args);
220 puts("bridge name\tbridge id\t\tSTP enabled\tinterfaces");
221 for (i = 0; i < num; i++) {
222 char ifname[IFNAMSIZ];
223 int j, tabs;
224 struct __bridge_info bi;
225 unsigned char *x;
226
227 if (!if_indextoname(bridx[i], brname))
228 bb_perror_msg_and_die("can't get bridge name for index %d", i);
229 strncpy_IFNAMSIZ(ifr.ifr_name, brname);
230
231 arm_ioctl(args, BRCTL_GET_BRIDGE_INFO,
232 (unsigned long) &bi, 0);
233 xioctl(fd, SIOCDEVPRIVATE, &ifr);
234 printf("%s\t\t", brname);
235
236 /* print bridge id */
237 x = (unsigned char *) &bi.bridge_id;
238 for (j = 0; j < 8; j++) {
239 printf("%02x", x[j]);
240 if (j == 1)
241 bb_putchar('.');
242 }
243 printf(bi.stp_enabled ? "\tyes" : "\tno");
244
245 /* print interface list */
246 arm_ioctl(args, BRCTL_GET_PORT_LIST,
247 (unsigned long) ifidx, MAX_PORTS);
248 xioctl(fd, SIOCDEVPRIVATE, &ifr);
249 tabs = 0;
250 for (j = 0; j < MAX_PORTS; j++) {
251 if (!ifidx[j])
252 continue;
253 if (!if_indextoname(ifidx[j], ifname))
254 bb_perror_msg_and_die("can't get interface name for index %d", j);
255 if (tabs)
256 printf("\t\t\t\t\t");
257 else
258 tabs = 1;
259 printf("\t\t%s\n", ifname);
260 }
261 if (!tabs) /* bridge has no interfaces */
262 bb_putchar('\n');
263 }
264 goto done;
265 }
266#endif
267
268 if (!*argv) /* all but 'show' need at least one argument */
269 bb_show_usage();
270
271 br = *argv++;
272
273 if (key == ARG_addbr || key == ARG_delbr) { /* addbr or delbr */
274 ioctl_or_perror_and_die(fd,
275 key == ARG_addbr ? SIOCBRADDBR : SIOCBRDELBR,
276 br, "bridge %s", br);
277 goto done;
278 }
279
280 if (!*argv) /* all but 'addbr/delbr' need at least two arguments */
281 bb_show_usage();
282
283 strncpy_IFNAMSIZ(ifr.ifr_name, br);
284 if (key == ARG_addif || key == ARG_delif) { /* addif or delif */
285 brif = *argv;
286 ifr.ifr_ifindex = if_nametoindex(brif);
287 if (!ifr.ifr_ifindex) {
288 bb_perror_msg_and_die("iface %s", brif);
289 }
290 ioctl_or_perror_and_die(fd,
291 key == ARG_addif ? SIOCBRADDIF : SIOCBRDELIF,
292 &ifr, "bridge %s", br);
293 goto done_next_argv;
294 }
295#if ENABLE_FEATURE_BRCTL_FANCY
296 if (key == ARG_stp) { /* stp */
297 static const char no_yes[] ALIGN1 =
298 "0\0" "off\0" "n\0" "no\0" /* 0 .. 3 */
299 "1\0" "on\0" "y\0" "yes\0"; /* 4 .. 7 */
300 int onoff = index_in_strings(no_yes, *argv);
301 if (onoff < 0)
302 bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name);
303 onoff = (unsigned)onoff / 4;
304 arm_ioctl(args, BRCTL_SET_BRIDGE_STP_STATE, onoff, 0);
305 goto fire;
306 }
307 if ((unsigned)(key - ARG_setageing) < 4) { /* time related ops */
308 static const uint8_t ops[] ALIGN1 = {
309 BRCTL_SET_AGEING_TIME, /* ARG_setageing */
310 BRCTL_SET_BRIDGE_FORWARD_DELAY, /* ARG_setfd */
311 BRCTL_SET_BRIDGE_HELLO_TIME, /* ARG_sethello */
312 BRCTL_SET_BRIDGE_MAX_AGE /* ARG_setmaxage */
313 };
314 arm_ioctl(args, ops[key - ARG_setageing], str_to_jiffies(*argv), 0);
315 goto fire;
316 }
317 if (key == ARG_setpathcost
318 || key == ARG_setportprio
319 || key == ARG_setbridgeprio
320 ) {
321 static const uint8_t ops[] ALIGN1 = {
322 BRCTL_SET_PATH_COST, /* ARG_setpathcost */
323 BRCTL_SET_PORT_PRIORITY, /* ARG_setportprio */
324 BRCTL_SET_BRIDGE_PRIORITY /* ARG_setbridgeprio */
325 };
326 int port = -1;
327 unsigned arg1, arg2;
328
329 if (key != ARG_setbridgeprio) {
330 /* get portnum */
331 unsigned i;
332
333 port = if_nametoindex(*argv++);
334 if (!port)
335 bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, "port");
336 memset(ifidx, 0, sizeof ifidx);
337 arm_ioctl(args, BRCTL_GET_PORT_LIST, (unsigned long)ifidx,
338 MAX_PORTS);
339 xioctl(fd, SIOCDEVPRIVATE, &ifr);
340 for (i = 0; i < MAX_PORTS; i++) {
341 if (ifidx[i] == port) {
342 port = i;
343 break;
344 }
345 }
346 }
347 arg1 = port;
348 arg2 = xatoi_positive(*argv);
349 if (key == ARG_setbridgeprio) {
350 arg1 = arg2;
351 arg2 = 0;
352 }
353 arm_ioctl(args, ops[key - ARG_setpathcost], arg1, arg2);
354 }
355 fire:
356 /* Execute the previously set command */
357 xioctl(fd, SIOCDEVPRIVATE, &ifr);
358#endif
359 done_next_argv:
360 argv++;
361 done:
362 close(fd);
363 }
364
365 return EXIT_SUCCESS;
366}
Note: See TracBrowser for help on using the repository browser.