blob: 1d7c37c43ead00104381921d47f01c37b2743abf [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2014-present Open Networking Laboratory
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07003 *
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 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.net.host.impl;
Jonathan Hartfca736c2014-09-19 17:26:59 -070017
Jonathan Hartfca736c2014-09-19 17:26:59 -070018import org.jboss.netty.util.Timeout;
19import org.jboss.netty.util.TimerTask;
Jonathan Hart6cd2f352015-01-13 17:44:45 -080020import org.onlab.packet.ARP;
21import org.onlab.packet.Ethernet;
Pavlin Radoslavov89edb542015-02-23 13:50:29 -080022import org.onlab.packet.ICMP6;
Pavlin Radoslavov89edb542015-02-23 13:50:29 -080023import org.onlab.packet.IPv6;
Jonathan Hart4cb39882015-08-12 23:50:55 -040024import org.onlab.packet.IpAddress;
Jonathan Hart6cd2f352015-01-13 17:44:45 -080025import org.onlab.packet.MacAddress;
26import org.onlab.packet.VlanId;
Pavlin Radoslavov89edb542015-02-23 13:50:29 -080027import org.onlab.packet.ndp.NeighborDiscoveryOptions;
28import org.onlab.packet.ndp.NeighborSolicitation;
Jonathan Hart6cd2f352015-01-13 17:44:45 -080029import org.onlab.util.Timer;
Jonathan Hart4cb39882015-08-12 23:50:55 -040030import org.onosproject.incubator.net.intf.Interface;
31import org.onosproject.incubator.net.intf.InterfaceService;
Brian O'Connorabafb502014-12-02 22:26:20 -080032import org.onosproject.net.ConnectPoint;
Brian O'Connorabafb502014-12-02 22:26:20 -080033import org.onosproject.net.Host;
Jonathan Hartfb32a6e2015-09-01 12:12:14 +020034import org.onosproject.net.edge.EdgePortService;
Brian O'Connorabafb502014-12-02 22:26:20 -080035import org.onosproject.net.flow.DefaultTrafficTreatment;
36import org.onosproject.net.flow.TrafficTreatment;
Brian O'Connorabafb502014-12-02 22:26:20 -080037import org.onosproject.net.host.HostProvider;
38import org.onosproject.net.host.InterfaceIpAddress;
Brian O'Connorabafb502014-12-02 22:26:20 -080039import org.onosproject.net.packet.DefaultOutboundPacket;
40import org.onosproject.net.packet.OutboundPacket;
41import org.onosproject.net.packet.PacketService;
42import org.onosproject.net.provider.ProviderId;
Jonathan Hartfb32a6e2015-09-01 12:12:14 +020043import org.slf4j.Logger;
44import org.slf4j.LoggerFactory;
Jonathan Hart6cd2f352015-01-13 17:44:45 -080045
46import java.nio.ByteBuffer;
Jonathan Hart6cd2f352015-01-13 17:44:45 -080047import java.util.Collections;
Jonathan Hart6cd2f352015-01-13 17:44:45 -080048import java.util.Set;
49import java.util.concurrent.ConcurrentHashMap;
50import java.util.concurrent.ConcurrentMap;
51import java.util.concurrent.TimeUnit;
Jonathan Hartfca736c2014-09-19 17:26:59 -070052
Jonathan Hart87fbbad2014-09-23 08:43:50 -070053/**
54 * Monitors hosts on the dataplane to detect changes in host data.
Thomas Vachuska4b420772014-10-30 16:46:17 -070055 * <p>
Jonathan Hart87fbbad2014-09-23 08:43:50 -070056 * The HostMonitor can monitor hosts that have already been detected for
57 * changes. At an application's request, it can also monitor and actively
58 * probe for hosts that have not yet been detected (specified by IP address).
Thomas Vachuska4b420772014-10-30 16:46:17 -070059 * </p>
Jonathan Hart87fbbad2014-09-23 08:43:50 -070060 */
tom202175a2014-09-19 19:00:11 -070061public class HostMonitor implements TimerTask {
Jonathan Hartfb32a6e2015-09-01 12:12:14 +020062
63 private Logger log = LoggerFactory.getLogger(getClass());
64
Jonathan Hart70da5122014-10-01 16:37:42 -070065 private PacketService packetService;
66 private HostManager hostManager;
Jonathan Hart4cb39882015-08-12 23:50:55 -040067 private InterfaceService interfaceService;
Jonathan Hartfb32a6e2015-09-01 12:12:14 +020068 private EdgePortService edgePortService;
Jonathan Hartfca736c2014-09-19 17:26:59 -070069
Jonathan Hart87fbbad2014-09-23 08:43:50 -070070 private final Set<IpAddress> monitoredAddresses;
Jonathan Hartfca736c2014-09-19 17:26:59 -070071
Jonathan Hart34ed2fd2014-10-02 19:08:55 -070072 private final ConcurrentMap<ProviderId, HostProvider> hostProviders;
Jonathan Hart70da5122014-10-01 16:37:42 -070073
Jonathan Hart34ed2fd2014-10-02 19:08:55 -070074 private static final long DEFAULT_PROBE_RATE = 30000; // milliseconds
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -080075 private static final byte[] ZERO_MAC_ADDRESS = MacAddress.ZERO.toBytes();
Jonathan Hart34ed2fd2014-10-02 19:08:55 -070076 private long probeRate = DEFAULT_PROBE_RATE;
Jonathan Hartfca736c2014-09-19 17:26:59 -070077
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -070078 private Timeout timeout;
Jonathan Hartfca736c2014-09-19 17:26:59 -070079
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -070080 /**
81 * Creates a new host monitor.
82 *
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -070083 * @param packetService packet service used to send packets on the data plane
Jonathan Hartb4758a92014-09-24 10:46:45 -070084 * @param hostManager host manager used to look up host information and
85 * probe existing hosts
Jonathan Hart4cb39882015-08-12 23:50:55 -040086 * @param interfaceService interface service for interface information
Thomas Vachuska0ae45602015-09-22 17:06:19 -070087 * @param edgePortService edge port service
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -070088 */
Jonathan Hart4cb39882015-08-12 23:50:55 -040089 public HostMonitor(PacketService packetService, HostManager hostManager,
Jonathan Hartfb32a6e2015-09-01 12:12:14 +020090 InterfaceService interfaceService,
91 EdgePortService edgePortService) {
Jonathan Hart70da5122014-10-01 16:37:42 -070092
Jonathan Hart87fbbad2014-09-23 08:43:50 -070093 this.packetService = packetService;
Jonathan Hartb4758a92014-09-24 10:46:45 -070094 this.hostManager = hostManager;
Jonathan Hart4cb39882015-08-12 23:50:55 -040095 this.interfaceService = interfaceService;
Jonathan Hartfb32a6e2015-09-01 12:12:14 +020096 this.edgePortService = edgePortService;
Jonathan Hartfca736c2014-09-19 17:26:59 -070097
Jonathan Hart4cb39882015-08-12 23:50:55 -040098 monitoredAddresses = Collections.newSetFromMap(new ConcurrentHashMap<>());
Jonathan Hart70da5122014-10-01 16:37:42 -070099 hostProviders = new ConcurrentHashMap<>();
Jonathan Hart70da5122014-10-01 16:37:42 -0700100 }
101
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -0700102 /**
103 * Adds an IP address to be monitored by the host monitor. The monitor will
104 * periodically probe the host to detect changes.
105 *
106 * @param ip IP address of the host to monitor
107 */
Jonathan Hart70da5122014-10-01 16:37:42 -0700108 void addMonitoringFor(IpAddress ip) {
Jonathan Hartfca736c2014-09-19 17:26:59 -0700109 monitoredAddresses.add(ip);
110 }
111
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -0700112 /**
113 * Stops monitoring the given IP address.
114 *
115 * @param ip IP address to stop monitoring on
116 */
Jonathan Hart70da5122014-10-01 16:37:42 -0700117 void stopMonitoring(IpAddress ip) {
Jonathan Hartfca736c2014-09-19 17:26:59 -0700118 monitoredAddresses.remove(ip);
119 }
120
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -0700121 /**
122 * Starts the host monitor. Does nothing if the monitor is already running.
123 */
124 void start() {
125 synchronized (this) {
126 if (timeout == null) {
127 timeout = Timer.getTimer().newTimeout(this, 0, TimeUnit.MILLISECONDS);
128 }
129 }
Jonathan Hartfca736c2014-09-19 17:26:59 -0700130 }
131
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -0700132 /**
133 * Stops the host monitor.
134 */
135 void shutdown() {
136 synchronized (this) {
137 timeout.cancel();
138 timeout = null;
139 }
140 }
141
142 /**
143 * Registers a host provider with the host monitor. The monitor can use the
144 * provider to probe hosts.
145 *
146 * @param provider the host provider to register
147 */
Jonathan Hart70da5122014-10-01 16:37:42 -0700148 void registerHostProvider(HostProvider provider) {
149 hostProviders.put(provider.id(), provider);
150 }
151
Jonathan Hartfca736c2014-09-19 17:26:59 -0700152 @Override
153 public void run(Timeout timeout) throws Exception {
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700154 for (IpAddress ip : monitoredAddresses) {
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700155 Set<Host> hosts = hostManager.getHostsByIp(ip);
Jonathan Hartfca736c2014-09-19 17:26:59 -0700156
157 if (hosts.isEmpty()) {
Jonathan Hart39ee6482015-08-31 16:00:19 +0200158 sendRequest(ip);
Jonathan Hartfca736c2014-09-19 17:26:59 -0700159 } else {
160 for (Host host : hosts) {
Jonathan Hart70da5122014-10-01 16:37:42 -0700161 HostProvider provider = hostProviders.get(host.providerId());
Jonathan Hart34ed2fd2014-10-02 19:08:55 -0700162 if (provider == null) {
163 hostProviders.remove(host.providerId(), null);
164 } else {
Jonathan Hart70da5122014-10-01 16:37:42 -0700165 provider.triggerProbe(host);
166 }
Jonathan Hartfca736c2014-09-19 17:26:59 -0700167 }
168 }
169 }
170
Satish Ke9d748f2015-11-24 19:05:01 +0530171 synchronized (this) {
172 this.timeout = Timer.getTimer().newTimeout(this, probeRate, TimeUnit.MILLISECONDS);
173 }
Jonathan Hartfca736c2014-09-19 17:26:59 -0700174 }
175
176 /**
Jonathan Hart39ee6482015-08-31 16:00:19 +0200177 * Sends an ARP or NDP request for the given IP address.
Jonathan Hartfca736c2014-09-19 17:26:59 -0700178 *
Pavlin Radoslavov89edb542015-02-23 13:50:29 -0800179 * @param targetIp IP address to send the request for
Jonathan Hartfca736c2014-09-19 17:26:59 -0700180 */
Jonathan Hart39ee6482015-08-31 16:00:19 +0200181 private void sendRequest(IpAddress targetIp) {
Jonathan Hart4cb39882015-08-12 23:50:55 -0400182 Interface intf = interfaceService.getMatchingInterface(targetIp);
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700183
Jonathan Hart4cb39882015-08-12 23:50:55 -0400184 if (intf == null) {
185 return;
186 }
187
Jonathan Hartfb32a6e2015-09-01 12:12:14 +0200188 if (!edgePortService.isEdgePoint(intf.connectPoint())) {
189 log.warn("Attempt to send probe out non-edge port: {}", intf);
190 return;
191 }
192
Jonathan Hart4cb39882015-08-12 23:50:55 -0400193 for (InterfaceIpAddress ia : intf.ipAddresses()) {
194 if (ia.subnetAddress().contains(targetIp)) {
Jonathan Hart39ee6482015-08-31 16:00:19 +0200195 sendProbe(intf.connectPoint(), targetIp, ia.ipAddress(),
Jonathan Hart4cb39882015-08-12 23:50:55 -0400196 intf.mac(), intf.vlan());
Jonathan Hartfca736c2014-09-19 17:26:59 -0700197 }
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700198 }
Jonathan Hartfca736c2014-09-19 17:26:59 -0700199 }
200
Jonathan Hart39ee6482015-08-31 16:00:19 +0200201 private void sendProbe(ConnectPoint connectPoint,
202 IpAddress targetIp,
203 IpAddress sourceIp, MacAddress sourceMac,
204 VlanId vlan) {
Pavlin Radoslavov89edb542015-02-23 13:50:29 -0800205 Ethernet probePacket = null;
206
Pavlin Radoslavov87dd9302015-03-10 13:53:24 -0700207 if (targetIp.isIp4()) {
Pavlin Radoslavov89edb542015-02-23 13:50:29 -0800208 // IPv4: Use ARP
Jonathan Hart39ee6482015-08-31 16:00:19 +0200209 probePacket = buildArpRequest(targetIp, sourceIp, sourceMac, vlan);
Pavlin Radoslavov89edb542015-02-23 13:50:29 -0800210 } else {
211 // IPv6: Use Neighbor Discovery
Jonathan Hart39ee6482015-08-31 16:00:19 +0200212 probePacket = buildNdpRequest(targetIp, sourceIp, sourceMac, vlan);
Pavlin Radoslavov89edb542015-02-23 13:50:29 -0800213 }
Jonathan Hartfca736c2014-09-19 17:26:59 -0700214
tom9a693fd2014-10-03 11:32:19 -0700215 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jonathan Hart4cb39882015-08-12 23:50:55 -0400216 .setOutput(connectPoint.port())
Pavlin Radoslavov89edb542015-02-23 13:50:29 -0800217 .build();
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700218
219 OutboundPacket outboundPacket =
Jonathan Hart4cb39882015-08-12 23:50:55 -0400220 new DefaultOutboundPacket(connectPoint.deviceId(), treatment,
Pavlin Radoslavov89edb542015-02-23 13:50:29 -0800221 ByteBuffer.wrap(probePacket.serialize()));
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700222
223 packetService.emit(outboundPacket);
224 }
225
Jonathan Hart70da5122014-10-01 16:37:42 -0700226 private Ethernet buildArpRequest(IpAddress targetIp, IpAddress sourceIp,
Pavlin Radoslavov89edb542015-02-23 13:50:29 -0800227 MacAddress sourceMac, VlanId vlan) {
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700228
229 ARP arp = new ARP();
230 arp.setHardwareType(ARP.HW_TYPE_ETHERNET)
Jonathan Hart70da5122014-10-01 16:37:42 -0700231 .setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
232 .setProtocolType(ARP.PROTO_TYPE_IP)
Pavlin Radoslavov52307e62014-10-29 15:07:37 -0700233 .setProtocolAddressLength((byte) IpAddress.INET_BYTE_LENGTH)
Jonathan Hart70da5122014-10-01 16:37:42 -0700234 .setOpCode(ARP.OP_REQUEST);
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700235
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800236 arp.setSenderHardwareAddress(sourceMac.toBytes())
Jonathan Hart70da5122014-10-01 16:37:42 -0700237 .setSenderProtocolAddress(sourceIp.toOctets())
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800238 .setTargetHardwareAddress(ZERO_MAC_ADDRESS)
Jonathan Hart70da5122014-10-01 16:37:42 -0700239 .setTargetProtocolAddress(targetIp.toOctets());
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700240
241 Ethernet ethernet = new Ethernet();
242 ethernet.setEtherType(Ethernet.TYPE_ARP)
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800243 .setDestinationMACAddress(MacAddress.BROADCAST)
244 .setSourceMACAddress(sourceMac)
Jonathan Hart70da5122014-10-01 16:37:42 -0700245 .setPayload(arp);
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700246
Jonathan Hart6cd2f352015-01-13 17:44:45 -0800247 if (!vlan.equals(VlanId.NONE)) {
248 ethernet.setVlanID(vlan.toShort());
249 }
250
alshabibaf734ff2015-07-01 16:35:26 -0700251 ethernet.setPad(true);
252
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700253 return ethernet;
Jonathan Hartfca736c2014-09-19 17:26:59 -0700254 }
Pavlin Radoslavov89edb542015-02-23 13:50:29 -0800255
256 private Ethernet buildNdpRequest(IpAddress targetIp, IpAddress sourceIp,
257 MacAddress sourceMac, VlanId vlan) {
258
259 // Create the Ethernet packet
260 Ethernet ethernet = new Ethernet();
261 ethernet.setEtherType(Ethernet.TYPE_IPV6)
262 .setDestinationMACAddress(MacAddress.BROADCAST)
263 .setSourceMACAddress(sourceMac);
264 if (!vlan.equals(VlanId.NONE)) {
265 ethernet.setVlanID(vlan.toShort());
266 }
267
268 //
269 // Create the IPv6 packet
270 //
271 // TODO: The destination IP address should be the
272 // solicited-node multicast address
273 IPv6 ipv6 = new IPv6();
274 ipv6.setSourceAddress(sourceIp.toOctets());
275 ipv6.setDestinationAddress(targetIp.toOctets());
276 ipv6.setHopLimit((byte) 255);
277
278 // Create the ICMPv6 packet
279 ICMP6 icmp6 = new ICMP6();
280 icmp6.setIcmpType(ICMP6.NEIGHBOR_SOLICITATION);
281 icmp6.setIcmpCode((byte) 0);
282
Jonathan Hart39ee6482015-08-31 16:00:19 +0200283 // Create the Neighbor Solicitation packet
Pavlin Radoslavov89edb542015-02-23 13:50:29 -0800284 NeighborSolicitation ns = new NeighborSolicitation();
285 ns.setTargetAddress(targetIp.toOctets());
286 ns.addOption(NeighborDiscoveryOptions.TYPE_SOURCE_LL_ADDRESS,
287 sourceMac.toBytes());
288
289 icmp6.setPayload(ns);
290 ipv6.setPayload(icmp6);
291 ethernet.setPayload(ipv6);
292
293 return ethernet;
294 }
Jonathan Hartfca736c2014-09-19 17:26:59 -0700295}