iplink.c revision 053255520216654c6914e84b0a37e86c542898bd
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)); 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), LIBDIR "/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 (matches(*argv, "help") == 0) 278 usage(); 279 if (*dev) 280 duparg2("dev", *argv); 281 *dev = *argv; 282 } 283 argc--; argv++; 284 } 285 286 return ret - argc; 287} 288 289static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv) 290{ 291 int len; 292 char *dev = NULL; 293 char *name = NULL; 294 char *link = NULL; 295 char *type = NULL; 296 struct link_util *lu = NULL; 297 struct iplink_req req; 298 int ret; 299 300 memset(&req, 0, sizeof(req)); 301 302 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); 303 req.n.nlmsg_flags = NLM_F_REQUEST|flags; 304 req.n.nlmsg_type = cmd; 305 req.i.ifi_family = preferred_family; 306 307 ret = iplink_parse(argc, argv, &req, &name, &type, &link, &dev); 308 if (ret < 0) 309 return ret; 310 311 argc -= ret; 312 argv += ret; 313 ll_init_map(&rth); 314 315 if (type) { 316 struct rtattr *linkinfo = NLMSG_TAIL(&req.n); 317 addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0); 318 addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type, 319 strlen(type)); 320 321 lu = get_link_kind(type); 322 if (lu && argc) { 323 struct rtattr * data = NLMSG_TAIL(&req.n); 324 addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0); 325 326 if (lu->parse_opt && 327 lu->parse_opt(lu, argc, argv, &req.n)) 328 return -1; 329 330 data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; 331 } else if (argc) { 332 if (matches(*argv, "help") == 0) 333 usage(); 334 fprintf(stderr, "Garbage instead of arguments \"%s ...\". " 335 "Try \"ip link help\".\n", *argv); 336 return -1; 337 } 338 linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; 339 } 340 341 if (!(flags & NLM_F_CREATE)) { 342 if (!dev) { 343 fprintf(stderr, "Not enough information: \"dev\" " 344 "argument is required.\n"); 345 exit(-1); 346 } 347 348 req.i.ifi_index = ll_name_to_index(dev); 349 if (req.i.ifi_index == 0) { 350 fprintf(stderr, "Cannot find device \"%s\"\n", dev); 351 return -1; 352 } 353 } else { 354 /* Allow "ip link add dev" and "ip link add name" */ 355 if (!name) 356 name = dev; 357 358 if (link) { 359 int ifindex; 360 361 ifindex = ll_name_to_index(link); 362 if (ifindex == 0) { 363 fprintf(stderr, "Cannot find device \"%s\"\n", 364 link); 365 return -1; 366 } 367 addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifindex, 4); 368 } 369 } 370 371 if (name) { 372 len = strlen(name) + 1; 373 if (len == 1) 374 invarg("\"\" is not a valid device identifier\n", "name"); 375 if (len > IFNAMSIZ) 376 invarg("\"name\" too long\n", name); 377 addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len); 378 } 379 380 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) 381 exit(2); 382 383 return 0; 384} 385 386#if IPLINK_IOCTL_COMPAT 387static int get_ctl_fd(void) 388{ 389 int s_errno; 390 int fd; 391 392 fd = socket(PF_INET, SOCK_DGRAM, 0); 393 if (fd >= 0) 394 return fd; 395 s_errno = errno; 396 fd = socket(PF_PACKET, SOCK_DGRAM, 0); 397 if (fd >= 0) 398 return fd; 399 fd = socket(PF_INET6, SOCK_DGRAM, 0); 400 if (fd >= 0) 401 return fd; 402 errno = s_errno; 403 perror("Cannot create control socket"); 404 return -1; 405} 406 407static int do_chflags(const char *dev, __u32 flags, __u32 mask) 408{ 409 struct ifreq ifr; 410 int fd; 411 int err; 412 413 strncpy(ifr.ifr_name, dev, IFNAMSIZ); 414 fd = get_ctl_fd(); 415 if (fd < 0) 416 return -1; 417 err = ioctl(fd, SIOCGIFFLAGS, &ifr); 418 if (err) { 419 perror("SIOCGIFFLAGS"); 420 close(fd); 421 return -1; 422 } 423 if ((ifr.ifr_flags^flags)&mask) { 424 ifr.ifr_flags &= ~mask; 425 ifr.ifr_flags |= mask&flags; 426 err = ioctl(fd, SIOCSIFFLAGS, &ifr); 427 if (err) 428 perror("SIOCSIFFLAGS"); 429 } 430 close(fd); 431 return err; 432} 433 434static int do_changename(const char *dev, const char *newdev) 435{ 436 struct ifreq ifr; 437 int fd; 438 int err; 439 440 strncpy(ifr.ifr_name, dev, IFNAMSIZ); 441 strncpy(ifr.ifr_newname, newdev, IFNAMSIZ); 442 fd = get_ctl_fd(); 443 if (fd < 0) 444 return -1; 445 err = ioctl(fd, SIOCSIFNAME, &ifr); 446 if (err) { 447 perror("SIOCSIFNAME"); 448 close(fd); 449 return -1; 450 } 451 close(fd); 452 return err; 453} 454 455static int set_qlen(const char *dev, int qlen) 456{ 457 struct ifreq ifr; 458 int s; 459 460 s = get_ctl_fd(); 461 if (s < 0) 462 return -1; 463 464 memset(&ifr, 0, sizeof(ifr)); 465 strncpy(ifr.ifr_name, dev, IFNAMSIZ); 466 ifr.ifr_qlen = qlen; 467 if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) { 468 perror("SIOCSIFXQLEN"); 469 close(s); 470 return -1; 471 } 472 close(s); 473 474 return 0; 475} 476 477static int set_mtu(const char *dev, int mtu) 478{ 479 struct ifreq ifr; 480 int s; 481 482 s = get_ctl_fd(); 483 if (s < 0) 484 return -1; 485 486 memset(&ifr, 0, sizeof(ifr)); 487 strncpy(ifr.ifr_name, dev, IFNAMSIZ); 488 ifr.ifr_mtu = mtu; 489 if (ioctl(s, SIOCSIFMTU, &ifr) < 0) { 490 perror("SIOCSIFMTU"); 491 close(s); 492 return -1; 493 } 494 close(s); 495 496 return 0; 497} 498 499static int get_address(const char *dev, int *htype) 500{ 501 struct ifreq ifr; 502 struct sockaddr_ll me; 503 socklen_t alen; 504 int s; 505 506 s = socket(PF_PACKET, SOCK_DGRAM, 0); 507 if (s < 0) { 508 perror("socket(PF_PACKET)"); 509 return -1; 510 } 511 512 memset(&ifr, 0, sizeof(ifr)); 513 strncpy(ifr.ifr_name, dev, IFNAMSIZ); 514 if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { 515 perror("SIOCGIFINDEX"); 516 close(s); 517 return -1; 518 } 519 520 memset(&me, 0, sizeof(me)); 521 me.sll_family = AF_PACKET; 522 me.sll_ifindex = ifr.ifr_ifindex; 523 me.sll_protocol = htons(ETH_P_LOOP); 524 if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) { 525 perror("bind"); 526 close(s); 527 return -1; 528 } 529 530 alen = sizeof(me); 531 if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) { 532 perror("getsockname"); 533 close(s); 534 return -1; 535 } 536 close(s); 537 *htype = me.sll_hatype; 538 return me.sll_halen; 539} 540 541static int parse_address(const char *dev, int hatype, int halen, 542 char *lla, struct ifreq *ifr) 543{ 544 int alen; 545 546 memset(ifr, 0, sizeof(*ifr)); 547 strncpy(ifr->ifr_name, dev, IFNAMSIZ); 548 ifr->ifr_hwaddr.sa_family = hatype; 549 alen = ll_addr_a2n(ifr->ifr_hwaddr.sa_data, 14, lla); 550 if (alen < 0) 551 return -1; 552 if (alen != halen) { 553 fprintf(stderr, "Wrong address (%s) length: expected %d bytes\n", lla, halen); 554 return -1; 555 } 556 return 0; 557} 558 559static int set_address(struct ifreq *ifr, int brd) 560{ 561 int s; 562 563 s = get_ctl_fd(); 564 if (s < 0) 565 return -1; 566 if (ioctl(s, brd?SIOCSIFHWBROADCAST:SIOCSIFHWADDR, ifr) < 0) { 567 perror(brd?"SIOCSIFHWBROADCAST":"SIOCSIFHWADDR"); 568 close(s); 569 return -1; 570 } 571 close(s); 572 return 0; 573} 574 575 576static int do_set(int argc, char **argv) 577{ 578 char *dev = NULL; 579 __u32 mask = 0; 580 __u32 flags = 0; 581 int qlen = -1; 582 int mtu = -1; 583 char *newaddr = NULL; 584 char *newbrd = NULL; 585 struct ifreq ifr0, ifr1; 586 char *newname = NULL; 587 int htype, halen; 588 589 while (argc > 0) { 590 if (strcmp(*argv, "up") == 0) { 591 mask |= IFF_UP; 592 flags |= IFF_UP; 593 } else if (strcmp(*argv, "down") == 0) { 594 mask |= IFF_UP; 595 flags &= ~IFF_UP; 596 } else if (strcmp(*argv, "name") == 0) { 597 NEXT_ARG(); 598 newname = *argv; 599 } else if (matches(*argv, "address") == 0) { 600 NEXT_ARG(); 601 newaddr = *argv; 602 } else if (matches(*argv, "broadcast") == 0 || 603 strcmp(*argv, "brd") == 0) { 604 NEXT_ARG(); 605 newbrd = *argv; 606 } else if (matches(*argv, "txqueuelen") == 0 || 607 strcmp(*argv, "qlen") == 0 || 608 matches(*argv, "txqlen") == 0) { 609 NEXT_ARG(); 610 if (qlen != -1) 611 duparg("txqueuelen", *argv); 612 if (get_integer(&qlen, *argv, 0)) 613 invarg("Invalid \"txqueuelen\" value\n", *argv); 614 } else if (strcmp(*argv, "mtu") == 0) { 615 NEXT_ARG(); 616 if (mtu != -1) 617 duparg("mtu", *argv); 618 if (get_integer(&mtu, *argv, 0)) 619 invarg("Invalid \"mtu\" value\n", *argv); 620 } else if (strcmp(*argv, "multicast") == 0) { 621 NEXT_ARG(); 622 mask |= IFF_MULTICAST; 623 if (strcmp(*argv, "on") == 0) { 624 flags |= IFF_MULTICAST; 625 } else if (strcmp(*argv, "off") == 0) { 626 flags &= ~IFF_MULTICAST; 627 } else 628 return on_off("multicast"); 629 } else if (strcmp(*argv, "allmulticast") == 0) { 630 NEXT_ARG(); 631 mask |= IFF_ALLMULTI; 632 if (strcmp(*argv, "on") == 0) { 633 flags |= IFF_ALLMULTI; 634 } else if (strcmp(*argv, "off") == 0) { 635 flags &= ~IFF_ALLMULTI; 636 } else 637 return on_off("allmulticast"); 638 } else if (strcmp(*argv, "promisc") == 0) { 639 NEXT_ARG(); 640 mask |= IFF_PROMISC; 641 if (strcmp(*argv, "on") == 0) { 642 flags |= IFF_PROMISC; 643 } else if (strcmp(*argv, "off") == 0) { 644 flags &= ~IFF_PROMISC; 645 } else 646 return on_off("promisc"); 647 } else if (strcmp(*argv, "trailers") == 0) { 648 NEXT_ARG(); 649 mask |= IFF_NOTRAILERS; 650 if (strcmp(*argv, "off") == 0) { 651 flags |= IFF_NOTRAILERS; 652 } else if (strcmp(*argv, "on") == 0) { 653 flags &= ~IFF_NOTRAILERS; 654 } else 655 return on_off("trailers"); 656 } else if (strcmp(*argv, "arp") == 0) { 657 NEXT_ARG(); 658 mask |= IFF_NOARP; 659 if (strcmp(*argv, "on") == 0) { 660 flags &= ~IFF_NOARP; 661 } else if (strcmp(*argv, "off") == 0) { 662 flags |= IFF_NOARP; 663 } else 664 return on_off("noarp"); 665#ifdef IFF_DYNAMIC 666 } else if (matches(*argv, "dynamic") == 0) { 667 NEXT_ARG(); 668 mask |= IFF_DYNAMIC; 669 if (strcmp(*argv, "on") == 0) { 670 flags |= IFF_DYNAMIC; 671 } else if (strcmp(*argv, "off") == 0) { 672 flags &= ~IFF_DYNAMIC; 673 } else 674 return on_off("dynamic"); 675#endif 676 } else { 677 if (strcmp(*argv, "dev") == 0) { 678 NEXT_ARG(); 679 } 680 if (matches(*argv, "help") == 0) 681 usage(); 682 if (dev) 683 duparg2("dev", *argv); 684 dev = *argv; 685 } 686 argc--; argv++; 687 } 688 689 if (!dev) { 690 fprintf(stderr, "Not enough of information: \"dev\" argument is required.\n"); 691 exit(-1); 692 } 693 694 if (newaddr || newbrd) { 695 halen = get_address(dev, &htype); 696 if (halen < 0) 697 return -1; 698 if (newaddr) { 699 if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0) 700 return -1; 701 } 702 if (newbrd) { 703 if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0) 704 return -1; 705 } 706 } 707 708 if (newname && strcmp(dev, newname)) { 709 if (strlen(newname) == 0) 710 invarg("\"\" is not a valid device identifier\n", "name"); 711 if (do_changename(dev, newname) < 0) 712 return -1; 713 dev = newname; 714 } 715 if (qlen != -1) { 716 if (set_qlen(dev, qlen) < 0) 717 return -1; 718 } 719 if (mtu != -1) { 720 if (set_mtu(dev, mtu) < 0) 721 return -1; 722 } 723 if (newaddr || newbrd) { 724 if (newbrd) { 725 if (set_address(&ifr1, 1) < 0) 726 return -1; 727 } 728 if (newaddr) { 729 if (set_address(&ifr0, 0) < 0) 730 return -1; 731 } 732 } 733 if (mask) 734 return do_chflags(dev, flags, mask); 735 return 0; 736} 737#endif /* IPLINK_IOCTL_COMPAT */ 738 739int do_iplink(int argc, char **argv) 740{ 741 if (argc > 0) { 742 if (iplink_have_newlink()) { 743 if (matches(*argv, "add") == 0) 744 return iplink_modify(RTM_NEWLINK, 745 NLM_F_CREATE|NLM_F_EXCL, 746 argc-1, argv+1); 747 if (matches(*argv, "set") == 0 || 748 matches(*argv, "change") == 0) 749 return iplink_modify(RTM_NEWLINK, 0, 750 argc-1, argv+1); 751 if (matches(*argv, "replace") == 0) 752 return iplink_modify(RTM_NEWLINK, 753 NLM_F_CREATE|NLM_F_REPLACE, 754 argc-1, argv+1); 755 if (matches(*argv, "delete") == 0) 756 return iplink_modify(RTM_DELLINK, 0, 757 argc-1, argv+1); 758 } else { 759#if IPLINK_IOCTL_COMPAT 760 if (matches(*argv, "set") == 0) 761 return do_set(argc-1, argv+1); 762#endif 763 } 764 if (matches(*argv, "show") == 0 || 765 matches(*argv, "lst") == 0 || 766 matches(*argv, "list") == 0) 767 return ipaddr_list_link(argc-1, argv+1); 768 if (matches(*argv, "help") == 0) 769 usage(); 770 } else 771 return ipaddr_list_link(0, NULL); 772 773 fprintf(stderr, "Command \"%s\" is unknown, try \"ip link help\".\n", *argv); 774 exit(-1); 775} 776