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