Extend 'may_learn' attribute to also control the treatment of
FIN_TIMEOUT action and asynchronous messages (packet ins,
continuations), so that when 'may_learn' is 'false' and
'resubmit_stats' is 'NULL', no OpenFlow-visible side effects are
generated by the translation.

Correspondingly, add support for one-time asynchronous messages to
xlate cache, so that all side-effects of the translation may be
executed at a later stage.  This will be useful for bundle commits.

Signed-off-by: Jarno Rajahalme <ja...@ovn.org>
---
 ofproto/ofproto-dpif-xlate.c | 53 +++++++++++++++++++++++++++++++++++++++-----
 ofproto/ofproto-dpif-xlate.h | 12 +++++++---
 2 files changed, 57 insertions(+), 8 deletions(-)

diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 2683464..83fdff7 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -3595,6 +3595,10 @@ execute_controller_action(struct xlate_ctx *ctx, int len,
         return;
     }
 
+    if (!ctx->xin->may_learn && !ctx->xin->xcache) {
+        return;
+    }
+
     packet = dp_packet_clone(ctx->xin->packet);
     packet_batch_init_packet(&batch, packet);
     odp_execute_actions(NULL, &batch, false,
@@ -3633,13 +3637,26 @@ execute_controller_action(struct xlate_ctx *ctx, int 
len,
     };
     flow_get_metadata(&ctx->xin->flow, &am->pin.up.public.flow_metadata);
 
-    ofproto_dpif_send_async_msg(ctx->xbridge->ofproto, am);
-    dp_packet_delete(packet);
+    /* Async messages are only sent once, so if we send one now, no
+     * xlate cache entry is created.  */
+    if (ctx->xin->may_learn) {
+        ofproto_dpif_send_async_msg(ctx->xbridge->ofproto, am);
+    } else /* xcache */ {
+        struct xc_entry *entry;
+
+        entry = xlate_cache_add_entry(ctx->xin->xcache, XC_CONTROLLER);
+        entry->u.controller.ofproto = ctx->xbridge->ofproto;
+        entry->u.controller.am = am;
+    }
 }
 
 static void
 emit_continuation(struct xlate_ctx *ctx, const struct frozen_state *state)
 {
+    if (!ctx->xin->may_learn && !ctx->xin->xcache) {
+        return;
+    }
+
     struct ofproto_async_msg *am = xmalloc(sizeof *am);
     *am = (struct ofproto_async_msg) {
         .controller_id = ctx->pause->controller_id,
@@ -3671,7 +3688,18 @@ emit_continuation(struct xlate_ctx *ctx, const struct 
frozen_state *state)
         },
     };
     flow_get_metadata(&ctx->xin->flow, &am->pin.up.public.flow_metadata);
-    ofproto_dpif_send_async_msg(ctx->xbridge->ofproto, am);
+
+    /* Async messages are only sent once, so if we send one now, no
+     * xlate cache entry is created.  */
+    if (ctx->xin->may_learn) {
+        ofproto_dpif_send_async_msg(ctx->xbridge->ofproto, am);
+    } else /* xcache */ {
+        struct xc_entry *entry;
+
+        entry = xlate_cache_add_entry(ctx->xin->xcache, XC_CONTROLLER);
+        entry->u.controller.ofproto = ctx->xbridge->ofproto;
+        entry->u.controller.am = am;
+    }
 }
 
 static void
@@ -4121,8 +4149,10 @@ xlate_fin_timeout(struct xlate_ctx *ctx,
                   const struct ofpact_fin_timeout *oft)
 {
     if (ctx->rule) {
-        xlate_fin_timeout__(ctx->rule, ctx->xin->tcp_flags,
-                            oft->fin_idle_timeout, oft->fin_hard_timeout);
+        if (ctx->xin->may_learn) {
+            xlate_fin_timeout__(ctx->rule, ctx->xin->tcp_flags,
+                                oft->fin_idle_timeout, oft->fin_hard_timeout);
+        }
         if (ctx->xin->xcache) {
             struct xc_entry *entry;
 
@@ -5810,6 +5840,13 @@ xlate_push_stats_entry(struct xc_entry *entry,
         tnl_neigh_lookup(entry->u.tnl_neigh_cache.br_name,
                          &entry->u.tnl_neigh_cache.d_ipv6, &dmac);
         break;
+    case XC_CONTROLLER:
+        if (entry->u.controller.am) {
+            ofproto_dpif_send_async_msg(entry->u.controller.ofproto,
+                                        entry->u.controller.am);
+            entry->u.controller.am = NULL; /* One time only. */
+        }
+        break;
     default:
         OVS_NOT_REACHED();
     }
@@ -5890,6 +5927,12 @@ xlate_cache_clear_entry(struct xc_entry *entry)
         break;
     case XC_TNL_NEIGH:
         break;
+    case XC_CONTROLLER:
+        if (entry->u.controller.am) {
+            ofproto_async_msg_free(entry->u.controller.am);
+            entry->u.controller.am = NULL;
+        }
+        break;
     default:
         OVS_NOT_REACHED();
     }
diff --git a/ofproto/ofproto-dpif-xlate.h b/ofproto/ofproto-dpif-xlate.h
index 7faa199..14d81f6 100644
--- a/ofproto/ofproto-dpif-xlate.h
+++ b/ofproto/ofproto-dpif-xlate.h
@@ -43,11 +43,12 @@ enum xc_type {
     XC_NETDEV,
     XC_NETFLOW,
     XC_MIRROR,
-    XC_LEARN,
+    XC_LEARN,            /* Calls back to ofproto. */
     XC_NORMAL,
-    XC_FIN_TIMEOUT,
+    XC_FIN_TIMEOUT,      /* Calls back to ofproto. */
     XC_GROUP,
     XC_TNL_NEIGH,
+    XC_CONTROLLER,
 };
 
 /* xlate_cache entries hold enough information to perform the side effects of
@@ -104,6 +105,10 @@ struct xc_entry {
             char br_name[IFNAMSIZ];
             struct in6_addr d_ipv6;
         } tnl_neigh_cache;
+        struct {
+            struct ofproto_dpif *ofproto;
+            struct ofproto_async_msg *am;
+        } controller;
     } u;
 };
 
@@ -135,7 +140,8 @@ struct xlate_in {
     const struct dp_packet *packet;
 
     /* Should OFPP_NORMAL update the MAC learning table?  Should "learn"
-     * actions update the flow table?
+     * actions update the flow table? Should FIN_TIMEOUT change the
+     * timeouts? Or should controller action send packet to the controller?
      *
      * We want to update these tables if we are actually processing a packet,
      * or if we are accounting for packets that the datapath has processed, but
-- 
2.1.4

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to