mirror of
https://git.kernel.org/pub/scm/network/iproute2/iproute2.git
synced 2024-11-14 13:33:50 +08:00
iplink: Fix link-netns id and link ifindex
When link-netns or link-netnsid is supplied, lookup link in that netns. And if both netns and link-netns are given, IFLA_LINK_NETNSID should be the nsid of link-netns from the view of target netns, not from current one. For example, when handling: # ip -n ns1 link add netns ns2 link-netns ns3 link eth1 eth1.100 type vlan id 100 should lookup eth1 in ns3 and IFLA_LINK_NETNSID is the id of ns3 from ns2. Signed-off-by: Xiao Liang <shaw.leon@gmail.com> Acked-by: Nicolas Dichtel <nicolas.dichtel@6wind.com> Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
This commit is contained in:
parent
18bbd74b34
commit
a597ab156b
142
ip/iplink.c
142
ip/iplink.c
@ -240,6 +240,38 @@ static int nl_get_ll_addr_len(const char *ifname)
|
||||
return len;
|
||||
}
|
||||
|
||||
static int get_ifindex_in_netns(struct rtnl_handle *rtnl, int netnsid,
|
||||
const char *ifname)
|
||||
{
|
||||
struct {
|
||||
struct nlmsghdr n;
|
||||
struct ifinfomsg ifm;
|
||||
char buf[1024];
|
||||
} req = {
|
||||
.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
|
||||
.n.nlmsg_flags = NLM_F_REQUEST,
|
||||
.n.nlmsg_type = RTM_GETLINK,
|
||||
};
|
||||
struct nlmsghdr *answer;
|
||||
int ifindex;
|
||||
|
||||
addattr32(&req.n, sizeof(req), IFLA_TARGET_NETNSID, netnsid);
|
||||
addattr_l(&req.n, sizeof(req),
|
||||
!check_ifname(ifname) ? IFLA_IFNAME : IFLA_ALT_IFNAME,
|
||||
ifname, strlen(ifname) + 1);
|
||||
|
||||
if (rtnl_talk(rtnl, &req.n, &answer) < 0)
|
||||
return 0;
|
||||
|
||||
if (answer->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) {
|
||||
free(answer);
|
||||
return 0;
|
||||
}
|
||||
ifindex = ((struct ifinfomsg *)NLMSG_DATA(answer))->ifi_index;
|
||||
free(answer);
|
||||
return ifindex;
|
||||
}
|
||||
|
||||
static void iplink_parse_vf_vlan_info(int vf, int *argcp, char ***argvp,
|
||||
struct ifla_vf_vlan_info *ivvip)
|
||||
{
|
||||
@ -536,7 +568,10 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type)
|
||||
int vf = -1;
|
||||
int numtxqueues = -1;
|
||||
int numrxqueues = -1;
|
||||
char *link_netns = NULL;
|
||||
int link_netnsid = -1;
|
||||
struct rtnl_handle netns_rtnl;
|
||||
struct rtnl_handle *rtnl = &rth;
|
||||
int index = 0;
|
||||
int group = -1;
|
||||
int addr_len = 0;
|
||||
@ -618,20 +653,25 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type)
|
||||
if (offload && name == dev)
|
||||
dev = NULL;
|
||||
} else if (strcmp(*argv, "netns") == 0) {
|
||||
int pid;
|
||||
|
||||
NEXT_ARG();
|
||||
if (netns != -1)
|
||||
duparg("netns", *argv);
|
||||
netns = netns_get_fd(*argv);
|
||||
if (netns >= 0) {
|
||||
open_fds_add(netns);
|
||||
addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_FD,
|
||||
&netns, 4);
|
||||
if (netns < 0 && get_integer(&pid, *argv, 0) == 0) {
|
||||
char path[PATH_MAX];
|
||||
|
||||
snprintf(path, sizeof(path), "/proc/%d/ns/net",
|
||||
pid);
|
||||
netns = open(path, O_RDONLY);
|
||||
}
|
||||
else if (get_integer(&netns, *argv, 0) == 0)
|
||||
addattr_l(&req->n, sizeof(*req),
|
||||
IFLA_NET_NS_PID, &netns, 4);
|
||||
else
|
||||
if (netns < 0)
|
||||
invarg("Invalid \"netns\" value\n", *argv);
|
||||
|
||||
open_fds_add(netns);
|
||||
addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_FD,
|
||||
&netns, 4);
|
||||
move_netns = true;
|
||||
} else if (strcmp(*argv, "multicast") == 0) {
|
||||
NEXT_ARG();
|
||||
@ -817,21 +857,12 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type)
|
||||
addattr_nest_end(&req->n, afs);
|
||||
} else if (matches(*argv, "link-netns") == 0) {
|
||||
NEXT_ARG();
|
||||
if (link_netnsid != -1)
|
||||
if (link_netnsid != -1 || link_netns)
|
||||
duparg("link-netns/link-netnsid", *argv);
|
||||
link_netnsid = netns_id_from_name(&rth, *argv);
|
||||
/* No nsid? Try to assign one. */
|
||||
if (link_netnsid < 0)
|
||||
set_netns_id_from_name(&rth, *argv, -1);
|
||||
link_netnsid = netns_id_from_name(&rth, *argv);
|
||||
if (link_netnsid < 0)
|
||||
invarg("Invalid \"link-netns\" value\n",
|
||||
*argv);
|
||||
addattr32(&req->n, sizeof(*req), IFLA_LINK_NETNSID,
|
||||
link_netnsid);
|
||||
link_netns = *argv;
|
||||
} else if (matches(*argv, "link-netnsid") == 0) {
|
||||
NEXT_ARG();
|
||||
if (link_netnsid != -1)
|
||||
if (link_netnsid != -1 || link_netns)
|
||||
duparg("link-netns/link-netnsid", *argv);
|
||||
if (get_integer(&link_netnsid, *argv, 0))
|
||||
invarg("Invalid \"link-netnsid\" value\n",
|
||||
@ -983,6 +1014,53 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type)
|
||||
}
|
||||
}
|
||||
|
||||
if (netns != -1 && (link_netnsid != -1 || link_netns)) {
|
||||
int orig_netns;
|
||||
|
||||
/*
|
||||
* When both link-netns and netns are set, open an RTNL in
|
||||
* target netns, to
|
||||
* 1) get link-netns id from the view of target netns, and
|
||||
* 2) get link ifindex from link-netns.
|
||||
*/
|
||||
orig_netns = open("/proc/self/ns/net", O_RDONLY);
|
||||
if (orig_netns == -1) {
|
||||
fprintf(stderr, "Cannot open namespace: %s\n",
|
||||
strerror(errno));
|
||||
exit(-1);
|
||||
}
|
||||
if (setns(netns, CLONE_NEWNET) < 0) {
|
||||
fprintf(stderr, "Cannot set namespace: %s\n",
|
||||
strerror(errno));
|
||||
exit(-1);
|
||||
}
|
||||
if (rtnl_open(&netns_rtnl, 0) < 0) {
|
||||
fprintf(stderr, "Cannot open rtnetlink\n");
|
||||
exit(-1);
|
||||
}
|
||||
if (setns(orig_netns, CLONE_NEWNET) < 0) {
|
||||
fprintf(stderr, "Cannot set namespace: %s\n",
|
||||
strerror(errno));
|
||||
exit(-1);
|
||||
}
|
||||
close(orig_netns);
|
||||
rtnl = &netns_rtnl;
|
||||
}
|
||||
|
||||
if (link_netns) {
|
||||
link_netnsid = netns_id_from_name(rtnl, link_netns);
|
||||
/* No nsid? Try to assign one. */
|
||||
if (link_netnsid < 0) {
|
||||
set_netns_id_from_name(rtnl, link_netns, -1);
|
||||
link_netnsid = netns_id_from_name(rtnl, link_netns);
|
||||
}
|
||||
if (link_netnsid < 0)
|
||||
invarg("Invalid \"link-netns\" value\n",
|
||||
*argv);
|
||||
addattr32(&req->n, sizeof(*req), IFLA_LINK_NETNSID,
|
||||
link_netnsid);
|
||||
}
|
||||
|
||||
if (!(req->n.nlmsg_flags & NLM_F_CREATE)) {
|
||||
if (!dev) {
|
||||
fprintf(stderr,
|
||||
@ -991,8 +1069,10 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type)
|
||||
}
|
||||
|
||||
req->i.ifi_index = ll_name_to_index(dev);
|
||||
if (!req->i.ifi_index)
|
||||
return nodev(dev);
|
||||
if (!req->i.ifi_index) {
|
||||
ret = nodev(dev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Not renaming to the same name */
|
||||
if (name == dev)
|
||||
@ -1010,9 +1090,17 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type)
|
||||
if (link) {
|
||||
int ifindex;
|
||||
|
||||
ifindex = ll_name_to_index(link);
|
||||
if (!ifindex)
|
||||
return nodev(link);
|
||||
if (link_netnsid == -1)
|
||||
ifindex = ll_name_to_index(link);
|
||||
else
|
||||
ifindex = get_ifindex_in_netns(rtnl,
|
||||
link_netnsid,
|
||||
link);
|
||||
|
||||
if (!ifindex) {
|
||||
ret = nodev(link);
|
||||
goto out;
|
||||
}
|
||||
addattr32(&req->n, sizeof(*req), IFLA_LINK, ifindex);
|
||||
}
|
||||
|
||||
@ -1024,6 +1112,10 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req, char **type)
|
||||
IFLA_IFNAME, name, strlen(name) + 1);
|
||||
}
|
||||
|
||||
out:
|
||||
if (rtnl == &netns_rtnl)
|
||||
rtnl_close(rtnl);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user