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