Remove redundant names in paths
[netvirt.git] / natservice / impl / src / main / java / org / opendaylight / netvirt / natservice / internal / NatInterfaceStateChangeListener.java
1 /*
2  * Copyright (c) 2016 - 2017 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.natservice.internal;
9
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;
36
37 @Singleton
38 public class NatInterfaceStateChangeListener
39     extends AsyncDataTreeChangeListenerBase<Interface, NatInterfaceStateChangeListener> {
40
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;
46
47     @Inject
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;
54     }
55
56     @Override
57     @PostConstruct
58     public void init() {
59         LOG.info("{} init", getClass().getSimpleName());
60         registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
61     }
62
63     @Override
64     protected InstanceIdentifier<Interface> getWildCardPath() {
65         return InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
66     }
67
68     @Override
69     protected NatInterfaceStateChangeListener getDataTreeChangeListener() {
70         return NatInterfaceStateChangeListener.this;
71     }
72
73     @Override
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());
80             return;
81         }
82
83         NatInterfaceStateAddWorker natIfaceStateAddWorker = new NatInterfaceStateAddWorker(intrf);
84         coordinator.enqueueJob(NAT_DS + "-" + intrf.getName(), natIfaceStateAddWorker);
85     }
86
87     @Override
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());
94             return;
95         }
96
97         NatInterfaceStateRemoveWorker natIfaceStateRemoveWorker = new NatInterfaceStateRemoveWorker(intrf);
98         coordinator.enqueueJob(NAT_DS + "-" + intrf.getName(), natIfaceStateRemoveWorker);
99     }
100
101     @Override
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());
108             return;
109         }
110
111         NatInterfaceStateUpdateWorker natIfaceStateupdateWorker = new NatInterfaceStateUpdateWorker(original,update);
112         coordinator.enqueueJob(NAT_DS + "-" + update.getName(), natIfaceStateupdateWorker);
113     }
114
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);
122             return;
123         }
124         NatUtil.addToNeutronRouterDpnsMap(dataBroker, routerName, interfaceName, dpId, writeOperTxn);
125         NatUtil.addToDpnRoutersMap(dataBroker, routerName, interfaceName, dpId, writeOperTxn);
126     }
127
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,
134                 writeOperTxn);
135     }
136
137     private class NatInterfaceStateAddWorker implements Callable<List<ListenableFuture<Void>>> {
138         Interface iface;
139
140         NatInterfaceStateAddWorker(Interface iface) {
141             this.iface = iface;
142         }
143
144         @Override
145         @SuppressWarnings("checkstyle:IllegalCatch")
146         public List<ListenableFuture<Void>> call() {
147             List<ListenableFuture<Void>> futures = new ArrayList<>();
148             final String interfaceName = iface.getName();
149             try {
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());
161                 } else {
162                     LOG.info("call : Unable to process add for interface {}", interfaceName);
163                 }
164             } catch (Exception e) {
165                 LOG.error("call : Exception caught in Interface {} Operational State Up event",
166                         interfaceName, e);
167             }
168             return futures;
169         }
170     }
171
172     private class NatInterfaceStateRemoveWorker implements Callable<List<ListenableFuture<Void>>> {
173         Interface iface;
174
175         NatInterfaceStateRemoveWorker(Interface iface) {
176             this.iface = iface;
177         }
178
179         @Override
180         @SuppressWarnings("checkstyle:IllegalCatch")
181         public List<ListenableFuture<Void>> call() {
182             final String interfaceName = iface.getName();
183             List<ListenableFuture<Void>> futures = new ArrayList<>();
184             try {
185                 LOG.trace("call : Received interface {} PORT DOWN or REMOVE event", interfaceName);
186                 BigInteger dpId = null;
187                 try {
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);
198                         return futures;
199                     }
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();
209                             break;
210                         }
211                     }
212                 }
213                 if (dpId == null || dpId.equals(BigInteger.ZERO)) {
214                     LOG.error("call : Unable to get DPN ID for the Interface {}", interfaceName);
215                     return futures;
216                 }
217                 WriteTransaction writeOperTxn = dataBroker.newWriteOnlyTransaction();
218                 RouterInterface routerInterface = NatUtil.getConfiguredRouterInterface(dataBroker, interfaceName);
219                 if (routerInterface != null) {
220                     handleRouterInterfacesDownEvent(routerInterface.getRouterName(), interfaceName, dpId, writeOperTxn);
221                 }
222                 futures.add(writeOperTxn.submit());
223             } catch (Exception e) {
224                 LOG.error("call : Exception observed in handling deletion of VPN Interface {}.", interfaceName, e);
225             }
226             return futures;
227         }
228     }
229
230     private class NatInterfaceStateUpdateWorker implements Callable<List<ListenableFuture<Void>>> {
231         Interface original;
232         Interface update;
233
234         NatInterfaceStateUpdateWorker(Interface original, Interface update) {
235             this.original = original;
236             this.update = update;
237         }
238
239         @Override
240         @SuppressWarnings("checkstyle:IllegalCatch")
241         public List<ListenableFuture<Void>> call() {
242             List<ListenableFuture<Void>> futures = new ArrayList<>();
243             try {
244                 final String interfaceName = update.getName();
245                 LOG.trace("call : Received interface {} state change event", interfaceName);
246                 BigInteger dpId = null;
247                 try {
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);
258                         return futures;
259                     }
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();
269                             break;
270                         }
271                     }
272                 }
273                 if (dpId == null || dpId.equals(BigInteger.ZERO)) {
274                     LOG.error("call : Unable to get DPN ID for the Interface {}", interfaceName);
275                     return futures;
276                 }
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);
297                         }
298                     }
299                 }
300                 futures.add(writeOperTxn.submit());
301             } catch (Exception e) {
302                 LOG.error("call : Exception observed in handling updation of VPN Interface {}.", update.getName(), e);
303             }
304             return futures;
305         }
306     }
307 }