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.List;
22 import java.util.Optional;
23 import java.util.concurrent.ExecutionException;
24 import java.util.concurrent.Future;
25 import javax.inject.Inject;
26 import javax.inject.Singleton;
27 import org.eclipse.jdt.annotation.NonNull;
28 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
29 import org.opendaylight.genius.infra.Datastore.Configuration;
30 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
31 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
32 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
33 import org.opendaylight.genius.infra.TypedWriteTransaction;
34 import org.opendaylight.genius.mdsalutil.ActionInfo;
35 import org.opendaylight.genius.mdsalutil.MDSALUtil;
36 import org.opendaylight.genius.mdsalutil.MatchInfo;
37 import org.opendaylight.genius.mdsalutil.NwConstants;
38 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
39 import org.opendaylight.genius.mdsalutil.actions.ActionPopMpls;
40 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetDestination;
41 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
42 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
43 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
44 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
45 import org.opendaylight.genius.mdsalutil.matches.MatchMplsLabel;
46 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
47 import org.opendaylight.infrautils.utils.concurrent.JdkFutures;
48 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
49 import org.opendaylight.mdsal.binding.api.DataBroker;
50 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
51 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
52 import org.opendaylight.netvirt.elanmanager.api.IElanService;
53 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
54 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
55 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
57 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
59 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
60 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
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.Flow;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilService;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpRequestInput;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpRequestInputBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.interfaces.InterfaceAddress;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.interfaces.InterfaceAddressBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInput;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInputBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryOutput;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInput;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInputBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryOutput;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets.Subnets;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.port.info.FloatingIpIdToPortMapping;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelInput;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelInputBuilder;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelOutput;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelInput;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelInputBuilder;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelOutput;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.VpnRpcService;
88 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
89 import org.opendaylight.yangtools.yang.common.RpcResult;
90 import org.opendaylight.yangtools.yang.common.Uint32;
91 import org.opendaylight.yangtools.yang.common.Uint64;
92 import org.slf4j.Logger;
93 import org.slf4j.LoggerFactory;
96 public class VpnFloatingIpHandler implements FloatingIPHandler {
97 private static final Logger LOG = LoggerFactory.getLogger(VpnFloatingIpHandler.class);
98 private static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
99 private static final String FLOWID_PREFIX = "NAT.";
101 private final DataBroker dataBroker;
102 private final ManagedNewTransactionRunner txRunner;
103 private final IMdsalApiManager mdsalManager;
104 private final VpnRpcService vpnService;
105 private final IBgpManager bgpManager;
106 private final FibRpcService fibService;
107 private final IVpnManager vpnManager;
108 private final IFibManager fibManager;
109 private final OdlArputilService arpUtilService;
110 private final IElanService elanService;
111 private final EvpnDnatFlowProgrammer evpnDnatFlowProgrammer;
112 private final NatServiceCounters natServiceCounters;
113 private final NatOverVxlanUtil natOverVxlanUtil;
116 public VpnFloatingIpHandler(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
117 final VpnRpcService vpnService,
118 final IBgpManager bgpManager,
119 final FibRpcService fibService,
120 final IFibManager fibManager,
121 final OdlArputilService arputilService,
122 final IVpnManager vpnManager,
123 final IElanService elanService,
124 final EvpnDnatFlowProgrammer evpnDnatFlowProgrammer,
125 final NatOverVxlanUtil natOverVxlanUtil,
126 NatServiceCounters natServiceCounters) {
127 this.dataBroker = dataBroker;
128 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
129 this.mdsalManager = mdsalManager;
130 this.vpnService = vpnService;
131 this.bgpManager = bgpManager;
132 this.fibService = fibService;
133 this.fibManager = fibManager;
134 this.arpUtilService = arputilService;
135 this.vpnManager = vpnManager;
136 this.elanService = elanService;
137 this.evpnDnatFlowProgrammer = evpnDnatFlowProgrammer;
138 this.natServiceCounters = natServiceCounters;
139 this.natOverVxlanUtil = natOverVxlanUtil;
143 public void onAddFloatingIp(final Uint64 dpnId, final String routerUuid, final Uint32 routerId,
144 final Uuid networkId, final String interfaceName,
145 final InternalToExternalPortMap mapping, final String rd,
146 TypedReadWriteTransaction<Configuration> confTx) {
147 String externalIp = mapping.getExternalIp();
148 String internalIp = mapping.getInternalIp();
149 Uuid floatingIpId = mapping.getExternalId();
150 Uuid subnetId = NatUtil.getFloatingIpPortSubnetIdFromFloatingIpId(dataBroker, floatingIpId);
151 String floatingIpPortMacAddress = NatUtil.getFloatingIpPortMacFromFloatingIpId(dataBroker, floatingIpId);
152 if (floatingIpPortMacAddress == null) {
153 LOG.error("onAddFloatingIp: Unable to retrieve floatingIp port MAC address from floatingIpId {} for "
154 + "router {} to handle floatingIp {}", floatingIpId, routerUuid, externalIp);
157 Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(dataBroker, subnetId);
158 final String vpnName = externalSubnet.isPresent() ? subnetId.getValue() :
159 NatUtil.getAssociatedVPN(dataBroker, networkId);
160 final String subnetVpnName = externalSubnet.isPresent() ? subnetId.getValue() : null;
161 if (vpnName == null) {
162 LOG.error("onAddFloatingIp: No VPN is associated with ext nw {} to handle add floating ip {} configuration "
163 + "for router {}", networkId, externalIp, routerId);
167 LOG.error("onAddFloatingIp: Unable to retrieve external (internet) VPN RD from external VPN {} for "
168 + "router {} to handle floatingIp {}", vpnName, routerId, externalIp);
171 ProviderTypes provType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerUuid, networkId);
172 if (provType == null) {
176 * For external network of type GRE, it is required to use "Internet VPN VNI" for intra-DC
177 * communication, but we still require "MPLS labels" to reach SNAT/DNAT VMs from external
178 * entities via MPLSOverGRE.
180 * MPLSOverGRE based external networks, the ``opendaylight-vni-ranges`` pool will be
181 * used to carve out a unique VNI per Internet VPN (GRE-provider-type) to be used in the
182 * datapath for traffic forwarding for ``SNAT-to-DNAT`` and ``DNAT-to-DNAT`` cases within the
185 String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, dpnId);
186 LOG.debug("onAddFloatingIp: Nexthop ip for prefix {} is {}", externalIp, nextHopIp);
187 if (provType == ProviderTypes.VXLAN) {
188 Uuid floatingIpInterface = NatEvpnUtil.getFloatingIpInterfaceIdFromFloatingIpId(dataBroker, floatingIpId);
189 evpnDnatFlowProgrammer.onAddFloatingIp(dpnId, routerUuid, routerId, vpnName, internalIp,
190 externalIp, networkId, interfaceName, floatingIpInterface.getValue(), floatingIpPortMacAddress,
191 rd, nextHopIp, confTx);
195 * MPLS label will be used to advertise prefixes and in "L3_LFIB_TABLE" (table 20) taking the packet
196 * to "INBOUND_NAPT_TABLE" (table 44) and "PDNAT_TABLE" (table 25).
198 GenerateVpnLabelInput labelInput = new GenerateVpnLabelInputBuilder().setVpnName(vpnName)
199 .setIpPrefix(externalIp).build();
200 ListenableFuture<RpcResult<GenerateVpnLabelOutput>> labelFuture = vpnService.generateVpnLabel(labelInput);
202 ListenableFuture<RpcResult<CreateFibEntryOutput>> future = Futures.transformAsync(labelFuture, result -> {
203 if (result.isSuccessful()) {
204 GenerateVpnLabelOutput output = result.getResult();
205 Uint32 label = output.getLabel();
206 LOG.debug("onAddFloatingIp : Generated label {} for prefix {}", label, externalIp);
207 FloatingIPListener.updateOperationalDS(dataBroker, routerUuid, interfaceName, label,
208 internalIp, externalIp);
210 * For external network of type VXLAN all packets going from VMs within the DC, towards the
211 * external gateway device via the External VXLAN Tunnel,we are setting the VXLAN Tunnel ID to
212 * the L3VNI value of VPNInstance to which the VM belongs to.
214 Uint32 l3vni = Uint32.ZERO;
215 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanService, provType)) {
216 l3vni = natOverVxlanUtil.getInternetVpnVni(vpnName, l3vni);
218 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
220 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd,
221 fibExternalIp, nextHopIp, networkId.getValue(), floatingIpPortMacAddress,
222 label, l3vni, RouteOrigin.STATIC, dpnId);
224 List<Instruction> instructions = new ArrayList<>();
225 List<ActionInfo> actionsInfos = new ArrayList<>();
226 actionsInfos.add(new ActionNxResubmit(NwConstants.PDNAT_TABLE));
227 instructions.add(new InstructionApplyActions(actionsInfos).buildInstruction(0));
229 List<ActionInfo> actionInfoFib = new ArrayList<>();
230 List<Instruction> customInstructions = new ArrayList<>();
231 actionInfoFib.add(new ActionSetFieldEthernetDestination(new MacAddress(floatingIpPortMacAddress)));
232 customInstructions.add(new InstructionApplyActions(actionInfoFib).buildInstruction(0));
233 customInstructions.add(new InstructionGotoTable(NwConstants.PDNAT_TABLE).buildInstruction(1));
235 ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
237 makeTunnelTableEntry(vpnName, dpnId, label, instructions, innerConfTx, provType);
238 makeLFibTableEntry(dpnId, label, floatingIpPortMacAddress, NwConstants.PDNAT_TABLE,
240 }), LOG, "Error adding tunnel or FIB table entries");
242 CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName)
243 .setSourceDpid(dpnId).setInstruction(customInstructions)
244 .setIpAddress(fibExternalIp).setServiceId(label)
245 .setIpAddressSource(CreateFibEntryInput.IpAddressSource.FloatingIP)
246 .setInstruction(customInstructions).build();
247 //Future<RpcResult<java.lang.Void>> createFibEntry(CreateFibEntryInput input);
248 ListenableFuture<RpcResult<CreateFibEntryOutput>> future1 = fibService.createFibEntry(input);
249 LOG.debug("onAddFloatingIp : Add Floating Ip {} , found associated to fixed port {}",
250 externalIp, interfaceName);
251 String networkVpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
252 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
253 vpnManager.addSubnetMacIntoVpnInstance(networkVpnName, subnetVpnName,
254 floatingIpPortMacAddress, dpnId, tx);
255 vpnManager.addArpResponderFlowsToExternalNetworkIps(routerUuid,
256 Collections.singleton(externalIp),
257 floatingIpPortMacAddress, dpnId, networkId);
261 String errMsg = String.format("onAddFloatingIp : Could not retrieve the label for prefix %s "
262 + "in VPN %s, %s", externalIp, vpnName, result.getErrors());
264 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
266 }, MoreExecutors.directExecutor());
268 Futures.addCallback(future, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
271 public void onFailure(@NonNull Throwable error) {
272 LOG.error("onAddFloatingIp : Error in generate label or fib install process", error);
276 public void onSuccess(@NonNull RpcResult<CreateFibEntryOutput> result) {
277 if (result.isSuccessful()) {
278 LOG.info("onAddFloatingIp : Successfully installed custom FIB routes for prefix {}", externalIp);
280 LOG.error("onAddFloatingIp : Error in rpc call to create custom Fib entries for prefix {} "
281 + "in DPN {}, {}", externalIp, dpnId, result.getErrors());
284 }, MoreExecutors.directExecutor());
286 // Handle GARP transmission
287 final IpAddress extrenalAddress = IpAddressBuilder.getDefaultInstance(externalIp);
288 sendGarpOnInterface(dpnId, networkId, extrenalAddress, floatingIpPortMacAddress);
293 public void onRemoveFloatingIp(final Uint64 dpnId, String routerUuid, Uint32 routerId, final Uuid networkId,
294 InternalToExternalPortMap mapping, final Uint32 label, final String vrfId,
295 TypedReadWriteTransaction<Configuration> confTx) {
296 String externalIp = mapping.getExternalIp();
297 Uuid floatingIpId = mapping.getExternalId();
298 Uuid subnetId = NatUtil.getFloatingIpPortSubnetIdFromFloatingIpId(confTx, floatingIpId);
299 Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(confTx, subnetId);
300 final String vpnName = externalSubnet.isPresent() ? subnetId.getValue() :
301 NatUtil.getAssociatedVPN(dataBroker, networkId);
302 if (vpnName == null) {
303 LOG.error("onRemoveFloatingIp: No VPN associated with ext nw {} to remove floating ip {} configuration "
304 + "for router {}", networkId, externalIp, routerUuid);
308 //Remove floating mac from mymac table
309 LOG.debug("onRemoveFloatingIp: Removing FloatingIp {}", externalIp);
310 String floatingIpPortMacAddress = NatUtil.getFloatingIpPortMacFromFloatingIpId(confTx, floatingIpId);
311 if (floatingIpPortMacAddress == null) {
312 LOG.error("onRemoveFloatingIp: Unable to retrieve floatingIp port MAC address from floatingIpId {} for "
313 + "router {} to remove floatingIp {}", floatingIpId, routerUuid, externalIp);
317 ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
318 String networkVpnName = NatUtil.getAssociatedVPN(tx, networkId);
319 vpnManager.removeSubnetMacFromVpnInstance(networkVpnName, subnetId.getValue(), floatingIpPortMacAddress,
321 vpnManager.removeArpResponderFlowsToExternalNetworkIps(routerUuid, Collections.singletonList(externalIp),
322 floatingIpPortMacAddress, dpnId, networkId);
323 }), LOG, "onRemoveFloatingIp");
325 removeFromFloatingIpPortInfo(floatingIpId);
326 ProviderTypes provType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerUuid, networkId);
327 if (provType == null) {
330 if (provType == ProviderTypes.VXLAN) {
331 Uuid floatingIpInterface = NatEvpnUtil.getFloatingIpInterfaceIdFromFloatingIpId(dataBroker, floatingIpId);
332 evpnDnatFlowProgrammer.onRemoveFloatingIp(dpnId, vpnName, externalIp, floatingIpInterface.getValue(),
333 floatingIpPortMacAddress, routerId);
336 cleanupFibEntries(dpnId, vpnName, externalIp, label, vrfId, confTx, provType);
340 public void cleanupFibEntries(Uint64 dpnId, String vpnName, String externalIp,
341 Uint32 label, final String rd, TypedReadWriteTransaction<Configuration> confTx,
342 ProviderTypes provType) {
343 //Remove Prefix from BGP
344 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
345 NatUtil.removePrefixFromBGP(bgpManager, fibManager, rd, fibExternalIp, vpnName);
346 NatUtil.deletePrefixToInterface(dataBroker, NatUtil.getVpnId(dataBroker, vpnName), fibExternalIp);
347 //Remove custom FIB routes
349 //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
350 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName)
351 .setSourceDpid(dpnId).setIpAddress(fibExternalIp).setServiceId(label)
352 .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.FloatingIP).build();
353 ListenableFuture<RpcResult<RemoveFibEntryOutput>> future = fibService.removeFibEntry(input);
355 ListenableFuture<RpcResult<RemoveVpnLabelOutput>> labelFuture = Futures.transformAsync(future, result -> {
357 if (result.isSuccessful()) {
358 /* check if any floating IP information is available in vpn-to-dpn-list for given dpn id. If exist any
359 * floating IP then do not remove INTERNAL_TUNNEL_TABLE (table=36) -> PDNAT_TABLE (table=25) flow entry
361 Boolean removeTunnelFlow = Boolean.TRUE;
362 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanService, provType)) {
363 if (NatUtil.isFloatingIpPresentForDpn(dataBroker, dpnId, rd, vpnName, externalIp,
365 removeTunnelFlow = Boolean.FALSE;
368 if (removeTunnelFlow) {
369 removeTunnelTableEntry(dpnId, label, confTx);
371 removeLFibTableEntry(dpnId, label, confTx);
372 RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder()
373 .setVpnName(vpnName).setIpPrefix(externalIp).build();
374 Future<RpcResult<RemoveVpnLabelOutput>> labelFuture1 = vpnService.removeVpnLabel(labelInput);
375 if (labelFuture1.get() == null || !labelFuture1.get().isSuccessful()) {
376 String errMsg = String.format(
377 "VpnFloatingIpHandler: RPC call to remove VPN label on dpn %s "
378 + "for prefix %s failed for vpn %s - %s",
379 dpnId, externalIp, vpnName, result.getErrors());
381 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
383 return JdkFutureAdapters.listenInPoolThread(labelFuture1);
385 String errMsg = String.format("onRemoveFloatingIp :RPC call to remove custom FIB entries "
386 + "on dpn %s for prefix %s Failed - %s", dpnId, externalIp, result.getErrors());
388 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
390 }, MoreExecutors.directExecutor());
392 Futures.addCallback(labelFuture, new FutureCallback<RpcResult<RemoveVpnLabelOutput>>() {
395 public void onFailure(@NonNull Throwable error) {
396 LOG.error("onRemoveFloatingIp : Error in removing the label or custom fib entries", error);
400 public void onSuccess(@NonNull RpcResult<RemoveVpnLabelOutput> result) {
401 if (result.isSuccessful()) {
402 LOG.debug("onRemoveFloatingIp : Successfully removed the label for the prefix {} from VPN {}",
403 externalIp, vpnName);
405 LOG.error("onRemoveFloatingIp : Error in removing the label for prefix {} from VPN {}, {}",
406 externalIp, vpnName, result.getErrors());
409 }, MoreExecutors.directExecutor());
412 private String getFlowRef(Uint64 dpnId, short tableId, Uint32 id, String ipAddress) {
413 return FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants.FLOWID_SEPARATOR + id
414 + NwConstants.FLOWID_SEPARATOR + ipAddress;
417 private void removeTunnelTableEntry(Uint64 dpnId, Uint32 serviceId,
418 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
420 LOG.debug("removeTunnelTableEntry : called with DpnId = {} and label = {}", dpnId, serviceId);
421 mdsalManager.removeFlow(confTx, dpnId,
422 new FlowKey(new FlowId(getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""))),
423 NwConstants.INTERNAL_TUNNEL_TABLE);
424 LOG.debug("removeTunnelTableEntry : Terminating service Entry for dpID {} : label : {} removed successfully",
428 private void makeTunnelTableEntry(String vpnName, Uint64 dpnId, Uint32 serviceId,
429 List<Instruction> customInstructions, TypedWriteTransaction<Configuration> confTx, ProviderTypes provType) {
430 List<MatchInfo> mkMatches = new ArrayList<>();
432 LOG.info("makeTunnelTableEntry on DpnId = {} and serviceId = {}", dpnId, serviceId);
433 int flowPriority = NatConstants.DEFAULT_VPN_INTERNAL_TUNNEL_TABLE_PRIORITY;
434 // Increased the 36->25 flow priority. If SNAT is also configured on the same
435 // DPN, then the traffic will be hijacked to DNAT and if there are no DNAT match,
436 // then handled back to using using flow 25->44(which will be installed as part of SNAT)
437 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanService, provType)) {
438 mkMatches.add(new MatchTunnelId(Uint64.valueOf(
439 natOverVxlanUtil.getInternetVpnVni(vpnName, serviceId).longValue())));
440 flowPriority = NatConstants.DEFAULT_VPN_INTERNAL_TUNNEL_TABLE_PRIORITY + 1;
442 mkMatches.add(new MatchTunnelId(Uint64.valueOf(serviceId)));
445 Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
446 getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), flowPriority,
447 String.format("%s:%s", "TST Flow Entry ", serviceId),
448 0, 0, Uint64.valueOf(COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId.longValue()))),
449 mkMatches, customInstructions);
451 mdsalManager.addFlow(confTx, dpnId, terminatingServiceTableFlowEntity);
454 private void makeLFibTableEntry(Uint64 dpId, Uint32 serviceId, String floatingIpPortMacAddress, short tableId,
455 TypedWriteTransaction<Configuration> confTx) {
456 List<MatchInfo> matches = new ArrayList<>();
457 matches.add(MatchEthernetType.MPLS_UNICAST);
458 matches.add(new MatchMplsLabel(serviceId.longValue()));
460 List<Instruction> instructions = new ArrayList<>();
461 List<ActionInfo> actionsInfos = new ArrayList<>();
462 //NAT is required for IPv4 only. Hence always etherType will be IPv4
463 actionsInfos.add(new ActionPopMpls(NwConstants.ETHTYPE_IPV4));
464 actionsInfos.add(new ActionSetFieldEthernetDestination(new MacAddress(floatingIpPortMacAddress)));
465 Instruction writeInstruction = new InstructionApplyActions(actionsInfos).buildInstruction(0);
466 instructions.add(writeInstruction);
467 instructions.add(new InstructionGotoTable(tableId).buildInstruction(1));
469 // Install the flow entry in L3_LFIB_TABLE
470 String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, serviceId, "");
472 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
474 NwConstants.COOKIE_VM_LFIB_TABLE, matches, instructions);
476 mdsalManager.addFlow(confTx, dpId, flowEntity);
478 LOG.debug("makeLFibTableEntry : LFIB Entry for dpID {} : label : {} modified successfully", dpId, serviceId);
481 private void removeLFibTableEntry(Uint64 dpnId, Uint32 serviceId,
482 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
484 String flowRef = getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, serviceId, "");
486 LOG.debug("removeLFibTableEntry : removing LFib entry with flow ref {}", flowRef);
488 mdsalManager.removeFlow(confTx, dpnId, new FlowKey(new FlowId(flowRef)), NwConstants.L3_LFIB_TABLE);
490 LOG.debug("removeLFibTableEntry : LFIB Entry for dpID : {} label : {} removed successfully",
494 // TODO Clean up the exception handling
495 @SuppressWarnings("checkstyle:IllegalCatch")
496 private void sendGarpOnInterface(final Uint64 dpnId, Uuid networkId, final IpAddress floatingIpAddress,
497 String floatingIpPortMacAddress) {
498 if (floatingIpAddress.getIpv4Address() == null) {
499 LOG.error("sendGarpOnInterface : Failed to send GARP for IP. recieved IPv6.");
500 natServiceCounters.garpFailedIpv6();
504 String interfaceName = elanService.getExternalElanInterface(networkId.getValue(), dpnId);
505 if (interfaceName == null) {
506 LOG.warn("sendGarpOnInterface : Failed to send GARP for IP. Failed to retrieve interface name "
507 + "from network {} and dpn id {}.", networkId.getValue(), dpnId);
508 natServiceCounters.garpFailedMissingInterface();
513 // find the external network interface name for dpn
514 List<InterfaceAddress> interfaceAddresses = new ArrayList<>();
515 interfaceAddresses.add(new InterfaceAddressBuilder()
516 .setInterface(interfaceName)
517 .setIpAddress(floatingIpAddress)
518 .setMacaddress(new PhysAddress(floatingIpPortMacAddress)).build());
520 SendArpRequestInput sendArpRequestInput = new SendArpRequestInputBuilder().setIpaddress(floatingIpAddress)
521 .setInterfaceAddress(interfaceAddresses).build();
523 JdkFutures.addErrorLogging(arpUtilService.sendArpRequest(sendArpRequestInput), LOG, "sendArpRequest");
524 natServiceCounters.garpSent();
525 } catch (Exception e) {
526 LOG.error("sendGarpOnInterface : Failed to send GARP request for floating ip {} from interface {}",
527 floatingIpAddress.getIpv4Address().getValue(), interfaceName, e);
528 natServiceCounters.garpFailedSend();
532 // TODO Clean up the exception handling
533 @SuppressWarnings("checkstyle:IllegalCatch")
534 private void removeFromFloatingIpPortInfo(Uuid floatingIpId) {
535 InstanceIdentifier id = buildfloatingIpIdToPortMappingIdentifier(floatingIpId);
537 Optional<FloatingIpIdToPortMapping> optFloatingIpIdToPortMapping =
538 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
539 LogicalDatastoreType.CONFIGURATION, id);
540 if (optFloatingIpIdToPortMapping.isPresent() && optFloatingIpIdToPortMapping.get().isFloatingIpDeleted()) {
541 LOG.debug("Deleting floating IP UUID {} to Floating IP neutron port mapping from Floating "
542 + "IP Port Info Config DS", floatingIpId.getValue());
543 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
545 } catch (Exception e) {
546 LOG.error("removeFromFloatingIpPortInfo : Deleting floating IP UUID {} to Floating IP neutron port "
547 + "mapping from Floating IP Port Info Config DS failed", floatingIpId.getValue(), e);