sdn控制器拓扑发现(二)

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


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

    def __init__(self, *args,**kwargs):
        super(MySwitch,self).__init__(*args,**kwargs)
        self.mac_to_port = {} # Mac address is defined
    @set_ev_cls(ofp_event.EventOFPSwitchFeatures,CONFIG_DISPATCHER)
    def switch_features_handler(self, ev):
        datapath = ev.msg.datapath
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser

        #set if packet is lldp, send to controller
        actions = [parser.OFPActionOutput(port=ofproto.OFPP_CONTROLLER,
                                          max_len=ofproto.OFPCML_NO_BUFFER)]
        inst = [parser.OFPInstructionActions(type_=ofproto.OFPIT_APPLY_ACTIONS,actions=actions)]
        match = parser.OFPMatch(eth_type=ether_types.ETH_TYPE_LLDP)
        //lib/packet/ether_types.py:25:ETH_TYPE_LLDP = 0x88cc
        mod = parser.OFPFlowMod(datapath=datapath,
                                priority=1,
                                match=match,
                                instructions=inst)
        datapath.send_msg(mod)

        self.send_port_desc_stats_request(datapath)# send the request


    def add_flow(self, datapath, priority, match, actions):
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser

        inst = [parser.OFPInstructionActions(ofproto.OFPIT_APPLY_ACTIONS,actions)]

        mod = parser.OFPFlowMod(datapath=datapath,priority=priority,match=match,instructions=inst)
        datapath.send_msg(mod)


    def send_port_desc_stats_request(self, datapath):
        ofproto = datapath.ofproto
        ofp_parser = datapath.ofproto_parser
    
        req = ofp_parser.OFPPortDescStatsRequest(datapath, 0)
        datapath.send_msg(req)


    # Send the lldp packet
    def send_lldp_packet(self, datapath, port, hw_addr, ttl):
        ofproto = datapath.ofproto
        ofp_parser = datapath.ofproto_parser

        pkt = packet.Packet()
        pkt.add_protocol(ethernet.ethernet(ethertype=ether_types.ETH_TYPE_LLDP,src=hw_addr ,dst=lldp.LLDP_MAC_NEAREST_BRIDGE))

        #chassis_id = lldp.ChassisID(subtype=lldp.ChassisID.SUB_LOCALLY_ASSIGNED, chassis_id=str(datapath.id))
        chassis_id = lldp.ChassisID(subtype=lldp.ChassisID.SUB_LOCALLY_ASSIGNED, chassis_id=str(datapath.id).encode('utf-8'))
        #port_id = lldp.PortID(subtype=lldp.PortID.SUB_LOCALLY_ASSIGNED, port_id=str(port))
        port_id = lldp.PortID(subtype=lldp.PortID.SUB_LOCALLY_ASSIGNED, port_id=str(port).encode('utf-8'))
        #port_id = lldp.PortID(subtype=lldp.PortID.SUB_LOCALLY_ASSIGNED, port_id=b'1/3')
        ttl = lldp.TTL(ttl=1)
        end = lldp.End()
        tlvs = (chassis_id,port_id,ttl,end)
        pkt.add_protocol(lldp.lldp(tlvs))
        pkt.serialize()
        self.logger.info("packet-out %s" % pkt)
        data = pkt.data
        actions = [ofp_parser.OFPActionOutput(port=port)]
        out = ofp_parser.OFPPacketOut(datapath=datapath,
                                  buffer_id=ofproto.OFP_NO_BUFFER,
                                  in_port=ofproto.OFPP_CONTROLLER,
                                  actions=actions,
                                  data=data)
        datapath.send_msg(out)
    '''
    @set_ev_cls(ofp_event.EventOFPPortDescStatsReply, MAIN_DISPATCHER)
    def port_desc_stats_reply_handler(self, ev):
        datapath = ev.msg.datapath
        ofproto = datapath.ofproto
        ports = []
        for p in ev.msg.body:
            if p.port_no <=ofproto.OFPP_MAX: 
                ports.append('port_no=%d hw_addr=%s name=%s config=0x%08x '
                     'state=0x%08x curr=0x%08x advertised=0x%08x '
                     'supported=0x%08x peer=0x%08x curr_speed=%d '
                     'max_speed=%d' %
                     (p.port_no, p.hw_addr,
                      p.name, p.config,
                      p.state, p.curr, p.advertised,
                      p.supported, p.peer, p.curr_speed,
                      p.max_speed))
        self.logger.debug('OFPPortDescStatsReply received: %s', ports)
    '''
    @set_ev_cls(ofp_event.EventOFPPortDescStatsReply, MAIN_DISPATCHER)
    def port_desc_stats_reply_handler(self, ev):
        datapath = ev.msg.datapath
        ofproto = datapath.ofproto
        ofp_parser = datapath.ofproto_parser
        ports = []
        for stat in ev.msg.body:
            if stat.port_no <=ofproto.OFPP_MAX: 
                ports.append({'port_no':stat.port_no,'hw_addr':stat.hw_addr})
        for no in ports:
            in_port = no['port_no']
            match = ofp_parser.OFPMatch(in_port = in_port)
            for other_no in ports:
                if other_no['port_no'] != in_port:
                    out_port = other_no['port_no']            ###适用于线性结构
            self.logger.debug('port 0x%08x  send lldp  to 0x%08x ', no['port_no'], out_port)
            self.send_lldp_packet(datapath,no['port_no'],no['hw_addr'],10)
            actions = [ofp_parser.OFPActionOutput(out_port)]
            self.add_flow(datapath, 1, match, actions)

    @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
    def packet_in_handler(self, ev):
        msg = ev.msg
        datapath = msg.datapath
        ofproto = datapath.ofproto
        parser = datapath.ofproto_parser


        pkt = packet.Packet(data=msg.data)
        dpid = datapath.id # switch id which send the packetin
        in_port  = msg.match['in_port']

        pkt_ethernet = pkt.get_protocol(ethernet.ethernet)
        pkt_lldp = pkt.get_protocol(lldp.lldp)
        if not pkt_ethernet:
            return 
        #print(pkt_lldp)
        if pkt_lldp:
            self.handle_lldp(dpid,in_port,pkt_lldp.tlvs[0].chassis_id,pkt_lldp.tlvs[1].port_id)


        #self.logger.info("packet-in %s" % (pkt,))

    # Link two switch
    def switch_link(self,s_a,s_b):
        return s_a + '<--->' + s_b
            
    def handle_lldp(self,dpid,in_port,lldp_dpid,lldp_in_port):
        switch_a = 'switch'+str(dpid)+', port'+str(in_port)
        switch_b = 'switch'+lldp_dpid.decode('utf-8')+', port'+lldp_in_port.decode('utf-8')
        link = self.switch_link(switch_a,switch_b)

        # Check the switch link is existed
        if not any(self.switch_link(switch_b,switch_a) == search for search in self.link):
            self.link.append(link)


        print(self.link)

 没有连接controller之前

