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