d0de55018b9fcd220163fc0935b26ed073ae45d1
[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                             long label = adj.getLabel();
297                             if ((tunnelAction == TunnelAction.TUNNEL_EP_ADD)
298                                 && (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue())) {
299                                 fibManager.manageRemoteRouteOnDPN(true, srcDpnId, vpnId, rd, prefix, destTepIp, label);
300                             }
301
302                             if ((tunnelAction == TunnelAction.TUNNEL_EP_DELETE)
303                                 && (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue())) {
304                                 fibManager.manageRemoteRouteOnDPN(false, srcDpnId, vpnId, rd, prefix, destTepIp, label);
305                             }
306                         }
307                     }
308                 }
309             }
310
311             //Iterate over the VpnId-to-Rd map.
312             for (Map.Entry<Long, String> entry : vpnIdRdMap.entrySet()) {
313                 Long vpnId = entry.getKey();
314                 rd = entry.getValue();
315                 if ((tunnelAction == TunnelAction.TUNNEL_EP_ADD)
316                     && (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue())) {
317                     fibManager.populateExternalRoutesOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
318                 } else if ((tunnelAction == TunnelAction.TUNNEL_EP_DELETE)
319                     && (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue())) {
320                     fibManager.cleanUpExternalRoutesOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
321                 }
322             }
323
324             if (tunnelAction == TunnelAction.TUNNEL_EP_ADD) {
325                 for (Uuid subnetId : subnetList) {
326                     // Populate the List of subnets
327                     vpnSubnetRouteHandler.updateSubnetRouteOnTunnelUpEvent(subnetId, srcDpnId);
328                 }
329             }
330
331             if ((tunnelAction == TunnelAction.TUNNEL_EP_DELETE) && isTepDeletedOnDpn) {
332                 for (Uuid subnetId : subnetList) {
333                     // Populate the List of subnets
334                     vpnSubnetRouteHandler.updateSubnetRouteOnTunnelDownEvent(subnetId, srcDpnId);
335                 }
336             }
337         } catch (Exception e) {
338             LOG.error("Unable to handle the tunnel event.", e);
339             return;
340         }
341     }
342
343
344     private class UpdateVpnInterfaceOnTunnelEvent implements Callable {
345         private VpnInterface vpnInterface;
346         private StateTunnelList stateTunnelList;
347         private VpnInterfaceManager vpnInterfaceManager;
348         private DataBroker broker;
349         private TunnelAction tunnelAction;
350         private boolean isTepDeletedOnDpn;
351
352         UpdateVpnInterfaceOnTunnelEvent(DataBroker broker,
353             VpnInterfaceManager vpnInterfaceManager,
354             TunnelAction tunnelAction,
355             VpnInterface vpnInterface,
356             StateTunnelList stateTunnelList,
357             boolean isTepDeletedOnDpn) {
358             this.broker = broker;
359             this.vpnInterfaceManager = vpnInterfaceManager;
360             this.stateTunnelList = stateTunnelList;
361             this.vpnInterface = vpnInterface;
362             this.tunnelAction = tunnelAction;
363             this.isTepDeletedOnDpn = isTepDeletedOnDpn;
364         }
365
366         @Override
367         public List<ListenableFuture<Void>> call() throws Exception {
368
369             if (tunnelAction == TunnelAction.TUNNEL_EP_ADD) {
370                 vpnInterfaceManager.updateVpnInterfaceOnTepAdd(vpnInterface, stateTunnelList);
371             }
372
373             if ((tunnelAction == TunnelAction.TUNNEL_EP_DELETE) && isTepDeletedOnDpn) {
374                 vpnInterfaceManager.updateVpnInterfaceOnTepDelete(vpnInterface, stateTunnelList);
375             }
376
377             return null;
378         }
379     }
380
381     private int getTunnelType(StateTunnelList stateTunnelList) {
382         int tunTypeVal = 0;
383         if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeInternal.class) {
384             tunTypeVal = VpnConstants.ITMTunnelLocType.Internal.getValue();
385         } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeExternal.class) {
386             tunTypeVal = VpnConstants.ITMTunnelLocType.External.getValue();
387         } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeHwvtep.class) {
388             tunTypeVal = VpnConstants.ITMTunnelLocType.Hwvtep.getValue();
389         } else {
390             tunTypeVal = VpnConstants.ITMTunnelLocType.Invalid.getValue();
391         }
392         return tunTypeVal;
393     }
394 }