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