Bump versions by 0.1.0 for next dev cycle
[vpnservice.git] / natservice / natservice-impl / src / main / java / org / opendaylight / vpnservice / natservice / internal / ExternalNetworksChangeListener.java
1 /*\r
2  * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.\r
3  *\r
4  * This program and the accompanying materials are made available under the\r
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
6  * and is available at http://www.eclipse.org/legal/epl-v10.html\r
7  */\r
8 \r
9 package org.opendaylight.vpnservice.natservice.internal;\r
10 \r
11 import com.google.common.base.Optional;\r
12 \r
13 import org.opendaylight.controller.md.sal.binding.api.DataBroker;\r
14 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;\r
15 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;\r
16 import org.opendaylight.vpnservice.datastoreutils.AsyncDataTreeChangeListenerBase;\r
17 import org.opendaylight.vpnservice.mdsalutil.MDSALUtil;\r
18 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;\r
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;\r
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceInput;\r
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceInputBuilder;\r
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.GetDpidFromInterfaceOutput;\r
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rpcs.rev151003.OdlInterfaceRpcService;\r
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ExternalNetworks;\r
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.IntextIpMap;\r
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.RouterPorts;\r
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.Ports;\r
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.ports.IpMapping;\r
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMappingKey;\r
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.ip.mapping.IpMap;\r
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.NaptSwitches;\r
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.external.networks.Networks;\r
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitch;\r
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;\r
35 import org.opendaylight.yangtools.concepts.ListenerRegistration;\r
36 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;\r
37 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;\r
38 import org.opendaylight.yangtools.yang.common.RpcResult;\r
39 import org.slf4j.Logger;\r
40 import org.slf4j.LoggerFactory;\r
41 \r
42 import java.math.BigInteger;\r
43 import java.util.List;\r
44 import java.util.concurrent.ExecutionException;\r
45 import java.util.concurrent.Future;\r
46 \r
47 import org.opendaylight.bgpmanager.api.IBgpManager;\r
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.fib.rpc.rev160121.FibRpcService;\r
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.vpn.rpc.rev160201.VpnRpcService;\r
50 \r
51 /**\r
52  * Created by ESUMAMS on 1/21/2016.\r
53  */\r
54 public class ExternalNetworksChangeListener extends AsyncDataTreeChangeListenerBase<Networks, ExternalNetworksChangeListener>\r
55 {\r
56     private static final Logger LOG = LoggerFactory.getLogger( ExternalNetworksChangeListener.class);\r
57 \r
58     private ListenerRegistration<DataChangeListener> listenerRegistration;\r
59     private final DataBroker dataBroker;\r
60     private IMdsalApiManager mdsalManager;\r
61     //private VpnFloatingIpHandler vpnFloatingIpHandler;\r
62     private FloatingIPListener floatingIpListener;\r
63     private ExternalRoutersListener externalRouterListener;\r
64     private OdlInterfaceRpcService interfaceManager;\r
65     private NaptManager naptManager;\r
66 \r
67     private IBgpManager bgpManager;\r
68     private VpnRpcService vpnService;\r
69     private FibRpcService fibService;\r
70 \r
71 \r
72     private ExternalRoutersListener externalRoutersListener;\r
73 \r
74     void setMdsalManager(IMdsalApiManager mdsalManager) {\r
75         this.mdsalManager = mdsalManager;\r
76     }\r
77 \r
78     void setInterfaceManager(OdlInterfaceRpcService interfaceManager) {\r
79         this.interfaceManager = interfaceManager;\r
80     }\r
81 \r
82     void setFloatingIpListener(FloatingIPListener floatingIpListener) {\r
83         this.floatingIpListener = floatingIpListener;\r
84     }\r
85 \r
86     void setExternalRoutersListener(ExternalRoutersListener externalRoutersListener) {\r
87         this.externalRouterListener = externalRoutersListener;\r
88     }\r
89 \r
90     public void setBgpManager(IBgpManager bgpManager) {\r
91         this.bgpManager = bgpManager;\r
92     }\r
93 \r
94     public void setNaptManager(NaptManager naptManager) {\r
95         this.naptManager = naptManager;\r
96     }\r
97 \r
98     public void setVpnService(VpnRpcService vpnService) {\r
99         this.vpnService = vpnService;\r
100     }\r
101 \r
102     public void setFibService(FibRpcService fibService) {\r
103         this.fibService = fibService;\r
104     }\r
105 \r
106     public void setListenerRegistration(ListenerRegistration<DataChangeListener> listenerRegistration) {\r
107         this.listenerRegistration = listenerRegistration;\r
108     }\r
109 \r
110     public ExternalNetworksChangeListener(final DataBroker dataBroker ) {\r
111         super( Networks.class, ExternalNetworksChangeListener.class );\r
112         this.dataBroker = dataBroker;\r
113     }\r
114 \r
115 \r
116     protected InstanceIdentifier<Networks> getWildCardPath() {\r
117         return InstanceIdentifier.create(ExternalNetworks.class).child(Networks.class);\r
118     }\r
119 \r
120 \r
121     @Override\r
122     protected void add(InstanceIdentifier<Networks> identifier, Networks networks) {\r
123 \r
124     }\r
125 \r
126     @Override\r
127     protected ExternalNetworksChangeListener getDataTreeChangeListener() {\r
128         return ExternalNetworksChangeListener.this;\r
129     }\r
130 \r
131     @Override\r
132     protected void remove(InstanceIdentifier<Networks> identifier, Networks networks) {\r
133         if( identifier == null || networks == null || networks.getRouterIds().isEmpty() ) {\r
134             LOG.info( "ExternalNetworksChangeListener:remove:: returning without processing since networks/identifier is null"  );\r
135             return;\r
136         }\r
137 \r
138         for( Uuid routerId: networks.getRouterIds() ) {\r
139             String routerName = routerId.toString();\r
140 \r
141             InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitchInstanceIdentifier =\r
142                     getRouterToNaptSwitchInstanceIdentifier( routerName);\r
143 \r
144             MDSALUtil.syncDelete( dataBroker, LogicalDatastoreType.OPERATIONAL, routerToNaptSwitchInstanceIdentifier );\r
145 \r
146             LOG.debug( "ExternalNetworksChangeListener:delete:: successful deletion of data in napt-switches container" );\r
147         }\r
148     }\r
149 \r
150     private static InstanceIdentifier<RouterToNaptSwitch> getRouterToNaptSwitchInstanceIdentifier( String routerName ) {\r
151 \r
152         return  InstanceIdentifier.builder( NaptSwitches.class )\r
153                         .child( RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();\r
154 \r
155     }\r
156 \r
157     public void close() throws Exception {\r
158         if (listenerRegistration != null) {\r
159             try {\r
160                 listenerRegistration.close();\r
161             }\r
162             catch (final Exception e) {\r
163                 LOG.error("Error when cleaning up ExternalNetworksChangeListener.", e);\r
164             }\r
165 \r
166             listenerRegistration = null;\r
167         }\r
168         LOG.debug("ExternalNetworksChangeListener Closed");\r
169     }\r
170 \r
171 \r
172     @Override\r
173     protected void update(InstanceIdentifier<Networks> identifier, Networks original, Networks update) {\r
174         //Check for VPN disassociation\r
175         Uuid originalVpn = original.getVpnid();\r
176         Uuid updatedVpn = update.getVpnid();\r
177         if(originalVpn == null && updatedVpn != null) {\r
178             //external network is dis-associated from L3VPN instance\r
179             associateExternalNetworkWithVPN(update);\r
180         } else if(originalVpn != null && updatedVpn == null) {\r
181             //external network is associated with vpn\r
182             disassociateExternalNetworkFromVPN(update, originalVpn.getValue());\r
183             //Remove the SNAT entries\r
184             removeSnatEntries(original, original.getId());\r
185         }\r
186     }\r
187 \r
188     private void removeSnatEntries(Networks original, Uuid networkUuid) {\r
189         List<Uuid> routerUuids = original.getRouterIds();\r
190         for (Uuid routerUuid : routerUuids) {\r
191             Long routerId = NatUtil.getVpnId(dataBroker, routerUuid.getValue());\r
192             if (routerId == NatConstants.INVALID_ID) {\r
193                 LOG.error("NAT Service : Invalid routerId returned for routerName {}", routerUuid.getValue());\r
194                 return;\r
195             }\r
196             List<String> externalIps = NatUtil.getExternalIpsForRouter(dataBroker,routerId);\r
197             externalRouterListener.handleDisableSnatInternetVpn(routerUuid.getValue(), networkUuid, externalIps, false, original.getVpnid().getValue());\r
198         }\r
199     }\r
200 \r
201     private void associateExternalNetworkWithVPN(Networks network) {\r
202         List<Uuid> routerIds = network.getRouterIds();\r
203         for(Uuid routerId : routerIds) {\r
204             //long router = NatUtil.getVpnId(dataBroker, routerId.getValue());\r
205 \r
206             InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerId.getValue());\r
207             Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerPortsId);\r
208             if(!optRouterPorts.isPresent()) {\r
209                 LOG.debug("Could not read Router Ports data object with id: {} to handle associate ext nw {}", routerId, network.getId());\r
210                 continue;\r
211             }\r
212             RouterPorts routerPorts = optRouterPorts.get();\r
213             List<Ports> interfaces = routerPorts.getPorts();\r
214             for(Ports port : interfaces) {\r
215                 String portName = port.getPortName();\r
216                 BigInteger dpnId = getDpnForInterface(interfaceManager, portName);\r
217                 if(dpnId.equals(BigInteger.ZERO)) {\r
218                     LOG.debug("DPN not found for {}, skip handling of ext nw {} association", portName, network.getId());\r
219                     continue;\r
220                 }\r
221                 List<IpMapping> ipMapping = port.getIpMapping();\r
222                 for(IpMapping ipMap : ipMapping) {\r
223                     String externalIp = ipMap.getExternalIp();\r
224                     //remove all VPN related entries\r
225                     floatingIpListener.createNATFlowEntries(dpnId, portName, routerId.getValue(), network.getId(), ipMap.getInternalIp(), externalIp);\r
226                 }\r
227             }\r
228         }\r
229 \r
230         // SNAT\r
231         for(Uuid routerId : routerIds) {\r
232             LOG.debug("NAT Service : associateExternalNetworkWithVPN() for routerId {}",  routerId);\r
233             Uuid networkId = network.getId();\r
234             if(networkId == null) {\r
235                 LOG.error("NAT Service : networkId is null for the router ID {}", routerId);\r
236                 return;\r
237             }\r
238             final String vpnName = network.getVpnid().getValue();\r
239             if(vpnName == null) {\r
240                 LOG.error("NAT Service : No VPN associated with ext nw {} for router {}", networkId, routerId);\r
241                 return;\r
242             }\r
243 \r
244             BigInteger dpnId = new BigInteger("0");\r
245             InstanceIdentifier<RouterToNaptSwitch> routerToNaptSwitch = NatUtil.buildNaptSwitchRouterIdentifier(routerId.getValue());\r
246             Optional<RouterToNaptSwitch> rtrToNapt = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, routerToNaptSwitch );\r
247             if(rtrToNapt.isPresent()) {\r
248                 dpnId = rtrToNapt.get().getPrimarySwitchId();\r
249             }\r
250             LOG.debug("NAT Service : got primarySwitch as dpnId{} ", dpnId);\r
251 \r
252             Long routerIdentifier = NatUtil.getVpnId(dataBroker, routerId.getValue());\r
253             InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping> idBuilder =\r
254                             InstanceIdentifier.builder(IntextIpMap.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping.class, new org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMappingKey(routerIdentifier));\r
255             InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping> id = idBuilder.build();\r
256             Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.map.IpMapping> ipMapping = MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL, id);\r
257             if (ipMapping.isPresent()) {\r
258                   List<IpMap> ipMaps = ipMapping.get().getIpMap();\r
259                   for (IpMap ipMap : ipMaps) {\r
260                       String externalIp = ipMap.getExternalIp();\r
261                       LOG.debug("NAT Service : got externalIp as {}", externalIp);\r
262                       LOG.debug("NAT Service : About to call advToBgpAndInstallFibAndTsFlows for dpnId {}, vpnName {} and externalIp {}", dpnId, vpnName, externalIp);\r
263                       externalRouterListener.advToBgpAndInstallFibAndTsFlows(dpnId, NatConstants.INBOUND_NAPT_TABLE, vpnName, NatUtil.getVpnId(dataBroker, routerId.getValue()), externalIp, vpnService, fibService, bgpManager, dataBroker, LOG);\r
264                   }\r
265             } else {\r
266                 LOG.warn("NAT Service : No ipMapping present fot the routerId {}", routerId);\r
267             }\r
268 \r
269             long vpnId = NatUtil.getVpnId(dataBroker, vpnName);\r
270             // Install 47 entry to point to 21\r
271             if(vpnId != -1) {\r
272                 LOG.debug("NAT Service : Calling externalRouterListener installNaptPfibEntry for donId {} and vpnId {}", dpnId, vpnId);\r
273                 externalRouterListener.installNaptPfibEntry(dpnId, vpnId);\r
274             }\r
275 \r
276         }\r
277 \r
278     }\r
279 \r
280     private void disassociateExternalNetworkFromVPN(Networks network, String vpnName) {\r
281         List<Uuid> routerIds = network.getRouterIds();\r
282 \r
283         //long vpnId = NatUtil.getVpnId(dataBroker, vpnName);\r
284         for(Uuid routerId : routerIds) {\r
285             //long router = NatUtil.getVpnId(dataBroker, routerId.getValue());\r
286 \r
287             InstanceIdentifier<RouterPorts> routerPortsId = NatUtil.getRouterPortsId(routerId.getValue());\r
288             Optional<RouterPorts> optRouterPorts = MDSALUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, routerPortsId);\r
289             if(!optRouterPorts.isPresent()) {\r
290                 LOG.debug("Could not read Router Ports data object with id: {} to handle disassociate ext nw {}", routerId, network.getId());\r
291                 continue;\r
292             }\r
293             RouterPorts routerPorts = optRouterPorts.get();\r
294             List<Ports> interfaces = routerPorts.getPorts();\r
295             for(Ports port : interfaces) {\r
296                 String portName = port.getPortName();\r
297                 BigInteger dpnId = getDpnForInterface(interfaceManager, portName);\r
298                 if(dpnId.equals(BigInteger.ZERO)) {\r
299                     LOG.debug("DPN not found for {}, skip handling of ext nw {} disassociation", portName, network.getId());\r
300                     continue;\r
301                 }\r
302                 List<IpMapping> ipMapping = port.getIpMapping();\r
303                 for(IpMapping ipMap : ipMapping) {\r
304                     String externalIp = ipMap.getExternalIp();\r
305                     floatingIpListener.removeNATFlowEntries(dpnId, portName, vpnName, routerId.getValue(), network.getId(), ipMap.getInternalIp(), externalIp);\r
306                 }\r
307             }\r
308         }\r
309     }\r
310 \r
311     public static BigInteger getDpnForInterface(OdlInterfaceRpcService interfaceManagerRpcService, String ifName) {\r
312         BigInteger nodeId = BigInteger.ZERO;\r
313         try {\r
314             GetDpidFromInterfaceInput\r
315                     dpIdInput =\r
316                     new GetDpidFromInterfaceInputBuilder().setIntfName(ifName).build();\r
317             Future<RpcResult<GetDpidFromInterfaceOutput>>\r
318                     dpIdOutput =\r
319                     interfaceManagerRpcService.getDpidFromInterface(dpIdInput);\r
320             RpcResult<GetDpidFromInterfaceOutput> dpIdResult = dpIdOutput.get();\r
321             if (dpIdResult.isSuccessful()) {\r
322                 nodeId = dpIdResult.getResult().getDpid();\r
323             } else {\r
324                 LOG.error("Could not retrieve DPN Id for interface {}", ifName);\r
325             }\r
326         } catch (InterruptedException | ExecutionException e) {\r
327             LOG.error("Exception when getting dpn for interface {}", ifName,  e);\r
328         }\r
329         return nodeId;\r
330     }\r
331 \r
332 }\r