iproute2/tc/m_csum.c
<<
>>
Prefs
   1/*
   2 * m_csum.c     checksum updating action
   3 *
   4 *              This program is free software; you can distribute it and/or
   5 *              modify it under the terms of the GNU General Public License
   6 *              as published by the Free Software Foundation; either version
   7 *              2 of the License, or (at your option) any later version.
   8 *
   9 * Authors: Gregoire Baron <baronchon@n7mm.org>
  10 */
  11
  12#include <stdio.h>
  13#include <stdlib.h>
  14#include <string.h>
  15#include <unistd.h>
  16
  17#include <linux/tc_act/tc_csum.h>
  18
  19#include "utils.h"
  20#include "tc_util.h"
  21
  22static void
  23explain(void)
  24{
  25        fprintf(stderr, "Usage: ... csum <UPDATE>\n"
  26                        "Where: UPDATE := <TARGET> [<UPDATE>]\n"
  27                        "       TARGET := { ip4h | icmp | igmp | tcp | udp | udplite | sctp | <SWEETS> }\n"
  28                        "       SWEETS := { and | or | \'+\' }\n");
  29}
  30
  31static void
  32usage(void)
  33{
  34        explain();
  35        exit(-1);
  36}
  37
  38static int
  39parse_csum_args(int *argc_p, char ***argv_p, struct tc_csum *sel)
  40{
  41        int argc = *argc_p;
  42        char **argv = *argv_p;
  43
  44        if (argc <= 0)
  45                return -1;
  46
  47        while (argc > 0) {
  48                if ((matches(*argv, "iph") == 0) ||
  49                    (matches(*argv, "ip4h") == 0) ||
  50                    (matches(*argv, "ipv4h") == 0))
  51                        sel->update_flags |= TCA_CSUM_UPDATE_FLAG_IPV4HDR;
  52
  53                else if (matches(*argv, "icmp") == 0)
  54                        sel->update_flags |= TCA_CSUM_UPDATE_FLAG_ICMP;
  55
  56                else if (matches(*argv, "igmp") == 0)
  57                        sel->update_flags |= TCA_CSUM_UPDATE_FLAG_IGMP;
  58
  59                else if (matches(*argv, "tcp") == 0)
  60                        sel->update_flags |= TCA_CSUM_UPDATE_FLAG_TCP;
  61
  62                else if (matches(*argv, "udp") == 0)
  63                        sel->update_flags |= TCA_CSUM_UPDATE_FLAG_UDP;
  64
  65                else if (matches(*argv, "udplite") == 0)
  66                        sel->update_flags |= TCA_CSUM_UPDATE_FLAG_UDPLITE;
  67
  68                else if (matches(*argv, "sctp") == 0)
  69                        sel->update_flags |= TCA_CSUM_UPDATE_FLAG_SCTP;
  70
  71                else if ((matches(*argv, "and") == 0) ||
  72                         (matches(*argv, "or") == 0) ||
  73                         (matches(*argv, "+") == 0))
  74                        ; /* just ignore: ... csum iph and tcp or udp */
  75                else
  76                        break;
  77                argc--;
  78                argv++;
  79        }
  80
  81        *argc_p = argc;
  82        *argv_p = argv;
  83
  84        return 0;
  85}
  86
  87static int
  88parse_csum(struct action_util *a, int *argc_p,
  89           char ***argv_p, int tca_id, struct nlmsghdr *n)
  90{
  91        struct tc_csum sel = {};
  92
  93        int argc = *argc_p;
  94        char **argv = *argv_p;
  95        int ok = 0;
  96        struct rtattr *tail;
  97
  98        while (argc > 0) {
  99                if (matches(*argv, "csum") == 0) {
 100                        NEXT_ARG();
 101                        if (parse_csum_args(&argc, &argv, &sel)) {
 102                                fprintf(stderr, "Illegal csum construct (%s)\n",
 103                                        *argv);
 104                                explain();
 105                                return -1;
 106                        }
 107                        ok++;
 108                        continue;
 109                } else if (matches(*argv, "help") == 0) {
 110                        usage();
 111                } else {
 112                        break;
 113                }
 114        }
 115
 116        if (!ok) {
 117                explain();
 118                return -1;
 119        }
 120
 121        if (sel.update_flags == 0) {
 122                fprintf(stderr, "Illegal csum construct, empty <UPDATE> list\n");
 123                return -1;
 124        }
 125
 126        parse_action_control_dflt(&argc, &argv, &sel.action, false, TC_ACT_OK);
 127
 128        if (argc) {
 129                if (matches(*argv, "index") == 0) {
 130                        NEXT_ARG();
 131                        if (get_u32(&sel.index, *argv, 10)) {
 132                                fprintf(stderr, "Illegal \"index\" (%s) <csum>\n",
 133                                        *argv);
 134                                return -1;
 135                        }
 136                        argc--;
 137                        argv++;
 138                }
 139        }
 140
 141        tail = addattr_nest(n, MAX_MSG, tca_id);
 142        addattr_l(n, MAX_MSG, TCA_CSUM_PARMS, &sel, sizeof(sel));
 143        addattr_nest_end(n, tail);
 144
 145        *argc_p = argc;
 146        *argv_p = argv;
 147
 148        return 0;
 149}
 150
 151static int
 152print_csum(struct action_util *au, FILE *f, struct rtattr *arg)
 153{
 154        struct tc_csum *sel;
 155
 156        struct rtattr *tb[TCA_CSUM_MAX + 1];
 157
 158        char *uflag_1 = "";
 159        char *uflag_2 = "";
 160        char *uflag_3 = "";
 161        char *uflag_4 = "";
 162        char *uflag_5 = "";
 163        char *uflag_6 = "";
 164        char *uflag_7 = "";
 165        SPRINT_BUF(buf);
 166
 167        int uflag_count = 0;
 168
 169        print_string(PRINT_ANY, "kind", "%s ", "csum");
 170        if (arg == NULL)
 171                return 0;
 172
 173        parse_rtattr_nested(tb, TCA_CSUM_MAX, arg);
 174
 175        if (tb[TCA_CSUM_PARMS] == NULL) {
 176                fprintf(stderr, "Missing csum parameters\n");
 177                return -1;
 178        }
 179        sel = RTA_DATA(tb[TCA_CSUM_PARMS]);
 180
 181        if (sel->update_flags & TCA_CSUM_UPDATE_FLAG_IPV4HDR) {
 182                uflag_1 = "iph";
 183                uflag_count++;
 184        }
 185        #define CSUM_UFLAG_BUFFER(flag_buffer, flag_value, flag_string) \
 186                do {                                                    \
 187                        if (sel->update_flags & flag_value) {           \
 188                                flag_buffer = uflag_count > 0 ?         \
 189                                        ", " flag_string : flag_string; \
 190                                uflag_count++;                          \
 191                        }                                               \
 192                } while (0)
 193        CSUM_UFLAG_BUFFER(uflag_2, TCA_CSUM_UPDATE_FLAG_ICMP, "icmp");
 194        CSUM_UFLAG_BUFFER(uflag_3, TCA_CSUM_UPDATE_FLAG_IGMP, "igmp");
 195        CSUM_UFLAG_BUFFER(uflag_4, TCA_CSUM_UPDATE_FLAG_TCP, "tcp");
 196        CSUM_UFLAG_BUFFER(uflag_5, TCA_CSUM_UPDATE_FLAG_UDP, "udp");
 197        CSUM_UFLAG_BUFFER(uflag_6, TCA_CSUM_UPDATE_FLAG_UDPLITE, "udplite");
 198        CSUM_UFLAG_BUFFER(uflag_7, TCA_CSUM_UPDATE_FLAG_SCTP, "sctp");
 199        if (!uflag_count) {
 200                uflag_1 = "?empty";
 201        }
 202
 203        snprintf(buf, sizeof(buf), "%s%s%s%s%s%s%s",
 204                 uflag_1, uflag_2, uflag_3,
 205                 uflag_4, uflag_5, uflag_6, uflag_7);
 206        print_string(PRINT_ANY, "csum", "(%s) ", buf);
 207
 208        print_action_control(f, "action ", sel->action, _SL_);
 209        print_uint(PRINT_ANY, "index", "\tindex %u", sel->index);
 210        print_int(PRINT_ANY, "ref", " ref %d", sel->refcnt);
 211        print_int(PRINT_ANY, "bind", " bind %d", sel->bindcnt);
 212
 213        if (show_stats) {
 214                if (tb[TCA_CSUM_TM]) {
 215                        struct tcf_t *tm = RTA_DATA(tb[TCA_CSUM_TM]);
 216
 217                        print_tm(f, tm);
 218                }
 219        }
 220        print_nl();
 221
 222        return 0;
 223}
 224
 225struct action_util csum_action_util = {
 226        .id = "csum",
 227        .parse_aopt = parse_csum,
 228        .print_aopt = print_csum,
 229};
 230