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
9 package org.opendaylight.netvirt.vpnmanager;
11 import com.google.common.base.Optional;
13 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
14 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
15 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
16 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
17 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
18 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
19 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnAfConfig;
20 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
21 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
22 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelsState;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeExternal;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeHwvtep;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeInternal;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.IsDcgwPresentInputBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.IsDcgwPresentOutput;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
35 import org.opendaylight.yangtools.concepts.ListenerRegistration;
36 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
37 import org.opendaylight.yangtools.yang.common.RpcResult;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
41 import java.math.BigInteger;
42 import java.util.Iterator;
43 import java.util.List;
44 import java.util.concurrent.Future;
46 public class TunnelInterfaceStateListener extends AbstractDataChangeListener<StateTunnelList> implements AutoCloseable{
48 private static final Logger LOG = LoggerFactory.getLogger(TunnelInterfaceStateListener.class);
49 protected enum UpdateRouteAction {
50 ADVERTISE_ROUTE, WITHDRAW_ROUTE
53 private ListenerRegistration<DataChangeListener> tunnelInterfaceStateListenerRegistration;
54 private final DataBroker broker;
55 private final IBgpManager bgpManager;
56 private IFibManager fibManager;
57 private ItmRpcService itmRpcService;
60 * Responsible for listening to tunnel interface state change
62 * @param db - dataBroker service reference
63 * @param bgpManager Used to advertise routes to the BGP Router
65 public TunnelInterfaceStateListener(final DataBroker db,
66 final IBgpManager bgpManager) {
67 super(StateTunnelList.class);
69 this.bgpManager = bgpManager;
73 public void setITMRpcService(ItmRpcService itmRpcService) {
74 this.itmRpcService = itmRpcService;
77 public void setFibManager(IFibManager fibManager) {
78 this.fibManager = fibManager;
81 public IFibManager getFibManager() {
82 return this.fibManager;
86 public void close() throws Exception {
87 if (tunnelInterfaceStateListenerRegistration != null) {
89 tunnelInterfaceStateListenerRegistration.close();
90 } catch (final Exception e) {
91 LOG.error("Error when cleaning up DataChangeListener.", e);
93 tunnelInterfaceStateListenerRegistration = null;
95 LOG.info("Tunnel Interface State Listener Closed");
98 private void registerListener(final DataBroker db) {
100 tunnelInterfaceStateListenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
101 getWildCardPath(), TunnelInterfaceStateListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
102 } catch (final Exception e) {
103 LOG.error("Tunnel Interface State Listener DataChange listener registration fail!", e);
104 throw new IllegalStateException("Tunnel Interface State Listener registration Listener failed.", e);
108 private InstanceIdentifier<StateTunnelList> getWildCardPath() {
109 return InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class);
113 protected void remove(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList del) {
114 LOG.trace("Tunnel deletion---- {}", del);
115 handlePrefixesForDPNs(del, UpdateRouteAction.WITHDRAW_ROUTE);
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.isTunnelState(), update.isTunnelState());
125 //withdraw all prefixes in all vpns for this dpn
126 boolean isTunnelUp = update.isTunnelState();
127 handlePrefixesForDPNs(update, isTunnelUp ? UpdateRouteAction.ADVERTISE_ROUTE :
128 UpdateRouteAction.WITHDRAW_ROUTE);
132 protected void add(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList add) {
133 LOG.trace("Tunnel addition---- {}", add);
135 if (!add.isTunnelState()) {
136 LOG.trace("Tunnel {} is not yet UP.",
137 add.getTunnelInterfaceName());
140 LOG.trace("ITM Tunnel ,type {} ,State is UP b/w src: {} and dest: {}",
141 fibManager.getTransportTypeStr(add.getTransportType().toString()),
142 add.getSrcInfo().getTepDeviceId(), add.getDstInfo().getTepDeviceId());
143 handlePrefixesForDPNs(add, UpdateRouteAction.ADVERTISE_ROUTE);
147 private void handlePrefixesForDPNs(StateTunnelList stateTunnelList, UpdateRouteAction action) {
148 BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
149 BigInteger destDpnId;
150 String srcTepIp = String.valueOf(stateTunnelList.getSrcInfo().getTepIp().getValue());
151 String destTepIp = String.valueOf(stateTunnelList.getDstInfo().getTepIp().getValue());
153 InstanceIdentifier.InstanceIdentifierBuilder<VpnInstances> idBuilder = InstanceIdentifier.builder(VpnInstances.class);
154 InstanceIdentifier<VpnInstances> vpnInstancesId = idBuilder.build();
155 Optional<VpnInstances> vpnInstances = VpnUtil.read(broker, LogicalDatastoreType.CONFIGURATION, vpnInstancesId);
156 long tunTypeVal = 0, vpnId;
158 if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeInternal.class) {
159 tunTypeVal = VpnConstants.ITMTunnelLocType.Internal.getValue();
160 } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeExternal.class) {
161 tunTypeVal = VpnConstants.ITMTunnelLocType.External.getValue();
162 } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeHwvtep.class) {
163 tunTypeVal = VpnConstants.ITMTunnelLocType.Hwvtep.getValue();
165 tunTypeVal = VpnConstants.ITMTunnelLocType.Invalid.getValue();
167 LOG.trace("tunTypeVal is {}", tunTypeVal);
169 long dcgwPresentStatus = VpnConstants.DCGWPresentStatus.Invalid.getValue();
170 if (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue()) {
171 Future<RpcResult<IsDcgwPresentOutput>> result;
173 result = itmRpcService.isDcgwPresent(new IsDcgwPresentInputBuilder()
174 .setDcgwIp(destTepIp)
176 RpcResult<IsDcgwPresentOutput> rpcResult = result.get();
177 if (!rpcResult.isSuccessful()) {
178 LOG.warn("RPC Call to isDcgwPresent {} returned with Errors {}", destTepIp, rpcResult.getErrors());
180 dcgwPresentStatus = rpcResult.getResult().getRetVal();
182 } catch (Exception e) {
183 LOG.warn("Exception {} when querying for isDcgwPresent {}, trace {}", e, destTepIp, e.getStackTrace());
187 if (vpnInstances.isPresent()) {
188 List<VpnInstance> vpnInstanceList = vpnInstances.get().getVpnInstance();
189 Iterator<VpnInstance> vpnInstIter = vpnInstanceList.iterator();
190 LOG.trace("vpnInstIter {}", vpnInstIter);
191 while (vpnInstIter.hasNext()) {
192 VpnInstance vpnInstance = vpnInstIter.next();
193 LOG.trace("vpnInstance {}", vpnInstance);
194 vpnId = VpnUtil.getVpnId(broker, vpnInstance.getVpnInstanceName());
196 VpnAfConfig vpnConfig = vpnInstance.getIpv4Family();
197 LOG.trace("vpnConfig {}", vpnConfig);
198 String rd = vpnConfig.getRouteDistinguisher();
199 if (rd == null || rd.isEmpty()) {
200 rd = vpnInstance.getVpnInstanceName();
201 LOG.trace("rd is null or empty. Assigning VpnInstanceName to rd {}", rd);
203 InstanceIdentifier<VpnToDpnList> srcId =
204 VpnUtil.getVpnToDpnListIdentifier(rd, srcDpnId);
205 Optional<VpnToDpnList> srcDpnInVpn =
206 VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, srcId);
207 if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
208 destDpnId = new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId());
209 InstanceIdentifier<VpnToDpnList> destId =
210 VpnUtil.getVpnToDpnListIdentifier(rd, destDpnId);
211 Optional<VpnToDpnList> destDpnInVpn =
212 VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, destId);
213 if (!(srcDpnInVpn.isPresent() &&
214 destDpnInVpn.isPresent())) {
215 LOG.trace(" srcDpn {} - destDPN {}, do not share the VPN {} with rd {}.",
216 srcDpnId, destDpnId, vpnInstance.getVpnInstanceName(), rd);
220 if (srcDpnInVpn.isPresent()) {
221 List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
222 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces>
223 vpnInterfaces = srcDpnInVpn.get().getVpnInterfaces();
224 for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
225 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces vpnInterface : vpnInterfaces) {
226 InstanceIdentifier<VpnInterface> vpnIntfId =
227 VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getInterfaceName());
228 LOG.trace("vpnInterface {}", vpnInterface);
229 InstanceIdentifier<Adjacencies> path =
230 vpnIntfId.augmentation(Adjacencies.class);
231 Optional<Adjacencies> adjacencies =
232 VpnUtil.read(broker, LogicalDatastoreType.OPERATIONAL, path);
233 LOG.trace("adjacencies {}", adjacencies);
234 if (adjacencies.isPresent()) {
235 List<Adjacency> adjacencyList = adjacencies.get().getAdjacency();
236 Iterator<Adjacency> adjacencyIterator = adjacencyList.iterator();
238 while (adjacencyIterator.hasNext()) {
239 Adjacency adjacency = adjacencyIterator.next();
241 if (action == UpdateRouteAction.ADVERTISE_ROUTE) {
242 LOG.info("VPNInterfaceManager : Added Fib Entry rd {} prefix {} nextHop {} label {}",
243 rd, adjacency.getIpAddress(), adjacency.getNextHopIpList(),
244 adjacency.getLabel());
245 // vrf = new VrfEntryBuilder().set
246 if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
247 fibManager.handleRemoteRoute(true,
248 new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId()),
249 new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId()),
250 VpnUtil.getVpnId(broker, vpnInstance.getVpnInstanceName()),
251 rd, adjacency.getIpAddress(), srcTepIp, destTepIp);
253 if (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue()) {
254 fibManager.populateFibOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
256 } else if (action == UpdateRouteAction.WITHDRAW_ROUTE) {
257 LOG.info("VPNInterfaceManager : Removed Fib entry rd {} prefix {}",
258 rd, adjacency.getIpAddress());
259 if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
260 fibManager.handleRemoteRoute(false, srcDpnId,
261 new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId()),
262 vpnId, rd, adjacency.getIpAddress(), srcTepIp, destTepIp);
264 if ((tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue()) &&
265 (dcgwPresentStatus == VpnConstants.DCGWPresentStatus.Absent.getValue())) { bgpManager.withdrawPrefix(rd, adjacency.getIpAddress());
266 fibManager.cleanUpDpnForVpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
269 } catch (Exception e) {
270 LOG.error("Exception when updating prefix {} in vrf {} to BGP",
271 adjacency.getIpAddress(), rd);
275 LOG.trace("no adjacencies present for path {}.", path);
278 // if (action == UpdateRouteAction.WITHDRAW_ROUTE) {
279 // fibManager.cleanUpDpnForVpn(dpnId, VpnUtil.getVpnId(broker, vpnInstance.getVpnInstanceName()), rd);
281 // Go through all the VrfEntries and withdraw and readvertise the prefixes to BGP for which the nextHop is the SrcTepIp
282 if ((action == UpdateRouteAction.ADVERTISE_ROUTE) &&
283 (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue())) {
284 List<VrfEntry> vrfEntries = VpnUtil.getAllVrfEntries(broker, rd);
285 if (vrfEntries != null) {
286 for (VrfEntry vrfEntry : vrfEntries) {
287 String destPrefix = vrfEntry.getDestPrefix().trim();
288 int vpnLabel = vrfEntry.getLabel().intValue();
289 List<String> nextHops = vrfEntry.getNextHopAddressList();
290 if (nextHops.contains(srcTepIp.trim())) {
291 bgpManager.withdrawPrefix(rd, destPrefix);
292 bgpManager.advertisePrefix(rd, destPrefix, nextHops, vpnLabel);
298 LOG.trace("dpnInVpn check failed for srcDpnId {}.", srcDpnId);
300 } catch (Exception e) {
301 LOG.error("updatePrefixesForDPN {} in vpn {} failed", 0, vpnInstance.getVpnInstanceName(), e);
305 LOG.trace("No vpn instances present.");