iplink.c 18 KB

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