Migrate ListenableFutures.addErrorLogging() users
[netvirt.git] / fibmanager / impl / src / main / java / org / opendaylight / netvirt / fibmanager / BaseVrfEntryHandler.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.stream.Collectors.toList;
11 import static org.opendaylight.genius.mdsalutil.NWUtil.isIpv4Address;
12
13 import java.net.Inet4Address;
14 import java.net.InetAddress;
15 import java.net.UnknownHostException;
16 import java.time.Duration;
17 import java.time.temporal.ChronoUnit;
18 import java.util.ArrayList;
19 import java.util.Collections;
20 import java.util.List;
21 import java.util.Optional;
22 import java.util.concurrent.ExecutionException;
23 import javax.inject.Inject;
24 import javax.inject.Singleton;
25 import org.eclipse.jdt.annotation.NonNull;
26 import org.eclipse.jdt.annotation.Nullable;
27 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
28 import org.opendaylight.genius.datastoreutils.listeners.DataTreeEventCallbackRegistrar;
29 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
30 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
31 import org.opendaylight.genius.mdsalutil.ActionInfo;
32 import org.opendaylight.genius.mdsalutil.FlowEntity;
33 import org.opendaylight.genius.mdsalutil.InstructionInfo;
34 import org.opendaylight.genius.mdsalutil.MDSALUtil;
35 import org.opendaylight.genius.mdsalutil.MatchInfo;
36 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
37 import org.opendaylight.genius.mdsalutil.NwConstants;
38 import org.opendaylight.genius.mdsalutil.actions.ActionMoveSourceDestinationEth;
39 import org.opendaylight.genius.mdsalutil.actions.ActionMoveSourceDestinationIp;
40 import org.opendaylight.genius.mdsalutil.actions.ActionNxLoadInPort;
41 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
42 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetDestination;
43 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetSource;
44 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldTunnelId;
45 import org.opendaylight.genius.mdsalutil.actions.ActionSetIcmpType;
46 import org.opendaylight.genius.mdsalutil.actions.ActionSetSourceIp;
47 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
48 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
49 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
50 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetDestination;
51 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
52 import org.opendaylight.genius.mdsalutil.matches.MatchIcmpv4;
53 import org.opendaylight.genius.mdsalutil.matches.MatchIpProtocol;
54 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Destination;
55 import org.opendaylight.genius.mdsalutil.matches.MatchIpv6Destination;
56 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
57 import org.opendaylight.genius.utils.batching.SubTransaction;
58 import org.opendaylight.genius.utils.batching.SubTransactionImpl;
59 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
60 import org.opendaylight.mdsal.binding.api.DataBroker;
61 import org.opendaylight.mdsal.binding.api.WriteTransaction;
62 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
63 import org.opendaylight.netvirt.fibmanager.NexthopManager.AdjacencyResult;
64 import org.opendaylight.netvirt.fibmanager.api.FibHelper;
65 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
66 import org.opendaylight.netvirt.vpnmanager.api.VpnExtraRouteHelper;
67 import org.opendaylight.serviceutils.upgrade.UpgradeState;
68 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
69 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeMplsOverGre;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePaths;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthop;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnToExtraroutes;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.Vpn;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.VpnKey;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.vpn.ExtraRoutes;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.vpn.ExtraRoutesKey;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.vpn.extra.routes.Routes;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.vpn.extra.routes.RoutesKey;
94 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
95 import org.opendaylight.yangtools.yang.common.Uint32;
96 import org.opendaylight.yangtools.yang.common.Uint64;
97 import org.slf4j.Logger;
98 import org.slf4j.LoggerFactory;
99
100 @Singleton
101 public class BaseVrfEntryHandler implements AutoCloseable {
102
103     private static final Logger LOG = LoggerFactory.getLogger(BaseVrfEntryHandler.class);
104     private static final Uint64 COOKIE_VM_FIB_TABLE =  Uint64.valueOf("8000003", 16).intern();
105     private static final int DEFAULT_FIB_FLOW_PRIORITY = 10;
106
107     private final DataBroker dataBroker;
108     private final ManagedNewTransactionRunner txRunner;
109     private final NexthopManager nextHopManager;
110     private final IMdsalApiManager mdsalManager;
111     private final FibUtil fibUtil;
112     private final UpgradeState upgradeState;
113     private final DataTreeEventCallbackRegistrar eventCallbacks;
114
115     @Inject
116     public BaseVrfEntryHandler(final DataBroker dataBroker,
117                                final NexthopManager nexthopManager,
118                                final IMdsalApiManager mdsalManager,
119                                final FibUtil fibUtil,
120                                final UpgradeState upgradeState,
121                                final DataTreeEventCallbackRegistrar eventCallbacks) {
122         this.dataBroker = dataBroker;
123         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
124         this.nextHopManager = nexthopManager;
125         this.mdsalManager = mdsalManager;
126         this.fibUtil = fibUtil;
127         this.upgradeState = upgradeState;
128         this.eventCallbacks = eventCallbacks;
129     }
130
131     @Override
132     public void close() {
133         LOG.info("{} closed", getClass().getSimpleName());
134     }
135
136     protected FibUtil getFibUtil() {
137         return fibUtil;
138     }
139
140     protected NexthopManager getNextHopManager() {
141         return nextHopManager;
142     }
143
144     private void addAdjacencyResultToList(List<AdjacencyResult> adjacencyList, AdjacencyResult adjacencyResult) {
145         if (adjacencyResult != null && !adjacencyList.contains(adjacencyResult)) {
146             adjacencyList.add(adjacencyResult);
147         }
148     }
149
150     protected void deleteLocalAdjacency(final Uint64 dpId, final Uint32 vpnId, final String ipAddress,
151                               final String ipPrefixAddress) {
152         LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, primaryIpAddress {} currIpPrefix {}",
153                 dpId, vpnId, ipAddress, ipPrefixAddress);
154         try {
155             nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress, ipPrefixAddress);
156         } catch (NullPointerException e) {
157             // FIXME: NPEs should not be caught but rather their root cause should be eliminated
158             LOG.trace("Failed to remove nexthop", e);
159         }
160     }
161
162     @NonNull
163     protected List<AdjacencyResult> resolveAdjacency(final Uint64 remoteDpnId, final Uint32 vpnId,
164                                                      final VrfEntry vrfEntry, String rd) {
165         List<RoutePaths> routePaths = new ArrayList<RoutePaths>(vrfEntry.nonnullRoutePaths().values());
166         FibHelper.sortIpAddress(routePaths);
167         List<AdjacencyResult> adjacencyList = new ArrayList<>();
168         List<String> prefixIpList;
169         LOG.trace("resolveAdjacency called with remotedDpnId {}, vpnId{}, VrfEntry {}",
170                 remoteDpnId, vpnId, vrfEntry);
171         final Class<? extends TunnelTypeBase> tunnelType;
172         try {
173             if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
174                 tunnelType = TunnelTypeVxlan.class;
175                 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, vrfEntry.getDestPrefix());
176                 List<Routes> vpnExtraRoutes = VpnExtraRouteHelper.getAllVpnExtraRoutes(dataBroker,
177                         fibUtil.getVpnNameFromId(vpnId), usedRds, vrfEntry.getDestPrefix());
178                 if (vpnExtraRoutes.isEmpty()) {
179                     Prefixes prefixInfo = fibUtil.getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
180                     /* We don't want to provide an adjacencyList for
181                      * (1) an extra-route-prefix or,
182                      * (2) for a local route without prefix-to-interface.
183                      * Allow only self-imported routes in such cases */
184                     if (prefixInfo == null && FibHelper
185                             .isControllerManagedNonSelfImportedRoute(RouteOrigin.value(vrfEntry.getOrigin()))) {
186                         LOG.debug("The prefix {} in rd {} for vpn {} does not have a valid extra-route or"
187                                 + " prefix-to-interface entry in the data-store", vrfEntry.getDestPrefix(), rd, vpnId);
188                         return adjacencyList;
189                     }
190                     prefixIpList = Collections.singletonList(vrfEntry.getDestPrefix());
191                 } else {
192                     List<String> prefixIpListLocal = new ArrayList<>();
193                     vpnExtraRoutes.stream().filter(route -> route.getNexthopIpList() != null).forEach(
194                         route -> route.getNexthopIpList().forEach(extraRouteIp -> {
195                             String ipPrefix;
196                             if (isIpv4Address(extraRouteIp)) {
197                                 ipPrefix = extraRouteIp + NwConstants.IPV4PREFIX;
198                             } else {
199                                 ipPrefix = extraRouteIp + NwConstants.IPV6PREFIX;
200                             }
201                             prefixIpListLocal.add(ipPrefix);
202                         }));
203                     prefixIpList = prefixIpListLocal;
204                 }
205             } else {
206                 prefixIpList = Collections.singletonList(vrfEntry.getDestPrefix());
207                 if (vrfEntry.getEncapType() == VrfEntry.EncapType.Mplsgre) {
208                     tunnelType = TunnelTypeMplsOverGre.class;
209                 } else {
210                     tunnelType = TunnelTypeVxlan.class;
211                 }
212             }
213
214             for (String prefixIp : prefixIpList) {
215                 if (routePaths == null || routePaths.isEmpty()) {
216                     LOG.trace("Processing Destination IP {} without NextHop IP", prefixIp);
217                     AdjacencyResult adjacencyResult = nextHopManager.getRemoteNextHopPointer(remoteDpnId, vpnId,
218                             prefixIp, null, tunnelType);
219                     addAdjacencyResultToList(adjacencyList, adjacencyResult);
220                     continue;
221                 }
222                 adjacencyList.addAll(routePaths.stream()
223                         .map(routePath -> {
224                             LOG.debug("NextHop IP for destination {} is {}", prefixIp,
225                                     routePath.getNexthopAddress());
226                             return nextHopManager.getRemoteNextHopPointer(remoteDpnId, vpnId,
227                                     prefixIp, routePath.getNexthopAddress(), tunnelType);
228                         })
229                         .filter(adjacencyResult -> adjacencyResult != null && !adjacencyList.contains(adjacencyResult))
230                         .distinct()
231                         .collect(toList()));
232             }
233         } catch (NullPointerException e) {
234             // FIXME: NPEs should not be caught but rather their root cause should be eliminated
235             LOG.trace("Failed to remove adjacency", e);
236         }
237         return adjacencyList;
238     }
239
240     // Allow deprecated TransactionRunner calls for now
241     @SuppressWarnings("ForbidCertainMethod")
242     protected void makeConnectedRoute(Uint64 dpId, Uint32 vpnId, VrfEntry vrfEntry, String rd,
243                                       @Nullable List<InstructionInfo> instructions, int addOrRemove,
244                                       WriteTransaction tx, @Nullable List<SubTransaction> subTxns) {
245         if (tx == null) {
246             LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(
247                 newTx -> makeConnectedRoute(dpId, vpnId, vrfEntry, rd, instructions, addOrRemove, newTx, subTxns)),
248                 LOG, "Error making connected route");
249             return;
250         }
251
252         LOG.trace("makeConnectedRoute: vrfEntry {}", vrfEntry);
253         String[] values = vrfEntry.getDestPrefix().split("/");
254         String ipAddress = values[0];
255         int prefixLength = values.length == 1 ? 0 : Integer.parseInt(values[1]);
256         if (addOrRemove == NwConstants.ADD_FLOW) {
257             LOG.debug("Adding route to DPN {} for rd {} prefix {} ", dpId, rd, vrfEntry.getDestPrefix());
258         } else {
259             LOG.debug("Removing route from DPN {} for rd {} prefix {}", dpId, rd, vrfEntry.getDestPrefix());
260         }
261         InetAddress destPrefix;
262         try {
263             destPrefix = InetAddress.getByName(ipAddress);
264         } catch (UnknownHostException e) {
265             LOG.error("Failed to get destPrefix for prefix {} rd {} VpnId {} DPN {}",
266                     vrfEntry.getDestPrefix(), rd, vpnId, dpId, e);
267             return;
268         }
269
270         List<MatchInfo> matches = new ArrayList<>();
271
272         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId.longValue()),
273             MetaDataUtil.METADATA_MASK_VRFID));
274
275         if (destPrefix instanceof Inet4Address) {
276             matches.add(MatchEthernetType.IPV4);
277             if (prefixLength != 0) {
278                 matches.add(new MatchIpv4Destination(destPrefix.getHostAddress(), Integer.toString(prefixLength)));
279             }
280         } else {
281             matches.add(MatchEthernetType.IPV6);
282             if (prefixLength != 0) {
283                 matches.add(new MatchIpv6Destination(destPrefix.getHostAddress() + "/" + prefixLength));
284             }
285         }
286
287         int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
288         String flowRef = FibUtil.getFlowRef(dpId, NwConstants.L3_FIB_TABLE, rd, priority, destPrefix);
289         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef, priority,
290                 flowRef, 0, 0,
291                 COOKIE_VM_FIB_TABLE, matches, instructions);
292         Flow flow = flowEntity.getFlowBuilder().build();
293         String flowId = flowEntity.getFlowId();
294         FlowKey flowKey = new FlowKey(new FlowId(flowId));
295         Node nodeDpn = FibUtil.buildDpnNode(dpId);
296
297         InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
298                 .child(Node.class, nodeDpn.key()).augmentation(FlowCapableNode.class)
299                 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
300
301         if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
302             SubTransaction subTransaction = new SubTransactionImpl();
303             if (addOrRemove == NwConstants.ADD_FLOW) {
304                 subTransaction.setInstanceIdentifier(flowInstanceId);
305                 subTransaction.setInstance(flow);
306                 subTransaction.setAction(SubTransaction.CREATE);
307             } else {
308                 subTransaction.setInstanceIdentifier(flowInstanceId);
309                 subTransaction.setAction(SubTransaction.DELETE);
310             }
311             subTxns.add(subTransaction);
312         }
313
314         if (addOrRemove == NwConstants.ADD_FLOW) {
315             tx.mergeParentStructurePut(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow);
316         } else {
317             tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
318         }
319     }
320
321     protected void addRewriteDstMacAction(Uint32 vpnId, VrfEntry vrfEntry, @Nullable Prefixes prefixInfo,
322                                           List<ActionInfo> actionInfos) {
323         if (vrfEntry.getMac() != null) {
324             actionInfos.add(new ActionSetFieldEthernetDestination(actionInfos.size(),
325                     new MacAddress(vrfEntry.getMac())));
326             return;
327         }
328         if (prefixInfo == null) {
329             prefixInfo = fibUtil.getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
330             //Checking PrefixtoInterface again as it is populated later in some cases
331             if (prefixInfo == null) {
332                 LOG.debug("No prefix info found for prefix {}", vrfEntry.getDestPrefix());
333                 return;
334             }
335         }
336         String ipPrefix = prefixInfo.getIpAddress();
337         String ifName = prefixInfo.getVpnInterfaceName();
338         if (ifName == null) {
339             LOG.debug("Failed to get VPN interface for prefix {}", ipPrefix);
340             return;
341         }
342         String vpnName = fibUtil.getVpnNameFromId(vpnId);
343         if (vpnName == null) {
344             LOG.debug("Failed to get VPN name for vpnId {}", vpnId);
345             return;
346         }
347         String macAddress = null;
348         if (vrfEntry.getParentVpnRd() != null) {
349             // Handling iRT/eRT use-case for missing destination mac address in Remote FIB flow
350             Optional<VpnInstanceOpDataEntry> vpnInstance = fibUtil.getVpnInstanceOpData(vrfEntry.getParentVpnRd());
351             if (vpnInstance.isPresent()) {
352                 macAddress = fibUtil.getMacAddressFromPrefix(ifName, vpnInstance.get().getVpnInstanceName(), ipPrefix);
353             } else {
354                 LOG.warn("VpnInstance missing for Parent Rd {} value for prefix {}", vrfEntry.getParentVpnRd(),
355                         vrfEntry.getDestPrefix());
356             }
357         } else {
358             macAddress = fibUtil.getMacAddressFromPrefix(ifName, vpnName, ipPrefix);
359         }
360         if (macAddress == null) {
361             LOG.warn("No MAC address found for VPN interface {} prefix {}", ifName, ipPrefix);
362             return;
363         }
364         actionInfos.add(new ActionSetFieldEthernetDestination(actionInfos.size(), new MacAddress(macAddress)));
365     }
366
367     protected void addTunnelInterfaceActions(AdjacencyResult adjacencyResult, Uint32 vpnId, VrfEntry vrfEntry,
368                                            List<ActionInfo> actionInfos, String rd) {
369         Class<? extends TunnelTypeBase> tunnelType =
370                 VpnExtraRouteHelper.getTunnelType(nextHopManager.getItmManager(), adjacencyResult.getInterfaceName());
371         if (tunnelType == null) {
372             LOG.debug("Tunnel type not found for vrfEntry {}", vrfEntry);
373             return;
374         }
375         // TODO - For now have added routePath into adjacencyResult so that we know for which
376         // routePath this result is built for. If this is not possible construct a map which does
377         // the same.
378         String nextHopIp = adjacencyResult.getNextHopIp();
379         java.util.Optional<Uint32> optionalLabel = FibUtil.getLabelForNextHop(vrfEntry, nextHopIp);
380         if (!optionalLabel.isPresent()) {
381             LOG.warn("NextHopIp {} not found in vrfEntry {}", nextHopIp, vrfEntry);
382             return;
383         }
384         Uint32 label = optionalLabel.get();
385         Uint64 tunnelId = null;
386         Prefixes prefixInfo = null;
387         // FIXME vxlan vni bit set is not working properly with OVS.need to
388         // revisit
389         if (tunnelType.equals(TunnelTypeVxlan.class)) {
390             if (FibHelper.isControllerManagedNonSelfImportedRoute(RouteOrigin.value(vrfEntry.getOrigin()))) {
391                 prefixInfo = fibUtil.getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
392                 //For extra route, the prefixInfo is fetched from the primary adjacency
393                 if (prefixInfo == null) {
394                     prefixInfo = fibUtil.getPrefixToInterface(vpnId, adjacencyResult.getPrefix());
395                 }
396             } else {
397                 //Imported Route. Get Prefix Info from parent RD
398                 VpnInstanceOpDataEntry parentVpn =  fibUtil.getVpnInstance(vrfEntry.getParentVpnRd());
399                 prefixInfo = fibUtil.getPrefixToInterface(parentVpn.getVpnId(), adjacencyResult.getPrefix());
400             }
401             // Internet VPN VNI will be used as tun_id for NAT use-cases
402             if (Prefixes.PrefixCue.Nat.equals(prefixInfo.getPrefixCue())) {
403                 if (vrfEntry.getL3vni() != null && vrfEntry.getL3vni().toJava() != 0) {
404                     tunnelId = Uint64.valueOf(vrfEntry.getL3vni().longValue());
405                 }
406             } else {
407                 if (FibUtil.isVxlanNetwork(prefixInfo.getNetworkType())) {
408                     tunnelId = Uint64.valueOf(prefixInfo.getSegmentationId().longValue());
409                 } else {
410                     LOG.warn("Network is not of type VXLAN for prefix {}."
411                             + "Going with default Lport Tag.", prefixInfo.toString());
412                     tunnelId = Uint64.valueOf(label.longValue());
413                 }
414             }
415         } else {
416             tunnelId = Uint64.valueOf(label.longValue());
417         }
418         LOG.debug("adding set tunnel id action for label {}", label);
419         actionInfos.add(new ActionSetFieldTunnelId(tunnelId));
420         addRewriteDstMacAction(vpnId, vrfEntry, prefixInfo, actionInfos);
421     }
422
423     @Nullable
424     private InstanceIdentifier<Interface> getFirstAbsentInterfaceStateIid(List<AdjacencyResult> adjacencyResults) {
425         InstanceIdentifier<Interface> res = null;
426         for (AdjacencyResult adjacencyResult : adjacencyResults) {
427             String interfaceName = adjacencyResult.getInterfaceName();
428             if (null == fibUtil.getInterfaceStateFromOperDS(interfaceName)) {
429                 res = FibUtil.buildStateInterfaceId(interfaceName);
430                 break;
431             }
432         }
433
434         return res;
435     }
436
437     // Allow deprecated TransactionRunner calls for now
438     @SuppressWarnings("ForbidCertainMethod")
439     public void programRemoteFib(final Uint64 remoteDpnId, final Uint32 vpnId,
440                                  final VrfEntry vrfEntry, WriteTransaction tx, String rd,
441                                  List<AdjacencyResult> adjacencyResults,
442                                  @Nullable List<SubTransaction> subTxns) {
443         if (upgradeState.isUpgradeInProgress()) {
444             InstanceIdentifier<Interface> absentInterfaceStateIid = getFirstAbsentInterfaceStateIid(adjacencyResults);
445             if (absentInterfaceStateIid != null) {
446                 LOG.info("programRemoteFib: interface state for {} not yet present, waiting...",
447                          absentInterfaceStateIid);
448                 eventCallbacks.onAddOrUpdate(LogicalDatastoreType.OPERATIONAL,
449                     absentInterfaceStateIid,
450                     (before, after) -> {
451                         LOG.info("programRemoteFib: waited for and got interface state {}", absentInterfaceStateIid);
452                         LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(
453                             (wtx) -> programRemoteFib(remoteDpnId, vpnId, vrfEntry, wtx, rd, adjacencyResults, null)),
454                             LOG, "Failed to program remote FIB {}", absentInterfaceStateIid);
455                         return DataTreeEventCallbackRegistrar.NextAction.UNREGISTER;
456                     },
457                     Duration.of(15, ChronoUnit.MINUTES),
458                     (iid) -> {
459                         LOG.error("programRemoteFib: timed out waiting for {}", absentInterfaceStateIid);
460                         LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(
461                             (wtx) -> programRemoteFib(remoteDpnId, vpnId, vrfEntry, wtx, rd, adjacencyResults, null)),
462                             LOG, "Failed to program timed-out remote FIB {}", absentInterfaceStateIid);
463                     });
464                 return;
465             }
466         }
467
468         List<InstructionInfo> instructions = new ArrayList<>();
469         for (AdjacencyResult adjacencyResult : adjacencyResults) {
470             List<ActionInfo> actionInfos = new ArrayList<>();
471             String egressInterface = adjacencyResult.getInterfaceName();
472             if (FibUtil.isTunnelInterface(adjacencyResult)) {
473                 addTunnelInterfaceActions(adjacencyResult, vpnId, vrfEntry, actionInfos, rd);
474             } else {
475                 addRewriteDstMacAction(vpnId, vrfEntry, null, actionInfos);
476             }
477             List<ActionInfo> egressActions = nextHopManager.getEgressActionsForInterface(egressInterface,
478                     actionInfos.size(), true, vpnId, vrfEntry.getDestPrefix());
479             if (egressActions.isEmpty()) {
480                 LOG.error(
481                         "Failed to retrieve egress action for prefix {} route-paths {} interface {}. "
482                                 + "Aborting remote FIB entry creation.",
483                         vrfEntry.getDestPrefix(), new ArrayList<RoutePaths>(vrfEntry.nonnullRoutePaths().values()),
484                         egressInterface);
485                 return;
486             }
487             actionInfos.addAll(egressActions);
488             instructions.add(new InstructionApplyActions(actionInfos));
489         }
490         makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx, subTxns);
491     }
492
493     public boolean checkDpnDeleteFibEntry(VpnNexthop localNextHopInfo, Uint64 remoteDpnId, Uint32 vpnId,
494                                           VrfEntry vrfEntry, String rd,
495                                           WriteTransaction tx, @Nullable List<SubTransaction> subTxns) {
496         boolean isRemoteRoute = true;
497         if (localNextHopInfo != null) {
498             isRemoteRoute = !remoteDpnId.equals(localNextHopInfo.getDpnId());
499         }
500         if (isRemoteRoute) {
501             makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW, tx, subTxns);
502             LOG.debug("Successfully delete FIB entry: vrfEntry={}, vpnId={}", vrfEntry.getDestPrefix(), vpnId);
503             return true;
504         } else {
505             LOG.debug("Did not delete FIB entry: rd={}, vrfEntry={}, as it is local to dpnId={}",
506                     rd, vrfEntry.getDestPrefix(), remoteDpnId);
507             return false;
508         }
509     }
510
511     // Allow deprecated TransactionRunner calls for now
512     @SuppressWarnings("ForbidCertainMethod")
513     public void deleteRemoteRoute(@Nullable final Uint64 localDpnId, final Uint64 remoteDpnId,
514                                   final Uint32 vpnId, final VrfTablesKey vrfTableKey,
515                                   final VrfEntry vrfEntry, Optional<Routes> extraRouteOptional,
516                                   @Nullable WriteTransaction tx) {
517         if (tx == null) {
518             LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(
519                 newTx -> deleteRemoteRoute(localDpnId, remoteDpnId, vpnId, vrfTableKey, vrfEntry,
520                         extraRouteOptional, newTx)), LOG, "Error deleting remote route");
521             return;
522         }
523
524         LOG.debug("deleting remote route: prefix={}, vpnId={} localDpnId {} remoteDpnId {}",
525                 vrfEntry.getDestPrefix(), vpnId, localDpnId, remoteDpnId);
526         String rd = vrfTableKey.getRouteDistinguisher();
527
528         if (localDpnId != null && !Uint64.ZERO.equals(localDpnId)) {
529             // localDpnId is not known when clean up happens for last vm for a vpn on a dpn
530             if (extraRouteOptional.isPresent()) {
531                 nextHopManager.deleteLoadBalancingNextHop(vpnId, remoteDpnId, vrfEntry.getDestPrefix());
532             }
533             makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW, tx, null);
534             LOG.debug("Successfully delete FIB entry: vrfEntry={}, vpnId={}", vrfEntry.getDestPrefix(), vpnId);
535             return;
536         }
537
538         // below two reads are kept as is, until best way is found to identify dpnID
539         VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
540         if (extraRouteOptional.isPresent()) {
541             nextHopManager.deleteLoadBalancingNextHop(vpnId, remoteDpnId, vrfEntry.getDestPrefix());
542         } else {
543             checkDpnDeleteFibEntry(localNextHopInfo, remoteDpnId, vpnId, vrfEntry, rd, tx, null);
544         }
545     }
546
547     public static InstanceIdentifier<Routes> getVpnToExtrarouteIdentifier(String vpnName, String vrfId,
548                                                                     String ipPrefix) {
549         return InstanceIdentifier.builder(VpnToExtraroutes.class)
550                 .child(Vpn.class, new VpnKey(vpnName)).child(ExtraRoutes.class,
551                         new ExtraRoutesKey(vrfId)).child(Routes.class, new RoutesKey(ipPrefix)).build();
552     }
553
554     @Nullable
555     public Routes getVpnToExtraroute(Uint32 vpnId, String vpnRd, String destPrefix) {
556         String optVpnName = fibUtil.getVpnNameFromId(vpnId);
557         if (optVpnName != null) {
558             InstanceIdentifier<Routes> vpnExtraRoutesId = getVpnToExtrarouteIdentifier(optVpnName, vpnRd, destPrefix);
559             try {
560                 return SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL,
561                         vpnExtraRoutesId).orElse(null);
562             } catch (ExecutionException | InterruptedException e) {
563                 LOG.error("getVpnToExtraroute: Exception while reading vpn-to-extraroute DS for the prefix {} "
564                         + "rd {} vpnId {} ", destPrefix, vpnRd, vpnId, e);
565             }
566         }
567         return null;
568     }
569
570     public FlowEntity buildL3vpnGatewayFlow(Uint64 dpId, String gwMacAddress, Uint32 vpnId) {
571         List<MatchInfo> mkMatches = new ArrayList<>();
572         mkMatches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId.longValue()),
573             MetaDataUtil.METADATA_MASK_VRFID));
574         mkMatches.add(new MatchEthernetDestination(new MacAddress(gwMacAddress)));
575         List<InstructionInfo> mkInstructions = new ArrayList<>();
576         mkInstructions.add(new InstructionGotoTable(NwConstants.L3_FIB_TABLE));
577         String flowId = FibUtil.getL3VpnGatewayFlowRef(NwConstants.L3_GW_MAC_TABLE, dpId, vpnId, gwMacAddress);
578         return MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_GW_MAC_TABLE,
579                 flowId, 20, flowId, 0, 0, NwConstants.COOKIE_L3_GW_MAC_TABLE, mkMatches, mkInstructions);
580     }
581
582     public void installPingResponderFlowEntry(Uint64 dpnId, Uint32 vpnId, String routerInternalIp,
583                                               MacAddress routerMac, Uint32 label, int addOrRemove) {
584
585         List<MatchInfo> matches = new ArrayList<>();
586         matches.add(MatchIpProtocol.ICMP);
587         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId.longValue()),
588             MetaDataUtil.METADATA_MASK_VRFID));
589         matches.add(new MatchIcmpv4((short) 8, (short) 0));
590         matches.add(MatchEthernetType.IPV4);
591         matches.add(new MatchIpv4Destination(routerInternalIp, "32"));
592
593         List<ActionInfo> actionsInfos = new ArrayList<>();
594
595         // Set Eth Src and Eth Dst
596         actionsInfos.add(new ActionMoveSourceDestinationEth());
597         actionsInfos.add(new ActionSetFieldEthernetSource(routerMac));
598
599         // Move Ip Src to Ip Dst
600         actionsInfos.add(new ActionMoveSourceDestinationIp());
601         actionsInfos.add(new ActionSetSourceIp(routerInternalIp, "32"));
602
603         // Set the ICMP type to 0 (echo reply)
604         actionsInfos.add(new ActionSetIcmpType((short) 0));
605
606         actionsInfos.add(new ActionNxLoadInPort(Uint64.ZERO));
607
608         actionsInfos.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
609
610         List<InstructionInfo> instructions = new ArrayList<>();
611
612         instructions.add(new InstructionApplyActions(actionsInfos));
613
614         int priority = FibConstants.DEFAULT_FIB_FLOW_PRIORITY + FibConstants.DEFAULT_PREFIX_LENGTH;
615         String flowRef = FibUtil.getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, label, priority);
616
617         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef,
618                 0, 0, NwConstants.COOKIE_VM_FIB_TABLE, matches, instructions);
619
620         if (addOrRemove == NwConstants.ADD_FLOW) {
621             mdsalManager.syncInstallFlow(flowEntity);
622         } else {
623             mdsalManager.syncRemoveFlow(flowEntity);
624         }
625     }
626 }