Пример #1
0
    def _packet_in_handler(self, ev):
        """Handle packet_in events."""
        if not self.link_discovery:
            return
        msg = ev.msg
        in_port = msg.match['in_port']
        packet = Packet(msg.data)
        efm = packet.get_protocol(ethernet.ethernet)
        if efm.ethertype == ether.ETH_TYPE_ARP:
            self.send_event_to_observers(event.EventArpReceived(ev))

        try:
            src_dpid, src_port_no = LLDPPacket.lldp_parse(msg.data)
        except LLDPPacket.LLDPUnknownFormat as e:
            # This handler can receive all the packtes which can be
            # not-LLDP packet. Ignore it silently
            return
        else:
            dst_dpid = msg.datapath.id
            dst_port_no = in_port

            src = self._get_port(src_dpid, src_port_no)
            if not src or src.dpid == dst_dpid:
                return

            dst = self._get_port(dst_dpid, dst_port_no)
            if not dst:
                return

            old_peer = self.links.get_peer(src)
            #LOG.debug("Packet-In")
            #LOG.debug("  src=%s", src)
            #LOG.debug("  dst=%s", dst)
            #LOG.debug("  old_peer=%s", old_peer)
            if old_peer and old_peer != dst:
                old_link = Link(src, old_peer)
                self.send_event_to_observers(event.EventLinkDelete(old_link))

            link = Link(src, dst)
            if not link in self.links:
                self.send_event_to_observers(event.EventLinkAdd(link))

            if not self.links.update_link(src, dst):
                # reverse link is not detected yet.
                # So schedule the check early because it's very likely it's up
                try:
                    self.ports.lldp_received(dst)
                except KeyError as e:
                    # There are races between EventOFPPacketIn and
                    # EventDPPortAdd. So packet-in event can happend before
                    # port add event. In that case key error can happend.
                    # LOG.debug('lldp_received: KeyError %s', e)
                    pass
                else:
                    self.ports.move_front(dst)
                    self.lldp_event.set()
Пример #2
0
 def _link_down(self, port):
     try:
         dst, rev_link_dst = self.links.port_deleted(port)
     except KeyError:
         # LOG.debug('key error. src=%s, dst=%s',
         #           port, self.links.get_peer(port))
         return
     link = Link(port, dst)
     self.send_event_to_observers(event.EventLinkDelete(link))
     if rev_link_dst:
         rev_link = Link(dst, rev_link_dst)
         self.send_event_to_observers(event.EventLinkDelete(rev_link))
     self.ports.move_front(dst)
Пример #3
0
    def dst_port_deleted(self, dst):
        src = self.get_peer(dst)
        if src is None:
            raise KeyError()

        link = Link(src, dst)
        rev_link = Link(dst, src)
        del self[link]
        del self._map[src]
        del self._rmap[dst]
        self.pop(rev_link, None)
        rev_link_dst = self._map.pop(dst, None)

        return src, rev_link_dst
Пример #4
0
    def link_loop(self):
        while self.is_active:
            self.link_event.clear()

            now = time.time()
            deleted = []
            for (link, timestamp) in self.links.items():
                if timestamp + self.LINK_TIMEOUT < now:
                    src = link.src
                    if src in self.ports:
                        port_data = self.ports.get_port(src)
                        if port_data.lldp_dropped() > self.LINK_LLDP_DROP:
                            deleted.append(link)

            for link in deleted:
                self.links.link_down(link)
                self.send_event_to_observers(event.EventLinkDelete(link))

                dst = link.dst
                rev_link = Link(dst, link.src)
                if rev_link not in deleted:
                    # It is very likely that the reverse link is also
                    # disconnected. Check it early.
                    expire = now - self.LINK_TIMEOUT
                    self.links.rev_link_set_timestamp(rev_link, expire)
                    if dst in self.ports:
                        self.ports.move_front(dst)
                        self.lldp_event.set()

            self.link_event.wait(timeout=self.TIMEOUT_CHECK_PERIOD)
