Quoting Dan Smith ([email protected]):
> When checkpointing a task tree with network namespaces, we hook into
> do_checkpoint_ns() along with the others.  Any devices in a given namespace
> are checkpointed (including their peer, in the case of veth) sequentially.
> Each network device stores a list of protocol addresses, as well as other
> information, such as hardware address.
> 
> This patch supports veth pairs, as well as the loopback adapter.  The
> loopback support is there to make sure that any additional addresses and
> state (such as up/down) is copied to the loopback adapter that we are
> given in the new network namespace.
> 
> On restart, we instantiate new network namespaces and veth pairs as
> necessary.  Any device we encounter that isn't in a network namespace
> that was checkpointed as part of a task is left in the namespace of the
> restarting process.  This will be the case for a veth half that exists
> in the init netns to provide network access to a container.
> 
> Still to do are:
> 
>   1. Routes
>   2. Netfilter rules
>   3. IPv6 addresses
>   4. Other virtual device types (e.g. bridges)
>   5. Multicast
>   6. Device config info (ipv4_devconf)
>   7. Additional ipv4 address attributes
> 
> Changes in v4:
>  - Fix allocation under lock in ckpt_netdev_inet_addrs()
>  - Add comment for case where there is no netns info in checkpoint image
>  - Fix inner structure alignment in netdev_addr header
>  - Fix instances of kfree(skb)
>  - Remove init_netns_ref from container header and checkpoint context
>  - Add 'extern' to checkpoint.h prototypes
>  - Swizzle do_restore_netns() to handle netns more like the others
>  - Return E2BIG for failure case when collecting inet addrs
>  - Report case where device doesn't support checkpoint
>  - Remove nested netns check from may_checkpoint_task()
>  - Move veth-specific netdev attributes into unioned struct to set an
>    example for specific attributes of additional device types
>  - Add 'sit' device restore path that doesn't really do anything
>  - Fail instead of skip when encountering a device with no checkpoint
>    support
> 
> Changes in v3:
>  - Use dev->checkpoint() for per-device checkpoint operation
>  - Use RTNL for veth pair creation on restart
>  - Export some of the functions that will be needed by dev->ndo_checkpoint()
> 
> Changes in v2:
>  - Add CONFIG_CHECKPOINT_NETNS that is dependent on NET, NET_NS, and
>    CHECKPOINT.  Conditionally compile the checkpoint_dev code based on it.
>  - Updated comment on should_checkpoint_netdev()
>  - Updated checkpoint_netdev() to explicitly check for "veth" in name
>  - Changed checkpoint_netns() to use BUG() for impossible condition
>  - Fixed a bug on restart with all devices in the init netns
>  - Lock the dev_base_lock while traversing interface addresses
>  - Collect all addresses for an interface before writing out in one
>    single pass
> 
> Signed-off-by: Dan Smith <[email protected]>
> Cc: [email protected]
> ---
>  checkpoint/checkpoint.c          |   18 +-
>  checkpoint/objhash.c             |   48 +++
>  include/linux/checkpoint.h       |   23 ++
>  include/linux/checkpoint_hdr.h   |   54 +++
>  include/linux/checkpoint_types.h |    1 +
>  kernel/nsproxy.c                 |   24 ++-
>  net/Kconfig                      |    4 +
>  net/Makefile                     |    1 +
>  net/checkpoint_dev.c             |  703 
> ++++++++++++++++++++++++++++++++++++++
>  9 files changed, 864 insertions(+), 12 deletions(-)
>  create mode 100644 net/checkpoint_dev.c
> 
> diff --git a/checkpoint/checkpoint.c b/checkpoint/checkpoint.c
> index b4e0021..119f093 100644
> --- a/checkpoint/checkpoint.c
> +++ b/checkpoint/checkpoint.c
> @@ -185,11 +185,10 @@ static int checkpoint_container(struct ckpt_ctx *ctx)
>       h = ckpt_hdr_get_type(ctx, sizeof(*h), CKPT_HDR_CONTAINER);
>       if (!h)
>               return -ENOMEM;
> -     ret = ckpt_write_obj(ctx, &h->h);
> -     ckpt_hdr_put(ctx, h);
> 
> +     ret = ckpt_write_obj(ctx, &h->h);
>       if (ret < 0)
> -             return ret;
> +             goto out;
> 
>       memset(ctx->lsm_name, 0, CHECKPOINT_LSM_NAME_MAX + 1);
>       strlcpy(ctx->lsm_name, security_get_lsm_name(),
> @@ -197,9 +196,13 @@ static int checkpoint_container(struct ckpt_ctx *ctx)
>       ret = ckpt_write_buffer(ctx, ctx->lsm_name,
>                               CHECKPOINT_LSM_NAME_MAX + 1);
>       if (ret < 0)
> -             return ret;
> +             goto out;
> 
> -     return security_checkpoint_header(ctx);
> +     ret = security_checkpoint_header(ctx);
> + out:
> +     ckpt_hdr_put(ctx, h);
> +
> +     return ret;
>  }

