Remove vpn-portip-to-port after unset router GW
[netvirt.git] / neutronvpn / impl / src / main / java / org / opendaylight / netvirt / neutronvpn / NeutronPortChangeListener.java
1 /*
2  * Copyright © 2015, 2018 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.netvirt.neutronvpn;
9
10 import com.google.common.base.Optional;
11 import com.google.common.base.Strings;
12 import com.google.gson.Gson;
13 import com.google.gson.JsonArray;
14 import com.google.gson.JsonElement;
15 import com.google.gson.JsonObject;
16
17 import java.time.Duration;
18 import java.util.ArrayList;
19 import java.util.Collections;
20 import java.util.HashMap;
21 import java.util.HashSet;
22 import java.util.List;
23 import java.util.Locale;
24 import java.util.Map;
25 import java.util.Set;
26 import java.util.stream.Collectors;
27 import javax.annotation.PostConstruct;
28 import javax.inject.Singleton;
29 import org.apache.commons.lang3.ObjectUtils;
30 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
31 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
32 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
33 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
34 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
35 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
36 import org.opendaylight.genius.datastoreutils.listeners.DataTreeEventCallbackRegistrar;
37 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
38 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
39 import org.opendaylight.genius.mdsalutil.MDSALUtil;
40 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
41 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
42 import org.opendaylight.netvirt.elanmanager.api.IElanService;
43 import org.opendaylight.netvirt.neutronvpn.api.enums.IpVersionChoice;
44 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronConstants;
45 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
46 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
47 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
48 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
49 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlan;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlanBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.InterfaceAcl;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.InterfaceAclBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.AllowedAddressPairs;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceKey;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntries;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.RoutersBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.port.info.FloatingIpIdToPortMappingBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.port.info.FloatingIpIdToPortMappingKey;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.PortBindingExtension;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.hostconfig.rev150712.hostconfig.attributes.hostconfigs.Hostconfig;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
73 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
74 import org.slf4j.Logger;
75 import org.slf4j.LoggerFactory;
76
77 @Singleton
78 public class NeutronPortChangeListener extends AsyncDataTreeChangeListenerBase<Port, NeutronPortChangeListener> {
79     private static final Logger LOG = LoggerFactory.getLogger(NeutronPortChangeListener.class);
80     private final DataBroker dataBroker;
81     private final ManagedNewTransactionRunner txRunner;
82     private final NeutronvpnManager nvpnManager;
83     private final NeutronvpnNatManager nvpnNatManager;
84     private final NeutronSubnetGwMacResolver gwMacResolver;
85     private final IElanService elanService;
86     private final JobCoordinator jobCoordinator;
87     private final NeutronvpnUtils neutronvpnUtils;
88     private final HostConfigCache hostConfigCache;
89     private final DataTreeEventCallbackRegistrar eventCallbacks;
90
91     public NeutronPortChangeListener(final DataBroker dataBroker,
92                                      final NeutronvpnManager neutronvpnManager,
93                                      final NeutronvpnNatManager neutronvpnNatManager,
94                                      final NeutronSubnetGwMacResolver gwMacResolver,
95                                      final IElanService elanService,
96                                      final JobCoordinator jobCoordinator,
97                                      final NeutronvpnUtils neutronvpnUtils,
98                                      final HostConfigCache hostConfigCache,
99                                      final DataTreeEventCallbackRegistrar dataTreeEventCallbackRegistrar) {
100         super(Port.class, NeutronPortChangeListener.class);
101         this.dataBroker = dataBroker;
102         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
103         nvpnManager = neutronvpnManager;
104         nvpnNatManager = neutronvpnNatManager;
105         this.gwMacResolver = gwMacResolver;
106         this.elanService = elanService;
107         this.jobCoordinator = jobCoordinator;
108         this.neutronvpnUtils = neutronvpnUtils;
109         this.hostConfigCache = hostConfigCache;
110         this.eventCallbacks = dataTreeEventCallbackRegistrar;
111     }
112
113     @Override
114     @PostConstruct
115     public void init() {
116         LOG.info("{} init", getClass().getSimpleName());
117         registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
118     }
119
120     @Override
121     protected InstanceIdentifier<Port> getWildCardPath() {
122         return InstanceIdentifier.create(Neutron.class).child(Ports.class).child(Port.class);
123     }
124
125     @Override
126     protected NeutronPortChangeListener getDataTreeChangeListener() {
127         return NeutronPortChangeListener.this;
128     }
129
130
131     @Override
132     protected void add(InstanceIdentifier<Port> identifier, Port input) {
133         String portName = input.getUuid().getValue();
134         LOG.trace("Adding Port : key: {}, value={}", identifier, input);
135         Network network = neutronvpnUtils.getNeutronNetwork(input.getNetworkId());
136         if (network == null || !NeutronvpnUtils.isNetworkTypeSupported(network)) {
137             LOG.warn("neutron vpn received a port add() for a network without a provider extension augmentation "
138                             + "or with an unsupported network type for the port {} which is part of network {}",
139                     portName, network);
140             return;
141         }
142
143         neutronvpnUtils.addToPortCache(input);
144         String portStatus = NeutronUtils.PORT_STATUS_DOWN;
145         if (!Strings.isNullOrEmpty(input.getDeviceOwner()) && !Strings.isNullOrEmpty(input.getDeviceId())) {
146             if (NeutronConstants.DEVICE_OWNER_ROUTER_INF.equals(input.getDeviceOwner())) {
147                 handleRouterInterfaceAdded(input);
148                 NeutronUtils.createPortStatus(input.getUuid().getValue(), NeutronUtils.PORT_STATUS_ACTIVE, dataBroker);
149                 return;
150             }
151             if (NeutronConstants.DEVICE_OWNER_GATEWAY_INF.equals(input.getDeviceOwner())) {
152                 handleRouterGatewayUpdated(input);
153                 portStatus = NeutronUtils.PORT_STATUS_ACTIVE;
154             } else if (NeutronConstants.DEVICE_OWNER_FLOATING_IP.equals(input.getDeviceOwner())) {
155                 handleFloatingIpPortUpdated(null, input);
156                 portStatus = NeutronUtils.PORT_STATUS_ACTIVE;
157             }
158         }
159         // Switchdev ports need to be bounded to a host before creation
160         // in order to validate the supported vnic types from the hostconfig
161         if (input.getFixedIps() != null
162             && !input.getFixedIps().isEmpty()
163             && !(isPortTypeSwitchdev(input) && !isPortBound(input))) {
164             handleNeutronPortCreated(input);
165         }
166         NeutronUtils.createPortStatus(input.getUuid().getValue(), portStatus, dataBroker);
167     }
168
169     @Override
170     protected void remove(InstanceIdentifier<Port> identifier, Port input) {
171         LOG.trace("Removing Port : key: {}, value={}", identifier, input);
172         Network network = neutronvpnUtils.getNeutronNetwork(input.getNetworkId());
173         // need to proceed with deletion in case network is null for a case where v2 sync happens and a read for
174         // network from NN returns null, but the deletion process for port needs to continue
175         if (network != null && !NeutronvpnUtils.isNetworkTypeSupported(network)) {
176             String portName = input.getUuid().getValue();
177             LOG.warn("neutron vpn received a port remove() for a network without a provider extension augmentation "
178                             + "or with an unsupported network type for the port {} which is part of network {}",
179                     portName, network);
180             return;
181         }
182         neutronvpnUtils.removeFromPortCache(input);
183         NeutronUtils.deletePortStatus(input.getUuid().getValue(), dataBroker);
184
185         if (!Strings.isNullOrEmpty(input.getDeviceOwner()) && !Strings.isNullOrEmpty(input.getDeviceId())) {
186             if (NeutronConstants.DEVICE_OWNER_ROUTER_INF.equals(input.getDeviceOwner())) {
187                 handleRouterInterfaceRemoved(input);
188                 /* nothing else to do here */
189                 return;
190             } else if (NeutronConstants.DEVICE_OWNER_GATEWAY_INF.equals(input.getDeviceOwner())
191                     || NeutronConstants.DEVICE_OWNER_FLOATING_IP.equals(input.getDeviceOwner())) {
192                 elanService.removeKnownL3DmacAddress(input.getMacAddress().getValue(), input.getNetworkId().getValue());
193             }
194         }
195         if (input.getFixedIps() != null) {
196             handleNeutronPortDeleted(input);
197         }
198     }
199
200     @Override
201     protected void update(InstanceIdentifier<Port> identifier, Port original, Port update) {
202         // Switchdev ports need to be bounded to a host before creation
203         // in order to validate the supported vnic types from the hostconfig
204         if (isPortTypeSwitchdev(original)
205             && !isPortBound(original)
206             && isPortBound(update)) {
207             handleNeutronPortCreated(update);
208         }
209         final String portName = update.getUuid().getValue();
210         Network network = neutronvpnUtils.getNeutronNetwork(update.getNetworkId());
211         LOG.info("Update port {} from network {}", portName, update.getNetworkId().toString());
212         if (network == null || !NeutronvpnUtils.isNetworkTypeSupported(network)) {
213             LOG.warn("neutron vpn received a port update() for a network without a provider extension augmentation "
214                     + "or with an unsupported network type for the port {} which is part of network {}",
215                     portName, network);
216             return;
217         }
218         neutronvpnUtils.addToPortCache(update);
219
220         if ((Strings.isNullOrEmpty(original.getDeviceOwner()) || Strings.isNullOrEmpty(original.getDeviceId())
221                 || NeutronConstants.FLOATING_IP_DEVICE_ID_PENDING.equalsIgnoreCase(original.getDeviceId()))
222                 && !Strings.isNullOrEmpty(update.getDeviceOwner()) && !Strings.isNullOrEmpty(update.getDeviceId())) {
223             if (NeutronConstants.DEVICE_OWNER_ROUTER_INF.equals(update.getDeviceOwner())) {
224                 handleRouterInterfaceAdded(update);
225                 return;
226             }
227             if (NeutronConstants.DEVICE_OWNER_GATEWAY_INF.equals(update.getDeviceOwner())) {
228                 handleRouterGatewayUpdated(update);
229             } else if (NeutronConstants.DEVICE_OWNER_FLOATING_IP.equals(update.getDeviceOwner())) {
230                 handleFloatingIpPortUpdated(original, update);
231             }
232         } else {
233             Set<FixedIps> oldIPs = getFixedIpSet(original.getFixedIps());
234             Set<FixedIps> newIPs = getFixedIpSet(update.getFixedIps());
235             if (!oldIPs.equals(newIPs)) {
236                 handleNeutronPortUpdated(original, update);
237             }
238         }
239
240         // check if port security enabled/disabled as part of port update
241         boolean origSecurityEnabled = NeutronvpnUtils.getPortSecurityEnabled(original);
242         boolean updatedSecurityEnabled = NeutronvpnUtils.getPortSecurityEnabled(update);
243
244         if (origSecurityEnabled || updatedSecurityEnabled) {
245             InstanceIdentifier<Interface>  interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(portName);
246             jobCoordinator.enqueueJob("PORT- " + portName,
247                 () -> Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(confTx -> {
248                     Optional<Interface> optionalInf =
249                             confTx.read(LogicalDatastoreType.CONFIGURATION, interfaceIdentifier).checkedGet();
250                     if (optionalInf.isPresent()) {
251                         InterfaceBuilder interfaceBuilder = new InterfaceBuilder(optionalInf.get());
252                         InterfaceAcl infAcl = handlePortSecurityUpdated(original, update,
253                                 origSecurityEnabled, updatedSecurityEnabled, interfaceBuilder).build();
254                         interfaceBuilder.addAugmentation(InterfaceAcl.class, infAcl);
255                         LOG.info("update: Of-port-interface updation for port {}", portName);
256                         // Update OFPort interface for this neutron port
257                         confTx.put(LogicalDatastoreType.CONFIGURATION, interfaceIdentifier,
258                                 interfaceBuilder.build());
259                     } else {
260                         LOG.warn("update: Interface {} is not present", portName);
261                     }
262                 })));
263         }
264     }
265
266     private void handleFloatingIpPortUpdated(Port original, Port update) {
267         if ((original == null || original.getDeviceId().equals(NeutronConstants.FLOATING_IP_DEVICE_ID_PENDING))
268             && !update.getDeviceId().equals(NeutronConstants.FLOATING_IP_DEVICE_ID_PENDING)) {
269             // populate floating-ip uuid and floating-ip port attributes (uuid, mac and subnet id for the ONLY
270             // fixed IP) to be used by NAT, depopulated in NATService once mac is retrieved in the removal path
271             addToFloatingIpPortInfo(new Uuid(update.getDeviceId()), update.getUuid(), update.getFixedIps().get(0)
272                     .getSubnetId(), update.getMacAddress().getValue());
273             elanService.addKnownL3DmacAddress(update.getMacAddress().getValue(), update.getNetworkId().getValue());
274         }
275     }
276
277     private void handleRouterInterfaceAdded(Port routerPort) {
278         if (routerPort.getDeviceId() != null) {
279             Uuid routerId = new Uuid(routerPort.getDeviceId());
280             Uuid infNetworkId = routerPort.getNetworkId();
281             Uuid existingVpnId = neutronvpnUtils.getVpnForNetwork(infNetworkId);
282
283             elanService.addKnownL3DmacAddress(routerPort.getMacAddress().getValue(), infNetworkId.getValue());
284             if (existingVpnId == null) {
285                 Set<Uuid> listVpnIds = new HashSet<>();
286                 Uuid vpnId = neutronvpnUtils.getVpnForRouter(routerId, true);
287                 if (vpnId == null) {
288                     vpnId = routerId;
289                 }
290                 listVpnIds.add(vpnId);
291                 Uuid internetVpnId = neutronvpnUtils.getInternetvpnUuidBoundToRouterId(routerId);
292                 List<Subnetmap> subnetMapList = new ArrayList<>();
293                 List<FixedIps> portIps = routerPort.getFixedIps();
294                 boolean portIsIpv6 = false;
295                 for (FixedIps portIP : portIps) {
296                     // NOTE:  Please donot change the order of calls to updateSubnetNodeWithFixedIP
297                     // and addSubnetToVpn here
298                     if (internetVpnId != null
299                         && portIP.getIpAddress().getIpv6Address() != null) {
300                         portIsIpv6 = true;
301                     }
302                     String ipValue = String.valueOf(portIP.getIpAddress().getValue());
303                     Uuid subnetId = portIP.getSubnetId();
304                     nvpnManager.updateSubnetNodeWithFixedIp(subnetId, routerId,
305                             routerPort.getUuid(), ipValue, routerPort.getMacAddress().getValue(), vpnId);
306                     Subnetmap sn = neutronvpnUtils.getSubnetmap(subnetId);
307                     subnetMapList.add(sn);
308                 }
309                 if (portIsIpv6) {
310                     listVpnIds.add(internetVpnId);
311                     if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChangeToAdd(
312                                      IpVersionChoice.IPV6, internetVpnId)) {
313                         neutronvpnUtils.updateVpnInstanceWithIpFamily(internetVpnId.getValue(),
314                                                                      IpVersionChoice.IPV6, true);
315                         neutronvpnUtils.updateVpnInstanceWithFallback(internetVpnId.getValue(), true);
316                     }
317                 }
318                 if (! subnetMapList.isEmpty()) {
319                     nvpnManager.createVpnInterface(listVpnIds, routerPort, null);
320                 }
321                 for (FixedIps portIP : routerPort.getFixedIps()) {
322                     String ipValue = String.valueOf(portIP.getIpAddress().getValue());
323                     IpVersionChoice version = neutronvpnUtils.getIpVersionFromString(ipValue);
324                     if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChangeToAdd(version, vpnId)) {
325                         neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(),
326                                version, true);
327                     }
328                     if (version.isIpVersionChosen(IpVersionChoice.IPV4)) {
329                         nvpnManager.addSubnetToVpn(vpnId, portIP.getSubnetId(),
330                                                         null /* internet-vpn-id */);
331                     } else {
332                         nvpnManager.addSubnetToVpn(vpnId, portIP.getSubnetId(), internetVpnId);
333                     }
334                     LOG.trace("NeutronPortChangeListener Add Subnet Gateway IP {} MAC {} Interface {} VPN {}",
335                             ipValue, routerPort.getMacAddress(),
336                             routerPort.getUuid().getValue(), vpnId.getValue());
337                 }
338                 nvpnManager.addToNeutronRouterInterfacesMap(routerId, routerPort.getUuid().getValue());
339                 nvpnNatManager.handleSubnetsForExternalRouter(routerId);
340                 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(confTx -> {
341                     String portInterfaceName = createOfPortInterface(routerPort, confTx);
342                     createElanInterface(routerPort, portInterfaceName, confTx);
343                 }), LOG, "Error creating ELAN interface for {}", routerPort);
344             } else {
345                 LOG.error("Neutron network {} corresponding to router interface port {} for neutron router {}"
346                     + " already associated to VPN {}", infNetworkId.getValue(), routerPort.getUuid().getValue(),
347                     routerId.getValue(), existingVpnId.getValue());
348             }
349         }
350     }
351
352     private void handleRouterInterfaceRemoved(Port routerPort) {
353         if (routerPort.getDeviceId() != null) {
354             Uuid routerId = new Uuid(routerPort.getDeviceId());
355             Uuid infNetworkId = routerPort.getNetworkId();
356             elanService.removeKnownL3DmacAddress(routerPort.getMacAddress().getValue(), infNetworkId.getValue());
357             Uuid vpnId = ObjectUtils.defaultIfNull(neutronvpnUtils.getVpnForRouter(routerId, true), routerId);
358             List<FixedIps> portIps = routerPort.getFixedIps();
359             boolean vpnInstanceInternetIpVersionRemoved = false;
360             Uuid vpnInstanceInternetUuid = null;
361             for (FixedIps portIP : portIps) {
362                 // Internet VPN : flush InternetVPN first
363                 Uuid subnetId = portIP.getSubnetId();
364                 Subnetmap sn = neutronvpnUtils.getSubnetmap(subnetId);
365                 if (sn != null && sn.getInternetVpnId() != null) {
366                     if (neutronvpnUtils.shouldVpnHandleIpVersionChangeToRemove(sn, sn.getInternetVpnId())) {
367                         vpnInstanceInternetIpVersionRemoved = true;
368                         vpnInstanceInternetUuid = sn.getInternetVpnId();
369                     }
370                     nvpnManager.updateVpnInternetForSubnet(sn, sn.getInternetVpnId(), false);
371                 }
372             }
373             /* Remove ping responder for router interfaces
374              *  A router interface reference in a VPN will have to be removed before the host interface references
375              * for that subnet in the VPN are removed. This is to ensure that the FIB Entry of the router interface
376              *  is not the last entry to be removed for that subnet in the VPN.
377              *  If router interface FIB entry is the last to be removed for a subnet in a VPN , then all the host
378              *  interface references in the vpn will already have been cleared, which will cause failures in
379              *  cleanup of router interface flows*/
380             nvpnManager.deleteVpnInterface(routerPort.getUuid().getValue(),
381                                            null /* vpn-id */, null /* wrtConfigTxn*/);
382             // update RouterInterfaces map
383             ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(confTx -> {
384                 boolean vpnInstanceIpVersionRemoved = false;
385                 IpVersionChoice vpnInstanceIpVersionToRemove = IpVersionChoice.UNDEFINED;
386                 for (FixedIps portIP : portIps) {
387                     Subnetmap sn = neutronvpnUtils.getSubnetmap(portIP.getSubnetId());
388                     // router Port have either IPv4 or IPv6, never both
389                     if (neutronvpnUtils.shouldVpnHandleIpVersionChangeToRemove(sn, vpnId)) {
390                         vpnInstanceIpVersionRemoved = true;
391                         vpnInstanceIpVersionToRemove = neutronvpnUtils.getIpVersionFromString(sn.getSubnetIp());
392                     }
393                     String ipValue = String.valueOf(portIP.getIpAddress().getValue());
394                     neutronvpnUtils.removeVpnPortFixedIpToPort(vpnId.getValue(), ipValue, confTx);
395                     // NOTE:  Please donot change the order of calls to removeSubnetFromVpn and
396                     // and updateSubnetNodeWithFixedIP
397                     nvpnManager.removeSubnetFromVpn(vpnId, portIP.getSubnetId(),
398                             sn != null ? sn.getInternetVpnId() : null);
399                     nvpnManager.updateSubnetNodeWithFixedIp(portIP.getSubnetId(), null, null, null, null, null);
400                 }
401                 nvpnManager.removeFromNeutronRouterInterfacesMap(routerId, routerPort.getUuid().getValue());
402                 deleteElanInterface(routerPort.getUuid().getValue(), confTx);
403                 deleteOfPortInterface(routerPort, confTx);
404                 nvpnNatManager.handleSubnetsForExternalRouter(routerId);
405                 if (vpnInstanceIpVersionRemoved) {
406                     neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), vpnInstanceIpVersionToRemove,
407                             false);
408                 }
409             }), LOG, "Error handling interface removal");
410             if (vpnInstanceInternetIpVersionRemoved) {
411                 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnInstanceInternetUuid.getValue(),
412                         IpVersionChoice.IPV6, false);
413                 neutronvpnUtils.updateVpnInstanceWithFallback(vpnInstanceInternetUuid.getValue(), false);
414             }
415         }
416     }
417
418     private void handleRouterGatewayUpdated(Port routerGwPort) {
419         Uuid routerId = new Uuid(routerGwPort.getDeviceId());
420         Uuid networkId = routerGwPort.getNetworkId();
421         Network network = neutronvpnUtils.getNeutronNetwork(networkId);
422         if (network == null) {
423             return;
424         }
425         boolean isExternal = neutronvpnUtils.getIsExternal(network);
426         if (isExternal) {
427             Uuid vpnInternetId = neutronvpnUtils.getVpnForNetwork(networkId);
428             if (vpnInternetId != null) {
429                 List<Subnetmap> snList = neutronvpnUtils.getNeutronRouterSubnetMaps(routerId);
430                 for (Subnetmap sn : snList) {
431                     if (sn.getNetworkId() == networkId) {
432                         continue;
433                     }
434                     if (neutronvpnUtils.getIpVersionFromString(sn.getSubnetIp()) != IpVersionChoice.IPV6) {
435                         continue;
436                     }
437                     nvpnManager.addSubnetToVpn(null, sn.getId(), vpnInternetId);
438                 }
439             }
440         }
441         elanService.addKnownL3DmacAddress(routerGwPort.getMacAddress().getValue(), networkId.getValue());
442
443         Router router = neutronvpnUtils.getNeutronRouter(routerId);
444         if (router == null) {
445             LOG.warn("No router found for router GW port {} for router {}", routerGwPort.getUuid().getValue(),
446                     routerId.getValue());
447             // NETVIRT-1249
448             eventCallbacks.onAddOrUpdate(LogicalDatastoreType.CONFIGURATION,
449                     neutronvpnUtils.getNeutronRouterIid(routerId), (unused, newRouter) -> {
450                     setupGwMac(newRouter, routerGwPort, routerId);
451                     return DataTreeEventCallbackRegistrar.NextAction.UNREGISTER;
452                 }, Duration.ofSeconds(3), iid -> {
453                     LOG.error("GwPort {} added without Router", routerGwPort.getUuid().getValue());
454                 });
455             return;
456         }
457         setupGwMac(router, routerGwPort, routerId);
458     }
459
460     private void setupGwMac(Router router, Port routerGwPort, Uuid routerId) {
461         gwMacResolver.sendArpRequestsToExtGateways(router);
462         setExternalGwMac(routerGwPort, routerId);
463
464     }
465
466     private void setExternalGwMac(Port routerGwPort, Uuid routerId) {
467         // During full-sync networking-odl syncs routers before ports. As such,
468         // the MAC of the router's gw port is not available to be set when the
469         // router is written. We catch that here.
470         InstanceIdentifier<Routers> routersId = NeutronvpnUtils.buildExtRoutersIdentifier(routerId);
471         Optional<Routers> optionalRouter = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routersId);
472         if (!optionalRouter.isPresent()) {
473             return;
474         }
475
476         Routers extRouters = optionalRouter.get();
477         if (extRouters.getExtGwMacAddress() != null) {
478             return;
479         }
480
481         RoutersBuilder builder = new RoutersBuilder(extRouters);
482         builder.setExtGwMacAddress(routerGwPort.getMacAddress().getValue());
483         MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, routersId, builder.build());
484     }
485
486     private String getPortHostId(final Port port) {
487         if (port != null) {
488             PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
489             if (portBinding != null) {
490                 return portBinding.getHostId();
491             }
492         }
493         return null;
494     }
495
496     private Hostconfig getHostConfig(final Port port) {
497         String hostId = getPortHostId(port);
498         if (hostId == null) {
499             return null;
500         }
501         Optional<Hostconfig> hostConfig;
502         try {
503             hostConfig = this.hostConfigCache.get(hostId);
504         } catch (ReadFailedException e) {
505             LOG.error("failed to read host config from host {}", hostId, e);
506             return null;
507         }
508         return hostConfig.isPresent() ? hostConfig.get() : null;
509     }
510
511     private boolean isPortBound(final Port port) {
512         String hostId = getPortHostId(port);
513         return hostId != null && !hostId.isEmpty();
514     }
515
516     private boolean isPortVnicTypeDirect(Port port) {
517         PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
518         if (portBinding == null || portBinding.getVnicType() == null) {
519             // By default, VNIC_TYPE is NORMAL
520             return false;
521         }
522         String vnicType = portBinding.getVnicType().trim().toLowerCase(Locale.getDefault());
523         return vnicType.equals(NeutronConstants.VNIC_TYPE_DIRECT);
524     }
525
526     private boolean isSupportedVnicTypeByHost(final Port port, final String vnicType) {
527         Hostconfig hostConfig = getHostConfig(port);
528         String supportStr = String.format("\"vnic_type\": \"%s\"", vnicType);
529         if (hostConfig != null && hostConfig.getConfig().contains(supportStr)) {
530             return true;
531         }
532         return false;
533     }
534
535     private Map<String, JsonElement> unmarshal(final String profile) {
536         if (null == profile) {
537             return null;
538         }
539         Gson gson = new Gson();
540         JsonObject jsonObject = gson.fromJson(profile, JsonObject.class);
541         Map<String, JsonElement> map = new HashMap();
542         for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
543             map.put(entry.getKey(), entry.getValue());
544         }
545         return map;
546     }
547
548     private boolean isPortTypeSwitchdev(final Port port) {
549         if (!isPortVnicTypeDirect(port)) {
550             return false;
551         }
552
553         PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
554         String profile = portBinding.getProfile();
555         if (profile == null || profile.isEmpty()) {
556             LOG.debug("Port {} has no binding:profile values", port.getUuid());
557             return false;
558         }
559
560         Map<String, JsonElement> mapProfile = unmarshal(profile);
561         JsonElement capabilities = mapProfile.get(NeutronConstants.BINDING_PROFILE_CAPABILITIES);
562         LOG.debug("Port {} capabilities: {}", port.getUuid(), capabilities);
563         if (capabilities == null || !capabilities.isJsonArray()) {
564             LOG.debug("binding profile capabilities not in array format: {}", capabilities);
565             return false;
566         }
567
568         JsonArray capabilitiesArray = capabilities.getAsJsonArray();
569         Gson gson = new Gson();
570         JsonElement switchdevElement = gson.fromJson(NeutronConstants.SWITCHDEV, JsonElement.class);
571         return capabilitiesArray.contains(switchdevElement);
572     }
573
574
575     private void handleNeutronPortCreated(final Port port) {
576         final String portName = port.getUuid().getValue();
577         final Uuid portId = port.getUuid();
578         final List<FixedIps> portIpAddrsList = port.getFixedIps();
579         if (NeutronConstants.IS_ODL_DHCP_PORT.test(port)) {
580             return;
581         }
582         jobCoordinator.enqueueJob("PORT- " + portName, () -> {
583             // add direct port to subnetMaps config DS
584             if (!(NeutronUtils.isPortVnicTypeNormal(port)
585                 || (isPortTypeSwitchdev(port)
586                 && isSupportedVnicTypeByHost(port, NeutronConstants.VNIC_TYPE_DIRECT)))) {
587                 for (FixedIps ip: portIpAddrsList) {
588                     nvpnManager.updateSubnetmapNodeWithPorts(ip.getSubnetId(), null, portId);
589                 }
590                 LOG.info("Port {} is not a normal and not a direct with switchdev VNIC type ;"
591                          + "OF Port interfaces are not created", portName);
592                 return Collections.emptyList();
593             }
594             return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
595                 LOG.info("Of-port-interface creation for port {}", portName);
596                 // Create of-port interface for this neutron port
597                 String portInterfaceName = createOfPortInterface(port, tx);
598                 LOG.debug("Creating ELAN Interface for port {}", portName);
599                 createElanInterface(port, portInterfaceName, tx);
600                 Set<Uuid> vpnIdList =  new HashSet<>();
601                 Set<Uuid> routerIds = new HashSet<>();
602                 for (FixedIps ip: portIpAddrsList) {
603                     Subnetmap subnetMap = nvpnManager.updateSubnetmapNodeWithPorts(ip.getSubnetId(), portId, null);
604                     if (subnetMap != null && subnetMap.getInternetVpnId() != null) {
605                         if (!vpnIdList.contains(subnetMap.getInternetVpnId())) {
606                             vpnIdList.add(subnetMap.getInternetVpnId());
607                         }
608                     }
609                     if (subnetMap != null && subnetMap.getVpnId() != null) {
610                         // can't use NeutronvpnUtils.getVpnForNetwork to optimise here, because it gives BGPVPN id
611                         // obtained subnetMaps belongs to one network => vpnId must be the same for each port Ip
612                         Uuid vpnId = subnetMap.getVpnId();
613                         if (vpnId != null) {
614                             vpnIdList.add(vpnId);
615                         }
616                     }
617                     if (subnetMap != null && subnetMap.getRouterId() != null) {
618                         routerIds.add(subnetMap.getRouterId());
619                     }
620                 }
621                 if (!vpnIdList.isEmpty()) {
622                     // create new vpn-interface for neutron port
623                     LOG.debug("handleNeutronPortCreated: Adding VPN Interface for port {} from network {}", portName,
624                             port.getNetworkId().toString());
625                     nvpnManager.createVpnInterface(vpnIdList, port, tx);
626                     if (!routerIds.isEmpty()) {
627                         for (Uuid routerId : routerIds) {
628                             nvpnManager.addToNeutronRouterInterfacesMap(routerId,port.getUuid().getValue());
629                         }
630                     }
631                 }
632             }));
633         });
634     }
635
636     private void handleNeutronPortDeleted(final Port port) {
637         final String portName = port.getUuid().getValue();
638         final Uuid portId = port.getUuid();
639         final List<FixedIps> portIpsList = port.getFixedIps();
640         jobCoordinator.enqueueJob("PORT- " + portName,
641             () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(confTx -> {
642                 if (!(NeutronUtils.isPortVnicTypeNormal(port) || isPortTypeSwitchdev(port))) {
643                     for (FixedIps ip : portIpsList) {
644                         // remove direct port from subnetMaps config DS
645                         nvpnManager.removePortsFromSubnetmapNode(ip.getSubnetId(), null, portId);
646                     }
647                     LOG.info("Port {} is not a normal and not a direct with switchdev VNIC type ;"
648                             + "Skipping OF Port interfaces removal", portName);
649                     return;
650                 }
651                 Uuid vpnId = null;
652                 Set<Uuid> routerIds = new HashSet<>();
653                 Uuid internetVpnId = null;
654                 for (FixedIps ip : portIpsList) {
655                     Subnetmap subnetMap = nvpnManager.removePortsFromSubnetmapNode(ip.getSubnetId(), portId, null);
656                     if (subnetMap == null) {
657                         continue;
658                     }
659                     if (subnetMap.getVpnId() != null) {
660                         // can't use NeutronvpnUtils.getVpnForNetwork to optimise here, because it gives BGPVPN id
661                         // obtained subnetMaps belongs to one network => vpnId must be the same for each port Ip
662                         vpnId = subnetMap.getVpnId();
663                     }
664                     if (subnetMap.getRouterId() != null) {
665                         routerIds.add(subnetMap.getRouterId());
666                     }
667                     internetVpnId = subnetMap.getInternetVpnId();
668
669                     if (NeutronConstants.DEVICE_OWNER_GATEWAY_INF.equals(port.getDeviceOwner())) {
670                         String routerGwIpAddress = String.valueOf(ip.getIpAddress().getValue());
671                         if (vpnId != null) {
672                             neutronvpnUtils.removeVpnPortFixedIpToPort(vpnId.getValue(), routerGwIpAddress, confTx);
673                         }
674                         if (internetVpnId != null) {
675                             neutronvpnUtils.removeVpnPortFixedIpToPort(internetVpnId.getValue(),
676                                 routerGwIpAddress, confTx);
677                         }
678                     }
679                 }
680                 if (vpnId != null || internetVpnId != null) {
681                     // remove vpn-interface for this neutron port
682                     LOG.debug("removing VPN Interface for port {}", portName);
683                     if (!routerIds.isEmpty()) {
684                         for (Uuid routerId : routerIds) {
685                             nvpnManager.removeFromNeutronRouterInterfacesMap(routerId, portName);
686                         }
687                     }
688                     nvpnManager.deleteVpnInterface(portName, null /* vpn-id */, confTx);
689                 }
690                 // Remove of-port interface for this neutron port
691                 // ELAN interface is also implicitly deleted as part of this operation
692                 LOG.debug("Of-port-interface removal for port {}", portName);
693                 deleteOfPortInterface(port, confTx);
694                 //dissociate fixedIP from floatingIP if associated
695                 nvpnManager.dissociatefixedIPFromFloatingIP(port.getUuid().getValue());
696             })));
697     }
698
699
700     private void handleNeutronPortUpdated(final Port portoriginal, final Port portupdate) {
701         final List<FixedIps> portoriginalIps = portoriginal.getFixedIps();
702         final List<FixedIps> portupdateIps = portupdate.getFixedIps();
703         if (portoriginalIps == null || portoriginalIps.isEmpty()) {
704             handleNeutronPortCreated(portupdate);
705             return;
706         }
707
708         if (portupdateIps == null || portupdateIps.isEmpty()) {
709             LOG.info("Ignoring portUpdate (fixed_ip removal) for port {} as this case is handled "
710                       + "during subnet deletion event.", portupdate.getUuid().getValue());
711             return;
712         }
713         jobCoordinator.enqueueJob("PORT- " + portupdate.getUuid().getValue(),
714             () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(confTx -> {
715                 final List<Uuid> originalSnMapsIds = portoriginalIps.stream().map(FixedIps::getSubnetId)
716                         .collect(Collectors.toList());
717                 final List<Uuid> updateSnMapsIds = portupdateIps.stream().map(FixedIps::getSubnetId)
718                         .collect(Collectors.toList());
719                 Set<Uuid> originalRouterIds = new HashSet<>();
720                 Set<Uuid> oldVpnIds = new HashSet<>();
721                 for (Uuid snId: originalSnMapsIds) {
722                     if (!updateSnMapsIds.remove(snId)) {
723                         // snId was present in originalSnMapsIds, but not in updateSnMapsIds
724                         Subnetmap subnetMapOld = nvpnManager.removePortsFromSubnetmapNode(snId, portoriginal.getUuid(),
725                                 null);
726                         if (subnetMapOld != null && subnetMapOld.getVpnId() != null) {
727                             oldVpnIds.add(subnetMapOld.getVpnId());
728                         }
729                         if (subnetMapOld != null && subnetMapOld.getInternetVpnId() != null) {
730                             oldVpnIds.add(subnetMapOld.getInternetVpnId());
731                         }
732                         if (subnetMapOld != null && subnetMapOld.getRouterId() != null) {
733                             originalRouterIds.add(subnetMapOld.getRouterId());
734                         }
735                     }
736                 }
737                 Set<Uuid> newVpnIds = new HashSet();
738                 Set<Uuid> newRouterIds = new HashSet<>();
739                 for (Uuid snId: updateSnMapsIds) {
740                     Subnetmap subnetMapNew = nvpnManager.updateSubnetmapNodeWithPorts(snId, portupdate.getUuid(), null);
741                     if (subnetMapNew != null) {
742                         if (subnetMapNew.getVpnId() != null) {
743                             newVpnIds.add(subnetMapNew.getVpnId());
744                         }
745                         if (subnetMapNew.getInternetVpnId() != null) {
746                             newVpnIds.add(subnetMapNew.getInternetVpnId());
747                         }
748                         if (subnetMapNew.getRouterId() != null) {
749                             newRouterIds.add(subnetMapNew.getRouterId());
750                         }
751                     }
752                 }
753                 if (!oldVpnIds.isEmpty()) {
754                     LOG.info("removing VPN Interface for port {}", portoriginal.getUuid().getValue());
755                     if (!originalRouterIds.isEmpty()) {
756                         for (Uuid routerId : originalRouterIds) {
757                             nvpnManager.removeFromNeutronRouterInterfacesMap(routerId,
758                                     portoriginal.getUuid().getValue());
759                         }
760                     }
761                     nvpnManager.deleteVpnInterface(portoriginal.getUuid().getValue(),
762                                                    null /* vpn-id */, confTx);
763                 }
764                 if (!newVpnIds.isEmpty()) {
765                     LOG.info("Adding VPN Interface for port {}", portupdate.getUuid().getValue());
766                     nvpnManager.createVpnInterface(newVpnIds, portupdate, confTx);
767                     if (!newRouterIds.isEmpty()) {
768                         for (Uuid routerId : newRouterIds) {
769                             nvpnManager.addToNeutronRouterInterfacesMap(routerId,portupdate.getUuid().getValue());
770                         }
771                     }
772                 }
773             })));
774     }
775
776     private InterfaceAclBuilder handlePortSecurityUpdated(Port portOriginal,
777             Port portUpdated, boolean origSecurityEnabled, boolean updatedSecurityEnabled,
778             InterfaceBuilder interfaceBuilder) {
779         InterfaceAclBuilder interfaceAclBuilder = null;
780         if (origSecurityEnabled != updatedSecurityEnabled) {
781             interfaceAclBuilder = new InterfaceAclBuilder();
782             interfaceAclBuilder.setPortSecurityEnabled(updatedSecurityEnabled);
783             if (updatedSecurityEnabled) {
784                 // Handle security group enabled
785                 NeutronvpnUtils.populateInterfaceAclBuilder(interfaceAclBuilder, portUpdated);
786                 neutronvpnUtils.populateSubnetInfo(portUpdated);
787             } else {
788                 // Handle security group disabled
789                 interfaceAclBuilder.setSecurityGroups(new ArrayList<>());
790                 interfaceAclBuilder.setAllowedAddressPairs(new ArrayList<>());
791             }
792         } else {
793             if (updatedSecurityEnabled) {
794                 // handle SG add/delete delta
795                 InterfaceAcl interfaceAcl = interfaceBuilder.augmentation(InterfaceAcl.class);
796                 interfaceAclBuilder = new InterfaceAclBuilder(interfaceAcl);
797                 interfaceAclBuilder.setSecurityGroups(
798                         NeutronvpnUtils.getUpdatedSecurityGroups(interfaceAcl.getSecurityGroups(),
799                                 portOriginal.getSecurityGroups(), portUpdated.getSecurityGroups()));
800                 List<AllowedAddressPairs> updatedAddressPairs = NeutronvpnUtils.getUpdatedAllowedAddressPairs(
801                         interfaceAcl.getAllowedAddressPairs(), portOriginal.getAllowedAddressPairs(),
802                         portUpdated.getAllowedAddressPairs());
803                 interfaceAclBuilder.setAllowedAddressPairs(NeutronvpnUtils.getAllowedAddressPairsForFixedIps(
804                         updatedAddressPairs, portOriginal.getMacAddress(), portOriginal.getFixedIps(),
805                         portUpdated.getFixedIps()));
806
807                 if (portOriginal.getFixedIps() != null
808                         && !portOriginal.getFixedIps().equals(portUpdated.getFixedIps())) {
809                     neutronvpnUtils.populateSubnetInfo(portUpdated);
810                 }
811             }
812         }
813         return interfaceAclBuilder;
814     }
815
816     private String createOfPortInterface(Port port, WriteTransaction wrtConfigTxn) {
817         Interface inf = createInterface(port);
818         String infName = inf.getName();
819
820         InstanceIdentifier<Interface> interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(infName);
821         try {
822             Optional<Interface> optionalInf =
823                     SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
824                             interfaceIdentifier);
825             if (!optionalInf.isPresent()) {
826                 wrtConfigTxn.put(LogicalDatastoreType.CONFIGURATION, interfaceIdentifier, inf);
827             } else {
828                 LOG.warn("Interface {} is already present", infName);
829             }
830         } catch (ReadFailedException e) {
831             LOG.error("failed to create interface {}", infName, e);
832         }
833         return infName;
834     }
835
836     private Interface createInterface(Port port) {
837         String interfaceName = port.getUuid().getValue();
838         IfL2vlan.L2vlanMode l2VlanMode = IfL2vlan.L2vlanMode.Trunk;
839         InterfaceBuilder interfaceBuilder = new InterfaceBuilder();
840         IfL2vlanBuilder ifL2vlanBuilder = new IfL2vlanBuilder();
841
842         Network network = neutronvpnUtils.getNeutronNetwork(port.getNetworkId());
843         Boolean isVlanTransparent = network.isVlanTransparent();
844         if (isVlanTransparent != null && isVlanTransparent) {
845             l2VlanMode = IfL2vlan.L2vlanMode.Transparent;
846         }
847
848         ifL2vlanBuilder.setL2vlanMode(l2VlanMode);
849
850         interfaceBuilder.setEnabled(true).setName(interfaceName).setType(L2vlan.class)
851                 .addAugmentation(IfL2vlan.class, ifL2vlanBuilder.build());
852
853         if (NeutronvpnUtils.getPortSecurityEnabled(port)) {
854             InterfaceAclBuilder interfaceAclBuilder = new InterfaceAclBuilder();
855             interfaceAclBuilder.setPortSecurityEnabled(true);
856             NeutronvpnUtils.populateInterfaceAclBuilder(interfaceAclBuilder, port);
857             interfaceBuilder.addAugmentation(InterfaceAcl.class, interfaceAclBuilder.build());
858             neutronvpnUtils.populateSubnetInfo(port);
859         }
860         return interfaceBuilder.build();
861     }
862
863     private void deleteOfPortInterface(Port port, WriteTransaction wrtConfigTxn) {
864         String name = port.getUuid().getValue();
865         LOG.debug("Removing OFPort Interface {}", name);
866         InstanceIdentifier<Interface>  interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(name);
867         try {
868             Optional<Interface> optionalInf =
869                     SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
870                             interfaceIdentifier);
871             if (optionalInf.isPresent()) {
872                 wrtConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, interfaceIdentifier);
873             } else {
874                 LOG.warn("deleteOfPortInterface: Interface {} is not present", name);
875             }
876         } catch (ReadFailedException e) {
877             LOG.error("deleteOfPortInterface: Failed to delete interface {}", name, e);
878         }
879     }
880
881     private void createElanInterface(Port port, String name, WriteTransaction wrtConfigTxn) {
882         String elanInstanceName = port.getNetworkId().getValue();
883         List<StaticMacEntries> staticMacEntries = NeutronvpnUtils.buildStaticMacEntry(port);
884
885         InstanceIdentifier<ElanInterface> id = InstanceIdentifier.builder(ElanInterfaces.class).child(ElanInterface
886                 .class, new ElanInterfaceKey(name)).build();
887         ElanInterface elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName)
888                 .setName(name).setStaticMacEntries(staticMacEntries).withKey(new ElanInterfaceKey(name)).build();
889         wrtConfigTxn.put(LogicalDatastoreType.CONFIGURATION, id, elanInterface);
890         LOG.debug("Creating new ELan Interface {}", elanInterface);
891     }
892
893     private void deleteElanInterface(String name, WriteTransaction wrtConfigTxn) {
894         InstanceIdentifier<ElanInterface> id = InstanceIdentifier.builder(ElanInterfaces.class).child(ElanInterface
895                 .class, new ElanInterfaceKey(name)).build();
896         wrtConfigTxn.delete(LogicalDatastoreType.CONFIGURATION, id);
897     }
898
899     // TODO Clean up the exception handling
900     @SuppressWarnings("checkstyle:IllegalCatch")
901     private void addToFloatingIpPortInfo(Uuid floatingIpId, Uuid floatingIpPortId, Uuid floatingIpPortSubnetId, String
902                                          floatingIpPortMacAddress) {
903         InstanceIdentifier id = NeutronvpnUtils.buildfloatingIpIdToPortMappingIdentifier(floatingIpId);
904         try {
905             FloatingIpIdToPortMappingBuilder floatingipIdToPortMacMappingBuilder = new
906                 FloatingIpIdToPortMappingBuilder().withKey(new FloatingIpIdToPortMappingKey(floatingIpId))
907                 .setFloatingIpId(floatingIpId).setFloatingIpPortId(floatingIpPortId)
908                 .setFloatingIpPortSubnetId(floatingIpPortSubnetId)
909                 .setFloatingIpPortMacAddress(floatingIpPortMacAddress);
910             LOG.debug("Creating floating IP UUID {} to Floating IP neutron port {} mapping in Floating IP"
911                 + " Port Info Config DS", floatingIpId.getValue(), floatingIpPortId.getValue());
912             MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id,
913                 floatingipIdToPortMacMappingBuilder.build());
914         } catch (Exception e) {
915             LOG.error("Creating floating IP UUID {} to Floating IP neutron port {} mapping in Floating IP"
916                 + " Port Info Config DS failed", floatingIpId.getValue(), floatingIpPortId.getValue(), e);
917         }
918     }
919
920     private Set<FixedIps> getFixedIpSet(List<FixedIps> fixedIps) {
921         return fixedIps != null ? new HashSet<>(fixedIps) : Collections.emptySet();
922     }
923 }