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