blob: 3ea56af6726c57e268c6945d2b1b312574db8cb0 [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2015-present Open Networking Foundation
Thomas Vachuska781d18b2014-10-27 10:31:25 -07003 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07004 * 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
Thomas Vachuska781d18b2014-10-27 10:31:25 -07007 *
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07008 * 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.
Thomas Vachuska781d18b2014-10-27 10:31:25 -070015 */
Brian O'Connorabafb502014-12-02 22:26:20 -080016package org.onosproject.provider.lldp.impl;
alshabib7911a052014-10-16 17:49:37 -070017
Ray Milkeyd9bbde82016-06-09 11:35:00 -070018import java.util.Dictionary;
19import java.util.EnumSet;
Jon Hall125c3f22017-08-09 13:46:28 -070020import java.util.LinkedList;
21import java.util.List;
Ray Milkeyd9bbde82016-06-09 11:35:00 -070022import java.util.Map;
23import java.util.Optional;
24import java.util.Properties;
25import java.util.Set;
26import java.util.concurrent.ConcurrentHashMap;
27import java.util.concurrent.ExecutorService;
28import java.util.concurrent.ScheduledExecutorService;
29
alshabib7911a052014-10-16 17:49:37 -070030import org.apache.felix.scr.annotations.Activate;
31import org.apache.felix.scr.annotations.Component;
32import org.apache.felix.scr.annotations.Deactivate;
Yuta HIGUCHI41289382014-12-19 17:47:12 -080033import org.apache.felix.scr.annotations.Modified;
34import org.apache.felix.scr.annotations.Property;
alshabib7911a052014-10-16 17:49:37 -070035import org.apache.felix.scr.annotations.Reference;
36import org.apache.felix.scr.annotations.ReferenceCardinality;
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080037import org.onlab.packet.Ethernet;
Thomas Vachuska6519e6f2015-03-11 02:29:31 -070038import org.onosproject.cfg.ComponentConfigService;
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080039import org.onosproject.cluster.ClusterMetadataService;
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -070040import org.onosproject.cluster.ClusterService;
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080041import org.onosproject.core.ApplicationId;
42import org.onosproject.core.CoreService;
Brian O'Connorabafb502014-12-02 22:26:20 -080043import org.onosproject.mastership.MastershipEvent;
44import org.onosproject.mastership.MastershipListener;
45import org.onosproject.mastership.MastershipService;
46import org.onosproject.net.ConnectPoint;
47import org.onosproject.net.Device;
48import org.onosproject.net.DeviceId;
Thomas Vachuskae4ebac92015-09-10 11:39:05 -070049import org.onosproject.net.LinkKey;
Brian O'Connorabafb502014-12-02 22:26:20 -080050import org.onosproject.net.Port;
Naoki Shiota399a0b32015-11-15 20:36:13 -060051import org.onosproject.net.config.ConfigFactory;
52import org.onosproject.net.config.NetworkConfigEvent;
53import org.onosproject.net.config.NetworkConfigListener;
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -070054import org.onosproject.net.config.NetworkConfigRegistry;
Brian O'Connorabafb502014-12-02 22:26:20 -080055import org.onosproject.net.device.DeviceEvent;
HIGUCHI Yuta1979f552015-12-28 21:24:26 -080056import org.onosproject.net.device.DeviceEvent.Type;
Brian O'Connorabafb502014-12-02 22:26:20 -080057import org.onosproject.net.device.DeviceListener;
58import org.onosproject.net.device.DeviceService;
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080059import org.onosproject.net.flow.DefaultTrafficSelector;
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080060import org.onosproject.net.flow.TrafficSelector;
Thomas Vachuskae4ebac92015-09-10 11:39:05 -070061import org.onosproject.net.link.DefaultLinkDescription;
Brian O'Connorabafb502014-12-02 22:26:20 -080062import org.onosproject.net.link.LinkProviderRegistry;
63import org.onosproject.net.link.LinkProviderService;
Thomas Vachuskae4ebac92015-09-10 11:39:05 -070064import org.onosproject.net.link.LinkService;
Ray Milkeyd9bbde82016-06-09 11:35:00 -070065import org.onosproject.net.link.ProbedLinkProvider;
Brian O'Connorabafb502014-12-02 22:26:20 -080066import org.onosproject.net.packet.PacketContext;
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080067import org.onosproject.net.packet.PacketPriority;
Brian O'Connorabafb502014-12-02 22:26:20 -080068import org.onosproject.net.packet.PacketProcessor;
69import org.onosproject.net.packet.PacketService;
70import org.onosproject.net.provider.AbstractProvider;
71import org.onosproject.net.provider.ProviderId;
Ray Milkey957390e2016-02-09 10:02:46 -080072import org.onosproject.provider.lldpcommon.LinkDiscovery;
Ray Milkeyd9bbde82016-06-09 11:35:00 -070073import org.onosproject.provider.lldpcommon.LinkDiscoveryContext;
Yuta HIGUCHI41289382014-12-19 17:47:12 -080074import org.osgi.service.component.ComponentContext;
alshabib7911a052014-10-16 17:49:37 -070075import org.slf4j.Logger;
76
Ray Milkeyd9bbde82016-06-09 11:35:00 -070077import com.google.common.collect.ImmutableMap;
78import com.google.common.collect.ImmutableSet;
79import com.google.common.collect.Maps;
Marc De Leenheer0bfc2a12016-02-02 22:46:27 -080080
81import static com.google.common.base.Strings.isNullOrEmpty;
82import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
83import static java.util.concurrent.TimeUnit.SECONDS;
84import static org.onlab.packet.Ethernet.TYPE_BSN;
85import static org.onlab.packet.Ethernet.TYPE_LLDP;
86import static org.onlab.util.Tools.get;
87import static org.onlab.util.Tools.groupedThreads;
Marc De Leenheer0bfc2a12016-02-02 22:46:27 -080088import static org.onosproject.net.Link.Type.DIRECT;
89import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
90import static org.onosproject.net.config.basics.SubjectFactories.CONNECT_POINT_SUBJECT_FACTORY;
91import static org.onosproject.net.config.basics.SubjectFactories.DEVICE_SUBJECT_FACTORY;
92import static org.slf4j.LoggerFactory.getLogger;
Yuta HIGUCHI41289382014-12-19 17:47:12 -080093
alshabib7911a052014-10-16 17:49:37 -070094/**
Thomas Vachuska05453c92015-09-09 14:40:49 -070095 * Provider which uses LLDP and BDDP packets to detect network infrastructure links.
alshabib7911a052014-10-16 17:49:37 -070096 */
97@Component(immediate = true)
Ayaka Koshibe48229222016-05-16 18:04:26 -070098public class LldpLinkProvider extends AbstractProvider implements ProbedLinkProvider {
alshabib7911a052014-10-16 17:49:37 -070099
Thomas Vachuskafc52fec2015-05-18 19:13:56 -0700100 private static final String PROVIDER_NAME = "org.onosproject.provider.lldp";
101
Thomas Vachuska05453c92015-09-09 14:40:49 -0700102 private static final String FORMAT =
103 "Settings: enabled={}, useBDDP={}, probeRate={}, " +
Samuel Jero31e16f52018-09-21 10:34:28 -0400104 "staleLinkAge={}, maxLLDPage={}";
Yuta HIGUCHI41289382014-12-19 17:47:12 -0800105
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700106 // When a Device/Port has this annotation, do not send out LLDP/BDDP
107 public static final String NO_LLDP = "no-lldp";
108
Thomas Vachuskaaad8b1d2015-12-11 10:36:53 -0800109 private static final int MAX_RETRIES = 5;
110 private static final int RETRY_DELAY = 1_000; // millis
111
alshabib7911a052014-10-16 17:49:37 -0700112 private final Logger log = getLogger(getClass());
113
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected CoreService coreService;
116
117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabib7911a052014-10-16 17:49:37 -0700118 protected LinkProviderRegistry providerRegistry;
119
120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
121 protected DeviceService deviceService;
122
123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700124 protected LinkService linkService;
125
126 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Marc De Leenheer8b3e80b2015-03-06 14:27:03 -0800127 protected PacketService packetService;
alshabib7911a052014-10-16 17:49:37 -0700128
alshabib875d6262014-10-17 16:19:40 -0700129 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
130 protected MastershipService masterService;
131
Thomas Vachuska6519e6f2015-03-11 02:29:31 -0700132 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
133 protected ComponentConfigService cfgService;
134
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700135 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
136 protected ClusterService clusterService;
137
138 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
139 protected NetworkConfigRegistry cfgRegistry;
140
Ayaka Koshibe12c8c082015-12-08 12:48:46 -0800141 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
142 protected ClusterMetadataService clusterMetadataService;
143
alshabib7911a052014-10-16 17:49:37 -0700144 private LinkProviderService providerService;
145
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800146 private ScheduledExecutorService executor;
Ray Milkeyd9bbde82016-06-09 11:35:00 -0700147 protected ExecutorService eventExecutor;
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800148
Ray Milkeye80e18f2016-06-02 16:44:14 -0700149 private boolean shuttingDown = false;
150
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700151 // TODO: Add sanity checking for the configurable params based on the delays
152 private static final long DEVICE_SYNC_DELAY = 5;
153 private static final long LINK_PRUNER_DELAY = 3;
Thomas Vachuska05453c92015-09-09 14:40:49 -0700154
155 private static final String PROP_ENABLED = "enabled";
156 @Property(name = PROP_ENABLED, boolValue = true,
157 label = "If false, link discovery is disabled")
158 private boolean enabled = false;
159
160 private static final String PROP_USE_BDDP = "useBDDP";
Thomas Vachuska6519e6f2015-03-11 02:29:31 -0700161 @Property(name = PROP_USE_BDDP, boolValue = true,
162 label = "Use BDDP for link discovery")
Jonathan Hartb35540a2015-11-17 09:30:56 -0800163 private boolean useBddp = true;
alshabib7911a052014-10-16 17:49:37 -0700164
Thomas Vachuska05453c92015-09-09 14:40:49 -0700165 private static final String PROP_PROBE_RATE = "probeRate";
Thomas Vachuska9e51fd02016-01-04 16:51:28 -0800166 private static final int DEFAULT_PROBE_RATE = 3000;
Thomas Vachuska05453c92015-09-09 14:40:49 -0700167 @Property(name = PROP_PROBE_RATE, intValue = DEFAULT_PROBE_RATE,
168 label = "LLDP and BDDP probe rate specified in millis")
169 private int probeRate = DEFAULT_PROBE_RATE;
Saurav Dasc313c402015-02-27 10:09:47 -0800170
Thomas Vachuska05453c92015-09-09 14:40:49 -0700171 private static final String PROP_STALE_LINK_AGE = "staleLinkAge";
Thomas Vachuska9e51fd02016-01-04 16:51:28 -0800172 private static final int DEFAULT_STALE_LINK_AGE = 10000;
Thomas Vachuska05453c92015-09-09 14:40:49 -0700173 @Property(name = PROP_STALE_LINK_AGE, intValue = DEFAULT_STALE_LINK_AGE,
174 label = "Number of millis beyond which links will be considered stale")
175 private int staleLinkAge = DEFAULT_STALE_LINK_AGE;
alshabib7911a052014-10-16 17:49:37 -0700176
Samuel Jero31e16f52018-09-21 10:34:28 -0400177 private static final String PROP_DISCOVERY_DELAY = "maxLLDPAge";
178 private static final int DEFAULT_DISCOVERY_DELAY = 1000;
179 @Property(name = PROP_DISCOVERY_DELAY, intValue = DEFAULT_DISCOVERY_DELAY,
180 label = "Number of millis beyond which an LLDP packet will not be accepted")
181 private int maxDiscoveryDelayMs = DEFAULT_DISCOVERY_DELAY;
182
Ray Milkey957390e2016-02-09 10:02:46 -0800183 private final LinkDiscoveryContext context = new InternalDiscoveryContext();
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800184 private final InternalRoleListener roleListener = new InternalRoleListener();
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700185 private final InternalDeviceListener deviceListener = new InternalDeviceListener();
186 private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800187
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700188 // Device link discovery helpers.
alshabib7911a052014-10-16 17:49:37 -0700189 protected final Map<DeviceId, LinkDiscovery> discoverers = new ConcurrentHashMap<>();
190
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700191 // Most recent time a tracked link was seen; links are tracked if their
192 // destination connection point is mastered by this controller instance.
193 private final Map<LinkKey, Long> linkTimes = Maps.newConcurrentMap();
194
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800195 private ApplicationId appId;
Yuta HIGUCHI41289382014-12-19 17:47:12 -0800196
Naoki Shiota399a0b32015-11-15 20:36:13 -0600197 static final SuppressionRules DEFAULT_RULES
Yuta HIGUCHI09697d02017-03-03 16:53:39 -0800198 = new SuppressionRules(EnumSet.of(Device.Type.ROADM,
199 Device.Type.FIBER_SWITCH,
200 Device.Type.OPTICAL_AMPLIFIER,
201 Device.Type.OTN),
Naoki Shiota399a0b32015-11-15 20:36:13 -0600202 ImmutableMap.of(NO_LLDP, SuppressionRules.ANY_VALUE));
203
204 private SuppressionRules rules = LldpLinkProvider.DEFAULT_RULES;
205
206 public static final String CONFIG_KEY = "suppression";
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800207 public static final String FEATURE_NAME = "linkDiscovery";
Naoki Shiota399a0b32015-11-15 20:36:13 -0600208
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800209 private final Set<ConfigFactory<?, ?>> factories = ImmutableSet.of(
Naoki Shiota399a0b32015-11-15 20:36:13 -0600210 new ConfigFactory<ApplicationId, SuppressionConfig>(APP_SUBJECT_FACTORY,
211 SuppressionConfig.class,
212 CONFIG_KEY) {
213 @Override
214 public SuppressionConfig createConfig() {
215 return new SuppressionConfig();
216 }
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800217 },
218 new ConfigFactory<DeviceId, LinkDiscoveryFromDevice>(DEVICE_SUBJECT_FACTORY,
219 LinkDiscoveryFromDevice.class, FEATURE_NAME) {
220 @Override
221 public LinkDiscoveryFromDevice createConfig() {
222 return new LinkDiscoveryFromDevice();
223 }
224 },
225 new ConfigFactory<ConnectPoint, LinkDiscoveryFromPort>(CONNECT_POINT_SUBJECT_FACTORY,
226 LinkDiscoveryFromPort.class, FEATURE_NAME) {
227 @Override
228 public LinkDiscoveryFromPort createConfig() {
229 return new LinkDiscoveryFromPort();
230 }
Naoki Shiota399a0b32015-11-15 20:36:13 -0600231 }
232 );
233
234 private final InternalConfigListener cfgListener = new InternalConfigListener();
235
alshabib7911a052014-10-16 17:49:37 -0700236 /**
237 * Creates an OpenFlow link provider.
238 */
Jonathan Hartb35540a2015-11-17 09:30:56 -0800239 public LldpLinkProvider() {
Thomas Vachuskafc52fec2015-05-18 19:13:56 -0700240 super(new ProviderId("lldp", PROVIDER_NAME));
alshabib7911a052014-10-16 17:49:37 -0700241 }
242
Sho SHIMIZU9efeb812016-08-18 09:29:20 -0700243 private String buildSrcMac() {
Ayaka Koshibe48229222016-05-16 18:04:26 -0700244 String defMac = ProbedLinkProvider.defaultMac();
Ray Milkey55f513f2017-12-01 15:58:21 -0800245 if (clusterMetadataService == null) {
246 log.debug("No cluster metadata service is available. Using default value {}", defMac);
247 return defMac;
248 }
249
250 String srcMac = ProbedLinkProvider.fingerprintMac(clusterMetadataService.getClusterMetadata());
Ayaka Koshibe48229222016-05-16 18:04:26 -0700251 if (srcMac.equals(defMac)) {
252 log.warn("Couldn't generate fingerprint. Using default value {}", defMac);
253 return defMac;
254 }
255 log.trace("Generated MAC address {}", srcMac);
256 return srcMac;
257 }
258
alshabib7911a052014-10-16 17:49:37 -0700259 @Activate
Saurav Dasc313c402015-02-27 10:09:47 -0800260 public void activate(ComponentContext context) {
Ray Milkeyd9bbde82016-06-09 11:35:00 -0700261 eventExecutor = newSingleThreadScheduledExecutor(groupedThreads("onos/linkevents", "events-%d", log));
Ray Milkeye80e18f2016-06-02 16:44:14 -0700262 shuttingDown = false;
Thomas Vachuska6519e6f2015-03-11 02:29:31 -0700263 cfgService.registerProperties(getClass());
Thomas Vachuskafc52fec2015-05-18 19:13:56 -0700264 appId = coreService.registerApplication(PROVIDER_NAME);
Naoki Shiota399a0b32015-11-15 20:36:13 -0600265
266 cfgRegistry.addListener(cfgListener);
267 factories.forEach(cfgRegistry::registerConfigFactory);
268
Madan Jampanic6371882016-06-03 21:30:17 -0700269 SuppressionConfig cfg = cfgRegistry.getConfig(appId, SuppressionConfig.class);
Naoki Shiota399a0b32015-11-15 20:36:13 -0600270 if (cfg == null) {
271 // If no configuration is found, register default.
Madan Jampanic6371882016-06-03 21:30:17 -0700272 cfg = this.setDefaultSuppressionConfig();
Naoki Shiota399a0b32015-11-15 20:36:13 -0600273 }
274 cfgListener.reconfigureSuppressionRules(cfg);
275
Saurav Dasc313c402015-02-27 10:09:47 -0800276 modified(context);
Thomas Vachuska05453c92015-09-09 14:40:49 -0700277 log.info("Started");
278 }
279
Thomas Vachuskaaad8b1d2015-12-11 10:36:53 -0800280 private SuppressionConfig setDefaultSuppressionConfig() {
281 SuppressionConfig cfg = cfgRegistry.addConfig(appId, SuppressionConfig.class);
282 cfg.deviceTypes(DEFAULT_RULES.getSuppressedDeviceType())
283 .annotation(DEFAULT_RULES.getSuppressedAnnotation())
284 .apply();
285 return cfg;
286 }
287
Thomas Vachuska05453c92015-09-09 14:40:49 -0700288 @Deactivate
289 public void deactivate() {
Ray Milkeye80e18f2016-06-02 16:44:14 -0700290 shuttingDown = true;
Naoki Shiota399a0b32015-11-15 20:36:13 -0600291 cfgRegistry.removeListener(cfgListener);
292 factories.forEach(cfgRegistry::unregisterConfigFactory);
293
Thomas Vachuska05453c92015-09-09 14:40:49 -0700294 cfgService.unregisterProperties(getClass(), false);
295 disable();
Ray Milkeyd9bbde82016-06-09 11:35:00 -0700296 eventExecutor.shutdownNow();
297 eventExecutor = null;
Thomas Vachuska05453c92015-09-09 14:40:49 -0700298 log.info("Stopped");
299 }
300
301 @Modified
302 public void modified(ComponentContext context) {
303 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
304
305 boolean newEnabled, newUseBddp;
Samuel Jero31e16f52018-09-21 10:34:28 -0400306 int newProbeRate, newStaleLinkAge, newDiscoveryDelay;
Thomas Vachuska05453c92015-09-09 14:40:49 -0700307 try {
308 String s = get(properties, PROP_ENABLED);
309 newEnabled = isNullOrEmpty(s) || Boolean.parseBoolean(s.trim());
310
311 s = get(properties, PROP_USE_BDDP);
312 newUseBddp = isNullOrEmpty(s) || Boolean.parseBoolean(s.trim());
313
314 s = get(properties, PROP_PROBE_RATE);
315 newProbeRate = isNullOrEmpty(s) ? probeRate : Integer.parseInt(s.trim());
316
317 s = get(properties, PROP_STALE_LINK_AGE);
318 newStaleLinkAge = isNullOrEmpty(s) ? staleLinkAge : Integer.parseInt(s.trim());
319
Samuel Jero31e16f52018-09-21 10:34:28 -0400320 s = get(properties, PROP_DISCOVERY_DELAY);
321 newDiscoveryDelay = isNullOrEmpty(s) ? maxDiscoveryDelayMs : Integer.parseInt(s.trim());
322
Thomas Vachuska05453c92015-09-09 14:40:49 -0700323 } catch (NumberFormatException e) {
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700324 log.warn("Component configuration had invalid values", e);
Thomas Vachuska05453c92015-09-09 14:40:49 -0700325 newEnabled = enabled;
Jonathan Hartb35540a2015-11-17 09:30:56 -0800326 newUseBddp = useBddp;
Thomas Vachuska05453c92015-09-09 14:40:49 -0700327 newProbeRate = probeRate;
328 newStaleLinkAge = staleLinkAge;
Samuel Jero31e16f52018-09-21 10:34:28 -0400329 newDiscoveryDelay = maxDiscoveryDelayMs;
Saurav Dasc313c402015-02-27 10:09:47 -0800330 }
Yuta HIGUCHI41289382014-12-19 17:47:12 -0800331
Thomas Vachuska05453c92015-09-09 14:40:49 -0700332 boolean wasEnabled = enabled;
333
334 enabled = newEnabled;
Jonathan Hartb35540a2015-11-17 09:30:56 -0800335 useBddp = newUseBddp;
Thomas Vachuska05453c92015-09-09 14:40:49 -0700336 probeRate = newProbeRate;
337 staleLinkAge = newStaleLinkAge;
Samuel Jero31e16f52018-09-21 10:34:28 -0400338 maxDiscoveryDelayMs = newDiscoveryDelay;
Thomas Vachuska05453c92015-09-09 14:40:49 -0700339
340 if (!wasEnabled && enabled) {
341 enable();
342 } else if (wasEnabled && !enabled) {
343 disable();
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700344 } else {
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700345 if (enabled) {
346 // update all discovery helper state
347 loadDevices();
348 }
Thomas Vachuska05453c92015-09-09 14:40:49 -0700349 }
350
Samuel Jero31e16f52018-09-21 10:34:28 -0400351 log.info(FORMAT, enabled, useBddp, probeRate, staleLinkAge, maxDiscoveryDelayMs);
Thomas Vachuska05453c92015-09-09 14:40:49 -0700352 }
353
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700354 /**
355 * Enables link discovery processing.
356 */
Thomas Vachuska05453c92015-09-09 14:40:49 -0700357 private void enable() {
alshabib7911a052014-10-16 17:49:37 -0700358 providerService = providerRegistry.register(this);
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800359 masterService.addListener(roleListener);
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700360 deviceService.addListener(deviceListener);
361 packetService.addProcessor(packetProcessor, PacketProcessor.advisor(0));
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800362
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700363 loadDevices();
Thomas Vachuska05453c92015-09-09 14:40:49 -0700364
HIGUCHI Yutad9e01052016-04-14 09:31:42 -0700365 executor = newSingleThreadScheduledExecutor(groupedThreads("onos/link", "discovery-%d", log));
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700366 executor.scheduleAtFixedRate(new SyncDeviceInfoTask(),
367 DEVICE_SYNC_DELAY, DEVICE_SYNC_DELAY, SECONDS);
368 executor.scheduleAtFixedRate(new LinkPrunerTask(),
369 LINK_PRUNER_DELAY, LINK_PRUNER_DELAY, SECONDS);
Thomas Vachuska05453c92015-09-09 14:40:49 -0700370
Thomas Vachuska05453c92015-09-09 14:40:49 -0700371 requestIntercepts();
372 }
373
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700374 /**
375 * Disables link discovery processing.
376 */
Thomas Vachuska05453c92015-09-09 14:40:49 -0700377 private void disable() {
378 withdrawIntercepts();
379
380 providerRegistry.unregister(this);
Thomas Vachuska05453c92015-09-09 14:40:49 -0700381 masterService.removeListener(roleListener);
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700382 deviceService.removeListener(deviceListener);
383 packetService.removeProcessor(packetProcessor);
Thomas Vachuska05453c92015-09-09 14:40:49 -0700384
385 if (executor != null) {
386 executor.shutdownNow();
387 }
388 discoverers.values().forEach(LinkDiscovery::stop);
389 discoverers.clear();
Jon Hall125c3f22017-08-09 13:46:28 -0700390 linkTimes.clear();
Thomas Vachuska05453c92015-09-09 14:40:49 -0700391
392 providerService = null;
393 }
394
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700395 /**
396 * Loads available devices and registers their ports to be probed.
397 */
398 private void loadDevices() {
Ray Milkey0f87d482016-07-06 11:49:19 -0700399 if (!enabled || deviceService == null) {
Naoki Shiota399a0b32015-11-15 20:36:13 -0600400 return;
401 }
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700402 deviceService.getAvailableDevices()
403 .forEach(d -> updateDevice(d)
404 .ifPresent(ld -> updatePorts(ld, d.id())));
405 }
406
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800407 private boolean isBlacklisted(DeviceId did) {
408 LinkDiscoveryFromDevice cfg = cfgRegistry.getConfig(did, LinkDiscoveryFromDevice.class);
409 if (cfg == null) {
410 return false;
411 }
412 return !cfg.enabled();
413 }
414
415 private boolean isBlacklisted(ConnectPoint cp) {
416 // if parent device is blacklisted, so is the port
417 if (isBlacklisted(cp.deviceId())) {
418 return true;
419 }
420 LinkDiscoveryFromPort cfg = cfgRegistry.getConfig(cp, LinkDiscoveryFromPort.class);
421 if (cfg == null) {
422 return false;
423 }
424 return !cfg.enabled();
425 }
426
427 private boolean isBlacklisted(Port port) {
428 return isBlacklisted(new ConnectPoint(port.element().id(), port.number()));
429 }
430
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700431 /**
432 * Updates discovery helper for specified device.
433 *
434 * Adds and starts a discovery helper for specified device if enabled,
435 * calls {@link #removeDevice(DeviceId)} otherwise.
436 *
437 * @param device device to add
438 * @return discovery helper if discovery is enabled for the device
439 */
440 private Optional<LinkDiscovery> updateDevice(Device device) {
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800441 if (device == null) {
442 return Optional.empty();
443 }
Jon Hall125c3f22017-08-09 13:46:28 -0700444 if (!masterService.isLocalMaster(device.id())) {
445 // Reset the last seen time for all links to this device
446 // then stop discovery for this device
447 List<LinkKey> updateLinks = new LinkedList<>();
448 linkTimes.forEach((link, time) -> {
449 if (link.dst().deviceId().equals(device.id())) {
450 updateLinks.add(link);
451 }
452 });
453 updateLinks.forEach(link -> linkTimes.remove(link));
454 removeDevice(device.id());
455 return Optional.empty();
456 }
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800457 if (rules.isSuppressed(device) || isBlacklisted(device.id())) {
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700458 log.trace("LinkDiscovery from {} disabled by configuration", device.id());
459 removeDevice(device.id());
460 return Optional.empty();
461 }
Ayaka Koshibe3ddb7b22015-12-10 17:32:59 -0800462
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700463 LinkDiscovery ld = discoverers.computeIfAbsent(device.id(),
464 did -> new LinkDiscovery(device, context));
465 if (ld.isStopped()) {
466 ld.start();
467 }
468 return Optional.of(ld);
469 }
470
471 /**
472 * Removes after stopping discovery helper for specified device.
473 * @param deviceId device to remove
474 */
475 private void removeDevice(final DeviceId deviceId) {
476 discoverers.computeIfPresent(deviceId, (did, ld) -> {
477 ld.stop();
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700478 return null;
479 });
480
481 }
482
483 /**
484 * Updates ports of the specified device to the specified discovery helper.
485 */
486 private void updatePorts(LinkDiscovery discoverer, DeviceId deviceId) {
487 deviceService.getPorts(deviceId).forEach(p -> updatePort(discoverer, p));
488 }
489
490 /**
491 * Updates discovery helper state of the specified port.
492 *
493 * Adds a port to the discovery helper if up and discovery is enabled,
494 * or calls {@link #removePort(Port)} otherwise.
495 */
496 private void updatePort(LinkDiscovery discoverer, Port port) {
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800497 if (port == null) {
498 return;
499 }
HIGUCHI Yutab853b3f2015-11-17 18:43:20 -0800500 if (port.number().isLogical()) {
501 // silently ignore logical ports
502 return;
503 }
Naoki Shiota399a0b32015-11-15 20:36:13 -0600504
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800505 if (rules.isSuppressed(port) || isBlacklisted(port)) {
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700506 log.trace("LinkDiscovery from {} disabled by configuration", port);
507 removePort(port);
508 return;
509 }
510
511 // check if enabled and turn off discovery?
512 if (!port.isEnabled()) {
513 removePort(port);
514 return;
515 }
516
HIGUCHI Yutab853b3f2015-11-17 18:43:20 -0800517 discoverer.addPort(port);
alshabib7911a052014-10-16 17:49:37 -0700518 }
519
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700520 /**
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700521 * Removes a port from the specified discovery helper.
522 * @param port the port
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700523 */
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700524 private void removePort(Port port) {
525 if (port.element() instanceof Device) {
526 Device d = (Device) port.element();
527 LinkDiscovery ld = discoverers.get(d.id());
528 if (ld != null) {
529 ld.removePort(port.number());
Jonathan Hart45066bc2015-07-28 11:18:34 -0700530 }
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700531 } else {
532 log.warn("Attempted to remove non-Device port", port);
Jonathan Hart45066bc2015-07-28 11:18:34 -0700533 }
534 }
535
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700536 /**
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700537 * Requests packet intercepts.
Charles M.C. Chane148de82015-05-06 12:38:21 +0800538 */
Thomas Vachuska27bee092015-06-23 19:03:10 -0700539 private void requestIntercepts() {
540 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
Thomas Vachuska347cc872015-09-23 10:25:29 -0700541 selector.matchEthType(TYPE_LLDP);
Thomas Vachuska27bee092015-06-23 19:03:10 -0700542 packetService.requestPackets(selector.build(), PacketPriority.CONTROL, appId);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800543
Thomas Vachuska347cc872015-09-23 10:25:29 -0700544 selector.matchEthType(TYPE_BSN);
Jonathan Hartb35540a2015-11-17 09:30:56 -0800545 if (useBddp) {
Thomas Vachuska27bee092015-06-23 19:03:10 -0700546 packetService.requestPackets(selector.build(), PacketPriority.CONTROL, appId);
547 } else {
548 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId);
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800549 }
550 }
551
Thomas Vachuska27bee092015-06-23 19:03:10 -0700552 /**
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700553 * Withdraws packet intercepts.
Thomas Vachuska27bee092015-06-23 19:03:10 -0700554 */
555 private void withdrawIntercepts() {
556 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
Thomas Vachuska347cc872015-09-23 10:25:29 -0700557 selector.matchEthType(TYPE_LLDP);
Thomas Vachuska27bee092015-06-23 19:03:10 -0700558 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId);
Thomas Vachuska347cc872015-09-23 10:25:29 -0700559 selector.matchEthType(TYPE_BSN);
Thomas Vachuska27bee092015-06-23 19:03:10 -0700560 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId);
561 }
562
Naoki Shiota399a0b32015-11-15 20:36:13 -0600563 protected SuppressionRules rules() {
564 return rules;
565 }
566
567 protected void updateRules(SuppressionRules newRules) {
568 if (!rules.equals(newRules)) {
569 rules = newRules;
570 loadDevices();
571 }
572 }
573
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700574 /**
575 * Processes device mastership role changes.
576 */
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800577 private class InternalRoleListener implements MastershipListener {
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800578 @Override
579 public void event(MastershipEvent event) {
Jordan Halterman9d982a52017-12-11 15:27:37 -0800580 if (event.type() == MastershipEvent.Type.MASTER_CHANGED) {
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800581 // only need new master events
Jon Hall7a8bfc62016-05-26 17:59:04 -0700582 eventExecutor.execute(() -> {
583 DeviceId deviceId = event.subject();
584 Device device = deviceService.getDevice(deviceId);
585 if (device == null) {
586 log.debug("Device {} doesn't exist, or isn't there yet", deviceId);
587 return;
588 }
Jordan Halterman9d982a52017-12-11 15:27:37 -0800589 updateDevice(device).ifPresent(ld -> updatePorts(ld, device.id()));
Jon Hall7a8bfc62016-05-26 17:59:04 -0700590 });
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800591 }
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800592 }
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800593 }
alshabib7911a052014-10-16 17:49:37 -0700594
Ray Milkeyd9bbde82016-06-09 11:35:00 -0700595 private class DeviceEventProcessor implements Runnable {
596
597 DeviceEvent event;
598
599 DeviceEventProcessor(DeviceEvent event) {
600 this.event = event;
601 }
602
alshabib7911a052014-10-16 17:49:37 -0700603 @Override
Ray Milkeyd9bbde82016-06-09 11:35:00 -0700604 public void run() {
alshabib7911a052014-10-16 17:49:37 -0700605 Device device = event.subject();
alshabibacd91832014-10-17 14:38:41 -0700606 Port port = event.port();
alshabibdfc7afb2014-10-21 20:13:27 -0700607 if (device == null) {
608 log.error("Device is null.");
609 return;
610 }
Yuta HIGUCHIeb24e9d2014-10-26 19:34:20 -0700611 log.trace("{} {} {}", event.type(), event.subject(), event);
Yuta HIGUCHId19f6702014-10-31 15:23:25 -0700612 final DeviceId deviceId = device.id();
alshabib7911a052014-10-16 17:49:37 -0700613 switch (event.type()) {
614 case DEVICE_ADDED:
Yuta HIGUCHIeb24e9d2014-10-26 19:34:20 -0700615 case DEVICE_UPDATED:
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700616 updateDevice(device).ifPresent(ld -> updatePorts(ld, deviceId));
alshabib7911a052014-10-16 17:49:37 -0700617 break;
618 case PORT_ADDED:
619 case PORT_UPDATED:
Yuta HIGUCHIf6725882014-10-29 15:25:51 -0700620 if (port.isEnabled()) {
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700621 updateDevice(device).ifPresent(ld -> updatePort(ld, port));
alshabib7911a052014-10-16 17:49:37 -0700622 } else {
Yuta HIGUCHIf6725882014-10-29 15:25:51 -0700623 log.debug("Port down {}", port);
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700624 removePort(port);
Naoki Shiota399a0b32015-11-15 20:36:13 -0600625 providerService.linksVanished(new ConnectPoint(port.element().id(),
626 port.number()));
alshabib7911a052014-10-16 17:49:37 -0700627 }
628 break;
629 case PORT_REMOVED:
Yuta HIGUCHIeb24e9d2014-10-26 19:34:20 -0700630 log.debug("Port removed {}", port);
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700631 removePort(port);
Naoki Shiota399a0b32015-11-15 20:36:13 -0600632 providerService.linksVanished(new ConnectPoint(port.element().id(),
633 port.number()));
alshabib7911a052014-10-16 17:49:37 -0700634 break;
635 case DEVICE_REMOVED:
636 case DEVICE_SUSPENDED:
Yuta HIGUCHId19f6702014-10-31 15:23:25 -0700637 log.debug("Device removed {}", deviceId);
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700638 removeDevice(deviceId);
Naoki Shiota399a0b32015-11-15 20:36:13 -0600639 providerService.linksVanished(deviceId);
alshabib7911a052014-10-16 17:49:37 -0700640 break;
641 case DEVICE_AVAILABILITY_CHANGED:
Yuta HIGUCHId19f6702014-10-31 15:23:25 -0700642 if (deviceService.isAvailable(deviceId)) {
643 log.debug("Device up {}", deviceId);
alshabibe3af2652015-12-01 23:05:34 -0800644 updateDevice(device).ifPresent(ld -> updatePorts(ld, deviceId));
alshabib7911a052014-10-16 17:49:37 -0700645 } else {
Yuta HIGUCHId19f6702014-10-31 15:23:25 -0700646 log.debug("Device down {}", deviceId);
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700647 removeDevice(deviceId);
Naoki Shiota399a0b32015-11-15 20:36:13 -0600648 providerService.linksVanished(deviceId);
alshabib7911a052014-10-16 17:49:37 -0700649 }
650 break;
Jonathan Hart9de692c2015-04-23 11:45:47 -0700651 case PORT_STATS_UPDATED:
652 break;
alshabib7911a052014-10-16 17:49:37 -0700653 default:
654 log.debug("Unknown event {}", event);
655 }
656 }
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700657 }
alshabib7911a052014-10-16 17:49:37 -0700658
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700659 /**
Ray Milkeyd9bbde82016-06-09 11:35:00 -0700660 * Processes device events.
661 */
662 private class InternalDeviceListener implements DeviceListener {
663 @Override
664 public void event(DeviceEvent event) {
665 if (event.type() == Type.PORT_STATS_UPDATED) {
666 return;
667 }
668
669 Runnable deviceEventProcessor = new DeviceEventProcessor(event);
670
671 eventExecutor.execute(deviceEventProcessor);
672 }
673 }
674
675 /**
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700676 * Processes incoming packets.
677 */
678 private class InternalPacketProcessor implements PacketProcessor {
alshabib7911a052014-10-16 17:49:37 -0700679 @Override
680 public void process(PacketContext context) {
Thomas Vachuska347cc872015-09-23 10:25:29 -0700681 if (context == null || context.isHandled()) {
alshabib4a179dc2014-10-17 17:17:01 -0700682 return;
683 }
Thomas Vachuska347cc872015-09-23 10:25:29 -0700684
685 Ethernet eth = context.inPacket().parsed();
686 if (eth == null || (eth.getEtherType() != TYPE_LLDP && eth.getEtherType() != TYPE_BSN)) {
687 return;
688 }
689
Thomas Vachuska96f3ea72015-09-08 13:50:12 -0700690 LinkDiscovery ld = discoverers.get(context.inPacket().receivedFrom().deviceId());
alshabib7911a052014-10-16 17:49:37 -0700691 if (ld == null) {
692 return;
693 }
694
Jonathan Hartb35540a2015-11-17 09:30:56 -0800695 if (ld.handleLldp(context)) {
alshabib7911a052014-10-16 17:49:37 -0700696 context.block();
697 }
698 }
699 }
700
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700701 /**
702 * Auxiliary task to keep device ports up to date.
703 */
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800704 private final class SyncDeviceInfoTask implements Runnable {
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800705 @Override
706 public void run() {
707 if (Thread.currentThread().isInterrupted()) {
708 log.info("Interrupted, quitting");
709 return;
710 }
711 // check what deviceService sees, to see if we are missing anything
712 try {
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700713 loadDevices();
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800714 } catch (Exception e) {
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700715 // Catch all exceptions to avoid task being suppressed
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800716 log.error("Exception thrown during synchronization process", e);
717 }
718 }
719 }
720
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700721 /**
722 * Auxiliary task for pruning stale links.
723 */
724 private class LinkPrunerTask implements Runnable {
725 @Override
726 public void run() {
727 if (Thread.currentThread().isInterrupted()) {
728 log.info("Interrupted, quitting");
729 return;
730 }
731
732 try {
733 // TODO: There is still a slight possibility of mastership
734 // change occurring right with link going stale. This will
735 // result in the stale link not being pruned.
736 Maps.filterEntries(linkTimes, e -> {
737 if (!masterService.isLocalMaster(e.getKey().dst().deviceId())) {
738 return true;
739 }
740 if (isStale(e.getValue())) {
741 providerService.linkVanished(new DefaultLinkDescription(e.getKey().src(),
742 e.getKey().dst(),
743 DIRECT));
744 return true;
745 }
746 return false;
747 }).clear();
748
749 } catch (Exception e) {
750 // Catch all exceptions to avoid task being suppressed
Ray Milkeye80e18f2016-06-02 16:44:14 -0700751 if (!shuttingDown) {
752 // Error condition
753 log.error("Exception thrown during link pruning process", e);
754 } else {
755 // Provider is shutting down, the error can be ignored
756 log.trace("Shutting down, ignoring error", e);
757 }
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700758 }
759 }
760
761 private boolean isStale(long lastSeen) {
762 return lastSeen < System.currentTimeMillis() - staleLinkAge;
763 }
764 }
765
766 /**
767 * Provides processing context for the device link discovery helpers.
768 */
Ray Milkey957390e2016-02-09 10:02:46 -0800769 private class InternalDiscoveryContext implements LinkDiscoveryContext {
Thomas Vachuska05453c92015-09-09 14:40:49 -0700770 @Override
771 public MastershipService mastershipService() {
772 return masterService;
773 }
774
775 @Override
776 public LinkProviderService providerService() {
777 return providerService;
778 }
779
780 @Override
781 public PacketService packetService() {
782 return packetService;
783 }
784
785 @Override
786 public long probeRate() {
787 return probeRate;
788 }
789
790 @Override
Jonathan Hartb35540a2015-11-17 09:30:56 -0800791 public boolean useBddp() {
792 return useBddp;
Thomas Vachuska05453c92015-09-09 14:40:49 -0700793 }
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700794
795 @Override
796 public void touchLink(LinkKey key) {
797 linkTimes.put(key, System.currentTimeMillis());
798 }
Ayaka Koshibe12c8c082015-12-08 12:48:46 -0800799
800 @Override
Ayaka Koshibe48229222016-05-16 18:04:26 -0700801 public DeviceService deviceService() {
802 return deviceService;
Ayaka Koshibe3ddb7b22015-12-10 17:32:59 -0800803 }
804
805 @Override
Ayaka Koshibe48229222016-05-16 18:04:26 -0700806 public String fingerprint() {
807 return buildSrcMac();
Ayaka Koshibe12c8c082015-12-08 12:48:46 -0800808 }
Samuel Jero31e16f52018-09-21 10:34:28 -0400809
810 @Override
811 public String lldpSecret() {
812 return clusterMetadataService.getClusterMetadata().getClusterSecret();
813 }
814
815 @Override
816 public long maxDiscoveryDelay() {
817 return maxDiscoveryDelayMs;
818 }
Thomas Vachuska05453c92015-09-09 14:40:49 -0700819 }
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700820
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800821 static final EnumSet<NetworkConfigEvent.Type> CONFIG_CHANGED
822 = EnumSet.of(NetworkConfigEvent.Type.CONFIG_ADDED,
823 NetworkConfigEvent.Type.CONFIG_UPDATED,
824 NetworkConfigEvent.Type.CONFIG_REMOVED);
825
Naoki Shiota399a0b32015-11-15 20:36:13 -0600826 private class InternalConfigListener implements NetworkConfigListener {
827
828 private synchronized void reconfigureSuppressionRules(SuppressionConfig cfg) {
829 if (cfg == null) {
Ray Milkey0a8ee912016-06-13 09:58:12 -0700830 log.debug("Suppression Config is null.");
Naoki Shiota399a0b32015-11-15 20:36:13 -0600831 return;
832 }
833
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800834 SuppressionRules newRules = new SuppressionRules(cfg.deviceTypes(),
Naoki Shiota399a0b32015-11-15 20:36:13 -0600835 cfg.annotation());
836
837 updateRules(newRules);
838 }
839
Jon Hall125c3f22017-08-09 13:46:28 -0700840 private boolean isRelevantDeviceEvent(NetworkConfigEvent event) {
841 return event.configClass() == LinkDiscoveryFromDevice.class &&
842 CONFIG_CHANGED.contains(event.type());
843 }
844
845 private boolean isRelevantPortEvent(NetworkConfigEvent event) {
846 return event.configClass() == LinkDiscoveryFromPort.class &&
847 CONFIG_CHANGED.contains(event.type());
848 }
849
850 private boolean isRelevantSuppressionEvent(NetworkConfigEvent event) {
851 return (event.configClass().equals(SuppressionConfig.class) &&
852 (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
853 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED));
854 }
855
Naoki Shiota399a0b32015-11-15 20:36:13 -0600856 @Override
857 public void event(NetworkConfigEvent event) {
Ray Milkeyd9bbde82016-06-09 11:35:00 -0700858 eventExecutor.execute(() -> {
Jon Hall125c3f22017-08-09 13:46:28 -0700859 if (isRelevantDeviceEvent(event)) {
Thomas Vachuskab5f6f522016-03-01 13:52:10 -0800860 if (event.subject() instanceof DeviceId) {
861 final DeviceId did = (DeviceId) event.subject();
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800862 Device device = deviceService.getDevice(did);
Thomas Vachuskab5f6f522016-03-01 13:52:10 -0800863 updateDevice(device).ifPresent(ld -> updatePorts(ld, did));
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800864 }
Jon Hall125c3f22017-08-09 13:46:28 -0700865 } else if (isRelevantPortEvent(event)) {
Thomas Vachuskab5f6f522016-03-01 13:52:10 -0800866 if (event.subject() instanceof ConnectPoint) {
867 ConnectPoint cp = (ConnectPoint) event.subject();
868 if (cp.elementId() instanceof DeviceId) {
869 final DeviceId did = (DeviceId) cp.elementId();
870 Device device = deviceService.getDevice(did);
871 Port port = deviceService.getPort(did, cp.port());
872 updateDevice(device).ifPresent(ld -> updatePort(ld, port));
873 }
874 }
Jon Hall125c3f22017-08-09 13:46:28 -0700875 } else if (isRelevantSuppressionEvent(event)) {
Thomas Vachuskab5f6f522016-03-01 13:52:10 -0800876 SuppressionConfig cfg = cfgRegistry.getConfig(appId, SuppressionConfig.class);
877 reconfigureSuppressionRules(cfg);
878 log.trace("Network config reconfigured");
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800879 }
Thomas Vachuskab5f6f522016-03-01 13:52:10 -0800880 });
Naoki Shiota399a0b32015-11-15 20:36:13 -0600881 }
882 }
alshabib7911a052014-10-16 17:49:37 -0700883}