2 * Copyright (c) 2016 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 java.math.BigInteger;
13 import java.util.concurrent.Callable;
14 import java.util.concurrent.Future;
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.PortOpData;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.port.op.data.PortOpDataEntry;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.port.op.data.PortOpDataEntryKey;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
48 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
49 import org.opendaylight.yangtools.yang.common.RpcResult;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
53 public class TunnelInterfaceStateListener extends AsyncDataTreeChangeListenerBase<StateTunnelList,
54 TunnelInterfaceStateListener> implements AutoCloseable{
55 private static final Logger LOG = LoggerFactory.getLogger(TunnelInterfaceStateListener.class);
56 private final DataBroker dataBroker;
57 private final IBgpManager bgpManager;
58 private final IFibManager fibManager;
59 private final ItmRpcService itmRpcService;
60 private OdlInterfaceRpcService intfRpcService;
61 private VpnInterfaceManager vpnInterfaceManager;
62 private VpnSubnetRouteHandler vpnSubnetRouteHandler;
63 protected enum UpdateRouteAction {
64 ADVERTISE_ROUTE, WITHDRAW_ROUTE
67 protected enum TunnelAction {
73 * Responsible for listening to tunnel interface state change
75 * @param dataBroker dataBroker
76 * @param bgpManager bgpManager
77 * @param fibManager fibManager
78 * @param itmRpcService itmRpcService
80 public TunnelInterfaceStateListener(final DataBroker dataBroker,
81 final IBgpManager bgpManager,
82 final IFibManager fibManager,
83 final ItmRpcService itmRpcService,
84 final OdlInterfaceRpcService ifaceMgrRpcService,
85 final VpnInterfaceManager vpnInterfaceManager,
86 final VpnSubnetRouteHandler vpnSubnetRouteHandler) {
87 super(StateTunnelList.class, TunnelInterfaceStateListener.class);
88 this.dataBroker = dataBroker;
89 this.bgpManager = bgpManager;
90 this.fibManager = fibManager;
91 this.itmRpcService = itmRpcService;
92 this.intfRpcService = ifaceMgrRpcService;
93 this.vpnInterfaceManager = vpnInterfaceManager;
94 this.vpnSubnetRouteHandler = vpnSubnetRouteHandler;
98 LOG.info("{} start", getClass().getSimpleName());
99 registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
103 protected InstanceIdentifier<StateTunnelList> getWildCardPath() {
104 return InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class);
108 protected TunnelInterfaceStateListener getDataTreeChangeListener() {
109 return TunnelInterfaceStateListener.this;
113 protected void remove(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList del) {
114 LOG.trace("Tunnel deletion---- {}", del);
115 handleTunnelEventForDPN(del, UpdateRouteAction.WITHDRAW_ROUTE , TunnelAction.TUNNEL_EP_DELETE);
119 protected void update(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList original, 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 private void handleTunnelEventForDPN(StateTunnelList stateTunnelList, UpdateRouteAction action, TunnelAction tunnelAction) {
159 final BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
160 final String srcTepIp = String.valueOf(stateTunnelList.getSrcInfo().getTepIp().getValue());
161 String destTepIp = String.valueOf(stateTunnelList.getDstInfo().getTepIp().getValue());
163 BigInteger remoteDpnId = null;
164 boolean isTepDeletedOnDpn = false;
166 LOG.trace("Handle tunnel event for srcDpn {} SrcTepIp {} DestTepIp {} ", srcDpnId, srcTepIp, destTepIp);
167 int tunTypeVal = getTunnelType(stateTunnelList);
169 LOG.trace("tunTypeVal is {}", tunTypeVal);
172 if (tunnelAction == TunnelAction.TUNNEL_EP_ADD) {
173 LOG.trace(" Tunnel ADD event received for Dpn {} VTEP Ip {} ", srcDpnId, srcTepIp);
174 } else if (tunnelAction == TunnelAction.TUNNEL_EP_DELETE) {
175 LOG.trace(" Tunnel DELETE event received for Dpn {} VTEP Ip {} ", srcDpnId, srcTepIp);
176 // When tunnel EP is deleted on a DPN , VPN gets two deletion event.
177 // One for a DPN on which tunnel EP was deleted and another for other-end DPN.
178 // Update the adj for the vpninterfaces for a DPN on which TEP is deleted.
179 // Update the adj & VRF for the vpninterfaces for a DPN on which TEP is deleted.
180 // Dont update the adj & VRF for vpninterfaces for a DPN on which TEP is not deleted.
181 String endpointIpForDPN = null;
183 endpointIpForDPN = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, srcDpnId);
184 } catch (Exception e) {
185 /* this dpn does not have the VTEP */
186 endpointIpForDPN = null;
189 if (endpointIpForDPN == null) {
190 LOG.trace("Tunnel TEP is deleted on Dpn {} VTEP Ip {}", srcDpnId, srcTepIp);
191 isTepDeletedOnDpn = true;
195 // Get the list of VpnInterfaces from Intf Mgr for a SrcDPN on which TEP is added/deleted
196 Future<RpcResult<GetDpnInterfaceListOutput>> result;
197 List<String> srcDpninterfacelist = new ArrayList<>();
198 List<String> destDpninterfacelist = new ArrayList<>();
200 result = intfRpcService.getDpnInterfaceList(new GetDpnInterfaceListInputBuilder().setDpid(srcDpnId).build());
201 RpcResult<GetDpnInterfaceListOutput> rpcResult = result.get();
202 if (!rpcResult.isSuccessful()) {
203 LOG.warn("RPC Call to GetDpnInterfaceList for dpnid {} returned with Errors {}", srcDpnId, rpcResult.getErrors());
205 srcDpninterfacelist = rpcResult.getResult().getInterfacesList();
207 } catch (Exception e) {
208 LOG.warn("Exception {} when querying for GetDpnInterfaceList for dpnid {}, trace {}", e, srcDpnId, e.getStackTrace());
211 // Get the list of VpnInterfaces from Intf Mgr for a destDPN only for internal tunnel.
212 if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
213 remoteDpnId = new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId());
215 result = intfRpcService.getDpnInterfaceList(new GetDpnInterfaceListInputBuilder().setDpid(remoteDpnId).build());
216 RpcResult<GetDpnInterfaceListOutput> rpcResult = result.get();
217 if (!rpcResult.isSuccessful()) {
218 LOG.warn("RPC Call to GetDpnInterfaceList for dpnid {} returned with Errors {}", srcDpnId, rpcResult.getErrors());
220 destDpninterfacelist = rpcResult.getResult().getInterfacesList();
222 } catch (Exception e) {
223 LOG.warn("Exception {} when querying for GetDpnInterfaceList for dpnid {}, trace {}", e, srcDpnId, e.getStackTrace());
228 * Iterate over the list of VpnInterface for a SrcDpn on which TEP is added or deleted and read the adj.
229 * Update the adjacencies with the updated nexthop.
231 Iterator<String> interfacelistIter = srcDpninterfacelist.iterator();
232 String intfName = null;
233 List<Uuid> subnetList = new ArrayList<Uuid>();
234 Map<Long, String> vpnIdRdMap = new HashMap<Long, String>();
236 while (interfacelistIter.hasNext()) {
237 intfName = interfacelistIter.next();
238 final VpnInterface vpnInterface = VpnUtil.getOperationalVpnInterface(dataBroker, intfName);
239 if (vpnInterface != null) {
241 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
242 dataStoreCoordinator.enqueueJob("VPNINTERFACE-" + intfName,
243 new UpdateVpnInterfaceOnTunnelEvent(dataBroker,
250 // Populate the List of subnets
251 InstanceIdentifier<PortOpDataEntry> portOpIdentifier = InstanceIdentifier.builder(PortOpData.class).
252 child(PortOpDataEntry.class, new PortOpDataEntryKey(intfName)).build();
253 Optional<PortOpDataEntry> optionalPortOp = VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, portOpIdentifier);
254 if (optionalPortOp.isPresent()) {
255 Uuid subnetId = optionalPortOp.get().getSubnetId();
256 if (!subnetList.contains(subnetId)) {
257 subnetList.add(subnetId);
261 //Populate the map for VpnId-to-Rd
262 long vpnId = VpnUtil.getVpnId(dataBroker, vpnInterface.getVpnInstanceName());
263 rd = VpnUtil.getVpnRd(dataBroker, vpnInterface.getVpnInstanceName());
264 vpnIdRdMap.put(vpnId, rd);
269 * Iterate over the list of VpnInterface for destDPN and get the prefix .
270 * Create remote rule for each of those prefix on srcDPN.
272 interfacelistIter = destDpninterfacelist.iterator();
273 while (interfacelistIter.hasNext()) {
274 intfName = interfacelistIter.next();
275 final VpnInterface vpnInterface = VpnUtil.getOperationalVpnInterface(dataBroker, intfName);
276 if (vpnInterface != null) {
277 List<Adjacency> adjList = vpnInterface.getAugmentation(Adjacencies.class).getAdjacency();
278 String prefix = null;
279 long vpnId = VpnUtil.getVpnId(dataBroker, vpnInterface.getVpnInstanceName());
280 if (vpnIdRdMap.containsKey(vpnId)) {
281 rd = vpnIdRdMap.get(vpnId);
282 LOG.trace(" Remote DpnId {} VpnId {} rd {} VpnInterface {}", remoteDpnId, vpnId, rd , vpnInterface);
283 for (Adjacency adj : adjList) {
284 prefix = adj.getIpAddress();
285 if ((tunnelAction == TunnelAction.TUNNEL_EP_ADD) &&
286 (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue())) {
287 fibManager.manageRemoteRouteOnDPN(true, srcDpnId, vpnId, rd, prefix, destTepIp);
290 if ((tunnelAction == TunnelAction.TUNNEL_EP_DELETE) &&
291 (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue())) {
292 fibManager.manageRemoteRouteOnDPN(false, srcDpnId, vpnId, rd, prefix, destTepIp);
299 //Iterate over the VpnId-to-Rd map.
300 Iterator<Map.Entry<Long, String>> entries = vpnIdRdMap.entrySet().iterator();
301 while (entries.hasNext()) {
302 Map.Entry<Long, String> entry = entries.next();
303 Long vpnId = entry.getKey();
304 rd = entry.getValue();
305 if ((tunnelAction == TunnelAction.TUNNEL_EP_ADD) &&
306 (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue())) {
307 fibManager.populateExternalRoutesOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
308 } else if ((tunnelAction == TunnelAction.TUNNEL_EP_DELETE) &&
309 (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue())) {
310 fibManager.cleanUpExternalRoutesOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
314 if (tunnelAction == TunnelAction.TUNNEL_EP_ADD) {
315 for (Uuid subnetId : subnetList) {
316 // Populate the List of subnets
317 vpnSubnetRouteHandler.updateSubnetRouteOnTunnelUpEvent(subnetId, srcDpnId);
321 if ((tunnelAction == TunnelAction.TUNNEL_EP_DELETE) && isTepDeletedOnDpn) {
322 for (Uuid subnetId : subnetList) {
323 // Populate the List of subnets
324 vpnSubnetRouteHandler.updateSubnetRouteOnTunnelDownEvent(subnetId, srcDpnId);
327 } catch (Exception e) {
328 LOG.error("Unable to handle the tunnel event.", e);
335 private class UpdateVpnInterfaceOnTunnelEvent implements Callable {
336 private VpnInterface vpnInterface;
337 private StateTunnelList stateTunnelList;
338 private VpnInterfaceManager vpnInterfaceManager;
339 private DataBroker broker;
340 private TunnelAction tunnelAction;
341 private boolean isTepDeletedOnDpn;
343 UpdateVpnInterfaceOnTunnelEvent(DataBroker broker,
344 VpnInterfaceManager vpnInterfaceManager,
345 TunnelAction tunnelAction,
346 VpnInterface vpnInterface,
347 StateTunnelList stateTunnelList,
348 boolean isTepDeletedOnDpn) {
349 this.broker = broker;
350 this.vpnInterfaceManager = vpnInterfaceManager;
351 this.stateTunnelList = stateTunnelList;
352 this.vpnInterface = vpnInterface;
353 this.tunnelAction = tunnelAction;
354 this.isTepDeletedOnDpn = isTepDeletedOnDpn;
357 public List<ListenableFuture<Void>> call() throws Exception {
359 if(tunnelAction == TunnelAction.TUNNEL_EP_ADD) {
360 vpnInterfaceManager.updateVpnInterfaceOnTepAdd(vpnInterface, stateTunnelList);
363 if((tunnelAction == TunnelAction.TUNNEL_EP_DELETE) && isTepDeletedOnDpn) {
364 vpnInterfaceManager.updateVpnInterfaceOnTepDelete(vpnInterface, stateTunnelList);
371 private int getTunnelType (StateTunnelList stateTunnelList) {
373 if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeInternal.class) {
374 tunTypeVal = VpnConstants.ITMTunnelLocType.Internal.getValue();
375 } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeExternal.class) {
376 tunTypeVal = VpnConstants.ITMTunnelLocType.External.getValue();
377 } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeHwvtep.class) {
378 tunTypeVal = VpnConstants.ITMTunnelLocType.Hwvtep.getValue();
380 tunTypeVal = VpnConstants.ITMTunnelLocType.Invalid.getValue();