mirror of
https://git.proxmox.com/git/mirror_iproute2
synced 2025-10-10 20:40:53 +00:00
Merge branch 'master' into net-next
This commit is contained in:
commit
d2b9100a08
73
ip/iplink.c
73
ip/iplink.c
@ -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;
|
||||||
|
20
ip/routel
20
ip/routel
@ -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 ' ' '
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
293
tc/m_pedit.c
293
tc/m_pedit.c
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
64
tc/m_pedit.h
64
tc/m_pedit.h
@ -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
72
tc/p_eth.c
Normal 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,
|
||||||
|
};
|
@ -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
|
||||||
|
21
tc/p_ip.c
21
tc/p_ip.c
@ -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;
|
||||||
|
40
tc/p_tcp.c
40
tc/p_tcp.c
@ -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 = {
|
||||||
|
30
tc/p_udp.c
30
tc/p_udp.c
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user