2 * Copyright © 2015, 2018 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.netvirt.neutronvpn;
10 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
12 import com.google.common.base.Strings;
13 import com.google.common.util.concurrent.ListenableFuture;
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;
26 import java.util.Optional;
28 import java.util.concurrent.ExecutionException;
29 import java.util.stream.Collectors;
30 import javax.annotation.PreDestroy;
31 import javax.inject.Inject;
32 import javax.inject.Singleton;
33 import org.apache.commons.lang3.ObjectUtils;
34 import org.eclipse.jdt.annotation.Nullable;
35 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
36 import org.opendaylight.genius.datastoreutils.listeners.DataTreeEventCallbackRegistrar;
37 import org.opendaylight.genius.infra.Datastore;
38 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
39 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
40 import org.opendaylight.genius.infra.TypedWriteTransaction;
41 import org.opendaylight.genius.mdsalutil.MDSALUtil;
42 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
43 import org.opendaylight.infrautils.utils.concurrent.Executors;
44 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
45 import org.opendaylight.mdsal.binding.api.DataBroker;
46 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
47 import org.opendaylight.mdsal.common.api.ReadFailedException;
48 import org.opendaylight.netvirt.elanmanager.api.IElanService;
49 import org.opendaylight.netvirt.neutronvpn.api.enums.IpVersionChoice;
50 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronConstants;
51 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
52 import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev170119.L2vlan;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlan;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlanBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefsBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.SplitHorizon;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.SplitHorizonBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.InterfaceAcl;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.InterfaceAclBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.AllowedAddressPairs;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceKey;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntries;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.RoutersBuilder;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.port.info.FloatingIpIdToPortMappingBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.port.info.FloatingIpIdToPortMappingKey;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.config.rev160806.NeutronvpnConfig;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.port.id.subport.data.PortIdToSubport;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.PortBindingExtension;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.hostconfig.rev150712.hostconfig.attributes.hostconfigs.Hostconfig;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
87 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
88 import org.slf4j.Logger;
89 import org.slf4j.LoggerFactory;
92 public class NeutronPortChangeListener extends AbstractAsyncDataTreeChangeListener<Port> {
93 private static final Logger LOG = LoggerFactory.getLogger(NeutronPortChangeListener.class);
94 private final DataBroker dataBroker;
95 private final ManagedNewTransactionRunner txRunner;
96 private final NeutronvpnManager nvpnManager;
97 private final NeutronvpnNatManager nvpnNatManager;
98 private final NeutronSubnetGwMacResolver gwMacResolver;
99 private final IElanService elanService;
100 private final JobCoordinator jobCoordinator;
101 private final NeutronvpnUtils neutronvpnUtils;
102 private final HostConfigCache hostConfigCache;
103 private final DataTreeEventCallbackRegistrar eventCallbacks;
104 private final NeutronvpnConfig neutronvpnConfig;
107 public NeutronPortChangeListener(final DataBroker dataBroker,
108 final NeutronvpnManager neutronvpnManager,
109 final NeutronvpnNatManager neutronvpnNatManager,
110 final NeutronSubnetGwMacResolver gwMacResolver,
111 final IElanService elanService,
112 final JobCoordinator jobCoordinator,
113 final NeutronvpnUtils neutronvpnUtils,
114 final HostConfigCache hostConfigCache,
115 final DataTreeEventCallbackRegistrar dataTreeEventCallbackRegistrar,
116 final NeutronvpnConfig neutronvpnConfig) {
117 super(dataBroker, LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(Neutron.class)
118 .child(Ports.class).child(Port.class),
119 Executors.newSingleThreadExecutor("NeutronPortChangeListener", LOG));
120 this.dataBroker = dataBroker;
121 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
122 nvpnManager = neutronvpnManager;
123 nvpnNatManager = neutronvpnNatManager;
124 this.gwMacResolver = gwMacResolver;
125 this.elanService = elanService;
126 this.jobCoordinator = jobCoordinator;
127 this.neutronvpnUtils = neutronvpnUtils;
128 this.hostConfigCache = hostConfigCache;
129 this.eventCallbacks = dataTreeEventCallbackRegistrar;
130 this.neutronvpnConfig = neutronvpnConfig;
135 LOG.info("{} init", getClass().getSimpleName());
140 public void close() {
142 Executors.shutdownAndAwaitTermination(getExecutorService());
146 public 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 {}",
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);
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;
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);
181 NeutronUtils.createPortStatus(input.getUuid().getValue(), portStatus, dataBroker);
185 public 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 {}",
197 neutronvpnUtils.removeFromPortCache(input);
198 NeutronUtils.deletePortStatus(input.getUuid().getValue(), dataBroker);
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 */
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());
211 if (input.getFixedIps() != null) {
212 handleNeutronPortDeleted(input);
217 public 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);
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 {}",
234 neutronvpnUtils.addToPortCache(update);
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);
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);
249 Set<FixedIps> oldIPs = getFixedIpSet(original.getFixedIps());
250 Set<FixedIps> newIPs = getFixedIpSet(update.getFixedIps());
251 if (!oldIPs.equals(newIPs)) {
252 handleNeutronPortUpdated(original, update);
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 ListenableFuture<Void> future = txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
266 Optional<Interface> optionalInf = confTx.read(interfaceIdentifier).get();
267 if (optionalInf.isPresent()) {
268 InterfaceBuilder interfaceBuilder = new InterfaceBuilder(optionalInf.get());
269 if (origSecurityEnabled || updatedSecurityEnabled) {
270 InterfaceAcl infAcl = handlePortSecurityUpdated(original, update, origSecurityEnabled,
271 updatedSecurityEnabled, interfaceBuilder).build();
272 interfaceBuilder.addAugmentation(InterfaceAcl.class, infAcl);
273 } else if (isDhcpServerPort) {
274 Set<FixedIps> oldIPs = getFixedIpSet(original.getFixedIps());
275 Set<FixedIps> newIPs = getFixedIpSet(update.getFixedIps());
276 if (!oldIPs.equals(newIPs)) {
277 InterfaceAcl infAcl = neutronvpnUtils.getDhcpInterfaceAcl(update);
278 interfaceBuilder.addAugmentation(InterfaceAcl.class, infAcl);
281 LOG.info("update: Of-port-interface updation for port {}", portName);
282 // Update OFPort interface for this neutron port
283 confTx.put(interfaceIdentifier, interfaceBuilder.build());
285 LOG.warn("update: Interface {} is not present", portName);
288 ListenableFutures.addErrorLogging(future, LOG,
289 "update: Failed to update interface {} with networkId {}", portName, network);
290 return Collections.singletonList(future);
295 private void handleFloatingIpPortUpdated(@Nullable Port original, Port update) {
296 if ((original == null || NeutronConstants.FLOATING_IP_DEVICE_ID_PENDING.equals(original.getDeviceId()))
297 && !NeutronConstants.FLOATING_IP_DEVICE_ID_PENDING.equals(update.getDeviceId())) {
298 // populate floating-ip uuid and floating-ip port attributes (uuid, mac and subnet id for the ONLY
299 // fixed IP) to be used by NAT, depopulated in NATService once mac is retrieved in the removal path
300 addToFloatingIpPortInfo(new Uuid(update.getDeviceId()), update.getUuid(), update.getFixedIps().get(0)
301 .getSubnetId(), update.getMacAddress().getValue());
302 elanService.addKnownL3DmacAddress(update.getMacAddress().getValue(), update.getNetworkId().getValue());
306 private void handleRouterInterfaceAdded(Port routerPort) {
307 if (routerPort.getDeviceId() != null) {
308 Uuid routerId = new Uuid(routerPort.getDeviceId());
309 Uuid infNetworkId = routerPort.getNetworkId();
310 Uuid existingVpnId = neutronvpnUtils.getVpnForNetwork(infNetworkId);
312 elanService.addKnownL3DmacAddress(routerPort.getMacAddress().getValue(), infNetworkId.getValue());
313 if (existingVpnId == null) {
314 Set<Uuid> listVpnIds = new HashSet<>();
315 Uuid vpnId = neutronvpnUtils.getVpnForRouter(routerId, true);
319 listVpnIds.add(vpnId);
320 Uuid internetVpnId = neutronvpnUtils.getInternetvpnUuidBoundToRouterId(routerId);
321 List<Subnetmap> subnetMapList = new ArrayList<>();
322 boolean portIsIpv6 = false;
323 for (FixedIps portIP : routerPort.nonnullFixedIps()) {
324 // NOTE: Please donot change the order of calls to updateSubnetNodeWithFixedIP
325 // and addSubnetToVpn here
326 if (internetVpnId != null
327 && portIP.getIpAddress().getIpv6Address() != null) {
330 String ipValue = portIP.getIpAddress().stringValue();
331 Uuid subnetId = portIP.getSubnetId();
332 nvpnManager.updateSubnetNodeWithFixedIp(subnetId, routerId,
333 routerPort.getUuid(), ipValue, routerPort.getMacAddress().getValue(), vpnId);
334 Subnetmap sn = neutronvpnUtils.getSubnetmap(subnetId);
335 subnetMapList.add(sn);
338 listVpnIds.add(internetVpnId);
339 if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(
340 IpVersionChoice.IPV6, routerId, true)) {
341 neutronvpnUtils.updateVpnInstanceWithIpFamily(internetVpnId.getValue(), IpVersionChoice.IPV6,
343 neutronvpnUtils.updateVpnInstanceWithFallback(routerId, internetVpnId, true);
346 if (! subnetMapList.isEmpty()) {
347 nvpnManager.createVpnInterface(listVpnIds, routerPort, null);
349 IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
350 for (FixedIps portIP : routerPort.nonnullFixedIps()) {
351 String ipValue = portIP.getIpAddress().stringValue();
352 ipVersion = NeutronvpnUtils.getIpVersionFromString(ipValue);
353 if (ipVersion.isIpVersionChosen(IpVersionChoice.IPV4)) {
354 nvpnManager.addSubnetToVpn(vpnId, portIP.getSubnetId(),
355 null /* internet-vpn-id */);
357 nvpnManager.addSubnetToVpn(vpnId, portIP.getSubnetId(), internetVpnId);
359 LOG.trace("NeutronPortChangeListener Add Subnet Gateway IP {} MAC {} Interface {} VPN {}",
360 ipValue, routerPort.getMacAddress(),
361 routerPort.getUuid().getValue(), vpnId.getValue());
363 if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(ipVersion, routerId, true)) {
364 LOG.debug("vpnInstanceOpDataEntry is getting update with ip address family {} for VPN {}",
365 ipVersion, vpnId.getValue());
366 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, true);
368 nvpnManager.addToNeutronRouterInterfacesMap(routerId, routerPort.getUuid().getValue());
369 jobCoordinator.enqueueJob(routerId.toString(), () -> {
370 nvpnNatManager.handleSubnetsForExternalRouter(routerId);
371 return Collections.emptyList();
373 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
375 String portInterfaceName = createOfPortInterface(routerPort, confTx);
376 createElanInterface(routerPort, portInterfaceName, confTx);
377 }), LOG, "Error creating ELAN interface for {}", routerPort);
379 LOG.error("Neutron network {} corresponding to router interface port {} for neutron router {}"
380 + " already associated to VPN {}", infNetworkId.getValue(), routerPort.getUuid().getValue(),
381 routerId.getValue(), existingVpnId.getValue());
386 private void handleRouterInterfaceRemoved(Port routerPort) {
387 if (routerPort.getDeviceId() != null) {
388 Uuid routerId = new Uuid(routerPort.getDeviceId());
389 Uuid infNetworkId = routerPort.getNetworkId();
390 elanService.removeKnownL3DmacAddress(routerPort.getMacAddress().getValue(), infNetworkId.getValue());
391 Uuid vpnId = ObjectUtils.defaultIfNull(neutronvpnUtils.getVpnForRouter(routerId, true),
393 List<FixedIps> portIps = routerPort.nonnullFixedIps();
394 boolean vpnInstanceInternetIpVersionRemoved = false;
395 Uuid vpnInstanceInternetUuid = null;
396 for (FixedIps portIP : portIps) {
397 // Internet VPN : flush InternetVPN first
398 Uuid subnetId = portIP.getSubnetId();
399 Subnetmap sn = neutronvpnUtils.getSubnetmap(subnetId);
400 if (sn != null && sn.getInternetVpnId() != null) {
401 if (neutronvpnUtils.shouldVpnHandleIpVersionChangeToRemove(sn, sn.getInternetVpnId())) {
402 vpnInstanceInternetIpVersionRemoved = true;
403 vpnInstanceInternetUuid = sn.getInternetVpnId();
405 nvpnManager.updateVpnInternetForSubnet(sn, sn.getInternetVpnId(), false);
408 /* Remove ping responder for router interfaces
409 * A router interface reference in a VPN will have to be removed before the host interface references
410 * for that subnet in the VPN are removed. This is to ensure that the FIB Entry of the router interface
411 * is not the last entry to be removed for that subnet in the VPN.
412 * If router interface FIB entry is the last to be removed for a subnet in a VPN , then all the host
413 * interface references in the vpn will already have been cleared, which will cause failures in
414 * cleanup of router interface flows*/
415 nvpnManager.deleteVpnInterface(routerPort.getUuid().getValue(),
416 null /* vpn-id */, null /* wrtConfigTxn*/);
417 // update RouterInterfaces map
418 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
420 IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
421 for (FixedIps portIP : portIps) {
422 Subnetmap sn = neutronvpnUtils.getSubnetmap(portIP.getSubnetId());
424 LOG.error("Subnetmap for subnet {} not found", portIP.getSubnetId().getValue());
427 // router Port have either IPv4 or IPv6, never both
428 ipVersion = neutronvpnUtils.getIpVersionFromString(sn.getSubnetIp());
429 String ipValue = portIP.getIpAddress().stringValue();
430 neutronvpnUtils.removeVpnPortFixedIpToPort(vpnId.getValue(), ipValue, confTx);
431 // NOTE: Please donot change the order of calls to removeSubnetFromVpn and
432 // and updateSubnetNodeWithFixedIP
433 nvpnManager.removeSubnetFromVpn(vpnId, sn, sn.getInternetVpnId());
434 nvpnManager.updateSubnetNodeWithFixedIp(portIP.getSubnetId(), null, null,
437 nvpnManager.removeFromNeutronRouterInterfacesMap(routerId, routerPort.getUuid().getValue());
438 deleteElanInterface(routerPort.getUuid().getValue(), confTx);
439 deleteOfPortInterface(routerPort, confTx);
440 jobCoordinator.enqueueJob(routerId.toString(), () -> {
441 nvpnNatManager.handleSubnetsForExternalRouter(routerId);
442 return Collections.emptyList();
444 if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(ipVersion, routerId, false)) {
445 LOG.debug("vpnInstanceOpDataEntry is getting update with ip address family {} for VPN {}",
446 ipVersion, vpnId.getValue());
447 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, false);
449 }), LOG, "Error handling interface removal");
450 if (vpnInstanceInternetIpVersionRemoved) {
451 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnInstanceInternetUuid.getValue(),
452 IpVersionChoice.IPV6, false);
453 neutronvpnUtils.updateVpnInstanceWithFallback(routerId, vpnInstanceInternetUuid, false);
458 private void handleRouterGatewayUpdated(Port routerGwPort, boolean isRtrGwRemoved) {
459 Uuid routerId = new Uuid(routerGwPort.getDeviceId());
460 Uuid networkId = routerGwPort.getNetworkId();
461 Network network = neutronvpnUtils.getNeutronNetwork(networkId);
462 if (network == null) {
465 boolean isExternal = NeutronvpnUtils.getIsExternal(network);
467 Uuid vpnInternetId = neutronvpnUtils.getVpnForNetwork(networkId);
468 if (vpnInternetId != null) {
469 if (!isRtrGwRemoved) {
470 nvpnManager.updateVpnMaps(vpnInternetId, null, routerId, null, null);
472 List<Subnetmap> snList = neutronvpnUtils.getNeutronRouterSubnetMaps(routerId);
473 for (Subnetmap sn : snList) {
474 if (sn.getNetworkId() == networkId) {
477 if (NeutronvpnUtils.getIpVersionFromString(sn.getSubnetIp()) != IpVersionChoice.IPV6) {
480 if (isRtrGwRemoved) {
481 nvpnManager.removeV6PrivateSubnetToExtNetwork(routerId, vpnInternetId, sn);
483 nvpnManager.addV6PrivateSubnetToExtNetwork(routerId, vpnInternetId, sn);
486 //Update Internet BGP-VPN
487 if (isRtrGwRemoved) {
488 nvpnManager.updateVpnMaps(vpnInternetId, null, null, null, null);
492 elanService.addKnownL3DmacAddress(routerGwPort.getMacAddress().getValue(), networkId.getValue());
494 Router router = neutronvpnUtils.getNeutronRouter(routerId);
495 if (router == null) {
496 LOG.warn("No router found for router GW port {} for router {}", routerGwPort.getUuid().getValue(),
497 routerId.getValue());
499 eventCallbacks.onAddOrUpdate(LogicalDatastoreType.CONFIGURATION,
500 neutronvpnUtils.getNeutronRouterIid(routerId), (unused, newRouter) -> {
501 setupGwMac(newRouter, routerGwPort, routerId);
502 return DataTreeEventCallbackRegistrar.NextAction.UNREGISTER;
503 }, Duration.ofSeconds(3), iid -> {
504 LOG.error("GwPort {} added without Router", routerGwPort.getUuid().getValue());
508 setupGwMac(router, routerGwPort, routerId);
511 private void setupGwMac(Router router, Port routerGwPort, Uuid routerId) {
512 gwMacResolver.sendArpRequestsToExtGateways(router);
513 jobCoordinator.enqueueJob(routerId.toString(), () -> {
514 setExternalGwMac(routerGwPort, routerId);
515 return Collections.emptyList();
519 private void setExternalGwMac(Port routerGwPort, Uuid routerId) {
520 // During full-sync networking-odl syncs routers before ports. As such,
521 // the MAC of the router's gw port is not available to be set when the
522 // router is written. We catch that here.
523 InstanceIdentifier<Routers> routersId = NeutronvpnUtils.buildExtRoutersIdentifier(routerId);
524 Optional<Routers> optionalRouter = null;
526 optionalRouter = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routersId);
527 if (!optionalRouter.isPresent()) {
530 Routers extRouters = optionalRouter.get();
531 if (extRouters.getExtGwMacAddress() != null) {
535 RoutersBuilder builder = new RoutersBuilder(extRouters);
536 builder.setExtGwMacAddress(routerGwPort.getMacAddress().getValue());
537 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, routersId, builder.build());
538 } catch (ExecutionException | InterruptedException e) {
539 LOG.error("setExternalGwMac: failed to read EXT-Routers for router Id {} rout-Gw port {} due to exception",
540 routerId, routerGwPort, e);
546 private String getPortHostId(final Port port) {
548 PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
549 if (portBinding != null) {
550 return portBinding.getHostId();
557 private Hostconfig getHostConfig(final Port port) {
558 String hostId = getPortHostId(port);
559 if (hostId == null) {
562 Optional<Hostconfig> hostConfig;
564 hostConfig = this.hostConfigCache.get(hostId);
565 } catch (ReadFailedException e) {
566 LOG.error("failed to read host config from host {}", hostId, e);
569 return hostConfig.orElse(null);
572 private boolean isPortBound(final Port port) {
573 String hostId = getPortHostId(port);
574 return hostId != null && !hostId.isEmpty();
577 private boolean isPortVnicTypeDirect(Port port) {
578 PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
579 if (portBinding == null || portBinding.getVnicType() == null) {
580 // By default, VNIC_TYPE is NORMAL
583 String vnicType = portBinding.getVnicType().trim().toLowerCase(Locale.getDefault());
584 return NeutronConstants.VNIC_TYPE_DIRECT.equals(vnicType);
587 private boolean isSupportedVnicTypeByHost(final Port port, final String vnicType) {
588 Hostconfig hostConfig = getHostConfig(port);
589 String supportStr = String.format("\"vnic_type\": \"%s\"", vnicType);
590 if (hostConfig != null && hostConfig.getConfig().contains(supportStr)) {
597 private Map<String, JsonElement> unmarshal(final String profile) {
598 if (null == profile) {
601 Gson gson = new Gson();
602 JsonObject jsonObject = gson.fromJson(profile, JsonObject.class);
603 Map<String, JsonElement> map = new HashMap<>();
604 for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
605 map.put(entry.getKey(), entry.getValue());
610 private boolean isPortTypeSwitchdev(final Port port) {
611 if (!isPortVnicTypeDirect(port)) {
615 PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
616 String profile = portBinding.getProfile();
617 if (profile == null || profile.isEmpty()) {
618 LOG.debug("Port {} has no binding:profile values", port.getUuid());
622 Map<String, JsonElement> mapProfile = unmarshal(profile);
623 JsonElement capabilities = mapProfile.get(NeutronConstants.BINDING_PROFILE_CAPABILITIES);
624 LOG.debug("Port {} capabilities: {}", port.getUuid(), capabilities);
625 if (capabilities == null || !capabilities.isJsonArray()) {
626 LOG.debug("binding profile capabilities not in array format: {}", capabilities);
630 JsonArray capabilitiesArray = capabilities.getAsJsonArray();
631 Gson gson = new Gson();
632 JsonElement switchdevElement = gson.fromJson(NeutronConstants.SWITCHDEV, JsonElement.class);
633 return capabilitiesArray.contains(switchdevElement);
637 private void handleNeutronPortCreated(final Port port) {
638 final String portName = port.getUuid().getValue();
639 final Uuid portId = port.getUuid();
640 final String networkId = port.getNetworkId().getValue();
641 final List<FixedIps> portIpAddrsList = port.nonnullFixedIps();
642 if (NeutronConstants.IS_ODL_DHCP_PORT.test(port)) {
645 if (!(NeutronUtils.isPortVnicTypeNormal(port)
646 || isPortTypeSwitchdev(port)
647 && isSupportedVnicTypeByHost(port, NeutronConstants.VNIC_TYPE_DIRECT))) {
648 for (FixedIps ip: portIpAddrsList) {
649 nvpnManager.updateSubnetmapNodeWithPorts(ip.getSubnetId(), null, portId);
651 LOG.info("Port {} is not a normal and not a direct with switchdev VNIC type ;"
652 + "OF Port interfaces are not created", portName);
655 jobCoordinator.enqueueJob("PORT- " + portName, () -> {
656 // add direct port to subnetMaps config DS
657 // TODO: for direct port as well, operations should be carried out per subnet based on port IP
659 ListenableFuture<Void> future = txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
660 LOG.info("Of-port-interface creation for port {}", portName);
661 // Create of-port interface for this neutron port
662 String portInterfaceName = createOfPortInterface(port, tx);
663 LOG.debug("Creating ELAN Interface for port {}", portName);
664 createElanInterface(port, portInterfaceName, tx);
665 Set<Uuid> vpnIdList = new HashSet<>();
666 Set<Uuid> routerIds = new HashSet<>();
667 for (FixedIps ip: portIpAddrsList) {
668 Subnetmap subnetMap = nvpnManager.updateSubnetmapNodeWithPorts(ip.getSubnetId(), portId, null);
669 if (subnetMap != null && subnetMap.getInternetVpnId() != null) {
670 if (!vpnIdList.contains(subnetMap.getInternetVpnId())) {
671 vpnIdList.add(subnetMap.getInternetVpnId());
674 if (subnetMap != null && subnetMap.getVpnId() != null) {
675 // can't use NeutronvpnUtils.getVpnForNetwork to optimise here, because it gives BGPVPN id
676 // obtained subnetMaps belongs to one network => vpnId must be the same for each port Ip
677 Uuid vpnId = subnetMap.getVpnId();
679 vpnIdList.add(vpnId);
682 if (subnetMap != null && subnetMap.getRouterId() != null) {
683 routerIds.add(subnetMap.getRouterId());
686 if (!vpnIdList.isEmpty()) {
687 // create new vpn-interface for neutron port
688 LOG.debug("handleNeutronPortCreated: Adding VPN Interface for port {} from network {}", portName,
690 nvpnManager.createVpnInterface(vpnIdList, port, tx);
691 for (Uuid routerId : routerIds) {
692 nvpnManager.addToNeutronRouterInterfacesMap(routerId,port.getUuid().getValue());
696 ListenableFutures.addErrorLogging(future, LOG,
697 "handleNeutronPortCreated: Failed for port {} with networkId {}", portName, networkId);
698 return Collections.singletonList(future);
702 private void handleNeutronPortDeleted(final Port port) {
703 final String portName = port.getUuid().getValue();
704 final Uuid portId = port.getUuid();
705 final List<FixedIps> portIpsList = port.nonnullFixedIps();
706 if (!(NeutronUtils.isPortVnicTypeNormal(port) || isPortTypeSwitchdev(port))) {
707 for (FixedIps ip : portIpsList) {
708 // remove direct port from subnetMaps config DS
709 // TODO: for direct port as well, operations should be carried out per subnet based on port IP
710 nvpnManager.removePortsFromSubnetmapNode(ip.getSubnetId(), null, portId);
712 LOG.info("Port {} is not a normal and not a direct with switchdev VNIC type ;"
713 + "Skipping OF Port interfaces removal", portName);
716 jobCoordinator.enqueueJob("PORT- " + portName, () -> {
717 ListenableFuture<Void> future = txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
720 Set<Uuid> routerIds = new HashSet<>();
721 Uuid internetVpnId = null;
722 for (FixedIps ip : portIpsList) {
723 Subnetmap subnetMap = nvpnManager.removePortsFromSubnetmapNode(ip.getSubnetId(), portId, null);
724 if (subnetMap == null) {
727 if (subnetMap.getVpnId() != null) {
728 // can't use NeutronvpnUtils.getVpnForNetwork to optimise here, because it gives BGPVPN id
729 // obtained subnetMaps belongs to one network => vpnId must be the same for each port Ip
730 vpnId = subnetMap.getVpnId();
732 if (subnetMap.getRouterId() != null) {
733 routerIds.add(subnetMap.getRouterId());
735 internetVpnId = subnetMap.getInternetVpnId();
737 if (NeutronConstants.DEVICE_OWNER_GATEWAY_INF.equals(port.getDeviceOwner())
738 || NeutronConstants.DEVICE_OWNER_FLOATING_IP.equals(port.getDeviceOwner())) {
739 String ipAddress = ip.getIpAddress().stringValue();
741 neutronvpnUtils.removeVpnPortFixedIpToPort(vpnId.getValue(), ipAddress, confTx);
743 if (internetVpnId != null) {
744 neutronvpnUtils.removeVpnPortFixedIpToPort(internetVpnId.getValue(),
749 if (vpnId != null || internetVpnId != null) {
750 // remove vpn-interface for this neutron port
751 LOG.debug("removing VPN Interface for port {}", portName);
752 if (!routerIds.isEmpty()) {
753 for (Uuid routerId : routerIds) {
754 nvpnManager.removeFromNeutronRouterInterfacesMap(routerId, portName);
757 nvpnManager.deleteVpnInterface(portName, null /* vpn-id */, confTx);
759 // Remove of-port interface for this neutron port
760 // ELAN interface is also implicitly deleted as part of this operation
761 LOG.debug("Of-port-interface removal for port {}", portName);
762 deleteOfPortInterface(port, confTx);
763 //dissociate fixedIP from floatingIP if associated
764 nvpnManager.dissociatefixedIPFromFloatingIP(port.getUuid().getValue());
766 ListenableFutures.addErrorLogging(future, LOG,
767 "handleNeutronPortDeleted: Failed to update interface {} with networkId", portName,
768 port.getNetworkId().getValue());
769 return Collections.singletonList(future);
774 private void handleNeutronPortUpdated(final Port portoriginal, final Port portupdate) {
775 final List<FixedIps> portoriginalIps = portoriginal.getFixedIps();
776 final List<FixedIps> portupdateIps = portupdate.getFixedIps();
777 if (portoriginalIps == null || portoriginalIps.isEmpty()) {
778 handleNeutronPortCreated(portupdate);
782 if (portupdateIps == null || portupdateIps.isEmpty()) {
783 LOG.info("Ignoring portUpdate (fixed_ip removal) for port {} as this case is handled "
784 + "during subnet deletion event.", portupdate.getUuid().getValue());
788 if (NeutronConstants.IS_ODL_DHCP_PORT.test(portupdate)) {
792 jobCoordinator.enqueueJob("PORT- " + portupdate.getUuid().getValue(),
793 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
794 final List<Uuid> originalSnMapsIds = portoriginalIps.stream().map(FixedIps::getSubnetId)
795 .collect(Collectors.toList());
796 final List<Uuid> updateSnMapsIds = portupdateIps.stream().map(FixedIps::getSubnetId)
797 .collect(Collectors.toList());
798 Set<Uuid> originalRouterIds = new HashSet<>();
799 Set<Uuid> oldVpnIds = new HashSet<>();
800 for (Uuid snId: originalSnMapsIds) {
801 if (!updateSnMapsIds.remove(snId)) {
802 // snId was present in originalSnMapsIds, but not in updateSnMapsIds
803 Subnetmap subnetMapOld = nvpnManager.removePortsFromSubnetmapNode(snId, portoriginal.getUuid(),
805 if (subnetMapOld != null && subnetMapOld.getVpnId() != null) {
806 oldVpnIds.add(subnetMapOld.getVpnId());
808 if (subnetMapOld != null && subnetMapOld.getInternetVpnId() != null) {
809 oldVpnIds.add(subnetMapOld.getInternetVpnId());
811 if (subnetMapOld != null && subnetMapOld.getRouterId() != null) {
812 originalRouterIds.add(subnetMapOld.getRouterId());
816 Set<Uuid> newVpnIds = new HashSet<>();
817 Set<Uuid> newRouterIds = new HashSet<>();
818 for (Uuid snId: updateSnMapsIds) {
819 Subnetmap subnetMapNew = nvpnManager.updateSubnetmapNodeWithPorts(snId, portupdate.getUuid(), null);
820 if (subnetMapNew != null) {
821 if (subnetMapNew.getVpnId() != null) {
822 newVpnIds.add(subnetMapNew.getVpnId());
824 if (subnetMapNew.getInternetVpnId() != null) {
825 newVpnIds.add(subnetMapNew.getInternetVpnId());
827 if (subnetMapNew.getRouterId() != null) {
828 newRouterIds.add(subnetMapNew.getRouterId());
832 if (!oldVpnIds.isEmpty()) {
833 LOG.info("removing VPN Interface for port {}", portoriginal.getUuid().getValue());
834 if (!originalRouterIds.isEmpty()) {
835 for (Uuid routerId : originalRouterIds) {
836 nvpnManager.removeFromNeutronRouterInterfacesMap(routerId,
837 portoriginal.getUuid().getValue());
840 nvpnManager.deleteVpnInterface(portoriginal.getUuid().getValue(),
841 null /* vpn-id */, confTx);
843 if (!newVpnIds.isEmpty()) {
844 LOG.info("Adding VPN Interface for port {}", portupdate.getUuid().getValue());
845 nvpnManager.createVpnInterface(newVpnIds, portupdate, confTx);
846 if (!newRouterIds.isEmpty()) {
847 for (Uuid routerId : newRouterIds) {
848 nvpnManager.addToNeutronRouterInterfacesMap(routerId,portupdate.getUuid().getValue());
856 private InterfaceAclBuilder handlePortSecurityUpdated(Port portOriginal,
857 Port portUpdated, boolean origSecurityEnabled, boolean updatedSecurityEnabled,
858 InterfaceBuilder interfaceBuilder) {
859 InterfaceAclBuilder interfaceAclBuilder = null;
860 if (origSecurityEnabled != updatedSecurityEnabled) {
861 interfaceAclBuilder = new InterfaceAclBuilder();
862 interfaceAclBuilder.setPortSecurityEnabled(updatedSecurityEnabled);
863 if (updatedSecurityEnabled) {
864 // Handle security group enabled
865 neutronvpnUtils.populateInterfaceAclBuilder(interfaceAclBuilder, portUpdated);
867 // Handle security group disabled
868 interfaceAclBuilder.setSecurityGroups(new ArrayList<>());
869 interfaceAclBuilder.setAllowedAddressPairs(new ArrayList<>());
870 interfaceAclBuilder.setSubnetInfo(new ArrayList<>());
873 if (updatedSecurityEnabled) {
874 // handle SG add/delete delta
875 InterfaceAcl interfaceAcl = interfaceBuilder.augmentation(InterfaceAcl.class);
876 interfaceAclBuilder = new InterfaceAclBuilder(interfaceAcl);
877 interfaceAclBuilder.setSecurityGroups(
878 NeutronvpnUtils.getUpdatedSecurityGroups(interfaceAcl.getSecurityGroups(),
879 portOriginal.getSecurityGroups(), portUpdated.getSecurityGroups()));
880 List<AllowedAddressPairs> updatedAddressPairs = NeutronvpnUtils.getUpdatedAllowedAddressPairs(
881 interfaceAcl.getAllowedAddressPairs(), portOriginal.getAllowedAddressPairs(),
882 portUpdated.getAllowedAddressPairs());
883 interfaceAclBuilder.setAllowedAddressPairs(NeutronvpnUtils.getAllowedAddressPairsForFixedIps(
884 updatedAddressPairs, portOriginal.getMacAddress(), portOriginal.getFixedIps(),
885 portUpdated.getFixedIps()));
887 if (portOriginal.getFixedIps() != null
888 && !portOriginal.getFixedIps().equals(portUpdated.getFixedIps())) {
889 neutronvpnUtils.populateSubnetInfo(interfaceAclBuilder, portUpdated);
893 return interfaceAclBuilder;
896 private String createOfPortInterface(Port port, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
897 Interface inf = createInterface(port);
898 String infName = inf.getName();
900 InstanceIdentifier<Interface> interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(infName);
902 Optional<Interface> optionalInf =
903 SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
904 interfaceIdentifier);
905 if (!optionalInf.isPresent()) {
906 wrtConfigTxn.put(interfaceIdentifier, inf);
907 } else if (isInterfaceUpdated(inf, optionalInf.get())) {
909 Case where an update DTCN wasn't received by this class due to node going down
910 upon cluster reboot or any other unknown reason
911 In such a case, updates contained in the missed DTCN won't be processed and have to be handled
913 Update of subports (vlanId, splithorizon tag) is handled here
914 Update of portSecurity (PortSecurityEnabled, SecurityGroups, AllowedAddressPairs) add is handled
915 Update of portSecurity update/removed is not handled
916 Update of parentrefs is not handled as parentrefs updation is handled by IFM Oxygen onwards
918 wrtConfigTxn.put(interfaceIdentifier, inf);
919 LOG.error("Interface {} is already present and is updated", infName);
921 LOG.warn("Interface {} is already present", infName);
923 } catch (ExecutionException | InterruptedException e) {
924 LOG.error("failed to create interface {}", infName, e);
929 // Not for generic use. For a special case where update DTCN isn't received
930 private static boolean isInterfaceUpdated(Interface newInterface, Interface oldInterface) {
931 if (newInterface.augmentation(SplitHorizon.class) != null) {
932 if (oldInterface.augmentation(SplitHorizon.class) == null) {
935 if (!newInterface.augmentation(SplitHorizon.class).equals(oldInterface
936 .augmentation(SplitHorizon.class))) {
940 if (!newInterface.augmentation(IfL2vlan.class).equals(oldInterface.augmentation(IfL2vlan.class))) {
943 if (newInterface.augmentation(InterfaceAcl.class) != null && oldInterface
944 .augmentation(InterfaceAcl.class) == null) {
950 private Interface createInterface(Port port) {
951 String interfaceName = port.getUuid().getValue();
952 IfL2vlan.L2vlanMode l2VlanMode = IfL2vlan.L2vlanMode.Trunk;
953 InterfaceBuilder interfaceBuilder = new InterfaceBuilder();
954 IfL2vlanBuilder ifL2vlanBuilder = new IfL2vlanBuilder();
956 Network network = neutronvpnUtils.getNeutronNetwork(port.getNetworkId());
957 Boolean isVlanTransparent = network.isVlanTransparent();
958 if (isVlanTransparent != null && isVlanTransparent) {
959 l2VlanMode = IfL2vlan.L2vlanMode.Transparent;
961 PortIdToSubport portIdToSubport = neutronvpnUtils.getPortIdToSubport(port.getUuid());
962 if (portIdToSubport != null) {
963 l2VlanMode = IfL2vlan.L2vlanMode.TrunkMember;
964 ifL2vlanBuilder.setVlanId(new VlanId(portIdToSubport.getVlanId().intValue()));
965 String parentRefName = portIdToSubport.getTrunkPortId().getValue();
966 ParentRefsBuilder parentRefsBuilder = new ParentRefsBuilder().setParentInterface(parentRefName);
967 interfaceBuilder.addAugmentation(ParentRefs.class, parentRefsBuilder.build());
968 SplitHorizon splitHorizon =
969 new SplitHorizonBuilder().setOverrideSplitHorizonProtection(true).build();
970 interfaceBuilder.addAugmentation(SplitHorizon.class, splitHorizon);
974 ifL2vlanBuilder.setL2vlanMode(l2VlanMode);
976 interfaceBuilder.setEnabled(true).setName(interfaceName).setType(L2vlan.class)
977 .addAugmentation(IfL2vlan.class, ifL2vlanBuilder.build());
979 if (NeutronvpnUtils.getPortSecurityEnabled(port)) {
980 InterfaceAclBuilder interfaceAclBuilder = new InterfaceAclBuilder();
981 interfaceAclBuilder.setPortSecurityEnabled(true);
982 neutronvpnUtils.populateInterfaceAclBuilder(interfaceAclBuilder, port);
983 interfaceBuilder.addAugmentation(InterfaceAcl.class, interfaceAclBuilder.build());
984 } else if (neutronvpnConfig.isLimitBumtrafficToDhcpserver() && NeutronvpnUtils.isDhcpServerPort(port)) {
985 interfaceBuilder.addAugmentation(InterfaceAcl.class, neutronvpnUtils.getDhcpInterfaceAcl(port));
987 return interfaceBuilder.build();
990 private void deleteOfPortInterface(Port port, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
991 String name = port.getUuid().getValue();
992 LOG.debug("Removing OFPort Interface {}", name);
993 InstanceIdentifier<Interface> interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(name);
995 Optional<Interface> optionalInf =
996 SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
997 interfaceIdentifier);
998 if (optionalInf.isPresent()) {
999 wrtConfigTxn.delete(interfaceIdentifier);
1001 LOG.warn("deleteOfPortInterface: Interface {} is not present", name);
1003 } catch (ExecutionException | InterruptedException e) {
1004 LOG.error("deleteOfPortInterface: Failed to delete interface {}", name, e);
1008 private void createElanInterface(Port port, String name,
1009 TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
1010 String elanInstanceName = port.getNetworkId().getValue();
1011 List<StaticMacEntries> staticMacEntries = NeutronvpnUtils.buildStaticMacEntry(port);
1013 InstanceIdentifier<ElanInterface> id = InstanceIdentifier.builder(ElanInterfaces.class).child(ElanInterface
1014 .class, new ElanInterfaceKey(name)).build();
1015 ElanInterface elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName)
1016 .setName(name).setStaticMacEntries(staticMacEntries).withKey(new ElanInterfaceKey(name)).build();
1017 wrtConfigTxn.put(id, elanInterface);
1018 LOG.debug("Creating new ELan Interface {}", elanInterface);
1021 private void deleteElanInterface(String name, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
1022 InstanceIdentifier<ElanInterface> id = InstanceIdentifier.builder(ElanInterfaces.class).child(ElanInterface
1023 .class, new ElanInterfaceKey(name)).build();
1024 wrtConfigTxn.delete(id);
1027 // TODO Clean up the exception handling
1028 @SuppressWarnings("checkstyle:IllegalCatch")
1029 private void addToFloatingIpPortInfo(Uuid floatingIpId, Uuid floatingIpPortId, Uuid floatingIpPortSubnetId, String
1030 floatingIpPortMacAddress) {
1031 InstanceIdentifier id = NeutronvpnUtils.buildfloatingIpIdToPortMappingIdentifier(floatingIpId);
1033 FloatingIpIdToPortMappingBuilder floatingipIdToPortMacMappingBuilder = new
1034 FloatingIpIdToPortMappingBuilder().withKey(new FloatingIpIdToPortMappingKey(floatingIpId))
1035 .setFloatingIpId(floatingIpId).setFloatingIpPortId(floatingIpPortId)
1036 .setFloatingIpPortSubnetId(floatingIpPortSubnetId)
1037 .setFloatingIpPortMacAddress(floatingIpPortMacAddress);
1038 LOG.debug("Creating floating IP UUID {} to Floating IP neutron port {} mapping in Floating IP"
1039 + " Port Info Config DS", floatingIpId.getValue(), floatingIpPortId.getValue());
1040 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id,
1041 floatingipIdToPortMacMappingBuilder.build());
1042 } catch (Exception e) {
1043 LOG.error("Creating floating IP UUID {} to Floating IP neutron port {} mapping in Floating IP"
1044 + " Port Info Config DS failed", floatingIpId.getValue(), floatingIpPortId.getValue(), e);
1048 private Set<FixedIps> getFixedIpSet(List<FixedIps> fixedIps) {
1049 return fixedIps != null ? new HashSet<>(fixedIps) : Collections.emptySet();