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 edu.umd.cs.findbugs.annotations.CheckReturnValue;
14 import java.util.ArrayList;
15 import java.util.List;
16 import java.util.Objects;
17 import java.util.concurrent.TimeUnit;
18 import javax.annotation.PostConstruct;
19 import javax.inject.Inject;
20 import javax.inject.Singleton;
21 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
22 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
23 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
24 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
25 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
26 import org.opendaylight.genius.mdsalutil.MDSALUtil;
27 import org.opendaylight.infrautils.utils.concurrent.NamedLocks;
28 import org.opendaylight.infrautils.utils.concurrent.NamedSimpleReentrantLock.AcquireResult;
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.yang.types.rev130715.Uuid;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.FloatingIpInfo;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPortsBuilder;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPortsKey;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.PortsBuilder;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.PortsKey;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMapBuilder;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMapKey;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.port.info.FloatingIpIdToPortMapping;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.port.info.FloatingIpIdToPortMappingBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.Floatingips;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.floatingips.attributes.floatingips.Floatingip;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
46 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
51 public class NeutronFloatingToFixedIpMappingChangeListener extends AsyncDataTreeChangeListenerBase<Floatingip,
52 NeutronFloatingToFixedIpMappingChangeListener> {
53 private static final Logger LOG = LoggerFactory.getLogger(NeutronFloatingToFixedIpMappingChangeListener.class);
54 private static final long LOCK_WAIT_TIME = 10L;
56 private final DataBroker dataBroker;
57 private final NamedLocks<String> routerLock = new NamedLocks<>();
60 public NeutronFloatingToFixedIpMappingChangeListener(final DataBroker dataBroker) {
61 super(Floatingip.class, NeutronFloatingToFixedIpMappingChangeListener.class);
62 this.dataBroker = dataBroker;
68 LOG.info("{} init", getClass().getSimpleName());
69 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
73 protected InstanceIdentifier<Floatingip> getWildCardPath() {
74 return InstanceIdentifier.create(Neutron.class).child(Floatingips.class).child(Floatingip.class);
78 protected NeutronFloatingToFixedIpMappingChangeListener getDataTreeChangeListener() {
79 return NeutronFloatingToFixedIpMappingChangeListener.this;
83 protected void add(InstanceIdentifier<Floatingip> identifier, Floatingip input) {
84 LOG.trace("Neutron Floating IP created: key: {}, value={}", identifier, input);
85 IpAddress fixedIp = input.getFixedIpAddress();
86 String floatingIp = input.getFloatingIpAddress().getIpv4Address().getValue();
87 if (fixedIp != null) {
88 addToFloatingIpInfo(input.getRouterId().getValue(), input.getFloatingNetworkId(), input.getPortId()
89 .getValue(), fixedIp.getIpv4Address().getValue(), floatingIp, input.getUuid());
94 protected void remove(InstanceIdentifier<Floatingip> identifier, Floatingip input) {
95 LOG.trace("Neutron Floating IP deleted : key: {}, value={}", identifier, input);
96 IpAddress fixedIp = input.getFixedIpAddress();
97 if (fixedIp != null) {
98 // update FloatingIpPortInfo to set isFloatingIpDeleted as true to enable deletion of FloatingIpPortInfo
99 // map once it is used for processing in the NAT removal path
100 updateFloatingIpPortInfo(input.getUuid(), input.getPortId());
101 clearFromFloatingIpInfo(input.getRouterId().getValue(), input.getPortId().getValue(), fixedIp
102 .getIpv4Address().getValue());
104 // delete FloatingIpPortInfo mapping since floating IP is deleted and no fixed IP is associated to it
105 removeFromFloatingIpPortInfo(input.getUuid());
109 // populate the floating to fixed ip map upon association/dissociation from fixed ip
111 protected void update(InstanceIdentifier<Floatingip> identifier, Floatingip original, Floatingip update) {
112 LOG.trace("Handling FloatingIptoFixedIp mapping : key: {}, original value={}, update value={}", identifier,
114 IpAddress oldFixedIp = original.getFixedIpAddress();
115 IpAddress newFixedIp = update.getFixedIpAddress();
116 String floatingIp = update.getFloatingIpAddress().getIpv4Address().getValue();
118 if (oldFixedIp != null && !oldFixedIp.equals(newFixedIp)) {
119 clearFromFloatingIpInfo(original.getRouterId().getValue(), original.getPortId().getValue(), oldFixedIp
120 .getIpv4Address().getValue());
122 if (newFixedIp != null && !newFixedIp.equals(oldFixedIp)) {
123 addToFloatingIpInfo(update.getRouterId().getValue(), update.getFloatingNetworkId(), update.getPortId()
124 .getValue(), newFixedIp.getIpv4Address().getValue(), floatingIp, update.getUuid());
128 // TODO Clean up the exception handling
129 @SuppressWarnings("checkstyle:IllegalCatch")
130 private void addToFloatingIpInfo(String routerName, Uuid extNetworkId, String fixedNeutronPortName, String
131 fixedIpAddress, String floatingIpAddress, Uuid floatingIpId) {
132 RouterPortsBuilder routerPortsBuilder;
133 InstanceIdentifier<RouterPorts> routerPortsIdentifier = InstanceIdentifier.builder(FloatingIpInfo.class)
134 .child(RouterPorts.class, new RouterPortsKey(routerName)).build();
136 Optional<RouterPorts> optionalRouterPorts =
137 SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
138 routerPortsIdentifier);
139 if (optionalRouterPorts.isPresent()) {
140 LOG.debug("Updating routerPorts node {} in floatingIpInfo DS for floating IP {} on fixed "
141 + "neutron port {} : ", routerName, floatingIpAddress, fixedNeutronPortName);
142 routerPortsBuilder = new RouterPortsBuilder(optionalRouterPorts.get());
144 LOG.debug("Creating new routerPorts node {} in floatingIpInfo DS for floating IP {} on fixed "
145 + "neutron port {} : ", routerName, floatingIpAddress, fixedNeutronPortName);
147 new RouterPortsBuilder().withKey(new RouterPortsKey(routerName)).setRouterId(routerName);
149 if (extNetworkId != null) {
150 routerPortsBuilder.setExternalNetworkId(extNetworkId);
152 if (fixedNeutronPortName != null) {
153 List<Ports> portsList = routerPortsBuilder.getPorts();
154 if (portsList == null) {
155 portsList = new ArrayList<>();
157 PortsBuilder fixedNeutronPortBuilder = null;
158 for (Ports neutronPort : portsList) {
159 if (neutronPort.getPortName().equals(fixedNeutronPortName)) {
160 fixedNeutronPortBuilder = new PortsBuilder(neutronPort);
164 if (fixedNeutronPortBuilder == null) {
165 fixedNeutronPortBuilder = new PortsBuilder().withKey(new PortsKey(fixedNeutronPortName))
166 .setPortName(fixedNeutronPortName);
168 if (fixedIpAddress != null) {
169 List<InternalToExternalPortMap> intExtPortMapList = fixedNeutronPortBuilder
170 .getInternalToExternalPortMap();
171 if (intExtPortMapList == null) {
172 intExtPortMapList = new ArrayList<>();
174 InternalToExternalPortMap intExtPortMap = new InternalToExternalPortMapBuilder().withKey(new
175 InternalToExternalPortMapKey(fixedIpAddress)).setInternalIp(fixedIpAddress)
176 .setExternalIp(floatingIpAddress).setExternalId(floatingIpId).setLabel(null).build();
177 intExtPortMapList.add(intExtPortMap);
178 fixedNeutronPortBuilder.setInternalToExternalPortMap(intExtPortMapList);
180 portsList.add(fixedNeutronPortBuilder.build());
181 routerPortsBuilder.setPorts(portsList);
184 try (AcquireResult lock = tryRouterLock(routerName)) {
185 if (!lock.wasAcquired()) {
186 // FIXME: why do we even bother with locking if we do not honor it?!
187 logTryLockFailure(routerName);
190 LOG.debug("Creating/Updating routerPorts node {} in floatingIpInfo DS for floating IP {} on fixed "
191 + "neutron port {} : ", routerName, floatingIpAddress, fixedNeutronPortName);
192 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, routerPortsIdentifier,
193 routerPortsBuilder.build());
194 LOG.debug("FloatingIpInfo DS updated for floating IP {} ", floatingIpAddress);
196 } catch (ReadFailedException | RuntimeException e) {
197 LOG.error("addToFloatingIpInfo failed for floating IP: {} ", floatingIpAddress, e);
201 // TODO Clean up the exception handling
202 @SuppressWarnings("checkstyle:IllegalCatch")
203 private void clearFromFloatingIpInfo(String routerName, String fixedNeutronPortName, String fixedIpAddress) {
204 InstanceIdentifier.InstanceIdentifierBuilder<RouterPorts> routerPortsIdentifierBuilder = InstanceIdentifier
205 .builder(FloatingIpInfo.class).child(RouterPorts.class, new RouterPortsKey(routerName));
207 Optional<RouterPorts> optionalRouterPorts =
208 SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
209 routerPortsIdentifierBuilder.build());
210 if (optionalRouterPorts.isPresent()) {
211 RouterPorts routerPorts = optionalRouterPorts.get();
212 List<Ports> portsList = routerPorts.nonnullPorts();
213 List<InternalToExternalPortMap> intExtPortMap = new ArrayList<>();
214 for (Ports ports : portsList) {
215 if (Objects.equals(ports.getPortName(), fixedNeutronPortName)) {
216 intExtPortMap = ports.nonnullInternalToExternalPortMap();
220 if (intExtPortMap.size() == 1) {
221 removeRouterPortsOrPortsNode(routerName, routerPortsIdentifierBuilder, portsList,
222 fixedNeutronPortName);
224 for (InternalToExternalPortMap intToExtMap : intExtPortMap) {
225 if (Objects.equals(intToExtMap.getInternalIp(), fixedIpAddress)) {
226 InstanceIdentifier<InternalToExternalPortMap> intExtPortMapIdentifier =
227 routerPortsIdentifierBuilder.child(Ports
228 .class, new PortsKey(fixedNeutronPortName)).child(InternalToExternalPortMap.class,
229 new InternalToExternalPortMapKey(fixedIpAddress)).build();
230 try (AcquireResult lock = tryRouterLock(fixedIpAddress)) {
231 if (!lock.wasAcquired()) {
232 // FIXME: why do we even bother with locking if we do not honor it?!
233 logTryLockFailure(fixedIpAddress);
236 // remove particular internal-to-external-port-map
237 LOG.debug("removing particular internal-to-external-port-map {}", intExtPortMap);
239 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION,
240 intExtPortMapIdentifier);
241 } catch (Exception e) {
242 LOG.error("Failure in deletion of internal-to-external-port-map {}", intExtPortMap,
249 LOG.debug("Deletion from FloatingIpInfo DS successful for fixedIp {} ", fixedIpAddress);
251 LOG.warn("routerPorts for router {} - fixedIp {} not found", routerName, fixedIpAddress);
253 } catch (RuntimeException | ReadFailedException e) {
254 LOG.error("Failed to delete internal-to-external-port-map from FloatingIpInfo DS for fixed Ip {}",
259 protected void dissociatefixedIPFromFloatingIP(String fixedNeutronPortName) {
260 InstanceIdentifier.InstanceIdentifierBuilder<FloatingIpInfo> floatingIpInfoIdentifierBuilder =
261 InstanceIdentifier.builder(FloatingIpInfo.class);
263 Optional<FloatingIpInfo> optionalFloatingIPInfo =
264 SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
265 floatingIpInfoIdentifierBuilder.build());
266 if (optionalFloatingIPInfo.isPresent()) {
267 List<RouterPorts> routerPortsList = optionalFloatingIPInfo.get().getRouterPorts();
268 if (routerPortsList != null && !routerPortsList.isEmpty()) {
269 for (RouterPorts routerPorts : routerPortsList) {
270 List<Ports> portsList = routerPorts.getPorts();
271 if (portsList != null && !portsList.isEmpty()) {
272 for (Ports ports : portsList) {
273 if (Objects.equals(ports.getPortName(), fixedNeutronPortName)) {
274 String routerName = routerPorts.getRouterId();
275 InstanceIdentifier.InstanceIdentifierBuilder<RouterPorts>
276 routerPortsIdentifierBuilder = floatingIpInfoIdentifierBuilder
277 .child(RouterPorts.class, new RouterPortsKey(routerName));
278 removeRouterPortsOrPortsNode(routerName, routerPortsIdentifierBuilder, portsList,
279 fixedNeutronPortName);
280 LOG.debug("Deletion from FloatingIpInfo DS successful for fixedIP neutron port {} ",
281 fixedNeutronPortName);
288 LOG.debug("No router present containing fixed to floating IP association(s)");
291 LOG.debug("FloatingIPInfo DS empty. Hence, no router present containing fixed to floating IP "
294 } catch (ReadFailedException e) {
295 LOG.error("Failed to dissociate fixedIP from FloatingIpInfo DS for neutron port {}",
296 fixedNeutronPortName, e);
300 private void removeRouterPortsOrPortsNode(String routerName,
301 InstanceIdentifier.InstanceIdentifierBuilder<RouterPorts> routerPortsIdentifierBuilder,
302 List<Ports> portsList, String fixedNeutronPortName) {
303 if (portsList.size() == 1) {
304 // remove entire routerPorts node
305 try (AcquireResult lock = tryRouterLock(routerName)) {
306 if (!lock.wasAcquired()) {
307 // FIXME: why do we even bother with locking if we do not honor it?!
308 logTryLockFailure(routerName);
311 LOG.debug("removing routerPorts node: {} ", routerName);
312 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, routerPortsIdentifierBuilder
316 // remove entire ports node under this routerPorts node
317 try (AcquireResult lock = tryRouterLock(fixedNeutronPortName)) {
318 if (!lock.wasAcquired()) {
319 // FIXME: why do we even bother with locking if we do not honor it?!
320 logTryLockFailure(fixedNeutronPortName);
323 LOG.debug("removing ports node {} under routerPorts node {}", fixedNeutronPortName, routerName);
324 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION,
325 routerPortsIdentifierBuilder.child(Ports.class, new PortsKey(fixedNeutronPortName)).build());
330 // TODO Clean up the exception handling
331 @SuppressWarnings("checkstyle:IllegalCatch")
332 // updates FloatingIPPortInfo to have isFloatingIPDeleted set to true on a floating IP delete
333 private void updateFloatingIpPortInfo(Uuid floatingIpId, Uuid floatingIpPortId) {
334 InstanceIdentifier<FloatingIpIdToPortMapping> id = buildfloatingIpIdToPortMappingIdentifier(floatingIpId);
336 FloatingIpIdToPortMappingBuilder floatingIpIdToPortMappingBuilder = new
337 FloatingIpIdToPortMappingBuilder().setFloatingIpId(floatingIpId).setFloatingIpDeleted(true);
338 LOG.debug("Updating floating IP UUID {} to Floating IP neutron port {} mapping in Floating IP"
339 + " Port Info Config DS to set isFloatingIpDeleted flag as true",
340 floatingIpId.getValue(), floatingIpPortId.getValue());
341 MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, id,
342 floatingIpIdToPortMappingBuilder.build());
343 } catch (Exception e) {
344 LOG.error("Updating floating IP UUID {} to Floating IP neutron port {} mapping in Floating IP"
345 + " Port Info Config DS to set isFloatingIpDeleted flag as true failed", floatingIpId.getValue(),
346 floatingIpPortId.getValue(), e);
350 // TODO Clean up the exception handling
351 @SuppressWarnings("checkstyle:IllegalCatch")
352 private void removeFromFloatingIpPortInfo(Uuid floatingIpId) {
353 InstanceIdentifier<FloatingIpIdToPortMapping> id = buildfloatingIpIdToPortMappingIdentifier(floatingIpId);
355 LOG.debug("Deleting floating IP UUID {} to Floating IP neutron port mapping from Floating "
356 + "IP Port Info Config DS", floatingIpId.getValue());
357 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
358 } catch (Exception e) {
359 LOG.error("Deleting floating IP UUID {} to Floating IP neutron port mapping from Floating "
360 + "IP Port Info Config DS failed", floatingIpId.getValue(), e);
365 private AcquireResult tryRouterLock(final String lockName) {
366 return routerLock.tryAcquire(lockName, LOCK_WAIT_TIME, TimeUnit.SECONDS);
369 private static void logTryLockFailure(String lockName) {
370 LOG.warn("Lock for {} was not acquired, continuing anyway", lockName, new Throwable());