244f5a232cef379c8e08b576a16922c262223ca8
[unimgr.git] / netvirt / src / main / java / org / opendaylight / unimgr / mef / netvirt / IpvcListener.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.math.BigInteger;
12 import java.util.ArrayList;
13 import java.util.Collections;
14 import java.util.List;
15 import java.util.concurrent.ConcurrentHashMap;
16 import java.util.stream.Collectors;
17
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
20 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
21 import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
22 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
23 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
24 import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
25 import org.opendaylight.unimgr.api.UnimgrDataTreeChangeListener;
26 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.subnets.Subnet;
27 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.subnets.SubnetBuilder;
28 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.uni.ip.unis.IpUni;
29 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.services.rev150526.IpvcVpn;
30 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.services.rev150526.mef.services.mef.service.mef.service.choice.ipvc.choice.Ipvc;
31 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.services.rev150526.mef.services.mef.service.mef.service.choice.ipvc.choice.ipvc.VpnElans;
32 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.services.rev150526.mef.services.mef.service.mef.service.choice.ipvc.choice.ipvc.unis.Uni;
33 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.services.rev150526.mef.services.mef.service.mef.service.choice.ipvc.choice.ipvc.unis.UniKey;
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.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.BridgeRefInfo;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntry;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntryKey;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface.EtreeInterfaceType;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
50 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
51 import org.opendaylight.yangtools.concepts.ListenerRegistration;
52 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56 import com.google.common.base.Optional;
57
58 public class IpvcListener extends UnimgrDataTreeChangeListener<Ipvc> implements IUniAwareService {
59     private static final Logger Log = LoggerFactory.getLogger(IpvcListener.class);
60     private final IUniPortManager uniPortManager;
61     private final ISubnetManager subnetManager;
62     private final UniQosManager uniQosManager;
63     private ListenerRegistration<IpvcListener> ipvcListenerRegistration;
64     @SuppressWarnings("unused")
65     private final UniAwareListener uniAwareListener;
66     private OdlInterfaceRpcService odlInterfaceRpcService;
67     private final SouthboundUtils southBoundUtils;
68     private final org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils mdsalUtils;
69     private final NotificationPublishService notificationPublishService;
70
71     private static final String LOCAL_IP = "local_ip";
72
73     // TODO: make it as service
74     private ConcurrentHashMap<String, BigInteger> portToDpn;
75
76     public IpvcListener(final DataBroker dataBroker, final IUniPortManager uniPortManager,
77             final ISubnetManager subnetManager, final UniQosManager uniQosManager,
78             final OdlInterfaceRpcService odlInterfaceRpcService, final NotificationPublishService notPublishService) {
79         super(dataBroker);
80         this.uniPortManager = uniPortManager;
81         this.subnetManager = subnetManager;
82         this.uniQosManager = uniQosManager;
83         this.uniAwareListener = new UniAwareListener(dataBroker, this);
84         this.odlInterfaceRpcService = odlInterfaceRpcService;
85         this.mdsalUtils = new org.opendaylight.ovsdb.utils.mdsal.utils.MdsalUtils(dataBroker);
86         this.southBoundUtils = new SouthboundUtils(mdsalUtils);
87         this.portToDpn = new ConcurrentHashMap<>();
88         this.notificationPublishService = notPublishService;
89
90         registerListener();
91     }
92
93     public void registerListener() {
94         try {
95             final DataTreeIdentifier<Ipvc> dataTreeIid = new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
96                     MefServicesUtils.getIpvcsInstanceIdentifier());
97             ipvcListenerRegistration = dataBroker.registerDataTreeChangeListener(dataTreeIid, this);
98             Log.info("IpvcDataTreeChangeListener created and registered");
99         } catch (final Exception e) {
100             Log.error("Ipvc DataChange listener registration failed !", e);
101             throw new IllegalStateException("Ipvc registration Listener failed.", e);
102         }
103     }
104
105     @Override
106     public void close() throws Exception {
107         ipvcListenerRegistration.close();
108     }
109
110     @Override
111     public void add(DataTreeModification<Ipvc> newDataObject) {
112         if (newDataObject.getRootPath() != null && newDataObject.getRootNode() != null) {
113             Log.info("ipvc {} created", newDataObject.getRootNode().getIdentifier());
114             addIpvc(newDataObject);
115         }
116     }
117
118     @Override
119     public void remove(DataTreeModification<Ipvc> removedDataObject) {
120         if (removedDataObject.getRootPath() != null && removedDataObject.getRootNode() != null) {
121             Log.info("ipvc {} deleted", removedDataObject.getRootNode().getIdentifier());
122             removeIpvc(removedDataObject);
123         }
124     }
125
126     @Override
127     public void update(DataTreeModification<Ipvc> modifiedDataObject) {
128         if (modifiedDataObject.getRootPath() != null && modifiedDataObject.getRootNode() != null) {
129             Log.info("ipvc {} updated", modifiedDataObject.getRootNode().getIdentifier());
130             updateIpvc(modifiedDataObject);
131         }
132     }
133
134     @Override
135     public void connectUni(String uniId) {
136         List<RetailSvcIdType> allIpvcs = MefServicesUtils.getAllIpvcsServiceIds(dataBroker);
137         allIpvcs = allIpvcs != null ? allIpvcs : Collections.emptyList();
138
139         for (RetailSvcIdType ipvcSerId : allIpvcs) {
140             InstanceIdentifier<Ipvc> ipvcId = MefServicesUtils.getIpvcInstanceIdentifier(ipvcSerId);
141             Ipvc ipvc = MefServicesUtils.getIpvc(dataBroker, ipvcId);
142             if (ipvc == null) {
143                 Log.error("Inconsistent data for svcId {}", ipvcSerId);
144                 continue;
145             }
146             List<Uni> toConnect = new ArrayList<>();
147
148             List<Uni> unis = ipvc.getUnis() != null ? ipvc.getUnis().getUni() : null;
149             unis = unis != null ? unis : Collections.emptyList();
150             for (Uni uni : unis) {
151                 if (uni.getUniId().getValue().equals(uniId)) {
152                     Log.info("Connecting Uni {} to svc id {}", uniId, ipvcSerId);
153                     toConnect.add(uni);
154                     break;
155                 }
156             }
157
158             IpvcVpn operIpvcVpn = MefServicesUtils.getOperIpvcVpn(dataBroker, ipvcId);
159             if (operIpvcVpn == null) {
160                 String instanceName = ipvc.getIpvcId().getValue();
161                 final String vpnName = NetvirtVpnUtils.getUUidFromString(instanceName);
162                 createVpnInstance(vpnName, ipvcId);
163                 operIpvcVpn = MefServicesUtils.getOperIpvcVpn(dataBroker, ipvcId);
164                 if (operIpvcVpn == null) {
165                     Log.error("Ipvc {} hasn't been created as required, Nothing to reconnect", ipvcSerId);
166                     return;
167                 }
168             }
169             String vpnName = operIpvcVpn.getVpnId();
170             String rd = waitForRd(vpnName);
171             createUnis(vpnName, ipvcId, toConnect, rd);
172         }
173     }
174
175     @Override
176     public void disconnectUni(String uniId) {
177
178         List<RetailSvcIdType> allIpvcs = MefServicesUtils.getAllIpvcsServiceIds(dataBroker);
179         allIpvcs = allIpvcs != null ? allIpvcs : Collections.emptyList();
180
181         for (RetailSvcIdType ipvcSerId : allIpvcs) {
182             InstanceIdentifier<Ipvc> ipvcId = MefServicesUtils.getIpvcInstanceIdentifier(ipvcSerId);
183             Ipvc ipvc = MefServicesUtils.getIpvc(dataBroker, ipvcId);
184             if (ipvc == null) {
185                 Log.error("Inconsistent data for svcId {}", ipvcSerId);
186                 continue;
187             }
188             List<Uni> toRemove = new ArrayList<>();
189
190             List<Uni> unis = ipvc.getUnis() != null ? ipvc.getUnis().getUni() : null;
191             unis = unis != null ? unis : Collections.emptyList();
192             for (Uni uni : unis) {
193                 if (uni.getUniId().getValue().equals(uniId)) {
194                     Log.info("Disconnecting Uni {} from svc id {}", uniId, ipvcSerId);
195                     toRemove.add(uni);
196                     break;
197                 }
198             }
199
200             IpvcVpn operIpvcVpn = MefServicesUtils.getOperIpvcVpn(dataBroker, ipvcId);
201             if (operIpvcVpn == null) {
202                 Log.error("Ipvc {} hasn't been created as required, Nothing to disconnect", ipvcSerId);
203                 return;
204             }
205
206             removeUnis(ipvcId, operIpvcVpn, toRemove);
207         }
208
209     }
210
211     private void addIpvc(DataTreeModification<Ipvc> newDataObject) {
212         try {
213             Ipvc ipvc = newDataObject.getRootNode().getDataAfter();
214             String instanceName = ipvc.getIpvcId().getValue();
215             final String vpnName = NetvirtVpnUtils.getUUidFromString(instanceName);
216             InstanceIdentifier<Ipvc> ipvcId = newDataObject.getRootPath().getRootIdentifier();
217             createVpnInstance(vpnName, ipvcId);
218             String rd = waitForRd(vpnName);
219
220             updateOperationalDataStoreWithVrfId(ipvcId, vpnName, rd);
221
222             List<Uni> unis = new ArrayList<>();
223             if (ipvc.getUnis() != null && ipvc.getUnis() != null) {
224                 unis = ipvc.getUnis().getUni();
225             }
226             Log.info("Number of UNI's: " + unis.size());
227
228             createUnis(vpnName, ipvcId, unis, rd);
229         } catch (final Exception e) {
230             Log.error("Add ipvc failed !", e);
231         }
232     }
233
234     private void updateOperationalDataStoreWithVrfId(InstanceIdentifier<Ipvc> ipvcId, String vpnName, String vrfId) {
235         WriteTransaction tx = MdsalUtils.createTransaction(dataBroker);
236         MefServicesUtils.addOperIpvcVpnElan(ipvcId, vpnName, vrfId, tx);
237         MdsalUtils.commitTransaction(tx);
238     }
239
240     private void createVpnInstance(final String vpnName, InstanceIdentifier<Ipvc> ipvcId) {
241         synchronized (vpnName.intern()) {
242             WriteTransaction tx = MdsalUtils.createTransaction(dataBroker);
243             Log.info("Adding vpn instance: " + vpnName);
244             NetvirtVpnUtils.createVpnInstance(vpnName, tx);
245             MefServicesUtils.addOperIpvcVpnElan(ipvcId, vpnName, tx);
246             MdsalUtils.commitTransaction(tx);
247         }
248     }
249
250     private String waitForRd(final String vpnName) {
251         InstanceIdentifier<VpnInstance> vpnId = NetvirtVpnUtils.getVpnInstanceToVpnIdIdentifier(vpnName);
252         @SuppressWarnings("resource")
253         DataWaitListener<VpnInstance> vpnInstanceWaiter = new DataWaitListener<VpnInstance>(dataBroker, vpnId, 5,
254                 LogicalDatastoreType.CONFIGURATION, vpn -> vpn.getVrfId());
255         if (!vpnInstanceWaiter.waitForData()) {
256             String errorMessage = String.format("Fail to wait for vrfId for vpn %s", vpnName);
257             Log.error(errorMessage);
258             throw new UnsupportedOperationException(errorMessage);
259         }
260         String rd = (String) vpnInstanceWaiter.getData();
261         return rd;
262     }
263
264     private void removeIpvc(DataTreeModification<Ipvc> removedDataObject) {
265         try {
266             Ipvc ipvc = removedDataObject.getRootNode().getDataBefore();
267             InstanceIdentifier<Ipvc> ipvcId = removedDataObject.getRootPath().getRootIdentifier();
268             IpvcVpn operIpvcVpn = MefServicesUtils.getOperIpvcVpn(dataBroker, ipvcId);
269             if (operIpvcVpn == null) {
270                 Log.error("Ipvc {} hasn't been created as required", ipvc.getIpvcId());
271                 return;
272             }
273             removeUnis(ipvcId, operIpvcVpn, ipvc.getUnis().getUni());
274             NetvirtUtils.safeSleep();
275
276             String vpnId = operIpvcVpn.getVpnId();
277             synchronized (vpnId.intern()) {
278                 WriteTransaction txvpn = MdsalUtils.createTransaction(dataBroker);
279                 NetvirtVpnUtils.removeVpnInstance(operIpvcVpn.getVpnId(), txvpn);
280                 MefServicesUtils.removeOperIpvcVpn(ipvcId, txvpn);
281                 MdsalUtils.commitTransaction(txvpn);
282             }
283         } catch (final Exception e) {
284             Log.error("Remove ipvc failed !", e);
285         }
286     }
287
288     private void removeUnis(InstanceIdentifier<Ipvc> ipvcId, IpvcVpn operIpvcVpn, List<Uni> uniToRemove) {
289         if (uniToRemove == null) {
290             Log.trace("No UNI's to remove");
291         }
292         for (Uni uni : uniToRemove) {
293             Identifier45 uniId = uni.getUniId();
294             Identifier45 ipUniId = uni.getIpUniId();
295             IpUni ipUni = MefInterfaceUtils.getIpUni(dataBroker, uniId, ipUniId, LogicalDatastoreType.CONFIGURATION);
296             if (ipUni == null) {
297                 String errorMessage = String.format("Couldn't find ipuni %s for uni %s", ipUniId, uniId);
298                 Log.error(errorMessage);
299                 throw new UnsupportedOperationException(errorMessage);
300             }
301
302             removeDirectSubnet(uni, ipUni);
303             subnetManager.unAssignIpUniNetworks(uni.getUniId(), ipUni.getIpUniId(), ipvcId);
304             removeInterfaces(ipvcId, operIpvcVpn, uni, ipUni);
305         }
306         updateQos(uniToRemove);
307     }
308
309     private void createUnis(String vpnName, InstanceIdentifier<Ipvc> ipvcId, List<Uni> uniToCreate, String rd) {
310         // Create elan/vpn interfaces
311         for (Uni uni : uniToCreate) {
312             createInterfaces(vpnName, uni, ipvcId, rd);
313         }
314
315         for (Uni uni : uniToCreate) {
316             IpUni ipUni = MefInterfaceUtils.getIpUni(dataBroker, uni.getUniId(), uni.getIpUniId(),
317                     LogicalDatastoreType.CONFIGURATION);
318             createDirectSubnet(uni, ipUni);
319             subnetManager.assignIpUniNetworks(uni.getUniId(), ipUni.getIpUniId(), ipvcId);
320         }
321         updateQos(uniToCreate);
322
323     }
324
325     private void updateIpvc(DataTreeModification<Ipvc> modifiedDataObject) {
326         try {
327             Ipvc origIpvc = modifiedDataObject.getRootNode().getDataBefore();
328             Ipvc updateIpvc = modifiedDataObject.getRootNode().getDataAfter();
329             InstanceIdentifier<Ipvc> ipvcId = modifiedDataObject.getRootPath().getRootIdentifier();
330             IpvcVpn operIpvcVpn = MefServicesUtils.getOperIpvcVpn(dataBroker, ipvcId);
331             if (operIpvcVpn == null) {
332                 Log.error("Ipvc {} hasn't been created as required", origIpvc.getIpvcId());
333                 return;
334             }
335             String vpnName = operIpvcVpn.getVpnId();
336             String rd = waitForRd(vpnName);
337             List<Uni> originalUni = origIpvc.getUnis() != null && origIpvc.getUnis().getUni() != null
338                     ? origIpvc.getUnis().getUni() : Collections.emptyList();
339             List<UniKey> originalUniIds = originalUni.stream().map(u -> u.getKey()).collect(Collectors.toList());
340             List<Uni> updateUni = updateIpvc.getUnis() != null && updateIpvc.getUnis().getUni() != null
341                     ? updateIpvc.getUnis().getUni() : Collections.emptyList();
342             List<UniKey> updateUniIds = updateUni.stream().map(u -> u.getKey()).collect(Collectors.toList());
343
344             List<Uni> uniToRemove = new ArrayList<>(originalUni);
345             uniToRemove.removeIf(u -> updateUniIds.contains(u.getKey()));
346             removeUnis(ipvcId, operIpvcVpn, uniToRemove);
347
348             List<Uni> uniToCreate = new ArrayList<>(updateUni);
349             uniToCreate.removeIf(u -> originalUniIds.contains(u.getKey()));
350             createUnis(vpnName, ipvcId, uniToCreate, rd);
351
352             List<Uni> uniToUpdate = new ArrayList<>(updateUni);
353             uniToUpdate.removeIf(u -> !originalUniIds.contains(u.getKey()));
354             updateUnis(uniToUpdate);
355
356         } catch (final Exception e) {
357             Log.error("Update ipvc failed !", e);
358         }
359     }
360
361     private void createInterfaces(String vpnName, Uni uniInService, InstanceIdentifier<Ipvc> ipvcId, String rd) {
362         WriteTransaction tx = MdsalUtils.createTransaction(dataBroker);
363         String uniId = uniInService.getUniId().getValue();
364         String ipUniId = uniInService.getIpUniId().getValue();
365         org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.Uni uni = MefInterfaceUtils
366                 .getUni(dataBroker, uniId, LogicalDatastoreType.OPERATIONAL);
367         if (uni == null) {
368             String errorMessage = String.format("Couldn't find uni %s for ipvc", uniId);
369             Log.error(errorMessage);
370             throw new UnsupportedOperationException(errorMessage);
371         }
372         IpUni ipUni = MefInterfaceUtils.getIpUni(dataBroker, uniInService.getUniId(), uniInService.getIpUniId(),
373                 LogicalDatastoreType.CONFIGURATION);
374         if (ipUni == null) {
375             String errorMessage = String.format("Couldn't find ipuni %s for uni %s", ipUniId, uniId);
376             Log.error(errorMessage);
377             throw new UnsupportedOperationException(errorMessage);
378         }
379
380         String interfaceName = null;
381         String elanName = NetvirtVpnUtils.getElanNameForVpnPort(uniId, ipUniId);
382
383         synchronized (vpnName.intern()) {
384             Long vlan = ipUni.getVlan() != null ? Long.valueOf(ipUni.getVlan().getValue()) : null;
385
386             interfaceName = createElanInterface(vpnName, ipvcId, uniId, elanName, vlan, ipUni.getSegmentationId());
387
388             String portMacAddress = uni.getMacAddress().getValue();
389             NetvirtVpnUtils.registerDirectSubnetForVpn(dataBroker, vpnName, new Uuid(elanName), ipUni.getIpAddress(),
390                     interfaceName, portMacAddress);
391
392             uniQosManager.mapUniPortBandwidthLimits(uniId, interfaceName, uniInService.getIngressBwProfile());
393             createVpnInterface(vpnName, uni, ipUni, interfaceName, elanName, tx);
394             NetvirtVpnUtils.createVpnPortFixedIp(dataBroker, vpnName, interfaceName, ipUni.getIpAddress(),
395                     uni.getMacAddress(), tx);
396             MefServicesUtils.addOperIpvcVpnElan(ipvcId, vpnName, uniInService.getUniId(), uniInService.getIpUniId(),
397                     elanName, interfaceName, null, tx);
398             MdsalUtils.commitTransaction(tx);
399         }
400     }
401
402     private String createElanInterface(String vpnName, InstanceIdentifier<Ipvc> ipvcId, String uniId, String elanName,
403             Long vlan, Long segmentationId) {
404         Log.info("Adding elan instance: " + elanName);
405         WriteTransaction tx = MdsalUtils.createTransaction(dataBroker);
406         NetvirtUtils.updateElanInstance(elanName, tx, segmentationId);
407
408         Log.info("Added trunk interface for uni {} vlan: {}", uniId, vlan);
409         if (vlan != null) {
410             uniPortManager.addCeVlan(uniId, vlan);
411         }
412         String interfaceName = uniPortManager.getUniVlanInterface(uniId, vlan);
413         if (interfaceName == null) {
414             String errorMessage = String.format("Couldn't create  uni %s vlan interface %s", uniId, vlan);
415             Log.error(errorMessage);
416             throw new UnsupportedOperationException(errorMessage);
417         }
418
419         Log.info("Adding elan interface: " + interfaceName);
420         NetvirtUtils.createElanInterface(elanName, interfaceName, EtreeInterfaceType.Root, false, tx);
421         MdsalUtils.commitTransaction(tx);
422         return interfaceName;
423     }
424
425     private void createVpnInterface(String vpnName,
426             org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.Uni uni,
427             IpUni ipUni, String interfaceName, String elanName, WriteTransaction tx) {
428
429         Log.info("Adding vpn interface: " + interfaceName);
430         BigInteger dpId = getPortDpId(interfaceName);
431         IpAddress nextHop = getNodeIP(dpId);
432         NetvirtVpnUtils.createUpdateVpnInterface(vpnName, interfaceName, nextHop, ipUni.getIpAddress(),
433                 uni.getMacAddress().getValue(), true, null, elanName, tx);
434         Log.info("Finished working on vpn instance {} interface () ", vpnName, interfaceName);
435     }
436
437     private void createDirectSubnet(Uni uni, IpUni ipUni) {
438         IpPrefix uniIpPrefix = ipUni.getIpAddress();
439         String subnetIp = NetvirtVpnUtils.getSubnetFromPrefix(uniIpPrefix);
440         IpPrefix subnetPrefix = new IpPrefix(new Ipv4Prefix(subnetIp));
441         InstanceIdentifier<Subnet> path = MefInterfaceUtils.getSubnetInstanceIdentifier(uni.getUniId(),
442                 ipUni.getIpUniId(), subnetPrefix);
443         SubnetBuilder subnet = new SubnetBuilder();
444         subnet.setUniId(uni.getUniId());
445         subnet.setIpUniId(ipUni.getIpUniId());
446         subnet.setSubnet(subnetPrefix);
447         MdsalUtils.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, path, subnet.build());
448     }
449
450     private void removeInterfaces(InstanceIdentifier<Ipvc> ipvcId, IpvcVpn ipvcVpn, Uni uniInService, IpUni ipUni) {
451         String uniId = uniInService.getUniId().getValue();
452         String vpnName = ipvcVpn.getVpnId();
453         VpnElans vpnElans = MefServicesUtils.findVpnElanForNetwork(new Identifier45(uniId), ipUni.getIpUniId(),
454                 ipvcVpn);
455         if (vpnElans == null) {
456             Log.error("Trying to remove non-operational vpn/elan for Uni {} Ip-UNi {}", uniId, ipUni.getIpUniId());
457             return;
458         }
459
460         synchronized (vpnName.intern()) {
461             NetvirtVpnUtils.unregisterDirectSubnetForVpn(dataBroker, vpnName, new Uuid(vpnElans.getElanId()),
462                     vpnElans.getElanPort());
463             uniQosManager.unMapUniPortBandwidthLimits(uniId, vpnElans.getElanPort());
464             NetvirtVpnUtils.removeLearnedVpnVipToPort(dataBroker, vpnName, vpnElans.getElanPort());
465             removeVpnInterface(vpnName, vpnElans, uniId, ipUni);
466         }
467         waitForInterfaceDpnClean(vpnName, ipvcVpn.getVrfId(), vpnElans.getElanPort());
468
469         synchronized (vpnName.intern()) {
470             removeElan(vpnElans, uniId, ipUni);
471             MefServicesUtils.removeOperIpvcElan(dataBroker, ipvcId, ipvcVpn.getVpnId(), uniInService.getUniId(),
472                     uniInService.getIpUniId(), vpnElans.getElanId(), vpnElans.getElanPort());
473         }
474
475     }
476
477     private void waitForInterfaceDpnClean(String vpnName, String rd, String interfaceName) {
478         InstanceIdentifier<VpnInstanceOpDataEntry> vpnId = NetvirtVpnUtils.getVpnInstanceOpDataIdentifier(rd);
479         DataWaitGetter<VpnInstanceOpDataEntry> getInterfByName = (vpn) -> {
480             if (vpn.getVpnToDpnList() == null)
481                 return null;
482             for (VpnToDpnList is : vpn.getVpnToDpnList()) {
483                 if (is.getVpnInterfaces() == null)
484                     continue;
485                 for (VpnInterfaces i : is.getVpnInterfaces()) {
486                     if (i.getInterfaceName().equals(interfaceName)) {
487                         Log.info("Waiting for deletion vpn interface from vpn to dpn list vpn : {} interface: {}",
488                                 vpnName, interfaceName);
489                         return interfaceName;
490                     }
491                 }
492             }
493             Log.info("Deleted vpn interface from vpn to dpn list vpn : {} interface: {}", vpnName, interfaceName);
494             return null;
495         };
496
497         int retryCount = 2;
498         Optional<VpnInstanceOpDataEntry> vpnOper = MdsalUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL, vpnId);
499         if (vpnOper.isPresent() && vpnOper.get().getVpnToDpnList() != null) {
500             for (VpnToDpnList vpnList : vpnOper.get().getVpnToDpnList()) {
501                 if (vpnList.getVpnInterfaces() != null) {
502                     retryCount = retryCount + 2 * vpnList.getVpnInterfaces().size();
503                 }
504             }
505         }
506
507         @SuppressWarnings("resource")
508         DataWaitListener<VpnInstanceOpDataEntry> vpnInstanceWaiter = new DataWaitListener<>(dataBroker, vpnId,
509                 retryCount, LogicalDatastoreType.OPERATIONAL, getInterfByName);
510         if (!vpnInstanceWaiter.waitForClean()) {
511             String errorMessage = String.format("Fail to wait for vpn to dpn list clean-up vpn : %s interface: %s",
512                     vpnName, interfaceName);
513             Log.error(errorMessage);
514             throw new UnsupportedOperationException(errorMessage);
515         }
516     }
517
518     private void removeElan(VpnElans vpnElans, String uniId, IpUni ipUni) {
519         WriteTransaction tx = MdsalUtils.createTransaction(dataBroker);
520
521         Long vlan = ipUni.getVlan() != null ? Long.valueOf(ipUni.getVlan().getValue()) : 0;
522         Log.info("Removing trunk interface for uni {} vlan: {}", uniId, vlan);
523         uniPortManager.removeCeVlan(uniId, vlan);
524
525         String elanName = vpnElans.getElanId();
526         String interfaceName = vpnElans.getElanPort();
527
528         Log.info("Removing elan instance {} and interface {}: ", elanName, interfaceName);
529         NetvirtUtils.deleteElanInterface(interfaceName, tx);
530         NetvirtUtils.deleteElanInstance(elanName, tx);
531         MdsalUtils.commitTransaction(tx);
532     }
533
534     private void removeVpnInterface(String vpnName, VpnElans vpnElans, String uniId, IpUni ipUni, WriteTransaction tx) {
535         String interfaceName = vpnElans.getElanPort();
536         NetvirtVpnUtils.removeVpnInterface(interfaceName, tx);
537         NetvirtVpnUtils.removeVpnPortFixedIp(vpnName, ipUni.getIpAddress(), tx);
538     }
539
540     private void removeVpnInterface(String vpnName, VpnElans vpnElans, String uniId, IpUni ipUni) {
541         Log.info("Removing vpn interface: " + vpnElans.getElanPort());
542         WriteTransaction tx = MdsalUtils.createTransaction(dataBroker);
543         removeVpnInterface(vpnName, vpnElans, uniId, ipUni, tx);
544         MdsalUtils.commitTransaction(tx);
545         Log.info("Finished working on vpn interface: " + vpnElans.getElanPort());
546     }
547
548     private void removeDirectSubnet(Uni uni, IpUni ipUni) {
549         IpPrefix uniIpPrefix = ipUni.getIpAddress();
550         String subnetIp = NetvirtVpnUtils.getSubnetFromPrefix(uniIpPrefix);
551         IpPrefix subnetPrefix = new IpPrefix(new Ipv4Prefix(subnetIp));
552         InstanceIdentifier<Subnet> path = MefInterfaceUtils.getSubnetInstanceIdentifier(uni.getUniId(),
553                 ipUni.getIpUniId(), subnetPrefix);
554         MdsalUtils.delete(dataBroker, LogicalDatastoreType.CONFIGURATION, path);
555     }
556
557     private void updateQos(List<Uni> uniToUpdate) {
558         uniToUpdate.forEach(u -> uniQosManager.setUniBandwidthLimits(u.getUniId()));
559     }
560
561     private void updateUnis(List<Uni> uniToUpdate) {
562         uniToUpdate.forEach(u -> uniQosManager.updateUni(u.getUniId(), u.getIngressBwProfile()));
563         updateQos(uniToUpdate);
564     }
565
566     private IpAddress getNodeIP(BigInteger dpId) {
567         Node node = getPortsNode(dpId);
568         String localIp = southBoundUtils.getOpenvswitchOtherConfig(node, LOCAL_IP);
569         if (localIp == null) {
570             throw new UnsupportedOperationException(
571                     "missing local_ip key in ovsdb:openvswitch-other-configs in operational"
572                             + " network-topology for node: " + node.getNodeId().getValue());
573         }
574
575         return new IpAddress(localIp.toCharArray());
576     }
577
578     @SuppressWarnings("unchecked")
579     private Node getPortsNode(BigInteger dpnId) {
580         InstanceIdentifier<BridgeRefEntry> bridgeRefInfoPath = InstanceIdentifier.create(BridgeRefInfo.class)
581                 .child(BridgeRefEntry.class, new BridgeRefEntryKey(dpnId));
582         BridgeRefEntry bridgeRefEntry = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, bridgeRefInfoPath);
583         if (bridgeRefEntry == null) {
584             throw new UnsupportedOperationException("no bridge ref entry found for dpnId: " + dpnId);
585         }
586
587         InstanceIdentifier<Node> nodeId = ((InstanceIdentifier<OvsdbBridgeAugmentation>) bridgeRefEntry
588                 .getBridgeReference().getValue()).firstIdentifierOf(Node.class);
589         Node node = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, nodeId);
590
591         if (node == null) {
592             throw new UnsupportedOperationException("missing node for dpnId: " + dpnId);
593         }
594         return node;
595
596     }
597
598     private BigInteger getPortDpId(String logicalPortId) {
599         BigInteger dpId = BigInteger.ZERO;
600         if (portToDpn.containsKey(logicalPortId)) {
601             dpId = portToDpn.get(logicalPortId);
602         } else {
603             dpId = NetvirtUtils.getDpnForInterface(odlInterfaceRpcService, logicalPortId);
604             portToDpn.put(logicalPortId, dpId);
605         }
606         return dpId;
607     }
608 }