Vxlan/Gre co-existence,Alarms,tunnelstate,TR fixes
[vpnservice.git] / itm / itm-impl / src / main / java / org / opendaylight / vpnservice / 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.vpnservice.itm.listeners;
10
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;
38
39 import com.google.common.base.Optional;
40 import com.google.common.net.InetAddresses;
41
42 public class InterfaceStateListener extends AbstractDataChangeListener<Interface> implements AutoCloseable {
43     private static final Logger LOG = LoggerFactory.getLogger(InterfaceStateListener.class);
44
45     private ListenerRegistration<DataChangeListener> listenerRegistration;
46     private final DataBroker broker;
47
48     public InterfaceStateListener(final DataBroker db) {
49         super(Interface.class);
50         broker = db;
51         registerListener(db);
52     }
53
54     @Override
55     public void close() throws Exception {
56         if (listenerRegistration != null) {
57             try {
58                 listenerRegistration.close();
59             } catch (final Exception e) {
60                 LOG.error("Error when cleaning up interface state listener", e);
61             }
62             listenerRegistration = null;
63         }
64         LOG.info("Interface state listener Closed");
65     }
66
67     private void registerListener(final DataBroker db) {
68         try {
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);
74         }
75     }
76
77     private InstanceIdentifier<Interface> getWildCardPath() {
78         return InstanceIdentifier.create(InterfacesState.class).child(Interface.class);
79     }
80
81     @Override
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);
87         }
88     }
89
90     @Override
91     protected void remove(InstanceIdentifier<Interface> identifier,
92             Interface iface) {
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);
101         }
102     }
103
104     @Override
105     protected void update(InstanceIdentifier<Interface> identifier,
106             Interface original, Interface update) {
107         /*
108          * update contains only delta, may not include iftype
109          * Note: This assumes type can't be edited on the fly
110          */
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);
117             }
118         }
119     }
120
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);
137         } else {
138             // Create new Tunnel State
139             try {
140                 /*FIXME:
141                  * A defensive try-catch to find issues without disrupting existing behavior.
142                  */
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);
149             }
150         }
151     }
152
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) {
160             return null;
161         }
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);
174         }
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());
188         }
189         stlBuilder.setKey(tlKey).setTunnelInterfaceName(name).setTunnelState(state)
190             .setDstInfo(dstInfoBuilder.build()).setSrcInfo(srcInfoBuilder.build());
191         return stlBuilder.build();
192     }
193
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;
199         } else {
200             return TepTypeInternal.class;
201         }
202     }
203
204     private InstanceIdentifier<StateTunnelList> buildStateTunnelListId(StateTunnelListKey tlKey) {
205         InstanceIdentifier<StateTunnelList> stListId =
206                         InstanceIdentifier.builder(TunnelsState.class).child(StateTunnelList.class, tlKey).build();
207         return stListId;
208     }
209
210 }