From: Ben Pfaff Date: Thu, 11 Sep 2008 22:12:46 +0000 (-0700) Subject: Break passive vconns out into separate pvconn routines and data structures. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=553dfa572d77bff616b1ea88d90eef266d202954;p=openvswitch Break passive vconns out into separate pvconn routines and data structures. There really was nothing in common between the active and passive vconns. This arrangement makes more sense. --- diff --git a/controller/controller.c b/controller/controller.c index 2d79afaa..48420c86 100644 --- a/controller/controller.c +++ b/controller/controller.c @@ -84,7 +84,7 @@ int main(int argc, char *argv[]) { struct switch_ switches[MAX_SWITCHES]; - struct vconn *listeners[MAX_LISTENERS]; + struct pvconn *listeners[MAX_LISTENERS]; int n_switches, n_listeners; int retval; int i; @@ -112,22 +112,23 @@ main(int argc, char *argv[]) int retval; retval = vconn_open(name, &vconn); - if (retval) { - VLOG_ERR("%s: connect: %s", name, strerror(retval)); - continue; - } - - if (vconn_is_passive(vconn)) { - if (n_listeners >= MAX_LISTENERS) { - fatal(0, "max %d passive connections", n_listeners); - } - listeners[n_listeners++] = vconn; - } else { + if (!retval) { if (n_switches >= MAX_SWITCHES) { fatal(0, "max %d switch connections", n_switches); } new_switch(&switches[n_switches++], vconn, name); + continue; + } else if (retval == EAFNOSUPPORT) { + struct pvconn *pvconn; + retval = pvconn_open(name, &pvconn); + if (!retval) { + if (n_listeners >= MAX_LISTENERS) { + fatal(0, "max %d passive connections", n_listeners); + } + listeners[n_listeners++] = pvconn; + } } + VLOG_ERR("%s: connect: %s", name, strerror(retval)); } if (n_switches == 0 && n_listeners == 0) { fatal(0, "no active or passive switch connections"); @@ -145,14 +146,14 @@ main(int argc, char *argv[]) struct vconn *new_vconn; int retval; - retval = vconn_accept(listeners[i], &new_vconn); + retval = pvconn_accept(listeners[i], &new_vconn); if (!retval || retval == EAGAIN) { if (!retval) { new_switch(&switches[n_switches++], new_vconn, "tcp"); } i++; } else { - vconn_close(listeners[i]); + pvconn_close(listeners[i]); listeners[i] = listeners[--n_listeners]; } } @@ -183,7 +184,7 @@ main(int argc, char *argv[]) /* Wait for something to happen. */ if (n_switches < MAX_SWITCHES) { for (i = 0; i < n_listeners; i++) { - vconn_accept_wait(listeners[i]); + pvconn_wait(listeners[i]); } } for (i = 0; i < n_switches; i++) { diff --git a/include/vconn-provider.h b/include/vconn-provider.h index 8bb8368a..f7c47e89 100644 --- a/include/vconn-provider.h +++ b/include/vconn-provider.h @@ -34,13 +34,13 @@ #ifndef VCONN_PROVIDER_H #define VCONN_PROVIDER_H 1 -/* Provider interface, which provide a virtual connection to an OpenFlow - * device. */ +/* Provider interface to vconns, which provide a virtual connection to an + * OpenFlow device. */ #include #include "vconn.h" - -/* Virtual connection to an OpenFlow device. + +/* Active virtual connection to an OpenFlow device. * * This structure should be treated as opaque by vconn implementations. */ struct vconn { @@ -80,58 +80,105 @@ struct vconn_class { /* Closes 'vconn' and frees associated memory. */ void (*close)(struct vconn *vconn); - /* Tries to complete the connection on 'vconn', which must be an active - * vconn. If 'vconn''s connection is complete, returns 0 if the connection - * was successful or a positive errno value if it failed. If the - * connection is still in progress, returns EAGAIN. + /* Tries to complete the connection on 'vconn'. If 'vconn''s connection is + * complete, returns 0 if the connection was successful or a positive errno + * value if it failed. If the connection is still in progress, returns + * EAGAIN. * * The connect function must not block waiting for the connection to * complete; instead, it should return EAGAIN immediately. */ int (*connect)(struct vconn *vconn); - /* Tries to accept a new connection on 'vconn', which must be a passive - * vconn. If successful, stores the new connection in '*new_vconnp' and - * returns 0. Otherwise, returns a positive errno value. - * - * The accept function must not block waiting for a connection. If no - * connection is ready to be accepted, it should return EAGAIN. - * - * Nonnull iff this is a passive vconn (one that accepts connections and - * does not transfer data). */ - int (*accept)(struct vconn *vconn, struct vconn **new_vconnp); - - /* Tries to receive an OpenFlow message from 'vconn', which must be an - * active vconn. If successful, stores the received message into '*msgp' - * and returns 0. The caller is responsible for destroying the message - * with buffer_delete(). On failure, returns a positive errno value and - * stores a null pointer into '*msgp'. + /* Tries to receive an OpenFlow message from 'vconn'. If successful, + * stores the received message into '*msgp' and returns 0. The caller is + * responsible for destroying the message with buffer_delete(). On + * failure, returns a positive errno value and stores a null pointer into + * '*msgp'. * * If the connection has been closed in the normal fashion, returns EOF. * * The recv function must not block waiting for a packet to arrive. If no - * packets have been received, it should return EAGAIN. - * - * Nonnull iff this is an active vconn (one that transfers data and does - * not accept connections). */ + * packets have been received, it should return EAGAIN. */ int (*recv)(struct vconn *vconn, struct buffer **msgp); - /* Tries to queue 'msg' for transmission on 'vconn', which must be an - * active vconn. If successful, returns 0, in which case ownership of - * 'msg' is transferred to the vconn. Success does not guarantee that - * 'msg' has been or ever will be delivered to the peer, only that it has - * been queued for transmission. + /* Tries to queue 'msg' for transmission on 'vconn'. If successful, + * returns 0, in which case ownership of 'msg' is transferred to the vconn. + * Success does not guarantee that 'msg' has been or ever will be delivered + * to the peer, only that it has been queued for transmission. * * Returns a positive errno value on failure, in which case the caller * retains ownership of 'msg'. * * The send function must not block. If 'msg' cannot be immediately - * accepted for transmission, it should return EAGAIN. - * - * Nonnull iff this is an active vconn (one that transfers data and does - * not accept connections). */ + * accepted for transmission, it should return EAGAIN. */ int (*send)(struct vconn *vconn, struct buffer *msg); - void (*wait)(struct vconn *vconn, enum vconn_wait_type); + /* Arranges for the poll loop to wake up when 'vconn' is ready to take an + * action of the given 'type'. */ + void (*wait)(struct vconn *vconn, enum vconn_wait_type type); +}; + +/* Passive virtual connection to an OpenFlow device. + * + * This structure should be treated as opaque by vconn implementations. */ +struct pvconn { + struct pvconn_class *class; + char *name; +}; + +void pvconn_init(struct pvconn *, struct pvconn_class *, const char *name); +static inline void pvconn_assert_class(const struct pvconn *pvconn, + const struct pvconn_class *class) +{ + assert(pvconn->class == class); +} + +struct pvconn_class { + /* Prefix for connection names, e.g. "ptcp", "pssl". */ + const char *name; + + /* Attempts to start listening for OpenFlow connections. 'name' is the + * full connection name provided by the user, e.g. "nl:0", "tcp:1.2.3.4". + * This name is useful for error messages but must not be modified. + * + * 'suffix' is a copy of 'name' following the colon and may be modified. + * + * Returns 0 if successful, otherwise a positive errno value. If + * successful, stores a pointer to the new connection in '*pvconnp'. + * + * The listen function must not block. If the connection cannot be + * completed immediately, it should return EAGAIN (not EINPROGRESS, as + * returned by the connect system call) and continue the connection in the + * background. */ + int (*listen)(const char *name, char *suffix, struct pvconn **pvconnp); + + /* Closes 'pvconn' and frees associated memory. */ + void (*close)(struct pvconn *pvconn); + + /* Tries to accept a new connection on 'pvconn'. If successful, stores the + * new connection in '*new_vconnp' and returns 0. Otherwise, returns a + * positive errno value. + * + * The accept function must not block waiting for a connection. If no + * connection is ready to be accepted, it should return EAGAIN. */ + int (*accept)(struct pvconn *pvconn, struct vconn **new_vconnp); + + /* Arranges for the poll loop to wake up when a connection is ready to be + * accepted on 'pvconn'. */ + void (*wait)(struct pvconn *pvconn); }; +/* Active and passive vconn classes. */ +extern struct vconn_class tcp_vconn_class; +extern struct pvconn_class ptcp_pvconn_class; +extern struct vconn_class unix_vconn_class; +extern struct pvconn_class punix_pvconn_class; +#ifdef HAVE_OPENSSL +extern struct vconn_class ssl_vconn_class; +extern struct pvconn_class pssl_pvconn_class; +#endif +#ifdef HAVE_NETLINK +extern struct vconn_class netlink_vconn_class; +#endif + #endif /* vconn-provider.h */ diff --git a/include/vconn-stream.h b/include/vconn-stream.h index d7eb59f8..a9b1e7b3 100644 --- a/include/vconn-stream.h +++ b/include/vconn-stream.h @@ -38,13 +38,14 @@ #include struct vconn; +struct pvconn; struct sockaddr; int new_stream_vconn(const char *name, int fd, int connect_status, uint32_t ip, struct vconn **vconnp); -int new_pstream_vconn(const char *name, int fd, +int new_pstream_pvconn(const char *name, int fd, int (*accept_cb)(int fd, const struct sockaddr *, size_t sa_len, struct vconn **), - struct vconn **vconnp); + struct pvconn **pvconnp); #endif /* vconn-stream.h */ diff --git a/include/vconn.h b/include/vconn.h index 6dcfd675..e13e21a4 100644 --- a/include/vconn.h +++ b/include/vconn.h @@ -40,21 +40,18 @@ struct buffer; struct flow; -struct pollfd; struct ofp_header; +struct pvconn; struct vconn; -/* Client interface to vconns, which provide a virtual connection to an - * OpenFlow device. */ - void vconn_usage(bool active, bool passive); + +/* Active vconns: virtual connections to OpenFlow devices. */ int vconn_open(const char *name, struct vconn **); void vconn_close(struct vconn *); const char *vconn_get_name(const struct vconn *); -bool vconn_is_passive(const struct vconn *); uint32_t vconn_get_ip(const struct vconn *); int vconn_connect(struct vconn *); -int vconn_accept(struct vconn *, struct vconn **); int vconn_recv(struct vconn *, struct buffer **); int vconn_send(struct vconn *, struct buffer *); int vconn_transact(struct vconn *, struct buffer *, struct buffer **); @@ -65,16 +62,21 @@ int vconn_recv_block(struct vconn *, struct buffer **); enum vconn_wait_type { WAIT_CONNECT, - WAIT_ACCEPT, WAIT_RECV, WAIT_SEND }; void vconn_wait(struct vconn *, enum vconn_wait_type); void vconn_connect_wait(struct vconn *); -void vconn_accept_wait(struct vconn *); void vconn_recv_wait(struct vconn *); void vconn_send_wait(struct vconn *); +/* Passive vconns: virtual listeners for incoming OpenFlow connections. */ +int pvconn_open(const char *name, struct pvconn **); +void pvconn_close(struct pvconn *); +int pvconn_accept(struct pvconn *, struct vconn **); +void pvconn_wait(struct pvconn *); + +/* OpenFlow protocol utility functions. */ void *make_openflow(size_t openflow_len, uint8_t type, struct buffer **); void *make_openflow_xid(size_t openflow_len, uint8_t type, uint32_t xid, struct buffer **); @@ -91,16 +93,4 @@ struct buffer *make_unbuffered_packet_out(const struct buffer *packet, struct buffer *make_echo_request(void); struct buffer *make_echo_reply(const struct ofp_header *rq); -extern struct vconn_class tcp_vconn_class; -extern struct vconn_class ptcp_vconn_class; -extern struct vconn_class unix_vconn_class; -extern struct vconn_class punix_vconn_class; -#ifdef HAVE_OPENSSL -extern struct vconn_class ssl_vconn_class; -extern struct vconn_class pssl_vconn_class; -#endif -#ifdef HAVE_NETLINK -extern struct vconn_class netlink_vconn_class; -#endif - #endif /* vconn.h */ diff --git a/lib/rconn.c b/lib/rconn.c index 991e386e..f0ee2bf6 100644 --- a/lib/rconn.c +++ b/lib/rconn.c @@ -311,13 +311,8 @@ run_CONNECTING(struct rconn *rc) if (!retval) { VLOG_WARN("%s: connected", rc->name); rc->n_successful_connections++; - if (vconn_is_passive(rc->vconn)) { - error(0, "%s: passive vconn not supported", rc->name); - state_transition(rc, S_VOID); - } else { - state_transition(rc, S_ACTIVE); - rc->last_connected = rc->state_entered; - } + state_transition(rc, S_ACTIVE); + rc->last_connected = rc->state_entered; } else if (retval != EAGAIN) { VLOG_WARN("%s: connection failed (%s)", rc->name, strerror(retval)); disconnect(rc, retval); diff --git a/lib/vconn-ssl.c b/lib/vconn-ssl.c index d899e091..bac39b5e 100644 --- a/lib/vconn-ssl.c +++ b/lib/vconn-ssl.c @@ -663,24 +663,26 @@ struct vconn_class ssl_vconn_class = { /* Passive SSL. */ -struct pssl_vconn +struct pssl_pvconn { - struct vconn vconn; + struct pvconn pvconn; int fd; }; -static struct pssl_vconn * -pssl_vconn_cast(struct vconn *vconn) +struct pvconn_class pssl_pvconn_class; + +static struct pssl_pvconn * +pssl_pvconn_cast(struct pvconn *pvconn) { - vconn_assert_class(vconn, &pssl_vconn_class); - return CONTAINER_OF(vconn, struct pssl_vconn, vconn); + pvconn_assert_class(pvconn, &pssl_pvconn_class); + return CONTAINER_OF(pvconn, struct pssl_pvconn, pvconn); } static int -pssl_open(const char *name, char *suffix, struct vconn **vconnp) +pssl_open(const char *name, char *suffix, struct pvconn **pvconnp) { struct sockaddr_in sin; - struct pssl_vconn *pssl; + struct pssl_pvconn *pssl; int retval; int fd; unsigned int yes = 1; @@ -731,24 +733,24 @@ pssl_open(const char *name, char *suffix, struct vconn **vconnp) } pssl = xmalloc(sizeof *pssl); - vconn_init(&pssl->vconn, &pssl_vconn_class, 0, 0, name); + pvconn_init(&pssl->pvconn, &pssl_pvconn_class, name); pssl->fd = fd; - *vconnp = &pssl->vconn; + *pvconnp = &pssl->pvconn; return 0; } static void -pssl_close(struct vconn *vconn) +pssl_close(struct pvconn *pvconn) { - struct pssl_vconn *pssl = pssl_vconn_cast(vconn); + struct pssl_pvconn *pssl = pssl_pvconn_cast(pvconn); close(pssl->fd); free(pssl); } static int -pssl_accept(struct vconn *vconn, struct vconn **new_vconnp) +pssl_accept(struct pvconn *pvconn, struct vconn **new_vconnp) { - struct pssl_vconn *pssl = pssl_vconn_cast(vconn); + struct pssl_pvconn *pssl = pssl_pvconn_cast(pvconn); struct sockaddr_in sin; socklen_t sin_len = sizeof sin; char name[128]; @@ -779,19 +781,18 @@ pssl_accept(struct vconn *vconn, struct vconn **new_vconnp) } static void -pssl_wait(struct vconn *vconn, enum vconn_wait_type wait) +pssl_wait(struct pvconn *pvconn) { - struct pssl_vconn *pssl = pssl_vconn_cast(vconn); - assert(wait == WAIT_ACCEPT); + struct pssl_pvconn *pssl = pssl_pvconn_cast(pvconn); poll_fd_wait(pssl->fd, POLLIN); } -struct vconn_class pssl_vconn_class = { - .name = "pssl", - .open = pssl_open, - .close = pssl_close, - .accept = pssl_accept, - .wait = pssl_wait, +struct pvconn_class pssl_pvconn_class = { + "pssl", + pssl_open, + pssl_close, + pssl_accept, + pssl_wait, }; /* diff --git a/lib/vconn-stream.c b/lib/vconn-stream.c index f58cc2c0..5cf296fc 100644 --- a/lib/vconn-stream.c +++ b/lib/vconn-stream.c @@ -256,30 +256,30 @@ static struct vconn_class stream_vconn_class = { /* Passive stream socket vconn. */ -struct pstream_vconn +struct pstream_pvconn { - struct vconn vconn; + struct pvconn pvconn; int fd; int (*accept_cb)(int fd, const struct sockaddr *, size_t sa_len, struct vconn **); }; -static struct vconn_class pstream_vconn_class; +static struct pvconn_class pstream_pvconn_class; -static struct pstream_vconn * -pstream_vconn_cast(struct vconn *vconn) +static struct pstream_pvconn * +pstream_pvconn_cast(struct pvconn *pvconn) { - vconn_assert_class(vconn, &pstream_vconn_class); - return CONTAINER_OF(vconn, struct pstream_vconn, vconn); + pvconn_assert_class(pvconn, &pstream_pvconn_class); + return CONTAINER_OF(pvconn, struct pstream_pvconn, pvconn); } int -new_pstream_vconn(const char *name, int fd, +new_pstream_pvconn(const char *name, int fd, int (*accept_cb)(int fd, const struct sockaddr *, size_t sa_len, struct vconn **), - struct vconn **vconnp) + struct pvconn **pvconnp) { - struct pstream_vconn *ps; + struct pstream_pvconn *ps; int retval; retval = set_nonblocking(fd); @@ -296,25 +296,25 @@ new_pstream_vconn(const char *name, int fd, } ps = xmalloc(sizeof *ps); - vconn_init(&ps->vconn, &pstream_vconn_class, 0, 0, name); + pvconn_init(&ps->pvconn, &pstream_pvconn_class, name); ps->fd = fd; ps->accept_cb = accept_cb; - *vconnp = &ps->vconn; + *pvconnp = &ps->pvconn; return 0; } static void -pstream_close(struct vconn *vconn) +pstream_close(struct pvconn *pvconn) { - struct pstream_vconn *ps = pstream_vconn_cast(vconn); + struct pstream_pvconn *ps = pstream_pvconn_cast(pvconn); close(ps->fd); free(ps); } static int -pstream_accept(struct vconn *vconn, struct vconn **new_vconnp) +pstream_accept(struct pvconn *pvconn, struct vconn **new_vconnp) { - struct pstream_vconn *ps = pstream_vconn_cast(vconn); + struct pstream_pvconn *ps = pstream_pvconn_cast(pvconn); struct sockaddr_storage ss; socklen_t ss_len = sizeof ss; int new_fd; @@ -340,16 +340,16 @@ pstream_accept(struct vconn *vconn, struct vconn **new_vconnp) } static void -pstream_wait(struct vconn *vconn, enum vconn_wait_type wait) +pstream_wait(struct pvconn *pvconn) { - struct pstream_vconn *ps = pstream_vconn_cast(vconn); - assert(wait == WAIT_ACCEPT); + struct pstream_pvconn *ps = pstream_pvconn_cast(pvconn); poll_fd_wait(ps->fd, POLLIN); } -static struct vconn_class pstream_vconn_class = { - .name = "pstream", - .close = pstream_close, - .accept = pstream_accept, - .wait = pstream_wait +static struct pvconn_class pstream_pvconn_class = { + "pstream", + NULL, + pstream_close, + pstream_accept, + pstream_wait }; diff --git a/lib/vconn-tcp.c b/lib/vconn-tcp.c index 7c314cc0..bf1851aa 100644 --- a/lib/vconn-tcp.c +++ b/lib/vconn-tcp.c @@ -137,7 +137,7 @@ static int ptcp_accept(int fd, const struct sockaddr *sa, size_t sa_len, struct vconn **vconnp); static int -ptcp_open(const char *name, char *suffix, struct vconn **vconnp) +ptcp_open(const char *name, char *suffix, struct pvconn **pvconnp) { struct sockaddr_in sin; int retval; @@ -167,7 +167,7 @@ ptcp_open(const char *name, char *suffix, struct vconn **vconnp) return error; } - return new_pstream_vconn("ptcp", fd, ptcp_accept, vconnp); + return new_pstream_pvconn("ptcp", fd, ptcp_accept, pvconnp); } static int @@ -188,8 +188,8 @@ ptcp_accept(int fd, const struct sockaddr *sa, size_t sa_len, return new_tcp_vconn(name, fd, 0, sin, vconnp); } -struct vconn_class ptcp_vconn_class = { - .name = "ptcp", - .open = ptcp_open, +struct pvconn_class ptcp_pvconn_class = { + "ptcp", + ptcp_open, }; diff --git a/lib/vconn-unix.c b/lib/vconn-unix.c index 356109da..cff7d2e6 100644 --- a/lib/vconn-unix.c +++ b/lib/vconn-unix.c @@ -92,7 +92,7 @@ static int punix_accept(int fd, const struct sockaddr *sa, size_t sa_len, struct vconn **vconnp); static int -punix_open(const char *name, char *suffix, struct vconn **vconnp) +punix_open(const char *name, char *suffix, struct pvconn **pvconnp) { int fd; @@ -102,7 +102,7 @@ punix_open(const char *name, char *suffix, struct vconn **vconnp) return errno; } - return new_pstream_vconn("punix", fd, punix_accept, vconnp); + return new_pstream_pvconn("punix", fd, punix_accept, pvconnp); } static int @@ -122,8 +122,8 @@ punix_accept(int fd, const struct sockaddr *sa, size_t sa_len, return new_stream_vconn(name, fd, 0, 0, vconnp); } -struct vconn_class punix_vconn_class = { - .name = "punix", - .open = punix_open, +struct pvconn_class punix_pvconn_class = { + "punix", + punix_open, }; diff --git a/lib/vconn.c b/lib/vconn.c index 723146ad..eba46c82 100644 --- a/lib/vconn.c +++ b/lib/vconn.c @@ -53,16 +53,21 @@ static struct vconn_class *vconn_classes[] = { &tcp_vconn_class, - &ptcp_vconn_class, + &unix_vconn_class, #ifdef HAVE_NETLINK &netlink_vconn_class, #endif #ifdef HAVE_OPENSSL &ssl_vconn_class, - &pssl_vconn_class, #endif - &unix_vconn_class, - &punix_vconn_class, +}; + +static struct pvconn_class *pvconn_classes[] = { + &ptcp_pvconn_class, + &punix_pvconn_class, +#ifdef HAVE_OPENSSL + &pssl_pvconn_class, +#endif }; /* High rate limit because most of the rate-limiting here is individual @@ -81,12 +86,23 @@ check_vconn_classes(void) struct vconn_class *class = vconn_classes[i]; assert(class->name != NULL); assert(class->open != NULL); - if (class->close || class->accept || class->recv || class->send - || class->wait) { + if (class->close || class->recv || class->send || class->wait) { assert(class->close != NULL); - assert(class->accept - ? !class->recv && !class->send - : class->recv && class->send); + assert(class->recv != NULL); + assert(class->send != NULL); + assert(class->wait != NULL); + } else { + /* This class delegates to another one. */ + } + } + + for (i = 0; i < ARRAY_SIZE(pvconn_classes); i++) { + struct pvconn_class *class = pvconn_classes[i]; + assert(class->name != NULL); + assert(class->listen != NULL); + if (class->close || class->accept || class->wait) { + assert(class->close != NULL); + assert(class->accept != NULL); assert(class->wait != NULL); } else { /* This class delegates to another one. */ @@ -143,8 +159,8 @@ vconn_usage(bool active, bool passive) } /* Attempts to connect to an OpenFlow device. 'name' is a connection name in - * the form "TYPE:ARGS", where TYPE is the vconn class's name and ARGS are - * vconn class-specific. + * the form "TYPE:ARGS", where TYPE is an active 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 '*vconnp', otherwise a null @@ -160,7 +176,6 @@ vconn_open(const char *name, struct vconn **vconnp) *vconnp = NULL; prefix_len = strcspn(name, ":"); if (prefix_len == strlen(name)) { - error(0, "`%s' not correct format for peer name", name); return EAFNOSUPPORT; } for (i = 0; i < ARRAY_SIZE(vconn_classes); i++) { @@ -174,13 +189,11 @@ vconn_open(const char *name, struct vconn **vconnp) if (!retval) { assert(vconn->connect_status != EAGAIN || vconn->class->connect); - vconn->name = xstrdup(name); *vconnp = vconn; } return retval; } } - error(0, "unknown peer type `%.*s'", (int) prefix_len, name); return EAFNOSUPPORT; } @@ -224,16 +237,6 @@ vconn_get_name(const struct vconn *vconn) return vconn->name; } -/* Returns true if 'vconn' is a passive vconn, that is, its purpose is to - * wait for connections to arrive, not to transfer data. Returns false if - * 'vconn' is an active vconn, that is, its purpose is to transfer data, not - * to wait for new connections to arrive. */ -bool -vconn_is_passive(const struct vconn *vconn) -{ - return vconn->class->accept != NULL; -} - /* Returns the IP address of the peer, or 0 if the peer is not connected over * an IP-based protocol or if its IP address is not yet known. */ uint32_t @@ -256,28 +259,6 @@ vconn_connect(struct vconn *vconn) return vconn->connect_status; } -/* Tries to accept a new connection on 'vconn', which must be a passive vconn. - * If successful, stores the new connection in '*new_vconn' and returns 0. - * Otherwise, returns a positive errno value. - * - * vconn_accept will not block waiting for a connection. If no connection is - * ready to be accepted, it returns EAGAIN immediately. */ -int -vconn_accept(struct vconn *vconn, struct vconn **new_vconn) -{ - int retval; - - retval = (vconn->class->accept)(vconn, new_vconn); - - if (retval) { - *new_vconn = NULL; - } else { - assert((*new_vconn)->connect_status != EAGAIN - || (*new_vconn)->class->connect); - } - return retval; -} - /* Tries to receive an OpenFlow message from 'vconn', which must be an active * vconn. If successful, stores the received message into '*msgp' and returns * 0. The caller is responsible for destroying the message with @@ -418,9 +399,7 @@ vconn_wait(struct vconn *vconn, enum vconn_wait_type wait) { int connect_status; - assert(vconn_is_passive(vconn) - ? wait == WAIT_ACCEPT || wait == WAIT_CONNECT - : wait == WAIT_CONNECT || wait == WAIT_RECV || wait == WAIT_SEND); + assert(wait == WAIT_CONNECT || wait == WAIT_RECV || wait == WAIT_SEND); connect_status = vconn_connect(vconn); if (connect_status) { @@ -441,12 +420,6 @@ vconn_connect_wait(struct vconn *vconn) vconn_wait(vconn, WAIT_CONNECT); } -void -vconn_accept_wait(struct vconn *vconn) -{ - vconn_wait(vconn, WAIT_ACCEPT); -} - void vconn_recv_wait(struct vconn *vconn) { @@ -459,6 +432,78 @@ vconn_send_wait(struct vconn *vconn) vconn_wait(vconn, WAIT_SEND); } +/* 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. + * + * 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, struct vconn **new_vconn) +{ + int retval = (pvconn->class->accept)(pvconn, new_vconn); + if (retval) { + *new_vconn = NULL; + } else { + assert((*new_vconn)->connect_status == 0 + || (*new_vconn)->class->connect); + } + 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 @@ -623,3 +668,10 @@ vconn_init(struct vconn *vconn, struct vconn_class *class, int connect_status, vconn->name = xstrdup(name); } +void +pvconn_init(struct pvconn *pvconn, struct pvconn_class *class, + const char *name) +{ + pvconn->class = class; + pvconn->name = xstrdup(name); +} diff --git a/secchan/secchan.c b/secchan/secchan.c index cd6b567d..e69a314c 100644 --- a/secchan/secchan.c +++ b/secchan/secchan.c @@ -140,12 +140,12 @@ static struct vlog_rate_limit vrl = VLOG_RATE_LIMIT_INIT(60, 60); static void parse_options(int argc, char *argv[], struct settings *); static void usage(void) NO_RETURN; -static struct vconn *open_passive_vconn(const char *name); -static struct vconn *accept_vconn(struct vconn *vconn); +static struct pvconn *open_passive_vconn(const char *name); +static struct vconn *accept_vconn(struct pvconn *pvconn); static struct relay *relay_create(struct rconn *local, struct rconn *remote, bool is_mgmt_conn); -static struct relay *relay_accept(const struct settings *, struct vconn *); +static struct relay *relay_accept(const struct settings *, struct pvconn *); static void relay_run(struct relay *, const struct hook[], size_t n_hooks); static void relay_wait(struct relay *); static void relay_destroy(struct relay *); @@ -220,9 +220,9 @@ main(int argc, char *argv[]) struct hook hooks[8]; size_t n_hooks = 0; - struct vconn *monitor; + struct pvconn *monitor; - struct vconn *listeners[MAX_MGMT]; + struct pvconn *listeners[MAX_MGMT]; size_t n_listeners; struct rconn *local_rconn, *remote_rconn; @@ -350,10 +350,10 @@ main(int argc, char *argv[]) relay_wait(r); } for (i = 0; i < n_listeners; i++) { - vconn_accept_wait(listeners[i]); + pvconn_wait(listeners[i]); } if (monitor) { - vconn_accept_wait(monitor); + pvconn_wait(monitor); } for (i = 0; i < n_hooks; i++) { if (hooks[i].wait_cb) { @@ -369,29 +369,26 @@ main(int argc, char *argv[]) return 0; } -static struct vconn * -open_passive_vconn(const char *name) +static struct pvconn * +open_passive_vconn(const char *name) { - struct vconn *vconn; + struct pvconn *pvconn; int retval; - retval = vconn_open(name, &vconn); + retval = pvconn_open(name, &pvconn); if (retval && retval != EAGAIN) { fatal(retval, "opening %s", name); } - if (!vconn_is_passive(vconn)) { - fatal(0, "%s is not a passive vconn", name); - } - return vconn; + return pvconn; } static struct vconn * -accept_vconn(struct vconn *vconn) +accept_vconn(struct pvconn *pvconn) { struct vconn *new; int retval; - retval = vconn_accept(vconn, &new); + retval = pvconn_accept(pvconn, &new); if (retval && retval != EAGAIN) { VLOG_WARN_RL(&vrl, "accept failed (%s)", strerror(retval)); } @@ -448,14 +445,14 @@ get_ofp_packet_eth_header(struct relay *r, struct ofp_packet_in **opip, /* OpenFlow message relaying. */ static struct relay * -relay_accept(const struct settings *s, struct vconn *listen_vconn) +relay_accept(const struct settings *s, struct pvconn *pvconn) { struct vconn *new_remote, *new_local; char *nl_name_without_subscription; struct rconn *r1, *r2; int retval; - new_remote = accept_vconn(listen_vconn); + new_remote = accept_vconn(pvconn); if (!new_remote) { return NULL; } diff --git a/switch/datapath.c b/switch/datapath.c index c709fb79..24744aa8 100644 --- a/switch/datapath.c +++ b/switch/datapath.c @@ -117,7 +117,7 @@ struct datapath { /* Remote connections. */ struct remote *controller; /* Connection to controller. */ struct list remotes; /* All connections (including controller). */ - struct vconn *listen_vconn; + struct pvconn *listen_pvconn; time_t last_timeout; @@ -212,7 +212,7 @@ dp_new(struct datapath **dp_, uint64_t dpid, struct rconn *rconn) dp->last_timeout = time_now(); list_init(&dp->remotes); dp->controller = remote_create(dp, rconn); - dp->listen_vconn = NULL; + dp->listen_pvconn = NULL; dp->id = dpid <= UINT64_C(0xffffffffffff) ? dpid : gen_datapath_id(); dp->chain = chain_create(); if (!dp->chain) { @@ -277,10 +277,10 @@ dp_add_port(struct datapath *dp, const char *name) } void -dp_add_listen_vconn(struct datapath *dp, struct vconn *listen_vconn) +dp_add_listen_pvconn(struct datapath *dp, struct pvconn *listen_pvconn) { - assert(!dp->listen_vconn); - dp->listen_vconn = listen_vconn; + assert(!dp->listen_pvconn); + dp->listen_pvconn = listen_pvconn; } void @@ -341,12 +341,12 @@ dp_run(struct datapath *dp) LIST_FOR_EACH_SAFE (r, rn, struct remote, node, &dp->remotes) { remote_run(dp, r); } - if (dp->listen_vconn) { + if (dp->listen_pvconn) { for (;;) { struct vconn *new_vconn; int retval; - retval = vconn_accept(dp->listen_vconn, &new_vconn); + retval = pvconn_accept(dp->listen_pvconn, &new_vconn); if (retval) { if (retval != EAGAIN) { VLOG_WARN_RL(&rl, "accept failed (%s)", strerror(retval)); @@ -479,8 +479,8 @@ dp_wait(struct datapath *dp) LIST_FOR_EACH (r, struct remote, node, &dp->remotes) { remote_wait(r); } - if (dp->listen_vconn) { - vconn_accept_wait(dp->listen_vconn); + if (dp->listen_pvconn) { + pvconn_wait(dp->listen_pvconn); } } diff --git a/switch/datapath.h b/switch/datapath.h index 6914782f..b2c0f507 100644 --- a/switch/datapath.h +++ b/switch/datapath.h @@ -44,11 +44,11 @@ struct datapath; struct rconn; -struct vconn; +struct pvconn; int dp_new(struct datapath **, uint64_t dpid, struct rconn *); int dp_add_port(struct datapath *, const char *netdev); -void dp_add_listen_vconn(struct datapath *, struct vconn *); +void dp_add_listen_pvconn(struct datapath *, struct pvconn *); void dp_run(struct datapath *); void dp_wait(struct datapath *); diff --git a/switch/switch.c b/switch/switch.c index 9d307db9..1f85b37b 100644 --- a/switch/switch.c +++ b/switch/switch.c @@ -68,7 +68,7 @@ char serial_num[SERIAL_NUM_LEN] = "None"; static void parse_options(int argc, char *argv[]); static void usage(void) NO_RETURN; -static const char *listen_vconn_name; +static const char *listen_pvconn_name; static struct datapath *dp; static uint64_t dpid = UINT64_MAX; static char *port_list; @@ -102,18 +102,15 @@ main(int argc, char *argv[]) fatal(0, "no support for %s vconn", argv[optind]); } error = dp_new(&dp, dpid, rconn); - if (listen_vconn_name) { - struct vconn *listen_vconn; + if (listen_pvconn_name) { + struct pvconn *listen_pvconn; int retval; - - retval = vconn_open(listen_vconn_name, &listen_vconn); + + retval = pvconn_open(listen_pvconn_name, &listen_pvconn); if (retval && retval != EAGAIN) { - fatal(retval, "opening %s", listen_vconn_name); - } - if (!vconn_is_passive(listen_vconn)) { - fatal(0, "%s is not a passive vconn", listen_vconn_name); + fatal(retval, "opening %s", listen_pvconn_name); } - dp_add_listen_vconn(dp, listen_vconn); + dp_add_listen_pvconn(dp, listen_pvconn); } if (error) { fatal(error, "could not create datapath"); @@ -267,10 +264,10 @@ parse_options(int argc, char *argv[]) break; case 'l': - if (listen_vconn_name) { + if (listen_pvconn_name) { fatal(0, "-l or --listen may be only specified once"); } - listen_vconn_name = optarg; + listen_pvconn_name = optarg; break; VCONN_SSL_OPTION_HANDLERS