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