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.mdsal.binding.util.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.Objects;
27 import java.util.Optional;
29 import java.util.concurrent.ExecutionException;
30 import java.util.stream.Collectors;
31 import javax.annotation.PreDestroy;
32 import javax.inject.Inject;
33 import javax.inject.Singleton;
34 import org.apache.commons.lang3.ObjectUtils;
35 import org.eclipse.jdt.annotation.Nullable;
36 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
37 import org.opendaylight.genius.datastoreutils.listeners.DataTreeEventCallbackRegistrar;
38 import org.opendaylight.genius.mdsalutil.MDSALUtil;
39 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
40 import org.opendaylight.infrautils.utils.concurrent.Executors;
41 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
42 import org.opendaylight.mdsal.binding.api.DataBroker;
43 import org.opendaylight.mdsal.binding.util.Datastore;
44 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunner;
45 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunnerImpl;
46 import org.opendaylight.mdsal.binding.util.TypedWriteTransaction;
47 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
48 import org.opendaylight.mdsal.common.api.ReadFailedException;
49 import org.opendaylight.netvirt.elanmanager.api.IElanService;
50 import org.opendaylight.netvirt.neutronvpn.api.enums.IpVersionChoice;
51 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronConstants;
52 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
53 import org.opendaylight.serviceutils.tools.listener.AbstractAsyncDataTreeChangeListener;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev170119.L2vlan;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
57 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlan;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfL2vlanBuilder;
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.port.attributes.FixedIpsKey;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
88 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
89 import org.slf4j.Logger;
90 import org.slf4j.LoggerFactory;
93 public class NeutronPortChangeListener extends AbstractAsyncDataTreeChangeListener<Port> {
94 private static final Logger LOG = LoggerFactory.getLogger(NeutronPortChangeListener.class);
95 private final DataBroker dataBroker;
96 private final ManagedNewTransactionRunner txRunner;
97 private final NeutronvpnManager nvpnManager;
98 private final NeutronvpnNatManager nvpnNatManager;
99 private final NeutronSubnetGwMacResolver gwMacResolver;
100 private final IElanService elanService;
101 private final JobCoordinator jobCoordinator;
102 private final NeutronvpnUtils neutronvpnUtils;
103 private final HostConfigCache hostConfigCache;
104 private final DataTreeEventCallbackRegistrar eventCallbacks;
105 private final NeutronvpnConfig neutronvpnConfig;
108 public NeutronPortChangeListener(final DataBroker dataBroker,
109 final NeutronvpnManager neutronvpnManager,
110 final NeutronvpnNatManager neutronvpnNatManager,
111 final NeutronSubnetGwMacResolver gwMacResolver,
112 final IElanService elanService,
113 final JobCoordinator jobCoordinator,
114 final NeutronvpnUtils neutronvpnUtils,
115 final HostConfigCache hostConfigCache,
116 final DataTreeEventCallbackRegistrar dataTreeEventCallbackRegistrar,
117 final NeutronvpnConfig neutronvpnConfig) {
118 super(dataBroker, LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(Neutron.class)
119 .child(Ports.class).child(Port.class),
120 Executors.newSingleThreadExecutor("NeutronPortChangeListener", LOG));
121 this.dataBroker = dataBroker;
122 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
123 nvpnManager = neutronvpnManager;
124 nvpnNatManager = neutronvpnNatManager;
125 this.gwMacResolver = gwMacResolver;
126 this.elanService = elanService;
127 this.jobCoordinator = jobCoordinator;
128 this.neutronvpnUtils = neutronvpnUtils;
129 this.hostConfigCache = hostConfigCache;
130 this.eventCallbacks = dataTreeEventCallbackRegistrar;
131 this.neutronvpnConfig = neutronvpnConfig;
136 LOG.info("{} init", getClass().getSimpleName());
141 public void close() {
143 Executors.shutdownAndAwaitTermination(getExecutorService());
147 public 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 {}",
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);
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;
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);
182 NeutronUtils.createPortStatus(input.getUuid().getValue(), portStatus, dataBroker);
186 public 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 {}",
198 neutronvpnUtils.removeFromPortCache(input);
199 NeutronUtils.deletePortStatus(input.getUuid().getValue(), dataBroker);
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 */
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());
212 if (input.getFixedIps() != null) {
213 handleNeutronPortDeleted(input);
218 public void update(InstanceIdentifier<Port> identifier, Port original, Port update) {
219 LOG.trace("Received port update event: original={}, update={}", original, update);
220 if (Objects.equals(original, update)) {
223 // Switchdev ports need to be bounded to a host before creation
224 // in order to validate the supported vnic types from the hostconfig
225 if (isPortTypeSwitchdev(original)
226 && !isPortBound(original)
227 && isPortBound(update)) {
228 handleNeutronPortCreated(update);
230 final String portName = update.getUuid().getValue();
231 Network network = neutronvpnUtils.getNeutronNetwork(update.getNetworkId());
232 if (network == null || !NeutronvpnUtils.isNetworkTypeSupported(network)) {
233 LOG.warn("neutron vpn received a port update() for a network without a provider extension augmentation "
234 + "or with an unsupported network type for the port {} which is part of network {}",
238 neutronvpnUtils.addToPortCache(update);
240 if ((Strings.isNullOrEmpty(original.getDeviceOwner()) || Strings.isNullOrEmpty(original.getDeviceId())
241 || NeutronConstants.FLOATING_IP_DEVICE_ID_PENDING.equalsIgnoreCase(original.getDeviceId()))
242 && !Strings.isNullOrEmpty(update.getDeviceOwner()) && !Strings.isNullOrEmpty(update.getDeviceId())) {
243 if (NeutronConstants.DEVICE_OWNER_ROUTER_INF.equals(update.getDeviceOwner())) {
244 handleRouterInterfaceAdded(update);
247 if (NeutronConstants.DEVICE_OWNER_GATEWAY_INF.equals(update.getDeviceOwner())) {
248 handleRouterGatewayUpdated(update, false);
249 } else if (NeutronConstants.DEVICE_OWNER_FLOATING_IP.equals(update.getDeviceOwner())) {
250 handleFloatingIpPortUpdated(original, update);
253 Set<FixedIps> oldIPs = getFixedIpSet(new ArrayList<>(original.nonnullFixedIps().values()));
254 Set<FixedIps> newIPs = getFixedIpSet(new ArrayList<>(update.nonnullFixedIps().values()));
255 if (!oldIPs.equals(newIPs)) {
256 handleNeutronPortUpdated(original, update);
260 // check if port security enabled/disabled as part of port update
261 boolean origSecurityEnabled = NeutronvpnUtils.getPortSecurityEnabled(original);
262 boolean updatedSecurityEnabled = NeutronvpnUtils.getPortSecurityEnabled(update);
263 boolean isDhcpServerPort = neutronvpnConfig.isLimitBumtrafficToDhcpserver()
264 && NeutronvpnUtils.isDhcpServerPort(update);
265 if (origSecurityEnabled || updatedSecurityEnabled || isDhcpServerPort) {
266 InstanceIdentifier<Interface> interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(portName);
267 jobCoordinator.enqueueJob("PORT- " + portName, () -> {
268 ListenableFuture<?> future = txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
270 Optional<Interface> optionalInf = confTx.read(interfaceIdentifier).get();
271 if (optionalInf.isPresent()) {
272 InterfaceBuilder interfaceBuilder = new InterfaceBuilder(optionalInf.get());
273 if (origSecurityEnabled || updatedSecurityEnabled) {
274 InterfaceAcl infAcl = handlePortSecurityUpdated(original, update, origSecurityEnabled,
275 updatedSecurityEnabled, interfaceBuilder).build();
276 interfaceBuilder.addAugmentation(infAcl);
277 } else if (isDhcpServerPort) {
278 Set<FixedIps> oldIPs = getFixedIpSet(
279 new ArrayList<>(original.nonnullFixedIps().values()));
280 Set<FixedIps> newIPs = getFixedIpSet(
281 new ArrayList<>(update.nonnullFixedIps().values()));
282 if (!oldIPs.equals(newIPs)) {
283 InterfaceAcl infAcl = neutronvpnUtils.getDhcpInterfaceAcl(update);
284 interfaceBuilder.addAugmentation(infAcl);
287 LOG.info("update: Of-port-interface updation for port {}", portName);
288 // Update OFPort interface for this neutron port
289 confTx.put(interfaceIdentifier, interfaceBuilder.build());
291 LOG.warn("update: Interface {} is not present", portName);
294 LoggingFutures.addErrorLogging(future, LOG,
295 "update: Failed to update interface {} with networkId {}", portName, network);
296 return Collections.singletonList(future);
301 private void handleFloatingIpPortUpdated(@Nullable Port original, Port update) {
302 if ((original == null || NeutronConstants.FLOATING_IP_DEVICE_ID_PENDING.equals(original.getDeviceId()))
303 && !NeutronConstants.FLOATING_IP_DEVICE_ID_PENDING.equals(update.getDeviceId())) {
304 // populate floating-ip uuid and floating-ip port attributes (uuid, mac and subnet id for the ONLY
305 // fixed IP) to be used by NAT, depopulated in NATService once mac is retrieved in the removal path
306 addToFloatingIpPortInfo(new Uuid(update.getDeviceId()), update.getUuid(),
307 new ArrayList<>(update.nonnullFixedIps().values()).get(0)
308 .getSubnetId(), update.getMacAddress().getValue());
309 elanService.addKnownL3DmacAddress(update.getMacAddress().getValue(), update.getNetworkId().getValue());
313 private void handleRouterInterfaceAdded(Port routerPort) {
314 if (routerPort.getDeviceId() != null) {
315 Uuid routerId = new Uuid(routerPort.getDeviceId());
316 Uuid infNetworkId = routerPort.getNetworkId();
317 Uuid existingVpnId = neutronvpnUtils.getVpnForNetwork(infNetworkId);
319 elanService.addKnownL3DmacAddress(routerPort.getMacAddress().getValue(), infNetworkId.getValue());
320 if (existingVpnId == null) {
321 Set<Uuid> listVpnIds = new HashSet<>();
322 Uuid vpnId = neutronvpnUtils.getVpnForRouter(routerId, true);
326 listVpnIds.add(vpnId);
327 Uuid internetVpnId = neutronvpnUtils.getInternetvpnUuidBoundToRouterId(routerId);
328 List<Subnetmap> subnetMapList = new ArrayList<>();
329 boolean portIsIpv6 = false;
330 for (FixedIps portIP : routerPort.nonnullFixedIps().values()) {
331 // NOTE: Please donot change the order of calls to updateSubnetNodeWithFixedIP
332 // and addSubnetToVpn here
333 if (internetVpnId != null
334 && portIP.getIpAddress().getIpv6Address() != null) {
337 String ipValue = portIP.getIpAddress().stringValue();
338 Uuid subnetId = portIP.getSubnetId();
339 nvpnManager.updateSubnetNodeWithFixedIp(subnetId, routerId,
340 routerPort.getUuid(), ipValue, routerPort.getMacAddress().getValue(), vpnId);
341 Subnetmap sn = neutronvpnUtils.getSubnetmap(subnetId);
342 subnetMapList.add(sn);
345 listVpnIds.add(internetVpnId);
346 if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(
347 IpVersionChoice.IPV6, routerId, true)) {
348 neutronvpnUtils.updateVpnInstanceWithIpFamily(internetVpnId.getValue(), IpVersionChoice.IPV6,
350 neutronvpnUtils.updateVpnInstanceWithFallback(routerId, internetVpnId, true);
353 if (! subnetMapList.isEmpty()) {
354 nvpnManager.createVpnInterface(listVpnIds, routerPort, null);
356 IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
357 for (FixedIps portIP : routerPort.nonnullFixedIps().values()) {
358 String ipValue = portIP.getIpAddress().stringValue();
359 ipVersion = NeutronvpnUtils.getIpVersionFromString(ipValue);
360 if (ipVersion.isIpVersionChosen(IpVersionChoice.IPV4)) {
361 nvpnManager.addSubnetToVpn(vpnId, portIP.getSubnetId(),
362 null /* internet-vpn-id */);
364 nvpnManager.addSubnetToVpn(vpnId, portIP.getSubnetId(), internetVpnId);
366 LOG.trace("NeutronPortChangeListener Add Subnet Gateway IP {} MAC {} Interface {} VPN {}",
367 ipValue, routerPort.getMacAddress(),
368 routerPort.getUuid().getValue(), vpnId.getValue());
370 if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(ipVersion, routerId, true)) {
371 LOG.debug("vpnInstanceOpDataEntry is getting update with ip address family {} for VPN {}",
372 ipVersion, vpnId.getValue());
373 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, true);
375 nvpnManager.addToNeutronRouterInterfacesMap(routerId, routerPort.getUuid().getValue());
376 jobCoordinator.enqueueJob(routerId.toString(), () -> {
377 nvpnNatManager.handleSubnetsForExternalRouter(routerId);
378 return Collections.emptyList();
380 LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
382 String portInterfaceName = createOfPortInterface(routerPort, confTx);
383 createElanInterface(routerPort, portInterfaceName, confTx);
384 }), LOG, "Error creating ELAN interface for {}", routerPort);
386 LOG.error("Neutron network {} corresponding to router interface port {} for neutron router {}"
387 + " already associated to VPN {}", infNetworkId.getValue(), routerPort.getUuid().getValue(),
388 routerId.getValue(), existingVpnId.getValue());
393 private void handleRouterInterfaceRemoved(Port routerPort) {
394 if (routerPort.getDeviceId() != null) {
395 Uuid routerId = new Uuid(routerPort.getDeviceId());
396 Uuid infNetworkId = routerPort.getNetworkId();
397 elanService.removeKnownL3DmacAddress(routerPort.getMacAddress().getValue(), infNetworkId.getValue());
398 Uuid vpnId = ObjectUtils.defaultIfNull(neutronvpnUtils.getVpnForRouter(routerId, true),
400 Map<FixedIpsKey, FixedIps> keyFixedIpsMap = routerPort.nonnullFixedIps();
401 boolean vpnInstanceInternetIpVersionRemoved = false;
402 Uuid vpnInstanceInternetUuid = null;
403 for (FixedIps portIP : keyFixedIpsMap.values()) {
404 // Internet VPN : flush InternetVPN first
405 Uuid subnetId = portIP.getSubnetId();
406 Subnetmap sn = neutronvpnUtils.getSubnetmap(subnetId);
407 if (sn != null && sn.getInternetVpnId() != null) {
408 if (neutronvpnUtils.shouldVpnHandleIpVersionChangeToRemove(sn, sn.getInternetVpnId())) {
409 vpnInstanceInternetIpVersionRemoved = true;
410 vpnInstanceInternetUuid = sn.getInternetVpnId();
412 nvpnManager.updateVpnInternetForSubnet(sn, sn.getInternetVpnId(), false);
415 /* Remove ping responder for router interfaces
416 * A router interface reference in a VPN will have to be removed before the host interface references
417 * for that subnet in the VPN are removed. This is to ensure that the FIB Entry of the router interface
418 * is not the last entry to be removed for that subnet in the VPN.
419 * If router interface FIB entry is the last to be removed for a subnet in a VPN , then all the host
420 * interface references in the vpn will already have been cleared, which will cause failures in
421 * cleanup of router interface flows*/
422 nvpnManager.deleteVpnInterface(routerPort.getUuid().getValue(),
423 null /* vpn-id */, null /* wrtConfigTxn*/);
424 // update RouterInterfaces map
425 LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
427 IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
428 for (FixedIps portIP : keyFixedIpsMap.values()) {
429 Subnetmap sn = neutronvpnUtils.getSubnetmap(portIP.getSubnetId());
431 LOG.error("Subnetmap for subnet {} not found", portIP.getSubnetId().getValue());
434 // router Port have either IPv4 or IPv6, never both
435 ipVersion = neutronvpnUtils.getIpVersionFromString(sn.getSubnetIp());
436 String ipValue = portIP.getIpAddress().stringValue();
437 neutronvpnUtils.removeVpnPortFixedIpToPort(vpnId.getValue(), ipValue, confTx);
438 // NOTE: Please donot change the order of calls to removeSubnetFromVpn and
439 // and updateSubnetNodeWithFixedIP
440 nvpnManager.removeSubnetFromVpn(vpnId, sn, sn.getInternetVpnId());
441 nvpnManager.updateSubnetNodeWithFixedIp(portIP.getSubnetId(), null, null,
444 nvpnManager.removeFromNeutronRouterInterfacesMap(routerId, routerPort.getUuid().getValue());
445 deleteElanInterface(routerPort.getUuid().getValue(), confTx);
446 deleteOfPortInterface(routerPort, confTx);
447 jobCoordinator.enqueueJob(routerId.toString(), () -> {
448 nvpnNatManager.handleSubnetsForExternalRouter(routerId);
449 return Collections.emptyList();
451 if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(ipVersion, routerId, false)) {
452 LOG.debug("vpnInstanceOpDataEntry is getting update with ip address family {} for VPN {}",
453 ipVersion, vpnId.getValue());
454 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, false);
456 }), LOG, "Error handling interface removal");
457 if (vpnInstanceInternetIpVersionRemoved) {
458 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnInstanceInternetUuid.getValue(),
459 IpVersionChoice.IPV6, false);
460 neutronvpnUtils.updateVpnInstanceWithFallback(routerId, vpnInstanceInternetUuid, false);
465 private void handleRouterGatewayUpdated(Port routerGwPort, boolean isRtrGwRemoved) {
466 Uuid routerId = new Uuid(routerGwPort.getDeviceId());
467 Uuid networkId = routerGwPort.getNetworkId();
468 Network network = neutronvpnUtils.getNeutronNetwork(networkId);
469 if (network == null) {
472 boolean isExternal = NeutronvpnUtils.getIsExternal(network);
474 Uuid vpnInternetId = neutronvpnUtils.getVpnForNetwork(networkId);
475 if (vpnInternetId != null) {
476 if (!isRtrGwRemoved) {
477 nvpnManager.updateVpnMaps(vpnInternetId, null, routerId, null, null);
479 List<Subnetmap> snList = neutronvpnUtils.getNeutronRouterSubnetMaps(routerId);
480 for (Subnetmap sn : snList) {
481 if (sn.getNetworkId() == networkId) {
484 if (NeutronvpnUtils.getIpVersionFromString(sn.getSubnetIp()) != IpVersionChoice.IPV6) {
487 if (isRtrGwRemoved) {
488 nvpnManager.removeV6PrivateSubnetToExtNetwork(routerId, vpnInternetId, sn);
490 nvpnManager.addV6PrivateSubnetToExtNetwork(routerId, vpnInternetId, sn);
493 //Update Internet BGP-VPN
494 if (isRtrGwRemoved) {
495 nvpnManager.updateVpnMaps(vpnInternetId, null, null, null, null);
499 elanService.addKnownL3DmacAddress(routerGwPort.getMacAddress().getValue(), networkId.getValue());
501 Router router = neutronvpnUtils.getNeutronRouter(routerId);
502 if (router == null) {
503 LOG.warn("No router found for router GW port {} for router {}", routerGwPort.getUuid().getValue(),
504 routerId.getValue());
506 eventCallbacks.onAddOrUpdate(LogicalDatastoreType.CONFIGURATION,
507 neutronvpnUtils.getNeutronRouterIid(routerId), (unused, newRouter) -> {
508 setupGwMac(newRouter, routerGwPort, routerId);
509 return DataTreeEventCallbackRegistrar.NextAction.UNREGISTER;
510 }, Duration.ofSeconds(3), iid -> {
511 LOG.error("GwPort {} added without Router", routerGwPort.getUuid().getValue());
515 setupGwMac(router, routerGwPort, routerId);
518 private void setupGwMac(Router router, Port routerGwPort, Uuid routerId) {
519 gwMacResolver.sendArpRequestsToExtGateways(router);
520 jobCoordinator.enqueueJob(routerId.toString(), () -> {
521 setExternalGwMac(routerGwPort, routerId);
522 return Collections.emptyList();
526 private void setExternalGwMac(Port routerGwPort, Uuid routerId) {
527 // During full-sync networking-odl syncs routers before ports. As such,
528 // the MAC of the router's gw port is not available to be set when the
529 // router is written. We catch that here.
530 InstanceIdentifier<Routers> routersId = NeutronvpnUtils.buildExtRoutersIdentifier(routerId);
531 Optional<Routers> optionalRouter = null;
533 optionalRouter = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routersId);
534 if (!optionalRouter.isPresent()) {
537 Routers extRouters = optionalRouter.get();
538 if (extRouters.getExtGwMacAddress() != null) {
542 RoutersBuilder builder = new RoutersBuilder(extRouters);
543 builder.setExtGwMacAddress(routerGwPort.getMacAddress().getValue());
544 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, routersId, builder.build());
545 } catch (ExecutionException | InterruptedException e) {
546 LOG.error("setExternalGwMac: failed to read EXT-Routers for router Id {} rout-Gw port {} due to exception",
547 routerId, routerGwPort, e);
553 private String getPortHostId(final Port port) {
555 PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
556 if (portBinding != null) {
557 return portBinding.getHostId();
564 private Hostconfig getHostConfig(final Port port) {
565 String hostId = getPortHostId(port);
566 if (hostId == null) {
569 Optional<Hostconfig> hostConfig;
571 hostConfig = this.hostConfigCache.get(hostId);
572 } catch (ReadFailedException e) {
573 LOG.error("failed to read host config from host {}", hostId, e);
576 return hostConfig.orElse(null);
579 private boolean isPortBound(final Port port) {
580 String hostId = getPortHostId(port);
581 return hostId != null && !hostId.isEmpty();
584 private boolean isPortVnicTypeDirect(Port port) {
585 PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
586 if (portBinding == null || portBinding.getVnicType() == null) {
587 // By default, VNIC_TYPE is NORMAL
590 String vnicType = portBinding.getVnicType().trim().toLowerCase(Locale.getDefault());
591 return NeutronConstants.VNIC_TYPE_DIRECT.equals(vnicType);
594 private boolean isSupportedVnicTypeByHost(final Port port, final String vnicType) {
595 Hostconfig hostConfig = getHostConfig(port);
596 String supportStr = String.format("\"vnic_type\": \"%s\"", vnicType);
597 if (hostConfig != null && hostConfig.getConfig().contains(supportStr)) {
604 private Map<String, JsonElement> unmarshal(final String profile) {
605 if (null == profile) {
608 Gson gson = new Gson();
609 JsonObject jsonObject = gson.fromJson(profile, JsonObject.class);
610 Map<String, JsonElement> map = new HashMap<>();
611 for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
612 map.put(entry.getKey(), entry.getValue());
617 private boolean isPortTypeSwitchdev(final Port port) {
618 if (!isPortVnicTypeDirect(port)) {
622 PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
623 String profile = portBinding.getProfile();
624 if (profile == null || profile.isEmpty()) {
625 LOG.debug("Port {} has no binding:profile values", port.getUuid());
629 Map<String, JsonElement> mapProfile = unmarshal(profile);
630 JsonElement capabilities = mapProfile.get(NeutronConstants.BINDING_PROFILE_CAPABILITIES);
631 LOG.debug("Port {} capabilities: {}", port.getUuid(), capabilities);
632 if (capabilities == null || !capabilities.isJsonArray()) {
633 LOG.debug("binding profile capabilities not in array format: {}", capabilities);
637 JsonArray capabilitiesArray = capabilities.getAsJsonArray();
638 Gson gson = new Gson();
639 JsonElement switchdevElement = gson.fromJson(NeutronConstants.SWITCHDEV, JsonElement.class);
640 return capabilitiesArray.contains(switchdevElement);
644 private void handleNeutronPortCreated(final Port port) {
645 final String portName = port.getUuid().getValue();
646 final Uuid portId = port.getUuid();
647 final String networkId = port.getNetworkId().getValue();
648 final Map<FixedIpsKey, FixedIps> keyFixedIpsMap = port.nonnullFixedIps();
649 if (NeutronConstants.IS_ODL_DHCP_PORT.test(port)) {
652 if (!NeutronUtils.isPortVnicTypeNormal(port)
653 && (!isPortTypeSwitchdev(port) || !isSupportedVnicTypeByHost(port, NeutronConstants.VNIC_TYPE_DIRECT))) {
654 for (FixedIps ip: keyFixedIpsMap.values()) {
655 nvpnManager.updateSubnetmapNodeWithPorts(ip.getSubnetId(), null, portId);
657 LOG.info("Port {} is not a normal and not a direct with switchdev VNIC type ;"
658 + "OF Port interfaces are not created", portName);
661 jobCoordinator.enqueueJob("PORT- " + portName, () -> {
662 // add direct port to subnetMaps config DS
663 // TODO: for direct port as well, operations should be carried out per subnet based on port IP
665 ListenableFuture<?> future = txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
666 LOG.info("Of-port-interface creation for port {}", portName);
667 // Create of-port interface for this neutron port
668 String portInterfaceName = createOfPortInterface(port, tx);
669 LOG.debug("Creating ELAN Interface for port {}", portName);
670 createElanInterface(port, portInterfaceName, tx);
671 Set<Uuid> vpnIdList = new HashSet<>();
672 Set<Uuid> routerIds = new HashSet<>();
673 for (FixedIps ip: keyFixedIpsMap.values()) {
674 Subnetmap subnetMap = nvpnManager.updateSubnetmapNodeWithPorts(ip.getSubnetId(), portId, null);
675 if (subnetMap != null && subnetMap.getInternetVpnId() != null) {
676 if (!vpnIdList.contains(subnetMap.getInternetVpnId())) {
677 vpnIdList.add(subnetMap.getInternetVpnId());
680 if (subnetMap != null && subnetMap.getVpnId() != null) {
681 // can't use NeutronvpnUtils.getVpnForNetwork to optimise here, because it gives BGPVPN id
682 // obtained subnetMaps belongs to one network => vpnId must be the same for each port Ip
683 Uuid vpnId = subnetMap.getVpnId();
685 vpnIdList.add(vpnId);
688 if (subnetMap != null && subnetMap.getRouterId() != null) {
689 routerIds.add(subnetMap.getRouterId());
692 if (!vpnIdList.isEmpty()) {
693 // create new vpn-interface for neutron port
694 LOG.debug("handleNeutronPortCreated: Adding VPN Interface for port {} from network {}", portName,
696 nvpnManager.createVpnInterface(vpnIdList, port, tx);
697 for (Uuid routerId : routerIds) {
698 nvpnManager.addToNeutronRouterInterfacesMap(routerId,port.getUuid().getValue());
702 LoggingFutures.addErrorLogging(future, LOG,
703 "handleNeutronPortCreated: Failed for port {} with networkId {}", portName, networkId);
704 return Collections.singletonList(future);
708 private void handleNeutronPortDeleted(final Port port) {
709 final String portName = port.getUuid().getValue();
710 final Uuid portId = port.getUuid();
711 final Map<FixedIpsKey, FixedIps> keyFixedIpsMap = port.nonnullFixedIps();
712 if (!NeutronUtils.isPortVnicTypeNormal(port) && !isPortTypeSwitchdev(port)) {
713 for (FixedIps ip : keyFixedIpsMap.values()) {
714 // remove direct port from subnetMaps config DS
715 // TODO: for direct port as well, operations should be carried out per subnet based on port IP
716 nvpnManager.removePortsFromSubnetmapNode(ip.getSubnetId(), null, portId);
718 LOG.info("Port {} is not a normal and not a direct with switchdev VNIC type ;"
719 + "Skipping OF Port interfaces removal", portName);
722 jobCoordinator.enqueueJob("PORT- " + portName, () -> {
723 ListenableFuture<?> future = txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
726 Set<Uuid> routerIds = new HashSet<>();
727 Uuid internetVpnId = null;
728 for (FixedIps ip : keyFixedIpsMap.values()) {
729 Subnetmap subnetMap = nvpnManager.removePortsFromSubnetmapNode(ip.getSubnetId(), portId, null);
730 if (subnetMap == null) {
733 if (subnetMap.getVpnId() != null) {
734 // can't use NeutronvpnUtils.getVpnForNetwork to optimise here, because it gives BGPVPN id
735 // obtained subnetMaps belongs to one network => vpnId must be the same for each port Ip
736 vpnId = subnetMap.getVpnId();
738 if (subnetMap.getRouterId() != null) {
739 routerIds.add(subnetMap.getRouterId());
741 internetVpnId = subnetMap.getInternetVpnId();
743 if (NeutronConstants.DEVICE_OWNER_GATEWAY_INF.equals(port.getDeviceOwner())
744 || NeutronConstants.DEVICE_OWNER_FLOATING_IP.equals(port.getDeviceOwner())) {
745 String ipAddress = ip.getIpAddress().stringValue();
747 neutronvpnUtils.removeVpnPortFixedIpToPort(vpnId.getValue(), ipAddress, confTx);
749 if (internetVpnId != null) {
750 neutronvpnUtils.removeVpnPortFixedIpToPort(internetVpnId.getValue(),
755 if (vpnId != null || internetVpnId != null) {
756 // remove vpn-interface for this neutron port
757 LOG.debug("removing VPN Interface for port {}", portName);
758 if (!routerIds.isEmpty()) {
759 for (Uuid routerId : routerIds) {
760 nvpnManager.removeFromNeutronRouterInterfacesMap(routerId, portName);
763 nvpnManager.deleteVpnInterface(portName, null /* vpn-id */, confTx);
765 // Remove of-port interface for this neutron port
766 // ELAN interface is also implicitly deleted as part of this operation
767 LOG.debug("Of-port-interface removal for port {}", portName);
768 deleteOfPortInterface(port, confTx);
769 //dissociate fixedIP from floatingIP if associated
770 nvpnManager.dissociatefixedIPFromFloatingIP(port.getUuid().getValue());
772 LoggingFutures.addErrorLogging(future, LOG,
773 "handleNeutronPortDeleted: Failed to update interface {} with networkId", portName,
774 port.getNetworkId().getValue());
775 return Collections.singletonList(future);
780 private void handleNeutronPortUpdated(final Port portoriginal, final Port portupdate) {
781 final Map<FixedIpsKey, FixedIps> portoriginalIpsMap = portoriginal.nonnullFixedIps();
782 final Map<FixedIpsKey, FixedIps> portupdateIpsMap = portupdate.nonnullFixedIps();
783 if (portoriginalIpsMap == null || portoriginalIpsMap.isEmpty()) {
784 handleNeutronPortCreated(portupdate);
788 if (portupdateIpsMap == null || portupdateIpsMap.isEmpty()) {
789 LOG.info("Ignoring portUpdate (fixed_ip removal) for port {} as this case is handled "
790 + "during subnet deletion event.", portupdate.getUuid().getValue());
794 if (NeutronConstants.IS_ODL_DHCP_PORT.test(portupdate)) {
798 jobCoordinator.enqueueJob("PORT- " + portupdate.getUuid().getValue(),
799 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
800 final List<Uuid> originalSnMapsIds = portoriginalIpsMap.values().stream().map(FixedIps::getSubnetId)
801 .collect(Collectors.toList());
802 final List<Uuid> updateSnMapsIds = portupdateIpsMap.values().stream().map(FixedIps::getSubnetId)
803 .collect(Collectors.toList());
804 Set<Uuid> originalRouterIds = new HashSet<>();
805 Set<Uuid> oldVpnIds = new HashSet<>();
806 for (Uuid snId: originalSnMapsIds) {
807 if (!updateSnMapsIds.remove(snId)) {
808 // snId was present in originalSnMapsIds, but not in updateSnMapsIds
809 Subnetmap subnetMapOld = nvpnManager.removePortsFromSubnetmapNode(snId, portoriginal.getUuid(),
811 if (subnetMapOld != null && subnetMapOld.getVpnId() != null) {
812 oldVpnIds.add(subnetMapOld.getVpnId());
814 if (subnetMapOld != null && subnetMapOld.getInternetVpnId() != null) {
815 oldVpnIds.add(subnetMapOld.getInternetVpnId());
817 if (subnetMapOld != null && subnetMapOld.getRouterId() != null) {
818 originalRouterIds.add(subnetMapOld.getRouterId());
822 Set<Uuid> newVpnIds = new HashSet<>();
823 Set<Uuid> newRouterIds = new HashSet<>();
824 for (Uuid snId: updateSnMapsIds) {
825 Subnetmap subnetMapNew = nvpnManager.updateSubnetmapNodeWithPorts(snId, portupdate.getUuid(), null);
826 if (subnetMapNew != null) {
827 if (subnetMapNew.getVpnId() != null) {
828 newVpnIds.add(subnetMapNew.getVpnId());
830 if (subnetMapNew.getInternetVpnId() != null) {
831 newVpnIds.add(subnetMapNew.getInternetVpnId());
833 if (subnetMapNew.getRouterId() != null) {
834 newRouterIds.add(subnetMapNew.getRouterId());
838 if (!oldVpnIds.isEmpty()) {
839 LOG.info("removing VPN Interface for port {}", portoriginal.getUuid().getValue());
840 if (!originalRouterIds.isEmpty()) {
841 for (Uuid routerId : originalRouterIds) {
842 nvpnManager.removeFromNeutronRouterInterfacesMap(routerId,
843 portoriginal.getUuid().getValue());
846 nvpnManager.deleteVpnInterface(portoriginal.getUuid().getValue(),
847 null /* vpn-id */, confTx);
849 if (!newVpnIds.isEmpty()) {
850 LOG.info("Adding VPN Interface for port {}", portupdate.getUuid().getValue());
851 nvpnManager.createVpnInterface(newVpnIds, portupdate, confTx);
852 if (!newRouterIds.isEmpty()) {
853 for (Uuid routerId : newRouterIds) {
854 nvpnManager.addToNeutronRouterInterfacesMap(routerId,portupdate.getUuid().getValue());
862 private InterfaceAclBuilder handlePortSecurityUpdated(Port portOriginal,
863 Port portUpdated, boolean origSecurityEnabled, boolean updatedSecurityEnabled,
864 InterfaceBuilder interfaceBuilder) {
865 InterfaceAclBuilder interfaceAclBuilder = null;
866 if (origSecurityEnabled != updatedSecurityEnabled) {
867 interfaceAclBuilder = new InterfaceAclBuilder();
868 interfaceAclBuilder.setPortSecurityEnabled(updatedSecurityEnabled);
869 if (updatedSecurityEnabled) {
870 // Handle security group enabled
871 neutronvpnUtils.populateInterfaceAclBuilder(interfaceAclBuilder, portUpdated);
873 // Handle security group disabled
874 interfaceAclBuilder.setSecurityGroups(new ArrayList<>());
875 interfaceAclBuilder.setAllowedAddressPairs(new ArrayList<>());
876 interfaceAclBuilder.setSubnetInfo(new ArrayList<>());
879 if (updatedSecurityEnabled) {
880 // handle SG add/delete delta
881 InterfaceAcl interfaceAcl = interfaceBuilder.augmentation(InterfaceAcl.class);
882 interfaceAclBuilder = new InterfaceAclBuilder(interfaceAcl);
883 interfaceAclBuilder.setSecurityGroups(
884 NeutronvpnUtils.getUpdatedSecurityGroups(interfaceAcl.getSecurityGroups(),
885 portOriginal.getSecurityGroups(), portUpdated.getSecurityGroups()));
886 List<AllowedAddressPairs> updatedAddressPairs = NeutronvpnUtils.getUpdatedAllowedAddressPairs(
887 new ArrayList<>(interfaceAcl.nonnullAllowedAddressPairs().values()),
888 new ArrayList<>(portOriginal.nonnullAllowedAddressPairs().values()),
889 new ArrayList<>(portUpdated.nonnullAllowedAddressPairs().values()));
890 interfaceAclBuilder.setAllowedAddressPairs(NeutronvpnUtils.getAllowedAddressPairsForFixedIps(
891 updatedAddressPairs, portOriginal.getMacAddress(), portOriginal.getFixedIps(),
892 portUpdated.nonnullFixedIps().values()));
894 if (portOriginal.getFixedIps() != null
895 && !portOriginal.getFixedIps().equals(portUpdated.getFixedIps())) {
896 neutronvpnUtils.populateSubnetInfo(interfaceAclBuilder, portUpdated);
900 return interfaceAclBuilder;
903 private String createOfPortInterface(Port port, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
904 Interface inf = createInterface(port);
905 String infName = inf.getName();
907 InstanceIdentifier<Interface> interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(infName);
909 Optional<Interface> optionalInf =
910 SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
911 interfaceIdentifier);
912 if (!optionalInf.isPresent()) {
913 wrtConfigTxn.put(interfaceIdentifier, inf);
914 } else if (isInterfaceUpdated(inf, optionalInf.get())) {
916 Case where an update DTCN wasn't received by this class due to node going down
917 upon cluster reboot or any other unknown reason
918 In such a case, updates contained in the missed DTCN won't be processed and have to be handled
920 Update of subports (vlanId, splithorizon tag) is handled here
921 Update of portSecurity (PortSecurityEnabled, SecurityGroups, AllowedAddressPairs) add is handled
922 Update of portSecurity update/removed is not handled
923 Update of parentrefs is not handled as parentrefs updation is handled by IFM Oxygen onwards
925 wrtConfigTxn.put(interfaceIdentifier, inf);
926 LOG.error("Interface {} is already present and is updated", infName);
928 LOG.warn("Interface {} is already present", infName);
930 } catch (ExecutionException | InterruptedException e) {
931 LOG.error("failed to create interface {}", infName, e);
936 // Not for generic use. For a special case where update DTCN isn't received
937 private static boolean isInterfaceUpdated(Interface newInterface, Interface oldInterface) {
938 if (newInterface.augmentation(SplitHorizon.class) != null) {
939 if (oldInterface.augmentation(SplitHorizon.class) == null) {
942 if (!newInterface.augmentation(SplitHorizon.class).equals(oldInterface
943 .augmentation(SplitHorizon.class))) {
947 if (!newInterface.augmentation(IfL2vlan.class).equals(oldInterface.augmentation(IfL2vlan.class))) {
950 if (newInterface.augmentation(InterfaceAcl.class) != null && oldInterface
951 .augmentation(InterfaceAcl.class) == null) {
957 private Interface createInterface(Port port) {
958 String interfaceName = port.getUuid().getValue();
959 IfL2vlan.L2vlanMode l2VlanMode = IfL2vlan.L2vlanMode.Trunk;
960 InterfaceBuilder interfaceBuilder = new InterfaceBuilder();
961 IfL2vlanBuilder ifL2vlanBuilder = new IfL2vlanBuilder();
963 Network network = neutronvpnUtils.getNeutronNetwork(port.getNetworkId());
964 Boolean isVlanTransparent = network.isVlanTransparent();
965 if (isVlanTransparent != null && isVlanTransparent) {
966 l2VlanMode = IfL2vlan.L2vlanMode.Transparent;
968 PortIdToSubport portIdToSubport = neutronvpnUtils.getPortIdToSubport(port.getUuid());
969 if (portIdToSubport != null) {
970 l2VlanMode = IfL2vlan.L2vlanMode.TrunkMember;
971 ifL2vlanBuilder.setVlanId(new VlanId(portIdToSubport.getVlanId().intValue()));
972 String parentRefName = portIdToSubport.getTrunkPortId().getValue();
973 ParentRefsBuilder parentRefsBuilder = new ParentRefsBuilder().setParentInterface(parentRefName);
974 interfaceBuilder.addAugmentation(parentRefsBuilder.build());
975 SplitHorizon splitHorizon =
976 new SplitHorizonBuilder().setOverrideSplitHorizonProtection(true).build();
977 interfaceBuilder.addAugmentation(splitHorizon);
981 ifL2vlanBuilder.setL2vlanMode(l2VlanMode);
983 interfaceBuilder.setEnabled(true).setName(interfaceName).setType(L2vlan.class)
984 .addAugmentation(ifL2vlanBuilder.build());
986 if (NeutronvpnUtils.getPortSecurityEnabled(port)) {
987 InterfaceAclBuilder interfaceAclBuilder = new InterfaceAclBuilder();
988 interfaceAclBuilder.setPortSecurityEnabled(true);
989 neutronvpnUtils.populateInterfaceAclBuilder(interfaceAclBuilder, port);
990 interfaceBuilder.addAugmentation(interfaceAclBuilder.build());
991 } else if (neutronvpnConfig.isLimitBumtrafficToDhcpserver() && NeutronvpnUtils.isDhcpServerPort(port)) {
992 interfaceBuilder.addAugmentation(neutronvpnUtils.getDhcpInterfaceAcl(port));
994 return interfaceBuilder.build();
997 private void deleteOfPortInterface(Port port, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
998 String name = port.getUuid().getValue();
999 LOG.debug("Removing OFPort Interface {}", name);
1000 InstanceIdentifier<Interface> interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(name);
1002 Optional<Interface> optionalInf =
1003 SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
1004 interfaceIdentifier);
1005 if (optionalInf.isPresent()) {
1006 wrtConfigTxn.delete(interfaceIdentifier);
1008 LOG.warn("deleteOfPortInterface: Interface {} is not present", name);
1010 } catch (ExecutionException | InterruptedException e) {
1011 LOG.error("deleteOfPortInterface: Failed to delete interface {}", name, e);
1015 private void createElanInterface(Port port, String name,
1016 TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
1017 String elanInstanceName = port.getNetworkId().getValue();
1018 List<StaticMacEntries> staticMacEntries = NeutronvpnUtils.buildStaticMacEntry(port);
1020 InstanceIdentifier<ElanInterface> id = InstanceIdentifier.builder(ElanInterfaces.class).child(ElanInterface
1021 .class, new ElanInterfaceKey(name)).build();
1022 ElanInterface elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName)
1023 .setName(name).setStaticMacEntries(staticMacEntries).withKey(new ElanInterfaceKey(name)).build();
1024 wrtConfigTxn.put(id, elanInterface);
1025 LOG.debug("Creating new ELan Interface {}", elanInterface);
1028 private void deleteElanInterface(String name, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
1029 InstanceIdentifier<ElanInterface> id = InstanceIdentifier.builder(ElanInterfaces.class).child(ElanInterface
1030 .class, new ElanInterfaceKey(name)).build();
1031 wrtConfigTxn.delete(id);
1034 // TODO Clean up the exception handling
1035 @SuppressWarnings("checkstyle:IllegalCatch")
1036 private void addToFloatingIpPortInfo(Uuid floatingIpId, Uuid floatingIpPortId, Uuid floatingIpPortSubnetId, String
1037 floatingIpPortMacAddress) {
1038 InstanceIdentifier id = NeutronvpnUtils.buildfloatingIpIdToPortMappingIdentifier(floatingIpId);
1040 FloatingIpIdToPortMappingBuilder floatingipIdToPortMacMappingBuilder = new
1041 FloatingIpIdToPortMappingBuilder().withKey(new FloatingIpIdToPortMappingKey(floatingIpId))
1042 .setFloatingIpId(floatingIpId).setFloatingIpPortId(floatingIpPortId)
1043 .setFloatingIpPortSubnetId(floatingIpPortSubnetId)
1044 .setFloatingIpPortMacAddress(floatingIpPortMacAddress);
1045 LOG.debug("Creating floating IP UUID {} to Floating IP neutron port {} mapping in Floating IP"
1046 + " Port Info Config DS", floatingIpId.getValue(), floatingIpPortId.getValue());
1047 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id,
1048 floatingipIdToPortMacMappingBuilder.build());
1049 } catch (Exception e) {
1050 LOG.error("Creating floating IP UUID {} to Floating IP neutron port {} mapping in Floating IP"
1051 + " Port Info Config DS failed", floatingIpId.getValue(), floatingIpPortId.getValue(), e);
1055 private Set<FixedIps> getFixedIpSet(List<FixedIps> fixedIps) {
1056 return fixedIps != null ? new HashSet<>(fixedIps) : Collections.emptySet();