+ LOG.info("updateVpnInstanceChange: Processed Add for update on VPNInterface {}"
+ + "from oldVpn(s) {} to newVpn {} ",
+ interfaceName, oldVpnListCopy, newVpnName);
+ /* This block will execute only if V6 subnet is associated with internet BGP-VPN.
+ * Use Case:
+ * In Dual stack network, first V4 subnet only attached to router and router is associated
+ * with internet BGP-VPN(router-gw). At this point VPN interface is having only router vpn instance.
+ * Later V6 subnet is added to router, at this point existing VPN interface will get updated
+ * with Internet BGP-VPN instance(Note: Internet BGP-VPN Instance update in vpn interface
+ * is applicable for only on V6 subnet is added to router). newVpnList = Contains only Internet
+ * BGP-VPN Instance. So we required V6 primary adjacency info needs to be populated onto
+ * router VPN as well as Internet BGP-VPN.
+ *
+ * addVpnInterfaceCall() --> It will create V6 Adj onto Internet BGP-VPN only.
+ * updateVpnInstanceAdjChange() --> This method call is needed for second primary V6 Adj
+ * update in existing router VPN instance.
+ */
+ if (vpnUtil.isBgpVpnInternet(newVpnName)) {
+ LOG.info("updateVpnInstanceChange: VPN Interface {} with new Adjacency {} in existing "
+ + "VPN instance {}", interfaceName, newAdjs, original.getVpnInstanceNames());
+ updateVpnInstanceAdjChange(original, update, interfaceName, futures);
+ }
+ } else {
+ LOG.info("updateVpnInstanceChange: failed to Add for update on VPNInterface {} from oldVpn(s) {} to "
+ + "newVpn {} as the new vpn does not exist in oper DS or it is in PENDING_DELETE state",
+ interfaceName, oldVpnListCopy, newVpnName);
+ }
+ }
+ }
+
+ // TODO Clean up the exception handling
+ @SuppressWarnings("checkstyle:IllegalCatch")
+ private List<ListenableFuture<Void>> updateVpnInstanceAdjChange(VpnInterface original, VpnInterface update,
+ String vpnInterfaceName,
+ List<ListenableFuture<Void>> futures) {
+ final Adjacencies origAdjs = original.augmentation(Adjacencies.class);
+ final List<Adjacency> oldAdjs = origAdjs != null && origAdjs.getAdjacency()
+ != null ? new ArrayList<Adjacency>(origAdjs.getAdjacency().values()) : new ArrayList<>();
+ final Adjacencies updateAdjs = update.augmentation(Adjacencies.class);
+ final List<Adjacency> newAdjs = updateAdjs != null && updateAdjs.getAdjacency()
+ != null ? new ArrayList<Adjacency>(updateAdjs.getAdjacency().values()) : new ArrayList<>();
+
+ final Uint64 dpnId = InterfaceUtils.getDpnForInterface(ifaceMgrRpcService, vpnInterfaceName);
+ for (VpnInstanceNames vpnInterfaceVpnInstance : update.nonnullVpnInstanceNames().values()) {
+ String newVpnName = vpnInterfaceVpnInstance.getVpnName();
+ List<Adjacency> copyNewAdjs = new ArrayList<>(newAdjs);
+ List<Adjacency> copyOldAdjs = new ArrayList<>(oldAdjs);
+ String primaryRd = vpnUtil.getPrimaryRd(newVpnName);
+ if (!vpnUtil.isVpnPendingDelete(primaryRd)) {
+ // TODO Deal with sequencing — the config tx must only submitted if the oper tx goes in
+ //set of prefix used as entry in prefix-to-interface datastore
+ // is prerequisite for refresh Fib to avoid race condition leading to missing remote next hop
+ // in bucket actions on bgp-vpn delete
+ Set<String> prefixListForRefreshFib = new HashSet<>();
+ ListenableFuture<Void> configTxFuture = txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
+ confTx -> futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(OPERATIONAL,
+ operTx -> {
+ InstanceIdentifier<VpnInterfaceOpDataEntry> vpnInterfaceOpIdentifier =
+ VpnUtil.getVpnInterfaceOpDataEntryIdentifier(vpnInterfaceName, newVpnName);
+ LOG.info("VPN Interface update event-intfName {} onto vpnName {} running config-driven",
+ update.getName(), newVpnName);
+ //handle both addition and removal of adjacencies
+ // currently, new adjacency may be an extra route
+ boolean isBgpVpnInternetVpn = vpnUtil.isBgpVpnInternet(newVpnName);
+ if (!oldAdjs.equals(newAdjs)) {
+ for (Adjacency adj : copyNewAdjs) {
+ if (copyOldAdjs.contains(adj)) {
+ copyOldAdjs.remove(adj);
+ } else {
+ // add new adjacency
+ if (!isBgpVpnInternetVpn || vpnUtil.isAdjacencyEligibleToVpnInternet(adj)) {
+ try {
+ addNewAdjToVpnInterface(vpnInterfaceOpIdentifier, primaryRd, adj,
+ dpnId, operTx, confTx, confTx, prefixListForRefreshFib);
+ } catch (RuntimeException e) {
+ LOG.error("Failed to add adjacency {} to vpn interface {} with"
+ + " dpnId {}", adj, vpnInterfaceName, dpnId, e);
+ }
+ }
+ LOG.info("update: new Adjacency {} with nextHop {} label {} subnet {} "
+ + " added to vpn interface {} on vpn {} dpnId {}",
+ adj.getIpAddress(), adj.getNextHopIpList(), adj.getLabel(),
+ adj.getSubnetId(), update.getName(), newVpnName, dpnId);
+ }
+ }
+ for (Adjacency adj : copyOldAdjs) {
+ if (!isBgpVpnInternetVpn || vpnUtil.isAdjacencyEligibleToVpnInternet(adj)) {
+ if (adj.getAdjacencyType() == AdjacencyType.PrimaryAdjacency
+ && !adj.isPhysNetworkFunc()) {
+ delAdjFromVpnInterface(vpnInterfaceOpIdentifier, adj, dpnId, operTx,
+ confTx);
+ //remove FIB entry
+ String vpnRd = vpnUtil.getVpnRd(newVpnName);
+ LOG.debug("update: remove prefix {} from the FIB and BGP entry "
+ + "for the Vpn-Rd {} ", adj.getIpAddress(), vpnRd);
+ //remove BGP entry
+ fibManager.removeFibEntry(vpnRd, adj.getIpAddress(), null, confTx);
+ if (vpnRd != null && !vpnRd.equalsIgnoreCase(newVpnName)) {
+ bgpManager.withdrawPrefix(vpnRd, adj.getIpAddress());
+ }
+ } else {
+ delAdjFromVpnInterface(vpnInterfaceOpIdentifier, adj, dpnId,
+ operTx, confTx);
+ }
+ }
+ LOG.info("update: Adjacency {} with nextHop {} label {} subnet {} removed from"
+ + " vpn interface {} on vpn {}", adj.getIpAddress(), adj.getNextHopIpList(),
+ adj.getLabel(), adj.getSubnetId(), update.getName(), newVpnName);
+ }
+ }
+ })));
+ Futures.addCallback(configTxFuture, new VpnInterfaceCallBackHandler(primaryRd, prefixListForRefreshFib),
+ MoreExecutors.directExecutor());
+ futures.add(configTxFuture);
+ for (ListenableFuture<Void> future : futures) {
+ LoggingFutures.addErrorLogging(future, LOG, "update: failed for interface {} on vpn {}",
+ update.getName(), update.getVpnInstanceNames());
+ }
+ } else {
+ LOG.error("update: Ignoring update of vpnInterface {}, as newVpnInstance {} with primaryRd {}"
+ + " is already marked for deletion", vpnInterfaceName, newVpnName, primaryRd);