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) {
123 protected void add(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList add) {
124 LOG.trace("Tunnel addition---- {}", add);
125 TunnelOperStatus tunOpStatus = add.getOperState();
126 if ((tunOpStatus != TunnelOperStatus.Down) && (tunOpStatus != TunnelOperStatus.Up)) {
127 LOG.trace("Returning from unsupported tunnelOperStatus {}", tunOpStatus);
130 if (tunOpStatus != TunnelOperStatus.Up) {
131 LOG.trace("Tunnel {} is not yet UP.", add.getTunnelInterfaceName());
133 LOG.trace("ITM Tunnel ,type {} ,added between src: {} and dest: {}",
134 fibManager.getTransportTypeStr(add.getTransportType().toString()),
135 add.getSrcInfo().getTepDeviceId(), add.getDstInfo().getTepDeviceId());
136 handleTunnelEventForDPN(add, UpdateRouteAction.ADVERTISE_ROUTE, TunnelAction.TUNNEL_EP_ADD);
139 // TODO Clean up the exception handling
140 @SuppressWarnings("checkstyle:IllegalCatch")
141 private void handleTunnelEventForDPN(StateTunnelList stateTunnelList, UpdateRouteAction action,
142 TunnelAction tunnelAction) {
143 final BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
144 final String srcTepIp = String.valueOf(stateTunnelList.getSrcInfo().getTepIp().getValue());
145 String destTepIp = String.valueOf(stateTunnelList.getDstInfo().getTepIp().getValue());
147 BigInteger remoteDpnId = null;
148 boolean isTepDeletedOnDpn = false;
150 LOG.trace("Handle tunnel event for srcDpn {} SrcTepIp {} DestTepIp {} ", srcDpnId, srcTepIp, destTepIp);
151 int tunTypeVal = getTunnelType(stateTunnelList);
153 LOG.trace("tunTypeVal is {}", tunTypeVal);
156 if (tunnelAction == TunnelAction.TUNNEL_EP_ADD) {
157 LOG.trace(" Tunnel ADD event received for Dpn {} VTEP Ip {} ", srcDpnId, srcTepIp);
158 } else if (tunnelAction == TunnelAction.TUNNEL_EP_DELETE) {
159 LOG.trace(" Tunnel DELETE event received for Dpn {} VTEP Ip {} ", srcDpnId, srcTepIp);
160 // When tunnel EP is deleted on a DPN , VPN gets two deletion event.
161 // One for a DPN on which tunnel EP was deleted and another for other-end DPN.
162 // Update the adj for the vpninterfaces for a DPN on which TEP is deleted.
163 // Update the adj & VRF for the vpninterfaces for a DPN on which TEP is deleted.
164 // Dont update the adj & VRF for vpninterfaces for a DPN on which TEP is not deleted.
165 String endpointIpForDPN = null;
167 endpointIpForDPN = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, srcDpnId);
168 } catch (Exception e) {
169 /* this dpn does not have the VTEP */
170 endpointIpForDPN = null;
173 if (endpointIpForDPN == null) {
174 LOG.trace("Tunnel TEP is deleted on Dpn {} VTEP Ip {}", srcDpnId, srcTepIp);
175 isTepDeletedOnDpn = true;
179 // Get the list of VpnInterfaces from Intf Mgr for a SrcDPN on which TEP is added/deleted
180 Future<RpcResult<GetDpnInterfaceListOutput>> result;
181 List<String> srcDpninterfacelist = new ArrayList<>();
182 List<String> destDpninterfacelist = new ArrayList<>();
185 intfRpcService.getDpnInterfaceList(new GetDpnInterfaceListInputBuilder().setDpid(srcDpnId).build());
186 RpcResult<GetDpnInterfaceListOutput> rpcResult = result.get();
187 if (!rpcResult.isSuccessful()) {
188 LOG.warn("RPC Call to GetDpnInterfaceList for dpnid {} returned with Errors {}", srcDpnId,
189 rpcResult.getErrors());
191 srcDpninterfacelist = rpcResult.getResult().getInterfacesList();
193 } catch (Exception e) {
194 LOG.warn("Exception when querying for GetDpnInterfaceList for dpnid {}", srcDpnId, e);
197 // Get the list of VpnInterfaces from Intf Mgr for a destDPN only for internal tunnel.
198 if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
199 remoteDpnId = new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId());
201 result = intfRpcService.getDpnInterfaceList(
202 new GetDpnInterfaceListInputBuilder().setDpid(remoteDpnId).build());
203 RpcResult<GetDpnInterfaceListOutput> rpcResult = result.get();
204 if (!rpcResult.isSuccessful()) {
205 LOG.warn("RPC Call to GetDpnInterfaceList for dpnid {} returned with Errors {}", srcDpnId,
206 rpcResult.getErrors());
208 destDpninterfacelist = rpcResult.getResult().getInterfacesList();
210 } catch (Exception e) {
211 LOG.warn("Exception when querying for GetDpnInterfaceList for dpnid {}", srcDpnId, e);
216 * Iterate over the list of VpnInterface for a SrcDpn on which TEP is added or deleted and read the adj.
217 * Update the adjacencies with the updated nexthop.
219 Iterator<String> interfacelistIter = srcDpninterfacelist.iterator();
220 String intfName = null;
221 List<Uuid> subnetList = new ArrayList<>();
222 Map<Long, String> vpnIdRdMap = new HashMap<>();
224 while (interfacelistIter.hasNext()) {
225 intfName = interfacelistIter.next();
226 final VpnInterface vpnInterface = VpnUtil.getOperationalVpnInterface(dataBroker, intfName);
227 if (vpnInterface != null) {
229 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
230 dataStoreCoordinator.enqueueJob("VPNINTERFACE-" + intfName,
231 new UpdateVpnInterfaceOnTunnelEvent(dataBroker,
238 // Populate the List of subnets
239 InstanceIdentifier<PortOpDataEntry> portOpIdentifier =
240 InstanceIdentifier.builder(PortOpData.class).child(PortOpDataEntry.class,
241 new PortOpDataEntryKey(intfName)).build();
242 Optional<PortOpDataEntry> optionalPortOp =
243 VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, portOpIdentifier);
244 if (optionalPortOp.isPresent()) {
245 Uuid subnetId = optionalPortOp.get().getSubnetId();
246 if (!subnetList.contains(subnetId)) {
247 subnetList.add(subnetId);
250 //Populate the map for VpnId-to-Rd
251 long vpnId = VpnUtil.getVpnId(dataBroker, vpnInterface.getVpnInstanceName());
252 rd = VpnUtil.getVpnRd(dataBroker, vpnInterface.getVpnInstanceName());
253 vpnIdRdMap.put(vpnId, rd);
258 * Iterate over the list of VpnInterface for destDPN and get the prefix .
259 * Create remote rule for each of those prefix on srcDPN.
261 interfacelistIter = destDpninterfacelist.iterator();
262 while (interfacelistIter.hasNext()) {
263 intfName = interfacelistIter.next();
264 final VpnInterface vpnInterface = VpnUtil.getOperationalVpnInterface(dataBroker, intfName);
265 if (vpnInterface != null) {
266 Adjacencies adjacencies = vpnInterface.getAugmentation(Adjacencies.class);
267 List<Adjacency> adjList = adjacencies != null ? adjacencies.getAdjacency()
268 : Collections.emptyList();
269 String prefix = null;
270 long vpnId = VpnUtil.getVpnId(dataBroker, vpnInterface.getVpnInstanceName());
271 if (vpnIdRdMap.containsKey(vpnId)) {
272 rd = vpnIdRdMap.get(vpnId);
273 LOG.trace(" Remote DpnId {} VpnId {} rd {} VpnInterface {}", remoteDpnId, vpnId, rd,
275 for (Adjacency adj : adjList) {
276 prefix = adj.getIpAddress();
277 long label = adj.getLabel();
278 if ((tunnelAction == TunnelAction.TUNNEL_EP_ADD)
279 && (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue())) {
280 fibManager.manageRemoteRouteOnDPN(true, srcDpnId, vpnId, rd, prefix, destTepIp, label);
283 if ((tunnelAction == TunnelAction.TUNNEL_EP_DELETE)
284 && (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue())) {
285 fibManager.manageRemoteRouteOnDPN(false, srcDpnId, vpnId, rd, prefix, destTepIp, label);
292 //Iterate over the VpnId-to-Rd map.
293 for (Map.Entry<Long, String> entry : vpnIdRdMap.entrySet()) {
294 Long vpnId = entry.getKey();
295 rd = entry.getValue();
296 if ((tunnelAction == TunnelAction.TUNNEL_EP_ADD)
297 && (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue())) {
298 fibManager.populateExternalRoutesOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
299 } else if ((tunnelAction == TunnelAction.TUNNEL_EP_DELETE)
300 && (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue())) {
301 fibManager.cleanUpExternalRoutesOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
305 if (tunnelAction == TunnelAction.TUNNEL_EP_ADD) {
306 for (Uuid subnetId : subnetList) {
307 // Populate the List of subnets
308 vpnSubnetRouteHandler.updateSubnetRouteOnTunnelUpEvent(subnetId, srcDpnId);
312 if ((tunnelAction == TunnelAction.TUNNEL_EP_DELETE) && isTepDeletedOnDpn) {
313 for (Uuid subnetId : subnetList) {
314 // Populate the List of subnets
315 vpnSubnetRouteHandler.updateSubnetRouteOnTunnelDownEvent(subnetId, srcDpnId);
318 } catch (Exception e) {
319 LOG.error("Unable to handle the tunnel event.", e);
325 private class UpdateVpnInterfaceOnTunnelEvent implements Callable {
326 private VpnInterface vpnInterface;
327 private StateTunnelList stateTunnelList;
328 private VpnInterfaceManager vpnInterfaceManager;
329 private DataBroker broker;
330 private TunnelAction tunnelAction;
331 private boolean isTepDeletedOnDpn;
333 UpdateVpnInterfaceOnTunnelEvent(DataBroker broker,
334 VpnInterfaceManager vpnInterfaceManager,
335 TunnelAction tunnelAction,
336 VpnInterface vpnInterface,
337 StateTunnelList stateTunnelList,
338 boolean isTepDeletedOnDpn) {
339 this.broker = broker;
340 this.vpnInterfaceManager = vpnInterfaceManager;
341 this.stateTunnelList = stateTunnelList;
342 this.vpnInterface = vpnInterface;
343 this.tunnelAction = tunnelAction;
344 this.isTepDeletedOnDpn = isTepDeletedOnDpn;
348 public List<ListenableFuture<Void>> call() throws Exception {
350 if (tunnelAction == TunnelAction.TUNNEL_EP_ADD) {
351 vpnInterfaceManager.updateVpnInterfaceOnTepAdd(vpnInterface, stateTunnelList);
354 if ((tunnelAction == TunnelAction.TUNNEL_EP_DELETE) && isTepDeletedOnDpn) {
355 vpnInterfaceManager.updateVpnInterfaceOnTepDelete(vpnInterface, stateTunnelList);
362 private int getTunnelType(StateTunnelList stateTunnelList) {
364 if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeInternal.class) {
365 tunTypeVal = VpnConstants.ITMTunnelLocType.Internal.getValue();
366 } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeExternal.class) {
367 tunTypeVal = VpnConstants.ITMTunnelLocType.External.getValue();
368 } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeHwvtep.class) {
369 tunTypeVal = VpnConstants.ITMTunnelLocType.Hwvtep.getValue();
371 tunTypeVal = VpnConstants.ITMTunnelLocType.Invalid.getValue();