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:
@@ -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;
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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])
|
||||
|
||||
|
Reference in New Issue
Block a user