2 * Copyright © 2016, 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.natservice.internal;
10 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
11 import static org.opendaylight.netvirt.natservice.internal.NatUtil.buildfloatingIpIdToPortMappingIdentifier;
13 import com.google.common.util.concurrent.FutureCallback;
14 import com.google.common.util.concurrent.Futures;
15 import com.google.common.util.concurrent.JdkFutureAdapters;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import com.google.common.util.concurrent.MoreExecutors;
18 import java.math.BigInteger;
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.HashMap;
22 import java.util.List;
24 import java.util.Optional;
25 import java.util.concurrent.ExecutionException;
26 import java.util.concurrent.Future;
27 import javax.inject.Inject;
28 import javax.inject.Singleton;
29 import org.eclipse.jdt.annotation.NonNull;
30 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
31 import org.opendaylight.genius.infra.Datastore.Configuration;
32 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
33 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
34 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
35 import org.opendaylight.genius.infra.TypedWriteTransaction;
36 import org.opendaylight.genius.mdsalutil.ActionInfo;
37 import org.opendaylight.genius.mdsalutil.MDSALUtil;
38 import org.opendaylight.genius.mdsalutil.MatchInfo;
39 import org.opendaylight.genius.mdsalutil.NwConstants;
40 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
41 import org.opendaylight.genius.mdsalutil.actions.ActionPopMpls;
42 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetDestination;
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.MatchEthernetType;
47 import org.opendaylight.genius.mdsalutil.matches.MatchMplsLabel;
48 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
49 import org.opendaylight.infrautils.utils.concurrent.JdkFutures;
50 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
51 import org.opendaylight.mdsal.binding.api.DataBroker;
52 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
53 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
54 import org.opendaylight.netvirt.elanmanager.api.IElanService;
55 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
56 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
57 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
59 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder;
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.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
62 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
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.flow.types.rev131026.instruction.list.Instruction;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilService;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpRequestInput;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpRequestInputBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.interfaces.InterfaceAddress;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.interfaces.InterfaceAddressBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInput;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInputBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryOutput;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInput;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInputBuilder;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryOutput;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets.Subnets;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.port.info.FloatingIpIdToPortMapping;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelInput;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelInputBuilder;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelOutput;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelInput;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelInputBuilder;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelOutput;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.VpnRpcService;
91 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
92 import org.opendaylight.yangtools.yang.common.RpcResult;
93 import org.opendaylight.yangtools.yang.common.Uint32;
94 import org.opendaylight.yangtools.yang.common.Uint64;
95 import org.slf4j.Logger;
96 import org.slf4j.LoggerFactory;
99 public class VpnFloatingIpHandler implements FloatingIPHandler {
100 private static final Logger LOG = LoggerFactory.getLogger(VpnFloatingIpHandler.class);
101 private static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
102 private static final String FLOWID_PREFIX = "NAT.";
104 private final DataBroker dataBroker;
105 private final ManagedNewTransactionRunner txRunner;
106 private final IMdsalApiManager mdsalManager;
107 private final VpnRpcService vpnService;
108 private final IBgpManager bgpManager;
109 private final FibRpcService fibService;
110 private final IVpnManager vpnManager;
111 private final IFibManager fibManager;
112 private final OdlArputilService arpUtilService;
113 private final IElanService elanService;
114 private final EvpnDnatFlowProgrammer evpnDnatFlowProgrammer;
115 private final NatServiceCounters natServiceCounters;
116 private final NatOverVxlanUtil natOverVxlanUtil;
119 public VpnFloatingIpHandler(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
120 final VpnRpcService vpnService,
121 final IBgpManager bgpManager,
122 final FibRpcService fibService,
123 final IFibManager fibManager,
124 final OdlArputilService arputilService,
125 final IVpnManager vpnManager,
126 final IElanService elanService,
127 final EvpnDnatFlowProgrammer evpnDnatFlowProgrammer,
128 final NatOverVxlanUtil natOverVxlanUtil,
129 NatServiceCounters natServiceCounters) {
130 this.dataBroker = dataBroker;
131 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
132 this.mdsalManager = mdsalManager;
133 this.vpnService = vpnService;
134 this.bgpManager = bgpManager;
135 this.fibService = fibService;
136 this.fibManager = fibManager;
137 this.arpUtilService = arputilService;
138 this.vpnManager = vpnManager;
139 this.elanService = elanService;
140 this.evpnDnatFlowProgrammer = evpnDnatFlowProgrammer;
141 this.natServiceCounters = natServiceCounters;
142 this.natOverVxlanUtil = natOverVxlanUtil;
146 public void onAddFloatingIp(final Uint64 dpnId, final String routerUuid, final Uint32 routerId,
147 final Uuid networkId, final String interfaceName,
148 final InternalToExternalPortMap mapping, final String rd,
149 TypedReadWriteTransaction<Configuration> confTx) {
150 String externalIp = mapping.getExternalIp();
151 String internalIp = mapping.getInternalIp();
152 Uuid floatingIpId = mapping.getExternalId();
153 Uuid subnetId = NatUtil.getFloatingIpPortSubnetIdFromFloatingIpId(dataBroker, floatingIpId);
154 String floatingIpPortMacAddress = NatUtil.getFloatingIpPortMacFromFloatingIpId(dataBroker, floatingIpId);
155 if (floatingIpPortMacAddress == null) {
156 LOG.error("onAddFloatingIp: Unable to retrieve floatingIp port MAC address from floatingIpId {} for "
157 + "router {} to handle floatingIp {}", floatingIpId, routerUuid, externalIp);
160 Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(dataBroker, subnetId);
161 final String vpnName = externalSubnet.isPresent() ? subnetId.getValue() :
162 NatUtil.getAssociatedVPN(dataBroker, networkId);
163 final String subnetVpnName = externalSubnet.isPresent() ? subnetId.getValue() : null;
164 if (vpnName == null) {
165 LOG.error("onAddFloatingIp: No VPN is associated with ext nw {} to handle add floating ip {} configuration "
166 + "for router {}", networkId, externalIp, routerId);
170 LOG.error("onAddFloatingIp: Unable to retrieve external (internet) VPN RD from external VPN {} for "
171 + "router {} to handle floatingIp {}", vpnName, routerId, externalIp);
174 ProviderTypes provType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerUuid, networkId);
175 if (provType == null) {
179 * For external network of type GRE, it is required to use "Internet VPN VNI" for intra-DC
180 * communication, but we still require "MPLS labels" to reach SNAT/DNAT VMs from external
181 * entities via MPLSOverGRE.
183 * MPLSOverGRE based external networks, the ``opendaylight-vni-ranges`` pool will be
184 * used to carve out a unique VNI per Internet VPN (GRE-provider-type) to be used in the
185 * datapath for traffic forwarding for ``SNAT-to-DNAT`` and ``DNAT-to-DNAT`` cases within the
188 String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, dpnId);
189 LOG.debug("onAddFloatingIp: Nexthop ip for prefix {} is {}", externalIp, nextHopIp);
190 if (provType == ProviderTypes.VXLAN) {
191 Uuid floatingIpInterface = NatEvpnUtil.getFloatingIpInterfaceIdFromFloatingIpId(dataBroker, floatingIpId);
192 evpnDnatFlowProgrammer.onAddFloatingIp(dpnId, routerUuid, routerId, vpnName, internalIp,
193 externalIp, networkId, interfaceName, floatingIpInterface.getValue(), floatingIpPortMacAddress,
194 rd, nextHopIp, confTx);
198 * MPLS label will be used to advertise prefixes and in "L3_LFIB_TABLE" (table 20) taking the packet
199 * to "INBOUND_NAPT_TABLE" (table 44) and "PDNAT_TABLE" (table 25).
201 GenerateVpnLabelInput labelInput = new GenerateVpnLabelInputBuilder().setVpnName(vpnName)
202 .setIpPrefix(externalIp).build();
203 ListenableFuture<RpcResult<GenerateVpnLabelOutput>> labelFuture = vpnService.generateVpnLabel(labelInput);
205 ListenableFuture<RpcResult<CreateFibEntryOutput>> future = Futures.transformAsync(labelFuture, result -> {
206 if (result.isSuccessful()) {
207 GenerateVpnLabelOutput output = result.getResult();
208 Uint32 label = output.getLabel();
209 LOG.debug("onAddFloatingIp : Generated label {} for prefix {}", label, externalIp);
210 FloatingIPListener.updateOperationalDS(dataBroker, routerUuid, interfaceName, label,
211 internalIp, externalIp);
213 * For external network of type VXLAN all packets going from VMs within the DC, towards the
214 * external gateway device via the External VXLAN Tunnel,we are setting the VXLAN Tunnel ID to
215 * the L3VNI value of VPNInstance to which the VM belongs to.
217 Uint32 l3vni = Uint32.ZERO;
218 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanService, provType)) {
219 l3vni = natOverVxlanUtil.getInternetVpnVni(vpnName, l3vni);
221 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
223 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd,
224 fibExternalIp, nextHopIp, networkId.getValue(), floatingIpPortMacAddress,
225 label, l3vni, RouteOrigin.STATIC, dpnId);
227 List<Instruction> instructions = new ArrayList<>();
228 List<ActionInfo> actionsInfos = new ArrayList<>();
229 actionsInfos.add(new ActionNxResubmit(NwConstants.PDNAT_TABLE));
230 instructions.add(new InstructionApplyActions(actionsInfos).buildInstruction(0));
232 List<ActionInfo> actionInfoFib = new ArrayList<>();
233 List<Instruction> customInstructions = new ArrayList<>();
234 actionInfoFib.add(new ActionSetFieldEthernetDestination(new MacAddress(floatingIpPortMacAddress)));
235 customInstructions.add(new InstructionApplyActions(actionInfoFib).buildInstruction(0));
236 customInstructions.add(new InstructionGotoTable(NwConstants.PDNAT_TABLE).buildInstruction(1));
238 ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
240 makeTunnelTableEntry(vpnName, dpnId, label, instructions, innerConfTx, provType);
241 makeLFibTableEntry(dpnId, label, floatingIpPortMacAddress, NwConstants.PDNAT_TABLE,
243 }), LOG, "Error adding tunnel or FIB table entries");
245 CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName)
246 .setSourceDpid(dpnId).setInstruction(customInstructions)
247 .setIpAddress(fibExternalIp).setServiceId(label)
248 .setIpAddressSource(CreateFibEntryInput.IpAddressSource.FloatingIP)
249 .setInstruction(customInstructions).build();
250 //Future<RpcResult<java.lang.Void>> createFibEntry(CreateFibEntryInput input);
251 ListenableFuture<RpcResult<CreateFibEntryOutput>> future1 = fibService.createFibEntry(input);
252 LOG.debug("onAddFloatingIp : Add Floating Ip {} , found associated to fixed port {}",
253 externalIp, interfaceName);
254 String networkVpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
255 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
256 vpnManager.addSubnetMacIntoVpnInstance(networkVpnName, subnetVpnName,
257 floatingIpPortMacAddress, dpnId, tx);
258 vpnManager.addArpResponderFlowsToExternalNetworkIps(routerUuid,
259 Collections.singleton(externalIp),
260 floatingIpPortMacAddress, dpnId, networkId);
264 String errMsg = String.format("onAddFloatingIp : Could not retrieve the label for prefix %s "
265 + "in VPN %s, %s", externalIp, vpnName, result.getErrors());
267 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
269 }, MoreExecutors.directExecutor());
271 Futures.addCallback(future, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
274 public void onFailure(@NonNull Throwable error) {
275 LOG.error("onAddFloatingIp : Error in generate label or fib install process", error);
279 public void onSuccess(@NonNull RpcResult<CreateFibEntryOutput> result) {
280 if (result.isSuccessful()) {
281 LOG.info("onAddFloatingIp : Successfully installed custom FIB routes for prefix {}", externalIp);
283 LOG.error("onAddFloatingIp : Error in rpc call to create custom Fib entries for prefix {} "
284 + "in DPN {}, {}", externalIp, dpnId, result.getErrors());
287 }, MoreExecutors.directExecutor());
289 // Handle GARP transmission
290 final IpAddress extrenalAddress = IpAddressBuilder.getDefaultInstance(externalIp);
291 sendGarpOnInterface(dpnId, networkId, extrenalAddress, floatingIpPortMacAddress);
296 public void onRemoveFloatingIp(final Uint64 dpnId, String routerUuid, Uint32 routerId, final Uuid networkId,
297 InternalToExternalPortMap mapping, final Uint32 label, final String vrfId,
298 TypedReadWriteTransaction<Configuration> confTx) {
299 String externalIp = mapping.getExternalIp();
300 Uuid floatingIpId = mapping.getExternalId();
301 Uuid subnetId = NatUtil.getFloatingIpPortSubnetIdFromFloatingIpId(confTx, floatingIpId);
302 Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(confTx, subnetId);
303 final String vpnName = externalSubnet.isPresent() ? subnetId.getValue() :
304 NatUtil.getAssociatedVPN(dataBroker, networkId);
305 if (vpnName == null) {
306 LOG.error("onRemoveFloatingIp: No VPN associated with ext nw {} to remove floating ip {} configuration "
307 + "for router {}", networkId, externalIp, routerUuid);
311 //Remove floating mac from mymac table
312 LOG.debug("onRemoveFloatingIp: Removing FloatingIp {}", externalIp);
313 String floatingIpPortMacAddress = NatUtil.getFloatingIpPortMacFromFloatingIpId(confTx, floatingIpId);
314 if (floatingIpPortMacAddress == null) {
315 LOG.error("onRemoveFloatingIp: Unable to retrieve floatingIp port MAC address from floatingIpId {} for "
316 + "router {} to remove floatingIp {}", floatingIpId, routerUuid, externalIp);
320 ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
321 String networkVpnName = NatUtil.getAssociatedVPN(tx, networkId);
322 vpnManager.removeSubnetMacFromVpnInstance(networkVpnName, subnetId.getValue(), floatingIpPortMacAddress,
324 vpnManager.removeArpResponderFlowsToExternalNetworkIps(routerUuid, Collections.singletonList(externalIp),
325 floatingIpPortMacAddress, dpnId, networkId);
326 }), LOG, "onRemoveFloatingIp");
328 removeFromFloatingIpPortInfo(floatingIpId);
329 ProviderTypes provType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerUuid, networkId);
330 if (provType == null) {
333 if (provType == ProviderTypes.VXLAN) {
334 Uuid floatingIpInterface = NatEvpnUtil.getFloatingIpInterfaceIdFromFloatingIpId(dataBroker, floatingIpId);
335 evpnDnatFlowProgrammer.onRemoveFloatingIp(dpnId, vpnName, externalIp, floatingIpInterface.getValue(),
336 floatingIpPortMacAddress, routerId);
339 cleanupFibEntries(dpnId, vpnName, externalIp, label, vrfId, confTx, provType);
343 public void cleanupFibEntries(Uint64 dpnId, String vpnName, String externalIp,
344 Uint32 label, final String rd, TypedReadWriteTransaction<Configuration> confTx,
345 ProviderTypes provType) {
346 //Remove Prefix from BGP
347 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
348 NatUtil.removePrefixFromBGP(bgpManager, fibManager, rd, fibExternalIp, vpnName);
349 NatUtil.deletePrefixToInterface(dataBroker, NatUtil.getVpnId(dataBroker, vpnName), fibExternalIp);
350 //Remove custom FIB routes
352 //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
353 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName)
354 .setSourceDpid(dpnId).setIpAddress(fibExternalIp).setServiceId(label)
355 .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.FloatingIP).build();
356 ListenableFuture<RpcResult<RemoveFibEntryOutput>> future = fibService.removeFibEntry(input);
358 ListenableFuture<RpcResult<RemoveVpnLabelOutput>> labelFuture = Futures.transformAsync(future, result -> {
360 if (result.isSuccessful()) {
361 /* check if any floating IP information is available in vpn-to-dpn-list for given dpn id. If exist any
362 * floating IP then do not remove INTERNAL_TUNNEL_TABLE (table=36) -> PDNAT_TABLE (table=25) flow entry
364 Boolean removeTunnelFlow = Boolean.TRUE;
365 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanService, provType)) {
366 if (NatUtil.isFloatingIpPresentForDpn(dataBroker, dpnId, rd, vpnName, externalIp,
368 removeTunnelFlow = Boolean.FALSE;
371 if (removeTunnelFlow) {
372 removeTunnelTableEntry(dpnId, label, confTx);
374 removeLFibTableEntry(dpnId, label, confTx);
375 RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder()
376 .setVpnName(vpnName).setIpPrefix(externalIp).build();
377 Future<RpcResult<RemoveVpnLabelOutput>> labelFuture1 = vpnService.removeVpnLabel(labelInput);
378 if (labelFuture1.get() == null || !labelFuture1.get().isSuccessful()) {
379 String errMsg = String.format(
380 "VpnFloatingIpHandler: RPC call to remove VPN label on dpn %s "
381 + "for prefix %s failed for vpn %s - %s",
382 dpnId, externalIp, vpnName, result.getErrors());
384 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
386 return JdkFutureAdapters.listenInPoolThread(labelFuture1);
388 String errMsg = String.format("onRemoveFloatingIp :RPC call to remove custom FIB entries "
389 + "on dpn %s for prefix %s Failed - %s", dpnId, externalIp, result.getErrors());
391 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
393 }, MoreExecutors.directExecutor());
395 Futures.addCallback(labelFuture, new FutureCallback<RpcResult<RemoveVpnLabelOutput>>() {
398 public void onFailure(@NonNull Throwable error) {
399 LOG.error("onRemoveFloatingIp : Error in removing the label or custom fib entries", error);
403 public void onSuccess(@NonNull RpcResult<RemoveVpnLabelOutput> result) {
404 if (result.isSuccessful()) {
405 LOG.debug("onRemoveFloatingIp : Successfully removed the label for the prefix {} from VPN {}",
406 externalIp, vpnName);
408 LOG.error("onRemoveFloatingIp : Error in removing the label for prefix {} from VPN {}, {}",
409 externalIp, vpnName, result.getErrors());
412 }, MoreExecutors.directExecutor());
415 private String getFlowRef(Uint64 dpnId, short tableId, Uint32 id, String ipAddress) {
416 return FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants.FLOWID_SEPARATOR + id
417 + NwConstants.FLOWID_SEPARATOR + ipAddress;
420 private void removeTunnelTableEntry(Uint64 dpnId, Uint32 serviceId,
421 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
423 LOG.debug("removeTunnelTableEntry : called with DpnId = {} and label = {}", dpnId, serviceId);
424 mdsalManager.removeFlow(confTx, dpnId,
425 new FlowKey(new FlowId(getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""))),
426 NwConstants.INTERNAL_TUNNEL_TABLE);
427 LOG.debug("removeTunnelTableEntry : Terminating service Entry for dpID {} : label : {} removed successfully",
431 private void makeTunnelTableEntry(String vpnName, Uint64 dpnId, Uint32 serviceId,
432 List<Instruction> customInstructions, TypedWriteTransaction<Configuration> confTx, ProviderTypes provType) {
433 List<MatchInfo> mkMatches = new ArrayList<>();
435 LOG.info("makeTunnelTableEntry on DpnId = {} and serviceId = {}", dpnId, serviceId);
436 int flowPriority = NatConstants.DEFAULT_VPN_INTERNAL_TUNNEL_TABLE_PRIORITY;
437 // Increased the 36->25 flow priority. If SNAT is also configured on the same
438 // DPN, then the traffic will be hijacked to DNAT and if there are no DNAT match,
439 // then handled back to using using flow 25->44(which will be installed as part of SNAT)
440 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanService, provType)) {
441 mkMatches.add(new MatchTunnelId(Uint64.valueOf(
442 natOverVxlanUtil.getInternetVpnVni(vpnName, serviceId).longValue())));
443 flowPriority = NatConstants.DEFAULT_VPN_INTERNAL_TUNNEL_TABLE_PRIORITY + 1;
445 mkMatches.add(new MatchTunnelId(Uint64.valueOf(serviceId)));
447 Map<InstructionKey, Instruction> customInstructionsMap = new HashMap<InstructionKey, Instruction>();
448 int instructionKey = 0;
449 for (Instruction instructionObj : customInstructions) {
450 customInstructionsMap.put(new InstructionKey(++instructionKey), instructionObj);
452 Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
453 getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), flowPriority,
454 String.format("%s:%s", "TST Flow Entry ", serviceId),
455 0, 0, Uint64.valueOf(COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId.longValue()))),
456 mkMatches, customInstructionsMap);
458 mdsalManager.addFlow(confTx, dpnId, terminatingServiceTableFlowEntity);
461 private void makeLFibTableEntry(Uint64 dpId, Uint32 serviceId, String floatingIpPortMacAddress, short tableId,
462 TypedWriteTransaction<Configuration> confTx) {
463 List<MatchInfo> matches = new ArrayList<>();
464 matches.add(MatchEthernetType.MPLS_UNICAST);
465 matches.add(new MatchMplsLabel(serviceId.longValue()));
467 Map<InstructionKey, Instruction> instructionMap = new HashMap<InstructionKey, Instruction>();
468 int instructionKey = 0;
469 List<ActionInfo> actionsInfos = new ArrayList<>();
470 //NAT is required for IPv4 only. Hence always etherType will be IPv4
471 actionsInfos.add(new ActionPopMpls(NwConstants.ETHTYPE_IPV4));
472 actionsInfos.add(new ActionSetFieldEthernetDestination(new MacAddress(floatingIpPortMacAddress)));
473 Instruction writeInstruction = new InstructionApplyActions(actionsInfos).buildInstruction(0);
474 instructionMap.put(new InstructionKey(++instructionKey), writeInstruction);
475 instructionMap.put(new InstructionKey(++instructionKey),
476 new InstructionGotoTable(tableId).buildInstruction(1));
478 // Install the flow entry in L3_LFIB_TABLE
479 String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, serviceId, "");
481 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
483 NwConstants.COOKIE_VM_LFIB_TABLE, matches, instructionMap);
485 mdsalManager.addFlow(confTx, dpId, flowEntity);
487 LOG.debug("makeLFibTableEntry : LFIB Entry for dpID {} : label : {} modified successfully", dpId, serviceId);
490 private void removeLFibTableEntry(Uint64 dpnId, Uint32 serviceId,
491 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
493 String flowRef = getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, serviceId, "");
495 LOG.debug("removeLFibTableEntry : removing LFib entry with flow ref {}", flowRef);
497 mdsalManager.removeFlow(confTx, dpnId, new FlowKey(new FlowId(flowRef)), NwConstants.L3_LFIB_TABLE);
499 LOG.debug("removeLFibTableEntry : LFIB Entry for dpID : {} label : {} removed successfully",
503 // TODO Clean up the exception handling
504 @SuppressWarnings("checkstyle:IllegalCatch")
505 private void sendGarpOnInterface(final Uint64 dpnId, Uuid networkId, final IpAddress floatingIpAddress,
506 String floatingIpPortMacAddress) {
507 if (floatingIpAddress.getIpv4Address() == null) {
508 LOG.error("sendGarpOnInterface : Failed to send GARP for IP. recieved IPv6.");
509 natServiceCounters.garpFailedIpv6();
513 String interfaceName = elanService.getExternalElanInterface(networkId.getValue(), dpnId);
514 if (interfaceName == null) {
515 LOG.warn("sendGarpOnInterface : Failed to send GARP for IP. Failed to retrieve interface name "
516 + "from network {} and dpn id {}.", networkId.getValue(), dpnId);
517 natServiceCounters.garpFailedMissingInterface();
522 // find the external network interface name for dpn
523 List<InterfaceAddress> interfaceAddresses = new ArrayList<>();
524 interfaceAddresses.add(new InterfaceAddressBuilder()
525 .setInterface(interfaceName)
526 .setIpAddress(floatingIpAddress)
527 .setMacaddress(new PhysAddress(floatingIpPortMacAddress)).build());
529 SendArpRequestInput sendArpRequestInput = new SendArpRequestInputBuilder().setIpaddress(floatingIpAddress)
530 .setInterfaceAddress(interfaceAddresses).build();
532 JdkFutures.addErrorLogging(arpUtilService.sendArpRequest(sendArpRequestInput), LOG, "sendArpRequest");
533 natServiceCounters.garpSent();
534 } catch (Exception e) {
535 LOG.error("sendGarpOnInterface : Failed to send GARP request for floating ip {} from interface {}",
536 floatingIpAddress.getIpv4Address().getValue(), interfaceName, e);
537 natServiceCounters.garpFailedSend();
541 // TODO Clean up the exception handling
542 @SuppressWarnings("checkstyle:IllegalCatch")
543 private void removeFromFloatingIpPortInfo(Uuid floatingIpId) {
544 InstanceIdentifier id = buildfloatingIpIdToPortMappingIdentifier(floatingIpId);
546 Optional<FloatingIpIdToPortMapping> optFloatingIpIdToPortMapping =
547 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
548 LogicalDatastoreType.CONFIGURATION, id);
549 if (optFloatingIpIdToPortMapping.isPresent() && optFloatingIpIdToPortMapping.get().isFloatingIpDeleted()) {
550 LOG.debug("Deleting floating IP UUID {} to Floating IP neutron port mapping from Floating "
551 + "IP Port Info Config DS", floatingIpId.getValue());
552 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
554 } catch (Exception e) {
555 LOG.error("removeFromFloatingIpPortInfo : Deleting floating IP UUID {} to Floating IP neutron port "
556 + "mapping from Floating IP Port Info Config DS failed", floatingIpId.getValue(), e);