Internet BGPVPN traffic is not working for IPv6
[netvirt.git] / neutronvpn / impl / src / main / java / org / opendaylight / netvirt / neutronvpn / NeutronPortChangeListener.java
1 /*
2  * Copyright © 2015, 2018 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.netvirt.neutronvpn;
9
10 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
11
12 import com.google.common.base.Optional;
13 import com.google.common.base.Strings;
14 import com.google.gson.Gson;
15 import com.google.gson.JsonArray;
16 import com.google.gson.JsonElement;
17 import com.google.gson.JsonObject;
18 import java.time.Duration;
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.List;
24 import java.util.Locale;
25 import java.util.Map;
26 import java.util.Set;
27 import java.util.stream.Collectors;
28 import javax.annotation.PostConstruct;
29 import javax.inject.Singleton;
30 import org.apache.commons.lang3.ObjectUtils;
31 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
32 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
33 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
34 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
35 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
36 import org.opendaylight.genius.datastoreutils.listeners.DataTreeEventCallbackRegistrar;
37 import org.opendaylight.genius.infra.Datastore;
38 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
39 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
40 import org.opendaylight.genius.infra.TypedWriteTransaction;
41 import org.opendaylight.genius.mdsalutil.MDSALUtil;
42 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
43 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
44 import org.opendaylight.netvirt.elanmanager.api.IElanService;
45 import org.opendaylight.netvirt.neutronvpn.api.enums.IpVersionChoice;
46 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronConstants;
47 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
48 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
49 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlan;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlanBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.InterfaceAcl;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.InterfaceAclBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.AllowedAddressPairs;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceKey;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntries;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
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         String portName = input.getUuid().getValue();
137         LOG.trace("Adding Port : key: {}, value={}", identifier, input);
138         Network network = neutronvpnUtils.getNeutronNetwork(input.getNetworkId());
139         if (network == null || !NeutronvpnUtils.isNetworkTypeSupported(network)) {
140             LOG.warn("neutron vpn received a port add() for a network without a provider extension augmentation "
141                             + "or with an unsupported network type for the port {} which is part of network {}",
142                     portName, network);
143             return;
144         }
145
146         neutronvpnUtils.addToPortCache(input);
147         String portStatus = NeutronUtils.PORT_STATUS_DOWN;
148         if (!Strings.isNullOrEmpty(input.getDeviceOwner()) && !Strings.isNullOrEmpty(input.getDeviceId())) {
149             if (NeutronConstants.DEVICE_OWNER_ROUTER_INF.equals(input.getDeviceOwner())) {
150                 handleRouterInterfaceAdded(input);
151                 NeutronUtils.createPortStatus(input.getUuid().getValue(), NeutronUtils.PORT_STATUS_ACTIVE, dataBroker);
152                 return;
153             }
154             if (NeutronConstants.DEVICE_OWNER_GATEWAY_INF.equals(input.getDeviceOwner())) {
155                 handleRouterGatewayUpdated(input, false);
156                 portStatus = NeutronUtils.PORT_STATUS_ACTIVE;
157             } else if (NeutronConstants.DEVICE_OWNER_FLOATING_IP.equals(input.getDeviceOwner())) {
158                 handleFloatingIpPortUpdated(null, input);
159                 portStatus = NeutronUtils.PORT_STATUS_ACTIVE;
160             }
161         }
162         // Switchdev ports need to be bounded to a host before creation
163         // in order to validate the supported vnic types from the hostconfig
164         if (input.getFixedIps() != null
165             && !input.getFixedIps().isEmpty()
166             && !(isPortTypeSwitchdev(input) && !isPortBound(input))) {
167             handleNeutronPortCreated(input);
168         }
169         NeutronUtils.createPortStatus(input.getUuid().getValue(), portStatus, dataBroker);
170     }
171
172     @Override
173     protected void remove(InstanceIdentifier<Port> identifier, Port input) {
174         LOG.trace("Removing Port : key: {}, value={}", identifier, input);
175         Network network = neutronvpnUtils.getNeutronNetwork(input.getNetworkId());
176         // need to proceed with deletion in case network is null for a case where v2 sync happens and a read for
177         // network from NN returns null, but the deletion process for port needs to continue
178         if (network != null && !NeutronvpnUtils.isNetworkTypeSupported(network)) {
179             String portName = input.getUuid().getValue();
180             LOG.warn("neutron vpn received a port remove() for a network without a provider extension augmentation "
181                             + "or with an unsupported network type for the port {} which is part of network {}",
182                     portName, network);
183             return;
184         }
185         neutronvpnUtils.removeFromPortCache(input);
186         NeutronUtils.deletePortStatus(input.getUuid().getValue(), dataBroker);
187
188         if (!Strings.isNullOrEmpty(input.getDeviceOwner()) && !Strings.isNullOrEmpty(input.getDeviceId())) {
189             if (NeutronConstants.DEVICE_OWNER_ROUTER_INF.equals(input.getDeviceOwner())) {
190                 handleRouterInterfaceRemoved(input);
191                 /* nothing else to do here */
192                 return;
193             } else if (NeutronConstants.DEVICE_OWNER_GATEWAY_INF.equals(input.getDeviceOwner())
194                     || NeutronConstants.DEVICE_OWNER_FLOATING_IP.equals(input.getDeviceOwner())) {
195                 handleRouterGatewayUpdated(input, true);
196                 elanService.removeKnownL3DmacAddress(input.getMacAddress().getValue(), input.getNetworkId().getValue());
197             }
198         }
199         if (input.getFixedIps() != null) {
200             handleNeutronPortDeleted(input);
201         }
202     }
203
204     @Override
205     protected void update(InstanceIdentifier<Port> identifier, Port original, Port update) {
206         // Switchdev ports need to be bounded to a host before creation
207         // in order to validate the supported vnic types from the hostconfig
208         if (isPortTypeSwitchdev(original)
209             && !isPortBound(original)
210             && isPortBound(update)) {
211             handleNeutronPortCreated(update);
212         }
213         final String portName = update.getUuid().getValue();
214         Network network = neutronvpnUtils.getNeutronNetwork(update.getNetworkId());
215         LOG.info("Update port {} from network {}", portName, update.getNetworkId().toString());
216         if (network == null || !NeutronvpnUtils.isNetworkTypeSupported(network)) {
217             LOG.warn("neutron vpn received a port update() for a network without a provider extension augmentation "
218                     + "or with an unsupported network type for the port {} which is part of network {}",
219                     portName, network);
220             return;
221         }
222         neutronvpnUtils.addToPortCache(update);
223
224         if ((Strings.isNullOrEmpty(original.getDeviceOwner()) || Strings.isNullOrEmpty(original.getDeviceId())
225                 || NeutronConstants.FLOATING_IP_DEVICE_ID_PENDING.equalsIgnoreCase(original.getDeviceId()))
226                 && !Strings.isNullOrEmpty(update.getDeviceOwner()) && !Strings.isNullOrEmpty(update.getDeviceId())) {
227             if (NeutronConstants.DEVICE_OWNER_ROUTER_INF.equals(update.getDeviceOwner())) {
228                 handleRouterInterfaceAdded(update);
229                 return;
230             }
231             if (NeutronConstants.DEVICE_OWNER_GATEWAY_INF.equals(update.getDeviceOwner())) {
232                 handleRouterGatewayUpdated(update, false);
233             } else if (NeutronConstants.DEVICE_OWNER_FLOATING_IP.equals(update.getDeviceOwner())) {
234                 handleFloatingIpPortUpdated(original, update);
235             }
236         } else {
237             Set<FixedIps> oldIPs = getFixedIpSet(original.getFixedIps());
238             Set<FixedIps> newIPs = getFixedIpSet(update.getFixedIps());
239             if (!oldIPs.equals(newIPs)) {
240                 handleNeutronPortUpdated(original, update);
241             }
242         }
243
244         // check if port security enabled/disabled as part of port update
245         boolean origSecurityEnabled = NeutronvpnUtils.getPortSecurityEnabled(original);
246         boolean updatedSecurityEnabled = NeutronvpnUtils.getPortSecurityEnabled(update);
247
248         if (origSecurityEnabled || updatedSecurityEnabled) {
249             InstanceIdentifier<Interface>  interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(portName);
250             jobCoordinator.enqueueJob("PORT- " + portName,
251                 () -> Collections.singletonList(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
252                     confTx -> {
253                         Optional<Interface> optionalInf =
254                                 confTx.read(interfaceIdentifier).get();
255                         if (optionalInf.isPresent()) {
256                             InterfaceBuilder interfaceBuilder = new InterfaceBuilder(optionalInf.get());
257                             InterfaceAcl infAcl = handlePortSecurityUpdated(original, update,
258                                     origSecurityEnabled, updatedSecurityEnabled, interfaceBuilder).build();
259                             interfaceBuilder.addAugmentation(InterfaceAcl.class, infAcl);
260                             LOG.info("update: Of-port-interface updation for port {}", portName);
261                             // Update OFPort interface for this neutron port
262                             confTx.put(interfaceIdentifier, interfaceBuilder.build());
263                         } else {
264                             LOG.warn("update: Interface {} is not present", portName);
265                         }
266                     })));
267         }
268     }
269
270     private void handleFloatingIpPortUpdated(Port original, Port update) {
271         if ((original == null || original.getDeviceId().equals(NeutronConstants.FLOATING_IP_DEVICE_ID_PENDING))
272             && !update.getDeviceId().equals(NeutronConstants.FLOATING_IP_DEVICE_ID_PENDING)) {
273             // populate floating-ip uuid and floating-ip port attributes (uuid, mac and subnet id for the ONLY
274             // fixed IP) to be used by NAT, depopulated in NATService once mac is retrieved in the removal path
275             addToFloatingIpPortInfo(new Uuid(update.getDeviceId()), update.getUuid(), update.getFixedIps().get(0)
276                     .getSubnetId(), update.getMacAddress().getValue());
277             elanService.addKnownL3DmacAddress(update.getMacAddress().getValue(), update.getNetworkId().getValue());
278         }
279     }
280
281     private void handleRouterInterfaceAdded(Port routerPort) {
282         if (routerPort.getDeviceId() != null) {
283             Uuid routerId = new Uuid(routerPort.getDeviceId());
284             Uuid infNetworkId = routerPort.getNetworkId();
285             Uuid existingVpnId = neutronvpnUtils.getVpnForNetwork(infNetworkId);
286
287             elanService.addKnownL3DmacAddress(routerPort.getMacAddress().getValue(), infNetworkId.getValue());
288             if (existingVpnId == null) {
289                 Set<Uuid> listVpnIds = new HashSet<>();
290                 Uuid vpnId = neutronvpnUtils.getVpnForRouter(routerId, true);
291                 if (vpnId == null) {
292                     vpnId = routerId;
293                 }
294                 listVpnIds.add(vpnId);
295                 Uuid internetVpnId = neutronvpnUtils.getInternetvpnUuidBoundToRouterId(routerId);
296                 List<Subnetmap> subnetMapList = new ArrayList<>();
297                 List<FixedIps> portIps = routerPort.getFixedIps();
298                 boolean portIsIpv6 = false;
299                 for (FixedIps portIP : portIps) {
300                     // NOTE:  Please donot change the order of calls to updateSubnetNodeWithFixedIP
301                     // and addSubnetToVpn here
302                     if (internetVpnId != null
303                         && portIP.getIpAddress().getIpv6Address() != null) {
304                         portIsIpv6 = true;
305                     }
306                     String ipValue = portIP.getIpAddress().stringValue();
307                     Uuid subnetId = portIP.getSubnetId();
308                     nvpnManager.updateSubnetNodeWithFixedIp(subnetId, routerId,
309                             routerPort.getUuid(), ipValue, routerPort.getMacAddress().getValue(), vpnId);
310                     Subnetmap sn = neutronvpnUtils.getSubnetmap(subnetId);
311                     subnetMapList.add(sn);
312                 }
313                 if (portIsIpv6) {
314                     listVpnIds.add(internetVpnId);
315                     if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(
316                                      IpVersionChoice.IPV6, routerId, true)) {
317                         neutronvpnUtils.updateVpnInstanceWithIpFamily(internetVpnId.getValue(), IpVersionChoice.IPV6,
318                                 true);
319                         neutronvpnUtils.updateVpnInstanceWithFallback(internetVpnId, true);
320                     }
321                 }
322                 if (! subnetMapList.isEmpty()) {
323                     nvpnManager.createVpnInterface(listVpnIds, routerPort, null);
324                 }
325                 IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
326                 for (FixedIps portIP : routerPort.getFixedIps()) {
327                     String ipValue = portIP.getIpAddress().stringValue();
328                     ipVersion = NeutronvpnUtils.getIpVersionFromString(ipValue);
329                     if (ipVersion.isIpVersionChosen(IpVersionChoice.IPV4)) {
330                         nvpnManager.addSubnetToVpn(vpnId, portIP.getSubnetId(),
331                                                         null /* internet-vpn-id */);
332                     } else {
333                         nvpnManager.addSubnetToVpn(vpnId, portIP.getSubnetId(), internetVpnId);
334                     }
335                     LOG.trace("NeutronPortChangeListener Add Subnet Gateway IP {} MAC {} Interface {} VPN {}",
336                             ipValue, routerPort.getMacAddress(),
337                             routerPort.getUuid().getValue(), vpnId.getValue());
338                 }
339                 if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(ipVersion, routerId, true)) {
340                     LOG.debug("vpnInstanceOpDataEntry is getting update with ip address family {} for VPN {}",
341                             ipVersion, vpnId.getValue());
342                     neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, true);
343                 }
344                 nvpnManager.addToNeutronRouterInterfacesMap(routerId, routerPort.getUuid().getValue());
345                 jobCoordinator.enqueueJob(routerId.toString(), () -> {
346                     nvpnNatManager.handleSubnetsForExternalRouter(routerId);
347                     return Collections.emptyList();
348                 });
349                 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
350                     confTx -> {
351                         String portInterfaceName = createOfPortInterface(routerPort, confTx);
352                         createElanInterface(routerPort, portInterfaceName, confTx);
353                     }), LOG, "Error creating ELAN interface for {}", routerPort);
354             } else {
355                 LOG.error("Neutron network {} corresponding to router interface port {} for neutron router {}"
356                     + " already associated to VPN {}", infNetworkId.getValue(), routerPort.getUuid().getValue(),
357                     routerId.getValue(), existingVpnId.getValue());
358             }
359         }
360     }
361
362     private void handleRouterInterfaceRemoved(Port routerPort) {
363         if (routerPort.getDeviceId() != null) {
364             Uuid routerId = new Uuid(routerPort.getDeviceId());
365             Uuid infNetworkId = routerPort.getNetworkId();
366             elanService.removeKnownL3DmacAddress(routerPort.getMacAddress().getValue(), infNetworkId.getValue());
367             Uuid vpnId = ObjectUtils.defaultIfNull(neutronvpnUtils.getVpnForRouter(routerId, true),
368                     routerId);
369             List<FixedIps> portIps = routerPort.getFixedIps();
370             boolean vpnInstanceInternetIpVersionRemoved = false;
371             Uuid vpnInstanceInternetUuid = null;
372             for (FixedIps portIP : portIps) {
373                 // Internet VPN : flush InternetVPN first
374                 Uuid subnetId = portIP.getSubnetId();
375                 Subnetmap sn = neutronvpnUtils.getSubnetmap(subnetId);
376                 if (sn != null && sn.getInternetVpnId() != null) {
377                     if (neutronvpnUtils.shouldVpnHandleIpVersionChangeToRemove(sn, sn.getInternetVpnId())) {
378                         vpnInstanceInternetIpVersionRemoved = true;
379                         vpnInstanceInternetUuid = sn.getInternetVpnId();
380                     }
381                     nvpnManager.updateVpnInternetForSubnet(sn, sn.getInternetVpnId(), false);
382                 }
383             }
384             /* Remove ping responder for router interfaces
385              *  A router interface reference in a VPN will have to be removed before the host interface references
386              * for that subnet in the VPN are removed. This is to ensure that the FIB Entry of the router interface
387              *  is not the last entry to be removed for that subnet in the VPN.
388              *  If router interface FIB entry is the last to be removed for a subnet in a VPN , then all the host
389              *  interface references in the vpn will already have been cleared, which will cause failures in
390              *  cleanup of router interface flows*/
391             nvpnManager.deleteVpnInterface(routerPort.getUuid().getValue(),
392                                            null /* vpn-id */, null /* wrtConfigTxn*/);
393             final Uuid internetVpnId = vpnInstanceInternetUuid;
394             // update RouterInterfaces map
395             ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
396                 confTx -> {
397                     IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
398                     for (FixedIps portIP : portIps) {
399                         Subnetmap sn = neutronvpnUtils.getSubnetmap(portIP.getSubnetId());
400                         // router Port have either IPv4 or IPv6, never both
401                         ipVersion = neutronvpnUtils.getIpVersionFromString(sn.getSubnetIp());
402                         String ipValue = portIP.getIpAddress().stringValue();
403                         neutronvpnUtils.removeVpnPortFixedIpToPort(vpnId.getValue(), ipValue, confTx);
404                         // NOTE:  Please donot change the order of calls to removeSubnetFromVpn and
405                         // and updateSubnetNodeWithFixedIP
406                         nvpnManager.removeSubnetFromVpn(vpnId, portIP.getSubnetId(), internetVpnId);
407                         nvpnManager.updateSubnetNodeWithFixedIp(portIP.getSubnetId(), null, null,
408                             null, null, null);
409                     }
410                     nvpnManager.removeFromNeutronRouterInterfacesMap(routerId, routerPort.getUuid().getValue());
411                     deleteElanInterface(routerPort.getUuid().getValue(), confTx);
412                     deleteOfPortInterface(routerPort, confTx);
413                     jobCoordinator.enqueueJob(routerId.toString(), () -> {
414                         nvpnNatManager.handleSubnetsForExternalRouter(routerId);
415                         return Collections.emptyList();
416                     });
417                     if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(ipVersion, routerId, false)) {
418                         LOG.debug("vpnInstanceOpDataEntry is getting update with ip address family {} for VPN {}",
419                                 ipVersion, vpnId.getValue());
420                         neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, false);
421                     }
422                 }), LOG, "Error handling interface removal");
423             if (vpnInstanceInternetIpVersionRemoved) {
424                 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnInstanceInternetUuid.getValue(),
425                         IpVersionChoice.IPV6, false);
426                 neutronvpnUtils.updateVpnInstanceWithFallback(vpnInstanceInternetUuid, false);
427             }
428         }
429     }
430
431     private void handleRouterGatewayUpdated(Port routerGwPort, boolean isRtrGwRemoved) {
432         Uuid routerId = new Uuid(routerGwPort.getDeviceId());
433         Uuid networkId = routerGwPort.getNetworkId();
434         Network network = neutronvpnUtils.getNeutronNetwork(networkId);
435         if (network == null) {
436             return;
437         }
438         boolean isExternal = NeutronvpnUtils.getIsExternal(network);
439         if (isExternal) {
440             Uuid vpnInternetId = neutronvpnUtils.getVpnForNetwork(networkId);
441             if (vpnInternetId != null) {
442                 if (isRtrGwRemoved) {
443                      //Set VPN type BGPVPNExternal from BGPVPNInternet for removal case
444                     neutronvpnUtils.updateVpnInstanceOpWithType(VpnInstanceOpDataEntry.BgpvpnType.BGPVPNExternal,
445                             vpnInternetId);
446                 } else {
447                     //Set VPN type BGPVPNInternet from BGPVPNExternal for add case
448                     neutronvpnUtils.updateVpnInstanceOpWithType(VpnInstanceOpDataEntry.BgpvpnType.BGPVPNInternet,
449                             vpnInternetId);
450                     nvpnManager.updateVpnMaps(vpnInternetId, null, routerId, null, null);
451                 }
452                 List<Subnetmap> snList = neutronvpnUtils.getNeutronRouterSubnetMaps(routerId);
453                 for (Subnetmap sn : snList) {
454                     if (sn.getNetworkId() == networkId) {
455                         continue;
456                     }
457                     if (NeutronvpnUtils.getIpVersionFromString(sn.getSubnetIp()) != IpVersionChoice.IPV6) {
458                         continue;
459                     }
460                     if (isRtrGwRemoved) {
461                         nvpnManager.removeV6PrivateSubnetToExtNetwork(routerId, vpnInternetId, sn);
462                     } else {
463                         nvpnManager.addV6PrivateSubnetToExtNetwork(routerId, vpnInternetId, sn);
464                     }
465                 }
466                 //Update Internet BGP-VPN
467                 if (isRtrGwRemoved) {
468                     nvpnManager.updateVpnMaps(vpnInternetId, null, null, null, null);
469                 }
470             }
471         }
472         elanService.addKnownL3DmacAddress(routerGwPort.getMacAddress().getValue(), networkId.getValue());
473
474         Router router = neutronvpnUtils.getNeutronRouter(routerId);
475         if (router == null) {
476             LOG.warn("No router found for router GW port {} for router {}", routerGwPort.getUuid().getValue(),
477                     routerId.getValue());
478             // NETVIRT-1249
479             eventCallbacks.onAddOrUpdate(LogicalDatastoreType.CONFIGURATION,
480                     neutronvpnUtils.getNeutronRouterIid(routerId), (unused, newRouter) -> {
481                     setupGwMac(newRouter, routerGwPort, routerId);
482                     return DataTreeEventCallbackRegistrar.NextAction.UNREGISTER;
483                 }, Duration.ofSeconds(3), iid -> {
484                     LOG.error("GwPort {} added without Router", routerGwPort.getUuid().getValue());
485                 });
486             return;
487         }
488         setupGwMac(router, routerGwPort, routerId);
489     }
490
491     private void setupGwMac(Router router, Port routerGwPort, Uuid routerId) {
492         gwMacResolver.sendArpRequestsToExtGateways(router);
493         jobCoordinator.enqueueJob(routerId.toString(), () -> {
494             setExternalGwMac(routerGwPort, routerId);
495             return Collections.emptyList();
496         });
497     }
498
499     private void setExternalGwMac(Port routerGwPort, Uuid routerId) {
500         // During full-sync networking-odl syncs routers before ports. As such,
501         // the MAC of the router's gw port is not available to be set when the
502         // router is written. We catch that here.
503         InstanceIdentifier<Routers> routersId = NeutronvpnUtils.buildExtRoutersIdentifier(routerId);
504         Optional<Routers> optionalRouter = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routersId);
505         if (!optionalRouter.isPresent()) {
506             return;
507         }
508
509         Routers extRouters = optionalRouter.get();
510         if (extRouters.getExtGwMacAddress() != null) {
511             return;
512         }
513
514         RoutersBuilder builder = new RoutersBuilder(extRouters);
515         builder.setExtGwMacAddress(routerGwPort.getMacAddress().getValue());
516         MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, routersId, builder.build());
517     }
518
519     private String getPortHostId(final Port port) {
520         if (port != null) {
521             PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
522             if (portBinding != null) {
523                 return portBinding.getHostId();
524             }
525         }
526         return null;
527     }
528
529     private Hostconfig getHostConfig(final Port port) {
530         String hostId = getPortHostId(port);
531         if (hostId == null) {
532             return null;
533         }
534         Optional<Hostconfig> hostConfig;
535         try {
536             hostConfig = this.hostConfigCache.get(hostId);
537         } catch (ReadFailedException e) {
538             LOG.error("failed to read host config from host {}", hostId, e);
539             return null;
540         }
541         return hostConfig.isPresent() ? hostConfig.get() : null;
542     }
543
544     private boolean isPortBound(final Port port) {
545         String hostId = getPortHostId(port);
546         return hostId != null && !hostId.isEmpty();
547     }
548
549     private boolean isPortVnicTypeDirect(Port port) {
550         PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
551         if (portBinding == null || portBinding.getVnicType() == null) {
552             // By default, VNIC_TYPE is NORMAL
553             return false;
554         }
555         String vnicType = portBinding.getVnicType().trim().toLowerCase(Locale.getDefault());
556         return vnicType.equals(NeutronConstants.VNIC_TYPE_DIRECT);
557     }
558
559     private boolean isSupportedVnicTypeByHost(final Port port, final String vnicType) {
560         Hostconfig hostConfig = getHostConfig(port);
561         String supportStr = String.format("\"vnic_type\": \"%s\"", vnicType);
562         if (hostConfig != null && hostConfig.getConfig().contains(supportStr)) {
563             return true;
564         }
565         return false;
566     }
567
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 = port.getFixedIps();
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 = port.getFixedIps();
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     private InterfaceAclBuilder handlePortSecurityUpdated(Port portOriginal,
816             Port portUpdated, boolean origSecurityEnabled, boolean updatedSecurityEnabled,
817             InterfaceBuilder interfaceBuilder) {
818         InterfaceAclBuilder interfaceAclBuilder = null;
819         if (origSecurityEnabled != updatedSecurityEnabled) {
820             interfaceAclBuilder = new InterfaceAclBuilder();
821             interfaceAclBuilder.setPortSecurityEnabled(updatedSecurityEnabled);
822             if (updatedSecurityEnabled) {
823                 // Handle security group enabled
824                 NeutronvpnUtils.populateInterfaceAclBuilder(interfaceAclBuilder, portUpdated);
825                 neutronvpnUtils.populateSubnetInfo(portUpdated);
826             } else {
827                 // Handle security group disabled
828                 interfaceAclBuilder.setSecurityGroups(new ArrayList<>());
829                 interfaceAclBuilder.setAllowedAddressPairs(new ArrayList<>());
830             }
831         } else {
832             if (updatedSecurityEnabled) {
833                 // handle SG add/delete delta
834                 InterfaceAcl interfaceAcl = interfaceBuilder.augmentation(InterfaceAcl.class);
835                 interfaceAclBuilder = new InterfaceAclBuilder(interfaceAcl);
836                 interfaceAclBuilder.setSecurityGroups(
837                         NeutronvpnUtils.getUpdatedSecurityGroups(interfaceAcl.getSecurityGroups(),
838                                 portOriginal.getSecurityGroups(), portUpdated.getSecurityGroups()));
839                 List<AllowedAddressPairs> updatedAddressPairs = NeutronvpnUtils.getUpdatedAllowedAddressPairs(
840                         interfaceAcl.getAllowedAddressPairs(), portOriginal.getAllowedAddressPairs(),
841                         portUpdated.getAllowedAddressPairs());
842                 interfaceAclBuilder.setAllowedAddressPairs(NeutronvpnUtils.getAllowedAddressPairsForFixedIps(
843                         updatedAddressPairs, portOriginal.getMacAddress(), portOriginal.getFixedIps(),
844                         portUpdated.getFixedIps()));
845
846                 if (portOriginal.getFixedIps() != null
847                         && !portOriginal.getFixedIps().equals(portUpdated.getFixedIps())) {
848                     neutronvpnUtils.populateSubnetInfo(portUpdated);
849                 }
850             }
851         }
852         return interfaceAclBuilder;
853     }
854
855     private String createOfPortInterface(Port port, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
856         Interface inf = createInterface(port);
857         String infName = inf.getName();
858
859         InstanceIdentifier<Interface> interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(infName);
860         try {
861             Optional<Interface> optionalInf =
862                     SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
863                             interfaceIdentifier);
864             if (!optionalInf.isPresent()) {
865                 wrtConfigTxn.put(interfaceIdentifier, inf);
866             } else {
867                 LOG.warn("Interface {} is already present", infName);
868             }
869         } catch (ReadFailedException e) {
870             LOG.error("failed to create interface {}", infName, e);
871         }
872         return infName;
873     }
874
875     private Interface createInterface(Port port) {
876         String interfaceName = port.getUuid().getValue();
877         IfL2vlan.L2vlanMode l2VlanMode = IfL2vlan.L2vlanMode.Trunk;
878         InterfaceBuilder interfaceBuilder = new InterfaceBuilder();
879         IfL2vlanBuilder ifL2vlanBuilder = new IfL2vlanBuilder();
880
881         Network network = neutronvpnUtils.getNeutronNetwork(port.getNetworkId());
882         Boolean isVlanTransparent = network.isVlanTransparent();
883         if (isVlanTransparent != null && isVlanTransparent) {
884             l2VlanMode = IfL2vlan.L2vlanMode.Transparent;
885         }
886
887         ifL2vlanBuilder.setL2vlanMode(l2VlanMode);
888
889         interfaceBuilder.setEnabled(true).setName(interfaceName).setType(L2vlan.class)
890                 .addAugmentation(IfL2vlan.class, ifL2vlanBuilder.build());
891
892         if (NeutronvpnUtils.getPortSecurityEnabled(port)) {
893             InterfaceAclBuilder interfaceAclBuilder = new InterfaceAclBuilder();
894             interfaceAclBuilder.setPortSecurityEnabled(true);
895             NeutronvpnUtils.populateInterfaceAclBuilder(interfaceAclBuilder, port);
896             interfaceBuilder.addAugmentation(InterfaceAcl.class, interfaceAclBuilder.build());
897             neutronvpnUtils.populateSubnetInfo(port);
898         }
899         return interfaceBuilder.build();
900     }
901
902     private void deleteOfPortInterface(Port port, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
903         String name = port.getUuid().getValue();
904         LOG.debug("Removing OFPort Interface {}", name);
905         InstanceIdentifier<Interface>  interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(name);
906         try {
907             Optional<Interface> optionalInf =
908                     SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
909                             interfaceIdentifier);
910             if (optionalInf.isPresent()) {
911                 wrtConfigTxn.delete(interfaceIdentifier);
912             } else {
913                 LOG.warn("deleteOfPortInterface: Interface {} is not present", name);
914             }
915         } catch (ReadFailedException e) {
916             LOG.error("deleteOfPortInterface: Failed to delete interface {}", name, e);
917         }
918     }
919
920     private void createElanInterface(Port port, String name,
921                                      TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
922         String elanInstanceName = port.getNetworkId().getValue();
923         List<StaticMacEntries> staticMacEntries = NeutronvpnUtils.buildStaticMacEntry(port);
924
925         InstanceIdentifier<ElanInterface> id = InstanceIdentifier.builder(ElanInterfaces.class).child(ElanInterface
926                 .class, new ElanInterfaceKey(name)).build();
927         ElanInterface elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName)
928                 .setName(name).setStaticMacEntries(staticMacEntries).withKey(new ElanInterfaceKey(name)).build();
929         wrtConfigTxn.put(id, elanInterface);
930         LOG.debug("Creating new ELan Interface {}", elanInterface);
931     }
932
933     private void deleteElanInterface(String name, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
934         InstanceIdentifier<ElanInterface> id = InstanceIdentifier.builder(ElanInterfaces.class).child(ElanInterface
935                 .class, new ElanInterfaceKey(name)).build();
936         wrtConfigTxn.delete(id);
937     }
938
939     // TODO Clean up the exception handling
940     @SuppressWarnings("checkstyle:IllegalCatch")
941     private void addToFloatingIpPortInfo(Uuid floatingIpId, Uuid floatingIpPortId, Uuid floatingIpPortSubnetId, String
942                                          floatingIpPortMacAddress) {
943         InstanceIdentifier id = NeutronvpnUtils.buildfloatingIpIdToPortMappingIdentifier(floatingIpId);
944         try {
945             FloatingIpIdToPortMappingBuilder floatingipIdToPortMacMappingBuilder = new
946                 FloatingIpIdToPortMappingBuilder().withKey(new FloatingIpIdToPortMappingKey(floatingIpId))
947                 .setFloatingIpId(floatingIpId).setFloatingIpPortId(floatingIpPortId)
948                 .setFloatingIpPortSubnetId(floatingIpPortSubnetId)
949                 .setFloatingIpPortMacAddress(floatingIpPortMacAddress);
950             LOG.debug("Creating floating IP UUID {} to Floating IP neutron port {} mapping in Floating IP"
951                 + " Port Info Config DS", floatingIpId.getValue(), floatingIpPortId.getValue());
952             MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id,
953                 floatingipIdToPortMacMappingBuilder.build());
954         } catch (Exception e) {
955             LOG.error("Creating floating IP UUID {} to Floating IP neutron port {} mapping in Floating IP"
956                 + " Port Info Config DS failed", floatingIpId.getValue(), floatingIpPortId.getValue(), e);
957         }
958     }
959
960     private Set<FixedIps> getFixedIpSet(List<FixedIps> fixedIps) {
961         return fixedIps != null ? new HashSet<>(fixedIps) : Collections.emptySet();
962     }
963 }