blob: 06de0f9511c3c3acb734da4298111ac1e859baa4 [file] [log] [blame]
Ray Milkeyb7f0f642016-01-22 16:08:14 -08001/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
Ray Milkeyb7f0f642016-01-22 16:08:14 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package org.onosproject.provider.netcfglinks;
17
Ray Milkeyb7f0f642016-01-22 16:08:14 -080018import org.onlab.packet.Ethernet;
19import org.onlab.packet.ONOSLLDP;
Ayaka Koshibe48229222016-05-16 18:04:26 -070020import org.onosproject.cluster.ClusterMetadataService;
Ray Milkeyb7f0f642016-01-22 16:08:14 -080021import org.onosproject.core.ApplicationId;
22import org.onosproject.core.CoreService;
23import org.onosproject.mastership.MastershipService;
24import org.onosproject.net.ConnectPoint;
25import org.onosproject.net.DefaultAnnotations;
26import org.onosproject.net.Device;
27import org.onosproject.net.DeviceId;
28import org.onosproject.net.Link;
29import org.onosproject.net.LinkKey;
30import org.onosproject.net.Port;
31import org.onosproject.net.PortNumber;
32import org.onosproject.net.config.NetworkConfigEvent;
33import org.onosproject.net.config.NetworkConfigListener;
34import org.onosproject.net.config.NetworkConfigRegistry;
35import org.onosproject.net.config.basics.BasicLinkConfig;
36import org.onosproject.net.device.DeviceEvent;
37import org.onosproject.net.device.DeviceListener;
38import org.onosproject.net.device.DeviceService;
39import org.onosproject.net.flow.DefaultTrafficSelector;
40import org.onosproject.net.flow.TrafficSelector;
41import org.onosproject.net.link.DefaultLinkDescription;
Ray Milkeyb7f0f642016-01-22 16:08:14 -080042import org.onosproject.net.link.LinkProviderRegistry;
43import org.onosproject.net.link.LinkProviderService;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070044import org.onosproject.net.link.ProbedLinkProvider;
Ray Milkeyb7f0f642016-01-22 16:08:14 -080045import org.onosproject.net.packet.InboundPacket;
46import org.onosproject.net.packet.PacketContext;
47import org.onosproject.net.packet.PacketPriority;
48import org.onosproject.net.packet.PacketProcessor;
49import org.onosproject.net.packet.PacketService;
50import org.onosproject.net.provider.AbstractProvider;
51import org.onosproject.net.provider.ProviderId;
Ray Milkey957390e2016-02-09 10:02:46 -080052import org.onosproject.provider.lldpcommon.LinkDiscovery;
Ray Milkeyd84f89b2018-08-17 14:54:17 -070053import org.onosproject.provider.lldpcommon.LinkDiscoveryContext;
54import org.osgi.service.component.annotations.Activate;
55import org.osgi.service.component.annotations.Component;
56import org.osgi.service.component.annotations.Deactivate;
57import org.osgi.service.component.annotations.Reference;
58import org.osgi.service.component.annotations.ReferenceCardinality;
Ray Milkeyb7f0f642016-01-22 16:08:14 -080059import org.slf4j.Logger;
60import org.slf4j.LoggerFactory;
61
Ray Milkeyd84f89b2018-08-17 14:54:17 -070062import java.util.HashSet;
63import java.util.Map;
64import java.util.Optional;
65import java.util.Set;
66import java.util.concurrent.ConcurrentHashMap;
67
Ray Milkeyb7f0f642016-01-22 16:08:14 -080068import static org.onlab.packet.Ethernet.TYPE_BSN;
69import static org.onlab.packet.Ethernet.TYPE_LLDP;
70import static org.onosproject.net.PortNumber.portNumber;
Ray Milkeyd17309c2018-10-18 09:34:54 -070071import static org.onosproject.provider.netcfglinks.OsgiPropertyConstants.DISCOVERY_DELAY_DEFAULT;
72import static org.onosproject.provider.netcfglinks.OsgiPropertyConstants.PROP_DISCOVERY_DELAY;
Thomas Vachuska4167c3f2018-10-16 07:16:31 -070073import static org.onosproject.provider.netcfglinks.OsgiPropertyConstants.PROP_PROBE_RATE;
74import static org.onosproject.provider.netcfglinks.OsgiPropertyConstants.PROBE_RATE_DEFAULT;
Ray Milkeyb7f0f642016-01-22 16:08:14 -080075
76/**
77 * Provider to pre-discover links and devices based on a specified network
78 * config.
79 */
80
Thomas Vachuska4167c3f2018-10-16 07:16:31 -070081@Component(immediate = true,
82 property = {
83 PROP_PROBE_RATE + ":Integer=" + PROBE_RATE_DEFAULT,
Ray Milkeyd17309c2018-10-18 09:34:54 -070084 PROP_DISCOVERY_DELAY + ":Integer=" + DISCOVERY_DELAY_DEFAULT,
Thomas Vachuska4167c3f2018-10-16 07:16:31 -070085 })
Ray Milkeyb7f0f642016-01-22 16:08:14 -080086public class NetworkConfigLinksProvider
87 extends AbstractProvider
Ayaka Koshibe48229222016-05-16 18:04:26 -070088 implements ProbedLinkProvider {
Ray Milkeyb7f0f642016-01-22 16:08:14 -080089
Ray Milkeyd84f89b2018-08-17 14:54:17 -070090 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeyb7f0f642016-01-22 16:08:14 -080091 protected LinkProviderRegistry providerRegistry;
92
Ray Milkeyd84f89b2018-08-17 14:54:17 -070093 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeyb7f0f642016-01-22 16:08:14 -080094 protected DeviceService deviceService;
95
Ray Milkeyd84f89b2018-08-17 14:54:17 -070096 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeyb7f0f642016-01-22 16:08:14 -080097 protected PacketService packetService;
98
Ray Milkeyd84f89b2018-08-17 14:54:17 -070099 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800100 protected MastershipService masterService;
101
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700102 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800103 protected NetworkConfigRegistry netCfgService;
104
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700105 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800106 protected CoreService coreService;
107
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700108 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ayaka Koshibe48229222016-05-16 18:04:26 -0700109 protected ClusterMetadataService metadataService;
110
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700111 //@Property(name = PROP_PROBE_RATE, intValue = DEFAULT_PROBE_RATE,
112 // label = "LLDP and BDDP probe rate specified in millis")
Thomas Vachuska4167c3f2018-10-16 07:16:31 -0700113 private int probeRate = PROBE_RATE_DEFAULT;
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800114
Ray Milkeyd17309c2018-10-18 09:34:54 -0700115 //@Property(name = PROP_DISCOVERY_DELAY, intValue = DEFAULT_DISCOVERY_DELAY,
116 // label = "Number of millis beyond which an LLDP packet will not be accepted")
117 private int maxDiscoveryDelayMs = DISCOVERY_DELAY_DEFAULT;
Samuel Jero31e16f52018-09-21 10:34:28 -0400118
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800119 // Device link discovery helpers.
120 protected final Map<DeviceId, LinkDiscovery> discoverers = new ConcurrentHashMap<>();
121
Ray Milkey957390e2016-02-09 10:02:46 -0800122 private final LinkDiscoveryContext context = new InternalDiscoveryContext();
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800123
124 private LinkProviderService providerService;
125
126 private static final String PROVIDER_NAME =
127 "org.onosproject.provider.netcfglinks";
128 private final Logger log = LoggerFactory.getLogger(getClass());
129
130 private ApplicationId appId;
131 private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
132 private final InternalDeviceListener deviceListener = new InternalDeviceListener();
133 private final InternalConfigListener cfgListener = new InternalConfigListener();
134
Ray Milkeycd6ab182016-02-03 11:13:09 -0800135 protected Set<LinkKey> configuredLinks = new HashSet<>();
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800136
137 public NetworkConfigLinksProvider() {
138 super(new ProviderId("lldp", PROVIDER_NAME));
139 }
140
Sho SHIMIZU9efeb812016-08-18 09:29:20 -0700141 private String buildSrcMac() {
Ayaka Koshibe48229222016-05-16 18:04:26 -0700142 String srcMac = ProbedLinkProvider.fingerprintMac(metadataService.getClusterMetadata());
143 String defMac = ProbedLinkProvider.defaultMac();
144 if (srcMac.equals(defMac)) {
145 log.warn("Couldn't generate fingerprint. Using default value {}", defMac);
146 return defMac;
147 }
148 log.trace("Generated MAC address {}", srcMac);
149 return srcMac;
150 }
151
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800152 private void createLinks() {
153 netCfgService.getSubjects(LinkKey.class)
154 .forEach(linkKey -> configuredLinks.add(linkKey));
155 }
156
157 @Activate
158 protected void activate() {
159 log.info("Activated");
160 appId = coreService.registerApplication(PROVIDER_NAME);
161 packetService.addProcessor(packetProcessor, PacketProcessor.advisor(0));
162 providerService = providerRegistry.register(this);
163 deviceService.addListener(deviceListener);
164 netCfgService.addListener(cfgListener);
165 requestIntercepts();
166 loadDevices();
167 createLinks();
168 }
169
170 @Deactivate
171 protected void deactivate() {
172 withdrawIntercepts();
173 providerRegistry.unregister(this);
Deepa Vaddireddy21f5ae82017-05-10 18:27:30 +0530174 deviceService.removeListener(deviceListener);
175 netCfgService.removeListener(cfgListener);
176 packetService.removeProcessor(packetProcessor);
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800177 disable();
178 log.info("Deactivated");
179 }
180
181 /**
182 * Loads available devices and registers their ports to be probed.
183 */
184 private void loadDevices() {
185 deviceService.getAvailableDevices()
186 .forEach(d -> updateDevice(d)
187 .ifPresent(ld -> updatePorts(ld, d.id())));
188 }
189
190 private Optional<LinkDiscovery> updateDevice(Device device) {
191 if (device == null) {
192 return Optional.empty();
193 }
194
195 LinkDiscovery ld = discoverers.computeIfAbsent(device.id(),
Ayaka Koshibe48229222016-05-16 18:04:26 -0700196 did -> new LinkDiscovery(device, context));
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800197 if (ld.isStopped()) {
198 ld.start();
199 }
200 return Optional.of(ld);
201 }
202
203 /**
204 * Updates ports of the specified device to the specified discovery helper.
205 */
206 private void updatePorts(LinkDiscovery discoverer, DeviceId deviceId) {
207 deviceService.getPorts(deviceId).forEach(p -> updatePort(discoverer, p));
208 }
209
210
211 private void updatePort(LinkDiscovery discoverer, Port port) {
212 if (port == null) {
213 return;
214 }
215 if (port.number().isLogical()) {
216 // silently ignore logical ports
217 return;
218 }
219
220 discoverer.addPort(port);
221 }
222
223 /**
224 * Disables link discovery processing.
225 */
226 private void disable() {
227
228 providerRegistry.unregister(this);
229 discoverers.values().forEach(LinkDiscovery::stop);
230 discoverers.clear();
231
232 providerService = null;
233 }
234
235 /**
236 * Provides processing context for the device link discovery helpers.
237 */
Ray Milkey957390e2016-02-09 10:02:46 -0800238 private class InternalDiscoveryContext implements LinkDiscoveryContext {
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800239 @Override
240 public MastershipService mastershipService() {
241 return masterService;
242 }
243
244 @Override
245 public LinkProviderService providerService() {
246 return providerService;
247 }
248
249 @Override
250 public PacketService packetService() {
251 return packetService;
252 }
253
254 @Override
255 public long probeRate() {
256 return probeRate;
257 }
258
259 @Override
260 public boolean useBddp() {
261 return true;
262 }
263
264 @Override
265 public void touchLink(LinkKey key) {
Ray Milkey957390e2016-02-09 10:02:46 -0800266 }
267
268 @Override
269 public String fingerprint() {
Ayaka Koshibe48229222016-05-16 18:04:26 -0700270 return buildSrcMac();
Ray Milkey957390e2016-02-09 10:02:46 -0800271 }
272
273 @Override
274 public DeviceService deviceService() {
275 return deviceService;
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800276 }
Samuel Jero31e16f52018-09-21 10:34:28 -0400277
278 @Override
279 public String lldpSecret() {
280 return metadataService.getClusterMetadata().getClusterSecret();
281 }
282
283 @Override
284 public long maxDiscoveryDelay() {
285 return maxDiscoveryDelayMs;
286 }
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800287 }
288
Samuel Jero31e16f52018-09-21 10:34:28 -0400289 // true if *NOT* this cluster's own probe.
290 private boolean isOthercluster(String mac) {
291 // if we are using DEFAULT_MAC, clustering hadn't initialized, so conservative 'yes'
292 String ourMac = context.fingerprint();
293 if (ProbedLinkProvider.defaultMac().equalsIgnoreCase(ourMac)) {
294 return true;
295 }
296 return !mac.equalsIgnoreCase(ourMac);
297 }
298
299 //doesn't validate. Used just to decide if this is expected link.
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800300 LinkKey extractLinkKey(PacketContext packetContext) {
301 Ethernet eth = packetContext.inPacket().parsed();
302 if (eth == null) {
303 return null;
304 }
305
306 ONOSLLDP onoslldp = ONOSLLDP.parseONOSLLDP(eth);
307 if (onoslldp != null) {
308 PortNumber srcPort = portNumber(onoslldp.getPort());
309 PortNumber dstPort = packetContext.inPacket().receivedFrom().port();
310 DeviceId srcDeviceId = DeviceId.deviceId(onoslldp.getDeviceString());
311 DeviceId dstDeviceId = packetContext.inPacket().receivedFrom().deviceId();
312
313 ConnectPoint src = new ConnectPoint(srcDeviceId, srcPort);
314 ConnectPoint dst = new ConnectPoint(dstDeviceId, dstPort);
315 return LinkKey.linkKey(src, dst);
316 }
317 return null;
318 }
319
Samuel Jero31e16f52018-09-21 10:34:28 -0400320 private boolean verify(PacketContext packetContext) {
321 Ethernet eth = packetContext.inPacket().parsed();
322 if (eth == null) {
323 return false;
324 }
325
326 ONOSLLDP onoslldp = ONOSLLDP.parseONOSLLDP(eth);
327 if (onoslldp != null) {
328 if (!isOthercluster(eth.getSourceMAC().toString())) {
329 return false;
330 }
331
332 if (!ONOSLLDP.verify(onoslldp, context.lldpSecret(), context.maxDiscoveryDelay())) {
333 log.warn("LLDP Packet failed to validate!");
334 return false;
335 }
336 return true;
337 }
338 return false;
339 }
340
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800341 /**
Ray Milkeycd6ab182016-02-03 11:13:09 -0800342 * Removes after stopping discovery helper for specified device.
343 * @param deviceId device to remove
344 */
345 private void removeDevice(final DeviceId deviceId) {
346 discoverers.computeIfPresent(deviceId, (did, ld) -> {
347 ld.stop();
348 return null;
349 });
350
351 }
352
353 /**
354 * Removes a port from the specified discovery helper.
355 * @param port the port
356 */
357 private void removePort(Port port) {
358 if (port.element() instanceof Device) {
359 Device d = (Device) port.element();
360 LinkDiscovery ld = discoverers.get(d.id());
361 if (ld != null) {
362 ld.removePort(port.number());
363 }
364 } else {
365 log.warn("Attempted to remove non-Device port", port);
366 }
367 }
368
369
370 /**
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800371 * Processes incoming packets.
372 */
373 private class InternalPacketProcessor implements PacketProcessor {
374 @Override
375 public void process(PacketContext context) {
376 if (context == null || context.isHandled()) {
377 return;
378 }
379
380 Ethernet eth = context.inPacket().parsed();
381 if (eth == null || (eth.getEtherType() != TYPE_LLDP && eth.getEtherType() != TYPE_BSN)) {
382 return;
383 }
384
385 InboundPacket inPacket = context.inPacket();
386 LinkKey linkKey = extractLinkKey(context);
387 if (linkKey != null) {
388 if (configuredLinks.contains(linkKey)) {
389 log.debug("Found configured link {}", linkKey);
390 LinkDiscovery ld = discoverers.get(inPacket.receivedFrom().deviceId());
391 if (ld == null) {
392 return;
393 }
394 if (ld.handleLldp(context)) {
395 context.block();
396 }
397 } else {
Samuel Jero31e16f52018-09-21 10:34:28 -0400398 if (verify(context)) {
399 log.debug("Found link that was not in the configuration {}", linkKey);
400 providerService.linkDetected(
401 new DefaultLinkDescription(linkKey.src(),
402 linkKey.dst(),
403 Link.Type.DIRECT,
404 DefaultLinkDescription.NOT_EXPECTED,
405 DefaultAnnotations.EMPTY));
406 }
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800407 }
408 }
409 }
410 }
411
412 /**
413 * Requests packet intercepts.
414 */
415 private void requestIntercepts() {
416 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
417 selector.matchEthType(TYPE_LLDP);
418 packetService.requestPackets(selector.build(), PacketPriority.CONTROL,
419 appId, Optional.empty());
420
421 selector.matchEthType(TYPE_BSN);
422
423 packetService.requestPackets(selector.build(), PacketPriority.CONTROL,
424 appId, Optional.empty());
425
426 }
427
428 /**
429 * Withdraws packet intercepts.
430 */
431 private void withdrawIntercepts() {
432 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
433 selector.matchEthType(TYPE_LLDP);
434 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL,
435 appId, Optional.empty());
436 selector.matchEthType(TYPE_BSN);
437 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL,
438 appId, Optional.empty());
439 }
440
441 /**
442 * Processes device events.
443 */
444 private class InternalDeviceListener implements DeviceListener {
445 @Override
446 public void event(DeviceEvent event) {
447 if (event.type() == DeviceEvent.Type.PORT_STATS_UPDATED) {
448 return;
449 }
450 Device device = event.subject();
451 Port port = event.port();
452 if (device == null) {
453 log.error("Device is null.");
454 return;
455 }
456 log.trace("{} {} {}", event.type(), event.subject(), event);
457 final DeviceId deviceId = device.id();
458 switch (event.type()) {
459 case DEVICE_ADDED:
460 case DEVICE_UPDATED:
461 updateDevice(device).ifPresent(ld -> updatePorts(ld, deviceId));
462 break;
463 case PORT_ADDED:
464 case PORT_UPDATED:
465 if (port.isEnabled()) {
466 updateDevice(device).ifPresent(ld -> updatePort(ld, port));
467 } else {
468 log.debug("Port down {}", port);
Ray Milkeycd6ab182016-02-03 11:13:09 -0800469 removePort(port);
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800470 providerService.linksVanished(new ConnectPoint(port.element().id(),
471 port.number()));
472 }
473 break;
474 case PORT_REMOVED:
475 log.debug("Port removed {}", port);
Ray Milkeycd6ab182016-02-03 11:13:09 -0800476 removePort(port);
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800477 providerService.linksVanished(new ConnectPoint(port.element().id(),
478 port.number()));
479 break;
480 case DEVICE_REMOVED:
481 case DEVICE_SUSPENDED:
482 log.debug("Device removed {}", deviceId);
Ray Milkeycd6ab182016-02-03 11:13:09 -0800483 removeDevice(deviceId);
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800484 providerService.linksVanished(deviceId);
485 break;
486 case DEVICE_AVAILABILITY_CHANGED:
487 if (deviceService.isAvailable(deviceId)) {
488 log.debug("Device up {}", deviceId);
489 updateDevice(device).ifPresent(ld -> updatePorts(ld, deviceId));
490 } else {
491 log.debug("Device down {}", deviceId);
Ray Milkeycd6ab182016-02-03 11:13:09 -0800492 removeDevice(deviceId);
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800493 providerService.linksVanished(deviceId);
494 }
495 break;
496 case PORT_STATS_UPDATED:
497 break;
498 default:
499 log.debug("Unknown event {}", event);
500 }
501 }
502 }
503
504 private class InternalConfigListener implements NetworkConfigListener {
505
506 private void addLink(LinkKey linkKey) {
507 configuredLinks.add(linkKey);
508 }
509
510 private void removeLink(LinkKey linkKey) {
511 DefaultLinkDescription linkDescription =
512 new DefaultLinkDescription(linkKey.src(), linkKey.dst(),
513 Link.Type.DIRECT);
514 configuredLinks.remove(linkKey);
515 providerService.linkVanished(linkDescription);
516 }
517
518 @Override
519 public void event(NetworkConfigEvent event) {
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800520 if (event.configClass().equals(BasicLinkConfig.class)) {
521 log.info("net config event of type {} for basic link {}",
522 event.type(), event.subject());
523 LinkKey linkKey = (LinkKey) event.subject();
524 if (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED) {
525 addLink(linkKey);
526 } else if (event.type() == NetworkConfigEvent.Type.CONFIG_REMOVED) {
527 removeLink(linkKey);
528 }
Charles Chane527eff2016-05-18 14:04:57 -0700529 log.info("Link reconfigured");
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800530 }
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800531 }
532 }
533
534}