From 33af7dcad396cb9bfc7d09622d47be853bf662dd Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Tue, 23 Nov 2010 13:05:59 -0800 Subject: [PATCH] vconn: New function vconn_transact_noreply(). --- lib/vconn.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/vconn.h | 1 + 2 files changed, 78 insertions(+) diff --git a/lib/vconn.c b/lib/vconn.c index fc1aff6b..d6d2bf42 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) { diff --git a/lib/vconn.h b/lib/vconn.h index e3412052..79666be3 100644 --- a/lib/vconn.h +++ b/lib/vconn.h @@ -48,6 +48,7 @@ int vconn_recv(struct vconn *, struct ofpbuf **); int vconn_send(struct vconn *, struct ofpbuf *); int vconn_recv_xid(struct vconn *, uint32_t xid, struct ofpbuf **); int vconn_transact(struct vconn *, struct ofpbuf *, struct ofpbuf **); +int vconn_transact_noreply(struct vconn *, struct ofpbuf *, struct ofpbuf **); void vconn_run(struct vconn *); void vconn_run_wait(struct vconn *); -- 2.30.2