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