f93010b1b10f33e747a9a61d4255a563b98b00b4
[netvirt.git] / vpnservice / elanmanager / elanmanager-impl / src / main / java / org / opendaylight / netvirt / elan / l2gw / listeners / HwvtepRemoteMcastMacListener.java
1 /*
2  * Copyright (c) 2016 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.listeners;
9
10 import java.util.List;
11 import java.util.concurrent.Callable;
12 import java.util.concurrent.atomic.AtomicBoolean;
13
14 import org.opendaylight.controller.md.sal.binding.api.ClusteredDataChangeListener;
15 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
16 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
17 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
18 import org.opendaylight.netvirt.elan.utils.ElanUtils;
19 import org.opendaylight.netvirt.elan.utils.ElanConstants;
20 import org.opendaylight.genius.datastoreutils.AsyncClusteredDataChangeListenerBase;
21 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
22 import org.opendaylight.netvirt.elan.l2gw.utils.ElanL2GatewayUtils;
23 import org.opendaylight.netvirt.neutronvpn.api.l2gw.L2GatewayDevice;
24 import org.opendaylight.genius.utils.SystemPropertyReader;
25 import org.opendaylight.genius.utils.hwvtep.HwvtepSouthboundUtils;
26 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.hwvtep.rev150901.hwvtep.global.attributes.RemoteMcastMacs;
29 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
30 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 import com.google.common.base.Optional;
35 import com.google.common.util.concurrent.ListenableFuture;
36
37 /**
38  * The listener class for listening to {@code RemoteMcastMacs}
39  * add/delete/update.
40  *
41  * @see RemoteMcastMacs
42  */
43 public class HwvtepRemoteMcastMacListener
44         extends AsyncClusteredDataChangeListenerBase<RemoteMcastMacs, HwvtepRemoteMcastMacListener> {
45
46     /** The Constant LOG. */
47     private static final Logger LOG = LoggerFactory.getLogger(HwvtepRemoteMcastMacListener.class);
48
49     /** The node id. */
50     private NodeId nodeId;
51
52     private List<IpAddress> expectedPhyLocatorIps;
53
54     private final DataBroker broker;
55     private final ElanUtils elanUtils;
56
57     String logicalSwitchName;
58
59     AtomicBoolean executeTask = new AtomicBoolean(true);
60
61     Callable<List<ListenableFuture<Void>>> taskToRun;
62
63     private final DataStoreJobCoordinator dataStoreJobCoordinator = DataStoreJobCoordinator.getInstance();
64
65     /**
66      * Instantiates a new remote mcast mac listener.
67      *
68      * @param broker                the mdsal databroker reference
69      * @param elanUtils             elan utils
70      * @param logicalSwitchName     the logical switch name
71      * @param l2GatewayDevice       the l2 gateway device
72      * @param expectedPhyLocatorIps the expected phy locator ips
73      * @param task                  the task to be run upon data presence
74      * @throws Exception            the exception
75      */
76     public HwvtepRemoteMcastMacListener(DataBroker broker, ElanUtils elanUtils, String logicalSwitchName,
77                                         L2GatewayDevice l2GatewayDevice,
78                                         List<IpAddress> expectedPhyLocatorIps,
79                                         Callable<List<ListenableFuture<Void>>> task) throws Exception {
80         super(RemoteMcastMacs.class, HwvtepRemoteMcastMacListener.class);
81         this.elanUtils = elanUtils;
82         this.nodeId = new NodeId(l2GatewayDevice.getHwvtepNodeId());
83         this.broker = broker;
84         this.taskToRun = task;
85         this.logicalSwitchName = logicalSwitchName;
86         this.expectedPhyLocatorIps = expectedPhyLocatorIps;
87         LOG.info("registering the listener for mcast mac ");
88         registerListener(LogicalDatastoreType.OPERATIONAL, broker);
89         LOG.info("registered the listener for mcast mac ");
90         if (isDataPresentInOpDs(getWildCardPath())) {
91             LOG.info("mcast mac already present running the task ");
92             if (executeTask.compareAndSet(true, false)) {
93                 runTask();
94             }
95         }
96     }
97
98     private boolean isDataPresentInOpDs(InstanceIdentifier<RemoteMcastMacs> path) throws Exception {
99         Optional<RemoteMcastMacs> mac = null;
100         try {
101             mac = elanUtils.read(broker, LogicalDatastoreType.OPERATIONAL, path);
102         } catch (Throwable e) {
103         }
104         if (mac == null || !mac.isPresent()) {
105             return false;
106         }
107         if (this.expectedPhyLocatorIps != null && !this.expectedPhyLocatorIps.isEmpty()) {
108             RemoteMcastMacs remoteMcastMac = mac.get();
109             if (remoteMcastMac.getLocatorSet() == null || remoteMcastMac.getLocatorSet().isEmpty()) {
110                 return false;
111             }
112             for (IpAddress ip : this.expectedPhyLocatorIps) {
113                 boolean ipExists = ElanL2GatewayUtils.checkIfPhyLocatorAlreadyExistsInRemoteMcastEntry(this.nodeId,
114                         remoteMcastMac, ip);
115                 if (!ipExists) {
116                     LOG.trace("IP [{}] not found in RemoteMcastMacs for node [{}]", String.valueOf(ip.getValue()),
117                             this.nodeId.getValue());
118                     return false;
119                 }
120             }
121         }
122         return true;
123     }
124
125     /*
126      * (non-Javadoc)
127      *
128      * @see
129      * org.opendaylight.genius.datastoreutils.AsyncDataChangeListenerBase#
130      * getWildCardPath()
131      */
132     @Override
133     public InstanceIdentifier<RemoteMcastMacs> getWildCardPath() {
134         return HwvtepSouthboundUtils.createRemoteMcastMacsInstanceIdentifier(nodeId,
135                 logicalSwitchName, new MacAddress(ElanConstants.UNKNOWN_DMAC));
136     }
137
138     /*
139      * (non-Javadoc)
140      *
141      * @see
142      * org.opendaylight.genius.datastoreutils.AsyncDataChangeListenerBase#
143      * getDataChangeListener()
144      */
145     @Override
146     protected ClusteredDataChangeListener getDataChangeListener() {
147         return HwvtepRemoteMcastMacListener.this;
148     }
149
150     /*
151      * (non-Javadoc)
152      *
153      * @see
154      * org.opendaylight.genius.datastoreutils.AsyncDataChangeListenerBase#
155      * getDataChangeScope()
156      */
157     @Override
158     protected AsyncDataBroker.DataChangeScope getDataChangeScope() {
159         return AsyncDataBroker.DataChangeScope.BASE;
160     }
161
162     /*
163      * (non-Javadoc)
164      *
165      * @see
166      * org.opendaylight.genius.datastoreutils.AsyncDataChangeListenerBase#
167      * remove(org.opendaylight.yangtools.yang.binding.InstanceIdentifier,
168      * org.opendaylight.yangtools.yang.binding.DataObject)
169      */
170     @Override
171     protected void remove(InstanceIdentifier<RemoteMcastMacs> identifier, RemoteMcastMacs deleted) {
172         LOG.trace("Received Remove DataChange Notification for identifier: {}, RemoteMcastMacs: {}", identifier,
173                 deleted);
174     }
175
176     /*
177      * (non-Javadoc)
178      *
179      * @see
180      * org.opendaylight.genius.datastoreutils.AsyncDataChangeListenerBase#
181      * update(org.opendaylight.yangtools.yang.binding.InstanceIdentifier,
182      * org.opendaylight.yangtools.yang.binding.DataObject,
183      * org.opendaylight.yangtools.yang.binding.DataObject)
184      */
185     @Override
186     protected void update(InstanceIdentifier<RemoteMcastMacs> identifier, RemoteMcastMacs old,
187             RemoteMcastMacs newdata) {
188         LOG.trace("Received Update DataChange Notification for identifier: {}, RemoteMcastMacs old: {}, new: {}."
189                 + "No Action Performed.", identifier, old, newdata);
190     }
191
192     /*
193      * (non-Javadoc)
194      *
195      * @see
196      * org.opendaylight.genius.datastoreutils.AsyncDataChangeListenerBase#
197      * add(org.opendaylight.yangtools.yang.binding.InstanceIdentifier,
198      * org.opendaylight.yangtools.yang.binding.DataObject)
199      */
200     @Override
201     protected void add(InstanceIdentifier<RemoteMcastMacs> identifier, RemoteMcastMacs mcastMac) {
202         LOG.debug("Received Add DataChange Notification for identifier: {}, RemoteMcastMacs: {}", identifier, mcastMac);
203         // No isDataPresentInOpDs check is done as assuming all the expected phy
204         // locator ips will be available during add
205         if (executeTask.compareAndSet(true, false)) {
206             runTask();
207         }
208     }
209
210     void runTask() {
211         try {
212
213             String jobKey = ElanL2GatewayUtils.getL2GatewayConnectionJobKey(nodeId.getValue(), nodeId.getValue());
214             dataStoreJobCoordinator.enqueueJob(jobKey, taskToRun, SystemPropertyReader.getDataStoreJobCoordinatorMaxRetries());
215         } catch (Exception e) {
216             LOG.error("Failed to handle remote mcast mac - add: {}", e);
217         } finally {
218             try {
219                 close();
220             } catch (Exception e) {
221                 LOG.warn("Failed to close McastMacSwitchListener: {}", e);
222             }
223         }
224     }
225 }