From dd5616b3d2722dba0eb4597d4b04af9386f5bfbb Mon Sep 17 00:00:00 2001
From: Ben Pfaff <blp@nicira.com>
Date: Wed, 10 Aug 2011 14:48:33 -0700
Subject: [PATCH] ofproto: Avoid using list_size() to compute length of
 'pending' list.

Currently this only gets checked for incoming OpenFlow OFPT_FLOW_MOD
messages, so it's hard to imagine it being any kind of bottleneck, but the
NXAST_LEARN action that is soon to be added will be able to create flows
more quickly than we normally expect from a controller.  (On the other
hand, ofproto-dpif, outside of a special testing mode, always completes
operations immediately, so 'pending' will always have length 0.  But this
change still feels right to me for some reason.)
---
 ofproto/ofproto-provider.h | 1 +
 ofproto/ofproto.c          | 8 +++++++-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
index fa583f86..6e29ed9b 100644
--- a/ofproto/ofproto-provider.h
+++ b/ofproto/ofproto-provider.h
@@ -64,6 +64,7 @@ struct ofproto {
     /* Flow table operation tracking. */
     int state;                  /* Internal state. */
     struct list pending;        /* List of "struct ofopgroup"s. */
+    unsigned int n_pending;     /* list_size(&pending). */
     struct hmap deletions;      /* All OFOPERATION_DELETE "ofoperation"s. */
 };
 
diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
index cbd89281..079927bd 100644
--- a/ofproto/ofproto.c
+++ b/ofproto/ofproto.c
@@ -338,6 +338,7 @@ ofproto_create(const char *datapath_name, const char *datapath_type,
     ofproto->connmgr = connmgr_create(ofproto, datapath_name, datapath_name);
     ofproto->state = S_OPENFLOW;
     list_init(&ofproto->pending);
+    ofproto->n_pending = 0;
     hmap_init(&ofproto->deletions);
 
     error = ofproto->ofproto_class->construct(ofproto, &n_tables);
@@ -713,6 +714,7 @@ ofproto_destroy__(struct ofproto *ofproto)
     struct classifier *table;
 
     assert(list_is_empty(&ofproto->pending));
+    assert(!ofproto->n_pending);
 
     connmgr_destroy(ofproto->connmgr);
 
@@ -2475,7 +2477,8 @@ handle_flow_mod(struct ofconn *ofconn, const struct ofp_header *oh)
         return error;
     }
 
-    if (list_size(&ofproto->pending) >= 50) {
+    if (ofproto->n_pending >= 50) {
+        assert(!list_is_empty(&ofproto->pending));
         return OFPROTO_POSTPONE;
     }
 
@@ -2778,6 +2781,7 @@ ofopgroup_submit(struct ofopgroup *group)
         ofopgroup_destroy(group);
     } else {
         list_push_back(&group->ofproto->pending, &group->ofproto_node);
+        group->ofproto->n_pending++;
     }
 }
 
@@ -2786,6 +2790,8 @@ ofopgroup_destroy(struct ofopgroup *group)
 {
     assert(list_is_empty(&group->ops));
     if (!list_is_empty(&group->ofproto_node)) {
+        assert(group->ofproto->n_pending > 0);
+        group->ofproto->n_pending--;
         list_remove(&group->ofproto_node);
     }
     if (!list_is_empty(&group->ofconn_node)) {
-- 
2.30.2