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