src/plugin.h: Added `VALUE_LIST_INIT', a static initializer for value_list_t.
[collectd.git] / src / nfs.c
1 /**
2  * collectd - src/nfs.c
3  * Copyright (C) 2005,2006  Jason Pepas
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; only version 2 of the License is applicable.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
17  *
18  * Authors:
19  *   Jason Pepas <cell at ices.utexas.edu>
20  *   Florian octo Forster <octo at verplant.org>
21  **/
22
23 #include "collectd.h"
24 #include "common.h"
25 #include "plugin.h"
26 #include "utils_debug.h"
27
28 #define MODULE_NAME "nfs"
29
30 /* #if defined(KERNEL_LINUX) || defined(HAVE_LIBKSTAT) */
31 #if KERNEL_LINUX
32 # define NFS_HAVE_READ 1
33 #else
34 # define NFS_HAVE_READ 0
35 #endif
36
37 /*
38 see /proc/net/rpc/nfs
39 see http://www.missioncriticallinux.com/orph/NFS-Statistics
40
41 net x x x x
42 rpc_stat.netcnt         Not used; always zero.
43 rpc_stat.netudpcnt      Not used; always zero.
44 rpc_stat.nettcpcnt      Not used; always zero.
45 rpc_stat.nettcpconn     Not used; always zero.
46
47 rpc x x x
48 rpc_stat.rpccnt             The number of RPC calls.
49 rpc_stat.rpcretrans         The number of retransmitted RPC calls.
50 rpc_stat.rpcauthrefresh     The number of credential refreshes.
51
52 proc2 x x x...
53 proc3 x x x...
54
55 Procedure   NFS Version NFS Version 3
56 Number      Procedures  Procedures
57
58 0           null        null
59 1           getattr     getattr
60 2           setattr     setattr
61 3           root        lookup
62 4           lookup      access
63 5           readlink    readlink
64 6           read        read
65 7           wrcache     write
66 8           write       create
67 9           create      mkdir
68 10          remove      symlink
69 11          rename      mknod
70 12          link        remove
71 13          symlink     rmdir
72 14          mkdir       rename
73 15          rmdir       link
74 16          readdir     readdir
75 17          fsstat      readdirplus
76 18                      fsstat
77 19                      fsinfo
78 20                      pathconf
79 21                      commit
80 */
81
82 static data_source_t procedure_dsrc[1] =
83 {
84         {"value", DS_TYPE_COUNTER, 0, 4294967295.0}
85 };
86
87 static data_set_t procedure_ds =
88 {
89         "nfs_procedure", 1, procedure_dsrc
90 };
91
92 static const char *nfs2_procedures_names[] =
93 {
94         "null",
95         "getattr",
96         "setattr",
97         "root",
98         "lookup",
99         "readlink",
100         "read",
101         "wrcache",
102         "write",
103         "create",
104         "remove",
105         "rename",
106         "link",
107         "symlink",
108         "mkdir",
109         "rmdir",
110         "readdir",
111         "fsstat",
112         NULL
113 };
114 static int nfs2_procedures_names_num = 18;
115
116 static const char *nfs3_procedures_names[] =
117 {
118         "null",
119         "getattr",
120         "setattr",
121         "lookup",
122         "access",
123         "readlink",
124         "read",
125         "write",
126         "create",
127         "mkdir",
128         "symlink",
129         "mknod",
130         "remove",
131         "rmdir",
132         "rename",
133         "link",
134         "readdir",
135         "readdirplus",
136         "fsstat",
137         "fsinfo",
138         "pathconf",
139         "commit",
140         NULL
141 };
142 static int nfs3_procedures_names_num = 22;
143
144 #if HAVE_LIBKSTAT && 0
145 extern kstat_ctl_t *kc;
146 static kstat_t *nfs2_ksp_client;
147 static kstat_t *nfs2_ksp_server;
148 static kstat_t *nfs3_ksp_client;
149 static kstat_t *nfs3_ksp_server;
150 static kstat_t *nfs4_ksp_client;
151 static kstat_t *nfs4_ksp_server;
152 #endif
153
154 /* Possibly TODO: NFSv4 statistics */
155
156 #if 0
157 static int nfs_init (void)
158 {
159 #if HAVE_LIBKSTAT && 0
160         kstat_t *ksp_chain;
161
162         nfs2_ksp_client = NULL;
163         nfs2_ksp_server = NULL;
164         nfs3_ksp_client = NULL;
165         nfs3_ksp_server = NULL;
166         nfs4_ksp_client = NULL;
167         nfs4_ksp_server = NULL;
168         
169         if (kc == NULL)
170                 return;
171
172         for (ksp_chain = kc->kc_chain; ksp_chain != NULL;
173                         ksp_chain = ksp_chain->ks_next)
174         {
175                 if (strncmp (ksp_chain->ks_module, "nfs", 3) != 0)
176                         continue;
177                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v2", 13) == 0)
178                         nfs2_ksp_server = ksp_chain;
179                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v3", 13) == 0)
180                         nfs3_ksp_server = ksp_chain;
181                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v4", 13) == 0)
182                         nfs4_ksp_server = ksp_chain;
183                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v2", 12) == 0)
184                         nfs2_ksp_client = ksp_chain;
185                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v3", 12) == 0)
186                         nfs3_ksp_client = ksp_chain;
187                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v4", 12) == 0)
188                         nfs4_ksp_client = ksp_chain;
189         }
190 #endif
191
192         return (0);
193 } /* int nfs_init */
194 #endif
195
196 #define BUFSIZE 1024
197 #if NFS_HAVE_READ
198 static void nfs_procedures_submit (const char *plugin_instance,
199                 unsigned long long *val, const char **names, int len)
200 {
201         value_t values[1];
202         value_list_t vl = VALUE_LIST_INIT;
203         int i;
204
205         vl.values = values;
206         vl.values_len = 1;
207         vl.time = time (NULL);
208         /* FIXME: do this globally */
209         if (gethostname (vl.host, sizeof (vl.host)) != 0)
210         {
211                 syslog (LOG_ERR, "load plugin: gethostname failed: %s",
212                                 strerror (errno));
213                 return;
214         }
215         strcpy (vl.plugin, "nfs");
216         strncpy (vl.plugin_instance, plugin_instance,
217                         sizeof (vl.plugin_instance));
218
219         for (i = 0; i < len; i++)
220         {
221                 values[0].counter = val[i];
222                 strncpy (vl.type_instance, names[i],
223                                 sizeof (vl.type_instance));
224                 DBG ("%s-%s/nfs_procedure-%s = %llu",
225                                 vl.plugin, vl.plugin_instance,
226                                 vl.type_instance, val[i]);
227                 plugin_dispatch_values ("nfs_procedure", &vl);
228         }
229 } /* void nfs_procedures_submit */
230 #endif /* NFS_HAVE_READ */
231
232 #if KERNEL_LINUX
233 static void nfs_read_stats_file (FILE *fh, char *inst)
234 {
235         char buffer[BUFSIZE];
236
237         char plugin_instance[DATA_MAX_NAME_LEN];
238
239         char *fields[48];
240         int numfields = 0;
241
242         if (fh == NULL)
243                 return;
244
245         while (fgets (buffer, BUFSIZE, fh) != NULL)
246         {
247                 numfields = strsplit (buffer, fields, 48);
248
249                 if (((numfields - 2) != nfs2_procedures_names_num)
250                                 && ((numfields - 2)
251                                         != nfs3_procedures_names_num))
252                         continue;
253
254                 if (strcmp (fields[0], "proc2") == 0)
255                 {
256                         int i;
257                         unsigned long long *values;
258
259                         if ((numfields - 2) != nfs2_procedures_names_num)
260                         {
261                                 syslog (LOG_WARNING, "nfs plugin: Wrong "
262                                                 "number of fields (= %i) "
263                                                 "for NFSv2 statistics.",
264                                                 numfields - 2);
265                                 continue;
266                         }
267
268                         snprintf (plugin_instance, sizeof (plugin_instance),
269                                         "v2%s", inst);
270                         plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
271
272                         values = (unsigned long long *) malloc (nfs2_procedures_names_num * sizeof (unsigned long long));
273                         if (values == NULL)
274                         {
275                                 syslog (LOG_ERR, "nfs plugin: malloc "
276                                                 "failed: %s",
277                                                 strerror (errno));
278                                 continue;
279                         }
280
281                         for (i = 0; i < nfs2_procedures_names_num; i++)
282                                 values[i] = atoll (fields[i + 2]);
283
284                         nfs_procedures_submit (plugin_instance, values,
285                                         nfs2_procedures_names,
286                                         nfs2_procedures_names_num);
287
288                         free (values);
289                 }
290                 else if (strncmp (fields[0], "proc3", 5) == 0)
291                 {
292                         int i;
293                         unsigned long long *values;
294
295                         if ((numfields - 2) != nfs3_procedures_names_num)
296                         {
297                                 syslog (LOG_WARNING, "nfs plugin: Wrong "
298                                                 "number of fields (= %i) "
299                                                 "for NFSv3 statistics.",
300                                                 numfields - 2);
301                                 continue;
302                         }
303
304                         snprintf (plugin_instance, sizeof (plugin_instance),
305                                         "v3%s", inst);
306                         plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
307
308                         values = (unsigned long long *) malloc (nfs3_procedures_names_num * sizeof (unsigned long long));
309                         if (values == NULL)
310                         {
311                                 syslog (LOG_ERR, "nfs plugin: malloc "
312                                                 "failed: %s",
313                                                 strerror (errno));
314                                 continue;
315                         }
316
317                         for (i = 0; i < nfs3_procedures_names_num; i++)
318                                 values[i] = atoll (fields[i + 2]);
319
320                         nfs_procedures_submit (plugin_instance, values,
321                                         nfs3_procedures_names,
322                                         nfs3_procedures_names_num);
323
324                         free (values);
325                 }
326         } /* while (fgets (buffer, BUFSIZE, fh) != NULL) */
327 } /* void nfs_read_stats_file */
328 #endif /* defined(KERNEL_LINUX) */
329 #undef BUFSIZE
330
331 #if HAVE_LIBKSTAT && 0
332 static void nfs2_read_kstat (kstat_t *ksp, char *inst)
333 {
334         unsigned long long values[18];
335
336         values[0] = get_kstat_value (ksp, "null");
337         values[1] = get_kstat_value (ksp, "getattr");
338         values[2] = get_kstat_value (ksp, "setattr");
339         values[3] = get_kstat_value (ksp, "root");
340         values[4] = get_kstat_value (ksp, "lookup");
341         values[5] = get_kstat_value (ksp, "readlink");
342         values[6] = get_kstat_value (ksp, "read");
343         values[7] = get_kstat_value (ksp, "wrcache");
344         values[8] = get_kstat_value (ksp, "write");
345         values[9] = get_kstat_value (ksp, "create");
346         values[10] = get_kstat_value (ksp, "remove");
347         values[11] = get_kstat_value (ksp, "rename");
348         values[12] = get_kstat_value (ksp, "link");
349         values[13] = get_kstat_value (ksp, "symlink");
350         values[14] = get_kstat_value (ksp, "mkdir");
351         values[15] = get_kstat_value (ksp, "rmdir");
352         values[16] = get_kstat_value (ksp, "readdir");
353         values[17] = get_kstat_value (ksp, "statfs");
354
355         nfs2_procedures_submit (values, inst);
356 }
357 #endif
358
359 #if NFS_HAVE_READ
360 static int nfs_read (void)
361 {
362 #if KERNEL_LINUX
363         FILE *fh;
364
365         if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
366         {
367                 nfs_read_stats_file (fh, "client");
368                 fclose (fh);
369         }
370
371         if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
372         {
373                 nfs_read_stats_file (fh, "server");
374                 fclose (fh);
375         }
376
377 /* #endif defined(KERNEL_LINUX) */
378
379 #elif HAVE_LIBKSTAT && 0
380         if (nfs2_ksp_client != NULL)
381                 nfs2_read_kstat (nfs2_ksp_client, "client");
382         if (nfs2_ksp_server != NULL)
383                 nfs2_read_kstat (nfs2_ksp_server, "server");
384 #endif /* defined(HAVE_LIBKSTAT) */
385
386         return (0);
387 }
388 #endif /* NFS_HAVE_READ */
389
390 void module_register (void)
391 {
392         plugin_register_data_set (&procedure_ds);
393
394 #if NFS_HAVE_READ
395         plugin_register_read ("nfs", nfs_read);
396 #endif
397 }
398
399 #undef MODULE_NAME