summaryrefslogtreecommitdiff
path: root/lib/vconn.c
diff options
context:
space:
mode:
authorBen Pfaff <blp@nicira.com>2010-11-23 13:05:59 -0800
committerBen Pfaff <blp@nicira.com>2010-12-02 14:57:04 -0800
commit33af7dcad396cb9bfc7d09622d47be853bf662dd (patch)
treebfd0b73e3b7b3cddee5ab8d2271a3518dd836210 /lib/vconn.c
parent3df3373283d794c03e1cd18585089d9f658ebd8c (diff)
downloadopenvswitch-33af7dcad396cb9bfc7d09622d47be853bf662dd.tar.gz
vconn: New function vconn_transact_noreply().
Diffstat (limited to 'lib/vconn.c')
-rw-r--r--lib/vconn.c77
1 files changed, 77 insertions, 0 deletions
diff --git a/lib/vconn.c b/lib/vconn.c
index fc1aff6b6..d6d2bf42e 100644
--- a/lib/vconn.c
+++ b/lib/vconn.c
@@ -682,6 +682,10 @@ vconn_recv_xid(struct vconn *vconn, ovs_be32 xid, struct ofpbuf **replyp)
* is stored in '*replyp' for the caller to examine and free. Otherwise
* returns a positive errno value, or EOF, and sets '*replyp' to null.
*
+ * 'request' should be an OpenFlow request that requires a reply. Otherwise,
+ * if there is no reply, this function can end up blocking forever (or until
+ * the peer drops the connection).
+ *
* 'request' is always destroyed, regardless of the return value. */
int
vconn_transact(struct vconn *vconn, struct ofpbuf *request,
@@ -698,6 +702,79 @@ 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
+ * '*replyp' to null.
+ *
+ * This function is useful for sending an OpenFlow request that doesn't
+ * ordinarily include a reply but might report an error in special
+ * circumstances.
+ *
+ * 'request' is always destroyed, regardless of the return value. */
+int
+vconn_transact_noreply(struct vconn *vconn, struct ofpbuf *request,
+ struct ofpbuf **replyp)
+{
+ ovs_be32 request_xid;
+ ovs_be32 barrier_xid;
+ struct ofpbuf *barrier;
+ int error;
+
+ *replyp = NULL;
+
+ /* Send request. */
+ request_xid = ((struct ofp_header *) request->data)->xid;
+ error = vconn_send_block(vconn, request);
+ if (error) {
+ ofpbuf_delete(request);
+ return error;
+ }
+
+ /* Send barrier. */
+ make_openflow(sizeof(struct ofp_header), OFPT_BARRIER_REQUEST, &barrier);
+ barrier_xid = ((struct ofp_header *) barrier->data)->xid;
+ error = vconn_send_block(vconn, barrier);
+ if (error) {
+ ofpbuf_delete(barrier);
+ return error;
+ }
+
+ for (;;) {
+ struct ofpbuf *msg;
+ ovs_be32 msg_xid;
+ int error;
+
+ error = vconn_recv_block(vconn, &msg);
+ if (error) {
+ ofpbuf_delete(*replyp);
+ *replyp = NULL;
+ return error;
+ }
+
+ msg_xid = ((struct ofp_header *) msg->data)->xid;
+ if (msg_xid == request_xid) {
+ if (*replyp) {
+ VLOG_WARN_RL(&bad_ofmsg_rl, "%s: duplicate replies with "
+ "xid %08"PRIx32, vconn->name, ntohl(msg_xid));
+ ofpbuf_delete(*replyp);
+ }
+ *replyp = msg;
+ } else {
+ ofpbuf_delete(msg);
+ if (msg_xid == barrier_xid) {
+ return 0;
+ } else {
+ VLOG_DBG_RL(&bad_ofmsg_rl, "%s: reply with xid %08"PRIx32
+ " != expected %08"PRIx32" or %08"PRIx32,
+ vconn->name, ntohl(msg_xid),
+ ntohl(request_xid), ntohl(barrier_xid));
+ }
+ }
+ }
+}
+
void
vconn_wait(struct vconn *vconn, enum vconn_wait_type wait)
{