[ovs-dev] [PATCH] ofproto: Make the resubmit recursion limit configurable.

Ethan Jackson ethan at nicira.com
Wed Aug 15 20:57:28 UTC 2012


It's desirable to keep the resubmit recursion limit as small as
possible to reduce the performance impact of buggy flow tables.
However, some controllers may need a relatively large value.  This
patch allows each controller to set the resubmit recursion limit
which is appropriate for its use case.

Signed-off-by: Ethan Jackson <ethan at nicira.com>
---
 NEWS                       |  1 +
 ofproto/ofproto-dpif.c     | 36 +++++++++++++++++++++++++++---------
 ofproto/ofproto-provider.h |  8 ++++++++
 ofproto/ofproto.c          | 16 ++++++++++++++++
 ofproto/ofproto.h          |  1 +
 vswitchd/bridge.c          |  8 ++++++++
 vswitchd/vswitch.xml       |  6 ++++++
 7 files changed, 67 insertions(+), 9 deletions(-)

diff --git a/NEWS b/NEWS
index 54a7114..db7970c 100644
--- a/NEWS
+++ b/NEWS
@@ -18,6 +18,7 @@ post-v1.8.0
       are true, but because we do not know of any users for this
       feature it seems better on balance to remove it.  (The ovs-pki-cgi
       program was not included in distribution packaging.)
+    - The resubmit recursion limit is now configurable.
 
 
 v1.8.0 - xx xxx xxxx
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index cf34e92..c3bfdf4 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -64,9 +64,9 @@ COVERAGE_DEFINE(facet_revalidate);
 COVERAGE_DEFINE(facet_unexpected);
 COVERAGE_DEFINE(facet_suppress);
 
-/* Maximum depth of flow table recursion (due to resubmit actions) in a
+/* Default maximum depth of flow table recursion (due to resubmit actions) in a
  * flow translation. */
-#define MAX_RESUBMIT_RECURSION 32
+#define DEFAULT_MAX_RESUBMIT 32
 
 /* Number of implemented OpenFlow tables. */
 enum { N_TABLES = 255 };
@@ -593,6 +593,7 @@ COVERAGE_DEFINE(rev_inconsistency);
 
 struct ofproto_dpif {
     struct hmap_node all_ofproto_dpifs_node; /* In 'all_ofproto_dpifs'. */
+    size_t max_resubmit;
     struct ofproto up;
     struct dpif *dpif;
     int max_ports;
@@ -751,6 +752,7 @@ construct(struct ofproto *ofproto_)
     }
 
     ofproto->max_ports = dpif_get_max_ports(ofproto->dpif);
+    ofproto->max_resubmit = DEFAULT_MAX_RESUBMIT;
     ofproto->n_matches = 0;
 
     dpif_flow_flush(ofproto->dpif);
