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