9cbf61e3bf081aff64933939969b32f5a00df4f5
[vtn.git] /
1 /*
2  * Copyright (c) 2015 NEC Corporation.  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.vtn.manager.internal.routing;
10
11 import java.util.List;
12
13 import org.slf4j.Logger;
14 import org.slf4j.LoggerFactory;
15
16 import org.apache.commons.collections15.Transformer;
17
18 import org.opendaylight.vtn.manager.PathPolicy;
19 import org.opendaylight.vtn.manager.VTNException;
20
21 import org.opendaylight.vtn.manager.internal.util.DataStoreUtils;
22 import org.opendaylight.vtn.manager.internal.util.inventory.InventoryReader;
23 import org.opendaylight.vtn.manager.internal.util.inventory.LinkEdge;
24 import org.opendaylight.vtn.manager.internal.util.inventory.NodeUtils;
25 import org.opendaylight.vtn.manager.internal.util.inventory.SalPort;
26 import org.opendaylight.vtn.manager.internal.util.pathpolicy.PathPolicyUtils;
27
28 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
29 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
30 import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
31 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
32
33 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
34
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.inventory.rev150209.vtn.node.info.VtnPort;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.VtnPathPolicies;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.vtn.path.policies.VtnPathPolicy;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.vtn.path.policies.VtnPathPolicyKey;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.vtn.path.policy.config.VtnPathCost;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.pathpolicy.rev150209.vtn.path.policy.config.VtnPathCostKey;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.types.rev150209.VtnPortDesc;
42
43 /**
44  * An implementation of {@link Transformer} that transforms link edge into
45  * the cost of the link.
46  *
47  * <p>
48  *   Note that this class is not synchronized.
49  * </p>
50  */
51 final class PathPolicyTransformer implements Transformer<LinkEdge, Long> {
52     /**
53      * Logger instance.
54      */
55     private static final Logger  LOG =
56         LoggerFactory.getLogger(PathPolicyTransformer.class);
57
58     /**
59      * A data broker service.
60      */
61     private final DataBroker  dataBroker;
62
63     /**
64      * The index of the path policy.
65      */
66     private final int  policyId;
67
68     /**
69      * VTN inventory reader.
70      */
71     private InventoryReader  reader;
72
73     /**
74      * A class which holds inventory reader and local DS transaction.
75      */
76     private final class InventoryReaderHolder {
77         /**
78          * An inventory reader.
79          */
80         private final InventoryReader  localReader;
81
82         /**
83          * A read-only MD-SAL DS transaction.
84          */
85         private final ReadOnlyTransaction  localTx;
86
87         /**
88          * Construct a new instance.
89          */
90         private InventoryReaderHolder() {
91             InventoryReader rdr = reader;
92             if (rdr == null) {
93                 // Create a new reader using local transaction.
94                 localTx = dataBroker.newReadOnlyTransaction();
95                 rdr = new InventoryReader(localTx);
96             } else {
97                 localTx = null;
98             }
99
100             localReader = rdr;
101         }
102
103         /**
104          * Return an inventory reader.
105          *
106          * @return  A {@link InventoryReader} instance.
107          */
108         private InventoryReader getReader() {
109             return localReader;
110         }
111
112         /**
113          * Close the MD-SAL DS transaction.
114          */
115         private void close() {
116             if (localTx != null) {
117                 localTx.close();
118             }
119         }
120     }
121
122     /**
123      * Construct a new instance.
124      *
125      * @param broker  A {@link DataBroker} service.
126      * @param id      The index of the path policy associated with this
127      *                instance.
128      */
129     PathPolicyTransformer(DataBroker broker, int id) {
130         dataBroker = broker;
131         policyId = id;
132     }
133
134     /**
135      * Set inventory reader that contains active transaction for the MD-SAL
136      * datastore.
137      *
138      * @param rdr  An {@link InventoryReader} instance.
139      * @return  An {@link InventoryReader} currently configured is returned.
140      */
141     InventoryReader setReader(InventoryReader rdr) {
142         InventoryReader old = reader;
143         reader = rdr;
144         return old;
145     }
146
147     /**
148      * Return the path cost associated with the given switch port.
149      *
150      * @param rdr    A {@link InventoryReader} instance.
151      * @param sport  A {@link SalPort} instance.
152      * @return  A {@link Long} instance which represents the cost.
153      *          {@code null} is returned if the default cost should be used.
154      * @throws VTNException  An error occurred.
155      */
156     private Long getCost(InventoryReader rdr, SalPort sport)
157         throws VTNException {
158         VtnPort vport = rdr.get(sport);
159         if (vport == null) {
160             // This should never happen.
161             LOG.warn("{}: Unknown port: {}", policyId, sport);
162             return Long.valueOf(Long.MAX_VALUE);
163         }
164
165         // Read path policy configuration.
166         VtnPathPolicyKey key = new VtnPathPolicyKey(Integer.valueOf(policyId));
167         InstanceIdentifier<VtnPathPolicy> path = InstanceIdentifier.
168             builder(VtnPathPolicies.class).
169             child(VtnPathPolicy.class, key).build();
170         LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
171         ReadTransaction rtx = rdr.getReadTransaction();
172         VtnPathPolicy vpp = DataStoreUtils.read(rtx, oper, path).orNull();
173         if (vpp == null) {
174             LOG.debug("{}: Path policy not found: port={}", policyId, sport);
175             return null;
176         }
177
178         List<VtnPathCost> vcosts = vpp.getVtnPathCost();
179         if (vcosts != null && !vcosts.isEmpty()) {
180             VtnPortDesc[] descriptors =
181                 NodeUtils.createPortDescArray(sport, vport);
182             for (VtnPortDesc vpdesc: descriptors) {
183                 VtnPathCostKey ckey = new VtnPathCostKey(vpdesc);
184                 InstanceIdentifier<VtnPathCost> cpath = InstanceIdentifier.
185                     builder(VtnPathPolicies.class).
186                     child(VtnPathPolicy.class, key).
187                     child(VtnPathCost.class, ckey).build();
188                 VtnPathCost vpc = DataStoreUtils.read(rtx, oper, cpath).
189                     orNull();
190                 if (vpc != null) {
191                     Long cost = vpc.getCost();
192                     LOG.trace("{}: Path cost was found: port={}, desc={}, " +
193                               "cost={}", policyId, sport, vpdesc.getValue(),
194                               cost);
195                     return cost;
196                 }
197             }
198         }
199
200         // Use default cost.
201         return getDefaultCost(vpp, sport, vport);
202     }
203
204     /**
205      * Return the default path cost.
206      *
207      * @param vpp    A {@link VtnPathPolicy} instance.
208      * @param sport  A {@link SalPort} instance.
209      * @param vport  A {@link VtnPort} instance.
210      * @return  A {@link Long} instance which represents the cost.
211      *          {@code null} is returned if the default cost should be used.
212      */
213     private Long getDefaultCost(VtnPathPolicy vpp, SalPort sport,
214                                 VtnPort vport) {
215         Long cost = vpp.getDefaultCost();
216         if (cost == null || cost.longValue() == PathPolicy.COST_UNDEF) {
217             cost = vport.getCost();
218             LOG.trace("{}: Use link cost in VTN port: port={}, cost={}",
219                       policyId, sport, cost);
220         } else {
221             LOG.trace("{}: Use default cost: port={}, cost={}", policyId,
222                       sport, cost);
223         }
224
225         return cost;
226     }
227
228     // Transformer
229
230     /**
231      * Return the cost associated with the given link edge.
232      *
233      * @param le  A {@link LinkEdge} instance.
234      * @return  A {@link Long} instance which represents the cost.
235      */
236     @Override
237     public Long transform(LinkEdge le) {
238         if (le == null) {
239             LOG.warn("{}: Link edge is null.", policyId);
240             return Long.valueOf(Long.MAX_VALUE);
241         }
242
243         SalPort sport = le.getSourcePort();
244         if (sport == null) {
245             LOG.warn("{}: Switch port is null: {}", policyId, le);
246             return Long.valueOf(Long.MAX_VALUE);
247         }
248
249         // Prepare MD-SAL datastore transaction.
250         InventoryReaderHolder holder = new InventoryReaderHolder();
251         Long cost;
252         try {
253             cost = getCost(holder.getReader(), sport);
254             if (cost == null) {
255                 cost = PathPolicyUtils.DEFAULT_LINK_COST;
256             }
257         } catch (Exception e) {
258             StringBuilder builder = new StringBuilder();
259             builder.append(policyId).
260                 append(": Failed to determine path cost for ").
261                 append(le).append('.');
262             LOG.warn(builder.toString(), e);
263             cost = Long.valueOf(Long.MAX_VALUE);
264         } finally {
265             holder.close();
266         }
267
268         return cost;
269     }
270 }