2015-07-08 5 views
0

У меня есть topo с 4 коммутаторами и 4 хостами. Коммутаторы создают цикл. Моя цель - изучить топологию сети, когда коммутаторы подключены к контроллеру. Проблема в том, что функция get_all_links() возвращает все возможные ссылки или, по крайней мере, что-то, что не имеет смысла. Я вызываю эту функцию при запуске события port_modify.get_all_link (self), выводящий все возможные LINK для topo

Вот код, я использую для построения топо:

<Removed Imports to save space> 
class Simple3PktSwitch(Topo): 
    """Simple topology example.""" 

    def __init__(self): 
     """Create custom topo.""" 

     # Initialize topology 
     Topo.__init__(self) 

     # Add hosts and switches 
     h1 = self.addHost('h1') 
     h2 = self.addHost('h2') 
     h3 = self.addHost('h3') 
     h4 = self.addHost('h4') 

     # Adding switches 
     p1 = self.addSwitch('p1', dpid="0000000000000001") 
     p2 = self.addSwitch('p2', dpid="0000000000000002") 
     p3 = self.addSwitch('p3', dpid="0000000000000003") 
     p4 = self.addSwitch('p4', dpid="0000000000000004") 

     # Add links 
     self.addLink(h1, p1) 
     self.addLink(h2, p2) 
     self.addLink(h3, p3) 
     self.addLink(h4, p4) 

     self.addLink(p2, p4) 
     self.addLink(p1, p2) 
     self.addLink(p3, p4) 
     self.addLink(p1, p3) 


def run(): 
    c = RemoteController('c', '0.0.0.0', 6633) 
    net = Mininet(topo=Simple3PktSwitch(), controller=None, autoSetMacs=True) 
    net.addController(c) 
    net.start() 

    # installStaticFlows(net) 
    CLI(net) 
    net.stop() 

# if the script is run directly (sudo custom/optical.py): 
if __name__ == '__main__': 
    setLogLevel('info') 
    run() 

Вот мой код для Ryu:

from ryu.base import app_manager 
from ryu.controller import ofp_event 
from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER, DEAD_DISPATCHER 
from ryu.controller.handler import set_ev_cls 
from ryu.ofproto import ofproto_v1_3 
from ryu.lib.packet import packet 
from ryu.lib.packet import ethernet 

from ryu.topology import event 
from ryu.topology.api import get_all_switch, get_all_link 
from ryu.lib import dpid as dpid_lib 
from ryu.controller import dpset 
import networkx as nx 
UP = 1 
DOWN = 0 


class SimpleSwitch13(app_manager.RyuApp): 
    OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION] 

    def __init__(self, *args, **kwargs): 
     super(SimpleSwitch13, self).__init__(*args, **kwargs) 
     # USed for learning switch functioning 
     self.mac_to_port = {} 
     # Holds the topology data and structure 
     self.topo_shape = TopoStructure() 


    """ 
    This function determines the links and switches currently in the topology 
    """ 
    def get_topology_data(self): 
     # Call get_switch() to get the list of objects Switch. 
     self.topo_shape.topo_raw_switches = get_all_switch(self) 

     # Call get_link() to get the list of objects Link. 
     self.topo_shape.topo_raw_links = get_all_link(self) 

     self.topo_shape.print_links("get_topology_data") 
     self.topo_shape.print_switches("get_topology_data") 

    ################################################################################### 
    """ 
    EventOFPPortStatus: An event class for switch port status notification. 
    The bellow handles the event. 
    """ 
    @set_ev_cls(dpset.EventPortModify, MAIN_DISPATCHER) 
    def port_modify_handler(self, ev): 
     dp = ev.dp 
     port_attr = ev.port 
     dp_str = dpid_lib.dpid_to_str(dp.id) 
     self.logger.info("\t ***switch dpid=%s" 
         "\n \t port_no=%d hw_addr=%s name=%s config=0x%08x " 
         "\n \t state=0x%08x curr=0x%08x advertised=0x%08x " 
         "\n \t supported=0x%08x peer=0x%08x curr_speed=%d max_speed=%d" % 
         (dp_str, port_attr.port_no, port_attr.hw_addr, 
          port_attr.name, port_attr.config, 
          port_attr.state, port_attr.curr, port_attr.advertised, 
          port_attr.supported, port_attr.peer, port_attr.curr_speed, 
          port_attr.max_speed)) 
     if port_attr.state == 1: 
      self.topo_shape.print_links("Link Down") 
      out = self.topo_shape.link_with_src_port(port_attr.port_no, dp.id) 
      print "out"+str(out) 
      if out is not None: 
       print(self.topo_shape.find_shortest_path(out.src.dpid)) 
     elif port_attr.state == 0: 
      self.topo_shape.topo_raw_links = get_all_link(self) ### HERE ### 
      print ("Link count: "+str(len(self.topo_shape.topo_raw_links))) 
      self.topo_shape.print_links("Link Up") 
      #self.topo_shape.topo_raw_links = get_all_link(self) 
      #self.topo_shape.print_links("Link Up") 


    ################################################################################### 

