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