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