2 * Copyright (c) 2016 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
9 package org.opendaylight.netvirt.elan.l2gw.listeners;
11 import com.google.common.base.Optional;
12 import com.google.common.util.concurrent.ListenableFuture;
13 import java.util.Collections;
14 import java.util.List;
16 import java.util.concurrent.Callable;
17 import java.util.concurrent.ExecutionException;
18 import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
21 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
22 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
23 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
24 import org.opendaylight.genius.datastoreutils.hwvtep.HwvtepAbstractDataTreeChangeListener;
25 import org.opendaylight.genius.mdsalutil.MDSALUtil;
26 import org.opendaylight.genius.utils.hwvtep.HwvtepHACache;
27 import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundConstants;
28 import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundUtils;
29 import org.opendaylight.netvirt.elan.l2gw.ha.listeners.HAOpClusteredListener;
30 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayUtils;
31 import org.opendaylight.netvirt.elan.l2gw.utils.L2GatewayConnectionUtils;
32 import org.opendaylight.netvirt.elan.utils.ElanClusterUtils;
33 import org.opendaylight.netvirt.elan.utils.ElanUtils;
34 import org.opendaylight.netvirt.elanmanager.utils.ElanL2GwCacheUtils;
35 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
36 import org.opendaylight.netvirt.neutronvpn.api.l2gw.utils.L2GatewayCacheUtils;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
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.HwvtepGlobalAugmentationBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.HwvtepGlobalRef;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.PhysicalSwitchAugmentation;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.physical._switch.attributes.TunnelIps;
45 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
46 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
47 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
48 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
49 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
50 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeBuilder;
51 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
56 * Listener to handle physical switch updates.
58 public class HwvtepPhysicalSwitchListener
59 extends HwvtepAbstractDataTreeChangeListener<PhysicalSwitchAugmentation, HwvtepPhysicalSwitchListener>
60 implements ClusteredDataTreeChangeListener<PhysicalSwitchAugmentation>, AutoCloseable {
62 /** The Constant LOG. */
63 private static final Logger LOG = LoggerFactory.getLogger(HwvtepPhysicalSwitchListener.class);
65 /** The data broker. */
66 private final DataBroker dataBroker;
68 /** The itm rpc service. */
69 private final ItmRpcService itmRpcService;
71 /** The entity ownership service. */
72 private final EntityOwnershipService entityOwnershipService;
74 private final L2GatewayConnectionUtils l2GatewayConnectionUtils;
76 private final HwvtepHACache hwvtepHACache = HwvtepHACache.getInstance();
79 * Instantiates a new hwvtep physical switch listener.
83 * @param itmRpcService itm rpc
84 * @param entityOwnershipService entity ownership service
85 * @param elanUtils elan utils
87 public HwvtepPhysicalSwitchListener(final DataBroker dataBroker, ItmRpcService itmRpcService,
88 EntityOwnershipService entityOwnershipService,
89 ElanUtils elanUtils) {
90 super(PhysicalSwitchAugmentation.class, HwvtepPhysicalSwitchListener.class);
91 this.dataBroker = dataBroker;
92 this.itmRpcService = itmRpcService;
93 this.entityOwnershipService = entityOwnershipService;
94 this.l2GatewayConnectionUtils = elanUtils.getL2GatewayConnectionUtils();
98 registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
102 protected InstanceIdentifier<PhysicalSwitchAugmentation> getWildCardPath() {
103 return InstanceIdentifier.create(NetworkTopology.class)
104 .child(Topology.class, new TopologyKey(HwvtepSouthboundConstants.HWVTEP_TOPOLOGY_ID)).child(Node.class)
105 .augmentation(PhysicalSwitchAugmentation.class);
109 protected HwvtepPhysicalSwitchListener getDataTreeChangeListener() {
110 return HwvtepPhysicalSwitchListener.this;
114 protected void removed(InstanceIdentifier<PhysicalSwitchAugmentation> identifier,
115 PhysicalSwitchAugmentation phySwitchDeleted) {
116 NodeId nodeId = getNodeId(identifier);
117 String psName = phySwitchDeleted.getHwvtepNodeName().getValue();
118 LOG.info("Received physical switch {} removed event for node {}", psName, nodeId.getValue());
120 L2GatewayDevice l2GwDevice = L2GatewayCacheUtils.getL2DeviceFromCache(psName);
121 if (l2GwDevice != null) {
122 if (!L2GatewayConnectionUtils.isGatewayAssociatedToL2Device(l2GwDevice)) {
123 L2GatewayCacheUtils.removeL2DeviceFromCache(psName);
124 LOG.debug("{} details removed from L2Gateway Cache", psName);
125 InstanceIdentifier<Node> iid =
126 HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(l2GwDevice.getHwvtepNodeId()));
127 boolean deleteNode = true;
128 if (hwvtepHACache.isHAParentNode(iid)) {
129 Optional<Node> nodeOptional = null;
131 nodeOptional = dataBroker.newReadWriteTransaction().read(
132 LogicalDatastoreType.CONFIGURATION, iid).checkedGet();
133 } catch (ReadFailedException e) {
134 nodeOptional = Optional.absent();
136 if (nodeOptional.isPresent()) {
137 Node node = nodeOptional.get();
138 NodeBuilder nodeBuilder = new NodeBuilder();
139 HwvtepGlobalAugmentationBuilder builder = new HwvtepGlobalAugmentationBuilder();
140 HwvtepGlobalAugmentation orig = node.getAugmentation(HwvtepGlobalAugmentation.class);
143 builder.setSwitches(orig.getSwitches());
144 builder.setManagers(orig.getManagers());
145 nodeBuilder.setKey(node.getKey());
146 nodeBuilder.setNodeId(node.getNodeId());
147 nodeBuilder.addAugmentation(HwvtepGlobalAugmentation.class, builder.build());
148 MDSALUtil.syncWrite(this.dataBroker, LogicalDatastoreType.CONFIGURATION,
149 iid, nodeBuilder.build());
154 MDSALUtil.syncDelete(this.dataBroker, LogicalDatastoreType.CONFIGURATION,
155 HwvtepSouthboundUtils.createInstanceIdentifier(new NodeId(l2GwDevice.getHwvtepNodeId())));
157 MDSALUtil.syncDelete(this.dataBroker, LogicalDatastoreType.CONFIGURATION,
158 HwvtepSouthboundUtils.createInstanceIdentifier(nodeId));
160 LOG.debug("{} details are not removed from L2Gateway Cache as it has L2Gateway reference", psName);
163 l2GwDevice.setConnected(false);
164 ElanL2GwCacheUtils.removeL2GatewayDeviceFromAllElanCache(psName);
166 LOG.error("Unable to find L2 Gateway details for {}", psName);
171 protected void updated(InstanceIdentifier<PhysicalSwitchAugmentation> identifier,
172 PhysicalSwitchAugmentation phySwitchBefore, PhysicalSwitchAugmentation phySwitchAfter) {
173 NodeId nodeId = getNodeId(identifier);
174 LOG.trace("Received PhysicalSwitch Update Event for node {}: PhysicalSwitch Before: {}, "
175 + "PhysicalSwitch After: {}", nodeId.getValue(), phySwitchBefore, phySwitchAfter);
176 String psName = phySwitchBefore.getHwvtepNodeName().getValue();
177 LOG.info("Received physical switch {} update event for node {}", psName, nodeId.getValue());
179 if (isTunnelIpNewlyConfigured(phySwitchBefore, phySwitchAfter)) {
180 final L2GatewayDevice l2GwDevice =
181 updateL2GatewayCache(psName, phySwitchAfter.getManagedBy(), phySwitchAfter.getTunnelIps());
182 handleAdd(l2GwDevice);
184 LOG.debug("Other updates in physical switch {} for node {}", psName, nodeId.getValue());
185 // TODO: handle tunnel ip change
190 protected void added(InstanceIdentifier<PhysicalSwitchAugmentation> identifier,
191 final PhysicalSwitchAugmentation phySwitchAdded) {
192 if (phySwitchAdded.getManagedBy() == null) {
193 LOG.info("managed by field is missing ");
196 InstanceIdentifier<Node> globalNodeId = (InstanceIdentifier<Node>)phySwitchAdded.getManagedBy().getValue();
197 NodeId nodeId = getNodeId(identifier);
198 final String psName = phySwitchAdded.getHwvtepNodeName().getValue();
199 LOG.info("Received physical switch {} added event received for node {}", psName, nodeId.getValue());
202 if (updateHACacheIfHANode(dataBroker, globalNodeId)) {
203 updateL2GatewayCache(psName, new HwvtepGlobalRef(hwvtepHACache.getParent(globalNodeId)),
204 phySwitchAdded.getTunnelIps());
207 } catch (ExecutionException e) {
208 LOG.error("Failed to read operational node {}", globalNodeId);
209 //TODO add retry mechanism
210 } catch (InterruptedException e) {
211 LOG.error("Failed to read operational node {}", globalNodeId);
212 //TODO add retry mechanism
214 L2GatewayDevice l2GwDevice =
215 updateL2GatewayCache(psName, phySwitchAdded.getManagedBy(), phySwitchAdded.getTunnelIps());
216 handleAdd(l2GwDevice);
219 boolean updateHACacheIfHANode(DataBroker broker, InstanceIdentifier<Node> globalNodeId)
220 throws ExecutionException, InterruptedException {
221 ReadWriteTransaction transaction = broker.newReadWriteTransaction();
222 Node node = transaction.read(LogicalDatastoreType.OPERATIONAL, globalNodeId).get().get();
223 HAOpClusteredListener.addToCacheIfHAChildNode(globalNodeId, node);
224 return hwvtepHACache.isHAEnabledDevice(globalNodeId);
233 private void handleAdd(L2GatewayDevice l2GwDevice) {
234 final String psName = l2GwDevice.getDeviceName();
235 final String hwvtepNodeId = l2GwDevice.getHwvtepNodeId();
236 Set<IpAddress> tunnelIps = l2GwDevice.getTunnelIps();
237 if (tunnelIps != null) {
238 for (final IpAddress tunnelIpAddr : tunnelIps) {
239 if (L2GatewayConnectionUtils.isGatewayAssociatedToL2Device(l2GwDevice)) {
240 LOG.debug("L2Gateway {} associated for {} physical switch; creating ITM tunnels for {}",
241 l2GwDevice.getL2GatewayIds(), psName, tunnelIpAddr);
243 // It's a pre-provision scenario
244 // Initiate ITM tunnel creation
245 ElanClusterUtils.runOnlyInLeaderNode(entityOwnershipService,
246 "handling Physical Switch add create itm tunnels ",
247 new Callable<List<ListenableFuture<Void>>>() {
249 public List<ListenableFuture<Void>> call() throws Exception {
250 ElanL2GatewayUtils.createItmTunnels(itmRpcService,
251 hwvtepNodeId, psName, tunnelIpAddr);
252 return Collections.emptyList();
256 // Initiate Logical switch creation for associated L2
257 // Gateway Connections
258 List<L2gatewayConnection> l2GwConns = L2GatewayConnectionUtils.getAssociatedL2GwConnections(
259 dataBroker, l2GwDevice.getL2GatewayIds());
260 if (l2GwConns != null) {
261 LOG.debug("L2GatewayConnections associated for {} physical switch", psName);
263 for (L2gatewayConnection l2GwConn : l2GwConns) {
264 LOG.trace("L2GatewayConnection {} changes executed on physical switch {}",
265 l2GwConn.getL2gatewayId(), psName);
267 l2GatewayConnectionUtils.addL2GatewayConnection(l2GwConn, psName);
270 // TODO handle deleted l2gw connections while the device is
278 private L2GatewayDevice updateL2GatewayCache(String psName, HwvtepGlobalRef globalRef, List<TunnelIps> tunnelIps) {
279 L2GatewayDevice l2GwDevice = L2GatewayCacheUtils.getL2DeviceFromCache(psName);
280 if (l2GwDevice == null) {
281 LOG.debug("{} details are not present in L2Gateway Cache; added now!", psName);
283 l2GwDevice = new L2GatewayDevice();
284 l2GwDevice.setDeviceName(psName);
285 L2GatewayCacheUtils.addL2DeviceToCache(psName, l2GwDevice);
287 LOG.debug("{} details are present in L2Gateway Cache and same reference used for updates", psName);
289 l2GwDevice.setConnected(true);
290 String hwvtepNodeId = getManagedByNodeId(globalRef);
291 l2GwDevice.setHwvtepNodeId(hwvtepNodeId);
293 if (tunnelIps != null && !tunnelIps.isEmpty()) {
294 for (TunnelIps tunnelIp : tunnelIps) {
295 IpAddress tunnelIpAddr = tunnelIp.getTunnelIpsKey();
296 l2GwDevice.addTunnelIp(tunnelIpAddr);
299 LOG.trace("L2Gateway cache updated with below details: {}", l2GwDevice);
304 * Gets the managed by node id.
308 * @return the managed by node id
310 private String getManagedByNodeId(HwvtepGlobalRef globalRef) {
311 InstanceIdentifier<?> instId = globalRef.getValue();
312 return instId.firstKeyOf(Node.class).getNodeId().getValue();
320 * @return the node id
322 private NodeId getNodeId(InstanceIdentifier<PhysicalSwitchAugmentation> identifier) {
323 return identifier.firstKeyOf(Node.class).getNodeId();
327 * Checks if is tunnel ip newly configured.
329 * @param phySwitchBefore
330 * the phy switch before
331 * @param phySwitchAfter
332 * the phy switch after
333 * @return true, if is tunnel ip newly configured
335 private boolean isTunnelIpNewlyConfigured(PhysicalSwitchAugmentation phySwitchBefore,
336 PhysicalSwitchAugmentation phySwitchAfter) {
337 return (phySwitchBefore.getTunnelIps() == null || phySwitchBefore.getTunnelIps().isEmpty())
338 && phySwitchAfter.getTunnelIps() != null && !phySwitchAfter.getTunnelIps().isEmpty();