blob: c9e0442ad4acb86b94b4c0f1b1776c79a2af796b [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 Hartfca736c2014-09-19 17:26:59 -07005import java.util.HashSet;
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;
Jonathan Hart70da5122014-10-01 16:37:42 -070036import org.slf4j.Logger;
37import org.slf4j.LoggerFactory;
Jonathan Hartfca736c2014-09-19 17:26:59 -070038
Jonathan Hart87fbbad2014-09-23 08:43:50 -070039/**
40 * Monitors hosts on the dataplane to detect changes in host data.
41 * <p/>
42 * The HostMonitor can monitor hosts that have already been detected for
43 * changes. At an application's request, it can also monitor and actively
44 * probe for hosts that have not yet been detected (specified by IP address).
45 */
tom202175a2014-09-19 19:00:11 -070046public class HostMonitor implements TimerTask {
Jonathan Hart70da5122014-10-01 16:37:42 -070047 private static final Logger log = LoggerFactory.getLogger(HostMonitor.class);
Jonathan Hart87fbbad2014-09-23 08:43:50 -070048
49 private static final byte[] ZERO_MAC_ADDRESS =
50 MacAddress.valueOf("00:00:00:00:00:00").getAddress();
51
52 // TODO put on Ethernet
53 private static final byte[] BROADCAST_MAC =
54 MacAddress.valueOf("ff:ff:ff:ff:ff:ff").getAddress();
55
Jonathan Hart70da5122014-10-01 16:37:42 -070056 private DeviceService deviceService;
57 private PacketService packetService;
58 private HostManager hostManager;
Jonathan Hartfca736c2014-09-19 17:26:59 -070059
Jonathan Hart87fbbad2014-09-23 08:43:50 -070060 private final Set<IpAddress> monitoredAddresses;
Jonathan Hartfca736c2014-09-19 17:26:59 -070061
Jonathan Hart34ed2fd2014-10-02 19:08:55 -070062 private final ConcurrentMap<ProviderId, HostProvider> hostProviders;
Jonathan Hart70da5122014-10-01 16:37:42 -070063
Jonathan Hart34ed2fd2014-10-02 19:08:55 -070064 private static final long DEFAULT_PROBE_RATE = 30000; // milliseconds
65 private long probeRate = DEFAULT_PROBE_RATE;
Jonathan Hartfca736c2014-09-19 17:26:59 -070066
alshabib010c31d2014-09-26 10:01:12 -070067 private final Timeout timeout;
Jonathan Hartfca736c2014-09-19 17:26:59 -070068
Jonathan Hart34ed2fd2014-10-02 19:08:55 -070069 public HostMonitor(DeviceService deviceService, PacketService packetService,
Jonathan Hart70da5122014-10-01 16:37:42 -070070 HostManager hostService) {
71
Jonathan Hartfca736c2014-09-19 17:26:59 -070072 this.deviceService = deviceService;
Jonathan Hart87fbbad2014-09-23 08:43:50 -070073 this.packetService = packetService;
Jonathan Hart70da5122014-10-01 16:37:42 -070074 this.hostManager = hostService;
Jonathan Hartfca736c2014-09-19 17:26:59 -070075
76 monitoredAddresses = new HashSet<>();
Jonathan Hart70da5122014-10-01 16:37:42 -070077 hostProviders = new ConcurrentHashMap<>();
Jonathan Hartfca736c2014-09-19 17:26:59 -070078
Jonathan Hartfca736c2014-09-19 17:26:59 -070079 timeout = Timer.getTimer().newTimeout(this, 0, TimeUnit.MILLISECONDS);
Jonathan Hart70da5122014-10-01 16:37:42 -070080 }
81
82 void addMonitoringFor(IpAddress ip) {
Jonathan Hartfca736c2014-09-19 17:26:59 -070083 monitoredAddresses.add(ip);
84 }
85
Jonathan Hart70da5122014-10-01 16:37:42 -070086 void stopMonitoring(IpAddress ip) {
Jonathan Hartfca736c2014-09-19 17:26:59 -070087 monitoredAddresses.remove(ip);
88 }
89
Jonathan Hart70da5122014-10-01 16:37:42 -070090 void shutdown() {
Jonathan Hartfca736c2014-09-19 17:26:59 -070091 timeout.cancel();
92 }
93
Jonathan Hart70da5122014-10-01 16:37:42 -070094 void registerHostProvider(HostProvider provider) {
95 hostProviders.put(provider.id(), provider);
96 }
97
Jonathan Hartfca736c2014-09-19 17:26:59 -070098 @Override
99 public void run(Timeout timeout) throws Exception {
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700100 for (IpAddress ip : monitoredAddresses) {
Jonathan Hart70da5122014-10-01 16:37:42 -0700101 // TODO have to convert right now because the HostService API uses IpPrefix
102 IpPrefix prefix = IpPrefix.valueOf(ip.toOctets());
103
104 Set<Host> hosts = hostManager.getHostsByIp(prefix);
Jonathan Hartfca736c2014-09-19 17:26:59 -0700105
106 if (hosts.isEmpty()) {
107 sendArpRequest(ip);
108 } else {
109 for (Host host : hosts) {
Jonathan Hart70da5122014-10-01 16:37:42 -0700110 HostProvider provider = hostProviders.get(host.providerId());
Jonathan Hart34ed2fd2014-10-02 19:08:55 -0700111 if (provider == null) {
112 hostProviders.remove(host.providerId(), null);
113 } else {
Jonathan Hart70da5122014-10-01 16:37:42 -0700114 provider.triggerProbe(host);
115 }
Jonathan Hartfca736c2014-09-19 17:26:59 -0700116 }
117 }
118 }
119
120 timeout = Timer.getTimer().newTimeout(this, probeRate, TimeUnit.MILLISECONDS);
121 }
122
123 /**
124 * Sends an ARP request for the given IP address.
125 *
126 * @param targetIp IP address to ARP for
127 */
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700128 private void sendArpRequest(IpAddress targetIp) {
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700129 // Find ports with an IP address in the target's subnet and sent ARP
130 // probes out those ports.
131 for (Device device : deviceService.getDevices()) {
Jonathan Hartfca736c2014-09-19 17:26:59 -0700132 for (Port port : deviceService.getPorts(device.id())) {
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700133 ConnectPoint cp = new ConnectPoint(device.id(), port.number());
Jonathan Hart70da5122014-10-01 16:37:42 -0700134 PortAddresses addresses = hostManager.getAddressBindingsForPort(cp);
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700135
Jonathan Hart70da5122014-10-01 16:37:42 -0700136 for (IpPrefix prefix : addresses.ips()) {
Jonathan Hart09585c62014-09-23 16:58:04 -0700137 if (prefix.contains(targetIp)) {
Jonathan Hart70da5122014-10-01 16:37:42 -0700138 sendProbe(device.id(), port, targetIp,
139 prefix.toIpAddress(), addresses.mac());
Jonathan Hart09585c62014-09-23 16:58:04 -0700140 }
Jonathan Hart70da5122014-10-01 16:37:42 -0700141 }
Jonathan Hartfca736c2014-09-19 17:26:59 -0700142 }
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700143 }
Jonathan Hartfca736c2014-09-19 17:26:59 -0700144 }
145
Jonathan Hart70da5122014-10-01 16:37:42 -0700146 private void sendProbe(DeviceId deviceId, Port port, IpAddress targetIp,
147 IpAddress sourceIp, MacAddress sourceMac) {
148 Ethernet arpPacket = buildArpRequest(targetIp, sourceIp, sourceMac);
Jonathan Hartfca736c2014-09-19 17:26:59 -0700149
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700150 List<Instruction> instructions = new ArrayList<>();
151 instructions.add(Instructions.createOutput(port.number()));
152
alshabib010c31d2014-09-26 10:01:12 -0700153 TrafficTreatment treatment = new DefaultTrafficTreatment.Builder()
154 .setOutput(port.number())
155 .build();
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700156
157 OutboundPacket outboundPacket =
158 new DefaultOutboundPacket(deviceId, treatment,
159 ByteBuffer.wrap(arpPacket.serialize()));
160
161 packetService.emit(outboundPacket);
162 }
163
Jonathan Hart70da5122014-10-01 16:37:42 -0700164 private Ethernet buildArpRequest(IpAddress targetIp, IpAddress sourceIp,
165 MacAddress sourceMac) {
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700166
167 ARP arp = new ARP();
168 arp.setHardwareType(ARP.HW_TYPE_ETHERNET)
Jonathan Hart70da5122014-10-01 16:37:42 -0700169 .setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
170 .setProtocolType(ARP.PROTO_TYPE_IP)
171 .setProtocolAddressLength((byte) IpPrefix.INET_LEN)
172 .setOpCode(ARP.OP_REQUEST);
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700173
Jonathan Hart70da5122014-10-01 16:37:42 -0700174 arp.setSenderHardwareAddress(sourceMac.getAddress())
175 .setSenderProtocolAddress(sourceIp.toOctets())
176 .setTargetHardwareAddress(ZERO_MAC_ADDRESS)
177 .setTargetProtocolAddress(targetIp.toOctets());
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700178
179 Ethernet ethernet = new Ethernet();
180 ethernet.setEtherType(Ethernet.TYPE_ARP)
Jonathan Hart70da5122014-10-01 16:37:42 -0700181 .setDestinationMACAddress(BROADCAST_MAC)
182 .setSourceMACAddress(sourceMac.getAddress())
183 .setPayload(arp);
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700184
185 return ethernet;
Jonathan Hartfca736c2014-09-19 17:26:59 -0700186 }
187}