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