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