2 * Copyright © 2017 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.netvirt.fibmanager;
10 import static java.util.stream.Collectors.toList;
11 import static org.opendaylight.genius.mdsalutil.NWUtil.isIpv4Address;
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.ListenableFutures;
60 import org.opendaylight.infrautils.utils.concurrent.LoggingFutures;
61 import org.opendaylight.mdsal.binding.api.DataBroker;
62 import org.opendaylight.mdsal.binding.api.WriteTransaction;
63 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
64 import org.opendaylight.netvirt.fibmanager.NexthopManager.AdjacencyResult;
65 import org.opendaylight.netvirt.fibmanager.api.FibHelper;
66 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
67 import org.opendaylight.netvirt.vpnmanager.api.VpnExtraRouteHelper;
68 import org.opendaylight.serviceutils.upgrade.UpgradeState;
69 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
70 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeBase;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeMplsOverGre;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.TunnelTypeVxlan;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.fibentries.VrfTablesKey;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentries.VrfEntry;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fibmanager.rev150330.vrfentrybase.RoutePaths;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3nexthop.rev150409.l3nexthop.vpnnexthops.VpnNexthop;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.VpnToExtraroutes;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.prefix.to._interface.vpn.ids.Prefixes;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.instance.op.data.VpnInstanceOpDataEntry;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.Vpn;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.VpnKey;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.vpn.ExtraRoutes;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.vpn.ExtraRoutesKey;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.vpn.extra.routes.Routes;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn.to.extraroutes.vpn.extra.routes.RoutesKey;
95 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
96 import org.opendaylight.yangtools.yang.common.Uint32;
97 import org.opendaylight.yangtools.yang.common.Uint64;
98 import org.slf4j.Logger;
99 import org.slf4j.LoggerFactory;
102 public class BaseVrfEntryHandler implements AutoCloseable {
104 private static final Logger LOG = LoggerFactory.getLogger(BaseVrfEntryHandler.class);
105 private static final Uint64 COOKIE_VM_FIB_TABLE = Uint64.valueOf("8000003", 16).intern();
106 private static final int DEFAULT_FIB_FLOW_PRIORITY = 10;
108 private final DataBroker dataBroker;
109 private final ManagedNewTransactionRunner txRunner;
110 private final NexthopManager nextHopManager;
111 private final IMdsalApiManager mdsalManager;
112 private final FibUtil fibUtil;
113 private final UpgradeState upgradeState;
114 private final DataTreeEventCallbackRegistrar eventCallbacks;
117 public BaseVrfEntryHandler(final DataBroker dataBroker,
118 final NexthopManager nexthopManager,
119 final IMdsalApiManager mdsalManager,
120 final FibUtil fibUtil,
121 final UpgradeState upgradeState,
122 final DataTreeEventCallbackRegistrar eventCallbacks) {
123 this.dataBroker = dataBroker;
124 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
125 this.nextHopManager = nexthopManager;
126 this.mdsalManager = mdsalManager;
127 this.fibUtil = fibUtil;
128 this.upgradeState = upgradeState;
129 this.eventCallbacks = eventCallbacks;
133 public void close() {
134 LOG.info("{} closed", getClass().getSimpleName());
137 protected FibUtil getFibUtil() {
141 protected NexthopManager getNextHopManager() {
142 return nextHopManager;
145 private void addAdjacencyResultToList(List<AdjacencyResult> adjacencyList, AdjacencyResult adjacencyResult) {
146 if (adjacencyResult != null && !adjacencyList.contains(adjacencyResult)) {
147 adjacencyList.add(adjacencyResult);
151 protected void deleteLocalAdjacency(final Uint64 dpId, final Uint32 vpnId, final String ipAddress,
152 final String ipPrefixAddress) {
153 LOG.trace("deleteLocalAdjacency called with dpid {}, vpnId{}, primaryIpAddress {} currIpPrefix {}",
154 dpId, vpnId, ipAddress, ipPrefixAddress);
156 nextHopManager.removeLocalNextHop(dpId, vpnId, ipAddress, ipPrefixAddress);
157 } catch (NullPointerException e) {
158 // FIXME: NPEs should not be caught but rather their root cause should be eliminated
159 LOG.trace("Failed to remove nexthop", e);
164 protected List<AdjacencyResult> resolveAdjacency(final Uint64 remoteDpnId, final Uint32 vpnId,
165 final VrfEntry vrfEntry, String rd) {
166 List<RoutePaths> routePaths = new ArrayList<RoutePaths>(vrfEntry.nonnullRoutePaths().values());
167 FibHelper.sortIpAddress(routePaths);
168 List<AdjacencyResult> adjacencyList = new ArrayList<>();
169 List<String> prefixIpList;
170 LOG.trace("resolveAdjacency called with remotedDpnId {}, vpnId{}, VrfEntry {}",
171 remoteDpnId, vpnId, vrfEntry);
172 final Class<? extends TunnelTypeBase> tunnelType;
174 if (RouteOrigin.value(vrfEntry.getOrigin()) != RouteOrigin.BGP) {
175 tunnelType = TunnelTypeVxlan.class;
176 List<String> usedRds = VpnExtraRouteHelper.getUsedRds(dataBroker, vpnId, vrfEntry.getDestPrefix());
177 List<Routes> vpnExtraRoutes = VpnExtraRouteHelper.getAllVpnExtraRoutes(dataBroker,
178 fibUtil.getVpnNameFromId(vpnId), usedRds, vrfEntry.getDestPrefix());
179 if (vpnExtraRoutes.isEmpty()) {
180 Prefixes prefixInfo = fibUtil.getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
181 /* We don't want to provide an adjacencyList for
182 * (1) an extra-route-prefix or,
183 * (2) for a local route without prefix-to-interface.
184 * Allow only self-imported routes in such cases */
185 if (prefixInfo == null && FibHelper
186 .isControllerManagedNonSelfImportedRoute(RouteOrigin.value(vrfEntry.getOrigin()))) {
187 LOG.debug("The prefix {} in rd {} for vpn {} does not have a valid extra-route or"
188 + " prefix-to-interface entry in the data-store", vrfEntry.getDestPrefix(), rd, vpnId);
189 return adjacencyList;
191 prefixIpList = Collections.singletonList(vrfEntry.getDestPrefix());
193 List<String> prefixIpListLocal = new ArrayList<>();
194 vpnExtraRoutes.stream().filter(route -> route.getNexthopIpList() != null).forEach(
195 route -> route.getNexthopIpList().forEach(extraRouteIp -> {
197 if (isIpv4Address(extraRouteIp)) {
198 ipPrefix = extraRouteIp + NwConstants.IPV4PREFIX;
200 ipPrefix = extraRouteIp + NwConstants.IPV6PREFIX;
202 prefixIpListLocal.add(ipPrefix);
204 prefixIpList = prefixIpListLocal;
207 prefixIpList = Collections.singletonList(vrfEntry.getDestPrefix());
208 if (vrfEntry.getEncapType() == VrfEntry.EncapType.Mplsgre) {
209 tunnelType = TunnelTypeMplsOverGre.class;
211 tunnelType = TunnelTypeVxlan.class;
215 for (String prefixIp : prefixIpList) {
216 if (routePaths == null || routePaths.isEmpty()) {
217 LOG.trace("Processing Destination IP {} without NextHop IP", prefixIp);
218 AdjacencyResult adjacencyResult = nextHopManager.getRemoteNextHopPointer(remoteDpnId, vpnId,
219 prefixIp, null, tunnelType);
220 addAdjacencyResultToList(adjacencyList, adjacencyResult);
223 adjacencyList.addAll(routePaths.stream()
225 LOG.debug("NextHop IP for destination {} is {}", prefixIp,
226 routePath.getNexthopAddress());
227 return nextHopManager.getRemoteNextHopPointer(remoteDpnId, vpnId,
228 prefixIp, routePath.getNexthopAddress(), tunnelType);
230 .filter(adjacencyResult -> adjacencyResult != null && !adjacencyList.contains(adjacencyResult))
234 } catch (NullPointerException e) {
235 // FIXME: NPEs should not be caught but rather their root cause should be eliminated
236 LOG.trace("Failed to remove adjacency", e);
238 return adjacencyList;
241 // Allow deprecated TransactionRunner calls for now
242 @SuppressWarnings("ForbidCertainMethod")
243 protected void makeConnectedRoute(Uint64 dpId, Uint32 vpnId, VrfEntry vrfEntry, String rd,
244 @Nullable List<InstructionInfo> instructions, int addOrRemove,
245 WriteTransaction tx, @Nullable List<SubTransaction> subTxns) {
247 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(
248 newTx -> makeConnectedRoute(dpId, vpnId, vrfEntry, rd, instructions, addOrRemove, newTx, subTxns)),
249 LOG, "Error making connected route");
253 LOG.trace("makeConnectedRoute: vrfEntry {}", vrfEntry);
254 String[] values = vrfEntry.getDestPrefix().split("/");
255 String ipAddress = values[0];
256 int prefixLength = values.length == 1 ? 0 : Integer.parseInt(values[1]);
257 if (addOrRemove == NwConstants.ADD_FLOW) {
258 LOG.debug("Adding route to DPN {} for rd {} prefix {} ", dpId, rd, vrfEntry.getDestPrefix());
260 LOG.debug("Removing route from DPN {} for rd {} prefix {}", dpId, rd, vrfEntry.getDestPrefix());
262 InetAddress destPrefix;
264 destPrefix = InetAddress.getByName(ipAddress);
265 } catch (UnknownHostException e) {
266 LOG.error("Failed to get destPrefix for prefix {} rd {} VpnId {} DPN {}",
267 vrfEntry.getDestPrefix(), rd, vpnId, dpId, e);
271 List<MatchInfo> matches = new ArrayList<>();
273 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId.longValue()),
274 MetaDataUtil.METADATA_MASK_VRFID));
276 if (destPrefix instanceof Inet4Address) {
277 matches.add(MatchEthernetType.IPV4);
278 if (prefixLength != 0) {
279 matches.add(new MatchIpv4Destination(destPrefix.getHostAddress(), Integer.toString(prefixLength)));
282 matches.add(MatchEthernetType.IPV6);
283 if (prefixLength != 0) {
284 matches.add(new MatchIpv6Destination(destPrefix.getHostAddress() + "/" + prefixLength));
288 int priority = DEFAULT_FIB_FLOW_PRIORITY + prefixLength;
289 String flowRef = FibUtil.getFlowRef(dpId, NwConstants.L3_FIB_TABLE, rd, priority, destPrefix);
290 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_FIB_TABLE, flowRef, priority,
292 COOKIE_VM_FIB_TABLE, matches, instructions);
293 Flow flow = flowEntity.getFlowBuilder().build();
294 String flowId = flowEntity.getFlowId();
295 FlowKey flowKey = new FlowKey(new FlowId(flowId));
296 Node nodeDpn = FibUtil.buildDpnNode(dpId);
298 InstanceIdentifier<Flow> flowInstanceId = InstanceIdentifier.builder(Nodes.class)
299 .child(Node.class, nodeDpn.key()).augmentation(FlowCapableNode.class)
300 .child(Table.class, new TableKey(flow.getTableId())).child(Flow.class, flowKey).build();
302 if (RouteOrigin.value(vrfEntry.getOrigin()) == RouteOrigin.BGP) {
303 SubTransaction subTransaction = new SubTransactionImpl();
304 if (addOrRemove == NwConstants.ADD_FLOW) {
305 subTransaction.setInstanceIdentifier(flowInstanceId);
306 subTransaction.setInstance(flow);
307 subTransaction.setAction(SubTransaction.CREATE);
309 subTransaction.setInstanceIdentifier(flowInstanceId);
310 subTransaction.setAction(SubTransaction.DELETE);
312 subTxns.add(subTransaction);
315 if (addOrRemove == NwConstants.ADD_FLOW) {
316 tx.mergeParentStructurePut(LogicalDatastoreType.CONFIGURATION, flowInstanceId, flow);
318 tx.delete(LogicalDatastoreType.CONFIGURATION, flowInstanceId);
322 protected void addRewriteDstMacAction(Uint32 vpnId, VrfEntry vrfEntry, @Nullable Prefixes prefixInfo,
323 List<ActionInfo> actionInfos) {
324 if (vrfEntry.getMac() != null) {
325 actionInfos.add(new ActionSetFieldEthernetDestination(actionInfos.size(),
326 new MacAddress(vrfEntry.getMac())));
329 if (prefixInfo == null) {
330 prefixInfo = fibUtil.getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
331 //Checking PrefixtoInterface again as it is populated later in some cases
332 if (prefixInfo == null) {
333 LOG.debug("No prefix info found for prefix {}", vrfEntry.getDestPrefix());
337 String ipPrefix = prefixInfo.getIpAddress();
338 String ifName = prefixInfo.getVpnInterfaceName();
339 if (ifName == null) {
340 LOG.debug("Failed to get VPN interface for prefix {}", ipPrefix);
343 String vpnName = fibUtil.getVpnNameFromId(vpnId);
344 if (vpnName == null) {
345 LOG.debug("Failed to get VPN name for vpnId {}", vpnId);
348 String macAddress = null;
349 if (vrfEntry.getParentVpnRd() != null) {
350 // Handling iRT/eRT use-case for missing destination mac address in Remote FIB flow
351 Optional<VpnInstanceOpDataEntry> vpnInstance = fibUtil.getVpnInstanceOpData(vrfEntry.getParentVpnRd());
352 if (vpnInstance.isPresent()) {
353 macAddress = fibUtil.getMacAddressFromPrefix(ifName, vpnInstance.get().getVpnInstanceName(), ipPrefix);
355 LOG.warn("VpnInstance missing for Parent Rd {} value for prefix {}", vrfEntry.getParentVpnRd(),
356 vrfEntry.getDestPrefix());
359 macAddress = fibUtil.getMacAddressFromPrefix(ifName, vpnName, ipPrefix);
361 if (macAddress == null) {
362 LOG.warn("No MAC address found for VPN interface {} prefix {}", ifName, ipPrefix);
365 actionInfos.add(new ActionSetFieldEthernetDestination(actionInfos.size(), new MacAddress(macAddress)));
368 protected void addTunnelInterfaceActions(AdjacencyResult adjacencyResult, Uint32 vpnId, VrfEntry vrfEntry,
369 List<ActionInfo> actionInfos, String rd) {
370 Class<? extends TunnelTypeBase> tunnelType =
371 VpnExtraRouteHelper.getTunnelType(nextHopManager.getItmManager(), adjacencyResult.getInterfaceName());
372 if (tunnelType == null) {
373 LOG.debug("Tunnel type not found for vrfEntry {}", vrfEntry);
376 // TODO - For now have added routePath into adjacencyResult so that we know for which
377 // routePath this result is built for. If this is not possible construct a map which does
379 String nextHopIp = adjacencyResult.getNextHopIp();
380 java.util.Optional<Uint32> optionalLabel = FibUtil.getLabelForNextHop(vrfEntry, nextHopIp);
381 if (!optionalLabel.isPresent()) {
382 LOG.warn("NextHopIp {} not found in vrfEntry {}", nextHopIp, vrfEntry);
385 Uint32 label = optionalLabel.get();
386 Uint64 tunnelId = null;
387 Prefixes prefixInfo = null;
388 // FIXME vxlan vni bit set is not working properly with OVS.need to
390 if (tunnelType.equals(TunnelTypeVxlan.class)) {
391 if (FibHelper.isControllerManagedNonSelfImportedRoute(RouteOrigin.value(vrfEntry.getOrigin()))) {
392 prefixInfo = fibUtil.getPrefixToInterface(vpnId, vrfEntry.getDestPrefix());
393 //For extra route, the prefixInfo is fetched from the primary adjacency
394 if (prefixInfo == null) {
395 prefixInfo = fibUtil.getPrefixToInterface(vpnId, adjacencyResult.getPrefix());
398 //Imported Route. Get Prefix Info from parent RD
399 VpnInstanceOpDataEntry parentVpn = fibUtil.getVpnInstance(vrfEntry.getParentVpnRd());
400 prefixInfo = fibUtil.getPrefixToInterface(parentVpn.getVpnId(), adjacencyResult.getPrefix());
402 // Internet VPN VNI will be used as tun_id for NAT use-cases
403 if (Prefixes.PrefixCue.Nat.equals(prefixInfo.getPrefixCue())) {
404 if (vrfEntry.getL3vni() != null && vrfEntry.getL3vni().toJava() != 0) {
405 tunnelId = Uint64.valueOf(vrfEntry.getL3vni().longValue());
408 if (FibUtil.isVxlanNetwork(prefixInfo.getNetworkType())) {
409 tunnelId = Uint64.valueOf(prefixInfo.getSegmentationId().longValue());
411 LOG.warn("Network is not of type VXLAN for prefix {}."
412 + "Going with default Lport Tag.", prefixInfo.toString());
413 tunnelId = Uint64.valueOf(label.longValue());
417 tunnelId = Uint64.valueOf(label.longValue());
419 LOG.debug("adding set tunnel id action for label {}", label);
420 actionInfos.add(new ActionSetFieldTunnelId(tunnelId));
421 addRewriteDstMacAction(vpnId, vrfEntry, prefixInfo, actionInfos);
425 private InstanceIdentifier<Interface> getFirstAbsentInterfaceStateIid(List<AdjacencyResult> adjacencyResults) {
426 InstanceIdentifier<Interface> res = null;
427 for (AdjacencyResult adjacencyResult : adjacencyResults) {
428 String interfaceName = adjacencyResult.getInterfaceName();
429 if (null == fibUtil.getInterfaceStateFromOperDS(interfaceName)) {
430 res = FibUtil.buildStateInterfaceId(interfaceName);
438 // Allow deprecated TransactionRunner calls for now
439 @SuppressWarnings("ForbidCertainMethod")
440 public void programRemoteFib(final Uint64 remoteDpnId, final Uint32 vpnId,
441 final VrfEntry vrfEntry, WriteTransaction tx, String rd,
442 List<AdjacencyResult> adjacencyResults,
443 @Nullable List<SubTransaction> subTxns) {
444 if (upgradeState.isUpgradeInProgress()) {
445 InstanceIdentifier<Interface> absentInterfaceStateIid = getFirstAbsentInterfaceStateIid(adjacencyResults);
446 if (absentInterfaceStateIid != null) {
447 LOG.info("programRemoteFib: interface state for {} not yet present, waiting...",
448 absentInterfaceStateIid);
449 eventCallbacks.onAddOrUpdate(LogicalDatastoreType.OPERATIONAL,
450 absentInterfaceStateIid,
452 LOG.info("programRemoteFib: waited for and got interface state {}", absentInterfaceStateIid);
453 LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(
454 (wtx) -> programRemoteFib(remoteDpnId, vpnId, vrfEntry, wtx, rd, adjacencyResults, null)),
455 LOG, "Failed to program remote FIB {}", absentInterfaceStateIid);
456 return DataTreeEventCallbackRegistrar.NextAction.UNREGISTER;
458 Duration.of(15, ChronoUnit.MINUTES),
460 LOG.error("programRemoteFib: timed out waiting for {}", absentInterfaceStateIid);
461 LoggingFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(
462 (wtx) -> programRemoteFib(remoteDpnId, vpnId, vrfEntry, wtx, rd, adjacencyResults, null)),
463 LOG, "Failed to program timed-out remote FIB {}", absentInterfaceStateIid);
469 List<InstructionInfo> instructions = new ArrayList<>();
470 for (AdjacencyResult adjacencyResult : adjacencyResults) {
471 List<ActionInfo> actionInfos = new ArrayList<>();
472 String egressInterface = adjacencyResult.getInterfaceName();
473 if (FibUtil.isTunnelInterface(adjacencyResult)) {
474 addTunnelInterfaceActions(adjacencyResult, vpnId, vrfEntry, actionInfos, rd);
476 addRewriteDstMacAction(vpnId, vrfEntry, null, actionInfos);
478 List<ActionInfo> egressActions = nextHopManager.getEgressActionsForInterface(egressInterface,
479 actionInfos.size(), true, vpnId, vrfEntry.getDestPrefix());
480 if (egressActions.isEmpty()) {
482 "Failed to retrieve egress action for prefix {} route-paths {} interface {}. "
483 + "Aborting remote FIB entry creation.",
484 vrfEntry.getDestPrefix(), new ArrayList<RoutePaths>(vrfEntry.nonnullRoutePaths().values()),
488 actionInfos.addAll(egressActions);
489 instructions.add(new InstructionApplyActions(actionInfos));
491 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, instructions, NwConstants.ADD_FLOW, tx, subTxns);
494 public boolean checkDpnDeleteFibEntry(VpnNexthop localNextHopInfo, Uint64 remoteDpnId, Uint32 vpnId,
495 VrfEntry vrfEntry, String rd,
496 WriteTransaction tx, @Nullable List<SubTransaction> subTxns) {
497 boolean isRemoteRoute = true;
498 if (localNextHopInfo != null) {
499 isRemoteRoute = !remoteDpnId.equals(localNextHopInfo.getDpnId());
502 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW, tx, subTxns);
503 LOG.debug("Successfully delete FIB entry: vrfEntry={}, vpnId={}", vrfEntry.getDestPrefix(), vpnId);
506 LOG.debug("Did not delete FIB entry: rd={}, vrfEntry={}, as it is local to dpnId={}",
507 rd, vrfEntry.getDestPrefix(), remoteDpnId);
512 // Allow deprecated TransactionRunner calls for now
513 @SuppressWarnings("ForbidCertainMethod")
514 public void deleteRemoteRoute(@Nullable final Uint64 localDpnId, final Uint64 remoteDpnId,
515 final Uint32 vpnId, final VrfTablesKey vrfTableKey,
516 final VrfEntry vrfEntry, Optional<Routes> extraRouteOptional,
517 @Nullable WriteTransaction tx) {
519 ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(
520 newTx -> deleteRemoteRoute(localDpnId, remoteDpnId, vpnId, vrfTableKey, vrfEntry,
521 extraRouteOptional, newTx)), LOG, "Error deleting remote route");
525 LOG.debug("deleting remote route: prefix={}, vpnId={} localDpnId {} remoteDpnId {}",
526 vrfEntry.getDestPrefix(), vpnId, localDpnId, remoteDpnId);
527 String rd = vrfTableKey.getRouteDistinguisher();
529 if (localDpnId != null && !Uint64.ZERO.equals(localDpnId)) {
530 // localDpnId is not known when clean up happens for last vm for a vpn on a dpn
531 if (extraRouteOptional.isPresent()) {
532 nextHopManager.deleteLoadBalancingNextHop(vpnId, remoteDpnId, vrfEntry.getDestPrefix());
534 makeConnectedRoute(remoteDpnId, vpnId, vrfEntry, rd, null, NwConstants.DEL_FLOW, tx, null);
535 LOG.debug("Successfully delete FIB entry: vrfEntry={}, vpnId={}", vrfEntry.getDestPrefix(), vpnId);
539 // below two reads are kept as is, until best way is found to identify dpnID
540 VpnNexthop localNextHopInfo = nextHopManager.getVpnNexthop(vpnId, vrfEntry.getDestPrefix());
541 if (extraRouteOptional.isPresent()) {
542 nextHopManager.deleteLoadBalancingNextHop(vpnId, remoteDpnId, vrfEntry.getDestPrefix());
544 checkDpnDeleteFibEntry(localNextHopInfo, remoteDpnId, vpnId, vrfEntry, rd, tx, null);
548 public static InstanceIdentifier<Routes> getVpnToExtrarouteIdentifier(String vpnName, String vrfId,
550 return InstanceIdentifier.builder(VpnToExtraroutes.class)
551 .child(Vpn.class, new VpnKey(vpnName)).child(ExtraRoutes.class,
552 new ExtraRoutesKey(vrfId)).child(Routes.class, new RoutesKey(ipPrefix)).build();
556 public Routes getVpnToExtraroute(Uint32 vpnId, String vpnRd, String destPrefix) {
557 String optVpnName = fibUtil.getVpnNameFromId(vpnId);
558 if (optVpnName != null) {
559 InstanceIdentifier<Routes> vpnExtraRoutesId = getVpnToExtrarouteIdentifier(optVpnName, vpnRd, destPrefix);
561 return SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL,
562 vpnExtraRoutesId).orElse(null);
563 } catch (ExecutionException | InterruptedException e) {
564 LOG.error("getVpnToExtraroute: Exception while reading vpn-to-extraroute DS for the prefix {} "
565 + "rd {} vpnId {} ", destPrefix, vpnRd, vpnId, e);
571 public FlowEntity buildL3vpnGatewayFlow(Uint64 dpId, String gwMacAddress, Uint32 vpnId) {
572 List<MatchInfo> mkMatches = new ArrayList<>();
573 mkMatches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId.longValue()),
574 MetaDataUtil.METADATA_MASK_VRFID));
575 mkMatches.add(new MatchEthernetDestination(new MacAddress(gwMacAddress)));
576 List<InstructionInfo> mkInstructions = new ArrayList<>();
577 mkInstructions.add(new InstructionGotoTable(NwConstants.L3_FIB_TABLE));
578 String flowId = FibUtil.getL3VpnGatewayFlowRef(NwConstants.L3_GW_MAC_TABLE, dpId, vpnId, gwMacAddress);
579 return MDSALUtil.buildFlowEntity(dpId, NwConstants.L3_GW_MAC_TABLE,
580 flowId, 20, flowId, 0, 0, NwConstants.COOKIE_L3_GW_MAC_TABLE, mkMatches, mkInstructions);
583 public void installPingResponderFlowEntry(Uint64 dpnId, Uint32 vpnId, String routerInternalIp,
584 MacAddress routerMac, Uint32 label, int addOrRemove) {
586 List<MatchInfo> matches = new ArrayList<>();
587 matches.add(MatchIpProtocol.ICMP);
588 matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId.longValue()),
589 MetaDataUtil.METADATA_MASK_VRFID));
590 matches.add(new MatchIcmpv4((short) 8, (short) 0));
591 matches.add(MatchEthernetType.IPV4);
592 matches.add(new MatchIpv4Destination(routerInternalIp, "32"));
594 List<ActionInfo> actionsInfos = new ArrayList<>();
596 // Set Eth Src and Eth Dst
597 actionsInfos.add(new ActionMoveSourceDestinationEth());
598 actionsInfos.add(new ActionSetFieldEthernetSource(routerMac));
600 // Move Ip Src to Ip Dst
601 actionsInfos.add(new ActionMoveSourceDestinationIp());
602 actionsInfos.add(new ActionSetSourceIp(routerInternalIp, "32"));
604 // Set the ICMP type to 0 (echo reply)
605 actionsInfos.add(new ActionSetIcmpType((short) 0));
607 actionsInfos.add(new ActionNxLoadInPort(Uint64.ZERO));
609 actionsInfos.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
611 List<InstructionInfo> instructions = new ArrayList<>();
613 instructions.add(new InstructionApplyActions(actionsInfos));
615 int priority = FibConstants.DEFAULT_FIB_FLOW_PRIORITY + FibConstants.DEFAULT_PREFIX_LENGTH;
616 String flowRef = FibUtil.getFlowRef(dpnId, NwConstants.L3_FIB_TABLE, label, priority);
618 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.L3_FIB_TABLE, flowRef, priority, flowRef,
619 0, 0, NwConstants.COOKIE_VM_FIB_TABLE, matches, instructions);
621 if (addOrRemove == NwConstants.ADD_FLOW) {
622 mdsalManager.syncInstallFlow(flowEntity);
624 mdsalManager.syncRemoveFlow(flowEntity);