Signed-off-by: Marcelo Ricardo Leitner <mleit...@redhat.com> --- include/uapi/linux/tc_act/tc_ct.h | 30 +++ tc/Makefile | 1 + tc/m_ct.c | 314 ++++++++++++++++++++++++++++++ 3 files changed, 345 insertions(+) create mode 100644 include/uapi/linux/tc_act/tc_ct.h create mode 100644 tc/m_ct.c
diff --git a/include/uapi/linux/tc_act/tc_ct.h b/include/uapi/linux/tc_act/tc_ct.h new file mode 100644 index 0000000000000000000000000000000000000000..d08a5afdc4b453c5388ad2ae63a00fd3b48457f0 --- /dev/null +++ b/include/uapi/linux/tc_act/tc_ct.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef __LINUX_TC_CT_H +#define __LINUX_TC_CT_H + +#include <linux/pkt_cls.h> +#include <linux/types.h> + +#define TCA_ACT_CT 27 + +enum { + TCA_CT_UNSPEC, + TCA_CT_TM, + TCA_CT_PARMS, + TCA_CT_PAD, + TCA_CT_ZONE, + TCA_CT_MARK, + TCA_CT_MARK_MASK, + TCA_CT_LABEL, + TCA_CT_LABEL_MASK, + TCA_CT_CHAIN, + TCA_CT_FLAGS, + __TCA_CT_MAX +}; +#define TCA_CT_MAX (__TCA_CT_MAX - 1) + +struct tc_ct { + tc_gen; +}; + +#endif diff --git a/tc/Makefile b/tc/Makefile index 2edaf2c8836475c78e713e789a05203e1c598327..79e10a1a5493bbc9703b47660aa145f98e533aea 100644 --- a/tc/Makefile +++ b/tc/Makefile @@ -51,6 +51,7 @@ TCMODULES += m_connmark.o TCMODULES += m_bpf.o TCMODULES += m_tunnel_key.o TCMODULES += m_sample.o +TCMODULES += m_ct.o TCMODULES += p_ip.o TCMODULES += p_ip6.o TCMODULES += p_icmp.o diff --git a/tc/m_ct.c b/tc/m_ct.c new file mode 100644 index 0000000000000000000000000000000000000000..e20837ba4f9c49d1603b14721cabca1fbeca0c74 --- /dev/null +++ b/tc/m_ct.c @@ -0,0 +1,314 @@ +/* + * m_ct.c Connection Tracking target module + * + * This program is free software; you can distribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Authors: Marcelo Ricardo Leitner <mleit...@redhat.com> + * + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <string.h> +#include "utils.h" +#include "tc_util.h" +#include "tc_common.h" +#include <linux/tc_act/tc_ct.h> + +static void +explain(void) +{ + fprintf(stderr, + "Usage: ct [mark <mark>] [zone <zone>] [label <label>] [chain <chain>]\n" + "where:\n"); +} + +static void +usage(void) +{ + explain(); + exit(-1); +} + +#if 0 +static int ct_parse_u8(char *str, int value_type, int mask_type, + int (*value_from_name)(const char *str, + __u8 *value), + bool (*value_validate)(__u8 value), + struct nlmsghdr *n) +{ + char *slash; + int ret, err = -1; + __u8 value, mask; + + slash = strchr(str, '/'); + if (slash) + *slash = '\0'; + + ret = value_from_name ? value_from_name(str, &value) : -1; + if (ret < 0) { + ret = get_u8(&value, str, 10); + if (ret) + goto err; + } + + if (value_validate && !value_validate(value)) + goto err; + + if (slash) { + ret = get_u8(&mask, slash + 1, 10); + if (ret) + goto err; + } + else { + mask = UINT8_MAX; + } + + addattr8(n, MAX_MSG, value_type, value); + addattr8(n, MAX_MSG, mask_type, mask); + + err = 0; +err: + if (slash) + *slash = '/'; + return err; +} +#endif + +static int ct_parse_u16(char *str, int value_type, int mask_type, + int (*value_from_name)(const char *str, + __u16 *value), + bool (*value_validate)(__u16 value), + struct nlmsghdr *n) +{ + char *slash; + int ret, err = -1; + __u16 value, mask; + + slash = strchr(str, '/'); + if (slash) + *slash = '\0'; + + ret = value_from_name ? value_from_name(str, &value) : -1; + if (ret < 0) { + ret = get_u16(&value, str, 10); + if (ret) + goto err; + } + + if (value_validate && !value_validate(value)) + goto err; + + if (slash) { + ret = get_u16(&mask, slash + 1, 10); + if (ret) + goto err; + } + else { + mask = UINT16_MAX; + } + + print_uint(PRINT_ANY, "zone", "zone %u ", value); + addattr16(n, MAX_MSG, value_type, value); + /* FIXME: find another parse function to avoid this */ + if (mask_type) + addattr16(n, MAX_MSG, mask_type, mask); + + err = 0; +err: + if (slash) + *slash = '/'; + return err; +} + +static int ct_parse_u32(char *str, int value_type, int mask_type, + int (*value_from_name)(const char *str, + __u32 *value), + bool (*value_validate)(__u32 value), + struct nlmsghdr *n) +{ + char *slash; + int ret, err = -1; + __u32 value, mask; + + slash = strchr(str, '/'); + if (slash) + *slash = '\0'; + + ret = value_from_name ? value_from_name(str, &value) : -1; + if (ret < 0) { + ret = get_u32(&value, str, 10); + if (ret) + goto err; + } + + if (value_validate && !value_validate(value)) + goto err; + + if (slash) { + ret = get_u32(&mask, slash + 1, 10); + if (ret) + goto err; + } + else { + mask = UINT32_MAX; + } + + addattr32(n, MAX_MSG, value_type, value); + addattr32(n, MAX_MSG, mask_type, mask); + + err = 0; +err: + if (slash) + *slash = '/'; + return err; +} + + +static int +parse_ct(struct action_util *a, int *argc_p, char ***argv_p, + int tca_id, struct nlmsghdr *n) +{ + int argc = *argc_p; + char **argv = *argv_p; + struct tc_ct p = {}; + struct rtattr *tail; + + if (argc <= 0) { + fprintf(stderr, "ct bad argument count %d\n", argc); + return -1; + } + + if (!matches(*argv, "ct")) { + NEXT_ARG_FWD(); + } else { + fprintf(stderr, "ct bad argument %s\n", *argv); + return -1; + } + + tail = addattr_nest(n, MAX_MSG, tca_id); + +again: + if (argc <= 0) { + addattr_l(n, MAX_MSG, TCA_CT_PARMS, &p, sizeof(p)); + addattr_nest_end(n, tail); + + *argc_p = argc; + *argv_p = argv; + return 0; + } + + if (!matches(*argv, "mark")) { + NEXT_ARG(); + ct_parse_u32(*argv, + TCA_CT_MARK, + TCA_CT_MARK_MASK, + NULL, NULL, n); + NEXT_ARG_FWD(); + goto again; + } + if (!matches(*argv, "zone")) { + NEXT_ARG(); + ct_parse_u16(*argv, + TCA_CT_ZONE, + 0, + NULL, NULL, n); + NEXT_ARG_FWD(); + goto again; + } +/* if (!matches(*argv, "state")) { + NEXT_ARG(); + ct_parse_u8(*argv, + TCA_FLOWER_KEY_CT_STATE, + TCA_FLOWER_KEY_CT_STATE_MASK, + NULL, NULL, n); + NEXT_ARG_FWD(); + goto again; + }*/ +/* if (!matches(*argv, "label")) { + NEXT_ARG(); + goto again; + }*/ +/* if (!matches(*argv, "chain")) { + NEXT_ARG(); + goto again; + }*/ + + if (!matches(*argv, "help") == 0) { + usage(); + } else { + fprintf(stderr, "ct option not supported %s\n", *argv); + } + + return -1; +} + +static void ct_print_mask(const char *name, __u32 key, __u32 mask) +{ + SPRINT_BUF(namefrm); + SPRINT_BUF(out); + size_t done; + + if (!key && !mask) + return; + + done = sprintf(out, "0x%x", key); + if (mask) + sprintf(out + done, "/%x", mask); + + print_string(PRINT_FP, NULL, "%s ", _SL_); + sprintf(namefrm, "%s %%s", name); + print_string(PRINT_ANY, name, namefrm, out); +} + +static int +print_ct(struct action_util *au, FILE *f, struct rtattr *arg) +{ + struct tc_ct *p; + struct rtattr *tb[TCA_CT_MAX + 1]; + + if (arg == NULL) + return -1; + + parse_rtattr_nested(tb, TCA_CT_MAX, arg); + + if (tb[TCA_CT_PARMS] == NULL) { + print_string(PRINT_FP, NULL, "%s", "[NULL ct parameters]"); + return -1; + } + p = RTA_DATA(tb[TCA_CT_PARMS]); + + print_string(PRINT_ANY, "kind", "%s ", "ct"); + ct_print_mask("mark", rta_getattr_u32(tb[TCA_CT_MARK]), + rta_getattr_u32(tb[TCA_CT_MARK_MASK])); + print_uint(PRINT_ANY, "zone", "zone %u ", rta_getattr_u16(tb[TCA_CT_ZONE])); + print_uint(PRINT_ANY, "chain", "chain %u", rta_getattr_u32(tb[TCA_CT_CHAIN])); + + print_uint(PRINT_ANY, "index", "\n \tindex %u", p->index); + print_int(PRINT_ANY, "ref", " ref %d", p->refcnt); + print_int(PRINT_ANY, "bind", " bind %d", p->bindcnt); + + if (show_stats) { + if (tb[TCA_CT_TM]) { + struct tcf_t *tm = RTA_DATA(tb[TCA_CT_TM]); + + print_tm(f, tm); + } + } + print_string(PRINT_FP, NULL, "%s", "\n "); + return 0; +} + +struct action_util ct_action_util = { + .id = "ct", + .parse_aopt = parse_ct, + .print_aopt = print_ct, +}; -- 2.20.1