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
9 package org.opendaylight.vpnservice.itm.listeners;
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.DataChangeScope;
14 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
15 import org.opendaylight.vpnservice.itm.impl.ItmUtils;
16 import org.opendaylight.vpnservice.mdsalutil.AbstractDataChangeListener;
17 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
18 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfTunnel;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.ParentRefs;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TepTypeBase;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TepTypeExternal;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TepTypeHwvtep;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TepTypeInternal;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.TunnelsState;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.external.tunnel.list.ExternalTunnel;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnel.list.InternalTunnel;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnels_state.StateTunnelList;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnels_state.StateTunnelListBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnels_state.StateTunnelListKey;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnels_state.state.tunnel.list.DstInfoBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.itm.op.rev150701.tunnels_state.state.tunnel.list.SrcInfoBuilder;
34 import org.opendaylight.yangtools.concepts.ListenerRegistration;
35 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
36 import org.slf4j.Logger;
37 import org.slf4j.LoggerFactory;
39 import com.google.common.base.Optional;
40 import com.google.common.net.InetAddresses;
42 public class InterfaceStateListener extends AbstractDataChangeListener<Interface> implements AutoCloseable {
43 private static final Logger LOG = LoggerFactory.getLogger(InterfaceStateListener.class);
45 private ListenerRegistration<DataChangeListener> listenerRegistration;
46 private final DataBroker broker;
48 public InterfaceStateListener(final DataBroker db) {
49 super(Interface.class);
55 public void close() throws Exception {
56 if (listenerRegistration != null) {
58 listenerRegistration.close();
59 } catch (final Exception e) {
60 LOG.error("Error when cleaning up interface state listener", e);
62 listenerRegistration = null;
64 LOG.info("Interface state listener Closed");
67 private void registerListener(final DataBroker db) {
69 listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
70 getWildCardPath(), InterfaceStateListener.this, DataChangeScope.SUBTREE);
71 } catch (final Exception e) {
72 LOG.error("ITM Interfaces State listener registration fail!", e);
73 throw new IllegalStateException("ITM Interfaces State listener registration failed.", e);
77 private InstanceIdentifier<Interface> getWildCardPath() {
78 return InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
82 protected void add(InstanceIdentifier<Interface> identifier, Interface iface) {
83 LOG.trace("Interface added: {}", iface);
84 if(ItmUtils.isItmIfType(iface.getType())) {
85 LOG.debug("Interface of type Tunnel added: {}", iface.getName());
86 updateItmState(iface);
91 protected void remove(InstanceIdentifier<Interface> identifier,
93 LOG.trace("Interface deleted: {}", iface);
94 if(ItmUtils.isItmIfType(iface.getType())) {
95 LOG.debug("Tunnel interface deleted: {}", iface.getName());
96 StateTunnelListKey tlKey = null;
97 tlKey = ItmUtils.getTunnelStateKey(iface);
98 InstanceIdentifier<StateTunnelList> stListId = buildStateTunnelListId(tlKey);
99 LOG.trace("Deleting tunnel_state for Id: {}", stListId);
100 ItmUtils.asyncDelete(LogicalDatastoreType.OPERATIONAL, stListId, broker, ItmUtils.DEFAULT_CALLBACK);
105 protected void update(InstanceIdentifier<Interface> identifier,
106 Interface original, Interface update) {
108 * update contains only delta, may not include iftype
109 * Note: This assumes type can't be edited on the fly
111 if(ItmUtils.isItmIfType(original.getType())) {
112 LOG.trace("Interface updated. Old: {} New: {}", original, update);
113 OperStatus operStatus = update.getOperStatus();
114 if( operStatus != null ) {
115 LOG.debug("Tunnel Interface {} changed state to {}", original.getName(), operStatus);
116 updateItmState(update);
121 private void updateItmState(Interface iface) {
122 StateTunnelListKey tlKey = null;
123 tlKey = ItmUtils.getTunnelStateKey(iface);
124 LOG.trace("TunnelStateKey: {} for interface: {}", tlKey, iface.getName());
125 InstanceIdentifier<StateTunnelList> stListId = buildStateTunnelListId(tlKey);
126 Optional<StateTunnelList> tunnelsState = ItmUtils.read(LogicalDatastoreType.OPERATIONAL, stListId, broker);
127 StateTunnelList tunnelStateList;
128 StateTunnelListBuilder stlBuilder;
129 boolean tunnelState = (iface.getOperStatus().equals(OperStatus.Up)) ? (true):(false);
130 if(tunnelsState.isPresent()) {
131 tunnelStateList = tunnelsState.get();
132 stlBuilder = new StateTunnelListBuilder(tunnelStateList);
133 stlBuilder.setTunnelState(tunnelState);
134 StateTunnelList stList = stlBuilder.build();
135 LOG.trace("Updating tunnel_state: {} for Id: {}",stList, stListId);
136 ItmUtils.asyncUpdate(LogicalDatastoreType.OPERATIONAL, stListId, stList, broker, ItmUtils.DEFAULT_CALLBACK);
138 // Create new Tunnel State
141 * A defensive try-catch to find issues without disrupting existing behavior.
143 tunnelStateList = buildStateTunnelList(tlKey, iface.getName(), tunnelState);
144 LOG.trace("Creating tunnel_state: {} for Id: {}", tunnelStateList, stListId);
145 ItmUtils.asyncUpdate(LogicalDatastoreType.OPERATIONAL, stListId, tunnelStateList, broker,
146 ItmUtils.DEFAULT_CALLBACK);
147 } catch (Exception e) {
148 LOG.warn("Exception trying to create tunnel state for {}", iface.getName(), e);
153 private StateTunnelList buildStateTunnelList(StateTunnelListKey tlKey, String name, boolean state) {
154 StateTunnelListBuilder stlBuilder = new StateTunnelListBuilder();
155 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface =
156 ItmUtils.getInterface(name, broker);
157 IfTunnel ifTunnel = iface.getAugmentation(IfTunnel.class);
158 ParentRefs parentRefs = iface.getAugmentation(ParentRefs.class);
159 if(ifTunnel == null && parentRefs == null) {
162 DstInfoBuilder dstInfoBuilder = new DstInfoBuilder();
163 SrcInfoBuilder srcInfoBuilder = new SrcInfoBuilder();
164 dstInfoBuilder.setTepIp(ifTunnel.getTunnelDestination());
165 srcInfoBuilder.setTepIp(ifTunnel.getTunnelSource());
166 //TODO: Add/Improve logic for device type
167 InternalTunnel internalTunnel = ItmUtils.itmCache.getInternalTunnel(name);
168 ExternalTunnel externalTunnel = ItmUtils.itmCache.getExternalTunnel(name);
169 if(internalTunnel == null && externalTunnel == null) {
170 // both not present in cache. let us update and try again.
171 ItmUtils.updateTunnelsCache(broker);
172 internalTunnel = ItmUtils.itmCache.getInternalTunnel(name);
173 externalTunnel = ItmUtils.itmCache.getExternalTunnel(name);
175 if(internalTunnel != null) {
176 srcInfoBuilder.setTepDeviceId(internalTunnel.getSourceDPN().toString()).setTepDeviceType(TepTypeInternal.class);
177 dstInfoBuilder.setTepDeviceId(internalTunnel.getDestinationDPN().toString())
178 .setTepDeviceType(TepTypeInternal.class);
179 stlBuilder.setTransportType(internalTunnel.getTransportType());
180 } else if(externalTunnel != null) {
181 ExternalTunnel tunnel = ItmUtils.itmCache.getExternalTunnel(name);
182 srcInfoBuilder.setTepDeviceId(tunnel.getSourceDevice())
183 .setTepDeviceType(getDeviceType(tunnel.getSourceDevice()));
184 dstInfoBuilder.setTepDeviceId(tunnel.getDestinationDevice())
185 .setTepDeviceType(getDeviceType(tunnel.getSourceDevice()))
186 .setTepIp(ifTunnel.getTunnelDestination());
187 stlBuilder.setTransportType(tunnel.getTransportType());
189 stlBuilder.setKey(tlKey).setTunnelInterfaceName(name).setTunnelState(state)
190 .setDstInfo(dstInfoBuilder.build()).setSrcInfo(srcInfoBuilder.build());
191 return stlBuilder.build();
194 private Class<? extends TepTypeBase> getDeviceType(String device) {
195 if(device.startsWith("hwvtep")) {
196 return TepTypeHwvtep.class;
197 } else if(InetAddresses.isInetAddress(device)) {
198 return TepTypeExternal.class;
200 return TepTypeInternal.class;
204 private InstanceIdentifier<StateTunnelList> buildStateTunnelListId(StateTunnelListKey tlKey) {
205 InstanceIdentifier<StateTunnelList> stListId =
206 InstanceIdentifier.builder(TunnelsState.class).child(StateTunnelList.class, tlKey).build();