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 (strcasecmp(mode, "default") == 0) 138 return IF_LINK_MODE_DEFAULT; 139 if (strcasecmp(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 if (strcmp(*argv, "state") == 0) { 441 int state; 442 NEXT_ARG(); 443 state = get_operstate(*argv); 444 if (state < 0) 445 invarg("Invalid operstate\n", *argv); 446 447 addattr8(&req->n, sizeof(*req), IFLA_OPERSTATE, state); 448 } else { 449 if (strcmp(*argv, "dev") == 0) { 450 NEXT_ARG(); 451 } 452 if (matches(*argv, "help") == 0) 453 usage(); 454 if (*dev) 455 duparg2("dev", *argv); 456 *dev = *argv; 457 } 458 argc--; argv++; 459 } 460 461 return ret - argc; 462} 463 464static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv) 465{ 466 int len; 467 char *dev = NULL; 468 char *name = NULL; 469 char *link = NULL; 470 char *type = NULL; 471 int group; 472 struct link_util *lu = NULL; 473 struct iplink_req req; 474 int ret; 475 476 memset(&req, 0, sizeof(req)); 477 478 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); 479 req.n.nlmsg_flags = NLM_F_REQUEST|flags; 480 req.n.nlmsg_type = cmd; 481 req.i.ifi_family = preferred_family; 482 483 ret = iplink_parse(argc, argv, &req, &name, &type, &link, &dev, &group); 484 if (ret < 0) 485 return ret; 486 487 argc -= ret; 488 argv += ret; 489 490 if (group != -1) { 491 if (dev) 492 addattr_l(&req.n, sizeof(req), IFLA_GROUP, 493 &group, sizeof(group)); 494 else { 495 if (argc) { 496 fprintf(stderr, "Garbage instead of arguments " 497 "\"%s ...\". Try \"ip link " 498 "help\".\n", *argv); 499 return -1; 500 } 501 if (flags & NLM_F_CREATE) { 502 fprintf(stderr, "group cannot be used when " 503 "creating devices.\n"); 504 return -1; 505 } 506 507 req.i.ifi_index = 0; 508 addattr32(&req.n, sizeof(req), IFLA_GROUP, group); 509 if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) 510 exit(2); 511 return 0; 512 } 513 } 514 515 ll_init_map(&rth); 516 517 if (!(flags & NLM_F_CREATE)) { 518 if (!dev) { 519 fprintf(stderr, "Not enough information: \"dev\" " 520 "argument is required.\n"); 521 exit(-1); 522 } 523 524 req.i.ifi_index = ll_name_to_index(dev); 525 if (req.i.ifi_index == 0) { 526 fprintf(stderr, "Cannot find device \"%s\"\n", dev); 527 return -1; 528 } 529 } else { 530 /* Allow "ip link add dev" and "ip link add name" */ 531 if (!name) 532 name = dev; 533 534 if (link) { 535 int ifindex; 536 537 ifindex = ll_name_to_index(link); 538 if (ifindex == 0) { 539 fprintf(stderr, "Cannot find device \"%s\"\n", 540 link); 541 return -1; 542 } 543 addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifindex, 4); 544 } 545 } 546 547 if (name) { 548 len = strlen(name) + 1; 549 if (len == 1) 550 invarg("\"\" is not a valid device identifier\n", "name"); 551 if (len > IFNAMSIZ) 552 invarg("\"name\" too long\n", name); 553 addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len); 554 } 555 556 if (type) { 557 struct rtattr *linkinfo = NLMSG_TAIL(&req.n); 558 addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0); 559 addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type, 560 strlen(type)); 561 562 lu = get_link_kind(type); 563 if (lu && argc) { 564 struct rtattr * data = NLMSG_TAIL(&req.n); 565 addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0); 566 567 if (lu->parse_opt && 568 lu->parse_opt(lu, argc, argv, &req.n)) 569 return -1; 570 571 data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; 572 } else if (argc) { 573 if (matches(*argv, "help") == 0) 574 usage(); 575 fprintf(stderr, "Garbage instead of arguments \"%s ...\". " 576 "Try \"ip link help\".\n", *argv); 577 return -1; 578 } 579 linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; 580 } else if (flags & NLM_F_CREATE) { 581 fprintf(stderr, "Not enough information: \"type\" argument " 582 "is required\n"); 583 return -1; 584 } 585 586 if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0) 587 exit(2); 588 589 return 0; 590} 591 592#if IPLINK_IOCTL_COMPAT 593static int get_ctl_fd(void) 594{ 595 int s_errno; 596 int fd; 597 598 fd = socket(PF_INET, SOCK_DGRAM, 0); 599 if (fd >= 0) 600 return fd; 601 s_errno = errno; 602 fd = socket(PF_PACKET, SOCK_DGRAM, 0); 603 if (fd >= 0) 604 return fd; 605 fd = socket(PF_INET6, SOCK_DGRAM, 0); 606 if (fd >= 0) 607 return fd; 608 errno = s_errno; 609 perror("Cannot create control socket"); 610 return -1; 611} 612 613static int do_chflags(const char *dev, __u32 flags, __u32 mask) 614{ 615 struct ifreq ifr; 616 int fd; 617 int err; 618 619 strncpy(ifr.ifr_name, dev, IFNAMSIZ); 620 fd = get_ctl_fd(); 621 if (fd < 0) 622 return -1; 623 err = ioctl(fd, SIOCGIFFLAGS, &ifr); 624 if (err) { 625 perror("SIOCGIFFLAGS"); 626 close(fd); 627 return -1; 628 } 629 if ((ifr.ifr_flags^flags)&mask) { 630 ifr.ifr_flags &= ~mask; 631 ifr.ifr_flags |= mask&flags; 632 err = ioctl(fd, SIOCSIFFLAGS, &ifr); 633 if (err) 634 perror("SIOCSIFFLAGS"); 635 } 636 close(fd); 637 return err; 638} 639 640static int do_changename(const char *dev, const char *newdev) 641{ 642 struct ifreq ifr; 643 int fd; 644 int err; 645 646 strncpy(ifr.ifr_name, dev, IFNAMSIZ); 647 strncpy(ifr.ifr_newname, newdev, IFNAMSIZ); 648 fd = get_ctl_fd(); 649 if (fd < 0) 650 return -1; 651 err = ioctl(fd, SIOCSIFNAME, &ifr); 652 if (err) { 653 perror("SIOCSIFNAME"); 654 close(fd); 655 return -1; 656 } 657 close(fd); 658 return err; 659} 660 661static int set_qlen(const char *dev, int qlen) 662{ 663 struct ifreq ifr; 664 int s; 665 666 s = get_ctl_fd(); 667 if (s < 0) 668 return -1; 669 670 memset(&ifr, 0, sizeof(ifr)); 671 strncpy(ifr.ifr_name, dev, IFNAMSIZ); 672 ifr.ifr_qlen = qlen; 673 if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) { 674 perror("SIOCSIFXQLEN"); 675 close(s); 676 return -1; 677 } 678 close(s); 679 680 return 0; 681} 682 683static int set_mtu(const char *dev, int mtu) 684{ 685 struct ifreq ifr; 686 int s; 687 688 s = get_ctl_fd(); 689 if (s < 0) 690 return -1; 691 692 memset(&ifr, 0, sizeof(ifr)); 693 strncpy(ifr.ifr_name, dev, IFNAMSIZ); 694 ifr.ifr_mtu = mtu; 695 if (ioctl(s, SIOCSIFMTU, &ifr) < 0) { 696 perror("SIOCSIFMTU"); 697 close(s); 698 return -1; 699 } 700 close(s); 701 702 return 0; 703} 704 705static int get_address(const char *dev, int *htype) 706{ 707 struct ifreq ifr; 708 struct sockaddr_ll me; 709 socklen_t alen; 710 int s; 711 712 s = socket(PF_PACKET, SOCK_DGRAM, 0); 713 if (s < 0) { 714 perror("socket(PF_PACKET)"); 715 return -1; 716 } 717 718 memset(&ifr, 0, sizeof(ifr)); 719 strncpy(ifr.ifr_name, dev, IFNAMSIZ); 720 if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { 721 perror("SIOCGIFINDEX"); 722 close(s); 723 return -1; 724 } 725 726 memset(&me, 0, sizeof(me)); 727 me.sll_family = AF_PACKET; 728 me.sll_ifindex = ifr.ifr_ifindex; 729 me.sll_protocol = htons(ETH_P_LOOP); 730 if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) { 731 perror("bind"); 732 close(s); 733 return -1; 734 } 735 736 alen = sizeof(me); 737 if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) { 738 perror("getsockname"); 739 close(s); 740 return -1; 741 } 742 close(s); 743 *htype = me.sll_hatype; 744 return me.sll_halen; 745} 746 747static int parse_address(const char *dev, int hatype, int halen, 748 char *lla, struct ifreq *ifr) 749{ 750 int alen; 751 752 memset(ifr, 0, sizeof(*ifr)); 753 strncpy(ifr->ifr_name, dev, IFNAMSIZ); 754 ifr->ifr_hwaddr.sa_family = hatype; 755 alen = ll_addr_a2n(ifr->ifr_hwaddr.sa_data, 14, lla); 756 if (alen < 0) 757 return -1; 758 if (alen != halen) { 759 fprintf(stderr, "Wrong address (%s) length: expected %d bytes\n", lla, halen); 760 return -1; 761 } 762 return 0; 763} 764 765static int set_address(struct ifreq *ifr, int brd) 766{ 767 int s; 768 769 s = get_ctl_fd(); 770 if (s < 0) 771 return -1; 772 if (ioctl(s, brd?SIOCSIFHWBROADCAST:SIOCSIFHWADDR, ifr) < 0) { 773 perror(brd?"SIOCSIFHWBROADCAST":"SIOCSIFHWADDR"); 774 close(s); 775 return -1; 776 } 777 close(s); 778 return 0; 779} 780 781 782static int do_set(int argc, char **argv) 783{ 784 char *dev = NULL; 785 __u32 mask = 0; 786 __u32 flags = 0; 787 int qlen = -1; 788 int mtu = -1; 789 char *newaddr = NULL; 790 char *newbrd = NULL; 791 struct ifreq ifr0, ifr1; 792 char *newname = NULL; 793 int htype, halen; 794 795 while (argc > 0) { 796 if (strcmp(*argv, "up") == 0) { 797 mask |= IFF_UP; 798 flags |= IFF_UP; 799 } else if (strcmp(*argv, "down") == 0) { 800 mask |= IFF_UP; 801 flags &= ~IFF_UP; 802 } else if (strcmp(*argv, "name") == 0) { 803 NEXT_ARG(); 804 newname = *argv; 805 } else if (matches(*argv, "address") == 0) { 806 NEXT_ARG(); 807 newaddr = *argv; 808 } else if (matches(*argv, "broadcast") == 0 || 809 strcmp(*argv, "brd") == 0) { 810 NEXT_ARG(); 811 newbrd = *argv; 812 } else if (matches(*argv, "txqueuelen") == 0 || 813 strcmp(*argv, "qlen") == 0 || 814 matches(*argv, "txqlen") == 0) { 815 NEXT_ARG(); 816 if (qlen != -1) 817 duparg("txqueuelen", *argv); 818 if (get_integer(&qlen, *argv, 0)) 819 invarg("Invalid \"txqueuelen\" value\n", *argv); 820 } else if (strcmp(*argv, "mtu") == 0) { 821 NEXT_ARG(); 822 if (mtu != -1) 823 duparg("mtu", *argv); 824 if (get_integer(&mtu, *argv, 0)) 825 invarg("Invalid \"mtu\" value\n", *argv); 826 } else if (strcmp(*argv, "multicast") == 0) { 827 NEXT_ARG(); 828 mask |= IFF_MULTICAST; 829 if (strcmp(*argv, "on") == 0) { 830 flags |= IFF_MULTICAST; 831 } else if (strcmp(*argv, "off") == 0) { 832 flags &= ~IFF_MULTICAST; 833 } else 834 return on_off("multicast"); 835 } else if (strcmp(*argv, "allmulticast") == 0) { 836 NEXT_ARG(); 837 mask |= IFF_ALLMULTI; 838 if (strcmp(*argv, "on") == 0) { 839 flags |= IFF_ALLMULTI; 840 } else if (strcmp(*argv, "off") == 0) { 841 flags &= ~IFF_ALLMULTI; 842 } else 843 return on_off("allmulticast"); 844 } else if (strcmp(*argv, "promisc") == 0) { 845 NEXT_ARG(); 846 mask |= IFF_PROMISC; 847 if (strcmp(*argv, "on") == 0) { 848 flags |= IFF_PROMISC; 849 } else if (strcmp(*argv, "off") == 0) { 850 flags &= ~IFF_PROMISC; 851 } else 852 return on_off("promisc"); 853 } else if (strcmp(*argv, "trailers") == 0) { 854 NEXT_ARG(); 855 mask |= IFF_NOTRAILERS; 856 if (strcmp(*argv, "off") == 0) { 857 flags |= IFF_NOTRAILERS; 858 } else if (strcmp(*argv, "on") == 0) { 859 flags &= ~IFF_NOTRAILERS; 860 } else 861 return on_off("trailers"); 862 } else if (strcmp(*argv, "arp") == 0) { 863 NEXT_ARG(); 864 mask |= IFF_NOARP; 865 if (strcmp(*argv, "on") == 0) { 866 flags &= ~IFF_NOARP; 867 } else if (strcmp(*argv, "off") == 0) { 868 flags |= IFF_NOARP; 869 } else 870 return on_off("noarp"); 871 } else if (matches(*argv, "dynamic") == 0) { 872 NEXT_ARG(); 873 mask |= IFF_DYNAMIC; 874 if (strcmp(*argv, "on") == 0) { 875 flags |= IFF_DYNAMIC; 876 } else if (strcmp(*argv, "off") == 0) { 877 flags &= ~IFF_DYNAMIC; 878 } else 879 return on_off("dynamic"); 880 } else { 881 if (strcmp(*argv, "dev") == 0) { 882 NEXT_ARG(); 883 } 884 if (matches(*argv, "help") == 0) 885 usage(); 886 if (dev) 887 duparg2("dev", *argv); 888 dev = *argv; 889 } 890 argc--; argv++; 891 } 892 893 if (!dev) { 894 fprintf(stderr, "Not enough of information: \"dev\" argument is required.\n"); 895 exit(-1); 896 } 897 898 if (newaddr || newbrd) { 899 halen = get_address(dev, &htype); 900 if (halen < 0) 901 return -1; 902 if (newaddr) { 903 if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0) 904 return -1; 905 } 906 if (newbrd) { 907 if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0) 908 return -1; 909 } 910 } 911 912 if (newname && strcmp(dev, newname)) { 913 if (strlen(newname) == 0) 914 invarg("\"\" is not a valid device identifier\n", "name"); 915 if (do_changename(dev, newname) < 0) 916 return -1; 917 dev = newname; 918 } 919 if (qlen != -1) { 920 if (set_qlen(dev, qlen) < 0) 921 return -1; 922 } 923 if (mtu != -1) { 924 if (set_mtu(dev, mtu) < 0) 925 return -1; 926 } 927 if (newaddr || newbrd) { 928 if (newbrd) { 929 if (set_address(&ifr1, 1) < 0) 930 return -1; 931 } 932 if (newaddr) { 933 if (set_address(&ifr0, 0) < 0) 934 return -1; 935 } 936 } 937 if (mask) 938 return do_chflags(dev, flags, mask); 939 return 0; 940} 941#endif /* IPLINK_IOCTL_COMPAT */ 942 943int do_iplink(int argc, char **argv) 944{ 945 if (argc > 0) { 946 if (iplink_have_newlink()) { 947 if (matches(*argv, "add") == 0) 948 return iplink_modify(RTM_NEWLINK, 949 NLM_F_CREATE|NLM_F_EXCL, 950 argc-1, argv+1); 951 if (matches(*argv, "set") == 0 || 952 matches(*argv, "change") == 0) 953 return iplink_modify(RTM_NEWLINK, 0, 954 argc-1, argv+1); 955 if (matches(*argv, "replace") == 0) 956 return iplink_modify(RTM_NEWLINK, 957 NLM_F_CREATE|NLM_F_REPLACE, 958 argc-1, argv+1); 959 if (matches(*argv, "delete") == 0) 960 return iplink_modify(RTM_DELLINK, 0, 961 argc-1, argv+1); 962 } else { 963#if IPLINK_IOCTL_COMPAT 964 if (matches(*argv, "set") == 0) 965 return do_set(argc-1, argv+1); 966#endif 967 } 968 if (matches(*argv, "show") == 0 || 969 matches(*argv, "lst") == 0 || 970 matches(*argv, "list") == 0) 971 return ipaddr_list_link(argc-1, argv+1); 972 if (matches(*argv, "help") == 0) 973 usage(); 974 } else 975 return ipaddr_list_link(0, NULL); 976 977 fprintf(stderr, "Command \"%s\" is unknown, try \"ip link help\".\n", *argv); 978 exit(-1); 979} 980