blob: d7299e8e4182191ccb15999e1942eb8cc51722a0 [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
2 * Copyright 2014 Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
tombe988312014-09-19 18:38:47 -070016package org.onlab.onos.net.host.impl;
Jonathan Hartfca736c2014-09-19 17:26:59 -070017
Jonathan Hart87fbbad2014-09-23 08:43:50 -070018import java.nio.ByteBuffer;
19import java.util.ArrayList;
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -070020import java.util.Collections;
Jonathan Hart87fbbad2014-09-23 08:43:50 -070021import java.util.List;
Jonathan Hartfca736c2014-09-19 17:26:59 -070022import java.util.Set;
Jonathan Hart70da5122014-10-01 16:37:42 -070023import java.util.concurrent.ConcurrentHashMap;
Jonathan Hart34ed2fd2014-10-02 19:08:55 -070024import java.util.concurrent.ConcurrentMap;
Jonathan Hartfca736c2014-09-19 17:26:59 -070025import java.util.concurrent.TimeUnit;
26
27import org.jboss.netty.util.Timeout;
28import org.jboss.netty.util.TimerTask;
Jonathan Hart87fbbad2014-09-23 08:43:50 -070029import org.onlab.onos.net.ConnectPoint;
30import org.onlab.onos.net.Device;
31import org.onlab.onos.net.DeviceId;
Jonathan Hartfca736c2014-09-19 17:26:59 -070032import org.onlab.onos.net.Host;
33import org.onlab.onos.net.Port;
34import org.onlab.onos.net.device.DeviceService;
Jonathan Hart87fbbad2014-09-23 08:43:50 -070035import org.onlab.onos.net.flow.DefaultTrafficTreatment;
36import org.onlab.onos.net.flow.TrafficTreatment;
37import org.onlab.onos.net.flow.instructions.Instruction;
38import org.onlab.onos.net.flow.instructions.Instructions;
Jonathan Hartfca736c2014-09-19 17:26:59 -070039import org.onlab.onos.net.host.HostProvider;
Pavlin Radoslavov76b0ae22014-10-27 15:33:19 -070040import org.onlab.onos.net.host.InterfaceIpAddress;
Jonathan Hart87fbbad2014-09-23 08:43:50 -070041import org.onlab.onos.net.host.PortAddresses;
42import org.onlab.onos.net.packet.DefaultOutboundPacket;
43import org.onlab.onos.net.packet.OutboundPacket;
44import org.onlab.onos.net.packet.PacketService;
Jonathan Hart70da5122014-10-01 16:37:42 -070045import org.onlab.onos.net.provider.ProviderId;
Jonathan Hart87fbbad2014-09-23 08:43:50 -070046import org.onlab.packet.ARP;
47import org.onlab.packet.Ethernet;
48import org.onlab.packet.IpAddress;
Jonathan Hart87fbbad2014-09-23 08:43:50 -070049import org.onlab.packet.MacAddress;
Jonathan Hartfca736c2014-09-19 17:26:59 -070050import org.onlab.util.Timer;
51
Jonathan Hart87fbbad2014-09-23 08:43:50 -070052/**
53 * Monitors hosts on the dataplane to detect changes in host data.
Thomas Vachuska4b420772014-10-30 16:46:17 -070054 * <p>
Jonathan Hart87fbbad2014-09-23 08:43:50 -070055 * The HostMonitor can monitor hosts that have already been detected for
56 * changes. At an application's request, it can also monitor and actively
57 * probe for hosts that have not yet been detected (specified by IP address).
Thomas Vachuska4b420772014-10-30 16:46:17 -070058 * </p>
Jonathan Hart87fbbad2014-09-23 08:43:50 -070059 */
tom202175a2014-09-19 19:00:11 -070060public class HostMonitor implements TimerTask {
Jonathan Hart70da5122014-10-01 16:37:42 -070061 private DeviceService deviceService;
62 private PacketService packetService;
63 private HostManager hostManager;
Jonathan Hartfca736c2014-09-19 17:26:59 -070064
Jonathan Hart87fbbad2014-09-23 08:43:50 -070065 private final Set<IpAddress> monitoredAddresses;
Jonathan Hartfca736c2014-09-19 17:26:59 -070066
Jonathan Hart34ed2fd2014-10-02 19:08:55 -070067 private final ConcurrentMap<ProviderId, HostProvider> hostProviders;
Jonathan Hart70da5122014-10-01 16:37:42 -070068
Jonathan Hart34ed2fd2014-10-02 19:08:55 -070069 private static final long DEFAULT_PROBE_RATE = 30000; // milliseconds
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -080070 private static final byte[] ZERO_MAC_ADDRESS = MacAddress.ZERO.toBytes();
Jonathan Hart34ed2fd2014-10-02 19:08:55 -070071 private long probeRate = DEFAULT_PROBE_RATE;
Jonathan Hartfca736c2014-09-19 17:26:59 -070072
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -070073 private Timeout timeout;
Jonathan Hartfca736c2014-09-19 17:26:59 -070074
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -070075 /**
76 * Creates a new host monitor.
77 *
78 * @param deviceService device service used to find edge ports
79 * @param packetService packet service used to send packets on the data plane
Jonathan Hartb4758a92014-09-24 10:46:45 -070080 * @param hostManager host manager used to look up host information and
81 * probe existing hosts
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -070082 */
Jonathan Hart34ed2fd2014-10-02 19:08:55 -070083 public HostMonitor(DeviceService deviceService, PacketService packetService,
Jonathan Hartb4758a92014-09-24 10:46:45 -070084 HostManager hostManager) {
Jonathan Hart70da5122014-10-01 16:37:42 -070085
Jonathan Hartfca736c2014-09-19 17:26:59 -070086 this.deviceService = deviceService;
Jonathan Hart87fbbad2014-09-23 08:43:50 -070087 this.packetService = packetService;
Jonathan Hartb4758a92014-09-24 10:46:45 -070088 this.hostManager = hostManager;
Jonathan Hartfca736c2014-09-19 17:26:59 -070089
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -070090 monitoredAddresses = Collections.newSetFromMap(
91 new ConcurrentHashMap<IpAddress, Boolean>());
Jonathan Hart70da5122014-10-01 16:37:42 -070092 hostProviders = new ConcurrentHashMap<>();
Jonathan Hart70da5122014-10-01 16:37:42 -070093 }
94
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -070095 /**
96 * Adds an IP address to be monitored by the host monitor. The monitor will
97 * periodically probe the host to detect changes.
98 *
99 * @param ip IP address of the host to monitor
100 */
Jonathan Hart70da5122014-10-01 16:37:42 -0700101 void addMonitoringFor(IpAddress ip) {
Jonathan Hartfca736c2014-09-19 17:26:59 -0700102 monitoredAddresses.add(ip);
103 }
104
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -0700105 /**
106 * Stops monitoring the given IP address.
107 *
108 * @param ip IP address to stop monitoring on
109 */
Jonathan Hart70da5122014-10-01 16:37:42 -0700110 void stopMonitoring(IpAddress ip) {
Jonathan Hartfca736c2014-09-19 17:26:59 -0700111 monitoredAddresses.remove(ip);
112 }
113
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -0700114 /**
115 * Starts the host monitor. Does nothing if the monitor is already running.
116 */
117 void start() {
118 synchronized (this) {
119 if (timeout == null) {
120 timeout = Timer.getTimer().newTimeout(this, 0, TimeUnit.MILLISECONDS);
121 }
122 }
Jonathan Hartfca736c2014-09-19 17:26:59 -0700123 }
124
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -0700125 /**
126 * Stops the host monitor.
127 */
128 void shutdown() {
129 synchronized (this) {
130 timeout.cancel();
131 timeout = null;
132 }
133 }
134
135 /**
136 * Registers a host provider with the host monitor. The monitor can use the
137 * provider to probe hosts.
138 *
139 * @param provider the host provider to register
140 */
Jonathan Hart70da5122014-10-01 16:37:42 -0700141 void registerHostProvider(HostProvider provider) {
142 hostProviders.put(provider.id(), provider);
143 }
144
Jonathan Hartfca736c2014-09-19 17:26:59 -0700145 @Override
146 public void run(Timeout timeout) throws Exception {
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700147 for (IpAddress ip : monitoredAddresses) {
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700148 Set<Host> hosts = hostManager.getHostsByIp(ip);
Jonathan Hartfca736c2014-09-19 17:26:59 -0700149
150 if (hosts.isEmpty()) {
151 sendArpRequest(ip);
152 } else {
153 for (Host host : hosts) {
Jonathan Hart70da5122014-10-01 16:37:42 -0700154 HostProvider provider = hostProviders.get(host.providerId());
Jonathan Hart34ed2fd2014-10-02 19:08:55 -0700155 if (provider == null) {
156 hostProviders.remove(host.providerId(), null);
157 } else {
Jonathan Hart70da5122014-10-01 16:37:42 -0700158 provider.triggerProbe(host);
159 }
Jonathan Hartfca736c2014-09-19 17:26:59 -0700160 }
161 }
162 }
163
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -0700164 this.timeout = Timer.getTimer().newTimeout(this, probeRate, TimeUnit.MILLISECONDS);
Jonathan Hartfca736c2014-09-19 17:26:59 -0700165 }
166
167 /**
168 * Sends an ARP request for the given IP address.
169 *
170 * @param targetIp IP address to ARP for
171 */
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700172 private void sendArpRequest(IpAddress targetIp) {
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700173 // Find ports with an IP address in the target's subnet and sent ARP
174 // probes out those ports.
175 for (Device device : deviceService.getDevices()) {
Jonathan Hartfca736c2014-09-19 17:26:59 -0700176 for (Port port : deviceService.getPorts(device.id())) {
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700177 ConnectPoint cp = new ConnectPoint(device.id(), port.number());
Jonathan Harta887ba82014-11-03 15:20:52 -0800178 Set<PortAddresses> portAddressSet =
Pavlin Radoslavov76b0ae22014-10-27 15:33:19 -0700179 hostManager.getAddressBindingsForPort(cp);
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700180
Jonathan Harta887ba82014-11-03 15:20:52 -0800181 for (PortAddresses portAddresses : portAddressSet) {
182 for (InterfaceIpAddress ia : portAddresses.ipAddresses()) {
183 if (ia.subnetAddress().contains(targetIp)) {
184 sendProbe(device.id(), port, targetIp,
185 ia.ipAddress(), portAddresses.mac());
186 }
Jonathan Hart09585c62014-09-23 16:58:04 -0700187 }
Jonathan Hart70da5122014-10-01 16:37:42 -0700188 }
Jonathan Hartfca736c2014-09-19 17:26:59 -0700189 }
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700190 }
Jonathan Hartfca736c2014-09-19 17:26:59 -0700191 }
192
Jonathan Hart70da5122014-10-01 16:37:42 -0700193 private void sendProbe(DeviceId deviceId, Port port, IpAddress targetIp,
194 IpAddress sourceIp, MacAddress sourceMac) {
195 Ethernet arpPacket = buildArpRequest(targetIp, sourceIp, sourceMac);
Jonathan Hartfca736c2014-09-19 17:26:59 -0700196
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700197 List<Instruction> instructions = new ArrayList<>();
198 instructions.add(Instructions.createOutput(port.number()));
199
tom9a693fd2014-10-03 11:32:19 -0700200 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
alshabib010c31d2014-09-26 10:01:12 -0700201 .setOutput(port.number())
202 .build();
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700203
204 OutboundPacket outboundPacket =
205 new DefaultOutboundPacket(deviceId, treatment,
206 ByteBuffer.wrap(arpPacket.serialize()));
207
208 packetService.emit(outboundPacket);
209 }
210
Jonathan Hart70da5122014-10-01 16:37:42 -0700211 private Ethernet buildArpRequest(IpAddress targetIp, IpAddress sourceIp,
212 MacAddress sourceMac) {
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700213
214 ARP arp = new ARP();
215 arp.setHardwareType(ARP.HW_TYPE_ETHERNET)
Jonathan Hart70da5122014-10-01 16:37:42 -0700216 .setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
217 .setProtocolType(ARP.PROTO_TYPE_IP)
Pavlin Radoslavov52307e62014-10-29 15:07:37 -0700218 .setProtocolAddressLength((byte) IpAddress.INET_BYTE_LENGTH)
Jonathan Hart70da5122014-10-01 16:37:42 -0700219 .setOpCode(ARP.OP_REQUEST);
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700220
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800221 arp.setSenderHardwareAddress(sourceMac.toBytes())
Jonathan Hart70da5122014-10-01 16:37:42 -0700222 .setSenderProtocolAddress(sourceIp.toOctets())
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800223 .setTargetHardwareAddress(ZERO_MAC_ADDRESS)
Jonathan Hart70da5122014-10-01 16:37:42 -0700224 .setTargetProtocolAddress(targetIp.toOctets());
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700225
226 Ethernet ethernet = new Ethernet();
227 ethernet.setEtherType(Ethernet.TYPE_ARP)
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800228 .setDestinationMACAddress(MacAddress.BROADCAST)
229 .setSourceMACAddress(sourceMac)
Jonathan Hart70da5122014-10-01 16:37:42 -0700230 .setPayload(arp);
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700231
232 return ethernet;
Jonathan Hartfca736c2014-09-19 17:26:59 -0700233 }
234}