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