[root@kunpeng82 devuser]# ovs-ofctl dump-flows s1 -O openflow13
[root@kunpeng82 devuser]# ovs-ofctl dump-flows s2 -O openflow13
[root@kunpeng82 devuser]# ovs-ofctl dump-flows s3 -O openflow13
[root@kunpeng82 devuser]# ovs-ofctl show s1 -O openflow13
OFPT_FEATURES_REPLY (OF1.3) (xid=0x2): dpid:0000000000000001
n_tables:254, n_buffers:0
capabilities: FLOW_STATS TABLE_STATS PORT_STATS GROUP_STATS QUEUE_STATS
OFPST_PORT_DESC reply (OF1.3) (xid=0x3):
 1(s1-eth1): addr:ae:a5:76:f3:e8:ae
     config:     0
     state:      LIVE
     current:    10GB-FD COPPER
     speed: 10000 Mbps now, 0 Mbps max
 2(s1-eth2): addr:be:6e:15:28:3c:5e
     config:     0
     state:      LIVE
     current:    10GB-FD COPPER
     speed: 10000 Mbps now, 0 Mbps max
 LOCAL(s1): addr:ea:00:dc:11:d4:4d
     config:     PORT_DOWN
     state:      LINK_DOWN
     speed: 0 Mbps now, 0 Mbps max
