Fix learning-switch STP breakage from "out_port" in flow stats request.
[sliver-openvswitch.git] / lib / vconn.c
index ee7f678..e630258 100644 (file)
@@ -44,7 +44,7 @@
 #include "flow.h"
 #include "ofp-print.h"
 #include "ofpbuf.h"
-#include "openflow.h"
+#include "openflow/openflow.h"
 #include "poll-loop.h"
 #include "random.h"
 #include "util.h"
@@ -319,7 +319,7 @@ vcs_recv_hello(struct vconn *vconn)
                 struct ds msg = DS_EMPTY_INITIALIZER;
                 ds_put_format(&msg, "%s: extra-long hello:\n", vconn->name);
                 ds_put_hex_dump(&msg, b->data, b->size, 0, true);
-                VLOG_WARN_RL(&rl, ds_cstr(&msg));
+                VLOG_WARN_RL(&rl, "%s", ds_cstr(&msg));
                 ds_destroy(&msg);
             }
 
@@ -372,6 +372,7 @@ vcs_send_error(struct vconn *vconn)
     error->type = htons(OFPET_HELLO_FAILED);
     error->code = htons(OFPHFC_INCOMPATIBLE);
     ofpbuf_put(b, s, strlen(s));
+    update_openflow_length(b);
     retval = do_send(vconn, b);
     if (retval) {
         ofpbuf_delete(b);
@@ -467,11 +468,11 @@ do_recv(struct vconn *vconn, struct ofpbuf **msgp)
             && oh->type != OFPT_VENDOR)
         {
             if (vconn->version < 0) {
-                VLOG_ERR_RL(&rl, "%s: received OpenFlow version %02"PRIx8" "
+                VLOG_ERR_RL(&rl, "%s: received OpenFlow message type %"PRIu8" "
                             "before version negotiation complete",
-                            vconn->name, oh->version);
+                            vconn->name, oh->type);
             } else {
-                VLOG_ERR_RL(&rl, "%s: received OpenFlow version %02"PRIx8" "
+                VLOG_ERR_RL(&rl, "%s: received OpenFlow version 0x%02"PRIx8" "
                             "!= expected %02x",
                             vconn->name, oh->version, vconn->version);
             }
@@ -551,45 +552,58 @@ vconn_recv_block(struct vconn *vconn, struct ofpbuf **msgp)
     return retval;
 }
 
-/* Sends 'request' to 'vconn' and blocks until it receives a reply with a
- * matching transaction ID.  Returns 0 if successful, in which case the reply
- * is stored in '*replyp' for the caller to examine and free.  Otherwise
- * returns a positive errno value, or EOF, and sets '*replyp' to null.
+/* Waits until a message with a transaction ID matching 'xid' is recived on
+ * 'vconn'.  Returns 0 if successful, in which case the reply 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' is always destroyed, regardless of the return value. */
 int
-vconn_transact(struct vconn *vconn, struct ofpbuf *request,
-               struct ofpbuf **replyp)
+vconn_recv_xid(struct vconn *vconn, uint32_t xid, struct ofpbuf **replyp)
 {
-    uint32_t send_xid = ((struct ofp_header *) request->data)->xid;
-    int error;
-
-    *replyp = NULL;
-    error = vconn_send_block(vconn, request);
-    if (error) {
-        ofpbuf_delete(request);
-        return error;
-    }
     for (;;) {
         uint32_t recv_xid;
         struct ofpbuf *reply;
+        int error;
 
         error = vconn_recv_block(vconn, &reply);
         if (error) {
+            *replyp = NULL;
             return error;
         }
         recv_xid = ((struct ofp_header *) reply->data)->xid;
-        if (send_xid == recv_xid) {
+        if (xid == recv_xid) {
             *replyp = reply;
             return 0;
         }
 
         VLOG_DBG_RL(&rl, "%s: received reply with xid %08"PRIx32" != expected "
-                    "%08"PRIx32, vconn->name, recv_xid, send_xid);
+                    "%08"PRIx32, vconn->name, recv_xid, xid);
         ofpbuf_delete(reply);
     }
 }
 
+/* Sends 'request' to 'vconn' and blocks until it receives a reply with a
+ * matching transaction ID.  Returns 0 if successful, in which case the reply
+ * 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' is always destroyed, regardless of the return value. */
+int
+vconn_transact(struct vconn *vconn, struct ofpbuf *request,
+               struct ofpbuf **replyp)
+{
+    uint32_t send_xid = ((struct ofp_header *) request->data)->xid;
+    int error;
+
+    *replyp = NULL;
+    error = vconn_send_block(vconn, request);
+    if (error) {
+        ofpbuf_delete(request);
+    }
+    return error ? error : vconn_recv_xid(vconn, send_xid, replyp);
+}
+
 void
 vconn_wait(struct vconn *vconn, enum vconn_wait_type wait)
 {
@@ -738,8 +752,7 @@ make_openflow_xid(size_t openflow_len, uint8_t type, uint32_t xid,
     assert(openflow_len >= sizeof *oh);
     assert(openflow_len <= UINT16_MAX);
     buffer = *bufferp = ofpbuf_new(openflow_len);
-    oh = ofpbuf_put_uninit(buffer, openflow_len);
-    memset(oh, 0, openflow_len);
+    oh = ofpbuf_put_zeros(buffer, openflow_len);
     oh->version = OFP_VERSION;
     oh->type = type;
     oh->length = htons(openflow_len);
@@ -758,13 +771,12 @@ update_openflow_length(struct ofpbuf *buffer)
 
 struct ofpbuf *
 make_add_flow(const struct flow *flow, uint32_t buffer_id,
-              uint16_t idle_timeout, size_t n_actions)
+              uint16_t idle_timeout, size_t actions_len)
 {
     struct ofp_flow_mod *ofm;
-    size_t size = sizeof *ofm + n_actions * sizeof ofm->actions[0];
+    size_t size = sizeof *ofm + actions_len;
     struct ofpbuf *out = ofpbuf_new(size);
-    ofm = ofpbuf_put_uninit(out, size);
-    memset(ofm, 0, size);
+    ofm = ofpbuf_put_zeros(out, size);
     ofm->header.version = OFP_VERSION;
     ofm->header.type = OFPT_FLOW_MOD;
     ofm->header.length = htons(size);
@@ -791,11 +803,14 @@ make_add_simple_flow(const struct flow *flow,
                      uint32_t buffer_id, uint16_t out_port,
                      uint16_t idle_timeout)
 {
-    struct ofpbuf *buffer = make_add_flow(flow, buffer_id, idle_timeout, 1);
+    struct ofp_action_output *oao;
+    struct ofpbuf *buffer = make_add_flow(flow, buffer_id, idle_timeout, 
+            sizeof *oao);
     struct ofp_flow_mod *ofm = buffer->data;
-    ofm->actions[0].type = htons(OFPAT_OUTPUT);
-    ofm->actions[0].arg.output.max_len = htons(0);
-    ofm->actions[0].arg.output.port = htons(out_port);
+    oao = (struct ofp_action_output *)&ofm->actions[0];
+    oao->type = htons(OFPAT_OUTPUT);
+    oao->len = htons(sizeof *oao);
+    oao->port = htons(out_port);
     return buffer;
 }
 
@@ -804,18 +819,23 @@ make_unbuffered_packet_out(const struct ofpbuf *packet,
                            uint16_t in_port, uint16_t out_port)
 {
     struct ofp_packet_out *opo;
-    size_t size = sizeof *opo + sizeof opo->actions[0];
+    struct ofp_action_output *oao;
+    size_t size = sizeof *opo + sizeof *oao;
     struct ofpbuf *out = ofpbuf_new(size + packet->size);
-    opo = ofpbuf_put_uninit(out, size);
-    memset(opo, 0, size);
+
+    opo = ofpbuf_put_zeros(out, size);
     opo->header.version = OFP_VERSION;
     opo->header.type = OFPT_PACKET_OUT;
     opo->buffer_id = htonl(UINT32_MAX);
     opo->in_port = htons(in_port);
-    opo->n_actions = htons(1);
-    opo->actions[0].type = htons(OFPAT_OUTPUT);
-    opo->actions[0].arg.output.max_len = htons(0);
-    opo->actions[0].arg.output.port = htons(out_port);
+
+    oao = (struct ofp_action_output *)&opo->actions[0];
+    oao->type = htons(OFPAT_OUTPUT);
+    oao->len = htons(sizeof *oao);
+    oao->port = htons(out_port);
+
+    opo->actions_len = htons(sizeof *oao);
+
     ofpbuf_put(out, packet->data, packet->size);
     update_openflow_length(out);
     return out;
@@ -826,19 +846,22 @@ make_buffered_packet_out(uint32_t buffer_id,
                          uint16_t in_port, uint16_t out_port)
 {
     struct ofp_packet_out *opo;
-    size_t size = sizeof *opo + sizeof opo->actions[0];
+    struct ofp_action_output *oao;
+    size_t size = sizeof *opo + sizeof *oao;
     struct ofpbuf *out = ofpbuf_new(size);
-    opo = ofpbuf_put_uninit(out, size);
-    memset(opo, 0, size);
+    opo = ofpbuf_put_zeros(out, size);
     opo->header.version = OFP_VERSION;
     opo->header.type = OFPT_PACKET_OUT;
     opo->header.length = htons(size);
     opo->buffer_id = htonl(buffer_id);
     opo->in_port = htons(in_port);
-    opo->n_actions = htons(1);
-    opo->actions[0].type = htons(OFPAT_OUTPUT);
-    opo->actions[0].arg.output.max_len = htons(0);
-    opo->actions[0].arg.output.port = htons(out_port);
+
+    oao = (struct ofp_action_output *)&opo->actions[0];
+    oao->type = htons(OFPAT_OUTPUT);
+    oao->len = htons(sizeof *oao);
+    oao->port = htons(out_port);
+
+    opo->actions_len = htons(sizeof *oao);
     return out;
 }