tc/pedit: p_eth: ETH header editor

For example, forward tcp traffic to veth0 and set
destination mac address to 11:22:33:44:55:66 :
$ tc filter add dev enp0s9 protocol ip parent ffff: \
    flower \
      ip_proto tcp \
    action pedit ex munge \
      eth dst set 11:22:33:44:55:66 \
    action mirred egress \
      redirect dev veth0

Signed-off-by: Amir Vadai <amir@vadai.me>
This commit is contained in:
Amir Vadai 2017-04-23 15:53:54 +03:00 committed by Stephen Hemminger
parent fa4652ff3b
commit 3cd5149ecd
5 changed files with 144 additions and 0 deletions

View File

@ -27,11 +27,17 @@ pedit - generic packet editor action
.ti -8 .ti -8
.IR EXTENDED_LAYERED_OP " := { " .IR EXTENDED_LAYERED_OP " := { "
.BI eth " ETHHDR_FIELD"
|
.BI ip " IPHDR_FIELD" .BI ip " IPHDR_FIELD"
| |
.BI ip " EX_IPHDR_FIELD" .BI ip " EX_IPHDR_FIELD"
.RI } " CMD_SPEC" .RI } " CMD_SPEC"
.ti -8
.IR ETHHDR_FIELD " := { "
.BR src " | " dst " | " type " }"
.ti -8 .ti -8
.IR IPHDR_FIELD " := { " .IR IPHDR_FIELD " := { "
.BR src " | " dst " | " tos " | " dsfield " | " ihl " | " protocol " |" .BR src " | " dst " | " tos " | " dsfield " | " ihl " | " protocol " |"
@ -103,6 +109,21 @@ and right-shifted by
before adding it to before adding it to
.IR OFFSET . .IR OFFSET .
.TP .TP
.BI eth " ETHHDR_FIELD"
Change an ETH header field. The supported keywords for
.I ETHHDR_FIELD
are:
.RS
.TP
.B src
.TQ
.B dst
Source or destination MAC address in the standard format: XX:XX:XX:XX:XX:XX
.TP
.B type
Ether-type in numeric value
.RE
.TP
.BI ip " IPHDR_FIELD" .BI ip " IPHDR_FIELD"
Change an IPv4 header field. The supported keywords for Change an IPv4 header field. The supported keywords for
.I IPHDR_FIELD .I IPHDR_FIELD
@ -269,6 +290,9 @@ tc filter add dev eth0 parent ffff: u32 \\
tc filter add dev eth0 parent ffff: u32 \\ tc filter add dev eth0 parent ffff: u32 \\
match ip sport 22 0xffff \\ match ip sport 22 0xffff \\
action pedit ex munge ip dst set 192.168.1.199 action pedit ex munge ip dst set 192.168.1.199
tc filter add dev eth0 parent ffff: u32 \\
match ip sport 22 0xffff \\
action pedit ex munge eth dst set 11:22:33:44:55:66
.EE .EE
.RE .RE
.SH SEE ALSO .SH SEE ALSO

View File

@ -54,6 +54,7 @@ TCMODULES += m_tunnel_key.o
TCMODULES += m_sample.o TCMODULES += m_sample.o
TCMODULES += p_ip.o TCMODULES += p_ip.o
TCMODULES += p_icmp.o TCMODULES += p_icmp.o
TCMODULES += p_eth.o
TCMODULES += p_tcp.o TCMODULES += p_tcp.o
TCMODULES += p_udp.o TCMODULES += p_udp.o
TCMODULES += em_nbyte.o TCMODULES += em_nbyte.o

View File