OFPT_GET_CONFIG_REPLY (OF1.3) (xid=0x9): frags=normal miss_send_len=0
[root@kunpeng82 devuser]# ovs-ofctl show s2 -O openflow13
OFPT_FEATURES_REPLY (OF1.3) (xid=0x2): dpid:0000000000000002
n_tables:254, n_buffers:0
capabilities: FLOW_STATS TABLE_STATS PORT_STATS GROUP_STATS QUEUE_STATS
OFPST_PORT_DESC reply (OF1.3) (xid=0x3):
 1(s2-eth1): addr:8e:9d:b7:2d:ed:93
     config:     0
     state:      LIVE
     current:    10GB-FD COPPER
     speed: 10000 Mbps now, 0 Mbps max
 2(s2-eth2): addr:6e:24:f3:05:31:c7
     config:     0
     state:      LIVE
     current:    10GB-FD COPPER
     speed: 10000 Mbps now, 0 Mbps max
 LOCAL(s2): addr:ca:51:08:ec:4d:4e
     config:     PORT_DOWN
     state:      LINK_DOWN
     speed: 0 Mbps now, 0 Mbps max
OFPT_GET_CONFIG_REPLY (OF1.3) (xid=0x9): frags=normal miss_send_len=0
[root@kunpeng82 devuser]# ovs-ofctl show s3 -O openflow13
OFPT_FEATURES_REPLY (OF1.3) (xid=0x2): dpid:0000000000000003
n_tables:254, n_buffers:0
capabilities: FLOW_STATS TABLE_STATS PORT_STATS GROUP_STATS QUEUE_STATS
OFPST_PORT_DESC reply (OF1.3) (xid=0x3):
 1(s3-eth1): addr:52:fd:e6:ed:97:13
     config:     0
     state:      LIVE
     current:    10GB-FD COPPER
     speed: 10000 Mbps now, 0 Mbps max
 2(s3-eth2): addr:5e:3f:0d:6d:7d:e6
     config:     0
     state:      LIVE
     current:    10GB-FD COPPER
     speed: 10000 Mbps now, 0 Mbps max
 LOCAL(s3): addr:fe:56:82:c2:fa:4c
     config:     PORT_DOWN
     state:      LINK_DOWN
     speed: 0 Mbps now, 0 Mbps max
OFPT_GET_CONFIG_REPLY (OF1.3) (xid=0x9): frags=normal miss_send_len=0
[root@kunpeng82 devuser]# 
lib/packet/lldp.py:59:LLDP_MAC_NEAREST_BRIDGE = '01:80:c2:00:00:0e'

