4fdba752d74b70ac030b2b96e95b80b5145091d4
[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.util.ArrayList;
12 import java.util.Collections;
13 import java.util.List;
14
15 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
16 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
17 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
18 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
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.interfaces.rev150526.mef.interfaces.subnets.Subnet;
22 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.subnets.SubnetBuilder;
23 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.uni.ip.unis.IpUni;
24 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.services.rev150526.IpvcVpn;
25 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.services.rev150526.mef.services.mef.service.mef.service.choice.ipvc.choice.Ipvc;
26 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;
27 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;
28 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.types.rev150526.Identifier45;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
30 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
31 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.etree.rev160614.EtreeInterface.EtreeInterfaceType;
34 import org.opendaylight.yangtools.concepts.ListenerRegistration;
35 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 public class IpvcListener extends UnimgrDataTreeChangeListener<Ipvc> {
40     private static final Logger Log = LoggerFactory.getLogger(IpvcListener.class);
41     private final IUniPortManager uniPortManager;
42     private final ISubnetManager subnetManager;
43     private ListenerRegistration<IpvcListener> ipvcListenerRegistration;
44
45     public IpvcListener(final DataBroker dataBroker, final IUniPortManager uniPortManager,
46             final ISubnetManager subnetManager) {
47         super(dataBroker);
48         this.uniPortManager = uniPortManager;
49         this.subnetManager = subnetManager;
50
51         registerListener();
52     }
53
54     public void registerListener() {
55         try {
56             final DataTreeIdentifier<Ipvc> dataTreeIid = new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
57                     MefServicesUtils.getIpvcsInstanceIdentifier());
58             ipvcListenerRegistration = dataBroker.registerDataTreeChangeListener(dataTreeIid, this);
59             Log.info("IpvcDataTreeChangeListener created and registered");
60         } catch (final Exception e) {
61             Log.error("Ipvc DataChange listener registration failed !", e);
62             throw new IllegalStateException("Ipvc registration Listener failed.", e);
63         }
64     }
65
66     @Override
67     public void close() throws Exception {
68         ipvcListenerRegistration.close();
69     }
70
71     @Override
72     public void add(DataTreeModification<Ipvc> newDataObject) {
73         if (newDataObject.getRootPath() != null && newDataObject.getRootNode() != null) {
74             Log.info("ipvc {} created", newDataObject.getRootNode().getIdentifier());
75             addIpvc(newDataObject);
76         }
77     }
78
79     @Override
80     public void remove(DataTreeModification<Ipvc> removedDataObject) {
81         if (removedDataObject.getRootPath() != null && removedDataObject.getRootNode() != null) {
82             Log.info("ipvc {} deleted", removedDataObject.getRootNode().getIdentifier());
83             removeIpvc(removedDataObject);
84         }
85     }
86
87     @Override
88     public void update(DataTreeModification<Ipvc> modifiedDataObject) {
89         if (modifiedDataObject.getRootPath() != null && modifiedDataObject.getRootNode() != null) {
90             Log.info("ipvc {} updated", modifiedDataObject.getRootNode().getIdentifier());
91             updateIpvc(modifiedDataObject);
92         }
93     }
94
95     private void addIpvc(DataTreeModification<Ipvc> newDataObject) {
96         try {
97             WriteTransaction tx = MdsalUtils.createTransaction(dataBroker);
98             Ipvc ipvc = newDataObject.getRootNode().getDataAfter();
99             String instanceName = ipvc.getIpvcId().getValue();
100             final String vpnName = NetvirtVpnUtils.getUUidFromString(instanceName);
101             InstanceIdentifier<Ipvc> ipvcId = newDataObject.getRootPath().getRootIdentifier();
102             List<Uni> unis = new ArrayList<>();
103             synchronized (vpnName.intern()) {
104                 Log.info("Adding vpn instance: " + instanceName);
105                 NetvirtVpnUtils.createVpnInstance(vpnName, tx);
106                 MefServicesUtils.addOperIpvcVpnElan(ipvcId, vpnName, tx);
107                 if (ipvc.getUnis() != null && ipvc.getUnis() != null) {
108                     unis = ipvc.getUnis().getUni();
109                 }
110                 Log.info("Number of UNI's: " + unis.size());
111
112                 // Create elan/vpn interfaces
113                 for (Uni uni : unis) {
114                     createInterfaces(vpnName, uni, ipvcId, tx);
115                 }
116                 MdsalUtils.commitTransaction(tx);
117             }
118             for (Uni uni : unis) {
119                 IpUni ipUni = MefInterfaceUtils.getIpUni(dataBroker, uni.getUniId(), uni.getIpUniId(),
120                         LogicalDatastoreType.CONFIGURATION);
121                 createDirectSubnet(uni, ipUni);
122                 subnetManager.assignIpUniNetworks(uni.getUniId(), ipUni.getIpUniId(), ipvcId);
123             }
124         } catch (final Exception e) {
125             Log.error("Add ipvc failed !", e);
126         }
127     }
128
129     private void removeIpvc(DataTreeModification<Ipvc> removedDataObject) {
130         try {
131             Ipvc ipvc = removedDataObject.getRootNode().getDataBefore();
132             InstanceIdentifier<Ipvc> ipvcId = removedDataObject.getRootPath().getRootIdentifier();
133             IpvcVpn operIpvcVpn = MefServicesUtils.getOperIpvcVpn(dataBroker, ipvcId);
134             if (operIpvcVpn == null) {
135                 Log.error("Ipvc {} hasn't been created as required", ipvc.getIpvcId());
136                 return;
137             }
138             String vpnName = operIpvcVpn.getVpnId();
139
140             synchronized (vpnName.intern()) {
141                 // remove elan/vpn interfaces
142                 // must be in different transactios
143                 WriteTransaction tx = MdsalUtils.createTransaction(dataBroker);
144                 removeUni(ipvcId, operIpvcVpn, ipvc.getUnis().getUni(), tx);
145                 MdsalUtils.commitTransaction(tx);
146                 // Let to work for listeners
147                 // TODO : change to listener
148                 NetvirtUtils.safeSleep();
149
150                 WriteTransaction txvpn = MdsalUtils.createTransaction(dataBroker);
151                 NetvirtVpnUtils.removeVpnInstance(operIpvcVpn.getVpnId(), txvpn);
152                 MefServicesUtils.removeOperIpvcVpn(ipvcId, txvpn);
153                 MdsalUtils.commitTransaction(txvpn);
154             }
155         } catch (final Exception e) {
156             Log.error("Remove ipvc failed !", e);
157         }
158     }
159
160     private void removeUni(InstanceIdentifier<Ipvc> ipvcId, IpvcVpn operIpvcVpn, List<Uni> uniToRemove,
161             WriteTransaction tx) {
162         if (uniToRemove == null) {
163             Log.trace("No UNI's to remove");
164         }
165         for (Uni uni : uniToRemove) {
166             Identifier45 uniId = uni.getUniId();
167             Identifier45 ipUniId = uni.getIpUniId();
168             IpUni ipUni = MefInterfaceUtils.getIpUni(dataBroker, uniId, ipUniId, LogicalDatastoreType.CONFIGURATION);
169             if (ipUni == null) {
170                 String errorMessage = String.format("Couldn't find ipuni %s for uni %s", ipUniId, uniId);
171                 Log.error(errorMessage);
172                 throw new UnsupportedOperationException(errorMessage);
173             }
174
175             removeDirectSubnet(uni, ipUni);
176             subnetManager.unAssignIpUniNetworks(uni.getUniId(), ipUni.getIpUniId(), ipvcId);
177             removeInterfaces(ipvcId, operIpvcVpn, uni, ipUni, tx);
178         }
179     }
180
181     private void updateIpvc(DataTreeModification<Ipvc> modifiedDataObject) {
182         try {
183             Ipvc origIpvc = modifiedDataObject.getRootNode().getDataBefore();
184             Ipvc updateIpvc = modifiedDataObject.getRootNode().getDataAfter();
185             InstanceIdentifier<Ipvc> ipvcId = modifiedDataObject.getRootPath().getRootIdentifier();
186             IpvcVpn operIpvcVpn = MefServicesUtils.getOperIpvcVpn(dataBroker, ipvcId);
187             if (operIpvcVpn == null) {
188                 Log.error("Ipvc {} hasn't been created as required", origIpvc.getIpvcId());
189                 return;
190             }
191             String vpnName = operIpvcVpn.getVpnId();
192
193             List<Uni> originalUni = origIpvc.getUnis() != null && origIpvc.getUnis().getUni() != null
194                     ? origIpvc.getUnis().getUni() : Collections.emptyList();
195             List<Uni> updateUni = updateIpvc.getUnis() != null && updateIpvc.getUnis().getUni() != null
196                     ? updateIpvc.getUnis().getUni() : Collections.emptyList();
197
198             synchronized (vpnName.intern()) {
199                 WriteTransaction txRemove = MdsalUtils.createTransaction(dataBroker);
200                 List<Uni> uniToRemove = new ArrayList<>(originalUni);
201                 uniToRemove.removeAll(updateUni);
202                 removeUni(ipvcId, operIpvcVpn, uniToRemove, txRemove);
203                 MdsalUtils.commitTransaction(txRemove);
204
205                 WriteTransaction tx = MdsalUtils.createTransaction(dataBroker);
206                 List<Uni> uniToCreate = new ArrayList<>(updateUni);
207                 uniToCreate.removeAll(originalUni);
208                 for (Uni uni : uniToCreate) {
209                     createInterfaces(vpnName, uni, ipvcId, tx);
210                 }
211                 MdsalUtils.commitTransaction(tx);
212
213                 for (Uni uni : uniToCreate) {
214                     IpUni ipUni = MefInterfaceUtils.getIpUni(dataBroker, uni.getUniId(), uni.getIpUniId(),
215                             LogicalDatastoreType.CONFIGURATION);
216                     createDirectSubnet(uni, ipUni);
217                     subnetManager.assignIpUniNetworks(uni.getUniId(), ipUni.getIpUniId(), ipvcId);
218                 }
219             }
220
221         } catch (final Exception e) {
222             Log.error("Update ipvc failed !", e);
223         }
224     }
225
226     private void createInterfaces(String vpnName, Uni uniInService, InstanceIdentifier<Ipvc> ipvcId,
227             WriteTransaction tx) {
228         String uniId = uniInService.getUniId().getValue();
229         String ipUniId = uniInService.getIpUniId().getValue();
230         org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.Uni uni = MefInterfaceUtils
231                 .getUni(dataBroker, uniId, LogicalDatastoreType.OPERATIONAL);
232         if (uni == null) {
233             String errorMessage = String.format("Couldn't find uni %s for ipvc", uniId);
234             Log.error(errorMessage);
235             throw new UnsupportedOperationException(errorMessage);
236         }
237         IpUni ipUni = MefInterfaceUtils.getIpUni(dataBroker, uniInService.getUniId(), uniInService.getIpUniId(),
238                 LogicalDatastoreType.CONFIGURATION);
239         if (ipUni == null) {
240             String errorMessage = String.format("Couldn't find ipuni %s for uni %s", ipUniId, uniId);
241             Log.error(errorMessage);
242             throw new UnsupportedOperationException(errorMessage);
243         }
244
245         Long vlan = ipUni.getVlan() != null ? Long.valueOf(ipUni.getVlan().getValue()) : null;
246         String elanName = NetvirtVpnUtils.getElanNameForVpnPort(uniId, ipUniId);
247
248         String srcIpAddressStr = NetvirtVpnUtils
249                 .getIpAddressFromPrefix(NetvirtVpnUtils.ipPrefixToString(ipUni.getIpAddress()));
250         IpAddress ipAddress = new IpAddress(srcIpAddressStr.toCharArray());
251
252         String interfaceName = createElanInterface(vpnName, ipvcId, uniId, elanName, vlan, ipAddress, tx);
253         createVpnInterface(vpnName, uni, ipUni, interfaceName, elanName, tx);
254         MefServicesUtils.addOperIpvcVpnElan(ipvcId, vpnName, uniInService.getUniId(), uniInService.getIpUniId(),
255                 elanName, interfaceName, null, tx);
256     }
257
258     private String createElanInterface(String vpnName, InstanceIdentifier<Ipvc> ipvcId, String uniId, String elanName,
259             Long vlan, IpAddress ipAddress, WriteTransaction tx) {
260         Log.info("Adding elan instance: " + elanName);
261         NetvirtUtils.updateElanInstance(elanName, tx);
262         NetvirtVpnUtils.registerDirectSubnetForVpn(dataBroker, new Uuid(elanName), ipAddress);
263
264         Log.info("Added trunk interface for uni {} vlan: {}", uniId, vlan);
265         if (vlan != null) {
266             uniPortManager.addCeVlan(uniId, vlan);
267         }
268         String interfaceName = uniPortManager.getUniVlanInterface(uniId, vlan);
269         if (interfaceName == null) {
270             String errorMessage = String.format("Couldn't create  uni %s vlan interface %s", uniId, vlan);
271             Log.error(errorMessage);
272             throw new UnsupportedOperationException(errorMessage);
273         }
274
275         Log.info("Adding elan interface: " + interfaceName);
276         NetvirtUtils.createElanInterface(elanName, interfaceName, EtreeInterfaceType.Root, false, tx);
277         return interfaceName;
278     }
279
280     private void createVpnInterface(String vpnName,
281             org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.Uni uni,
282             IpUni ipUni, String interfaceName, String elanName, WriteTransaction tx) {
283
284         Log.info("Adding vpn interface: " + interfaceName);
285         NetvirtVpnUtils.createUpdateVpnInterface(vpnName, interfaceName, ipUni.getIpAddress(),
286                 uni.getMacAddress().getValue(), true, null, elanName, tx);
287         NetvirtVpnUtils.createVpnPortFixedIp(vpnName, interfaceName, ipUni.getIpAddress(), uni.getMacAddress(), tx);
288         Log.info("Finished working on vpn instance: " + vpnName);
289     }
290
291     private void createDirectSubnet(Uni uni, IpUni ipUni) {
292         IpPrefix uniIpPrefix = ipUni.getIpAddress();
293         String subnetIp = NetvirtVpnUtils.getSubnetFromPrefix(uniIpPrefix);
294         IpPrefix subnetPrefix = new IpPrefix(new Ipv4Prefix(subnetIp));
295         InstanceIdentifier<Subnet> path = MefInterfaceUtils.getSubnetInstanceIdentifier(uni.getUniId(),
296                 ipUni.getIpUniId(), subnetPrefix);
297         SubnetBuilder subnet = new SubnetBuilder();
298         subnet.setUniId(uni.getUniId());
299         subnet.setIpUniId(ipUni.getIpUniId());
300         subnet.setSubnet(subnetPrefix);
301         MdsalUtils.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, path, subnet.build());
302     }
303
304     private void removeInterfaces(InstanceIdentifier<Ipvc> ipvcId, IpvcVpn ipvcVpn, Uni uniInService, IpUni ipUni,
305             WriteTransaction tx) {
306         String uniId = uniInService.getUniId().getValue();
307         org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.Uni uni = MefInterfaceUtils
308                 .getUni(dataBroker, uniId, LogicalDatastoreType.OPERATIONAL);
309         if (uni == null) {
310             String errorMessage = String.format("Couldn't find uni %s for ipvc", uniId);
311             Log.error(errorMessage);
312             throw new UnsupportedOperationException(errorMessage);
313         }
314
315         String vpnName = ipvcVpn.getVpnId();
316         VpnElans vpnElans = MefServicesUtils.findVpnElanForNetwork(new Identifier45(uniId), ipUni.getIpUniId(),
317                 ipvcVpn);
318         if (vpnElans == null) {
319             Log.error("Trying to remome non-operational vpn/elan for Uni {} Ip-UNi {}", uniId, ipUni.getIpUniId());
320         }
321
322         NetvirtVpnUtils.removeVpnInterfaceAdjacencies(dataBroker, vpnName, vpnElans.getElanPort());
323         // TODO : change to listener
324         NetvirtUtils.safeSleep();
325         removeElan(vpnElans, uniId, ipUni, tx);
326         removeVpnInterface(vpnName, vpnElans, uniId, ipUni, tx);
327         MefServicesUtils.removeOperIpvcElan(dataBroker, ipvcId, ipvcVpn.getVpnId(), uniInService.getUniId(),
328                 uniInService.getIpUniId(), vpnElans.getElanId(), vpnElans.getElanPort());
329     }
330
331     private void removeElan(VpnElans vpnElans, String uniId, IpUni ipUni, WriteTransaction tx) {
332         Long vlan = ipUni.getVlan() != null ? Long.valueOf(ipUni.getVlan().getValue()) : 0;
333         Log.info("Removing trunk interface for uni {} vlan: {}", uniId, vlan);
334         uniPortManager.removeCeVlan(uniId, vlan);
335
336         String elanName = vpnElans.getElanId();
337         String interfaceName = vpnElans.getElanPort();
338
339         Log.info("Removing elan instance {} and interface {}: ", elanName, interfaceName);
340         NetvirtVpnUtils.unregisterDirectSubnetForVpn(dataBroker, new Uuid(elanName));
341         NetvirtUtils.deleteElanInterface(interfaceName, tx);
342         NetvirtUtils.deleteElanInstance(elanName, tx);
343     }
344
345     private void removeVpnInterface(String vpnName, VpnElans vpnElans, String uniId, IpUni ipUni, WriteTransaction tx) {
346         String interfaceName = vpnElans.getElanPort();
347         Log.info("Removing vpn interface: " + interfaceName);
348         NetvirtVpnUtils.removeVpnInterface(interfaceName, tx);
349         NetvirtVpnUtils.removeVpnPortFixedIp(vpnName, ipUni.getIpAddress(), tx);
350         Log.info("Finished working on vpn instance: " + vpnName);
351     }
352
353     private void removeDirectSubnet(Uni uni, IpUni ipUni) {
354         IpPrefix uniIpPrefix = ipUni.getIpAddress();
355         String subnetIp = NetvirtVpnUtils.getSubnetFromPrefix(uniIpPrefix);
356         IpPrefix subnetPrefix = new IpPrefix(new Ipv4Prefix(subnetIp));
357         InstanceIdentifier<Subnet> path = MefInterfaceUtils.getSubnetInstanceIdentifier(uni.getUniId(),
358                 ipUni.getIpUniId(), subnetPrefix);
359         MdsalUtils.delete(dataBroker, LogicalDatastoreType.CONFIGURATION, path);
360     }
361 }