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