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