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