Пример #1
0
 def do_ips(self, line):
     """ips n1 n2 ...: return the ips associated to the given node name"""
     for n in line.split(' '):
         try:
             l = [itf.ip for itf in self.mn[n].intfList()]
         except KeyError:
             l = 'unknown node'
         finally:
             lg.output(n, '|', l, "\n")
Пример #2
0
    def restoreIntfs(interfaces: List[IPIntf]):
        """Restore interfaces

            :param interfaces: the list of interfaces to restore
        """
        log.output("** starting restoring link\n")
        for interface in interfaces:
            interface.up(restore=True)
            log.output("** interfaces " + str(interface) + " up\n")
Пример #3
0
 def do_ip(self, line):
     """ip IP1 IP2 ...: return the node associated to the given IP"""
     for ip in line.split(' '):
         try:
             n = self.mn.node_for_ip(ip)
         except KeyError:
             n = 'unknown IP'
         finally:
             lg.output(ip, '|', n, "\n")
Пример #4
0
def get_config():
    conf = None
    try:
        line = sys.stdin.readline()
        conf = eval(line)
    except Exception as e:
        lg.output(str(e))
    if 'controllers' not in conf:
        return None
    if 'topo_discovery' not in conf:
        return None
    return conf
Пример #5
0
 def do_ips(self, line: str):
     """ips n1 n2 ...: return the ips associated to the given node name"""
     for n in line.split(' '):
         try:
             ips = [
                 ip.ip.compressed for itf in self.mn[n].intfList()
                 for ip in list(itf.ips()) +
                 list(itf.ip6s(exclude_lls=True))
             ]
         except KeyError:
             ips = 'unknown node'
         finally:
             lg.output(n, '|', ips, "\n")
Пример #6
0
def main():
    # Set Log Level
    lg.setLogLevel('info')
    #lg.setLogLevel( 'error' )

    #Read and parse configuration
    conf = get_config()
    if conf is None:
        send_output(None)
        return

    ctlip = list()
    ctlport = list()
    for i in range(0, len(conf['controllers'])):
        ctlip.append(conf['controllers'][i][0])
        ctlport.append(conf['controllers'][i][1])

    #Setup Network
    ts = time.time()
    topo = FixedTree(depth=1, fanout=2)
    network = Mininet(topo=topo, controller=None, switch=OVSKernelSwitch)
    for i in range(0, len(ctlip)):
        network.addController('c' + str(i + 1),
                              controller=RemoteController,
                              ip=ctlip[i],
                              port=ctlport[i])
    network.start()
    if ENABLE_STAT:
        lg.output('[timer] Setup network: %f sec.\n' % (time.time() - ts))

    #Start Switch Monitor
    monitor_id = procmon.start(pname=SWITCH_PNAME, lg=lg)

    #Tests
    ts = time.time()
    hc = HostController(network, lg, conf)
    results = hc.do_test()
    if results == None:
        results = [False]
    if ENABLE_STAT:
        lg.output('[timer] Tests: %f sec.\n' % (time.time() - ts))

    #Dump process monitor output
    stat_dict = procmon.stop(monitor_id, lg)

    # Pull Rules
    raw = []
    for s in network.switches:
        raw.append(s.name + "," + s.dpctl("dump-flows"))

    #Write Output
    d = {"results": results, "rules": raw, "stat": stat_dict}
    send_output(d)
    lg.output(str(d) + "\n")

    # Cleanup Network
    ts = time.time()
    network.stop()
    if ENABLE_STAT:
        lg.output('[timer] Stop network: %f sec.\n' % (time.time() - ts))
Пример #7
0
    def _ping_set(self, src: Node,
                  dst_dict: Mapping[Node, Union[IPv4Address, IPv6Address, str]],
                  timeout: Optional[str], v4=True) -> Tuple[int, int]:
        """Do the actual ping to the dict of {dst: dst_ip} from src

           :param src: origin of the ping
           :param dst_dict: destinations {dst: dst_ip} of the ping
           :param timeout: the time to wait for a response, as string
           :param v4: whether IPv4 or IPv6 is used
           :param return: a tuple (lost packets, sent packets)"""
        if len(dst_dict) == 0:
            return 0, 0
        lost = 0
        packets = 0
        opts = ''
        if timeout:
            opts = '-W %s' % timeout

        log.output("%s --%s--> " % (src.name, "IPv4" if v4 else "IPv6"))
        for dst, dst_ip in dst_dict.items():
            result = src.cmd('%s -c1 %s %s' % ("ping" if v4 else PING6_CMD,
                                               opts, dst_ip))
            sent, received = self._parsePing(result)
            lost += sent - received
            packets += sent
            log.output("%s " % dst.name if received else "X ")
        log.output('\n')

        return lost, packets
