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