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 javax.annotation.Nonnull;
23 import javax.inject.Inject;
24 import javax.inject.Singleton;
25 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
28 import org.opendaylight.genius.infra.Datastore.Configuration;
29 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
30 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
31 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
32 import org.opendaylight.genius.infra.TypedWriteTransaction;
33 import org.opendaylight.genius.mdsalutil.ActionInfo;
34 import org.opendaylight.genius.mdsalutil.MDSALUtil;
35 import org.opendaylight.genius.mdsalutil.MatchInfo;
36 import org.opendaylight.genius.mdsalutil.NwConstants;
37 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
38 import org.opendaylight.genius.mdsalutil.actions.ActionPopMpls;
39 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetDestination;
40 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
41 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
42 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
43 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
44 import org.opendaylight.genius.mdsalutil.matches.MatchMplsLabel;
45 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
46 import org.opendaylight.infrautils.utils.concurrent.JdkFutures;
47 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
48 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
49 import org.opendaylight.netvirt.elanmanager.api.IElanService;
50 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
51 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
52 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
53 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddressBuilder;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
57 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.PhysAddress;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.OdlArputilService;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpRequestInput;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.SendArpRequestInputBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.interfaces.InterfaceAddress;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.arputil.rev160406.interfaces.InterfaceAddressBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.idmanager.rev160406.IdManagerService;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInput;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInputBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryOutput;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInput;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInputBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryOutput;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.subnets.Subnets;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.port.info.FloatingIpIdToPortMapping;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelInput;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelInputBuilder;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.GenerateVpnLabelOutput;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelInput;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelInputBuilder;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.RemoveVpnLabelOutput;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.vpn.rpc.rev160201.VpnRpcService;
87 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
88 import org.opendaylight.yangtools.yang.common.RpcResult;
89 import org.slf4j.Logger;
90 import org.slf4j.LoggerFactory;
93 public class VpnFloatingIpHandler implements FloatingIPHandler {
94 private static final Logger LOG = LoggerFactory.getLogger(VpnFloatingIpHandler.class);
95 private static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
96 private static final String FLOWID_PREFIX = "NAT.";
98 private final DataBroker dataBroker;
99 private final ManagedNewTransactionRunner txRunner;
100 private final IMdsalApiManager mdsalManager;
101 private final VpnRpcService vpnService;
102 private final IBgpManager bgpManager;
103 private final FibRpcService fibService;
104 private final IVpnManager vpnManager;
105 private final IFibManager fibManager;
106 private final OdlArputilService arpUtilService;
107 private final IElanService elanService;
108 private final EvpnDnatFlowProgrammer evpnDnatFlowProgrammer;
109 private final INeutronVpnManager nvpnManager;
110 private final IdManagerService idManager;
111 private final NatServiceCounters natServiceCounters;
114 public VpnFloatingIpHandler(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
115 final VpnRpcService vpnService,
116 final IBgpManager bgpManager,
117 final FibRpcService fibService,
118 final IFibManager fibManager,
119 final OdlArputilService arputilService,
120 final IVpnManager vpnManager,
121 final IElanService elanService,
122 final EvpnDnatFlowProgrammer evpnDnatFlowProgrammer,
123 final INeutronVpnManager nvpnManager,
124 final IdManagerService idManager,
125 NatServiceCounters natServiceCounters) {
126 this.dataBroker = dataBroker;
127 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
128 this.mdsalManager = mdsalManager;
129 this.vpnService = vpnService;
130 this.bgpManager = bgpManager;
131 this.fibService = fibService;
132 this.fibManager = fibManager;
133 this.arpUtilService = arputilService;
134 this.vpnManager = vpnManager;
135 this.elanService = elanService;
136 this.evpnDnatFlowProgrammer = evpnDnatFlowProgrammer;
137 this.nvpnManager = nvpnManager;
138 this.idManager = idManager;
139 this.natServiceCounters = natServiceCounters;
143 public void onAddFloatingIp(final BigInteger dpnId, final String routerUuid, final long routerId,
144 final Uuid networkId, final String interfaceName,
145 final InternalToExternalPortMap mapping,
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);
166 String rd = NatUtil.getVpnRd(dataBroker, vpnName);
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 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanService, provType)) {
187 NatOverVxlanUtil.validateAndCreateVxlanVniPool(dataBroker, nvpnManager, idManager,
188 NatConstants.ODL_VNI_POOL_NAME);
190 String nextHopIp = NatUtil.getEndpointIpAddressForDPN(dataBroker, dpnId);
191 LOG.debug("onAddFloatingIp: Nexthop ip for prefix {} is {}", externalIp, nextHopIp);
192 if (provType == ProviderTypes.VXLAN) {
193 Uuid floatingIpInterface = NatEvpnUtil.getFloatingIpInterfaceIdFromFloatingIpId(dataBroker, floatingIpId);
194 evpnDnatFlowProgrammer.onAddFloatingIp(dpnId, routerUuid, routerId, vpnName, internalIp,
195 externalIp, networkId, interfaceName, floatingIpInterface.getValue(), floatingIpPortMacAddress,
196 rd, nextHopIp, confTx);
200 * MPLS label will be used to advertise prefixes and in "L3_LFIB_TABLE" (table 20) taking the packet
201 * to "INBOUND_NAPT_TABLE" (table 44) and "PDNAT_TABLE" (table 25).
203 GenerateVpnLabelInput labelInput = new GenerateVpnLabelInputBuilder().setVpnName(vpnName)
204 .setIpPrefix(externalIp).build();
205 ListenableFuture<RpcResult<GenerateVpnLabelOutput>> labelFuture = vpnService.generateVpnLabel(labelInput);
207 ListenableFuture<RpcResult<CreateFibEntryOutput>> future = Futures.transformAsync(labelFuture, result -> {
208 if (result.isSuccessful()) {
209 GenerateVpnLabelOutput output = result.getResult();
210 long label = output.getLabel();
211 LOG.debug("onAddFloatingIp : Generated label {} for prefix {}", label, externalIp);
212 FloatingIPListener.updateOperationalDS(dataBroker, routerUuid, interfaceName, label,
213 internalIp, externalIp);
215 * For external network of type VXLAN all packets going from VMs within the DC, towards the
216 * external gateway device via the External VXLAN Tunnel,we are setting the VXLAN Tunnel ID to
217 * the L3VNI value of VPNInstance to which the VM belongs to.
220 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanService, provType)) {
221 l3vni = NatOverVxlanUtil.getInternetVpnVni(idManager, vpnName, l3vni).longValue();
223 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
225 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd, subnetId,
226 fibExternalIp, nextHopIp, networkId.getValue(), floatingIpPortMacAddress,
227 label, l3vni, RouteOrigin.STATIC, dpnId);
229 List<Instruction> instructions = new ArrayList<>();
230 List<ActionInfo> actionsInfos = new ArrayList<>();
231 actionsInfos.add(new ActionNxResubmit(NwConstants.PDNAT_TABLE));
232 instructions.add(new InstructionApplyActions(actionsInfos).buildInstruction(0));
234 List<ActionInfo> actionInfoFib = new ArrayList<>();
235 List<Instruction> customInstructions = new ArrayList<>();
236 actionInfoFib.add(new ActionSetFieldEthernetDestination(new MacAddress(floatingIpPortMacAddress)));
237 customInstructions.add(new InstructionApplyActions(actionInfoFib).buildInstruction(0));
238 customInstructions.add(new InstructionGotoTable(NwConstants.PDNAT_TABLE).buildInstruction(1));
240 ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
242 makeTunnelTableEntry(vpnName, dpnId, label, instructions, innerConfTx, provType);
243 makeLFibTableEntry(dpnId, label, floatingIpPortMacAddress, NwConstants.PDNAT_TABLE,
245 }), LOG, "Error adding tunnel or FIB table entries");
247 CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName)
248 .setSourceDpid(dpnId).setInstruction(customInstructions)
249 .setIpAddress(fibExternalIp).setServiceId(label)
250 .setIpAddressSource(CreateFibEntryInput.IpAddressSource.FloatingIP)
251 .setInstruction(customInstructions).build();
252 //Future<RpcResult<java.lang.Void>> createFibEntry(CreateFibEntryInput input);
253 ListenableFuture<RpcResult<CreateFibEntryOutput>> future1 = fibService.createFibEntry(input);
254 LOG.debug("onAddFloatingIp : Add Floating Ip {} , found associated to fixed port {}",
255 externalIp, interfaceName);
256 String networkVpnName = NatUtil.getAssociatedVPN(dataBroker, networkId);
257 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
258 vpnManager.addSubnetMacIntoVpnInstance(networkVpnName, subnetVpnName,
259 floatingIpPortMacAddress, dpnId, tx);
260 vpnManager.addArpResponderFlowsToExternalNetworkIps(routerUuid,
261 Collections.singleton(externalIp),
262 floatingIpPortMacAddress, dpnId, networkId);
266 String errMsg = String.format("onAddFloatingIp : Could not retrieve the label for prefix %s "
267 + "in VPN %s, %s", externalIp, vpnName, result.getErrors());
269 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
271 }, MoreExecutors.directExecutor());
273 Futures.addCallback(future, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
276 public void onFailure(@Nonnull Throwable error) {
277 LOG.error("onAddFloatingIp : Error in generate label or fib install process", error);
281 public void onSuccess(@Nonnull RpcResult<CreateFibEntryOutput> result) {
282 if (result.isSuccessful()) {
283 LOG.info("onAddFloatingIp : Successfully installed custom FIB routes for prefix {}", externalIp);
285 LOG.error("onAddFloatingIp : Error in rpc call to create custom Fib entries for prefix {} "
286 + "in DPN {}, {}", externalIp, dpnId, result.getErrors());
289 }, MoreExecutors.directExecutor());
291 // Handle GARP transmission
292 final IpAddress extrenalAddress = IpAddressBuilder.getDefaultInstance(externalIp);
293 sendGarpOnInterface(dpnId, networkId, extrenalAddress, floatingIpPortMacAddress);
298 public void onRemoveFloatingIp(final BigInteger dpnId, String routerUuid, long routerId, final Uuid networkId,
299 InternalToExternalPortMap mapping, final long label,
300 TypedReadWriteTransaction<Configuration> confTx) {
301 String externalIp = mapping.getExternalIp();
302 Uuid floatingIpId = mapping.getExternalId();
303 Uuid subnetId = NatUtil.getFloatingIpPortSubnetIdFromFloatingIpId(confTx, floatingIpId);
304 Optional<Subnets> externalSubnet = NatUtil.getOptionalExternalSubnets(confTx, subnetId);
305 final String vpnName = externalSubnet.isPresent() ? subnetId.getValue() :
306 NatUtil.getAssociatedVPN(dataBroker, networkId);
307 if (vpnName == null) {
308 LOG.error("onRemoveFloatingIp: No VPN associated with ext nw {} to remove floating ip {} configuration "
309 + "for router {}", networkId, externalIp, routerUuid);
313 //Remove floating mac from mymac table
314 LOG.debug("onRemoveFloatingIp: Removing FloatingIp {}", externalIp);
315 String floatingIpPortMacAddress = NatUtil.getFloatingIpPortMacFromFloatingIpId(confTx, floatingIpId);
316 if (floatingIpPortMacAddress == null) {
317 LOG.error("onRemoveFloatingIp: Unable to retrieve floatingIp port MAC address from floatingIpId {} for "
318 + "router {} to remove floatingIp {}", floatingIpId, routerUuid, externalIp);
322 ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
323 String networkVpnName = NatUtil.getAssociatedVPN(tx, networkId);
324 vpnManager.removeSubnetMacFromVpnInstance(networkVpnName, subnetId.getValue(), floatingIpPortMacAddress,
326 vpnManager.removeArpResponderFlowsToExternalNetworkIps(routerUuid, Collections.singletonList(externalIp),
327 floatingIpPortMacAddress, dpnId, networkId);
328 }), LOG, "onRemoveFloatingIp");
330 removeFromFloatingIpPortInfo(floatingIpId);
331 ProviderTypes provType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerUuid, networkId);
332 if (provType == null) {
335 if (provType == ProviderTypes.VXLAN) {
336 Uuid floatingIpInterface = NatEvpnUtil.getFloatingIpInterfaceIdFromFloatingIpId(dataBroker, floatingIpId);
337 evpnDnatFlowProgrammer.onRemoveFloatingIp(dpnId, vpnName, externalIp, floatingIpInterface.getValue(),
338 floatingIpPortMacAddress, routerId, confTx);
341 cleanupFibEntries(dpnId, vpnName, externalIp, label, confTx, provType);
345 public void cleanupFibEntries(BigInteger dpnId, String vpnName, String externalIp,
346 long label, TypedReadWriteTransaction<Configuration> confTx, ProviderTypes provType) {
347 //Remove Prefix from BGP
348 String rd = NatUtil.getVpnRd(confTx, vpnName);
349 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
350 NatUtil.removePrefixFromBGP(bgpManager, fibManager, rd, fibExternalIp, vpnName, LOG);
352 //Remove custom FIB routes
354 //Future<RpcResult<java.lang.Void>> removeFibEntry(RemoveFibEntryInput input);
355 RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName)
356 .setSourceDpid(dpnId).setIpAddress(fibExternalIp).setServiceId(label)
357 .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.FloatingIP).build();
358 ListenableFuture<RpcResult<RemoveFibEntryOutput>> future = fibService.removeFibEntry(input);
360 ListenableFuture<RpcResult<RemoveVpnLabelOutput>> labelFuture = Futures.transformAsync(future, result -> {
362 if (result.isSuccessful()) {
363 /* check if any floating IP information is available in vpn-to-dpn-list for given dpn id. If exist any
364 * floating IP then do not remove INTERNAL_TUNNEL_TABLE (table=36) -> PDNAT_TABLE (table=25) flow entry
366 Boolean removeTunnelFlow = Boolean.TRUE;
367 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanService, provType)) {
368 if (NatUtil.isFloatingIpPresentForDpn(dataBroker, dpnId, rd, vpnName, externalIp, false)) {
369 removeTunnelFlow = Boolean.FALSE;
372 if (removeTunnelFlow) {
373 removeTunnelTableEntry(dpnId, label, confTx);
375 removeLFibTableEntry(dpnId, label, confTx);
376 RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder()
377 .setVpnName(vpnName).setIpPrefix(externalIp).build();
378 return vpnService.removeVpnLabel(labelInput);
380 String errMsg = String.format("onRemoveFloatingIp :RPC call to remove custom FIB entries "
381 + "on dpn %s for prefix %s Failed - %s", dpnId, externalIp, result.getErrors());
383 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
385 }, MoreExecutors.directExecutor());
387 Futures.addCallback(labelFuture, new FutureCallback<RpcResult<RemoveVpnLabelOutput>>() {
390 public void onFailure(@Nonnull Throwable error) {
391 LOG.error("onRemoveFloatingIp : Error in removing the label or custom fib entries", error);
395 public void onSuccess(@Nonnull RpcResult<RemoveVpnLabelOutput> result) {
396 if (result.isSuccessful()) {
397 LOG.debug("onRemoveFloatingIp : Successfully removed the label for the prefix {} from VPN {}",
398 externalIp, vpnName);
400 LOG.error("onRemoveFloatingIp : Error in removing the label for prefix {} from VPN {}, {}",
401 externalIp, vpnName, result.getErrors());
404 }, MoreExecutors.directExecutor());
407 private String getFlowRef(BigInteger dpnId, short tableId, long id, String ipAddress) {
408 return FLOWID_PREFIX + dpnId + NwConstants.FLOWID_SEPARATOR + tableId + NwConstants.FLOWID_SEPARATOR + id
409 + NwConstants.FLOWID_SEPARATOR + ipAddress;
412 private void removeTunnelTableEntry(BigInteger dpnId, long serviceId,
413 TypedReadWriteTransaction<Configuration> confTx) {
415 LOG.debug("removeTunnelTableEntry : called with DpnId = {} and label = {}", dpnId, serviceId);
416 mdsalManager.removeFlow(confTx, dpnId,
417 new FlowKey(new FlowId(getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""))),
418 NwConstants.INTERNAL_TUNNEL_TABLE);
419 LOG.debug("removeTunnelTableEntry : Terminating service Entry for dpID {} : label : {} removed successfully",
423 private void makeTunnelTableEntry(String vpnName, BigInteger dpnId, long serviceId,
424 List<Instruction> customInstructions, TypedWriteTransaction<Configuration> confTx, ProviderTypes provType) {
425 List<MatchInfo> mkMatches = new ArrayList<>();
427 LOG.info("makeTunnelTableEntry on DpnId = {} and serviceId = {}", dpnId, serviceId);
428 int flowPriority = 5;
429 // Increased the 36->25 flow priority. If SNAT is also configured on the same
430 // DPN, then the traffic will be hijacked to DNAT and if there are no DNAT match,
431 // then handled back to using using flow 25->44(which will be installed as part of SNAT)
432 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanService, provType)) {
433 mkMatches.add(new MatchTunnelId(NatOverVxlanUtil.getInternetVpnVni(idManager, vpnName, serviceId)));
436 mkMatches.add(new MatchTunnelId(BigInteger.valueOf(serviceId)));
439 Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
440 getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, serviceId, ""), flowPriority,
441 String.format("%s:%d", "TST Flow Entry ", serviceId),
442 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(serviceId)), mkMatches, customInstructions);
444 mdsalManager.addFlow(confTx, dpnId, terminatingServiceTableFlowEntity);
447 private void makeLFibTableEntry(BigInteger dpId, long serviceId, String floatingIpPortMacAddress, short tableId,
448 TypedWriteTransaction<Configuration> confTx) {
449 List<MatchInfo> matches = new ArrayList<>();
450 matches.add(MatchEthernetType.MPLS_UNICAST);
451 matches.add(new MatchMplsLabel(serviceId));
453 List<Instruction> instructions = new ArrayList<>();
454 List<ActionInfo> actionsInfos = new ArrayList<>();
455 //NAT is required for IPv4 only. Hence always etherType will be IPv4
456 actionsInfos.add(new ActionPopMpls(NwConstants.ETHTYPE_IPV4));
457 actionsInfos.add(new ActionSetFieldEthernetDestination(new MacAddress(floatingIpPortMacAddress)));
458 Instruction writeInstruction = new InstructionApplyActions(actionsInfos).buildInstruction(0);
459 instructions.add(writeInstruction);
460 instructions.add(new InstructionGotoTable(tableId).buildInstruction(1));
462 // Install the flow entry in L3_LFIB_TABLE
463 String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, serviceId, "");
465 Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
467 NwConstants.COOKIE_VM_LFIB_TABLE, matches, instructions);
469 mdsalManager.addFlow(confTx, dpId, flowEntity);
471 LOG.debug("makeLFibTableEntry : LFIB Entry for dpID {} : label : {} modified successfully", dpId, serviceId);
474 private void removeLFibTableEntry(BigInteger dpnId, long serviceId,
475 TypedReadWriteTransaction<Configuration> confTx) {
477 String flowRef = getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, serviceId, "");
479 LOG.debug("removeLFibTableEntry : removing LFib entry with flow ref {}", flowRef);
481 mdsalManager.removeFlow(confTx, dpnId, new FlowKey(new FlowId(flowRef)), NwConstants.L3_LFIB_TABLE);
483 LOG.debug("removeLFibTableEntry : LFIB Entry for dpID : {} label : {} removed successfully",
487 // TODO Clean up the exception handling
488 @SuppressWarnings("checkstyle:IllegalCatch")
489 private void sendGarpOnInterface(final BigInteger dpnId, Uuid networkId, final IpAddress floatingIpAddress,
490 String floatingIpPortMacAddress) {
491 if (floatingIpAddress.getIpv4Address() == null) {
492 LOG.error("sendGarpOnInterface : Failed to send GARP for IP. recieved IPv6.");
493 natServiceCounters.garpFailedIpv6();
497 String interfaceName = elanService.getExternalElanInterface(networkId.getValue(), dpnId);
498 if (interfaceName == null) {
499 LOG.warn("sendGarpOnInterface : Failed to send GARP for IP. Failed to retrieve interface name "
500 + "from network {} and dpn id {}.", networkId.getValue(), dpnId);
501 natServiceCounters.garpFailedMissingInterface();
506 // find the external network interface name for dpn
507 List<InterfaceAddress> interfaceAddresses = new ArrayList<>();
508 interfaceAddresses.add(new InterfaceAddressBuilder()
509 .setInterface(interfaceName)
510 .setIpAddress(floatingIpAddress)
511 .setMacaddress(new PhysAddress(floatingIpPortMacAddress)).build());
513 SendArpRequestInput sendArpRequestInput = new SendArpRequestInputBuilder().setIpaddress(floatingIpAddress)
514 .setInterfaceAddress(interfaceAddresses).build();
516 JdkFutures.addErrorLogging(arpUtilService.sendArpRequest(sendArpRequestInput), LOG, "sendArpRequest");
517 natServiceCounters.garpSent();
518 } catch (Exception e) {
519 LOG.error("sendGarpOnInterface : Failed to send GARP request for floating ip {} from interface {}",
520 floatingIpAddress.getIpv4Address().getValue(), interfaceName, e);
521 natServiceCounters.garpFailedSend();
525 // TODO Clean up the exception handling
526 @SuppressWarnings("checkstyle:IllegalCatch")
527 private void removeFromFloatingIpPortInfo(Uuid floatingIpId) {
528 InstanceIdentifier id = buildfloatingIpIdToPortMappingIdentifier(floatingIpId);
530 Optional<FloatingIpIdToPortMapping> optFloatingIpIdToPortMapping =
531 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
532 LogicalDatastoreType.CONFIGURATION, id);
533 if (optFloatingIpIdToPortMapping.isPresent() && optFloatingIpIdToPortMapping.get().isFloatingIpDeleted()) {
534 LOG.debug("Deleting floating IP UUID {} to Floating IP neutron port mapping from Floating "
535 + "IP Port Info Config DS", floatingIpId.getValue());
536 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, id);
538 } catch (Exception e) {
539 LOG.error("removeFromFloatingIpPortInfo : Deleting floating IP UUID {} to Floating IP neutron port "
540 + "mapping from Floating IP Port Info Config DS failed", floatingIpId.getValue(), e);