Пример #8
0
    def _ping_set(self, src, dst_dict, timeout, v4=True):
        """Do the actual ping to the dict of {dst: dst_ip} from src

           :param src: origin of the ping
           :param dst_dict: destinations {dst: dst_ip} of the ping
           :param timeout: the time to wait for a response, as string
           :param v4: whether IPv4 or IPv6 is used
           :param return: a tuple (lost packets, sent packets)"""
        if len(dst_dict) == 0:
            return 0, 0
        lost = 0
        packets = 0
        opts = ''
        if timeout:
            opts = '-W %s' % timeout

        log.output("%s --%s--> " % (src.name, "IPv4" if v4 else "IPv6"))
        for dst, dst_ip in dst_dict.iteritems():
            result = src.cmd('%s -c1 %s %s' % ("ping" if v4 else PING6_CMD,
                                               opts, dst_ip))
            sent, received = self._parsePing(result)
            lost += sent - received
            packets += sent
            log.output("%s " % dst.name if received else "X ")
        log.output('\n')

        return lost, packets
Пример #9
0
    def runFailurePlan(self, failure_plan: List[Tuple[str, str]]) \
            -> List[IPIntf]:
        """Run a failure plan

            :param: A list of pairs of node names: links connecting these two
                    links will be downed
            :return: A list of interfaces that were downed
        """
        log.output("** Starting failure plan\n")
        interfaces_down = []
        for node1, node2 in failure_plan:
            try:
                links = self[node1].connectionsTo(self[node2])
                for link in links:
                    interfaces_down.extend(link)
            except KeyError as e:
                log.error("Node " + str(e) + " does not exist\n")
                interfaces_down = []
        for interface in interfaces_down:
            interface.down(backup=True)
            log.output("** Interface " + str(interface) + " down\n")
        return interfaces_down
Пример #10
0
    def randomFailure(self, n: int, weak_links: Optional[List[IPLink]] = None)\
            -> List[IPIntf]:
        """Randomly down 'n' link

            :param n: the number of link to be downed
            :param weak_links: the list of links that can be downed; if set
                               to None, every network link can be downed
            :return: the list of interfaces which were downed
        """
        all_links = weak_links if weak_links is not None else self.links
        number_of_links = len(all_links)
        if n > number_of_links:
            log.error("More link down requested than number of link"
                      " that can be downed\n")
            return []

        downed_interfaces = []
        down_links = random.sample(all_links, k=n)
        for link in down_links:
            for intf in [link.intf1, link.intf2]:
                intf.down(backup=True)
                log.output("** Interface " + str(intf) + " down\n")
                downed_interfaces.append(intf)
        return downed_interfaces
Пример #11
0
    def ping(self, hosts: Optional[List[Node]] = None,
             timeout: Optional[str] = None, use_v4=True, use_v6=True) -> float:
        """Ping between all specified hosts.
           If use_v4 is true, pings over IPv4 are used between any pair of
           hosts having at least one IPv4 address on one of their interfaces
           (loopback excluded).
           If use_v6 is true, pings over IPv6 are used between any pair of
           hosts having at least one non-link-local IPv6 address on one of
           their interfaces (loopback excluded).

           :param hosts: list of hosts or None if all must be pinged
           :param timeout: time to wait for a response, as string
           :param use_v4: whether IPv4 addresses can be used
           :param use_v6: whether IPv6 addresses can be used
           :return: the packet loss percentage of IPv4 connectivity if
                    self.use_v4 is set the loss percentage of IPv6 connectivity
                    otherwise"""
        packets = lost = 0
        host_list = self.hosts
        if hosts is not None:
            host_list = hosts
        incompatible_hosts = {}  # type: Dict[str, Set[str]]
        if not use_v4 and not use_v6:
            log.output("*** Warning: Parameters forbid both IPv4 and IPv6 for "
                       "pings\n")
            return 0

        log.output("*** Ping: testing reachability over %s%s%s\n"
                   % ("IPv4" if use_v4 else "",
                      " and " if use_v4 and use_v6 else "",
                      "IPv6" if use_v6 else ""))
        for src in host_list:
            src_ip, src_ip6 = address_pair(src, use_v4, use_v6)
            ping_dict = {}
            ping6_dict = {}
            for dst in host_list:
                if src != dst:
                    dst_ip, dst_ip6 = address_pair(dst, src_ip is not None,
                                                   src_ip6 is not None)
                    if dst_ip is not None:
                        ping_dict[dst] = dst_ip
                    if dst_ip6 is not None:
                        ping6_dict[dst] = dst_ip6
                    if (use_v4 and dst_ip is None and
                            use_v6 and dst_ip6 is None):
                        node1 = src if src.name <= dst.name else dst
                        node2 = src if node1 != src else dst
                        if node2.name not in incompatible_hosts.setdefault(
                                node1.name, set()):
                            incompatible_hosts[node1.name].add(node2.name)

            result = self._ping_set(src, ping_dict, timeout, True)
            lost += result[0]
            packets += result[1]
            result = self._ping_set(src, ping6_dict, timeout, False)
            lost += result[0]
            packets += result[1]

        for node1, incompatibilities in incompatible_hosts.items():
            for node2 in incompatibilities:
                log.output("*** Warning: %s and %s have no global address "
                           "in the same IP version\n" % (node1, node2))

        if packets > 0:
            ploss = 100.0 * lost / packets
            received = packets - lost
            log.output("*** Results: %i%% dropped (%d/%d received)\n" %
                       (ploss, received, packets))
        else:
            ploss = 0
            log.output("*** Warning: No packets sent\n")

        return ploss
