X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=itm%2Fitm-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fvpnservice%2Fitm%2Flisteners%2FInterfaceStateListener.java;fp=itm%2Fitm-impl%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fvpnservice%2Fitm%2Flisteners%2FInterfaceStateListener.java;h=49c9bda8e216005c39bbee1f1497595545b58f57;hb=ad664a0c796d1b29f0f337a4ce0a26ce9b3c2238;hp=0000000000000000000000000000000000000000;hpb=3e0f21d10b63d08737ce649b50c2412368147687;p=vpnservice.git diff --git a/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/listeners/InterfaceStateListener.java b/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/listeners/InterfaceStateListener.java new file mode 100644 index 00000000..49c9bda8 --- /dev/null +++ b/itm/itm-impl/src/main/java/org/opendaylight/vpnservice/itm/listeners/InterfaceStateListener.java @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.vpnservice.itm.listeners; + +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.DataChangeListener; +import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.vpnservice.itm.impl.ItmUtils; +import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.ParentRefs; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TepTypeBase; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TepTypeExternal; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TepTypeHwvtep; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TepTypeInternal; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelsState; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnel; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnel.list.InternalTunnel; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnels_state.StateTunnelList; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnels_state.StateTunnelListBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnels_state.StateTunnelListKey; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnels_state.state.tunnel.list.DstInfoBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnels_state.state.tunnel.list.SrcInfoBuilder; +import org.opendaylight.yangtools.concepts.ListenerRegistration; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.base.Optional; +import com.google.common.net.InetAddresses; + +public class InterfaceStateListener extends AbstractDataChangeListener implements AutoCloseable { + private static final Logger LOG = LoggerFactory.getLogger(InterfaceStateListener.class); + + private ListenerRegistration listenerRegistration; + private final DataBroker broker; + + public InterfaceStateListener(final DataBroker db) { + super(Interface.class); + broker = db; + registerListener(db); + } + + @Override + public void close() throws Exception { + if (listenerRegistration != null) { + try { + listenerRegistration.close(); + } catch (final Exception e) { + LOG.error("Error when cleaning up interface state listener", e); + } + listenerRegistration = null; + } + LOG.info("Interface state listener Closed"); + } + + private void registerListener(final DataBroker db) { + try { + listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL, + getWildCardPath(), InterfaceStateListener.this, DataChangeScope.SUBTREE); + } catch (final Exception e) { + LOG.error("ITM Interfaces State listener registration fail!", e); + throw new IllegalStateException("ITM Interfaces State listener registration failed.", e); + } + } + + private InstanceIdentifier getWildCardPath() { + return InstanceIdentifier.create(InterfacesState.class).child(Interface.class); + } + + @Override + protected void add(InstanceIdentifier identifier, Interface iface) { + LOG.trace("Interface added: {}", iface); + if(ItmUtils.isItmIfType(iface.getType())) { + LOG.debug("Interface of type Tunnel added: {}", iface.getName()); + updateItmState(iface); + } + } + + @Override + protected void remove(InstanceIdentifier identifier, + Interface iface) { + LOG.trace("Interface deleted: {}", iface); + if(ItmUtils.isItmIfType(iface.getType())) { + LOG.debug("Tunnel interface deleted: {}", iface.getName()); + StateTunnelListKey tlKey = null; + tlKey = ItmUtils.getTunnelStateKey(iface); + InstanceIdentifier stListId = buildStateTunnelListId(tlKey); + LOG.trace("Deleting tunnel_state for Id: {}", stListId); + ItmUtils.asyncDelete(LogicalDatastoreType.OPERATIONAL, stListId, broker, ItmUtils.DEFAULT_CALLBACK); + } + } + + @Override + protected void update(InstanceIdentifier identifier, + Interface original, Interface update) { + /* + * update contains only delta, may not include iftype + * Note: This assumes type can't be edited on the fly + */ + if(ItmUtils.isItmIfType(original.getType())) { + LOG.trace("Interface updated. Old: {} New: {}", original, update); + OperStatus operStatus = update.getOperStatus(); + if( operStatus != null ) { + LOG.debug("Tunnel Interface {} changed state to {}", original.getName(), operStatus); + updateItmState(update); + } + } + } + + private void updateItmState(Interface iface) { + StateTunnelListKey tlKey = null; + tlKey = ItmUtils.getTunnelStateKey(iface); + LOG.trace("TunnelStateKey: {} for interface: {}", tlKey, iface.getName()); + InstanceIdentifier stListId = buildStateTunnelListId(tlKey); + Optional tunnelsState = ItmUtils.read(LogicalDatastoreType.OPERATIONAL, stListId, broker); + StateTunnelList tunnelStateList; + StateTunnelListBuilder stlBuilder; + boolean tunnelState = (iface.getOperStatus().equals(OperStatus.Up)) ? (true):(false); + if(tunnelsState.isPresent()) { + tunnelStateList = tunnelsState.get(); + stlBuilder = new StateTunnelListBuilder(tunnelStateList); + stlBuilder.setTunnelState(tunnelState); + StateTunnelList stList = stlBuilder.build(); + LOG.trace("Updating tunnel_state: {} for Id: {}",stList, stListId); + ItmUtils.asyncUpdate(LogicalDatastoreType.OPERATIONAL, stListId, stList, broker, ItmUtils.DEFAULT_CALLBACK); + } else { + // Create new Tunnel State + try { + /*FIXME: + * A defensive try-catch to find issues without disrupting existing behavior. + */ + tunnelStateList = buildStateTunnelList(tlKey, iface.getName(), tunnelState); + LOG.trace("Creating tunnel_state: {} for Id: {}", tunnelStateList, stListId); + ItmUtils.asyncUpdate(LogicalDatastoreType.OPERATIONAL, stListId, tunnelStateList, broker, + ItmUtils.DEFAULT_CALLBACK); + } catch (Exception e) { + LOG.warn("Exception trying to create tunnel state for {}", iface.getName(), e); + } + } + } + + private StateTunnelList buildStateTunnelList(StateTunnelListKey tlKey, String name, boolean state) { + StateTunnelListBuilder stlBuilder = new StateTunnelListBuilder(); + org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface = + ItmUtils.getInterface(name, broker); + IfTunnel ifTunnel = iface.getAugmentation(IfTunnel.class); + ParentRefs parentRefs = iface.getAugmentation(ParentRefs.class); + if(ifTunnel == null && parentRefs == null) { + return null; + } + DstInfoBuilder dstInfoBuilder = new DstInfoBuilder(); + SrcInfoBuilder srcInfoBuilder = new SrcInfoBuilder(); + dstInfoBuilder.setTepIp(ifTunnel.getTunnelDestination()); + srcInfoBuilder.setTepIp(ifTunnel.getTunnelSource()); + //TODO: Add/Improve logic for device type + InternalTunnel internalTunnel = ItmUtils.itmCache.getInternalTunnel(name); + ExternalTunnel externalTunnel = ItmUtils.itmCache.getExternalTunnel(name); + if(internalTunnel == null && externalTunnel == null) { + // both not present in cache. let us update and try again. + ItmUtils.updateTunnelsCache(broker); + internalTunnel = ItmUtils.itmCache.getInternalTunnel(name); + externalTunnel = ItmUtils.itmCache.getExternalTunnel(name); + } + if(internalTunnel != null) { + srcInfoBuilder.setTepDeviceId(internalTunnel.getSourceDPN().toString()).setTepDeviceType(TepTypeInternal.class); + dstInfoBuilder.setTepDeviceId(internalTunnel.getDestinationDPN().toString()) + .setTepDeviceType(TepTypeInternal.class); + stlBuilder.setTransportType(internalTunnel.getTransportType()); + } else if(externalTunnel != null) { + ExternalTunnel tunnel = ItmUtils.itmCache.getExternalTunnel(name); + srcInfoBuilder.setTepDeviceId(tunnel.getSourceDevice()) + .setTepDeviceType(getDeviceType(tunnel.getSourceDevice())); + dstInfoBuilder.setTepDeviceId(tunnel.getDestinationDevice()) + .setTepDeviceType(getDeviceType(tunnel.getSourceDevice())) + .setTepIp(ifTunnel.getTunnelDestination()); + stlBuilder.setTransportType(tunnel.getTransportType()); + } + stlBuilder.setKey(tlKey).setTunnelInterfaceName(name).setTunnelState(state) + .setDstInfo(dstInfoBuilder.build()).setSrcInfo(srcInfoBuilder.build()); + return stlBuilder.build(); + } + + private Class getDeviceType(String device) { + if(device.startsWith("hwvtep")) { + return TepTypeHwvtep.class; + } else if(InetAddresses.isInetAddress(device)) { + return TepTypeExternal.class; + } else { + return TepTypeInternal.class; + } + } + + private InstanceIdentifier buildStateTunnelListId(StateTunnelListKey tlKey) { + InstanceIdentifier stListId = + InstanceIdentifier.builder(TunnelsState.class).child(StateTunnelList.class, tlKey).build(); + return stListId; + } + +}