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.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
36 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;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.to.vpn.id.VpnInstance;
38 import org.opendaylight.yangtools.concepts.ListenerRegistration;
39 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
43 public class IpvcListener extends UnimgrDataTreeChangeListener<Ipvc> {
44 private static final Logger Log = LoggerFactory.getLogger(IpvcListener.class);
45 private final IUniPortManager uniPortManager;
46 private final ISubnetManager subnetManager;
47 private final UniQosManager uniQosManager;
48 private ListenerRegistration<IpvcListener> ipvcListenerRegistration;
50 public IpvcListener(final DataBroker dataBroker, final IUniPortManager uniPortManager,
51 final ISubnetManager subnetManager, final UniQosManager uniQosManager) {
53 this.uniPortManager = uniPortManager;
54 this.subnetManager = subnetManager;
55 this.uniQosManager = uniQosManager;
59 public void registerListener() {
61 final DataTreeIdentifier<Ipvc> dataTreeIid = new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
62 MefServicesUtils.getIpvcsInstanceIdentifier());
63 ipvcListenerRegistration = dataBroker.registerDataTreeChangeListener(dataTreeIid, this);
64 Log.info("IpvcDataTreeChangeListener created and registered");
65 } catch (final Exception e) {
66 Log.error("Ipvc DataChange listener registration failed !", e);
67 throw new IllegalStateException("Ipvc registration Listener failed.", e);
72 public void close() throws Exception {
73 ipvcListenerRegistration.close();
77 public void add(DataTreeModification<Ipvc> newDataObject) {
78 if (newDataObject.getRootPath() != null && newDataObject.getRootNode() != null) {
79 Log.info("ipvc {} created", newDataObject.getRootNode().getIdentifier());
80 addIpvc(newDataObject);
85 public void remove(DataTreeModification<Ipvc> removedDataObject) {
86 if (removedDataObject.getRootPath() != null && removedDataObject.getRootNode() != null) {
87 Log.info("ipvc {} deleted", removedDataObject.getRootNode().getIdentifier());
88 removeIpvc(removedDataObject);
93 public void update(DataTreeModification<Ipvc> modifiedDataObject) {
94 if (modifiedDataObject.getRootPath() != null && modifiedDataObject.getRootNode() != null) {
95 Log.info("ipvc {} updated", modifiedDataObject.getRootNode().getIdentifier());
96 updateIpvc(modifiedDataObject);
100 private void addIpvc(DataTreeModification<Ipvc> newDataObject) {
102 Ipvc ipvc = newDataObject.getRootNode().getDataAfter();
103 String instanceName = ipvc.getIpvcId().getValue();
104 final String vpnName = NetvirtVpnUtils.getUUidFromString(instanceName);
105 InstanceIdentifier<Ipvc> ipvcId = newDataObject.getRootPath().getRootIdentifier();
106 List<Uni> unis = new ArrayList<>();
108 synchronized (vpnName.intern()) {
109 WriteTransaction tx = MdsalUtils.createTransaction(dataBroker);
110 Log.info("Adding vpn instance: " + instanceName);
111 NetvirtVpnUtils.createVpnInstance(vpnName, tx);
112 MefServicesUtils.addOperIpvcVpnElan(ipvcId, vpnName, tx);
113 MdsalUtils.commitTransaction(tx);
115 InstanceIdentifier<VpnInstance> vpnId = NetvirtVpnUtils.getVpnInstanceToVpnIdIdentifier(vpnName);
116 DataWaitListener<VpnInstance> vpnInstanceWaiter = new DataWaitListener<>(dataBroker, vpnId, 10,
117 LogicalDatastoreType.CONFIGURATION, vpn -> vpn.getVrfId());
118 if (!vpnInstanceWaiter.waitForData()) {
119 String errorMessage = String.format("Fail to wait for vrfId for vpn %s", vpnName);
120 Log.error(errorMessage);
121 throw new UnsupportedOperationException(errorMessage);
123 rd = (String) vpnInstanceWaiter.getData();
126 if (ipvc.getUnis() != null && ipvc.getUnis() != null) {
127 unis = ipvc.getUnis().getUni();
129 Log.info("Number of UNI's: " + unis.size());
131 // Create elan/vpn interfaces
132 for (Uni uni : unis) {
133 createInterfaces(vpnName, uni, ipvcId, rd);
136 createUnis(ipvcId, unis);
137 } catch (final Exception e) {
138 Log.error("Add ipvc failed !", e);
142 private void removeIpvc(DataTreeModification<Ipvc> removedDataObject) {
144 Ipvc ipvc = removedDataObject.getRootNode().getDataBefore();
145 InstanceIdentifier<Ipvc> ipvcId = removedDataObject.getRootPath().getRootIdentifier();
146 IpvcVpn operIpvcVpn = MefServicesUtils.getOperIpvcVpn(dataBroker, ipvcId);
147 if (operIpvcVpn == null) {
148 Log.error("Ipvc {} hasn't been created as required", ipvc.getIpvcId());
151 String vpnName = operIpvcVpn.getVpnId();
153 synchronized (vpnName.intern()) {
154 // remove elan/vpn interfaces
155 // must be in different transactios
156 WriteTransaction tx = MdsalUtils.createTransaction(dataBroker);
157 removeUnis(ipvcId, operIpvcVpn, ipvc.getUnis().getUni(), tx);
158 MdsalUtils.commitTransaction(tx);
159 // Let to work for listeners
160 // TODO : change to listener
161 NetvirtUtils.safeSleep();
163 WriteTransaction txvpn = MdsalUtils.createTransaction(dataBroker);
164 NetvirtVpnUtils.removeVpnInstance(operIpvcVpn.getVpnId(), txvpn);
165 MefServicesUtils.removeOperIpvcVpn(ipvcId, txvpn);
166 MdsalUtils.commitTransaction(txvpn);
168 } catch (final Exception e) {
169 Log.error("Remove ipvc failed !", e);
173 private void removeUnis(InstanceIdentifier<Ipvc> ipvcId, IpvcVpn operIpvcVpn, List<Uni> uniToRemove,
174 WriteTransaction tx) {
175 if (uniToRemove == null) {
176 Log.trace("No UNI's to remove");
178 for (Uni uni : uniToRemove) {
179 Identifier45 uniId = uni.getUniId();
180 Identifier45 ipUniId = uni.getIpUniId();
181 IpUni ipUni = MefInterfaceUtils.getIpUni(dataBroker, uniId, ipUniId, LogicalDatastoreType.CONFIGURATION);
183 String errorMessage = String.format("Couldn't find ipuni %s for uni %s", ipUniId, uniId);
184 Log.error(errorMessage);
185 throw new UnsupportedOperationException(errorMessage);
188 removeDirectSubnet(uni, ipUni);
189 subnetManager.unAssignIpUniNetworks(uni.getUniId(), ipUni.getIpUniId(), ipvcId);
190 removeInterfaces(ipvcId, operIpvcVpn, uni, ipUni, tx);
192 updateQos(uniToRemove);
195 private void createUnis(InstanceIdentifier<Ipvc> ipvcId, List<Uni> uniToCreate) {
196 for (Uni uni : uniToCreate) {
197 IpUni ipUni = MefInterfaceUtils.getIpUni(dataBroker, uni.getUniId(), uni.getIpUniId(),
198 LogicalDatastoreType.CONFIGURATION);
199 createDirectSubnet(uni, ipUni);
200 subnetManager.assignIpUniNetworks(uni.getUniId(), ipUni.getIpUniId(), ipvcId);
202 updateQos(uniToCreate);
205 private void updateIpvc(DataTreeModification<Ipvc> modifiedDataObject) {
207 Ipvc origIpvc = modifiedDataObject.getRootNode().getDataBefore();
208 Ipvc updateIpvc = modifiedDataObject.getRootNode().getDataAfter();
209 InstanceIdentifier<Ipvc> ipvcId = modifiedDataObject.getRootPath().getRootIdentifier();
210 IpvcVpn operIpvcVpn = MefServicesUtils.getOperIpvcVpn(dataBroker, ipvcId);
211 if (operIpvcVpn == null) {
212 Log.error("Ipvc {} hasn't been created as required", origIpvc.getIpvcId());
215 String vpnName = operIpvcVpn.getVpnId();
216 InstanceIdentifier<VpnInstance> vpnId = NetvirtVpnUtils.getVpnInstanceToVpnIdIdentifier(vpnName);
217 @SuppressWarnings("resource")
218 DataWaitListener<VpnInstance> vpnInstanceWaiter = new DataWaitListener<>(dataBroker, vpnId, 10,
219 LogicalDatastoreType.CONFIGURATION, vpn -> vpn.getVrfId());
220 if (!vpnInstanceWaiter.waitForData()) {
221 String errorMessage = String.format("Fail to wait for vrfId for vpn %s", vpnName);
222 Log.error(errorMessage);
223 throw new UnsupportedOperationException(errorMessage);
225 String rd = (String) vpnInstanceWaiter.getData();
227 List<Uni> originalUni = origIpvc.getUnis() != null && origIpvc.getUnis().getUni() != null
228 ? origIpvc.getUnis().getUni() : Collections.emptyList();
229 List<Uni> updateUni = updateIpvc.getUnis() != null && updateIpvc.getUnis().getUni() != null
230 ? updateIpvc.getUnis().getUni() : Collections.emptyList();
232 synchronized (vpnName.intern()) {
233 WriteTransaction txRemove = MdsalUtils.createTransaction(dataBroker);
234 List<Uni> uniToRemove = new ArrayList<>(originalUni);
235 uniToRemove.removeAll(updateUni);
236 removeUnis(ipvcId, operIpvcVpn, uniToRemove, txRemove);
237 MdsalUtils.commitTransaction(txRemove);
239 List<Uni> uniToCreate = new ArrayList<>(updateUni);
240 uniToCreate.removeAll(originalUni);
242 for (Uni uni : uniToCreate) {
243 createInterfaces(vpnName, uni, ipvcId, rd);
245 createUnis(ipvcId, uniToCreate);
247 } catch (final Exception e) {
248 Log.error("Update ipvc failed !", e);
252 private void createInterfaces(String vpnName, Uni uniInService, InstanceIdentifier<Ipvc> ipvcId, String rd) {
254 WriteTransaction tx = MdsalUtils.createTransaction(dataBroker);
255 String uniId = uniInService.getUniId().getValue();
256 String ipUniId = uniInService.getIpUniId().getValue();
257 org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.Uni uni = MefInterfaceUtils
258 .getUni(dataBroker, uniId, LogicalDatastoreType.OPERATIONAL);
260 String errorMessage = String.format("Couldn't find uni %s for ipvc", uniId);
261 Log.error(errorMessage);
262 throw new UnsupportedOperationException(errorMessage);
264 IpUni ipUni = MefInterfaceUtils.getIpUni(dataBroker, uniInService.getUniId(), uniInService.getIpUniId(),
265 LogicalDatastoreType.CONFIGURATION);
267 String errorMessage = String.format("Couldn't find ipuni %s for uni %s", ipUniId, uniId);
268 Log.error(errorMessage);
269 throw new UnsupportedOperationException(errorMessage);
272 String interfaceName = null;
273 synchronized (vpnName.intern()) {
274 Long vlan = ipUni.getVlan() != null ? Long.valueOf(ipUni.getVlan().getValue()) : null;
275 String elanName = NetvirtVpnUtils.getElanNameForVpnPort(uniId, ipUniId);
277 String srcIpAddressStr = NetvirtVpnUtils
278 .getIpAddressFromPrefix(NetvirtVpnUtils.ipPrefixToString(ipUni.getIpAddress()));
279 IpAddress ipAddress = new IpAddress(srcIpAddressStr.toCharArray());
281 interfaceName = createElanInterface(vpnName, ipvcId, uniId, elanName, vlan, ipAddress, tx,
282 ipUni.getSegmentationId());
283 uniQosManager.mapUniPortBandwidthLimits(uniId, interfaceName, uniInService.getIngressBwProfile());
284 createVpnInterface(vpnName, uni, ipUni, interfaceName, elanName, tx);
285 MefServicesUtils.addOperIpvcVpnElan(ipvcId, vpnName, uniInService.getUniId(), uniInService.getIpUniId(),
286 elanName, interfaceName, null, tx);
287 MdsalUtils.commitTransaction(tx);
290 waitForInterfaceDpn(vpnName, rd, interfaceName);
292 NetvirtVpnUtils.createVpnPortFixedIp(dataBroker, vpnName, interfaceName, ipUni.getIpAddress(),
293 uni.getMacAddress());
296 private void waitForInterfaceDpn(String vpnName, String rd, String interfaceName) {
297 InstanceIdentifier<VpnInstanceOpDataEntry> vpnId = NetvirtVpnUtils.getVpnInstanceOpDataIdentifier(rd);
298 DataWaitGetter<VpnInstanceOpDataEntry> getInterfByName = (vpn) -> {
299 if (vpn.getVpnToDpnList() == null)
301 for (VpnToDpnList is : vpn.getVpnToDpnList()) {
302 if (is.getVpnInterfaces() == null)
304 for (VpnInterfaces i : is.getVpnInterfaces()) {
305 if (i.getInterfaceName().equals(interfaceName))
306 return interfaceName;
311 @SuppressWarnings("resource")
312 DataWaitListener<VpnInstanceOpDataEntry> vpnInstanceWaiter = new DataWaitListener<>(dataBroker, vpnId, 10,
313 LogicalDatastoreType.OPERATIONAL, getInterfByName);
314 if (!vpnInstanceWaiter.waitForData()) {
315 String errorMessage = String.format("Fail to wait for vpn to dpn list %s", vpnName);
316 Log.error(errorMessage);
317 throw new UnsupportedOperationException(errorMessage);
321 private String createElanInterface(String vpnName, InstanceIdentifier<Ipvc> ipvcId, String uniId, String elanName,
322 Long vlan, IpAddress ipAddress, WriteTransaction tx, Long segmentationId) {
323 Log.info("Adding elan instance: " + elanName);
324 NetvirtUtils.updateElanInstance(elanName, tx, segmentationId);
325 NetvirtVpnUtils.registerDirectSubnetForVpn(dataBroker, new Uuid(elanName), ipAddress);
327 Log.info("Added trunk interface for uni {} vlan: {}", uniId, vlan);
329 uniPortManager.addCeVlan(uniId, vlan);
331 String interfaceName = uniPortManager.getUniVlanInterface(uniId, vlan);
332 if (interfaceName == null) {
333 String errorMessage = String.format("Couldn't create uni %s vlan interface %s", uniId, vlan);
334 Log.error(errorMessage);
335 throw new UnsupportedOperationException(errorMessage);
338 Log.info("Adding elan interface: " + interfaceName);
339 NetvirtUtils.createElanInterface(elanName, interfaceName, EtreeInterfaceType.Root, false, tx);
340 return interfaceName;
343 private void createVpnInterface(String vpnName,
344 org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.Uni uni,
345 IpUni ipUni, String interfaceName, String elanName, WriteTransaction tx) {
347 Log.info("Adding vpn interface: " + interfaceName);
349 NetvirtVpnUtils.createUpdateVpnInterface(vpnName, interfaceName, ipUni.getIpAddress(),
350 uni.getMacAddress().getValue(), true, null, elanName, tx);
352 Log.info("Finished working on vpn instance {} interface () ", vpnName, interfaceName);
355 private void createDirectSubnet(Uni uni, IpUni ipUni) {
356 IpPrefix uniIpPrefix = ipUni.getIpAddress();
357 String subnetIp = NetvirtVpnUtils.getSubnetFromPrefix(uniIpPrefix);
358 IpPrefix subnetPrefix = new IpPrefix(new Ipv4Prefix(subnetIp));
359 InstanceIdentifier<Subnet> path = MefInterfaceUtils.getSubnetInstanceIdentifier(uni.getUniId(),
360 ipUni.getIpUniId(), subnetPrefix);
361 SubnetBuilder subnet = new SubnetBuilder();
362 subnet.setUniId(uni.getUniId());
363 subnet.setIpUniId(ipUni.getIpUniId());
364 subnet.setSubnet(subnetPrefix);
365 MdsalUtils.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, path, subnet.build());
368 private void removeInterfaces(InstanceIdentifier<Ipvc> ipvcId, IpvcVpn ipvcVpn, Uni uniInService, IpUni ipUni,
369 WriteTransaction tx) {
370 String uniId = uniInService.getUniId().getValue();
371 org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.Uni uni = MefInterfaceUtils
372 .getUni(dataBroker, uniId, LogicalDatastoreType.OPERATIONAL);
374 String errorMessage = String.format("Couldn't find uni %s for ipvc", uniId);
375 Log.error(errorMessage);
376 throw new UnsupportedOperationException(errorMessage);
379 String vpnName = ipvcVpn.getVpnId();
380 VpnElans vpnElans = MefServicesUtils.findVpnElanForNetwork(new Identifier45(uniId), ipUni.getIpUniId(),
382 if (vpnElans == null) {
383 Log.error("Trying to remome non-operational vpn/elan for Uni {} Ip-UNi {}", uniId, ipUni.getIpUniId());
386 NetvirtVpnUtils.removeVpnInterfaceAdjacencies(dataBroker, vpnName, vpnElans.getElanPort());
387 // TODO : change to listener
388 NetvirtUtils.safeSleep();
389 uniQosManager.unMapUniPortBandwidthLimits(uniId, vpnElans.getElanPort());
390 removeElan(vpnElans, uniId, ipUni, tx);
391 // record Uni bw limits
392 removeVpnInterface(vpnName, vpnElans, uniId, ipUni, tx);
393 MefServicesUtils.removeOperIpvcElan(dataBroker, ipvcId, ipvcVpn.getVpnId(), uniInService.getUniId(),
394 uniInService.getIpUniId(), vpnElans.getElanId(), vpnElans.getElanPort());
397 private void removeElan(VpnElans vpnElans, String uniId, IpUni ipUni, WriteTransaction tx) {
398 Long vlan = ipUni.getVlan() != null ? Long.valueOf(ipUni.getVlan().getValue()) : 0;
399 Log.info("Removing trunk interface for uni {} vlan: {}", uniId, vlan);
400 uniPortManager.removeCeVlan(uniId, vlan);
402 String elanName = vpnElans.getElanId();
403 String interfaceName = vpnElans.getElanPort();
405 Log.info("Removing elan instance {} and interface {}: ", elanName, interfaceName);
406 NetvirtVpnUtils.unregisterDirectSubnetForVpn(dataBroker, new Uuid(elanName));
407 NetvirtUtils.deleteElanInterface(interfaceName, tx);
408 NetvirtUtils.deleteElanInstance(elanName, tx);
411 private void removeVpnInterface(String vpnName, VpnElans vpnElans, String uniId, IpUni ipUni, WriteTransaction tx) {
412 String interfaceName = vpnElans.getElanPort();
413 Log.info("Removing vpn interface: " + interfaceName);
414 NetvirtVpnUtils.removeVpnInterface(interfaceName, tx);
415 NetvirtVpnUtils.removeVpnPortFixedIp(vpnName, ipUni.getIpAddress(), tx);
416 Log.info("Finished working on vpn instance: " + vpnName);
419 private void removeDirectSubnet(Uni uni, IpUni ipUni) {
420 IpPrefix uniIpPrefix = ipUni.getIpAddress();
421 String subnetIp = NetvirtVpnUtils.getSubnetFromPrefix(uniIpPrefix);
422 IpPrefix subnetPrefix = new IpPrefix(new Ipv4Prefix(subnetIp));
423 InstanceIdentifier<Subnet> path = MefInterfaceUtils.getSubnetInstanceIdentifier(uni.getUniId(),
424 ipUni.getIpUniId(), subnetPrefix);
425 MdsalUtils.delete(dataBroker, LogicalDatastoreType.CONFIGURATION, path);
428 private void updateQos(List<Uni> uniToUpdate) {
429 uniToUpdate.forEach(u -> uniQosManager.setUniBandwidthLimits(u.getUniId()));