Пример #12
0
        stat_dict = procmon.stop(monitor_id, lg)
    except Exception as e:
        lg.output(str(e))
        stat_dict = {}

    # Pull Rules
    raw = []
    for s in network.switches:
        raw.append(s.name + "," + s.dpctl("dump-flows"))

    #Write Output
    d = {"results": results, "rules": raw, "stat": stat_dict}
    send_output(d)
    lg.output(str(d) + "\n")

    # Cleanup Network
    ts = time.time()
    network.stop()
    if ENABLE_STAT:
        lg.output('[timer] Stop network: %f sec.\n' % (time.time() - ts))


# Main
if __name__ == '__main__':
    try:
        main()
    except Exception as e:
        send_output(None)
        lg.output(e)
        os.system("mn -c > /dev/null 2>/dev/null")
Пример #13
0
    def ping(self, hosts=None, timeout=None, use_v4=True, use_v6=True):
        """Ping between all specified hosts.
           If use_v4 is true, pings over IPv4 are used between any pair of
           hosts having at least one IPv4 address on one of their interfaces
           (loopback excluded).
           If use_v6 is true, pings over IPv6 are used between any pair of
           hosts having at least one non-link-local IPv6 address on one of
           their interfaces (loopback excluded).

           :param hosts: list of hosts or None if all must be pinged
           :param timeout: time to wait for a response, as string
           :param use_v4: whether IPv4 addresses can be used
           :param use_v6: whether IPv6 addresses can be used
           :return: the packet loss percentage of IPv4 connectivity if
                    self.use_v4 is set the loss percentage of IPv6 connectivity
                    otherwise"""
        packets = lost = 0
        if not hosts:
            hosts = self.hosts
        incompatible_hosts = {}
        if not use_v4 and not use_v6:
            log.output("*** Warning: Parameters forbid both IPv4 and IPv6 for "
                       "pings\n")
            return 0

        log.output("*** Ping: testing reachability over %s%s%s\n"
                   % ("IPv4" if use_v4 else "",
                      " and " if use_v4 and use_v6 else "",
                      "IPv6" if use_v6 else ""))
        for src in hosts:
            src_ip, src_ip6 = address_pair(src, use_v4, use_v6)
            ping_dict = {}
            ping6_dict = {}
            for dst in hosts:
                if src != dst:
                    dst_ip, dst_ip6 = address_pair(dst, src_ip is not None,
                                                   src_ip6 is not None)
                    if dst_ip is not None:
                        ping_dict[dst] = dst_ip
                    if dst_ip6 is not None:
                        ping6_dict[dst] = dst_ip6
                    if (use_v4 and dst_ip is None and
                            use_v6 and dst_ip6 is None):
                        node1 = src if src.name <= dst.name else dst
                        node2 = src if node1 != src else dst
                        if node2.name not in incompatible_hosts.setdefault(
                                node1.name, set()):
                            incompatible_hosts[node1.name].add(node2.name)

            result = self._ping_set(src, ping_dict, timeout, True)
            lost += result[0]
            packets += result[1]
            result = self._ping_set(src, ping6_dict, timeout, False)
            lost += result[0]
            packets += result[1]

        for node1, incompatibilities in incompatible_hosts.iteritems():
            for node2 in incompatibilities:
                log.output("*** Warning: %s and %s have no global address "
                           "in the same IP version\n" % (node1, node2))

        if packets > 0:
            ploss = 100.0 * lost / packets
            received = packets - lost
            log.output("*** Results: %i%% dropped (%d/%d received)\n" %
                       (ploss, received, packets))
        else:
            ploss = 0
            log.output("*** Warning: No packets sent\n")

        return ploss
