ae173a7117624050f703e3ccb5a96c97422635a6
[controller.git] / opendaylight / md-sal / topology-manager / src / main / java / org / opendaylight / md / controller / topology / manager / FlowCapableTopologyExporter.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. 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.md.controller.topology.manager;
9
10 import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.getNodeConnectorKey;
11 import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.getNodeKey;
12 import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.toTerminationPoint;
13 import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.toTerminationPointId;
14 import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.toTopologyLink;
15 import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.toTopologyNode;
16 import static org.opendaylight.md.controller.topology.manager.FlowCapableNodeMapping.toTopologyNodeId;
17
18 import java.util.concurrent.Future;
19
20 import org.opendaylight.controller.md.sal.binding.util.TypeSafeDataReader;
21 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
22 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
23 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorUpdated;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdated;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.FlowTopologyDiscoveryListener;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.LinkDiscovered;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.LinkOverutilized;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.LinkRemoved;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.topology.discovery.rev130819.LinkUtilizationNormal;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRemoved;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdated;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemoved;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeUpdated;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.OpendaylightInventoryListener;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
39 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
40 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
41 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
42 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TpId;
43 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
44 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyBuilder;
45 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
46 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Link;
47 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
48 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
49 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
50 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
51 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
52 import org.opendaylight.yangtools.yang.common.RpcResult;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56 import com.google.common.util.concurrent.FutureCallback;
57 import com.google.common.util.concurrent.Futures;
58 import com.google.common.util.concurrent.JdkFutureAdapters;
59
60 class FlowCapableTopologyExporter implements FlowTopologyDiscoveryListener, OpendaylightInventoryListener {
61     protected final static Logger LOG = LoggerFactory.getLogger(FlowCapableTopologyExporter.class);
62     public static final TopologyKey TOPOLOGY = new TopologyKey(new TopologyId("flow:1"));
63
64     // FIXME: Flow capable topology exporter should use transaction chaining API
65     private DataProviderService dataService;
66
67     public DataProviderService getDataService() {
68         return dataService;
69     }
70
71     public void setDataService(final DataProviderService dataService) {
72         this.dataService = dataService;
73     }
74
75     private InstanceIdentifier<Topology> topologyPath;
76
77     public void start() {
78         TopologyBuilder tb = new TopologyBuilder();
79         tb.setKey(TOPOLOGY);
80         topologyPath = InstanceIdentifier.builder(NetworkTopology.class).child(Topology.class, TOPOLOGY).build();
81         Topology top = tb.build();
82         DataModificationTransaction tx = dataService.beginTransaction();
83         tx.putOperationalData(topologyPath, top);
84         listenOnTransactionState(tx.getIdentifier(),tx.commit());
85     }
86
87     @Override
88     public void onNodeRemoved(final NodeRemoved notification) {
89         NodeId nodeId = toTopologyNodeId(getNodeKey(notification.getNodeRef()).getId());
90         InstanceIdentifier<Node> nodeInstance = toNodeIdentifier(notification.getNodeRef());
91
92         synchronized (this) {
93             DataModificationTransaction tx = dataService.beginTransaction();
94             tx.removeOperationalData(nodeInstance);
95             removeAffectedLinks(tx, nodeId);
96             listenOnTransactionState(tx.getIdentifier(),tx.commit());
97         }
98     }
99
100     @Override
101     public void onNodeUpdated(final NodeUpdated notification) {
102         FlowCapableNodeUpdated fcnu = notification.getAugmentation(FlowCapableNodeUpdated.class);
103         if (fcnu != null) {
104             Node node = toTopologyNode(toTopologyNodeId(notification.getId()), notification.getNodeRef());
105             InstanceIdentifier<Node> path = getNodePath(toTopologyNodeId(notification.getId()));
106
107             synchronized (this) {
108                 DataModificationTransaction tx = dataService.beginTransaction();
109                 tx.putOperationalData(path, node);
110                 listenOnTransactionState(tx.getIdentifier(),tx.commit());
111             }
112         }
113     }
114
115     @Override
116     public void onNodeConnectorRemoved(final NodeConnectorRemoved notification) {
117         InstanceIdentifier<TerminationPoint> tpInstance = toTerminationPointIdentifier(notification
118                 .getNodeConnectorRef());
119         TpId tpId = toTerminationPointId(getNodeConnectorKey(notification.getNodeConnectorRef()).getId());
120
121         synchronized (this) {
122             DataModificationTransaction tx = dataService.beginTransaction();
123             tx.removeOperationalData(tpInstance);
124             removeAffectedLinks(tx, tpId);
125             listenOnTransactionState(tx.getIdentifier(),tx.commit());
126         }
127     }
128
129     @Override
130     public void onNodeConnectorUpdated(final NodeConnectorUpdated notification) {
131         FlowCapableNodeConnectorUpdated fcncu = notification.getAugmentation(FlowCapableNodeConnectorUpdated.class);
132         if (fcncu != null) {
133             NodeId nodeId = toTopologyNodeId(getNodeKey(notification.getNodeConnectorRef()).getId());
134             TerminationPoint point = toTerminationPoint(toTerminationPointId(notification.getId()),
135                     notification.getNodeConnectorRef());
136             InstanceIdentifier<TerminationPoint> path = tpPath(nodeId, point.getKey().getTpId());
137
138             synchronized (this) {
139                 DataModificationTransaction tx = dataService.beginTransaction();
140                 tx.putOperationalData(path, point);
141                 if ((fcncu.getState() != null && fcncu.getState().isLinkDown())
142                         || (fcncu.getConfiguration() != null && fcncu.getConfiguration().isPORTDOWN())) {
143                     removeAffectedLinks(tx, point.getTpId());
144                 }
145                 listenOnTransactionState(tx.getIdentifier(),tx.commit());
146             }
147         }
148     }
149
150     @Override
151     public void onLinkDiscovered(final LinkDiscovered notification) {
152         Link link = toTopologyLink(notification);
153         InstanceIdentifier<Link> path = linkPath(link);
154
155         synchronized (this) {
156             DataModificationTransaction tx = dataService.beginTransaction();
157             tx.putOperationalData(path, link);
158             listenOnTransactionState(tx.getIdentifier(),tx.commit());
159         }
160     }
161
162     @Override
163     public void onLinkOverutilized(final LinkOverutilized notification) {
164         // NOOP
165     }
166
167     @Override
168     public void onLinkRemoved(final LinkRemoved notification) {
169         InstanceIdentifier<Link> path = linkPath(toTopologyLink(notification));
170
171         synchronized (this) {
172             DataModificationTransaction tx = dataService.beginTransaction();
173             tx.removeOperationalData(path);
174             listenOnTransactionState(tx.getIdentifier(),tx.commit());
175         }
176     }
177
178     @Override
179     public void onLinkUtilizationNormal(final LinkUtilizationNormal notification) {
180         // NOOP
181     }
182
183     private static InstanceIdentifier<Node> toNodeIdentifier(final NodeRef ref) {
184         org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey invNodeKey = getNodeKey(ref);
185
186         NodeKey nodeKey = new NodeKey(toTopologyNodeId(invNodeKey.getId()));
187         return InstanceIdentifier.builder(NetworkTopology.class).child(Topology.class, TOPOLOGY)
188                 .child(Node.class, nodeKey).build();
189     }
190
191     private static InstanceIdentifier<TerminationPoint> toTerminationPointIdentifier(final NodeConnectorRef ref) {
192         org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey invNodeKey = getNodeKey(ref);
193         NodeConnectorKey invNodeConnectorKey = getNodeConnectorKey(ref);
194         return tpPath(toTopologyNodeId(invNodeKey.getId()), toTerminationPointId(invNodeConnectorKey.getId()));
195     }
196
197     private void removeAffectedLinks(final DataModificationTransaction transaction, final NodeId id) {
198         TypeSafeDataReader reader = TypeSafeDataReader.forReader(transaction);
199
200         Topology topologyData = reader.readOperationalData(topologyPath);
201         if (topologyData == null) {
202             return;
203         }
204         for (Link link : topologyData.getLink()) {
205             if (id.equals(link.getSource().getSourceNode()) || id.equals(link.getDestination().getDestNode())) {
206                 InstanceIdentifier<Link> path = topologyPath.child(Link.class, link.getKey());
207                 transaction.removeOperationalData(path);
208             }
209         }
210     }
211
212     private void removeAffectedLinks(final DataModificationTransaction transaction, final TpId id) {
213         TypeSafeDataReader reader = TypeSafeDataReader.forReader(transaction);
214         Topology topologyData = reader.readOperationalData(topologyPath);
215         if (topologyData == null) {
216             return;
217         }
218         for (Link link : topologyData.getLink()) {
219             if (id.equals(link.getSource().getSourceTp()) || id.equals(link.getDestination().getDestTp())) {
220                 InstanceIdentifier<Link> path = topologyPath.child(Link.class, link.getKey());
221                 transaction.removeOperationalData(path);
222             }
223         }
224     }
225
226     private static InstanceIdentifier<Node> getNodePath(final NodeId nodeId) {
227         NodeKey nodeKey = new NodeKey(nodeId);
228         return InstanceIdentifier.builder(NetworkTopology.class).child(Topology.class, TOPOLOGY)
229                 .child(Node.class, nodeKey).build();
230     }
231
232     private static InstanceIdentifier<TerminationPoint> tpPath(final NodeId nodeId, final TpId tpId) {
233         NodeKey nodeKey = new NodeKey(nodeId);
234         TerminationPointKey tpKey = new TerminationPointKey(tpId);
235         return InstanceIdentifier.builder(NetworkTopology.class).child(Topology.class, TOPOLOGY)
236                 .child(Node.class, nodeKey).child(TerminationPoint.class, tpKey).build();
237     }
238
239     private static InstanceIdentifier<Link> linkPath(final Link link) {
240         InstanceIdentifier<Link> linkInstanceId = InstanceIdentifier.builder(NetworkTopology.class)
241                 .child(Topology.class, TOPOLOGY).child(Link.class, link.getKey()).build();
242         return linkInstanceId;
243     }
244
245     /**
246      * @param txId transaction identificator
247      * @param future transaction result
248      */
249     private static void listenOnTransactionState(final Object txId, final Future<RpcResult<TransactionStatus>> future) {
250         Futures.addCallback(JdkFutureAdapters.listenInPoolThread(future),new FutureCallback<RpcResult<TransactionStatus>>() {
251             @Override
252             public void onFailure(final Throwable t) {
253                 LOG.error("Topology export failed for Tx:{}", txId, t);
254             }
255
256             @Override
257             public void onSuccess(final RpcResult<TransactionStatus> result) {
258                 if(!result.isSuccessful()) {
259                     LOG.error("Topology export failed for Tx:{}", txId);
260                 }
261             }
262         });
263     }
264 }