Пример #5
0
    def packet_in_handler(self, ev):
        self._logger.debug('Packet in')
        msg = ev.msg
        ofp = msg.datapath.ofproto
        pkt = packet.Packet(msg.data)
        headers = dict((p.protocol_name, p)
                       for p in pkt.protocols if type(p) != str)
        src_mac = headers[ETHERNET].src
        try:
            src_dpid, src_port_no = LLDPPacket.lldp_parse(msg.data)
        except LLDPPacket.LLDPUnknownFormat as e:
            self._logger.debug('LLDPUnknownFormat %s', e)
            return
        dst_port_no = self.ofctl.get_packet_in_inport(msg)
        dst = self._get_port(dst_port_no)
        self._logger.debug('LLDP from %d.%d -> %d',
                           src_dpid,
                           src_port_no,
                           dst_port_no)
        if not dst:
            self._logger.warning('Dst not found.')
            return
        self.ports.lldp_received(dst)
        src = Port(PortData(src_dpid, port_no=src_port_no, hw_addr=src_mac))
        old_peer = self.links.get_peer(dst)
        need_update = False
        if old_peer and old_peer != src:
            self._logger.info('Peer changed.')
            self._report_link_deleted(Link(old_peer, dst))
            need_update = True
        link = Link(src, dst)
        if link not in self.links:
            need_update = True
            self._report_link_added(Link(src, dst))
            self.lldp_event.set()

        # Always return false, since we don't have the reverse link information
        if need_update:
            self.links.update_link(src, dst)
            self._logger.info('Update link %d.%d -> %d.%d',
                              src.dpid,
                              src.port_no,
                              dst.dpid,
                              dst.port_no)
Пример #6
0
 def _link_down(self, port):
     try:
         src, rev_link_dst = self.links.dst_port_deleted(port)
         self._logger.info('Link down: %d.%d -> %d.%d',
                           src.dpid,
                           src.port_no,
                           port.dpid,
                           port.port_no)
     except KeyError:
         self._logger.info('Cannot find peer of %d.%d',
                           port.dpid,
                           port.port_no)
         return
     self._report_link_deleted(Link(src, port))
Пример #7
0
 def link_deleted(self, src_port_data, dst_port_data):
     try:
         with self._switches_lock:
             src_port = self.switches[src_port_data.dpid].update_port(
                 src_port_data)
             dst_port = self.switches[dst_port_data.dpid].update_port(
                 dst_port_data)
         with self._links_lock:
             del self.links[src_port.dpid][dst_port.dpid]
         self._logger.info('Link %d.%d -> %d.%d down', src_port_data.dpid,
                           src_port_data.port_no, dst_port_data.dpid,
                           dst_port_data.port_no)
         self.send_event_to_observers(
             EventLinkDelete(Link(src_port, dst_port)))
     except KeyError:
         self._logger.error('Cannot find link %d.%d -> %d.%d',
                            src_port_data.dpid, src_port_data.port_no,
                            dst_port_data.dpid, dst_port_data.port_no)
Пример #8
0
 def link_added(self, src_port_data, dst_port_data):
     try:
         with self._switches_lock:
             src_port = self.switches[src_port_data.dpid].update_port(
                 src_port_data)
             dst_port = self.switches[dst_port_data.dpid].update_port(
                 dst_port_data)
         link = Link(src_port, dst_port)
         with self._links_lock:
             if src_port.dpid not in self.links.keys():
                 self.links[src_port.dpid] = {}
             self.links[src_port.dpid][dst_port.dpid] = link
         self._logger.info('Link %d.%d -> %d.%d up', src_port_data.dpid,
                           src_port_data.port_no, dst_port_data.dpid,
                           dst_port_data.port_no)
         self.send_event_to_observers(EventLinkAdd(link))
     except KeyError:
         self._logger.error('Cannot find dst port %d.%d',
                            dst_port_data.dpid, dst_port_data.port_no)
Пример #9
0
 def _createLink(self, src_dpid, src_port_no, dst_dpid, dst_port_no):
     port_src = self._createPort(src_dpid, src_port_no)
     port_dst = self._createPort(dst_dpid, dst_port_no)
     return Link(port_src, port_dst)
