X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=lib%2Frconn.c;h=2cbe43e98df6c3c7642471fd6e0f5d398661d4cd;hb=refs%2Fheads%2Fxs5.7;hp=4c6c9e955a5e0358c3381e9376408e63e16e006b;hpb=1d87357a1322c2faa290452c08c7f794c0be848b;p=sliver-openvswitch.git diff --git a/lib/rconn.c b/lib/rconn.c index 4c6c9e955..2cbe43e98 100644 --- a/lib/rconn.c +++ b/lib/rconn.c @@ -111,6 +111,18 @@ struct rconn { * a response. */ int probe_interval; /* Secs of inactivity before sending probe. */ + /* When we create a vconn we obtain these values, to save them past the end + * of the vconn's lifetime. Otherwise, in-band control will only allow + * traffic when a vconn is actually open, but it is nice to allow ARP to + * complete even between connection attempts, and it is also polite to + * allow traffic from other switches to go through to the controller + * whether or not we are connected. + * + * We don't cache the local port, because that changes from one connection + * attempt to the next. */ + uint32_t local_ip, remote_ip; + uint16_t remote_port; + /* Messages sent or received are copied to the monitor connections. */ #define MAX_MONITORS 8 struct vconn *monitors[8]; @@ -121,6 +133,7 @@ static unsigned int elapsed_in_this_state(const struct rconn *); static unsigned int timeout(const struct rconn *); static bool timed_out(const struct rconn *); static void state_transition(struct rconn *, enum state); +static void set_vconn_name(struct rconn *, const char *name); static int try_send(struct rconn *); static int reconnect(struct rconn *); static void disconnect(struct rconn *, int error); @@ -236,8 +249,7 @@ int rconn_connect(struct rconn *rc, const char *name) { rconn_disconnect(rc); - free(rc->name); - rc->name = xstrdup(name); + set_vconn_name(rc, name); rc->reliable = true; return reconnect(rc); } @@ -248,8 +260,7 @@ rconn_connect_unreliably(struct rconn *rc, { assert(vconn != NULL); rconn_disconnect(rc); - free(rc->name); - rc->name = xstrdup(name); + set_vconn_name(rc, name); rc->reliable = false; rc->vconn = vconn; rc->last_connected = time_now(); @@ -273,8 +284,7 @@ rconn_disconnect(struct rconn *rc) vconn_close(rc->vconn); rc->vconn = NULL; } - free(rc->name); - rc->name = xstrdup("void"); + set_vconn_name(rc, "void"); rc->reliable = false; rc->backoff = 0; @@ -323,6 +333,9 @@ reconnect(struct rconn *rc) rc->n_attempted_connections++; retval = vconn_open(rc->name, OFP_VERSION, &rc->vconn); if (!retval) { + rc->remote_ip = vconn_get_remote_ip(rc->vconn); + rc->local_ip = vconn_get_local_ip(rc->vconn); + rc->remote_port = vconn_get_remote_port(rc->vconn); rc->backoff_deadline = time_now() + rc->backoff; state_transition(rc, S_CONNECTING); } else { @@ -486,7 +499,7 @@ rconn_recv(struct rconn *rc) int error = vconn_recv(rc->vconn, &buffer); if (!error) { copy_to_monitor(rc, buffer); - if (is_admitted_msg(buffer) + if (rc->probably_admitted || is_admitted_msg(buffer) || time_now() - rc->last_connected >= 30) { rc->probably_admitted = true; rc->last_admitted = time_now(); @@ -624,31 +637,38 @@ rconn_is_connected(const struct rconn *rconn) return is_connected_state(rconn->state); } -/* Returns 0 if 'rconn' is connected. Otherwise, if 'rconn' is in a "failure - * mode" (that is, it is not connected), returns the number of seconds that it - * has been in failure mode, ignoring any times that it connected but the - * controller's admission control policy caused it to be quickly - * disconnected. */ +/* Returns true if 'rconn' is connected and thought to have been accepted by + * the peer's admission-control policy. */ +bool +rconn_is_admitted(const struct rconn *rconn) +{ + return (rconn_is_connected(rconn) + && rconn->last_admitted >= rconn->last_connected); +} + +/* Returns 0 if 'rconn' is currently connected and considered to have been + * accepted by the peer's admission-control policy, otherwise the number of + * seconds since 'rconn' was last in such a state. */ int rconn_failure_duration(const struct rconn *rconn) { - return rconn_is_connected(rconn) ? 0 : time_now() - rconn->last_admitted; + return rconn_is_admitted(rconn) ? 0 : time_now() - rconn->last_admitted; } -/* 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 known. */ +/* Returns the IP address of the peer, or 0 if the peer's IP address is not + * known. */ uint32_t rconn_get_remote_ip(const struct rconn *rconn) { - return rconn->vconn ? vconn_get_remote_ip(rconn->vconn) : 0; + return rconn->remote_ip; } -/* Returns the transport port of the peer, or 0 if the peer does not - * contain a port or if the port is not known. */ +/* Returns the transport port of the peer, or 0 if the peer's port is not + * known. */ uint16_t rconn_get_remote_port(const struct rconn *rconn) { - return rconn->vconn ? vconn_get_remote_port(rconn->vconn) : 0; + return rconn->remote_port; } /* Returns the IP address used to connect to the peer, or 0 if the @@ -657,7 +677,7 @@ rconn_get_remote_port(const struct rconn *rconn) uint32_t rconn_get_local_ip(const struct rconn *rconn) { - return rconn->vconn ? vconn_get_local_ip(rconn->vconn) : 0; + return rconn->local_ip; } /* Returns the transport port used to connect to the peer, or 0 if the @@ -805,6 +825,19 @@ rconn_packet_counter_dec(struct rconn_packet_counter *c) } } +/* Set the name of the remote vconn to 'name' and clear out the cached IP + * address and port information, since changing the name also likely changes + * these values. */ +static void +set_vconn_name(struct rconn *rc, const char *name) +{ + free(rc->name); + rc->name = xstrdup(name); + rc->local_ip = 0; + rc->remote_ip = 0; + rc->remote_port = 0; +} + /* Tries to send a packet from 'rc''s send buffer. Returns 0 if successful, * otherwise a positive errno value. */ static int