2 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved.
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
8 package org.opendaylight.vpnservice.natservice.internal;
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;
39 import com.google.common.base.Optional;
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;
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;
58 public InterfaceStateEventListener(final DataBroker db){
59 super(Interface.class);
64 public void setMdsalManager(IMdsalApiManager mdsalManager) {
65 this.mdsalManager = mdsalManager;
68 public void setFloatingIpListener(FloatingIPListener floatingIPListener) {
69 this.floatingIPListener = floatingIPListener;
72 public void setNeutronVpnService(NeutronvpnService neutronVpnService) {
73 this.neutronVpnService = neutronVpnService;
76 public void setNaptManager(NaptManager naptManager) {
77 this.naptManager = naptManager;
81 private void registerListener(final DataBroker db) {
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);
91 private InstanceIdentifier<Interface> getWildCardPath() {
92 return InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
96 protected void remove(InstanceIdentifier<Interface> identifier, Interface delintrf) {
97 LOG.trace("NAT Service : Interface {} removed event received", delintrf);
99 if (delintrf != null) {
100 String interfaceName = delintrf.getName();
101 LOG.trace("NAT Service : Port removed event received for interface {} ", interfaceName);
103 BigInteger dpnId = NatUtil.getDpIdFromInterface(delintrf);
104 LOG.trace("NAT Service : PORT_REMOVE: Interface {} down in Dpn {}", interfaceName, dpnId);
106 String routerName = getRouterIdForPort(dataBroker, interfaceName);
107 if (routerName != null) {
108 processInterfaceRemoved(interfaceName, routerName);
109 removeSnatEntriesForPort(interfaceName,routerName);
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);
115 } catch(Exception e) {
116 LOG.error("NAT Service : Exception caught in InterfaceOperationalStateRemove : {}", e);
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)) {
128 LOG.trace("NAT Service : Port DOWN event received for interface {} ", interfaceName);
130 BigInteger dpnId = NatUtil.getDpIdFromInterface(update);
131 LOG.trace("NAT Service : PORT_DOWN: Interface {} down in Dpn {}", interfaceName, dpnId);
133 String routerName = getRouterIdForPort(dataBroker, interfaceName);
134 if (routerName != null) {
135 removeSnatEntriesForPort(interfaceName,routerName);
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);
140 } catch (Exception ex) {
141 LOG.error("NAT Service : Exception caught in InterfaceOperationalStateDown : {}",ex);
147 protected void add(InstanceIdentifier<Interface> identifier, Interface intrf) {
148 LOG.trace("NAT Service : Interface {} up event received", intrf);
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);
156 } catch (Exception ex) {
157 LOG.error("NAT Service : Exception caught in Interface Operational State Up event: {}", ex);
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);
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);
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);
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
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);
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);
200 String externalIpAddress = ipPortExternal.getIpAddress();
201 Integer portNumber = ipPortExternal.getPortNum();
203 //build and remove the flow in inboundtable
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);
211 String internalIpPort = internalIp + ":" + portnum;
212 // delete the entry from IntExtIpPortMap DS
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);
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);
225 LOG.debug("NAT Service : No {} session for interface {} with internalIP {} in router with id {}",protocol,interfaceName,internalIp,routerId);
231 private String getRouterIdForPort(DataBroker dataBroker,String interfaceName) {
232 String vpnName = null, routerName = null;
233 if (NatUtil.isVpnInterfaceConfigured(dataBroker, interfaceName)) {
235 VpnInterface vpnInterface = null;
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);
241 if (vpnInterface != null) {
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);
249 if (vpnName != null) {
251 routerName = NatUtil.getRouterIdfromVpnId(dataBroker, vpnName);
252 } catch (Exception e) {
253 LOG.error("NAT Service : Unable to get routerId for vpnName {} - {}", vpnName, e);
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);
262 LOG.info("NAT Service : Interface {} associated to routerId {} is not associated to external network",
263 interfaceName, routerName);
266 LOG.debug("Router is not associated to vpnname {} for interface {}",vpnName,interfaceName);
269 LOG.debug("NAT Service : vpnName not found for vpnInterface {} of port {}",vpnInterface,interfaceName);
273 LOG.debug("NAT Service : Interface {} is not a vpninterface",interfaceName);
278 private List<ProtocolTypes> getPortocolList() {
279 List<ProtocolTypes> protocollist = Lists.newArrayList();
280 protocollist.add(ProtocolTypes.TCP);
281 protocollist.add(ProtocolTypes.UDP);
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();
296 private void removeNatFlow(BigInteger dpnId, short tableId,Long routerId, String ipAddress,int ipPort) {
298 String switchFlowRef = NatUtil.getNaptFlowRef(dpnId, tableId, String.valueOf(routerId), ipAddress, ipPort);
299 FlowEntity snatFlowEntity = NatUtil.buildFlowEntity(dpnId, tableId, switchFlowRef);
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);
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);
314 InstanceIdentifier<RouterPorts> pIdentifier = NatUtil.buildRouterPortsIdentifier(routerId);
315 for (IpMapping ipMapping : ipMappingList) {
316 floatingIPListener.createNATFlowEntries(portName, ipMapping, pIdentifier, routerId);
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);
328 InstanceIdentifier<RouterPorts> pIdentifier = NatUtil.buildRouterPortsIdentifier(routerId);
329 for (IpMapping ipMapping : ipMappingList) {
330 floatingIPListener.removeNATFlowEntries(portName, ipMapping, pIdentifier, routerId);
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);
341 List<IpMapping> ipMappingList = port.get().getIpMapping();
342 return ipMappingList;
345 private List<String> getFixedIpsForPort (String interfname) {
346 LOG.debug("getFixedIpsForPort method is called for interface {}",interfname);
348 Future<RpcResult<GetFixedIPsForNeutronPortOutput>> result =
349 neutronVpnService.getFixedIPsForNeutronPort(new GetFixedIPsForNeutronPortInputBuilder()
350 .setPortId(new Uuid(interfname)).build());
352 RpcResult<GetFixedIPsForNeutronPortOutput> rpcResult = result.get();
353 if(!rpcResult.isSuccessful()) {
354 LOG.warn("NAT Service : RPC Call to GetFixedIPsForNeutronPortOutput returned with Errors {}", rpcResult.getErrors());
356 return rpcResult.getResult().getFixedIPs();
358 } catch (InterruptedException | ExecutionException | NullPointerException ex ) {
359 LOG.error("NAT Service : Exception while receiving fixedIps for port {}",interfname);
365 public void close() throws Exception {
366 if (listenerRegistration != null) {
368 listenerRegistration.close();
369 } catch (final Exception e) {
370 LOG.error("NAT Service : Error when cleaning up DataChangeListener.", e);
372 listenerRegistration = null;
374 LOG.info("NAT Service : Interface listener Closed");