Store ofproto provider meter ID corresponding to the OpenFlow meter ID to
the meter action when installing flow's actions to avoid multi-threaded
access to ofproto's meters.
Changed the ofproto meter API to require the provider keep the provider
meter ID unchanged when modifying a meter.

Signed-off-by: Jarno Rajahalme <jrajaha...@nicira.com>
---
 lib/ofp-actions.h          |    3 +-
 ofproto/ofproto-provider.h |    8 ++---
 ofproto/ofproto.c          |   79 ++++++++++++++++++++++++++++++--------------
 ofproto/ofproto.h          |    3 --
 4 files changed, 61 insertions(+), 32 deletions(-)

diff --git a/lib/ofp-actions.h b/lib/ofp-actions.h
index a3fb60f..0784384 100644
--- a/lib/ofp-actions.h
+++ b/lib/ofp-actions.h
@@ -381,7 +381,8 @@ struct ofpact_metadata {
  * Used for OFPIT13_METER. */
 struct ofpact_meter {
     struct ofpact ofpact;
-    uint32_t meter_id;
+    uint32_t meter_id;            /* OpenFlow meter ID. */
+    uint32_t provider_meter_id;   /* Used internally by ofproto providers. */
 };
 
 /* OFPACT_RESUBMIT.
diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
index 0b8a5e5..4def111 100644
--- a/ofproto/ofproto-provider.h
+++ b/ofproto/ofproto-provider.h
@@ -85,6 +85,7 @@ struct ofproto {
      * OpenFlow meters start at 1.  To avoid confusion we leave the first
      * pointer in the array un-used, and index directly with the OpenFlow
      * meter_id. */
+    struct ovs_rwlock meters_rwlock;
     struct ofputil_meter_features meter_features;
     struct meter **meters; /* 'meter_features.max_meter' + 1 pointers. */
 
@@ -1480,10 +1481,9 @@ struct ofproto_class {
      * implementation.
      *
      * If '*id' is a value other than UINT32_MAX, modifies the existing meter
-     * with that meter provider ID to have configuration 'config'.  On failure,
-     * the existing meter configuration is left intact.  Regardless of success,
-     * any change to '*id' updates the provider meter id used for this
-     * meter. */
+     * with that meter provider ID to have configuration 'config', while
+     * leaving '*id' unchanged.  On failure, the existing meter configuration
+     * is left intact. */
     enum ofperr (*meter_set)(struct ofproto *ofproto, ofproto_meter_id *id,
                              const struct ofputil_meter_config *config);
 
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index f413193..71db0b6 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -2491,40 +2491,63 @@ reject_slave_controller(struct ofconn *ofconn)
 }
 
 /* Finds the OFPACT_METER action, if any, in the 'ofpacts_len' bytes of
- * 'ofpacts'.  If found, returns its meter ID; if not, returns 0.
+ * 'ofpacts'.  If found, returns pointer to the ofpact found, or NULL.
  *
  * This function relies on the order of 'ofpacts' being correct (as checked by
  * ofpacts_verify()). */
-static uint32_t
-find_meter(const struct ofpact ofpacts[], size_t ofpacts_len)
+static struct ofpact *
+find_meter_ofpact(struct ofpact ofpacts[], size_t ofpacts_len)
 {
-    const struct ofpact *a;
+    struct ofpact *a;
 
     OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
         enum ovs_instruction_type inst;
 
         inst = ovs_instruction_type_from_ofpact_type(a->type);
         if (a->type == OFPACT_METER) {
-            return ofpact_get_METER(a)->meter_id;
+            return a;
         } else if (inst > OVSINST_OFPIT13_METER) {
             break;
         }
     }
 
+    return NULL;
+
+}
+
+/* Finds the OFPACT_METER action, if any, in the 'ofpacts_len' bytes of
+ * 'ofpacts'.  If found, returns its meter ID; if not, returns 0.
+ *
+ * This function relies on the order of 'ofpacts' being correct (as checked by
+ * ofpacts_verify()). */
+static uint32_t
+find_meter(struct ofpact ofpacts[], size_t ofpacts_len)
+{
+    const struct ofpact *a = find_meter_ofpact(ofpacts, ofpacts_len);
+
+    if (a) {
+        return ofpact_get_METER(a)->meter_id;
+    }
+
     return 0;
 }
 
+static uint32_t get_provider_meter_id(const struct ofproto * ofproto,
+                                      uint32_t of_meter_id);
+
 /* Checks that the 'ofpacts_len' bytes of actions in 'ofpacts' are appropriate
  * for a packet with the prerequisites satisfied by 'flow' in table 'table_id'.
  * 'flow' may be temporarily modified, but is restored at return.
- */
+ * ofproto private fields in actions may be set as required for further action
+ * processing. */
 static enum ofperr
