iproute2/tc/m_mirred.c
<<
>>
Prefs
   1/*
   2 * m_egress.c           ingress/egress packet mirror/redir actions module
   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:  J Hadi Salim (hadi@cyberus.ca)
  10 *
  11 * TODO: Add Ingress support
  12 *
  13 */
  14
  15#include <stdio.h>
  16#include <stdlib.h>
  17#include <unistd.h>
  18#include <fcntl.h>
  19#include <sys/socket.h>
  20#include <netinet/in.h>
  21#include <arpa/inet.h>
  22#include <string.h>
  23#include "utils.h"
  24#include "tc_util.h"
  25#include "tc_common.h"
  26#include <linux/tc_act/tc_mirred.h>
  27
  28static void
  29explain(void)
  30{
  31        fprintf(stderr,
  32                "Usage: mirred <DIRECTION> <ACTION> [index INDEX] <dev DEVICENAME>\n"
  33                "where:\n"
  34                "\tDIRECTION := <ingress | egress>\n"
  35                "\tACTION := <mirror | redirect>\n"
  36                "\tINDEX  is the specific policy instance id\n"
  37                "\tDEVICENAME is the devicename\n");
  38}
  39
  40static void
  41usage(void)
  42{
  43        explain();
  44        exit(-1);
  45}
  46
  47static const char *mirred_n2a(int action)
  48{
  49        switch (action) {
  50        case TCA_EGRESS_REDIR:
  51                return "Egress Redirect";
  52        case TCA_INGRESS_REDIR:
  53                return "Ingress Redirect";
  54        case TCA_EGRESS_MIRROR:
  55                return "Egress Mirror";
  56        case TCA_INGRESS_MIRROR:
  57                return "Ingress Mirror";
  58        default:
  59                return "unknown";
  60        }
  61}
  62
  63static const char *mirred_direction(int action)
  64{
  65        switch (action) {
  66        case TCA_EGRESS_REDIR:
  67        case TCA_EGRESS_MIRROR:
  68                return "egress";
  69        case TCA_INGRESS_REDIR:
  70        case TCA_INGRESS_MIRROR:
  71                return "ingress";
  72        default:
  73                return "unknown";
  74        }
  75}
  76
  77static const char *mirred_action(int action)
  78{
  79        switch (action) {
  80        case TCA_EGRESS_REDIR:
  81        case TCA_INGRESS_REDIR:
  82                return "redirect";
  83        case TCA_EGRESS_MIRROR:
  84        case TCA_INGRESS_MIRROR:
  85                return "mirror";
  86        default:
  87                return "unknown";
  88        }
  89}
  90
  91static int
  92parse_direction(struct action_util *a, int *argc_p, char ***argv_p,
  93                int tca_id, struct nlmsghdr *n)
  94{
  95
  96        int argc = *argc_p;
  97        char **argv = *argv_p;
  98        int ok = 0, iok = 0, mirror = 0, redir = 0, ingress = 0, egress = 0;
  99        struct tc_mirred p = {};
 100        struct rtattr *tail;
 101        char d[IFNAMSIZ] = {};
 102
 103        while (argc > 0) {
 104
 105                if (matches(*argv, "action") == 0) {
 106                        NEXT_ARG();
 107                        break;
 108                } else if (!egress && matches(*argv, "egress") == 0) {
 109                        egress = 1;
 110                        if (ingress) {
 111                                fprintf(stderr,
 112                                        "Can't have both egress and ingress\n");
 113                                return -1;
 114                        }
 115                        NEXT_ARG();
 116                        ok++;
 117                        continue;
 118                } else if (!ingress && matches(*argv, "ingress") == 0) {
 119                        ingress = 1;
 120                        if (egress) {
 121                                fprintf(stderr,
 122                                        "Can't have both ingress and egress\n");
 123                                return -1;
 124                        }
 125                        NEXT_ARG();
 126                        ok++;
 127                        continue;
 128                } else {
 129
 130                        if (matches(*argv, "index") == 0) {
 131                                NEXT_ARG();
 132                                if (get_u32(&p.index, *argv, 10)) {
 133                                        fprintf(stderr, "Illegal \"index\"\n");
 134                                        return -1;
 135                                }
 136                                iok++;
 137                                if (!ok) {
 138                                        argc--;
 139                                        argv++;
 140                                        break;
 141                                }
 142                        } else if (!ok) {
 143                                fprintf(stderr,
 144                                        "was expecting egress or ingress (%s)\n",
 145                                        *argv);
 146                                break;
 147
 148                        } else if (!mirror && matches(*argv, "mirror") == 0) {
 149                                mirror = 1;
 150                                if (redir) {
 151                                        fprintf(stderr,
 152                                                "Can't have both mirror and redir\n");
 153                                        return -1;
 154                                }
 155                                p.eaction = egress ? TCA_EGRESS_MIRROR :
 156                                        TCA_INGRESS_MIRROR;
 157                                p.action = TC_ACT_PIPE;
 158                                ok++;
 159                        } else if (!redir && matches(*argv, "redirect") == 0) {
 160                                redir = 1;
 161                                if (mirror) {
 162                                        fprintf(stderr,
 163                                                "Can't have both mirror and redir\n");
 164                                        return -1;
 165                                }
 166                                p.eaction = egress ? TCA_EGRESS_REDIR :
 167                                        TCA_INGRESS_REDIR;
 168                                p.action = TC_ACT_STOLEN;
 169                                ok++;
 170                        } else if ((redir || mirror) &&
 171                                   matches(*argv, "dev") == 0) {
 172                                NEXT_ARG();
 173                                if (strlen(d))
 174                                        duparg("dev", *argv);
 175
 176                                strncpy(d, *argv, sizeof(d)-1);
 177                                argc--;
 178                                argv++;
 179
 180                                break;
 181
 182                        }
 183                }
 184
 185                NEXT_ARG();
 186        }
 187
 188        if (!ok && !iok)
 189                return -1;
 190
 191        if (d[0])  {
 192                int idx;
 193
 194                ll_init_map(&rth);
 195
 196                idx = ll_name_to_index(d);
 197                if (!idx)
 198                        return nodev(d);
 199
 200                p.ifindex = idx;
 201        }
 202
 203
 204        if (p.eaction == TCA_EGRESS_MIRROR || p.eaction == TCA_INGRESS_MIRROR)
 205                parse_action_control_dflt(&argc, &argv, &p.action, false,
 206                                          TC_ACT_PIPE);
 207
 208        if (argc) {
 209                if (iok && matches(*argv, "index") == 0) {
 210                        fprintf(stderr, "mirred: Illegal double index\n");
 211                        return -1;
 212                }
 213
 214                if (matches(*argv, "index") == 0) {
 215                        NEXT_ARG();
 216                        if (get_u32(&p.index, *argv, 10)) {
 217                                fprintf(stderr,
 218                                        "mirred: Illegal \"index\"\n");
 219                                return -1;
 220                        }
 221                        argc--;
 222                        argv++;
 223                }
 224        }
 225
 226        tail = addattr_nest(n, MAX_MSG, tca_id);
 227        addattr_l(n, MAX_MSG, TCA_MIRRED_PARMS, &p, sizeof(p));
 228        addattr_nest_end(n, tail);
 229
 230        *argc_p = argc;
 231        *argv_p = argv;
 232        return 0;
 233}
 234
 235
 236static int
 237parse_mirred(struct action_util *a, int *argc_p, char ***argv_p,
 238             int tca_id, struct nlmsghdr *n)
 239{
 240
 241        int argc = *argc_p;
 242        char **argv = *argv_p;
 243
 244        if (argc < 0) {
 245                fprintf(stderr, "mirred bad argument count %d\n", argc);
 246                return -1;
 247        }
 248
 249        if (matches(*argv, "mirred") == 0) {
 250                NEXT_ARG();
 251        } else {
 252                fprintf(stderr, "mirred bad argument %s\n", *argv);
 253                return -1;
 254        }
 255
 256
 257        if (matches(*argv, "egress") == 0 || matches(*argv, "ingress") == 0 ||
 258            matches(*argv, "index") == 0) {
 259                int ret = parse_direction(a, &argc, &argv, tca_id, n);
 260
 261                if (ret == 0) {
 262                        *argc_p = argc;
 263                        *argv_p = argv;
 264                        return 0;
 265                }
 266
 267        } else if (matches(*argv, "help") == 0) {
 268                usage();
 269        } else {
 270                fprintf(stderr, "mirred option not supported %s\n", *argv);
 271        }
 272
 273        return -1;
 274
 275}
 276
 277static int
 278print_mirred(struct action_util *au, FILE *f, struct rtattr *arg)
 279{
 280        struct tc_mirred *p;
 281        struct rtattr *tb[TCA_MIRRED_MAX + 1];
 282        const char *dev;
 283
 284        print_string(PRINT_ANY, "kind", "%s ", "mirred");
 285        if (arg == NULL)
 286                return 0;
 287
 288        parse_rtattr_nested(tb, TCA_MIRRED_MAX, arg);
 289
 290        if (tb[TCA_MIRRED_PARMS] == NULL) {
 291                fprintf(stderr, "Missing mirred parameters\n");
 292                return -1;
 293        }
 294        p = RTA_DATA(tb[TCA_MIRRED_PARMS]);
 295
 296        dev = ll_index_to_name(p->ifindex);
 297        if (dev == 0) {
 298                fprintf(stderr, "Cannot find device %d\n", p->ifindex);
 299                return -1;
 300        }
 301
 302        print_string(PRINT_FP, NULL, "(%s", mirred_n2a(p->eaction));
 303        print_string(PRINT_JSON, "mirred_action", NULL,
 304                     mirred_action(p->eaction));
 305        print_string(PRINT_JSON, "direction", NULL,
 306                     mirred_direction(p->eaction));
 307        print_string(PRINT_ANY, "to_dev", " to device %s)", dev);
 308        print_action_control(f, " ", p->action, "");
 309
 310        print_nl();
 311        print_uint(PRINT_ANY, "index", "\tindex %u", p->index);
 312        print_int(PRINT_ANY, "ref", " ref %d", p->refcnt);
 313        print_int(PRINT_ANY, "bind", " bind %d", p->bindcnt);
 314
 315        if (show_stats) {
 316                if (tb[TCA_MIRRED_TM]) {
 317                        struct tcf_t *tm = RTA_DATA(tb[TCA_MIRRED_TM]);
 318
 319                        print_tm(f, tm);
 320                }
 321        }
 322        print_nl();
 323        return 0;
 324}
 325
 326struct action_util mirred_action_util = {
 327        .id = "mirred",
 328        .parse_aopt = parse_mirred,
 329        .print_aopt = print_mirred,
 330};
 331