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