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>
69 /* FIXME: These 4 funcs are not really clean and could be improved */
70 static ALWAYS_INLINE
void strtotimeval(struct timeval
*tv
,
74 # if BRCTL_USE_INTERNAL
76 secs
= /*bb_*/strtod(time_str
, &endptr
);
77 if (endptr
== time_str
)
79 if (sscanf(time_str
, "%lf", &secs
) != 1)
81 bb_error_msg_and_die(bb_msg_invalid_arg
, time_str
, "timespec");
83 tv
->tv_usec
= 1000000 * (secs
- tv
->tv_sec
);
86 static ALWAYS_INLINE
unsigned long tv_to_jiffies(const struct timeval
*tv
)
88 unsigned long long jif
;
90 jif
= 1000000ULL * tv
->tv_sec
+ tv
->tv_usec
;
95 static void jiffies_to_tv(struct timeval
*tv
, unsigned long jiffies
)
97 unsigned long long tvusec
;
99 tvusec
= 10000ULL*jiffies
;
100 tv
->tv_sec
= tvusec
/1000000;
101 tv
->tv_usec
= tvusec
- 1000000 * tv
->tv_sec
;
104 static unsigned long str_to_jiffies(const char *time_str
)
107 strtotimeval(&tv
, time_str
);
108 return tv_to_jiffies(&tv
);
111 static void arm_ioctl(unsigned long *args
,
112 unsigned long arg0
, unsigned long arg1
, unsigned long arg2
)
122 int brctl_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
123 int brctl_main(int argc UNUSED_PARAM
, char **argv
)
125 static const char keywords
[] ALIGN1
=
126 "addbr\0" "delbr\0" "addif\0" "delif\0"
127 IF_FEATURE_BRCTL_FANCY(
129 "setageing\0" "setfd\0" "sethello\0" "setmaxage\0"
130 "setpathcost\0" "setportprio\0" "setbridgeprio\0"
132 IF_FEATURE_BRCTL_SHOW("showmacs\0" "show\0");
134 enum { ARG_addbr
= 0, ARG_delbr
, ARG_addif
, ARG_delif
135 IF_FEATURE_BRCTL_FANCY(,
137 ARG_setageing
, ARG_setfd
, ARG_sethello
, ARG_setmaxage
,
138 ARG_setpathcost
, ARG_setportprio
, ARG_setbridgeprio
140 IF_FEATURE_BRCTL_SHOW(, ARG_showmacs
, ARG_show
)
150 #if ENABLE_FEATURE_BRCTL_FANCY
151 int ifidx
[MAX_PORTS
];
152 unsigned long args
[4];
153 ifr
.ifr_data
= (char *) &args
;
156 key
= index_in_strings(keywords
, *argv
);
157 if (key
== -1) /* no match found in keywords array, bail out. */
158 bb_error_msg_and_die(bb_msg_invalid_arg
, *argv
, applet_name
);
160 fd
= xsocket(AF_INET
, SOCK_STREAM
, 0);
162 #if ENABLE_FEATURE_BRCTL_SHOW
163 if (key
== ARG_show
) { /* show */
164 char brname
[IFNAMSIZ
];
165 int bridx
[MAX_PORTS
];
167 arm_ioctl(args
, BRCTL_GET_BRIDGES
,
168 (unsigned long) bridx
, MAX_PORTS
);
169 num
= xioctl(fd
, SIOCGIFBR
, args
);
170 printf("bridge name\tbridge id\t\tSTP enabled\tinterfaces\n");
171 for (i
= 0; i
< num
; i
++) {
172 char ifname
[IFNAMSIZ
];
174 struct __bridge_info bi
;
177 if (!if_indextoname(bridx
[i
], brname
))
178 bb_perror_msg_and_die("can't get bridge name for index %d", i
);
179 strncpy_IFNAMSIZ(ifr
.ifr_name
, brname
);
181 arm_ioctl(args
, BRCTL_GET_BRIDGE_INFO
,
182 (unsigned long) &bi
, 0);
183 xioctl(fd
, SIOCDEVPRIVATE
, &ifr
);
184 printf("%s\t\t", brname
);
186 /* print bridge id */
187 x
= (unsigned char *) &bi
.bridge_id
;
188 for (j
= 0; j
< 8; j
++) {
189 printf("%.2x", x
[j
]);
193 printf(bi
.stp_enabled
? "\tyes" : "\tno");
195 /* print interface list */
196 arm_ioctl(args
, BRCTL_GET_PORT_LIST
,
197 (unsigned long) ifidx
, MAX_PORTS
);
198 xioctl(fd
, SIOCDEVPRIVATE
, &ifr
);
200 for (j
= 0; j
< MAX_PORTS
; j
++) {
203 if (!if_indextoname(ifidx
[j
], ifname
))
204 bb_perror_msg_and_die("can't get interface name for index %d", j
);
206 printf("\t\t\t\t\t");
209 printf("\t\t%s\n", ifname
);
211 if (!tabs
) /* bridge has no interfaces */
218 if (!*argv
) /* all but 'show' need at least one argument */
223 if (key
== ARG_addbr
|| key
== ARG_delbr
) { /* addbr or delbr */
224 ioctl_or_perror_and_die(fd
,
225 key
== ARG_addbr
? SIOCBRADDBR
: SIOCBRDELBR
,
226 br
, "bridge %s", br
);
230 if (!*argv
) /* all but 'addbr/delbr' need at least two arguments */
233 strncpy_IFNAMSIZ(ifr
.ifr_name
, br
);
234 if (key
== ARG_addif
|| key
== ARG_delif
) { /* addif or delif */
236 ifr
.ifr_ifindex
= if_nametoindex(brif
);
237 if (!ifr
.ifr_ifindex
) {
238 bb_perror_msg_and_die("iface %s", brif
);
240 ioctl_or_perror_and_die(fd
,
241 key
== ARG_addif
? SIOCBRADDIF
: SIOCBRDELIF
,
242 &ifr
, "bridge %s", br
);
245 #if ENABLE_FEATURE_BRCTL_FANCY
246 if (key
== ARG_stp
) { /* stp */
247 static const char no_yes
[] ALIGN1
=
248 "0\0" "off\0" "n\0" "no\0" /* 0 .. 3 */
249 "1\0" "on\0" "y\0" "yes\0"; /* 4 .. 7 */
250 int onoff
= index_in_strings(no_yes
, *argv
);
252 bb_error_msg_and_die(bb_msg_invalid_arg
, *argv
, applet_name
);
253 onoff
= (unsigned)onoff
/ 4;
254 arm_ioctl(args
, BRCTL_SET_BRIDGE_STP_STATE
, onoff
, 0);
257 if ((unsigned)(key
- ARG_setageing
) < 4) { /* time related ops */
258 static const uint8_t ops
[] ALIGN1
= {
259 BRCTL_SET_AGEING_TIME
, /* ARG_setageing */
260 BRCTL_SET_BRIDGE_FORWARD_DELAY
, /* ARG_setfd */
261 BRCTL_SET_BRIDGE_HELLO_TIME
, /* ARG_sethello */
262 BRCTL_SET_BRIDGE_MAX_AGE
/* ARG_setmaxage */
264 arm_ioctl(args
, ops
[key
- ARG_setageing
], str_to_jiffies(*argv
), 0);
267 if (key
== ARG_setpathcost
268 || key
== ARG_setportprio
269 || key
== ARG_setbridgeprio
271 static const uint8_t ops
[] ALIGN1
= {
272 BRCTL_SET_PATH_COST
, /* ARG_setpathcost */
273 BRCTL_SET_PORT_PRIORITY
, /* ARG_setportprio */
274 BRCTL_SET_BRIDGE_PRIORITY
/* ARG_setbridgeprio */
279 if (key
!= ARG_setbridgeprio
) {
283 port
= if_nametoindex(*argv
++);
285 bb_error_msg_and_die(bb_msg_invalid_arg
, *argv
, "port");
286 memset(ifidx
, 0, sizeof ifidx
);
287 arm_ioctl(args
, BRCTL_GET_PORT_LIST
, (unsigned long)ifidx
,
289 xioctl(fd
, SIOCDEVPRIVATE
, &ifr
);
290 for (i
= 0; i
< MAX_PORTS
; i
++) {
291 if (ifidx
[i
] == port
) {
298 arg2
= xatoi_positive(*argv
);
299 if (key
== ARG_setbridgeprio
) {
303 arm_ioctl(args
, ops
[key
- ARG_setpathcost
], arg1
, arg2
);
306 /* Execute the previously set command */
307 xioctl(fd
, SIOCDEVPRIVATE
, &ifr
);