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