blob: 825221395979aa8e400e6464b2ce35716dec3130 [file] [log] [blame]
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2014-present Open Networking Foundation
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 Hart6cd2f352015-01-13 17:44:45 -080018import org.onlab.packet.ARP;
19import org.onlab.packet.Ethernet;
Pavlin Radoslavov89edb542015-02-23 13:50:29 -080020import org.onlab.packet.IPv6;
Charles Chan82fac582017-09-12 12:09:22 -070021import org.onlab.packet.Ip4Address;
22import org.onlab.packet.Ip6Address;
Jonathan Hart4cb39882015-08-12 23:50:55 -040023import org.onlab.packet.IpAddress;
Jonathan Hart6cd2f352015-01-13 17:44:45 -080024import org.onlab.packet.MacAddress;
25import org.onlab.packet.VlanId;
Pavlin Radoslavov89edb542015-02-23 13:50:29 -080026import org.onlab.packet.ndp.NeighborSolicitation;
Yuta HIGUCHI19afc032017-05-20 23:44:17 -070027import org.onlab.util.SharedScheduledExecutors;
Charles Chana618d742022-01-04 16:39:44 -080028import org.onosproject.net.Port;
29import org.onosproject.net.device.DeviceService;
Ray Milkeyfacf2862017-08-03 11:58:29 -070030import org.onosproject.net.intf.InterfaceService;
Brian O'Connorabafb502014-12-02 22:26:20 -080031import org.onosproject.net.ConnectPoint;
Brian O'Connorabafb502014-12-02 22:26:20 -080032import org.onosproject.net.Host;
Jonathan Hartfb32a6e2015-09-01 12:12:14 +020033import org.onosproject.net.edge.EdgePortService;
Brian O'Connorabafb502014-12-02 22:26:20 -080034import org.onosproject.net.flow.DefaultTrafficTreatment;
35import org.onosproject.net.flow.TrafficTreatment;
Brian O'Connorabafb502014-12-02 22:26:20 -080036import org.onosproject.net.host.HostProvider;
Brian O'Connorabafb502014-12-02 22:26:20 -080037import org.onosproject.net.packet.DefaultOutboundPacket;
38import org.onosproject.net.packet.OutboundPacket;
39import org.onosproject.net.packet.PacketService;
40import org.onosproject.net.provider.ProviderId;
Jonathan Hartfb32a6e2015-09-01 12:12:14 +020041import org.slf4j.Logger;
42import org.slf4j.LoggerFactory;
Jonathan Hart6cd2f352015-01-13 17:44:45 -080043
44import java.nio.ByteBuffer;
Jonathan Hart6cd2f352015-01-13 17:44:45 -080045import java.util.Collections;
Jonathan Hart6cd2f352015-01-13 17:44:45 -080046import java.util.Set;
47import java.util.concurrent.ConcurrentHashMap;
48import java.util.concurrent.ConcurrentMap;
Yuta HIGUCHI19afc032017-05-20 23:44:17 -070049import java.util.concurrent.ScheduledFuture;
Jonathan Hart6cd2f352015-01-13 17:44:45 -080050import java.util.concurrent.TimeUnit;
Jonathan Hartfca736c2014-09-19 17:26:59 -070051
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 */
Yuta HIGUCHI19afc032017-05-20 23:44:17 -070060public class HostMonitor implements Runnable {
Jonathan Hartfb32a6e2015-09-01 12:12:14 +020061
62 private Logger log = LoggerFactory.getLogger(getClass());
63
Jonathan Hart70da5122014-10-01 16:37:42 -070064 private PacketService packetService;
65 private HostManager hostManager;
Jonathan Hart4cb39882015-08-12 23:50:55 -040066 private InterfaceService interfaceService;
Jonathan Hartfb32a6e2015-09-01 12:12:14 +020067 private EdgePortService edgePortService;
Charles Chana618d742022-01-04 16:39:44 -080068 private DeviceService deviceService;
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
Yuta HIGUCHI19afc032017-05-20 23:44:17 -070078 private ScheduledFuture<?> 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
Charles Chana618d742022-01-04 16:39:44 -080084 * @param hostManager host manager used to look up host information and probe existing hosts
Jonathan Hart4cb39882015-08-12 23:50:55 -040085 * @param interfaceService interface service for interface information
Thomas Vachuska0ae45602015-09-22 17:06:19 -070086 * @param edgePortService edge port service
Charles Chana618d742022-01-04 16:39:44 -080087 * @param deviceService device 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,
Charles Chana618d742022-01-04 16:39:44 -080091 EdgePortService edgePortService,
92 DeviceService deviceService) {
Jonathan Hart70da5122014-10-01 16:37:42 -070093
Jonathan Hart87fbbad2014-09-23 08:43:50 -070094 this.packetService = packetService;
Jonathan Hartb4758a92014-09-24 10:46:45 -070095 this.hostManager = hostManager;
Jonathan Hart4cb39882015-08-12 23:50:55 -040096 this.interfaceService = interfaceService;
Jonathan Hartfb32a6e2015-09-01 12:12:14 +020097 this.edgePortService = edgePortService;
Charles Chana618d742022-01-04 16:39:44 -080098 this.deviceService = deviceService;
Jonathan Hartfca736c2014-09-19 17:26:59 -070099
Jonathan Hart4cb39882015-08-12 23:50:55 -0400100 monitoredAddresses = Collections.newSetFromMap(new ConcurrentHashMap<>());
Jonathan Hart70da5122014-10-01 16:37:42 -0700101 hostProviders = new ConcurrentHashMap<>();
Jonathan Hart70da5122014-10-01 16:37:42 -0700102 }
103
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -0700104 /**
105 * Adds an IP address to be monitored by the host monitor. The monitor will
106 * periodically probe the host to detect changes.
107 *
108 * @param ip IP address of the host to monitor
109 */
Jonathan Hart70da5122014-10-01 16:37:42 -0700110 void addMonitoringFor(IpAddress ip) {
Jonathan Hartf4edb312017-03-24 10:43:10 -0700111 if (monitoredAddresses.add(ip)) {
112 probe(ip);
113 }
Jonathan Hartfca736c2014-09-19 17:26:59 -0700114 }
115
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -0700116 /**
117 * Stops monitoring the given IP address.
118 *
119 * @param ip IP address to stop monitoring on
120 */
Jonathan Hart70da5122014-10-01 16:37:42 -0700121 void stopMonitoring(IpAddress ip) {
Jonathan Hartfca736c2014-09-19 17:26:59 -0700122 monitoredAddresses.remove(ip);
123 }
124
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -0700125 /**
126 * Starts the host monitor. Does nothing if the monitor is already running.
127 */
128 void start() {
129 synchronized (this) {
130 if (timeout == null) {
Yuta HIGUCHI19afc032017-05-20 23:44:17 -0700131 timeout = SharedScheduledExecutors.newTimeout(this, 0, TimeUnit.MILLISECONDS);
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -0700132 }
133 }
Jonathan Hartfca736c2014-09-19 17:26:59 -0700134 }
135
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -0700136 /**
137 * Stops the host monitor.
138 */
139 void shutdown() {
140 synchronized (this) {
Yuta HIGUCHI19afc032017-05-20 23:44:17 -0700141 timeout.cancel(true);
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -0700142 timeout = null;
143 }
144 }
145
sdn94b00152016-08-30 02:12:32 -0700146 /*
147 * Sets the probe rate.
148 */
149 void setProbeRate(long probeRate) {
150 this.probeRate = probeRate;
151 }
152
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -0700153 /**
154 * Registers a host provider with the host monitor. The monitor can use the
155 * provider to probe hosts.
156 *
157 * @param provider the host provider to register
158 */
Jonathan Hart70da5122014-10-01 16:37:42 -0700159 void registerHostProvider(HostProvider provider) {
160 hostProviders.put(provider.id(), provider);
161 }
162
Jonathan Hartfca736c2014-09-19 17:26:59 -0700163 @Override
Yuta HIGUCHI19afc032017-05-20 23:44:17 -0700164 public void run() {
Jonathan Hart78613d22016-07-27 11:25:29 -0700165 monitoredAddresses.forEach(this::probe);
Jonathan Hartfca736c2014-09-19 17:26:59 -0700166
Satish Ke9d748f2015-11-24 19:05:01 +0530167 synchronized (this) {
Yuta HIGUCHI19afc032017-05-20 23:44:17 -0700168 this.timeout = SharedScheduledExecutors.newTimeout(this, probeRate, TimeUnit.MILLISECONDS);
Satish Ke9d748f2015-11-24 19:05:01 +0530169 }
Jonathan Hartfca736c2014-09-19 17:26:59 -0700170 }
171
Jonathan Hart78613d22016-07-27 11:25:29 -0700172 private void probe(IpAddress ip) {
173 Set<Host> hosts = hostManager.getHostsByIp(ip);
174
175 if (hosts.isEmpty()) {
176 sendRequest(ip);
177 } else {
178 for (Host host : hosts) {
179 HostProvider provider = hostProviders.get(host.providerId());
180 if (provider == null) {
181 hostProviders.remove(host.providerId(), null);
182 } else {
183 provider.triggerProbe(host);
184 }
185 }
186 }
187 }
188
Jonathan Hartfca736c2014-09-19 17:26:59 -0700189 /**
Jonathan Hart39ee6482015-08-31 16:00:19 +0200190 * Sends an ARP or NDP request for the given IP address.
Jonathan Hartfca736c2014-09-19 17:26:59 -0700191 *
Pavlin Radoslavov89edb542015-02-23 13:50:29 -0800192 * @param targetIp IP address to send the request for
Jonathan Hartfca736c2014-09-19 17:26:59 -0700193 */
Jonathan Hart39ee6482015-08-31 16:00:19 +0200194 private void sendRequest(IpAddress targetIp) {
Charles Chan9238b382017-03-14 13:14:58 -0700195 interfaceService.getMatchingInterfaces(targetIp).forEach(intf -> {
Charles Chana618d742022-01-04 16:39:44 -0800196 Port port = deviceService.getPort(intf.connectPoint());
197 if (port == null) {
198 log.debug("Aborting probing non-existent port: {}", intf);
199 return;
200 }
201 if (!port.isEnabled()) {
202 log.debug("Aborting probing disabled port: {}", intf);
203 return;
204 }
Charles Chan9238b382017-03-14 13:14:58 -0700205 if (!edgePortService.isEdgePoint(intf.connectPoint())) {
Charles Chana618d742022-01-04 16:39:44 -0800206 log.warn("Aborting probing non-edge port: {}", intf);
Charles Chan9238b382017-03-14 13:14:58 -0700207 return;
Jonathan Hartfca736c2014-09-19 17:26:59 -0700208 }
Charles Chan9238b382017-03-14 13:14:58 -0700209
210 intf.ipAddressesList().stream()
211 .filter(ia -> ia.subnetAddress().contains(targetIp))
212 .forEach(ia -> {
Charles Chan82fac582017-09-12 12:09:22 -0700213 MacAddress probeMac = intf.mac();
214 IpAddress probeIp = !probeMac.equals(MacAddress.ONOS) ?
215 ia.ipAddress() :
216 (ia.ipAddress().isIp4() ? Ip4Address.ZERO : Ip6Address.ZERO);
217 sendProbe(intf.connectPoint(), targetIp, probeIp, probeMac, intf.vlan());
218
Charles Chan9238b382017-03-14 13:14:58 -0700219 // account for use-cases where tagged-vlan config is used
220 if (!intf.vlanTagged().isEmpty()) {
221 intf.vlanTagged().forEach(tag -> {
Charles Chan82fac582017-09-12 12:09:22 -0700222 sendProbe(intf.connectPoint(), targetIp, probeIp, probeMac, tag);
Charles Chan9238b382017-03-14 13:14:58 -0700223 });
224 }
225 });
226 });
Jonathan Hartfca736c2014-09-19 17:26:59 -0700227 }
228
Charles Chan82fac582017-09-12 12:09:22 -0700229 public void sendProbe(ConnectPoint connectPoint, IpAddress targetIp, IpAddress sourceIp,
230 MacAddress sourceMac, VlanId vlan) {
231 log.debug("Sending probe for target:{} out of intf:{} vlan:{}", targetIp, connectPoint, vlan);
232
Pier Ventre78e73f62016-12-02 19:59:28 -0800233 Ethernet probePacket;
Pavlin Radoslavov89edb542015-02-23 13:50:29 -0800234
Pavlin Radoslavov87dd9302015-03-10 13:53:24 -0700235 if (targetIp.isIp4()) {
Pavlin Radoslavov89edb542015-02-23 13:50:29 -0800236 // IPv4: Use ARP
Jonathan Hart39ee6482015-08-31 16:00:19 +0200237 probePacket = buildArpRequest(targetIp, sourceIp, sourceMac, vlan);
Pavlin Radoslavov89edb542015-02-23 13:50:29 -0800238 } else {
Pier Luigi9b1d6262017-02-02 22:31:34 -0800239 // IPv6: Use Neighbor Discovery. According to the NDP protocol,
240 // we should use the solicitation node address as IPv6 destination
241 // and the multicast mac address as Ethernet destination.
Pier Luigi37b687b2017-01-16 22:46:33 -0800242 byte[] destIp = IPv6.getSolicitNodeAddress(targetIp.toOctets());
Pier Ventre78e73f62016-12-02 19:59:28 -0800243 probePacket = NeighborSolicitation.buildNdpSolicit(
Ray Milkey49724162019-01-25 15:59:36 -0800244 targetIp.getIp6Address(),
245 sourceIp.getIp6Address(),
246 Ip6Address.valueOf(destIp),
247 sourceMac,
248 MacAddress.valueOf(IPv6.getMCastMacAddress(destIp)),
Pier Ventre78e73f62016-12-02 19:59:28 -0800249 vlan
250 );
251 }
252
253 if (probePacket == null) {
254 log.warn("Not able to build the probe packet");
255 return;
Pavlin Radoslavov89edb542015-02-23 13:50:29 -0800256 }
Jonathan Hartfca736c2014-09-19 17:26:59 -0700257
tom9a693fd2014-10-03 11:32:19 -0700258 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Jonathan Hart4cb39882015-08-12 23:50:55 -0400259 .setOutput(connectPoint.port())
Pavlin Radoslavov89edb542015-02-23 13:50:29 -0800260 .build();
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700261
262 OutboundPacket outboundPacket =
Jonathan Hart4cb39882015-08-12 23:50:55 -0400263 new DefaultOutboundPacket(connectPoint.deviceId(), treatment,
Pavlin Radoslavov89edb542015-02-23 13:50:29 -0800264 ByteBuffer.wrap(probePacket.serialize()));
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700265
266 packetService.emit(outboundPacket);
267 }
268
Jonathan Hart70da5122014-10-01 16:37:42 -0700269 private Ethernet buildArpRequest(IpAddress targetIp, IpAddress sourceIp,
Pavlin Radoslavov89edb542015-02-23 13:50:29 -0800270 MacAddress sourceMac, VlanId vlan) {
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700271
272 ARP arp = new ARP();
273 arp.setHardwareType(ARP.HW_TYPE_ETHERNET)
Jonathan Hart70da5122014-10-01 16:37:42 -0700274 .setHardwareAddressLength((byte) Ethernet.DATALAYER_ADDRESS_LENGTH)
275 .setProtocolType(ARP.PROTO_TYPE_IP)
Pavlin Radoslavov52307e62014-10-29 15:07:37 -0700276 .setProtocolAddressLength((byte) IpAddress.INET_BYTE_LENGTH)
Jonathan Hart70da5122014-10-01 16:37:42 -0700277 .setOpCode(ARP.OP_REQUEST);
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700278
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800279 arp.setSenderHardwareAddress(sourceMac.toBytes())
Jonathan Hart70da5122014-10-01 16:37:42 -0700280 .setSenderProtocolAddress(sourceIp.toOctets())
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800281 .setTargetHardwareAddress(ZERO_MAC_ADDRESS)
Jonathan Hart70da5122014-10-01 16:37:42 -0700282 .setTargetProtocolAddress(targetIp.toOctets());
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700283
284 Ethernet ethernet = new Ethernet();
285 ethernet.setEtherType(Ethernet.TYPE_ARP)
Yuta HIGUCHI3e848a82014-11-02 20:19:42 -0800286 .setDestinationMACAddress(MacAddress.BROADCAST)
287 .setSourceMACAddress(sourceMac)
Jonathan Hart70da5122014-10-01 16:37:42 -0700288 .setPayload(arp);
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700289
Jonathan Hart6cd2f352015-01-13 17:44:45 -0800290 if (!vlan.equals(VlanId.NONE)) {
291 ethernet.setVlanID(vlan.toShort());
292 }
293
alshabibaf734ff2015-07-01 16:35:26 -0700294 ethernet.setPad(true);
295
Jonathan Hart87fbbad2014-09-23 08:43:50 -0700296 return ethernet;
Jonathan Hartfca736c2014-09-19 17:26:59 -0700297 }
Pavlin Radoslavov89edb542015-02-23 13:50:29 -0800298
Jonathan Hartfca736c2014-09-19 17:26:59 -0700299}