" [ broadcast LLADDR ]\n"
" [ mtu MTU ]\n"
" [ netns { PID | NAME } ]\n"
- " [ link-netnsid ID ]\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"
"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");
+ " vti | nlmon | team_slave | bond_slave | bridge_slave |\n"
+ " ipvlan | ipvtap | geneve | vrf | macsec | netdevsim | rmnet }\n");
}
exit(-1);
}
#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);
}
#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)),
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;
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,
}
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;
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;
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)
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;
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) {
req->i.ifi_flags &= ~IFF_UP;
} else if (strcmp(*argv, "name") == 0) {
NEXT_ARG();
+ if (name)
+ duparg("name", *argv);
if (check_ifname(*argv))
invarg("\"name\" not a valid ifname", *argv);
- *name = *argv;
+ 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);
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;
} else if (strcmp(*argv, "netns") == 0) {
NEXT_ARG();
if (netns != -1)
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;
} else if (matches(*argv, "master") == 0) {
int ifindex;
*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;
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);
if (strcmp(*argv, "dev") == 0)
NEXT_ARG();
- if (*dev)
+ if (dev != name)
duparg2("dev", *argv);
if (check_ifname(*argv))
invarg("\"dev\" not a valid ifname", *argv);
- *dev = *argv;
- dev_index = ll_name_to_index(*dev);
+ dev = *argv;
}
argc--; argv++;
}
- if (dev_index && addr_len) {
- int halen = nl_get_ll_addr_len(dev_index);
+ 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 (dev && addr_len) {
+ int halen = nl_get_ll_addr_len(dev);
if (halen >= 0 && halen != addr_len) {
fprintf(stderr,
}
}
- 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 (!(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);
}
- if (cmd == RTM_NEWLINK && index) {
+
+ req->i.ifi_index = ll_name_to_index(dev);
+ if (!req->i.ifi_index)
+ return nodev(dev);
+
+ /* Not renaming to the same name */
+ if (name == dev)
+ name = NULL;
+ } else {
+ if (name != dev) {
fprintf(stderr,
- "index can be used only when creating devices.\n");
+ "both \"name\" and \"dev\" cannot be used when creating devices.\n");
exit(-1);
}
- req.i.ifi_index = ll_name_to_index(dev);
- if (req.i.ifi_index == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n", dev);
- return -1;
- }
- } else {
- /* Allow "ip link add dev" and "ip link add name" */
- if (!name)
- name = dev;
-
if (link) {
int ifindex;
ifindex = ll_name_to_index(link);
- if (ifindex == 0) {
- fprintf(stderr, "Cannot find device \"%s\"\n",
- link);
- return -1;
- }
- addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifindex, 4);
+ if (!ifindex)
+ return nodev(link);
+ 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;
iflatype = IFLA_INFO_SLAVE_DATA;
else
iflatype = IFLA_INFO_DATA;
+
+ argc -= ret;
+ argv += ret;
+
if (lu && argc) {
- struct rtattr *data
- = addattr_nest(&req.n,
- sizeof(req), iflatype);
+ struct rtattr *data;
+
+ data = addattr_nest(&req.n, sizeof(req), iflatype);
if (lu->parse_opt &&
lu->parse_opt(lu, argc, argv, &req.n))
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,
};
return -2;
open_json_object(NULL);
- if (brief)
- print_linkinfo_brief(NULL, answer, stdout);
- else
- print_linkinfo(NULL, answer, stdout);
+ print_linkinfo(answer, stdout);
close_json_object();
free(answer);
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;
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;
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);
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);
return -1;
}
- strncpy(ifr.ifr_name, dev, IFNAMSIZ);
+ strlcpy(ifr.ifr_name, dev, IFNAMSIZ);
if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
perror("SIOCGIFINDEX");
close(s);
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)
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];
}
}
- 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;
}