]> git.proxmox.com Git - mirror_iproute2.git/blobdiff - ip/iplink.c
libnetlink: add size argument to rtnl_talk
[mirror_iproute2.git] / ip / iplink.c
index 1a907d998a87f3730a68cd8de8baa6fd544d0113..a4a498055d463518028e1e1435b86c828e9ca853 100644 (file)
@@ -32,6 +32,7 @@
 #include "rt_names.h"
 #include "utils.h"
 #include "ip_common.h"
+#include "namespace.h"
 
 #define IPLINK_IOCTL_COMPAT    1
 #ifndef LIBDIR
@@ -52,9 +53,9 @@ void iplink_usage(void)
                fprintf(stderr, "                   [ numtxqueues QUEUE_COUNT ]\n");
                fprintf(stderr, "                   [ numrxqueues QUEUE_COUNT ]\n");
                fprintf(stderr, "                   type TYPE [ ARGS ]\n");
-               fprintf(stderr, "       ip link delete DEV type TYPE [ ARGS ]\n");
+               fprintf(stderr, "       ip link delete { DEVICE | dev DEVICE | group DEVGROUP } type TYPE [ ARGS ]\n");
                fprintf(stderr, "\n");
-               fprintf(stderr, "       ip link set { dev DEVICE | group DEVGROUP } [ { up | down } ]\n");
+               fprintf(stderr, "       ip link set { DEVICE | dev DEVICE | group DEVGROUP } [ { up | down } ]\n");
        } else
                fprintf(stderr, "Usage: ip link set DEVICE [ { up | down } ]\n");
 
@@ -71,6 +72,7 @@ void iplink_usage(void)
        fprintf(stderr, "                         [ mtu MTU ]\n");
        fprintf(stderr, "                         [ netns PID ]\n");
        fprintf(stderr, "                         [ netns NAME ]\n");
+       fprintf(stderr, "                         [ link-netnsid ID ]\n");
        fprintf(stderr, "                         [ alias NAME ]\n");
        fprintf(stderr, "                         [ vf NUM [ mac LLADDR ]\n");
        fprintf(stderr, "                                  [ vlan VLANID [ qos VLAN-QOS ] ]\n");
@@ -78,17 +80,20 @@ void iplink_usage(void)
        fprintf(stderr, "                                  [ rate TXRATE ] ] \n");
 
        fprintf(stderr, "                                  [ spoofchk { on | off} ] ] \n");
+       fprintf(stderr, "                                  [ query_rss { on | off} ] ] \n");
        fprintf(stderr, "                                  [ state { auto | enable | disable} ] ]\n");
        fprintf(stderr, "                         [ master DEVICE ]\n");
        fprintf(stderr, "                         [ nomaster ]\n");
        fprintf(stderr, "                         [ addrgenmode { eui64 | none } ]\n");
-       fprintf(stderr, "       ip link show [ DEVICE | group GROUP ] [up]\n");
+       fprintf(stderr, "       ip link show [ DEVICE | group GROUP ] [up] [master DEV] [type TYPE]\n");
 
        if (iplink_have_newlink()) {
+               fprintf(stderr, "       ip link help [ TYPE ]\n");
                fprintf(stderr, "\n");
                fprintf(stderr, "TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap |\n");
                fprintf(stderr, "          bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan |\n");
-               fprintf(stderr, "          gre | gretap | ip6gre | ip6gretap | vti | nlmon }\n");
+               fprintf(stderr, "          gre | gretap | ip6gre | ip6gretap | vti | nlmon |\n");
+               fprintf(stderr, "          bond_slave | ipvlan }\n");
        }
        exit(-1);
 }
@@ -327,6 +332,18 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
                        ivs.vf = vf;
                        addattr_l(&req->n, sizeof(*req), IFLA_VF_SPOOFCHK, &ivs, sizeof(ivs));
 