@ -28,6 +28,7 @@
#include "utils.h" #include "utils.h"
#include "tc_util.h" #include "tc_util.h"
#include "m_pedit.h" #include "m_pedit.h"
#include "rt_names.h"
static struct m_pedit_util *pedit_list; static struct m_pedit_util *pedit_list;
static int pedit_debug; static int pedit_debug;
@ -223,6 +224,38 @@ int pack_key8(__u32 retain, struct m_pedit_sel *sel, struct m_pedit_key *tkey)
return pack_key(sel, tkey); return pack_key(sel, tkey);
} }
static int pack_mac(struct m_pedit_sel *sel, struct m_pedit_key *tkey,
__u8 *mac)
{
int ret = 0;
if (!(tkey->off & 0x3)) {
tkey->mask = 0;
tkey->val = ntohl(*((__u32 *)mac));
ret |= pack_key32(~0, sel, tkey);
tkey->off += 4;
tkey->mask = 0;
tkey->val = ntohs(*((__u16 *)&mac[4]));
ret |= pack_key16(~0, sel, tkey);
} else if (!(tkey->off & 0x1)) {
tkey->mask = 0;
tkey->val = ntohs(*((__u16 *)mac));
ret |= pack_key16(~0, sel, tkey);
tkey->off += 4;
tkey->mask = 0;
tkey->val = ntohl(*((__u32 *)(mac + 2)));
ret |= pack_key32(~0, sel, tkey);
} else {
fprintf(stderr,
"pack_mac: mac offsets must begin in 32bit or 16bit boundaries\n");
return -1;
}
return ret;
}
int parse_val(int *argc_p, char ***argv_p, __u32 *val, int type) int parse_val(int *argc_p, char ***argv_p, __u32 *val, int type)
{ {
int argc = *argc_p; int argc = *argc_p;
@ -250,6 +283,14 @@ int parse_val(int *argc_p, char ***argv_p, __u32 *val, int type)
if (type == TIPV6) if (type == TIPV6)
return -1; /* not implemented yet */ return -1; /* not implemented yet */
if (type == TMAC) {
#define MAC_ALEN 6
int ret = ll_addr_a2n((char *)val, MAC_ALEN, *argv);
if (ret == MAC_ALEN)
return 0;
}
return -1; return -1;
} }
@ -310,6 +351,11 @@ int parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type, __u32 retain,
argv++; argv++;
} }
if (type == TMAC) {
res = pack_mac(sel, tkey, (__u8 *)val);
goto done;
}
tkey->val = *v; tkey->val = *v;
tkey->mask = *m; tkey->mask = *m;

View File

@ -32,6 +32,7 @@
#define TIPV6 2 #define TIPV6 2
#define TINT 3 #define TINT 3
#define TU32 4 #define TU32 4
#define TMAC 5
#define RU32 0xFFFFFFFF #define RU32 0xFFFFFFFF
#define RU16 0xFFFF #define RU16 0xFFFF

72
tc/p_eth.c Normal file
View File

@ -0,0 +1,72 @@
/*
* m_pedit_eth.c packet editor: ETH header
*
* 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: Amir Vadai (amir@vadai.me)
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <syslog.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 "m_pedit.h"
static int
parse_eth(int *argc_p, char ***argv_p,
struct m_pedit_sel *sel, struct m_pedit_key *tkey)
{
int res = -1;
int argc = *argc_p;
char **argv = *argv_p;
if (argc < 2)
return -1;
tkey->htype = TCA_PEDIT_KEY_EX_HDR_TYPE_ETH;
if (strcmp(*argv, "type") == 0) {
NEXT_ARG();
tkey->off = 12;
res = parse_cmd(&argc, &argv, 2, TU32, RU16, sel, tkey);
goto done;
}
if (strcmp(*argv, "dst") == 0) {
NEXT_ARG();
tkey->off = 0;
res = parse_cmd(&argc, &argv, 6, TMAC, RU32, sel, tkey);
goto done;
}
if (strcmp(*argv, "src") == 0) {
NEXT_ARG();
tkey->off = 6;
res = parse_cmd(&argc, &argv, 6, TMAC, RU32, sel, tkey);
goto done;
}
return -1;
done:
*argc_p = argc;
*argv_p = argv;
return res;
}
struct m_pedit_util p_pedit_eth = {
NULL,
"eth",
parse_eth,
};