blob: e6e348f970086f6dc6f3af90898f00cd164f3787 [file] [log] [blame]
tombe988312014-09-19 18:38:47 -07001package org.onlab.onos.net.host.impl;
Jonathan Hartfca736c2014-09-19 17:26:59 -07002
Jonathan Hart87fbbad2014-09-23 08:43:50 -07003import java.nio.ByteBuffer;
4import java.util.ArrayList;
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -07005import java.util.Collections;
Jonathan Hart87fbbad2014-09-23 08:43:50 -07006import java.util.List;
Jonathan Hartfca736c2014-09-19 17:26:59 -07007import java.util.Set;
Jonathan Hart70da5122014-10-01 16:37:42 -07008import java.util.concurrent.ConcurrentHashMap;
Jonathan Hart34ed2fd2014-10-02 19:08:55 -07009import java.util.concurrent.ConcurrentMap;
Jonathan Hartfca736c2014-09-19 17:26:59 -070010import java.util.concurrent.TimeUnit;
11
12import org.jboss.netty.util.Timeout;
13import org.jboss.netty.util.TimerTask;
Jonathan Hart87fbbad2014-09-23 08:43:50 -070014import org.onlab.onos.net.ConnectPoint;
15import org.onlab.onos.net.Device;
16import org.onlab.onos.net.DeviceId;
Jonathan Hartfca736c2014-09-19 17:26:59 -070017import org.onlab.onos.net.Host;
18import org.onlab.onos.net.Port;
19import org.onlab.onos.net.device.DeviceService;
Jonathan Hart87fbbad2014-09-23 08:43:50 -070020import org.onlab.onos.net.flow.DefaultTrafficTreatment;
21import org.onlab.onos.net.flow.TrafficTreatment;
22import org.onlab.onos.net.flow.instructions.Instruction;
23import org.onlab.onos.net.flow.instructions.Instructions;
Jonathan Hartfca736c2014-09-19 17:26:59 -070024import org.onlab.onos.net.host.HostProvider;
Jonathan Hart87fbbad2014-09-23 08:43:50 -070025import org.onlab.onos.net.host.PortAddresses;
26import org.onlab.onos.net.packet.DefaultOutboundPacket;
27import org.onlab.onos.net.packet.OutboundPacket;
28import org.onlab.onos.net.packet.PacketService;
Jonathan Hart70da5122014-10-01 16:37:42 -070029import org.onlab.onos.net.provider.ProviderId;
Jonathan Hart87fbbad2014-09-23 08:43:50 -070030import org.onlab.packet.ARP;
31import org.onlab.packet.Ethernet;
32import org.onlab.packet.IpAddress;
Jonathan Hartfca736c2014-09-19 17:26:59 -070033import org.onlab.packet.IpPrefix;
Jonathan Hart87fbbad2014-09-23 08:43:50 -070034import org.onlab.packet.MacAddress;
Jonathan Hartfca736c2014-09-19 17:26:59 -070035import org.onlab.util.Timer;
36
Jonathan Hart87fbbad2014-09-23 08:43:50 -070037/**
38 * Monitors hosts on the dataplane to detect changes in host data.
39 * <p/>
40 * The HostMonitor can monitor hosts that have already been detected for
41 * changes. At an application's request, it can also monitor and actively
42 * probe for hosts that have not yet been detected (specified by IP address).
43 */
tom202175a2014-09-19 19:00:11 -070044public class HostMonitor implements TimerTask {
Jonathan Hart70da5122014-10-01 16:37:42 -070045 private DeviceService deviceService;
46 private PacketService packetService;
47 private HostManager hostManager;
Jonathan Hartfca736c2014-09-19 17:26:59 -070048
Jonathan Hart87fbbad2014-09-23 08:43:50 -070049 private final Set<IpAddress> monitoredAddresses;
Jonathan Hartfca736c2014-09-19 17:26:59 -070050
Jonathan Hart34ed2fd2014-10-02 19:08:55 -070051 private final ConcurrentMap<ProviderId, HostProvider> hostProviders;
Jonathan Hart70da5122014-10-01 16:37:42 -070052
Jonathan Hart34ed2fd2014-10-02 19:08:55 -070053 private static final long DEFAULT_PROBE_RATE = 30000; // milliseconds
54 private long probeRate = DEFAULT_PROBE_RATE;
Jonathan Hartfca736c2014-09-19 17:26:59 -070055
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -070056 private Timeout timeout;
Jonathan Hartfca736c2014-09-19 17:26:59 -070057
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -070058 /**
59 * Creates a new host monitor.
60 *
61 * @param deviceService device service used to find edge ports
62 * @param packetService packet service used to send packets on the data plane
Jonathan Hartb4758a92014-09-24 10:46:45 -070063 * @param hostManager host manager used to look up host information and
64 * probe existing hosts
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -070065 */
Jonathan Hart34ed2fd2014-10-02 19:08:55 -070066 public HostMonitor(DeviceService deviceService, PacketService packetService,
Jonathan Hartb4758a92014-09-24 10:46:45 -070067 HostManager hostManager) {
Jonathan Hart70da5122014-10-01 16:37:42 -070068
Jonathan Hartfca736c2014-09-19 17:26:59 -070069 this.deviceService = deviceService;
Jonathan Hart87fbbad2014-09-23 08:43:50 -070070 this.packetService = packetService;
Jonathan Hartb4758a92014-09-24 10:46:45 -070071 this.hostManager = hostManager;
Jonathan Hartfca736c2014-09-19 17:26:59 -070072
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -070073 monitoredAddresses = Collections.newSetFromMap(
74 new ConcurrentHashMap<IpAddress, Boolean>());
Jonathan Hart70da5122014-10-01 16:37:42 -070075 hostProviders = new ConcurrentHashMap<>();
Jonathan Hartfca736c2014-09-19 17:26:59 -070076
Jonathan Hartfca736c2014-09-19 17:26:59 -070077 timeout = Timer.getTimer().newTimeout(this, 0, TimeUnit.MILLISECONDS);
Jonathan Hart70da5122014-10-01 16:37:42 -070078 }
79
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -070080 /**
81 * Adds an IP address to be monitored by the host monitor. The monitor will
82 * periodically probe the host to detect changes.
83 *
84 * @param ip IP address of the host to monitor
85 */
Jonathan Hart70da5122014-10-01 16:37:42 -070086 void addMonitoringFor(IpAddress ip) {
Jonathan Hartfca736c2014-09-19 17:26:59 -070087 monitoredAddresses.add(ip);
88 }
89
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -070090 /**
91 * Stops monitoring the given IP address.
92 *
93 * @param ip IP address to stop monitoring on
94 */
Jonathan Hart70da5122014-10-01 16:37:42 -070095 void stopMonitoring(IpAddress ip) {
Jonathan Hartfca736c2014-09-19 17:26:59 -070096 monitoredAddresses.remove(ip);
97 }
98
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -070099 /**
100 * Starts the host monitor. Does nothing if the monitor is already running.
101 */
102 void start() {
103 synchronized (this) {
104 if (timeout == null) {
105 timeout = Timer.getTimer().newTimeout(this, 0, TimeUnit.MILLISECONDS);
106 }
107 }
Jonathan Hartfca736c2014-09-19 17:26:59 -0700108 }
109
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -0700110 /**
111 * Stops the host monitor.
112 */
113 void shutdown() {
114 synchronized (this) {
115 timeout.cancel();
116 timeout = null;
117 }
118 }
119
120 /**
121 * Registers a host provider with the host monitor. The monitor can use the
122 * provider to probe hosts.
123 *
124 * @param provider the host provider to register
125 */
Jonathan Hart70da5122014-10-01 16:37:42 -0700126 void registerHostProvider(HostProvider provider) {
127 hostProviders.put(provider.id(), provider);
128 }
129
Jonathan Hartfca736c2014-09-19 17:26:59 -0700130 @Override
131 public void run(Timeout timeout) throws Exception {
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700132 for (IpAddress ip : monitoredAddresses) {
Jonathan Hart70da5122014-10-01 16:37:42 -0700133 // TODO have to convert right now because the HostService API uses IpPrefix
134 IpPrefix prefix = IpPrefix.valueOf(ip.toOctets());
135
136 Set<Host> hosts = hostManager.getHostsByIp(prefix);
Jonathan Hartfca736c2014-09-19 17:26:59 -0700137
138 if (hosts.isEmpty()) {
139 sendArpRequest(ip);
140 } else {
141 for (Host host : hosts) {
Jonathan Hart70da5122014-10-01 16:37:42 -0700142 HostProvider provider = hostProviders.get(host.providerId());
Jonathan Hart34ed2fd2014-10-02 19:08:55 -0700143 if (provider == null) {
144 hostProviders.remove(host.providerId(), null);
145 } else {
Jonathan Hart70da5122014-10-01 16:37:42 -0700146 provider.triggerProbe(host);
147 }
Jonathan Hartfca736c2014-09-19 17:26:59 -0700148 }
149 }
150 }
151
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -0700152 this.timeout = Timer.getTimer().newTimeout(this, probeRate, TimeUnit.MILLISECONDS);
Jonathan Hartfca736c2014-09-19 17:26:59 -0700153 }
154
155 /**
156 * Sends an ARP request for the given IP address.
157 *
158 * @param targetIp IP address to ARP for
159 */
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700160 private void sendArpRequest(IpAddress targetIp) {
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700161 // Find ports with an IP address in the target's subnet and sent ARP
162 // probes out those ports.
163 for (Device device : deviceService.getDevices()) {
Jonathan Hartfca736c2014-09-19 17:26:59 -0700164 for (Port port : deviceService.getPorts(device.id())) {
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700165 ConnectPoint cp = new ConnectPoint(device.id(), port.number());
Jonathan Hart70da5122014-10-01 16:37:42 -0700166 PortAddresses addresses = hostManager.getAddressBindingsForPort(cp);
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700167
Jonathan Hart70da5122014-10-01 16:37:42 -0700168 for (IpPrefix prefix : addresses.ips()) {
Jonathan Hart09585c62014-09-23 16:58:04 -0700169 if (prefix.contains(targetIp)) {
Jonathan Hart70da5122014-10-01 16:37:42 -0700170 sendProbe(device.id(), port, targetIp,
171 prefix.toIpAddress(), addresses.mac());
Jonathan Hart09585c62014-09-23 16:58:04 -0700172 }
Jonathan Hart70da5122014-10-01 16:37:42 -0700173 }
Jonathan Hartfca736c2014-09-19 17:26:59 -0700174 }
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700175 }
Jonathan Hartfca736c2014-09-19 17:26:59 -0700176 }
177
Jonathan Hart70da5122014-10-01 16:37:42 -0700178 private void sendProbe(DeviceId deviceId, Port port, IpAddress targetIp,
179 IpAddress sourceIp, MacAddress sourceMac) {
180 Ethernet arpPacket = buildArpRequest(targetIp, sourceIp, sourceMac);
Jonathan Hartfca736c2014-09-19 17:26:59 -0700181
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700182 List<Instruction> instructions = new ArrayList<>();
183 instructions.add(Instructions.createOutput(port.number()));
184
tom9a693fd2014-10-03 11:32:19 -0700185 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
alshabib010c31d2014-09-26 10:01:12 -0700186 .setOutput(port.number())
187 .build();
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700188
189 OutboundPacket outboundPacket =
190 new DefaultOutboundPacket(deviceId, treatment,
191 ByteBuffer.wrap(arpPacket.serialize()));
192
193 packetService.emit(outboundPacket);
194 }
195
Jonathan Hart70da5122014-10-01 16:37:42 -0700196 private Ethernet buildArpRequest(IpAddress targetIp, IpAddress sourceIp,
197 MacAddress sourceMac) {
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700198
199 ARP arp = new ARP();
200 arp.setHardwareType(ARP.HW_TYPE_ETHERNET)
Jonathan Hart70da5122014-10-01 16:37:42 -0700201 .setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
202 .setProtocolType(ARP.PROTO_TYPE_IP)
203 .setProtocolAddressLength((byte) IpPrefix.INET_LEN)
204 .setOpCode(ARP.OP_REQUEST);
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700205
Jonathan Hart70da5122014-10-01 16:37:42 -0700206 arp.setSenderHardwareAddress(sourceMac.getAddress())
207 .setSenderProtocolAddress(sourceIp.toOctets())
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -0700208 .setTargetHardwareAddress(MacAddress.ZERO_MAC_ADDRESS)
Jonathan Hart70da5122014-10-01 16:37:42 -0700209 .setTargetProtocolAddress(targetIp.toOctets());
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700210
211 Ethernet ethernet = new Ethernet();
212 ethernet.setEtherType(Ethernet.TYPE_ARP)
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -0700213 .setDestinationMACAddress(MacAddress.BROADCAST_MAC)
Jonathan Hart70da5122014-10-01 16:37:42 -0700214 .setSourceMACAddress(sourceMac.getAddress())
215 .setPayload(arp);
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700216
217 return ethernet;
Jonathan Hartfca736c2014-09-19 17:26:59 -0700218 }
219}