Bump versions by 0.1.0 for next dev cycle
[vpnservice.git] / natservice / natservice-impl / src / main / java / org / opendaylight / vpnservice / natservice / internal / FloatingIPListener.java
1 /*
2  * Copyright (c) 2016 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.vpnservice.natservice.internal;
9
10 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
11 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
12 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
13 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
14 import org.opendaylight.vpnservice.mdsalutil.ActionInfo;
15 import org.opendaylight.vpnservice.mdsalutil.ActionType;
16 import org.opendaylight.vpnservice.mdsalutil.FlowEntity;
17 import org.opendaylight.vpnservice.mdsalutil.InstructionInfo;
18 import org.opendaylight.vpnservice.mdsalutil.InstructionType;
19 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;
20 import org.opendaylight.vpnservice.mdsalutil.MatchFieldType;
21 import org.opendaylight.vpnservice.mdsalutil.MatchInfo;
22 import org.opendaylight.vpnservice.mdsalutil.MetaDataUtil;
23 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ext.routers.Routers;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.FloatingIpInfo;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.RouterPorts;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.Ports;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.PortsBuilder;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.PortsKey;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.ports.IpMapping;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.ports.IpMappingBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.ports.IpMappingKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.networks.Networks;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.networks.NetworksKey;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ExternalNetworks;
36 import org.opendaylight.yangtools.concepts.ListenerRegistration;
37 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceInput;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceInputBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceOutput;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
45 import org.opendaylight.yangtools.yang.common.RpcResult;
46
47 import java.util.concurrent.ExecutionException;
48 import java.util.concurrent.Future;
49
50 import com.google.common.base.Optional;
51 import com.google.common.base.Strings;
52
53 import java.math.BigInteger;
54 import java.net.InetAddress;
55 import java.net.UnknownHostException;
56 import java.util.ArrayList;
57 import java.util.List;
58
59 /**
60  * Created by emhamla on 1/18/2016.
61  */
62 public class FloatingIPListener extends org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener<IpMapping> implements AutoCloseable{
63     private static final Logger LOG = LoggerFactory.getLogger(FloatingIPListener.class);
64     private ListenerRegistration<DataChangeListener> listenerRegistration;
65     private final DataBroker broker;
66     private OdlInterfaceRpcService interfaceManager;
67     private IMdsalApiManager mdsalManager;
68     private FloatingIPHandler handler;
69
70
71     public FloatingIPListener (final DataBroker db) {
72         super(IpMapping.class);
73         broker = db;
74         registerListener(db);
75     }
76
77     void setFloatingIpHandler(FloatingIPHandler handler) {
78         this.handler = handler;
79     }
80
81     @Override
82     public void close() throws Exception {
83         if (listenerRegistration != null) {
84             try {
85                 listenerRegistration.close();
86             } catch (final Exception e) {
87                 LOG.error("Error when cleaning up DataChangeListener.", e);
88             }
89             listenerRegistration = null;
90         }
91         LOG.info("FloatingIP Listener Closed");
92     }
93
94     private void registerListener(final DataBroker db) {
95         try {
96             listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
97                     getWildCardPath(), FloatingIPListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
98         } catch (final Exception e) {
99             LOG.error("FloatingIP DataChange listener registration fail!", e);
100             throw new IllegalStateException("FloatingIP Listener registration Listener failed.", e);
101         }
102     }
103
104     private InstanceIdentifier<IpMapping> getWildCardPath() {
105         return InstanceIdentifier.create(FloatingIpInfo.class).child(RouterPorts.class).child(Ports.class).child(IpMapping.class);
106     }
107
108     public void setInterfaceManager(OdlInterfaceRpcService interfaceManager) {
109         this.interfaceManager = interfaceManager;
110     }
111
112     public void setMdsalManager(IMdsalApiManager mdsalManager) {
113         this.mdsalManager = mdsalManager;
114     }
115
116     @Override
117     protected void add(final InstanceIdentifier<IpMapping> identifier,
118                        final IpMapping mapping) {
119         LOG.trace("FloatingIPListener add ip mapping method - key: " + identifier + ", value=" + mapping );
120         processFloatingIPAdd(identifier, mapping);
121     }
122
123     @Override
124     protected void remove(InstanceIdentifier<IpMapping> identifier, IpMapping mapping) {
125         LOG.trace("FloatingIPListener remove ip mapping method - key: " + identifier + ", value=" + mapping );
126         processFloatingIPDel(identifier, mapping);
127     }
128
129     @Override
130     protected void update(InstanceIdentifier<IpMapping> identifier, IpMapping original, IpMapping update) {
131         LOG.trace("FloatingIPListener update ip mapping method - key: " + identifier + ", original=" + original + ", update=" + update );
132     }
133
134     public static BigInteger getDpnForInterface(OdlInterfaceRpcService interfaceManagerRpcService, String ifName) {
135         BigInteger nodeId = BigInteger.ZERO;
136         try {
137             GetDpidFromInterfaceInput
138                     dpIdInput =
139                     new GetDpidFromInterfaceInputBuilder().setIntfName(ifName).build();
140             Future<RpcResult<GetDpidFromInterfaceOutput>>
141                     dpIdOutput =
142                     interfaceManagerRpcService.getDpidFromInterface(dpIdInput);
143             RpcResult<GetDpidFromInterfaceOutput> dpIdResult = dpIdOutput.get();
144             if (dpIdResult.isSuccessful()) {
145                 nodeId = dpIdResult.getResult().getDpid();
146             } else {
147                 LOG.error("Could not retrieve DPN Id for interface {}", ifName);
148             }
149         } catch (InterruptedException | ExecutionException e) {
150             LOG.error("Exception when getting dpn for interface {}", ifName,  e);
151         }
152         return nodeId;
153     }
154
155     private FlowEntity buildPreDNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long routerId, long vpnId) {
156         return buildPreDNATFlowEntity(dpId, internalIp, externalIp, routerId, vpnId, NatConstants.INVALID_ID);
157     }
158
159     private FlowEntity buildPreDNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long routerId, long vpnId, long associatedVpn) {
160         LOG.info("Bulding DNAT Flow entity for ip {} ", externalIp);
161
162         long segmentId = (associatedVpn == NatConstants.INVALID_ID) ? routerId : associatedVpn;
163         LOG.debug("Segment id {} in build preDNAT Flow", segmentId);
164
165         List<MatchInfo> matches = new ArrayList<MatchInfo>();
166         matches.add(new MatchInfo(MatchFieldType.eth_type,
167                 new long[] { 0x0800L }));
168
169         matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] {
170                 externalIp, "32" }));
171
172 //        matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
173 //                BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
174
175         List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
176         actionsInfos.add(new ActionInfo(ActionType.set_destination_ip, new String[]{ internalIp, "32" }));
177
178         List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
179         instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { BigInteger.valueOf
180                 (segmentId), MetaDataUtil.METADATA_MASK_VRFID }));
181         instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
182         instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NatConstants.DNAT_TABLE }));
183
184         String flowRef = NatUtil.getFlowRef(dpId, NatConstants.PDNAT_TABLE, routerId, externalIp);
185
186         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PDNAT_TABLE, flowRef,
187                 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
188                 NatConstants.COOKIE_DNAT_TABLE, matches, instructions);
189
190         return flowEntity;
191     }
192
193
194
195     private FlowEntity buildDNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long routerId) {
196         return buildDNATFlowEntity(dpId, internalIp, externalIp, routerId, NatConstants.INVALID_ID);
197     }
198
199     private FlowEntity buildDNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long routerId, long associatedVpn) {
200
201         LOG.info("Bulding DNAT Flow entity for ip {} ", externalIp);
202
203         long segmentId = (associatedVpn == NatConstants.INVALID_ID) ? routerId : associatedVpn;
204         LOG.debug("Segment id {} in build DNAT", segmentId);
205
206         List<MatchInfo> matches = new ArrayList<MatchInfo>();
207         matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
208                 BigInteger.valueOf(segmentId), MetaDataUtil.METADATA_MASK_VRFID }));
209
210         matches.add(new MatchInfo(MatchFieldType.eth_type,
211                 new long[] { 0x0800L }));
212
213         matches.add(new MatchInfo(MatchFieldType.ipv4_destination, new String[] {
214         //        externalIp, "32" }));
215                   internalIp, "32" }));
216
217         List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
218 //        actionsInfos.add(new ActionInfo(ActionType.set_destination_ip, new String[]{ internalIp, "32" }));
219
220         List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
221 //        instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { BigInteger.valueOf
222 //                (routerId), MetaDataUtil.METADATA_MASK_VRFID }));
223         actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[] { Integer.toString(NatConstants.L3_FIB_TABLE) }));
224         instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
225         //instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NatConstants.L3_FIB_TABLE }));
226
227         String flowRef = NatUtil.getFlowRef(dpId, NatConstants.DNAT_TABLE, routerId, externalIp);
228
229         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.DNAT_TABLE, flowRef,
230                 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
231                 NatConstants.COOKIE_DNAT_TABLE, matches, instructions);
232
233         return flowEntity;
234
235     }
236
237     private FlowEntity buildPreSNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long vpnId, long routerId) {
238         return buildPreSNATFlowEntity(dpId, internalIp, externalIp, vpnId, routerId, NatConstants.INVALID_ID);
239     }
240
241     private FlowEntity buildPreSNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long vpnId, long routerId, long associatedVpn) {
242
243         LOG.info("Building PSNAT Flow entity for ip {} ", internalIp);
244
245         long segmentId = (associatedVpn == NatConstants.INVALID_ID) ? routerId : associatedVpn;
246
247         LOG.debug("Segment id {} in build preSNAT flow", segmentId);
248
249         List<MatchInfo> matches = new ArrayList<MatchInfo>();
250         matches.add(new MatchInfo(MatchFieldType.eth_type,
251                 new long[] { 0x0800L }));
252
253         matches.add(new MatchInfo(MatchFieldType.ipv4_source, new String[] {
254                 internalIp, "32" }));
255
256         matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
257                 BigInteger.valueOf(segmentId), MetaDataUtil.METADATA_MASK_VRFID }));
258
259         List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
260         actionsInfos.add(new ActionInfo(ActionType.set_source_ip, new String[]{ externalIp, "32" }));
261
262         List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
263         instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
264         instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
265         instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NatConstants.SNAT_TABLE }));
266
267         String flowRef = NatUtil.getFlowRef(dpId, NatConstants.PSNAT_TABLE, routerId, internalIp);
268
269         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
270                 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
271                 NatConstants.COOKIE_DNAT_TABLE, matches, instructions);
272
273         return flowEntity;
274     }
275
276     private FlowEntity buildSNATFlowEntity(BigInteger dpId, String internalIp, String externalIp, long vpnId, String macAddress) {
277
278         LOG.info("Building SNAT Flow entity for ip {} ", internalIp);
279
280         List<MatchInfo> matches = new ArrayList<MatchInfo>();
281         matches.add(new MatchInfo(MatchFieldType.metadata, new BigInteger[] {
282                 BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
283
284         matches.add(new MatchInfo(MatchFieldType.eth_type,
285                 new long[] { 0x0800L }));
286
287         matches.add(new MatchInfo(MatchFieldType.ipv4_source, new String[] {
288         //        internalIp, "32" }));
289                   externalIp, "32" }));
290
291         List<ActionInfo> actionsInfos = new ArrayList<ActionInfo>();
292 //        actionsInfos.add(new ActionInfo(ActionType.set_source_ip, new String[]{ externalIp, "32" }));
293
294         //TODO: Set external gateway mac address
295         if(!Strings.isNullOrEmpty(macAddress)) {
296             LOG.debug("Setting ext gw mac address {} in SNAT {} flow action", macAddress, internalIp);
297             actionsInfos.add(new ActionInfo(ActionType.set_field_eth_dest, new String[]{ macAddress }));
298         }
299
300         List<InstructionInfo> instructions = new ArrayList<InstructionInfo>();
301         //instructions.add(new InstructionInfo(InstructionType.write_metadata, new BigInteger[] { BigInteger.valueOf(vpnId), MetaDataUtil.METADATA_MASK_VRFID }));
302         actionsInfos.add(new ActionInfo(ActionType.nx_resubmit, new String[] { Integer.toString(NatConstants.L3_FIB_TABLE) }));
303         instructions.add(new InstructionInfo(InstructionType.apply_actions, actionsInfos));
304         //instructions.add(new InstructionInfo(InstructionType.goto_table, new long[] { NatConstants.L3_FIB_TABLE }));
305
306         String flowRef = NatUtil.getFlowRef(dpId, NatConstants.SNAT_TABLE, vpnId, internalIp);
307
308         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.SNAT_TABLE, flowRef,
309                 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
310                 NatConstants.COOKIE_DNAT_TABLE, matches, instructions);
311
312         return flowEntity;
313
314
315     }
316
317     private void createDNATTblEntry(BigInteger dpnId, String internalIp, String externalIp, long routerId, long vpnId, long associatedVpnId) {
318         FlowEntity pFlowEntity = buildPreDNATFlowEntity(dpnId, internalIp, externalIp, routerId, vpnId, associatedVpnId );
319         mdsalManager.installFlow(pFlowEntity);
320
321         FlowEntity flowEntity = buildDNATFlowEntity(dpnId, internalIp, externalIp, routerId, associatedVpnId);
322         mdsalManager.installFlow(flowEntity);
323     }
324
325     private void removeDNATTblEntry(BigInteger dpnId, String internalIp, String externalIp, long routerId) {
326         FlowEntity pFlowEntity = buildPreDNATDeleteFlowEntity(dpnId, internalIp, externalIp, routerId );
327         mdsalManager.removeFlow(pFlowEntity);
328
329         FlowEntity flowEntity = buildDNATDeleteFlowEntity(dpnId, internalIp, externalIp, routerId);
330         mdsalManager.removeFlow(flowEntity);
331     }
332
333     private void createSNATTblEntry(BigInteger dpnId, String internalIp, String externalIp, long vpnId, long routerId, String macAddress, long associatedVpnId) {
334         FlowEntity pFlowEntity = buildPreSNATFlowEntity(dpnId, internalIp, externalIp, vpnId , routerId, associatedVpnId);
335         mdsalManager.installFlow(pFlowEntity);
336
337         FlowEntity flowEntity = buildSNATFlowEntity(dpnId, internalIp, externalIp, vpnId, macAddress);
338         mdsalManager.installFlow(flowEntity);
339
340     }
341
342     private void removeSNATTblEntry(BigInteger dpnId, String internalIp, long routerId, String externalIp, long vpnId) {
343         FlowEntity pFlowEntity = buildPreSNATDeleteFlowEntity(dpnId, internalIp, routerId, externalIp);
344         mdsalManager.removeFlow(pFlowEntity);
345
346         FlowEntity flowEntity = buildSNATDeleteFlowEntity(dpnId, internalIp, vpnId, externalIp);
347         mdsalManager.removeFlow(flowEntity);
348
349     }
350
351     private Uuid getExtNetworkId(final InstanceIdentifier<RouterPorts> pIdentifier) {
352         Optional<RouterPorts> rtrPort = NatUtil.read(broker, LogicalDatastoreType.CONFIGURATION, pIdentifier);
353         if(!rtrPort.isPresent()) {
354             LOG.error("Unable to read router port entry for {}", pIdentifier);
355             return null;
356         }
357
358         Uuid extNwId = rtrPort.get().getExternalNetworkId();
359         return extNwId;
360     }
361
362     private long getVpnId(Uuid extNwId) {
363         InstanceIdentifier<Networks> nwId = InstanceIdentifier.builder(ExternalNetworks.class).child(Networks.class, new NetworksKey(extNwId)).build();
364         Optional<Networks> nw = NatUtil.read(broker, LogicalDatastoreType.CONFIGURATION, nwId);
365         if(!nw.isPresent()) {
366             LOG.error("Unable to read external network for {}", extNwId);
367             return NatConstants.INVALID_ID;
368         }
369
370         Uuid vpnUuid = nw.get().getVpnid();
371         if(vpnUuid == null) {
372             return NatConstants.INVALID_ID;
373         }
374
375         //Get the id using the VPN UUID (also vpn instance name)
376         return NatUtil.readVpnId(broker, vpnUuid.getValue());
377     }
378
379     private void processFloatingIPAdd(final InstanceIdentifier<IpMapping> identifier,
380                                       final IpMapping mapping) {
381         LOG.trace("Add event - key: {}, value: {}", identifier, mapping);
382
383         final String routerId = identifier.firstKeyOf(RouterPorts.class).getRouterId();
384         final PortsKey pKey = identifier.firstKeyOf(Ports.class);
385         String interfaceName = pKey.getPortName();
386
387         InstanceIdentifier<RouterPorts> pIdentifier = identifier.firstIdentifierOf(RouterPorts.class);
388         createNATFlowEntries(interfaceName, mapping, pIdentifier, routerId);
389     }
390
391     private void processFloatingIPDel(final InstanceIdentifier<IpMapping> identifier,
392                                       final IpMapping mapping) {
393         LOG.trace("Del event - key: {}, value: {}", identifier, mapping);
394
395         final String routerId = identifier.firstKeyOf(RouterPorts.class).getRouterId();
396         final PortsKey pKey = identifier.firstKeyOf(Ports.class);
397         String interfaceName = pKey.getPortName();
398
399         InstanceIdentifier<RouterPorts> pIdentifier = identifier.firstIdentifierOf(RouterPorts.class);
400         removeNATFlowEntries(interfaceName, mapping, pIdentifier, routerId);
401     }
402
403     private InetAddress getInetAddress(String ipAddr) {
404         InetAddress ipAddress = null;
405         try {
406             ipAddress = InetAddress.getByName(ipAddr);
407         } catch (UnknownHostException e) {
408             LOG.error("UnknowHostException for ip {}", ipAddr);
409         }
410         return ipAddress;
411     }
412
413     private boolean validateIpMapping(IpMapping mapping) {
414         return getInetAddress(mapping.getInternalIp()) != null &&
415                     getInetAddress(mapping.getExternalIp()) != null;
416     }
417
418     void createNATFlowEntries(String interfaceName, final IpMapping mapping,
419                               final InstanceIdentifier<RouterPorts> pIdentifier, final String routerName) {
420         if(!validateIpMapping(mapping)) {
421             LOG.warn("Not a valid ip addresses in the mapping {}", mapping);
422             return;
423         }
424
425         //Get the DPN on which this interface resides
426         BigInteger dpnId = getDpnForInterface(interfaceManager, interfaceName);
427
428         if(dpnId.equals(BigInteger.ZERO)) {
429              LOG.error("No DPN for interface {}. NAT flow entries for ip mapping {} will not be installed", 
430                      interfaceName, mapping);
431              return;
432         }
433
434         long routerId = NatUtil.getVpnId(broker, routerName);
435         if(routerId == NatConstants.INVALID_ID) {
436             LOG.warn("Could not retrieve router id for {} to create NAT Flow entries", routerName);
437             return;
438         }
439         //Check if the router to vpn association is present
440         //long associatedVpnId = NatUtil.getAssociatedVpn(broker, routerName);
441         Uuid associatedVpn = NatUtil.getVpnForRouter(broker, routerName);
442         long associatedVpnId = NatConstants.INVALID_ID;
443         if(associatedVpn == null) {
444             LOG.debug("Router {} is not assicated with any BGP VPN instance", routerName);
445         } else {
446             LOG.debug("Router {} is associated with VPN Instance with Id {}", routerName, associatedVpn);
447             associatedVpnId = NatUtil.getVpnId(broker, associatedVpn.getValue());
448             LOG.debug("vpninstance Id is {} for VPN {}", associatedVpnId, associatedVpn);
449             //routerId = associatedVpnId;
450         }
451
452         Uuid extNwId = getExtNetworkId(pIdentifier);
453         if(extNwId == null) {
454             LOG.error("External network associated with interface {} could not be retrieved", interfaceName);
455             LOG.error("NAT flow entries will not be installed {}", mapping);
456             return;
457         }
458         long vpnId = getVpnId(extNwId);
459         if(vpnId < 0) {
460             LOG.error("No VPN associated with Ext nw {}. Unable to create SNAT table entry for fixed ip {}", 
461                     extNwId, mapping.getInternalIp());
462             return;
463         }
464
465         //Create the DNAT and SNAT table entries
466         createDNATTblEntry(dpnId, mapping.getInternalIp(), mapping.getExternalIp(), routerId, vpnId, associatedVpnId);
467
468
469         String macAddr = getExternalGatewayMacAddress(routerName);
470         createSNATTblEntry(dpnId, mapping.getInternalIp(), mapping.getExternalIp(), vpnId, routerId, macAddr, associatedVpnId);
471
472         handler.onAddFloatingIp(dpnId, routerName, extNwId, interfaceName, mapping.getExternalIp(), mapping
473                 .getInternalIp());
474     }
475
476     void createNATFlowEntries(BigInteger dpnId,  String interfaceName, String routerName, Uuid externalNetworkId, String internalIp, String externalIp) {
477         long routerId = NatUtil.getVpnId(broker, routerName);
478         if(routerId == NatConstants.INVALID_ID) {
479             LOG.warn("Could not retrieve router id for {} to create NAT Flow entries", routerName);
480             return;
481         }
482         //Check if the router to vpn association is present
483         long associatedVpnId = NatUtil.getAssociatedVpn(broker, routerName);
484         if(associatedVpnId == NatConstants.INVALID_ID) {
485             LOG.debug("Router {} is not assicated with any BGP VPN instance", routerName);
486         } else {
487             LOG.debug("Router {} is associated with VPN Instance with Id {}", routerName, associatedVpnId);
488             //routerId = associatedVpnId;
489         }
490         
491         long vpnId = getVpnId(externalNetworkId);
492         if(vpnId < 0) {
493             LOG.error("Unable to create SNAT table entry for fixed ip {}", internalIp);
494             return;
495         }
496         //Create the DNAT and SNAT table entries
497         createDNATTblEntry(dpnId, internalIp, externalIp, routerId, vpnId, associatedVpnId);
498
499         String macAddr = getExternalGatewayMacAddress(routerName);
500         createSNATTblEntry(dpnId, internalIp, externalIp, vpnId, routerId, macAddr, associatedVpnId);
501
502         handler.onAddFloatingIp(dpnId, routerName, externalNetworkId, interfaceName, externalIp, internalIp);
503     }
504
505     void createNATOnlyFlowEntries(BigInteger dpnId,  String interfaceName, String routerName, String associatedVPN, Uuid externalNetworkId, String internalIp, String externalIp) {
506         //String segmentId = associatedVPN == null ? routerName : associatedVPN;
507         LOG.debug("Retrieving vpn id for VPN {} to proceed with create NAT Flows", routerName);
508         long routerId = NatUtil.getVpnId(broker, routerName);
509         if(routerId == NatConstants.INVALID_ID) {
510             LOG.warn("Could not retrieve vpn id for {} to create NAT Flow entries", routerName);
511             return;
512         }
513         long associatedVpnId = NatUtil.getVpnId(broker, associatedVPN);
514         LOG.debug("Associated VPN Id {} for router {}", associatedVpnId, routerName);
515         long vpnId = getVpnId(externalNetworkId);
516         if(vpnId < 0) {
517             LOG.error("Unable to create SNAT table entry for fixed ip {}", internalIp);
518             return;
519         }
520         //Create the DNAT and SNAT table entries
521         //createDNATTblEntry(dpnId, internalIp, externalIp, routerId, vpnId);
522         FlowEntity pFlowEntity = buildPreDNATFlowEntity(dpnId, internalIp, externalIp, routerId, vpnId, associatedVpnId );
523         mdsalManager.installFlow(pFlowEntity);
524
525         FlowEntity flowEntity = buildDNATFlowEntity(dpnId, internalIp, externalIp, routerId, associatedVpnId);
526         mdsalManager.installFlow(flowEntity);
527
528         String macAddr = getExternalGatewayMacAddress(routerName);
529         //createSNATTblEntry(dpnId, internalIp, externalIp, vpnId, routerId, macAddr);
530         pFlowEntity = buildPreSNATFlowEntity(dpnId, internalIp, externalIp, vpnId , routerId, associatedVpnId);
531         mdsalManager.installFlow(pFlowEntity);
532
533         flowEntity = buildSNATFlowEntity(dpnId, internalIp, externalIp, vpnId, macAddr);
534         mdsalManager.installFlow(flowEntity);
535
536     }
537
538     private String getExternalGatewayMacAddress(String routerName) {
539         InstanceIdentifier<Routers> routersIdentifier = NatUtil.buildRouterIdentifier(routerName);
540         Optional<Routers> optRouters = NatUtil.read(broker, LogicalDatastoreType.CONFIGURATION, routersIdentifier);
541         if(optRouters.isPresent()) {
542             Routers routers = optRouters.get();
543             return routers.getExtGwMacAddress();
544         }
545         return "";
546     }
547
548     void removeNATFlowEntries(String interfaceName, final IpMapping mapping,
549                               final InstanceIdentifier<RouterPorts> pIdentifier, final String routerName) {
550
551         //Get the DPN on which this interface resides
552         BigInteger dpnId = getDpnForInterface(interfaceManager, interfaceName);
553         if(dpnId.equals(BigInteger.ZERO)) {
554             LOG.info("Abort processing Floating ip configuration. No DPN for port : {}", interfaceName);
555             return;
556         }
557
558         long routerId = NatUtil.getVpnId(broker, routerName);
559         if(routerId == NatConstants.INVALID_ID) {
560             LOG.warn("Could not retrieve router id for {} to remove NAT Flow entries", routerName);
561             return;
562         }
563         //if(routerId == NatConstants.INVALID_ID) {
564         //The router could be associated with BGP VPN
565         Uuid associatedVPN = NatUtil.getVpnForRouter(broker, routerName);
566         long associatedVpnId = NatConstants.INVALID_ID;
567         if(associatedVPN == null) {
568             LOG.warn("Could not retrieve router id for {} to remove NAT Flow entries", routerName);
569         } else {
570             LOG.debug("Retrieving vpn id for VPN {} to proceed with remove NAT Flows", associatedVPN.getValue());
571             associatedVpnId = NatUtil.getVpnId(broker, associatedVPN.getValue());
572         }
573
574         //Delete the DNAT and SNAT table entries
575         removeDNATTblEntry(dpnId, mapping.getInternalIp(), mapping.getExternalIp(), routerId);
576
577         Uuid extNwId = getExtNetworkId(pIdentifier);
578         if(extNwId == null) {
579             LOG.error("External network associated with interface {} could not be retrieved", interfaceName);
580             return;
581         }
582         long vpnId = getVpnId(extNwId);
583         if(vpnId < 0) {
584             LOG.error("No VPN associated with ext nw {}. Unable to delete SNAT table entry for fixed ip {}", 
585                     extNwId, mapping.getInternalIp());
586             return;
587         }
588         removeSNATTblEntry(dpnId, mapping.getInternalIp(), routerId, mapping.getExternalIp(), vpnId);
589
590         long label = getOperationalIpMapping(routerName, interfaceName, mapping.getInternalIp());
591         if(label < 0) {
592             LOG.error("Could not retrieve label for prefix {} in router {}", mapping.getInternalIp(), routerId);
593             return;
594         }
595         //Uuid extNwId = getExtNetworkId(pIdentifier);
596 //        Uuid extNwId = getExternalNetworkForRouter(routerName);
597 //        if(extNwId == null) {
598 //            LOG.error("External network associated with router {} could not be retrieved", routerName);
599 //            return;
600 //        }
601         handler.onRemoveFloatingIp(dpnId, routerName, extNwId, mapping.getExternalIp(), mapping.getInternalIp(), (int) label);
602         removeOperationalDS(routerName, interfaceName, mapping.getInternalIp(), mapping.getExternalIp());
603
604     }
605
606     void removeNATFlowEntries(BigInteger dpnId, String interfaceName, String vpnName, String routerName, Uuid externalNetworkId, String internalIp, String externalIp) {
607         long routerId = NatUtil.getVpnId(broker, routerName);
608         if(routerId == NatConstants.INVALID_ID) {
609             LOG.warn("Could not retrieve router id for {} to remove NAT Flow entries", routerName);
610             return;
611         }
612
613         long vpnId = NatUtil.getVpnId(broker, vpnName);
614         if(vpnId == NatConstants.INVALID_ID) {
615             LOG.warn("VPN Id not found for {} to remove NAT flow entries {}", vpnName, internalIp);
616         }
617
618         //Delete the DNAT and SNAT table entries
619         removeDNATTblEntry(dpnId, internalIp, externalIp, routerId);
620
621         removeSNATTblEntry(dpnId, internalIp, routerId, externalIp, vpnId);
622
623         long label = getOperationalIpMapping(routerName, interfaceName, internalIp);
624         if(label < 0) {
625             LOG.error("Could not retrieve label for prefix {} in router {}", internalIp, routerId);
626             return;
627         }
628         //handler.onRemoveFloatingIp(dpnId, routerName, externalNetworkId, externalIp, internalIp, (int)label);
629         ((VpnFloatingIpHandler)handler).cleanupFibEntries(dpnId, vpnName, externalIp, label);
630         removeOperationalDS(routerName, interfaceName, internalIp, externalIp);
631     }
632
633     void removeNATOnlyFlowEntries(BigInteger dpnId, String interfaceName, String routerName, String associatedVPN,
634                                                                           String internalIp, String externalIp) {
635         String segmentId = associatedVPN == null ? routerName : associatedVPN;
636         LOG.debug("Retrieving vpn id for VPN {} to proceed with remove NAT Flows", segmentId);
637         long routerId = NatUtil.getVpnId(broker, segmentId);
638         if(routerId == NatConstants.INVALID_ID) {
639             LOG.warn("Could not retrieve vpn id for {} to remove NAT Flow entries", segmentId);
640             return;
641         }
642         //Delete the DNAT and SNAT table entries
643         removeDNATTblEntry(dpnId, internalIp, externalIp, routerId);
644
645         //removeSNATTblEntry(dpnId, internalIp, routerId, externalIp);
646     }
647
648     private long getOperationalIpMapping(String routerId, String interfaceName, String internalIp) {
649         InstanceIdentifier<IpMapping> ipMappingIdentifier = NatUtil.getIpMappingIdentifier(routerId, interfaceName, internalIp);
650         Optional<IpMapping> ipMapping = NatUtil.read(broker, LogicalDatastoreType.OPERATIONAL, ipMappingIdentifier);
651         if(ipMapping.isPresent()) {
652             return ipMapping.get().getLabel();
653         }
654         return NatConstants.INVALID_ID;
655     }
656
657     private Uuid getExternalNetworkForRouter(String routerId) {
658         InstanceIdentifier<RouterPorts> identifier = NatUtil.getRouterPortsId(routerId);
659         Optional<RouterPorts> optRouterPorts = NatUtil.read(broker, LogicalDatastoreType.OPERATIONAL, identifier);
660         if(optRouterPorts.isPresent()) {
661             RouterPorts routerPorts = optRouterPorts.get();
662             return routerPorts.getExternalNetworkId();
663         }
664         return null;
665     }
666
667     void updateOperationalDS(String routerId, String interfaceName, int label, String internalIp, String externalIp) {
668
669         LOG.info("Updating operational DS for floating ip config : {} with label {}", internalIp, label);
670         InstanceIdentifier<Ports> portsId = NatUtil.getPortsIdentifier(routerId, interfaceName);
671         Optional<Ports> optPorts = NatUtil.read(broker, LogicalDatastoreType.OPERATIONAL, portsId);
672         IpMapping ipMapping = new IpMappingBuilder().setKey(new IpMappingKey(internalIp)).setInternalIp(internalIp)
673                 .setExternalIp(externalIp).setLabel(label).build();
674         if(optPorts.isPresent()) {
675             LOG.debug("Ports {} entry already present. Updating ipmapping for internal ip {}", interfaceName, internalIp);
676             MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, portsId.child(IpMapping.class, new IpMappingKey(internalIp)), ipMapping);
677         } else {
678             LOG.debug("Adding Ports entry {} along with ipmapping {}", interfaceName, internalIp);
679             List<IpMapping> ipMappings = new ArrayList<>();
680             ipMappings.add(ipMapping);
681             Ports ports = new PortsBuilder().setKey(new PortsKey(interfaceName)).setPortName(interfaceName).setIpMapping(ipMappings).build();
682             MDSALUtil.syncWrite(broker, LogicalDatastoreType.OPERATIONAL, portsId, ports);
683         }
684     }
685
686     void removeOperationalDS(String routerId, String interfaceName, String internalIp, String externalIp) {
687         LOG.info("Remove operational DS for floating ip config: {}", internalIp);
688         InstanceIdentifier<IpMapping> ipMappingId = NatUtil.getIpMappingIdentifier(routerId, interfaceName, internalIp);
689         MDSALUtil.syncDelete(broker, LogicalDatastoreType.OPERATIONAL, ipMappingId);
690     }
691
692     private FlowEntity buildPreDNATDeleteFlowEntity(BigInteger dpId, String internalIp, String externalIp, long routerId) {
693
694         LOG.info("Bulding Delete DNAT Flow entity for ip {} ", externalIp);
695
696         String flowRef = NatUtil.getFlowRef(dpId, NatConstants.PDNAT_TABLE, routerId, externalIp);
697
698         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PDNAT_TABLE, flowRef,
699                 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
700                 NatConstants.COOKIE_DNAT_TABLE, null, null);
701
702         return flowEntity;
703     }
704
705
706
707     private FlowEntity buildDNATDeleteFlowEntity(BigInteger dpId, String internalIp, String externalIp, long routerId) {
708
709         LOG.info("Bulding Delete DNAT Flow entity for ip {} ", externalIp);
710
711         String flowRef = NatUtil.getFlowRef(dpId, NatConstants.DNAT_TABLE, routerId, externalIp);
712
713         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.DNAT_TABLE, flowRef,
714                 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
715                 NatConstants.COOKIE_DNAT_TABLE, null, null);
716
717         return flowEntity;
718
719     }
720
721     private FlowEntity buildPreSNATDeleteFlowEntity(BigInteger dpId, String internalIp, long routerId, String externalIp) {
722
723         LOG.info("Building Delete PSNAT Flow entity for ip {} ", internalIp);
724
725         String flowRef = NatUtil.getFlowRef(dpId, NatConstants.PSNAT_TABLE, routerId, internalIp);
726
727         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.PSNAT_TABLE, flowRef,
728                 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
729                 NatConstants.COOKIE_DNAT_TABLE, null, null);
730
731         return flowEntity;
732     }
733
734     private FlowEntity buildSNATDeleteFlowEntity(BigInteger dpId, String internalIp, long routerId, String externalIp) {
735
736         LOG.info("Building Delete SNAT Flow entity for ip {} ", internalIp);
737
738         String flowRef = NatUtil.getFlowRef(dpId, NatConstants.SNAT_TABLE, routerId, internalIp);
739
740         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpId, NatConstants.SNAT_TABLE, flowRef,
741                 NatConstants.DEFAULT_DNAT_FLOW_PRIORITY, flowRef, 0, 0,
742                 NatConstants.COOKIE_DNAT_TABLE, null, null);
743
744         return flowEntity;
745
746
747     }
748 }
749