2 * Copyright (c) 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.elan.l2gw.utils;
10 import static org.opendaylight.mdsal.binding.util.Datastore.CONFIGURATION;
12 import java.util.ArrayList;
13 import java.util.Collections;
14 import java.util.HashMap;
15 import java.util.List;
17 import java.util.concurrent.ConcurrentHashMap;
18 import java.util.concurrent.ExecutionException;
19 import java.util.concurrent.ScheduledFuture;
20 import java.util.concurrent.TimeUnit;
21 import java.util.function.BiPredicate;
22 import java.util.function.Function;
23 import java.util.function.Predicate;
24 import java.util.stream.Collectors;
25 import javax.inject.Inject;
26 import javax.inject.Singleton;
27 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
28 import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundUtils;
29 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
30 import org.opendaylight.mdsal.binding.api.DataBroker;
31 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunner;
32 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunnerImpl;
33 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
34 import org.opendaylight.netvirt.elan.cache.ElanInstanceCache;
35 import org.opendaylight.netvirt.elan.utils.Scheduler;
36 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayCache;
37 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.config.rev150710.ElanConfig;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.connections.attributes.l2gatewayconnections.L2gatewayConnection;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalPortAugmentation;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.port.attributes.VlanBindings;
44 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
45 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
46 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
47 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
48 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
49 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
54 public class StaleVlanBindingsCleaner {
56 private static final Logger LOG = LoggerFactory.getLogger(StaleVlanBindingsCleaner.class);
57 private static final int DEFAULT_STALE_CLEANUP_DELAY_SECS = 900;
59 private static Function<VlanBindings, String> LOGICAL_SWITCH_FROM_BINDING =
60 (binding) -> binding.getLogicalSwitchRef().getValue().firstKeyOf(
61 LogicalSwitches.class).getHwvtepNodeName().getValue();
63 private static BiPredicate<List<String>, String> IS_STALE_LOGICAL_SWITCH =
64 (validNetworks, logicalSwitch) -> !validNetworks.contains(logicalSwitch);
66 private static Predicate<TerminationPoint> CONTAINS_VLANBINDINGS = (port) ->
67 port.augmentation(HwvtepPhysicalPortAugmentation.class) != null
68 && port.augmentation(HwvtepPhysicalPortAugmentation.class).getVlanBindings() != null;
71 private final DataBroker broker;
72 private final ManagedNewTransactionRunner txRunner;
73 private final ElanL2GatewayUtils elanL2GatewayUtils;
74 private final Scheduler scheduler;
75 private final ElanConfig elanConfig;
76 private final L2GatewayCache l2GatewayCache;
77 private final ElanInstanceCache elanInstanceCache;
78 private final Map<NodeId, ScheduledFuture> cleanupTasks = new ConcurrentHashMap<>();
81 public StaleVlanBindingsCleaner(final DataBroker broker,
82 final ElanL2GatewayUtils elanL2GatewayUtils,
83 final Scheduler scheduler,
84 final ElanConfig elanConfig,
85 final L2GatewayCache l2GatewayCache,
86 final ElanInstanceCache elanInstanceCache) {
88 this.txRunner = new ManagedNewTransactionRunnerImpl(broker);
89 this.elanL2GatewayUtils = elanL2GatewayUtils;
90 this.scheduler = scheduler;
91 this.elanConfig = elanConfig;
92 this.l2GatewayCache = l2GatewayCache;
93 this.elanInstanceCache = elanInstanceCache;
96 private long getCleanupDelay() {
97 return elanConfig.getL2gwStaleVlanCleanupDelaySecs() != null
98 ? elanConfig.getL2gwStaleVlanCleanupDelaySecs().toJava() : DEFAULT_STALE_CLEANUP_DELAY_SECS;
101 public void scheduleStaleCleanup(final String deviceName,
102 final InstanceIdentifier<Node> globalNodeIid,
103 final InstanceIdentifier<Node> psNodeIid) {
104 NodeId psNodeId = psNodeIid.firstKeyOf(Node.class).getNodeId();
105 cleanupTasks.compute(psNodeId, (key, ft) -> {
109 return scheduler.getScheduledExecutorService().schedule(
111 L2GatewayDevice l2GwDevice = l2GatewayCache.get(deviceName);
112 NodeId globalNodeId = globalNodeIid.firstKeyOf(Node.class).getNodeId();
114 Node configNode = SingleTransactionDataBroker.syncReadOptional(broker,
115 LogicalDatastoreType.CONFIGURATION, globalNodeIid).orElse(defaultNode(globalNodeId));
116 Node configPsNode = SingleTransactionDataBroker.syncReadOptional(broker,
117 LogicalDatastoreType.CONFIGURATION, psNodeIid)
118 .orElse(defaultNode(psNodeId));
119 cleanupStaleLogicalSwitches(l2GwDevice, configNode, configPsNode);
120 cleanupTasks.remove(psNodeIid.firstKeyOf(Node.class).getNodeId());
121 } catch (ExecutionException | InterruptedException e) {
122 LOG.error("scheduleStaleCleanup: Exception while reading globalNodeIid/psNodeIid DS for "
123 + "the globalNodeIid {} psNodeIid {}", globalNodeId, psNodeId, e);
125 }, getCleanupDelay(), TimeUnit.SECONDS);
129 private static Node defaultNode(final NodeId nodeId) {
130 return new NodeBuilder().setNodeId(nodeId).build();
133 private void cleanupStaleLogicalSwitches(final L2GatewayDevice l2GwDevice,
134 final Node configNode,
135 final Node configPsNode) {
137 String globalNodeId = configNode.getNodeId().getValue();
138 List<L2gatewayConnection> connectionsOfDevice = L2GatewayConnectionUtils.getAssociatedL2GwConnections(
139 broker, l2GwDevice.getL2GatewayIds());
141 List<String> validNetworks = connectionsOfDevice.stream()
142 .map((connection) -> connection.getNetworkId().getValue())
143 .filter(elan -> elanInstanceCache.get(elan).isPresent())
144 .collect(Collectors.toList());
146 List<String> logicalSwitchesOnDevice = getLogicalSwitchesOnDevice(configNode);
148 List<String> staleLogicalSwitches = logicalSwitchesOnDevice.stream()
149 .filter((staleLogicalSwitch) -> IS_STALE_LOGICAL_SWITCH.test(validNetworks, staleLogicalSwitch))
150 .collect(Collectors.toList());
152 if (!staleLogicalSwitches.isEmpty()) {
153 Map<String, List<InstanceIdentifier<VlanBindings>>> vlansByLogicalSwitch = getVlansByLogicalSwitchOnDevice(
155 staleLogicalSwitches.forEach((staleLogicalSwitch) -> cleanupStaleBindings(
156 globalNodeId, vlansByLogicalSwitch, staleLogicalSwitch));
160 private static Map<String, List<InstanceIdentifier<VlanBindings>>> getVlansByLogicalSwitchOnDevice(
161 final Node configPsNode) {
162 Map<TerminationPointKey, TerminationPoint> ports = configPsNode.nonnullTerminationPoint();
164 return Collections.emptyMap();
166 Map<String, List<InstanceIdentifier<VlanBindings>>> vlans = new HashMap<>();
167 ports.values().stream()
168 .filter(CONTAINS_VLANBINDINGS)
169 .forEach((port) -> port.augmentation(HwvtepPhysicalPortAugmentation.class)
170 .nonnullVlanBindings().values()
171 .forEach((binding) -> putVlanBindingVsLogicalSwitch(configPsNode, vlans, port, binding)));
175 private static void putVlanBindingVsLogicalSwitch(final Node configPsNode,
176 final Map<String, List<InstanceIdentifier<VlanBindings>>> vlans,
177 final TerminationPoint port,
178 final VlanBindings binding) {
179 String logicalSwitch = LOGICAL_SWITCH_FROM_BINDING.apply(binding);
180 vlans.computeIfAbsent(logicalSwitch, (name) -> new ArrayList<>())
181 .add(createVlanIid(configPsNode.getNodeId(), port, binding));
184 private static InstanceIdentifier<VlanBindings> createVlanIid(final NodeId nodeId,
185 final TerminationPoint tp,
186 final VlanBindings vlanBinding) {
187 return HwvtepSouthboundUtils.createInstanceIdentifier(nodeId)
188 .child(TerminationPoint.class, tp.key())
189 .augmentation(HwvtepPhysicalPortAugmentation.class)
190 .child(VlanBindings.class, vlanBinding.key());
193 private void cleanupStaleBindings(final String globalNodeId,
194 final Map<String, List<InstanceIdentifier<VlanBindings>>> vlans,
195 final String staleLogicalSwitch) {
197 LOG.trace("CleanupStaleBindings for logical switch {}", staleLogicalSwitch);
198 LoggingFutures.addErrorLogging(
199 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
200 if (vlans.containsKey(staleLogicalSwitch)) {
201 vlans.get(staleLogicalSwitch).forEach((vlanIid) -> tx.delete(vlanIid));
204 LOG, "Failed to delete stale vlan bindings from node {}", globalNodeId);
205 elanL2GatewayUtils.scheduleDeleteLogicalSwitch(new NodeId(globalNodeId), staleLogicalSwitch, true);
208 private static List<String> getLogicalSwitchesOnDevice(final Node globalConfigNode) {
209 HwvtepGlobalAugmentation augmentation = globalConfigNode.augmentation(HwvtepGlobalAugmentation.class);
210 if (augmentation == null || augmentation.getLogicalSwitches() == null) {
211 return Collections.emptyList();
214 .nonnullLogicalSwitches().values()
216 .map((ls) -> ls.getHwvtepNodeName().getValue())
217 .collect(Collectors.toList());