]> git.proxmox.com Git - mirror_iproute2.git/blob - ip/iplink.c
iproute2: add vcan to ip link help text
[mirror_iproute2.git] / ip / iplink.c
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
31 #include "rt_names.h"
32 #include "utils.h"
33 #include "ip_common.h"
34
35 #define IPLINK_IOCTL_COMPAT 1
36 #ifndef LIBDIR
37 #define LIBDIR "/usr/lib/"
38 #endif
39
40 static void usage(void) __attribute__((noreturn));
41 static int iplink_have_newlink(void);
42
43 void iplink_usage(void)
44 {
45 if (iplink_have_newlink()) {
46 fprintf(stderr, "Usage: ip link add link DEV [ name ] NAME\n");
47 fprintf(stderr, " [ txqueuelen PACKETS ]\n");
48 fprintf(stderr, " [ address LLADDR ]\n");
49 fprintf(stderr, " [ broadcast LLADDR ]\n");
50 fprintf(stderr, " [ mtu MTU ]\n");
51 fprintf(stderr, " type TYPE [ ARGS ]\n");
52 fprintf(stderr, " ip link delete DEV type TYPE [ ARGS ]\n");
53 fprintf(stderr, "\n");
54 fprintf(stderr, " ip link set DEVICE [ { up | down } ]\n");
55 } else
56 fprintf(stderr, "Usage: ip link set DEVICE [ { up | down } ]\n");
57
58 fprintf(stderr, " [ arp { on | off } ]\n");
59 fprintf(stderr, " [ dynamic { on | off } ]\n");
60 fprintf(stderr, " [ multicast { on | off } ]\n");
61 fprintf(stderr, " [ allmulticast { on | off } ]\n");
62 fprintf(stderr, " [ promisc { on | off } ]\n");
63 fprintf(stderr, " [ trailers { on | off } ]\n");
64 fprintf(stderr, " [ txqueuelen PACKETS ]\n");
65 fprintf(stderr, " [ name NEWNAME ]\n");
66 fprintf(stderr, " [ address LLADDR ]\n");
67 fprintf(stderr, " [ broadcast LLADDR ]\n");
68 fprintf(stderr, " [ mtu MTU ]\n");
69 fprintf(stderr, " [ netns PID ]\n");
70 fprintf(stderr, " [ alias NAME ]\n");
71 fprintf(stderr, " ip link show [ DEVICE ]\n");
72
73 if (iplink_have_newlink()) {
74 fprintf(stderr, "\n");
75 fprintf(stderr, "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan }\n");
76 }
77 exit(-1);
78 }
79
80 static void usage(void)
81 {
82 iplink_usage();
83 }
84
85 static int on_off(char *msg)
86 {
87 fprintf(stderr, "Error: argument of \"%s\" must be \"on\" or \"off\"\n", msg);
88 return -1;
89 }
90
91 static void *BODY; /* cached dlopen(NULL) handle */
92 static struct link_util *linkutil_list;
93
94 struct link_util *get_link_kind(const char *id)
95 {
96 void *dlh;
97 char buf[256];
98 struct link_util *l;
99
100 for (l = linkutil_list; l; l = l->next)
101 if (strcmp(l->id, id) == 0)
102 return l;
103
104 snprintf(buf, sizeof(buf), LIBDIR "/ip/link_%s.so", id);
105 dlh = dlopen(buf, RTLD_LAZY);
106 if (dlh == NULL) {
107 /* look in current binary, only open once */
108 dlh = BODY;
109 if (dlh == NULL) {
110 dlh = BODY = dlopen(NULL, RTLD_LAZY);
111 if (dlh == NULL)
112 return NULL;
113 }
114 }
115
116 snprintf(buf, sizeof(buf), "%s_link_util", id);
117 l = dlsym(dlh, buf);
118 if (l == NULL)
119 return NULL;
120
121 l->next = linkutil_list;
122 linkutil_list = l;
123 return l;
124 }
125
126 #if IPLINK_IOCTL_COMPAT
127 static int have_rtnl_newlink = -1;
128
129 static int accept_msg(const struct sockaddr_nl *who,
130 struct nlmsghdr *n, void *arg)
131 {
132 struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
133
134 if (n->nlmsg_type == NLMSG_ERROR &&
135 (err->error == -EOPNOTSUPP || err->error == -EINVAL))
136 have_rtnl_newlink = 0;
137 else
138 have_rtnl_newlink = 1;
139 return -1;
140 }
141
142 static int iplink_have_newlink(void)
143 {
144 struct {
145 struct nlmsghdr n;
146 struct ifinfomsg i;
147 char buf[1024];
148 } req;
149
150 if (have_rtnl_newlink < 0) {
151 memset(&req, 0, sizeof(req));
152
153 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
154 req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
155 req.n.nlmsg_type = RTM_NEWLINK;
156 req.i.ifi_family = AF_UNSPEC;
157
158 rtnl_send(&rth, (char *)&req.n, req.n.nlmsg_len);
159 rtnl_listen(&rth, accept_msg, NULL);
160 }
161 return have_rtnl_newlink;
162 }
163 #else /* IPLINK_IOCTL_COMPAT */
164 static int iplink_have_newlink(void)
165 {
166 return 1;
167 }
168 #endif /* ! IPLINK_IOCTL_COMPAT */
169
170 struct iplink_req {
171 struct nlmsghdr n;
172 struct ifinfomsg i;
173 char buf[1024];
174 };
175
176 int iplink_parse(int argc, char **argv, struct iplink_req *req,
177 char **name, char **type, char **link, char **dev)
178 {
179 int ret, len;
180 char abuf[32];
181 int qlen = -1;
182 int mtu = -1;
183 int netns = -1;
184
185 ret = argc;
186
187 while (argc > 0) {
188 if (strcmp(*argv, "up") == 0) {
189 req->i.ifi_change |= IFF_UP;
190 req->i.ifi_flags |= IFF_UP;
191 } else if (strcmp(*argv, "down") == 0) {
192 req->i.ifi_change |= IFF_UP;
193 req->i.ifi_flags &= ~IFF_UP;
194 } else if (strcmp(*argv, "name") == 0) {
195 NEXT_ARG();
196 *name = *argv;
197 } else if (matches(*argv, "link") == 0) {
198 NEXT_ARG();
199 *link = *argv;
200 } else if (matches(*argv, "address") == 0) {
201 NEXT_ARG();
202 len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
203 addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, len);
204 } else if (matches(*argv, "broadcast") == 0 ||
205 strcmp(*argv, "brd") == 0) {
206 NEXT_ARG();
207 len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
208 addattr_l(&req->n, sizeof(*req), IFLA_BROADCAST, abuf, len);
209 } else if (matches(*argv, "txqueuelen") == 0 ||
210 strcmp(*argv, "qlen") == 0 ||
211 matches(*argv, "txqlen") == 0) {
212 NEXT_ARG();
213 if (qlen != -1)
214 duparg("txqueuelen", *argv);
215 if (get_integer(&qlen, *argv, 0))
216 invarg("Invalid \"txqueuelen\" value\n", *argv);
217 addattr_l(&req->n, sizeof(*req), IFLA_TXQLEN, &qlen, 4);
218 } else if (strcmp(*argv, "mtu") == 0) {
219 NEXT_ARG();
220 if (mtu != -1)
221 duparg("mtu", *argv);
222 if (get_integer(&mtu, *argv, 0))
223 invarg("Invalid \"mtu\" value\n", *argv);
224 addattr_l(&req->n, sizeof(*req), IFLA_MTU, &mtu, 4);
225 } else if (strcmp(*argv, "netns") == 0) {
226 NEXT_ARG();
227 if (netns != -1)
228 duparg("netns", *argv);
229 if (get_integer(&netns, *argv, 0))
230 invarg("Invalid \"netns\" value\n", *argv);
231 addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID, &netns, 4);
232 } else if (strcmp(*argv, "multicast") == 0) {
233 NEXT_ARG();
234 req->i.ifi_change |= IFF_MULTICAST;
235 if (strcmp(*argv, "on") == 0) {
236 req->i.ifi_flags |= IFF_MULTICAST;
237 } else if (strcmp(*argv, "off") == 0) {
238 req->i.ifi_flags &= ~IFF_MULTICAST;
239 } else
240 return on_off("multicast");
241 } else if (strcmp(*argv, "allmulticast") == 0) {
242 NEXT_ARG();
243 req->i.ifi_change |= IFF_ALLMULTI;
244 if (strcmp(*argv, "on") == 0) {
245 req->i.ifi_flags |= IFF_ALLMULTI;
246 } else if (strcmp(*argv, "off") == 0) {
247 req->i.ifi_flags &= ~IFF_ALLMULTI;
248 } else
249 return on_off("allmulticast");
250 } else if (strcmp(*argv, "promisc") == 0) {
251 NEXT_ARG();
252 req->i.ifi_change |= IFF_PROMISC;
253 if (strcmp(*argv, "on") == 0) {
254 req->i.ifi_flags |= IFF_PROMISC;
255 } else if (strcmp(*argv, "off") == 0) {
256 req->i.ifi_flags &= ~IFF_PROMISC;
257 } else
258 return on_off("promisc");
259 } else if (strcmp(*argv, "trailers") == 0) {
260 NEXT_ARG();
261 req->i.ifi_change |= IFF_NOTRAILERS;
262 if (strcmp(*argv, "off") == 0) {
263 req->i.ifi_flags |= IFF_NOTRAILERS;
264 } else if (strcmp(*argv, "on") == 0) {
265 req->i.ifi_flags &= ~IFF_NOTRAILERS;
266 } else
267 return on_off("trailers");
268 } else if (strcmp(*argv, "arp") == 0) {
269 NEXT_ARG();
270 req->i.ifi_change |= IFF_NOARP;
271 if (strcmp(*argv, "on") == 0) {
272 req->i.ifi_flags &= ~IFF_NOARP;
273 } else if (strcmp(*argv, "off") == 0) {
274 req->i.ifi_flags |= IFF_NOARP;
275 } else
276 return on_off("noarp");
277 #ifdef IFF_DYNAMIC
278 } else if (matches(*argv, "dynamic") == 0) {
279 NEXT_ARG();
280 req->i.ifi_change |= IFF_DYNAMIC;
281 if (strcmp(*argv, "on") == 0) {
282 req->i.ifi_flags |= IFF_DYNAMIC;
283 } else if (strcmp(*argv, "off") == 0) {
284 req->i.ifi_flags &= ~IFF_DYNAMIC;
285 } else
286 return on_off("dynamic");
287 #endif
288 } else if (matches(*argv, "type") == 0) {
289 NEXT_ARG();
290 *type = *argv;
291 argc--; argv++;
292 break;
293 } else if (matches(*argv, "alias") == 0) {
294 NEXT_ARG();
295 addattr_l(&req->n, sizeof(*req), IFLA_IFALIAS,
296 *argv, strlen(*argv));
297 argc--; argv++;
298 break;
299 } else {
300 if (strcmp(*argv, "dev") == 0) {
301 NEXT_ARG();
302 }
303 if (matches(*argv, "help") == 0)
304 usage();
305 if (*dev)
306 duparg2("dev", *argv);
307 *dev = *argv;
308 }
309 argc--; argv++;
310 }
311
312 return ret - argc;
313 }
314
315 static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
316 {
317 int len;
318 char *dev = NULL;
319 char *name = NULL;
320 char *link = NULL;
321 char *type = NULL;
322 struct link_util *lu = NULL;
323 struct iplink_req req;
324 int ret;
325
326 memset(&req, 0, sizeof(req));
327
328 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
329 req.n.nlmsg_flags = NLM_F_REQUEST|flags;
330 req.n.nlmsg_type = cmd;
331 req.i.ifi_family = preferred_family;
332
333 ret = iplink_parse(argc, argv, &req, &name, &type, &link, &dev);
334 if (ret < 0)
335 return ret;
336
337 argc -= ret;
338 argv += ret;
339 ll_init_map(&rth);
340
341 if (type) {
342 struct rtattr *linkinfo = NLMSG_TAIL(&req.n);
343 addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
344 addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type,
345 strlen(type));
346
347 lu = get_link_kind(type);
348 if (lu && argc) {
349 struct rtattr * data = NLMSG_TAIL(&req.n);
350 addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0);
351
352 if (lu->parse_opt &&
353 lu->parse_opt(lu, argc, argv, &req.n))
354 return -1;
355
356 data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;
357 } else if (argc) {
358 if (matches(*argv, "help") == 0)
359 usage();
360 fprintf(stderr, "Garbage instead of arguments \"%s ...\". "
361 "Try \"ip link help\".\n", *argv);
362 return -1;
363 }
364 linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
365 } else if (flags & NLM_F_CREATE) {
366 fprintf(stderr, "Not enough information: \"type\" argument "
367 "is required\n");
368 return -1;
369 }
370
371 if (!(flags & NLM_F_CREATE)) {
372 if (!dev) {
373 fprintf(stderr, "Not enough information: \"dev\" "
374 "argument is required.\n");
375 exit(-1);
376 }
377
378 req.i.ifi_index = ll_name_to_index(dev);
379 if (req.i.ifi_index == 0) {
380 fprintf(stderr, "Cannot find device \"%s\"\n", dev);
381 return -1;
382 }
383 } else {
384 /* Allow "ip link add dev" and "ip link add name" */
385 if (!name)
386 name = dev;
387
388 if (link) {
389 int ifindex;
390
391 ifindex = ll_name_to_index(link);
392 if (ifindex == 0) {
393 fprintf(stderr, "Cannot find device \"%s\"\n",
394 link);
395 return -1;
396 }
397 addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifindex, 4);
398 }
399 }
400
401 if (name) {
402 len = strlen(name) + 1;
403 if (len == 1)
404 invarg("\"\" is not a valid device identifier\n", "name");
405 if (len > IFNAMSIZ)
406 invarg("\"name\" too long\n", name);
407 addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len);
408 }
409
410 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
411 exit(2);
412
413 return 0;
414 }
415
416 #if IPLINK_IOCTL_COMPAT
417 static int get_ctl_fd(void)
418 {
419 int s_errno;
420 int fd;
421
422 fd = socket(PF_INET, SOCK_DGRAM, 0);
423 if (fd >= 0)
424 return fd;
425 s_errno = errno;
426 fd = socket(PF_PACKET, SOCK_DGRAM, 0);
427 if (fd >= 0)
428 return fd;
429 fd = socket(PF_INET6, SOCK_DGRAM, 0);
430 if (fd >= 0)
431 return fd;
432 errno = s_errno;
433 perror("Cannot create control socket");
434 return -1;
435 }
436
437 static int do_chflags(const char *dev, __u32 flags, __u32 mask)
438 {
439 struct ifreq ifr;
440 int fd;
441 int err;
442
443 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
444 fd = get_ctl_fd();
445 if (fd < 0)
446 return -1;
447 err = ioctl(fd, SIOCGIFFLAGS, &ifr);
448 if (err) {
449 perror("SIOCGIFFLAGS");
450 close(fd);
451 return -1;
452 }
453 if ((ifr.ifr_flags^flags)&mask) {
454 ifr.ifr_flags &= ~mask;
455 ifr.ifr_flags |= mask&flags;
456 err = ioctl(fd, SIOCSIFFLAGS, &ifr);
457 if (err)
458 perror("SIOCSIFFLAGS");
459 }
460 close(fd);
461 return err;
462 }
463
464 static int do_changename(const char *dev, const char *newdev)
465 {
466 struct ifreq ifr;
467 int fd;
468 int err;
469
470 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
471 strncpy(ifr.ifr_newname, newdev, IFNAMSIZ);
472 fd = get_ctl_fd();
473 if (fd < 0)
474 return -1;
475 err = ioctl(fd, SIOCSIFNAME, &ifr);
476 if (err) {
477 perror("SIOCSIFNAME");
478 close(fd);
479 return -1;
480 }
481 close(fd);
482 return err;
483 }
484
485 static int set_qlen(const char *dev, int qlen)
486 {
487 struct ifreq ifr;
488 int s;
489
490 s = get_ctl_fd();
491 if (s < 0)
492 return -1;
493
494 memset(&ifr, 0, sizeof(ifr));
495 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
496 ifr.ifr_qlen = qlen;
497 if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) {
498 perror("SIOCSIFXQLEN");
499 close(s);
500 return -1;
501 }
502 close(s);
503
504 return 0;
505 }
506
507 static int set_mtu(const char *dev, int mtu)
508 {
509 struct ifreq ifr;
510 int s;
511
512 s = get_ctl_fd();
513 if (s < 0)
514 return -1;
515
516 memset(&ifr, 0, sizeof(ifr));
517 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
518 ifr.ifr_mtu = mtu;
519 if (ioctl(s, SIOCSIFMTU, &ifr) < 0) {
520 perror("SIOCSIFMTU");
521 close(s);
522 return -1;
523 }
524 close(s);
525
526 return 0;
527 }
528
529 static int get_address(const char *dev, int *htype)
530 {
531 struct ifreq ifr;
532 struct sockaddr_ll me;
533 socklen_t alen;
534 int s;
535
536 s = socket(PF_PACKET, SOCK_DGRAM, 0);
537 if (s < 0) {
538 perror("socket(PF_PACKET)");
539 return -1;
540 }
541
542 memset(&ifr, 0, sizeof(ifr));
543 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
544 if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
545 perror("SIOCGIFINDEX");
546 close(s);
547 return -1;
548 }
549
550 memset(&me, 0, sizeof(me));
551 me.sll_family = AF_PACKET;
552 me.sll_ifindex = ifr.ifr_ifindex;
553 me.sll_protocol = htons(ETH_P_LOOP);
554 if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) {
555 perror("bind");
556 close(s);
557 return -1;
558 }
559
560 alen = sizeof(me);
561 if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) {
562 perror("getsockname");
563 close(s);
564 return -1;
565 }
566 close(s);
567 *htype = me.sll_hatype;
568 return me.sll_halen;
569 }
570
571 static int parse_address(const char *dev, int hatype, int halen,
572 char *lla, struct ifreq *ifr)
573 {
574 int alen;
575
576 memset(ifr, 0, sizeof(*ifr));
577 strncpy(ifr->ifr_name, dev, IFNAMSIZ);
578 ifr->ifr_hwaddr.sa_family = hatype;
579 alen = ll_addr_a2n(ifr->ifr_hwaddr.sa_data, 14, lla);
580 if (alen < 0)
581 return -1;
582 if (alen != halen) {
583 fprintf(stderr, "Wrong address (%s) length: expected %d bytes\n", lla, halen);
584 return -1;
585 }
586 return 0;
587 }
588
589 static int set_address(struct ifreq *ifr, int brd)
590 {
591 int s;
592
593 s = get_ctl_fd();
594 if (s < 0)
595 return -1;
596 if (ioctl(s, brd?SIOCSIFHWBROADCAST:SIOCSIFHWADDR, ifr) < 0) {
597 perror(brd?"SIOCSIFHWBROADCAST":"SIOCSIFHWADDR");
598 close(s);
599 return -1;
600 }
601 close(s);
602 return 0;
603 }
604
605
606 static int do_set(int argc, char **argv)
607 {
608 char *dev = NULL;
609 __u32 mask = 0;
610 __u32 flags = 0;
611 int qlen = -1;
612 int mtu = -1;
613 char *newaddr = NULL;
614 char *newbrd = NULL;
615 struct ifreq ifr0, ifr1;
616 char *newname = NULL;
617 int htype, halen;
618
619 while (argc > 0) {
620 if (strcmp(*argv, "up") == 0) {
621 mask |= IFF_UP;
622 flags |= IFF_UP;
623 } else if (strcmp(*argv, "down") == 0) {
624 mask |= IFF_UP;
625 flags &= ~IFF_UP;
626 } else if (strcmp(*argv, "name") == 0) {
627 NEXT_ARG();
628 newname = *argv;
629 } else if (matches(*argv, "address") == 0) {
630 NEXT_ARG();
631 newaddr = *argv;
632 } else if (matches(*argv, "broadcast") == 0 ||
633 strcmp(*argv, "brd") == 0) {
634 NEXT_ARG();
635 newbrd = *argv;
636 } else if (matches(*argv, "txqueuelen") == 0 ||
637 strcmp(*argv, "qlen") == 0 ||
638 matches(*argv, "txqlen") == 0) {
639 NEXT_ARG();
640 if (qlen != -1)
641 duparg("txqueuelen", *argv);
642 if (get_integer(&qlen, *argv, 0))
643 invarg("Invalid \"txqueuelen\" value\n", *argv);
644 } else if (strcmp(*argv, "mtu") == 0) {
645 NEXT_ARG();
646 if (mtu != -1)
647 duparg("mtu", *argv);
648 if (get_integer(&mtu, *argv, 0))
649 invarg("Invalid \"mtu\" value\n", *argv);
650 } else if (strcmp(*argv, "multicast") == 0) {
651 NEXT_ARG();
652 mask |= IFF_MULTICAST;
653 if (strcmp(*argv, "on") == 0) {
654 flags |= IFF_MULTICAST;
655 } else if (strcmp(*argv, "off") == 0) {
656 flags &= ~IFF_MULTICAST;
657 } else
658 return on_off("multicast");
659 } else if (strcmp(*argv, "allmulticast") == 0) {
660 NEXT_ARG();
661 mask |= IFF_ALLMULTI;
662 if (strcmp(*argv, "on") == 0) {
663 flags |= IFF_ALLMULTI;
664 } else if (strcmp(*argv, "off") == 0) {
665 flags &= ~IFF_ALLMULTI;
666 } else
667 return on_off("allmulticast");
668 } else if (strcmp(*argv, "promisc") == 0) {
669 NEXT_ARG();
670 mask |= IFF_PROMISC;
671 if (strcmp(*argv, "on") == 0) {
672 flags |= IFF_PROMISC;
673 } else if (strcmp(*argv, "off") == 0) {
674 flags &= ~IFF_PROMISC;
675 } else
676 return on_off("promisc");
677 } else if (strcmp(*argv, "trailers") == 0) {
678 NEXT_ARG();
679 mask |= IFF_NOTRAILERS;
680 if (strcmp(*argv, "off") == 0) {
681 flags |= IFF_NOTRAILERS;
682 } else if (strcmp(*argv, "on") == 0) {
683 flags &= ~IFF_NOTRAILERS;
684 } else
685 return on_off("trailers");
686 } else if (strcmp(*argv, "arp") == 0) {
687 NEXT_ARG();
688 mask |= IFF_NOARP;
689 if (strcmp(*argv, "on") == 0) {
690 flags &= ~IFF_NOARP;
691 } else if (strcmp(*argv, "off") == 0) {
692 flags |= IFF_NOARP;
693 } else
694 return on_off("noarp");
695 #ifdef IFF_DYNAMIC
696 } else if (matches(*argv, "dynamic") == 0) {
697 NEXT_ARG();
698 mask |= IFF_DYNAMIC;
699 if (strcmp(*argv, "on") == 0) {
700 flags |= IFF_DYNAMIC;
701 } else if (strcmp(*argv, "off") == 0) {
702 flags &= ~IFF_DYNAMIC;
703 } else
704 return on_off("dynamic");
705 #endif
706 } else {
707 if (strcmp(*argv, "dev") == 0) {
708 NEXT_ARG();
709 }
710 if (matches(*argv, "help") == 0)
711 usage();
712 if (dev)
713 duparg2("dev", *argv);
714 dev = *argv;
715 }
716 argc--; argv++;
717 }
718
719 if (!dev) {
720 fprintf(stderr, "Not enough of information: \"dev\" argument is required.\n");
721 exit(-1);
722 }
723
724 if (newaddr || newbrd) {
725 halen = get_address(dev, &htype);
726 if (halen < 0)
727 return -1;
728 if (newaddr) {
729 if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0)
730 return -1;
731 }
732 if (newbrd) {
733 if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0)
734 return -1;
735 }
736 }
737
738 if (newname && strcmp(dev, newname)) {
739 if (strlen(newname) == 0)
740 invarg("\"\" is not a valid device identifier\n", "name");
741 if (do_changename(dev, newname) < 0)
742 return -1;
743 dev = newname;
744 }
745 if (qlen != -1) {
746 if (set_qlen(dev, qlen) < 0)
747 return -1;
748 }
749 if (mtu != -1) {
750 if (set_mtu(dev, mtu) < 0)
751 return -1;
752 }
753 if (newaddr || newbrd) {
754 if (newbrd) {
755 if (set_address(&ifr1, 1) < 0)
756 return -1;
757 }
758 if (newaddr) {
759 if (set_address(&ifr0, 0) < 0)
760 return -1;
761 }
762 }
763 if (mask)
764 return do_chflags(dev, flags, mask);
765 return 0;
766 }
767 #endif /* IPLINK_IOCTL_COMPAT */
768
769 int do_iplink(int argc, char **argv)
770 {
771 if (argc > 0) {
772 if (iplink_have_newlink()) {
773 if (matches(*argv, "add") == 0)
774 return iplink_modify(RTM_NEWLINK,
775 NLM_F_CREATE|NLM_F_EXCL,
776 argc-1, argv+1);
777 if (matches(*argv, "set") == 0 ||
778 matches(*argv, "change") == 0)
779 return iplink_modify(RTM_NEWLINK, 0,
780 argc-1, argv+1);
781 if (matches(*argv, "replace") == 0)
782 return iplink_modify(RTM_NEWLINK,
783 NLM_F_CREATE|NLM_F_REPLACE,
784 argc-1, argv+1);
785 if (matches(*argv, "delete") == 0)
786 return iplink_modify(RTM_DELLINK, 0,
787 argc-1, argv+1);
788 } else {
789 #if IPLINK_IOCTL_COMPAT
790 if (matches(*argv, "set") == 0)
791 return do_set(argc-1, argv+1);
792 #endif
793 }
794 if (matches(*argv, "show") == 0 ||
795 matches(*argv, "lst") == 0 ||
796 matches(*argv, "list") == 0)
797 return ipaddr_list_link(argc-1, argv+1);
798 if (matches(*argv, "help") == 0)
799 usage();
800 } else
801 return ipaddr_list_link(0, NULL);
802
803 fprintf(stderr, "Command \"%s\" is unknown, try \"ip link help\".\n", *argv);
804 exit(-1);
805 }