Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 1 | /* vi: set sw=4 ts=4: */ |
| 2 | /* |
| 3 | * Small implementation of brctl for busybox. |
| 4 | * |
Bernhard Reutner-Fischer | 6c4dade | 2008-09-25 12:13:34 +0000 | [diff] [blame] | 5 | * Copyright (C) 2008 by Bernhard Reutner-Fischer |
Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 6 | * |
Bernhard Reutner-Fischer | 2b11fb4 | 2008-01-14 16:10:11 +0000 | [diff] [blame] | 7 | * Some helper functions from bridge-utils are |
| 8 | * Copyright (C) 2000 Lennert Buytenhek |
| 9 | * |
Denys Vlasenko | 0ef64bd | 2010-08-16 20:14:46 +0200 | [diff] [blame] | 10 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. |
Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 11 | */ |
Denys Vlasenko | 47367e1 | 2016-11-23 09:05:14 +0100 | [diff] [blame] | 12 | //config:config BRCTL |
Denys Vlasenko | 4eed2c6 | 2017-07-18 22:01:24 +0200 | [diff] [blame] | 13 | //config: bool "brctl (4.7 kb)" |
Denys Vlasenko | 47367e1 | 2016-11-23 09:05:14 +0100 | [diff] [blame] | 14 | //config: default y |
Denys Vlasenko | 47367e1 | 2016-11-23 09:05:14 +0100 | [diff] [blame] | 15 | //config: help |
Denys Vlasenko | 72089cf | 2017-07-21 09:50:55 +0200 | [diff] [blame] | 16 | //config: Manage ethernet bridges. |
| 17 | //config: Supports addbr/delbr and addif/delif. |
Denys Vlasenko | 47367e1 | 2016-11-23 09:05:14 +0100 | [diff] [blame] | 18 | //config: |
| 19 | //config:config FEATURE_BRCTL_FANCY |
| 20 | //config: bool "Fancy options" |
| 21 | //config: default y |
| 22 | //config: depends on BRCTL |
| 23 | //config: help |
Denys Vlasenko | 72089cf | 2017-07-21 09:50:55 +0200 | [diff] [blame] | 24 | //config: Add support for extended option like: |
| 25 | //config: setageing, setfd, sethello, setmaxage, |
| 26 | //config: setpathcost, setportprio, setbridgeprio, |
| 27 | //config: stp |
| 28 | //config: This adds about 600 bytes. |
Denys Vlasenko | 47367e1 | 2016-11-23 09:05:14 +0100 | [diff] [blame] | 29 | //config: |
| 30 | //config:config FEATURE_BRCTL_SHOW |
| 31 | //config: bool "Support show" |
| 32 | //config: default y |
| 33 | //config: depends on BRCTL && FEATURE_BRCTL_FANCY |
| 34 | //config: help |
Denys Vlasenko | 72089cf | 2017-07-21 09:50:55 +0200 | [diff] [blame] | 35 | //config: Add support for option which prints the current config: |
| 36 | //config: show |
Denys Vlasenko | 47367e1 | 2016-11-23 09:05:14 +0100 | [diff] [blame] | 37 | |
Denys Vlasenko | 86e07f6 | 2017-08-06 20:14:02 +0200 | [diff] [blame] | 38 | //applet:IF_BRCTL(APPLET_NOEXEC(brctl, brctl, BB_DIR_USR_SBIN, BB_SUID_DROP, brctl)) |
Denys Vlasenko | 47367e1 | 2016-11-23 09:05:14 +0100 | [diff] [blame] | 39 | |
| 40 | //kbuild:lib-$(CONFIG_BRCTL) += brctl.o |
Pere Orga | 5bc8c00 | 2011-04-11 03:29:49 +0200 | [diff] [blame] | 41 | |
| 42 | //usage:#define brctl_trivial_usage |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 43 | //usage: "COMMAND [BRIDGE [ARGS]]" |
Pere Orga | 5bc8c00 | 2011-04-11 03:29:49 +0200 | [diff] [blame] | 44 | //usage:#define brctl_full_usage "\n\n" |
Denys Vlasenko | 2945822 | 2019-04-13 15:48:31 +0200 | [diff] [blame] | 45 | //usage: "Manage ethernet bridges" |
Pere Orga | 5bc8c00 | 2011-04-11 03:29:49 +0200 | [diff] [blame] | 46 | //usage: "\nCommands:" |
| 47 | //usage: IF_FEATURE_BRCTL_SHOW( |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 48 | //usage: "\n show [BRIDGE]... Show bridges" |
Pere Orga | 5bc8c00 | 2011-04-11 03:29:49 +0200 | [diff] [blame] | 49 | //usage: ) |
| 50 | //usage: "\n addbr BRIDGE Create BRIDGE" |
| 51 | //usage: "\n delbr BRIDGE Delete BRIDGE" |
| 52 | //usage: "\n addif BRIDGE IFACE Add IFACE to BRIDGE" |
| 53 | //usage: "\n delif BRIDGE IFACE Delete IFACE from BRIDGE" |
| 54 | //usage: IF_FEATURE_BRCTL_FANCY( |
Denys Vlasenko | eb13951 | 2019-10-12 19:51:46 +0200 | [diff] [blame] | 55 | //usage: "\n showmacs BRIDGE List MAC addresses" |
Denys Vlasenko | 3398753 | 2019-10-12 19:24:38 +0200 | [diff] [blame] | 56 | //usage: "\n showstp BRIDGE Show STP info" |
Denys Vlasenko | eb13951 | 2019-10-12 19:51:46 +0200 | [diff] [blame] | 57 | //usage: "\n stp BRIDGE 1/yes/on|0/no/off Set STP on/off" |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 58 | //usage: "\n setageing BRIDGE SECONDS Set ageing time" |
| 59 | //usage: "\n setfd BRIDGE SECONDS Set bridge forward delay" |
| 60 | //usage: "\n sethello BRIDGE SECONDS Set hello time" |
| 61 | //usage: "\n setmaxage BRIDGE SECONDS Set max message age" |
Pere Orga | 5bc8c00 | 2011-04-11 03:29:49 +0200 | [diff] [blame] | 62 | //usage: "\n setbridgeprio BRIDGE PRIO Set bridge priority" |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 63 | //usage: "\n setportprio BRIDGE IFACE PRIO Set port priority" |
| 64 | //usage: "\n setpathcost BRIDGE IFACE COST Set path cost" |
Pere Orga | 5bc8c00 | 2011-04-11 03:29:49 +0200 | [diff] [blame] | 65 | //usage: ) |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 66 | // Not yet implemented: |
Denys Vlasenko | eb13951 | 2019-10-12 19:51:46 +0200 | [diff] [blame] | 67 | // hairpin BRIDGE IFACE on|off Set hairpin on/off |
Martin Lewis | 6dcf563 | 2019-10-10 16:00:19 -0500 | [diff] [blame] | 68 | |
Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 69 | #include "libbb.h" |
Denys Vlasenko | c5150e9 | 2019-04-12 18:52:31 +0200 | [diff] [blame] | 70 | #include "common_bufsiz.h" |
Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 71 | #include <linux/sockios.h> |
| 72 | #include <net/if.h> |
| 73 | |
Denis Vlasenko | 802cab1 | 2009-01-31 20:08:21 +0000 | [diff] [blame] | 74 | #ifndef SIOCBRADDBR |
| 75 | # define SIOCBRADDBR BRCTL_ADD_BRIDGE |
| 76 | #endif |
| 77 | #ifndef SIOCBRDELBR |
| 78 | # define SIOCBRDELBR BRCTL_DEL_BRIDGE |
| 79 | #endif |
| 80 | #ifndef SIOCBRADDIF |
| 81 | # define SIOCBRADDIF BRCTL_ADD_IF |
| 82 | #endif |
| 83 | #ifndef SIOCBRDELIF |
| 84 | # define SIOCBRDELIF BRCTL_DEL_IF |
| 85 | #endif |
| 86 | |
Bernhard Reutner-Fischer | 1aac3ab | 2008-01-13 18:43:50 +0000 | [diff] [blame] | 87 | #if ENABLE_FEATURE_BRCTL_FANCY |
Denys Vlasenko | 9435608 | 2019-04-13 14:17:55 +0200 | [diff] [blame] | 88 | static unsigned str_to_jiffies(const char *time_str) |
Bernhard Reutner-Fischer | 1aac3ab | 2008-01-13 18:43:50 +0000 | [diff] [blame] | 89 | { |
Denys Vlasenko | 9435608 | 2019-04-13 14:17:55 +0200 | [diff] [blame] | 90 | double dd; |
Maciek Borzecki | 46abfc0 | 2010-03-16 12:41:29 +0100 | [diff] [blame] | 91 | char *endptr; |
Denys Vlasenko | c2bd0b6 | 2021-03-23 13:50:02 +0100 | [diff] [blame] | 92 | //TODO: needs setlocale(LC_NUMERIC, "C")? |
Denys Vlasenko | 9435608 | 2019-04-13 14:17:55 +0200 | [diff] [blame] | 93 | dd = /*bb_*/strtod(time_str, &endptr); |
| 94 | if (endptr == time_str || dd < 0) |
Denys Vlasenko | 0f296a3 | 2015-10-14 13:21:01 +0200 | [diff] [blame] | 95 | bb_error_msg_and_die(bb_msg_invalid_arg_to, time_str, "timespec"); |
Bernhard Reutner-Fischer | 1aac3ab | 2008-01-13 18:43:50 +0000 | [diff] [blame] | 96 | |
Denys Vlasenko | 9435608 | 2019-04-13 14:17:55 +0200 | [diff] [blame] | 97 | dd *= 100; |
| 98 | /* For purposes of brctl, |
| 99 | * capping SECONDS by ~20 million seconds is quite enough: |
| 100 | */ |
| 101 | if (dd > INT_MAX) |
| 102 | dd = INT_MAX; |
Bernhard Reutner-Fischer | 1aac3ab | 2008-01-13 18:43:50 +0000 | [diff] [blame] | 103 | |
Denys Vlasenko | 9435608 | 2019-04-13 14:17:55 +0200 | [diff] [blame] | 104 | return dd; |
Bernhard Reutner-Fischer | 1aac3ab | 2008-01-13 18:43:50 +0000 | [diff] [blame] | 105 | } |
Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 106 | #endif |
| 107 | |
Denys Vlasenko | c5150e9 | 2019-04-12 18:52:31 +0200 | [diff] [blame] | 108 | #define filedata bb_common_bufsiz1 |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 109 | |
Denys Vlasenko | df1f479 | 2020-06-23 03:13:55 +0200 | [diff] [blame] | 110 | #if ENABLE_FEATURE_BRCTL_SHOW || ENABLE_FEATURE_BRCTL_FANCY |
Denys Vlasenko | c5150e9 | 2019-04-12 18:52:31 +0200 | [diff] [blame] | 111 | static int read_file(const char *name) |
| 112 | { |
| 113 | int n = open_read_close(name, filedata, COMMON_BUFSIZE - 1); |
| 114 | if (n < 0) { |
| 115 | filedata[0] = '\0'; |
| 116 | } else { |
| 117 | filedata[n] = '\0'; |
| 118 | if (n != 0 && filedata[n - 1] == '\n') |
| 119 | filedata[--n] = '\0'; |
| 120 | } |
| 121 | return n; |
| 122 | } |
Denys Vlasenko | df1f479 | 2020-06-23 03:13:55 +0200 | [diff] [blame] | 123 | #endif |
Denys Vlasenko | c5150e9 | 2019-04-12 18:52:31 +0200 | [diff] [blame] | 124 | |
Denys Vlasenko | df1f479 | 2020-06-23 03:13:55 +0200 | [diff] [blame] | 125 | #if ENABLE_FEATURE_BRCTL_SHOW |
Denys Vlasenko | c5150e9 | 2019-04-12 18:52:31 +0200 | [diff] [blame] | 126 | /* NB: we are in /sys/class/net |
| 127 | */ |
| 128 | static int show_bridge(const char *name, int need_hdr) |
| 129 | { |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 130 | /* Output: |
| 131 | *bridge name bridge id STP enabled interfaces |
| 132 | *br0 8000.000000000000 no eth0 |
| 133 | */ |
Denys Vlasenko | 3398753 | 2019-10-12 19:24:38 +0200 | [diff] [blame] | 134 | char pathbuf[IFNAMSIZ + sizeof("/bridge/bridge_id") + 8]; |
Denys Vlasenko | c5150e9 | 2019-04-12 18:52:31 +0200 | [diff] [blame] | 135 | int tabs; |
| 136 | DIR *ifaces; |
| 137 | struct dirent *ent; |
| 138 | char *sfx; |
| 139 | |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 140 | #if IFNAMSIZ == 16 |
| 141 | sfx = pathbuf + sprintf(pathbuf, "%.16s/bridge/", name); |
| 142 | #else |
| 143 | sfx = pathbuf + sprintf(pathbuf, "%.*s/bridge/", (int)IFNAMSIZ, name); |
| 144 | #endif |
Denys Vlasenko | c5150e9 | 2019-04-12 18:52:31 +0200 | [diff] [blame] | 145 | strcpy(sfx, "bridge_id"); |
| 146 | if (read_file(pathbuf) < 0) |
| 147 | return -1; /* this iface is not a bridge */ |
| 148 | |
| 149 | if (need_hdr) |
| 150 | puts("bridge name\tbridge id\t\tSTP enabled\tinterfaces"); |
Martin Lewis | 6dcf563 | 2019-10-10 16:00:19 -0500 | [diff] [blame] | 151 | printf("%s\t\t%s\t", name, filedata); |
Denys Vlasenko | c5150e9 | 2019-04-12 18:52:31 +0200 | [diff] [blame] | 152 | |
| 153 | strcpy(sfx, "stp_state"); |
| 154 | read_file(pathbuf); |
| 155 | if (LONE_CHAR(filedata, '0')) |
| 156 | strcpy(filedata, "no"); |
| 157 | else |
| 158 | if (LONE_CHAR(filedata, '1')) |
| 159 | strcpy(filedata, "yes"); |
Ron Yorston | cad3fc7 | 2021-02-03 20:47:14 +0100 | [diff] [blame] | 160 | fputs_stdout(filedata); |
Denys Vlasenko | c5150e9 | 2019-04-12 18:52:31 +0200 | [diff] [blame] | 161 | |
Denys Vlasenko | 37a9008 | 2019-10-15 12:31:54 +0200 | [diff] [blame] | 162 | /* sfx points past "BR/bridge/", turn it into "BR/brif": */ |
| 163 | sfx[-4] = 'f'; sfx[-3] = '\0'; |
Denys Vlasenko | c5150e9 | 2019-04-12 18:52:31 +0200 | [diff] [blame] | 164 | tabs = 0; |
| 165 | ifaces = opendir(pathbuf); |
| 166 | if (ifaces) { |
| 167 | while ((ent = readdir(ifaces)) != NULL) { |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 168 | if (DOT_OR_DOTDOT(ent->d_name)) |
| 169 | continue; /* . or .. */ |
Denys Vlasenko | c5150e9 | 2019-04-12 18:52:31 +0200 | [diff] [blame] | 170 | if (tabs) |
| 171 | printf("\t\t\t\t\t"); |
| 172 | else |
| 173 | tabs = 1; |
| 174 | printf("\t\t%s\n", ent->d_name); |
| 175 | } |
| 176 | closedir(ifaces); |
| 177 | } |
| 178 | if (!tabs) /* bridge has no interfaces */ |
| 179 | bb_putchar('\n'); |
| 180 | return 0; |
| 181 | } |
Denys Vlasenko | 3e463e1 | 2019-06-08 12:35:06 +0200 | [diff] [blame] | 182 | #endif |
Bernhard Reutner-Fischer | 1aac3ab | 2008-01-13 18:43:50 +0000 | [diff] [blame] | 183 | |
Denys Vlasenko | 3e463e1 | 2019-06-08 12:35:06 +0200 | [diff] [blame] | 184 | #if ENABLE_FEATURE_BRCTL_FANCY |
Denys Vlasenko | 9435608 | 2019-04-13 14:17:55 +0200 | [diff] [blame] | 185 | static void write_uint(const char *name, const char *leaf, unsigned val) |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 186 | { |
| 187 | char pathbuf[IFNAMSIZ + sizeof("/bridge/bridge_id") + 32]; |
| 188 | int fd, n; |
| 189 | |
| 190 | #if IFNAMSIZ == 16 |
| 191 | sprintf(pathbuf, "%.16s/%s", name, leaf); |
| 192 | #else |
| 193 | sprintf(pathbuf, "%.*s/%s", (int)IFNAMSIZ, name, leaf); |
| 194 | #endif |
| 195 | fd = xopen(pathbuf, O_WRONLY); |
Denys Vlasenko | 9435608 | 2019-04-13 14:17:55 +0200 | [diff] [blame] | 196 | n = sprintf(filedata, "%u\n", val); |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 197 | if (write(fd, filedata, n) < 0) |
| 198 | bb_simple_perror_msg_and_die(name); |
Denys Vlasenko | 3398753 | 2019-10-12 19:24:38 +0200 | [diff] [blame] | 199 | /* So far all callers exit very soon after calling us. |
| 200 | * Do not bother closing fd (unless debugging): |
| 201 | */ |
| 202 | if (ENABLE_FEATURE_CLEAN_UP) |
| 203 | close(fd); |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 204 | } |
Martin Lewis | 6c1af28 | 2019-09-15 18:04:49 +0200 | [diff] [blame] | 205 | |
| 206 | struct fdb_entry { |
| 207 | uint8_t mac_addr[6]; |
| 208 | uint8_t port_no; |
| 209 | uint8_t is_local; |
| 210 | uint32_t ageing_timer_value; |
| 211 | uint8_t port_hi; |
| 212 | uint8_t pad0; |
| 213 | uint16_t unused; |
| 214 | }; |
| 215 | |
| 216 | static int compare_fdbs(const void *_f0, const void *_f1) |
| 217 | { |
| 218 | const struct fdb_entry *f0 = _f0; |
| 219 | const struct fdb_entry *f1 = _f1; |
| 220 | |
| 221 | return memcmp(f0->mac_addr, f1->mac_addr, 6); |
| 222 | } |
| 223 | |
| 224 | static size_t read_bridge_forward_db(const char *name, struct fdb_entry **_fdb) |
| 225 | { |
Denys Vlasenko | 3398753 | 2019-10-12 19:24:38 +0200 | [diff] [blame] | 226 | char pathbuf[IFNAMSIZ + sizeof("/brforward") + 8]; |
Martin Lewis | 6c1af28 | 2019-09-15 18:04:49 +0200 | [diff] [blame] | 227 | struct fdb_entry *fdb; |
| 228 | size_t nentries; |
Martin Lewis | 6c1af28 | 2019-09-15 18:04:49 +0200 | [diff] [blame] | 229 | int fd; |
| 230 | ssize_t cc; |
| 231 | |
Denys Vlasenko | 3398753 | 2019-10-12 19:24:38 +0200 | [diff] [blame] | 232 | #if IFNAMSIZ == 16 |
| 233 | sprintf(pathbuf, "%.16s/brforward", name); |
| 234 | #else |
| 235 | sprintf(pathbuf, "%.*s/brforward", (int)IFNAMSIZ, name); |
| 236 | #endif |
| 237 | fd = open(pathbuf, O_RDONLY); |
Martin Lewis | 6c1af28 | 2019-09-15 18:04:49 +0200 | [diff] [blame] | 238 | if (fd < 0) |
| 239 | bb_error_msg_and_die("bridge %s does not exist", name); |
| 240 | |
| 241 | fdb = NULL; |
| 242 | nentries = 0; |
| 243 | for (;;) { |
| 244 | fdb = xrealloc_vector(fdb, 4, nentries); |
| 245 | cc = full_read(fd, &fdb[nentries], sizeof(*fdb)); |
| 246 | if (cc == 0) { |
| 247 | break; |
| 248 | } |
| 249 | if (cc != sizeof(*fdb)) { |
| 250 | bb_perror_msg_and_die("can't read bridge %s forward db", name); |
| 251 | } |
| 252 | ++nentries; |
| 253 | } |
| 254 | |
Denys Vlasenko | 3398753 | 2019-10-12 19:24:38 +0200 | [diff] [blame] | 255 | if (ENABLE_FEATURE_CLEAN_UP) |
| 256 | close(fd); |
Martin Lewis | 6c1af28 | 2019-09-15 18:04:49 +0200 | [diff] [blame] | 257 | |
| 258 | qsort(fdb, nentries, sizeof(*fdb), compare_fdbs); |
| 259 | |
| 260 | *_fdb = fdb; |
| 261 | return nentries; |
| 262 | } |
| 263 | |
| 264 | static void show_bridge_macs(const char *name) |
| 265 | { |
| 266 | struct fdb_entry *fdb; |
| 267 | size_t nentries; |
| 268 | size_t i; |
| 269 | |
| 270 | nentries = read_bridge_forward_db(name, &fdb); |
| 271 | |
| 272 | printf("port no\tmac addr\t\tis local?\tageing timer\n"); |
| 273 | for (i = 0; i < nentries; ++i) { |
| 274 | const struct fdb_entry *f = &fdb[i]; |
Denys Vlasenko | 3398753 | 2019-10-12 19:24:38 +0200 | [diff] [blame] | 275 | unsigned tv_sec = f->ageing_timer_value / 100; |
| 276 | unsigned tv_csec = f->ageing_timer_value % 100; |
Martin Lewis | 6c1af28 | 2019-09-15 18:04:49 +0200 | [diff] [blame] | 277 | printf("%3u\t" |
| 278 | "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\t" |
| 279 | "%s\t\t" |
| 280 | "%4u.%.2u\n", |
| 281 | f->port_no, |
| 282 | f->mac_addr[0], f->mac_addr[1], f->mac_addr[2], |
| 283 | f->mac_addr[3], f->mac_addr[4], f->mac_addr[5], |
| 284 | (f->is_local ? "yes" : "no"), |
Denys Vlasenko | 3398753 | 2019-10-12 19:24:38 +0200 | [diff] [blame] | 285 | tv_sec, tv_csec |
Martin Lewis | 6c1af28 | 2019-09-15 18:04:49 +0200 | [diff] [blame] | 286 | ); |
| 287 | } |
| 288 | |
Denys Vlasenko | 3398753 | 2019-10-12 19:24:38 +0200 | [diff] [blame] | 289 | if (ENABLE_FEATURE_CLEAN_UP) |
| 290 | free(fdb); |
Martin Lewis | 6c1af28 | 2019-09-15 18:04:49 +0200 | [diff] [blame] | 291 | } |
Martin Lewis | 6dcf563 | 2019-10-10 16:00:19 -0500 | [diff] [blame] | 292 | |
| 293 | static void show_bridge_timer(const char *msg) |
| 294 | { |
Denys Vlasenko | 3398753 | 2019-10-12 19:24:38 +0200 | [diff] [blame] | 295 | unsigned long long centisec = xstrtoull(filedata, 0); |
| 296 | unsigned tv_sec = centisec / 100; |
| 297 | unsigned tv_csec = centisec % 100; |
| 298 | printf("%s%4u.%.2u", msg, tv_sec, tv_csec); |
Martin Lewis | 6dcf563 | 2019-10-10 16:00:19 -0500 | [diff] [blame] | 299 | } |
| 300 | |
| 301 | static const char *show_bridge_state(unsigned state) |
| 302 | { |
| 303 | /* See linux/if_bridge.h, BR_STATE_ constants */ |
Denys Vlasenko | 3398753 | 2019-10-12 19:24:38 +0200 | [diff] [blame] | 304 | static const char state_names[] ALIGN1 = |
Martin Lewis | 6dcf563 | 2019-10-10 16:00:19 -0500 | [diff] [blame] | 305 | "disabled\0" //BR_STATE_DISABLED 0 |
| 306 | "listening\0" //BR_STATE_LISTENING 1 |
| 307 | "learning\0" //BR_STATE_LEARNING 2 |
| 308 | "forwarding\0" //BR_STATE_FORWARDING 3 |
| 309 | "blocking" //BR_STATE_BLOCKING 4 |
| 310 | ; |
| 311 | if (state < 5) |
| 312 | return nth_string(state_names, state); |
| 313 | return utoa(state); |
| 314 | } |
| 315 | |
| 316 | static void printf_xstrtou(const char *fmt) |
| 317 | { |
| 318 | printf(fmt, xstrtou(filedata, 0)); |
| 319 | } |
| 320 | |
Denys Vlasenko | 53b2fdc | 2021-10-10 13:50:53 +0200 | [diff] [blame] | 321 | static NOINLINE void show_bridge_port(const char *name) |
Martin Lewis | 6dcf563 | 2019-10-10 16:00:19 -0500 | [diff] [blame] | 322 | { |
Denys Vlasenko | 3398753 | 2019-10-12 19:24:38 +0200 | [diff] [blame] | 323 | char pathbuf[IFNAMSIZ + sizeof("/brport/forward_delay_timer") + 8]; |
Martin Lewis | 6dcf563 | 2019-10-10 16:00:19 -0500 | [diff] [blame] | 324 | char *sfx; |
| 325 | |
| 326 | #if IFNAMSIZ == 16 |
| 327 | sfx = pathbuf + sprintf(pathbuf, "%.16s/brport/", name); |
| 328 | #else |
| 329 | sfx = pathbuf + sprintf(pathbuf, "%.*s/brport/", (int)IFNAMSIZ, name); |
| 330 | #endif |
| 331 | |
| 332 | strcpy(sfx, "port_no"); |
| 333 | read_file(pathbuf); |
| 334 | printf("%s (%u)\n", name, xstrtou(filedata, 0)); |
| 335 | |
| 336 | strcpy(sfx + 5, "id"); // "port_id" |
| 337 | read_file(pathbuf); |
| 338 | printf_xstrtou(" port id\t\t%.4x"); |
| 339 | |
| 340 | strcpy(sfx, "state"); |
| 341 | read_file(pathbuf); |
| 342 | printf("\t\t\tstate\t\t%15s\n", show_bridge_state(xstrtou(filedata, 0))); |
| 343 | |
| 344 | strcpy(sfx, "designated_root"); |
| 345 | read_file(pathbuf); |
| 346 | printf(" designated root\t%s", filedata); |
| 347 | |
| 348 | strcpy(sfx, "path_cost"); |
| 349 | read_file(pathbuf); |
| 350 | printf_xstrtou("\tpath cost\t\t%4u\n"); |
| 351 | |
| 352 | strcpy(sfx, "designated_bridge"); |
| 353 | read_file(pathbuf); |
| 354 | printf(" designated bridge\t%s", filedata); |
| 355 | |
| 356 | strcpy(sfx, "message_age_timer"); |
| 357 | read_file(pathbuf); |
| 358 | show_bridge_timer("\tmessage age timer\t"); |
| 359 | |
| 360 | strcpy(sfx, "designated_port"); |
| 361 | read_file(pathbuf); |
| 362 | printf_xstrtou("\n designated port\t%.4x"); |
| 363 | |
| 364 | strcpy(sfx, "forward_delay_timer"); |
| 365 | read_file(pathbuf); |
| 366 | show_bridge_timer("\t\t\tforward delay timer\t"); |
| 367 | |
| 368 | strcpy(sfx, "designated_cost"); |
| 369 | read_file(pathbuf); |
| 370 | printf_xstrtou("\n designated cost\t%4u"); |
| 371 | |
| 372 | strcpy(sfx, "hold_timer"); |
| 373 | read_file(pathbuf); |
| 374 | show_bridge_timer("\t\t\thold timer\t\t"); |
| 375 | |
| 376 | printf("\n flags\t\t\t"); |
| 377 | |
| 378 | strcpy(sfx, "config_pending"); |
| 379 | read_file(pathbuf); |
| 380 | if (!LONE_CHAR(filedata, '0')) |
| 381 | printf("CONFIG_PENDING "); |
| 382 | |
| 383 | strcpy(sfx, "change_ack"); |
| 384 | read_file(pathbuf); |
| 385 | if (!LONE_CHAR(filedata, '0')) |
| 386 | printf("TOPOLOGY_CHANGE_ACK "); |
| 387 | |
| 388 | strcpy(sfx, "hairpin_mode"); |
| 389 | read_file(pathbuf); |
| 390 | if (!LONE_CHAR(filedata, '0')) |
| 391 | printf_xstrtou("\n hairpin mode\t\t%4u"); |
| 392 | |
| 393 | printf("\n\n"); |
| 394 | } |
| 395 | |
Martin Lewis | 6dcf563 | 2019-10-10 16:00:19 -0500 | [diff] [blame] | 396 | static void show_bridge_stp(const char *name) |
| 397 | { |
Denys Vlasenko | 3398753 | 2019-10-12 19:24:38 +0200 | [diff] [blame] | 398 | char pathbuf[IFNAMSIZ + sizeof("/bridge/topology_change_timer") + 8]; |
Martin Lewis | 6dcf563 | 2019-10-10 16:00:19 -0500 | [diff] [blame] | 399 | char *sfx; |
| 400 | |
| 401 | #if IFNAMSIZ == 16 |
| 402 | sfx = pathbuf + sprintf(pathbuf, "%.16s/bridge/", name); |
| 403 | #else |
| 404 | sfx = pathbuf + sprintf(pathbuf, "%.*s/bridge/", (int)IFNAMSIZ, name); |
| 405 | #endif |
| 406 | |
| 407 | strcpy(sfx, "bridge_id"); |
| 408 | if (read_file(pathbuf) < 0) |
| 409 | bb_error_msg_and_die("bridge %s does not exist", name); |
| 410 | |
| 411 | printf("%s\n" |
| 412 | " bridge id\t\t%s", name, filedata); |
| 413 | |
| 414 | strcpy(sfx, "root_id"); |
| 415 | read_file(pathbuf); |
| 416 | printf("\n designated root\t%s", filedata); |
| 417 | |
| 418 | strcpy(sfx + 5, "port"); // "root_port" |
| 419 | read_file(pathbuf); |
| 420 | printf_xstrtou("\n root port\t\t%4u\t\t\t"); |
| 421 | |
| 422 | strcpy(sfx + 6, "ath_cost"); // "root_path_cost" |
| 423 | read_file(pathbuf); |
| 424 | printf_xstrtou("path cost\t\t%4u\n"); |
| 425 | |
| 426 | strcpy(sfx, "max_age"); |
| 427 | read_file(pathbuf); |
| 428 | show_bridge_timer(" max age\t\t"); |
| 429 | show_bridge_timer("\t\t\tbridge max age\t\t"); |
| 430 | |
| 431 | strcpy(sfx, "hello_time"); |
| 432 | read_file(pathbuf); |
| 433 | show_bridge_timer("\n hello time\t\t"); |
| 434 | show_bridge_timer("\t\t\tbridge hello time\t"); |
| 435 | |
| 436 | strcpy(sfx, "forward_delay"); |
| 437 | read_file(pathbuf); |
| 438 | show_bridge_timer("\n forward delay\t\t"); |
| 439 | show_bridge_timer("\t\t\tbridge forward delay\t"); |
| 440 | |
| 441 | strcpy(sfx, "ageing_time"); |
| 442 | read_file(pathbuf); |
| 443 | show_bridge_timer("\n ageing time\t\t"); |
| 444 | |
| 445 | strcpy(sfx, "hello_timer"); |
| 446 | read_file(pathbuf); |
| 447 | show_bridge_timer("\n hello timer\t\t"); |
| 448 | |
| 449 | strcpy(sfx, "tcn_timer"); |
| 450 | read_file(pathbuf); |
| 451 | show_bridge_timer("\t\t\ttcn timer\t\t"); |
| 452 | |
| 453 | strcpy(sfx, "topology_change_timer"); |
| 454 | read_file(pathbuf); |
| 455 | show_bridge_timer("\n topology change timer\t"); |
| 456 | |
| 457 | strcpy(sfx, "gc_timer"); |
| 458 | read_file(pathbuf); |
| 459 | show_bridge_timer("\t\t\tgc timer\t\t"); |
| 460 | |
| 461 | printf("\n flags\t\t\t"); |
| 462 | |
| 463 | strcpy(sfx, "topology_change"); |
| 464 | read_file(pathbuf); |
| 465 | if (!LONE_CHAR(filedata, '0')) |
| 466 | printf("TOPOLOGY_CHANGE "); |
| 467 | |
| 468 | strcpy(sfx, "topology_change_detected"); |
| 469 | read_file(pathbuf); |
| 470 | if (!LONE_CHAR(filedata, '0')) |
| 471 | printf("TOPOLOGY_CHANGE_DETECTED "); |
| 472 | printf("\n\n\n"); |
| 473 | |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 474 | /* Show bridge ports */ |
| 475 | { |
| 476 | DIR *ifaces; |
| 477 | |
Denys Vlasenko | 37a9008 | 2019-10-15 12:31:54 +0200 | [diff] [blame] | 478 | /* sfx points past "BR/bridge/", turn it into "BR/brif": */ |
| 479 | sfx[-4] = 'f'; sfx[-3] = '\0'; |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 480 | ifaces = opendir(pathbuf); |
| 481 | if (ifaces) { |
| 482 | struct dirent *ent; |
| 483 | while ((ent = readdir(ifaces)) != NULL) { |
| 484 | if (DOT_OR_DOTDOT(ent->d_name)) |
| 485 | continue; /* . or .. */ |
| 486 | show_bridge_port(ent->d_name); |
| 487 | } |
| 488 | if (ENABLE_FEATURE_CLEAN_UP) |
| 489 | closedir(ifaces); |
| 490 | } |
| 491 | } |
Martin Lewis | 6dcf563 | 2019-10-10 16:00:19 -0500 | [diff] [blame] | 492 | } |
Denys Vlasenko | 3e463e1 | 2019-06-08 12:35:06 +0200 | [diff] [blame] | 493 | #endif |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 494 | |
Denis Vlasenko | d0a071a | 2008-03-17 09:33:45 +0000 | [diff] [blame] | 495 | int brctl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
Denis Vlasenko | a60f84e | 2008-07-05 09:18:54 +0000 | [diff] [blame] | 496 | int brctl_main(int argc UNUSED_PARAM, char **argv) |
Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 497 | { |
Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 498 | static const char keywords[] ALIGN1 = |
| 499 | "addbr\0" "delbr\0" "addif\0" "delif\0" |
Denis Vlasenko | 5e34ff2 | 2009-04-21 11:09:40 +0000 | [diff] [blame] | 500 | IF_FEATURE_BRCTL_FANCY( |
Bernhard Reutner-Fischer | 2b11fb4 | 2008-01-14 16:10:11 +0000 | [diff] [blame] | 501 | "stp\0" |
Martin Lewis | 6dcf563 | 2019-10-10 16:00:19 -0500 | [diff] [blame] | 502 | "showstp\0" |
Bernhard Reutner-Fischer | 1aac3ab | 2008-01-13 18:43:50 +0000 | [diff] [blame] | 503 | "setageing\0" "setfd\0" "sethello\0" "setmaxage\0" |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 504 | "setpathcost\0" "setportprio\0" |
| 505 | "setbridgeprio\0" |
Martin Lewis | 6c1af28 | 2019-09-15 18:04:49 +0200 | [diff] [blame] | 506 | "showmacs\0" |
Bernhard Reutner-Fischer | 1aac3ab | 2008-01-13 18:43:50 +0000 | [diff] [blame] | 507 | ) |
Nicolas Thill | f47ce07 | 2012-09-25 14:06:01 +0200 | [diff] [blame] | 508 | IF_FEATURE_BRCTL_SHOW("show\0"); |
Bernhard Reutner-Fischer | 1aac3ab | 2008-01-13 18:43:50 +0000 | [diff] [blame] | 509 | enum { ARG_addbr = 0, ARG_delbr, ARG_addif, ARG_delif |
Denis Vlasenko | 5e34ff2 | 2009-04-21 11:09:40 +0000 | [diff] [blame] | 510 | IF_FEATURE_BRCTL_FANCY(, |
Denys Vlasenko | 60cb48c | 2013-01-14 15:57:44 +0100 | [diff] [blame] | 511 | ARG_stp, |
Martin Lewis | 6dcf563 | 2019-10-10 16:00:19 -0500 | [diff] [blame] | 512 | ARG_showstp, |
Denys Vlasenko | 60cb48c | 2013-01-14 15:57:44 +0100 | [diff] [blame] | 513 | ARG_setageing, ARG_setfd, ARG_sethello, ARG_setmaxage, |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 514 | ARG_setpathcost, ARG_setportprio, |
Martin Lewis | 6c1af28 | 2019-09-15 18:04:49 +0200 | [diff] [blame] | 515 | ARG_setbridgeprio, |
| 516 | ARG_showmacs |
Bernhard Reutner-Fischer | 1aac3ab | 2008-01-13 18:43:50 +0000 | [diff] [blame] | 517 | ) |
Nicolas Thill | f47ce07 | 2012-09-25 14:06:01 +0200 | [diff] [blame] | 518 | IF_FEATURE_BRCTL_SHOW(, ARG_show) |
Denis Vlasenko | d0a071a | 2008-03-17 09:33:45 +0000 | [diff] [blame] | 519 | }; |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 520 | int key; |
| 521 | char *br; |
Denis Vlasenko | d0a071a | 2008-03-17 09:33:45 +0000 | [diff] [blame] | 522 | |
Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 523 | argv++; |
Denys Vlasenko | c5150e9 | 2019-04-12 18:52:31 +0200 | [diff] [blame] | 524 | if (!*argv) { |
| 525 | /* bare "brctl" shows --help */ |
| 526 | bb_show_usage(); |
| 527 | } |
| 528 | |
| 529 | xchdir("/sys/class/net"); |
| 530 | |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 531 | key = index_in_strings(keywords, *argv); |
| 532 | if (key == -1) /* no match found in keywords array, bail out. */ |
| 533 | bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name); |
| 534 | argv++; |
Denis Vlasenko | 278a1c2 | 2008-04-06 07:17:02 +0000 | [diff] [blame] | 535 | |
Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 536 | #if ENABLE_FEATURE_BRCTL_SHOW |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 537 | if (key == ARG_show) { /* show [BR]... */ |
| 538 | DIR *net; |
| 539 | struct dirent *ent; |
| 540 | int need_hdr = 1; |
| 541 | int exitcode = EXIT_SUCCESS; |
Denis Vlasenko | 278a1c2 | 2008-04-06 07:17:02 +0000 | [diff] [blame] | 542 | |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 543 | if (*argv) { |
| 544 | /* "show BR1 BR2 BR3" */ |
| 545 | do { |
| 546 | if (show_bridge(*argv, need_hdr) >= 0) { |
| 547 | need_hdr = 0; |
| 548 | } else { |
| 549 | bb_error_msg("bridge %s does not exist", *argv); |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 550 | //TODO: if device exists, but is not a BR, brctl from bridge-utils 1.6 |
| 551 | //says this instead: "device eth0 is not a bridge" |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 552 | exitcode = EXIT_FAILURE; |
| 553 | } |
| 554 | } while (*++argv != NULL); |
Denys Vlasenko | c5150e9 | 2019-04-12 18:52:31 +0200 | [diff] [blame] | 555 | return exitcode; |
Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 556 | } |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 557 | |
| 558 | /* "show" (if no ifaces, shows nothing, not even header) */ |
| 559 | net = xopendir("."); |
| 560 | while ((ent = readdir(net)) != NULL) { |
| 561 | if (DOT_OR_DOTDOT(ent->d_name)) |
| 562 | continue; /* . or .. */ |
| 563 | if (show_bridge(ent->d_name, need_hdr) >= 0) |
| 564 | need_hdr = 0; |
| 565 | } |
| 566 | if (ENABLE_FEATURE_CLEAN_UP) |
| 567 | closedir(net); |
| 568 | return exitcode; |
| 569 | } |
Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 570 | #endif |
Denis Vlasenko | 278a1c2 | 2008-04-06 07:17:02 +0000 | [diff] [blame] | 571 | |
Denys Vlasenko | eb13951 | 2019-10-12 19:51:46 +0200 | [diff] [blame] | 572 | if (!*argv) /* All of the below need at least one argument */ |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 573 | bb_show_usage(); |
Denis Vlasenko | 278a1c2 | 2008-04-06 07:17:02 +0000 | [diff] [blame] | 574 | |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 575 | br = *argv++; |
Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 576 | |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 577 | if (key == ARG_addbr || key == ARG_delbr) { |
| 578 | /* brctl from bridge-utils 1.6 still uses ioctl |
| 579 | * for SIOCBRADDBR / SIOCBRDELBR, not /sys accesses |
| 580 | */ |
| 581 | int fd = xsocket(AF_INET, SOCK_STREAM, 0); |
| 582 | ioctl_or_perror_and_die(fd, |
| 583 | key == ARG_addbr ? SIOCBRADDBR : SIOCBRDELBR, |
| 584 | br, "bridge %s", br |
| 585 | ); |
| 586 | //close(fd); |
| 587 | //goto done; |
| 588 | /* bridge-utils 1.6 simply ignores trailing args: |
| 589 | * "brctl addbr BR1 ARGS" ignores ARGS |
| 590 | */ |
| 591 | if (ENABLE_FEATURE_CLEAN_UP) |
| 592 | close(fd); |
| 593 | return EXIT_SUCCESS; |
| 594 | } |
Denis Vlasenko | 278a1c2 | 2008-04-06 07:17:02 +0000 | [diff] [blame] | 595 | |
Denys Vlasenko | 6eb38fd | 2020-06-23 02:46:53 +0200 | [diff] [blame] | 596 | #if ENABLE_FEATURE_BRCTL_FANCY |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 597 | if (key == ARG_showmacs) { |
| 598 | show_bridge_macs(br); |
| 599 | return EXIT_SUCCESS; |
| 600 | } |
| 601 | if (key == ARG_showstp) { |
| 602 | show_bridge_stp(br); |
| 603 | return EXIT_SUCCESS; |
| 604 | } |
Denys Vlasenko | 6eb38fd | 2020-06-23 02:46:53 +0200 | [diff] [blame] | 605 | #endif |
Martin Lewis | 6c1af28 | 2019-09-15 18:04:49 +0200 | [diff] [blame] | 606 | |
Denys Vlasenko | eb13951 | 2019-10-12 19:51:46 +0200 | [diff] [blame] | 607 | if (!*argv) /* All of the below need at least two arguments */ |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 608 | bb_show_usage(); |
Denis Vlasenko | 278a1c2 | 2008-04-06 07:17:02 +0000 | [diff] [blame] | 609 | |
Bernhard Reutner-Fischer | 1aac3ab | 2008-01-13 18:43:50 +0000 | [diff] [blame] | 610 | #if ENABLE_FEATURE_BRCTL_FANCY |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 611 | if (key == ARG_stp) { |
| 612 | static const char no_yes[] ALIGN1 = |
| 613 | "0\0" "off\0" "n\0" "no\0" /* 0 .. 3 */ |
| 614 | "1\0" "on\0" "y\0" "yes\0"; /* 4 .. 7 */ |
| 615 | int onoff = index_in_strings(no_yes, *argv); |
| 616 | if (onoff < 0) |
| 617 | bb_error_msg_and_die(bb_msg_invalid_arg_to, *argv, applet_name); |
| 618 | onoff = (unsigned)onoff / 4; |
| 619 | write_uint(br, "bridge/stp_state", onoff); |
| 620 | return EXIT_SUCCESS; |
| 621 | } |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 622 | |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 623 | if ((unsigned)(key - ARG_setageing) < 4) { /* time related ops */ |
| 624 | /* setageing BR N: "N*100\n" to /sys/class/net/BR/bridge/ageing_time |
| 625 | * setfd BR N: "N*100\n" to /sys/class/net/BR/bridge/forward_delay |
| 626 | * sethello BR N: "N*100\n" to /sys/class/net/BR/bridge/hello_time |
| 627 | * setmaxage BR N: "N*100\n" to /sys/class/net/BR/bridge/max_age |
| 628 | */ |
| 629 | write_uint(br, |
| 630 | nth_string( |
| 631 | "bridge/ageing_time" "\0" /* ARG_setageing */ |
| 632 | "bridge/forward_delay""\0" /* ARG_setfd */ |
| 633 | "bridge/hello_time" "\0" /* ARG_sethello */ |
| 634 | "bridge/max_age", /* ARG_setmaxage */ |
| 635 | key - ARG_setageing |
| 636 | ), |
| 637 | str_to_jiffies(*argv) |
| 638 | ); |
| 639 | return EXIT_SUCCESS; |
| 640 | } |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 641 | |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 642 | if (key == ARG_setbridgeprio) { |
| 643 | write_uint(br, "bridge/priority", xatoi_positive(*argv)); |
| 644 | return EXIT_SUCCESS; |
| 645 | } |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 646 | |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 647 | if (key == ARG_setpathcost |
| 648 | || key == ARG_setportprio |
| 649 | ) { |
| 650 | if (!argv[1]) |
| 651 | bb_show_usage(); |
| 652 | /* BR is not used (and ignored!) for these commands: |
| 653 | * "setpathcost BR PORT N" writes "N\n" to |
| 654 | * /sys/class/net/PORT/brport/path_cost |
| 655 | * "setportprio BR PORT N" writes "N\n" to |
| 656 | * /sys/class/net/PORT/brport/priority |
| 657 | */ |
| 658 | write_uint(argv[0], |
| 659 | nth_string( |
| 660 | "brport/path_cost" "\0" /* ARG_setpathcost */ |
| 661 | "brport/priority", /* ARG_setportprio */ |
| 662 | key - ARG_setpathcost |
| 663 | ), |
| 664 | xatoi_positive(argv[1]) |
| 665 | ); |
| 666 | return EXIT_SUCCESS; |
| 667 | } |
Bernhard Reutner-Fischer | 1aac3ab | 2008-01-13 18:43:50 +0000 | [diff] [blame] | 668 | #endif |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 669 | /* always true: if (key == ARG_addif || key == ARG_delif) */ { |
| 670 | struct ifreq ifr; |
| 671 | int fd = xsocket(AF_INET, SOCK_STREAM, 0); |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 672 | |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 673 | strncpy_IFNAMSIZ(ifr.ifr_name, br); |
| 674 | ifr.ifr_ifindex = if_nametoindex(*argv); |
| 675 | if (ifr.ifr_ifindex == 0) { |
| 676 | bb_perror_msg_and_die("iface %s", *argv); |
Denys Vlasenko | dc1b2d4 | 2019-04-13 13:58:06 +0200 | [diff] [blame] | 677 | } |
Denys Vlasenko | b4fa16d | 2019-10-12 19:42:37 +0200 | [diff] [blame] | 678 | ioctl_or_perror_and_die(fd, |
| 679 | key == ARG_addif ? SIOCBRADDIF : SIOCBRDELIF, |
| 680 | &ifr, "bridge %s", br |
| 681 | ); |
| 682 | if (ENABLE_FEATURE_CLEAN_UP) |
| 683 | close(fd); |
Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 684 | } |
Denis Vlasenko | 278a1c2 | 2008-04-06 07:17:02 +0000 | [diff] [blame] | 685 | |
Bernhard Reutner-Fischer | d27d925 | 2008-01-13 15:23:27 +0000 | [diff] [blame] | 686 | return EXIT_SUCCESS; |
| 687 | } |