blob: 9f8dd48d713165c6bb950ad24efafdf0823bc4cf [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 Hart70da5122014-10-01 16:37:42 -07007import java.util.Map;
Jonathan Hartfca736c2014-09-19 17:26:59 -07008import java.util.Set;
Jonathan Hart70da5122014-10-01 16:37:42 -07009import java.util.concurrent.ConcurrentHashMap;
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 Hart70da5122014-10-01 16:37:42 -070062 private final Map<ProviderId, HostProvider> hostProviders;
63
Jonathan Hartfca736c2014-09-19 17:26:59 -070064 private final long probeRate;
65
alshabib010c31d2014-09-26 10:01:12 -070066 private final Timeout timeout;
Jonathan Hartfca736c2014-09-19 17:26:59 -070067
Jonathan Hart70da5122014-10-01 16:37:42 -070068 public HostMonitor(
alshabib010c31d2014-09-26 10:01:12 -070069 DeviceService deviceService,
Jonathan Hart70da5122014-10-01 16:37:42 -070070 PacketService packetService,
71 HostManager hostService) {
72
Jonathan Hartfca736c2014-09-19 17:26:59 -070073 this.deviceService = deviceService;
Jonathan Hart87fbbad2014-09-23 08:43:50 -070074 this.packetService = packetService;
Jonathan Hart70da5122014-10-01 16:37:42 -070075 this.hostManager = hostService;
Jonathan Hartfca736c2014-09-19 17:26:59 -070076
77 monitoredAddresses = new HashSet<>();
Jonathan Hart70da5122014-10-01 16:37:42 -070078 hostProviders = new ConcurrentHashMap<>();
Jonathan Hartfca736c2014-09-19 17:26:59 -070079
80 probeRate = 30000; // milliseconds
81
82 timeout = Timer.getTimer().newTimeout(this, 0, TimeUnit.MILLISECONDS);
Jonathan Hart70da5122014-10-01 16:37:42 -070083
84 addDefaultAddresses();
Jonathan Hartfca736c2014-09-19 17:26:59 -070085 }
86
Jonathan Hart70da5122014-10-01 16:37:42 -070087 private void addDefaultAddresses() {
88 //monitoredAddresses.add(IpAddress.valueOf("10.0.0.1"));
89 }
90
91 void addMonitoringFor(IpAddress ip) {
Jonathan Hartfca736c2014-09-19 17:26:59 -070092 monitoredAddresses.add(ip);
93 }
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 Hart70da5122014-10-01 16:37:42 -070099 void shutdown() {
Jonathan Hartfca736c2014-09-19 17:26:59 -0700100 timeout.cancel();
101 }
102
Jonathan Hart70da5122014-10-01 16:37:42 -0700103 void registerHostProvider(HostProvider provider) {
104 hostProviders.put(provider.id(), provider);
105 }
106
107 void unregisterHostProvider(HostProvider provider) {
108 // TODO find out how to call this
109 }
110
Jonathan Hartfca736c2014-09-19 17:26:59 -0700111 @Override
112 public void run(Timeout timeout) throws Exception {
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700113 for (IpAddress ip : monitoredAddresses) {
Jonathan Hart70da5122014-10-01 16:37:42 -0700114 // TODO have to convert right now because the HostService API uses IpPrefix
115 IpPrefix prefix = IpPrefix.valueOf(ip.toOctets());
116
117 Set<Host> hosts = hostManager.getHostsByIp(prefix);
Jonathan Hartfca736c2014-09-19 17:26:59 -0700118
119 if (hosts.isEmpty()) {
120 sendArpRequest(ip);
121 } else {
122 for (Host host : hosts) {
Jonathan Hart70da5122014-10-01 16:37:42 -0700123 HostProvider provider = hostProviders.get(host.providerId());
124 if (provider != null) {
125 provider.triggerProbe(host);
126 }
Jonathan Hartfca736c2014-09-19 17:26:59 -0700127 }
128 }
129 }
130
131 timeout = Timer.getTimer().newTimeout(this, probeRate, TimeUnit.MILLISECONDS);
132 }
133
134 /**
135 * Sends an ARP request for the given IP address.
136 *
137 * @param targetIp IP address to ARP for
138 */
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700139 private void sendArpRequest(IpAddress targetIp) {
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700140 // Find ports with an IP address in the target's subnet and sent ARP
141 // probes out those ports.
142 for (Device device : deviceService.getDevices()) {
Jonathan Hartfca736c2014-09-19 17:26:59 -0700143 for (Port port : deviceService.getPorts(device.id())) {
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700144 ConnectPoint cp = new ConnectPoint(device.id(), port.number());
Jonathan Hart70da5122014-10-01 16:37:42 -0700145 PortAddresses addresses = hostManager.getAddressBindingsForPort(cp);
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700146
Jonathan Hart70da5122014-10-01 16:37:42 -0700147 for (IpPrefix prefix : addresses.ips()) {
Jonathan Hart09585c62014-09-23 16:58:04 -0700148 if (prefix.contains(targetIp)) {
Jonathan Hart70da5122014-10-01 16:37:42 -0700149 sendProbe(device.id(), port, targetIp,
150 prefix.toIpAddress(), addresses.mac());
Jonathan Hart09585c62014-09-23 16:58:04 -0700151 }
Jonathan Hart70da5122014-10-01 16:37:42 -0700152 }
Jonathan Hartfca736c2014-09-19 17:26:59 -0700153 }
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700154 }
Jonathan Hartfca736c2014-09-19 17:26:59 -0700155 }
156
Jonathan Hart70da5122014-10-01 16:37:42 -0700157 private void sendProbe(DeviceId deviceId, Port port, IpAddress targetIp,
158 IpAddress sourceIp, MacAddress sourceMac) {
159 Ethernet arpPacket = buildArpRequest(targetIp, sourceIp, sourceMac);
Jonathan Hartfca736c2014-09-19 17:26:59 -0700160
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700161 List<Instruction> instructions = new ArrayList<>();
162 instructions.add(Instructions.createOutput(port.number()));
163
alshabib010c31d2014-09-26 10:01:12 -0700164 TrafficTreatment treatment = new DefaultTrafficTreatment.Builder()
165 .setOutput(port.number())
166 .build();
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700167
168 OutboundPacket outboundPacket =
169 new DefaultOutboundPacket(deviceId, treatment,
170 ByteBuffer.wrap(arpPacket.serialize()));
171
172 packetService.emit(outboundPacket);
173 }
174
Jonathan Hart70da5122014-10-01 16:37:42 -0700175 private Ethernet buildArpRequest(IpAddress targetIp, IpAddress sourceIp,
176 MacAddress sourceMac) {
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700177
178 ARP arp = new ARP();
179 arp.setHardwareType(ARP.HW_TYPE_ETHERNET)
Jonathan Hart70da5122014-10-01 16:37:42 -0700180 .setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
181 .setProtocolType(ARP.PROTO_TYPE_IP)
182 .setProtocolAddressLength((byte) IpPrefix.INET_LEN)
183 .setOpCode(ARP.OP_REQUEST);
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700184
Jonathan Hart70da5122014-10-01 16:37:42 -0700185 arp.setSenderHardwareAddress(sourceMac.getAddress())
186 .setSenderProtocolAddress(sourceIp.toOctets())
187 .setTargetHardwareAddress(ZERO_MAC_ADDRESS)
188 .setTargetProtocolAddress(targetIp.toOctets());
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700189
190 Ethernet ethernet = new Ethernet();
191 ethernet.setEtherType(Ethernet.TYPE_ARP)
Jonathan Hart70da5122014-10-01 16:37:42 -0700192 .setDestinationMACAddress(BROADCAST_MAC)
193 .setSourceMACAddress(sourceMac.getAddress())
194 .setPayload(arp);
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700195
196 return ethernet;
Jonathan Hartfca736c2014-09-19 17:26:59 -0700197 }
198}