2 * Copyright © 2015, 2018 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.genius.infra.Datastore.CONFIGURATION;
12 import com.google.common.base.Optional;
13 import com.google.common.base.Strings;
14 import com.google.gson.Gson;
15 import com.google.gson.JsonArray;
16 import com.google.gson.JsonElement;
17 import com.google.gson.JsonObject;
18 import java.time.Duration;
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.List;
24 import java.util.Locale;
27 import java.util.stream.Collectors;
28 import javax.annotation.PostConstruct;
29 import javax.inject.Singleton;
30 import org.apache.commons.lang3.ObjectUtils;
31 import org.eclipse.jdt.annotation.Nullable;
32 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
33 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
34 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
35 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
36 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
37 import org.opendaylight.genius.datastoreutils.listeners.DataTreeEventCallbackRegistrar;
38 import org.opendaylight.genius.infra.Datastore;
39 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
40 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
41 import org.opendaylight.genius.infra.TypedWriteTransaction;
42 import org.opendaylight.genius.mdsalutil.MDSALUtil;
43 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
44 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
45 import org.opendaylight.netvirt.elanmanager.api.IElanService;
46 import org.opendaylight.netvirt.neutronvpn.api.enums.IpVersionChoice;
47 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronConstants;
48 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
49 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev170119.L2vlan;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlan;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlanBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.InterfaceAcl;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.InterfaceAclBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.AllowedAddressPairs;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceKey;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntries;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.RoutersBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.port.info.FloatingIpIdToPortMappingBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.port.info.FloatingIpIdToPortMappingKey;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.PortBindingExtension;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.hostconfig.rev150712.hostconfig.attributes.hostconfigs.Hostconfig;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
76 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
77 import org.slf4j.Logger;
78 import org.slf4j.LoggerFactory;
81 public class NeutronPortChangeListener extends AsyncDataTreeChangeListenerBase<Port, NeutronPortChangeListener> {
82 private static final Logger LOG = LoggerFactory.getLogger(NeutronPortChangeListener.class);
83 private final DataBroker dataBroker;
84 private final ManagedNewTransactionRunner txRunner;
85 private final NeutronvpnManager nvpnManager;
86 private final NeutronvpnNatManager nvpnNatManager;
87 private final NeutronSubnetGwMacResolver gwMacResolver;
88 private final IElanService elanService;
89 private final JobCoordinator jobCoordinator;
90 private final NeutronvpnUtils neutronvpnUtils;
91 private final HostConfigCache hostConfigCache;
92 private final DataTreeEventCallbackRegistrar eventCallbacks;
94 public NeutronPortChangeListener(final DataBroker dataBroker,
95 final NeutronvpnManager neutronvpnManager,
96 final NeutronvpnNatManager neutronvpnNatManager,
97 final NeutronSubnetGwMacResolver gwMacResolver,
98 final IElanService elanService,
99 final JobCoordinator jobCoordinator,
100 final NeutronvpnUtils neutronvpnUtils,
101 final HostConfigCache hostConfigCache,
102 final DataTreeEventCallbackRegistrar dataTreeEventCallbackRegistrar) {
103 super(Port.class, NeutronPortChangeListener.class);
104 this.dataBroker = dataBroker;
105 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
106 nvpnManager = neutronvpnManager;
107 nvpnNatManager = neutronvpnNatManager;
108 this.gwMacResolver = gwMacResolver;
109 this.elanService = elanService;
110 this.jobCoordinator = jobCoordinator;
111 this.neutronvpnUtils = neutronvpnUtils;
112 this.hostConfigCache = hostConfigCache;
113 this.eventCallbacks = dataTreeEventCallbackRegistrar;
119 LOG.info("{} init", getClass().getSimpleName());
120 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
124 protected InstanceIdentifier<Port> getWildCardPath() {
125 return InstanceIdentifier.create(Neutron.class).child(Ports.class).child(Port.class);
129 protected NeutronPortChangeListener getDataTreeChangeListener() {
130 return NeutronPortChangeListener.this;
135 protected void add(InstanceIdentifier<Port> identifier, Port input) {
136 LOG.trace("Received port add event: port={}", input);
137 String portName = input.getUuid().getValue();
138 LOG.trace("Adding Port : key: {}, value={}", identifier, input);
139 Network network = neutronvpnUtils.getNeutronNetwork(input.getNetworkId());
140 if (network == null || !NeutronvpnUtils.isNetworkTypeSupported(network)) {
141 LOG.warn("neutron vpn received a port add() for a network without a provider extension augmentation "
142 + "or with an unsupported network type for the port {} which is part of network {}",
147 neutronvpnUtils.addToPortCache(input);
148 String portStatus = NeutronUtils.PORT_STATUS_DOWN;
149 if (!Strings.isNullOrEmpty(input.getDeviceOwner()) && !Strings.isNullOrEmpty(input.getDeviceId())) {
150 if (NeutronConstants.DEVICE_OWNER_ROUTER_INF.equals(input.getDeviceOwner())) {
151 handleRouterInterfaceAdded(input);
152 NeutronUtils.createPortStatus(input.getUuid().getValue(), NeutronUtils.PORT_STATUS_ACTIVE, dataBroker);
155 if (NeutronConstants.DEVICE_OWNER_GATEWAY_INF.equals(input.getDeviceOwner())) {
156 handleRouterGatewayUpdated(input, false);
157 portStatus = NeutronUtils.PORT_STATUS_ACTIVE;
158 } else if (NeutronConstants.DEVICE_OWNER_FLOATING_IP.equals(input.getDeviceOwner())) {
159 handleFloatingIpPortUpdated(null, input);
160 portStatus = NeutronUtils.PORT_STATUS_ACTIVE;
163 // Switchdev ports need to be bounded to a host before creation
164 // in order to validate the supported vnic types from the hostconfig
165 if (input.getFixedIps() != null
166 && !input.getFixedIps().isEmpty()
167 && !(isPortTypeSwitchdev(input) && !isPortBound(input))) {
168 handleNeutronPortCreated(input);
170 NeutronUtils.createPortStatus(input.getUuid().getValue(), portStatus, dataBroker);
174 protected void remove(InstanceIdentifier<Port> identifier, Port input) {
175 LOG.trace("Removing Port : key: {}, value={}", identifier, input);
176 Network network = neutronvpnUtils.getNeutronNetwork(input.getNetworkId());
177 // need to proceed with deletion in case network is null for a case where v2 sync happens and a read for
178 // network from NN returns null, but the deletion process for port needs to continue
179 if (network != null && !NeutronvpnUtils.isNetworkTypeSupported(network)) {
180 String portName = input.getUuid().getValue();
181 LOG.warn("neutron vpn received a port remove() for a network without a provider extension augmentation "
182 + "or with an unsupported network type for the port {} which is part of network {}",
186 neutronvpnUtils.removeFromPortCache(input);
187 NeutronUtils.deletePortStatus(input.getUuid().getValue(), dataBroker);
189 if (!Strings.isNullOrEmpty(input.getDeviceOwner()) && !Strings.isNullOrEmpty(input.getDeviceId())) {
190 if (NeutronConstants.DEVICE_OWNER_ROUTER_INF.equals(input.getDeviceOwner())) {
191 handleRouterInterfaceRemoved(input);
192 /* nothing else to do here */
194 } else if (NeutronConstants.DEVICE_OWNER_GATEWAY_INF.equals(input.getDeviceOwner())
195 || NeutronConstants.DEVICE_OWNER_FLOATING_IP.equals(input.getDeviceOwner())) {
196 handleRouterGatewayUpdated(input, true);
197 elanService.removeKnownL3DmacAddress(input.getMacAddress().getValue(), input.getNetworkId().getValue());
200 if (input.getFixedIps() != null) {
201 handleNeutronPortDeleted(input);
206 protected void update(InstanceIdentifier<Port> identifier, Port original, Port update) {
207 LOG.trace("Received port update event: original={}, update={}", original, update);
208 // Switchdev ports need to be bounded to a host before creation
209 // in order to validate the supported vnic types from the hostconfig
210 if (isPortTypeSwitchdev(original)
211 && !isPortBound(original)
212 && isPortBound(update)) {
213 handleNeutronPortCreated(update);
215 final String portName = update.getUuid().getValue();
216 Network network = neutronvpnUtils.getNeutronNetwork(update.getNetworkId());
217 LOG.info("Update port {} from network {}", portName, update.getNetworkId().toString());
218 if (network == null || !NeutronvpnUtils.isNetworkTypeSupported(network)) {
219 LOG.warn("neutron vpn received a port update() for a network without a provider extension augmentation "
220 + "or with an unsupported network type for the port {} which is part of network {}",
224 neutronvpnUtils.addToPortCache(update);
226 if ((Strings.isNullOrEmpty(original.getDeviceOwner()) || Strings.isNullOrEmpty(original.getDeviceId())
227 || NeutronConstants.FLOATING_IP_DEVICE_ID_PENDING.equalsIgnoreCase(original.getDeviceId()))
228 && !Strings.isNullOrEmpty(update.getDeviceOwner()) && !Strings.isNullOrEmpty(update.getDeviceId())) {
229 if (NeutronConstants.DEVICE_OWNER_ROUTER_INF.equals(update.getDeviceOwner())) {
230 handleRouterInterfaceAdded(update);
233 if (NeutronConstants.DEVICE_OWNER_GATEWAY_INF.equals(update.getDeviceOwner())) {
234 handleRouterGatewayUpdated(update, false);
235 } else if (NeutronConstants.DEVICE_OWNER_FLOATING_IP.equals(update.getDeviceOwner())) {
236 handleFloatingIpPortUpdated(original, update);
239 Set<FixedIps> oldIPs = getFixedIpSet(original.getFixedIps());
240 Set<FixedIps> newIPs = getFixedIpSet(update.getFixedIps());
241 if (!oldIPs.equals(newIPs)) {
242 handleNeutronPortUpdated(original, update);
246 // check if port security enabled/disabled as part of port update
247 boolean origSecurityEnabled = NeutronvpnUtils.getPortSecurityEnabled(original);
248 boolean updatedSecurityEnabled = NeutronvpnUtils.getPortSecurityEnabled(update);
250 if (origSecurityEnabled || updatedSecurityEnabled) {
251 InstanceIdentifier<Interface> interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(portName);
252 jobCoordinator.enqueueJob("PORT- " + portName,
253 () -> Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
255 Optional<Interface> optionalInf =
256 confTx.read(interfaceIdentifier).get();
257 if (optionalInf.isPresent()) {
258 InterfaceBuilder interfaceBuilder = new InterfaceBuilder(optionalInf.get());
259 InterfaceAcl infAcl = handlePortSecurityUpdated(original, update,
260 origSecurityEnabled, updatedSecurityEnabled, interfaceBuilder).build();
261 interfaceBuilder.addAugmentation(InterfaceAcl.class, infAcl);
262 LOG.info("update: Of-port-interface updation for port {}", portName);
263 // Update OFPort interface for this neutron port
264 confTx.put(interfaceIdentifier, interfaceBuilder.build());
266 LOG.warn("update: Interface {} is not present", portName);
272 private void handleFloatingIpPortUpdated(@Nullable Port original, Port update) {
273 if ((original == null || NeutronConstants.FLOATING_IP_DEVICE_ID_PENDING.equals(original.getDeviceId()))
274 && !NeutronConstants.FLOATING_IP_DEVICE_ID_PENDING.equals(update.getDeviceId())) {
275 // populate floating-ip uuid and floating-ip port attributes (uuid, mac and subnet id for the ONLY
276 // fixed IP) to be used by NAT, depopulated in NATService once mac is retrieved in the removal path
277 addToFloatingIpPortInfo(new Uuid(update.getDeviceId()), update.getUuid(), update.getFixedIps().get(0)
278 .getSubnetId(), update.getMacAddress().getValue());
279 elanService.addKnownL3DmacAddress(update.getMacAddress().getValue(), update.getNetworkId().getValue());
283 private void handleRouterInterfaceAdded(Port routerPort) {
284 if (routerPort.getDeviceId() != null) {
285 Uuid routerId = new Uuid(routerPort.getDeviceId());
286 Uuid infNetworkId = routerPort.getNetworkId();
287 Uuid existingVpnId = neutronvpnUtils.getVpnForNetwork(infNetworkId);
289 elanService.addKnownL3DmacAddress(routerPort.getMacAddress().getValue(), infNetworkId.getValue());
290 if (existingVpnId == null) {
291 Set<Uuid> listVpnIds = new HashSet<>();
292 Uuid vpnId = neutronvpnUtils.getVpnForRouter(routerId, true);
296 listVpnIds.add(vpnId);
297 Uuid internetVpnId = neutronvpnUtils.getInternetvpnUuidBoundToRouterId(routerId);
298 List<Subnetmap> subnetMapList = new ArrayList<>();
299 boolean portIsIpv6 = false;
300 for (FixedIps portIP : routerPort.nonnullFixedIps()) {
301 // NOTE: Please donot change the order of calls to updateSubnetNodeWithFixedIP
302 // and addSubnetToVpn here
303 if (internetVpnId != null
304 && portIP.getIpAddress().getIpv6Address() != null) {
307 String ipValue = portIP.getIpAddress().stringValue();
308 Uuid subnetId = portIP.getSubnetId();
309 nvpnManager.updateSubnetNodeWithFixedIp(subnetId, routerId,
310 routerPort.getUuid(), ipValue, routerPort.getMacAddress().getValue(), vpnId);
311 Subnetmap sn = neutronvpnUtils.getSubnetmap(subnetId);
312 subnetMapList.add(sn);
315 listVpnIds.add(internetVpnId);
316 if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(
317 IpVersionChoice.IPV6, routerId, true)) {
318 neutronvpnUtils.updateVpnInstanceWithIpFamily(internetVpnId.getValue(), IpVersionChoice.IPV6,
320 neutronvpnUtils.updateVpnInstanceWithFallback(routerId, internetVpnId, true);
323 if (! subnetMapList.isEmpty()) {
324 nvpnManager.createVpnInterface(listVpnIds, routerPort, null);
326 IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
327 for (FixedIps portIP : routerPort.nonnullFixedIps()) {
328 String ipValue = portIP.getIpAddress().stringValue();
329 ipVersion = NeutronvpnUtils.getIpVersionFromString(ipValue);
330 if (ipVersion.isIpVersionChosen(IpVersionChoice.IPV4)) {
331 nvpnManager.addSubnetToVpn(vpnId, portIP.getSubnetId(),
332 null /* internet-vpn-id */);
334 nvpnManager.addSubnetToVpn(vpnId, portIP.getSubnetId(), internetVpnId);
336 LOG.trace("NeutronPortChangeListener Add Subnet Gateway IP {} MAC {} Interface {} VPN {}",
337 ipValue, routerPort.getMacAddress(),
338 routerPort.getUuid().getValue(), vpnId.getValue());
340 if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(ipVersion, routerId, true)) {
341 LOG.debug("vpnInstanceOpDataEntry is getting update with ip address family {} for VPN {}",
342 ipVersion, vpnId.getValue());
343 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, true);
345 nvpnManager.addToNeutronRouterInterfacesMap(routerId, routerPort.getUuid().getValue());
346 jobCoordinator.enqueueJob(routerId.toString(), () -> {
347 nvpnNatManager.handleSubnetsForExternalRouter(routerId);
348 return Collections.emptyList();
350 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
352 String portInterfaceName = createOfPortInterface(routerPort, confTx);
353 createElanInterface(routerPort, portInterfaceName, confTx);
354 }), LOG, "Error creating ELAN interface for {}", routerPort);
356 LOG.error("Neutron network {} corresponding to router interface port {} for neutron router {}"
357 + " already associated to VPN {}", infNetworkId.getValue(), routerPort.getUuid().getValue(),
358 routerId.getValue(), existingVpnId.getValue());
363 private void handleRouterInterfaceRemoved(Port routerPort) {
364 if (routerPort.getDeviceId() != null) {
365 Uuid routerId = new Uuid(routerPort.getDeviceId());
366 Uuid infNetworkId = routerPort.getNetworkId();
367 elanService.removeKnownL3DmacAddress(routerPort.getMacAddress().getValue(), infNetworkId.getValue());
368 Uuid vpnId = ObjectUtils.defaultIfNull(neutronvpnUtils.getVpnForRouter(routerId, true),
370 List<FixedIps> portIps = routerPort.nonnullFixedIps();
371 boolean vpnInstanceInternetIpVersionRemoved = false;
372 Uuid vpnInstanceInternetUuid = null;
373 for (FixedIps portIP : portIps) {
374 // Internet VPN : flush InternetVPN first
375 Uuid subnetId = portIP.getSubnetId();
376 Subnetmap sn = neutronvpnUtils.getSubnetmap(subnetId);
377 if (sn != null && sn.getInternetVpnId() != null) {
378 if (neutronvpnUtils.shouldVpnHandleIpVersionChangeToRemove(sn, sn.getInternetVpnId())) {
379 vpnInstanceInternetIpVersionRemoved = true;
380 vpnInstanceInternetUuid = sn.getInternetVpnId();
382 nvpnManager.updateVpnInternetForSubnet(sn, sn.getInternetVpnId(), false);
385 /* Remove ping responder for router interfaces
386 * A router interface reference in a VPN will have to be removed before the host interface references
387 * for that subnet in the VPN are removed. This is to ensure that the FIB Entry of the router interface
388 * is not the last entry to be removed for that subnet in the VPN.
389 * If router interface FIB entry is the last to be removed for a subnet in a VPN , then all the host
390 * interface references in the vpn will already have been cleared, which will cause failures in
391 * cleanup of router interface flows*/
392 nvpnManager.deleteVpnInterface(routerPort.getUuid().getValue(),
393 null /* vpn-id */, null /* wrtConfigTxn*/);
394 final Uuid internetVpnId = vpnInstanceInternetUuid;
395 // update RouterInterfaces map
396 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
398 IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
399 for (FixedIps portIP : portIps) {
400 Subnetmap sn = neutronvpnUtils.getSubnetmap(portIP.getSubnetId());
401 // router Port have either IPv4 or IPv6, never both
402 ipVersion = neutronvpnUtils.getIpVersionFromString(sn.getSubnetIp());
403 String ipValue = portIP.getIpAddress().stringValue();
404 neutronvpnUtils.removeVpnPortFixedIpToPort(vpnId.getValue(), ipValue, confTx);
405 // NOTE: Please donot change the order of calls to removeSubnetFromVpn and
406 // and updateSubnetNodeWithFixedIP
407 nvpnManager.removeSubnetFromVpn(vpnId, portIP.getSubnetId(), internetVpnId);
408 nvpnManager.updateSubnetNodeWithFixedIp(portIP.getSubnetId(), null, null,
411 nvpnManager.removeFromNeutronRouterInterfacesMap(routerId, routerPort.getUuid().getValue());
412 deleteElanInterface(routerPort.getUuid().getValue(), confTx);
413 deleteOfPortInterface(routerPort, confTx);
414 jobCoordinator.enqueueJob(routerId.toString(), () -> {
415 nvpnNatManager.handleSubnetsForExternalRouter(routerId);
416 return Collections.emptyList();
418 if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(ipVersion, routerId, false)) {
419 LOG.debug("vpnInstanceOpDataEntry is getting update with ip address family {} for VPN {}",
420 ipVersion, vpnId.getValue());
421 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, false);
423 }), LOG, "Error handling interface removal");
424 if (vpnInstanceInternetIpVersionRemoved) {
425 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnInstanceInternetUuid.getValue(),
426 IpVersionChoice.IPV6, false);
427 neutronvpnUtils.updateVpnInstanceWithFallback(routerId, vpnInstanceInternetUuid, false);
432 private void handleRouterGatewayUpdated(Port routerGwPort, boolean isRtrGwRemoved) {
433 Uuid routerId = new Uuid(routerGwPort.getDeviceId());
434 Uuid networkId = routerGwPort.getNetworkId();
435 Network network = neutronvpnUtils.getNeutronNetwork(networkId);
436 if (network == null) {
439 boolean isExternal = NeutronvpnUtils.getIsExternal(network);
441 Uuid vpnInternetId = neutronvpnUtils.getVpnForNetwork(networkId);
442 if (vpnInternetId != null) {
443 if (!isRtrGwRemoved) {
444 nvpnManager.updateVpnMaps(vpnInternetId, null, routerId, null, null);
446 List<Subnetmap> snList = neutronvpnUtils.getNeutronRouterSubnetMaps(routerId);
447 for (Subnetmap sn : snList) {
448 if (sn.getNetworkId() == networkId) {
451 if (NeutronvpnUtils.getIpVersionFromString(sn.getSubnetIp()) != IpVersionChoice.IPV6) {
454 if (isRtrGwRemoved) {
455 nvpnManager.removeV6PrivateSubnetToExtNetwork(routerId, vpnInternetId, sn);
457 nvpnManager.addV6PrivateSubnetToExtNetwork(routerId, vpnInternetId, sn);
460 //Update Internet BGP-VPN
461 if (isRtrGwRemoved) {
462 nvpnManager.updateVpnMaps(vpnInternetId, null, null, null, null);
466 elanService.addKnownL3DmacAddress(routerGwPort.getMacAddress().getValue(), networkId.getValue());
468 Router router = neutronvpnUtils.getNeutronRouter(routerId);
469 if (router == null) {
470 LOG.warn("No router found for router GW port {} for router {}", routerGwPort.getUuid().getValue(),
471 routerId.getValue());
473 eventCallbacks.onAddOrUpdate(LogicalDatastoreType.CONFIGURATION,
474 neutronvpnUtils.getNeutronRouterIid(routerId), (unused, newRouter) -> {
475 setupGwMac(newRouter, routerGwPort, routerId);
476 return DataTreeEventCallbackRegistrar.NextAction.UNREGISTER;
477 }, Duration.ofSeconds(3), iid -> {
478 LOG.error("GwPort {} added without Router", routerGwPort.getUuid().getValue());
482 setupGwMac(router, routerGwPort, routerId);
485 private void setupGwMac(Router router, Port routerGwPort, Uuid routerId) {
486 gwMacResolver.sendArpRequestsToExtGateways(router);
487 jobCoordinator.enqueueJob(routerId.toString(), () -> {
488 setExternalGwMac(routerGwPort, routerId);
489 return Collections.emptyList();
493 private void setExternalGwMac(Port routerGwPort, Uuid routerId) {
494 // During full-sync networking-odl syncs routers before ports. As such,
495 // the MAC of the router's gw port is not available to be set when the
496 // router is written. We catch that here.
497 InstanceIdentifier<Routers> routersId = NeutronvpnUtils.buildExtRoutersIdentifier(routerId);
498 Optional<Routers> optionalRouter = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routersId);
499 if (!optionalRouter.isPresent()) {
503 Routers extRouters = optionalRouter.get();
504 if (extRouters.getExtGwMacAddress() != null) {
508 RoutersBuilder builder = new RoutersBuilder(extRouters);
509 builder.setExtGwMacAddress(routerGwPort.getMacAddress().getValue());
510 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, routersId, builder.build());
514 private String getPortHostId(final Port port) {
516 PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
517 if (portBinding != null) {
518 return portBinding.getHostId();
525 private Hostconfig getHostConfig(final Port port) {
526 String hostId = getPortHostId(port);
527 if (hostId == null) {
530 Optional<Hostconfig> hostConfig;
532 hostConfig = this.hostConfigCache.get(hostId);
533 } catch (ReadFailedException e) {
534 LOG.error("failed to read host config from host {}", hostId, e);
537 return hostConfig.orNull();
540 private boolean isPortBound(final Port port) {
541 String hostId = getPortHostId(port);
542 return hostId != null && !hostId.isEmpty();
545 private boolean isPortVnicTypeDirect(Port port) {
546 PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
547 if (portBinding == null || portBinding.getVnicType() == null) {
548 // By default, VNIC_TYPE is NORMAL
551 String vnicType = portBinding.getVnicType().trim().toLowerCase(Locale.getDefault());
552 return vnicType.equals(NeutronConstants.VNIC_TYPE_DIRECT);
555 private boolean isSupportedVnicTypeByHost(final Port port, final String vnicType) {
556 Hostconfig hostConfig = getHostConfig(port);
557 String supportStr = String.format("\"vnic_type\": \"%s\"", vnicType);
558 if (hostConfig != null && hostConfig.getConfig().contains(supportStr)) {
565 private Map<String, JsonElement> unmarshal(final String profile) {
566 if (null == profile) {
569 Gson gson = new Gson();
570 JsonObject jsonObject = gson.fromJson(profile, JsonObject.class);
571 Map<String, JsonElement> map = new HashMap<>();
572 for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
573 map.put(entry.getKey(), entry.getValue());
578 private boolean isPortTypeSwitchdev(final Port port) {
579 if (!isPortVnicTypeDirect(port)) {
583 PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
584 String profile = portBinding.getProfile();
585 if (profile == null || profile.isEmpty()) {
586 LOG.debug("Port {} has no binding:profile values", port.getUuid());
590 Map<String, JsonElement> mapProfile = unmarshal(profile);
591 JsonElement capabilities = mapProfile.get(NeutronConstants.BINDING_PROFILE_CAPABILITIES);
592 LOG.debug("Port {} capabilities: {}", port.getUuid(), capabilities);
593 if (capabilities == null || !capabilities.isJsonArray()) {
594 LOG.debug("binding profile capabilities not in array format: {}", capabilities);
598 JsonArray capabilitiesArray = capabilities.getAsJsonArray();
599 Gson gson = new Gson();
600 JsonElement switchdevElement = gson.fromJson(NeutronConstants.SWITCHDEV, JsonElement.class);
601 return capabilitiesArray.contains(switchdevElement);
605 private void handleNeutronPortCreated(final Port port) {
606 final String portName = port.getUuid().getValue();
607 final Uuid portId = port.getUuid();
608 final List<FixedIps> portIpAddrsList = port.nonnullFixedIps();
609 if (NeutronConstants.IS_ODL_DHCP_PORT.test(port)) {
612 jobCoordinator.enqueueJob("PORT- " + portName, () -> {
613 // add direct port to subnetMaps config DS
614 if (!(NeutronUtils.isPortVnicTypeNormal(port)
615 || isPortTypeSwitchdev(port)
616 && isSupportedVnicTypeByHost(port, NeutronConstants.VNIC_TYPE_DIRECT))) {
617 for (FixedIps ip: portIpAddrsList) {
618 nvpnManager.updateSubnetmapNodeWithPorts(ip.getSubnetId(), null, portId);
620 LOG.info("Port {} is not a normal and not a direct with switchdev VNIC type ;"
621 + "OF Port interfaces are not created", portName);
622 return Collections.emptyList();
624 return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
625 LOG.info("Of-port-interface creation for port {}", portName);
626 // Create of-port interface for this neutron port
627 String portInterfaceName = createOfPortInterface(port, tx);
628 LOG.debug("Creating ELAN Interface for port {}", portName);
629 createElanInterface(port, portInterfaceName, tx);
630 Set<Uuid> vpnIdList = new HashSet<>();
631 Set<Uuid> routerIds = new HashSet<>();
632 for (FixedIps ip: portIpAddrsList) {
633 Subnetmap subnetMap = nvpnManager.updateSubnetmapNodeWithPorts(ip.getSubnetId(), portId, null);
634 if (subnetMap != null && subnetMap.getInternetVpnId() != null) {
635 if (!vpnIdList.contains(subnetMap.getInternetVpnId())) {
636 vpnIdList.add(subnetMap.getInternetVpnId());
639 if (subnetMap != null && subnetMap.getVpnId() != null) {
640 // can't use NeutronvpnUtils.getVpnForNetwork to optimise here, because it gives BGPVPN id
641 // obtained subnetMaps belongs to one network => vpnId must be the same for each port Ip
642 Uuid vpnId = subnetMap.getVpnId();
644 vpnIdList.add(vpnId);
647 if (subnetMap != null && subnetMap.getRouterId() != null) {
648 routerIds.add(subnetMap.getRouterId());
651 if (!vpnIdList.isEmpty()) {
652 // create new vpn-interface for neutron port
653 LOG.debug("handleNeutronPortCreated: Adding VPN Interface for port {} from network {}", portName,
654 port.getNetworkId().toString());
655 nvpnManager.createVpnInterface(vpnIdList, port, tx);
656 if (!routerIds.isEmpty()) {
657 for (Uuid routerId : routerIds) {
658 nvpnManager.addToNeutronRouterInterfacesMap(routerId,port.getUuid().getValue());
666 private void handleNeutronPortDeleted(final Port port) {
667 final String portName = port.getUuid().getValue();
668 final Uuid portId = port.getUuid();
669 final List<FixedIps> portIpsList = port.nonnullFixedIps();
670 jobCoordinator.enqueueJob("PORT- " + portName,
671 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
672 if (!(NeutronUtils.isPortVnicTypeNormal(port) || isPortTypeSwitchdev(port))) {
673 for (FixedIps ip : portIpsList) {
674 // remove direct port from subnetMaps config DS
675 nvpnManager.removePortsFromSubnetmapNode(ip.getSubnetId(), null, portId);
677 LOG.info("Port {} is not a normal and not a direct with switchdev VNIC type ;"
678 + "Skipping OF Port interfaces removal", portName);
682 Set<Uuid> routerIds = new HashSet<>();
683 Uuid internetVpnId = null;
684 for (FixedIps ip : portIpsList) {
685 Subnetmap subnetMap = nvpnManager.removePortsFromSubnetmapNode(ip.getSubnetId(), portId, null);
686 if (subnetMap == null) {
689 if (subnetMap.getVpnId() != null) {
690 // can't use NeutronvpnUtils.getVpnForNetwork to optimise here, because it gives BGPVPN id
691 // obtained subnetMaps belongs to one network => vpnId must be the same for each port Ip
692 vpnId = subnetMap.getVpnId();
694 if (subnetMap.getRouterId() != null) {
695 routerIds.add(subnetMap.getRouterId());
697 internetVpnId = subnetMap.getInternetVpnId();
699 if (NeutronConstants.DEVICE_OWNER_GATEWAY_INF.equals(port.getDeviceOwner())
700 || NeutronConstants.DEVICE_OWNER_FLOATING_IP.equals(port.getDeviceOwner())) {
701 String ipAddress = ip.getIpAddress().stringValue();
703 neutronvpnUtils.removeVpnPortFixedIpToPort(vpnId.getValue(), ipAddress, confTx);
705 if (internetVpnId != null) {
706 neutronvpnUtils.removeVpnPortFixedIpToPort(internetVpnId.getValue(),
711 if (vpnId != null || internetVpnId != null) {
712 // remove vpn-interface for this neutron port
713 LOG.debug("removing VPN Interface for port {}", portName);
714 if (!routerIds.isEmpty()) {
715 for (Uuid routerId : routerIds) {
716 nvpnManager.removeFromNeutronRouterInterfacesMap(routerId, portName);
719 nvpnManager.deleteVpnInterface(portName, null /* vpn-id */, confTx);
721 // Remove of-port interface for this neutron port
722 // ELAN interface is also implicitly deleted as part of this operation
723 LOG.debug("Of-port-interface removal for port {}", portName);
724 deleteOfPortInterface(port, confTx);
725 //dissociate fixedIP from floatingIP if associated
726 nvpnManager.dissociatefixedIPFromFloatingIP(port.getUuid().getValue());
731 private void handleNeutronPortUpdated(final Port portoriginal, final Port portupdate) {
732 final List<FixedIps> portoriginalIps = portoriginal.getFixedIps();
733 final List<FixedIps> portupdateIps = portupdate.getFixedIps();
734 if (portoriginalIps == null || portoriginalIps.isEmpty()) {
735 handleNeutronPortCreated(portupdate);
739 if (portupdateIps == null || portupdateIps.isEmpty()) {
740 LOG.info("Ignoring portUpdate (fixed_ip removal) for port {} as this case is handled "
741 + "during subnet deletion event.", portupdate.getUuid().getValue());
745 if (NeutronConstants.IS_ODL_DHCP_PORT.test(portupdate)) {
749 jobCoordinator.enqueueJob("PORT- " + portupdate.getUuid().getValue(),
750 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
751 final List<Uuid> originalSnMapsIds = portoriginalIps.stream().map(FixedIps::getSubnetId)
752 .collect(Collectors.toList());
753 final List<Uuid> updateSnMapsIds = portupdateIps.stream().map(FixedIps::getSubnetId)
754 .collect(Collectors.toList());
755 Set<Uuid> originalRouterIds = new HashSet<>();
756 Set<Uuid> oldVpnIds = new HashSet<>();
757 for (Uuid snId: originalSnMapsIds) {
758 if (!updateSnMapsIds.remove(snId)) {
759 // snId was present in originalSnMapsIds, but not in updateSnMapsIds
760 Subnetmap subnetMapOld = nvpnManager.removePortsFromSubnetmapNode(snId, portoriginal.getUuid(),
762 if (subnetMapOld != null && subnetMapOld.getVpnId() != null) {
763 oldVpnIds.add(subnetMapOld.getVpnId());
765 if (subnetMapOld != null && subnetMapOld.getInternetVpnId() != null) {
766 oldVpnIds.add(subnetMapOld.getInternetVpnId());
768 if (subnetMapOld != null && subnetMapOld.getRouterId() != null) {
769 originalRouterIds.add(subnetMapOld.getRouterId());
773 Set<Uuid> newVpnIds = new HashSet<>();
774 Set<Uuid> newRouterIds = new HashSet<>();
775 for (Uuid snId: updateSnMapsIds) {
776 Subnetmap subnetMapNew = nvpnManager.updateSubnetmapNodeWithPorts(snId, portupdate.getUuid(), null);
777 if (subnetMapNew != null) {
778 if (subnetMapNew.getVpnId() != null) {
779 newVpnIds.add(subnetMapNew.getVpnId());
781 if (subnetMapNew.getInternetVpnId() != null) {
782 newVpnIds.add(subnetMapNew.getInternetVpnId());
784 if (subnetMapNew.getRouterId() != null) {
785 newRouterIds.add(subnetMapNew.getRouterId());
789 if (!oldVpnIds.isEmpty()) {
790 LOG.info("removing VPN Interface for port {}", portoriginal.getUuid().getValue());
791 if (!originalRouterIds.isEmpty()) {
792 for (Uuid routerId : originalRouterIds) {
793 nvpnManager.removeFromNeutronRouterInterfacesMap(routerId,
794 portoriginal.getUuid().getValue());
797 nvpnManager.deleteVpnInterface(portoriginal.getUuid().getValue(),
798 null /* vpn-id */, confTx);
800 if (!newVpnIds.isEmpty()) {
801 LOG.info("Adding VPN Interface for port {}", portupdate.getUuid().getValue());
802 nvpnManager.createVpnInterface(newVpnIds, portupdate, confTx);
803 if (!newRouterIds.isEmpty()) {
804 for (Uuid routerId : newRouterIds) {
805 nvpnManager.addToNeutronRouterInterfacesMap(routerId,portupdate.getUuid().getValue());
813 private InterfaceAclBuilder handlePortSecurityUpdated(Port portOriginal,
814 Port portUpdated, boolean origSecurityEnabled, boolean updatedSecurityEnabled,
815 InterfaceBuilder interfaceBuilder) {
816 InterfaceAclBuilder interfaceAclBuilder = null;
817 if (origSecurityEnabled != updatedSecurityEnabled) {
818 interfaceAclBuilder = new InterfaceAclBuilder();
819 interfaceAclBuilder.setPortSecurityEnabled(updatedSecurityEnabled);
820 if (updatedSecurityEnabled) {
821 // Handle security group enabled
822 neutronvpnUtils.populateInterfaceAclBuilder(interfaceAclBuilder, portUpdated);
824 // Handle security group disabled
825 interfaceAclBuilder.setSecurityGroups(new ArrayList<>());
826 interfaceAclBuilder.setAllowedAddressPairs(new ArrayList<>());
827 interfaceAclBuilder.setSubnetInfo(new ArrayList<>());
830 if (updatedSecurityEnabled) {
831 // handle SG add/delete delta
832 InterfaceAcl interfaceAcl = interfaceBuilder.augmentation(InterfaceAcl.class);
833 interfaceAclBuilder = new InterfaceAclBuilder(interfaceAcl);
834 interfaceAclBuilder.setSecurityGroups(
835 NeutronvpnUtils.getUpdatedSecurityGroups(interfaceAcl.getSecurityGroups(),
836 portOriginal.getSecurityGroups(), portUpdated.getSecurityGroups()));
837 List<AllowedAddressPairs> updatedAddressPairs = NeutronvpnUtils.getUpdatedAllowedAddressPairs(
838 interfaceAcl.getAllowedAddressPairs(), portOriginal.getAllowedAddressPairs(),
839 portUpdated.getAllowedAddressPairs());
840 interfaceAclBuilder.setAllowedAddressPairs(NeutronvpnUtils.getAllowedAddressPairsForFixedIps(
841 updatedAddressPairs, portOriginal.getMacAddress(), portOriginal.getFixedIps(),
842 portUpdated.getFixedIps()));
844 if (portOriginal.getFixedIps() != null
845 && !portOriginal.getFixedIps().equals(portUpdated.getFixedIps())) {
846 neutronvpnUtils.populateSubnetInfo(interfaceAclBuilder, portUpdated);
850 return interfaceAclBuilder;
853 private String createOfPortInterface(Port port, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
854 Interface inf = createInterface(port);
855 String infName = inf.getName();
857 InstanceIdentifier<Interface> interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(infName);
859 Optional<Interface> optionalInf =
860 SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
861 interfaceIdentifier);
862 if (!optionalInf.isPresent()) {
863 wrtConfigTxn.put(interfaceIdentifier, inf);
865 LOG.warn("Interface {} is already present", infName);
867 } catch (ReadFailedException e) {
868 LOG.error("failed to create interface {}", infName, e);
873 private Interface createInterface(Port port) {
874 String interfaceName = port.getUuid().getValue();
875 IfL2vlan.L2vlanMode l2VlanMode = IfL2vlan.L2vlanMode.Trunk;
876 InterfaceBuilder interfaceBuilder = new InterfaceBuilder();
877 IfL2vlanBuilder ifL2vlanBuilder = new IfL2vlanBuilder();
879 Network network = neutronvpnUtils.getNeutronNetwork(port.getNetworkId());
880 Boolean isVlanTransparent = network.isVlanTransparent();
881 if (isVlanTransparent != null && isVlanTransparent) {
882 l2VlanMode = IfL2vlan.L2vlanMode.Transparent;
885 ifL2vlanBuilder.setL2vlanMode(l2VlanMode);
887 interfaceBuilder.setEnabled(true).setName(interfaceName).setType(L2vlan.class)
888 .addAugmentation(IfL2vlan.class, ifL2vlanBuilder.build());
890 if (NeutronvpnUtils.getPortSecurityEnabled(port)) {
891 InterfaceAclBuilder interfaceAclBuilder = new InterfaceAclBuilder();
892 interfaceAclBuilder.setPortSecurityEnabled(true);
893 neutronvpnUtils.populateInterfaceAclBuilder(interfaceAclBuilder, port);
894 interfaceBuilder.addAugmentation(InterfaceAcl.class, interfaceAclBuilder.build());
896 return interfaceBuilder.build();
899 private void deleteOfPortInterface(Port port, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
900 String name = port.getUuid().getValue();
901 LOG.debug("Removing OFPort Interface {}", name);
902 InstanceIdentifier<Interface> interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(name);
904 Optional<Interface> optionalInf =
905 SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
906 interfaceIdentifier);
907 if (optionalInf.isPresent()) {
908 wrtConfigTxn.delete(interfaceIdentifier);
910 LOG.warn("deleteOfPortInterface: Interface {} is not present", name);
912 } catch (ReadFailedException e) {
913 LOG.error("deleteOfPortInterface: Failed to delete interface {}", name, e);
917 private void createElanInterface(Port port, String name,
918 TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
919 String elanInstanceName = port.getNetworkId().getValue();
920 List<StaticMacEntries> staticMacEntries = NeutronvpnUtils.buildStaticMacEntry(port);
922 InstanceIdentifier<ElanInterface> id = InstanceIdentifier.builder(ElanInterfaces.class).child(ElanInterface
923 .class, new ElanInterfaceKey(name)).build();
924 ElanInterface elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName)
925 .setName(name).setStaticMacEntries(staticMacEntries).withKey(new ElanInterfaceKey(name)).build();
926 wrtConfigTxn.put(id, elanInterface);
927 LOG.debug("Creating new ELan Interface {}", elanInterface);
930 private void deleteElanInterface(String name, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
931 InstanceIdentifier<ElanInterface> id = InstanceIdentifier.builder(ElanInterfaces.class).child(ElanInterface
932 .class, new ElanInterfaceKey(name)).build();
933 wrtConfigTxn.delete(id);
936 // TODO Clean up the exception handling
937 @SuppressWarnings("checkstyle:IllegalCatch")
938 private void addToFloatingIpPortInfo(Uuid floatingIpId, Uuid floatingIpPortId, Uuid floatingIpPortSubnetId, String
939 floatingIpPortMacAddress) {
940 InstanceIdentifier id = NeutronvpnUtils.buildfloatingIpIdToPortMappingIdentifier(floatingIpId);
942 FloatingIpIdToPortMappingBuilder floatingipIdToPortMacMappingBuilder = new
943 FloatingIpIdToPortMappingBuilder().withKey(new FloatingIpIdToPortMappingKey(floatingIpId))
944 .setFloatingIpId(floatingIpId).setFloatingIpPortId(floatingIpPortId)
945 .setFloatingIpPortSubnetId(floatingIpPortSubnetId)
946 .setFloatingIpPortMacAddress(floatingIpPortMacAddress);
947 LOG.debug("Creating floating IP UUID {} to Floating IP neutron port {} mapping in Floating IP"
948 + " Port Info Config DS", floatingIpId.getValue(), floatingIpPortId.getValue());
949 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id,
950 floatingipIdToPortMacMappingBuilder.build());
951 } catch (Exception e) {
952 LOG.error("Creating floating IP UUID {} to Floating IP neutron port {} mapping in Floating IP"
953 + " Port Info Config DS failed", floatingIpId.getValue(), floatingIpPortId.getValue(), e);
957 private Set<FixedIps> getFixedIpSet(List<FixedIps> fixedIps) {
958 return fixedIps != null ? new HashSet<>(fixedIps) : Collections.emptySet();