<s> import logging <EOL> import six <EOL> import struct <EOL> import time <EOL> import json <EOL> from ryu import cfg <EOL> from ryu . topology import event <EOL> from ryu . base import app_manager <EOL> from ryu . controller import ofp_event <EOL> from ryu . controller . handler import set_ev_cls <EOL> from ryu . controller . handler import MAIN_DISPATCHER , DEAD_DISPATCHER <EOL> from ryu . exception import RyuException <EOL> from ryu . lib import addrconv , hub <EOL> from ryu . lib . mac import DONTCARE_STR <EOL> from ryu . lib . dpid import dpid_to_str , str_to_dpid <EOL> from ryu . lib . port_no import port_no_to_str <EOL> from ryu . lib . packet import packet , ethernet <EOL> from ryu . lib . packet import lldp , ether_types <EOL> from ryu . lib . packet import arp , ipv4 , ipv6 <EOL> from ryu . ofproto . ether import ETH_TYPE_LLDP <EOL> from ryu . ofproto import nx_match <EOL> from ryu . ofproto import ofproto_v1_0 <EOL> from ryu . ofproto import ofproto_v1_2 <EOL> from ryu . ofproto import ofproto_v1_3 <EOL> from ryu . ofproto import ofproto_v1_4 <EOL> LOG = logging . getLogger ( __name__ ) <EOL> CONF = cfg . CONF <EOL> CONF . register_cli_opts ( [ <EOL> cfg . BoolOpt ( '<STR_LIT>' , default = False , <EOL> help = '<STR_LIT>' ) , <EOL> cfg . BoolOpt ( '<STR_LIT>' , default = True , <EOL> help = '<STR_LIT>' <EOL> '<STR_LIT>' ) , <EOL> cfg . BoolOpt ( '<STR_LIT>' , default = True , <EOL> help = '<STR_LIT>' ) <EOL> ] ) <EOL> class Port ( object ) : <EOL> def __init__ ( self , dpid , ofproto , ofpport ) : <EOL> super ( Port , self ) . __init__ ( ) <EOL> self . dpid = dpid <EOL> self . _ofproto = ofproto <EOL> self . _config = ofpport . config <EOL> self . _state = ofpport . state <EOL> self . port_no = ofpport . port_no <EOL> self . hw_addr = ofpport . hw_addr <EOL> self . name = ofpport . name <EOL> def is_reserved ( self ) : <EOL> return self . port_no > self . _ofproto . OFPP_MAX <EOL> def is_down ( self ) : <EOL> return ( self . _state & self . _ofproto . OFPPS_LINK_DOWN ) > <NUM_LIT:0> or ( self . _config & self . _ofproto . OFPPC_PORT_DOWN ) > <NUM_LIT:0> <EOL> def is_live ( self ) : <EOL> return not self . is_down ( ) <EOL> def to_dict ( self ) : <EOL> return { '<STR_LIT>' : dpid_to_str ( self . dpid ) , <EOL> '<STR_LIT>' : port_no_to_str ( self . port_no ) , <EOL> '<STR_LIT>' : self . hw_addr , <EOL> '<STR_LIT:name>' : self . name . rstrip ( '<STR_LIT>' ) } <EOL> def __eq__ ( self , other ) : <EOL> return self . dpid == other . dpid and self . port_no == other . port_no <EOL> def __ne__ ( self , other ) : <EOL> return not self . __eq__ ( other ) <EOL> def __hash__ ( self ) : <EOL> return hash ( ( self . dpid , self . port_no ) ) <EOL> def __str__ ( self ) : <EOL> LIVE_MSG = { False : '<STR_LIT>' , True : '<STR_LIT>' } <EOL> return '<STR_LIT>' % ( self . dpid , self . port_no , LIVE_MSG [ self . is_live ( ) ] ) <EOL> class Switch ( object ) : <EOL> def __init__ ( self , dp ) : <EOL> super ( Switch , self ) . __init__ ( ) <EOL> self . dp = dp <EOL> self . ports = [ ] <EOL> def add_port ( self , ofpport ) : <EOL> port = Port ( self . dp . id , self . dp . ofproto , ofpport ) <EOL> if not port . is_reserved ( ) : <EOL> self . ports . append ( port ) <EOL> def del_port ( self , ofpport ) : <EOL> self . ports . remove ( Port ( ofpport ) ) <EOL> def to_dict ( self ) : <EOL> d = { '<STR_LIT>' : dpid_to_str ( self . dp . id ) , <EOL> '<STR_LIT>' : [ port . to_dict ( ) for port in self . ports ] } <EOL> return d <EOL> def __str__ ( self ) : <EOL> msg = '<STR_LIT>' % self . dp . id <EOL> for port in self . ports : <EOL> msg += str ( port ) + '<STR_LIT:U+0020>' <EOL> msg += '<STR_LIT:>>' <EOL> return msg <EOL> class Link ( object ) : <EOL> def __init__ ( self , src , dst ) : <EOL> super ( Link , self ) . __init__ ( ) <EOL> self . src = src <EOL> self . dst = dst <EOL> def to_dict ( self ) : <EOL> d = { '<STR_LIT:src>' : self . src . to_dict ( ) , <EOL> '<STR_LIT>' : self . dst . to_dict ( ) } <EOL> return d <EOL> def __eq__ ( self , other ) : <EOL> return self . src == other . src and self . dst == other . dst <EOL> def __ne__ ( self , other ) : <EOL> return not self . __eq__ ( other ) <EOL> def __hash__ ( self ) : <EOL> return hash ( ( self . src , self . dst ) ) <EOL> def __str__ ( self ) : <EOL> return '<STR_LIT>' % ( self . src , self . dst ) <EOL> class Host ( object ) : <EOL> def __init__ ( self , mac , port ) : <EOL> super ( Host , self ) . __init__ ( ) <EOL> self . port = port <EOL> self . mac = mac <EOL> self . ipv4 = [ ] <EOL> self . ipv6 = [ ] <EOL> def to_dict ( self ) : <EOL> d = { '<STR_LIT>' : self . mac , <EOL> '<STR_LIT>' : self . ipv4 , <EOL> '<STR_LIT>' : self . ipv6 , <EOL> '<STR_LIT:port>' : self . port . to_dict ( ) } <EOL> return d <EOL> def __eq__ ( self , host ) : <EOL> return self . mac == host . mac and self . port == host . port <EOL> def __str__ ( self ) : <EOL> msg = '<STR_LIT>' % ( self . mac , str ( self . port ) ) <EOL> msg += '<STR_LIT:U+002C>' . join ( self . ipv4 ) <EOL> msg += '<STR_LIT:U+002C>' . join ( self . ipv6 ) <EOL> msg += '<STR_LIT:>>' <EOL> return msg <EOL> class HostState ( dict ) : <EOL> def __init__ ( self ) : <EOL> super ( HostState , self ) . __init__ ( ) <EOL> def add ( self , host ) : <EOL> mac = host . mac <EOL> self . setdefault ( mac , host ) <EOL> def update_ip ( self , host , ip_v4 = None , ip_v6 = None ) : <EOL> mac = host . mac <EOL> host = None <EOL> if mac in self : <EOL> host = self [ mac ] <EOL> if not host : <EOL> return <EOL> if ip_v4 != None : <EOL> if ip_v4 in host . ipv4 : <EOL> host . ipv4 . remove ( ip_v4 ) <EOL> host . ipv4 . append ( ip_v4 ) <EOL> if ip_v6 != None : <EOL> if ip_v6 in host . ipv6 : <EOL> host . ipv6 . remove ( ip_v6 ) <EOL> host . ipv6 . append ( ip_v6 ) <EOL> def get_by_dpid ( self , dpid ) : <EOL> result = [ ] <EOL> for mac in self : <EOL> host = self [ mac ] <EOL> if host . port . dpid == dpid : <EOL> result . append ( host ) <EOL> return result <EOL> class PortState ( dict ) : <EOL> def __init__ ( self ) : <EOL> super ( PortState , self ) . __init__ ( ) <EOL> def add ( self , port_no , port ) : <EOL> self [ port_no ] = port <EOL> def remove ( self , port_no ) : <EOL> del self [ port_no ] <EOL> def modify ( self , port_no , port ) : <EOL> self [ port_no ] = port <EOL> class PortData ( object ) : <EOL> def __init__ ( self , is_down , lldp_data ) : <EOL> super ( PortData , self ) . __init__ ( ) <EOL> self . is_down = is_down <EOL> self . lldp_data = lldp_data <EOL> self . timestamp = None <EOL> self . sent = <NUM_LIT:0> <EOL> def lldp_sent ( self ) : <EOL> self . timestamp = time . time ( ) <EOL> self . sent += <NUM_LIT:1> <EOL> def lldp_received ( self ) : <EOL> self . sent = <NUM_LIT:0> <EOL> def lldp_dropped ( self ) : <EOL> return self . sent <EOL> def clear_timestamp ( self ) : <EOL> self . timestamp = None <EOL> def set_down ( self , is_down ) : <EOL> self . is_down = is_down <EOL> def __str__ ( self ) : <EOL> return '<STR_LIT>' % ( not self . is_down , self . timestamp , self . sent ) <EOL> class PortDataState ( dict ) : <EOL> _PREV = <NUM_LIT:0> <EOL> _NEXT = <NUM_LIT:1> <EOL> _KEY = <NUM_LIT:2> <EOL> def __init__ ( self ) : <EOL> super ( PortDataState , self ) . __init__ ( ) <EOL> self . _root = root = [ ] <EOL> root [ : ] = [ root , root , None ] <EOL> self . _map = { } <EOL> def _remove_key ( self , key ) : <EOL> link_prev , link_next , key = self . _map . pop ( key ) <EOL> link_prev [ self . _NEXT ] = link_next <EOL> link_next [ self . _PREV ] = link_prev <EOL> def _append_key ( self , key ) : <EOL> root = self . _root <EOL> last = root [ self . _PREV ] <EOL> last [ self . _NEXT ] = root [ self . _PREV ] = self . _map [ key ] = [ last , root , <EOL> key ] <EOL> def _prepend_key ( self , key ) : <EOL> root = self . _root <EOL> first = root [ self . _NEXT ] <EOL> first [ self . _PREV ] = root [ self . _NEXT ] = self . _map [ key ] = [ root , first , <EOL> key ] <EOL> def _move_last_key ( self , key ) : <EOL> self . _remove_key ( key ) <EOL> self . _append_key ( key ) <EOL> def _move_front_key ( self , key ) : <EOL> self . _remove_key ( key ) <EOL> self . _prepend_key ( key ) <EOL> def add_port ( self , port , lldp_data ) : <EOL> if port not in self : <EOL> self . _prepend_key ( port ) <EOL> self [ port ] = PortData ( port . is_down ( ) , lldp_data ) <EOL> else : <EOL> self [ port ] . is_down = port . is_down ( ) <EOL> def lldp_sent ( self , port ) : <EOL> port_data = self [ port ] <EOL> port_data . lldp_sent ( ) <EOL> self . _move_last_key ( port ) <EOL> return port_data <EOL> def lldp_received ( self , port ) : <EOL> self [ port ] . lldp_received ( ) <EOL> def move_front ( self , port ) : <EOL> port_data = self . get ( port , None ) <EOL> if port_data is not None : <EOL> port_data . clear_timestamp ( ) <EOL> self . _move_front_key ( port ) <EOL> def set_down ( self , port ) : <EOL> is_down = port . is_down ( ) <EOL> port_data = self [ port ] <EOL> port_data . set_down ( is_down ) <EOL> port_data . clear_timestamp ( ) <EOL> if not is_down : <EOL> self . _move_front_key ( port ) <EOL> return is_down <EOL> def get_port ( self , port ) : <EOL> return self [ port ] <EOL> def del_port ( self , port ) : <EOL> del self [ port ] <EOL> self . _remove_key ( port ) <EOL> def __iter__ ( self ) : <EOL> root = self . _root <EOL> curr = root [ self . _NEXT ] <EOL> while curr is not root : <EOL> yield curr [ self . _KEY ] <EOL> curr = curr [ self . _NEXT ] <EOL> def clear ( self ) : <EOL> for node in self . _map . values ( ) : <EOL> del node [ : ] <EOL> root = self . _root <EOL> root [ : ] = [ root , root , None ] <EOL> self . _map . clear ( ) <EOL> dict . clear ( self ) <EOL> def items ( self ) : <EOL> '<STR_LIT>' <EOL> return [ ( key , self [ key ] ) for key in self ] <EOL> def iteritems ( self ) : <EOL> '<STR_LIT>' <EOL> for k in self : <EOL> yield ( k , self [ k ] ) <EOL> class LinkState ( dict ) : <EOL> def __init__ ( self ) : <EOL> super ( LinkState , self ) . __init__ ( ) <EOL> self . _map = { } <EOL> def get_peer ( self , src ) : <EOL> return self . _map . get ( src , None ) <EOL> def update_link ( self , src , dst ) : <EOL> link = Link ( src , dst ) <EOL> self [ link ] = time . time ( ) <EOL> self . _map [ src ] = dst <EOL> rev_link = Link ( dst , src ) <EOL> return rev_link in self <EOL> def link_down ( self , link ) : <EOL> del self [ link ] <EOL> del self . _map [ link . src ] <EOL> def rev_link_set_timestamp ( self , rev_link , timestamp ) : <EOL> if rev_link in self : <EOL> self [ rev_link ] = timestamp <EOL> def port_deleted ( self , src ) : <EOL> dst = self . get_peer ( src ) <EOL> if dst is None : <EOL> raise KeyError ( ) <EOL> link = Link ( src , dst ) <EOL> rev_link = Link ( dst , src ) <EOL> del self [ link ] <EOL> del self . _map [ src ] <EOL> self . pop ( rev_link , None ) <EOL> rev_link_dst = self . _map . pop ( dst , None ) <EOL> return dst , rev_link_dst <EOL> class LLDPPacket ( object ) : <EOL> CHASSIS_ID_PREFIX = '<STR_LIT>' <EOL> CHASSIS_ID_PREFIX_LEN = len ( CHASSIS_ID_PREFIX ) <EOL> CHASSIS_ID_FMT = CHASSIS_ID_PREFIX + '<STR_LIT:%s>' <EOL> PORT_ID_STR = '<STR_LIT>' <EOL> PORT_ID_SIZE = <NUM_LIT:4> <EOL> class LLDPUnknownFormat ( RyuException ) : <EOL> message = '<STR_LIT>' <EOL> @ staticmethod <EOL> def lldp_packet ( dpid , port_no , dl_addr , ttl ) : <EOL> pkt = packet . Packet ( ) <EOL> dst = lldp . LLDP_MAC_NEAREST_BRIDGE <EOL> src = dl_addr <EOL> ethertype = ETH_TYPE_LLDP <EOL> eth_pkt = ethernet . ethernet ( dst , src , ethertype ) <EOL> pkt . add_protocol ( eth_pkt ) <EOL> tlv_chassis_id = lldp . ChassisID ( <EOL> subtype = lldp . ChassisID . SUB_LOCALLY_ASSIGNED , <EOL> chassis_id = ( LLDPPacket . CHASSIS_ID_FMT % <EOL> dpid_to_str ( dpid ) ) . encode ( '<STR_LIT:ascii>' ) ) <EOL> tlv_port_id = lldp . PortID ( subtype = lldp . PortID . SUB_PORT_COMPONENT , <EOL> port_id = struct . pack ( <EOL> LLDPPacket . PORT_ID_STR , <EOL> port_no ) ) <EOL> tlv_ttl = lldp . TTL ( ttl = ttl ) <EOL> tlv_end = lldp . End ( ) <EOL> tlvs = ( tlv_chassis_id , tlv_port_id , tlv_ttl , tlv_end ) <EOL> lldp_pkt = lldp . lldp ( tlvs ) <EOL> pkt . add_protocol ( lldp_pkt ) <EOL> pkt . serialize ( ) <EOL> return pkt . data <EOL> @ staticmethod <EOL> def lldp_parse ( data ) : <EOL> pkt = packet . Packet ( data ) <EOL> i = iter ( pkt ) <EOL> eth_pkt = six . next ( i ) <EOL> assert type ( eth_pkt ) == ethernet . ethernet <EOL> lldp_pkt = six . next ( i ) <EOL> if type ( lldp_pkt ) != lldp . lldp : <EOL> raise LLDPPacket . LLDPUnknownFormat ( ) <EOL> tlv_chassis_id = lldp_pkt . tlvs [ <NUM_LIT:0> ] <EOL> if tlv_chassis_id . subtype != lldp . ChassisID . SUB_LOCALLY_ASSIGNED : <EOL> raise LLDPPacket . LLDPUnknownFormat ( <EOL> msg = '<STR_LIT>' % tlv_chassis_id . subtype ) <EOL> chassis_id = tlv_chassis_id . chassis_id <EOL> if not chassis_id . startswith ( LLDPPacket . CHASSIS_ID_PREFIX ) : <EOL> raise LLDPPacket . LLDPUnknownFormat ( <EOL> msg = '<STR_LIT>' % chassis_id ) <EOL> src_dpid = str_to_dpid ( chassis_id [ LLDPPacket . CHASSIS_ID_PREFIX_LEN : ] ) <EOL> tlv_port_id = lldp_pkt . tlvs [ <NUM_LIT:1> ] <EOL> if tlv_port_id . subtype != lldp . PortID . SUB_PORT_COMPONENT : <EOL> raise LLDPPacket . LLDPUnknownFormat ( <EOL> msg = '<STR_LIT>' % tlv_port_id . subtype ) <EOL> port_id = tlv_port_id . port_id <EOL> if len ( port_id ) != LLDPPacket . PORT_ID_SIZE : <EOL> raise LLDPPacket . LLDPUnknownFormat ( <EOL> msg = '<STR_LIT>' % port_id ) <EOL> ( src_port_no , ) = struct . unpack ( LLDPPacket . PORT_ID_STR , port_id ) <EOL> return src_dpid , src_port_no <EOL> class Switches ( app_manager . RyuApp ) : <EOL> OFP_VERSIONS = [ ofproto_v1_0 . OFP_VERSION , ofproto_v1_2 . OFP_VERSION , <EOL> ofproto_v1_3 . OFP_VERSION , ofproto_v1_4 . OFP_VERSION ] <EOL> _EVENTS = [ event . EventSwitchEnter , event . EventSwitchLeave , <EOL> event . EventSwitchReconnected , <EOL> event . EventPortAdd , event . EventPortDelete , <EOL> event . EventPortModify , <EOL> event . EventLinkAdd , event . EventLinkDelete , <EOL> event . EventHostAdd ] <EOL> DEFAULT_TTL = <NUM_LIT> <EOL> LLDP_PACKET_LEN = len ( LLDPPacket . lldp_packet ( <NUM_LIT:0> , <NUM_LIT:0> , DONTCARE_STR , <NUM_LIT:0> ) ) <EOL> LLDP_SEND_GUARD = <NUM_LIT> <EOL> LLDP_SEND_PERIOD_PER_PORT = <NUM_LIT> <EOL> TIMEOUT_CHECK_PERIOD = <NUM_LIT> <EOL> LINK_TIMEOUT = TIMEOUT_CHECK_PERIOD * <NUM_LIT:2> <EOL> LINK_LLDP_DROP = <NUM_LIT:5> <EOL> def __init__ ( self , * args , ** kwargs ) : <EOL> super ( Switches , self ) . __init__ ( * args , ** kwargs ) <EOL> self . name = '<STR_LIT>' <EOL> self . dps = { } <EOL> self . port_state = { } <EOL> self . ports = PortDataState ( ) <EOL> self . links = LinkState ( ) <EOL> self . hosts = HostState ( ) <EOL> self . is_active = True <EOL> self . link_discovery = self . CONF . observe_links <EOL> if self . link_discovery : <EOL> self . install_flow = self . CONF . install_lldp_flow <EOL> self . explicit_drop = self . CONF . explicit_drop <EOL> self . lldp_event = hub . Event ( ) <EOL> self . link_event = hub . Event ( ) <EOL> self . threads . append ( hub . spawn ( self . lldp_loop ) ) <EOL> self . threads . append ( hub . spawn ( self . link_loop ) ) <EOL> def close ( self ) : <EOL> self . is_active = False <EOL> if self . link_discovery : <EOL> self . lldp_event . set ( ) <EOL> self . link_event . set ( ) <EOL> hub . joinall ( self . threads ) <EOL> def _register ( self , dp ) : <EOL> assert dp . id is not None <EOL> self . dps [ dp . id ] = dp <EOL> if dp . id not in self . port_state : <EOL> self . port_state [ dp . id ] = PortState ( ) <EOL> for port in dp . ports . values ( ) : <EOL> self . port_state [ dp . id ] . add ( port . port_no , port ) <EOL> def _unregister ( self , dp ) : <EOL> if dp . id in self . dps : <EOL> if ( self . dps [ dp . id ] == dp ) : <EOL> del self . dps [ dp . id ] <EOL> del self . port_state [ dp . id ] <EOL> def _get_switch ( self , dpid ) : <EOL> if dpid in self . dps : <EOL> switch = Switch ( self . dps [ dpid ] ) <EOL> for ofpport in self . port_state [ dpid ] . values ( ) : <EOL> switch . add_port ( ofpport ) <EOL> return switch <EOL> def _get_port ( self , dpid , port_no ) : <EOL> switch = self . _get_switch ( dpid ) <EOL> if switch : <EOL> for p in switch . ports : <EOL> if p . port_no == port_no : <EOL> return p <EOL> def _port_added ( self , port ) : <EOL> lldp_data = LLDPPacket . lldp_packet ( <EOL> port . dpid , port . port_no , port . hw_addr , self . DEFAULT_TTL ) <EOL> self . ports . add_port ( port , lldp_data ) <EOL> def _link_down ( self , port ) : <EOL> try : <EOL> dst , rev_link_dst = self . links . port_deleted ( port ) <EOL> except KeyError : <EOL> return <EOL> link = Link ( port , dst ) <EOL> self . send_event_to_observers ( event . EventLinkDelete ( link ) ) <EOL> if rev_link_dst : <EOL> rev_link = Link ( dst , rev_link_dst ) <EOL> self . send_event_to_observers ( event . EventLinkDelete ( rev_link ) ) <EOL> self . ports . move_front ( dst ) <EOL> def _is_edge_port ( self , port ) : <EOL> for link in self . links : <EOL> if port == link . src or port == link . dst : <EOL> return False <EOL> return True <EOL> @ set_ev_cls ( ofp_event . EventOFPStateChange , <EOL> [ MAIN_DISPATCHER , DEAD_DISPATCHER ] ) <EOL> def state_change_handler ( self , ev ) : <EOL> dp = ev . datapath <EOL> assert dp is not None <EOL> LOG . debug ( dp ) <EOL> if ev . state == MAIN_DISPATCHER : <EOL> dp_multiple_conns = False <EOL> if dp . id in self . dps : <EOL> LOG . warning ( '<STR_LIT>' , dpid_to_str ( dp . id ) ) <EOL> dp_multiple_conns = True <EOL> ( self . dps [ dp . id ] ) . close ( ) <EOL> self . _register ( dp ) <EOL> switch = self . _get_switch ( dp . id ) <EOL> LOG . debug ( '<STR_LIT>' , switch ) <EOL> if not dp_multiple_conns : <EOL> self . send_event_to_observers ( event . EventSwitchEnter ( switch ) ) <EOL> else : <EOL> self . send_event_to_observers ( event . EventSwitchReconnected ( switch ) ) <EOL> if not self . link_discovery : <EOL> return <EOL> if self . install_flow : <EOL> ofproto = dp . ofproto <EOL> ofproto_parser = dp . ofproto_parser <EOL> if ofproto . OFP_VERSION == ofproto_v1_0 . OFP_VERSION : <EOL> rule = nx_match . ClsRule ( ) <EOL> rule . set_dl_dst ( addrconv . mac . text_to_bin ( <EOL> lldp . LLDP_MAC_NEAREST_BRIDGE ) ) <EOL> rule . set_dl_type ( ETH_TYPE_LLDP ) <EOL> actions = [ ofproto_parser . OFPActionOutput ( <EOL> ofproto . OFPP_CONTROLLER , self . LLDP_PACKET_LEN ) ] <EOL> dp . send_flow_mod ( <EOL> rule = rule , cookie = <NUM_LIT:0> , command = ofproto . OFPFC_ADD , <EOL> idle_timeout = <NUM_LIT:0> , hard_timeout = <NUM_LIT:0> , actions = actions , <EOL> priority = <NUM_LIT> ) <EOL> elif ofproto . OFP_VERSION >= ofproto_v1_2 . OFP_VERSION : <EOL> match = ofproto_parser . OFPMatch ( <EOL> eth_type = ETH_TYPE_LLDP , <EOL> eth_dst = lldp . LLDP_MAC_NEAREST_BRIDGE ) <EOL> parser = ofproto_parser <EOL> actions = [ parser . OFPActionOutput ( ofproto . OFPP_CONTROLLER , <EOL> ofproto . OFPCML_NO_BUFFER <EOL> ) ] <EOL> inst = [ parser . OFPInstructionActions ( <EOL> ofproto . OFPIT_APPLY_ACTIONS , actions ) ] <EOL> mod = parser . OFPFlowMod ( datapath = dp , match = match , <EOL> idle_timeout = <NUM_LIT:0> , hard_timeout = <NUM_LIT:0> , <EOL> instructions = inst , <EOL> priority = <NUM_LIT> ) <EOL> dp . send_msg ( mod ) <EOL> else : <EOL> LOG . error ( '<STR_LIT>' , <EOL> dp . ofproto . OFP_VERSION ) <EOL> if not dp_multiple_conns : <EOL> for port in switch . ports : <EOL> if not port . is_reserved ( ) : <EOL> self . _port_added ( port ) <EOL> self . lldp_event . set ( ) <EOL> elif ev . state == DEAD_DISPATCHER : <EOL> if dp . id is None : <EOL> return <EOL> switch = self . _get_switch ( dp . id ) <EOL> if switch : <EOL> if switch . dp is dp : <EOL> self . _unregister ( dp ) <EOL> LOG . debug ( '<STR_LIT>' , switch ) <EOL> self . send_event_to_observers ( event . EventSwitchLeave ( switch ) ) <EOL> if not self . link_discovery : <EOL> return <EOL> for port in switch . ports : <EOL> if not port . is_reserved ( ) : <EOL> self . ports . del_port ( port ) <EOL> self . _link_down ( port ) <EOL> self . lldp_event . set ( ) <EOL> @ set_ev_cls ( ofp_event . EventOFPPortStatus , MAIN_DISPATCHER ) <EOL> def port_status_handler ( self , ev ) : <EOL> msg = ev . msg <EOL> reason = msg . reason <EOL> dp = msg . datapath <EOL> ofpport = msg . desc <EOL> if reason == dp . ofproto . OFPPR_ADD : <EOL> self . port_state [ dp . id ] . add ( ofpport . port_no , ofpport ) <EOL> self . send_event_to_observers ( <EOL> event . EventPortAdd ( Port ( dp . id , dp . ofproto , ofpport ) ) ) <EOL> if not self . link_discovery : <EOL> return <EOL> port = self . _get_port ( dp . id , ofpport . port_no ) <EOL> if port and not port . is_reserved ( ) : <EOL> self . _port_added ( port ) <EOL> self . lldp_event . set ( ) <EOL> elif reason == dp . ofproto . OFPPR_DELETE : <EOL> self . port_state [ dp . id ] . remove ( ofpport . port_no ) <EOL> self . send_event_to_observers ( <EOL> event . EventPortDelete ( Port ( dp . id , dp . ofproto , ofpport ) ) ) <EOL> if not self . link_discovery : <EOL> return <EOL> port = self . _get_port ( dp . id , ofpport . port_no ) <EOL> if port and not port . is_reserved ( ) : <EOL> self . ports . del_port ( port ) <EOL> self . _link_down ( port ) <EOL> self . lldp_event . set ( ) <EOL> else : <EOL> assert reason == dp . ofproto . OFPPR_MODIFY <EOL> self . port_state [ dp . id ] . modify ( ofpport . port_no , ofpport ) <EOL> self . send_event_to_observers ( <EOL> event . EventPortModify ( Port ( dp . id , dp . ofproto , ofpport ) ) ) <EOL> if not self . link_discovery : <EOL> return <EOL> port = self . _get_port ( dp . id , ofpport . port_no ) <EOL> if port and not port . is_reserved ( ) : <EOL> if self . ports . set_down ( port ) : <EOL> self . _link_down ( port ) <EOL> self . lldp_event . set ( ) <EOL> @ staticmethod <EOL> def _drop_packet ( msg ) : <EOL> buffer_id = msg . buffer_id <EOL> if buffer_id == msg . datapath . ofproto . OFP_NO_BUFFER : <EOL> return <EOL> dp = msg . datapath <EOL> if dp . ofproto . OFP_VERSION == ofproto_v1_0 . OFP_VERSION : <EOL> dp . send_packet_out ( buffer_id , msg . in_port , [ ] ) <EOL> elif dp . ofproto . OFP_VERSION >= ofproto_v1_2 . OFP_VERSION : <EOL> dp . send_packet_out ( buffer_id , msg . match [ '<STR_LIT>' ] , [ ] ) <EOL> else : <EOL> LOG . error ( '<STR_LIT>' , <EOL> dp . ofproto . OFP_VERSION ) <EOL> @ set_ev_cls ( ofp_event . EventOFPPacketIn , MAIN_DISPATCHER ) <EOL> def lldp_packet_in_handler ( self , ev ) : <EOL> if not self . link_discovery : <EOL> return <EOL> msg = ev . msg <EOL> try : <EOL> src_dpid , src_port_no = LLDPPacket . lldp_parse ( msg . data ) <EOL> except LLDPPacket . LLDPUnknownFormat as e : <EOL> return <EOL> dst_dpid = msg . datapath . id <EOL> if msg . datapath . ofproto . OFP_VERSION == ofproto_v1_0 . OFP_VERSION : <EOL> dst_port_no = msg . in_port <EOL> elif msg . datapath . ofproto . OFP_VERSION >= ofproto_v1_2 . OFP_VERSION : <EOL> dst_port_no = msg . match [ '<STR_LIT>' ] <EOL> else : <EOL> LOG . error ( '<STR_LIT>' , <EOL> msg . datapath . ofproto . OFP_VERSION ) <EOL> src = self . _get_port ( src_dpid , src_port_no ) <EOL> if not src or src . dpid == dst_dpid : <EOL> return <EOL> try : <EOL> self . ports . lldp_received ( src ) <EOL> except KeyError : <EOL> pass <EOL> dst = self . _get_port ( dst_dpid , dst_port_no ) <EOL> if not dst : <EOL> return <EOL> old_peer = self . links . get_peer ( src ) <EOL> if old_peer and old_peer != dst : <EOL> old_link = Link ( src , old_peer ) <EOL> del self . links [ old_link ] <EOL> self . send_event_to_observers ( event . EventLinkDelete ( old_link ) ) <EOL> link = Link ( src , dst ) <EOL> if link not in self . links : <EOL> self . send_event_to_observers ( event . EventLinkAdd ( link ) ) <EOL> for host in self . hosts . values ( ) : <EOL> if not self . _is_edge_port ( host . port ) : <EOL> del self . hosts [ host . mac ] <EOL> if not self . links . update_link ( src , dst ) : <EOL> self . ports . move_front ( dst ) <EOL> self . lldp_event . set ( ) <EOL> if self . explicit_drop : <EOL> self . _drop_packet ( msg ) <EOL> @ set_ev_cls ( ofp_event . EventOFPPacketIn , MAIN_DISPATCHER ) <EOL> def host_discovery_packet_in_handler ( self , ev ) : <EOL> msg = ev . msg <EOL> pkt = packet . Packet ( msg . data ) <EOL> eth = pkt . get_protocols ( ethernet . ethernet ) [ <NUM_LIT:0> ] <EOL> if eth . ethertype == ETH_TYPE_LLDP : <EOL> return <EOL> datapath = msg . datapath <EOL> dpid = datapath . id <EOL> port_no = - <NUM_LIT:1> <EOL> if msg . datapath . ofproto . OFP_VERSION == ofproto_v1_0 . OFP_VERSION : <EOL> port_no = msg . in_port <EOL> else : <EOL> port_no = msg . match [ '<STR_LIT>' ] <EOL> port = self . _get_port ( dpid , port_no ) <EOL> if not port : <EOL> return <EOL> if not self . _is_edge_port ( port ) : <EOL> return <EOL> host_mac = eth . src <EOL> host = Host ( host_mac , port ) <EOL> if host_mac not in self . hosts : <EOL> self . hosts . add ( host ) <EOL> ev = event . EventHostAdd ( host ) <EOL> self . send_event_to_observers ( ev ) <EOL> if eth . ethertype == ether_types . ETH_TYPE_ARP : <EOL> arp_pkt = pkt . get_protocols ( arp . arp ) [ <NUM_LIT:0> ] <EOL> self . hosts . update_ip ( host , ip_v4 = arp_pkt . src_ip ) <EOL> elif eth . ethertype == ether_types . ETH_TYPE_IP : <EOL> ipv4_pkt = pkt . get_protocols ( ipv4 . ipv4 ) [ <NUM_LIT:0> ] <EOL> self . hosts . update_ip ( host , ip_v4 = ipv4_pkt . src ) <EOL> elif eth . ethertype == ether_types . ETH_TYPE_IPV6 : <EOL> ipv6_pkt = pkt . get_protocols ( ipv6 . ipv6 ) [ <NUM_LIT:0> ] <EOL> self . hosts . update_ip ( host , ip_v6 = ipv6_pkt . src ) <EOL> def send_lldp_packet ( self , port ) : <EOL> try : <EOL> port_data = self . ports . lldp_sent ( port ) <EOL> except KeyError as e : <EOL> return <EOL> if port_data . is_down : <EOL> return <EOL> dp = self . dps . get ( port . dpid , None ) <EOL> if dp is None : <EOL> return <EOL> if dp . ofproto . OFP_VERSION == ofproto_v1_0 . OFP_VERSION : <EOL> actions = [ dp . ofproto_parser . OFPActionOutput ( port . port_no ) ] <EOL> dp . send_packet_out ( actions = actions , data = port_data . lldp_data ) <EOL> elif dp . ofproto . OFP_VERSION >= ofproto_v1_2 . OFP_VERSION : <EOL> actions = [ dp . ofproto_parser . OFPActionOutput ( port . port_no ) ] <EOL> out = dp . ofproto_parser . OFPPacketOut ( <EOL> datapath = dp , in_port = dp . ofproto . OFPP_CONTROLLER , <EOL> buffer_id = dp . ofproto . OFP_NO_BUFFER , actions = actions , <EOL> data = port_data . lldp_data ) <EOL> dp . send_msg ( out ) <EOL> else : <EOL> LOG . error ( '<STR_LIT>' , <EOL> dp . ofproto . OFP_VERSION ) <EOL> def lldp_loop ( self ) : <EOL> while self . is_active : <EOL> self . lldp_event . clear ( ) <EOL> now = time . time ( ) <EOL> timeout = None <EOL> ports_now = [ ] <EOL> ports = [ ] <EOL> for ( key , data ) in self . ports . items ( ) : <EOL> if data . timestamp is None : <EOL> ports_now . append ( key ) <EOL> continue <EOL> expire = data . timestamp + self . LLDP_SEND_PERIOD_PER_PORT <EOL> if expire <= now : <EOL> ports . append ( key ) <EOL> continue <EOL> timeout = expire - now <EOL> break <EOL> for port in ports_now : <EOL> self . send_lldp_packet ( port ) <EOL> for port in ports : <EOL> self . send_lldp_packet ( port ) <EOL> hub . sleep ( self . LLDP_SEND_GUARD ) <EOL> if timeout is not None and ports : <EOL> timeout = <NUM_LIT:0> <EOL> self . lldp_event . wait ( timeout = timeout ) <EOL> def link_loop ( self ) : <EOL> while self . is_active : <EOL> self . link_event . clear ( ) <EOL> now = time . time ( ) <EOL> deleted = [ ] <EOL> for ( link , timestamp ) in self . links . items ( ) : <EOL> if timestamp + self . LINK_TIMEOUT < now : <EOL> src = link . src <EOL> if src in self . ports : <EOL> port_data = self . ports . get_port ( src ) <EOL> if port_data . lldp_dropped ( ) > self . LINK_LLDP_DROP : <EOL> deleted . append ( link ) <EOL> for link in deleted : <EOL> self . links . link_down ( link ) <EOL> self . send_event_to_observers ( event . EventLinkDelete ( link ) ) <EOL> dst = link . dst <EOL> rev_link = Link ( dst , link . src ) <EOL> if rev_link not in deleted : <EOL> expire = now - self . LINK_TIMEOUT <EOL> self . links . rev_link_set_timestamp ( rev_link , expire ) <EOL> if dst in self . ports : <EOL> self . ports . move_front ( dst ) <EOL> self . lldp_event . set ( ) <EOL> self . link_event . wait ( timeout = self . TIMEOUT_CHECK_PERIOD ) <EOL> @ set_ev_cls ( event . EventSwitchRequest ) <EOL> def switch_request_handler ( self , req ) : <EOL> dpid = req . dpid <EOL> switches = [ ] <EOL> if dpid is None : <EOL> for dp in self . dps . values ( ) : <EOL> switches . append ( self . _get_switch ( dp . id ) ) <EOL> elif dpid in self . dps : <EOL> switches . append ( self . _get_switch ( dpid ) ) <EOL> rep = event . EventSwitchReply ( req . src , switches ) <EOL> self . reply_to_request ( req , rep ) <EOL> @ set_ev_cls ( event . EventLinkRequest ) <EOL> def link_request_handler ( self , req ) : <EOL> dpid = req . dpid <EOL> if dpid is None : <EOL> links = self . links <EOL> else : <EOL> links = [ link for link in self . links if link . src . dpid == dpid ] <EOL> rep = event . EventLinkReply ( req . src , dpid , links ) <EOL> self . reply_to_request ( req , rep ) <EOL> @ set_ev_cls ( event . EventHostRequest ) <EOL> def host_request_handler ( self , req ) : <EOL> dpid = req . dpid <EOL> hosts = [ ] <EOL> if dpid is None : <EOL> for mac in self . hosts : <EOL> hosts . append ( self . hosts [ mac ] ) <EOL> else : <EOL> hosts = self . hosts . get_by_dpid ( dpid ) <EOL> rep = event . EventHostReply ( req . src , dpid , hosts ) <EOL> self . reply_to_request ( req , rep ) </s>
