iplink.c revision 632110aa0db4518b33fc09189ffcdd1b2e2e1762
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 31#include "rt_names.h" 32#include "utils.h" 33#include "ip_common.h" 34 35#define IPLINK_IOCTL_COMPAT 1 36#ifndef LIBDIR 37#define LIBDIR "/usr/lib/" 38#endif 39 40static void usage(void) __attribute__((noreturn)); 41static int iplink_have_newlink(void); 42 43void iplink_usage(void) 44{ 45 if (iplink_have_newlink()) { 46 fprintf(stderr, "Usage: ip link add link DEV [ name ] NAME\n"); 47 fprintf(stderr, " [ txqueuelen PACKETS ]\n"); 48 fprintf(stderr, " [ address LLADDR ]\n"); 49 fprintf(stderr, " [ broadcast LLADDR ]\n"); 50 fprintf(stderr, " [ mtu MTU ]\n"); 51 fprintf(stderr, " type TYPE [ ARGS ]\n"); 52 fprintf(stderr, " ip link delete DEV type TYPE [ ARGS ]\n"); 53 fprintf(stderr, "\n"); 54 fprintf(stderr, " ip link set DEVICE [ { up | down } ]\n"); 55 } else 56 fprintf(stderr, "Usage: ip link set DEVICE [ { up | down } ]\n"); 57 58 fprintf(stderr, " [ arp { on | off } ]\n"); 59 fprintf(stderr, " [ dynamic { on | off } ]\n"); 60 fprintf(stderr, " [ multicast { on | off } ]\n"); 61 fprintf(stderr, " [ allmulticast { on | off } ]\n"); 62 fprintf(stderr, " [ promisc { on | off } ]\n"); 63 fprintf(stderr, " [ trailers { on | off } ]\n"); 64 fprintf(stderr, " [ txqueuelen PACKETS ]\n"); 65 fprintf(stderr, " [ name NEWNAME ]\n"); 66 fprintf(stderr, " [ address LLADDR ]\n"); 67 fprintf(stderr, " [ broadcast LLADDR ]\n"); 68 fprintf(stderr, " [ mtu MTU ]\n"); 69 fprintf(stderr, " [ netns PID ]\n"); 70 fprintf(stderr, " [ alias NAME ]\n"); 71 fprintf(stderr, " [ port MODE { PROFILE | VSI } ]\n"); 72 fprintf(stderr, " [ vf NUM [ mac LLADDR ]\n"); 73 fprintf(stderr, " [ vlan VLANID [ qos VLAN-QOS ] ]\n"); 74 fprintf(stderr, " [ rate TXRATE ]\n"); 75 fprintf(stderr, " [ port MODE { PROFILE | VSI } ] ]\n"); 76 fprintf(stderr, " ip link show [ DEVICE ]\n"); 77 78 if (iplink_have_newlink()) { 79 fprintf(stderr, "\n"); 80 fprintf(stderr, "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | can }\n"); 81 fprintf(stderr, "MODE := { assoc | preassoc | preassocrr | disassoc }\n"); 82 fprintf(stderr, "PROFILE := profile PROFILE\n"); 83 fprintf(stderr, " [ instance UUID ]\n"); 84 fprintf(stderr, " [ host UUID ]\n"); 85 fprintf(stderr, "VSI := vsi mgr MGRID type VTID ver VER\n"); 86 fprintf(stderr, " [ instance UUID ]\n"); 87 } 88 exit(-1); 89} 90 91static void usage(void) 92{ 93 iplink_usage(); 94} 95 96static int on_off(char *msg) 97{ 98 fprintf(stderr, "Error: argument of \"%s\" must be \"on\" or \"off\"\n", msg); 99 return -1; 100} 101 102static void *BODY; /* cached dlopen(NULL) handle */ 103static struct link_util *linkutil_list; 104 105struct link_util *get_link_kind(const char *id) 106{ 107 void *dlh; 108 char buf[256]; 109 struct link_util *l; 110 111 for (l = linkutil_list; l; l = l->next) 112 if (strcmp(l->id, id) == 0) 113 return l; 114 115 snprintf(buf, sizeof(buf), LIBDIR "/ip/link_%s.so", id); 116 dlh = dlopen(buf, RTLD_LAZY); 117 if (dlh == NULL) { 118 /* look in current binary, only open once */ 119 dlh = BODY; 120 if (dlh == NULL) { 121 dlh = BODY = dlopen(NULL, RTLD_LAZY); 122 if (dlh == NULL) 123 return NULL; 124 } 125 } 126 127 snprintf(buf, sizeof(buf), "%s_link_util", id); 128 l = dlsym(dlh, buf); 129 if (l == NULL) 130 return NULL; 131 132 l->next = linkutil_list; 133 linkutil_list = l; 134 return l; 135} 136 137#if IPLINK_IOCTL_COMPAT 138static int have_rtnl_newlink = -1; 139 140static int accept_msg(const struct sockaddr_nl *who, 141 struct nlmsghdr *n, void *arg) 142{ 143 struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n); 144 145 if (n->nlmsg_type == NLMSG_ERROR && 146 (err->error == -EOPNOTSUPP || err->error == -EINVAL)) 147 have_rtnl_newlink = 0; 148 else 149 have_rtnl_newlink = 1; 150 return -1; 151} 152 153static int iplink_have_newlink(void) 154{ 155 struct { 156 struct nlmsghdr n; 157 struct ifinfomsg i; 158 char buf[1024]; 159 } req; 160 161 if (have_rtnl_newlink < 0) { 162 memset(&req, 0, sizeof(req)); 163 164 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); 165 req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; 166 req.n.nlmsg_type = RTM_NEWLINK; 167 req.i.ifi_family = AF_UNSPEC; 168 169 rtnl_send(&rth, (char *)&req.n, req.n.nlmsg_len); 170 rtnl_listen(&rth, accept_msg, NULL); 171 } 172 return have_rtnl_newlink; 173} 174#else /* IPLINK_IOCTL_COMPAT */ 175static int iplink_have_newlink(void) 176{ 177 return 1; 178} 179#endif /* ! IPLINK_IOCTL_COMPAT */ 180 181struct iplink_req { 182 struct nlmsghdr n; 183 struct ifinfomsg i; 184 char buf[1024]; 185}; 186 187void iplink_parse_port(int vf, int *argcp, char ***argvp, 188 struct iplink_req *req) 189{ 190 int argc = *argcp; 191 char **argv = *argvp; 192 struct rtattr *nest, *nest_inner = NULL; 193 struct ifla_port_vsi port_vsi; 194 char *port_profile = NULL; 195 char *instance_uuid = NULL; 196 char *host_uuid = NULL; 197 unsigned char uuid[16]; 198 char *uuid_fmt = "%02X%02X%02X%02X-%02X%02X-%02X%02X-" 199 "%02X%02X-%02X%02X%02X%02X%02X%02X"; 200 int parsed; 201 int manager_id = -1; 202 int type_id = -1; 203 int type_id_version = -1; 204 int request = -1; 205 int vsi = 0; 206 207 if (NEXT_ARG_OK()) { 208 NEXT_ARG(); 209 if (matches(*argv, "assoc") == 0) 210 request = PORT_REQUEST_ASSOCIATE; 211 else if (matches(*argv, "preassoc") == 0) 212 request = PORT_REQUEST_PREASSOCIATE; 213 else if (matches(*argv, "preassocrr") == 0) 214 request = PORT_REQUEST_PREASSOCIATE_RR; 215 else if (matches(*argv, "disassoc") == 0) 216 request = PORT_REQUEST_DISASSOCIATE; 217 } 218 219 while (NEXT_ARG_OK()) { 220 NEXT_ARG(); 221 if (matches(*argv, "vsi") == 0) { 222 vsi = 1; 223 } else if (matches(*argv, "mgr") == 0) { 224 NEXT_ARG(); 225 if (get_integer(&manager_id, *argv, 0)) 226 invarg("Invalid \"mgr\" value\n", *argv); 227 } else if (matches(*argv, "type") == 0) { 228 NEXT_ARG(); 229 if (get_integer(&type_id, *argv, 0)) 230 invarg("Invalid \"type\" value\n", *argv); 231 } else if (matches(*argv, "ver") == 0) { 232 NEXT_ARG(); 233 if (get_integer(&type_id_version, *argv, 0)) 234 invarg("Invalid \"ver\" value\n", *argv); 235 } else if (matches(*argv, "profile") == 0) { 236 NEXT_ARG(); 237 port_profile = *argv; 238 } else if (matches(*argv, "instance") == 0) { 239 NEXT_ARG(); 240 instance_uuid = *argv; 241 } else if (matches(*argv, "host") == 0) { 242 NEXT_ARG(); 243 host_uuid = *argv; 244 } else { 245 /* rewind arg */ 246 PREV_ARG(); 247 break; 248 } 249 } 250 251 if (argc == *argcp) 252 incomplete_command(); 253 254 if (vf == PORT_SELF_VF) { 255 nest = addattr_nest(&req->n, sizeof(*req), IFLA_PORT_SELF); 256 } else { 257 nest = addattr_nest(&req->n, sizeof(*req), IFLA_VF_PORTS); 258 nest_inner = addattr_nest(&req->n, sizeof(*req), IFLA_VF_PORT); 259 addattr_l(&req->n, sizeof(*req), IFLA_PORT_VF, 260 (uint32_t *)&vf, sizeof(uint32_t)); 261 } 262 263 if (port_profile) 264 addattr_l(&req->n, sizeof(*req), IFLA_PORT_PROFILE, 265 port_profile, strlen(port_profile) + 1); 266 267 if (instance_uuid) { 268 parsed = sscanf(instance_uuid, uuid_fmt, 269 &uuid[0], &uuid[1], &uuid[2], &uuid[3], 270 &uuid[4], &uuid[5], &uuid[6], &uuid[7], 271 &uuid[8], &uuid[9], &uuid[10], &uuid[11], 272 &uuid[12], &uuid[13], &uuid[14], &uuid[15]); 273 if (parsed != sizeof(uuid)) 274 invarg("Invalid \"uuid\" value\n", instance_uuid); 275 addattr_l(&req->n, sizeof(*req), IFLA_PORT_INSTANCE_UUID, 276 uuid, sizeof(uuid)); 277 278 } 279 280 if (host_uuid) { 281 parsed = sscanf(host_uuid, uuid_fmt, 282 &uuid[0], &uuid[1], &uuid[2], &uuid[3], 283 &uuid[4], &uuid[5], &uuid[6], &uuid[7], 284 &uuid[8], &uuid[9], &uuid[10], &uuid[11], 285 &uuid[12], &uuid[13], &uuid[14], &uuid[15]); 286 if (parsed != sizeof(uuid)) 287 invarg("Invalid \"uuid\" value\n", host_uuid); 288 addattr_l(&req->n, sizeof(*req), IFLA_PORT_HOST_UUID, 289 uuid, sizeof(uuid)); 290 291 } 292 293 if (vsi) { 294 port_vsi.vsi_mgr_id = manager_id; 295 memcpy(&port_vsi.vsi_type_id, &type_id, 296 sizeof(port_vsi.vsi_type_id)); 297 port_vsi.vsi_type_version = type_id_version; 298 addattr_l(&req->n, sizeof(*req), IFLA_PORT_VSI_TYPE, 299 &port_vsi, sizeof(port_vsi)); 300 } 301 302 addattr_l(&req->n, sizeof(*req), IFLA_PORT_REQUEST, 303 &request, 1); 304 305 if (nest_inner) 306 addattr_nest_end(&req->n, nest_inner); 307 addattr_nest_end(&req->n, nest); 308 309 *argcp = argc; 310 *argvp = argv; 311} 312 313void iplink_parse_vf(int vf, int *argcp, char ***argvp, 314 struct iplink_req *req) 315{ 316 int len, argc = *argcp; 317 char **argv = *argvp; 318 struct rtattr *vflist; 319 struct rtattr *vfinfo; 320 char *mac = NULL; 321 char *vlan = NULL; 322 char *qos = NULL; 323 char *rate = NULL; 324 struct ifla_vf_mac ivm = { .vf = vf, }; 325 struct ifla_vf_vlan ivv = { .vf = vf, .qos = 0, }; 326 struct ifla_vf_tx_rate ivt = { .vf = vf, }; 327 328 while (NEXT_ARG_OK()) { 329 NEXT_ARG(); 330 if (matches(*argv, "port") == 0) { 331 iplink_parse_port(vf, &argc, &argv, req); 332 } else if (matches(*argv, "mac") == 0) { 333 NEXT_ARG(); 334 mac = *argv; 335 } else if (matches(*argv, "vlan") == 0) { 336 NEXT_ARG(); 337 vlan = *argv; 338 if (NEXT_ARG_OK()) { 339 NEXT_ARG(); 340 if (matches(*argv, "qos") == 0) { 341 NEXT_ARG(); 342 qos = *argv; 343 } else { 344 /* rewind arg */ 345 PREV_ARG(); 346 } 347 } 348 } else if (matches(*argv, "rate") == 0) { 349 NEXT_ARG(); 350 rate = *argv; 351 } else { 352 /* rewind arg */ 353 PREV_ARG(); 354 break; 355 } 356 } 357 358 if (argc == *argcp) 359 incomplete_command(); 360 361 if (mac || vlan || rate) { 362 363 vflist = addattr_nest(&req->n, sizeof(*req), IFLA_VFINFO_LIST); 364 vfinfo = addattr_nest(&req->n, sizeof(*req), IFLA_VF_INFO); 365 366 if (mac) { 367 len = ll_addr_a2n((char *)ivm.mac, 32, mac); 368 if (len < 0) 369 invarg("Invalid \"mac\" value\n", mac); 370 addattr_l(&req->n, sizeof(*req), IFLA_VF_MAC, 371 &ivm, sizeof(ivm)); 372 } 373 374 if (vlan) { 375 if (get_unsigned(&ivv.vlan, vlan, 0)) 376 invarg("Invalid \"vlan\" value\n", vlan); 377 if (qos) { 378 if (get_unsigned(&ivv.qos, qos, 0)) 379 invarg("Invalid \"qos\" value\n", qos); 380 } 381 addattr_l(&req->n, sizeof(*req), IFLA_VF_VLAN, 382 &ivv, sizeof(ivv)); 383 } 384 385 if (rate) { 386 if (get_unsigned(&ivt.rate, rate, 0)) 387 invarg("Invalid \"rate\" value\n", rate); 388 addattr_l(&req->n, sizeof(*req), IFLA_VF_TX_RATE, 389 &ivt, sizeof(ivt)); 390 } 391 392 addattr_nest_end(&req->n, vfinfo); 393 addattr_nest_end(&req->n, vflist); 394 } 395 396 *argcp = argc; 397 *argvp = argv; 398} 399 400 401int iplink_parse(int argc, char **argv, struct iplink_req *req, 402 char **name, char **type, char **link, char **dev) 403{ 404 int ret, len; 405 char abuf[32]; 406 int qlen = -1; 407 int mtu = -1; 408 int netns = -1; 409 int vf = -1; 410 411 ret = argc; 412 413 while (argc > 0) { 414 if (strcmp(*argv, "up") == 0) { 415 req->i.ifi_change |= IFF_UP; 416 req->i.ifi_flags |= IFF_UP; 417 } else if (strcmp(*argv, "down") == 0) { 418 req->i.ifi_change |= IFF_UP; 419 req->i.ifi_flags &= ~IFF_UP; 420 } else if (strcmp(*argv, "name") == 0) { 421 NEXT_ARG(); 422 *name = *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 (get_integer(&netns, *argv, 0)) 460 invarg("Invalid \"netns\" value\n", *argv); 461 addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID, &netns, 4); 462 } else if (strcmp(*argv, "multicast") == 0) { 463 NEXT_ARG(); 464 req->i.ifi_change |= IFF_MULTICAST; 465 if (strcmp(*argv, "on") == 0) { 466 req->i.ifi_flags |= IFF_MULTICAST; 467 } else if (strcmp(*argv, "off") == 0) { 468 req->i.ifi_flags &= ~IFF_MULTICAST; 469 } else 470 return on_off("multicast"); 471 } else if (strcmp(*argv, "allmulticast") == 0) { 472 NEXT_ARG(); 473 req->i.ifi_change |= IFF_ALLMULTI; 474 if (strcmp(*argv, "on") == 0) { 475 req->i.ifi_flags |= IFF_ALLMULTI; 476 } else if (strcmp(*argv, "off") == 0) { 477 req->i.ifi_flags &= ~IFF_ALLMULTI; 478 } else 479 return on_off("allmulticast"); 480 } else if (strcmp(*argv, "promisc") == 0) { 481 NEXT_ARG(); 482 req->i.ifi_change |= IFF_PROMISC; 483 if (strcmp(*argv, "on") == 0) { 484 req->i.ifi_flags |= IFF_PROMISC; 485 } else if (strcmp(*argv, "off") == 0) { 486 req->i.ifi_flags &= ~IFF_PROMISC; 487 } else 488 return on_off("promisc"); 489 } else if (strcmp(*argv, "trailers") == 0) { 490 NEXT_ARG(); 491 req->i.ifi_change |= IFF_NOTRAILERS; 492 if (strcmp(*argv, "off") == 0) { 493 req->i.ifi_flags |= IFF_NOTRAILERS; 494 } else if (strcmp(*argv, "on") == 0) { 495 req->i.ifi_flags &= ~IFF_NOTRAILERS; 496 } else 497 return on_off("trailers"); 498 } else if (strcmp(*argv, "arp") == 0) { 499 NEXT_ARG(); 500 req->i.ifi_change |= IFF_NOARP; 501 if (strcmp(*argv, "on") == 0) { 502 req->i.ifi_flags &= ~IFF_NOARP; 503 } else if (strcmp(*argv, "off") == 0) { 504 req->i.ifi_flags |= IFF_NOARP; 505 } else 506 return on_off("noarp"); 507 } else if (strcmp(*argv, "port") == 0) { 508 iplink_parse_port(vf, &argc, &argv, req); 509 } else if (strcmp(*argv, "vf") == 0) { 510 NEXT_ARG(); 511 if (get_integer(&vf, *argv, 0)) { 512 invarg("Invalid \"vf\" value\n", *argv); 513 } 514 iplink_parse_vf(vf, &argc, &argv, req); 515#ifdef IFF_DYNAMIC 516 } else if (matches(*argv, "dynamic") == 0) { 517 NEXT_ARG(); 518 req->i.ifi_change |= IFF_DYNAMIC; 519 if (strcmp(*argv, "on") == 0) { 520 req->i.ifi_flags |= IFF_DYNAMIC; 521 } else if (strcmp(*argv, "off") == 0) { 522 req->i.ifi_flags &= ~IFF_DYNAMIC; 523 } else 524 return on_off("dynamic"); 525#endif 526 } else if (matches(*argv, "type") == 0) { 527 NEXT_ARG(); 528 *type = *argv; 529 argc--; argv++; 530 break; 531 } else if (matches(*argv, "alias") == 0) { 532 NEXT_ARG(); 533 addattr_l(&req->n, sizeof(*req), IFLA_IFALIAS, 534 *argv, strlen(*argv)); 535 argc--; argv++; 536 break; 537 } else { 538 if (strcmp(*argv, "dev") == 0) { 539 NEXT_ARG(); 540 } 541 if (matches(*argv, "help") == 0) 542 usage(); 543 if (*dev) 544 duparg2("dev", *argv); 545 *dev = *argv; 546 } 547 argc--; argv++; 548 } 549 550 return ret - argc; 551} 552 553static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv) 554{ 555 int len; 556 char *dev = NULL; 557 char *name = NULL; 558 char *link = NULL; 559 char *type = NULL; 560 struct link_util *lu = NULL; 561 struct iplink_req req; 562 int ret; 563 564 memset(&req, 0, sizeof(req)); 565 566 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); 567 req.n.nlmsg_flags = NLM_F_REQUEST|flags; 568 req.n.nlmsg_type = cmd; 569 req.i.ifi_family = preferred_family; 570 571 ret = iplink_parse(argc, argv, &req, &name, &type, &link, &dev); 572 if (ret < 0) 573 return ret; 574 575 argc -= ret; 576 argv += ret; 577 ll_init_map(&rth); 578 579 if (type) { 580 struct rtattr *linkinfo = NLMSG_TAIL(&req.n); 581 addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0); 582 addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type, 583 strlen(type)); 584 585 lu = get_link_kind(type); 586 if (lu && argc) { 587 struct rtattr * data = NLMSG_TAIL(&req.n); 588 addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0); 589 590 if (lu->parse_opt && 591 lu->parse_opt(lu, argc, argv, &req.n)) 592 return -1; 593 594 data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; 595 } else if (argc) { 596 if (matches(*argv, "help") == 0) 597 usage(); 598 fprintf(stderr, "Garbage instead of arguments \"%s ...\". " 599 "Try \"ip link help\".\n", *argv); 600 return -1; 601 } 602 linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; 603 } else if (flags & NLM_F_CREATE) { 604 fprintf(stderr, "Not enough information: \"type\" argument " 605 "is required\n"); 606 return -1; 607 } 608 609 if (!(flags & NLM_F_CREATE)) { 610 if (!dev) { 611 fprintf(stderr, "Not enough information: \"dev\" " 612 "argument is required.\n"); 613 exit(-1); 614 } 615 616 req.i.ifi_index = ll_name_to_index(dev); 617 if (req.i.ifi_index == 0) { 618 fprintf(stderr, "Cannot find device \"%s\"\n", dev); 619 return -1; 620 } 621 } else { 622 /* Allow "ip link add dev" and "ip link add name" */ 623 if (!name) 624 name = dev; 625 626 if (link) { 627 int ifindex; 628 629 ifindex = ll_name_to_index(link); 630 if (ifindex == 0) { 631 fprintf(stderr, "Cannot find device \"%s\"\n", 632 link); 633 return -1; 634 } 635 addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifindex, 4); 636 } 637 } 638 639 if (name) { 640 len = strlen(name) + 1; 641 if (len == 1) 642 invarg("\"\" is not a valid device identifier\n", "name"); 643 if (len > IFNAMSIZ) 644 invarg("\"name\" too long\n", name); 645 addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name, len); 646 } 647 648 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) 649 exit(2); 650 651 return 0; 652} 653 654#if IPLINK_IOCTL_COMPAT 655static int get_ctl_fd(void) 656{ 657 int s_errno; 658 int fd; 659 660 fd = socket(PF_INET, SOCK_DGRAM, 0); 661 if (fd >= 0) 662 return fd; 663 s_errno = errno; 664 fd = socket(PF_PACKET, SOCK_DGRAM, 0); 665 if (fd >= 0) 666 return fd; 667 fd = socket(PF_INET6, SOCK_DGRAM, 0); 668 if (fd >= 0) 669 return fd; 670 errno = s_errno; 671 perror("Cannot create control socket"); 672 return -1; 673} 674 675static int do_chflags(const char *dev, __u32 flags, __u32 mask) 676{ 677 struct ifreq ifr; 678 int fd; 679 int err; 680 681 strncpy(ifr.ifr_name, dev, IFNAMSIZ); 682 fd = get_ctl_fd(); 683 if (fd < 0) 684 return -1; 685 err = ioctl(fd, SIOCGIFFLAGS, &ifr); 686 if (err) { 687 perror("SIOCGIFFLAGS"); 688 close(fd); 689 return -1; 690 } 691 if ((ifr.ifr_flags^flags)&mask) { 692 ifr.ifr_flags &= ~mask; 693 ifr.ifr_flags |= mask&flags; 694 err = ioctl(fd, SIOCSIFFLAGS, &ifr); 695 if (err) 696 perror("SIOCSIFFLAGS"); 697 } 698 close(fd); 699 return err; 700} 701 702static int do_changename(const char *dev, const char *newdev) 703{ 704 struct ifreq ifr; 705 int fd; 706 int err; 707 708 strncpy(ifr.ifr_name, dev, IFNAMSIZ); 709 strncpy(ifr.ifr_newname, newdev, IFNAMSIZ); 710 fd = get_ctl_fd(); 711 if (fd < 0) 712 return -1; 713 err = ioctl(fd, SIOCSIFNAME, &ifr); 714 if (err) { 715 perror("SIOCSIFNAME"); 716 close(fd); 717 return -1; 718 } 719 close(fd); 720 return err; 721} 722 723static int set_qlen(const char *dev, int qlen) 724{ 725 struct ifreq ifr; 726 int s; 727 728 s = get_ctl_fd(); 729 if (s < 0) 730 return -1; 731 732 memset(&ifr, 0, sizeof(ifr)); 733 strncpy(ifr.ifr_name, dev, IFNAMSIZ); 734 ifr.ifr_qlen = qlen; 735 if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) { 736 perror("SIOCSIFXQLEN"); 737 close(s); 738 return -1; 739 } 740 close(s); 741 742 return 0; 743} 744 745static int set_mtu(const char *dev, int mtu) 746{ 747 struct ifreq ifr; 748 int s; 749 750 s = get_ctl_fd(); 751 if (s < 0) 752 return -1; 753 754 memset(&ifr, 0, sizeof(ifr)); 755 strncpy(ifr.ifr_name, dev, IFNAMSIZ); 756 ifr.ifr_mtu = mtu; 757 if (ioctl(s, SIOCSIFMTU, &ifr) < 0) { 758 perror("SIOCSIFMTU"); 759 close(s); 760 return -1; 761 } 762 close(s); 763 764 return 0; 765} 766 767static int get_address(const char *dev, int *htype) 768{ 769 struct ifreq ifr; 770 struct sockaddr_ll me; 771 socklen_t alen; 772 int s; 773 774 s = socket(PF_PACKET, SOCK_DGRAM, 0); 775 if (s < 0) { 776 perror("socket(PF_PACKET)"); 777 return -1; 778 } 779 780 memset(&ifr, 0, sizeof(ifr)); 781 strncpy(ifr.ifr_name, dev, IFNAMSIZ); 782 if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { 783 perror("SIOCGIFINDEX"); 784 close(s); 785 return -1; 786 } 787 788 memset(&me, 0, sizeof(me)); 789 me.sll_family = AF_PACKET; 790 me.sll_ifindex = ifr.ifr_ifindex; 791 me.sll_protocol = htons(ETH_P_LOOP); 792 if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) { 793 perror("bind"); 794 close(s); 795 return -1; 796 } 797 798 alen = sizeof(me); 799 if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) { 800 perror("getsockname"); 801 close(s); 802 return -1; 803 } 804 close(s); 805 *htype = me.sll_hatype; 806 return me.sll_halen; 807} 808 809static int parse_address(const char *dev, int hatype, int halen, 810 char *lla, struct ifreq *ifr) 811{ 812 int alen; 813 814 memset(ifr, 0, sizeof(*ifr)); 815 strncpy(ifr->ifr_name, dev, IFNAMSIZ); 816 ifr->ifr_hwaddr.sa_family = hatype; 817 alen = ll_addr_a2n(ifr->ifr_hwaddr.sa_data, 14, lla); 818 if (alen < 0) 819 return -1; 820 if (alen != halen) { 821 fprintf(stderr, "Wrong address (%s) length: expected %d bytes\n", lla, halen); 822 return -1; 823 } 824 return 0; 825} 826 827static int set_address(struct ifreq *ifr, int brd) 828{ 829 int s; 830 831 s = get_ctl_fd(); 832 if (s < 0) 833 return -1; 834 if (ioctl(s, brd?SIOCSIFHWBROADCAST:SIOCSIFHWADDR, ifr) < 0) { 835 perror(brd?"SIOCSIFHWBROADCAST":"SIOCSIFHWADDR"); 836 close(s); 837 return -1; 838 } 839 close(s); 840 return 0; 841} 842 843 844static int do_set(int argc, char **argv) 845{ 846 char *dev = NULL; 847 __u32 mask = 0; 848 __u32 flags = 0; 849 int qlen = -1; 850 int mtu = -1; 851 char *newaddr = NULL; 852 char *newbrd = NULL; 853 struct ifreq ifr0, ifr1; 854 char *newname = NULL; 855 int htype, halen; 856 857 while (argc > 0) { 858 if (strcmp(*argv, "up") == 0) { 859 mask |= IFF_UP; 860 flags |= IFF_UP; 861 } else if (strcmp(*argv, "down") == 0) { 862 mask |= IFF_UP; 863 flags &= ~IFF_UP; 864 } else if (strcmp(*argv, "name") == 0) { 865 NEXT_ARG(); 866 newname = *argv; 867 } else if (matches(*argv, "address") == 0) { 868 NEXT_ARG(); 869 newaddr = *argv; 870 } else if (matches(*argv, "broadcast") == 0 || 871 strcmp(*argv, "brd") == 0) { 872 NEXT_ARG(); 873 newbrd = *argv; 874 } else if (matches(*argv, "txqueuelen") == 0 || 875 strcmp(*argv, "qlen") == 0 || 876 matches(*argv, "txqlen") == 0) { 877 NEXT_ARG(); 878 if (qlen != -1) 879 duparg("txqueuelen", *argv); 880 if (get_integer(&qlen, *argv, 0)) 881 invarg("Invalid \"txqueuelen\" value\n", *argv); 882 } else if (strcmp(*argv, "mtu") == 0) { 883 NEXT_ARG(); 884 if (mtu != -1) 885 duparg("mtu", *argv); 886 if (get_integer(&mtu, *argv, 0)) 887 invarg("Invalid \"mtu\" value\n", *argv); 888 } else if (strcmp(*argv, "multicast") == 0) { 889 NEXT_ARG(); 890 mask |= IFF_MULTICAST; 891 if (strcmp(*argv, "on") == 0) { 892 flags |= IFF_MULTICAST; 893 } else if (strcmp(*argv, "off") == 0) { 894 flags &= ~IFF_MULTICAST; 895 } else 896 return on_off("multicast"); 897 } else if (strcmp(*argv, "allmulticast") == 0) { 898 NEXT_ARG(); 899 mask |= IFF_ALLMULTI; 900 if (strcmp(*argv, "on") == 0) { 901 flags |= IFF_ALLMULTI; 902 } else if (strcmp(*argv, "off") == 0) { 903 flags &= ~IFF_ALLMULTI; 904 } else 905 return on_off("allmulticast"); 906 } else if (strcmp(*argv, "promisc") == 0) { 907 NEXT_ARG(); 908 mask |= IFF_PROMISC; 909 if (strcmp(*argv, "on") == 0) { 910 flags |= IFF_PROMISC; 911 } else if (strcmp(*argv, "off") == 0) { 912 flags &= ~IFF_PROMISC; 913 } else 914 return on_off("promisc"); 915 } else if (strcmp(*argv, "trailers") == 0) { 916 NEXT_ARG(); 917 mask |= IFF_NOTRAILERS; 918 if (strcmp(*argv, "off") == 0) { 919 flags |= IFF_NOTRAILERS; 920 } else if (strcmp(*argv, "on") == 0) { 921 flags &= ~IFF_NOTRAILERS; 922 } else 923 return on_off("trailers"); 924 } else if (strcmp(*argv, "arp") == 0) { 925 NEXT_ARG(); 926 mask |= IFF_NOARP; 927 if (strcmp(*argv, "on") == 0) { 928 flags &= ~IFF_NOARP; 929 } else if (strcmp(*argv, "off") == 0) { 930 flags |= IFF_NOARP; 931 } else 932 return on_off("noarp"); 933#ifdef IFF_DYNAMIC 934 } else if (matches(*argv, "dynamic") == 0) { 935 NEXT_ARG(); 936 mask |= IFF_DYNAMIC; 937 if (strcmp(*argv, "on") == 0) { 938 flags |= IFF_DYNAMIC; 939 } else if (strcmp(*argv, "off") == 0) { 940 flags &= ~IFF_DYNAMIC; 941 } else 942 return on_off("dynamic"); 943#endif 944 } else { 945 if (strcmp(*argv, "dev") == 0) { 946 NEXT_ARG(); 947 } 948 if (matches(*argv, "help") == 0) 949 usage(); 950 if (dev) 951 duparg2("dev", *argv); 952 dev = *argv; 953 } 954 argc--; argv++; 955 } 956 957 if (!dev) { 958 fprintf(stderr, "Not enough of information: \"dev\" argument is required.\n"); 959 exit(-1); 960 } 961 962 if (newaddr || newbrd) { 963 halen = get_address(dev, &htype); 964 if (halen < 0) 965 return -1; 966 if (newaddr) { 967 if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0) 968 return -1; 969 } 970 if (newbrd) { 971 if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0) 972 return -1; 973 } 974 } 975 976 if (newname && strcmp(dev, newname)) { 977 if (strlen(newname) == 0) 978 invarg("\"\" is not a valid device identifier\n", "name"); 979 if (do_changename(dev, newname) < 0) 980 return -1; 981 dev = newname; 982 } 983 if (qlen != -1) { 984 if (set_qlen(dev, qlen) < 0) 985 return -1; 986 } 987 if (mtu != -1) { 988 if (set_mtu(dev, mtu) < 0) 989 return -1; 990 } 991 if (newaddr || newbrd) { 992 if (newbrd) { 993 if (set_address(&ifr1, 1) < 0) 994 return -1; 995 } 996 if (newaddr) { 997 if (set_address(&ifr0, 0) < 0) 998 return -1; 999 } 1000 } 1001 if (mask) 1002 return do_chflags(dev, flags, mask); 1003 return 0; 1004} 1005#endif /* IPLINK_IOCTL_COMPAT */ 1006 1007int do_iplink(int argc, char **argv) 1008{ 1009 if (argc > 0) { 1010 if (iplink_have_newlink()) { 1011 if (matches(*argv, "add") == 0) 1012 return iplink_modify(RTM_NEWLINK, 1013 NLM_F_CREATE|NLM_F_EXCL, 1014 argc-1, argv+1); 1015 if (matches(*argv, "set") == 0 || 1016 matches(*argv, "change") == 0) 1017 return iplink_modify(RTM_NEWLINK, 0, 1018 argc-1, argv+1); 1019 if (matches(*argv, "replace") == 0) 1020 return iplink_modify(RTM_NEWLINK, 1021 NLM_F_CREATE|NLM_F_REPLACE, 1022 argc-1, argv+1); 1023 if (matches(*argv, "delete") == 0) 1024 return iplink_modify(RTM_DELLINK, 0, 1025 argc-1, argv+1); 1026 } else { 1027#if IPLINK_IOCTL_COMPAT 1028 if (matches(*argv, "set") == 0) 1029 return do_set(argc-1, argv+1); 1030#endif 1031 } 1032 if (matches(*argv, "show") == 0 || 1033 matches(*argv, "lst") == 0 || 1034 matches(*argv, "list") == 0) 1035 return ipaddr_list_link(argc-1, argv+1); 1036 if (matches(*argv, "help") == 0) 1037 usage(); 1038 } else 1039 return ipaddr_list_link(0, NULL); 1040 1041 fprintf(stderr, "Command \"%s\" is unknown, try \"ip link help\".\n", *argv); 1042 exit(-1); 1043} 1044