ec6a69b9d4ce3524998297f165def96519f8e25f
[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.flow.stats;
11
12 import java.math.BigInteger;
13 import java.util.ArrayList;
14 import java.util.List;
15 import java.util.Timer;
16 import java.util.TimerTask;
17
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
20
21 import com.google.common.base.Optional;
22
23 import org.opendaylight.vtn.manager.VTNException;
24
25 import org.opendaylight.vtn.manager.internal.TxContext;
26 import org.opendaylight.vtn.manager.internal.TxQueue;
27 import org.opendaylight.vtn.manager.internal.VTNManagerProvider;
28 import org.opendaylight.vtn.manager.internal.util.DataStoreUtils;
29 import org.opendaylight.vtn.manager.internal.util.FixedLogger;
30 import org.opendaylight.vtn.manager.internal.util.LogRecord;
31 import org.opendaylight.vtn.manager.internal.util.flow.FlowCache;
32 import org.opendaylight.vtn.manager.internal.util.flow.FlowStatsUtils;
33 import org.opendaylight.vtn.manager.internal.util.tx.AbstractTxTask;
34
35 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
36 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
37
38 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
39
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.flow.rev150313.VtnFlows;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.flow.rev150313.tenant.flow.info.VtnDataFlow;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.flow.rev150313.tenant.flow.info.VtnDataFlowKey;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.flow.rev150313.vtn.data.flow.fields.FlowStatsHistory;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.flow.rev150313.vtn.data.flow.fields.VtnFlowEntry;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.flow.rev150313.vtn.data.flow.fields.flow.stats.history.FlowStatsRecord;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.flow.rev150313.vtn.data.flow.fields.flow.stats.history.FlowStatsRecordBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.vtn.impl.flow.rev150313.vtn.flows.VtnFlowTable;
48
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics;
51
52 /**
53  * The timer task that collects flow statistics periodically.
54  */
55 public final class StatsTimerTask extends TimerTask implements AutoCloseable {
56     /**
57      * Logger instance.
58      */
59     private static final Logger  LOG =
60         LoggerFactory.getLogger(StatsTimerTask.class);
61
62     /**
63      * The interval in milliseconds for updating flow statistics information.
64      */
65     private static final long  STATS_INTERVAL = 10000;
66
67     /**
68      * The MD-SAL transaction queue used to update the MD-SAL datastore.
69      */
70     private final TxQueue  txQueue;
71
72     /**
73      * {@code StatsUpdator} describes the MD-SAL datastore transaction task
74      * that updates flow statistics information.
75      */
76     private static class StatsUpdator extends AbstractTxTask<Void> {
77         /**
78          * A logger for trace logs.
79          */
80         private final FixedLogger  traceLogger = new FixedLogger.Trace(LOG);
81
82         /**
83          * The system time when the flow statistics are collected.
84          */
85         private Long  systemTime;
86
87         /**
88          * A list of log records.
89          */
90         private List<LogRecord>  logRecords;
91
92         /**
93          * The MAC address of the controller.
94          */
95         private Long  controllerAddress;
96
97         /**
98          * Update flow statistics in the specified VTN.
99          *
100          * @param tx     A {@link ReadWriteTransaction} instance.
101          * @param table  A flow table that contains all the flow entries in
102          *               the VTN.
103          * @throws VTNException  An error occurred.
104          */
105         private void update(ReadWriteTransaction tx, VtnFlowTable table)
106             throws VTNException {
107             List<VtnDataFlow> dataFlows = table.getVtnDataFlow();
108             if (dataFlows != null) {
109                 String tname = table.getTenantName();
110                 for (VtnDataFlow vdf: dataFlows) {
111                     update(tx, tname, vdf);
112                 }
113             }
114         }
115
116         /**
117          * Update statistics information for the given flow entry.
118          *
119          * @param tx     A {@link ReadWriteTransaction} instance.
120          * @param tname  The name of the VTN.
121          * @param vdf    A {@link VtnDataFlow} instance.
122          * @throws VTNException  An error occurred.
123          */
124         private void update(ReadWriteTransaction tx, String tname,
125                             VtnDataFlow vdf) throws VTNException {
126             VtnDataFlowKey key = vdf.getKey();
127             BigInteger id = key.getFlowId().getValue();
128             Long mac = vdf.getControllerAddress();
129             if (!controllerAddress.equals(mac)) {
130                 String maddr = (mac == null)
131                     ? "<null>"
132                     : Long.toHexString(mac.longValue());
133                 traceLog("Skip flow entry: %s: Not owner: %s", id, maddr);
134                 return;
135             }
136
137             FlowId fid = vdf.getSalFlowId();
138             if (fid == null) {
139                 traceLog("Skip flow entry: %s: No MD-SAL flow ID.", id);
140                 return;
141             }
142
143             // Read flow statistics collected by the MD-SAL statistics manager.
144             FlowCache fc = new FlowCache(vdf);
145             VtnFlowEntry vfent = fc.getIngressFlow();
146             GenericStatistics fstats =
147                 FlowStatsUtils.read(tx, vfent.getNode(), fid);
148             String err = FlowStatsUtils.check(fstats);
149             if (err != null) {
150                 traceLog("Skip flow entry: %s: %s", id, err);
151                 return;
152             }
153
154             // Update the hisotry of flow statistics if needed.
155             FlowStatsRecord fsr = new FlowStatsRecordBuilder(fstats).
156                 setTime(systemTime).setPeriodic(true).build();
157             FlowStatsHistory history =
158                 FlowStatsUtils.update(vdf.getFlowStatsHistory(), fsr);
159             if (history == null) {
160                 traceLog("Skip flow entry: %s: Too rapid.", id);
161             } else {
162                 traceLog("Flow statistics has been updated: %s, %s",
163                          id, fid.getValue());
164                 InstanceIdentifier<FlowStatsHistory> path =
165                     FlowStatsUtils.getIdentifier(tname, key);
166                 LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
167                 tx.put(oper, path, history, false);
168             }
169         }
170
171         /**
172          * Record a trace log message.
173          *
174          * @param format  A format string used to construct log message.
175          * @param args    An object array used to construct log message.
176          */
177         private void traceLog(String format, Object ... args) {
178             if (traceLogger.isEnabled()) {
179                 logRecords.add(new LogRecord(traceLogger, format, args));
180             }
181         }
182
183         // AbstractTxTask
184
185         /**
186          * {@inheritDoc}
187          */
188         @Override
189         public Void execute(TxContext ctx) throws VTNException {
190             systemTime = System.currentTimeMillis();
191             logRecords = new ArrayList<>();
192             if (controllerAddress == null) {
193                 controllerAddress = ctx.getProvider().getVTNConfig().
194                     getControllerMacAddress().getAddress();
195             }
196
197             // Read the root container of flow tables.
198             InstanceIdentifier<VtnFlows> path =
199                 InstanceIdentifier.create(VtnFlows.class);
200             LogicalDatastoreType oper = LogicalDatastoreType.OPERATIONAL;
201             ReadWriteTransaction tx = ctx.getReadWriteTransaction();
202             Optional<VtnFlows> opt = DataStoreUtils.read(tx, oper, path);
203             if (opt.isPresent()) {
204                 List<VtnFlowTable> tables = opt.get().getVtnFlowTable();
205                 if (tables != null) {
206                     for (VtnFlowTable table: tables) {
207                         // Update flow statistics for this VTN.
208                         update(tx, table);
209                     }
210                 }
211             }
212
213             return null;
214         }
215
216         // TxTask
217
218         /**
219          * Invoked when the task has been completed successfully.
220          *
221          * @param provider  VTN Manager provider service.
222          * @param result    The result of this task.
223          */
224         @Override
225         public void onSuccess(VTNManagerProvider provider, Void result) {
226             for (LogRecord r: logRecords) {
227                 r.log();
228             }
229
230             LOG.debug("Flow statistics have been updated successfully.");
231         }
232
233         /**
234          * Invoked when the task has failed.
235          *
236          * @param provider  VTN Manager provider service.
237          * @param t         A {@link Throwable} thrown by the task.
238          */
239         @Override
240         public void onFailure(VTNManagerProvider provider, Throwable t) {
241             LOG.error("Failed to update flow statistics.", t);
242         }
243     }
244
245     /**
246      * Construct a new instance.
247      *
248      * @param timer  A timer thread.
249      * @param txq    A {@link TxQueue} instance used to update the MD-SAL
250      *               datastore.
251      */
252     public StatsTimerTask(Timer timer, TxQueue txq) {
253         txQueue = txq;
254         timer.scheduleAtFixedRate(this, STATS_INTERVAL, STATS_INTERVAL);
255     }
256
257     // Runnable
258
259     /**
260      * Run the timer task to update flow statistics.
261      */
262     @Override
263     public void run() {
264         txQueue.post(new StatsUpdator());
265     }
266
267     // AutoCloseable
268
269     /**
270      * Close this timer task.
271      */
272     @Override
273     public void close() {
274         cancel();
275     }
276 }