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