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