1 # Copyright (C) 2014 SDN Hub
3 # Licensed under the GNU GENERAL PUBLIC LICENSE, Version 3.
4 # You may not use this file except in compliance with this License.
5 # You may obtain a copy of the License at
7 # http://www.gnu.org/licenses/gpl-3.0.txt
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
16 from webob import Response
18 from threading import Timer
20 from ryu.base import app_manager
21 from ryu.controller import ofp_event
22 from ryu.controller.handler import MAIN_DISPATCHER
23 from ryu.controller.handler import set_ev_cls
24 from ryu.controller import dpset
25 from ryu.app.wsgi import ControllerBase, WSGIApplication
27 from ryu.lib.packet import packet
28 from ryu.lib.packet import ethernet
29 from ryu.lib.packet import ipv4
30 from ryu.lib.packet import arp
31 from ryu.ofproto import ether
32 from ryu.ofproto import ofproto_v1_0, ofproto_v1_3
33 from ryu.lib import dpid as dpid_lib
36 class HostTracker(app_manager.RyuApp):
37 def __init__(self, *args, **kwargs):
38 super(HostTracker, self).__init__(*args, **kwargs)
41 self.IDLE_TIMEOUT = 300
43 Timer(self.IDLE_TIMEOUT, self.expireHostEntries).start()
45 def expireHostEntries(self):
47 for key,val in self.hosts.iteritems():
48 if int(time.time()) > val['timestamp'] + self.IDLE_TIMEOUT:
49 expiredEntries.append(key)
51 for ip in expiredEntries:
54 Timer(self.IDLE_TIMEOUT, self.expireHostEntries).start()
56 # The hypothesis is that a router will be the srcMAC
57 # for many IP addresses at the same time
58 def isRouter(self, mac):
59 if mac in self.routers:
63 for key,val in self.hosts.iteritems():
70 self.routers.append(mac)
75 def updateHostTable(self, srcIP, dpid, port):
76 self.hosts[srcIP]['timestamp'] = int(time.time())
77 self.hosts[srcIP]['dpid'] = dpid
78 self.hosts[srcIP]['port'] = port
80 @set_ev_cls(ofp_event.EventOFPPacketIn, MAIN_DISPATCHER)
81 def packet_in_handler(self, ev):
83 datapath = msg.datapath
84 ofproto = datapath.ofproto
85 parser = datapath.ofproto_parser
86 in_port = msg.match['in_port']
88 pkt = packet.Packet(msg.data)
89 eth = pkt.get_protocols(ethernet.ethernet)[0]
91 if eth.ethertype == ether.ETH_TYPE_ARP:
92 arp_pkt = pkt.get_protocols(arp.arp)[0]
93 srcMac = arp_pkt.src_mac
94 srcIP = arp_pkt.src_ip
95 elif eth.ethertype == ether.ETH_TYPE_IP:
96 ip = pkt.get_protocols(ipv4.ipv4)[0]
102 if self.isRouter(srcMac):
105 if srcIP not in self.hosts:
106 self.hosts[srcIP] = {}
108 # Always update MAC and switch-port location, just in case
109 # DHCP reassigned the IP or the host moved
110 self.hosts[srcIP]['mac'] = srcMac
111 self.updateHostTable(srcIP, dpid_lib.dpid_to_str(datapath.id), in_port)