1 /* vi: set sw=4 ts=4: */
3 * Small implementation of brctl for busybox.
5 * Copyright (C) 2008 by Bernhard Reutner-Fischer
7 * Some helper functions from bridge-utils are
8 * Copyright (C) 2000 Lennert Buytenhek
10 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
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.
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"
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"
40 #include <linux/sockios.h>
44 # define SIOCBRADDBR BRCTL_ADD_BRIDGE
47 # define SIOCBRDELBR BRCTL_DEL_BRIDGE
50 # define SIOCBRADDIF BRCTL_ADD_IF
53 # define SIOCBRDELIF BRCTL_DEL_IF
57 /* Maximum number of ports supported per bridge interface. */
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
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'
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
96 struct __bridge_info
{
97 uint64_t designated_root
;
99 uint32_t root_path_cost
;
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
;
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
;
117 /* end <linux/if_bridge.h> */
119 /* FIXME: These 4 funcs are not really clean and could be improved */
120 static ALWAYS_INLINE
void bb_strtotimeval(struct timeval
*tv
,
121 const char *time_str
)
124 # if BRCTL_USE_INTERNAL
126 secs
= /*bb_*/strtod(time_str
, &endptr
);
127 if (endptr
== time_str
)
129 if (sscanf(time_str
, "%lf", &secs
) != 1)
131 bb_error_msg_and_die(bb_msg_invalid_arg_to
, time_str
, "timespec");
133 tv
->tv_usec
= 1000000 * (secs
- tv
->tv_sec
);
136 static ALWAYS_INLINE
unsigned long tv_to_jiffies(const struct timeval
*tv
)
138 unsigned long long jif
;
140 jif
= 1000000ULL * tv
->tv_sec
+ tv
->tv_usec
;
145 static void jiffies_to_tv(struct timeval
*tv
, unsigned long jiffies
)
147 unsigned long long tvusec
;
149 tvusec
= 10000ULL*jiffies
;
150 tv
->tv_sec
= tvusec
/1000000;
151 tv
->tv_usec
= tvusec
- 1000000 * tv
->tv_sec
;
154 static unsigned long str_to_jiffies(const char *time_str
)
157 bb_strtotimeval(&tv
, time_str
);
158 return tv_to_jiffies(&tv
);
161 static void arm_ioctl(unsigned long *args
,
162 unsigned long arg0
, unsigned long arg1
, unsigned long arg2
)
172 int brctl_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
173 int brctl_main(int argc UNUSED_PARAM
, char **argv
)
175 static const char keywords
[] ALIGN1
=
176 "addbr\0" "delbr\0" "addif\0" "delif\0"
177 IF_FEATURE_BRCTL_FANCY(
179 "setageing\0" "setfd\0" "sethello\0" "setmaxage\0"
180 "setpathcost\0" "setportprio\0" "setbridgeprio\0"
182 IF_FEATURE_BRCTL_SHOW("show\0");
184 enum { ARG_addbr
= 0, ARG_delbr
, ARG_addif
, ARG_delif
185 IF_FEATURE_BRCTL_FANCY(,
187 ARG_setageing
, ARG_setfd
, ARG_sethello
, ARG_setmaxage
,
188 ARG_setpathcost
, ARG_setportprio
, ARG_setbridgeprio
190 IF_FEATURE_BRCTL_SHOW(, ARG_show
)
200 #if ENABLE_FEATURE_BRCTL_FANCY
201 int ifidx
[MAX_PORTS
];
202 unsigned long args
[4];
203 ifr
.ifr_data
= (char *) &args
;
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
);
210 fd
= xsocket(AF_INET
, SOCK_STREAM
, 0);
212 #if ENABLE_FEATURE_BRCTL_SHOW
213 if (key
== ARG_show
) { /* show */
214 char brname
[IFNAMSIZ
];
215 int bridx
[MAX_PORTS
];
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
];
224 struct __bridge_info bi
;
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
);
231 arm_ioctl(args
, BRCTL_GET_BRIDGE_INFO
,
232 (unsigned long) &bi
, 0);
233 xioctl(fd
, SIOCDEVPRIVATE
, &ifr
);
234 printf("%s\t\t", brname
);
236 /* print bridge id */
237 x
= (unsigned char *) &bi
.bridge_id
;
238 for (j
= 0; j
< 8; j
++) {
239 printf("%02x", x
[j
]);
243 printf(bi
.stp_enabled
? "\tyes" : "\tno");
245 /* print interface list */
246 arm_ioctl(args
, BRCTL_GET_PORT_LIST
,
247 (unsigned long) ifidx
, MAX_PORTS
);
248 xioctl(fd
, SIOCDEVPRIVATE
, &ifr
);
250 for (j
= 0; j
< MAX_PORTS
; j
++) {
253 if (!if_indextoname(ifidx
[j
], ifname
))
254 bb_perror_msg_and_die("can't get interface name for index %d", j
);
256 printf("\t\t\t\t\t");
259 printf("\t\t%s\n", ifname
);
261 if (!tabs
) /* bridge has no interfaces */
268 if (!*argv
) /* all but 'show' need at least one argument */
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
);
280 if (!*argv
) /* all but 'addbr/delbr' need at least two arguments */
283 strncpy_IFNAMSIZ(ifr
.ifr_name
, br
);
284 if (key
== ARG_addif
|| key
== ARG_delif
) { /* addif or delif */
286 ifr
.ifr_ifindex
= if_nametoindex(brif
);
287 if (!ifr
.ifr_ifindex
) {
288 bb_perror_msg_and_die("iface %s", brif
);
290 ioctl_or_perror_and_die(fd
,
291 key
== ARG_addif
? SIOCBRADDIF
: SIOCBRDELIF
,
292 &ifr
, "bridge %s", br
);
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
);
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);
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 */
314 arm_ioctl(args
, ops
[key
- ARG_setageing
], str_to_jiffies(*argv
), 0);
317 if (key
== ARG_setpathcost
318 || key
== ARG_setportprio
319 || key
== ARG_setbridgeprio
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 */
329 if (key
!= ARG_setbridgeprio
) {
333 port
= if_nametoindex(*argv
++);
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
,
339 xioctl(fd
, SIOCDEVPRIVATE
, &ifr
);
340 for (i
= 0; i
< MAX_PORTS
; i
++) {
341 if (ifidx
[i
] == port
) {
348 arg2
= xatoi_positive(*argv
);
349 if (key
== ARG_setbridgeprio
) {
353 arm_ioctl(args
, ops
[key
- ARG_setpathcost
], arg1
, arg2
);
356 /* Execute the previously set command */
357 xioctl(fd
, SIOCDEVPRIVATE
, &ifr
);