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 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 // Switchdev ports need to be bounded to a host before creation
208 // in order to validate the supported vnic types from the hostconfig
209 if (isPortTypeSwitchdev(original)
210 && !isPortBound(original)
211 && isPortBound(update)) {
212 handleNeutronPortCreated(update);
214 final String portName = update.getUuid().getValue();
215 Network network = neutronvpnUtils.getNeutronNetwork(update.getNetworkId());
216 LOG.info("Update port {} from network {}", portName, update.getNetworkId().toString());
217 if (network == null || !NeutronvpnUtils.isNetworkTypeSupported(network)) {
218 LOG.warn("neutron vpn received a port update() for a network without a provider extension augmentation "
219 + "or with an unsupported network type for the port {} which is part of network {}",
223 neutronvpnUtils.addToPortCache(update);
225 if ((Strings.isNullOrEmpty(original.getDeviceOwner()) || Strings.isNullOrEmpty(original.getDeviceId())
226 || NeutronConstants.FLOATING_IP_DEVICE_ID_PENDING.equalsIgnoreCase(original.getDeviceId()))
227 && !Strings.isNullOrEmpty(update.getDeviceOwner()) && !Strings.isNullOrEmpty(update.getDeviceId())) {
228 if (NeutronConstants.DEVICE_OWNER_ROUTER_INF.equals(update.getDeviceOwner())) {
229 handleRouterInterfaceAdded(update);
232 if (NeutronConstants.DEVICE_OWNER_GATEWAY_INF.equals(update.getDeviceOwner())) {
233 handleRouterGatewayUpdated(update, false);
234 } else if (NeutronConstants.DEVICE_OWNER_FLOATING_IP.equals(update.getDeviceOwner())) {
235 handleFloatingIpPortUpdated(original, update);
238 Set<FixedIps> oldIPs = getFixedIpSet(original.getFixedIps());
239 Set<FixedIps> newIPs = getFixedIpSet(update.getFixedIps());
240 if (!oldIPs.equals(newIPs)) {
241 handleNeutronPortUpdated(original, update);
245 // check if port security enabled/disabled as part of port update
246 boolean origSecurityEnabled = NeutronvpnUtils.getPortSecurityEnabled(original);
247 boolean updatedSecurityEnabled = NeutronvpnUtils.getPortSecurityEnabled(update);
249 if (origSecurityEnabled || updatedSecurityEnabled) {
250 InstanceIdentifier<Interface> interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(portName);
251 jobCoordinator.enqueueJob("PORT- " + portName,
252 () -> Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
254 Optional<Interface> optionalInf =
255 confTx.read(interfaceIdentifier).get();
256 if (optionalInf.isPresent()) {
257 InterfaceBuilder interfaceBuilder = new InterfaceBuilder(optionalInf.get());
258 InterfaceAcl infAcl = handlePortSecurityUpdated(original, update,
259 origSecurityEnabled, updatedSecurityEnabled, interfaceBuilder).build();
260 interfaceBuilder.addAugmentation(InterfaceAcl.class, infAcl);
261 LOG.info("update: Of-port-interface updation for port {}", portName);
262 // Update OFPort interface for this neutron port
263 confTx.put(interfaceIdentifier, interfaceBuilder.build());
265 LOG.warn("update: Interface {} is not present", portName);
271 private void handleFloatingIpPortUpdated(@Nullable Port original, Port update) {
272 if ((original == null || NeutronConstants.FLOATING_IP_DEVICE_ID_PENDING.equals(original.getDeviceId()))
273 && !NeutronConstants.FLOATING_IP_DEVICE_ID_PENDING.equals(update.getDeviceId())) {
274 // populate floating-ip uuid and floating-ip port attributes (uuid, mac and subnet id for the ONLY
275 // fixed IP) to be used by NAT, depopulated in NATService once mac is retrieved in the removal path
276 addToFloatingIpPortInfo(new Uuid(update.getDeviceId()), update.getUuid(), update.getFixedIps().get(0)
277 .getSubnetId(), update.getMacAddress().getValue());
278 elanService.addKnownL3DmacAddress(update.getMacAddress().getValue(), update.getNetworkId().getValue());
282 private void handleRouterInterfaceAdded(Port routerPort) {
283 if (routerPort.getDeviceId() != null) {
284 Uuid routerId = new Uuid(routerPort.getDeviceId());
285 Uuid infNetworkId = routerPort.getNetworkId();
286 Uuid existingVpnId = neutronvpnUtils.getVpnForNetwork(infNetworkId);
288 elanService.addKnownL3DmacAddress(routerPort.getMacAddress().getValue(), infNetworkId.getValue());
289 if (existingVpnId == null) {
290 Set<Uuid> listVpnIds = new HashSet<>();
291 Uuid vpnId = neutronvpnUtils.getVpnForRouter(routerId, true);
295 listVpnIds.add(vpnId);
296 Uuid internetVpnId = neutronvpnUtils.getInternetvpnUuidBoundToRouterId(routerId);
297 List<Subnetmap> subnetMapList = new ArrayList<>();
298 boolean portIsIpv6 = false;
299 for (FixedIps portIP : requireNonNullElse(routerPort.getFixedIps(),
300 Collections.<FixedIps>emptyList())) {
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 : requireNonNullElse(routerPort.getFixedIps(),
328 Collections.<FixedIps>emptyList())) {
329 String ipValue = portIP.getIpAddress().stringValue();
330 ipVersion = NeutronvpnUtils.getIpVersionFromString(ipValue);
331 if (ipVersion.isIpVersionChosen(IpVersionChoice.IPV4)) {
332 nvpnManager.addSubnetToVpn(vpnId, portIP.getSubnetId(),
333 null /* internet-vpn-id */);
335 nvpnManager.addSubnetToVpn(vpnId, portIP.getSubnetId(), internetVpnId);
337 LOG.trace("NeutronPortChangeListener Add Subnet Gateway IP {} MAC {} Interface {} VPN {}",
338 ipValue, routerPort.getMacAddress(),
339 routerPort.getUuid().getValue(), vpnId.getValue());
341 if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(ipVersion, routerId, true)) {
342 LOG.debug("vpnInstanceOpDataEntry is getting update with ip address family {} for VPN {}",
343 ipVersion, vpnId.getValue());
344 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, true);
346 nvpnManager.addToNeutronRouterInterfacesMap(routerId, routerPort.getUuid().getValue());
347 jobCoordinator.enqueueJob(routerId.toString(), () -> {
348 nvpnNatManager.handleSubnetsForExternalRouter(routerId);
349 return Collections.emptyList();
351 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
353 String portInterfaceName = createOfPortInterface(routerPort, confTx);
354 createElanInterface(routerPort, portInterfaceName, confTx);
355 }), LOG, "Error creating ELAN interface for {}", routerPort);
357 LOG.error("Neutron network {} corresponding to router interface port {} for neutron router {}"
358 + " already associated to VPN {}", infNetworkId.getValue(), routerPort.getUuid().getValue(),
359 routerId.getValue(), existingVpnId.getValue());
364 private void handleRouterInterfaceRemoved(Port routerPort) {
365 if (routerPort.getDeviceId() != null) {
366 Uuid routerId = new Uuid(routerPort.getDeviceId());
367 Uuid infNetworkId = routerPort.getNetworkId();
368 elanService.removeKnownL3DmacAddress(routerPort.getMacAddress().getValue(), infNetworkId.getValue());
369 Uuid vpnId = ObjectUtils.defaultIfNull(neutronvpnUtils.getVpnForRouter(routerId, true),
371 List<FixedIps> portIps = requireNonNullElse(routerPort.getFixedIps(), Collections.emptyList());
372 boolean vpnInstanceInternetIpVersionRemoved = false;
373 Uuid vpnInstanceInternetUuid = null;
374 for (FixedIps portIP : portIps) {
375 // Internet VPN : flush InternetVPN first
376 Uuid subnetId = portIP.getSubnetId();
377 Subnetmap sn = neutronvpnUtils.getSubnetmap(subnetId);
378 if (sn != null && sn.getInternetVpnId() != null) {
379 if (neutronvpnUtils.shouldVpnHandleIpVersionChangeToRemove(sn, sn.getInternetVpnId())) {
380 vpnInstanceInternetIpVersionRemoved = true;
381 vpnInstanceInternetUuid = sn.getInternetVpnId();
383 nvpnManager.updateVpnInternetForSubnet(sn, sn.getInternetVpnId(), false);
386 /* Remove ping responder for router interfaces
387 * A router interface reference in a VPN will have to be removed before the host interface references
388 * for that subnet in the VPN are removed. This is to ensure that the FIB Entry of the router interface
389 * is not the last entry to be removed for that subnet in the VPN.
390 * If router interface FIB entry is the last to be removed for a subnet in a VPN , then all the host
391 * interface references in the vpn will already have been cleared, which will cause failures in
392 * cleanup of router interface flows*/
393 nvpnManager.deleteVpnInterface(routerPort.getUuid().getValue(),
394 null /* vpn-id */, null /* wrtConfigTxn*/);
395 final Uuid internetVpnId = vpnInstanceInternetUuid;
396 // update RouterInterfaces map
397 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
399 IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
400 for (FixedIps portIP : portIps) {
401 Subnetmap sn = neutronvpnUtils.getSubnetmap(portIP.getSubnetId());
402 // router Port have either IPv4 or IPv6, never both
403 ipVersion = neutronvpnUtils.getIpVersionFromString(sn.getSubnetIp());
404 String ipValue = portIP.getIpAddress().stringValue();
405 neutronvpnUtils.removeVpnPortFixedIpToPort(vpnId.getValue(), ipValue, confTx);
406 // NOTE: Please donot change the order of calls to removeSubnetFromVpn and
407 // and updateSubnetNodeWithFixedIP
408 nvpnManager.removeSubnetFromVpn(vpnId, portIP.getSubnetId(), internetVpnId);
409 nvpnManager.updateSubnetNodeWithFixedIp(portIP.getSubnetId(), null, null,
412 nvpnManager.removeFromNeutronRouterInterfacesMap(routerId, routerPort.getUuid().getValue());
413 deleteElanInterface(routerPort.getUuid().getValue(), confTx);
414 deleteOfPortInterface(routerPort, confTx);
415 jobCoordinator.enqueueJob(routerId.toString(), () -> {
416 nvpnNatManager.handleSubnetsForExternalRouter(routerId);
417 return Collections.emptyList();
419 if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(ipVersion, routerId, false)) {
420 LOG.debug("vpnInstanceOpDataEntry is getting update with ip address family {} for VPN {}",
421 ipVersion, vpnId.getValue());
422 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, false);
424 }), LOG, "Error handling interface removal");
425 if (vpnInstanceInternetIpVersionRemoved) {
426 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnInstanceInternetUuid.getValue(),
427 IpVersionChoice.IPV6, false);
428 neutronvpnUtils.updateVpnInstanceWithFallback(routerId, vpnInstanceInternetUuid, false);
433 private void handleRouterGatewayUpdated(Port routerGwPort, boolean isRtrGwRemoved) {
434 Uuid routerId = new Uuid(routerGwPort.getDeviceId());
435 Uuid networkId = routerGwPort.getNetworkId();
436 Network network = neutronvpnUtils.getNeutronNetwork(networkId);
437 if (network == null) {
440 boolean isExternal = NeutronvpnUtils.getIsExternal(network);
442 Uuid vpnInternetId = neutronvpnUtils.getVpnForNetwork(networkId);
443 if (vpnInternetId != null) {
444 if (!isRtrGwRemoved) {
445 nvpnManager.updateVpnMaps(vpnInternetId, null, routerId, null, null);
447 List<Subnetmap> snList = neutronvpnUtils.getNeutronRouterSubnetMaps(routerId);
448 for (Subnetmap sn : snList) {
449 if (sn.getNetworkId() == networkId) {
452 if (NeutronvpnUtils.getIpVersionFromString(sn.getSubnetIp()) != IpVersionChoice.IPV6) {
455 if (isRtrGwRemoved) {
456 nvpnManager.removeV6PrivateSubnetToExtNetwork(routerId, vpnInternetId, sn);
458 nvpnManager.addV6PrivateSubnetToExtNetwork(routerId, vpnInternetId, sn);
461 //Update Internet BGP-VPN
462 if (isRtrGwRemoved) {
463 nvpnManager.updateVpnMaps(vpnInternetId, null, null, null, null);
467 elanService.addKnownL3DmacAddress(routerGwPort.getMacAddress().getValue(), networkId.getValue());
469 Router router = neutronvpnUtils.getNeutronRouter(routerId);
470 if (router == null) {
471 LOG.warn("No router found for router GW port {} for router {}", routerGwPort.getUuid().getValue(),
472 routerId.getValue());
474 eventCallbacks.onAddOrUpdate(LogicalDatastoreType.CONFIGURATION,
475 neutronvpnUtils.getNeutronRouterIid(routerId), (unused, newRouter) -> {
476 setupGwMac(newRouter, routerGwPort, routerId);
477 return DataTreeEventCallbackRegistrar.NextAction.UNREGISTER;
478 }, Duration.ofSeconds(3), iid -> {
479 LOG.error("GwPort {} added without Router", routerGwPort.getUuid().getValue());
483 setupGwMac(router, routerGwPort, routerId);
486 private void setupGwMac(Router router, Port routerGwPort, Uuid routerId) {
487 gwMacResolver.sendArpRequestsToExtGateways(router);
488 jobCoordinator.enqueueJob(routerId.toString(), () -> {
489 setExternalGwMac(routerGwPort, routerId);
490 return Collections.emptyList();
494 private void setExternalGwMac(Port routerGwPort, Uuid routerId) {
495 // During full-sync networking-odl syncs routers before ports. As such,
496 // the MAC of the router's gw port is not available to be set when the
497 // router is written. We catch that here.
498 InstanceIdentifier<Routers> routersId = NeutronvpnUtils.buildExtRoutersIdentifier(routerId);
499 Optional<Routers> optionalRouter = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routersId);
500 if (!optionalRouter.isPresent()) {
504 Routers extRouters = optionalRouter.get();
505 if (extRouters.getExtGwMacAddress() != null) {
509 RoutersBuilder builder = new RoutersBuilder(extRouters);
510 builder.setExtGwMacAddress(routerGwPort.getMacAddress().getValue());
511 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, routersId, builder.build());
515 private String getPortHostId(final Port port) {
517 PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
518 if (portBinding != null) {
519 return portBinding.getHostId();
526 private Hostconfig getHostConfig(final Port port) {
527 String hostId = getPortHostId(port);
528 if (hostId == null) {
531 Optional<Hostconfig> hostConfig;
533 hostConfig = this.hostConfigCache.get(hostId);
534 } catch (ReadFailedException e) {
535 LOG.error("failed to read host config from host {}", hostId, e);
538 return hostConfig.orNull();
541 private boolean isPortBound(final Port port) {
542 String hostId = getPortHostId(port);
543 return hostId != null && !hostId.isEmpty();
546 private boolean isPortVnicTypeDirect(Port port) {
547 PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
548 if (portBinding == null || portBinding.getVnicType() == null) {
549 // By default, VNIC_TYPE is NORMAL
552 String vnicType = portBinding.getVnicType().trim().toLowerCase(Locale.getDefault());
553 return vnicType.equals(NeutronConstants.VNIC_TYPE_DIRECT);
556 private boolean isSupportedVnicTypeByHost(final Port port, final String vnicType) {
557 Hostconfig hostConfig = getHostConfig(port);
558 String supportStr = String.format("\"vnic_type\": \"%s\"", vnicType);
559 if (hostConfig != null && hostConfig.getConfig().contains(supportStr)) {
566 private Map<String, JsonElement> unmarshal(final String profile) {
567 if (null == profile) {
570 Gson gson = new Gson();
571 JsonObject jsonObject = gson.fromJson(profile, JsonObject.class);
572 Map<String, JsonElement> map = new HashMap<>();
573 for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
574 map.put(entry.getKey(), entry.getValue());
579 private boolean isPortTypeSwitchdev(final Port port) {
580 if (!isPortVnicTypeDirect(port)) {
584 PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
585 String profile = portBinding.getProfile();
586 if (profile == null || profile.isEmpty()) {
587 LOG.debug("Port {} has no binding:profile values", port.getUuid());
591 Map<String, JsonElement> mapProfile = unmarshal(profile);
592 JsonElement capabilities = mapProfile.get(NeutronConstants.BINDING_PROFILE_CAPABILITIES);
593 LOG.debug("Port {} capabilities: {}", port.getUuid(), capabilities);
594 if (capabilities == null || !capabilities.isJsonArray()) {
595 LOG.debug("binding profile capabilities not in array format: {}", capabilities);
599 JsonArray capabilitiesArray = capabilities.getAsJsonArray();
600 Gson gson = new Gson();
601 JsonElement switchdevElement = gson.fromJson(NeutronConstants.SWITCHDEV, JsonElement.class);
602 return capabilitiesArray.contains(switchdevElement);
606 private void handleNeutronPortCreated(final Port port) {
607 final String portName = port.getUuid().getValue();
608 final Uuid portId = port.getUuid();
609 final List<FixedIps> portIpAddrsList = requireNonNullElse(port.getFixedIps(), Collections.emptyList());
610 if (NeutronConstants.IS_ODL_DHCP_PORT.test(port)) {
613 jobCoordinator.enqueueJob("PORT- " + portName, () -> {
614 // add direct port to subnetMaps config DS
615 if (!(NeutronUtils.isPortVnicTypeNormal(port)
616 || isPortTypeSwitchdev(port)
617 && isSupportedVnicTypeByHost(port, NeutronConstants.VNIC_TYPE_DIRECT))) {
618 for (FixedIps ip: portIpAddrsList) {
619 nvpnManager.updateSubnetmapNodeWithPorts(ip.getSubnetId(), null, portId);
621 LOG.info("Port {} is not a normal and not a direct with switchdev VNIC type ;"
622 + "OF Port interfaces are not created", portName);
623 return Collections.emptyList();
625 return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
626 LOG.info("Of-port-interface creation for port {}", portName);
627 // Create of-port interface for this neutron port
628 String portInterfaceName = createOfPortInterface(port, tx);
629 LOG.debug("Creating ELAN Interface for port {}", portName);
630 createElanInterface(port, portInterfaceName, tx);
631 Set<Uuid> vpnIdList = new HashSet<>();
632 Set<Uuid> routerIds = new HashSet<>();
633 for (FixedIps ip: portIpAddrsList) {
634 Subnetmap subnetMap = nvpnManager.updateSubnetmapNodeWithPorts(ip.getSubnetId(), portId, null);
635 if (subnetMap != null && subnetMap.getInternetVpnId() != null) {
636 if (!vpnIdList.contains(subnetMap.getInternetVpnId())) {
637 vpnIdList.add(subnetMap.getInternetVpnId());
640 if (subnetMap != null && subnetMap.getVpnId() != null) {
641 // can't use NeutronvpnUtils.getVpnForNetwork to optimise here, because it gives BGPVPN id
642 // obtained subnetMaps belongs to one network => vpnId must be the same for each port Ip
643 Uuid vpnId = subnetMap.getVpnId();
645 vpnIdList.add(vpnId);
648 if (subnetMap != null && subnetMap.getRouterId() != null) {
649 routerIds.add(subnetMap.getRouterId());
652 if (!vpnIdList.isEmpty()) {
653 // create new vpn-interface for neutron port
654 LOG.debug("handleNeutronPortCreated: Adding VPN Interface for port {} from network {}", portName,
655 port.getNetworkId().toString());
656 nvpnManager.createVpnInterface(vpnIdList, port, tx);
657 if (!routerIds.isEmpty()) {
658 for (Uuid routerId : routerIds) {
659 nvpnManager.addToNeutronRouterInterfacesMap(routerId,port.getUuid().getValue());
667 private void handleNeutronPortDeleted(final Port port) {
668 final String portName = port.getUuid().getValue();
669 final Uuid portId = port.getUuid();
670 final List<FixedIps> portIpsList = requireNonNullElse(port.getFixedIps(), Collections.emptyList());
671 jobCoordinator.enqueueJob("PORT- " + portName,
672 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
673 if (!(NeutronUtils.isPortVnicTypeNormal(port) || isPortTypeSwitchdev(port))) {
674 for (FixedIps ip : portIpsList) {
675 // remove direct port from subnetMaps config DS
676 nvpnManager.removePortsFromSubnetmapNode(ip.getSubnetId(), null, portId);
678 LOG.info("Port {} is not a normal and not a direct with switchdev VNIC type ;"
679 + "Skipping OF Port interfaces removal", portName);
683 Set<Uuid> routerIds = new HashSet<>();
684 Uuid internetVpnId = null;
685 for (FixedIps ip : portIpsList) {
686 Subnetmap subnetMap = nvpnManager.removePortsFromSubnetmapNode(ip.getSubnetId(), portId, null);
687 if (subnetMap == null) {
690 if (subnetMap.getVpnId() != null) {
691 // can't use NeutronvpnUtils.getVpnForNetwork to optimise here, because it gives BGPVPN id
692 // obtained subnetMaps belongs to one network => vpnId must be the same for each port Ip
693 vpnId = subnetMap.getVpnId();
695 if (subnetMap.getRouterId() != null) {
696 routerIds.add(subnetMap.getRouterId());
698 internetVpnId = subnetMap.getInternetVpnId();
700 if (NeutronConstants.DEVICE_OWNER_GATEWAY_INF.equals(port.getDeviceOwner())
701 || NeutronConstants.DEVICE_OWNER_FLOATING_IP.equals(port.getDeviceOwner())) {
702 String ipAddress = ip.getIpAddress().stringValue();
704 neutronvpnUtils.removeVpnPortFixedIpToPort(vpnId.getValue(), ipAddress, confTx);
706 if (internetVpnId != null) {
707 neutronvpnUtils.removeVpnPortFixedIpToPort(internetVpnId.getValue(),
712 if (vpnId != null || internetVpnId != null) {
713 // remove vpn-interface for this neutron port
714 LOG.debug("removing VPN Interface for port {}", portName);
715 if (!routerIds.isEmpty()) {
716 for (Uuid routerId : routerIds) {
717 nvpnManager.removeFromNeutronRouterInterfacesMap(routerId, portName);
720 nvpnManager.deleteVpnInterface(portName, null /* vpn-id */, confTx);
722 // Remove of-port interface for this neutron port
723 // ELAN interface is also implicitly deleted as part of this operation
724 LOG.debug("Of-port-interface removal for port {}", portName);
725 deleteOfPortInterface(port, confTx);
726 //dissociate fixedIP from floatingIP if associated
727 nvpnManager.dissociatefixedIPFromFloatingIP(port.getUuid().getValue());
732 private void handleNeutronPortUpdated(final Port portoriginal, final Port portupdate) {
733 final List<FixedIps> portoriginalIps = portoriginal.getFixedIps();
734 final List<FixedIps> portupdateIps = portupdate.getFixedIps();
735 if (portoriginalIps == null || portoriginalIps.isEmpty()) {
736 handleNeutronPortCreated(portupdate);
740 if (portupdateIps == null || portupdateIps.isEmpty()) {
741 LOG.info("Ignoring portUpdate (fixed_ip removal) for port {} as this case is handled "
742 + "during subnet deletion event.", portupdate.getUuid().getValue());
746 if (NeutronConstants.IS_ODL_DHCP_PORT.test(portupdate)) {
750 jobCoordinator.enqueueJob("PORT- " + portupdate.getUuid().getValue(),
751 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
752 final List<Uuid> originalSnMapsIds = portoriginalIps.stream().map(FixedIps::getSubnetId)
753 .collect(Collectors.toList());
754 final List<Uuid> updateSnMapsIds = portupdateIps.stream().map(FixedIps::getSubnetId)
755 .collect(Collectors.toList());
756 Set<Uuid> originalRouterIds = new HashSet<>();
757 Set<Uuid> oldVpnIds = new HashSet<>();
758 for (Uuid snId: originalSnMapsIds) {
759 if (!updateSnMapsIds.remove(snId)) {
760 // snId was present in originalSnMapsIds, but not in updateSnMapsIds
761 Subnetmap subnetMapOld = nvpnManager.removePortsFromSubnetmapNode(snId, portoriginal.getUuid(),
763 if (subnetMapOld != null && subnetMapOld.getVpnId() != null) {
764 oldVpnIds.add(subnetMapOld.getVpnId());
766 if (subnetMapOld != null && subnetMapOld.getInternetVpnId() != null) {
767 oldVpnIds.add(subnetMapOld.getInternetVpnId());
769 if (subnetMapOld != null && subnetMapOld.getRouterId() != null) {
770 originalRouterIds.add(subnetMapOld.getRouterId());
774 Set<Uuid> newVpnIds = new HashSet<>();
775 Set<Uuid> newRouterIds = new HashSet<>();
776 for (Uuid snId: updateSnMapsIds) {
777 Subnetmap subnetMapNew = nvpnManager.updateSubnetmapNodeWithPorts(snId, portupdate.getUuid(), null);
778 if (subnetMapNew != null) {
779 if (subnetMapNew.getVpnId() != null) {
780 newVpnIds.add(subnetMapNew.getVpnId());
782 if (subnetMapNew.getInternetVpnId() != null) {
783 newVpnIds.add(subnetMapNew.getInternetVpnId());
785 if (subnetMapNew.getRouterId() != null) {
786 newRouterIds.add(subnetMapNew.getRouterId());
790 if (!oldVpnIds.isEmpty()) {
791 LOG.info("removing VPN Interface for port {}", portoriginal.getUuid().getValue());
792 if (!originalRouterIds.isEmpty()) {
793 for (Uuid routerId : originalRouterIds) {
794 nvpnManager.removeFromNeutronRouterInterfacesMap(routerId,
795 portoriginal.getUuid().getValue());
798 nvpnManager.deleteVpnInterface(portoriginal.getUuid().getValue(),
799 null /* vpn-id */, confTx);
801 if (!newVpnIds.isEmpty()) {
802 LOG.info("Adding VPN Interface for port {}", portupdate.getUuid().getValue());
803 nvpnManager.createVpnInterface(newVpnIds, portupdate, confTx);
804 if (!newRouterIds.isEmpty()) {
805 for (Uuid routerId : newRouterIds) {
806 nvpnManager.addToNeutronRouterInterfacesMap(routerId,portupdate.getUuid().getValue());
814 private InterfaceAclBuilder handlePortSecurityUpdated(Port portOriginal,
815 Port portUpdated, boolean origSecurityEnabled, boolean updatedSecurityEnabled,
816 InterfaceBuilder interfaceBuilder) {
817 InterfaceAclBuilder interfaceAclBuilder = null;
818 if (origSecurityEnabled != updatedSecurityEnabled) {
819 interfaceAclBuilder = new InterfaceAclBuilder();
820 interfaceAclBuilder.setPortSecurityEnabled(updatedSecurityEnabled);
821 if (updatedSecurityEnabled) {
822 // Handle security group enabled
823 NeutronvpnUtils.populateInterfaceAclBuilder(interfaceAclBuilder, portUpdated);
824 neutronvpnUtils.populateSubnetInfo(portUpdated);
826 // Handle security group disabled
827 interfaceAclBuilder.setSecurityGroups(new ArrayList<>());
828 interfaceAclBuilder.setAllowedAddressPairs(new ArrayList<>());
831 if (updatedSecurityEnabled) {
832 // handle SG add/delete delta
833 InterfaceAcl interfaceAcl = interfaceBuilder.augmentation(InterfaceAcl.class);
834 interfaceAclBuilder = new InterfaceAclBuilder(interfaceAcl);
835 interfaceAclBuilder.setSecurityGroups(
836 NeutronvpnUtils.getUpdatedSecurityGroups(interfaceAcl.getSecurityGroups(),
837 portOriginal.getSecurityGroups(), portUpdated.getSecurityGroups()));
838 List<AllowedAddressPairs> updatedAddressPairs = NeutronvpnUtils.getUpdatedAllowedAddressPairs(
839 interfaceAcl.getAllowedAddressPairs(), portOriginal.getAllowedAddressPairs(),
840 portUpdated.getAllowedAddressPairs());
841 interfaceAclBuilder.setAllowedAddressPairs(NeutronvpnUtils.getAllowedAddressPairsForFixedIps(
842 updatedAddressPairs, portOriginal.getMacAddress(), portOriginal.getFixedIps(),
843 portUpdated.getFixedIps()));
845 if (portOriginal.getFixedIps() != null
846 && !portOriginal.getFixedIps().equals(portUpdated.getFixedIps())) {
847 neutronvpnUtils.populateSubnetInfo(portUpdated);
851 return interfaceAclBuilder;
854 private String createOfPortInterface(Port port, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
855 Interface inf = createInterface(port);
856 String infName = inf.getName();
858 InstanceIdentifier<Interface> interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(infName);
860 Optional<Interface> optionalInf =
861 SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
862 interfaceIdentifier);
863 if (!optionalInf.isPresent()) {
864 wrtConfigTxn.put(interfaceIdentifier, inf);
866 LOG.warn("Interface {} is already present", infName);
868 } catch (ReadFailedException e) {
869 LOG.error("failed to create interface {}", infName, e);
874 private Interface createInterface(Port port) {
875 String interfaceName = port.getUuid().getValue();
876 IfL2vlan.L2vlanMode l2VlanMode = IfL2vlan.L2vlanMode.Trunk;
877 InterfaceBuilder interfaceBuilder = new InterfaceBuilder();
878 IfL2vlanBuilder ifL2vlanBuilder = new IfL2vlanBuilder();
880 Network network = neutronvpnUtils.getNeutronNetwork(port.getNetworkId());
881 Boolean isVlanTransparent = network.isVlanTransparent();
882 if (isVlanTransparent != null && isVlanTransparent) {
883 l2VlanMode = IfL2vlan.L2vlanMode.Transparent;
886 ifL2vlanBuilder.setL2vlanMode(l2VlanMode);
888 interfaceBuilder.setEnabled(true).setName(interfaceName).setType(L2vlan.class)
889 .addAugmentation(IfL2vlan.class, ifL2vlanBuilder.build());
891 if (NeutronvpnUtils.getPortSecurityEnabled(port)) {
892 InterfaceAclBuilder interfaceAclBuilder = new InterfaceAclBuilder();
893 interfaceAclBuilder.setPortSecurityEnabled(true);
894 NeutronvpnUtils.populateInterfaceAclBuilder(interfaceAclBuilder, port);
895 interfaceBuilder.addAugmentation(InterfaceAcl.class, interfaceAclBuilder.build());
896 neutronvpnUtils.populateSubnetInfo(port);
898 return interfaceBuilder.build();
901 private void deleteOfPortInterface(Port port, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
902 String name = port.getUuid().getValue();
903 LOG.debug("Removing OFPort Interface {}", name);
904 InstanceIdentifier<Interface> interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(name);
906 Optional<Interface> optionalInf =
907 SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
908 interfaceIdentifier);
909 if (optionalInf.isPresent()) {
910 wrtConfigTxn.delete(interfaceIdentifier);
912 LOG.warn("deleteOfPortInterface: Interface {} is not present", name);
914 } catch (ReadFailedException e) {
915 LOG.error("deleteOfPortInterface: Failed to delete interface {}", name, e);
919 private void createElanInterface(Port port, String name,
920 TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
921 String elanInstanceName = port.getNetworkId().getValue();
922 List<StaticMacEntries> staticMacEntries = NeutronvpnUtils.buildStaticMacEntry(port);
924 InstanceIdentifier<ElanInterface> id = InstanceIdentifier.builder(ElanInterfaces.class).child(ElanInterface
925 .class, new ElanInterfaceKey(name)).build();
926 ElanInterface elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName)
927 .setName(name).setStaticMacEntries(staticMacEntries).withKey(new ElanInterfaceKey(name)).build();
928 wrtConfigTxn.put(id, elanInterface);
929 LOG.debug("Creating new ELan Interface {}", elanInterface);
932 private void deleteElanInterface(String name, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
933 InstanceIdentifier<ElanInterface> id = InstanceIdentifier.builder(ElanInterfaces.class).child(ElanInterface
934 .class, new ElanInterfaceKey(name)).build();
935 wrtConfigTxn.delete(id);
938 // TODO Clean up the exception handling
939 @SuppressWarnings("checkstyle:IllegalCatch")
940 private void addToFloatingIpPortInfo(Uuid floatingIpId, Uuid floatingIpPortId, Uuid floatingIpPortSubnetId, String
941 floatingIpPortMacAddress) {
942 InstanceIdentifier id = NeutronvpnUtils.buildfloatingIpIdToPortMappingIdentifier(floatingIpId);
944 FloatingIpIdToPortMappingBuilder floatingipIdToPortMacMappingBuilder = new
945 FloatingIpIdToPortMappingBuilder().withKey(new FloatingIpIdToPortMappingKey(floatingIpId))
946 .setFloatingIpId(floatingIpId).setFloatingIpPortId(floatingIpPortId)
947 .setFloatingIpPortSubnetId(floatingIpPortSubnetId)
948 .setFloatingIpPortMacAddress(floatingIpPortMacAddress);
949 LOG.debug("Creating floating IP UUID {} to Floating IP neutron port {} mapping in Floating IP"
950 + " Port Info Config DS", floatingIpId.getValue(), floatingIpPortId.getValue());
951 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id,
952 floatingipIdToPortMacMappingBuilder.build());
953 } catch (Exception e) {
954 LOG.error("Creating floating IP UUID {} to Floating IP neutron port {} mapping in Floating IP"
955 + " Port Info Config DS failed", floatingIpId.getValue(), floatingIpPortId.getValue(), e);
959 private Set<FixedIps> getFixedIpSet(List<FixedIps> fixedIps) {
960 return fixedIps != null ? new HashSet<>(fixedIps) : Collections.emptySet();