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.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 // Switchdev ports need to be bounded to a host before creation
221 // in order to validate the supported vnic types from the hostconfig
222 if (isPortTypeSwitchdev(original)
223 && !isPortBound(original)
224 && isPortBound(update)) {
225 handleNeutronPortCreated(update);
227 final String portName = update.getUuid().getValue();
228 Network network = neutronvpnUtils.getNeutronNetwork(update.getNetworkId());
229 if (network == null || !NeutronvpnUtils.isNetworkTypeSupported(network)) {
230 LOG.warn("neutron vpn received a port update() for a network without a provider extension augmentation "
231 + "or with an unsupported network type for the port {} which is part of network {}",
235 neutronvpnUtils.addToPortCache(update);
237 if ((Strings.isNullOrEmpty(original.getDeviceOwner()) || Strings.isNullOrEmpty(original.getDeviceId())
238 || NeutronConstants.FLOATING_IP_DEVICE_ID_PENDING.equalsIgnoreCase(original.getDeviceId()))
239 && !Strings.isNullOrEmpty(update.getDeviceOwner()) && !Strings.isNullOrEmpty(update.getDeviceId())) {
240 if (NeutronConstants.DEVICE_OWNER_ROUTER_INF.equals(update.getDeviceOwner())) {
241 handleRouterInterfaceAdded(update);
244 if (NeutronConstants.DEVICE_OWNER_GATEWAY_INF.equals(update.getDeviceOwner())) {
245 handleRouterGatewayUpdated(update, false);
246 } else if (NeutronConstants.DEVICE_OWNER_FLOATING_IP.equals(update.getDeviceOwner())) {
247 handleFloatingIpPortUpdated(original, update);
250 Set<FixedIps> oldIPs = getFixedIpSet(new ArrayList<FixedIps>(original.nonnullFixedIps().values()));
251 Set<FixedIps> newIPs = getFixedIpSet(new ArrayList<FixedIps>(update.nonnullFixedIps().values()));
252 if (!oldIPs.equals(newIPs)) {
253 handleNeutronPortUpdated(original, update);
257 // check if port security enabled/disabled as part of port update
258 boolean origSecurityEnabled = NeutronvpnUtils.getPortSecurityEnabled(original);
259 boolean updatedSecurityEnabled = NeutronvpnUtils.getPortSecurityEnabled(update);
260 boolean isDhcpServerPort = neutronvpnConfig.isLimitBumtrafficToDhcpserver()
261 && NeutronvpnUtils.isDhcpServerPort(update);
262 if (origSecurityEnabled || updatedSecurityEnabled || isDhcpServerPort) {
263 InstanceIdentifier<Interface> interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(portName);
264 jobCoordinator.enqueueJob("PORT- " + portName, () -> {
265 ListenableFuture<Void> future = txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
267 Optional<Interface> optionalInf = confTx.read(interfaceIdentifier).get();
268 if (optionalInf.isPresent()) {
269 InterfaceBuilder interfaceBuilder = new InterfaceBuilder(optionalInf.get());
270 if (origSecurityEnabled || updatedSecurityEnabled) {
271 InterfaceAcl infAcl = handlePortSecurityUpdated(original, update, origSecurityEnabled,
272 updatedSecurityEnabled, interfaceBuilder).build();
273 interfaceBuilder.addAugmentation(InterfaceAcl.class, infAcl);
274 } else if (isDhcpServerPort) {
275 Set<FixedIps> oldIPs = getFixedIpSet(
276 new ArrayList<FixedIps>(original.nonnullFixedIps().values()));
277 Set<FixedIps> newIPs = getFixedIpSet(
278 new ArrayList<FixedIps>(update.nonnullFixedIps().values()));
279 if (!oldIPs.equals(newIPs)) {
280 InterfaceAcl infAcl = neutronvpnUtils.getDhcpInterfaceAcl(update);
281 interfaceBuilder.addAugmentation(InterfaceAcl.class, infAcl);
284 LOG.info("update: Of-port-interface updation for port {}", portName);
285 // Update OFPort interface for this neutron port
286 confTx.put(interfaceIdentifier, interfaceBuilder.build());
288 LOG.warn("update: Interface {} is not present", portName);
291 ListenableFutures.addErrorLogging(future, LOG,
292 "update: Failed to update interface {} with networkId {}", portName, network);
293 return Collections.singletonList(future);
298 private void handleFloatingIpPortUpdated(@Nullable Port original, Port update) {
299 if ((original == null || NeutronConstants.FLOATING_IP_DEVICE_ID_PENDING.equals(original.getDeviceId()))
300 && !NeutronConstants.FLOATING_IP_DEVICE_ID_PENDING.equals(update.getDeviceId())) {
301 // populate floating-ip uuid and floating-ip port attributes (uuid, mac and subnet id for the ONLY
302 // fixed IP) to be used by NAT, depopulated in NATService once mac is retrieved in the removal path
303 addToFloatingIpPortInfo(new Uuid(update.getDeviceId()), update.getUuid(),
304 new ArrayList<FixedIps>(update.nonnullFixedIps().values()).get(0)
305 .getSubnetId(), update.getMacAddress().getValue());
306 elanService.addKnownL3DmacAddress(update.getMacAddress().getValue(), update.getNetworkId().getValue());
310 private void handleRouterInterfaceAdded(Port routerPort) {
311 if (routerPort.getDeviceId() != null) {
312 Uuid routerId = new Uuid(routerPort.getDeviceId());
313 Uuid infNetworkId = routerPort.getNetworkId();
314 Uuid existingVpnId = neutronvpnUtils.getVpnForNetwork(infNetworkId);
316 elanService.addKnownL3DmacAddress(routerPort.getMacAddress().getValue(), infNetworkId.getValue());
317 if (existingVpnId == null) {
318 Set<Uuid> listVpnIds = new HashSet<>();
319 Uuid vpnId = neutronvpnUtils.getVpnForRouter(routerId, true);
323 listVpnIds.add(vpnId);
324 Uuid internetVpnId = neutronvpnUtils.getInternetvpnUuidBoundToRouterId(routerId);
325 List<Subnetmap> subnetMapList = new ArrayList<>();
326 boolean portIsIpv6 = false;
327 for (FixedIps portIP : routerPort.nonnullFixedIps().values()) {
328 // NOTE: Please donot change the order of calls to updateSubnetNodeWithFixedIP
329 // and addSubnetToVpn here
330 if (internetVpnId != null
331 && portIP.getIpAddress().getIpv6Address() != null) {
334 String ipValue = portIP.getIpAddress().stringValue();
335 Uuid subnetId = portIP.getSubnetId();
336 nvpnManager.updateSubnetNodeWithFixedIp(subnetId, routerId,
337 routerPort.getUuid(), ipValue, routerPort.getMacAddress().getValue(), vpnId);
338 Subnetmap sn = neutronvpnUtils.getSubnetmap(subnetId);
339 subnetMapList.add(sn);
342 listVpnIds.add(internetVpnId);
343 if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(
344 IpVersionChoice.IPV6, routerId, true)) {
345 neutronvpnUtils.updateVpnInstanceWithIpFamily(internetVpnId.getValue(), IpVersionChoice.IPV6,
347 neutronvpnUtils.updateVpnInstanceWithFallback(routerId, internetVpnId, true);
350 if (! subnetMapList.isEmpty()) {
351 nvpnManager.createVpnInterface(listVpnIds, routerPort, null);
353 IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
354 for (FixedIps portIP : routerPort.nonnullFixedIps().values()) {
355 String ipValue = portIP.getIpAddress().stringValue();
356 ipVersion = NeutronvpnUtils.getIpVersionFromString(ipValue);
357 if (ipVersion.isIpVersionChosen(IpVersionChoice.IPV4)) {
358 nvpnManager.addSubnetToVpn(vpnId, portIP.getSubnetId(),
359 null /* internet-vpn-id */);
361 nvpnManager.addSubnetToVpn(vpnId, portIP.getSubnetId(), internetVpnId);
363 LOG.trace("NeutronPortChangeListener Add Subnet Gateway IP {} MAC {} Interface {} VPN {}",
364 ipValue, routerPort.getMacAddress(),
365 routerPort.getUuid().getValue(), vpnId.getValue());
367 if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(ipVersion, routerId, true)) {
368 LOG.debug("vpnInstanceOpDataEntry is getting update with ip address family {} for VPN {}",
369 ipVersion, vpnId.getValue());
370 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, true);
372 nvpnManager.addToNeutronRouterInterfacesMap(routerId, routerPort.getUuid().getValue());
373 jobCoordinator.enqueueJob(routerId.toString(), () -> {
374 nvpnNatManager.handleSubnetsForExternalRouter(routerId);
375 return Collections.emptyList();
377 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
379 String portInterfaceName = createOfPortInterface(routerPort, confTx);
380 createElanInterface(routerPort, portInterfaceName, confTx);
381 }), LOG, "Error creating ELAN interface for {}", routerPort);
383 LOG.error("Neutron network {} corresponding to router interface port {} for neutron router {}"
384 + " already associated to VPN {}", infNetworkId.getValue(), routerPort.getUuid().getValue(),
385 routerId.getValue(), existingVpnId.getValue());
390 private void handleRouterInterfaceRemoved(Port routerPort) {
391 if (routerPort.getDeviceId() != null) {
392 Uuid routerId = new Uuid(routerPort.getDeviceId());
393 Uuid infNetworkId = routerPort.getNetworkId();
394 elanService.removeKnownL3DmacAddress(routerPort.getMacAddress().getValue(), infNetworkId.getValue());
395 Uuid vpnId = ObjectUtils.defaultIfNull(neutronvpnUtils.getVpnForRouter(routerId, true),
397 Map<FixedIpsKey, FixedIps> keyFixedIpsMap = routerPort.nonnullFixedIps();
398 boolean vpnInstanceInternetIpVersionRemoved = false;
399 Uuid vpnInstanceInternetUuid = null;
400 for (FixedIps portIP : keyFixedIpsMap.values()) {
401 // Internet VPN : flush InternetVPN first
402 Uuid subnetId = portIP.getSubnetId();
403 Subnetmap sn = neutronvpnUtils.getSubnetmap(subnetId);
404 if (sn != null && sn.getInternetVpnId() != null) {
405 if (neutronvpnUtils.shouldVpnHandleIpVersionChangeToRemove(sn, sn.getInternetVpnId())) {
406 vpnInstanceInternetIpVersionRemoved = true;
407 vpnInstanceInternetUuid = sn.getInternetVpnId();
409 nvpnManager.updateVpnInternetForSubnet(sn, sn.getInternetVpnId(), false);
412 /* Remove ping responder for router interfaces
413 * A router interface reference in a VPN will have to be removed before the host interface references
414 * for that subnet in the VPN are removed. This is to ensure that the FIB Entry of the router interface
415 * is not the last entry to be removed for that subnet in the VPN.
416 * If router interface FIB entry is the last to be removed for a subnet in a VPN , then all the host
417 * interface references in the vpn will already have been cleared, which will cause failures in
418 * cleanup of router interface flows*/
419 nvpnManager.deleteVpnInterface(routerPort.getUuid().getValue(),
420 null /* vpn-id */, null /* wrtConfigTxn*/);
421 // update RouterInterfaces map
422 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
424 IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
425 for (FixedIps portIP : keyFixedIpsMap.values()) {
426 Subnetmap sn = neutronvpnUtils.getSubnetmap(portIP.getSubnetId());
428 LOG.error("Subnetmap for subnet {} not found", portIP.getSubnetId().getValue());
431 // router Port have either IPv4 or IPv6, never both
432 ipVersion = neutronvpnUtils.getIpVersionFromString(sn.getSubnetIp());
433 String ipValue = portIP.getIpAddress().stringValue();
434 neutronvpnUtils.removeVpnPortFixedIpToPort(vpnId.getValue(), ipValue, confTx);
435 // NOTE: Please donot change the order of calls to removeSubnetFromVpn and
436 // and updateSubnetNodeWithFixedIP
437 nvpnManager.removeSubnetFromVpn(vpnId, sn, sn.getInternetVpnId());
438 nvpnManager.updateSubnetNodeWithFixedIp(portIP.getSubnetId(), null, null,
441 nvpnManager.removeFromNeutronRouterInterfacesMap(routerId, routerPort.getUuid().getValue());
442 deleteElanInterface(routerPort.getUuid().getValue(), confTx);
443 deleteOfPortInterface(routerPort, confTx);
444 jobCoordinator.enqueueJob(routerId.toString(), () -> {
445 nvpnNatManager.handleSubnetsForExternalRouter(routerId);
446 return Collections.emptyList();
448 if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(ipVersion, routerId, false)) {
449 LOG.debug("vpnInstanceOpDataEntry is getting update with ip address family {} for VPN {}",
450 ipVersion, vpnId.getValue());
451 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, false);
453 }), LOG, "Error handling interface removal");
454 if (vpnInstanceInternetIpVersionRemoved) {
455 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnInstanceInternetUuid.getValue(),
456 IpVersionChoice.IPV6, false);
457 neutronvpnUtils.updateVpnInstanceWithFallback(routerId, vpnInstanceInternetUuid, false);
462 private void handleRouterGatewayUpdated(Port routerGwPort, boolean isRtrGwRemoved) {
463 Uuid routerId = new Uuid(routerGwPort.getDeviceId());
464 Uuid networkId = routerGwPort.getNetworkId();
465 Network network = neutronvpnUtils.getNeutronNetwork(networkId);
466 if (network == null) {
469 boolean isExternal = NeutronvpnUtils.getIsExternal(network);
471 Uuid vpnInternetId = neutronvpnUtils.getVpnForNetwork(networkId);
472 if (vpnInternetId != null) {
473 if (!isRtrGwRemoved) {
474 nvpnManager.updateVpnMaps(vpnInternetId, null, routerId, null, null);
476 List<Subnetmap> snList = neutronvpnUtils.getNeutronRouterSubnetMaps(routerId);
477 for (Subnetmap sn : snList) {
478 if (sn.getNetworkId() == networkId) {
481 if (NeutronvpnUtils.getIpVersionFromString(sn.getSubnetIp()) != IpVersionChoice.IPV6) {
484 if (isRtrGwRemoved) {
485 nvpnManager.removeV6PrivateSubnetToExtNetwork(routerId, vpnInternetId, sn);
487 nvpnManager.addV6PrivateSubnetToExtNetwork(routerId, vpnInternetId, sn);
490 //Update Internet BGP-VPN
491 if (isRtrGwRemoved) {
492 nvpnManager.updateVpnMaps(vpnInternetId, null, null, null, null);
496 elanService.addKnownL3DmacAddress(routerGwPort.getMacAddress().getValue(), networkId.getValue());
498 Router router = neutronvpnUtils.getNeutronRouter(routerId);
499 if (router == null) {
500 LOG.warn("No router found for router GW port {} for router {}", routerGwPort.getUuid().getValue(),
501 routerId.getValue());
503 eventCallbacks.onAddOrUpdate(LogicalDatastoreType.CONFIGURATION,
504 neutronvpnUtils.getNeutronRouterIid(routerId), (unused, newRouter) -> {
505 setupGwMac(newRouter, routerGwPort, routerId);
506 return DataTreeEventCallbackRegistrar.NextAction.UNREGISTER;
507 }, Duration.ofSeconds(3), iid -> {
508 LOG.error("GwPort {} added without Router", routerGwPort.getUuid().getValue());
512 setupGwMac(router, routerGwPort, routerId);
515 private void setupGwMac(Router router, Port routerGwPort, Uuid routerId) {
516 gwMacResolver.sendArpRequestsToExtGateways(router);
517 jobCoordinator.enqueueJob(routerId.toString(), () -> {
518 setExternalGwMac(routerGwPort, routerId);
519 return Collections.emptyList();
523 private void setExternalGwMac(Port routerGwPort, Uuid routerId) {
524 // During full-sync networking-odl syncs routers before ports. As such,
525 // the MAC of the router's gw port is not available to be set when the
526 // router is written. We catch that here.
527 InstanceIdentifier<Routers> routersId = NeutronvpnUtils.buildExtRoutersIdentifier(routerId);
528 Optional<Routers> optionalRouter = null;
530 optionalRouter = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routersId);
531 if (!optionalRouter.isPresent()) {
534 Routers extRouters = optionalRouter.get();
535 if (extRouters.getExtGwMacAddress() != null) {
539 RoutersBuilder builder = new RoutersBuilder(extRouters);
540 builder.setExtGwMacAddress(routerGwPort.getMacAddress().getValue());
541 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, routersId, builder.build());
542 } catch (ExecutionException | InterruptedException e) {
543 LOG.error("setExternalGwMac: failed to read EXT-Routers for router Id {} rout-Gw port {} due to exception",
544 routerId, routerGwPort, e);
550 private String getPortHostId(final Port port) {
552 PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
553 if (portBinding != null) {
554 return portBinding.getHostId();
561 private Hostconfig getHostConfig(final Port port) {
562 String hostId = getPortHostId(port);
563 if (hostId == null) {
566 Optional<Hostconfig> hostConfig;
568 hostConfig = this.hostConfigCache.get(hostId);
569 } catch (ReadFailedException e) {
570 LOG.error("failed to read host config from host {}", hostId, e);
573 return hostConfig.orElse(null);
576 private boolean isPortBound(final Port port) {
577 String hostId = getPortHostId(port);
578 return hostId != null && !hostId.isEmpty();
581 private boolean isPortVnicTypeDirect(Port port) {
582 PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
583 if (portBinding == null || portBinding.getVnicType() == null) {
584 // By default, VNIC_TYPE is NORMAL
587 String vnicType = portBinding.getVnicType().trim().toLowerCase(Locale.getDefault());
588 return NeutronConstants.VNIC_TYPE_DIRECT.equals(vnicType);
591 private boolean isSupportedVnicTypeByHost(final Port port, final String vnicType) {
592 Hostconfig hostConfig = getHostConfig(port);
593 String supportStr = String.format("\"vnic_type\": \"%s\"", vnicType);
594 if (hostConfig != null && hostConfig.getConfig().contains(supportStr)) {
601 private Map<String, JsonElement> unmarshal(final String profile) {
602 if (null == profile) {
605 Gson gson = new Gson();
606 JsonObject jsonObject = gson.fromJson(profile, JsonObject.class);
607 Map<String, JsonElement> map = new HashMap<>();
608 for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
609 map.put(entry.getKey(), entry.getValue());
614 private boolean isPortTypeSwitchdev(final Port port) {
615 if (!isPortVnicTypeDirect(port)) {
619 PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
620 String profile = portBinding.getProfile();
621 if (profile == null || profile.isEmpty()) {
622 LOG.debug("Port {} has no binding:profile values", port.getUuid());
626 Map<String, JsonElement> mapProfile = unmarshal(profile);
627 JsonElement capabilities = mapProfile.get(NeutronConstants.BINDING_PROFILE_CAPABILITIES);
628 LOG.debug("Port {} capabilities: {}", port.getUuid(), capabilities);
629 if (capabilities == null || !capabilities.isJsonArray()) {
630 LOG.debug("binding profile capabilities not in array format: {}", capabilities);
634 JsonArray capabilitiesArray = capabilities.getAsJsonArray();
635 Gson gson = new Gson();
636 JsonElement switchdevElement = gson.fromJson(NeutronConstants.SWITCHDEV, JsonElement.class);
637 return capabilitiesArray.contains(switchdevElement);
641 private void handleNeutronPortCreated(final Port port) {
642 final String portName = port.getUuid().getValue();
643 final Uuid portId = port.getUuid();
644 final String networkId = port.getNetworkId().getValue();
645 final Map<FixedIpsKey, FixedIps> keyFixedIpsMap = port.nonnullFixedIps();
646 if (NeutronConstants.IS_ODL_DHCP_PORT.test(port)) {
649 if (!(NeutronUtils.isPortVnicTypeNormal(port)
650 || isPortTypeSwitchdev(port)
651 && isSupportedVnicTypeByHost(port, NeutronConstants.VNIC_TYPE_DIRECT))) {
652 for (FixedIps ip: keyFixedIpsMap.values()) {
653 nvpnManager.updateSubnetmapNodeWithPorts(ip.getSubnetId(), null, portId);
655 LOG.info("Port {} is not a normal and not a direct with switchdev VNIC type ;"
656 + "OF Port interfaces are not created", portName);
659 jobCoordinator.enqueueJob("PORT- " + portName, () -> {
660 // add direct port to subnetMaps config DS
661 // TODO: for direct port as well, operations should be carried out per subnet based on port IP
663 ListenableFuture<Void> future = txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
664 LOG.info("Of-port-interface creation for port {}", portName);
665 // Create of-port interface for this neutron port
666 String portInterfaceName = createOfPortInterface(port, tx);
667 LOG.debug("Creating ELAN Interface for port {}", portName);
668 createElanInterface(port, portInterfaceName, tx);
669 Set<Uuid> vpnIdList = new HashSet<>();
670 Set<Uuid> routerIds = new HashSet<>();
671 for (FixedIps ip: keyFixedIpsMap.values()) {
672 Subnetmap subnetMap = nvpnManager.updateSubnetmapNodeWithPorts(ip.getSubnetId(), portId, null);
673 if (subnetMap != null && subnetMap.getInternetVpnId() != null) {
674 if (!vpnIdList.contains(subnetMap.getInternetVpnId())) {
675 vpnIdList.add(subnetMap.getInternetVpnId());
678 if (subnetMap != null && subnetMap.getVpnId() != null) {
679 // can't use NeutronvpnUtils.getVpnForNetwork to optimise here, because it gives BGPVPN id
680 // obtained subnetMaps belongs to one network => vpnId must be the same for each port Ip
681 Uuid vpnId = subnetMap.getVpnId();
683 vpnIdList.add(vpnId);
686 if (subnetMap != null && subnetMap.getRouterId() != null) {
687 routerIds.add(subnetMap.getRouterId());
690 if (!vpnIdList.isEmpty()) {
691 // create new vpn-interface for neutron port
692 LOG.debug("handleNeutronPortCreated: Adding VPN Interface for port {} from network {}", portName,
694 nvpnManager.createVpnInterface(vpnIdList, port, tx);
695 for (Uuid routerId : routerIds) {
696 nvpnManager.addToNeutronRouterInterfacesMap(routerId,port.getUuid().getValue());
700 ListenableFutures.addErrorLogging(future, LOG,
701 "handleNeutronPortCreated: Failed for port {} with networkId {}", portName, networkId);
702 return Collections.singletonList(future);
706 private void handleNeutronPortDeleted(final Port port) {
707 final String portName = port.getUuid().getValue();
708 final Uuid portId = port.getUuid();
709 final Map<FixedIpsKey, FixedIps> keyFixedIpsMap = port.nonnullFixedIps();
710 if (!(NeutronUtils.isPortVnicTypeNormal(port) || isPortTypeSwitchdev(port))) {
711 for (FixedIps ip : keyFixedIpsMap.values()) {
712 // remove direct port from subnetMaps config DS
713 // TODO: for direct port as well, operations should be carried out per subnet based on port IP
714 nvpnManager.removePortsFromSubnetmapNode(ip.getSubnetId(), null, portId);
716 LOG.info("Port {} is not a normal and not a direct with switchdev VNIC type ;"
717 + "Skipping OF Port interfaces removal", portName);
720 jobCoordinator.enqueueJob("PORT- " + portName, () -> {
721 ListenableFuture<Void> future = txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
724 Set<Uuid> routerIds = new HashSet<>();
725 Uuid internetVpnId = null;
726 for (FixedIps ip : keyFixedIpsMap.values()) {
727 Subnetmap subnetMap = nvpnManager.removePortsFromSubnetmapNode(ip.getSubnetId(), portId, null);
728 if (subnetMap == null) {
731 if (subnetMap.getVpnId() != null) {
732 // can't use NeutronvpnUtils.getVpnForNetwork to optimise here, because it gives BGPVPN id
733 // obtained subnetMaps belongs to one network => vpnId must be the same for each port Ip
734 vpnId = subnetMap.getVpnId();
736 if (subnetMap.getRouterId() != null) {
737 routerIds.add(subnetMap.getRouterId());
739 internetVpnId = subnetMap.getInternetVpnId();
741 if (NeutronConstants.DEVICE_OWNER_GATEWAY_INF.equals(port.getDeviceOwner())
742 || NeutronConstants.DEVICE_OWNER_FLOATING_IP.equals(port.getDeviceOwner())) {
743 String ipAddress = ip.getIpAddress().stringValue();
745 neutronvpnUtils.removeVpnPortFixedIpToPort(vpnId.getValue(), ipAddress, confTx);
747 if (internetVpnId != null) {
748 neutronvpnUtils.removeVpnPortFixedIpToPort(internetVpnId.getValue(),
753 if (vpnId != null || internetVpnId != null) {
754 // remove vpn-interface for this neutron port
755 LOG.debug("removing VPN Interface for port {}", portName);
756 if (!routerIds.isEmpty()) {
757 for (Uuid routerId : routerIds) {
758 nvpnManager.removeFromNeutronRouterInterfacesMap(routerId, portName);
761 nvpnManager.deleteVpnInterface(portName, null /* vpn-id */, confTx);
763 // Remove of-port interface for this neutron port
764 // ELAN interface is also implicitly deleted as part of this operation
765 LOG.debug("Of-port-interface removal for port {}", portName);
766 deleteOfPortInterface(port, confTx);
767 //dissociate fixedIP from floatingIP if associated
768 nvpnManager.dissociatefixedIPFromFloatingIP(port.getUuid().getValue());
770 ListenableFutures.addErrorLogging(future, LOG,
771 "handleNeutronPortDeleted: Failed to update interface {} with networkId", portName,
772 port.getNetworkId().getValue());
773 return Collections.singletonList(future);
778 private void handleNeutronPortUpdated(final Port portoriginal, final Port portupdate) {
779 final Map<FixedIpsKey, FixedIps> portoriginalIpsMap = portoriginal.nonnullFixedIps();
780 final Map<FixedIpsKey, FixedIps> portupdateIpsMap = portupdate.nonnullFixedIps();
781 if (portoriginalIpsMap == null || portoriginalIpsMap.isEmpty()) {
782 handleNeutronPortCreated(portupdate);
786 if (portupdateIpsMap == null || portupdateIpsMap.isEmpty()) {
787 LOG.info("Ignoring portUpdate (fixed_ip removal) for port {} as this case is handled "
788 + "during subnet deletion event.", portupdate.getUuid().getValue());
792 if (NeutronConstants.IS_ODL_DHCP_PORT.test(portupdate)) {
796 jobCoordinator.enqueueJob("PORT- " + portupdate.getUuid().getValue(),
797 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
798 final List<Uuid> originalSnMapsIds = portoriginalIpsMap.values().stream().map(FixedIps::getSubnetId)
799 .collect(Collectors.toList());
800 final List<Uuid> updateSnMapsIds = portupdateIpsMap.values().stream().map(FixedIps::getSubnetId)
801 .collect(Collectors.toList());
802 Set<Uuid> originalRouterIds = new HashSet<>();
803 Set<Uuid> oldVpnIds = new HashSet<>();
804 for (Uuid snId: originalSnMapsIds) {
805 if (!updateSnMapsIds.remove(snId)) {
806 // snId was present in originalSnMapsIds, but not in updateSnMapsIds
807 Subnetmap subnetMapOld = nvpnManager.removePortsFromSubnetmapNode(snId, portoriginal.getUuid(),
809 if (subnetMapOld != null && subnetMapOld.getVpnId() != null) {
810 oldVpnIds.add(subnetMapOld.getVpnId());
812 if (subnetMapOld != null && subnetMapOld.getInternetVpnId() != null) {
813 oldVpnIds.add(subnetMapOld.getInternetVpnId());
815 if (subnetMapOld != null && subnetMapOld.getRouterId() != null) {
816 originalRouterIds.add(subnetMapOld.getRouterId());
820 Set<Uuid> newVpnIds = new HashSet<>();
821 Set<Uuid> newRouterIds = new HashSet<>();
822 for (Uuid snId: updateSnMapsIds) {
823 Subnetmap subnetMapNew = nvpnManager.updateSubnetmapNodeWithPorts(snId, portupdate.getUuid(), null);
824 if (subnetMapNew != null) {
825 if (subnetMapNew.getVpnId() != null) {
826 newVpnIds.add(subnetMapNew.getVpnId());
828 if (subnetMapNew.getInternetVpnId() != null) {
829 newVpnIds.add(subnetMapNew.getInternetVpnId());
831 if (subnetMapNew.getRouterId() != null) {
832 newRouterIds.add(subnetMapNew.getRouterId());
836 if (!oldVpnIds.isEmpty()) {
837 LOG.info("removing VPN Interface for port {}", portoriginal.getUuid().getValue());
838 if (!originalRouterIds.isEmpty()) {
839 for (Uuid routerId : originalRouterIds) {
840 nvpnManager.removeFromNeutronRouterInterfacesMap(routerId,
841 portoriginal.getUuid().getValue());
844 nvpnManager.deleteVpnInterface(portoriginal.getUuid().getValue(),
845 null /* vpn-id */, confTx);
847 if (!newVpnIds.isEmpty()) {
848 LOG.info("Adding VPN Interface for port {}", portupdate.getUuid().getValue());
849 nvpnManager.createVpnInterface(newVpnIds, portupdate, confTx);
850 if (!newRouterIds.isEmpty()) {
851 for (Uuid routerId : newRouterIds) {
852 nvpnManager.addToNeutronRouterInterfacesMap(routerId,portupdate.getUuid().getValue());
860 private InterfaceAclBuilder handlePortSecurityUpdated(Port portOriginal,
861 Port portUpdated, boolean origSecurityEnabled, boolean updatedSecurityEnabled,
862 InterfaceBuilder interfaceBuilder) {
863 InterfaceAclBuilder interfaceAclBuilder = null;
864 if (origSecurityEnabled != updatedSecurityEnabled) {
865 interfaceAclBuilder = new InterfaceAclBuilder();
866 interfaceAclBuilder.setPortSecurityEnabled(updatedSecurityEnabled);
867 if (updatedSecurityEnabled) {
868 // Handle security group enabled
869 neutronvpnUtils.populateInterfaceAclBuilder(interfaceAclBuilder, portUpdated);
871 // Handle security group disabled
872 interfaceAclBuilder.setSecurityGroups(new ArrayList<>());
873 interfaceAclBuilder.setAllowedAddressPairs(new ArrayList<>());
874 interfaceAclBuilder.setSubnetInfo(new ArrayList<>());
877 if (updatedSecurityEnabled) {
878 // handle SG add/delete delta
879 InterfaceAcl interfaceAcl = interfaceBuilder.augmentation(InterfaceAcl.class);
880 interfaceAclBuilder = new InterfaceAclBuilder(interfaceAcl);
881 interfaceAclBuilder.setSecurityGroups(
882 NeutronvpnUtils.getUpdatedSecurityGroups(interfaceAcl.getSecurityGroups(),
883 portOriginal.getSecurityGroups(), portUpdated.getSecurityGroups()));
884 List<AllowedAddressPairs> updatedAddressPairs = NeutronvpnUtils.getUpdatedAllowedAddressPairs(
885 new ArrayList<AllowedAddressPairs>(interfaceAcl.nonnullAllowedAddressPairs().values()),
886 new ArrayList<>(portOriginal.nonnullAllowedAddressPairs().values()),
887 new ArrayList<org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port
888 .attributes.AllowedAddressPairs>(portUpdated.nonnullAllowedAddressPairs().values()));
889 interfaceAclBuilder.setAllowedAddressPairs(NeutronvpnUtils.getAllowedAddressPairsForFixedIps(
890 updatedAddressPairs, portOriginal.getMacAddress(), portOriginal.getFixedIps(),
891 portUpdated.nonnullFixedIps().values()));
893 if (portOriginal.getFixedIps() != null
894 && !portOriginal.getFixedIps().equals(portUpdated.getFixedIps())) {
895 neutronvpnUtils.populateSubnetInfo(interfaceAclBuilder, portUpdated);
899 return interfaceAclBuilder;
902 private String createOfPortInterface(Port port, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
903 Interface inf = createInterface(port);
904 String infName = inf.getName();
906 InstanceIdentifier<Interface> interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(infName);
908 Optional<Interface> optionalInf =
909 SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
910 interfaceIdentifier);
911 if (!optionalInf.isPresent()) {
912 wrtConfigTxn.put(interfaceIdentifier, inf);
913 } else if (isInterfaceUpdated(inf, optionalInf.get())) {
915 Case where an update DTCN wasn't received by this class due to node going down
916 upon cluster reboot or any other unknown reason
917 In such a case, updates contained in the missed DTCN won't be processed and have to be handled
919 Update of subports (vlanId, splithorizon tag) is handled here
920 Update of portSecurity (PortSecurityEnabled, SecurityGroups, AllowedAddressPairs) add is handled
921 Update of portSecurity update/removed is not handled
922 Update of parentrefs is not handled as parentrefs updation is handled by IFM Oxygen onwards
924 wrtConfigTxn.put(interfaceIdentifier, inf);
925 LOG.error("Interface {} is already present and is updated", infName);
927 LOG.warn("Interface {} is already present", infName);
929 } catch (ExecutionException | InterruptedException e) {
930 LOG.error("failed to create interface {}", infName, e);
935 // Not for generic use. For a special case where update DTCN isn't received
936 private static boolean isInterfaceUpdated(Interface newInterface, Interface oldInterface) {
937 if (newInterface.augmentation(SplitHorizon.class) != null) {
938 if (oldInterface.augmentation(SplitHorizon.class) == null) {
941 if (!newInterface.augmentation(SplitHorizon.class).equals(oldInterface
942 .augmentation(SplitHorizon.class))) {
946 if (!newInterface.augmentation(IfL2vlan.class).equals(oldInterface.augmentation(IfL2vlan.class))) {
949 if (newInterface.augmentation(InterfaceAcl.class) != null && oldInterface
950 .augmentation(InterfaceAcl.class) == null) {
956 private Interface createInterface(Port port) {
957 String interfaceName = port.getUuid().getValue();
958 IfL2vlan.L2vlanMode l2VlanMode = IfL2vlan.L2vlanMode.Trunk;
959 InterfaceBuilder interfaceBuilder = new InterfaceBuilder();
960 IfL2vlanBuilder ifL2vlanBuilder = new IfL2vlanBuilder();
962 Network network = neutronvpnUtils.getNeutronNetwork(port.getNetworkId());
963 Boolean isVlanTransparent = network.isVlanTransparent();
964 if (isVlanTransparent != null && isVlanTransparent) {
965 l2VlanMode = IfL2vlan.L2vlanMode.Transparent;
967 PortIdToSubport portIdToSubport = neutronvpnUtils.getPortIdToSubport(port.getUuid());
968 if (portIdToSubport != null) {
969 l2VlanMode = IfL2vlan.L2vlanMode.TrunkMember;
970 ifL2vlanBuilder.setVlanId(new VlanId(portIdToSubport.getVlanId().intValue()));
971 String parentRefName = portIdToSubport.getTrunkPortId().getValue();
972 ParentRefsBuilder parentRefsBuilder = new ParentRefsBuilder().setParentInterface(parentRefName);
973 interfaceBuilder.addAugmentation(ParentRefs.class, parentRefsBuilder.build());
974 SplitHorizon splitHorizon =
975 new SplitHorizonBuilder().setOverrideSplitHorizonProtection(true).build();
976 interfaceBuilder.addAugmentation(SplitHorizon.class, splitHorizon);
980 ifL2vlanBuilder.setL2vlanMode(l2VlanMode);
982 interfaceBuilder.setEnabled(true).setName(interfaceName).setType(L2vlan.class)
983 .addAugmentation(IfL2vlan.class, ifL2vlanBuilder.build());
985 if (NeutronvpnUtils.getPortSecurityEnabled(port)) {
986 InterfaceAclBuilder interfaceAclBuilder = new InterfaceAclBuilder();
987 interfaceAclBuilder.setPortSecurityEnabled(true);
988 neutronvpnUtils.populateInterfaceAclBuilder(interfaceAclBuilder, port);
989 interfaceBuilder.addAugmentation(InterfaceAcl.class, interfaceAclBuilder.build());
990 } else if (neutronvpnConfig.isLimitBumtrafficToDhcpserver() && NeutronvpnUtils.isDhcpServerPort(port)) {
991 interfaceBuilder.addAugmentation(InterfaceAcl.class, neutronvpnUtils.getDhcpInterfaceAcl(port));
993 return interfaceBuilder.build();
996 private void deleteOfPortInterface(Port port, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
997 String name = port.getUuid().getValue();
998 LOG.debug("Removing OFPort Interface {}", name);
999 InstanceIdentifier<Interface> interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(name);
1001 Optional<Interface> optionalInf =
1002 SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
1003 interfaceIdentifier);
1004 if (optionalInf.isPresent()) {
1005 wrtConfigTxn.delete(interfaceIdentifier);
1007 LOG.warn("deleteOfPortInterface: Interface {} is not present", name);
1009 } catch (ExecutionException | InterruptedException e) {
1010 LOG.error("deleteOfPortInterface: Failed to delete interface {}", name, e);
1014 private void createElanInterface(Port port, String name,
1015 TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
1016 String elanInstanceName = port.getNetworkId().getValue();
1017 List<StaticMacEntries> staticMacEntries = NeutronvpnUtils.buildStaticMacEntry(port);
1019 InstanceIdentifier<ElanInterface> id = InstanceIdentifier.builder(ElanInterfaces.class).child(ElanInterface
1020 .class, new ElanInterfaceKey(name)).build();
1021 ElanInterface elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName)
1022 .setName(name).setStaticMacEntries(staticMacEntries).withKey(new ElanInterfaceKey(name)).build();
1023 wrtConfigTxn.put(id, elanInterface);
1024 LOG.debug("Creating new ELan Interface {}", elanInterface);
1027 private void deleteElanInterface(String name, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
1028 InstanceIdentifier<ElanInterface> id = InstanceIdentifier.builder(ElanInterfaces.class).child(ElanInterface
1029 .class, new ElanInterfaceKey(name)).build();
1030 wrtConfigTxn.delete(id);
1033 // TODO Clean up the exception handling
1034 @SuppressWarnings("checkstyle:IllegalCatch")
1035 private void addToFloatingIpPortInfo(Uuid floatingIpId, Uuid floatingIpPortId, Uuid floatingIpPortSubnetId, String
1036 floatingIpPortMacAddress) {
1037 InstanceIdentifier id = NeutronvpnUtils.buildfloatingIpIdToPortMappingIdentifier(floatingIpId);
1039 FloatingIpIdToPortMappingBuilder floatingipIdToPortMacMappingBuilder = new
1040 FloatingIpIdToPortMappingBuilder().withKey(new FloatingIpIdToPortMappingKey(floatingIpId))
1041 .setFloatingIpId(floatingIpId).setFloatingIpPortId(floatingIpPortId)
1042 .setFloatingIpPortSubnetId(floatingIpPortSubnetId)
1043 .setFloatingIpPortMacAddress(floatingIpPortMacAddress);
1044 LOG.debug("Creating floating IP UUID {} to Floating IP neutron port {} mapping in Floating IP"
1045 + " Port Info Config DS", floatingIpId.getValue(), floatingIpPortId.getValue());
1046 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id,
1047 floatingipIdToPortMacMappingBuilder.build());
1048 } catch (Exception e) {
1049 LOG.error("Creating floating IP UUID {} to Floating IP neutron port {} mapping in Floating IP"
1050 + " Port Info Config DS failed", floatingIpId.getValue(), floatingIpPortId.getValue(), e);
1054 private Set<FixedIps> getFixedIpSet(List<FixedIps> fixedIps) {
1055 return fixedIps != null ? new HashSet<>(fixedIps) : Collections.emptySet();