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