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.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;
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
71 protected enum TunnelAction {
77 * Responsible for listening to tunnel interface state change
79 * @param dataBroker dataBroker
80 * @param bgpManager bgpManager
81 * @param fibManager fibManager
82 * @param itmRpcService itmRpcService
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;
101 public void start() {
102 LOG.info("{} start", getClass().getSimpleName());
103 registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
107 protected InstanceIdentifier<StateTunnelList> getWildCardPath() {
108 return InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class);
112 protected TunnelInterfaceStateListener getDataTreeChangeListener() {
113 return TunnelInterfaceStateListener.this;
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);
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);
135 boolean isTunnelUp = (tunOpStatus == TunnelOperStatus.Up);
136 handleTunnelEventForDPN(update,
137 isTunnelUp ? UpdateRouteAction.ADVERTISE_ROUTE : UpdateRouteAction.WITHDRAW_ROUTE,
138 TunnelAction.TUNNEL_EP_UPDATE);
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);
149 boolean isTunnelUp = (tunOpStatus == TunnelOperStatus.Up);
151 LOG.trace("Tunnel {} is not yet UP.",
152 add.getTunnelInterfaceName());
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);
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);
169 LOG.trace("tunTypeVal is {}", tunTypeVal);
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);
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);
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());
194 } else if (tunnelAction == TunnelAction.TUNNEL_EP_DELETE) {
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;
202 endpointIpForDPN = InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, srcDpnId);
203 } catch (Exception e) {
204 /* this dpn does not have the VTEP */
205 endpointIpForDPN = null;
208 if (endpointIpForDPN != null) {
209 LOG.trace("Ignore Tunnel DELETE event received for Dpn {} VTEP Ip {}", srcDpnId, srcTepIp);
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);
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);
228 LOG.trace(" Tunnel DELETE event already received for Dpn {} VTEP Ip {} ", srcDpnId, srcTepIp);
232 // Get the list of VpnInterfaces from Intf Mgr for a given DPN.
233 Future<RpcResult<GetDpnInterfaceListOutput>> result;
234 List<String> interfacelist = new ArrayList<>();
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());
241 interfacelist = rpcResult.getResult().getInterfacesList();
243 } catch (Exception e) {
244 LOG.warn("Exception {} when querying for GetDpnInterfaceList for dpnid {}, trace {}", e, srcDpnId, e.getStackTrace());
248 * Iterate over the list of VpnInterface for a given Dpn and read the adj.
249 * Update the adjacencies with the updated nexthop.
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>();
256 while (interfacelistIter.hasNext()) {
257 intfName = interfacelistIter.next();
258 final VpnInterface vpnInterface = VpnUtil.getOperationalVpnInterface(dataBroker, intfName);
259 if (vpnInterface != null) {
261 DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
262 dataStoreCoordinator.enqueueJob("VPNINTERFACE-" + intfName,
263 new UpdateVpnInterfaceOnTunnelEvent(dataBroker,
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);
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);
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);
299 if(tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue()) {
300 fibManager.populateExternalRoutesOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
302 } else if (tunnelAction == TunnelAction.TUNNEL_EP_DELETE) {
303 if(tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
304 fibManager.cleanUpInternalRoutesOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
306 if(tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue()) {
307 fibManager.cleanUpExternalRoutesOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
312 if (action == UpdateRouteAction.ADVERTISE_ROUTE) {
313 for (Uuid subnetId : subnetList) {
314 // Populate the List of subnets
315 vpnSubnetRouteHandler.updateSubnetRouteOnTunnelUpEvent(subnetId, srcDpnId);
319 if (action == UpdateRouteAction.WITHDRAW_ROUTE) {
320 for (Uuid subnetId : subnetList) {
321 // Populate the List of subnets
322 vpnSubnetRouteHandler.updateSubnetRouteOnTunnelDownEvent(subnetId, srcDpnId);
325 } catch (Exception e) {
326 LOG.error("Unable to handle the tunnel event.", e);
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;
342 UpdateVpnInterfaceOnTunnelEvent(DataBroker broker,
343 VpnInterfaceManager vpnInterfaceManager,
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;
358 public List<ListenableFuture<Void>> call() throws Exception {
359 WriteTransaction writeOperTxn = broker.newWriteOnlyTransaction();
360 WriteTransaction writeConfigTxn = broker.newWriteOnlyTransaction();
362 if(tunnelAction == TunnelAction.TUNNEL_EP_ADD) {
363 vpnInterfaceManager.updateVpnInterfaceOnTepAdd(vpnInterface, stateTunnelList, writeOperTxn, writeConfigTxn);
366 if(tunnelAction == TunnelAction.TUNNEL_EP_DELETE) {
367 vpnInterfaceManager.updateVpnInterfaceOnTepDelete(vpnInterface, writeOperTxn, writeConfigTxn);
370 List<ListenableFuture<Void>> futures = new ArrayList<ListenableFuture<Void>>();
371 futures.add(writeOperTxn.submit());
372 futures.add(writeConfigTxn.submit());
377 private int getTunnelType (StateTunnelList stateTunnelList) {
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();
386 tunTypeVal = VpnConstants.ITMTunnelLocType.Invalid.getValue();