To improve performance and avoid wasting resources for HW offloaded
flows, do not rewrite fields that are matched with the same value.
Signed-off-by: Eli Britstein
Reviewed-by: Roi Dayan
---
lib/odp-util.c| 110 +-
tests/mpls-xlate.at | 2 +-
tests/ofproto-dpif.at | 14 +++
3 files changed, 108 insertions(+), 18 deletions(-)
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 778c00ee8..e7a389c8c 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -43,6 +43,7 @@
#include "uuid.h"
#include "openvswitch/vlog.h"
#include "openvswitch/match.h"
+#include "odp-netlink-xmacros.h"
VLOG_DEFINE_THIS_MODULE(odp_util);
@@ -7093,12 +7094,49 @@ commit_odp_tunnel_action(const struct flow *flow,
struct flow *base,
}
}
+struct ovs_key_field_properties {
+int offset;
+int size;
+};
+
+/* Compare the keys similary to memcmp, but each field separately.
+ * The offsets and sizes of each field is provided by field_properties
+ * argument.
+ * For fields with the same value, zero out their mask part in order not to
+ * rewrite them as it's unnecessary */
+static bool
+keycmp_mask(const void *key0, const void *key1,
+struct ovs_key_field_properties *field_properties, void *mask)
+{
+int field;
+bool differ = false;
+
+for (field = 0 ; ; field++) {
+int size = field_properties[field].size;
+int offset = field_properties[field].offset;
+char *pkey0 = ((char *)key0) + offset;
+char *pkey1 = ((char *)key1) + offset;
+char *pmask = ((char *)mask) + offset;
+
+if (size == 0)
+break;
+
+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 ovs_key_field_properties *field_properties,
struct ofpbuf *odp_actions)
{
-if (memcmp(key, base, size)) {
+if (keycmp_mask(key, base, field_properties, mask)) {
bool fully_masked = odp_mask_is_exact(attr, mask, size);
if (use_masked_set && !fully_masked) {
@@ -7140,6 +7178,12 @@ commit_set_ether_action(const struct flow *flow, struct
flow *base_flow,
bool use_masked)
{
struct ovs_key_ethernet key, base, mask;
+struct ovs_key_field_properties ovs_key_ethernet_field_properties[] = {
+#define __OVS_KEY_FIELD(type, name) {offsetof(struct ovs_key_ethernet, name),
sizeof(type)},
+__OVS_KEY_ETHERNET_FIELDS
+{0, 0}
+#undef __OVS_KEY_FIELD
+};
if (flow->packet_type != htonl(PT_ETH)) {
return;
@@ -7150,7 +7194,8 @@ commit_set_ether_action(const struct flow *flow, struct
flow *base_flow,
get_ethernet_key(>masks, );
if (commit(OVS_KEY_ATTR_ETHERNET, use_masked,
- , , , sizeof key, odp_actions)) {
+ , , , sizeof key,
+ ovs_key_ethernet_field_properties, odp_actions)) {
put_ethernet_key(, base_flow);
put_ethernet_key(, >masks);
}
@@ -7276,6 +7321,12 @@ commit_set_ipv4_action(const struct flow *flow, struct
flow *base_flow,
bool use_masked)
{
struct ovs_key_ipv4 key, mask, base;
+struct ovs_key_field_properties ovs_key_ipv4_field_properties[] = {
+#define __OVS_KEY_FIELD(type, name) {offsetof(struct ovs_key_ipv4, name),
sizeof(type)},
+__OVS_KEY_IPV4_FIELDS
+{0, 0}
+#undef __OVS_KEY_FIELD
+};
/* Check that nw_proto and nw_frag remain unchanged. */
ovs_assert(flow->nw_proto == base_flow->nw_proto &&
@@ -7293,7 +7344,7 @@ commit_set_ipv4_action(const struct flow *flow, struct
flow *base_flow,
}
if (commit(OVS_KEY_ATTR_IPV4, use_masked, , , , sizeof key,
- odp_actions)) {
+ ovs_key_ipv4_field_properties, odp_actions)) {
put_ipv4_key(, base_flow, false);
if (mask.ipv4_proto != 0) { /* Mask was changed by commit(). */
put_ipv4_key(, >masks, true);
@@ -7331,6 +7382,12 @@ commit_set_ipv6_action(const struct flow *flow, struct
flow *base_flow,
bool use_masked)
{
struct ovs_key_ipv6 key, mask, base;
+struct ovs_key_field_properties ovs_key_ipv6_field_properties[] = {
+#define __OVS_KEY_FIELD(type, name) {offsetof(struct ovs_key_ipv6, name),
sizeof(type)},
+__OVS_KEY_IPV6_FIELDS
+{0, 0}
+#undef __OVS_KEY_FIELD
+};
/* Check that nw_proto and nw_frag remain unchanged. */
ovs_assert(flow->nw_proto == base_flow->nw_proto &&
@@ -7349,7 +7406,7 @@ commit_set_ipv6_action(const struct flow *flow, struct
flow *base_flow,
}
if (commit(OVS_KEY_ATTR_IPV6, use_masked, , , , sizeof key,
- odp_actions)) {
+ ovs_key_ipv6_field_properties, odp_actions)) {
put_ipv6_key(, base_flow,