Until now "ovs-ofctl add-flows ..." command sent each OFPC_ADD
request one by one accompanied with a barrier request.  This
meant that before ovs-ofctl could send next OFPC_ADD request
it had to wait for a barrier response that was sent together
with previous OFPC_ADD request.

After this patch ovs-ofctl batches together all OFPC_ADD requests
and sends only a single barrier request for the last OFPC_ADD
request.  As a result of this patch, ovs-ofctl was able to insert
60K flows in 1 second instead of 7 seconds.  This is especially
helpful when restarting ovs-vswitchd.

One possible side effect of this patch is that ovs-ofctl
might ignore some error messages that resulted in failed
OFPC_ADD.

Signed-off-by: Ansis Atteka <aatt...@nicira.com>
---
 include/openvswitch/vconn.h |    5 +++--
 lib/vconn.c                 |   32 ++++++++++++++++++++++--------
 utilities/ovs-ofctl.c       |   45 +++++++++++++++++++++++++------------------
 3 files changed, 53 insertions(+), 29 deletions(-)

diff --git a/include/openvswitch/vconn.h b/include/openvswitch/vconn.h
index 3b157e1..d7bc420 100644
--- a/include/openvswitch/vconn.h
+++ b/include/openvswitch/vconn.h
@@ -52,9 +52,10 @@ int vconn_recv(struct vconn *, struct ofpbuf **);
 int vconn_send(struct vconn *, struct ofpbuf *);
 int vconn_recv_xid(struct vconn *, ovs_be32 xid, struct ofpbuf **);
 int vconn_transact(struct vconn *, struct ofpbuf *, struct ofpbuf **);
-int vconn_transact_noreply(struct vconn *, struct ofpbuf *, struct ofpbuf **);
+int vconn_transact_noreply(struct vconn *, struct ofpbuf *, struct ofpbuf **,
+                           bool skip_barrier);
 int vconn_transact_multiple_noreply(struct vconn *, struct ovs_list *requests,
-                                    struct ofpbuf **replyp);
+                                    struct ofpbuf **replyp, bool batch);
 
 void vconn_run(struct vconn *);
 void vconn_run_wait(struct vconn *);
diff --git a/lib/vconn.c b/lib/vconn.c
index 5a28603..c93c657 100644
--- a/lib/vconn.c
+++ b/lib/vconn.c
@@ -801,10 +801,11 @@ vconn_transact(struct vconn *vconn, struct ofpbuf 
*request,
     return error ? error : vconn_recv_xid(vconn, send_xid, replyp);
 }
 
