2 * Copyright (c) 2016 - 2017 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.natservice.internal;
10 import com.google.common.base.Optional;
11 import com.google.common.util.concurrent.ListenableFuture;
12 import java.math.BigInteger;
13 import java.util.ArrayList;
14 import java.util.List;
15 import java.util.concurrent.Callable;
16 import javax.annotation.PostConstruct;
17 import javax.inject.Inject;
18 import javax.inject.Singleton;
19 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
20 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
23 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
24 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
25 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
26 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.vpn._interface.VpnInstanceNames;
27 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.L2vlan;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.router.interfaces.RouterInterface;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntry;
33 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
38 public class NatInterfaceStateChangeListener
39 extends AsyncDataTreeChangeListenerBase<Interface, NatInterfaceStateChangeListener> {
41 private static final Logger LOG = LoggerFactory.getLogger(NatInterfaceStateChangeListener.class);
42 private static final String NAT_DS = "NATDS";
43 private final DataBroker dataBroker;
44 private final OdlInterfaceRpcService odlInterfaceRpcService;
45 private final JobCoordinator coordinator;
48 public NatInterfaceStateChangeListener(final DataBroker dataBroker,
49 final OdlInterfaceRpcService odlInterfaceRpcService, final JobCoordinator coordinator) {
50 super(Interface.class, NatInterfaceStateChangeListener.class);
51 this.dataBroker = dataBroker;
52 this.odlInterfaceRpcService = odlInterfaceRpcService;
53 this.coordinator = coordinator;
59 LOG.info("{} init", getClass().getSimpleName());
60 registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
64 protected InstanceIdentifier<Interface> getWildCardPath() {
65 return InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
69 protected NatInterfaceStateChangeListener getDataTreeChangeListener() {
70 return NatInterfaceStateChangeListener.this;
74 // TODO Clean up the exception handling
75 @SuppressWarnings("checkstyle:IllegalCatch")
76 protected void add(InstanceIdentifier<Interface> identifier, Interface intrf) {
77 LOG.trace("add : Interface {} up event received", intrf);
78 if (!L2vlan.class.equals(intrf.getType())) {
79 LOG.debug("add : Interface {} is not Vlan Interface.Ignoring", intrf.getName());
83 NatInterfaceStateAddWorker natIfaceStateAddWorker = new NatInterfaceStateAddWorker(intrf);
84 coordinator.enqueueJob(NAT_DS + "-" + intrf.getName(), natIfaceStateAddWorker);
88 // TODO Clean up the exception handling
89 @SuppressWarnings("checkstyle:IllegalCatch")
90 protected void remove(InstanceIdentifier<Interface> identifier, Interface intrf) {
91 LOG.trace("remove : Interface {} removed event received", intrf);
92 if (!L2vlan.class.equals(intrf.getType())) {
93 LOG.debug("remove : Interface {} is not Vlan Interface.Ignoring", intrf.getName());
97 NatInterfaceStateRemoveWorker natIfaceStateRemoveWorker = new NatInterfaceStateRemoveWorker(intrf);
98 coordinator.enqueueJob(NAT_DS + "-" + intrf.getName(), natIfaceStateRemoveWorker);
102 // TODO Clean up the exception handling
103 @SuppressWarnings("checkstyle:IllegalCatch")
104 protected void update(InstanceIdentifier<Interface> identifier, Interface original, Interface update) {
105 LOG.trace("update : Operation Interface update event - Old: {}, New: {}", original, update);
106 if (!L2vlan.class.equals(update.getType())) {
107 LOG.debug("update : Interface {} is not Vlan Interface.Ignoring", update.getName());
111 NatInterfaceStateUpdateWorker natIfaceStateupdateWorker = new NatInterfaceStateUpdateWorker(original,update);
112 coordinator.enqueueJob(NAT_DS + "-" + update.getName(), natIfaceStateupdateWorker);
115 void handleRouterInterfacesUpEvent(String routerName, String interfaceName, WriteTransaction writeOperTxn) {
116 LOG.debug("handleRouterInterfacesUpEvent : Handling UP event for router interface {} in Router {}",
117 interfaceName, routerName);
118 BigInteger dpId = NatUtil.getDpnForInterface(odlInterfaceRpcService, interfaceName);
119 if (dpId.equals(BigInteger.ZERO)) {
120 LOG.warn("handleRouterInterfacesUpEvent : Could not retrieve dp id for interface {} to handle router {} "
121 + "association model", interfaceName, routerName);
124 NatUtil.addToNeutronRouterDpnsMap(dataBroker, routerName, interfaceName, dpId, writeOperTxn);
125 NatUtil.addToDpnRoutersMap(dataBroker, routerName, interfaceName, dpId, writeOperTxn);
128 void handleRouterInterfacesDownEvent(String routerName, String interfaceName, BigInteger dpnId,
129 WriteTransaction writeOperTxn) {
130 LOG.debug("handleRouterInterfacesDownEvent : Handling DOWN event for router Interface {} in Router {}",
131 interfaceName, routerName);
132 NatUtil.removeFromNeutronRouterDpnsMap(dataBroker, routerName, interfaceName, dpnId, writeOperTxn);
133 NatUtil.removeFromDpnRoutersMap(dataBroker, routerName, interfaceName, dpnId, odlInterfaceRpcService,
137 private class NatInterfaceStateAddWorker implements Callable<List<ListenableFuture<Void>>> {
140 NatInterfaceStateAddWorker(Interface iface) {
145 @SuppressWarnings("checkstyle:IllegalCatch")
146 public List<ListenableFuture<Void>> call() {
147 List<ListenableFuture<Void>> futures = new ArrayList<>();
148 final String interfaceName = iface.getName();
150 LOG.trace("call : Received interface {} PORT UP OR ADD event ", interfaceName);
151 // We service only VM interfaces and Router interfaces here. We do not service Tunnel Interfaces here.
152 // Tunnel events are directly serviced by TunnelInterfacesStateListener present as part of
153 // VpnInterfaceManager
154 RouterInterface routerInterface = NatUtil.getConfiguredRouterInterface(dataBroker, interfaceName);
155 if (routerInterface != null) {
156 String routerName = routerInterface.getRouterName();
157 LOG.debug("call : Router Name {} ", routerInterface.getRouterName());
158 WriteTransaction writeOperTxn = dataBroker.newWriteOnlyTransaction();
159 handleRouterInterfacesUpEvent(routerName, interfaceName, writeOperTxn);
160 futures.add(writeOperTxn.submit());
162 LOG.info("call : Unable to process add for interface {}", interfaceName);
164 } catch (Exception e) {
165 LOG.error("call : Exception caught in Interface {} Operational State Up event",
172 private class NatInterfaceStateRemoveWorker implements Callable<List<ListenableFuture<Void>>> {
175 NatInterfaceStateRemoveWorker(Interface iface) {
180 @SuppressWarnings("checkstyle:IllegalCatch")
181 public List<ListenableFuture<Void>> call() {
182 final String interfaceName = iface.getName();
183 List<ListenableFuture<Void>> futures = new ArrayList<>();
185 LOG.trace("call : Received interface {} PORT DOWN or REMOVE event", interfaceName);
186 BigInteger dpId = null;
188 dpId = NatUtil.getDpIdFromInterface(iface);
189 } catch (Exception e) {
190 LOG.error("call : Unable to retrieve DPNID from Interface operational data store for "
191 + "Interface {}.", interfaceName, e);
192 InstanceIdentifier<VpnInterface> id = NatUtil.getVpnInterfaceIdentifier(interfaceName);
193 Optional<VpnInterface> cfgVpnInterface =
194 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(
195 dataBroker, LogicalDatastoreType.CONFIGURATION, id);
196 if (!cfgVpnInterface.isPresent()) {
197 LOG.warn("call : Interface {} is not a VPN Interface, ignoring.", interfaceName);
200 for (VpnInstanceNames vpnInterfaceVpnInstance : cfgVpnInterface.get().getVpnInstanceNames()) {
201 String vpnName = vpnInterfaceVpnInstance.getVpnName();
202 InstanceIdentifier<VpnInterfaceOpDataEntry> idOper = NatUtil
203 .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
204 Optional<VpnInterfaceOpDataEntry> optVpnInterface =
205 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(
206 dataBroker, LogicalDatastoreType.CONFIGURATION, idOper);
207 if (optVpnInterface.isPresent()) {
208 dpId = optVpnInterface.get().getDpnId();
213 if (dpId == null || dpId.equals(BigInteger.ZERO)) {
214 LOG.error("call : Unable to get DPN ID for the Interface {}", interfaceName);
217 WriteTransaction writeOperTxn = dataBroker.newWriteOnlyTransaction();
218 RouterInterface routerInterface = NatUtil.getConfiguredRouterInterface(dataBroker, interfaceName);
219 if (routerInterface != null) {
220 handleRouterInterfacesDownEvent(routerInterface.getRouterName(), interfaceName, dpId, writeOperTxn);
222 futures.add(writeOperTxn.submit());
223 } catch (Exception e) {
224 LOG.error("call : Exception observed in handling deletion of VPN Interface {}.", interfaceName, e);
230 private class NatInterfaceStateUpdateWorker implements Callable<List<ListenableFuture<Void>>> {
234 NatInterfaceStateUpdateWorker(Interface original, Interface update) {
235 this.original = original;
236 this.update = update;
240 @SuppressWarnings("checkstyle:IllegalCatch")
241 public List<ListenableFuture<Void>> call() {
242 List<ListenableFuture<Void>> futures = new ArrayList<>();
244 final String interfaceName = update.getName();
245 LOG.trace("call : Received interface {} state change event", interfaceName);
246 BigInteger dpId = null;
248 dpId = NatUtil.getDpIdFromInterface(update);
249 } catch (Exception e) {
250 LOG.error("call : Unable to retrieve DPN ID from Interface operational data "
251 + "store for Interface {}", update.getName(), e);
252 InstanceIdentifier<VpnInterface> id = NatUtil.getVpnInterfaceIdentifier(interfaceName);
253 Optional<VpnInterface> cfgVpnInterface =
254 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(
255 dataBroker, LogicalDatastoreType.CONFIGURATION, id);
256 if (!cfgVpnInterface.isPresent()) {
257 LOG.warn("call : Interface {} is not a VPN Interface, ignoring.", interfaceName);
260 for (VpnInstanceNames vpnInterfaceVpnInstance : cfgVpnInterface.get().getVpnInstanceNames()) {
261 String vpnName = vpnInterfaceVpnInstance.getVpnName();
262 InstanceIdentifier<VpnInterfaceOpDataEntry> idOper = NatUtil
263 .getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
264 Optional<VpnInterfaceOpDataEntry> optVpnInterface =
265 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(
266 dataBroker, LogicalDatastoreType.OPERATIONAL, idOper);
267 if (optVpnInterface.isPresent()) {
268 dpId = optVpnInterface.get().getDpnId();
273 if (dpId == null || dpId.equals(BigInteger.ZERO)) {
274 LOG.error("call : Unable to get DPN ID for the Interface {}", interfaceName);
277 LOG.debug("call : DPN ID {} for the interface {} ", dpId, interfaceName);
278 WriteTransaction writeOperTxn = dataBroker.newWriteOnlyTransaction();
279 RouterInterface routerInterface = NatUtil.getConfiguredRouterInterface(dataBroker, interfaceName);
280 if (routerInterface != null) {
281 Interface.OperStatus originalOperStatus = original.getOperStatus();
282 Interface.OperStatus updateOperStatus = update.getOperStatus();
283 if (originalOperStatus != updateOperStatus) {
284 String routerName = routerInterface.getRouterName();
285 if (updateOperStatus == Interface.OperStatus.Unknown) {
286 LOG.debug("call : DPN {} connnected to the interface {} has gone down."
287 + "Hence clearing the dpn-vpninterfaces-list entry from the"
288 + " neutron-router-dpns model in the ODL:L3VPN", dpId, interfaceName);
289 // If the interface state is unknown, it means that the corresponding DPN has gone down.
290 // So remove the dpn-vpninterfaces-list from the neutron-router-dpns model.
291 NatUtil.removeFromNeutronRouterDpnsMap(dataBroker, routerName, dpId, writeOperTxn);
292 } else if (updateOperStatus == Interface.OperStatus.Up) {
293 LOG.debug("call : DPN {} connnected to the interface {} has come up. Hence adding"
294 + " the dpn-vpninterfaces-list entry from the neutron-router-dpns model"
295 + " in the ODL:L3VPN", dpId, interfaceName);
296 handleRouterInterfacesUpEvent(routerName, interfaceName, writeOperTxn);
300 futures.add(writeOperTxn.submit());
301 } catch (Exception e) {
302 LOG.error("call : Exception observed in handling updation of VPN Interface {}.", update.getName(), e);