fff75627529d99576395c3798abcc04ec98d285d
[netvirt.git] / natservice / impl / src / main / java / org / opendaylight / netvirt / natservice / internal / EvpnDnatFlowProgrammer.java
1 /*
2  * Copyright (c) 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
9 package org.opendaylight.netvirt.natservice.internal;
10
11 import static org.opendaylight.controller.md.sal.binding.api.WriteTransaction.CREATE_MISSING_PARENTS;
12 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
13 import static org.opendaylight.genius.infra.Datastore.OPERATIONAL;
14
15 import com.google.common.base.Optional;
16 import com.google.common.util.concurrent.FutureCallback;
17 import com.google.common.util.concurrent.Futures;
18 import com.google.common.util.concurrent.ListenableFuture;
19 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 javax.annotation.Nonnull;
26 import javax.inject.Inject;
27 import javax.inject.Singleton;
28 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
29 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
30 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
31 import org.opendaylight.genius.infra.Datastore.Configuration;
32 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
33 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
34 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
35 import org.opendaylight.genius.infra.TypedWriteTransaction;
36 import org.opendaylight.genius.mdsalutil.ActionInfo;
37 import org.opendaylight.genius.mdsalutil.MDSALUtil;
38 import org.opendaylight.genius.mdsalutil.MatchInfo;
39 import org.opendaylight.genius.mdsalutil.NwConstants;
40 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
41 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetDestination;
42 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
43 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
44 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
45 import org.opendaylight.genius.mdsalutil.matches.MatchTunnelId;
46 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
47 import org.opendaylight.netvirt.bgpmanager.api.IBgpManager;
48 import org.opendaylight.netvirt.fibmanager.api.IFibManager;
49 import org.opendaylight.netvirt.fibmanager.api.RouteOrigin;
50 import org.opendaylight.netvirt.vpnmanager.api.IVpnManager;
51 import org.opendaylight.netvirt.vpnmanager.api.VpnHelper;
52 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
53 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterfaceBuilder;
54 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.vpn._interface.VpnInstanceNames;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInput;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryInputBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.CreateFibEntryOutput;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.FibRpcService;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInput;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryInputBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.fib.rpc.rev160121.RemoveFibEntryOutput;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.Adjacencies;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacenciesOp;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.AdjacenciesOpBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.adjacency.list.Adjacency;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntry;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntryBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.l3vpn.rev130911.vpn._interface.op.data.VpnInterfaceOpDataEntryKey;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
74 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
75 import org.opendaylight.yangtools.yang.common.RpcResult;
76 import org.slf4j.Logger;
77 import org.slf4j.LoggerFactory;
78
79 @Singleton
80 public class EvpnDnatFlowProgrammer {
81     private static final Logger LOG = LoggerFactory.getLogger(EvpnDnatFlowProgrammer.class);
82
83     private static final BigInteger COOKIE_TUNNEL = new BigInteger("9000000", 16);
84
85     private final DataBroker dataBroker;
86     private final ManagedNewTransactionRunner txRunner;
87     private final IMdsalApiManager mdsalManager;
88     private final IBgpManager bgpManager;
89     private final IFibManager fibManager;
90     private final FibRpcService fibService;
91     private final IVpnManager vpnManager;
92     private final NatOverVxlanUtil natOverVxlanUtil;
93
94     @Inject
95     public EvpnDnatFlowProgrammer(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
96                            final IBgpManager bgpManager,
97                            final IFibManager fibManager,
98                            final FibRpcService fibService,
99                            final IVpnManager vpnManager,
100                            final NatOverVxlanUtil natOverVxlanUtil) {
101         this.dataBroker = dataBroker;
102         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
103         this.mdsalManager = mdsalManager;
104         this.bgpManager = bgpManager;
105         this.fibManager = fibManager;
106         this.fibService = fibService;
107         this.vpnManager = vpnManager;
108         this.natOverVxlanUtil = natOverVxlanUtil;
109     }
110
111     public void onAddFloatingIp(final BigInteger dpnId, final String routerName, final long routerId,
112                                 final String vpnName,
113                                 final String internalIp, final String externalIp, final Uuid networkId,
114                                 final String interfaceName,
115                                 final String floatingIpInterface,
116                                 final String floatingIpPortMacAddress,
117                                 final String rd,
118                                 final String nextHopIp, final TypedReadWriteTransaction<Configuration> confTx) {
119     /*
120      *  1) Install the flow INTERNAL_TUNNEL_TABLE (table=36)-> PDNAT_TABLE (table=25) (SNAT VM on DPN1 is
121      *     responding back to FIP VM on DPN2) {SNAT to DNAT traffic on different Hypervisor}
122      *
123      *  2) Install the flow L3_FIB_TABLE (table=21)-> PDNAT_TABLE (table=25) (FIP VM1 to FIP VM2
124      *    Traffic on Same Hypervisor) {DNAT to DNAT on Same Hypervisor}
125      *
126      *  3) Install the flow L3_GW_MAC_TABLE (table=19)-> PDNAT_TABLE (table=25)
127      *    (DC-GW is responding back to FIP VM) {DNAT Reverse traffic})
128      *
129      */
130         long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
131         if (vpnId == NatConstants.INVALID_ID) {
132             LOG.error("onAddFloatingIp : Invalid Vpn Id is found for Vpn Name {}", vpnName);
133             return;
134         }
135         long l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
136         if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
137             LOG.debug("onAddFloatingIp : L3VNI value is not configured in Internet VPN {} and RD {} "
138                     + "Carve-out L3VNI value from OpenDaylight VXLAN VNI Pool and continue with installing "
139                     + "DNAT flows for FloatingIp {}", vpnName, rd, externalIp);
140             l3Vni = natOverVxlanUtil.getInternetVpnVni(vpnName, routerId).longValue();
141         }
142         FloatingIPListener.updateOperationalDS(dataBroker, routerName, interfaceName, NatConstants.DEFAULT_LABEL_VALUE,
143                 internalIp, externalIp);
144         String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
145         //Inform to FIB and BGP
146         NatEvpnUtil.addRoutesForVxLanProvType(dataBroker, bgpManager, fibManager, vpnName, rd, fibExternalIp,
147                 nextHopIp, l3Vni, floatingIpInterface, floatingIpPortMacAddress,
148                 confTx, RouteOrigin.STATIC, dpnId, networkId);
149
150         /* Install the flow table L3_FIB_TABLE (table=21)-> PDNAT_TABLE (table=25)
151          * (SNAT to DNAT reverse traffic: If the DPN has both SNAT and  DNAT configured )
152          */
153         List<ActionInfo> actionInfoFib = new ArrayList<>();
154         actionInfoFib.add(new ActionSetFieldEthernetDestination(new MacAddress(floatingIpPortMacAddress)));
155         List<Instruction> instructionsFib = new ArrayList<>();
156         instructionsFib.add(new InstructionApplyActions(actionInfoFib).buildInstruction(0));
157         instructionsFib.add(new InstructionGotoTable(NwConstants.PDNAT_TABLE).buildInstruction(1));
158
159         CreateFibEntryInput input = new CreateFibEntryInputBuilder().setVpnName(vpnName)
160                 .setSourceDpid(dpnId).setIpAddress(fibExternalIp)
161                 .setServiceId(l3Vni).setIpAddressSource(CreateFibEntryInput.IpAddressSource.FloatingIP)
162                 .setInstruction(instructionsFib).build();
163
164         ListenableFuture<RpcResult<CreateFibEntryOutput>> futureVxlan = fibService.createFibEntry(input);
165         LOG.debug("onAddFloatingIp : Add Floating Ip {} , found associated to fixed port {}",
166                 externalIp, interfaceName);
167         if (floatingIpPortMacAddress != null) {
168             ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, tx -> {
169                 vpnManager.addSubnetMacIntoVpnInstance(vpnName, null, floatingIpPortMacAddress, dpnId, tx);
170                 vpnManager.addArpResponderFlowsToExternalNetworkIps(routerName,
171                         Collections.singleton(externalIp),
172                         floatingIpPortMacAddress, dpnId, networkId);
173             }), LOG, "Error processing floating IP port with MAC address {}", floatingIpPortMacAddress);
174         }
175         final long finalL3Vni = l3Vni;
176         Futures.addCallback(futureVxlan, new FutureCallback<RpcResult<CreateFibEntryOutput>>() {
177
178             @Override
179             public void onFailure(@Nonnull Throwable error) {
180                 LOG.error("onAddFloatingIp : Error {} in custom fib routes install process for Floating "
181                         + "IP Prefix {} on DPN {}", error, externalIp, dpnId);
182             }
183
184             @Override
185             public void onSuccess(@Nonnull RpcResult<CreateFibEntryOutput> result) {
186                 if (result.isSuccessful()) {
187                     ListenableFutures.addErrorLogging(
188                         txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION, innerConfTx -> {
189                             LOG.info("onAddFloatingIp : Successfully installed custom FIB routes for Floating "
190                                 + "IP Prefix {} on DPN {}", externalIp, dpnId);
191                             List<Instruction> instructions = new ArrayList<>();
192                             List<ActionInfo> actionsInfos = new ArrayList<>();
193                             List<Instruction> customInstructions = new ArrayList<>();
194                             customInstructions.add(
195                                 new InstructionGotoTable(NwConstants.PDNAT_TABLE).buildInstruction(0));
196                             actionsInfos.add(new ActionNxResubmit(NwConstants.PDNAT_TABLE));
197                             instructions.add(new InstructionApplyActions(actionsInfos).buildInstruction(0));
198                             /* If more than one floatingIp is available in vpn-to-dpn-list for given dpn id, do not
199                             call for
200                              * installing INTERNAL_TUNNEL_TABLE (table=36) -> PDNAT_TABLE (table=25) flow entry with
201                              * same tunnel_id
202                              * again and again.
203                              */
204                             if (!NatUtil.isFloatingIpPresentForDpn(dataBroker, dpnId, rd, vpnName, externalIp, true)) {
205                                 makeTunnelTableEntry(dpnId, finalL3Vni, instructions, innerConfTx);
206                             }
207                             /* Install the flow L3_GW_MAC_TABLE (table=19)-> PDNAT_TABLE (table=25)
208                              * (DNAT reverse traffic: If the traffic is Initiated from DC-GW to FIP VM (DNAT forward
209                              * traffic))
210                              */
211                             NatEvpnUtil.makeL3GwMacTableEntry(dpnId, vpnId, floatingIpPortMacAddress,
212                                 customInstructions,
213                                 mdsalManager, innerConfTx);
214                         }), LOG, "Error installing DNAT flows");
215                 } else {
216                     LOG.error("onAddFloatingIp : Error {} in rpc call to create custom Fib entries for Floating "
217                             + "IP Prefix {} on DPN {}", result.getErrors(), externalIp, dpnId);
218                 }
219             }
220         }, MoreExecutors.directExecutor());
221
222         //Read the FIP vpn-interface details from Configuration l3vpn:vpn-interfaces model and write into Operational DS
223         InstanceIdentifier<VpnInterface> vpnIfIdentifier = NatUtil.getVpnInterfaceIdentifier(floatingIpInterface);
224         Optional<VpnInterface> optionalVpnInterface =
225                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
226                         LogicalDatastoreType.CONFIGURATION, vpnIfIdentifier);
227         if (optionalVpnInterface.isPresent()) {
228             ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx -> {
229                 for (VpnInstanceNames vpnInstance : optionalVpnInterface.get().nonnullVpnInstanceNames()) {
230                     if (!vpnName.equals(vpnInstance.getVpnName())) {
231                         continue;
232                     }
233                     VpnInterfaceBuilder vpnIfBuilder = new VpnInterfaceBuilder(optionalVpnInterface.get());
234                     Adjacencies adjs = vpnIfBuilder.augmentation(Adjacencies.class);
235                     VpnInterfaceOpDataEntryBuilder vpnIfOpDataEntryBuilder = new VpnInterfaceOpDataEntryBuilder();
236                     vpnIfOpDataEntryBuilder.withKey(new VpnInterfaceOpDataEntryKey(interfaceName, vpnName));
237
238                     List<Adjacency> adjacencyList =
239                         adjs != null && adjs.getAdjacency() != null ? adjs.getAdjacency() : new ArrayList<>();
240                     List<Adjacency> adjacencyListToImport = new ArrayList<>();
241                     for (Adjacency adj : adjacencyList) {
242                         Subnetmap sn = VpnHelper.getSubnetmapFromItsUuid(dataBroker, adj.getSubnetId());
243                         if (!VpnHelper.isSubnetPartOfVpn(sn, vpnName)) {
244                             continue;
245                         }
246                         adjacencyListToImport.add(adj);
247                     }
248                     AdjacenciesOp adjacenciesOp = new AdjacenciesOpBuilder()
249                             .setAdjacency(adjacencyListToImport).build();
250                     vpnIfOpDataEntryBuilder.addAugmentation(AdjacenciesOp.class, adjacenciesOp);
251
252                     LOG.debug("onAddFloatingIp : Add vpnInterface {} to Operational l3vpn:vpn-interfaces-op-data ",
253                             floatingIpInterface);
254                     InstanceIdentifier<VpnInterfaceOpDataEntry> vpnIfIdentifierOpDataEntry =
255                             NatUtil.getVpnInterfaceOpDataEntryIdentifier(interfaceName, vpnName);
256                     tx.put(vpnIfIdentifierOpDataEntry, vpnIfOpDataEntryBuilder.build(), CREATE_MISSING_PARENTS);
257                     break;
258                 }
259             }), LOG, "onAddFloatingIp : Could not write Interface {}, vpnName {}", interfaceName, vpnName);
260         } else {
261             LOG.debug("onAddFloatingIp : No vpnInterface {} found in Configuration l3vpn:vpn-interfaces ",
262                            floatingIpInterface);
263         }
264     }
265
266     public void onRemoveFloatingIp(final BigInteger dpnId, final String vpnName, final String externalIp,
267                                    final String floatingIpInterface, final String floatingIpPortMacAddress,
268                                    final long routerId, TypedReadWriteTransaction<Configuration> confTx) {
269     /*
270      *  1) Remove the flow INTERNAL_TUNNEL_TABLE (table=36)-> PDNAT_TABLE (table=25) (SNAT VM on DPN1 is
271      *     responding back to FIP VM on DPN2) {SNAT to DNAT traffic on different Hypervisor}
272      *
273      *  2) Remove the flow L3_FIB_TABLE (table=21)-> PDNAT_TABLE (table=25) (FIP VM1 to FIP VM2
274      *    Traffic on Same Hypervisor) {DNAT to DNAT on Same Hypervisor}
275      *
276      *  3) Remove the flow L3_GW_MAC_TABLE (table=19)-> PDNAT_TABLE (table=25)
277      *    (DC-GW is responding back to FIP VM) {DNAT Reverse traffic})
278      *
279      */
280         String rd = NatUtil.getVpnRd(dataBroker, vpnName);
281         if (rd == null) {
282             LOG.error("onRemoveFloatingIp : Could not retrieve RD value from VPN Name {}  ", vpnName);
283             return;
284         }
285         long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
286         if (vpnId == NatConstants.INVALID_ID) {
287             LOG.error("onRemoveFloatingIp : Invalid Vpn Id is found for Vpn Name {}", vpnName);
288             return;
289         }
290         long l3Vni = NatEvpnUtil.getL3Vni(dataBroker, rd);
291         if (l3Vni == NatConstants.DEFAULT_L3VNI_VALUE) {
292             LOG.debug("onRemoveFloatingIp : L3VNI value is not configured in Internet VPN {} and RD {} "
293                     + "Carve-out L3VNI value from OpenDaylight VXLAN VNI Pool and continue with installing "
294                     + "DNAT flows for FloatingIp {}", vpnName, rd, externalIp);
295             l3Vni = natOverVxlanUtil.getInternetVpnVni(vpnName, routerId).longValue();
296         }
297         String fibExternalIp = NatUtil.validateAndAddNetworkMask(externalIp);
298
299         //Remove Prefix from BGP
300         NatUtil.removePrefixFromBGP(bgpManager, fibManager, rd, fibExternalIp, vpnName, LOG);
301
302         //Remove custom FIB routes flow for L3_FIB_TABLE (table=21)-> PDNAT_TABLE (table=25)
303         RemoveFibEntryInput input = new RemoveFibEntryInputBuilder().setVpnName(vpnName)
304                 .setSourceDpid(dpnId).setIpAddress(fibExternalIp).setServiceId(l3Vni)
305                 .setIpAddressSource(RemoveFibEntryInput.IpAddressSource.FloatingIP).build();
306         ListenableFuture<RpcResult<RemoveFibEntryOutput>> futureVxlan = fibService.removeFibEntry(input);
307         final long finalL3Vni = l3Vni;
308         Futures.addCallback(futureVxlan, new FutureCallback<RpcResult<RemoveFibEntryOutput>>() {
309
310             @Override
311             public void onFailure(@Nonnull Throwable error) {
312                 LOG.error("onRemoveFloatingIp : Error {} in custom fib routes remove process for Floating "
313                         + "IP Prefix {} on DPN {}", error, externalIp, dpnId);
314             }
315
316             @Override
317             public void onSuccess(@Nonnull RpcResult<RemoveFibEntryOutput> result) {
318                 if (result.isSuccessful()) {
319                     ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
320                         innerConfTx -> {
321                             LOG.info("onRemoveFloatingIp : Successfully removed custom FIB routes for Floating "
322                                 + "IP Prefix {} on DPN {}", externalIp, dpnId);
323                             /*  check if any floating IP information is available in vpn-to-dpn-list for given dpn id.
324                              *  If exist any floating IP then do not remove
325                              *  INTERNAL_TUNNEL_TABLE (table=36) -> PDNAT_TABLE (table=25) flow entry.
326                              */
327                             if (!NatUtil.isFloatingIpPresentForDpn(dataBroker, dpnId, rd, vpnName, externalIp, false)) {
328                                 //Remove the flow for INTERNAL_TUNNEL_TABLE (table=36)-> PDNAT_TABLE (table=25)
329                                 removeTunnelTableEntry(dpnId, finalL3Vni, innerConfTx);
330                             }
331                             //Remove the flow for L3_GW_MAC_TABLE (table=19)-> PDNAT_TABLE (table=25)
332                             NatEvpnUtil.removeL3GwMacTableEntry(dpnId, vpnId, floatingIpPortMacAddress, mdsalManager,
333                                 innerConfTx);
334                         }), LOG, "Error removing flows");
335                 } else {
336                     LOG.error("onRemoveFloatingIp : Error {} in rpc call to remove custom Fib entries for Floating "
337                             + "IP Prefix {} on DPN {}", result.getErrors(), externalIp, dpnId);
338                 }
339             }
340         }, MoreExecutors.directExecutor());
341         //Read the FIP vpn-interface details from Operational l3vpn:vpn-interfaces model and delete from Operational DS
342         InstanceIdentifier<VpnInterface> vpnIfIdentifier = NatUtil.getVpnInterfaceIdentifier(floatingIpInterface);
343         Optional<VpnInterface> optionalVpnInterface =
344                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
345                         LogicalDatastoreType.CONFIGURATION, vpnIfIdentifier);
346         if (optionalVpnInterface.isPresent()) {
347             ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(OPERATIONAL, tx -> {
348                 for (VpnInstanceNames vpnInstance : optionalVpnInterface.get().nonnullVpnInstanceNames()) {
349                     if (!vpnName.equals(vpnInstance.getVpnName())) {
350                         continue;
351                     }
352                     InstanceIdentifier<VpnInterfaceOpDataEntry> vpnOpIfIdentifier = NatUtil
353                             .getVpnInterfaceOpDataEntryIdentifier(floatingIpInterface, vpnName);
354                     tx.delete(vpnOpIfIdentifier);
355                     break;
356                 }
357             }), LOG, "onRemoveFloatingIp : Could not remove vpnInterface {}, vpnName {} from Operational "
358                     + "odl-l3vpn:vpn-interface-op-data", floatingIpInterface, vpnName);
359
360             LOG.debug("onRemoveFloatingIp : Remove vpnInterface {} vpnName {} "
361                      + "to Operational odl-l3vpn:vpn-interface-op-data", floatingIpInterface, vpnName);
362         } else {
363             LOG.debug("onRemoveFloatingIp : No vpnInterface {} found "
364                     + "in Operational odl-l3vpn:vpn-interface-op-data", floatingIpInterface);
365         }
366     }
367
368     private void makeTunnelTableEntry(BigInteger dpnId, long l3Vni, List<Instruction> customInstructions,
369                                       TypedWriteTransaction<Configuration> confTx) {
370         LOG.debug("makeTunnelTableEntry : Create terminating service table {} --> table {} flow on DpnId {} "
371                 + "with l3Vni {} as matching parameter", NwConstants.INTERNAL_TUNNEL_TABLE, NwConstants.PDNAT_TABLE,
372                 dpnId, l3Vni);
373         List<MatchInfo> mkMatches = new ArrayList<>();
374         mkMatches.add(new MatchTunnelId(BigInteger.valueOf(l3Vni)));
375         Flow terminatingServiceTableFlowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
376                 NatEvpnUtil.getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, l3Vni, NatConstants.DNAT_FLOW_NAME), 6,
377                 String.format("%s:%d", "TST Flow Entry ", l3Vni),
378                 0, 0, COOKIE_TUNNEL.add(BigInteger.valueOf(l3Vni)), mkMatches, customInstructions);
379         mdsalManager.addFlow(confTx, dpnId, terminatingServiceTableFlowEntity);
380         LOG.debug("makeTunnelTableEntry : Successfully installed terminating service table flow {} on DpnId {}",
381                 terminatingServiceTableFlowEntity, dpnId);
382     }
383
384     private void removeTunnelTableEntry(BigInteger dpnId, long l3Vni, TypedReadWriteTransaction<Configuration> confTx)
385             throws ExecutionException, InterruptedException {
386         LOG.debug("removeTunnelTableEntry : Remove terminating service table {} --> table {} flow on DpnId {} "
387                 + "with l3Vni {} as matching parameter", NwConstants.INTERNAL_TUNNEL_TABLE, NwConstants.PDNAT_TABLE,
388                 dpnId, l3Vni);
389         List<MatchInfo> mkMatches = new ArrayList<>();
390         mkMatches.add(new MatchTunnelId(BigInteger.valueOf(l3Vni)));
391         Flow flowEntity = MDSALUtil.buildFlowNew(NwConstants.INTERNAL_TUNNEL_TABLE,
392                 NatEvpnUtil.getFlowRef(dpnId, NwConstants.INTERNAL_TUNNEL_TABLE, l3Vni, NatConstants.DNAT_FLOW_NAME),
393                 6, String.format("%s:%d", "TST Flow Entry ", l3Vni), 0, 0,
394                 COOKIE_TUNNEL.add(BigInteger.valueOf(l3Vni)), mkMatches, null);
395         mdsalManager.removeFlow(confTx, dpnId, flowEntity);
396         LOG.debug("removeTunnelTableEntry : Successfully removed terminating service table flow {} on DpnId {}",
397                 flowEntity, dpnId);
398     }
399 }