-ofproto_check_ofpacts(struct ofproto *ofproto,
-                      const struct ofpact ofpacts[], size_t ofpacts_len,
-                      struct flow *flow, uint8_t table_id)
+ofproto_check_and_set_ofpacts(struct ofproto *ofproto,
+                              struct ofpact ofpacts[],
+                              size_t ofpacts_len,
+                              struct flow *flow, uint8_t table_id)
 {
     enum ofperr error;
-    uint32_t mid;
+    struct ofpact *a;
 
     error = ofpacts_check(ofpacts, ofpacts_len, flow,
                           u16_to_ofp(ofproto->max_ports), table_id);
@@ -2532,9 +2555,16 @@ ofproto_check_ofpacts(struct ofproto *ofproto,
         return error;
     }
 
-    mid = find_meter(ofpacts, ofpacts_len);
-    if (mid && ofproto_get_provider_meter_id(ofproto, mid) == UINT32_MAX) {
-        return OFPERR_OFPMMFC_INVALID_METER;
+    a = find_meter_ofpact(ofpacts, ofpacts_len);
+    if (a) {
+        uint32_t mid;
+        mid = get_provider_meter_id(ofproto, ofpact_get_METER(a)->meter_id);
+        if (mid == UINT32_MAX) {
+            return OFPERR_OFPMMFC_INVALID_METER;
+        } else {
+            /* Store the provider meter ID. */
+            ofpact_get_METER(a)->provider_meter_id = mid;
+        }
     }
     return 0;
 }
@@ -2585,7 +2615,8 @@ handle_packet_out(struct ofconn *ofconn, const struct 
ofp_header *oh)
     /* Verify actions against packet, then send packet if successful. */
     in_port_.ofp_port = po.in_port;
     flow_extract(payload, 0, 0, NULL, &in_port_, &flow);
-    error = ofproto_check_ofpacts(p, po.ofpacts, po.ofpacts_len, &flow, 0);
+    error = ofproto_check_and_set_ofpacts(p, po.ofpacts, po.ofpacts_len,
+                                          &flow, 0);
     if (!error) {
         error = p->ofproto_class->packet_out(p, payload, &flow,
                                              po.ofpacts, po.ofpacts_len);
@@ -3512,8 +3543,9 @@ add_flow(struct ofproto *ofproto, struct ofconn *ofconn,
     }
 
     /* Verify actions. */
-    error = ofproto_check_ofpacts(ofproto, fm->ofpacts, fm->ofpacts_len,
-                                  &fm->match.flow, table_id);
+    error = ofproto_check_and_set_ofpacts(ofproto, fm->ofpacts,
+                                          fm->ofpacts_len, &fm->match.flow,
+                                          table_id);
     if (error) {
         cls_rule_destroy(&cr);
         return error;
@@ -4445,9 +4477,9 @@ handle_flow_monitor_cancel(struct ofconn *ofconn, const 
struct ofp_header *oh)
  * 'provider_meter_id' is for the provider's private use.
  */
 struct meter {
+    ofproto_meter_id provider_meter_id;
     long long int created;      /* Time created. */
     struct list rules;          /* List of "struct rule_dpif"s. */
-    ofproto_meter_id provider_meter_id;
     uint16_t flags;             /* Meter flags. */
     uint16_t n_bands;           /* Number of meter bands. */
     struct ofputil_meter_band *bands;
@@ -4456,13 +4488,10 @@ struct meter {
 /*
  * This is used in instruction validation at flow set-up time,
  * as flows may not use non-existing meters.
- * This is also used by ofproto-providers to translate OpenFlow meter_ids
- * in METER instructions to the corresponding provider meter IDs.
  * Return value of UINT32_MAX signifies an invalid meter.
  */
-uint32_t
-ofproto_get_provider_meter_id(const struct ofproto * ofproto,
-                              uint32_t of_meter_id)
+static uint32_t
+get_provider_meter_id(const struct ofproto * ofproto, uint32_t of_meter_id)
 {
     if (of_meter_id && of_meter_id <= ofproto->meter_features.max_meters) {
         const struct meter *meter = ofproto->meters[of_meter_id];
@@ -4533,7 +4562,7 @@ handle_add_meter(struct ofproto *ofproto, struct 
ofputil_meter_mod *mm)
         ovs_assert(provider_meter_id.uint32 != UINT32_MAX);
         *meterp = meter_create(&mm->meter, provider_meter_id);
     }
-    return 0;
+    return error;
 }
 
 static enum ofperr
@@ -4541,15 +4570,17 @@ handle_modify_meter(struct ofproto *ofproto, struct 
ofputil_meter_mod *mm)
 {
     struct meter *meter = ofproto->meters[mm->meter.meter_id];
     enum ofperr error;
+    uint32_t provider_meter_id;
 
     if (!meter) {
         return OFPERR_OFPMMFC_UNKNOWN_METER;
     }
 
+    provider_meter_id = meter->provider_meter_id.uint32;
     error = ofproto->ofproto_class->meter_set(ofproto,
                                               &meter->provider_meter_id,
                                               &mm->meter);
-    ovs_assert(meter->provider_meter_id.uint32 != UINT32_MAX);
+    ovs_assert(meter->provider_meter_id.uint32 == provider_meter_id);
     if (!error) {
         meter_update(meter, &mm->meter);
     }
diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h
index 9adda2c..c42b068 100644
--- a/ofproto/ofproto.h
+++ b/ofproto/ofproto.h
@@ -434,9 +434,6 @@ bool ofproto_has_vlan_usage_changed(const struct ofproto *);
 int ofproto_port_set_realdev(struct ofproto *, ofp_port_t vlandev_ofp_port,
                              ofp_port_t realdev_ofp_port, int vid);
 
-uint32_t ofproto_get_provider_meter_id(const struct ofproto *,
-                                       uint32_t of_meter_id);
-
 #ifdef  __cplusplus
 }
 #endif
-- 
1.7.10.4

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

Reply via email to