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