4688f95700eba5ca2db77848ab6cbcc6c90fc60b
[netvirt.git] / elanmanager / impl / src / main / java / org / opendaylight / netvirt / elan / l2gw / utils / StaleVlanBindingsCleaner.java
1 /*
2  * Copyright (c) 2018 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.netvirt.elan.l2gw.utils;
9
10 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
11
12 import java.util.ArrayList;
13 import java.util.Collections;
14 import java.util.HashMap;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.concurrent.ConcurrentHashMap;
18 import java.util.concurrent.ScheduledFuture;
19 import java.util.concurrent.TimeUnit;
20 import java.util.function.BiPredicate;
21 import java.util.function.Function;
22 import java.util.function.Predicate;
23 import java.util.stream.Collectors;
24 import javax.inject.Inject;
25 import javax.inject.Singleton;
26 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
27 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
28 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
29 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
30 import org.opendaylight.genius.mdsalutil.MDSALUtil;
31 import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundUtils;
32 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
33 import org.opendaylight.netvirt.elan.cache.ElanInstanceCache;
34 import org.opendaylight.netvirt.elan.utils.Scheduler;
35 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayCache;
36 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.elan.config.rev150710.ElanConfig;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l2gateways.rev150712.l2gateway.connections.attributes.l2gatewayconnections.L2gatewayConnection;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalAugmentation;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepPhysicalPortAugmentation;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.LogicalSwitches;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical.port.attributes.VlanBindings;
43 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
44 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
45 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
46 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
47 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
50
51 @Singleton
52 public class StaleVlanBindingsCleaner {
53
54     private static final Logger LOG = LoggerFactory.getLogger(StaleVlanBindingsCleaner.class);
55     private static final int DEFAULT_STALE_CLEANUP_DELAY_SECS = 900;
56
57     private static Function<VlanBindings, String> LOGICAL_SWITCH_FROM_BINDING =
58         (binding) -> binding.getLogicalSwitchRef().getValue().firstKeyOf(
59                 LogicalSwitches.class).getHwvtepNodeName().getValue();
60
61     private static BiPredicate<List<String>, String> IS_STALE_LOGICAL_SWITCH =
62         (validNetworks, logicalSwitch) -> !validNetworks.contains(logicalSwitch);
63
64     private static Predicate<TerminationPoint> CONTAINS_VLANBINDINGS = (port) ->
65             port.augmentation(HwvtepPhysicalPortAugmentation.class) != null
66                     && port.augmentation(HwvtepPhysicalPortAugmentation.class).getVlanBindings() != null;
67
68
69     private final DataBroker broker;
70     private final ManagedNewTransactionRunner txRunner;
71     private final ElanL2GatewayUtils elanL2GatewayUtils;
72     private final Scheduler scheduler;
73     private final ElanConfig elanConfig;
74     private final L2GatewayCache l2GatewayCache;
75     private final ElanInstanceCache elanInstanceCache;
76     private final Map<NodeId, ScheduledFuture> cleanupTasks = new ConcurrentHashMap<>();
77
78     @Inject
79     public StaleVlanBindingsCleaner(final DataBroker broker,
80                                     final ElanL2GatewayUtils elanL2GatewayUtils,
81                                     final Scheduler scheduler,
82                                     final ElanConfig elanConfig,
83                                     final L2GatewayCache l2GatewayCache,
84                                     final ElanInstanceCache elanInstanceCache) {
85         this.broker = broker;
86         this.txRunner = new ManagedNewTransactionRunnerImpl(broker);
87         this.elanL2GatewayUtils = elanL2GatewayUtils;
88         this.scheduler = scheduler;
89         this.elanConfig = elanConfig;
90         this.l2GatewayCache = l2GatewayCache;
91         this.elanInstanceCache = elanInstanceCache;
92     }
93
94     private long getCleanupDelay() {
95         return elanConfig.getL2gwStaleVlanCleanupDelaySecs() != null
96                 ? elanConfig.getL2gwStaleVlanCleanupDelaySecs().toJava() : DEFAULT_STALE_CLEANUP_DELAY_SECS;
97     }
98
99     public void scheduleStaleCleanup(final String deviceName,
100                                      final InstanceIdentifier<Node> globalNodeIid,
101                                      final InstanceIdentifier<Node> psNodeIid) {
102         NodeId psNodeId = psNodeIid.firstKeyOf(Node.class).getNodeId();
103         cleanupTasks.compute(psNodeId, (key, ft) -> {
104             if (ft != null) {
105                 ft.cancel(false);
106             }
107             return scheduler.getScheduledExecutorService().schedule(
108                 () -> {
109                     L2GatewayDevice l2GwDevice = l2GatewayCache.get(deviceName);
110                     NodeId globalNodeId = globalNodeIid.firstKeyOf(Node.class).getNodeId();
111                     Node configNode = MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, globalNodeIid)
112                             .or(defaultNode(globalNodeId));
113                     Node configPsNode =
114                         MDSALUtil.read(broker, LogicalDatastoreType.CONFIGURATION, psNodeIid).or(defaultNode(psNodeId));
115                     cleanupStaleLogicalSwitches(l2GwDevice, configNode, configPsNode);
116                     cleanupTasks.remove(psNodeIid.firstKeyOf(Node.class).getNodeId());
117                 }, getCleanupDelay(), TimeUnit.SECONDS);
118         });
119     }
120
121     private static Node defaultNode(final NodeId nodeId) {
122         return new NodeBuilder().setNodeId(nodeId).build();
123     }
124
125     private void cleanupStaleLogicalSwitches(final L2GatewayDevice l2GwDevice,
126                                              final Node configNode,
127                                              final Node configPsNode) {
128
129         String globalNodeId = configNode.getNodeId().getValue();
130         List<L2gatewayConnection> connectionsOfDevice = L2GatewayConnectionUtils.getAssociatedL2GwConnections(
131                 broker, l2GwDevice.getL2GatewayIds());
132
133         List<String> validNetworks = connectionsOfDevice.stream()
134                 .map((connection) -> connection.getNetworkId().getValue())
135                 .filter(elan -> elanInstanceCache.get(elan).isPresent())
136                 .collect(Collectors.toList());
137
138         List<String> logicalSwitchesOnDevice = getLogicalSwitchesOnDevice(configNode);
139
140         List<String> staleLogicalSwitches = logicalSwitchesOnDevice.stream()
141                 .filter((staleLogicalSwitch) -> IS_STALE_LOGICAL_SWITCH.test(validNetworks, staleLogicalSwitch))
142                 .collect(Collectors.toList());
143
144         if (!staleLogicalSwitches.isEmpty()) {
145             Map<String, List<InstanceIdentifier<VlanBindings>>> vlansByLogicalSwitch = getVlansByLogicalSwitchOnDevice(
146                     configPsNode);
147             staleLogicalSwitches.forEach((staleLogicalSwitch) -> cleanupStaleBindings(
148                     globalNodeId, vlansByLogicalSwitch, staleLogicalSwitch));
149         }
150     }
151
152     private static Map<String, List<InstanceIdentifier<VlanBindings>>> getVlansByLogicalSwitchOnDevice(
153             final Node configPsNode) {
154         List<TerminationPoint> ports = configPsNode.getTerminationPoint();
155         if (ports == null) {
156             return Collections.emptyMap();
157         }
158         Map<String, List<InstanceIdentifier<VlanBindings>>> vlans = new HashMap<>();
159         ports.stream()
160                 .filter(CONTAINS_VLANBINDINGS)
161                 .forEach((port) -> port.augmentation(HwvtepPhysicalPortAugmentation.class)
162                         .getVlanBindings()
163                         .forEach((binding) -> putVlanBindingVsLogicalSwitch(configPsNode, vlans, port, binding)));
164         return vlans;
165     }
166
167     private static void putVlanBindingVsLogicalSwitch(final Node configPsNode,
168                                                       final Map<String, List<InstanceIdentifier<VlanBindings>>> vlans,
169                                                       final TerminationPoint port,
170                                                       final VlanBindings binding) {
171         String logicalSwitch = LOGICAL_SWITCH_FROM_BINDING.apply(binding);
172         vlans.computeIfAbsent(logicalSwitch, (name) -> new ArrayList<>())
173                 .add(createVlanIid(configPsNode.getNodeId(), port, binding));
174     }
175
176     private static InstanceIdentifier<VlanBindings> createVlanIid(final NodeId nodeId,
177                                                                   final TerminationPoint tp,
178                                                                   final VlanBindings vlanBinding) {
179         return HwvtepSouthboundUtils.createInstanceIdentifier(nodeId)
180                 .child(TerminationPoint.class, tp.key())
181                 .augmentation(HwvtepPhysicalPortAugmentation.class)
182                 .child(VlanBindings.class, vlanBinding.key());
183     }
184
185     private void cleanupStaleBindings(final String globalNodeId,
186                                       final Map<String, List<InstanceIdentifier<VlanBindings>>> vlans,
187                                       final String staleLogicalSwitch) {
188
189         LOG.trace("CleanupStaleBindings for logical switch {}", staleLogicalSwitch);
190         LoggingFutures.addErrorLogging(
191             txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
192                 if (vlans.containsKey(staleLogicalSwitch)) {
193                     vlans.get(staleLogicalSwitch).forEach((vlanIid) -> tx.delete(vlanIid));
194                 }
195             }),
196             LOG, "Failed to delete stale vlan bindings from node {}", globalNodeId);
197         elanL2GatewayUtils.scheduleDeleteLogicalSwitch(new NodeId(globalNodeId), staleLogicalSwitch, true);
198     }
199
200     private static List<String> getLogicalSwitchesOnDevice(final Node globalConfigNode) {
201         HwvtepGlobalAugmentation augmentation = globalConfigNode.augmentation(HwvtepGlobalAugmentation.class);
202         if (augmentation == null || augmentation.getLogicalSwitches() == null) {
203             return Collections.emptyList();
204         }
205         return augmentation
206                 .getLogicalSwitches()
207                 .stream()
208                 .map((ls) -> ls.getHwvtepNodeName().getValue())
209                 .collect(Collectors.toList());
210     }
211 }