2 * Copyright (c) 2016 Hewlett Packard Enterprise, Co. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.unimgr.mef.netvirt;
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.List;
14 import java.util.stream.Collectors;
16 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
17 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
18 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.unimgr.api.UnimgrDataTreeChangeListener;
21 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.services.rev150526.mef.services.MefService;
22 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.services.rev150526.mef.services.mef.service.mef.service.choice.evc.choice.Evc;
23 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.services.rev150526.mef.services.mef.service.mef.service.choice.evc.choice.evc.unis.Uni;
24 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.services.rev150526.mef.services.mef.service.mef.service.choice.evc.choice.evc.unis.uni.EvcUniCeVlans;
25 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.services.rev150526.mef.services.mef.service.mef.service.choice.evc.choice.evc.unis.uni.evc.uni.ce.vlans.EvcUniCeVlan;
26 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.services.rev150526.EvcElan;
27 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.services.rev150526.EvcElanBuilder;
28 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.services.rev150526.mef.services.mef.service.mef.service.choice.evc.choice.evc.ElanPorts;
29 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.services.rev150526.mef.services.mef.service.mef.service.choice.evc.choice.evc.ElanPortsBuilder;
31 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.types.rev150526.EvcType;
32 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.types.rev150526.EvcUniRoleType;
33 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.types.rev150526.Identifier45;
34 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.types.rev150526.RetailSvcIdType;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface.EtreeInterfaceType;
36 import org.opendaylight.yangtools.concepts.ListenerRegistration;
37 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
41 import com.google.common.base.Optional;
43 import jline.internal.Log;
45 public class EvcListener extends UnimgrDataTreeChangeListener<Evc> implements IUniAwareService {
47 private static final Logger log = LoggerFactory.getLogger(EvcListener.class);
48 private ListenerRegistration<EvcListener> evcListenerRegistration;
49 private final IUniPortManager uniPortManager;
50 private final UniQosManager uniQosManager;
51 @SuppressWarnings("unused")
52 private final UniAwareListener uniAwareListener;
54 public EvcListener(final DataBroker dataBroker, final UniPortManager uniPortManager,
55 final UniQosManager uniQosManager) {
57 this.uniPortManager = uniPortManager;
58 this.uniQosManager = uniQosManager;
59 this.uniAwareListener = new UniAwareListener(dataBroker, this);
63 public void registerListener() {
65 final DataTreeIdentifier<Evc> dataTreeIid = new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
66 MefServicesUtils.getEvcsInstanceIdentifier());
67 evcListenerRegistration = dataBroker.registerDataTreeChangeListener(dataTreeIid, this);
68 log.info("EvcDataTreeChangeListener created and registered");
69 } catch (final Exception e) {
70 log.error("Evc DataChange listener registration failed !", e);
71 throw new IllegalStateException("Evc registration Listener failed.", e);
76 public void close() throws Exception {
77 evcListenerRegistration.close();
81 public void add(DataTreeModification<Evc> newDataObject) {
82 if (newDataObject.getRootPath() != null && newDataObject.getRootNode() != null) {
83 log.info("evc {} created", newDataObject.getRootNode().getIdentifier());
84 addEvc(newDataObject);
89 public void remove(DataTreeModification<Evc> removedDataObject) {
90 if (removedDataObject.getRootPath() != null && removedDataObject.getRootNode() != null) {
91 log.info("evc {} deleted", removedDataObject.getRootNode().getIdentifier());
92 removeEvc(removedDataObject);
97 public void update(DataTreeModification<Evc> modifiedDataObject) {
98 if (modifiedDataObject.getRootPath() != null && modifiedDataObject.getRootNode() != null) {
99 log.info("evc {} updated", modifiedDataObject.getRootNode().getIdentifier());
100 updateEvc(modifiedDataObject);
105 public void connectUni(String uniId) {
106 List<RetailSvcIdType> allEvcs = MefServicesUtils.getAllEvcsServiceIds(dataBroker);
107 allEvcs = (allEvcs != null) ? allEvcs : Collections.emptyList();
109 for (RetailSvcIdType evcSerId : allEvcs) {
110 InstanceIdentifier<Evc> evcId = MefServicesUtils.getEvcInstanceIdentifier(evcSerId);
111 Evc evc = MefServicesUtils.getEvc(dataBroker, evcId);
113 Log.error("Inconsistent data for svcId {}", evcSerId);
117 String instanceName = evc.getEvcId().getValue();
118 boolean isEtree = evc.getEvcType() == EvcType.RootedMultipoint;
120 List<Uni> toConnect = new ArrayList<>();
121 List<Uni> unis = (evc.getUnis() != null) ? evc.getUnis().getUni() : null;
122 unis = (unis != null) ? unis : Collections.emptyList();
123 for (Uni uni : unis) {
124 if (uni.getUniId().getValue().equals(uniId)) {
125 Log.info("Connecting Uni {} to svc id {}", uniId, evcSerId);
131 EvcElan evcElan = getOperEvcElan(evcId);
132 if (evcElan == null) {
133 NetvirtUtils.createElanInstance(dataBroker, instanceName, isEtree, evc.getSegmentationId());
134 evcElan = getOperEvcElan(evcId);
135 if (evcElan == null) {
136 log.error("Evc {} has not been created as required. Nothing to reconnect", evcId);
141 for (Uni uni : toConnect) {
142 createUniElanInterfaces(evcId, instanceName, uni, isEtree);
144 updateQos(toConnect);
149 public void disconnectUni(String uniId) {
150 List<RetailSvcIdType> allEvcs = MefServicesUtils.getAllEvcsServiceIds(dataBroker);
151 allEvcs = (allEvcs != null) ? allEvcs : Collections.emptyList();
153 for (RetailSvcIdType evcSerId : allEvcs) {
154 InstanceIdentifier<Evc> evcId = MefServicesUtils.getEvcInstanceIdentifier(evcSerId);
155 Evc evc = MefServicesUtils.getEvc(dataBroker, evcId);
157 Log.error("Inconsistent data for svcId {}", evcSerId);
161 String instanceName = evc.getEvcId().getValue();
162 List<Uni> toDisconnect = new ArrayList<>();
163 List<Uni> unis = (evc.getUnis() != null) ? evc.getUnis().getUni() : null;
164 unis = (unis != null) ? unis : Collections.emptyList();
165 for (Uni uni : unis) {
166 if (uni.getUniId().getValue().equals(uniId)) {
167 Log.info("Disconnecting Uni {} from svc id {}", uniId, evcSerId);
168 toDisconnect.add(uni);
173 EvcElan evcElan = getOperEvcElan(evcId);
174 if (evcElan == null) {
175 log.error("Evc {} has not been created as required. Nothing to disconnect", evcId);
179 updateQos(toDisconnect);
180 for (Uni uni : toDisconnect) {
181 removeUniElanInterfaces(evcId, instanceName, uni);
187 private void addEvc(DataTreeModification<Evc> newDataObject) {
189 Evc data = newDataObject.getRootNode().getDataAfter();
190 String instanceName = data.getEvcId().getValue();
191 boolean isEtree = data.getEvcType() == EvcType.RootedMultipoint;
192 InstanceIdentifier<Evc> evcId = newDataObject.getRootPath().getRootIdentifier();
194 synchronized (instanceName.intern()) {
195 NetvirtUtils.createElanInstance(dataBroker, instanceName, isEtree, data.getSegmentationId(),
196 data.getMacTimeout());
199 if (data.getUnis() == null) {
200 log.info("No UNI's in service {}, exiting", instanceName);
203 for (Uni uni : data.getUnis().getUni()) {
204 createUniElanInterfaces(evcId, instanceName, uni, isEtree);
206 updateQos(data.getUnis().getUni());
208 } catch (final Exception e) {
209 log.error("Add evc failed !", e);
213 private void removeEvc(DataTreeModification<Evc> removedDataObject) {
215 Evc data = removedDataObject.getRootNode().getDataBefore();
216 InstanceIdentifier<Evc> evcId = removedDataObject.getRootPath().getRootIdentifier();
217 List<Uni> uniToRemove = data.getUnis() != null && data.getUnis().getUni() != null ? data.getUnis().getUni()
218 : Collections.emptyList();
220 synchronized (data.getEvcId().getValue().intern()) {
221 updateQos(uniToRemove);
222 EvcElan evcElan = getOperEvcElan(evcId);
223 if (evcElan == null) {
224 log.error("Evc {} has not been created as required. Nothing to remove", data.getEvcId().getValue());
228 String instanceName = evcElan.getElanId();
230 for (Uni uni : uniToRemove) {
231 removeUniElanInterfaces(evcId, instanceName, uni);
234 log.info("Removing elan instance: " + instanceName);
235 NetvirtUtils.deleteElanInstance(dataBroker, instanceName);
236 removeOperEvcElan(evcId);
238 } catch (final Exception e) {
239 log.error("Remove evc failed !", e);
243 private void updateEvc(DataTreeModification<Evc> modifiedDataObject) {
244 InstanceIdentifier<Evc> evcId = modifiedDataObject.getRootPath().getRootIdentifier();
247 Evc original = modifiedDataObject.getRootNode().getDataBefore();
248 Evc update = modifiedDataObject.getRootNode().getDataAfter();
250 List<Uni> originalUni = original.getUnis() != null && original.getUnis().getUni() != null
251 ? original.getUnis().getUni() : Collections.emptyList();
252 List<Identifier45> originalUniIds = originalUni.stream().map(u -> u.getUniId())
253 .collect(Collectors.toList());
254 List<Uni> updateUni = update.getUnis() != null && update.getUnis().getUni() != null
255 ? update.getUnis().getUni() : Collections.emptyList();
256 List<Identifier45> updateUniIds = updateUni.stream().map(u -> u.getUniId()).collect(Collectors.toList());
258 synchronized (original.getEvcId().getValue().intern()) {
260 String instanceName = original.getEvcId().getValue();
261 boolean isEtree = update.getEvcType() == EvcType.RootedMultipoint;
262 log.info("Updating {} instance: {}", isEtree ? "etree" : "elan", instanceName);
264 // Changed Uni will be deleted / recreated
265 List<Uni> uniToRemove = new ArrayList<>(originalUni);
266 uniToRemove.removeIf(u -> updateUniIds.contains(u.getUniId()));
267 for (Uni uni : uniToRemove) {
268 removeUniElanInterfaces(evcId, instanceName, uni);
270 updateQos(uniToRemove);
272 List<Uni> uniToCreate = new ArrayList<>(updateUni);
273 uniToCreate.removeIf(u -> originalUniIds.contains(u.getUniId()));
274 uniToCreate.removeAll(originalUni);
275 for (Uni uni : uniToCreate) {
276 createUniElanInterfaces(evcId, instanceName, uni, isEtree);
278 updateQos(uniToCreate);
280 List<Uni> uniToUpdate = new ArrayList<>(updateUni);
281 uniToUpdate.removeIf(u -> !originalUniIds.contains(u.getUniId()));
282 updateUnis(uniToUpdate);
284 } catch (final Exception e) {
285 log.error("Update evc failed !", e);
289 private void createUniElanInterfaces(InstanceIdentifier<Evc> evcId, String instanceName, Uni uni, boolean isEtree) {
290 EvcUniRoleType role = uni.getRole();
291 EvcUniCeVlans evcUniCeVlans = uni.getEvcUniCeVlans();
293 List<EvcUniCeVlan> evcUniCeVlan = evcUniCeVlans != null && evcUniCeVlans.getEvcUniCeVlan() != null
294 && !evcUniCeVlans.getEvcUniCeVlan().isEmpty() ? evcUniCeVlans.getEvcUniCeVlan()
295 : Collections.emptyList();
297 for (EvcUniCeVlan ceVlan : evcUniCeVlan) {
298 Long vlan = safeCastVlan(ceVlan.getVid());
299 uniPortManager.addCeVlan(uni.getUniId().getValue(), vlan);
302 if (evcUniCeVlan.isEmpty()) {
303 String interfaceName = uniPortManager.getUniVlanInterface(uni.getUniId().getValue(), Long.valueOf(0));
304 if (interfaceName == null) {
305 String errorMessage = String.format("Uni %s Interface for vlan %d is not operational ", uni.getUniId(),
307 Log.error(errorMessage);
308 throw new UnsupportedOperationException(errorMessage);
310 if (isOperEvcElanPort(evcId, interfaceName)) {
311 log.info("elan interface for elan {} vlan {} interface {} exists already", instanceName, 0,
315 log.info("Creting elan interface for elan {} vlan {} interface {}", instanceName, 0, interfaceName);
316 NetvirtUtils.createElanInterface(dataBroker, instanceName, interfaceName, roleToInterfaceType(role),
318 uniQosManager.mapUniPortBandwidthLimits(uni.getUniId().getValue(), interfaceName,
319 uni.getIngressBwProfile());
320 setOperEvcElanPort(evcId, instanceName, interfaceName);
322 for (EvcUniCeVlan ceVlan : evcUniCeVlan) {
323 Long vlan = safeCastVlan(ceVlan.getVid());
324 String interfaceName = uniPortManager.getUniVlanInterface(uni.getUniId().getValue(), vlan);
325 if (interfaceName == null) {
326 String errorMessage = String.format("Uni %s Interface for vlan %d is not operational ",
328 Log.error(errorMessage);
329 throw new UnsupportedOperationException(errorMessage);
331 if (isOperEvcElanPort(evcId, interfaceName)) {
332 log.info("elan interface for elan {} vlan {} interface {} exists already", instanceName, 0,
336 log.info("Creting elan interface for elan {} vlan {} interface {}", instanceName, 0, interfaceName);
337 NetvirtUtils.createElanInterface(dataBroker, instanceName, interfaceName, roleToInterfaceType(role),
339 uniQosManager.mapUniPortBandwidthLimits(uni.getUniId().getValue(), interfaceName,
340 uni.getIngressBwProfile());
341 setOperEvcElanPort(evcId, instanceName, interfaceName);
346 private void removeUniElanInterfaces(InstanceIdentifier<Evc> evcId, String instanceName, Uni uni) {
347 EvcUniCeVlans evcUniCeVlans = uni.getEvcUniCeVlans();
349 List<EvcUniCeVlan> evcUniCeVlan = evcUniCeVlans != null && evcUniCeVlans.getEvcUniCeVlan() != null
350 && !evcUniCeVlans.getEvcUniCeVlan().isEmpty() ? evcUniCeVlans.getEvcUniCeVlan()
351 : Collections.emptyList();
353 if (evcUniCeVlan.isEmpty()) {
354 String interfaceName = uniPortManager.getUniVlanInterface(uni.getUniId().getValue(), Long.valueOf(0));
355 if (interfaceName == null || !isOperEvcElanPort(evcId, interfaceName)) {
356 log.info("elan interface for elan {} vlan {} is not operational, nothing to remove", instanceName, 0,
358 interfaceName = uniPortManager.getUniVlanInterfaceName(uni.getUniId().getValue(), null);
360 removeElanInterface(evcId, uni.getUniId().getValue(), interfaceName);
362 for (EvcUniCeVlan ceVlan : evcUniCeVlan) {
363 Long vlan = safeCastVlan(ceVlan.getVid());
364 String interfaceName = uniPortManager.getUniVlanInterface(uni.getUniId().getValue(), vlan);
365 if (interfaceName == null || !isOperEvcElanPort(evcId, interfaceName)) {
366 log.info("elan interface for elan {} vlan {} is not operational, nothing to remove", instanceName,
367 vlan, interfaceName);
368 interfaceName = uniPortManager.getUniVlanInterfaceName(uni.getUniId().getValue(), vlan);
370 removeElanInterface(evcId, uni.getUniId().getValue(), interfaceName);
374 for (EvcUniCeVlan ceVlan : evcUniCeVlan) {
375 Long vlan = safeCastVlan(ceVlan.getVid());
376 uniPortManager.removeCeVlan(uni.getUniId().getValue(), vlan);
380 private void removeElanInterface(InstanceIdentifier<Evc> identifier, String uniId, String interfaceName) {
381 log.info("Removing elan interface: " + interfaceName);
382 uniQosManager.unMapUniPortBandwidthLimits(uniId, interfaceName);
383 NetvirtUtils.deleteElanInterface(dataBroker, interfaceName);
385 EvcElan evcElan = getOperEvcElan(identifier);
386 if (evcElan == null) {
387 log.error("Removing non-operational Elan interface {}", interfaceName);
390 deleteOperEvcElanPort(identifier, interfaceName);
393 // Expected from API is Long
394 private Long safeCastVlan(Object vid) {
395 if (!(vid instanceof Long)) {
396 String errorMessage = String.format("vlan id %s cannot be cast to Long", vid);
397 log.error(errorMessage);
398 throw new UnsupportedOperationException(errorMessage);
403 private static EtreeInterfaceType roleToInterfaceType(EvcUniRoleType role) {
404 if (role == EvcUniRoleType.Root) {
405 return EtreeInterfaceType.Root;
407 return EtreeInterfaceType.Leaf;
411 private EvcElan getOperEvcElan(InstanceIdentifier<Evc> identifier) {
412 InstanceIdentifier<EvcElan> path = identifier.augmentation(EvcElan.class);
413 Optional<EvcElan> evcElan = MdsalUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL, path);
414 if (evcElan.isPresent()) {
415 return evcElan.get();
421 private void removeOperEvcElan(InstanceIdentifier<Evc> identifier) {
422 final InstanceIdentifier<MefService> serviceId = identifier.firstIdentifierOf(MefService.class);
423 MdsalUtils.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, serviceId);
426 private boolean isOperEvcElanPort(InstanceIdentifier<Evc> identifier, String elanPort) {
427 EvcElan evcElan = getOperEvcElan(identifier);
428 if (evcElan == null || evcElan.getElanPorts() == null) {
431 List<ElanPorts> exPorts = evcElan.getElanPorts();
432 return exPorts.stream().anyMatch(p -> p.getPortId().equals(elanPort));
435 private void setOperEvcElanPort(InstanceIdentifier<Evc> identifier, String elanName, String elanPort) {
436 InstanceIdentifier<EvcElan> path = identifier.augmentation(EvcElan.class);
437 EvcElan evcElan = getOperEvcElan(identifier);
438 EvcElanBuilder evcElanBuilder = evcElan != null ? new EvcElanBuilder(evcElan) : new EvcElanBuilder();
439 List<ElanPorts> exPorts = evcElan != null && evcElan.getElanPorts() != null ? evcElan.getElanPorts()
442 ElanPortsBuilder portB = new ElanPortsBuilder();
443 portB.setPortId(elanPort);
444 exPorts.add(portB.build());
445 evcElanBuilder.setElanId(elanName);
446 evcElanBuilder.setElanPorts(exPorts);
447 MdsalUtils.write(dataBroker, LogicalDatastoreType.OPERATIONAL, path, evcElanBuilder.build());
450 private void deleteOperEvcElanPort(InstanceIdentifier<Evc> identifier, String elanPort) {
451 InstanceIdentifier<EvcElan> path = identifier.augmentation(EvcElan.class);
452 EvcElan evcElan = getOperEvcElan(identifier);
453 EvcElanBuilder evcElanBuilder = null;
454 List<ElanPorts> exPorts = Collections.emptyList();
455 if (evcElan != null) {
456 evcElanBuilder = new EvcElanBuilder(evcElan);
457 exPorts = evcElan.getElanPorts() != null ? evcElan.getElanPorts() : Collections.emptyList();
459 Log.error("Deleting non-operational Elan port {}", elanPort);
462 List<ElanPorts> newList = exPorts.stream().filter(p -> !p.getPortId().equals(elanPort))
463 .collect(Collectors.toList());
464 evcElanBuilder.setElanPorts(newList);
465 MdsalUtils.write(dataBroker, LogicalDatastoreType.OPERATIONAL, path, evcElanBuilder.build());
468 private void updateQos(List<Uni> uniToUpdate) {
469 uniToUpdate.forEach(u -> uniQosManager.setUniBandwidthLimits(u.getUniId()));
472 private void updateUnis(List<Uni> uniToUpdate) {
473 uniToUpdate.forEach(u -> uniQosManager.updateUni(u.getUniId(), u.getIngressBwProfile()));
474 updateQos(uniToUpdate);