blob: e425678d6502adfe86bf5e10f71e3dc24ac906ec [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 Milkeyd84f89b2018-08-17 14:54:17 -070018import com.google.common.collect.ImmutableMap;
19import com.google.common.collect.ImmutableSet;
20import com.google.common.collect.Maps;
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080021import org.onlab.packet.Ethernet;
Thomas Vachuska6519e6f2015-03-11 02:29:31 -070022import org.onosproject.cfg.ComponentConfigService;
Ayaka Koshibe12c8c082015-12-08 12:48:46 -080023import org.onosproject.cluster.ClusterMetadataService;
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -070024import org.onosproject.cluster.ClusterService;
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080025import org.onosproject.core.ApplicationId;
26import org.onosproject.core.CoreService;
Brian O'Connorabafb502014-12-02 22:26:20 -080027import org.onosproject.mastership.MastershipEvent;
28import org.onosproject.mastership.MastershipListener;
29import org.onosproject.mastership.MastershipService;
30import org.onosproject.net.ConnectPoint;
31import org.onosproject.net.Device;
32import org.onosproject.net.DeviceId;
Thomas Vachuskae4ebac92015-09-10 11:39:05 -070033import org.onosproject.net.LinkKey;
Brian O'Connorabafb502014-12-02 22:26:20 -080034import org.onosproject.net.Port;
Naoki Shiota399a0b32015-11-15 20:36:13 -060035import org.onosproject.net.config.ConfigFactory;
36import org.onosproject.net.config.NetworkConfigEvent;
37import org.onosproject.net.config.NetworkConfigListener;
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -070038import org.onosproject.net.config.NetworkConfigRegistry;
Brian O'Connorabafb502014-12-02 22:26:20 -080039import org.onosproject.net.device.DeviceEvent;
HIGUCHI Yuta1979f552015-12-28 21:24:26 -080040import org.onosproject.net.device.DeviceEvent.Type;
Brian O'Connorabafb502014-12-02 22:26:20 -080041import org.onosproject.net.device.DeviceListener;
42import org.onosproject.net.device.DeviceService;
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080043import org.onosproject.net.flow.DefaultTrafficSelector;
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -080044import org.onosproject.net.flow.TrafficSelector;
Thomas Vachuskae4ebac92015-09-10 11:39:05 -070045import org.onosproject.net.link.DefaultLinkDescription;
Brian O'Connorabafb502014-12-02 22:26:20 -080046import org.onosproject.net.link.LinkProviderRegistry;
47import org.onosproject.net.link.LinkProviderService;
Thomas Vachuskae4ebac92015-09-10 11:39:05 -070048import org.onosproject.net.link.LinkService;
Ray Milkeyd9bbde82016-06-09 11:35:00 -070049import org.onosproject.net.link.ProbedLinkProvider;
Brian O'Connorabafb502014-12-02 22:26:20 -080050import org.onosproject.net.packet.PacketContext;
Jonathan Hart3cfce8e2015-01-14 16:43:27 -080051import org.onosproject.net.packet.PacketPriority;
Brian O'Connorabafb502014-12-02 22:26:20 -080052import org.onosproject.net.packet.PacketProcessor;
53import org.onosproject.net.packet.PacketService;
54import org.onosproject.net.provider.AbstractProvider;
55import org.onosproject.net.provider.ProviderId;
Ray Milkey957390e2016-02-09 10:02:46 -080056import org.onosproject.provider.lldpcommon.LinkDiscovery;
Ray Milkeyd9bbde82016-06-09 11:35:00 -070057import org.onosproject.provider.lldpcommon.LinkDiscoveryContext;
Yuta HIGUCHI41289382014-12-19 17:47:12 -080058import org.osgi.service.component.ComponentContext;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070059import org.osgi.service.component.annotations.Activate;
60import org.osgi.service.component.annotations.Component;
61import org.osgi.service.component.annotations.Deactivate;
62import org.osgi.service.component.annotations.Modified;
63import org.osgi.service.component.annotations.Reference;
64import org.osgi.service.component.annotations.ReferenceCardinality;
alshabib7911a052014-10-16 17:49:37 -070065import org.slf4j.Logger;
66
Ray Milkeyd84f89b2018-08-17 14:54:17 -070067import java.util.Dictionary;
68import java.util.EnumSet;
69import java.util.LinkedList;
70import java.util.List;
71import java.util.Map;
72import java.util.Optional;
73import java.util.Properties;
74import java.util.Set;
75import java.util.concurrent.ConcurrentHashMap;
76import java.util.concurrent.ExecutorService;
77import java.util.concurrent.ScheduledExecutorService;
Marc De Leenheer0bfc2a12016-02-02 22:46:27 -080078
79import static com.google.common.base.Strings.isNullOrEmpty;
80import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
81import static java.util.concurrent.TimeUnit.SECONDS;
82import static org.onlab.packet.Ethernet.TYPE_BSN;
83import static org.onlab.packet.Ethernet.TYPE_LLDP;
84import static org.onlab.util.Tools.get;
85import static org.onlab.util.Tools.groupedThreads;
Marc De Leenheer0bfc2a12016-02-02 22:46:27 -080086import static org.onosproject.net.Link.Type.DIRECT;
87import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
88import static org.onosproject.net.config.basics.SubjectFactories.CONNECT_POINT_SUBJECT_FACTORY;
89import static org.onosproject.net.config.basics.SubjectFactories.DEVICE_SUBJECT_FACTORY;
90import static org.slf4j.LoggerFactory.getLogger;
Yuta HIGUCHI41289382014-12-19 17:47:12 -080091
alshabib7911a052014-10-16 17:49:37 -070092/**
Thomas Vachuska05453c92015-09-09 14:40:49 -070093 * Provider which uses LLDP and BDDP packets to detect network infrastructure links.
alshabib7911a052014-10-16 17:49:37 -070094 */
95@Component(immediate = true)
Ayaka Koshibe48229222016-05-16 18:04:26 -070096public class LldpLinkProvider extends AbstractProvider implements ProbedLinkProvider {
alshabib7911a052014-10-16 17:49:37 -070097
Thomas Vachuskafc52fec2015-05-18 19:13:56 -070098 private static final String PROVIDER_NAME = "org.onosproject.provider.lldp";
99
Thomas Vachuska05453c92015-09-09 14:40:49 -0700100 private static final String FORMAT =
101 "Settings: enabled={}, useBDDP={}, probeRate={}, " +
Naoki Shiota399a0b32015-11-15 20:36:13 -0600102 "staleLinkAge={}";
Yuta HIGUCHI41289382014-12-19 17:47:12 -0800103
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700104 // When a Device/Port has this annotation, do not send out LLDP/BDDP
105 public static final String NO_LLDP = "no-lldp";
106
Thomas Vachuskaaad8b1d2015-12-11 10:36:53 -0800107 private static final int MAX_RETRIES = 5;
108 private static final int RETRY_DELAY = 1_000; // millis
109
alshabib7911a052014-10-16 17:49:37 -0700110 private final Logger log = getLogger(getClass());
111
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700112 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800113 protected CoreService coreService;
114
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700115 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabib7911a052014-10-16 17:49:37 -0700116 protected LinkProviderRegistry providerRegistry;
117
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700118 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabib7911a052014-10-16 17:49:37 -0700119 protected DeviceService deviceService;
120
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700121 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700122 protected LinkService linkService;
123
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700124 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Marc De Leenheer8b3e80b2015-03-06 14:27:03 -0800125 protected PacketService packetService;
alshabib7911a052014-10-16 17:49:37 -0700126
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700127 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabib875d6262014-10-17 16:19:40 -0700128 protected MastershipService masterService;
129
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700130 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuska6519e6f2015-03-11 02:29:31 -0700131 protected ComponentConfigService cfgService;
132
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700133 @Reference(cardinality = ReferenceCardinality.MANDATORY)
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700134 protected ClusterService clusterService;
135
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700136 @Reference(cardinality = ReferenceCardinality.MANDATORY)
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700137 protected NetworkConfigRegistry cfgRegistry;
138
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700139 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ayaka Koshibe12c8c082015-12-08 12:48:46 -0800140 protected ClusterMetadataService clusterMetadataService;
141
alshabib7911a052014-10-16 17:49:37 -0700142 private LinkProviderService providerService;
143
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800144 private ScheduledExecutorService executor;
Ray Milkeyd9bbde82016-06-09 11:35:00 -0700145 protected ExecutorService eventExecutor;
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800146
Ray Milkeye80e18f2016-06-02 16:44:14 -0700147 private boolean shuttingDown = false;
148
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700149 // TODO: Add sanity checking for the configurable params based on the delays
150 private static final long DEVICE_SYNC_DELAY = 5;
151 private static final long LINK_PRUNER_DELAY = 3;
Thomas Vachuska05453c92015-09-09 14:40:49 -0700152
153 private static final String PROP_ENABLED = "enabled";
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700154 //@Property(name = PROP_ENABLED, boolValue = true,
155 // label = "If false, link discovery is disabled")
Thomas Vachuska05453c92015-09-09 14:40:49 -0700156 private boolean enabled = false;
157
158 private static final String PROP_USE_BDDP = "useBDDP";
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700159 //@Property(name = PROP_USE_BDDP, boolValue = true,
160 // label = "Use BDDP for link discovery")
Jonathan Hartb35540a2015-11-17 09:30:56 -0800161 private boolean useBddp = true;
alshabib7911a052014-10-16 17:49:37 -0700162
Thomas Vachuska05453c92015-09-09 14:40:49 -0700163 private static final String PROP_PROBE_RATE = "probeRate";
Thomas Vachuska9e51fd02016-01-04 16:51:28 -0800164 private static final int DEFAULT_PROBE_RATE = 3000;
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700165 //@Property(name = PROP_PROBE_RATE, intValue = DEFAULT_PROBE_RATE,
166 // label = "LLDP and BDDP probe rate specified in millis")
Thomas Vachuska05453c92015-09-09 14:40:49 -0700167 private int probeRate = DEFAULT_PROBE_RATE;
Saurav Dasc313c402015-02-27 10:09:47 -0800168
Thomas Vachuska05453c92015-09-09 14:40:49 -0700169 private static final String PROP_STALE_LINK_AGE = "staleLinkAge";
Thomas Vachuska9e51fd02016-01-04 16:51:28 -0800170 private static final int DEFAULT_STALE_LINK_AGE = 10000;
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700171 //@Property(name = PROP_STALE_LINK_AGE, intValue = DEFAULT_STALE_LINK_AGE,
172 // label = "Number of millis beyond which links will be considered stale")
Thomas Vachuska05453c92015-09-09 14:40:49 -0700173 private int staleLinkAge = DEFAULT_STALE_LINK_AGE;
alshabib7911a052014-10-16 17:49:37 -0700174
Ray Milkey957390e2016-02-09 10:02:46 -0800175 private final LinkDiscoveryContext context = new InternalDiscoveryContext();
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800176 private final InternalRoleListener roleListener = new InternalRoleListener();
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700177 private final InternalDeviceListener deviceListener = new InternalDeviceListener();
178 private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800179
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700180 // Device link discovery helpers.
alshabib7911a052014-10-16 17:49:37 -0700181 protected final Map<DeviceId, LinkDiscovery> discoverers = new ConcurrentHashMap<>();
182
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700183 // Most recent time a tracked link was seen; links are tracked if their
184 // destination connection point is mastered by this controller instance.
185 private final Map<LinkKey, Long> linkTimes = Maps.newConcurrentMap();
186
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800187 private ApplicationId appId;
Yuta HIGUCHI41289382014-12-19 17:47:12 -0800188
Naoki Shiota399a0b32015-11-15 20:36:13 -0600189 static final SuppressionRules DEFAULT_RULES
Yuta HIGUCHI09697d02017-03-03 16:53:39 -0800190 = new SuppressionRules(EnumSet.of(Device.Type.ROADM,
191 Device.Type.FIBER_SWITCH,
192 Device.Type.OPTICAL_AMPLIFIER,
193 Device.Type.OTN),
Naoki Shiota399a0b32015-11-15 20:36:13 -0600194 ImmutableMap.of(NO_LLDP, SuppressionRules.ANY_VALUE));
195
196 private SuppressionRules rules = LldpLinkProvider.DEFAULT_RULES;
197
198 public static final String CONFIG_KEY = "suppression";
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800199 public static final String FEATURE_NAME = "linkDiscovery";
Naoki Shiota399a0b32015-11-15 20:36:13 -0600200
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800201 private final Set<ConfigFactory<?, ?>> factories = ImmutableSet.of(
Naoki Shiota399a0b32015-11-15 20:36:13 -0600202 new ConfigFactory<ApplicationId, SuppressionConfig>(APP_SUBJECT_FACTORY,
203 SuppressionConfig.class,
204 CONFIG_KEY) {
205 @Override
206 public SuppressionConfig createConfig() {
207 return new SuppressionConfig();
208 }
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800209 },
210 new ConfigFactory<DeviceId, LinkDiscoveryFromDevice>(DEVICE_SUBJECT_FACTORY,
211 LinkDiscoveryFromDevice.class, FEATURE_NAME) {
212 @Override
213 public LinkDiscoveryFromDevice createConfig() {
214 return new LinkDiscoveryFromDevice();
215 }
216 },
217 new ConfigFactory<ConnectPoint, LinkDiscoveryFromPort>(CONNECT_POINT_SUBJECT_FACTORY,
218 LinkDiscoveryFromPort.class, FEATURE_NAME) {
219 @Override
220 public LinkDiscoveryFromPort createConfig() {
221 return new LinkDiscoveryFromPort();
222 }
Naoki Shiota399a0b32015-11-15 20:36:13 -0600223 }
224 );
225
226 private final InternalConfigListener cfgListener = new InternalConfigListener();
227
alshabib7911a052014-10-16 17:49:37 -0700228 /**
229 * Creates an OpenFlow link provider.
230 */
Jonathan Hartb35540a2015-11-17 09:30:56 -0800231 public LldpLinkProvider() {
Thomas Vachuskafc52fec2015-05-18 19:13:56 -0700232 super(new ProviderId("lldp", PROVIDER_NAME));
alshabib7911a052014-10-16 17:49:37 -0700233 }
234
Sho SHIMIZU9efeb812016-08-18 09:29:20 -0700235 private String buildSrcMac() {
Ayaka Koshibe48229222016-05-16 18:04:26 -0700236 String defMac = ProbedLinkProvider.defaultMac();
Ray Milkey55f513f2017-12-01 15:58:21 -0800237 if (clusterMetadataService == null) {
238 log.debug("No cluster metadata service is available. Using default value {}", defMac);
239 return defMac;
240 }
241
242 String srcMac = ProbedLinkProvider.fingerprintMac(clusterMetadataService.getClusterMetadata());
Ayaka Koshibe48229222016-05-16 18:04:26 -0700243 if (srcMac.equals(defMac)) {
244 log.warn("Couldn't generate fingerprint. Using default value {}", defMac);
245 return defMac;
246 }
247 log.trace("Generated MAC address {}", srcMac);
248 return srcMac;
249 }
250
alshabib7911a052014-10-16 17:49:37 -0700251 @Activate
Saurav Dasc313c402015-02-27 10:09:47 -0800252 public void activate(ComponentContext context) {
Ray Milkeyd9bbde82016-06-09 11:35:00 -0700253 eventExecutor = newSingleThreadScheduledExecutor(groupedThreads("onos/linkevents", "events-%d", log));
Ray Milkeye80e18f2016-06-02 16:44:14 -0700254 shuttingDown = false;
Thomas Vachuska6519e6f2015-03-11 02:29:31 -0700255 cfgService.registerProperties(getClass());
Thomas Vachuskafc52fec2015-05-18 19:13:56 -0700256 appId = coreService.registerApplication(PROVIDER_NAME);
Naoki Shiota399a0b32015-11-15 20:36:13 -0600257
258 cfgRegistry.addListener(cfgListener);
259 factories.forEach(cfgRegistry::registerConfigFactory);
260
Madan Jampanic6371882016-06-03 21:30:17 -0700261 SuppressionConfig cfg = cfgRegistry.getConfig(appId, SuppressionConfig.class);
Naoki Shiota399a0b32015-11-15 20:36:13 -0600262 if (cfg == null) {
263 // If no configuration is found, register default.
Madan Jampanic6371882016-06-03 21:30:17 -0700264 cfg = this.setDefaultSuppressionConfig();
Naoki Shiota399a0b32015-11-15 20:36:13 -0600265 }
266 cfgListener.reconfigureSuppressionRules(cfg);
267
Saurav Dasc313c402015-02-27 10:09:47 -0800268 modified(context);
Thomas Vachuska05453c92015-09-09 14:40:49 -0700269 log.info("Started");
270 }
271
Thomas Vachuskaaad8b1d2015-12-11 10:36:53 -0800272 private SuppressionConfig setDefaultSuppressionConfig() {
273 SuppressionConfig cfg = cfgRegistry.addConfig(appId, SuppressionConfig.class);
274 cfg.deviceTypes(DEFAULT_RULES.getSuppressedDeviceType())
275 .annotation(DEFAULT_RULES.getSuppressedAnnotation())
276 .apply();
277 return cfg;
278 }
279
Thomas Vachuska05453c92015-09-09 14:40:49 -0700280 @Deactivate
281 public void deactivate() {
Ray Milkeye80e18f2016-06-02 16:44:14 -0700282 shuttingDown = true;
Naoki Shiota399a0b32015-11-15 20:36:13 -0600283 cfgRegistry.removeListener(cfgListener);
284 factories.forEach(cfgRegistry::unregisterConfigFactory);
285
Thomas Vachuska05453c92015-09-09 14:40:49 -0700286 cfgService.unregisterProperties(getClass(), false);
287 disable();
Ray Milkeyd9bbde82016-06-09 11:35:00 -0700288 eventExecutor.shutdownNow();
289 eventExecutor = null;
Thomas Vachuska05453c92015-09-09 14:40:49 -0700290 log.info("Stopped");
291 }
292
293 @Modified
294 public void modified(ComponentContext context) {
295 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
296
297 boolean newEnabled, newUseBddp;
298 int newProbeRate, newStaleLinkAge;
Thomas Vachuska05453c92015-09-09 14:40:49 -0700299 try {
300 String s = get(properties, PROP_ENABLED);
301 newEnabled = isNullOrEmpty(s) || Boolean.parseBoolean(s.trim());
302
303 s = get(properties, PROP_USE_BDDP);
304 newUseBddp = isNullOrEmpty(s) || Boolean.parseBoolean(s.trim());
305
306 s = get(properties, PROP_PROBE_RATE);
307 newProbeRate = isNullOrEmpty(s) ? probeRate : Integer.parseInt(s.trim());
308
309 s = get(properties, PROP_STALE_LINK_AGE);
310 newStaleLinkAge = isNullOrEmpty(s) ? staleLinkAge : Integer.parseInt(s.trim());
311
Thomas Vachuska05453c92015-09-09 14:40:49 -0700312 } catch (NumberFormatException e) {
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700313 log.warn("Component configuration had invalid values", e);
Thomas Vachuska05453c92015-09-09 14:40:49 -0700314 newEnabled = enabled;
Jonathan Hartb35540a2015-11-17 09:30:56 -0800315 newUseBddp = useBddp;
Thomas Vachuska05453c92015-09-09 14:40:49 -0700316 newProbeRate = probeRate;
317 newStaleLinkAge = staleLinkAge;
Saurav Dasc313c402015-02-27 10:09:47 -0800318 }
Yuta HIGUCHI41289382014-12-19 17:47:12 -0800319
Thomas Vachuska05453c92015-09-09 14:40:49 -0700320 boolean wasEnabled = enabled;
321
322 enabled = newEnabled;
Jonathan Hartb35540a2015-11-17 09:30:56 -0800323 useBddp = newUseBddp;
Thomas Vachuska05453c92015-09-09 14:40:49 -0700324 probeRate = newProbeRate;
325 staleLinkAge = newStaleLinkAge;
Thomas Vachuska05453c92015-09-09 14:40:49 -0700326
327 if (!wasEnabled && enabled) {
328 enable();
329 } else if (wasEnabled && !enabled) {
330 disable();
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700331 } else {
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700332 if (enabled) {
333 // update all discovery helper state
334 loadDevices();
335 }
Thomas Vachuska05453c92015-09-09 14:40:49 -0700336 }
337
Naoki Shiota399a0b32015-11-15 20:36:13 -0600338 log.info(FORMAT, enabled, useBddp, probeRate, staleLinkAge);
Thomas Vachuska05453c92015-09-09 14:40:49 -0700339 }
340
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700341 /**
342 * Enables link discovery processing.
343 */
Thomas Vachuska05453c92015-09-09 14:40:49 -0700344 private void enable() {
alshabib7911a052014-10-16 17:49:37 -0700345 providerService = providerRegistry.register(this);
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800346 masterService.addListener(roleListener);
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700347 deviceService.addListener(deviceListener);
348 packetService.addProcessor(packetProcessor, PacketProcessor.advisor(0));
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800349
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700350 loadDevices();
Thomas Vachuska05453c92015-09-09 14:40:49 -0700351
HIGUCHI Yutad9e01052016-04-14 09:31:42 -0700352 executor = newSingleThreadScheduledExecutor(groupedThreads("onos/link", "discovery-%d", log));
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700353 executor.scheduleAtFixedRate(new SyncDeviceInfoTask(),
354 DEVICE_SYNC_DELAY, DEVICE_SYNC_DELAY, SECONDS);
355 executor.scheduleAtFixedRate(new LinkPrunerTask(),
356 LINK_PRUNER_DELAY, LINK_PRUNER_DELAY, SECONDS);
Thomas Vachuska05453c92015-09-09 14:40:49 -0700357
Thomas Vachuska05453c92015-09-09 14:40:49 -0700358 requestIntercepts();
359 }
360
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700361 /**
362 * Disables link discovery processing.
363 */
Thomas Vachuska05453c92015-09-09 14:40:49 -0700364 private void disable() {
365 withdrawIntercepts();
366
367 providerRegistry.unregister(this);
Thomas Vachuska05453c92015-09-09 14:40:49 -0700368 masterService.removeListener(roleListener);
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700369 deviceService.removeListener(deviceListener);
370 packetService.removeProcessor(packetProcessor);
Thomas Vachuska05453c92015-09-09 14:40:49 -0700371
372 if (executor != null) {
373 executor.shutdownNow();
374 }
375 discoverers.values().forEach(LinkDiscovery::stop);
376 discoverers.clear();
Jon Hall125c3f22017-08-09 13:46:28 -0700377 linkTimes.clear();
Thomas Vachuska05453c92015-09-09 14:40:49 -0700378
379 providerService = null;
380 }
381
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700382 /**
383 * Loads available devices and registers their ports to be probed.
384 */
385 private void loadDevices() {
Ray Milkey0f87d482016-07-06 11:49:19 -0700386 if (!enabled || deviceService == null) {
Naoki Shiota399a0b32015-11-15 20:36:13 -0600387 return;
388 }
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700389 deviceService.getAvailableDevices()
390 .forEach(d -> updateDevice(d)
391 .ifPresent(ld -> updatePorts(ld, d.id())));
392 }
393
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800394 private boolean isBlacklisted(DeviceId did) {
395 LinkDiscoveryFromDevice cfg = cfgRegistry.getConfig(did, LinkDiscoveryFromDevice.class);
396 if (cfg == null) {
397 return false;
398 }
399 return !cfg.enabled();
400 }
401
402 private boolean isBlacklisted(ConnectPoint cp) {
403 // if parent device is blacklisted, so is the port
404 if (isBlacklisted(cp.deviceId())) {
405 return true;
406 }
407 LinkDiscoveryFromPort cfg = cfgRegistry.getConfig(cp, LinkDiscoveryFromPort.class);
408 if (cfg == null) {
409 return false;
410 }
411 return !cfg.enabled();
412 }
413
414 private boolean isBlacklisted(Port port) {
415 return isBlacklisted(new ConnectPoint(port.element().id(), port.number()));
416 }
417
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700418 /**
419 * Updates discovery helper for specified device.
420 *
421 * Adds and starts a discovery helper for specified device if enabled,
422 * calls {@link #removeDevice(DeviceId)} otherwise.
423 *
424 * @param device device to add
425 * @return discovery helper if discovery is enabled for the device
426 */
427 private Optional<LinkDiscovery> updateDevice(Device device) {
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800428 if (device == null) {
429 return Optional.empty();
430 }
Jon Hall125c3f22017-08-09 13:46:28 -0700431 if (!masterService.isLocalMaster(device.id())) {
432 // Reset the last seen time for all links to this device
433 // then stop discovery for this device
434 List<LinkKey> updateLinks = new LinkedList<>();
435 linkTimes.forEach((link, time) -> {
436 if (link.dst().deviceId().equals(device.id())) {
437 updateLinks.add(link);
438 }
439 });
440 updateLinks.forEach(link -> linkTimes.remove(link));
441 removeDevice(device.id());
442 return Optional.empty();
443 }
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800444 if (rules.isSuppressed(device) || isBlacklisted(device.id())) {
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700445 log.trace("LinkDiscovery from {} disabled by configuration", device.id());
446 removeDevice(device.id());
447 return Optional.empty();
448 }
Ayaka Koshibe3ddb7b22015-12-10 17:32:59 -0800449
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700450 LinkDiscovery ld = discoverers.computeIfAbsent(device.id(),
451 did -> new LinkDiscovery(device, context));
452 if (ld.isStopped()) {
453 ld.start();
454 }
455 return Optional.of(ld);
456 }
457
458 /**
459 * Removes after stopping discovery helper for specified device.
460 * @param deviceId device to remove
461 */
462 private void removeDevice(final DeviceId deviceId) {
463 discoverers.computeIfPresent(deviceId, (did, ld) -> {
464 ld.stop();
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700465 return null;
466 });
467
468 }
469
470 /**
471 * Updates ports of the specified device to the specified discovery helper.
472 */
473 private void updatePorts(LinkDiscovery discoverer, DeviceId deviceId) {
474 deviceService.getPorts(deviceId).forEach(p -> updatePort(discoverer, p));
475 }
476
477 /**
478 * Updates discovery helper state of the specified port.
479 *
480 * Adds a port to the discovery helper if up and discovery is enabled,
481 * or calls {@link #removePort(Port)} otherwise.
482 */
483 private void updatePort(LinkDiscovery discoverer, Port port) {
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800484 if (port == null) {
485 return;
486 }
HIGUCHI Yutab853b3f2015-11-17 18:43:20 -0800487 if (port.number().isLogical()) {
488 // silently ignore logical ports
489 return;
490 }
Naoki Shiota399a0b32015-11-15 20:36:13 -0600491
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800492 if (rules.isSuppressed(port) || isBlacklisted(port)) {
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700493 log.trace("LinkDiscovery from {} disabled by configuration", port);
494 removePort(port);
495 return;
496 }
497
498 // check if enabled and turn off discovery?
499 if (!port.isEnabled()) {
500 removePort(port);
501 return;
502 }
503
HIGUCHI Yutab853b3f2015-11-17 18:43:20 -0800504 discoverer.addPort(port);
alshabib7911a052014-10-16 17:49:37 -0700505 }
506
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700507 /**
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700508 * Removes a port from the specified discovery helper.
509 * @param port the port
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700510 */
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700511 private void removePort(Port port) {
512 if (port.element() instanceof Device) {
513 Device d = (Device) port.element();
514 LinkDiscovery ld = discoverers.get(d.id());
515 if (ld != null) {
516 ld.removePort(port.number());
Jonathan Hart45066bc2015-07-28 11:18:34 -0700517 }
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700518 } else {
519 log.warn("Attempted to remove non-Device port", port);
Jonathan Hart45066bc2015-07-28 11:18:34 -0700520 }
521 }
522
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700523 /**
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700524 * Requests packet intercepts.
Charles M.C. Chane148de82015-05-06 12:38:21 +0800525 */
Thomas Vachuska27bee092015-06-23 19:03:10 -0700526 private void requestIntercepts() {
527 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
Thomas Vachuska347cc872015-09-23 10:25:29 -0700528 selector.matchEthType(TYPE_LLDP);
Thomas Vachuska27bee092015-06-23 19:03:10 -0700529 packetService.requestPackets(selector.build(), PacketPriority.CONTROL, appId);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800530
Thomas Vachuska347cc872015-09-23 10:25:29 -0700531 selector.matchEthType(TYPE_BSN);
Jonathan Hartb35540a2015-11-17 09:30:56 -0800532 if (useBddp) {
Thomas Vachuska27bee092015-06-23 19:03:10 -0700533 packetService.requestPackets(selector.build(), PacketPriority.CONTROL, appId);
534 } else {
535 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId);
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800536 }
537 }
538
Thomas Vachuska27bee092015-06-23 19:03:10 -0700539 /**
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700540 * Withdraws packet intercepts.
Thomas Vachuska27bee092015-06-23 19:03:10 -0700541 */
542 private void withdrawIntercepts() {
543 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
Thomas Vachuska347cc872015-09-23 10:25:29 -0700544 selector.matchEthType(TYPE_LLDP);
Thomas Vachuska27bee092015-06-23 19:03:10 -0700545 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId);
Thomas Vachuska347cc872015-09-23 10:25:29 -0700546 selector.matchEthType(TYPE_BSN);
Thomas Vachuska27bee092015-06-23 19:03:10 -0700547 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId);
548 }
549
Naoki Shiota399a0b32015-11-15 20:36:13 -0600550 protected SuppressionRules rules() {
551 return rules;
552 }
553
554 protected void updateRules(SuppressionRules newRules) {
555 if (!rules.equals(newRules)) {
556 rules = newRules;
557 loadDevices();
558 }
559 }
560
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700561 /**
562 * Processes device mastership role changes.
563 */
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800564 private class InternalRoleListener implements MastershipListener {
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800565 @Override
566 public void event(MastershipEvent event) {
Jordan Halterman9d982a52017-12-11 15:27:37 -0800567 if (event.type() == MastershipEvent.Type.MASTER_CHANGED) {
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800568 // only need new master events
Jon Hall7a8bfc62016-05-26 17:59:04 -0700569 eventExecutor.execute(() -> {
570 DeviceId deviceId = event.subject();
571 Device device = deviceService.getDevice(deviceId);
572 if (device == null) {
573 log.debug("Device {} doesn't exist, or isn't there yet", deviceId);
574 return;
575 }
Jordan Halterman9d982a52017-12-11 15:27:37 -0800576 updateDevice(device).ifPresent(ld -> updatePorts(ld, device.id()));
Jon Hall7a8bfc62016-05-26 17:59:04 -0700577 });
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800578 }
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800579 }
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800580 }
alshabib7911a052014-10-16 17:49:37 -0700581
Ray Milkeyd9bbde82016-06-09 11:35:00 -0700582 private class DeviceEventProcessor implements Runnable {
583
584 DeviceEvent event;
585
586 DeviceEventProcessor(DeviceEvent event) {
587 this.event = event;
588 }
589
alshabib7911a052014-10-16 17:49:37 -0700590 @Override
Ray Milkeyd9bbde82016-06-09 11:35:00 -0700591 public void run() {
alshabib7911a052014-10-16 17:49:37 -0700592 Device device = event.subject();
alshabibacd91832014-10-17 14:38:41 -0700593 Port port = event.port();
alshabibdfc7afb2014-10-21 20:13:27 -0700594 if (device == null) {
595 log.error("Device is null.");
596 return;
597 }
Yuta HIGUCHIeb24e9d2014-10-26 19:34:20 -0700598 log.trace("{} {} {}", event.type(), event.subject(), event);
Yuta HIGUCHId19f6702014-10-31 15:23:25 -0700599 final DeviceId deviceId = device.id();
alshabib7911a052014-10-16 17:49:37 -0700600 switch (event.type()) {
601 case DEVICE_ADDED:
Yuta HIGUCHIeb24e9d2014-10-26 19:34:20 -0700602 case DEVICE_UPDATED:
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700603 updateDevice(device).ifPresent(ld -> updatePorts(ld, deviceId));
alshabib7911a052014-10-16 17:49:37 -0700604 break;
605 case PORT_ADDED:
606 case PORT_UPDATED:
Yuta HIGUCHIf6725882014-10-29 15:25:51 -0700607 if (port.isEnabled()) {
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700608 updateDevice(device).ifPresent(ld -> updatePort(ld, port));
alshabib7911a052014-10-16 17:49:37 -0700609 } else {
Yuta HIGUCHIf6725882014-10-29 15:25:51 -0700610 log.debug("Port down {}", port);
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700611 removePort(port);
Naoki Shiota399a0b32015-11-15 20:36:13 -0600612 providerService.linksVanished(new ConnectPoint(port.element().id(),
613 port.number()));
alshabib7911a052014-10-16 17:49:37 -0700614 }
615 break;
616 case PORT_REMOVED:
Yuta HIGUCHIeb24e9d2014-10-26 19:34:20 -0700617 log.debug("Port removed {}", port);
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700618 removePort(port);
Naoki Shiota399a0b32015-11-15 20:36:13 -0600619 providerService.linksVanished(new ConnectPoint(port.element().id(),
620 port.number()));
alshabib7911a052014-10-16 17:49:37 -0700621 break;
622 case DEVICE_REMOVED:
623 case DEVICE_SUSPENDED:
Yuta HIGUCHId19f6702014-10-31 15:23:25 -0700624 log.debug("Device removed {}", deviceId);
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700625 removeDevice(deviceId);
Naoki Shiota399a0b32015-11-15 20:36:13 -0600626 providerService.linksVanished(deviceId);
alshabib7911a052014-10-16 17:49:37 -0700627 break;
628 case DEVICE_AVAILABILITY_CHANGED:
Yuta HIGUCHId19f6702014-10-31 15:23:25 -0700629 if (deviceService.isAvailable(deviceId)) {
630 log.debug("Device up {}", deviceId);
alshabibe3af2652015-12-01 23:05:34 -0800631 updateDevice(device).ifPresent(ld -> updatePorts(ld, deviceId));
alshabib7911a052014-10-16 17:49:37 -0700632 } else {
Yuta HIGUCHId19f6702014-10-31 15:23:25 -0700633 log.debug("Device down {}", deviceId);
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700634 removeDevice(deviceId);
Naoki Shiota399a0b32015-11-15 20:36:13 -0600635 providerService.linksVanished(deviceId);
alshabib7911a052014-10-16 17:49:37 -0700636 }
637 break;
Jonathan Hart9de692c2015-04-23 11:45:47 -0700638 case PORT_STATS_UPDATED:
639 break;
alshabib7911a052014-10-16 17:49:37 -0700640 default:
641 log.debug("Unknown event {}", event);
642 }
643 }
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700644 }
alshabib7911a052014-10-16 17:49:37 -0700645
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700646 /**
Ray Milkeyd9bbde82016-06-09 11:35:00 -0700647 * Processes device events.
648 */
649 private class InternalDeviceListener implements DeviceListener {
650 @Override
651 public void event(DeviceEvent event) {
652 if (event.type() == Type.PORT_STATS_UPDATED) {
653 return;
654 }
655
656 Runnable deviceEventProcessor = new DeviceEventProcessor(event);
657
658 eventExecutor.execute(deviceEventProcessor);
659 }
660 }
661
662 /**
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700663 * Processes incoming packets.
664 */
665 private class InternalPacketProcessor implements PacketProcessor {
alshabib7911a052014-10-16 17:49:37 -0700666 @Override
667 public void process(PacketContext context) {
Thomas Vachuska347cc872015-09-23 10:25:29 -0700668 if (context == null || context.isHandled()) {
alshabib4a179dc2014-10-17 17:17:01 -0700669 return;
670 }
Thomas Vachuska347cc872015-09-23 10:25:29 -0700671
672 Ethernet eth = context.inPacket().parsed();
673 if (eth == null || (eth.getEtherType() != TYPE_LLDP && eth.getEtherType() != TYPE_BSN)) {
674 return;
675 }
676
Thomas Vachuska96f3ea72015-09-08 13:50:12 -0700677 LinkDiscovery ld = discoverers.get(context.inPacket().receivedFrom().deviceId());
alshabib7911a052014-10-16 17:49:37 -0700678 if (ld == null) {
679 return;
680 }
681
Jonathan Hartb35540a2015-11-17 09:30:56 -0800682 if (ld.handleLldp(context)) {
alshabib7911a052014-10-16 17:49:37 -0700683 context.block();
684 }
685 }
686 }
687
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700688 /**
689 * Auxiliary task to keep device ports up to date.
690 */
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800691 private final class SyncDeviceInfoTask implements Runnable {
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800692 @Override
693 public void run() {
694 if (Thread.currentThread().isInterrupted()) {
695 log.info("Interrupted, quitting");
696 return;
697 }
698 // check what deviceService sees, to see if we are missing anything
699 try {
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700700 loadDevices();
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800701 } catch (Exception e) {
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700702 // Catch all exceptions to avoid task being suppressed
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800703 log.error("Exception thrown during synchronization process", e);
704 }
705 }
706 }
707
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700708 /**
709 * Auxiliary task for pruning stale links.
710 */
711 private class LinkPrunerTask implements Runnable {
712 @Override
713 public void run() {
714 if (Thread.currentThread().isInterrupted()) {
715 log.info("Interrupted, quitting");
716 return;
717 }
718
719 try {
720 // TODO: There is still a slight possibility of mastership
721 // change occurring right with link going stale. This will
722 // result in the stale link not being pruned.
723 Maps.filterEntries(linkTimes, e -> {
724 if (!masterService.isLocalMaster(e.getKey().dst().deviceId())) {
725 return true;
726 }
727 if (isStale(e.getValue())) {
728 providerService.linkVanished(new DefaultLinkDescription(e.getKey().src(),
729 e.getKey().dst(),
730 DIRECT));
731 return true;
732 }
733 return false;
734 }).clear();
735
736 } catch (Exception e) {
737 // Catch all exceptions to avoid task being suppressed
Ray Milkeye80e18f2016-06-02 16:44:14 -0700738 if (!shuttingDown) {
739 // Error condition
740 log.error("Exception thrown during link pruning process", e);
741 } else {
742 // Provider is shutting down, the error can be ignored
743 log.trace("Shutting down, ignoring error", e);
744 }
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700745 }
746 }
747
748 private boolean isStale(long lastSeen) {
749 return lastSeen < System.currentTimeMillis() - staleLinkAge;
750 }
751 }
752
753 /**
754 * Provides processing context for the device link discovery helpers.
755 */
Ray Milkey957390e2016-02-09 10:02:46 -0800756 private class InternalDiscoveryContext implements LinkDiscoveryContext {
Thomas Vachuska05453c92015-09-09 14:40:49 -0700757 @Override
758 public MastershipService mastershipService() {
759 return masterService;
760 }
761
762 @Override
763 public LinkProviderService providerService() {
764 return providerService;
765 }
766
767 @Override
768 public PacketService packetService() {
769 return packetService;
770 }
771
772 @Override
773 public long probeRate() {
774 return probeRate;
775 }
776
777 @Override
Jonathan Hartb35540a2015-11-17 09:30:56 -0800778 public boolean useBddp() {
779 return useBddp;
Thomas Vachuska05453c92015-09-09 14:40:49 -0700780 }
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700781
782 @Override
783 public void touchLink(LinkKey key) {
784 linkTimes.put(key, System.currentTimeMillis());
785 }
Ayaka Koshibe12c8c082015-12-08 12:48:46 -0800786
787 @Override
Ayaka Koshibe48229222016-05-16 18:04:26 -0700788 public DeviceService deviceService() {
789 return deviceService;
Ayaka Koshibe3ddb7b22015-12-10 17:32:59 -0800790 }
791
792 @Override
Ayaka Koshibe48229222016-05-16 18:04:26 -0700793 public String fingerprint() {
794 return buildSrcMac();
Ayaka Koshibe12c8c082015-12-08 12:48:46 -0800795 }
Thomas Vachuska05453c92015-09-09 14:40:49 -0700796 }
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700797
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800798 static final EnumSet<NetworkConfigEvent.Type> CONFIG_CHANGED
799 = EnumSet.of(NetworkConfigEvent.Type.CONFIG_ADDED,
800 NetworkConfigEvent.Type.CONFIG_UPDATED,
801 NetworkConfigEvent.Type.CONFIG_REMOVED);
802
Naoki Shiota399a0b32015-11-15 20:36:13 -0600803 private class InternalConfigListener implements NetworkConfigListener {
804
805 private synchronized void reconfigureSuppressionRules(SuppressionConfig cfg) {
806 if (cfg == null) {
Ray Milkey0a8ee912016-06-13 09:58:12 -0700807 log.debug("Suppression Config is null.");
Naoki Shiota399a0b32015-11-15 20:36:13 -0600808 return;
809 }
810
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800811 SuppressionRules newRules = new SuppressionRules(cfg.deviceTypes(),
Naoki Shiota399a0b32015-11-15 20:36:13 -0600812 cfg.annotation());
813
814 updateRules(newRules);
815 }
816
Jon Hall125c3f22017-08-09 13:46:28 -0700817 private boolean isRelevantDeviceEvent(NetworkConfigEvent event) {
818 return event.configClass() == LinkDiscoveryFromDevice.class &&
819 CONFIG_CHANGED.contains(event.type());
820 }
821
822 private boolean isRelevantPortEvent(NetworkConfigEvent event) {
823 return event.configClass() == LinkDiscoveryFromPort.class &&
824 CONFIG_CHANGED.contains(event.type());
825 }
826
827 private boolean isRelevantSuppressionEvent(NetworkConfigEvent event) {
828 return (event.configClass().equals(SuppressionConfig.class) &&
829 (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
830 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED));
831 }
832
Naoki Shiota399a0b32015-11-15 20:36:13 -0600833 @Override
834 public void event(NetworkConfigEvent event) {
Ray Milkeyd9bbde82016-06-09 11:35:00 -0700835 eventExecutor.execute(() -> {
Jon Hall125c3f22017-08-09 13:46:28 -0700836 if (isRelevantDeviceEvent(event)) {
Thomas Vachuskab5f6f522016-03-01 13:52:10 -0800837 if (event.subject() instanceof DeviceId) {
838 final DeviceId did = (DeviceId) event.subject();
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800839 Device device = deviceService.getDevice(did);
Thomas Vachuskab5f6f522016-03-01 13:52:10 -0800840 updateDevice(device).ifPresent(ld -> updatePorts(ld, did));
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800841 }
Jon Hall125c3f22017-08-09 13:46:28 -0700842 } else if (isRelevantPortEvent(event)) {
Thomas Vachuskab5f6f522016-03-01 13:52:10 -0800843 if (event.subject() instanceof ConnectPoint) {
844 ConnectPoint cp = (ConnectPoint) event.subject();
845 if (cp.elementId() instanceof DeviceId) {
846 final DeviceId did = (DeviceId) cp.elementId();
847 Device device = deviceService.getDevice(did);
848 Port port = deviceService.getPort(did, cp.port());
849 updateDevice(device).ifPresent(ld -> updatePort(ld, port));
850 }
851 }
Jon Hall125c3f22017-08-09 13:46:28 -0700852 } else if (isRelevantSuppressionEvent(event)) {
Thomas Vachuskab5f6f522016-03-01 13:52:10 -0800853 SuppressionConfig cfg = cfgRegistry.getConfig(appId, SuppressionConfig.class);
854 reconfigureSuppressionRules(cfg);
855 log.trace("Network config reconfigured");
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800856 }
Thomas Vachuskab5f6f522016-03-01 13:52:10 -0800857 });
Naoki Shiota399a0b32015-11-15 20:36:13 -0600858 }
859 }
alshabib7911a052014-10-16 17:49:37 -0700860}