VPNInstance IP Addr Family update is not working
[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.shouldVpnHandleIpVersionChoiceChange(
314                                      IpVersionChoice.IPV6, routerId, true)) {
315                         neutronvpnUtils.updateVpnInstanceWithIpFamily(internetVpnId.getValue(), IpVersionChoice.IPV6,
316                                 true);
317                         neutronvpnUtils.updateVpnInstanceWithFallback(internetVpnId.getValue(), true);
318                     }
319                 }
320                 if (! subnetMapList.isEmpty()) {
321                     nvpnManager.createVpnInterface(listVpnIds, routerPort, null);
322                 }
323                 IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
324                 for (FixedIps portIP : routerPort.getFixedIps()) {
325                     String ipValue = portIP.getIpAddress().stringValue();
326                     ipVersion = NeutronvpnUtils.getIpVersionFromString(ipValue);
327                     if (ipVersion.isIpVersionChosen(IpVersionChoice.IPV4)) {
328                         nvpnManager.addSubnetToVpn(vpnId, portIP.getSubnetId(),
329                                                         null /* internet-vpn-id */);
330                     } else {
331                         nvpnManager.addSubnetToVpn(vpnId, portIP.getSubnetId(), internetVpnId);
332                     }
333                     LOG.trace("NeutronPortChangeListener Add Subnet Gateway IP {} MAC {} Interface {} VPN {}",
334                             ipValue, routerPort.getMacAddress(),
335                             routerPort.getUuid().getValue(), vpnId.getValue());
336                 }
337                 if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(ipVersion, routerId, true)) {
338                     LOG.debug("vpnInstanceOpDataEntry is getting update with ip address family {} for VPN {}",
339                             ipVersion, vpnId.getValue());
340                     neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, true);
341                 }
342                 nvpnManager.addToNeutronRouterInterfacesMap(routerId, routerPort.getUuid().getValue());
343                 jobCoordinator.enqueueJob(routerId.toString(), () -> {
344                     nvpnNatManager.handleSubnetsForExternalRouter(routerId);
345                     return Collections.emptyList();
346                 });
347                 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
348                     confTx -> {
349                         String portInterfaceName = createOfPortInterface(routerPort, confTx);
350                         createElanInterface(routerPort, portInterfaceName, confTx);
351                     }), LOG, "Error creating ELAN interface for {}", routerPort);
352             } else {
353                 LOG.error("Neutron network {} corresponding to router interface port {} for neutron router {}"
354                     + " already associated to VPN {}", infNetworkId.getValue(), routerPort.getUuid().getValue(),
355                     routerId.getValue(), existingVpnId.getValue());
356             }
357         }
358     }
359
360     private void handleRouterInterfaceRemoved(Port routerPort) {
361         if (routerPort.getDeviceId() != null) {
362             Uuid routerId = new Uuid(routerPort.getDeviceId());
363             Uuid infNetworkId = routerPort.getNetworkId();
364             elanService.removeKnownL3DmacAddress(routerPort.getMacAddress().getValue(), infNetworkId.getValue());
365             Uuid vpnId = ObjectUtils.defaultIfNull(neutronvpnUtils.getVpnForRouter(routerId, true), routerId);
366             List<FixedIps> portIps = routerPort.getFixedIps();
367             boolean vpnInstanceInternetIpVersionRemoved = false;
368             Uuid vpnInstanceInternetUuid = null;
369             for (FixedIps portIP : portIps) {
370                 // Internet VPN : flush InternetVPN first
371                 Uuid subnetId = portIP.getSubnetId();
372                 Subnetmap sn = neutronvpnUtils.getSubnetmap(subnetId);
373                 if (sn != null && sn.getInternetVpnId() != null) {
374                     if (neutronvpnUtils.shouldVpnHandleIpVersionChangeToRemove(sn, sn.getInternetVpnId())) {
375                         vpnInstanceInternetIpVersionRemoved = true;
376                         vpnInstanceInternetUuid = sn.getInternetVpnId();
377                     }
378                     nvpnManager.updateVpnInternetForSubnet(sn, sn.getInternetVpnId(), false);
379                 }
380             }
381             /* Remove ping responder for router interfaces
382              *  A router interface reference in a VPN will have to be removed before the host interface references
383              * for that subnet in the VPN are removed. This is to ensure that the FIB Entry of the router interface
384              *  is not the last entry to be removed for that subnet in the VPN.
385              *  If router interface FIB entry is the last to be removed for a subnet in a VPN , then all the host
386              *  interface references in the vpn will already have been cleared, which will cause failures in
387              *  cleanup of router interface flows*/
388             nvpnManager.deleteVpnInterface(routerPort.getUuid().getValue(),
389                                            null /* vpn-id */, null /* wrtConfigTxn*/);
390             // update RouterInterfaces map
391             ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
392                 confTx -> {
393                     IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
394                     for (FixedIps portIP : portIps) {
395                         Subnetmap sn = neutronvpnUtils.getSubnetmap(portIP.getSubnetId());
396                         // router Port have either IPv4 or IPv6, never both
397                         ipVersion = neutronvpnUtils.getIpVersionFromString(sn.getSubnetIp());
398                         String ipValue = portIP.getIpAddress().stringValue();
399                         neutronvpnUtils.removeVpnPortFixedIpToPort(vpnId.getValue(), ipValue, confTx);
400                         // NOTE:  Please donot change the order of calls to removeSubnetFromVpn and
401                         // and updateSubnetNodeWithFixedIP
402                         nvpnManager.removeSubnetFromVpn(vpnId, portIP.getSubnetId(), sn.getInternetVpnId());
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                     jobCoordinator.enqueueJob(routerId.toString(), () -> {
410                         nvpnNatManager.handleSubnetsForExternalRouter(routerId);
411                         return Collections.emptyList();
412                     });
413                     if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(ipVersion, routerId, false)) {
414                         LOG.debug("vpnInstanceOpDataEntry is getting update with ip address family {} for VPN {}",
415                                 ipVersion, vpnId.getValue());
416                         neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, false);
417                     }
418                 }), LOG, "Error handling interface removal");
419             if (vpnInstanceInternetIpVersionRemoved) {
420                 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnInstanceInternetUuid.getValue(), IpVersionChoice.IPV6,
421                          false);
422                 neutronvpnUtils.updateVpnInstanceWithFallback(vpnInstanceInternetUuid.getValue(), false);
423             }
424         }
425     }
426
427     private void handleRouterGatewayUpdated(Port routerGwPort) {
428         Uuid routerId = new Uuid(routerGwPort.getDeviceId());
429         Uuid networkId = routerGwPort.getNetworkId();
430         Network network = neutronvpnUtils.getNeutronNetwork(networkId);
431         if (network == null) {
432             return;
433         }
434         boolean isExternal = NeutronvpnUtils.getIsExternal(network);
435         if (isExternal) {
436             Uuid vpnInternetId = neutronvpnUtils.getVpnForNetwork(networkId);
437             if (vpnInternetId != null) {
438                 List<Subnetmap> snList = neutronvpnUtils.getNeutronRouterSubnetMaps(routerId);
439                 for (Subnetmap sn : snList) {
440                     if (sn.getNetworkId() == networkId) {
441                         continue;
442                     }
443                     if (NeutronvpnUtils.getIpVersionFromString(sn.getSubnetIp()) != IpVersionChoice.IPV6) {
444                         continue;
445                     }
446                     nvpnManager.addSubnetToVpn(null, sn.getId(), vpnInternetId);
447                 }
448             }
449         }
450         elanService.addKnownL3DmacAddress(routerGwPort.getMacAddress().getValue(), networkId.getValue());
451
452         Router router = neutronvpnUtils.getNeutronRouter(routerId);
453         if (router == null) {
454             LOG.warn("No router found for router GW port {} for router {}", routerGwPort.getUuid().getValue(),
455                     routerId.getValue());
456             // NETVIRT-1249
457             eventCallbacks.onAddOrUpdate(LogicalDatastoreType.CONFIGURATION,
458                     neutronvpnUtils.getNeutronRouterIid(routerId), (unused, newRouter) -> {
459                     setupGwMac(newRouter, routerGwPort, routerId);
460                     return DataTreeEventCallbackRegistrar.NextAction.UNREGISTER;
461                 }, Duration.ofSeconds(3), iid -> {
462                     LOG.error("GwPort {} added without Router", routerGwPort.getUuid().getValue());
463                 });
464             return;
465         }
466         setupGwMac(router, routerGwPort, routerId);
467     }
468
469     private void setupGwMac(Router router, Port routerGwPort, Uuid routerId) {
470         gwMacResolver.sendArpRequestsToExtGateways(router);
471         jobCoordinator.enqueueJob(routerId.toString(), () -> {
472             setExternalGwMac(routerGwPort, routerId);
473             return Collections.emptyList();
474         });
475     }
476
477     private void setExternalGwMac(Port routerGwPort, Uuid routerId) {
478         // During full-sync networking-odl syncs routers before ports. As such,
479         // the MAC of the router's gw port is not available to be set when the
480         // router is written. We catch that here.
481         InstanceIdentifier<Routers> routersId = NeutronvpnUtils.buildExtRoutersIdentifier(routerId);
482         Optional<Routers> optionalRouter = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routersId);
483         if (!optionalRouter.isPresent()) {
484             return;
485         }
486
487         Routers extRouters = optionalRouter.get();
488         if (extRouters.getExtGwMacAddress() != null) {
489             return;
490         }
491
492         RoutersBuilder builder = new RoutersBuilder(extRouters);
493         builder.setExtGwMacAddress(routerGwPort.getMacAddress().getValue());
494         MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, routersId, builder.build());
495     }
496
497     private String getPortHostId(final Port port) {
498         if (port != null) {
499             PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
500             if (portBinding != null) {
501                 return portBinding.getHostId();
502             }
503         }
504         return null;
505     }
506
507     private Hostconfig getHostConfig(final Port port) {
508         String hostId = getPortHostId(port);
509         if (hostId == null) {
510             return null;
511         }
512         Optional<Hostconfig> hostConfig;
513         try {
514             hostConfig = this.hostConfigCache.get(hostId);
515         } catch (ReadFailedException e) {
516             LOG.error("failed to read host config from host {}", hostId, e);
517             return null;
518         }
519         return hostConfig.isPresent() ? hostConfig.get() : null;
520     }
521
522     private boolean isPortBound(final Port port) {
523         String hostId = getPortHostId(port);
524         return hostId != null && !hostId.isEmpty();
525     }
526
527     private boolean isPortVnicTypeDirect(Port port) {
528         PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
529         if (portBinding == null || portBinding.getVnicType() == null) {
530             // By default, VNIC_TYPE is NORMAL
531             return false;
532         }
533         String vnicType = portBinding.getVnicType().trim().toLowerCase(Locale.getDefault());
534         return vnicType.equals(NeutronConstants.VNIC_TYPE_DIRECT);
535     }
536
537     private boolean isSupportedVnicTypeByHost(final Port port, final String vnicType) {
538         Hostconfig hostConfig = getHostConfig(port);
539         String supportStr = String.format("\"vnic_type\": \"%s\"", vnicType);
540         if (hostConfig != null && hostConfig.getConfig().contains(supportStr)) {
541             return true;
542         }
543         return false;
544     }
545
546     private Map<String, JsonElement> unmarshal(final String profile) {
547         if (null == profile) {
548             return null;
549         }
550         Gson gson = new Gson();
551         JsonObject jsonObject = gson.fromJson(profile, JsonObject.class);
552         Map<String, JsonElement> map = new HashMap();
553         for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
554             map.put(entry.getKey(), entry.getValue());
555         }
556         return map;
557     }
558
559     private boolean isPortTypeSwitchdev(final Port port) {
560         if (!isPortVnicTypeDirect(port)) {
561             return false;
562         }
563
564         PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
565         String profile = portBinding.getProfile();
566         if (profile == null || profile.isEmpty()) {
567             LOG.debug("Port {} has no binding:profile values", port.getUuid());
568             return false;
569         }
570
571         Map<String, JsonElement> mapProfile = unmarshal(profile);
572         JsonElement capabilities = mapProfile.get(NeutronConstants.BINDING_PROFILE_CAPABILITIES);
573         LOG.debug("Port {} capabilities: {}", port.getUuid(), capabilities);
574         if (capabilities == null || !capabilities.isJsonArray()) {
575             LOG.debug("binding profile capabilities not in array format: {}", capabilities);
576             return false;
577         }
578
579         JsonArray capabilitiesArray = capabilities.getAsJsonArray();
580         Gson gson = new Gson();
581         JsonElement switchdevElement = gson.fromJson(NeutronConstants.SWITCHDEV, JsonElement.class);
582         return capabilitiesArray.contains(switchdevElement);
583     }
584
585
586     private void handleNeutronPortCreated(final Port port) {
587         final String portName = port.getUuid().getValue();
588         final Uuid portId = port.getUuid();
589         final List<FixedIps> portIpAddrsList = port.getFixedIps();
590         if (NeutronConstants.IS_ODL_DHCP_PORT.test(port)) {
591             return;
592         }
593         jobCoordinator.enqueueJob("PORT- " + portName, () -> {
594             // add direct port to subnetMaps config DS
595             if (!(NeutronUtils.isPortVnicTypeNormal(port)
596                 || isPortTypeSwitchdev(port)
597                 && isSupportedVnicTypeByHost(port, NeutronConstants.VNIC_TYPE_DIRECT))) {
598                 for (FixedIps ip: portIpAddrsList) {
599                     nvpnManager.updateSubnetmapNodeWithPorts(ip.getSubnetId(), null, portId);
600                 }
601                 LOG.info("Port {} is not a normal and not a direct with switchdev VNIC type ;"
602                          + "OF Port interfaces are not created", portName);
603                 return Collections.emptyList();
604             }
605             return Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
606                 LOG.info("Of-port-interface creation for port {}", portName);
607                 // Create of-port interface for this neutron port
608                 String portInterfaceName = createOfPortInterface(port, tx);
609                 LOG.debug("Creating ELAN Interface for port {}", portName);
610                 createElanInterface(port, portInterfaceName, tx);
611                 Set<Uuid> vpnIdList =  new HashSet<>();
612                 Set<Uuid> routerIds = new HashSet<>();
613                 for (FixedIps ip: portIpAddrsList) {
614                     Subnetmap subnetMap = nvpnManager.updateSubnetmapNodeWithPorts(ip.getSubnetId(), portId, null);
615                     if (subnetMap != null && subnetMap.getInternetVpnId() != null) {
616                         if (!vpnIdList.contains(subnetMap.getInternetVpnId())) {
617                             vpnIdList.add(subnetMap.getInternetVpnId());
618                         }
619                     }
620                     if (subnetMap != null && subnetMap.getVpnId() != null) {
621                         // can't use NeutronvpnUtils.getVpnForNetwork to optimise here, because it gives BGPVPN id
622                         // obtained subnetMaps belongs to one network => vpnId must be the same for each port Ip
623                         Uuid vpnId = subnetMap.getVpnId();
624                         if (vpnId != null) {
625                             vpnIdList.add(vpnId);
626                         }
627                     }
628                     if (subnetMap != null && subnetMap.getRouterId() != null) {
629                         routerIds.add(subnetMap.getRouterId());
630                     }
631                 }
632                 if (!vpnIdList.isEmpty()) {
633                     // create new vpn-interface for neutron port
634                     LOG.debug("handleNeutronPortCreated: Adding VPN Interface for port {} from network {}", portName,
635                             port.getNetworkId().toString());
636                     nvpnManager.createVpnInterface(vpnIdList, port, tx);
637                     if (!routerIds.isEmpty()) {
638                         for (Uuid routerId : routerIds) {
639                             nvpnManager.addToNeutronRouterInterfacesMap(routerId,port.getUuid().getValue());
640                         }
641                     }
642                 }
643             }));
644         });
645     }
646
647     private void handleNeutronPortDeleted(final Port port) {
648         final String portName = port.getUuid().getValue();
649         final Uuid portId = port.getUuid();
650         final List<FixedIps> portIpsList = port.getFixedIps();
651         jobCoordinator.enqueueJob("PORT- " + portName,
652             () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
653                 if (!(NeutronUtils.isPortVnicTypeNormal(port) || isPortTypeSwitchdev(port))) {
654                     for (FixedIps ip : portIpsList) {
655                         // remove direct port from subnetMaps config DS
656                         nvpnManager.removePortsFromSubnetmapNode(ip.getSubnetId(), null, portId);
657                     }
658                     LOG.info("Port {} is not a normal and not a direct with switchdev VNIC type ;"
659                             + "Skipping OF Port interfaces removal", portName);
660                     return;
661                 }
662                 Uuid vpnId = null;
663                 Set<Uuid> routerIds = new HashSet<>();
664                 Uuid internetVpnId = null;
665                 for (FixedIps ip : portIpsList) {
666                     Subnetmap subnetMap = nvpnManager.removePortsFromSubnetmapNode(ip.getSubnetId(), portId, null);
667                     if (subnetMap == null) {
668                         continue;
669                     }
670                     if (subnetMap.getVpnId() != null) {
671                         // can't use NeutronvpnUtils.getVpnForNetwork to optimise here, because it gives BGPVPN id
672                         // obtained subnetMaps belongs to one network => vpnId must be the same for each port Ip
673                         vpnId = subnetMap.getVpnId();
674                     }
675                     if (subnetMap.getRouterId() != null) {
676                         routerIds.add(subnetMap.getRouterId());
677                     }
678                     internetVpnId = subnetMap.getInternetVpnId();
679
680                     if (NeutronConstants.DEVICE_OWNER_GATEWAY_INF.equals(port.getDeviceOwner())
681                         || NeutronConstants.DEVICE_OWNER_FLOATING_IP.equals(port.getDeviceOwner())) {
682                         String ipAddress = ip.getIpAddress().stringValue();
683                         if (vpnId != null) {
684                             neutronvpnUtils.removeVpnPortFixedIpToPort(vpnId.getValue(), ipAddress, confTx);
685                         }
686                         if (internetVpnId != null) {
687                             neutronvpnUtils.removeVpnPortFixedIpToPort(internetVpnId.getValue(),
688                                 ipAddress, confTx);
689                         }
690                     }
691                 }
692                 if (vpnId != null || internetVpnId != null) {
693                     // remove vpn-interface for this neutron port
694                     LOG.debug("removing VPN Interface for port {}", portName);
695                     if (!routerIds.isEmpty()) {
696                         for (Uuid routerId : routerIds) {
697                             nvpnManager.removeFromNeutronRouterInterfacesMap(routerId, portName);
698                         }
699                     }
700                     nvpnManager.deleteVpnInterface(portName, null /* vpn-id */, confTx);
701                 }
702                 // Remove of-port interface for this neutron port
703                 // ELAN interface is also implicitly deleted as part of this operation
704                 LOG.debug("Of-port-interface removal for port {}", portName);
705                 deleteOfPortInterface(port, confTx);
706                 //dissociate fixedIP from floatingIP if associated
707                 nvpnManager.dissociatefixedIPFromFloatingIP(port.getUuid().getValue());
708             })));
709     }
710
711
712     private void handleNeutronPortUpdated(final Port portoriginal, final Port portupdate) {
713         final List<FixedIps> portoriginalIps = portoriginal.getFixedIps();
714         final List<FixedIps> portupdateIps = portupdate.getFixedIps();
715         if (portoriginalIps == null || portoriginalIps.isEmpty()) {
716             handleNeutronPortCreated(portupdate);
717             return;
718         }
719
720         if (portupdateIps == null || portupdateIps.isEmpty()) {
721             LOG.info("Ignoring portUpdate (fixed_ip removal) for port {} as this case is handled "
722                       + "during subnet deletion event.", portupdate.getUuid().getValue());
723             return;
724         }
725
726         if (NeutronConstants.IS_ODL_DHCP_PORT.test(portupdate)) {
727             return;
728         }
729
730         jobCoordinator.enqueueJob("PORT- " + portupdate.getUuid().getValue(),
731             () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
732                 final List<Uuid> originalSnMapsIds = portoriginalIps.stream().map(FixedIps::getSubnetId)
733                         .collect(Collectors.toList());
734                 final List<Uuid> updateSnMapsIds = portupdateIps.stream().map(FixedIps::getSubnetId)
735                         .collect(Collectors.toList());
736                 Set<Uuid> originalRouterIds = new HashSet<>();
737                 Set<Uuid> oldVpnIds = new HashSet<>();
738                 for (Uuid snId: originalSnMapsIds) {
739                     if (!updateSnMapsIds.remove(snId)) {
740                         // snId was present in originalSnMapsIds, but not in updateSnMapsIds
741                         Subnetmap subnetMapOld = nvpnManager.removePortsFromSubnetmapNode(snId, portoriginal.getUuid(),
742                                 null);
743                         if (subnetMapOld != null && subnetMapOld.getVpnId() != null) {
744                             oldVpnIds.add(subnetMapOld.getVpnId());
745                         }
746                         if (subnetMapOld != null && subnetMapOld.getInternetVpnId() != null) {
747                             oldVpnIds.add(subnetMapOld.getInternetVpnId());
748                         }
749                         if (subnetMapOld != null && subnetMapOld.getRouterId() != null) {
750                             originalRouterIds.add(subnetMapOld.getRouterId());
751                         }
752                     }
753                 }
754                 Set<Uuid> newVpnIds = new HashSet<>();
755                 Set<Uuid> newRouterIds = new HashSet<>();
756                 for (Uuid snId: updateSnMapsIds) {
757                     Subnetmap subnetMapNew = nvpnManager.updateSubnetmapNodeWithPorts(snId, portupdate.getUuid(), null);
758                     if (subnetMapNew != null) {
759                         if (subnetMapNew.getVpnId() != null) {
760                             newVpnIds.add(subnetMapNew.getVpnId());
761                         }
762                         if (subnetMapNew.getInternetVpnId() != null) {
763                             newVpnIds.add(subnetMapNew.getInternetVpnId());
764                         }
765                         if (subnetMapNew.getRouterId() != null) {
766                             newRouterIds.add(subnetMapNew.getRouterId());
767                         }
768                     }
769                 }
770                 if (!oldVpnIds.isEmpty()) {
771                     LOG.info("removing VPN Interface for port {}", portoriginal.getUuid().getValue());
772                     if (!originalRouterIds.isEmpty()) {
773                         for (Uuid routerId : originalRouterIds) {
774                             nvpnManager.removeFromNeutronRouterInterfacesMap(routerId,
775                                     portoriginal.getUuid().getValue());
776                         }
777                     }
778                     nvpnManager.deleteVpnInterface(portoriginal.getUuid().getValue(),
779                                                    null /* vpn-id */, confTx);
780                 }
781                 if (!newVpnIds.isEmpty()) {
782                     LOG.info("Adding VPN Interface for port {}", portupdate.getUuid().getValue());
783                     nvpnManager.createVpnInterface(newVpnIds, portupdate, confTx);
784                     if (!newRouterIds.isEmpty()) {
785                         for (Uuid routerId : newRouterIds) {
786                             nvpnManager.addToNeutronRouterInterfacesMap(routerId,portupdate.getUuid().getValue());
787                         }
788                     }
789                 }
790             })));
791     }
792
793     private InterfaceAclBuilder handlePortSecurityUpdated(Port portOriginal,
794             Port portUpdated, boolean origSecurityEnabled, boolean updatedSecurityEnabled,
795             InterfaceBuilder interfaceBuilder) {
796         InterfaceAclBuilder interfaceAclBuilder = null;
797         if (origSecurityEnabled != updatedSecurityEnabled) {
798             interfaceAclBuilder = new InterfaceAclBuilder();
799             interfaceAclBuilder.setPortSecurityEnabled(updatedSecurityEnabled);
800             if (updatedSecurityEnabled) {
801                 // Handle security group enabled
802                 NeutronvpnUtils.populateInterfaceAclBuilder(interfaceAclBuilder, portUpdated);
803                 neutronvpnUtils.populateSubnetInfo(portUpdated);
804             } else {
805                 // Handle security group disabled
806                 interfaceAclBuilder.setSecurityGroups(new ArrayList<>());
807                 interfaceAclBuilder.setAllowedAddressPairs(new ArrayList<>());
808             }
809         } else {
810             if (updatedSecurityEnabled) {
811                 // handle SG add/delete delta
812                 InterfaceAcl interfaceAcl = interfaceBuilder.augmentation(InterfaceAcl.class);
813                 interfaceAclBuilder = new InterfaceAclBuilder(interfaceAcl);
814                 interfaceAclBuilder.setSecurityGroups(
815                         NeutronvpnUtils.getUpdatedSecurityGroups(interfaceAcl.getSecurityGroups(),
816                                 portOriginal.getSecurityGroups(), portUpdated.getSecurityGroups()));
817                 List<AllowedAddressPairs> updatedAddressPairs = NeutronvpnUtils.getUpdatedAllowedAddressPairs(
818                         interfaceAcl.getAllowedAddressPairs(), portOriginal.getAllowedAddressPairs(),
819                         portUpdated.getAllowedAddressPairs());
820                 interfaceAclBuilder.setAllowedAddressPairs(NeutronvpnUtils.getAllowedAddressPairsForFixedIps(
821                         updatedAddressPairs, portOriginal.getMacAddress(), portOriginal.getFixedIps(),
822                         portUpdated.getFixedIps()));
823
824                 if (portOriginal.getFixedIps() != null
825                         && !portOriginal.getFixedIps().equals(portUpdated.getFixedIps())) {
826                     neutronvpnUtils.populateSubnetInfo(portUpdated);
827                 }
828             }
829         }
830         return interfaceAclBuilder;
831     }
832
833     private String createOfPortInterface(Port port, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
834         Interface inf = createInterface(port);
835         String infName = inf.getName();
836
837         InstanceIdentifier<Interface> interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(infName);
838         try {
839             Optional<Interface> optionalInf =
840                     SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
841                             interfaceIdentifier);
842             if (!optionalInf.isPresent()) {
843                 wrtConfigTxn.put(interfaceIdentifier, inf);
844             } else {
845                 LOG.warn("Interface {} is already present", infName);
846             }
847         } catch (ReadFailedException e) {
848             LOG.error("failed to create interface {}", infName, e);
849         }
850         return infName;
851     }
852
853     private Interface createInterface(Port port) {
854         String interfaceName = port.getUuid().getValue();
855         IfL2vlan.L2vlanMode l2VlanMode = IfL2vlan.L2vlanMode.Trunk;
856         InterfaceBuilder interfaceBuilder = new InterfaceBuilder();
857         IfL2vlanBuilder ifL2vlanBuilder = new IfL2vlanBuilder();
858
859         Network network = neutronvpnUtils.getNeutronNetwork(port.getNetworkId());
860         Boolean isVlanTransparent = network.isVlanTransparent();
861         if (isVlanTransparent != null && isVlanTransparent) {
862             l2VlanMode = IfL2vlan.L2vlanMode.Transparent;
863         }
864
865         ifL2vlanBuilder.setL2vlanMode(l2VlanMode);
866
867         interfaceBuilder.setEnabled(true).setName(interfaceName).setType(L2vlan.class)
868                 .addAugmentation(IfL2vlan.class, ifL2vlanBuilder.build());
869
870         if (NeutronvpnUtils.getPortSecurityEnabled(port)) {
871             InterfaceAclBuilder interfaceAclBuilder = new InterfaceAclBuilder();
872             interfaceAclBuilder.setPortSecurityEnabled(true);
873             NeutronvpnUtils.populateInterfaceAclBuilder(interfaceAclBuilder, port);
874             interfaceBuilder.addAugmentation(InterfaceAcl.class, interfaceAclBuilder.build());
875             neutronvpnUtils.populateSubnetInfo(port);
876         }
877         return interfaceBuilder.build();
878     }
879
880     private void deleteOfPortInterface(Port port, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
881         String name = port.getUuid().getValue();
882         LOG.debug("Removing OFPort Interface {}", name);
883         InstanceIdentifier<Interface>  interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(name);
884         try {
885             Optional<Interface> optionalInf =
886                     SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
887                             interfaceIdentifier);
888             if (optionalInf.isPresent()) {
889                 wrtConfigTxn.delete(interfaceIdentifier);
890             } else {
891                 LOG.warn("deleteOfPortInterface: Interface {} is not present", name);
892             }
893         } catch (ReadFailedException e) {
894             LOG.error("deleteOfPortInterface: Failed to delete interface {}", name, e);
895         }
896     }
897
898     private void createElanInterface(Port port, String name,
899                                      TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
900         String elanInstanceName = port.getNetworkId().getValue();
901         List<StaticMacEntries> staticMacEntries = NeutronvpnUtils.buildStaticMacEntry(port);
902
903         InstanceIdentifier<ElanInterface> id = InstanceIdentifier.builder(ElanInterfaces.class).child(ElanInterface
904                 .class, new ElanInterfaceKey(name)).build();
905         ElanInterface elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName)
906                 .setName(name).setStaticMacEntries(staticMacEntries).withKey(new ElanInterfaceKey(name)).build();
907         wrtConfigTxn.put(id, elanInterface);
908         LOG.debug("Creating new ELan Interface {}", elanInterface);
909     }
910
911     private void deleteElanInterface(String name, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
912         InstanceIdentifier<ElanInterface> id = InstanceIdentifier.builder(ElanInterfaces.class).child(ElanInterface
913                 .class, new ElanInterfaceKey(name)).build();
914         wrtConfigTxn.delete(id);
915     }
916
917     // TODO Clean up the exception handling
918     @SuppressWarnings("checkstyle:IllegalCatch")
919     private void addToFloatingIpPortInfo(Uuid floatingIpId, Uuid floatingIpPortId, Uuid floatingIpPortSubnetId, String
920                                          floatingIpPortMacAddress) {
921         InstanceIdentifier id = NeutronvpnUtils.buildfloatingIpIdToPortMappingIdentifier(floatingIpId);
922         try {
923             FloatingIpIdToPortMappingBuilder floatingipIdToPortMacMappingBuilder = new
924                 FloatingIpIdToPortMappingBuilder().withKey(new FloatingIpIdToPortMappingKey(floatingIpId))
925                 .setFloatingIpId(floatingIpId).setFloatingIpPortId(floatingIpPortId)
926                 .setFloatingIpPortSubnetId(floatingIpPortSubnetId)
927                 .setFloatingIpPortMacAddress(floatingIpPortMacAddress);
928             LOG.debug("Creating floating IP UUID {} to Floating IP neutron port {} mapping in Floating IP"
929                 + " Port Info Config DS", floatingIpId.getValue(), floatingIpPortId.getValue());
930             MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id,
931                 floatingipIdToPortMacMappingBuilder.build());
932         } catch (Exception e) {
933             LOG.error("Creating floating IP UUID {} to Floating IP neutron port {} mapping in Floating IP"
934                 + " Port Info Config DS failed", floatingIpId.getValue(), floatingIpPortId.getValue(), e);
935         }
936     }
937
938     private Set<FixedIps> getFixedIpSet(List<FixedIps> fixedIps) {
939         return fixedIps != null ? new HashSet<>(fixedIps) : Collections.emptySet();
940     }
941 }