Recirculation ID needs to be unique per datapath. Its usage will be
tracked by the backer that corresponds to the datapath.

In theory, Recirculation ID can be any uint32_t value, except 0. This
implementation limits to a smaller range just for ease of debugging.
Make the range size 0 effectively disables recirculation.

Signed-off-by: Andy Zhou <az...@nicira.com>
---
 ofproto/ofproto-dpif.c |  152 +++++++++++++++++++++++++++++++++++++++++++++++-
 ofproto/ofproto-dpif.h |    4 ++
 2 files changed, 155 insertions(+), 1 deletion(-)

diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index cc1e9d5..b79f335 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -236,6 +236,29 @@ COVERAGE_DEFINE(rev_port_toggled);
 COVERAGE_DEFINE(rev_flow_table);
 COVERAGE_DEFINE(rev_mac_learning);
 
+/* A map for recirculation ID allocation. */
+struct rid_map {
+    struct hmap map;
+};
+
+struct rid_node {
+    struct hmap_node node;
+    uint32_t recirc_id;
+};
+
+struct recirc_id_set {
+    struct rid_map ridmap;
+    uint32_t base;         /* IDs in the range of [base, base + n_ids). */
+    uint32_t n_ids;        /* Total number of ids in the set. */
+    uint32_t next_free_id; /* Possible next free id. */
+};
+
+static void recirc_id_set_init(struct recirc_id_set *set, uint32_t base,
+                          uint32_t n_ids);
+static void recirc_id_set_uninit(struct recirc_id_set *set);
+static uint32_t recirc_id_alloc(struct recirc_id_set *set);
+static void recirc_id_free(struct recirc_id_set *set, uint32_t recirc_id);
+
 /* All datapaths of a given type share a single dpif backer instance. */
 struct dpif_backer {
     char *type;
@@ -252,6 +275,10 @@ struct dpif_backer {
 
     bool recv_set_enable; /* Enables or disables receiving packets. */
 
+    /* Recirculation. */
+    struct ovs_mutex recirc_id_lock; /* lock for recirc_ids */
+    struct recirc_id_set rids;       /* Managing recirculation ID. */
+
     /* True if the datapath supports variable-length
      * OVS_USERSPACE_ATTR_USERDATA in OVS_ACTION_ATTR_USERSPACE actions.
      * False if the datapath supports only 8-byte (or shorter) userdata. */
@@ -768,9 +795,9 @@ close_dpif_backer(struct dpif_backer *backer)
     ovs_rwlock_destroy(&backer->odp_to_ofport_lock);
     hmap_destroy(&backer->odp_to_ofport_map);
     shash_find_and_delete(&all_dpif_backers, backer->type);
+    recirc_id_set_uninit(&backer->rids);
     free(backer->type);
     dpif_close(backer->dpif);
-
     free(backer);
 }
 
@@ -886,6 +913,9 @@ open_dpif_backer(const char *type, struct dpif_backer 
**backerp)
         udpif_set_threads(backer->udpif, n_handlers, n_revalidators);
     }
 
+    ovs_mutex_init(&backer->recirc_id_lock);
+    recirc_id_set_init(&backer->rids, 0, 0);
+
     return error;
 }
 
@@ -4359,6 +4389,126 @@ vsp_add(struct ofport_dpif *port, ofp_port_t 
realdev_ofp_port, int vid)
     ovs_mutex_unlock(&ofproto->vsp_mutex);
 }
 
