820cffd24a2f0980fb5d0af3377aadcb257ad71c
[netvirt.git] / vpnservice / vpnmanager / vpnmanager-impl / src / main / java / org / opendaylight / netvirt / vpnmanager / InterfaceStateChangeListener.java
1 /*
2  * Copyright (c) 2015 - 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.vpnmanager;
9
10 import com.google.common.base.Optional;
11
12 import com.google.common.util.concurrent.CheckedFuture;
13 import com.google.common.util.concurrent.ListenableFuture;
14 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
15 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
16 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
17 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
18 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
19 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
20 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
21 import org.opendaylight.netvirt.vpnmanager.utilities.InterfaceUtils;
22 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
23 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
25 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.router.interfaces.RouterInterface;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
31 import org.opendaylight.yangtools.concepts.ListenerRegistration;
32 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 import java.math.BigInteger;
37 import java.util.List;
38 import java.util.concurrent.Callable;
39 import java.util.concurrent.ExecutionException;
40
41 public class InterfaceStateChangeListener extends AbstractDataChangeListener<Interface> implements AutoCloseable {
42     private static final Logger LOG = LoggerFactory.getLogger(InterfaceStateChangeListener.class);
43     private ListenerRegistration<DataChangeListener> listenerRegistration;
44     private final DataBroker dataBroker;
45     private final VpnInterfaceManager vpnInterfaceManager;
46
47     public InterfaceStateChangeListener(final DataBroker dataBroker, VpnInterfaceManager vpnInterfaceManager) {
48         super(Interface.class);
49         this.dataBroker = dataBroker;
50         this.vpnInterfaceManager = vpnInterfaceManager;
51     }
52
53     public void start() {
54         LOG.info("{} start", getClass().getSimpleName());
55         listenerRegistration = dataBroker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
56                 getWildCardPath(), this, DataChangeScope.SUBTREE);
57     }
58
59     private InstanceIdentifier<Interface> getWildCardPath() {
60         return InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
61     }
62
63     @Override
64     public void close() throws Exception {
65         if (listenerRegistration != null) {
66             listenerRegistration.close();
67             listenerRegistration = null;
68         }
69         LOG.info("{} close", getClass().getSimpleName());
70     }
71
72     @Override
73     protected void add(InstanceIdentifier<Interface> identifier, Interface intrf) {
74         LOG.trace("Received interface {} add event", intrf);
75         try {
76             final String interfaceName = intrf.getName();
77             LOG.info("Received interface add event for interface {} ", interfaceName);
78             org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface
79                     configInterface = InterfaceUtils.getInterface(dataBroker, interfaceName);
80             if (configInterface != null) {
81                 if (!configInterface.getType().equals(Tunnel.class)) {
82                     // We service only VM interfaces and Router interfaces here.
83                     // We donot service Tunnel Interfaces here.
84                     // Tunnel events are directly serviced
85                     // by TunnelInterfacesStateListener present as part of VpnInterfaceManager
86                     LOG.debug("Config Interface Name {}", configInterface.getName());
87                     final VpnInterface vpnInterface = VpnUtil.getConfiguredVpnInterface(dataBroker, interfaceName);
88                     if (vpnInterface != null) {
89                         LOG.debug("VPN Interface Name {}", vpnInterface);
90                         final BigInteger dpnId = InterfaceUtils.getDpIdFromInterface(intrf);
91                         final int ifIndex = intrf.getIfIndex();
92                         DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
93                         dataStoreCoordinator.enqueueJob("VPNINTERFACE-" + intrf.getName(),
94                                 new Callable<List<ListenableFuture<Void>>>() {
95                                     @Override
96                                     public List<ListenableFuture<Void>> call() throws Exception {
97                                         WriteTransaction writeConfigTxn = dataBroker.newWriteOnlyTransaction();
98                                         WriteTransaction writeOperTxn = dataBroker.newWriteOnlyTransaction();
99                                         WriteTransaction writeInvTxn = dataBroker.newWriteOnlyTransaction();
100                                         vpnInterfaceManager.processVpnInterfaceUp(dpnId, vpnInterface, ifIndex, false,
101                                                 writeConfigTxn, writeOperTxn, writeInvTxn);
102                                         String routerName = VpnUtil.getNeutronRouterFromInterface(dataBroker, interfaceName);
103                                         if (routerName != null) {
104                                             LOG.debug("Router Name {} ", routerName);
105                                             handleRouterInterfacesUpEvent(routerName, interfaceName, writeOperTxn);
106                                         } else {
107                                             LOG.info("Unable to process add for interface {} for NAT service", interfaceName);
108                                         }
109                                         CheckedFuture<Void, TransactionCommitFailedException> futures = writeOperTxn.submit();
110                                         try {
111                                             futures.get();
112                                         } catch (InterruptedException | ExecutionException e) {
113                                             LOG.error("Error adding Oper data for interface {} to vpn {} on dpn {}", interfaceName,
114                                                     vpnInterface.getVpnInstanceName(), dpnId);
115                                             throw new RuntimeException(e.getMessage());
116                                         }
117                                         futures = writeConfigTxn.submit();
118                                         try {
119                                             futures.get();
120                                         } catch (InterruptedException | ExecutionException e) {
121                                             LOG.error("Error adding Config data for interface {} to vpn {} on dpn {}", interfaceName,
122                                                     vpnInterface.getVpnInstanceName(), dpnId);
123                                             throw new RuntimeException(e.getMessage());
124                                         }
125                                         futures = writeInvTxn.submit();
126                                         try {
127                                             futures.get();
128                                         } catch (InterruptedException | ExecutionException e) {
129                                             LOG.error("Error adding inventory/flow data for interface {} to vpn {} on dpn {}", interfaceName,
130                                                     vpnInterface.getVpnInstanceName(), dpnId);
131                                             throw new RuntimeException(e.getMessage());
132                                         }
133                                         LOG.warn("InterfaceStateChangeListner returning null while adding the " +
134                                                 "interface {}", interfaceName);
135                                         return null;
136                                     }
137                                 });
138                     }
139                 }
140             } else {
141                 LOG.error("Unable to process add for interface {} ," +
142                         "since Interface ConfigDS entry absent for the same", interfaceName);
143             }
144         } catch (Exception e) {
145           LOG.error("Exception caught in Interface Operational State Up event", e);
146         }
147     }
148
149     @Override
150     protected void remove(InstanceIdentifier<Interface> identifier, Interface intrf) {
151         LOG.trace("Received interface {} down event", intrf);
152         try {
153             final String interfaceName = intrf.getName();
154             LOG.info("Received port DOWN event for interface {} ", interfaceName);
155             if (intrf != null && intrf.getType() != null && intrf.getType().equals(Tunnel.class)) {
156                 //withdraw all prefixes in all vpns for this dpn from bgp
157                 // FIXME: Blocked until tunnel event[vxlan/gre] support is available
158                 // vpnInterfaceManager.updatePrefixesForDPN(dpId, VpnInterfaceManager.UpdateRouteAction.WITHDRAW_ROUTE);
159             } else {
160                 BigInteger dpId = BigInteger.ZERO;
161                 InstanceIdentifier<VpnInterface> id = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
162                 Optional<VpnInterface> optVpnInterface = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
163                 if (!optVpnInterface.isPresent()) {
164                     LOG.debug("Interface {} is not a vpninterface, ignoring.", intrf.getName());
165                     return;
166                 }
167                 final VpnInterface vpnInterface = optVpnInterface.get();
168                 try {
169                     dpId = InterfaceUtils.getDpIdFromInterface(intrf);
170                 } catch (Exception e){
171                     LOG.warn("Unable to retrieve dpnId from interface operational data store for interface {}. Fetching from vpn interface op data store. ", intrf.getName(), e);
172                     dpId = vpnInterface.getDpnId();
173                 }
174                 final BigInteger dpnId = dpId;
175                 final int ifIndex = intrf.getIfIndex();
176                 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
177                 dataStoreCoordinator.enqueueJob("VPNINTERFACE-" + intrf.getName(),
178                         new Callable<List<ListenableFuture<Void>>>() {
179                             @Override
180                             public List<ListenableFuture<Void>> call() throws Exception {
181                                 WriteTransaction writeOperTxn = dataBroker.newWriteOnlyTransaction();
182                                 WriteTransaction writeConfigTxn = dataBroker.newWriteOnlyTransaction();
183                                 WriteTransaction writeInvTxn = dataBroker.newWriteOnlyTransaction();
184                                 vpnInterfaceManager.processVpnInterfaceDown(dpnId, interfaceName, ifIndex, false, false,
185                                         writeConfigTxn, writeOperTxn, writeInvTxn);
186                                 RouterInterface routerInterface = VpnUtil.getConfiguredRouterInterface(dataBroker, interfaceName);
187                                 if (routerInterface != null) {
188                                     handleRouterInterfacesDownEvent(routerInterface.getRouterName(), interfaceName, dpnId, writeOperTxn);
189                                 }
190                                 CheckedFuture<Void, TransactionCommitFailedException> futures = writeOperTxn.submit();
191                                 try {
192                                     futures.get();
193                                 } catch (InterruptedException | ExecutionException e) {
194                                     LOG.error("Error removing Oper data for interface {} from vpn {} on dpn {}", interfaceName,
195                                             vpnInterface.getVpnInstanceName(), dpnId);
196                                     throw new RuntimeException(e.getMessage());
197                                 }
198                                 futures = writeConfigTxn.submit();
199                                 try {
200                                     futures.get();
201                                 } catch (InterruptedException | ExecutionException e) {
202                                     LOG.error("Error removing Config data for interface {} from vpn {} on dpn {}", interfaceName,
203                                             vpnInterface.getVpnInstanceName(), dpnId);
204                                     throw new RuntimeException(e.getMessage());
205                                 }
206                                 futures = writeInvTxn.submit();
207                                 try {
208                                     futures.get();
209                                 } catch (InterruptedException | ExecutionException e) {
210                                     LOG.error("Error removing Inventory/Flow data for interface {} from vpn {} on dpn {}", interfaceName,
211                                             vpnInterface.getVpnInstanceName(), dpnId);
212                                     throw new RuntimeException(e.getMessage());
213                                 }
214                                 return null;
215                             }
216                         });
217             }
218         } catch (Exception e) {
219             LOG.error("Exception observed in handling deletion of VPN Interface {}. ", intrf.getName(), e);
220         }
221     }
222
223     @Override
224     protected void update(InstanceIdentifier<Interface> identifier,
225                           Interface original, Interface update) {
226         LOG.trace("Operation Interface update event - Old: {}, New: {}", original, update);
227         final String interfaceName = update.getName();
228         if (original.getOperStatus().equals(Interface.OperStatus.Unknown) ||
229                 update.getOperStatus().equals(Interface.OperStatus.Unknown)){
230             LOG.debug("Interface {} state change is from/to UNKNOWN. Ignoring the update event.", interfaceName);
231             return;
232         }
233         final BigInteger dpnId = InterfaceUtils.getDpIdFromInterface(update);
234         final int ifIndex = update.getIfIndex();
235         if (update != null) {
236             if (!update.getType().equals(Tunnel.class)) {
237                 final VpnInterface vpnInterface = VpnUtil.getConfiguredVpnInterface(dataBroker, interfaceName);
238                 if (vpnInterface != null) {
239                     if (update.getOperStatus().equals(Interface.OperStatus.Up)) {
240                         DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
241                         dataStoreCoordinator.enqueueJob("VPNINTERFACE-" + interfaceName,
242                                 new Callable<List<ListenableFuture<Void>>>() {
243                                     @Override
244                                     public List<ListenableFuture<Void>> call() throws Exception {
245                                         WriteTransaction writeConfigTxn = dataBroker.newWriteOnlyTransaction();
246                                         WriteTransaction writeOperTxn = dataBroker.newWriteOnlyTransaction();
247                                         WriteTransaction writeInvTxn = dataBroker.newWriteOnlyTransaction();
248                                         vpnInterfaceManager.processVpnInterfaceUp(dpnId, vpnInterface, ifIndex, 
249                                                 true, writeConfigTxn, writeOperTxn, writeInvTxn);
250                                         CheckedFuture<Void, TransactionCommitFailedException> futures = writeOperTxn.submit();
251                                         try {
252                                             futures.get();
253                                         } catch (InterruptedException | ExecutionException e) {
254                                             LOG.error("Error updating oper data for interface {} in vpn {} on dpn {}", interfaceName,
255                                                     vpnInterface.getVpnInstanceName(), dpnId);
256                                             throw new RuntimeException(e.getMessage());
257                                         }
258                                         futures = writeConfigTxn.submit();
259                                         try {
260                                             futures.get();
261                                         } catch (InterruptedException | ExecutionException e) {
262                                             LOG.error("Error updating config data for interface {} in vpn {} on dpn {}", interfaceName,
263                                                     vpnInterface.getVpnInstanceName(), dpnId);
264                                             throw new RuntimeException(e.getMessage());
265                                         }
266                                         futures = writeInvTxn.submit();
267                                         try {
268                                             futures.get();
269                                         } catch (InterruptedException | ExecutionException e) {
270                                             LOG.error("Error adding inventory/flow data for interface {} to vpn {} on dpn {}", interfaceName,
271                                                     vpnInterface.getVpnInstanceName(), dpnId);
272                                             throw new RuntimeException(e.getMessage());
273                                         }
274                                         return null;
275                                     }
276                                 });
277                     } else if (update.getOperStatus().equals(Interface.OperStatus.Down)) {
278                         DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
279                         dataStoreCoordinator.enqueueJob(interfaceName,
280                                 new Callable<List<ListenableFuture<Void>>>() {
281                                     @Override
282                                     public List<ListenableFuture<Void>> call() throws Exception {
283                                         WriteTransaction writeConfigTxn = dataBroker.newWriteOnlyTransaction();
284                                         WriteTransaction writeOperTxn = dataBroker.newWriteOnlyTransaction();
285                                         WriteTransaction writeInvTxn = dataBroker.newWriteOnlyTransaction();
286                                         vpnInterfaceManager.processVpnInterfaceDown(dpnId, interfaceName, ifIndex, true, false,
287                                                 writeConfigTxn, writeOperTxn, writeInvTxn);
288                                         CheckedFuture<Void, TransactionCommitFailedException> futures = writeOperTxn.submit();
289                                         try {
290                                             futures.get();
291                                         } catch (InterruptedException | ExecutionException e) {
292                                             LOG.error("Error updating oper data for interface {} from vpn {} on dpn {}", interfaceName,
293                                                     vpnInterface.getVpnInstanceName(), dpnId);
294                                             throw new RuntimeException(e.getMessage());
295                                         }
296                                         futures = writeConfigTxn.submit();
297                                         try {
298                                             futures.get();
299                                         } catch (InterruptedException | ExecutionException e) {
300                                             LOG.error("Error updating config data for interface {} from vpn {} on dpn {}", interfaceName,
301                                                     vpnInterface.getVpnInstanceName(), dpnId);
302                                             throw new RuntimeException(e.getMessage());
303                                         }
304                                         futures = writeInvTxn.submit();
305                                         try {
306                                             futures.get();
307                                         } catch (InterruptedException | ExecutionException e) {
308                                             LOG.error("Error updating inventory/flow for interface {} from vpn {} on dpn {}", interfaceName,
309                                                     vpnInterface.getVpnInstanceName(), dpnId);
310                                             throw new RuntimeException(e.getMessage());
311                                         }
312                                         return null;
313                                     }
314                                 });
315                     }
316                 }
317             }
318         }
319     }
320
321     void handleRouterInterfacesUpEvent(String routerName, String interfaceName, WriteTransaction writeOperTxn) {
322         LOG.debug("Handling UP event for router interface {} in Router {}", interfaceName, routerName);
323         vpnInterfaceManager.addToNeutronRouterDpnsMap(routerName, interfaceName, writeOperTxn);
324     }
325
326     void handleRouterInterfacesDownEvent(String routerName, String interfaceName, BigInteger dpnId,
327                                          WriteTransaction writeOperTxn) {
328         LOG.debug("Handling DOWN event for router interface {} in Router {}", interfaceName, routerName);
329         vpnInterfaceManager.removeFromNeutronRouterDpnsMap(routerName, interfaceName, dpnId, writeOperTxn);
330     }
331
332 }