blob: 768c20704d900f1f22b8b324e3916ffbbda96b01 [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;
Thomas Vachuska4167c3f2018-10-16 07:16:31 -070090import static org.onosproject.provider.lldp.impl.OsgiPropertyConstants.*;
Marc De Leenheer0bfc2a12016-02-02 22:46:27 -080091import static org.slf4j.LoggerFactory.getLogger;
Yuta HIGUCHI41289382014-12-19 17:47:12 -080092
alshabib7911a052014-10-16 17:49:37 -070093/**
Thomas Vachuska05453c92015-09-09 14:40:49 -070094 * Provider which uses LLDP and BDDP packets to detect network infrastructure links.
alshabib7911a052014-10-16 17:49:37 -070095 */
Thomas Vachuska4167c3f2018-10-16 07:16:31 -070096@Component(immediate = true,
97 property = {
98 PROP_ENABLED + ":Boolean=" + ENABLED_DEFAULT,
99 PROP_USE_BDDP + ":Boolean=" + USE_BDDP_DEFAULT,
100 PROP_PROBE_RATE + ":Integer=" + PROBE_RATE_DEFAULT,
101 PROP_STALE_LINK_AGE + ":Integer=" + STALE_LINK_AGE_DEFAULT,
Ray Milkeyd17309c2018-10-18 09:34:54 -0700102 PROP_DISCOVERY_DELAY + ":Integer=" + DISCOVERY_DELAY_DEFAULT,
Thomas Vachuska4167c3f2018-10-16 07:16:31 -0700103 })
Ayaka Koshibe48229222016-05-16 18:04:26 -0700104public class LldpLinkProvider extends AbstractProvider implements ProbedLinkProvider {
alshabib7911a052014-10-16 17:49:37 -0700105
Thomas Vachuskafc52fec2015-05-18 19:13:56 -0700106 private static final String PROVIDER_NAME = "org.onosproject.provider.lldp";
107
Thomas Vachuska05453c92015-09-09 14:40:49 -0700108 private static final String FORMAT =
109 "Settings: enabled={}, useBDDP={}, probeRate={}, " +
Samuel Jero31e16f52018-09-21 10:34:28 -0400110 "staleLinkAge={}, maxLLDPage={}";
Yuta HIGUCHI41289382014-12-19 17:47:12 -0800111
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700112 // When a Device/Port has this annotation, do not send out LLDP/BDDP
113 public static final String NO_LLDP = "no-lldp";
114
alshabib7911a052014-10-16 17:49:37 -0700115 private final Logger log = getLogger(getClass());
116
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700117 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800118 protected CoreService coreService;
119
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700120 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabib7911a052014-10-16 17:49:37 -0700121 protected LinkProviderRegistry providerRegistry;
122
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700123 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabib7911a052014-10-16 17:49:37 -0700124 protected DeviceService deviceService;
125
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700126 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700127 protected LinkService linkService;
128
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700129 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Marc De Leenheer8b3e80b2015-03-06 14:27:03 -0800130 protected PacketService packetService;
alshabib7911a052014-10-16 17:49:37 -0700131
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700132 @Reference(cardinality = ReferenceCardinality.MANDATORY)
alshabib875d6262014-10-17 16:19:40 -0700133 protected MastershipService masterService;
134
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700135 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Thomas Vachuska6519e6f2015-03-11 02:29:31 -0700136 protected ComponentConfigService cfgService;
137
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700138 @Reference(cardinality = ReferenceCardinality.MANDATORY)
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700139 protected ClusterService clusterService;
140
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700141 @Reference(cardinality = ReferenceCardinality.MANDATORY)
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700142 protected NetworkConfigRegistry cfgRegistry;
143
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700144 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ayaka Koshibe12c8c082015-12-08 12:48:46 -0800145 protected ClusterMetadataService clusterMetadataService;
146
alshabib7911a052014-10-16 17:49:37 -0700147 private LinkProviderService providerService;
148
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800149 private ScheduledExecutorService executor;
Ray Milkeyd9bbde82016-06-09 11:35:00 -0700150 protected ExecutorService eventExecutor;
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800151
Ray Milkeye80e18f2016-06-02 16:44:14 -0700152 private boolean shuttingDown = false;
153
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700154 // TODO: Add sanity checking for the configurable params based on the delays
155 private static final long DEVICE_SYNC_DELAY = 5;
156 private static final long LINK_PRUNER_DELAY = 3;
Thomas Vachuska05453c92015-09-09 14:40:49 -0700157
Thomas Vachuska24d4f6d2018-10-19 11:25:04 -0700158 /** If false, link discovery is disabled. */
Ray Milkey7e7bd862018-10-18 08:53:34 -0700159 protected boolean enabled = false;
Thomas Vachuska05453c92015-09-09 14:40:49 -0700160
Thomas Vachuska24d4f6d2018-10-19 11:25:04 -0700161 /** Use BDDP for link discovery. */
Thomas Vachuska1c23d042018-10-17 10:05:19 -0700162 protected boolean useBddp = USE_BDDP_DEFAULT;
alshabib7911a052014-10-16 17:49:37 -0700163
Thomas Vachuska24d4f6d2018-10-19 11:25:04 -0700164 /** LLDP and BDDP probe rate specified in millis. */
Thomas Vachuska1c23d042018-10-17 10:05:19 -0700165 protected int probeRate = PROBE_RATE_DEFAULT;
Saurav Dasc313c402015-02-27 10:09:47 -0800166
Thomas Vachuska24d4f6d2018-10-19 11:25:04 -0700167 /** Number of millis beyond which links will be considered stale. */
Thomas Vachuska1c23d042018-10-17 10:05:19 -0700168 protected int staleLinkAge = STALE_LINK_AGE_DEFAULT;
alshabib7911a052014-10-16 17:49:37 -0700169
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -0700170 /** Number of millis beyond which an LLDP packet will not be accepted. */
Ray Milkeyd17309c2018-10-18 09:34:54 -0700171 private int maxDiscoveryDelayMs = DISCOVERY_DELAY_DEFAULT;
Samuel Jero31e16f52018-09-21 10:34:28 -0400172
Ray Milkey957390e2016-02-09 10:02:46 -0800173 private final LinkDiscoveryContext context = new InternalDiscoveryContext();
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800174 private final InternalRoleListener roleListener = new InternalRoleListener();
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700175 private final InternalDeviceListener deviceListener = new InternalDeviceListener();
176 private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800177
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700178 // Device link discovery helpers.
alshabib7911a052014-10-16 17:49:37 -0700179 protected final Map<DeviceId, LinkDiscovery> discoverers = new ConcurrentHashMap<>();
180
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700181 // Most recent time a tracked link was seen; links are tracked if their
182 // destination connection point is mastered by this controller instance.
183 private final Map<LinkKey, Long> linkTimes = Maps.newConcurrentMap();
184
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800185 private ApplicationId appId;
Yuta HIGUCHI41289382014-12-19 17:47:12 -0800186
Naoki Shiota399a0b32015-11-15 20:36:13 -0600187 static final SuppressionRules DEFAULT_RULES
Yuta HIGUCHI09697d02017-03-03 16:53:39 -0800188 = new SuppressionRules(EnumSet.of(Device.Type.ROADM,
189 Device.Type.FIBER_SWITCH,
190 Device.Type.OPTICAL_AMPLIFIER,
Andrea Campanellafa0f6cc2018-12-18 15:17:53 +0100191 Device.Type.OTN,
Andrea Campanella1c24fb92018-12-20 16:43:59 +0100192 Device.Type.OLS,
193 Device.Type.TERMINAL_DEVICE),
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;
Samuel Jero31e16f52018-09-21 10:34:28 -0400298 int newProbeRate, newStaleLinkAge, newDiscoveryDelay;
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
Samuel Jero31e16f52018-09-21 10:34:28 -0400312 s = get(properties, PROP_DISCOVERY_DELAY);
313 newDiscoveryDelay = isNullOrEmpty(s) ? maxDiscoveryDelayMs : Integer.parseInt(s.trim());
314
Thomas Vachuska05453c92015-09-09 14:40:49 -0700315 } catch (NumberFormatException e) {
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700316 log.warn("Component configuration had invalid values", e);
Thomas Vachuska05453c92015-09-09 14:40:49 -0700317 newEnabled = enabled;
Jonathan Hartb35540a2015-11-17 09:30:56 -0800318 newUseBddp = useBddp;
Thomas Vachuska05453c92015-09-09 14:40:49 -0700319 newProbeRate = probeRate;
320 newStaleLinkAge = staleLinkAge;
Samuel Jero31e16f52018-09-21 10:34:28 -0400321 newDiscoveryDelay = maxDiscoveryDelayMs;
Saurav Dasc313c402015-02-27 10:09:47 -0800322 }
Yuta HIGUCHI41289382014-12-19 17:47:12 -0800323
Thomas Vachuska05453c92015-09-09 14:40:49 -0700324 boolean wasEnabled = enabled;
325
326 enabled = newEnabled;
Jonathan Hartb35540a2015-11-17 09:30:56 -0800327 useBddp = newUseBddp;
Thomas Vachuska05453c92015-09-09 14:40:49 -0700328 probeRate = newProbeRate;
329 staleLinkAge = newStaleLinkAge;
Samuel Jero31e16f52018-09-21 10:34:28 -0400330 maxDiscoveryDelayMs = newDiscoveryDelay;
Thomas Vachuska05453c92015-09-09 14:40:49 -0700331
332 if (!wasEnabled && enabled) {
333 enable();
334 } else if (wasEnabled && !enabled) {
335 disable();
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700336 } else {
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700337 if (enabled) {
338 // update all discovery helper state
339 loadDevices();
340 }
Thomas Vachuska05453c92015-09-09 14:40:49 -0700341 }
342
Samuel Jero31e16f52018-09-21 10:34:28 -0400343 log.info(FORMAT, enabled, useBddp, probeRate, staleLinkAge, maxDiscoveryDelayMs);
Thomas Vachuska05453c92015-09-09 14:40:49 -0700344 }
345
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700346 /**
347 * Enables link discovery processing.
348 */
Thomas Vachuska05453c92015-09-09 14:40:49 -0700349 private void enable() {
alshabib7911a052014-10-16 17:49:37 -0700350 providerService = providerRegistry.register(this);
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800351 masterService.addListener(roleListener);
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700352 deviceService.addListener(deviceListener);
353 packetService.addProcessor(packetProcessor, PacketProcessor.advisor(0));
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800354
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700355 loadDevices();
Thomas Vachuska05453c92015-09-09 14:40:49 -0700356
HIGUCHI Yutad9e01052016-04-14 09:31:42 -0700357 executor = newSingleThreadScheduledExecutor(groupedThreads("onos/link", "discovery-%d", log));
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700358 executor.scheduleAtFixedRate(new SyncDeviceInfoTask(),
359 DEVICE_SYNC_DELAY, DEVICE_SYNC_DELAY, SECONDS);
360 executor.scheduleAtFixedRate(new LinkPrunerTask(),
361 LINK_PRUNER_DELAY, LINK_PRUNER_DELAY, SECONDS);
Thomas Vachuska05453c92015-09-09 14:40:49 -0700362
Thomas Vachuska05453c92015-09-09 14:40:49 -0700363 requestIntercepts();
364 }
365
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700366 /**
367 * Disables link discovery processing.
368 */
Thomas Vachuska05453c92015-09-09 14:40:49 -0700369 private void disable() {
370 withdrawIntercepts();
371
372 providerRegistry.unregister(this);
Thomas Vachuska05453c92015-09-09 14:40:49 -0700373 masterService.removeListener(roleListener);
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700374 deviceService.removeListener(deviceListener);
375 packetService.removeProcessor(packetProcessor);
Thomas Vachuska05453c92015-09-09 14:40:49 -0700376
377 if (executor != null) {
378 executor.shutdownNow();
379 }
380 discoverers.values().forEach(LinkDiscovery::stop);
381 discoverers.clear();
Jon Hall125c3f22017-08-09 13:46:28 -0700382 linkTimes.clear();
Thomas Vachuska05453c92015-09-09 14:40:49 -0700383
384 providerService = null;
385 }
386
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700387 /**
388 * Loads available devices and registers their ports to be probed.
389 */
390 private void loadDevices() {
Ray Milkey0f87d482016-07-06 11:49:19 -0700391 if (!enabled || deviceService == null) {
Naoki Shiota399a0b32015-11-15 20:36:13 -0600392 return;
393 }
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700394 deviceService.getAvailableDevices()
395 .forEach(d -> updateDevice(d)
396 .ifPresent(ld -> updatePorts(ld, d.id())));
397 }
398
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800399 private boolean isBlacklisted(DeviceId did) {
400 LinkDiscoveryFromDevice cfg = cfgRegistry.getConfig(did, LinkDiscoveryFromDevice.class);
401 if (cfg == null) {
402 return false;
403 }
404 return !cfg.enabled();
405 }
406
407 private boolean isBlacklisted(ConnectPoint cp) {
408 // if parent device is blacklisted, so is the port
409 if (isBlacklisted(cp.deviceId())) {
410 return true;
411 }
412 LinkDiscoveryFromPort cfg = cfgRegistry.getConfig(cp, LinkDiscoveryFromPort.class);
413 if (cfg == null) {
414 return false;
415 }
416 return !cfg.enabled();
417 }
418
419 private boolean isBlacklisted(Port port) {
420 return isBlacklisted(new ConnectPoint(port.element().id(), port.number()));
421 }
422
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700423 /**
424 * Updates discovery helper for specified device.
425 *
426 * Adds and starts a discovery helper for specified device if enabled,
427 * calls {@link #removeDevice(DeviceId)} otherwise.
428 *
429 * @param device device to add
430 * @return discovery helper if discovery is enabled for the device
431 */
432 private Optional<LinkDiscovery> updateDevice(Device device) {
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800433 if (device == null) {
434 return Optional.empty();
435 }
Jon Hall125c3f22017-08-09 13:46:28 -0700436 if (!masterService.isLocalMaster(device.id())) {
437 // Reset the last seen time for all links to this device
438 // then stop discovery for this device
439 List<LinkKey> updateLinks = new LinkedList<>();
440 linkTimes.forEach((link, time) -> {
441 if (link.dst().deviceId().equals(device.id())) {
442 updateLinks.add(link);
443 }
444 });
445 updateLinks.forEach(link -> linkTimes.remove(link));
446 removeDevice(device.id());
447 return Optional.empty();
448 }
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800449 if (rules.isSuppressed(device) || isBlacklisted(device.id())) {
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700450 log.trace("LinkDiscovery from {} disabled by configuration", device.id());
451 removeDevice(device.id());
452 return Optional.empty();
453 }
Ayaka Koshibe3ddb7b22015-12-10 17:32:59 -0800454
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700455 LinkDiscovery ld = discoverers.computeIfAbsent(device.id(),
DongRyeol Chac80570b2018-11-07 11:55:32 +0900456 did -> new LinkDiscovery(device.id(), context));
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700457 if (ld.isStopped()) {
458 ld.start();
459 }
460 return Optional.of(ld);
461 }
462
463 /**
464 * Removes after stopping discovery helper for specified device.
465 * @param deviceId device to remove
466 */
467 private void removeDevice(final DeviceId deviceId) {
468 discoverers.computeIfPresent(deviceId, (did, ld) -> {
469 ld.stop();
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700470 return null;
471 });
472
473 }
474
475 /**
476 * Updates ports of the specified device to the specified discovery helper.
477 */
478 private void updatePorts(LinkDiscovery discoverer, DeviceId deviceId) {
479 deviceService.getPorts(deviceId).forEach(p -> updatePort(discoverer, p));
480 }
481
482 /**
483 * Updates discovery helper state of the specified port.
484 *
485 * Adds a port to the discovery helper if up and discovery is enabled,
486 * or calls {@link #removePort(Port)} otherwise.
487 */
488 private void updatePort(LinkDiscovery discoverer, Port port) {
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800489 if (port == null) {
490 return;
491 }
HIGUCHI Yutab853b3f2015-11-17 18:43:20 -0800492 if (port.number().isLogical()) {
493 // silently ignore logical ports
494 return;
495 }
Naoki Shiota399a0b32015-11-15 20:36:13 -0600496
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800497 if (rules.isSuppressed(port) || isBlacklisted(port)) {
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700498 log.trace("LinkDiscovery from {} disabled by configuration", port);
499 removePort(port);
500 return;
501 }
502
503 // check if enabled and turn off discovery?
504 if (!port.isEnabled()) {
505 removePort(port);
506 return;
507 }
508
HIGUCHI Yutab853b3f2015-11-17 18:43:20 -0800509 discoverer.addPort(port);
alshabib7911a052014-10-16 17:49:37 -0700510 }
511
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700512 /**
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700513 * Removes a port from the specified discovery helper.
514 * @param port the port
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700515 */
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700516 private void removePort(Port port) {
517 if (port.element() instanceof Device) {
518 Device d = (Device) port.element();
519 LinkDiscovery ld = discoverers.get(d.id());
520 if (ld != null) {
521 ld.removePort(port.number());
Jonathan Hart45066bc2015-07-28 11:18:34 -0700522 }
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700523 } else {
524 log.warn("Attempted to remove non-Device port", port);
Jonathan Hart45066bc2015-07-28 11:18:34 -0700525 }
526 }
527
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700528 /**
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700529 * Requests packet intercepts.
Charles M.C. Chane148de82015-05-06 12:38:21 +0800530 */
Thomas Vachuska27bee092015-06-23 19:03:10 -0700531 private void requestIntercepts() {
532 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
Thomas Vachuska347cc872015-09-23 10:25:29 -0700533 selector.matchEthType(TYPE_LLDP);
Thomas Vachuska27bee092015-06-23 19:03:10 -0700534 packetService.requestPackets(selector.build(), PacketPriority.CONTROL, appId);
Jonathan Hart3cfce8e2015-01-14 16:43:27 -0800535
Thomas Vachuska347cc872015-09-23 10:25:29 -0700536 selector.matchEthType(TYPE_BSN);
Jonathan Hartb35540a2015-11-17 09:30:56 -0800537 if (useBddp) {
Thomas Vachuska27bee092015-06-23 19:03:10 -0700538 packetService.requestPackets(selector.build(), PacketPriority.CONTROL, appId);
539 } else {
540 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId);
Pavlin Radoslavovd36a74b2015-01-09 11:59:07 -0800541 }
542 }
543
Thomas Vachuska27bee092015-06-23 19:03:10 -0700544 /**
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700545 * Withdraws packet intercepts.
Thomas Vachuska27bee092015-06-23 19:03:10 -0700546 */
547 private void withdrawIntercepts() {
548 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
Thomas Vachuska347cc872015-09-23 10:25:29 -0700549 selector.matchEthType(TYPE_LLDP);
Thomas Vachuska27bee092015-06-23 19:03:10 -0700550 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId);
Thomas Vachuska347cc872015-09-23 10:25:29 -0700551 selector.matchEthType(TYPE_BSN);
Thomas Vachuska27bee092015-06-23 19:03:10 -0700552 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL, appId);
553 }
554
Naoki Shiota399a0b32015-11-15 20:36:13 -0600555 protected SuppressionRules rules() {
556 return rules;
557 }
558
559 protected void updateRules(SuppressionRules newRules) {
560 if (!rules.equals(newRules)) {
561 rules = newRules;
562 loadDevices();
563 }
564 }
565
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700566 /**
567 * Processes device mastership role changes.
568 */
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800569 private class InternalRoleListener implements MastershipListener {
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800570 @Override
571 public void event(MastershipEvent event) {
Jordan Halterman9d982a52017-12-11 15:27:37 -0800572 if (event.type() == MastershipEvent.Type.MASTER_CHANGED) {
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800573 // only need new master events
Jon Hall7a8bfc62016-05-26 17:59:04 -0700574 eventExecutor.execute(() -> {
575 DeviceId deviceId = event.subject();
576 Device device = deviceService.getDevice(deviceId);
577 if (device == null) {
578 log.debug("Device {} doesn't exist, or isn't there yet", deviceId);
579 return;
580 }
Jordan Halterman9d982a52017-12-11 15:27:37 -0800581 updateDevice(device).ifPresent(ld -> updatePorts(ld, device.id()));
Jon Hall7a8bfc62016-05-26 17:59:04 -0700582 });
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800583 }
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800584 }
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800585 }
alshabib7911a052014-10-16 17:49:37 -0700586
Ray Milkeyd9bbde82016-06-09 11:35:00 -0700587 private class DeviceEventProcessor implements Runnable {
588
589 DeviceEvent event;
590
591 DeviceEventProcessor(DeviceEvent event) {
592 this.event = event;
593 }
594
alshabib7911a052014-10-16 17:49:37 -0700595 @Override
Ray Milkeyd9bbde82016-06-09 11:35:00 -0700596 public void run() {
alshabib7911a052014-10-16 17:49:37 -0700597 Device device = event.subject();
alshabibacd91832014-10-17 14:38:41 -0700598 Port port = event.port();
alshabibdfc7afb2014-10-21 20:13:27 -0700599 if (device == null) {
600 log.error("Device is null.");
601 return;
602 }
Yuta HIGUCHIeb24e9d2014-10-26 19:34:20 -0700603 log.trace("{} {} {}", event.type(), event.subject(), event);
Yuta HIGUCHId19f6702014-10-31 15:23:25 -0700604 final DeviceId deviceId = device.id();
alshabib7911a052014-10-16 17:49:37 -0700605 switch (event.type()) {
606 case DEVICE_ADDED:
Yuta HIGUCHIeb24e9d2014-10-26 19:34:20 -0700607 case DEVICE_UPDATED:
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700608 updateDevice(device).ifPresent(ld -> updatePorts(ld, deviceId));
alshabib7911a052014-10-16 17:49:37 -0700609 break;
610 case PORT_ADDED:
611 case PORT_UPDATED:
Yuta HIGUCHIf6725882014-10-29 15:25:51 -0700612 if (port.isEnabled()) {
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700613 updateDevice(device).ifPresent(ld -> updatePort(ld, port));
alshabib7911a052014-10-16 17:49:37 -0700614 } else {
Yuta HIGUCHIf6725882014-10-29 15:25:51 -0700615 log.debug("Port down {}", port);
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700616 removePort(port);
Naoki Shiota399a0b32015-11-15 20:36:13 -0600617 providerService.linksVanished(new ConnectPoint(port.element().id(),
618 port.number()));
alshabib7911a052014-10-16 17:49:37 -0700619 }
620 break;
621 case PORT_REMOVED:
Yuta HIGUCHIeb24e9d2014-10-26 19:34:20 -0700622 log.debug("Port removed {}", port);
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700623 removePort(port);
Naoki Shiota399a0b32015-11-15 20:36:13 -0600624 providerService.linksVanished(new ConnectPoint(port.element().id(),
625 port.number()));
alshabib7911a052014-10-16 17:49:37 -0700626 break;
627 case DEVICE_REMOVED:
628 case DEVICE_SUSPENDED:
Yuta HIGUCHId19f6702014-10-31 15:23:25 -0700629 log.debug("Device removed {}", deviceId);
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700630 removeDevice(deviceId);
Naoki Shiota399a0b32015-11-15 20:36:13 -0600631 providerService.linksVanished(deviceId);
alshabib7911a052014-10-16 17:49:37 -0700632 break;
633 case DEVICE_AVAILABILITY_CHANGED:
Yuta HIGUCHId19f6702014-10-31 15:23:25 -0700634 if (deviceService.isAvailable(deviceId)) {
635 log.debug("Device up {}", deviceId);
alshabibe3af2652015-12-01 23:05:34 -0800636 updateDevice(device).ifPresent(ld -> updatePorts(ld, deviceId));
alshabib7911a052014-10-16 17:49:37 -0700637 } else {
Yuta HIGUCHId19f6702014-10-31 15:23:25 -0700638 log.debug("Device down {}", deviceId);
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700639 removeDevice(deviceId);
Naoki Shiota399a0b32015-11-15 20:36:13 -0600640 providerService.linksVanished(deviceId);
alshabib7911a052014-10-16 17:49:37 -0700641 }
642 break;
Jonathan Hart9de692c2015-04-23 11:45:47 -0700643 case PORT_STATS_UPDATED:
644 break;
alshabib7911a052014-10-16 17:49:37 -0700645 default:
646 log.debug("Unknown event {}", event);
647 }
648 }
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700649 }
alshabib7911a052014-10-16 17:49:37 -0700650
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700651 /**
Ray Milkeyd9bbde82016-06-09 11:35:00 -0700652 * Processes device events.
653 */
654 private class InternalDeviceListener implements DeviceListener {
655 @Override
656 public void event(DeviceEvent event) {
657 if (event.type() == Type.PORT_STATS_UPDATED) {
658 return;
659 }
660
661 Runnable deviceEventProcessor = new DeviceEventProcessor(event);
662
663 eventExecutor.execute(deviceEventProcessor);
664 }
665 }
666
667 /**
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700668 * Processes incoming packets.
669 */
670 private class InternalPacketProcessor implements PacketProcessor {
alshabib7911a052014-10-16 17:49:37 -0700671 @Override
672 public void process(PacketContext context) {
Thomas Vachuska347cc872015-09-23 10:25:29 -0700673 if (context == null || context.isHandled()) {
alshabib4a179dc2014-10-17 17:17:01 -0700674 return;
675 }
Thomas Vachuska347cc872015-09-23 10:25:29 -0700676
677 Ethernet eth = context.inPacket().parsed();
678 if (eth == null || (eth.getEtherType() != TYPE_LLDP && eth.getEtherType() != TYPE_BSN)) {
679 return;
680 }
681
Thomas Vachuska96f3ea72015-09-08 13:50:12 -0700682 LinkDiscovery ld = discoverers.get(context.inPacket().receivedFrom().deviceId());
alshabib7911a052014-10-16 17:49:37 -0700683 if (ld == null) {
684 return;
685 }
686
Jonathan Hartb35540a2015-11-17 09:30:56 -0800687 if (ld.handleLldp(context)) {
alshabib7911a052014-10-16 17:49:37 -0700688 context.block();
689 }
690 }
691 }
692
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700693 /**
694 * Auxiliary task to keep device ports up to date.
695 */
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800696 private final class SyncDeviceInfoTask implements Runnable {
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800697 @Override
698 public void run() {
699 if (Thread.currentThread().isInterrupted()) {
700 log.info("Interrupted, quitting");
701 return;
702 }
703 // check what deviceService sees, to see if we are missing anything
704 try {
HIGUCHI Yuta9a9edf82015-10-21 11:23:20 -0700705 loadDevices();
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800706 } catch (Exception e) {
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700707 // Catch all exceptions to avoid task being suppressed
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800708 log.error("Exception thrown during synchronization process", e);
709 }
710 }
711 }
712
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700713 /**
714 * Auxiliary task for pruning stale links.
715 */
716 private class LinkPrunerTask implements Runnable {
717 @Override
718 public void run() {
719 if (Thread.currentThread().isInterrupted()) {
720 log.info("Interrupted, quitting");
721 return;
722 }
723
724 try {
725 // TODO: There is still a slight possibility of mastership
726 // change occurring right with link going stale. This will
727 // result in the stale link not being pruned.
728 Maps.filterEntries(linkTimes, e -> {
729 if (!masterService.isLocalMaster(e.getKey().dst().deviceId())) {
730 return true;
731 }
732 if (isStale(e.getValue())) {
733 providerService.linkVanished(new DefaultLinkDescription(e.getKey().src(),
734 e.getKey().dst(),
735 DIRECT));
736 return true;
737 }
738 return false;
739 }).clear();
740
741 } catch (Exception e) {
742 // Catch all exceptions to avoid task being suppressed
Ray Milkeye80e18f2016-06-02 16:44:14 -0700743 if (!shuttingDown) {
744 // Error condition
745 log.error("Exception thrown during link pruning process", e);
746 } else {
747 // Provider is shutting down, the error can be ignored
748 log.trace("Shutting down, ignoring error", e);
749 }
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700750 }
751 }
752
753 private boolean isStale(long lastSeen) {
754 return lastSeen < System.currentTimeMillis() - staleLinkAge;
755 }
756 }
757
758 /**
759 * Provides processing context for the device link discovery helpers.
760 */
Ray Milkey957390e2016-02-09 10:02:46 -0800761 private class InternalDiscoveryContext implements LinkDiscoveryContext {
Thomas Vachuska05453c92015-09-09 14:40:49 -0700762 @Override
763 public MastershipService mastershipService() {
764 return masterService;
765 }
766
767 @Override
768 public LinkProviderService providerService() {
769 return providerService;
770 }
771
772 @Override
773 public PacketService packetService() {
774 return packetService;
775 }
776
777 @Override
778 public long probeRate() {
779 return probeRate;
780 }
781
782 @Override
Jonathan Hartb35540a2015-11-17 09:30:56 -0800783 public boolean useBddp() {
784 return useBddp;
Thomas Vachuska05453c92015-09-09 14:40:49 -0700785 }
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700786
787 @Override
788 public void touchLink(LinkKey key) {
789 linkTimes.put(key, System.currentTimeMillis());
790 }
Ayaka Koshibe12c8c082015-12-08 12:48:46 -0800791
792 @Override
DongRyeol Chace65cc02018-07-23 15:02:28 +0900793 public void setTtl(LinkKey key, short ttl) {
794 linkTimes.put(key, System.currentTimeMillis() - staleLinkAge + SECONDS.toMillis(ttl));
795 }
796
797 @Override
Ayaka Koshibe48229222016-05-16 18:04:26 -0700798 public DeviceService deviceService() {
799 return deviceService;
Ayaka Koshibe3ddb7b22015-12-10 17:32:59 -0800800 }
801
802 @Override
Ayaka Koshibe48229222016-05-16 18:04:26 -0700803 public String fingerprint() {
804 return buildSrcMac();
Ayaka Koshibe12c8c082015-12-08 12:48:46 -0800805 }
Samuel Jero31e16f52018-09-21 10:34:28 -0400806
807 @Override
808 public String lldpSecret() {
809 return clusterMetadataService.getClusterMetadata().getClusterSecret();
810 }
811
812 @Override
813 public long maxDiscoveryDelay() {
814 return maxDiscoveryDelayMs;
815 }
Thomas Vachuska05453c92015-09-09 14:40:49 -0700816 }
Thomas Vachuskae4ebac92015-09-10 11:39:05 -0700817
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800818 static final EnumSet<NetworkConfigEvent.Type> CONFIG_CHANGED
819 = EnumSet.of(NetworkConfigEvent.Type.CONFIG_ADDED,
820 NetworkConfigEvent.Type.CONFIG_UPDATED,
821 NetworkConfigEvent.Type.CONFIG_REMOVED);
822
Naoki Shiota399a0b32015-11-15 20:36:13 -0600823 private class InternalConfigListener implements NetworkConfigListener {
824
825 private synchronized void reconfigureSuppressionRules(SuppressionConfig cfg) {
826 if (cfg == null) {
Ray Milkey0a8ee912016-06-13 09:58:12 -0700827 log.debug("Suppression Config is null.");
Naoki Shiota399a0b32015-11-15 20:36:13 -0600828 return;
829 }
830
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800831 SuppressionRules newRules = new SuppressionRules(cfg.deviceTypes(),
Naoki Shiota399a0b32015-11-15 20:36:13 -0600832 cfg.annotation());
833
834 updateRules(newRules);
835 }
836
Jon Hall125c3f22017-08-09 13:46:28 -0700837 private boolean isRelevantDeviceEvent(NetworkConfigEvent event) {
838 return event.configClass() == LinkDiscoveryFromDevice.class &&
839 CONFIG_CHANGED.contains(event.type());
840 }
841
842 private boolean isRelevantPortEvent(NetworkConfigEvent event) {
843 return event.configClass() == LinkDiscoveryFromPort.class &&
844 CONFIG_CHANGED.contains(event.type());
845 }
846
847 private boolean isRelevantSuppressionEvent(NetworkConfigEvent event) {
848 return (event.configClass().equals(SuppressionConfig.class) &&
849 (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
850 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED));
851 }
852
Naoki Shiota399a0b32015-11-15 20:36:13 -0600853 @Override
854 public void event(NetworkConfigEvent event) {
Ray Milkeyd9bbde82016-06-09 11:35:00 -0700855 eventExecutor.execute(() -> {
Jon Hall125c3f22017-08-09 13:46:28 -0700856 if (isRelevantDeviceEvent(event)) {
Thomas Vachuskab5f6f522016-03-01 13:52:10 -0800857 if (event.subject() instanceof DeviceId) {
858 final DeviceId did = (DeviceId) event.subject();
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800859 Device device = deviceService.getDevice(did);
Thomas Vachuskab5f6f522016-03-01 13:52:10 -0800860 updateDevice(device).ifPresent(ld -> updatePorts(ld, did));
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800861 }
Jon Hall125c3f22017-08-09 13:46:28 -0700862 } else if (isRelevantPortEvent(event)) {
Thomas Vachuskab5f6f522016-03-01 13:52:10 -0800863 if (event.subject() instanceof ConnectPoint) {
864 ConnectPoint cp = (ConnectPoint) event.subject();
865 if (cp.elementId() instanceof DeviceId) {
866 final DeviceId did = (DeviceId) cp.elementId();
867 Device device = deviceService.getDevice(did);
868 Port port = deviceService.getPort(did, cp.port());
869 updateDevice(device).ifPresent(ld -> updatePort(ld, port));
870 }
871 }
Jon Hall125c3f22017-08-09 13:46:28 -0700872 } else if (isRelevantSuppressionEvent(event)) {
Thomas Vachuskab5f6f522016-03-01 13:52:10 -0800873 SuppressionConfig cfg = cfgRegistry.getConfig(appId, SuppressionConfig.class);
874 reconfigureSuppressionRules(cfg);
875 log.trace("Network config reconfigured");
HIGUCHI Yutad9fe3a32015-11-24 18:52:25 -0800876 }
Thomas Vachuskab5f6f522016-03-01 13:52:10 -0800877 });
Naoki Shiota399a0b32015-11-15 20:36:13 -0600878 }
879 }
alshabib7911a052014-10-16 17:49:37 -0700880}