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.UniKey;
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.EvcUniCeVlans;
26 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;
27 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.services.rev150526.EvcElan;
28 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.services.rev150526.EvcElanBuilder;
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.ElanPorts;
30 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;
32 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.types.rev150526.EvcType;
33 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.types.rev150526.EvcUniRoleType;
34 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.types.rev150526.Identifier45;
35 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.types.rev150526.RetailSvcIdType;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface.EtreeInterfaceType;
37 import org.opendaylight.yangtools.concepts.ListenerRegistration;
38 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
42 import com.google.common.base.Optional;
44 import jline.internal.Log;
46 public class EvcListener extends UnimgrDataTreeChangeListener<Evc> implements IUniAwareService {
48 private static final Logger log = LoggerFactory.getLogger(EvcListener.class);
49 private ListenerRegistration<EvcListener> evcListenerRegistration;
50 private final IUniPortManager uniPortManager;
51 private final UniQosManager uniQosManager;
52 @SuppressWarnings("unused")
53 private final UniAwareListener uniAwareListener;
55 public EvcListener(final DataBroker dataBroker, final UniPortManager uniPortManager,
56 final UniQosManager uniQosManager) {
58 this.uniPortManager = uniPortManager;
59 this.uniQosManager = uniQosManager;
60 this.uniAwareListener = new UniAwareListener(dataBroker, this);
64 public void registerListener() {
66 final DataTreeIdentifier<Evc> dataTreeIid = new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
67 MefServicesUtils.getEvcsInstanceIdentifier());
68 evcListenerRegistration = dataBroker.registerDataTreeChangeListener(dataTreeIid, this);
69 log.info("EvcDataTreeChangeListener created and registered");
70 } catch (final Exception e) {
71 log.error("Evc DataChange listener registration failed !", e);
72 throw new IllegalStateException("Evc registration Listener failed.", e);
77 public void close() throws Exception {
78 evcListenerRegistration.close();
82 public void add(DataTreeModification<Evc> newDataObject) {
83 if (newDataObject.getRootPath() != null && newDataObject.getRootNode() != null) {
84 log.info("evc {} created", newDataObject.getRootNode().getIdentifier());
85 addEvc(newDataObject);
90 public void remove(DataTreeModification<Evc> removedDataObject) {
91 if (removedDataObject.getRootPath() != null && removedDataObject.getRootNode() != null) {
92 log.info("evc {} deleted", removedDataObject.getRootNode().getIdentifier());
93 removeEvc(removedDataObject);
98 public void update(DataTreeModification<Evc> modifiedDataObject) {
99 if (modifiedDataObject.getRootPath() != null && modifiedDataObject.getRootNode() != null) {
100 log.info("evc {} updated", modifiedDataObject.getRootNode().getIdentifier());
101 updateEvc(modifiedDataObject);
106 public void connectUni(String uniId) {
107 List<RetailSvcIdType> allEvcs = MefServicesUtils.getAllEvcsServiceIds(dataBroker);
108 allEvcs = (allEvcs != null) ? allEvcs : Collections.emptyList();
110 for (RetailSvcIdType evcSerId : allEvcs) {
111 InstanceIdentifier<Evc> evcId = MefServicesUtils.getEvcInstanceIdentifier(evcSerId);
112 Evc evc = MefServicesUtils.getEvc(dataBroker, evcId);
114 Log.error("Inconsistent data for svcId {}", evcSerId);
118 String instanceName = evc.getEvcId().getValue();
119 boolean isEtree = evc.getEvcType() == EvcType.RootedMultipoint;
121 List<Uni> toConnect = new ArrayList<>();
122 List<Uni> unis = (evc.getUnis() != null) ? evc.getUnis().getUni() : null;
123 unis = (unis != null) ? unis : Collections.emptyList();
124 for (Uni uni : unis) {
125 if (uni.getUniId().getValue().equals(uniId)) {
126 Log.info("Connecting Uni {} to svc id {}", uniId, evcSerId);
132 EvcElan evcElan = getOperEvcElan(evcId);
133 if (evcElan == null) {
134 NetvirtUtils.createElanInstance(dataBroker, instanceName, isEtree, evc.getSegmentationId());
135 evcElan = getOperEvcElan(evcId);
136 if (evcElan == null) {
137 log.error("Evc {} has not been created as required. Nothing to reconnect", evcId);
142 for (Uni uni : toConnect) {
143 createUniElanInterfaces(evcId, instanceName, uni, isEtree);
145 updateQos(toConnect);
150 public void disconnectUni(String uniId) {
151 List<RetailSvcIdType> allEvcs = MefServicesUtils.getAllEvcsServiceIds(dataBroker);
152 allEvcs = (allEvcs != null) ? allEvcs : Collections.emptyList();
154 for (RetailSvcIdType evcSerId : allEvcs) {
155 InstanceIdentifier<Evc> evcId = MefServicesUtils.getEvcInstanceIdentifier(evcSerId);
156 Evc evc = MefServicesUtils.getEvc(dataBroker, evcId);
158 Log.error("Inconsistent data for svcId {}", evcSerId);
162 String instanceName = evc.getEvcId().getValue();
163 List<Uni> toDisconnect = new ArrayList<>();
164 List<Uni> unis = (evc.getUnis() != null) ? evc.getUnis().getUni() : null;
165 unis = (unis != null) ? unis : Collections.emptyList();
166 for (Uni uni : unis) {
167 if (uni.getUniId().getValue().equals(uniId)) {
168 Log.info("Disconnecting Uni {} from svc id {}", uniId, evcSerId);
169 toDisconnect.add(uni);
174 EvcElan evcElan = getOperEvcElan(evcId);
175 if (evcElan == null) {
176 log.error("Evc {} has not been created as required. Nothing to disconnect", evcId);
180 updateQos(toDisconnect);
181 for (Uni uni : toDisconnect) {
182 removeUniElanInterfaces(evcId, instanceName, uni);
188 private void addEvc(DataTreeModification<Evc> newDataObject) {
190 Evc data = newDataObject.getRootNode().getDataAfter();
191 String instanceName = data.getEvcId().getValue();
192 boolean isEtree = data.getEvcType() == EvcType.RootedMultipoint;
193 InstanceIdentifier<Evc> evcId = newDataObject.getRootPath().getRootIdentifier();
195 synchronized (instanceName.intern()) {
196 NetvirtUtils.createElanInstance(dataBroker, instanceName, isEtree, data.getSegmentationId(),
197 data.getMacTimeout());
200 if (data.getUnis() == null) {
201 log.info("No UNI's in service {}, exiting", instanceName);
204 for (Uni uni : data.getUnis().getUni()) {
205 createUniElanInterfaces(evcId, instanceName, uni, isEtree);
207 updateQos(data.getUnis().getUni());
209 } catch (final Exception e) {
210 log.error("Add evc failed !", e);
214 private void removeEvc(DataTreeModification<Evc> removedDataObject) {
216 Evc data = removedDataObject.getRootNode().getDataBefore();
217 InstanceIdentifier<Evc> evcId = removedDataObject.getRootPath().getRootIdentifier();
218 List<Uni> uniToRemove = data.getUnis() != null && data.getUnis().getUni() != null ? data.getUnis().getUni()
219 : Collections.emptyList();
221 synchronized (data.getEvcId().getValue().intern()) {
222 updateQos(uniToRemove);
223 EvcElan evcElan = getOperEvcElan(evcId);
224 if (evcElan == null) {
225 log.error("Evc {} has not been created as required. Nothing to remove", data.getEvcId().getValue());
229 String instanceName = evcElan.getElanId();
231 for (Uni uni : uniToRemove) {
232 removeUniElanInterfaces(evcId, instanceName, uni);
235 log.info("Removing elan instance: " + instanceName);
236 NetvirtUtils.deleteElanInstance(dataBroker, instanceName);
237 removeOperEvcElan(evcId);
239 } catch (final Exception e) {
240 log.error("Remove evc failed !", e);
244 private void updateEvc(DataTreeModification<Evc> modifiedDataObject) {
245 InstanceIdentifier<Evc> evcId = modifiedDataObject.getRootPath().getRootIdentifier();
248 Evc original = modifiedDataObject.getRootNode().getDataBefore();
249 Evc update = modifiedDataObject.getRootNode().getDataAfter();
251 List<Uni> originalUni = original.getUnis() != null && original.getUnis().getUni() != null
252 ? original.getUnis().getUni() : Collections.emptyList();
253 List<UniKey> originalUniIds = originalUni.stream().map(u -> u.getKey())
254 .collect(Collectors.toList());
255 List<Uni> updateUni = update.getUnis() != null && update.getUnis().getUni() != null
256 ? update.getUnis().getUni() : Collections.emptyList();
257 List<UniKey> updateUniIds = updateUni.stream().map(u -> u.getKey()).collect(Collectors.toList());
259 synchronized (original.getEvcId().getValue().intern()) {
261 String instanceName = original.getEvcId().getValue();
262 boolean isEtree = update.getEvcType() == EvcType.RootedMultipoint;
263 log.info("Updating {} instance: {}", isEtree ? "etree" : "elan", instanceName);
265 // Changed Uni will be deleted / recreated
266 List<Uni> uniToRemove = new ArrayList<>(originalUni);
267 uniToRemove.removeIf(u -> updateUniIds.contains(u.getKey()));
268 for (Uni uni : uniToRemove) {
269 removeUniElanInterfaces(evcId, instanceName, uni);
271 updateQos(uniToRemove);
273 List<Uni> uniToCreate = new ArrayList<>(updateUni);
274 uniToCreate.removeIf(u -> originalUniIds.contains(u.getKey()));
275 uniToCreate.removeAll(originalUni);
276 for (Uni uni : uniToCreate) {
277 createUniElanInterfaces(evcId, instanceName, uni, isEtree);
279 updateQos(uniToCreate);
281 List<Uni> uniToUpdate = new ArrayList<>(updateUni);
282 uniToUpdate.removeIf(u -> !originalUniIds.contains(u.getKey()));
283 updateUnis(uniToUpdate);
285 } catch (final Exception e) {
286 log.error("Update evc failed !", e);
290 private void createUniElanInterfaces(InstanceIdentifier<Evc> evcId, String instanceName, Uni uni, boolean isEtree) {
291 EvcUniRoleType role = uni.getRole();
292 EvcUniCeVlans evcUniCeVlans = uni.getEvcUniCeVlans();
294 List<EvcUniCeVlan> evcUniCeVlan = evcUniCeVlans != null && evcUniCeVlans.getEvcUniCeVlan() != null
295 && !evcUniCeVlans.getEvcUniCeVlan().isEmpty() ? evcUniCeVlans.getEvcUniCeVlan()
296 : Collections.emptyList();
298 for (EvcUniCeVlan ceVlan : evcUniCeVlan) {
299 Long vlan = safeCastVlan(ceVlan.getVid());
300 uniPortManager.addCeVlan(uni.getUniId().getValue(), vlan);
303 if (evcUniCeVlan.isEmpty()) {
304 String interfaceName = uniPortManager.getUniVlanInterface(uni.getUniId().getValue(), Long.valueOf(0));
305 if (interfaceName == null) {
306 String errorMessage = String.format("Uni %s Interface for vlan %d is not operational ", uni.getUniId(),
308 Log.error(errorMessage);
309 throw new UnsupportedOperationException(errorMessage);
311 if (isOperEvcElanPort(evcId, interfaceName)) {
312 log.info("elan interface for elan {} vlan {} interface {} exists already", instanceName, 0,
316 log.info("Creting elan interface for elan {} vlan {} interface {}", instanceName, 0, interfaceName);
317 NetvirtUtils.createElanInterface(dataBroker, instanceName, interfaceName, roleToInterfaceType(role),
319 uniQosManager.mapUniPortBandwidthLimits(uni.getUniId().getValue(), interfaceName,
320 uni.getIngressBwProfile());
321 setOperEvcElanPort(evcId, instanceName, interfaceName);
323 for (EvcUniCeVlan ceVlan : evcUniCeVlan) {
324 Long vlan = safeCastVlan(ceVlan.getVid());
325 String interfaceName = uniPortManager.getUniVlanInterface(uni.getUniId().getValue(), vlan);
326 if (interfaceName == null) {
327 String errorMessage = String.format("Uni %s Interface for vlan %d is not operational ",
329 Log.error(errorMessage);
330 throw new UnsupportedOperationException(errorMessage);
332 if (isOperEvcElanPort(evcId, interfaceName)) {
333 log.info("elan interface for elan {} vlan {} interface {} exists already", instanceName, 0,
337 log.info("Creting elan interface for elan {} vlan {} interface {}", instanceName, 0, interfaceName);
338 NetvirtUtils.createElanInterface(dataBroker, instanceName, interfaceName, roleToInterfaceType(role),
340 uniQosManager.mapUniPortBandwidthLimits(uni.getUniId().getValue(), interfaceName,
341 uni.getIngressBwProfile());
342 setOperEvcElanPort(evcId, instanceName, interfaceName);
347 private void removeUniElanInterfaces(InstanceIdentifier<Evc> evcId, String instanceName, Uni uni) {
348 EvcUniCeVlans evcUniCeVlans = uni.getEvcUniCeVlans();
350 List<EvcUniCeVlan> evcUniCeVlan = evcUniCeVlans != null && evcUniCeVlans.getEvcUniCeVlan() != null
351 && !evcUniCeVlans.getEvcUniCeVlan().isEmpty() ? evcUniCeVlans.getEvcUniCeVlan()
352 : Collections.emptyList();
354 if (evcUniCeVlan.isEmpty()) {
355 String interfaceName = uniPortManager.getUniVlanInterface(uni.getUniId().getValue(), Long.valueOf(0));
356 if (interfaceName == null || !isOperEvcElanPort(evcId, interfaceName)) {
357 log.info("elan interface for elan {} vlan {} is not operational, nothing to remove", instanceName, 0,
359 interfaceName = uniPortManager.getUniVlanInterfaceName(uni.getUniId().getValue(), null);
361 removeElanInterface(evcId, uni.getUniId().getValue(), interfaceName);
363 for (EvcUniCeVlan ceVlan : evcUniCeVlan) {
364 Long vlan = safeCastVlan(ceVlan.getVid());
365 String interfaceName = uniPortManager.getUniVlanInterface(uni.getUniId().getValue(), vlan);
366 if (interfaceName == null || !isOperEvcElanPort(evcId, interfaceName)) {
367 log.info("elan interface for elan {} vlan {} is not operational, nothing to remove", instanceName,
368 vlan, interfaceName);
369 interfaceName = uniPortManager.getUniVlanInterfaceName(uni.getUniId().getValue(), vlan);
371 removeElanInterface(evcId, uni.getUniId().getValue(), interfaceName);
375 for (EvcUniCeVlan ceVlan : evcUniCeVlan) {
376 Long vlan = safeCastVlan(ceVlan.getVid());
377 uniPortManager.removeCeVlan(uni.getUniId().getValue(), vlan);
381 private void removeElanInterface(InstanceIdentifier<Evc> identifier, String uniId, String interfaceName) {
382 log.info("Removing elan interface: " + interfaceName);
383 uniQosManager.unMapUniPortBandwidthLimits(uniId, interfaceName);
384 NetvirtUtils.deleteElanInterface(dataBroker, interfaceName);
386 EvcElan evcElan = getOperEvcElan(identifier);
387 if (evcElan == null) {
388 log.error("Removing non-operational Elan interface {}", interfaceName);
391 deleteOperEvcElanPort(identifier, interfaceName);
394 // Expected from API is Long
395 private Long safeCastVlan(Object vid) {
396 if (!(vid instanceof Long)) {
397 String errorMessage = String.format("vlan id %s cannot be cast to Long", vid);
398 log.error(errorMessage);
399 throw new UnsupportedOperationException(errorMessage);
404 private static EtreeInterfaceType roleToInterfaceType(EvcUniRoleType role) {
405 if (role == EvcUniRoleType.Root) {
406 return EtreeInterfaceType.Root;
408 return EtreeInterfaceType.Leaf;
412 private EvcElan getOperEvcElan(InstanceIdentifier<Evc> identifier) {
413 InstanceIdentifier<EvcElan> path = identifier.augmentation(EvcElan.class);
414 Optional<EvcElan> evcElan = MdsalUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL, path);
415 if (evcElan.isPresent()) {
416 return evcElan.get();
422 private void removeOperEvcElan(InstanceIdentifier<Evc> identifier) {
423 final InstanceIdentifier<MefService> serviceId = identifier.firstIdentifierOf(MefService.class);
424 MdsalUtils.delete(dataBroker, LogicalDatastoreType.OPERATIONAL, serviceId);
427 private boolean isOperEvcElanPort(InstanceIdentifier<Evc> identifier, String elanPort) {
428 EvcElan evcElan = getOperEvcElan(identifier);
429 if (evcElan == null || evcElan.getElanPorts() == null) {
432 List<ElanPorts> exPorts = evcElan.getElanPorts();
433 return exPorts.stream().anyMatch(p -> p.getPortId().equals(elanPort));
436 private void setOperEvcElanPort(InstanceIdentifier<Evc> identifier, String elanName, String elanPort) {
437 InstanceIdentifier<EvcElan> path = identifier.augmentation(EvcElan.class);
438 EvcElan evcElan = getOperEvcElan(identifier);
439 EvcElanBuilder evcElanBuilder = evcElan != null ? new EvcElanBuilder(evcElan) : new EvcElanBuilder();
440 List<ElanPorts> exPorts = evcElan != null && evcElan.getElanPorts() != null ? evcElan.getElanPorts()
443 ElanPortsBuilder portB = new ElanPortsBuilder();
444 portB.setPortId(elanPort);
445 exPorts.add(portB.build());
446 evcElanBuilder.setElanId(elanName);
447 evcElanBuilder.setElanPorts(exPorts);
448 MdsalUtils.write(dataBroker, LogicalDatastoreType.OPERATIONAL, path, evcElanBuilder.build());
451 private void deleteOperEvcElanPort(InstanceIdentifier<Evc> identifier, String elanPort) {
452 InstanceIdentifier<EvcElan> path = identifier.augmentation(EvcElan.class);
453 EvcElan evcElan = getOperEvcElan(identifier);
454 EvcElanBuilder evcElanBuilder = null;
455 List<ElanPorts> exPorts = Collections.emptyList();
456 if (evcElan != null) {
457 evcElanBuilder = new EvcElanBuilder(evcElan);
458 exPorts = evcElan.getElanPorts() != null ? evcElan.getElanPorts() : Collections.emptyList();
460 Log.error("Deleting non-operational Elan port {}", elanPort);
463 List<ElanPorts> newList = exPorts.stream().filter(p -> !p.getPortId().equals(elanPort))
464 .collect(Collectors.toList());
465 evcElanBuilder.setElanPorts(newList);
466 MdsalUtils.write(dataBroker, LogicalDatastoreType.OPERATIONAL, path, evcElanBuilder.build());
469 private void updateQos(List<Uni> uniToUpdate) {
470 uniToUpdate.forEach(u -> uniQosManager.setUniBandwidthLimits(u.getUniId()));
473 private void updateUnis(List<Uni> uniToUpdate) {
474 uniToUpdate.forEach(u -> uniQosManager.updateUni(u.getUniId(), u.getIngressBwProfile()));
475 updateQos(uniToUpdate);