ab47a3a1f87055c26424c895f31c4f8eec9ecb80
[netvirt.git] / vpnservice / vpnmanager / vpnmanager-impl / src / main / java / org / opendaylight / netvirt / vpnmanager / TunnelInterfaceStateListener.java
1 /*
2  * Copyright © 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.vpnmanager;
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.Collections;
15 import java.util.HashMap;
16 import java.util.Iterator;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.concurrent.Callable;
20 import java.util.concurrent.Future;
21 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
22 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
23 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
24 import org.opendaylight.genius.datastoreutils.DataStoreJobCoordinator;
25 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
26 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
27 import org.opendaylight.netvirt.vpnmanager.utilities.InterfaceUtils;
28 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpnInterfaceListInputBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpnInterfaceListOutput;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeExternal;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeHwvtep;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeInternal;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelOperStatus;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelsState;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.PortOpData;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.port.op.data.PortOpDataEntry;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.port.op.data.PortOpDataEntryKey;
45 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
46 import org.opendaylight.yangtools.yang.common.RpcResult;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49
50 public class TunnelInterfaceStateListener extends AsyncDataTreeChangeListenerBase<StateTunnelList,
51     TunnelInterfaceStateListener> implements AutoCloseable {
52     private static final Logger LOG = LoggerFactory.getLogger(TunnelInterfaceStateListener.class);
53     private final DataBroker dataBroker;
54     private final IBgpManager bgpManager;
55     private final IFibManager fibManager;
56     private final ItmRpcService itmRpcService;
57     private OdlInterfaceRpcService intfRpcService;
58     private VpnInterfaceManager vpnInterfaceManager;
59     private VpnSubnetRouteHandler vpnSubnetRouteHandler;
60
61     protected enum UpdateRouteAction {
62         ADVERTISE_ROUTE, WITHDRAW_ROUTE
63     }
64
65     protected enum TunnelAction {
66         TUNNEL_EP_ADD,
67         TUNNEL_EP_DELETE,
68         TUNNEL_EP_UPDATE
69     }
70
71     /**
72      * Responsible for listening to tunnel interface state change.
73      *
74      * @param dataBroker dataBroker
75      * @param bgpManager bgpManager
76      * @param fibManager fibManager
77      * @param itmRpcService itmRpcService
78      */
79     public TunnelInterfaceStateListener(final DataBroker dataBroker,
80         final IBgpManager bgpManager,
81         final IFibManager fibManager,
82         final ItmRpcService itmRpcService,
83         final OdlInterfaceRpcService ifaceMgrRpcService,
84         final VpnInterfaceManager vpnInterfaceManager,
85         final VpnSubnetRouteHandler vpnSubnetRouteHandler) {
86         super(StateTunnelList.class, TunnelInterfaceStateListener.class);
87         this.dataBroker = dataBroker;
88         this.bgpManager = bgpManager;
89         this.fibManager = fibManager;
90         this.itmRpcService = itmRpcService;
91         this.intfRpcService = ifaceMgrRpcService;
92         this.vpnInterfaceManager = vpnInterfaceManager;
93         this.vpnSubnetRouteHandler = vpnSubnetRouteHandler;
94     }
95
96     public void start() {
97         LOG.info("{} start", getClass().getSimpleName());
98         registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
99     }
100
101     @Override
102     protected InstanceIdentifier<StateTunnelList> getWildCardPath() {
103         return InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class);
104     }
105
106     @Override
107     protected TunnelInterfaceStateListener getDataTreeChangeListener() {
108         return TunnelInterfaceStateListener.this;
109     }
110
111     @Override
112     protected void remove(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList del) {
113         LOG.trace("Tunnel deletion---- {}", del);
114         handleTunnelEventForDPN(del, UpdateRouteAction.WITHDRAW_ROUTE, TunnelAction.TUNNEL_EP_DELETE);
115     }
116
117     @Override
118     protected void update(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList original,
119         StateTunnelList update) {
120         LOG.trace("Tunnel updation---- {}", update);
121         LOG.trace("ITM Tunnel {} of type {} state event changed from :{} to :{}",
122             update.getTunnelInterfaceName(),
123             fibManager.getTransportTypeStr(update.getTransportType().toString()),
124             original.getOperState(), update.getOperState());
125         //withdraw all prefixes in all vpns for this dpn
126         TunnelOperStatus tunOpStatus = update.getOperState();
127         if ((tunOpStatus != TunnelOperStatus.Down) && (tunOpStatus != TunnelOperStatus.Up)) {
128             LOG.trace("Returning from unsupported tunnelOperStatus {}", tunOpStatus);
129             return;
130         }
131         boolean isTunnelUp = (tunOpStatus == TunnelOperStatus.Up);
132         handleTunnelEventForDPN(update,
133             isTunnelUp ? UpdateRouteAction.ADVERTISE_ROUTE : UpdateRouteAction.WITHDRAW_ROUTE,
134             TunnelAction.TUNNEL_EP_UPDATE);
135     }
136
137     @Override
138     protected void add(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList add) {
139         LOG.trace("Tunnel addition---- {}", add);
140         TunnelOperStatus tunOpStatus = add.getOperState();
141         if ((tunOpStatus != TunnelOperStatus.Down) && (tunOpStatus != TunnelOperStatus.Up)) {
142             LOG.trace("Returning from unsupported tunnelOperStatus {}", tunOpStatus);
143             return;
144         }
145         boolean isTunnelUp = (tunOpStatus == TunnelOperStatus.Up);
146         if (!isTunnelUp) {
147             LOG.trace("Tunnel {} is not yet UP.",
148                 add.getTunnelInterfaceName());
149             return;
150         } else {
151             LOG.trace("ITM Tunnel ,type {} ,State is UP b/w src: {} and dest: {}",
152                 fibManager.getTransportTypeStr(add.getTransportType().toString()),
153                 add.getSrcInfo().getTepDeviceId(), add.getDstInfo().getTepDeviceId());
154             handleTunnelEventForDPN(add, UpdateRouteAction.ADVERTISE_ROUTE, TunnelAction.TUNNEL_EP_ADD);
155         }
156     }
157
158     // TODO Clean up the exception handling
159     @SuppressWarnings("checkstyle:IllegalCatch")
160     private void handleTunnelEventForDPN(StateTunnelList stateTunnelList, UpdateRouteAction action,
161         TunnelAction tunnelAction) {
162         final BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
163         final String srcTepIp = String.valueOf(stateTunnelList.getSrcInfo().getTepIp().getValue());
164         String destTepIp = String.valueOf(stateTunnelList.getDstInfo().getTepIp().getValue());
165         String rd;
166         BigInteger remoteDpnId = null;
167         boolean isTepDeletedOnDpn = false;
168
169         LOG.trace("Handle tunnel event for srcDpn {} SrcTepIp {} DestTepIp {} ", srcDpnId, srcTepIp, destTepIp);
170         int tunTypeVal = getTunnelType(stateTunnelList);
171
172         LOG.trace("tunTypeVal is {}", tunTypeVal);
173
174         try {
175             if (tunnelAction == TunnelAction.TUNNEL_EP_ADD) {
176                 LOG.trace(" Tunnel ADD event received for Dpn {} VTEP Ip {} ", srcDpnId, srcTepIp);
177             } else if (tunnelAction == TunnelAction.TUNNEL_EP_DELETE) {
178                 LOG.trace(" Tunnel DELETE event received for Dpn {} VTEP Ip {} ", srcDpnId, srcTepIp);
179                 // When tunnel EP is deleted on a DPN , VPN gets two deletion event.
180                 // One for a DPN on which tunnel EP was deleted and another for other-end DPN.
181                 // Update the adj for the vpninterfaces for a DPN on which TEP is deleted.
182                 // Update the adj & VRF for the vpninterfaces for a DPN on which TEP is deleted.
183                 // Dont update the adj & VRF for vpninterfaces for a DPN on which TEP is not deleted.
184                 String endpointIpForDPN = null;
185                 try {
186                     endpointIpForDPN = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, srcDpnId);
187                 } catch (Exception e) {
188                     /* this dpn does not have the VTEP */
189                     endpointIpForDPN = null;
190                 }
191
192                 if (endpointIpForDPN == null) {
193                     LOG.trace("Tunnel TEP is deleted on Dpn {} VTEP Ip {}", srcDpnId, srcTepIp);
194                     isTepDeletedOnDpn = true;
195                 }
196             }
197
198             // Get the list of VpnInterfaces from Intf Mgr for a SrcDPN on which TEP is added/deleted
199             Future<RpcResult<GetDpnInterfaceListOutput>> result;
200             List<String> srcDpninterfacelist = new ArrayList<>();
201             List<String> destDpninterfacelist = new ArrayList<>();
202             try {
203                 result =
204                     intfRpcService.getDpnInterfaceList(new GetDpnInterfaceListInputBuilder().setDpid(srcDpnId).build());
205                 RpcResult<GetDpnInterfaceListOutput> rpcResult = result.get();
206                 if (!rpcResult.isSuccessful()) {
207                     LOG.warn("RPC Call to GetDpnInterfaceList for dpnid {} returned with Errors {}", srcDpnId,
208                         rpcResult.getErrors());
209                 } else {
210                     srcDpninterfacelist = rpcResult.getResult().getInterfacesList();
211                 }
212             } catch (Exception e) {
213                 LOG.warn("Exception when querying for GetDpnInterfaceList for dpnid {}", srcDpnId, e);
214             }
215
216             // Get the list of VpnInterfaces from Intf Mgr for a destDPN only for internal tunnel.
217             if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
218                 remoteDpnId = new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId());
219                 try {
220                     result = intfRpcService.getDpnInterfaceList(
221                         new GetDpnInterfaceListInputBuilder().setDpid(remoteDpnId).build());
222                     RpcResult<GetDpnInterfaceListOutput> rpcResult = result.get();
223                     if (!rpcResult.isSuccessful()) {
224                         LOG.warn("RPC Call to GetDpnInterfaceList for dpnid {} returned with Errors {}", srcDpnId,
225                             rpcResult.getErrors());
226                     } else {
227                         destDpninterfacelist = rpcResult.getResult().getInterfacesList();
228                     }
229                 } catch (Exception e) {
230                     LOG.warn("Exception when querying for GetDpnInterfaceList for dpnid {}", srcDpnId, e);
231                 }
232             }
233
234             /*
235              * Iterate over the list of VpnInterface for a SrcDpn on which TEP is added or deleted and read the adj.
236              * Update the adjacencies with the updated nexthop.
237              */
238             Iterator<String> interfacelistIter = srcDpninterfacelist.iterator();
239             String intfName = null;
240             List<Uuid> subnetList = new ArrayList<>();
241             Map<Long, String> vpnIdRdMap = new HashMap<>();
242
243             while (interfacelistIter.hasNext()) {
244                 intfName = interfacelistIter.next();
245                 final VpnInterface vpnInterface = VpnUtil.getOperationalVpnInterface(dataBroker, intfName);
246                 if (vpnInterface != null) {
247
248                     DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
249                     dataStoreCoordinator.enqueueJob("VPNINTERFACE-" + intfName,
250                             new UpdateVpnInterfaceOnTunnelEvent(dataBroker,
251                                     vpnInterfaceManager,
252                                     tunnelAction,
253                                     vpnInterface,
254                                     stateTunnelList,
255                                     isTepDeletedOnDpn));
256
257                     // Populate the List of subnets
258                     InstanceIdentifier<PortOpDataEntry> portOpIdentifier =
259                         InstanceIdentifier.builder(PortOpData.class).child(PortOpDataEntry.class,
260                             new PortOpDataEntryKey(intfName)).build();
261                     Optional<PortOpDataEntry> optionalPortOp =
262                         VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, portOpIdentifier);
263                     if (optionalPortOp.isPresent()) {
264                         Uuid subnetId = optionalPortOp.get().getSubnetId();
265                         if (!subnetList.contains(subnetId)) {
266                             subnetList.add(subnetId);
267                         }
268                     }
269                     //Populate the map for VpnId-to-Rd
270                     long vpnId = VpnUtil.getVpnId(dataBroker, vpnInterface.getVpnInstanceName());
271                     rd = VpnUtil.getVpnRd(dataBroker, vpnInterface.getVpnInstanceName());
272                     vpnIdRdMap.put(vpnId, rd);
273                 }
274             }
275
276             /*
277              * Iterate over the list of VpnInterface for destDPN and get the prefix .
278              * Create remote rule for each of those prefix on srcDPN.
279              */
280             interfacelistIter = destDpninterfacelist.iterator();
281             while (interfacelistIter.hasNext()) {
282                 intfName = interfacelistIter.next();
283                 final VpnInterface vpnInterface = VpnUtil.getOperationalVpnInterface(dataBroker, intfName);
284                 if (vpnInterface != null) {
285                     Adjacencies adjacencies = vpnInterface.getAugmentation(Adjacencies.class);
286                     List<Adjacency> adjList = adjacencies != null ? adjacencies.getAdjacency()
287                             : Collections.emptyList();
288                     String prefix = null;
289                     long vpnId = VpnUtil.getVpnId(dataBroker, vpnInterface.getVpnInstanceName());
290                     if (vpnIdRdMap.containsKey(vpnId)) {
291                         rd = vpnIdRdMap.get(vpnId);
292                         LOG.trace(" Remote DpnId {} VpnId {} rd {} VpnInterface {}", remoteDpnId, vpnId, rd,
293                             vpnInterface);
294                         for (Adjacency adj : adjList) {
295                             prefix = adj.getIpAddress();
296                             if ((tunnelAction == TunnelAction.TUNNEL_EP_ADD)
297                                 && (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue())) {
298                                 fibManager.manageRemoteRouteOnDPN(true, srcDpnId, vpnId, rd, prefix, destTepIp);
299                             }
300
301                             if ((tunnelAction == TunnelAction.TUNNEL_EP_DELETE)
302                                 && (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue())) {
303                                 fibManager.manageRemoteRouteOnDPN(false, srcDpnId, vpnId, rd, prefix, destTepIp);
304                             }
305                         }
306                     }
307                 }
308             }
309
310             //Iterate over the VpnId-to-Rd map.
311             for (Map.Entry<Long, String> entry : vpnIdRdMap.entrySet()) {
312                 Long vpnId = entry.getKey();
313                 rd = entry.getValue();
314                 if ((tunnelAction == TunnelAction.TUNNEL_EP_ADD)
315                     && (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue())) {
316                     fibManager.populateExternalRoutesOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
317                 } else if ((tunnelAction == TunnelAction.TUNNEL_EP_DELETE)
318                     && (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue())) {
319                     fibManager.cleanUpExternalRoutesOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
320                 }
321             }
322
323             if (tunnelAction == TunnelAction.TUNNEL_EP_ADD) {
324                 for (Uuid subnetId : subnetList) {
325                     // Populate the List of subnets
326                     vpnSubnetRouteHandler.updateSubnetRouteOnTunnelUpEvent(subnetId, srcDpnId);
327                 }
328             }
329
330             if ((tunnelAction == TunnelAction.TUNNEL_EP_DELETE) && isTepDeletedOnDpn) {
331                 for (Uuid subnetId : subnetList) {
332                     // Populate the List of subnets
333                     vpnSubnetRouteHandler.updateSubnetRouteOnTunnelDownEvent(subnetId, srcDpnId);
334                 }
335             }
336         } catch (Exception e) {
337             LOG.error("Unable to handle the tunnel event.", e);
338             return;
339         }
340     }
341
342
343     private class UpdateVpnInterfaceOnTunnelEvent implements Callable {
344         private VpnInterface vpnInterface;
345         private StateTunnelList stateTunnelList;
346         private VpnInterfaceManager vpnInterfaceManager;
347         private DataBroker broker;
348         private TunnelAction tunnelAction;
349         private boolean isTepDeletedOnDpn;
350
351         UpdateVpnInterfaceOnTunnelEvent(DataBroker broker,
352             VpnInterfaceManager vpnInterfaceManager,
353             TunnelAction tunnelAction,
354             VpnInterface vpnInterface,
355             StateTunnelList stateTunnelList,
356             boolean isTepDeletedOnDpn) {
357             this.broker = broker;
358             this.vpnInterfaceManager = vpnInterfaceManager;
359             this.stateTunnelList = stateTunnelList;
360             this.vpnInterface = vpnInterface;
361             this.tunnelAction = tunnelAction;
362             this.isTepDeletedOnDpn = isTepDeletedOnDpn;
363         }
364
365         @Override
366         public List<ListenableFuture<Void>> call() throws Exception {
367
368             if (tunnelAction == TunnelAction.TUNNEL_EP_ADD) {
369                 vpnInterfaceManager.updateVpnInterfaceOnTepAdd(vpnInterface, stateTunnelList);
370             }
371
372             if ((tunnelAction == TunnelAction.TUNNEL_EP_DELETE) && isTepDeletedOnDpn) {
373                 vpnInterfaceManager.updateVpnInterfaceOnTepDelete(vpnInterface, stateTunnelList);
374             }
375
376             return null;
377         }
378     }
379
380     private int getTunnelType(StateTunnelList stateTunnelList) {
381         int tunTypeVal = 0;
382         if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeInternal.class) {
383             tunTypeVal = VpnConstants.ITMTunnelLocType.Internal.getValue();
384         } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeExternal.class) {
385             tunTypeVal = VpnConstants.ITMTunnelLocType.External.getValue();
386         } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeHwvtep.class) {
387             tunTypeVal = VpnConstants.ITMTunnelLocType.Hwvtep.getValue();
388         } else {
389             tunTypeVal = VpnConstants.ITMTunnelLocType.Invalid.getValue();
390         }
391         return tunTypeVal;
392     }
393 }