iproute2/tc/m_ctinfo.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2/*
   3 * m_ctinfo.c           netfilter ctinfo mark action
   4 *
   5 * Copyright (c) 2019 Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
   6 */
   7
   8#include <stdio.h>
   9#include <stdlib.h>
  10#include <unistd.h>
  11#include <string.h>
  12#include "utils.h"
  13#include "tc_util.h"
  14#include <linux/tc_act/tc_ctinfo.h>
  15
  16static void
  17explain(void)
  18{
  19        fprintf(stderr,
  20                "Usage: ... ctinfo [dscp mask [statemask]] [cpmark [mask]] [zone ZONE] [CONTROL] [index <INDEX>]\n"
  21                "where :\n"
  22                "\tdscp   MASK bitmask location of stored DSCP\n"
  23                "\t       STATEMASK bitmask to determine conditional restoring\n"
  24                "\tcpmark MASK mask applied to mark on restoration\n"
  25                "\tZONE is the conntrack zone\n"
  26                "\tCONTROL := reclassify | pipe | drop | continue | ok |\n"
  27                "\t           goto chain <CHAIN_INDEX>\n");
  28}
  29
  30static void
  31usage(void)
  32{
  33        explain();
  34        exit(-1);
  35}
  36
  37static int
  38parse_ctinfo(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
  39             struct nlmsghdr *n)
  40{
  41        unsigned int cpmarkmask = 0, dscpmask = 0, dscpstatemask = 0;
  42        struct tc_ctinfo sel = {};
  43        unsigned short zone = 0;
  44        char **argv = *argv_p;
  45        struct rtattr *tail;
  46        int argc = *argc_p;
  47        int ok = 0;
  48        __u8 i;
  49
  50        while (argc > 0) {
  51                if (matches(*argv, "ctinfo") == 0) {
  52                        ok = 1;
  53                        NEXT_ARG_FWD();
  54                } else if (matches(*argv, "help") == 0) {
  55                        usage();
  56                } else {
  57                        break;
  58                }
  59
  60        }
  61
  62        if (!ok) {
  63                explain();
  64                return -1;
  65        }
  66
  67        if (argc) {
  68                if (matches(*argv, "dscp") == 0) {
  69                        NEXT_ARG();
  70                        if (get_u32(&dscpmask, *argv, 0)) {
  71                                fprintf(stderr,
  72                                        "ctinfo: Illegal dscp \"mask\"\n");
  73                                return -1;
  74                        }
  75                        if (NEXT_ARG_OK()) {
  76                                NEXT_ARG_FWD();
  77                                if (!get_u32(&dscpstatemask, *argv, 0))
  78                                        NEXT_ARG_FWD(); /* was a statemask */
  79                        } else {
  80                                NEXT_ARG_FWD();
  81                        }
  82                }
  83        }
  84
  85        /* cpmark has optional mask parameter, so the next arg might not  */
  86        /* exist, or it might be the next option, or it may actually be a */
  87        /* 32bit mask */
  88        if (argc) {
  89                if (matches(*argv, "cpmark") == 0) {
  90                        cpmarkmask = ~0;
  91                        if (NEXT_ARG_OK()) {
  92                                NEXT_ARG_FWD();
  93                                if (!get_u32(&cpmarkmask, *argv, 0))
  94                                        NEXT_ARG_FWD(); /* was a mask */
  95                        } else {
  96                                NEXT_ARG_FWD();
  97                        }
  98                }
  99        }
 100
 101        if (argc) {
 102                if (matches(*argv, "zone") == 0) {
 103                        NEXT_ARG();
 104                        if (get_u16(&zone, *argv, 10)) {
 105                                fprintf(stderr, "ctinfo: Illegal \"zone\"\n");
 106                                return -1;
 107                        }
 108                        NEXT_ARG_FWD();
 109                }
 110        }
 111
 112        parse_action_control_dflt(&argc, &argv, &sel.action,
 113                                  false, TC_ACT_PIPE);
 114
 115        if (argc) {
 116                if (matches(*argv, "index") == 0) {
 117                        NEXT_ARG();
 118                        if (get_u32(&sel.index, *argv, 10)) {
 119                                fprintf(stderr, "ctinfo: Illegal \"index\"\n");
 120                                return -1;
 121                        }
 122                        NEXT_ARG_FWD();
 123                }
 124        }
 125
 126        if (dscpmask & dscpstatemask) {
 127                fprintf(stderr,
 128                        "ctinfo: dscp mask & statemask must NOT overlap\n");
 129                return -1;
 130        }
 131
 132        i = ffs(dscpmask);
 133        if (i && ((~0 & (dscpmask >> (i - 1))) != 0x3f)) {
 134                fprintf(stderr,
 135                        "ctinfo: dscp mask must be 6 contiguous bits long\n");
 136                return -1;
 137        }
 138
 139        tail = addattr_nest(n, MAX_MSG, tca_id);
 140        addattr_l(n, MAX_MSG, TCA_CTINFO_ACT, &sel, sizeof(sel));
 141        addattr16(n, MAX_MSG, TCA_CTINFO_ZONE, zone);
 142
 143        if (dscpmask)
 144                addattr32(n, MAX_MSG,
 145                          TCA_CTINFO_PARMS_DSCP_MASK, dscpmask);
 146
 147        if (dscpstatemask)
 148                addattr32(n, MAX_MSG,
 149                          TCA_CTINFO_PARMS_DSCP_STATEMASK, dscpstatemask);
 150
 151        if (cpmarkmask)
 152                addattr32(n, MAX_MSG,
 153                          TCA_CTINFO_PARMS_CPMARK_MASK, cpmarkmask);
 154
 155        addattr_nest_end(n, tail);
 156
 157        *argc_p = argc;
 158        *argv_p = argv;
 159        return 0;
 160}
 161
 162static void print_ctinfo_stats(FILE *f, struct rtattr *tb[TCA_CTINFO_MAX + 1])
 163{
 164        struct tcf_t *tm;
 165
 166        if (tb[TCA_CTINFO_TM]) {
 167                tm = RTA_DATA(tb[TCA_CTINFO_TM]);
 168
 169                print_tm(f, tm);
 170        }
 171
 172        if (tb[TCA_CTINFO_STATS_DSCP_SET])
 173                print_lluint(PRINT_ANY, "dscpset", " DSCP set %llu",
 174                             rta_getattr_u64(tb[TCA_CTINFO_STATS_DSCP_SET]));
 175        if (tb[TCA_CTINFO_STATS_DSCP_ERROR])
 176                print_lluint(PRINT_ANY, "dscperror", " error %llu",
 177                             rta_getattr_u64(tb[TCA_CTINFO_STATS_DSCP_ERROR]));
 178
 179        if (tb[TCA_CTINFO_STATS_CPMARK_SET])
 180                print_lluint(PRINT_ANY, "cpmarkset", " CPMARK set %llu",
 181                             rta_getattr_u64(tb[TCA_CTINFO_STATS_CPMARK_SET]));
 182}
 183
 184static int print_ctinfo(struct action_util *au, FILE *f, struct rtattr *arg)
 185{
 186        unsigned int cpmarkmask = ~0, dscpmask = 0, dscpstatemask = 0;
 187        struct rtattr *tb[TCA_CTINFO_MAX + 1];
 188        unsigned short zone = 0;
 189        struct tc_ctinfo *ci;
 190
 191        print_string(PRINT_ANY, "kind", "%s ", "ctinfo");
 192        if (arg == NULL)
 193                return 0;
 194
 195        parse_rtattr_nested(tb, TCA_CTINFO_MAX, arg);
 196        if (!tb[TCA_CTINFO_ACT]) {
 197                print_string(PRINT_FP, NULL, "%s",
 198                             "[NULL ctinfo action parameters]");
 199                return -1;
 200        }
 201
 202        ci = RTA_DATA(tb[TCA_CTINFO_ACT]);
 203
 204        if (tb[TCA_CTINFO_PARMS_DSCP_MASK]) {
 205                if (RTA_PAYLOAD(tb[TCA_CTINFO_PARMS_DSCP_MASK]) >=
 206                    sizeof(__u32))
 207                        dscpmask = rta_getattr_u32(
 208                                        tb[TCA_CTINFO_PARMS_DSCP_MASK]);
 209                else
 210                        print_string(PRINT_FP, NULL, "%s",
 211                                     "[invalid dscp mask parameter]");
 212        }
 213
 214        if (tb[TCA_CTINFO_PARMS_DSCP_STATEMASK]) {
 215                if (RTA_PAYLOAD(tb[TCA_CTINFO_PARMS_DSCP_STATEMASK]) >=
 216                    sizeof(__u32))
 217                        dscpstatemask = rta_getattr_u32(
 218                                        tb[TCA_CTINFO_PARMS_DSCP_STATEMASK]);
 219                else
 220                        print_string(PRINT_FP, NULL, "%s",
 221                                     "[invalid dscp statemask parameter]");
 222        }
 223
 224        if (tb[TCA_CTINFO_PARMS_CPMARK_MASK]) {
 225                if (RTA_PAYLOAD(tb[TCA_CTINFO_PARMS_CPMARK_MASK]) >=
 226                    sizeof(__u32))
 227                        cpmarkmask = rta_getattr_u32(
 228                                        tb[TCA_CTINFO_PARMS_CPMARK_MASK]);
 229                else
 230                        print_string(PRINT_FP, NULL, "%s",
 231                                     "[invalid cpmark mask parameter]");
 232        }
 233
 234        if (tb[TCA_CTINFO_ZONE] && RTA_PAYLOAD(tb[TCA_CTINFO_ZONE]) >=
 235            sizeof(__u16))
 236                zone = rta_getattr_u16(tb[TCA_CTINFO_ZONE]);
 237
 238        print_hu(PRINT_ANY, "zone", "zone %u", zone);
 239        print_action_control(f, " ", ci->action, "");
 240
 241        print_nl();
 242        print_uint(PRINT_ANY, "index", "\t index %u", ci->index);
 243        print_int(PRINT_ANY, "ref", " ref %d", ci->refcnt);
 244        print_int(PRINT_ANY, "bind", " bind %d", ci->bindcnt);
 245
 246        if (tb[TCA_CTINFO_PARMS_DSCP_MASK]) {
 247                print_0xhex(PRINT_ANY, "dscpmask", " dscp %#010llx", dscpmask);
 248                print_0xhex(PRINT_ANY, "dscpstatemask", " %#010llx",
 249                            dscpstatemask);
 250        }
 251
 252        if (tb[TCA_CTINFO_PARMS_CPMARK_MASK])
 253                print_0xhex(PRINT_ANY, "cpmark", " cpmark %#010llx",
 254                            cpmarkmask);
 255
 256        if (show_stats)
 257                print_ctinfo_stats(f, tb);
 258
 259        print_nl();
 260
 261        return 0;
 262}
 263
 264struct action_util ctinfo_action_util = {
 265        .id = "ctinfo",
 266        .parse_aopt = parse_ctinfo,
 267        .print_aopt = print_ctinfo,
 268};
 269