<p dir="ltr"><br>
On Feb 6, 2016 09:54, &quot;Pavel Emelyanov&quot; &lt;<a href="mailto:xemul@virtuozzo.com">xemul@virtuozzo.com</a>&gt; wrote:<br>
&gt;<br>
&gt; On 02/04/2016 10:36 PM, Andrey Vagin wrote:<br>
&gt; &gt; From: Andrew Vagin &lt;<a href="mailto:avagin@virtuozzo.com">avagin@virtuozzo.com</a>&gt;<br>
&gt; &gt;<br>
&gt; &gt; We request all contracks via netlink and save netlink messages which<br>
&gt; &gt; describe them in an image file, then we send these netlink messages back on restore.<br>
&gt;<br>
&gt; Does it require any non-upstream kernel patch to work?</p>
<p dir="ltr">No, it doesn&#39;t</p>
<p dir="ltr">&gt;<br>
&gt; &gt; <a href="https://github.com/xemul/criu/issues/54">https://github.com/xemul/criu/issues/54</a><br>
&gt; &gt; Signed-off-by: Andrew Vagin &lt;<a href="mailto:avagin@virtuozzo.com">avagin@virtuozzo.com</a>&gt;<br>
&gt; &gt; ---<br>
&gt; &gt;  image-desc.c         |   2 +<br>
&gt; &gt;  include/image-desc.h |   2 +<br>
&gt; &gt;  include/magic.h      |   2 +<br>
&gt; &gt;  net.c                | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++<br>
&gt; &gt;  4 files changed, 132 insertions(+)<br>
&gt; &gt;<br>
&gt; &gt; diff --git a/image-desc.c b/image-desc.c<br>
&gt; &gt; index 9fb96c8..6770675 100644<br>
&gt; &gt; --- a/image-desc.c<br>
&gt; &gt; +++ b/image-desc.c<br>
&gt; &gt; @@ -95,6 +95,8 @@ struct cr_fd_desc_tmpl imgset_template[CR_FD_MAX] = {<br>
&gt; &gt;       FD_ENTRY(CPUINFO,       &quot;cpuinfo&quot;),<br>
&gt; &gt;       FD_ENTRY(SECCOMP,       &quot;seccomp&quot;),<br>
&gt; &gt;       FD_ENTRY(USERNS,        &quot;userns-%d&quot;),<br>
&gt; &gt; +     FD_ENTRY(NETNF_CT,      &quot;netns-ct-%d&quot;),<br>
&gt; &gt; +     FD_ENTRY(NETNF_EXP,     &quot;netns-exp-%d&quot;),<br>
&gt; &gt;<br>
&gt; &gt;       [CR_FD_STATS] = {<br>
&gt; &gt;               .fmt    = &quot;stats-%s&quot;,<br>
&gt; &gt; diff --git a/include/image-desc.h b/include/image-desc.h<br>
&gt; &gt; index 90933e9..532ced8 100644<br>
&gt; &gt; --- a/include/image-desc.h<br>
&gt; &gt; +++ b/include/image-desc.h<br>
&gt; &gt; @@ -44,6 +44,8 @@ enum {<br>
&gt; &gt;       CR_FD_IPTABLES,<br>
&gt; &gt;       CR_FD_IP6TABLES,<br>
&gt; &gt;       CR_FD_NETNS,<br>
&gt; &gt; +     CR_FD_NETNF_CT,<br>
&gt; &gt; +     CR_FD_NETNF_EXP,<br>
&gt; &gt;       _CR_FD_NETNS_TO,<br>
&gt; &gt;<br>
&gt; &gt;       CR_FD_PSTREE,<br>
&gt; &gt; diff --git a/include/magic.h b/include/magic.h<br>
&gt; &gt; index 3cb3766..b11a70e 100644<br>
&gt; &gt; --- a/include/magic.h<br>
&gt; &gt; +++ b/include/magic.h<br>
&gt; &gt; @@ -100,6 +100,8 @@<br>
&gt; &gt;  #define TMPFS_DEV_MAGIC              RAW_IMAGE_MAGIC<br>
&gt; &gt;  #define IPTABLES_MAGIC               RAW_IMAGE_MAGIC<br>
&gt; &gt;  #define IP6TABLES_MAGIC              RAW_IMAGE_MAGIC<br>
&gt; &gt; +#define NETNF_CT_MAGIC               RAW_IMAGE_MAGIC<br>
&gt; &gt; +#define NETNF_EXP_MAGIC              RAW_IMAGE_MAGIC<br>
&gt; &gt;<br>
&gt; &gt;  #define PAGES_OLD_MAGIC              PAGEMAP_MAGIC<br>
&gt; &gt;  #define SHM_PAGES_OLD_MAGIC  PAGEMAP_MAGIC<br>
&gt; &gt; diff --git a/net.c b/net.c<br>
&gt; &gt; index 51b3159..c611f61 100644<br>
&gt; &gt; --- a/net.c<br>
&gt; &gt; +++ b/net.c<br>
&gt; &gt; @@ -2,6 +2,9 @@<br>
&gt; &gt;  #include &lt;sys/socket.h&gt;<br>
&gt; &gt;  #include &lt;linux/netlink.h&gt;<br>
&gt; &gt;  #include &lt;linux/rtnetlink.h&gt;<br>
&gt; &gt; +#include &lt;linux/netfilter/nfnetlink.h&gt;<br>
&gt; &gt; +#include &lt;linux/netfilter/nfnetlink_conntrack.h&gt;<br>
&gt; &gt; +#include &lt;linux/netfilter/nf_conntrack_tcp.h&gt;<br>
&gt; &gt;  #include &lt;string.h&gt;<br>
&gt; &gt;  #include &lt;net/if_arp.h&gt;<br>
&gt; &gt;  #include &lt;sys/wait.h&gt;<br>
&gt; &gt; @@ -344,6 +347,121 @@ unk:<br>
&gt; &gt;       return ret;<br>
&gt; &gt;  }<br>
&gt; &gt;<br>
&gt; &gt; +static int dump_one_nf(struct nlmsghdr *hdr, void *arg)<br>
&gt; &gt; +{<br>
&gt; &gt; +     struct cr_img *img = arg;<br>
&gt; &gt; +<br>
&gt; &gt; +     if (lazy_image(img) &amp;&amp; open_image_lazy(img))<br>
&gt; &gt; +             return -1;<br>
&gt; &gt; +<br>
&gt; &gt; +     if (write_img_buf(img, hdr, hdr-&gt;nlmsg_len))<br>
&gt; &gt; +             return -1;<br>
&gt; &gt; +<br>
&gt; &gt; +     return 0;<br>
&gt; &gt; +}<br>
&gt; &gt; +<br>
&gt; &gt; +static int restore_nf_ct(int pid, int type)<br>
&gt; &gt; +{<br>
&gt; &gt; +     struct nlmsghdr *nlh = NULL;<br>
&gt; &gt; +     int exit_code = -1, sk;<br>
&gt; &gt; +     struct cr_img *img;<br>
&gt; &gt; +<br>
&gt; &gt; +     img = open_image(type, O_RSTR, pid);<br>
&gt; &gt; +     if (empty_image(img)) {<br>
&gt; &gt; +             close_image(img);<br>
&gt; &gt; +             return 0;<br>
&gt; &gt; +     }<br>
&gt; &gt; +<br>
&gt; &gt; +     sk = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER);<br>
&gt; &gt; +     if (sk &lt; 0) {<br>
&gt; &gt; +             pr_perror(&quot;Can&#39;t open rtnl sock for net dump&quot;);<br>
&gt; &gt; +             goto out_img;<br>
&gt; &gt; +     }<br>
&gt; &gt; +<br>
&gt; &gt; +     nlh = xmalloc(sizeof(struct nlmsghdr));<br>
&gt; &gt; +     if (nlh == NULL)<br>
&gt; &gt; +             goto out;<br>
&gt; &gt; +<br>
&gt; &gt; +     while (1) {<br>
&gt; &gt; +             struct nlmsghdr *p;<br>
&gt; &gt; +             int ret;<br>
&gt; &gt; +<br>
&gt; &gt; +             ret = read_img_buf_eof(img, nlh, sizeof(struct nlmsghdr));<br>
&gt; &gt; +             if (ret &lt; 0)<br>
&gt; &gt; +                     goto out;<br>
&gt; &gt; +             if (ret == 0)<br>
&gt; &gt; +                     break;<br>
&gt; &gt; +<br>
&gt; &gt; +             p = xrealloc(nlh, nlh-&gt;nlmsg_len);<br>
&gt; &gt; +             if (p == NULL)<br>
&gt; &gt; +                     goto out;<br>
&gt; &gt; +             nlh = p;<br>
&gt; &gt; +<br>
&gt; &gt; +             ret = read_img_buf_eof(img, nlh + 1, nlh-&gt;nlmsg_len - sizeof(struct nlmsghdr));<br>
&gt; &gt; +             if (ret &lt; 0)<br>
&gt; &gt; +                     goto out;<br>
&gt; &gt; +             if (ret == 0) {<br>
&gt; &gt; +                     pr_err(&quot;The image file was truncated\n&quot;);<br>
&gt; &gt; +                     goto out;<br>
&gt; &gt; +             }<br>
&gt; &gt; +<br>
&gt; &gt; +             nlh-&gt;nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK|NLM_F_CREATE;<br>
&gt; &gt; +             ret = do_rtnl_req(sk, nlh, nlh-&gt;nlmsg_len, NULL, NULL, NULL);<br>
&gt; &gt; +             if (ret)<br>
&gt; &gt; +                     goto out;<br>
&gt; &gt; +     }<br>
&gt; &gt; +<br>
&gt; &gt; +     exit_code = 0;<br>
&gt; &gt; +out:<br>
&gt; &gt; +     xfree(nlh);<br>
&gt; &gt; +     close(sk);<br>
&gt; &gt; +out_img:<br>
&gt; &gt; +     close_image(img);<br>
&gt; &gt; +     return exit_code;<br>
&gt; &gt; +}<br>
&gt; &gt; +<br>
&gt; &gt; +static int dump_nf_ct(struct cr_imgset *fds, int type)<br>
&gt; &gt; +{<br>
&gt; &gt; +     struct cr_img *img;<br>
&gt; &gt; +     struct {<br>
&gt; &gt; +             struct nlmsghdr nlh;<br>
&gt; &gt; +             struct nfgenmsg g;<br>
&gt; &gt; +     } req;<br>
&gt; &gt; +     int sk, ret;<br>
&gt; &gt; +<br>
&gt; &gt; +     pr_info(&quot;Dumping netns links\n&quot;);<br>
&gt; &gt; +<br>
&gt; &gt; +     ret = sk = socket(AF_NETLINK, SOCK_RAW, NETLINK_NETFILTER);<br>
&gt; &gt; +     if (sk &lt; 0) {<br>
&gt; &gt; +             pr_perror(&quot;Can&#39;t open rtnl sock for net dump&quot;);<br>
&gt; &gt; +             goto out;<br>
&gt; &gt; +     }<br>
&gt; &gt; +<br>
&gt; &gt; +     memset(&amp;req, 0, sizeof(req));<br>
&gt; &gt; +     req.nlh.nlmsg_len = sizeof(req);<br>
&gt; &gt; +     req.nlh.nlmsg_type = (NFNL_SUBSYS_CTNETLINK &lt;&lt; 8);<br>
&gt; &gt; +<br>
&gt; &gt; +     if (type == CR_FD_NETNF_CT)<br>
&gt; &gt; +             req.nlh.nlmsg_type |= IPCTNL_MSG_CT_GET;<br>
&gt; &gt; +     else if (type == CR_FD_NETNF_EXP)<br>
&gt; &gt; +             req.nlh.nlmsg_type |= IPCTNL_MSG_EXP_GET;<br>
&gt; &gt; +     else<br>
&gt; &gt; +             BUG();<br>
&gt; &gt; +<br>
&gt; &gt; +     req.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;<br>
&gt; &gt; +     req.nlh.nlmsg_pid = 0;<br>
&gt; &gt; +     req.nlh.nlmsg_seq = CR_NLMSG_SEQ;<br>
&gt; &gt; +     req.g.nfgen_family = AF_UNSPEC;<br>
&gt; &gt; +<br>
&gt; &gt; +     img = img_from_set(fds, type);<br>
&gt; &gt; +<br>
&gt; &gt; +     ret = do_rtnl_req(sk, &amp;req, sizeof(req), dump_one_nf, NULL, img);<br>
&gt; &gt; +     close(sk);<br>
&gt; &gt; +out:<br>
&gt; &gt; +     return ret;<br>
&gt; &gt; +<br>
&gt; &gt; +}<br>
&gt; &gt; +<br>
&gt; &gt;  static int dump_links(struct cr_imgset *fds)<br>
&gt; &gt;  {<br>
&gt; &gt;       int sk, ret;<br>
&gt; &gt; @@ -904,6 +1022,10 @@ int dump_net_ns(int ns_id)<br>
&gt; &gt;               ret = dump_rule(fds);<br>
&gt; &gt;       if (!ret)<br>
&gt; &gt;               ret = dump_iptables(fds);<br>
&gt; &gt; +     if (!ret)<br>
&gt; &gt; +             ret = dump_nf_ct(fds, CR_FD_NETNF_CT);<br>
&gt; &gt; +     if (!ret)<br>
&gt; &gt; +             ret = dump_nf_ct(fds, CR_FD_NETNF_EXP);<br>
&gt; &gt;<br>
&gt; &gt;       close(ns_sysfs_fd);<br>
&gt; &gt;       ns_sysfs_fd = -1;<br>
&gt; &gt; @@ -931,6 +1053,10 @@ int prepare_net_ns(int pid)<br>
&gt; &gt;               ret = restore_rule(pid);<br>
&gt; &gt;       if (!ret)<br>
&gt; &gt;               ret = restore_iptables(pid);<br>
&gt; &gt; +     if (!ret)<br>
&gt; &gt; +             ret = restore_nf_ct(pid, CR_FD_NETNF_CT);<br>
&gt; &gt; +     if (!ret)<br>
&gt; &gt; +             ret = restore_nf_ct(pid, CR_FD_NETNF_EXP);<br>
&gt; &gt;<br>
&gt; &gt;       close_service_fd(NS_FD_OFF);<br>
&gt; &gt;<br>
&gt; &gt;<br>
&gt;<br>
</p>