]> git.proxmox.com Git - mirror_iproute2.git/blobdiff - ip/iplink.c
Merge branch 'master' into next
[mirror_iproute2.git] / ip / iplink.c
index 6d3ebdee512529cae9291d6073a0a276c399eb1b..47f73988c2d58da5a7e362b2c2cc2b3afcb64186 100644 (file)
@@ -54,74 +54,78 @@ void iplink_usage(void)
        if (iplink_have_newlink()) {
                fprintf(stderr,
                        "Usage: ip link add [link DEV] [ name ] NAME\n"
-                       "                   [ txqueuelen PACKETS ]\n"
-                       "                   [ address LLADDR ]\n"
-                       "                   [ broadcast LLADDR ]\n"
-                       "                   [ mtu MTU ] [index IDX ]\n"
-                       "                   [ numtxqueues QUEUE_COUNT ]\n"
-                       "                   [ numrxqueues QUEUE_COUNT ]\n"
-                       "                   type TYPE [ ARGS ]\n"
+                       "                   [ txqueuelen PACKETS ]\n"
+                       "                   [ address LLADDR ]\n"
+                       "                   [ broadcast LLADDR ]\n"
+                       "                   [ mtu MTU ] [index IDX ]\n"
+                       "                   [ numtxqueues QUEUE_COUNT ]\n"
+                       "                   [ numrxqueues QUEUE_COUNT ]\n"
+                       "                   type TYPE [ ARGS ]\n"
                        "\n"
-                       "       ip link delete { DEVICE | dev DEVICE | group DEVGROUP } type TYPE [ ARGS ]\n"
+                       "       ip link delete { DEVICE | dev DEVICE | group DEVGROUP } type TYPE [ ARGS ]\n"
                        "\n"
-                       "       ip link set { DEVICE | dev DEVICE | group DEVGROUP }\n"
-                       "                         [ { up | down } ]\n"
-                       "                         [ type TYPE ARGS ]\n");
+                       "       ip link set { DEVICE | dev DEVICE | group DEVGROUP }\n"
+                       "                       [ { up | down } ]\n"
+                       "                       [ type TYPE ARGS ]\n");
        } else
                fprintf(stderr,
                        "Usage: ip link set DEVICE [ { up | down } ]\n");
 
        fprintf(stderr,
-               "                         [ arp { on | off } ]\n"
-               "                         [ dynamic { on | off } ]\n"
-               "                         [ multicast { on | off } ]\n"
-               "                         [ allmulticast { on | off } ]\n"
-               "                         [ promisc { on | off } ]\n"
-               "                         [ trailers { on | off } ]\n"
-               "                         [ carrier { on | off } ]\n"
-               "                         [ txqueuelen PACKETS ]\n"
-               "                         [ name NEWNAME ]\n"
-               "                         [ address LLADDR ]\n"
-               "                         [ broadcast LLADDR ]\n"
-               "                         [ mtu MTU ]\n"
-               "                         [ netns { PID | NAME } ]\n"
-               "                         [ link-netnsid ID ]\n"
-               "                         [ alias NAME ]\n"
-               "                         [ vf NUM [ mac LLADDR ]\n"
-               "                                  [ vlan VLANID [ qos VLAN-QOS ] [ proto VLAN-PROTO ] ]\n"
-               "                                  [ rate TXRATE ]\n"
-               "                                  [ max_tx_rate TXRATE ]\n"
-               "                                  [ min_tx_rate TXRATE ]\n"
-               "                                  [ spoofchk { on | off} ]\n"
-               "                                  [ query_rss { on | off} ]\n"
-               "                                  [ state { auto | enable | disable} ] ]\n"
-               "                                  [ trust { on | off} ] ]\n"
-               "                                  [ node_guid { eui64 } ]\n"
-               "                                  [ port_guid { eui64 } ]\n"
-               "                         [ xdp { off |\n"
+               "               [ arp { on | off } ]\n"
+               "               [ dynamic { on | off } ]\n"
+               "               [ multicast { on | off } ]\n"
+               "               [ allmulticast { on | off } ]\n"
+               "               [ promisc { on | off } ]\n"
+               "               [ trailers { on | off } ]\n"
+               "               [ carrier { on | off } ]\n"
+               "               [ txqueuelen PACKETS ]\n"
+               "               [ name NEWNAME ]\n"
+               "               [ address LLADDR ]\n"
+               "               [ broadcast LLADDR ]\n"
+               "               [ mtu MTU ]\n"
+               "               [ netns { PID | NAME } ]\n"
+               "               [ link-netns NAME | link-netnsid ID ]\n"
+               "                       [ alias NAME ]\n"
+               "                       [ vf NUM [ mac LLADDR ]\n"
+               "                                [ vlan VLANID [ qos VLAN-QOS ] [ proto VLAN-PROTO ] ]\n"
+               "                                [ rate TXRATE ]\n"
+               "                                [ max_tx_rate TXRATE ]\n"
+               "                                [ min_tx_rate TXRATE ]\n"
+               "                                [ spoofchk { on | off} ]\n"
+               "                                [ query_rss { on | off} ]\n"
+               "                                [ state { auto | enable | disable} ] ]\n"
+               "                                [ trust { on | off} ] ]\n"
+               "                                [ node_guid { eui64 } ]\n"
+               "                                [ port_guid { eui64 } ]\n"
+               "                       [ { xdp | xdpgeneric | xdpdrv | xdpoffload } { off |\n"
                "                                 object FILE [ section NAME ] [ verbose ] |\n"
                "                                 pinned FILE } ]\n"
-               "                         [ master DEVICE ][ vrf NAME ]\n"
-               "                         [ nomaster ]\n"
-               "                         [ addrgenmode { eui64 | none | stable_secret | random } ]\n"
-               "                         [ protodown { on | off } ]\n"
-               "                         [ gso_max_size BYTES ] | [ gso_max_segs PACKETS ]\n"
+               "                       [ master DEVICE ][ vrf NAME ]\n"
+               "                       [ nomaster ]\n"
+               "                       [ addrgenmode { eui64 | none | stable_secret | random } ]\n"
+               "                       [ protodown { on | off } ]\n"
+               "                       [ gso_max_size BYTES ] | [ gso_max_segs PACKETS ]\n"
                "\n"
-               "       ip link show [ DEVICE | group GROUP ] [up] [master DEV] [vrf NAME] [type TYPE]\n");
-
-       fprintf(stderr, "\n       ip link xstats type TYPE [ ARGS ]\n");
-       fprintf(stderr, "\n       ip link afstats [ dev DEVICE ]\n");
+               "       ip link show [ DEVICE | group GROUP ] [up] [master DEV] [vrf NAME] [type TYPE]\n"
+               "\n"
+               "       ip link xstats type TYPE [ ARGS ]\n"
+               "\n"
+               "       ip link afstats [ dev DEVICE ]\n"
+               "       ip link property add dev DEVICE [ altname NAME .. ]\n"
+               "       ip link property del dev DEVICE [ altname NAME .. ]\n");
 
        if (iplink_have_newlink()) {
                fprintf(stderr,
                        "\n"
-                       "       ip link help [ TYPE ]\n"
+                       "       ip link help [ TYPE ]\n"
                        "\n"
                        "TYPE := { vlan | veth | vcan | vxcan | dummy | ifb | macvlan | macvtap |\n"
-                       "          bridge | bond | team | ipoib | ip6tnl | ipip | sit | vxlan |\n"
-                       "          gre | gretap | erspan | ip6gre | ip6gretap | ip6erspan |\n"
-                       "          vti | nlmon | team_slave | bond_slave | ipvlan | geneve |\n"
-                       "          bridge_slave | vrf | macsec | netdevsim }\n");
+                       "          bridge | bond | team | ipoib | ip6tnl | ipip | sit | vxlan |\n"
+                       "          gre | gretap | erspan | ip6gre | ip6gretap | ip6erspan |\n"
+                       "          vti | nlmon | team_slave | bond_slave | bridge_slave |\n"
+                       "          ipvlan | ipvtap | geneve | vrf | macsec | netdevsim | rmnet |\n"
+                       "          xfrm }\n");
        }
        exit(-1);
 }
