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