+ if (Objects.equals(original, update)) {
+ return;
+ }
+ jobCoordinator.enqueueJob("VPN-" + original.getVpnInstanceName(),
+ new UpdateVpnInstanceWorker(dataBroker, identifier, original, update));
+ }
+
+ private class UpdateVpnInstanceWorker implements Callable<List<? extends ListenableFuture<?>>> {
+ private final Logger log = LoggerFactory.getLogger(VpnInstanceListener.UpdateVpnInstanceWorker.class);
+ VpnInstance original;
+ VpnInstance update;
+ InstanceIdentifier<VpnInstance> vpnIdentifier;
+ DataBroker broker;
+ String vpnName;
+
+ UpdateVpnInstanceWorker(DataBroker broker,
+ InstanceIdentifier<VpnInstance> identifier,
+ VpnInstance original,
+ VpnInstance update) {
+ this.broker = broker;
+ this.vpnIdentifier = identifier;
+ this.original = original;
+ this.update = update;
+ this.vpnName = update.getVpnInstanceName();
+ }
+
+ @Override
+ @SuppressWarnings("checkstyle:ForbidCertainMethod")
+ public List<ListenableFuture<Void>> call() {
+ WriteTransaction writeOperTxn = broker.newWriteOnlyTransaction();
+ List<ListenableFuture<Void>> futures = new ArrayList<>();
+ String primaryRd = vpnUtil.getVpnRd(vpnName);
+ if (primaryRd == null) {
+ log.error("{}, failed to update VPN: PrimaryRD is null for vpnName {}", LOGGING_PREFIX_UPDATE, vpnName);
+ return futures;
+ }
+ updateVpnInstance(writeOperTxn, primaryRd);
+ try {
+ writeOperTxn.commit().get();
+ } catch (InterruptedException | ExecutionException e) {
+ log.error("{}, failed to update VPN: Exception in updating vpn {} rd {} ", LOGGING_PREFIX_UPDATE,
+ vpnName, update.getRouteDistinguisher(), e);
+ futures.add(Futures.immediateFailedFuture(e));
+ return futures;
+ }
+ ListenableFuture<List<Void>> listenableFuture = Futures.allAsList(futures);
+ boolean isIpAddressFamilyUpdated = false;
+ if (original.getIpAddressFamilyConfigured() == VpnInstance.IpAddressFamilyConfigured.Undefined
+ && update.getIpAddressFamilyConfigured() != original.getIpAddressFamilyConfigured()) {
+ isIpAddressFamilyUpdated = true;
+ }
+ Futures.addCallback(listenableFuture,
+ new PostVpnInstanceChangeWorker(update , isIpAddressFamilyUpdated, primaryRd),
+ MoreExecutors.directExecutor());
+ return futures;
+ }
+
+ private class PostVpnInstanceChangeWorker implements FutureCallback<List<Void>> {
+ private final Logger log = LoggerFactory.getLogger(PostVpnInstanceChangeWorker.class);
+ VpnInstance vpnInstance;
+ String vpnName;
+ boolean isIpAddressFamilyUpdated;
+ String primaryRd;
+
+ PostVpnInstanceChangeWorker(VpnInstance vpnInstance, boolean isIpAddressFamilyUpdated, String primaryRd) {
+ this.vpnInstance = vpnInstance;
+ this.vpnName = vpnInstance.getVpnInstanceName();
+ this.isIpAddressFamilyUpdated = isIpAddressFamilyUpdated;
+ this.primaryRd = primaryRd;
+ }
+
+ /**
+ * This implies that all the future instances have returned success. -- TODO: Confirm this
+ */
+ @Override
+ public void onSuccess(List<Void> voids) {
+ if (!VpnUtil.isBgpVpn(vpnName, primaryRd)) {
+ // plain router
+ notifyTask();
+ vpnInterfaceManager.vpnInstanceIsReady(vpnName);
+ return;
+ }
+ if (isIpAddressFamilyUpdated) {
+ //bgpvpn
+ notifyTask();
+ vpnInterfaceManager.vpnInstanceIsReady(vpnName);
+ }
+ }
+
+ /**
+ * This method is used to handle failure callbacks.
+ * If more retry needed, the retrycount is decremented and mainworker is executed again.
+ * After retries completed, rollbackworker is executed.
+ * If rollbackworker fails, this is a double-fault. Double fault is logged and ignored.
+ */
+
+ @Override
+ public void onFailure(Throwable throwable) {
+ log.error("{} onFailure: Job for vpnInstance: {} with rd {} failed with exception:", LOGGING_PREFIX_ADD,
+ vpnName, primaryRd, throwable);
+ vpnInterfaceManager.vpnInstanceFailed(vpnName);
+ }
+
+ private void notifyTask() {
+ vpnOpDataNotifier.notifyVpnOpDataReady(VpnOpDataSyncer.VpnOpDataType.vpnInstanceToId,
+ vpnInstance.getVpnInstanceName());
+ vpnOpDataNotifier.notifyVpnOpDataReady(VpnOpDataSyncer.VpnOpDataType.vpnOpData,
+ vpnInstance.getVpnInstanceName());
+ }
+ }
+
+ public void updateVpnInstance(WriteTransaction writeOperTxn, String primaryRd) {
+ log.trace("updateVpnInstance: VPN event key: {}, value: {}.", vpnIdentifier, update);
+ InstanceIdentifier<VrfTables> id = VpnUtil.buildVrfTableForPrimaryRd(primaryRd);
+ Optional<VrfTables> vrfTable;
+ try {
+ vrfTable = SingleTransactionDataBroker.syncReadOptional(dataBroker,
+ LogicalDatastoreType.CONFIGURATION, id);
+ } catch (ExecutionException | InterruptedException e) {
+ log.trace("updateVpnInstance: Exception while reading FIB VRF Table for VPN Instance {} with "
+ + "Primary RD {}.", vpnName, primaryRd);
+ return;
+ }
+ //TODO Later if FIB VRF table is available we need to callback the vpnInstanceOpData Update to proceed
+ if (!vrfTable.isPresent()) {
+ log.error("updateVpnInstance: FIB VRF table is not present for the VPN Instance {} "
+ + "with Primary RD {}. Unable to Proceed VpnInstanceOpData Update event {}",
+ vpnName, primaryRd, update);
+ return;
+ }
+ List<String> vpnInstanceUpdatedRdList = Collections.emptyList();
+ boolean isBgpVrfTableUpdateRequired = false;
+ boolean isVpnInstanceRdUpdated = false;
+ //Handle VpnInstance Address Family update
+ int originalIpAddrFamilyValue = original.getIpAddressFamilyConfigured().getIntValue();
+ int updateIpAddrFamilyValue = update.getIpAddressFamilyConfigured().getIntValue();
+ if (originalIpAddrFamilyValue != updateIpAddrFamilyValue) {
+ log.debug("updateVpnInstance: VpnInstance: {} updated with IP address family {} from IP address "
+ + "family {}", vpnName, update.getIpAddressFamilyConfigured().getName(),
+ original.getIpAddressFamilyConfigured().getName());
+ vpnUtil.setVpnInstanceOpDataWithAddressFamily(vpnName, update.getIpAddressFamilyConfigured(),
+ writeOperTxn);
+ }
+ //Update VpnInstanceOpData with BGPVPN to Internet BGPVPN and vice-versa
+ if (original.getBgpvpnType() != update.getBgpvpnType()) {
+ log.debug("updateVpnInstance: VpnInstance: {} updated with BGP-VPN type: {} from BGP-VPN type: {}",
+ vpnName, update.getBgpvpnType(), original.getBgpvpnType());
+ vpnUtil.updateVpnInstanceOpDataWithVpnType(vpnName, update.getBgpvpnType(), writeOperTxn);
+ }
+ //Handle BGP-VPN Instance RD Update
+ if ((update.getBgpvpnType() != VpnInstance.BgpvpnType.InternalVPN)) {
+ if (originalIpAddrFamilyValue < updateIpAddrFamilyValue) {
+ isBgpVrfTableUpdateRequired = true;
+ }
+ if (original.getRouteDistinguisher().size() != update.getRouteDistinguisher().size()) {
+ log.debug("updateVpnInstance: VpnInstance:{} updated with new RDs: {} from old RDs: {}", vpnName,
+ update.getRouteDistinguisher(), original.getRouteDistinguisher());
+ vpnUtil.updateVpnInstanceOpDataWithRdList(vpnName, update.getRouteDistinguisher(), writeOperTxn);
+ /* Update BGP Vrf entry for newly added RD. VPN Instance does not support for
+ * deleting the existing RDs
+ */
+ vpnInstanceUpdatedRdList = update.getRouteDistinguisher() != null
+ ? new ArrayList<>(update.getRouteDistinguisher()) : new ArrayList<>();
+ vpnInstanceUpdatedRdList.removeAll(original.getRouteDistinguisher());
+ isBgpVrfTableUpdateRequired = true;
+ isVpnInstanceRdUpdated = true;
+ }
+ }
+ //update Bgp VrfTable
+ if (isBgpVrfTableUpdateRequired) {
+ addBgpVrfTableForVpn(update, vpnName, vpnInstanceUpdatedRdList, isVpnInstanceRdUpdated);
+ }