Пример #10
0
    def _monitor(self):
        hub.sleep(200)  # Wait for the topology discovery

        host_list = get_host(self, None)
        switch_list = get_switch(self, None)
        link_list = get_link(self, None).keys()

        # Add missing backward links
        link_pairs = set([(link.src.dpid, link.dst.dpid)
                          for link in link_list])
        missing_links = [
            Link(link.dst, link.src) for link in link_list
            if not (link.dst.dpid, link.src.dpid) in link_pairs
        ]
        link_list.extend(missing_links)

        H, S = (len(host_list), len(switch_list))

        # The number of nodes, the number of flows and the number of links respectively
        # +2*H is for the links connecting switches and hosts (bidrectional)
        N, H2, L = (H + S, H * (H - 1), len(link_list) + 2 * H)

        # Gather Flow Table Rules
        self.port_dst_to_rule = {}
        self.R, self.t = (0, None)
        for dp in self.datapaths.values():
            self._request_stats(dp)
        hub.sleep(5)

        # self.port_to_link[switch_id][port_no] gives the corresponding link id
        # of the port of the switch
        self.port_to_link = {}

        # self.port_to_host[switch_id][port_no] gives the corresponding host of
        # the port of the switch
        self.port_to_host = {}

        # switch_to_links[switch_id] provides the id list of the links
        # connected to the switch
        switch_to_links = {}

        # switch_to_rules[switch_id] provides the id list of the rules
        # in the switch
        switch_to_rules = {}

        # Populate the dictionaries
        for link_id, link in enumerate(link_list):
            self.port_to_link.setdefault(link.src.dpid, {})
            self.port_to_link[link.src.dpid][link.src.port_no] = link_id, link

            switch_to_links.setdefault(link.src.dpid, [])
            switch_to_links[link.src.dpid].append(link_id)
            switch_to_links.setdefault(link.dst.dpid, [])
            switch_to_links[link.dst.dpid].append(link_id)

        # Add hosts with the links
        for host_id, host in enumerate(host_list):
            rlink_id = len(link_list) + host_id  # (Host -> Switch)
            tlink_id = rlink_id + H  # (Switch -> Host)
            switch_to_links[host.port.dpid].extend([rlink_id, tlink_id])

            self.port_to_host.setdefault(host.port.dpid, {})
            self.port_to_host[host.port.dpid][
                host.port.port_no] = rlink_id, tlink_id, host

        for switch_id in self.port_dst_to_rule:
            switch_to_rules[switch_id] = [
                rule_id for rule_id, port_no in
                self.port_dst_to_rule[switch_id].values()
            ]

        # Create the routing matricess
        A = np.zeros((L, H2))
        B = np.zeros((self.R, H2))
        flow_id = 0
        for src_id, src in enumerate(host_list):
            for dst_id, dst in enumerate(host_list):
                if src_id != dst_id:

                    # Outgoing link id of src host (Host -> Switch)
                    link_id = len(link_list) + src_id
                    A[link_id, flow_id] = 1

                    # The first switch on the path
                    switch_id = src.port.dpid

                    # The corresponding rule and out port
                    rule_id, port_no = self.port_dst_to_rule[switch_id][
                        src.port.port_no, dst.mac]
                    B[rule_id, flow_id] = 1

                    # Populate through the switches on the path
                    while port_no in self.port_to_link[switch_id]:

                        # Next Link
                        link_id, link = self.port_to_link[switch_id][port_no]
                        A[link_id, flow_id] = 1

                        # Next Switch
                        switch_id = link.dst.dpid

                        rule_id, port_no = self.port_dst_to_rule[switch_id][
                            link.dst.port_no, dst.mac]
                        B[rule_id, flow_id] = 1

                    # Incoming link id of the dst host (Switch -> Host)
                    link_id = len(link_list) + H + dst_id
                    A[link_id, flow_id] = 1

                    flow_id += 1

        im = InferenceModule(A, links=switch_to_links)
        im2 = InferenceModule(B, links=switch_to_rules)

        # Start monitoring
        T = 1000  # The number of time steps
        self.trace = np.zeros((T, L))  # Time Step x Link ID
        self.trace2 = np.zeros((T, self.R))  # Time Step x Link ID
        for self.t in range(T):
            self.logger.info('Time Step: ' + str(self.t))
            for dp in self.datapaths.values():  # Complete measurement
                self._request_stats(dp)  # See SimpleMonitor13._request_stats
            hub.sleep(1)

        # Save
        with open(
                'trace_' + datetime.now().strftime('%Y-%m-%d_%H:%M:%S') +
                '.pkl', 'w') as trace_file:
            pickle.dump(
                {
                    'im':
                    im,
                    'im2':
                    im2,
                    'A':
                    A,
                    'B':
                    B,
                    'trace':
                    self.trace,
                    'trace2':
                    self.trace2,
                    'port_dst_to_rule':
                    self.port_dst_to_rule,
                    'switch_links': [(link.src.dpid, link.dst.dpid)
                                     for link in link_list],
                    'host_links': [(host.mac, host.port.dpid)
                                   for host in host_list],
                    'switch_to_links':
                    switch_to_links,
                    'switch_to_rules':
                    switch_to_rules,
                    'H':
                    H,
                    'S':
                    S,
                    'N':
                    N,
                    'H2':
                    H2,
                    'L':
                    L,
                    'R':
                    self.R,
                    'T':
                    T
                }, trace_file)
Пример #11
0
def createLink(src_dpid, src_port_no, dst_dpid, dst_port_no):
    port_src = createPort(src_dpid, src_port_no)
    port_dst = createPort(dst_dpid, dst_port_no)
    return Link(port_src, port_dst)