blob: e58a57091de96c95e309b575999a96faf251170e [file] [log] [blame]
Sean Condon0e89bda2017-03-21 14:23:19 +00001/*
2 * Copyright 2017-present Open Networking Foundation
3 *
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.incubator.net.l2monitoring.cfm.impl;
17
Sean Condon96b896d2017-12-11 12:44:29 -080018import static org.onlab.util.Tools.groupedThreads;
Sean Condon0e89bda2017-03-21 14:23:19 +000019import static org.slf4j.LoggerFactory.getLogger;
20
21import java.util.ArrayList;
22import java.util.Collection;
Sean Condon96b896d2017-12-11 12:44:29 -080023import java.util.HashSet;
24import java.util.Iterator;
25import java.util.List;
26import java.util.Optional;
27import java.util.Set;
28import java.util.concurrent.ConcurrentLinkedQueue;
29import java.util.concurrent.Executors;
30import java.util.concurrent.ScheduledExecutorService;
31import java.util.concurrent.ScheduledFuture;
32import java.util.concurrent.TimeUnit;
Sean Condon0e89bda2017-03-21 14:23:19 +000033
34import org.apache.felix.scr.annotations.Activate;
35import org.apache.felix.scr.annotations.Component;
36import org.apache.felix.scr.annotations.Deactivate;
37import org.apache.felix.scr.annotations.Reference;
38import org.apache.felix.scr.annotations.ReferenceCardinality;
39import org.apache.felix.scr.annotations.Service;
40import org.onosproject.core.CoreService;
41import org.onosproject.core.IdGenerator;
42import org.onosproject.event.AbstractListenerManager;
Sean Condon96b896d2017-12-11 12:44:29 -080043import org.onosproject.event.Event;
44import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceDomain;
Sean Condon0e89bda2017-03-21 14:23:19 +000045import org.onosproject.incubator.net.l2monitoring.cfm.Mep;
46import org.onosproject.incubator.net.l2monitoring.cfm.MepEntry;
47import org.onosproject.incubator.net.l2monitoring.cfm.MepLbCreate;
48import org.onosproject.incubator.net.l2monitoring.cfm.MepLtCreate;
49import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
50import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
51import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
Sean Condon96b896d2017-12-11 12:44:29 -080052import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepKeyId;
Sean Condon0e89bda2017-03-21 14:23:19 +000053import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
54import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMdService;
55import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMepEvent;
56import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMepListener;
57import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMepProgrammable;
58import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMepService;
Sean Condon96b896d2017-12-11 12:44:29 -080059import org.onosproject.incubator.net.l2monitoring.cfm.service.MdEvent;
60import org.onosproject.incubator.net.l2monitoring.cfm.service.MdListener;
61import org.onosproject.incubator.net.l2monitoring.cfm.service.MepStore;
62import org.onosproject.incubator.net.l2monitoring.cfm.service.MepStoreDelegate;
Sean Condon0e89bda2017-03-21 14:23:19 +000063import org.onosproject.mastership.MastershipService;
64import org.onosproject.net.Device;
65import org.onosproject.net.DeviceId;
66import org.onosproject.net.device.DeviceEvent;
67import org.onosproject.net.device.DeviceListener;
68import org.onosproject.net.device.DeviceService;
69import org.slf4j.Logger;
70
71/**
72 * Provides implementation of the CFM North and South Bound Interfaces.
73 */
74@Component(immediate = true)
75@Service
76public class CfmMepManager
77 extends AbstractListenerManager<CfmMepEvent, CfmMepListener>
78 implements CfmMepService {
79
80 private final Logger log = getLogger(getClass());
81
Sean Condon96b896d2017-12-11 12:44:29 -080082 private InternalDeviceListener deviceListener = null;
83 private InternalMdListener mdListener = null;
Sean Condon0e89bda2017-03-21 14:23:19 +000084
85 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 protected DeviceService deviceService;
87
88 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
89 protected CoreService coreService;
90
91 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
92 protected MastershipService mastershipService;
93
94 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
95 protected CfmMdService cfmMdService;
96
97 private static final int DEFAULT_POLL_FREQUENCY = 30;
98 private int fallbackMepPollFrequency = DEFAULT_POLL_FREQUENCY;
99
Sean Condon96b896d2017-12-11 12:44:29 -0800100 private InternalEventHandler eventHandler = new InternalEventHandler();
101 private static final Object THREAD_SCHED_LOCK = new Object();
102 private static int numOfEventsQueued = 0;
103 private static int numOfEventsExecuted = 0;
104 private static int numOfHandlerExecution = 0;
105 private static int numOfHandlerScheduled = 0;
106
107 private ScheduledExecutorService executorService = Executors
108 .newScheduledThreadPool(1,
109 groupedThreads("CfmMepManager", "event-%d", log));
110
111 @SuppressWarnings("unused")
112 private static ScheduledFuture<?> eventHandlerFuture = null;
113 @SuppressWarnings("rawtypes")
114 private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<>();
115
116
Sean Condon0e89bda2017-03-21 14:23:19 +0000117 private IdGenerator idGenerator;
118
Sean Condon96b896d2017-12-11 12:44:29 -0800119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
120 protected MepStore mepStore;
Sean Condon0e89bda2017-03-21 14:23:19 +0000121
Sean Condon96b896d2017-12-11 12:44:29 -0800122 protected final MepStoreDelegate delegate = new InternalStoreDelegate();
Sean Condon0e89bda2017-03-21 14:23:19 +0000123
124 @Activate
125 public void activate() {
Sean Condon96b896d2017-12-11 12:44:29 -0800126 mepStore.setDelegate(delegate);
Sean Condon0e89bda2017-03-21 14:23:19 +0000127
Sean Condon96b896d2017-12-11 12:44:29 -0800128 deviceListener = new InternalDeviceListener();
Sean Condon0e89bda2017-03-21 14:23:19 +0000129 deviceService.addListener(deviceListener);
Sean Condon96b896d2017-12-11 12:44:29 -0800130 mdListener = new InternalMdListener();
131 cfmMdService.addListener(mdListener);
132 eventDispatcher.addSink(CfmMepEvent.class, listenerRegistry);
Sean Condon0e89bda2017-03-21 14:23:19 +0000133 idGenerator = coreService.getIdGenerator("mep-ids");
134 log.info("CFM MEP Manager Started");
135 }
136
137 @Deactivate
138 public void deactivate() {
139 deviceService.removeListener(deviceListener);
Sean Condon96b896d2017-12-11 12:44:29 -0800140 cfmMdService.removeListener(mdListener);
Sean Condon0e89bda2017-03-21 14:23:19 +0000141 eventDispatcher.removeSink(CfmMepEvent.class);
142 log.info("CFM MEP Manager Stopped");
Sean Condon96b896d2017-12-11 12:44:29 -0800143 mepStore.unsetDelegate(delegate);
144 deviceListener = null;
145 mdListener = null;
Sean Condon0e89bda2017-03-21 14:23:19 +0000146 }
147
148 @Override
149 public Collection<MepEntry> getAllMeps(MdId mdName, MaIdShort maName)
150 throws CfmConfigException {
151 //Will throw IllegalArgumentException if ma does not exist
152 cfmMdService.getMaintenanceAssociation(mdName, maName);
153
Sean Condon96b896d2017-12-11 12:44:29 -0800154 Collection<Mep> mepStoreCollection = mepStore.getAllMeps();
Sean Condon0e89bda2017-03-21 14:23:19 +0000155 Collection<MepEntry> mepEntryCollection = new ArrayList<>();
156
Sean Condon96b896d2017-12-11 12:44:29 -0800157 for (Mep mep : mepStoreCollection) {
Sean Condon0e89bda2017-03-21 14:23:19 +0000158 if (mep.mdId().equals(mdName) && mep.maId().equals(maName)) {
159 DeviceId mepDeviceId = mep.deviceId();
160 if (deviceService.getDevice(mepDeviceId) == null) {
161 log.warn("Device not found/available " + mepDeviceId +
Sean Condon96b896d2017-12-11 12:44:29 -0800162 " for MEP: " + mdName + "/" + maName + "/" + mep.mepId());
Sean Condon0e89bda2017-03-21 14:23:19 +0000163 continue;
164 } else if (!deviceService.getDevice(mepDeviceId)
Sean Condon96b896d2017-12-11 12:44:29 -0800165 .is(CfmMepProgrammable.class)) {
Sean Condon0e89bda2017-03-21 14:23:19 +0000166 throw new CfmConfigException("Device " + mepDeviceId +
167 " does not support CfmMepProgrammable behaviour.");
168 }
169
170 log.debug("Retrieving MEP results for Mep {} in MD {}, MA {} "
Sean Condon96b896d2017-12-11 12:44:29 -0800171 + "on Device {}", mep.mepId(), mdName, maName, mepDeviceId);
Sean Condon0e89bda2017-03-21 14:23:19 +0000172 mepEntryCollection.add(deviceService
Sean Condon96b896d2017-12-11 12:44:29 -0800173 .getDevice(mepDeviceId)
174 .as(CfmMepProgrammable.class)
175 .getMep(mdName, maName, mep.mepId()));
Sean Condon0e89bda2017-03-21 14:23:19 +0000176 }
177 }
178
179 return mepEntryCollection;
180 }
181
182 @Override
Sean Condon96b896d2017-12-11 12:44:29 -0800183 public Collection<Mep> getAllMepsByDevice(DeviceId deviceId) throws CfmConfigException {
184 return mepStore.getMepsByDeviceId(deviceId);
Sean Condon0e89bda2017-03-21 14:23:19 +0000185 }
186
187 @Override
Sean Condon96b896d2017-12-11 12:44:29 -0800188 public MepEntry getMep(MdId mdName, MaIdShort maName, MepId mepId) throws CfmConfigException {
189 MepKeyId key = new MepKeyId(mdName, maName, mepId);
190
Sean Condon0e89bda2017-03-21 14:23:19 +0000191 //Will throw IllegalArgumentException if ma does not exist
192 cfmMdService.getMaintenanceAssociation(mdName, maName);
193
Sean Condon96b896d2017-12-11 12:44:29 -0800194 Optional<Mep> mepOptional = mepStore.getMep(key);
195 if (mepOptional.isPresent()) {
196 Mep mep = mepOptional.get();
197 DeviceId mepDeviceId = mep.deviceId();
198 if (deviceService.getDevice(mepDeviceId) == null) {
199 throw new CfmConfigException("Device not found " + mepDeviceId);
200 } else if (!deviceService.getDevice(mepDeviceId).is(CfmMepProgrammable.class)) {
201 throw new CfmConfigException("Device " + mepDeviceId +
202 " does not support CfmMepProgrammable behaviour.");
203 }
204
205 log.debug("Retrieving MEP reults for Mep {} in MD {}, MA {} on Device {}",
206 mep.mepId(), mdName, maName, mepDeviceId);
207
208 return deviceService.getDevice(mepDeviceId)
209 .as(CfmMepProgrammable.class).getMep(mdName, maName, mepId);
210 } else {
211 return null;
212 }
213 }
214
215 @Override
216 public boolean deleteMep(MdId mdName, MaIdShort maName, MepId mepId,
217 Optional<MaintenanceDomain> oldMd) throws CfmConfigException {
218 MepKeyId key = new MepKeyId(mdName, maName, mepId);
219
220 //Will throw IllegalArgumentException if ma does not exist
221 cfmMdService.getMaintenanceAssociation(mdName, maName);
222
223 //Get the device ID from the MEP
224 Optional<Mep> deletedMep = mepStore.getMep(key);
225 if (!deletedMep.isPresent()) {
226 log.warn("MEP {} not found when deleting Mep", key);
227 return false;
228 }
229
230 DeviceId mepDeviceId = deletedMep.get().deviceId();
231 boolean deleted = mepStore.deleteMep(key);
232
233 Device mepDevice = deviceService.getDevice(mepDeviceId);
234 if (mepDevice == null || !mepDevice.is(CfmMepProgrammable.class)) {
235 throw new CfmConfigException("Unexpeced fault on device driver for "
236 + mepDeviceId);
237 }
238 try {
239 deleted = mepDevice.as(CfmMepProgrammable.class)
240 .deleteMep(mdName, maName, mepId, oldMd);
241 } catch (CfmConfigException e) {
242 log.warn("MEP could not be deleted on device - perhaps it "
243 + "does not exist. Continuing");
244 }
245
246 //Iterate through all other devices and remove as a Remote Mep
247 int mepsOnMdCount = 0;
248 int mepsOnMaCount = 0;
249 for (Mep mep : mepStore.getAllMeps()) {
250 if (mep.deviceId().equals(mepDeviceId) && mdName.equals(mep.mdId())) {
251 mepsOnMdCount++;
252 if (maName.equals(mep.maId())) {
253 mepsOnMaCount++;
Sean Condon0e89bda2017-03-21 14:23:19 +0000254 }
255 }
Sean Condon96b896d2017-12-11 12:44:29 -0800256 List<DeviceId> alreadyHandledDevices = new ArrayList<>();
257 if (mep.deviceId().equals(mepDeviceId) || !mep.mdId().equals(mdName) ||
258 !mep.maId().equals(maName) ||
259 alreadyHandledDevices.contains(mep.deviceId())) {
260 continue;
261 }
262 deviceService.getDevice(mep.deviceId())
263 .as(CfmMepProgrammable.class)
264 .deleteMaRemoteMepOnDevice(mdName, maName, mepId);
265 alreadyHandledDevices.add(mep.deviceId());
266 log.info("Deleted RMep entry on {} on device {}",
267 mdName.mdName() + "/" + maName.maName(), mep.deviceId());
Sean Condon0e89bda2017-03-21 14:23:19 +0000268 }
Sean Condon96b896d2017-12-11 12:44:29 -0800269
270 //Also if this is the last MEP in this MA then delete this MA from device
271 //If this is the last MA in this MD on device, then delete the MD from the device
272 if (mepsOnMdCount == 0) {
273 boolean deletedMd = deviceService.getDevice(mepDeviceId)
274 .as(CfmMepProgrammable.class).deleteMdOnDevice(mdName, oldMd);
275 log.info("Deleted MD {} from Device {}", mdName.mdName(), mepDeviceId);
276 } else if (mepsOnMaCount == 0) {
277 boolean deletedMa = deviceService.getDevice(mepDeviceId)
278 .as(CfmMepProgrammable.class).deleteMaOnDevice(mdName, maName, oldMd);
279 log.info("Deleted MA {} from Device {}",
280 mdName.mdName() + "/" + maName.maName(), mepDeviceId);
281 }
282
283 return deleted;
Sean Condon0e89bda2017-03-21 14:23:19 +0000284 }
285
286 @Override
287 public boolean createMep(MdId mdName, MaIdShort maName, Mep newMep) throws CfmConfigException {
Sean Condon96b896d2017-12-11 12:44:29 -0800288 MepKeyId key = new MepKeyId(mdName, maName, newMep.mepId());
Sean Condon0e89bda2017-03-21 14:23:19 +0000289 log.debug("Creating MEP " + newMep.mepId() + " on MD {}, MA {} on Device {}",
290 mdName, maName, newMep.deviceId().toString());
Sean Condon96b896d2017-12-11 12:44:29 -0800291 if (mepStore.getMep(key).isPresent()) {
292 return false;
Sean Condon0e89bda2017-03-21 14:23:19 +0000293 }
294
295 //Will throw IllegalArgumentException if ma does not exist
296 cfmMdService.getMaintenanceAssociation(mdName, maName);
297
298 DeviceId mepDeviceId = newMep.deviceId();
299 if (deviceService.getDevice(mepDeviceId) == null) {
300 throw new CfmConfigException("Device not found " + mepDeviceId);
301 } else if (!deviceService.getDevice(mepDeviceId).is(CfmMepProgrammable.class)) {
302 throw new CfmConfigException("Device " + mepDeviceId + " does not support CfmMepProgrammable behaviour.");
303 }
304
305 boolean deviceResult =
306 deviceService.getDevice(mepDeviceId).as(CfmMepProgrammable.class).createMep(mdName, maName, newMep);
307 log.debug("MEP created on {}", mepDeviceId);
308 if (deviceResult) {
Sean Condon96b896d2017-12-11 12:44:29 -0800309 boolean alreadyExisted = mepStore.createUpdateMep(key, newMep);
310
311 //Add to other Remote Mep List on other devices
312 for (Mep mep:mepStore.getMepsByMdMa(mdName, maName)) {
313 List<DeviceId> alreadyHandledDevices = new ArrayList<>();
314 if (mep.deviceId().equals(mepDeviceId) ||
315 alreadyHandledDevices.contains(mep.deviceId())) {
316 continue;
317 }
318 boolean created = deviceService.getDevice(mep.deviceId())
319 .as(CfmMepProgrammable.class)
320 .createMaRemoteMepOnDevice(mdName, maName, newMep.mepId());
321 alreadyHandledDevices.add(mep.deviceId());
322 log.info("Created RMep entry on {} on device {}",
323 mdName.mdName() + "/" + maName.maName(), mep.deviceId());
324 }
325
326 return !alreadyExisted;
Sean Condon0e89bda2017-03-21 14:23:19 +0000327 } else {
328 return deviceResult;
329 }
330 }
331
332 @Override
333 public void transmitLoopback(MdId mdName, MaIdShort maName,
Sean Condon96b896d2017-12-11 12:44:29 -0800334 MepId mepId, MepLbCreate lbCreate) throws CfmConfigException {
335 MepKeyId key = new MepKeyId(mdName, maName, mepId);
336 Mep mep = mepStore.getMep(key)
337 .orElseThrow(() -> new CfmConfigException("Mep " + mdName + "/" + maName + "/"
338 + mepId + " not found when calling Transmit Loopback"));
339
340 log.debug("Transmitting Loopback on MEP {} on Device {}",
341 key, mep.deviceId());
342 deviceService.getDevice(mep.deviceId())
343 .as(CfmMepProgrammable.class)
344 .transmitLoopback(mdName, maName, mepId, lbCreate);
Sean Condon0e89bda2017-03-21 14:23:19 +0000345 }
346
347 @Override
348 public void abortLoopback(MdId mdName, MaIdShort maName, MepId mepId)
349 throws CfmConfigException {
Sean Condon96b896d2017-12-11 12:44:29 -0800350
351 MepKeyId key = new MepKeyId(mdName, maName, mepId);
352 Mep mep = mepStore.getMep(key)
353 .orElseThrow(() -> new CfmConfigException("Mep " + mdName + "/" + maName + "/"
354 + mepId + " not found when calling Aborting Loopback"));
355
356 log.debug("Aborting Loopback on MEP {} on Device {}",
357 key, mep.deviceId());
358 deviceService.getDevice(mep.deviceId())
359 .as(CfmMepProgrammable.class)
360 .abortLoopback(mdName, maName, mepId);
Sean Condon0e89bda2017-03-21 14:23:19 +0000361 }
362
363 @Override
364 public void transmitLinktrace(MdId mdName, MaIdShort maName, MepId mepId,
Sean Condon96b896d2017-12-11 12:44:29 -0800365 MepLtCreate ltCreate) {
Sean Condon0e89bda2017-03-21 14:23:19 +0000366 throw new UnsupportedOperationException("Not yet implemented");
367 }
368
Sean Condon96b896d2017-12-11 12:44:29 -0800369 private class InternalMdListener implements MdListener {
370 @Override
371 public boolean isRelevant(MdEvent event) {
372 return event.type().equals(MdEvent.Type.MD_REMOVED) ||
373 event.type().equals(MdEvent.Type.MA_REMOVED);
374 }
375
376 @Override
377 public void event(MdEvent event) {
378 MdId mdName = event.subject();
379 switch (event.type()) {
380 case MA_REMOVED:
381 case MD_REMOVED:
382 log.trace("Event {} receieved from MD Service for {}", event.type(), mdName);
383 scheduleEventHandlerIfNotScheduled(event);
384 break;
385 default:
386 log.warn("Unhandled Event {} received from MD Service", event.type());
387 break;
388 }
389 }
390 }
391
Sean Condon0e89bda2017-03-21 14:23:19 +0000392 private class InternalDeviceListener implements DeviceListener {
393 @Override
Sean Condon96b896d2017-12-11 12:44:29 -0800394 public boolean isRelevant(DeviceEvent event) {
395 return event.type().equals(DeviceEvent.Type.DEVICE_REMOVED);
396 }
397
398 @Override
Sean Condon0e89bda2017-03-21 14:23:19 +0000399 public void event(DeviceEvent event) {
Sean Condon96b896d2017-12-11 12:44:29 -0800400 DeviceId deviceId = event.subject().id();
Sean Condon0e89bda2017-03-21 14:23:19 +0000401 switch (event.type()) {
Sean Condon96b896d2017-12-11 12:44:29 -0800402 case DEVICE_ADDED:
403 case PORT_UPDATED:
404 case PORT_ADDED:
405 case DEVICE_UPDATED:
Sean Condon0e89bda2017-03-21 14:23:19 +0000406 case DEVICE_REMOVED:
407 case DEVICE_AVAILABILITY_CHANGED:
Sean Condon96b896d2017-12-11 12:44:29 -0800408 log.trace("Event {} received from Device Service", event.type());
409 scheduleEventHandlerIfNotScheduled(event);
Sean Condon0e89bda2017-03-21 14:23:19 +0000410 break;
411 default:
Sean Condon96b896d2017-12-11 12:44:29 -0800412 log.warn("Unhandled Event {} received from Device Service", event.type());
Sean Condon0e89bda2017-03-21 14:23:19 +0000413 break;
414 }
415 }
416 }
Sean Condon96b896d2017-12-11 12:44:29 -0800417
418 @SuppressWarnings("rawtypes")
419 private void scheduleEventHandlerIfNotScheduled(Event event) {
420 synchronized (THREAD_SCHED_LOCK) {
421 eventQueue.add(event);
422 numOfEventsQueued++;
423
424 if ((numOfHandlerScheduled - numOfHandlerExecution) == 0) {
425 //No pending scheduled event handling threads. So start a new one.
426 eventHandlerFuture = executorService
427 .schedule(eventHandler, 100, TimeUnit.MILLISECONDS);
428 numOfHandlerScheduled++;
429 }
430 log.trace("numOfEventsQueued {}, numOfEventHandlerScheduled {}",
431 numOfEventsQueued,
432 numOfHandlerScheduled);
433 }
434 }
435
436 private class InternalEventHandler implements Runnable {
437 @Override
438 public void run() {
439 try {
440 while (true) {
441 @SuppressWarnings("rawtypes")
442 Event event;
443 synchronized (THREAD_SCHED_LOCK) {
444 if (!eventQueue.isEmpty()) {
445 event = eventQueue.poll();
446 numOfEventsExecuted++;
447 } else {
448 numOfHandlerExecution++;
449 log.debug("numOfHandlerExecution {} numOfEventsExecuted {}",
450 numOfHandlerExecution, numOfEventsExecuted);
451 break;
452 }
453 }
454 if (event.type() == DeviceEvent.Type.DEVICE_REMOVED) {
455 DeviceId deviceId = ((Device) event.subject()).id();
456 log.info("Processing device removal event for unavailable device {}",
457 deviceId);
458 processDeviceRemoved((Device) event.subject());
459 } else if (event.type() == MdEvent.Type.MD_REMOVED) {
460 MdId mdName = (MdId) event.subject();
461 log.info("Processing MD removal event for MD {}",
462 mdName);
463 processMdRemoved(mdName, ((MdEvent) event).md().get());
464 } else if (event.type() == MdEvent.Type.MA_REMOVED) {
465 MdId mdName = (MdId) event.subject();
466 MaIdShort maName = ((MdEvent) event).maId().get();
467 log.info("Processing MA removal event for MA {}",
468 mdName.mdName() + "/" + maName.maName());
469 processMaRemoved(mdName, maName, ((MdEvent) event).md().get());
470 }
471 }
472 } catch (Exception e) {
473 log.error("CfmMepService event handler "
474 + "thread thrown an exception: {}", e);
475 }
476 }
477 }
478
479 /**
480 * This removes a MEP from the internal list of Meps, and updates remote meps list on other Meps.
481 * Note: This does not call the device's CfmMepProgrammable, because there
482 * would be no point as the device has already been removed from ONOS.
483 * The configuration for this MEP may still be present on the actual device, and
484 * any future config would have to be careful to wipe the Mep from the device
485 * before applying a Mep again
486 * @param removedDevice The device that has been removed
487 */
488 protected void processDeviceRemoved(Device removedDevice) {
489 log.warn("Remove Mep(s) associated with Device: " + removedDevice.id());
490 Collection<Mep> mepListForDevice = mepStore.getMepsByDeviceId(removedDevice.id());
491
492
493 for (Mep mep:mepStore.getAllMeps()) {
494 for (Mep mepForDevice:mepListForDevice) {
495 if (mep.mdId().equals(mepForDevice.mdId()) && mep.maId().equals(mepForDevice.maId())) {
496 Device mepDevice = deviceService.getDevice(mep.deviceId());
497 log.info("Removing Remote Mep {} from MA{} on device {}",
498 mepForDevice.mepId(),
499 mep.mdId().mdName() + "/" + mep.maId().maName(),
500 mepDevice.id());
501 try {
502 mepDevice.as(CfmMepProgrammable.class)
503 .deleteMaRemoteMepOnDevice(mep.mdId(), mep.maId(), mepForDevice.mepId());
504 } catch (CfmConfigException e) {
505 log.error("Error when removing Remote Mep {} from MA {}. Continuing.",
506 mep.mdId().mdName() + "/" + mep.maId().maName(),
507 mepForDevice.mepId());
508 }
509 }
510 }
511 }
512
513 for (Iterator<Mep> iter = mepListForDevice.iterator(); iter.hasNext();) {
514 mepStore.deleteMep(new MepKeyId(iter.next()));
515 }
516 }
517
518 protected void processMaRemoved(MdId mdId, MaIdShort maId, MaintenanceDomain oldMd) {
519 Set<DeviceId> deviceIdsRemoved = new HashSet<>();
520
521 for (Iterator<Mep> iter = mepStore.getMepsByMdMa(mdId, maId).iterator(); iter.hasNext();) {
522 Mep mepForMdMa = iter.next();
523 DeviceId mepDeviceId = mepForMdMa.deviceId();
524 try {
525 deviceService.getDevice(mepDeviceId).as(CfmMepProgrammable.class)
526 .deleteMep(mdId, maId, mepForMdMa.mepId(), Optional.of(oldMd));
527 deviceIdsRemoved.add(mepDeviceId);
528 } catch (CfmConfigException e) {
529 log.warn("Could not delete MEP {} from Device {}", mepForMdMa.mepId(), mepDeviceId, e);
530 }
531 iter.remove();
532
533 log.info("Removed MEP {} from Device {} because MA {} was deleted",
534 mepForMdMa.mepId(), mepDeviceId, mdId.mdName() + "/" + maId.maName());
535 }
536
537 deviceIdsRemoved.forEach(deviceId -> {
538 try {
539 deviceService.getDevice(deviceId).as(CfmMepProgrammable.class)
540 .deleteMaOnDevice(mdId, maId, Optional.of(oldMd));
541 } catch (CfmConfigException e) {
542 log.warn("Could not delete MA {} from Device {}",
543 mdId.mdName() + "/" + maId.maName(), deviceId, e);
544 }
545 });
546 }
547
548 protected void processMdRemoved(MdId mdId, MaintenanceDomain oldMd) {
549 Set<DeviceId> deviceIdsRemoved = new HashSet<>();
550 for (Iterator<Mep> iter = mepStore.getMepsByMd(mdId).iterator(); iter.hasNext();) {
551 Mep mep = iter.next();
552 DeviceId mepDeviceId = mep.deviceId();
553 try {
554 deviceService.getDevice(mepDeviceId).as(CfmMepProgrammable.class)
555 .deleteMep(mdId, mep.maId(), mep.mepId(), Optional.of(oldMd));
556 deviceIdsRemoved.add(mepDeviceId);
557 } catch (CfmConfigException e) {
558 log.warn("Could not delete MEP {} from Device {}", mep.mepId(), mepDeviceId, e);
559 }
560 iter.remove();
561 log.info("Removed MEP {} from Device {} because MD {} was deleted",
562 mep.mepId(), mepDeviceId, mdId.mdName());
563 }
564
565 deviceIdsRemoved.forEach(deviceId -> {
566 try {
567 deviceService.getDevice(deviceId).as(CfmMepProgrammable.class)
568 .deleteMdOnDevice(mdId, Optional.of(oldMd));
569 } catch (CfmConfigException e) {
570 log.warn("Could not delete MD {} from Device {}",
571 mdId.mdName(), deviceId, e);
572 }
573 });
574 }
575
576 private class InternalStoreDelegate implements MepStoreDelegate {
577 @Override
578 public void notify(CfmMepEvent event) {
579 log.debug("New Mep event: {}", event);
580 eventDispatcher.post(event);
581 }
582 }
Sean Condon0e89bda2017-03-21 14:23:19 +0000583}