2 * Copyright © 2016, 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.netvirt.vpnmanager;
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;
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;
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;
61 protected enum UpdateRouteAction {
62 ADVERTISE_ROUTE, WITHDRAW_ROUTE
65 protected enum TunnelAction {
72 * Responsible for listening to tunnel interface state change.
74 * @param dataBroker dataBroker
75 * @param bgpManager bgpManager
76 * @param fibManager fibManager
77 * @param itmRpcService itmRpcService
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;
97 LOG.info("{} start", getClass().getSimpleName());
98 registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
102 protected InstanceIdentifier<StateTunnelList> getWildCardPath() {
103 return InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class);
107 protected TunnelInterfaceStateListener getDataTreeChangeListener() {
108 return TunnelInterfaceStateListener.this;
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);
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);
131 boolean isTunnelUp = (tunOpStatus == TunnelOperStatus.Up);
132 handleTunnelEventForDPN(update,
133 isTunnelUp ? UpdateRouteAction.ADVERTISE_ROUTE : UpdateRouteAction.WITHDRAW_ROUTE,
134 TunnelAction.TUNNEL_EP_UPDATE);
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);
145 boolean isTunnelUp = (tunOpStatus == TunnelOperStatus.Up);
147 LOG.trace("Tunnel {} is not yet UP.",
148 add.getTunnelInterfaceName());
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);
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());
166 BigInteger remoteDpnId = null;
167 boolean isTepDeletedOnDpn = false;
169 LOG.trace("Handle tunnel event for srcDpn {} SrcTepIp {} DestTepIp {} ", srcDpnId, srcTepIp, destTepIp);
170 int tunTypeVal = getTunnelType(stateTunnelList);
172 LOG.trace("tunTypeVal is {}", tunTypeVal);
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;
186 endpointIpForDPN = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, srcDpnId);
187 } catch (Exception e) {
188 /* this dpn does not have the VTEP */
189 endpointIpForDPN = null;
192 if (endpointIpForDPN == null) {
193 LOG.trace("Tunnel TEP is deleted on Dpn {} VTEP Ip {}", srcDpnId, srcTepIp);
194 isTepDeletedOnDpn = true;
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<>();
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());
210 srcDpninterfacelist = rpcResult.getResult().getInterfacesList();
212 } catch (Exception e) {
213 LOG.warn("Exception when querying for GetDpnInterfaceList for dpnid {}", srcDpnId, e);
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());
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());
227 destDpninterfacelist = rpcResult.getResult().getInterfacesList();
229 } catch (Exception e) {
230 LOG.warn("Exception when querying for GetDpnInterfaceList for dpnid {}", srcDpnId, e);
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.
238 Iterator<String> interfacelistIter = srcDpninterfacelist.iterator();
239 String intfName = null;
240 List<Uuid> subnetList = new ArrayList<>();
241 Map<Long, String> vpnIdRdMap = new HashMap<>();
243 while (interfacelistIter.hasNext()) {
244 intfName = interfacelistIter.next();
245 final VpnInterface vpnInterface = VpnUtil.getOperationalVpnInterface(dataBroker, intfName);
246 if (vpnInterface != null) {
248 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
249 dataStoreCoordinator.enqueueJob("VPNINTERFACE-" + intfName,
250 new UpdateVpnInterfaceOnTunnelEvent(dataBroker,
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);
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);
277 * Iterate over the list of VpnInterface for destDPN and get the prefix .
278 * Create remote rule for each of those prefix on srcDPN.
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,
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);
301 if ((tunnelAction == TunnelAction.TUNNEL_EP_DELETE)
302 && (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue())) {
303 fibManager.manageRemoteRouteOnDPN(false, srcDpnId, vpnId, rd, prefix, destTepIp);
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);
323 if (tunnelAction == TunnelAction.TUNNEL_EP_ADD) {
324 for (Uuid subnetId : subnetList) {
325 // Populate the List of subnets
326 vpnSubnetRouteHandler.updateSubnetRouteOnTunnelUpEvent(subnetId, srcDpnId);
330 if ((tunnelAction == TunnelAction.TUNNEL_EP_DELETE) && isTepDeletedOnDpn) {
331 for (Uuid subnetId : subnetList) {
332 // Populate the List of subnets
333 vpnSubnetRouteHandler.updateSubnetRouteOnTunnelDownEvent(subnetId, srcDpnId);
336 } catch (Exception e) {
337 LOG.error("Unable to handle the tunnel event.", e);
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;
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;
366 public List<ListenableFuture<Void>> call() throws Exception {
368 if (tunnelAction == TunnelAction.TUNNEL_EP_ADD) {
369 vpnInterfaceManager.updateVpnInterfaceOnTepAdd(vpnInterface, stateTunnelList);
372 if ((tunnelAction == TunnelAction.TUNNEL_EP_DELETE) && isTepDeletedOnDpn) {
373 vpnInterfaceManager.updateVpnInterfaceOnTepDelete(vpnInterface, stateTunnelList);
380 private int getTunnelType(StateTunnelList stateTunnelList) {
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();
389 tunTypeVal = VpnConstants.ITMTunnelLocType.Invalid.getValue();