From: "fu.lin" fu.lin10@huawei.com
libmnl provides the communication between userspace and kernelspace for netfilter netlink. I abstract here for the next usage.
Conflict:NA Reference:https://gitee.com/src-openeuler/criu/pulls/21 Signed-off-by: fu.lin fu.lin10@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 a9008f0..ff6b597 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 += devname.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; +}