iproute2/tc/m_mirred.c
Stephen Hemminger d5ddb441a5 tc: print all error messages to stderr
Many tc modules were printing error messages to stdout.
This is problematic if using JSON or other output formats.
Change all these places to use fprintf(stderr, ...) instead.

Also, remove unnecessary initialization and places
where else is used after error return.

Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
2019-07-11 15:35:07 -07:00

330 lines
6.6 KiB
C

/*
* m_egress.c ingress/egress packet mirror/redir actions 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: J Hadi Salim (hadi@cyberus.ca)
*
* TODO: Add Ingress support
*
*/
#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_mirred.h>
static void
explain(void)
{
fprintf(stderr,
"Usage: mirred <DIRECTION> <ACTION> [index INDEX] <dev DEVICENAME>\n"
"where:\n"
"\tDIRECTION := <ingress | egress>\n"
"\tACTION := <mirror | redirect>\n"
"\tINDEX is the specific policy instance id\n"
"\tDEVICENAME is the devicename\n");
}
static void
usage(void)
{
explain();
exit(-1);
}
static const char *mirred_n2a(int action)
{
switch (action) {
case TCA_EGRESS_REDIR:
return "Egress Redirect";
case TCA_INGRESS_REDIR:
return "Ingress Redirect";
case TCA_EGRESS_MIRROR:
return "Egress Mirror";
case TCA_INGRESS_MIRROR:
return "Ingress Mirror";
default:
return "unknown";
}
}
static const char *mirred_direction(int action)
{
switch (action) {
case TCA_EGRESS_REDIR:
case TCA_EGRESS_MIRROR:
return "egress";
case TCA_INGRESS_REDIR:
case TCA_INGRESS_MIRROR:
return "ingress";
default:
return "unknown";
}
}
static const char *mirred_action(int action)
{
switch (action) {
case TCA_EGRESS_REDIR:
case TCA_INGRESS_REDIR:
return "redirect";
case TCA_EGRESS_MIRROR:
case TCA_INGRESS_MIRROR:
return "mirror";
default:
return "unknown";
}
}
static int
parse_direction(struct action_util *a, int *argc_p, char ***argv_p,
int tca_id, struct nlmsghdr *n)
{
int argc = *argc_p;
char **argv = *argv_p;
int ok = 0, iok = 0, mirror = 0, redir = 0, ingress = 0, egress = 0;
struct tc_mirred p = {};
struct rtattr *tail;
char d[IFNAMSIZ] = {};
while (argc > 0) {
if (matches(*argv, "action") == 0) {
NEXT_ARG();
break;
} else if (!egress && matches(*argv, "egress") == 0) {
egress = 1;
if (ingress) {
fprintf(stderr,
"Can't have both egress and ingress\n");
return -1;
}
NEXT_ARG();
ok++;
continue;
} else if (!ingress && matches(*argv, "ingress") == 0) {
ingress = 1;
if (egress) {
fprintf(stderr,
"Can't have both ingress and egress\n");
return -1;
}
NEXT_ARG();
ok++;
continue;
} else {
if (matches(*argv, "index") == 0) {
NEXT_ARG();
if (get_u32(&p.index, *argv, 10)) {
fprintf(stderr, "Illegal \"index\"\n");
return -1;
}
iok++;
if (!ok) {
argc--;
argv++;
break;
}
} else if (!ok) {
fprintf(stderr,
"was expecting egress or ingress (%s)\n",
*argv);
break;
} else if (!mirror && matches(*argv, "mirror") == 0) {
mirror = 1;
if (redir) {
fprintf(stderr,
"Can't have both mirror and redir\n");
return -1;
}
p.eaction = egress ? TCA_EGRESS_MIRROR :
TCA_INGRESS_MIRROR;
p.action = TC_ACT_PIPE;
ok++;
} else if (!redir && matches(*argv, "redirect") == 0) {
redir = 1;
if (mirror) {
fprintf(stderr,
"Can't have both mirror and redir\n");
return -1;
}
p.eaction = egress ? TCA_EGRESS_REDIR :
TCA_INGRESS_REDIR;
p.action = TC_ACT_STOLEN;
ok++;
} else if ((redir || mirror) &&
matches(*argv, "dev") == 0) {
NEXT_ARG();
if (strlen(d))
duparg("dev", *argv);
strncpy(d, *argv, sizeof(d)-1);
argc--;
argv++;
break;
}
}
NEXT_ARG();
}
if (!ok && !iok)
return -1;
if (d[0]) {
int idx;
ll_init_map(&rth);
idx = ll_name_to_index(d);
if (!idx)
return nodev(d);
p.ifindex = idx;
}
if (p.eaction == TCA_EGRESS_MIRROR || p.eaction == TCA_INGRESS_MIRROR)
parse_action_control_dflt(&argc, &argv, &p.action, false,
TC_ACT_PIPE);
if (argc) {
if (iok && matches(*argv, "index") == 0) {
fprintf(stderr, "mirred: Illegal double index\n");
return -1;
}
if (matches(*argv, "index") == 0) {
NEXT_ARG();
if (get_u32(&p.index, *argv, 10)) {
fprintf(stderr,
"mirred: Illegal \"index\"\n");
return -1;
}
argc--;
argv++;
}
}
tail = addattr_nest(n, MAX_MSG, tca_id);
addattr_l(n, MAX_MSG, TCA_MIRRED_PARMS, &p, sizeof(p));
addattr_nest_end(n, tail);
*argc_p = argc;
*argv_p = argv;
return 0;
}
static int
parse_mirred(struct action_util *a, int *argc_p, char ***argv_p,
int tca_id, struct nlmsghdr *n)
{
int argc = *argc_p;
char **argv = *argv_p;
if (argc < 0) {
fprintf(stderr, "mirred bad argument count %d\n", argc);
return -1;
}
if (matches(*argv, "mirred") == 0) {
NEXT_ARG();
} else {
fprintf(stderr, "mirred bad argument %s\n", *argv);
return -1;
}
if (matches(*argv, "egress") == 0 || matches(*argv, "ingress") == 0 ||
matches(*argv, "index") == 0) {
int ret = parse_direction(a, &argc, &argv, tca_id, n);
if (ret == 0) {
*argc_p = argc;
*argv_p = argv;
return 0;
}
} else if (matches(*argv, "help") == 0) {
usage();
} else {
fprintf(stderr, "mirred option not supported %s\n", *argv);
}
return -1;
}
static int
print_mirred(struct action_util *au, FILE *f, struct rtattr *arg)
{
struct tc_mirred *p;
struct rtattr *tb[TCA_MIRRED_MAX + 1];
const char *dev;
if (arg == NULL)
return -1;
parse_rtattr_nested(tb, TCA_MIRRED_MAX, arg);
if (tb[TCA_MIRRED_PARMS] == NULL) {
fprintf(stderr, "Missing mirred parameters\n");
return -1;
}
p = RTA_DATA(tb[TCA_MIRRED_PARMS]);
dev = ll_index_to_name(p->ifindex);
if (dev == 0) {
fprintf(stderr, "Cannot find device %d\n", p->ifindex);
return -1;
}
print_string(PRINT_ANY, "kind", "%s ", "mirred");
print_string(PRINT_FP, NULL, "(%s", mirred_n2a(p->eaction));
print_string(PRINT_JSON, "mirred_action", NULL,
mirred_action(p->eaction));
print_string(PRINT_JSON, "direction", NULL,
mirred_direction(p->eaction));
print_string(PRINT_ANY, "to_dev", " to device %s)", dev);
print_action_control(f, " ", p->action, "");
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_MIRRED_TM]) {
struct tcf_t *tm = RTA_DATA(tb[TCA_MIRRED_TM]);
print_tm(f, tm);
}
}
print_string(PRINT_FP, NULL, "%s", "\n ");
return 0;
}
struct action_util mirred_action_util = {
.id = "mirred",
.parse_aopt = parse_mirred,
.print_aopt = print_mirred,
};