def get_talker_state(self, src, src_stream, dst, dst_stream, action): if graph.find_path(self, src, dst) is None: state = 'talker_redundant' elif action == 'connect': if self.connected(src, src_stream, dst, dst_stream): state = 'talker_redundant' else: if self.listener_active_count(dst, dst_stream): state = 'talker_redundant' elif self.talker_active_count(src, src_stream): state = 'talker_existing' else: state = 'talker_new' elif action == 'disconnect': if not self.connected(src, src_stream, dst, dst_stream): state = 'talker_redundant' else: if self.talker_active_count(src, src_stream) == 1: state = 'talker_all' else: state = 'talker_existing' else: base.testError("Unknown action '%s'" % action, critical=True) log_debug("get_talker_state for %s %d %s %d: %s" % (src, src_stream, dst, dst_stream, state)) return (state + '_' + action)
def get_endpoints_connected_to(state, node): connected = set() for endpoint in endpoints.get_all(): if find_path(state, node, endpoint): connected |= set([endpoint]) log_debug("get_endpoints_connected_to %s: %s" % (node, connected)) return connected
def get_controller_state(self, controller_id, src, src_stream, dst, dst_stream, action): controllable_endpoints = graph.get_endpoints_connected_to(self, controller_id) if src not in controllable_endpoints or dst not in controllable_endpoints: state = 'timeout' elif action == 'connect': if src == dst: if self.listener_active_count(dst, dst_stream): state = 'listener_exclusive' else: state = 'listener_talker_timeout' elif self.connected(src, src_stream, dst, dst_stream): state = 'success' elif self.listener_active_count(dst, dst_stream): state = 'listener_exclusive' else: state = 'success' elif action == 'disconnect': if not self.connected(src, src_stream, dst, dst_stream): state = 'redundant' else: state = 'success' else: base.testError("Unknown action '%s'" % action, critical=True) log_debug("get_controller_state for %s %d %s %d: %s" % (src, src_stream, dst, dst_stream, state)) return ('controller_' + state + '_' + action)
def is_in_loop(state, node): in_loop = False loops = get_loops(state) for loop in loops: if node in loop: in_loop = True break log_debug("is_in_loop %s = %d" % (node, in_loop)) return in_loop
def get_eth_id(args): """ Get the ethernet interface ID for the current user """ with open('eth.json') as f: eth = json.load(f) if args.user not in eth: log_debug('User %s missing from eth.json' % args.user) sys.exit(1) return eth[args.user]
def get_loops(state): """ Find all the loops in the current set of connections. """ loops = [] for t,n in state.active_talkers.iteritems(): # If the endpoint is not active or already in a loop then ignore it if not n or any(t.src in loop for loop in loops): continue _get_loops(state, t.src, [t.src], loops) log_debug("get_loops got %s" % loops) return loops
def node_will_see_stream_enable(state, src, src_stream, dst, dst_stream, node): """ Determine whether a given node will see the stream between src/dst as a new stream. Returns True if it will be a new stream, False if it is an existing stream. """ log_debug("node_will_see_stream_enable %s ?" % node) if (state.connected(src, src_stream, dst, dst_stream) or state.listener_active_count(dst, dst_stream)): # Connection will have no effect log_debug("No, connection will not happen") return False # Look at all connections of this src stream for c,n in state.active_connections.iteritems(): if not n or c.talker.src != src or c.talker.src_stream != src_stream: continue nodes = find_path(state, src, c.listener.dst) log_debug("What about path %s?" % nodes) # Look for all nodes past this one in the path. If one of them is connected to # this stream then this node won't see enable, otherwise it should expect to past_node = False for n in nodes: if past_node: if state.connected(src, src_stream, n): log_debug("No forwarding, node %s is connected beyond %s?" % (n, node)) return False elif n == node: past_node = True return True
def get_forward_port(state, src, dst, node): """ Find the port name that is used to forward out of a node on a path from src -> dst. This is done by finding the node in the path. Its forwarding port name is the next node in the path. The port ID is the last character of that name. """ port = None try: path = find_path(state, src, dst) index = path.index(node) port_name = path[index + 1] port = int(port_name[-1]) except: pass log_debug("get_forward_port %s in %s -> %s: %s" % (node, src, dst, port)) return port
def port_will_see_bandwidth_change(state, src, src_stream, ep_name, port, command): num_active_streams = 0 # Look at all connections of this src stream for c,n in state.active_connections.iteritems(): if not n or c.talker.src != src or c.talker.src_stream != src_stream: continue if port_is_egress_in_path(state, c, ep_name, port): num_active_streams += 1 log_debug("port_will_see_bandwidth_change found %d active streams for %s:%s" % ( num_active_streams, ep_name, port)) if command == 'connect': # On connect the bandwidth should only change if this stream is not currently # forwarded through this port return num_active_streams == 0 else: # On disconnect the bandwidth should only change if there is 1 active # stream as this will be removed return num_active_streams == 1
def connected(self, src, src_stream, dst, dst_stream=None): """ Check whether a src stream is connected to a dest node. Can specify the dest stream if desired. """ talker = Talker(src, src_stream) listener = Listener(dst, dst_stream) connected = False if dst_stream: connection = Connection(talker, listener) if self.active_connections.get(connection, 0): connected = True else: for c,n in self.active_connections.iteritems(): if not n: continue if c.talker == talker and c.listener.dst == dst: connected = True # Note that the format of each operand is %s because that copes with a None log_debug("connected %s %s %s %s ? %s" % (src, src_stream, dst, dst_stream, connected)) return connected
def node_will_see_stream_disable(state, src, src_stream, dst, dst_stream, node): """ Determine whether a given node will see being disabled if it is turned off. """ log_debug("node_will_see_stream_disable %s ?" % node) if not state.connected(src, src_stream, dst, dst_stream): # Disconnection will have no effect log_debug("No, stream not connected") return False # Look at all connections of this src stream for c,n in state.active_connections.iteritems(): if not n: continue if c.talker.src != src or c.talker.src_stream != src_stream: continue nodes = find_path(state, src, c.listener.dst) log_debug("What about path %s?" % nodes) # Look for all nodes past this one in the path. If one of them is connected to # this stream then this node won't see disable, otherwise it should expect to past_node = False for n in nodes: if n == dst: # Ignore the current connection continue if past_node: if state.connected(src, src_stream, n): log_debug("No forwarding, node %s is connected beyond %s?" % (n, node)) return False elif n == node: past_node = True return True
def runTest(args): """ The test program - needs to yield on each expect and be decorated with @inlineCallbacks """ startup = AllOf([Expected(e, "Started", 10) for e in endpoints]) log_debug(startup) yield master.expect(startup) next_steps = AllOf([AllOf([Expected('ep0', "Next", 10)]), AllOf([Expected('ep1', "Next", 10)])]) log_debug(next_steps) yield master.expect(next_steps) seq = AllOf([Sequence([Expected(e, "Count0", 10), Expected(e, "Count1", 10)]) for e in endpoints]) log_debug(seq) yield master.expect(seq) base.testComplete(reactor)
def find_path(state, start, end, path=[]): """ A front-end for debug purposes """ path = _find_path(state, start, end) log_debug("find_path %s -> %s : %s" % (start, end, path)) return path
def draw_state(s, ep_names): """ Draw a graph of the connections. Creates the endpoints down the left. Creates connections at a depth to right which depends on the talker index. """ ep_offset = 0 ep_num = 0 active_talkers = set() num_endpoints = len(ep_names) lines = [] # The endpoints are rendered over 5 lines (start, out, name, in, end) # and then there is a 1-line gap between. num_lines = num_endpoints * 5 + num_endpoints - 1 for line_num in range(0, num_lines): ep_name = ep_names[ep_num] line = "" if ep_offset == 0 or ep_offset == 4: line += get_header(s, ep_name) line += " " + non_connection_line(ep_names, active_talkers) elif ep_offset == 1: line += " | | " if s.talker_active_count(ep_name, 0): max_listener_index = get_max_listener_index(s, ep_names, ep_name) if max_listener_index > ep_num: active_talkers |= set([ep_name]) else: if ep_name in active_talkers: active_talkers.remove(ep_name) line += "--" line += connection_line(ep_names, ep_num, active_talkers) else: line += " " + non_connection_line(ep_names, active_talkers) elif ep_offset == 2: line += " | %-4s | " % ep_name line += " " + non_connection_line(ep_names, active_talkers) elif ep_offset == 3: line += " | | " if s.listener_active_count(ep_name, 0): talker = get_talker_for_listener(s, ep_name) talker_index = ep_names.index(talker) if talker_index > ep_num: active_talkers |= set([talker]) else: max_listener_index = get_max_listener_index(s, ep_names, talker) if max_listener_index <= ep_num and talker in active_talkers: active_talkers.remove(talker) line += "<-" line += connection_line(ep_names, talker_index, active_talkers) else: line += " " + non_connection_line(ep_names, active_talkers) else: line += " " line += " " + non_connection_line(ep_names, active_talkers) ep_num += 1 ep_offset = -1 ep_offset += 1 lines += [line] for line in lines: log_debug(line)
def dump(self): log_debug("State:") for t,n in self.active_talkers.iteritems(): log_debug("Talker %s : %d" % (t, n)) for l,n in self.active_listeners.iteritems(): log_debug("Listeners %s : %d" % (l, n)) for c,n in self.active_connections.iteritems(): log_debug("Connection %s : %d" % (c, n)) for c,n in self.talker_on_count.iteritems(): log_debug("Talker on count %s : %d" % (c, n)) for c,n in self.clock_source_master.iteritems(): if n: log_debug("Clock source master %s" % c) rendering.draw_state(self, sorted(endpoints.get_all().keys()))