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;
49 public EvcListener(final DataBroker dataBroker, final UniPortManager uniPortManager) {
51 this.uniPortManager = uniPortManager;
55 public void registerListener() {
57 final DataTreeIdentifier<Evc> dataTreeIid = new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
58 MefServicesUtils.getEvcsInstanceIdentifier());
59 evcListenerRegistration = dataBroker.registerDataTreeChangeListener(dataTreeIid, this);
60 log.info("EvcDataTreeChangeListener created and registered");
61 } catch (final Exception e) {
62 log.error("Evc DataChange listener registration failed !", e);
63 throw new IllegalStateException("Evc registration Listener failed.", e);
68 public void close() throws Exception {
69 evcListenerRegistration.close();
73 public void add(DataTreeModification<Evc> newDataObject) {
74 if (newDataObject.getRootPath() != null && newDataObject.getRootNode() != null) {
75 log.info("evc {} created", newDataObject.getRootNode().getIdentifier());
76 addEvc(newDataObject);
81 public void remove(DataTreeModification<Evc> removedDataObject) {
82 if (removedDataObject.getRootPath() != null && removedDataObject.getRootNode() != null) {
83 log.info("evc {} deleted", removedDataObject.getRootNode().getIdentifier());
84 removeEvc(removedDataObject);
89 public void update(DataTreeModification<Evc> modifiedDataObject) {
90 if (modifiedDataObject.getRootPath() != null && modifiedDataObject.getRootNode() != null) {
91 log.info("evc {} updated", modifiedDataObject.getRootNode().getIdentifier());
92 updateEvc(modifiedDataObject);
96 private void addEvc(DataTreeModification<Evc> newDataObject) {
98 Evc data = newDataObject.getRootNode().getDataAfter();
99 String instanceName = data.getEvcId().getValue();
100 boolean isEtree = data.getEvcType() == EvcType.RootedMultipoint;
101 InstanceIdentifier<Evc> evcId = newDataObject.getRootPath().getRootIdentifier();
103 synchronized (instanceName.intern()) {
104 NetvirtUtils.createElanInstance(dataBroker, instanceName, isEtree);
107 if (data.getUnis() == null) {
108 log.info("No UNI's in service {}, exiting", instanceName);
111 for (Uni uni : data.getUnis().getUni()) {
112 createUniElanInterfaces(evcId, instanceName, uni, isEtree);
115 } catch (final Exception e) {
116 log.error("Add evc failed !", e);
120 private void removeEvc(DataTreeModification<Evc> removedDataObject) {
122 Evc data = removedDataObject.getRootNode().getDataBefore();
123 InstanceIdentifier<Evc> evcId = removedDataObject.getRootPath().getRootIdentifier();
124 List<Uni> uniToRemove = data.getUnis() != null && data.getUnis().getUni() != null
125 ? data.getUnis().getUni() : Collections.emptyList();
128 synchronized (data.getEvcId().getValue().intern()) {
129 EvcElan evcElan = getOperEvcElan(evcId);
130 if (evcElan == null) {
131 log.error("Evc {} has not been created as required. Nothing to remove", data.getEvcId().getValue());
134 String instanceName = evcElan.getElanId();
136 for (Uni uni : uniToRemove) {
137 removeUniElanInterfaces(evcId, instanceName, uni);
140 log.info("Removing elan instance: " + instanceName);
141 NetvirtUtils.deleteElanInstance(dataBroker, instanceName);
142 removeOperEvcElan(evcId);
144 } catch (final Exception e) {
145 log.error("Remove evc failed !", e);
149 private void updateEvc(DataTreeModification<Evc> modifiedDataObject) {
150 InstanceIdentifier<Evc> evcId = modifiedDataObject.getRootPath().getRootIdentifier();
153 Evc original = modifiedDataObject.getRootNode().getDataBefore();
154 Evc update = modifiedDataObject.getRootNode().getDataAfter();
156 List<Uni> originalUni = original.getUnis() != null && original.getUnis().getUni() != null
157 ? original.getUnis().getUni() : Collections.emptyList();
158 List<Uni> updateUni = update.getUnis() != null && update.getUnis().getUni() != null
159 ? update.getUnis().getUni() : Collections.emptyList();
161 synchronized (original.getEvcId().getValue().intern()) {
163 String instanceName = original.getEvcId().getValue();
164 boolean isEtree = update.getEvcType() == EvcType.RootedMultipoint;
165 log.info("Updating {} instance: {}", isEtree ? "etree" : "elan", instanceName);
167 // Changed Uni will be deleted / recreated
168 List<Uni> uniToRemove = new ArrayList<>(originalUni);
169 uniToRemove.removeAll(updateUni);
170 for (Uni uni : uniToRemove) {
171 removeUniElanInterfaces(evcId, instanceName, uni);
174 List<Uni> uniToCreate = new ArrayList<>(updateUni);
175 uniToCreate.removeAll(originalUni);
176 for (Uni uni : uniToCreate) {
177 createUniElanInterfaces(evcId, instanceName, uni, isEtree);
180 } catch (final Exception e) {
181 log.error("Update evc failed !", e);
185 private void createUniElanInterfaces(InstanceIdentifier<Evc> evcId, String instanceName, Uni uni, boolean isEtree) {
186 EvcUniRoleType role = uni.getRole();
187 EvcUniCeVlans evcUniCeVlans = uni.getEvcUniCeVlans();
189 List<EvcUniCeVlan> evcUniCeVlan = evcUniCeVlans != null && evcUniCeVlans.getEvcUniCeVlan() != null
190 && !evcUniCeVlans.getEvcUniCeVlan().isEmpty() ? evcUniCeVlans.getEvcUniCeVlan()
191 : Collections.emptyList();
193 for (EvcUniCeVlan ceVlan : evcUniCeVlan) {
194 Long vlan = safeCastVlan(ceVlan.getVid());
195 uniPortManager.addCeVlan(uni.getUniId().getValue(), vlan);
198 if (evcUniCeVlan.isEmpty()) {
199 String interfaceName = uniPortManager.getUniVlanInterface(uni.getUniId().getValue(), Long.valueOf(0));
200 if (isOperEvcElanPort(evcId, interfaceName)) {
201 log.info("elan interface for elan {} vlan {} interface {} exists already", instanceName, 0,
205 log.info("Creting elan interface for elan {} vlan {} interface {}", instanceName, 0, interfaceName);
206 NetvirtUtils.createElanInterface(dataBroker, instanceName, interfaceName, roleToInterfaceType(role),
208 setOperEvcElanPort(evcId, instanceName, interfaceName);
210 for (EvcUniCeVlan ceVlan : evcUniCeVlan) {
211 Long vlan = safeCastVlan(ceVlan.getVid());
212 String interfaceName = uniPortManager.getUniVlanInterface(uni.getUniId().getValue(), vlan);
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 setOperEvcElanPort(evcId, instanceName, interfaceName);
226 private void removeUniElanInterfaces(InstanceIdentifier<Evc> evcId, String instanceName, Uni uni) {
227 EvcUniCeVlans evcUniCeVlans = uni.getEvcUniCeVlans();
229 List<EvcUniCeVlan> evcUniCeVlan = evcUniCeVlans != null && evcUniCeVlans.getEvcUniCeVlan() != null
230 && !evcUniCeVlans.getEvcUniCeVlan().isEmpty() ? evcUniCeVlans.getEvcUniCeVlan()
231 : Collections.emptyList();
233 for (EvcUniCeVlan ceVlan : evcUniCeVlan) {
234 Long vlan = safeCastVlan(ceVlan.getVid());
235 uniPortManager.removeCeVlan(uni.getUniId().getValue(), vlan);
238 if (evcUniCeVlan.isEmpty()) {
239 String interfaceName = uniPortManager.getUniVlanInterface(uni.getUniId().getValue(), Long.valueOf(0));
240 if (!isOperEvcElanPort(evcId, interfaceName)) {
241 log.info("elan interface for elan {} vlan {} is not operational, nothing to remove", instanceName, 0,
245 removeElanInterface(evcId, interfaceName);
247 for (EvcUniCeVlan ceVlan : evcUniCeVlan) {
248 Long vlan = safeCastVlan(ceVlan.getVid());
249 String interfaceName = uniPortManager.getUniVlanInterface(uni.getUniId().getValue(), vlan);
250 if (!isOperEvcElanPort(evcId, interfaceName)) {
251 log.info("elan interface for elan {} vlan {} is not operational, nothing to remove", instanceName,
252 vlan, interfaceName);
255 removeElanInterface(evcId, interfaceName);
260 private void removeElanInterface(InstanceIdentifier<Evc> identifier, String interfaceName) {
261 log.info("Removing elan interface: " + interfaceName);
262 NetvirtUtils.deleteElanInterface(dataBroker, interfaceName);
264 EvcElan evcElan = getOperEvcElan(identifier);
265 if (evcElan == null) {
266 log.error("Removing non-operational Elan interface {}", interfaceName);
268 deleteOperEvcElanPort(identifier, interfaceName);
271 // Expected from API is Long
272 private Long safeCastVlan(Object vid) {
273 if (!(vid instanceof Long)) {
274 String errorMessage = String.format("vlan id %s cannot be cast to Long", vid);
275 log.error(errorMessage);
276 throw new UnsupportedOperationException(errorMessage);
281 private static EtreeInterfaceType roleToInterfaceType(EvcUniRoleType role) {
282 if (role == EvcUniRoleType.Root) {
283 return EtreeInterfaceType.Root;
285 return EtreeInterfaceType.Leaf;
289 private EvcElan getOperEvcElan(InstanceIdentifier<Evc> identifier) {
290 InstanceIdentifier<EvcElan> path = identifier.augmentation(EvcElan.class);
291 Optional<EvcElan> evcElan = MdsalUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL, path);
292 if (evcElan.isPresent()) {
293 return evcElan.get();
299 private void removeOperEvcElan(InstanceIdentifier<Evc> identifier) {
300 InstanceIdentifier<EvcElan> path = identifier.augmentation(EvcElan.class);
301 MdsalUtils.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, path);
304 private boolean isOperEvcElanPort(InstanceIdentifier<Evc> identifier, String elanPort) {
305 EvcElan evcElan = getOperEvcElan(identifier);
306 if (evcElan == null || evcElan.getElanPorts() == null) {
309 List<ElanPorts> exPorts = evcElan.getElanPorts();
310 return exPorts.stream().anyMatch(p -> p.getPortId().equals(elanPort));
313 private void setOperEvcElanPort(InstanceIdentifier<Evc> identifier, String elanName, String elanPort) {
314 InstanceIdentifier<EvcElan> path = identifier.augmentation(EvcElan.class);
315 EvcElan evcElan = getOperEvcElan(identifier);
316 EvcElanBuilder evcElanBuilder = evcElan != null ? new EvcElanBuilder(evcElan) : new EvcElanBuilder();
317 List<ElanPorts> exPorts = evcElan != null && evcElan.getElanPorts() != null ? evcElan.getElanPorts() : new ArrayList<>();
319 ElanPortsBuilder portB = new ElanPortsBuilder();
320 portB.setPortId(elanPort);
321 exPorts.add(portB.build());
322 evcElanBuilder.setElanId(elanName);
323 evcElanBuilder.setElanPorts(exPorts);
324 MdsalUtils.write(dataBroker, LogicalDatastoreType.OPERATIONAL, path, evcElanBuilder.build());
327 private void deleteOperEvcElanPort(InstanceIdentifier<Evc> identifier, String elanPort) {
328 InstanceIdentifier<EvcElan> path = identifier.augmentation(EvcElan.class);
329 EvcElan evcElan = getOperEvcElan(identifier);
330 EvcElanBuilder evcElanBuilder = null;
331 List<ElanPorts> exPorts = Collections.emptyList();
332 if (evcElan != null) {
333 evcElanBuilder = new EvcElanBuilder(evcElan);
334 exPorts = evcElan.getElanPorts() != null ? evcElan.getElanPorts() : Collections.emptyList();
336 Log.error("Deleting non-operational Elan port {}", elanPort);
339 List<ElanPorts> newList = exPorts.stream().filter(p -> !p.getPortId().equals(elanPort))
340 .collect(Collectors.toList());
341 evcElanBuilder.setElanPorts(newList);
342 MdsalUtils.write(dataBroker, LogicalDatastoreType.OPERATIONAL, path, evcElanBuilder.build());