From: Emeel Hakim <[email protected]>

A dp_hash select group computes a dp_hash only if the packet has none,
otherwise it uses the one that the packet carries, even if another
dp_hash select group computed it with its own hash algorithm and basis.

Make every dp_hash select group compute its own dp_hash.  Mark that a
dp_hash select group used the dp_hash of the packet, and keep the mark
across re-circulations, except for the one that computes a new dp_hash,
so that a dp_hash is used only once, by the group that requested it.

Fixes: 53cc166ae5fe ("xlate: Use dp_hash for select groups.")
Signed-off-by: Emeel Hakim <[email protected]>
Signed-off-by: Eli Britstein <[email protected]>
---
 ofproto/ofproto-dpif-rid.c   |  2 ++
 ofproto/ofproto-dpif-rid.h   |  1 +
 ofproto/ofproto-dpif-xlate.c | 34 +++++++++++++++++++++++++++++++---
 tests/ofproto-dpif.at        | 23 +++++++++++++++++++++++
 4 files changed, 57 insertions(+), 3 deletions(-)

diff --git a/ofproto/ofproto-dpif-rid.c b/ofproto/ofproto-dpif-rid.c
index 820de1417..a407a1696 100644
--- a/ofproto/ofproto-dpif-rid.c
+++ b/ofproto/ofproto-dpif-rid.c
@@ -136,6 +136,7 @@ frozen_state_hash(const struct frozen_state *state)
                         sizeof state->metadata, hash);
     hash = hash_boolean(state->conntracked, hash);
     hash = hash_boolean(state->was_mpls, hash);
+    hash = hash_boolean(state->dp_hashed, hash);
     if (state->stack && state->stack_size) {
         hash = hash_bytes(state->stack, state->stack_size, hash);
     }
@@ -165,6 +166,7 @@ frozen_state_equal(const struct frozen_state *a, const 
struct frozen_state *b)
             && a->mirrors == b->mirrors
             && a->conntracked == b->conntracked
             && a->was_mpls == b->was_mpls
