mirror of
https://github.com/openvswitch/ovs
synced 2025-08-31 06:15:47 +00:00
netdev-offload-tc: Allow to match the IP and port mask of tunnel
This patch allows users to offload the TC flower rules with tunnel mask. This patch allows masked match of the following, where previously supported an exact match was supported: * Remote (dst) tunnel endpoint address * Local (src) tunnel endpoint address * Remote (dst) tunnel endpoint UDP port And also allows masked match of the following, where previously no match was supported: * Local (src) tunnel endpoint UDP port In some case, mask is useful as wildcards. For example, DDOS, in that case, we don’t want to allow specified hosts IPs or only source Ports to access the targeted host. For example: $ ovs-appctl dpctl/add-flow "tunnel(dst=2.2.2.100,src=2.2.2.0/255.255.255.0,tp_dst=4789),\ recirc_id(0),in_port(3),eth(),eth_type(0x0800),ipv4()" "" $ tc filter show dev vxlan_sys_4789 ingress ... eth_type ipv4 enc_dst_ip 2.2.2.100 enc_src_ip 2.2.2.0/24 enc_dst_port 4789 enc_ttl 64 in_hw in_hw_count 2 action order 1: gact action drop ... Signed-off-by: Tonghao Zhang <xiangxia.m.yue@gmail.com> Acked-by: Roi Dayan <roid@mellanox.com> Signed-off-by: Simon Horman <simon.horman@netronome.com>
This commit is contained in:
committed by
Simon Horman
parent
4f4be08e47
commit
5f568d0491
5
NEWS
5
NEWS
@@ -16,6 +16,11 @@ Post-v2.13.0
|
||||
by enabling interrupt mode.
|
||||
- Userspace datapath:
|
||||
* Add support for conntrack zone-based timeout policy.
|
||||
- Tunnels: TC Flower offload
|
||||
* Tunnel Local endpoint address masked match are supported.
|
||||
* Tunnel Romte endpoint address masked match are supported.
|
||||
* Tunnel Local endpoint ports masked match are supported.
|
||||
* Tunnel Romte endpoint ports masked match are supported.
|
||||
|
||||
|
||||
v2.13.0 - 14 Feb 2020
|
||||
|
@@ -105,6 +105,9 @@ void match_set_tun_flags(struct match *match, uint16_t flags);
|
||||
void match_set_tun_flags_masked(struct match *match, uint16_t flags, uint16_t mask);
|
||||
void match_set_tun_tp_dst(struct match *match, ovs_be16 tp_dst);
|
||||
void match_set_tun_tp_dst_masked(struct match *match, ovs_be16 port, ovs_be16 mask);
|
||||
void match_set_tun_tp_src(struct match *match, ovs_be16 tp_src);
|
||||
void match_set_tun_tp_src_masked(struct match *match,
|
||||
ovs_be16 port, ovs_be16 mask);
|
||||
void match_set_tun_gbp_id_masked(struct match *match, ovs_be16 gbp_id, ovs_be16 mask);
|
||||
void match_set_tun_gbp_id(struct match *match, ovs_be16 gbp_id);
|
||||
void match_set_tun_gbp_flags_masked(struct match *match, uint8_t flags, uint8_t mask);
|
||||
|
13
lib/match.c
13
lib/match.c
@@ -293,6 +293,19 @@ match_set_tun_tp_dst_masked(struct match *match, ovs_be16 port, ovs_be16 mask)
|
||||
match->flow.tunnel.tp_dst = port & mask;
|
||||
}
|
||||
|
||||
void
|
||||
match_set_tun_tp_src(struct match *match, ovs_be16 tp_src)
|
||||
{
|
||||
match_set_tun_tp_src_masked(match, tp_src, OVS_BE16_MAX);
|
||||
}
|
||||
|
||||
void
|
||||
match_set_tun_tp_src_masked(struct match *match, ovs_be16 port, ovs_be16 mask)
|
||||
{
|
||||
match->wc.masks.tunnel.tp_src = mask;
|
||||
match->flow.tunnel.tp_src = port & mask;
|
||||
}
|
||||
|
||||
void
|
||||
match_set_tun_gbp_id_masked(struct match *match, ovs_be16 gbp_id, ovs_be16 mask)
|
||||
{
|
||||
|
@@ -633,13 +633,20 @@ parse_tc_flower_to_match(struct tc_flower *flower,
|
||||
match_set_tun_id(match, flower->key.tunnel.id);
|
||||
match->flow.tunnel.flags |= FLOW_TNL_F_KEY;
|
||||
}
|
||||
if (flower->key.tunnel.ipv4.ipv4_dst) {
|
||||
match_set_tun_src(match, flower->key.tunnel.ipv4.ipv4_src);
|
||||
match_set_tun_dst(match, flower->key.tunnel.ipv4.ipv4_dst);
|
||||
} else if (!is_all_zeros(&flower->key.tunnel.ipv6.ipv6_dst,
|
||||
sizeof flower->key.tunnel.ipv6.ipv6_dst)) {
|
||||
match_set_tun_ipv6_src(match, &flower->key.tunnel.ipv6.ipv6_src);
|
||||
match_set_tun_ipv6_dst(match, &flower->key.tunnel.ipv6.ipv6_dst);
|
||||
if (flower->mask.tunnel.ipv4.ipv4_dst) {
|
||||
match_set_tun_dst_masked(match,
|
||||
flower->key.tunnel.ipv4.ipv4_dst,
|
||||
flower->mask.tunnel.ipv4.ipv4_dst);
|
||||
match_set_tun_src_masked(match,
|
||||
flower->key.tunnel.ipv4.ipv4_src,
|
||||
flower->mask.tunnel.ipv4.ipv4_src);
|
||||
} else if (ipv6_addr_is_set(&flower->mask.tunnel.ipv6.ipv6_dst)) {
|
||||
match_set_tun_ipv6_dst_masked(match,
|
||||
&flower->key.tunnel.ipv6.ipv6_dst,
|
||||
&flower->mask.tunnel.ipv6.ipv6_dst);
|
||||
match_set_tun_ipv6_src_masked(match,
|
||||
&flower->key.tunnel.ipv6.ipv6_src,
|
||||
&flower->mask.tunnel.ipv6.ipv6_src);
|
||||
}
|
||||
if (flower->key.tunnel.tos) {
|
||||
match_set_tun_tos_masked(match, flower->key.tunnel.tos,
|
||||
@@ -649,8 +656,15 @@ parse_tc_flower_to_match(struct tc_flower *flower,
|
||||
match_set_tun_ttl_masked(match, flower->key.tunnel.ttl,
|
||||
flower->mask.tunnel.ttl);
|
||||
}
|
||||
if (flower->key.tunnel.tp_dst) {
|
||||
match_set_tun_tp_dst(match, flower->key.tunnel.tp_dst);
|
||||
if (flower->mask.tunnel.tp_dst) {
|
||||
match_set_tun_tp_dst_masked(match,
|
||||
flower->key.tunnel.tp_dst,
|
||||
flower->mask.tunnel.tp_dst);
|
||||
}
|
||||
if (flower->mask.tunnel.tp_src) {
|
||||
match_set_tun_tp_src_masked(match,
|
||||
flower->key.tunnel.tp_src,
|
||||
flower->mask.tunnel.tp_src);
|
||||
}
|
||||
if (flower->key.tunnel.metadata.present.len) {
|
||||
flower_tun_opt_to_match(match, flower);
|
||||
@@ -1402,8 +1416,14 @@ netdev_tc_flow_put(struct netdev *netdev, struct match *match,
|
||||
flower.key.tunnel.ttl = tnl->ip_ttl;
|
||||
flower.key.tunnel.tp_src = tnl->tp_src;
|
||||
flower.key.tunnel.tp_dst = tnl->tp_dst;
|
||||
flower.mask.tunnel.ipv4.ipv4_src = tnl_mask->ip_src;
|
||||
flower.mask.tunnel.ipv4.ipv4_dst = tnl_mask->ip_dst;
|
||||
flower.mask.tunnel.ipv6.ipv6_src = tnl_mask->ipv6_src;
|
||||
flower.mask.tunnel.ipv6.ipv6_dst = tnl_mask->ipv6_dst;
|
||||
flower.mask.tunnel.tos = tnl_mask->ip_tos;
|
||||
flower.mask.tunnel.ttl = tnl_mask->ip_ttl;
|
||||
flower.mask.tunnel.tp_src = tnl_mask->tp_src;
|
||||
flower.mask.tunnel.tp_dst = tnl_mask->tp_dst;
|
||||
flower.mask.tunnel.id = (tnl->flags & FLOW_TNL_F_KEY) ? tnl_mask->tun_id : 0;
|
||||
flower_match_to_tun_opt(&flower, tnl, tnl_mask);
|
||||
flower.tunnel = true;
|
||||
|
57
lib/tc.c
57
lib/tc.c
@@ -372,6 +372,12 @@ static const struct nl_policy tca_flower_policy[] = {
|
||||
.optional = true, },
|
||||
[TCA_FLOWER_KEY_ENC_UDP_DST_PORT] = { .type = NL_A_U16,
|
||||
.optional = true, },
|
||||
[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT] = { .type = NL_A_U16,
|
||||
.optional = true, },
|
||||
[TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK] = { .type = NL_A_U16,
|
||||
.optional = true, },
|
||||
[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK] = { .type = NL_A_U16,
|
||||
.optional = true, },
|
||||
[TCA_FLOWER_KEY_FLAGS] = { .type = NL_A_BE32, .optional = true, },
|
||||
[TCA_FLOWER_KEY_FLAGS_MASK] = { .type = NL_A_BE32, .optional = true, },
|
||||
[TCA_FLOWER_KEY_IP_TTL] = { .type = NL_A_U8,
|
||||
@@ -650,22 +656,38 @@ nl_parse_flower_tunnel(struct nlattr **attrs, struct tc_flower *flower)
|
||||
flower->mask.tunnel.id = OVS_BE64_MAX;
|
||||
}
|
||||
if (attrs[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK]) {
|
||||
flower->mask.tunnel.ipv4.ipv4_src =
|
||||
nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK]);
|
||||
flower->key.tunnel.ipv4.ipv4_src =
|
||||
nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ENC_IPV4_SRC]);
|
||||
}
|
||||
if (attrs[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK]) {
|
||||
flower->mask.tunnel.ipv4.ipv4_dst =
|
||||
nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ENC_IPV4_DST_MASK]);
|
||||
flower->key.tunnel.ipv4.ipv4_dst =
|
||||
nl_attr_get_be32(attrs[TCA_FLOWER_KEY_ENC_IPV4_DST]);
|
||||
}
|
||||
if (attrs[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK]) {
|
||||
flower->mask.tunnel.ipv6.ipv6_src =
|
||||
nl_attr_get_in6_addr(attrs[TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK]);
|
||||
flower->key.tunnel.ipv6.ipv6_src =
|
||||
nl_attr_get_in6_addr(attrs[TCA_FLOWER_KEY_ENC_IPV6_SRC]);
|
||||
}
|
||||
if (attrs[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK]) {
|
||||
flower->mask.tunnel.ipv6.ipv6_dst =
|
||||
nl_attr_get_in6_addr(attrs[TCA_FLOWER_KEY_ENC_IPV6_DST_MASK]);
|
||||
flower->key.tunnel.ipv6.ipv6_dst =
|
||||
nl_attr_get_in6_addr(attrs[TCA_FLOWER_KEY_ENC_IPV6_DST]);
|
||||
}
|
||||
if (attrs[TCA_FLOWER_KEY_ENC_UDP_DST_PORT]) {
|
||||
if (attrs[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK]) {
|
||||
flower->mask.tunnel.tp_src =
|
||||
nl_attr_get_be16(attrs[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK]);
|
||||
flower->key.tunnel.tp_src =
|
||||
nl_attr_get_be16(attrs[TCA_FLOWER_KEY_ENC_UDP_SRC_PORT]);
|
||||
}
|
||||
if (attrs[TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK]) {
|
||||
flower->mask.tunnel.tp_dst =
|
||||
nl_attr_get_be16(attrs[TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK]);
|
||||
flower->key.tunnel.tp_dst =
|
||||
nl_attr_get_be16(attrs[TCA_FLOWER_KEY_ENC_UDP_DST_PORT]);
|
||||
}
|
||||
@@ -2592,11 +2614,18 @@ nl_msg_put_flower_tunnel_opts(struct ofpbuf *request, uint16_t type,
|
||||
static void
|
||||
nl_msg_put_flower_tunnel(struct ofpbuf *request, struct tc_flower *flower)
|
||||
{
|
||||
ovs_be32 ipv4_src_mask = flower->mask.tunnel.ipv4.ipv4_src;
|
||||
ovs_be32 ipv4_dst_mask = flower->mask.tunnel.ipv4.ipv4_dst;
|
||||
ovs_be32 ipv4_src = flower->key.tunnel.ipv4.ipv4_src;
|
||||
ovs_be32 ipv4_dst = flower->key.tunnel.ipv4.ipv4_dst;
|
||||
struct in6_addr *ipv6_src_mask = &flower->mask.tunnel.ipv6.ipv6_src;
|
||||
struct in6_addr *ipv6_dst_mask = &flower->mask.tunnel.ipv6.ipv6_dst;
|
||||
struct in6_addr *ipv6_src = &flower->key.tunnel.ipv6.ipv6_src;
|
||||
struct in6_addr *ipv6_dst = &flower->key.tunnel.ipv6.ipv6_dst;
|
||||
ovs_be16 tp_dst_mask = flower->mask.tunnel.tp_dst;
|
||||
ovs_be16 tp_src_mask = flower->mask.tunnel.tp_src;
|
||||
ovs_be16 tp_dst = flower->key.tunnel.tp_dst;
|
||||
ovs_be16 tp_src = flower->key.tunnel.tp_src;
|
||||
ovs_be32 id = be64_to_be32(flower->key.tunnel.id);
|
||||
uint8_t tos = flower->key.tunnel.tos;
|
||||
uint8_t ttl = flower->key.tunnel.ttl;
|
||||
@@ -2604,12 +2633,21 @@ nl_msg_put_flower_tunnel(struct ofpbuf *request, struct tc_flower *flower)
|
||||
uint8_t ttl_mask = flower->mask.tunnel.ttl;
|
||||
ovs_be64 id_mask = flower->mask.tunnel.id;
|
||||
|
||||
if (ipv4_dst) {
|
||||
nl_msg_put_be32(request, TCA_FLOWER_KEY_ENC_IPV4_SRC, ipv4_src);
|
||||
if (ipv4_dst_mask || ipv4_src_mask) {
|
||||
nl_msg_put_be32(request, TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,
|
||||
ipv4_dst_mask);
|
||||
nl_msg_put_be32(request, TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,
|
||||
ipv4_src_mask);
|
||||
nl_msg_put_be32(request, TCA_FLOWER_KEY_ENC_IPV4_DST, ipv4_dst);
|
||||
} else if (!is_all_zeros(ipv6_dst, sizeof *ipv6_dst)) {
|
||||
nl_msg_put_in6_addr(request, TCA_FLOWER_KEY_ENC_IPV6_SRC, ipv6_src);
|
||||
nl_msg_put_be32(request, TCA_FLOWER_KEY_ENC_IPV4_SRC, ipv4_src);
|
||||
} else if (ipv6_addr_is_set(ipv6_dst_mask) ||
|
||||
ipv6_addr_is_set(ipv6_src_mask)) {
|
||||
nl_msg_put_in6_addr(request, TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,
|
||||
ipv6_dst_mask);
|
||||
nl_msg_put_in6_addr(request, TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,
|
||||
ipv6_src_mask);
|
||||
nl_msg_put_in6_addr(request, TCA_FLOWER_KEY_ENC_IPV6_DST, ipv6_dst);
|
||||
nl_msg_put_in6_addr(request, TCA_FLOWER_KEY_ENC_IPV6_SRC, ipv6_src);
|
||||
}
|
||||
if (tos_mask) {
|
||||
nl_msg_put_u8(request, TCA_FLOWER_KEY_ENC_IP_TOS, tos);
|
||||
@@ -2619,9 +2657,16 @@ nl_msg_put_flower_tunnel(struct ofpbuf *request, struct tc_flower *flower)
|
||||
nl_msg_put_u8(request, TCA_FLOWER_KEY_ENC_IP_TTL, ttl);
|
||||
nl_msg_put_u8(request, TCA_FLOWER_KEY_ENC_IP_TTL_MASK, ttl_mask);
|
||||
}
|
||||
if (tp_dst) {
|
||||
if (tp_dst_mask) {
|
||||
nl_msg_put_be16(request, TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK,
|
||||
tp_dst_mask);
|
||||
nl_msg_put_be16(request, TCA_FLOWER_KEY_ENC_UDP_DST_PORT, tp_dst);
|
||||
}
|
||||
if (tp_src_mask) {
|
||||
nl_msg_put_be16(request, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK,
|
||||
tp_src_mask);
|
||||
nl_msg_put_be16(request, TCA_FLOWER_KEY_ENC_UDP_SRC_PORT, tp_src);
|
||||
}
|
||||
if (id_mask) {
|
||||
nl_msg_put_be32(request, TCA_FLOWER_KEY_ENC_KEY_ID, id);
|
||||
}
|
||||
|
@@ -110,6 +110,28 @@ Datapath actions: drop
|
||||
OVS_VSWITCHD_STOP(["/dropping tunnel packet marked ECN CE but is not ECN capable/d"])
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([tunnel - input with matching tunnel mask])
|
||||
OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=gre \
|
||||
options:remote_ip=1.1.1.1 \
|
||||
ofport_request=1 \
|
||||
-- add-port br0 p2 -- set Interface p2 type=dummy \
|
||||
ofport_request=2])
|
||||
|
||||
AT_CHECK([ovs-appctl dpif/show | tail -n +3], [0], [dnl
|
||||
br0 65534/100: (dummy-internal)
|
||||
p1 1/1: (gre: remote_ip=1.1.1.1)
|
||||
p2 2/2: (dummy)
|
||||
])
|
||||
|
||||
AT_CHECK([ovs-appctl dpctl/add-flow "tunnel(dst=1.1.1.1,src=3.3.3.200/255.255.255.0,tp_dst=123,tp_src=1/0xf,ttl=64),recirc_id(0),in_port(1),eth(),eth_type(0x0800),ipv4()" "2"])
|
||||
|
||||
AT_CHECK([ovs-appctl dpctl/dump-flows | tail -1], [0], [dnl
|
||||
tunnel(src=3.3.3.200/255.255.255.0,dst=1.1.1.1,ttl=64,tp_src=1/0xf,tp_dst=123),recirc_id(0),in_port(1),eth_type(0x0800), packets:0, bytes:0, used:never, actions:2
|
||||
])
|
||||
|
||||
OVS_VSWITCHD_STOP
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([tunnel - output])
|
||||
OVS_VSWITCHD_START([add-port br0 p1 -- set Interface p1 type=gre \
|
||||
options:remote_ip=1.1.1.1 options:local_ip=2.2.2.2 \
|
||||
|
Reference in New Issue
Block a user