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