connected socket:<eventlet.greenio.base.GreenSocket object at 0xffff7970ad68> address:('127.0.0.1', 47426)
hello ev <ryu.controller.ofp_event.EventOFPHello object at 0xffff7970a780>
move onto config mode
connected socket:<eventlet.greenio.base.GreenSocket object at 0xffff7970ab38> address:('127.0.0.1', 47428)
hello ev <ryu.controller.ofp_event.EventOFPHello object at 0xffff7970a0b8>
move onto config mode
connected socket:<eventlet.greenio.base.GreenSocket object at 0xffff7970a160> address:('127.0.0.1', 47430)
hello ev <ryu.controller.ofp_event.EventOFPHello object at 0xffff796f5a90>
move onto config mode
EVENT ofp_event->MySwitch EventOFPSwitchFeatures
switch features ev version=0x4,msg_type=0x6,msg_len=0x20,xid=0xa860fcf3,OFPSwitchFeatures(auxiliary_id=0,capabilities=79,datapath_id=3,n_buffers=0,n_tables=254)
EVENT ofp_event->MySwitch EventOFPSwitchFeatures
switch features ev version=0x4,msg_type=0x6,msg_len=0x20,xid=0x2e031d87,OFPSwitchFeatures(auxiliary_id=0,capabilities=79,datapath_id=1,n_buffers=0,n_tables=254)
move onto main mode
EVENT ofp_event->MySwitch EventOFPPortDescStatsReply
port b's1-eth1' 0x00000001  send lldp  to 0x00000002 
packet-out ethernet(dst='01:80:c2:00:00:0e',ethertype=35020,src='9e:48:6a:42:e7:e6'), lldp(tlvs=(ChassisID(chassis_id=b'1',len=2,subtype=7,typelen=514), PortID(len=2,port_id=b'1',subtype=7,typelen=1026), TTL(len=2,ttl=1,typelen=1538), End(len=0,typelen=0)))
port b's1-eth2' 0x00000002  send lldp  to 0x00000001 
packet-out ethernet(dst='01:80:c2:00:00:0e',ethertype=35020,src='26:fe:ef:c1:d1:cd'), lldp(tlvs=(ChassisID(chassis_id=b'1',len=2,subtype=7,typelen=514), PortID(len=2,port_id=b'2',subtype=7,typelen=1026), TTL(len=2,ttl=1,typelen=1538), End(len=0,typelen=0)))
move onto main mode
EVENT ofp_event->MySwitch EventOFPPortDescStatsReply
EVENT ofp_event->MySwitch EventOFPSwitchFeatures
switch features ev version=0x4,msg_type=0x6,msg_len=0x20,xid=0x8f906e6f,OFPSwitchFeatures(auxiliary_id=0,capabilities=79,datapath_id=2,n_buffers=0,n_tables=254)
port b's3-eth1' 0x00000001  send lldp  to 0x00000002 
packet-out ethernet(dst='01:80:c2:00:00:0e',ethertype=35020,src='1a:d2:d5:c9:3c:5e'), lldp(tlvs=(ChassisID(chassis_id=b'3',len=2,subtype=7,typelen=514), PortID(len=2,port_id=b'1',subtype=7,typelen=1026), TTL(len=2,ttl=1,typelen=1538), End(len=0,typelen=0)))
port b's3-eth2' 0x00000002  send lldp  to 0x00000001 
packet-out ethernet(dst='01:80:c2:00:00:0e',ethertype=35020,src='8a:d2:8d:2f:4c:21'), lldp(tlvs=(ChassisID(chassis_id=b'3',len=2,subtype=7,typelen=514), PortID(len=2,port_id=b'2',subtype=7,typelen=1026), TTL(len=2,ttl=1,typelen=1538), End(len=0,typelen=0)))
move onto main mode
EVENT ofp_event->MySwitch EventOFPPortDescStatsReply
port b's2-eth1' 0x00000001  send lldp  to 0x00000002 
packet-out ethernet(dst='01:80:c2:00:00:0e',ethertype=35020,src='d6:63:a2:0c:7f:70'), lldp(tlvs=(ChassisID(chassis_id=b'2',len=2,subtype=7,typelen=514), PortID(len=2,port_id=b'1',subtype=7,typelen=1026), TTL(len=2,ttl=1,typelen=1538), End(len=0,typelen=0)))
port b's2-eth2' 0x00000002  send lldp  to 0x00000001 
packet-out ethernet(dst='01:80:c2:00:00:0e',ethertype=35020,src='d2:3e:f9:67:b5:a0'), lldp(tlvs=(ChassisID(chassis_id=b'2',len=2,subtype=7,typelen=514), PortID(len=2,port_id=b'2',subtype=7,typelen=1026), TTL(len=2,ttl=1,typelen=1538), End(len=0,typelen=0)))
EVENT ofp_event->MySwitch EventOFPPacketIn
['switch2, port2<--->switch3, port1']
EVENT ofp_event->MySwitch EventOFPPacketIn
['switch2, port2<--->switch3, port1', 'switch1, port2<--->switch2, port1']
EVENT ofp_event->MySwitch EventOFPPacketIn
['switch2, port2<--->switch3, port1', 'switch1, port2<--->switch2, port1']
[root@kunpeng82 app]# ovs-ofctl dump-flows s1
2020-06-19T06:34:16Z|00001|vconn|WARN|unix:/var/run/openvswitch/s1.mgmt: version negotiation failed (we support version 0x01, peer supports version 0x04)
ovs-ofctl: s1: failed to connect to socket (Broken pipe)
[root@kunpeng82 app]# 
[root@kunpeng82 app]# ovs-ofctl dump-flows s1 -O OpenFlow13
 cookie=0x0, duration=1435.263s, table=0, n_packets=2, n_bytes=120, priority=1,dl_type=0x88cc actions=CONTROLLER:65535
 cookie=0x0, duration=1435.255s, table=0, n_packets=3, n_bytes=210, priority=1,in_port="s1-eth1" actions=output:"s1-eth2"
 cookie=0x0, duration=1435.254s, table=0, n_packets=9, n_bytes=630, priority=1,in_port="s1-eth2" actions=output:"s1-eth1"


