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.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.RoutersBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.port.info.FloatingIpIdToPortMappingBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.port.info.FloatingIpIdToPortMappingKey;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.PortBindingExtension;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.hostconfig.rev150712.hostconfig.attributes.hostconfigs.Hostconfig;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
78 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
79 import org.slf4j.Logger;
80 import org.slf4j.LoggerFactory;
83 public class NeutronPortChangeListener extends AsyncDataTreeChangeListenerBase<Port, NeutronPortChangeListener> {
84 private static final Logger LOG = LoggerFactory.getLogger(NeutronPortChangeListener.class);
85 private final DataBroker dataBroker;
86 private final ManagedNewTransactionRunner txRunner;
87 private final NeutronvpnManager nvpnManager;
88 private final NeutronvpnNatManager nvpnNatManager;
89 private final NeutronSubnetGwMacResolver gwMacResolver;
90 private final IElanService elanService;
91 private final JobCoordinator jobCoordinator;
92 private final NeutronvpnUtils neutronvpnUtils;
93 private final HostConfigCache hostConfigCache;
94 private final DataTreeEventCallbackRegistrar eventCallbacks;
96 public NeutronPortChangeListener(final DataBroker dataBroker,
97 final NeutronvpnManager neutronvpnManager,
98 final NeutronvpnNatManager neutronvpnNatManager,
99 final NeutronSubnetGwMacResolver gwMacResolver,
100 final IElanService elanService,
101 final JobCoordinator jobCoordinator,
102 final NeutronvpnUtils neutronvpnUtils,
103 final HostConfigCache hostConfigCache,
104 final DataTreeEventCallbackRegistrar dataTreeEventCallbackRegistrar) {
105 super(Port.class, NeutronPortChangeListener.class);
106 this.dataBroker = dataBroker;
107 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
108 nvpnManager = neutronvpnManager;
109 nvpnNatManager = neutronvpnNatManager;
110 this.gwMacResolver = gwMacResolver;
111 this.elanService = elanService;
112 this.jobCoordinator = jobCoordinator;
113 this.neutronvpnUtils = neutronvpnUtils;
114 this.hostConfigCache = hostConfigCache;
115 this.eventCallbacks = dataTreeEventCallbackRegistrar;
121 LOG.info("{} init", getClass().getSimpleName());
122 registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
126 protected InstanceIdentifier<Port> getWildCardPath() {
127 return InstanceIdentifier.create(Neutron.class).child(Ports.class).child(Port.class);
131 protected NeutronPortChangeListener getDataTreeChangeListener() {
132 return NeutronPortChangeListener.this;
137 protected void add(InstanceIdentifier<Port> identifier, 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 // 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 : requireNonNullElse(routerPort.getFixedIps(),
301 Collections.<FixedIps>emptyList())) {
302 // NOTE: Please donot change the order of calls to updateSubnetNodeWithFixedIP
303 // and addSubnetToVpn here
304 if (internetVpnId != null
305 && portIP.getIpAddress().getIpv6Address() != null) {
308 String ipValue = portIP.getIpAddress().stringValue();
309 Uuid subnetId = portIP.getSubnetId();
310 nvpnManager.updateSubnetNodeWithFixedIp(subnetId, routerId,
311 routerPort.getUuid(), ipValue, routerPort.getMacAddress().getValue(), vpnId);
312 Subnetmap sn = neutronvpnUtils.getSubnetmap(subnetId);
313 subnetMapList.add(sn);
316 listVpnIds.add(internetVpnId);
317 if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(
318 IpVersionChoice.IPV6, routerId, true)) {
319 neutronvpnUtils.updateVpnInstanceWithIpFamily(internetVpnId.getValue(), IpVersionChoice.IPV6,
321 neutronvpnUtils.updateVpnInstanceWithFallback(internetVpnId, true);
324 if (! subnetMapList.isEmpty()) {
325 nvpnManager.createVpnInterface(listVpnIds, routerPort, null);
327 IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
328 for (FixedIps portIP : requireNonNullElse(routerPort.getFixedIps(),
329 Collections.<FixedIps>emptyList())) {
330 String ipValue = portIP.getIpAddress().stringValue();
331 ipVersion = NeutronvpnUtils.getIpVersionFromString(ipValue);
332 if (ipVersion.isIpVersionChosen(IpVersionChoice.IPV4)) {
333 nvpnManager.addSubnetToVpn(vpnId, portIP.getSubnetId(),
334 null /* internet-vpn-id */);
336 nvpnManager.addSubnetToVpn(vpnId, portIP.getSubnetId(), internetVpnId);
338 LOG.trace("NeutronPortChangeListener Add Subnet Gateway IP {} MAC {} Interface {} VPN {}",
339 ipValue, routerPort.getMacAddress(),
340 routerPort.getUuid().getValue(), vpnId.getValue());
342 if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(ipVersion, routerId, true)) {
343 LOG.debug("vpnInstanceOpDataEntry is getting update with ip address family {} for VPN {}",
344 ipVersion, vpnId.getValue());
345 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, true);
347 nvpnManager.addToNeutronRouterInterfacesMap(routerId, routerPort.getUuid().getValue());
348 jobCoordinator.enqueueJob(routerId.toString(), () -> {
349 nvpnNatManager.handleSubnetsForExternalRouter(routerId);
350 return Collections.emptyList();
352 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
354 String portInterfaceName = createOfPortInterface(routerPort, confTx);
355 createElanInterface(routerPort, portInterfaceName, confTx);
356 }), LOG, "Error creating ELAN interface for {}", routerPort);
358 LOG.error("Neutron network {} corresponding to router interface port {} for neutron router {}"
359 + " already associated to VPN {}", infNetworkId.getValue(), routerPort.getUuid().getValue(),
360 routerId.getValue(), existingVpnId.getValue());
365 private void handleRouterInterfaceRemoved(Port routerPort) {
366 if (routerPort.getDeviceId() != null) {
367 Uuid routerId = new Uuid(routerPort.getDeviceId());
368 Uuid infNetworkId = routerPort.getNetworkId();
369 elanService.removeKnownL3DmacAddress(routerPort.getMacAddress().getValue(), infNetworkId.getValue());
370 Uuid vpnId = ObjectUtils.defaultIfNull(neutronvpnUtils.getVpnForRouter(routerId, true),
372 List<FixedIps> portIps = requireNonNullElse(routerPort.getFixedIps(), Collections.emptyList());
373 boolean vpnInstanceInternetIpVersionRemoved = false;
374 Uuid vpnInstanceInternetUuid = null;
375 for (FixedIps portIP : portIps) {
376 // Internet VPN : flush InternetVPN first
377 Uuid subnetId = portIP.getSubnetId();
378 Subnetmap sn = neutronvpnUtils.getSubnetmap(subnetId);
379 if (sn != null && sn.getInternetVpnId() != null) {
380 if (neutronvpnUtils.shouldVpnHandleIpVersionChangeToRemove(sn, sn.getInternetVpnId())) {
381 vpnInstanceInternetIpVersionRemoved = true;
382 vpnInstanceInternetUuid = sn.getInternetVpnId();
384 nvpnManager.updateVpnInternetForSubnet(sn, sn.getInternetVpnId(), false);
387 /* Remove ping responder for router interfaces
388 * A router interface reference in a VPN will have to be removed before the host interface references
389 * for that subnet in the VPN are removed. This is to ensure that the FIB Entry of the router interface
390 * is not the last entry to be removed for that subnet in the VPN.
391 * If router interface FIB entry is the last to be removed for a subnet in a VPN , then all the host
392 * interface references in the vpn will already have been cleared, which will cause failures in
393 * cleanup of router interface flows*/
394 nvpnManager.deleteVpnInterface(routerPort.getUuid().getValue(),
395 null /* vpn-id */, null /* wrtConfigTxn*/);
396 final Uuid internetVpnId = vpnInstanceInternetUuid;
397 // update RouterInterfaces map
398 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
400 IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
401 for (FixedIps portIP : portIps) {
402 Subnetmap sn = neutronvpnUtils.getSubnetmap(portIP.getSubnetId());
403 // router Port have either IPv4 or IPv6, never both
404 ipVersion = neutronvpnUtils.getIpVersionFromString(sn.getSubnetIp());
405 String ipValue = portIP.getIpAddress().stringValue();
406 neutronvpnUtils.removeVpnPortFixedIpToPort(vpnId.getValue(), ipValue, confTx);
407 // NOTE: Please donot change the order of calls to removeSubnetFromVpn and
408 // and updateSubnetNodeWithFixedIP
409 nvpnManager.removeSubnetFromVpn(vpnId, portIP.getSubnetId(), internetVpnId);
410 nvpnManager.updateSubnetNodeWithFixedIp(portIP.getSubnetId(), null, null,
413 nvpnManager.removeFromNeutronRouterInterfacesMap(routerId, routerPort.getUuid().getValue());
414 deleteElanInterface(routerPort.getUuid().getValue(), confTx);
415 deleteOfPortInterface(routerPort, confTx);
416 jobCoordinator.enqueueJob(routerId.toString(), () -> {
417 nvpnNatManager.handleSubnetsForExternalRouter(routerId);
418 return Collections.emptyList();
420 if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(ipVersion, routerId, false)) {
421 LOG.debug("vpnInstanceOpDataEntry is getting update with ip address family {} for VPN {}",
422 ipVersion, vpnId.getValue());
423 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, false);
425 }), LOG, "Error handling interface removal");
426 if (vpnInstanceInternetIpVersionRemoved) {
427 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnInstanceInternetUuid.getValue(),
428 IpVersionChoice.IPV6, false);
429 neutronvpnUtils.updateVpnInstanceWithFallback(vpnInstanceInternetUuid, false);
434 private void handleRouterGatewayUpdated(Port routerGwPort, boolean isRtrGwRemoved) {
435 Uuid routerId = new Uuid(routerGwPort.getDeviceId());
436 Uuid networkId = routerGwPort.getNetworkId();
437 Network network = neutronvpnUtils.getNeutronNetwork(networkId);
438 if (network == null) {
441 boolean isExternal = NeutronvpnUtils.getIsExternal(network);
443 Uuid vpnInternetId = neutronvpnUtils.getVpnForNetwork(networkId);
444 if (vpnInternetId != null) {
445 if (isRtrGwRemoved) {
446 //Set VPN type BGPVPNExternal from BGPVPNInternet for removal case
447 neutronvpnUtils.updateVpnInstanceOpWithType(VpnInstanceOpDataEntry.BgpvpnType.BGPVPNExternal,
450 //Set VPN type BGPVPNInternet from BGPVPNExternal for add case
451 neutronvpnUtils.updateVpnInstanceOpWithType(VpnInstanceOpDataEntry.BgpvpnType.BGPVPNInternet,
453 nvpnManager.updateVpnMaps(vpnInternetId, null, routerId, null, null);
455 List<Subnetmap> snList = neutronvpnUtils.getNeutronRouterSubnetMaps(routerId);
456 for (Subnetmap sn : snList) {
457 if (sn.getNetworkId() == networkId) {
460 if (NeutronvpnUtils.getIpVersionFromString(sn.getSubnetIp()) != IpVersionChoice.IPV6) {
463 if (isRtrGwRemoved) {
464 nvpnManager.removeV6PrivateSubnetToExtNetwork(routerId, vpnInternetId, sn);
466 nvpnManager.addV6PrivateSubnetToExtNetwork(routerId, vpnInternetId, sn);
469 //Update Internet BGP-VPN
470 if (isRtrGwRemoved) {
471 nvpnManager.updateVpnMaps(vpnInternetId, null, null, null, null);
475 elanService.addKnownL3DmacAddress(routerGwPort.getMacAddress().getValue(), networkId.getValue());
477 Router router = neutronvpnUtils.getNeutronRouter(routerId);
478 if (router == null) {
479 LOG.warn("No router found for router GW port {} for router {}", routerGwPort.getUuid().getValue(),
480 routerId.getValue());
482 eventCallbacks.onAddOrUpdate(LogicalDatastoreType.CONFIGURATION,
483 neutronvpnUtils.getNeutronRouterIid(routerId), (unused, newRouter) -> {
484 setupGwMac(newRouter, routerGwPort, routerId);
485 return DataTreeEventCallbackRegistrar.NextAction.UNREGISTER;
486 }, Duration.ofSeconds(3), iid -> {
487 LOG.error("GwPort {} added without Router", routerGwPort.getUuid().getValue());
491 setupGwMac(router, routerGwPort, routerId);
494 private void setupGwMac(Router router, Port routerGwPort, Uuid routerId) {
495 gwMacResolver.sendArpRequestsToExtGateways(router);
496 jobCoordinator.enqueueJob(routerId.toString(), () -> {
497 setExternalGwMac(routerGwPort, routerId);
498 return Collections.emptyList();
502 private void setExternalGwMac(Port routerGwPort, Uuid routerId) {
503 // During full-sync networking-odl syncs routers before ports. As such,
504 // the MAC of the router's gw port is not available to be set when the
505 // router is written. We catch that here.
506 InstanceIdentifier<Routers> routersId = NeutronvpnUtils.buildExtRoutersIdentifier(routerId);
507 Optional<Routers> optionalRouter = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routersId);
508 if (!optionalRouter.isPresent()) {
512 Routers extRouters = optionalRouter.get();
513 if (extRouters.getExtGwMacAddress() != null) {
517 RoutersBuilder builder = new RoutersBuilder(extRouters);
518 builder.setExtGwMacAddress(routerGwPort.getMacAddress().getValue());
519 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, routersId, builder.build());
523 private String getPortHostId(final Port port) {
525 PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
526 if (portBinding != null) {
527 return portBinding.getHostId();
534 private Hostconfig getHostConfig(final Port port) {
535 String hostId = getPortHostId(port);
536 if (hostId == null) {
539 Optional<Hostconfig> hostConfig;
541 hostConfig = this.hostConfigCache.get(hostId);
542 } catch (ReadFailedException e) {
543 LOG.error("failed to read host config from host {}", hostId, e);
546 return hostConfig.orNull();
549 private boolean isPortBound(final Port port) {
550 String hostId = getPortHostId(port);
551 return hostId != null && !hostId.isEmpty();
554 private boolean isPortVnicTypeDirect(Port port) {
555 PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
556 if (portBinding == null || portBinding.getVnicType() == null) {
557 // By default, VNIC_TYPE is NORMAL
560 String vnicType = portBinding.getVnicType().trim().toLowerCase(Locale.getDefault());
561 return vnicType.equals(NeutronConstants.VNIC_TYPE_DIRECT);
564 private boolean isSupportedVnicTypeByHost(final Port port, final String vnicType) {
565 Hostconfig hostConfig = getHostConfig(port);
566 String supportStr = String.format("\"vnic_type\": \"%s\"", vnicType);
567 if (hostConfig != null && hostConfig.getConfig().contains(supportStr)) {
574 private Map<String, JsonElement> unmarshal(final String profile) {
575 if (null == profile) {
578 Gson gson = new Gson();
579 JsonObject jsonObject = gson.fromJson(profile, JsonObject.class);
580 Map<String, JsonElement> map = new HashMap<>();
581 for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
582 map.put(entry.getKey(), entry.getValue());
587 private boolean isPortTypeSwitchdev(final Port port) {
588 if (!isPortVnicTypeDirect(port)) {
592 PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
593 String profile = portBinding.getProfile();
594 if (profile == null || profile.isEmpty()) {
595 LOG.debug("Port {} has no binding:profile values", port.getUuid());
599 Map<String, JsonElement> mapProfile = unmarshal(profile);
600 JsonElement capabilities = mapProfile.get(NeutronConstants.BINDING_PROFILE_CAPABILITIES);
601 LOG.debug("Port {} capabilities: {}", port.getUuid(), capabilities);
602 if (capabilities == null || !capabilities.isJsonArray()) {
603 LOG.debug("binding profile capabilities not in array format: {}", capabilities);
607 JsonArray capabilitiesArray = capabilities.getAsJsonArray();
608 Gson gson = new Gson();
609 JsonElement switchdevElement = gson.fromJson(NeutronConstants.SWITCHDEV, JsonElement.class);
610 return capabilitiesArray.contains(switchdevElement);
614 private void handleNeutronPortCreated(final Port port) {
615 final String portName = port.getUuid().getValue();
616 final Uuid portId = port.getUuid();
617 final List<FixedIps> portIpAddrsList = requireNonNullElse(port.getFixedIps(), Collections.emptyList());
618 if (NeutronConstants.IS_ODL_DHCP_PORT.test(port)) {
621 jobCoordinator.enqueueJob("PORT- " + portName, () -> {
622 // add direct port to subnetMaps config DS
623 if (!(NeutronUtils.isPortVnicTypeNormal(port)
624 || isPortTypeSwitchdev(port)
625 && isSupportedVnicTypeByHost(port, NeutronConstants.VNIC_TYPE_DIRECT))) {
626 for (FixedIps ip: portIpAddrsList) {
627 nvpnManager.updateSubnetmapNodeWithPorts(ip.getSubnetId(), null, portId);
629 LOG.info("Port {} is not a normal and not a direct with switchdev VNIC type ;"
630 + "OF Port interfaces are not created", portName);
631 return Collections.emptyList();
633 return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
634 LOG.info("Of-port-interface creation for port {}", portName);
635 // Create of-port interface for this neutron port
636 String portInterfaceName = createOfPortInterface(port, tx);
637 LOG.debug("Creating ELAN Interface for port {}", portName);
638 createElanInterface(port, portInterfaceName, tx);
639 Set<Uuid> vpnIdList = new HashSet<>();
640 Set<Uuid> routerIds = new HashSet<>();
641 for (FixedIps ip: portIpAddrsList) {
642 Subnetmap subnetMap = nvpnManager.updateSubnetmapNodeWithPorts(ip.getSubnetId(), portId, null);
643 if (subnetMap != null && subnetMap.getInternetVpnId() != null) {
644 if (!vpnIdList.contains(subnetMap.getInternetVpnId())) {
645 vpnIdList.add(subnetMap.getInternetVpnId());
648 if (subnetMap != null && subnetMap.getVpnId() != null) {
649 // can't use NeutronvpnUtils.getVpnForNetwork to optimise here, because it gives BGPVPN id
650 // obtained subnetMaps belongs to one network => vpnId must be the same for each port Ip
651 Uuid vpnId = subnetMap.getVpnId();
653 vpnIdList.add(vpnId);
656 if (subnetMap != null && subnetMap.getRouterId() != null) {
657 routerIds.add(subnetMap.getRouterId());
660 if (!vpnIdList.isEmpty()) {
661 // create new vpn-interface for neutron port
662 LOG.debug("handleNeutronPortCreated: Adding VPN Interface for port {} from network {}", portName,
663 port.getNetworkId().toString());
664 nvpnManager.createVpnInterface(vpnIdList, port, tx);
665 if (!routerIds.isEmpty()) {
666 for (Uuid routerId : routerIds) {
667 nvpnManager.addToNeutronRouterInterfacesMap(routerId,port.getUuid().getValue());
675 private void handleNeutronPortDeleted(final Port port) {
676 final String portName = port.getUuid().getValue();
677 final Uuid portId = port.getUuid();
678 final List<FixedIps> portIpsList = requireNonNullElse(port.getFixedIps(), Collections.emptyList());
679 jobCoordinator.enqueueJob("PORT- " + portName,
680 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
681 if (!(NeutronUtils.isPortVnicTypeNormal(port) || isPortTypeSwitchdev(port))) {
682 for (FixedIps ip : portIpsList) {
683 // remove direct port from subnetMaps config DS
684 nvpnManager.removePortsFromSubnetmapNode(ip.getSubnetId(), null, portId);
686 LOG.info("Port {} is not a normal and not a direct with switchdev VNIC type ;"
687 + "Skipping OF Port interfaces removal", portName);
691 Set<Uuid> routerIds = new HashSet<>();
692 Uuid internetVpnId = null;
693 for (FixedIps ip : portIpsList) {
694 Subnetmap subnetMap = nvpnManager.removePortsFromSubnetmapNode(ip.getSubnetId(), portId, null);
695 if (subnetMap == null) {
698 if (subnetMap.getVpnId() != null) {
699 // can't use NeutronvpnUtils.getVpnForNetwork to optimise here, because it gives BGPVPN id
700 // obtained subnetMaps belongs to one network => vpnId must be the same for each port Ip
701 vpnId = subnetMap.getVpnId();
703 if (subnetMap.getRouterId() != null) {
704 routerIds.add(subnetMap.getRouterId());
706 internetVpnId = subnetMap.getInternetVpnId();
708 if (NeutronConstants.DEVICE_OWNER_GATEWAY_INF.equals(port.getDeviceOwner())
709 || NeutronConstants.DEVICE_OWNER_FLOATING_IP.equals(port.getDeviceOwner())) {
710 String ipAddress = ip.getIpAddress().stringValue();
712 neutronvpnUtils.removeVpnPortFixedIpToPort(vpnId.getValue(), ipAddress, confTx);
714 if (internetVpnId != null) {
715 neutronvpnUtils.removeVpnPortFixedIpToPort(internetVpnId.getValue(),
720 if (vpnId != null || internetVpnId != null) {
721 // remove vpn-interface for this neutron port
722 LOG.debug("removing VPN Interface for port {}", portName);
723 if (!routerIds.isEmpty()) {
724 for (Uuid routerId : routerIds) {
725 nvpnManager.removeFromNeutronRouterInterfacesMap(routerId, portName);
728 nvpnManager.deleteVpnInterface(portName, null /* vpn-id */, confTx);
730 // Remove of-port interface for this neutron port
731 // ELAN interface is also implicitly deleted as part of this operation
732 LOG.debug("Of-port-interface removal for port {}", portName);
733 deleteOfPortInterface(port, confTx);
734 //dissociate fixedIP from floatingIP if associated
735 nvpnManager.dissociatefixedIPFromFloatingIP(port.getUuid().getValue());
740 private void handleNeutronPortUpdated(final Port portoriginal, final Port portupdate) {
741 final List<FixedIps> portoriginalIps = portoriginal.getFixedIps();
742 final List<FixedIps> portupdateIps = portupdate.getFixedIps();
743 if (portoriginalIps == null || portoriginalIps.isEmpty()) {
744 handleNeutronPortCreated(portupdate);
748 if (portupdateIps == null || portupdateIps.isEmpty()) {
749 LOG.info("Ignoring portUpdate (fixed_ip removal) for port {} as this case is handled "
750 + "during subnet deletion event.", portupdate.getUuid().getValue());
754 if (NeutronConstants.IS_ODL_DHCP_PORT.test(portupdate)) {
758 jobCoordinator.enqueueJob("PORT- " + portupdate.getUuid().getValue(),
759 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
760 final List<Uuid> originalSnMapsIds = portoriginalIps.stream().map(FixedIps::getSubnetId)
761 .collect(Collectors.toList());
762 final List<Uuid> updateSnMapsIds = portupdateIps.stream().map(FixedIps::getSubnetId)
763 .collect(Collectors.toList());
764 Set<Uuid> originalRouterIds = new HashSet<>();
765 Set<Uuid> oldVpnIds = new HashSet<>();
766 for (Uuid snId: originalSnMapsIds) {
767 if (!updateSnMapsIds.remove(snId)) {
768 // snId was present in originalSnMapsIds, but not in updateSnMapsIds
769 Subnetmap subnetMapOld = nvpnManager.removePortsFromSubnetmapNode(snId, portoriginal.getUuid(),
771 if (subnetMapOld != null && subnetMapOld.getVpnId() != null) {
772 oldVpnIds.add(subnetMapOld.getVpnId());
774 if (subnetMapOld != null && subnetMapOld.getInternetVpnId() != null) {
775 oldVpnIds.add(subnetMapOld.getInternetVpnId());
777 if (subnetMapOld != null && subnetMapOld.getRouterId() != null) {
778 originalRouterIds.add(subnetMapOld.getRouterId());
782 Set<Uuid> newVpnIds = new HashSet<>();
783 Set<Uuid> newRouterIds = new HashSet<>();
784 for (Uuid snId: updateSnMapsIds) {
785 Subnetmap subnetMapNew = nvpnManager.updateSubnetmapNodeWithPorts(snId, portupdate.getUuid(), null);
786 if (subnetMapNew != null) {
787 if (subnetMapNew.getVpnId() != null) {
788 newVpnIds.add(subnetMapNew.getVpnId());
790 if (subnetMapNew.getInternetVpnId() != null) {
791 newVpnIds.add(subnetMapNew.getInternetVpnId());
793 if (subnetMapNew.getRouterId() != null) {
794 newRouterIds.add(subnetMapNew.getRouterId());
798 if (!oldVpnIds.isEmpty()) {
799 LOG.info("removing VPN Interface for port {}", portoriginal.getUuid().getValue());
800 if (!originalRouterIds.isEmpty()) {
801 for (Uuid routerId : originalRouterIds) {
802 nvpnManager.removeFromNeutronRouterInterfacesMap(routerId,
803 portoriginal.getUuid().getValue());
806 nvpnManager.deleteVpnInterface(portoriginal.getUuid().getValue(),
807 null /* vpn-id */, confTx);
809 if (!newVpnIds.isEmpty()) {
810 LOG.info("Adding VPN Interface for port {}", portupdate.getUuid().getValue());
811 nvpnManager.createVpnInterface(newVpnIds, portupdate, confTx);
812 if (!newRouterIds.isEmpty()) {
813 for (Uuid routerId : newRouterIds) {
814 nvpnManager.addToNeutronRouterInterfacesMap(routerId,portupdate.getUuid().getValue());
822 private InterfaceAclBuilder handlePortSecurityUpdated(Port portOriginal,
823 Port portUpdated, boolean origSecurityEnabled, boolean updatedSecurityEnabled,
824 InterfaceBuilder interfaceBuilder) {
825 InterfaceAclBuilder interfaceAclBuilder = null;
826 if (origSecurityEnabled != updatedSecurityEnabled) {
827 interfaceAclBuilder = new InterfaceAclBuilder();
828 interfaceAclBuilder.setPortSecurityEnabled(updatedSecurityEnabled);
829 if (updatedSecurityEnabled) {
830 // Handle security group enabled
831 NeutronvpnUtils.populateInterfaceAclBuilder(interfaceAclBuilder, portUpdated);
832 neutronvpnUtils.populateSubnetInfo(portUpdated);
834 // Handle security group disabled
835 interfaceAclBuilder.setSecurityGroups(new ArrayList<>());
836 interfaceAclBuilder.setAllowedAddressPairs(new ArrayList<>());
839 if (updatedSecurityEnabled) {
840 // handle SG add/delete delta
841 InterfaceAcl interfaceAcl = interfaceBuilder.augmentation(InterfaceAcl.class);
842 interfaceAclBuilder = new InterfaceAclBuilder(interfaceAcl);
843 interfaceAclBuilder.setSecurityGroups(
844 NeutronvpnUtils.getUpdatedSecurityGroups(interfaceAcl.getSecurityGroups(),
845 portOriginal.getSecurityGroups(), portUpdated.getSecurityGroups()));
846 List<AllowedAddressPairs> updatedAddressPairs = NeutronvpnUtils.getUpdatedAllowedAddressPairs(
847 interfaceAcl.getAllowedAddressPairs(), portOriginal.getAllowedAddressPairs(),
848 portUpdated.getAllowedAddressPairs());
849 interfaceAclBuilder.setAllowedAddressPairs(NeutronvpnUtils.getAllowedAddressPairsForFixedIps(
850 updatedAddressPairs, portOriginal.getMacAddress(), portOriginal.getFixedIps(),
851 portUpdated.getFixedIps()));
853 if (portOriginal.getFixedIps() != null
854 && !portOriginal.getFixedIps().equals(portUpdated.getFixedIps())) {
855 neutronvpnUtils.populateSubnetInfo(portUpdated);
859 return interfaceAclBuilder;
862 private String createOfPortInterface(Port port, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
863 Interface inf = createInterface(port);
864 String infName = inf.getName();
866 InstanceIdentifier<Interface> interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(infName);
868 Optional<Interface> optionalInf =
869 SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
870 interfaceIdentifier);
871 if (!optionalInf.isPresent()) {
872 wrtConfigTxn.put(interfaceIdentifier, inf);
874 LOG.warn("Interface {} is already present", infName);
876 } catch (ReadFailedException e) {
877 LOG.error("failed to create interface {}", infName, e);
882 private Interface createInterface(Port port) {
883 String interfaceName = port.getUuid().getValue();
884 IfL2vlan.L2vlanMode l2VlanMode = IfL2vlan.L2vlanMode.Trunk;
885 InterfaceBuilder interfaceBuilder = new InterfaceBuilder();
886 IfL2vlanBuilder ifL2vlanBuilder = new IfL2vlanBuilder();
888 Network network = neutronvpnUtils.getNeutronNetwork(port.getNetworkId());
889 Boolean isVlanTransparent = network.isVlanTransparent();
890 if (isVlanTransparent != null && isVlanTransparent) {
891 l2VlanMode = IfL2vlan.L2vlanMode.Transparent;
894 ifL2vlanBuilder.setL2vlanMode(l2VlanMode);
896 interfaceBuilder.setEnabled(true).setName(interfaceName).setType(L2vlan.class)
897 .addAugmentation(IfL2vlan.class, ifL2vlanBuilder.build());
899 if (NeutronvpnUtils.getPortSecurityEnabled(port)) {
900 InterfaceAclBuilder interfaceAclBuilder = new InterfaceAclBuilder();
901 interfaceAclBuilder.setPortSecurityEnabled(true);
902 NeutronvpnUtils.populateInterfaceAclBuilder(interfaceAclBuilder, port);
903 interfaceBuilder.addAugmentation(InterfaceAcl.class, interfaceAclBuilder.build());
904 neutronvpnUtils.populateSubnetInfo(port);
906 return interfaceBuilder.build();
909 private void deleteOfPortInterface(Port port, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
910 String name = port.getUuid().getValue();
911 LOG.debug("Removing OFPort Interface {}", name);
912 InstanceIdentifier<Interface> interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(name);
914 Optional<Interface> optionalInf =
915 SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
916 interfaceIdentifier);
917 if (optionalInf.isPresent()) {
918 wrtConfigTxn.delete(interfaceIdentifier);
920 LOG.warn("deleteOfPortInterface: Interface {} is not present", name);
922 } catch (ReadFailedException e) {
923 LOG.error("deleteOfPortInterface: Failed to delete interface {}", name, e);
927 private void createElanInterface(Port port, String name,
928 TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
929 String elanInstanceName = port.getNetworkId().getValue();
930 List<StaticMacEntries> staticMacEntries = NeutronvpnUtils.buildStaticMacEntry(port);
932 InstanceIdentifier<ElanInterface> id = InstanceIdentifier.builder(ElanInterfaces.class).child(ElanInterface
933 .class, new ElanInterfaceKey(name)).build();
934 ElanInterface elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName)
935 .setName(name).setStaticMacEntries(staticMacEntries).withKey(new ElanInterfaceKey(name)).build();
936 wrtConfigTxn.put(id, elanInterface);
937 LOG.debug("Creating new ELan Interface {}", elanInterface);
940 private void deleteElanInterface(String name, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
941 InstanceIdentifier<ElanInterface> id = InstanceIdentifier.builder(ElanInterfaces.class).child(ElanInterface
942 .class, new ElanInterfaceKey(name)).build();
943 wrtConfigTxn.delete(id);
946 // TODO Clean up the exception handling
947 @SuppressWarnings("checkstyle:IllegalCatch")
948 private void addToFloatingIpPortInfo(Uuid floatingIpId, Uuid floatingIpPortId, Uuid floatingIpPortSubnetId, String
949 floatingIpPortMacAddress) {
950 InstanceIdentifier id = NeutronvpnUtils.buildfloatingIpIdToPortMappingIdentifier(floatingIpId);
952 FloatingIpIdToPortMappingBuilder floatingipIdToPortMacMappingBuilder = new
953 FloatingIpIdToPortMappingBuilder().withKey(new FloatingIpIdToPortMappingKey(floatingIpId))
954 .setFloatingIpId(floatingIpId).setFloatingIpPortId(floatingIpPortId)
955 .setFloatingIpPortSubnetId(floatingIpPortSubnetId)
956 .setFloatingIpPortMacAddress(floatingIpPortMacAddress);
957 LOG.debug("Creating floating IP UUID {} to Floating IP neutron port {} mapping in Floating IP"
958 + " Port Info Config DS", floatingIpId.getValue(), floatingIpPortId.getValue());
959 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id,
960 floatingipIdToPortMacMappingBuilder.build());
961 } catch (Exception e) {
962 LOG.error("Creating floating IP UUID {} to Floating IP neutron port {} mapping in Floating IP"
963 + " Port Info Config DS failed", floatingIpId.getValue(), floatingIpPortId.getValue(), e);
967 private Set<FixedIps> getFixedIpSet(List<FixedIps> fixedIps) {
968 return fixedIps != null ? new HashSet<>(fixedIps) : Collections.emptySet();