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