iplink.c revision ace9c96121b10ff8f91d79b7486bb8a5520c12df
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 40static void usage(void) __attribute__((noreturn)); 41static int iplink_have_newlink(void); 42 43void 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 | dummy | ifb | macvlan }\n"); 76 } 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 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 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 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 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 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 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) 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 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; 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 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 437static 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 464static 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 485static 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 507static 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 529static 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 571static 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 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); 602 return 0; 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"); 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 769int 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} 806