d826db01221387a6d4e84962b6d22040ee99593a
[vtn.git] /
1 /*
2  * Copyright (c) 2015 NEC Corporation
3  * All rights reserved.
4  *
5  * This program and the accompanying materials are made available under the
6  * terms of the Eclipse Public License v1.0 which accompanies this
7  * distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
8  */
9
10 package org.opendaylight.vtn.manager.internal.inventory;
11
12 import java.util.List;
13
14 import com.google.common.base.Optional;
15 import com.google.common.util.concurrent.CheckedFuture;
16
17 import org.slf4j.Logger;
18
19 import org.opendaylight.vtn.manager.VTNException;
20
21 import org.opendaylight.vtn.manager.internal.TxContext;
22 import org.opendaylight.vtn.manager.internal.TxQueue;
23 import org.opendaylight.vtn.manager.internal.TxTask;
24 import org.opendaylight.vtn.manager.internal.util.DataStoreListener;
25 import org.opendaylight.vtn.manager.internal.util.DataStoreUtils;
26 import org.opendaylight.vtn.manager.internal.util.inventory.InventoryReader;
27 import org.opendaylight.vtn.manager.internal.util.inventory.InventoryUtils;
28 import org.opendaylight.vtn.manager.internal.util.inventory.SalNode;
29 import org.opendaylight.vtn.manager.internal.util.inventory.SalPort;
30
31 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
32 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
33 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
34 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
35 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
36
37 import org.opendaylight.yangtools.yang.binding.DataObject;
38 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
39
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.node.info.VtnPort;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.port.info.PortLink;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.IgnoredLinks;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.VtnTopology;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.ignored.links.IgnoredLink;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.topology.rev150209.vtn.topology.VtnLink;
46
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
48
49 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.LinkId;
50
51 /**
52  * Base class for MD-SAL data change listeners that maintain the VTN inventory
53  * data.
54  *
55  * @param <T>  Type of data object in the MD-SAL datastore to listen.
56  * @param <C>  Type of event context.
57  */
58 public abstract class InventoryMaintainer<T extends DataObject, C>
59     extends DataStoreListener<T, C> {
60     /**
61      * The transaction submit queue for the VTN inventory data models.
62      */
63     private final TxQueue  txQueue;
64
65     /**
66      * Construct a new instance.
67      *
68      * @param queue   A {@link TxQueue} instance used to update the
69      *                VTN inventory.
70      * @param broker  A {@link DataBroker} service instance.
71      * @param clz     A {@link Class} instance that represents the target type.
72      * @param scope   A {@link DataChangeScope} instance used to register
73      *                data change listener.
74      */
75     protected InventoryMaintainer(TxQueue queue, DataBroker broker,
76                                   Class<T> clz, DataChangeScope scope) {
77         super(clz);
78         txQueue = queue;
79         registerListener(broker, LogicalDatastoreType.OPERATIONAL, scope);
80     }
81
82     /**
83      * Execute the given transaction task on the transaction queue.
84      *
85      * @param task  A {@link TxTask} that updates the MD-SAL datastore.
86      */
87     protected final void submit(TxTask<?> task) {
88         txQueue.post(task);
89     }
90
91     /**
92      * Execute the given transaction task for initialization on the
93      * transaction queue.
94      *
95      * @param task  A {@link TxTask} that initializes the MD-SAL datastore.
96      */
97     protected final void submitInitial(TxTask<?> task) {
98         txQueue.postFirst(task);
99     }
100
101     /**
102      * Read the specified VTN port asynchronously.
103      *
104      * @param tx     A {@link ReadWriteTransaction} instance.
105      * @param sport  A {@link SalPort} instance corresponding to the VTN port.
106      * @return  A future associated with a MD-SAL datastore read transaction.
107      */
108     protected final CheckedFuture<Optional<VtnPort>, ReadFailedException> read(
109         ReadWriteTransaction tx, SalPort sport) {
110         InstanceIdentifier<VtnPort> path = sport.getVtnPortIdentifier();
111         return tx.read(LogicalDatastoreType.OPERATIONAL, path);
112     }
113
114     /**
115      * Determine whether the given VTN port is present or not.
116      *
117      * @param tx     A {@link ReadWriteTransaction} instance.
118      * @param sport  A {@link SalPort} instance corresponding to the VTN port.
119      * @return  {@code true} only if the specified VTN port is present.
120      * @throws VTNException
121      *    An error occurred.
122      */
123     protected final boolean isPresent(ReadWriteTransaction tx, SalPort sport)
124         throws VTNException {
125         InstanceIdentifier<VtnPort> path = sport.getVtnPortIdentifier();
126         LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
127         return DataStoreUtils.read(tx, oper, path).isPresent();
128     }
129
130     /**
131      * Add the given inter-switch link information into the VTN inventory data.
132      *
133      * @param tx   A {@link ReadWriteTransaction} instance.
134      * @param lid  The identifier of the created link.
135      * @param src  A {@link SalPort} instance corresponding to the source
136      *             of the created link.
137      * @param dst  A {@link SalPort} instance corresponding to the destination
138      *             of the created link.
139      * @return  {@code true} if the link was added to the vtn-topology list.
140      *          {@code false} if the link was added to the ignored-links list.
141      * @throws VTNException
142      *    An error occurred.
143      */
144     protected final boolean addVtnLink(ReadWriteTransaction tx, LinkId lid,
145                                        SalPort src, SalPort dst)
146         throws VTNException {
147         // Determine whether the VTN port for both termination points are
148         // present or not.
149         CheckedFuture<Optional<VtnPort>, ReadFailedException> sf =
150             read(tx, src);
151         CheckedFuture<Optional<VtnPort>, ReadFailedException> df =
152             read(tx, dst);
153         boolean srcPresent = DataStoreUtils.read(sf).isPresent();
154         boolean dstPresent = DataStoreUtils.read(df).isPresent();
155
156         boolean ret;
157         if (srcPresent && dstPresent) {
158             // Create link information.
159             createVtnLink(tx, lid, src, dst);
160             ret = true;
161         } else {
162             // Put link information into ignored link list.
163             InstanceIdentifier<IgnoredLink> key =
164                 InventoryUtils.toIgnoredLinkIdentifier(lid);
165             IgnoredLink ilink =
166                 InventoryUtils.toIgnoredLinkBuilder(lid, src, dst).build();
167             tx.merge(LogicalDatastoreType.OPERATIONAL, key, ilink, true);
168             ret = false;
169         }
170
171         return ret;
172     }
173
174     /**
175      * Remove all VTN links affected by the the removed VTN node.
176      *
177      * @param tx     A {@link ReadWriteTransaction} instance.
178      * @param snode  A {@link SalNode} instance corresponding to the removed
179      *               VTN node.
180      * @throws VTNException
181      *    An error occurred.
182      */
183     protected final void removeVtnLink(ReadWriteTransaction tx, SalNode snode)
184         throws VTNException {
185         removeVtnTopologyLink(tx, snode);
186         removeIgnoredLink(tx, snode);
187     }
188
189     /**
190      * Remove all VTN links in vtn-topology affected by the removed VTN node.
191      *
192      * @param tx     A {@link ReadWriteTransaction} instance.
193      * @param snode  A {@link SalNode} instance corresponding to the removed
194      *               VTN node.
195      * @throws VTNException
196      *    An error occurred.
197      */
198     protected final void removeVtnTopologyLink(ReadWriteTransaction tx,
199                                                SalNode snode)
200         throws VTNException {
201         InstanceIdentifier<VtnTopology> topoPath =
202             InstanceIdentifier.create(VtnTopology.class);
203         LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
204         VtnTopology topology = DataStoreUtils.read(tx, oper, topoPath).
205             orNull();
206         if (topology == null) {
207             return;
208         }
209
210         List<VtnLink> links = topology.getVtnLink();
211         if (links == null) {
212             return;
213         }
214
215         long dpid = snode.getNodeNumber();
216         for (VtnLink vlink: links) {
217             LinkId lid = vlink.getLinkId();
218             SalPort src = SalPort.create(vlink.getSource());
219             SalPort dst = SalPort.create(vlink.getDestination());
220             long srcDpid = src.getNodeNumber();
221             long dstDpid = dst.getNodeNumber();
222
223             boolean rmLink = false;
224             if (srcDpid == dpid) {
225                 rmLink = true;
226                 if (dstDpid != dpid) {
227                     removePortLink(tx, dst, lid);
228                 }
229             } else if (dstDpid == dpid) {
230                 rmLink = true;
231                 removePortLink(tx, src, lid);
232             }
233
234             if (rmLink) {
235                 InstanceIdentifier<VtnLink> lpath =
236                     InventoryUtils.toVtnLinkIdentifier(lid);
237                 tx.delete(oper, lpath);
238             }
239         }
240     }
241
242     /**
243      * Remove all VTN links in ignored-links affected by the removed VTN node.
244      *
245      * @param tx     A {@link ReadWriteTransaction} instance.
246      * @param snode  A {@link SalNode} instance corresponding to the removed
247      *               VTN node.
248      * @throws VTNException
249      *    An error occurred.
250      */
251     protected final void removeIgnoredLink(ReadWriteTransaction tx,
252                                            SalNode snode)
253         throws VTNException {
254         InstanceIdentifier<IgnoredLinks> igPath =
255             InstanceIdentifier.create(IgnoredLinks.class);
256         LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
257         IgnoredLinks igList = DataStoreUtils.read(tx, oper, igPath).orNull();
258         if (igList == null) {
259             return;
260         }
261
262         List<IgnoredLink> links = igList.getIgnoredLink();
263         if (links == null) {
264             return;
265         }
266
267         long dpid = snode.getNodeNumber();
268         for (IgnoredLink vlink: links) {
269             LinkId lid = vlink.getLinkId();
270             SalPort src = SalPort.create(vlink.getSource());
271             SalPort dst = SalPort.create(vlink.getDestination());
272             long srcDpid = src.getNodeNumber();
273             long dstDpid = dst.getNodeNumber();
274
275             if (srcDpid == dpid || dstDpid == dpid) {
276                 InstanceIdentifier<VtnLink> lpath =
277                     InventoryUtils.toVtnLinkIdentifier(lid);
278                 tx.delete(LogicalDatastoreType.OPERATIONAL, lpath);
279             }
280         }
281     }
282
283     /**
284      * Remove all VTN links affected by the removed VTN port.
285      *
286      * @param tx     A {@link ReadWriteTransaction} instance.
287      * @param vport  A {@link VtnPort} instance corresponding to the removed
288      *               VTN port.
289      */
290     protected final void removeVtnLink(ReadWriteTransaction tx,
291                                        VtnPort vport) {
292         List<PortLink> links = vport.getPortLink();
293         if (links == null) {
294             return;
295         }
296
297         for (PortLink plink: links) {
298             LinkId lid = plink.getLinkId();
299             NodeConnectorId peer = plink.getPeer();
300             SalPort p = SalPort.create(peer);
301             removePortLink(tx, p, lid);
302
303             InstanceIdentifier<VtnLink> lpath =
304                 InventoryUtils.toVtnLinkIdentifier(lid);
305             tx.delete(LogicalDatastoreType.OPERATIONAL, lpath);
306         }
307     }
308
309     /**
310      * Remove the specified port link.
311      *
312      * @param tx     A {@link ReadWriteTransaction} instance.
313      * @param sport  A {@link SalPort} instance corresponding to a VTN port.
314      * @param lid    A {@link LinkId} that specifies inter-switch link to be
315      *               removed.
316      */
317     protected final void removePortLink(ReadWriteTransaction tx, SalPort sport,
318                                         LinkId lid) {
319         InstanceIdentifier<PortLink> path = sport.getPortLinkIdentifier(lid);
320         tx.delete(LogicalDatastoreType.OPERATIONAL, path);
321     }
322
323     /**
324      * Try to resolve ignored inter-switch links.
325      *
326      * @param ctx     A runtime context for transaction task.
327      * @param logger  A {@link Logger} instance.
328      * @throws VTNException
329      *    An error occurred.
330      */
331     protected final void resolveIgnoredLinks(TxContext ctx, Logger logger)
332         throws VTNException {
333         // Read all ignored inter-switch links.
334         InstanceIdentifier<IgnoredLinks> igPath =
335             InstanceIdentifier.create(IgnoredLinks.class);
336         ReadWriteTransaction tx = ctx.getReadWriteTransaction();
337         LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
338         IgnoredLinks igLinks = DataStoreUtils.read(tx, oper, igPath).orNull();
339         if (igLinks == null) {
340             return;
341         }
342
343         List<IgnoredLink> igList = igLinks.getIgnoredLink();
344         if (igList == null) {
345             return;
346         }
347
348         InventoryReader reader = ctx.getInventoryReader();
349         for (IgnoredLink ignored: igList) {
350             SalPort src = SalPort.create(ignored.getSource());
351             SalPort dst = SalPort.create(ignored.getDestination());
352             if (reader.get(src) != null && reader.get(dst) != null) {
353                 // Move this link to vtn-topology.
354                 LinkId lid = ignored.getLinkId();
355                 InstanceIdentifier<IgnoredLink> ipath =
356                     InventoryUtils.toIgnoredLinkIdentifier(lid);
357                 tx.delete(oper, ipath);
358                 createVtnLink(tx, lid, src, dst);
359                 logger.info("Inter-switch link has been resolved: {}: {} -> {}",
360                             lid.getValue(), src, dst);
361             }
362         }
363     }
364
365     /**
366      * Create a VTN link information.
367      *
368      * @param tx   A {@link ReadWriteTransaction} instance.
369      * @param lid  The identifier of the created link.
370      * @param src  A {@link SalPort} instance corresponding to the source
371      *             of the created link.
372      * @param dst  A {@link SalPort} instance corresponding to the destination
373      *             of the created link.
374      */
375     private void createVtnLink(ReadWriteTransaction tx, LinkId lid,
376                                SalPort src, SalPort dst) {
377         // Put the link information into vtn-topology list.
378         InstanceIdentifier<VtnLink> key =
379             InventoryUtils.toVtnLinkIdentifier(lid);
380         VtnLink vlink = InventoryUtils.toVtnLinkBuilder(lid, src, dst).build();
381         LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
382         tx.merge(oper, key, vlink, true);
383
384         // Create source port link.
385         InstanceIdentifier<PortLink> pkey = src.getPortLinkIdentifier(lid);
386         PortLink plink = InventoryUtils.toPortLinkBuilder(lid, dst).build();
387         tx.merge(oper, pkey, plink, true);
388
389         // Create destination port link.
390         pkey = dst.getPortLinkIdentifier(lid);
391         plink = InventoryUtils.toPortLinkBuilder(lid, src).build();
392         tx.merge(oper, pkey, plink, true);
393     }
394 }