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;
11 import static org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils.requireNonNullElse;
13 import com.google.common.base.Optional;
14 import com.google.common.base.Strings;
15 import com.google.gson.Gson;
16 import com.google.gson.JsonArray;
17 import com.google.gson.JsonElement;
18 import com.google.gson.JsonObject;
19 import java.time.Duration;
20 import java.util.ArrayList;
21 import java.util.Collections;
22 import java.util.HashMap;
23 import java.util.HashSet;
24 import java.util.List;
25 import java.util.Locale;
28 import java.util.stream.Collectors;
29 import javax.annotation.Nullable;
30 import javax.annotation.PostConstruct;
31 import javax.inject.Singleton;
32 import org.apache.commons.lang3.ObjectUtils;
33 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
34 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
35 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
36 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
37 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
38 import org.opendaylight.genius.datastoreutils.listeners.DataTreeEventCallbackRegistrar;
39 import org.opendaylight.genius.infra.Datastore;
40 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
41 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
42 import org.opendaylight.genius.infra.TypedWriteTransaction;
43 import org.opendaylight.genius.mdsalutil.MDSALUtil;
44 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
45 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
46 import org.opendaylight.netvirt.elanmanager.api.IElanService;
47 import org.opendaylight.netvirt.neutronvpn.api.enums.IpVersionChoice;
48 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronConstants;
49 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlan;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlanBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.InterfaceAcl;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.InterfaceAclBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.AllowedAddressPairs;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceKey;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntries;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.RoutersBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.port.info.FloatingIpIdToPortMappingBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.port.info.FloatingIpIdToPortMappingKey;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.PortBindingExtension;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.hostconfig.rev150712.hostconfig.attributes.hostconfigs.Hostconfig;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
77 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
78 import org.slf4j.Logger;
79 import org.slf4j.LoggerFactory;
82 public class NeutronPortChangeListener extends AsyncDataTreeChangeListenerBase<Port, NeutronPortChangeListener> {
83 private static final Logger LOG = LoggerFactory.getLogger(NeutronPortChangeListener.class);
84 private final DataBroker dataBroker;
85 private final ManagedNewTransactionRunner txRunner;
86 private final NeutronvpnManager nvpnManager;
87 private final NeutronvpnNatManager nvpnNatManager;
88 private final NeutronSubnetGwMacResolver gwMacResolver;
89 private final IElanService elanService;
90 private final JobCoordinator jobCoordinator;
91 private final NeutronvpnUtils neutronvpnUtils;
92 private final HostConfigCache hostConfigCache;
93 private final DataTreeEventCallbackRegistrar eventCallbacks;
95 public NeutronPortChangeListener(final DataBroker dataBroker,
96 final NeutronvpnManager neutronvpnManager,
97 final NeutronvpnNatManager neutronvpnNatManager,
98 final NeutronSubnetGwMacResolver gwMacResolver,
99 final IElanService elanService,
100 final JobCoordinator jobCoordinator,
101 final NeutronvpnUtils neutronvpnUtils,
102 final HostConfigCache hostConfigCache,
103 final DataTreeEventCallbackRegistrar dataTreeEventCallbackRegistrar) {
104 super(Port.class, NeutronPortChangeListener.class);
105 this.dataBroker = dataBroker;
106 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
107 nvpnManager = neutronvpnManager;
108 nvpnNatManager = neutronvpnNatManager;
109 this.gwMacResolver = gwMacResolver;
110 this.elanService = elanService;
111 this.jobCoordinator = jobCoordinator;
112 this.neutronvpnUtils = neutronvpnUtils;
113 this.hostConfigCache = hostConfigCache;
114 this.eventCallbacks = dataTreeEventCallbackRegistrar;
120 LOG.info("{} init", getClass().getSimpleName());
121 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
125 protected InstanceIdentifier<Port> getWildCardPath() {
126 return InstanceIdentifier.create(Neutron.class).child(Ports.class).child(Port.class);
130 protected NeutronPortChangeListener getDataTreeChangeListener() {
131 return NeutronPortChangeListener.this;
136 protected void add(InstanceIdentifier<Port> identifier, Port input) {
137 LOG.trace("Received port add event: port={}", input);
138 String portName = input.getUuid().getValue();
139 LOG.trace("Adding Port : key: {}, value={}", identifier, input);
140 Network network = neutronvpnUtils.getNeutronNetwork(input.getNetworkId());
141 if (network == null || !NeutronvpnUtils.isNetworkTypeSupported(network)) {
142 LOG.warn("neutron vpn received a port add() for a network without a provider extension augmentation "
143 + "or with an unsupported network type for the port {} which is part of network {}",
148 neutronvpnUtils.addToPortCache(input);
149 String portStatus = NeutronUtils.PORT_STATUS_DOWN;
150 if (!Strings.isNullOrEmpty(input.getDeviceOwner()) && !Strings.isNullOrEmpty(input.getDeviceId())) {
151 if (NeutronConstants.DEVICE_OWNER_ROUTER_INF.equals(input.getDeviceOwner())) {
152 handleRouterInterfaceAdded(input);
153 NeutronUtils.createPortStatus(input.getUuid().getValue(), NeutronUtils.PORT_STATUS_ACTIVE, dataBroker);
156 if (NeutronConstants.DEVICE_OWNER_GATEWAY_INF.equals(input.getDeviceOwner())) {
157 handleRouterGatewayUpdated(input, false);
158 portStatus = NeutronUtils.PORT_STATUS_ACTIVE;
159 } else if (NeutronConstants.DEVICE_OWNER_FLOATING_IP.equals(input.getDeviceOwner())) {
160 handleFloatingIpPortUpdated(null, input);
161 portStatus = NeutronUtils.PORT_STATUS_ACTIVE;
164 // Switchdev ports need to be bounded to a host before creation
165 // in order to validate the supported vnic types from the hostconfig
166 if (input.getFixedIps() != null
167 && !input.getFixedIps().isEmpty()
168 && !(isPortTypeSwitchdev(input) && !isPortBound(input))) {
169 handleNeutronPortCreated(input);
171 NeutronUtils.createPortStatus(input.getUuid().getValue(), portStatus, dataBroker);
175 protected void remove(InstanceIdentifier<Port> identifier, Port input) {
176 LOG.trace("Removing Port : key: {}, value={}", identifier, input);
177 Network network = neutronvpnUtils.getNeutronNetwork(input.getNetworkId());
178 // need to proceed with deletion in case network is null for a case where v2 sync happens and a read for
179 // network from NN returns null, but the deletion process for port needs to continue
180 if (network != null && !NeutronvpnUtils.isNetworkTypeSupported(network)) {
181 String portName = input.getUuid().getValue();
182 LOG.warn("neutron vpn received a port remove() for a network without a provider extension augmentation "
183 + "or with an unsupported network type for the port {} which is part of network {}",
187 neutronvpnUtils.removeFromPortCache(input);
188 NeutronUtils.deletePortStatus(input.getUuid().getValue(), dataBroker);
190 if (!Strings.isNullOrEmpty(input.getDeviceOwner()) && !Strings.isNullOrEmpty(input.getDeviceId())) {
191 if (NeutronConstants.DEVICE_OWNER_ROUTER_INF.equals(input.getDeviceOwner())) {
192 handleRouterInterfaceRemoved(input);
193 /* nothing else to do here */
195 } else if (NeutronConstants.DEVICE_OWNER_GATEWAY_INF.equals(input.getDeviceOwner())
196 || NeutronConstants.DEVICE_OWNER_FLOATING_IP.equals(input.getDeviceOwner())) {
197 handleRouterGatewayUpdated(input, true);
198 elanService.removeKnownL3DmacAddress(input.getMacAddress().getValue(), input.getNetworkId().getValue());
201 if (input.getFixedIps() != null) {
202 handleNeutronPortDeleted(input);
207 protected void update(InstanceIdentifier<Port> identifier, Port original, Port update) {
208 LOG.trace("Received port update event: original={}, update={}", original, update);
209 // Switchdev ports need to be bounded to a host before creation
210 // in order to validate the supported vnic types from the hostconfig
211 if (isPortTypeSwitchdev(original)
212 && !isPortBound(original)
213 && isPortBound(update)) {
214 handleNeutronPortCreated(update);
216 final String portName = update.getUuid().getValue();
217 Network network = neutronvpnUtils.getNeutronNetwork(update.getNetworkId());
218 LOG.info("Update port {} from network {}", portName, update.getNetworkId().toString());
219 if (network == null || !NeutronvpnUtils.isNetworkTypeSupported(network)) {
220 LOG.warn("neutron vpn received a port update() for a network without a provider extension augmentation "
221 + "or with an unsupported network type for the port {} which is part of network {}",
225 neutronvpnUtils.addToPortCache(update);
227 if ((Strings.isNullOrEmpty(original.getDeviceOwner()) || Strings.isNullOrEmpty(original.getDeviceId())
228 || NeutronConstants.FLOATING_IP_DEVICE_ID_PENDING.equalsIgnoreCase(original.getDeviceId()))
229 && !Strings.isNullOrEmpty(update.getDeviceOwner()) && !Strings.isNullOrEmpty(update.getDeviceId())) {
230 if (NeutronConstants.DEVICE_OWNER_ROUTER_INF.equals(update.getDeviceOwner())) {
231 handleRouterInterfaceAdded(update);
234 if (NeutronConstants.DEVICE_OWNER_GATEWAY_INF.equals(update.getDeviceOwner())) {
235 handleRouterGatewayUpdated(update, false);
236 } else if (NeutronConstants.DEVICE_OWNER_FLOATING_IP.equals(update.getDeviceOwner())) {
237 handleFloatingIpPortUpdated(original, update);
240 Set<FixedIps> oldIPs = getFixedIpSet(original.getFixedIps());
241 Set<FixedIps> newIPs = getFixedIpSet(update.getFixedIps());
242 if (!oldIPs.equals(newIPs)) {
243 handleNeutronPortUpdated(original, update);
247 // check if port security enabled/disabled as part of port update
248 boolean origSecurityEnabled = NeutronvpnUtils.getPortSecurityEnabled(original);
249 boolean updatedSecurityEnabled = NeutronvpnUtils.getPortSecurityEnabled(update);
251 if (origSecurityEnabled || updatedSecurityEnabled) {
252 InstanceIdentifier<Interface> interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(portName);
253 jobCoordinator.enqueueJob("PORT- " + portName,
254 () -> Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
256 Optional<Interface> optionalInf =
257 confTx.read(interfaceIdentifier).get();
258 if (optionalInf.isPresent()) {
259 InterfaceBuilder interfaceBuilder = new InterfaceBuilder(optionalInf.get());
260 InterfaceAcl infAcl = handlePortSecurityUpdated(original, update,
261 origSecurityEnabled, updatedSecurityEnabled, interfaceBuilder).build();
262 interfaceBuilder.addAugmentation(InterfaceAcl.class, infAcl);
263 LOG.info("update: Of-port-interface updation for port {}", portName);
264 // Update OFPort interface for this neutron port
265 confTx.put(interfaceIdentifier, interfaceBuilder.build());
267 LOG.warn("update: Interface {} is not present", portName);
273 private void handleFloatingIpPortUpdated(@Nullable Port original, Port update) {
274 if ((original == null || NeutronConstants.FLOATING_IP_DEVICE_ID_PENDING.equals(original.getDeviceId()))
275 && !NeutronConstants.FLOATING_IP_DEVICE_ID_PENDING.equals(update.getDeviceId())) {
276 // populate floating-ip uuid and floating-ip port attributes (uuid, mac and subnet id for the ONLY
277 // fixed IP) to be used by NAT, depopulated in NATService once mac is retrieved in the removal path
278 addToFloatingIpPortInfo(new Uuid(update.getDeviceId()), update.getUuid(), update.getFixedIps().get(0)
279 .getSubnetId(), update.getMacAddress().getValue());
280 elanService.addKnownL3DmacAddress(update.getMacAddress().getValue(), update.getNetworkId().getValue());
284 private void handleRouterInterfaceAdded(Port routerPort) {
285 if (routerPort.getDeviceId() != null) {
286 Uuid routerId = new Uuid(routerPort.getDeviceId());
287 Uuid infNetworkId = routerPort.getNetworkId();
288 Uuid existingVpnId = neutronvpnUtils.getVpnForNetwork(infNetworkId);
290 elanService.addKnownL3DmacAddress(routerPort.getMacAddress().getValue(), infNetworkId.getValue());
291 if (existingVpnId == null) {
292 Set<Uuid> listVpnIds = new HashSet<>();
293 Uuid vpnId = neutronvpnUtils.getVpnForRouter(routerId, true);
297 listVpnIds.add(vpnId);
298 Uuid internetVpnId = neutronvpnUtils.getInternetvpnUuidBoundToRouterId(routerId);
299 List<Subnetmap> subnetMapList = new ArrayList<>();
300 boolean portIsIpv6 = false;
301 for (FixedIps portIP : requireNonNullElse(routerPort.getFixedIps(),
302 Collections.<FixedIps>emptyList())) {
303 // NOTE: Please donot change the order of calls to updateSubnetNodeWithFixedIP
304 // and addSubnetToVpn here
305 if (internetVpnId != null
306 && portIP.getIpAddress().getIpv6Address() != null) {
309 String ipValue = portIP.getIpAddress().stringValue();
310 Uuid subnetId = portIP.getSubnetId();
311 nvpnManager.updateSubnetNodeWithFixedIp(subnetId, routerId,
312 routerPort.getUuid(), ipValue, routerPort.getMacAddress().getValue(), vpnId);
313 Subnetmap sn = neutronvpnUtils.getSubnetmap(subnetId);
314 subnetMapList.add(sn);
317 listVpnIds.add(internetVpnId);
318 if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(
319 IpVersionChoice.IPV6, routerId, true)) {
320 neutronvpnUtils.updateVpnInstanceWithIpFamily(internetVpnId.getValue(), IpVersionChoice.IPV6,
322 neutronvpnUtils.updateVpnInstanceWithFallback(routerId, internetVpnId, true);
325 if (! subnetMapList.isEmpty()) {
326 nvpnManager.createVpnInterface(listVpnIds, routerPort, null);
328 IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
329 for (FixedIps portIP : requireNonNullElse(routerPort.getFixedIps(),
330 Collections.<FixedIps>emptyList())) {
331 String ipValue = portIP.getIpAddress().stringValue();
332 ipVersion = NeutronvpnUtils.getIpVersionFromString(ipValue);
333 if (ipVersion.isIpVersionChosen(IpVersionChoice.IPV4)) {
334 nvpnManager.addSubnetToVpn(vpnId, portIP.getSubnetId(),
335 null /* internet-vpn-id */);
337 nvpnManager.addSubnetToVpn(vpnId, portIP.getSubnetId(), internetVpnId);
339 LOG.trace("NeutronPortChangeListener Add Subnet Gateway IP {} MAC {} Interface {} VPN {}",
340 ipValue, routerPort.getMacAddress(),
341 routerPort.getUuid().getValue(), vpnId.getValue());
343 if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(ipVersion, routerId, true)) {
344 LOG.debug("vpnInstanceOpDataEntry is getting update with ip address family {} for VPN {}",
345 ipVersion, vpnId.getValue());
346 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, true);
348 nvpnManager.addToNeutronRouterInterfacesMap(routerId, routerPort.getUuid().getValue());
349 jobCoordinator.enqueueJob(routerId.toString(), () -> {
350 nvpnNatManager.handleSubnetsForExternalRouter(routerId);
351 return Collections.emptyList();
353 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
355 String portInterfaceName = createOfPortInterface(routerPort, confTx);
356 createElanInterface(routerPort, portInterfaceName, confTx);
357 }), LOG, "Error creating ELAN interface for {}", routerPort);
359 LOG.error("Neutron network {} corresponding to router interface port {} for neutron router {}"
360 + " already associated to VPN {}", infNetworkId.getValue(), routerPort.getUuid().getValue(),
361 routerId.getValue(), existingVpnId.getValue());
366 private void handleRouterInterfaceRemoved(Port routerPort) {
367 if (routerPort.getDeviceId() != null) {
368 Uuid routerId = new Uuid(routerPort.getDeviceId());
369 Uuid infNetworkId = routerPort.getNetworkId();
370 elanService.removeKnownL3DmacAddress(routerPort.getMacAddress().getValue(), infNetworkId.getValue());
371 Uuid vpnId = ObjectUtils.defaultIfNull(neutronvpnUtils.getVpnForRouter(routerId, true),
373 List<FixedIps> portIps = requireNonNullElse(routerPort.getFixedIps(), Collections.emptyList());
374 boolean vpnInstanceInternetIpVersionRemoved = false;
375 Uuid vpnInstanceInternetUuid = null;
376 for (FixedIps portIP : portIps) {
377 // Internet VPN : flush InternetVPN first
378 Uuid subnetId = portIP.getSubnetId();
379 Subnetmap sn = neutronvpnUtils.getSubnetmap(subnetId);
380 if (sn != null && sn.getInternetVpnId() != null) {
381 if (neutronvpnUtils.shouldVpnHandleIpVersionChangeToRemove(sn, sn.getInternetVpnId())) {
382 vpnInstanceInternetIpVersionRemoved = true;
383 vpnInstanceInternetUuid = sn.getInternetVpnId();
385 nvpnManager.updateVpnInternetForSubnet(sn, sn.getInternetVpnId(), false);
388 /* Remove ping responder for router interfaces
389 * A router interface reference in a VPN will have to be removed before the host interface references
390 * for that subnet in the VPN are removed. This is to ensure that the FIB Entry of the router interface
391 * is not the last entry to be removed for that subnet in the VPN.
392 * If router interface FIB entry is the last to be removed for a subnet in a VPN , then all the host
393 * interface references in the vpn will already have been cleared, which will cause failures in
394 * cleanup of router interface flows*/
395 nvpnManager.deleteVpnInterface(routerPort.getUuid().getValue(),
396 null /* vpn-id */, null /* wrtConfigTxn*/);
397 final Uuid internetVpnId = vpnInstanceInternetUuid;
398 // update RouterInterfaces map
399 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
401 IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
402 for (FixedIps portIP : portIps) {
403 Subnetmap sn = neutronvpnUtils.getSubnetmap(portIP.getSubnetId());
404 // router Port have either IPv4 or IPv6, never both
405 ipVersion = neutronvpnUtils.getIpVersionFromString(sn.getSubnetIp());
406 String ipValue = portIP.getIpAddress().stringValue();
407 neutronvpnUtils.removeVpnPortFixedIpToPort(vpnId.getValue(), ipValue, confTx);
408 // NOTE: Please donot change the order of calls to removeSubnetFromVpn and
409 // and updateSubnetNodeWithFixedIP
410 nvpnManager.removeSubnetFromVpn(vpnId, portIP.getSubnetId(), internetVpnId);
411 nvpnManager.updateSubnetNodeWithFixedIp(portIP.getSubnetId(), null, null,
414 nvpnManager.removeFromNeutronRouterInterfacesMap(routerId, routerPort.getUuid().getValue());
415 deleteElanInterface(routerPort.getUuid().getValue(), confTx);
416 deleteOfPortInterface(routerPort, confTx);
417 jobCoordinator.enqueueJob(routerId.toString(), () -> {
418 nvpnNatManager.handleSubnetsForExternalRouter(routerId);
419 return Collections.emptyList();
421 if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(ipVersion, routerId, false)) {
422 LOG.debug("vpnInstanceOpDataEntry is getting update with ip address family {} for VPN {}",
423 ipVersion, vpnId.getValue());
424 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, false);
426 }), LOG, "Error handling interface removal");
427 if (vpnInstanceInternetIpVersionRemoved) {
428 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnInstanceInternetUuid.getValue(),
429 IpVersionChoice.IPV6, false);
430 neutronvpnUtils.updateVpnInstanceWithFallback(routerId, vpnInstanceInternetUuid, false);
435 private void handleRouterGatewayUpdated(Port routerGwPort, boolean isRtrGwRemoved) {
436 Uuid routerId = new Uuid(routerGwPort.getDeviceId());
437 Uuid networkId = routerGwPort.getNetworkId();
438 Network network = neutronvpnUtils.getNeutronNetwork(networkId);
439 if (network == null) {
442 boolean isExternal = NeutronvpnUtils.getIsExternal(network);
444 Uuid vpnInternetId = neutronvpnUtils.getVpnForNetwork(networkId);
445 if (vpnInternetId != null) {
446 if (!isRtrGwRemoved) {
447 nvpnManager.updateVpnMaps(vpnInternetId, null, routerId, null, null);
449 List<Subnetmap> snList = neutronvpnUtils.getNeutronRouterSubnetMaps(routerId);
450 for (Subnetmap sn : snList) {
451 if (sn.getNetworkId() == networkId) {
454 if (NeutronvpnUtils.getIpVersionFromString(sn.getSubnetIp()) != IpVersionChoice.IPV6) {
457 if (isRtrGwRemoved) {
458 nvpnManager.removeV6PrivateSubnetToExtNetwork(routerId, vpnInternetId, sn);
460 nvpnManager.addV6PrivateSubnetToExtNetwork(routerId, vpnInternetId, sn);
463 //Update Internet BGP-VPN
464 if (isRtrGwRemoved) {
465 nvpnManager.updateVpnMaps(vpnInternetId, null, null, null, null);
469 elanService.addKnownL3DmacAddress(routerGwPort.getMacAddress().getValue(), networkId.getValue());
471 Router router = neutronvpnUtils.getNeutronRouter(routerId);
472 if (router == null) {
473 LOG.warn("No router found for router GW port {} for router {}", routerGwPort.getUuid().getValue(),
474 routerId.getValue());
476 eventCallbacks.onAddOrUpdate(LogicalDatastoreType.CONFIGURATION,
477 neutronvpnUtils.getNeutronRouterIid(routerId), (unused, newRouter) -> {
478 setupGwMac(newRouter, routerGwPort, routerId);
479 return DataTreeEventCallbackRegistrar.NextAction.UNREGISTER;
480 }, Duration.ofSeconds(3), iid -> {
481 LOG.error("GwPort {} added without Router", routerGwPort.getUuid().getValue());
485 setupGwMac(router, routerGwPort, routerId);
488 private void setupGwMac(Router router, Port routerGwPort, Uuid routerId) {
489 gwMacResolver.sendArpRequestsToExtGateways(router);
490 jobCoordinator.enqueueJob(routerId.toString(), () -> {
491 setExternalGwMac(routerGwPort, routerId);
492 return Collections.emptyList();
496 private void setExternalGwMac(Port routerGwPort, Uuid routerId) {
497 // During full-sync networking-odl syncs routers before ports. As such,
498 // the MAC of the router's gw port is not available to be set when the
499 // router is written. We catch that here.
500 InstanceIdentifier<Routers> routersId = NeutronvpnUtils.buildExtRoutersIdentifier(routerId);
501 Optional<Routers> optionalRouter = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routersId);
502 if (!optionalRouter.isPresent()) {
506 Routers extRouters = optionalRouter.get();
507 if (extRouters.getExtGwMacAddress() != null) {
511 RoutersBuilder builder = new RoutersBuilder(extRouters);
512 builder.setExtGwMacAddress(routerGwPort.getMacAddress().getValue());
513 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, routersId, builder.build());
517 private String getPortHostId(final Port port) {
519 PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
520 if (portBinding != null) {
521 return portBinding.getHostId();
528 private Hostconfig getHostConfig(final Port port) {
529 String hostId = getPortHostId(port);
530 if (hostId == null) {
533 Optional<Hostconfig> hostConfig;
535 hostConfig = this.hostConfigCache.get(hostId);
536 } catch (ReadFailedException e) {
537 LOG.error("failed to read host config from host {}", hostId, e);
540 return hostConfig.orNull();
543 private boolean isPortBound(final Port port) {
544 String hostId = getPortHostId(port);
545 return hostId != null && !hostId.isEmpty();
548 private boolean isPortVnicTypeDirect(Port port) {
549 PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
550 if (portBinding == null || portBinding.getVnicType() == null) {
551 // By default, VNIC_TYPE is NORMAL
554 String vnicType = portBinding.getVnicType().trim().toLowerCase(Locale.getDefault());
555 return vnicType.equals(NeutronConstants.VNIC_TYPE_DIRECT);
558 private boolean isSupportedVnicTypeByHost(final Port port, final String vnicType) {
559 Hostconfig hostConfig = getHostConfig(port);
560 String supportStr = String.format("\"vnic_type\": \"%s\"", vnicType);
561 if (hostConfig != null && hostConfig.getConfig().contains(supportStr)) {
568 private Map<String, JsonElement> unmarshal(final String profile) {
569 if (null == profile) {
572 Gson gson = new Gson();
573 JsonObject jsonObject = gson.fromJson(profile, JsonObject.class);
574 Map<String, JsonElement> map = new HashMap<>();
575 for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
576 map.put(entry.getKey(), entry.getValue());
581 private boolean isPortTypeSwitchdev(final Port port) {
582 if (!isPortVnicTypeDirect(port)) {
586 PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
587 String profile = portBinding.getProfile();
588 if (profile == null || profile.isEmpty()) {
589 LOG.debug("Port {} has no binding:profile values", port.getUuid());
593 Map<String, JsonElement> mapProfile = unmarshal(profile);
594 JsonElement capabilities = mapProfile.get(NeutronConstants.BINDING_PROFILE_CAPABILITIES);
595 LOG.debug("Port {} capabilities: {}", port.getUuid(), capabilities);
596 if (capabilities == null || !capabilities.isJsonArray()) {
597 LOG.debug("binding profile capabilities not in array format: {}", capabilities);
601 JsonArray capabilitiesArray = capabilities.getAsJsonArray();
602 Gson gson = new Gson();
603 JsonElement switchdevElement = gson.fromJson(NeutronConstants.SWITCHDEV, JsonElement.class);
604 return capabilitiesArray.contains(switchdevElement);
608 private void handleNeutronPortCreated(final Port port) {
609 final String portName = port.getUuid().getValue();
610 final Uuid portId = port.getUuid();
611 final List<FixedIps> portIpAddrsList = requireNonNullElse(port.getFixedIps(), Collections.emptyList());
612 if (NeutronConstants.IS_ODL_DHCP_PORT.test(port)) {
615 jobCoordinator.enqueueJob("PORT- " + portName, () -> {
616 // add direct port to subnetMaps config DS
617 if (!(NeutronUtils.isPortVnicTypeNormal(port)
618 || isPortTypeSwitchdev(port)
619 && isSupportedVnicTypeByHost(port, NeutronConstants.VNIC_TYPE_DIRECT))) {
620 for (FixedIps ip: portIpAddrsList) {
621 nvpnManager.updateSubnetmapNodeWithPorts(ip.getSubnetId(), null, portId);
623 LOG.info("Port {} is not a normal and not a direct with switchdev VNIC type ;"
624 + "OF Port interfaces are not created", portName);
625 return Collections.emptyList();
627 return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
628 LOG.info("Of-port-interface creation for port {}", portName);
629 // Create of-port interface for this neutron port
630 String portInterfaceName = createOfPortInterface(port, tx);
631 LOG.debug("Creating ELAN Interface for port {}", portName);
632 createElanInterface(port, portInterfaceName, tx);
633 Set<Uuid> vpnIdList = new HashSet<>();
634 Set<Uuid> routerIds = new HashSet<>();
635 for (FixedIps ip: portIpAddrsList) {
636 Subnetmap subnetMap = nvpnManager.updateSubnetmapNodeWithPorts(ip.getSubnetId(), portId, null);
637 if (subnetMap != null && subnetMap.getInternetVpnId() != null) {
638 if (!vpnIdList.contains(subnetMap.getInternetVpnId())) {
639 vpnIdList.add(subnetMap.getInternetVpnId());
642 if (subnetMap != null && subnetMap.getVpnId() != null) {
643 // can't use NeutronvpnUtils.getVpnForNetwork to optimise here, because it gives BGPVPN id
644 // obtained subnetMaps belongs to one network => vpnId must be the same for each port Ip
645 Uuid vpnId = subnetMap.getVpnId();
647 vpnIdList.add(vpnId);
650 if (subnetMap != null && subnetMap.getRouterId() != null) {
651 routerIds.add(subnetMap.getRouterId());
654 if (!vpnIdList.isEmpty()) {
655 // create new vpn-interface for neutron port
656 LOG.debug("handleNeutronPortCreated: Adding VPN Interface for port {} from network {}", portName,
657 port.getNetworkId().toString());
658 nvpnManager.createVpnInterface(vpnIdList, port, tx);
659 if (!routerIds.isEmpty()) {
660 for (Uuid routerId : routerIds) {
661 nvpnManager.addToNeutronRouterInterfacesMap(routerId,port.getUuid().getValue());
669 private void handleNeutronPortDeleted(final Port port) {
670 final String portName = port.getUuid().getValue();
671 final Uuid portId = port.getUuid();
672 final List<FixedIps> portIpsList = requireNonNullElse(port.getFixedIps(), Collections.emptyList());
673 jobCoordinator.enqueueJob("PORT- " + portName,
674 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
675 if (!(NeutronUtils.isPortVnicTypeNormal(port) || isPortTypeSwitchdev(port))) {
676 for (FixedIps ip : portIpsList) {
677 // remove direct port from subnetMaps config DS
678 nvpnManager.removePortsFromSubnetmapNode(ip.getSubnetId(), null, portId);
680 LOG.info("Port {} is not a normal and not a direct with switchdev VNIC type ;"
681 + "Skipping OF Port interfaces removal", portName);
685 Set<Uuid> routerIds = new HashSet<>();
686 Uuid internetVpnId = null;
687 for (FixedIps ip : portIpsList) {
688 Subnetmap subnetMap = nvpnManager.removePortsFromSubnetmapNode(ip.getSubnetId(), portId, null);
689 if (subnetMap == null) {
692 if (subnetMap.getVpnId() != null) {
693 // can't use NeutronvpnUtils.getVpnForNetwork to optimise here, because it gives BGPVPN id
694 // obtained subnetMaps belongs to one network => vpnId must be the same for each port Ip
695 vpnId = subnetMap.getVpnId();
697 if (subnetMap.getRouterId() != null) {
698 routerIds.add(subnetMap.getRouterId());
700 internetVpnId = subnetMap.getInternetVpnId();
702 if (NeutronConstants.DEVICE_OWNER_GATEWAY_INF.equals(port.getDeviceOwner())
703 || NeutronConstants.DEVICE_OWNER_FLOATING_IP.equals(port.getDeviceOwner())) {
704 String ipAddress = ip.getIpAddress().stringValue();
706 neutronvpnUtils.removeVpnPortFixedIpToPort(vpnId.getValue(), ipAddress, confTx);
708 if (internetVpnId != null) {
709 neutronvpnUtils.removeVpnPortFixedIpToPort(internetVpnId.getValue(),
714 if (vpnId != null || internetVpnId != null) {
715 // remove vpn-interface for this neutron port
716 LOG.debug("removing VPN Interface for port {}", portName);
717 if (!routerIds.isEmpty()) {
718 for (Uuid routerId : routerIds) {
719 nvpnManager.removeFromNeutronRouterInterfacesMap(routerId, portName);
722 nvpnManager.deleteVpnInterface(portName, null /* vpn-id */, confTx);
724 // Remove of-port interface for this neutron port
725 // ELAN interface is also implicitly deleted as part of this operation
726 LOG.debug("Of-port-interface removal for port {}", portName);
727 deleteOfPortInterface(port, confTx);
728 //dissociate fixedIP from floatingIP if associated
729 nvpnManager.dissociatefixedIPFromFloatingIP(port.getUuid().getValue());
734 private void handleNeutronPortUpdated(final Port portoriginal, final Port portupdate) {
735 final List<FixedIps> portoriginalIps = portoriginal.getFixedIps();
736 final List<FixedIps> portupdateIps = portupdate.getFixedIps();
737 if (portoriginalIps == null || portoriginalIps.isEmpty()) {
738 handleNeutronPortCreated(portupdate);
742 if (portupdateIps == null || portupdateIps.isEmpty()) {
743 LOG.info("Ignoring portUpdate (fixed_ip removal) for port {} as this case is handled "
744 + "during subnet deletion event.", portupdate.getUuid().getValue());
748 if (NeutronConstants.IS_ODL_DHCP_PORT.test(portupdate)) {
752 jobCoordinator.enqueueJob("PORT- " + portupdate.getUuid().getValue(),
753 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
754 final List<Uuid> originalSnMapsIds = portoriginalIps.stream().map(FixedIps::getSubnetId)
755 .collect(Collectors.toList());
756 final List<Uuid> updateSnMapsIds = portupdateIps.stream().map(FixedIps::getSubnetId)
757 .collect(Collectors.toList());
758 Set<Uuid> originalRouterIds = new HashSet<>();
759 Set<Uuid> oldVpnIds = new HashSet<>();
760 for (Uuid snId: originalSnMapsIds) {
761 if (!updateSnMapsIds.remove(snId)) {
762 // snId was present in originalSnMapsIds, but not in updateSnMapsIds
763 Subnetmap subnetMapOld = nvpnManager.removePortsFromSubnetmapNode(snId, portoriginal.getUuid(),
765 if (subnetMapOld != null && subnetMapOld.getVpnId() != null) {
766 oldVpnIds.add(subnetMapOld.getVpnId());
768 if (subnetMapOld != null && subnetMapOld.getInternetVpnId() != null) {
769 oldVpnIds.add(subnetMapOld.getInternetVpnId());
771 if (subnetMapOld != null && subnetMapOld.getRouterId() != null) {
772 originalRouterIds.add(subnetMapOld.getRouterId());
776 Set<Uuid> newVpnIds = new HashSet<>();
777 Set<Uuid> newRouterIds = new HashSet<>();
778 for (Uuid snId: updateSnMapsIds) {
779 Subnetmap subnetMapNew = nvpnManager.updateSubnetmapNodeWithPorts(snId, portupdate.getUuid(), null);
780 if (subnetMapNew != null) {
781 if (subnetMapNew.getVpnId() != null) {
782 newVpnIds.add(subnetMapNew.getVpnId());
784 if (subnetMapNew.getInternetVpnId() != null) {
785 newVpnIds.add(subnetMapNew.getInternetVpnId());
787 if (subnetMapNew.getRouterId() != null) {
788 newRouterIds.add(subnetMapNew.getRouterId());
792 if (!oldVpnIds.isEmpty()) {
793 LOG.info("removing VPN Interface for port {}", portoriginal.getUuid().getValue());
794 if (!originalRouterIds.isEmpty()) {
795 for (Uuid routerId : originalRouterIds) {
796 nvpnManager.removeFromNeutronRouterInterfacesMap(routerId,
797 portoriginal.getUuid().getValue());
800 nvpnManager.deleteVpnInterface(portoriginal.getUuid().getValue(),
801 null /* vpn-id */, confTx);
803 if (!newVpnIds.isEmpty()) {
804 LOG.info("Adding VPN Interface for port {}", portupdate.getUuid().getValue());
805 nvpnManager.createVpnInterface(newVpnIds, portupdate, confTx);
806 if (!newRouterIds.isEmpty()) {
807 for (Uuid routerId : newRouterIds) {
808 nvpnManager.addToNeutronRouterInterfacesMap(routerId,portupdate.getUuid().getValue());
816 private InterfaceAclBuilder handlePortSecurityUpdated(Port portOriginal,
817 Port portUpdated, boolean origSecurityEnabled, boolean updatedSecurityEnabled,
818 InterfaceBuilder interfaceBuilder) {
819 InterfaceAclBuilder interfaceAclBuilder = null;
820 if (origSecurityEnabled != updatedSecurityEnabled) {
821 interfaceAclBuilder = new InterfaceAclBuilder();
822 interfaceAclBuilder.setPortSecurityEnabled(updatedSecurityEnabled);
823 if (updatedSecurityEnabled) {
824 // Handle security group enabled
825 NeutronvpnUtils.populateInterfaceAclBuilder(interfaceAclBuilder, portUpdated);
826 neutronvpnUtils.populateSubnetInfo(portUpdated);
828 // Handle security group disabled
829 interfaceAclBuilder.setSecurityGroups(new ArrayList<>());
830 interfaceAclBuilder.setAllowedAddressPairs(new ArrayList<>());
833 if (updatedSecurityEnabled) {
834 // handle SG add/delete delta
835 InterfaceAcl interfaceAcl = interfaceBuilder.augmentation(InterfaceAcl.class);
836 interfaceAclBuilder = new InterfaceAclBuilder(interfaceAcl);
837 interfaceAclBuilder.setSecurityGroups(
838 NeutronvpnUtils.getUpdatedSecurityGroups(interfaceAcl.getSecurityGroups(),
839 portOriginal.getSecurityGroups(), portUpdated.getSecurityGroups()));
840 List<AllowedAddressPairs> updatedAddressPairs = NeutronvpnUtils.getUpdatedAllowedAddressPairs(
841 interfaceAcl.getAllowedAddressPairs(), portOriginal.getAllowedAddressPairs(),
842 portUpdated.getAllowedAddressPairs());
843 interfaceAclBuilder.setAllowedAddressPairs(NeutronvpnUtils.getAllowedAddressPairsForFixedIps(
844 updatedAddressPairs, portOriginal.getMacAddress(), portOriginal.getFixedIps(),
845 portUpdated.getFixedIps()));
847 if (portOriginal.getFixedIps() != null
848 && !portOriginal.getFixedIps().equals(portUpdated.getFixedIps())) {
849 neutronvpnUtils.populateSubnetInfo(portUpdated);
853 return interfaceAclBuilder;
856 private String createOfPortInterface(Port port, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
857 Interface inf = createInterface(port);
858 String infName = inf.getName();
860 InstanceIdentifier<Interface> interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(infName);
862 Optional<Interface> optionalInf =
863 SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
864 interfaceIdentifier);
865 if (!optionalInf.isPresent()) {
866 wrtConfigTxn.put(interfaceIdentifier, inf);
868 LOG.warn("Interface {} is already present", infName);
870 } catch (ReadFailedException e) {
871 LOG.error("failed to create interface {}", infName, e);
876 private Interface createInterface(Port port) {
877 String interfaceName = port.getUuid().getValue();
878 IfL2vlan.L2vlanMode l2VlanMode = IfL2vlan.L2vlanMode.Trunk;
879 InterfaceBuilder interfaceBuilder = new InterfaceBuilder();
880 IfL2vlanBuilder ifL2vlanBuilder = new IfL2vlanBuilder();
882 Network network = neutronvpnUtils.getNeutronNetwork(port.getNetworkId());
883 Boolean isVlanTransparent = network.isVlanTransparent();
884 if (isVlanTransparent != null && isVlanTransparent) {
885 l2VlanMode = IfL2vlan.L2vlanMode.Transparent;
888 ifL2vlanBuilder.setL2vlanMode(l2VlanMode);
890 interfaceBuilder.setEnabled(true).setName(interfaceName).setType(L2vlan.class)
891 .addAugmentation(IfL2vlan.class, ifL2vlanBuilder.build());
893 if (NeutronvpnUtils.getPortSecurityEnabled(port)) {
894 InterfaceAclBuilder interfaceAclBuilder = new InterfaceAclBuilder();
895 interfaceAclBuilder.setPortSecurityEnabled(true);
896 NeutronvpnUtils.populateInterfaceAclBuilder(interfaceAclBuilder, port);
897 interfaceBuilder.addAugmentation(InterfaceAcl.class, interfaceAclBuilder.build());
898 neutronvpnUtils.populateSubnetInfo(port);
900 return interfaceBuilder.build();
903 private void deleteOfPortInterface(Port port, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
904 String name = port.getUuid().getValue();
905 LOG.debug("Removing OFPort Interface {}", name);
906 InstanceIdentifier<Interface> interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(name);
908 Optional<Interface> optionalInf =
909 SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
910 interfaceIdentifier);
911 if (optionalInf.isPresent()) {
912 wrtConfigTxn.delete(interfaceIdentifier);
914 LOG.warn("deleteOfPortInterface: Interface {} is not present", name);
916 } catch (ReadFailedException e) {
917 LOG.error("deleteOfPortInterface: Failed to delete interface {}", name, e);
921 private void createElanInterface(Port port, String name,
922 TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
923 String elanInstanceName = port.getNetworkId().getValue();
924 List<StaticMacEntries> staticMacEntries = NeutronvpnUtils.buildStaticMacEntry(port);
926 InstanceIdentifier<ElanInterface> id = InstanceIdentifier.builder(ElanInterfaces.class).child(ElanInterface
927 .class, new ElanInterfaceKey(name)).build();
928 ElanInterface elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName)
929 .setName(name).setStaticMacEntries(staticMacEntries).withKey(new ElanInterfaceKey(name)).build();
930 wrtConfigTxn.put(id, elanInterface);
931 LOG.debug("Creating new ELan Interface {}", elanInterface);
934 private void deleteElanInterface(String name, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
935 InstanceIdentifier<ElanInterface> id = InstanceIdentifier.builder(ElanInterfaces.class).child(ElanInterface
936 .class, new ElanInterfaceKey(name)).build();
937 wrtConfigTxn.delete(id);
940 // TODO Clean up the exception handling
941 @SuppressWarnings("checkstyle:IllegalCatch")
942 private void addToFloatingIpPortInfo(Uuid floatingIpId, Uuid floatingIpPortId, Uuid floatingIpPortSubnetId, String
943 floatingIpPortMacAddress) {
944 InstanceIdentifier id = NeutronvpnUtils.buildfloatingIpIdToPortMappingIdentifier(floatingIpId);
946 FloatingIpIdToPortMappingBuilder floatingipIdToPortMacMappingBuilder = new
947 FloatingIpIdToPortMappingBuilder().withKey(new FloatingIpIdToPortMappingKey(floatingIpId))
948 .setFloatingIpId(floatingIpId).setFloatingIpPortId(floatingIpPortId)
949 .setFloatingIpPortSubnetId(floatingIpPortSubnetId)
950 .setFloatingIpPortMacAddress(floatingIpPortMacAddress);
951 LOG.debug("Creating floating IP UUID {} to Floating IP neutron port {} mapping in Floating IP"
952 + " Port Info Config DS", floatingIpId.getValue(), floatingIpPortId.getValue());
953 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id,
954 floatingipIdToPortMacMappingBuilder.build());
955 } catch (Exception e) {
956 LOG.error("Creating floating IP UUID {} to Floating IP neutron port {} mapping in Floating IP"
957 + " Port Info Config DS failed", floatingIpId.getValue(), floatingIpPortId.getValue(), e);
961 private Set<FixedIps> getFixedIpSet(List<FixedIps> fixedIps) {
962 return fixedIps != null ? new HashSet<>(fixedIps) : Collections.emptySet();