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