1 /*
2 * iplink.c "ip link".
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
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10 *
11 */
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <syslog.h>
17 #include <fcntl.h>
18 #include <dlfcn.h>
19 #include <errno.h>
20 #include <sys/socket.h>
21 #include <linux/if.h>
22 #include <linux/if_packet.h>
23 #include <linux/if_ether.h>
24 #include <linux/sockios.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 #include <string.h>
28 #include <sys/ioctl.h>
29 #include <linux/sockios.h>
30 #include <stdbool.h>
31
32 #include "rt_names.h"
33 #include "utils.h"
34 #include "ip_common.h"
35 #include "namespace.h"
36
37 #define IPLINK_IOCTL_COMPAT 1
38 #ifndef LIBDIR
39 #define LIBDIR "/usr/lib"
40 #endif
41
42 static void usage(void) __attribute__((noreturn));
43 static int iplink_have_newlink(void);
44
iplink_usage(void)45 void iplink_usage(void)
46 {
47 if (iplink_have_newlink()) {
48 fprintf(stderr, "Usage: ip link add [link DEV] [ name ] NAME\n");
49 fprintf(stderr, " [ txqueuelen PACKETS ]\n");
50 fprintf(stderr, " [ address LLADDR ]\n");
51 fprintf(stderr, " [ broadcast LLADDR ]\n");
52 fprintf(stderr, " [ mtu MTU ] [index IDX ]\n");
53 fprintf(stderr, " [ numtxqueues QUEUE_COUNT ]\n");
54 fprintf(stderr, " [ numrxqueues QUEUE_COUNT ]\n");
55 fprintf(stderr, " type TYPE [ ARGS ]\n");
56 fprintf(stderr, " ip link delete { DEVICE | dev DEVICE | group DEVGROUP } type TYPE [ ARGS ]\n");
57 fprintf(stderr, "\n");
58 fprintf(stderr, " ip link set { DEVICE | dev DEVICE | group DEVGROUP } [ { up | down } ]\n");
59 } else
60 fprintf(stderr, "Usage: ip link set DEVICE [ { up | down } ]\n");
61
62 fprintf(stderr, " [ arp { on | off } ]\n");
63 fprintf(stderr, " [ dynamic { on | off } ]\n");
64 fprintf(stderr, " [ multicast { on | off } ]\n");
65 fprintf(stderr, " [ allmulticast { on | off } ]\n");
66 fprintf(stderr, " [ promisc { on | off } ]\n");
67 fprintf(stderr, " [ trailers { on | off } ]\n");
68 fprintf(stderr, " [ txqueuelen PACKETS ]\n");
69 fprintf(stderr, " [ name NEWNAME ]\n");
70 fprintf(stderr, " [ address LLADDR ]\n");
71 fprintf(stderr, " [ broadcast LLADDR ]\n");
72 fprintf(stderr, " [ mtu MTU ]\n");
73 fprintf(stderr, " [ netns PID ]\n");
74 fprintf(stderr, " [ netns NAME ]\n");
75 fprintf(stderr, " [ link-netnsid ID ]\n");
76 fprintf(stderr, " [ alias NAME ]\n");
77 fprintf(stderr, " [ vf NUM [ mac LLADDR ]\n");
78 fprintf(stderr, " [ vlan VLANID [ qos VLAN-QOS ] ]\n");
79
80 fprintf(stderr, " [ rate TXRATE ] ]\n");
81
82 fprintf(stderr, " [ spoofchk { on | off} ] ]\n");
83 fprintf(stderr, " [ query_rss { on | off} ] ]\n");
84 fprintf(stderr, " [ state { auto | enable | disable} ] ]\n");
85 fprintf(stderr, " [ master DEVICE ]\n");
86 fprintf(stderr, " [ nomaster ]\n");
87 fprintf(stderr, " [ addrgenmode { eui64 | none | stable_secret | random } ]\n");
88 fprintf(stderr, " [ protodown { on | off } ]\n");
89 fprintf(stderr, " ip link show [ DEVICE | group GROUP ] [up] [master DEV] [type TYPE]\n");
90
91 if (iplink_have_newlink()) {
92 fprintf(stderr, " ip link help [ TYPE ]\n");
93 fprintf(stderr, "\n");
94 fprintf(stderr, "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap |\n");
95 fprintf(stderr, " bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |\n");
96 fprintf(stderr, " gre | gretap | ip6gre | ip6gretap | vti | nlmon |\n");
97 fprintf(stderr, " bond_slave | ipvlan | geneve | bridge_slave | vrf }\n");
98 }
99 exit(-1);
100 }
101
usage(void)102 static void usage(void)
103 {
104 iplink_usage();
105 }
106
on_off(const char * msg,const char * realval)107 static int on_off(const char *msg, const char *realval)
108 {
109 fprintf(stderr,
110 "Error: argument of \"%s\" must be \"on\" or \"off\", not \"%s\"\n",
111 msg, realval);
112 return -1;
113 }
114
115 static void *BODY; /* cached dlopen(NULL) handle */
116 static struct link_util *linkutil_list;
117
__get_link_kind(const char * id,bool slave)118 static struct link_util *__get_link_kind(const char *id, bool slave)
119 {
120 void *dlh;
121 char buf[256];
122 struct link_util *l;
123
124 for (l = linkutil_list; l; l = l->next)
125 if (strcmp(l->id, id) == 0 &&
126 l->slave == slave)
127 return l;
128
129 snprintf(buf, sizeof(buf), LIBDIR "/ip/link_%s.so", id);
130 dlh = dlopen(buf, RTLD_LAZY);
131 if (dlh == NULL) {
132 /* look in current binary, only open once */
133 dlh = BODY;
134 if (dlh == NULL) {
135 dlh = BODY = dlopen(NULL, RTLD_LAZY);
136 if (dlh == NULL)
137 return NULL;
138 }
139 }
140
141 if (slave)
142 snprintf(buf, sizeof(buf), "%s_slave_link_util", id);
143 else
144 snprintf(buf, sizeof(buf), "%s_link_util", id);
145 l = dlsym(dlh, buf);
146 if (l == NULL)
147 return NULL;
148
149 l->next = linkutil_list;
150 linkutil_list = l;
151 return l;
152 }
153
get_link_kind(const char * id)154 struct link_util *get_link_kind(const char *id)
155 {
156 return __get_link_kind(id, false);
157 }
158
get_link_slave_kind(const char * id)159 struct link_util *get_link_slave_kind(const char *id)
160 {
161 return __get_link_kind(id, true);
162 }
163
get_link_mode(const char * mode)164 static int get_link_mode(const char *mode)
165 {
166 if (strcasecmp(mode, "default") == 0)
167 return IF_LINK_MODE_DEFAULT;
168 if (strcasecmp(mode, "dormant") == 0)
169 return IF_LINK_MODE_DORMANT;
170 return -1;
171 }
172
get_addr_gen_mode(const char * mode)173 static int get_addr_gen_mode(const char *mode)
174 {
175 if (strcasecmp(mode, "eui64") == 0)
176 return IN6_ADDR_GEN_MODE_EUI64;
177 if (strcasecmp(mode, "none") == 0)
178 return IN6_ADDR_GEN_MODE_NONE;
179 if (strcasecmp(mode, "stable_secret") == 0)
180 return IN6_ADDR_GEN_MODE_STABLE_PRIVACY;
181 if (strcasecmp(mode, "random") == 0)
182 return IN6_ADDR_GEN_MODE_RANDOM;
183 return -1;
184 }
185
186 #if IPLINK_IOCTL_COMPAT
187 static int have_rtnl_newlink = -1;
188
accept_msg(const struct sockaddr_nl * who,struct rtnl_ctrl_data * ctrl,struct nlmsghdr * n,void * arg)189 static int accept_msg(const struct sockaddr_nl *who,
190 struct rtnl_ctrl_data *ctrl,
191 struct nlmsghdr *n, void *arg)
192 {
193 struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
194
195 if (n->nlmsg_type == NLMSG_ERROR &&
196 (err->error == -EOPNOTSUPP || err->error == -EINVAL))
197 have_rtnl_newlink = 0;
198 else
199 have_rtnl_newlink = 1;
200 return -1;
201 }
202
iplink_have_newlink(void)203 static int iplink_have_newlink(void)
204 {
205 struct {
206 struct nlmsghdr n;
207 struct ifinfomsg i;
208 char buf[1024];
209 } req;
210
211 if (have_rtnl_newlink < 0) {
212 memset(&req, 0, sizeof(req));
213
214 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
215 req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
216 req.n.nlmsg_type = RTM_NEWLINK;
217 req.i.ifi_family = AF_UNSPEC;
218
219 if (rtnl_send(&rth, &req.n, req.n.nlmsg_len) < 0) {
220 perror("request send failed");
221 exit(1);
222 }
223 rtnl_listen(&rth, accept_msg, NULL);
224 }
225 return have_rtnl_newlink;
226 }
227 #else /* IPLINK_IOCTL_COMPAT */
iplink_have_newlink(void)228 static int iplink_have_newlink(void)
229 {
230 return 1;
231 }
232 #endif /* ! IPLINK_IOCTL_COMPAT */
233
234 struct iplink_req {
235 struct nlmsghdr n;
236 struct ifinfomsg i;
237 char buf[1024];
238 };
239
iplink_parse_vf(int vf,int * argcp,char *** argvp,struct iplink_req * req,int dev_index)240 static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
241 struct iplink_req *req, int dev_index)
242 {
243 char new_rate_api = 0, count = 0, override_legacy_rate = 0;
244 struct ifla_vf_rate tivt;
245 int len, argc = *argcp;
246 char **argv = *argvp;
247 struct rtattr *vfinfo;
248
249 tivt.min_tx_rate = -1;
250 tivt.max_tx_rate = -1;
251
252 vfinfo = addattr_nest(&req->n, sizeof(*req), IFLA_VF_INFO);
253
254 while (NEXT_ARG_OK()) {
255 NEXT_ARG();
256 count++;
257 if (!matches(*argv, "max_tx_rate")) {
258 /* new API in use */
259 new_rate_api = 1;
260 /* override legacy rate */
261 override_legacy_rate = 1;
262 } else if (!matches(*argv, "min_tx_rate")) {
263 /* new API in use */
264 new_rate_api = 1;
265 }
266 }
267
268 while (count--) {
269 /* rewind arg */
270 PREV_ARG();
271 }
272
273 while (NEXT_ARG_OK()) {
274 NEXT_ARG();
275 if (matches(*argv, "mac") == 0) {
276 struct ifla_vf_mac ivm;
277
278 NEXT_ARG();
279 ivm.vf = vf;
280 len = ll_addr_a2n((char *)ivm.mac, 32, *argv);
281 if (len < 0)
282 return -1;
283 addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC, &ivm, sizeof(ivm));
284 } else if (matches(*argv, "vlan") == 0) {
285 struct ifla_vf_vlan ivv;
286
287 NEXT_ARG();
288 if (get_unsigned(&ivv.vlan, *argv, 0))
289 invarg("Invalid \"vlan\" value\n", *argv);
290
291 ivv.vf = vf;
292 ivv.qos = 0;
293 if (NEXT_ARG_OK()) {
294 NEXT_ARG();
295 if (matches(*argv, "qos") == 0) {
296 NEXT_ARG();
297 if (get_unsigned(&ivv.qos, *argv, 0))
298 invarg("Invalid \"qos\" value\n", *argv);
299 } else {
300 /* rewind arg */
301 PREV_ARG();
302 }
303 }
304 addattr_l(&req->n, sizeof(*req), IFLA_VF_VLAN, &ivv, sizeof(ivv));
305 } else if (matches(*argv, "rate") == 0) {
306 struct ifla_vf_tx_rate ivt;
307
308 NEXT_ARG();
309 if (get_unsigned(&ivt.rate, *argv, 0))
310 invarg("Invalid \"rate\" value\n", *argv);
311
312 ivt.vf = vf;
313 if (!new_rate_api)
314 addattr_l(&req->n, sizeof(*req),
315 IFLA_VF_TX_RATE, &ivt, sizeof(ivt));
316 else if (!override_legacy_rate)
317 tivt.max_tx_rate = ivt.rate;
318
319 } else if (matches(*argv, "max_tx_rate") == 0) {
320 NEXT_ARG();
321 if (get_unsigned(&tivt.max_tx_rate, *argv, 0))
322 invarg("Invalid \"max tx rate\" value\n",
323 *argv);
324 tivt.vf = vf;
325
326 } else if (matches(*argv, "min_tx_rate") == 0) {
327 NEXT_ARG();
328 if (get_unsigned(&tivt.min_tx_rate, *argv, 0))
329 invarg("Invalid \"min tx rate\" value\n",
330 *argv);
331 tivt.vf = vf;
332
333 } else if (matches(*argv, "spoofchk") == 0) {
334 struct ifla_vf_spoofchk ivs;
335
336 NEXT_ARG();
337 if (matches(*argv, "on") == 0)
338 ivs.setting = 1;
339 else if (matches(*argv, "off") == 0)
340 ivs.setting = 0;
341 else
342 return on_off("spoofchk", *argv);
343 ivs.vf = vf;
344 addattr_l(&req->n, sizeof(*req), IFLA_VF_SPOOFCHK, &ivs, sizeof(ivs));
345
346 } else if (matches(*argv, "query_rss") == 0) {
347 struct ifla_vf_rss_query_en ivs;
348
349 NEXT_ARG();
350 if (matches(*argv, "on") == 0)
351 ivs.setting = 1;
352 else if (matches(*argv, "off") == 0)
353 ivs.setting = 0;
354 else
355 return on_off("query_rss", *argv);
356 ivs.vf = vf;
357 addattr_l(&req->n, sizeof(*req), IFLA_VF_RSS_QUERY_EN, &ivs, sizeof(ivs));
358
359 } else if (matches(*argv, "state") == 0) {
360 struct ifla_vf_link_state ivl;
361
362 NEXT_ARG();
363 if (matches(*argv, "auto") == 0)
364 ivl.link_state = IFLA_VF_LINK_STATE_AUTO;
365 else if (matches(*argv, "enable") == 0)
366 ivl.link_state = IFLA_VF_LINK_STATE_ENABLE;
367 else if (matches(*argv, "disable") == 0)
368 ivl.link_state = IFLA_VF_LINK_STATE_DISABLE;
369 else
370 invarg("Invalid \"state\" value\n", *argv);
371 ivl.vf = vf;
372 addattr_l(&req->n, sizeof(*req), IFLA_VF_LINK_STATE, &ivl, sizeof(ivl));
373 } else {
374 /* rewind arg */
375 PREV_ARG();
376 break;
377 }
378 }
379
380 if (new_rate_api) {
381 int tmin, tmax;
382
383 if (tivt.min_tx_rate == -1 || tivt.max_tx_rate == -1) {
384 ipaddr_get_vf_rate(tivt.vf, &tmin, &tmax, dev_index);
385 if (tivt.min_tx_rate == -1)
386 tivt.min_tx_rate = tmin;
387 if (tivt.max_tx_rate == -1)
388 tivt.max_tx_rate = tmax;
389 }
390 addattr_l(&req->n, sizeof(*req), IFLA_VF_RATE, &tivt,
391 sizeof(tivt));
392 }
393
394 if (argc == *argcp)
395 incomplete_command();
396
397 addattr_nest_end(&req->n, vfinfo);
398
399 *argcp = argc;
400 *argvp = argv;
401 return 0;
402 }
403
iplink_parse(int argc,char ** argv,struct iplink_req * req,char ** name,char ** type,char ** link,char ** dev,int * group,int * index)404 int iplink_parse(int argc, char **argv, struct iplink_req *req,
405 char **name, char **type, char **link, char **dev,
406 int *group, int *index)
407 {
408 int ret, len;
409 char abuf[32];
410 int qlen = -1;
411 int mtu = -1;
412 int netns = -1;
413 int vf = -1;
414 int numtxqueues = -1;
415 int numrxqueues = -1;
416 int dev_index = 0;
417 int link_netnsid = -1;
418
419 *group = -1;
420 ret = argc;
421
422 while (argc > 0) {
423 if (strcmp(*argv, "up") == 0) {
424 req->i.ifi_change |= IFF_UP;
425 req->i.ifi_flags |= IFF_UP;
426 } else if (strcmp(*argv, "down") == 0) {
427 req->i.ifi_change |= IFF_UP;
428 req->i.ifi_flags &= ~IFF_UP;
429 } else if (strcmp(*argv, "name") == 0) {
430 NEXT_ARG();
431 *name = *argv;
432 } else if (strcmp(*argv, "index") == 0) {
433 NEXT_ARG();
434 *index = atoi(*argv);
435 if (*index < 0)
436 invarg("Invalid \"index\" value", *argv);
437 } else if (matches(*argv, "link") == 0) {
438 NEXT_ARG();
439 *link = *argv;
440 } else if (matches(*argv, "address") == 0) {
441 NEXT_ARG();
442 len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
443 if (len < 0)
444 return -1;
445 addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, len);
446 } else if (matches(*argv, "broadcast") == 0 ||
447 strcmp(*argv, "brd") == 0) {
448 NEXT_ARG();
449 len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
450 if (len < 0)
451 return -1;
452 addattr_l(&req->n, sizeof(*req), IFLA_BROADCAST, abuf, len);
453 } else if (matches(*argv, "txqueuelen") == 0 ||
454 strcmp(*argv, "qlen") == 0 ||
455 matches(*argv, "txqlen") == 0) {
456 NEXT_ARG();
457 if (qlen != -1)
458 duparg("txqueuelen", *argv);
459 if (get_integer(&qlen, *argv, 0))
460 invarg("Invalid \"txqueuelen\" value\n", *argv);
461 addattr_l(&req->n, sizeof(*req), IFLA_TXQLEN, &qlen, 4);
462 } else if (strcmp(*argv, "mtu") == 0) {
463 NEXT_ARG();
464 if (mtu != -1)
465 duparg("mtu", *argv);
466 if (get_integer(&mtu, *argv, 0))
467 invarg("Invalid \"mtu\" value\n", *argv);
468 addattr_l(&req->n, sizeof(*req), IFLA_MTU, &mtu, 4);
469 } else if (strcmp(*argv, "netns") == 0) {
470 NEXT_ARG();
471 if (netns != -1)
472 duparg("netns", *argv);
473 netns = netns_get_fd(*argv);
474 if (netns >= 0)
475 addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_FD, &netns, 4);
476 else if (get_integer(&netns, *argv, 0) == 0)
477 addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID, &netns, 4);
478 else
479 invarg("Invalid \"netns\" value\n", *argv);
480 } else if (strcmp(*argv, "multicast") == 0) {
481 NEXT_ARG();
482 req->i.ifi_change |= IFF_MULTICAST;
483
484 if (strcmp(*argv, "on") == 0)
485 req->i.ifi_flags |= IFF_MULTICAST;
486 else if (strcmp(*argv, "off") == 0)
487 req->i.ifi_flags &= ~IFF_MULTICAST;
488 else
489 return on_off("multicast", *argv);
490 } else if (strcmp(*argv, "allmulticast") == 0) {
491 NEXT_ARG();
492 req->i.ifi_change |= IFF_ALLMULTI;
493
494 if (strcmp(*argv, "on") == 0)
495 req->i.ifi_flags |= IFF_ALLMULTI;
496 else if (strcmp(*argv, "off") == 0)
497 req->i.ifi_flags &= ~IFF_ALLMULTI;
498 else
499 return on_off("allmulticast", *argv);
500 } else if (strcmp(*argv, "promisc") == 0) {
501 NEXT_ARG();
502 req->i.ifi_change |= IFF_PROMISC;
503
504 if (strcmp(*argv, "on") == 0)
505 req->i.ifi_flags |= IFF_PROMISC;
506 else if (strcmp(*argv, "off") == 0)
507 req->i.ifi_flags &= ~IFF_PROMISC;
508 else
509 return on_off("promisc", *argv);
510 } else if (strcmp(*argv, "trailers") == 0) {
511 NEXT_ARG();
512 req->i.ifi_change |= IFF_NOTRAILERS;
513
514 if (strcmp(*argv, "off") == 0)
515 req->i.ifi_flags |= IFF_NOTRAILERS;
516 else if (strcmp(*argv, "on") == 0)
517 req->i.ifi_flags &= ~IFF_NOTRAILERS;
518 else
519 return on_off("trailers", *argv);
520 } else if (strcmp(*argv, "arp") == 0) {
521 NEXT_ARG();
522 req->i.ifi_change |= IFF_NOARP;
523
524 if (strcmp(*argv, "on") == 0)
525 req->i.ifi_flags &= ~IFF_NOARP;
526 else if (strcmp(*argv, "off") == 0)
527 req->i.ifi_flags |= IFF_NOARP;
528 else
529 return on_off("arp", *argv);
530 } else if (strcmp(*argv, "vf") == 0) {
531 struct rtattr *vflist;
532
533 NEXT_ARG();
534 if (get_integer(&vf, *argv, 0))
535 invarg("Invalid \"vf\" value\n", *argv);
536
537 vflist = addattr_nest(&req->n, sizeof(*req),
538 IFLA_VFINFO_LIST);
539 if (dev_index == 0)
540 missarg("dev");
541
542 len = iplink_parse_vf(vf, &argc, &argv, req, dev_index);
543 if (len < 0)
544 return -1;
545 addattr_nest_end(&req->n, vflist);
546 } else if (matches(*argv, "master") == 0) {
547 int ifindex;
548
549 NEXT_ARG();
550 ifindex = ll_name_to_index(*argv);
551 if (!ifindex)
552 invarg("Device does not exist\n", *argv);
553 addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
554 &ifindex, 4);
555 } else if (matches(*argv, "nomaster") == 0) {
556 int ifindex = 0;
557
558 addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
559 &ifindex, 4);
560 } else if (matches(*argv, "dynamic") == 0) {
561 NEXT_ARG();
562 req->i.ifi_change |= IFF_DYNAMIC;
563
564 if (strcmp(*argv, "on") == 0)
565 req->i.ifi_flags |= IFF_DYNAMIC;
566 else if (strcmp(*argv, "off") == 0)
567 req->i.ifi_flags &= ~IFF_DYNAMIC;
568 else
569 return on_off("dynamic", *argv);
570 } else if (matches(*argv, "type") == 0) {
571 NEXT_ARG();
572 *type = *argv;
573 argc--; argv++;
574 break;
575 } else if (matches(*argv, "alias") == 0) {
576 NEXT_ARG();
577 addattr_l(&req->n, sizeof(*req), IFLA_IFALIAS,
578 *argv, strlen(*argv));
579 argc--; argv++;
580 break;
581 } else if (strcmp(*argv, "group") == 0) {
582 NEXT_ARG();
583 if (*group != -1)
584 duparg("group", *argv);
585 if (rtnl_group_a2n(group, *argv))
586 invarg("Invalid \"group\" value\n", *argv);
587 } else if (strcmp(*argv, "mode") == 0) {
588 int mode;
589
590 NEXT_ARG();
591 mode = get_link_mode(*argv);
592 if (mode < 0)
593 invarg("Invalid link mode\n", *argv);
594 addattr8(&req->n, sizeof(*req), IFLA_LINKMODE, mode);
595 } else if (strcmp(*argv, "state") == 0) {
596 int state;
597
598 NEXT_ARG();
599 state = get_operstate(*argv);
600 if (state < 0)
601 invarg("Invalid operstate\n", *argv);
602
603 addattr8(&req->n, sizeof(*req), IFLA_OPERSTATE, state);
604 } else if (matches(*argv, "numtxqueues") == 0) {
605 NEXT_ARG();
606 if (numtxqueues != -1)
607 duparg("numtxqueues", *argv);
608 if (get_integer(&numtxqueues, *argv, 0))
609 invarg("Invalid \"numtxqueues\" value\n", *argv);
610 addattr_l(&req->n, sizeof(*req), IFLA_NUM_TX_QUEUES,
611 &numtxqueues, 4);
612 } else if (matches(*argv, "numrxqueues") == 0) {
613 NEXT_ARG();
614 if (numrxqueues != -1)
615 duparg("numrxqueues", *argv);
616 if (get_integer(&numrxqueues, *argv, 0))
617 invarg("Invalid \"numrxqueues\" value\n", *argv);
618 addattr_l(&req->n, sizeof(*req), IFLA_NUM_RX_QUEUES,
619 &numrxqueues, 4);
620 } else if (matches(*argv, "addrgenmode") == 0) {
621 struct rtattr *afs, *afs6;
622 int mode;
623
624 NEXT_ARG();
625 mode = get_addr_gen_mode(*argv);
626 if (mode < 0)
627 invarg("Invalid address generation mode\n", *argv);
628 afs = addattr_nest(&req->n, sizeof(*req), IFLA_AF_SPEC);
629 afs6 = addattr_nest(&req->n, sizeof(*req), AF_INET6);
630 addattr8(&req->n, sizeof(*req), IFLA_INET6_ADDR_GEN_MODE, mode);
631 addattr_nest_end(&req->n, afs6);
632 addattr_nest_end(&req->n, afs);
633 } else if (matches(*argv, "link-netnsid") == 0) {
634 NEXT_ARG();
635 if (link_netnsid != -1)
636 duparg("link-netnsid", *argv);
637 if (get_integer(&link_netnsid, *argv, 0))
638 invarg("Invalid \"link-netnsid\" value\n", *argv);
639 addattr32(&req->n, sizeof(*req), IFLA_LINK_NETNSID,
640 link_netnsid);
641 } else if (strcmp(*argv, "protodown") == 0) {
642 unsigned int proto_down;
643
644 NEXT_ARG();
645 if (strcmp(*argv, "on") == 0)
646 proto_down = 1;
647 else if (strcmp(*argv, "off") == 0)
648 proto_down = 0;
649 else
650 return on_off("protodown", *argv);
651 addattr8(&req->n, sizeof(*req), IFLA_PROTO_DOWN,
652 proto_down);
653 } else {
654 if (matches(*argv, "help") == 0)
655 usage();
656
657 if (strcmp(*argv, "dev") == 0)
658 NEXT_ARG();
659 if (*dev)
660 duparg2("dev", *argv);
661 *dev = *argv;
662 dev_index = ll_name_to_index(*dev);
663 }
664 argc--; argv++;
665 }
666
667 return ret - argc;
668 }
669
iplink_modify(int cmd,unsigned int flags,int argc,char ** argv)670 static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
671 {
672 int len;
673 char *dev = NULL;
674 char *name = NULL;
675 char *link = NULL;
676 char *type = NULL;
677 int index = -1;
678 int group;
679 struct link_util *lu = NULL;
680 struct iplink_req req;
681 int ret;
682
683 memset(&req, 0, sizeof(req));
684
685 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
686 req.n.nlmsg_flags = NLM_F_REQUEST|flags;
687 req.n.nlmsg_type = cmd;
688 req.i.ifi_family = preferred_family;
689
690 ret = iplink_parse(argc, argv, &req, &name, &type, &link, &dev, &group, &index);
691 if (ret < 0)
692 return ret;
693
694 argc -= ret;
695 argv += ret;
696
697 if (group != -1) {
698 if (dev)
699 addattr_l(&req.n, sizeof(req), IFLA_GROUP,
700 &group, sizeof(group));
701 else {
702 if (argc) {
703 fprintf(stderr, "Garbage instead of arguments "
704 "\"%s ...\". Try \"ip link "
705 "help\".\n", *argv);
706 return -1;
707 }
708 if (flags & NLM_F_CREATE) {
709 fprintf(stderr, "group cannot be used when "
710 "creating devices.\n");
711 return -1;
712 }
713
714 req.i.ifi_index = 0;
715 addattr32(&req.n, sizeof(req), IFLA_GROUP, group);
716 if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
717 return -2;
718 return 0;
719 }
720 }
721
722 if (!(flags & NLM_F_CREATE)) {
723 if (!dev) {
724 fprintf(stderr, "Not enough information: \"dev\" "
725 "argument is required.\n");
726 exit(-1);
727 }
728 if (cmd == RTM_NEWLINK && index != -1) {
729 fprintf(stderr, "index can be used only when "
730 "creating devices.\n");
731 exit(-1);
732 }
733
734 req.i.ifi_index = ll_name_to_index(dev);
735 if (req.i.ifi_index == 0) {
736 fprintf(stderr, "Cannot find device \"%s\"\n", dev);
737 return -1;
738 }
739 } else {
740 /* Allow "ip link add dev" and "ip link add name" */
741 if (!name)
742 name = dev;
743
744 if (link) {
745 int ifindex;
746
747 ifindex = ll_name_to_index(link);
748 if (ifindex == 0) {
749 fprintf(stderr, "Cannot find device \"%s\"\n",
750 link);
751 return -1;
752 }
753 addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifindex, 4);
754 }
755
756 if (index == -1)
757 req.i.ifi_index = 0;
758 else
759 req.i.ifi_index = index;
760 }
761
762 if (name) {
763 len = strlen(name) + 1;
764 if (len == 1)
765 invarg("\"\" is not a valid device identifier\n", "name");
766 if (len > IFNAMSIZ)
767 invarg("\"name\" too long\n", name);
768 addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len);
769 }
770
771 if (type) {
772 struct rtattr *linkinfo;
773 char slavebuf[128], *ulinep = strchr(type, '_');
774 int iflatype;
775
776 linkinfo = addattr_nest(&req.n, sizeof(req), IFLA_LINKINFO);
777 addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type,
778 strlen(type));
779
780 if (ulinep && !strcmp(ulinep, "_slave")) {
781 strncpy(slavebuf, type, sizeof(slavebuf));
782 slavebuf[sizeof(slavebuf) - 1] = '\0';
783 ulinep = strchr(slavebuf, '_');
784 /* check in case it was after sizeof(slavebuf) - 1*/
785 if (ulinep)
786 *ulinep = '\0';
787 lu = get_link_slave_kind(slavebuf);
788 iflatype = IFLA_INFO_SLAVE_DATA;
789 } else {
790 lu = get_link_kind(type);
791 iflatype = IFLA_INFO_DATA;
792 }
793 if (lu && argc) {
794 struct rtattr *data = addattr_nest(&req.n, sizeof(req), iflatype);
795
796 if (lu->parse_opt &&
797 lu->parse_opt(lu, argc, argv, &req.n))
798 return -1;
799
800 addattr_nest_end(&req.n, data);
801 } else if (argc) {
802 if (matches(*argv, "help") == 0)
803 usage();
804 fprintf(stderr, "Garbage instead of arguments \"%s ...\". "
805 "Try \"ip link help\".\n", *argv);
806 return -1;
807 }
808 addattr_nest_end(&req.n, linkinfo);
809 } else if (flags & NLM_F_CREATE) {
810 fprintf(stderr, "Not enough information: \"type\" argument "
811 "is required\n");
812 return -1;
813 }
814
815 if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
816 return -2;
817
818 return 0;
819 }
820
iplink_get(unsigned int flags,char * name,__u32 filt_mask)821 int iplink_get(unsigned int flags, char *name, __u32 filt_mask)
822 {
823 int len;
824 struct iplink_req req;
825 struct {
826 struct nlmsghdr n;
827 char buf[16384];
828 } answer;
829
830 memset(&req, 0, sizeof(req));
831
832 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
833 req.n.nlmsg_flags = NLM_F_REQUEST|flags;
834 req.n.nlmsg_type = RTM_GETLINK;
835 req.i.ifi_family = preferred_family;
836
837 if (name) {
838 len = strlen(name) + 1;
839 if (len == 1)
840 invarg("\"\" is not a valid device identifier\n",
841 "name");
842 if (len > IFNAMSIZ)
843 invarg("\"name\" too long\n", name);
844 addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len);
845 }
846 addattr32(&req.n, sizeof(req), IFLA_EXT_MASK, filt_mask);
847
848 if (rtnl_talk(&rth, &req.n, &answer.n, sizeof(answer)) < 0)
849 return -2;
850
851 if (brief)
852 print_linkinfo_brief(NULL, &answer.n, stdout);
853 else
854 print_linkinfo(NULL, &answer.n, stdout);
855
856 return 0;
857 }
858
859 #if IPLINK_IOCTL_COMPAT
get_ctl_fd(void)860 static int get_ctl_fd(void)
861 {
862 int s_errno;
863 int fd;
864
865 fd = socket(PF_INET, SOCK_DGRAM, 0);
866 if (fd >= 0)
867 return fd;
868 s_errno = errno;
869 fd = socket(PF_PACKET, SOCK_DGRAM, 0);
870 if (fd >= 0)
871 return fd;
872 fd = socket(PF_INET6, SOCK_DGRAM, 0);
873 if (fd >= 0)
874 return fd;
875 errno = s_errno;
876 perror("Cannot create control socket");
877 return -1;
878 }
879
do_chflags(const char * dev,__u32 flags,__u32 mask)880 static int do_chflags(const char *dev, __u32 flags, __u32 mask)
881 {
882 struct ifreq ifr;
883 int fd;
884 int err;
885
886 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
887 fd = get_ctl_fd();
888 if (fd < 0)
889 return -1;
890 err = ioctl(fd, SIOCGIFFLAGS, &ifr);
891 if (err) {
892 perror("SIOCGIFFLAGS");
893 close(fd);
894 return -1;
895 }
896 if ((ifr.ifr_flags^flags)&mask) {
897 ifr.ifr_flags &= ~mask;
898 ifr.ifr_flags |= mask&flags;
899 err = ioctl(fd, SIOCSIFFLAGS, &ifr);
900 if (err)
901 perror("SIOCSIFFLAGS");
902 }
903 close(fd);
904 return err;
905 }
906
do_changename(const char * dev,const char * newdev)907 static int do_changename(const char *dev, const char *newdev)
908 {
909 struct ifreq ifr;
910 int fd;
911 int err;
912
913 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
914 strncpy(ifr.ifr_newname, newdev, IFNAMSIZ);
915 fd = get_ctl_fd();
916 if (fd < 0)
917 return -1;
918 err = ioctl(fd, SIOCSIFNAME, &ifr);
919 if (err) {
920 perror("SIOCSIFNAME");
921 close(fd);
922 return -1;
923 }
924 close(fd);
925 return err;
926 }
927
set_qlen(const char * dev,int qlen)928 static int set_qlen(const char *dev, int qlen)
929 {
930 struct ifreq ifr;
931 int s;
932
933 s = get_ctl_fd();
934 if (s < 0)
935 return -1;
936
937 memset(&ifr, 0, sizeof(ifr));
938 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
939 ifr.ifr_qlen = qlen;
940 if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) {
941 perror("SIOCSIFXQLEN");
942 close(s);
943 return -1;
944 }
945 close(s);
946
947 return 0;
948 }
949
set_mtu(const char * dev,int mtu)950 static int set_mtu(const char *dev, int mtu)
951 {
952 struct ifreq ifr;
953 int s;
954
955 s = get_ctl_fd();
956 if (s < 0)
957 return -1;
958
959 memset(&ifr, 0, sizeof(ifr));
960 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
961 ifr.ifr_mtu = mtu;
962 if (ioctl(s, SIOCSIFMTU, &ifr) < 0) {
963 perror("SIOCSIFMTU");
964 close(s);
965 return -1;
966 }
967 close(s);
968
969 return 0;
970 }
971
get_address(const char * dev,int * htype)972 static int get_address(const char *dev, int *htype)
973 {
974 struct ifreq ifr;
975 struct sockaddr_ll me;
976 socklen_t alen;
977 int s;
978
979 s = socket(PF_PACKET, SOCK_DGRAM, 0);
980 if (s < 0) {
981 perror("socket(PF_PACKET)");
982 return -1;
983 }
984
985 memset(&ifr, 0, sizeof(ifr));
986 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
987 if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
988 perror("SIOCGIFINDEX");
989 close(s);
990 return -1;
991 }
992
993 memset(&me, 0, sizeof(me));
994 me.sll_family = AF_PACKET;
995 me.sll_ifindex = ifr.ifr_ifindex;
996 me.sll_protocol = htons(ETH_P_LOOP);
997 if (bind(s, (struct sockaddr *)&me, sizeof(me)) == -1) {
998 perror("bind");
999 close(s);
1000 return -1;
1001 }
1002
1003 alen = sizeof(me);
1004 if (getsockname(s, (struct sockaddr *)&me, &alen) == -1) {
1005 perror("getsockname");
1006 close(s);
1007 return -1;
1008 }
1009 close(s);
1010 *htype = me.sll_hatype;
1011 return me.sll_halen;
1012 }
1013
parse_address(const char * dev,int hatype,int halen,char * lla,struct ifreq * ifr)1014 static int parse_address(const char *dev, int hatype, int halen,
1015 char *lla, struct ifreq *ifr)
1016 {
1017 int alen;
1018
1019 memset(ifr, 0, sizeof(*ifr));
1020 strncpy(ifr->ifr_name, dev, IFNAMSIZ);
1021 ifr->ifr_hwaddr.sa_family = hatype;
1022 alen = ll_addr_a2n(ifr->ifr_hwaddr.sa_data, 14, lla);
1023 if (alen < 0)
1024 return -1;
1025 if (alen != halen) {
1026 fprintf(stderr, "Wrong address (%s) length: expected %d bytes\n", lla, halen);
1027 return -1;
1028 }
1029 return 0;
1030 }
1031
set_address(struct ifreq * ifr,int brd)1032 static int set_address(struct ifreq *ifr, int brd)
1033 {
1034 int s;
1035
1036 s = get_ctl_fd();
1037 if (s < 0)
1038 return -1;
1039 if (ioctl(s, brd?SIOCSIFHWBROADCAST:SIOCSIFHWADDR, ifr) < 0) {
1040 perror(brd?"SIOCSIFHWBROADCAST":"SIOCSIFHWADDR");
1041 close(s);
1042 return -1;
1043 }
1044 close(s);
1045 return 0;
1046 }
1047
do_set(int argc,char ** argv)1048 static int do_set(int argc, char **argv)
1049 {
1050 char *dev = NULL;
1051 __u32 mask = 0;
1052 __u32 flags = 0;
1053 int qlen = -1;
1054 int mtu = -1;
1055 char *newaddr = NULL;
1056 char *newbrd = NULL;
1057 struct ifreq ifr0, ifr1;
1058 char *newname = NULL;
1059 int htype, halen;
1060
1061 while (argc > 0) {
1062 if (strcmp(*argv, "up") == 0) {
1063 mask |= IFF_UP;
1064 flags |= IFF_UP;
1065 } else if (strcmp(*argv, "down") == 0) {
1066 mask |= IFF_UP;
1067 flags &= ~IFF_UP;
1068 } else if (strcmp(*argv, "name") == 0) {
1069 NEXT_ARG();
1070 newname = *argv;
1071 } else if (matches(*argv, "address") == 0) {
1072 NEXT_ARG();
1073 newaddr = *argv;
1074 } else if (matches(*argv, "broadcast") == 0 ||
1075 strcmp(*argv, "brd") == 0) {
1076 NEXT_ARG();
1077 newbrd = *argv;
1078 } else if (matches(*argv, "txqueuelen") == 0 ||
1079 strcmp(*argv, "qlen") == 0 ||
1080 matches(*argv, "txqlen") == 0) {
1081 NEXT_ARG();
1082 if (qlen != -1)
1083 duparg("txqueuelen", *argv);
1084 if (get_integer(&qlen, *argv, 0))
1085 invarg("Invalid \"txqueuelen\" value\n", *argv);
1086 } else if (strcmp(*argv, "mtu") == 0) {
1087 NEXT_ARG();
1088 if (mtu != -1)
1089 duparg("mtu", *argv);
1090 if (get_integer(&mtu, *argv, 0))
1091 invarg("Invalid \"mtu\" value\n", *argv);
1092 } else if (strcmp(*argv, "multicast") == 0) {
1093 NEXT_ARG();
1094 mask |= IFF_MULTICAST;
1095
1096 if (strcmp(*argv, "on") == 0)
1097 flags |= IFF_MULTICAST;
1098 else if (strcmp(*argv, "off") == 0)
1099 flags &= ~IFF_MULTICAST;
1100 else
1101 return on_off("multicast", *argv);
1102 } else if (strcmp(*argv, "allmulticast") == 0) {
1103 NEXT_ARG();
1104 mask |= IFF_ALLMULTI;
1105
1106 if (strcmp(*argv, "on") == 0)
1107 flags |= IFF_ALLMULTI;
1108 else if (strcmp(*argv, "off") == 0)
1109 flags &= ~IFF_ALLMULTI;
1110 else
1111 return on_off("allmulticast", *argv);
1112 } else if (strcmp(*argv, "promisc") == 0) {
1113 NEXT_ARG();
1114 mask |= IFF_PROMISC;
1115
1116 if (strcmp(*argv, "on") == 0)
1117 flags |= IFF_PROMISC;
1118 else if (strcmp(*argv, "off") == 0)
1119 flags &= ~IFF_PROMISC;
1120 else
1121 return on_off("promisc", *argv);
1122 } else if (strcmp(*argv, "trailers") == 0) {
1123 NEXT_ARG();
1124 mask |= IFF_NOTRAILERS;
1125
1126 if (strcmp(*argv, "off") == 0)
1127 flags |= IFF_NOTRAILERS;
1128 else if (strcmp(*argv, "on") == 0)
1129 flags &= ~IFF_NOTRAILERS;
1130 else
1131 return on_off("trailers", *argv);
1132 } else if (strcmp(*argv, "arp") == 0) {
1133 NEXT_ARG();
1134 mask |= IFF_NOARP;
1135
1136 if (strcmp(*argv, "on") == 0)
1137 flags &= ~IFF_NOARP;
1138 else if (strcmp(*argv, "off") == 0)
1139 flags |= IFF_NOARP;
1140 else
1141 return on_off("arp", *argv);
1142 } else if (matches(*argv, "dynamic") == 0) {
1143 NEXT_ARG();
1144 mask |= IFF_DYNAMIC;
1145
1146 if (strcmp(*argv, "on") == 0)
1147 flags |= IFF_DYNAMIC;
1148 else if (strcmp(*argv, "off") == 0)
1149 flags &= ~IFF_DYNAMIC;
1150 else
1151 return on_off("dynamic", *argv);
1152 } else {
1153 if (strcmp(*argv, "dev") == 0)
1154 NEXT_ARG();
1155 else if (matches(*argv, "help") == 0)
1156 usage();
1157
1158 if (dev)
1159 duparg2("dev", *argv);
1160 dev = *argv;
1161 }
1162 argc--; argv++;
1163 }
1164
1165 if (!dev) {
1166 fprintf(stderr, "Not enough of information: \"dev\" argument is required.\n");
1167 exit(-1);
1168 }
1169
1170 if (newaddr || newbrd) {
1171 halen = get_address(dev, &htype);
1172 if (halen < 0)
1173 return -1;
1174 if (newaddr) {
1175 if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0)
1176 return -1;
1177 }
1178 if (newbrd) {
1179 if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0)
1180 return -1;
1181 }
1182 }
1183
1184 if (newname && strcmp(dev, newname)) {
1185 if (strlen(newname) == 0)
1186 invarg("\"\" is not a valid device identifier\n", "name");
1187 if (do_changename(dev, newname) < 0)
1188 return -1;
1189 dev = newname;
1190 }
1191 if (qlen != -1) {
1192 if (set_qlen(dev, qlen) < 0)
1193 return -1;
1194 }
1195 if (mtu != -1) {
1196 if (set_mtu(dev, mtu) < 0)
1197 return -1;
1198 }
1199 if (newaddr || newbrd) {
1200 if (newbrd) {
1201 if (set_address(&ifr1, 1) < 0)
1202 return -1;
1203 }
1204 if (newaddr) {
1205 if (set_address(&ifr0, 0) < 0)
1206 return -1;
1207 }
1208 }
1209 if (mask)
1210 return do_chflags(dev, flags, mask);
1211 return 0;
1212 }
1213 #endif /* IPLINK_IOCTL_COMPAT */
1214
do_help(int argc,char ** argv)1215 static void do_help(int argc, char **argv)
1216 {
1217 struct link_util *lu = NULL;
1218
1219 if (argc <= 0) {
1220 usage();
1221 return;
1222 }
1223
1224 lu = get_link_kind(*argv);
1225 if (lu && lu->print_help)
1226 lu->print_help(lu, argc-1, argv+1, stdout);
1227 else
1228 usage();
1229 }
1230
do_iplink(int argc,char ** argv)1231 int do_iplink(int argc, char **argv)
1232 {
1233 if (argc < 1)
1234 return ipaddr_list_link(0, NULL);
1235
1236 if (iplink_have_newlink()) {
1237 if (matches(*argv, "add") == 0)
1238 return iplink_modify(RTM_NEWLINK,
1239 NLM_F_CREATE|NLM_F_EXCL,
1240 argc-1, argv+1);
1241 if (matches(*argv, "set") == 0 ||
1242 matches(*argv, "change") == 0)
1243 return iplink_modify(RTM_NEWLINK, 0,
1244 argc-1, argv+1);
1245 if (matches(*argv, "replace") == 0)
1246 return iplink_modify(RTM_NEWLINK,
1247 NLM_F_CREATE|NLM_F_REPLACE,
1248 argc-1, argv+1);
1249 if (matches(*argv, "delete") == 0)
1250 return iplink_modify(RTM_DELLINK, 0,
1251 argc-1, argv+1);
1252 } else {
1253 #if IPLINK_IOCTL_COMPAT
1254 if (matches(*argv, "set") == 0)
1255 return do_set(argc-1, argv+1);
1256 #endif
1257 }
1258
1259 if (matches(*argv, "show") == 0 ||
1260 matches(*argv, "lst") == 0 ||
1261 matches(*argv, "list") == 0)
1262 return ipaddr_list_link(argc-1, argv+1);
1263
1264 if (matches(*argv, "help") == 0) {
1265 do_help(argc-1, argv+1);
1266 return 0;
1267 }
1268
1269 fprintf(stderr, "Command \"%s\" is unknown, try \"ip link help\".\n",
1270 *argv);
1271 exit(-1);
1272 }
1273