def test_next_hop_ibgp(self): # Arrange graph, origin_ann = self.get_ibgp_topo() r1, r2, r3, r4 = 'R1', 'R2', 'R3', 'R4' prefix = origin_ann.prefix req1 = PathReq(Protocols.BGP, dst_net=prefix, path=[r2, r1], strict=False) req2 = PathReq(Protocols.BGP, dst_net=prefix, path=[r3, r1], strict=False) req3 = PathReq(Protocols.BGP, dst_net=prefix, path=[r4, r1], strict=False) netcomplete = NetComplete([req1, req2, req3], graph, [origin_ann]) next_hop_vals = { 'R1': '0.0.0.0', 'R2': 'R1-lo100', 'R3': 'R1-lo100', 'R4': 'R1-lo100', } as_path_vals = { 'R1': 'as_path_100_100', 'R2': 'as_path_100_100', 'R3': 'as_path_100_100', 'R4': 'as_path_100_100', } as_path_len_vals = { 'R1': 1, 'R2': 1, 'R3': 1, 'R4': 1, } # Act ret = netcomplete.synthesize() netcomplete.write_configs('out-configs/ibgp') # Assert self.assertTrue(ret) for node, attrs in netcomplete.bgp_synthesizer.ibgp_propagation.nodes(data=True): for ann in attrs['box'].selected_sham: self.assertTrue(ann.permitted.is_concrete) self.assertTrue(ann.permitted.get_value()) self.assertTrue(ann.prefix.is_concrete) self.assertEquals(desanitize_smt_name(ann.prefix.get_value()), prefix) self.assertTrue(ann.next_hop.is_concrete) self.assertEquals(desanitize_smt_name(ann.next_hop.get_value()), next_hop_vals[node]) self.assertTrue(ann.as_path.is_concrete) self.assertEquals(ann.as_path.get_value(), as_path_vals[node]) self.assertTrue(ann.as_path_len.is_concrete) self.assertEquals(ann.as_path_len.get_value(), as_path_len_vals[node]) self.assertTrue(ann.med.is_concrete) self.assertEquals(ann.med.get_value(), origin_ann.med) self.assertTrue(ann.local_pref.is_concrete) self.assertEquals(ann.local_pref.get_value(), origin_ann.local_pref) for comm, val in ann.communities.iteritems(): self.assertTrue(val.is_concrete) self.assertEquals(val.get_value(), origin_ann.communities[comm])
def test_not_empty(self): g = self.get_two_nodes() prefix = 'P0' reqs = [PathReq(Protocols.BGP, prefix, ['R1', 'R2'], False)] static_syn = StaticSyn(reqs, g) with self.assertRaises(CannotSynthesizeStaticRoute): static_syn.synthesize()
def test_two_existing(self): g = self.get_two_nodes() prefix = 'P0' reqs = [PathReq(Protocols.BGP, prefix, ['R1', 'R2'], False)] g.add_static_route('R1', prefix, 'R2') static_syn = StaticSyn(reqs, g) static_syn.synthesize() self.assertEquals(g.get_static_routes('R1')[prefix], 'R2')
def read_reqs(req_file): with open(req_file) as f: s = f.read() parsed = parse_inputs(s) nets = {} for line in parsed: op, predicate, values = line assert op == '+', op assert predicate == 'Fwd', predicate net = values[0] protocol = values[-1] src, dst = values[1:-1] if net not in nets: nets[net] = {} if protocol not in nets[net]: nets[net][protocol] = [] paths = nets[net][protocol] appened = False for path in paths: assert isinstance(path, list) if path[-1] == src: path.append(dst) appened = True elif path[0] == dst: path.insert(0, src) appened = True if not appened: paths.append([src, dst]) proto_map = { 'ospf': Protocols.OSPF, 'static': Protocols.Static, 'bgp': Protocols.BGP } ospf_reqs = [] static_reqs = [] bgp_reqs = [] for net in nets: for protocol in nets[net]: paths = nets[net][protocol] proto = proto_map[protocol] for path in paths: req = PathReq(protocol=proto, dst_net=net, path=path, strict=False) if proto == Protocols.OSPF: ospf_reqs.append(req) elif proto == Protocols.Static: static_reqs.append(req) elif proto == Protocols.BGP: bgp_reqs.append(req) else: raise ValueError("Unknown protocol") return static_reqs, ospf_reqs, bgp_reqs
def get_3path_req(): p1 = ['R1', 'R4'] p2 = ['R1', 'R2', 'R3', 'R4'] p3 = ['R1', 'R3', 'R4'] paths = [p1, p2, p3] reqs = [] for path in paths: req = PathReq(Protocols.OSPF, path[-1], path, False) reqs.append(req) return reqs
def test_ordered_correct(self): fan_out = 4 network_graph = self.get_triangles(fan_out) source = 'source' sink = 'sink' p1 = [source, 'R1', sink] p2 = [source, 'R2', sink] p3 = [source, 'R3', sink] p4 = [source, 'R4', sink] path1 = PathReq(Protocols.OSPF, 'Google', p1, False) path2 = PathReq(Protocols.OSPF, 'Google', p2, False) path3 = PathReq(Protocols.OSPF, 'Google', p3, False) paths = [path1, path2, path3] order_req = PathOrderReq(Protocols.OSPF, 'Google', paths, False) ospf = synet.synthesis.ospf_heuristic.OSPFSyn(network_graph, gen_paths=10) ospf.add_req(order_req) ret = ospf.synthesize() self.assertTrue(ret) ospf.update_network_graph() p1_cost = [ network_graph.get_edge_ospf_cost(src, dst) for src, dst in zip(p1[0::1], p1[1::1]) ] p2_cost = [ network_graph.get_edge_ospf_cost(src, dst) for src, dst in zip(p2[0::1], p2[1::1]) ] p3_cost = [ network_graph.get_edge_ospf_cost(src, dst) for src, dst in zip(p3[0::1], p3[1::1]) ] p4_cost = [ network_graph.get_edge_ospf_cost(src, dst) for src, dst in zip(p4[0::1], p4[1::1]) ] p1_cost = sum(p1_cost) p2_cost = sum(p2_cost) p3_cost = sum(p3_cost) p4_cost = sum(p4_cost) self.assertLessEqual(p1_cost, p2_cost) self.assertLessEqual(p2_cost, p3_cost) self.assertLessEqual(p3_cost, p4_cost)
def generate_simple_reqs(topo, reqsize, rand): """Generate reqsize of PathReq""" paths = get_reqs(graph=topo, reqsize=reqsize, k=1, rand=rand) reqs = [] for plist in paths.values(): assert len(plist) >= 1 path = plist[0] req = PathReq(Protocols.OSPF, path[-1], path, False) reqs.append(req) return reqs
def test_ordered_notvalid(self): fan_out = 4 network_graph = self.get_triangles(fan_out) source = 'source' sink = 'sink' p1 = [source, 'R1', sink] p2 = [source, 'R2', sink] p3 = [source, 'R3', sink] path1 = PathReq(Protocols.OSPF, 'Google', p1, False) path2 = PathReq(Protocols.OSPF, 'Google', p2, False) path3 = PathReq(Protocols.OSPF, 'Google', p3, False) paths = [path1, path2, path3] order_req1 = PathOrderReq(Protocols.OSPF, 'Google', paths, False) order_req2 = PathOrderReq(Protocols.OSPF, 'Google', [path3, path2, path1], False) ospf = synet.synthesis.ospf_heuristic.OSPFSyn(network_graph, gen_paths=10) ospf.add_req(order_req1) ospf.add_req(order_req2) ret = ospf.synthesize() self.assertFalse(ret)
def generate_ecmp_reqs(topo, reqsize, ecmp, rand): """Generate reqsize of ECMPPathsReq each has ecmp paths""" paths = get_reqs(graph=topo, reqsize=reqsize, k=ecmp, rand=rand) reqs = [] for plist in paths.values(): assert len(plist) >= ecmp req = ECMPPathsReq(Protocols.OSPF, plist[0][-1], [ PathReq(Protocols.OSPF, path[-1], path, False) for path in plist[:ecmp] ], False) reqs.append(req) return reqs
def test_grid_one_peer(self): anns = self.get_announcements(1, 1) g = gen_mesh(4, 100) self.get_add_one_peer(g, ['R2'], anns.values()) ann = anns.values()[0] reqs = [ PathReq(Protocols.BGP, ann.prefix, ['ATT', 'R2'], False), PathReq(Protocols.BGP, ann.prefix, ['ATT', 'R2', 'R1'], False), PathReq(Protocols.BGP, ann.prefix, ['ATT', 'R2', 'R3'], False), PathReq(Protocols.BGP, ann.prefix, ['ATT', 'R2', 'R4'], False), ] # Set Iface for R2 to ATT iface = 'Fa0/0' g.add_iface('R2', iface, is_shutdown=False) g.set_iface_addr('R2', iface, VALUENOTSET) g.set_edge_iface('R2', 'ATT', iface) g.set_iface_description('R2', iface, '' "To {}" ''.format('ATT')) p = ConnectedSyn(reqs, g) p.synthesize()
def test_ecmp_full(self): fan_out = 4 network_graph = self.get_triangles(fan_out) source = 'source' sink = 'sink' p1 = [source, 'R1', sink] p2 = [source, 'R2', sink] path1 = PathReq(Protocols.OSPF, 'Google', p1, False) path2 = PathReq(Protocols.OSPF, 'Google', p2, False) ecmp_req = ECMPPathsReq(Protocols.OSPF, 'Google', [path1, path2], False) ospf = synet.synthesis.ospf.OSPFSyn(network_graph) ospf.add_req(ecmp_req) ret = ospf.solve() self.assertTrue(ret) ospf.update_network_graph() ecmp = [ tuple(p) for p in nx.all_shortest_paths(network_graph, source, sink, 'ospf_cost') ] ecmp = set(ecmp) self.assertEquals(ecmp, set([tuple(p1), tuple(p2)]))
def test_ebgp_linear(self): # Arrange N = 4 g = get_ebgp_linear_topo(N) net = "Prefix0" prefix_map = {net: ip_network(u'128.0.0.0/24')} addr = (prefix_map[net].hosts().next(), prefix_map[net].prefixlen) g.set_loopback_addr('R1', 'lo0', ip_interface("%s/%d" % addr)) for i in range(1, N + 1): first = 'R%d' % (i - 1) if i > 1 else None middle = 'R%d' % i last = 'R%d' % (i + 1) if i < N else None if last: #if middle == 'R1': # continue rline = RouteMapLine(None, None, VALUENOTSET, 10) rmap = RouteMap('Exp_%s' % last, [rline]) g.add_route_map(middle, rmap) g.add_bgp_export_route_map(middle, last, rmap.name) print "ADD EXPORT ROUTE MAP AT", middle, rmap.name if first: rmap = RouteMap('Imp_%s' % first, [rline]) g.add_route_map(middle, rmap) g.add_bgp_import_route_map(middle, first, rmap.name) print "ADD IMPORT ROUTE MAP AT", middle, rmap.name #nx.nx_pydot.write_dot(g, '/tmp/linear.xdot') req = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R2', 'R1'], strict=False) ctx = self.create_context([req], g) # Act propagation = EBGPPropagation([req], g, ctx) propagation.compute_dags() # Assert ebgp = propagation.ebgp_graphs['Prefix0'] ibgp = propagation.ibgp_graphs['Prefix0'] nx.nx_pydot.write_dot(ebgp, '/tmp/ebgp_linear.xdot') nx.nx_pydot.write_dot(ibgp, '/tmp/ibgp_linear.xdot') propagation.synthesize() solver = z3.Solver(ctx=ctx.z3_ctx) ret = ctx.check(solver) assert ret == z3.sat, solver.unsat_core() propagation.update_network_graph() gns3 = GNS3Topo(g, prefix_map) gns3.write_configs('./out-configs/ebgp-linear-%s' % N)
def test_one_extra(self): g = self.get_two_nodes() g.add_router('R3') g.add_router_edge('R1', 'R3') g.add_router_edge('R2', 'R3') g.add_router_edge('R3', 'R1') g.add_router_edge('R3', 'R2') reqs = [PathReq(Protocols.BGP, 'Prefix', ['R1', 'R2'], False)] # Set Iface for R1 to R3 iface1 = 'Fa0/0' addr1 = ip_interface(u"192.168.0.1/24") g.add_iface('R1', iface1, is_shutdown=False) g.set_iface_addr('R1', iface1, addr1) g.set_edge_iface('R1', 'R3', iface1) g.set_iface_description('R1', iface1, '' "To {}" ''.format('R3')) # Set Iface for R3 to R1 iface2 = 'Fa0/0' addr2 = ip_interface(u"192.168.0.2/24") g.add_iface('R3', iface2, is_shutdown=False) g.set_iface_addr('R3', iface2, addr2) g.set_edge_iface('R3', 'R1', iface2) g.set_iface_description('R3', iface2, '' "To {}" ''.format('R1')) # Set Iface for R2 to R3 iface3 = 'Fa0/0' addr3 = ip_interface(u"192.168.1.1/24") g.add_iface('R2', iface3, is_shutdown=True) g.set_iface_addr('R2', iface3, addr3) g.set_edge_iface('R2', 'R3', iface3) g.set_iface_description('R2', iface3, '' "To {}" ''.format('R3')) # Set Iface for R3 to R2 iface4 = 'Fa0/1' addr4 = ip_interface(u"192.168.2.2/24") g.add_iface('R3', iface4, is_shutdown=True) g.set_iface_addr('R3', iface4, addr4) g.set_edge_iface('R3', 'R2', iface4) g.set_iface_description('R3', iface4, '' "To {}" ''.format('R1')) p = ConnectedSyn(reqs, g) p.synthesize() self.assertTrue(g.has_edge('R1', 'R2')) self.assertTrue(g.has_edge('R1', 'R3')) self.assertTrue(g.has_edge('R2', 'R1')) self.assertFalse(g.has_edge('R2', 'R3')) self.assertTrue(g.has_edge('R3', 'R1')) self.assertFalse(g.has_edge('R3', 'R2'))
def generate_ordered_reqs(topo, reqsize, ordered, rand): """Generate reqsize of PathOrderReq each has ordered paths""" graph = nx.DiGraph() for src, dst in topo.edges(): graph.add_edge(src, dst) computed_paths = {} tmp_cost = 'tmp-cost' for src, dst in graph.edges(): graph[src][dst][tmp_cost] = rand.randint(1, sys.maxint) for src in graph.nodes(): for dst in graph.nodes(): if src == dst: continue if (src, dst) not in computed_paths: shortest = nx.shortest_path(graph, src, dst, weight=tmp_cost) computed_paths[(src, dst)] = [shortest] edges = list(graph.edges()) for src, dst in edges: cost = graph[src][dst][tmp_cost] graph.remove_edge(src, dst) if nx.has_path(graph, src, dst): shortest = nx.shortest_path(graph, src, dst, weight=tmp_cost) if shortest not in computed_paths[(src, dst)]: computed_paths[(src, dst)].append(shortest) graph.add_edge(src, dst, **{tmp_cost: cost}) valid = [] for (src, dst) in computed_paths: k = len(computed_paths[(src, dst)]) if k == ordered: valid.append(computed_paths[(src, dst)]) if len(valid) >= reqsize: sampled = random.sample(valid, reqsize) reqs = [] for plist in sampled: req = PathOrderReq(Protocols.OSPF, plist[0][-1], [ PathReq(Protocols.OSPF, path[-1], path, False) for path in plist ], False) reqs.append(req) return reqs else: print "Regenerating random ordered paths" return generate_ordered_reqs(topo, reqsize, ordered, rand)
def test_expand_single(self): # Arrange N = 4 g = get_ibgp_linear_topo(N=N) req = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R1'], strict=False) ctx = self.create_context([req], g) propagation = EBGPPropagation([req], g, ctx) # Act # Case 1 p1 = propagation.expand_as_path((100, ), ['R1']) print "P1", p1 expected = set([ ('R1', ), ('R1', 'R2'), ('R1', 'R3'), ('R1', 'R4'), ]) self.assertEquals(p1, expected)
def test_one_side_concrete(self): g = self.get_two_nodes() reqs = [PathReq(Protocols.BGP, 'Prefix', ['R1', 'R2'], False)] addr1 = ip_interface(u"192.168.0.1/24") # Set Iface for R1 to R2 iface = 'Fa0/0' g.add_iface('R1', iface, is_shutdown=False) g.set_iface_addr('R1', iface, addr1) g.set_edge_iface('R1', 'R2', iface) g.set_iface_description('R1', iface, '' "To {}" ''.format('R2')) # Set Iface for R2 to R1 iface = 'Fa0/0' g.add_iface('R2', iface, is_shutdown=False) g.set_iface_addr('R2', iface, VALUENOTSET) g.set_edge_iface('R2', 'R1', iface) g.set_iface_description('R2', iface, '' "To {}" ''.format('R1')) p = ConnectedSyn(reqs, g) p.synthesize() self.assertNotEqual(g.get_iface_addr('R2', iface), VALUENOTSET)
def test_ospf_enabled(self): # Arrange configs1 = NetCompleteConfigs(auto_enable_ospf_process=False) configs2 = NetCompleteConfigs(auto_enable_ospf_process=True) graph1 = get_ibgp_linear_topo(2) graph2 = get_ibgp_linear_topo(2) graph2.enable_ospf('R1', 100) # graph2.enable_ospf('R2', 100) graph2.add_ospf_network('R1', 'prefix', 0) reqs = [PathReq(Protocols.OSPF, 'prefix', ['R2', 'R1'], False)] # Act synthesizer1 = NetComplete(reqs=reqs, topo=graph1, external_announcements=[], netcompplete_config=configs1) synthesizer2 = NetComplete(reqs=reqs, topo=graph2, external_announcements=[], netcompplete_config=configs2) ret2 = synthesizer2.synthesize() # Assert self.assertRaises(SketchError, synthesizer1.synthesize) self.assertTrue(ret2)
def generate_paths(self, g, reqsize): """ Generate a random set of path requirements that are guaranteed to be satisfiable :param g: Network topology :param reqsize: the number of required path :return: list of PathReq """ routers = [n for n in g.local_routers_iter()] paths = [] # Generate the required paths for i in range(0, reqsize): src, dst = self.random.sample(routers, 2) assert src != dst path = random_requirement_path(g, src, dst, random_obj=self.random, tmp_weight_name='test-weight') paths.append(path) reqs = [] for path in paths: reqs.append(PathReq(Protocols.OSPF, path[-1], path, False)) return reqs
def test_wrong_subnets(self): g = self.get_two_nodes() reqs = [PathReq(Protocols.BGP, 'Prefix', ['R1', 'R2'], False)] addr1 = ip_interface(u"192.168.0.1/24") addr2 = ip_interface(u"192.168.0.2/25") # Set Iface for R1 to R2 iface = 'Fa0/0' g.add_iface('R1', iface, is_shutdown=False) g.set_iface_addr('R1', iface, addr1) g.set_edge_iface('R1', 'R2', iface) g.set_iface_description('R1', iface, '' "To {}" ''.format('R2')) # Set Iface for R2 to R1 iface = 'Fa0/0' g.add_iface('R2', iface, is_shutdown=False) g.set_iface_addr('R2', iface, addr2) g.set_edge_iface('R2', 'R1', iface) g.set_iface_description('R2', iface, '' "To {}" ''.format('R1')) p = ConnectedSyn(reqs, g) with self.assertRaises(NotValidSubnetsError): p.synthesize()
def test_kconnected_ebgp(self): # Arrange graph, (ann1, ann2, ann3) = self.get_cust_peer_linear_topo() r1, r2, provider1, provider2, customer = 'R1', 'R2', 'Provider1', 'Provider2', 'Customer' prefix1 = ann1.prefix graph.add_bgp_advertise(node=provider1, announcement=ann1, loopback='lo10') graph.add_bgp_advertise(node=provider2, announcement=ann2, loopback='lo10') rline = RouteMapLine(matches=[], actions=[], access=Access.deny, lineno=100) rmap_export = RouteMap(name='DenyExport', lines=[rline]) graph.add_route_map(r1, rmap_export) graph.add_bgp_export_route_map(r1, provider1, rmap_export.name) graph.add_bgp_export_route_map(r1, provider2, rmap_export.name) p1 = PathReq(Protocols.BGP, dst_net=prefix1, path=[customer, r2, r1, provider1], strict=False) p2 = PathReq(Protocols.BGP, dst_net=prefix1, path=[customer, r2, r1, provider1], strict=False) req1 = KConnectedPathsReq(Protocols.BGP, prefix1, [p2, p1], strict=False) netcomplete = NetComplete([req1], graph, [ann1, ann2]) next_hop_vals = { 'R1': 'Provider1-Fa0-0', 'R2': 'Provider1-Fa0-0', 'Customer': 'R2-Fa0-0', 'Provider1': '0.0.0.0', 'Provider2': '0.0.0.0', } provider1_as = [graph.get_bgp_asnum(provider1)] + ann1.as_path provider2_as = [graph.get_bgp_asnum(provider2)] + ann2.as_path r1_as = [graph.get_bgp_asnum(r1)] + provider1_as customer_as = [graph.get_bgp_asnum(customer)] + r1_as as_path_vals = { 'R1': 'as_path_{}'.format('_'.join([str(x) for x in r1_as])), 'R2': 'as_path_{}'.format('_'.join([str(x) for x in r1_as])), 'Customer': 'as_path_{}'.format('_'.join([str(x) for x in customer_as])), 'Provider1': 'as_path_{}'.format('_'.join([str(x) for x in provider1_as])), 'Provider2': 'as_path_{}'.format('_'.join([str(x) for x in provider2_as])), } as_path_len_vals = { 'R1': len(r1_as) - 1, 'R2': len(r1_as) - 1, 'Customer': len(customer_as) - 1, 'Provider1': len(provider1_as) - 1, 'Provider2': len(provider2_as) - 1, } # Act ret = netcomplete.synthesize() netcomplete.write_configs('out-configs/ibgp') # Assert self.assertTrue(ret) for node, attrs in netcomplete.bgp_synthesizer.ibgp_propagation.nodes(data=True): for ann in attrs['box'].selected_sham: self.assertTrue(ann.permitted.is_concrete) self.assertTrue(ann.permitted.get_value()) self.assertTrue(ann.prefix.is_concrete) self.assertEquals(desanitize_smt_name(ann.prefix.get_value()), prefix1) self.assertTrue(ann.next_hop.is_concrete) self.assertEquals(desanitize_smt_name(ann.next_hop.get_value()), next_hop_vals[node]) self.assertTrue(ann.as_path.is_concrete) self.assertEquals(ann.as_path.get_value(), as_path_vals[node]) self.assertTrue(ann.as_path_len.is_concrete) self.assertEquals(ann.as_path_len.get_value(), as_path_len_vals[node]) self.assertTrue(ann.med.is_concrete) self.assertEquals(ann.med.get_value(), DEFAULT_MED) self.assertTrue(ann.local_pref.is_concrete) self.assertEquals(ann.local_pref.get_value(), DEFAULT_LOCAL_PREF) for comm, val in ann.communities.iteritems(): self.assertTrue(val.is_concrete) self.assertFalse(val.get_value())
def get_1path_req(): p1 = ['R1', 'R2', 'R3', 'R4'] req = PathReq(Protocols.OSPF, p1[-1], p1, False) return [req]
def test_good_gadget(self): # Arrange g = get_griffin_graph() net = "Prefix0" prefix_map = {net: ip_network(u'128.0.0.0/24')} addr = (prefix_map[net].hosts().next(), prefix_map[net].prefixlen) g.set_loopback_addr('R1', 'lo0', ip_interface("%s/%d" % addr)) for src in g.routers_iter(): for dst in g.get_bgp_neighbors(src): if src == dst: continue # Export ip_list = IpPrefixList(name="L_%s-to_%s" % (src, dst), access=Access.permit, networks=[VALUENOTSET]) g.add_ip_prefix_list(src, ip_list) rline = RouteMapLine([MatchIpPrefixListList(ip_list)], [ActionSetLocalPref(VALUENOTSET)], VALUENOTSET, 10) rmap = RouteMap('Exp_%s' % dst, [rline]) g.add_route_map(src, rmap) g.add_bgp_export_route_map(src, dst, rmap.name) # Import #rline = RouteMapLine(None, [ActionSetLocalPref(VALUENOTSET)], VALUENOTSET, 10) #rmap = RouteMap('Imp_%s' % dst, [rline]) #g.add_route_map(src, rmap) #g.add_bgp_import_route_map(src, dst, rmap.name) rline1 = RouteMapLine([MatchAsPath(VALUENOTSET)], [ActionSetLocalPref(VALUENOTSET)], VALUENOTSET, 10) rline2 = RouteMapLine([MatchAsPath(VALUENOTSET)], [ActionSetLocalPref(VALUENOTSET)], VALUENOTSET, 20) rline3 = RouteMapLine([MatchAsPath(VALUENOTSET)], [ActionSetLocalPref(VALUENOTSET)], VALUENOTSET, 30) rmap = RouteMap('Imp_%s' % dst, [rline1, rline2, rline3]) g.add_route_map(src, rmap) g.add_bgp_import_route_map(src, dst, rmap.name) p0 = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R2', 'R4', 'R1'], strict=False) p1 = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R2', 'R1'], strict=False) r2_req = PathOrderReq(Protocols.BGP, dst_net='Prefix0', paths=[p0, p1], strict=False) p2 = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R3', 'R2', 'R1'], strict=False) p3 = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R3', 'R1'], strict=False) r3_req = PathOrderReq(Protocols.BGP, dst_net='Prefix0', paths=[p2, p3], strict=False) r4_req = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R4', 'R1'], strict=False) p6 = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R5', 'R4', 'R1'], strict=False) p7 = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R5', 'R3', 'R1'], strict=False) r5_req = PathOrderReq(Protocols.BGP, dst_net='Prefix0', paths=[p6, p7], strict=False) # Action reqs = [r2_req, r3_req, r4_req, r5_req] ctx = self.create_context(reqs, g) propagation = EBGPPropagation(reqs, g, ctx) unmatching_order = propagation.compute_dags() assert not unmatching_order propagation.synthesize() solver = z3.Solver(ctx=ctx.z3_ctx) ret = ctx.check(solver) assert ret == z3.sat, solver.unsat_core() print solver.model() propagation.update_network_graph() gns3 = GNS3Topo(g, prefix_map) gns3.write_configs('./out-configs/good_gadget')
def two_ebgp_nodes(export_path): """ Two routers connected via eBGP Very simple once router announces a single prefix and the other selects it """ graph = NetworkGraph() r1, r2 = 'R1', 'R2' graph.add_router(r1) graph.add_router(r2) graph.add_router_edge(r1, r2) graph.add_router_edge(r2, r1) # BGP configs graph.set_bgp_asnum(r1, 100) graph.set_bgp_asnum(r2, 200) # Establish peering # The actual network interfaces used for peering will be synthesized graph.add_bgp_neighbor(r1, r2, router_a_iface=VALUENOTSET, router_b_iface=VALUENOTSET) # Some internal network net = ip_network(u'128.0.0.0/24') prefix = '128_0_0_0' prefix_map = {prefix: net} lo0 = 'lo0' graph.set_loopback_addr( r1, lo0, ip_interface("%s/%d" % (net.hosts().next(), net.prefixlen))) # Announce the internal network graph.add_bgp_announces(r1, lo0) # The communities recognized by us comms = [Community("100:10"), Community("100:20")] # The announcement that will be propagated by R1 ann = Announcement(prefix=prefix, peer=r1, origin=BGP_ATTRS_ORIGIN.EBGP, next_hop='R1Hop', as_path=[100], as_path_len=1, local_pref=100, med=100, communities=dict([(c, False) for c in comms]), permitted=True) path = PathReq(Protocols.BGP, prefix, ['R2', 'R1'], False) reqs = [path] # Get SMT Context ctx = create_context(reqs, graph, [ann]) propagation = EBGPPropagation(reqs, graph, ctx) propagation.compute_dags() propagation.synthesize() # Synthesize all the interfaces and link configurations connecte_syn = ConnectedSyn([], graph, full=True) connecte_syn.synthesize() # SMT Solving solver = z3.Solver(ctx=ctx.z3_ctx) assert ctx.check(solver) == z3.sat, solver.unsat_core() # Update graph with the concrete values after solver propagation.update_network_graph() gns3 = GNS3Topo(graph=graph, prefix_map=prefix_map) gns3.write_configs('%s/ibgp-simple' % export_path)
def test_double_import(): """Unit test of Route maps""" graph = NetworkGraph() r1, r2 = 'R1', 'R2' graph.add_router(r1) graph.add_router(r2) graph.add_router_edge(r1, r2) graph.add_router_edge(r2, r1) # BGP configs graph.set_bgp_asnum(r1, 100) graph.set_bgp_asnum(r2, 200) # Establish peering # The actual network interfaces used for peering will be synthesized graph.add_bgp_neighbor(r1, r2, router_a_iface=VALUENOTSET, router_b_iface=VALUENOTSET) # Some internal network net = ip_network(u'128.0.0.0/24') prefix = '128_0_0_0' prefix_map = {prefix: net} lo0 = 'lo0' graph.set_loopback_addr( r1, lo0, ip_interface("%s/%d" % (net.hosts().next(), net.prefixlen))) # Announce the internal network graph.add_bgp_announces(r1, lo0) # The communities recognized by us comms = [Community("100:10"), Community("100:20")] # The announcement that will be propagated by R1 ann = Announcement(prefix=prefix, peer=r1, origin=BGP_ATTRS_ORIGIN.EBGP, next_hop='R1Hop', as_path=[100], as_path_len=1, local_pref=100, med=100, communities=dict([(c, False) for c in comms]), permitted=True) path = PathReq(Protocols.BGP, prefix, ['R2', 'R1'], False) reqs = [path] ctx = create_context(reqs, graph, [ann], create_as_paths=True) from synet.utils.fnfree_policy import SMTRouteMap rline1 = RouteMapLine(matches=None, actions=None, access=VALUENOTSET, lineno=10) deny_line1 = RouteMapLine(matches=None, actions=None, access=Access.deny, lineno=100) rmap1 = RouteMap(name='Rmap1', lines=[rline1, deny_line1]) rline2 = RouteMapLine(matches=None, actions=None, access=VALUENOTSET, lineno=10) deny_line2 = RouteMapLine(matches=None, actions=None, access=Access.deny, lineno=100) rmap2 = RouteMap(name='Rmap1', lines=[rline2, deny_line2]) sym = get_sym([ann], ctx) smt1 = SMTRouteMap(rmap1, sym, ctx) smt2 = SMTRouteMap(rmap2, smt1.announcements, ctx) print "Original permitted", sym.announcements[0].permitted print "SMT 1 permitted", smt1.announcements[0].permitted print "SMT 2 permitted", smt2.announcements[0].permitted ctx.register_constraint(smt1.announcements[0].permitted.var == True) ctx.register_constraint(smt2.announcements[0].permitted.var == False) solver = z3.Solver(ctx=ctx.z3_ctx) ret = ctx.check(solver) #print solver.to_smt2() assert ret == z3.sat, solver.unsat_core() #print solver.model() print "Original permitted", sym.announcements[0].permitted print "SMT 1 permitted", smt1.announcements[0].permitted print "SMT 2 permitted", smt2.announcements[0].permitted
def linear_ebgp(N, export_path): """ Routers connected in a line and each eBGP pair with it's direct neighbors """ # Topology g = get_ebgp_linear_topo(N) # Announce locally prefix = "Prefix0" net = ip_network(u'128.0.0.0/24') prefix_map = {prefix: net} g.set_loopback_addr( 'R1', 'lo0', ip_interface("%s/%d" % (net.hosts().next(), net.prefixlen))) g.add_bgp_announces('R1', 'lo0') # Announcement comms = [Community("100:10"), Community("100:20")] cs = dict([(c, False) for c in comms]) # The announcement that will be propagated by R1 ann = get_announcement(prefix=prefix, peer='R1', comms=cs) # Set up route maps for i in range(1, N + 1): first = 'R%d' % (i - 1) if i > 1 else None middle = 'R%d' % i last = 'R%d' % (i + 1) if i < N else None if last: matches = [MatchAsPath(VALUENOTSET)] #matches = None rline = RouteMapLine(matches, None, VALUENOTSET, 10) deny_line = RouteMapLine(None, None, Access.deny, 100) rmap = RouteMap('Exp_%s' % last, [rline, deny_line]) g.add_route_map(middle, rmap) g.add_bgp_export_route_map(middle, last, rmap.name) if first: matches = [MatchAsPath(VALUENOTSET)] #matches = None rline = RouteMapLine(matches, None, VALUENOTSET, 10) deny_line = RouteMapLine(None, None, Access.deny, 100) rmap = RouteMap('Imp_%s' % first, [rline, deny_line]) g.add_route_map(middle, rmap) g.add_bgp_import_route_map(middle, first, rmap.name) # nx.nx_pydot.write_dot(g, '/tmp/linear.xdot') req = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R2', 'R1'], strict=False) ctx = create_context([req], g, [ann]) propagation = EBGPPropagation([req], g, ctx) propagation.compute_dags() propagation.synthesize() solver = z3.Solver(ctx=ctx.z3_ctx) ret = ctx.check(solver) assert ret == z3.sat, solver.unsat_core() propagation.update_network_graph() gns3 = GNS3Topo(g, prefix_map) gns3.write_configs('%s/linear-ebgp-%d' % (export_path, N))
def two_ebgp_nodes_route_map(export_path): """ Two routers connected via eBGP with route maps Very simple one router announces a single prefix and the other selects it """ graph = NetworkGraph() r1, r2 = 'R1', 'R2' graph.add_router(r1) graph.add_router(r2) graph.add_router_edge(r1, r2) graph.add_router_edge(r2, r1) # BGP configs graph.set_bgp_asnum(r1, 100) graph.set_bgp_asnum(r2, 200) # Establish peering # The actual network interfaces used for peering will be synthesized graph.add_bgp_neighbor(r1, r2, router_a_iface=VALUENOTSET, router_b_iface=VALUENOTSET) # Some internal network net = ip_network(u'128.0.0.0/24') prefix = '128_0_0_0' prefix_map = {prefix: net} lo0 = 'lo0' graph.set_loopback_addr( r1, lo0, ip_interface("%s/%d" % (net.hosts().next(), net.prefixlen))) # Announce the internal network graph.add_bgp_announces(r1, lo0) # The communities recognized by us comms = [Community("100:10"), Community("100:20")] # The announcement that will be propagated by R1 ann = Announcement(prefix=prefix, peer=r1, origin=BGP_ATTRS_ORIGIN.EBGP, next_hop='R1Hop', as_path=[100], as_path_len=1, local_pref=100, med=100, communities=dict([(c, False) for c in comms]), permitted=True) path = PathReq(Protocols.BGP, prefix, ['R2', 'R1'], False) reqs = [path] # Create a route map to export from R1 to R2 iplist = IpPrefixList(name='IpList1', access=Access.permit, networks=[prefix]) graph.add_ip_prefix_list(r1, iplist) ip_match = MatchIpPrefixListList(iplist) set_community = ActionSetCommunity([comms[0]]) rline = RouteMapLine(matches=[ip_match], actions=[set_community], access=Access.permit, lineno=10) export_map = RouteMap(name="Export_R1_to_R2", lines=[rline]) # Register the route map graph.add_route_map(r1, export_map) # Set the route map as an export route map graph.add_bgp_export_route_map(r1, r2, export_map.name) # Create a route map to import at R2 to from R1 comm_list = CommunityList(list_id=1, access=Access.permit, communities=[comms[0]]) graph.add_bgp_community_list(r2, comm_list) comm_match = MatchCommunitiesList(comm_list) set_local_pref = ActionSetLocalPref(200) rline = RouteMapLine(matches=[MatchNextHop(VALUENOTSET)], actions=[set_local_pref], access=Access.permit, lineno=10) import_map = RouteMap(name="Import_R2_from_R1", lines=[rline]) # Register the route map graph.add_route_map(r2, import_map) # Set the route map as an import route map graph.add_bgp_import_route_map(r2, r1, import_map.name) # Get SMT Context ctx = create_context(reqs, graph, [ann]) propagation = EBGPPropagation(reqs, graph, ctx) propagation.compute_dags() propagation.synthesize() # Synthesize all the interfaces and link configurations connecte_syn = ConnectedSyn([], graph, full=True) connecte_syn.synthesize() # SMT Solving solver = z3.Solver(ctx=ctx.z3_ctx) assert ctx.check(solver) == z3.sat, solver.unsat_core() # Update graph with the concrete values after solver propagation.update_network_graph() gns3 = GNS3Topo(graph=graph, prefix_map=prefix_map) gns3.write_configs('%s/ebgp-route-map' % export_path) graph.write_graphml('%s/ebgp-route-map/topology.graphml' % export_path)
def test_bad_gadget(self): # Arrange g = get_griffin_graph() p0 = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R2', 'R4', 'R1'], strict=False) p1 = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R2', 'R1'], strict=False) r2_req = PathOrderReq(Protocols.BGP, dst_net='Prefix0', paths=[p0, p1], strict=False) p2 = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R3', 'R2', 'R1'], strict=False) p3 = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R3', 'R1'], strict=False) r3_req = PathOrderReq(Protocols.BGP, dst_net='Prefix0', paths=[p2, p3], strict=False) p4 = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R4', 'R5', 'R3', 'R1'], strict=False) p5 = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R4', 'R1'], strict=False) r4_req = PathOrderReq(Protocols.BGP, dst_net='Prefix0', paths=[p4, p5], strict=False) p6 = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R5', 'R3', 'R1'], strict=False) p7 = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R5', 'R4', 'R1'], strict=False) r5_req = PathOrderReq(Protocols.BGP, dst_net='Prefix0', paths=[p6, p7], strict=False) reqs = [r2_req, r3_req, r4_req, r5_req] # Action ctx = self.create_context(reqs, g) propagation = EBGPPropagation(reqs, g, ctx) unmatching_order = propagation.compute_dags() dag = propagation.ebgp_graphs['Prefix0'] # Assert assert unmatching_order
def test_good_gadget_ibgp(self): # Arrange g = get_griffin_ibgp_graph() for src in g.routers_iter(): for dst in g.get_bgp_neighbors(src): if src == dst: continue # Export matches1 = [MatchAsPath(VALUENOTSET)] matches2 = [MatchAsPath(VALUENOTSET)] rline1 = RouteMapLine(matches1, [ActionSetLocalPref(VALUENOTSET)], VALUENOTSET, 10) rline2 = RouteMapLine(matches2, [ActionSetLocalPref(VALUENOTSET)], VALUENOTSET, 20) rmap = RouteMap('Exp_%s' % dst, [rline1, rline2]) g.add_route_map(src, rmap) g.add_bgp_export_route_map(src, dst, rmap.name) # Import matches1 = [MatchAsPath(VALUENOTSET)] matches2 = [MatchAsPath(VALUENOTSET)] rline1 = RouteMapLine(matches1, [ActionSetLocalPref(VALUENOTSET)], VALUENOTSET, 10) rline2 = RouteMapLine(matches2, [ActionSetLocalPref(VALUENOTSET)], VALUENOTSET, 20) rmap = RouteMap('Imp_%s' % dst, [rline1, rline2]) g.add_route_map(src, rmap) g.add_bgp_import_route_map(src, dst, rmap.name) p0 = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R2_2', 'R2_0', 'R4', 'R1'], strict=False) p1 = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R2_2', 'R1'], strict=False) r2_req = PathOrderReq(Protocols.BGP, dst_net='Prefix0', paths=[p0, p1], strict=False) p2 = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R3', 'R2_3', 'R1'], strict=False) p3 = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R3', 'R1'], strict=False) r3_req = PathOrderReq(Protocols.BGP, dst_net='Prefix0', paths=[p2, p3], strict=False) r4_req = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R4', 'R1'], strict=False) p6 = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R5_3', 'R5_2', 'R5_0', 'R4', 'R1'], strict=False) p7 = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R5_3', 'R5_1', 'R3', 'R1'], strict=False) r5_req = PathOrderReq(Protocols.BGP, dst_net='Prefix0', paths=[p6, p7], strict=False) reqs = [r2_req, r3_req, r4_req, r5_req] ctx = self.create_context(reqs, g) # Act propagation = EBGPPropagation(reqs, g, ctx) unmatching_order = propagation.compute_dags() ebgp = propagation.ebgp_graphs['Prefix0'] ibgp = propagation.ibgp_graphs['Prefix0'] #nx.nx_pydot.write_dot(ibgp, '/tmp/ibgp_good.xdot') #nx.nx_pydot.write_dot(ebgp, '/tmp/ebgp_good.xdot') # Assert assert not unmatching_order # Assert eBGP propagation self.assertEqual(ebgp.node[100]['order'], [set([(100, )])]) self.assertEqual( ebgp.node[200]['order'], [set([(100, 400, 200)]), set([(100, 200)])]) self.assertEqual( ebgp.node[300]['order'], [set([(100, 200, 300)]), set([(100, 300)])]) self.assertEqual(ebgp.node[400]['order'], [set([(100, 400)])]) self.assertEqual(ebgp.node[500]['order'], [set([(100, 400, 500)]), set([(100, 300, 500)])]) # Assert iBGP propagation self.assertEqual(ibgp.node['R1']['order'], [set([('R1', )])]) self.assertEqual(ibgp.node['R2_0']['order'], [set([('R1', 'R4', 'R2_0')])]) self.assertEqual(ibgp.node['R2_1']['order'], []) self.assertEqual( ibgp.node['R2_2']['order'], [set([('R1', 'R4', 'R2_0', 'R2_2')]), set([('R1', 'R2_2')])]) self.assertEqual(ibgp.node['R2_3']['order'], [set([('R1', 'R2_3')])]) self.assertEqual(ibgp.node['R3']['order'], [set([('R1', 'R2_3', 'R3')]), set([('R1', 'R3')])]) self.assertEqual(ibgp.node['R4']['order'], [set([('R1', 'R4')])]) self.assertEqual(ibgp.node['R5_0']['order'], [set([('R1', 'R4', 'R5_0')])]) self.assertEqual(ibgp.node['R5_1']['order'], [set([('R1', 'R3', 'R5_1')])]) self.assertEqual(ibgp.node['R5_2']['order'], [set([('R1', 'R4', 'R5_0', 'R5_2')])]) self.assertEqual(ibgp.node['R5_3']['order'], [ set([('R1', 'R4', 'R5_0', 'R5_2', 'R5_3')]), set([('R1', 'R3', 'R5_1', 'R5_3')]) ]) propagation.synthesize()
def test_ibgp_linear(self): # Arrange N = 4 g = get_ibgp_linear_topo(N=N) net = "Prefix0" prefix_map = {net: ip_network(u'128.0.0.0/24')} ifaddr = ip_interface( "%s/%d" % (prefix_map[net].hosts().next(), prefix_map[net].prefixlen)) g.set_loopback_addr('R1', 'lo0', ifaddr) for i, node in enumerate(sorted(g.routers_iter())): g.set_loopback_addr('R%d' % (i + 1), 'lo100', ip_interface(u'192.168.0.%d/32' % i)) #for i in range(1, N): # r1 = 'R1' # r2 = "R%d" % (i + 1) # g.set_bgp_neighbor_iface(r1, r2, 'lo100') for i in range(2, N + 1): r1 = 'R1' node = 'R%s' % i rline = RouteMapLine(None, None, VALUENOTSET, 10) #rmap = RouteMap('Exp_%s' % node, [rline]) #g.add_route_map(r1, rmap) #g.add_bgp_export_route_map('R1', 'R%d' % i, rmap.name) rmap = RouteMap('Imp_%s' % r1, [rline]) g.add_route_map(node, rmap) g.add_bgp_import_route_map(node, r1, rmap.name) #nx.nx_pydot.write_dot(g, '/tmp/linear.dot') req1 = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R3', 'R1'], strict=False) req2 = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R2', 'R1'], strict=False) reqs = [req1, req2] ctx = self.create_context(reqs, g) # Act propagation = EBGPPropagation(reqs, g, ctx) propagation.compute_dags() # Assert #ebgp = propagation.ebgp_graphs['Prefix0'] #ibgp = propagation.ibgp_graphs['Prefix0'] #nx.nx_pydot.write_dot(ebgp, '/tmp/ebgp_linear.dot') #nx.nx_pydot.write_dot(ibgp, '/tmp/ibgp_linear.dot') propagation.synthesize() solver = z3.Solver(ctx=ctx.z3_ctx) ret = ctx.check(solver) assert ret == z3.sat, solver.unsat_core() propagation.update_network_graph() for router in g.routers_iter(): g.enable_ospf(router, 100) for iface in g.get_ifaces(router): g.add_ospf_network(router, iface, 0) if router != 'R1': g.add_ospf_network( router, g.get_loopback_addr(router, 'lo100').network, 0) g.add_ospf_network('R1', g.get_loopback_addr('R1', 'lo0').network, 0) gns3 = GNS3Topo(g, prefix_map) gns3.write_configs('./out-configs/ibgp-linear-%d' % N)
def test_expand(self): # Arrange g = get_griffin_ibgp_graph() p0 = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R2_2', 'R2_0', 'R4', 'R1'], strict=False) p1 = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R2_2', 'R1'], strict=False) r2_req = PathOrderReq(Protocols.BGP, dst_net='Prefix0', paths=[p0, p1], strict=False) p2 = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R3', 'R2_3', 'R1'], strict=False) p3 = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R3', 'R1'], strict=False) r3_req = PathOrderReq(Protocols.BGP, dst_net='Prefix0', paths=[p2, p3], strict=False) r4_req = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R4', 'R1'], strict=False) p6 = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R5_3', 'R5_2', 'R5_0', 'R4', 'R1'], strict=False) p7 = PathReq(Protocols.BGP, dst_net='Prefix0', path=['R5_3', 'R5_1', 'R3', 'R1'], strict=False) r5_req = PathOrderReq(Protocols.BGP, dst_net='Prefix0', paths=[p6, p7], strict=False) reqs = [r2_req, r3_req, r4_req, r5_req] ctx = self.create_context(reqs, g) propagation = EBGPPropagation(reqs, g, ctx) # Act # Case 1: Direct eBGP p1 = propagation.expand_as_path((100, ), ['R1']) p2 = propagation.expand_as_path((100, 400), ['R1']) self.assertEquals(p1, set([ ('R1', ), ])) self.assertEquals(p2, set([('R1', 'R4')])) # Case 2: Direct eBGP->iBGP p3 = propagation.expand_as_path((100, 200), ['R1']) paths_to_r2 = set([ ('R1', 'R2_2'), ('R1', 'R2_2', 'R2_0'), ('R1', 'R2_2', 'R2_1'), ('R1', 'R2_2', 'R2_3'), ('R1', 'R2_3'), ('R1', 'R2_3', 'R2_0'), ('R1', 'R2_3', 'R2_1'), ('R1', 'R2_3', 'R2_2'), ]) self.assertEquals(p3, paths_to_r2) ## Case 3: eBGP-> iBGP -> eBGP p4 = propagation.expand_as_path((100, 200, 300), ['R1']) paths_to_r3 = set([ ('R1', 'R2_2', 'R2_1', 'R3'), ('R1', 'R2_2', 'R2_3', 'R3'), ('R1', 'R2_3', 'R3'), ('R1', 'R2_3', 'R2_1', 'R3'), ]) self.assertEquals(p4, paths_to_r3)