[CRIU] [PATCH 3/5] net: add support for macvlan link types
Tycho Andersen
tycho.andersen at canonical.com
Tue Jun 14 09:45:30 PDT 2016
While this is in principle similar to how veths are handled, we have to do
things in two different ways depending on whether or not there is a user
namespace involved, because there is no way to ask the kernel to attach a
macvlan NIC to a device in a net ns that we don't have CAP_NET_ADMIN in.
So we do it in two ways:
a. If we are in a user namespace, we create the device in usernsd and use
IFLA_NET_NS_PID to set the netns which it should be created in (saving
us a "move into this netns" step).
b. If we aren't in a user namespace, we could still be in a net namespace,
so we use IFLA_LINK_NETNSID to set namespace that the i/o device will be
in. This is sort of a hack, since we have to do it via NSID, which we
know is 0 because we don't allow namespace nesting.
Signed-off-by: Tycho Andersen <tycho.andersen at canonical.com>
---
criu/net.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++
images/Makefile | 1 +
images/macvlan.proto | 4 ++
images/netdev.proto | 6 +++
4 files changed, 143 insertions(+)
create mode 100644 images/macvlan.proto
diff --git a/criu/net.c b/criu/net.c
index 9954270..793b625 100644
--- a/criu/net.c
+++ b/criu/net.c
@@ -476,6 +476,61 @@ static int dump_bridge(NetDeviceEntry *nde, struct cr_imgset *imgset, struct nla
return write_netdev_img(nde, imgset, data);
}
+static int dump_macvlan(NetDeviceEntry *nde, struct cr_imgset *imgset, struct nlattr **tb)
+{
+ MacvlanLinkEntry macvlan = MACVLAN_LINK_ENTRY__INIT;
+ int ret;
+ struct nlattr *info[IFLA_INFO_MAX], *data[IFLA_MACVLAN_MAX];
+
+ if (!tb || !tb[IFLA_LINKINFO]) {
+ pr_err("no for macvlan\n");
+ return -1;
+ }
+
+ if (tb[IFLA_LINK]) {
+ nde->has_link = true;
+ nde->link = *(int *)RTA_DATA(tb[IFLA_LINK]);
+ }
+
+ if (tb[IFLA_LINK_NETNSID]) {
+ nde->has_netns_id = true;
+ nde->netns_id = *(int *)RTA_DATA(tb[IFLA_LINK_NETNSID]);
+ }
+
+ ret = nla_parse_nested(info, IFLA_INFO_MAX, tb[IFLA_LINKINFO], NULL);
+ if (ret < 0) {
+ pr_err("failed to parse nested linkinfo\n");
+ return -1;
+ }
+
+ if (!info[IFLA_INFO_DATA]) {
+ pr_err("no link info data for macvlan\n");
+ return -1;
+ }
+
+ ret = nla_parse_nested(data, IFLA_MACVLAN_MAX, info[IFLA_INFO_DATA], NULL);
+ if (ret < 0) {
+ pr_err("failed ot parse macvlan data\n");
+ return -1;
+ }
+
+ if (!data[IFLA_MACVLAN_MODE]) {
+ pr_err("macvlan mode required for %s\n", nde->name);
+ return -1;
+ }
+
+ macvlan.mode = *((u32 *)RTA_DATA(data[IFLA_MACVLAN_MODE]));
+
+ if (data[IFLA_MACVLAN_FLAGS])
+ macvlan.flags = *((u16 *) RTA_DATA(data[IFLA_MACVLAN_FLAGS]));
+
+ nde->macvlan = &macvlan;
+ ret = write_netdev_img(nde, imgset, data);
+
+ nde->macvlan = NULL;
+ return ret;
+}
+
static int dump_one_ethernet(struct ifinfomsg *ifi, char *kind,
struct nlattr **tb, struct cr_imgset *fds)
{
@@ -508,6 +563,8 @@ static int dump_one_ethernet(struct ifinfomsg *ifi, char *kind,
pr_warn("GRE tap device %s not supported natively\n", name);
}
+ if (!strcmp(kind, "macvlan"))
+ return dump_one_netdev(ND_TYPE__MACVLAN, ifi, tb, fds, dump_macvlan);
return dump_unknown_device(ifi, kind, tb, fds);
}
@@ -828,6 +885,22 @@ static int populate_newlink_req(struct newlink_req *req, int msg_type, NetDevice
req->i.ifi_index = nde->ifindex;
req->i.ifi_flags = nde->flags;
+ /* Note that this id isn't preserved anywhere, but since we don't
+ * support nested namespaces, right now there is only one peer
+ * namespace, the parent NS with an id of 0, so this works. In the
+ * future, we'll need to be more careful about munging this ID to be
+ * correct (or restoring namespaces in such a way that they get the
+ * same ID).
+ */
+ if (nde->has_netns_id)
+ addattr_l(&req->h, sizeof(*req), IFLA_LINK_NETNSID, &nde->netns_id, sizeof(nde->netns_id));
+
+ /* Like netns_id, this is not preserved across hosts (indeed, a link
+ * with this ifindex may not even exist). We add support for rewriting
+ * it in a later patch.
+ */
+ if (nde->has_link)
+ addattr_l(&req->h, sizeof(*req), IFLA_LINK, &nde->link, sizeof(nde->link));
addattr_l(&req->h, sizeof(*req), IFLA_IFNAME, nde->name, strlen(nde->name));
addattr_l(&req->h, sizeof(*req), IFLA_MTU, &nde->mtu, sizeof(nde->mtu));
@@ -949,6 +1022,49 @@ static int bridge_link_info(NetDeviceEntry *nde, struct newlink_req *req)
return 0;
}
+static int macvlan_link_info(NetDeviceEntry *nde, struct newlink_req *req)
+{
+ struct rtattr *macvlan_data;
+ MacvlanLinkEntry *macvlan = nde->macvlan;
+
+ if (!macvlan) {
+ pr_err("Missing macvlan link entry %d\n", nde->ifindex);
+ return -1;
+ }
+
+ addattr_l(&req->h, sizeof(*req), IFLA_INFO_KIND, "macvlan", 7);
+
+ macvlan_data = NLMSG_TAIL(&req->h);
+ addattr_l(&req->h, sizeof(*req), IFLA_INFO_DATA, NULL, 0);
+
+ addattr_l(&req->h, sizeof(*req), IFLA_MACVLAN_MODE, &macvlan->mode, sizeof(macvlan->mode));
+
+ if (macvlan->has_flags)
+ addattr_l(&req->h, sizeof(*req), IFLA_MACVLAN_FLAGS, &macvlan->flags, sizeof(macvlan->flags));
+
+ macvlan_data->rta_len = (void *)NLMSG_TAIL(&req->h) - (void *)macvlan_data;
+
+ return 0;
+}
+
+static int userns_restore_one_link(void *arg, int fd, pid_t pid)
+{
+ int nlsk, ret;
+ struct newlink_req *req = arg;
+
+ nlsk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (nlsk < 0) {
+ pr_perror("Can't create nlk socket");
+ return -1;
+ }
+
+ addattr_l(&req->h, sizeof(*req), IFLA_NET_NS_PID, &pid, sizeof(pid));
+
+ ret = do_rtnl_req(nlsk, req, req->h.nlmsg_len, restore_link_cb, NULL, NULL);
+ close(nlsk);
+ return ret;
+}
+
static int restore_link(NetDeviceEntry *nde, int nlsk)
{
pr_info("Restoring link %s type %d\n", nde->name, nde->type);
@@ -965,7 +1081,23 @@ static int restore_link(NetDeviceEntry *nde, int nlsk)
return restore_one_tun(nde, nlsk);
case ND_TYPE__BRIDGE:
return restore_one_link(nde, nlsk, bridge_link_info);
+ case ND_TYPE__MACVLAN: {
+ if (root_ns_mask & CLONE_NEWNET) {
+ struct newlink_req req;
+ if (populate_newlink_req(&req, RTM_NEWLINK, nde, macvlan_link_info) < 0)
+ return -1;
+
+ if (userns_call(userns_restore_one_link, 0, &req, sizeof(req), -1) < 0) {
+ pr_err("couldn't restore macvlan interface %s via usernsd\n", nde->name);
+ return -1;
+ }
+
+ return 0;
+ }
+
+ return restore_one_link(nde, nlsk, macvlan_link_info);
+ }
default:
pr_err("Unsupported link type %d\n", nde->type);
break;
diff --git a/images/Makefile b/images/Makefile
index cf50794..eb18526 100644
--- a/images/Makefile
+++ b/images/Makefile
@@ -60,6 +60,7 @@ proto-obj-y += binfmt-misc.o
proto-obj-y += time.o
proto-obj-y += sysctl.o
proto-obj-y += autofs.o
+proto-obj-y += macvlan.o
CFLAGS += -iquote $(obj)/
diff --git a/images/macvlan.proto b/images/macvlan.proto
new file mode 100644
index 0000000..c9c9045
--- /dev/null
+++ b/images/macvlan.proto
@@ -0,0 +1,4 @@
+message macvlan_link_entry {
+ required uint32 mode = 1;
+ optional uint32 flags = 2;
+}
diff --git a/images/netdev.proto b/images/netdev.proto
index 37cafb3..746db16 100644
--- a/images/netdev.proto
+++ b/images/netdev.proto
@@ -1,3 +1,4 @@
+import "macvlan.proto";
import "opts.proto";
import "tun.proto";
import "sysctl.proto";
@@ -18,6 +19,7 @@ enum nd_type {
*/
VENET = 5;
BRIDGE = 6;
+ MACVLAN = 7;
}
message net_device_entry {
@@ -36,6 +38,10 @@ message net_device_entry {
repeated sysctl_entry conf4 = 9;
repeated sysctl_entry conf6 = 10;
+
+ optional int32 link = 11;
+ optional int32 netns_id = 12;
+ optional macvlan_link_entry macvlan = 13;
}
message netns_entry {
--
2.7.4
More information about the CRIU
mailing list