X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=python%2Fovs%2Freconnect.py;h=a6ecc39b32710ece063efb850072d19f0c5c44fa;hb=3a656eafb96ab8a474e943baabdb2679d0a6b0ef;hp=3445245db61e9ef3c02102d7c7b59ce6ae090b21;hpb=c36cf65edac28ccd7d2681521a651c35c8b2453e;p=sliver-openvswitch.git diff --git a/python/ovs/reconnect.py b/python/ovs/reconnect.py index 3445245db..a6ecc39b3 100644 --- a/python/ovs/reconnect.py +++ b/python/ovs/reconnect.py @@ -1,4 +1,4 @@ -# Copyright (c) 2010 Nicira Networks +# Copyright (c) 2010, 2011 Nicira Networks # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,15 +12,18 @@ # See the License for the specific language governing permissions and # limitations under the License. -import logging import os +import ovs.vlog + # Values returned by Reconnect.run() CONNECT = 'connect' DISCONNECT = 'disconnect' PROBE = 'probe' EOF = -1 +vlog = ovs.vlog.Vlog("reconnect") + class Reconnect(object): """A finite-state machine for connecting and reconnecting to a network @@ -96,9 +99,9 @@ class Reconnect(object): @staticmethod def run(fsm, now): - logging.debug("%s: idle %d ms, sending inactivity probe" - % (fsm.name, - now - max(fsm.last_received, fsm.state_entered))) + vlog.dbg("%s: idle %d ms, sending inactivity probe" + % (fsm.name, + now - max(fsm.last_received, fsm.state_entered))) fsm._transition(now, Reconnect.Idle) return PROBE @@ -112,12 +115,12 @@ class Reconnect(object): @staticmethod def run(fsm, now): - logging.error("%s: no response to inactivity probe after %.3g " - "seconds, disconnecting" - % (fsm.name, (now - fsm.state_entered) / 1000.0)) + vlog.err("%s: no response to inactivity probe after %.3g " + "seconds, disconnecting" + % (fsm.name, (now - fsm.state_entered) / 1000.0)) return DISCONNECT - class Reconnect: + class Reconnect(object): name = "RECONNECT" is_connected = False @@ -139,14 +142,14 @@ class Reconnect(object): self.max_backoff = 8000 self.probe_interval = 5000 self.passive = False - self.info_level = logging.info + self.info_level = vlog.info self.state = Reconnect.Void self.state_entered = now self.backoff = 0 self.last_received = now - self.last_connected = now - self.last_disconnected = now + self.last_connected = None + self.last_disconnected = None self.max_tries = None self.creation_time = now @@ -160,16 +163,16 @@ class Reconnect(object): debug level, by default keeping them out of log files. This is appropriate if the connection is one that is expected to be short-lived, so that the log messages are merely distracting. - + If 'quiet' is false, this object logs informational messages at info level. This is the default. - + This setting has no effect on the log level of debugging, warning, or error messages.""" if quiet: - self.info_level = logging.debug + self.info_level = vlog.dbg else: - self.info_level = logging.info + self.info_level = vlog.info def get_name(self): return self.name @@ -177,7 +180,7 @@ class Reconnect(object): def set_name(self, name): """Sets this object's name to 'name'. If 'name' is None, then "void" is used instead. - + The name is used in log messages.""" if name is None: self.name = "void" @@ -235,7 +238,7 @@ class Reconnect(object): if (self.state == Reconnect.Backoff and self.backoff > self.max_backoff): self.backoff = self.max_backoff - + def set_probe_interval(self, probe_interval): """Sets the "probe interval" to 'probe_interval', in milliseconds. If this is zero, it disables the connection keepalive feature. If it is @@ -260,7 +263,8 @@ class Reconnect(object): def set_passive(self, passive, now): """Configures this FSM for active or passive mode. In active mode (the default), the FSM is attempting to connect to a remote host. In - passive mode, the FSM is listening for connections from a remote host.""" + passive mode, the FSM is listening for connections from a remote + host.""" if self.passive != passive: self.passive = passive @@ -316,8 +320,8 @@ class Reconnect(object): # Report what happened if self.state in (Reconnect.Active, Reconnect.Idle): if error > 0: - logging.warning("%s: connection dropped (%s)" - % (self.name, os.strerror(error))) + vlog.warn("%s: connection dropped (%s)" + % (self.name, os.strerror(error))) elif error == EOF: self.info_level("%s: connection closed by peer" % self.name) @@ -325,22 +329,22 @@ class Reconnect(object): self.info_level("%s: connection dropped" % self.name) elif self.state == Reconnect.Listening: if error > 0: - logging.warning("%s: error listening for connections (%s)" - % (self.name, os.strerror(error))) + vlog.warn("%s: error listening for connections (%s)" + % (self.name, os.strerror(error))) else: self.info_level("%s: error listening for connections" % self.name) else: if self.passive: - type = "listen" + type_ = "listen" else: - type = "connection" + type_ = "connection" if error > 0: - logging.warning("%s: %s attempt failed (%s)" - % (self.name, type, os.strerror(error))) + vlog.warn("%s: %s attempt failed (%s)" + % (self.name, type_, os.strerror(error))) else: self.info_level("%s: %s attempt timed out" - % (self.name, type)) + % (self.name, type_)) if (self.state in (Reconnect.Active, Reconnect.Idle)): self.last_disconnected = now @@ -386,15 +390,15 @@ class Reconnect(object): else: self.info_level("%s: connecting..." % self.name) self._transition(now, Reconnect.ConnectInProgress) - + def listening(self, now): """Tell this FSM that the client is listening for connection attempts. This state last indefinitely until the client reports some change. - + The natural progression from this state is for the client to report that a connection has been accepted or is in progress of being accepted, by calling self.connecting() or self.connected(). - + The client may also report that listening failed (e.g. accept() returned an unexpected error such as ENOMEM) by calling self.listen_error(), in which case the FSM will back off and eventually @@ -407,7 +411,7 @@ class Reconnect(object): def listen_error(self, now, error): """Tell this FSM that the client's attempt to accept a connection failed (e.g. accept() returned an unexpected error such as ENOMEM). - + If the FSM is currently listening (self.listening() was called), it will back off and eventually return ovs.reconnect.CONNECT from self.run() to tell the client to try listening again. If there is an @@ -456,44 +460,44 @@ class Reconnect(object): if connected_before: self.total_connected_duration += now - self.last_connected self.seqno += 1 - - logging.debug("%s: entering %s" % (self.name, state.name)) + + vlog.dbg("%s: entering %s" % (self.name, state.name)) self.state = state self.state_entered = now def run(self, now): """Assesses whether any action should be taken on this FSM. The return value is one of: - + - None: The client need not take any action. - + - Active client, ovs.reconnect.CONNECT: The client should start a connection attempt and indicate this by calling self.connecting(). If the connection attempt has definitely succeeded, it should call self.connected(). If the connection attempt has definitely failed, it should call self.connect_failed(). - + The FSM is smart enough to back off correctly after successful connections that quickly abort, so it is OK to call self.connected() after a low-level successful connection (e.g. connect()) even if the connection might soon abort due to a failure at a high-level (e.g. SSL negotiation failure). - + - Passive client, ovs.reconnect.CONNECT: The client should try to listen for a connection, if it is not already listening. It should call self.listening() if successful, otherwise self.connecting() or reconnected_connect_failed() if the attempt is in progress or definitely failed, respectively. - + A listening passive client should constantly attempt to accept a new connection and report an accepted connection with self.connected(). - + - ovs.reconnect.DISCONNECT: The client should abort the current connection or connection attempt or listen attempt and call self.disconnected() or self.connect_failed() to indicate it. - + - ovs.reconnect.PROBE: The client should send some kind of request to the peer that will elicit a response, to ensure that the connection is indeed in working order. (This will only be @@ -503,7 +507,7 @@ class Reconnect(object): return self.state.run(self, now) else: return None - + def wait(self, poller, now): """Causes the next call to poller.block() to wake up when self.run() should be called.""" @@ -513,8 +517,8 @@ class Reconnect(object): def timeout(self, now): """Returns the number of milliseconds after which self.run() should be - called if nothing else notable happens in the meantime, or a negative - number if this is currently unnecessary.""" + called if nothing else notable happens in the meantime, or None if this + is currently unnecessary.""" deadline = self.state.deadline(self) if deadline is not None: remaining = deadline - now @@ -529,23 +533,21 @@ class Reconnect(object): False otherwise.""" return self.state.is_connected - def get_connection_duration(self, now): - """Returns the number of milliseconds for which this FSM has been - continuously connected to its peer. (If this FSM is not currently - connected, this is 0.)""" - if self.is_connected(): + def get_last_connect_elapsed(self, now): + """Returns the number of milliseconds since 'fsm' was last connected + to its peer. Returns None if never connected.""" + if self.last_connected: return now - self.last_connected else: - return 0 + return None - def get_disconnect_duration(self, now): - """Returns the number of milliseconds for which this FSM has been - continuously disconnected from its peer. (If this FSM is not currently - connected, this is 0.)""" - if not self.is_connected(): + def get_last_disconnect_elapsed(self, now): + """Returns the number of milliseconds since 'fsm' was last disconnected + from its peer. Returns None if never disconnected.""" + if self.last_disconnected: return now - self.last_disconnected else: - return 0 + return None def get_stats(self, now): class Stats(object): @@ -558,10 +560,12 @@ class Reconnect(object): stats.backoff = self.backoff stats.seqno = self.seqno stats.is_connected = self.is_connected() - stats.current_connection_duration = self.get_connection_duration(now) - stats.current_disconnect_duration = self.get_disconnect_duration(now) - stats.total_connected_duration = (stats.current_connection_duration + - self.total_connected_duration) + stats.msec_since_connect = self.get_last_connect_elapsed(now) + stats.msec_since_disconnect = self.get_last_disconnect_elapsed(now) + stats.total_connected_duration = self.total_connected_duration + if self.is_connected(): + stats.total_connected_duration += ( + self.get_last_connect_elapsed(now)) stats.n_attempted_connections = self.n_attempted_connections stats.n_successful_connections = self.n_successful_connections stats.state = self.state.name