def run(): os.system('mn -c') c0 = RemoteController('c1', '127.0.0.1') ovs13 = partial(OVSKernelSwitch, protocols="OpenFlow13") topo = FatTree(k) net = Mininet(topo=topo, link=TCLink, controller=None, switch=ovs13, autoSetMacs=True) net.addController(c0) net.start() print ('==== Total server(s) = %s' % h) print ('==== Total switches(s) = %s' % s) print ('==== Initiating topology ping test...') host = [] for i in range(h): host.append(net.get('h%s' % (i + 1))) # Make directory for result directory = '/home/DCResult/FatTree' + str(s) os.system('mkdir -p ' + directory + '/latency') os.system('mkdir -p ' + directory + '/convergence') os.system('mkdir -p ' + directory + '/throughput') # Homemade pingall print '==== Pingall from h1 to all hosts to initiate paths...' print '==== Pingall will be initiate in 1 second' time.sleep(1) for i in range(1, len(host)): # print "h1 pinging to %s" % host[i] host[0].cmd('ping %s -c 1 &' % host[i].IP()) print('Wait 40 sec for test to complete') print '==== Latency test' for i in range(1, len(host)): host[i].cmd('ping 10.0.0.1 -c 10 > ' + directory + '/latency/h%s.txt &' % (i + 1)) time.sleep(10) print '==== Throughput test' # Using Nping as background traffic ips = '' for i in range(2, len(host) - 1): ips += host[i].IP() + ' ' host[0].cmd('iperf -s &') host[1].cmd('nping -c 10 --tcp ' + ips + '&') host[-1].cmd('iperf -c 10.0.0.1 -t 10 -i 1 > ' + directory + '/throughput/throughput.txt &') time.sleep(10) print '==== Convergence test' print sw_list host[-1].cmd('ping 10.0.0.1 -c 20 -D > ' + directory + '/convergence/convergence.txt &') time.sleep(3) for i in range(len(sw_list)): print 'cut off ', EdgeSwitchList[0], AggSwitchList[i] net.configLinkStatus(EdgeSwitchList[0], AggSwitchList[i], 'down') time.sleep(0.5) print 'turn up ', EdgeSwitchList[0], AggSwitchList[0] net.configLinkStatus(EdgeSwitchList[0], AggSwitchList[0], 'up') time.sleep(17) os.system('chmod -R 777 /home/DCResult') #CLI(net) net.stop()
def emptyNet(): "Create an empty network and add nodes to it." #net = Mininet( controller=Controller ) net = Mininet( controller=RemoteController ) info( '*** Adding controller\n' ) net.addController( 'c0' ) info( '*** Adding hosts\n' ) h1 = net.addHost( 'h1', ip='10.0.0.1' ) h2 = net.addHost( 'h2', ip='10.0.0.2' ) info( '*** Adding switch\n' ) s3 = net.addSwitch( 's3' ) s4 = net.addSwitch( 's4' ) s5 = net.addSwitch( 's5' ) s6 = net.addSwitch( 's6' ) info( '*** Creating links\n' ) net.addLink( h1, s3 ) net.addLink( s3, s4 ) net.addLink( s3, s5 ) net.addLink( s4, s6 ) net.addLink( s5, s6 ) net.addLink( h2, s6 ) print "Stopping of " + 's5' net.configLinkStatus('s5', 's3', 'down') #net.configLinkStatus('s5', 's6', 'down') #net.hosts[0].cmd("ping -w 15 10.0.0.2") #net.pingAll() return net
def IEEE30BusNetwork(): """Kickoff the network""" topo = IEEE30BusTopology() net = Mininet(topo=topo, host=Host, switch=OVSKernelSwitch, \ controller=RemoteController, autoStaticArp=True, waitConnected=True) net.start() changed_sw = ['s5', 's8', 's13', 's18', 's20'] if args.short: # test connectivity info('****** Quick test for connectivity between PMU and PDC ******\n') info('*** PING Test from PMU15 PMU23 and PMU25 ***\n') # PMUPingPDC(net, 'PMU15', 'PDC8', 1) # PMUPingPDC(net, 'PMU9', 'PDC5', 1) PMUPingAllPDC(net, 'PMU15', timeout=1) PMUPingAllPDC(net, 'PMU23', timeout=1) PMUPingAllPDC(net, 'PMU25', timeout=1) else: AllPMUPingAllPDC(net, 1) info('\n****** Show rules on critical switches ******\n') for sw in changed_sw: DumpRule(net, sw) # remove 2 pdcs by tear down link # info("\n****** Tear down link between PDC8 and Switch 8 ******\n") # info("****** Tear down link between PDC13 and Switch 13 ******\n") net.configLinkStatus('PDC8', 's8', 'down') net.configLinkStatus('PDC13', 's13', 'down') # old pdc should be unreachable info('\n****** PDC8 is isolated after being compromised ******\n') info('*** PING Test from PMU15 PMU23 ***\n') # PMUPingPDC(net, 'PMU15', 'PDC8', 1) PMUPingAllPDC(net, 'PMU15', 1) PMUPingAllPDC(net, 'PMU23', 1) info('\n****** PDC13 is isolated after being compromised ******\n') info('*** PING Test from PMU25 ***\n') PMUPingAllPDC(net, 'PMU25', 1) raw_input("\n****** Self-heal controller installed new rules to reconnect PMUs ******\n") # test newly installed rules info('*** Test rules installed to connect PMU15 to PDC5 ***\n') # PMUPingPDC(net, 'PMU15', 'PDC5', 1) PMUPingAllPDC(net, 'PMU15', timeout=1) info('*** Test rules installed to connect PMU23 to PDC5 ***\n') PMUPingAllPDC(net, 'PMU23', timeout=1) info('*** Test rules installed to connect PMU25 to PDC5 ***\n') PMUPingAllPDC(net, 'PMU25', timeout=1) info('\n****** Show rules on critical switches ******\n') for sw in changed_sw: DumpRule(net, sw) # if not args.short: # AllPMUPingAllPDC(net, 1) CLI(net) net.stop()
def emptyNet(): net = Mininet(controller=RemoteController, switch=OVSKernelSwitch) h1 = net.addHost('h1', ip='10.0.0.1') h2 = net.addHost('h2', ip='10.0.0.2') h3 = net.addHost('h3', ip='10.0.0.3') h4 = net.addHost('h4', ip='10.0.0.4') h5 = net.addHost('h5', ip='10.0.0.5') s1 = net.addSwitch('s1') s2 = net.addSwitch('s2') s3 = net.addSwitch('s3') s4 = net.addSwitch('s4') s1.linkTo(h1) s1.linkTo(h2) s1.linkTo(s2) s2.linkTo(h3) s2.linkTo(h4) s2.linkTo(s3) s3.linkTo(h5) s4.linkTo(s1) net.build() net.start() c1 = net.addController('c1', controller=RemoteController, ip="127.0.0.1", port=6653) c2 = net.addController('c2', controller=RemoteController, ip="127.0.0.1", port=6657) c3 = net.addController('c3', controller=RemoteController, ip="127.0.0.1", port=6658) s1.start([c1]) s2.start([c2]) s3.start([c2]) s4.start([c3]) for i in range(1, 500): time.sleep(randint(3000, 6000) / 1000) args = "s2 s3 up".split() net.configLinkStatus(*args) time.sleep(randint(3000, 6000) / 1000) args = "s2 s3 down".split() net.configLinkStatus(*args) CLI(net) net.stop()
def create_topology(number_of_switches, number_of_hosts): """ Create a topology with n switches connected to m hosts. """ topology = Ring(number_of_switches, number_of_hosts) net = Mininet(topology) net.start() # Down a link in order to fix the circular problem net.configLinkStatus('s1', 's2', 'down') net.pingAll() # Test if all hosts can communicate net.stop()
def start_cli(): topo = create_topo() net = Mininet(topo=topo) net.start() dumpNodeConnections(net.hosts) s1, s2, h1, h2 = net.get('s1', 's2', 'h1', 'h2') net.pingAll() net.configLinkStatus('s1', 's2', 'down') net.pingAll() h1.cmd('ethtool --offload h1-eth0 rx off tx off') h2.cmd('ethtool --offload h2-eth0 rx off tx off') h2.cmd('python3 modbus_server.py &') h1.cmd('tcpdump -i h1-eth0 -w h1.pcap &') h2.cmd('tcpdump -i h2-eth0 -w h2.pcap &') CLI(net) net.stop()
def BandwidthTest(): topo = CustomTopologyInitializer("../../test_results/grid/grid1.p") net = Mininet(topo=topo, controller=RemoteController, switch=OVSKernelSwitch, autoSetMacs=True, autoStaticArp=True) net.start() waitingTime = 20 print "*** Waiting for ", waitingTime, " seconds ***" time.sleep(waitingTime) net.pingAll() iperfBetweenHosts(net, topo.myHosts) net.configLinkStatus("s18", "s20", "down") net.pingAll() iperfBetweenHosts(net, topo.myHosts) net.stop()
def run(): topo = MyTopo() net = Mininet(topo=topo, controller=None, link=TCLink) net.addController('c0', controller=RemoteController, ip='127.0.0.1', port=6633) print("=== Add root ===") root = Node('root', inNamespace=False) intf = net.addLink(root, net['s1']).intf1 root.setIP('192.168.44.100/32', intf=intf) net.start() s8 = net.getNodeByName('s8') h9 = net.getNodeByName('h9') net.configLinkStatus(s8, h9, 'down') print("=== Run apache server ===") portal = net.getNodeByName('portal') portal.cmdPrint('/etc/init.d/apache2 restart') print("=== Run DHCP server ===") dhcp = net.getNodeByName('dhcp') # dhcp.cmdPrint('service isc-dhcp-server restart &') dhcp.cmdPrint( '/usr/sbin/dhcpd -q 4 -pf /run/dhcp-server-dhcpd.pid -cf ./dhcpd.conf %s' % dhcp.defaultIntf()) print("=== Request IP ===") for host in net.hosts: if str(host) != 'portal' and str(host) != 'dhcp' and str( host) != 'web' and str(host) != 'h9': host.cmdPrint('dhclient ' + host.defaultIntf().name) print("=== Open simple HTTP server ===") web = net.getNodeByName('web') web.cmdPrint('python -m SimpleHTTPServer 80 &') print("=== Set route ===") for route in ['192.168.44.0/24']: root.cmd('route add -net ' + route + ' dev ' + str(intf)) CLI(net) net.stop()
def runPingTest(delay, bw): c = RemoteController('c', '172.16.197.137', 6653) net = Mininet(topo=MyTopo(delay, bw), link=TCLink, controller=None) net.addController(c) net.start() print "running pingAll() command" sleep(5) net.pingAll() print "httping from h1 to h2" h1 = net.get('h1') h2 = net.get('h2') fileOperation("Starting tests", "") i = 15 while(i > 0): print "starting/restating httpserver on host h2" h2.cmd('python -m SimpleHTTPServer 80 &') sleep(2) fileOperation("Test number ", i) print "printing to the output /tmp/ping32.txt" h1.cmd('httping %s >> /tmp/ping32.txt &' %h2.IP()) #result = h1.cmd('httping %s' %h2.IP()) #fileOperation(result, "") sleep(5) fileOperation("Link down", "") print "Link going down" net.configLinkStatus('s9','s13','down') #print >>f, "after link down" fileOperation("After link down", "") sleep(20) print "Link going up" fileOperation("After link up", "") net.configLinkStatus('s9','s13','up') h1.cmd('kill %httping') i = i - 1 sleep(5) print("end of script") net.stop()
def myTest(): c = RemoteController('c', '192.168.56.102', 6633) topo = MyTopo() net = Mininet(topo, controller=None) net.addController(c) net.start() print "Testing connectivity" sleep(10) net.pingAll() sleep(10) net.pingAll() print "Running test" h1, h2 = net.get('h1', 'h2') h2.cmd('python -m SimpleHTTPServer 80 &') sleep(2) h1.cmd('tcpping 10.0.0.2 > /tmp/output.txt &') sleep(15) net.configLinkStatus('s5', 's7', 'down') sleep(15) net.configLinkStatus('s8', 's10', 'down') sleep(15) h1.cmd('kill %tcpping') h2.cmd('kill %python') net.stop()
class MininetWrapper(object): def __init__(self): self.mininet_client = None self.topology = [] self.delay = None def set_delay(self, delay): delay = str(int(delay)) + 'ms' self.delay = delay def run_mininet(self, topology_string): """ Create and run multiple link network """ self.topo_client = Topo() hosts = set() switches = set() relations = re.sub(r's', '', topology_string) relations = [i.split(':') for i in relations.split(',') if 'h' not in i] relations = [[int(y) - 1 for y in x] for x in relations] builtin.log(relations, 'DEBUG') verticles_count = len(set(list(itertools.chain(*relations)))) builtin.log(self.topology, 'DEBUG') for i in xrange(verticles_count): temp = [] for j in xrange(verticles_count): temp.append(-1) self.topology.append(temp[:]) builtin.log(self.topology, 'DEBUG') for i in relations: self.topology[i[0]][i[1]] = 1 self.topology[i[1]][i[0]] = 1 builtin.log(self.topology, 'DEBUG') for v1, v2 in [x.split(':') for x in str(topology_string).split(',')]: if 'h' in v1 and v1 not in hosts: self.topo_client.addHost(v1) hosts.add(v1) if 'h' in v2 and v2 not in hosts: self.topo_client.addHost(v2) hosts.add(v2) if 's' in v1 and v1 not in switches: self.topo_client.addSwitch(v1) switches.add(v1) if 's' in v2 and v2 not in switches: self.topo_client.addSwitch(v2) switches.add(v2) if self.delay: self.topo_client.addLink(v1, v2, delay=self.delay) else: self.topo_client.addLink(v1, v2) self.mininet_client = Mininet(switch=user_switch, controller=remote_controller, topo=self.topo_client, link=TCLink) self.mininet_client.start() builtin.log('Links info:') for link in self.topo_client.links(withKeys=True, withInfo=True): builtin.log(link) # self.mininet_client.waitConnected(timeout=20) sleep(20) def stop_mininet(self): if self.mininet_client is not None: self.mininet_client.stop() if self.topology: self.topology = [] self.delay = None cleanup() sleep(20) def kill_link(self, host1, host2): host1, host2 = str(host1), str(host2) self.mininet_client.configLinkStatus(host1, host2, 'down') if 'h' not in host1 and 'h' not in host2: num_1 = int(host1[1:]) - 1 num_2 = int(host2[1:]) - 1 self.topology[num_1][num_2] = -1 self.topology[num_2][num_1] = -1 builtin.log(self.topology, 'DEBUG') builtin.log('Down link {0} - {1}'.format(host1, host2), 'DEBUG') def check_link(self, host1, host2): switch = self.mininet_client.getNodeByName(host1) connections = switch.connectionsTo(host2) if connections: return True else: return False def up_link(self, host1, host2): host1, host2 = str(host1), str(host2) self.mininet_client.configLinkStatus(host1, host2, 'up') if 'h' not in host1 and 'h' not in host2: num_1 = int(host1[1:]) - 1 num_2 = int(host2[1:]) - 1 self.topology[num_1][num_2] = 1 self.topology[num_2][num_1] = 1 builtin.log(self.topology, 'DEBUG') builtin.log('Up link {0} - {1}'.format(host1, host2), 'DEBUG') def stop_node(self, name): node = self.mininet_client.getNodeByName(name) node.stop() num_node = int(name[1:]) - 1 self.topology[num_node][num_node] = -1 builtin.log('Node {0} was stoped'.format(name), 'DEBUG') def check_connected_node(self, name): switch = self.mininet_client.getNodeByName(name) return switch.connected() # NOTE(msenin) unstable method - after stoping mininet cant start node # mininet doesn't return exception def start_node(self, name): node = self.mininet_client.getNodeByName(name) # TODO (msenin) add option controller_name controllers = self.mininet_client.controllers builtin.log('Controllers: {0}'.format(controllers), 'DEBUG') node.start([controllers[0]]) def check_rules(self): switches = self.mininet_client.switches results = [] regex = (r'(cookie=[\w\d]+),|(dl_dst=[\w\d:\/]{35})' '|(priority=[\d]+),|(dl_src=[\w\d:\/]{17})') for switch in switches: ans = switch.dpctl('dump-flows -O OpenFlow13') builtin.log( 'Rules on the switch {0}: {1}'.format(switch.name, ans), 'DEBUG') ans_with_regex = "" for m in re.finditer(regex, ans): for i in xrange(1, 5): if m.group(i): ans_with_regex = ans_with_regex + ', ' + m.group(i) builtin.log( 'Rules with regex {0}: {1}'.format(switch.name, ans), 'DEBUG') results.append({switch.name: ans_with_regex}) return results def compare_dumped_flows(self, rules1, rules2): rules_1 = str(rules1) rules_2 = str(rules2) builtin.log('Compare two flow tables(without changing parts): ', 'DEBUG') builtin.log(rules_1, 'DEBUG') builtin.log(rules_2, 'DEBUG') if rules_1 != rules_2: return False return True def ping(self, name1, name2): node1 = self.mininet_client.getNodeByName(name1) node2 = self.mininet_client.getNodeByName(name2) ping = self.mininet_client.ping(hosts=[node1, node2], timeout=10) num1, num2 = name1[1:], name2[1:] cmd1 = node1.cmd('ifconfig') builtin.log('{0}'.format(cmd1), 'DEBUG') cmd1 = node1.cmd('ping -d -c 5 -w 5 10.0.0.' + num2) builtin.log('{0}'.format(cmd1), 'DEBUG') cmd2 = node2.cmd('ifconfig') builtin.log('{0}'.format(cmd2), 'DEBUG') cmd1 = node2.cmd('ping -d -c 5 -w 5 10.0.0.' + num1) builtin.log('{0}'.format(cmd1), 'DEBUG') return int(ping) def check_route_state(self, route): # TODO (msenin) delete method after tests refactoring """Check the state of route :param route: list with verticles (each verticle is switch id) """ route = map(lambda x: int(x) - 1, route) for i in xrange(1, len(route)): prev = route[i - 1] cur = route[i] if (self.topology[prev][prev] == -1 or self.topology[cur][cur] == -1): return False if self.topology[prev][cur] == -1: return False return True def contains_route_in_routes(self, route, routes): builtin.log("route: {0}".format(route), 'DEBUG') builtin.log("routes: {0}".format(routes), 'DEBUG') route = map(lambda x: int(x), route) for i in routes: if i.get('route') and map(lambda x: int(x), i['route']) == route: return True return False def parse_tree(self, resp): """Define and check the routes and links :param resp:json from response """ builtin.log("JSON for parsing: {0}".format(resp), 'DEBUG') source_node_list = set() destination_node_list = set() links_dict = collections.OrderedDict() routes = [] states_dict = dict() route_container = resp.get('route-container') route_list = route_container.get('route-list') route_list_length = len(route_list) # TODO for i in range(0, route_list_length): needed_leaf = i route_leaf = route_list[needed_leaf] leaf_source = route_leaf.get('source') leaf_destination = route_leaf.get('destination') states_dict['source'] = leaf_source states_dict['destination'] = leaf_destination route = route_leaf.get('route', []) for i in range(0, len(route)): route_state = dict() vertexes = set() path = route[i] state = path.get('state') route_state['state'] = state route_state['route'] = vertexes routes.append(route_state) states_dict['routes'] = routes links = path.get('path') links_count = len(links) for j in range(0, links_count): link = links[j] link_source = link.get('source') link_destination = link.get('destination') source_node = link_source.get('source-node') destination_node = link_destination.get('dest-node') source_flow = source_node.split(':')[-1] destination_flow = destination_node.split(':')[-1] vertexes.add(source_flow) vertexes.add(destination_flow) source_node_list.add(source_node) destination_node_list.add(destination_node) links_dict[source_node] = destination_node return states_dict def parse_tree_2(self, resp): """Parse output json from ncn restconfig :param resp:json from response [{'state': 'up', 'destination': '4', 'route': ['1', '4'], 'source': '1', 'id': 100}, .................................................................... {'destination': '3', 'source': '1'}, {'destination': '7', 'source': '1'}] """ builtin.log("JSON for parsing: {0}".format(resp), 'DEBUG') routes = [] route_list = resp.get('route-container').get('route-list') for routes_between_switches in route_list: routes_rest_conf = routes_between_switches.get("route") if routes_rest_conf: # NOTE (msenin) # format of fields 'source' and 'destination': openflow:4 for route_rest in routes_rest_conf: route = {} route['source'] = int(route_rest['source'][9:]) route['destination'] = \ int(route_rest['destination'][9:]) route['state'] = route_rest['state'] pathes = route_rest.get('path') route['id'] = route_rest.get('id') path = [] for link in pathes: link_source = link.get('source') link_destination = link.get('destination') source_node = link_source.get('source-node') destination_node = link_destination.get('dest-node') source_flow = int(source_node[9:]) destination_flow = int(destination_node[9:]) if source_flow not in path: path.append(source_flow) if destination_flow not in path: path.append(destination_flow) route['route'] = path routes.append(route) else: route = {} route['source'] = int(routes_between_switches['source'][9:]) route['destination'] = \ int(routes_between_switches['destination'][9:]) routes.append(route) return routes def check_route_state_by_DOM_tree(self, route, tree): """ return 1 if route up, -1 down and 0 if unexist """ if isinstance(route, str) or isinstance(route, unicode): route = list(route[1:-1].split(',')) route = map(lambda x: int(x), route) builtin.log("route: {0}".format(route), 'DEBUG') tree = self.parse_tree_2(tree) builtin.log("tree: {0}".format(tree), 'DEBUG') filtered_tree = filter(lambda x: x.get('route') == route, tree) if filtered_tree: if filtered_tree[0]['state'] == 'up': return 1 else: return -1 else: return 0 def filter_DOM_tree_by_field(self, condition, tree): # TODO (msenin) add logger tree = self.parse_tree_2(tree) filtered_tree = filter(lambda field: eval(condition), tree) return filtered_tree
def test( self ): #Funções para inicialização do iperf cliente #Cada função representa um host #Falta aumentar o tempo de duração do teste do iperf de cada cliente (-t) def iperF2(): print h2.cmd('iperf3 -c %s -p 5201 -u -b 20M -i 1 -t 86400 &' % h1.IP()) return iperF2 def iperF22(): print h22.cmd('iperf3 -c %s -p 5202 -u -b 40M -i 1 -t 86400 &' % h11.IP()) return iperF22 def iperF3(): print h3.cmd('iperf3 -c %s -p 5203 -u -b 5M -i 1 -t 86400 &' % h1.IP()) return iperF3 def iperF33(): print h33.cmd('iperf3 -c %s -p 5204 -u -b 5M -i 1 -t 86400 &' % h11.IP()) def iperF4(): print h4.cmd('iperf3 -c %s -p 5205 -u -b 20M -i 1 -t 86400 & ' % h1.IP()) return iperF4 #INICIALIZA A REDE COM A FUNÇÃO MININET net = Mininet( topo=None, controller=RemoteController, build=False ) info('\n') #Esse print net foi apenas para visualizar o que a variável "net" retorna :P. Não é, de fato, necessário print net, '<----- net ' #ADICIONA O CONTROLADOR c0 = net.addController( 'c0', ip='192.168.56.101', port=6633 ) info('Adding Hosts\n\n') #CRIA OS HOSTS E SWITCHES #Cada host possue um rede diferente e foi necessário adicionar uma rota padrão em cada um deles h1 = net.addHost( 'h1', ip='192.168.1.1/24', defaultRoute='via 192.168.1.1' ) h2 = net.addHost( 'h2', ip='192.168.2.1/24', defaultRoute='via 192.168.2.1' ) h3 = net.addHost( 'h3', ip='192.168.3.1/24', defaultRoute='via 192.168.3.1' ) h4 = net.addHost( 'h4', ip='192.168.4.1/24', defaultRoute='via 192.168.4.1' ) h11 = net.addHost( 'h11', ip='192.168.1.11/24', defaultRoute='via 192.168.1.11' ) h22 = net.addHost( 'h22', ip='192.168.2.22/24', defaultRoute='via 192.168.2.22' ) h33 = net.addHost( 'h33', ip='192.168.3.33/24', defaultRoute='via 192.168.3.33' ) h44 = net.addHost( 'h44', ip='192.168.4.44/24', defaultRoute='via 192.168.4.44' ) s1 = net.addSwitch( 's1_POP' ) s2 = net.addSwitch( 's2_FUNDAJ' ) s3 = net.addSwitch( 's3_CPOR' ) s4 = net.addSwitch( 's4_IFPE' ) #CRIA OS LINKS ENTRE HOSTS E SWITCHES info('Link between devices at 100Mb/s\n\n') net.addLink( h1, s1, cls=TCLink, bw=40 ) net.addLink( h11, s1, cls=TCLink, bw=40 ) net.addLink( h2, s2, cls=TCLink, bw=40 ) net.addLink( h22, s2, cls=TCLink, bw=40 ) net.addLink( h3, s3, cls=TCLink, bw=40 ) net.addLink( h33, s3, cls=TCLink, bw=40 ) net.addLink( h4, s4, cls=TCLink, bw=40 ) net.addLink( h44, s4, cls=TCLink, bw=40 ) net.addLink( s1, s2, cls=TCLink, bw=40 ) net.addLink( s2, s3, cls=TCLink, bw=40 ) net.addLink( s1, s4, cls=TCLink, bw=40 ) net.addLink( s4, s3, cls=TCLink, bw=40 ) try: #INICIA A EMULAÇÃO net.start() #CONTADOR DE 30 SEGUNDOS PARA O PROTOCOLO STP info('\nwaiting 30sec\n' ) info('*** converging ring topology\n\n') c = 0 for c in range (30): c+=1 print(c) time.sleep(1) #LISTA TODOS OS HOSTS E SEUS LINKS print (net.hosts) #INICIA O MODO SERVIDOR NOS HOSTS h1 E h11 info('\n\n*** Starting Iper3 Server h1 and h11\n\n') print h1.cmd('iperf3 -s -p 5201 &') #h2 time.sleep(1) print h1.cmd('iperf3 -s -p 5203 &') #h3 time.sleep(1) print h1.cmd('iperf3 -s -p 5205 &') #h4 time.sleep(1) print h11.cmd('iperf3 -s -p 5202 &') #h22 time.sleep(1) print h11.cmd( 'iperf3 -s -p 5204 &') #h33 time.sleep(1) print h1.cmd('jobs') time.sleep(1) print h11.cmd ('jobs') #A EMULAÇÃO INICIA COM O TRÁFEGO DOS HOSTS h2 E h4 #info('\n\n***Starting iperf3 clients on Host2 and Host4\n\n') #iperF2() #time.sleep(1) #print h2.cmd('jobs') #iperF4() #time.sleep(1) #print h4.cmd('jobs') #PAUSA DE X SEGUNDOS PARA ADICIONAR GRÁFICOS NO CACTI #sleep(10) #TRATAMENTO DE EXCEÇÕES E MENU DE MANIPULAÇÃO DA TOPOLOGIA try: info('Choose the action: \n\n') info('a: Link s2_FUNDAJ/s1-POP up\n') info('b: Link s2_FUNDAJ/s1_POP down\n') info('c: Link s2_FUNDAJ/s3_CPOR up\n') info('d: Link s2_FUNDAJ/s3_CPOR down\n') info('e: Start host3 - s3_CPOR \n') info('f: Start host22 - s2_FUNDAJ \n') info('g: Shutdown host22 (s2_FUNDAJ) down') info('h: Start host2 (s2_FUNDAJ) up\n') info('i: Shutdown host2 (s2_FUNDAJ) down\n') info('j: Start host33 - s3_CPOR \n') info('l: Shutdown host33 (s3_CPOR) down\n') info('m: Start host4 (s4_IFPE) up\n') info('n: Exit\n\n') inputKey = '' while inputKey != 'n': inputKey = raw_input('Choose an option (just one letter): ') if inputKey == 'a': time.sleep(1) info('\nlink s2_FUNDAJ / s1_POP UP\n') net.configLinkStatus('s2_FUNDAJ','s1_POP','up') time.sleep(1) inputKey = '' elif inputKey == 'b': time.sleep(1) info('\nlink s2_FUNDAJ / s1_POP DOWN\n') net.configLinkStatus('s2_FUNDAJ','s1_POP','down') time.sleep(1) inputKey = '' elif inputKey == 'c': time.sleep(1) info('\nlink s2_FUNDAJ / s3_CPOR UP\n') net.configLinkStatus('s2_FUNDAJ','s3_CPOR','up') time.sleep(1) inputKey = '' elif inputKey == 'd': time.sleep(1) info('\nlink s2_FUNDAJ \ s3_CPOR DOWN\n') net.configLinkStatus('s2_FUNDAJ','s3_CPOR','down') time.sleep(1) inputKey = '' elif inputKey == 'e': time.sleep(1) iperF3() info('\njobs from h3\n') print h3.cmd('jobs') time.sleep(1) inputKey='' elif inputKey == 'f': time.sleep(1) iperF22() time.sleep(1) info('\n***Starting h22***\n') print h22.cmd('jobs') time.sleep(1) inputKey = '' elif inputKey == 'g': time.sleep(1) info('\nhost-h22 (s2_FUNDAJ) down\n') print h22.cmd('killid="$(ps -eopid,cmd | egrep "*-p 5202 -u*" | cut -f1 -d " " | head -n 1)"') time.sleep(1) print h22.cmd('kill 9 $killid') time.sleep(1) print h22.cmd('unset killid') time.sleep(1) print h22.cmd('jobs') time.sleep(1) inputKey = '' elif inputKey == 'h': time.sleep(1) info('\nhost-h2 (s2_FUNDAJ) UP\n') iperF2() time.sleep(1) print h2.cmd('jobs') time.sleep(1) inputKey = '' elif inputKey == 'i': time.sleep(1) info('\nhost-h2 (s2_FUNDAJ) DOWN\n') print h2.cmd('killid="$(ps -eopid,cmd | egrep "*-p 5201 -u*" | cut -f1 -d " " | head -n 1)"') time.sleep(1) print h2.cmd('kill 9 $killid') time.sleep(1) print h2.cmd('unset killid') time.sleep(1) print h2.cmd('jobs') inputKey = '' elif inputKey == 'j': time.sleep(1) info('\n***Starting h33***\n') iperF33() time.sleep(1) print h33.cmd('jobs') time.sleep(1) inputKey = '' elif inputKey == 'l': time.sleep(1) info('\nhost-h33 (s3_CPOR) down\n') print h33.cmd('killid="$(ps -eopid,cmd | egrep "*-p 5204 -u*" | cut -f1 -d " " | head -n 1)"') time.sleep(1) print h33.cmd('kill 9 $killid') time.sleep(1) print h33.cmd('unset killid') time.sleep(1) print h33.cmd('jobs') inputKey = '' elif inputKey == 'm': time.sleep(1) info('\nhost-h4 (s4_IFPE) UP\n') iperF4() time.sleep(1) print h4.cmd('jobs') time.sleep(1) inputKey = '' elif inputKey == 'n': time.sleep(1) info('\n\n***Exit***\n\n') break else: time.sleep(1) info('\n\n--Option not recognized, Repeat--\n\n') inputKey = '' except KeyboardInterrupt: print '\n\nDont use Ctrl+C, Use option "m" for exit\n\n' #continue except EOFError: print '\n\nEOF detected: This program doesnt support EOF ending emulation...\n\n' print '\n\nEnding Emulation ...\n\n' net.stop() except KeyboardInterrupt: print '\n\n*** Aborting Emulation ***\n\n' net.stop()
import thread import time # ping forever function def ping_thread (threadName, src, dst): while (1): time.sleep(1) print src.cmd('ping -c1 %s' % dst.IP()) # setup mininet network net = Mininet() c0 = net.addController('c0') s0 = net.addSwitch('s0') h0 = net.addHost('h0') h1 = net.addHost('h1') net.addLink(s0, h0) net.addLink(s0, h1) # start network and test net.start() # do the actual test and run forever thread.start_new_thread(ping_thread, ("pinging thread", h0, h1)) # wait 10 seconds before killing the network time.sleep(10) net.configLinkStatus("s0", "h1", "down") # stop network net.stop()
class MininetCreator(): def __init__(self): self.logger = logging.getLogger(__name__) pass def create_mininet(self, topo=None, tunnels=[], switch=UserSwitch, controller=None): "Create a Mininet and test it with pingall" self.setLogLevel('debug') self.logger.info("Creating mininet instance") if not topo: topo=SingleSwitchTopo(k=2) if controller: self.net = Mininet(topo=topo, intf=TCIntf, link=TCLink, switch=switch, controller=controller) else: self.net = Mininet(topo=topo, intf=TCIntf, link=TCLink, switch=switch) self.logger.info("Adding tunnels to mininet instance") for tunnel in tunnels: port=None cls=None if "port" in tunnel[2].keys(): port = tunnel[2]["port"] del tunnel[2]["port"] if "cls" in tunnel[2].keys(): cls = tunnel[2]["cls"] del tunnel[2]["cls"] self.addTunnel(tunnel[0], tunnel[1], port, cls, **tunnel[2]) self.logger.info("Starting Mininet...") self.net.start() #print "Dumping host connections" dumpNodeConnections(self.net.hosts) self.logger.info("Startup complete.") # print "Testing network connectivity" # self.net.pingAll() # self.net.stop() # print "net created, pingAll finished!" #return net # to do: it seems we get in trouble with serializing Mininet objects def getHosts(self): # todo just return the hosts names not the objects themselves they are not serializable hosts = self.net.hosts self.logger.debug('hosts type: ', type(hosts), ' ||| elem type:', type(hosts[0])) return hosts def setLogLevel(self, level='info'): ''' set worker's mininet instance log level ''' mnSetLogLevel(level) def configLinkStatus(self,src,dst,status): self.net.configLinkStatus(src,dst,status) def rpc(self, hostname, cmd, *params1, **params2): h = self.net.get(hostname) return getattr(h,cmd)(*params1, **params2) def attr(self, hostname, name): h = self.net.get(hostname) return getattr(h,name) def addHost(self,name, cls=None,**params): self.net.addHost(name,cls, **params) return name def addSwitch(self,name,cls=None, **params): self.net.addSwitch(name, cls, **params) self.net.get(name).start(self.net.controllers) #TODO: This should not be done here return name def addController(self,name="c0", controller=None,**params): self.net.addController(name, controller,**params) return name def addTunnel(self, name, switch, port, cls, **params): switch=self.net.get(switch) #self.net.addTunnel(name, switch, port, cls, **params) if not cls: cls=TCIntf cls(name, node=switch, port=port, link=None, **params) def tunnelX11(self, node,display): node = self.net.get(node) mininet.term.tunnelX11(node,display) def addLink(self, node1, node2, port1 = None, port2 = None, cls = None, **params): node1=self.net.get(node1) node2=self.net.get(node2) l=self.net.addLink(node1,node2,port1,port2,cls,**params) return ((node1.name,l.intf1.name),(node2.name,l.intf2.name)) def runCmdOnHost(self, hostname, command, noWait=False): ''' e.g. runCmdOnHost('h1', 'ifconfig') ''' h1 = self.net.get(hostname) if noWait: return h1.sendCmd(command) else: return h1.cmd(command) def getNodePID(self, nodename): # todo : get pid of a specific switch or host in order to log its resource usage pass def stop(self): self.net.stop() self.logger.info('network stopped')
class MIXTT(): """ Mininet IXP topology tester. Takes json with topology information and builds a network based on this. It will check the reachability of all hosts as well as redundancy is working by turning off each link between switches and validates that hosts are still able to communicate. """ def __init__(self): self.net = None self.network_matrix = None self.hosts_matrix = None self.link_matrix = None self.switch_dps = None self.vlan_matrix = {} self.vlan_to_host_id = [] self.p4_switches = [] self.ping_count = 1 self.no_redundancy = False self.logger = None def build_network(self): """ Builds a mininet network based on the network matrix that's been given """ topo = self.MyTopo(hosts_matrix=self.hosts_matrix, switch_matrix=self.link_matrix, switch_dps=self.switch_dps, p4_switches=self.p4_switches, logger=self.logger) self.net = Mininet(topo=topo, controller=RemoteController(name="faucet", ip="127.0.0.1", port=6653)) def test_network(self): """ Sets up the network and tests that all hosts can ping each other in ipv4 and ipv6. Also tests failover by disabling links between switches """ self.ping_vlan_v4() # Compensates for ipv6 taking some time to set up time.sleep(1) self.ping_vlan_v6() # No redundancy mode until p4 redundancy has been tested more if self.no_redundancy or self.p4_switches: return for link in self.link_matrix: s1, s2 = link[0], link[2] self.log_info(f"Setting link between {s1} and {s2} down") self.net.configLinkStatus(s1, s2, "down") self.ping_vlan_v4() self.ping_vlan_v6() self.log_info(f"Setting link between {s1} and {s2} up") self.net.configLinkStatus(s1, s2, "up") self.ping_vlan_v4() self.ping_vlan_v6() def cleanup_ips(self): """ Cleans up ip addresses, in particular hosts with multiple interfaces and vlans """ self.vlan_matrix["none"] = [] for iface in self.hosts_matrix: h = {"name": iface["name"]} h["port"] = f"h{iface['id']}-eth0" h["id"] = iface["id"] if "ipv4" in iface: h["ipv4"] = iface["ipv4"] if "ipv6" in iface: h["ipv6"] = iface["ipv6"] self.add_ipv6(iface['id'], f"h{iface['id']}-eth0", iface) if "vlan" not in iface: self.vlan_matrix["none"].append(h) for iface in self.vlan_to_host_id: h = {"name": iface["name"]} h["port"] = "eth-0" if "ipv4" in iface: h["ipv4"] = iface["ipv4"] if "ipv6" in iface: h["ipv6"] = iface["ipv6"] hnode = self.net.getNodeByName(f"h{iface['id']}") if hnode.IP() == "127.0.0.1": hnode.cmd(f"ip addr del dev h{iface['id']}-eth0 127.0.0.1") hnode.cmd(f"ip -6 addr flush dev h{iface['id']}-eth0") hnode.cmd(f"ip link set dev h{iface['id']}-eth0 {iface['mac']}") self.add_vlan(iface["id"], iface, 0) def add_vlan(self, hostname, iface, port): """ Adds a vlan address to the specified port """ self.vlan_matrix.setdefault(iface["vlan"], []) h = self.net.getNodeByName(f"h{hostname}") phase = f"h{hostname}-eth{port}" vid = iface["vlan"] vlan_port_name = f"eth{port}.{vid}" host = {"name": iface["name"]} host["port"] = vlan_port_name host["id"] = iface["id"] h.cmd( f'ip link add link {phase} name {vlan_port_name} type vlan id {vid}' ) if "ipv4" in iface: h.cmd(f"ip addr add dev {vlan_port_name} {iface['ipv4']}") host["ipv4"] = iface["ipv4"] if "ipv6" in iface: self.add_ipv6(hostname, vlan_port_name, iface) host["ipv6"] = iface["ipv6"] self.vlan_matrix[iface["vlan"]].append(host) h.cmd(f"ip link set dev {vlan_port_name} up") def add_ipv6(self, hostname, portname, iface): """ Removes the default ipv6 address from hosts and adds the ip based on the hosts matrix """ h = self.net.getNodeByName(f"h{hostname}") h.cmd(f"ip -6 addr flush dev {portname}") h.cmd(f"ip -6 addr add dev {portname} {iface['ipv6']}") def ping_vlan_v4(self): """ Uses the hosts matrix and pings all the ipv6 addresses, similar to mininet's pingall format """ self.log_info('*** Ping: testing ping4 reachability') packets = 0 lost = 0 ploss = None for vlan in self.vlan_matrix: self.log_info(f"Testing reachability for hosts with vlan: {vlan}") for host in self.vlan_matrix[vlan]: results = [] h = self.net.getNodeByName(f"h{host['id']}") # self.logger.info(f'{host["name"]} -> ') self.to_console(f'{host["name"]} -> ') for dst in self.vlan_matrix[vlan]: if dst is host: continue if "ipv4" not in host: continue addr = dst['ipv4'].split('/')[0] result = h.cmd( f'ping -I {host["port"]} -c{self.ping_count} -i 0.01 {addr}' ) self.logger.debug(result) sent, received = self.net._parsePing(result) packets += sent lost += sent - received out = 'X' if received: out = dst["name"] self.to_console(f'{out} ') results.append(out) output('\n') if packets > 0: ploss = 100.0 * lost / packets received = packets - lost self.log_info("*** Results: %i%% dropped (%d/%d received)" % (ploss, received, packets)) def ping_vlan_v6(self): """ Uses the hosts matrix and pings all the ipv6 addresses, similar to mininet's pingall format """ self.log_info('*** Ping: testing ping6 reachability') packets = 0 lost = 0 ploss = None for vlan in self.vlan_matrix: self.log_info(f"Testing reachability for hosts with vlan: {vlan}") for host in self.vlan_matrix[vlan]: h = self.net.getNodeByName(f"h{host['id']}") output(f'{host["name"]} -> ') for dst in self.vlan_matrix[vlan]: if dst is host: continue if "ipv6" not in host: continue addr = dst['ipv6'].split('/')[0] result = h.cmd( f'ping6 -I {host["port"]} -c{self.ping_count} -i 0.01 {addr}' ) self.logger.debug(result) sent, received = self.net._parsePing(result) packets += sent lost += sent - received out = 'X' if received: out = dst["name"] output(f'{out} ') output('\n') if packets > 0: ploss = 100.0 * lost / packets received = packets - lost self.log_info("*** Results: %i%% dropped (%d/%d received)" % (ploss, received, packets)) # Possibly redundant code, keeping for testing purpose def pingAllV4(self): """ Uses the hosts matrix and pings all the ipv6 addresses, similar to mininet's pingall format """ self.logger.info('*** Ping: testing ping4 reachability\n') packets = 0 lost = 0 ploss = None for host in self.hosts_matrix: h = self.net.getNodeByName(host[0]) self.logger.info(f'{host[0]} -> ') for dst in self.hosts_matrix: if dst is host: continue addr6 = dst[1].split('/')[0] result = h.cmd(f'ping -c{self.ping_count} -i 0.01 {addr6}') sent, received = self.net._parsePing(result) packets += sent lost += sent - received out = 'X' if received: out = dst[0] self.logger.info(f'{out} ') self.logger.info('\n') if packets > 0: ploss = 100.0 * lost / packets received = packets - lost self.logger.info("*** Results: %i%% dropped (%d/%d received)\n" % (ploss, received, packets)) # Possibly redundant code, keeping for testing purpose def pingAllV6(self): """ Uses the hosts matrix and pings all the ipv6 addresses, similar to mininet's pingall format """ self.logger.info('*** Ping: testing ping6 reachability\n') packets = 0 lost = 0 ploss = None for host in self.hosts_matrix: h = self.net.getNodeByName(host[0]) self.logger.info(f'{host[0]} -> ') for dst in self.hosts_matrix: if dst is host: continue addr6 = dst[2].split('/')[0] result = h.cmd(f'ping -c{self.ping_count} -i 0.01 -6 {addr6}') sent, received = self.net._parsePing(result) packets += sent lost += sent - received out = 'X' if received: out = dst[0] self.logger.info(f'{out} ') self.logger.info('\n') if packets > 0: ploss = 100.0 * lost / packets received = packets - lost self.logger.info("*** Results: %i%% dropped (%d/%d received)\n" % (ploss, received, packets)) def start(self, args, logger): """ Starts the program """ self.logger = logger info(f"{datetime.now().strftime('%b %d %H:%M:%S')}\n") info('Starting new Testing instance\n') nw_matrix = None if args.json_topology: self.logger.error("Direct JSON is not yet supported") sys.exit() # network_matrix = self.parse_json(args.json) if args.topology_file: nw_matrix = self.open_file(args.topology_file) if not args.json_topology and not args.topology_file: nw_matrix = self.open_file(DEFAULT_INPUT_FILE) try: args.ping = int(args.ping) self.ping_count = args.ping except: self.log_error( 'Ping input is not a number, using the default ping count of 1' ) if not nw_matrix: self.log_error("No topology discovered. Please check input files") if args.thrift_port: self.thrift_port = args.thrift_port if args.no_redundancy: self.no_redundancy = True self.log_info('No redundancy testing mode') if nw_matrix: self.check_matrix(nw_matrix) self.build_network() self.net.start() self.cleanup_ips() if (args.cli): CLI(self.net) else: self.test_network() self.net.stop() def parse_json(self, json_string): """ Parses json string entered through cli """ data = None try: data = json.loads(json_string) except ValueError as err: self.log_error(f"Error in the input json string\n") return data def open_file(self, input_file): """ Opens the json file that contains the network topology """ data = None try: with open(input_file) as jsonFile: data = json.load(jsonFile) except (UnicodeDecodeError, PermissionError, ValueError) as err: self.logger.error(f"Error in the file {input_file}\n") except FileNotFoundError as err: self.logger.error(f"File not found: {input_file}\n") if input_file is DEFAULT_INPUT_FILE: self.logger.error( "Please specify a default topology in " + "/etc/mxitt/topology.json or specify a topology file " + "using the -i --input option\n") sys.exit() return data def check_matrix(self, nw_matrix): """ Checks and validates the network matrix format """ err_msg = "Malformed config detected! Please check config: " if "hosts_matrix" not in nw_matrix: self.logger.error(f"{err_msg}No \"hosts_matrix\" is detected\n") sys.exit() if not nw_matrix["hosts_matrix"]: self.logger.error(f"{err_msg}hosts_matrix doesn't have content\n") sys.exit() for host in nw_matrix["hosts_matrix"]: malformed = False if "name" not in host: self.logger.error(f"{err_msg} Entry detected without a name\n") malformed = True if "interfaces" not in host: self.logger.error( f"{err_msg} Entry detected without any interfaces\n") malformed = True if malformed: sys.exit() for iface in host["interfaces"]: if "ipv4" in iface: if "." not in iface["ipv4"] or "/" not in iface["ipv4"]: self.logger.error( f"{err_msg}Host: {host['name']} has an self.logger.error in the ipv4 section\n" ) self.logger.error(f"IPv4 section: {iface['ipv4']}\n") malformed = True if "ipv6" in iface: if ":" not in iface["ipv6"] or "/" not in iface["ipv6"]: self.logger.error( f"{err_msg}Host: {host['name']} has an self.logger.error in ipv6 section\n" ) self.logger.error(f"IPv6 section: {iface['ipv6']}\n") malformed = True if "ipv4" not in iface and "ipv6" not in iface: self.logger.error( f"{err_msg}Host: {host['name']} has neither an IPv4 or IPv6 address\n" ) malformed = True if "mac" not in iface: mac = "" for other_iface in host["interfaces"]: if iface is other_iface: continue if not malformed and \ iface["switch"] == other_iface["switch"] and \ iface["swport"] == other_iface["swport"] and \ "mac" in other_iface: mac = other_iface["mac"] iface["mac"] = mac if not mac: self.logger.error( f"{err_msg}Host: {host['name']} does not have a mac address\n" ) malformed = True if "mac" in iface: if ":" not in iface["mac"]: self.logger.error( f"{err_msg}Host: {host['name']} has an self.logger.error in mac section\n" ) self.logger.error(f"mac section: {iface['mac']}\n") malformed = True if "swport" not in iface: self.logger.error( f"{err_msg}Host: {host['name']} does not have a switch port\n" ) malformed = True if "switch" not in iface: self.logger.error( f"{err_msg}Host: {host['name']} does not have a switch property\n" ) malformed = True if "vlan" in iface: vid = int(iface["vlan"]) if vid < 0 or vid > 4095: self.logger.error( f"{err_msg}Host: {host['name']} has an interface" + f"an invalid vlan id. Vid should be between 1" + f" and 4095. Vid :{vid} detected\n") if malformed: sys.exit() if "switch_matrix" not in nw_matrix: self.logger.error(f"{err_msg}No \"switch_matrix\" detected\n") sys.exit() if not nw_matrix["switch_matrix"]: self.logger.error(f"{err_msg}switch matrix doesn't have content\n") sys.exit() if "links" not in nw_matrix["switch_matrix"]: self.logger.error( f'{err_msg}switch matrix is missing a links section\n') sys.exit() for switch in nw_matrix["switch_matrix"]["links"]: if len(switch) != 4: self.logger.error( f"{err_msg}The switch matrix seems to be missing parts. " + "please ensure format is as follows:\n" + "[switch1_name,\tport_connecting_switch1_to_switch2," + "\tswitch2_name,\tport_connecting_switch2_to_switch1]\n") sys.exit() if "dp_ids" not in nw_matrix["switch_matrix"]: self.logger.warning( "No \"switch_dps\" detected, dps generated in Mininet might" + " not match dps in faucet config\n") else: self.switch_dps = nw_matrix["switch_matrix"]["dp_ids"] if "p4" in nw_matrix["switch_matrix"]: self.p4_switches = nw_matrix["switch_matrix"]["p4"] self.hosts_matrix = self.flatten_nw_matrix(nw_matrix) self.link_matrix = nw_matrix["switch_matrix"]["links"] def flatten_nw_matrix(self, nw_matrix): """ Flattens out the topology matrix turning each interface into a separate namespace """ flattened_matrix = [] id = 1 for host in nw_matrix["hosts_matrix"]: hname = host["name"] connected_sw = {} ifaces = [] vlan_ifaces = [] untagged_ids = [] tagged_ids = [] for iface in host["interfaces"]: switch = iface["switch"] swport = iface["swport"] if switch not in connected_sw: connected_sw[switch] = {swport: id} h = iface h["name"] = hname h["id"] = id if "vlan" not in iface: ifaces.append(h) untagged_ids.append(id) else: vlan_ifaces.append(h) tagged_ids.append(id) id += 1 continue if swport not in connected_sw[switch]: connected_sw[switch][swport] = id h = iface h["name"] = hname h["id"] = id if "vlan" not in iface: ifaces.append(h) untagged_ids.append(id) else: vlan_ifaces.append(h) tagged_ids.append(id) id += 1 continue tempid = connected_sw[switch][swport] h = iface h["name"] = hname h["id"] = tempid if "vlan" not in iface: ifaces.append(h) untagged_ids.append(tempid) else: vlan_ifaces.append(h) tagged_ids.append(tempid) id += 1 continue for iface in vlan_ifaces: if iface["id"] not in untagged_ids: # To prevent interference with multiple vlans on same iface untagged_ids.append(iface["id"]) ifaces.append(iface) self.vlan_to_host_id.extend(vlan_ifaces) flattened_matrix.extend(ifaces) return flattened_matrix def to_console(self, message): output(message) def log_info(self, message): info(f'{message}\n') self.logger.info(message) def log_error(self, message): error(f'{message}\n') self.logger.error('message') class MyTopo(Topo): """ Custom topology generator """ def __init__(self, hosts_matrix=None, switch_matrix=None, switch_dps=None, p4_switches=None, sw_path=DEFAULT_P4_SWITCH, p4_json=DEFAULT_UMBRELLA_JSON, logger=None): """ Create a topology based on input JSON""" # Initialize topology Topo.__init__(self) switch_list = [] self.logger = logger for sw in switch_dps: dp_id = switch_dps[sw] switch_list.append(sw) self.addSwitch(sw, dpid='%x' % dp_id) if p4_switches: self.log_info('Adding p4 switches:') i = 0 for sw in p4_switches: self.log_info(f'{sw}') # Need to allow for multiple p4 switches to be used # Can't use 9090 due to promethues clash t_port = 9190 + i i = +1 # TODO: Change to variables self.addSwitch(sw, cls=P4Switch, sw_path=sw_path, json_path=p4_json, thrift_port=t_port) switch_list.append(sw) # logger.info('\n') for switch in switch_matrix: self.addLink(switch[0], switch[2], int(switch[1]), int(switch[3])) for host in hosts_matrix: self.hostAdd(host) def hostAdd(self, host): """ Adds the host to the network """ hname = f"h{host['id']}" if "ipv4" in host and "vlan" not in host: self.addHost(hname, ip=host["ipv4"], mac=host["mac"], intf="eth-0") else: self.addHost(hname, ip="127.0.0.1/32", mac=host["mac"], intf="eth-0") self.addLink(host["switch"], hname, host["swport"]) def to_console(self, message): output(message) def log_info(self, message): info(f'{message}\n') self.logger.info(message) def log_error(self, message): error(f'{message}\n') self.logger.error('message')
def run(): os.system('mn -c') topo = xpanderTopo() OVS13 = partial(OVSKernelSwitch, protocols='OpenFlow13') net = Mininet(topo=topo, link=TCLink, controller=None, switch=OVS13) c = RemoteController('c0', '127.0.0.1') net.addController(c) net.start() print ('==== Total server(s) = %s' % h) print ('==== Total switches(s) = %s' % s) # Getting switch few switches for i in range(s): if mat[0, i] == 1: sw_list.append('s%s' % (i + 1)) host = [] for i in range(h): host.append(net.get('h%s' % (i + 1))) # Make directory for result directory = '/home/DCResult/Xpander' + str(s) os.system('mkdir -p ' + directory + '/latency') os.system('mkdir -p ' + directory + '/convergence') os.system('mkdir -p ' + directory + '/throughput') # Homemade pingall print '==== Pingall from h1 to all hosts to initiate paths...' print '==== Pingall will be initiate in 1 second' time.sleep(1) for i in range(1, len(host)): # print "h1 pinging to %s" % host[i] host[0].cmd('ping %s -c 1 &' % host[i].IP()) print('Wait 30 sec for test to complete') print '==== Latency test' for i in range(1, len(host)): host[i].cmd('ping 10.0.0.1 -c 10 > ' + directory + '/latency/h%s.txt &' % (i + 1)) time.sleep(10) print '==== Throughput test' # Using Nping as background traffic ips = '' for i in range(2, len(host) - 1): ips += host[i].IP() + ' ' host[0].cmd('iperf -s &') host[1].cmd('nping -c 10 --tcp ' + ips + '&') host[-1].cmd('iperf -c 10.0.0.1 -t 10 -i 1 > ' + directory + '/throughput/throughput.txt &') time.sleep(10) print '==== Convergence test' host[-1].cmd('ping 10.0.0.1 -c 20 -D > ' + directory + '/convergence/convergence.txt &') time.sleep(3) for i in range(0, len(sw_list)): net.configLinkStatus('s1', sw_list[i], 'down') time.sleep(0.5) net.configLinkStatus('s1', sw_list[0], 'up') time.sleep(17) os.system('chmod -R 777 /home/DCResult') #CLI(net) net.stop()
class MininetManager(object): def __init__(self): self.logger = logging.getLogger(__name__) self.net = None @Pyro4.expose def create_mininet(self, topo, tunnels=[], switch=UserSwitch, controller=None, STT=False): if(not self.net is None): self.logger.warn("running mininet instance detected!\ Shutting it down...") self.destroy_mininet() self.logger.info("Creating mininet instance") if controller: self.net = Mininet(topo=topo, intf=TCIntf, link=TCLink, switch=switch, controller=controller) else: self.net = Mininet(topo=topo, intf=TCIntf, link=TCLink, switch=switch) if STT: self.logger.info("Starting Mininet...") self.net.start() self.logger.info("Adding tunnels to mininet instance") for tunnel in tunnels: port = None cls = None if "port" in tunnel[2].keys(): port = tunnel[2]["port"] del tunnel[2]["port"] if "cls" in tunnel[2].keys(): cls = tunnel[2]["cls"] del tunnel[2]["cls"] self.addTunnel(tunnel[0], tunnel[1], port, cls, STT=STT, **tunnel[2]) if not STT: self.logger.info("Starting Mininet...") self.net.start() self.logger.info("Startup complete.") self.x11popens = [] return True @Pyro4.expose def destroy_mininet(self): """shut down mininet instance""" if self.net: for popen in self.x11popens: popen.terminate() popen.communicate() popen.wait() self.net.stop() self.logger.info("mininet instance terminated") self.net = None @Pyro4.expose def configLinkStatus(self, src, dst, status): self.net.configLinkStatus(src, dst, status) @Pyro4.expose def rpc(self, hostname, cmd, *params1, **params2): h = self.net.get(hostname) return getattr(h, cmd)(*params1, **params2) @Pyro4.expose def attr(self, hostname, name): h = self.net.get(hostname) return getattr(h, name) @Pyro4.expose def addHost(self, name, cls=None, **params): self.net.addHost(name, cls, **params) return name @Pyro4.expose def addSwitch(self, name, cls=None, **params): self.net.addSwitch(name, cls, **params) #TODO: This should not be done here self.net.get(name).start(self.net.controllers) return name @Pyro4.expose def addController(self, name="c0", controller=None, **params): self.net.addController(name, controller, **params) return name @Pyro4.expose def addTunnel(self, name, switch, port, intf, STT=False, **params): switch_i = self.net.get(switch) if not intf: intf = TCIntf if STT: subprocess.check_output(["ovs-vsctl","add-port", switch, name]) else: intf(name, node=switch_i, port=port, link=None, **params) @Pyro4.expose def tunnelX11(self, node, display): node = self.net.get(node) (tunnel, popen) = mininet.term.tunnelX11(node, display) self.x11popens.append(popen) @Pyro4.expose def addLink(self, node1, node2, port1=None, port2=None, cls=None, **params): node1 = self.net.get(node1) node2 = self.net.get(node2) l = self.net.addLink(node1, node2, port1, port2, cls, **params) return ((node1.name, l.intf1.name), (node2.name, l.intf2.name)) @Pyro4.expose def runCmdOnHost(self, hostname, command, noWait=False): ''' e.g. runCmdOnHost('h1', 'ifconfig') ''' h1 = self.net.get(hostname) if noWait: return h1.sendCmd(command) else: return h1.cmd(command)
h3 = self.addHost('h3', mac="00:00:00:00:11:13", ip="192.168.1.3/24") h4 = self.addHost('h4', mac="00:00:00:00:11:14", ip="192.168.1.4/24") self.addLink(h1, s1) self.addLink(h2, s2) self.addLink(h3, s3) self.addLink(h4, s4) self.addLink(s1, s2) self.addLink(s2, s3) self.addLink(s3, s4) if __name__ == '__main__': setLogLevel('info') topo = SingleSwitchTopo() c1 = RemoteController('c1', ip='127.0.0.1') net = Mininet(topo=topo, controller=c1) net.start() sleep(5) print("Topology is up, lets ping") net.pingAll() print("Link S3 to S4 - bringing down - h4 will not be reachable(ping)") net.configLinkStatus('s3', 's4', 'down') net.pingAll() print("Link S3 to S4 - bringing up again - all nodes will be reachable") net.configLinkStatus('s3', 's4', 'up') net.pingAll() CLI(net) net.stop()
class ATHOS(): """ Mininet IXP topology tester. Takes json with topology information and builds a network based on this. It will check the reachability of all hosts as well as redundancy is working by turning off each link between switches and validates that hosts are still able to communicate. """ def __init__(self): self.net = None self.network_matrix = None self.hosts_matrix = None self.link_matrix = None self.switch_dps = None self.vlan_matrix = {} self.vlan_to_host_id = [] self.p4_switches = [] self.logger = None self.unmanaged_switches = [] self.ploss_threshold = DEFAULT_PLOSS_THRESHOLD def build_network(self, thrift_port_base=9190): """ Builds a mininet network based on the network matrix that's been given """ topo = self.MyTopo(hosts_matrix=self.hosts_matrix, switch_matrix=self.link_matrix, switch_dps=self.switch_dps, p4_switches=self.p4_switches, unmanaged_switches=self.unmanaged_switches, logger=self.logger, thrift_port_base=thrift_port_base) self.net = Mininet( topo=topo, controller=RemoteController( name="cerberus-controller", ip="127.0.0.1", port=6653 )) def test_network(self, no_redundancy=False, ping_count=1): """ Sets up the network and tests that all hosts can ping each other in ipv4 and ipv6. Also tests failover by disabling links between switches """ v4_loss = self.ping_vlan_v4(ping_count) # Compensates for ipv6 taking some time to set up time.sleep(1) v6_loss = self.ping_vlan_v6(ping_count) ploss_passed = self.packet_loss_threshold_passed(v4_loss, v6_loss) if not ploss_passed: return # No redundancy mode until p4 redundancy has been tested more if no_redundancy or self.p4_switches: return for link in (l for l in self.link_matrix if self.backup_exists(l)): source_switch, destination_switch = link[0], link[2] info(f"Setting link between {source_switch} and " f"{destination_switch} down\n") self.net.configLinkStatus(source_switch, destination_switch, "down") self.ping_vlan_v4(ping_count) self.ping_vlan_v6(ping_count) ploss_passed = self.packet_loss_threshold_passed(v4_loss, v6_loss, source_switch, destination_switch, "down") if not ploss_passed: return info(f"Setting link between {source_switch} and " f"{destination_switch} up\n") self.net.configLinkStatus(source_switch, destination_switch, "up") self.ping_vlan_v4(ping_count) self.ping_vlan_v6(ping_count) ploss_passed = self.packet_loss_threshold_passed(v4_loss, v6_loss, source_switch, destination_switch, "up") if not ploss_passed: return def cleanup_ips(self): """ Cleans up ip addresses, in particular hosts with multiple interfaces and vlans """ self.vlan_matrix["none"] = [] for iface in self.hosts_matrix: host = {"name": iface["name"]} host["port"] = f"h{iface['id']}-eth0" host["id"] = iface["id"] if "ipv4" in iface: host["ipv4"] = iface["ipv4"] if "ipv6" in iface: host["ipv6"] = iface["ipv6"] self.add_ipv6(iface['id'], f"h{iface['id']}-eth0", iface) if "vlan" not in iface: self.vlan_matrix["none"].append(host) for iface in self.vlan_to_host_id: host = {"name": iface["name"]} host["port"] = "eth-0" if "ipv4" in iface: host["ipv4"] = iface["ipv4"] if "ipv6" in iface: host["ipv6"] = iface["ipv6"] hnode = self.net.getNodeByName(f"h{iface['id']}") if hnode.IP() == "127.0.0.1": hnode.cmd(f"ip addr del dev h{iface['id']}-eth0 127.0.0.1") hnode.cmd(f"ip -6 addr flush dev h{iface['id']}-eth0") hnode.cmd(f"ip link set dev h{iface['id']}-eth0 {iface['mac']}") self.add_vlan(iface["id"], iface, 0) def add_vlan(self, hostname, iface, port): """ Adds a vlan address to the specified port """ self.vlan_matrix.setdefault(iface["vlan"], []) host_node = self.net.getNodeByName(f"h{hostname}") phase = f"h{hostname}-eth{port}" vid = iface["vlan"] vlan_port_name = f"eth{port}.{vid}" if iface['tagged'] else f'h{iface["id"]}-eth0' host = {"name": iface["name"]} host["port"] = vlan_port_name host["id"] = iface["id"] if iface["tagged"]: host_node.cmd(f'ip link add link {phase} name ' + f'{vlan_port_name} type vlan id {vid}') if "ipv4" in iface: host_node.cmd(f"ip addr add dev {vlan_port_name} {iface['ipv4']}") host["ipv4"] = iface["ipv4"] if "ipv6" in iface: self.add_ipv6(hostname, vlan_port_name, iface) host["ipv6"] = iface["ipv6"] if iface["tagged"]: host_node.cmd(f"ip link set dev {vlan_port_name} up") host_node.cmd(f"ip link set address {iface['mac']} dev {vlan_port_name}") self.vlan_matrix[iface["vlan"]].append(host) def add_ipv6(self, hostname, portname, iface): """ Removes the default ipv6 address from hosts and adds the ip based on the hosts matrix """ host_node = self.net.getNodeByName(f"h{hostname}") host_node.cmd(f"ip -6 addr flush dev {portname}") host_node.cmd(f"ip -6 addr add dev {portname} {iface['ipv6']}") def ping_vlan_v4(self, ping_count=1): """ Uses the hosts matrix and pings all the ipv6 addresses, similar to mininet's pingall format """ info('*** Ping: testing ping4 reachability\n') packets = 0 lost = 0 ploss = None for vlan in self.vlan_matrix: info(f"Testing reachability for hosts with vlan: {vlan}\n") for host in self.vlan_matrix[vlan]: results = [] if "ipv4" not in host: continue host_node = self.net.getNodeByName(f"h{host['id']}") output(f'{host["name"]} -> ') for dst in self.vlan_matrix[vlan]: if dst is host: continue if "ipv4" not in dst: continue addr = dst['ipv4'].split('/')[0] result = host_node.cmd(f'ping -I {host["port"]}' + f' -c{ping_count} -W 1 -i 0.01 {addr}') self.logger.debug(result) sent, received = self.net._parsePing(result) packets += sent lost += sent - received out = 'X' if received: out = dst["name"] output(f'{out} ') results.append(out) output('\n') if packets > 0: ploss = 100.0 * lost / packets received = packets - lost info(f"*** Results: {round(ploss, 2)}% dropped " f"({received}/{packets} received)\n") return ploss def ping_vlan_v6(self, ping_count=1): """ Uses the hosts matrix and pings all the ipv6 addresses, similar to mininet's pingall format """ info('*** Ping: testing ping6 reachability\n') packets = 0 lost = 0 ploss = None for vlan in self.vlan_matrix: info(f"Testing reachability for hosts with vlan: {vlan}\n") for host in self.vlan_matrix[vlan]: if "ipv6" not in host: continue host_node = self.net.getNodeByName(f"h{host['id']}") output(f'{host["name"]} -> ') for dst in self.vlan_matrix[vlan]: if dst is host: continue if "ipv6" not in dst: continue addr = dst['ipv6'].split('/')[0] result = host_node.cmd( f'ping6 -I {host["port"]} -c{ping_count} -W 1 -i 0.01 {addr}') sent, received = self.net._parsePing(result) packets += sent lost += sent - received out = 'X' if received: out = dst["name"] output(f'{out} ') output('\n') if packets > 0: ploss = 100.0 * lost / packets received = packets - lost info(f"*** Results: {round(ploss, 2)}% dropped " f"({received}/{packets} received)\n") return ploss def backup_exists(self, link): """ Checks if the switches have a redundant path setup """ src_switch, dst_switch = link[0], link[2] src_has_other_link = False dst_has_other_link = False for l in (i for i in self.link_matrix if i != link): src_has_other_link = True if src_switch in l else src_has_other_link dst_has_other_link = True if dst_switch in l else dst_has_other_link if not src_has_other_link: warn(f"Warning: {src_switch} does not have another core link, the " f"link between {src_switch} and {dst_switch} will not be " f"turned off\n") return False if not dst_has_other_link: warn(f"Warning: {dst_switch} does not have another core link, the " f"link between {dst_switch} and {src_switch} will not be " f"turned off\n") return False return True def start(self, args, logger): """ Starts the program """ self.logger = logger ping_count = 1 info(f"{datetime.now().strftime('%b %d %H:%M:%S')}\n") info('Starting new Testing instance\n') nw_matrix = None if args.json_topology: error("Direct JSON is not yet supported\n") sys.exit() if args.topology_file: nw_matrix = self.open_file(args.topology_file) if not args.json_topology and not args.topology_file: nw_matrix = self.open_file(DEFAULT_INPUT_FILE) if not nw_matrix: error("No topology discovered. Please check input files\n") try: ping_count = int(args.ping) except TypeError as err: error('Ping input is not a number, using the default ping ' 'count of 1\n{err}') t_port = None if args.thrift_port: t_port = args.thrift_port if nw_matrix: self.parse_config(nw_matrix) self.build_network(t_port) self.net.start() self.cleanup_ips() if args.script: ATHOS.run_start_script(args.script) if args.cli: CLI(self.net) else: self.test_network(args.no_redundancy, ping_count) self.net.stop() def parse_json(self, json_string): """ Parses json string entered through cli """ data = None try: data = json.loads(json_string) except ValueError as err: error(f"Error in the input json string\n{err}") return data def open_file(self, input_file): """ Opens the json file that contains the network topology """ data = None try: with open(input_file) as json_file: data = json.load(json_file) except (UnicodeDecodeError, PermissionError, ValueError) as err: error(f"Error in the file {input_file}\n{err}\n") except FileNotFoundError as err: error(f"File not found: {input_file}\n") if input_file is DEFAULT_INPUT_FILE: error("Please specify a default topology in " "/etc/mxitt/topology.json or specify a topology file " f"using the -i --input option\n{err}\n") sys.exit() return data @staticmethod def run_start_script(script): """ Runs specified startup script before continuing. Typical use cases would be starting controllers or loading switches with rules """ call(script, shell=True) def parse_config(self, nw_matrix): """ Parses and validates the config """ err_msg = "Malformed config detected! " try: if "hosts_matrix" not in nw_matrix: raise ConfigError(f"{err_msg}No 'hosts_matrix' found\n") if "switch_matrix" not in nw_matrix: raise ConfigError(f"{err_msg}No 'hosts_matrix' found\n") except ConfigError as err: error(err) sys.exit() self.check_hosts_config(nw_matrix["hosts_matrix"]) self.check_switch_config(nw_matrix["switch_matrix"]) self.hosts_matrix = self.flatten_nw_matrix(nw_matrix) def check_hosts_config(self, host_matrix): """ Parses and validates the hosts matrix """ err_msg = ("Malformed config detected in the hosts section!\n" + "Please check the config:\n") if not host_matrix: error(f"{err_msg}The hosts_matrix doesn't have any content\n") for host in host_matrix: malformed = False if "name" not in host: error(f"{err_msg}Entry detected without a name\n") malformed = True if "interfaces" not in host: error(f"{err_msg}Entry detected without any interfaces\n") malformed = True if malformed: sys.exit() self.check_host_interfaces(err_msg, host) def check_host_interfaces(self, err_msg, host): """ Parse and validates the host's interfaces """ err_msg = err_msg + f"Host: {host['name']} has an error" try: if not host["interfaces"]: raise ConfigError(f"{err_msg} interfaces section is empty") for iface in host["interfaces"]: if "swport" not in iface: raise ConfigError(f"{err_msg}. It does not have a " + "switch port\n") if "switch" not in iface: raise ConfigError(f"{err_msg}. It does not have an " + "assigned switch\n") if "ipv4" in iface: self.check_ipv4_address(err_msg, iface["ipv4"]) if "ipv6" in iface: self.check_ipv6_address(err_msg, iface["ipv6"]) if "ipv4" not in iface and "ipv6" not in iface: raise ConfigError(f"{err_msg}. It has neither an IPv4" + " or IPv6 address\n") if "mac" not in iface: iface["mac"] = \ self.check_for_available_mac(err_msg, iface, host["interfaces"]) if "mac" in iface: self.check_mac_address(err_msg, iface["mac"]) if "vlan" in iface: self.check_vlan_validity(err_msg, iface["vlan"]) except ConfigError as err: error(err + "\n") sys.exit() def check_ipv4_address(self, err_msg, v4_address): """ Checks validity of ipv4 address """ try: if not v4_address: raise ConfigError(f"{err_msg} please check that ipv4 sections " "have addresses assigned\n") if "." not in v4_address or "/" not in v4_address: raise ConfigError(f"{err_msg} in the ipv4 section\n" f"IPv4 section: {v4_address}\n") except ConfigError as err: error(err) sys.exit() def check_ipv6_address(self, err_msg, v6_address): """ Checks validity of ipv6 address """ try: if not v6_address: raise ConfigError(f"{err_msg} please check that ipv6 sections" + "have addresses assigned\n") if ":" not in v6_address or "/" not in v6_address: raise ConfigError(f"{err_msg} in the ipv6 section\n" + f"IPv6 section: {v6_address}\n") except ConfigError as err: error(err) sys.exit() def check_mac_address(self, err_msg, mac_address): """ Checks validity of MAC address """ try: if not mac_address: raise ConfigError(f"{err_msg} please check that MAC sections" + "have addresses assigned\n") if ":" not in mac_address: raise ConfigError(f"{err_msg} in the MAC section. Currently " "only addresses seperated with : is " f"supported.\nMAC section: {mac_address}\n") except ConfigError as err: error(err) sys.exit() def check_for_available_mac(self, err_msg, iface, host_interfaces): """ Checks if port another mac address is assigned to the port """ mac = "" try: for other_iface in host_interfaces: if iface is other_iface: continue if iface["switch"] == other_iface["switch"] and \ iface["swport"] == other_iface["swport"] and \ "mac" in other_iface: mac = other_iface["mac"] if not mac: raise ConfigError(f"{err_msg} in the mac section. " + "No mac address was provided\n") except ConfigError as err: error(err) return mac def check_vlan_validity(self, err_msg, vlan): """ Checks that the assigned vlan is a valid value """ try: vid = int(vlan) if vid < 0 or vid > 4095: raise ConfigError(f"{err_msg}. Invalid vlan id(vid) detected. " "A valid vid should be between 1 and 4095.\n" f"Found vid: {vid}\n") except (ConfigError, ValueError) as err: error(err) sys.exit() def packet_loss_threshold_passed(self, v4_loss, v6_loss, src_switch=None, dst_switch=None, status=""): """ Helper to check packet loss and if it is more than the maximum allowed """ link_error_msg = "" if src_switch and dst_switch: link_error_msg = (f" when the link between {src_switch} and " f"{dst_switch} was set {status}.") else: link_error_msg = (f" before any links were changed.") if v4_loss and v4_loss > self.ploss_threshold \ and v6_loss and v6_loss > self.ploss_threshold: error(f"FAIL: Reachability failed for both IPv4 and IPv6" f"{link_error_msg}") error(f"Packet loss threshold: {self.ploss_threshold}\n" f"IPv4 loss: {v4_loss}\tIPv6 loss: {v6_loss}") return False elif v4_loss and v4_loss > self.ploss_threshold: error(f"FAIL: Reachability failed for IPv4{link_error_msg}\n") error(f"Packet loss threshold: {self.ploss_threshold}\n" f"IPv4 loss: {v4_loss}") return False elif v6_loss and v6_loss > self.ploss_threshold: error(f"FAIL: Reachability failed for IPv6{link_error_msg}\n") error(f"Packet loss threshold: {self.ploss_threshold}\t" f"IPv6 loss: {v6_loss}") return False else: return True def check_switch_config(self, sw_matrix): """ Parses and validates the switch matrix """ err_msg = ("Malformed config detected in the switch section!\n" + "Please check the config:\n") try: if not sw_matrix: raise ConfigError(f"{err_msg}Switch matrix is empty\n") if "links" not in sw_matrix: raise ConfigError(f"{err_msg}No links section found\n") for link in sw_matrix["links"]: if len(link) != 4: raise ConfigError(f"{err_msg}Invalid link found. The " "expected link format should be:\n" "[switchA,portA,switchB,portB]\nWhere portA is the port" " on switchA connected to switchB, and vice versa " f"for portB\nLink found: {link}\n") port_a = int(link[1]) port_b = int(link[3]) if port_a < 0 or port_a > 255 or port_b < 0 or port_b > 255: raise ConfigError("Invalid port number detected. Ensure " "that port numbers are between 0 and 255 " f"sw1_port: {port_a}\t sw2_port:{port_b}\n") if "dp_ids" not in sw_matrix: warn(f"{err_msg}No dp_id section found, dp_ids generated in " "Mininet might not match those in controller config\n") else: for _, dp_id in sw_matrix["dp_ids"].items(): if not hex(dp_id): raise ConfigError(f"{err_msg}Please ensure that dp_ids " "are valid numbers\n") self.switch_dps = sw_matrix["dp_ids"] if "p4" in sw_matrix: self.p4_switches = sw_matrix["p4"] if "unmanaged_switches" in sw_matrix: self.unmanaged_switches = sw_matrix["unmanaged_switches"] self.link_matrix = sw_matrix["links"] except ConfigError as err: error(err) sys.exit() except ValueError as err: error(f"{err_msg}Please check value of port numbers and vlan ids\n") error(err) sys.exit() def flatten_nw_matrix(self, nw_matrix): """ Flattens out the topology matrix turning each interface into a separate namespace """ flattened_matrix = [] id = 1 for host in nw_matrix["hosts_matrix"]: hname = host["name"] connected_sw = {} ifaces = [] vlan_ifaces = [] untagged_ids = [] tagged_ids = [] for iface in host["interfaces"]: switch = iface["switch"] swport = iface["swport"] if switch not in connected_sw: connected_sw[switch] = {swport:id} h = iface h["name"] = hname h["id"] = id if "vlan" not in iface: ifaces.append(h) untagged_ids.append(id) else: vlan_ifaces.append(h) tagged_ids.append(id) id += 1 continue if swport not in connected_sw[switch]: connected_sw[switch][swport] = id h = iface h["name"] = hname h["id"] = id if "vlan" not in iface: ifaces.append(h) untagged_ids.append(id) else: vlan_ifaces.append(h) tagged_ids.append(id) id += 1 continue tempid = connected_sw[switch][swport] h = iface h["name"] = hname h["id"] = tempid if "vlan" not in iface: ifaces.append(h) untagged_ids.append(tempid) else: vlan_ifaces.append(h) tagged_ids.append(tempid) id += 1 continue for iface in vlan_ifaces: if iface["id"] not in untagged_ids: # To prevent interference with multiple vlans on same iface untagged_ids.append(iface["id"]) ifaces.append(iface) self.vlan_to_host_id.extend(vlan_ifaces) flattened_matrix.extend(ifaces) return flattened_matrix class MyTopo(Topo): """ Custom topology generator """ def __init__(self, hosts_matrix=None, switch_matrix=None, switch_dps=None, p4_switches=None, unmanaged_switches=None, sw_path=DEFAULT_P4_SWITCH, p4_json=DEFAULT_UMBRELLA_JSON, logger=None, thrift_port_base=9190): """ Create a topology based on input JSON""" # Initialize topology Topo.__init__(self) switch_list = [] self.logger = logger for sw in switch_dps: dp_id = switch_dps[sw] switch_list.append(sw) self.addSwitch(sw, dpid='%x' % dp_id) if p4_switches: info('Adding p4 switches:') i = 0 for sw in p4_switches: info(f'{sw}') # Need to allow for multiple p4 switches to be used # Can't use 9090 due to promethues clash t_port = int(thrift_port_base) + int(i) i += 1 self.addSwitch(sw, cls=P4Switch, sw_path=sw_path, json_path=p4_json, thrift_port=t_port ) switch_list.append(sw) if unmanaged_switches: for sw in unmanaged_switches: self.addSwitch(sw, failMode="standalone") for switch in switch_matrix: self.addLink(switch[0], switch[2], int(switch[1]), int(switch[3])) for host in hosts_matrix: self.host_add(host) def host_add(self, host): """ Adds the host to the network """ hname = f"h{host['id']}" if "ipv4" in host and "vlan" not in host: self.addHost(hname, ip=host["ipv4"], mac=host["mac"], intf="eth-0") if "ipv4" in host and "tagged" in host and not host["tagged"]: self.addHost(hname, ip=host["ipv4"], mac=host["mac"], intf="eth-0") else: self.addHost(hname, ip="127.0.0.1/32", mac=host["mac"], intf="eth-0") self.addLink(host["switch"], hname, host["swport"])
class MininetCreator(): def __init__(self): self.logger = logging.getLogger(__name__) pass def create_mininet(self, topo=None, tunnels=[], switch=UserSwitch, controller=None): "Create a Mininet and test it with pingall" self.setLogLevel('debug') self.logger.info("Creating mininet instance") if not topo: topo = SingleSwitchTopo(k=2) if controller: self.net = Mininet(topo=topo, intf=TCIntf, link=TCLink, switch=switch, controller=controller) else: self.net = Mininet(topo=topo, intf=TCIntf, link=TCLink, switch=switch) self.logger.info("Adding tunnels to mininet instance") for tunnel in tunnels: port = None cls = None if "port" in tunnel[2].keys(): port = tunnel[2]["port"] del tunnel[2]["port"] if "cls" in tunnel[2].keys(): cls = tunnel[2]["cls"] del tunnel[2]["cls"] self.addTunnel(tunnel[0], tunnel[1], port, cls, **tunnel[2]) self.logger.info("Starting Mininet...") self.net.start() dumpNodeConnections(self.net.hosts) self.logger.info("Startup complete.") def getHosts(self): # todo just return the hosts names not the objects themselves # they are not serializable hosts = self.net.hosts self.logger.debug('hosts type: ', type(hosts), ' ||| elem type:', type(hosts[0])) return hosts def setLogLevel(self, level='info'): ''' set worker's mininet instance log level ''' mnSetLogLevel(level) def configLinkStatus(self, src, dst, status): self.net.configLinkStatus(src, dst, status) def rpc(self, hostname, cmd, *params1, **params2): h = self.net.get(hostname) return getattr(h, cmd)(*params1, **params2) def attr(self, hostname, name): h = self.net.get(hostname) return getattr(h, name) def addHost(self, name, cls=None, **params): self.net.addHost(name, cls, **params) return name def addSwitch(self, name, cls=None, **params): self.net.addSwitch(name, cls, **params) #TODO: This should not be done here self.net.get(name).start(self.net.controllers) return name def addController(self, name="c0", controller=None, **params): self.net.addController(name, controller, **params) return name def addTunnel(self, name, switch, port, intf, **params): switch = self.net.get(switch) if not intf: intf = TCIntf intf(name, node=switch, port=port, link=None, **params) def tunnelX11(self, node, display): node = self.net.get(node) mininet.term.tunnelX11(node, display) def addLink(self, node1, node2, port1=None, port2=None, cls=None, **params): node1 = self.net.get(node1) node2 = self.net.get(node2) l = self.net.addLink(node1, node2, port1, port2, cls, **params) return ((node1.name, l.intf1.name), (node2.name, l.intf2.name)) def runCmdOnHost(self, hostname, command, noWait=False): ''' e.g. runCmdOnHost('h1', 'ifconfig') ''' h1 = self.net.get(hostname) if noWait: return h1.sendCmd(command) else: return h1.cmd(command) def getNodePID(self, nodename): # todo : get pid of a specific switch or host in order to log # its resource usage pass def stop(self): self.net.stop() self.logger.info('network stopped')
class NetworkConfiguration(object): def __init__(self, controller, topo_name, topo_params, conf_root, synthesis_name, synthesis_params, flow_specs, # mhasan: added link param in constructor topo_link_params, number_of_RT_flows, number_of_BE_flows, test_case_id ): self.controller = controller self.topo_name = topo_name self.topo_params = topo_params self.topo_name = topo_name self.conf_root = conf_root self.synthesis_name = synthesis_name self.synthesis_params = synthesis_params self.flow_specs = flow_specs # mhasan: added link param self.topo_link_params = topo_link_params self.number_of_RT_flows = number_of_RT_flows self.number_of_BE_flows = number_of_BE_flows self.controller_port = 6633 self.topo = None self.nc_topo_str = None self.init_topo() self.init_synthesis() self.mininet_obj = None self.ng = None self.test_case_id = test_case_id self.isFeasible = True self.min_delay_budget_for_all_flows = None # will update later self.network_diameter = None # will update later # Setup the directory for saving configs, check if one does not exist, # if not, assume that the controller, mininet and rule synthesis needs to be triggered. self.conf_path = self.conf_root + str(self) + "/" if not os.path.exists(self.conf_path): os.makedirs(self.conf_path) self.load_config = False self.save_config = True else: self.load_config = True self.save_config = False # # self.load_config = False # self.save_config = True # Initialize things to talk to controller self.baseUrlRyu = "http://localhost:8080/" self.h = httplib2.Http(".cache") self.h.add_credentials('admin', 'admin') #mhasan : added path self.path = None def __str__(self): return self.controller + "_" + str(self.synthesis) + "_" + str(self.topo) + "_" + str( self.number_of_RT_flows) + "_" + str(self.test_case_id) def init_topo(self): # mhasan : added ring topo with param if self.topo_name == "ring_with_param": # mhasan: create topo with link param self.topo = RingTopoWithParams(self.topo_params, self.topo_link_params) self.nc_topo_str = "Ring topology with " + str(self.topo.total_switches) + " switches" elif self.topo_name == "random_with_param": # mhasan: create topo with link param self.topo = RandomTopoWithParams(self.topo_params, self.topo_link_params) self.nc_topo_str = "Random topology with " + str(self.topo.total_switches) + " switches" elif self.topo_name == "ring": # self.topo = RingTopo(self.topo_params) # mhasan: create topo with link param self.topo = RingTopo(self.topo_params) self.nc_topo_str = "Ring topology with " + str(self.topo.total_switches) + " switches" elif self.topo_name == "clostopo": self.topo = ClosTopo(self.topo_params) self.nc_topo_str = "Clos topology with " + str(self.topo.total_switches) + " switches" elif self.topo_name == "linear": # self.topo = LinearTopo(self.topo_params) # mhasan: create topo with link param self.topo = LinearTopo(self.topo_params, self.topo_link_params) self.nc_topo_str = "Linear topology with " + str(self.topo_params["num_switches"]) + " switches" else: raise NotImplementedError("Topology: %s" % self.topo_name) def init_synthesis(self): if self.synthesis_name == "DijkstraSynthesis": self.synthesis_params["master_switch"] = self.topo_name == "linear" self.synthesis = DijkstraSynthesis(self.synthesis_params) elif self.synthesis_name == "SynthesizeQoS": self.synthesis = SynthesizeQoS(self.synthesis_params) elif self.synthesis_name == "AboresceneSynthesis": self.synthesis = AboresceneSynthesis(self.synthesis_params) def test_synthesis(self): self.mininet_obj.pingAll() # is_bi_connected = self.is_bi_connected_manual_ping_test_all_hosts() # is_bi_connected = self.is_bi_connected_manual_ping_test([(self.mininet_obj.get('h11'), self.mininet_obj.get('h31'))]) # is_bi_connected = self.is_bi_connected_manual_ping_test([(self.mininet_obj.get('h31'), self.mininet_obj.get('h41'))], # [('s1', 's2')]) # print "is_bi_connected:", is_bi_connected def get_ryu_switches(self): ryu_switches = {} request_gap = 0 # Get all the ryu_switches from the inventory API remaining_url = 'stats/switches' time.sleep(request_gap) resp, content = self.h.request(self.baseUrlRyu + remaining_url, "GET") ryu_switch_numbers = json.loads(content) for dpid in ryu_switch_numbers: this_ryu_switch = {} # Get the flows remaining_url = 'stats/flow' + "/" + str(dpid) resp, content = self.h.request(self.baseUrlRyu + remaining_url, "GET") time.sleep(request_gap) if resp["status"] == "200": switch_flows = json.loads(content) switch_flow_tables = defaultdict(list) for flow_rule in switch_flows[str(dpid)]: switch_flow_tables[flow_rule["table_id"]].append(flow_rule) this_ryu_switch["flow_tables"] = switch_flow_tables else: print "Error pulling switch flows from RYU." # Get the ports remaining_url = 'stats/portdesc' + "/" + str(dpid) resp, content = self.h.request(self.baseUrlRyu + remaining_url, "GET") time.sleep(request_gap) if resp["status"] == "200": switch_ports = json.loads(content) this_ryu_switch["ports"] = switch_ports[str(dpid)] else: print "Error pulling switch ports from RYU." # Get the groups remaining_url = 'stats/groupdesc' + "/" + str(dpid) resp, content = self.h.request(self.baseUrlRyu + remaining_url, "GET") time.sleep(request_gap) if resp["status"] == "200": switch_groups = json.loads(content) this_ryu_switch["groups"] = switch_groups[str(dpid)] else: print "Error pulling switch ports from RYU." ryu_switches[dpid] = this_ryu_switch with open(self.conf_path + "ryu_switches.json", "w") as outfile: json.dump(ryu_switches, outfile) def get_host_nodes(self): mininet_host_nodes = {} for sw in self.topo.switches(): mininet_host_nodes[sw] = [] for h in self.get_all_switch_hosts(sw): mininet_host_dict = {"host_switch_id": "s" + sw[1:], "host_name": h.name, "host_IP": h.IP(), "host_MAC": h.MAC()} mininet_host_nodes[sw].append(mininet_host_dict) with open(self.conf_path + "mininet_host_nodes.json", "w") as outfile: json.dump(mininet_host_nodes, outfile) return mininet_host_nodes def get_links(self): mininet_port_links = {} with open(self.conf_path + "mininet_port_links.json", "w") as outfile: json.dump(self.topo.ports, outfile) return mininet_port_links # mhasan : for different params in different links def get_link_params(self): mininet_link_params = self.topo.link_params with open(self.conf_path + "mininet_link_params.json", "w") as outfile: json.dump(mininet_link_params, outfile) return mininet_link_params def get_switches(self): # Now the output of synthesis is carted away if self.controller == "ryu": self.get_ryu_switches() else: raise NotImplemented def init_flow_specs(self): for fs in self.flow_specs: fs.ng_src_host = self.ng.get_node_object(fs.src_host_id) fs.ng_dst_host = self.ng.get_node_object(fs.dst_host_id) if self.mininet_obj: fs.mn_src_host = self.mininet_obj.getNodeByName(fs.src_host_id) fs.mn_dst_host = self.mininet_obj.getNodeByName(fs.dst_host_id) def setup_network_graph(self, mininet_setup_gap=None, synthesis_setup_gap=None): self.start_mininet() if mininet_setup_gap: time.sleep(mininet_setup_gap) # These things are needed by network graph... self.get_host_nodes() self.get_links() # mhasan : for link params self.get_link_params() self.get_switches() self.ng = NetworkGraph(network_configuration=self) self.ng.parse_network_graph() # Now the synthesis... if synthesis_setup_gap: time.sleep(synthesis_setup_gap) # Refresh just the switches in the network graph, post synthesis self.get_switches() self.ng.parse_switches() # TODO: Figure out a new home for these two self.synthesis.network_graph = self.ng self.synthesis.mininet_obj = self.mininet_obj self.synthesis.synthesis_lib = SynthesisLib("localhost", "8181", self.ng) return self.ng def get_random_link_data(self, node1, node2): delay = int(self.topo_link_params["delay"].replace('us', '')) delay = random.randint(delay / 5, delay) # get a random delay link_data = NetworkGraphLinkData(node1, None, node2, None, None, self.topo_link_params['bw'] * 1000000, # in BPS # convert to float and microsecond to second float(delay) * 0.000001) return link_data def setup_network_graph_without_mininet(self): #TODO nw_graph = nx.Graph() switch_names = [] # setup the switchs for i in xrange(self.topo_params["num_switches"]): nw_graph.add_node("s" + str(i+1)) switch_names.append("s" + str(i+1)) # add hosts per switch for j in xrange(self.topo_params["num_hosts_per_switch"]): nw_graph.add_node("h" + str(i+1) + str(j+1)) # add link link_data = self.get_random_link_data("s" + str(i+1), "h" + str(i+1) + str(j+1)) nw_graph.add_edge("s" + str(i + 1), "h" + str(i + 1) + str(j + 1), link_data=link_data) # Add links between switches if self.topo_params["num_switches"] > 1: for i in xrange(self.topo_params["num_switches"] - 1): link_data = self.get_random_link_data(switch_names[i], switch_names[i+1]) nw_graph.add_edge(switch_names[i], switch_names[i+1], link_data=link_data) # Form a ring only when there are more than two switches if self.topo_params["num_switches"] > 2: link_data = self.get_random_link_data(switch_names[0], switch_names[-1]) nw_graph.add_edge(switch_names[0], switch_names[-1], link_data=link_data) # create some random links nodelist = self.noncontiguoussample(self.topo_params["num_switches"] - 1, int(self.topo_params["num_switches"] / 2.0)) for i in range(len(nodelist) - 1): switch_names[nodelist[i]] link_data = self.get_random_link_data(switch_names[nodelist[i]], switch_names[nodelist[i + 1]]) nw_graph.add_edge(switch_names[nodelist[i]], switch_names[nodelist[i + 1]], link_data=link_data) # print 'adjacency matrix' # nx.write_adjlist(nw_graph, sys.stdout) # write adjacency list to screen # print 'end adjacency matrix' # print nw_graph.edges(data=True) self.ng = NetworkGraph(network_configuration=self) self.ng.graph = nw_graph return self.ng def noncontiguoussample(self, n, k): # How many numbers we're not picking total_skips = n - k # Distribute the additional skips across the range skip_cutoffs = random.sample(range(total_skips + 1), k) skip_cutoffs.sort() # Construct the final set of numbers based on our skip distribution samples = [] for index, skip_spot in enumerate(skip_cutoffs): # This is just some math-fu that translates indices within the # skips to values in the overall result. samples.append(1 + index + skip_spot) return samples def start_mininet(self): self.cleanup_mininet() intf = custom(TCIntf, bw=1000) self.mininet_obj = Mininet(topo=self.topo, intf=TCIntf, link=TCLink, cleanup=True, autoStaticArp=True, controller=lambda name: RemoteController(name, ip='127.0.0.1', port=self.controller_port), switch=partial(OVSSwitch, protocols='OpenFlow14')) self.mininet_obj.start() def cleanup_mininet(self): if self.mininet_obj: print "Mininet cleanup..." #self.mininet_obj.stop() os.system("sudo mn -c") def get_all_switch_hosts(self, switch_id): p = self.topo.ports for node in p: # Only look for this switch's hosts if node != switch_id: continue for switch_port in p[node]: dst_list = p[node][switch_port] dst_node = dst_list[0] if dst_node.startswith("h"): yield self.mininet_obj.get(dst_node) def _get_experiment_host_pair(self): for src_switch in self.topo.get_switches_with_hosts(): for dst_switch in self.topo.get_switches_with_hosts(): if src_switch == dst_switch: continue # Assume one host per switch src_host = "h" + src_switch[1:] + "1" dst_host = "h" + dst_switch[1:] + "1" src_host_node = self.mininet_obj.get(src_host) dst_host_node = self.mininet_obj.get(dst_host) yield (src_host_node, dst_host_node) def is_host_pair_pingable(self, src_host, dst_host): hosts = [src_host, dst_host] ping_loss_rate = self.mininet_obj.ping(hosts, '1') # If some packets get through, then declare pingable if ping_loss_rate < 100.0: return True else: # If not, do a double check: cmd_output = src_host.cmd("ping -c 3 " + dst_host.IP()) print cmd_output if cmd_output.find("0 received") != -1: return False else: return True def are_all_hosts_pingable(self): ping_loss_rate = self.mininet_obj.pingAll('1') # If some packets get through, then declare pingable if ping_loss_rate < 100.0: return True else: return False def get_intf_status(self, ifname): # set some symbolic constants SIOCGIFFLAGS = 0x8913 null256 = '\0'*256 # create a socket so we have a handle to query s = socket(AF_INET, SOCK_DGRAM) # call ioctl() to get the flags for the given interface result = fcntl.ioctl(s.fileno(), SIOCGIFFLAGS, ifname + null256) # extract the interface's flags from the return value flags, = struct.unpack('H', result[16:18]) # check "UP" bit and print a message up = flags & 1 return ('down', 'up')[up] def wait_until_link_status(self, sw_i, sw_j, intended_status): num_seconds = 0 for link in self.mininet_obj.links: if (sw_i in link.intf1.name and sw_j in link.intf2.name) or (sw_i in link.intf2.name and sw_j in link.intf1.name): while True: status_i = self.get_intf_status(link.intf1.name) status_j = self.get_intf_status(link.intf2.name) if status_i == intended_status and status_j == intended_status: break time.sleep(1) num_seconds +=1 return num_seconds def is_bi_connected_manual_ping_test(self, experiment_host_pairs_to_check, edges_to_try=None): is_bi_connected= True if not edges_to_try: edges_to_try = self.topo.g.edges() for edge in edges_to_try: # Only try and break switch-switch edges if edge[0].startswith("h") or edge[1].startswith("h"): continue for (src_host, dst_host) in experiment_host_pairs_to_check: is_pingable_before_failure = self.is_host_pair_pingable(src_host, dst_host) if not is_pingable_before_failure: print "src_host:", src_host, "dst_host:", dst_host, "are not connected." is_bi_connected = False break self.mininet_obj.configLinkStatus(edge[0], edge[1], 'down') self.wait_until_link_status(edge[0], edge[1], 'down') time.sleep(5) is_pingable_after_failure = self.is_host_pair_pingable(src_host, dst_host) self.mininet_obj.configLinkStatus(edge[0], edge[1], 'up') self.wait_until_link_status(edge[0], edge[1], 'up') time.sleep(5) is_pingable_after_restoration = self.is_host_pair_pingable(src_host, dst_host) if not is_pingable_after_failure == True: is_bi_connected = False print "Got a problem with edge:", edge, " for src_host:", src_host, "dst_host:", dst_host break return is_bi_connected def is_bi_connected_manual_ping_test_all_hosts(self, edges_to_try=None): is_bi_connected= True if not edges_to_try: edges_to_try = self.topo.g.edges() for edge in edges_to_try: # Only try and break switch-switch edges if edge[0].startswith("h") or edge[1].startswith("h"): continue is_pingable_before_failure = self.are_all_hosts_pingable() if not is_pingable_before_failure: is_bi_connected = False break self.mininet_obj.configLinkStatus(edge[0], edge[1], 'down') self.wait_until_link_status(edge[0], edge[1], 'down') time.sleep(5) is_pingable_after_failure = self.are_all_hosts_pingable() self.mininet_obj.configLinkStatus(edge[0], edge[1], 'up') self.wait_until_link_status(edge[0], edge[1], 'up') time.sleep(5) is_pingable_after_restoration = self.are_all_hosts_pingable() if not is_pingable_after_failure == True: is_bi_connected = False break return is_bi_connected # mhasan: calibrate delay based on network toplogy # mhasan: lower index -> lower delay budget -> higher priority def calibrate_delay(self, base_delay_budget): #self.min_delay_budget_for_all_flows = base_delay_budget # save for schedulability calculation diameter = nx.diameter(self.ng.get_node_graph()) self.network_diameter = diameter # save for schedulability calculation base_delay_budget *= diameter # vary with topology as Rakesh K. mentioned delta = base_delay_budget/10 # a fraction that increase the delay requirement from flow to flow #delta = base_delay_budget / 5 # a fraction that increase the delay requirement from flow to flow #delta = 5 * base_delay_budget # a fraction that increase the delay requirement from flow to flow for flow_id, current_flow in enumerate(self.flow_specs): # do for every odd (forward flow), reverse flow will be the same. if flow_id % 2 == 0: current_flow.delay_budget = base_delay_budget self.flow_specs[flow_id+1].delay_budget = base_delay_budget # for reverse flow base_delay_budget += delta
class NetworkConfiguration(object): def __init__(self, controller, controller_ip, controller_port, controller_api_base_url, controller_api_user_name, controller_api_password, topo_name, topo_params, conf_root, synthesis_name, synthesis_params): self.controller = controller self.topo_name = topo_name self.topo_params = topo_params self.topo_name = topo_name self.conf_root = conf_root self.synthesis_name = synthesis_name self.synthesis_params = synthesis_params self.controller_ip = controller_ip self.controller_port = controller_port self.topo = None self.nc_topo_str = None self.init_topo() self.init_synthesis() self.mininet_obj = None self.cm = None self.ng = None # Setup the directory for saving configs, check if one does not exist, # if not, assume that the controller, mininet and rule synthesis needs to be triggered. self.conf_path = self.conf_root + str(self) + "/" if not os.path.exists(self.conf_path): os.makedirs(self.conf_path) self.load_config = False self.save_config = True else: self.load_config = True self.save_config = False self.h = httplib2.Http() self.controller_api_base_url = controller_api_base_url self.controller_api_base_url = controller_api_base_url self.h.add_credentials(controller_api_user_name, controller_api_password) def __str__(self): return self.controller + "_" + str(self.synthesis) + "_" + str(self.topo) def __del__(self): if not self.load_config and self.save_config: if self.cm: self.cm.stop_controller() self.cleanup_mininet() def init_topo(self): if self.topo_name == "ring": self.topo = RingTopo(self.topo_params) self.nc_topo_str = "Ring topology with " + str(self.topo.total_switches) + " switches" elif self.topo_name == "wsc": self.topo = WSCTopo(self.topo_params) self.nc_topo_str = "WSC topology with " + str(self.topo.total_switches) + " switches" elif self.topo_name == "adhoc": self.topo = AdHocTopo(self.topo_params) self.nc_topo_str = "AdHoc topology with " + str(self.topo.total_switches) + " switches" elif self.topo_name == "clostopo": self.topo = ClosTopo(self.topo_params) self.nc_topo_str = "Clos topology with " + str(self.topo.total_switches) + " switches" elif self.topo_name == "cliquetopo": self.topo = CliqueTopo(self.topo_params) self.nc_topo_str = "Clique topology with " + str(self.topo.total_switches) + " switches" elif self.topo_name == "linear": self.topo = LinearTopo(self.topo_params) self.nc_topo_str = "Linear topology with " + str(self.topo_params["num_switches"]) + " switches" elif self.topo_name == "microgrid_topo": self.topo = MicrogridsTopo(self.topo_params) self.nc_topo_str = "Microgrid topology with " + str(self.topo_params["num_switches"]) + " switches " + str(self.topo_params["nHostsPerSwitch"]) + " hps" else: raise NotImplementedError("Topology: %s" % self.topo_name) def init_synthesis(self): if self.synthesis_name == "DijkstraSynthesis": self.synthesis_params["master_switch"] = self.topo_name == "linear" self.synthesis = DijkstraSynthesis(self.synthesis_params) elif self.synthesis_name == "AboresceneSynthesis": self.synthesis = AboresceneSynthesis(self.synthesis_params) elif self.synthesis_name == "VPLSSynthesis": self.synthesis = self.synthesis_name else: self.synthesis = None def trigger_synthesis(self, synthesis_setup_gap, flow_specs): if self.synthesis_name == "DijkstraSynthesis": self.synthesis.network_graph = self.ng self.synthesis.network_configuration = self self.synthesis.synthesis_lib = SynthesisLib("localhost", "8181", self.ng, self) if flow_specs: self.synthesis.synthesize_node_pairs(flow_specs["src_hosts"], flow_specs["dst_hosts"]) else: self.synthesis.synthesize_all_node_pairs() elif self.synthesis_name == "AboresceneSynthesis": self.synthesis.network_graph = self.ng self.synthesis.network_configuration = self self.synthesis.synthesis_lib = SynthesisLib("localhost", "8181", self.ng, self) flow_match = Match(is_wildcard=True) flow_match["ethernet_type"] = 0x0800 self.synthesis.synthesize_all_switches(flow_match) if synthesis_setup_gap: time.sleep(synthesis_setup_gap) if self.mininet_obj: pass #self.mininet_obj.pingAll() #CLI(self.mininet_obj) #is_bi_connected = self.is_bi_connected_manual_ping_test_all_hosts_single_link() # self.is_pingable_all_two_link_failures() # is_bi_connected = self.is_bi_connected_manual_ping_test([(self.mininet_obj.get('h11'), self.mininet_obj.get('h31'))]) # is_bi_connected = self.is_bi_connected_manual_ping_test([(self.mininet_obj.get('h11'), # self.mininet_obj.get('h41'))], # [('s1', 's3')]) # print "is_bi_connected:", is_bi_connected # h1 is disconnected from everyone # self.is_host_pair_pingable_after_two_failures(self.mininet_obj.get('h41'), # self.mininet_obj.get('h11'), # (('s1', 's3', 1), ('s1', 's2', 1))) def is_host_pair_pingable_after_two_failures(self, src_host, dst_host, edges): self.is_host_pair_pingable(src_host, dst_host) self.mininet_obj.configLinkStatus(edges[0][0], edges[0][1], 'down') self.wait_until_link_status(edges[0][0], edges[0][1], 'down') time.sleep(5) self.is_host_pair_pingable(src_host, dst_host) self.mininet_obj.configLinkStatus(edges[1][0], edges[1][1], 'down') self.wait_until_link_status(edges[1][0], edges[1][1], 'down') time.sleep(5) self.is_host_pair_pingable(src_host, dst_host) self.mininet_obj.configLinkStatus(edges[0][0], edges[0][1], 'up') self.wait_until_link_status(edges[0][0], edges[0][1], 'up') time.sleep(5) self.is_host_pair_pingable(src_host, dst_host) self.mininet_obj.configLinkStatus(edges[1][0], edges[1][1], 'up') self.wait_until_link_status(edges[1][0], edges[1][1], 'up') time.sleep(5) self.is_host_pair_pingable(src_host, dst_host) def is_pingable_all_two_link_failures(self): lmbdas = list(itertools.combinations_with_replacement(self.topo.g.edges(), 2)) for edges in lmbdas: if edges[0][0].startswith("h") or edges[0][1].startswith("h"): continue if edges[1][0].startswith("h") or edges[1][1].startswith("h"): continue print edges self.mininet_obj.configLinkStatus(edges[0][0], edges[0][1], 'down') self.wait_until_link_status(edges[0][0], edges[0][1], 'down') time.sleep(5) self.mininet_obj.configLinkStatus(edges[1][0], edges[1][1], 'down') self.wait_until_link_status(edges[1][0], edges[1][1], 'down') time.sleep(5) self.are_all_hosts_pingable() self.mininet_obj.configLinkStatus(edges[0][0], edges[0][1], 'up') self.wait_until_link_status(edges[0][0], edges[0][1], 'up') time.sleep(5) self.mininet_obj.configLinkStatus(edges[1][0], edges[1][1], 'up') self.wait_until_link_status(edges[1][0], edges[1][1], 'up') time.sleep(5) def get_ryu_switches(self): if not self.load_config and self.save_config: ryu_switches = {} # Get all the ryu_switches from the inventory API remaining_url = 'stats/switches' resp, content = self.h.request(self.controller_api_base_url + remaining_url, "GET") ryu_switch_numbers = json.loads(content) for dpid in ryu_switch_numbers: this_ryu_switch = {} # Get the flows remaining_url = 'stats/flow' + "/" + str(dpid) resp, content = self.h.request(self.controller_api_base_url + remaining_url, "GET") if resp["status"] == "200": switch_flows = json.loads(content) switch_flow_tables = defaultdict(list) for flow_rule in switch_flows[str(dpid)]: switch_flow_tables[flow_rule["table_id"]].append(flow_rule) this_ryu_switch["flow_tables"] = switch_flow_tables else: print "Error pulling switch flows from RYU." # Get the ports remaining_url = 'stats/portdesc' + "/" + str(dpid) resp, content = self.h.request(self.controller_api_base_url + remaining_url, "GET") if resp["status"] == "200": switch_ports = json.loads(content) this_ryu_switch["ports"] = switch_ports[str(dpid)] else: print "Error pulling switch ports from RYU." # Get the groups remaining_url = 'stats/groupdesc' + "/" + str(dpid) resp, content = self.h.request(self.controller_api_base_url + remaining_url, "GET") if resp["status"] == "200": switch_groups = json.loads(content) this_ryu_switch["groups"] = switch_groups[str(dpid)] else: print "Error pulling switch ports from RYU." ryu_switches[dpid] = this_ryu_switch with open(self.conf_path + "ryu_switches.json", "w") as outfile: json.dump(ryu_switches, outfile, indent=4) else: with open(self.conf_path + "ryu_switches.json", "r") as in_file: ryu_switches = json.loads(in_file.read()) return ryu_switches def get_onos_switches(self): if not self.load_config and self.save_config: # Get all the onos_switches from the inventory API remaining_url = 'devices' resp, content = self.h.request(self.controller_api_base_url + remaining_url, "GET") onos_switches = json.loads(content) for this_switch in onos_switches["devices"]: if this_switch["available"]: # Get the flows remaining_url = 'flows' + "/" + this_switch["id"] resp, content = self.h.request(self.controller_api_base_url + remaining_url, "GET") if resp["status"] == "200": switch_flows = json.loads(content) switch_flow_tables = defaultdict(list) for flow_rule in switch_flows["flows"]: switch_flow_tables[flow_rule["tableId"]].append(flow_rule) this_switch["flow_tables"] = switch_flow_tables else: print "Error pulling switch flows from Onos." # Get the ports remaining_url = 'devices' + "/" + this_switch["id"] + "/ports" resp, content = self.h.request(self.controller_api_base_url + remaining_url, "GET") if resp["status"] == "200": this_switch["ports"] = json.loads(content)["ports"] else: print "Error pulling switch ports from RYU." # Get the groups remaining_url = 'groups' + "/" + this_switch["id"] resp, content = self.h.request(self.controller_api_base_url + remaining_url, "GET") if resp["status"] == "200": this_switch["groups"] = json.loads(content)["groups"] else: print "Error pulling switch ports from RYU." with open(self.conf_path + "onos_switches.json", "w") as outfile: json.dump(onos_switches, outfile, indent=4) else: with open(self.conf_path + "onos_switches.json", "r") as in_file: onos_switches = json.loads(in_file.read()) return onos_switches def get_mininet_host_nodes(self): if not self.load_config and self.save_config: mininet_host_nodes = {} for sw in self.topo.switches(): mininet_host_nodes[sw] = [] for h in self.get_all_switch_hosts(sw): mininet_host_dict = {"host_switch_id": "s" + sw[1:], "host_name": h.name, "host_IP": h.IP(), "host_MAC": h.MAC()} mininet_host_nodes[sw].append(mininet_host_dict) with open(self.conf_path + "mininet_host_nodes.json", "w") as outfile: json.dump(mininet_host_nodes, outfile, indent=4) else: with open(self.conf_path + "mininet_host_nodes.json", "r") as in_file: mininet_host_nodes = json.loads(in_file.read()) return mininet_host_nodes def get_onos_host_nodes(self): if not self.load_config and self.save_config: # Get all the onos_hosts from the inventory API remaining_url = 'hosts' resp, content = self.h.request(self.controller_api_base_url + remaining_url, "GET") onos_hosts = json.loads(content)["hosts"] with open(self.conf_path + "onos_hosts.json", "w") as outfile: json.dump(onos_hosts, outfile, indent=4) else: with open(self.conf_path + "onos_hosts.json", "r") as in_file: onos_hosts = json.loads(in_file.read()) return onos_hosts def get_host_nodes(self): if self.controller == "ryu": return self.get_mininet_host_nodes() elif self.controller == "onos": return self.get_onos_host_nodes() else: raise NotImplemented def get_mininet_links(self): if not self.load_config and self.save_config: mininet_port_links = self.topo.ports with open(self.conf_path + "mininet_port_links.json", "w") as outfile: json.dump(mininet_port_links, outfile, indent=4) else: with open(self.conf_path + "mininet_port_links.json", "r") as in_file: mininet_port_links = json.loads(in_file.read()) return mininet_port_links def get_onos_links(self): if not self.load_config and self.save_config: # Get all the onos_links from the inventory API remaining_url = 'links' resp, content = self.h.request(self.controller_api_base_url + remaining_url, "GET") onos_links = json.loads(content)["links"] with open(self.conf_path + "onos_links.json", "w") as outfile: json.dump(onos_links, outfile, indent=4) else: with open(self.conf_path + "onos_links.json", "r") as in_file: onos_links = json.loads(in_file.read()) return onos_links def get_all_links(self): if self.controller == "ryu": return self.get_mininet_links() elif self.controller == "onos": return self.get_onos_links() else: raise NotImplementedError def get_switches(self): # Now the output of synthesis is carted away if self.controller == "ryu": return self.get_ryu_switches() elif self.controller == "onos": return self.get_onos_switches() else: raise NotImplementedError def setup_network_graph(self, mininet_setup_gap=None, synthesis_setup_gap=None, flow_specs=None): if not self.load_config and self.save_config: if self.controller == "ryu": self.cm = ControllerMan(controller=self.controller) self.cm.start_controller() time.sleep(5) self.start_mininet() if mininet_setup_gap: time.sleep(mininet_setup_gap) elif self.controller == "sel": self.start_mininet() if mininet_setup_gap: time.sleep(mininet_setup_gap) # These things are needed by network graph... switches = self.get_switches() hosts = self.get_host_nodes() links = self.get_all_links() self.ng = NetworkGraph(self.controller) self.ng.parse_network_graph(switches, (hosts, links), links) if self.synthesis_name: # Now the synthesis... self.trigger_synthesis(synthesis_setup_gap, flow_specs) # Refresh just the switches in the network graph, post synthesis switches = self.get_switches() self.ng.parse_network_graph(switches, (hosts, links), links) else: # These things are needed by the network graph... switches = self.get_switches() hosts = self.get_host_nodes() links = self.get_all_links() self.ng = NetworkGraph(self.controller) self.ng.parse_network_graph(switches, (hosts, links), links) return self.ng def start_mininet(self): self.cleanup_mininet() if self.controller == "ryu": self.mininet_obj = Mininet(topo=self.topo, cleanup=True, autoStaticArp=True, controller=lambda name: RemoteController(name, ip=self.controller_ip, port=self.controller_port), switch=partial(OVSSwitch, protocols='OpenFlow14')) self.mininet_obj.start() elif self.controller == "sel": subprocess.call(["sudo", "ovs-vsctl", "set-ssl", "/etc/openvswitch/switchkey.pem", "/etc/openvswitch/switchcert.pem", "/var/lib/openvswitch/pki/controllerca/fullca.pem"]) self.mininet_obj = Mininet(topo=self.topo, cleanup=True, autoStaticArp=True, controller=lambda name: RemoteController(name, protocol="ssl", ip=self.controller_ip, port=self.controller_port), switch=partial(OVSSwitch, protocols='OpenFlow13')) self.mininet_obj.start() def cleanup_mininet(self): # Do clean ups only for mininets that were spawned by this guy if self.mininet_obj: print "Mininet cleanup..." self.mininet_obj.stop() os.system("sudo mn -c") def get_all_switch_hosts(self, switch_id): p = self.topo.ports for node in p: # Only look for this switch's hosts if node != switch_id: continue for switch_port in p[node]: dst_list = p[node][switch_port] dst_node = dst_list[0] if dst_node.startswith("h"): yield self.mininet_obj.get(dst_node) def _get_experiment_host_pair(self): for src_switch in self.topo.get_switches_with_hosts(): for dst_switch in self.topo.get_switches_with_hosts(): if src_switch == dst_switch: continue # Assume one host per switch src_host = "h" + src_switch[1:] + "1" dst_host = "h" + dst_switch[1:] + "1" src_host_node = self.mininet_obj.get(src_host) dst_host_node = self.mininet_obj.get(dst_host) yield (src_host_node, dst_host_node) def is_host_pair_pingable(self, src_host, dst_host): hosts = [src_host, dst_host] ping_loss_rate = self.mininet_obj.ping(hosts, '1') # If some packets get through, then declare pingable if ping_loss_rate < 100.0: return True else: # If not, do a double check: cmd_output = src_host.cmd("ping -c 3 " + dst_host.IP()) print cmd_output if cmd_output.find("0 received") != -1: return False else: return True def are_all_hosts_pingable(self): ping_loss_rate = self.mininet_obj.pingAll('1') # If some packets get through, then declare pingable if ping_loss_rate < 100.0: return True else: return False def get_intf_status(self, ifname): # set some symbolic constants SIOCGIFFLAGS = 0x8913 null256 = '\0'*256 # create a socket so we have a handle to query s = socket(AF_INET, SOCK_DGRAM) # call ioctl() to get the flags for the given interface result = fcntl.ioctl(s.fileno(), SIOCGIFFLAGS, ifname + null256) # extract the interface's flags from the return value flags, = struct.unpack('H', result[16:18]) # check "UP" bit and print a message up = flags & 1 return ('down', 'up')[up] def wait_until_link_status(self, sw_i, sw_j, intended_status): num_seconds = 0 for link in self.mininet_obj.links: if (sw_i in link.intf1.name and sw_j in link.intf2.name) or (sw_i in link.intf2.name and sw_j in link.intf1.name): while True: status_i = self.get_intf_status(link.intf1.name) status_j = self.get_intf_status(link.intf2.name) if status_i == intended_status and status_j == intended_status: break time.sleep(1) num_seconds +=1 return num_seconds def is_bi_connected_manual_ping_test(self, experiment_host_pairs_to_check, edges_to_try=None): is_bi_connected = True if not edges_to_try: edges_to_try = self.topo.g.edges() for edge in edges_to_try: # Only try and break switch-switch edges if edge[0].startswith("h") or edge[1].startswith("h"): continue for (src_host, dst_host) in experiment_host_pairs_to_check: is_pingable_before_failure = self.is_host_pair_pingable(src_host, dst_host) if not is_pingable_before_failure: print "src_host:", src_host, "dst_host:", dst_host, "are not connected." is_bi_connected = False break self.mininet_obj.configLinkStatus(edge[0], edge[1], 'down') self.wait_until_link_status(edge[0], edge[1], 'down') time.sleep(5) is_pingable_after_failure = self.is_host_pair_pingable(src_host, dst_host) self.mininet_obj.configLinkStatus(edge[0], edge[1], 'up') self.wait_until_link_status(edge[0], edge[1], 'up') time.sleep(5) is_pingable_after_restoration = self.is_host_pair_pingable(src_host, dst_host) if not is_pingable_after_failure == True: is_bi_connected = False print "Got a problem with edge:", edge, " for src_host:", src_host, "dst_host:", dst_host break return is_bi_connected def is_bi_connected_manual_ping_test_all_hosts_single_link(self, edges_to_try=None): is_bi_connected = True if not edges_to_try: edges_to_try = self.topo.g.edges() for edge in edges_to_try: # Only try and break switch-switch edges if edge[0].startswith("h") or edge[1].startswith("h"): continue print "Failed Edge:", edge is_pingable_before_failure = self.are_all_hosts_pingable() if not is_pingable_before_failure: is_bi_connected = False break self.mininet_obj.configLinkStatus(edge[0], edge[1], 'down') self.wait_until_link_status(edge[0], edge[1], 'down') time.sleep(5) is_pingable_after_failure = self.are_all_hosts_pingable() self.mininet_obj.configLinkStatus(edge[0], edge[1], 'up') self.wait_until_link_status(edge[0], edge[1], 'up') time.sleep(5) is_pingable_after_restoration = self.are_all_hosts_pingable() if not is_pingable_after_failure == True: is_bi_connected = False break return is_bi_connected def parse_iperf_output(self, iperf_output_string): data_lines = iperf_output_string.split('\r\n') interesting_line_index = None for i in xrange(len(data_lines)): if data_lines[i].endswith('Server Report:'): interesting_line_index = i + 1 data_tokens = data_lines[interesting_line_index].split() print "Transferred Rate:", data_tokens[7] print "Jitter:", data_tokens[9] def parse_ping_output(self,ping_output_string): data_lines = ping_output_string.split('\r\n') interesting_line_index = None for i in xrange(len(data_lines)): if data_lines[i].startswith('5 packets transmitted'): interesting_line_index = i + 1 data_tokens = data_lines[interesting_line_index].split() data_tokens = data_tokens[3].split('/') print 'Min Delay:', data_tokens[0] print 'Avg Delay:', data_tokens[1] print 'Max Delay:', data_tokens[2]
class MininetWrapper(object): def __init__(self): self.mininet_client = None self.topology = [] self.delay = None def set_delay(self, delay): delay = str(int(delay)) + 'ms' self.delay = delay def run_mininet(self, topology_string): """ Create and run multiple link network """ self.topo_client = Topo() hosts = set() switches = set() relations = re.sub(r's', '', topology_string) relations = [ i.split(':') for i in relations.split(',') if 'h' not in i ] relations = [[int(y) - 1 for y in x] for x in relations] builtin.log(relations, 'DEBUG') verticles_count = len(set(list(itertools.chain(*relations)))) builtin.log(self.topology, 'DEBUG') for i in xrange(verticles_count): temp = [] for j in xrange(verticles_count): temp.append(-1) self.topology.append(temp[:]) builtin.log(self.topology, 'DEBUG') for i in relations: self.topology[i[0]][i[1]] = 1 self.topology[i[1]][i[0]] = 1 builtin.log(self.topology, 'DEBUG') for v1, v2 in [x.split(':') for x in str(topology_string).split(',')]: if 'h' in v1 and v1 not in hosts: self.topo_client.addHost(v1) hosts.add(v1) if 'h' in v2 and v2 not in hosts: self.topo_client.addHost(v2) hosts.add(v2) if 's' in v1 and v1 not in switches: self.topo_client.addSwitch(v1) switches.add(v1) if 's' in v2 and v2 not in switches: self.topo_client.addSwitch(v2) switches.add(v2) if self.delay: self.topo_client.addLink(v1, v2, delay=self.delay) else: self.topo_client.addLink(v1, v2) self.mininet_client = Mininet(switch=user_switch, controller=remote_controller, topo=self.topo_client, link=TCLink) self.mininet_client.start() builtin.log('Links info:') for link in self.topo_client.links(withKeys=True, withInfo=True): builtin.log(link) # self.mininet_client.waitConnected(timeout=20) sleep(20) def stop_mininet(self): if self.mininet_client is not None: self.mininet_client.stop() if self.topology: self.topology = [] self.delay = None cleanup() sleep(20) def kill_link(self, host1, host2): host1, host2 = str(host1), str(host2) self.mininet_client.configLinkStatus(host1, host2, 'down') if 'h' not in host1 and 'h' not in host2: num_1 = int(host1[1:]) - 1 num_2 = int(host2[1:]) - 1 self.topology[num_1][num_2] = -1 self.topology[num_2][num_1] = -1 builtin.log(self.topology, 'DEBUG') builtin.log('Down link {0} - {1}'.format(host1, host2), 'DEBUG') def check_link(self, host1, host2): switch = self.mininet_client.getNodeByName(host1) connections = switch.connectionsTo(host2) if connections: return True else: return False def up_link(self, host1, host2): host1, host2 = str(host1), str(host2) self.mininet_client.configLinkStatus(host1, host2, 'up') if 'h' not in host1 and 'h' not in host2: num_1 = int(host1[1:]) - 1 num_2 = int(host2[1:]) - 1 self.topology[num_1][num_2] = 1 self.topology[num_2][num_1] = 1 builtin.log(self.topology, 'DEBUG') builtin.log('Up link {0} - {1}'.format(host1, host2), 'DEBUG') def stop_node(self, name): node = self.mininet_client.getNodeByName(name) node.stop() num_node = int(name[1:]) - 1 self.topology[num_node][num_node] = -1 builtin.log('Node {0} was stoped'.format(name), 'DEBUG') def check_connected_node(self, name): switch = self.mininet_client.getNodeByName(name) return switch.connected() # NOTE(msenin) unstable method - after stoping mininet cant start node # mininet doesn't return exception def start_node(self, name): node = self.mininet_client.getNodeByName(name) # TODO (msenin) add option controller_name controllers = self.mininet_client.controllers builtin.log('Controllers: {0}'.format(controllers), 'DEBUG') node.start([controllers[0]]) def check_rules(self): switches = self.mininet_client.switches results = [] regex = (r'(cookie=[\w\d]+),|(dl_dst=[\w\d:\/]{35})' '|(priority=[\d]+),|(dl_src=[\w\d:\/]{17})') for switch in switches: ans = switch.dpctl('dump-flows -O OpenFlow13') builtin.log( 'Rules on the switch {0}: {1}'.format(switch.name, ans), 'DEBUG') ans_with_regex = "" for m in re.finditer(regex, ans): for i in xrange(1, 5): if m.group(i): ans_with_regex = ans_with_regex + ', ' + m.group(i) builtin.log('Rules with regex {0}: {1}'.format(switch.name, ans), 'DEBUG') results.append({switch.name: ans_with_regex}) return results def compare_dumped_flows(self, rules1, rules2): rules_1 = str(rules1) rules_2 = str(rules2) builtin.log('Compare two flow tables(without changing parts): ', 'DEBUG') builtin.log(rules_1, 'DEBUG') builtin.log(rules_2, 'DEBUG') if rules_1 != rules_2: return False return True def ping(self, name1, name2): node1 = self.mininet_client.getNodeByName(name1) node2 = self.mininet_client.getNodeByName(name2) ping = self.mininet_client.ping(hosts=[node1, node2], timeout=10) num1, num2 = name1[1:], name2[1:] cmd1 = node1.cmd('ifconfig') builtin.log('{0}'.format(cmd1), 'DEBUG') cmd1 = node1.cmd('ping -d -c 5 -w 5 10.0.0.' + num2) builtin.log('{0}'.format(cmd1), 'DEBUG') cmd2 = node2.cmd('ifconfig') builtin.log('{0}'.format(cmd2), 'DEBUG') cmd1 = node2.cmd('ping -d -c 5 -w 5 10.0.0.' + num1) builtin.log('{0}'.format(cmd1), 'DEBUG') return int(ping) def check_route_state(self, route): # TODO (msenin) delete method after tests refactoring """Check the state of route :param route: list with verticles (each verticle is switch id) """ route = map(lambda x: int(x) - 1, route) for i in xrange(1, len(route)): prev = route[i - 1] cur = route[i] if (self.topology[prev][prev] == -1 or self.topology[cur][cur] == -1): return False if self.topology[prev][cur] == -1: return False return True def contains_route_in_routes(self, route, routes): builtin.log("route: {0}".format(route), 'DEBUG') builtin.log("routes: {0}".format(routes), 'DEBUG') route = map(lambda x: int(x), route) for i in routes: if i.get('route') and map(lambda x: int(x), i['route']) == route: return True return False def parse_tree(self, resp): """Define and check the routes and links :param resp:json from response """ builtin.log("JSON for parsing: {0}".format(resp), 'DEBUG') source_node_list = set() destination_node_list = set() links_dict = collections.OrderedDict() routes = [] states_dict = dict() route_container = resp.get('route-container') route_list = route_container.get('route-list') route_list_length = len(route_list) # TODO for i in range(0, route_list_length): needed_leaf = i route_leaf = route_list[needed_leaf] leaf_source = route_leaf.get('source') leaf_destination = route_leaf.get('destination') states_dict['source'] = leaf_source states_dict['destination'] = leaf_destination route = route_leaf.get('route', []) for i in range(0, len(route)): route_state = dict() vertexes = set() path = route[i] state = path.get('state') route_state['state'] = state route_state['route'] = vertexes routes.append(route_state) states_dict['routes'] = routes links = path.get('path') links_count = len(links) for j in range(0, links_count): link = links[j] link_source = link.get('source') link_destination = link.get('destination') source_node = link_source.get('source-node') destination_node = link_destination.get('dest-node') source_flow = source_node.split(':')[-1] destination_flow = destination_node.split(':')[-1] vertexes.add(source_flow) vertexes.add(destination_flow) source_node_list.add(source_node) destination_node_list.add(destination_node) links_dict[source_node] = destination_node return states_dict def parse_tree_2(self, resp): """Parse output json from ncn restconfig :param resp:json from response [{'state': 'up', 'destination': '4', 'route': ['1', '4'], 'source': '1', 'id': 100}, .................................................................... {'destination': '3', 'source': '1'}, {'destination': '7', 'source': '1'}] """ builtin.log("JSON for parsing: {0}".format(resp), 'DEBUG') routes = [] route_list = resp.get('route-container').get('route-list') for routes_between_switches in route_list: routes_rest_conf = routes_between_switches.get("route") if routes_rest_conf: # NOTE (msenin) # format of fields 'source' and 'destination': openflow:4 for route_rest in routes_rest_conf: route = {} route['source'] = int(route_rest['source'][9:]) route['destination'] = \ int(route_rest['destination'][9:]) route['state'] = route_rest['state'] pathes = route_rest.get('path') route['id'] = route_rest.get('id') path = [] for link in pathes: link_source = link.get('source') link_destination = link.get('destination') source_node = link_source.get('source-node') destination_node = link_destination.get('dest-node') source_flow = int(source_node[9:]) destination_flow = int(destination_node[9:]) if source_flow not in path: path.append(source_flow) if destination_flow not in path: path.append(destination_flow) route['route'] = path routes.append(route) else: route = {} route['source'] = int(routes_between_switches['source'][9:]) route['destination'] = \ int(routes_between_switches['destination'][9:]) routes.append(route) return routes def check_route_state_by_DOM_tree(self, route, tree): """ return 1 if route up, -1 down and 0 if unexist """ if isinstance(route, str) or isinstance(route, unicode): route = list(route[1:-1].split(',')) route = map(lambda x: int(x), route) builtin.log("route: {0}".format(route), 'DEBUG') tree = self.parse_tree_2(tree) builtin.log("tree: {0}".format(tree), 'DEBUG') filtered_tree = filter(lambda x: x.get('route') == route, tree) if filtered_tree: if filtered_tree[0]['state'] == 'up': return 1 else: return -1 else: return 0 def filter_DOM_tree_by_field(self, condition, tree): # TODO (msenin) add logger tree = self.parse_tree_2(tree) filtered_tree = filter(lambda field: eval(condition), tree) return filtered_tree
def runMinimalTopo(): "Bootstrap a Mininet network using the Minimal Topology" # Create an instance of our topology topo = MinimalTopo() # Create a network based on the topology using OVS and controlled by # a remote controller. net = Mininet(topo=topo, controller=lambda name: RemoteController( name, ip='127.0.0.1', port=6653), switch=OVSSwitch, autoSetMacs=True) # list = makeSwitches(topo, 8) # Actually start the network net.start() # print "-------start sleeping--------" # time.sleep(3) #print "-------start pinging/netvorky--------" s1 = net.getNodeByName("s1") s1.cmd('ovs-vsctl set Bridge s1 protocols=OpenFlow13') s2 = net.getNodeByName("s2") s2.cmd('ovs-vsctl set Bridge s2 protocols=OpenFlow13') h1 = net.getNodeByName("h1") #h1.cmd('ip addr del 10.0.0.1/8 dev h1-eth0') #h1.cmd('ip addr add 10.1.1.13/24 dev h1-eth0') h1.cmd('ip route add default via 10.1.1.1') #print h1.cmd('ping 10.1.1.1 -c 2') h2 = net.getNodeByName("h2") #h2.cmd('ip addr del 10.0.0.2/8 dev h2-eth0') #h2.cmd('ip addr add 10.1.2.13/24 dev h2-eth0') h2.cmd('ip route add default via 10.1.2.1') #net.links. # print h2.cmd('ping 10.1.2.1 -c 2') # print h2.cmd('ping 10.1.1.1 -c 2') # time.sleep(1) # print h2.cmd('ping 10.1.1.1 -c 2') # time.sleep(1) # print h2.cmd('ping 10.1.1.1 -c 2') # time.sleep(1) # print h2.cmd('ping 10.1.1.13 -c 2') #h1 ping 10.1.1.1 -c 2 #print s2.cmd('ifconfig') # Drop the user in to a CLI so user can run commands. CLI(net) print "[DELETE]", call([ "curl", "-X DELETE", "-d {\"route_id\": \"all\"}", "-v", "http://localhost:8080/router/all" ]) net.configLinkStatus("s1", "s2", "down") # print h2.cmd('ping 10.1.2.1 -c 25') print "HOTOVOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" CLI(net) print "[DELETE]", call([ "curl", "-X DELETE", "-d {\"route_id\": \"all\"}", "-v", "http://localhost:8080/router/all", "--trace-ascii", "/dev/stdout" ]) net.configLinkStatus("s1", "s2", "up") print h2.cmd('ping 10.1.2.1 -c 20') CLI(net) print "[DELETE]", call([ "curl", "-X DELETE", "-d {\"route_id\": \"all\"}", "-v", "http://localhost:8080/router/all" ]) net.configLinkStatus("s1", "s2", "down") # print h2.cmd('ping 10.1.2.1 -c 25') print "HOTOVOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" CLI(net) print "[DELETE]", call([ "curl", "-X DELETE", "-d {\"route_id\": \"all\"}", "-v", "http://localhost:8080/router/all", "--trace-ascii", "/dev/stdout" ]) net.configLinkStatus("s1", "s2", "up") print h2.cmd('ping 10.1.2.1 -c 20') CLI(net) print "[DELETE]", call([ "curl", "-X DELETE", "-d {\"route_id\": \"all\"}", "-v", "http://localhost:8080/router/all" ]) net.configLinkStatus("s1", "s2", "down") # print h2.cmd('ping 10.1.2.1 -c 25') print "HOTOVOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" CLI(net) print "[DELETE]", call([ "curl", "-X DELETE", "-d {\"route_id\": \"all\"}", "-v", "http://localhost:8080/router/all", "--trace-ascii", "/dev/stdout" ]) net.configLinkStatus("s1", "s2", "up") print h2.cmd('ping 10.1.2.1 -c 20') CLI(net) print "[DELETE]", call([ "curl", "-X DELETE", "-d {\"route_id\": \"all\"}", "-v", "http://localhost:8080/router/all" ]) net.configLinkStatus("s1", "s2", "down") # print h2.cmd('ping 10.1.2.1 -c 25') print "HOTOVOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" CLI(net) print "[DELETE]", call([ "curl", "-X DELETE", "-d {\"route_id\": \"all\"}", "-v", "http://localhost:8080/router/all", "--trace-ascii", "/dev/stdout" ]) net.configLinkStatus("s1", "s2", "up") print h2.cmd('ping 10.1.2.1 -c 20') CLI(net) print "[DELETE]", call([ "curl", "-X DELETE", "-d {\"route_id\": \"all\"}", "-v", "http://localhost:8080/router/all" ]) net.configLinkStatus("s1", "s2", "down") # print h2.cmd('ping 10.1.2.1 -c 25') print "HOTOVOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" CLI(net) print "[DELETE]", call([ "curl", "-X DELETE", "-d {\"route_id\": \"all\"}", "-v", "http://localhost:8080/router/all", "--trace-ascii", "/dev/stdout" ]) net.configLinkStatus("s1", "s2", "up") CLI(net) print "[DELETE]", call([ "curl", "-X DELETE", "-d {\"route_id\": \"all\"}", "-v", "http://localhost:8080/router/all" ]) net.configLinkStatus("s1", "s2", "down") # print h2.cmd('ping 10.1.2.1 -c 25') print "HOTOVOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" CLI(net) print "[DELETE]", call([ "curl", "-X DELETE", "-d {\"route_id\": \"all\"}", "-v", "http://localhost:8080/router/all", "--trace-ascii", "/dev/stdout" ]) net.configLinkStatus("s1", "s2", "up") print h2.cmd('ping 10.1.2.1 -c 20') CLI(net) # After the user exits the CLI, shutdown the network. net.stop()
class Simulation(object): def __init__(self, seed=None): cleanup() config = ConfigParser.ConfigParser() config2 = ConfigParser.ConfigParser() config.read(['./config']) config2.read(['./repo_subnets']) self.config = config self.config2 = config2 self.namespace = [0, 0] ip = self.config.get('main', 'Ip') if seed == None or 'None' in seed: self.seed = random.randint(1, 10000) else: self.seed = seed print ' Seed = %s' % self.seed self.create_topo() controller = RemoteController('c1', ip=ip, port=6633) self.net = Mininet(topo=self.topo, link=TCLink, controller=controller) def create_topo(self): link_type = self.config.get('main', 'Distribution') nm_sw_sf = int(self.config.get('main', 'MainSwitches')) nm_ho_sf = 0 datac = int(self.config.get('main', 'Datacenters')) extra_nets = self.config.sections() self.topo = scalefree.RandomScaleFree(self.seed, link_type, datac, nm_sw_sf, nm_ho_sf) if datac > 0: self.namespace = [nm_sw_sf + 3 * datac, nm_ho_sf + 3 * datac] else: self.namespace = [nm_sw_sf, nm_ho_sf] self.trim() if (len(extra_nets) > 1): extra_topos = {} n_networks = len(extra_nets) - 1 topo_counter = 0 for i in range(n_networks): nm_networks = int(self.config.get(extra_nets[i + 1], 'Number')) for n in range(nm_networks): nm_sw = int(self.config2.get(extra_nets[i + 1], 'Switches')) nm_ho = int(self.config2.get(extra_nets[i + 1], 'Hosts')) extra_topos["topo{}".format( topo_counter)] = scalefree.RandomScaleFree( self.seed, link_type, 0, nm_sw, nm_ho, self.namespace) self.namespace[0] += nm_sw self.namespace[1] += nm_ho topo_counter += 1 print "Building network..." self.join_networks(extra_topos, link_type) return def trim(self): switches = self.topo.switches() links = self.topo.links() counter = 0 other_switch = '' for s in range(len(switches)): for l in range(len(links)): if switches[s] == links[l][0]: if links[l][1] == other_switch: continue else: counter += 1 other_switch = links[l][1] if switches[s] == links[l][1]: if links[l][0] == other_switch: continue else: counter += 1 other_switch = links[l][0] if counter == 1: switches_b = self.topo.switches() switches_b.remove(other_switch) switches_b.remove(switches[s]) self.topo.addLink(switches[s], random.choice(switches_b), bw=1000, lat="3ms") counter = 0 other_switch = '' # Join networks def join_networks(self, extra_networks, link_type): main = self.topo main_switches = main.switches() for i in range(len(extra_networks)): topo = extra_networks["topo{}".format(i)] topo_links = topo.links() topo_switches = topo.switches() topo_hosts = topo.hosts() for n in range(len(topo_switches)): main.addSwitch(topo_switches[n]) for n in range(len(topo_hosts)): main.addHost(topo_hosts[n]) for n in range(len(topo_links)): if "h" not in topo_links[n][0] and "h" not in topo_links[n][1]: main.addLink(topo_links[n][0], topo_links[n][1], bw=1000, lat='3ms') else: main.addLink(topo_links[n][0], topo_links[n][1], bw=self.random_access(link_type), lat='3ms') sw_connect = [ random.choice(main_switches), random.choice(main_switches), random.choice(main_switches) ] sw_connect_2 = [ random.choice(topo_switches), random.choice(topo_switches), random.choice(topo_switches) ] n_sw_conn = random.randint(1, 4) for n in range(n_sw_conn): main.addSwitch('s{}'.format(self.namespace[0] + n + 1)) for m in range(len(sw_connect)): main.addLink(sw_connect[m], 's{}'.format(self.namespace[0] + n + 1), bw=1000, lat='3ms') for m in range(len(sw_connect_2)): main.addLink(sw_connect_2[m], 's{}'.format(self.namespace[0] + n + 1), bw=1000, lat='3ms') self.namespace[0] += n_sw_conn return # Randomize bw of access link def random_access(self, link_type="equal"): type_id = 0 if link_type == "equal": type_id = random.randint(0, 4) elif link_type == "badwifi": type_id_float = random.gauss(0, 0.75) type_id = int(type_id_float) elif link_type == "wifi": type_id_float = random.gauss(1, 0.75) type_id = int(type_id_float) elif link_type == "xdsl": type_id_float = random.gauss(2, 0.75) type_id = int(type_id_float) elif link_type == "fiber50": type_id_float = random.gauss(3, 0.75) type_id = int(type_id_float) elif link_type == "fiber300": type_id_float = random.gauss(4, 0.75) type_id = int(type_id_float) if type_id < 0: type_id = 0 elif type_id > 4: type_id = 4 bw_table = [3, 10, 20, 50, 300] return bw_table[type_id] def run(self, predefined_error=0): net = self.net setLogLevel("debug") net.start() net.pingAll() error_interval = int(self.config.get('main', 'ErrorInterval')) datac = int(self.config.get('main', 'Datacenters')) # DEBUGGING: MainHosts is zero nm_ho_sf = 0 #All datacenters will activate their servers scenario = self.config.get('main', 'StreamingScenario') for n in range(nm_ho_sf + 1, nm_ho_sf + datac * 3 + 1): h = net.get('h{}'.format(n)) h.cmd('./net/server.sh &') h.cmd('./net/streaming_server.sh &') h.cmd('./net/mail_listen_receive.sh &') h.cmd('./net/mail_listen_send.sh &') h.cmd('iperf -s &') if 'Yes' in scenario: for n in range(nm_ho_sf, nm_ho_sf + datac): h = net.get('h{}'.format(n * 3 + 1)) h.cmd('./net/vlc_send.sh &') # XTERM any host to connect vlc to the datacenter CLI(net) elif 'No' not in scenario: print ' I could not understand the "StreamingScenario" field ' #nm_ho is the number of hosts (incuding datacenters) in the network nm_ho = nm_ho_sf + datac * 3 extra_networks = self.config.sections() if (len(extra_networks) > 1): n_networks = len(extra_networks) - 1 for i in range(n_networks): nm_ho += int(self.config2.get(extra_networks[i + 1], 'Hosts')) #All hosts will be listening for normal and small traffic for n in range(nm_ho): h = net.get('h{}'.format(n + 1)) h.cmd('./net/listen.sh &') h.cmd('./net/small_listen.sh &') print "Generating traffic..." #DEBUGGING: not smart enough self.create_traffic(datac, nm_ho) #Simulation ID orig_timestamp = datetime.now() sim_id = str(orig_timestamp.year) + str(orig_timestamp.month) + str( orig_timestamp.day) + str(orig_timestamp.hour) + str( orig_timestamp.minute) + '_' + str(predefined_error) print "Simulation ID = %s" % sim_id #Setting up log print "Setting up log..." logger = logging.getLogger() hdlr = logging.FileHandler('/root/log/' + sim_id + '.log') formatter = logging.Formatter('%(asctime)s %(levelname)s %(message)s') hdlr.setFormatter(formatter) logger.addHandler(hdlr) logger.setLevel(logging.INFO) logger.info(sim_id + " start " + str(json.dumps(errors.encode_errors()))) switches_list = net.switches for switch in switches_list: errors.config_push(switch.dpid) print "Giving time for the collector to catch up..." time.sleep(25) print "Beginning test..." minutes = int(self.config.get('main', 'MinutesRunning')) now_timestamp = datetime.now() while (now_timestamp - orig_timestamp).total_seconds() < minutes * 60: time.sleep(error_interval * 2) if predefined_error != 0: if (predefined_error == 2 or predefined_error == 1): print '1 and 2 errors not supported for the time being' break self.create_error(predefined_error, nm_ho, datac, sim_id, logger, error_interval) else: # Excluding traffic errors (1 and 2) for the time being # Checking error 3 ... self.create_error(random.randint(4, 12), nm_ho, datac, sim_id, logger, error_interval) now_timestamp = datetime.now() logger.info(sim_id + " stop") print "Test ended. Shutting down network..." net.stop() return def create_traffic(self, datac, nm_ho, temp=False): for n in range(nm_ho): x = random.randint(0, 6) h = self.net.get('h{}'.format(n + 1)) # DEBUGGING This is considering that we have 0 hosts in main network # DEBUGGING One could send messages to himself if datac > 0: randip_datac = '10.0.0.' + str(random.randint(1, datac * 3)) else: randip_datac = '0.0.0.0' randip_ho = '10.0.0.' + str(random.randint(datac + 1, nm_ho)) if temp is True: traffic = { 0: ' ', 1: './net/mail_receive.sh ' + randip_datac + ' temp' + ' &', 2: './net/mail_send.sh ' + randip_datac + ' temp' + ' &', 3: './net/small_send.sh ' + randip_ho + ' temp' + ' &', 4: './net/send.sh ' + randip_ho + ' temp' + ' &', 5: './net/streaming_client.sh ' + randip_datac + ' temp' + ' &', 6: './net/server_connect.sh ' + randip_datac + ' temp' + ' &' } else: traffic = { 0: ' ', 1: './net/mail_receive.sh ' + randip_datac + ' &', 2: './net/mail_send.sh ' + randip_datac + ' &', 3: './net/small_send.sh ' + randip_ho + ' &', 4: './net/send.sh ' + randip_ho + ' &', 5: './net/streaming_client.sh ' + randip_datac + ' &', 6: './net/server_connect.sh ' + randip_datac + ' &' } print " Command type : " + str(x) h.cmd(str(traffic.get(x, ' '))) print " Done" print " End of iteration" return # Creates an error in the network according to a given number def create_error(self, err, nm_ho, datac, sim_id, logger, error_interval=10): #DEBUGGING I'm supposing zero hosts in the main network host = random.randint(datac * 3 + 1, nm_ho) config = ConfigParser.ConfigParser() config.read(['./config']) switch = self.config.get('main', 'Switch') node = self.net.get(str(switch)) if datac > 0: server = random.randint(1, datac * 3) ip_datac = '10.0.0.' + str(server) else: ip_datac = '0.0.0.0' if err == 1: print 'Error %d in host %s' % (err, host) for n in range(0, 6): time.sleep(0.5) print ' Iteration %d' % (n + 1) h = self.net.get('h{}'.format(host)) h.cmd('./net/streaming_client.sh ' + ip_datac + ' temp' + ' &') errors.send_report(err, { 'Host': 'h{}'.format(host), 'Timestamp': str(datetime.now()) }, sim_id, logger) if error_interval < 60: time.sleep(60) else: time.sleep(error_interval) print "Fixed traffic-consuming host error" errors.send_report( str(err) + 'f', { 'Host': 'h{}'.format(host), 'Timestamp': str(datetime.now()) }, sim_id, logger) elif err == 2: print 'Error %d ' % err for n in range(0, 10): print ' Iteration %d' % (n + 1) self.create_traffic(datac, nm_ho, temp=True) errors.send_report(err, {'Timestamp': str(datetime.now())}, sim_id, logger) if error_interval < 60: time.sleep(60) else: time.sleep(error_interval) print "Fixed general traffic error" errors.send_report( str(err) + 'f', {'Timestamp': str(datetime.now())}, sim_id, logger) elif err == 3: print 'Error %d' % err links_list = self.net.links # Beginning in 1 instead of 0, because 0 is loopback #link_down = links_list[random.randint(1, len(links_list)-1)] links_list = node.intfs link_down = links_list[random.randint(1, len(links_list) - 1)].link print 'link down: %s - %s' % (link_down.intf1, link_down.intf2) errors.send_report( err, { 'Interface 1': str(link_down.intf1), 'Interface 2': str(link_down.intf2), 'Timestamp': str(datetime.now()) }, sim_id, logger) self.net.configLinkStatus(str(link_down.intf1.node), str(link_down.intf2.node), "down") time.sleep(error_interval) print "Fixing link down" self.net.configLinkStatus(str(link_down.intf1.node), str(link_down.intf2.node), "up") print 'Fixed' errors.send_report( str(err) + 'f', { 'Interface 1': str(link_down.intf1), 'Interface 2': str(link_down.intf2), 'Timestamp': str(datetime.now()) }, sim_id, logger) elif err == 4: print 'Error %d' % err switches_list = self.net.switches #switch_down = self.net.switches[random.randint(0, len(switches_list)-1)] print 'switch down: %s' % node.name logger.info(sim_id + ' pause') time.sleep(4) errors.send_report( err, { 'Switch': str(int(node.dpid, 16)), 'Timestamp': str(datetime.now()) }, sim_id, logger) old_xml = errors.delete_flow(node.dpid) #old_lldp = errors.delete_lldp_flow(switch_down.dpid) logger.info(sim_id + ' play') time.sleep(error_interval) print 'Fixing switch down error...' logger.info(sim_id + ' pause') time.sleep(4) #errors.fix_node_table(switch_down.dpid, old_lldp) errors.fix_node_flow(node.dpid, old_xml) print 'Fixed' errors.send_report( str(err) + 'f', { 'Switch': str(int(node.dpid, 16)), 'Timestamp': str(datetime.now()) }, sim_id, logger) logger.info(sim_id + ' play') elif err == 5: if datac <= 0: print 'No datacenters in the network!' print ' Error 5 shuts down a host in a datacenter' else: print 'Error %d' % err host_list = [] for i in range(datac * 3): host_list.append(self.net.get("h" + str(i + 1))) host_down = self.net.get("h" + str(random.randint(1, datac * 3))) print 'host down: pid: %s name: %s' % (host_down.pid, host_down.name) deleted_links = [] links_list = self.net.links logger.info(sim_id + ' pause') time.sleep(4) for link in links_list: if (host_down.name + '-' in str( link.intf1)) or (host_down.name + '-' in str( link.intf2)): deleted_links.append(link) print link self.net.configLinkStatus(str(link.intf1.node), str(link.intf2.node), 'down') errors.send_report(err, { 'Host': host_down.name, 'Timestamp': str(datetime.now()) }, sim_id, logger) logger.info(sim_id + ' play') time.sleep(error_interval) print 'Fixing host down error...' logger.info(sim_id + ' pause') time.sleep(4) for deleted in deleted_links: self.net.configLinkStatus(str(deleted.intf1.node), str(deleted.intf2.node), 'up') time.sleep(1) print host_list self.net.ping(host_list) print 'Fixed' errors.send_report( str(err) + 'f', { 'Host': host_down.name, 'Timestamp': str(datetime.now()) }, sim_id, logger) logger.info(sim_id + ' play') elif err == 6: print 'Error %d' % err #switches_list = self.net.switches #switch_down = switches_list[random.randint(0, len(switches_list)-1)] print 'switch whose flow has been modified: %s' % node.dpid logger.info(sim_id + ' pause') time.sleep(4) errors.send_report( err, { 'Switch': str(int(node.dpid, 16)), 'Timestamp': str(datetime.now()) }, sim_id, logger) dictionary = errors.change_flow(node.dpid) logger.info(sim_id + ' play') time.sleep(error_interval) print 'Fixing modified flows error...' logger.info(sim_id + ' pause') time.sleep(4) errors.fix_node_flow(node.dpid, dictionary) print 'Fixed' errors.send_report( str(err) + 'f', { 'Switch': str(int(node.dpid, 16)), 'Timestamp': str(datetime.now()) }, sim_id, logger) logger.info(sim_id + ' play') elif err == 7: print 'Error %d' % err #switches_list = self.net.switches #switch_down = switches_list[random.randint(0, len(switches_list)-1)] print 'Switch whose in-ports have been messed: %s' % node.dpid logger.info(sim_id + ' pause') time.sleep(4) errors.send_report( err, { 'Switch': str(int(node.dpid, 16)), 'Timestamp': str(datetime.now()) }, sim_id, logger) old_inports = errors.change_inport(node.dpid) logger.info(sim_id + ' play') time.sleep(error_interval) print 'Fixing in-ports error...' logger.info(sim_id + ' pause') time.sleep(4) errors.fix_node_flow(node.dpid, old_inports) print 'Fixed' errors.send_report( str(err) + 'f', { 'Switch': str(int(node.dpid, 16)), 'Timestamp': str(datetime.now()) }, sim_id, logger) logger.info(sim_id + ' play') elif err == 8: print 'Error %d' % err #switches_list = self.net.switches seconds = random.randint(1, 5) #switch_down = switches_list[random.randint(0, len(switches_list)-1)] print 'Switch %s: idle-timeout has been added with %d seconds' % ( node.name, seconds) dictionary = {} logger.info(sim_id + ' pause') time.sleep(4) errors.send_report(err, { 'Time': str(seconds), 'Timestamp': str(datetime.now()) }, sim_id, logger) old_xml = errors.change_idletimeout(node.dpid, seconds) dictionary[node.dpid] = old_xml logger.info(sim_id + ' play') time.sleep(error_interval) print 'Fixing idle-timeout error...' logger.info(sim_id + ' pause') time.sleep(4) for key, value in dictionary.iteritems(): errors.fix_node_flow(key, value) print 'Fixed' errors.send_report( str(err) + 'f', { 'Time': str(0), 'Timestamp': str(datetime.now()) }, sim_id, logger) logger.info(sim_id + ' play') elif err == 9: print 'Error %d' % err #switches_list = self.net.switches seconds = random.randint(30, 60) #switch_down = switches_list[random.randint(0, len(switches_list)-1)] print 'Switch %s: hard-timeout has been added with %d seconds' % ( node.name, seconds) dictionary = {} logger.info(sim_id + ' pause') time.sleep(4) errors.send_report(err, { 'Time': str(seconds), 'Timestamp': str(datetime.now()) }, sim_id, logger) old_xml = errors.change_hardtimeout(node.dpid, seconds) dictionary[node.dpid] = old_xml logger.info(sim_id + ' play') time.sleep(error_interval) print 'Fixing hard-timeout error...' logger.info(sim_id + ' pause') time.sleep(4) for key, value in dictionary.iteritems(): errors.fix_node_flow(key, value) print 'Fixed' errors.send_report( str(err) + 'f', { 'Time': str(0), 'Timestamp': str(datetime.now()) }, sim_id, logger) logger.info(sim_id + ' play') elif err == 10: print 'Error %d' % err #switches_list = self.net.switches #switch_down = switches_list[random.randint(0, len(switches_list)-1)] print 'Switch whose flows priorities have changed: %s' % node.dpid logger.info(sim_id + ' pause') time.sleep(4) errors.send_report( err, { 'Switch': str(int(node.dpid, 16)), 'Timestamp': str(datetime.now()) }, sim_id, logger) old_xml = errors.change_priority(node.dpid) logger.info(sim_id + ' play') time.sleep(error_interval) print 'Fixing priorities error...' logger.info(sim_id + ' pause') time.sleep(4) errors.fix_node_flow(node.dpid, old_xml) print 'Fixed' errors.send_report( str(err) + 'f', { 'Switch': str(int(node.dpid, 16)), 'Timestamp': str(datetime.now()) }, sim_id, logger) logger.info(sim_id + ' play') elif err == 11: print 'Error %d' % err #switches_list = self.net.switches #switch_down = switches_list[random.randint(0, len(switches_list)-1)] print 'Switch that will drop its lldp packages: %s' % node.dpid logger.info(sim_id + ' pause') time.sleep(4) old_xml = errors.delete_lldp_flow(node.dpid) errors.send_report( err, { 'Switch': str(int(node.dpid, 16)), 'Timestamp': str(datetime.now()) }, sim_id, logger) logger.info(sim_id + ' play') time.sleep(error_interval) print 'Fixing lldp error...' logger.info(sim_id + ' pause') time.sleep(4) errors.fix_node_table(node.dpid, old_xml) print 'Fixed' errors.send_report( str(err) + 'f', { 'Switch': str(int(node.dpid, 16)), 'Timestamp': str(datetime.now()) }, sim_id, logger) logger.info(sim_id + ' play') elif err == 12: print 'Error %d' % err #switches_list = self.net.switches #switch_down = switches_list[random.randint(0, len(switches_list)-1)] print 'Switch whose outport and inport have been modified: %s' % node.dpid logger.info(sim_id + ' pause') time.sleep(4) errors.send_report( err, { 'Switch': str(int(node.dpid, 16)), 'Timestamp': str(datetime.now()) }, sim_id, logger) dictionary = errors.change_flow(node.dpid) time.sleep(4) errors.change_inport(node.dpid) logger.info(sim_id + ' play') time.sleep(error_interval) print 'Fixing error 12...' logger.info(sim_id + ' pause') time.sleep(4) errors.fix_node_flow(node.dpid, dictionary) logger.info(sim_id + ' play') print 'Fixed' errors.send_report( str(err) + 'f', { 'Switch': str(int(node.dpid, 16)), 'Timestamp': str(datetime.now()) }, sim_id, logger) return
# ping forever function def ping_thread(threadName, src, dst): while (1): time.sleep(1) print src.cmd('ping -c1 %s' % dst.IP()) # setup mininet network net = Mininet() c0 = net.addController('c0') s0 = net.addSwitch('s0') h0 = net.addHost('h0') h1 = net.addHost('h1') net.addLink(s0, h0) net.addLink(s0, h1) # start network and test net.start() # do the actual test and run forever thread.start_new_thread(ping_thread, ("pinging thread", h0, h1)) # wait 10 seconds before killing the network time.sleep(10) net.configLinkStatus("s0", "h1", "down") # stop network net.stop()
def testFaultTolerance(): """Fault-tolerance test in Section 7.3 of the DCell paper.""" SERVER_LOG = os.path.join(comm.DIR_LOG, "fault_server.log") CLIENT_LOG = os.path.join(comm.DIR_LOG, "fault_client.log") FIGURE = os.path.join(comm.DIR_FIGURE, "fault_tolerance.png") DURATION = 160 # seconds if comm.DCELL_K != 1 or comm.DCELL_N != 4: print "Failed: require level-1 DCell with n=4" return # create net net = Mininet(topo=DCellTopo(tree=False), link=TCLink, controller=DCellController) net.start() print "Waiting controller setup..." time.sleep(5) net.pingAll() print "\n[Fault-Tolerance Test]" # create results directory if not os.path.exists(comm.DIR_LOG): os.mkdir(comm.DIR_LOG) if not os.path.exists(comm.DIR_FIGURE): os.mkdir(comm.DIR_FIGURE) # start iperf server on host (4,3) print "Running iperf server..." net["h20"].cmd("iperf -s >{} 2>&1 &".format(SERVER_LOG)) time.sleep(1) # start iperf client on host (0,0) print "Running iperf client (estimated duration: {} seconds)...".format( DURATION) net["h1"].cmd("iperf -c 10.0.0.20 -t {} -i 1 -y c >{} 2>&1 &".format( DURATION, CLIENT_LOG)) # unplug link (0,3)-(4,0) at time 34s time.sleep(34) net.configLinkStatus("s4", "s17", "down") print "34s: (0,3)-(4,0) down" # replug link (0,3)-(4,0) at time 42s time.sleep(8) net.configLinkStatus("s4", "s17", "up") print "42s: (0,3)-(4,0) up" # shutdown (0,3) at time 104s time.sleep(62) net.configLinkStatus("s4", "s17", "down") net.configLinkStatus("s4", "s21", "down") print "104s: (0,3) down" time.sleep(60) # build figure throughputs = [] with open(CLIENT_LOG, "r") as f: for line in f.readlines(): throughputs.append(int(line.strip().split(",")[-1]) / 1e6) # Mbps plt.plot(range(len(throughputs)), throughputs, "r") plt.title("Fault-Tolerance Test") plt.xlabel("Time (second)") plt.ylabel("TCP Throughput (Mb/s)") plt.savefig(FIGURE) plt.clf() # stop net print "" net.stop()
class Dispatcher(Bottle): def __init__(self): super(Dispatcher, self).__init__() config = { 'user': '******', 'password': '******', 'host': 'db', 'port': '3306', 'database': 'emulator' } self.connection = mysql.connector.connect(**config) self.connection.autocommit = True self.cursor = self.connection.cursor() self.topo_handler = TopoHandler() self.ryu_cmd = "ryu-manager --observe-links --wsapi-host %s --wsapi-port %s ryu.app.iot_switch &" % ( CONTROLLER_HOST, CONTROLLER_PORT) self.is_net_started = False self.initial_charge_level = 10000 self.start_net() self.route('/nodes/<node_name>', method='POST', callback=self.post_node) self.route('/switch/<switch_name>', method='POST', callback=self.add_switch) self.route('/switch/<switch_name>', method='DELETE', callback=self.del_switch) self.route('/host/<host_name>', method='POST', callback=self.add_host) self.route('/host/<host_name>', method='DELETE', callback=self.del_host) self.route('/link', method='POST', callback=self.add_link) self.route('/link', method='DELETE', callback=self.del_link) self.route('/test', method='GET', callback=self.test) self.route('/nodes/<node_name>/cmd', method='POST', callback=self.do_cmd) self.route('/events/<dpid>', method='GET', callback=self.get_events_page) self.route('/events/<dpid>/total', method='GET', callback=self.get_events_total) self.route('/events/charge_state', method='GET', callback=self.get_charge_state) self.route('/count/events', method='GET', callback=self.get_events_count) self.route('/events/<dpid>/charge_events', method='GET', callback=self.get_charge_events) self.route('/events/<dpid>/charge_events/total', method='GET', callback=self.get_charge_total) self.route('/initial_charge', method='GET', callback=self.get_initial_charge_level) self.route('/initial_charge', method='PUT', callback=self.set_initial_charge_level) self.route('/', method='OPTIONS', callback=self.options_handler) self.route('/<path:path>', method='OPTIONS', callback=self.options_handler) self.route('/net/start', method='GET', callback=self.start_net) self.route('/net/stop', method='GET', callback=self.stop_net) self.route('/net/status', method='GET', callback=self.net_status) self.route('/net/topo', method='GET', callback=self.get_topology) def options_handler(self, path=None): return def get_req(self, req): while True: try: print "trying to get ", req l = requests.get(req).json() break except: time.sleep(5) return l def start_net(self): if self.is_net_started: response.status = 403 else: self.cursor.execute('DELETE FROM topology') for node_a, node_b in self.topo_handler.get_links(): self.cursor.execute( "REPLACE INTO topology (node_a, node_b) VALUES (%s, %s)", (node_a, node_b)) self.connection.commit() self.net = Mininet(MyTopo(self.topo_handler), switch=OVSSwitch, controller=RemoteController('c0', ip='127.0.0.1', port=6653)) self.net.start() self.net['c0'].cmd(self.ryu_cmd) self.update_mac_to_dpid() self.net.pingAll() ts = time.time() timestamp = datetime.datetime.fromtimestamp(ts).strftime( '%Y-%m-%d %H:%M:%S') l = self.get_req('http://localhost:5555/v1.0/topology/switches') for el in l: self.cursor.execute( "REPLACE INTO charge_state (dpid, charge, ts) VALUES (%s, %s, %s)", (el['dpid'], self.initial_charge_level, timestamp)) self.connection.commit() self.is_net_started = True print "*** Network has started ***" def stop_net(self): if not self.is_net_started: response.status = 403 else: self.net.stop() os.system('fuser -k 6653/tcp') # kill mininet controller self.is_net_started = False def net_status(self): return {"status": self.is_net_started} def update_mac_to_dpid(self): self.cursor.execute("DELETE FROM mac_to_dpid") l = self.get_req('http://localhost:5555/v1.0/topology/switches') for el in l: for mac in el['ports']: self.cursor.execute( "REPLACE INTO mac_to_dpid (mac_addr, dpid) VALUES (%s, %s)", (mac['hw_addr'], el['dpid'])) for el in self.topo_handler.get_hosts(): self.cursor.execute( "REPLACE INTO mac_to_dpid (mac_addr, dpid) VALUES (%s, %s)", (self.topo_handler.get_host_mac(el), el)) self.connection.commit() def test(self): return "TEST!" def post_node(self, node_name): if not self.is_net_started: response.status = 403 else: node = self.net[node_name] node.params.update(request.json['params']) def add_switch(self, switch_name): if switch_name not in self.topo_handler.get_switches( ) and not self.is_net_started: c0 = self.net.get('c0') self.topo_handler.add_switch(switch_name) else: response.status = 403 def add_host(self, host_name): if host_name not in self.topo_handler.get_switches( ) and not self.is_net_started: self.topo_handler.add_host(host_name) else: response.status = 403 def del_switch(self, switch_name): if switch_name in self.topo_handler.get_switches( ) and not self.is_net_started: self.topo_handler.delete_switch(switch_name) else: response.status = 403 def del_host(self, host_name): if host_name in self.topo_handler.get_hosts( ) and not self.is_net_started: self.topo_handler.delete_host(host_name) else: response.status = 403 def del_link(self): a = request.json['a'] b = request.json['b'] has_link = ((a, b) not in self.topo_handler.get_links() and (b, a) not in self.topo_handler.get_links()) if has_link or self.is_net_started: response.status = 403 else: self.net.configLinkStatus(a, b, 'down') if (a, b) in self.topo_handler.get_links(): self.topo_handler.delete_link((a, b)) else: self.topo_handler.delete_link((b, a)) self.net.start() def is_node(self, name): return name in self.topo_handler.get_switches( ) or name in self.topo_handler.get_hosts() def add_link(self): a = request.json['a'] b = request.json['b'] nodes = self.is_node(a) and self.is_node(b) if not nodes or self.is_net_started: response.status = 403 else: self.topo_handler.add_link((a, b)) def get_topology(self): return { "hosts": list(self.topo_handler.get_hosts()), "switches": list(self.topo_handler.get_switches()), "links": self.topo_handler.get_links() } def do_cmd(self, node_name): if not self.is_net_started: response.status = 403 else: timeout = float(request.query['timeout']) args = request.body.read() node = self.net[node_name] rest = args.split(' ') # Substitute IP addresses for node names in command # If updateIP() returns None, then use node name rest = [ self.net[arg].defaultIntf().updateIP() or arg if arg in self.net else arg for arg in rest ] rest = ' '.join(rest) # Run cmd on node: node.sendCmd(rest) output = '' init_time = time.time() while node.waiting: exec_time = time.time() - init_time #timeout of 5 seconds if exec_time > timeout: break data = node.monitor(timeoutms=1000) output += data # Force process to stop if not stopped in timeout if node.waiting: node.sendInt() time.sleep(0.5) data = node.monitor(timeoutms=1000) output += data node.waiting = False output = output.replace('<', '<') output = output.replace('>', '>') output = output.replace('\n', '<br>') return output def get_events_count(self): start = request.query['start'] end = request.query['end'] db_query = 'select dpid, count(*) as events from charge_events where ts >= %s and ts <= %s group by dpid' return self.jsonify_query(db_query, start, end) def get_events_total(self, dpid): db_query = 'SELECT count(*) as total FROM send_events WHERE dpid = %s' return self.jsonify_query(db_query, dpid) def get_events_page(self, dpid): perpage = int(request.query['perpage']) startat = int(request.query['page']) * perpage db_query = self.paginate( 'SELECT from_mac, to_mac, from_port, to_port, ts FROM send_events WHERE dpid = %s' ) return self.jsonify_query(db_query, dpid, perpage, startat) def get_charge_state(self): if not self.is_net_started: response.status = 403 else: return self.jsonify_query('SELECT * FROM charge_state') def get_charge_total(self, dpid): db_query = 'SELECT count(*) as total FROM charge_events WHERE dpid = %s' return self.jsonify_query(db_query, dpid) def get_charge_events(self, dpid): perpage = int(request.query['perpage']) startat = int(request.query['page']) * perpage return self.jsonify_query( self.paginate('SELECT * FROM charge_events WHERE dpid = %s'), dpid, perpage, startat) def get_initial_charge_level(self): return {"charge": self.initial_charge_level} def set_initial_charge_level(self): charge = request.json['charge'] self.initial_charge_level = charge return {"charge": self.initial_charge_level} def paginate(self, query): return query + ' ORDER BY id DESC LIMIT %s OFFSET %s;' def jsonify_query(self, db_query, *args): self.cursor.execute(db_query, args) hdrs = [x[0] for x in self.cursor.description] rv = self.cursor.fetchall() res = [] for el in rv: res.append(dict(zip(hdrs, el))) response.content_type = 'application/json' return json.dumps(res, indent=4, sort_keys=True, default=str)
class App: def __init__(self): self.app = Bottle() self.net = Mininet(controller=RemoteController) h1 = self.net.addHost('h1') h2 = self.net.addHost('h2') h3 = self.net.addHost('h3') s1 = self.net.addSwitch('s1') s2 = self.net.addSwitch('s2') s3 = self.net.addSwitch('s3') c0 = self.net.addController('c0', controller=RemoteController, ip='127.0.0.1', port=8888) self.net.addLink(h1, s1) self.net.addLink(s1, s2) self.net.addLink(s2, h2) self.net.addLink(s1, s3) self.net.addLink(s3, s2) self.net.addLink(s3, h3) pass def run(self): bp = self.start_bottle_process() self.run_mininet() bp.terminate() def start_bottle_process(self): p = Process(target=self.run_bottle) p.start() return p def run_mininet(self): self.net.start() CLI(self.net) self.net.stop() def run_bottle(self): self.app.route('/check_connection/', callback=self.check_connection) self.app.post('/change_setting/', callback=self.change_setting) self.app.route('/stop', callback=self.stop) self.app.run(host=self.read_ip(), port=SERVER_PORT) def read_ip(self): f = open(IP_DATA_FILE, "r") my_ip = f.readline().rstrip('\n') if self.is_valid_ipv4_address(my_ip): print('Bottle server IP set as = ' + my_ip) print('Set server IP in your RyuPilot app as \'' + my_ip + '\'.') return my_ip else: print('Bottle server IP = ' + my_ip + ' invalid, changed to = localhost.') return 'localhost' def is_valid_ipv4_address(self, address): try: socket.inet_pton(socket.AF_INET, address) except AttributeError: try: socket.inet_aton(address) except socket.error: return False return address.count('.') == 3 except socket.error: return False return True def check_connection(self): print("Connection correct.") return "<p>Connection correct.</p>" def change_setting(self): postdata = request.body.read() json = request.json setting_id = json["setting_id"] print("Requested setting_id = " + str(setting_id)) #for safety remember to always update all links #everything off if setting_id == 1: print('Setting network up.') print('Setting h3 to be connected through s3 & disconnecting s1 from s2') self.net.configLinkStatus(src='h1', dst='s1', status='up') self.net.configLinkStatus(src='s2', dst='h2', status='up') self.net.configLinkStatus(src='s1', dst='s2', status='down') self.net.configLinkStatus(src='s1', dst='s3', status='up') self.net.configLinkStatus(src='s3', dst='h3', status='up') self.net.configLinkStatus(src='s3', dst='s2', status='up') print(str(setting_id) + " set successfully.") if setting_id == 2: print('Disconnecting h2.') print('Setting links h1-s1 and s1-h2 to status=\'up\'.') self.net.configLinkStatus(src='h1', dst='s1', status='up') self.net.configLinkStatus(src='s1', dst='s2', status='up') self.net.configLinkStatus(src='s2', dst='h2', status='up') self.net.configLinkStatus(src='s1', dst='s3', status='down') self.net.configLinkStatus(src='s3', dst='s2', status='down') self.net.configLinkStatus(src='s3', dst='h3', status='down') print(str(setting_id) + " set successfully.") if setting_id == 3: print('Disconnecting h1.') self.net.configLinkStatus(src='h1', dst='s1', status='down') self.net.configLinkStatus(src='s2', dst='h2', status='up') self.net.configLinkStatus(src='s1', dst='s2', status='down') self.net.configLinkStatus(src='s1', dst='s3', status='down') self.net.configLinkStatus(src='s3', dst='h3', status='up') self.net.configLinkStatus(src='s3', dst='s2', status='up') print(str(setting_id) + " set successfully.") if setting_id == 4: print('Setting network down.') print('Setting links h1-s1 and s1-h2 to status=\'down\'.') self.net.configLinkStatus(src='h1', dst='s1', status='down') self.net.configLinkStatus(src='s2', dst='h2', status='down') self.net.configLinkStatus(src='s1', dst='s3', status='down') self.net.configLinkStatus(src='s3', dst='s2', status='down') self.net.configLinkStatus(src='s3', dst='h3', status='down') self.net.configLinkStatus(src='s1', dst='s2', status='down') print(str(setting_id) + " set successfully.") def stop(self): self.net.stop() print("Requested stop.")
sleep(15) # start the traffic print("starting the traffic") h1.cmd('iperf -s &') h4.cmd('iperf -c 10.0.0.1 -t 100 &') # start the monitoring print("starting the monitoring") s4.cmd( "bwm-ng -o csv -c 80 -T rate -I s4-eth2 -t 1000 > logs/S4toS3.csv &") s4.cmd( "bwm-ng -o csv -c 80 -T rate -I s4-eth3 -t 1000 > logs/S4toS5.csv &") h4.cmd("bwm-ng -o csv -c 80 -T rate -I h4-eth0 -t 1000 > logs/host.csv &") sleep(10) net.configLinkStatus("s3", "s4", "down") sleep(20) net.configLinkStatus("s3", "s4", "up") sleep(20) net.configLinkStatus("s3", "s4", "down") net.configLinkStatus("s2", "s3", "down") sleep(30) # shuting down the controller c0_process.terminate() sleep(3) if c0_process.poll() is None: print("kill kill") c0_process.kill() net.stop()
def run(): os.system('mn -c') c0 = RemoteController('c1', '127.0.0.1') ovs13 = partial(OVSKernelSwitch, protocols=OFVersion) topo = JFTopo() net = Mininet(topo=topo, link=TCLink, controller=None, switch=ovs13, autoSetMacs=True) net.addController(c0) net.start() print('==== Total server(s) = %s' % h) print('==== Total switches(s) = %s' % n) print('==== Initiating topology ping test...') # Getting switch few switches for i in range(n): if mat[0, i] == 1: sw_list.append('s%s' % (i + 1)) # Fetch all host host = [] for i in range(h): host.append(net.get('h%s' % (i + 1))) # net.pingAll() # Make directory for result directory = '/home/DCResult/Jellyfish' + str(n) os.system('mkdir -p ' + directory + '/latency') os.system('mkdir -p ' + directory + '/convergence') os.system('mkdir -p ' + directory + '/throughput') # Homemade pingall print '==== Pingall from h1 to all hosts to initiate paths...' print '==== Pingall will be initiate in 1 second' time.sleep(1) for i in range(1, len(host)): # print "h1 pinging to %s" % host[i] host[0].cmd('ping %s -c 1 &' % host[i].IP()) # h1 as iperf server print('Wait 55 sec for test to complete') print '==== Latency test' for i in range(1, len(host)): host[i].cmd('ping 10.0.0.1 -c 10 > ' + directory + '/latency/h%s.txt &' % (i + 1)) # host[i].cmdPrint('iperf -c 10.0.0.1 -b 100 > /home/DCResult/Jellyfish/iperf/resIperf-h%s.txt &' % (i + 1)) # host[i].cmd('iperf -c 10.0.0.1 -t 10 -y C >> /home/DCResult/Jellyfish/throughput/throughput.csv &') time.sleep(15) print '==== Throughput test' # Using Nping as background traffic ips = '' for i in range(2, len(host) - 1): ips += host[i].IP() + ' ' host[0].cmd('iperf -s &') host[1].cmd('nping -c 10 --tcp ' + ips + '&') host[-1].cmd('iperf -c 10.0.0.1 -t 10 -i 1 > ' + directory + '/throughput/throughput.txt &') time.sleep(20) print '==== Convergence test' host[-1].cmd('ping 10.0.0.1 -c 20 -D > ' + directory + '/convergence/convergence.txt &') time.sleep(3) for i in range(0, len(sw_list)): net.configLinkStatus('s1', sw_list[i], 'down') time.sleep(0.5) net.configLinkStatus('s1', sw_list[0], 'up') time.sleep(17) os.system('chmod -R 777 /home/DCResult') # CLI(net) net.stop()
class NetworkConfiguration(object): def __init__(self, controller, controller_ip, controller_port, controller_api_base_url, controller_api_user_name, controller_api_password, topo_name, topo_params, conf_root, synthesis_name, synthesis_params, roles, project_name="test", power_simulator_ip="127.0.0.1", link_latency=""): self.controller = controller self.topo_name = topo_name self.topo_params = topo_params self.topo_name = topo_name self.conf_root = conf_root self.synthesis_name = synthesis_name self.synthesis_params = synthesis_params self.roles = roles self.project_name = project_name self.power_simulator_ip = power_simulator_ip self.link_latency = link_latency self.controller_ip = controller_ip self.controller_port = controller_port self.topo = None self.nc_topo_str = None self.init_topo() self.init_synthesis() self.mininet_obj = None self.cm = None self.ng = None # Setup the directory for saving configs, check if one does not exist, # if not, assume that the controller, cyber_network and rule synthesis needs to be triggered. self.conf_path = self.conf_root + str(self) + "/" if not os.path.exists(self.conf_path): os.makedirs(self.conf_path) self.load_config = False self.save_config = True else: self.load_config = False self.save_config = True self.h = httplib2.Http() self.controller_api_base_url = controller_api_base_url self.controller_api_base_url = controller_api_base_url self.h.add_credentials(controller_api_user_name, controller_api_password) def __str__(self): return self.controller + "_" + str(self.synthesis) + "_" + str( self.topo) def __del__(self): self.cm.stop_controller() self.cleanup_mininet() def init_topo(self): if self.topo_name == "ring": self.topo = RingTopo(self.topo_params) self.nc_topo_str = "Ring topology with " + str( self.topo.total_switches) + " switches" elif self.topo_name == "clostopo": self.topo = ClosTopo(self.topo_params) self.nc_topo_str = "Clos topology with " + str( self.topo.total_switches) + " switches" elif self.topo_name == "linear": self.topo = LinearTopo(self.topo_params) self.nc_topo_str = "Linear topology with " + str( self.topo_params["num_switches"]) + " switches" elif self.topo_name == "clique": self.topo = CliqueTopo(self.topo_params) self.nc_topo_str = "Linear topology with " + str( self.topo_params["num_switches"]) + " switches" elif self.topo_name == "clique_enterprise": self.topo = CliqueEnterpriseTopo(self.topo_params) self.nc_topo_str = "Clique Enterprise topology with " + str( self.topo_params["num_switches"]) + " switches" else: raise NotImplementedError("Topology: %s" % self.topo_name) def init_synthesis(self): if self.synthesis_name == "DijkstraSynthesis": self.synthesis_params["master_switch"] = self.topo_name == "linear" self.synthesis = DijkstraSynthesis(self.synthesis_params) elif self.synthesis_name == "AboresceneSynthesis": self.synthesis = AboresceneSynthesis(self.synthesis_params) elif self.synthesis_name == "SimpleMACSynthesis": self.synthesis = SimpleMACSynthesis(self.synthesis_params) else: self.synthesis = None def prepare_all_flow_specifications(self): flow_specs = [] flow_match = Match(is_wildcard=True) #flow_match["ethernet_type"] = 0x0800 for src_host_id, dst_host_id in permutations(self.ng.host_ids, 2): if src_host_id == dst_host_id: continue fs = FlowSpecification(src_host_id, dst_host_id, flow_match) fs.ng_src_host = self.ng.get_node_object(src_host_id) fs.ng_dst_host = self.ng.get_node_object(dst_host_id) fs.mn_src_host = self.mininet_obj.get(src_host_id) fs.mn_dst_host = self.mininet_obj.get(dst_host_id) flow_specs.append(fs) return flow_specs def trigger_synthesis(self, synthesis_setup_gap): if self.synthesis_name == "DijkstraSynthesis": self.synthesis.network_graph = self.ng self.synthesis.synthesis_lib = SynthesisLib( "localhost", "8181", self.ng) self.synthesis.synthesize_all_node_pairs() elif self.synthesis_name == "AboresceneSynthesis": self.synthesis.network_graph = self.ng self.synthesis.synthesis_lib = SynthesisLib( "localhost", "8181", self.ng) flow_match = Match(is_wildcard=True) flow_match["ethernet_type"] = 0x0800 self.synthesis.synthesize_all_switches(flow_match, 2) elif self.synthesis_name == "SimpleMACSynthesis": self.synthesis.network_graph = self.ng self.synthesis.synthesis_lib = SynthesisLib( "localhost", "8181", self.ng) flow_specs = self.prepare_all_flow_specifications() self.synthesis.synthesize_flow_specifications(flow_specs) if synthesis_setup_gap: time.sleep(synthesis_setup_gap) if self.mininet_obj: #self.mininet_obj.pingAll() # full_data = self.mininet_obj.pingFull(hosts=[self.mininet_obj.get('h1'), # self.mininet_obj.get('h2')]) # print full_data """ h1 = self.mininet_obj.get('h1') h2 = self.mininet_obj.get('h2') s1 = self.mininet_obj.get('s1') cmd = "ping -c3 " + h2.IP() output = h1.cmd(cmd) macAddr = os.popen("ifconfig -a s1-eth1 | grep HWaddr | awk -F \' \' \'{print $5}\'").read().rstrip('\n') #macAddr = str(proc.stdout.read()) os.system("sudo tcprewrite --enet-smac=" + str(macAddr) + " --infile=/home/ubuntu/Desktop/Workspace/NetPower_TestBed/test.pcap --outfile=/home/ubuntu/Desktop/Workspace/NetPower_TestBed/test2.pcap") cmd = "sudo tcpreplay -i s1-eth1 /home/ubuntu/Desktop/Workspace/NetPower_TestBed/test2.pcap" os.system(cmd) #output = h1.cmd(cmd) print "here" """ def get_ryu_switches(self): ryu_switches = {} # Get all the ryu_switches from the inventory API remaining_url = 'stats/switches' resp, content = self.h.request( self.controller_api_base_url + remaining_url, "GET") #CLI(self.mininet_obj) #import pdb; pdb.set_trace() ryu_switch_numbers = json.loads(content) for dpid in ryu_switch_numbers: this_ryu_switch = {} # Get the flows remaining_url = 'stats/flow' + "/" + str(dpid) resp, content = self.h.request( self.controller_api_base_url + remaining_url, "GET") if resp["status"] == "200": switch_flows = json.loads(content) switch_flow_tables = defaultdict(list) for flow_rule in switch_flows[str(dpid)]: switch_flow_tables[flow_rule["table_id"]].append(flow_rule) this_ryu_switch["flow_tables"] = switch_flow_tables else: print "Error pulling switch flows from RYU." # Get the ports remaining_url = 'stats/portdesc' + "/" + str(dpid) resp, content = self.h.request( self.controller_api_base_url + remaining_url, "GET") if resp["status"] == "200": switch_ports = json.loads(content) this_ryu_switch["ports"] = switch_ports[str(dpid)] else: print "Error pulling switch ports from RYU." # Get the groups remaining_url = 'stats/groupdesc' + "/" + str(dpid) resp, content = self.h.request( self.controller_api_base_url + remaining_url, "GET") if resp["status"] == "200": switch_groups = json.loads(content) this_ryu_switch["groups"] = switch_groups[str(dpid)] else: print "Error pulling switch ports from RYU." ryu_switches[dpid] = this_ryu_switch with open(self.conf_path + "ryu_switches.json", "w") as outfile: json.dump(ryu_switches, outfile) def get_onos_switches(self): # Get all the onos_switches from the inventory API remaining_url = 'devices' resp, content = self.h.request( self.controller_api_base_url + remaining_url, "GET") onos_switches = json.loads(content) for this_switch in onos_switches["devices"]: # Get the flows remaining_url = 'flows' + "/" + this_switch["id"] resp, content = self.h.request( self.controller_api_base_url + remaining_url, "GET") if resp["status"] == "200": switch_flows = json.loads(content) switch_flow_tables = defaultdict(list) for flow_rule in switch_flows["flows"]: switch_flow_tables[flow_rule["tableId"]].append(flow_rule) this_switch["flow_tables"] = switch_flow_tables else: print "Error pulling switch flows from Onos." # Get the ports remaining_url = "links?device=" + this_switch["id"] resp, content = self.h.request( self.controller_api_base_url + remaining_url, "GET") if resp["status"] == "200": switch_links = json.loads(content)["links"] this_switch["ports"] = {} for link in switch_links: if link["src"]["device"] == this_switch["id"]: this_switch["ports"][link["src"]["port"]] = link["src"] elif link["dst"]["device"] == this_switch["id"]: this_switch["ports"][link["dst"]["port"]] = link["dst"] else: print "Error pulling switch ports from RYU." # Get the groups remaining_url = 'groups' + "/" + this_switch["id"] resp, content = self.h.request( self.controller_api_base_url + remaining_url, "GET") if resp["status"] == "200": this_switch["groups"] = json.loads(content)["groups"] else: print "Error pulling switch ports from RYU." with open(self.conf_path + "onos_switches.json", "w") as outfile: json.dump(onos_switches, outfile) def get_mininet_host_nodes(self): mininet_host_nodes = {} for sw in self.topo.switches(): mininet_host_nodes[sw] = [] for h in self.get_all_switch_hosts(sw): mininet_host_dict = { "host_switch_id": "s" + sw[1:], "host_name": h.name, "host_IP": h.IP(), "host_MAC": h.MAC() } mininet_host_nodes[sw].append(mininet_host_dict) with open(self.conf_path + "mininet_host_nodes.json", "w") as outfile: json.dump(mininet_host_nodes, outfile) return mininet_host_nodes def get_onos_host_nodes(self): # Get all the onos_hosts from the inventory API remaining_url = 'hosts' resp, content = self.h.request( self.controller_api_base_url + remaining_url, "GET") onos_hosts = json.loads(content)["hosts"] with open(self.conf_path + "onos_hosts.json", "w") as outfile: json.dump(onos_hosts, outfile) return onos_hosts def get_host_nodes(self): if self.controller == "ryu": self.get_mininet_host_nodes() elif self.controller == "onos": self.get_onos_host_nodes() else: raise NotImplemented def get_mininet_links(self): mininet_port_links = {} with open(self.conf_path + "mininet_port_links.json", "w") as outfile: json.dump(self.topo.ports, outfile) return mininet_port_links def get_onos_links(self): # Get all the onos_links from the inventory API remaining_url = 'links' resp, content = self.h.request( self.controller_api_base_url + remaining_url, "GET") onos_links = json.loads(content)["links"] with open(self.conf_path + "onos_links.json", "w") as outfile: json.dump(onos_links, outfile) return onos_links def get_links(self): if self.controller == "ryu": self.get_mininet_links() elif self.controller == "onos": self.get_onos_links() else: raise NotImplementedError def get_switches(self): # Now the output of synthesis is carted away if self.controller == "ryu": self.get_ryu_switches() elif self.controller == "onos": self.get_onos_switches() else: raise NotImplementedError def setup_network_graph(self, mininet_setup_gap=None, synthesis_setup_gap=None): if not self.load_config and self.save_config: if self.controller == "ryu": self.cm = ControllerMan(controller=self.controller) self.cm.start_controller() #time.sleep(mininet_setup_gap) self.start_mininet() if mininet_setup_gap: time.sleep(mininet_setup_gap) # These things are needed by network graph... self.get_switches() self.get_host_nodes() self.get_links() self.ng = NetworkGraph(network_configuration=self) self.ng.parse_network_graph() if self.synthesis_name: # Now the synthesis... self.trigger_synthesis(synthesis_setup_gap) # Refresh just the switches in the network graph, post synthesis self.get_switches() self.ng.parse_network_graph() #self.ng.parse_switches() else: self.ng = NetworkGraph(network_configuration=self) self.ng.parse_network_graph() print "total_flow_rules:", self.ng.total_flow_rules return self.ng def start_mininet(self): self.cleanup_mininet() if self.controller == "ryu": self.mininet_obj = Mininet( topo=self.topo, cleanup=True, autoStaticArp=True, link=TCLink, controller=lambda name: RemoteController( name, ip=self.controller_ip, port=self.controller_port), switch=partial(OVSSwitch, protocols='OpenFlow13')) #self.set_switch_netdevice_owners() self.mininet_obj.start() def cleanup_mininet(self): if self.mininet_obj: print "Mininet cleanup..." #self.mininet_obj.stop() os.system("sudo mn -c") def get_all_switch_hosts(self, switch_id): p = self.topo.ports for node in p: # Only look for this switch's hosts if node != switch_id: continue for switch_port in p[node]: dst_list = p[node][switch_port] dst_node = dst_list[0] if dst_node.startswith("h"): yield self.mininet_obj.get(dst_node) def get_mininet_hosts_obj(self): for sw in self.topo.switches(): for h in self.get_all_switch_hosts(sw): yield h def is_host_pair_pingable(self, src_host, dst_host): hosts = [src_host, dst_host] ping_loss_rate = self.mininet_obj.ping(hosts, '1') # If some packets get through, then declare pingable if ping_loss_rate < 100.0: return True else: # If not, do a double check: cmd_output = src_host.cmd("ping -c 3 " + dst_host.IP()) print cmd_output if cmd_output.find("0 received") != -1: return False else: return True def are_all_hosts_pingable(self): ping_loss_rate = self.mininet_obj.pingAll('1') # If some packets get through, then declare pingable if ping_loss_rate < 100.0: return True else: return False def get_intf_status(self, ifname): # set some symbolic constants SIOCGIFFLAGS = 0x8913 null256 = '\0' * 256 # create a socket so we have a handle to query s = socket(AF_INET, SOCK_DGRAM) # call ioctl() to get the flags for the given interface result = fcntl.ioctl(s.fileno(), SIOCGIFFLAGS, ifname + null256) # extract the interface's flags from the return value flags, = struct.unpack('H', result[16:18]) # check "UP" bit and print a message up = flags & 1 return ('down', 'up')[up] def wait_until_link_status(self, sw_i, sw_j, intended_status): num_seconds = 0 for link in self.mininet_obj.links: if (sw_i in link.intf1.name and sw_j in link.intf2.name) or ( sw_i in link.intf2.name and sw_j in link.intf1.name): while True: status_i = self.get_intf_status(link.intf1.name) status_j = self.get_intf_status(link.intf2.name) if status_i == intended_status and status_j == intended_status: break time.sleep(1) num_seconds += 1 return num_seconds def is_bi_connected_manual_ping_test(self, experiment_host_pairs_to_check, edges_to_try=None): is_bi_connected = True if not edges_to_try: edges_to_try = self.topo.g.edges() for edge in edges_to_try: # Only try and break switch-switch edges if edge[0].startswith("h") or edge[1].startswith("h"): continue for (src_host, dst_host) in experiment_host_pairs_to_check: is_pingable_before_failure = self.is_host_pair_pingable( src_host, dst_host) if not is_pingable_before_failure: print "src_host:", src_host, "dst_host:", dst_host, "are not connected." is_bi_connected = False break self.mininet_obj.configLinkStatus(edge[0], edge[1], 'down') self.wait_until_link_status(edge[0], edge[1], 'down') time.sleep(5) is_pingable_after_failure = self.is_host_pair_pingable( src_host, dst_host) self.mininet_obj.configLinkStatus(edge[0], edge[1], 'up') self.wait_until_link_status(edge[0], edge[1], 'up') time.sleep(5) is_pingable_after_restoration = self.is_host_pair_pingable( src_host, dst_host) if not is_pingable_after_failure == True: is_bi_connected = False print "Got a problem with edge:", edge, " for src_host:", src_host, "dst_host:", dst_host break return is_bi_connected def is_bi_connected_manual_ping_test_all_hosts(self, edges_to_try=None): is_bi_connected = True if not edges_to_try: edges_to_try = self.topo.g.edges() for edge in edges_to_try: # Only try and break switch-switch edges if edge[0].startswith("h") or edge[1].startswith("h"): continue is_pingable_before_failure = self.are_all_hosts_pingable() if not is_pingable_before_failure: is_bi_connected = False break self.mininet_obj.configLinkStatus(edge[0], edge[1], 'down') self.wait_until_link_status(edge[0], edge[1], 'down') time.sleep(5) is_pingable_after_failure = self.are_all_hosts_pingable() self.mininet_obj.configLinkStatus(edge[0], edge[1], 'up') self.wait_until_link_status(edge[0], edge[1], 'up') time.sleep(5) is_pingable_after_restoration = self.are_all_hosts_pingable() if not is_pingable_after_failure == True: is_bi_connected = False break return is_bi_connected def parse_iperf_output(self, iperf_output_string): data_lines = iperf_output_string.split('\r\n') interesting_line_index = None for i in xrange(len(data_lines)): if data_lines[i].endswith('Server Report:'): interesting_line_index = i + 1 data_tokens = data_lines[interesting_line_index].split() print "Transferred Rate:", data_tokens[7] print "Jitter:", data_tokens[9] def parse_ping_output(self, ping_output_string): data_lines = ping_output_string.split('\r\n') interesting_line_index = None for i in xrange(len(data_lines)): if data_lines[i].startswith('5 packets transmitted'): interesting_line_index = i + 1 data_tokens = data_lines[interesting_line_index].split() data_tokens = data_tokens[3].split('/') print 'Min Delay:', data_tokens[0] print 'Avg Delay:', data_tokens[1] print 'Max Delay:', data_tokens[2] def set_netdevice_owner_in_timekeeper(self, intfNames, pid): for name in intfNames: if name != "lo": print "Setting net-device owner for ", name set_netdevice_owner(pid, name) def set_switch_netdevice_owners(self): import pdb pdb.set_trace() for i in xrange(0, len(self.mininet_obj.switches)): mininet_switch = self.mininet_obj.switches[i] # set netdevices owner self.set_netdevice_owner_in_timekeeper(mininet_switch.intfNames(), mininet_switch.pid)
class NetworkTest: def __init__( self, controller_ip, topo_name="ring", db_client=mongo_client, db_client_options=None, ): # Create an instance of our topology mininet.clean.cleanup() # Create a network based on the topology using # OVS and controlled by a remote controller patch('mininet.util.fixLimits', side_effect=None) self.net = Mininet(topo=topos.get(topo_name, (lambda: RingTopo()))(), controller=lambda name: RemoteController( name, ip=controller_ip, port=6653), switch=OVSSwitch, autoSetMacs=True) db_client_kwargs = db_client_options or {} db_name = db_client_kwargs.get("database") or os.environ.get( "MONGO_DBNAME") self.db_client = db_client(**db_client_kwargs) self.db_name = db_name self.db = self.db_client[self.db_name] def start(self): self.net.start() self.start_controller(clean_config=True) def drop_database(self): """Drop database.""" self.db_client.drop_database(self.db_name) def start_controller(self, clean_config=False, enable_all=False, del_flows=False, port=None, database='mongodb'): # Restart kytos and check if the napp is still disabled try: os.system('pkill kytosd') # with open('/var/run/kytos/kytosd.pid', "r") as f: # pid = int(f.read()) # os.kill(pid, signal.SIGTERM) time.sleep(5) if os.path.exists('/var/run/kytos/kytosd.pid'): raise Exception("Kytos pid still exists.") except Exception as e: print("FAIL to stop kytos after 5 seconds -- %s. Force stop!" % e) os.system('pkill -9 kytosd') os.system('rm -f /var/run/kytos/kytosd.pid') if clean_config and database: try: self.drop_database() except ServerSelectionTimeoutError as exc: print(f"FAIL to drop database. {str(exc)}") if clean_config or del_flows: # Remove any installed flow for sw in self.net.switches: sw.dpctl('del-flows') daemon = 'kytosd' if database: daemon += f' --database {database}' if port: daemon += ' --port %s' % port if enable_all: daemon += ' -E' os.system(daemon) self.wait_controller_start() def wait_controller_start(self): """Wait until controller starts according to core/status API.""" wait_count = 0 while wait_count < 60: try: response = requests.get( 'http://127.0.0.1:8181/api/kytos/core/status/', timeout=1) assert response.json()['response'] == 'running' break except: time.sleep(0.5) wait_count += 0.5 else: msg = 'Timeout while starting Kytos controller.' raise Exception(msg) def wait_switches_connect(self): max_wait = 0 while any(not sw.connected() for sw in self.net.switches): time.sleep(1) max_wait += 1 if max_wait > 30: status = [(sw.name, sw.connected()) for sw in self.net.switches] raise Exception( 'Timeout: timed out waiting switches reconnect. Status %s' % status) def restart_kytos_clean(self): self.start_controller(clean_config=True, enable_all=True) self.wait_switches_connect() def config_all_links_up(self): for link in self.net.links: self.net.configLinkStatus(link.intf1.node.name, link.intf2.node.name, "up") def stop(self): self.net.stop() mininet.clean.cleanup()
class TestMininet(unittest.TestCase): """ Utility to create a virtual network to test fuse kafka resiliancy """ def impersonate(self, inital_user = True): """ changes effective group and user ids """ uid = gid = None if inital_user: uid = os.getuid() gid = os.getuid() else: stat = os.stat(".") uid = stat.st_uid gid = stat.st_gid os.setegid(gid) os.seteuid(uid) def start_network(self): """ starts-up a single switch topology """ from mininet.topo import Topo from mininet.net import Mininet from mininet.node import OVSController class SingleSwitchTopo(Topo): "Single Switch Topology" def __init__(self, count=1, **params): Topo.__init__(self, **params) hosts = [ self.addHost('h%d' % i) for i in range(1, count + 1) ] s1 = self.addSwitch('s1') for h in hosts: self.addLink(h, s1) self.net = Mininet(topo = SingleSwitchTopo(4), controller = OVSController) self.net.start() self.impersonate(False) def log_path(self, name): return "/tmp/{}.log".format(name) def shell(self): """ launches mininet CLI """ from mininet.cli import CLI CLI(self.net) def clients_initialize(self): """ initializes clients variables based on hosts """ self.kafka = self.net.get('h1') self.zookeeper = self.net.get('h2') self.fuse_kafka = self.net.get('h3') self.client = self.net.get('h4') self.hosts = [self.kafka, self.zookeeper, self.fuse_kafka, self.client] self.switch = self.net.get('s1') self.java_clients = [self.client, self.kafka, self.zookeeper] def cmd(self, where, cmd): import pwd command = "su {} -c '{}'".format( pwd.getpwuid(os.stat(".").st_uid).pw_name, cmd) print(command) return where.cmd(command) def data_directories_cleanup(self): """ cleanups generated directory """ self.cmd(self.zookeeper, "rm -rf /tmp/kafka-logs /tmp/zookeeper") def zookeeper_start(self): """ starts zookeeper server """ self.cmd(self.zookeeper, self.launch.format("zookeeper") + kafka_config_directory + 'zookeeper.properties >> {} 2>&1 &'.format(self.log_path('zookeeper'))) def kafka_start(self): """ starts kafka server and creates logging topic """ import tempfile if not hasattr(self, 'kafka_config'): self.kafka_config = tempfile.NamedTemporaryFile(delete=False) self.kafka_config.write("zookeeper.connect={}\n".format(self.zookeeper.IP())) self.kafka_config.write("broker.id=0\n") self.kafka_config.write("host.name={}\n".format(self.kafka.IP())) self.kafka_config.close() self.cmd(self.kafka, self.launch.format("kafka") + self.kafka_config.name + ' > {} 2>&1 &'.format(self.log_path('kafka'))) self.cmd(self.kafka, create_topic_command( self.zookeeper.IP()) + " > {} 2>&1 ".format(self.log_path('create_topic'))) def kafka_stop(self): """ stops kafka server """ self.cmd(self.kafka, self.stop.format("kafka")) def zookeeper_stop(self): """ stops zookeeper server """ self.cmd(self.zookeeper, "pkill -9 -f zookeeper.properties") def fuse_kafka_start(self): """ starts fuse_kafka """ cwd = os.getcwd() + "/" self.fuse_kafka_path = '{}/fuse_kafka'.format(cwd) conf = "/tmp/conf" self.cmd(self.fuse_kafka, "mkdir -p {}".format(conf)) self.cmd(self.fuse_kafka, "cp {}conf/fuse_kafka.properties {}".format(cwd, conf)) self.cmd(self.fuse_kafka, "sed -i 's/127.0.0.1/{}/' {}/fuse_kafka.properties" .format(self.zookeeper.IP(), conf)) self.cmd(self.fuse_kafka, "ln -s {}/fuse_kafka {}/../fuse_kafka" .format(cwd, conf)) for path in glob.glob(cwd + "/*.so"): self.cmd(self.fuse_kafka, "ln -s {} {}/../{}" .format(path, conf, path.split("/")[-1])) self.cmd(self.fuse_kafka, "ln -s {}/fuse_kafka {}/../fuse_kafka" .format(cwd, conf)) self.cmd(self.fuse_kafka, 'bash -c "cd {}/..;{}src/fuse_kafka.py start > {} 2>&1"' .format(conf, cwd, self.log_path('fuse_kafka'))) def consumer_start(self): """ starts fuse_kafka consumer """ if os.path.exists(self.log_path('consumer')): os.remove(self.log_path('consumer')) command = os.getcwd() + "/" + kafka_bin_directory command += "kafka-console-consumer.sh --zookeeper " command += self.zookeeper.IP() + " --topic logs" print(command) self.impersonate() # popen require setns() self.consumer = self.client.popen(command) self.impersonate(False) def tearDown(self): """ stops fuse_kafka, zookeeper, kafka, cleans their working directory and stops the virtual topology """ for host in self.java_clients: self.cmd(host, 'pkill -9 java') self.consumer.kill() self.cmd(self.fuse_kafka, 'src/fuse_kafka.py stop') os.remove(self.kafka_config.name) self.data_directories_cleanup() self.impersonate() self.net.stop() def setUp(self): """ starts the topology, downloads kafka, does a data directory cleanup in case of previous run """ self.launch = kafka_bin_directory + '{}-server-start.sh ' self.stop = kafka_bin_directory + '{}-server-stop.sh ' self.start_network() kafka_download() self.clients_initialize() self.data_directories_cleanup() self.components_start() # wait for fuse-kafka to be ready time.sleep(2) def check(self): self.assertTrue(os.path.exists(self.fuse_kafka_path), "you must build fuse kafka to run tests") os.stat("/tmp/fuse-kafka-test") def get_consumed_events(self, expected_number): from mininet.util import pmonitor events = [] log = FuseKafkaLog() popens = {} popens[self.client] = self.consumer for host, line in pmonitor(popens): self.consumer.poll() events.append(log.load_fuse_kafka_event(line)) if len(events) >= expected_number: break self.assertEqual(expected_number, len(events)) return events def write_to_log(self, what = "test"): self.cmd(self.fuse_kafka, "echo -n {} > /tmp/fuse-kafka-test/xd 2>&1".format(what)) def components_start(self): """ starts zookeepre, kafka, fuse_kafka, fuse_kafka consumer """ self.zookeeper_start() self.kafka_start() self.fuse_kafka_start() self.consumer_start() def test_basic(self): """ runs the topology with a mininet shell """ self.check() for message in ["hello", "world"]: self.write_to_log(message) events = self.get_consumed_events(1) self.assertEqual(message, events[0]["@message"]) expected = ["foo", "bar"] for message in expected: self.write_to_log(message) actual = [event["@message"] for event in self.get_consumed_events(2)] self.assertEqual(sorted(expected), sorted(actual)) def test_shutting_down_kafka(self): self.check() self.kafka_stop() self.write_to_log() self.kafka_start() self.get_consumed_events(1) def test_shutting_down_zookeeper(self): self.check() self.zookeeper_stop() self.write_to_log() self.zookeeper_start() self.get_consumed_events(1) def test_bringing_down_kafka(self): self.check() self.kafka_stop() self.write_to_log() self.kafka_start() self.get_consumed_events(1) def test_cutting_kafka(self): self.check() self.write_to_log() self.net.configLinkStatus(self.kafka.name, self.switch.name, "down") self.assertRaises(ValueError, self.get_consumed_events, (1)) self.net.configLinkStatus(self.kafka.name, self.switch.name, "up") self.get_consumed_events(1) def test_cutting_zookeeper(self): self.check() self.write_to_log() self.net.configLinkStatus(self.zookeeper.name, self.switch.name, "down") # zookeeper being brought down should not influence an already launched producer self.get_consumed_events(1) def test_cutting_kafka_periodically(self): self.check() ranges = {10: range(3), 1: range(4), 0: range(10)} for sleep_time in ranges: print("sleep time: " + str(sleep_time)) for i in ranges[sleep_time]: print("loop # " + str(i)) self.net.configLinkStatus(self.kafka.name, self.switch.name, "down") time.sleep(sleep_time) self.assertRaises(ValueError, self.get_consumed_events, (1)) self.net.configLinkStatus(self.kafka.name, self.switch.name, "up") if sleep_time > 1: time.sleep(7) # wait for kafka to be restarted self.write_to_log() self.get_consumed_events(1)
def myNetwork(): net = Mininet( topo=None, build=False, ipBase='10.0.0.0/16') info( '*** Adding controllers\n' ) c1=net.addController(name='c1', controller=RemoteController, ip='10.0.0.1', protocol='tcp', port=6653) info( '*** Add switches\n') s1 = net.addSwitch('s1', cls=OVSKernelSwitch, protocols='OpenFlow13') s2 = net.addSwitch('s2', cls=OVSKernelSwitch, protocols='OpenFlow13') s3 = net.addSwitch('s3', cls=OVSKernelSwitch, protocols='OpenFlow13') s4 = net.addSwitch('s4', cls=OVSKernelSwitch, protocols='OpenFlow13') info( '*** Add hosts\n') h1 = net.addHost('h1', cls=Host, ip='10.0.0.11', mac='00:00:00:00:00:01', defaultRoute=None) h2 = net.addHost('h2', cls=Host, ip='10.0.0.12', mac='00:00:00:00:00:02', defaultRoute=None) # h3 = net.addHost('h3', cls=Host, ip='10.0.0.13', mac='00:00:00:00:00:03', defaultRoute=None) # h4 = net.addHost('h4', cls=Host, ip='10.0.0.14', mac='00:00:00:00:00:04', defaultRoute=None) # h5 = net.addHost('h5', cls=Host, ip='10.0.0.15', mac='00:00:00:00:00:05', defaultRoute=None) # h6 = net.addHost('h6', cls=Host, ip='10.0.0.16', mac='00:00:00:00:00:06', defaultRoute=None) # h7 = net.addHost('h7', cls=Host, ip='10.0.0.17', mac='00:00:00:00:00:07', defaultRoute=None) # h8 = net.addHost('h8', cls=Host, ip='10.0.0.18', mac='00:00:00:00:00:08', defaultRoute=None) info( '*** Add links\n') net.addLink(h1, s1) net.addLink(h2, s4) # net.addLink(h2, s1) # net.addLink(h3, s2) # net.addLink(h4, s2) # net.addLink(h5, s3) #net.addLink(h6, s4) #net.configLinkStatus( 'h6', 's4', 'down' ) # net.addLink(h6, s3) #h6.nameToIntf['h6-eth1'].setIP('10.0.0.16/16') #h6.nameToIntf['h6-eth1'].setMAC('00:00:00:00:00:06') # net.addLink(h7, s4) #net.addLink(h8, s3) #net.configLinkStatus( 'h8', 's3', 'down' ) # net.addLink(h8, s4) #h8.nameToIntf['h8-eth1'].setIP('10.0.0.18/16') #h8.nameToIntf['h8-eth1'].setMAC('00:00:00:00:00:08') net.addLink(s1, s2) net.addLink(s1, s3) net.addLink(s1, s4) net.addLink(s2, s3) net.addLink(s2, s4) net.addLink(s3, s4) info( '*** Starting network\n') net.build() info( '*** Starting controllers\n') for controller in net.controllers: info(controller) controller.start() info( '*** Starting switches\n') net.get('s1').start([c1]) net.get('s2').start([c1]) net.get('s3').start([c1]) net.get('s4').start([c1]) info( '*** Post configure switches and hosts\n') h1.cmd('sudo ./sv.o 80 000000000001 010CCD040001 4001 4001 MidiaCom1CFG/LLN0\$PhsMeas1 1 1 0 300 300 300 0 288 288 288 0 0 60 0 1 4 h1-eth0 &') # h2.cmd('sudo ./goose.o -i h2-eth0 -p 8081 &') # h3.cmd('sudo ./goose.o -i h3-eth0 -p 8080 &') sleep(5) # h2.cmd('sh scripts/h2pott.sh') # h3.cmd('sh scripts/h3pott.sh') # h3.cmd('sh scripts/h3dtt.sh') CLI(net) start = datetime.now() flag = True while True: print(datetime.now() - start) for index in ['1', '2', '3', '4']: c1.cmd('echo $(date) >> logs/s' + index + '.log') c1.cmd('sudo ovs-ofctl dump-flows s' + index +' -O OpenFlow13 >> logs/s' + index + '.log') sleep(1 * 60) if flag: net.configLinkStatus('s1', 's4', 'down') else: net.configLinkStatus('s1', 's4', 'up') flag = not flag # h2.cmd("tcpreplay -i h2-eth0 -K --loop 50000 goose_test.pcap &") # h1.cmd("wireshark -i h1-eth0 -Y arp &") # h2.cmd("wireshark -i h2-eth0 -Y arp &") # h3.cmd("wireshark -i h3-eth0 -Y arp &") # h4.cmd("wireshark -i h4-eth0 -Y arp &") CLI(net) net.stop()
def BeginSimulation() : # We begin mininet initially net = Mininet( controller=Controller, switch=OVSSwitch) print "*** Creating (reference) controllers On 192.168.2.50/51 Change if necessary" c0 = RemoteController( 'c0', ip='192.168.56.21', port=6634 ) #This is parent controller (change tomcat 8081) c1 = RemoteController( 'c1', ip='192.168.56.21', port=6633 ) c2 = RemoteController( 'c2', ip='192.168.56.1', port=6633 ) print "*** Creating switches" s1 = net.addSwitch( 's1' ) s2 = net.addSwitch( 's2' ) s3 = net.addSwitch( 's3' ) s4 = net.addSwitch( 's4' ) gs1 = net.addSwitch( 'gs1' ) gs2 = net.addSwitch( 'gs2' ) print "*** Creating hosts" print "*** Creating hosts" hosts1 = [ addHost1( net, n) for n in 1, 2, 3, 4 ] hosts2 = [ addHost2( net, n) for n in 5, 6, 7, 8 ] hosts3 = [ addHost3( net, n) for n in 9, 10, 11, 12 ] hosts4 = [ addHost4( net, n) for n in 13, 14, 15, 16 ] # These are the hsots that move to other side. We will bring the links up when we want to show the host movement s3_temp_host1 = net.addHost( 'h17', ip = '10.0.0.66', mac = '00:00:00:00:00:1') s3_temp_host2 = net.addHost( 'h18', ip = '10.0.0.67', mac = '00:00:00:00:00:2') print "*** Creating links" for h in hosts1: net.addLink( s1, h ) for h in hosts2: net.addLink( s2, h ) for h in hosts3: net.addLink( s3, h ) for h in hosts4: net.addLink( s4, h ) net.addLink( s1, s2 ) net.addLink( s3, s4 ) net.addLink( s2, s3 ) net.addLink( gs1, gs2 ) # Additional links to simlulate host movement (handover). Note that this link will be down initially net.addLink( s3, s3_temp_host1) net.addLink( s3, s3_temp_host2) print "*** Starting network" net.build() c0.start() c1.start() c2.start() s1.start( [ c1 ] ) s2.start( [ c1 ] ) s3.start( [ c2 ] ) s4.start( [ c2 ] ) gs1.start( [ c0 ] ) gs2.start( [ c0 ] ) # Remember that these two links will be down initially and needs to be manually pulled up whenever we need handover net.configLinkStatus('h17', 's3', 'down') net.configLinkStatus('h18', 's3', 'down') CLI(net)
h2.cmd('route add default gw 10.0.6.4') # for debug #r1.cmd("route add -net 10.0.6.0 netmask 255.255.255.0 gw 10.0.2.2 dev r1-eth1") #r2.cmd("route add -net 10.0.1.0 netmask 255.255.255.0 gw 10.0.2.1 dev r2-eth0") for h in (h1, h2): h.cmd('./scripts/disable_offloading.sh') h.cmd('./scripts/disable_ipv6.sh') for r in (r1, r2, r3, r4): r.cmd('./scripts/disable_arp.sh') r.cmd('./scripts/disable_icmp.sh') r.cmd('./scripts/disable_ip_forward.sh') r.cmd('./scripts/disable_ipv6.sh') net.start() for index, r in enumerate((r1, r2, r3, r4)): #r.cmd('stdbuf -oL -eL ./build/mospfd-reference > result-reference/STEP1-r%d.txt 2>&1 &' % (index+1)) r.cmd('stdbuf -oL -eL ./build/mospfd > result/STEP1-r%d.txt 2>&1 &' % (index + 1)) time.sleep(20) h1.cmd("traceroute 10.0.6.22 > result/STEP2-firstPing.txt 2>&1") net.configLinkStatus("r2", "r4", "down") time.sleep(20) h1.cmd("traceroute 10.0.6.22 > result/STEP2-secondPing.txt 2>&1") net.stop()