Hey Dan,

the above two hunks change the flow in checkpoint_container(), but
they don't seem to actually add anything.  And I don't see (with a
quick browse) any later patch in this series changing this either.
Is this just noise?

It doesn't seem broken, so it's not a huge deal, but I want to make
sure I'm not missing something

> 
>  /* write the checkpoint trailer */
> @@ -285,11 +288,6 @@ static int may_checkpoint_task(struct ckpt_ctx *ctx, 
> struct task_struct *t)
>               _ckpt_err(ctx, -EPERM, "%(T)Nested mnt_ns unsupported\n");
>               ret = -EPERM;
>       }
> -     /* no support for >1 private netns */
> -     if (nsproxy->net_ns != ctx->root_nsproxy->net_ns) {
> -             _ckpt_err(ctx, -EPERM, "%(T)Nested net_ns unsupported\n");
> -             ret = -EPERM;
> -     }
>       /* no support for >1 private pidns */
>       if (nsproxy->pid_ns != ctx->root_nsproxy->pid_ns) {
>               _ckpt_err(ctx, -EPERM, "%(T)Nested pid_ns unsupported\n");
> diff --git a/checkpoint/objhash.c b/checkpoint/objhash.c
> index 4ca7799..729fbe5 100644
> --- a/checkpoint/objhash.c
> +++ b/checkpoint/objhash.c
> @@ -348,6 +348,36 @@ static void lsm_string_drop(void *ptr, int lastref)
>       kref_put(&s->kref, lsm_string_free);
>  }
> 
> +static int netns_grab(void *ptr)
> +{
> +     struct net *net = ptr;
> +
> +     get_net(net);
> +     return 0;
> +}
> +
> +static void netns_drop(void *ptr, int lastref)
> +{
> +     struct net *net = ptr;
> +
> +     put_net(net);
> +}
> +
> +static int netdev_grab(void *ptr)
> +{
> +     struct net_device *dev = ptr;
> +
> +     dev_hold(dev);
> +     return 0;
> +}
> +
> +static void netdev_drop(void *ptr, int lastref)
> +{
> +     struct net_device *dev = ptr;
> +
> +     dev_put(dev);
> +}
> +
>  /* security context strings */
>  static int checkpoint_lsm_string(struct ckpt_ctx *ctx, void *ptr);
>  static struct ckpt_lsm_string *restore_lsm_string(struct ckpt_ctx *ctx);
> @@ -550,6 +580,24 @@ static struct ckpt_obj_ops ckpt_obj_ops[] = {
>               .checkpoint = checkpoint_lsm_string,
>               .restore = restore_lsm_string_wrap,
>       },
> +     /* Network Namespace Object */
> +     {
> +             .obj_name = "NET_NS",
> +             .obj_type = CKPT_OBJ_NET_NS,
> +             .ref_grab = netns_grab,
> +             .ref_drop = netns_drop,
> +             .checkpoint = checkpoint_netns,
> +             .restore = restore_netns,
> +     },
> +     /* Network Device Object */
> +     {
> +             .obj_name = "NET_DEV",
> +             .obj_type = CKPT_OBJ_NETDEV,
> +             .ref_grab = netdev_grab,
> +             .ref_drop = netdev_drop,
> +             .checkpoint = checkpoint_netdev,
> +             .restore = restore_netdev,
> +     },
>  };
> 
> 
> diff --git a/include/linux/checkpoint.h b/include/linux/checkpoint.h
> index 7101d6f..a25bac1 100644
> --- a/include/linux/checkpoint.h
> +++ b/include/linux/checkpoint.h
> @@ -35,6 +35,7 @@
>  #include <linux/checkpoint_types.h>
>  #include <linux/checkpoint_hdr.h>
>  #include <linux/err.h>
> +#include <linux/inetdevice.h>
>  #include <net/sock.h>
> 
>  /* sycall helpers */
> @@ -119,6 +120,28 @@ extern int ckpt_sock_getnames(struct ckpt_ctx *ctx,
>  extern struct sk_buff *sock_restore_skb(struct ckpt_ctx *ctx, struct sock 
> *sk);
>  extern void sock_listening_list_free(struct list_head *head);
> 
> +#ifdef CONFIG_CHECKPOINT_NETNS
> +extern int checkpoint_netns(struct ckpt_ctx *ctx, void *ptr);
> +extern void *restore_netns(struct ckpt_ctx *ctx);
> +extern int checkpoint_netdev(struct ckpt_ctx *ctx, void *ptr);
> +extern void *restore_netdev(struct ckpt_ctx *ctx);
> +
> +extern int ckpt_netdev_in_init_netns(struct ckpt_ctx *ctx,
> +                                  struct net_device *dev);
> +extern int ckpt_netdev_inet_addrs(struct in_device *indev,
> +                               struct ckpt_netdev_addr *list[]);
> +extern int ckpt_netdev_hwaddr(struct net_device *dev,
> +                           struct ckpt_hdr_netdev *h);
> +extern struct ckpt_hdr_netdev *ckpt_netdev_base(struct ckpt_ctx *ctx,
> +                                             struct net_device *dev,
> +                                             struct ckpt_netdev_addr 
> *addrs[]);
> +#else
> +# define checkpoint_netns NULL
> +# define restore_netns NULL
> +# define checkpoint_netdev NULL
> +# define restore_netdev NULL
> +#endif
> +
>  /* ckpt kflags */
>  #define ckpt_set_ctx_kflag(__ctx, __kflag)  \
>       set_bit(__kflag##_BIT, &(__ctx)->kflags)
> diff --git a/include/linux/checkpoint_hdr.h b/include/linux/checkpoint_hdr.h
> index e591fd1..1fa0482 100644
> --- a/include/linux/checkpoint_hdr.h
> +++ b/include/linux/checkpoint_hdr.h
> @@ -181,6 +181,12 @@ enum {
>  #define CKPT_HDR_SOCKET_UNIX CKPT_HDR_SOCKET_UNIX
>       CKPT_HDR_SOCKET_INET,
>  #define CKPT_HDR_SOCKET_INET CKPT_HDR_SOCKET_INET
> +     CKPT_HDR_NET_NS,
> +#define CKPT_HDR_NET_NS CKPT_HDR_NET_NS
> +     CKPT_HDR_NETDEV,
> +#define CKPT_HDR_NETDEV CKPT_HDR_NETDEV
> +     CKPT_HDR_NETDEV_ADDR,
> +#define CKPT_HDR_NETDEV_ADDR CKPT_HDR_NETDEV_ADDR
> 
>       CKPT_HDR_TAIL = 9001,
>  #define CKPT_HDR_TAIL CKPT_HDR_TAIL
> @@ -253,6 +259,10 @@ enum obj_type {
>  #define CKPT_OBJ_SECURITY_PTR CKPT_OBJ_SECURITY_PTR
>       CKPT_OBJ_SECURITY,
>  #define CKPT_OBJ_SECURITY CKPT_OBJ_SECURITY
> +     CKPT_OBJ_NET_NS,
> +#define CKPT_OBJ_NET_NS CKPT_OBJ_NET_NS
> +     CKPT_OBJ_NETDEV,
> +#define CKPT_OBJ_NETDEV CKPT_OBJ_NETDEV
>       CKPT_OBJ_MAX
>  #define CKPT_OBJ_MAX CKPT_OBJ_MAX
>  };
> @@ -313,6 +323,7 @@ struct ckpt_hdr_tail {
>  /* container configuration section header */
>  struct ckpt_hdr_container {
>       struct ckpt_hdr h;
> +     __s32 init_netns_ref;
>       /*
>        * the header is followed by the string:
>        *   char lsm_name[SECURITY_NAME_MAX + 1]
> @@ -434,6 +445,7 @@ struct ckpt_hdr_ns {
>       struct ckpt_hdr h;
>       __s32 uts_objref;
>       __s32 ipc_objref;
> +     __s32 net_objref;
>  } __attribute__((aligned(8)));
> 
>  /* cannot include <linux/tty.h> from userspace, so define: */
> @@ -758,6 +770,48 @@ struct ckpt_hdr_file_socket {
>       __s32 sock_objref;
>  } __attribute__((aligned(8)));
> 
> +struct ckpt_hdr_netns {
> +     struct ckpt_hdr h;
> +     __s32 this_ref;
> +} __attribute__((aligned(8)));
> +
> +enum ckpt_netdev_types {
> +     CKPT_NETDEV_LO,
> +     CKPT_NETDEV_VETH,
> +     CKPT_NETDEV_SIT,
> +};
> +
> +struct ckpt_hdr_netdev {
> +     struct ckpt_hdr h;
> +     __s32 netns_ref;
> +     union {
> +             struct {
> +                     __s32 this_ref;
> +                     __s32 peer_ref;
> +             } veth;
> +     };
> +     __u32 inet_addrs;
> +     __u16 type;
> +     __u16 flags;
> +     __u8 hwaddr[6];
> +} __attribute__((aligned(8)));
> +
> +enum ckpt_netdev_addr_types {
> +     CKPT_NETDEV_ADDR_IPV4,
> +};
> +
> +struct ckpt_netdev_addr {
> +     __u16 type;
> +     union {
> +             struct {
> +                     __u32 inet4_local;
> +                     __u32 inet4_address;
> +                     __u32 inet4_mask;
> +                     __u32 inet4_broadcast;
> +             };
> +     } __attribute__((aligned(8)));
> +} __attribute__((aligned(8)));
> +
>  struct ckpt_hdr_eventpoll_items {
>       struct ckpt_hdr h;
>       __s32  epfile_objref;
> diff --git a/include/linux/checkpoint_types.h 
> b/include/linux/checkpoint_types.h
> index 51efd5a..e646ec6 100644
> --- a/include/linux/checkpoint_types.h
> +++ b/include/linux/checkpoint_types.h
> @@ -86,6 +86,7 @@ struct ckpt_ctx {
>       wait_queue_head_t ghostq;       /* waitqueue for ghost tasks */
>       struct cred *realcred, *ecred;  /* tmp storage for cred at restart */
>       struct list_head listen_sockets;/* listening parent sockets */
> +     int init_netns_ref;             /* Objref of root net namespace */
> 
>       struct ckpt_stats stats;        /* statistics */
> 
> diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c
> index b0e71f2..e6c84cd 100644
> --- a/kernel/nsproxy.c
> +++ b/kernel/nsproxy.c
> @@ -248,6 +248,11 @@ int ckpt_collect_ns(struct ckpt_ctx *ctx, struct 
> task_struct *t)
>       ret = ckpt_obj_collect(ctx, nsproxy->uts_ns, CKPT_OBJ_UTS_NS);
>       if (ret < 0)
>               goto out;
> +#ifdef CONFIG_CHECKPOINT_NETNS
> +     ret = ckpt_obj_collect(ctx, nsproxy->net_ns, CKPT_OBJ_NET_NS);
> +     if (ret < 0)
> +             goto out;
> +#endif
>       ret = ckpt_obj_collect(ctx, nsproxy->ipc_ns, CKPT_OBJ_IPC_NS);
>       if (ret < 0)
>               goto out;
> @@ -288,6 +293,12 @@ static int do_checkpoint_ns(struct ckpt_ctx *ctx, struct 
> nsproxy *nsproxy)
>       if (ret < 0)
>               goto out;
>       h->ipc_objref = ret;
> +#ifdef CONFIG_CHECKPOINT_NETNS
> +     ret = checkpoint_obj(ctx, nsproxy->net_ns, CKPT_OBJ_NET_NS);
> +     if (ret < 0)
> +             goto out;
> +     h->net_objref = ret;
> +#endif
> 
>       /* FIXME: for now, only marked visited to pacify leaks */
>       ret = ckpt_obj_visit(ctx, nsproxy->mnt_ns, CKPT_OBJ_MNT_NS);
> @@ -312,6 +323,7 @@ static struct nsproxy *do_restore_ns(struct ckpt_ctx *ctx)
>       struct nsproxy *nsproxy = NULL;
>       struct uts_namespace *uts_ns;
>       struct ipc_namespace *ipc_ns;
> +     struct net *net_ns;
>       int ret;
> 
>       h = ckpt_read_obj_type(ctx, sizeof(*h), CKPT_HDR_NS);
> @@ -333,6 +345,14 @@ static struct nsproxy *do_restore_ns(struct ckpt_ctx 
> *ctx)
>               ret = PTR_ERR(ipc_ns);
>               goto out;
>       }
> +     if (h->net_objref == 0)
> +             net_ns = current->nsproxy->net_ns;
> +     else
> +             net_ns = ckpt_obj_fetch(ctx, h->net_objref, CKPT_OBJ_NET_NS);
> +     if (IS_ERR(net_ns)) {
> +             ret = PTR_ERR(net_ns);
> +             goto out;
> +     }
> 
>  #if defined(COFNIG_UTS_NS) || defined(CONFIG_IPC_NS)
>       ret = -ENOMEM;
> @@ -344,13 +364,13 @@ static struct nsproxy *do_restore_ns(struct ckpt_ctx 
> *ctx)
>       nsproxy->uts_ns = uts_ns;
>       get_ipc_ns(ipc_ns);
>       nsproxy->ipc_ns = ipc_ns;
> +     get_net(net_ns);
> +     nsproxy->net_ns = net_ns;
> 
>       get_pid_ns(current->nsproxy->pid_ns);
>       nsproxy->pid_ns = current->nsproxy->pid_ns;
>       get_mnt_ns(current->nsproxy->mnt_ns);
>       nsproxy->mnt_ns = current->nsproxy->mnt_ns;
> -     get_net(current->nsproxy->net_ns);
> -     nsproxy->net_ns = current->nsproxy->net_ns;
>  #else
>       nsproxy = current->nsproxy;
>       get_nsproxy(nsproxy);
> diff --git a/net/Kconfig b/net/Kconfig
> index 041c35e..64dd3cd 100644
> --- a/net/Kconfig
> +++ b/net/Kconfig
> @@ -276,4 +276,8 @@ source "net/wimax/Kconfig"
>  source "net/rfkill/Kconfig"
>  source "net/9p/Kconfig"
> 
> +config CHECKPOINT_NETNS
> +       bool
> +       default y if NET && NET_NS && CHECKPOINT
> +
>  endif   # if NET
> diff --git a/net/Makefile b/net/Makefile
> index 74b038f..570ee98 100644
> --- a/net/Makefile
> +++ b/net/Makefile
> @@ -67,3 +67,4 @@ endif
>  obj-$(CONFIG_WIMAX)          += wimax/
> 
>  obj-$(CONFIG_CHECKPOINT)     += checkpoint.o
> +obj-$(CONFIG_CHECKPOINT_NETNS)       += checkpoint_dev.o
> diff --git a/net/checkpoint_dev.c b/net/checkpoint_dev.c
> new file mode 100644
> index 0000000..3515560
> --- /dev/null
> +++ b/net/checkpoint_dev.c
> @@ -0,0 +1,703 @@
> +/*
> + *  Copyright 2010 IBM Corporation
> + *
> + *  Author(s): Dan Smith <[email protected]>
> + *
> + *  This program is free software; you can redistribute it and/or
> + *  modify it under the terms of the GNU General Public License as
> + *  published by the Free Software Foundation, version 2 of the
> + *  License.
> + */
> +
> +#include <linux/sched.h>
> +#include <linux/if.h>
> +#include <linux/if_arp.h>
> +#include <linux/inetdevice.h>
> +#include <linux/veth.h>
> +#include <linux/checkpoint.h>
> +#include <linux/checkpoint_hdr.h>
> +#include <linux/deferqueue.h>
> +
> +#include <net/net_namespace.h>
> +#include <net/sch_generic.h>
> +
> +struct dq_netdev {
> +     struct net_device *dev;
> +     struct ckpt_ctx *ctx;
> +};
> +
> +static int __kern_devinet_ioctl(struct net *net, unsigned int cmd, void *arg)
> +{
> +     mm_segment_t fs;
> +     int ret;
> +
> +     fs = get_fs();
> +     set_fs(KERNEL_DS);
> +     ret = devinet_ioctl(net, cmd, arg);
> +     set_fs(fs);
> +
> +     return ret;
> +}
> +
> +static int __kern_dev_ioctl(struct net *net, unsigned int cmd, void *arg)
> +{
> +     mm_segment_t fs;
> +     int ret;
> +
> +     fs = get_fs();
> +     set_fs(KERNEL_DS);
> +     ret = dev_ioctl(net, cmd, arg);
> +     set_fs(fs);
> +
> +     return ret;
> +}
> +
> +static struct socket *rtnl_open(void)
> +{
> +     struct socket *sock;
> +     int ret;
> +
> +     ret = sock_create(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE, &sock);
> +     if (ret < 0)
> +             return ERR_PTR(ret);
> +
> +     return sock;
> +}
> +
> +static int rtnl_close(struct socket *rtnl)
> +{
> +     if (rtnl)
> +             return kernel_sock_shutdown(rtnl, SHUT_RDWR);
> +     else
> +             return 0;
> +}
> +
> +static struct nlmsghdr *rtnl_get_response(struct socket *rtnl,
> +                                       struct sk_buff **skb)
> +{
> +     int ret;
> +     long timeo = MAX_SCHEDULE_TIMEOUT;
> +     struct nlmsghdr *nlh;
> +
> +     ret = sk_wait_data(rtnl->sk, &timeo);
> +     if (!ret)
> +             return ERR_PTR(-EPIPE);
> +
> +     *skb = skb_dequeue(&rtnl->sk->sk_receive_queue);
> +     if (!*skb)
> +             return ERR_PTR(-EPIPE);
> +
> +     ret = -EINVAL;
> +     nlh = nlmsg_hdr(*skb);
> +     if (!nlh)
> +             goto err;
> +
> +     if (nlh->nlmsg_type == NLMSG_ERROR) {
> +             struct nlmsgerr *errmsg = nlmsg_data(nlh);
> +             ret = errmsg->error;
> +             goto err;
> +     }
> +
> +     return nlh;
> + err:
> +     kfree_skb(*skb);
> +     *skb = NULL;
> +
> +     return ERR_PTR(ret);
> +}
> +
> +int ckpt_netdev_in_init_netns(struct ckpt_ctx *ctx, struct net_device *dev)
> +{
> +     return dev->nd_net == current->nsproxy->net_ns;
> +}

You are comparing it to the net_ns of the checkpointing task.  I'm not
sure that makes sense - but I'm also not sure what if anything makes more
sense.

What exactly do you mean by the 'init' netns here?  Do you mean the
init_net_ns for the container, or that it is the net_ns of whatever
task created the container?

> +
> +int ckpt_netdev_hwaddr(struct net_device *dev, struct ckpt_hdr_netdev *h)
> +{
> +     struct net *net = dev->nd_net;
> +     struct ifreq req;
> +     int ret;
> +
> +     memcpy(req.ifr_name, dev->name, IFNAMSIZ);
> +     ret = __kern_dev_ioctl(net, SIOCGIFFLAGS, &req);
> +     h->flags = req.ifr_flags;
> +     if (ret < 0)
> +             return ret;
> +
> +     ret = __kern_dev_ioctl(net, SIOCGIFHWADDR, &req);
> +     if (ret < 0)
> +             return ret;
> +
> +     memcpy(h->hwaddr, req.ifr_hwaddr.sa_data, sizeof(h->hwaddr));
> +
> +     return 0;
> +}
> +
> +int ckpt_netdev_inet_addrs(struct in_device *indev,
> +                        struct ckpt_netdev_addr *_abuf[])
> +{
> +     struct ckpt_netdev_addr *abuf = NULL;
> +     struct in_ifaddr *addr = indev->ifa_list;
> +     int pages = 0;
> +     int addrs = 0;
> +     int max;
> +
> + retry:
> +     if (++pages > 4) {
> +             addrs = -E2BIG;
> +             goto out;
> +     }
> +
> +     *_abuf = krealloc(abuf, PAGE_SIZE * pages, GFP_KERNEL);
> +     if (*_abuf == NULL) {
> +             addrs = -ENOMEM;
> +             goto out;
> +     }
> +     abuf = *_abuf;
> +
> +     read_lock(&dev_base_lock);
> +
> +     max = (pages * PAGE_SIZE) / sizeof(*abuf);
> +     while (addr) {
> +             abuf[addrs].type = CKPT_NETDEV_ADDR_IPV4; /* Only IPv4 now */
> +             abuf[addrs].inet4_local = addr->ifa_local;
> +             abuf[addrs].inet4_address = addr->ifa_address;
> +             abuf[addrs].inet4_mask = addr->ifa_mask;
> +             abuf[addrs].inet4_broadcast = addr->ifa_broadcast;
> +
> +             addr = addr->ifa_next;
> +             if (++addrs >= max) {
> +                     read_unlock(&dev_base_lock);
> +                     goto retry;
> +             }
> +     }
> +
> +     read_unlock(&dev_base_lock);
> + out:
> +     if (addrs < 0) {
> +             kfree(abuf);
> +             *_abuf = NULL;
> +     }
> +
> +     return addrs;
> +}
> +
> +struct ckpt_hdr_netdev *ckpt_netdev_base(struct ckpt_ctx *ctx,
> +                                      struct net_device *dev,
> +                                      struct ckpt_netdev_addr *addrs[])
> +{
> +     struct ckpt_hdr_netdev *h;
> +     int ret;
> +
> +     h = ckpt_hdr_get_type(ctx, sizeof(*h), CKPT_HDR_NETDEV);
> +     if (!h)
> +             return ERR_PTR(-ENOMEM);
> +
> +     ret = ckpt_netdev_hwaddr(dev, h);
> +     if (ret < 0)
> +             goto out;
> +
> +     *addrs = NULL;
> +     ret = h->inet_addrs = ckpt_netdev_inet_addrs(dev->ip_ptr, addrs);
> +     if (ret < 0) {
> +             if (ret == -E2BIG)
> +                     ckpt_err(ctx, ret,
> +                              "Too many inet addresses on interface %s\n",
> +                              dev->name);
> +             goto out;
> +     }
> +
> +     if (ckpt_netdev_in_init_netns(ctx, dev))
> +             ret = h->netns_ref = 0;
> +     else
> +             ret = h->netns_ref = checkpoint_obj(ctx, dev->nd_net,
> +                                                 CKPT_OBJ_NET_NS);
> + out:
> +     if (ret < 0) {
> +             ckpt_hdr_put(ctx, h);
> +             h = ERR_PTR(ret);
> +             if (*addrs)
> +                     kfree(*addrs);
> +     }
> +
> +     return h;
> +}
> +
> +int checkpoint_netdev(struct ckpt_ctx *ctx, void *ptr)
> +{
> +     struct net_device *dev = (struct net_device *)ptr;
> +
> +     if (!dev->netdev_ops->ndo_checkpoint) {
> +             ckpt_err(ctx, -ENOSYS,
> +                      "Device %s does not support checkpoint\n", dev->name);
> +             return -ENOSYS;
> +     }
> +
> +     ckpt_debug("checkpointing netdev %s\n", dev->name);
> +
> +     return dev->netdev_ops->ndo_checkpoint(ctx, dev);
> +}
> +
> +int checkpoint_netns(struct ckpt_ctx *ctx, void *ptr)
> +{
> +     struct net *net = ptr;
> +     struct net_device *dev;
> +     struct ckpt_hdr_netns *h;
> +     int ret;
> +
> +     h = ckpt_hdr_get_type(ctx, sizeof(*h), CKPT_HDR_NET_NS);
> +     if (!h)
> +             return -ENOMEM;
> +
> +     h->this_ref = ckpt_obj_lookup(ctx, net, CKPT_OBJ_NET_NS);
> +     BUG_ON(h->this_ref == 0);
> +
> +     ret = ckpt_write_obj(ctx, (struct ckpt_hdr *) h);
> +     if (ret < 0)
> +             goto out;
> +
> +     for_each_netdev(net, dev) {
> +             if (!dev->netdev_ops->ndo_checkpoint) {
> +                     ckpt_debug("Device %s does not support checkpoint\n",
> +                                dev->name);

How about a
                        ckpt_err(ctx, -ENOSYS,
                                Device %s does not support checkpoint\n",
                                dev->name);

here to put a meaningful msg in the user's log?

> +                     ret = -ENOSYS;
> +                     break;
> +             }
> +
> +             ret = checkpoint_obj(ctx, dev, CKPT_OBJ_NETDEV);
> +             if (ret < 0)
> +                     break;
> +     }
> + out:
> +     ckpt_hdr_put(ctx, h);
> +
> +     return ret;
> +}

thanks,
-serge
_______________________________________________
Containers mailing list
[email protected]
https://lists.linux-foundation.org/mailman/listinfo/containers

_______________________________________________
Devel mailing list
[email protected]
https://openvz.org/mailman/listinfo/devel

Reply via email to