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