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