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