add host discovery functions
Signed-off-by: Takeshi <a86487817@gmail.com> Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
This commit is contained in:
parent
b5c4b9ae51
commit
af63e5f519
@ -35,4 +35,12 @@ def get_all_link(app):
|
||||
return get_link(app)
|
||||
|
||||
|
||||
def get_host(app, dpid=None):
|
||||
rep = app.send_request(event.EventHostRequest(dpid))
|
||||
return rep.hosts
|
||||
|
||||
|
||||
def get_all_host(app):
|
||||
return get_host(app)
|
||||
|
||||
app_manager.require_app('ryu.topology.switches', api_style=True)
|
||||
|
@ -126,3 +126,26 @@ class EventLinkReply(event.EventReplyBase):
|
||||
def __str__(self):
|
||||
return 'EventLinkReply<dst=%s, dpid=%s, links=%s>' % \
|
||||
(self.dst, self.dpid, len(self.links))
|
||||
|
||||
|
||||
class EventHostRequest(event.EventRequestBase):
|
||||
# if dpid is None, replay all hosts
|
||||
def __init__(self, dpid=None):
|
||||
super(EventHostRequest, self).__init__()
|
||||
self.dst = 'switches'
|
||||
self.dpid = dpid
|
||||
|
||||
def __str__(self):
|
||||
return 'EventHostRequest<src=%s, dpid=%s>' % \
|
||||
(self.src, self.dpid)
|
||||
|
||||
|
||||
class EventHostReply(event.EventReplyBase):
|
||||
def __init__(self, dst, dpid, hosts):
|
||||
super(EventHostReply, self).__init__(dst)
|
||||
self.dpid = dpid
|
||||
self.hosts = hosts
|
||||
|
||||
def __str__(self):
|
||||
return 'EventHostReply<dst=%s, dpid=%s, hosts=%s>' % \
|
||||
(self.dst, self.dpid, len(self.hosts))
|
||||
|
@ -29,10 +29,12 @@ from ryu.lib import addrconv, hub
|
||||
from ryu.lib.mac import DONTCARE_STR
|
||||
from ryu.lib.dpid import dpid_to_str, str_to_dpid
|
||||
from ryu.lib.port_no import port_no_to_str
|
||||
from ryu.lib.packet import packet, ethernet, lldp
|
||||
from ryu.lib.packet import packet, ethernet
|
||||
from ryu.lib.packet import lldp, ether_types
|
||||
from ryu.lib.packet import arp, ipv4, ipv6
|
||||
from ryu.ofproto.ether import ETH_TYPE_LLDP
|
||||
from ryu.ofproto import ofproto_v1_0
|
||||
from ryu.ofproto import nx_match
|
||||
from ryu.ofproto import ofproto_v1_0
|
||||
from ryu.ofproto import ofproto_v1_2
|
||||
from ryu.ofproto import ofproto_v1_3
|
||||
from ryu.ofproto import ofproto_v1_4
|
||||
@ -158,6 +160,68 @@ class Link(object):
|
||||
return 'Link: %s to %s' % (self.src, self.dst)
|
||||
|
||||
|
||||
class Host(object):
|
||||
# This is data class passed by EventHostXXX
|
||||
def __init__(self, mac, port):
|
||||
super(Host, self).__init__()
|
||||
self.port = port
|
||||
self.mac = mac
|
||||
self.ipv4 = []
|
||||
self.ipv6 = []
|
||||
|
||||
def to_dict(self):
|
||||
d = {'mac': self.mac,
|
||||
'ipv4': self.ipv4,
|
||||
'ipv6': self.ipv6,
|
||||
'port': self.port.to_dict()}
|
||||
return d
|
||||
|
||||
def __eq__(self, host):
|
||||
return self.mac == host.mac and self.port == host.port
|
||||
|
||||
def __str__(self):
|
||||
msg = 'Host<mac=%s, port=%s,' % (self.mac, str(self.port))
|
||||
msg += ','.join(self.ipv4)
|
||||
msg += ','.join(self.ipv6)
|
||||
msg += '>'
|
||||
return msg
|
||||
|
||||
|
||||
class HostState(dict):
|
||||
# mac address -> Host class
|
||||
def __init__(self):
|
||||
super(HostState, self).__init__()
|
||||
|
||||
def add(self, host):
|
||||
mac = host.mac
|
||||
self.setdefault(mac, host)
|
||||
|
||||
def update_ip(self, host, ip_v4=None, ip_v6=None):
|
||||
mac = host.mac
|
||||
host = None
|
||||
if mac in self:
|
||||
host = self[mac]
|
||||
|
||||
if not host:
|
||||
return
|
||||
|
||||
if ip_v4 != None and ip_v4 not in host.ipv4:
|
||||
host.ipv4.append(ip_v4)
|
||||
|
||||
if ip_v6 != None and ip_v6 not in host.ipv6:
|
||||
host.ipv6.append(ip_v6)
|
||||
|
||||
def get_by_dpid(self, dpid):
|
||||
result = []
|
||||
|
||||
for mac in self:
|
||||
host = self[mac]
|
||||
if host.port.dpid == dpid:
|
||||
result.append(host)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class PortState(dict):
|
||||
# dict: int port_no -> OFPPort port
|
||||
# OFPPort is defined in ryu.ofproto.ofproto_v1_X_parser
|
||||
@ -451,6 +515,7 @@ class Switches(app_manager.RyuApp):
|
||||
self.port_state = {} # datapath_id => ports
|
||||
self.ports = PortDataState() # Port class -> PortData class
|
||||
self.links = LinkState() # Link class -> timestamp
|
||||
self.hosts = HostState() # mac address -> Host class list
|
||||
self.is_active = True
|
||||
|
||||
self.link_discovery = self.CONF.observe_links
|
||||
@ -518,6 +583,13 @@ class Switches(app_manager.RyuApp):
|
||||
self.send_event_to_observers(event.EventLinkDelete(rev_link))
|
||||
self.ports.move_front(dst)
|
||||
|
||||
def _is_edge_port(self, port):
|
||||
for link in self.links:
|
||||
if port == link.src or port == link.dst:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
@set_ev_cls(ofp_event.EventOFPStateChange,
|
||||
[MAIN_DISPATCHER, DEAD_DISPATCHER])
|
||||
def state_change_handler(self, ev):
|
||||
@ -680,7 +752,7 @@ class Switches(app_manager.RyuApp):
|
||||
dp.ofproto.OFP_VERSION)
|
||||
|
||||
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
|
||||
def packet_in_handler(self, ev):
|
||||
def lldp_packet_in_handler(self, ev):
|
||||
if not self.link_discovery:
|
||||
return
|
||||
|
||||
@ -738,6 +810,54 @@ class Switches(app_manager.RyuApp):
|
||||
if self.explicit_drop:
|
||||
self._drop_packet(msg)
|
||||
|
||||
@set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
|
||||
def host_discovery_packet_in_handler(self, ev):
|
||||
msg = ev.msg
|
||||
pkt = packet.Packet(msg.data)
|
||||
eth = pkt.get_protocols(ethernet.ethernet)[0]
|
||||
|
||||
# ignore lldp packet
|
||||
if eth.ethertype == ETH_TYPE_LLDP:
|
||||
return
|
||||
|
||||
datapath = msg.datapath
|
||||
dpid = datapath.id
|
||||
port_no = -1
|
||||
|
||||
if msg.datapath.ofproto.OFP_VERSION == ofproto_v1_0.OFP_VERSION:
|
||||
port_no = msg.in_port
|
||||
else:
|
||||
port_no = msg.match['in_port']
|
||||
|
||||
port = self._get_port(dpid, port_no)
|
||||
|
||||
# can't find this port(ex: logic port)
|
||||
if not port:
|
||||
return
|
||||
# ignore switch-to-switch port
|
||||
if not self._is_edge_port(port):
|
||||
return
|
||||
|
||||
host_mac = eth.src
|
||||
host = Host(host_mac, port)
|
||||
|
||||
# arp packet, update both location and ip
|
||||
if eth.ethertype == ether_types.ETH_TYPE_ARP:
|
||||
self.hosts.add(host)
|
||||
arp_pkt = pkt.get_protocols(arp.arp)[0]
|
||||
self.hosts.update_ip(host, ip_v4=arp_pkt.src_ip)
|
||||
|
||||
# ipv4 packet, update ip only
|
||||
elif eth.ethertype == ether_types.ETH_TYPE_IP:
|
||||
ipv4_pkt = pkt.get_protocols(ipv4.ipv4)[0]
|
||||
self.hosts.update_ip(host, ip_v4=ipv4_pkt.src)
|
||||
|
||||
# ipv6 packet, update ip only
|
||||
elif eth.ethertype == ether_types.ETH_TYPE_IPV6:
|
||||
# TODO: need to handle NDP
|
||||
ipv6_pkt = pkt.get_protocols(ipv6.ipv6)[0]
|
||||
self.hosts.update_ip(host, ip_v6=ipv6_pkt.src)
|
||||
|
||||
def send_lldp_packet(self, port):
|
||||
try:
|
||||
port_data = self.ports.lldp_sent(port)
|
||||
@ -862,3 +982,16 @@ class Switches(app_manager.RyuApp):
|
||||
links = [link for link in self.links if link.src.dpid == dpid]
|
||||
rep = event.EventLinkReply(req.src, dpid, links)
|
||||
self.reply_to_request(req, rep)
|
||||
|
||||
@set_ev_cls(event.EventHostRequest)
|
||||
def host_request_handler(self, req):
|
||||
dpid = req.dpid
|
||||
hosts = []
|
||||
if dpid is None:
|
||||
for mac in self.hosts:
|
||||
hosts.append(self.hosts[mac])
|
||||
else:
|
||||
hosts = self.hosts.get_by_dpid(dpid)
|
||||
|
||||
rep = event.EventHostReply(req.src, dpid, hosts)
|
||||
self.reply_to_request(req, rep)
|
||||
|
Loading…
Reference in New Issue
Block a user