@@ -199,8 +203,7 @@ static int get_addr_gen_mode(const char *mode)
 #if IPLINK_IOCTL_COMPAT
 static int have_rtnl_newlink = -1;
 
-static int accept_msg(const struct sockaddr_nl *who,
-                     struct rtnl_ctrl_data *ctrl,
+static int accept_msg(struct rtnl_ctrl_data *ctrl,
                      struct nlmsghdr *n, void *arg)
 {
        struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
@@ -242,9 +245,10 @@ static int iplink_have_newlink(void)
 }
 #endif /* ! IPLINK_IOCTL_COMPAT */
 
-static int nl_get_ll_addr_len(unsigned int dev_index)
+static int nl_get_ll_addr_len(const char *ifname)
 {
        int len;
+       int dev_index = ll_name_to_index(ifname);
        struct iplink_req req = {
                .n = {
                        .nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
@@ -259,6 +263,9 @@ static int nl_get_ll_addr_len(unsigned int dev_index)
        struct nlmsghdr *answer;
        struct rtattr *tb[IFLA_MAX+1];
 
+       if (dev_index == 0)
+               return -1;
+
        if (rtnl_talk(&rth, &req.n, &answer) < 0)
                return -1;
 
@@ -275,8 +282,9 @@ static int nl_get_ll_addr_len(unsigned int dev_index)
                return -1;
        }
 
+       len = RTA_PAYLOAD(tb[IFLA_ADDRESS]);
        free(answer);
-       return RTA_PAYLOAD(tb[IFLA_ADDRESS]);
+       return len;
 }
 
 static void iplink_parse_vf_vlan_info(int vf, int *argcp, char ***argvp,
@@ -336,7 +344,7 @@ static void iplink_parse_vf_vlan_info(int vf, int *argcp, char ***argvp,
 }
 
 static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
-                          struct iplink_req *req, int dev_index)
+                          struct iplink_req *req, const char *dev)
 {
        char new_rate_api = 0, count = 0, override_legacy_rate = 0;
        struct ifla_vf_rate tivt;
@@ -372,7 +380,7 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
                NEXT_ARG();
                if (matches(*argv, "mac") == 0) {
                        struct ifla_vf_mac ivm = { 0 };
-                       int halen = nl_get_ll_addr_len(dev_index);
+                       int halen = nl_get_ll_addr_len(dev);
 
                        NEXT_ARG();
                        ivm.vf = vf;
@@ -541,7 +549,7 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
                int tmin, tmax;
 
                if (tivt.min_tx_rate == -1 || tivt.max_tx_rate == -1) {
-                       ipaddr_get_vf_rate(tivt.vf, &tmin, &tmax, dev_index);
+                       ipaddr_get_vf_rate(tivt.vf, &tmin, &tmax, dev);
                        if (tivt.min_tx_rate == -1)
                                tivt.min_tx_rate = tmin;
                        if (tivt.max_tx_rate == -1)
@@ -569,10 +577,11 @@ static int iplink_parse_vf(int vf, int *argcp, char ***argvp,
        return 0;
 }
 
-int iplink_parse(int argc, char **argv, struct iplink_req *req,
-                char **name, char **type, char **link, char **dev,
-                int *group, int *index)
+int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type)
 {
+       char *name = NULL;
+       char *dev = NULL;
+       char *link = NULL;
        int ret, len;
        char abuf[32];
        int qlen = -1;
@@ -581,11 +590,11 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
        int vf = -1;
        int numtxqueues = -1;
        int numrxqueues = -1;
-       int dev_index = 0;
        int link_netnsid = -1;
+       int index = 0;
+       int group = -1;
        int addr_len = 0;
 
-       *group = -1;
        ret = argc;
 
        while (argc > 0) {
@@ -597,25 +606,23 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
                        req->i.ifi_flags &= ~IFF_UP;
                } else if (strcmp(*argv, "name") == 0) {
                        NEXT_ARG();
-                       if (*name)
+                       if (name)
                                duparg("name", *argv);
                        if (check_ifname(*argv))
                                invarg("\"name\" not a valid ifname", *argv);
-                       *name = *argv;
-                       if (!*dev) {
-                               *dev = *name;
-                               dev_index = ll_name_to_index(*dev);
-                       }
+                       name = *argv;
+                       if (!dev)
+                               dev = name;
                } else if (strcmp(*argv, "index") == 0) {
                        NEXT_ARG();
-                       if (*index)
+                       if (index)
                                duparg("index", *argv);
-                       *index = atoi(*argv);
-                       if (*index <= 0)
+                       index = atoi(*argv);
+                       if (index <= 0)
                                invarg("Invalid \"index\" value", *argv);
                } else if (matches(*argv, "link") == 0) {
                        NEXT_ARG();
-                       *link = *argv;
+                       link = *argv;
                } else if (matches(*argv, "address") == 0) {
                        NEXT_ARG();
                        addr_len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
@@ -657,12 +664,12 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
                        bool offload = strcmp(*argv, "xdpoffload") == 0;
 
                        NEXT_ARG();
-                       if (xdp_parse(&argc, &argv, req, dev_index,
+                       if (xdp_parse(&argc, &argv, req, dev,
                                      generic, drv, offload))
                                exit(-1);
 
-                       if (offload && *name == *dev)
-                               *dev = NULL;
+                       if (offload && name == dev)
+                               dev = NULL;
                } else if (strcmp(*argv, "netns") == 0) {
                        NEXT_ARG();
                        if (netns != -1)
@@ -747,16 +754,16 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
 
                        vflist = addattr_nest(&req->n, sizeof(*req),
                                              IFLA_VFINFO_LIST);
-                       if (dev_index == 0)
+                       if (!dev)
                                missarg("dev");
 
-                       len = iplink_parse_vf(vf, &argc, &argv, req, dev_index);
+                       len = iplink_parse_vf(vf, &argc, &argv, req, dev);
                        if (len < 0)
                                return -1;
                        addattr_nest_end(&req->n, vflist);
 
-                       if (*name == *dev)
-                               *dev = NULL;
+                       if (name == dev)
+                               dev = NULL;
                } else if (matches(*argv, "master") == 0) {
                        int ifindex;
 
@@ -806,10 +813,11 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
                                  *argv, len);
                } else if (strcmp(*argv, "group") == 0) {
                        NEXT_ARG();
-                       if (*group != -1)
+                       if (group != -1)
                                duparg("group", *argv);
-                       if (rtnl_group_a2n(group, *argv))
+                       if (rtnl_group_a2n(&group, *argv))
                                invarg("Invalid \"group\" value\n", *argv);
+                       addattr32(&req->n, sizeof(*req), IFLA_GROUP, group);
                } else if (strcmp(*argv, "mode") == 0) {
                        int mode;
 
@@ -860,10 +868,24 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
                                 IFLA_INET6_ADDR_GEN_MODE, mode);
                        addattr_nest_end(&req->n, afs6);
                        addattr_nest_end(&req->n, afs);
+               } else if (matches(*argv, "link-netns") == 0) {
+                       NEXT_ARG();
+                       if (link_netnsid != -1)
+                               duparg("link-netns/link-netnsid", *argv);
+                       link_netnsid = get_netnsid_from_name(*argv);
+                       /* No nsid? Try to assign one. */
+                       if (link_netnsid < 0)
+                               set_netnsid_from_name(*argv, -1);
+                       link_netnsid = get_netnsid_from_name(*argv);
+                       if (link_netnsid < 0)
+                               invarg("Invalid \"link-netns\" value\n",
+                                      *argv);
+                       addattr32(&req->n, sizeof(*req), IFLA_LINK_NETNSID,
+                                 link_netnsid);
                } else if (matches(*argv, "link-netnsid") == 0) {
                        NEXT_ARG();
                        if (link_netnsid != -1)
-                               duparg("link-netnsid", *argv);
+                               duparg("link-netns/link-netnsid", *argv);
                        if (get_integer(&link_netnsid, *argv, 0))
                                invarg("Invalid \"link-netnsid\" value\n",
                                       *argv);
@@ -907,26 +929,28 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
 
                        if (strcmp(*argv, "dev") == 0)
                                NEXT_ARG();
-                       if (*dev != *name)
+                       if (dev != name)
                                duparg2("dev", *argv);
-                       if (check_ifname(*argv))
+                       if (check_altifname(*argv))
                                invarg("\"dev\" not a valid ifname", *argv);
-                       *dev = *argv;
-                       dev_index = ll_name_to_index(*dev);
+                       dev = *argv;
                }
                argc--; argv++;
        }
 
+       ret -= argc;
+
        /* Allow "ip link add dev" and "ip link add name" */
-       if (!*name)
-               *name = *dev;
-       else if (!*dev)
-               *dev = *name;
-       else if (!strcmp(*name, *dev))
-               *name = *dev;
+       if (!name)
+               name = dev;
+       else if (!dev)
+               dev = name;
+       else if (!strcmp(name, dev))
+               name = dev;
 
-       if (dev_index && addr_len) {
-               int halen = nl_get_ll_addr_len(dev_index);
+       if (dev && addr_len &&
+           !(req->n.nlmsg_flags & NLM_F_CREATE)) {
+               int halen = nl_get_ll_addr_len(dev);
 
                if (halen >= 0 && halen != addr_len) {
                        fprintf(stderr,
@@ -936,73 +960,40 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
                }
        }
 
-       return ret - argc;
-}
-
-static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
-{
-       char *dev = NULL;
-       char *name = NULL;
-       char *link = NULL;
-       char *type = NULL;
-       int index = 0;
-       int group;
-       struct link_util *lu = NULL;
-       struct iplink_req req = {
-               .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
-               .n.nlmsg_flags = NLM_F_REQUEST | flags,
-               .n.nlmsg_type = cmd,
-               .i.ifi_family = preferred_family,
-       };
-       int ret;
-
-       ret = iplink_parse(argc, argv,
-                          &req, &name, &type, &link, &dev, &group, &index);
-       if (ret < 0)
-               return ret;
-
-       argc -= ret;
-       argv += ret;
-
-       if (!(flags & NLM_F_CREATE) && index) {
+       if (!(req->n.nlmsg_flags & NLM_F_CREATE) && index) {
                fprintf(stderr,
                        "index can be used only when creating devices.\n");
                exit(-1);
        }
 
        if (group != -1) {
-               if (dev)
-                       addattr_l(&req.n, sizeof(req), IFLA_GROUP,
-                                       &group, sizeof(group));
-               else {
+               if (!dev) {
                        if (argc) {
                                fprintf(stderr,
                                        "Garbage instead of arguments \"%s ...\". Try \"ip link help\".\n",
                                        *argv);
-                               return -1;
+                               exit(-1);
                        }
-                       if (flags & NLM_F_CREATE) {
+                       if (req->n.nlmsg_flags & NLM_F_CREATE) {
                                fprintf(stderr,
                                        "group cannot be used when creating devices.\n");
-                               return -1;
+                               exit(-1);
                        }
 
-                       addattr32(&req.n, sizeof(req), IFLA_GROUP, group);
-                       if (rtnl_talk(&rth, &req.n, NULL) < 0)
-                               return -2;
-                       return 0;
+                       *type = NULL;
+                       return ret;
                }
        }
 
-       if (!(flags & NLM_F_CREATE)) {
+       if (!(req->n.nlmsg_flags & NLM_F_CREATE)) {
                if (!dev) {
                        fprintf(stderr,
                                "Not enough information: \"dev\" argument is required.\n");
                        exit(-1);
                }
 
-               req.i.ifi_index = ll_name_to_index(dev);
-               if (!req.i.ifi_index)
+               req->i.ifi_index = ll_name_to_index(dev);
+               if (!req->i.ifi_index)
                        return nodev(dev);
 
                /* Not renaming to the same name */
@@ -1021,18 +1012,37 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
                        ifindex = ll_name_to_index(link);
                        if (!ifindex)
                                return nodev(link);
-                       addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifindex, 4);
+                       addattr32(&req->n, sizeof(*req), IFLA_LINK, ifindex);
                }
 
-               req.i.ifi_index = index;
+               req->i.ifi_index = index;
        }
 
        if (name) {
-               addattr_l(&req.n, sizeof(req),
+               addattr_l(&req->n, sizeof(*req),
                          IFLA_IFNAME, name, strlen(name) + 1);
        }
 
+       return ret;
+}
+
+static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
+{
+       char *type = NULL;
+       struct iplink_req req = {
+               .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
+               .n.nlmsg_flags = NLM_F_REQUEST | flags,
+               .n.nlmsg_type = cmd,
+               .i.ifi_family = preferred_family,
+       };
+       int ret;
+
+       ret = iplink_parse(argc, argv, &req, &type);
+       if (ret < 0)
+               return ret;
+
        if (type) {
+               struct link_util *lu;
                struct rtattr *linkinfo;
                char *ulinep = strchr(type, '_');
                int iflatype;
@@ -1046,6 +1056,10 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
                        iflatype = IFLA_INFO_SLAVE_DATA;
                else
                        iflatype = IFLA_INFO_DATA;
+
+               argc -= ret;
+               argv += ret;
+
                if (lu && argc) {
                        struct rtattr *data;
 
@@ -1074,14 +1088,17 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
        if (rtnl_talk(&rth, &req.n, NULL) < 0)
                return -2;
 
+       /* remove device from cache; next use can refresh with new data */
+       ll_drop_by_index(req.i.ifi_index);
+
        return 0;
 }
 
-int iplink_get(unsigned int flags, char *name, __u32 filt_mask)
+int iplink_get(char *name, __u32 filt_mask)
 {
        struct iplink_req req = {
                .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
-               .n.nlmsg_flags = NLM_F_REQUEST | flags,
+               .n.nlmsg_flags = NLM_F_REQUEST,
                .n.nlmsg_type = RTM_GETLINK,
                .i.ifi_family = preferred_family,
        };
@@ -1089,7 +1106,8 @@ int iplink_get(unsigned int flags, char *name, __u32 filt_mask)
 
        if (name) {
                addattr_l(&req.n, sizeof(req),
-                         IFLA_IFNAME, name, strlen(name) + 1);
+                         !check_ifname(name) ? IFLA_IFNAME : IFLA_ALT_IFNAME,
+                         name, strlen(name) + 1);
        }
        addattr32(&req.n, sizeof(req), IFLA_EXT_MASK, filt_mask);
 
@@ -1097,7 +1115,7 @@ int iplink_get(unsigned int flags, char *name, __u32 filt_mask)
                return -2;
 
        open_json_object(NULL);
-       print_linkinfo(NULL, answer, stdout);
+       print_linkinfo(answer, stdout);
        close_json_object();
 
        free(answer);
@@ -1131,7 +1149,7 @@ static int do_chflags(const char *dev, __u32 flags, __u32 mask)
        int fd;
        int err;
 
-       strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+       strlcpy(ifr.ifr_name, dev, IFNAMSIZ);
        fd = get_ctl_fd();
        if (fd < 0)
                return -1;
@@ -1158,8 +1176,8 @@ static int do_changename(const char *dev, const char *newdev)
        int fd;
        int err;
 
-       strncpy(ifr.ifr_name, dev, IFNAMSIZ);
-       strncpy(ifr.ifr_newname, newdev, IFNAMSIZ);
+       strlcpy(ifr.ifr_name, dev, IFNAMSIZ);
+       strlcpy(ifr.ifr_newname, newdev, IFNAMSIZ);
        fd = get_ctl_fd();
        if (fd < 0)
                return -1;
@@ -1182,7 +1200,7 @@ static int set_qlen(const char *dev, int qlen)
        if (s < 0)
                return -1;
 
-       strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+       strlcpy(ifr.ifr_name, dev, IFNAMSIZ);
        if (ioctl(s, SIOCSIFTXQLEN, &ifr) < 0) {
                perror("SIOCSIFXQLEN");
                close(s);
@@ -1202,7 +1220,7 @@ static int set_mtu(const char *dev, int mtu)
        if (s < 0)
                return -1;
 
-       strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+       strlcpy(ifr.ifr_name, dev, IFNAMSIZ);
        if (ioctl(s, SIOCSIFMTU, &ifr) < 0) {
                perror("SIOCSIFMTU");
                close(s);
@@ -1229,7 +1247,7 @@ static int get_address(const char *dev, int *htype)
                return -1;
        }
 
-       strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+       strlcpy(ifr.ifr_name, dev, IFNAMSIZ);
        if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
                perror("SIOCGIFINDEX");
                close(s);
@@ -1260,7 +1278,7 @@ static int parse_address(const char *dev, int hatype, int halen,
        int alen;
 
        memset(ifr, 0, sizeof(*ifr));
-       strncpy(ifr->ifr_name, dev, IFNAMSIZ);
+       strlcpy(ifr->ifr_name, dev, IFNAMSIZ);
        ifr->ifr_hwaddr.sa_family = hatype;
        alen = ll_addr_a2n(ifr->ifr_hwaddr.sa_data, 14, lla);
        if (alen < 0)
@@ -1526,9 +1544,7 @@ struct af_stats_ctx {
        int ifindex;
 };
 
-static int print_af_stats(const struct sockaddr_nl *who,
-                         struct nlmsghdr *n,
-                         void *arg)
+static int print_af_stats(struct nlmsghdr *n, void *arg)
 {
        struct if_stats_msg *ifsm = NLMSG_DATA(n);
        struct rtattr *tb[IFLA_STATS_MAX+1];
@@ -1591,9 +1607,7 @@ static int iplink_afstats(int argc, char **argv)
                }
        }
 
-       if (rtnl_wilddump_stats_req_filter(&rth, AF_UNSPEC,
-                                          RTM_GETSTATS,
-                                          filt_mask) < 0) {
+       if (rtnl_statsdump_req_filter(&rth, AF_UNSPEC, filt_mask) < 0) {
                perror("Cannont send dump request");
                return 1;
        }
@@ -1606,6 +1620,80 @@ static int iplink_afstats(int argc, char **argv)
        return 0;
 }
 
+static int iplink_prop_mod(int argc, char **argv, struct iplink_req *req)
+{
+       struct rtattr *proplist;
+       char *dev = NULL;
+       char *name;
+
+       proplist = addattr_nest(&req->n, sizeof(*req),
+                               IFLA_PROP_LIST | NLA_F_NESTED);
+
+       while (argc > 0) {
+               if (matches(*argv, "altname") == 0) {
+                       NEXT_ARG();
+                       if (check_altifname(*argv))
+                               invarg("not a valid altname", *argv);
+                       name = *argv;
+                       addattr_l(&req->n, sizeof(*req), IFLA_ALT_IFNAME,
+                                 name, strlen(name) + 1);
+               } else if (matches(*argv, "help") == 0) {
+                       usage();
+               } else {
+                       if (strcmp(*argv, "dev") == 0)
+                               NEXT_ARG();
+                       if (dev)
+                               duparg2("dev", *argv);
+                       if (check_altifname(*argv))
+                               invarg("\"dev\" not a valid ifname", *argv);
+                       dev = *argv;
+               }
+               argv++; argc--;
+       }
+       addattr_nest_end(&req->n, proplist);
+
+       if (!dev) {
+               fprintf(stderr, "Not enough of information: \"dev\" argument is required.\n");
+               exit(-1);
+       }
+
+       req->i.ifi_index = ll_name_to_index(dev);
+       if (!req->i.ifi_index)
+               return nodev(dev);
+
+       if (rtnl_talk(&rth, &req->n, NULL) < 0)
+               return -2;
+
+       return 0;
+}
+
+static int iplink_prop(int argc, char **argv)
+{
+       struct iplink_req req = {
+               .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
+               .n.nlmsg_flags = NLM_F_REQUEST,
+               .i.ifi_family = preferred_family,
+       };
+
+       if (argc <= 0) {
+               usage();
+               exit(-1);
+       }
+
+       if (matches(*argv, "add") == 0) {
+               req.n.nlmsg_flags |= NLM_F_EXCL | NLM_F_CREATE | NLM_F_APPEND;
+               req.n.nlmsg_type = RTM_NEWLINKPROP;
+       } else if (matches(*argv, "del") == 0) {
+               req.n.nlmsg_type = RTM_DELLINKPROP;
+       } else if (matches(*argv, "help") == 0) {
+               usage();
+       } else {
+               fprintf(stderr, "Operator required\n");
+               exit(-1);
+       }
+       return iplink_prop_mod(argc - 1, argv + 1, &req);
+}
+
 static void do_help(int argc, char **argv)
 {
        struct link_util *lu = NULL;
@@ -1663,6 +1751,9 @@ int do_iplink(int argc, char **argv)
                return 0;
        }
 
+       if (matches(*argv, "property") == 0)
+               return iplink_prop(argc-1, argv+1);
+
        if (matches(*argv, "help") == 0) {
                do_help(argc-1, argv+1);
                return 0;