iplink: implement support for selecting a master interface
authorJan Luebbe <jluebbe@debian.org>
Wed, 14 Feb 2018 13:05:27 +0000 (14:05 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Tue, 20 Feb 2018 18:43:32 +0000 (19:43 +0100)
Attaching an interface to a VRF is done by setting the interface's
master. Besides VRF, this can also be used for bridges.

function                                             old     new   delta
set_master                                             -     142    +142
do_iplink                                           1262    1357     +95
packed_usage                                       32546   32539      -7
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 1/1 up/down: 237/-7)            Total: 230 bytes

Signed-off-by: Jan Luebbe <jluebbe@debian.org>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
networking/ip.c
networking/libiproute/iplink.c
networking/tcpudp.c

index 665f9bcce06490fe5a1839c6279fe3e414dba723..accf90759eb1d9c1314147405f54f32f050cf6ca 100644 (file)
 //--------------123456789.123456789.123456789.123456789.123456789.123456789.123456789.123....79
 //usage:#define iplink_trivial_usage
 //usage:       /*Usage:iplink*/"set IFACE [up|down] [arp on|off] [multicast on|off]\n"
-//usage:       "       [promisc on|off] [mtu NUM] [name NAME] [qlen NUM] [address MAC]"
+//usage:       "       [promisc on|off] [mtu NUM] [name NAME] [qlen NUM] [address MAC]\n"
+//usage:       "       [master IFACE | nomaster]\n"
 // * short help shows only "set" command, long help continues (with just one "\n")
 // * and shows all other commands:
 //usage:#define iplink_full_usage "\n"
index 312283318cef2ad5949f485746b2092ebe9aa004..2aa8b683b41c16a209cdb5be13c21fa0282f7668 100644 (file)
@@ -127,6 +127,31 @@ static void set_mtu(char *dev, int mtu)
        close(s);
 }
 
+/* Exits on error */
+static void set_master(char *dev, int master)
+{
+       struct rtnl_handle rth;
+       struct {
+               struct nlmsghdr  n;
+               struct ifinfomsg i;
+               char             buf[1024];
+       } req;
+
+       memset(&req, 0, sizeof(req));
+
+       req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+       req.n.nlmsg_flags = NLM_F_REQUEST;
+       req.n.nlmsg_type = RTM_NEWLINK;
+       req.i.ifi_family = preferred_family;
+
+       xrtnl_open(&rth);
+       req.i.ifi_index = xll_name_to_index(dev);
+       //printf("master %i for %i\n", master, req.i.ifi_index);
+       addattr_l(&req.n, sizeof(req), IFLA_MASTER, &master, 4);
+       if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
+               xfunc_die();
+}
+
 /* Exits on error */
 static int get_address(char *dev, int *htype)
 {
@@ -200,6 +225,7 @@ static int do_set(char **argv)
        uint32_t flags = 0;
        int qlen = -1;
        int mtu = -1;
+       int master = -1;
        char *newaddr = NULL;
        char *newbrd = NULL;
        struct ifreq ifr0, ifr1;
@@ -209,9 +235,11 @@ static int do_set(char **argv)
        static const char keywords[] ALIGN1 =
                "up\0""down\0""name\0""mtu\0""qlen\0""multicast\0"
                "arp\0""promisc\0""address\0"
+               "master\0""nomaster\0"
                "dev\0" /* must be last */;
        enum { ARG_up = 0, ARG_down, ARG_name, ARG_mtu, ARG_qlen, ARG_multicast,
                ARG_arp, ARG_promisc, ARG_addr,
+               ARG_master, ARG_nomaster,
                ARG_dev };
        enum { PARM_on = 0, PARM_off };
        smalluint key;
@@ -243,6 +271,11 @@ static int do_set(char **argv)
                } else if (key == ARG_addr) {
                        NEXT_ARG();
                        newaddr = *argv;
+               } else if (key == ARG_master) {
+                       NEXT_ARG();
+                       master = xll_name_to_index(*argv);
+               } else if (key == ARG_nomaster) {
+                       master = 0;
                } else if (key >= ARG_dev) {
                        /* ^^^^^^ ">=" here results in "dev IFACE" treated as default */
                        if (key == ARG_dev) {
@@ -427,6 +460,9 @@ static int do_set(char **argv)
        if (mtu != -1) {
                set_mtu(dev, mtu);
        }
+       if (master != -1) {
+               set_master(dev, master);
+       }
        if (mask)
                do_chflags(dev, flags, mask);
        return 0;
@@ -673,6 +709,8 @@ int FAST_FUNC do_iplink(char **argv)
 {
        static const char keywords[] ALIGN1 =
                "add\0""delete\0""set\0""show\0""lst\0""list\0";
+
+       xfunc_error_retval = 2; //TODO: move up to "ip"? Is it the common rule for all "ip" tools?
        if (*argv) {
                int key = index_in_substrings(keywords, *argv);
                if (key < 0) /* invalid argument */
index d4c69e0f76a270b76d2e62fd66ebfc4059ef276f..2feb63a0139f7df74877610bb6df1964024cadae 100644 (file)
@@ -318,7 +318,7 @@ int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv)
        sslser = user;
        client = 0;
        if ((getuid() == 0) && !(opts & OPT_u)) {
-               xfunc_exitcode = 100;
+               xfunc_error_retval = 100;
                bb_error_msg_and_die(bb_msg_you_must_be_root);
        }
        if (opts & OPT_u)