Datastore txes: natservice, part 3
[netvirt.git] / natservice / impl / src / main / java / org / opendaylight / netvirt / natservice / internal / VpnFloatingIpHandler.java
1 /*
2  * Copyright © 2016, 2017 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.netvirt.natservice.internal;
9
10 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
11 import static org.opendaylight.netvirt.natservice.internal.NatUtil.buildfloatingIpIdToPortMappingIdentifier;
12
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;
91
92 @Singleton
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.";
97
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;
112
113     @Inject
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;
140     }
141
142     @Override
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);
155             return;
156         }
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);
164             return;
165         }
166         String rd = NatUtil.getVpnRd(dataBroker, vpnName);
167         if (rd == null) {
168             LOG.error("onAddFloatingIp: Unable to retrieve external (internet) VPN RD from external VPN {} for "
169                     + "router {} to handle floatingIp {}", vpnName, routerId, externalIp);
170             return;
171         }
172         ProviderTypes provType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerUuid, networkId);
173         if (provType == null) {
174             return;
175         }
176         /*
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.
180          *
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
184          *  DataCenter.
185         */
186         if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanService, provType)) {
187             NatOverVxlanUtil.validateAndCreateVxlanVniPool(dataBroker, nvpnManager, idManager,
188                     NatConstants.ODL_VNI_POOL_NAME);
189         }
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);
197             return;
198         }
199         /*
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).
202          */
203         GenerateVpnLabelInput labelInput = new GenerateVpnLabelInputBuilder().setVpnName(vpnName)
204             .setIpPrefix(externalIp).build();
205         ListenableFuture<RpcResult<GenerateVpnLabelOutput>> labelFuture = vpnService.generateVpnLabel(labelInput);
206
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);
214                 /*
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.
218                  */
219                 long l3vni = 0;
220                 if (NatUtil.isOpenStackVniSemanticsEnforcedForGreAndVxlan(elanService, provType)) {
221                     l3vni = NatOverVxlanUtil.getInternetVpnVni(idManager, vpnName, l3vni).longValue();
222                 }
223                 String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
224                 //Inform BGP
225                 NatUtil.addPrefixToBGP(dataBroker, bgpManager, fibManager, vpnName, rd, subnetId,
226                         fibExternalIp, nextHopIp, networkId.getValue(), floatingIpPortMacAddress,
227                         label, l3vni, RouteOrigin.STATIC, dpnId);
228
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));
233
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));
239
240                 ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
241                     innerConfTx -> {
242                         makeTunnelTableEntry(vpnName, dpnId, label, instructions, innerConfTx, provType);
243                         makeLFibTableEntry(dpnId, label, floatingIpPortMacAddress, NwConstants.PDNAT_TABLE,
244                             innerConfTx);
245                     }), LOG, "Error adding tunnel or FIB table entries");
246
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);
263                 });
264                 return future1;
265             } else {
266                 String errMsg = String.format("onAddFloatingIp : Could not retrieve the label for prefix %s "
267                         + "in VPN %s, %s", externalIp, vpnName, result.getErrors());
268                 LOG.error(errMsg);
269                 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
270             }
271         }, MoreExecutors.directExecutor());
272
273         Futures.addCallback(future, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
274
275             @Override
276             public void onFailure(@Nonnull Throwable error) {
277                 LOG.error("onAddFloatingIp : Error in generate label or fib install process", error);
278             }
279
280             @Override
281             public void onSuccess(@Nonnull RpcResult<CreateFibEntryOutput> result) {
282                 if (result.isSuccessful()) {
283                     LOG.info("onAddFloatingIp : Successfully installed custom FIB routes for prefix {}", externalIp);
284                 } else {
285                     LOG.error("onAddFloatingIp : Error in rpc call to create custom Fib entries for prefix {} "
286                             + "in DPN {}, {}", externalIp, dpnId, result.getErrors());
287                 }
288             }
289         }, MoreExecutors.directExecutor());
290
291         // Handle GARP transmission
292         final IpAddress extrenalAddress = IpAddressBuilder.getDefaultInstance(externalIp);
293         sendGarpOnInterface(dpnId, networkId, extrenalAddress, floatingIpPortMacAddress);
294
295     }
296
297     @Override
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);
310             return;
311         }
312
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);
319             return;
320         }
321
322         ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
323             String networkVpnName =  NatUtil.getAssociatedVPN(tx, networkId);
324             vpnManager.removeSubnetMacFromVpnInstance(networkVpnName, subnetId.getValue(), floatingIpPortMacAddress,
325                     dpnId, tx);
326             vpnManager.removeArpResponderFlowsToExternalNetworkIps(routerUuid, Collections.singletonList(externalIp),
327                     floatingIpPortMacAddress, dpnId, networkId);
328         }), LOG, "onRemoveFloatingIp");
329
330         removeFromFloatingIpPortInfo(floatingIpId);
331         ProviderTypes provType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerUuid, networkId);
332         if (provType == null) {
333             return;
334         }
335         if (provType == ProviderTypes.VXLAN) {
336             Uuid floatingIpInterface = NatEvpnUtil.getFloatingIpInterfaceIdFromFloatingIpId(dataBroker, floatingIpId);
337             evpnDnatFlowProgrammer.onRemoveFloatingIp(dpnId, vpnName, externalIp, floatingIpInterface.getValue(),
338                     floatingIpPortMacAddress, routerId, confTx);
339             return;
340         }
341         cleanupFibEntries(dpnId, vpnName, externalIp, label, confTx, provType);
342     }
343
344     @Override
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);
351
352         //Remove custom FIB routes
353
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);
359
360         ListenableFuture<RpcResult<RemoveVpnLabelOutput>> labelFuture = Futures.transformAsync(future, result -> {
361             //Release label
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
365                  */
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;
370                     }
371                 }
372                 if (removeTunnelFlow) {
373                     removeTunnelTableEntry(dpnId, label, confTx);
374                 }
375                 removeLFibTableEntry(dpnId, label, confTx);
376                 RemoveVpnLabelInput labelInput = new RemoveVpnLabelInputBuilder()
377                         .setVpnName(vpnName).setIpPrefix(externalIp).build();
378                 return vpnService.removeVpnLabel(labelInput);
379             } else {
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());
382                 LOG.error(errMsg);
383                 return Futures.immediateFailedFuture(new RuntimeException(errMsg));
384             }
385         }, MoreExecutors.directExecutor());
386
387         Futures.addCallback(labelFuture, new FutureCallback<RpcResult<RemoveVpnLabelOutput>>() {
388
389             @Override
390             public void onFailure(@Nonnull Throwable error) {
391                 LOG.error("onRemoveFloatingIp : Error in removing the label or custom fib entries", error);
392             }
393
394             @Override
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);
399                 } else {
400                     LOG.error("onRemoveFloatingIp : Error in removing the label for prefix {} from VPN {}, {}",
401                         externalIp, vpnName, result.getErrors());
402                 }
403             }
404         }, MoreExecutors.directExecutor());
405     }
406
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;
410     }
411
412     private void removeTunnelTableEntry(BigInteger dpnId, long serviceId,
413         TypedReadWriteTransaction<Configuration> confTx) {
414
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",
420                 dpnId, serviceId);
421     }
422
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<>();
426
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)));
434             flowPriority = 6;
435         } else {
436             mkMatches.add(new MatchTunnelId(BigInteger.valueOf(serviceId)));
437         }
438
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);
443
444         mdsalManager.addFlow(confTx, dpnId, terminatingServiceTableFlowEntity);
445     }
446
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));
452
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));
461
462         // Install the flow entry in L3_LFIB_TABLE
463         String flowRef = getFlowRef(dpId, NwConstants.L3_LFIB_TABLE, serviceId, "");
464
465         Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.L3_LFIB_TABLE, flowRef,
466             10, flowRef, 0, 0,
467             NwConstants.COOKIE_VM_LFIB_TABLE, matches, instructions);
468
469         mdsalManager.addFlow(confTx, dpId, flowEntity);
470
471         LOG.debug("makeLFibTableEntry : LFIB Entry for dpID {} : label : {} modified successfully", dpId, serviceId);
472     }
473
474     private void removeLFibTableEntry(BigInteger dpnId, long serviceId,
475         TypedReadWriteTransaction<Configuration> confTx) {
476
477         String flowRef = getFlowRef(dpnId, NwConstants.L3_LFIB_TABLE, serviceId, "");
478
479         LOG.debug("removeLFibTableEntry : removing LFib entry with flow ref {}", flowRef);
480
481         mdsalManager.removeFlow(confTx, dpnId, new FlowKey(new FlowId(flowRef)), NwConstants.L3_LFIB_TABLE);
482
483         LOG.debug("removeLFibTableEntry : LFIB Entry for dpID : {} label : {} removed successfully",
484                 dpnId, serviceId);
485     }
486
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();
494             return;
495         }
496
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();
502             return;
503         }
504
505         try {
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());
512
513             SendArpRequestInput sendArpRequestInput = new SendArpRequestInputBuilder().setIpaddress(floatingIpAddress)
514                 .setInterfaceAddress(interfaceAddresses).build();
515
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();
522         }
523     }
524
525     // TODO Clean up the exception handling
526     @SuppressWarnings("checkstyle:IllegalCatch")
527     private void removeFromFloatingIpPortInfo(Uuid floatingIpId) {
528         InstanceIdentifier id = buildfloatingIpIdToPortMappingIdentifier(floatingIpId);
529         try {
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);
537             }
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);
541         }
542     }
543
544 }