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