PageRenderTime 54ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/bridge/link.c

https://github.com/CyanogenMod/android_external_iproute2
C | 476 lines | 403 code | 61 blank | 12 comment | 149 complexity | 7281e40d32b98612bbc3d18b42ad05b7 MD5 | raw file
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <time.h>
  5. #include <sys/socket.h>
  6. #include <sys/time.h>
  7. #include <netinet/in.h>
  8. #include <linux/if.h>
  9. #include <linux/if_bridge.h>
  10. #include <string.h>
  11. #include <stdbool.h>
  12. #include "libnetlink.h"
  13. #include "utils.h"
  14. #include "br_common.h"
  15. static unsigned int filter_index;
  16. static const char *port_states[] = {
  17. [BR_STATE_DISABLED] = "disabled",
  18. [BR_STATE_LISTENING] = "listening",
  19. [BR_STATE_LEARNING] = "learning",
  20. [BR_STATE_FORWARDING] = "forwarding",
  21. [BR_STATE_BLOCKING] = "blocking",
  22. };
  23. extern char *if_indextoname (unsigned int __ifindex, char *__ifname);
  24. static void print_link_flags(FILE *fp, unsigned flags)
  25. {
  26. fprintf(fp, "<");
  27. if (flags & IFF_UP && !(flags & IFF_RUNNING))
  28. fprintf(fp, "NO-CARRIER%s", flags ? "," : "");
  29. flags &= ~IFF_RUNNING;
  30. #define _PF(f) if (flags&IFF_##f) { \
  31. flags &= ~IFF_##f ; \
  32. fprintf(fp, #f "%s", flags ? "," : ""); }
  33. _PF(LOOPBACK);
  34. _PF(BROADCAST);
  35. _PF(POINTOPOINT);
  36. _PF(MULTICAST);
  37. _PF(NOARP);
  38. _PF(ALLMULTI);
  39. _PF(PROMISC);
  40. _PF(MASTER);
  41. _PF(SLAVE);
  42. _PF(DEBUG);
  43. _PF(DYNAMIC);
  44. _PF(AUTOMEDIA);
  45. _PF(PORTSEL);
  46. _PF(NOTRAILERS);
  47. _PF(UP);
  48. _PF(LOWER_UP);
  49. _PF(DORMANT);
  50. _PF(ECHO);
  51. #undef _PF
  52. if (flags)
  53. fprintf(fp, "%x", flags);
  54. fprintf(fp, "> ");
  55. }
  56. static const char *oper_states[] = {
  57. "UNKNOWN", "NOTPRESENT", "DOWN", "LOWERLAYERDOWN",
  58. "TESTING", "DORMANT", "UP"
  59. };
  60. static const char *hw_mode[] = {"VEB", "VEPA"};
  61. static void print_operstate(FILE *f, __u8 state)
  62. {
  63. if (state >= sizeof(oper_states)/sizeof(oper_states[0]))
  64. fprintf(f, "state %#x ", state);
  65. else
  66. fprintf(f, "state %s ", oper_states[state]);
  67. }
  68. static void print_portstate(FILE *f, __u8 state)
  69. {
  70. if (state <= BR_STATE_BLOCKING)
  71. fprintf(f, "state %s ", port_states[state]);
  72. else
  73. fprintf(f, "state (%d) ", state);
  74. }
  75. static void print_onoff(FILE *f, char *flag, __u8 val)
  76. {
  77. fprintf(f, "%s %s ", flag, val ? "on" : "off");
  78. }
  79. static void print_hwmode(FILE *f, __u16 mode)
  80. {
  81. if (mode >= sizeof(hw_mode)/sizeof(hw_mode[0]))
  82. fprintf(f, "hwmode %#hx ", mode);
  83. else
  84. fprintf(f, "hwmode %s ", hw_mode[mode]);
  85. }
  86. int print_linkinfo(const struct sockaddr_nl *who,
  87. struct nlmsghdr *n, void *arg)
  88. {
  89. FILE *fp = arg;
  90. int len = n->nlmsg_len;
  91. struct ifinfomsg *ifi = NLMSG_DATA(n);
  92. struct rtattr * tb[IFLA_MAX+1];
  93. char b1[IFNAMSIZ];
  94. len -= NLMSG_LENGTH(sizeof(*ifi));
  95. if (len < 0) {
  96. fprintf(stderr, "Message too short!\n");
  97. return -1;
  98. }
  99. if (!(ifi->ifi_family == AF_BRIDGE || ifi->ifi_family == AF_UNSPEC))
  100. return 0;
  101. if (filter_index && filter_index != ifi->ifi_index)
  102. return 0;
  103. parse_rtattr_flags(tb, IFLA_MAX, IFLA_RTA(ifi), len, NLA_F_NESTED);
  104. if (tb[IFLA_IFNAME] == NULL) {
  105. fprintf(stderr, "BUG: nil ifname\n");
  106. return -1;
  107. }
  108. if (n->nlmsg_type == RTM_DELLINK)
  109. fprintf(fp, "Deleted ");
  110. fprintf(fp, "%d: %s ", ifi->ifi_index,
  111. tb[IFLA_IFNAME] ? rta_getattr_str(tb[IFLA_IFNAME]) : "<nil>");
  112. if (tb[IFLA_OPERSTATE])
  113. print_operstate(fp, rta_getattr_u8(tb[IFLA_OPERSTATE]));
  114. if (tb[IFLA_LINK]) {
  115. SPRINT_BUF(b1);
  116. int iflink = rta_getattr_u32(tb[IFLA_LINK]);
  117. if (iflink == 0)
  118. fprintf(fp, "@NONE: ");
  119. else
  120. fprintf(fp, "@%s: ",
  121. if_indextoname(iflink, b1));
  122. } else
  123. fprintf(fp, ": ");
  124. print_link_flags(fp, ifi->ifi_flags);
  125. if (tb[IFLA_MTU])
  126. fprintf(fp, "mtu %u ", rta_getattr_u32(tb[IFLA_MTU]));
  127. if (tb[IFLA_MASTER])
  128. fprintf(fp, "master %s ",
  129. if_indextoname(rta_getattr_u32(tb[IFLA_MASTER]), b1));
  130. if (tb[IFLA_PROTINFO]) {
  131. if (tb[IFLA_PROTINFO]->rta_type & NLA_F_NESTED) {
  132. struct rtattr *prtb[IFLA_BRPORT_MAX+1];
  133. parse_rtattr_nested(prtb, IFLA_BRPORT_MAX,
  134. tb[IFLA_PROTINFO]);
  135. if (prtb[IFLA_BRPORT_STATE])
  136. print_portstate(fp,
  137. rta_getattr_u8(prtb[IFLA_BRPORT_STATE]));
  138. if (prtb[IFLA_BRPORT_PRIORITY])
  139. fprintf(fp, "priority %hu ",
  140. rta_getattr_u16(prtb[IFLA_BRPORT_PRIORITY]));
  141. if (prtb[IFLA_BRPORT_COST])
  142. fprintf(fp, "cost %u ",
  143. rta_getattr_u32(prtb[IFLA_BRPORT_COST]));
  144. if (show_details) {
  145. fprintf(fp, "%s ", _SL_);
  146. if (prtb[IFLA_BRPORT_MODE])
  147. print_onoff(fp, "hairpin",
  148. rta_getattr_u8(prtb[IFLA_BRPORT_MODE]));
  149. if (prtb[IFLA_BRPORT_GUARD])
  150. print_onoff(fp, "guard",
  151. rta_getattr_u8(prtb[IFLA_BRPORT_GUARD]));
  152. if (prtb[IFLA_BRPORT_PROTECT])
  153. print_onoff(fp, "root_block",
  154. rta_getattr_u8(prtb[IFLA_BRPORT_PROTECT]));
  155. if (prtb[IFLA_BRPORT_FAST_LEAVE])
  156. print_onoff(fp, "fastleave",
  157. rta_getattr_u8(prtb[IFLA_BRPORT_FAST_LEAVE]));
  158. if (prtb[IFLA_BRPORT_LEARNING])
  159. print_onoff(fp, "learning",
  160. rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING]));
  161. if (prtb[IFLA_BRPORT_LEARNING_SYNC])
  162. print_onoff(fp, "learning_sync",
  163. rta_getattr_u8(prtb[IFLA_BRPORT_LEARNING_SYNC]));
  164. if (prtb[IFLA_BRPORT_UNICAST_FLOOD])
  165. print_onoff(fp, "flood",
  166. rta_getattr_u8(prtb[IFLA_BRPORT_UNICAST_FLOOD]));
  167. }
  168. } else
  169. print_portstate(fp, rta_getattr_u8(tb[IFLA_PROTINFO]));
  170. }
  171. if (tb[IFLA_AF_SPEC]) {
  172. /* This is reported by HW devices that have some bridging
  173. * capabilities.
  174. */
  175. struct rtattr *aftb[IFLA_BRIDGE_MAX+1];
  176. parse_rtattr_nested(aftb, IFLA_BRIDGE_MAX, tb[IFLA_AF_SPEC]);
  177. if (aftb[IFLA_BRIDGE_MODE])
  178. print_hwmode(fp, rta_getattr_u16(aftb[IFLA_BRIDGE_MODE]));
  179. }
  180. fprintf(fp, "\n");
  181. fflush(fp);
  182. return 0;
  183. }
  184. static void usage(void)
  185. {
  186. fprintf(stderr, "Usage: bridge link set dev DEV [ cost COST ] [ priority PRIO ] [ state STATE ]\n");
  187. fprintf(stderr, " [ guard {on | off} ]\n");
  188. fprintf(stderr, " [ hairpin {on | off} ] \n");
  189. fprintf(stderr, " [ fastleave {on | off} ]\n");
  190. fprintf(stderr, " [ root_block {on | off} ]\n");
  191. fprintf(stderr, " [ learning {on | off} ]\n");
  192. fprintf(stderr, " [ learning_sync {on | off} ]\n");
  193. fprintf(stderr, " [ flood {on | off} ]\n");
  194. fprintf(stderr, " [ hwmode {vepa | veb} ]\n");
  195. fprintf(stderr, " [ self ] [ master ]\n");
  196. fprintf(stderr, " bridge link show [dev DEV]\n");
  197. exit(-1);
  198. }
  199. static bool on_off(char *arg, __s8 *attr, char *val)
  200. {
  201. if (strcmp(val, "on") == 0)
  202. *attr = 1;
  203. else if (strcmp(val, "off") == 0)
  204. *attr = 0;
  205. else {
  206. fprintf(stderr,
  207. "Error: argument of \"%s\" must be \"on\" or \"off\"\n",
  208. arg);
  209. return false;
  210. }
  211. return true;
  212. }
  213. static int brlink_modify(int argc, char **argv)
  214. {
  215. struct {
  216. struct nlmsghdr n;
  217. struct ifinfomsg ifm;
  218. char buf[512];
  219. } req;
  220. char *d = NULL;
  221. __s8 learning = -1;
  222. __s8 learning_sync = -1;
  223. __s8 flood = -1;
  224. __s8 hairpin = -1;
  225. __s8 bpdu_guard = -1;
  226. __s8 fast_leave = -1;
  227. __s8 root_block = -1;
  228. __u32 cost = 0;
  229. __s16 priority = -1;
  230. __s8 state = -1;
  231. __s16 mode = -1;
  232. __u16 flags = 0;
  233. struct rtattr *nest;
  234. memset(&req, 0, sizeof(req));
  235. req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
  236. req.n.nlmsg_flags = NLM_F_REQUEST;
  237. req.n.nlmsg_type = RTM_SETLINK;
  238. req.ifm.ifi_family = PF_BRIDGE;
  239. while (argc > 0) {
  240. if (strcmp(*argv, "dev") == 0) {
  241. NEXT_ARG();
  242. d = *argv;
  243. } else if (strcmp(*argv, "guard") == 0) {
  244. NEXT_ARG();
  245. if (!on_off("guard", &bpdu_guard, *argv))
  246. return -1;
  247. } else if (strcmp(*argv, "hairpin") == 0) {
  248. NEXT_ARG();
  249. if (!on_off("hairping", &hairpin, *argv))
  250. return -1;
  251. } else if (strcmp(*argv, "fastleave") == 0) {
  252. NEXT_ARG();
  253. if (!on_off("fastleave", &fast_leave, *argv))
  254. return -1;
  255. } else if (strcmp(*argv, "root_block") == 0) {
  256. NEXT_ARG();
  257. if (!on_off("root_block", &root_block, *argv))
  258. return -1;
  259. } else if (strcmp(*argv, "learning") == 0) {
  260. NEXT_ARG();
  261. if (!on_off("learning", &learning, *argv))
  262. return -1;
  263. } else if (strcmp(*argv, "learning_sync") == 0) {
  264. NEXT_ARG();
  265. if (!on_off("learning_sync", &learning_sync, *argv))
  266. return -1;
  267. } else if (strcmp(*argv, "flood") == 0) {
  268. NEXT_ARG();
  269. if (!on_off("flood", &flood, *argv))
  270. return -1;
  271. } else if (strcmp(*argv, "cost") == 0) {
  272. NEXT_ARG();
  273. cost = atoi(*argv);
  274. } else if (strcmp(*argv, "priority") == 0) {
  275. NEXT_ARG();
  276. priority = atoi(*argv);
  277. } else if (strcmp(*argv, "state") == 0) {
  278. NEXT_ARG();
  279. char *endptr;
  280. size_t nstates = sizeof(port_states) / sizeof(*port_states);
  281. state = strtol(*argv, &endptr, 10);
  282. if (!(**argv != '\0' && *endptr == '\0')) {
  283. for (state = 0; state < nstates; state++)
  284. if (strcmp(port_states[state], *argv) == 0)
  285. break;
  286. if (state == nstates) {
  287. fprintf(stderr,
  288. "Error: invalid STP port state\n");
  289. return -1;
  290. }
  291. }
  292. } else if (strcmp(*argv, "hwmode") == 0) {
  293. NEXT_ARG();
  294. flags = BRIDGE_FLAGS_SELF;
  295. if (strcmp(*argv, "vepa") == 0)
  296. mode = BRIDGE_MODE_VEPA;
  297. else if (strcmp(*argv, "veb") == 0)
  298. mode = BRIDGE_MODE_VEB;
  299. else {
  300. fprintf(stderr,
  301. "Mode argument must be \"vepa\" or "
  302. "\"veb\".\n");
  303. return -1;
  304. }
  305. } else if (strcmp(*argv, "self") == 0) {
  306. flags |= BRIDGE_FLAGS_SELF;
  307. } else if (strcmp(*argv, "master") == 0) {
  308. flags |= BRIDGE_FLAGS_MASTER;
  309. } else {
  310. usage();
  311. }
  312. argc--; argv++;
  313. }
  314. if (d == NULL) {
  315. fprintf(stderr, "Device is a required argument.\n");
  316. return -1;
  317. }
  318. req.ifm.ifi_index = ll_name_to_index(d);
  319. if (req.ifm.ifi_index == 0) {
  320. fprintf(stderr, "Cannot find bridge device \"%s\"\n", d);
  321. return -1;
  322. }
  323. /* Nested PROTINFO attribute. Contains: port flags, cost, priority and
  324. * state.
  325. */
  326. nest = addattr_nest(&req.n, sizeof(req),
  327. IFLA_PROTINFO | NLA_F_NESTED);
  328. /* Flags first */
  329. if (bpdu_guard >= 0)
  330. addattr8(&req.n, sizeof(req), IFLA_BRPORT_GUARD, bpdu_guard);
  331. if (hairpin >= 0)
  332. addattr8(&req.n, sizeof(req), IFLA_BRPORT_MODE, hairpin);
  333. if (fast_leave >= 0)
  334. addattr8(&req.n, sizeof(req), IFLA_BRPORT_FAST_LEAVE,
  335. fast_leave);
  336. if (root_block >= 0)
  337. addattr8(&req.n, sizeof(req), IFLA_BRPORT_PROTECT, root_block);
  338. if (flood >= 0)
  339. addattr8(&req.n, sizeof(req), IFLA_BRPORT_UNICAST_FLOOD, flood);
  340. if (learning >= 0)
  341. addattr8(&req.n, sizeof(req), IFLA_BRPORT_LEARNING, learning);
  342. if (learning_sync >= 0)
  343. addattr8(&req.n, sizeof(req), IFLA_BRPORT_LEARNING_SYNC,
  344. learning_sync);
  345. if (cost > 0)
  346. addattr32(&req.n, sizeof(req), IFLA_BRPORT_COST, cost);
  347. if (priority >= 0)
  348. addattr16(&req.n, sizeof(req), IFLA_BRPORT_PRIORITY, priority);
  349. if (state >= 0)
  350. addattr8(&req.n, sizeof(req), IFLA_BRPORT_STATE, state);
  351. addattr_nest_end(&req.n, nest);
  352. /* IFLA_AF_SPEC nested attribute. Contains IFLA_BRIDGE_FLAGS that
  353. * designates master or self operation and IFLA_BRIDGE_MODE
  354. * for hw 'vepa' or 'veb' operation modes. The hwmodes are
  355. * only valid in 'self' mode on some devices so far.
  356. */
  357. if (mode >= 0 || flags > 0) {
  358. nest = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC);
  359. if (flags > 0)
  360. addattr16(&req.n, sizeof(req), IFLA_BRIDGE_FLAGS, flags);
  361. if (mode >= 0)
  362. addattr16(&req.n, sizeof(req), IFLA_BRIDGE_MODE, mode);
  363. addattr_nest_end(&req.n, nest);
  364. }
  365. if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
  366. return -1;
  367. return 0;
  368. }
  369. static int brlink_show(int argc, char **argv)
  370. {
  371. char *filter_dev = NULL;
  372. while (argc > 0) {
  373. if (strcmp(*argv, "dev") == 0) {
  374. NEXT_ARG();
  375. if (filter_dev)
  376. duparg("dev", *argv);
  377. filter_dev = *argv;
  378. }
  379. argc--; argv++;
  380. }
  381. if (filter_dev) {
  382. if ((filter_index = ll_name_to_index(filter_dev)) == 0) {
  383. fprintf(stderr, "Cannot find device \"%s\"\n",
  384. filter_dev);
  385. return -1;
  386. }
  387. }
  388. if (rtnl_wilddump_request(&rth, PF_BRIDGE, RTM_GETLINK) < 0) {
  389. perror("Cannon send dump request");
  390. exit(1);
  391. }
  392. if (rtnl_dump_filter(&rth, print_linkinfo, stdout) < 0) {
  393. fprintf(stderr, "Dump terminated\n");
  394. exit(1);
  395. }
  396. return 0;
  397. }
  398. int do_link(int argc, char **argv)
  399. {
  400. ll_init_map(&rth);
  401. if (argc > 0) {
  402. if (matches(*argv, "set") == 0 ||
  403. matches(*argv, "change") == 0)
  404. return brlink_modify(argc-1, argv+1);
  405. if (matches(*argv, "show") == 0 ||
  406. matches(*argv, "lst") == 0 ||
  407. matches(*argv, "list") == 0)
  408. return brlink_show(argc-1, argv+1);
  409. if (matches(*argv, "help") == 0)
  410. usage();
  411. } else
  412. return brlink_show(0, NULL);
  413. fprintf(stderr, "Command \"%s\" is unknown, try \"bridge link help\".\n", *argv);
  414. exit(-1);
  415. }