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