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