Datastore txes: natservice, part 2
[netvirt.git] / natservice / impl / src / main / java / org / opendaylight / netvirt / natservice / internal / FloatingIPListener.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
12 import com.google.common.base.Optional;
13 import java.math.BigInteger;
14 import java.net.InetAddress;
15 import java.net.UnknownHostException;
16 import java.util.ArrayList;
17 import java.util.Collections;
18 import java.util.List;
19 import javax.annotation.PostConstruct;
20 import javax.inject.Inject;
21 import javax.inject.Singleton;
22 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
23 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
24 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
25 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
26 import org.opendaylight.genius.infra.Datastore.Configuration;
27 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
28 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
29 import org.opendaylight.genius.infra.TypedReadWriteTransaction;
30 import org.opendaylight.genius.mdsalutil.ActionInfo;
31 import org.opendaylight.genius.mdsalutil.FlowEntity;
32 import org.opendaylight.genius.mdsalutil.InstructionInfo;
33 import org.opendaylight.genius.mdsalutil.MDSALUtil;
34 import org.opendaylight.genius.mdsalutil.MatchInfo;
35 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
36 import org.opendaylight.genius.mdsalutil.NwConstants;
37 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
38 import org.opendaylight.genius.mdsalutil.actions.ActionSetDestinationIp;
39 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldEthernetSource;
40 import org.opendaylight.genius.mdsalutil.actions.ActionSetSourceIp;
41 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
42 import org.opendaylight.genius.mdsalutil.instructions.InstructionGotoTable;
43 import org.opendaylight.genius.mdsalutil.instructions.InstructionWriteMetadata;
44 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
45 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetDestination;
46 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
47 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Destination;
48 import org.opendaylight.genius.mdsalutil.matches.MatchIpv4Source;
49 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
50 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
51 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.MacAddress;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ExternalNetworks;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.FloatingIpInfo;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.ProviderTypes;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.Networks;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.external.networks.NetworksKey;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.RouterPorts;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.Ports;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.PortsBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.PortsKey;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMap;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMapBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.natservice.rev160111.floating.ip.info.router.ports.ports.InternalToExternalPortMapKey;
67 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
68 import org.slf4j.Logger;
69 import org.slf4j.LoggerFactory;
70
71 @Singleton
72 public class FloatingIPListener extends AsyncDataTreeChangeListenerBase<InternalToExternalPortMap, FloatingIPListener> {
73     private static final Logger LOG = LoggerFactory.getLogger(FloatingIPListener.class);
74     private final DataBroker dataBroker;
75     private final ManagedNewTransactionRunner txRunner;
76     private final IMdsalApiManager mdsalManager;
77     private final OdlInterfaceRpcService interfaceManager;
78     private final FloatingIPHandler floatingIPHandler;
79     private final SNATDefaultRouteProgrammer defaultRouteProgrammer;
80     private final JobCoordinator coordinator;
81
82     @Inject
83     public FloatingIPListener(final DataBroker dataBroker, final IMdsalApiManager mdsalManager,
84                               final OdlInterfaceRpcService interfaceManager,
85                               final FloatingIPHandler floatingIPHandler,
86                               final SNATDefaultRouteProgrammer snatDefaultRouteProgrammer,
87                               final JobCoordinator coordinator) {
88         super(InternalToExternalPortMap.class, FloatingIPListener.class);
89         this.dataBroker = dataBroker;
90         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
91         this.mdsalManager = mdsalManager;
92         this.interfaceManager = interfaceManager;
93         this.floatingIPHandler = floatingIPHandler;
94         this.defaultRouteProgrammer = snatDefaultRouteProgrammer;
95         this.coordinator = coordinator;
96     }
97
98     @Override
99     @PostConstruct
100     public void init() {
101         LOG.info("{} init", getClass().getSimpleName());
102         registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
103     }
104
105     @Override
106     protected InstanceIdentifier<InternalToExternalPortMap> getWildCardPath() {
107         return InstanceIdentifier.create(FloatingIpInfo.class).child(RouterPorts.class).child(Ports.class)
108                 .child(InternalToExternalPortMap.class);
109     }
110
111     @Override
112     protected FloatingIPListener getDataTreeChangeListener() {
113         return FloatingIPListener.this;
114     }
115
116     @Override
117     protected void add(final InstanceIdentifier<InternalToExternalPortMap> identifier,
118                        final InternalToExternalPortMap mapping) {
119         LOG.trace("FloatingIPListener add ip mapping method - key: {} value: {}",mapping.key(), mapping);
120         processFloatingIPAdd(identifier, mapping);
121     }
122
123     @Override
124     protected void remove(InstanceIdentifier<InternalToExternalPortMap> identifier, InternalToExternalPortMap mapping) {
125         LOG.trace("FloatingIPListener remove ip mapping method - kkey: {} value: {}",mapping.key(), mapping);
126         processFloatingIPDel(identifier, mapping);
127     }
128
129     @Override
130     protected void update(InstanceIdentifier<InternalToExternalPortMap> identifier, InternalToExternalPortMap
131             original, InternalToExternalPortMap update) {
132         LOG.trace("FloatingIPListener update ip mapping method - key: {}, original: {}, update: {}",
133                 update.key(), original, update);
134     }
135
136     private FlowEntity buildPreDNATFlowEntity(BigInteger dpId, InternalToExternalPortMap mapping, long routerId, long
137             associatedVpn) {
138         String externalIp = mapping.getExternalIp();
139         Uuid floatingIpId = mapping.getExternalId();
140         //Get the FIP MAC address for DNAT
141         String floatingIpPortMacAddress = NatUtil.getFloatingIpPortMacFromFloatingIpId(dataBroker, floatingIpId);
142         if (floatingIpPortMacAddress == null) {
143             LOG.error("buildPreDNATFlowEntity : Unable to retrieve floatingIpPortMacAddress from floating IP UUID {} "
144                     + "for floating IP {}", floatingIpId, externalIp);
145             return null;
146         }
147         LOG.debug("buildPreDNATFlowEntity : Bulding DNAT Flow entity for ip {} ", externalIp);
148         long segmentId = associatedVpn == NatConstants.INVALID_ID ? routerId : associatedVpn;
149         LOG.debug("buildPreDNATFlowEntity : Segment id {} in build preDNAT Flow", segmentId);
150
151         List<MatchInfo> matches = new ArrayList<>();
152         matches.add(MatchEthernetType.IPV4);
153
154         matches.add(new MatchIpv4Destination(externalIp, "32"));
155         //Match Destination Floating IP MAC Address on table = 25 (PDNAT_TABLE)
156         matches.add(new MatchEthernetDestination(new MacAddress(floatingIpPortMacAddress)));
157
158 //        matches.add(new MatchMetadata(
159 //                BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
160         List<ActionInfo> actionsInfos = new ArrayList<>();
161         String internalIp = mapping.getInternalIp();
162         actionsInfos.add(new ActionSetDestinationIp(internalIp, "32"));
163
164         List<InstructionInfo> instructions = new ArrayList<>();
165         instructions.add(new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(segmentId),
166                 MetaDataUtil.METADATA_MASK_VRFID));
167         instructions.add(new InstructionApplyActions(actionsInfos));
168         instructions.add(new InstructionGotoTable(NwConstants.DNAT_TABLE));
169
170         String flowRef = NatUtil.getFlowRef(dpId, NwConstants.PDNAT_TABLE, routerId, externalIp);
171
172         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PDNAT_TABLE, flowRef,
173                 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
174                 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
175
176         return flowEntity;
177     }
178
179     private FlowEntity buildDNATFlowEntity(BigInteger dpId, InternalToExternalPortMap mapping, long routerId, long
180             associatedVpn) {
181         String externalIp = mapping.getExternalIp();
182         LOG.info("buildDNATFlowEntity : Bulding DNAT Flow entity for ip {} ", externalIp);
183
184         long segmentId = associatedVpn == NatConstants.INVALID_ID ? routerId : associatedVpn;
185         LOG.debug("buildDNATFlowEntity : Segment id {} in build DNAT", segmentId);
186
187         List<MatchInfo> matches = new ArrayList<>();
188         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID));
189
190         matches.add(MatchEthernetType.IPV4);
191         String internalIp = mapping.getInternalIp();
192         matches.add(new MatchIpv4Destination(internalIp, "32"));
193
194         List<ActionInfo> actionsInfos = new ArrayList<>();
195 //        actionsInfos.add(new ActionSetDestinationIp(internalIp, "32"));
196
197         List<InstructionInfo> instructions = new ArrayList<>();
198 //        instructions.add(new InstructionWriteMetadata(BigInteger.valueOf
199 //                (routerId), MetaDataUtil.METADATA_MASK_VRFID));
200         actionsInfos.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
201         instructions.add(new InstructionApplyActions(actionsInfos));
202         //instructions.add(new InstructionGotoTable(NatConstants.L3_FIB_TABLE));
203
204         String flowRef = NatUtil.getFlowRef(dpId, NwConstants.DNAT_TABLE, routerId, internalIp);
205
206         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.DNAT_TABLE, flowRef,
207                 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
208                 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
209
210         return flowEntity;
211
212     }
213
214     private FlowEntity buildPreSNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long vpnId, long
215             routerId, long associatedVpn) {
216
217         LOG.debug("buildPreSNATFlowEntity : Building PSNAT Flow entity for ip {} ", internalIp);
218
219         long segmentId = associatedVpn == NatConstants.INVALID_ID ? routerId : associatedVpn;
220
221         LOG.debug("buildPreSNATFlowEntity : Segment id {} in build preSNAT flow", segmentId);
222
223         List<MatchInfo> matches = new ArrayList<>();
224         matches.add(MatchEthernetType.IPV4);
225
226         matches.add(new MatchIpv4Source(internalIp, "32"));
227
228         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(segmentId), MetaDataUtil.METADATA_MASK_VRFID));
229
230         List<ActionInfo> actionsInfos = new ArrayList<>();
231         actionsInfos.add(new ActionSetSourceIp(externalIp, "32"));
232
233         List<InstructionInfo> instructions = new ArrayList<>();
234         instructions.add(
235                 new InstructionWriteMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
236         instructions.add(new InstructionApplyActions(actionsInfos));
237         instructions.add(new InstructionGotoTable(NwConstants.SNAT_TABLE));
238
239         String flowRef = NatUtil.getFlowRef(dpId, NwConstants.PSNAT_TABLE, routerId, internalIp);
240
241         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
242                 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
243                 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
244
245         return flowEntity;
246     }
247
248     private FlowEntity buildSNATFlowEntity(BigInteger dpId, InternalToExternalPortMap mapping, long vpnId, Uuid
249             externalNetworkId) {
250         String internalIp = mapping.getInternalIp();
251         LOG.debug("buildSNATFlowEntity : Building SNAT Flow entity for ip {} ", internalIp);
252
253         ProviderTypes provType = NatUtil.getProviderTypefromNetworkId(dataBroker, externalNetworkId);
254         if (provType == null) {
255             LOG.error("buildSNATFlowEntity : Unable to get Network Provider Type for network {}", externalNetworkId);
256             return null;
257         }
258
259         List<MatchInfo> matches = new ArrayList<>();
260         matches.add(new MatchMetadata(MetaDataUtil.getVpnIdMetadata(vpnId), MetaDataUtil.METADATA_MASK_VRFID));
261         matches.add(MatchEthernetType.IPV4);
262         String externalIp = mapping.getExternalIp();
263         matches.add(new MatchIpv4Source(externalIp, "32"));
264
265         List<ActionInfo> actionsInfo = new ArrayList<>();
266         Uuid floatingIpId = mapping.getExternalId();
267         String macAddress = NatUtil.getFloatingIpPortMacFromFloatingIpId(dataBroker, floatingIpId);
268         if (macAddress != null) {
269             actionsInfo.add(new ActionSetFieldEthernetSource(new MacAddress(macAddress)));
270         } else {
271             LOG.warn("buildSNATFlowEntity : No MAC address found for floating IP {}", externalIp);
272         }
273
274         LOG.trace("buildSNATFlowEntity : External Network Provider Type is {}, resubmit to FIB", provType.toString());
275         actionsInfo.add(new ActionNxResubmit(NwConstants.L3_FIB_TABLE));
276         List<InstructionInfo> instructions = new ArrayList<>();
277         instructions.add(new InstructionApplyActions(actionsInfo));
278         String flowRef = NatUtil.getFlowRef(dpId, NwConstants.SNAT_TABLE, vpnId, externalIp);
279
280         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.SNAT_TABLE, flowRef,
281                 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
282                 NwConstants.COOKIE_DNAT_TABLE, matches, instructions);
283
284         return flowEntity;
285
286     }
287
288     private void createDNATTblEntry(BigInteger dpnId, InternalToExternalPortMap mapping, long routerId,
289                                     long associatedVpnId, TypedReadWriteTransaction<Configuration> confTx) {
290         FlowEntity preFlowEntity = buildPreDNATFlowEntity(dpnId, mapping, routerId, associatedVpnId);
291         if (preFlowEntity == null) {
292             LOG.error("createDNATTblEntry : Flow entity received as NULL. "
293                     + "Cannot proceed with installation of Pre-DNAT flow table {} --> table {} on DpnId {}",
294                     NwConstants.PDNAT_TABLE, NwConstants.DNAT_TABLE, dpnId);
295         } else {
296             mdsalManager.addFlow(confTx, preFlowEntity);
297             FlowEntity flowEntity = buildDNATFlowEntity(dpnId, mapping, routerId, associatedVpnId);
298             if (flowEntity != null) {
299                 mdsalManager.addFlow(confTx, flowEntity);
300             }
301         }
302     }
303
304     private void removeDNATTblEntry(BigInteger dpnId, String internalIp, String externalIp, long routerId,
305         TypedReadWriteTransaction<Configuration> confTx) {
306         FlowEntity preFlowEntity = buildPreDNATDeleteFlowEntity(dpnId, externalIp, routerId);
307         mdsalManager.removeFlow(confTx, preFlowEntity);
308
309         FlowEntity flowEntity = buildDNATDeleteFlowEntity(dpnId, internalIp, routerId);
310         if (flowEntity != null) {
311             mdsalManager.removeFlow(confTx, flowEntity);
312         }
313     }
314
315     private void createSNATTblEntry(BigInteger dpnId, InternalToExternalPortMap mapping, long vpnId, long routerId,
316         long associatedVpnId, Uuid externalNetworkId, TypedReadWriteTransaction<Configuration> confTx) {
317         FlowEntity preFlowEntity = buildPreSNATFlowEntity(dpnId, mapping.getInternalIp(), mapping.getExternalIp(),
318             vpnId, routerId, associatedVpnId);
319         mdsalManager.addFlow(confTx, preFlowEntity);
320
321         FlowEntity flowEntity = buildSNATFlowEntity(dpnId, mapping, vpnId, externalNetworkId);
322         if (flowEntity != null) {
323             mdsalManager.addFlow(confTx, flowEntity);
324         }
325     }
326
327     private void removeSNATTblEntry(BigInteger dpnId, String internalIp, String externalIp, long routerId, long vpnId,
328                                     TypedReadWriteTransaction<Configuration> removeFlowInvTx) {
329         FlowEntity preFlowEntity = buildPreSNATDeleteFlowEntity(dpnId, internalIp, routerId);
330         mdsalManager.removeFlow(removeFlowInvTx, preFlowEntity);
331
332         FlowEntity flowEntity = buildSNATDeleteFlowEntity(dpnId, externalIp, vpnId);
333         if (flowEntity != null) {
334             mdsalManager.removeFlow(removeFlowInvTx, flowEntity);
335         }
336     }
337
338     private Uuid getExtNetworkId(final InstanceIdentifier<RouterPorts> portIid,
339                                  LogicalDatastoreType dataStoreType) {
340         Optional<RouterPorts> rtrPort =
341                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
342                         dataStoreType, portIid);
343         if (!rtrPort.isPresent()) {
344             LOG.error("getExtNetworkId : Unable to read router port entry for {}", portIid);
345             return null;
346         }
347
348         Uuid extNwId = rtrPort.get().getExternalNetworkId();
349         return extNwId;
350     }
351
352     private long getVpnId(Uuid extNwId, Uuid floatingIpExternalId) {
353         Uuid subnetId = NatUtil.getFloatingIpPortSubnetIdFromFloatingIpId(dataBroker, floatingIpExternalId);
354         if (subnetId != null) {
355             long vpnId = NatUtil.getVpnId(dataBroker, subnetId.getValue());
356             if (vpnId != NatConstants.INVALID_ID) {
357                 LOG.debug("getVpnId : Got vpnId {} for floatingIpExternalId {}", vpnId, floatingIpExternalId);
358                 return vpnId;
359             }
360         }
361
362         InstanceIdentifier<Networks> nwId = InstanceIdentifier.builder(ExternalNetworks.class).child(Networks.class,
363                 new NetworksKey(extNwId)).build();
364         Optional<Networks> nw =
365                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
366                         LogicalDatastoreType.CONFIGURATION, nwId);
367         if (!nw.isPresent()) {
368             LOG.error("getVpnId : Unable to read external network for {}", extNwId);
369             return NatConstants.INVALID_ID;
370         }
371
372         Uuid vpnUuid = nw.get().getVpnid();
373         if (vpnUuid == null) {
374             LOG.error("getVpnId : Unable to read vpn from External network: {}", extNwId);
375             return NatConstants.INVALID_ID;
376         }
377
378         //Get the id using the VPN UUID (also vpn instance name)
379         return NatUtil.getVpnId(dataBroker, vpnUuid.getValue());
380     }
381
382     private void processFloatingIPAdd(final InstanceIdentifier<InternalToExternalPortMap> identifier,
383                                       final InternalToExternalPortMap mapping) {
384         LOG.trace("processFloatingIPAdd key: {}, value: {}", mapping.key(), mapping);
385
386         final String routerId = identifier.firstKeyOf(RouterPorts.class).getRouterId();
387         final PortsKey pKey = identifier.firstKeyOf(Ports.class);
388         String interfaceName = pKey.getPortName();
389
390         InstanceIdentifier<RouterPorts> portIid = identifier.firstIdentifierOf(RouterPorts.class);
391         coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + mapping.key(), () -> Collections.singletonList(
392                 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
393                     tx -> createNATFlowEntries(interfaceName, mapping, portIid, routerId, tx))),
394                 NatConstants.NAT_DJC_MAX_RETRIES);
395     }
396
397     private void processFloatingIPDel(final InstanceIdentifier<InternalToExternalPortMap> identifier,
398                                       final InternalToExternalPortMap mapping) {
399         LOG.trace("processFloatingIPDel : key: {}, value: {}", mapping.key(), mapping);
400
401         final String routerId = identifier.firstKeyOf(RouterPorts.class).getRouterId();
402         final PortsKey pKey = identifier.firstKeyOf(Ports.class);
403         String interfaceName = pKey.getPortName();
404
405         InstanceIdentifier<RouterPorts> portIid = identifier.firstIdentifierOf(RouterPorts.class);
406         coordinator.enqueueJob(NatConstants.NAT_DJC_PREFIX + mapping.key(), () -> Collections.singletonList(
407                 txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
408                     tx -> removeNATFlowEntries(interfaceName, mapping, portIid, routerId, null, tx))),
409                 NatConstants.NAT_DJC_MAX_RETRIES);
410     }
411
412     private InetAddress getInetAddress(String ipAddr) {
413         InetAddress ipAddress = null;
414         try {
415             ipAddress = InetAddress.getByName(ipAddr);
416         } catch (UnknownHostException e) {
417             LOG.error("getInetAddress : UnknowHostException for ip {}", ipAddr, e);
418         }
419         return ipAddress;
420     }
421
422     private boolean validateIpMapping(InternalToExternalPortMap mapping) {
423         return getInetAddress(mapping.getInternalIp()) != null && getInetAddress(mapping.getExternalIp()) != null;
424     }
425
426     void createNATFlowEntries(String interfaceName, final InternalToExternalPortMap mapping,
427                               final InstanceIdentifier<RouterPorts> portIid, final String routerName,
428         TypedReadWriteTransaction<Configuration> confTx) {
429         if (!validateIpMapping(mapping)) {
430             LOG.error("createNATFlowEntries : Not a valid ip addresses in the mapping {}", mapping);
431             return;
432         }
433
434         //Get the DPN on which this interface resides
435         BigInteger dpnId = NatUtil.getDpnForInterface(interfaceManager, interfaceName);
436
437         if (dpnId.equals(BigInteger.ZERO)) {
438             LOG.warn("createNATFlowEntries : No DPN for interface {}. NAT flow entries for ip mapping {} will "
439                 + "not be installed", interfaceName, mapping);
440             return;
441         }
442
443         long routerId = NatUtil.getVpnId(dataBroker, routerName);
444         if (routerId == NatConstants.INVALID_ID) {
445             LOG.error("createNATFlowEntries : Could not retrieve router id for {} to create NAT Flow entries",
446                     routerName);
447             return;
448         }
449         //Check if the router to vpn association is present
450         //long associatedVpnId = NatUtil.getAssociatedVpn(dataBroker, routerName);
451         Uuid associatedVpn = NatUtil.getVpnForRouter(dataBroker, routerName);
452         long associatedVpnId = NatConstants.INVALID_ID;
453         if (associatedVpn == null) {
454             LOG.debug("createNATFlowEntries : Router {} is not assicated with any BGP VPN instance", routerName);
455         } else {
456             LOG.debug("createNATFlowEntries : Router {} is associated with VPN Instance with Id {}",
457                     routerName, associatedVpn);
458             associatedVpnId = NatUtil.getVpnId(dataBroker, associatedVpn.getValue());
459             LOG.debug("createNATFlowEntries : vpninstance Id is {} for VPN {}", associatedVpnId, associatedVpn);
460             //routerId = associatedVpnId;
461         }
462
463         Uuid extNwId = getExtNetworkId(portIid, LogicalDatastoreType.CONFIGURATION);
464         if (extNwId == null) {
465             LOG.error("createNATFlowEntries : External network associated with interface {} could not be retrieved",
466                 interfaceName);
467             return;
468         }
469         long vpnId = getVpnId(extNwId, mapping.getExternalId());
470         if (vpnId < 0) {
471             LOG.error("createNATFlowEntries : No VPN associated with Ext nw {}. Unable to create SNAT table entry "
472                     + "for fixed ip {}", extNwId, mapping.getInternalIp());
473             return;
474         }
475         //Install the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
476         boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
477         if (!isSnatEnabled) {
478             addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, confTx, true);
479         }
480         //Create the DNAT and SNAT table entries
481         createDNATTblEntry(dpnId, mapping, routerId, associatedVpnId, confTx);
482         createSNATTblEntry(dpnId, mapping, vpnId, routerId, associatedVpnId, extNwId, confTx);
483         floatingIPHandler.onAddFloatingIp(dpnId, routerName, routerId, extNwId, interfaceName, mapping, confTx);
484     }
485
486     void createNATFlowEntries(BigInteger dpnId,  String interfaceName, String routerName, Uuid externalNetworkId,
487                               InternalToExternalPortMap mapping, TypedReadWriteTransaction<Configuration> confTx) {
488         String internalIp = mapping.getInternalIp();
489         long routerId = NatUtil.getVpnId(dataBroker, routerName);
490         if (routerId == NatConstants.INVALID_ID) {
491             LOG.error("createNATFlowEntries : Could not retrieve router id for {} to create NAT Flow entries",
492                     routerName);
493             return;
494         }
495         //Check if the router to vpn association is present
496         long associatedVpnId = NatUtil.getAssociatedVpn(dataBroker, routerName);
497         if (associatedVpnId == NatConstants.INVALID_ID) {
498             LOG.debug("createNATFlowEntries : Router {} is not assicated with any BGP VPN instance", routerName);
499         } else {
500             LOG.debug("createNATFlowEntries : Router {} is associated with VPN Instance with Id {}",
501                 routerName, associatedVpnId);
502             //routerId = associatedVpnId;
503         }
504
505         long vpnId = getVpnId(externalNetworkId, mapping.getExternalId());
506         if (vpnId < 0) {
507             LOG.error("createNATFlowEntries : Unable to create SNAT table entry for fixed ip {}", internalIp);
508             return;
509         }
510         //Install the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
511         boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
512         if (!isSnatEnabled) {
513             addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, confTx, true);
514         }
515         //Create the DNAT and SNAT table entries
516         createDNATTblEntry(dpnId, mapping, routerId, associatedVpnId, confTx);
517         createSNATTblEntry(dpnId, mapping, vpnId, routerId, associatedVpnId, externalNetworkId, confTx);
518         floatingIPHandler.onAddFloatingIp(dpnId, routerName, routerId, externalNetworkId, interfaceName, mapping,
519                 confTx);
520     }
521
522     void createNATOnlyFlowEntries(BigInteger dpnId, String routerName, String associatedVPN,
523                                   Uuid externalNetworkId, InternalToExternalPortMap mapping) {
524         String internalIp = mapping.getInternalIp();
525         //String segmentId = associatedVPN == null ? routerName : associatedVPN;
526         LOG.debug("createNATOnlyFlowEntries : Retrieving vpn id for VPN {} to proceed with create NAT Flows",
527                 routerName);
528         long routerId = NatUtil.getVpnId(dataBroker, routerName);
529         if (routerId == NatConstants.INVALID_ID) {
530             LOG.error("createNATOnlyFlowEntries : Could not retrieve vpn id for {} to create NAT Flow entries",
531                     routerName);
532             return;
533         }
534         long associatedVpnId = NatUtil.getVpnId(dataBroker, associatedVPN);
535         LOG.debug("createNATOnlyFlowEntries : Associated VPN Id {} for router {}", associatedVpnId, routerName);
536         long vpnId = getVpnId(externalNetworkId, mapping.getExternalId());
537         if (vpnId < 0) {
538             LOG.error("createNATOnlyFlowEntries : Unable to create SNAT table entry for fixed ip {}", internalIp);
539             return;
540         }
541         //Install the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
542         boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
543         if (!isSnatEnabled) {
544             addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, null, true);
545         }
546         //Create the DNAT and SNAT table entries
547         FlowEntity preFlowEntity = buildPreDNATFlowEntity(dpnId, mapping, routerId, associatedVpnId);
548         mdsalManager.installFlow(preFlowEntity);
549
550         FlowEntity flowEntity = buildDNATFlowEntity(dpnId, mapping, routerId, associatedVpnId);
551         mdsalManager.installFlow(flowEntity);
552
553         String externalIp = mapping.getExternalIp();
554         preFlowEntity = buildPreSNATFlowEntity(dpnId, internalIp, externalIp, vpnId , routerId, associatedVpnId);
555         mdsalManager.installFlow(preFlowEntity);
556
557         flowEntity = buildSNATFlowEntity(dpnId, mapping, vpnId, externalNetworkId);
558         if (flowEntity != null) {
559             mdsalManager.installFlow(flowEntity);
560         }
561
562     }
563
564     void removeNATFlowEntries(String interfaceName, final InternalToExternalPortMap mapping,
565                               InstanceIdentifier<RouterPorts> portIid, final String routerName, BigInteger dpnId,
566                               TypedReadWriteTransaction<Configuration> removeFlowInvTx) {
567         String internalIp = mapping.getInternalIp();
568         String externalIp = mapping.getExternalIp();
569         //Get the DPN on which this interface resides
570         if (dpnId == null) {
571             dpnId = NatUtil.getDpnForInterface(interfaceManager, interfaceName);
572             if (dpnId.equals(BigInteger.ZERO)) {
573                 LOG.warn("removeNATFlowEntries: Abort processing Floating ip configuration. No DPN for port: {}",
574                         interfaceName);
575                 return;
576             }
577         }
578
579         long routerId = NatUtil.getVpnId(dataBroker, routerName);
580         if (routerId == NatConstants.INVALID_ID) {
581             LOG.error("removeNATFlowEntries : Could not retrieve router id for {} to remove NAT Flow entries",
582                     routerName);
583             return;
584         }
585
586         //Delete the DNAT and SNAT table entries
587         removeDNATTblEntry(dpnId, internalIp, externalIp, routerId, removeFlowInvTx);
588
589         Uuid extNwId = getExtNetworkId(portIid, LogicalDatastoreType.OPERATIONAL);
590         if (extNwId == null) {
591             LOG.error("removeNATFlowEntries : External network associated with interface {} could not be retrieved",
592                 interfaceName);
593             return;
594         }
595         long vpnId = getVpnId(extNwId, mapping.getExternalId());
596         if (vpnId < 0) {
597             LOG.error("removeNATFlowEntries : No VPN associated with ext nw {}. Unable to delete SNAT table "
598                 + "entry for fixed ip {}", extNwId, internalIp);
599             return;
600         }
601         removeSNATTblEntry(dpnId, internalIp, externalIp, routerId, vpnId, removeFlowInvTx);
602         //Remove the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
603         boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
604         if (!isSnatEnabled) {
605             addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, removeFlowInvTx, false);
606         }
607         ProviderTypes provType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, extNwId);
608         if (provType == null) {
609             LOG.error("removeNATFlowEntries : External Network Provider Type missing");
610             return;
611         }
612         if (provType == ProviderTypes.VXLAN) {
613             floatingIPHandler.onRemoveFloatingIp(dpnId, routerName, routerId, extNwId, mapping,
614                     NatConstants.DEFAULT_L3VNI_VALUE, removeFlowInvTx);
615             removeOperationalDS(routerName, interfaceName, internalIp);
616             return;
617         }
618         long label = getOperationalIpMapping(routerName, interfaceName, internalIp);
619         if (label < 0) {
620             LOG.error("removeNATFlowEntries : Could not retrieve label for prefix {} in router {}",
621                     internalIp, routerId);
622             return;
623         }
624         floatingIPHandler.onRemoveFloatingIp(dpnId, routerName, routerId, extNwId, mapping, (int) label,
625                 removeFlowInvTx);
626         removeOperationalDS(routerName, interfaceName, internalIp);
627     }
628
629     void removeNATFlowEntries(BigInteger dpnId, String interfaceName, String vpnName, String routerName,
630                               InternalToExternalPortMap mapping, TypedReadWriteTransaction<Configuration> confTx) {
631         String internalIp = mapping.getInternalIp();
632         String externalIp = mapping.getExternalIp();
633         long routerId = NatUtil.getVpnId(dataBroker, routerName);
634         if (routerId == NatConstants.INVALID_ID) {
635             LOG.error("removeNATFlowEntries : Could not retrieve router id for {} to remove NAT Flow entries",
636                     routerName);
637             return;
638         }
639
640         long vpnId = NatUtil.getVpnId(dataBroker, vpnName);
641         if (vpnId == NatConstants.INVALID_ID) {
642             LOG.warn("removeNATFlowEntries : VPN Id not found for {} to remove NAT flow entries {}",
643                     vpnName, internalIp);
644         }
645
646         //Delete the DNAT and SNAT table entries
647         removeDNATTblEntry(dpnId, internalIp, externalIp, routerId, confTx);
648         removeSNATTblEntry(dpnId, internalIp, externalIp, routerId, vpnId, confTx);
649         //Remove the DNAT default FIB flow L3_FIB_TABLE (21) -> PSNAT_TABLE (26) if SNAT is disabled
650         boolean isSnatEnabled = NatUtil.isSnatEnabledForRouterId(dataBroker, routerName);
651         if (!isSnatEnabled) {
652             addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, confTx, false);
653         }
654         Uuid externalNetworkId = NatUtil.getNetworkIdFromRouterName(dataBroker,routerName);
655         ProviderTypes provType = NatEvpnUtil.getExtNwProvTypeFromRouterName(dataBroker, routerName, externalNetworkId);
656         if (provType == null) {
657             LOG.error("removeNATFlowEntries : External Network Provider Type Missing");
658             return;
659         }
660         if (provType == ProviderTypes.VXLAN) {
661             floatingIPHandler.cleanupFibEntries(dpnId, vpnName, externalIp, NatConstants.DEFAULT_L3VNI_VALUE,
662                     confTx, provType);
663             removeOperationalDS(routerName, interfaceName, internalIp);
664             return;
665         }
666         long label = getOperationalIpMapping(routerName, interfaceName, internalIp);
667         if (label < 0) {
668             LOG.error("removeNATFlowEntries : Could not retrieve label for prefix {} in router {}",
669                     internalIp, routerId);
670             return;
671         }
672         floatingIPHandler.cleanupFibEntries(dpnId, vpnName, externalIp, label, confTx, provType);
673         removeOperationalDS(routerName, interfaceName, internalIp);
674     }
675
676     protected long getOperationalIpMapping(String routerId, String interfaceName, String internalIp) {
677         InstanceIdentifier<InternalToExternalPortMap> intExtPortMapIdentifier =
678             NatUtil.getIntExtPortMapIdentifier(routerId, interfaceName, internalIp);
679         return SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
680                 LogicalDatastoreType.OPERATIONAL, intExtPortMapIdentifier).toJavaUtil().map(
681                 InternalToExternalPortMap::getLabel).orElse(NatConstants.INVALID_ID);
682     }
683
684     static void updateOperationalDS(DataBroker dataBroker, String routerId, String interfaceName, long label,
685                                     String internalIp, String externalIp) {
686
687         LOG.info("updateOperationalDS : Updating operational DS for floating ip config : {} with label {}",
688                 internalIp, label);
689         InstanceIdentifier<Ports> portsId = NatUtil.getPortsIdentifier(routerId, interfaceName);
690         Optional<Ports> optPorts =
691                 SingleTransactionDataBroker.syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(dataBroker,
692                         LogicalDatastoreType.OPERATIONAL, portsId);
693         InternalToExternalPortMap intExtPortMap = new InternalToExternalPortMapBuilder().withKey(new
694                 InternalToExternalPortMapKey(internalIp)).setInternalIp(internalIp).setExternalIp(externalIp)
695                 .setLabel(label).build();
696         if (optPorts.isPresent()) {
697             LOG.debug("updateOperationalDS : Ports {} entry already present. Updating intExtPortMap for internal ip {}",
698                     interfaceName, internalIp);
699             MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, portsId.child(InternalToExternalPortMap
700                     .class, new InternalToExternalPortMapKey(internalIp)), intExtPortMap);
701         } else {
702             LOG.debug("updateOperationalDS : Adding Ports entry {} along with intExtPortMap {}",
703                     interfaceName, internalIp);
704             List<InternalToExternalPortMap> intExtPortMapList = new ArrayList<>();
705             intExtPortMapList.add(intExtPortMap);
706             Ports ports = new PortsBuilder().withKey(new PortsKey(interfaceName)).setPortName(interfaceName)
707                     .setInternalToExternalPortMap(intExtPortMapList).build();
708             MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.OPERATIONAL, portsId, ports);
709         }
710     }
711
712     void removeOperationalDS(String routerId, String interfaceName, String internalIp) {
713         LOG.info("removeOperationalDS : Remove operational DS for floating ip config: {}", internalIp);
714         InstanceIdentifier<InternalToExternalPortMap> intExtPortMapId = NatUtil.getIntExtPortMapIdentifier(routerId,
715                 interfaceName, internalIp);
716         MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.OPERATIONAL, intExtPortMapId);
717     }
718
719     private FlowEntity buildPreDNATDeleteFlowEntity(BigInteger dpId, String externalIp, long routerId) {
720
721         LOG.info("buildPreDNATDeleteFlowEntity : Bulding Delete DNAT Flow entity for ip {} ", externalIp);
722
723         String flowRef = NatUtil.getFlowRef(dpId, NwConstants.PDNAT_TABLE, routerId, externalIp);
724
725         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PDNAT_TABLE, flowRef,
726                 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
727                 NwConstants.COOKIE_DNAT_TABLE, null, null);
728
729         return flowEntity;
730     }
731
732
733
734     private FlowEntity buildDNATDeleteFlowEntity(BigInteger dpId, String internalIp, long routerId) {
735
736         LOG.info("buildDNATDeleteFlowEntity : Bulding Delete DNAT Flow entity for ip {} ", internalIp);
737
738         String flowRef = NatUtil.getFlowRef(dpId, NwConstants.DNAT_TABLE, routerId, internalIp);
739
740         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.DNAT_TABLE, flowRef,
741                 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
742                 NwConstants.COOKIE_DNAT_TABLE, null, null);
743
744         return flowEntity;
745
746     }
747
748     private FlowEntity buildPreSNATDeleteFlowEntity(BigInteger dpId, String internalIp, long routerId) {
749
750         LOG.info("buildPreSNATDeleteFlowEntity : Building Delete PSNAT Flow entity for ip {} ", internalIp);
751
752         String flowRef = NatUtil.getFlowRef(dpId, NwConstants.PSNAT_TABLE, routerId, internalIp);
753
754         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.PSNAT_TABLE, flowRef,
755                 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
756                 NwConstants.COOKIE_DNAT_TABLE, null, null);
757         return flowEntity;
758     }
759
760     private FlowEntity buildSNATDeleteFlowEntity(BigInteger dpId, String externalIp, long routerId) {
761
762         LOG.info("buildSNATDeleteFlowEntity : Building Delete SNAT Flow entity for ip {} ", externalIp);
763
764         String flowRef = NatUtil.getFlowRef(dpId, NwConstants.SNAT_TABLE, routerId, externalIp);
765
766         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NwConstants.SNAT_TABLE, flowRef,
767                 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
768                 NwConstants.COOKIE_DNAT_TABLE, null, null);
769
770         return flowEntity;
771     }
772
773     private void addOrDelDefaultFibRouteForDnat(BigInteger dpnId, String routerName, long routerId,
774         TypedReadWriteTransaction<Configuration> confTx, boolean create) {
775         if (confTx == null) {
776             ListenableFutures.addErrorLogging(txRunner.callWithNewReadWriteTransactionAndSubmit(CONFIGURATION,
777                 newTx -> addOrDelDefaultFibRouteForDnat(dpnId, routerName, routerId, newTx, create)), LOG,
778                 "Error handling default FIB route for DNAT");
779             return;
780         }
781         //Check if the router to bgp-vpn association is present
782         long associatedVpnId = NatConstants.INVALID_ID;
783         Uuid associatedVpn = NatUtil.getVpnForRouter(dataBroker, routerName);
784         if (associatedVpn != null) {
785             associatedVpnId = NatUtil.getVpnId(dataBroker, associatedVpn.getValue());
786         }
787         if (create) {
788             if (associatedVpnId != NatConstants.INVALID_ID) {
789                 LOG.debug("addOrDelDefaultFibRouteForDnat: Install NAT default route on DPN {} for the router {} with "
790                         + "vpn-id {}", dpnId, routerName, associatedVpnId);
791                 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, associatedVpnId, routerId, confTx);
792             } else {
793                 LOG.debug("addOrDelDefaultFibRouteForDnat: Install NAT default route on DPN {} for the router {} with "
794                         + "vpn-id {}", dpnId, routerName, routerId);
795                 defaultRouteProgrammer.installDefNATRouteInDPN(dpnId, routerId, confTx);
796             }
797         } else {
798             if (associatedVpnId != NatConstants.INVALID_ID) {
799                 LOG.debug("addOrDelDefaultFibRouteForDnat: Remove NAT default route on DPN {} for the router {} "
800                         + "with vpn-id {}", dpnId, routerName, associatedVpnId);
801                 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, associatedVpnId, routerId, confTx);
802             } else {
803                 LOG.debug("addOrDelDefaultFibRouteForDnat: Remove NAT default route on DPN {} for the router {} "
804                         + "with vpn-id {}", dpnId, routerName, routerId);
805                 defaultRouteProgrammer.removeDefNATRouteInDPN(dpnId, routerId, confTx);
806             }
807         }
808     }
809 }