]> git.proxmox.com Git - mirror_iproute2.git/blame - ip/iplink.c
Allow default DP of zero in gred
[mirror_iproute2.git] / ip / iplink.c
CommitLineData
aba5acdf
SH
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>
1d934839 18#include <dlfcn.h>
aba5acdf
SH
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
1d934839 35#define IPLINK_IOCTL_COMPAT 1
5e3bb534
AH
36#ifndef LIBDIR
37#define LIBDIR "/usr/lib/"
b514b358 38#endif
aba5acdf
SH
39
40static void usage(void) __attribute__((noreturn));
750a405a 41static int iplink_have_newlink(void);
aba5acdf
SH
42
43void iplink_usage(void)
44{
750a405a
SH
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");
ace9c961 70 fprintf(stderr, " [ alias NAME ]\n");
aba5acdf 71 fprintf(stderr, " ip link show [ DEVICE ]\n");
750a405a
SH
72
73 if (iplink_have_newlink()) {
74 fprintf(stderr, "\n");
685f3a9f 75 fprintf(stderr, "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan }\n");
750a405a 76 }
aba5acdf
SH
77 exit(-1);
78}
79
80static void usage(void)
81{
82 iplink_usage();
83}
84
85static 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
1d934839
PM
91static void *BODY; /* cached dlopen(NULL) handle */
92static struct link_util *linkutil_list;
93
94struct 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
5e3bb534 104 snprintf(buf, sizeof(buf), LIBDIR "/ip/link_%s.so", id);
1d934839
PM
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
127static int have_rtnl_newlink = -1;
128
129static 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
66e529f5
PM
134 if (n->nlmsg_type == NLMSG_ERROR &&
135 (err->error == -EOPNOTSUPP || err->error == -EINVAL))
1d934839
PM
136 have_rtnl_newlink = 0;
137 else
138 have_rtnl_newlink = 1;
139 return -1;
140}
141
142static 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 */
164static int iplink_have_newlink(void)
165{
166 return 1;
167}
168#endif /* ! IPLINK_IOCTL_COMPAT */
169
909dfe2c
PE
170struct iplink_req {
171 struct nlmsghdr n;
172 struct ifinfomsg i;
173 char buf[1024];
174};
175
176int iplink_parse(int argc, char **argv, struct iplink_req *req,
177 char **name, char **type, char **link, char **dev)
1d934839 178{
909dfe2c
PE
179 int ret, len;
180 char abuf[32];
1d934839
PM
181 int qlen = -1;
182 int mtu = -1;
e2613dc8 183 int netns = -1;
1d934839 184
909dfe2c 185 ret = argc;
1d934839
PM
186
187 while (argc > 0) {
188 if (strcmp(*argv, "up") == 0) {
909dfe2c
PE
189 req->i.ifi_change |= IFF_UP;
190 req->i.ifi_flags |= IFF_UP;
1d934839 191 } else if (strcmp(*argv, "down") == 0) {
909dfe2c
PE
192 req->i.ifi_change |= IFF_UP;
193 req->i.ifi_flags &= ~IFF_UP;
1d934839
PM
194 } else if (strcmp(*argv, "name") == 0) {
195 NEXT_ARG();
909dfe2c 196 *name = *argv;
1d934839
PM
197 } else if (matches(*argv, "link") == 0) {
198 NEXT_ARG();
909dfe2c 199 *link = *argv;
1d934839
PM
200 } else if (matches(*argv, "address") == 0) {
201 NEXT_ARG();
202 len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
909dfe2c 203 addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, len);
1d934839 204 } else if (matches(*argv, "broadcast") == 0 ||
909dfe2c 205 strcmp(*argv, "brd") == 0) {
1d934839
PM
206 NEXT_ARG();
207 len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
909dfe2c 208 addattr_l(&req->n, sizeof(*req), IFLA_BROADCAST, abuf, len);
1d934839 209 } else if (matches(*argv, "txqueuelen") == 0 ||
909dfe2c
PE
210 strcmp(*argv, "qlen") == 0 ||
211 matches(*argv, "txqlen") == 0) {
1d934839
PM
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);
909dfe2c 217 addattr_l(&req->n, sizeof(*req), IFLA_TXQLEN, &qlen, 4);
1d934839
PM
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);
909dfe2c 224 addattr_l(&req->n, sizeof(*req), IFLA_MTU, &mtu, 4);
e2613dc8
BT
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);
1d934839
PM
232 } else if (strcmp(*argv, "multicast") == 0) {
233 NEXT_ARG();
909dfe2c 234 req->i.ifi_change |= IFF_MULTICAST;
1d934839 235 if (strcmp(*argv, "on") == 0) {
909dfe2c 236 req->i.ifi_flags |= IFF_MULTICAST;
1d934839 237 } else if (strcmp(*argv, "off") == 0) {
909dfe2c 238 req->i.ifi_flags &= ~IFF_MULTICAST;
1d934839
PM
239 } else
240 return on_off("multicast");
241 } else if (strcmp(*argv, "allmulticast") == 0) {
242 NEXT_ARG();
909dfe2c 243 req->i.ifi_change |= IFF_ALLMULTI;
1d934839 244 if (strcmp(*argv, "on") == 0) {
909dfe2c 245 req->i.ifi_flags |= IFF_ALLMULTI;
1d934839 246 } else if (strcmp(*argv, "off") == 0) {
909dfe2c 247 req->i.ifi_flags &= ~IFF_ALLMULTI;
1d934839
PM
248 } else
249 return on_off("allmulticast");
250 } else if (strcmp(*argv, "promisc") == 0) {
251 NEXT_ARG();
909dfe2c 252 req->i.ifi_change |= IFF_PROMISC;
1d934839 253 if (strcmp(*argv, "on") == 0) {
909dfe2c 254 req->i.ifi_flags |= IFF_PROMISC;
1d934839 255 } else if (strcmp(*argv, "off") == 0) {
909dfe2c 256 req->i.ifi_flags &= ~IFF_PROMISC;
1d934839
PM
257 } else
258 return on_off("promisc");
259 } else if (strcmp(*argv, "trailers") == 0) {
260 NEXT_ARG();
909dfe2c 261 req->i.ifi_change |= IFF_NOTRAILERS;
1d934839 262 if (strcmp(*argv, "off") == 0) {
909dfe2c 263 req->i.ifi_flags |= IFF_NOTRAILERS;
1d934839 264 } else if (strcmp(*argv, "on") == 0) {
909dfe2c 265 req->i.ifi_flags &= ~IFF_NOTRAILERS;
1d934839
PM
266 } else
267 return on_off("trailers");
268 } else if (strcmp(*argv, "arp") == 0) {
269 NEXT_ARG();
909dfe2c 270 req->i.ifi_change |= IFF_NOARP;
1d934839 271 if (strcmp(*argv, "on") == 0) {
909dfe2c 272 req->i.ifi_flags &= ~IFF_NOARP;
1d934839 273 } else if (strcmp(*argv, "off") == 0) {
909dfe2c 274 req->i.ifi_flags |= IFF_NOARP;
1d934839
PM
275 } else
276 return on_off("noarp");
277#ifdef IFF_DYNAMIC
278 } else if (matches(*argv, "dynamic") == 0) {
279 NEXT_ARG();
909dfe2c 280 req->i.ifi_change |= IFF_DYNAMIC;
1d934839 281 if (strcmp(*argv, "on") == 0) {
909dfe2c 282 req->i.ifi_flags |= IFF_DYNAMIC;
1d934839 283 } else if (strcmp(*argv, "off") == 0) {
909dfe2c 284 req->i.ifi_flags &= ~IFF_DYNAMIC;
1d934839
PM
285 } else
286 return on_off("dynamic");
287#endif
288 } else if (matches(*argv, "type") == 0) {
289 NEXT_ARG();
909dfe2c 290 *type = *argv;
1d934839
PM
291 argc--; argv++;
292 break;
ace9c961
SH
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;
1d934839 299 } else {
909dfe2c 300 if (strcmp(*argv, "dev") == 0) {
1d934839
PM
301 NEXT_ARG();
302 }
05325552
PM
303 if (matches(*argv, "help") == 0)
304 usage();
909dfe2c 305 if (*dev)
1d934839 306 duparg2("dev", *argv);
909dfe2c 307 *dev = *argv;
1d934839
PM
308 }
309 argc--; argv++;
310 }
311
909dfe2c
PE
312 return ret - argc;
313}
314
315static 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;
1d934839
PM
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;
3ef0c859
PM
365 } else if (flags & NLM_F_CREATE) {
366 fprintf(stderr, "Not enough information: \"type\" argument "
367 "is required\n");
368 return -1;
1d934839
PM
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;
ca78b0e7
PM
403 if (len == 1)
404 invarg("\"\" is not a valid device identifier\n", "name");
1d934839 405 if (len > IFNAMSIZ)
ca78b0e7 406 invarg("\"name\" too long\n", name);
1d934839
PM
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
aba5acdf
SH
417static 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
71058eb8 437static int do_chflags(const char *dev, __u32 flags, __u32 mask)
aba5acdf
SH
438{
439 struct ifreq ifr;
440 int fd;
441 int err;
442
71058eb8 443 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
aba5acdf
SH
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
71058eb8 464static int do_changename(const char *dev, const char *newdev)
aba5acdf
SH
465{
466 struct ifreq ifr;
467 int fd;
468 int err;
469
71058eb8
SH
470 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
471 strncpy(ifr.ifr_newname, newdev, IFNAMSIZ);
aba5acdf
SH
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
71058eb8 485static int set_qlen(const char *dev, int qlen)
aba5acdf
SH
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));
ae665a52
SH
495 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
496 ifr.ifr_qlen = qlen;
aba5acdf
SH
497 if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) {
498 perror("SIOCSIFXQLEN");
499 close(s);
500 return -1;
501 }
502 close(s);
503
ae665a52 504 return 0;
aba5acdf
SH
505}
506
71058eb8 507static int set_mtu(const char *dev, int mtu)
aba5acdf
SH
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));
ae665a52
SH
517 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
518 ifr.ifr_mtu = mtu;
aba5acdf
SH
519 if (ioctl(s, SIOCSIFMTU, &ifr) < 0) {
520 perror("SIOCSIFMTU");
521 close(s);
522 return -1;
523 }
524 close(s);
525
ae665a52 526 return 0;
aba5acdf
SH
527}
528
71058eb8 529static int get_address(const char *dev, int *htype)
aba5acdf
SH
530{
531 struct ifreq ifr;
532 struct sockaddr_ll me;
f332d169 533 socklen_t alen;
aba5acdf
SH
534 int s;
535
536 s = socket(PF_PACKET, SOCK_DGRAM, 0);
ae665a52 537 if (s < 0) {
aba5acdf
SH
538 perror("socket(PF_PACKET)");
539 return -1;
540 }
541
542 memset(&ifr, 0, sizeof(ifr));
71058eb8 543 strncpy(ifr.ifr_name, dev, IFNAMSIZ);
aba5acdf
SH
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
ae665a52 571static int parse_address(const char *dev, int hatype, int halen,
7b565754 572 char *lla, struct ifreq *ifr)
aba5acdf
SH
573{
574 int alen;
575
576 memset(ifr, 0, sizeof(*ifr));
71058eb8 577 strncpy(ifr->ifr_name, dev, IFNAMSIZ);
aba5acdf
SH
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 }
ae665a52 586 return 0;
aba5acdf
SH
587}
588
589static 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);
ae665a52 602 return 0;
aba5acdf
SH
603}
604
605
606static 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");
d27b1b5b 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");
aba5acdf
SH
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)
ae665a52 734 return -1;
aba5acdf
SH
735 }
736 }
737
738 if (newname && strcmp(dev, newname)) {
ca78b0e7
PM
739 if (strlen(newname) == 0)
740 invarg("\"\" is not a valid device identifier\n", "name");
aba5acdf
SH
741 if (do_changename(dev, newname) < 0)
742 return -1;
743 dev = newname;
744 }
ae665a52 745 if (qlen != -1) {
aba5acdf 746 if (set_qlen(dev, qlen) < 0)
ae665a52 747 return -1;
aba5acdf 748 }
ae665a52 749 if (mtu != -1) {
aba5acdf 750 if (set_mtu(dev, mtu) < 0)
ae665a52 751 return -1;
aba5acdf
SH
752 }
753 if (newaddr || newbrd) {
754 if (newbrd) {
755 if (set_address(&ifr1, 1) < 0)
ae665a52 756 return -1;
aba5acdf
SH
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}
1d934839 767#endif /* IPLINK_IOCTL_COMPAT */
aba5acdf
SH
768
769int do_iplink(int argc, char **argv)
770{
771 if (argc > 0) {
1d934839
PM
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 }
aba5acdf
SH
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}