2
0
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:
Tonghao Zhang
2020-06-02 21:50:24 +08:00
committed by Simon Horman
parent 4f4be08e47
commit 5f568d0491
6 changed files with 123 additions and 15 deletions

5
NEWS
View File

@@ -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

View File

@@ -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);

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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 \