blob: 8bd4c41cd1107818b740da1f737c41f962ced661 [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
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -0700111 /** LLDP and BDDP probe rate specified in millis. */
Thomas Vachuska4167c3f2018-10-16 07:16:31 -0700112 private int probeRate = PROBE_RATE_DEFAULT;
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800113
Thomas Vachuska00b5d4f2018-10-30 15:13:20 -0700114 /** Number of millis beyond which an LLDP packet will not be accepted. */
Ray Milkeyd17309c2018-10-18 09:34:54 -0700115 private int maxDiscoveryDelayMs = DISCOVERY_DELAY_DEFAULT;
Samuel Jero31e16f52018-09-21 10:34:28 -0400116
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800117 // Device link discovery helpers.
118 protected final Map<DeviceId, LinkDiscovery> discoverers = new ConcurrentHashMap<>();
119
Ray Milkey957390e2016-02-09 10:02:46 -0800120 private final LinkDiscoveryContext context = new InternalDiscoveryContext();
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800121
122 private LinkProviderService providerService;
123
124 private static final String PROVIDER_NAME =
125 "org.onosproject.provider.netcfglinks";
126 private final Logger log = LoggerFactory.getLogger(getClass());
127
128 private ApplicationId appId;
129 private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
130 private final InternalDeviceListener deviceListener = new InternalDeviceListener();
131 private final InternalConfigListener cfgListener = new InternalConfigListener();
132
Ray Milkeycd6ab182016-02-03 11:13:09 -0800133 protected Set<LinkKey> configuredLinks = new HashSet<>();
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800134
135 public NetworkConfigLinksProvider() {
136 super(new ProviderId("lldp", PROVIDER_NAME));
137 }
138
Sho SHIMIZU9efeb812016-08-18 09:29:20 -0700139 private String buildSrcMac() {
Ayaka Koshibe48229222016-05-16 18:04:26 -0700140 String srcMac = ProbedLinkProvider.fingerprintMac(metadataService.getClusterMetadata());
141 String defMac = ProbedLinkProvider.defaultMac();
142 if (srcMac.equals(defMac)) {
143 log.warn("Couldn't generate fingerprint. Using default value {}", defMac);
144 return defMac;
145 }
146 log.trace("Generated MAC address {}", srcMac);
147 return srcMac;
148 }
149
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800150 private void createLinks() {
151 netCfgService.getSubjects(LinkKey.class)
152 .forEach(linkKey -> configuredLinks.add(linkKey));
153 }
154
155 @Activate
156 protected void activate() {
157 log.info("Activated");
158 appId = coreService.registerApplication(PROVIDER_NAME);
159 packetService.addProcessor(packetProcessor, PacketProcessor.advisor(0));
160 providerService = providerRegistry.register(this);
161 deviceService.addListener(deviceListener);
162 netCfgService.addListener(cfgListener);
163 requestIntercepts();
164 loadDevices();
165 createLinks();
166 }
167
168 @Deactivate
169 protected void deactivate() {
170 withdrawIntercepts();
171 providerRegistry.unregister(this);
Deepa Vaddireddy21f5ae82017-05-10 18:27:30 +0530172 deviceService.removeListener(deviceListener);
173 netCfgService.removeListener(cfgListener);
174 packetService.removeProcessor(packetProcessor);
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800175 disable();
176 log.info("Deactivated");
177 }
178
179 /**
180 * Loads available devices and registers their ports to be probed.
181 */
182 private void loadDevices() {
183 deviceService.getAvailableDevices()
184 .forEach(d -> updateDevice(d)
185 .ifPresent(ld -> updatePorts(ld, d.id())));
186 }
187
188 private Optional<LinkDiscovery> updateDevice(Device device) {
189 if (device == null) {
190 return Optional.empty();
191 }
192
193 LinkDiscovery ld = discoverers.computeIfAbsent(device.id(),
Ayaka Koshibe48229222016-05-16 18:04:26 -0700194 did -> new LinkDiscovery(device, context));
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800195 if (ld.isStopped()) {
196 ld.start();
197 }
198 return Optional.of(ld);
199 }
200
201 /**
202 * Updates ports of the specified device to the specified discovery helper.
203 */
204 private void updatePorts(LinkDiscovery discoverer, DeviceId deviceId) {
205 deviceService.getPorts(deviceId).forEach(p -> updatePort(discoverer, p));
206 }
207
208
209 private void updatePort(LinkDiscovery discoverer, Port port) {
210 if (port == null) {
211 return;
212 }
213 if (port.number().isLogical()) {
214 // silently ignore logical ports
215 return;
216 }
217
218 discoverer.addPort(port);
219 }
220
221 /**
222 * Disables link discovery processing.
223 */
224 private void disable() {
225
226 providerRegistry.unregister(this);
227 discoverers.values().forEach(LinkDiscovery::stop);
228 discoverers.clear();
229
230 providerService = null;
231 }
232
233 /**
234 * Provides processing context for the device link discovery helpers.
235 */
Ray Milkey957390e2016-02-09 10:02:46 -0800236 private class InternalDiscoveryContext implements LinkDiscoveryContext {
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800237 @Override
238 public MastershipService mastershipService() {
239 return masterService;
240 }
241
242 @Override
243 public LinkProviderService providerService() {
244 return providerService;
245 }
246
247 @Override
248 public PacketService packetService() {
249 return packetService;
250 }
251
252 @Override
253 public long probeRate() {
254 return probeRate;
255 }
256
257 @Override
258 public boolean useBddp() {
259 return true;
260 }
261
262 @Override
263 public void touchLink(LinkKey key) {
Ray Milkey957390e2016-02-09 10:02:46 -0800264 }
265
266 @Override
DongRyeol Chace65cc02018-07-23 15:02:28 +0900267 public void setTtl(LinkKey key, short ttl) {
268 }
269
270 @Override
Ray Milkey957390e2016-02-09 10:02:46 -0800271 public String fingerprint() {
Ayaka Koshibe48229222016-05-16 18:04:26 -0700272 return buildSrcMac();
Ray Milkey957390e2016-02-09 10:02:46 -0800273 }
274
275 @Override
276 public DeviceService deviceService() {
277 return deviceService;
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800278 }
Samuel Jero31e16f52018-09-21 10:34:28 -0400279
280 @Override
281 public String lldpSecret() {
282 return metadataService.getClusterMetadata().getClusterSecret();
283 }
284
285 @Override
286 public long maxDiscoveryDelay() {
287 return maxDiscoveryDelayMs;
288 }
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800289 }
290
Samuel Jero31e16f52018-09-21 10:34:28 -0400291 // true if *NOT* this cluster's own probe.
292 private boolean isOthercluster(String mac) {
293 // if we are using DEFAULT_MAC, clustering hadn't initialized, so conservative 'yes'
294 String ourMac = context.fingerprint();
295 if (ProbedLinkProvider.defaultMac().equalsIgnoreCase(ourMac)) {
296 return true;
297 }
298 return !mac.equalsIgnoreCase(ourMac);
299 }
300
301 //doesn't validate. Used just to decide if this is expected link.
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800302 LinkKey extractLinkKey(PacketContext packetContext) {
303 Ethernet eth = packetContext.inPacket().parsed();
304 if (eth == null) {
305 return null;
306 }
307
308 ONOSLLDP onoslldp = ONOSLLDP.parseONOSLLDP(eth);
309 if (onoslldp != null) {
310 PortNumber srcPort = portNumber(onoslldp.getPort());
311 PortNumber dstPort = packetContext.inPacket().receivedFrom().port();
312 DeviceId srcDeviceId = DeviceId.deviceId(onoslldp.getDeviceString());
313 DeviceId dstDeviceId = packetContext.inPacket().receivedFrom().deviceId();
314
315 ConnectPoint src = new ConnectPoint(srcDeviceId, srcPort);
316 ConnectPoint dst = new ConnectPoint(dstDeviceId, dstPort);
317 return LinkKey.linkKey(src, dst);
318 }
319 return null;
320 }
321
Samuel Jero31e16f52018-09-21 10:34:28 -0400322 private boolean verify(PacketContext packetContext) {
323 Ethernet eth = packetContext.inPacket().parsed();
324 if (eth == null) {
325 return false;
326 }
327
328 ONOSLLDP onoslldp = ONOSLLDP.parseONOSLLDP(eth);
329 if (onoslldp != null) {
330 if (!isOthercluster(eth.getSourceMAC().toString())) {
331 return false;
332 }
333
334 if (!ONOSLLDP.verify(onoslldp, context.lldpSecret(), context.maxDiscoveryDelay())) {
335 log.warn("LLDP Packet failed to validate!");
336 return false;
337 }
338 return true;
339 }
340 return false;
341 }
342
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800343 /**
Ray Milkeycd6ab182016-02-03 11:13:09 -0800344 * Removes after stopping discovery helper for specified device.
345 * @param deviceId device to remove
346 */
347 private void removeDevice(final DeviceId deviceId) {
348 discoverers.computeIfPresent(deviceId, (did, ld) -> {
349 ld.stop();
350 return null;
351 });
352
353 }
354
355 /**
356 * Removes a port from the specified discovery helper.
357 * @param port the port
358 */
359 private void removePort(Port port) {
360 if (port.element() instanceof Device) {
361 Device d = (Device) port.element();
362 LinkDiscovery ld = discoverers.get(d.id());
363 if (ld != null) {
364 ld.removePort(port.number());
365 }
366 } else {
367 log.warn("Attempted to remove non-Device port", port);
368 }
369 }
370
371
372 /**
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800373 * Processes incoming packets.
374 */
375 private class InternalPacketProcessor implements PacketProcessor {
376 @Override
377 public void process(PacketContext context) {
378 if (context == null || context.isHandled()) {
379 return;
380 }
381
382 Ethernet eth = context.inPacket().parsed();
383 if (eth == null || (eth.getEtherType() != TYPE_LLDP && eth.getEtherType() != TYPE_BSN)) {
384 return;
385 }
386
387 InboundPacket inPacket = context.inPacket();
388 LinkKey linkKey = extractLinkKey(context);
389 if (linkKey != null) {
390 if (configuredLinks.contains(linkKey)) {
391 log.debug("Found configured link {}", linkKey);
392 LinkDiscovery ld = discoverers.get(inPacket.receivedFrom().deviceId());
393 if (ld == null) {
394 return;
395 }
396 if (ld.handleLldp(context)) {
397 context.block();
398 }
399 } else {
Samuel Jero31e16f52018-09-21 10:34:28 -0400400 if (verify(context)) {
401 log.debug("Found link that was not in the configuration {}", linkKey);
402 providerService.linkDetected(
403 new DefaultLinkDescription(linkKey.src(),
404 linkKey.dst(),
405 Link.Type.DIRECT,
406 DefaultLinkDescription.NOT_EXPECTED,
407 DefaultAnnotations.EMPTY));
408 }
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800409 }
410 }
411 }
412 }
413
414 /**
415 * Requests packet intercepts.
416 */
417 private void requestIntercepts() {
418 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
419 selector.matchEthType(TYPE_LLDP);
420 packetService.requestPackets(selector.build(), PacketPriority.CONTROL,
421 appId, Optional.empty());
422
423 selector.matchEthType(TYPE_BSN);
424
425 packetService.requestPackets(selector.build(), PacketPriority.CONTROL,
426 appId, Optional.empty());
427
428 }
429
430 /**
431 * Withdraws packet intercepts.
432 */
433 private void withdrawIntercepts() {
434 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
435 selector.matchEthType(TYPE_LLDP);
436 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL,
437 appId, Optional.empty());
438 selector.matchEthType(TYPE_BSN);
439 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL,
440 appId, Optional.empty());
441 }
442
443 /**
444 * Processes device events.
445 */
446 private class InternalDeviceListener implements DeviceListener {
447 @Override
448 public void event(DeviceEvent event) {
449 if (event.type() == DeviceEvent.Type.PORT_STATS_UPDATED) {
450 return;
451 }
452 Device device = event.subject();
453 Port port = event.port();
454 if (device == null) {
455 log.error("Device is null.");
456 return;
457 }
458 log.trace("{} {} {}", event.type(), event.subject(), event);
459 final DeviceId deviceId = device.id();
460 switch (event.type()) {
461 case DEVICE_ADDED:
462 case DEVICE_UPDATED:
463 updateDevice(device).ifPresent(ld -> updatePorts(ld, deviceId));
464 break;
465 case PORT_ADDED:
466 case PORT_UPDATED:
467 if (port.isEnabled()) {
468 updateDevice(device).ifPresent(ld -> updatePort(ld, port));
469 } else {
470 log.debug("Port down {}", port);
Ray Milkeycd6ab182016-02-03 11:13:09 -0800471 removePort(port);
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800472 providerService.linksVanished(new ConnectPoint(port.element().id(),
473 port.number()));
474 }
475 break;
476 case PORT_REMOVED:
477 log.debug("Port removed {}", port);
Ray Milkeycd6ab182016-02-03 11:13:09 -0800478 removePort(port);
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800479 providerService.linksVanished(new ConnectPoint(port.element().id(),
480 port.number()));
481 break;
482 case DEVICE_REMOVED:
483 case DEVICE_SUSPENDED:
484 log.debug("Device removed {}", deviceId);
Ray Milkeycd6ab182016-02-03 11:13:09 -0800485 removeDevice(deviceId);
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800486 providerService.linksVanished(deviceId);
487 break;
488 case DEVICE_AVAILABILITY_CHANGED:
489 if (deviceService.isAvailable(deviceId)) {
490 log.debug("Device up {}", deviceId);
491 updateDevice(device).ifPresent(ld -> updatePorts(ld, deviceId));
492 } else {
493 log.debug("Device down {}", deviceId);
Ray Milkeycd6ab182016-02-03 11:13:09 -0800494 removeDevice(deviceId);
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800495 providerService.linksVanished(deviceId);
496 }
497 break;
498 case PORT_STATS_UPDATED:
499 break;
500 default:
501 log.debug("Unknown event {}", event);
502 }
503 }
504 }
505
506 private class InternalConfigListener implements NetworkConfigListener {
507
508 private void addLink(LinkKey linkKey) {
509 configuredLinks.add(linkKey);
510 }
511
512 private void removeLink(LinkKey linkKey) {
513 DefaultLinkDescription linkDescription =
514 new DefaultLinkDescription(linkKey.src(), linkKey.dst(),
515 Link.Type.DIRECT);
516 configuredLinks.remove(linkKey);
517 providerService.linkVanished(linkDescription);
518 }
519
520 @Override
521 public void event(NetworkConfigEvent event) {
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800522 if (event.configClass().equals(BasicLinkConfig.class)) {
523 log.info("net config event of type {} for basic link {}",
524 event.type(), event.subject());
525 LinkKey linkKey = (LinkKey) event.subject();
526 if (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED) {
527 addLink(linkKey);
528 } else if (event.type() == NetworkConfigEvent.Type.CONFIG_REMOVED) {
529 removeLink(linkKey);
530 }
Charles Chane527eff2016-05-18 14:04:57 -0700531 log.info("Link reconfigured");
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800532 }
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800533 }
534 }
535
536}