Merge branch 'master' into net-next

This commit is contained in:
Stephen Hemminger 2017-05-01 09:26:51 -07:00
commit d2b9100a08
12 changed files with 662 additions and 89 deletions

View File

@ -63,7 +63,8 @@ void iplink_usage(void)
" [ { up | down } ]\n" " [ { up | down } ]\n"
" [ type TYPE ARGS ]\n"); " [ type TYPE ARGS ]\n");
} else } else
fprintf(stderr, "Usage: ip link set DEVICE [ { up | down } ]\n"); fprintf(stderr,
"Usage: ip link set DEVICE [ { up | down } ]\n");
fprintf(stderr, fprintf(stderr,
" [ arp { on | off } ]\n" " [ arp { on | off } ]\n"
@ -72,6 +73,7 @@ void iplink_usage(void)
" [ allmulticast { on | off } ]\n" " [ allmulticast { on | off } ]\n"
" [ promisc { on | off } ]\n" " [ promisc { on | off } ]\n"
" [ trailers { on | off } ]\n" " [ trailers { on | off } ]\n"
" [ carrier { on | off } ]\n"
" [ txqueuelen PACKETS ]\n" " [ txqueuelen PACKETS ]\n"
" [ name NEWNAME ]\n" " [ name NEWNAME ]\n"
" [ address LLADDR ]\n" " [ address LLADDR ]\n"
@ -297,7 +299,8 @@ static void iplink_parse_vf_vlan_info(int vf, int *argcp, char ***argvp,
SPRINT_BUF(b2); SPRINT_BUF(b2);
char msg[64 + sizeof(b1) + sizeof(b2)]; char msg[64 + sizeof(b1) + sizeof(b2)];
sprintf(msg, "Invalid \"vlan protocol\" value - supported %s, %s\n", sprintf(msg,
"Invalid \"vlan protocol\" value - supported %s, %s\n",
ll_proto_n2a(htons(ETH_P_8021Q), ll_proto_n2a(htons(ETH_P_8021Q),
b1, sizeof(b1)), b1, sizeof(b1)),
ll_proto_n2a(htons(ETH_P_8021AD), ll_proto_n2a(htons(ETH_P_8021AD),
@ -582,14 +585,16 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
addr_len = ll_addr_a2n(abuf, sizeof(abuf), *argv); addr_len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
if (addr_len < 0) if (addr_len < 0)
return -1; return -1;
addattr_l(&req->n, sizeof(*req), IFLA_ADDRESS, abuf, addr_len); addattr_l(&req->n, sizeof(*req),
IFLA_ADDRESS, abuf, addr_len);
} else if (matches(*argv, "broadcast") == 0 || } else if (matches(*argv, "broadcast") == 0 ||
strcmp(*argv, "brd") == 0) { strcmp(*argv, "brd") == 0) {
NEXT_ARG(); NEXT_ARG();
len = ll_addr_a2n(abuf, sizeof(abuf), *argv); len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
if (len < 0) if (len < 0)
return -1; return -1;
addattr_l(&req->n, sizeof(*req), IFLA_BROADCAST, abuf, len); addattr_l(&req->n, sizeof(*req),
IFLA_BROADCAST, abuf, len);
} else if (matches(*argv, "txqueuelen") == 0 || } else if (matches(*argv, "txqueuelen") == 0 ||
strcmp(*argv, "qlen") == 0 || strcmp(*argv, "qlen") == 0 ||
matches(*argv, "txqlen") == 0) { matches(*argv, "txqlen") == 0) {
@ -598,7 +603,8 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
duparg("txqueuelen", *argv); duparg("txqueuelen", *argv);
if (get_integer(&qlen, *argv, 0)) if (get_integer(&qlen, *argv, 0))
invarg("Invalid \"txqueuelen\" value\n", *argv); invarg("Invalid \"txqueuelen\" value\n", *argv);
addattr_l(&req->n, sizeof(*req), IFLA_TXQLEN, &qlen, 4); addattr_l(&req->n, sizeof(*req),
IFLA_TXQLEN, &qlen, 4);
} else if (strcmp(*argv, "mtu") == 0) { } else if (strcmp(*argv, "mtu") == 0) {
NEXT_ARG(); NEXT_ARG();
if (mtu != -1) if (mtu != -1)
@ -619,8 +625,8 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_FD, addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_FD,
&netns, 4); &netns, 4);
else if (get_integer(&netns, *argv, 0) == 0) else if (get_integer(&netns, *argv, 0) == 0)
addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID, addattr_l(&req->n, sizeof(*req),
&netns, 4); IFLA_NET_NS_PID, &netns, 4);
else else
invarg("Invalid \"netns\" value\n", *argv); invarg("Invalid \"netns\" value\n", *argv);
} else if (strcmp(*argv, "multicast") == 0) { } else if (strcmp(*argv, "multicast") == 0) {
@ -673,6 +679,18 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
req->i.ifi_flags |= IFF_NOARP; req->i.ifi_flags |= IFF_NOARP;
else else
return on_off("arp", *argv); return on_off("arp", *argv);
} else if (strcmp(*argv, "carrier") == 0) {
int carrier;
NEXT_ARG();
if (strcmp(*argv, "on") == 0)
carrier = 1;
else if (strcmp(*argv, "off") == 0)
carrier = 0;
else
return on_off("carrier", *argv);
addattr8(&req->n, sizeof(*req), IFLA_CARRIER, carrier);
} else if (strcmp(*argv, "vf") == 0) { } else if (strcmp(*argv, "vf") == 0) {
struct rtattr *vflist; struct rtattr *vflist;
@ -763,7 +781,8 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
if (numtxqueues != -1) if (numtxqueues != -1)
duparg("numtxqueues", *argv); duparg("numtxqueues", *argv);
if (get_integer(&numtxqueues, *argv, 0)) if (get_integer(&numtxqueues, *argv, 0))
invarg("Invalid \"numtxqueues\" value\n", *argv); invarg("Invalid \"numtxqueues\" value\n",
*argv);
addattr_l(&req->n, sizeof(*req), IFLA_NUM_TX_QUEUES, addattr_l(&req->n, sizeof(*req), IFLA_NUM_TX_QUEUES,
&numtxqueues, 4); &numtxqueues, 4);
} else if (matches(*argv, "numrxqueues") == 0) { } else if (matches(*argv, "numrxqueues") == 0) {
@ -771,7 +790,8 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
if (numrxqueues != -1) if (numrxqueues != -1)
duparg("numrxqueues", *argv); duparg("numrxqueues", *argv);
if (get_integer(&numrxqueues, *argv, 0)) if (get_integer(&numrxqueues, *argv, 0))
invarg("Invalid \"numrxqueues\" value\n", *argv); invarg("Invalid \"numrxqueues\" value\n",
*argv);
addattr_l(&req->n, sizeof(*req), IFLA_NUM_RX_QUEUES, addattr_l(&req->n, sizeof(*req), IFLA_NUM_RX_QUEUES,
&numrxqueues, 4); &numrxqueues, 4);
} else if (matches(*argv, "addrgenmode") == 0) { } else if (matches(*argv, "addrgenmode") == 0) {
@ -781,7 +801,8 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
NEXT_ARG(); NEXT_ARG();
mode = get_addr_gen_mode(*argv); mode = get_addr_gen_mode(*argv);
if (mode < 0) if (mode < 0)
invarg("Invalid address generation mode\n", *argv); invarg("Invalid address generation mode\n",
*argv);
afs = addattr_nest(&req->n, sizeof(*req), IFLA_AF_SPEC); afs = addattr_nest(&req->n, sizeof(*req), IFLA_AF_SPEC);
afs6 = addattr_nest(&req->n, sizeof(*req), AF_INET6); afs6 = addattr_nest(&req->n, sizeof(*req), AF_INET6);
addattr8(&req->n, sizeof(*req), addattr8(&req->n, sizeof(*req),
@ -793,7 +814,8 @@ int iplink_parse(int argc, char **argv, struct iplink_req *req,
if (link_netnsid != -1) if (link_netnsid != -1)
duparg("link-netnsid", *argv); duparg("link-netnsid", *argv);
if (get_integer(&link_netnsid, *argv, 0)) if (get_integer(&link_netnsid, *argv, 0))
invarg("Invalid \"link-netnsid\" value\n", *argv); invarg("Invalid \"link-netnsid\" value\n",
*argv);
addattr32(&req->n, sizeof(*req), IFLA_LINK_NETNSID, addattr32(&req->n, sizeof(*req), IFLA_LINK_NETNSID,
link_netnsid); link_netnsid);
} else if (strcmp(*argv, "protodown") == 0) { } else if (strcmp(*argv, "protodown") == 0) {
@ -874,7 +896,8 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
return -1; return -1;
} }
if (flags & NLM_F_CREATE) { if (flags & NLM_F_CREATE) {
fprintf(stderr, "group cannot be used when creating devices.\n"); fprintf(stderr,
"group cannot be used when creating devices.\n");
return -1; return -1;
} }
@ -888,11 +911,13 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
if (!(flags & NLM_F_CREATE)) { if (!(flags & NLM_F_CREATE)) {
if (!dev) { if (!dev) {
fprintf(stderr, "Not enough information: \"dev\" argument is required.\n"); fprintf(stderr,
"Not enough information: \"dev\" argument is required.\n");
exit(-1); exit(-1);
} }
if (cmd == RTM_NEWLINK && index != -1) { if (cmd == RTM_NEWLINK && index != -1) {
fprintf(stderr, "index can be used only when creating devices.\n"); fprintf(stderr,
"index can be used only when creating devices.\n");
exit(-1); exit(-1);
} }
@ -949,8 +974,9 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
else else
iflatype = IFLA_INFO_DATA; iflatype = IFLA_INFO_DATA;
if (lu && argc) { if (lu && argc) {
struct rtattr *data = addattr_nest(&req.n, struct rtattr *data
sizeof(req), iflatype); = addattr_nest(&req.n,
sizeof(req), iflatype);
if (lu->parse_opt && if (lu->parse_opt &&
lu->parse_opt(lu, argc, argv, &req.n)) lu->parse_opt(lu, argc, argv, &req.n))
@ -967,7 +993,8 @@ static int iplink_modify(int cmd, unsigned int flags, int argc, char **argv)
} }
addattr_nest_end(&req.n, linkinfo); addattr_nest_end(&req.n, linkinfo);
} else if (flags & NLM_F_CREATE) { } else if (flags & NLM_F_CREATE) {
fprintf(stderr, "Not enough information: \"type\" argument is required\n"); fprintf(stderr,
"Not enough information: \"type\" argument is required\n");
return -1; return -1;
} }
@ -1175,7 +1202,8 @@ static int parse_address(const char *dev, int hatype, int halen,
if (alen < 0) if (alen < 0)
return -1; return -1;
if (alen != halen) { if (alen != halen) {
fprintf(stderr, "Wrong address (%s) length: expected %d bytes\n", fprintf(stderr,
"Wrong address (%s) length: expected %d bytes\n",
lla, halen); lla, halen);
return -1; return -1;
} }
@ -1326,18 +1354,21 @@ static int do_set(int argc, char **argv)
if (halen < 0) if (halen < 0)
return -1; return -1;
if (newaddr) { if (newaddr) {
if (parse_address(dev, htype, halen, newaddr, &ifr0) < 0) if (parse_address(dev, htype, halen,
newaddr, &ifr0) < 0)
return -1; return -1;
} }
if (newbrd) { if (newbrd) {
if (parse_address(dev, htype, halen, newbrd, &ifr1) < 0) if (parse_address(dev, htype, halen,
newbrd, &ifr1) < 0)
return -1; return -1;
} }
} }
if (newname && strcmp(dev, newname)) { if (newname && strcmp(dev, newname)) {
if (strlen(newname) == 0) if (strlen(newname) == 0)
invarg("\"\" is not a valid device identifier\n", "name"); invarg("\"\" is not a valid device identifier\n",
"name");
if (do_changename(dev, newname) < 0) if (do_changename(dev, newname) < 0)
return -1; return -1;
dev = newname; dev = newname;

View File

@ -32,10 +32,22 @@ ip route list table "$@" |
esac esac
while test $# != 0 while test $# != 0
do do
key=$1 case "$1" in
val=$2 proto|via|dev|scope|src|table)
eval "$key=$val" key=$1
shift 2 val=$2
eval "$key='$val'"
shift 2
;;
dead|onlink|pervasive|offload|notify|linkdown|unresolved)
shift
;;
*)
# avoid infinite loop on unknown keyword without value at line end
shift
shift
;;
esac
done done
echo "$network $via $src $proto $scope $dev $table" echo "$network $via $src $proto $scope $dev $table"
done | awk -F ' ' ' done | awk -F ' ' '

View File

@ -95,7 +95,10 @@ Each policy routing rule consists of a
.B selector .B selector
and an and an
.B action predicate. .B action predicate.
The RPDB is scanned in order of decreasing priority. The selector The RPDB is scanned in order of decreasing priority (note that lower number
means higher priority, see the description of
.I PREFERENCE
below). The selector
of each rule is applied to {source address, destination address, incoming of each rule is applied to {source address, destination address, incoming
interface, tos, fwmark} and, if the selector matches the packet, interface, tos, fwmark} and, if the selector matches the packet,
the action is performed. The action predicate may return with success. the action is performed. The action predicate may return with success.
@ -225,7 +228,8 @@ value to match.
.BI priority " PREFERENCE" .BI priority " PREFERENCE"
the priority of this rule. the priority of this rule.
.I PREFERENCE .I PREFERENCE
is an unsigned integer value, higher number means lower priority. Each rule is an unsigned integer value, higher number means lower priority, and rules get
processed in order of increasing number. Each rule
should have an explicitly set should have an explicitly set
.I unique .I unique
priority value. priority value.

View File

@ -5,8 +5,8 @@ pedit - generic packet editor action
.SH SYNOPSIS .SH SYNOPSIS
.in +8 .in +8
.ti -8 .ti -8
.BR tc " ... " "action pedit munge " { .BR tc " ... " "action pedit [ex] munge " {
.IR RAW_OP " | " LAYERED_OP " } [ " CONTROL " ]" .IR RAW_OP " | " LAYERED_OP " | " EXTENDED_LAYERED_OP " } [ " CONTROL " ]"
.ti -8 .ti -8
.IR RAW_OP " := " .IR RAW_OP " := "
@ -22,25 +22,53 @@ pedit - generic packet editor action
.IR LAYERED_OP " := { " .IR LAYERED_OP " := { "
.BI ip " IPHDR_FIELD" .BI ip " IPHDR_FIELD"
| |
.BI ip6 " IP6HDR_FIELD" .BI ip " BEYOND_IPHDR_FIELD"
.RI } " CMD_SPEC"
.ti -8
.IR EXTENDED_LAYERED_OP " := { "
.BI eth " ETHHDR_FIELD"
| |
.BI udp " UDPHDR_FIELD" .BI ip " IPHDR_FIELD"
|
.BI ip " EX_IPHDR_FIELD"
| |
.BI tcp " TCPHDR_FIELD" .BI tcp " TCPHDR_FIELD"
| |
.BI icmp " ICMPHDR_FIELD" .BI udp " UDPHDR_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 " |"
.BR precedence " | " nofrag " | " firstfrag " | " ce " | " df " |" .BR precedence " | " nofrag " | " firstfrag " | " ce " | " df " }"
.BR mf " | " dport " | " sport " | " icmp_type " | " icmp_code " }"
.ti -8
.IR BEYOND_IPHDR_FIELD " := { "
.BR dport " | " sport " | " icmp_type " | " icmp_code " }"
.ti -8
.IR EX_IPHDR_FIELD " := { "
.BR ttl " }"
.ti -8
.IR TCPHDR_FIELD " := { "
.BR sport " | " dport " | " flags " }"
.ti -8
.IR UDPHDR_FIELD " := { "
.BR sport " | " dport " }"
.ti -8 .ti -8
.IR CMD_SPEC " := {" .IR CMD_SPEC " := {"
.BR clear " | " invert " | " set .BR clear " | " invert " | " set
.IR VAL " | " .IR VAL " | "
.BR add
.IR VAL " | "
.BR preserve " } [ " retain .BR preserve " } [ " retain
.IR RVAL " ]" .IR RVAL " ]"
@ -58,6 +86,13 @@ chosen automatically based on the header field size. Currently this is supported
only for IPv4 headers. only for IPv4 headers.
.SH OPTIONS .SH OPTIONS
.TP .TP
.B ex
Use extended pedit.
.I EXTENDED_LAYERED_OP
and the add
.I CMD_SPEC
are allowed only in this mode.
.TP
.BI offset " OFFSET " "\fR{ \fBu32 \fR| \fBu16 \fR| \fBu8 \fR}" .BI offset " OFFSET " "\fR{ \fBu32 \fR| \fBu16 \fR| \fBu8 \fR}"
Specify the offset at which to change data. Specify the offset at which to change data.
.I OFFSET .I OFFSET
@ -86,6 +121,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
@ -123,6 +173,15 @@ Change IP header flags. Note that the value to pass to the
.B set .B set
command is not just a bit value, but the full byte including the flags field. command is not just a bit value, but the full byte including the flags field.
Though only the relevant bits of that value are respected, the rest ignored. Though only the relevant bits of that value are respected, the rest ignored.
.RE
.TP
.BI ip " BEYOND_IPHDR_FIELD"
Supported only for non-extended layered op. It is passed to the kernel as
offsets relative to the beginning of the IP header and assumes the IP header is
of minimum size (20 bytes). The supported keywords for
.I BEYOND_IPHDR_FIELD
are:
.RS
.TP .TP
.B dport .B dport
.TQ .TQ
@ -141,6 +200,43 @@ If it is not or the latter is bigger than the minimum of 20 bytes, this will do
unexpected things. These fields are eight-bit values. unexpected things. These fields are eight-bit values.
.RE .RE
.TP .TP
.BI ip " EX_IPHDR_FIELD"
Supported only when
.I ex
is used. The supported keywords for
.I EX_IPHDR_FIELD
are:
.RS
.TP
.B ttl
.RE
.TP
.BI tcp " TCPHDR_FIELD"
The supported keywords for
.I TCPHDR_FIELD
are:
.RS
.TP
.B sport
.TQ
.B dport
Source or destination TCP port number, a 16-bit value.
.TP
.B flags
.RE
.TP
.BI udp " UDPHDR_FIELD"
The supported keywords for
.I UDPHDR_FIELD
are:
.RS
.TP
.B sport
.TQ
.B dport
Source or destination TCP port number, a 16-bit value.
.RE
.TP
.B clear .B clear
Clear the addressed data (i.e., set it to zero). Clear the addressed data (i.e., set it to zero).
.TP .TP
@ -157,6 +253,13 @@ keywords in
or the size of the addressed header field in or the size of the addressed header field in
.IR LAYERED_OP . .IR LAYERED_OP .
.TP .TP
.BI add " VAL"
Add the addressed data by a specific value. The size of
.I VAL
is defined by the size of the addressed header field in
.IR EXTENDED_LAYERED_OP .
This operation is supported only for extended layered op.
.TP
.B preserve .B preserve
Keep the addressed data as is. Keep the addressed data as is.
.TP .TP
@ -222,6 +325,15 @@ tc filter add dev eth0 parent 1: 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 pedit munge ip sport set 23 action pedit pedit munge ip sport set 23
tc filter add dev eth0 parent ffff: u32 \\
match ip sport 22 0xffff \\
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
tc filter add dev eth0 parent ffff: u32 \\
match ip dport 23 0xffff \\
action pedit ex munge tcp dport set 22
.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,23 +28,25 @@
#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;
static void explain(void) static void explain(void)
{ {
fprintf(stderr, "Usage: ... pedit munge <MUNGE> [CONTROL]\n"); fprintf(stderr, "Usage: ... pedit munge [ex] <MUNGE> [CONTROL]\n");
fprintf(stderr, fprintf(stderr,
"Where: MUNGE := <RAW>|<LAYERED>\n" "Where: MUNGE := <RAW>|<LAYERED>\n"
"\t<RAW>:= <OFFSETC>[ATC]<CMD>\n \t\tOFFSETC:= offset <offval> <u8|u16|u32>\n" "\t<RAW>:= <OFFSETC>[ATC]<CMD>\n \t\tOFFSETC:= offset <offval> <u8|u16|u32>\n"
"\t\tATC:= at <atval> offmask <maskval> shift <shiftval>\n" "\t\tATC:= at <atval> offmask <maskval> shift <shiftval>\n"
"\t\tNOTE: offval is byte offset, must be multiple of 4\n" "\t\tNOTE: offval is byte offset, must be multiple of 4\n"
"\t\tNOTE: maskval is a 32 bit hex number\n \t\tNOTE: shiftval is a is a shift value\n" "\t\tNOTE: maskval is a 32 bit hex number\n \t\tNOTE: shiftval is a shift value\n"
"\t\tCMD:= clear | invert | set <setval>| retain\n" "\t\tCMD:= clear | invert | set <setval>| add <addval> | retain\n"
"\t<LAYERED>:= ip <ipdata> | ip6 <ip6data>\n" "\t<LAYERED>:= ip <ipdata> | ip6 <ip6data>\n"
" \t\t| udp <udpdata> | tcp <tcpdata> | icmp <icmpdata>\n" " \t\t| udp <udpdata> | tcp <tcpdata> | icmp <icmpdata>\n"
"\tCONTROL:= reclassify | pipe | drop | continue | pass\n" "\tCONTROL:= reclassify | pipe | drop | continue | pass\n"
"\tNOTE: if 'ex' is set, extended functionality will be supported (kernel >= 4.11)\n"
"For Example usage look at the examples directory\n"); "For Example usage look at the examples directory\n");
} }
@ -56,8 +58,8 @@ static void usage(void)
} }
static int pedit_parse_nopopt(int *argc_p, char ***argv_p, static int pedit_parse_nopopt(int *argc_p, char ***argv_p,
struct tc_pedit_sel *sel, struct m_pedit_sel *sel,
struct tc_pedit_key *tkey) struct m_pedit_key *tkey)
{ {
int argc = *argc_p; int argc = *argc_p;
char **argv = *argv_p; char **argv = *argv_p;
@ -116,8 +118,10 @@ noexist:
return p; return p;
} }
int pack_key(struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) int pack_key(struct m_pedit_sel *_sel, struct m_pedit_key *tkey)
{ {
struct tc_pedit_sel *sel = &_sel->sel;
struct m_pedit_key_ex *keys_ex = _sel->keys_ex;
int hwm = sel->nkeys; int hwm = sel->nkeys;
if (hwm >= MAX_OFFS) if (hwm >= MAX_OFFS)
@ -134,12 +138,25 @@ int pack_key(struct tc_pedit_sel *sel, struct tc_pedit_key *tkey)
sel->keys[hwm].at = tkey->at; sel->keys[hwm].at = tkey->at;
sel->keys[hwm].offmask = tkey->offmask; sel->keys[hwm].offmask = tkey->offmask;
sel->keys[hwm].shift = tkey->shift; sel->keys[hwm].shift = tkey->shift;
if (_sel->extended) {
keys_ex[hwm].htype = tkey->htype;
keys_ex[hwm].cmd = tkey->cmd;
} else {
if (tkey->htype != TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK ||
tkey->cmd != TCA_PEDIT_KEY_EX_CMD_SET) {
fprintf(stderr,
"Munge parameters not supported. Use 'munge ex'.\n");
return -1;
}
}
sel->nkeys++; sel->nkeys++;
return 0; return 0;
} }
int pack_key32(__u32 retain, struct tc_pedit_sel *sel, int pack_key32(__u32 retain, struct m_pedit_sel *sel,
struct tc_pedit_key *tkey) struct m_pedit_key *tkey)
{ {
if (tkey->off > (tkey->off & ~3)) { if (tkey->off > (tkey->off & ~3)) {
fprintf(stderr, fprintf(stderr,
@ -152,8 +169,8 @@ int pack_key32(__u32 retain, struct tc_pedit_sel *sel,
return pack_key(sel, tkey); return pack_key(sel, tkey);
} }
int pack_key16(__u32 retain, struct tc_pedit_sel *sel, int pack_key16(__u32 retain, struct m_pedit_sel *sel,
struct tc_pedit_key *tkey) struct m_pedit_key *tkey)
{ {
int ind, stride; int ind, stride;
__u32 m[4] = { 0x0000FFFF, 0xFF0000FF, 0xFFFF0000 }; __u32 m[4] = { 0x0000FFFF, 0xFF0000FF, 0xFFFF0000 };
@ -183,7 +200,7 @@ int pack_key16(__u32 retain, struct tc_pedit_sel *sel,
} }
int pack_key8(__u32 retain, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) int pack_key8(__u32 retain, struct m_pedit_sel *sel, struct m_pedit_key *tkey)
{ {
int ind, stride; int ind, stride;
__u32 m[4] = { 0x00FFFFFF, 0xFF00FFFF, 0xFFFF00FF, 0xFFFFFF00 }; __u32 m[4] = { 0x00FFFFFF, 0xFF00FFFF, 0xFFFF00FF, 0xFFFFFF00 };
@ -208,6 +225,38 @@ int pack_key8(__u32 retain, struct tc_pedit_sel *sel, struct tc_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;
@ -235,13 +284,24 @@ 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;
} }
int parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type, __u32 retain, int parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type, __u32 retain,
struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) struct m_pedit_sel *sel, struct m_pedit_key *tkey)
{ {
__u32 mask = 0, val = 0; __u32 mask[4] = { 0 };
__u32 val[4] = { 0 };
__u32 *m = &mask[0];
__u32 *v = &val[0];
__u32 o = 0xFF; __u32 o = 0xFF;
int res = -1; int res = -1;
int argc = *argc_p; int argc = *argc_p;
@ -260,10 +320,20 @@ int parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type, __u32 retain,
o = 0xFFFFFFFF; o = 0xFFFFFFFF;
if (matches(*argv, "invert") == 0) { if (matches(*argv, "invert") == 0) {
val = mask = o; *v = *m = o;
} else if (matches(*argv, "set") == 0) { } else if (matches(*argv, "set") == 0 ||
matches(*argv, "add") == 0) {
if (matches(*argv, "add") == 0)
tkey->cmd = TCA_PEDIT_KEY_EX_CMD_ADD;
if (!sel->extended && tkey->cmd) {
fprintf(stderr,
"Non extended mode. only 'set' command is supported\n");
return -1;
}
NEXT_ARG(); NEXT_ARG();
if (parse_val(&argc, &argv, &val, type)) if (parse_val(&argc, &argv, val, type))
return -1; return -1;
} else if (matches(*argv, "preserve") == 0) { } else if (matches(*argv, "preserve") == 0) {
retain = 0; retain = 0;
@ -283,8 +353,13 @@ int parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type, __u32 retain,
argv++; argv++;
} }
tkey->val = val; if (type == TMAC) {
tkey->mask = mask; res = pack_mac(sel, tkey, (__u8 *)val);
goto done;
}
tkey->val = *v;
tkey->mask = *m;
if (type == TIPV4) if (type == TIPV4)
tkey->val = ntohl(tkey->val); tkey->val = ntohl(tkey->val);
@ -313,8 +388,8 @@ done:
} }
int parse_offset(int *argc_p, char ***argv_p, struct tc_pedit_sel *sel, int parse_offset(int *argc_p, char ***argv_p, struct m_pedit_sel *sel,
struct tc_pedit_key *tkey) struct m_pedit_key *tkey)
{ {
int off; int off;
__u32 len, retain; __u32 len, retain;
@ -389,9 +464,9 @@ done:
return res; return res;
} }
static int parse_munge(int *argc_p, char ***argv_p, struct tc_pedit_sel *sel) static int parse_munge(int *argc_p, char ***argv_p, struct m_pedit_sel *sel)
{ {
struct tc_pedit_key tkey = {}; struct m_pedit_key tkey = {};
int argc = *argc_p; int argc = *argc_p;
char **argv = *argv_p; char **argv = *argv_p;
int res = -1; int res = -1;
@ -433,13 +508,69 @@ done:
return res; return res;
} }
static int pedit_keys_ex_getattr(struct rtattr *attr,
struct m_pedit_key_ex *keys_ex, int n)
{
struct rtattr *i;
int rem = RTA_PAYLOAD(attr);
struct rtattr *tb[TCA_PEDIT_KEY_EX_MAX + 1];
struct m_pedit_key_ex *k = keys_ex;
for (i = RTA_DATA(attr); RTA_OK(i, rem); i = RTA_NEXT(i, rem)) {
if (!n)
return -1;
if (i->rta_type != TCA_PEDIT_KEY_EX)
return -1;
parse_rtattr_nested(tb, TCA_PEDIT_KEY_EX_MAX, i);
k->htype = rta_getattr_u16(tb[TCA_PEDIT_KEY_EX_HTYPE]);
k->cmd = rta_getattr_u16(tb[TCA_PEDIT_KEY_EX_CMD]);
k++;
n--;
}
return !!n;
}
static int pedit_keys_ex_addattr(struct m_pedit_sel *sel, struct nlmsghdr *n)
{
struct m_pedit_key_ex *k = sel->keys_ex;
struct rtattr *keys_start;
int i;
if (!sel->extended)
return 0;
keys_start = addattr_nest(n, MAX_MSG, TCA_PEDIT_KEYS_EX | NLA_F_NESTED);
for (i = 0; i < sel->sel.nkeys; i++) {
struct rtattr *key_start;
key_start = addattr_nest(n, MAX_MSG,
TCA_PEDIT_KEY_EX | NLA_F_NESTED);
if (addattr16(n, MAX_MSG, TCA_PEDIT_KEY_EX_HTYPE, k->htype) ||
addattr16(n, MAX_MSG, TCA_PEDIT_KEY_EX_CMD, k->cmd)) {
return -1;
}
addattr_nest_end(n, key_start);
k++;
}
addattr_nest_end(n, keys_start);
return 0;
}
int parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, int parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
struct nlmsghdr *n) struct nlmsghdr *n)
{ {
struct { struct m_pedit_sel sel = {};
struct tc_pedit_sel sel;
struct tc_pedit_key keys[MAX_OFFS];
} sel = {};
int argc = *argc_p; int argc = *argc_p;
char **argv = *argv_p; char **argv = *argv_p;
@ -452,6 +583,18 @@ int parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
if (matches(*argv, "pedit") == 0) { if (matches(*argv, "pedit") == 0) {
NEXT_ARG(); NEXT_ARG();
ok++; ok++;
if (matches(*argv, "ex") == 0) {
if (ok > 1) {
fprintf(stderr,
"'ex' must be before first 'munge'\n");
explain();
return -1;
}
sel.extended = true;
NEXT_ARG();
}
continue; continue;
} else if (matches(*argv, "help") == 0) { } else if (matches(*argv, "help") == 0) {
usage(); usage();
@ -463,7 +606,8 @@ int parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
return -1; return -1;
} }
NEXT_ARG(); NEXT_ARG();
if (parse_munge(&argc, &argv, &sel.sel)) {
if (parse_munge(&argc, &argv, &sel)) {
fprintf(stderr, "Bad pedit construct (%s)\n", fprintf(stderr, "Bad pedit construct (%s)\n",
*argv); *argv);
explain(); explain();
@ -499,9 +643,18 @@ int parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
tail = NLMSG_TAIL(n); tail = NLMSG_TAIL(n);
addattr_l(n, MAX_MSG, tca_id, NULL, 0); addattr_l(n, MAX_MSG, tca_id, NULL, 0);
addattr_l(n, MAX_MSG, TCA_PEDIT_PARMS, &sel, if (!sel.extended) {
sizeof(sel.sel) + addattr_l(n, MAX_MSG, TCA_PEDIT_PARMS, &sel,
sel.sel.nkeys * sizeof(struct tc_pedit_key)); sizeof(sel.sel) +
sel.sel.nkeys * sizeof(struct tc_pedit_key));
} else {
addattr_l(n, MAX_MSG, TCA_PEDIT_PARMS_EX, &sel,
sizeof(sel.sel) +
sel.sel.nkeys * sizeof(struct tc_pedit_key));
pedit_keys_ex_addattr(&sel, n);
}
tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail; tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail;
*argc_p = argc; *argc_p = argc;
@ -509,21 +662,74 @@ int parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
return 0; return 0;
} }
const char *pedit_htype_str[] = {
[TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK] = "",
[TCA_PEDIT_KEY_EX_HDR_TYPE_ETH] = "eth",
[TCA_PEDIT_KEY_EX_HDR_TYPE_IP4] = "ipv4",
[TCA_PEDIT_KEY_EX_HDR_TYPE_IP6] = "ipv6",
[TCA_PEDIT_KEY_EX_HDR_TYPE_TCP] = "tcp",
[TCA_PEDIT_KEY_EX_HDR_TYPE_UDP] = "udp",
};
static void print_pedit_location(FILE *f,
enum pedit_header_type htype, __u32 off)
{
if (htype == TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK) {
fprintf(f, "%d", (unsigned int)off);
return;
}
if (htype < ARRAY_SIZE(pedit_htype_str))
fprintf(f, "%s", pedit_htype_str[htype]);
else
fprintf(f, "unknown(%d)", htype);
fprintf(f, "%c%d", (int)off >= 0 ? '+' : '-', abs((int)off));
}
int print_pedit(struct action_util *au, FILE *f, struct rtattr *arg) int print_pedit(struct action_util *au, FILE *f, struct rtattr *arg)
{ {
struct tc_pedit_sel *sel; struct tc_pedit_sel *sel;
struct rtattr *tb[TCA_PEDIT_MAX + 1]; struct rtattr *tb[TCA_PEDIT_MAX + 1];
struct m_pedit_key_ex *keys_ex = NULL;
if (arg == NULL) if (arg == NULL)
return -1; return -1;
parse_rtattr_nested(tb, TCA_PEDIT_MAX, arg); parse_rtattr_nested(tb, TCA_PEDIT_MAX, arg);
if (tb[TCA_PEDIT_PARMS] == NULL) { if (!tb[TCA_PEDIT_PARMS] && !tb[TCA_PEDIT_PARMS_EX]) {
fprintf(f, "[NULL pedit parameters]"); fprintf(f, "[NULL pedit parameters]");
return -1; return -1;
} }
sel = RTA_DATA(tb[TCA_PEDIT_PARMS]);
if (tb[TCA_PEDIT_PARMS]) {
sel = RTA_DATA(tb[TCA_PEDIT_PARMS]);
} else {
int err;
sel = RTA_DATA(tb[TCA_PEDIT_PARMS_EX]);
if (!tb[TCA_PEDIT_KEYS_EX]) {
fprintf(f, "Netlink error\n");
return -1;
}
keys_ex = calloc(sel->nkeys, sizeof(*keys_ex));
if (!keys_ex) {
fprintf(f, "Out of memory\n");
return -1;
}
err = pedit_keys_ex_getattr(tb[TCA_PEDIT_KEYS_EX], keys_ex,
sel->nkeys);
if (err) {
fprintf(f, "Netlink error\n");
free(keys_ex);
return -1;
}
}
fprintf(f, " pedit action %s keys %d\n ", fprintf(f, " pedit action %s keys %d\n ",
action_n2a(sel->action), sel->nkeys); action_n2a(sel->action), sel->nkeys);
@ -540,11 +746,28 @@ int print_pedit(struct action_util *au, FILE *f, struct rtattr *arg)
if (sel->nkeys) { if (sel->nkeys) {
int i; int i;
struct tc_pedit_key *key = sel->keys; struct tc_pedit_key *key = sel->keys;
struct m_pedit_key_ex *key_ex = keys_ex;
for (i = 0; i < sel->nkeys; i++, key++) { for (i = 0; i < sel->nkeys; i++, key++) {
enum pedit_header_type htype =
TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK;
enum pedit_cmd cmd = TCA_PEDIT_KEY_EX_CMD_SET;
if (keys_ex) {
htype = key_ex->htype;
cmd = key_ex->cmd;
key_ex++;
}
fprintf(f, "\n\t key #%d", i); fprintf(f, "\n\t key #%d", i);
fprintf(f, " at %d: val %08x mask %08x",
(unsigned int)key->off, fprintf(f, " at ");
print_pedit_location(f, htype, key->off);
fprintf(f, ": %s %08x mask %08x",
cmd ? "add" : "val",
(unsigned int)ntohl(key->val), (unsigned int)ntohl(key->val),
(unsigned int)ntohl(key->mask)); (unsigned int)ntohl(key->mask));
} }
@ -554,6 +777,8 @@ int print_pedit(struct action_util *au, FILE *f, struct rtattr *arg)
} }
fprintf(f, "\n "); fprintf(f, "\n ");
free(keys_ex);
return 0; return 0;
} }

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
@ -39,24 +40,55 @@
#define PEDITKINDSIZ 16 #define PEDITKINDSIZ 16
struct m_pedit_util struct m_pedit_key {
{ __u32 mask; /* AND */
struct m_pedit_util *next; __u32 val; /*XOR */
char id[PEDITKINDSIZ]; __u32 off; /*offset */
int (*parse_peopt)(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey); __u32 at;
__u32 offmask;
__u32 shift;
enum pedit_header_type htype;
enum pedit_cmd cmd;
}; };
struct m_pedit_key_ex {
enum pedit_header_type htype;
enum pedit_cmd cmd;
};
extern int parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type,__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey); struct m_pedit_sel {
extern int pack_key(struct tc_pedit_sel *sel,struct tc_pedit_key *tkey); struct tc_pedit_sel sel;
extern int pack_key32(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey); struct tc_pedit_key keys[MAX_OFFS];
extern int pack_key16(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey); struct m_pedit_key_ex keys_ex[MAX_OFFS];
extern int pack_key8(__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey); bool extended;
extern int parse_val(int *argc_p, char ***argv_p, __u32 * val, int type); };
extern int parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type,__u32 retain,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey);
extern int parse_offset(int *argc_p, char ***argv_p,struct tc_pedit_sel *sel,struct tc_pedit_key *tkey); struct m_pedit_util {
int parse_pedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n); struct m_pedit_util *next;
extern int print_pedit(struct action_util *au,FILE * f, struct rtattr *arg); char id[PEDITKINDSIZ];
extern int pedit_print_xstats(struct action_util *au, FILE *f, struct rtattr *xstats); int (*parse_peopt)(int *argc_p, char ***argv_p,
struct m_pedit_sel *sel,
struct m_pedit_key *tkey);
};
extern int pack_key(struct m_pedit_sel *sel, struct m_pedit_key *tkey);
extern int pack_key32(__u32 retain, struct m_pedit_sel *sel,
struct m_pedit_key *tkey);
extern int pack_key16(__u32 retain, struct m_pedit_sel *sel,
struct m_pedit_key *tkey);
extern int pack_key8(__u32 retain, struct m_pedit_sel *sel,
struct m_pedit_key *tkey);
extern int parse_val(int *argc_p, char ***argv_p, __u32 *val, int type);
extern int parse_cmd(int *argc_p, char ***argv_p, __u32 len, int type,
__u32 retain,
struct m_pedit_sel *sel, struct m_pedit_key *tkey);
extern int parse_offset(int *argc_p, char ***argv_p,
struct m_pedit_sel *sel, struct m_pedit_key *tkey);
int parse_pedit(struct action_util *a, int *argc_p, char ***argv_p,
int tca_id, struct nlmsghdr *n);
extern int print_pedit(struct action_util *au, FILE *f, struct rtattr *arg);
extern int pedit_print_xstats(struct action_util *au, FILE *f,
struct rtattr *xstats);
#endif #endif

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,
};

View File

@ -25,7 +25,8 @@
static int static int
parse_icmp(int *argc_p, char ***argv_p, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) parse_icmp(int *argc_p, char ***argv_p,
struct m_pedit_sel *sel, struct m_pedit_key *tkey)
{ {
int res = -1; int res = -1;
#if 0 #if 0

View File

@ -25,7 +25,7 @@
static int static int
parse_ip(int *argc_p, char ***argv_p, parse_ip(int *argc_p, char ***argv_p,
struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) struct m_pedit_sel *sel, struct m_pedit_key *tkey)
{ {
int res = -1; int res = -1;
int argc = *argc_p; int argc = *argc_p;
@ -34,6 +34,10 @@ parse_ip(int *argc_p, char ***argv_p,
if (argc < 2) if (argc < 2)
return -1; return -1;
tkey->htype = sel->extended ?
TCA_PEDIT_KEY_EX_HDR_TYPE_IP4 :
TCA_PEDIT_KEY_EX_HDR_TYPE_NETWORK;
if (strcmp(*argv, "src") == 0) { if (strcmp(*argv, "src") == 0) {
NEXT_ARG(); NEXT_ARG();
tkey->off = 12; tkey->off = 12;
@ -62,6 +66,12 @@ parse_ip(int *argc_p, char ***argv_p,
res = parse_cmd(&argc, &argv, 1, TU32, 0x0f, sel, tkey); res = parse_cmd(&argc, &argv, 1, TU32, 0x0f, sel, tkey);
goto done; goto done;
} }
if (strcmp(*argv, "ttl") == 0) {
NEXT_ARG();
tkey->off = 8;
res = parse_cmd(&argc, &argv, 1, TU32, RU8, sel, tkey);
goto done;
}
if (strcmp(*argv, "protocol") == 0) { if (strcmp(*argv, "protocol") == 0) {
NEXT_ARG(); NEXT_ARG();
tkey->off = 9; tkey->off = 9;
@ -107,6 +117,13 @@ parse_ip(int *argc_p, char ***argv_p,
res = parse_cmd(&argc, &argv, 1, TU32, 0x20, sel, tkey); res = parse_cmd(&argc, &argv, 1, TU32, 0x20, sel, tkey);
goto done; goto done;
} }
if (sel->extended)
return -1; /* fields located outside IP header should be
* addressed using the relevant header type in
* extended pedit kABI
*/
if (strcmp(*argv, "dport") == 0) { if (strcmp(*argv, "dport") == 0) {
NEXT_ARG(); NEXT_ARG();
tkey->off = 22; tkey->off = 22;
@ -141,7 +158,7 @@ done:
static int static int
parse_ip6(int *argc_p, char ***argv_p, parse_ip6(int *argc_p, char ***argv_p,
struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) struct m_pedit_sel *sel, struct m_pedit_key *tkey)
{ {
int res = -1; int res = -1;
return res; return res;

View File

@ -24,9 +24,47 @@
#include "m_pedit.h" #include "m_pedit.h"
static int static int
parse_tcp(int *argc_p, char ***argv_p, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) parse_tcp(int *argc_p, char ***argv_p,
struct m_pedit_sel *sel, struct m_pedit_key *tkey)
{ {
int res = -1; int res = -1;
int argc = *argc_p;
char **argv = *argv_p;
if (argc < 2)
return -1;
if (!sel->extended)
return -1;
tkey->htype = TCA_PEDIT_KEY_EX_HDR_TYPE_TCP;
if (strcmp(*argv, "sport") == 0) {
NEXT_ARG();
tkey->off = 0;
res = parse_cmd(&argc, &argv, 2, TU32, RU16, sel, tkey);
goto done;
}
if (strcmp(*argv, "dport") == 0) {
NEXT_ARG();
tkey->off = 2;
res = parse_cmd(&argc, &argv, 2, TU32, RU16, sel, tkey);
goto done;
}
if (strcmp(*argv, "flags") == 0) {
NEXT_ARG();
tkey->off = 13;
res = parse_cmd(&argc, &argv, 1, TU32, RU8, sel, tkey);
goto done;
}
return -1;
done:
*argc_p = argc;
*argv_p = argv;
return res; return res;
} }
struct m_pedit_util p_pedit_tcp = { struct m_pedit_util p_pedit_tcp = {

View File

@ -24,9 +24,37 @@
#include "m_pedit.h" #include "m_pedit.h"
static int static int
parse_udp(int *argc_p, char ***argv_p, struct tc_pedit_sel *sel, struct tc_pedit_key *tkey) parse_udp(int *argc_p, char ***argv_p,
struct m_pedit_sel *sel, struct m_pedit_key *tkey)
{ {
int res = -1; int res = -1;
int argc = *argc_p;
char **argv = *argv_p;
if (argc < 2)
return -1;
tkey->htype = TCA_PEDIT_KEY_EX_HDR_TYPE_UDP;
if (strcmp(*argv, "sport") == 0) {
NEXT_ARG();
tkey->off = 0;
res = parse_cmd(&argc, &argv, 2, TU32, RU16, sel, tkey);
goto done;
}
if (strcmp(*argv, "dport") == 0) {
NEXT_ARG();
tkey->off = 2;
res = parse_cmd(&argc, &argv, 2, TU32, RU16, sel, tkey);
goto done;
}
return -1;
done:
*argc_p = argc;
*argv_p = argv;
return res; return res;
} }