diff -Nur criu/0008-fix-multi-thread-recover-problem-with-pin-memory.patch obs_criu/0008-fix-multi-thread-recover-problem-with-pin-memory.patch
--- criu/0008-fix-multi-thread-recover-problem-with-pin-memory.patch	1970-01-01 08:00:00.000000000 +0800
+++ obs_criu/0008-fix-multi-thread-recover-problem-with-pin-memory.patch	2022-10-17 16:18:23.000000000 +0800
@@ -0,0 +1,81 @@
+From d4fc065ffa77a886eb310241b53ddf2bccc8fad7 Mon Sep 17 00:00:00 2001
+From: Your Name <you@example.com>
+Date: Fri, 14 Oct 2022 16:20:06 +0800
+Subject: [PATCH 2/6] fix-multi-thread-recover-problem-with-pin-memory
+
+Signed-off-by: Jingxian He <hejingxian@huawei.com>
+---
+ criu/include/restorer.h |  3 +++
+ criu/seize.c            | 24 ++++++++++++++++++++++++
+ 2 files changed, 27 insertions(+)
+
+diff --git a/criu/include/restorer.h b/criu/include/restorer.h
+index 3d1a3c0..f7e4f64 100644
+--- a/criu/include/restorer.h
++++ b/criu/include/restorer.h
+@@ -325,10 +325,13 @@ enum {
+ #define _CLEAR_PIN_MEM_AREA  2
+ #define _REMAP_PIN_MEM_AREA  3
+ #define _SET_FORK_PID        6
++#define _CLEAR_TASK_OUTDATED_STATE  7
++
+ #define SET_PIN_MEM_AREA        _IOW(PIN_MEM_MAGIC, _SET_PIN_MEM_AREA, struct pin_mem_area_set)
+ #define CLEAR_PIN_MEM_AREA      _IOW(PIN_MEM_MAGIC, _CLEAR_PIN_MEM_AREA, int)
+ #define REMAP_PIN_MEM_AREA      _IOW(PIN_MEM_MAGIC, _REMAP_PIN_MEM_AREA, int)
+ #define SET_FORK_PID            _IOW(PIN_MEM_MAGIC, _SET_FORK_PID, int)
++#define CLEAR_TASK_OUTDATED_STATE       _IOW(PIN_MEM_MAGIC, _CLEAR_TASK_OUTDATED_STATE, int)
+ 
+ #define ONCE_PIN_MEM_SIZE_LIMIT  32 * 1024 * 1024
+ #define MAX_PIN_MEM_AREA_NUM  16
+diff --git a/criu/seize.c b/criu/seize.c
+index f973806..7dc92ec 100644
+--- a/criu/seize.c
++++ b/criu/seize.c
+@@ -23,6 +23,7 @@
+ #include "string.h"
+ #include "xmalloc.h"
+ #include "util.h"
++#include "restorer.h"
+ 
+ #define NR_ATTEMPTS 5
+ 
+@@ -648,6 +649,24 @@ free:
+ 	return ret < 0 ? ret : nr_inprogress;
+ }
+ 
++static int clear_task_outdated_state(int pid)
++{
++	int fd, ret;
++
++	fd = open(PIN_MEM_FILE, O_RDWR, 0);
++	if (fd < 0) {
++		pr_warn("error open file: %s\n", PIN_MEM_FILE);
++		return -1;
++	}
++
++	ret = ioctl(fd, CLEAR_TASK_OUTDATED_STATE, (unsigned long) &pid);
++	if (ret < 0)
++		pr_warn("CLEAR_TASK_OUTDATED_STATE for %d fail\n", pid);
++
++	close(fd);
++	return ret;
++}
++
+ static void unseize_task_and_threads(const struct pstree_item *item, int st)
+ {
+ 	int i;
+@@ -655,6 +674,11 @@ static void unseize_task_and_threads(const struct pstree_item *item, int st)
+ 	if (item->pid->state == TASK_DEAD)
+ 		return;
+ 
++	if (opts.pin_memory) {
++		for (i = 0; i < item->nr_threads; i++)
++			clear_task_outdated_state(item->threads[i].real);
++	}
++
+ 	/*
+ 	 * The st is the state we want to switch tasks into,
+ 	 * the item->state is the state task was in when we seized one.
+-- 
+2.33.0
+
diff -Nur criu/0009-nftables-add-mnl-api.patch obs_criu/0009-nftables-add-mnl-api.patch
--- criu/0009-nftables-add-mnl-api.patch	1970-01-01 08:00:00.000000000 +0800
+++ obs_criu/0009-nftables-add-mnl-api.patch	2022-10-17 09:36:25.000000000 +0800
@@ -0,0 +1,270 @@
+From c19a4e2fa94eae0dd386fe7061d3fd719330c37a Mon Sep 17 00:00:00 2001
+From: Jingxian He <hejingxian@huawei.com>
+Date: Fri, 14 Oct 2022 16:22:41 +0800
+Subject: [PATCH 3/6] nftables-add-mnl-api
+
+libmnl provides the communication between userspace and kernelspace for
+netfilter netlink. I abstract here for the next usage.
+
+Signed-off-by: fu.lin <fulin10@huawei.com>
+Signed-off-by: Jingxian He <hejingxian@huawei.com>
+---
+ criu/Makefile.crtools   |   1 +
+ criu/Makefile.packages  |   6 ++
+ criu/include/nftables.h |  28 +++++++
+ criu/mnl.c              | 165 ++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 200 insertions(+)
+ create mode 100644 criu/include/nftables.h
+ create mode 100644 criu/mnl.c
+
+diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools
+index dcffb4f..d2088bb 100644
+--- a/criu/Makefile.crtools
++++ b/criu/Makefile.crtools
+@@ -89,6 +89,7 @@ obj-y			+= servicefd.o
+ obj-y			+= pie-util-vdso.o
+ obj-y			+= vdso.o
+ obj-y			+= timens.o
++obj-y			+= mnl.o
+ obj-$(CONFIG_HAS_LIBBPF)	+= bpfmap.o
+ obj-$(CONFIG_COMPAT)	+= pie-util-vdso-elf32.o
+ CFLAGS_pie-util-vdso-elf32.o	+= -DCONFIG_VDSO_32
+diff --git a/criu/Makefile.packages b/criu/Makefile.packages
+index 13c346f..c1d87a5 100644
+--- a/criu/Makefile.packages
++++ b/criu/Makefile.packages
+@@ -7,6 +7,8 @@ REQ-RPM-PKG-NAMES	+= protobuf-python
+ REQ-RPM-PKG-NAMES	+= libnl3-devel
+ REQ-RPM-PKG-NAMES	+= libcap-devel
+ REQ-RPM-PKG-NAMES	+= $(PYTHON)-future
++REQ-RPM-PKG-NAMES	+= libmnl-devel
++REQ-RPM-PKG-NAMES	+= libnftnl-devel
+ 
+ REQ-RPM-PKG-TEST-NAMES  += libaio-devel
+ 
+@@ -18,6 +20,8 @@ REQ-DEB-PKG-NAMES	+= $(PYTHON)-protobuf
+ REQ-DEB-PKG-NAMES	+= $(PYTHON)-future
+ REQ-DEB-PKG-NAMES	+= libnl-3-dev
+ REQ-DEB-PKG-NAMES	+= libcap-dev
++REQ-DEB-PKG-NAMES	+= libmnl-dev
++REQ-DEB-PKG-NAMES	+= libnftnl-dev
+ 
+ REQ-DEB-PKG-TEST-NAMES	+= $(PYTHON)-yaml
+ REQ-DEB-PKG-TEST-NAMES	+= libaio-dev
+@@ -31,6 +35,8 @@ REQ-RPM-PKG-TEST-NAMES	+= $(PYTHON)-pyyaml
+ endif
+ 
+ export LIBS		+= -lprotobuf-c -ldl -lnl-3 -lsoccr -Lsoccr/ -lnet
++export LIBS		+= $(shell pkg-config --libs libmnl)
++export LIBS		+= $(shell pkg-config --libs libnftnl)
+ 
+ check-packages-failed:
+ 	$(warning Can not find some of the required libraries)
+diff --git a/criu/include/nftables.h b/criu/include/nftables.h
+new file mode 100644
+index 0000000..0bdab31
+--- /dev/null
++++ b/criu/include/nftables.h
+@@ -0,0 +1,28 @@
++#ifndef __CR_NFTABLES_H__
++#define __CR_NFTABLES_H__
++
++#include <libmnl/libmnl.h>
++
++struct mnl_params {
++	struct mnl_socket *nl;
++	char *buf;
++	struct mnl_nlmsg_batch *batch;
++	uint32_t seq;
++};
++
++typedef struct nlmsghdr * (*buf_func_t)(struct mnl_params *mnl_params, void *args);
++typedef int (*batch_func_t)(struct mnl_params *mnl_params, void *args);
++typedef int (*mnl_func_t)(struct mnl_params *mnl, batch_func_t cb, void *args);
++
++struct mnl_cb_params {
++	pid_t tree_id;
++	bool create;
++	bool ipv6;
++};
++
++int mnl_sendmsg(batch_func_t batch_cb, void *args);
++int mnl_common(mnl_func_t mnl_cb, void *arg1, void *arg2);
++int mnl_batch_send_and_recv(struct mnl_params *mnl_params, batch_func_t cb, void *args, int *result);
++int mnl_buf_send_and_recv(struct mnl_params *mnl_params, buf_func_t cb, void *args, int *result);
++
++#endif /* __CR_NFTABLES_H__ */
+diff --git a/criu/mnl.c b/criu/mnl.c
+new file mode 100644
+index 0000000..3a03202
+--- /dev/null
++++ b/criu/mnl.c
+@@ -0,0 +1,165 @@
++#include <string.h>
++#include <time.h>
++#include <errno.h>
++
++#include <libnftnl/common.h>
++
++#include "nftables.h"
++#include "log.h"
++
++int mnl_common(mnl_func_t mnl_cb, void *arg1, void *arg2)
++{
++	char buf[MNL_SOCKET_BUFFER_SIZE];
++	struct mnl_params mnl = {
++		.seq = time(NULL),
++	};
++	int retval = -1;
++
++	mnl.nl = mnl_socket_open(NETLINK_NETFILTER);
++	if (mnl.nl == NULL) {
++		pr_err("mnl_socket_open failed with %d: %s\n", errno, strerror(errno));
++		return -1;
++	}
++
++	if (mnl_socket_bind(mnl.nl, 0, MNL_SOCKET_AUTOPID) < 0) {
++		pr_err("mnl_socket_bind wailed with %d: %s\n", errno, strerror(errno));
++		goto err_mnl;
++	}
++
++	mnl.buf = buf;
++	mnl.batch = mnl_nlmsg_batch_start(buf, sizeof(buf));
++	if (mnl.batch == NULL)
++		goto err_mnl;
++
++	if (mnl_cb(&mnl, arg1, arg2) < 0)
++		goto err_batch;
++
++	retval = 0;
++
++err_batch:
++	mnl_nlmsg_batch_stop(mnl.batch);
++err_mnl:
++	mnl_socket_close(mnl.nl);
++
++	return retval;
++}
++
++static int mnl_sendmsg_internal(struct mnl_params *mnl, batch_func_t cb, void *args)
++{
++	int retval = -1;
++
++	nftnl_batch_begin(mnl_nlmsg_batch_current(mnl->batch), mnl->seq++);
++	mnl_nlmsg_batch_next(mnl->batch);
++
++	if (cb(mnl, args) < 0)
++		goto err_batch;
++
++	nftnl_batch_end(mnl_nlmsg_batch_current(mnl->batch), mnl->seq++);
++	mnl_nlmsg_batch_next(mnl->batch);
++
++	if (mnl_socket_sendto(mnl->nl, mnl_nlmsg_batch_head(mnl->batch),
++			      mnl_nlmsg_batch_size(mnl->batch)) < 0) {
++		pr_err("%s: mnl_socket_sendto failed with %d: %s\n",
++				__func__, errno, strerror(errno));
++		goto err_batch;
++	}
++
++	retval = 0;
++
++err_batch:
++	return retval;
++}
++
++int mnl_sendmsg(batch_func_t batch_cb, void *args)
++{
++	return mnl_common(mnl_sendmsg_internal, batch_cb, args);
++}
++
++int mnl_batch_send_and_recv(struct mnl_params *mnl_params, batch_func_t cb,
++			    void *args, int *result)
++{
++	struct mnl_socket *nl = mnl_params->nl;
++	struct mnl_nlmsg_batch *batch = mnl_params->batch;
++	uint32_t *seq = &mnl_params->seq;
++	char buf[MNL_SOCKET_BUFFER_SIZE];
++	int retval;
++
++	mnl_nlmsg_batch_reset(batch);
++	nftnl_batch_begin(mnl_nlmsg_batch_current(batch), (*seq)++);
++	mnl_nlmsg_batch_next(batch);
++
++	if (cb(mnl_params, args) < 0)
++		return -1;
++
++	nftnl_batch_end(mnl_nlmsg_batch_current(batch), (*seq)++);
++	mnl_nlmsg_batch_next(batch);
++
++	if (mnl_socket_sendto(nl, mnl_nlmsg_batch_head(batch),
++			      mnl_nlmsg_batch_size(batch)) < 0) {
++		pr_err("%s: mnl_socket_sendto failed with %d: %s\n",
++				__func__, errno, strerror(errno));
++		return -1;
++	}
++
++	/* don't care the netlink retval, and nlmsg hdr flags has no `NLM_F_ACK` */
++	if (result == NULL)
++		return 0;
++
++	retval = mnl_socket_recvfrom(nl, buf, sizeof(buf));
++	while (retval > 0) {
++		retval = mnl_cb_run(buf, retval, 0, mnl_socket_get_portid(nl), NULL, NULL);
++		if (retval <= 0)
++			break;
++		retval = mnl_socket_recvfrom(nl, buf, sizeof(buf));
++	}
++
++	if (retval < 0) {
++		pr_err("%s: mnl batch socket recv errno with %d: %s\n",
++				__func__, errno, strerror(errno));
++		*result = errno;
++		return -1;
++	}
++
++	*result = 0;
++	return 0;
++}
++
++int mnl_buf_send_and_recv(struct mnl_params *mnl_params, buf_func_t cb,
++			  void *args, int *result)
++{
++	struct mnl_socket *nl = mnl_params->nl;
++	char buf[MNL_SOCKET_BUFFER_SIZE];
++	struct nlmsghdr *nlh;
++	int retval = 0;
++
++	if ((nlh = cb(mnl_params, args)) == NULL)
++		return -1;
++
++	if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
++		pr_err("%s: mnl_socket_sendto failed with %d: %s\n",
++				__func__, errno, strerror(errno));
++		return -1;
++	}
++
++	/* don't care the netlink retval, and nlmsg hdr flags has no `NLM_F_ACK` */
++	if (result == NULL)
++		return 0;
++
++	retval = mnl_socket_recvfrom(nl, buf, sizeof(buf));
++	while (retval > 0) {
++		retval = mnl_cb_run(buf, retval, 0, mnl_socket_get_portid(nl), NULL, NULL);
++		if (retval <= 0)
++			break;
++		retval = mnl_socket_recvfrom(nl, buf, sizeof(buf));
++	}
++
++	if (retval < 0) {
++		pr_info("%s: mnl buf socket recv errno with %d: %s\n",
++				__func__, errno, strerror(errno));
++		*result = errno;
++		return -1;
++	}
++
++	*result = 0;
++	return 0;
++}
+-- 
+2.33.0
+
diff -Nur criu/0010-nftables-implement-nft-api-for-tcp.patch obs_criu/0010-nftables-implement-nft-api-for-tcp.patch
--- criu/0010-nftables-implement-nft-api-for-tcp.patch	1970-01-01 08:00:00.000000000 +0800
+++ obs_criu/0010-nftables-implement-nft-api-for-tcp.patch	2022-10-17 09:36:26.000000000 +0800
@@ -0,0 +1,1011 @@
+From e2ce779838ce1e93e3a0012901165e60a4586ae9 Mon Sep 17 00:00:00 2001
+From: Jingxian He <hejingxian@huawei.com>
+Date: Fri, 14 Oct 2022 16:23:13 +0800
+Subject: [PATCH 4/6] nftables-implement-nft-api-for-tcp
+
+Signed-off-by: fu.lin <fu.lin10@huawei.com>
+---
+ criu/Makefile.crtools   |   1 +
+ criu/include/nftables.h | 138 +++++++
+ criu/nftables.c         | 823 ++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 962 insertions(+)
+ create mode 100644 criu/nftables.c
+
+diff --git a/criu/Makefile.crtools b/criu/Makefile.crtools
+index d2088bb..204924e 100644
+--- a/criu/Makefile.crtools
++++ b/criu/Makefile.crtools
+@@ -90,6 +90,7 @@ obj-y			+= pie-util-vdso.o
+ obj-y			+= vdso.o
+ obj-y			+= timens.o
+ obj-y			+= mnl.o
++obj-y			+= nftables.o
+ obj-$(CONFIG_HAS_LIBBPF)	+= bpfmap.o
+ obj-$(CONFIG_COMPAT)	+= pie-util-vdso-elf32.o
+ CFLAGS_pie-util-vdso-elf32.o	+= -DCONFIG_VDSO_32
+diff --git a/criu/include/nftables.h b/criu/include/nftables.h
+index 0bdab31..3b51a3d 100644
+--- a/criu/include/nftables.h
++++ b/criu/include/nftables.h
+@@ -3,6 +3,99 @@
+ 
+ #include <libmnl/libmnl.h>
+ 
++#include <libnftnl/table.h>
++#include <libnftnl/chain.h>
++#include <libnftnl/set.h>
++#include <libnftnl/rule.h>
++#include <libnftnl/expr.h>
++
++#define construct_buf(buf, type, family, flags, seq, payload, cb_prefix)	\
++	({	\
++		struct nlmsghdr *_nlh;	\
++		\
++		_nlh = nftnl_##cb_prefix##_nlmsg_build_hdr((buf),	\
++					(type), (family), (flags), (seq));	\
++		nftnl_##cb_prefix##_nlmsg_build_payload(_nlh, (payload));	\
++		nftnl_##cb_prefix##_free((payload));	\
++		_nlh;	\
++	})
++
++#define construct_table_buf(buf, type, family, flags, seq, payload)	\
++		construct_buf((buf), (type), (family), (flags), (seq),	\
++				(payload), table)
++
++#define construct_chain_buf(buf, type, family, flags, seq, payload)	\
++		construct_buf((buf), (type), (family), (flags), (seq),	\
++				(payload), chain)
++
++#define construct_batch(batch, type, family, flags, seq, payload, cb_prefix)	\
++	{	\
++		struct nlmsghdr *_nlh;	\
++		\
++		_nlh = nftnl_##cb_prefix##_nlmsg_build_hdr(	\
++					mnl_nlmsg_batch_current(batch),	\
++					(type), (family), (flags), (seq));	\
++		nftnl_##cb_prefix##_nlmsg_build_payload(_nlh, (payload));	\
++		nftnl_##cb_prefix##_free((payload));	\
++		mnl_nlmsg_batch_next((batch));	\
++	}
++
++#define construct_table_batch(batch, type, family, flags, seq, payload)	\
++		construct_batch((batch), (type), (family), (flags), (seq),	\
++				(payload), table)
++
++#define construct_chain_batch(batch, type, family, flags, seq, payload)	\
++		construct_batch((batch), (type), (family), (flags), (seq),	\
++				(payload), chain)
++
++#define construct_set_batch(batch, type, family, flags, seq, payload)	\
++		construct_batch((batch), (type), (family), (flags), (seq),	\
++				(payload), set)
++
++#define construct_rule_batch(batch, type, family, flags, seq, payload)	\
++		construct_batch((batch), (type), (family), (flags), (seq),	\
++				(payload), rule)
++
++#define construct_set_elems_batch(batch, type, family, flags, seq, payload)	\
++	{	\
++		struct nlmsghdr *_nlh;	\
++		\
++		_nlh = nftnl_nlmsg_build_hdr(	\
++					mnl_nlmsg_batch_current(batch),	\
++					(type), (family), (flags), (seq));	\
++		nftnl_set_elems_nlmsg_build_payload(_nlh, (payload));	\
++		nftnl_set_free((payload));	\
++		mnl_nlmsg_batch_next((batch));	\
++	}
++
++#define TABLE_NAME	"filter"
++#define INPUT_CHAIN_NAME	"criu-input"
++#define OUTPUT_CHAIN_NAME	"criu-output"
++#define INPUT_IPV4_SET_NAME	"criu-input-ipv4-blacklist-%d"
++#define INPUT_IPV6_SET_NAME	"criu-input-ipv6-blacklist-%d"
++#define OUTPUT_IPV4_SET_NAME	"criu-output-ipv4-blacklist-%d"
++#define OUTPUT_IPV6_SET_NAME	"criu-output-ipv6-blacklist-%d"
++
++/* set key type, see nftables/include/datatypes.h
++ * The rule of the datatype calculation:
++ *   Each type occupies 6 bits, type:
++ *   - ipaddr: 7, 4 bytes
++ *   - ip6addr: 8, 16 types
++ *   - inet_service: 13, 2 bytes (pading to 4 bytes)
++ *
++ *   0x1cd1cd: 0b 000111 001101 000111 001101
++ *   0x20d20d: 0b 001000 001101 001000 001101
++ */
++#define INET_SERVICE_LEN	2
++#define IPADDR_LEN	4
++#define IP6ADDR_LEN	16
++#define div_round_up(n, d)	(((n) + (d) - 1) / (d))
++
++#define IPv4_KEY_TYPE	0x1cd1cd
++#define IPv4_KEY_LEN	div_round_up(IPADDR_LEN + INET_SERVICE_LEN, 4) * 4 * 2
++#define IPv6_KEY_TYPE	0x20d20d
++#define IPv6_KEY_LEN	div_round_up(IP6ADDR_LEN + INET_SERVICE_LEN, 4) * 4 * 2
++
+ struct mnl_params {
+ 	struct mnl_socket *nl;
+ 	char *buf;
+@@ -25,4 +118,49 @@ int mnl_common(mnl_func_t mnl_cb, void *arg1, void *arg2);
+ int mnl_batch_send_and_recv(struct mnl_params *mnl_params, batch_func_t cb, void *args, int *result);
+ int mnl_buf_send_and_recv(struct mnl_params *mnl_params, buf_func_t cb, void *args, int *result);
+ 
++struct nft_chain_params {
++	char *name;
++	uint32_t hooknum;
++	char *type;
++	uint32_t prio;
++	uint32_t policy;
++};
++
++struct nft_set_params {
++	char name[128];
++	uint32_t id;
++	uint32_t datatype;
++	uint32_t key_len;
++};
++
++struct nft_rule_params {
++	char *chain_name;
++	char set_name[128];
++	uint32_t mark;
++	uint16_t mark_op;
++	uint32_t nfproto;
++	uint8_t l4proto;
++	unsigned int stmt;
++	bool ipv6;
++};
++
++struct nft_set_elem_params {
++	char set_name[128];
++	char data[40];
++	size_t data_len;
++};
++
++struct nf_conn_params {
++	uint8_t family;
++	uint32_t *src_addr;
++	uint16_t src_port;
++	uint32_t *dst_addr;
++	uint16_t dst_port;
++	bool lock;
++	pid_t tree_id;
++};
++
++struct inet_sk_desc;
++int nft_connection_switch(struct inet_sk_desc *sk, bool lock, pid_t tree_id);
++
+ #endif /* __CR_NFTABLES_H__ */
+diff --git a/criu/nftables.c b/criu/nftables.c
+new file mode 100644
+index 0000000..57774e6
+--- /dev/null
++++ b/criu/nftables.c
+@@ -0,0 +1,823 @@
++#include <libmnl/libmnl.h>
++#include <stddef.h>
++#include <string.h>
++#include <sys/socket.h>
++#include <time.h>
++
++#include <netinet/in.h>
++#include <arpa/inet.h>
++
++#include <linux/netfilter.h>
++#include <linux/netfilter_ipv4.h>
++#include <linux/netfilter/nf_tables.h>
++#include <linux/if_ether.h>
++#include <linux/ip.h>
++#include <linux/ipv6.h>
++
++#include "sk-inet.h"
++#include "nftables.h"
++
++#include "../soccr/soccr.h"
++
++#include "log.h"
++
++static struct nftnl_table *setup_table(uint8_t family, const char *table)
++{
++	struct nftnl_table *t;
++
++	t = nftnl_table_alloc();
++	if (t == NULL)
++		return NULL;
++
++	nftnl_table_set_u32(t, NFTNL_TABLE_FAMILY, family);
++	if (nftnl_table_set_str(t, NFTNL_TABLE_NAME, table) < 0)
++		goto err;
++
++	return t;
++err:
++	nftnl_table_free(t);
++	return NULL;
++}
++
++static struct nftnl_chain *setup_chain(const char *table,
++				       struct nft_chain_params *params,
++				       bool create)
++{
++	struct nftnl_chain *c;
++
++	c = nftnl_chain_alloc();
++	if (c == NULL)
++		return NULL;
++
++	if (nftnl_chain_set_str(c, NFTNL_CHAIN_TABLE, table) < 0)
++		goto err;
++	if (nftnl_chain_set_str(c, NFTNL_CHAIN_NAME, params->name) < 0)
++		goto err;
++	if (create) {
++		nftnl_chain_set_u32(c, NFTNL_CHAIN_HOOKNUM, params->hooknum);
++		if (nftnl_chain_set_str(c, NFTNL_CHAIN_TYPE, params->type) < 0)
++			goto err;
++		nftnl_chain_set_u32(c, NFTNL_CHAIN_PRIO, params->prio);
++		nftnl_chain_set_u32(c, NFTNL_CHAIN_POLICY, params->policy);
++	}
++
++	return c;
++err:
++	nftnl_chain_free(c);
++	return NULL;
++}
++
++static struct nftnl_set *setup_set(uint8_t family, const char *table,
++				   struct nft_set_params *params,
++				   bool create)
++{
++	struct nftnl_set *s;
++
++	s = nftnl_set_alloc();
++	if (s == NULL)
++		return NULL;
++
++	if (nftnl_set_set_str(s, NFTNL_SET_TABLE, table) < 0)
++		goto err;
++	if (nftnl_set_set_str(s, NFTNL_SET_NAME, params->name) < 0)
++		goto err;
++	if (create) {
++		nftnl_set_set_u32(s, NFTNL_SET_FAMILY, family);
++		nftnl_set_set_u32(s, NFTNL_SET_ID, params->id);
++
++		nftnl_set_set_u32(s, NFTNL_SET_KEY_TYPE, params->datatype);
++		nftnl_set_set_u32(s, NFTNL_SET_KEY_LEN, params->key_len);
++	}
++
++	return s;
++err:
++	nftnl_set_free(s);
++	return NULL;
++}
++
++static int add_mark(struct nftnl_rule *r, uint32_t meta_key, enum nft_registers dreg)
++{
++	struct nftnl_expr *e;
++
++	e = nftnl_expr_alloc("meta");
++	if (e == NULL)
++		return -1;
++
++	nftnl_expr_set_u32(e, NFTNL_EXPR_META_KEY, meta_key);
++	nftnl_expr_set_u32(e, NFTNL_EXPR_META_DREG, dreg);
++
++	nftnl_rule_add_expr(r, e);
++
++	return 0;
++}
++
++static int add_proto(struct nftnl_rule *r, enum nft_registers dreg)
++{
++	struct nftnl_expr *e;
++
++	e = nftnl_expr_alloc("meta");
++	if (e == NULL)
++		return -1;
++
++	nftnl_expr_set_u32(e, NFTNL_EXPR_META_KEY, NFT_META_L4PROTO);
++	nftnl_expr_set_u32(e, NFTNL_EXPR_META_DREG, dreg);
++
++	nftnl_rule_add_expr(r, e);
++
++	return 0;
++}
++
++static int add_payload(struct nftnl_rule *r, uint32_t base, uint32_t dreg,
++		       uint32_t offset, uint32_t len)
++{
++	struct nftnl_expr *e;
++
++	e = nftnl_expr_alloc("payload");
++	if (e == NULL)
++		return -1;
++
++	nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_BASE, base);
++	nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_DREG, dreg);
++	nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_OFFSET, offset);
++	nftnl_expr_set_u32(e, NFTNL_EXPR_PAYLOAD_LEN, len);
++
++	nftnl_rule_add_expr(r, e);
++
++	return 0;
++}
++
++static int add_cmp(struct nftnl_rule *r, enum nft_registers sreg, uint32_t op,
++		   const void *data, uint32_t data_len)
++{
++	struct nftnl_expr *e;
++
++	e = nftnl_expr_alloc("cmp");
++	if (e == NULL)
++		return -1;
++
++	nftnl_expr_set_u32(e, NFTNL_EXPR_CMP_SREG, sreg);
++	nftnl_expr_set_u32(e, NFTNL_EXPR_CMP_OP, op);
++	nftnl_expr_set(e, NFTNL_EXPR_CMP_DATA, data, data_len);
++
++	nftnl_rule_add_expr(r, e);
++
++	return 0;
++}
++
++static int add_lookup(struct nftnl_rule *r, enum nft_registers sreg,
++			const char *set)
++{
++	struct nftnl_expr *e;
++
++	e = nftnl_expr_alloc("lookup");
++	if (e == NULL)
++		return -1;
++
++	if (nftnl_expr_set_str(e, NFTNL_EXPR_LOOKUP_SET, set) < 0)
++		goto err;
++	nftnl_expr_set_u32(e, NFTNL_EXPR_LOOKUP_SREG, sreg);
++
++	nftnl_rule_add_expr(r, e);
++
++	return 0;
++err:
++	nftnl_expr_free(e);
++	return -1;
++}
++
++static int add_counter(struct nftnl_rule *r)
++{
++	struct nftnl_expr *e;
++
++	e = nftnl_expr_alloc("counter");
++	if (e == NULL)
++		return -1;
++
++	nftnl_rule_add_expr(r, e);
++
++	return 0;
++}
++
++static int add_verdict(struct nftnl_rule *r, const char *chain, int verdict)
++{
++	struct nftnl_expr *e;
++
++	e = nftnl_expr_alloc("immediate");
++	if (e == NULL)
++		return -1;
++
++	nftnl_expr_set_u32(e, NFTNL_EXPR_IMM_DREG, NFT_REG_VERDICT);
++	nftnl_expr_set_u32(e, NFTNL_EXPR_IMM_VERDICT, verdict);
++
++	nftnl_rule_add_expr(r, e);
++
++	return 0;
++}
++
++static int __setup_rule(struct nftnl_rule *r, struct nft_rule_params *params)
++{
++	/* meta nfproto == <nfproto> */
++	if (add_mark(r, NFT_META_PROTOCOL, NFT_REG32_00) < 0)
++		return -1;
++	if (add_cmp(r, NFT_REG32_00, NFT_CMP_EQ, &params->nfproto, sizeof(uint32_t))< 0)
++		return -1;
++
++	/* meta l4proto == <l4proto> */
++	if (add_proto(r, NFT_REG32_00) < 0)
++		return -1;
++	if (add_cmp(r, NFT_REG32_00, NFT_CMP_EQ, &params->l4proto, sizeof(uint8_t)) < 0)
++		return -1;
++
++	/* ip saddr . sport . daddr . dport @<set> */
++	if (params->ipv6 == false) {
++		if (add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG32_00,
++				offsetof(struct iphdr, saddr), IPADDR_LEN) < 0)
++			return -1;
++		if (add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG32_01,
++				offsetof(struct tcphdr, source), INET_SERVICE_LEN) < 0)
++			return -1;
++		if (add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG32_02,
++				offsetof(struct iphdr, daddr), IPADDR_LEN) < 0)
++			return -1;
++		if (add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG32_03,
++				offsetof(struct tcphdr, dest), INET_SERVICE_LEN) < 0)
++			return -1;
++
++		if (add_lookup(r, NFT_REG32_00, params->set_name) < 0)
++			return -1;
++	} else {
++		if (add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG32_00,
++				offsetof(struct ipv6hdr, saddr), IP6ADDR_LEN) < 0)
++			return -1;
++		if (add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG32_04,
++				offsetof(struct tcphdr, source), INET_SERVICE_LEN) < 0)
++			return -1;
++		if (add_payload(r, NFT_PAYLOAD_NETWORK_HEADER, NFT_REG32_05,
++				offsetof(struct ipv6hdr, daddr), IP6ADDR_LEN) < 0)
++			return -1;
++		if (add_payload(r, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG32_09,
++				offsetof(struct tcphdr, dest), INET_SERVICE_LEN) < 0)
++			return -1;
++
++		if (add_lookup(r, NFT_REG32_00, params->set_name) < 0)
++			return -1;
++	}
++
++	/* counter */
++	if (add_counter(r) < 0)
++		return -1;
++
++	return 0;
++}
++
++static struct nftnl_rule *setup_rule(uint8_t family, const char *table,
++				     struct nft_rule_params *params,
++				     bool create, bool ns)
++{
++	struct nftnl_rule *r = NULL;
++
++	r = nftnl_rule_alloc();
++	if (r == NULL)
++		return NULL;
++
++	if (nftnl_rule_set_str(r, NFTNL_RULE_TABLE, table) < 0)
++		goto err;
++	nftnl_rule_set_u32(r, NFTNL_RULE_FAMILY, family);
++	if (nftnl_rule_set_str(r, NFTNL_RULE_CHAIN, params->chain_name) < 0)
++		goto err;
++
++	if (params->mark != 0) {
++		/* meta mark != <mark> */
++		if (add_mark(r, NFT_META_MARK, NFT_REG32_00) < 0)
++			goto err;
++		if (add_cmp(r, NFT_REG32_00, params->mark_op, &params->mark, sizeof(uint32_t)) < 0)
++			goto err;
++	}
++
++	if (!ns && __setup_rule(r, params) < 0)
++			goto err;
++
++	/* drop */
++	if (add_verdict(r, params->chain_name, params->stmt) < 0)
++		goto err;
++
++	return r;
++
++err:
++	nftnl_rule_free(r);
++	return NULL;
++}
++
++static struct nlmsghdr *nft_table_detect(struct mnl_params *mnl_params, void *args)
++{
++	struct nftnl_table *table;
++
++	table = setup_table(NFPROTO_INET, TABLE_NAME);
++	if (table == NULL)
++		return NULL;
++
++	return construct_table_buf(mnl_params->buf, NFT_MSG_GETTABLE, NFPROTO_INET,
++					NLM_F_ACK, mnl_params->seq++, table);
++}
++
++static int nft_table_create(struct mnl_params *mnl_params, void *args)
++{
++	struct nftnl_table *table;
++
++	table = setup_table(NFPROTO_INET, TABLE_NAME);
++	if (table == NULL)
++		return -1;
++
++	construct_table_batch(mnl_params->batch, NFT_MSG_NEWTABLE, NFPROTO_INET,
++			      NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK,
++			      mnl_params->seq++, table);
++
++	return 0;
++}
++
++static int nft_table_prepare(struct mnl_params *mnl_params)
++{
++	int result = 0;
++
++	if (mnl_buf_send_and_recv(mnl_params, nft_table_detect, NULL, &result) == 0)
++		return 0;
++
++	pr_debug("%s: detect table result %d\n", __func__, result);
++
++	if (result == ENOENT &&
++			(mnl_batch_send_and_recv(mnl_params, nft_table_create, NULL, &result) < 0
++				&& (result != 0 && result != EEXIST))) {
++		pr_err("%s: create nftables table failed!\n", __func__);
++		return -1;
++	} else if (result != 0) {
++		pr_err("%s: detect table result %d\n", __func__, -result);
++		return -1;
++	}
++
++	return 0;
++}
++
++static struct nlmsghdr *nft_chain_detect(struct mnl_params *mnl_params, void *args)
++{
++	struct nftnl_chain *chain;
++
++	chain = setup_chain(TABLE_NAME, args, false);
++	if (chain == NULL)
++		return NULL;
++
++	return construct_chain_buf(mnl_params->buf, NFT_MSG_GETCHAIN, NFPROTO_INET,
++					NLM_F_ACK, mnl_params->seq++, chain);
++}
++
++static int nft_chain_create(struct mnl_params *mnl_params, void *args)
++{
++	struct nftnl_chain *chain;
++
++	chain = setup_chain(TABLE_NAME, args, true);
++	if (chain == NULL)
++		return -1;
++
++	construct_chain_batch(mnl_params->batch, NFT_MSG_NEWCHAIN, NFPROTO_INET,
++			      NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK, mnl_params->seq++, chain);
++
++	return 0;
++}
++
++static int nft_chain_prepare_internal(struct mnl_params *mnl_params,
++					   struct nft_chain_params *params)
++{
++	int result = 0;
++
++	if (mnl_buf_send_and_recv(mnl_params, nft_chain_detect, params, &result) == 0)
++		return 0;
++
++	pr_debug("%s: detect chain result %d\n", __func__, result);
++
++	if (result == ENOENT &&
++			(mnl_batch_send_and_recv(mnl_params, nft_chain_create, params, &result) < 0
++				&& (result != 0 && result != EEXIST))) {
++		pr_err("%s: nftables create chain %s failed!\n",
++				__func__, params->name);
++		return -1;
++	} else if (result != 0) {
++		pr_err("%s: detect chain result %d\n", __func__, -result);
++		return -1;
++	}
++
++	return result;
++}
++
++static int nft_chain_prepare(struct mnl_params *mnl_params)
++{
++	struct nft_chain_params params = {
++		.type = "filter",
++		.prio = NF_IP_PRI_FILTER,
++		.policy = NF_ACCEPT,
++	};
++
++	/* prepare ipv4 input chain in filter table */
++	params.name = INPUT_CHAIN_NAME;
++	params.hooknum = NF_INET_LOCAL_IN;
++
++	if (nft_chain_prepare_internal(mnl_params, &params) < 0)
++		return -1;
++
++	/* prepare ipv4 output chain in filter table */
++	params.name = OUTPUT_CHAIN_NAME;
++	params.hooknum = NF_INET_LOCAL_OUT;
++
++	if (nft_chain_prepare_internal(mnl_params, &params) < 0)
++		return -1;
++
++	return 0;
++}
++
++static int nft_set_internal(uint8_t family, struct mnl_params *mnl_params,
++				 struct nft_set_params *params, bool create)
++{
++	struct nftnl_set *set;
++
++	set = setup_set(family, TABLE_NAME, params, create);
++	if (set == NULL)
++		return -1;
++
++	if (create) {
++		construct_set_batch(mnl_params->batch, NFT_MSG_NEWSET, family,
++				    NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK, mnl_params->seq++, set);
++	} else {
++		construct_set_batch(mnl_params->batch, NFT_MSG_DELSET, family,
++				    0, mnl_params->seq++, set);
++	}
++
++	return 0;
++}
++
++static int nft_set_raw(struct mnl_params *mnl_params,
++			    struct mnl_cb_params *args, bool input)
++{
++	const uint32_t set_id_base = input ? 0x12315 : 0x17173;
++	const uint8_t family = NFPROTO_INET;
++	struct nft_set_params params = { 0 };
++	char *set_name;
++	int idx = 0;
++
++	if (!args->ipv6) {
++		params.datatype = IPv4_KEY_TYPE;
++		params.key_len = IPv4_KEY_LEN;
++		idx = 4;
++	} else {
++		params.datatype = IPv6_KEY_TYPE;
++		params.key_len = IPv6_KEY_LEN;
++		idx = 6;
++	}
++
++	if (args->ipv6 && input)
++		set_name = INPUT_IPV6_SET_NAME;
++	else if (args->ipv6 && !input)
++		set_name = OUTPUT_IPV6_SET_NAME;
++	else if (!args->ipv6 && input)
++		set_name = INPUT_IPV4_SET_NAME;
++	else
++		set_name = OUTPUT_IPV4_SET_NAME;
++
++	snprintf(params.name, sizeof(params.name)-1, set_name, args->tree_id);
++	params.id = set_id_base + args->tree_id + idx;
++
++	if (nft_set_internal(family, mnl_params, &params, args->create) < 0) {
++		pr_err("%s: create nftables %s %s set failed!\n", __func__,
++				args->ipv6 ? "ipv6" : "ipv4",
++				input ? "input" : "output");
++		return -1;
++	}
++
++	return 0;
++}
++
++static int nft_set(struct mnl_params *mnl_params, void *args)
++{
++	struct mnl_cb_params *params = args;
++
++	params->ipv6 = false;
++	if (nft_set_raw(mnl_params, params, true) < 0)
++		return -1;
++
++	if (nft_set_raw(mnl_params, params, false) < 0)
++		return -1;
++
++	params->ipv6 = true;
++	if (nft_set_raw(mnl_params, params, true) < 0)
++		return -1;
++
++	if (nft_set_raw(mnl_params, params, false) < 0)
++		return -1;
++
++	return 0;
++}
++
++static int nft_set_common(struct mnl_params *mnl_params, pid_t tree_id, bool create)
++{
++	struct mnl_cb_params params = {
++		.tree_id = tree_id,
++		.create = create,
++	};
++	int result = 0;
++
++	if (create &&
++		(mnl_batch_send_and_recv(mnl_params, nft_set, &params, &result) < 0
++			&& (result != 0 && result != EEXIST))) {
++		pr_err("%s: create set failed!\n", __func__);
++		return -1;
++	} else if (!create &&
++			mnl_batch_send_and_recv(mnl_params, nft_set, &params, NULL) < 0) {
++		pr_err("%s: delete set failed!\n", __func__);
++		return -1;
++	}
++
++	return 0;
++}
++
++static int nft_rule_internal(uint8_t family, struct mnl_params *mnl_params,
++				  struct nft_rule_params *params, bool create)
++{
++	struct nftnl_rule *rule;
++
++	rule = setup_rule(family, TABLE_NAME, params, create, false);
++	if (rule == NULL)
++		return -1;
++
++	if (create) {
++		construct_rule_batch(mnl_params->batch, NFT_MSG_NEWRULE, family,
++				     NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK,
++				     mnl_params->seq++, rule);
++	} else {
++		construct_rule_batch(mnl_params->batch, NFT_MSG_DELRULE, family,
++				     0, mnl_params->seq++, rule);
++	}
++
++	return 0;
++}
++
++static int nft_rule_raw(struct mnl_params *mnl_params, struct mnl_cb_params *args,
++			     struct nft_rule_params *params)
++{
++	char *set_name;
++
++	params->nfproto = params->ipv6 ? htons(ETH_P_IPV6) : htons(ETH_P_IP);
++
++	set_name = params->ipv6 ? INPUT_IPV6_SET_NAME : INPUT_IPV4_SET_NAME;
++	params->chain_name = INPUT_CHAIN_NAME;
++	snprintf(params->set_name, sizeof(params->set_name)-1, set_name, args->tree_id);
++	if (nft_rule_internal(NFPROTO_INET, mnl_params, params, args->create) < 0) {
++		pr_err("%s: create nft %s input rule failed!\n",
++				__func__, params->ipv6 ? "ipv6" : "ipv4");
++		return -1;
++	}
++
++	set_name = params->ipv6 ? OUTPUT_IPV6_SET_NAME : OUTPUT_IPV4_SET_NAME;
++	params->chain_name = OUTPUT_CHAIN_NAME;
++	snprintf(params->set_name, sizeof(params->set_name)-1, set_name, args->tree_id);
++	if (nft_rule_internal(NFPROTO_INET, mnl_params, params, args->create) < 0) {
++		pr_err("%s: create nftables %s output rule failed!\n",
++				__func__, params->ipv6 ? "ipv6" : "ipv4");
++		return -1;
++	}
++
++	return 0;
++}
++
++static int nft_rule(struct mnl_params *mnl_params, void *args)
++{
++	struct nft_rule_params params = {
++		.l4proto = IPPROTO_TCP,
++		.mark = SOCCR_MARK,
++		.mark_op = NFT_CMP_NEQ,
++		.stmt = NF_DROP,
++	};
++
++	params.ipv6 = false;
++	if (nft_rule_raw(mnl_params, args, &params) < 0)
++		return -1;
++
++	params.ipv6 = true;
++	if (nft_rule_raw(mnl_params, args, &params) < 0)
++		return -1;
++
++	return 0;
++}
++
++static int nft_rule_common(struct mnl_params *mnl_params, pid_t tree_id, bool create)
++{
++	struct mnl_cb_params params = {
++		.tree_id = tree_id,
++		.create = create,
++	};
++	int result = 0;
++
++	if (create &&
++		(mnl_batch_send_and_recv(mnl_params, nft_rule, &params, &result) < 0
++			&& (result != 0 && result != EEXIST))) {
++		pr_err("%s: create rule failed!\n", __func__);
++		return -1;
++	} else if (!create &&
++			mnl_batch_send_and_recv(mnl_params, nft_rule, &params, NULL) < 0) {
++		pr_err("%s: delete rule failed!\n", __func__);
++		return -1;
++	}
++
++	return 0;
++}
++
++static int network_prepare_internal(struct mnl_params *params, batch_func_t _, void *args)
++{
++	pid_t tree_id = *(pid_t *)args;
++
++	if (nft_table_prepare(params) < 0)
++		return -1;
++
++	if (nft_chain_prepare(params) < 0)
++		return -1;
++
++	if (nft_set_common(params, tree_id, true) < 0)
++		return -1;
++
++	if (nft_rule_common(params, tree_id, true) < 0)
++		return -1;
++
++	return 0;
++}
++
++int network_prepare(pid_t tree_id)
++{
++	pr_info("Prepare network\n");
++
++	return mnl_common(network_prepare_internal, NULL, &tree_id);
++}
++
++static int network_unprepare_internal(struct mnl_params *params,
++				      batch_func_t _, void *args)
++{
++	pid_t tree_id = *(pid_t *)args;
++
++	if (nft_rule_common(params, tree_id, false) < 0)
++		return -1;
++
++	if (nft_set_common(params, tree_id, false) < 0)
++		return -1;
++
++	return 0;
++}
++
++void network_unprepare(pid_t tree_id)
++{
++	pr_info("Unprepare network\n");
++
++	mnl_common(network_unprepare_internal, NULL, &tree_id);
++}
++
++static int add_set_elem_internal(struct nftnl_set *s, void *data, size_t len)
++{
++	struct nftnl_set_elem *e;
++
++	e = nftnl_set_elem_alloc();
++	if (e == NULL)
++		return -1;
++
++	nftnl_set_elem_set(e, NFTNL_SET_ELEM_KEY, data, len);
++
++	nftnl_set_elem_add(s, e);
++
++	return 0;
++}
++
++static struct nftnl_set *add_set_elem(const char *table, const char *set,
++				      void *data, size_t len)
++{
++	struct nftnl_set *s;
++
++	s = nftnl_set_alloc();
++	if (s == NULL)
++		return NULL;
++
++	if (nftnl_set_set_str(s, NFTNL_SET_TABLE, table) < 0)
++		goto err;
++	if (nftnl_set_set_str(s, NFTNL_SET_NAME, set) < 0)
++		goto err;
++
++	if (add_set_elem_internal(s, data, len) < 0)
++		goto err;
++
++	return s;
++
++err:
++	nftnl_set_free(s);
++	return NULL;
++}
++
++static int nft_set_elem(uint8_t family, struct mnl_params *mnl_param,
++			     struct nft_set_elem_params *elem_param,
++			     bool lock)
++{
++	struct nftnl_set *set;
++
++	set = add_set_elem(TABLE_NAME, elem_param->set_name,
++			   elem_param->data, elem_param->data_len);
++	if (set == NULL)
++		return -1;
++
++	if (lock) {
++		construct_set_elems_batch(mnl_param->batch, NFT_MSG_NEWSETELEM,
++					  family, NLM_F_CREATE|NLM_F_EXCL,
++					  mnl_param->seq++, set);
++	} else {
++		construct_set_elems_batch(mnl_param->batch, NFT_MSG_DELSETELEM,
++					  family, 0, mnl_param->seq++, set);
++	}
++
++	return 0;
++}
++
++static void construct_set_elem_key(void *data, struct nf_conn_params *param, bool output)
++{
++	size_t offset = 0;
++	size_t addr_len = param->family == AF_INET ? IPADDR_LEN : IP6ADDR_LEN;
++
++	memcpy(data+offset, output ? param->src_addr : param->dst_addr, addr_len);
++	offset = addr_len;
++	*(uint32_t *)(data + offset) = htons(output ? param->src_port : param->dst_port);
++	offset += sizeof(uint32_t);
++	memcpy(data+offset, output ? param->dst_addr : param->src_addr, addr_len);
++	offset += addr_len;
++	*(uint32_t *)(data + offset) = htons(output ? param->dst_port : param->src_port);
++}
++
++static int nf_connection_switch_raw(struct mnl_params *mnl_params, void *args)
++{
++	struct nf_conn_params *param = args;
++	char *input_set_name, *output_set_name;
++	struct nft_set_elem_params elem;
++
++	switch (param->family) {
++	case AF_INET:
++		input_set_name = INPUT_IPV4_SET_NAME;
++		output_set_name = OUTPUT_IPV4_SET_NAME;
++		elem.data_len = IPv4_KEY_LEN;
++		break;
++	case AF_INET6:
++		input_set_name = INPUT_IPV6_SET_NAME;
++		output_set_name = OUTPUT_IPV6_SET_NAME;
++		elem.data_len = IPv6_KEY_LEN;
++		break;
++	default:
++		pr_err("Unknown socket family %d\n", param->family);
++		return -1;
++	}
++
++	construct_set_elem_key(elem.data, param, false);
++	snprintf(elem.set_name, sizeof(elem.set_name)-1, input_set_name, param->tree_id);
++	if (nft_set_elem(NFPROTO_INET, mnl_params, &elem, param->lock) < 0)
++		return -1;
++
++	construct_set_elem_key(elem.data, param, true);
++	snprintf(elem.set_name, sizeof(elem.set_name)-1, output_set_name, param->tree_id);
++	if (nft_set_elem(NFPROTO_INET, mnl_params, &elem, param->lock) < 0)
++		return -1;
++
++	return 0;
++}
++
++/* IPv4-Mapped IPv6 Addresses */
++static int ipv6_addr_mapped(uint32_t *addr)
++{
++	return (addr[2] == htonl(0x0000ffff));
++}
++
++int nft_connection_switch(struct inet_sk_desc *sk, bool lock, pid_t tree_id)
++{
++	char sip[INET_ADDR_LEN], dip[INET_ADDR_LEN];
++	struct nf_conn_params param = {
++		.family = sk->sd.family,
++		.src_addr = sk->src_addr,
++		.src_port = sk->src_port,
++		.dst_addr = sk->dst_addr,
++		.dst_port = sk->dst_port,
++		.lock = lock,
++		.tree_id = tree_id,
++	};
++
++	if (param.family == AF_INET6 && ipv6_addr_mapped(param.dst_addr)) {
++		param.family = AF_INET;
++		param.src_addr = &param.src_addr[3];
++		param.dst_addr = &param.dst_addr[3];
++	}
++
++	if (!inet_ntop(param.family, (void *)param.src_addr, sip, INET_ADDR_LEN) ||
++			!inet_ntop(param.family, (void *)param.dst_addr, dip, INET_ADDR_LEN)) {
++		pr_perror("nf: Can't translate ip addr");
++		return -1;
++	}
++
++	pr_info("%s %s:%d - %s:%d connection\n", lock ? "Locked" : "Unlocked",
++			sip, (int)param.src_port, dip, (int)param.dst_port);
++
++	return mnl_sendmsg(nf_connection_switch_raw, &param);
++}
+-- 
+2.33.0
+
diff -Nur criu/0011-nftables-implement-nft-api-for-lock-net-ns.patch obs_criu/0011-nftables-implement-nft-api-for-lock-net-ns.patch
--- criu/0011-nftables-implement-nft-api-for-lock-net-ns.patch	1970-01-01 08:00:00.000000000 +0800
+++ obs_criu/0011-nftables-implement-nft-api-for-lock-net-ns.patch	2022-10-17 09:36:26.000000000 +0800
@@ -0,0 +1,146 @@
+From 72eb8ace01dbaa26282ef7228c0ba22eb6618d20 Mon Sep 17 00:00:00 2001
+From: Jingxian He <hejingxian@huawei.com>
+Date: Fri, 14 Oct 2022 16:23:40 +0800
+Subject: [PATCH 5/6] nftables-implement-nft-api-for-lock-net-ns
+
+Signed-off-by: fu.lin <fu.lin10@huawei.com>
+---
+ criu/include/nftables.h |   2 +
+ criu/nftables.c         | 112 ++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 114 insertions(+)
+
+diff --git a/criu/include/nftables.h b/criu/include/nftables.h
+index 3b51a3d..e462919 100644
+--- a/criu/include/nftables.h
++++ b/criu/include/nftables.h
+@@ -162,5 +162,7 @@ struct nf_conn_params {
+ 
+ struct inet_sk_desc;
+ int nft_connection_switch(struct inet_sk_desc *sk, bool lock, pid_t tree_id);
++int nft_lock(void);
++int nft_unlock(void);
+ 
+ #endif /* __CR_NFTABLES_H__ */
+diff --git a/criu/nftables.c b/criu/nftables.c
+index 57774e6..817f157 100644
+--- a/criu/nftables.c
++++ b/criu/nftables.c
+@@ -821,3 +821,115 @@ int nft_connection_switch(struct inet_sk_desc *sk, bool lock, pid_t tree_id)
+ 
+ 	return mnl_sendmsg(nf_connection_switch_raw, &param);
+ }
++
++static int nft_ns_rule_internal(uint8_t family, struct mnl_params *mnl_params,
++				struct nft_rule_params *params, bool create)
++{
++	struct nftnl_rule *rule;
++
++	rule = setup_rule(family, TABLE_NAME, params, create, true);
++	if (rule == NULL)
++		return -1;
++
++	if (create) {
++		construct_rule_batch(mnl_params->batch, NFT_MSG_NEWRULE, family,
++				     NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK,
++				     mnl_params->seq++, rule);
++	} else {
++		construct_rule_batch(mnl_params->batch, NFT_MSG_DELRULE, family,
++				     0, mnl_params->seq++, rule);
++	}
++
++	return 0;
++}
++
++static int nft_ns_rule_raw(struct mnl_params *mnl_params, struct mnl_cb_params *args,
++			   struct nft_rule_params *params)
++{
++	params->chain_name = INPUT_CHAIN_NAME;
++	if (nft_ns_rule_internal(NFPROTO_INET, mnl_params, params, args->create) < 0) {
++		pr_err("%s: create nft input rule failed!\n", __func__);
++		return -1;
++	}
++
++	params->chain_name = OUTPUT_CHAIN_NAME;
++	if (nft_ns_rule_internal(NFPROTO_INET, mnl_params, params, args->create) < 0) {
++		pr_err("%s: create nft output rule failed!\n", __func__);
++		return -1;
++	}
++
++	return 0;
++}
++
++static int nft_ns_rule(struct mnl_params *mnl_params, void *args)
++{
++	struct nft_rule_params params = { 0 };
++
++	params.mark = 0;
++	params.mark_op = NFT_CMP_EQ;
++	params.stmt = NF_DROP;
++	if (nft_ns_rule_raw(mnl_params, args, &params) < 0)
++		return -1;
++
++	params.mark = SOCCR_MARK;
++
++	params.stmt = NF_ACCEPT;
++	if (nft_ns_rule_raw(mnl_params, args, &params) < 0)
++		return -1;
++
++	return 0;
++}
++
++static int nft_ns_rule_common(struct mnl_params *mnl_params, bool create)
++{
++	struct mnl_cb_params params = {
++		.create = create,
++	};
++	int result = 0;
++
++	if (create &&
++		(mnl_batch_send_and_recv(mnl_params, nft_ns_rule, &params, &result) < 0
++		 && (result != 0 && result != EEXIST))) {
++		pr_err("%s: crete ns rule failed!\n", __func__);
++		return -1;
++	} else if (!create &&
++			(mnl_batch_send_and_recv(mnl_params, nft_ns_rule, &params, NULL) < 0)) {
++		pr_err("%s: delete ns rule failed!\n", __func__);
++		return -1;
++	}
++
++	return 0;
++}
++
++static int network_lock_internal(struct mnl_params *params,
++				 batch_func_t _, void *args)
++{
++	if (nft_table_prepare(params) < 0)
++		return -1;
++
++	if (nft_chain_prepare(params) < 0)
++		return -1;
++
++	if (nft_ns_rule_common(params, true) < 0)
++		return -1;
++
++	return 0;
++}
++
++int nft_lock(void)
++{
++	return mnl_common(network_lock_internal, NULL, NULL);
++}
++
++static int network_unlock_internal(struct mnl_params *params, batch_func_t _,
++				   void *args)
++{
++	if (nft_ns_rule_common(params, false) < 0)
++		return -1;
++	return 0;
++}
++
++int nft_unlock(void)
++{
++	return mnl_common(network_unlock_internal, NULL, NULL);
++}
+-- 
+2.33.0
+
diff -Nur criu/0012-criu-switch-to-nftables-api.patch obs_criu/0012-criu-switch-to-nftables-api.patch
--- criu/0012-criu-switch-to-nftables-api.patch	1970-01-01 08:00:00.000000000 +0800
+++ obs_criu/0012-criu-switch-to-nftables-api.patch	2022-10-17 09:36:27.000000000 +0800
@@ -0,0 +1,333 @@
+From 3a5c545bda9abb6f9c269be85a3fe2f5d147f7c6 Mon Sep 17 00:00:00 2001
+From: Jingxian He <hejingxian@huawei.com>
+Date: Fri, 14 Oct 2022 16:26:54 +0800
+Subject: [PATCH 6/6] criu-switch-to-nftables-api
+
+usage: criu --use-nft
+
+Signed-off-by: fu.lin <fu.lin10@huawei.com>
+Signed-off-by: Jingxian He <hejingxian@huawei.com>
+---
+ criu/config.c             |  1 +
+ criu/cr-dump.c            |  4 ++--
+ criu/cr-restore.c         |  2 +-
+ criu/crtools.c            |  1 +
+ criu/include/cr_options.h |  1 +
+ criu/include/net.h        |  6 ++++--
+ criu/include/netfilter.h  |  7 +++++--
+ criu/include/sk-inet.h    |  2 +-
+ criu/kerndat.c            |  3 ++-
+ criu/net.c                | 37 +++++++++++++++++++++++++++----------
+ criu/netfilter.c          | 14 +++++++++++---
+ criu/sk-tcp.c             | 14 +++++++-------
+ 12 files changed, 63 insertions(+), 29 deletions(-)
+
+diff --git a/criu/config.c b/criu/config.c
+index a5bcf10..3cccdbb 100644
+--- a/criu/config.c
++++ b/criu/config.c
+@@ -544,6 +544,7 @@ int parse_options(int argc, char **argv, bool *usage_error,
+ 		BOOL_OPT("with-cpu-affinity", &opts.with_cpu_affinity),
+ 		BOOL_OPT("pin-memory", &opts.pin_memory),
+ 		BOOL_OPT("use-fork-pid", &opts.use_fork_pid),
++		BOOL_OPT("use-nft", &opts.use_nft),
+ 		{ },
+ 	};
+ 
+diff --git a/criu/cr-dump.c b/criu/cr-dump.c
+index f078c27..1188556 100644
+--- a/criu/cr-dump.c
++++ b/criu/cr-dump.c
+@@ -1754,7 +1754,7 @@ static int cr_dump_finish(int ret)
+ 	 *    start rollback procedure and cleanup everything.
+ 	 */
+ 	if (ret || post_dump_ret || opts.final_state == TASK_ALIVE) {
+-		network_unlock();
++		network_unlock(opts.tree_id);
+ 		delete_link_remaps();
+ 		clean_cr_time_mounts();
+ 	}
+@@ -1869,7 +1869,7 @@ int cr_dump_tasks(pid_t pid)
+ 	if (collect_pstree_ids())
+ 		goto err;
+ 
+-	if (network_lock())
++	if (network_lock(opts.tree_id))
+ 		goto err;
+ 
+ 	if (collect_file_locks())
+diff --git a/criu/cr-restore.c b/criu/cr-restore.c
+index 6977443..d20937c 100644
+--- a/criu/cr-restore.c
++++ b/criu/cr-restore.c
+@@ -2406,7 +2406,7 @@ skip_ns_bouncing:
+ 		goto out_kill;
+ 
+ 	/* Unlock network before disabling repair mode on sockets */
+-	network_unlock();
++	network_unlock(vpid(init));
+ 
+ 	/*
+ 	 * Stop getting sigchld, after we resume the tasks they
+diff --git a/criu/crtools.c b/criu/crtools.c
+index c33902a..d683dc7 100644
+--- a/criu/crtools.c
++++ b/criu/crtools.c
+@@ -444,6 +444,7 @@ usage:
+ "  --with-cpu-affinity Allow to restore cpu affinity. Only for hosts with\n"
+ "			same cpu quantity.\n"
+ "  --use-fork-pid       Allow to restore task pid by setting fork pid of task struct.\n"
++"  --use-nft             Use nft API instead of iptables cmd in network locking\n"
+ "\n"
+ "Check options:\n"
+ "  Without options, \"criu check\" checks availability of absolutely required\n"
+diff --git a/criu/include/cr_options.h b/criu/include/cr_options.h
+index 7fad678..9b76969 100644
+--- a/criu/include/cr_options.h
++++ b/criu/include/cr_options.h
+@@ -178,6 +178,7 @@ struct cr_options {
+ 	int			with_cpu_affinity;
+ 	int			pin_memory;
+ 	int			use_fork_pid;
++	int			use_nft;
+ };
+ 
+ extern struct cr_options opts;
+diff --git a/criu/include/net.h b/criu/include/net.h
+index 0a556f3..f18912a 100644
+--- a/criu/include/net.h
++++ b/criu/include/net.h
+@@ -29,8 +29,10 @@ struct veth_pair {
+ 
+ extern int collect_net_namespaces(bool for_dump);
+ 
+-extern int network_lock(void);
+-extern void network_unlock(void);
++extern int network_prepare(pid_t tree_id);
++extern void network_unprepare(pid_t tree_id);
++extern int network_lock(pid_t tree_id);
++extern void network_unlock(pid_t tree_id);
+ extern int network_lock_internal(void);
+ 
+ extern struct ns_desc net_ns_desc;
+diff --git a/criu/include/netfilter.h b/criu/include/netfilter.h
+index 35ef262..c92762c 100644
+--- a/criu/include/netfilter.h
++++ b/criu/include/netfilter.h
+@@ -1,9 +1,12 @@
+ #ifndef __CR_NETFILTER_H__
+ #define __CR_NETFILTER_H__
+ 
++#include <sys/types.h>
++#include <stdbool.h>
++
+ struct inet_sk_desc;
+-extern int nf_lock_connection(struct inet_sk_desc *);
+-extern int nf_unlock_connection(struct inet_sk_desc *);
++extern int nf_lock_connection(struct inet_sk_desc *, pid_t, bool);
++extern int nf_unlock_connection(struct inet_sk_desc *, bool);
+ 
+ struct inet_sk_info;
+ extern int nf_unlock_connection_info(struct inet_sk_info *);
+diff --git a/criu/include/sk-inet.h b/criu/include/sk-inet.h
+index dec67ca..66cf2dd 100644
+--- a/criu/include/sk-inet.h
++++ b/criu/include/sk-inet.h
+@@ -81,7 +81,7 @@ static inline void tcp_repair_off(int fd)
+ 
+ extern void tcp_locked_conn_add(struct inet_sk_info *);
+ extern void rst_unlock_tcp_connections(void);
+-extern void cpt_unlock_tcp_connections(void);
++extern void cpt_unlock_tcp_connections(bool);
+ 
+ extern int dump_one_tcp(int sk, struct inet_sk_desc *sd, SkOptsEntry *soe);
+ extern int restore_one_tcp(int sk, struct inet_sk_info *si);
+diff --git a/criu/kerndat.c b/criu/kerndat.c
+index b2c47c5..59570a2 100644
+--- a/criu/kerndat.c
++++ b/criu/kerndat.c
+@@ -1065,7 +1065,8 @@ int kerndat_init(void)
+ 	memset(&kdat, 0, sizeof(kdat));
+ 
+ 	preload_socket_modules();
+-	preload_netfilter_modules();
++	if (!opts.use_nft)
++		preload_netfilter_modules();
+ 
+ 	if (check_pagemap()) {
+ 		pr_err("check_pagemap failed when initializing kerndat.\n");
+diff --git a/criu/net.c b/criu/net.c
+index 4f1f7d4..4007b16 100644
+--- a/criu/net.c
++++ b/criu/net.c
+@@ -45,6 +45,7 @@
+ #include "util.h"
+ #include "external.h"
+ #include "fdstore.h"
++#include "nftables.h"
+ 
+ #include "protobuf.h"
+ #include "images/netdev.pb-c.h"
+@@ -2868,9 +2869,13 @@ int network_lock_internal(void)
+ 		return -1;
+ 
+ 
+-	ret |= iptables_restore(false, conf, sizeof(conf) - 1);
+-	if (kdat.ipv6)
+-		ret |= iptables_restore(true, conf, sizeof(conf) - 1);
++	if (opts.use_nft)
++		ret = nft_lock();
++	else {
++		ret |= iptables_restore(false, conf, sizeof(conf) - 1);
++		if (kdat.ipv6)
++			ret |= iptables_restore(true, conf, sizeof(conf) - 1);
++	}
+ 
+ 	if (ret)
+ 		pr_err("Locking network failed: iptables-restore returned %d. "
+@@ -2898,9 +2903,13 @@ static int network_unlock_internal(void)
+ 		return -1;
+ 
+ 
+-	ret |= iptables_restore(false, conf, sizeof(conf) - 1);
+-	if (kdat.ipv6)
+-		ret |= iptables_restore(true, conf, sizeof(conf) - 1);
++	if (opts.use_nft)
++		ret = nft_unlock();
++	else {
++		ret |= iptables_restore(false, conf, sizeof(conf) - 1);
++		if (kdat.ipv6)
++			ret |= iptables_restore(true, conf, sizeof(conf) - 1);
++	}
+ 
+ 	if (restore_ns(nsret, &net_ns_desc))
+ 		ret = -1;
+@@ -2908,10 +2917,13 @@ static int network_unlock_internal(void)
+ 	return ret;
+ }
+ 
+-int network_lock(void)
++int network_lock(pid_t tree_id)
+ {
+ 	pr_info("Lock network\n");
+ 
++	if (opts.use_nft && opts.tcp_established_ok && network_prepare(tree_id) < 0)
++		return -1;
++
+ 	/* Each connection will be locked on dump */
+ 	if  (!(root_ns_mask & CLONE_NEWNET))
+ 		return 0;
+@@ -2922,12 +2934,17 @@ int network_lock(void)
+ 	return network_lock_internal();
+ }
+ 
+-void network_unlock(void)
++void network_unlock(pid_t tree_id)
+ {
+ 	pr_info("Unlock network\n");
+ 
+-	cpt_unlock_tcp_connections();
+-	rst_unlock_tcp_connections();
++	if (opts.use_nft && opts.tcp_established_ok)
++		network_unprepare(tree_id);
++
++	cpt_unlock_tcp_connections(opts.use_nft);
++
++	if (!opts.use_nft)
++		rst_unlock_tcp_connections();
+ 
+ 	if (root_ns_mask & CLONE_NEWNET) {
+ 		run_scripts(ACT_NET_UNLOCK);
+diff --git a/criu/netfilter.c b/criu/netfilter.c
+index 368651c..b2ec7ed 100644
+--- a/criu/netfilter.c
++++ b/criu/netfilter.c
+@@ -15,6 +15,8 @@
+ #include "sk-inet.h"
+ #include "kerndat.h"
+ 
++#include "nftables.h"
++
+ static char buf[512];
+ 
+ /*
+@@ -129,13 +131,19 @@ static int nf_connection_switch(struct inet_sk_desc *sk, bool lock)
+ 	return ret;
+ }
+ 
+-int nf_lock_connection(struct inet_sk_desc *sk)
++int nf_lock_connection(struct inet_sk_desc *sk, pid_t tree_id, bool use_nft)
+ {
+-	return nf_connection_switch(sk, true);
++	if (use_nft)
++		return nft_connection_switch(sk, true, tree_id);
++	else
++		return nf_connection_switch(sk, true);
+ }
+ 
+-int nf_unlock_connection(struct inet_sk_desc *sk)
++int nf_unlock_connection(struct inet_sk_desc *sk, bool use_nft)
+ {
++	if (use_nft)
++		return 0;
++
+ 	return nf_connection_switch(sk, false);
+ }
+ 
+diff --git a/criu/sk-tcp.c b/criu/sk-tcp.c
+index 0409e22..11557f5 100644
+--- a/criu/sk-tcp.c
++++ b/criu/sk-tcp.c
+@@ -51,7 +51,7 @@ static int tcp_repair_established(int fd, struct inet_sk_desc *sk)
+ 	}
+ 
+ 	if (!(root_ns_mask & CLONE_NEWNET)) {
+-		ret = nf_lock_connection(sk);
++		ret = nf_lock_connection(sk, opts.tree_id, opts.use_nft);
+ 		if (ret < 0)
+ 			goto err2;
+ 	}
+@@ -66,21 +66,21 @@ static int tcp_repair_established(int fd, struct inet_sk_desc *sk)
+ 
+ err3:
+ 	if (!(root_ns_mask & CLONE_NEWNET))
+-		nf_unlock_connection(sk);
++		nf_unlock_connection(sk, opts.use_nft);
+ err2:
+ 	close(sk->rfd);
+ err1:
+ 	return -1;
+ }
+ 
+-static void tcp_unlock_one(struct inet_sk_desc *sk)
++static void tcp_unlock_one(struct inet_sk_desc *sk, bool use_nft)
+ {
+ 	int ret;
+ 
+ 	list_del(&sk->rlist);
+ 
+-	if (!(root_ns_mask & CLONE_NEWNET)) {
+-		ret = nf_unlock_connection(sk);
++	if (!(root_ns_mask & CLONE_NEWNET) && !use_nft) {
++		ret = nf_unlock_connection(sk, false);
+ 		if (ret < 0)
+ 			pr_perror("Failed to unlock TCP connection");
+ 	}
+@@ -97,12 +97,12 @@ static void tcp_unlock_one(struct inet_sk_desc *sk)
+ 	close(sk->rfd);
+ }
+ 
+-void cpt_unlock_tcp_connections(void)
++void cpt_unlock_tcp_connections(bool use_nft)
+ {
+ 	struct inet_sk_desc *sk, *n;
+ 
+ 	list_for_each_entry_safe(sk, n, &cpt_tcp_repair_sockets, rlist)
+-		tcp_unlock_one(sk);
++		tcp_unlock_one(sk, use_nft);
+ }
+ 
+ static int dump_tcp_conn_state(struct inet_sk_desc *sk)
+-- 
+2.33.0
+
diff -Nur criu/0013-fix-compile-problem-for-x86.patch obs_criu/0013-fix-compile-problem-for-x86.patch
--- criu/0013-fix-compile-problem-for-x86.patch	1970-01-01 08:00:00.000000000 +0800
+++ obs_criu/0013-fix-compile-problem-for-x86.patch	2022-10-17 10:12:18.000000000 +0800
@@ -0,0 +1,142 @@
+From 792dc7fb0875ec62216397be2e3f40f2741befe5 Mon Sep 17 00:00:00 2001
+From: Your Name <you@example.com>
+Date: Fri, 14 Oct 2022 16:10:59 +0800
+Subject: [PATCH 1/6] fix-compile-problem-for-x86
+
+---
+ criu/include/irmap.h            | 7 +++++--
+ criu/include/parasite-syscall.h | 5 ++---
+ criu/include/pstree.h           | 2 +-
+ criu/include/rst_info.h         | 5 ++---
+ criu/mem.c                      | 2 +-
+ lib/c/criu.h                    | 3 ++-
+ 6 files changed, 13 insertions(+), 11 deletions(-)
+
+diff --git a/criu/include/irmap.h b/criu/include/irmap.h
+index 033f71e..4da2d64 100644
+--- a/criu/include/irmap.h
++++ b/criu/include/irmap.h
+@@ -1,13 +1,16 @@
+ #ifndef __CR_IRMAP__H__
+ #define __CR_IRMAP__H__
++
++#include "images/fh.pb-c.h"
++
+ char *irmap_lookup(unsigned int s_dev, unsigned long i_ino);
+ struct _FhEntry;
+ int irmap_queue_cache(unsigned int dev, unsigned long ino,
+-		struct _FhEntry *fh);
++		FhEntry *fh);
+ int irmap_predump_prep(void);
+ int irmap_predump_run(void);
+ int check_open_handle(unsigned int s_dev, unsigned long i_ino,
+-		struct _FhEntry *f_handle);
++		FhEntry *f_handle);
+ int irmap_load_cache(void);
+ int irmap_scan_path_add(char *path);
+ #endif
+diff --git a/criu/include/parasite-syscall.h b/criu/include/parasite-syscall.h
+index c86a724..4a0bd72 100644
+--- a/criu/include/parasite-syscall.h
++++ b/criu/include/parasite-syscall.h
+@@ -12,7 +12,6 @@ struct parasite_drain_fd;
+ struct vm_area_list;
+ struct pstree_item;
+ struct _CredsEntry;
+-struct _CoreEntry;
+ struct list_head;
+ struct cr_imgset;
+ struct fd_opts;
+@@ -32,10 +31,10 @@ extern int parasite_dump_posix_timers_seized(struct proc_posix_timers_stat *proc
+ 
+ extern int parasite_dump_misc_seized(struct parasite_ctl *ctl, struct parasite_dump_misc *misc);
+ extern int parasite_dump_creds(struct parasite_ctl *ctl, struct _CredsEntry *ce);
+-extern int parasite_dump_thread_leader_seized(struct parasite_ctl *ctl, int pid, struct _CoreEntry *core);
++extern int parasite_dump_thread_leader_seized(struct parasite_ctl *ctl, int pid, CoreEntry *core);
+ extern int parasite_dump_thread_seized(struct parasite_thread_ctl *tctl,
+ 				       struct parasite_ctl *ctl, int id,
+-				       struct pid *tid, struct _CoreEntry *core);
++				       struct pid *tid, CoreEntry *core);
+ extern int dump_thread_core(int pid, CoreEntry *core,
+ 					const struct parasite_dump_thread *dt);
+ 
+diff --git a/criu/include/pstree.h b/criu/include/pstree.h
+index 61ab0ce..17d22e7 100644
+--- a/criu/include/pstree.h
++++ b/criu/include/pstree.h
+@@ -113,7 +113,7 @@ extern int prepare_task_entries(void);
+ extern int prepare_dummy_task_state(struct pstree_item *pi);
+ 
+ extern int get_task_ids(struct pstree_item *);
+-extern struct _TaskKobjIdsEntry *root_ids;
++extern TaskKobjIdsEntry *root_ids;
+ 
+ extern void core_entry_free(CoreEntry *core);
+ extern CoreEntry *core_entry_alloc(int alloc_thread_info, int alloc_tc);
+diff --git a/criu/include/rst_info.h b/criu/include/rst_info.h
+index 3283849..3dc119a 100644
+--- a/criu/include/rst_info.h
++++ b/criu/include/rst_info.h
+@@ -5,6 +5,7 @@
+ #include "common/list.h"
+ #include "vma.h"
+ #include "kerndat.h"
++#include "images/mm.pb-c.h"
+ 
+ struct task_entries {
+ 	int nr_threads, nr_tasks, nr_helpers;
+@@ -25,8 +26,6 @@ struct fdt {
+ 	futex_t			fdt_lock;
+ };
+ 
+-struct _MmEntry;
+-
+ struct rst_info {
+ 	struct list_head	fds;
+ 
+@@ -40,7 +39,7 @@ struct rst_info {
+ 	struct fdt		*fdt;
+ 
+ 	struct vm_area_list	vmas;
+-	struct _MmEntry		*mm;
++	MmEntry		*mm;
+ 	struct list_head	vma_io;
+ 	unsigned int		pages_img_id;
+ 
+diff --git a/criu/mem.c b/criu/mem.c
+index 709de4e..6ceb733 100644
+--- a/criu/mem.c
++++ b/criu/mem.c
+@@ -1319,7 +1319,7 @@ err_addr:
+ 
+ static int maybe_disable_thp(struct pstree_item *t, struct page_read *pr)
+ {
+-	struct _MmEntry *mm = rsti(t)->mm;
++	MmEntry *mm = rsti(t)->mm;
+ 
+ 	/*
+ 	 * There is no need to disable it if the page read doesn't
+diff --git a/lib/c/criu.h b/lib/c/criu.h
+index e9b2f1e..3340de2 100644
+--- a/lib/c/criu.h
++++ b/lib/c/criu.h
+@@ -22,6 +22,7 @@
+ #include <stdbool.h>
+ 
+ #include "version.h"
++#include "rpc.pb-c.h"
+ 
+ #ifdef __GNUG__
+ 	extern "C" {
+@@ -111,7 +112,7 @@ int criu_set_pre_dump_mode(enum criu_pre_dump_mode mode);
+  * some non-existing one is reported.
+  */
+ 
+-typedef struct _CriuNotify *criu_notify_arg_t;
++typedef CriuNotify *criu_notify_arg_t;
+ void criu_set_notify_cb(int (*cb)(char *action, criu_notify_arg_t na));
+ 
+ /* Get pid of root task. 0 if not available */
+-- 
+2.33.0
+
diff -Nur criu/criu.spec obs_criu/criu.spec
--- criu/criu.spec	2022-11-02 15:29:06.302185340 +0800
+++ obs_criu/criu.spec	2022-10-17 16:18:24.000000000 +0800
@@ -1,6 +1,6 @@
 Name:          criu
 Version:       3.15
-Release:       3
+Release:       4
 Provides:      crtools = %{version}-%{release}
 Obsoletes:     crtools <= 1.0-2
 Summary:       A tool of Checkpoint/Restore in User-space
@@ -9,6 +9,7 @@
 Source0:       http://download.openvz.org/criu/criu-%{version}.tar.bz2
 BuildRequires: systemd libnet-devel asciidoc xmlto perl-interpreter libselinux-devel
 BuildRequires: protobuf-devel protobuf-c-devel python3-devel libnl3-devel libcap-devel
+BuildRequires: libnftnl-devel libmnl-devel
 Recommends:    tar
 ExclusiveArch: x86_64 %{arm} ppc64le aarch64 s390x
 Requires:      %{name} = %{version}-%{release}
@@ -22,6 +23,14 @@
 Patch0005:     0005-vdso-fix-segmentation-fault-caused-by-char-pointer-a.patch
 Patch0006:     0006-criu-add-pin-memory-method.patch
 Patch0007:     0007-criu-add-pid-recover-method-for-criu.patch
+Patch0008:     0008-fix-multi-thread-recover-problem-with-pin-memory.patch
+Patch0009:     0009-nftables-add-mnl-api.patch
+Patch0010:     0010-nftables-implement-nft-api-for-tcp.patch
+Patch0011:     0011-nftables-implement-nft-api-for-lock-net-ns.patch
+Patch0012:     0012-criu-switch-to-nftables-api.patch
+%ifarch x86_64
+Patch0013:     0013-fix-compile-problem-for-x86.patch
+%endif
 
 %description
 Checkpoint/Restore in Userspace(CRIU),is a software tool for the linux operating system.
@@ -95,6 +104,9 @@
 %doc %{_mandir}/man1/{compel.1*,crit.1*}
 
 %changelog
+* Fri Oct 14 2021 Jingxian He <hejingxian@huawei.com> - 3.15-4
+- Add pid recover method for criu
+
 * Fri Jul 23 2021 snoweay <snoweay@163.com> - 3.15-3
 - Add pid recover method for criu
 
