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()
Example #2
0
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
Example #3
0
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()
Example #4
0
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()
Example #5
0
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()
Example #6
0
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()
Example #8
0
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
Example #12
0
    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()
Example #13
0
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()
Example #14
0
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')
Example #15
0
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')
Example #16
0
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()
Example #17
0
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()
Example #19
0
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"])
Example #20
0
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')
Example #21
0
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()
Example #25
0
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
Example #26
0

# 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()
Example #27
0
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()
Example #28
0
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('<', '&lt;')
            output = output.replace('>', '&gt;')

            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)
Example #29
0
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.")
Example #30
0
    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)
Example #33
0
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()
Example #34
0
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()
Example #36
0
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)
Example #37
0
    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()