Bug 6863 - Router interfaces incorrectly include network interfaces
[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.ListenableFuture;
13 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
14 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
15 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
16 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
17 import org.opendaylight.netvirt.vpnmanager.utilities.InterfaceUtils;
18 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
19 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev140508.Tunnel;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.router.interfaces.RouterInterface;
24 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
27
28 import java.math.BigInteger;
29 import java.util.ArrayList;
30 import java.util.List;
31 import java.util.concurrent.Callable;
32
33 public class InterfaceStateChangeListener extends AsyncDataTreeChangeListenerBase<Interface,
34         InterfaceStateChangeListener> implements AutoCloseable {
35     private static final Logger LOG = LoggerFactory.getLogger(InterfaceStateChangeListener.class);
36     private final DataBroker dataBroker;
37     private final VpnInterfaceManager vpnInterfaceManager;
38
39     public InterfaceStateChangeListener(final DataBroker dataBroker, VpnInterfaceManager vpnInterfaceManager) {
40         super(Interface.class, InterfaceStateChangeListener.class);
41         this.dataBroker = dataBroker;
42         this.vpnInterfaceManager = vpnInterfaceManager;
43     }
44
45     public void start() {
46         LOG.info("{} start", getClass().getSimpleName());
47         registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
48     }
49
50
51     @Override
52     protected InstanceIdentifier<Interface> getWildCardPath() {
53         return InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
54     }
55
56     @Override
57     protected InterfaceStateChangeListener getDataTreeChangeListener() {
58         return InterfaceStateChangeListener.this;
59     }
60
61
62     @Override
63     protected void add(InstanceIdentifier<Interface> identifier, Interface intrf) {
64         LOG.trace("Received interface {} add event", intrf);
65         LOG.info("Received interface {} add event", intrf.getName());
66         try {
67             final String interfaceName = intrf.getName();
68             LOG.info("Received interface add event for interface {} ", interfaceName);
69             org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface
70                     configInterface = InterfaceUtils.getInterface(dataBroker, interfaceName);
71             if (configInterface != null) {
72                 if (!configInterface.getType().equals(Tunnel.class)) {
73                     // We service only VM interfaces and Router interfaces here.
74                     // We donot service Tunnel Interfaces here.
75                     // Tunnel events are directly serviced
76                     // by TunnelInterfacesStateListener present as part of VpnInterfaceManager
77                     LOG.debug("Config Interface Name {}", configInterface.getName());
78                     final VpnInterface vpnInterface = VpnUtil.getConfiguredVpnInterface(dataBroker, interfaceName);
79                     if (vpnInterface != null) {
80                         LOG.debug("VPN Interface Name {}", vpnInterface);
81                         BigInteger intfDpnId = BigInteger.ZERO;
82                         try {
83                             intfDpnId = InterfaceUtils.getDpIdFromInterface(intrf);
84                         } catch (Exception e){
85                             LOG.error("Unable to retrieve dpnId for interface {}. Process vpn interface add fail with exception {}.",
86                                     intrf.getName(), e);
87                             return;
88                         }
89                         final BigInteger dpnId = intfDpnId;
90                         final int ifIndex = intrf.getIfIndex();
91                         DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
92                         dataStoreCoordinator.enqueueJob("VPNINTERFACE-" + intrf.getName(),
93                                 new Callable<List<ListenableFuture<Void>>>() {
94                                     @Override
95                                     public List<ListenableFuture<Void>> call() throws Exception {
96                                         WriteTransaction writeConfigTxn = dataBroker.newWriteOnlyTransaction();
97                                         WriteTransaction writeOperTxn = dataBroker.newWriteOnlyTransaction();
98                                         WriteTransaction writeInvTxn = dataBroker.newWriteOnlyTransaction();
99                                         vpnInterfaceManager.processVpnInterfaceUp(dpnId, vpnInterface, ifIndex, false,
100                                                 writeConfigTxn, writeOperTxn, writeInvTxn);
101                                         String routerName = VpnUtil.getNeutronRouterFromInterface(dataBroker, interfaceName);
102                                         if (routerName != null) {
103                                             LOG.debug("Router Name {} ", routerName);
104                                             handleRouterInterfacesUpEvent(routerName, interfaceName, writeOperTxn);
105                                         } else {
106                                             LOG.info("Unable to process add for interface {} for NAT service", interfaceName);
107                                         }
108                                         List<ListenableFuture<Void>> futures = new ArrayList<ListenableFuture<Void>>();
109                                         futures.add(writeOperTxn.submit());
110                                         futures.add(writeConfigTxn.submit());
111                                         futures.add(writeInvTxn.submit());
112                                         return futures;
113                                     }
114                                 });
115                     }
116                 }
117             } else {
118                 LOG.error("Unable to process add for interface {} ," +
119                         "since Interface ConfigDS entry absent for the same", interfaceName);
120             }
121         } catch (Exception e) {
122           LOG.error("Exception caught in Interface Operational State Up event", e);
123         }
124     }
125
126     @Override
127     protected void remove(InstanceIdentifier<Interface> identifier, Interface intrf) {
128         LOG.trace("Received interface {} down event", intrf);
129         LOG.info("Received interface {} remove event", intrf.getName());
130         try {
131             final String interfaceName = intrf.getName();
132             LOG.info("Received port DOWN event for interface {} ", interfaceName);
133             if (intrf != null && intrf.getType() != null && !intrf.getType().equals(Tunnel.class)) {
134                 BigInteger dpId = BigInteger.ZERO;
135                 InstanceIdentifier<VpnInterface> id = VpnUtil.getVpnInterfaceIdentifier(interfaceName);
136                 Optional<VpnInterface> optVpnInterface = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);
137                 if (!optVpnInterface.isPresent()) {
138                     LOG.debug("Interface {} is not a vpninterface, ignoring.", intrf.getName());
139                     return;
140                 }
141                 final VpnInterface vpnInterface = optVpnInterface.get();
142                 try {
143                     dpId = InterfaceUtils.getDpIdFromInterface(intrf);
144                 } catch (Exception e){
145                     LOG.error("Unable to retrieve dpnId from interface operational data store for interface {}.Fetching from vpn interface op data store. ", intrf.getName(), e);
146                     dpId = vpnInterface.getDpnId();
147                 }
148                 final BigInteger dpnId = dpId;
149                 final int ifIndex = intrf.getIfIndex();
150                 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
151                 dataStoreCoordinator.enqueueJob("VPNINTERFACE-" + intrf.getName(),
152                         new Callable<List<ListenableFuture<Void>>>() {
153                             @Override
154                             public List<ListenableFuture<Void>> call() throws Exception {
155                                 WriteTransaction writeOperTxn = dataBroker.newWriteOnlyTransaction();
156                                 WriteTransaction writeConfigTxn = dataBroker.newWriteOnlyTransaction();
157                                 WriteTransaction writeInvTxn = dataBroker.newWriteOnlyTransaction();
158                                 vpnInterfaceManager.processVpnInterfaceDown(dpnId, interfaceName, ifIndex, false, false,
159                                         writeConfigTxn, writeOperTxn, writeInvTxn);
160                                 RouterInterface routerInterface = VpnUtil.getConfiguredRouterInterface(dataBroker, interfaceName);
161                                 if (routerInterface != null) {
162                                     handleRouterInterfacesDownEvent(routerInterface.getRouterName(), interfaceName, dpnId, writeOperTxn);
163                                 }
164                                 List<ListenableFuture<Void>> futures = new ArrayList<ListenableFuture<Void>>();
165                                 futures.add(writeOperTxn.submit());
166                                 futures.add(writeConfigTxn.submit());
167                                 futures.add(writeInvTxn.submit());
168                                 return futures;
169                             }
170                         });
171             }
172         } catch (Exception e) {
173             LOG.error("Exception observed in handling deletion of VPN Interface {}. ", intrf.getName(), e);
174         }
175     }
176
177     @Override
178     protected void update(InstanceIdentifier<Interface> identifier,
179                           Interface original, Interface update) {
180         LOG.trace("Operation Interface update event - Old: {}, New: {}", original, update);
181         final String interfaceName = update.getName();
182         if (original.getOperStatus().equals(Interface.OperStatus.Unknown) ||
183                 update.getOperStatus().equals(Interface.OperStatus.Unknown)){
184             LOG.debug("Interface {} state change is from/to UNKNOWN. Ignoring the update event.", interfaceName);
185             return;
186         }
187         final BigInteger dpnId = InterfaceUtils.getDpIdFromInterface(update);
188
189         if (update.getIfIndex() == null) {
190             return;
191         }
192         if (update != null && (update.getType() != null)) {
193             if (!update.getType().equals(Tunnel.class)) {
194                 final VpnInterface vpnInterface = VpnUtil.getConfiguredVpnInterface(dataBroker, interfaceName);
195                 if (vpnInterface != null) {
196                     final int ifIndex = update.getIfIndex();
197                     if (update.getOperStatus().equals(Interface.OperStatus.Up)) {
198                         DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
199                         dataStoreCoordinator.enqueueJob("VPNINTERFACE-" + interfaceName,
200                                 new Callable<List<ListenableFuture<Void>>>() {
201                                     @Override
202                                     public List<ListenableFuture<Void>> call() throws Exception {
203                                         WriteTransaction writeConfigTxn = dataBroker.newWriteOnlyTransaction();
204                                         WriteTransaction writeOperTxn = dataBroker.newWriteOnlyTransaction();
205                                         WriteTransaction writeInvTxn = dataBroker.newWriteOnlyTransaction();
206                                         vpnInterfaceManager.processVpnInterfaceUp(dpnId, vpnInterface, ifIndex, 
207                                                 true, writeConfigTxn, writeOperTxn, writeInvTxn);
208                                         List<ListenableFuture<Void>> futures = new ArrayList<ListenableFuture<Void>>();
209                                         futures.add(writeOperTxn.submit());
210                                         futures.add(writeConfigTxn.submit());
211                                         futures.add(writeInvTxn.submit());
212                                         return futures;
213                                     }
214                                 });
215                     } else if (update.getOperStatus().equals(Interface.OperStatus.Down)) {
216                         DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
217                         dataStoreCoordinator.enqueueJob(interfaceName,
218                                 new Callable<List<ListenableFuture<Void>>>() {
219                                     @Override
220                                     public List<ListenableFuture<Void>> call() throws Exception {
221                                         WriteTransaction writeConfigTxn = dataBroker.newWriteOnlyTransaction();
222                                         WriteTransaction writeOperTxn = dataBroker.newWriteOnlyTransaction();
223                                         WriteTransaction writeInvTxn = dataBroker.newWriteOnlyTransaction();
224                                         vpnInterfaceManager.processVpnInterfaceDown(dpnId, interfaceName, ifIndex, true, false,
225                                                 writeConfigTxn, writeOperTxn, writeInvTxn);
226                                         List<ListenableFuture<Void>> futures = new ArrayList<ListenableFuture<Void>>();
227                                         futures.add(writeOperTxn.submit());
228                                         futures.add(writeConfigTxn.submit());
229                                         futures.add(writeInvTxn.submit());
230                                         return futures;
231                                     }
232                                 });
233                     }
234                 }
235             }
236         }
237     }
238
239     void handleRouterInterfacesUpEvent(String routerName, String interfaceName, WriteTransaction writeOperTxn) {
240         LOG.debug("Handling UP event for router interface {} in Router {}", interfaceName, routerName);
241         vpnInterfaceManager.addToNeutronRouterDpnsMap(routerName, interfaceName, writeOperTxn);
242     }
243
244     void handleRouterInterfacesDownEvent(String routerName, String interfaceName, BigInteger dpnId,
245                                          WriteTransaction writeOperTxn) {
246         LOG.debug("Handling DOWN event for router interface {} in Router {}", interfaceName, routerName);
247         vpnInterfaceManager.removeFromNeutronRouterDpnsMap(routerName, interfaceName, dpnId, writeOperTxn);
248     }
249
250 }