Stale MIP FIB/Flow entries present upon deletion of VRRP master
[netvirt.git] / vpnmanager / impl / src / main / java / org / opendaylight / netvirt / vpnmanager / InterfaceStateChangeListener.java
1 /*
2  * Copyright (c) 2015, 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;
9
10 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
11 import static org.opendaylight.genius.infra.Datastore.OPERATIONAL;
12
13 import com.google.common.base.Optional;
14 import com.google.common.collect.HashBasedTable;
15 import com.google.common.collect.Table;
16 import com.google.common.util.concurrent.FutureCallback;
17 import com.google.common.util.concurrent.Futures;
18 import com.google.common.util.concurrent.ListenableFuture;
19 import com.google.common.util.concurrent.MoreExecutors;
20 import java.util.ArrayList;
21 import java.util.HashMap;
22 import java.util.HashSet;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Set;
26 import javax.annotation.PostConstruct;
27 import javax.inject.Inject;
28 import javax.inject.Singleton;
29 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
30 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
31 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
32 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
33 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
34 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
35 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
36 import org.opendaylight.netvirt.vpnmanager.api.InterfaceUtils;
37 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.iana._if.type.rev170119.L2vlan;
38 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
39 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.learnt.vpn.vip.to.port.data.LearntVpnVipToPort;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntry;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.Adjacencies;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.adjacency.list.Adjacency;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.interfaces.VpnInterface;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.l3vpn.rev200204.vpn.interfaces.vpn._interface.VpnInstanceNames;
47 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
48 import org.opendaylight.yangtools.yang.common.Uint64;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51
52 @Singleton
53 public class InterfaceStateChangeListener
54     extends AsyncDataTreeChangeListenerBase<Interface, InterfaceStateChangeListener> {
55
56     private static final Logger LOG = LoggerFactory.getLogger(InterfaceStateChangeListener.class);
57     private static final short DJC_MAX_RETRIES = 3;
58     private final DataBroker dataBroker;
59     private final ManagedNewTransactionRunner txRunner;
60     private final VpnInterfaceManager vpnInterfaceManager;
61     private final VpnUtil vpnUtil;
62     private final JobCoordinator jobCoordinator;
63     private final IFibManager fibManager;
64
65     Table<OperStatus, OperStatus, IntfTransitionState> stateTable = HashBasedTable.create();
66
67     enum IntfTransitionState {
68         STATE_UP,
69         STATE_DOWN,
70         STATE_IGNORE
71     }
72
73     private void initialize() {
74         //  Interface State Transition Table
75         //               Up                Down            Unknown
76         // ---------------------------------------------------------------
77         /* Up       { STATE_IGNORE,   STATE_DOWN,     STATE_IGNORE }, */
78         /* Down     { STATE_UP,       STATE_IGNORE,   STATE_IGNORE }, */
79         /* Unknown  { STATE_UP,       STATE_DOWN,     STATE_IGNORE }, */
80
81         stateTable.put(Interface.OperStatus.Up, Interface.OperStatus.Down, IntfTransitionState.STATE_DOWN);
82         stateTable.put(Interface.OperStatus.Down, Interface.OperStatus.Up, IntfTransitionState.STATE_UP);
83         stateTable.put(Interface.OperStatus.Unknown, Interface.OperStatus.Up, IntfTransitionState.STATE_UP);
84         stateTable.put(Interface.OperStatus.Unknown, Interface.OperStatus.Down, IntfTransitionState.STATE_DOWN);
85     }
86
87     @Inject
88     public InterfaceStateChangeListener(final DataBroker dataBroker, final VpnInterfaceManager vpnInterfaceManager,
89             final VpnUtil vpnUtil, final JobCoordinator jobCoordinator, final IFibManager fibManager) {
90         super(Interface.class, InterfaceStateChangeListener.class);
91         this.dataBroker = dataBroker;
92         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
93         this.vpnInterfaceManager = vpnInterfaceManager;
94         this.vpnUtil = vpnUtil;
95         this.jobCoordinator = jobCoordinator;
96         this.fibManager = fibManager;
97         initialize();
98     }
99
100     @PostConstruct
101     public void start() {
102         LOG.info("{} start", getClass().getSimpleName());
103         registerListener(LogicalDatastoreType.OPERATIONAL, dataBroker);
104     }
105
106
107     @Override
108     protected InstanceIdentifier<Interface> getWildCardPath() {
109         return InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
110     }
111
112     @Override
113     protected InterfaceStateChangeListener getDataTreeChangeListener() {
114         return InterfaceStateChangeListener.this;
115     }
116
117
118     @Override
119     // TODO Clean up the exception handling
120     @SuppressWarnings("checkstyle:IllegalCatch")
121     protected void add(InstanceIdentifier<Interface> identifier, Interface intrf) {
122         try {
123             if (L2vlan.class.equals(intrf.getType())) {
124                 LOG.info("VPN Interface add event - intfName {} from InterfaceStateChangeListener",
125                                 intrf.getName());
126                 jobCoordinator.enqueueJob("VPNINTERFACE-" + intrf.getName(), () -> {
127                     List<ListenableFuture<Void>> futures = new ArrayList<>(3);
128                     futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, writeInvTxn -> {
129                         //map of prefix and vpn name used, as entry in prefix-to-interface datastore
130                         // is prerequisite for refresh Fib to avoid race condition leading to missing remote next hop
131                         // in bucket actions on bgp-vpn delete
132                         Map<String, Set<String>> mapOfRdAndPrefixesForRefreshFib = new HashMap<>();
133                         ListenableFuture<Void> configFuture
134                             = txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, writeConfigTxn -> {
135                                 ListenableFuture<Void> operFuture
136                                     = txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, writeOperTxn -> {
137                                         final String interfaceName = intrf.getName();
138                                         LOG.info("Detected interface add event for interface {}", interfaceName);
139                                         final VpnInterface vpnIf = vpnUtil.getConfiguredVpnInterface(interfaceName);
140                                         if (vpnIf != null) {
141                                             for (VpnInstanceNames vpnInterfaceVpnInstance :
142                                                     vpnIf.nonnullVpnInstanceNames()) {
143                                                 String vpnName = vpnInterfaceVpnInstance.getVpnName();
144                                                 String primaryRd = vpnUtil.getPrimaryRd(vpnName);
145                                                 if (!vpnInterfaceManager.isVpnInstanceReady(vpnName)) {
146                                                     LOG.info("VPN Interface add event - intfName {} onto vpnName {} "
147                                                             + "running oper-driven, VpnInstance not ready, holding"
148                                                             + " on", vpnIf.getName(), vpnName);
149                                                 } else if (vpnUtil.isVpnPendingDelete(primaryRd)) {
150                                                     LOG.error("add: Ignoring addition of vpnInterface {}, as"
151                                                             + " vpnInstance {} with primaryRd {} is already marked for"
152                                                             + " deletion", interfaceName, vpnName, primaryRd);
153                                                 } else {
154                                                     Uint64 intfDpnId = Uint64.ZERO;
155                                                     try {
156                                                         intfDpnId = InterfaceUtils.getDpIdFromInterface(intrf);
157                                                     } catch (Exception e) {
158                                                         LOG.error("Unable to retrieve dpnId for interface {}. "
159                                                                 + "Process vpn interface add failed",intrf.getName(),
160                                                                 e);
161                                                         return;
162                                                     }
163                                                     LOG.error("InterfaceStateChangeListener- Processing ifState"
164                                                                     + " {} add event with dpnId {}",
165                                                             intrf.getName(), intfDpnId);
166                                                     final Uint64 dpnId = intfDpnId;
167                                                     final int ifIndex = intrf.getIfIndex();
168                                                     LOG.info("VPN Interface add event - intfName {} onto vpnName {}"
169                                                             + " running oper-driven", vpnIf.getName(), vpnName);
170                                                     Set<String> prefixes = new HashSet<>();
171                                                     vpnInterfaceManager.processVpnInterfaceUp(dpnId, vpnIf, primaryRd,
172                                                             ifIndex, false, writeConfigTxn, writeOperTxn, writeInvTxn,
173                                                             intrf, vpnName, prefixes);
174                                                     mapOfRdAndPrefixesForRefreshFib.put(primaryRd, prefixes);
175                                                 }
176                                             }
177
178                                         }
179                                     });
180                                 futures.add(operFuture);
181                                 operFuture.get(); //Synchronous submit of operTxn
182                             });
183                         Futures.addCallback(configFuture,
184                                 new VpnInterfaceCallBackHandler(mapOfRdAndPrefixesForRefreshFib),
185                                 MoreExecutors.directExecutor());
186                         futures.add(configFuture);
187                         //TODO: Allow immediateFailedFuture from writeCfgTxn to cancel writeInvTxn as well.
188                         Futures.addCallback(configFuture, new PostVpnInterfaceThreadWorker(intrf.getName(), true,
189                                 "Operational"), MoreExecutors.directExecutor());
190                     }));
191                     return futures;
192                 });
193             }
194         } catch (Exception e) {
195             LOG.error("Exception caught in Interface {} Operational State Up event", intrf.getName(), e);
196         }
197     }
198
199     @Override
200     // TODO Clean up the exception handling
201     @SuppressWarnings("checkstyle:IllegalCatch")
202     protected void remove(InstanceIdentifier<Interface> identifier, Interface intrf) {
203         final String ifName = intrf.getName();
204         Uint64 dpId = Uint64.ZERO;
205         try {
206             if (L2vlan.class.equals(intrf.getType())) {
207                 LOG.info("VPN Interface remove event - intfName {} from InterfaceStateChangeListener",
208                                 intrf.getName());
209                 try {
210                     dpId = InterfaceUtils.getDpIdFromInterface(intrf);
211                 } catch (Exception e) {
212                     LOG.error("Unable to retrieve dpnId from interface operational data store for interface"
213                             + " {}. Fetching from vpn interface op data store. ", ifName, e);
214                 }
215                 final Uint64 inputDpId = dpId;
216                 jobCoordinator.enqueueJob("VPNINTERFACE-" + ifName, () -> {
217                     List<ListenableFuture<Void>> futures = new ArrayList<>(3);
218                     ListenableFuture<Void> configFuture =
219                         txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
220                             writeConfigTxn -> futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL,
221                                 writeOperTxn -> futures.add(
222                                     txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, writeInvTxn -> {
223                                         VpnInterface cfgVpnInterface =
224                                             vpnUtil.getConfiguredVpnInterface(ifName);
225                                         if (cfgVpnInterface == null) {
226                                             LOG.debug("Interface {} is not a vpninterface, ignoring.", ifName);
227                                             return;
228                                         }
229                                         for (VpnInstanceNames vpnInterfaceVpnInstance :
230                                                 cfgVpnInterface.nonnullVpnInstanceNames()) {
231                                             String vpnName = vpnInterfaceVpnInstance.getVpnName();
232                                             Optional<VpnInterfaceOpDataEntry> optVpnInterface =
233                                                 vpnUtil.getVpnInterfaceOpDataEntry(ifName, vpnName);
234                                             if (!optVpnInterface.isPresent()) {
235                                                 LOG.debug("Interface {} vpn {} is not a vpninterface, or deletion"
236                                                     + " triggered by northbound agent. ignoring.", ifName, vpnName);
237                                                 continue;
238                                             }
239                                             handleMipAdjRemoval(cfgVpnInterface, vpnName);
240                                             final VpnInterfaceOpDataEntry vpnInterface = optVpnInterface.get();
241                                             String gwMac = intrf.getPhysAddress() != null ? intrf.getPhysAddress()
242                                                 .getValue() : vpnInterface.getGatewayMacAddress();
243                                             Uint64 dpnId = inputDpId;
244                                             if (dpnId == null || dpnId.equals(Uint64.ZERO)) {
245                                                 dpnId = vpnInterface.getDpnId();
246                                             }
247                                             final int ifIndex = intrf.getIfIndex();
248                                             LOG.info("VPN Interface remove event - intfName {} onto vpnName {}"
249                                                 + " running oper-driver", vpnInterface.getName(), vpnName);
250                                             vpnInterfaceManager.processVpnInterfaceDown(dpnId, ifName, ifIndex, gwMac,
251                                                 vpnInterface, false, writeConfigTxn, writeOperTxn, writeInvTxn);
252                                         }
253                                     })))));
254                     futures.add(configFuture);
255                     Futures.addCallback(configFuture, new PostVpnInterfaceThreadWorker(intrf.getName(), false,
256                             "Operational"), MoreExecutors.directExecutor());
257                     return futures;
258                 }, DJC_MAX_RETRIES);
259             }
260         } catch (Exception e) {
261             LOG.error("Exception observed in handling deletion of VPN Interface {}. ", ifName, e);
262         }
263     }
264
265     // TODO Clean up the exception handling
266     @SuppressWarnings("checkstyle:IllegalCatch")
267     @Override
268     protected void update(InstanceIdentifier<Interface> identifier,
269                     Interface original, Interface update) {
270         final String ifName = update.getName();
271         try {
272             if (update.getIfIndex() == null) {
273                 return;
274             }
275             if (L2vlan.class.equals(update.getType())) {
276                 LOG.info("VPN Interface update event - intfName {} from InterfaceStateChangeListener",
277                         update.getName());
278                 jobCoordinator.enqueueJob("VPNINTERFACE-" + ifName, () -> {
279                     List<ListenableFuture<Void>> futures = new ArrayList<>(3);
280                     futures.add(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, writeOperTxn -> {
281                         //map of prefix and vpn name used, as entry in prefix-to-interface datastore
282                         // is prerequisite for refresh Fib to avoid race condition leading to missing remote
283                         // next hop in bucket actions on bgp-vpn delete
284                         Map<String, Set<String>> mapOfRdAndPrefixesForRefreshFib = new HashMap<>();
285                         ListenableFuture<Void> configTxFuture =
286                                 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, writeConfigTxn ->
287                                     futures.add(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
288                                         writeInvTxn -> {
289                                             final VpnInterface vpnIf = vpnUtil.getConfiguredVpnInterface(ifName);
290                                             if (vpnIf != null) {
291                                                 final int ifIndex = update.getIfIndex();
292                                                 Uint64 dpnId;
293                                                 try {
294                                                     dpnId = InterfaceUtils.getDpIdFromInterface(update);
295                                                 } catch (Exception e) {
296                                                     LOG.error("remove: Unable to retrieve dpnId for interface {}",
297                                                         ifName, e);
298                                                     return;
299                                                 }
300                                                 IntfTransitionState state = getTransitionState(
301                                                         original.getOperStatus(), update.getOperStatus());
302                                                 if (state.equals(IntfTransitionState.STATE_IGNORE)) {
303                                                     LOG.info("InterfaceStateChangeListener: Interface {} state "
304                                                          + "original {}" + "updated {} not handled", ifName,
305                                                          original.getOperStatus(), update.getOperStatus());
306                                                     return;
307                                                 }
308                                                 LOG.error("InterfaceStateChangeListener- Processing ifState {} "
309                                                                 + "update event "
310                                                                 + "with dpnId {} operstate {}",
311                                                         ifName, dpnId, update.getOperStatus());
312                                                 if (state.equals(IntfTransitionState.STATE_UP)
313                                                         && vpnIf.getVpnInstanceNames() != null) {
314                                                     for (VpnInstanceNames vpnInterfaceVpnInstance :
315                                                             vpnIf.getVpnInstanceNames()) {
316                                                         String vpnName = vpnInterfaceVpnInstance.getVpnName();
317                                                         String primaryRd = vpnUtil.getPrimaryRd(vpnName);
318                                                         Set<String> prefixes = new HashSet<>();
319                                                         if (!vpnInterfaceManager.isVpnInstanceReady(vpnName)) {
320                                                             LOG.error("VPN Interface update event - intfName {} "
321                                                                 + "onto vpnName {} running oper-driven UP, "
322                                                                 + "VpnInstance not ready, holding on",
323                                                                 vpnIf.getName(), vpnName);
324                                                         } else if (vpnUtil.isVpnPendingDelete(primaryRd)) {
325                                                             LOG.error("update: Ignoring UP event for vpnInterface "
326                                                                 + "{}, as vpnInstance {} with primaryRd {} is "
327                                                                 + "already marked for deletion ",
328                                                                 vpnIf.getName(), vpnName, primaryRd);
329                                                         } else {
330                                                             vpnInterfaceManager.processVpnInterfaceUp(dpnId, vpnIf,
331                                                                 primaryRd, ifIndex, true, writeConfigTxn,
332                                                                 writeOperTxn, writeInvTxn, update, vpnName, prefixes);
333                                                             mapOfRdAndPrefixesForRefreshFib.put(primaryRd, prefixes);
334                                                         }
335                                                     }
336                                                 } else if (state.equals(IntfTransitionState.STATE_DOWN)
337                                                         && vpnIf.getVpnInstanceNames() != null) {
338                                                     for (VpnInstanceNames vpnInterfaceVpnInstance :
339                                                             vpnIf.getVpnInstanceNames()) {
340                                                         String vpnName = vpnInterfaceVpnInstance.getVpnName();
341                                                         LOG.info("VPN Interface update event - intfName {} "
342                                                             + " onto vpnName {} running oper-driven DOWN",
343                                                             vpnIf.getName(), vpnName);
344                                                         Optional<VpnInterfaceOpDataEntry> optVpnInterface = vpnUtil
345                                                             .getVpnInterfaceOpDataEntry(vpnIf.getName(), vpnName);
346                                                         if (optVpnInterface.isPresent()) {
347                                                             VpnInterfaceOpDataEntry vpnOpInterface =
348                                                                 optVpnInterface.get();
349                                                             handleMipAdjRemoval(vpnIf, vpnName);
350                                                             vpnInterfaceManager.processVpnInterfaceDown(dpnId,
351                                                                 vpnIf.getName(), ifIndex, update.getPhysAddress()
352                                                                 .getValue(), vpnOpInterface, true,
353                                                                 writeConfigTxn, writeOperTxn, writeInvTxn);
354                                                         } else {
355                                                             LOG.error("InterfaceStateChangeListener Update DOWN - "
356                                                                 + " vpnInterface {}not available, ignoring event",
357                                                                 vpnIf.getName());
358                                                             continue;
359                                                         }
360                                                     }
361                                                 }
362                                             } else {
363                                                 LOG.debug("Interface {} is not a vpninterface, ignoring.", ifName);
364                                             }
365                                         })));
366                         Futures.addCallback(configTxFuture,
367                             new VpnInterfaceCallBackHandler(mapOfRdAndPrefixesForRefreshFib),
368                             MoreExecutors.directExecutor());
369                         futures.add(configTxFuture);
370                     }));
371                     return futures;
372                 });
373             }
374         } catch (Exception e) {
375             LOG.error("Exception observed in handling updation of VPN Interface {}. ", update.getName(), e);
376         }
377     }
378
379     private void handleMipAdjRemoval(VpnInterface cfgVpnInterface, String vpnName) {
380         String interfaceName = cfgVpnInterface.getName();
381         Adjacencies adjacencies = cfgVpnInterface.augmentation(Adjacencies.class);
382         if (adjacencies != null) {
383             List<Adjacency> adjacencyList = adjacencies.getAdjacency();
384             if (!adjacencyList.isEmpty()) {
385                 for (Adjacency adj : adjacencyList) {
386                     if (adj.getAdjacencyType() != Adjacency.AdjacencyType.PrimaryAdjacency) {
387                         String ipAddress = adj.getIpAddress();
388                         String prefix = ipAddress.split("/")[0];
389                         LearntVpnVipToPort vpnVipToPort = vpnUtil.getLearntVpnVipToPort(vpnName, prefix);
390                         if (vpnVipToPort != null && vpnVipToPort.getPortName().equals(interfaceName)) {
391                             vpnUtil.removeMipAdjacency(vpnName, interfaceName, ipAddress, null);
392                         } else {
393                             LOG.debug("IP {} could be extra-route or learnt-ip on different interface"
394                                     + "than oper-vpn-interface {}", ipAddress, interfaceName);
395                         }
396                     }
397                 }
398             }
399         }
400     }
401
402     private class PostVpnInterfaceThreadWorker implements FutureCallback<Void> {
403         private final String interfaceName;
404         private final boolean add;
405         private final String txnDestination;
406
407         PostVpnInterfaceThreadWorker(String interfaceName, boolean add, String transactionDest) {
408             this.interfaceName = interfaceName;
409             this.add = add;
410             this.txnDestination = transactionDest;
411         }
412
413         @Override
414         public void onSuccess(Void voidObj) {
415             if (add) {
416                 LOG.debug("InterfaceStateChangeListener: VrfEntries for {} stored into destination {} successfully",
417                         interfaceName, txnDestination);
418             } else {
419                 LOG.debug("InterfaceStateChangeListener:  VrfEntries for {} removed successfully", interfaceName);
420             }
421         }
422
423         @Override
424         public void onFailure(Throwable throwable) {
425             if (add) {
426                 LOG.error("InterfaceStateChangeListener: VrfEntries for {} failed to store into destination {}",
427                         interfaceName, txnDestination, throwable);
428             } else {
429                 LOG.error("InterfaceStateChangeListener: VrfEntries for {} removal failed", interfaceName, throwable);
430                 vpnUtil.unsetScheduledToRemoveForVpnInterface(interfaceName);
431             }
432         }
433     }
434
435     private IntfTransitionState getTransitionState(Interface.OperStatus original , Interface.OperStatus updated) {
436         IntfTransitionState transitionState = stateTable.get(original, updated);
437
438         if (transitionState == null) {
439             return IntfTransitionState.STATE_IGNORE;
440         }
441         return transitionState;
442     }
443
444     private class VpnInterfaceCallBackHandler implements FutureCallback<Void> {
445         private final Map<String, Set<String>> mapOfRdAndPrefixesForRefreshFib;
446
447         VpnInterfaceCallBackHandler(Map<String, Set<String>> mapOfRdAndPrefixesForRefreshFib) {
448             this.mapOfRdAndPrefixesForRefreshFib = mapOfRdAndPrefixesForRefreshFib;
449         }
450
451         @Override
452         public void onSuccess(Void voidObj) {
453             mapOfRdAndPrefixesForRefreshFib.forEach((primaryRd, prefixes) -> {
454                 prefixes.forEach(prefix -> {
455                     fibManager.refreshVrfEntry(primaryRd, prefix);
456                 });
457             });
458         }
459
460         @Override
461         public void onFailure(Throwable throwable) {
462             LOG.debug("write Tx config operation failedTunnelEndPointChangeListener", throwable);
463         }
464     }
465 }