diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 14:18:53 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 14:18:53 +0000 |
commit | a0e0018c9a7ef5ce7f6d2c3ae16aecbbd16a8f67 (patch) | |
tree | 8feaf1a1932871b139b3b30be4c09c66489918be /tc/m_ctinfo.c | |
parent | Initial commit. (diff) | |
download | iproute2-a0e0018c9a7ef5ce7f6d2c3ae16aecbbd16a8f67.tar.xz iproute2-a0e0018c9a7ef5ce7f6d2c3ae16aecbbd16a8f67.zip |
Adding upstream version 6.1.0.upstream/6.1.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | tc/m_ctinfo.c | 268 |
1 files changed, 268 insertions, 0 deletions
diff --git a/tc/m_ctinfo.c b/tc/m_ctinfo.c new file mode 100644 index 0000000..996a362 --- /dev/null +++ b/tc/m_ctinfo.c @@ -0,0 +1,268 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * m_ctinfo.c netfilter ctinfo mark action + * + * Copyright (c) 2019 Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk> + */ + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include "utils.h" +#include "tc_util.h" +#include <linux/tc_act/tc_ctinfo.h> + +static void +explain(void) +{ + fprintf(stderr, + "Usage: ... ctinfo [dscp mask [statemask]] [cpmark [mask]] [zone ZONE] [CONTROL] [index <INDEX>]\n" + "where :\n" + "\tdscp MASK bitmask location of stored DSCP\n" + "\t STATEMASK bitmask to determine conditional restoring\n" + "\tcpmark MASK mask applied to mark on restoration\n" + "\tZONE is the conntrack zone\n" + "\tCONTROL := reclassify | pipe | drop | continue | ok |\n" + "\t goto chain <CHAIN_INDEX>\n"); +} + +static void +usage(void) +{ + explain(); + exit(-1); +} + +static int +parse_ctinfo(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, + struct nlmsghdr *n) +{ + unsigned int cpmarkmask = 0, dscpmask = 0, dscpstatemask = 0; + struct tc_ctinfo sel = {}; + unsigned short zone = 0; + char **argv = *argv_p; + struct rtattr *tail; + int argc = *argc_p; + int ok = 0; + __u8 i; + + while (argc > 0) { + if (matches(*argv, "ctinfo") == 0) { + ok = 1; + NEXT_ARG_FWD(); + } else if (matches(*argv, "help") == 0) { + usage(); + } else { + break; + } + + } + + if (!ok) { + explain(); + return -1; + } + + if (argc) { + if (matches(*argv, "dscp") == 0) { + NEXT_ARG(); + if (get_u32(&dscpmask, *argv, 0)) { + fprintf(stderr, + "ctinfo: Illegal dscp \"mask\"\n"); + return -1; + } + if (NEXT_ARG_OK()) { + NEXT_ARG_FWD(); + if (!get_u32(&dscpstatemask, *argv, 0)) + NEXT_ARG_FWD(); /* was a statemask */ + } else { + NEXT_ARG_FWD(); + } + } + } + + /* cpmark has optional mask parameter, so the next arg might not */ + /* exist, or it might be the next option, or it may actually be a */ + /* 32bit mask */ + if (argc) { + if (matches(*argv, "cpmark") == 0) { + cpmarkmask = ~0; + if (NEXT_ARG_OK()) { + NEXT_ARG_FWD(); + if (!get_u32(&cpmarkmask, *argv, 0)) + NEXT_ARG_FWD(); /* was a mask */ + } else { + NEXT_ARG_FWD(); + } + } + } + + if (argc) { + if (matches(*argv, "zone") == 0) { + NEXT_ARG(); + if (get_u16(&zone, *argv, 10)) { + fprintf(stderr, "ctinfo: Illegal \"zone\"\n"); + return -1; + } + NEXT_ARG_FWD(); + } + } + + parse_action_control_dflt(&argc, &argv, &sel.action, + false, TC_ACT_PIPE); + + if (argc) { + if (matches(*argv, "index") == 0) { + NEXT_ARG(); + if (get_u32(&sel.index, *argv, 10)) { + fprintf(stderr, "ctinfo: Illegal \"index\"\n"); + return -1; + } + NEXT_ARG_FWD(); + } + } + + if (dscpmask & dscpstatemask) { + fprintf(stderr, + "ctinfo: dscp mask & statemask must NOT overlap\n"); + return -1; + } + + i = ffs(dscpmask); + if (i && ((~0 & (dscpmask >> (i - 1))) != 0x3f)) { + fprintf(stderr, + "ctinfo: dscp mask must be 6 contiguous bits long\n"); + return -1; + } + + tail = addattr_nest(n, MAX_MSG, tca_id); + addattr_l(n, MAX_MSG, TCA_CTINFO_ACT, &sel, sizeof(sel)); + addattr16(n, MAX_MSG, TCA_CTINFO_ZONE, zone); + + if (dscpmask) + addattr32(n, MAX_MSG, + TCA_CTINFO_PARMS_DSCP_MASK, dscpmask); + + if (dscpstatemask) + addattr32(n, MAX_MSG, + TCA_CTINFO_PARMS_DSCP_STATEMASK, dscpstatemask); + + if (cpmarkmask) + addattr32(n, MAX_MSG, + TCA_CTINFO_PARMS_CPMARK_MASK, cpmarkmask); + + addattr_nest_end(n, tail); + + *argc_p = argc; + *argv_p = argv; + return 0; +} + +static void print_ctinfo_stats(FILE *f, struct rtattr *tb[TCA_CTINFO_MAX + 1]) +{ + struct tcf_t *tm; + + if (tb[TCA_CTINFO_TM]) { + tm = RTA_DATA(tb[TCA_CTINFO_TM]); + + print_tm(f, tm); + } + + if (tb[TCA_CTINFO_STATS_DSCP_SET]) + print_lluint(PRINT_ANY, "dscpset", " DSCP set %llu", + rta_getattr_u64(tb[TCA_CTINFO_STATS_DSCP_SET])); + if (tb[TCA_CTINFO_STATS_DSCP_ERROR]) + print_lluint(PRINT_ANY, "dscperror", " error %llu", + rta_getattr_u64(tb[TCA_CTINFO_STATS_DSCP_ERROR])); + + if (tb[TCA_CTINFO_STATS_CPMARK_SET]) + print_lluint(PRINT_ANY, "cpmarkset", " CPMARK set %llu", + rta_getattr_u64(tb[TCA_CTINFO_STATS_CPMARK_SET])); +} + +static int print_ctinfo(struct action_util *au, FILE *f, struct rtattr *arg) +{ + unsigned int cpmarkmask = ~0, dscpmask = 0, dscpstatemask = 0; + struct rtattr *tb[TCA_CTINFO_MAX + 1]; + unsigned short zone = 0; + struct tc_ctinfo *ci; + + print_string(PRINT_ANY, "kind", "%s ", "ctinfo"); + if (arg == NULL) + return 0; + + parse_rtattr_nested(tb, TCA_CTINFO_MAX, arg); + if (!tb[TCA_CTINFO_ACT]) { + print_string(PRINT_FP, NULL, "%s", + "[NULL ctinfo action parameters]"); + return -1; + } + + ci = RTA_DATA(tb[TCA_CTINFO_ACT]); + + if (tb[TCA_CTINFO_PARMS_DSCP_MASK]) { + if (RTA_PAYLOAD(tb[TCA_CTINFO_PARMS_DSCP_MASK]) >= + sizeof(__u32)) + dscpmask = rta_getattr_u32( + tb[TCA_CTINFO_PARMS_DSCP_MASK]); + else + print_string(PRINT_FP, NULL, "%s", + "[invalid dscp mask parameter]"); + } + + if (tb[TCA_CTINFO_PARMS_DSCP_STATEMASK]) { + if (RTA_PAYLOAD(tb[TCA_CTINFO_PARMS_DSCP_STATEMASK]) >= + sizeof(__u32)) + dscpstatemask = rta_getattr_u32( + tb[TCA_CTINFO_PARMS_DSCP_STATEMASK]); + else + print_string(PRINT_FP, NULL, "%s", + "[invalid dscp statemask parameter]"); + } + + if (tb[TCA_CTINFO_PARMS_CPMARK_MASK]) { + if (RTA_PAYLOAD(tb[TCA_CTINFO_PARMS_CPMARK_MASK]) >= + sizeof(__u32)) + cpmarkmask = rta_getattr_u32( + tb[TCA_CTINFO_PARMS_CPMARK_MASK]); + else + print_string(PRINT_FP, NULL, "%s", + "[invalid cpmark mask parameter]"); + } + + if (tb[TCA_CTINFO_ZONE] && RTA_PAYLOAD(tb[TCA_CTINFO_ZONE]) >= + sizeof(__u16)) + zone = rta_getattr_u16(tb[TCA_CTINFO_ZONE]); + + print_hu(PRINT_ANY, "zone", "zone %u", zone); + print_action_control(f, " ", ci->action, ""); + + print_nl(); + print_uint(PRINT_ANY, "index", "\t index %u", ci->index); + print_int(PRINT_ANY, "ref", " ref %d", ci->refcnt); + print_int(PRINT_ANY, "bind", " bind %d", ci->bindcnt); + + if (tb[TCA_CTINFO_PARMS_DSCP_MASK]) { + print_0xhex(PRINT_ANY, "dscpmask", " dscp %#010llx", dscpmask); + print_0xhex(PRINT_ANY, "dscpstatemask", " %#010llx", + dscpstatemask); + } + + if (tb[TCA_CTINFO_PARMS_CPMARK_MASK]) + print_0xhex(PRINT_ANY, "cpmark", " cpmark %#010llx", + cpmarkmask); + + if (show_stats) + print_ctinfo_stats(f, tb); + + print_nl(); + + return 0; +} + +struct action_util ctinfo_action_util = { + .id = "ctinfo", + .parse_aopt = parse_ctinfo, + .print_aopt = print_ctinfo, +}; |