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;
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);
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 EvcElan evcElan = getOperEvcElan(evcId);
133 if (evcElan == null) {
134 log.error("Evc {} has not been created as required. Nothing to remove", data.getEvcId().getValue());
137 String instanceName = evcElan.getElanId();
139 for (Uni uni : uniToRemove) {
140 removeUniElanInterfaces(evcId, instanceName, uni);
142 updateQos(uniToRemove);
144 log.info("Removing elan instance: " + instanceName);
145 NetvirtUtils.deleteElanInstance(dataBroker, instanceName);
146 removeOperEvcElan(evcId);
148 } catch (final Exception e) {
149 log.error("Remove evc failed !", e);
153 private void updateEvc(DataTreeModification<Evc> modifiedDataObject) {
154 InstanceIdentifier<Evc> evcId = modifiedDataObject.getRootPath().getRootIdentifier();
157 Evc original = modifiedDataObject.getRootNode().getDataBefore();
158 Evc update = modifiedDataObject.getRootNode().getDataAfter();
160 List<Uni> originalUni = original.getUnis() != null && original.getUnis().getUni() != null
161 ? original.getUnis().getUni() : Collections.emptyList();
162 List<Uni> updateUni = update.getUnis() != null && update.getUnis().getUni() != null
163 ? update.getUnis().getUni() : Collections.emptyList();
165 synchronized (original.getEvcId().getValue().intern()) {
167 String instanceName = original.getEvcId().getValue();
168 boolean isEtree = update.getEvcType() == EvcType.RootedMultipoint;
169 log.info("Updating {} instance: {}", isEtree ? "etree" : "elan", instanceName);
171 // Changed Uni will be deleted / recreated
172 List<Uni> uniToRemove = new ArrayList<>(originalUni);
173 uniToRemove.removeAll(updateUni);
174 for (Uni uni : uniToRemove) {
175 removeUniElanInterfaces(evcId, instanceName, uni);
177 updateQos(uniToRemove);
179 List<Uni> uniToCreate = new ArrayList<>(updateUni);
180 uniToCreate.removeAll(originalUni);
181 for (Uni uni : uniToCreate) {
182 createUniElanInterfaces(evcId, instanceName, uni, isEtree);
184 updateQos(uniToCreate);
186 } catch (final Exception e) {
187 log.error("Update evc failed !", e);
191 private void createUniElanInterfaces(InstanceIdentifier<Evc> evcId, String instanceName, Uni uni, boolean isEtree) {
192 EvcUniRoleType role = uni.getRole();
193 EvcUniCeVlans evcUniCeVlans = uni.getEvcUniCeVlans();
195 List<EvcUniCeVlan> evcUniCeVlan = evcUniCeVlans != null && evcUniCeVlans.getEvcUniCeVlan() != null
196 && !evcUniCeVlans.getEvcUniCeVlan().isEmpty() ? evcUniCeVlans.getEvcUniCeVlan()
197 : Collections.emptyList();
199 for (EvcUniCeVlan ceVlan : evcUniCeVlan) {
200 Long vlan = safeCastVlan(ceVlan.getVid());
201 uniPortManager.addCeVlan(uni.getUniId().getValue(), vlan);
204 if (evcUniCeVlan.isEmpty()) {
205 String interfaceName = uniPortManager.getUniVlanInterface(uni.getUniId().getValue(), Long.valueOf(0));
206 if (isOperEvcElanPort(evcId, interfaceName)) {
207 log.info("elan interface for elan {} vlan {} interface {} exists already", instanceName, 0,
211 log.info("Creting elan interface for elan {} vlan {} interface {}", instanceName, 0, interfaceName);
212 NetvirtUtils.createElanInterface(dataBroker, instanceName, interfaceName, roleToInterfaceType(role),
214 uniQosManager.mapUniPortBandwidthLimits(uni.getUniId().getValue(), interfaceName,
215 uni.getIngressBwProfile());
216 setOperEvcElanPort(evcId, instanceName, interfaceName);
218 for (EvcUniCeVlan ceVlan : evcUniCeVlan) {
219 Long vlan = safeCastVlan(ceVlan.getVid());
220 String interfaceName = uniPortManager.getUniVlanInterface(uni.getUniId().getValue(), vlan);
221 if (isOperEvcElanPort(evcId, interfaceName)) {
222 log.info("elan interface for elan {} vlan {} interface {} exists already", instanceName, 0,
226 log.info("Creting elan interface for elan {} vlan {} interface {}", instanceName, 0, interfaceName);
227 NetvirtUtils.createElanInterface(dataBroker, instanceName, interfaceName, roleToInterfaceType(role),
229 uniQosManager.mapUniPortBandwidthLimits(uni.getUniId().getValue(), interfaceName,
230 uni.getIngressBwProfile());
231 setOperEvcElanPort(evcId, instanceName, interfaceName);
236 private void removeUniElanInterfaces(InstanceIdentifier<Evc> evcId, String instanceName, Uni uni) {
237 EvcUniCeVlans evcUniCeVlans = uni.getEvcUniCeVlans();
239 List<EvcUniCeVlan> evcUniCeVlan = evcUniCeVlans != null && evcUniCeVlans.getEvcUniCeVlan() != null
240 && !evcUniCeVlans.getEvcUniCeVlan().isEmpty() ? evcUniCeVlans.getEvcUniCeVlan()
241 : Collections.emptyList();
243 for (EvcUniCeVlan ceVlan : evcUniCeVlan) {
244 Long vlan = safeCastVlan(ceVlan.getVid());
245 uniPortManager.removeCeVlan(uni.getUniId().getValue(), vlan);
248 if (evcUniCeVlan.isEmpty()) {
249 String interfaceName = uniPortManager.getUniVlanInterface(uni.getUniId().getValue(), Long.valueOf(0));
250 if (!isOperEvcElanPort(evcId, interfaceName)) {
251 log.info("elan interface for elan {} vlan {} is not operational, nothing to remove", instanceName, 0,
255 removeElanInterface(evcId, uni.getUniId().getValue(), interfaceName);
257 for (EvcUniCeVlan ceVlan : evcUniCeVlan) {
258 Long vlan = safeCastVlan(ceVlan.getVid());
259 String interfaceName = uniPortManager.getUniVlanInterface(uni.getUniId().getValue(), vlan);
260 if (!isOperEvcElanPort(evcId, interfaceName)) {
261 log.info("elan interface for elan {} vlan {} is not operational, nothing to remove", instanceName,
262 vlan, interfaceName);
265 removeElanInterface(evcId, uni.getUniId().getValue(), interfaceName);
270 private void removeElanInterface(InstanceIdentifier<Evc> identifier, String uniId, String interfaceName) {
271 log.info("Removing elan interface: " + interfaceName);
272 uniQosManager.unMapUniPortBandwidthLimits(uniId, interfaceName);
273 NetvirtUtils.deleteElanInterface(dataBroker, interfaceName);
275 EvcElan evcElan = getOperEvcElan(identifier);
276 if (evcElan == null) {
277 log.error("Removing non-operational Elan interface {}", interfaceName);
280 deleteOperEvcElanPort(identifier, interfaceName);
283 // Expected from API is Long
284 private Long safeCastVlan(Object vid) {
285 if (!(vid instanceof Long)) {
286 String errorMessage = String.format("vlan id %s cannot be cast to Long", vid);
287 log.error(errorMessage);
288 throw new UnsupportedOperationException(errorMessage);
293 private static EtreeInterfaceType roleToInterfaceType(EvcUniRoleType role) {
294 if (role == EvcUniRoleType.Root) {
295 return EtreeInterfaceType.Root;
297 return EtreeInterfaceType.Leaf;
301 private EvcElan getOperEvcElan(InstanceIdentifier<Evc> identifier) {
302 InstanceIdentifier<EvcElan> path = identifier.augmentation(EvcElan.class);
303 Optional<EvcElan> evcElan = MdsalUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL, path);
304 if (evcElan.isPresent()) {
305 return evcElan.get();
311 private void removeOperEvcElan(InstanceIdentifier<Evc> identifier) {
312 InstanceIdentifier<EvcElan> path = identifier.augmentation(EvcElan.class);
313 MdsalUtils.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, path);
316 private boolean isOperEvcElanPort(InstanceIdentifier<Evc> identifier, String elanPort) {
317 EvcElan evcElan = getOperEvcElan(identifier);
318 if (evcElan == null || evcElan.getElanPorts() == null) {
321 List<ElanPorts> exPorts = evcElan.getElanPorts();
322 return exPorts.stream().anyMatch(p -> p.getPortId().equals(elanPort));
325 private void setOperEvcElanPort(InstanceIdentifier<Evc> identifier, String elanName, String elanPort) {
326 InstanceIdentifier<EvcElan> path = identifier.augmentation(EvcElan.class);
327 EvcElan evcElan = getOperEvcElan(identifier);
328 EvcElanBuilder evcElanBuilder = evcElan != null ? new EvcElanBuilder(evcElan) : new EvcElanBuilder();
329 List<ElanPorts> exPorts = evcElan != null && evcElan.getElanPorts() != null ? evcElan.getElanPorts()
332 ElanPortsBuilder portB = new ElanPortsBuilder();
333 portB.setPortId(elanPort);
334 exPorts.add(portB.build());
335 evcElanBuilder.setElanId(elanName);
336 evcElanBuilder.setElanPorts(exPorts);
337 MdsalUtils.write(dataBroker, LogicalDatastoreType.OPERATIONAL, path, evcElanBuilder.build());
340 private void deleteOperEvcElanPort(InstanceIdentifier<Evc> identifier, String elanPort) {
341 InstanceIdentifier<EvcElan> path = identifier.augmentation(EvcElan.class);
342 EvcElan evcElan = getOperEvcElan(identifier);
343 EvcElanBuilder evcElanBuilder = null;
344 List<ElanPorts> exPorts = Collections.emptyList();
345 if (evcElan != null) {
346 evcElanBuilder = new EvcElanBuilder(evcElan);
347 exPorts = evcElan.getElanPorts() != null ? evcElan.getElanPorts() : Collections.emptyList();
349 Log.error("Deleting non-operational Elan port {}", elanPort);
352 List<ElanPorts> newList = exPorts.stream().filter(p -> !p.getPortId().equals(elanPort))
353 .collect(Collectors.toList());
354 evcElanBuilder.setElanPorts(newList);
355 MdsalUtils.write(dataBroker, LogicalDatastoreType.OPERATIONAL, path, evcElanBuilder.build());
358 private void updateQos(List<Uni> uniToUpdate) {
359 uniToUpdate.forEach(u -> uniQosManager.setUniBandwidthLimits(u.getUniId()));