@@ -10,6 +10,11 @@ Post-v2.13.0
* Deprecated DPDK ring ports (dpdkr) are no longer supported.
- Linux datapath:
* Support for kernel versions up to 5.5.x.
+ - 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);
@@ -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;
@@ -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 \