NETVIRT-1630 migrate to md-sal APIs
[netvirt.git] / vpnmanager / impl / src / main / java / org / opendaylight / netvirt / vpnmanager / intervpnlink / IVpnLinkServiceImpl.java
1 /*
2  * Copyright (c) 2017 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.netvirt.vpnmanager.intervpnlink;
9
10 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
11
12 import com.google.common.base.Preconditions;
13 import java.util.ArrayList;
14 import java.util.Collections;
15 import java.util.HashMap;
16 import java.util.List;
17 import java.util.Map;
18 import java.util.Objects;
19 import java.util.Optional;
20 import java.util.concurrent.ExecutionException;
21 import java.util.stream.Collectors;
22 import javax.annotation.PreDestroy;
23 import javax.inject.Inject;
24 import javax.inject.Singleton;
25 import org.eclipse.jdt.annotation.Nullable;
26 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
27 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
28 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
29 import org.opendaylight.genius.mdsalutil.NwConstants;
30 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
31 import org.opendaylight.mdsal.binding.api.DataBroker;
32 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
33 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
34 import org.opendaylight.netvirt.fibmanager.api.FibHelper;
35 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
36 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
37 import org.opendaylight.netvirt.neutronvpn.api.utils.NeutronUtils;
38 import org.opendaylight.netvirt.vpnmanager.VpnConstants;
39 import org.opendaylight.netvirt.vpnmanager.VpnUtil;
40 import org.opendaylight.netvirt.vpnmanager.api.InterfaceUtils;
41 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.IVpnLinkService;
42 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkCache;
43 import org.opendaylight.netvirt.vpnmanager.api.intervpnlink.InterVpnLinkDataComposite;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
45 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.FibEntries;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntryKey;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.VpnMaps;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.vpnmaps.VpnMap;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.l3.attributes.Routes;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.Routers;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
59 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
60 import org.opendaylight.yangtools.yang.common.Uint32;
61 import org.opendaylight.yangtools.yang.common.Uint64;
62 import org.slf4j.Logger;
63 import org.slf4j.LoggerFactory;
64
65 @Singleton
66 public class IVpnLinkServiceImpl implements IVpnLinkService, AutoCloseable {
67
68     private static final Logger LOG = LoggerFactory.getLogger(IVpnLinkServiceImpl.class);
69
70     private final DataBroker dataBroker;
71     private final ManagedNewTransactionRunner txRunner;
72     private final IdManagerService idManager;
73     private final IBgpManager bgpManager;
74     private final IFibManager fibManager;
75     private final InterVpnLinkCache interVpnLinkCache;
76     private final VpnUtil vpnUtil;
77     private final InterVpnLinkUtil interVpnLinkUtil;
78
79     @Inject
80     public IVpnLinkServiceImpl(final DataBroker dataBroker, final IdManagerService idMgr, final IBgpManager bgpMgr,
81                                final IFibManager fibMgr, final InterVpnLinkCache interVpnLinkCache,
82                                VpnUtil vpnUtil, InterVpnLinkUtil interVpnLinkUtil) {
83         this.dataBroker = dataBroker;
84         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
85         this.idManager = idMgr;
86         this.bgpManager = bgpMgr;
87         this.fibManager = fibMgr;
88         this.interVpnLinkCache = interVpnLinkCache;
89         this.vpnUtil = vpnUtil;
90         this.interVpnLinkUtil = interVpnLinkUtil;
91     }
92
93     public void start() {
94         LOG.info("{} start", getClass().getSimpleName());
95     }
96
97     @Override
98     @PreDestroy
99     public void close() {
100     }
101
102     @Override
103     public void leakRoute(String vpnName, String prefix, List<String> nextHopList, Uint32 label, int addOrRemove) {
104         LOG.trace("leakRoute: vpnName={}  prefix={}  nhList={}  label={}", vpnName, prefix, nextHopList, label);
105         Optional<InterVpnLinkDataComposite> optIVpnLink = interVpnLinkCache.getInterVpnLinkByVpnId(vpnName);
106         if (!optIVpnLink.isPresent()) {
107             LOG.debug("Vpn {} not involved in any InterVpnLink", vpnName);
108             return;
109         }
110         leakRoute(optIVpnLink.get(), vpnName, prefix, nextHopList, label, addOrRemove);
111     }
112
113     // TODO Clean up the exception handling
114     @SuppressWarnings("checkstyle:IllegalCatch")
115     private void leakRoute(InterVpnLinkDataComposite interVpnLink, String vpnName, String prefix,
116                            List<String> nextHopList, Uint32 label, int addOrRemove) {
117
118         String dstVpnName = interVpnLink.getOtherVpnName(vpnName);
119
120         LOG.trace("leakingRoute: from VPN={} to VPN={}: prefix={}  nhList={}  label={}",
121                   vpnName, dstVpnName, prefix, nextHopList, label);
122
123         // For leaking, we need the InterVpnLink to be active.
124         if (addOrRemove == NwConstants.ADD_FLOW && !interVpnLink.isActive()) {
125             LOG.warn("Cannot leak route [prefix={}, label={}] from VPN {} to VPN {} because "
126                      + "InterVpnLink {} is not active",
127                      prefix, label, vpnName, dstVpnName, interVpnLink.getInterVpnLinkName());
128             return;
129         }
130
131         String dstVpnRd = vpnUtil.getVpnRd(dstVpnName);
132         if (addOrRemove == NwConstants.ADD_FLOW) {
133             LOG.debug("Leaking route (prefix={}, nexthop={}) from Vpn={} to Vpn={} (RD={})",
134                       prefix, nextHopList, vpnName, dstVpnName, dstVpnRd);
135             String key = dstVpnRd + VpnConstants.SEPARATOR + prefix;
136             Uint32 leakedLabel = vpnUtil.getUniqueId(VpnConstants.VPN_IDPOOL_NAME, key);
137             String leakedNexthop = interVpnLink.getEndpointIpAddr(vpnName);
138             fibManager.addOrUpdateFibEntry(dstVpnRd, null /*macAddress*/, prefix,
139                                            Collections.singletonList(leakedNexthop), VrfEntry.EncapType.Mplsgre,
140                                            leakedLabel, Uint32.ZERO /*l3vni*/, null /*gatewayMacAddress*/,
141                                            null /*parentVpnRd*/, RouteOrigin.INTERVPN, null /*writeConfigTxn*/);
142
143             List<String> ivlNexthops =
144                 interVpnLink.getEndpointDpnsByVpnName(dstVpnName).stream()
145                             .map(dpnId -> InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId))
146                             .collect(Collectors.toList());
147             try {
148                 bgpManager.advertisePrefix(dstVpnRd, null /*macAddress*/, prefix, ivlNexthops,
149                                            VrfEntry.EncapType.Mplsgre, leakedLabel, Uint32.ZERO /*l3vni*/,
150                                            Uint32.ZERO /*l2vni*/, null /*gwMacAddress*/);
151             } catch (Exception e) {
152                 LOG.error("Exception while advertising prefix {} on vpnRd {} for intervpn link", prefix, dstVpnRd, e);
153             }
154         } else {
155             LOG.debug("Removing leaked route to {} from VPN {}", prefix, dstVpnName);
156             fibManager.removeFibEntry(dstVpnRd, prefix, null, null /*writeConfigTxn*/);
157             bgpManager.withdrawPrefix(dstVpnRd, prefix);
158         }
159     }
160
161     // TODO Clean up the exception handling
162     @SuppressWarnings("checkstyle:IllegalCatch")
163     @Override
164     public void leakRoute(InterVpnLinkDataComposite interVpnLink, String srcVpnUuid, String dstVpnUuid,
165                           String prefix, Uint32 label, @Nullable RouteOrigin forcedOrigin) {
166         String ivpnLinkName = interVpnLink.getInterVpnLinkName();
167         // The source VPN must participate in the InterVpnLink
168         Preconditions.checkArgument(interVpnLink.isVpnLinked(srcVpnUuid),
169                                     "The source VPN {} does not participate in the interVpnLink {}",
170                                     srcVpnUuid, ivpnLinkName);
171         // The destination VPN must participate in the InterVpnLink
172         Preconditions.checkArgument(interVpnLink.isVpnLinked(dstVpnUuid),
173                                     "The destination VPN {} does not participate in the interVpnLink {}",
174                                     dstVpnUuid, ivpnLinkName);
175
176         String endpointIp = interVpnLink.getOtherEndpointIpAddr(dstVpnUuid);
177         String leakedOrigin = forcedOrigin != null ? forcedOrigin.getValue() : RouteOrigin.INTERVPN.getValue();
178         FibHelper.buildRoutePath(endpointIp, label);
179         VrfEntry newVrfEntry =
180             new VrfEntryBuilder().withKey(new VrfEntryKey(prefix)).setDestPrefix(prefix)
181                                  .setRoutePaths(
182                                      Collections.singletonList(FibHelper.buildRoutePath(endpointIp, label)))
183                                  .setOrigin(leakedOrigin).build();
184
185         String dstVpnRd = vpnUtil.getVpnRd(dstVpnUuid);
186         InstanceIdentifier<VrfEntry> newVrfEntryIid =
187             InstanceIdentifier.builder(FibEntries.class)
188                               .child(VrfTables.class, new VrfTablesKey(dstVpnRd))
189                               .child(VrfEntry.class, new VrfEntryKey(newVrfEntry.getDestPrefix()))
190                               .build();
191         ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx ->
192             tx.put(newVrfEntryIid, newVrfEntry)), LOG, "Error adding VRF entry {}", newVrfEntry);
193
194         // Finally, route is advertised it to the DC-GW. But while in the FibEntries the nexthop is the other
195         // endpoint's IP, in the DC-GW the nexthop for those prefixes are the IPs of those DPNs where the target
196         // VPN has been instantiated
197         List<Uint64> srcDpnList = interVpnLink.getEndpointDpnsByVpnName(srcVpnUuid);
198         List<String> nexthops =
199             srcDpnList.stream().map(dpnId -> InterfaceUtils.getEndpointIpAddressForDPN(dataBroker, dpnId))
200                                .collect(Collectors.toList());
201
202         LOG.debug("Advertising route in VPN={} [prefix={} label={}  nexthops={}] to DC-GW",
203                   dstVpnRd, newVrfEntry.getDestPrefix(), label.intValue(), nexthops);
204         try {
205             bgpManager.advertisePrefix(dstVpnRd, null /*macAddress*/, prefix, nexthops,
206                                        VrfEntry.EncapType.Mplsgre, label, Uint32.ZERO /*l3vni*/, Uint32.ZERO /*l2vni*/,
207                                        null /*gwMacAddress*/);
208         } catch (Exception e) {
209             LOG.error("Exception while advertising prefix {} on vpnRd {} for intervpn link", prefix, dstVpnRd, e);
210         }
211     }
212
213     @Override
214     public void leakRouteIfNeeded(String vpnName, String prefix, List<String> nextHopList, Uint32 label,
215                                   RouteOrigin origin, int addOrRemove) {
216
217         Optional<InterVpnLinkDataComposite> optIVpnLink = interVpnLinkCache.getInterVpnLinkByVpnId(vpnName);
218         if (!optIVpnLink.isPresent()) {
219             LOG.debug("Vpn {} not involved in any InterVpnLink", vpnName);
220             return;
221         }
222         InterVpnLinkDataComposite ivpnLink = optIVpnLink.get();
223         if (addOrRemove == NwConstants.ADD_FLOW && !ivpnLink.isActive()) {
224             // Note: for the removal case it is not necessary that ivpnlink is ACTIVE
225             LOG.debug("Route to {} in VPN {} cannot be leaked because InterVpnLink {} is not ACTIVE",
226                       prefix, vpnName, ivpnLink.getInterVpnLinkName());
227             return;
228         }
229
230         switch (origin) {
231             case BGP:
232                 if (!ivpnLink.isBgpRoutesLeaking()) {
233                     LOG.debug("BGP route to {} not leaked because bgp-routes-leaking is disabled", prefix);
234                     return;
235                 }
236                 leakRoute(vpnName, prefix, nextHopList, label, addOrRemove);
237                 break;
238             case STATIC:
239                 /* NOTE: There are 2 types of static routes depending on the next hop:
240                     + static route when next hop is a VM, the DC-GW or a DPNIP
241                     + static route when next hop is an Inter-VPN Link
242                  Only the 1st type should be considered since the 2nd has a special treatment */
243                 if (!ivpnLink.isStaticRoutesLeaking()) {
244                     LOG.debug("Static route to {} not leaked because static-routes-leaking is disabled", prefix);
245                     return;
246                 }
247                 leakRoute(vpnName, prefix, nextHopList, label, addOrRemove);
248                 break;
249             case CONNECTED:
250                 if (!ivpnLink.isConnectedRoutesLeaking()) {
251                     LOG.debug("Connected route to {} not leaked because connected-routes-leaking is disabled", prefix);
252                     return;
253                 }
254                 leakRoute(vpnName, prefix, nextHopList, label, addOrRemove);
255                 break;
256             default:
257                 LOG.warn("origin {} not considered in Route-leaking", origin.getValue());
258         }
259
260     }
261
262     @Override
263     public void exchangeRoutes(InterVpnLinkDataComposite ivpnLink) {
264         if (!ivpnLink.isComplete()) {
265             return;
266         }
267
268         // The type of routes to exchange depend on the leaking flags that have been activated
269         List<RouteOrigin> originsToConsider = new ArrayList<>();
270         if (ivpnLink.isBgpRoutesLeaking()) {
271             originsToConsider.add(RouteOrigin.BGP);
272         }
273         if (ivpnLink.isStaticRoutesLeaking()) {
274             originsToConsider.add(RouteOrigin.STATIC);
275         }
276         if (ivpnLink.isConnectedRoutesLeaking()) {
277             originsToConsider.add(RouteOrigin.CONNECTED);
278         }
279
280         String vpn1Uuid = ivpnLink.getFirstEndpointVpnUuid().get();
281         String vpn2Uuid = ivpnLink.getSecondEndpointVpnUuid().get();
282
283         if (! originsToConsider.isEmpty()) {
284             // 1st Endpoint ==> 2nd endpoint
285             leakRoutes(ivpnLink, vpn1Uuid, vpn2Uuid, originsToConsider);
286
287
288             // 2nd Endpoint ==> 1st endpoint
289             leakRoutes(ivpnLink, vpn2Uuid, vpn1Uuid, originsToConsider);
290         }
291
292         // Static routes in Vpn1 pointing to Vpn2's endpoint
293         leakExtraRoutesToVpnEndpoint(ivpnLink, vpn1Uuid, vpn2Uuid);
294
295         // Static routes in Vpn2 pointing to Vpn1's endpoint
296         leakExtraRoutesToVpnEndpoint(ivpnLink, vpn2Uuid, vpn1Uuid);
297     }
298
299     /*
300      * Checks if there are static routes in Vpn1 whose nexthop is Vpn2's endpoint.
301      * Those routes must be leaked to Vpn1.
302      *
303      * @param vpnLink
304      * @param vpn1Uuid
305      * @param vpn2Uuid
306      */
307     private void leakExtraRoutesToVpnEndpoint(InterVpnLinkDataComposite vpnLink, String vpn1Uuid, String vpn2Uuid) {
308
309         String vpn1Rd = vpnUtil.getVpnRd(vpn1Uuid);
310         String vpn2Endpoint = vpnLink.getOtherEndpointIpAddr(vpn2Uuid);
311         List<VrfEntry> allVpnVrfEntries = vpnUtil.getAllVrfEntries(vpn1Rd);
312         for (VrfEntry vrfEntry : allVpnVrfEntries) {
313             vrfEntry.nonnullRoutePaths().stream()
314                     .filter(routePath -> Objects.equals(routePath.getNexthopAddress(), vpn2Endpoint))
315                     .forEach(routePath -> {
316                         // Vpn1 has a route pointing to Vpn2's endpoint. Forcing the leaking of the route will update
317                         // the BGP accordingly
318                         Uint32 label = vpnUtil.getUniqueId(VpnConstants.VPN_IDPOOL_NAME,
319                                                          VpnUtil.getNextHopLabelKey(vpn1Rd, vrfEntry.getDestPrefix()));
320                         if (label.longValue() == VpnConstants.INVALID_LABEL) {
321                             LOG.error("Unable to fetch label from Id Manager. Bailing out of leaking extra routes for "
322                                       + "InterVpnLink {} rd {} prefix {}",
323                                       vpnLink.getInterVpnLinkName(), vpn1Rd, vrfEntry.getDestPrefix());
324                         } else {
325                             leakRoute(vpnLink, vpn2Uuid, vpn1Uuid, vrfEntry.getDestPrefix(), label,
326                                       RouteOrigin.value(vrfEntry.getOrigin()));
327                         }
328                     });
329
330         }
331     }
332
333     private void leakRoutes(InterVpnLinkDataComposite vpnLink, String srcVpnUuid, String dstVpnUuid,
334                             List<RouteOrigin> originsToConsider) {
335         String srcVpnRd = vpnUtil.getVpnRd(srcVpnUuid);
336         String dstVpnRd = vpnUtil.getVpnRd(dstVpnUuid);
337         List<VrfEntry> srcVpnRemoteVrfEntries = vpnUtil.getVrfEntriesByOrigin(srcVpnRd, originsToConsider);
338         for (VrfEntry vrfEntry : srcVpnRemoteVrfEntries) {
339             Uint32 label = vpnUtil.getUniqueId(VpnConstants.VPN_IDPOOL_NAME,
340                                              VpnUtil.getNextHopLabelKey(dstVpnRd, vrfEntry.getDestPrefix()));
341             if (label.longValue() == VpnConstants.INVALID_LABEL) {
342                 LOG.error("Unable to fetch label from Id Manager. Bailing out of leaking routes for InterVpnLink {} "
343                           + "rd {} prefix {}",
344                         vpnLink.getInterVpnLinkName(), dstVpnRd, vrfEntry.getDestPrefix());
345                 continue;
346             }
347             leakRoute(vpnLink, srcVpnUuid, dstVpnUuid, vrfEntry.getDestPrefix(), label, null /*NotForcedOrigin*/);
348         }
349     }
350
351     private Map<String, String> buildRouterXL3VPNMap() {
352         InstanceIdentifier<VpnMaps> vpnMapsIdentifier = InstanceIdentifier.builder(VpnMaps.class).build();
353         Optional<VpnMaps> optVpnMaps = Optional.empty();
354         try {
355             optVpnMaps = SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.CONFIGURATION,
356                     vpnMapsIdentifier);
357         } catch (ExecutionException | InterruptedException e) {
358             LOG.error("buildRouterXL3VPNMap: Exception while reading VpnMaps DS", e);
359         }
360         if (!optVpnMaps.isPresent()) {
361             LOG.info("Could not retrieve VpnMaps object from Configurational DS");
362             return new HashMap<>();
363         }
364         Map<String,String> vmap = new HashMap<>();
365         final List<VpnMap> VpnMapList = optVpnMaps.get().nonnullVpnMap();
366         for (VpnMap map : VpnMapList) {
367             if (map.getRouterIds() == null) {
368                 continue;
369             }
370             final List<Uuid> vpnRouterIds = NeutronUtils.getVpnMapRouterIdsListUuid(map.getRouterIds());
371             for (Uuid routerId : vpnRouterIds) {
372                 if (map.getVpnId().getValue().equalsIgnoreCase(routerId.getValue())) {
373                     break; // VPN is internal
374                 }
375                 vmap.put(routerId.getValue(), map.getVpnId().getValue());
376             }
377         }
378         return vmap;
379     }
380
381
382     @Override
383     public void handleStaticRoutes(InterVpnLinkDataComposite ivpnLink) {
384         /*
385          * Checks if there are any static routes pointing to any of both
386          * InterVpnLink's endpoints. Goes through all routers checking if they have
387          * a route whose nexthop is an InterVpnLink endpoint
388          */
389
390         // Map that corresponds a routerId with the L3VPN that it's been assigned to.
391         Map<String, String> routerXL3VpnMap = buildRouterXL3VPNMap();
392
393         // Retrieving all Routers
394         InstanceIdentifier<Routers> routersIid = InstanceIdentifier.builder(Neutron.class)
395                 .child(Routers.class).build();
396         Optional<Routers> routerOpData = Optional.empty();
397         try {
398             routerOpData = SingleTransactionDataBroker.syncReadOptional(dataBroker,
399                     LogicalDatastoreType.CONFIGURATION, routersIid);
400         } catch (ExecutionException | InterruptedException e) {
401             LOG.error("handleStaticRoutes: Exception while reading routers DS", e);
402         }
403         if (!routerOpData.isPresent()) {
404             return;
405         }
406         List<Router> routers = routerOpData.get().nonnullRouter();
407         for (Router router : routers) {
408             String vpnId = routerXL3VpnMap.get(router.getUuid().getValue());
409             if (vpnId == null) {
410                 LOG.warn("Could not find suitable VPN for router {}", router.getUuid());
411                 continue; // with next router
412             }
413             List<Routes> routerRoutes = router.getRoutes();
414             if (routerRoutes != null) {
415                 for (Routes route : routerRoutes) {
416                     handleStaticRoute(vpnId, route, ivpnLink);
417                 }
418             }
419         }
420     }
421
422     /*
423      * Takes care of an static route to see if flows related to interVpnLink
424      * must be installed in tables 20 and 17
425      *
426      * @param vpnId Vpn to which the route belongs
427      * @param route Route to handle. Will only be considered if its nexthop is the VPN's endpoint IpAddress
428      *              at the other side of the InterVpnLink
429      * @param iVpnLink
430      */
431     @SuppressWarnings("checkstyle:IllegalCatch")
432     private void handleStaticRoute(String vpnId, Routes route, InterVpnLinkDataComposite ivpnLink) {
433
434         IpAddress nhIpAddr = route.getNexthop();
435         String routeNextHop = nhIpAddr.getIpv4Address() != null ? nhIpAddr.getIpv4Address().getValue()
436                                                                   : nhIpAddr.getIpv6Address().getValue();
437         String destination = route.getDestination().stringValue();
438
439         // is nexthop the other endpoint's IP
440         String otherEndpoint = ivpnLink.getOtherEndpoint(vpnId);
441         if (!routeNextHop.equals(otherEndpoint)) {
442             LOG.debug("VPN {}: Route to {} nexthop={} points to an InterVpnLink endpoint, but its not "
443                       + "the other endpoint. Other endpoint is {}",
444                       vpnId, destination, routeNextHop, otherEndpoint);
445             return;
446         }
447
448         // Lets work: 1) write Fibentry, 2) advertise to BGP and 3) check if it must be leaked
449         String vpnRd = vpnUtil.getVpnRd(vpnId);
450         if (vpnRd == null) {
451             LOG.warn("Could not find Route-Distinguisher for VpnName {}", vpnId);
452             return;
453         }
454
455         Uint32 label = vpnUtil.getUniqueId(VpnConstants.VPN_IDPOOL_NAME,
456                                 VpnUtil.getNextHopLabelKey(vpnId, destination));
457
458         try {
459             interVpnLinkUtil.handleStaticRoute(ivpnLink, vpnId, destination, routeNextHop, label);
460         } catch (Exception e) {
461             LOG.error("Exception while advertising prefix for intervpn link", e);
462         }
463     }
464 }