2 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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
8 package org.opendaylight.netvirt.neutronvpn;
10 import static org.opendaylight.netvirt.neutronvpn.NeutronvpnUtils.buildfloatingIpIdToPortMappingIdentifier;
12 import com.google.common.base.Optional;
13 import java.util.ArrayList;
14 import java.util.List;
15 import java.util.Objects;
16 import java.util.concurrent.TimeUnit;
17 import javax.annotation.PostConstruct;
18 import javax.inject.Inject;
19 import javax.inject.Singleton;
20 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
23 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
24 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
25 import org.opendaylight.genius.mdsalutil.MDSALUtil;
26 import org.opendaylight.infrautils.utils.concurrent.KeyedLocks;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.FloatingIpInfo;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPortsBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPortsKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.PortsBuilder;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.PortsKey;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMapBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMapKey;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.port.info.FloatingIpIdToPortMapping;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.port.info.FloatingIpIdToPortMappingBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.Floatingips;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.floatingips.Floatingip;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
44 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
49 public class NeutronFloatingToFixedIpMappingChangeListener extends AsyncDataTreeChangeListenerBase<Floatingip,
50 NeutronFloatingToFixedIpMappingChangeListener> {
51 private static final Logger LOG = LoggerFactory.getLogger(NeutronFloatingToFixedIpMappingChangeListener.class);
52 private static long LOCK_WAIT_TIME = 10L;
54 private final DataBroker dataBroker;
55 private final KeyedLocks<String> routerLock = new KeyedLocks<>();
58 public NeutronFloatingToFixedIpMappingChangeListener(final DataBroker dataBroker) {
59 super(Floatingip.class, NeutronFloatingToFixedIpMappingChangeListener.class);
60 this.dataBroker = dataBroker;
66 LOG.info("{} init", getClass().getSimpleName());
67 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
71 protected InstanceIdentifier<Floatingip> getWildCardPath() {
72 return InstanceIdentifier.create(Neutron.class).child(Floatingips.class).child(Floatingip.class);
76 protected NeutronFloatingToFixedIpMappingChangeListener getDataTreeChangeListener() {
77 return NeutronFloatingToFixedIpMappingChangeListener.this;
81 protected void add(InstanceIdentifier<Floatingip> identifier, Floatingip input) {
82 LOG.trace("Neutron Floating IP created: key: {}, value={}", identifier, input);
83 IpAddress fixedIp = input.getFixedIpAddress();
84 String floatingIp = input.getFloatingIpAddress().getIpv4Address().getValue();
85 if (fixedIp != null) {
86 addToFloatingIpInfo(input.getRouterId().getValue(), input.getFloatingNetworkId(), input.getPortId()
87 .getValue(), fixedIp.getIpv4Address().getValue(), floatingIp, input.getUuid());
92 protected void remove(InstanceIdentifier<Floatingip> identifier, Floatingip input) {
93 LOG.trace("Neutron Floating IP deleted : key: {}, value={}", identifier, input);
94 IpAddress fixedIp = input.getFixedIpAddress();
95 if (fixedIp != null) {
96 // update FloatingIpPortInfo to set isFloatingIpDeleted as true to enable deletion of FloatingIpPortInfo
97 // map once it is used for processing in the NAT removal path
98 updateFloatingIpPortInfo(input.getUuid(), input.getPortId());
99 clearFromFloatingIpInfo(input.getRouterId().getValue(), input.getPortId().getValue(), fixedIp
100 .getIpv4Address().getValue());
102 // delete FloatingIpPortInfo mapping since floating IP is deleted and no fixed IP is associated to it
103 removeFromFloatingIpPortInfo(input.getUuid());
107 // populate the floating to fixed ip map upon association/dissociation from fixed ip
109 protected void update(InstanceIdentifier<Floatingip> identifier, Floatingip original, Floatingip update) {
110 LOG.trace("Handling FloatingIptoFixedIp mapping : key: {}, original value={}, update value={}", identifier,
112 IpAddress oldFixedIp = original.getFixedIpAddress();
113 IpAddress newFixedIp = update.getFixedIpAddress();
114 String floatingIp = update.getFloatingIpAddress().getIpv4Address().getValue();
116 if (oldFixedIp != null && !oldFixedIp.equals(newFixedIp)) {
117 clearFromFloatingIpInfo(original.getRouterId().getValue(), original.getPortId().getValue(), oldFixedIp
118 .getIpv4Address().getValue());
120 if (newFixedIp != null && !newFixedIp.equals(oldFixedIp)) {
121 addToFloatingIpInfo(update.getRouterId().getValue(), update.getFloatingNetworkId(), update.getPortId()
122 .getValue(), newFixedIp.getIpv4Address().getValue(), floatingIp, update.getUuid());
126 // TODO Clean up the exception handling
127 @SuppressWarnings("checkstyle:IllegalCatch")
128 private void addToFloatingIpInfo(String routerName, Uuid extNetworkId, String fixedNeutronPortName, String
129 fixedIpAddress, String floatingIpAddress, Uuid floatingIpId) {
130 RouterPortsBuilder routerPortsBuilder;
131 boolean isLockAcquired = false;
132 InstanceIdentifier<RouterPorts> routerPortsIdentifier = InstanceIdentifier.builder(FloatingIpInfo.class)
133 .child(RouterPorts.class, new RouterPortsKey(routerName)).build();
135 Optional<RouterPorts> optionalRouterPorts =
136 SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
137 routerPortsIdentifier);
138 if (optionalRouterPorts.isPresent()) {
139 LOG.debug("Updating routerPorts node {} in floatingIpInfo DS for floating IP {} on fixed "
140 + "neutron port {} : ", routerName, floatingIpAddress, fixedNeutronPortName);
141 routerPortsBuilder = new RouterPortsBuilder(optionalRouterPorts.get());
143 LOG.debug("Creating new routerPorts node {} in floatingIpInfo DS for floating IP {} on fixed "
144 + "neutron port {} : ", routerName, floatingIpAddress, fixedNeutronPortName);
146 new RouterPortsBuilder().withKey(new RouterPortsKey(routerName)).setRouterId(routerName);
148 if (extNetworkId != null) {
149 routerPortsBuilder.setExternalNetworkId(extNetworkId);
151 if (fixedNeutronPortName != null) {
152 List<Ports> portsList = routerPortsBuilder.getPorts();
153 if (portsList == null) {
154 portsList = new ArrayList<>();
156 PortsBuilder fixedNeutronPortBuilder = null;
157 for (Ports neutronPort : portsList) {
158 if (neutronPort.getPortName().equals(fixedNeutronPortName)) {
159 fixedNeutronPortBuilder = new PortsBuilder(neutronPort);
163 if (fixedNeutronPortBuilder == null) {
164 fixedNeutronPortBuilder = new PortsBuilder().withKey(new PortsKey(fixedNeutronPortName))
165 .setPortName(fixedNeutronPortName);
167 if (fixedIpAddress != null) {
168 List<InternalToExternalPortMap> intExtPortMapList = fixedNeutronPortBuilder
169 .getInternalToExternalPortMap();
170 if (intExtPortMapList == null) {
171 intExtPortMapList = new ArrayList<>();
173 InternalToExternalPortMap intExtPortMap = new InternalToExternalPortMapBuilder().withKey(new
174 InternalToExternalPortMapKey(fixedIpAddress)).setInternalIp(fixedIpAddress)
175 .setExternalIp(floatingIpAddress).setExternalId(floatingIpId).setLabel(null).build();
176 intExtPortMapList.add(intExtPortMap);
177 fixedNeutronPortBuilder.setInternalToExternalPortMap(intExtPortMapList);
179 portsList.add(fixedNeutronPortBuilder.build());
180 routerPortsBuilder.setPorts(portsList);
182 isLockAcquired = routerLock.tryLock(routerName, LOCK_WAIT_TIME, TimeUnit.SECONDS);
183 LOG.debug("Creating/Updating routerPorts node {} in floatingIpInfo DS for floating IP {} on fixed "
184 + "neutron port {} : ", routerName, floatingIpAddress, fixedNeutronPortName);
185 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, routerPortsIdentifier,
186 routerPortsBuilder.build());
187 LOG.debug("FloatingIpInfo DS updated for floating IP {} ", floatingIpAddress);
188 } catch (ReadFailedException | RuntimeException e) {
189 LOG.error("addToFloatingIpInfo failed for floating IP: {} ", floatingIpAddress, e);
191 if (isLockAcquired) {
192 routerLock.unlock(routerName);
197 // TODO Clean up the exception handling
198 @SuppressWarnings("checkstyle:IllegalCatch")
199 private void clearFromFloatingIpInfo(String routerName, String fixedNeutronPortName, String fixedIpAddress) {
200 boolean isLockAcquired = false;
201 InstanceIdentifier.InstanceIdentifierBuilder<RouterPorts> routerPortsIdentifierBuilder = InstanceIdentifier
202 .builder(FloatingIpInfo.class).child(RouterPorts.class, new RouterPortsKey(routerName));
204 Optional<RouterPorts> optionalRouterPorts =
205 SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
206 routerPortsIdentifierBuilder.build());
207 if (optionalRouterPorts.isPresent()) {
208 RouterPorts routerPorts = optionalRouterPorts.get();
209 List<Ports> portsList = routerPorts.nonnullPorts();
210 List<InternalToExternalPortMap> intExtPortMap = new ArrayList<>();
211 for (Ports ports : portsList) {
212 if (Objects.equals(ports.getPortName(), fixedNeutronPortName)) {
213 intExtPortMap = ports.nonnullInternalToExternalPortMap();
217 if (intExtPortMap.size() == 1) {
218 removeRouterPortsOrPortsNode(routerName, routerPortsIdentifierBuilder, portsList,
219 fixedNeutronPortName, isLockAcquired);
221 for (InternalToExternalPortMap intToExtMap : intExtPortMap) {
222 if (Objects.equals(intToExtMap.getInternalIp(), fixedIpAddress)) {
223 InstanceIdentifier<InternalToExternalPortMap> intExtPortMapIdentifier =
224 routerPortsIdentifierBuilder.child(Ports
225 .class, new PortsKey(fixedNeutronPortName)).child(InternalToExternalPortMap.class,
226 new InternalToExternalPortMapKey(fixedIpAddress)).build();
228 // remove particular internal-to-external-port-map
229 isLockAcquired = routerLock.tryLock(fixedIpAddress, LOCK_WAIT_TIME, TimeUnit.SECONDS);
230 LOG.debug("removing particular internal-to-external-port-map {}", intExtPortMap);
231 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION,
232 intExtPortMapIdentifier);
233 } catch (Exception e) {
234 LOG.error("Failure in deletion of internal-to-external-port-map {}", intExtPortMap, e);
236 if (isLockAcquired) {
237 routerLock.unlock(fixedIpAddress);
243 LOG.debug("Deletion from FloatingIpInfo DS successful for fixedIp {} ", fixedIpAddress);
245 LOG.warn("routerPorts for router {} - fixedIp {} not found", routerName, fixedIpAddress);
247 } catch (RuntimeException | ReadFailedException e) {
248 LOG.error("Failed to delete internal-to-external-port-map from FloatingIpInfo DS for fixed Ip {}",
253 protected void dissociatefixedIPFromFloatingIP(String fixedNeutronPortName) {
254 boolean isLockAcquired = false;
255 InstanceIdentifier.InstanceIdentifierBuilder<FloatingIpInfo> floatingIpInfoIdentifierBuilder =
256 InstanceIdentifier.builder(FloatingIpInfo.class);
258 Optional<FloatingIpInfo> optionalFloatingIPInfo =
259 SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
260 floatingIpInfoIdentifierBuilder.build());
261 if (optionalFloatingIPInfo.isPresent()) {
262 List<RouterPorts> routerPortsList = optionalFloatingIPInfo.get().getRouterPorts();
263 if (routerPortsList != null && !routerPortsList.isEmpty()) {
264 for (RouterPorts routerPorts : routerPortsList) {
265 List<Ports> portsList = routerPorts.getPorts();
266 if (portsList != null && !portsList.isEmpty()) {
267 for (Ports ports : portsList) {
268 if (Objects.equals(ports.getPortName(), fixedNeutronPortName)) {
269 String routerName = routerPorts.getRouterId();
270 InstanceIdentifier.InstanceIdentifierBuilder<RouterPorts>
271 routerPortsIdentifierBuilder = floatingIpInfoIdentifierBuilder
272 .child(RouterPorts.class, new RouterPortsKey(routerName));
273 removeRouterPortsOrPortsNode(routerName, routerPortsIdentifierBuilder, portsList,
274 fixedNeutronPortName, isLockAcquired);
275 LOG.debug("Deletion from FloatingIpInfo DS successful for fixedIP neutron port {} ",
276 fixedNeutronPortName);
283 LOG.debug("No router present containing fixed to floating IP association(s)");
286 LOG.debug("FloatingIPInfo DS empty. Hence, no router present containing fixed to floating IP "
289 } catch (ReadFailedException e) {
290 LOG.error("Failed to dissociate fixedIP from FloatingIpInfo DS for neutron port {}",
291 fixedNeutronPortName, e);
295 // TODO Clean up the exception handling
296 @SuppressWarnings("checkstyle:IllegalCatch")
297 private void removeRouterPortsOrPortsNode(String routerName, InstanceIdentifier
298 .InstanceIdentifierBuilder<RouterPorts> routerPortsIdentifierBuilder, List<Ports> portsList,
299 String fixedNeutronPortName, boolean isLockAcquired) {
300 String lockName = null;
302 if (portsList.size() == 1) {
303 // remove entire routerPorts node
304 lockName = routerName;
305 isLockAcquired = routerLock.tryLock(lockName, LOCK_WAIT_TIME, TimeUnit.SECONDS);
306 LOG.debug("removing routerPorts node: {} ", routerName);
307 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, routerPortsIdentifierBuilder
310 // remove entire ports node under this routerPorts node
311 lockName = fixedNeutronPortName;
312 isLockAcquired = routerLock.tryLock(lockName, LOCK_WAIT_TIME, TimeUnit.SECONDS);
313 LOG.debug("removing ports node {} under routerPorts node {}", fixedNeutronPortName, routerName);
314 InstanceIdentifier.InstanceIdentifierBuilder<Ports> portsIdentifierBuilder =
315 routerPortsIdentifierBuilder.child(Ports.class, new PortsKey(fixedNeutronPortName));
316 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, portsIdentifierBuilder.build());
318 } catch (Exception e) {
319 LOG.error("Failure in deletion of routerPorts node {}", routerName, e);
321 if (isLockAcquired) {
322 routerLock.unlock(lockName);
327 // TODO Clean up the exception handling
328 @SuppressWarnings("checkstyle:IllegalCatch")
329 // updates FloatingIPPortInfo to have isFloatingIPDeleted set to true on a floating IP delete
330 private void updateFloatingIpPortInfo(Uuid floatingIpId, Uuid floatingIpPortId) {
331 InstanceIdentifier<FloatingIpIdToPortMapping> id = buildfloatingIpIdToPortMappingIdentifier(floatingIpId);
333 FloatingIpIdToPortMappingBuilder floatingIpIdToPortMappingBuilder = new
334 FloatingIpIdToPortMappingBuilder().setFloatingIpId(floatingIpId).setFloatingIpDeleted(true);
335 LOG.debug("Updating floating IP UUID {} to Floating IP neutron port {} mapping in Floating IP"
336 + " Port Info Config DS to set isFloatingIpDeleted flag as true",
337 floatingIpId.getValue(), floatingIpPortId.getValue());
338 MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, id,
339 floatingIpIdToPortMappingBuilder.build());
340 } catch (Exception e) {
341 LOG.error("Updating floating IP UUID {} to Floating IP neutron port {} mapping in Floating IP"
342 + " Port Info Config DS to set isFloatingIpDeleted flag as true failed", floatingIpId.getValue(),
343 floatingIpPortId.getValue(), e);
347 // TODO Clean up the exception handling
348 @SuppressWarnings("checkstyle:IllegalCatch")
349 private void removeFromFloatingIpPortInfo(Uuid floatingIpId) {
350 InstanceIdentifier<FloatingIpIdToPortMapping> id = buildfloatingIpIdToPortMappingIdentifier(floatingIpId);
352 LOG.debug("Deleting floating IP UUID {} to Floating IP neutron port mapping from Floating "
353 + "IP Port Info Config DS", floatingIpId.getValue());
354 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
355 } catch (Exception e) {
356 LOG.error("Deleting floating IP UUID {} to Floating IP neutron port mapping from Floating "
357 + "IP Port Info Config DS failed", floatingIpId.getValue(), e);