+            && a->dp_hashed == b->dp_hashed
             && ofpacts_equal(a->ofpacts, a->ofpacts_len,
                              b->ofpacts, b->ofpacts_len)
             && ofpacts_equal(a->action_set, a->action_set_len,
diff --git a/ofproto/ofproto-dpif-rid.h b/ofproto/ofproto-dpif-rid.h
index 8e9a16503..db5786d84 100644
--- a/ofproto/ofproto-dpif-rid.h
+++ b/ofproto/ofproto-dpif-rid.h
@@ -154,6 +154,7 @@ struct frozen_state {
     mirror_mask_t mirrors;        /* Mirrors already output. */
     bool conntracked;             /* Conntrack occurred prior to freeze. */
     bool was_mpls;                /* MPLS packet */
+    bool dp_hashed;               /* dp_hash occurred prior to freeze. */
     struct uuid xport_uuid;       /* UUID of 1st port packet received on. */
 
     /* Actions to be translated when thawing. */
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 4e7d6fb40..f9b9ea0bd 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -403,6 +403,11 @@ struct xlate_ctx {
      * state from the datapath should be honored after thawing. */
     bool conntracked;
 
+    /* True if a dp_hash select group has used the dp_hash of this packet.
+     * This is used to determine whether a dp_hash select group needs to
+     * compute a new dp_hash instead of using the one of the packet. */
+    bool dp_hashed;
+
     /* Pointer to an embedded NAT action in a conntrack action, or NULL. */
     struct ofpact_nat *ct_nat_action;
 
@@ -4180,6 +4185,7 @@ patch_port_output(struct xlate_ctx *ctx, const struct 
xport *in_dev,
     bool old_was_mpls = ctx->was_mpls;
     struct flow *flow = &ctx->xin->flow;
     bool old_conntrack = ctx->conntracked;
+    bool old_dp_hashed = ctx->dp_hashed;
     struct xretained_state *retained_state;
     struct ovs_list *old_trace = ctx->xin->trace;
     ovs_version_t old_version = ctx->xin->tables_version;
@@ -4264,6 +4270,10 @@ patch_port_output(struct xlate_ctx *ctx, const struct 
xport *in_dev,
      * original bridge. */
     ctx->conntracked = old_conntrack;
 
+    /* The out bridge's dp_hash select groups should have no effect on the
+     * original bridge. */
+    ctx->dp_hashed = old_dp_hashed;
+
     /* The fact that the out bridge exits (for any reason) does not mean
      * that the original bridge should exit.  Specifically, if the out
      * bridge freezes translation, the original bridge must continue
@@ -5026,8 +5036,9 @@ pick_dp_hash_select_group(struct xlate_ctx *ctx, struct 
group_dpif *group)
     /* dp_hash value 0 is special since it means that the dp_hash has not been
      * computed, as all computed dp_hash values are non-zero.  Therefore
      * compare to zero can be used to decide if the dp_hash value is valid
-     * without masking the dp_hash field. */
-    if (!dp_hash) {
+     * without masking the dp_hash field.  The value is also invalid once a
+     * dp_hash select group has used it, as each group computes its own. */
+    if (!dp_hash || ctx->dp_hashed) {
         enum ovs_hash_alg hash_alg = group->hash_alg;
         if (hash_alg > ctx->xbridge->support.max_hash_alg) {
             /* Algorithm supported by all datapaths. */
@@ -5039,6 +5050,8 @@ pick_dp_hash_select_group(struct xlate_ctx *ctx, struct 
group_dpif *group)
         return NULL;
     } else {
         uint32_t hash_mask = group->hash_mask;
+
+        ctx->dp_hashed = true;
         ctx->wc->masks.dp_hash |= hash_mask;
 
         /* Starting from the original masked dp_hash value iterate over the
@@ -5305,6 +5318,7 @@ xlate_controller_action(struct xlate_ctx *ctx, int len,
         .mirrors = ctx->mirrors,
         .conntracked = ctx->conntracked,
         .was_mpls = ctx->was_mpls,
+        .dp_hashed = ctx->dp_hashed,
         .ofpacts = NULL,
         .ofpacts_len = 0,
         .action_set = NULL,
@@ -5349,6 +5363,9 @@ finish_freezing__(struct xlate_ctx *ctx, uint8_t table)
         .mirrors = ctx->mirrors,
         .conntracked = ctx->conntracked,
         .was_mpls = ctx->was_mpls,
+        /* No dp_hash select group has used a dp_hash computed right before
+         * the recirculation. */
+        .dp_hashed = ctx->dp_hashed && !ctx->recirc_update_dp_hash,
         .xport_uuid = ctx->xin->xport_uuid,
         .ofpacts = ctx->frozen_actions.data,
         .ofpacts_len = ctx->frozen_actions.size,
@@ -6250,8 +6267,8 @@ clone_xlate_actions(const struct ofpact *actions, size_t 
actions_len,
                     struct xlate_ctx *ctx, bool is_last_action,
                     bool group_bucket_action OVS_UNUSED)
 {
+    bool old_was_mpls, old_conntracked, old_dp_hashed;
     struct xretained_state *retained_state;
-    bool old_was_mpls, old_conntracked;
     size_t body_offset, body_size;
     uint32_t old_observe_offset;
 
@@ -6269,6 +6286,7 @@ clone_xlate_actions(const struct ofpact *actions, size_t 
actions_len,
     old_was_mpls = ctx->was_mpls;
     old_conntracked = ctx->conntracked;
     old_observe_offset = ctx->xout->last_observe_offset;
+    old_dp_hashed = ctx->dp_hashed;
 
     body_offset = ctx->odp_actions->size;
 
@@ -6329,6 +6347,10 @@ clone_xlate_actions(const struct ofpact *actions, size_t 
actions_len,
     ctx->conntracked = old_conntracked;
     ctx->was_mpls = old_was_mpls;
 
+    /* The clone's dp_hash select groups should have no effect on the original
+     * packet. */
+    ctx->dp_hashed = old_dp_hashed;
+
     xretain_state_restore_and_free(ctx, retained_state);
 }
 
@@ -6867,6 +6889,7 @@ xlate_check_pkt_larger(struct xlate_ctx *ctx,
 
     bool old_was_mpls = ctx->was_mpls;
     bool old_conntracked = ctx->conntracked;
+    bool old_dp_hashed = ctx->dp_hashed;
 
     size_t offset = nl_msg_start_nested(ctx->odp_actions,
                                         OVS_ACTION_ATTR_CHECK_PKT_LEN);
@@ -6889,6 +6912,7 @@ xlate_check_pkt_larger(struct xlate_ctx *ctx,
     xretain_flow_restore(ctx, retained_state);
     ctx->was_mpls = old_was_mpls;
     ctx->conntracked = old_conntracked;
+    ctx->dp_hashed = old_dp_hashed;
 
     /* If the flow translation for the IF_GREATER case requires freezing,
      * then ctx->exit would be true. Reset to false so that we can
@@ -6913,6 +6937,7 @@ xlate_check_pkt_larger(struct xlate_ctx *ctx,
 
     ctx->was_mpls = old_was_mpls;
     ctx->conntracked = old_conntracked;
+    ctx->dp_hashed = old_dp_hashed;
     ctx->exit = old_exit;
     xretain_base_flow_restore(ctx, retained_state);
     xretain_state_restore_and_free(ctx, retained_state);
@@ -8365,6 +8390,7 @@ xlate_actions(struct xlate_in *xin, struct xlate_out 
*xout)
 
         .was_mpls = false,
         .conntracked = false,
+        .dp_hashed = false,
 
         .ct_nat_action = NULL,
 
@@ -8431,6 +8457,8 @@ xlate_actions(struct xlate_in *xin, struct xlate_out 
*xout)
         xlate_report(&ctx, OFT_THAW,
                      "Resuming from table %"PRIu8, ctx.table_id);
 
+        ctx.dp_hashed = state->dp_hashed;
+
         ctx.conntracked = state->conntracked;
         if (!state->conntracked) {
             clear_conntrack(&ctx);
diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at
index e50d77216..2fb3423ef 100644
--- a/tests/ofproto-dpif.at
+++ b/tests/ofproto-dpif.at
@@ -1222,6 +1222,29 @@ 
recirc_id(0x1),dp_hash(0xXXXX/0xf),in_port(1),packet_type(ns=0,id=0),eth_type(0x
 OVS_VSWITCHD_STOP
 AT_CLEANUP
 
+AT_SETUP([ofproto-dpif - select group with dp_hash after another select group])
+
+OVS_VSWITCHD_START
+add_of_ports br0 1 10
+AT_CHECK([ovs-ofctl -O OpenFlow12 add-group br0 
'group_id=1,type=select,bucket=group:2'])
+AT_CHECK([ovs-ofctl -O OpenFlow12 add-group br0 
'group_id=2,type=select,bucket=output:10'])
+AT_CHECK([ovs-ofctl -O OpenFlow12 add-flow br0 'ip actions=group:1'])
+
+AT_CHECK([ovs-appctl netdev-dummy/receive p1 
"in_port(1),eth(src=50:54:00:00:00:07,dst=50:54:00:00:00:05),eth_type(0x0800),ipv4(src=192.168.0.1,dst=192.168.0.2,proto=1,tos=0,ttl=128,frag=no),icmp(type=8,code=0)"])
+
+dnl Group 2 computes its own dp_hash instead of using the one of group 1.
+AT_CHECK([ovs-appctl dpctl/dump-flows --names | strip_ufid | strip_used \
+            | strip_recirc | sed 's/dp_hash(.*\/0xf)/dp_hash(0xXXXX\/0xf)/' \
+            | sort], [0], [dnl
+flow-dump from the main thread:
+recirc_id(<recirc>),dp_hash(0xXXXX/0xf),in_port(p1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no),
 packets:0, bytes:0, used:never, actions:hash(sym_l4(0)),recirc(<recirc>)
+recirc_id(<recirc>),dp_hash(0xXXXX/0xf),in_port(p1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no),
 packets:0, bytes:0, used:never, actions:p10
+recirc_id(<recirc>),in_port(p1),packet_type(ns=0,id=0),eth_type(0x0800),ipv4(frag=no),
 packets:0, bytes:0, used:never, actions:hash(sym_l4(0)),recirc(<recirc>)
+])
+
+OVS_VSWITCHD_STOP
+AT_CLEANUP
+
 AT_SETUP([ofproto-dpif - select group with weights])
 
 # Helper function to check the accuracy of distribution of packets over buckets
-- 
2.43.0

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to