+/* Attempts to start listening for OpenFlow connections. 'name' is a
+ * connection name in the form "TYPE:ARGS", where TYPE is an passive vconn
+ * class's name and ARGS are vconn class-specific.
+ *
+ * Returns 0 if successful, otherwise a positive errno value. If successful,
+ * stores a pointer to the new connection in '*pvconnp', otherwise a null
+ * pointer. */
+int
+pvconn_open(const char *name, struct pvconn **pvconnp)
+{
+ size_t prefix_len;
+ size_t i;
+
+ check_vconn_classes();
+
+ *pvconnp = NULL;
+ prefix_len = strcspn(name, ":");
+ if (prefix_len == strlen(name)) {
+ return EAFNOSUPPORT;
+ }
+ for (i = 0; i < ARRAY_SIZE(pvconn_classes); i++) {
+ struct pvconn_class *class = pvconn_classes[i];
+ if (strlen(class->name) == prefix_len
+ && !memcmp(class->name, name, prefix_len)) {
+ char *suffix_copy = xstrdup(name + prefix_len + 1);
+ int retval = class->listen(name, suffix_copy, pvconnp);
+ free(suffix_copy);
+ if (retval) {
+ *pvconnp = NULL;
+ }
+ return retval;
+ }
+ }
+ return EAFNOSUPPORT;
+}
+
+/* Closes 'pvconn'. */
+void
+pvconn_close(struct pvconn *pvconn)
+{
+ if (pvconn != NULL) {
+ char *name = pvconn->name;
+ (pvconn->class->close)(pvconn);
+ free(name);
+ }
+}
+
+/* Tries to accept a new connection on 'pvconn'. If successful, stores the new
+ * connection in '*new_vconn' and returns 0. Otherwise, returns a positive
+ * errno value.
+ *
+ * The new vconn will automatically negotiate an OpenFlow protocol version
+ * acceptable to both peers on the connection. The version negotiated will be
+ * no lower than 'min_version' and no higher than OFP_VERSION.
+ *
+ * pvconn_accept() will not block waiting for a connection. If no connection
+ * is ready to be accepted, it returns EAGAIN immediately. */
+int
+pvconn_accept(struct pvconn *pvconn, int min_version, struct vconn **new_vconn)
+{
+ int retval = (pvconn->class->accept)(pvconn, new_vconn);
+ if (retval) {
+ *new_vconn = NULL;
+ } else {
+ assert((*new_vconn)->state != VCS_CONNECTING
+ || (*new_vconn)->class->connect);
+ (*new_vconn)->min_version = min_version;
+ }
+ return retval;
+}
+
+void
+pvconn_wait(struct pvconn *pvconn)
+{
+ (pvconn->class->wait)(pvconn);
+}
+
+/* Allocates and returns the first byte of a buffer 'openflow_len' bytes long,
+ * containing an OpenFlow header with the given 'type' and a random transaction
+ * id. Stores the new buffer in '*bufferp'. The caller must free the buffer
+ * when it is no longer needed. */
+void *
+make_openflow(size_t openflow_len, uint8_t type, struct ofpbuf **bufferp)
+{
+ return make_openflow_xid(openflow_len, type, random_uint32(), bufferp);
+}
+
+/* Allocates and returns the first byte of a buffer 'openflow_len' bytes long,
+ * containing an OpenFlow header with the given 'type' and transaction id
+ * 'xid'. Stores the new buffer in '*bufferp'. The caller must free the
+ * buffer when it is no longer needed. */
+void *
+make_openflow_xid(size_t openflow_len, uint8_t type, uint32_t xid,
+ struct ofpbuf **bufferp)
+{
+ struct ofpbuf *buffer;
+ struct ofp_header *oh;
+
+ 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->version = OFP_VERSION;
+ oh->type = type;
+ oh->length = htons(openflow_len);
+ oh->xid = xid;
+ return oh;
+}
+
+/* Updates the 'length' field of the OpenFlow message in 'buffer' to
+ * 'buffer->size'. */
+void
+update_openflow_length(struct ofpbuf *buffer)
+{
+ struct ofp_header *oh = ofpbuf_at_assert(buffer, 0, sizeof *oh);
+ oh->length = htons(buffer->size);
+}
+
+struct ofpbuf *
+make_add_flow(const struct flow *flow, uint32_t buffer_id,
+ uint16_t idle_timeout, size_t n_actions)