Freeze upstream versions
[netvirt.git] / fibmanager / impl / src / main / java / org / opendaylight / netvirt / fibmanager / BgpRouteVrfEntryHandler.java
1 /*
2  * Copyright © 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.fibmanager;
9
10 import static java.util.Objects.requireNonNull;
11 import static java.util.stream.Collectors.toList;
12
13 import java.util.ArrayList;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Optional;
17 import java.util.concurrent.BlockingQueue;
18 import java.util.concurrent.LinkedBlockingQueue;
19 import java.util.function.Consumer;
20 import javax.annotation.PostConstruct;
21 import javax.inject.Inject;
22 import javax.inject.Singleton;
23 import org.eclipse.jdt.annotation.Nullable;
24 import org.opendaylight.genius.datastoreutils.listeners.DataTreeEventCallbackRegistrar;
25 import org.opendaylight.genius.mdsalutil.ActionInfo;
26 import org.opendaylight.genius.mdsalutil.InstructionInfo;
27 import org.opendaylight.genius.mdsalutil.NwConstants;
28 import org.opendaylight.genius.mdsalutil.actions.ActionGroup;
29 import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadInPort;
30 import org.opendaylight.genius.mdsalutil.actions.ActionPushMpls;
31 import org.opendaylight.genius.mdsalutil.actions.ActionRegLoad;
32 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetDestination;
33 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldMplsLabel;
34 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
35 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
36 import org.opendaylight.genius.utils.batching.ActionableResource;
37 import org.opendaylight.genius.utils.batching.ActionableResources;
38 import org.opendaylight.genius.utils.batching.ResourceBatchingManager;
39 import org.opendaylight.genius.utils.batching.ResourceHandler;
40 import org.opendaylight.genius.utils.batching.SubTransaction;
41 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
42 import org.opendaylight.mdsal.binding.api.DataBroker;
43 import org.opendaylight.mdsal.binding.api.WriteTransaction;
44 import org.opendaylight.mdsal.binding.util.Datastore;
45 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunner;
46 import org.opendaylight.mdsal.binding.util.ManagedNewTransactionRunnerImpl;
47 import org.opendaylight.mdsal.binding.util.TransactionAdapter;
48 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
49 import org.opendaylight.netvirt.vpnmanager.api.VpnExtraRouteHelper;
50 import org.opendaylight.serviceutils.upgrade.UpgradeState;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeMplsOverGre;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTables;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthop;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnList;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.vpn.instance.op.data.entry.VpnToDpnListKey;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.vpn.extra.routes.Routes;
64 import org.opendaylight.yangtools.concepts.Identifier;
65 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
66 import org.opendaylight.yangtools.yang.common.Uint32;
67 import org.opendaylight.yangtools.yang.common.Uint64;
68 import org.slf4j.Logger;
69 import org.slf4j.LoggerFactory;
70
71
72 @Singleton
73 public class BgpRouteVrfEntryHandler extends BaseVrfEntryHandler implements ResourceHandler {
74     private static final class ActionableResourceIdentifier implements Identifier {
75         private static final long serialVersionUID = 1L;
76
77         private final String routeDistinguisher;
78         private final String destPrefix;
79
80         ActionableResourceIdentifier(final String routeDistinguisher, final String destPrefix) {
81             this.routeDistinguisher = requireNonNull(routeDistinguisher);
82             this.destPrefix = requireNonNull(destPrefix);
83         }
84
85         @Override
86         public int hashCode() {
87             return routeDistinguisher.hashCode() * 31 + destPrefix.hashCode();
88         }
89
90         @Override
91         public boolean equals(final Object obj) {
92             if (this == obj) {
93                 return true;
94             }
95             if (!(obj instanceof ActionableResourceIdentifier)) {
96                 return false;
97             }
98             final ActionableResourceIdentifier other = (ActionableResourceIdentifier) obj;
99             return routeDistinguisher.equals(other.routeDistinguisher) && destPrefix.equals(other.destPrefix);
100         }
101
102         @Override
103         public String toString() {
104             return routeDistinguisher + destPrefix;
105         }
106     }
107
108     private static final Logger LOG = LoggerFactory.getLogger(BgpRouteVrfEntryHandler.class);
109     private static final int BATCH_INTERVAL = 500;
110     private static final int BATCH_SIZE = 1000;
111
112     private final DataBroker dataBroker;
113     private final ManagedNewTransactionRunner txRunner;
114     private final BlockingQueue<ActionableResource<?>> vrfEntryBufferQ = new LinkedBlockingQueue<>();
115     private final ResourceBatchingManager resourceBatchingManager;
116     private final NexthopManager nexthopManager;
117
118     @Inject
119     public BgpRouteVrfEntryHandler(final DataBroker dataBroker,
120                                    final NexthopManager nexthopManager,
121                                    final FibUtil fibUtil,
122                                    final UpgradeState upgradeState,
123                                    final DataTreeEventCallbackRegistrar eventCallbacks) {
124         super(dataBroker, nexthopManager, null, fibUtil, upgradeState, eventCallbacks);
125         this.dataBroker = dataBroker;
126         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
127         this.nexthopManager = nexthopManager;
128
129         resourceBatchingManager = ResourceBatchingManager.getInstance();
130         resourceBatchingManager.registerBatchableResource("FIB-VRFENTRY", vrfEntryBufferQ, this);
131     }
132
133     @PostConstruct
134     public void init() {
135         LOG.info("{} start", getClass().getSimpleName());
136     }
137
138     @Override
139     public void close() {
140         LOG.info("{} close", getClass().getSimpleName());
141     }
142
143     @Override
144     public DataBroker getResourceBroker() {
145         return dataBroker;
146     }
147
148     @Override
149     public int getBatchSize() {
150         return BATCH_SIZE;
151     }
152
153     @Override
154     public int getBatchInterval() {
155         return BATCH_INTERVAL;
156     }
157
158     @Override
159     public LogicalDatastoreType getDatastoreType() {
160         return LogicalDatastoreType.CONFIGURATION;
161     }
162
163     @Override
164     public void update(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier,
165                        Object original, Object update, List<SubTransaction> subTxns) {
166         if (original instanceof VrfEntry && update instanceof VrfEntry) {
167             createFibEntries(tx, identifier, (VrfEntry) update, subTxns);
168         }
169     }
170
171     @Override
172     public void updateContainer(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier,
173                                 Object original, Object update, List<SubTransaction> transactionObjects) {
174     }
175
176     @Override
177     public void create(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier,
178                        Object vrfEntry, List<SubTransaction> subTxns) {
179         if (vrfEntry instanceof VrfEntry) {
180             createFibEntries(tx, identifier, (VrfEntry) vrfEntry, subTxns);
181         }
182     }
183
184     @Override
185     public void delete(WriteTransaction tx, LogicalDatastoreType datastoreType, InstanceIdentifier identifier,
186                        Object vrfEntry, List<SubTransaction> subTxns) {
187         if (vrfEntry instanceof VrfEntry) {
188             deleteFibEntries(tx, identifier, (VrfEntry) vrfEntry, subTxns);
189         }
190     }
191
192     void createFlows(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntry, String rd) {
193         vrfEntryBufferQ.add(ActionableResources.create(new ActionableResourceIdentifier(rd, vrfEntry.getDestPrefix()),
194             identifier, vrfEntry));
195     }
196
197     void removeFlows(InstanceIdentifier<VrfEntry> identifier, VrfEntry vrfEntry, String rd) {
198         vrfEntryBufferQ.add(ActionableResources.delete(new ActionableResourceIdentifier(rd, vrfEntry.getDestPrefix()),
199             identifier, vrfEntry));
200     }
201
202     void updateFlows(InstanceIdentifier<VrfEntry> identifier, VrfEntry original, VrfEntry update, String rd) {
203         vrfEntryBufferQ.add(ActionableResources.update(new ActionableResourceIdentifier(rd, update.getDestPrefix()),
204             identifier, update, original));
205     }
206
207     /*
208       Please note that the following createFibEntries will be invoked only for BGP Imported Routes.
209       The invocation of the following method is via create() callback from the MDSAL Batching Infrastructure
210       provided by ResourceBatchingManager
211      */
212     private void createFibEntries(WriteTransaction writeTx, final InstanceIdentifier<VrfEntry> vrfEntryIid,
213                                   final VrfEntry vrfEntry, List<SubTransaction> subTxns) {
214         final VrfTablesKey vrfTableKey = vrfEntryIid.firstKeyOf(VrfTables.class);
215         LOG.trace("Creating fib entry for vrfEntry with destPrefix{}, rd {}",
216             vrfEntry.getDestPrefix(), vrfTableKey.getRouteDistinguisher());
217         final VpnInstanceOpDataEntry vpnInstance =
218                 getFibUtil().getVpnInstance(vrfTableKey.getRouteDistinguisher());
219         if (vpnInstance == null || vpnInstance.getVpnId() == null) {
220             LOG.error("Vpn Instance not availabe {}", vrfTableKey.getRouteDistinguisher());
221             return;
222         }
223         final Map<VpnToDpnListKey, VpnToDpnList> keyVpnToDpnListMap = vpnInstance.nonnullVpnToDpnList();
224         if (keyVpnToDpnListMap != null) {
225             for (VpnToDpnList vpnDpn : keyVpnToDpnListMap.values()) {
226                 LOG.trace("Dpnstate is {} for dpn {} in vpn {}", vpnDpn.getDpnState(), vpnDpn.getDpnId(),
227                     vpnInstance.getVpnId());
228                 if (vpnDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
229                     createRemoteFibEntry(vpnDpn.getDpnId(), vpnInstance.getVpnId(),
230                             vrfTableKey.getRouteDistinguisher(), vrfEntry, writeTx, subTxns);
231                 }
232             }
233         }
234         LOG.trace("Created fib entry for vrfEntry with destPrefix{}, rd {}",
235             vrfEntry.getDestPrefix(), vrfTableKey.getRouteDistinguisher());
236     }
237
238     /*
239       Please note that the following deleteFibEntries will be invoked only for BGP Imported Routes.
240       The invocation of the following method is via delete() callback from the MDSAL Batching Infrastructure
241       provided by ResourceBatchingManager
242      */
243     private void deleteFibEntries(WriteTransaction writeTx, final InstanceIdentifier<VrfEntry> identifier,
244                                   final VrfEntry vrfEntry, List<SubTransaction> subTxns) {
245         final VrfTablesKey vrfTableKey = identifier.firstKeyOf(VrfTables.class);
246         String rd = vrfTableKey.getRouteDistinguisher();
247         final VpnInstanceOpDataEntry vpnInstance =
248                 getFibUtil().getVpnInstance(vrfTableKey.getRouteDistinguisher());
249         if (vpnInstance == null) {
250             LOG.debug("VPN Instance for rd {} is not available from VPN Op Instance Datastore", rd);
251             return;
252         }
253         String vpnName = getFibUtil().getVpnNameFromId(vpnInstance.getVpnId());
254         final Map<VpnToDpnListKey, VpnToDpnList> keyVpnToDpnListMap = vpnInstance.nonnullVpnToDpnList();
255         if (keyVpnToDpnListMap != null) {
256             List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker,
257                     vpnInstance.getVpnId(), vrfEntry.getDestPrefix());
258             Optional<Routes> extraRouteOptional;
259             //Is this fib route an extra route? If yes, get the nexthop which would be an adjacency in the vpn
260             if (usedRds != null && !usedRds.isEmpty()) {
261                 if (usedRds.size() > 1) {
262                     LOG.error("The extra route prefix is still present in some DPNs");
263                     return ;
264                 } else {
265                     extraRouteOptional = VpnExtraRouteHelper.getVpnExtraroutes(dataBroker, vpnName,
266                             usedRds.get(0), vrfEntry.getDestPrefix());
267                 }
268             } else {
269                 extraRouteOptional = Optional.empty();
270             }
271             for (VpnToDpnList curDpn : keyVpnToDpnListMap.values()) {
272                 if (curDpn.getDpnState() == VpnToDpnList.DpnState.Active) {
273                     deleteRemoteRoute(Uint64.ZERO, curDpn.getDpnId(), vpnInstance.getVpnId(),
274                             vrfTableKey, vrfEntry, extraRouteOptional, writeTx, subTxns);
275                 }
276             }
277         }
278     }
279
280     public void programRemoteFibForBgpRoutes(final Uint64 remoteDpnId,
281                                              final Uint32 vpnId,
282                                              final VrfEntry vrfEntry,
283                                              WriteTransaction tx,
284                                              String rd,
285                                              List<NexthopManager.AdjacencyResult> adjacencyResults,
286                                              List<SubTransaction> subTxns) {
287         if (vrfEntry.nonnullRoutePaths().size() > 2) {
288             LOG.error("DC-GW can advertise only 2 bestPaths for prefix {}", vrfEntry.getDestPrefix());
289             return;
290         }
291         LOG.trace("Start programming remote fib for destPrefix {}, vpnId {}, dpnId {}",
292             vrfEntry.getDestPrefix(), vpnId, remoteDpnId);
293         if (adjacencyResults.size() == 1) {
294             programRemoteFib(remoteDpnId, vpnId, vrfEntry, tx, rd, adjacencyResults, subTxns);
295             return;
296         }
297         // ECMP Use case, point to LB group. Move the mpls label accordingly.
298         List<String> tunnelList =
299                 adjacencyResults.stream()
300                         .map(NexthopManager.AdjacencyResult::getNextHopIp)
301                         .sorted().collect(toList());
302         String lbGroupKey = FibUtil.getGreLbGroupKey(tunnelList);
303         long groupId = nexthopManager.createNextHopPointer(lbGroupKey);
304         int index = 0;
305         List<ActionInfo> actionInfos = new ArrayList<>();
306         for (NexthopManager.AdjacencyResult adjResult : adjacencyResults) {
307             String nextHopIp = adjResult.getNextHopIp();
308             java.util.Optional<Uint32> optionalLabel = FibUtil.getLabelForNextHop(vrfEntry, nextHopIp);
309             if (!optionalLabel.isPresent()) {
310                 LOG.warn("NextHopIp {} not found in vrfEntry {}", nextHopIp, vrfEntry);
311                 continue;
312             }
313             long label = optionalLabel.get().toJava();
314
315             actionInfos.add(new ActionRegLoad(index, FibConstants.NXM_REG_MAPPING.get(index++), 0,
316                     31, label));
317         }
318         List<InstructionInfo> instructions = new ArrayList<>();
319         actionInfos.add(new ActionGroup(index, groupId));
320         instructions.add(new InstructionApplyActions(actionInfos));
321         makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx, subTxns);
322         LOG.trace("End programming remote fib for destPrefix {}, vpnId {}, dpnId {}",
323                 vrfEntry.getDestPrefix(), vpnId, remoteDpnId);
324     }
325
326     // Allow deprecated TransactionRunner calls for now
327     @SuppressWarnings("ForbidCertainMethod")
328     public void createRemoteFibEntry(final Uint64 remoteDpnId,
329                                      final Uint32 vpnId,
330                                      final String rd,
331                                      final VrfEntry vrfEntry,
332                                      WriteTransaction tx,
333                                      List<SubTransaction> subTxns) {
334         if (tx == null) {
335             LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(Datastore.CONFIGURATION,
336                 newTx -> createRemoteFibEntry(remoteDpnId, vpnId, rd, vrfEntry,
337                         TransactionAdapter.toWriteTransaction(newTx), subTxns)), LOG,
338                 "Error creating remote FIB entry");
339             return;
340         }
341
342         LOG.debug("createRemoteFibEntry: adding route {} for rd {} on remoteDpnId {}",
343                 vrfEntry.getDestPrefix(), rd, remoteDpnId);
344
345         List<NexthopManager.AdjacencyResult> adjacencyResults =
346                 resolveAdjacency(remoteDpnId, vpnId, vrfEntry, rd);
347         if (adjacencyResults.isEmpty()) {
348             LOG.error("Could not get interface for route-paths: {} in vpn {}", vrfEntry.getRoutePaths(), rd);
349             LOG.warn("Failed to add Route: {} in vpn: {}", vrfEntry.getDestPrefix(), rd);
350             return;
351         }
352
353         programRemoteFibForBgpRoutes(remoteDpnId, vpnId, vrfEntry, tx, rd, adjacencyResults, subTxns);
354
355         LOG.debug("Successfully added FIB entry for prefix {} in vpnId {}", vrfEntry.getDestPrefix(), vpnId);
356     }
357
358     private void deleteFibEntryForBgpRoutes(Uint64 remoteDpnId, Uint32 vpnId, VrfEntry vrfEntry,
359                                              String rd, WriteTransaction tx, List<SubTransaction> subTxns) {
360         // When the tunnel is removed the fib entries should be reprogrammed/deleted depending on
361         // the adjacencyResults.
362         List<NexthopManager.AdjacencyResult> adjacencyResults = resolveAdjacency(remoteDpnId, vpnId, vrfEntry, rd);
363         if (!adjacencyResults.isEmpty()) {
364             programRemoteFibForBgpRoutes(remoteDpnId, vpnId, vrfEntry, tx, rd, adjacencyResults, subTxns);
365         }
366     }
367
368     // Allow deprecated TransactionRunner calls for now
369     @SuppressWarnings("ForbidCertainMethod")
370     public void deleteRemoteRoute(@Nullable final Uint64 localDpnId, final Uint64 remoteDpnId,
371                                   final Uint32 vpnId, final VrfTablesKey vrfTableKey,
372                                   final VrfEntry vrfEntry, Optional<Routes> extraRouteOptional,
373                                   @Nullable WriteTransaction tx, List<SubTransaction> subTxns) {
374         if (tx == null) {
375             LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(Datastore.CONFIGURATION,
376                 newTx -> deleteRemoteRoute(localDpnId, remoteDpnId, vpnId, vrfTableKey, vrfEntry,
377                         extraRouteOptional, TransactionAdapter.toWriteTransaction(newTx))),
378                     LOG, "Error deleting remote route");
379             return;
380         }
381
382         LOG.debug("deleting remote route: prefix={}, vpnId={} localDpnId {} remoteDpnId {}",
383                 vrfEntry.getDestPrefix(), vpnId, localDpnId, remoteDpnId);
384         String rd = vrfTableKey.getRouteDistinguisher();
385
386         if (localDpnId != null && !Uint64.ZERO.equals(localDpnId)) {
387             // localDpnId is not known when clean up happens for last vm for a vpn on a dpn
388             if (extraRouteOptional.isPresent()) {
389                 nexthopManager.deleteLoadBalancingNextHop(vpnId, remoteDpnId, vrfEntry.getDestPrefix());
390             }
391             deleteFibEntryForBgpRoutes(remoteDpnId, vpnId, vrfEntry, rd, tx, subTxns);
392             return;
393         }
394
395         // below two reads are kept as is, until best way is found to identify dpnID
396         VpnNexthop localNextHopInfo = nexthopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
397         if (extraRouteOptional.isPresent()) {
398             nexthopManager.deleteLoadBalancingNextHop(vpnId, remoteDpnId, vrfEntry.getDestPrefix());
399         } else {
400             checkDpnDeleteFibEntry(localNextHopInfo, remoteDpnId, vpnId, vrfEntry, rd, tx, subTxns);
401         }
402     }
403
404     public Consumer<? super VrfEntry> getConsumerForCreatingRemoteFib(
405             final Uint64 dpnId, final Uint32 vpnId, final String rd,
406             final String remoteNextHopIp, final Optional<VrfTables> vrfTable,
407             WriteTransaction writeCfgTxn, List<SubTransaction> subTxns) {
408         return vrfEntry -> vrfEntry.nonnullRoutePaths().values().stream()
409                 .filter(routes -> !routes.getNexthopAddress().isEmpty()
410                         && remoteNextHopIp.trim().equals(routes.getNexthopAddress().trim()))
411                 .findFirst()
412                 .ifPresent(routes -> {
413                     LOG.trace("creating remote FIB entry for prefix {} rd {} on Dpn {}",
414                             vrfEntry.getDestPrefix(), rd, dpnId);
415                     createRemoteFibEntry(dpnId, vpnId, vrfTable.get().getRouteDistinguisher(),
416                             vrfEntry, writeCfgTxn, subTxns);
417                 });
418     }
419
420     public Consumer<? super VrfEntry> getConsumerForDeletingRemoteFib(
421             final Uint64 dpnId, final Uint32 vpnId,
422             final String remoteNextHopIp, final Optional<VrfTables> vrfTable,
423             WriteTransaction writeCfgTxn, List<SubTransaction> subTxns) {
424         return vrfEntry -> vrfEntry.nonnullRoutePaths().values().stream()
425                 .filter(routes -> !routes.getNexthopAddress().isEmpty()
426                         && remoteNextHopIp.trim().equals(routes.getNexthopAddress().trim()))
427                 .findFirst()
428                 .ifPresent(routes -> {
429                     LOG.trace(" deleting remote FIB entry {}", vrfEntry);
430                     deleteRemoteRoute(null, dpnId, vpnId, vrfTable.get().key(), vrfEntry,
431                             Optional.empty(), writeCfgTxn, subTxns);
432                 });
433     }
434
435     @Override
436     protected void addTunnelInterfaceActions(NexthopManager.AdjacencyResult adjacencyResult, Uint32 vpnId,
437             VrfEntry vrfEntry, List<ActionInfo> actionInfos, String rd) {
438         Class<? extends TunnelTypeBase> tunnelType = VpnExtraRouteHelper
439                 .getTunnelType(getNextHopManager().getItmManager(), adjacencyResult.getInterfaceName());
440         if (tunnelType == null) {
441             LOG.debug("Tunnel type not found for vrfEntry {}", vrfEntry);
442             return;
443         }
444         String nextHopIp = adjacencyResult.getNextHopIp();
445         if (tunnelType.equals(TunnelTypeMplsOverGre.class)) {
446             java.util.Optional<Uint32> optionalLabel = FibUtil.getLabelForNextHop(vrfEntry, nextHopIp);
447             if (!optionalLabel.isPresent()) {
448                 LOG.warn("NextHopIp {} not found in vrfEntry {}", nextHopIp, vrfEntry);
449                 return;
450             }
451             long label = optionalLabel.get().toJava();
452             LOG.debug("addTunnelInterfaceActions: Push label action for prefix {} rd {} l3vni {} nextHop {}",
453                     vrfEntry.getDestPrefix(), rd, vrfEntry.getL3vni(), nextHopIp);
454             actionInfos.add(new ActionPushMpls());
455             actionInfos.add(new ActionSetFieldMplsLabel(label));
456             actionInfos.add(new ActionNxLoadInPort(Uint64.ZERO));
457         } else if (tunnelType.equals(TunnelTypeVxlan.class)) {
458             actionInfos.add(new ActionSetFieldTunnelId(Uint64.valueOf(vrfEntry.getL3vni().longValue())));
459             LOG.debug("addTunnelInterfaceActions: adding set tunnel id action for prefix {} rd {} l3vni {}"
460                     + " nextHop {} ", vrfEntry.getDestPrefix(), rd, vrfEntry.getL3vni(), nextHopIp);
461             addRewriteDstMacAction(vpnId, vrfEntry, null /*prefixInfo*/, actionInfos);
462         }
463     }
464
465     @Override
466     protected void addRewriteDstMacAction(Uint32 vpnId, VrfEntry vrfEntry, @Nullable Prefixes prefixInfo,
467                                           List<ActionInfo> actionInfos) {
468         if (vrfEntry.getGatewayMacAddress() != null) {
469             actionInfos.add(new ActionSetFieldEthernetDestination(actionInfos.size(),
470                     new MacAddress(vrfEntry.getGatewayMacAddress())));
471         }
472     }
473
474 }