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