2 * Copyright (c) 2016 Hewlett Packard Enterprise, Co. and others. All rights reserved.
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
9 package org.opendaylight.unimgr.mef.netvirt;
11 import java.util.ArrayList;
12 import java.util.Collections;
13 import java.util.List;
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;
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;
45 public IpvcListener(final DataBroker dataBroker, final IUniPortManager uniPortManager,
46 final ISubnetManager subnetManager) {
48 this.uniPortManager = uniPortManager;
49 this.subnetManager = subnetManager;
54 public void registerListener() {
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);
67 public void close() throws Exception {
68 ipvcListenerRegistration.close();
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);
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);
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);
95 private void addIpvc(DataTreeModification<Ipvc> newDataObject) {
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();
110 Log.info("Number of UNI's: " + unis.size());
112 // Create elan/vpn interfaces
113 for (Uni uni : unis) {
114 createInterfaces(vpnName, uni, ipvcId, tx);
116 MdsalUtils.commitTransaction(tx);
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);
124 } catch (final Exception e) {
125 Log.error("Add ipvc failed !", e);
129 private void removeIpvc(DataTreeModification<Ipvc> removedDataObject) {
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());
138 String vpnName = operIpvcVpn.getVpnId();
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();
150 WriteTransaction txvpn = MdsalUtils.createTransaction(dataBroker);
151 NetvirtVpnUtils.removeVpnInstance(operIpvcVpn.getVpnId(), txvpn);
152 MefServicesUtils.removeOperIpvcVpn(ipvcId, txvpn);
153 MdsalUtils.commitTransaction(txvpn);
155 } catch (final Exception e) {
156 Log.error("Remove ipvc failed !", e);
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");
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);
170 String errorMessage = String.format("Couldn't find ipuni %s for uni %s", ipUniId, uniId);
171 Log.error(errorMessage);
172 throw new UnsupportedOperationException(errorMessage);
175 removeDirectSubnet(uni, ipUni);
176 subnetManager.unAssignIpUniNetworks(uni.getUniId(), ipUni.getIpUniId(), ipvcId);
177 removeInterfaces(ipvcId, operIpvcVpn, uni, ipUni, tx);
181 private void updateIpvc(DataTreeModification<Ipvc> modifiedDataObject) {
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());
191 String vpnName = operIpvcVpn.getVpnId();
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();
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);
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);
211 MdsalUtils.commitTransaction(tx);
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);
221 } catch (final Exception e) {
222 Log.error("Update ipvc failed !", e);
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);
233 String errorMessage = String.format("Couldn't find uni %s for ipvc", uniId);
234 Log.error(errorMessage);
235 throw new UnsupportedOperationException(errorMessage);
237 IpUni ipUni = MefInterfaceUtils.getIpUni(dataBroker, uniInService.getUniId(), uniInService.getIpUniId(),
238 LogicalDatastoreType.CONFIGURATION);
240 String errorMessage = String.format("Couldn't find ipuni %s for uni %s", ipUniId, uniId);
241 Log.error(errorMessage);
242 throw new UnsupportedOperationException(errorMessage);
245 Long vlan = ipUni.getVlan() != null ? Long.valueOf(ipUni.getVlan().getValue()) : null;
246 String elanName = NetvirtVpnUtils.getElanNameForVpnPort(uniId, ipUniId);
248 String srcIpAddressStr = NetvirtVpnUtils
249 .getIpAddressFromPrefix(NetvirtVpnUtils.ipPrefixToString(ipUni.getIpAddress()));
250 IpAddress ipAddress = new IpAddress(srcIpAddressStr.toCharArray());
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);
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);
264 Log.info("Added trunk interface for uni {} vlan: {}", uniId, vlan);
266 uniPortManager.addCeVlan(uniId, vlan);
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);
275 Log.info("Adding elan interface: " + interfaceName);
276 NetvirtUtils.createElanInterface(elanName, interfaceName, EtreeInterfaceType.Root, false, tx);
277 return interfaceName;
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) {
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);
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());
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);
310 String errorMessage = String.format("Couldn't find uni %s for ipvc", uniId);
311 Log.error(errorMessage);
312 throw new UnsupportedOperationException(errorMessage);
315 String vpnName = ipvcVpn.getVpnId();
316 VpnElans vpnElans = MefServicesUtils.findVpnElanForNetwork(new Identifier45(uniId), ipUni.getIpUniId(),
318 if (vpnElans == null) {
319 Log.error("Trying to remome non-operational vpn/elan for Uni {} Ip-UNi {}", uniId, ipUni.getIpUniId());
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());
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);
336 String elanName = vpnElans.getElanId();
337 String interfaceName = vpnElans.getElanPort();
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);
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);
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);