iplink.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  4. * Patrick McHardy <kaber@trash.net>
  5. *
  6. * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  7. */
  8. #include <net/if.h>
  9. /*#include <net/if_packet.h> - not needed? */
  10. #include <netpacket/packet.h>
  11. #include <netinet/if_ether.h>
  12. #include <linux/if_vlan.h>
  13. #include "ip_common.h" /* #include "libbb.h" is inside */
  14. #include "rt_names.h"
  15. #include "utils.h"
  16. #undef ETH_P_8021AD
  17. #define ETH_P_8021AD 0x88A8
  18. #undef VLAN_FLAG_REORDER_HDR
  19. #define VLAN_FLAG_REORDER_HDR 0x1
  20. #undef VLAN_FLAG_GVRP
  21. #define VLAN_FLAG_GVRP 0x2
  22. #undef VLAN_FLAG_LOOSE_BINDING
  23. #define VLAN_FLAG_LOOSE_BINDING 0x4
  24. #undef VLAN_FLAG_MVRP
  25. #define VLAN_FLAG_MVRP 0x8
  26. #undef IFLA_VLAN_PROTOCOL
  27. #define IFLA_VLAN_PROTOCOL 5
  28. #ifndef IFLA_LINKINFO
  29. # define IFLA_LINKINFO 18
  30. # define IFLA_INFO_KIND 1
  31. # define IFLA_INFO_DATA 2
  32. #endif
  33. #ifndef IFLA_VLAN_MAX
  34. # define IFLA_VLAN_ID 1
  35. # define IFLA_VLAN_FLAGS 2
  36. struct ifla_vlan_flags {
  37. uint32_t flags;
  38. uint32_t mask;
  39. };
  40. #endif
  41. /* taken from linux/sockios.h */
  42. #define SIOCSIFNAME 0x8923 /* set interface name */
  43. #if 0
  44. # define dbg(...) bb_error_msg(__VA_ARGS__)
  45. #else
  46. # define dbg(...) ((void)0)
  47. #endif
  48. #define str_on_off "on\0""off\0"
  49. /* Exits on error */
  50. static int get_ctl_fd(void)
  51. {
  52. int fd;
  53. fd = socket(PF_INET, SOCK_DGRAM, 0);
  54. if (fd >= 0)
  55. return fd;
  56. fd = socket(PF_PACKET, SOCK_DGRAM, 0);
  57. if (fd >= 0)
  58. return fd;
  59. return xsocket(PF_INET6, SOCK_DGRAM, 0);
  60. }
  61. /* Exits on error */
  62. static void do_chflags(char *dev, uint32_t flags, uint32_t mask)
  63. {
  64. struct ifreq ifr;
  65. int fd;
  66. strncpy_IFNAMSIZ(ifr.ifr_name, dev);
  67. fd = get_ctl_fd();
  68. xioctl(fd, SIOCGIFFLAGS, &ifr);
  69. if ((ifr.ifr_flags ^ flags) & mask) {
  70. ifr.ifr_flags &= ~mask;
  71. ifr.ifr_flags |= mask & flags;
  72. xioctl(fd, SIOCSIFFLAGS, &ifr);
  73. }
  74. close(fd);
  75. }
  76. /* Exits on error */
  77. static void do_changename(char *dev, char *newdev)
  78. {
  79. struct ifreq ifr;
  80. int fd;
  81. strncpy_IFNAMSIZ(ifr.ifr_name, dev);
  82. strncpy_IFNAMSIZ(ifr.ifr_newname, newdev);
  83. fd = get_ctl_fd();
  84. xioctl(fd, SIOCSIFNAME, &ifr);
  85. close(fd);
  86. }
  87. /* Exits on error */
  88. static void set_qlen(char *dev, int qlen)
  89. {
  90. struct ifreq ifr;
  91. int s;
  92. s = get_ctl_fd();
  93. memset(&ifr, 0, sizeof(ifr));
  94. strncpy_IFNAMSIZ(ifr.ifr_name, dev);
  95. ifr.ifr_qlen = qlen;
  96. xioctl(s, SIOCSIFTXQLEN, &ifr);
  97. close(s);
  98. }
  99. /* Exits on error */
  100. static void set_mtu(char *dev, int mtu)
  101. {
  102. struct ifreq ifr;
  103. int s;
  104. s = get_ctl_fd();
  105. memset(&ifr, 0, sizeof(ifr));
  106. strncpy_IFNAMSIZ(ifr.ifr_name, dev);
  107. ifr.ifr_mtu = mtu;
  108. xioctl(s, SIOCSIFMTU, &ifr);
  109. close(s);
  110. }
  111. /* Exits on error */
  112. static void set_master(char *dev, int master)
  113. {
  114. struct rtnl_handle rth;
  115. struct {
  116. struct nlmsghdr n;
  117. struct ifinfomsg i;
  118. char buf[1024];
  119. } req;
  120. memset(&req, 0, sizeof(req));
  121. req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
  122. req.n.nlmsg_flags = NLM_F_REQUEST;
  123. req.n.nlmsg_type = RTM_NEWLINK;
  124. req.i.ifi_family = preferred_family;
  125. xrtnl_open(&rth);
  126. req.i.ifi_index = xll_name_to_index(dev);
  127. //printf("master %i for %i\n", master, req.i.ifi_index);
  128. addattr_l(&req.n, sizeof(req), IFLA_MASTER, &master, 4);
  129. if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
  130. xfunc_die();
  131. }
  132. /* Exits on error */
  133. static void set_netns(char *dev, int netns)
  134. {
  135. struct rtnl_handle rth;
  136. struct {
  137. struct nlmsghdr n;
  138. struct ifinfomsg i;
  139. char buf[1024];
  140. } req;
  141. memset(&req, 0, sizeof(req));
  142. req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
  143. req.n.nlmsg_flags = NLM_F_REQUEST;
  144. req.n.nlmsg_type = RTM_NEWLINK;
  145. req.i.ifi_family = preferred_family;
  146. xrtnl_open(&rth);
  147. req.i.ifi_index = xll_name_to_index(dev);
  148. //printf("netns %i for %i\n", netns, req.i.ifi_index);
  149. addattr_l(&req.n, sizeof(req), IFLA_NET_NS_PID, &netns, 4);
  150. if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
  151. xfunc_die();
  152. }
  153. /* Exits on error */
  154. static int get_address(char *dev, int *htype)
  155. {
  156. struct ifreq ifr;
  157. struct sockaddr_ll me;
  158. int s;
  159. s = xsocket(PF_PACKET, SOCK_DGRAM, 0);
  160. /*memset(&ifr, 0, sizeof(ifr)); - SIOCGIFINDEX does not need to clear all */
  161. strncpy_IFNAMSIZ(ifr.ifr_name, dev);
  162. xioctl(s, SIOCGIFINDEX, &ifr);
  163. memset(&me, 0, sizeof(me));
  164. me.sll_family = AF_PACKET;
  165. me.sll_ifindex = ifr.ifr_ifindex;
  166. me.sll_protocol = htons(ETH_P_LOOP);
  167. xbind(s, (struct sockaddr*)&me, sizeof(me));
  168. bb_getsockname(s, (struct sockaddr*)&me, sizeof(me));
  169. //never happens:
  170. //if (getsockname(s, (struct sockaddr*)&me, &alen) == -1)
  171. // bb_perror_msg_and_die("getsockname");
  172. close(s);
  173. *htype = me.sll_hatype;
  174. return me.sll_halen;
  175. }
  176. /* Exits on error */
  177. static void parse_address(char *dev, int hatype, int halen, char *lla, struct ifreq *ifr)
  178. {
  179. int alen;
  180. memset(ifr, 0, sizeof(*ifr));
  181. strncpy_IFNAMSIZ(ifr->ifr_name, dev);
  182. ifr->ifr_hwaddr.sa_family = hatype;
  183. alen = hatype == 1/*ARPHRD_ETHER*/ ? 14/*ETH_HLEN*/ : 19/*INFINIBAND_HLEN*/;
  184. alen = ll_addr_a2n((unsigned char *)(ifr->ifr_hwaddr.sa_data), alen, lla);
  185. if (alen < 0)
  186. exit(EXIT_FAILURE);
  187. if (alen != halen) {
  188. bb_error_msg_and_die("wrong address (%s) length: expected %d bytes", lla, halen);
  189. }
  190. }
  191. /* Exits on error */
  192. static void set_address(struct ifreq *ifr, int brd)
  193. {
  194. int s;
  195. s = get_ctl_fd();
  196. if (brd)
  197. xioctl(s, SIOCSIFHWBROADCAST, ifr);
  198. else
  199. xioctl(s, SIOCSIFHWADDR, ifr);
  200. close(s);
  201. }
  202. static void die_must_be_on_off(const char *msg) NORETURN;
  203. static void die_must_be_on_off(const char *msg)
  204. {
  205. bb_error_msg_and_die("argument of \"%s\" must be \"on\" or \"off\"", msg);
  206. }
  207. /* Return value becomes exitcode. It's okay to not return at all */
  208. static int do_set(char **argv)
  209. {
  210. char *dev = NULL;
  211. uint32_t mask = 0;
  212. uint32_t flags = 0;
  213. int qlen = -1;
  214. int mtu = -1;
  215. int master = -1;
  216. int netns = -1;
  217. char *newaddr = NULL;
  218. char *newbrd = NULL;
  219. struct ifreq ifr0, ifr1;
  220. char *newname = NULL;
  221. int htype, halen;
  222. /* If you add stuff here, update iplink_full_usage */
  223. static const char keywords[] ALIGN1 =
  224. "up\0""down\0""name\0""mtu\0""qlen\0""multicast\0"
  225. "arp\0""promisc\0""address\0""netns\0"
  226. "master\0""nomaster\0"
  227. "dev\0" /* must be last */;
  228. enum { ARG_up = 0, ARG_down, ARG_name, ARG_mtu, ARG_qlen, ARG_multicast,
  229. ARG_arp, ARG_promisc, ARG_addr, ARG_netns,
  230. ARG_master, ARG_nomaster,
  231. ARG_dev };
  232. enum { PARM_on = 0, PARM_off };
  233. smalluint key;
  234. while (*argv) {
  235. /* substring search ensures that e.g. "addr" and "address"
  236. * are both accepted */
  237. key = index_in_substrings(keywords, *argv);
  238. if (key == ARG_up) {
  239. mask |= IFF_UP;
  240. flags |= IFF_UP;
  241. } else if (key == ARG_down) {
  242. mask |= IFF_UP;
  243. flags &= ~IFF_UP;
  244. } else if (key == ARG_name) {
  245. NEXT_ARG();
  246. newname = *argv;
  247. } else if (key == ARG_mtu) {
  248. NEXT_ARG();
  249. if (mtu != -1)
  250. duparg("mtu", *argv);
  251. mtu = get_unsigned(*argv, "mtu");
  252. } else if (key == ARG_qlen) {
  253. //TODO: txqueuelen, txqlen are synonyms to qlen
  254. NEXT_ARG();
  255. if (qlen != -1)
  256. duparg("qlen", *argv);
  257. qlen = get_unsigned(*argv, "qlen");
  258. } else if (key == ARG_addr) {
  259. NEXT_ARG();
  260. newaddr = *argv;
  261. } else if (key == ARG_master) {
  262. NEXT_ARG();
  263. master = xll_name_to_index(*argv);
  264. } else if (key == ARG_nomaster) {
  265. master = 0;
  266. } else if (key == ARG_netns) {
  267. NEXT_ARG();
  268. netns = get_unsigned(*argv, "netns");
  269. } else if (key >= ARG_dev) {
  270. /* ^^^^^^ ">=" here results in "dev IFACE" treated as default */
  271. if (key == ARG_dev) {
  272. NEXT_ARG();
  273. }
  274. if (dev)
  275. duparg2("dev", *argv);
  276. dev = *argv;
  277. } else {
  278. /* "on|off" options */
  279. int param;
  280. NEXT_ARG();
  281. param = index_in_strings(str_on_off, *argv);
  282. if (key == ARG_multicast) {
  283. if (param < 0)
  284. die_must_be_on_off("multicast");
  285. mask |= IFF_MULTICAST;
  286. if (param == PARM_on)
  287. flags |= IFF_MULTICAST;
  288. else
  289. flags &= ~IFF_MULTICAST;
  290. } else if (key == ARG_arp) {
  291. if (param < 0)
  292. die_must_be_on_off("arp");
  293. mask |= IFF_NOARP;
  294. if (param == PARM_on)
  295. flags &= ~IFF_NOARP;
  296. else
  297. flags |= IFF_NOARP;
  298. } else if (key == ARG_promisc) {
  299. if (param < 0)
  300. die_must_be_on_off("promisc");
  301. mask |= IFF_PROMISC;
  302. if (param == PARM_on)
  303. flags |= IFF_PROMISC;
  304. else
  305. flags &= ~IFF_PROMISC;
  306. }
  307. }
  308. /* Other keywords recognized by iproute2-3.12.0: */
  309. #if 0
  310. } else if (matches(*argv, "broadcast") == 0 ||
  311. strcmp(*argv, "brd") == 0) {
  312. NEXT_ARG();
  313. len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
  314. if (len < 0)
  315. return -1;
  316. addattr_l(&req->n, sizeof(*req), IFLA_BROADCAST, abuf, len);
  317. } else if (strcmp(*argv, "netns") == 0) {
  318. NEXT_ARG();
  319. if (netns != -1)
  320. duparg("netns", *argv);
  321. if ((netns = get_netns_fd(*argv)) >= 0)
  322. addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_FD, &netns, 4);
  323. else if (get_integer(&netns, *argv, 0) == 0)
  324. addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID, &netns, 4);
  325. else
  326. invarg_1_to_2(*argv, "netns");
  327. } else if (strcmp(*argv, "allmulticast") == 0) {
  328. NEXT_ARG();
  329. req->i.ifi_change |= IFF_ALLMULTI;
  330. if (strcmp(*argv, "on") == 0) {
  331. req->i.ifi_flags |= IFF_ALLMULTI;
  332. } else if (strcmp(*argv, "off") == 0) {
  333. req->i.ifi_flags &= ~IFF_ALLMULTI;
  334. } else
  335. return on_off("allmulticast", *argv);
  336. } else if (strcmp(*argv, "trailers") == 0) {
  337. NEXT_ARG();
  338. req->i.ifi_change |= IFF_NOTRAILERS;
  339. if (strcmp(*argv, "off") == 0) {
  340. req->i.ifi_flags |= IFF_NOTRAILERS;
  341. } else if (strcmp(*argv, "on") == 0) {
  342. req->i.ifi_flags &= ~IFF_NOTRAILERS;
  343. } else
  344. return on_off("trailers", *argv);
  345. } else if (strcmp(*argv, "vf") == 0) {
  346. struct rtattr *vflist;
  347. NEXT_ARG();
  348. if (get_integer(&vf, *argv, 0)) {
  349. invarg_1_to_2(*argv, "vf");
  350. }
  351. vflist = addattr_nest(&req->n, sizeof(*req),
  352. IFLA_VFINFO_LIST);
  353. len = iplink_parse_vf(vf, &argc, &argv, req);
  354. if (len < 0)
  355. return -1;
  356. addattr_nest_end(&req->n, vflist);
  357. } else if (matches(*argv, "master") == 0) {
  358. int ifindex;
  359. NEXT_ARG();
  360. ifindex = ll_name_to_index(*argv);
  361. if (!ifindex)
  362. invarg_1_to_2(*argv, "master");
  363. addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
  364. &ifindex, 4);
  365. } else if (matches(*argv, "nomaster") == 0) {
  366. int ifindex = 0;
  367. addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
  368. &ifindex, 4);
  369. } else if (matches(*argv, "dynamic") == 0) {
  370. NEXT_ARG();
  371. req->i.ifi_change |= IFF_DYNAMIC;
  372. if (strcmp(*argv, "on") == 0) {
  373. req->i.ifi_flags |= IFF_DYNAMIC;
  374. } else if (strcmp(*argv, "off") == 0) {
  375. req->i.ifi_flags &= ~IFF_DYNAMIC;
  376. } else
  377. return on_off("dynamic", *argv);
  378. } else if (matches(*argv, "alias") == 0) {
  379. NEXT_ARG();
  380. addattr_l(&req->n, sizeof(*req), IFLA_IFALIAS,
  381. *argv, strlen(*argv));
  382. argc--; argv++;
  383. break;
  384. } else if (strcmp(*argv, "group") == 0) {
  385. NEXT_ARG();
  386. if (*group != -1)
  387. duparg("group", *argv);
  388. if (rtnl_group_a2n(group, *argv))
  389. invarg_1_to_2(*argv, "group");
  390. } else if (strcmp(*argv, "mode") == 0) {
  391. int mode;
  392. NEXT_ARG();
  393. mode = get_link_mode(*argv);
  394. if (mode < 0)
  395. invarg_1_to_2(*argv, "mode");
  396. addattr8(&req->n, sizeof(*req), IFLA_LINKMODE, mode);
  397. } else if (strcmp(*argv, "state") == 0) {
  398. int state;
  399. NEXT_ARG();
  400. state = get_operstate(*argv);
  401. if (state < 0)
  402. invarg_1_to_2(*argv, "state");
  403. addattr8(&req->n, sizeof(*req), IFLA_OPERSTATE, state);
  404. } else if (matches(*argv, "numtxqueues") == 0) {
  405. NEXT_ARG();
  406. if (numtxqueues != -1)
  407. duparg("numtxqueues", *argv);
  408. if (get_integer(&numtxqueues, *argv, 0))
  409. invarg_1_to_2(*argv, "numtxqueues");
  410. addattr_l(&req->n, sizeof(*req), IFLA_NUM_TX_QUEUES,
  411. &numtxqueues, 4);
  412. } else if (matches(*argv, "numrxqueues") == 0) {
  413. NEXT_ARG();
  414. if (numrxqueues != -1)
  415. duparg("numrxqueues", *argv);
  416. if (get_integer(&numrxqueues, *argv, 0))
  417. invarg_1_to_2(*argv, "numrxqueues");
  418. addattr_l(&req->n, sizeof(*req), IFLA_NUM_RX_QUEUES,
  419. &numrxqueues, 4);
  420. }
  421. #endif
  422. argv++;
  423. }
  424. if (!dev) {
  425. bb_error_msg_and_die(bb_msg_requires_arg, "\"dev\"");
  426. }
  427. if (newaddr || newbrd) {
  428. halen = get_address(dev, &htype);
  429. if (newaddr) {
  430. parse_address(dev, htype, halen, newaddr, &ifr0);
  431. set_address(&ifr0, 0);
  432. }
  433. if (newbrd) {
  434. parse_address(dev, htype, halen, newbrd, &ifr1);
  435. set_address(&ifr1, 1);
  436. }
  437. }
  438. if (newname && strcmp(dev, newname)) {
  439. do_changename(dev, newname);
  440. dev = newname;
  441. }
  442. if (qlen != -1) {
  443. set_qlen(dev, qlen);
  444. }
  445. if (mtu != -1) {
  446. set_mtu(dev, mtu);
  447. }
  448. if (master != -1) {
  449. set_master(dev, master);
  450. }
  451. if (netns != -1) {
  452. set_netns(dev, netns);
  453. }
  454. if (mask)
  455. do_chflags(dev, flags, mask);
  456. return 0;
  457. }
  458. static int ipaddr_list_link(char **argv)
  459. {
  460. preferred_family = AF_PACKET;
  461. return ipaddr_list_or_flush(argv, 0);
  462. }
  463. static void vlan_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size)
  464. {
  465. static const char keywords[] ALIGN1 =
  466. "id\0"
  467. "protocol\0"
  468. "reorder_hdr\0"
  469. "gvrp\0"
  470. "mvrp\0"
  471. "loose_binding\0"
  472. ;
  473. static const char protocols[] ALIGN1 =
  474. "802.1q\0"
  475. "802.1ad\0"
  476. ;
  477. enum {
  478. ARG_id = 0,
  479. ARG_protocol,
  480. ARG_reorder_hdr,
  481. ARG_gvrp,
  482. ARG_mvrp,
  483. ARG_loose_binding,
  484. };
  485. enum {
  486. PROTO_8021Q = 0,
  487. PROTO_8021AD,
  488. };
  489. enum {
  490. PARM_on = 0,
  491. PARM_off
  492. };
  493. int arg;
  494. uint16_t id, proto;
  495. struct ifla_vlan_flags flags = {};
  496. while (*argv) {
  497. arg = index_in_substrings(keywords, *argv);
  498. if (arg < 0)
  499. invarg_1_to_2(*argv, "type vlan");
  500. NEXT_ARG();
  501. if (arg == ARG_id) {
  502. id = get_u16(*argv, "id");
  503. addattr_l(n, size, IFLA_VLAN_ID, &id, sizeof(id));
  504. } else if (arg == ARG_protocol) {
  505. arg = index_in_substrings(protocols, str_tolower(*argv));
  506. if (arg == PROTO_8021Q)
  507. proto = htons(ETH_P_8021Q);
  508. else if (arg == PROTO_8021AD)
  509. proto = htons(ETH_P_8021AD);
  510. else
  511. bb_error_msg_and_die("unknown VLAN encapsulation protocol '%s'",
  512. *argv);
  513. addattr_l(n, size, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));
  514. } else {
  515. int param = index_in_strings(str_on_off, *argv);
  516. if (param < 0)
  517. die_must_be_on_off(nth_string(keywords, arg));
  518. if (arg == ARG_reorder_hdr) {
  519. flags.mask |= VLAN_FLAG_REORDER_HDR;
  520. flags.flags &= ~VLAN_FLAG_REORDER_HDR;
  521. if (param == PARM_on)
  522. flags.flags |= VLAN_FLAG_REORDER_HDR;
  523. } else if (arg == ARG_gvrp) {
  524. flags.mask |= VLAN_FLAG_GVRP;
  525. flags.flags &= ~VLAN_FLAG_GVRP;
  526. if (param == PARM_on)
  527. flags.flags |= VLAN_FLAG_GVRP;
  528. } else if (arg == ARG_mvrp) {
  529. flags.mask |= VLAN_FLAG_MVRP;
  530. flags.flags &= ~VLAN_FLAG_MVRP;
  531. if (param == PARM_on)
  532. flags.flags |= VLAN_FLAG_MVRP;
  533. } else { /*if (arg == ARG_loose_binding) */
  534. flags.mask |= VLAN_FLAG_LOOSE_BINDING;
  535. flags.flags &= ~VLAN_FLAG_LOOSE_BINDING;
  536. if (param == PARM_on)
  537. flags.flags |= VLAN_FLAG_LOOSE_BINDING;
  538. }
  539. }
  540. argv++;
  541. }
  542. if (flags.mask)
  543. addattr_l(n, size, IFLA_VLAN_FLAGS, &flags, sizeof(flags));
  544. }
  545. static void vrf_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size)
  546. {
  547. /* IFLA_VRF_TABLE is an enum, not a define -
  548. * can't test "defined(IFLA_VRF_TABLE)".
  549. */
  550. #if !defined(IFLA_VRF_MAX)
  551. # define IFLA_VRF_TABLE 1
  552. #endif
  553. uint32_t table;
  554. if (strcmp(*argv, "table") != 0)
  555. invarg_1_to_2(*argv, "type vrf");
  556. NEXT_ARG();
  557. table = get_u32(*argv, "table");
  558. addattr_l(n, size, IFLA_VRF_TABLE, &table, sizeof(table));
  559. }
  560. #ifndef NLMSG_TAIL
  561. #define NLMSG_TAIL(nmsg) \
  562. ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
  563. #endif
  564. /* Return value becomes exitcode. It's okay to not return at all */
  565. static int do_add_or_delete(char **argv, const unsigned rtm)
  566. {
  567. static const char keywords[] ALIGN1 =
  568. "link\0""name\0""type\0""dev\0""address\0";
  569. enum {
  570. ARG_link,
  571. ARG_name,
  572. ARG_type,
  573. ARG_dev,
  574. ARG_address,
  575. };
  576. struct rtnl_handle rth;
  577. struct {
  578. struct nlmsghdr n;
  579. struct ifinfomsg i;
  580. char buf[1024];
  581. } req;
  582. smalluint arg;
  583. char *name_str = NULL;
  584. char *link_str = NULL;
  585. char *type_str = NULL;
  586. char *dev_str = NULL;
  587. char *address_str = NULL;
  588. memset(&req, 0, sizeof(req));
  589. req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
  590. req.n.nlmsg_flags = NLM_F_REQUEST;
  591. req.n.nlmsg_type = rtm;
  592. req.i.ifi_family = preferred_family;
  593. if (rtm == RTM_NEWLINK)
  594. req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
  595. /* NB: update iplink_full_usage if you extend this code */
  596. while (*argv) {
  597. arg = index_in_substrings(keywords, *argv);
  598. if (arg == ARG_type) {
  599. NEXT_ARG();
  600. type_str = *argv++;
  601. dbg("type_str:'%s'", type_str);
  602. break;
  603. }
  604. if (arg == ARG_link) {
  605. NEXT_ARG();
  606. link_str = *argv;
  607. dbg("link_str:'%s'", link_str);
  608. } else if (arg == ARG_name) {
  609. NEXT_ARG();
  610. name_str = *argv;
  611. dbg("name_str:'%s'", name_str);
  612. } else if (arg == ARG_address) {
  613. NEXT_ARG();
  614. address_str = *argv;
  615. dbg("address_str:'%s'", address_str);
  616. } else {
  617. if (arg == ARG_dev) {
  618. if (dev_str)
  619. duparg(*argv, "dev");
  620. NEXT_ARG();
  621. }
  622. dev_str = *argv;
  623. dbg("dev_str:'%s'", dev_str);
  624. }
  625. argv++;
  626. }
  627. xrtnl_open(&rth);
  628. ll_init_map(&rth);
  629. if (type_str) {
  630. struct rtattr *linkinfo = NLMSG_TAIL(&req.n);
  631. addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
  632. addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type_str,
  633. strlen(type_str));
  634. if (*argv) {
  635. struct rtattr *data = NLMSG_TAIL(&req.n);
  636. addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0);
  637. if (strcmp(type_str, "vlan") == 0)
  638. vlan_parse_opt(argv, &req.n, sizeof(req));
  639. else if (strcmp(type_str, "vrf") == 0)
  640. vrf_parse_opt(argv, &req.n, sizeof(req));
  641. data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;
  642. }
  643. linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
  644. }
  645. /* Allow "ip link add dev" and "ip link add name" */
  646. if (!name_str)
  647. name_str = dev_str;
  648. else if (!dev_str)
  649. dev_str = name_str;
  650. /* else if (!strcmp(name_str, dev_str))
  651. name_str = dev_str; */
  652. if (rtm != RTM_NEWLINK) {
  653. if (!dev_str)
  654. return 1; /* Need a device to delete */
  655. req.i.ifi_index = xll_name_to_index(dev_str);
  656. } else {
  657. if (link_str) {
  658. int idx = xll_name_to_index(link_str);
  659. addattr_l(&req.n, sizeof(req), IFLA_LINK, &idx, 4);
  660. }
  661. if (address_str) {
  662. unsigned char abuf[32];
  663. int len = ll_addr_a2n(abuf, sizeof(abuf), address_str);
  664. dbg("address len:%d", len);
  665. if (len < 0)
  666. return -1;
  667. addattr_l(&req.n, sizeof(req), IFLA_ADDRESS, abuf, len);
  668. }
  669. }
  670. if (name_str) {
  671. const size_t name_len = strlen(name_str) + 1;
  672. if (name_len < 2 || name_len > IFNAMSIZ)
  673. invarg_1_to_2(name_str, "name");
  674. addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name_str, name_len);
  675. }
  676. if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
  677. return 2;
  678. return 0;
  679. }
  680. /* Return value becomes exitcode. It's okay to not return at all */
  681. int FAST_FUNC do_iplink(char **argv)
  682. {
  683. static const char keywords[] ALIGN1 =
  684. "add\0""delete\0""set\0""show\0""lst\0""list\0";
  685. xfunc_error_retval = 2; //TODO: move up to "ip"? Is it the common rule for all "ip" tools?
  686. if (*argv) {
  687. int key = index_in_substrings(keywords, *argv);
  688. if (key < 0) /* invalid argument */
  689. invarg_1_to_2(*argv, applet_name);
  690. argv++;
  691. if (key <= 1) /* add/delete */
  692. return do_add_or_delete(argv, key ? RTM_DELLINK : RTM_NEWLINK);
  693. if (key == 2) /* set */
  694. return do_set(argv);
  695. }
  696. /* show, lst, list */
  697. return ipaddr_list_link(argv);
  698. }