2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-31 22:35:15 +00:00

odp-util: Do not rewrite fields with the same values as matched

To improve performance and avoid wasting resources for HW offloaded
flows, do not rewrite fields that are matched with the same value.

Reviewed-by: Roi Dayan <roid@mellanox.com>
Signed-off-by: Eli Britstein <elibr@mellanox.com>
Signed-off-by: Ben Pfaff <blp@ovn.org>
This commit is contained in:
Eli Britstein
2019-03-21 07:44:16 +00:00
committed by Ben Pfaff
parent 5f44aaba7b
commit dbf4a92800
3 changed files with 86 additions and 21 deletions

View File

@@ -43,6 +43,7 @@
#include "uuid.h"
#include "openvswitch/vlog.h"
#include "openvswitch/match.h"
#include "odp-netlink-macros.h"
VLOG_DEFINE_THIS_MODULE(odp_util);
@@ -7361,12 +7362,49 @@ commit_odp_tunnel_action(const struct flow *flow, struct flow *base,
}
}
struct offsetof_sizeof {
int offset;
int size;
};
/* Compares each of the fields in 'key0' and 'key1'. The fields are specified
* in 'offsetof_sizeof_arr', which is an array terminated by a 0-size field.
* Returns true if all of the fields are equal, false if at least one differs.
* As a side effect, for each field that is the same in 'key0' and 'key1',
* zeros the corresponding bytes in 'mask'. */
static bool
keycmp_mask(const void *key0, const void *key1,
struct offsetof_sizeof *offsetof_sizeof_arr, void *mask)
{
bool differ = false;
for (int field = 0 ; ; field++) {
int size = offsetof_sizeof_arr[field].size;
int offset = offsetof_sizeof_arr[field].offset;
if (size == 0) {
break;
}
char *pkey0 = ((char *)key0) + offset;
char *pkey1 = ((char *)key1) + offset;
char *pmask = ((char *)mask) + offset;
if (memcmp(pkey0, pkey1, size) == 0) {
memset(pmask, 0, size);
} else {
differ = true;
}
}
return differ;
}
static bool
commit(enum ovs_key_attr attr, bool use_masked_set,
const void *key, void *base, void *mask, size_t size,
struct offsetof_sizeof *offsetof_sizeof_arr,
struct ofpbuf *odp_actions)
{
if (memcmp(key, base, size)) {
if (keycmp_mask(key, base, offsetof_sizeof_arr, mask)) {
bool fully_masked = odp_mask_is_exact(attr, mask, size);
if (use_masked_set && !fully_masked) {
@@ -7408,7 +7446,8 @@ commit_set_ether_action(const struct flow *flow, struct flow *base_flow,
bool use_masked)
{
struct ovs_key_ethernet key, base, mask;
struct offsetof_sizeof ovs_key_ethernet_offsetof_sizeof_arr[] =
OVS_KEY_ETHERNET_OFFSETOF_SIZEOF_ARR;
if (flow->packet_type != htonl(PT_ETH)) {
return;
}
@@ -7418,7 +7457,8 @@ commit_set_ether_action(const struct flow *flow, struct flow *base_flow,
get_ethernet_key(&wc->masks, &mask);
if (commit(OVS_KEY_ATTR_ETHERNET, use_masked,
&key, &base, &mask, sizeof key, odp_actions)) {
&key, &base, &mask, sizeof key,
ovs_key_ethernet_offsetof_sizeof_arr, odp_actions)) {
put_ethernet_key(&base, base_flow);
put_ethernet_key(&mask, &wc->masks);
}
@@ -7544,6 +7584,8 @@ commit_set_ipv4_action(const struct flow *flow, struct flow *base_flow,
bool use_masked)
{
struct ovs_key_ipv4 key, mask, base;
struct offsetof_sizeof ovs_key_ipv4_offsetof_sizeof_arr[] =
OVS_KEY_IPV4_OFFSETOF_SIZEOF_ARR;
/* Check that nw_proto and nw_frag remain unchanged. */
ovs_assert(flow->nw_proto == base_flow->nw_proto &&
@@ -7561,7 +7603,7 @@ commit_set_ipv4_action(const struct flow *flow, struct flow *base_flow,
}
if (commit(OVS_KEY_ATTR_IPV4, use_masked, &key, &base, &mask, sizeof key,
odp_actions)) {
ovs_key_ipv4_offsetof_sizeof_arr, odp_actions)) {
put_ipv4_key(&base, base_flow, false);
if (mask.ipv4_proto != 0) { /* Mask was changed by commit(). */
put_ipv4_key(&mask, &wc->masks, true);
@@ -7599,6 +7641,8 @@ commit_set_ipv6_action(const struct flow *flow, struct flow *base_flow,
bool use_masked)
{
struct ovs_key_ipv6 key, mask, base;
struct offsetof_sizeof ovs_key_ipv6_offsetof_sizeof_arr[] =
OVS_KEY_IPV6_OFFSETOF_SIZEOF_ARR;
/* Check that nw_proto and nw_frag remain unchanged. */
ovs_assert(flow->nw_proto == base_flow->nw_proto &&
@@ -7617,7 +7661,7 @@ commit_set_ipv6_action(const struct flow *flow, struct flow *base_flow,
}
if (commit(OVS_KEY_ATTR_IPV6, use_masked, &key, &base, &mask, sizeof key,
odp_actions)) {
ovs_key_ipv6_offsetof_sizeof_arr, odp_actions)) {
put_ipv6_key(&base, base_flow, false);
if (mask.ipv6_proto != 0) { /* Mask was changed by commit(). */
put_ipv6_key(&mask, &wc->masks, true);
@@ -7653,13 +7697,15 @@ commit_set_arp_action(const struct flow *flow, struct flow *base_flow,
struct ofpbuf *odp_actions, struct flow_wildcards *wc)
{
struct ovs_key_arp key, mask, base;
struct offsetof_sizeof ovs_key_arp_offsetof_sizeof_arr[] =
OVS_KEY_ARP_OFFSETOF_SIZEOF_ARR;
get_arp_key(flow, &key);
get_arp_key(base_flow, &base);
get_arp_key(&wc->masks, &mask);
if (commit(OVS_KEY_ATTR_ARP, true, &key, &base, &mask, sizeof key,
odp_actions)) {
ovs_key_arp_offsetof_sizeof_arr, odp_actions)) {
put_arp_key(&base, base_flow);
put_arp_key(&mask, &wc->masks);
return SLOW_ACTION;
@@ -7688,6 +7734,8 @@ commit_set_icmp_action(const struct flow *flow, struct flow *base_flow,
struct ofpbuf *odp_actions, struct flow_wildcards *wc)
{
struct ovs_key_icmp key, mask, base;
struct offsetof_sizeof ovs_key_icmp_offsetof_sizeof_arr[] =
OVS_KEY_ICMP_OFFSETOF_SIZEOF_ARR;
enum ovs_key_attr attr;
if (is_icmpv4(flow, NULL)) {
@@ -7702,7 +7750,8 @@ commit_set_icmp_action(const struct flow *flow, struct flow *base_flow,
get_icmp_key(base_flow, &base);
get_icmp_key(&wc->masks, &mask);
if (commit(attr, false, &key, &base, &mask, sizeof key, odp_actions)) {
if (commit(attr, false, &key, &base, &mask, sizeof key,
ovs_key_icmp_offsetof_sizeof_arr, odp_actions)) {
put_icmp_key(&base, base_flow);
put_icmp_key(&mask, &wc->masks);
return SLOW_ACTION;
@@ -7752,13 +7801,15 @@ commit_set_nd_action(const struct flow *flow, struct flow *base_flow,
struct flow_wildcards *wc, bool use_masked)
{
struct ovs_key_nd key, mask, base;
struct offsetof_sizeof ovs_key_nd_offsetof_sizeof_arr[] =
OVS_KEY_ND_OFFSETOF_SIZEOF_ARR;
get_nd_key(flow, &key);
get_nd_key(base_flow, &base);
get_nd_key(&wc->masks, &mask);
if (commit(OVS_KEY_ATTR_ND, use_masked, &key, &base, &mask, sizeof key,
odp_actions)) {
ovs_key_nd_offsetof_sizeof_arr, odp_actions)) {
put_nd_key(&base, base_flow);
put_nd_key(&mask, &wc->masks);
return SLOW_ACTION;
@@ -7774,13 +7825,16 @@ commit_set_nd_extensions_action(const struct flow *flow,
struct flow_wildcards *wc, bool use_masked)
{
struct ovs_key_nd_extensions key, mask, base;
struct offsetof_sizeof ovs_key_nd_extensions_offsetof_sizeof_arr[] =
OVS_KEY_ND_EXTENSIONS_OFFSETOF_SIZEOF_ARR;
get_nd_extensions_key(flow, &key);
get_nd_extensions_key(base_flow, &base);
get_nd_extensions_key(&wc->masks, &mask);
if (commit(OVS_KEY_ATTR_ND_EXTENSIONS, use_masked, &key,
&base, &mask, sizeof key, odp_actions)) {
if (commit(OVS_KEY_ATTR_ND_EXTENSIONS, use_masked, &key, &base, &mask,
sizeof key, ovs_key_nd_extensions_offsetof_sizeof_arr,
odp_actions)) {
put_nd_extensions_key(&base, base_flow);
put_nd_extensions_key(&mask, &wc->masks);
return SLOW_ACTION;
@@ -7997,6 +8051,8 @@ commit_set_port_action(const struct flow *flow, struct flow *base_flow,
{
enum ovs_key_attr key_type;
union ovs_key_tp key, mask, base;
struct offsetof_sizeof ovs_key_tp_offsetof_sizeof_arr[] =
OVS_KEY_TCP_OFFSETOF_SIZEOF_ARR;
/* Check if 'flow' really has an L3 header. */
if (!flow->nw_proto) {
@@ -8022,7 +8078,7 @@ commit_set_port_action(const struct flow *flow, struct flow *base_flow,
get_tp_key(&wc->masks, &mask);
if (commit(key_type, use_masked, &key, &base, &mask, sizeof key,
odp_actions)) {
ovs_key_tp_offsetof_sizeof_arr, odp_actions)) {
put_tp_key(&base, base_flow);
put_tp_key(&mask, &wc->masks);
}
@@ -8035,13 +8091,17 @@ commit_set_priority_action(const struct flow *flow, struct flow *base_flow,
bool use_masked)
{
uint32_t key, mask, base;
struct offsetof_sizeof ovs_key_prio_offsetof_sizeof_arr[] = {
{0, sizeof(uint32_t)},
{0, 0}
};
key = flow->skb_priority;
base = base_flow->skb_priority;
mask = wc->masks.skb_priority;
if (commit(OVS_KEY_ATTR_PRIORITY, use_masked, &key, &base, &mask,
sizeof key, odp_actions)) {
sizeof key, ovs_key_prio_offsetof_sizeof_arr, odp_actions)) {
base_flow->skb_priority = base;
wc->masks.skb_priority = mask;
}
@@ -8054,13 +8114,18 @@ commit_set_pkt_mark_action(const struct flow *flow, struct flow *base_flow,
bool use_masked)
{
uint32_t key, mask, base;
struct offsetof_sizeof ovs_key_pkt_mark_offsetof_sizeof_arr[] = {
{0, sizeof(uint32_t)},
{0, 0}
};
key = flow->pkt_mark;
base = base_flow->pkt_mark;
mask = wc->masks.pkt_mark;
if (commit(OVS_KEY_ATTR_SKB_MARK, use_masked, &key, &base, &mask,
sizeof key, odp_actions)) {
sizeof key, ovs_key_pkt_mark_offsetof_sizeof_arr,
odp_actions)) {
base_flow->pkt_mark = base;
wc->masks.pkt_mark = mask;
}

View File

@@ -182,7 +182,7 @@ AT_CHECK([ovs-ofctl -O OpenFlow13 add-flow br1 in_port=1,ip,actions=dec_ttl,push
dnl MPLS push+pop
AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(100),eth(src=f8:bc:12:44:34:b6,dst=f8:bc:12:46:58:e0),eth_type(0x0800),ipv4(src=10.1.1.22,dst=10.0.0.3,proto=6,tos=0,ttl=64,frag=no),tcp(src=53295,dst=8080)'], [0], [stdout])
AT_CHECK([tail -1 stdout], [0],
[Datapath actions: set(ipv4(ttl=63)),push_mpls(label=0,tc=0,ttl=63,bos=1,eth_type=0x8847),3,pop_mpls(eth_type=0x800),set(ipv4(tos=0/0xfc,ttl=64)),1,1
[Datapath actions: set(ipv4(ttl=63)),push_mpls(label=0,tc=0,ttl=63,bos=1,eth_type=0x8847),3,pop_mpls(eth_type=0x800),set(ipv4(ttl=64)),1,1
])
OVS_VSWITCHD_STOP

View File

@@ -4346,7 +4346,7 @@ do
elif test $type = later; then
echo "Datapath actions: $exp_output" >> expout
else
echo "Datapath actions: set(tcp(src=80,dst=80)),$exp_output" >> expout
echo "Datapath actions: set(tcp(src=80)),$exp_output" >> expout
fi
AT_CHECK([grep 'IP fragments' stdout; tail -1 stdout], [0], [expout])
done
@@ -7252,7 +7252,7 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt], [0], [ignore])
AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.10.10.2,dst=10.10.10.1,proto=1,tos=1,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout])
AT_CHECK([tail -1 stdout], [0], [dnl
Datapath actions: set(ipv4(src=10.10.10.2,dst=192.168.4.4)),2,set(eth(src=80:81:81:81:81:81)),set(ipv4(src=10.10.10.2,dst=192.168.5.5)),3,set(eth(src=50:54:00:00:00:09)),set(ipv4(src=10.10.10.2,dst=10.10.10.1)),4
Datapath actions: set(ipv4(dst=192.168.4.4)),2,set(eth(src=80:81:81:81:81:81)),set(ipv4(dst=192.168.5.5)),3,set(eth(src=50:54:00:00:00:09)),set(ipv4(dst=10.10.10.1)),4
])
dnl Test flow xlate openflow clone action without using datapath clone action.
@@ -7261,14 +7261,14 @@ AT_CHECK([ovs-appctl dpif/set-dp-features br0 clone false], [0], [ignore])
AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.10.10.2,dst=10.10.10.1,proto=1,tos=1,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout])
AT_CHECK([tail -1 stdout], [0], [dnl
Datapath actions: set(ipv4(src=10.10.10.2,dst=192.168.4.4)),2,set(eth(src=80:81:81:81:81:81)),set(ipv4(src=10.10.10.2,dst=192.168.5.5)),3,set(eth(src=50:54:00:00:00:09)),set(ipv4(src=10.10.10.2,dst=10.10.10.1)),4
Datapath actions: set(ipv4(dst=192.168.4.4)),2,set(eth(src=80:81:81:81:81:81)),set(ipv4(dst=192.168.5.5)),3,set(eth(src=50:54:00:00:00:09)),set(ipv4(dst=10.10.10.1)),4
])
AT_CHECK([ovs-appctl dpif/set-dp-features br0 sample_nesting 2], [0], [ignore])
AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.10.10.2,dst=10.10.10.1,proto=1,tos=1,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout])
AT_CHECK([tail -1 stdout], [0], [dnl
Datapath actions: set(ipv4(src=10.10.10.2,dst=192.168.4.4)),2,set(eth(src=80:81:81:81:81:81)),set(ipv4(src=10.10.10.2,dst=192.168.5.5)),3,set(eth(src=50:54:00:00:00:09)),set(ipv4(src=10.10.10.2,dst=10.10.10.1)),4
Datapath actions: set(ipv4(dst=192.168.4.4)),2,set(eth(src=80:81:81:81:81:81)),set(ipv4(dst=192.168.5.5)),3,set(eth(src=50:54:00:00:00:09)),set(ipv4(dst=10.10.10.1)),4
])
dnl Mixing reversible and irreversible open flow clone actions. Datapath clone action
@@ -7286,7 +7286,7 @@ AT_CHECK([ovs-ofctl add-flows br0 flows.txt], [0], [ignore])
AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.10.10.2,dst=10.10.10.1,proto=1,tos=1,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout])
AT_CHECK([tail -1 stdout], [0], [dnl
Datapath actions: set(ipv4(src=10.10.10.2,dst=192.168.4.4)),2,set(ipv4(src=10.10.10.2,dst=10.10.10.1)),clone(ct(commit),3),4
Datapath actions: set(ipv4(dst=192.168.4.4)),2,set(ipv4(dst=10.10.10.1)),clone(ct(commit),3),4
])
AT_CHECK([ovs-appctl dpif/set-dp-features br0 clone false], [0], [ignore])
@@ -7294,14 +7294,14 @@ AT_CHECK([ovs-appctl dpif/set-dp-features br0 clone false], [0], [ignore])
AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.10.10.2,dst=10.10.10.1,proto=1,tos=1,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout])
AT_CHECK([tail -1 stdout], [0], [dnl
Datapath actions: set(ipv4(src=10.10.10.2,dst=192.168.4.4)),2,set(ipv4(src=10.10.10.2,dst=10.10.10.1)),sample(sample=100.0%,actions(ct(commit),3)),4
Datapath actions: set(ipv4(dst=192.168.4.4)),2,set(ipv4(dst=10.10.10.1)),sample(sample=100.0%,actions(ct(commit),3)),4
])
AT_CHECK([ovs-appctl dpif/set-dp-features br0 sample_nesting 2], [0], [ignore])
AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=50:54:00:00:00:09,dst=50:54:00:00:00:0a),eth_type(0x0800),ipv4(src=10.10.10.2,dst=10.10.10.1,proto=1,tos=1,ttl=128,frag=no),icmp(type=8,code=0)'], [0], [stdout])
AT_CHECK([tail -1 stdout], [0], [dnl
Datapath actions: set(ipv4(src=10.10.10.2,dst=192.168.4.4)),2,set(ipv4(src=10.10.10.2,dst=10.10.10.1)),4
Datapath actions: set(ipv4(dst=192.168.4.4)),2,set(ipv4(dst=10.10.10.1)),4
])
AT_CHECK([grep "Failed to compose clone action" stdout], [0], [ignore])