def test_min_latency_app(): """Test a single min latency app""" topo = complete_topology(4) for link in topo.links(): topo.set_resource(link, BANDWIDTH, 1) tcs = [TrafficClass(0, u'classname', 0, 2, array([1]))] # Generate all paths for this traffic class pptc = generate_paths_tc(topo, tcs, null_predicate, cutoff=100) appconfig = { 'name': u'te', 'constraints': [(Constraint.ROUTE_ALL, (), {})], 'obj': (Objective.MIN_LATENCY, (), {}), 'resource_cost': { BANDWIDTH: (LINKS, 1, None) } } app = App(pptc, **appconfig) caps = NetworkCaps(topo) caps.add_cap(BANDWIDTH, cap=1) opt = from_app(topo, app, NetworkConfig(caps)) opt.solve() assert opt.is_solved() # norm factor for latency is diameter * n^2 norm = topo.diameter() * 16 # the objective is 1-normalized latency, and latency is 1. # because 1 path with flow fraction of 1. solution = opt.get_solved_objective(app)[0] assert solution == 1 - 1 / norm or abs(solution - (1 - 1 / norm)) <= EPSILON solution = opt.get_solved_objective() assert solution == 1 - 1 / norm or abs(solution - (1 - 1 / norm)) <= EPSILON
def test_maxflow(cap): """ Check that maxflow works correctly, for a single traffic class """ # Generate a topology: topo = complete_topology(4) for link in topo.links(): topo.set_resource(link, BANDWIDTH, 1) tcs = [TrafficClass(0, u'classname', 0, 2, array([3]))] # Generate all paths for this traffic class pptc = generate_paths_tc(topo, tcs, null_predicate, cutoff=100) appconfig = { 'name': u'mf', 'constraints': [], 'obj': (Objective.MAX_FLOW, (), {}), 'resource_cost': { BANDWIDTH: (LINKS, 1, None) } } app = App(pptc, **appconfig) caps = NetworkCaps(topo) caps.add_cap(BANDWIDTH, cap=cap) opt = from_app(topo, app, NetworkConfig(caps)) opt.solve() assert opt.is_solved() # Ensure that both app objective and global objective are the same # Also, use abs(actual - exprected) because floating point errors solution = opt.get_solved_objective(app)[0] assert solution == cap or abs(solution - cap) <= EPSILON solution = opt.get_solved_objective() assert solution == cap or abs(solution - cap) <= EPSILON
def test_mbox_load_balancing(): """Test the middlebox loadbalancing""" topo = complete_topology(4) for n in topo.nodes(): topo.set_resource(n, CPU, 1) topo.set_mbox(n) tcs = [TrafficClass(0, u'classname', 0, 2, array([1]))] # Generate all paths for this traffic class pptc = generate_paths_tc(topo, tcs, has_mbox_predicate, modify_func=use_mbox_modifier, cutoff=100) appconfig = { 'name': u'mb_lb', 'constraints': [(Constraint.ROUTE_ALL, (), {})], 'obj': (Objective.MIN_NODE_LOAD, (CPU, ), {}), 'resource_cost': { CPU: (MBOXES, 1, None) } } app = App(pptc, **appconfig) caps = NetworkCaps(topo) caps.add_cap(CPU, cap=1) opt = from_app(topo, app, NetworkConfig(caps)) opt.solve() assert opt.is_solved() # THE solution is 1-objective because of the maximization flip solution = 1 - opt.get_solved_objective(app)[0] # Use abs(actual - exprected) because floating point errors assert solution == .25 or abs(solution - .25) <= EPSILON solution = 1 - opt.get_solved_objective() assert solution == .25 or abs(solution - .25) <= EPSILON
def test_te_app(): """ Test a single traffic engineering app""" topo = complete_topology(4) for link in topo.links(): topo.set_resource(link, BANDWIDTH, 1) tcs = [TrafficClass(0, u'classname', 0, 2, array([1]))] # Generate all paths for this traffic class pptc = generate_paths_tc(topo, tcs, null_predicate, cutoff=100) appconfig = { 'name': u'te', 'constraints': [(Constraint.ROUTE_ALL, (), {})], 'obj': (Objective.MIN_LINK_LOAD, (BANDWIDTH,), {}), 'resource_cost': {BANDWIDTH: (LINKS, 1, None)} } app = App(pptc, **appconfig) caps = NetworkCaps(topo) caps.add_cap(BANDWIDTH, cap=1) opt = from_app(topo, app, NetworkConfig(caps)) opt.solve() assert opt.is_solved() # THE solution is 1-objective because of the maximization flip solution = 1 - opt.get_solved_objective(app)[0] # Use abs(actual - exprected) because floating point errors assert solution == .333333 or abs(solution - .33333) <= EPSILON solution = 1 - opt.get_solved_objective() assert solution == .333333 or abs(solution - .33333) <= EPSILON
def test_maxflow_inapp_caps(cap): """Text maxflow, but use the CAP constraint instead of global network caps""" # Generate a topology: topo = complete_topology(4) for link in topo.links(): topo.set_resource(link, BANDWIDTH, 1) tcs = [TrafficClass(0, u'classname', 0, 2, array([3]))] # Generate all paths for this traffic class pptc = generate_paths_tc(topo, tcs, null_predicate, cutoff=100) caps = {link: cap for link in topo.links()} appconfig = { 'name': u'mf', 'constraints': [(Constraint.CAP_LINKS, (BANDWIDTH, caps), {})], 'obj': (Objective.MAX_FLOW, (), {}), 'resource_cost': {BANDWIDTH: (LINKS, 1, None)} } app = App(pptc, **appconfig) opt = from_app(topo, app, NetworkConfig()) opt.solve() assert opt.is_solved() # Ensure that both app objective and global objective are the same # Also, use abs(actual - exprected) because floating point errors solution = opt.get_solved_objective(app)[0] assert solution == cap or abs(solution - cap) <= EPSILON solution = opt.get_solved_objective() assert solution == cap or abs(solution - cap) <= EPSILON
def test_mbox_load_balancing_all_tcs(): """Test the middlebox loadbalancing""" topo = complete_topology(4) for n in topo.nodes(): topo.set_resource(n, CPU, 1) topo.set_mbox(n) tcs = [TrafficClass(0, u'classname', s, t, array([1])) for (s, t) in product(topo.nodes(), repeat=2)] # Generate all paths for this traffic class pptc = generate_paths_tc(topo, tcs, has_mbox_predicate, modify_func=use_mbox_modifier, cutoff=100) appconfig = { 'name': u'mb_lb', 'constraints': [(Constraint.ROUTE_ALL, (), {})], 'obj': (Objective.MIN_NODE_LOAD, (CPU,), {}), 'resource_cost': {CPU: (MBOXES, 1, None)} } app = App(pptc, **appconfig) caps = NetworkCaps(topo) caps.add_cap(CPU, cap=1) opt = from_app(topo, app, NetworkConfig(caps)) opt.solve() assert opt.is_solved() # THE solution is 1-objective because of the maximization flip solution = 1 - opt.get_solved_objective(app)[0] # Use abs(actual - exprected) because floating point errors assert solution == 1 or abs(solution - 1) <= EPSILON solution = 1 - opt.get_solved_objective() assert solution == 1 or abs(solution - 1) <= EPSILON
def test_te_app(): """ Test a single traffic engineering app""" topo = complete_topology(4) for link in topo.links(): topo.set_resource(link, BANDWIDTH, 1) tcs = [TrafficClass(0, u'classname', 0, 2, array([1]))] # Generate all paths for this traffic class pptc = generate_paths_tc(topo, tcs, null_predicate, cutoff=100) appconfig = { 'name': u'te', 'constraints': [(Constraint.ROUTE_ALL, (), {})], 'obj': (Objective.MIN_LINK_LOAD, (BANDWIDTH, ), {}), 'resource_cost': { BANDWIDTH: (LINKS, 1, None) } } app = App(pptc, **appconfig) caps = NetworkCaps(topo) caps.add_cap(BANDWIDTH, cap=1) opt = from_app(topo, app, NetworkConfig(caps)) opt.solve() assert opt.is_solved() # THE solution is 1-objective because of the maximization flip solution = 1 - opt.get_solved_objective(app)[0] # Use abs(actual - exprected) because floating point errors assert solution == .333333 or abs(solution - .33333) <= EPSILON solution = 1 - opt.get_solved_objective() assert solution == .333333 or abs(solution - .33333) <= EPSILON
def test_min_latency_app(): """Test a single min latency app""" topo = complete_topology(4) for link in topo.links(): topo.set_resource(link, BANDWIDTH, 1) tcs = [TrafficClass(0, u'classname', 0, 2, array([1]))] # Generate all paths for this traffic class pptc = generate_paths_tc(topo, tcs, null_predicate, cutoff=100) appconfig = { 'name': u'te', 'constraints': [(Constraint.ROUTE_ALL, (), {})], 'obj': (Objective.MIN_LATENCY, (), {}), 'resource_cost': {BANDWIDTH: (LINKS, 1, None)} } app = App(pptc, **appconfig) caps = NetworkCaps(topo) caps.add_cap(BANDWIDTH, cap=1) opt = from_app(topo, app, NetworkConfig(caps)) opt.solve() assert opt.is_solved() # norm factor for latency is diameter * n^2 norm = topo.diameter() * 16 # the objective is 1-normalized latency, and latency is 1. # because 1 path with flow fraction of 1. solution = opt.get_solved_objective(app)[0] assert solution == 1 - 1 / norm or abs(solution - (1 - 1 / norm)) <= EPSILON solution = opt.get_solved_objective() assert solution == 1 - 1 / norm or abs(solution - (1 - 1 / norm)) <= EPSILON
def test_switch_labels(): """ Ensure that switches are labeled appropriately by default """ for topo in [complete_topology(5), chain_topology(5)]: for node in topo.nodes(): assert SWITCH in topo.get_service_types(node)
def test_graph_directed(): """ Insure we keep newly constructed topologies as directed graph """ topo = complete_topology(5) assert isinstance(topo.get_graph(), networkx.DiGraph) # even if original graph is undirected topo = Topology('noname', networkx.star_graph(8)) assert topo.get_graph().is_directed()
def MaxFlow(): # ============== # Let's generate some example data; SOL has some functions to help with that. # ============== # A complete topology topo = complete_topology(5) # ingress-egress pairs, between which the traffic will flow iePairs = [(0, 3)] # generate a traffic matrix, in this case, a uniform traffic matrix with a million flows trafficMatrix = provisioning.uniformTM( iePairs, 10 ** 6) # compute traffic classes. We will only have one class that encompasses all the traffic; # assume that each flow consumes 2000 units of bandwidth trafficClasses = generateTrafficClasses(iePairs, trafficMatrix, {'allTraffic': 1}, {'allTraffic': 2000}) # since our topology is "fake", provision our links and generate link capacities in our network linkcaps = provisioning.provision_links(topo, trafficClasses, 1) # these will be our link constraints: do not load links more than 50% linkConstrCaps = {(u, v): .5 for u, v in topo.links()} # ============== # Optimization # ============== # Start our optimization. # SOL automatically takes care of the path generation, but it needs the topology, traffic classes, path predicate # and path selection strategy. # nullPredicate means any path will do, no specific service chaining or policy requirements. # Then, SOL will choose maximum of 5 shortest paths for each traffic class to route traffic on. opt, pptc = initOptimization(topo, trafficClasses, nullPredicate, 'shortest', 5, backend='CPLEX') # Now, our constraints. # First, we must allocate some amount of flow (i.e, tell SOL to route things frorm ingress to egress) opt.allocate_flow(pptc) # Traffic must not overload links -- so cap links according to our link constraints (recall the 50%) # linkcapfunc defines how bandwidth is consumed. linkcapfunc = lambda link, tc, path, resource: tc.volBytes / linkcaps[link] opt.capLinks(pptc, 'bandwidth', linkConstrCaps, linkcapfunc) # Push as much traffic as we can opt.maxFlow(pptc) # Solve the optimization opt.solve() # For simple applications we can interface with ONOS and setup forwarding routes automatically: # Insert correct address to the web interface here; # You must ensure that ONOS is running the SOL app to be able to install rules in a batch onos = ONOSInterface("localhost:8181") routes = {} for tc, paths in opt.get_path_fractions(pptc).iteritems(): routes.update(computeSplit(tc, paths, 0)) onos.push_routes(routes) print("Done")
def test_complete_generators(size): """ Some basic tests for complete topology generators. Ensure we return correct types and correct number of nodes. """ topo = complete_topology(size) assert isinstance(topo, Topology) assert isinstance(topo.get_graph(), networkx.DiGraph) assert topo.num_nodes() == size assert networkx.is_isomorphic(topo.get_graph().to_undirected(), networkx.complete_graph(size))
def MaxFlow(): # ============== # Let's generate some example data; SOL has some functions to help with that. # ============== # A complete topology topo = complete_topology(5) # ingress-egress pairs, between which the traffic will flow iePairs = [(0, 3)] # generate a traffic matrix, in this case, a uniform traffic matrix with a million flows trafficMatrix = provisioning.uniformTM( iePairs, 10 ** 6) # compute traffic classes. We will only have one class that encompasses all the traffic; # assume that each flow consumes 2000 units of bandwidth trafficClasses = generateTrafficClasses(iePairs, trafficMatrix, {'allTraffic': 1}, {'allTraffic': 2000}) # since our topology is "fake", provision our links and generate link capacities in our network linkcaps = provisioning.provision_links(topo, trafficClasses, 1) # these will be our link constraints: do not load links more than 50% linkConstrCaps = {(u, v): .5 for u, v in topo.links()} # ============== # Optimization # ============== # Start our optimization. # SOL automatically takes care of the path generation, but it needs the topology, traffic classes, path predicate # and path selection strategy. # nullPredicate means any path will do, no specific service chaining or policy requirements. # Then, SOL will choose maximum of 5 shortest paths for each traffic class to route traffic on. opt, pptc = initOptimization(topo, trafficClasses, nullPredicate, 'shortest', 5, backend='CPLEX') # Now, our constraints. # First, we must allocate some amount of flow (i.e, tell SOL to route things frorm ingress to egress) opt.allocate_flow(pptc) # Traffic must not overload links -- so cap links according to our link constraints (recall the 50%) # linkcapfunc defines how bandwidth is consumed. linkcapfunc = lambda link, tc, path, resource: tc.volBytes / linkcaps[link] opt.capLinks(pptc, 'bandwidth', linkConstrCaps, linkcapfunc) # Push as much traffic as we can opt.maxFlow(pptc) # Solve the optimization opt.solve() ### Results # Print the objective function --- this is the flow fraction we managed to send through the network print opt.get_solved_objective() # pretty-print the paths on which the traffic is routed, along with the fraction for each traffic class for tc, paths in opt.get_path_fractions(pptc).iteritems(): print 'src:', tc.src, 'dst:', tc.dst, 'paths:', pprint.pformat(paths)
def pptc(): """ An example paths per traffic class """ # get a complete topology topo = complete_topology(5) # generate a dummy TM and traffic classes tm = tmgen.uniform_tm(5, 20, 50, 1) tc = traffic_classes(tm, {u'all': 1}, as_dict=False) # generate all possibe paths res = generate_paths_tc(topo, tc, null_predicate, 10, numpy.inf) return res
def test_num_nodes(size, some_text): """ Check that num_nodes functions correctly regardless of topology size and service type :param size: size of the topology :param some_text: service type to test the absense of. So anything except 'switch' :return: """ assume(some_text) topo = complete_topology(size) assert topo.num_nodes() == size # size of the network assert topo.num_nodes(SWITCH) == size # everyting is a switch assert topo.num_nodes(some_text) == 0 # no other functions present
def test_write_read(tmpdir): """Check that writing topology to disk and restoring it produces the expected result""" dirname = u(os.path.abspath(tmpdir.dirname)) topo = complete_topology(5) for l in topo.links(): topo.set_resource(l, 'myresource', 4) topo.write_graph(dirname + os.path.sep + u'testgml.gml') topo2 = Topology(topo.name) topo2.load_graph(dirname + os.path.sep + u'testgml.gml') assert networkx.is_isomorphic(topo.get_graph(), topo2.get_graph()) assert topo.name == topo2.name # Check that resources are preserved for n in topo.nodes(): assert topo.get_resources(n) == topo2.get_resources(n) for l in topo.links(): assert topo.get_resources(n) == topo2.get_resources(n)
def test_shortest_path(): """ Check that we can correctly implement shortest path routing """ # Generate a topology: topo = complete_topology(5) # Generate a single traffic class: # TrafficClass (id, name, source node, destination node) tcs = [TrafficClass(0, u'classname', 0, 2)] # Generate all paths for this traffic class pptc = generate_paths_tc(topo, tcs, null_predicate, cutoff=100) # Application configuration appconfig = { 'name': u'minLatencyApp', 'constraints': [(Constraint.ROUTE_ALL, (pptc.tcs(),), {})], 'obj': (Objective.MIN_LATENCY, (), {}), 'resource_cost': {} } # Create an application based on our config app = App(pptc, **appconfig) # Create and solve an optimization based on the app # No link capacities will just result in a single shortest path opt = from_app(topo, app, NetworkConfig(None)) opt.solve() assert opt.is_solved() paths = opt.get_paths() for pi, p in enumerate(paths.paths(tcs[0])): if list(p.nodes()) == [0, 2]: assert p.flow_fraction() == 1 else: assert p.flow_fraction() == 0 # norm factor for latency is diameter * n^2 norm = topo.diameter() * 25 # the objective is 1-normalized latency, and latency is 1. # because 1 path with flow fraction of 1. solution = opt.get_solved_objective(app)[0] assert solution == 1 - 1 / norm or abs(solution - 1 - 1 / norm) <= EPSILON solution = opt.get_solved_objective() assert solution == 1 - 1 / norm or abs(solution - 1 - 1 / norm) <= EPSILON
def test_shortest_path(): """ Check that we can correctly implement shortest path routing """ # Generate a topology: topo = complete_topology(5) # Generate a single traffic class: # TrafficClass (id, name, source node, destination node) tcs = [TrafficClass(0, u'classname', 0, 2)] # Generate all paths for this traffic class pptc = generate_paths_tc(topo, tcs, null_predicate, cutoff=100) # Application configuration appconfig = { 'name': u'minLatencyApp', 'constraints': [(Constraint.ROUTE_ALL, (pptc.tcs(), ), {})], 'obj': (Objective.MIN_LATENCY, (), {}), 'resource_cost': {} } # Create an application based on our config app = App(pptc, **appconfig) # Create and solve an optimization based on the app # No link capacities will just result in a single shortest path opt = from_app(topo, app, NetworkConfig(None)) opt.solve() assert opt.is_solved() paths = opt.get_paths() for pi, p in enumerate(paths.paths(tcs[0])): if list(p.nodes()) == [0, 2]: assert p.flow_fraction() == 1 else: assert p.flow_fraction() == 0 # norm factor for latency is diameter * n^2 norm = topo.diameter() * 25 # the objective is 1-normalized latency, and latency is 1. # because 1 path with flow fraction of 1. solution = opt.get_solved_objective(app)[0] assert solution == 1 - 1 / norm or abs(solution - 1 - 1 / norm) <= EPSILON solution = opt.get_solved_objective() assert solution == 1 - 1 / norm or abs(solution - 1 - 1 / norm) <= EPSILON
def topo(): return complete_topology(8)
def topo(request): n = request.param t = complete_topology(n) for l in t.links(): t.set_resource(l, BANDWIDTH, n * (n - 1)) return t