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.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.concurrent.ExecutionException;
23 import javax.annotation.Nonnull;
24 import javax.inject.Inject;
25 import javax.inject.Singleton;
26 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
27 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
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.netvirt.bgpmanager.api.IBgpManager;
50 import org.opendaylight.netvirt.elanmanager.api.IElanService;
51 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
52 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
53 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
54 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder;
57 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
59 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilService;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpRequestInput;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpRequestInputBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.interfaces.InterfaceAddress;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.interfaces.InterfaceAddressBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
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.slf4j.Logger;
91 import org.slf4j.LoggerFactory;
94 public class VpnFloatingIpHandler implements FloatingIPHandler {
95 private static final Logger LOG = LoggerFactory.getLogger(VpnFloatingIpHandler.class);
96 private static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
97 private static final String FLOWID_PREFIX = "NAT.";
99 private final DataBroker dataBroker;
100 private final ManagedNewTransactionRunner txRunner;
101 private final IMdsalApiManager mdsalManager;
102 private final VpnRpcService vpnService;
103 private final IBgpManager bgpManager;
104 private final FibRpcService fibService;
105 private final IVpnManager vpnManager;
106 private final IFibManager fibManager;
107 private final OdlArputilService arpUtilService;
108 private final IElanService elanService;
109 private final EvpnDnatFlowProgrammer evpnDnatFlowProgrammer;
110 private final INeutronVpnManager nvpnManager;
111 private final IdManagerService idManager;
112 private final NatServiceCounters natServiceCounters;
115 public VpnFloatingIpHandler(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
116 final VpnRpcService vpnService,
117 final IBgpManager bgpManager,
118 final FibRpcService fibService,
119 final IFibManager fibManager,
120 final OdlArputilService arputilService,
121 final IVpnManager vpnManager,
122 final IElanService elanService,
123 final EvpnDnatFlowProgrammer evpnDnatFlowProgrammer,
124 final INeutronVpnManager nvpnManager,
125 final IdManagerService idManager,
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.nvpnManager = nvpnManager;
139 this.idManager = idManager;
140 this.natServiceCounters = natServiceCounters;
144 public void onAddFloatingIp(final BigInteger dpnId, final String routerUuid, final long routerId,
145 final Uuid networkId, final String interfaceName,
146 final InternalToExternalPortMap mapping,
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);
167 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
169 LOG.error("onAddFloatingIp: Unable to retrieve external (internet) VPN RD from external VPN {} for "
170 + "router {} to handle floatingIp {}", vpnName, routerId, externalIp);
173 ProviderTypes provType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerUuid, networkId);
174 if (provType == null) {
178 * For external network of type GRE, it is required to use "Internet VPN VNI" for intra-DC
179 * communication, but we still require "MPLS labels" to reach SNAT/DNAT VMs from external
180 * entities via MPLSOverGRE.
182 * MPLSOverGRE based external networks, the ``opendaylight-vni-ranges`` pool will be
183 * used to carve out a unique VNI per Internet VPN (GRE-provider-type) to be used in the
184 * datapath for traffic forwarding for ``SNAT-to-DNAT`` and ``DNAT-to-DNAT`` cases within the
187 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanService, provType)) {
188 NatOverVxlanUtil.validateAndCreateVxlanVniPool(dataBroker, nvpnManager, idManager,
189 NatConstants.ODL_VNI_POOL_NAME);
191 String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, dpnId);
192 LOG.debug("onAddFloatingIp: Nexthop ip for prefix {} is {}", externalIp, nextHopIp);
193 if (provType == ProviderTypes.VXLAN) {
194 Uuid floatingIpInterface = NatEvpnUtil.getFloatingIpInterfaceIdFromFloatingIpId(dataBroker, floatingIpId);
195 evpnDnatFlowProgrammer.onAddFloatingIp(dpnId, routerUuid, routerId, vpnName, internalIp,
196 externalIp, networkId, interfaceName, floatingIpInterface.getValue(), floatingIpPortMacAddress,
197 rd, nextHopIp, confTx);
201 * MPLS label will be used to advertise prefixes and in "L3_LFIB_TABLE" (table 20) taking the packet
202 * to "INBOUND_NAPT_TABLE" (table 44) and "PDNAT_TABLE" (table 25).
204 GenerateVpnLabelInput labelInput = new GenerateVpnLabelInputBuilder().setVpnName(vpnName)
205 .setIpPrefix(externalIp).build();
206 ListenableFuture<RpcResult<GenerateVpnLabelOutput>> labelFuture = vpnService.generateVpnLabel(labelInput);
208 ListenableFuture<RpcResult<CreateFibEntryOutput>> future = Futures.transformAsync(labelFuture, result -> {
209 if (result.isSuccessful()) {
210 GenerateVpnLabelOutput output = result.getResult();
211 long label = output.getLabel();
212 LOG.debug("onAddFloatingIp : Generated label {} for prefix {}", label, externalIp);
213 FloatingIPListener.updateOperationalDS(dataBroker, routerUuid, interfaceName, label,
214 internalIp, externalIp);
216 * For external network of type VXLAN all packets going from VMs within the DC, towards the
217 * external gateway device via the External VXLAN Tunnel,we are setting the VXLAN Tunnel ID to
218 * the L3VNI value of VPNInstance to which the VM belongs to.
221 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanService, provType)) {
222 l3vni = NatOverVxlanUtil.getInternetVpnVni(idManager, vpnName, l3vni).longValue();
224 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
226 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd,
227 fibExternalIp, nextHopIp, networkId.getValue(), floatingIpPortMacAddress,
228 label, l3vni, RouteOrigin.STATIC, dpnId);
230 List<Instruction> instructions = new ArrayList<>();
231 List<ActionInfo> actionsInfos = new ArrayList<>();
232 actionsInfos.add(new ActionNxResubmit(NwConstants.PDNAT_TABLE));
233 instructions.add(new InstructionApplyActions(actionsInfos).buildInstruction(0));
235 List<ActionInfo> actionInfoFib = new ArrayList<>();
236 List<Instruction> customInstructions = new ArrayList<>();
237 actionInfoFib.add(new ActionSetFieldEthernetDestination(new MacAddress(floatingIpPortMacAddress)));
238 customInstructions.add(new InstructionApplyActions(actionInfoFib).buildInstruction(0));
239 customInstructions.add(new InstructionGotoTable(NwConstants.PDNAT_TABLE).buildInstruction(1));
241 ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
243 makeTunnelTableEntry(vpnName, dpnId, label, instructions, innerConfTx, provType);
244 makeLFibTableEntry(dpnId, label, floatingIpPortMacAddress, NwConstants.PDNAT_TABLE,
246 }), LOG, "Error adding tunnel or FIB table entries");
248 CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName)
249 .setSourceDpid(dpnId).setInstruction(customInstructions)
250 .setIpAddress(fibExternalIp).setServiceId(label)
251 .setIpAddressSource(CreateFibEntryInput.IpAddressSource.FloatingIP)
252 .setInstruction(customInstructions).build();
253 //Future<RpcResult<java.lang.Void>> createFibEntry(CreateFibEntryInput input);
254 ListenableFuture<RpcResult<CreateFibEntryOutput>> future1 = fibService.createFibEntry(input);
255 LOG.debug("onAddFloatingIp : Add Floating Ip {} , found associated to fixed port {}",
256 externalIp, interfaceName);
257 String networkVpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
258 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
259 vpnManager.addSubnetMacIntoVpnInstance(networkVpnName, subnetVpnName,
260 floatingIpPortMacAddress, dpnId, tx);
261 vpnManager.addArpResponderFlowsToExternalNetworkIps(routerUuid,
262 Collections.singleton(externalIp),
263 floatingIpPortMacAddress, dpnId, networkId);
267 String errMsg = String.format("onAddFloatingIp : Could not retrieve the label for prefix %s "
268 + "in VPN %s, %s", externalIp, vpnName, result.getErrors());
270 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
272 }, MoreExecutors.directExecutor());
274 Futures.addCallback(future, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
277 public void onFailure(@Nonnull Throwable error) {
278 LOG.error("onAddFloatingIp : Error in generate label or fib install process", error);
282 public void onSuccess(@Nonnull RpcResult<CreateFibEntryOutput> result) {
283 if (result.isSuccessful()) {
284 LOG.info("onAddFloatingIp : Successfully installed custom FIB routes for prefix {}", externalIp);
286 LOG.error("onAddFloatingIp : Error in rpc call to create custom Fib entries for prefix {} "
287 + "in DPN {}, {}", externalIp, dpnId, result.getErrors());
290 }, MoreExecutors.directExecutor());
292 // Handle GARP transmission
293 final IpAddress extrenalAddress = IpAddressBuilder.getDefaultInstance(externalIp);
294 sendGarpOnInterface(dpnId, networkId, extrenalAddress, floatingIpPortMacAddress);
299 public void onRemoveFloatingIp(final BigInteger dpnId, String routerUuid, long routerId, final Uuid networkId,
300 InternalToExternalPortMap mapping, final long label,
301 TypedReadWriteTransaction<Configuration> confTx) {
302 String externalIp = mapping.getExternalIp();
303 Uuid floatingIpId = mapping.getExternalId();
304 Uuid subnetId = NatUtil.getFloatingIpPortSubnetIdFromFloatingIpId(confTx, floatingIpId);
305 Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(confTx, subnetId);
306 final String vpnName = externalSubnet.isPresent() ? subnetId.getValue() :
307 NatUtil.getAssociatedVPN(dataBroker, networkId);
308 if (vpnName == null) {
309 LOG.error("onRemoveFloatingIp: No VPN associated with ext nw {} to remove floating ip {} configuration "
310 + "for router {}", networkId, externalIp, routerUuid);
314 //Remove floating mac from mymac table
315 LOG.debug("onRemoveFloatingIp: Removing FloatingIp {}", externalIp);
316 String floatingIpPortMacAddress = NatUtil.getFloatingIpPortMacFromFloatingIpId(confTx, floatingIpId);
317 if (floatingIpPortMacAddress == null) {
318 LOG.error("onRemoveFloatingIp: Unable to retrieve floatingIp port MAC address from floatingIpId {} for "
319 + "router {} to remove floatingIp {}", floatingIpId, routerUuid, externalIp);
323 ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
324 String networkVpnName = NatUtil.getAssociatedVPN(tx, networkId);
325 vpnManager.removeSubnetMacFromVpnInstance(networkVpnName, subnetId.getValue(), floatingIpPortMacAddress,
327 vpnManager.removeArpResponderFlowsToExternalNetworkIps(routerUuid, Collections.singletonList(externalIp),
328 floatingIpPortMacAddress, dpnId, networkId);
329 }), LOG, "onRemoveFloatingIp");
331 removeFromFloatingIpPortInfo(floatingIpId);
332 ProviderTypes provType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerUuid, networkId);
333 if (provType == null) {
336 if (provType == ProviderTypes.VXLAN) {
337 Uuid floatingIpInterface = NatEvpnUtil.getFloatingIpInterfaceIdFromFloatingIpId(dataBroker, floatingIpId);
338 evpnDnatFlowProgrammer.onRemoveFloatingIp(dpnId, vpnName, externalIp, floatingIpInterface.getValue(),
339 floatingIpPortMacAddress, routerId, confTx);
342 cleanupFibEntries(dpnId, vpnName, externalIp, label, confTx, provType);
346 public void cleanupFibEntries(BigInteger dpnId, String vpnName, String externalIp,
347 long label, TypedReadWriteTransaction<Configuration> confTx, ProviderTypes provType) {
348 //Remove Prefix from BGP
349 String rd = NatUtil.getVpnRd(confTx, vpnName);
350 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
351 NatUtil.removePrefixFromBGP(bgpManager, fibManager, rd, fibExternalIp, vpnName, LOG);
353 //Remove custom FIB routes
355 //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
356 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName)
357 .setSourceDpid(dpnId).setIpAddress(fibExternalIp).setServiceId(label)
358 .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.FloatingIP).build();
359 ListenableFuture<RpcResult<RemoveFibEntryOutput>> future = fibService.removeFibEntry(input);
361 ListenableFuture<RpcResult<RemoveVpnLabelOutput>> labelFuture = Futures.transformAsync(future, result -> {
363 if (result.isSuccessful()) {
364 /* check if any floating IP information is available in vpn-to-dpn-list for given dpn id. If exist any
365 * floating IP then do not remove INTERNAL_TUNNEL_TABLE (table=36) -> PDNAT_TABLE (table=25) flow entry
367 Boolean removeTunnelFlow = Boolean.TRUE;
368 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanService, provType)) {
369 if (NatUtil.isFloatingIpPresentForDpn(dataBroker, dpnId, rd, vpnName, externalIp, false)) {
370 removeTunnelFlow = Boolean.FALSE;
373 if (removeTunnelFlow) {
374 removeTunnelTableEntry(dpnId, label, confTx);
376 removeLFibTableEntry(dpnId, label, confTx);
377 RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder()
378 .setVpnName(vpnName).setIpPrefix(externalIp).build();
379 return vpnService.removeVpnLabel(labelInput);
381 String errMsg = String.format("onRemoveFloatingIp :RPC call to remove custom FIB entries "
382 + "on dpn %s for prefix %s Failed - %s", dpnId, externalIp, result.getErrors());
384 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
386 }, MoreExecutors.directExecutor());
388 Futures.addCallback(labelFuture, new FutureCallback<RpcResult<RemoveVpnLabelOutput>>() {
391 public void onFailure(@Nonnull Throwable error) {
392 LOG.error("onRemoveFloatingIp : Error in removing the label or custom fib entries", error);
396 public void onSuccess(@Nonnull RpcResult<RemoveVpnLabelOutput> result) {
397 if (result.isSuccessful()) {
398 LOG.debug("onRemoveFloatingIp : Successfully removed the label for the prefix {} from VPN {}",
399 externalIp, vpnName);
401 LOG.error("onRemoveFloatingIp : Error in removing the label for prefix {} from VPN {}, {}",
402 externalIp, vpnName, result.getErrors());
405 }, MoreExecutors.directExecutor());
408 private String getFlowRef(BigInteger dpnId, short tableId, long id, String ipAddress) {
409 return FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants.FLOWID_SEPARATOR + id
410 + NwConstants.FLOWID_SEPARATOR + ipAddress;
413 private void removeTunnelTableEntry(BigInteger dpnId, long serviceId,
414 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
416 LOG.debug("removeTunnelTableEntry : called with DpnId = {} and label = {}", dpnId, serviceId);
417 mdsalManager.removeFlow(confTx, dpnId,
418 new FlowKey(new FlowId(getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""))),
419 NwConstants.INTERNAL_TUNNEL_TABLE);
420 LOG.debug("removeTunnelTableEntry : Terminating service Entry for dpID {} : label : {} removed successfully",
424 private void makeTunnelTableEntry(String vpnName, BigInteger dpnId, long serviceId,
425 List<Instruction> customInstructions, TypedWriteTransaction<Configuration> confTx, ProviderTypes provType) {
426 List<MatchInfo> mkMatches = new ArrayList<>();
428 LOG.info("makeTunnelTableEntry on DpnId = {} and serviceId = {}", dpnId, serviceId);
429 int flowPriority = 5;
430 // Increased the 36->25 flow priority. If SNAT is also configured on the same
431 // DPN, then the traffic will be hijacked to DNAT and if there are no DNAT match,
432 // then handled back to using using flow 25->44(which will be installed as part of SNAT)
433 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanService, provType)) {
434 mkMatches.add(new MatchTunnelId(NatOverVxlanUtil.getInternetVpnVni(idManager, vpnName, serviceId)));
437 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(serviceId)));
440 Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
441 getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), flowPriority,
442 String.format("%s:%d", "TST Flow Entry ", serviceId),
443 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, customInstructions);
445 mdsalManager.addFlow(confTx, dpnId, terminatingServiceTableFlowEntity);
448 private void makeLFibTableEntry(BigInteger dpId, long serviceId, String floatingIpPortMacAddress, short tableId,
449 TypedWriteTransaction<Configuration> confTx) {
450 List<MatchInfo> matches = new ArrayList<>();
451 matches.add(MatchEthernetType.MPLS_UNICAST);
452 matches.add(new MatchMplsLabel(serviceId));
454 List<Instruction> instructions = new ArrayList<>();
455 List<ActionInfo> actionsInfos = new ArrayList<>();
456 //NAT is required for IPv4 only. Hence always etherType will be IPv4
457 actionsInfos.add(new ActionPopMpls(NwConstants.ETHTYPE_IPV4));
458 actionsInfos.add(new ActionSetFieldEthernetDestination(new MacAddress(floatingIpPortMacAddress)));
459 Instruction writeInstruction = new InstructionApplyActions(actionsInfos).buildInstruction(0);
460 instructions.add(writeInstruction);
461 instructions.add(new InstructionGotoTable(tableId).buildInstruction(1));
463 // Install the flow entry in L3_LFIB_TABLE
464 String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, serviceId, "");
466 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
468 NwConstants.COOKIE_VM_LFIB_TABLE, matches, instructions);
470 mdsalManager.addFlow(confTx, dpId, flowEntity);
472 LOG.debug("makeLFibTableEntry : LFIB Entry for dpID {} : label : {} modified successfully", dpId, serviceId);
475 private void removeLFibTableEntry(BigInteger dpnId, long serviceId,
476 TypedReadWriteTransaction<Configuration> confTx) throws ExecutionException, InterruptedException {
478 String flowRef = getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, serviceId, "");
480 LOG.debug("removeLFibTableEntry : removing LFib entry with flow ref {}", flowRef);
482 mdsalManager.removeFlow(confTx, dpnId, new FlowKey(new FlowId(flowRef)), NwConstants.L3_LFIB_TABLE);
484 LOG.debug("removeLFibTableEntry : LFIB Entry for dpID : {} label : {} removed successfully",
488 // TODO Clean up the exception handling
489 @SuppressWarnings("checkstyle:IllegalCatch")
490 private void sendGarpOnInterface(final BigInteger dpnId, Uuid networkId, final IpAddress floatingIpAddress,
491 String floatingIpPortMacAddress) {
492 if (floatingIpAddress.getIpv4Address() == null) {
493 LOG.error("sendGarpOnInterface : Failed to send GARP for IP. recieved IPv6.");
494 natServiceCounters.garpFailedIpv6();
498 String interfaceName = elanService.getExternalElanInterface(networkId.getValue(), dpnId);
499 if (interfaceName == null) {
500 LOG.warn("sendGarpOnInterface : Failed to send GARP for IP. Failed to retrieve interface name "
501 + "from network {} and dpn id {}.", networkId.getValue(), dpnId);
502 natServiceCounters.garpFailedMissingInterface();
507 // find the external network interface name for dpn
508 List<InterfaceAddress> interfaceAddresses = new ArrayList<>();
509 interfaceAddresses.add(new InterfaceAddressBuilder()
510 .setInterface(interfaceName)
511 .setIpAddress(floatingIpAddress)
512 .setMacaddress(new PhysAddress(floatingIpPortMacAddress)).build());
514 SendArpRequestInput sendArpRequestInput = new SendArpRequestInputBuilder().setIpaddress(floatingIpAddress)
515 .setInterfaceAddress(interfaceAddresses).build();
517 JdkFutures.addErrorLogging(arpUtilService.sendArpRequest(sendArpRequestInput), LOG, "sendArpRequest");
518 natServiceCounters.garpSent();
519 } catch (Exception e) {
520 LOG.error("sendGarpOnInterface : Failed to send GARP request for floating ip {} from interface {}",
521 floatingIpAddress.getIpv4Address().getValue(), interfaceName, e);
522 natServiceCounters.garpFailedSend();
526 // TODO Clean up the exception handling
527 @SuppressWarnings("checkstyle:IllegalCatch")
528 private void removeFromFloatingIpPortInfo(Uuid floatingIpId) {
529 InstanceIdentifier id = buildfloatingIpIdToPortMappingIdentifier(floatingIpId);
531 Optional<FloatingIpIdToPortMapping> optFloatingIpIdToPortMapping =
532 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
533 LogicalDatastoreType.CONFIGURATION, id);
534 if (optFloatingIpIdToPortMapping.isPresent() && optFloatingIpIdToPortMapping.get().isFloatingIpDeleted()) {
535 LOG.debug("Deleting floating IP UUID {} to Floating IP neutron port mapping from Floating "
536 + "IP Port Info Config DS", floatingIpId.getValue());
537 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
539 } catch (Exception e) {
540 LOG.error("removeFromFloatingIpPortInfo : Deleting floating IP UUID {} to Floating IP neutron port "
541 + "mapping from Floating IP Port Info Config DS failed", floatingIpId.getValue(), e);