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.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface.EtreeInterfaceType;
34 import org.opendaylight.yangtools.concepts.ListenerRegistration;
35 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
39 import com.google.common.base.Optional;
41 import jline.internal.Log;
43 public class EvcListener extends UnimgrDataTreeChangeListener<Evc> {
45 private static final Logger log = LoggerFactory.getLogger(EvcListener.class);
46 private ListenerRegistration<EvcListener> evcListenerRegistration;
47 private final IUniPortManager uniPortManager;
48 private final UniQosManager uniQosManager;
50 public EvcListener(final DataBroker dataBroker, final UniPortManager uniPortManager,
51 final UniQosManager uniQosManager) {
53 this.uniPortManager = uniPortManager;
54 this.uniQosManager = uniQosManager;
58 public void registerListener() {
60 final DataTreeIdentifier<Evc> dataTreeIid = new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
61 MefServicesUtils.getEvcsInstanceIdentifier());
62 evcListenerRegistration = dataBroker.registerDataTreeChangeListener(dataTreeIid, this);
63 log.info("EvcDataTreeChangeListener created and registered");
64 } catch (final Exception e) {
65 log.error("Evc DataChange listener registration failed !", e);
66 throw new IllegalStateException("Evc registration Listener failed.", e);
71 public void close() throws Exception {
72 evcListenerRegistration.close();
76 public void add(DataTreeModification<Evc> newDataObject) {
77 if (newDataObject.getRootPath() != null && newDataObject.getRootNode() != null) {
78 log.info("evc {} created", newDataObject.getRootNode().getIdentifier());
79 addEvc(newDataObject);
84 public void remove(DataTreeModification<Evc> removedDataObject) {
85 if (removedDataObject.getRootPath() != null && removedDataObject.getRootNode() != null) {
86 log.info("evc {} deleted", removedDataObject.getRootNode().getIdentifier());
87 removeEvc(removedDataObject);
92 public void update(DataTreeModification<Evc> modifiedDataObject) {
93 if (modifiedDataObject.getRootPath() != null && modifiedDataObject.getRootNode() != null) {
94 log.info("evc {} updated", modifiedDataObject.getRootNode().getIdentifier());
95 updateEvc(modifiedDataObject);
99 private void addEvc(DataTreeModification<Evc> newDataObject) {
101 Evc data = newDataObject.getRootNode().getDataAfter();
102 String instanceName = data.getEvcId().getValue();
103 boolean isEtree = data.getEvcType() == EvcType.RootedMultipoint;
104 InstanceIdentifier<Evc> evcId = newDataObject.getRootPath().getRootIdentifier();
106 synchronized (instanceName.intern()) {
107 NetvirtUtils.createElanInstance(dataBroker, instanceName, isEtree, data.getSegmentationId());
110 if (data.getUnis() == null) {
111 log.info("No UNI's in service {}, exiting", instanceName);
114 for (Uni uni : data.getUnis().getUni()) {
115 createUniElanInterfaces(evcId, instanceName, uni, isEtree);
117 updateQos(data.getUnis().getUni());
119 } catch (final Exception e) {
120 log.error("Add evc failed !", e);
124 private void removeEvc(DataTreeModification<Evc> removedDataObject) {
126 Evc data = removedDataObject.getRootNode().getDataBefore();
127 InstanceIdentifier<Evc> evcId = removedDataObject.getRootPath().getRootIdentifier();
128 List<Uni> uniToRemove = data.getUnis() != null && data.getUnis().getUni() != null ? data.getUnis().getUni()
129 : Collections.emptyList();
131 synchronized (data.getEvcId().getValue().intern()) {
132 updateQos(uniToRemove);
133 EvcElan evcElan = getOperEvcElan(evcId);
134 if (evcElan == null) {
135 log.error("Evc {} has not been created as required. Nothing to remove", data.getEvcId().getValue());
139 String instanceName = evcElan.getElanId();
141 for (Uni uni : uniToRemove) {
142 removeUniElanInterfaces(evcId, instanceName, uni);
145 log.info("Removing elan instance: " + instanceName);
146 NetvirtUtils.deleteElanInstance(dataBroker, instanceName);
147 removeOperEvcElan(evcId);
149 } catch (final Exception e) {
150 log.error("Remove evc failed !", e);
154 private void updateEvc(DataTreeModification<Evc> modifiedDataObject) {
155 InstanceIdentifier<Evc> evcId = modifiedDataObject.getRootPath().getRootIdentifier();
158 Evc original = modifiedDataObject.getRootNode().getDataBefore();
159 Evc update = modifiedDataObject.getRootNode().getDataAfter();
161 List<Uni> originalUni = original.getUnis() != null && original.getUnis().getUni() != null
162 ? original.getUnis().getUni() : Collections.emptyList();
163 List<Uni> updateUni = update.getUnis() != null && update.getUnis().getUni() != null
164 ? update.getUnis().getUni() : Collections.emptyList();
166 synchronized (original.getEvcId().getValue().intern()) {
168 String instanceName = original.getEvcId().getValue();
169 boolean isEtree = update.getEvcType() == EvcType.RootedMultipoint;
170 log.info("Updating {} instance: {}", isEtree ? "etree" : "elan", instanceName);
172 // Changed Uni will be deleted / recreated
173 List<Uni> uniToRemove = new ArrayList<>(originalUni);
174 uniToRemove.removeAll(updateUni);
175 for (Uni uni : uniToRemove) {
176 removeUniElanInterfaces(evcId, instanceName, uni);
178 updateQos(uniToRemove);
180 List<Uni> uniToCreate = new ArrayList<>(updateUni);
181 uniToCreate.removeAll(originalUni);
182 for (Uni uni : uniToCreate) {
183 createUniElanInterfaces(evcId, instanceName, uni, isEtree);
185 updateQos(uniToCreate);
187 } catch (final Exception e) {
188 log.error("Update evc failed !", e);
192 private void createUniElanInterfaces(InstanceIdentifier<Evc> evcId, String instanceName, Uni uni, boolean isEtree) {
193 EvcUniRoleType role = uni.getRole();
194 EvcUniCeVlans evcUniCeVlans = uni.getEvcUniCeVlans();
196 List<EvcUniCeVlan> evcUniCeVlan = evcUniCeVlans != null && evcUniCeVlans.getEvcUniCeVlan() != null
197 && !evcUniCeVlans.getEvcUniCeVlan().isEmpty() ? evcUniCeVlans.getEvcUniCeVlan()
198 : Collections.emptyList();
200 for (EvcUniCeVlan ceVlan : evcUniCeVlan) {
201 Long vlan = safeCastVlan(ceVlan.getVid());
202 uniPortManager.addCeVlan(uni.getUniId().getValue(), vlan);
205 if (evcUniCeVlan.isEmpty()) {
206 String interfaceName = uniPortManager.getUniVlanInterface(uni.getUniId().getValue(), Long.valueOf(0));
207 if (interfaceName == null) {
208 String errorMessage = String.format("Uni %s Interface for vlan %d is not operational ", uni.getUniId(),
210 Log.error(errorMessage);
211 throw new UnsupportedOperationException(errorMessage);
213 if (isOperEvcElanPort(evcId, interfaceName)) {
214 log.info("elan interface for elan {} vlan {} interface {} exists already", instanceName, 0,
218 log.info("Creting elan interface for elan {} vlan {} interface {}", instanceName, 0, interfaceName);
219 NetvirtUtils.createElanInterface(dataBroker, instanceName, interfaceName, roleToInterfaceType(role),
221 uniQosManager.mapUniPortBandwidthLimits(uni.getUniId().getValue(), interfaceName,
222 uni.getIngressBwProfile());
223 setOperEvcElanPort(evcId, instanceName, interfaceName);
225 for (EvcUniCeVlan ceVlan : evcUniCeVlan) {
226 Long vlan = safeCastVlan(ceVlan.getVid());
227 String interfaceName = uniPortManager.getUniVlanInterface(uni.getUniId().getValue(), vlan);
228 if (interfaceName == null) {
229 String errorMessage = String.format("Uni %s Interface for vlan %d is not operational ",
231 Log.error(errorMessage);
232 throw new UnsupportedOperationException(errorMessage);
234 if (isOperEvcElanPort(evcId, interfaceName)) {
235 log.info("elan interface for elan {} vlan {} interface {} exists already", instanceName, 0,
239 log.info("Creting elan interface for elan {} vlan {} interface {}", instanceName, 0, interfaceName);
240 NetvirtUtils.createElanInterface(dataBroker, instanceName, interfaceName, roleToInterfaceType(role),
242 uniQosManager.mapUniPortBandwidthLimits(uni.getUniId().getValue(), interfaceName,
243 uni.getIngressBwProfile());
244 setOperEvcElanPort(evcId, instanceName, interfaceName);
249 private void removeUniElanInterfaces(InstanceIdentifier<Evc> evcId, String instanceName, Uni uni) {
250 EvcUniCeVlans evcUniCeVlans = uni.getEvcUniCeVlans();
252 List<EvcUniCeVlan> evcUniCeVlan = evcUniCeVlans != null && evcUniCeVlans.getEvcUniCeVlan() != null
253 && !evcUniCeVlans.getEvcUniCeVlan().isEmpty() ? evcUniCeVlans.getEvcUniCeVlan()
254 : Collections.emptyList();
256 for (EvcUniCeVlan ceVlan : evcUniCeVlan) {
257 Long vlan = safeCastVlan(ceVlan.getVid());
258 uniPortManager.removeCeVlan(uni.getUniId().getValue(), vlan);
261 if (evcUniCeVlan.isEmpty()) {
262 String interfaceName = uniPortManager.getUniVlanInterface(uni.getUniId().getValue(), Long.valueOf(0));
263 if (!isOperEvcElanPort(evcId, interfaceName)) {
264 log.info("elan interface for elan {} vlan {} is not operational, nothing to remove", instanceName, 0,
268 removeElanInterface(evcId, uni.getUniId().getValue(), interfaceName);
270 for (EvcUniCeVlan ceVlan : evcUniCeVlan) {
271 Long vlan = safeCastVlan(ceVlan.getVid());
272 String interfaceName = uniPortManager.getUniVlanInterface(uni.getUniId().getValue(), vlan);
273 if (!isOperEvcElanPort(evcId, interfaceName)) {
274 log.info("elan interface for elan {} vlan {} is not operational, nothing to remove", instanceName,
275 vlan, interfaceName);
278 removeElanInterface(evcId, uni.getUniId().getValue(), interfaceName);
283 private void removeElanInterface(InstanceIdentifier<Evc> identifier, String uniId, String interfaceName) {
284 log.info("Removing elan interface: " + interfaceName);
285 uniQosManager.unMapUniPortBandwidthLimits(uniId, interfaceName);
286 NetvirtUtils.deleteElanInterface(dataBroker, interfaceName);
288 EvcElan evcElan = getOperEvcElan(identifier);
289 if (evcElan == null) {
290 log.error("Removing non-operational Elan interface {}", interfaceName);
293 deleteOperEvcElanPort(identifier, interfaceName);
296 // Expected from API is Long
297 private Long safeCastVlan(Object vid) {
298 if (!(vid instanceof Long)) {
299 String errorMessage = String.format("vlan id %s cannot be cast to Long", vid);
300 log.error(errorMessage);
301 throw new UnsupportedOperationException(errorMessage);
306 private static EtreeInterfaceType roleToInterfaceType(EvcUniRoleType role) {
307 if (role == EvcUniRoleType.Root) {
308 return EtreeInterfaceType.Root;
310 return EtreeInterfaceType.Leaf;
314 private EvcElan getOperEvcElan(InstanceIdentifier<Evc> identifier) {
315 InstanceIdentifier<EvcElan> path = identifier.augmentation(EvcElan.class);
316 Optional<EvcElan> evcElan = MdsalUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL, path);
317 if (evcElan.isPresent()) {
318 return evcElan.get();
324 private void removeOperEvcElan(InstanceIdentifier<Evc> identifier) {
325 final InstanceIdentifier<MefService> serviceId = identifier.firstIdentifierOf(MefService.class);
326 MdsalUtils.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, serviceId);
329 private boolean isOperEvcElanPort(InstanceIdentifier<Evc> identifier, String elanPort) {
330 EvcElan evcElan = getOperEvcElan(identifier);
331 if (evcElan == null || evcElan.getElanPorts() == null) {
334 List<ElanPorts> exPorts = evcElan.getElanPorts();
335 return exPorts.stream().anyMatch(p -> p.getPortId().equals(elanPort));
338 private void setOperEvcElanPort(InstanceIdentifier<Evc> identifier, String elanName, String elanPort) {
339 InstanceIdentifier<EvcElan> path = identifier.augmentation(EvcElan.class);
340 EvcElan evcElan = getOperEvcElan(identifier);
341 EvcElanBuilder evcElanBuilder = evcElan != null ? new EvcElanBuilder(evcElan) : new EvcElanBuilder();
342 List<ElanPorts> exPorts = evcElan != null && evcElan.getElanPorts() != null ? evcElan.getElanPorts()
345 ElanPortsBuilder portB = new ElanPortsBuilder();
346 portB.setPortId(elanPort);
347 exPorts.add(portB.build());
348 evcElanBuilder.setElanId(elanName);
349 evcElanBuilder.setElanPorts(exPorts);
350 MdsalUtils.write(dataBroker, LogicalDatastoreType.OPERATIONAL, path, evcElanBuilder.build());
353 private void deleteOperEvcElanPort(InstanceIdentifier<Evc> identifier, String elanPort) {
354 InstanceIdentifier<EvcElan> path = identifier.augmentation(EvcElan.class);
355 EvcElan evcElan = getOperEvcElan(identifier);
356 EvcElanBuilder evcElanBuilder = null;
357 List<ElanPorts> exPorts = Collections.emptyList();
358 if (evcElan != null) {
359 evcElanBuilder = new EvcElanBuilder(evcElan);
360 exPorts = evcElan.getElanPorts() != null ? evcElan.getElanPorts() : Collections.emptyList();
362 Log.error("Deleting non-operational Elan port {}", elanPort);
365 List<ElanPorts> newList = exPorts.stream().filter(p -> !p.getPortId().equals(elanPort))
366 .collect(Collectors.toList());
367 evcElanBuilder.setElanPorts(newList);
368 MdsalUtils.write(dataBroker, LogicalDatastoreType.OPERATIONAL, path, evcElanBuilder.build());
371 private void updateQos(List<Uni> uniToUpdate) {
372 uniToUpdate.forEach(u -> uniQosManager.setUniBandwidthLimits(u.getUniId()));