[CRIU] dump/restore: Supported ipset

Submitted by Valeriy Vdovin on Jan. 29, 2020, 5:04 p.m.

Details

Message ID 1580317455-173797-1-git-send-email-valeriy.vdovin@virtuozzo.com
State New
Series "dump/restore: Supported ipset"
Headers show

Commit Message

Valeriy Vdovin Jan. 29, 2020, 5:04 p.m.
https://jira.sw.ru/browse/PSBM-100083

Added ipset dump/restore functionality. At dump operation it calls
'ipset save' and stores result into raw text image. At restore
it restores ipset by calling 'ipset restore'. This is done prior
to restoring iptables.

Signed-off-by: Valeriy Vdovin <valeriy.vdovin@virtuozzo.com>
---
 criu/image-desc.c              |  1 +
 criu/include/image-desc.h      |  1 +
 criu/include/magic.h           |  1 +
 criu/net.c                     | 43 +++++++++++++++++++++++++++++++++++
 test/zdtm/static/Makefile      |  1 +
 test/zdtm/static/netns-ipset.c | 51 ++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 98 insertions(+)
 create mode 100644 test/zdtm/static/netns-ipset.c

Patch hide | download patch | download mbox

diff --git a/criu/image-desc.c b/criu/image-desc.c
index 04e827d..475d176 100644
--- a/criu/image-desc.c
+++ b/criu/image-desc.c
@@ -74,6 +74,7 @@  struct cr_fd_desc_tmpl imgset_template[CR_FD_MAX] = {
 	FD_ENTRY_F(ROUTE,	"route-%u", O_NOBUF),
 	FD_ENTRY_F(ROUTE6,	"route6-%u", O_NOBUF),
 	FD_ENTRY_F(RULE,	"rule-%u", O_NOBUF),
+	FD_ENTRY_F(IPSET,	"ipset-%u", O_NOBUF),
 	FD_ENTRY_F(IPTABLES,	"iptables-%u", O_NOBUF),
 	FD_ENTRY_F(IP6TABLES,	"ip6tables-%u", O_NOBUF),
 	FD_ENTRY_F(NFTABLES,	"nftables-%u", O_NOBUF),
diff --git a/criu/include/image-desc.h b/criu/include/image-desc.h
index 1015191..d875722 100644
--- a/criu/include/image-desc.h
+++ b/criu/include/image-desc.h
@@ -40,6 +40,7 @@  enum {
 	CR_FD_ROUTE,
 	CR_FD_ROUTE6,
 	CR_FD_RULE,
+	CR_FD_IPSET,
 	CR_FD_IPTABLES,
 	CR_FD_IP6TABLES,
 	CR_FD_NFTABLES,
diff --git a/criu/include/magic.h b/criu/include/magic.h
index 1a583f4..32421ed 100644
--- a/criu/include/magic.h
+++ b/criu/include/magic.h
@@ -101,6 +101,7 @@ 
 #define RULE_MAGIC		RAW_IMAGE_MAGIC
 #define TMPFS_IMG_MAGIC		RAW_IMAGE_MAGIC
 #define TMPFS_DEV_MAGIC		RAW_IMAGE_MAGIC
+#define IPSET_MAGIC		RAW_IMAGE_MAGIC
 #define IPTABLES_MAGIC		RAW_IMAGE_MAGIC
 #define IP6TABLES_MAGIC		RAW_IMAGE_MAGIC
 #define NFTABLES_MAGIC		RAW_IMAGE_MAGIC
diff --git a/criu/net.c b/criu/net.c
index 8ee560c..dccc491 100644
--- a/criu/net.c
+++ b/criu/net.c
@@ -1775,6 +1775,26 @@  static int restore_links()
 	return 0;
 }
 
+static int run_ipset_tool(char *arg1, char *arg2, char *arg3, int fdin, int fdout)
+{
+	char *cmd;
+	int ret;
+
+	pr_debug("\tRunning ipset %s %s %s \n", arg1, arg2, arg3 ? : "");
+
+	cmd = getenv("CR_IPSET_TOOL");
+	if (!cmd)
+		cmd = "ipset";
+
+	ret = cr_system(fdin, fdout, -1, cmd,
+				(char *[]) { cmd, arg1, arg2, arg3, NULL }, 0);
+	if (ret) {
+		pr_err("ipset tool failed on %s %s %s \n", arg1, arg2, arg3 ? : "");
+		return -1;
+	}
+
+	return 0;
+}
 
 static int run_ip_tool(char *arg1, char *arg2, char *arg3, char *arg4, int fdin, int fdout, unsigned flags)
 {
@@ -1845,6 +1865,7 @@  static int iptables_tool_dump(char *def_cmd, int fdin, int fdout)
 	return run_iptables_tool(def_cmd, fdin, fdout);
 }
 
+
 static inline int dump_ifaddr(struct cr_imgset *fds)
 {
 	struct cr_img *img = img_from_set(fds, CR_FD_IFADDR);
@@ -1891,6 +1912,13 @@  static inline int dump_rule(struct cr_imgset *fds)
 	return 0;
 }
 
+static inline int dump_ipset(struct cr_imgset *fds)
+{
+	struct cr_img *img;
+	img = img_from_set(fds, CR_FD_IPSET);
+	return run_ipset_tool("save", 0, 0, -1, img_raw_fd(img));
+}
+
 static inline int dump_iptables(struct cr_imgset *fds)
 {
 	struct cr_img *img;
@@ -2129,6 +2157,17 @@  static int prepare_xtable_lock()
 	return 0;
 }
 
+static inline int restore_ipset(int pid)
+{
+	struct cr_img *img;
+	img = open_image(CR_FD_IPSET, O_RSTR, pid);
+	if (img == NULL)
+		return -1;
+	if (empty_image(img))
+		return 0;
+	return run_ipset_tool("restore", 0, 0, img_raw_fd(img), -1);
+}
+
 static inline int restore_iptables(int pid)
 {
 	int ret = -1;
@@ -2446,6 +2485,8 @@  int dump_net_ns(struct ns_id *ns)
 		if (!ret)
 			ret = dump_rule(fds);
 		if (!ret)
+			ret = dump_ipset(fds);
+		if (!ret)
 			ret = dump_iptables(fds);
 		if (!ret)
 			ret = dump_nftables(fds);
@@ -2541,6 +2582,8 @@  static int prepare_net_ns_second_stage(struct ns_id *ns)
 		if (!ret)
 			ret = restore_rule(nsid);
 		if (!ret)
+			ret = restore_ipset(nsid);
+		if (!ret)
 			ret = restore_iptables(nsid);
 		if (!ret)
 			ret = restore_nftables(nsid);
diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile
index 28717b1..bdef4d0 100644
--- a/test/zdtm/static/Makefile
+++ b/test/zdtm/static/Makefile
@@ -143,6 +143,7 @@  TST_NOFILE	:=				\
 		poll				\
 		mountpoints			\
 		netns				\
+		netns-ipset			\
 		netns-dev			\
 		session01			\
 		session02			\
diff --git a/test/zdtm/static/netns-ipset.c b/test/zdtm/static/netns-ipset.c
new file mode 100644
index 0000000..2650685
--- /dev/null
+++ b/test/zdtm/static/netns-ipset.c
@@ -0,0 +1,51 @@ 
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "zdtmtst.h"
+
+const char *test_doc	= "Check that ipset are dumped and restored correctly";
+
+#define RUN_OR_ERR(cmd, failmsg) if (system(cmd)) { pr_perror(failmsg); return -1; }
+#define RUN_OR_FAIL(cmd, failmsg) if (system(cmd)) { fail(failmsg); return -1; }
+
+int main(int argc, char **argv)
+{
+	char dump_ipset_old[]    = "ipset save > ipset.old";
+	char dump_ipset_new[]    = "ipset save > ipset.new";
+	char dump_iptables_old[] = "iptables -L INPUT 1 > iptables.old";
+	char dump_iptables_new[] = "iptables -L INPUT 1 > iptables.new";
+	char cmp_ipset[]         = "diff ipset.old ipset.new";
+	char cmp_iptables[]      = "diff iptables.old iptables.new";
+
+	test_init(argc, argv);
+
+	/* create ipset group and add some ip addresses to it */
+	RUN_OR_ERR("ipset create testgroup nethash", "Can't create test ipset");
+	RUN_OR_ERR("ipset add testgroup 127.0.0.1/8", "Can't add ip addresses to ipset group");
+
+	/* Use testgroup in iptables rule */
+	RUN_OR_ERR("iptables -I INPUT 1 -p tcp -m set --match-set testgroup src,dst -j ACCEPT",
+		"Failed to setup iptables rule with ipset group");
+
+	/* dump ipset and iptables states to text files */
+	RUN_OR_ERR(dump_iptables_old, "Can't save iptables rules.");
+	RUN_OR_ERR(dump_ipset_old   , "Can't save ipset list.");
+
+	test_daemon();
+	test_waitsig();
+
+	/* again dump ipset and iptables states to other text files */
+	RUN_OR_ERR(dump_iptables_new, "Can't dump restored iptables rules.");
+	RUN_OR_ERR(dump_ipset_new   , "Can't save restored ipset list to file.");
+
+	/* compare original and restored iptables rules */
+	RUN_OR_FAIL(cmp_iptables, "iptables rules differ");
+
+	/* compare original and restored ipset rules */
+	RUN_OR_FAIL(cmp_ipset, "ipset lists differ");
+
+	pass();
+	return 0;
+}

Comments

Alexander Mikhalitsyn Jan. 30, 2020, 8:56 a.m.
On Wed, 29 Jan 2020 20:04:15 +0300
Valeriy Vdovin <valeriy.vdovin@virtuozzo.com> wrote:

> https://jira.sw.ru/browse/PSBM-100083
> 
> Added ipset dump/restore functionality. At dump operation it calls
> 'ipset save' and stores result into raw text image. At restore
> it restores ipset by calling 'ipset restore'. This is done prior
> to restoring iptables.
> 
> Signed-off-by: Valeriy Vdovin <valeriy.vdovin@virtuozzo.com>
> ---
>  criu/image-desc.c              |  1 +
>  criu/include/image-desc.h      |  1 +
>  criu/include/magic.h           |  1 +
>  criu/net.c                     | 43 +++++++++++++++++++++++++++++++++++
>  test/zdtm/static/Makefile      |  1 +
>  test/zdtm/static/netns-ipset.c | 51 ++++++++++++++++++++++++++++++++++++++++++
>  6 files changed, 98 insertions(+)
>  create mode 100644 test/zdtm/static/netns-ipset.c
> 
> diff --git a/criu/image-desc.c b/criu/image-desc.c
> index 04e827d..475d176 100644
> --- a/criu/image-desc.c
> +++ b/criu/image-desc.c
> @@ -74,6 +74,7 @@ struct cr_fd_desc_tmpl imgset_template[CR_FD_MAX] = {
>  	FD_ENTRY_F(ROUTE,	"route-%u", O_NOBUF),
>  	FD_ENTRY_F(ROUTE6,	"route6-%u", O_NOBUF),
>  	FD_ENTRY_F(RULE,	"rule-%u", O_NOBUF),
> +	FD_ENTRY_F(IPSET,	"ipset-%u", O_NOBUF),
>  	FD_ENTRY_F(IPTABLES,	"iptables-%u", O_NOBUF),
>  	FD_ENTRY_F(IP6TABLES,	"ip6tables-%u", O_NOBUF),
>  	FD_ENTRY_F(NFTABLES,	"nftables-%u", O_NOBUF),
> diff --git a/criu/include/image-desc.h b/criu/include/image-desc.h
> index 1015191..d875722 100644
> --- a/criu/include/image-desc.h
> +++ b/criu/include/image-desc.h
> @@ -40,6 +40,7 @@ enum {
>  	CR_FD_ROUTE,
>  	CR_FD_ROUTE6,
>  	CR_FD_RULE,
> +	CR_FD_IPSET,
>  	CR_FD_IPTABLES,
>  	CR_FD_IP6TABLES,
>  	CR_FD_NFTABLES,
> diff --git a/criu/include/magic.h b/criu/include/magic.h
> index 1a583f4..32421ed 100644
> --- a/criu/include/magic.h
> +++ b/criu/include/magic.h
> @@ -101,6 +101,7 @@
>  #define RULE_MAGIC		RAW_IMAGE_MAGIC
>  #define TMPFS_IMG_MAGIC		RAW_IMAGE_MAGIC
>  #define TMPFS_DEV_MAGIC		RAW_IMAGE_MAGIC
> +#define IPSET_MAGIC		RAW_IMAGE_MAGIC
>  #define IPTABLES_MAGIC		RAW_IMAGE_MAGIC
>  #define IP6TABLES_MAGIC		RAW_IMAGE_MAGIC
>  #define NFTABLES_MAGIC		RAW_IMAGE_MAGIC
> diff --git a/criu/net.c b/criu/net.c
> index 8ee560c..dccc491 100644
> --- a/criu/net.c
> +++ b/criu/net.c
> @@ -1775,6 +1775,26 @@ static int restore_links()
>  	return 0;
>  }
>  
> +static int run_ipset_tool(char *arg1, char *arg2, char *arg3, int fdin, int fdout)
> +{
> +	char *cmd;
> +	int ret;
> +
> +	pr_debug("\tRunning ipset %s %s %s \n", arg1, arg2, arg3 ? : "");
> +
> +	cmd = getenv("CR_IPSET_TOOL");
> +	if (!cmd)
> +		cmd = "ipset";
> +
> +	ret = cr_system(fdin, fdout, -1, cmd,
> +				(char *[]) { cmd, arg1, arg2, arg3, NULL }, 0);
> +	if (ret) {
> +		pr_err("ipset tool failed on %s %s %s \n", arg1, arg2, arg3 ? : "");
> +		return -1;
> +	}
> +
> +	return 0;
> +}
>  
>  static int run_ip_tool(char *arg1, char *arg2, char *arg3, char *arg4, int fdin, int fdout, unsigned flags)
>  {
> @@ -1845,6 +1865,7 @@ static int iptables_tool_dump(char *def_cmd, int fdin, int fdout)
>  	return run_iptables_tool(def_cmd, fdin, fdout);
>  }
>  
> +
is it needed here?
>  static inline int dump_ifaddr(struct cr_imgset *fds)
>  {
>  	struct cr_img *img = img_from_set(fds, CR_FD_IFADDR);
> @@ -1891,6 +1912,13 @@ static inline int dump_rule(struct cr_imgset *fds)
>  	return 0;
>  }
>  
> +static inline int dump_ipset(struct cr_imgset *fds)
> +{
> +	struct cr_img *img;
> +	img = img_from_set(fds, CR_FD_IPSET);
> +	return run_ipset_tool("save", 0, 0, -1, img_raw_fd(img));
> +}
> +
>  static inline int dump_iptables(struct cr_imgset *fds)
>  {
>  	struct cr_img *img;
> @@ -2129,6 +2157,17 @@ static int prepare_xtable_lock()
>  	return 0;
>  }
>  
> +static inline int restore_ipset(int pid)
> +{
> +	struct cr_img *img;
> +	img = open_image(CR_FD_IPSET, O_RSTR, pid);
> +	if (img == NULL)
> +		return -1;
> +	if (empty_image(img))
close_image(img) ?
> +		return 0;
> +	return run_ipset_tool("restore", 0, 0, img_raw_fd(img), -1);
here, you also need to close_image(img).
> +}
> +
>  static inline int restore_iptables(int pid)
>  {
>  	int ret = -1;
> @@ -2446,6 +2485,8 @@ int dump_net_ns(struct ns_id *ns)
>  		if (!ret)
>  			ret = dump_rule(fds);
>  		if (!ret)
> +			ret = dump_ipset(fds);
> +		if (!ret)
>  			ret = dump_iptables(fds);
>  		if (!ret)
>  			ret = dump_nftables(fds);
> @@ -2541,6 +2582,8 @@ static int prepare_net_ns_second_stage(struct ns_id *ns)
>  		if (!ret)
>  			ret = restore_rule(nsid);
>  		if (!ret)
> +			ret = restore_ipset(nsid);
> +		if (!ret)
>  			ret = restore_iptables(nsid);
>  		if (!ret)
>  			ret = restore_nftables(nsid);
> diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile
> index 28717b1..bdef4d0 100644
> --- a/test/zdtm/static/Makefile
> +++ b/test/zdtm/static/Makefile
> @@ -143,6 +143,7 @@ TST_NOFILE	:=				\
>  		poll				\
>  		mountpoints			\
>  		netns				\
> +		netns-ipset			\
>  		netns-dev			\
>  		session01			\
>  		session02			\
> diff --git a/test/zdtm/static/netns-ipset.c b/test/zdtm/static/netns-ipset.c
> new file mode 100644
> index 0000000..2650685
> --- /dev/null
> +++ b/test/zdtm/static/netns-ipset.c
> @@ -0,0 +1,51 @@
> +#include <string.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +
> +#include "zdtmtst.h"
> +
> +const char *test_doc	= "Check that ipset are dumped and restored correctly";
> +
> +#define RUN_OR_ERR(cmd, failmsg) if (system(cmd)) { pr_perror(failmsg); return -1; }
> +#define RUN_OR_FAIL(cmd, failmsg) if (system(cmd)) { fail(failmsg); return -1; }
> +
> +int main(int argc, char **argv)
> +{
> +	char dump_ipset_old[]    = "ipset save > ipset.old";
> +	char dump_ipset_new[]    = "ipset save > ipset.new";
> +	char dump_iptables_old[] = "iptables -L INPUT 1 > iptables.old";
> +	char dump_iptables_new[] = "iptables -L INPUT 1 > iptables.new";
> +	char cmp_ipset[]         = "diff ipset.old ipset.new";
> +	char cmp_iptables[]      = "diff iptables.old iptables.new";
> +
> +	test_init(argc, argv);
> +
> +	/* create ipset group and add some ip addresses to it */
> +	RUN_OR_ERR("ipset create testgroup nethash", "Can't create test ipset");
> +	RUN_OR_ERR("ipset add testgroup 127.0.0.1/8", "Can't add ip addresses to ipset group");
what about ipv6?
> +
> +	/* Use testgroup in iptables rule */
> +	RUN_OR_ERR("iptables -I INPUT 1 -p tcp -m set --match-set testgroup src,dst -j ACCEPT",
> +		"Failed to setup iptables rule with ipset group");
> +
> +	/* dump ipset and iptables states to text files */
> +	RUN_OR_ERR(dump_iptables_old, "Can't save iptables rules.");
> +	RUN_OR_ERR(dump_ipset_old   , "Can't save ipset list.");
> +
> +	test_daemon();
> +	test_waitsig();
> +
> +	/* again dump ipset and iptables states to other text files */
> +	RUN_OR_ERR(dump_iptables_new, "Can't dump restored iptables rules.");
> +	RUN_OR_ERR(dump_ipset_new   , "Can't save restored ipset list to file.");
> +
> +	/* compare original and restored iptables rules */
> +	RUN_OR_FAIL(cmp_iptables, "iptables rules differ");
> +
> +	/* compare original and restored ipset rules */
> +	RUN_OR_FAIL(cmp_ipset, "ipset lists differ");
> +
> +	pass();
> +	return 0;
> +}
> -- 
> 1.8.3.1
>