-/* Sends 'request' followed by a barrier request to 'vconn', then blocks until
- * it receives a reply to the barrier.  If successful, stores the reply to
- * 'request' in '*replyp', if one was received, and otherwise NULL, then
- * returns 0.  Otherwise returns a positive errno value, or EOF, and sets
+/* Sends 'request' to 'vconn'.  If 'skip_barrier' is not set, then also
+ * sends a barrier request and blocks until it receives a barrier reply.
+ * If successful, stores the reply to 'request' in '*replyp',
+ * if one was received, and otherwise NULL, then returns 0.
+ * Otherwise returns a positive errno value, or EOF, and sets
  * '*replyp' to null.
  *
  * This function is useful for sending an OpenFlow request that doesn't
@@ -814,7 +815,7 @@ vconn_transact(struct vconn *vconn, struct ofpbuf *request,
  * 'request' is always destroyed, regardless of the return value. */
 int
 vconn_transact_noreply(struct vconn *vconn, struct ofpbuf *request,
-                       struct ofpbuf **replyp)
+                       struct ofpbuf **replyp, bool skip_barrier)
 {
     ovs_be32 request_xid;
     ovs_be32 barrier_xid;
@@ -831,6 +832,20 @@ vconn_transact_noreply(struct vconn *vconn, struct ofpbuf 
*request,
         return error;
     }
 
+    if (skip_barrier) {
+        /* Don't send barrier.  However, if there are any pending replies,
+         * then still read them and discard. */
+        int retval;
+        struct ofpbuf *msgp = NULL;
+
+        while (!(retval = vconn_recv(vconn, &msgp))) {
+            ofpbuf_delete(msgp);
+            msgp = NULL;
+        }
+
+        return retval == EAGAIN ? 0 : retval;
+    }
+
     /* Send barrier. */
     barrier = ofputil_encode_barrier_request(vconn_get_version(vconn));
     barrier_xid = ((struct ofp_header *) barrier->data)->xid;
@@ -876,10 +891,11 @@ vconn_transact_noreply(struct vconn *vconn, struct ofpbuf 
*request,
 
 /* vconn_transact_noreply() for a list of "struct ofpbuf"s, sent one by one.
  * All of the requests on 'requests' are always destroyed, regardless of the
- * return value. */
+ * return value.  if 'skip_barrier' is set, then request will be sent
+ * witout waiting for changes to be actually committed. */
 int
 vconn_transact_multiple_noreply(struct vconn *vconn, struct ovs_list *requests,
-                                struct ofpbuf **replyp)
+                                struct ofpbuf **replyp, bool skip_barrier)
 {
     struct ofpbuf *request, *next;
 
@@ -888,7 +904,7 @@ vconn_transact_multiple_noreply(struct vconn *vconn, struct 
ovs_list *requests,
 
         list_remove(&request->list_node);
 
-        error = vconn_transact_noreply(vconn, request, replyp);
+        error = vconn_transact_noreply(vconn, request, replyp, skip_barrier);
         if (error || *replyp) {
             ofpbuf_list_delete(requests);
             return error;
diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c
index 44c5275..ffe13a0 100644
--- a/utilities/ovs-ofctl.c
+++ b/utilities/ovs-ofctl.c
@@ -582,7 +582,8 @@ dump_trivial_stats_transaction(const char *vconn_name, enum 
ofpraw raw)
  *
  * Destroys all of the 'requests'. */
 static void
-transact_multiple_noreply(struct vconn *vconn, struct ovs_list *requests)
+transact_multiple_noreply(struct vconn *vconn, struct ovs_list *requests,
+                          bool skip_barrier)
 {
     struct ofpbuf *request, *reply;
 
@@ -590,7 +591,7 @@ transact_multiple_noreply(struct vconn *vconn, struct 
ovs_list *requests)
         ofpmsg_update_length(request);
     }
 
-    run(vconn_transact_multiple_noreply(vconn, requests, &reply),
+    run(vconn_transact_multiple_noreply(vconn, requests, &reply, skip_barrier),
         "talking to %s", vconn_get_name(vconn));
     if (reply) {
         ofp_print(stderr, reply->data, reply->size, verbosity + 2);
@@ -605,13 +606,14 @@ transact_multiple_noreply(struct vconn *vconn, struct 
ovs_list *requests)
  *
  * Destroys 'request'. */
 static void
-transact_noreply(struct vconn *vconn, struct ofpbuf *request)
+transact_noreply(struct vconn *vconn, struct ofpbuf *request,
+                 bool skip_barrier)
 {
     struct ovs_list requests;
 
     list_init(&requests);
     list_push_back(&requests, &request->list_node);
-    transact_multiple_noreply(vconn, &requests);
+    transact_multiple_noreply(vconn, &requests, skip_barrier);
 }
 
 static void
@@ -645,7 +647,7 @@ set_switch_config(struct vconn *vconn, const struct 
ofp_switch_config *config)
     request = ofpraw_alloc(OFPRAW_OFPT_SET_CONFIG, vconn_get_version(vconn), 
0);
     ofpbuf_put(request, config, sizeof *config);
 
-    transact_noreply(vconn, request);
+    transact_noreply(vconn, request, false);
 }
 
 static void
@@ -903,7 +905,7 @@ try_set_protocol(struct vconn *vconn, enum ofputil_protocol 
want,
             return *cur == want;
         }
 
-        run(vconn_transact_noreply(vconn, request, &reply),
+        run(vconn_transact_noreply(vconn, request, &reply, false),
             "talking to %s", vconn_get_name(vconn));
         if (reply) {
             char *s = ofp_to_string(reply->data, reply->size, 2);
@@ -1173,7 +1175,8 @@ open_vconn_for_flow_mod(const char *remote, struct vconn 
**vconnp,
 
 static void
 ofctl_flow_mod__(const char *remote, struct ofputil_flow_mod *fms,
-                 size_t n_fms, enum ofputil_protocol usable_protocols)
+                 size_t n_fms, enum ofputil_protocol usable_protocols,
+                 bool batch)
 {
     enum ofputil_protocol protocol;
     struct vconn *vconn;
@@ -1183,8 +1186,11 @@ ofctl_flow_mod__(const char *remote, struct 
ofputil_flow_mod *fms,
 
     for (i = 0; i < n_fms; i++) {
         struct ofputil_flow_mod *fm = &fms[i];
+        bool skip_barrier = batch && (i < (n_fms - 1));
 
-        transact_noreply(vconn, ofputil_encode_flow_mod(fm, protocol));
+        /* Don't send barrier request for the last message if batch is set */
+        transact_noreply(vconn, ofputil_encode_flow_mod(fm, protocol),
+                         skip_barrier);
         free(CONST_CAST(struct ofpact *, fm->ofpacts));
     }
     vconn_close(vconn);
@@ -1203,7 +1209,7 @@ ofctl_flow_mod_file(int argc OVS_UNUSED, char *argv[], 
uint16_t command)
     if (error) {
         ovs_fatal(0, "%s", error);
     }
-    ofctl_flow_mod__(argv[1], fms, n_fms, usable_protocols);
+    ofctl_flow_mod__(argv[1], fms, n_fms, usable_protocols, true);
     free(fms);
 }
 
@@ -1222,7 +1228,7 @@ ofctl_flow_mod(int argc, char *argv[], uint16_t command)
         if (error) {
             ovs_fatal(0, "%s", error);
         }
-        ofctl_flow_mod__(argv[1], &fm, 1, usable_protocols);
+        ofctl_flow_mod__(argv[1], &fm, 1, usable_protocols, false);
     }
 }
 
@@ -1258,7 +1264,7 @@ set_packet_in_format(struct vconn *vconn,
 
     spif = ofputil_make_set_packet_in_format(vconn_get_version(vconn),
                                              packet_in_format);
-    transact_noreply(vconn, spif);
+    transact_noreply(vconn, spif, false);
     VLOG_DBG("%s: using user-specified packet in format %s",
              vconn_get_name(vconn),
              ofputil_packet_in_format_to_string(packet_in_format));
@@ -1591,7 +1597,7 @@ ofctl_monitor(int argc, char *argv[])
 
             spif = ofputil_make_set_packet_in_format(vconn_get_version(vconn),
                                                      NXPIF_NXM);
-            run(vconn_transact_noreply(vconn, spif, &reply),
+            run(vconn_transact_noreply(vconn, spif, &reply, false),
                 "talking to %s", vconn_get_name(vconn));
             if (reply) {
                 char *s = ofp_to_string(reply->data, reply->size, 2);
@@ -1708,7 +1714,7 @@ ofctl_packet_out(int argc, char *argv[])
         po.packet = dp_packet_data(packet);
         po.packet_len = dp_packet_size(packet);
         opo = ofputil_encode_packet_out(&po, protocol);
-        transact_noreply(vconn, opo);
+        transact_noreply(vconn, opo, false);
         dp_packet_delete(packet);
     }
     vconn_close(vconn);
@@ -1771,7 +1777,7 @@ ofctl_mod_port(int argc OVS_UNUSED, char *argv[])
 
 found:
     protocol = open_vconn(argv[1], &vconn);
-    transact_noreply(vconn, ofputil_encode_port_mod(&pm, protocol));
+    transact_noreply(vconn, ofputil_encode_port_mod(&pm, protocol), false);
     vconn_close(vconn);
 }
 
@@ -1807,7 +1813,7 @@ ofctl_mod_table(int argc OVS_UNUSED, char *argv[])
         ovs_fatal(0, "Switch does not support table mod message(%s)", 
usable_s);
     }
 
-    transact_noreply(vconn, ofputil_encode_table_mod(&tm, protocol));
+    transact_noreply(vconn, ofputil_encode_table_mod(&tm, protocol), false);
     vconn_close(vconn);
 }
 
@@ -2104,7 +2110,7 @@ ofctl_group_mod__(const char *remote, struct 
ofputil_group_mod *gms,
         gm = &gms[i];
         request = ofputil_encode_group_mod(version, gm);
         if (request) {
-            transact_noreply(vconn, request);
+            transact_noreply(vconn, request, false);
         }
     }
 
@@ -2632,7 +2638,7 @@ ofctl_replace_flows(int argc OVS_UNUSED, char *argv[])
             fte_make_flow_mod(fte, FILE_IDX, OFPFC_ADD, protocol, &requests);
         }
     }
-    transact_multiple_noreply(vconn, &requests);
+    transact_multiple_noreply(vconn, &requests, false);
     vconn_close(vconn);
 
     fte_free_all(&cls);
@@ -2724,7 +2730,7 @@ ofctl_meter_mod__(const char *bridge, const char *str, 
int command)
 
     protocol = open_vconn_for_flow_mod(bridge, &vconn, usable_protocols);
     version = ofputil_protocol_to_ofp_version(protocol);
-    transact_noreply(vconn, ofputil_encode_meter_mod(version, &mm));
+    transact_noreply(vconn, ofputil_encode_meter_mod(version, &mm), false);
     vconn_close(vconn);
 }
 
@@ -2753,7 +2759,8 @@ ofctl_meter_request__(const char *bridge, const char *str,
     version = ofputil_protocol_to_ofp_version(protocol);
     transact_noreply(vconn, ofputil_encode_meter_request(version,
                                                          type,
-                                                         mm.meter.meter_id));
+                                                         mm.meter.meter_id),
+                     false);
     vconn_close(vconn);
 }
 
-- 
1.7.9.5

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

Reply via email to