+static void
+recirc_id_set_init(struct recirc_id_set *set, uint32_t base,
+                          uint32_t n_ids)
+{
+    set->base = base;
+    set->n_ids = n_ids;
+    set->next_free_id = base;
+    hmap_init(&set->ridmap.map);
+}
+
+static void
+recirc_id_set_uninit(struct recirc_id_set *set)
+{
+    struct rid_node *rid, *next;
+
+    HMAP_FOR_EACH_SAFE(rid, next, node, &set->ridmap.map) {
+        hmap_remove(&set->ridmap.map, &rid->node);
+        free(rid);
+    }
+
+    hmap_destroy(&set->ridmap.map);
+}
+
+static struct rid_node *
+ridset_find(struct recirc_id_set *set, uint32_t id)
+{
+    size_t hash;
+    struct rid_node *rid;
+
+    hash = hash_int(id, 0);
+    HMAP_FOR_EACH_WITH_HASH(rid, node, hash, &set->ridmap.map) {
+        if (id == rid->recirc_id) {
+            return rid;
+        }
+    }
+    return NULL;
+}
+
+static struct rid_node *
+ridset_add(struct recirc_id_set *set, uint32_t id)
+{
+    struct rid_node *rid = xmalloc(sizeof *rid);
+    size_t hash;
+
+    rid->recirc_id = id;
+    hash = hash_int(id, 0);
+    hmap_insert(&set->ridmap.map, &rid->node, hash);
+    return rid;
+}
+
+static uint32_t
+recirc_id_alloc(struct recirc_id_set *set)
+{
+    uint32_t id;
+
+    if (set->n_ids == 0)
+        return 0;
+
+    if (!(ridset_find(set, set->next_free_id))) {
+        id = set->next_free_id;
+        goto found_free_id;
+    }
+
+    for (id = set->base; id < set->base + set->n_ids; id++) {
+        if ((ridset_find(set, id)))
+            goto found_free_id;
+    }
+
+    /* Not available. */
+    return 0;
+
+found_free_id:
+    ridset_add(set, id);
+
+    if (id < set->base + set->n_ids) {
+        set->next_free_id = id + 1;
+    } else {
+        set->next_free_id = set->base;
+    }
+
+    return id;
+}
+
+static void
+recirc_id_free(struct recirc_id_set *set, uint32_t recirc_id)
+{
+    struct rid_node *rid;
+    if (recirc_id > set->base && (recirc_id <= set->base + set->n_ids)) {
+        rid = ridset_find(set, recirc_id);
+        if (rid) {
+            hmap_remove(&set->ridmap.map, &rid->node);
+        }
+    }
+}
+
+uint32_t
+ofproto_dpif_alloc_recirc_id(struct ofproto *ofproto_)
+{
+    struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
+    struct dpif_backer *backer = ofproto->backer;
+    uint32_t id;
+
+    ovs_mutex_lock(&backer->recirc_id_lock);
+    id = recirc_id_alloc(&backer->rids);
+    ovs_mutex_unlock(&backer->recirc_id_lock);
+
+    return id;
+}
+
+void
+ofproto_dpif_free_recirc_id(struct ofproto *ofproto_, uint32_t recirc_id)
+{
+    struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
+    struct dpif_backer *backer = ofproto->backer;
+
+    ovs_mutex_lock(&backer->recirc_id_lock);
+    recirc_id_free(&backer->rids, recirc_id);
+    ovs_mutex_unlock(&backer->recirc_id_lock);
+}
+
 static odp_port_t
 ofp_port_to_odp_port(const struct ofproto_dpif *ofproto, ofp_port_t ofp_port)
 {
diff --git a/ofproto/ofproto-dpif.h b/ofproto/ofproto-dpif.h
index 5da0b5d..898448a 100644
--- a/ofproto/ofproto-dpif.h
+++ b/ofproto/ofproto-dpif.h
@@ -27,6 +27,7 @@
 
 union user_action_cookie;
 struct dpif_flow_stats;
+struct ofproto;
 struct ofproto_dpif;
 struct ofproto_packet_in;
 struct ofport_dpif;
@@ -117,6 +118,9 @@ void ofproto_dpif_send_packet_in(struct ofproto_dpif *,
 int ofproto_dpif_send_packet(const struct ofport_dpif *, struct ofpbuf *);
 void ofproto_dpif_flow_mod(struct ofproto_dpif *, struct ofputil_flow_mod *);
 
+uint32_t ofproto_dpif_alloc_recirc_id(struct ofproto *ofproto_);
+void ofproto_dpif_free_recirc_id(struct ofproto *ofproto_, uint32_t recirc_id);
+
 struct ofport_dpif *odp_port_to_ofport(const struct dpif_backer *, odp_port_t);
 
 #endif /* ofproto-dpif.h */
-- 
1.7.9.5

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

Reply via email to