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