mirror_iproute2/tc/m_skbmod.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

235 lines
5.4 KiB
C

/*
* m_skbmod.c skb modifier action 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 (jhs@mojatatu.com)
*
*/
#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 <linux/netdevice.h>
#include "rt_names.h"
#include "utils.h"
#include "tc_util.h"
#include <linux/tc_act/tc_skbmod.h>
static void skbmod_explain(void)
{
fprintf(stderr,
"Usage:... skbmod {[set <SETTABLE>] [swap <SWAPABLE>]} [CONTROL] [index INDEX]\n"
"where SETTABLE is: [dmac DMAC] [smac SMAC] [etype ETYPE]\n"
"where SWAPABLE is: \"mac\" to swap mac addresses\n"
"note: \"swap mac\" is done after any outstanding D/SMAC change\n"
"\tDMAC := 6 byte Destination MAC address\n"
"\tSMAC := optional 6 byte Source MAC address\n"
"\tETYPE := optional 16 bit ethertype\n"
"\tCONTROL := reclassify | pipe | drop | continue | ok |\n"
"\t goto chain <CHAIN_INDEX>\n"
"\tINDEX := skbmod index value to use\n");
}
static void skbmod_usage(void)
{
skbmod_explain();
exit(-1);
}
static int parse_skbmod(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;
struct tc_skbmod p;
struct rtattr *tail;
char dbuf[ETH_ALEN];
char sbuf[ETH_ALEN];
__u16 skbmod_etype = 0;
char *daddr = NULL;
char *saddr = NULL;
memset(&p, 0, sizeof(p));
if (argc <= 0)
return -1;
while (argc > 0) {
if (matches(*argv, "skbmod") == 0) {
NEXT_ARG();
continue;
} else if (matches(*argv, "swap") == 0) {
NEXT_ARG();
continue;
} else if (matches(*argv, "mac") == 0) {
p.flags |= SKBMOD_F_SWAPMAC;
ok += 1;
} else if (matches(*argv, "set") == 0) {
NEXT_ARG();
continue;
} else if (matches(*argv, "etype") == 0) {
NEXT_ARG();
if (get_u16(&skbmod_etype, *argv, 0))
invarg("ethertype is invalid", *argv);
fprintf(stderr, "skbmod etype 0x%x\n", skbmod_etype);
p.flags |= SKBMOD_F_ETYPE;
ok += 1;
} else if (matches(*argv, "dmac") == 0) {
NEXT_ARG();
daddr = *argv;
if (sscanf(daddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
dbuf, dbuf + 1, dbuf + 2,
dbuf + 3, dbuf + 4, dbuf + 5) != 6) {
fprintf(stderr, "Invalid dst mac address %s\n",
daddr);
return -1;
}
p.flags |= SKBMOD_F_DMAC;
fprintf(stderr, "dst MAC address <%s>\n", daddr);
ok += 1;
} else if (matches(*argv, "smac") == 0) {
NEXT_ARG();
saddr = *argv;
if (sscanf(saddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
sbuf, sbuf + 1, sbuf + 2,
sbuf + 3, sbuf + 4, sbuf + 5) != 6) {
fprintf(stderr, "Invalid smac address %s\n",
saddr);
return -1;
}
p.flags |= SKBMOD_F_SMAC;
fprintf(stderr, "src MAC address <%s>\n", saddr);
ok += 1;
} else if (matches(*argv, "help") == 0) {
skbmod_usage();
} else {
break;
}
argc--;
argv++;
}
parse_action_control_dflt(&argc, &argv, &p.action, false, TC_ACT_PIPE);
if (argc) {
if (matches(*argv, "index") == 0) {
NEXT_ARG();
if (get_u32(&p.index, *argv, 0)) {
fprintf(stderr, "skbmod: Illegal \"index\"\n");
return -1;
}
ok++;
argc--;
argv++;
}
}
if (!ok) {
fprintf(stderr, "skbmod requires at least one option\n");
skbmod_usage();
}
tail = addattr_nest(n, MAX_MSG, tca_id);
addattr_l(n, MAX_MSG, TCA_SKBMOD_PARMS, &p, sizeof(p));
if (daddr)
addattr_l(n, MAX_MSG, TCA_SKBMOD_DMAC, dbuf, ETH_ALEN);
if (skbmod_etype)
addattr16(n, MAX_MSG, TCA_SKBMOD_ETYPE, skbmod_etype);
if (saddr)
addattr_l(n, MAX_MSG, TCA_SKBMOD_SMAC, sbuf, ETH_ALEN);
addattr_nest_end(n, tail);
*argc_p = argc;
*argv_p = argv;
return 0;
}
static int print_skbmod(struct action_util *au, FILE *f, struct rtattr *arg)
{
struct tc_skbmod *p;
struct rtattr *tb[TCA_SKBMOD_MAX + 1];
__u16 skbmod_etype = 0;
int has_optional = 0;
SPRINT_BUF(b1);
SPRINT_BUF(b2);
if (arg == NULL)
return -1;
parse_rtattr_nested(tb, TCA_SKBMOD_MAX, arg);
if (tb[TCA_SKBMOD_PARMS] == NULL) {
fprintf(stderr, "Missing skbmod parameters\n");
return -1;
}
p = RTA_DATA(tb[TCA_SKBMOD_PARMS]);
fprintf(f, "skbmod ");
print_action_control(f, "", p->action, " ");
if (tb[TCA_SKBMOD_ETYPE]) {
skbmod_etype = rta_getattr_u16(tb[TCA_SKBMOD_ETYPE]);
has_optional = 1;
fprintf(f, "set etype 0x%X ", skbmod_etype);
}
if (has_optional)
fprintf(f, "\n\t ");
if (tb[TCA_SKBMOD_DMAC]) {
has_optional = 1;
fprintf(f, "set dmac %s ",
ll_addr_n2a(RTA_DATA(tb[TCA_SKBMOD_DMAC]),
RTA_PAYLOAD(tb[TCA_SKBMOD_DMAC]), 0, b1,
sizeof(b1)));
}
if (tb[TCA_SKBMOD_SMAC]) {
has_optional = 1;
fprintf(f, "set smac %s ",
ll_addr_n2a(RTA_DATA(tb[TCA_SKBMOD_SMAC]),
RTA_PAYLOAD(tb[TCA_SKBMOD_SMAC]), 0, b2,
sizeof(b2)));
}
if (p->flags & SKBMOD_F_SWAPMAC)
fprintf(f, "swap mac ");
fprintf(f, "\n\t index %u ref %d bind %d", p->index, p->refcnt,
p->bindcnt);
if (show_stats) {
if (tb[TCA_SKBMOD_TM]) {
struct tcf_t *tm = RTA_DATA(tb[TCA_SKBMOD_TM]);
print_tm(f, tm);
}
}
fprintf(f, "\n");
return 0;
}
struct action_util skbmod_action_util = {
.id = "skbmod",
.parse_aopt = parse_skbmod,
.print_aopt = print_skbmod,
};