Пример #14
0
def do(datadir, jsondir, tmpdir, runs):
    """

    :param datadir: directory where to save pcaps
    :param jsondir: directory where to save jsons
    :param tmpdir:  directory where to save pcaps temporarily
    :param runs: list of topology information
    """
    runtime_params = []

    # it is possible to have multiple topologies in parallel (untested, we only used one)
    for run in runs:
        runtime_params.append({})
        runtime_params[-1]['time'] = run['time']
        runtime_params[-1]['opts'] = run
        ok = False

        while True:
            # find unused filenames
            uniqueid = uuid.uuid4().hex
            runtime_params[-1]['uniquename'] = run['pcapName'] + '+' + uniqueid

            logfilename = jsondir + runtime_params[-1]['uniquename'] + ".log"
            templogfilename = tmpdir + '/' + runtime_params[-1][
                'uniquename'] + ".log"
            runtime_params[-1]['templogfilename'] = templogfilename
            runtime_params[-1]['logfilename'] = logfilename

            runtime_params[-1]['jsonfilename'] = jsondir + runtime_params[-1][
                'uniquename'] + ".json"

            if not os._exists(logfilename):
                break

        # log into file
        runtime_params[-1]['filehandler'] = logging.FileHandler(
            templogfilename)

        runtime_params[-1]['filehandler'].setLevel(logging.INFO)
        lg.addHandler(runtime_params[-1]['filehandler'])

    retry = 0
    while True:
        retry += 1

        # setup topology from params
        topo = DynamicTopo(runs)
        net = MininetCong(
            topo=topo,
            link=TCLinkTBF,
            controller=None,  # OVSController,
            switch=OVSBridge)
        # setup and build network
        net.start()
        net.waitConnected()

        for runtime in runtime_params:
            lg.output("%s\n" % runtime['opts'])

        run_senders = topo.getSenders()
        run_recordsenders = topo.getRecordsenders()
        run_receivers = topo.getReceivers()
        run_recorddevcons = topo.getRecordDevCons()
        # print(run_recorddevcons)
        run_recordlinks = topo.getRecordingLinks()

        switch_by_name = {s.name: s for s in net.switches}
        hosts_by_name = {h.name: h for h in net.hosts}

        run_senders = [[hosts_by_name[sender] for sender in senders]
                       for senders in run_senders]
        run_receivers = [[hosts_by_name[receiver] for receiver in receivers]
                         for receivers in run_receivers]
        run_recordsenders = [[
            hosts_by_name[recordsender] for recordsender in recordsenders
        ] for recordsenders in run_recordsenders]
        run_recorddevcons = [[(hosts_by_name[a], hosts_by_name[b], c, p)
                              for a, b, c, p in devcons]
                             for devcons in run_recorddevcons]

        recs = []

        # set up recordings
        for senders, recordlinks, runtime, recordsenders in zip(
                run_senders, run_recordlinks, runtime_params,
                run_recordsenders):
            last_sender = recordsenders[0]
            assert len(recordsenders) == 1
            # switches = [(s0, "s0"), (s1, "s1"), (s4, "s4"), (s5, "s5")]
            # edgeswitches = [(switch_by_name[first_switch], "s0"), (switch_by_name[last_switch], "s5")]

            runtime['opts']['ip'] = last_sender.IP()

            for link, switchname, name in recordlinks:
                print(link())
                switch = switch_by_name[switchname]
                filename = runtime['uniquename'] + "+" + name + ".pcap"
                recs.append(
                    PcapRecorder(switch, tmpdir + '/' + filename,
                                 link().name, last_sender.IP(),
                                 datadir + filename))

        # try up to 40 times to ping the connected hots
        for i in range(40):
            l = 0
            for senders, receivers, recordsenders in zip(
                    run_senders, run_receivers, run_recordsenders):
                all_hosts = senders + recordsenders + receivers
                l += net.ping(all_hosts)

            if l == 0:
                break

        sleep(2)

        # start trafficgen server
        for receiver, runtime in zip(run_receivers, runtime_params):
            for h2 in receiver:
                lg.output("start own server %s\n" % h2.name)
                # h1 is client sender, h2 is server receiver
                # data is sent from h1 to h2
                net.ownStartServer(h2, seconds=runtime['time'] + 10)
                # h2.cmd("timeout 20 nc -l -p 5001 > /dev/null &")

        sleep(2)

        # start test is server is listening
        con = True
        for recorddevcon, runtime in zip(run_recorddevcons, runtime_params):
            for (h1, h2, c, p) in recorddevcon:
                lg.output("test connection between server %s and client %s\n" %
                          (h2.name, h1.name))
                con = net.ownTestConnection(h2, h1)
                if not con:
                    break
        if not con:
            lg.output("connection failed\n")
            with open("errors.txt", "a+") as f:
                f.write("connection failed\n")
            for receiver in run_receivers:
                for h2 in receiver:
                    lg.output("stop own server %s\n" % h2.name)
                    # h1 is client, h2 is server
                    # data is sent from h1 to h2
                    net.ownStopServer(h2)
            try:
                net.stop()
            except:
                pass
            cleanup()
            if retry <= 3:
                continue
            else:
                lg.output("3 retries failed\n")
                with open("errors.txt", "a+") as f:
                    f.write("3 retries failed\n")
                break

        lg.output("run generation\n")

        # start client (sender) of background connections
        i = 0
        for recordsenders, devcon, runtime in zip(run_recordsenders,
                                                  run_recorddevcons,
                                                  runtime_params):
            # for (h1, h2) in zip(sender, receiver):
            for (h1, h2, cong, pacing) in devcon:
                if h1 in recordsenders:
                    continue
                net.ownStartClient(h2,
                                   h1,
                                   seconds=runtime['time'] + 2 + 2,
                                   cong=cong,
                                   pacing=pacing)
                # h1.cmd("timeout 15 nc 10.0.0.1 5001 & ")
                i += 1

        # start tcpdump recording
        for rec in recs:
            rec.start()

        sleep(2)

        # start client (sender) which should be recorded
        for recordsenders, devcon, runtime in zip(run_recordsenders,
                                                  run_recorddevcons,
                                                  runtime_params):
            # for (h1, h2) in zip(sender, receiver):
            for (h1, h2, cong, pacing) in devcon:
                if not h1 in recordsenders:
                    continue
                net.ownStartClient(h2,
                                   h1,
                                   seconds=runtime['time'],
                                   cong=cong,
                                   pacing=pacing)
                # h1.cmd("timeout 10 dd if=/dev/zero | nc 10.0.0.2 5001")
                #        net.iperf((h1, h2), seconds=5, cong=cong[-1])

        sleep(max([runtime['time'] for runtime in runtime_params]) + 2)

        # stop recording
        for rec in recs:
            rec.stop()

        # stop client and server and check whether succesful
        try:
            for sender, receiver, recordsender, runtime in zip(
                    run_senders, run_receivers, run_recordsenders,
                    runtime_params):
                for h1 in sender + recordsender:
                    # h1 is client, h2 is server
                    lg.output("stop %s\n" % h1.name)
                    net._parseOwn(net.ownStopClient(h1))
                for h2 in receiver:
                    lg.output("stop %s\n" % h2.name)
                    net._parseOwn(net.ownStopServer(h2))

        except Exception as e:
            lg.output("stopping hosts failed\n")
            with open("errors.txt", "a+") as f:
                f.write("stopping hosts failed " + str(e) + "\n")
            for sender, receiver, recordsender, runtime in zip(
                    run_senders, run_receivers, run_recordsenders,
                    runtime_params):
                for h1 in sender + recordsender:
                    # h1 is client, h2 is server
                    lg.output("stop %s\n" % h1.name)
                    net.ownStopClient(h1)
                for h2 in receiver:
                    lg.output("stop %s\n" % h2.name)
                    net.ownStopServer(h2)
            cleanup()
            if retry <= 3:
                continue
            else:
                lg.output("3 retries failed\n")
                with open("errors.txt", "a+") as f:
                    f.write("3 retries failed\n")
                break

        net.stop()
        ok = True
        break

    print("remove handler\n")
    for runtime in runtime_params:
        with open(runtime['jsonfilename'], 'w') as f:
            f.write(json.dumps(runtime['opts']))
            f.flush()
        lg.removeHandler(runtime['filehandler'])
        shutil.move(runtime['templogfilename'], runtime['logfilename'])
    cleanup()
    print("done\n")
    return ok
Пример #15
0
 def do_route(self, line=""):
     """route destination: Print all the routes towards that destination
     for every router in the network"""
     for r in self.mn.routers:
         lg.output("[%s] " % r.name)
         self.default('%s ip route get %s' % (r.name, line))