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;
12 import java.util.Iterator;
13 import java.util.List;
14 import java.util.concurrent.Future;
15 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
16 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
17 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
18 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
19 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
20 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
21 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnAfConfig;
22 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.VpnInstances;
23 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.instances.VpnInstance;
24 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeExternal;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeHwvtep;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeInternal;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelsState;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.IsDcgwPresentInputBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.IsDcgwPresentOutput;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.rpcs.rev160406.ItmRpcService;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
37 import org.opendaylight.yangtools.concepts.ListenerRegistration;
38 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
39 import org.opendaylight.yangtools.yang.common.RpcResult;
40 import org.slf4j.Logger;
41 import org.slf4j.LoggerFactory;
43 public class TunnelInterfaceStateListener extends AbstractDataChangeListener<StateTunnelList>
44 implements AutoCloseable{
45 private static final Logger LOG = LoggerFactory.getLogger(TunnelInterfaceStateListener.class);
46 private ListenerRegistration<DataChangeListener> listenerRegistration;
47 private final DataBroker dataBroker;
48 private final IBgpManager bgpManager;
49 private IFibManager fibManager;
50 private ItmRpcService itmRpcService;
51 protected enum UpdateRouteAction {
52 ADVERTISE_ROUTE, WITHDRAW_ROUTE
56 * Responsible for listening to tunnel interface state change
58 * @param dataBroker dataBroker
59 * @param bgpManager bgpManager
60 * @param fibManager fibManager
61 * @param itmRpcService itmRpcService
63 public TunnelInterfaceStateListener(final DataBroker dataBroker,
64 final IBgpManager bgpManager,
65 final IFibManager fibManager,
66 final ItmRpcService itmRpcService) {
67 super(StateTunnelList.class);
68 this.dataBroker = dataBroker;
69 this.bgpManager = bgpManager;
70 this.fibManager = fibManager;
71 this.itmRpcService = itmRpcService;
75 LOG.info("{} start", getClass().getSimpleName());
76 listenerRegistration = dataBroker.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
77 getWildCardPath(), this, AsyncDataBroker.DataChangeScope.SUBTREE);
80 private InstanceIdentifier<StateTunnelList> getWildCardPath() {
81 return InstanceIdentifier.create(TunnelsState.class).child(StateTunnelList.class);
85 public void close() throws Exception {
86 if (listenerRegistration != null) {
87 listenerRegistration.close();
88 listenerRegistration = null;
90 LOG.info("{} close", getClass().getSimpleName());
94 protected void remove(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList del) {
95 LOG.trace("Tunnel deletion---- {}", del);
96 handlePrefixesForDPNs(del, UpdateRouteAction.WITHDRAW_ROUTE);
100 protected void update(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList original, StateTunnelList update) {
101 LOG.trace("Tunnel updation---- {}", update);
102 LOG.trace("ITM Tunnel {} of type {} state event changed from :{} to :{}",
103 update.getTunnelInterfaceName(),
104 fibManager.getTransportTypeStr(update.getTransportType().toString()),
105 original.isTunnelState(), update.isTunnelState());
106 //withdraw all prefixes in all vpns for this dpn
107 boolean isTunnelUp = update.isTunnelState();
108 handlePrefixesForDPNs(update, isTunnelUp ? UpdateRouteAction.ADVERTISE_ROUTE :
109 UpdateRouteAction.WITHDRAW_ROUTE);
113 protected void add(InstanceIdentifier<StateTunnelList> identifier, StateTunnelList add) {
114 LOG.trace("Tunnel addition---- {}", add);
116 if (!add.isTunnelState()) {
117 LOG.trace("Tunnel {} is not yet UP.",
118 add.getTunnelInterfaceName());
121 LOG.trace("ITM Tunnel ,type {} ,State is UP b/w src: {} and dest: {}",
122 fibManager.getTransportTypeStr(add.getTransportType().toString()),
123 add.getSrcInfo().getTepDeviceId(), add.getDstInfo().getTepDeviceId());
124 handlePrefixesForDPNs(add, UpdateRouteAction.ADVERTISE_ROUTE);
128 private void handlePrefixesForDPNs(StateTunnelList stateTunnelList, UpdateRouteAction action) {
129 BigInteger srcDpnId = new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId());
130 BigInteger destDpnId;
131 String srcTepIp = String.valueOf(stateTunnelList.getSrcInfo().getTepIp().getValue());
132 String destTepIp = String.valueOf(stateTunnelList.getDstInfo().getTepIp().getValue());
134 InstanceIdentifier.InstanceIdentifierBuilder<VpnInstances> idBuilder = InstanceIdentifier.builder(VpnInstances.class);
135 InstanceIdentifier<VpnInstances> vpnInstancesId = idBuilder.build();
136 Optional<VpnInstances> vpnInstances = VpnUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, vpnInstancesId);
137 long tunTypeVal = 0, vpnId;
139 if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeInternal.class) {
140 tunTypeVal = VpnConstants.ITMTunnelLocType.Internal.getValue();
141 } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeExternal.class) {
142 tunTypeVal = VpnConstants.ITMTunnelLocType.External.getValue();
143 } else if (stateTunnelList.getDstInfo().getTepDeviceType() == TepTypeHwvtep.class) {
144 tunTypeVal = VpnConstants.ITMTunnelLocType.Hwvtep.getValue();
146 tunTypeVal = VpnConstants.ITMTunnelLocType.Invalid.getValue();
148 LOG.trace("tunTypeVal is {}", tunTypeVal);
150 long dcgwPresentStatus = VpnConstants.DCGWPresentStatus.Invalid.getValue();
151 if (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue()) {
152 Future<RpcResult<IsDcgwPresentOutput>> result;
154 result = itmRpcService.isDcgwPresent(new IsDcgwPresentInputBuilder()
155 .setDcgwIp(destTepIp)
157 RpcResult<IsDcgwPresentOutput> rpcResult = result.get();
158 if (!rpcResult.isSuccessful()) {
159 LOG.warn("RPC Call to isDcgwPresent {} returned with Errors {}", destTepIp, rpcResult.getErrors());
161 dcgwPresentStatus = rpcResult.getResult().getRetVal();
163 } catch (Exception e) {
164 LOG.warn("Exception {} when querying for isDcgwPresent {}, trace {}", e, destTepIp, e.getStackTrace());
168 if (vpnInstances.isPresent()) {
169 List<VpnInstance> vpnInstanceList = vpnInstances.get().getVpnInstance();
170 Iterator<VpnInstance> vpnInstIter = vpnInstanceList.iterator();
171 LOG.trace("vpnInstIter {}", vpnInstIter);
172 while (vpnInstIter.hasNext()) {
173 VpnInstance vpnInstance = vpnInstIter.next();
174 LOG.trace("vpnInstance {}", vpnInstance);
175 vpnId = VpnUtil.getVpnId(dataBroker, vpnInstance.getVpnInstanceName());
177 VpnAfConfig vpnConfig = vpnInstance.getIpv4Family();
178 LOG.trace("vpnConfig {}", vpnConfig);
179 String rd = vpnConfig.getRouteDistinguisher();
180 if (rd == null || rd.isEmpty()) {
181 rd = vpnInstance.getVpnInstanceName();
182 LOG.trace("rd is null or empty. Assigning VpnInstanceName to rd {}", rd);
184 InstanceIdentifier<VpnToDpnList> srcId =
185 VpnUtil.getVpnToDpnListIdentifier(rd, srcDpnId);
186 Optional<VpnToDpnList> srcDpnInVpn =
187 VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, srcId);
188 if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
189 destDpnId = new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId());
190 InstanceIdentifier<VpnToDpnList> destId =
191 VpnUtil.getVpnToDpnListIdentifier(rd, destDpnId);
192 Optional<VpnToDpnList> destDpnInVpn =
193 VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, destId);
194 if (!(srcDpnInVpn.isPresent() &&
195 destDpnInVpn.isPresent())) {
196 LOG.trace(" srcDpn {} - destDPN {}, do not share the VPN {} with rd {}.",
197 srcDpnId, destDpnId, vpnInstance.getVpnInstanceName(), rd);
201 if (srcDpnInVpn.isPresent()) {
202 List<org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
203 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces>
204 vpnInterfaces = srcDpnInVpn.get().getVpnInterfaces();
205 for (org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data
206 .vpn.instance.op.data.entry.vpn.to.dpn.list.VpnInterfaces vpnInterface : vpnInterfaces) {
207 InstanceIdentifier<VpnInterface> vpnIntfId =
208 VpnUtil.getVpnInterfaceIdentifier(vpnInterface.getInterfaceName());
209 LOG.trace("vpnInterface {}", vpnInterface);
210 InstanceIdentifier<Adjacencies> path =
211 vpnIntfId.augmentation(Adjacencies.class);
212 Optional<Adjacencies> adjacencies =
213 VpnUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, path);
214 LOG.trace("adjacencies {}", adjacencies);
215 if (adjacencies.isPresent()) {
216 List<Adjacency> adjacencyList = adjacencies.get().getAdjacency();
217 Iterator<Adjacency> adjacencyIterator = adjacencyList.iterator();
219 while (adjacencyIterator.hasNext()) {
220 Adjacency adjacency = adjacencyIterator.next();
222 if (action == UpdateRouteAction.ADVERTISE_ROUTE) {
223 LOG.info("VPNInterfaceManager : Added Fib Entry rd {} prefix {} nextHop {} label {}",
224 rd, adjacency.getIpAddress(), adjacency.getNextHopIpList(),
225 adjacency.getLabel());
226 // vrf = new VrfEntryBuilder().set
227 if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
228 fibManager.handleRemoteRoute(true,
229 new BigInteger(stateTunnelList.getSrcInfo().getTepDeviceId()),
230 new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId()),
231 VpnUtil.getVpnId(dataBroker, vpnInstance.getVpnInstanceName()),
232 rd, adjacency.getIpAddress(), srcTepIp, destTepIp);
234 if (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue()) {
235 fibManager.populateFibOnDpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
237 } else if (action == UpdateRouteAction.WITHDRAW_ROUTE) {
238 LOG.info("VPNInterfaceManager : Removed Fib entry rd {} prefix {}",
239 rd, adjacency.getIpAddress());
240 if (tunTypeVal == VpnConstants.ITMTunnelLocType.Internal.getValue()) {
241 fibManager.handleRemoteRoute(false, srcDpnId,
242 new BigInteger(stateTunnelList.getDstInfo().getTepDeviceId()),
243 vpnId, rd, adjacency.getIpAddress(), srcTepIp, destTepIp);
245 if ((tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue()) &&
246 (dcgwPresentStatus == VpnConstants.DCGWPresentStatus.Absent.getValue())) { bgpManager.withdrawPrefix(rd, adjacency.getIpAddress());
247 fibManager.cleanUpDpnForVpn(srcDpnId, vpnId, rd, srcTepIp, destTepIp);
250 } catch (Exception e) {
251 LOG.error("Exception when updating prefix {} in vrf {} to BGP",
252 adjacency.getIpAddress(), rd);
256 LOG.trace("no adjacencies present for path {}.", path);
259 // if (action == UpdateRouteAction.WITHDRAW_ROUTE) {
260 // fibManager.cleanUpDpnForVpn(dpnId, VpnUtil.getVpnId(dataBroker, vpnInstance.getVpnInstanceName()), rd);
262 // Go through all the VrfEntries and withdraw and readvertise the prefixes to BGP for which the nextHop is the SrcTepIp
263 if ((action == UpdateRouteAction.ADVERTISE_ROUTE) &&
264 (tunTypeVal == VpnConstants.ITMTunnelLocType.External.getValue())) {
265 List<VrfEntry> vrfEntries = VpnUtil.getAllVrfEntries(dataBroker, rd);
266 if (vrfEntries != null) {
267 for (VrfEntry vrfEntry : vrfEntries) {
268 String destPrefix = vrfEntry.getDestPrefix().trim();
269 int vpnLabel = vrfEntry.getLabel().intValue();
270 List<String> nextHops = vrfEntry.getNextHopAddressList();
271 if (nextHops.contains(srcTepIp.trim())) {
272 bgpManager.withdrawPrefix(rd, destPrefix);
273 bgpManager.advertisePrefix(rd, destPrefix, nextHops, vpnLabel);
279 LOG.trace("dpnInVpn check failed for srcDpnId {}.", srcDpnId);
281 } catch (Exception e) {
282 LOG.error("updatePrefixesForDPN {} in vpn {} failed", 0, vpnInstance.getVpnInstanceName(), e);
286 LOG.trace("No vpn instances present.");