+               } else if (matches(*argv, "query_rss") == 0) {
+                       struct ifla_vf_rss_query_en ivs;
+                       NEXT_ARG();
+                       if (matches(*argv, "on") == 0)
+                               ivs.setting = 1;
+                       else if (matches(*argv, "off") == 0)
+                               ivs.setting = 0;
+                       else
+                               invarg("Invalid \"query_rss\" value\n", *argv);
+                       ivs.vf = vf;
+                       addattr_l(&req->n, sizeof(*req), IFLA_VF_RSS_QUERY_EN, &ivs, sizeof(ivs));
+
                } else if (matches(*argv, "state") == 0) {
                        struct ifla_vf_link_state ivl;
                        NEXT_ARG();
@@ -383,6 +400,7 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
        int numtxqueues = -1;
        int numrxqueues = -1;
        int dev_index = 0;
+       int link_netnsid = -1;
 
        *group = -1;
        ret = argc;
@@ -400,6 +418,8 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
                } else if (strcmp(*argv, "index") == 0) {
                        NEXT_ARG();
                        *index = atoi(*argv);
+                       if (*index < 0)
+                               invarg("Invalid \"index\" value", *argv);
                } else if (matches(*argv, "link") == 0) {
                        NEXT_ARG();
                        *link = *argv;
@@ -436,7 +456,7 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
                        NEXT_ARG();
                        if (netns != -1)
                                duparg("netns", *argv);
-                       if ((netns = get_netns_fd(*argv)) >= 0)
+                       if ((netns = netns_get_fd(*argv)) >= 0)
                                addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_FD, &netns, 4);
                        else if (get_integer(&netns, *argv, 0) == 0)
                                addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID, &netns, 4);
@@ -583,6 +603,14 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
                        addattr8(&req->n, sizeof(*req), IFLA_INET6_ADDR_GEN_MODE, mode);
                        addattr_nest_end(&req->n, afs6);
                        addattr_nest_end(&req->n, afs);
+               } else if (matches(*argv, "link-netnsid") == 0) {
+                       NEXT_ARG();
+                       if (link_netnsid != -1)
+                               duparg("link-netnsid", *argv);
+                       if (get_integer(&link_netnsid, *argv, 0))
+                               invarg("Invalid \"link-netnsid\" value\n", *argv);
+                       addattr32(&req->n, sizeof(*req), IFLA_LINK_NETNSID,
+                                 link_netnsid);
                } else {
                        if (strcmp(*argv, "dev") == 0) {
                                NEXT_ARG();
@@ -593,8 +621,6 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
                                duparg2("dev", *argv);
                        *dev = *argv;
                        dev_index = ll_name_to_index(*dev);
-                       if (dev_index == 0)
-                               invarg("Unknown device", *argv);
                }
                argc--; argv++;
        }
@@ -609,7 +635,7 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
        char *name = NULL;
        char *link = NULL;
        char *type = NULL;
-       int index = 0;
+       int index = -1;
        int group;
        struct link_util *lu = NULL;
        struct iplink_req req;
@@ -648,7 +674,7 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
 
                        req.i.ifi_index = 0;
                        addattr32(&req.n, sizeof(req), IFLA_GROUP, group);
-                       if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+                       if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
                                exit(2);
                        return 0;
                }
@@ -660,6 +686,11 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
                                        "argument is required.\n");
                        exit(-1);
                }
+               if (cmd == RTM_NEWLINK && index != -1) {
+                       fprintf(stderr, "index can be used only when "
+                                       "creating devices.\n");
+                       exit(-1);
+               }
 
                req.i.ifi_index = ll_name_to_index(dev);
                if (req.i.ifi_index == 0) {
@@ -683,7 +714,10 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
                        addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifindex, 4);
                }
 
-               req.i.ifi_index = index;
+               if (index == -1)
+                       req.i.ifi_index = 0;
+               else
+                       req.i.ifi_index = index;
        }
 
        if (name) {
@@ -696,21 +730,35 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
        }
 
        if (type) {
-               struct rtattr *linkinfo = NLMSG_TAIL(&req.n);
-               addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0);
+               struct rtattr *linkinfo;
+               char slavebuf[128], *ulinep = strchr(type, '_');
+               int iflatype;
+
+               linkinfo = addattr_nest(&req.n, sizeof(req), IFLA_LINKINFO);
                addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type,
                         strlen(type));
 
