e23568010f7185b30272528426acad2da44cd899
[genius.git] / itm / itm-impl / src / main / java / org / opendaylight / genius / itm / listeners / InterfaceStateListener.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.genius.itm.listeners;
10
11 import com.google.common.base.Optional;
12 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
13 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
14 import org.opendaylight.genius.itm.impl.ItmUtils;
15 import org.opendaylight.genius.datastoreutils.AsyncDataTreeChangeListenerBase;
16 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
17 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
18 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.IfTunnel;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rev160406.ParentRefs;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeBase;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeExternal;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeHwvtep;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TepTypeInternal;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.TunnelsState;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.external.tunnel.list.ExternalTunnel;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnel.list.InternalTunnel;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelList;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelListBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.StateTunnelListKey;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.state.tunnel.list.DstInfoBuilder;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.tunnels_state.state.tunnel.list.SrcInfoBuilder;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.itm.op.rev160406.*;
34 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 public class InterfaceStateListener extends AsyncDataTreeChangeListenerBase<Interface, InterfaceStateListener> implements AutoCloseable {
39     private static final Logger LOG = LoggerFactory.getLogger(InterfaceStateListener.class);
40
41     private final DataBroker broker;
42
43     public InterfaceStateListener(final DataBroker db) {
44         super(Interface.class, InterfaceStateListener.class);
45         broker = db;
46         registerListener(broker);
47     }
48
49     @Override
50     public void close() throws Exception {
51         
52         LOG.info("Interface state listener Closed");
53     }
54
55     private void registerListener(final DataBroker db) {
56         try {
57             registerListener(LogicalDatastoreType.OPERATIONAL,db);
58         } catch (final Exception e) {
59             LOG.error("ITM Interfaces State listener registration fail!", e);
60             throw new IllegalStateException("ITM Interfaces State listener registration failed.", e);
61         }
62     }
63
64     @Override
65     protected InstanceIdentifier<Interface> getWildCardPath() {
66         return InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
67     }
68
69     @Override
70     protected InterfaceStateListener getDataTreeChangeListener() {
71         return this;
72     }
73
74     @Override
75     protected void add(InstanceIdentifier<Interface> identifier, Interface iface) {
76         LOG.trace("Interface added: {}", iface);
77         if (ItmUtils.isItmIfType(iface.getType())) {
78             LOG.debug("Interface of type Tunnel added: {}", iface.getName());
79             updateItmState(iface);
80         }
81     }
82
83     @Override
84     protected void remove(InstanceIdentifier<Interface> identifier, Interface iface) {
85         LOG.trace("Interface deleted: {}", iface);
86         if (ItmUtils.isItmIfType(iface.getType())) {
87             LOG.debug("Tunnel interface deleted: {}", iface.getName());
88             StateTunnelListKey tlKey = ItmUtils.getTunnelStateKey(iface);
89             InstanceIdentifier<StateTunnelList> stListId = buildStateTunnelListId(tlKey);
90             LOG.trace("Deleting tunnel_state for Id: {}", stListId);
91             ItmUtils.asyncDelete(LogicalDatastoreType.OPERATIONAL, stListId, broker, ItmUtils.DEFAULT_CALLBACK);
92         }
93     }
94
95     @Override
96     protected void update(InstanceIdentifier<Interface> identifier, Interface original, Interface update) {
97         /*
98          * update contains only delta, may not include iftype Note: This assumes
99          * type can't be edited on the fly
100          */
101         if (ItmUtils.isItmIfType(original.getType())) {
102             LOG.trace("Interface updated. Old: {} New: {}", original, update);
103             OperStatus operStatus = update.getOperStatus();
104             if (operStatus != null) {
105                 LOG.debug("Tunnel Interface {} changed state to {}", original.getName(), operStatus);
106                 updateItmState(update);
107             }
108         }
109     }
110
111     private void updateItmState(Interface iface) {
112         StateTunnelListKey tlKey = ItmUtils.getTunnelStateKey(iface);
113         LOG.trace("TunnelStateKey: {} for interface: {}", tlKey, iface.getName());
114         InstanceIdentifier<StateTunnelList> stListId = buildStateTunnelListId(tlKey);
115         Optional<StateTunnelList> tunnelsState = ItmUtils.read(LogicalDatastoreType.OPERATIONAL, stListId, broker);
116         StateTunnelList tunnelStateList;
117         StateTunnelListBuilder stlBuilder;
118         TunnelOperStatus tunnelOperStatus;
119         boolean tunnelState = iface.getOperStatus().equals(OperStatus.Up);
120         switch (iface.getOperStatus()) {
121             case Up:
122                 tunnelOperStatus = TunnelOperStatus.Up;
123                 break;
124             case Down:
125                 tunnelOperStatus = TunnelOperStatus.Down;
126                 break;
127             case Unknown:
128                 tunnelOperStatus = TunnelOperStatus.Unknown;
129                 break;
130             default:
131                 tunnelOperStatus = TunnelOperStatus.Ignore;
132         }
133         if(tunnelsState.isPresent()) {
134             tunnelStateList = tunnelsState.get();
135             stlBuilder = new StateTunnelListBuilder(tunnelStateList);
136             stlBuilder.setTunnelState(tunnelState);
137             stlBuilder.setOperState(tunnelOperStatus);
138             StateTunnelList stList = stlBuilder.build();
139             LOG.trace("Updating tunnel_state: {} for Id: {}", stList, stListId);
140             ItmUtils.asyncUpdate(LogicalDatastoreType.OPERATIONAL, stListId, stList, broker, ItmUtils.DEFAULT_CALLBACK);
141         } else {
142             // Create new Tunnel State
143             try {
144                 /*
145                  * FIXME: A defensive try-catch to find issues without
146                  * disrupting existing behavior.
147                  */
148                 tunnelStateList = buildStateTunnelList(tlKey, iface.getName(), tunnelState, tunnelOperStatus);
149                 LOG.trace("Creating tunnel_state: {} for Id: {}", tunnelStateList, stListId);
150                 ItmUtils.asyncUpdate(LogicalDatastoreType.OPERATIONAL, stListId, tunnelStateList, broker,
151                         ItmUtils.DEFAULT_CALLBACK);
152             } catch (Exception e) {
153                 LOG.warn("Exception trying to create tunnel state for {}", iface.getName(), e);
154             }
155         }
156     }
157
158
159     private StateTunnelList buildStateTunnelList(StateTunnelListKey tlKey, String name, boolean state, TunnelOperStatus tunOpStatus) {
160         StateTunnelListBuilder stlBuilder = new StateTunnelListBuilder();
161         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface iface = ItmUtils
162                 .getInterface(name, broker);
163         IfTunnel ifTunnel = iface.getAugmentation(IfTunnel.class);
164         ParentRefs parentRefs = iface.getAugmentation(ParentRefs.class);
165         if (ifTunnel == null && parentRefs == null) {
166             return null;
167         }
168         DstInfoBuilder dstInfoBuilder = new DstInfoBuilder();
169         SrcInfoBuilder srcInfoBuilder = new SrcInfoBuilder();
170         dstInfoBuilder.setTepIp(ifTunnel.getTunnelDestination());
171         srcInfoBuilder.setTepIp(ifTunnel.getTunnelSource());
172         // TODO: Add/Improve logic for device type
173         InternalTunnel internalTunnel = ItmUtils.itmCache.getInternalTunnel(name);
174         ExternalTunnel externalTunnel = ItmUtils.itmCache.getExternalTunnel(name);
175         if (internalTunnel == null && externalTunnel == null) {
176             // both not present in cache. let us update and try again.
177             ItmUtils.updateTunnelsCache(broker);
178             internalTunnel = ItmUtils.itmCache.getInternalTunnel(name);
179             externalTunnel = ItmUtils.itmCache.getExternalTunnel(name);
180         }
181         if (internalTunnel != null) {
182             srcInfoBuilder.setTepDeviceId(internalTunnel.getSourceDPN().toString())
183                     .setTepDeviceType(TepTypeInternal.class);
184             dstInfoBuilder.setTepDeviceId(internalTunnel.getDestinationDPN().toString())
185                     .setTepDeviceType(TepTypeInternal.class);
186             stlBuilder.setTransportType(internalTunnel.getTransportType());
187         } else if (externalTunnel != null) {
188             ExternalTunnel tunnel = ItmUtils.itmCache.getExternalTunnel(name);
189             srcInfoBuilder.setTepDeviceId(tunnel.getSourceDevice())
190                     .setTepDeviceType(getDeviceType(tunnel.getSourceDevice()));
191             dstInfoBuilder.setTepDeviceId(tunnel.getDestinationDevice())
192                     .setTepDeviceType(getDeviceType(tunnel.getDestinationDevice()))
193                     .setTepIp(ifTunnel.getTunnelDestination());
194             stlBuilder.setTransportType(tunnel.getTransportType());
195         }
196         stlBuilder.setKey(tlKey).setTunnelInterfaceName(name).setOperState(tunOpStatus).setTunnelState(state)
197             .setDstInfo(dstInfoBuilder.build()).setSrcInfo(srcInfoBuilder.build());
198         return stlBuilder.build();
199     }
200
201     private Class<? extends TepTypeBase> getDeviceType(String device) {
202         if (device.startsWith("hwvtep")) {
203             return TepTypeHwvtep.class;
204         } else if (device.contains("IpAddress")) {
205             return TepTypeExternal.class;
206         } else {
207             return TepTypeInternal.class;
208         }
209     }
210
211     private InstanceIdentifier<StateTunnelList> buildStateTunnelListId(StateTunnelListKey tlKey) {
212         return InstanceIdentifier.builder(TunnelsState.class)
213                 .child(StateTunnelList.class, tlKey).build();
214     }
215 }