blob: b8905aefe54e79b74240445c9546b9affc1039f3 [file] [log] [blame]
Thomas Vachuska781d18b2014-10-27 10:31:25 -07001/*
Thomas Vachuska4f1a60c2014-10-28 13:39:07 -07002 * Copyright 2014 Open Networking Laboratory
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 */
alshabib7911a052014-10-16 17:49:37 -070016package org.onlab.onos.provider.lldp.impl;
17
18import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
21import org.apache.felix.scr.annotations.Reference;
22import org.apache.felix.scr.annotations.ReferenceCardinality;
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -080023import org.onlab.onos.mastership.MastershipEvent;
24import org.onlab.onos.mastership.MastershipListener;
alshabib875d6262014-10-17 16:19:40 -070025import org.onlab.onos.mastership.MastershipService;
alshabib7911a052014-10-16 17:49:37 -070026import org.onlab.onos.net.ConnectPoint;
27import org.onlab.onos.net.Device;
28import org.onlab.onos.net.DeviceId;
alshabibacd91832014-10-17 14:38:41 -070029import org.onlab.onos.net.Port;
alshabib7911a052014-10-16 17:49:37 -070030import org.onlab.onos.net.device.DeviceEvent;
31import org.onlab.onos.net.device.DeviceListener;
32import org.onlab.onos.net.device.DeviceService;
33import org.onlab.onos.net.link.LinkProvider;
34import org.onlab.onos.net.link.LinkProviderRegistry;
35import org.onlab.onos.net.link.LinkProviderService;
36import org.onlab.onos.net.packet.PacketContext;
37import org.onlab.onos.net.packet.PacketProcessor;
38import org.onlab.onos.net.packet.PacketService;
39import org.onlab.onos.net.provider.AbstractProvider;
40import org.onlab.onos.net.provider.ProviderId;
41import org.slf4j.Logger;
42
43import java.util.Map;
44import java.util.concurrent.ConcurrentHashMap;
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -080045import java.util.concurrent.ScheduledExecutorService;
46import java.util.concurrent.TimeUnit;
alshabib7911a052014-10-16 17:49:37 -070047
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -080048import static java.util.concurrent.Executors.newSingleThreadScheduledExecutor;
49import static org.onlab.util.Tools.namedThreads;
alshabib7911a052014-10-16 17:49:37 -070050import static org.slf4j.LoggerFactory.getLogger;
51
52
53/**
54 * Provider which uses an OpenFlow controller to detect network
55 * infrastructure links.
56 */
57@Component(immediate = true)
58public class LLDPLinkProvider extends AbstractProvider implements LinkProvider {
59
60 private final Logger log = getLogger(getClass());
61
62 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
63 protected LinkProviderRegistry providerRegistry;
64
65 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
66 protected DeviceService deviceService;
67
68 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
69 protected PacketService packetSevice;
70
alshabib875d6262014-10-17 16:19:40 -070071 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
72 protected MastershipService masterService;
73
alshabib7911a052014-10-16 17:49:37 -070074 private LinkProviderService providerService;
75
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -080076 private ScheduledExecutorService executor;
77
alshabib7911a052014-10-16 17:49:37 -070078 private final boolean useBDDP = true;
79
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -080080 private static final long INIT_DELAY = 5;
81 private static final long DELAY = 5;
alshabib7911a052014-10-16 17:49:37 -070082
83 private final InternalLinkProvider listener = new InternalLinkProvider();
84
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -080085 private final InternalRoleListener roleListener = new InternalRoleListener();
86
alshabib7911a052014-10-16 17:49:37 -070087 protected final Map<DeviceId, LinkDiscovery> discoverers = new ConcurrentHashMap<>();
88
89 /**
90 * Creates an OpenFlow link provider.
91 */
92 public LLDPLinkProvider() {
93 super(new ProviderId("lldp", "org.onlab.onos.provider.lldp"));
94 }
95
96 @Activate
97 public void activate() {
98 providerService = providerRegistry.register(this);
99 deviceService.addListener(listener);
100 packetSevice.addProcessor(listener, 0);
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800101 masterService.addListener(roleListener);
102
alshabibdfc7afb2014-10-21 20:13:27 -0700103 LinkDiscovery ld;
104 for (Device device : deviceService.getDevices()) {
105 ld = new LinkDiscovery(device, packetSevice, masterService,
106 providerService, useBDDP);
107 discoverers.put(device.id(), ld);
108 for (Port p : deviceService.getPorts(device.id())) {
Yuta HIGUCHI00b476f2014-10-25 21:33:07 -0700109 if (!p.number().isLogical()) {
110 ld.addPort(p);
111 }
alshabibdfc7afb2014-10-21 20:13:27 -0700112 }
113 }
alshabib7911a052014-10-16 17:49:37 -0700114
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800115 executor = newSingleThreadScheduledExecutor(namedThreads("device-sync-%d"));
116 executor.scheduleAtFixedRate(new SyncDeviceInfoTask(), INIT_DELAY,
117 DELAY, TimeUnit.SECONDS);
118
alshabib7911a052014-10-16 17:49:37 -0700119 log.info("Started");
120 }
121
122 @Deactivate
123 public void deactivate() {
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800124 executor.shutdownNow();
alshabib7911a052014-10-16 17:49:37 -0700125 for (LinkDiscovery ld : discoverers.values()) {
126 ld.stop();
127 }
128 providerRegistry.unregister(this);
129 deviceService.removeListener(listener);
130 packetSevice.removeProcessor(listener);
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800131 masterService.removeListener(roleListener);
alshabib7911a052014-10-16 17:49:37 -0700132 providerService = null;
133
134 log.info("Stopped");
135 }
136
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800137 private class InternalRoleListener implements MastershipListener {
138
139 @Override
140 public void event(MastershipEvent event) {
141
142 if (MastershipEvent.Type.BACKUPS_CHANGED.equals(event.type())) {
143 // only need new master events
144 return;
145 }
146
147 DeviceId deviceId = event.subject();
148 Device device = deviceService.getDevice(deviceId);
149 if (device == null) {
150 log.warn("Device {} doesn't exist, or isn't there yet", deviceId);
151 return;
152 }
153 synchronized (discoverers) {
154 if (!discoverers.containsKey(deviceId)) {
155 // TODO: ideally, should never reach here
156 log.debug("Device mastership changed ({}) {}",
157 event.type(), deviceId);
158 discoverers.put(deviceId, new LinkDiscovery(device,
159 packetSevice, masterService, providerService,
160 useBDDP));
161 }
162 }
163 }
164
165 }
alshabib7911a052014-10-16 17:49:37 -0700166
167 private class InternalLinkProvider implements PacketProcessor, DeviceListener {
168
169 @Override
170 public void event(DeviceEvent event) {
171 LinkDiscovery ld = null;
172 Device device = event.subject();
alshabibacd91832014-10-17 14:38:41 -0700173 Port port = event.port();
alshabibdfc7afb2014-10-21 20:13:27 -0700174 if (device == null) {
175 log.error("Device is null.");
176 return;
177 }
Yuta HIGUCHIeb24e9d2014-10-26 19:34:20 -0700178 log.trace("{} {} {}", event.type(), event.subject(), event);
Yuta HIGUCHId19f6702014-10-31 15:23:25 -0700179 final DeviceId deviceId = device.id();
alshabib7911a052014-10-16 17:49:37 -0700180 switch (event.type()) {
181 case DEVICE_ADDED:
Yuta HIGUCHIeb24e9d2014-10-26 19:34:20 -0700182 case DEVICE_UPDATED:
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800183 synchronized (discoverers) {
Yuta HIGUCHId19f6702014-10-31 15:23:25 -0700184 ld = discoverers.get(deviceId);
Yuta HIGUCHIeb24e9d2014-10-26 19:34:20 -0700185 if (ld == null) {
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800186 log.debug("Device added ({}) {}", event.type(),
187 deviceId);
188 discoverers.put(deviceId, new LinkDiscovery(device,
189 packetSevice, masterService, providerService,
190 useBDDP));
Yuta HIGUCHIeb24e9d2014-10-26 19:34:20 -0700191 } else {
192 if (ld.isStopped()) {
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800193 log.debug("Device restarted ({}) {}", event.type(),
194 deviceId);
Yuta HIGUCHIeb24e9d2014-10-26 19:34:20 -0700195 ld.start();
196 }
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800197 }
Yuta HIGUCHIeb24e9d2014-10-26 19:34:20 -0700198 }
alshabib7911a052014-10-16 17:49:37 -0700199 break;
200 case PORT_ADDED:
201 case PORT_UPDATED:
Yuta HIGUCHIf6725882014-10-29 15:25:51 -0700202 if (port.isEnabled()) {
Yuta HIGUCHId19f6702014-10-31 15:23:25 -0700203 ld = discoverers.get(deviceId);
alshabib7911a052014-10-16 17:49:37 -0700204 if (ld == null) {
205 return;
206 }
Yuta HIGUCHI00b476f2014-10-25 21:33:07 -0700207 if (!port.number().isLogical()) {
Yuta HIGUCHIeb24e9d2014-10-26 19:34:20 -0700208 log.debug("Port added {}", port);
Yuta HIGUCHI00b476f2014-10-25 21:33:07 -0700209 ld.addPort(port);
210 }
alshabib7911a052014-10-16 17:49:37 -0700211 } else {
Yuta HIGUCHIf6725882014-10-29 15:25:51 -0700212 log.debug("Port down {}", port);
Yuta HIGUCHId19f6702014-10-31 15:23:25 -0700213 ConnectPoint point = new ConnectPoint(deviceId,
alshabibacd91832014-10-17 14:38:41 -0700214 port.number());
alshabib7911a052014-10-16 17:49:37 -0700215 providerService.linksVanished(point);
216 }
217 break;
218 case PORT_REMOVED:
Yuta HIGUCHIeb24e9d2014-10-26 19:34:20 -0700219 log.debug("Port removed {}", port);
Yuta HIGUCHId19f6702014-10-31 15:23:25 -0700220 ConnectPoint point = new ConnectPoint(deviceId,
alshabibacd91832014-10-17 14:38:41 -0700221 port.number());
alshabib7911a052014-10-16 17:49:37 -0700222 providerService.linksVanished(point);
Yuta HIGUCHIeb24e9d2014-10-26 19:34:20 -0700223 // TODO: Don't we need to removePort from ld?
alshabib7911a052014-10-16 17:49:37 -0700224 break;
225 case DEVICE_REMOVED:
226 case DEVICE_SUSPENDED:
Yuta HIGUCHId19f6702014-10-31 15:23:25 -0700227 log.debug("Device removed {}", deviceId);
228 ld = discoverers.get(deviceId);
alshabib7911a052014-10-16 17:49:37 -0700229 if (ld == null) {
230 return;
231 }
232 ld.stop();
Yuta HIGUCHId19f6702014-10-31 15:23:25 -0700233 providerService.linksVanished(deviceId);
alshabib7911a052014-10-16 17:49:37 -0700234 break;
235 case DEVICE_AVAILABILITY_CHANGED:
Yuta HIGUCHId19f6702014-10-31 15:23:25 -0700236 ld = discoverers.get(deviceId);
alshabib7911a052014-10-16 17:49:37 -0700237 if (ld == null) {
238 return;
239 }
Yuta HIGUCHId19f6702014-10-31 15:23:25 -0700240 if (deviceService.isAvailable(deviceId)) {
241 log.debug("Device up {}", deviceId);
alshabib7911a052014-10-16 17:49:37 -0700242 ld.start();
243 } else {
Yuta HIGUCHId19f6702014-10-31 15:23:25 -0700244 providerService.linksVanished(deviceId);
245 log.debug("Device down {}", deviceId);
alshabib7911a052014-10-16 17:49:37 -0700246 ld.stop();
247 }
248 break;
alshabib7911a052014-10-16 17:49:37 -0700249 default:
250 log.debug("Unknown event {}", event);
251 }
252 }
253
254 @Override
255 public void process(PacketContext context) {
alshabib4a179dc2014-10-17 17:17:01 -0700256 if (context == null) {
257 return;
258 }
alshabib7911a052014-10-16 17:49:37 -0700259 LinkDiscovery ld = discoverers.get(
260 context.inPacket().receivedFrom().deviceId());
261 if (ld == null) {
262 return;
263 }
264
265 if (ld.handleLLDP(context)) {
266 context.block();
267 }
268 }
269 }
270
Ayaka Koshibeccfa94c2014-11-20 11:15:52 -0800271 private final class SyncDeviceInfoTask implements Runnable {
272
273 @Override
274 public void run() {
275 if (Thread.currentThread().isInterrupted()) {
276 log.info("Interrupted, quitting");
277 return;
278 }
279 // check what deviceService sees, to see if we are missing anything
280 try {
281 LinkDiscovery ld = null;
282 for (Device dev : deviceService.getDevices()) {
283 DeviceId did = dev.id();
284 synchronized (discoverers) {
285 if (!discoverers.containsKey(did)) {
286 ld = new LinkDiscovery(dev, packetSevice,
287 masterService, providerService, useBDDP);
288 discoverers.put(did, ld);
289 for (Port p : deviceService.getPorts(did)) {
290 if (!p.number().isLogical()) {
291 ld.addPort(p);
292 }
293 }
294 }
295 }
296 }
297 } catch (Exception e) {
298 // catch all Exception to avoid Scheduled task being suppressed.
299 log.error("Exception thrown during synchronization process", e);
300 }
301 }
302 }
303
alshabib7911a052014-10-16 17:49:37 -0700304}