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