@@ -4980,8 +4982,9 @@ static void
 xlate_table_action(struct action_xlate_ctx *ctx,
                    uint16_t in_port, uint8_t table_id)
 {
-    if (ctx->recurse < MAX_RESUBMIT_RECURSION) {
-        struct ofproto_dpif *ofproto = ctx->ofproto;
+    struct ofproto_dpif *ofproto = ctx->ofproto;
+
+    if (ctx->recurse < ofproto->max_resubmit) {
         struct rule_dpif *rule;
         uint16_t old_in_port;
         uint8_t old_table_id;
@@ -5032,8 +5035,8 @@ xlate_table_action(struct action_xlate_ctx *ctx,
     } else {
         static struct vlog_rate_limit recurse_rl = VLOG_RATE_LIMIT_INIT(1, 1);
 
-        VLOG_ERR_RL(&recurse_rl, "resubmit actions recursed over %d times",
-                    MAX_RESUBMIT_RECURSION);
+        VLOG_ERR_RL(&recurse_rl, "resubmit actions recursed over %zu times",
+                    ofproto->max_resubmit);
         ctx->max_resubmit_trigger = true;
     }
 }
@@ -5601,9 +5604,9 @@ xlate_actions(struct action_xlate_ctx *ctx,
               const struct ofpact *ofpacts, size_t ofpacts_len,
               struct ofpbuf *odp_actions)
 {
-    /* Normally false.  Set to true if we ever hit MAX_RESUBMIT_RECURSION, so
-     * that in the future we always keep a copy of the original flow for
-     * tracing purposes. */
+    /* Normally false.  Set to true if we ever hit the resubmit recursion
+     * limit, so that in the future we always keep a copy of the original flow
+     * for tracing purposes. */
     static bool hit_resubmit_limit;
 
     enum slow_path_reason special;
@@ -6379,6 +6382,20 @@ rule_invalidate(const struct rule_dpif *rule)
     }
 }
 
+static int
+set_max_resubmit(struct ofproto *ofproto, size_t max_resubmit)
+{
+    /* Arbitrarily chosen ridiculously high limit.  This should prevent a buggy
+     * controller from essentially setting max_resubmit to infinity and
+     * shooting itself in the foot. */
+    if (max_resubmit > 1024) {
+        return EINVAL;
+    }
+
+    ofproto_dpif_cast(ofproto)->max_resubmit = max_resubmit;
+    return 0;
+}
+
 static bool
 set_frag_handling(struct ofproto *ofproto_,
                   enum ofp_config_flags frag_handling)
@@ -7174,6 +7191,7 @@ const struct ofproto_class ofproto_dpif_class = {
     rule_get_stats,
     rule_execute,
     rule_modify_actions,
+    set_max_resubmit,
     set_frag_handling,
     packet_out,
     set_netflow,
diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
index 15dc347..eb78663 100644
--- a/ofproto/ofproto-provider.h
+++ b/ofproto/ofproto-provider.h
@@ -899,6 +899,14 @@ struct ofproto_class {
      * rule. */
     void (*rule_modify_actions)(struct rule *rule);
 
+    /* Sets the resubmit recursion limit of 'ofproto' to 'max_resubmit'.  Flows
+     * which resubmit deeper than the recursion limit are dropped.
+     *
+     * Returns 0 if successful, or an error.  EOPNOTSUPP as a return value
+     * indicates that 'ofproto' does not support changing the resubmit
+     * recursion limit, as does a null pointer. */
+    int (*set_max_resubmit)(struct ofproto *ofproto, size_t max_resubmit);
+
     /* Changes the OpenFlow IP fragment handling policy to 'frag_handling',
      * which takes one of the following values, with the corresponding
      * meanings:
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index 5c9ab9d..79e9b11 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -455,6 +455,22 @@ ofproto_set_datapath_id(struct ofproto *p, uint64_t datapath_id)
     }
 }
 
+/* Sets the resubmit recursion limit of 'ofproto' to 'max_resubmit'.  Flows
+ * which resubmit deeper than the recursion limit are dropped. */
+void
+ofproto_set_max_resubmit(struct ofproto *ofproto, size_t max_resubmit)
+{
+    int error;
+
+    error = (ofproto->ofproto_class->set_max_resubmit
+             ? ofproto->ofproto_class->set_max_resubmit(ofproto, max_resubmit)
+             : EOPNOTSUPP);
+    if (error) {
+        VLOG_WARN("%s: failed to set maximum resubmit limit (%s)",
+                  ofproto->name, strerror(error));
+    }
+}
+
 void
 ofproto_set_controllers(struct ofproto *p,
                         const struct ofproto_controller *controllers,
diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h
index 32a00f2..7911f68 100644
--- a/ofproto/ofproto.h
+++ b/ofproto/ofproto.h
@@ -203,6 +203,7 @@ int ofproto_port_query_by_name(const struct ofproto *, const char *devname,
 /* Top-level configuration. */
 uint64_t ofproto_get_datapath_id(const struct ofproto *);
 void ofproto_set_datapath_id(struct ofproto *, uint64_t datapath_id);
+void ofproto_set_max_resubmit(struct ofproto *, size_t max_resubmit);
 void ofproto_set_controllers(struct ofproto *,
                              const struct ofproto_controller *, size_t n);
 void ofproto_set_fail_mode(struct ofproto *, enum ofproto_fail_mode fail_mode);
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index 9bafa66..5b0a960 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -528,6 +528,7 @@ bridge_reconfigure_continue(const struct ovsrec_open_vswitch *ovs_cfg)
     collect_in_band_managers(ovs_cfg, &managers, &n_managers);
     HMAP_FOR_EACH (br, node, &all_bridges) {
         struct port *port;
+        int max_resubmit;
 
         /* We need the datapath ID early to allow LACP ports to use it as the
          * default system ID. */
@@ -544,6 +545,13 @@ bridge_reconfigure_continue(const struct ovsrec_open_vswitch *ovs_cfg)
                 iface_set_mac(iface);
             }
         }
+
+        max_resubmit = smap_get_int(&br->cfg->other_config,
+                                    "max-resubmit-recursion", -1);
+        if (max_resubmit >= 0) {
+            ofproto_set_max_resubmit(br->ofproto, max_resubmit);
+        }
+
         bridge_configure_mirrors(br);
         bridge_configure_flow_eviction_threshold(br);
         bridge_configure_forward_bpdu(br);
diff --git a/vswitchd/vswitch.xml b/vswitchd/vswitch.xml
index 7b30ce8..d075d84 100644
--- a/vswitchd/vswitch.xml
+++ b/vswitchd/vswitch.xml
@@ -453,6 +453,12 @@
         QoS configured, or if the port does not have a queue with the specified
         ID, the default queue is used instead.
       </column>
+
+      <column name="other_config" key="max-resubmit-recursion"
+              type='{"type": "integer", "minInteger": 0, "maxInteger": 1024}'>
+        Configures how deeply a flow can resubmit before being dropped.  If
+        unset, OVS will choose a reasonable default.
+      </column>
     </group>
 
     <group title="Spanning Tree Configuration">
-- 
1.7.11.4




More information about the dev mailing list