/* * 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 #include #include #include #include #include #include #include #include #include "rt_names.h" #include "utils.h" #include "tc_util.h" #include static void skbmod_explain(void) { fprintf(stderr, "Usage:... skbmod {[set ] [swap ]} [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 \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, };