+ public LogicalDatastoreType getDatastoreType() {
+ return LogicalDatastoreType.CONFIGURATION;
+ }
+
+ private void createFibEntries(final InstanceIdentifier<VrfEntry> vrfEntryIid, final VrfEntry vrfEntry) {
+ final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
+
+ final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
+ Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher());
+ Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + " has null vpnId!");
+
+ final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
+ final Long vpnId = vpnInstance.getVpnId();
+ final String rd = vrfTableKey.getRouteDistinguisher();
+ SubnetRoute subnetRoute = vrfEntry.getAugmentation(SubnetRoute.class);
+ if (subnetRoute != null) {
+ final long elanTag = subnetRoute.getElantag();
+ LOG.trace("SubnetRoute augmented vrfentry found for rd {} prefix {} with elantag {}",
+ rd, vrfEntry.getDestPrefix(), elanTag);
+ if (vpnToDpnList != null) {
+ DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+ dataStoreCoordinator.enqueueJob("FIB"+rd.toString()+vrfEntry.getDestPrefix(),
+ new Callable<List<ListenableFuture<Void>>>() {
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ WriteTransaction tx = broker.newWriteOnlyTransaction();
+ for (final VpnToDpnList curDpn : vpnToDpnList) {
+ if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
+ installSubnetRouteInFib(curDpn.getDpnId(), elanTag, rd, vpnId.longValue(), vrfEntry, tx);
+ }
+ }
+ List<ListenableFuture<Void>> futures = new ArrayList<>();
+ futures.add(tx.submit());
+ return futures;
+ }
+ });
+ }
+ return;
+ }
+
+ if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.INTERVPN) {
+ // When it is a leaked route, the LFIB and FIB goes a bit different.
+ installInterVpnRouteInLFib(rd, vrfEntry);
+ return;
+ }
+
+ final List<BigInteger> localDpnIdList = createLocalFibEntry(vpnInstance.getVpnId(), rd, vrfEntry);
+
+ if (vpnToDpnList != null) {
+ DataStoreJobCoordinator dataStoreCoordinator = DataStoreJobCoordinator.getInstance();
+ dataStoreCoordinator.enqueueJob("FIB"+rd.toString()+vrfEntry.getDestPrefix(),
+ new Callable<List<ListenableFuture<Void>>>() {
+ @Override
+ public List<ListenableFuture<Void>> call() throws Exception {
+ WriteTransaction tx = broker.newWriteOnlyTransaction();
+ for (VpnToDpnList vpnDpn : vpnToDpnList) {
+ if ( !localDpnIdList.contains(vpnDpn.getDpnId())) {
+ if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
+ createRemoteFibEntry(vpnDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, tx);
+ }
+ }
+ }
+ List<ListenableFuture<Void>> futures = new ArrayList<>();
+ futures.add(tx.submit());
+ return futures;
+ }
+ });
+ }
+
+ Optional<String> vpnUuid = FibUtil.getVpnNameFromRd(broker, rd);
+ if ( vpnUuid.isPresent() ) {
+ Optional<InterVpnLink> interVpnLink = FibUtil.getInterVpnLinkByVpnUuid(broker, vpnUuid.get());
+ if ( interVpnLink.isPresent() ) {
+ String routeNexthop = vrfEntry.getNextHopAddressList().get(0);
+ if ( isNexthopTheOtherVpnLinkEndpoint(routeNexthop, vpnUuid.get(), interVpnLink.get()) ) {
+ // This is an static route that points to the other endpoint of an InterVpnLink
+ // In that case, we should add another entry in FIB table pointing to LPortDispatcher table.
+ installRouteInInterVpnLink(interVpnLink.get(), rd, vrfEntry, vpnId);
+ }
+ }
+ }
+ }
+
+
+ /*
+ Please note that the following createFibEntries will be invoked only for BGP Imported Routes.
+ The invocation of the following method is via create() callback from the MDSAL Batching Infrastructure
+ provided by ResourceBatchingManager
+ */
+ private void createFibEntries(WriteTransaction writeTx, final InstanceIdentifier<VrfEntry> vrfEntryIid, final VrfEntry vrfEntry) {
+ final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
+
+ final VpnInstanceOpDataEntry vpnInstance = getVpnInstance(vrfTableKey.getRouteDistinguisher());
+ Preconditions.checkNotNull(vpnInstance, "Vpn Instance not available " + vrfTableKey.getRouteDistinguisher());
+ Preconditions.checkNotNull(vpnInstance.getVpnId(), "Vpn Instance with rd " + vpnInstance.getVrfId() + " has null vpnId!");
+
+ final Collection<VpnToDpnList> vpnToDpnList = vpnInstance.getVpnToDpnList();
+ final String rd = vrfTableKey.getRouteDistinguisher();
+ if (vpnToDpnList != null) {
+ for (VpnToDpnList vpnDpn : vpnToDpnList) {
+ if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
+ createRemoteFibEntry(vpnDpn.getDpnId(), vpnInstance.getVpnId(), vrfTableKey, vrfEntry, writeTx);
+ }
+ }
+ }
+ }
+
+ /*
+ * Returns true if the specified nexthop is the other endpoint in an
+ * InterVpnLink, regarding one of the VPN's point of view.
+ */
+ private boolean isNexthopTheOtherVpnLinkEndpoint(String nexthop, String thisVpnUuid, InterVpnLink interVpnLink) {
+ return
+ interVpnLink != null
+ && ( (interVpnLink.getFirstEndpoint().getVpnUuid().getValue().equals(thisVpnUuid)
+ && interVpnLink.getSecondEndpoint().getIpAddress().getValue().equals(nexthop))
+ || (interVpnLink.getSecondEndpoint().getVpnUuid().getValue().equals(thisVpnUuid )
+ && interVpnLink.getFirstEndpoint().getIpAddress().getValue().equals(nexthop)) );
+ }
+
+
+ // FIXME: Refactoring needed here.
+ // This kind of logic must be taken to an 'upper' layer like BgpManager or VpnManager
+ private void leakRouteIfNeeded(final InstanceIdentifier<VrfEntry> vrfEntryIid, final VrfEntry vrfEntry,
+ int addOrRemove) {
+ Preconditions.checkNotNull(vrfEntry, "VrfEntry cannot be null or empty!");
+ final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
+
+ String rd = vrfTableKey.getRouteDistinguisher();
+ VpnInstanceOpDataEntry vpnInstance = getVpnInstance(rd);
+ if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
+ if (vpnInstance == null) {
+ LOG.error("Vpn Instance not available for external route with prefix {} label {} nexthop {}. Returning...", vrfEntry.getDestPrefix(), vrfEntry.getLabel(), vrfEntry.getNextHopAddressList());
+ return;
+ }
+ } else {
+ Preconditions.checkNotNull(vpnInstance,
+ "Vpn Instance not available with rd " + vrfTableKey.getRouteDistinguisher());
+ }
+ String vpnUuid = vpnInstance.getVpnInstanceName();
+ Preconditions.checkArgument(vpnUuid != null && !vpnUuid.isEmpty(),
+ "Could not find suitable VPN UUID for Route-Distinguisher=" + rd);
+
+ // if the new vrfEntry has been learned by Quagga BGP, its necessary to check if it's
+ // there an interVpnLink for the involved vpn in order to make learn the new route to
+ // the other part of the inter-vpn-link.
+
+ // For leaking, we need the InterVpnLink to be active. For removal, we just need a InterVpnLink.
+ Optional<InterVpnLink> interVpnLink =
+ (addOrRemove == NwConstants.ADD_FLOW) ? FibUtil.getActiveInterVpnLinkFromRd(broker, rd)
+ : FibUtil.getInterVpnLinkByRd(broker, rd);
+ if ( !interVpnLink.isPresent() ) {
+ LOG.debug("Could not find an InterVpnLink for Route-Distinguisher={}", rd);
+ return;
+ }
+
+ // Ok, at this point everything is ready for the leaking/removal... but should it be performed?
+ // For removal, we remove all leaked routes, but we only leak a route if the corresponding flag is enabled.
+ boolean proceed = (addOrRemove == NwConstants.DEL_FLOW )
+ || ( RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP
+ && interVpnLink.get().isBgpRoutesLeaking() );
+
+ if ( proceed ) {
+ String theOtherVpnId = ( interVpnLink.get().getFirstEndpoint().getVpnUuid().getValue().equals(vpnUuid) )
+ ? interVpnLink.get().getSecondEndpoint().getVpnUuid().getValue()
+ : vpnUuid;
+
+ String dstVpnRd = FibUtil.getVpnRd(broker, theOtherVpnId);
+ String endpointIp = vrfEntry.getNextHopAddressList().get(0);
+
+ InstanceIdentifier<VrfEntry> vrfEntryIidInOtherVpn =
+ InstanceIdentifier.builder(FibEntries.class)
+ .child(VrfTables.class, new VrfTablesKey(dstVpnRd))
+ .child(VrfEntry.class, new VrfEntryKey(vrfEntry.getDestPrefix()))
+ .build();
+ if ( addOrRemove == NwConstants.ADD_FLOW ) {
+ LOG.info("Leaking route (destination={}, nexthop={}) from Vrf={} to Vrf={}",
+ vrfEntry.getDestPrefix(), vrfEntry.getNextHopAddressList(), rd, dstVpnRd);
+ String key = rd + FibConstants.SEPARATOR + vrfEntry.getDestPrefix();
+ long label = FibUtil.getUniqueId(idManager, FibConstants.VPN_IDPOOL_NAME, key);
+ VrfEntry newVrfEntry = new VrfEntryBuilder(vrfEntry).setNextHopAddressList(Arrays.asList(endpointIp))
+ .setLabel(label)
+ .setOrigin(RouteOrigin.INTERVPN.getValue())
+ .build();
+ MDSALUtil.syncUpdate(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryIidInOtherVpn, newVrfEntry);
+ } else {
+ LOG.info("Removing leaked vrfEntry={}", vrfEntryIidInOtherVpn.toString());
+ MDSALUtil.syncDelete(broker, LogicalDatastoreType.CONFIGURATION, vrfEntryIidInOtherVpn);