2 * Copyright (c) 2015 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
8 package org.opendaylight.vpnservice.interfacemgr;
11 import java.util.concurrent.ConcurrentHashMap;
12 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.OperStatus;
13 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
14 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.IfL3tunnel;
15 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceBuilder;
16 import java.math.BigInteger;
17 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Counter32;
18 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Counter64;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DateAndTime;
20 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state._interface.StatisticsBuilder;
21 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state._interface.Statistics;
22 import com.google.common.util.concurrent.Futures;
23 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
24 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
25 import com.google.common.util.concurrent.FutureCallback;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.vpnservice.interfacemgr.rev150331.BaseIds;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
34 import org.opendaylight.vpnservice.AbstractDataChangeListener;
35 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
36 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
37 import org.opendaylight.yangtools.concepts.ListenerRegistration;
38 import org.opendaylight.yangtools.yang.binding.DataObject;
39 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
40 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
41 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
42 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
43 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
44 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.Interfaces;
45 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.Interface;
46 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.InterfaceKey;
47 import org.slf4j.Logger;
48 import org.slf4j.LoggerFactory;
49 import com.google.common.base.Optional;
51 public class InterfaceManager extends AbstractDataChangeListener<Interface> implements AutoCloseable{
52 private static final Logger LOG = LoggerFactory.getLogger(InterfaceManager.class);
53 private ListenerRegistration<DataChangeListener> listenerRegistration;
54 private final DataBroker broker;
55 private final Map<NodeConnectorId, String> mapNcToInterfaceName = new ConcurrentHashMap<>();
57 private static final FutureCallback<Void> DEFAULT_CALLBACK =
58 new FutureCallback<Void>() {
59 public void onSuccess(Void result) {
60 LOG.debug("Success in Datastore write operation");
63 public void onFailure(Throwable error) {
64 LOG.error("Error in Datastore write operation", error);
68 public InterfaceManager(final DataBroker db) {
69 super(Interface.class);
75 public void close() throws Exception {
76 if (listenerRegistration != null) {
78 listenerRegistration.close();
79 } catch (final Exception e) {
80 LOG.error("Error when cleaning up DataChangeListener.", e);
82 listenerRegistration = null;
84 LOG.info("Interface Manager Closed");
87 private void registerListener(final DataBroker db) {
89 listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
90 getWildCardPath(), InterfaceManager.this, DataChangeScope.SUBTREE);
91 } catch (final Exception e) {
92 LOG.error("InterfaceManager DataChange listener registration fail!", e);
93 throw new IllegalStateException("InterfaceManager registration Listener failed.", e);
98 protected void add(final InstanceIdentifier<Interface> identifier,
99 final Interface imgrInterface) {
100 LOG.trace("key: " + identifier + ", value=" + imgrInterface );
101 addInterface(identifier, imgrInterface);
104 private InstanceIdentifier<Interface> buildId(final InstanceIdentifier<Interface> identifier) {
105 //TODO Make this generic and move to AbstractDataChangeListener or Utils.
106 final InterfaceKey key = identifier.firstKeyOf(Interface.class, InterfaceKey.class);
107 return buildId(key.getName());
110 private InstanceIdentifier<Interface> buildId(String interfaceName) {
111 //TODO Make this generic and move to AbstractDataChangeListener or Utils.
112 InstanceIdentifierBuilder<Interface> idBuilder =
113 InstanceIdentifier.builder(Interfaces.class).child(Interface.class, new InterfaceKey(interfaceName));
114 InstanceIdentifier<Interface> id = idBuilder.build();
118 private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> buildStateInterfaceId(String interfaceName) {
119 //TODO Make this generic and move to AbstractDataChangeListener or Utils.
120 InstanceIdentifierBuilder<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> idBuilder =
121 InstanceIdentifier.builder(InterfacesState.class)
122 .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.class,
123 new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey(interfaceName));
124 InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> id = idBuilder.build();
128 private void addInterface(final InstanceIdentifier<Interface> identifier,
129 final Interface imgrInterface) {
130 InstanceIdentifier<Interface> id = buildId(identifier);
131 Optional<Interface> port = read(LogicalDatastoreType.CONFIGURATION, id);
132 if(port.isPresent()) {
133 Interface interf = port.get();
134 NodeConnector nodeConn = getNodeConnectorFromDataStore(interf);
135 updateInterfaceState(identifier, interf, nodeConn);
136 if(nodeConn == null) {
137 mapNcToInterfaceName.put(this.getNodeConnectorIdFromInterface(interf) , interf.getName());
139 mapNcToInterfaceName.put(nodeConn.getId(), interf.getName());
142 * 1. Get interface-id from id manager
143 * 2. Update interface-state with following:
144 * admin-status = set to enable value
145 * oper-status = Down [?]
146 * if-index = interface-id
148 * 1. Get operational data from node-connector-id?
154 private void updateInterfaceState(InstanceIdentifier<Interface> identifier,
155 Interface interf, NodeConnector nodeConn) {
156 /* Update InterfaceState
157 * 1. Get interfaces-state Identifier
158 * 2. Add interface to interfaces-state/interface
159 * 3. Get interface-id from id manager
160 * 4. Update interface-state with following:
161 * admin-status = set to enable value
162 * oper-status = Down [?]
163 * if-index = interface-id
165 InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> id =
166 buildStateInterfaceId(interf.getName());
167 Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> stateIf =
168 read(LogicalDatastoreType.OPERATIONAL, id);
169 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface stateIface;
170 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder ifaceBuilder =
171 new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder();
172 if(!stateIf.isPresent()) {
173 // TODO: Get interface-id from IdManager
174 ifaceBuilder.setAdminStatus((interf.isEnabled()) ? org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus.Up :
175 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus.Down);
176 ifaceBuilder.setOperStatus(getOperStatus(nodeConn));
178 ifaceBuilder.setIfIndex(200).setName(interf.getName()).setType(interf.getType());
179 ifaceBuilder.setKey(getStateInterfaceKeyFromName(interf.getName()));
180 //ifaceBuilder.setStatistics(createStatistics(interf.getName(), nodeConn));
181 stateIface = ifaceBuilder.build();
182 LOG.trace("Adding stateIface {} and id {} to OPERATIONAL DS", stateIface, id);
183 asyncWrite(LogicalDatastoreType.OPERATIONAL, id, stateIface, DEFAULT_CALLBACK);
185 if(interf.isEnabled() != null) {
186 ifaceBuilder.setAdminStatus((interf.isEnabled()) ? org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus.Up :
187 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface.AdminStatus.Down);
189 if(interf.getType() != null) {
190 ifaceBuilder.setType(interf.getType());
192 ifaceBuilder.setOperStatus(getOperStatus(nodeConn));
193 stateIface = ifaceBuilder.build();
194 LOG.trace("updating OPERATIONAL data store with stateIface {} and id {}", stateIface, id);
195 asyncUpdate(LogicalDatastoreType.OPERATIONAL, id, stateIface, DEFAULT_CALLBACK);
200 private void setAugmentations(
201 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder ifaceBuilder,
202 InstanceIdentifier<Interface> identifier, Interface interf) {
203 // TODO Add code for all augmentations
204 InstanceIdentifier<IfL3tunnel> ifL3TunnelPath = identifier.augmentation(IfL3tunnel.class);
205 Optional<IfL3tunnel> l3Tunnel = read(LogicalDatastoreType.CONFIGURATION, ifL3TunnelPath);
206 String ifName = interf.getName();
207 if(l3Tunnel.isPresent()) {
213 private OperStatus getOperStatus(NodeConnector nodeConn) {
214 LOG.trace("nodeConn is {}", nodeConn);
215 if(nodeConn == null) {
216 return OperStatus.Down;
218 return OperStatus.Up;
222 private Statistics createStatistics(String name, NodeConnector nodeConn) {
223 Counter64 init64 = new Counter64(new BigInteger("0000000000000000"));
224 Counter32 init32 = new Counter32((long) 0);
225 StatisticsBuilder statBuilder = new StatisticsBuilder();
226 statBuilder.setDiscontinuityTime(new DateAndTime("2015-04-04T00:00:00Z"))
227 .setInBroadcastPkts(init64).setInDiscards(init32).setInErrors(init32).setInMulticastPkts(init64)
228 .setInOctets(init64).setInUnicastPkts(init64).setInUnknownProtos(init32).setOutBroadcastPkts(init64)
229 .setOutDiscards(init32).setOutErrors(init32).setOutMulticastPkts(init64).setOutOctets(init64)
230 .setOutUnicastPkts(init64);
231 return statBuilder.build();
234 private org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey getStateInterfaceKeyFromName(
236 return new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceKey(name);
239 private NodeConnector getNodeConnectorFromDataStore(Interface interf) {
240 NodeConnectorId ncId = interf.getAugmentation(BaseIds.class).getOfPortId();
241 //TODO: Replace with MDSAL Util method
242 NodeId nodeId = new NodeId(ncId.getValue().substring(0,ncId.getValue().lastIndexOf(":")));
243 InstanceIdentifier<NodeConnector> ncIdentifier = InstanceIdentifier.builder(Nodes.class)
244 .child(Node.class, new NodeKey(nodeId))
245 .child(NodeConnector.class, new NodeConnectorKey(ncId)).build();
247 Optional<NodeConnector> nc = read(LogicalDatastoreType.OPERATIONAL, ncIdentifier);
249 NodeConnector nodeConn = nc.get();
250 LOG.trace("nodeConnector: {}",nodeConn);
256 private NodeConnectorId getNodeConnectorIdFromInterface(Interface interf) {
257 return interf.getAugmentation(BaseIds.class).getOfPortId();
260 private void delInterface(final InstanceIdentifier<Interface> identifier,
261 final Interface delInterface) {
262 InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> id =
263 buildStateInterfaceId(delInterface.getName());
264 Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> stateIf =
265 read(LogicalDatastoreType.OPERATIONAL, id);
266 if(stateIf.isPresent()) {
267 LOG.trace("deleting interfaces:state OPERATIONAL data store with id {}", id);
268 asyncRemove(LogicalDatastoreType.OPERATIONAL, id, DEFAULT_CALLBACK);
269 NodeConnectorId ncId = getNodeConnectorIdFromInterface(delInterface);
271 mapNcToInterfaceName.remove(ncId);
276 private void updateInterface(final InstanceIdentifier<Interface> identifier,
277 final Interface original, final Interface update) {
278 InstanceIdentifier<Interface> id = buildId(identifier);
279 Optional<Interface> port = read(LogicalDatastoreType.CONFIGURATION, id);
280 if(port.isPresent()) {
281 Interface interf = port.get();
282 NodeConnector nc = getNodeConnectorFromDataStore(update);
283 updateInterfaceState(identifier, update, nc);
285 * Alternative is to get from interf and update map irrespective if NCID changed or not.
288 // Name doesn't change. Is it present in update?
289 mapNcToInterfaceName.put(nc.getId(), original.getName());
291 //TODO: Update operational data
295 private <T extends DataObject> Optional<T> read(LogicalDatastoreType datastoreType,
296 InstanceIdentifier<T> path) {
298 ReadOnlyTransaction tx = broker.newReadOnlyTransaction();
300 Optional<T> result = Optional.absent();
302 result = tx.read(datastoreType, path).get();
303 } catch (Exception e) {
304 throw new RuntimeException(e);
310 private InstanceIdentifier<Interface> getWildCardPath() {
311 return InstanceIdentifier.create(Interfaces.class).child(Interface.class);
315 protected void remove(InstanceIdentifier<Interface> identifier, Interface del) {
316 LOG.trace("remove - key: " + identifier + ", value=" + del );
317 delInterface(identifier, del);
321 protected void update(InstanceIdentifier<Interface> identifier, Interface original, Interface update) {
322 LOG.trace("update - key: " + identifier + ", original=" + original + ", update=" + update );
323 updateInterface(identifier, original, update);
326 private <T extends DataObject> void asyncWrite(LogicalDatastoreType datastoreType,
327 InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
328 WriteTransaction tx = broker.newWriteOnlyTransaction();
329 tx.put(datastoreType, path, data, true);
330 Futures.addCallback(tx.submit(), callback);
333 private <T extends DataObject> void asyncUpdate(LogicalDatastoreType datastoreType,
334 InstanceIdentifier<T> path, T data, FutureCallback<Void> callback) {
335 WriteTransaction tx = broker.newWriteOnlyTransaction();
336 tx.merge(datastoreType, path, data, true);
337 Futures.addCallback(tx.submit(), callback);
340 private <T extends DataObject> void asyncRemove(LogicalDatastoreType datastoreType,
341 InstanceIdentifier<T> path, FutureCallback<Void> callback) {
342 WriteTransaction tx = broker.newWriteOnlyTransaction();
343 tx.delete(datastoreType, path);
344 Futures.addCallback(tx.submit(), callback);
347 void processPortAdd(NodeConnector port) {
348 NodeConnectorId portId = port.getId();
349 FlowCapableNodeConnector ofPort = port.getAugmentation(FlowCapableNodeConnector.class);
350 LOG.debug("PortAdd: PortId { "+portId.getValue()+"} PortName {"+ofPort.getName()+"}");
351 String ifName = this.mapNcToInterfaceName.get(portId);
352 setInterfaceOperStatus(ifName, OperStatus.Up);
355 void processPortUpdate(NodeConnector oldPort, NodeConnector update) {
356 //TODO: Currently nothing to do here.
357 //LOG.trace("map: {}", this.mapNcToInterfaceName);
360 void processPortDelete(NodeConnector port) {
361 NodeConnectorId portId = port.getId();
362 FlowCapableNodeConnector ofPort = port.getAugmentation(FlowCapableNodeConnector.class);
363 LOG.debug("PortDelete: PortId { "+portId.getValue()+"} PortName {"+ofPort.getName()+"}");
364 String ifName = this.mapNcToInterfaceName.get(portId);
365 setInterfaceOperStatus(ifName, OperStatus.Down);
368 private void setInterfaceOperStatus(String ifName, OperStatus opStatus) {
369 if (ifName != null) {
370 InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> id =
371 buildStateInterfaceId(ifName);
372 Optional<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface> stateIf =
373 read(LogicalDatastoreType.OPERATIONAL, id);
374 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface stateIface;
375 org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder ifaceBuilder =
376 new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.InterfaceBuilder();
377 if (stateIf.isPresent()) {
378 stateIface = ifaceBuilder.setOperStatus(opStatus).build();
379 LOG.trace("Setting OperStatus for {} to {} in OPERATIONAL DS", ifName, opStatus);
380 asyncUpdate(LogicalDatastoreType.OPERATIONAL, id, stateIface, DEFAULT_CALLBACK);