PageRenderTime 51ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/bridge-utils-1.5/libbridge/libbridge_devif.c

#
C | 449 lines | 338 code | 74 blank | 37 comment | 28 complexity | f54d5ae939850f44e7f88a44f6ecdf67 MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. * Copyright (C) 2000 Lennert Buytenhek
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17. */
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <unistd.h>
  21. #include <errno.h>
  22. #include <string.h>
  23. #include <dirent.h>
  24. #include <sys/fcntl.h>
  25. #include "libbridge.h"
  26. #include "libbridge_private.h"
  27. static FILE *fpopen(const char *dir, const char *name)
  28. {
  29. char path[SYSFS_PATH_MAX];
  30. snprintf(path, SYSFS_PATH_MAX, "%s/%s", dir, name);
  31. return fopen(path, "r");
  32. }
  33. static void fetch_id(const char *dev, const char *name, struct bridge_id *id)
  34. {
  35. FILE *f = fpopen(dev, name);
  36. if (!f)
  37. fprintf(stderr, "%s: %s\n", dev, strerror(errno));
  38. else {
  39. fscanf(f, "%2hhx%2hhx.%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx",
  40. &id->prio[0], &id->prio[1],
  41. &id->addr[0], &id->addr[1], &id->addr[2],
  42. &id->addr[3], &id->addr[4], &id->addr[5]);
  43. fclose(f);
  44. }
  45. }
  46. /* Fetch an integer attribute out of sysfs. */
  47. static int fetch_int(const char *dev, const char *name)
  48. {
  49. FILE *f = fpopen(dev, name);
  50. int value = -1;
  51. if (!f)
  52. return 0;
  53. fscanf(f, "%i", &value);
  54. fclose(f);
  55. return value;
  56. }
  57. /* Get a time value out of sysfs */
  58. static void fetch_tv(const char *dev, const char *name,
  59. struct timeval *tv)
  60. {
  61. __jiffies_to_tv(tv, fetch_int(dev, name));
  62. }
  63. /*
  64. * Convert device name to an index in the list of ports in bridge.
  65. *
  66. * Old API does bridge operations as if ports were an array
  67. * inside bridge structure.
  68. */
  69. static int get_portno(const char *brname, const char *ifname)
  70. {
  71. int i;
  72. int ifindex = if_nametoindex(ifname);
  73. int ifindices[MAX_PORTS];
  74. unsigned long args[4] = { BRCTL_GET_PORT_LIST,
  75. (unsigned long)ifindices, MAX_PORTS, 0 };
  76. struct ifreq ifr;
  77. if (ifindex <= 0)
  78. goto error;
  79. memset(ifindices, 0, sizeof(ifindices));
  80. strncpy(ifr.ifr_name, brname, IFNAMSIZ);
  81. ifr.ifr_data = (char *) &args;
  82. if (ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr) < 0) {
  83. dprintf("get_portno: get ports of %s failed: %s\n",
  84. brname, strerror(errno));
  85. goto error;
  86. }
  87. for (i = 0; i < MAX_PORTS; i++) {
  88. if (ifindices[i] == ifindex)
  89. return i;
  90. }
  91. dprintf("%s is not a in bridge %s\n", ifname, brname);
  92. error:
  93. return -1;
  94. }
  95. /* get information via ioctl */
  96. static int old_get_bridge_info(const char *bridge, struct bridge_info *info)
  97. {
  98. struct ifreq ifr;
  99. struct __bridge_info i;
  100. unsigned long args[4] = { BRCTL_GET_BRIDGE_INFO,
  101. (unsigned long) &i, 0, 0 };
  102. memset(info, 0, sizeof(*info));
  103. strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
  104. ifr.ifr_data = (char *) &args;
  105. if (ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr) < 0) {
  106. dprintf("%s: can't get info %s\n",
  107. bridge, strerror(errno));
  108. return errno;
  109. }
  110. memcpy(&info->designated_root, &i.designated_root, 8);
  111. memcpy(&info->bridge_id, &i.bridge_id, 8);
  112. info->root_path_cost = i.root_path_cost;
  113. info->root_port = i.root_port;
  114. info->topology_change = i.topology_change;
  115. info->topology_change_detected = i.topology_change_detected;
  116. info->stp_enabled = i.stp_enabled;
  117. __jiffies_to_tv(&info->max_age, i.max_age);
  118. __jiffies_to_tv(&info->hello_time, i.hello_time);
  119. __jiffies_to_tv(&info->forward_delay, i.forward_delay);
  120. __jiffies_to_tv(&info->bridge_max_age, i.bridge_max_age);
  121. __jiffies_to_tv(&info->bridge_hello_time, i.bridge_hello_time);
  122. __jiffies_to_tv(&info->bridge_forward_delay, i.bridge_forward_delay);
  123. __jiffies_to_tv(&info->ageing_time, i.ageing_time);
  124. __jiffies_to_tv(&info->hello_timer_value, i.hello_timer_value);
  125. __jiffies_to_tv(&info->tcn_timer_value, i.tcn_timer_value);
  126. __jiffies_to_tv(&info->topology_change_timer_value,
  127. i.topology_change_timer_value);
  128. __jiffies_to_tv(&info->gc_timer_value, i.gc_timer_value);
  129. return 0;
  130. }
  131. /*
  132. * Get bridge parameters using either sysfs or old
  133. * ioctl.
  134. */
  135. int br_get_bridge_info(const char *bridge, struct bridge_info *info)
  136. {
  137. DIR *dir;
  138. char path[SYSFS_PATH_MAX];
  139. snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/bridge", bridge);
  140. dir = opendir(path);
  141. if (dir == NULL) {
  142. dprintf("path '%s' is not a directory\n", path);
  143. goto fallback;
  144. }
  145. memset(info, 0, sizeof(*info));
  146. fetch_id(path, "root_id", &info->designated_root);
  147. fetch_id(path, "bridge_id", &info->bridge_id);
  148. info->root_path_cost = fetch_int(path, "root_path_cost");
  149. fetch_tv(path, "max_age", &info->max_age);
  150. fetch_tv(path, "hello_time", &info->hello_time);
  151. fetch_tv(path, "forward_delay", &info->forward_delay);
  152. fetch_tv(path, "max_age", &info->bridge_max_age);
  153. fetch_tv(path, "hello_time", &info->bridge_hello_time);
  154. fetch_tv(path, "forward_delay", &info->bridge_forward_delay);
  155. fetch_tv(path, "ageing_time", &info->ageing_time);
  156. fetch_tv(path, "hello_timer", &info->hello_timer_value);
  157. fetch_tv(path, "tcn_timer", &info->tcn_timer_value);
  158. fetch_tv(path, "topology_change_timer",
  159. &info->topology_change_timer_value);;
  160. fetch_tv(path, "gc_timer", &info->gc_timer_value);
  161. info->root_port = fetch_int(path, "root_port");
  162. info->stp_enabled = fetch_int(path, "stp_state");
  163. info->topology_change = fetch_int(path, "topology_change");
  164. info->topology_change_detected = fetch_int(path, "topology_change_detected");
  165. closedir(dir);
  166. return 0;
  167. fallback:
  168. return old_get_bridge_info(bridge, info);
  169. }
  170. static int old_get_port_info(const char *brname, const char *port,
  171. struct port_info *info)
  172. {
  173. struct __port_info i;
  174. int index;
  175. memset(info, 0, sizeof(*info));
  176. index = get_portno(brname, port);
  177. if (index < 0)
  178. return errno;
  179. else {
  180. struct ifreq ifr;
  181. unsigned long args[4] = { BRCTL_GET_PORT_INFO,
  182. (unsigned long) &i, index, 0 };
  183. strncpy(ifr.ifr_name, brname, IFNAMSIZ);
  184. ifr.ifr_data = (char *) &args;
  185. if (ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr) < 0) {
  186. dprintf("old can't get port %s(%d) info %s\n",
  187. brname, index, strerror(errno));
  188. return errno;
  189. }
  190. }
  191. info->port_no = index;
  192. memcpy(&info->designated_root, &i.designated_root, 8);
  193. memcpy(&info->designated_bridge, &i.designated_bridge, 8);
  194. info->port_id = i.port_id;
  195. info->designated_port = i.designated_port;
  196. info->path_cost = i.path_cost;
  197. info->designated_cost = i.designated_cost;
  198. info->state = i.state;
  199. info->top_change_ack = i.top_change_ack;
  200. info->config_pending = i.config_pending;
  201. __jiffies_to_tv(&info->message_age_timer_value,
  202. i.message_age_timer_value);
  203. __jiffies_to_tv(&info->forward_delay_timer_value,
  204. i.forward_delay_timer_value);
  205. __jiffies_to_tv(&info->hold_timer_value, i.hold_timer_value);
  206. info->hairpin_mode = 0;
  207. return 0;
  208. }
  209. /*
  210. * Get information about port on bridge.
  211. */
  212. int br_get_port_info(const char *brname, const char *port,
  213. struct port_info *info)
  214. {
  215. DIR *d;
  216. char path[SYSFS_PATH_MAX];
  217. snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brport", port);
  218. d = opendir(path);
  219. if (!d)
  220. goto fallback;
  221. memset(info, 0, sizeof(*info));
  222. fetch_id(path, "designated_root", &info->designated_root);
  223. fetch_id(path, "designated_bridge", &info->designated_bridge);
  224. info->port_no = fetch_int(path, "port_no");
  225. info->port_id = fetch_int(path, "port_id");
  226. info->designated_port = fetch_int(path, "designated_port");
  227. info->path_cost = fetch_int(path, "path_cost");
  228. info->designated_cost = fetch_int(path, "designated_cost");
  229. info->state = fetch_int(path, "state");
  230. info->top_change_ack = fetch_int(path, "change_ack");
  231. info->config_pending = fetch_int(path, "config_pending");
  232. fetch_tv(path, "message_age_timer", &info->message_age_timer_value);
  233. fetch_tv(path, "forward_delay_timer", &info->forward_delay_timer_value);
  234. fetch_tv(path, "hold_timer", &info->hold_timer_value);
  235. info->hairpin_mode = fetch_int(path, "hairpin_mode");
  236. closedir(d);
  237. return 0;
  238. fallback:
  239. return old_get_port_info(brname, port, info);
  240. }
  241. static int set_sysfs(const char *path, unsigned long value)
  242. {
  243. int fd, ret = 0, cc;
  244. char buf[32];
  245. fd = open(path, O_WRONLY);
  246. if (fd < 0)
  247. return -1;
  248. cc = snprintf(buf, sizeof(buf), "%lu\n", value);
  249. if (write(fd, buf, cc) < 0)
  250. ret = -1;
  251. close(fd);
  252. return ret;
  253. }
  254. static int br_set(const char *bridge, const char *name,
  255. unsigned long value, unsigned long oldcode)
  256. {
  257. int ret;
  258. char path[SYSFS_PATH_MAX];
  259. snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/bridge/%s",
  260. bridge, name);
  261. if ((ret = set_sysfs(path, value)) < 0) {
  262. /* fallback to old ioctl */
  263. struct ifreq ifr;
  264. unsigned long args[4] = { oldcode, value, 0, 0 };
  265. strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
  266. ifr.ifr_data = (char *) &args;
  267. ret = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
  268. }
  269. return ret < 0 ? errno : 0;
  270. }
  271. int br_set_bridge_forward_delay(const char *br, struct timeval *tv)
  272. {
  273. return br_set(br, "forward_delay", __tv_to_jiffies(tv),
  274. BRCTL_SET_BRIDGE_FORWARD_DELAY);
  275. }
  276. int br_set_bridge_hello_time(const char *br, struct timeval *tv)
  277. {
  278. return br_set(br, "hello_time", __tv_to_jiffies(tv),
  279. BRCTL_SET_BRIDGE_HELLO_TIME);
  280. }
  281. int br_set_bridge_max_age(const char *br, struct timeval *tv)
  282. {
  283. return br_set(br, "max_age", __tv_to_jiffies(tv),
  284. BRCTL_SET_BRIDGE_MAX_AGE);
  285. }
  286. int br_set_ageing_time(const char *br, struct timeval *tv)
  287. {
  288. return br_set(br, "ageing_time", __tv_to_jiffies(tv),
  289. BRCTL_SET_AGEING_TIME);
  290. }
  291. int br_set_stp_state(const char *br, int stp_state)
  292. {
  293. return br_set(br, "stp_state", stp_state, BRCTL_SET_BRIDGE_STP_STATE);
  294. }
  295. int br_set_bridge_priority(const char *br, int bridge_priority)
  296. {
  297. return br_set(br, "priority", bridge_priority,
  298. BRCTL_SET_BRIDGE_PRIORITY);
  299. }
  300. static int port_set(const char *bridge, const char *ifname,
  301. const char *name, unsigned long value,
  302. unsigned long oldcode)
  303. {
  304. int ret;
  305. char path[SYSFS_PATH_MAX];
  306. snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brport/%s", ifname, name);
  307. if ((ret = set_sysfs(path, value)) < 0) {
  308. int index = get_portno(bridge, ifname);
  309. if (index < 0)
  310. ret = index;
  311. else {
  312. struct ifreq ifr;
  313. unsigned long args[4] = { oldcode, index, value, 0 };
  314. strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
  315. ifr.ifr_data = (char *) &args;
  316. ret = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
  317. }
  318. }
  319. return ret < 0 ? errno : 0;
  320. }
  321. int br_set_port_priority(const char *bridge, const char *port, int priority)
  322. {
  323. return port_set(bridge, port, "priority", priority, BRCTL_SET_PORT_PRIORITY);
  324. }
  325. int br_set_path_cost(const char *bridge, const char *port, int cost)
  326. {
  327. return port_set(bridge, port, "path_cost", cost, BRCTL_SET_PATH_COST);
  328. }
  329. int br_set_hairpin_mode(const char *bridge, const char *port, int hairpin_mode)
  330. {
  331. return port_set(bridge, port, "hairpin_mode", hairpin_mode, 0);
  332. }
  333. static inline void __copy_fdb(struct fdb_entry *ent,
  334. const struct __fdb_entry *f)
  335. {
  336. memcpy(ent->mac_addr, f->mac_addr, 6);
  337. ent->port_no = f->port_no;
  338. ent->is_local = f->is_local;
  339. __jiffies_to_tv(&ent->ageing_timer_value, f->ageing_timer_value);
  340. }
  341. int br_read_fdb(const char *bridge, struct fdb_entry *fdbs,
  342. unsigned long offset, int num)
  343. {
  344. FILE *f;
  345. int i, n;
  346. struct __fdb_entry fe[num];
  347. char path[SYSFS_PATH_MAX];
  348. /* open /sys/class/net/brXXX/brforward */
  349. snprintf(path, SYSFS_PATH_MAX, SYSFS_CLASS_NET "%s/brforward", bridge);
  350. f = fopen(path, "r");
  351. if (f) {
  352. fseek(f, offset*sizeof(struct __fdb_entry), SEEK_SET);
  353. n = fread(fe, sizeof(struct __fdb_entry), num, f);
  354. fclose(f);
  355. } else {
  356. /* old kernel, use ioctl */
  357. unsigned long args[4] = { BRCTL_GET_FDB_ENTRIES,
  358. (unsigned long) fe,
  359. num, offset };
  360. struct ifreq ifr;
  361. int retries = 0;
  362. strncpy(ifr.ifr_name, bridge, IFNAMSIZ);
  363. ifr.ifr_data = (char *) args;
  364. retry:
  365. n = ioctl(br_socket_fd, SIOCDEVPRIVATE, &ifr);
  366. /* table can change during ioctl processing */
  367. if (n < 0 && errno == EAGAIN && ++retries < 10) {
  368. sleep(0);
  369. goto retry;
  370. }
  371. }
  372. for (i = 0; i < n; i++)
  373. __copy_fdb(fdbs+i, fe+i);
  374. return n;
  375. }