Interfacemgr: Listener for NodeConnector events
[vpnservice.git] / interfacemgr / interfacemgr-impl / src / main / java / org / opendaylight / vpnservice / interfacemgr / InterfaceManager.java
1 /*
2  * Copyright (c) 2015 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 package org.opendaylight.vpnservice.interfacemgr;
9
10 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
11
12 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfL3tunnel;
13 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
14 import java.math.BigInteger;
15 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Counter32;
16 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Counter64;
17 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DateAndTime;
18 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state._interface.StatisticsBuilder;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state._interface.Statistics;
20 import com.google.common.util.concurrent.Futures;
21 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
22 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
23 import com.google.common.util.concurrent.FutureCallback;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.BaseIds;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
32 import org.opendaylight.vpnservice.AbstractDataChangeListener;
33 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
34 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
35 import org.opendaylight.yangtools.concepts.ListenerRegistration;
36 import org.opendaylight.yangtools.yang.binding.DataObject;
37 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
38 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
39 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
40 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
41 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
42 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
43 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47 import com.google.common.base.Optional;
48
49 public class InterfaceManager extends AbstractDataChangeListener<Interface> implements AutoCloseable{
50     private static final Logger LOG = LoggerFactory.getLogger(InterfaceManager.class);
51     private ListenerRegistration<DataChangeListener> listenerRegistration;
52     private final DataBroker broker;
53
54     private static final FutureCallback<Void> DEFAULT_CALLBACK =
55                     new FutureCallback<Void>() {
56                         public void onSuccess(Void result) {
57                             LOG.debug("Success in Datastore write operation");
58                         }
59
60                         public void onFailure(Throwable error) {
61                             LOG.error("Error in Datastore write operation", error);
62                         };
63                     };
64
65     public InterfaceManager(final DataBroker db) {
66         super(Interface.class);
67         broker = db;
68         registerListener(db);
69     }
70
71     @Override
72     public void close() throws Exception {
73         if (listenerRegistration != null) {
74             try {
75                 listenerRegistration.close();
76             } catch (final Exception e) {
77                 LOG.error("Error when cleaning up DataChangeListener.", e);
78             }
79             listenerRegistration = null;
80         }
81         LOG.info("Interface Manager Closed");
82     }
83
84     private void registerListener(final DataBroker db) {
85         try {
86             listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
87                     getWildCardPath(), InterfaceManager.this, DataChangeScope.SUBTREE);
88         } catch (final Exception e) {
89             LOG.error("InterfaceManager DataChange listener registration fail!", e);
90             throw new IllegalStateException("InterfaceManager registration Listener failed.", e);
91         }
92     }
93
94     @Override
95     protected void add(final InstanceIdentifier<Interface> identifier,
96             final Interface imgrInterface) {
97         LOG.trace("key: " + identifier + ", value=" + imgrInterface );
98         addInterface(identifier, imgrInterface);
99     }
100
101     private InstanceIdentifier<Interface> buildId(final InstanceIdentifier<Interface> identifier) {
102         //TODO Make this generic and move to AbstractDataChangeListener or Utils.
103         final InterfaceKey key = identifier.firstKeyOf(Interface.class, InterfaceKey.class);
104         String interfaceName = key.getName();
105         InstanceIdentifierBuilder<Interface> idBuilder =
106                 InstanceIdentifier.builder(Interfaces.class).child(Interface.class, new InterfaceKey(interfaceName));
107         InstanceIdentifier<Interface> id = idBuilder.build();
108         return id;
109     }
110
111     private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> buildStateInterfaceId(String interfaceName) {
112         //TODO Make this generic and move to AbstractDataChangeListener or Utils.
113         InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> idBuilder =
114                 InstanceIdentifier.builder(InterfacesState.class)
115                 .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class,
116                                 new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey(interfaceName));
117         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> id = idBuilder.build();
118         return id;
119     }
120
121     private void addInterface(final InstanceIdentifier<Interface> identifier,
122                               final Interface imgrInterface) {
123         InstanceIdentifier<Interface> id = buildId(identifier);
124         Optional<Interface> port = read(LogicalDatastoreType.CONFIGURATION, id);
125         if(port.isPresent()) {
126             Interface interf = port.get();
127             NodeConnector nodeConn = getNodeConnectorFromInterface(interf);
128             updateInterfaceState(identifier, interf, nodeConn);
129             /* TODO:
130              *  1. Get interface-id from id manager
131              *  2. Update interface-state with following:
132              *    admin-status = set to enable value
133              *    oper-status = Down [?]
134              *    if-index = interface-id
135              * FIXME:
136              *  1. Get operational data from node-connector-id?
137              *
138              */
139         }
140     }
141
142     private void updateInterfaceState(InstanceIdentifier<Interface> identifier,
143                     Interface interf, NodeConnector nodeConn) {
144         /* Update InterfaceState
145          * 1. Get interfaces-state Identifier
146          * 2. Add interface to interfaces-state/interface
147          * 3. Get interface-id from id manager
148          * 4. Update interface-state with following:
149          *    admin-status = set to enable value
150          *    oper-status = Down [?]
151          *    if-index = interface-id
152         */
153         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> id =
154                         buildStateInterfaceId(interf.getName());
155         Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> stateIf =
156                         read(LogicalDatastoreType.OPERATIONAL, id);
157         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface stateIface;
158         org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder ifaceBuilder =
159                         new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder();
160         if(!stateIf.isPresent()) {
161             // TODO: Get interface-id from IdManager
162             ifaceBuilder.setAdminStatus((interf.isEnabled()) ?  org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus.Up :
163                 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus.Down);
164             ifaceBuilder.setOperStatus(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus.Down);
165             ifaceBuilder.setIfIndex(200).setName(interf.getName()).setType(interf.getType());
166             ifaceBuilder.setKey(getStateInterfaceKeyFromName(interf.getName()));
167             //ifaceBuilder.setStatistics(createStatistics(interf.getName(), nodeConn));
168             stateIface = ifaceBuilder.build();
169             LOG.trace("Adding stateIface {} and id {} to OPERATIONAL DS", stateIface, id);
170             asyncWrite(LogicalDatastoreType.OPERATIONAL, id, stateIface, DEFAULT_CALLBACK);
171         } else {
172             if(interf.isEnabled() != null) {
173                 ifaceBuilder.setAdminStatus((interf.isEnabled()) ?  org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus.Up :
174                     org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus.Down);
175             }
176             if(interf.getType() != null) {
177                 ifaceBuilder.setType(interf.getType());
178             }
179
180             stateIface = ifaceBuilder.build();
181             LOG.trace("updating OPERATIONAL data store with stateIface {} and id {}", stateIface, id);
182             asyncUpdate(LogicalDatastoreType.OPERATIONAL, id, stateIface, DEFAULT_CALLBACK);
183         }
184     }
185
186     /*
187     private void setAugmentations(
188                     org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder ifaceBuilder,
189                     InstanceIdentifier<Interface> identifier, Interface interf) {
190         // TODO Add code for all augmentations
191         InstanceIdentifier<IfL3tunnel> ifL3TunnelPath = identifier.augmentation(IfL3tunnel.class);
192         Optional<IfL3tunnel> l3Tunnel = read(LogicalDatastoreType.CONFIGURATION, ifL3TunnelPath);
193         String ifName = interf.getName();
194         if(l3Tunnel.isPresent()) {
195             l3Tunnel.get();
196         }
197     }
198     */
199
200     private Statistics createStatistics(String name, NodeConnector nodeConn) {
201         Counter64 init64 = new Counter64(new BigInteger("0000000000000000"));
202         Counter32 init32 = new Counter32((long) 0);
203         StatisticsBuilder statBuilder = new StatisticsBuilder();
204         statBuilder.setDiscontinuityTime(new DateAndTime("2015-04-04T00:00:00Z"))
205         .setInBroadcastPkts(init64).setInDiscards(init32).setInErrors(init32).setInMulticastPkts(init64)
206         .setInOctets(init64).setInUnicastPkts(init64).setInUnknownProtos(init32).setOutBroadcastPkts(init64)
207         .setOutDiscards(init32).setOutErrors(init32).setOutMulticastPkts(init64).setOutOctets(init64)
208         .setOutUnicastPkts(init64);
209         return statBuilder.build();
210     }
211
212     private org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey getStateInterfaceKeyFromName(
213                     String name) {
214         return new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey(name);
215     }
216
217     private NodeConnector getNodeConnectorFromInterface(Interface interf) {
218         NodeConnectorId ncId = interf.getAugmentation(BaseIds.class).getOfPortId();
219         //TODO: Replace with MDSAL Util method
220         NodeId nodeId = new NodeId(ncId.getValue().substring(0,ncId.getValue().lastIndexOf(":")));
221         InstanceIdentifier<NodeConnector> ncIdentifier = InstanceIdentifier.builder(Nodes.class)
222                         .child(Node.class, new NodeKey(nodeId))
223                         .child(NodeConnector.class, new NodeConnectorKey(ncId)).build();
224
225         Optional<NodeConnector> nc = read(LogicalDatastoreType.OPERATIONAL, ncIdentifier);
226         if(nc.isPresent()) {
227             NodeConnector nodeConn = nc.get();
228             LOG.trace("nodeConnector: {}",nodeConn);
229             return nodeConn;
230         }
231         return null;
232     }
233
234     private void delInterface(final InstanceIdentifier<Interface> identifier,
235                               final Interface delInterface) {
236         InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> id =
237                         buildStateInterfaceId(delInterface.getName());
238         Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> stateIf =
239                         read(LogicalDatastoreType.OPERATIONAL, id);
240         if(!stateIf.isPresent()) {
241             LOG.trace("deleting interfaces:state OPERATIONAL data store with id {}", id);
242             asyncRemove(LogicalDatastoreType.OPERATIONAL, id, DEFAULT_CALLBACK);
243         }
244     }
245
246     private void updateInterface(final InstanceIdentifier<Interface> identifier,
247                               final Interface original, final Interface udpate) {
248         InstanceIdentifier<Interface> id = buildId(identifier);
249         Optional<Interface> port = read(LogicalDatastoreType.CONFIGURATION, id);
250         if(port.isPresent()) {
251             Interface interf = port.get();
252             //TODO: Update operational data
253         }
254     }
255
256     private <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType,
257             InstanceIdentifier<T> path) {
258
259         ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
260
261         Optional<T> result = Optional.absent();
262         try {
263             result = tx.read(datastoreType, path).get();
264         } catch (Exception e) {
265             throw new RuntimeException(e);
266         }
267
268         return result;
269     }
270
271     private InstanceIdentifier<Interface> getWildCardPath() {
272         return InstanceIdentifier.create(Interfaces.class).child(Interface.class);
273     }
274
275     @Override
276     protected void remove(InstanceIdentifier<Interface> identifier, Interface del) {
277         LOG.trace("key: " + identifier + ", value=" + del );
278         delInterface(identifier, del);
279     }
280
281     @Override
282     protected void update(InstanceIdentifier<Interface> identifier, Interface original, Interface update) {
283         LOG.trace("key: " + identifier + ", original=" + original + ", update=" + update );
284         updateInterface(identifier, original, update);
285     }
286
287     private <T extends DataObject> void asyncWrite(LogicalDatastoreType datastoreType,
288                     InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
289     WriteTransaction tx = broker.newWriteOnlyTransaction();
290     tx.put(datastoreType, path, data, true);
291     Futures.addCallback(tx.submit(), callback);
292     }
293
294     private <T extends DataObject> void asyncUpdate(LogicalDatastoreType datastoreType,
295                     InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
296     WriteTransaction tx = broker.newWriteOnlyTransaction();
297     tx.merge(datastoreType, path, data, true);
298     Futures.addCallback(tx.submit(), callback);
299     }
300
301     private <T extends DataObject> void asyncRemove(LogicalDatastoreType datastoreType,
302                     InstanceIdentifier<T> path, FutureCallback<Void> callback) {
303     WriteTransaction tx = broker.newWriteOnlyTransaction();
304     tx.delete(datastoreType, path);
305     Futures.addCallback(tx.submit(), callback);
306     }
307
308     public void processPortAdd(NodeConnector port) {
309         String strPortId = port.getId().getValue();
310         FlowCapableNodeConnector ofPort = port.getAugmentation(FlowCapableNodeConnector.class);
311         LOG.debug("PortAdd: PortId { "+strPortId+"} PortName {"+ofPort.getName()+"}");
312     }
313
314     public void processPortUpdate(NodeConnector oldPort, NodeConnector update) {
315         String oldPortId = oldPort.getId().getValue();
316         FlowCapableNodeConnector oldOfPort = oldPort.getAugmentation(FlowCapableNodeConnector.class);
317         String strPortId = update.getId().getValue();
318         FlowCapableNodeConnector ofPort = update.getAugmentation(FlowCapableNodeConnector.class);
319         LOG.debug("PortUpdate: { "+strPortId+", "+ofPort.getName()+"}");
320     }
321
322     public void processPortDelete(NodeConnector port) {
323         String strPortId = port.getId().getValue();
324         FlowCapableNodeConnector ofPort = port.getAugmentation(FlowCapableNodeConnector.class);
325         LOG.debug("PortDelete: PortId { "+strPortId+"} PortName {"+ofPort.getName()+"}");
326     }
327
328 }