refactoring to support delete\update of servics.
[unimgr.git] / netvirt / src / main / java / org / opendaylight / unimgr / mef / netvirt / UniPortManager.java
1 /*
2  * Copyright (c) 2016 Hewlett Packard Enterprise, Co. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.unimgr.mef.netvirt;
10
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.List;
14 import java.util.stream.Collectors;
15
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.binding.api.WriteTransaction;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.unimgr.api.UnimgrDataTreeChangeListener;
22 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.PortVlanMapping;
23 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.PortVlanMappingBuilder;
24 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.Uni;
25 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.UniBuilder;
26 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.uni.CeVlansBuilder;
27 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.uni.VlanToPort;
28 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.uni.VlanToPortBuilder;
29 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.uni.ce.vlans.CeVlan;
30 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.uni.ce.vlans.CeVlanBuilder;
31 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.uni.physical.layers.links.Link;
32 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.types.rev150526.VlanIdOrNoneType;
33 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.types.rev150526.VlanIdType;
34 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
35 import org.opendaylight.yangtools.concepts.ListenerRegistration;
36 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
39 import com.google.common.base.Optional;
40
41 public class UniPortManager extends UnimgrDataTreeChangeListener<Uni> implements IUniPortManager {
42
43     private static final Logger log = LoggerFactory.getLogger(UniPortManager.class);
44     private ListenerRegistration<UniPortManager> uniListenerRegistration;
45     private static int maxWaitRetries = 3;
46
47     public UniPortManager(final DataBroker dataBroker) {
48         super(dataBroker);
49
50         registerListener();
51     }
52
53     public void registerListener() {
54         try {
55             final DataTreeIdentifier<Uni> dataTreeIid = new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
56                     getInstanceIdentifier());
57             uniListenerRegistration = dataBroker.registerDataTreeChangeListener(dataTreeIid, this);
58             log.info("UniPortListener created and registered");
59         } catch (final Exception e) {
60             log.error("UniPortListener registration failed !", e);
61             throw new IllegalStateException("UniPortListener registration failed.", e);
62         }
63     }
64
65     private InstanceIdentifier<Uni> getInstanceIdentifier() {
66         return MefInterfaceUtils.getUniListInstanceIdentifier();
67     }
68
69     @Override
70     public void close() throws Exception {
71         uniListenerRegistration.close();
72     }
73
74     @Override
75     public void add(DataTreeModification<Uni> newDataObject) {
76         if (newDataObject.getRootPath() != null && newDataObject.getRootNode() != null) {
77             log.info("uni node {} created", newDataObject.getRootNode().getIdentifier());
78         }
79         Uni confUni = newDataObject.getRootNode().getDataAfter();
80         String uniId = confUni.getUniId().getValue();
81
82         synchronized (uniId.intern()) {
83             if (!checkOperUni(uniId)) {
84                 return;
85             }
86             addCheckUniPorts(confUni);
87         }
88     }
89
90     @Override
91     public void remove(DataTreeModification<Uni> removedDataObject) {
92         if (removedDataObject.getRootPath() != null && removedDataObject.getRootNode() != null) {
93             log.info("uni node {} deleted", removedDataObject.getRootNode().getIdentifier());
94         }
95         Uni confUni = removedDataObject.getRootNode().getDataBefore();
96         String uniId = confUni.getUniId().getValue();
97         synchronized (uniId.intern()) {
98             if (!checkOperUni(uniId)) {
99                 return;
100             }
101             removeUniPorts(confUni);
102         }
103     }
104
105     @Override
106     public void update(DataTreeModification<Uni> modifiedDataObject) {
107         if (modifiedDataObject.getRootPath() != null && modifiedDataObject.getRootNode() != null) {
108             log.info("node connector {} updated", modifiedDataObject.getRootNode().getIdentifier());
109         }
110         Uni confUni = modifiedDataObject.getRootNode().getDataAfter();
111         String uniId = confUni.getUniId().getValue();
112         synchronized (uniId.intern()) {
113             if (!checkOperUni(uniId)) {
114                 return;
115             }
116             removeCheckUniPorts(confUni);
117             addCheckUniPorts(confUni);
118         }
119     }
120
121     @Override
122     public void updateOperUni(String uniId) {
123         Uni confUni = MefInterfaceUtils.getUni(dataBroker, uniId, LogicalDatastoreType.CONFIGURATION);
124         if (confUni == null) {
125             log.debug("No UNI {} exists, nothing to update");
126             return;
127         }
128         synchronized (uniId.intern()) {
129             if (!checkOperUni(uniId)) {
130                 return;
131             }
132             log.info("UNI  {} ports updated", uniId);
133
134             removeCheckUniPorts(confUni);
135             addCheckUniPorts(confUni);
136         }
137     }
138
139     @Override
140     public void removeUniPorts(String uniId) {
141         Uni confUni = MefInterfaceUtils.getUni(dataBroker, uniId, LogicalDatastoreType.CONFIGURATION);
142         if (confUni == null) {
143             log.debug("No UNI {} exists, nothing to update");
144             return;
145         }
146         synchronized (uniId.intern()) {
147             if (!checkOperUni(uniId)) {
148                 return;
149             }
150             removeUniPorts(confUni);
151         }
152     }
153
154     private boolean checkOperUni(String uniId) {
155         Uni operUni = MefInterfaceUtils.getUni(dataBroker, uniId, LogicalDatastoreType.OPERATIONAL);
156         if (operUni == null) {
157             log.info("Uni {} is not operational", uniId);
158             return false;
159         }
160         return true;
161     }
162
163     private void addCheckUniPorts(Uni confUni) {
164         WriteTransaction tx = MdsalUtils.createTransaction(dataBroker);
165
166         String uniId = confUni.getUniId().getValue();
167         Link link = MefInterfaceUtils.getLink(dataBroker, uniId, LogicalDatastoreType.OPERATIONAL);
168         String trunkInterface = MefInterfaceUtils.getInterfaceNameForVlan(uniId, null);
169         String parentInterfaceName = MefInterfaceUtils.getTrunkParentName(link);
170         List<VlanToPort> operVlanInterfaces = getOperTrunkInterfaces(uniId);
171         if (!hasVlanPort(operVlanInterfaces, Long.valueOf(0))) {
172             VlanToPort newOperVlanInterface = addTrunkInterface(trunkInterface, parentInterfaceName, tx);
173             operVlanInterfaces.add(newOperVlanInterface);
174         }
175
176         List<CeVlan> ceVlans = confUni.getCeVlans() != null ? confUni.getCeVlans().getCeVlan()
177                 : Collections.emptyList();
178         for (CeVlan ceVlan : ceVlans) {
179             Long vlan = ceVlan.getVid().getValue().longValue();
180             if (hasVlanPort(operVlanInterfaces, vlan)) {
181                 continue;
182             }
183
184             String trunkMemberName = MefInterfaceUtils.getInterfaceNameForVlan(uniId, vlan);
185             VlanToPort newOperVlanInterface = addTrunkMemberInterface(trunkMemberName, trunkInterface, vlan, tx);
186             operVlanInterfaces.add(newOperVlanInterface);
187         }
188         // set VlanMapping to Uni
189         setOperTrunkInterfaces(uniId, operVlanInterfaces, tx);
190
191         MdsalUtils.commitTransaction(tx);
192     }
193
194     private void removeCheckUniPorts(Uni confUni) {
195         WriteTransaction tx = MdsalUtils.createTransaction(dataBroker);
196
197         List<CeVlan> ceVlans = confUni.getCeVlans() != null ? confUni.getCeVlans().getCeVlan()
198                 : Collections.emptyList();
199         List<Long> vlansValue = ceVlans.stream().map(x -> x.getVid().getValue()).collect(Collectors.toList());
200
201         String uniId = confUni.getUniId().getValue();
202         List<VlanToPort> operVlanInterfaces = getOperTrunkInterfaces(uniId);
203
204         for (VlanToPort oldPort : getOperTrunkInterfaces(uniId)) {
205             Long oldVlan = oldPort.getVlan().getValue();
206             if (!vlansValue.contains(oldVlan)) {
207                 VlanToPort removedOperVlanInterface = removeTrunkInterface(oldPort.getVlanPortId(), oldVlan, tx);
208                 operVlanInterfaces.remove(removedOperVlanInterface);
209             }
210         }
211         // set VlanMapping to Uni
212         setOperTrunkInterfaces(uniId, operVlanInterfaces, tx);
213
214         MdsalUtils.commitTransaction(tx);
215     }
216
217     private void removeUniPorts(Uni confUni) {
218         WriteTransaction tx = MdsalUtils.createTransaction(dataBroker);
219         String uniId = confUni.getUniId().getValue();
220
221         for (VlanToPort oldPort : getOperTrunkInterfaces(uniId)) {
222             Long oldVlan = oldPort.getVlan().getValue();
223             removeTrunkInterface(oldPort.getVlanPortId(), oldVlan, tx);
224         }
225         setOperTrunkInterfaces(uniId, new ArrayList<>(), tx);
226
227         MdsalUtils.commitTransaction(tx);
228     }
229
230     private VlanToPort addTrunkInterface(String interfaceName, String parentInterfaceName, WriteTransaction tx) {
231         log.info("Adding VLAN trunk {} ParentRef {}", interfaceName, parentInterfaceName);
232         Interface trunkInterface = NetvirtUtils.createTrunkInterface(interfaceName, parentInterfaceName);
233         NetvirtUtils.writeInterface(trunkInterface, tx);
234         return createOperTrunkInterfaceMapping(Long.valueOf(0), trunkInterface.getName());
235     }
236
237     private VlanToPort addTrunkMemberInterface(String interfaceName, String parentInterfaceName, Long vlan,
238             WriteTransaction tx) {
239         log.info("Adding VLAN trunk member {} ParentRef {}", interfaceName, parentInterfaceName);
240         Interface trunkInterface = NetvirtUtils.createTrunkMemberInterface(interfaceName, parentInterfaceName,
241                 vlan.intValue());
242         NetvirtUtils.writeInterface(trunkInterface, tx);
243         return createOperTrunkInterfaceMapping(vlan, trunkInterface.getName());
244     }
245
246     private VlanToPort removeTrunkInterface(String interfaceName, Long vlan, WriteTransaction tx) {
247         log.info("Delete VLAN trunk {} ParentRef {}", interfaceName);
248         NetvirtUtils.deleteInterface(interfaceName, tx);
249         return createOperTrunkInterfaceMapping(vlan, interfaceName);
250     }
251
252     private List<VlanToPort> getOperTrunkInterfaces(String operUniId) {
253         InstanceIdentifier<Uni> identifier = MefInterfaceUtils.getUniInstanceIdentifier(operUniId);
254         InstanceIdentifier<PortVlanMapping> path = identifier.augmentation(PortVlanMapping.class);
255         Optional<PortVlanMapping> portVlanMapping = MdsalUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL, path);
256         if (portVlanMapping.isPresent()) {
257             return portVlanMapping.get().getVlanToPort();
258         } else {
259             return new ArrayList<>();
260         }
261     }
262
263     private void setOperTrunkInterfaces(String operUniId, List<VlanToPort> vlanToPort, WriteTransaction tx) {
264         InstanceIdentifier<Uni> identifier = MefInterfaceUtils.getUniInstanceIdentifier(operUniId);
265         InstanceIdentifier<PortVlanMapping> path = identifier.augmentation(PortVlanMapping.class);
266
267         PortVlanMappingBuilder portVlanMappingB = new PortVlanMappingBuilder();
268         portVlanMappingB.setVlanToPort(vlanToPort);
269
270         tx.put(LogicalDatastoreType.OPERATIONAL, path, portVlanMappingB.build());
271     }
272
273     private VlanToPort createOperTrunkInterfaceMapping(Long vlan, String interfaceName) {
274         final Long vlanNotNull = replaceNull(vlan);
275
276         VlanToPortBuilder vlanToPortBuilder = new VlanToPortBuilder();
277         vlanToPortBuilder.setVlan(new VlanIdOrNoneType(vlanNotNull));
278         vlanToPortBuilder.setVlanPortId(interfaceName);
279         return vlanToPortBuilder.build();
280     }
281
282     private boolean hasVlanPort(List<VlanToPort> vlanInterfaces, Long vlan) {
283         if (vlanInterfaces == null) {
284             return false;
285         }
286         final Long vlanNotNull = replaceNull(vlan);
287
288         if (vlanInterfaces.stream().filter(x -> x.getVlan().getValue().equals(vlanNotNull)).findAny().isPresent()) {
289             return true;
290         }
291         return false;
292     }
293
294     private static final Long replaceNull(Long vlan) {
295         if (vlan == null) {
296             return Long.valueOf(0);
297         }
298         return vlan;
299     }
300
301     @Override
302     public void addCeVlan(String uniId, Long vlanId) {
303         if (getUniVlanInterfaceNoRetry(uniId, vlanId) != null) {
304             log.debug("UNI {} Port for vlan {} exists already, nothing to update", uniId, vlanId);
305             return;
306         }
307         synchronized (uniId.intern()) {
308             Uni confUni = MefInterfaceUtils.getUni(dataBroker, uniId, LogicalDatastoreType.CONFIGURATION);
309             if (confUni == null) {
310                 log.debug("No UNI {} exists, nothing to update");
311                 return;
312             }
313             if (!checkOperUni(uniId)) {
314                 return;
315             }
316             log.info("UNI  {} Vlan {} adding", uniId, vlanId);
317             List<CeVlan> ceVlans = confUni.getCeVlans() != null ? confUni.getCeVlans().getCeVlan() : new ArrayList<>();
318             CeVlanBuilder ceVlanBuilder = new CeVlanBuilder();
319             ceVlanBuilder.setVid(new VlanIdType(vlanId));
320             CeVlansBuilder ceVlansBuilder = confUni.getCeVlans() != null ? new CeVlansBuilder(confUni.getCeVlans())
321                     : new CeVlansBuilder();
322             ceVlans.add(ceVlanBuilder.build());
323             ceVlansBuilder.setCeVlan(ceVlans);
324             UniBuilder uniBuilder = new UniBuilder();
325             uniBuilder.setUniId(confUni.getUniId());
326             uniBuilder.setCeVlans(ceVlansBuilder.build());
327             MdsalUtils.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION,
328                     MefInterfaceUtils.getUniInstanceIdentifier(uniId), uniBuilder.build());
329         }
330     }
331
332     @Override
333     public void removeCeVlan(String uniId, Long vlanId) {
334         if (getUniVlanInterfaceNoRetry(uniId, vlanId) == null) {
335             log.debug("No UNI {} Port for vlan {} exists already, nothing to delete", uniId, vlanId);
336             return;
337         }
338         synchronized (uniId.intern()) {
339             Uni confUni = MefInterfaceUtils.getUni(dataBroker, uniId, LogicalDatastoreType.CONFIGURATION);
340             if (confUni == null) {
341                 log.debug("No UNI {} exists, nothing to update");
342                 return;
343             }
344             if (!checkOperUni(uniId)) {
345                 return;
346             }
347             log.info("UNI  {} Vlan {} deleting", uniId, vlanId);
348             UniBuilder uniBuilder = new UniBuilder(confUni);
349
350             if (vlanId != null && vlanId != 0l) {
351                 List<CeVlan> ceVlans = confUni.getCeVlans() != null ? confUni.getCeVlans().getCeVlan()
352                         : Collections.emptyList();
353                 CeVlanBuilder ceVlanBuilder = new CeVlanBuilder();
354                 ceVlanBuilder.setVid(new VlanIdType(vlanId));
355                 CeVlansBuilder ceVlansBuilder = new CeVlansBuilder(confUni.getCeVlans());
356                 ceVlans.remove(ceVlanBuilder.build());
357                 ceVlansBuilder.setCeVlan(ceVlans);
358                 uniBuilder.setCeVlans(ceVlansBuilder.build());
359             } else {
360                 uniBuilder.setCeVlans(null);
361             }
362             MdsalUtils.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
363                     MefInterfaceUtils.getUniInstanceIdentifier(uniId), uniBuilder.build());
364         }
365
366     }
367
368     @Override
369     public List<String> getUniVlanInterfaces(String uniId) {
370         synchronized (uniId.intern()) {
371             List<VlanToPort> vlanToPorts = getOperTrunkInterfaces(uniId);
372             return vlanToPorts.stream().map(port -> port.getVlanPortId()).collect(Collectors.toList());
373         }
374     }
375
376     @Override
377     public String getUniVlanInterface(String uniId, Long vlanId) {
378         Long vlanNotNull = replaceNull(vlanId);
379         return getUniVlanInterfaceRetry(uniId, vlanNotNull, 0);
380     }
381
382     public String getUniVlanInterfaceNoRetry(String uniId, Long vlanId) {
383         Long vlanNotNull = replaceNull(vlanId);
384         return getUniVlanInterfaceRetry(uniId, vlanNotNull, maxWaitRetries);
385     }
386
387     private String getUniVlanInterfaceRetry(String uniId, Long vlanId, int retries) {
388         log.trace("Retry {} to wait for uniId {} vlan {} interface", retries, uniId, vlanId);
389         List<VlanToPort> vlanToPorts = getOperTrunkInterfaces(uniId);
390         java.util.Optional<String> toReturn = vlanToPorts.stream()
391                 .filter(port -> port.getVlan().getValue().equals(vlanId)).map(port -> port.getVlanPortId()).findFirst();
392         if (toReturn.isPresent()) {
393             return toReturn.get();
394         } else {
395             if (retries >= maxWaitRetries) {
396                 return null;
397             }
398             NetvirtUtils.safeSleep();
399             return getUniVlanInterfaceRetry(uniId, vlanId, ++retries);
400         }
401     }
402 }