Bump versions by 0.1.0 for next dev cycle
[vpnservice.git] / natservice / natservice-impl / src / main / java / org / opendaylight / vpnservice / natservice / internal / InterfaceStateEventListener.java
1 /*
2  * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.vpnservice.natservice.internal;
9
10 import com.google.common.collect.Lists;
11 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
12 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
13 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
14 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
15 import org.opendaylight.vpnservice.mdsalutil.*;
16 import org.opendaylight.vpnservice.mdsalutil.interfaces.IMdsalApiManager;
17 import org.opendaylight.vpnservice.mdsalutil.packet.IPProtocols;
18 import org.opendaylight.yang.gen.v1.urn.huawei.params.xml.ns.yang.l3vpn.rev140815.vpn.interfaces.VpnInterface;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.NaptSwitches;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.RouterPorts;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.Ports;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.floating.ip.info.router.ports.ports.IpMapping;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.ProtocolTypes;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.intext.ip.port.map.ip.port.mapping.intext.ip.protocol.type.ip.port.map.IpPortExternal;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitch;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.natservice.rev160111.napt.switches.RouterToNaptSwitchKey;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.GetFixedIPsForNeutronPortInputBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.GetFixedIPsForNeutronPortOutput;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.neutronvpn.rev150602.NeutronvpnService;
33 import org.opendaylight.yangtools.concepts.ListenerRegistration;
34 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
35 import org.opendaylight.yangtools.yang.common.RpcResult;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
38
39 import com.google.common.base.Optional;
40
41 import java.math.BigInteger;
42 import java.net.InetAddress;
43 import java.net.UnknownHostException;
44 import java.util.ArrayList;
45 import java.util.List;
46 import java.util.concurrent.ExecutionException;
47 import java.util.concurrent.Future;
48
49 public class InterfaceStateEventListener extends AbstractDataChangeListener<Interface> implements AutoCloseable {
50     private static final Logger LOG = LoggerFactory.getLogger(InterfaceStateEventListener.class);
51     private ListenerRegistration<DataChangeListener> listenerRegistration;
52     private final DataBroker dataBroker;
53     private IMdsalApiManager mdsalManager;
54     private FloatingIPListener floatingIPListener;
55     private NaptManager naptManager;
56     private NeutronvpnService neutronVpnService;
57
58     public InterfaceStateEventListener(final DataBroker db){
59         super(Interface.class);
60         dataBroker = db;
61         registerListener(db);
62     }
63
64     public void setMdsalManager(IMdsalApiManager mdsalManager) {
65         this.mdsalManager = mdsalManager;
66     }
67
68     public void setFloatingIpListener(FloatingIPListener floatingIPListener) {
69         this.floatingIPListener = floatingIPListener;
70     }
71
72     public void setNeutronVpnService(NeutronvpnService neutronVpnService) {
73         this.neutronVpnService = neutronVpnService;
74     }
75
76     public void setNaptManager(NaptManager naptManager) {
77         this.naptManager = naptManager;
78
79     }
80
81     private void registerListener(final DataBroker db) {
82         try {
83             listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
84                     getWildCardPath(), InterfaceStateEventListener.this, AsyncDataBroker.DataChangeScope.SUBTREE);
85         } catch (final Exception e) {
86             LOG.error("Interface DataChange listener registration failed", e);
87             throw new IllegalStateException("Nexthop Manager registration Listener failed.", e);
88         }
89     }
90
91     private InstanceIdentifier<Interface> getWildCardPath() {
92         return InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
93     }
94
95     @Override
96     protected void remove(InstanceIdentifier<Interface> identifier, Interface delintrf) {
97         LOG.trace("NAT Service : Interface {} removed event received", delintrf);
98         try {
99             if (delintrf != null) {
100                 String interfaceName = delintrf.getName();
101                 LOG.trace("NAT Service : Port removed event received for interface {} ", interfaceName);
102
103                 BigInteger dpnId = NatUtil.getDpIdFromInterface(delintrf);
104                 LOG.trace("NAT Service : PORT_REMOVE: Interface {} down in Dpn {}", interfaceName, dpnId);
105
106                 String routerName = getRouterIdForPort(dataBroker, interfaceName);
107                 if (routerName != null) {
108                     processInterfaceRemoved(interfaceName, routerName);
109                     removeSnatEntriesForPort(interfaceName,routerName);
110                 } else {
111                     LOG.debug("NAT Service : PORT_REMOVE: Router Id is null either Interface {} is not associated " +
112                                 "to router or failed to retrieve routerId due to exception", interfaceName);
113                 }
114             }
115         } catch(Exception e) {
116             LOG.error("NAT Service : Exception caught in InterfaceOperationalStateRemove : {}", e);
117         }
118     }
119
120     @Override
121     protected void update(InstanceIdentifier<Interface> identifier, Interface original, Interface update) {
122         LOG.trace("NAT Service : Operation Interface update event - Old: {}, New: {}", original, update);
123         String interfaceName = update.getName();
124         if (update.getOperStatus().equals(Interface.OperStatus.Up)) {
125             LOG.trace("NAT Service : Port UP event received for interface {} ", interfaceName);
126         } else if (update.getOperStatus().equals(Interface.OperStatus.Down)) {
127             try {
128                 LOG.trace("NAT Service : Port DOWN event received for interface {} ", interfaceName);
129
130                 BigInteger dpnId = NatUtil.getDpIdFromInterface(update);
131                 LOG.trace("NAT Service : PORT_DOWN: Interface {} down in Dpn {}", interfaceName, dpnId);
132
133                 String routerName = getRouterIdForPort(dataBroker, interfaceName);
134                 if (routerName != null) {
135                     removeSnatEntriesForPort(interfaceName,routerName);
136                 } else {
137                     LOG.debug("NAT Service : PORT_DOWN: Router Id is null, either Interface {} is not associated " +
138                             "to router or failed to retrieve routerId due to exception", interfaceName);
139                 }
140             } catch (Exception ex) {
141                 LOG.error("NAT Service : Exception caught in InterfaceOperationalStateDown : {}",ex);
142             }
143         }
144     }
145
146     @Override
147     protected void add(InstanceIdentifier<Interface> identifier, Interface intrf) {
148         LOG.trace("NAT Service : Interface {} up event received", intrf);
149         try {
150             String interfaceName = intrf.getName();
151             LOG.trace("NAT Service : Port added event received for interface {} ", interfaceName);
152             String routerId = getRouterIdForPort(dataBroker,interfaceName);
153             if (routerId != null) {
154                 processInterfaceAdded(interfaceName, routerId);
155             }
156         } catch (Exception ex) {
157         LOG.error("NAT Service : Exception caught in Interface Operational State Up event: {}", ex);
158         }
159     }
160
161     private void removeSnatEntriesForPort(String interfaceName,String routerName) {
162         Long routerId = NatUtil.getVpnId(dataBroker, routerName);
163         if (routerId == NatConstants.INVALID_ID) {
164             LOG.error("NAT Service : routerId not found for routername {}",routerName);
165             return;
166         }
167         BigInteger naptSwitch = getNaptSwitchforRouter(dataBroker,routerName);
168         if (naptSwitch == null) {
169             LOG.error("NAT Service : NaptSwitch is not elected for router {} with Id {}",routerName,routerId);
170             return;
171         }
172         //getInternalIp for port
173         List<String> fixedIps = getFixedIpsForPort(interfaceName);
174         if (fixedIps == null) {
175             LOG.debug("NAT Service : Internal Ips not found for InterfaceName {} in router {} with id {}",interfaceName,routerName,routerId);
176             return;
177         }
178         List<ProtocolTypes> protocolTypesList = getPortocolList();
179         for (String internalIp : fixedIps) {
180             LOG.debug("NAT Service : Internal Ip retrieved for interface {} is {} in router with Id {}",interfaceName,internalIp,routerId);
181             for(ProtocolTypes protocol : protocolTypesList) {
182                 List<Integer> portList = NatUtil.getInternalIpPortListInfo(dataBroker, routerId, internalIp, protocol);
183                 if (portList != null) {
184                     for (Integer portnum : portList) {
185                         //build and remove the flow in outbound table
186                         try {
187                             removeNatFlow(naptSwitch, NatConstants.OUTBOUND_NAPT_TABLE, routerId, internalIp, portnum);
188                         } catch (Exception ex) {
189                             LOG.error("NAT Service : Failed to remove snat flow for internalIP {} with Port {} protocol {} for routerId {} " +
190                                     "in OUTBOUNDTABLE of NaptSwitch {}: {}",internalIp,portnum,protocol,routerId,naptSwitch,ex);
191                         }
192                         //Get the external IP address and the port from the model
193                         NAPTEntryEvent.Protocol proto = protocol.toString().equals(ProtocolTypes.TCP.toString()) ? NAPTEntryEvent.Protocol.TCP : NAPTEntryEvent.Protocol.UDP;
194                         IpPortExternal ipPortExternal = NatUtil.getExternalIpPortMap(dataBroker, routerId,
195                                 internalIp, String.valueOf(portnum), proto);
196                         if (ipPortExternal == null) {
197                             LOG.error("Mapping for internalIp {} with port {} is not found in router with Id {}",internalIp,portnum,routerId);
198                             return;
199                         }
200                         String externalIpAddress = ipPortExternal.getIpAddress();
201                         Integer portNumber = ipPortExternal.getPortNum();
202
203                         //build and remove the flow in inboundtable
204                         try {
205                             removeNatFlow(naptSwitch, NatConstants.INBOUND_NAPT_TABLE,routerId, externalIpAddress, portNumber);
206                         } catch (Exception ex) {
207                             LOG.error("NAT Service : Failed to remove snat flow internalIP {} with Port {} protocol {} for routerId {} " +
208                                     "in INBOUNDTABLE of naptSwitch {} : {}",externalIpAddress,portNumber,protocol,routerId,naptSwitch,ex);
209                         }
210
211                         String internalIpPort = internalIp + ":" + portnum;
212                         // delete the entry from IntExtIpPortMap DS
213                         try {
214                             naptManager.removeFromIpPortMapDS(routerId, internalIpPort, proto);
215                             naptManager.removePortFromPool(internalIpPort,externalIpAddress);
216                         } catch (Exception ex){
217                             LOG.error("NAPT Service : releaseIpExtPortMapping failed, Removal of ipportmap {} for router {} failed {}" ,
218                                     internalIpPort, routerId, ex);
219                         }
220                     }
221                     // delete the entry from SnatIntIpPortMap DS
222                     LOG.debug("NAT Service : Removing InternalIp :{} portlist :{} for protocol :{} of router {}",internalIp,portList,protocol,routerId);
223                     naptManager.removeFromSnatIpPortDS(routerId,internalIp);
224                 } else {
225                     LOG.debug("NAT Service : No {} session for interface {} with internalIP {} in router with id {}",protocol,interfaceName,internalIp,routerId);
226                 }
227             }
228         }
229     }
230
231     private String getRouterIdForPort(DataBroker dataBroker,String interfaceName) {
232         String vpnName = null, routerName = null;
233         if (NatUtil.isVpnInterfaceConfigured(dataBroker, interfaceName)) {
234             //getVpnInterface
235             VpnInterface vpnInterface = null;
236             try {
237                 vpnInterface = NatUtil.getConfiguredVpnInterface(dataBroker, interfaceName);
238             } catch (Exception ex) {
239                 LOG.error("NAT Service : Unable to process for interface {} as it is not configured", interfaceName);
240             }
241             if (vpnInterface != null) {
242                 //getVpnName
243                 try {
244                     vpnName = vpnInterface.getVpnInstanceName();
245                     LOG.debug("NAT Service : Retrieved VpnName {}", vpnName);
246                 } catch (Exception e) {
247                     LOG.error("NAT Service : Unable to get vpnname for vpninterface {} - {}", vpnInterface, e);
248                 }
249                 if (vpnName != null) {
250                     try {
251                         routerName = NatUtil.getRouterIdfromVpnId(dataBroker, vpnName);
252                     } catch (Exception e) {
253                         LOG.error("NAT Service : Unable to get routerId for vpnName {} - {}", vpnName, e);
254                     }
255                     if (routerName != null) {
256                         //check router is associated to external network
257                         if (NatUtil.isSnatEnabledForRouterId(dataBroker, routerName)) {
258                             LOG.debug("NAT Service : Retreived Router Id {} for vpnname {} associated to interface {}",
259                                     routerName,vpnName,interfaceName);
260                             return routerName;
261                         } else {
262                             LOG.info("NAT Service : Interface {} associated to routerId {} is not associated to external network",
263                                     interfaceName, routerName);
264                         }
265                     } else {
266                         LOG.debug("Router is not associated to vpnname {} for interface {}",vpnName,interfaceName);
267                     }
268                 } else {
269                     LOG.debug("NAT Service : vpnName not found for vpnInterface {} of port {}",vpnInterface,interfaceName);
270                 }
271             }
272         } else {
273             LOG.debug("NAT Service : Interface {} is not a vpninterface",interfaceName);
274         }
275         return null;
276     }
277
278     private List<ProtocolTypes> getPortocolList() {
279         List<ProtocolTypes> protocollist = Lists.newArrayList();
280         protocollist.add(ProtocolTypes.TCP);
281         protocollist.add(ProtocolTypes.UDP);
282         return protocollist;
283     }
284
285     private BigInteger getNaptSwitchforRouter(DataBroker broker,String routerName) {
286         InstanceIdentifier<RouterToNaptSwitch> rtrNaptSw = InstanceIdentifier.builder(NaptSwitches.class).child
287                 (RouterToNaptSwitch.class, new RouterToNaptSwitchKey(routerName)).build();
288         Optional<RouterToNaptSwitch> routerToNaptSwitchData = NatUtil.read(broker, LogicalDatastoreType.OPERATIONAL, rtrNaptSw);
289         if (routerToNaptSwitchData.isPresent()) {
290             RouterToNaptSwitch routerToNaptSwitchInstance = routerToNaptSwitchData.get();
291             return routerToNaptSwitchInstance.getPrimarySwitchId();
292         }
293         return null;
294     }
295
296     private void removeNatFlow(BigInteger dpnId, short tableId,Long routerId, String ipAddress,int ipPort) {
297
298         String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, tableId, String.valueOf(routerId), ipAddress, ipPort);
299         FlowEntity snatFlowEntity = NatUtil.buildFlowEntity(dpnId, tableId, switchFlowRef);
300
301         mdsalManager.removeFlow(snatFlowEntity);
302         LOG.debug("NAT Service : Removed the flow in table {} for the switch with the DPN ID {} for router {} ip {} port {}",
303                 tableId,dpnId,routerId,ipAddress,ipPort);
304     }
305
306     private void processInterfaceAdded(String portName, String rtrId) {
307         LOG.trace("Processing Interface Add Event for interface {}", portName);
308         String routerId = getRouterIdForPort(dataBroker, portName);
309         List<IpMapping> ipMappingList = getIpMappingForPortName(portName, routerId);
310         if (ipMappingList == null || ipMappingList.isEmpty()) {
311             LOG.trace("Ip Mapping list is empty/null for portname {}", portName);
312             return;
313         }
314         InstanceIdentifier<RouterPorts> pIdentifier = NatUtil.buildRouterPortsIdentifier(routerId);
315         for (IpMapping ipMapping : ipMappingList) {
316             floatingIPListener.createNATFlowEntries(portName, ipMapping, pIdentifier, routerId);
317         }
318     }
319
320     private void processInterfaceRemoved(String portName, String rtrId) {
321         LOG.trace("Processing Interface Removed Event for interface {}", portName);
322         String routerId = getRouterIdForPort(dataBroker, portName);
323         List<IpMapping> ipMappingList = getIpMappingForPortName(portName, routerId);
324         if (ipMappingList == null || ipMappingList.isEmpty()) {
325             LOG.trace("Ip Mapping list is empty/null for portName {}", portName);
326             return;
327         }
328         InstanceIdentifier<RouterPorts> pIdentifier = NatUtil.buildRouterPortsIdentifier(routerId);
329         for (IpMapping ipMapping : ipMappingList) {
330             floatingIPListener.removeNATFlowEntries(portName, ipMapping, pIdentifier, routerId);
331         }
332     }
333
334     private List<IpMapping> getIpMappingForPortName(String portName, String routerId) {
335         InstanceIdentifier<Ports> portToIpMapIdentifier = NatUtil.buildPortToIpMapIdentifier(routerId, portName);
336         Optional<Ports> port = NatUtil.read(dataBroker, LogicalDatastoreType.CONFIGURATION, portToIpMapIdentifier);
337         if(!port.isPresent()) {
338             LOG.error("NAT Service : Unable to read router port entry for router ID {} and port name {}", routerId, portName);
339             return null;
340         }
341         List<IpMapping> ipMappingList = port.get().getIpMapping();
342         return ipMappingList;
343     }
344
345     private List<String> getFixedIpsForPort (String interfname) {
346         LOG.debug("getFixedIpsForPort method is called for interface {}",interfname);
347         try {
348             Future<RpcResult<GetFixedIPsForNeutronPortOutput>> result =
349                     neutronVpnService.getFixedIPsForNeutronPort(new GetFixedIPsForNeutronPortInputBuilder()
350                             .setPortId(new Uuid(interfname)).build());
351
352             RpcResult<GetFixedIPsForNeutronPortOutput> rpcResult = result.get();
353             if(!rpcResult.isSuccessful()) {
354                 LOG.warn("NAT Service : RPC Call to GetFixedIPsForNeutronPortOutput returned with Errors {}", rpcResult.getErrors());
355             } else {
356                 return rpcResult.getResult().getFixedIPs();
357             }
358         } catch (InterruptedException | ExecutionException | NullPointerException ex ) {
359             LOG.error("NAT Service : Exception while receiving fixedIps for port {}",interfname);
360         }
361         return null;
362     }
363
364     @Override
365     public void close() throws Exception {
366         if (listenerRegistration != null) {
367             try {
368                 listenerRegistration.close();
369             } catch (final Exception e) {
370                 LOG.error("NAT Service : Error when cleaning up DataChangeListener.", e);
371             }
372             listenerRegistration = null;
373         }
374         LOG.info("NAT Service : Interface listener Closed");
375     }
376 }