blob: 3bacd7f871b8569874d44cd4132b7e4eacb1f596 [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;
tomdb0d03f2014-08-27 16:34:15 -070017
jobind19b7142019-05-17 09:46:52 -040018import com.google.common.collect.Sets;
Pier Luigi9b1d6262017-02-02 22:31:34 -080019import org.onlab.packet.Ip6Address;
Simon Huntff663742015-05-14 13:33:05 -070020import org.onlab.packet.IpAddress;
21import org.onlab.packet.MacAddress;
22import org.onlab.packet.VlanId;
soumya3e6f05e2016-08-05 15:11:11 -070023import org.onlab.util.Tools;
24import org.onosproject.cfg.ComponentConfigService;
Charles Chan888e20a2017-05-01 15:44:23 -070025import org.onosproject.net.ConnectPoint;
26import org.onosproject.net.DeviceId;
27import org.onosproject.net.Host;
28import org.onosproject.net.HostId;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070029import org.onosproject.net.HostLocation;
Rafał Szaleckide5cf842018-11-17 13:30:01 +010030import org.onosproject.net.config.Config;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070031import org.onosproject.net.config.NetworkConfigEvent;
32import org.onosproject.net.config.NetworkConfigListener;
33import org.onosproject.net.config.NetworkConfigService;
34import org.onosproject.net.config.basics.BasicHostConfig;
Rafał Szaleckide5cf842018-11-17 13:30:01 +010035import org.onosproject.net.config.basics.HostAnnotationConfig;
Brian O'Connorabafb502014-12-02 22:26:20 -080036import org.onosproject.net.device.DeviceService;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070037import org.onosproject.net.edge.EdgePortService;
Brian O'Connorabafb502014-12-02 22:26:20 -080038import org.onosproject.net.host.HostAdminService;
39import org.onosproject.net.host.HostDescription;
40import org.onosproject.net.host.HostEvent;
41import org.onosproject.net.host.HostListener;
42import org.onosproject.net.host.HostProvider;
43import org.onosproject.net.host.HostProviderRegistry;
44import org.onosproject.net.host.HostProviderService;
45import org.onosproject.net.host.HostService;
46import org.onosproject.net.host.HostStore;
47import org.onosproject.net.host.HostStoreDelegate;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070048import org.onosproject.net.intf.Interface;
49import org.onosproject.net.intf.InterfaceService;
Brian O'Connorabafb502014-12-02 22:26:20 -080050import org.onosproject.net.packet.PacketService;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070051import org.onosproject.net.provider.AbstractListenerProviderRegistry;
Brian O'Connorabafb502014-12-02 22:26:20 -080052import org.onosproject.net.provider.AbstractProviderService;
soumya3e6f05e2016-08-05 15:11:11 -070053import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070054import org.osgi.service.component.annotations.Activate;
55import org.osgi.service.component.annotations.Component;
56import org.osgi.service.component.annotations.Deactivate;
57import org.osgi.service.component.annotations.Modified;
58import org.osgi.service.component.annotations.Reference;
59import org.osgi.service.component.annotations.ReferenceCardinality;
tomdb0d03f2014-08-27 16:34:15 -070060import org.slf4j.Logger;
tom5f38b3a2014-08-27 23:50:54 -070061
soumya3e6f05e2016-08-05 15:11:11 -070062import java.util.Dictionary;
jobind19b7142019-05-17 09:46:52 -040063import java.util.Map;
Rafał Szaleckide5cf842018-11-17 13:30:01 +010064import java.util.Optional;
Simon Huntff663742015-05-14 13:33:05 -070065import java.util.Set;
jobind19b7142019-05-17 09:46:52 -040066import java.util.concurrent.ConcurrentHashMap;
67import java.util.concurrent.Executors;
68import java.util.concurrent.ScheduledExecutorService;
69import java.util.concurrent.TimeUnit;
Simon Huntff663742015-05-14 13:33:05 -070070
71import static com.google.common.base.Preconditions.checkNotNull;
Sahil Lele3a0cdd52015-07-21 14:16:31 -070072import static com.google.common.base.Preconditions.checkState;
jobind19b7142019-05-17 09:46:52 -040073import static com.google.common.base.Strings.isNullOrEmpty;
Pier Luigi9b1d6262017-02-02 22:31:34 -080074import static org.onlab.packet.IPv6.getLinkLocalAddress;
jobind19b7142019-05-17 09:46:52 -040075import static org.onlab.util.Tools.get;
Ray Milkeyd04e2272018-10-16 18:20:18 -070076import static org.onosproject.net.OsgiPropertyConstants.HM_ALLOW_DUPLICATE_IPS;
77import static org.onosproject.net.OsgiPropertyConstants.HM_ALLOW_DUPLICATE_IPS_DEFAULT;
78import static org.onosproject.net.OsgiPropertyConstants.HM_GREEDY_LEARNING_IPV6;
79import static org.onosproject.net.OsgiPropertyConstants.HM_GREEDY_LEARNING_IPV6_DEFAULT;
80import static org.onosproject.net.OsgiPropertyConstants.HM_MONITOR_HOSTS;
81import static org.onosproject.net.OsgiPropertyConstants.HM_MONITOR_HOSTS_DEFAULT;
82import static org.onosproject.net.OsgiPropertyConstants.HM_PROBE_RATE;
83import static org.onosproject.net.OsgiPropertyConstants.HM_PROBE_RATE_DEFAULT;
jobind19b7142019-05-17 09:46:52 -040084import static org.onosproject.net.OsgiPropertyConstants.HM_HOST_MOVED_THRESHOLD_IN_MILLIS;
85import static org.onosproject.net.OsgiPropertyConstants.HM_HOST_MOVED_THRESHOLD_IN_MILLIS_DEFAULT;
86import static org.onosproject.net.OsgiPropertyConstants.HM_HOST_MOVE_COUNTER;
87import static org.onosproject.net.OsgiPropertyConstants.HM_HOST_MOVE_COUNTER_DEFAULT;
88import static org.onosproject.net.OsgiPropertyConstants.HM_HOST_MOVE_TRACKER_ENABLE;
89import static org.onosproject.net.OsgiPropertyConstants.HM_HOST_MOVE_TRACKER_ENABLE_DEFAULT;
90import static org.onosproject.net.OsgiPropertyConstants.HM_OFFENDING_HOST_EXPIRY_IN_MINS;
91import static org.onosproject.net.OsgiPropertyConstants.HM_OFFENDING_HOST_EXPIRY_IN_MINS_DEFAULT;
92import static org.onosproject.net.OsgiPropertyConstants.HM_OFFENDING_HOST_THREADS_POOL_SIZE;
93import static org.onosproject.net.OsgiPropertyConstants.HM_OFFENDING_HOST_THREADS_POOL_SIZE_DEFAULT;
94
Changhoon Yoon541ef712015-05-23 17:18:34 +090095import static org.onosproject.security.AppGuard.checkPermission;
Simon Huntffbad3b2017-05-16 15:37:51 -070096import static org.onosproject.security.AppPermission.Type.HOST_EVENT;
97import static org.onosproject.security.AppPermission.Type.HOST_READ;
Thomas Vachuska42e8cce2015-07-29 19:25:18 -070098import static org.slf4j.LoggerFactory.getLogger;
Simon Huntff663742015-05-14 13:33:05 -070099
tomdb0d03f2014-08-27 16:34:15 -0700100/**
101 * Provides basic implementation of the host SB & NB APIs.
102 */
Ray Milkeyd04e2272018-10-16 18:20:18 -0700103@Component(
104 immediate = true,
105 service = {
106 HostService.class,
107 HostAdminService.class,
108 HostProviderRegistry.class
109 },
110 property = {
jobind19b7142019-05-17 09:46:52 -0400111 HM_ALLOW_DUPLICATE_IPS + ":Boolean=" + HM_ALLOW_DUPLICATE_IPS_DEFAULT,
112 HM_MONITOR_HOSTS + ":Boolean=" + HM_MONITOR_HOSTS_DEFAULT,
113 HM_PROBE_RATE + ":Integer=" + HM_PROBE_RATE_DEFAULT,
114 HM_GREEDY_LEARNING_IPV6 + ":Boolean=" + HM_GREEDY_LEARNING_IPV6_DEFAULT,
115 HM_HOST_MOVE_TRACKER_ENABLE + ":Boolean=" + HM_HOST_MOVE_TRACKER_ENABLE_DEFAULT,
116 HM_HOST_MOVED_THRESHOLD_IN_MILLIS + ":Integer=" + HM_HOST_MOVED_THRESHOLD_IN_MILLIS_DEFAULT,
117 HM_HOST_MOVE_COUNTER + ":Integer=" + HM_HOST_MOVE_COUNTER_DEFAULT,
118 HM_OFFENDING_HOST_EXPIRY_IN_MINS + ":Long=" + HM_OFFENDING_HOST_EXPIRY_IN_MINS_DEFAULT,
119 HM_OFFENDING_HOST_THREADS_POOL_SIZE + ":Integer=" + HM_OFFENDING_HOST_THREADS_POOL_SIZE_DEFAULT
120
121
Ray Milkeyd04e2272018-10-16 18:20:18 -0700122 }
123)
tom202175a2014-09-19 19:00:11 -0700124public class HostManager
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700125 extends AbstractListenerProviderRegistry<HostEvent, HostListener, HostProvider, HostProviderService>
tom89b63c52014-09-16 09:19:51 -0700126 implements HostService, HostAdminService, HostProviderRegistry {
tomdb0d03f2014-08-27 16:34:15 -0700127
tom5f38b3a2014-08-27 23:50:54 -0700128 private final Logger log = getLogger(getClass());
tomdb0d03f2014-08-27 16:34:15 -0700129
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700130 public static final String HOST_ID_NULL = "Host ID cannot be null";
tom5f38b3a2014-08-27 23:50:54 -0700131
Sahil Lele3a0cdd52015-07-21 14:16:31 -0700132 private final NetworkConfigListener networkConfigListener = new InternalNetworkConfigListener();
133
tomc78acee2014-09-24 15:16:55 -0700134 private HostStoreDelegate delegate = new InternalStoreDelegate();
135
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700136 @Reference(cardinality = ReferenceCardinality.MANDATORY)
tom5bcc9462014-09-19 10:11:31 -0700137 protected HostStore store;
tom7869ad92014-09-09 14:32:08 -0700138
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700139 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Hart70da5122014-10-01 16:37:42 -0700140 protected DeviceService deviceService;
141
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700142 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Hart70da5122014-10-01 16:37:42 -0700143 protected PacketService packetService;
144
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700145 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Sahil Lele3a0cdd52015-07-21 14:16:31 -0700146 protected NetworkConfigService networkConfigService;
147
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700148 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Hart4cb39882015-08-12 23:50:55 -0400149 protected InterfaceService interfaceService;
150
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700151 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Jonathan Hartfb32a6e2015-09-01 12:12:14 +0200152 protected EdgePortService edgePortService;
153
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700154 @Reference(cardinality = ReferenceCardinality.MANDATORY)
soumya3e6f05e2016-08-05 15:11:11 -0700155 protected ComponentConfigService cfgService;
156
Thomas Vachuskaf566fa22018-10-30 14:03:36 -0700157 /** Enable removal of duplicate ip address. */
Ray Milkeyd04e2272018-10-16 18:20:18 -0700158 private boolean allowDuplicateIps = HM_ALLOW_DUPLICATE_IPS_DEFAULT;
sdn94b00152016-08-30 02:12:32 -0700159
Thomas Vachuskaf566fa22018-10-30 14:03:36 -0700160 /** Enable/Disable monitoring of hosts. */
Ray Milkeyd04e2272018-10-16 18:20:18 -0700161 private boolean monitorHosts = HM_MONITOR_HOSTS_DEFAULT;
sdn94b00152016-08-30 02:12:32 -0700162
Thomas Vachuskaf566fa22018-10-30 14:03:36 -0700163 /** Set the probe Rate in milli seconds. */
Ray Milkeyd04e2272018-10-16 18:20:18 -0700164 private long probeRate = HM_PROBE_RATE_DEFAULT;
sdn94b00152016-08-30 02:12:32 -0700165
Thomas Vachuskaf566fa22018-10-30 14:03:36 -0700166 /** Enable/Disable greedy learning of IPv6 link local address. */
Ray Milkeyd04e2272018-10-16 18:20:18 -0700167 private boolean greedyLearningIpv6 = HM_GREEDY_LEARNING_IPV6_DEFAULT;
Pier Luigi9b1d6262017-02-02 22:31:34 -0800168
jobind19b7142019-05-17 09:46:52 -0400169 /** Enable/Disable tracking of rogue host moves. */
170 private boolean hostMoveTrackerEnabled = HM_HOST_MOVE_TRACKER_ENABLE_DEFAULT;
171
172 /** Host move threshold in milli seconds. */
173 private int hostMoveThresholdInMillis = HM_HOST_MOVED_THRESHOLD_IN_MILLIS_DEFAULT;
174
175 /** If the host move happening within given threshold then increment the host move counter. */
176 private int hostMoveCounter = HM_HOST_MOVE_COUNTER_DEFAULT;
177
178 /** Max value of the counter after which the host will not be considered as offending host. */
179 private long offendingHostExpiryInMins = HM_OFFENDING_HOST_EXPIRY_IN_MINS_DEFAULT;
180
181 /** Default pool size of offending host clear executor thread. */
182 private int offendingHostClearThreadPool = HM_OFFENDING_HOST_THREADS_POOL_SIZE_DEFAULT;
183
Jonathan Hart70da5122014-10-01 16:37:42 -0700184 private HostMonitor monitor;
Rafał Szaleckide5cf842018-11-17 13:30:01 +0100185 private HostAnnotationOperator hostAnnotationOperator;
jobind19b7142019-05-17 09:46:52 -0400186 private ScheduledExecutorService offendingHostUnblockExecutor = null;
187 private Map<HostId, HostMoveTracker> hostMoveTracker = new ConcurrentHashMap<>();
tomdb0d03f2014-08-27 16:34:15 -0700188
soumya3e6f05e2016-08-05 15:11:11 -0700189
tomdb0d03f2014-08-27 16:34:15 -0700190 @Activate
soumya3e6f05e2016-08-05 15:11:11 -0700191 public void activate(ComponentContext context) {
Rafał Szaleckide5cf842018-11-17 13:30:01 +0100192 hostAnnotationOperator = new HostAnnotationOperator(networkConfigService);
tomc78acee2014-09-24 15:16:55 -0700193 store.setDelegate(delegate);
tom96dfcab2014-08-28 09:26:03 -0700194 eventDispatcher.addSink(HostEvent.class, listenerRegistry);
soumya3e6f05e2016-08-05 15:11:11 -0700195 cfgService.registerProperties(getClass());
Sahil Lele3a0cdd52015-07-21 14:16:31 -0700196 networkConfigService.addListener(networkConfigListener);
Jonathan Hartfb32a6e2015-09-01 12:12:14 +0200197 monitor = new HostMonitor(packetService, this, interfaceService, edgePortService);
sdn94b00152016-08-30 02:12:32 -0700198 monitor.setProbeRate(probeRate);
Jonathan Hart8f6f1ea2014-10-03 16:05:19 -0700199 monitor.start();
sdn94b00152016-08-30 02:12:32 -0700200 cfgService.registerProperties(getClass());
jobind19b7142019-05-17 09:46:52 -0400201 modified(context);
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700202 log.info("Started");
tomdb0d03f2014-08-27 16:34:15 -0700203 }
204
sdn94b00152016-08-30 02:12:32 -0700205 @Deactivate
206 public void deactivate() {
207 store.unsetDelegate(delegate);
208 eventDispatcher.removeSink(HostEvent.class);
209 networkConfigService.removeListener(networkConfigListener);
210 cfgService.unregisterProperties(getClass(), false);
211 monitor.shutdown();
jobind19b7142019-05-17 09:46:52 -0400212 if (offendingHostUnblockExecutor != null) {
213 offendingHostUnblockExecutor.shutdown();
214 }
sdn94b00152016-08-30 02:12:32 -0700215 log.info("Stopped");
216 }
217
soumya3e6f05e2016-08-05 15:11:11 -0700218 @Modified
Simon Huntffbad3b2017-05-16 15:37:51 -0700219 public void modified(ComponentContext context) {
sdn94b00152016-08-30 02:12:32 -0700220 boolean oldValue = monitorHosts;
221 readComponentConfiguration(context);
222 if (probeRate > 0) {
223 monitor.setProbeRate(probeRate);
224 } else {
Thomas Vachuskaf566fa22018-10-30 14:03:36 -0700225 log.warn("ProbeRate cannot be less than 0");
sdn94b00152016-08-30 02:12:32 -0700226 }
227
228 if (oldValue != monitorHosts) {
229 if (monitorHosts) {
230 startMonitoring();
231 } else {
232 stopMonitoring();
233 }
234 }
235 }
236
237 /**
238 * Extracts properties from the component configuration context.
239 *
240 * @param context the component context
241 */
242 private void readComponentConfiguration(ComponentContext context) {
soumya3e6f05e2016-08-05 15:11:11 -0700243 Dictionary<?, ?> properties = context.getProperties();
244 Boolean flag;
jobind19b7142019-05-17 09:46:52 -0400245 int newHostMoveThresholdInMillis;
246 int newHostMoveCounter;
247 int newOffendinghostPoolSize;
248 long newOffendingHostExpiryInMins;
sdn94b00152016-08-30 02:12:32 -0700249
Thomas Vachuskaf566fa22018-10-30 14:03:36 -0700250 flag = Tools.isPropertyEnabled(properties, HM_MONITOR_HOSTS);
sdn94b00152016-08-30 02:12:32 -0700251 if (flag == null) {
252 log.info("monitorHosts is not enabled " +
253 "using current value of {}", monitorHosts);
254 } else {
255 monitorHosts = flag;
256 log.info("Configured. monitorHosts {}",
Simon Huntffbad3b2017-05-16 15:37:51 -0700257 monitorHosts ? "enabled" : "disabled");
sdn94b00152016-08-30 02:12:32 -0700258 }
259
Thomas Vachuskaf566fa22018-10-30 14:03:36 -0700260 Long longValue = Tools.getLongProperty(properties, HM_PROBE_RATE);
sdn94b00152016-08-30 02:12:32 -0700261 if (longValue == null || longValue == 0) {
262 log.info("probeRate is not set sing default value of {}", probeRate);
263 } else {
264 probeRate = longValue;
265 log.info("Configured. probeRate {}", probeRate);
266 }
267
Thomas Vachuskaf566fa22018-10-30 14:03:36 -0700268 flag = Tools.isPropertyEnabled(properties, HM_ALLOW_DUPLICATE_IPS);
soumya3e6f05e2016-08-05 15:11:11 -0700269 if (flag == null) {
270 log.info("Removal of duplicate ip address is not configured");
271 } else {
272 allowDuplicateIps = flag;
273 log.info("Removal of duplicate ip address is {}",
274 allowDuplicateIps ? "disabled" : "enabled");
275 }
sdn94b00152016-08-30 02:12:32 -0700276
Thomas Vachuskaf566fa22018-10-30 14:03:36 -0700277 flag = Tools.isPropertyEnabled(properties, HM_GREEDY_LEARNING_IPV6);
Pier Luigi9b1d6262017-02-02 22:31:34 -0800278 if (flag == null) {
279 log.info("greedy learning is not enabled " +
280 "using current value of {}", greedyLearningIpv6);
281 } else {
282 greedyLearningIpv6 = flag;
283 log.info("Configured. greedyLearningIpv6 {}",
284 greedyLearningIpv6 ? "enabled" : "disabled");
285 }
jobind19b7142019-05-17 09:46:52 -0400286 flag = Tools.isPropertyEnabled(properties, HM_HOST_MOVE_TRACKER_ENABLE);
287 if (flag == null) {
288 log.info("Host move tracker is not configured " +
289 "using current value of {}", hostMoveTrackerEnabled);
290 } else {
291 hostMoveTrackerEnabled = flag;
292 log.info("Configured. hostMoveTrackerEnabled {}",
293 hostMoveTrackerEnabled ? "enabled" : "disabled");
Pier Luigi9b1d6262017-02-02 22:31:34 -0800294
jobind19b7142019-05-17 09:46:52 -0400295 //On enable cfg ,sets default configuration vales added , else use the default values
296 properties = context.getProperties();
297 try {
298 String s = get(properties, HM_HOST_MOVED_THRESHOLD_IN_MILLIS);
299 newHostMoveThresholdInMillis = isNullOrEmpty(s) ?
300 hostMoveThresholdInMillis : Integer.parseInt(s.trim());
301
302 s = get(properties, HM_HOST_MOVE_COUNTER);
303 newHostMoveCounter = isNullOrEmpty(s) ? hostMoveCounter : Integer.parseInt(s.trim());
304
305 s = get(properties, HM_OFFENDING_HOST_EXPIRY_IN_MINS);
306 newOffendingHostExpiryInMins = isNullOrEmpty(s) ?
307 offendingHostExpiryInMins : Integer.parseInt(s.trim());
308
309 s = get(properties, HM_OFFENDING_HOST_THREADS_POOL_SIZE);
310 newOffendinghostPoolSize = isNullOrEmpty(s) ?
311 offendingHostClearThreadPool : Integer.parseInt(s.trim());
312 } catch (NumberFormatException | ClassCastException e) {
313 newHostMoveThresholdInMillis = HM_HOST_MOVED_THRESHOLD_IN_MILLIS_DEFAULT;
314 newHostMoveCounter = HM_HOST_MOVE_COUNTER_DEFAULT;
315 newOffendingHostExpiryInMins = HM_OFFENDING_HOST_EXPIRY_IN_MINS_DEFAULT;
316 newOffendinghostPoolSize = HM_OFFENDING_HOST_THREADS_POOL_SIZE_DEFAULT;
317 }
318 if (newHostMoveThresholdInMillis != hostMoveThresholdInMillis) {
319 hostMoveThresholdInMillis = newHostMoveThresholdInMillis;
320 }
321 if (newHostMoveCounter != hostMoveCounter) {
322 hostMoveCounter = newHostMoveCounter;
323 }
324 if (newOffendingHostExpiryInMins != offendingHostExpiryInMins) {
325 offendingHostExpiryInMins = newOffendingHostExpiryInMins;
326 }
327 if (hostMoveTrackerEnabled && offendingHostUnblockExecutor == null) {
328 setupThreadPool();
329 } else if (newOffendinghostPoolSize != offendingHostClearThreadPool
330 && offendingHostUnblockExecutor != null) {
331 offendingHostClearThreadPool = newOffendinghostPoolSize;
332 offendingHostUnblockExecutor.shutdown();
333 offendingHostUnblockExecutor = null;
334 setupThreadPool();
335 } else if (!hostMoveTrackerEnabled && offendingHostUnblockExecutor != null) {
336 offendingHostUnblockExecutor.shutdown();
337 offendingHostUnblockExecutor = null;
338 }
339 if (newOffendinghostPoolSize != offendingHostClearThreadPool) {
340 offendingHostClearThreadPool = newOffendinghostPoolSize;
341 }
342
343 log.debug("modified hostMoveThresholdInMillis: {}, hostMoveCounter: {}, " +
344 "offendingHostExpiryInMins: {} ", hostMoveThresholdInMillis,
345 hostMoveCounter, offendingHostExpiryInMins);
346 }
347 }
348
349 private synchronized void setupThreadPool() {
350 offendingHostUnblockExecutor = Executors.newScheduledThreadPool(offendingHostClearThreadPool);
soumya3e6f05e2016-08-05 15:11:11 -0700351 }
352
sdn94b00152016-08-30 02:12:32 -0700353 /**
354 * Starts monitoring the hosts by IP Address.
sdn94b00152016-08-30 02:12:32 -0700355 */
356 private void startMonitoring() {
357 store.getHosts().forEach(host -> {
Simon Huntffbad3b2017-05-16 15:37:51 -0700358 host.ipAddresses().forEach(ip -> {
359 monitor.addMonitoringFor(ip);
sdn94b00152016-08-30 02:12:32 -0700360 });
361 });
362 }
363
364 /**
365 * Stops monitoring the hosts by IP Address.
sdn94b00152016-08-30 02:12:32 -0700366 */
367 private void stopMonitoring() {
368 store.getHosts().forEach(host -> {
Simon Huntffbad3b2017-05-16 15:37:51 -0700369 host.ipAddresses().forEach(ip -> {
370 monitor.stopMonitoring(ip);
sdn94b00152016-08-30 02:12:32 -0700371 });
372 });
tomdb0d03f2014-08-27 16:34:15 -0700373 }
374
375 @Override
tom5f38b3a2014-08-27 23:50:54 -0700376 protected HostProviderService createProviderService(HostProvider provider) {
Jonathan Hart70da5122014-10-01 16:37:42 -0700377 monitor.registerHostProvider(provider);
tom5f38b3a2014-08-27 23:50:54 -0700378 return new InternalHostProviderService(provider);
tomdb0d03f2014-08-27 16:34:15 -0700379 }
380
tom7869ad92014-09-09 14:32:08 -0700381 @Override
382 public int getHostCount() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900383 checkPermission(HOST_READ);
tom7869ad92014-09-09 14:32:08 -0700384 return store.getHostCount();
385 }
386
387 @Override
388 public Iterable<Host> getHosts() {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900389 checkPermission(HOST_READ);
tom7869ad92014-09-09 14:32:08 -0700390 return store.getHosts();
391 }
392
393 @Override
394 public Host getHost(HostId hostId) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900395 checkPermission(HOST_READ);
tom7869ad92014-09-09 14:32:08 -0700396 checkNotNull(hostId, HOST_ID_NULL);
397 return store.getHost(hostId);
398 }
399
400 @Override
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700401 public Set<Host> getHostsByVlan(VlanId vlanId) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900402 checkPermission(HOST_READ);
tom7869ad92014-09-09 14:32:08 -0700403 return store.getHosts(vlanId);
404 }
405
406 @Override
Ayaka Koshibea9c199f2014-09-16 16:21:40 -0700407 public Set<Host> getHostsByMac(MacAddress mac) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900408 checkPermission(HOST_READ);
tom7869ad92014-09-09 14:32:08 -0700409 checkNotNull(mac, "MAC address cannot be null");
410 return store.getHosts(mac);
411 }
412
413 @Override
Pavlin Radoslavov33f228a2014-10-27 19:33:16 -0700414 public Set<Host> getHostsByIp(IpAddress ip) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900415 checkPermission(HOST_READ);
tom7869ad92014-09-09 14:32:08 -0700416 checkNotNull(ip, "IP address cannot be null");
417 return store.getHosts(ip);
418 }
419
420 @Override
421 public Set<Host> getConnectedHosts(ConnectPoint connectPoint) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900422 checkPermission(HOST_READ);
tom7869ad92014-09-09 14:32:08 -0700423 checkNotNull(connectPoint, "Connection point cannot be null");
424 return store.getConnectedHosts(connectPoint);
425 }
426
427 @Override
428 public Set<Host> getConnectedHosts(DeviceId deviceId) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900429 checkPermission(HOST_READ);
tom7869ad92014-09-09 14:32:08 -0700430 checkNotNull(deviceId, "Device ID cannot be null");
431 return store.getConnectedHosts(deviceId);
432 }
433
434 @Override
Jonathan Hartac60c082014-09-23 08:55:17 -0700435 public void startMonitoringIp(IpAddress ip) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900436 checkPermission(HOST_EVENT);
Jonathan Hart70da5122014-10-01 16:37:42 -0700437 monitor.addMonitoringFor(ip);
Jonathan Hartfca736c2014-09-19 17:26:59 -0700438 }
439
440 @Override
Jonathan Hartac60c082014-09-23 08:55:17 -0700441 public void stopMonitoringIp(IpAddress ip) {
Changhoon Yoonb856b812015-08-10 03:47:19 +0900442 checkPermission(HOST_EVENT);
Jonathan Hart70da5122014-10-01 16:37:42 -0700443 monitor.stopMonitoring(ip);
Jonathan Hartac60c082014-09-23 08:55:17 -0700444 }
445
446 @Override
447 public void requestMac(IpAddress ip) {
Thomas Vachuska42e8cce2015-07-29 19:25:18 -0700448 // FIXME!!!! Auto-generated method stub
tom7869ad92014-09-09 14:32:08 -0700449 }
450
tom89b63c52014-09-16 09:19:51 -0700451 @Override
452 public void removeHost(HostId hostId) {
453 checkNotNull(hostId, HOST_ID_NULL);
Charles Chan009c3082015-11-10 14:18:04 -0800454 store.removeHost(hostId);
tom89b63c52014-09-16 09:19:51 -0700455 }
456
tomdb0d03f2014-08-27 16:34:15 -0700457 // Personalized host provider service issued to the supplied provider.
tom7869ad92014-09-09 14:32:08 -0700458 private class InternalHostProviderService
459 extends AbstractProviderService<HostProvider>
tomdb0d03f2014-08-27 16:34:15 -0700460 implements HostProviderService {
tomcfde0622014-09-09 11:02:42 -0700461 InternalHostProviderService(HostProvider provider) {
tomdb0d03f2014-08-27 16:34:15 -0700462 super(provider);
463 }
464
465 @Override
Ray Milkey718e4382018-12-05 09:08:01 -0800466 public void hostDetected(HostId hostId, HostDescription initialHostDescription, boolean replaceIps) {
467 HostDescription hostDescription = initialHostDescription;
tom7869ad92014-09-09 14:32:08 -0700468 checkNotNull(hostId, HOST_ID_NULL);
469 checkValidity();
Sahil Lele3a0cdd52015-07-21 14:16:31 -0700470 hostDescription = validateHost(hostDescription, hostId);
soumya3e6f05e2016-08-05 15:11:11 -0700471
472 if (!allowDuplicateIps) {
473 removeDuplicates(hostId, hostDescription);
474 }
Rafał Szaleckide5cf842018-11-17 13:30:01 +0100475
476 BasicHostConfig cfg = networkConfigService.getConfig(hostId, BasicHostConfig.class);
477 if (!isAllowed(cfg)) {
478 log.warn("Host {} is not allowed to be added into the contol domain", hostId);
479 return;
480 }
481
Ray Milkey718e4382018-12-05 09:08:01 -0800482 hostDescription = BasicHostOperator.combine(cfg, initialHostDescription);
Rafał Szaleckide5cf842018-11-17 13:30:01 +0100483 HostAnnotationConfig annoConfig = networkConfigService.getConfig(hostId, HostAnnotationConfig.class);
484 if (annoConfig != null) {
485 hostDescription = hostAnnotationOperator.combine(hostId, hostDescription, Optional.of(annoConfig));
486 }
487
jobind19b7142019-05-17 09:46:52 -0400488 if (!hostMoveTrackerEnabled) {
489 store.createOrUpdateHost(provider().id(), hostId,
490 hostDescription, replaceIps);
491 } else if (!shouldBlock(hostId, hostDescription.locations())) {
492 log.debug("Host move is allowed for host with Id: {} ", hostId);
493 store.createOrUpdateHost(provider().id(), hostId,
494 hostDescription, replaceIps);
495 } else {
496 log.info("Host move is NOT allowed for host with Id: {} , removing from host store ", hostId);
497 }
sdn94b00152016-08-30 02:12:32 -0700498
499 if (monitorHosts) {
500 hostDescription.ipAddress().forEach(ip -> {
501 monitor.addMonitoringFor(ip);
502 });
503 }
Pier Luigi9b1d6262017-02-02 22:31:34 -0800504
505 // Greedy learning of IPv6 host. We have to disable the greedy
506 // learning of configured hosts. Validate hosts each time will
Charles Chan82fac582017-09-12 12:09:22 -0700507 // overwrite the learnt information with the configured information.
Pier Luigi9b1d6262017-02-02 22:31:34 -0800508 if (greedyLearningIpv6) {
509 // Auto-generation of the IPv6 link local address
510 // using the mac address
511 Ip6Address targetIp6Address = Ip6Address.valueOf(
512 getLinkLocalAddress(hostId.mac().toBytes())
513 );
514 // If we already know this guy we don't need to do other
515 if (!hostDescription.ipAddress().contains(targetIp6Address)) {
516 Host host = store.getHost(hostId);
517 // Configured host, skip it.
518 if (host != null && host.configured()) {
519 return;
520 }
521 // Host does not exist in the store or the target is not known
522 if ((host == null || !host.ipAddresses().contains(targetIp6Address))) {
Charles Chan82fac582017-09-12 12:09:22 -0700523 // Use DAD to probe if interface MAC is not specified
524 MacAddress probeMac = interfaceService.getInterfacesByPort(hostDescription.location())
525 .stream().map(Interface::mac).findFirst().orElse(MacAddress.ONOS);
526 Ip6Address probeIp = !probeMac.equals(MacAddress.ONOS) ?
527 Ip6Address.valueOf(getLinkLocalAddress(probeMac.toBytes())) :
528 Ip6Address.ZERO;
Pier Luigi9b1d6262017-02-02 22:31:34 -0800529 // We send a probe using the monitoring service
530 monitor.sendProbe(
531 hostDescription.location(),
532 targetIp6Address,
Charles Chan82fac582017-09-12 12:09:22 -0700533 probeIp,
534 probeMac,
Pier Luigi9b1d6262017-02-02 22:31:34 -0800535 hostId.vlanId()
536 );
537 }
538 }
539 }
tomdb0d03f2014-08-27 16:34:15 -0700540 }
541
soumya3e6f05e2016-08-05 15:11:11 -0700542 // When a new IP is detected, remove that IP on other hosts if it exists
543 public void removeDuplicates(HostId hostId, HostDescription desc) {
544 desc.ipAddress().forEach(ip -> {
545 Set<Host> allHosts = store.getHosts(ip);
546 allHosts.forEach(eachHost -> {
547 if (!(eachHost.id().equals(hostId))) {
548 log.info("Duplicate ip {} found on host {} and {}", ip,
jobind19b7142019-05-17 09:46:52 -0400549 hostId.toString(), eachHost.id().toString());
soumya3e6f05e2016-08-05 15:11:11 -0700550 store.removeIp(eachHost.id(), ip);
551 }
552 });
553 });
Jonathan Hart38feb6e2016-08-29 22:54:16 +0000554 }
555
Sahil Lele3a0cdd52015-07-21 14:16:31 -0700556 // returns a HostDescription made from the union of the BasicHostConfig
557 // annotations if it exists
558 private HostDescription validateHost(HostDescription hostDescription, HostId hostId) {
559 BasicHostConfig cfg = networkConfigService.getConfig(hostId, BasicHostConfig.class);
560 checkState(cfg == null || cfg.isAllowed(), "Host {} is not allowed", hostId);
Ayaka Koshibe5373e762015-08-06 12:31:44 -0700561
562 return BasicHostOperator.combine(cfg, hostDescription);
Sahil Lele3a0cdd52015-07-21 14:16:31 -0700563 }
564
tomdb0d03f2014-08-27 16:34:15 -0700565 @Override
tom7869ad92014-09-09 14:32:08 -0700566 public void hostVanished(HostId hostId) {
567 checkNotNull(hostId, HOST_ID_NULL);
568 checkValidity();
sdn94b00152016-08-30 02:12:32 -0700569 Host host = store.getHost(hostId);
Charles Chan29ecdee2017-02-22 18:46:56 -0800570
Charles Chan888e20a2017-05-01 15:44:23 -0700571 if (!allowedToChange(hostId)) {
572 log.info("Request to remove {} is ignored due to provider mismatch", hostId);
Charles Chan29ecdee2017-02-22 18:46:56 -0800573 return;
574 }
575
sdn94b00152016-08-30 02:12:32 -0700576 if (monitorHosts) {
577 host.ipAddresses().forEach(ip -> {
578 monitor.stopMonitoring(ip);
579 });
580 }
Charles Chan009c3082015-11-10 14:18:04 -0800581 store.removeHost(hostId);
tomdb0d03f2014-08-27 16:34:15 -0700582 }
samanwita palc40e5ed2015-09-24 11:01:51 -0700583
584 @Override
585 public void removeIpFromHost(HostId hostId, IpAddress ipAddress) {
586 checkNotNull(hostId, HOST_ID_NULL);
587 checkValidity();
Charles Chan888e20a2017-05-01 15:44:23 -0700588
589 if (!allowedToChange(hostId)) {
590 log.info("Request to remove {} from {} is ignored due to provider mismatch",
591 ipAddress, hostId);
592 return;
593 }
594
Charles Chan009c3082015-11-10 14:18:04 -0800595 store.removeIp(hostId, ipAddress);
samanwita palc40e5ed2015-09-24 11:01:51 -0700596 }
Charles Chan888e20a2017-05-01 15:44:23 -0700597
598 @Override
Charles Chanff79dd92018-06-01 16:33:48 -0700599 public void addLocationToHost(HostId hostId, HostLocation location) {
600 checkNotNull(hostId, HOST_ID_NULL);
601 checkValidity();
602
603 if (!allowedToChange(hostId)) {
Charles Chanb928b3f2018-07-23 15:37:08 -0700604 log.info("Request to add {} to {} is ignored due to provider mismatch",
Charles Chanff79dd92018-06-01 16:33:48 -0700605 location, hostId);
606 return;
607 }
608
609 store.appendLocation(hostId, location);
610 }
611
612 @Override
Charles Chan888e20a2017-05-01 15:44:23 -0700613 public void removeLocationFromHost(HostId hostId, HostLocation location) {
614 checkNotNull(hostId, HOST_ID_NULL);
615 checkValidity();
616
617 if (!allowedToChange(hostId)) {
618 log.info("Request to remove {} from {} is ignored due to provider mismatch",
619 location, hostId);
620 return;
621 }
622
623 store.removeLocation(hostId, location);
624 }
625
Charles Chand0c147a2017-09-14 14:00:10 -0700626 /**
627 * Providers should only be able to remove a host that is provided by itself,
628 * or a host that is not configured.
629 */
Charles Chan888e20a2017-05-01 15:44:23 -0700630 private boolean allowedToChange(HostId hostId) {
Charles Chan888e20a2017-05-01 15:44:23 -0700631 Host host = store.getHost(hostId);
Charles Chand0c147a2017-09-14 14:00:10 -0700632 return host == null || !host.configured() || host.providerId().equals(provider().id());
Charles Chan888e20a2017-05-01 15:44:23 -0700633 }
jobind19b7142019-05-17 09:46:52 -0400634
635
636 /**
637 * Deny host move if happening within the threshold time,
638 * track moved host to identify offending hosts.
639 *
640 * @param hostId host identifier
641 * @param locations host locations
642 */
643 private boolean shouldBlock(HostId hostId, Set<HostLocation> locations) {
644 Host host = store.getHost(hostId);
645 // If host is not present in host store means host added for hte first time.
646 if (host != null) {
647 if (host.suspended()) {
648 // Checks host is marked as offending in other onos cluster instance/local instance
649 log.debug("Host id {} is moving frequently hence host moving " +
650 "processing is ignored", hostId);
651 return true;
652 }
653 } else {
654 //host added for the first time.
655 return false;
656 }
657 HostMoveTracker hostMove = hostMoveTracker.computeIfAbsent(hostId, id -> new HostMoveTracker(locations));
658 if (Sets.difference(hostMove.getLocations(), locations).isEmpty() &&
659 Sets.difference(locations, hostMove.getLocations()).isEmpty()) {
660 log.debug("Not hostmove scenario: Host id: {}, Old Host Location: {}, New host Location: {}",
661 hostId, hostMove.getLocations(), locations);
662 return false; // It is not a host move scenario
663 } else if (hostMove.getCounter() >= hostMoveCounter && System.currentTimeMillis() - hostMove.getTimeStamp()
664 < hostMoveThresholdInMillis) {
665 //Check host move is crossed the threshold, then to mark as offending Host
666 log.debug("Host id {} is identified as offending host and entry is added in cache", hostId);
667 hostMove.resetHostMoveTracker(locations);
668 store.suspend(hostId);
669 //Set host suspended flag to false after given offendingHostExpiryInMins
670 offendingHostUnblockExecutor.schedule(new UnblockOffendingHost(hostId),
671 offendingHostExpiryInMins,
672 TimeUnit.MINUTES);
673 return true;
674 } else if (System.currentTimeMillis() - hostMove.getTimeStamp()
675 < hostMoveThresholdInMillis) {
676 //Increment the host move count as hostmove occured within the hostMoveThresholdInMillis time
677 hostMove.updateHostMoveTracker(locations);
678 log.debug("Updated the tracker with the host move registered for host: {}", hostId);
679 } else if (System.currentTimeMillis() - hostMove.getTimeStamp()
680 > hostMoveThresholdInMillis) {
681 //Hostmove is happened after hostMoveThresholdInMillis time so remove from host tracker.
682 hostMove.resetHostMoveTracker(locations);
683 store.unsuspend(hostId);
684 log.debug("Reset the tracker with the host move registered for host: {}", hostId);
685 }
686 return false;
687 }
688
689 // Set host suspended flag to false after given offendingHostExpiryInMins.
690 private final class UnblockOffendingHost implements Runnable {
691 private HostId hostId;
692
693 UnblockOffendingHost(HostId hostId) {
694 this.hostId = hostId;
695 }
696
697 @Override
698 public void run() {
699 // Set the host suspended flag to false
700 try {
701 store.unsuspend(hostId);
702 log.debug("Host {}: Marked host as unsuspended", hostId);
703 } catch (Exception ex) {
704 log.debug("Host {}: not present in host list", hostId);
705 }
706 }
707 }
tomdb0d03f2014-08-27 16:34:15 -0700708 }
tom7869ad92014-09-09 14:32:08 -0700709
jobind19b7142019-05-17 09:46:52 -0400710
tomc78acee2014-09-24 15:16:55 -0700711 // Store delegate to re-post events emitted from the store.
712 private class InternalStoreDelegate implements HostStoreDelegate {
713 @Override
714 public void notify(HostEvent event) {
715 post(event);
716 }
717 }
Sahil Lele3a0cdd52015-07-21 14:16:31 -0700718
719 // listens for NetworkConfigEvents of type BasicHostConfig and removes
720 // links that the config does not allow
721 private class InternalNetworkConfigListener implements NetworkConfigListener {
722 @Override
Simon Huntffbad3b2017-05-16 15:37:51 -0700723 public boolean isRelevant(NetworkConfigEvent event) {
724 return (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED
725 || event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED)
Rafał Szaleckide5cf842018-11-17 13:30:01 +0100726 && (event.configClass().equals(BasicHostConfig.class)
727 || event.configClass().equals(HostAnnotationConfig.class));
Simon Huntffbad3b2017-05-16 15:37:51 -0700728 }
729
730 @Override
Sahil Lele3a0cdd52015-07-21 14:16:31 -0700731 public void event(NetworkConfigEvent event) {
Simon Huntffbad3b2017-05-16 15:37:51 -0700732 log.debug("Detected host network config event {}", event.type());
733 HostEvent he = null;
734
735 HostId hostId = (HostId) event.subject();
736 BasicHostConfig cfg =
737 networkConfigService.getConfig(hostId, BasicHostConfig.class);
738
739 if (!isAllowed(cfg)) {
740 kickOutBadHost(hostId);
Rafał Szaleckide5cf842018-11-17 13:30:01 +0100741 } else if (event.configClass().equals(BasicHostConfig.class)) {
Simon Huntffbad3b2017-05-16 15:37:51 -0700742 Host host = getHost(hostId);
743 HostDescription desc =
744 (host == null) ? null : BasicHostOperator.descriptionOf(host);
745 desc = BasicHostOperator.combine(cfg, desc);
746 if (desc != null) {
747 he = store.createOrUpdateHost(host.providerId(), hostId, desc, false);
748 }
Rafał Szaleckide5cf842018-11-17 13:30:01 +0100749 } else if (event.configClass().equals(HostAnnotationConfig.class)) {
750 Host host = getHost(hostId);
Ray Milkey718e4382018-12-05 09:08:01 -0800751 HostProvider hp = (host == null) ? null : getProvider(host.providerId());
Rafał Szaleckide5cf842018-11-17 13:30:01 +0100752 HostDescription desc = (host == null) ? null : BasicHostOperator.descriptionOf(host);
753 Optional<Config> prevConfig = event.prevConfig();
754 log.debug("Host annotations: {} prevconfig {} desc {}", hostId, prevConfig, desc);
755 desc = hostAnnotationOperator.combine(hostId, desc, prevConfig);
756 if (desc != null && hp != null) {
757 log.debug("Host annotations update - updated host description :{}", desc.toString());
758 he = store.createOrUpdateHost(hp.id(), hostId, desc, false);
759 if (he != null && he.subject() != null) {
760 log.debug("Host annotations update - Host Event : {}", he.subject().annotations());
761 }
762 }
Simon Huntffbad3b2017-05-16 15:37:51 -0700763 }
764
765 if (he != null) {
766 post(he);
Sahil Lele3a0cdd52015-07-21 14:16:31 -0700767 }
768 }
769 }
770
Simon Huntffbad3b2017-05-16 15:37:51 -0700771 // by default allowed, otherwise check flag
772 private boolean isAllowed(BasicHostConfig cfg) {
773 return (cfg == null || cfg.isAllowed());
774 }
775
776 // removes the specified host, if it exists
Sahil Lele3a0cdd52015-07-21 14:16:31 -0700777 private void kickOutBadHost(HostId hostId) {
Simon Huntffbad3b2017-05-16 15:37:51 -0700778 Host badHost = getHost(hostId);
779 if (badHost != null) {
780 removeHost(hostId);
Sahil Lele3a0cdd52015-07-21 14:16:31 -0700781 }
782 }
tomdb0d03f2014-08-27 16:34:15 -0700783}