-               lu = get_link_kind(type);
+               if (ulinep && !strcmp(ulinep, "_slave")) {
+                       strncpy(slavebuf, type, sizeof(slavebuf));
+                       slavebuf[sizeof(slavebuf) - 1] = '\0';
+                       ulinep = strchr(slavebuf, '_');
+                       /* check in case it was after sizeof(slavebuf) - 1*/
+                       if (ulinep)
+                               *ulinep = '\0';
+                       lu = get_link_slave_kind(slavebuf);
+                       iflatype = IFLA_INFO_SLAVE_DATA;
+               } else {
+                       lu = get_link_kind(type);
+                       iflatype = IFLA_INFO_DATA;
+               }
                if (lu && argc) {
-                       struct rtattr * data = NLMSG_TAIL(&req.n);
-                       addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0);
+                       struct rtattr *data = addattr_nest(&req.n, sizeof(req), iflatype);
 
                        if (lu->parse_opt &&
                            lu->parse_opt(lu, argc, argv, &req.n))
                                return -1;
 
-                       data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data;
+                       addattr_nest_end(&req.n, data);
                } else if (argc) {
                        if (matches(*argv, "help") == 0)
                                usage();
@@ -718,14 +766,14 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
                                        "Try \"ip link help\".\n", *argv);
                        return -1;
                }
-               linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo;
+               addattr_nest_end(&req.n, linkinfo);
        } else if (flags & NLM_F_CREATE) {
                fprintf(stderr, "Not enough information: \"type\" argument "
                                "is required\n");
                return -1;
        }
 
-       if (rtnl_talk(&rth, &req.n, 0, 0, NULL) < 0)
+       if (rtnl_talk(&rth, &req.n, NULL, 0) < 0)
                exit(2);
 
        return 0;
@@ -735,7 +783,10 @@ int iplink_get(unsigned int flags, char *name, __u32 filt_mask)
 {
        int len;
        struct iplink_req req;
-       char answer[16384];
+       struct {
+               struct nlmsghdr n;
+               char buf[16384];
+       } answer;
 
        memset(&req, 0, sizeof(req));
 
@@ -755,10 +806,10 @@ int iplink_get(unsigned int flags, char *name, __u32 filt_mask)
        }
        addattr32(&req.n, sizeof(req), IFLA_EXT_MASK, filt_mask);
 
-       if (rtnl_talk(&rth, &req.n, 0, 0, (struct nlmsghdr *)answer) < 0)
+       if (rtnl_talk(&rth, &req.n, &answer.n, sizeof(answer)) < 0)
                return -2;
 
-       print_linkinfo(NULL, (struct nlmsghdr *)answer, stdout);
+       print_linkinfo(NULL, &answer.n, stdout);
 
        return 0;
 }
@@ -1113,6 +1164,23 @@ static int do_set(int argc, char **argv)
 }
 #endif /* IPLINK_IOCTL_COMPAT */
 
+static void do_help(int argc, char **argv)
+{
+       struct link_util *lu = NULL;
+
+       if (argc <= 0) {
+               usage();
+               return ;
+       }
+
+       lu = get_link_kind(*argv);
+
+       if (lu && lu->print_help)
+               lu->print_help(lu, argc-1, argv+1, stdout);
+       else
+               usage();
+}
+
 int do_iplink(int argc, char **argv)
 {
        if (argc > 0) {
@@ -1142,8 +1210,10 @@ int do_iplink(int argc, char **argv)
                    matches(*argv, "lst") == 0 ||
                    matches(*argv, "list") == 0)
                        return ipaddr_list_link(argc-1, argv+1);
-               if (matches(*argv, "help") == 0)
-                       usage();
+               if (matches(*argv, "help") == 0) {
+                       do_help(argc-1, argv+1);
+                       return 0;
+               }
        } else
                return ipaddr_list_link(0, NULL);