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.ParentRefs;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefsBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.SplitHorizon;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.SplitHorizonBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.l2.types.rev130827.VlanId;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.InterfaceAcl;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.InterfaceAclBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.aclservice.rev160608.interfaces._interface.AllowedAddressPairs;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.ElanInterfaces;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterface;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.ElanInterfaceKey;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.rev150602.elan.interfaces.elan._interface.StaticMacEntries;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.Routers;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ext.routers.RoutersBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.port.info.FloatingIpIdToPortMappingBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.port.info.FloatingIpIdToPortMappingKey;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.config.rev160806.NeutronvpnConfig;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.neutron.vpn.port.id.subport.data.PortIdToSubport;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.binding.rev150712.PortBindingExtension;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.hostconfig.rev150712.hostconfig.attributes.hostconfigs.Hostconfig;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIpsKey;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
89 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
90 import org.slf4j.Logger;
91 import org.slf4j.LoggerFactory;
94 public class NeutronPortChangeListener extends AbstractAsyncDataTreeChangeListener<Port> {
95 private static final Logger LOG = LoggerFactory.getLogger(NeutronPortChangeListener.class);
96 private final DataBroker dataBroker;
97 private final ManagedNewTransactionRunner txRunner;
98 private final NeutronvpnManager nvpnManager;
99 private final NeutronvpnNatManager nvpnNatManager;
100 private final NeutronSubnetGwMacResolver gwMacResolver;
101 private final IElanService elanService;
102 private final JobCoordinator jobCoordinator;
103 private final NeutronvpnUtils neutronvpnUtils;
104 private final HostConfigCache hostConfigCache;
105 private final DataTreeEventCallbackRegistrar eventCallbacks;
106 private final NeutronvpnConfig neutronvpnConfig;
109 public NeutronPortChangeListener(final DataBroker dataBroker,
110 final NeutronvpnManager neutronvpnManager,
111 final NeutronvpnNatManager neutronvpnNatManager,
112 final NeutronSubnetGwMacResolver gwMacResolver,
113 final IElanService elanService,
114 final JobCoordinator jobCoordinator,
115 final NeutronvpnUtils neutronvpnUtils,
116 final HostConfigCache hostConfigCache,
117 final DataTreeEventCallbackRegistrar dataTreeEventCallbackRegistrar,
118 final NeutronvpnConfig neutronvpnConfig) {
119 super(dataBroker, LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(Neutron.class)
120 .child(Ports.class).child(Port.class),
121 Executors.newSingleThreadExecutor("NeutronPortChangeListener", LOG));
122 this.dataBroker = dataBroker;
123 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
124 nvpnManager = neutronvpnManager;
125 nvpnNatManager = neutronvpnNatManager;
126 this.gwMacResolver = gwMacResolver;
127 this.elanService = elanService;
128 this.jobCoordinator = jobCoordinator;
129 this.neutronvpnUtils = neutronvpnUtils;
130 this.hostConfigCache = hostConfigCache;
131 this.eventCallbacks = dataTreeEventCallbackRegistrar;
132 this.neutronvpnConfig = neutronvpnConfig;
137 LOG.info("{} init", getClass().getSimpleName());
142 public void close() {
144 Executors.shutdownAndAwaitTermination(getExecutorService());
148 public void add(InstanceIdentifier<Port> identifier, Port input) {
149 LOG.trace("Received port add event: port={}", input);
150 String portName = input.getUuid().getValue();
151 LOG.trace("Adding Port : key: {}, value={}", identifier, input);
152 Network network = neutronvpnUtils.getNeutronNetwork(input.getNetworkId());
153 if (network == null || !NeutronvpnUtils.isNetworkTypeSupported(network)) {
154 LOG.warn("neutron vpn received a port add() for a network without a provider extension augmentation "
155 + "or with an unsupported network type for the port {} which is part of network {}",
160 neutronvpnUtils.addToPortCache(input);
161 String portStatus = NeutronUtils.PORT_STATUS_DOWN;
162 if (!Strings.isNullOrEmpty(input.getDeviceOwner()) && !Strings.isNullOrEmpty(input.getDeviceId())) {
163 if (NeutronConstants.DEVICE_OWNER_ROUTER_INF.equals(input.getDeviceOwner())) {
164 handleRouterInterfaceAdded(input);
165 NeutronUtils.createPortStatus(input.getUuid().getValue(), NeutronUtils.PORT_STATUS_ACTIVE, dataBroker);
168 if (NeutronConstants.DEVICE_OWNER_GATEWAY_INF.equals(input.getDeviceOwner())) {
169 handleRouterGatewayUpdated(input, false);
170 portStatus = NeutronUtils.PORT_STATUS_ACTIVE;
171 } else if (NeutronConstants.DEVICE_OWNER_FLOATING_IP.equals(input.getDeviceOwner())) {
172 handleFloatingIpPortUpdated(null, input);
173 portStatus = NeutronUtils.PORT_STATUS_ACTIVE;
176 // Switchdev ports need to be bounded to a host before creation
177 // in order to validate the supported vnic types from the hostconfig
178 if (input.getFixedIps() != null
179 && !input.getFixedIps().isEmpty()
180 && !(isPortTypeSwitchdev(input) && !isPortBound(input))) {
181 handleNeutronPortCreated(input);
183 NeutronUtils.createPortStatus(input.getUuid().getValue(), portStatus, dataBroker);
187 public void remove(InstanceIdentifier<Port> identifier, Port input) {
188 LOG.trace("Removing Port : key: {}, value={}", identifier, input);
189 Network network = neutronvpnUtils.getNeutronNetwork(input.getNetworkId());
190 // need to proceed with deletion in case network is null for a case where v2 sync happens and a read for
191 // network from NN returns null, but the deletion process for port needs to continue
192 if (network != null && !NeutronvpnUtils.isNetworkTypeSupported(network)) {
193 String portName = input.getUuid().getValue();
194 LOG.warn("neutron vpn received a port remove() for a network without a provider extension augmentation "
195 + "or with an unsupported network type for the port {} which is part of network {}",
199 neutronvpnUtils.removeFromPortCache(input);
200 NeutronUtils.deletePortStatus(input.getUuid().getValue(), dataBroker);
202 if (!Strings.isNullOrEmpty(input.getDeviceOwner()) && !Strings.isNullOrEmpty(input.getDeviceId())) {
203 if (NeutronConstants.DEVICE_OWNER_ROUTER_INF.equals(input.getDeviceOwner())) {
204 handleRouterInterfaceRemoved(input);
205 /* nothing else to do here */
207 } else if (NeutronConstants.DEVICE_OWNER_GATEWAY_INF.equals(input.getDeviceOwner())
208 || NeutronConstants.DEVICE_OWNER_FLOATING_IP.equals(input.getDeviceOwner())) {
209 handleRouterGatewayUpdated(input, true);
210 elanService.removeKnownL3DmacAddress(input.getMacAddress().getValue(), input.getNetworkId().getValue());
213 if (input.getFixedIps() != null) {
214 handleNeutronPortDeleted(input);
219 public void update(InstanceIdentifier<Port> identifier, Port original, Port update) {
220 LOG.trace("Received port update event: original={}, update={}", original, update);
221 if (Objects.equals(original, update)) {
224 // Switchdev ports need to be bounded to a host before creation
225 // in order to validate the supported vnic types from the hostconfig
226 if (isPortTypeSwitchdev(original)
227 && !isPortBound(original)
228 && isPortBound(update)) {
229 handleNeutronPortCreated(update);
231 final String portName = update.getUuid().getValue();
232 Network network = neutronvpnUtils.getNeutronNetwork(update.getNetworkId());
233 if (network == null || !NeutronvpnUtils.isNetworkTypeSupported(network)) {
234 LOG.warn("neutron vpn received a port update() for a network without a provider extension augmentation "
235 + "or with an unsupported network type for the port {} which is part of network {}",
239 neutronvpnUtils.addToPortCache(update);
241 if ((Strings.isNullOrEmpty(original.getDeviceOwner()) || Strings.isNullOrEmpty(original.getDeviceId())
242 || NeutronConstants.FLOATING_IP_DEVICE_ID_PENDING.equalsIgnoreCase(original.getDeviceId()))
243 && !Strings.isNullOrEmpty(update.getDeviceOwner()) && !Strings.isNullOrEmpty(update.getDeviceId())) {
244 if (NeutronConstants.DEVICE_OWNER_ROUTER_INF.equals(update.getDeviceOwner())) {
245 handleRouterInterfaceAdded(update);
248 if (NeutronConstants.DEVICE_OWNER_GATEWAY_INF.equals(update.getDeviceOwner())) {
249 handleRouterGatewayUpdated(update, false);
250 } else if (NeutronConstants.DEVICE_OWNER_FLOATING_IP.equals(update.getDeviceOwner())) {
251 handleFloatingIpPortUpdated(original, update);
254 Set<FixedIps> oldIPs = getFixedIpSet(new ArrayList<FixedIps>(original.nonnullFixedIps().values()));
255 Set<FixedIps> newIPs = getFixedIpSet(new ArrayList<FixedIps>(update.nonnullFixedIps().values()));
256 if (!oldIPs.equals(newIPs)) {
257 handleNeutronPortUpdated(original, update);
261 // check if port security enabled/disabled as part of port update
262 boolean origSecurityEnabled = NeutronvpnUtils.getPortSecurityEnabled(original);
263 boolean updatedSecurityEnabled = NeutronvpnUtils.getPortSecurityEnabled(update);
264 boolean isDhcpServerPort = neutronvpnConfig.isLimitBumtrafficToDhcpserver()
265 && NeutronvpnUtils.isDhcpServerPort(update);
266 if (origSecurityEnabled || updatedSecurityEnabled || isDhcpServerPort) {
267 InstanceIdentifier<Interface> interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(portName);
268 jobCoordinator.enqueueJob("PORT- " + portName, () -> {
269 ListenableFuture<?> future = txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
271 Optional<Interface> optionalInf = confTx.read(interfaceIdentifier).get();
272 if (optionalInf.isPresent()) {
273 InterfaceBuilder interfaceBuilder = new InterfaceBuilder(optionalInf.get());
274 if (origSecurityEnabled || updatedSecurityEnabled) {
275 InterfaceAcl infAcl = handlePortSecurityUpdated(original, update, origSecurityEnabled,
276 updatedSecurityEnabled, interfaceBuilder).build();
277 interfaceBuilder.addAugmentation(InterfaceAcl.class, infAcl);
278 } else if (isDhcpServerPort) {
279 Set<FixedIps> oldIPs = getFixedIpSet(
280 new ArrayList<FixedIps>(original.nonnullFixedIps().values()));
281 Set<FixedIps> newIPs = getFixedIpSet(
282 new ArrayList<FixedIps>(update.nonnullFixedIps().values()));
283 if (!oldIPs.equals(newIPs)) {
284 InterfaceAcl infAcl = neutronvpnUtils.getDhcpInterfaceAcl(update);
285 interfaceBuilder.addAugmentation(InterfaceAcl.class, infAcl);
288 LOG.info("update: Of-port-interface updation for port {}", portName);
289 // Update OFPort interface for this neutron port
290 confTx.put(interfaceIdentifier, interfaceBuilder.build());
292 LOG.warn("update: Interface {} is not present", portName);
295 LoggingFutures.addErrorLogging(future, LOG,
296 "update: Failed to update interface {} with networkId {}", portName, network);
297 return Collections.singletonList(future);
302 private void handleFloatingIpPortUpdated(@Nullable Port original, Port update) {
303 if ((original == null || NeutronConstants.FLOATING_IP_DEVICE_ID_PENDING.equals(original.getDeviceId()))
304 && !NeutronConstants.FLOATING_IP_DEVICE_ID_PENDING.equals(update.getDeviceId())) {
305 // populate floating-ip uuid and floating-ip port attributes (uuid, mac and subnet id for the ONLY
306 // fixed IP) to be used by NAT, depopulated in NATService once mac is retrieved in the removal path
307 addToFloatingIpPortInfo(new Uuid(update.getDeviceId()), update.getUuid(),
308 new ArrayList<FixedIps>(update.nonnullFixedIps().values()).get(0)
309 .getSubnetId(), update.getMacAddress().getValue());
310 elanService.addKnownL3DmacAddress(update.getMacAddress().getValue(), update.getNetworkId().getValue());
314 private void handleRouterInterfaceAdded(Port routerPort) {
315 if (routerPort.getDeviceId() != null) {
316 Uuid routerId = new Uuid(routerPort.getDeviceId());
317 Uuid infNetworkId = routerPort.getNetworkId();
318 Uuid existingVpnId = neutronvpnUtils.getVpnForNetwork(infNetworkId);
320 elanService.addKnownL3DmacAddress(routerPort.getMacAddress().getValue(), infNetworkId.getValue());
321 if (existingVpnId == null) {
322 Set<Uuid> listVpnIds = new HashSet<>();
323 Uuid vpnId = neutronvpnUtils.getVpnForRouter(routerId, true);
327 listVpnIds.add(vpnId);
328 Uuid internetVpnId = neutronvpnUtils.getInternetvpnUuidBoundToRouterId(routerId);
329 List<Subnetmap> subnetMapList = new ArrayList<>();
330 boolean portIsIpv6 = false;
331 for (FixedIps portIP : routerPort.nonnullFixedIps().values()) {
332 // NOTE: Please donot change the order of calls to updateSubnetNodeWithFixedIP
333 // and addSubnetToVpn here
334 if (internetVpnId != null
335 && portIP.getIpAddress().getIpv6Address() != null) {
338 String ipValue = portIP.getIpAddress().stringValue();
339 Uuid subnetId = portIP.getSubnetId();
340 nvpnManager.updateSubnetNodeWithFixedIp(subnetId, routerId,
341 routerPort.getUuid(), ipValue, routerPort.getMacAddress().getValue(), vpnId);
342 Subnetmap sn = neutronvpnUtils.getSubnetmap(subnetId);
343 subnetMapList.add(sn);
346 listVpnIds.add(internetVpnId);
347 if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(
348 IpVersionChoice.IPV6, routerId, true)) {
349 neutronvpnUtils.updateVpnInstanceWithIpFamily(internetVpnId.getValue(), IpVersionChoice.IPV6,
351 neutronvpnUtils.updateVpnInstanceWithFallback(routerId, internetVpnId, true);
354 if (! subnetMapList.isEmpty()) {
355 nvpnManager.createVpnInterface(listVpnIds, routerPort, null);
357 IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
358 for (FixedIps portIP : routerPort.nonnullFixedIps().values()) {
359 String ipValue = portIP.getIpAddress().stringValue();
360 ipVersion = NeutronvpnUtils.getIpVersionFromString(ipValue);
361 if (ipVersion.isIpVersionChosen(IpVersionChoice.IPV4)) {
362 nvpnManager.addSubnetToVpn(vpnId, portIP.getSubnetId(),
363 null /* internet-vpn-id */);
365 nvpnManager.addSubnetToVpn(vpnId, portIP.getSubnetId(), internetVpnId);
367 LOG.trace("NeutronPortChangeListener Add Subnet Gateway IP {} MAC {} Interface {} VPN {}",
368 ipValue, routerPort.getMacAddress(),
369 routerPort.getUuid().getValue(), vpnId.getValue());
371 if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(ipVersion, routerId, true)) {
372 LOG.debug("vpnInstanceOpDataEntry is getting update with ip address family {} for VPN {}",
373 ipVersion, vpnId.getValue());
374 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, true);
376 nvpnManager.addToNeutronRouterInterfacesMap(routerId, routerPort.getUuid().getValue());
377 jobCoordinator.enqueueJob(routerId.toString(), () -> {
378 nvpnNatManager.handleSubnetsForExternalRouter(routerId);
379 return Collections.emptyList();
381 LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
383 String portInterfaceName = createOfPortInterface(routerPort, confTx);
384 createElanInterface(routerPort, portInterfaceName, confTx);
385 }), LOG, "Error creating ELAN interface for {}", routerPort);
387 LOG.error("Neutron network {} corresponding to router interface port {} for neutron router {}"
388 + " already associated to VPN {}", infNetworkId.getValue(), routerPort.getUuid().getValue(),
389 routerId.getValue(), existingVpnId.getValue());
394 private void handleRouterInterfaceRemoved(Port routerPort) {
395 if (routerPort.getDeviceId() != null) {
396 Uuid routerId = new Uuid(routerPort.getDeviceId());
397 Uuid infNetworkId = routerPort.getNetworkId();
398 elanService.removeKnownL3DmacAddress(routerPort.getMacAddress().getValue(), infNetworkId.getValue());
399 Uuid vpnId = ObjectUtils.defaultIfNull(neutronvpnUtils.getVpnForRouter(routerId, true),
401 Map<FixedIpsKey, FixedIps> keyFixedIpsMap = routerPort.nonnullFixedIps();
402 boolean vpnInstanceInternetIpVersionRemoved = false;
403 Uuid vpnInstanceInternetUuid = null;
404 for (FixedIps portIP : keyFixedIpsMap.values()) {
405 // Internet VPN : flush InternetVPN first
406 Uuid subnetId = portIP.getSubnetId();
407 Subnetmap sn = neutronvpnUtils.getSubnetmap(subnetId);
408 if (sn != null && sn.getInternetVpnId() != null) {
409 if (neutronvpnUtils.shouldVpnHandleIpVersionChangeToRemove(sn, sn.getInternetVpnId())) {
410 vpnInstanceInternetIpVersionRemoved = true;
411 vpnInstanceInternetUuid = sn.getInternetVpnId();
413 nvpnManager.updateVpnInternetForSubnet(sn, sn.getInternetVpnId(), false);
416 /* Remove ping responder for router interfaces
417 * A router interface reference in a VPN will have to be removed before the host interface references
418 * for that subnet in the VPN are removed. This is to ensure that the FIB Entry of the router interface
419 * is not the last entry to be removed for that subnet in the VPN.
420 * If router interface FIB entry is the last to be removed for a subnet in a VPN , then all the host
421 * interface references in the vpn will already have been cleared, which will cause failures in
422 * cleanup of router interface flows*/
423 nvpnManager.deleteVpnInterface(routerPort.getUuid().getValue(),
424 null /* vpn-id */, null /* wrtConfigTxn*/);
425 // update RouterInterfaces map
426 LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
428 IpVersionChoice ipVersion = IpVersionChoice.UNDEFINED;
429 for (FixedIps portIP : keyFixedIpsMap.values()) {
430 Subnetmap sn = neutronvpnUtils.getSubnetmap(portIP.getSubnetId());
432 LOG.error("Subnetmap for subnet {} not found", portIP.getSubnetId().getValue());
435 // router Port have either IPv4 or IPv6, never both
436 ipVersion = neutronvpnUtils.getIpVersionFromString(sn.getSubnetIp());
437 String ipValue = portIP.getIpAddress().stringValue();
438 neutronvpnUtils.removeVpnPortFixedIpToPort(vpnId.getValue(), ipValue, confTx);
439 // NOTE: Please donot change the order of calls to removeSubnetFromVpn and
440 // and updateSubnetNodeWithFixedIP
441 nvpnManager.removeSubnetFromVpn(vpnId, sn, sn.getInternetVpnId());
442 nvpnManager.updateSubnetNodeWithFixedIp(portIP.getSubnetId(), null, null,
445 nvpnManager.removeFromNeutronRouterInterfacesMap(routerId, routerPort.getUuid().getValue());
446 deleteElanInterface(routerPort.getUuid().getValue(), confTx);
447 deleteOfPortInterface(routerPort, confTx);
448 jobCoordinator.enqueueJob(routerId.toString(), () -> {
449 nvpnNatManager.handleSubnetsForExternalRouter(routerId);
450 return Collections.emptyList();
452 if (neutronvpnUtils.shouldVpnHandleIpVersionChoiceChange(ipVersion, routerId, false)) {
453 LOG.debug("vpnInstanceOpDataEntry is getting update with ip address family {} for VPN {}",
454 ipVersion, vpnId.getValue());
455 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnId.getValue(), ipVersion, false);
457 }), LOG, "Error handling interface removal");
458 if (vpnInstanceInternetIpVersionRemoved) {
459 neutronvpnUtils.updateVpnInstanceWithIpFamily(vpnInstanceInternetUuid.getValue(),
460 IpVersionChoice.IPV6, false);
461 neutronvpnUtils.updateVpnInstanceWithFallback(routerId, vpnInstanceInternetUuid, false);
466 private void handleRouterGatewayUpdated(Port routerGwPort, boolean isRtrGwRemoved) {
467 Uuid routerId = new Uuid(routerGwPort.getDeviceId());
468 Uuid networkId = routerGwPort.getNetworkId();
469 Network network = neutronvpnUtils.getNeutronNetwork(networkId);
470 if (network == null) {
473 boolean isExternal = NeutronvpnUtils.getIsExternal(network);
475 Uuid vpnInternetId = neutronvpnUtils.getVpnForNetwork(networkId);
476 if (vpnInternetId != null) {
477 if (!isRtrGwRemoved) {
478 nvpnManager.updateVpnMaps(vpnInternetId, null, routerId, null, null);
480 List<Subnetmap> snList = neutronvpnUtils.getNeutronRouterSubnetMaps(routerId);
481 for (Subnetmap sn : snList) {
482 if (sn.getNetworkId() == networkId) {
485 if (NeutronvpnUtils.getIpVersionFromString(sn.getSubnetIp()) != IpVersionChoice.IPV6) {
488 if (isRtrGwRemoved) {
489 nvpnManager.removeV6PrivateSubnetToExtNetwork(routerId, vpnInternetId, sn);
491 nvpnManager.addV6PrivateSubnetToExtNetwork(routerId, vpnInternetId, sn);
494 //Update Internet BGP-VPN
495 if (isRtrGwRemoved) {
496 nvpnManager.updateVpnMaps(vpnInternetId, null, null, null, null);
500 elanService.addKnownL3DmacAddress(routerGwPort.getMacAddress().getValue(), networkId.getValue());
502 Router router = neutronvpnUtils.getNeutronRouter(routerId);
503 if (router == null) {
504 LOG.warn("No router found for router GW port {} for router {}", routerGwPort.getUuid().getValue(),
505 routerId.getValue());
507 eventCallbacks.onAddOrUpdate(LogicalDatastoreType.CONFIGURATION,
508 neutronvpnUtils.getNeutronRouterIid(routerId), (unused, newRouter) -> {
509 setupGwMac(newRouter, routerGwPort, routerId);
510 return DataTreeEventCallbackRegistrar.NextAction.UNREGISTER;
511 }, Duration.ofSeconds(3), iid -> {
512 LOG.error("GwPort {} added without Router", routerGwPort.getUuid().getValue());
516 setupGwMac(router, routerGwPort, routerId);
519 private void setupGwMac(Router router, Port routerGwPort, Uuid routerId) {
520 gwMacResolver.sendArpRequestsToExtGateways(router);
521 jobCoordinator.enqueueJob(routerId.toString(), () -> {
522 setExternalGwMac(routerGwPort, routerId);
523 return Collections.emptyList();
527 private void setExternalGwMac(Port routerGwPort, Uuid routerId) {
528 // During full-sync networking-odl syncs routers before ports. As such,
529 // the MAC of the router's gw port is not available to be set when the
530 // router is written. We catch that here.
531 InstanceIdentifier<Routers> routersId = NeutronvpnUtils.buildExtRoutersIdentifier(routerId);
532 Optional<Routers> optionalRouter = null;
534 optionalRouter = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routersId);
535 if (!optionalRouter.isPresent()) {
538 Routers extRouters = optionalRouter.get();
539 if (extRouters.getExtGwMacAddress() != null) {
543 RoutersBuilder builder = new RoutersBuilder(extRouters);
544 builder.setExtGwMacAddress(routerGwPort.getMacAddress().getValue());
545 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, routersId, builder.build());
546 } catch (ExecutionException | InterruptedException e) {
547 LOG.error("setExternalGwMac: failed to read EXT-Routers for router Id {} rout-Gw port {} due to exception",
548 routerId, routerGwPort, e);
554 private String getPortHostId(final Port port) {
556 PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
557 if (portBinding != null) {
558 return portBinding.getHostId();
565 private Hostconfig getHostConfig(final Port port) {
566 String hostId = getPortHostId(port);
567 if (hostId == null) {
570 Optional<Hostconfig> hostConfig;
572 hostConfig = this.hostConfigCache.get(hostId);
573 } catch (ReadFailedException e) {
574 LOG.error("failed to read host config from host {}", hostId, e);
577 return hostConfig.orElse(null);
580 private boolean isPortBound(final Port port) {
581 String hostId = getPortHostId(port);
582 return hostId != null && !hostId.isEmpty();
585 private boolean isPortVnicTypeDirect(Port port) {
586 PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
587 if (portBinding == null || portBinding.getVnicType() == null) {
588 // By default, VNIC_TYPE is NORMAL
591 String vnicType = portBinding.getVnicType().trim().toLowerCase(Locale.getDefault());
592 return NeutronConstants.VNIC_TYPE_DIRECT.equals(vnicType);
595 private boolean isSupportedVnicTypeByHost(final Port port, final String vnicType) {
596 Hostconfig hostConfig = getHostConfig(port);
597 String supportStr = String.format("\"vnic_type\": \"%s\"", vnicType);
598 if (hostConfig != null && hostConfig.getConfig().contains(supportStr)) {
605 private Map<String, JsonElement> unmarshal(final String profile) {
606 if (null == profile) {
609 Gson gson = new Gson();
610 JsonObject jsonObject = gson.fromJson(profile, JsonObject.class);
611 Map<String, JsonElement> map = new HashMap<>();
612 for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
613 map.put(entry.getKey(), entry.getValue());
618 private boolean isPortTypeSwitchdev(final Port port) {
619 if (!isPortVnicTypeDirect(port)) {
623 PortBindingExtension portBinding = port.augmentation(PortBindingExtension.class);
624 String profile = portBinding.getProfile();
625 if (profile == null || profile.isEmpty()) {
626 LOG.debug("Port {} has no binding:profile values", port.getUuid());
630 Map<String, JsonElement> mapProfile = unmarshal(profile);
631 JsonElement capabilities = mapProfile.get(NeutronConstants.BINDING_PROFILE_CAPABILITIES);
632 LOG.debug("Port {} capabilities: {}", port.getUuid(), capabilities);
633 if (capabilities == null || !capabilities.isJsonArray()) {
634 LOG.debug("binding profile capabilities not in array format: {}", capabilities);
638 JsonArray capabilitiesArray = capabilities.getAsJsonArray();
639 Gson gson = new Gson();
640 JsonElement switchdevElement = gson.fromJson(NeutronConstants.SWITCHDEV, JsonElement.class);
641 return capabilitiesArray.contains(switchdevElement);
645 private void handleNeutronPortCreated(final Port port) {
646 final String portName = port.getUuid().getValue();
647 final Uuid portId = port.getUuid();
648 final String networkId = port.getNetworkId().getValue();
649 final Map<FixedIpsKey, FixedIps> keyFixedIpsMap = port.nonnullFixedIps();
650 if (NeutronConstants.IS_ODL_DHCP_PORT.test(port)) {
653 if (!(NeutronUtils.isPortVnicTypeNormal(port)
654 || isPortTypeSwitchdev(port)
655 && isSupportedVnicTypeByHost(port, NeutronConstants.VNIC_TYPE_DIRECT))) {
656 for (FixedIps ip: keyFixedIpsMap.values()) {
657 nvpnManager.updateSubnetmapNodeWithPorts(ip.getSubnetId(), null, portId);
659 LOG.info("Port {} is not a normal and not a direct with switchdev VNIC type ;"
660 + "OF Port interfaces are not created", portName);
663 jobCoordinator.enqueueJob("PORT- " + portName, () -> {
664 // add direct port to subnetMaps config DS
665 // TODO: for direct port as well, operations should be carried out per subnet based on port IP
667 ListenableFuture<?> future = txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
668 LOG.info("Of-port-interface creation for port {}", portName);
669 // Create of-port interface for this neutron port
670 String portInterfaceName = createOfPortInterface(port, tx);
671 LOG.debug("Creating ELAN Interface for port {}", portName);
672 createElanInterface(port, portInterfaceName, tx);
673 Set<Uuid> vpnIdList = new HashSet<>();
674 Set<Uuid> routerIds = new HashSet<>();
675 for (FixedIps ip: keyFixedIpsMap.values()) {
676 Subnetmap subnetMap = nvpnManager.updateSubnetmapNodeWithPorts(ip.getSubnetId(), portId, null);
677 if (subnetMap != null && subnetMap.getInternetVpnId() != null) {
678 if (!vpnIdList.contains(subnetMap.getInternetVpnId())) {
679 vpnIdList.add(subnetMap.getInternetVpnId());
682 if (subnetMap != null && subnetMap.getVpnId() != null) {
683 // can't use NeutronvpnUtils.getVpnForNetwork to optimise here, because it gives BGPVPN id
684 // obtained subnetMaps belongs to one network => vpnId must be the same for each port Ip
685 Uuid vpnId = subnetMap.getVpnId();
687 vpnIdList.add(vpnId);
690 if (subnetMap != null && subnetMap.getRouterId() != null) {
691 routerIds.add(subnetMap.getRouterId());
694 if (!vpnIdList.isEmpty()) {
695 // create new vpn-interface for neutron port
696 LOG.debug("handleNeutronPortCreated: Adding VPN Interface for port {} from network {}", portName,
698 nvpnManager.createVpnInterface(vpnIdList, port, tx);
699 for (Uuid routerId : routerIds) {
700 nvpnManager.addToNeutronRouterInterfacesMap(routerId,port.getUuid().getValue());
704 LoggingFutures.addErrorLogging(future, LOG,
705 "handleNeutronPortCreated: Failed for port {} with networkId {}", portName, networkId);
706 return Collections.singletonList(future);
710 private void handleNeutronPortDeleted(final Port port) {
711 final String portName = port.getUuid().getValue();
712 final Uuid portId = port.getUuid();
713 final Map<FixedIpsKey, FixedIps> keyFixedIpsMap = port.nonnullFixedIps();
714 if (!(NeutronUtils.isPortVnicTypeNormal(port) || isPortTypeSwitchdev(port))) {
715 for (FixedIps ip : keyFixedIpsMap.values()) {
716 // remove direct port from subnetMaps config DS
717 // TODO: for direct port as well, operations should be carried out per subnet based on port IP
718 nvpnManager.removePortsFromSubnetmapNode(ip.getSubnetId(), null, portId);
720 LOG.info("Port {} is not a normal and not a direct with switchdev VNIC type ;"
721 + "Skipping OF Port interfaces removal", portName);
724 jobCoordinator.enqueueJob("PORT- " + portName, () -> {
725 ListenableFuture<?> future = txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
728 Set<Uuid> routerIds = new HashSet<>();
729 Uuid internetVpnId = null;
730 for (FixedIps ip : keyFixedIpsMap.values()) {
731 Subnetmap subnetMap = nvpnManager.removePortsFromSubnetmapNode(ip.getSubnetId(), portId, null);
732 if (subnetMap == null) {
735 if (subnetMap.getVpnId() != null) {
736 // can't use NeutronvpnUtils.getVpnForNetwork to optimise here, because it gives BGPVPN id
737 // obtained subnetMaps belongs to one network => vpnId must be the same for each port Ip
738 vpnId = subnetMap.getVpnId();
740 if (subnetMap.getRouterId() != null) {
741 routerIds.add(subnetMap.getRouterId());
743 internetVpnId = subnetMap.getInternetVpnId();
745 if (NeutronConstants.DEVICE_OWNER_GATEWAY_INF.equals(port.getDeviceOwner())
746 || NeutronConstants.DEVICE_OWNER_FLOATING_IP.equals(port.getDeviceOwner())) {
747 String ipAddress = ip.getIpAddress().stringValue();
749 neutronvpnUtils.removeVpnPortFixedIpToPort(vpnId.getValue(), ipAddress, confTx);
751 if (internetVpnId != null) {
752 neutronvpnUtils.removeVpnPortFixedIpToPort(internetVpnId.getValue(),
757 if (vpnId != null || internetVpnId != null) {
758 // remove vpn-interface for this neutron port
759 LOG.debug("removing VPN Interface for port {}", portName);
760 if (!routerIds.isEmpty()) {
761 for (Uuid routerId : routerIds) {
762 nvpnManager.removeFromNeutronRouterInterfacesMap(routerId, portName);
765 nvpnManager.deleteVpnInterface(portName, null /* vpn-id */, confTx);
767 // Remove of-port interface for this neutron port
768 // ELAN interface is also implicitly deleted as part of this operation
769 LOG.debug("Of-port-interface removal for port {}", portName);
770 deleteOfPortInterface(port, confTx);
771 //dissociate fixedIP from floatingIP if associated
772 nvpnManager.dissociatefixedIPFromFloatingIP(port.getUuid().getValue());
774 LoggingFutures.addErrorLogging(future, LOG,
775 "handleNeutronPortDeleted: Failed to update interface {} with networkId", portName,
776 port.getNetworkId().getValue());
777 return Collections.singletonList(future);
782 private void handleNeutronPortUpdated(final Port portoriginal, final Port portupdate) {
783 final Map<FixedIpsKey, FixedIps> portoriginalIpsMap = portoriginal.nonnullFixedIps();
784 final Map<FixedIpsKey, FixedIps> portupdateIpsMap = portupdate.nonnullFixedIps();
785 if (portoriginalIpsMap == null || portoriginalIpsMap.isEmpty()) {
786 handleNeutronPortCreated(portupdate);
790 if (portupdateIpsMap == null || portupdateIpsMap.isEmpty()) {
791 LOG.info("Ignoring portUpdate (fixed_ip removal) for port {} as this case is handled "
792 + "during subnet deletion event.", portupdate.getUuid().getValue());
796 if (NeutronConstants.IS_ODL_DHCP_PORT.test(portupdate)) {
800 jobCoordinator.enqueueJob("PORT- " + portupdate.getUuid().getValue(),
801 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, confTx -> {
802 final List<Uuid> originalSnMapsIds = portoriginalIpsMap.values().stream().map(FixedIps::getSubnetId)
803 .collect(Collectors.toList());
804 final List<Uuid> updateSnMapsIds = portupdateIpsMap.values().stream().map(FixedIps::getSubnetId)
805 .collect(Collectors.toList());
806 Set<Uuid> originalRouterIds = new HashSet<>();
807 Set<Uuid> oldVpnIds = new HashSet<>();
808 for (Uuid snId: originalSnMapsIds) {
809 if (!updateSnMapsIds.remove(snId)) {
810 // snId was present in originalSnMapsIds, but not in updateSnMapsIds
811 Subnetmap subnetMapOld = nvpnManager.removePortsFromSubnetmapNode(snId, portoriginal.getUuid(),
813 if (subnetMapOld != null && subnetMapOld.getVpnId() != null) {
814 oldVpnIds.add(subnetMapOld.getVpnId());
816 if (subnetMapOld != null && subnetMapOld.getInternetVpnId() != null) {
817 oldVpnIds.add(subnetMapOld.getInternetVpnId());
819 if (subnetMapOld != null && subnetMapOld.getRouterId() != null) {
820 originalRouterIds.add(subnetMapOld.getRouterId());
824 Set<Uuid> newVpnIds = new HashSet<>();
825 Set<Uuid> newRouterIds = new HashSet<>();
826 for (Uuid snId: updateSnMapsIds) {
827 Subnetmap subnetMapNew = nvpnManager.updateSubnetmapNodeWithPorts(snId, portupdate.getUuid(), null);
828 if (subnetMapNew != null) {
829 if (subnetMapNew.getVpnId() != null) {
830 newVpnIds.add(subnetMapNew.getVpnId());
832 if (subnetMapNew.getInternetVpnId() != null) {
833 newVpnIds.add(subnetMapNew.getInternetVpnId());
835 if (subnetMapNew.getRouterId() != null) {
836 newRouterIds.add(subnetMapNew.getRouterId());
840 if (!oldVpnIds.isEmpty()) {
841 LOG.info("removing VPN Interface for port {}", portoriginal.getUuid().getValue());
842 if (!originalRouterIds.isEmpty()) {
843 for (Uuid routerId : originalRouterIds) {
844 nvpnManager.removeFromNeutronRouterInterfacesMap(routerId,
845 portoriginal.getUuid().getValue());
848 nvpnManager.deleteVpnInterface(portoriginal.getUuid().getValue(),
849 null /* vpn-id */, confTx);
851 if (!newVpnIds.isEmpty()) {
852 LOG.info("Adding VPN Interface for port {}", portupdate.getUuid().getValue());
853 nvpnManager.createVpnInterface(newVpnIds, portupdate, confTx);
854 if (!newRouterIds.isEmpty()) {
855 for (Uuid routerId : newRouterIds) {
856 nvpnManager.addToNeutronRouterInterfacesMap(routerId,portupdate.getUuid().getValue());
864 private InterfaceAclBuilder handlePortSecurityUpdated(Port portOriginal,
865 Port portUpdated, boolean origSecurityEnabled, boolean updatedSecurityEnabled,
866 InterfaceBuilder interfaceBuilder) {
867 InterfaceAclBuilder interfaceAclBuilder = null;
868 if (origSecurityEnabled != updatedSecurityEnabled) {
869 interfaceAclBuilder = new InterfaceAclBuilder();
870 interfaceAclBuilder.setPortSecurityEnabled(updatedSecurityEnabled);
871 if (updatedSecurityEnabled) {
872 // Handle security group enabled
873 neutronvpnUtils.populateInterfaceAclBuilder(interfaceAclBuilder, portUpdated);
875 // Handle security group disabled
876 interfaceAclBuilder.setSecurityGroups(new ArrayList<>());
877 interfaceAclBuilder.setAllowedAddressPairs(new ArrayList<>());
878 interfaceAclBuilder.setSubnetInfo(new ArrayList<>());
881 if (updatedSecurityEnabled) {
882 // handle SG add/delete delta
883 InterfaceAcl interfaceAcl = interfaceBuilder.augmentation(InterfaceAcl.class);
884 interfaceAclBuilder = new InterfaceAclBuilder(interfaceAcl);
885 interfaceAclBuilder.setSecurityGroups(
886 NeutronvpnUtils.getUpdatedSecurityGroups(interfaceAcl.getSecurityGroups(),
887 portOriginal.getSecurityGroups(), portUpdated.getSecurityGroups()));
888 List<AllowedAddressPairs> updatedAddressPairs = NeutronvpnUtils.getUpdatedAllowedAddressPairs(
889 new ArrayList<AllowedAddressPairs>(interfaceAcl.nonnullAllowedAddressPairs().values()),
890 new ArrayList<>(portOriginal.nonnullAllowedAddressPairs().values()),
891 new ArrayList<org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port
892 .attributes.AllowedAddressPairs>(portUpdated.nonnullAllowedAddressPairs().values()));
893 interfaceAclBuilder.setAllowedAddressPairs(NeutronvpnUtils.getAllowedAddressPairsForFixedIps(
894 updatedAddressPairs, portOriginal.getMacAddress(), portOriginal.getFixedIps(),
895 portUpdated.nonnullFixedIps().values()));
897 if (portOriginal.getFixedIps() != null
898 && !portOriginal.getFixedIps().equals(portUpdated.getFixedIps())) {
899 neutronvpnUtils.populateSubnetInfo(interfaceAclBuilder, portUpdated);
903 return interfaceAclBuilder;
906 private String createOfPortInterface(Port port, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
907 Interface inf = createInterface(port);
908 String infName = inf.getName();
910 InstanceIdentifier<Interface> interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(infName);
912 Optional<Interface> optionalInf =
913 SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
914 interfaceIdentifier);
915 if (!optionalInf.isPresent()) {
916 wrtConfigTxn.put(interfaceIdentifier, inf);
917 } else if (isInterfaceUpdated(inf, optionalInf.get())) {
919 Case where an update DTCN wasn't received by this class due to node going down
920 upon cluster reboot or any other unknown reason
921 In such a case, updates contained in the missed DTCN won't be processed and have to be handled
923 Update of subports (vlanId, splithorizon tag) is handled here
924 Update of portSecurity (PortSecurityEnabled, SecurityGroups, AllowedAddressPairs) add is handled
925 Update of portSecurity update/removed is not handled
926 Update of parentrefs is not handled as parentrefs updation is handled by IFM Oxygen onwards
928 wrtConfigTxn.put(interfaceIdentifier, inf);
929 LOG.error("Interface {} is already present and is updated", infName);
931 LOG.warn("Interface {} is already present", infName);
933 } catch (ExecutionException | InterruptedException e) {
934 LOG.error("failed to create interface {}", infName, e);
939 // Not for generic use. For a special case where update DTCN isn't received
940 private static boolean isInterfaceUpdated(Interface newInterface, Interface oldInterface) {
941 if (newInterface.augmentation(SplitHorizon.class) != null) {
942 if (oldInterface.augmentation(SplitHorizon.class) == null) {
945 if (!newInterface.augmentation(SplitHorizon.class).equals(oldInterface
946 .augmentation(SplitHorizon.class))) {
950 if (!newInterface.augmentation(IfL2vlan.class).equals(oldInterface.augmentation(IfL2vlan.class))) {
953 if (newInterface.augmentation(InterfaceAcl.class) != null && oldInterface
954 .augmentation(InterfaceAcl.class) == null) {
960 private Interface createInterface(Port port) {
961 String interfaceName = port.getUuid().getValue();
962 IfL2vlan.L2vlanMode l2VlanMode = IfL2vlan.L2vlanMode.Trunk;
963 InterfaceBuilder interfaceBuilder = new InterfaceBuilder();
964 IfL2vlanBuilder ifL2vlanBuilder = new IfL2vlanBuilder();
966 Network network = neutronvpnUtils.getNeutronNetwork(port.getNetworkId());
967 Boolean isVlanTransparent = network.isVlanTransparent();
968 if (isVlanTransparent != null && isVlanTransparent) {
969 l2VlanMode = IfL2vlan.L2vlanMode.Transparent;
971 PortIdToSubport portIdToSubport = neutronvpnUtils.getPortIdToSubport(port.getUuid());
972 if (portIdToSubport != null) {
973 l2VlanMode = IfL2vlan.L2vlanMode.TrunkMember;
974 ifL2vlanBuilder.setVlanId(new VlanId(portIdToSubport.getVlanId().intValue()));
975 String parentRefName = portIdToSubport.getTrunkPortId().getValue();
976 ParentRefsBuilder parentRefsBuilder = new ParentRefsBuilder().setParentInterface(parentRefName);
977 interfaceBuilder.addAugmentation(ParentRefs.class, parentRefsBuilder.build());
978 SplitHorizon splitHorizon =
979 new SplitHorizonBuilder().setOverrideSplitHorizonProtection(true).build();
980 interfaceBuilder.addAugmentation(SplitHorizon.class, splitHorizon);
984 ifL2vlanBuilder.setL2vlanMode(l2VlanMode);
986 interfaceBuilder.setEnabled(true).setName(interfaceName).setType(L2vlan.class)
987 .addAugmentation(IfL2vlan.class, ifL2vlanBuilder.build());
989 if (NeutronvpnUtils.getPortSecurityEnabled(port)) {
990 InterfaceAclBuilder interfaceAclBuilder = new InterfaceAclBuilder();
991 interfaceAclBuilder.setPortSecurityEnabled(true);
992 neutronvpnUtils.populateInterfaceAclBuilder(interfaceAclBuilder, port);
993 interfaceBuilder.addAugmentation(InterfaceAcl.class, interfaceAclBuilder.build());
994 } else if (neutronvpnConfig.isLimitBumtrafficToDhcpserver() && NeutronvpnUtils.isDhcpServerPort(port)) {
995 interfaceBuilder.addAugmentation(InterfaceAcl.class, neutronvpnUtils.getDhcpInterfaceAcl(port));
997 return interfaceBuilder.build();
1000 private void deleteOfPortInterface(Port port, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
1001 String name = port.getUuid().getValue();
1002 LOG.debug("Removing OFPort Interface {}", name);
1003 InstanceIdentifier<Interface> interfaceIdentifier = NeutronvpnUtils.buildVlanInterfaceIdentifier(name);
1005 Optional<Interface> optionalInf =
1006 SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
1007 interfaceIdentifier);
1008 if (optionalInf.isPresent()) {
1009 wrtConfigTxn.delete(interfaceIdentifier);
1011 LOG.warn("deleteOfPortInterface: Interface {} is not present", name);
1013 } catch (ExecutionException | InterruptedException e) {
1014 LOG.error("deleteOfPortInterface: Failed to delete interface {}", name, e);
1018 private void createElanInterface(Port port, String name,
1019 TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
1020 String elanInstanceName = port.getNetworkId().getValue();
1021 List<StaticMacEntries> staticMacEntries = NeutronvpnUtils.buildStaticMacEntry(port);
1023 InstanceIdentifier<ElanInterface> id = InstanceIdentifier.builder(ElanInterfaces.class).child(ElanInterface
1024 .class, new ElanInterfaceKey(name)).build();
1025 ElanInterface elanInterface = new ElanInterfaceBuilder().setElanInstanceName(elanInstanceName)
1026 .setName(name).setStaticMacEntries(staticMacEntries).withKey(new ElanInterfaceKey(name)).build();
1027 wrtConfigTxn.put(id, elanInterface);
1028 LOG.debug("Creating new ELan Interface {}", elanInterface);
1031 private void deleteElanInterface(String name, TypedWriteTransaction<Datastore.Configuration> wrtConfigTxn) {
1032 InstanceIdentifier<ElanInterface> id = InstanceIdentifier.builder(ElanInterfaces.class).child(ElanInterface
1033 .class, new ElanInterfaceKey(name)).build();
1034 wrtConfigTxn.delete(id);
1037 // TODO Clean up the exception handling
1038 @SuppressWarnings("checkstyle:IllegalCatch")
1039 private void addToFloatingIpPortInfo(Uuid floatingIpId, Uuid floatingIpPortId, Uuid floatingIpPortSubnetId, String
1040 floatingIpPortMacAddress) {
1041 InstanceIdentifier id = NeutronvpnUtils.buildfloatingIpIdToPortMappingIdentifier(floatingIpId);
1043 FloatingIpIdToPortMappingBuilder floatingipIdToPortMacMappingBuilder = new
1044 FloatingIpIdToPortMappingBuilder().withKey(new FloatingIpIdToPortMappingKey(floatingIpId))
1045 .setFloatingIpId(floatingIpId).setFloatingIpPortId(floatingIpPortId)
1046 .setFloatingIpPortSubnetId(floatingIpPortSubnetId)
1047 .setFloatingIpPortMacAddress(floatingIpPortMacAddress);
1048 LOG.debug("Creating floating IP UUID {} to Floating IP neutron port {} mapping in Floating IP"
1049 + " Port Info Config DS", floatingIpId.getValue(), floatingIpPortId.getValue());
1050 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION, id,
1051 floatingipIdToPortMacMappingBuilder.build());
1052 } catch (Exception e) {
1053 LOG.error("Creating floating IP UUID {} to Floating IP neutron port {} mapping in Floating IP"
1054 + " Port Info Config DS failed", floatingIpId.getValue(), floatingIpPortId.getValue(), e);
1058 private Set<FixedIps> getFixedIpSet(List<FixedIps> fixedIps) {
1059 return fixedIps != null ? new HashSet<>(fixedIps) : Collections.emptySet();