def all_pairs_shortest_path(topo, hosts_only=False): """Construct all-pairs-shortest-path routing policy. Constructs an all-pairs shortest path routing policy for topo, using each switch or host id number as the source and destination mac address. Only make paths to hosts if hosts_only RETURNS: a policy that implements all-pairs shortest path """ forwarding_trees = [] for source in (topo.hosts() if hosts_only else topo.nodes()): # For each node, build the shortest paths to that node # We 'start' at the node because networkx forces us to. paths = nx.shortest_path(topo, source=source) # Build next-hop table next_hops = {} for dest, path in paths.items(): # path is a list, starting at source and ending at dest. if dest is not source and topo.node[dest]['isSwitch']: next_hops[dest] = path[-2] policies = [] for node, next_node in next_hops.items(): out_port = topo.node[node]['ports'][next_node] policies.append(Header({'switch': node}) |then| forward(node, out_port)) forwarding_trees.append(nary_policy_union(policies) % Header({'dstmac': source})) return nary_policy_union(forwarding_trees)
def compile_slices(topo, slices, assigner=vl.edge_optimal, verbose=False): """Turn a set of slices sharing a physical topology into a list of policies. See transform for more documentation. """ slice_only = [s for (s, p) in slices] if verbose: import sys print 'Assigning slice vlans...', vlans = assigner(topo, slice_only, verbose=verbose) slice_lookup = get_slice_lookup(vlans) if verbose: print 'done.' for i in range(len(slice_lookup)): print '%d: %s' % (i, slice_lookup[slice_only[i]]) print 'Compiling slices...', policy_list = [] count = 0 for slic, policy in slices: vlan_dict = symmetric_edge(slice_lookup[slic]) internal_p = internal_policy(slic.l_topo, policy, vlan_dict) external_p = external_policy(slic, policy, vlan_dict) policies = [p.get_physical_rep(slic.node_map, slic.port_map) for p in internal_p + external_p] policies = [p for p in policies if not isinstance(p, nc.BottomPolicy)] policy_list.append(nc.nary_policy_union(policies)) if verbose: count += 1 print '.', sys.stdout.flush() if verbose: print 'done.' print '%d policies generated.' % len(policy_list) return policy_list
def transform(combined, assigner=vl.sequential, verbose=False): """Turn a set of slices sharing a physical topology into a single policy. ARGS: combined: set of (slices, policies) (with the same physical topology) to combine assigner: function to use to assign vlans to slices. Must return a {slice: vlan} dictionary, defaults to sequential. verbose: print out progress information RETURNS: a single Policy encapsulating the shared but isolated behavior of all the slices """ policy_list = compile_slices(combined, assigner=assigner, verbose=verbose) return nc.nary_policy_union(policy_list)
def flood(topo, all_ports=False): """Construct a policy that floods packets out each port on each switch. if all_ports is set, even forward back out the port it came in. """ switches = topo.switches() policies = [] for switch in switches: ports = set(topo.node[switch]['port'].keys()) for port in ports: # Make a copy of ports without this one if all_ports: other_ports = ports else: other_ports = ports.difference([port]) for other_port in other_ports: pol = inport(switch, port) |then| forward(switch, other_port) policies.append(pol) return nary_policy_union(policies).reduce()
def multicast(topo, multicast_field='dstmac', multicast_value=0): """Construct a policy that multicasts packets to all nodes along the MST. Uses multicast_field:multicast_value to recognize multicast packets to send along the minimum spanning tree. """ mst = nx.minimum_spanning_tree(topo) edges = set(mst.edges()) for (n1, n2) in list(edges): edges.add((n2, n1)) policies = [] for node in topo.switches(): ports = set() for switch, port in topo.node[node]['ports'].items(): # If this link is in the MST if (node, switch) in edges: ports.add(port) for port in ports: others = ports.difference([port]) policies.append(inport(node, port) |then| Action(node, others)) return (nary_policy_union(policies) % Header({multicast_field: multicast_value}))
def flood_observe(topo, label=None, all_ports=False): """Construct a policy that floods packets and observes at the leaves. Sequentially assigns labels if none is set. Not thread-safe. """ if label is None: global next_label label = next_label next_label += 1 switches = topo.switches() policies = [] for switch in switches: ports = set(topo.node[switch]['port'].keys()) for port in ports: # Make a copy of ports without this one if all_ports: other_ports = ports else: other_ports = ports.difference([port]) for other_port in other_ports: pol = inport(switch, port) |then|\ Action(switch, ports=[other_port], obs=[label]) policies.append(pol) return nary_policy_union(policies).reduce()