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