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