2012-08-02 08:06:29 +04:00
|
|
|
#include <unistd.h>
|
2012-08-02 08:17:27 +04:00
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <linux/netlink.h>
|
|
|
|
#include <linux/rtnetlink.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <net/if_arp.h>
|
|
|
|
#include <sys/wait.h>
|
2012-08-10 19:14:36 +04:00
|
|
|
#include <sched.h>
|
2013-08-17 01:30:48 +04:00
|
|
|
#include <sys/mount.h>
|
|
|
|
|
2012-08-02 08:06:29 +04:00
|
|
|
#include "syscall-types.h"
|
|
|
|
#include "namespaces.h"
|
|
|
|
#include "net.h"
|
2012-08-02 08:17:27 +04:00
|
|
|
#include "libnetlink.h"
|
2012-09-02 01:07:32 +04:00
|
|
|
#include "crtools.h"
|
2012-09-17 20:05:55 +04:00
|
|
|
#include "sk-inet.h"
|
2013-08-23 19:02:55 +04:00
|
|
|
#include "tun.h"
|
2013-08-17 01:30:48 +04:00
|
|
|
#include "util-pie.h"
|
2012-08-02 08:17:27 +04:00
|
|
|
|
|
|
|
#include "protobuf.h"
|
|
|
|
#include "protobuf/netdev.pb-c.h"
|
|
|
|
|
2012-08-10 19:14:36 +04:00
|
|
|
static int ns_fd = -1;
|
2013-08-17 01:30:48 +04:00
|
|
|
static int ns_sysfs_fd = -1;
|
2012-08-10 19:14:36 +04:00
|
|
|
|
2013-08-17 01:34:17 +04:00
|
|
|
int read_ns_sys_file(char *path, char *buf, int len)
|
|
|
|
{
|
|
|
|
int fd, rlen;
|
|
|
|
|
|
|
|
BUG_ON(ns_sysfs_fd == -1);
|
|
|
|
|
|
|
|
fd = openat(ns_sysfs_fd, path, O_RDONLY, 0);
|
|
|
|
if (fd < 0) {
|
|
|
|
pr_perror("Can't open ns' %s", path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
rlen = read(fd, buf, len);
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
if (rlen >= 0)
|
|
|
|
buf[rlen] = '\0';
|
|
|
|
|
|
|
|
return rlen;
|
|
|
|
}
|
|
|
|
|
2013-08-17 01:10:15 +04:00
|
|
|
int write_netdev_img(NetDeviceEntry *nde, struct cr_fdset *fds)
|
|
|
|
{
|
|
|
|
return pb_write_one(fdset_fd(fds, CR_FD_NETDEV), nde, PB_NETDEV);
|
|
|
|
}
|
|
|
|
|
2012-08-10 13:09:03 +04:00
|
|
|
static int dump_one_netdev(int type, struct ifinfomsg *ifi,
|
2013-08-17 01:10:15 +04:00
|
|
|
struct rtattr **tb, struct cr_fdset *fds,
|
|
|
|
int (*dump)(NetDeviceEntry *, struct cr_fdset *))
|
2012-08-02 08:17:27 +04:00
|
|
|
{
|
|
|
|
NetDeviceEntry netdev = NET_DEVICE_ENTRY__INIT;
|
|
|
|
|
|
|
|
if (!tb[IFLA_IFNAME]) {
|
|
|
|
pr_err("No name for link %d\n", ifi->ifi_index);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
netdev.type = type;
|
|
|
|
netdev.ifindex = ifi->ifi_index;
|
|
|
|
netdev.mtu = *(int *)RTA_DATA(tb[IFLA_MTU]);
|
|
|
|
netdev.flags = ifi->ifi_flags;
|
|
|
|
netdev.name = RTA_DATA(tb[IFLA_IFNAME]);
|
|
|
|
|
2013-08-24 01:07:33 +04:00
|
|
|
if (tb[IFLA_ADDRESS] && (type != ND_TYPE__LOOPBACK)) {
|
|
|
|
netdev.has_address = true;
|
|
|
|
netdev.address.data = RTA_DATA(tb[IFLA_ADDRESS]);
|
|
|
|
netdev.address.len = RTA_PAYLOAD(tb[IFLA_ADDRESS]);
|
|
|
|
pr_info("Found ll addr (%02x:../%d) for %s\n",
|
|
|
|
(int)netdev.address.data[0],
|
|
|
|
(int)netdev.address.len, netdev.name);
|
|
|
|
}
|
|
|
|
|
2013-08-17 01:10:15 +04:00
|
|
|
if (!dump)
|
|
|
|
dump = write_netdev_img;
|
|
|
|
|
|
|
|
return dump(&netdev, fds);
|
2012-08-02 08:17:27 +04:00
|
|
|
}
|
|
|
|
|
2013-06-10 16:17:45 +04:00
|
|
|
static char *link_kind(struct ifinfomsg *ifi, struct rtattr **tb)
|
2012-08-10 17:24:11 +04:00
|
|
|
{
|
|
|
|
struct rtattr *linkinfo[IFLA_INFO_MAX + 1];
|
|
|
|
|
|
|
|
if (!tb[IFLA_LINKINFO]) {
|
|
|
|
pr_err("No linkinfo for eth link %d\n", ifi->ifi_index);
|
2013-06-10 16:17:45 +04:00
|
|
|
return NULL;
|
2012-08-10 17:24:11 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]);
|
|
|
|
if (!linkinfo[IFLA_INFO_KIND]) {
|
|
|
|
pr_err("No kind for eth link %d\n", ifi->ifi_index);
|
2013-06-10 16:17:45 +04:00
|
|
|
return NULL;
|
2012-08-10 17:24:11 +04:00
|
|
|
}
|
|
|
|
|
2013-06-10 16:17:45 +04:00
|
|
|
return RTA_DATA(linkinfo[IFLA_INFO_KIND]);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int dump_one_ethernet(struct ifinfomsg *ifi,
|
|
|
|
struct rtattr **tb, struct cr_fdset *fds)
|
|
|
|
{
|
|
|
|
char *kind;
|
|
|
|
|
|
|
|
kind = link_kind(ifi, tb);
|
|
|
|
if (!kind)
|
|
|
|
goto unk;
|
|
|
|
|
2012-08-10 17:24:11 +04:00
|
|
|
if (!strcmp(kind, "veth"))
|
|
|
|
/*
|
|
|
|
* This is not correct. The peer of the veth device may
|
|
|
|
* be either outside or inside the netns we're working
|
|
|
|
* on, but there's currently no way of finding this out.
|
|
|
|
*
|
|
|
|
* Sigh... we have to assume, that the veth device is a
|
|
|
|
* connection to the outer world and just dump this end :(
|
|
|
|
*/
|
2013-08-17 01:10:15 +04:00
|
|
|
return dump_one_netdev(ND_TYPE__VETH, ifi, tb, fds, NULL);
|
2013-08-23 19:02:55 +04:00
|
|
|
if (!strcmp(kind, "tun"))
|
|
|
|
return dump_one_netdev(ND_TYPE__TUN, ifi, tb, fds, dump_tun_link);
|
2013-06-10 16:17:45 +04:00
|
|
|
unk:
|
2012-08-10 17:24:11 +04:00
|
|
|
pr_err("Unknown eth kind %s link %d\n", kind, ifi->ifi_index);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-08-23 19:02:55 +04:00
|
|
|
static int dump_one_gendev(struct ifinfomsg *ifi,
|
|
|
|
struct rtattr **tb, struct cr_fdset *fds)
|
|
|
|
{
|
|
|
|
char *kind;
|
|
|
|
|
|
|
|
kind = link_kind(ifi, tb);
|
|
|
|
if (!kind)
|
|
|
|
goto unk;
|
|
|
|
|
|
|
|
if (!strcmp(kind, "tun"))
|
|
|
|
return dump_one_netdev(ND_TYPE__TUN, ifi, tb, fds, dump_tun_link);
|
|
|
|
|
|
|
|
unk:
|
|
|
|
pr_err("Unknown ARPHRD_NONE kind %s link %d\n", kind, ifi->ifi_index);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-08-02 08:17:27 +04:00
|
|
|
static int dump_one_link(struct nlmsghdr *hdr, void *arg)
|
|
|
|
{
|
|
|
|
struct cr_fdset *fds = arg;
|
|
|
|
struct ifinfomsg *ifi;
|
2012-08-10 13:09:03 +04:00
|
|
|
int ret = 0, len = hdr->nlmsg_len - NLMSG_LENGTH(sizeof(*ifi));
|
2012-08-11 22:03:11 +04:00
|
|
|
struct rtattr *tb[IFLA_MAX + 1];
|
2012-08-02 08:17:27 +04:00
|
|
|
|
|
|
|
ifi = NLMSG_DATA(hdr);
|
2012-08-10 13:09:03 +04:00
|
|
|
|
|
|
|
if (len < 0) {
|
|
|
|
pr_err("No iflas for link %d\n", ifi->ifi_index);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
|
|
|
|
|
2012-08-02 08:17:27 +04:00
|
|
|
pr_info("\tLD: Got link %d, type %d\n", ifi->ifi_index, ifi->ifi_type);
|
|
|
|
|
|
|
|
switch (ifi->ifi_type) {
|
|
|
|
case ARPHRD_LOOPBACK:
|
2013-08-17 01:10:15 +04:00
|
|
|
ret = dump_one_netdev(ND_TYPE__LOOPBACK, ifi, tb, fds, NULL);
|
2012-08-02 08:17:27 +04:00
|
|
|
break;
|
2012-08-10 17:24:11 +04:00
|
|
|
case ARPHRD_ETHER:
|
|
|
|
ret = dump_one_ethernet(ifi, tb, fds);
|
|
|
|
break;
|
2013-08-23 19:02:55 +04:00
|
|
|
case ARPHRD_NONE:
|
|
|
|
ret = dump_one_gendev(ifi, tb, fds);
|
|
|
|
break;
|
2012-08-02 08:17:27 +04:00
|
|
|
default:
|
2013-06-10 16:17:45 +04:00
|
|
|
pr_err("Unsupported link type %d, kind %s\n",
|
|
|
|
ifi->ifi_type, link_kind(ifi, tb));
|
2012-08-02 08:17:27 +04:00
|
|
|
ret = 0; /* just skip for now */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-09-10 12:45:42 +04:00
|
|
|
static int dump_links(struct cr_fdset *fds)
|
2012-08-02 08:17:27 +04:00
|
|
|
{
|
|
|
|
int sk, ret;
|
|
|
|
struct {
|
|
|
|
struct nlmsghdr nlh;
|
|
|
|
struct rtgenmsg g;
|
|
|
|
} req;
|
|
|
|
|
2013-09-10 12:45:42 +04:00
|
|
|
pr_info("Dumping netns links\n");
|
|
|
|
|
2012-08-02 08:17:27 +04:00
|
|
|
ret = sk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
|
|
|
if (sk < 0) {
|
|
|
|
pr_perror("Can't open rtnl sock for net dump");
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&req, 0, sizeof(req));
|
|
|
|
req.nlh.nlmsg_len = sizeof(req);
|
|
|
|
req.nlh.nlmsg_type = RTM_GETLINK;
|
|
|
|
req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
|
|
|
|
req.nlh.nlmsg_pid = 0;
|
|
|
|
req.nlh.nlmsg_seq = CR_NLMSG_SEQ;
|
|
|
|
req.g.rtgen_family = AF_PACKET;
|
|
|
|
|
2013-09-10 12:45:42 +04:00
|
|
|
ret = do_rtnl_req(sk, &req, sizeof(req), dump_one_link, fds);
|
2012-08-02 08:17:27 +04:00
|
|
|
close(sk);
|
|
|
|
out:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int restore_link_cb(struct nlmsghdr *hdr, void *arg)
|
|
|
|
{
|
2013-04-12 13:00:05 -07:00
|
|
|
pr_info("Got response on SETLINK =)\n");
|
2012-08-02 08:17:27 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-10 17:27:36 +04:00
|
|
|
struct newlink_req {
|
|
|
|
struct nlmsghdr h;
|
|
|
|
struct ifinfomsg i;
|
|
|
|
char buf[1024];
|
|
|
|
};
|
|
|
|
|
2013-08-23 18:46:48 +04:00
|
|
|
static int do_rtm_link_req(int msg_type, NetDeviceEntry *nde, int nlsk,
|
2012-08-10 17:32:56 +04:00
|
|
|
int (*link_info)(NetDeviceEntry *, struct newlink_req *))
|
2012-08-02 08:17:27 +04:00
|
|
|
{
|
2012-08-10 17:27:36 +04:00
|
|
|
struct newlink_req req;
|
2012-08-02 08:17:27 +04:00
|
|
|
|
|
|
|
memset(&req, 0, sizeof(req));
|
|
|
|
|
|
|
|
req.h.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
|
2012-08-10 17:25:42 +04:00
|
|
|
req.h.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK|NLM_F_CREATE;
|
2013-08-23 18:46:48 +04:00
|
|
|
req.h.nlmsg_type = msg_type;
|
2012-08-02 08:17:27 +04:00
|
|
|
req.h.nlmsg_seq = CR_NLMSG_SEQ;
|
|
|
|
req.i.ifi_family = AF_PACKET;
|
|
|
|
req.i.ifi_index = nde->ifindex;
|
|
|
|
req.i.ifi_flags = nde->flags;
|
|
|
|
|
2012-08-10 17:31:03 +04:00
|
|
|
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));
|
2012-08-02 08:17:27 +04:00
|
|
|
|
2013-08-24 01:07:33 +04:00
|
|
|
if (nde->has_address) {
|
|
|
|
pr_debug("Restore ll addr (%02x:../%d) for device\n",
|
|
|
|
(int)nde->address.data[0], (int)nde->address.len);
|
|
|
|
addattr_l(&req.h, sizeof(req), IFLA_ADDRESS,
|
|
|
|
nde->address.data, nde->address.len);
|
|
|
|
}
|
|
|
|
|
2012-08-10 17:32:56 +04:00
|
|
|
if (link_info) {
|
|
|
|
struct rtattr *linkinfo;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
linkinfo = NLMSG_TAIL(&req.h);
|
|
|
|
addattr_l(&req.h, sizeof(req), IFLA_LINKINFO, NULL, 0);
|
|
|
|
|
|
|
|
ret = link_info(nde, &req);
|
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
linkinfo->rta_len = (void *)NLMSG_TAIL(&req.h) - (void *)linkinfo;
|
|
|
|
}
|
|
|
|
|
2012-08-10 17:27:36 +04:00
|
|
|
return do_rtnl_req(nlsk, &req, req.h.nlmsg_len, restore_link_cb, NULL);
|
2012-08-02 08:17:27 +04:00
|
|
|
}
|
|
|
|
|
2013-08-23 18:46:48 +04:00
|
|
|
int restore_link_parms(NetDeviceEntry *nde, int nlsk)
|
|
|
|
{
|
|
|
|
return do_rtm_link_req(RTM_SETLINK, nde, nlsk, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int restore_one_link(NetDeviceEntry *nde, int nlsk,
|
|
|
|
int (*link_info)(NetDeviceEntry *, struct newlink_req *))
|
|
|
|
{
|
2013-09-18 20:43:59 +04:00
|
|
|
pr_info("Restoring netdev %s idx %d\n", nde->name, nde->ifindex);
|
2013-08-23 18:46:48 +04:00
|
|
|
return do_rtm_link_req(RTM_NEWLINK, nde, nlsk, link_info);
|
|
|
|
}
|
|
|
|
|
2012-08-10 17:36:00 +04:00
|
|
|
#ifndef VETH_INFO_MAX
|
|
|
|
enum {
|
|
|
|
VETH_INFO_UNSPEC,
|
|
|
|
VETH_INFO_PEER,
|
|
|
|
|
|
|
|
__VETH_INFO_MAX
|
|
|
|
#define VETH_INFO_MAX (__VETH_INFO_MAX - 1)
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
2012-08-10 19:14:36 +04:00
|
|
|
#if IFLA_MAX <= 28
|
|
|
|
#define IFLA_NET_NS_FD 28
|
|
|
|
#endif
|
|
|
|
|
2012-08-10 17:36:00 +04:00
|
|
|
static int veth_link_info(NetDeviceEntry *nde, struct newlink_req *req)
|
|
|
|
{
|
|
|
|
struct rtattr *veth_data, *peer_data;
|
|
|
|
struct ifinfomsg ifm;
|
2012-09-02 01:07:32 +04:00
|
|
|
struct veth_pair *n;
|
2012-08-10 17:36:00 +04:00
|
|
|
|
2012-08-10 19:14:36 +04:00
|
|
|
BUG_ON(ns_fd < 0);
|
|
|
|
|
2012-08-10 17:36:00 +04:00
|
|
|
addattr_l(&req->h, sizeof(*req), IFLA_INFO_KIND, "veth", 4);
|
|
|
|
|
|
|
|
veth_data = NLMSG_TAIL(&req->h);
|
|
|
|
addattr_l(&req->h, sizeof(*req), IFLA_INFO_DATA, NULL, 0);
|
|
|
|
peer_data = NLMSG_TAIL(&req->h);
|
|
|
|
memset(&ifm, 0, sizeof(ifm));
|
|
|
|
addattr_l(&req->h, sizeof(*req), VETH_INFO_PEER, &ifm, sizeof(ifm));
|
2012-09-02 01:07:32 +04:00
|
|
|
list_for_each_entry(n, &opts.veth_pairs, node) {
|
|
|
|
if (!strcmp(nde->name, n->inside))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (&n->node != &opts.veth_pairs)
|
|
|
|
addattr_l(&req->h, sizeof(*req), IFLA_IFNAME, n->outside, strlen(n->outside));
|
2012-08-10 19:14:36 +04:00
|
|
|
addattr_l(&req->h, sizeof(*req), IFLA_NET_NS_FD, &ns_fd, sizeof(ns_fd));
|
2012-08-10 17:36:00 +04:00
|
|
|
peer_data->rta_len = (void *)NLMSG_TAIL(&req->h) - (void *)peer_data;
|
|
|
|
veth_data->rta_len = (void *)NLMSG_TAIL(&req->h) - (void *)veth_data;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2012-08-02 08:17:27 +04:00
|
|
|
static int restore_link(NetDeviceEntry *nde, int nlsk)
|
|
|
|
{
|
2013-09-18 20:43:59 +04:00
|
|
|
pr_info("Restoring link %s type %d\n", nde->name, nde->type);
|
2012-08-02 08:17:27 +04:00
|
|
|
|
|
|
|
switch (nde->type) {
|
|
|
|
case ND_TYPE__LOOPBACK:
|
2012-08-10 17:32:56 +04:00
|
|
|
return restore_one_link(nde, nlsk, NULL);
|
2013-10-10 14:31:33 +04:00
|
|
|
case ND_TYPE__EXTLINK:
|
|
|
|
/* see comment in protobuf/netdev.proto */
|
|
|
|
return restore_link_parms(nde, nlsk);
|
2012-08-10 17:24:11 +04:00
|
|
|
case ND_TYPE__VETH:
|
2012-08-10 17:36:00 +04:00
|
|
|
return restore_one_link(nde, nlsk, veth_link_info);
|
2013-08-23 19:10:15 +04:00
|
|
|
case ND_TYPE__TUN:
|
|
|
|
return restore_one_tun(nde, nlsk);
|
2013-02-11 17:14:20 +04:00
|
|
|
default:
|
|
|
|
pr_err("Unsupported link type %d\n", nde->type);
|
|
|
|
break;
|
2012-08-02 08:17:27 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int restore_links(int pid)
|
|
|
|
{
|
|
|
|
int fd, nlsk, ret;
|
|
|
|
NetDeviceEntry *nde;
|
|
|
|
|
2013-04-09 11:13:51 +04:00
|
|
|
fd = open_image(CR_FD_NETDEV, O_RSTR, pid);
|
2012-08-02 08:17:27 +04:00
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
nlsk = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
|
|
|
if (nlsk < 0) {
|
|
|
|
pr_perror("Can't create nlk socket");
|
2012-10-24 16:51:50 +04:00
|
|
|
close_safe(&fd);
|
2012-08-02 08:17:27 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (1) {
|
2012-08-07 02:42:58 +04:00
|
|
|
ret = pb_read_one_eof(fd, &nde, PB_NETDEV);
|
2012-08-02 08:17:27 +04:00
|
|
|
if (ret <= 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
ret = restore_link(nde, nlsk);
|
|
|
|
net_device_entry__free_unpacked(nde, NULL);
|
|
|
|
if (ret)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
close(nlsk);
|
|
|
|
close(fd);
|
|
|
|
return ret;
|
|
|
|
}
|
2012-08-02 08:06:29 +04:00
|
|
|
|
2012-08-02 08:26:43 +04:00
|
|
|
static int run_ip_tool(char *arg1, char *arg2, int fdin, int fdout)
|
2012-08-02 08:21:19 +04:00
|
|
|
{
|
2012-09-28 14:09:58 +04:00
|
|
|
char *ip_tool_cmd;
|
|
|
|
int ret;
|
2012-08-02 08:21:19 +04:00
|
|
|
|
|
|
|
pr_debug("\tRunning ip %s %s\n", arg1, arg2);
|
|
|
|
|
2012-09-28 14:09:58 +04:00
|
|
|
ip_tool_cmd = getenv("CR_IP_TOOL");
|
|
|
|
if (!ip_tool_cmd)
|
|
|
|
ip_tool_cmd = "ip";
|
2012-08-02 08:21:19 +04:00
|
|
|
|
2012-09-28 14:09:58 +04:00
|
|
|
ret = cr_system(fdin, fdout, -1, ip_tool_cmd,
|
|
|
|
(char *[]) { "ip", arg1, arg2, NULL });
|
|
|
|
if (ret) {
|
|
|
|
pr_err("IP tool failed on %s %s\n", arg1, arg2);
|
2012-08-02 08:21:19 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-10-04 02:51:33 +04:00
|
|
|
static int run_iptables_tool(char *def_cmd, int fdin, int fdout)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
char *cmd;
|
|
|
|
|
|
|
|
cmd = getenv("CR_IPTABLES");
|
|
|
|
if (!cmd)
|
|
|
|
cmd = def_cmd;
|
|
|
|
pr_debug("\tRunning %s for %s\n", cmd, def_cmd);
|
|
|
|
ret = cr_system(fdin, fdout, -1, "sh", (char *[]) { "sh", "-c", cmd, NULL });
|
|
|
|
if (ret)
|
|
|
|
pr_err("%s failed\n", def_cmd);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2012-08-02 08:26:43 +04:00
|
|
|
static inline int dump_ifaddr(struct cr_fdset *fds)
|
|
|
|
{
|
|
|
|
return run_ip_tool("addr", "save", -1, fdset_fd(fds, CR_FD_IFADDR));
|
|
|
|
}
|
|
|
|
|
2012-08-02 08:31:46 +04:00
|
|
|
static inline int dump_route(struct cr_fdset *fds)
|
|
|
|
{
|
|
|
|
return run_ip_tool("route", "save", -1, fdset_fd(fds, CR_FD_ROUTE));
|
|
|
|
}
|
|
|
|
|
2013-10-04 02:51:33 +04:00
|
|
|
static inline int dump_iptables(struct cr_fdset *fds)
|
|
|
|
{
|
|
|
|
return run_iptables_tool("iptables-save", -1, fdset_fd(fds, CR_FD_IPTABLES));
|
|
|
|
}
|
|
|
|
|
2012-08-02 08:26:43 +04:00
|
|
|
static int restore_ip_dump(int type, int pid, char *cmd)
|
|
|
|
{
|
|
|
|
int fd, ret;
|
|
|
|
|
2013-04-09 11:13:51 +04:00
|
|
|
ret = fd = open_image(type, O_RSTR, pid);
|
2013-01-15 18:53:00 +04:00
|
|
|
if (fd >= 0) {
|
2012-08-02 08:26:43 +04:00
|
|
|
ret = run_ip_tool(cmd, "restore", fd, -1);
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int restore_ifaddr(int pid)
|
|
|
|
{
|
|
|
|
return restore_ip_dump(CR_FD_IFADDR, pid, "addr");
|
|
|
|
}
|
|
|
|
|
2012-08-02 08:31:46 +04:00
|
|
|
static inline int restore_route(int pid)
|
|
|
|
{
|
|
|
|
return restore_ip_dump(CR_FD_ROUTE, pid, "route");
|
|
|
|
}
|
|
|
|
|
2013-10-04 02:51:33 +04:00
|
|
|
static inline int restore_iptables(int pid)
|
|
|
|
{
|
|
|
|
int ret, fd;
|
|
|
|
|
|
|
|
ret = fd = open_image(CR_FD_IPTABLES, O_RSTR, pid);
|
|
|
|
if (fd >= 0) {
|
|
|
|
ret = run_iptables_tool("iptables-restore", fd, -1);
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-08-17 01:30:48 +04:00
|
|
|
static int mount_ns_sysfs(void)
|
|
|
|
{
|
|
|
|
char sys_mount[] = "crtools-sys.XXXXXX";
|
|
|
|
|
|
|
|
BUG_ON(ns_sysfs_fd != -1);
|
|
|
|
|
2013-08-29 17:46:28 +04:00
|
|
|
/*
|
|
|
|
* A new mntns is required to avoid the race between
|
|
|
|
* open_detach_mount and creating mntns.
|
|
|
|
*/
|
|
|
|
if (unshare(CLONE_NEWNS)) {
|
|
|
|
pr_perror("Can't create new mount namespace");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mount(NULL, "/", NULL, MS_PRIVATE | MS_REC, NULL)) {
|
|
|
|
pr_perror("Can't mark the root mount as private");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-08-17 01:30:48 +04:00
|
|
|
if (mkdtemp(sys_mount) == NULL) {
|
|
|
|
pr_perror("mkdtemp failed %s", sys_mount);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The setns() is called, so we're in proper context,
|
|
|
|
* no need in pulling the mountpoint from parasite.
|
|
|
|
*/
|
|
|
|
pr_info("Mount ns' sysfs in %s\n", sys_mount);
|
|
|
|
if (mount("sysfs", sys_mount, "sysfs", MS_MGC_VAL, NULL)) {
|
|
|
|
pr_perror("mount failed");
|
|
|
|
rmdir(sys_mount);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
ns_sysfs_fd = open_detach_mount(sys_mount);
|
|
|
|
return ns_sysfs_fd >= 0 ? 0 : -1;
|
|
|
|
}
|
|
|
|
|
2013-09-30 17:16:46 +04:00
|
|
|
int dump_net_ns(int pid, int ns_id)
|
2012-08-02 08:06:29 +04:00
|
|
|
{
|
2013-09-30 17:16:46 +04:00
|
|
|
struct cr_fdset *fds;
|
2012-08-02 08:06:29 +04:00
|
|
|
int ret;
|
|
|
|
|
2013-09-28 05:39:52 +04:00
|
|
|
fds = cr_fdset_open(ns_id, NETNS, O_DUMP);
|
2013-09-30 17:16:46 +04:00
|
|
|
if (fds == NULL)
|
|
|
|
return -1;
|
|
|
|
|
2013-01-15 23:24:01 +04:00
|
|
|
ret = switch_ns(pid, &net_ns_desc, NULL);
|
2013-08-17 01:30:48 +04:00
|
|
|
if (!ret)
|
|
|
|
ret = mount_ns_sysfs();
|
2012-08-02 08:17:27 +04:00
|
|
|
if (!ret)
|
|
|
|
ret = dump_links(fds);
|
2012-08-02 08:26:43 +04:00
|
|
|
if (!ret)
|
|
|
|
ret = dump_ifaddr(fds);
|
2012-08-02 08:31:46 +04:00
|
|
|
if (!ret)
|
|
|
|
ret = dump_route(fds);
|
2013-10-04 02:51:33 +04:00
|
|
|
if (!ret)
|
|
|
|
ret = dump_iptables(fds);
|
2012-08-02 08:06:29 +04:00
|
|
|
|
2013-08-17 01:30:48 +04:00
|
|
|
close(ns_sysfs_fd);
|
|
|
|
ns_sysfs_fd = -1;
|
|
|
|
|
2013-09-30 17:16:46 +04:00
|
|
|
close_cr_fdset(&fds);
|
2012-08-02 08:06:29 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int prepare_net_ns(int pid)
|
|
|
|
{
|
2012-08-02 08:17:27 +04:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = restore_links(pid);
|
2012-08-02 08:26:43 +04:00
|
|
|
if (!ret)
|
|
|
|
ret = restore_ifaddr(pid);
|
2012-08-02 08:31:46 +04:00
|
|
|
if (!ret)
|
|
|
|
ret = restore_route(pid);
|
2013-10-04 02:51:33 +04:00
|
|
|
if (!ret)
|
|
|
|
ret = restore_iptables(pid);
|
2012-08-02 08:17:27 +04:00
|
|
|
|
2012-08-10 19:14:36 +04:00
|
|
|
close(ns_fd);
|
|
|
|
|
2012-08-02 08:17:27 +04:00
|
|
|
return ret;
|
2012-08-02 08:06:29 +04:00
|
|
|
}
|
2012-08-10 19:14:36 +04:00
|
|
|
|
|
|
|
int netns_pre_create(void)
|
|
|
|
{
|
|
|
|
ns_fd = open("/proc/self/ns/net", O_RDONLY);
|
|
|
|
if (ns_fd < 0) {
|
|
|
|
pr_perror("Can't cache net fd");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_info("Saved netns fd for links restore\n");
|
|
|
|
return 0;
|
|
|
|
}
|
2012-09-17 20:05:55 +04:00
|
|
|
|
|
|
|
int network_lock(void)
|
|
|
|
{
|
|
|
|
pr_info("Lock network\n");
|
|
|
|
|
|
|
|
/* Each connection will be locked on dump */
|
2013-01-17 18:14:55 +04:00
|
|
|
if (!(current_ns_mask & CLONE_NEWNET))
|
2012-09-17 20:05:55 +04:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
return run_scripts("network-lock");
|
|
|
|
}
|
|
|
|
|
|
|
|
void network_unlock(void)
|
|
|
|
{
|
|
|
|
pr_info("Unlock network\n");
|
|
|
|
|
2013-01-17 18:14:55 +04:00
|
|
|
if (!(current_ns_mask & CLONE_NEWNET)) {
|
2012-09-17 20:07:03 +04:00
|
|
|
cpt_unlock_tcp_connections();
|
|
|
|
rst_unlock_tcp_connections();
|
2012-09-17 20:05:55 +04:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
run_scripts("network-unlock");
|
|
|
|
}
|
|
|
|
|
2013-05-20 13:30:17 +04:00
|
|
|
struct ns_desc net_ns_desc = NS_DESC_ENTRY(CLONE_NEWNET, "net");
|