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