blob: 2d44c5bf95830fd0279c0ddf0529c98be22abaf7 [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;
71
72/**
73 * Provider to pre-discover links and devices based on a specified network
74 * config.
75 */
76
77@Component(immediate = true)
78public class NetworkConfigLinksProvider
79 extends AbstractProvider
Ayaka Koshibe48229222016-05-16 18:04:26 -070080 implements ProbedLinkProvider {
Ray Milkeyb7f0f642016-01-22 16:08:14 -080081
Ray Milkeyd84f89b2018-08-17 14:54:17 -070082 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeyb7f0f642016-01-22 16:08:14 -080083 protected LinkProviderRegistry providerRegistry;
84
Ray Milkeyd84f89b2018-08-17 14:54:17 -070085 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeyb7f0f642016-01-22 16:08:14 -080086 protected DeviceService deviceService;
87
Ray Milkeyd84f89b2018-08-17 14:54:17 -070088 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeyb7f0f642016-01-22 16:08:14 -080089 protected PacketService packetService;
90
Ray Milkeyd84f89b2018-08-17 14:54:17 -070091 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeyb7f0f642016-01-22 16:08:14 -080092 protected MastershipService masterService;
93
Ray Milkeyd84f89b2018-08-17 14:54:17 -070094 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeyb7f0f642016-01-22 16:08:14 -080095 protected NetworkConfigRegistry netCfgService;
96
Ray Milkeyd84f89b2018-08-17 14:54:17 -070097 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ray Milkeyb7f0f642016-01-22 16:08:14 -080098 protected CoreService coreService;
99
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700100 @Reference(cardinality = ReferenceCardinality.MANDATORY)
Ayaka Koshibe48229222016-05-16 18:04:26 -0700101 protected ClusterMetadataService metadataService;
102
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800103 private static final String PROP_PROBE_RATE = "probeRate";
104 private static final int DEFAULT_PROBE_RATE = 3000;
Ray Milkeyd84f89b2018-08-17 14:54:17 -0700105 //@Property(name = PROP_PROBE_RATE, intValue = DEFAULT_PROBE_RATE,
106 // label = "LLDP and BDDP probe rate specified in millis")
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800107 private int probeRate = DEFAULT_PROBE_RATE;
108
109 // Device link discovery helpers.
110 protected final Map<DeviceId, LinkDiscovery> discoverers = new ConcurrentHashMap<>();
111
Ray Milkey957390e2016-02-09 10:02:46 -0800112 private final LinkDiscoveryContext context = new InternalDiscoveryContext();
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800113
114 private LinkProviderService providerService;
115
116 private static final String PROVIDER_NAME =
117 "org.onosproject.provider.netcfglinks";
118 private final Logger log = LoggerFactory.getLogger(getClass());
119
120 private ApplicationId appId;
121 private final InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
122 private final InternalDeviceListener deviceListener = new InternalDeviceListener();
123 private final InternalConfigListener cfgListener = new InternalConfigListener();
124
Ray Milkeycd6ab182016-02-03 11:13:09 -0800125 protected Set<LinkKey> configuredLinks = new HashSet<>();
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800126
127 public NetworkConfigLinksProvider() {
128 super(new ProviderId("lldp", PROVIDER_NAME));
129 }
130
Sho SHIMIZU9efeb812016-08-18 09:29:20 -0700131 private String buildSrcMac() {
Ayaka Koshibe48229222016-05-16 18:04:26 -0700132 String srcMac = ProbedLinkProvider.fingerprintMac(metadataService.getClusterMetadata());
133 String defMac = ProbedLinkProvider.defaultMac();
134 if (srcMac.equals(defMac)) {
135 log.warn("Couldn't generate fingerprint. Using default value {}", defMac);
136 return defMac;
137 }
138 log.trace("Generated MAC address {}", srcMac);
139 return srcMac;
140 }
141
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800142 private void createLinks() {
143 netCfgService.getSubjects(LinkKey.class)
144 .forEach(linkKey -> configuredLinks.add(linkKey));
145 }
146
147 @Activate
148 protected void activate() {
149 log.info("Activated");
150 appId = coreService.registerApplication(PROVIDER_NAME);
151 packetService.addProcessor(packetProcessor, PacketProcessor.advisor(0));
152 providerService = providerRegistry.register(this);
153 deviceService.addListener(deviceListener);
154 netCfgService.addListener(cfgListener);
155 requestIntercepts();
156 loadDevices();
157 createLinks();
158 }
159
160 @Deactivate
161 protected void deactivate() {
162 withdrawIntercepts();
163 providerRegistry.unregister(this);
Deepa Vaddireddy21f5ae82017-05-10 18:27:30 +0530164 deviceService.removeListener(deviceListener);
165 netCfgService.removeListener(cfgListener);
166 packetService.removeProcessor(packetProcessor);
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800167 disable();
168 log.info("Deactivated");
169 }
170
171 /**
172 * Loads available devices and registers their ports to be probed.
173 */
174 private void loadDevices() {
175 deviceService.getAvailableDevices()
176 .forEach(d -> updateDevice(d)
177 .ifPresent(ld -> updatePorts(ld, d.id())));
178 }
179
180 private Optional<LinkDiscovery> updateDevice(Device device) {
181 if (device == null) {
182 return Optional.empty();
183 }
184
185 LinkDiscovery ld = discoverers.computeIfAbsent(device.id(),
Ayaka Koshibe48229222016-05-16 18:04:26 -0700186 did -> new LinkDiscovery(device, context));
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800187 if (ld.isStopped()) {
188 ld.start();
189 }
190 return Optional.of(ld);
191 }
192
193 /**
194 * Updates ports of the specified device to the specified discovery helper.
195 */
196 private void updatePorts(LinkDiscovery discoverer, DeviceId deviceId) {
197 deviceService.getPorts(deviceId).forEach(p -> updatePort(discoverer, p));
198 }
199
200
201 private void updatePort(LinkDiscovery discoverer, Port port) {
202 if (port == null) {
203 return;
204 }
205 if (port.number().isLogical()) {
206 // silently ignore logical ports
207 return;
208 }
209
210 discoverer.addPort(port);
211 }
212
213 /**
214 * Disables link discovery processing.
215 */
216 private void disable() {
217
218 providerRegistry.unregister(this);
219 discoverers.values().forEach(LinkDiscovery::stop);
220 discoverers.clear();
221
222 providerService = null;
223 }
224
225 /**
226 * Provides processing context for the device link discovery helpers.
227 */
Ray Milkey957390e2016-02-09 10:02:46 -0800228 private class InternalDiscoveryContext implements LinkDiscoveryContext {
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800229 @Override
230 public MastershipService mastershipService() {
231 return masterService;
232 }
233
234 @Override
235 public LinkProviderService providerService() {
236 return providerService;
237 }
238
239 @Override
240 public PacketService packetService() {
241 return packetService;
242 }
243
244 @Override
245 public long probeRate() {
246 return probeRate;
247 }
248
249 @Override
250 public boolean useBddp() {
251 return true;
252 }
253
254 @Override
255 public void touchLink(LinkKey key) {
Ray Milkey957390e2016-02-09 10:02:46 -0800256 }
257
258 @Override
259 public String fingerprint() {
Ayaka Koshibe48229222016-05-16 18:04:26 -0700260 return buildSrcMac();
Ray Milkey957390e2016-02-09 10:02:46 -0800261 }
262
263 @Override
264 public DeviceService deviceService() {
265 return deviceService;
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800266 }
267 }
268
269 LinkKey extractLinkKey(PacketContext packetContext) {
270 Ethernet eth = packetContext.inPacket().parsed();
271 if (eth == null) {
272 return null;
273 }
274
275 ONOSLLDP onoslldp = ONOSLLDP.parseONOSLLDP(eth);
276 if (onoslldp != null) {
277 PortNumber srcPort = portNumber(onoslldp.getPort());
278 PortNumber dstPort = packetContext.inPacket().receivedFrom().port();
279 DeviceId srcDeviceId = DeviceId.deviceId(onoslldp.getDeviceString());
280 DeviceId dstDeviceId = packetContext.inPacket().receivedFrom().deviceId();
281
282 ConnectPoint src = new ConnectPoint(srcDeviceId, srcPort);
283 ConnectPoint dst = new ConnectPoint(dstDeviceId, dstPort);
284 return LinkKey.linkKey(src, dst);
285 }
286 return null;
287 }
288
289 /**
Ray Milkeycd6ab182016-02-03 11:13:09 -0800290 * Removes after stopping discovery helper for specified device.
291 * @param deviceId device to remove
292 */
293 private void removeDevice(final DeviceId deviceId) {
294 discoverers.computeIfPresent(deviceId, (did, ld) -> {
295 ld.stop();
296 return null;
297 });
298
299 }
300
301 /**
302 * Removes a port from the specified discovery helper.
303 * @param port the port
304 */
305 private void removePort(Port port) {
306 if (port.element() instanceof Device) {
307 Device d = (Device) port.element();
308 LinkDiscovery ld = discoverers.get(d.id());
309 if (ld != null) {
310 ld.removePort(port.number());
311 }
312 } else {
313 log.warn("Attempted to remove non-Device port", port);
314 }
315 }
316
317
318 /**
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800319 * Processes incoming packets.
320 */
321 private class InternalPacketProcessor implements PacketProcessor {
322 @Override
323 public void process(PacketContext context) {
324 if (context == null || context.isHandled()) {
325 return;
326 }
327
328 Ethernet eth = context.inPacket().parsed();
329 if (eth == null || (eth.getEtherType() != TYPE_LLDP && eth.getEtherType() != TYPE_BSN)) {
330 return;
331 }
332
333 InboundPacket inPacket = context.inPacket();
334 LinkKey linkKey = extractLinkKey(context);
335 if (linkKey != null) {
336 if (configuredLinks.contains(linkKey)) {
337 log.debug("Found configured link {}", linkKey);
338 LinkDiscovery ld = discoverers.get(inPacket.receivedFrom().deviceId());
339 if (ld == null) {
340 return;
341 }
342 if (ld.handleLldp(context)) {
343 context.block();
344 }
345 } else {
346 log.debug("Found link that was not in the configuration {}", linkKey);
347 providerService.linkDetected(
348 new DefaultLinkDescription(linkKey.src(),
349 linkKey.dst(),
350 Link.Type.DIRECT,
351 DefaultLinkDescription.NOT_EXPECTED,
352 DefaultAnnotations.EMPTY));
353 }
354 }
355 }
356 }
357
358 /**
359 * Requests packet intercepts.
360 */
361 private void requestIntercepts() {
362 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
363 selector.matchEthType(TYPE_LLDP);
364 packetService.requestPackets(selector.build(), PacketPriority.CONTROL,
365 appId, Optional.empty());
366
367 selector.matchEthType(TYPE_BSN);
368
369 packetService.requestPackets(selector.build(), PacketPriority.CONTROL,
370 appId, Optional.empty());
371
372 }
373
374 /**
375 * Withdraws packet intercepts.
376 */
377 private void withdrawIntercepts() {
378 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
379 selector.matchEthType(TYPE_LLDP);
380 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL,
381 appId, Optional.empty());
382 selector.matchEthType(TYPE_BSN);
383 packetService.cancelPackets(selector.build(), PacketPriority.CONTROL,
384 appId, Optional.empty());
385 }
386
387 /**
388 * Processes device events.
389 */
390 private class InternalDeviceListener implements DeviceListener {
391 @Override
392 public void event(DeviceEvent event) {
393 if (event.type() == DeviceEvent.Type.PORT_STATS_UPDATED) {
394 return;
395 }
396 Device device = event.subject();
397 Port port = event.port();
398 if (device == null) {
399 log.error("Device is null.");
400 return;
401 }
402 log.trace("{} {} {}", event.type(), event.subject(), event);
403 final DeviceId deviceId = device.id();
404 switch (event.type()) {
405 case DEVICE_ADDED:
406 case DEVICE_UPDATED:
407 updateDevice(device).ifPresent(ld -> updatePorts(ld, deviceId));
408 break;
409 case PORT_ADDED:
410 case PORT_UPDATED:
411 if (port.isEnabled()) {
412 updateDevice(device).ifPresent(ld -> updatePort(ld, port));
413 } else {
414 log.debug("Port down {}", port);
Ray Milkeycd6ab182016-02-03 11:13:09 -0800415 removePort(port);
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800416 providerService.linksVanished(new ConnectPoint(port.element().id(),
417 port.number()));
418 }
419 break;
420 case PORT_REMOVED:
421 log.debug("Port removed {}", port);
Ray Milkeycd6ab182016-02-03 11:13:09 -0800422 removePort(port);
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800423 providerService.linksVanished(new ConnectPoint(port.element().id(),
424 port.number()));
425 break;
426 case DEVICE_REMOVED:
427 case DEVICE_SUSPENDED:
428 log.debug("Device removed {}", deviceId);
Ray Milkeycd6ab182016-02-03 11:13:09 -0800429 removeDevice(deviceId);
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800430 providerService.linksVanished(deviceId);
431 break;
432 case DEVICE_AVAILABILITY_CHANGED:
433 if (deviceService.isAvailable(deviceId)) {
434 log.debug("Device up {}", deviceId);
435 updateDevice(device).ifPresent(ld -> updatePorts(ld, deviceId));
436 } else {
437 log.debug("Device down {}", deviceId);
Ray Milkeycd6ab182016-02-03 11:13:09 -0800438 removeDevice(deviceId);
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800439 providerService.linksVanished(deviceId);
440 }
441 break;
442 case PORT_STATS_UPDATED:
443 break;
444 default:
445 log.debug("Unknown event {}", event);
446 }
447 }
448 }
449
450 private class InternalConfigListener implements NetworkConfigListener {
451
452 private void addLink(LinkKey linkKey) {
453 configuredLinks.add(linkKey);
454 }
455
456 private void removeLink(LinkKey linkKey) {
457 DefaultLinkDescription linkDescription =
458 new DefaultLinkDescription(linkKey.src(), linkKey.dst(),
459 Link.Type.DIRECT);
460 configuredLinks.remove(linkKey);
461 providerService.linkVanished(linkDescription);
462 }
463
464 @Override
465 public void event(NetworkConfigEvent event) {
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800466 if (event.configClass().equals(BasicLinkConfig.class)) {
467 log.info("net config event of type {} for basic link {}",
468 event.type(), event.subject());
469 LinkKey linkKey = (LinkKey) event.subject();
470 if (event.type() == NetworkConfigEvent.Type.CONFIG_ADDED) {
471 addLink(linkKey);
472 } else if (event.type() == NetworkConfigEvent.Type.CONFIG_REMOVED) {
473 removeLink(linkKey);
474 }
Charles Chane527eff2016-05-18 14:04:57 -0700475 log.info("Link reconfigured");
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800476 }
Ray Milkeyb7f0f642016-01-22 16:08:14 -0800477 }
478 }
479
480}