busybox/networking/libiproute/iplink.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*
   3 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
   4 *                      Patrick McHardy <kaber@trash.net>
   5 *
   6 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
   7 */
   8#include <net/if.h>
   9/*#include <net/if_packet.h> - not needed? */
  10#include <netpacket/packet.h>
  11#include <netinet/if_ether.h>
  12
  13#include <linux/if_vlan.h>
  14#include "ip_common.h"  /* #include "libbb.h" is inside */
  15#include "rt_names.h"
  16#include "utils.h"
  17
  18#undef  ETH_P_8021AD
  19#define ETH_P_8021AD            0x88A8
  20#undef  VLAN_FLAG_REORDER_HDR
  21#define VLAN_FLAG_REORDER_HDR   0x1
  22#undef  VLAN_FLAG_GVRP
  23#define VLAN_FLAG_GVRP          0x2
  24#undef  VLAN_FLAG_LOOSE_BINDING
  25#define VLAN_FLAG_LOOSE_BINDING 0x4
  26#undef  VLAN_FLAG_MVRP
  27#define VLAN_FLAG_MVRP          0x8
  28#undef  IFLA_VLAN_PROTOCOL
  29#define IFLA_VLAN_PROTOCOL      5
  30
  31#ifndef IFLA_LINKINFO
  32# define IFLA_LINKINFO 18
  33# define IFLA_INFO_KIND 1
  34# define IFLA_INFO_DATA 2
  35#endif
  36
  37#ifndef IFLA_VLAN_MAX
  38# define IFLA_VLAN_ID 1
  39# define IFLA_VLAN_FLAGS 2
  40struct ifla_vlan_flags {
  41        uint32_t        flags;
  42        uint32_t        mask;
  43};
  44#endif
  45
  46/* taken from linux/sockios.h */
  47#define SIOCSIFNAME  0x8923  /* set interface name */
  48
  49#if 0
  50# define dbg(...) bb_error_msg(__VA_ARGS__)
  51#else
  52# define dbg(...) ((void)0)
  53#endif
  54
  55/* Exits on error */
  56static int get_ctl_fd(void)
  57{
  58        int fd;
  59
  60        fd = socket(PF_INET, SOCK_DGRAM, 0);
  61        if (fd >= 0)
  62                return fd;
  63        fd = socket(PF_PACKET, SOCK_DGRAM, 0);
  64        if (fd >= 0)
  65                return fd;
  66        return xsocket(PF_INET6, SOCK_DGRAM, 0);
  67}
  68
  69/* Exits on error */
  70static void do_chflags(char *dev, uint32_t flags, uint32_t mask)
  71{
  72        struct ifreq ifr;
  73        int fd;
  74
  75        strncpy_IFNAMSIZ(ifr.ifr_name, dev);
  76        fd = get_ctl_fd();
  77        xioctl(fd, SIOCGIFFLAGS, &ifr);
  78        if ((ifr.ifr_flags ^ flags) & mask) {
  79                ifr.ifr_flags &= ~mask;
  80                ifr.ifr_flags |= mask & flags;
  81                xioctl(fd, SIOCSIFFLAGS, &ifr);
  82        }
  83        close(fd);
  84}
  85
  86/* Exits on error */
  87static void do_changename(char *dev, char *newdev)
  88{
  89        struct ifreq ifr;
  90        int fd;
  91
  92        strncpy_IFNAMSIZ(ifr.ifr_name, dev);
  93        strncpy_IFNAMSIZ(ifr.ifr_newname, newdev);
  94        fd = get_ctl_fd();
  95        xioctl(fd, SIOCSIFNAME, &ifr);
  96        close(fd);
  97}
  98
  99/* Exits on error */
 100static void set_qlen(char *dev, int qlen)
 101{
 102        struct ifreq ifr;
 103        int s;
 104
 105        s = get_ctl_fd();
 106        memset(&ifr, 0, sizeof(ifr));
 107        strncpy_IFNAMSIZ(ifr.ifr_name, dev);
 108        ifr.ifr_qlen = qlen;
 109        xioctl(s, SIOCSIFTXQLEN, &ifr);
 110        close(s);
 111}
 112
 113/* Exits on error */
 114static void set_mtu(char *dev, int mtu)
 115{
 116        struct ifreq ifr;
 117        int s;
 118
 119        s = get_ctl_fd();
 120        memset(&ifr, 0, sizeof(ifr));
 121        strncpy_IFNAMSIZ(ifr.ifr_name, dev);
 122        ifr.ifr_mtu = mtu;
 123        xioctl(s, SIOCSIFMTU, &ifr);
 124        close(s);
 125}
 126
 127/* Exits on error */
 128static int get_address(char *dev, int *htype)
 129{
 130        struct ifreq ifr;
 131        struct sockaddr_ll me;
 132        socklen_t alen;
 133        int s;
 134
 135        s = xsocket(PF_PACKET, SOCK_DGRAM, 0);
 136
 137        memset(&ifr, 0, sizeof(ifr));
 138        strncpy_IFNAMSIZ(ifr.ifr_name, dev);
 139        xioctl(s, SIOCGIFINDEX, &ifr);
 140
 141        memset(&me, 0, sizeof(me));
 142        me.sll_family = AF_PACKET;
 143        me.sll_ifindex = ifr.ifr_ifindex;
 144        me.sll_protocol = htons(ETH_P_LOOP);
 145        xbind(s, (struct sockaddr*)&me, sizeof(me));
 146        alen = sizeof(me);
 147        getsockname(s, (struct sockaddr*)&me, &alen);
 148        //never happens:
 149        //if (getsockname(s, (struct sockaddr*)&me, &alen) == -1)
 150        //      bb_perror_msg_and_die("getsockname");
 151        close(s);
 152        *htype = me.sll_hatype;
 153        return me.sll_halen;
 154}
 155
 156/* Exits on error */
 157static void parse_address(char *dev, int hatype, int halen, char *lla, struct ifreq *ifr)
 158{
 159        int alen;
 160
 161        memset(ifr, 0, sizeof(*ifr));
 162        strncpy_IFNAMSIZ(ifr->ifr_name, dev);
 163        ifr->ifr_hwaddr.sa_family = hatype;
 164
 165        alen = hatype == 1/*ARPHRD_ETHER*/ ? 14/*ETH_HLEN*/ : 19/*INFINIBAND_HLEN*/;
 166        alen = ll_addr_a2n((unsigned char *)(ifr->ifr_hwaddr.sa_data), alen, lla);
 167        if (alen < 0)
 168                exit(EXIT_FAILURE);
 169        if (alen != halen) {
 170                bb_error_msg_and_die("wrong address (%s) length: expected %d bytes", lla, halen);
 171        }
 172}
 173
 174/* Exits on error */
 175static void set_address(struct ifreq *ifr, int brd)
 176{
 177        int s;
 178
 179        s = get_ctl_fd();
 180        if (brd)
 181                xioctl(s, SIOCSIFHWBROADCAST, ifr);
 182        else
 183                xioctl(s, SIOCSIFHWADDR, ifr);
 184        close(s);
 185}
 186
 187
 188static void die_must_be_on_off(const char *msg) NORETURN;
 189static void die_must_be_on_off(const char *msg)
 190{
 191        bb_error_msg_and_die("argument of \"%s\" must be \"on\" or \"off\"", msg);
 192}
 193
 194/* Return value becomes exitcode. It's okay to not return at all */
 195static int do_set(char **argv)
 196{
 197        char *dev = NULL;
 198        uint32_t mask = 0;
 199        uint32_t flags = 0;
 200        int qlen = -1;
 201        int mtu = -1;
 202        char *newaddr = NULL;
 203        char *newbrd = NULL;
 204        struct ifreq ifr0, ifr1;
 205        char *newname = NULL;
 206        int htype, halen;
 207        static const char keywords[] ALIGN1 =
 208                "up\0""down\0""name\0""mtu\0""qlen\0""multicast\0"
 209                "arp\0""address\0""dev\0";
 210        enum { ARG_up = 0, ARG_down, ARG_name, ARG_mtu, ARG_qlen, ARG_multicast,
 211                ARG_arp, ARG_addr, ARG_dev };
 212        static const char str_on_off[] ALIGN1 = "on\0""off\0";
 213        enum { PARM_on = 0, PARM_off };
 214        smalluint key;
 215
 216        while (*argv) {
 217                /* substring search ensures that e.g. "addr" and "address"
 218                 * are both accepted */
 219                key = index_in_substrings(keywords, *argv);
 220                if (key == ARG_up) {
 221                        mask |= IFF_UP;
 222                        flags |= IFF_UP;
 223                } else if (key == ARG_down) {
 224                        mask |= IFF_UP;
 225                        flags &= ~IFF_UP;
 226                } else if (key == ARG_name) {
 227                        NEXT_ARG();
 228                        newname = *argv;
 229                } else if (key == ARG_mtu) {
 230                        NEXT_ARG();
 231                        if (mtu != -1)
 232                                duparg("mtu", *argv);
 233                        mtu = get_unsigned(*argv, "mtu");
 234                } else if (key == ARG_qlen) {
 235                        NEXT_ARG();
 236                        if (qlen != -1)
 237                                duparg("qlen", *argv);
 238                        qlen = get_unsigned(*argv, "qlen");
 239                } else if (key == ARG_addr) {
 240                        NEXT_ARG();
 241                        newaddr = *argv;
 242                } else if (key >= ARG_dev) {
 243                        if (key == ARG_dev) {
 244                                NEXT_ARG();
 245                        }
 246                        if (dev)
 247                                duparg2("dev", *argv);
 248                        dev = *argv;
 249                } else {
 250                        int param;
 251                        NEXT_ARG();
 252                        param = index_in_strings(str_on_off, *argv);
 253                        if (key == ARG_multicast) {
 254                                if (param < 0)
 255                                        die_must_be_on_off("multicast");
 256                                mask |= IFF_MULTICAST;
 257                                if (param == PARM_on)
 258                                        flags |= IFF_MULTICAST;
 259                                else
 260                                        flags &= ~IFF_MULTICAST;
 261                        } else if (key == ARG_arp) {
 262                                if (param < 0)
 263                                        die_must_be_on_off("arp");
 264                                mask |= IFF_NOARP;
 265                                if (param == PARM_on)
 266                                        flags &= ~IFF_NOARP;
 267                                else
 268                                        flags |= IFF_NOARP;
 269                        }
 270                }
 271                argv++;
 272        }
 273
 274        if (!dev) {
 275                bb_error_msg_and_die(bb_msg_requires_arg, "\"dev\"");
 276        }
 277
 278        if (newaddr || newbrd) {
 279                halen = get_address(dev, &htype);
 280                if (newaddr) {
 281                        parse_address(dev, htype, halen, newaddr, &ifr0);
 282                        set_address(&ifr0, 0);
 283                }
 284                if (newbrd) {
 285                        parse_address(dev, htype, halen, newbrd, &ifr1);
 286                        set_address(&ifr1, 1);
 287                }
 288        }
 289
 290        if (newname && strcmp(dev, newname)) {
 291                do_changename(dev, newname);
 292                dev = newname;
 293        }
 294        if (qlen != -1) {
 295                set_qlen(dev, qlen);
 296        }
 297        if (mtu != -1) {
 298                set_mtu(dev, mtu);
 299        }
 300        if (mask)
 301                do_chflags(dev, flags, mask);
 302        return 0;
 303}
 304
 305static int ipaddr_list_link(char **argv)
 306{
 307        preferred_family = AF_PACKET;
 308        return ipaddr_list_or_flush(argv, 0);
 309}
 310
 311static void vlan_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size)
 312{
 313        static const char keywords[] ALIGN1 =
 314                "id\0"
 315                "protocol\0"
 316                "reorder_hdr\0"
 317                "gvrp\0"
 318                "mvrp\0"
 319                "loose_binding\0"
 320        ;
 321        static const char protocols[] ALIGN1 =
 322                "802.1q\0"
 323                "802.1ad\0"
 324        ;
 325        static const char str_on_off[] ALIGN1 =
 326                "on\0"
 327                "off\0"
 328        ;
 329        enum {
 330                ARG_id = 0,
 331                ARG_reorder_hdr,
 332                ARG_gvrp,
 333                ARG_mvrp,
 334                ARG_loose_binding,
 335                ARG_protocol,
 336        };
 337        enum {
 338                PROTO_8021Q = 0,
 339                PROTO_8021AD,
 340        };
 341        enum {
 342                PARM_on = 0,
 343                PARM_off
 344        };
 345        int arg;
 346        uint16_t id, proto;
 347        struct ifla_vlan_flags flags = {};
 348
 349        while (*argv) {
 350                arg = index_in_substrings(keywords, *argv);
 351                if (arg < 0)
 352                        invarg(*argv, "type vlan");
 353
 354                NEXT_ARG();
 355                if (arg == ARG_id) {
 356                        id = get_u16(*argv, "id");
 357                        addattr_l(n, size, IFLA_VLAN_ID, &id, sizeof(id));
 358                } else if (arg == ARG_protocol) {
 359                        arg = index_in_substrings(protocols, *argv);
 360                        if (arg == PROTO_8021Q)
 361                                proto = ETH_P_8021Q;
 362                        else if (arg == PROTO_8021AD)
 363                                proto = ETH_P_8021AD;
 364                        else
 365                                bb_error_msg_and_die("unknown VLAN encapsulation protocol '%s'",
 366                                                                     *argv);
 367                        addattr_l(n, size, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto));
 368                } else {
 369                        int param = index_in_strings(str_on_off, *argv);
 370                        if (param < 0)
 371                                die_must_be_on_off(nth_string(keywords, arg));
 372
 373                        if (arg == ARG_reorder_hdr) {
 374                                flags.mask |= VLAN_FLAG_REORDER_HDR;
 375                                flags.flags &= ~VLAN_FLAG_REORDER_HDR;
 376                                if (param == PARM_on)
 377                                        flags.flags |= VLAN_FLAG_REORDER_HDR;
 378                        } else if (arg == ARG_gvrp) {
 379                                flags.mask |= VLAN_FLAG_GVRP;
 380                                flags.flags &= ~VLAN_FLAG_GVRP;
 381                                if (param == PARM_on)
 382                                        flags.flags |= VLAN_FLAG_GVRP;
 383                        } else if (arg == ARG_mvrp) {
 384                                flags.mask |= VLAN_FLAG_MVRP;
 385                                flags.flags &= ~VLAN_FLAG_MVRP;
 386                                if (param == PARM_on)
 387                                        flags.flags |= VLAN_FLAG_MVRP;
 388                        } else { /*if (arg == ARG_loose_binding) */
 389                                flags.mask |= VLAN_FLAG_LOOSE_BINDING;
 390                                flags.flags &= ~VLAN_FLAG_LOOSE_BINDING;
 391                                if (param == PARM_on)
 392                                        flags.flags |= VLAN_FLAG_LOOSE_BINDING;
 393                        }
 394                }
 395                argv++;
 396        }
 397
 398        if (flags.mask)
 399                addattr_l(n, size, IFLA_VLAN_FLAGS, &flags, sizeof(flags));
 400}
 401
 402#ifndef NLMSG_TAIL
 403#define NLMSG_TAIL(nmsg) \
 404        ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
 405#endif
 406/* Return value becomes exitcode. It's okay to not return at all */
 407static int do_add_or_delete(char **argv, const unsigned rtm)
 408{
 409        static const char keywords[] ALIGN1 =
 410                "link\0""name\0""type\0""dev\0""address\0";
 411        enum {
 412                ARG_link,
 413                ARG_name,
 414                ARG_type,
 415                ARG_dev,
 416                ARG_address,
 417        };
 418        struct rtnl_handle rth;
 419        struct {
 420                struct nlmsghdr  n;
 421                struct ifinfomsg i;
 422                char             buf[1024];
 423        } req;
 424        smalluint arg;
 425        char *name_str = NULL;
 426        char *link_str = NULL;
 427        char *type_str = NULL;
 428        char *dev_str = NULL;
 429        char *address_str = NULL;
 430
 431        memset(&req, 0, sizeof(req));
 432
 433        req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
 434        req.n.nlmsg_flags = NLM_F_REQUEST;
 435        req.n.nlmsg_type = rtm;
 436        req.i.ifi_family = preferred_family;
 437        if (rtm == RTM_NEWLINK)
 438                req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
 439
 440        while (*argv) {
 441                arg = index_in_substrings(keywords, *argv);
 442                if (arg == ARG_type) {
 443                        NEXT_ARG();
 444                        type_str = *argv++;
 445                        dbg("type_str:'%s'", type_str);
 446                        break;
 447                }
 448                if (arg == ARG_link) {
 449                        NEXT_ARG();
 450                        link_str = *argv;
 451                        dbg("link_str:'%s'", link_str);
 452                } else if (arg == ARG_name) {
 453                        NEXT_ARG();
 454                        name_str = *argv;
 455                        dbg("name_str:'%s'", name_str);
 456                } else if (arg == ARG_address) {
 457                        NEXT_ARG();
 458                        address_str = *argv;
 459                        dbg("address_str:'%s'", name_str);
 460                } else {
 461                        if (arg == ARG_dev) {
 462                                if (dev_str)
 463                                        duparg(*argv, "dev");
 464                                NEXT_ARG();
 465                        }
 466                        dev_str = *argv;
 467                        dbg("dev_str:'%s'", dev_str);
 468                }
 469                argv++;
 470        }
 471        xrtnl_open(&rth);
 472        ll_init_map(&rth);
 473        if (type_str) {
 474                struct rtattr *linkinfo = NLMSG_TAIL(&req.n);
 475
 476                addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
 477                addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type_str,
 478                                strlen(type_str));
 479
 480                if (*argv) {
 481                        struct rtattr *data = NLMSG_TAIL(&req.n);
 482                        addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0);
 483
 484                        if (strcmp(type_str, "vlan") == 0)
 485                                vlan_parse_opt(argv, &req.n, sizeof(req));
 486
 487                        data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;
 488                }
 489
 490                linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
 491        }
 492        if (rtm != RTM_NEWLINK) {
 493                if (!dev_str)
 494                        return 1; /* Need a device to delete */
 495                req.i.ifi_index = xll_name_to_index(dev_str);
 496        } else {
 497                if (!name_str)
 498                        name_str = dev_str;
 499                if (link_str) {
 500                        int idx = xll_name_to_index(link_str);
 501                        addattr_l(&req.n, sizeof(req), IFLA_LINK, &idx, 4);
 502                }
 503                if (address_str) {
 504                        unsigned char abuf[32];
 505                        int len = ll_addr_a2n(abuf, sizeof(abuf), address_str);
 506                        dbg("address len:%d", len);
 507                        if (len < 0)
 508                                return -1;
 509                        addattr_l(&req.n, sizeof(req), IFLA_ADDRESS, abuf, len);
 510                }
 511        }
 512        if (name_str) {
 513                const size_t name_len = strlen(name_str) + 1;
 514                if (name_len < 2 || name_len > IFNAMSIZ)
 515                        invarg(name_str, "name");
 516                addattr_l(&req.n, sizeof(req), IFLA_IFNAME, name_str, name_len);
 517        }
 518        if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
 519                return 2;
 520        return 0;
 521}
 522
 523/* Other keywords recognized by iproute2-3.12.0: */
 524#if 0
 525                } else if (matches(*argv, "broadcast") == 0 ||
 526                                strcmp(*argv, "brd") == 0) {
 527                        NEXT_ARG();
 528                        len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
 529                        if (len < 0)
 530                                return -1;
 531                        addattr_l(&req->n, sizeof(*req), IFLA_BROADCAST, abuf, len);
 532                } else if (matches(*argv, "txqueuelen") == 0 ||
 533                                strcmp(*argv, "qlen") == 0 ||
 534                                matches(*argv, "txqlen") == 0) {
 535                        NEXT_ARG();
 536                        if (qlen != -1)
 537                                duparg("txqueuelen", *argv);
 538                        if (get_integer(&qlen,  *argv, 0))
 539                                invarg("Invalid \"txqueuelen\" value\n", *argv);
 540                        addattr_l(&req->n, sizeof(*req), IFLA_TXQLEN, &qlen, 4);
 541                } else if (strcmp(*argv, "mtu") == 0) {
 542                        NEXT_ARG();
 543                        if (mtu != -1)
 544                                duparg("mtu", *argv);
 545                        if (get_integer(&mtu, *argv, 0))
 546                                invarg("Invalid \"mtu\" value\n", *argv);
 547                        addattr_l(&req->n, sizeof(*req), IFLA_MTU, &mtu, 4);
 548                } else if (strcmp(*argv, "netns") == 0) {
 549                        NEXT_ARG();
 550                        if (netns != -1)
 551                                duparg("netns", *argv);
 552                        if ((netns = get_netns_fd(*argv)) >= 0)
 553                                addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_FD, &netns, 4);
 554                        else if (get_integer(&netns, *argv, 0) == 0)
 555                                addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID, &netns, 4);
 556                        else
 557                                invarg("Invalid \"netns\" value\n", *argv);
 558                } else if (strcmp(*argv, "multicast") == 0) {
 559                        NEXT_ARG();
 560                        req->i.ifi_change |= IFF_MULTICAST;
 561                        if (strcmp(*argv, "on") == 0) {
 562                                req->i.ifi_flags |= IFF_MULTICAST;
 563                        } else if (strcmp(*argv, "off") == 0) {
 564                                req->i.ifi_flags &= ~IFF_MULTICAST;
 565                        } else
 566                                return on_off("multicast", *argv);
 567                } else if (strcmp(*argv, "allmulticast") == 0) {
 568                        NEXT_ARG();
 569                        req->i.ifi_change |= IFF_ALLMULTI;
 570                        if (strcmp(*argv, "on") == 0) {
 571                                req->i.ifi_flags |= IFF_ALLMULTI;
 572                        } else if (strcmp(*argv, "off") == 0) {
 573                                req->i.ifi_flags &= ~IFF_ALLMULTI;
 574                        } else
 575                                return on_off("allmulticast", *argv);
 576                } else if (strcmp(*argv, "promisc") == 0) {
 577                        NEXT_ARG();
 578                        req->i.ifi_change |= IFF_PROMISC;
 579                        if (strcmp(*argv, "on") == 0) {
 580                                req->i.ifi_flags |= IFF_PROMISC;
 581                        } else if (strcmp(*argv, "off") == 0) {
 582                                req->i.ifi_flags &= ~IFF_PROMISC;
 583                        } else
 584                                return on_off("promisc", *argv);
 585                } else if (strcmp(*argv, "trailers") == 0) {
 586                        NEXT_ARG();
 587                        req->i.ifi_change |= IFF_NOTRAILERS;
 588                        if (strcmp(*argv, "off") == 0) {
 589                                req->i.ifi_flags |= IFF_NOTRAILERS;
 590                        } else if (strcmp(*argv, "on") == 0) {
 591                                req->i.ifi_flags &= ~IFF_NOTRAILERS;
 592                        } else
 593                                return on_off("trailers", *argv);
 594                } else if (strcmp(*argv, "arp") == 0) {
 595                        NEXT_ARG();
 596                        req->i.ifi_change |= IFF_NOARP;
 597                        if (strcmp(*argv, "on") == 0) {
 598                                req->i.ifi_flags &= ~IFF_NOARP;
 599                        } else if (strcmp(*argv, "off") == 0) {
 600                                req->i.ifi_flags |= IFF_NOARP;
 601                        } else
 602                                return on_off("noarp", *argv);
 603                } else if (strcmp(*argv, "vf") == 0) {
 604                        struct rtattr *vflist;
 605                        NEXT_ARG();
 606                        if (get_integer(&vf,  *argv, 0)) {
 607                                invarg("Invalid \"vf\" value\n", *argv);
 608                        }
 609                        vflist = addattr_nest(&req->n, sizeof(*req),
 610                                              IFLA_VFINFO_LIST);
 611                        len = iplink_parse_vf(vf, &argc, &argv, req);
 612                        if (len < 0)
 613                                return -1;
 614                        addattr_nest_end(&req->n, vflist);
 615                } else if (matches(*argv, "master") == 0) {
 616                        int ifindex;
 617                        NEXT_ARG();
 618                        ifindex = ll_name_to_index(*argv);
 619                        if (!ifindex)
 620                                invarg("Device does not exist\n", *argv);
 621                        addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
 622                                  &ifindex, 4);
 623                } else if (matches(*argv, "nomaster") == 0) {
 624                        int ifindex = 0;
 625                        addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
 626                                  &ifindex, 4);
 627                } else if (matches(*argv, "dynamic") == 0) {
 628                        NEXT_ARG();
 629                        req->i.ifi_change |= IFF_DYNAMIC;
 630                        if (strcmp(*argv, "on") == 0) {
 631                                req->i.ifi_flags |= IFF_DYNAMIC;
 632                        } else if (strcmp(*argv, "off") == 0) {
 633                                req->i.ifi_flags &= ~IFF_DYNAMIC;
 634                        } else
 635                                return on_off("dynamic", *argv);
 636                } else if (matches(*argv, "alias") == 0) {
 637                        NEXT_ARG();
 638                        addattr_l(&req->n, sizeof(*req), IFLA_IFALIAS,
 639                                  *argv, strlen(*argv));
 640                        argc--; argv++;
 641                        break;
 642                } else if (strcmp(*argv, "group") == 0) {
 643                        NEXT_ARG();
 644                        if (*group != -1)
 645                                duparg("group", *argv);
 646                        if (rtnl_group_a2n(group, *argv))
 647                                invarg("Invalid \"group\" value\n", *argv);
 648                } else if (strcmp(*argv, "mode") == 0) {
 649                        int mode;
 650                        NEXT_ARG();
 651                        mode = get_link_mode(*argv);
 652                        if (mode < 0)
 653                                invarg("Invalid link mode\n", *argv);
 654                        addattr8(&req->n, sizeof(*req), IFLA_LINKMODE, mode);
 655                } else if (strcmp(*argv, "state") == 0) {
 656                        int state;
 657                        NEXT_ARG();
 658                        state = get_operstate(*argv);
 659                        if (state < 0)
 660                                invarg("Invalid operstate\n", *argv);
 661
 662                        addattr8(&req->n, sizeof(*req), IFLA_OPERSTATE, state);
 663                } else if (matches(*argv, "numtxqueues") == 0) {
 664                        NEXT_ARG();
 665                        if (numtxqueues != -1)
 666                                duparg("numtxqueues", *argv);
 667                        if (get_integer(&numtxqueues, *argv, 0))
 668                                invarg("Invalid \"numtxqueues\" value\n", *argv);
 669                        addattr_l(&req->n, sizeof(*req), IFLA_NUM_TX_QUEUES,
 670                                  &numtxqueues, 4);
 671                } else if (matches(*argv, "numrxqueues") == 0) {
 672                        NEXT_ARG();
 673                        if (numrxqueues != -1)
 674                                duparg("numrxqueues", *argv);
 675                        if (get_integer(&numrxqueues, *argv, 0))
 676                                invarg("Invalid \"numrxqueues\" value\n", *argv);
 677                        addattr_l(&req->n, sizeof(*req), IFLA_NUM_RX_QUEUES,
 678                                  &numrxqueues, 4);
 679                }
 680#endif
 681
 682/* Return value becomes exitcode. It's okay to not return at all */
 683int FAST_FUNC do_iplink(char **argv)
 684{
 685        static const char keywords[] ALIGN1 =
 686                "add\0""delete\0""set\0""show\0""lst\0""list\0";
 687        if (*argv) {
 688                int key = index_in_substrings(keywords, *argv);
 689                if (key < 0) /* invalid argument */
 690                        invarg(*argv, applet_name);
 691                argv++;
 692                if (key <= 1) /* add/delete */
 693                        return do_add_or_delete(argv, key ? RTM_DELLINK : RTM_NEWLINK);
 694                if (key == 2) /* set */
 695                        return do_set(argv);
 696        }
 697        /* show, lst, list */
 698        return ipaddr_list_link(argv);
 699}
 700