lib/packet/ether_types.py:25:ETH_TYPE_LLDP = 0x88cc
       The following shorthand notations are also available:

       ip     Same as dl_type=0x0800.

       ipv6   Same as dl_type=0x86dd.

       icmp   Same as dl_type=0x0800,nw_proto=1.

       icmp6  Same as dl_type=0x86dd,nw_proto=58.

       tcp    Same as dl_type=0x0800,nw_proto=6.

       tcp6   Same as dl_type=0x86dd,nw_proto=6.

       udp    Same as dl_type=0x0800,nw_proto=17.

       udp6   Same as dl_type=0x86dd,nw_proto=17.

       sctp   Same as dl_type=0x0800,nw_proto=132.

       sctp6  Same as dl_type=0x86dd,nw_proto=132.

       arp    Same as dl_type=0x0806.

       rarp   Same as dl_type=0x8035.

       mpls   Same as dl_type=0x8847.

       mplsm  Same as dl_type=0x8848.
[root@kunpeng82 ryu]# ovs-ofctl dump-flows s1 -O OpenFlow13
 cookie=0x0, duration=1950.532s, table=0, n_packets=2, n_bytes=120, priority=1,dl_type=0x88cc actions=CONTROLLER:65535
 cookie=0x0, duration=1950.524s, table=0, n_packets=3, n_bytes=210, priority=1,in_port="s1-eth1" actions=output:"s1-eth2"
 cookie=0x0, duration=1950.523s, table=0, n_packets=9, n_bytes=630, priority=1,in_port="s1-eth2" actions=output:"s1-eth1"
[root@kunpeng82 ryu]# ovs-ofctl dump-flows s2 -O OpenFlow13
 cookie=0x0, duration=1955.206s, table=0, n_packets=4, n_bytes=240, priority=1,dl_type=0x88cc actions=CONTROLLER:65535
 cookie=0x0, duration=1955.199s, table=0, n_packets=6, n_bytes=420, priority=1,in_port="s2-eth1" actions=output:"s2-eth2"
 cookie=0x0, duration=1955.199s, table=0, n_packets=6, n_bytes=420, priority=1,in_port="s2-eth2" actions=output:"s2-eth1"
[root@kunpeng82 ryu]# ovs-ofctl dump-flows s3 -O OpenFlow13
 cookie=0x0, duration=1958.804s, table=0, n_packets=2, n_bytes=120, priority=1,dl_type=0x88cc actions=CONTROLLER:65535
 cookie=0x0, duration=1958.789s, table=0, n_packets=9, n_bytes=630, priority=1,in_port="s3-eth1" actions=output:"s3-eth2"
 cookie=0x0, duration=1958.789s, table=0, n_packets=3, n_bytes=210, priority=1,in_port="s3-eth2" actions=output:"s3-eth1"
[root@kunpeng82 ryu]# 
原文地址:https://www.cnblogs.com/dream397/p/13162306.html