""" 
This class holds the list of links and switches in the topology and it provides some useful functions 
""" 
class TopoStructure(): 
    def __init__(self, *args, **kwargs): 
     self.topo_raw_switches = [] 
     self.topo_raw_links = [] 
     self.topo_links = [] 

     self.net = nx.DiGraph() 

    def print_links(self, func_str=None): 
     # Convert the raw link to list so that it is printed easily 
     print(" \t"+str(func_str)+": Current Links:") 
     for l in self.topo_raw_links: 
      print (" \t\t"+str(l)) 

    def print_switches(self, func_str=None): 
     print(" \t"+str(func_str)+": Current Switches:") 
     for s in self.topo_raw_switches: 
      print (" \t\t"+str(s)) 

    def switches_count(self): 
     return len(self.topo_raw_switches) 

    def convert_raw_links_to_list(self): 
     # Build a list with all the links [((srcNode,port), (dstNode, port))]. 
     # The list is easier for printing. 
     self.lock.acquire() 
     self.topo_links = [((link.src.dpid, link.src.port_no), 
          (link.dst.dpid, link.dst.port_no)) 
          for link in self.topo_raw_links] 
     self.lock.release() 

    def convert_raw_switch_to_list(self): 
     # Build a list with all the switches ([switches]) 
     self.lock.acquire() 
     self.topo_switches = [(switch.dp.id, UP) for switch in self.topo_raw_switches] 
     self.lock.release() 

    """ 
    Adds the link to list of raw links 
    """ 
    def bring_up_link(self, link): 
     self.topo_raw_links.append(link) 

    """ 
    Check if a link with specific nodes exists. 
    """ 
    def check_link(self,sdpid, sport, ddpid, dport): 
     for i, link in self.topo_raw_links: 
      if ((sdpid, sport), (ddpid, dport)) == ((link.src.dpid, link.src.port_no), (link.dst.dpid, link.dst.port_no)): 
       return True 
     return False 

    """ 
    Finds the shortest path from source s to destination d. 
    Both s and d are switches. 
    """ 
    def find_shortest_path(self, s): 
     s_count = self.switches_count() 
     s_temp = s 
     visited = [] 
     shortest_path = {} 

     while s_count != len(visited): 
      print visited 
      visited.append(s_temp) 
      print visited 
      print ("s_temp 1: " + str(s_temp)) 
      for l in self.find_links_with_src(s_temp): 
       print "\t"+str(l) 
       if l.dst.dpid not in visited: 
        print ("\t\tDPID dst: "+ str(l.dst.dpid)) 
        if l.src.dpid in shortest_path: 
         shortest_path[l.dst.dpid] += 1 
         print("\t\t\tdpid found. Count: "+str(shortest_path[l.dst.dpid])) 
        else: 
         print("\t\t\tdpid not found.") 
         shortest_path[l.dst.dpid] = 0 
      print ("shortest_path: "+str(shortest_path)) 
      min_val = min(shortest_path.itervalues()) 
      t = [k for k,v in shortest_path.iteritems() if v == min_val] 
      s_temp = t[0] 
      print "s_temp 2: " + str(s_temp)+"\n" 
     return shortest_path 

    """ 
    Finds the dpids of destinations where the links' source is s_dpid 
    """ 
    def find_dst_with_src(self, s_dpid): 
     d = [] 
     for l in self.topo_raw_links: 
      if l.src.dpid == s_dpid: 
       d.append(l.dst.dpid) 
     return d 

    """ 
    Finds the list of link objects where links' src dpid is s_dpid 
    """ 
    def find_links_with_src(self, s_dpid): 
     d_links = [] 
     for l in self.topo_raw_links: 
      if l.src.dpid == s_dpid: 
       d_links.append(l) 
     return d_links 

    """ 
    Returns a link object that has in_dpid and in_port as either source or destination dpid and port. 
    """ 
    def link_with_src_dst_port(self, in_port, in_dpid): 
     for l in self.topo_raw_links: 
      if (l.src.dpid == in_dpid and l.src.port_no == in_port) or (l.dst.dpid == in_dpid and l.src.port_no == in_port): 
       return l 
     return None 
    """ 
    Returns a link object that has in_dpid and in_port as either source dpid and port. 
    """ 
    def link_with_src_port(self, in_port, in_dpid): 
     for l in self.topo_raw_links: 
      if (l.src.dpid == in_dpid and l.src.port_no == in_port) or (l.dst.dpid == in_dpid and l.src.port_no == in_port): 
       return l 
     return None 

Так что, когда я проверяю ссылки он дает мне 24 ссылки в то время как Eсть только 4.

Код частично на SDNLab. Я удалил некоторые события, чтобы сэкономить место. Полный код: https://github.com/Ehsan70/RyuApps/blob/master/topo_learner.py

ответ

0

Проблема решена.

Мне пришлось использовать copy.copy() для обновления self.topo_shape.topo_raw_switches. то есть: self.topo_shape.topo_raw_switches = copy.copy(get_all_switch(self))