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