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