Merge branch 'master' into collectd-4
[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 #if NFS_HAVE_READ
93 static const char *nfs2_procedures_names[] =
94 {
95         "null",
96         "getattr",
97         "setattr",
98         "root",
99         "lookup",
100         "readlink",
101         "read",
102         "wrcache",
103         "write",
104         "create",
105         "remove",
106         "rename",
107         "link",
108         "symlink",
109         "mkdir",
110         "rmdir",
111         "readdir",
112         "fsstat",
113         NULL
114 };
115 static int nfs2_procedures_names_num = 18;
116
117 static const char *nfs3_procedures_names[] =
118 {
119         "null",
120         "getattr",
121         "setattr",
122         "lookup",
123         "access",
124         "readlink",
125         "read",
126         "write",
127         "create",
128         "mkdir",
129         "symlink",
130         "mknod",
131         "remove",
132         "rmdir",
133         "rename",
134         "link",
135         "readdir",
136         "readdirplus",
137         "fsstat",
138         "fsinfo",
139         "pathconf",
140         "commit",
141         NULL
142 };
143 static int nfs3_procedures_names_num = 22;
144
145 #if HAVE_LIBKSTAT && 0
146 extern kstat_ctl_t *kc;
147 static kstat_t *nfs2_ksp_client;
148 static kstat_t *nfs2_ksp_server;
149 static kstat_t *nfs3_ksp_client;
150 static kstat_t *nfs3_ksp_server;
151 static kstat_t *nfs4_ksp_client;
152 static kstat_t *nfs4_ksp_server;
153 #endif
154
155 /* Possibly TODO: NFSv4 statistics */
156
157 #if 0
158 static int nfs_init (void)
159 {
160 #if HAVE_LIBKSTAT && 0
161         kstat_t *ksp_chain;
162
163         nfs2_ksp_client = NULL;
164         nfs2_ksp_server = NULL;
165         nfs3_ksp_client = NULL;
166         nfs3_ksp_server = NULL;
167         nfs4_ksp_client = NULL;
168         nfs4_ksp_server = NULL;
169         
170         if (kc == NULL)
171                 return;
172
173         for (ksp_chain = kc->kc_chain; ksp_chain != NULL;
174                         ksp_chain = ksp_chain->ks_next)
175         {
176                 if (strncmp (ksp_chain->ks_module, "nfs", 3) != 0)
177                         continue;
178                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v2", 13) == 0)
179                         nfs2_ksp_server = ksp_chain;
180                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v3", 13) == 0)
181                         nfs3_ksp_server = ksp_chain;
182                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v4", 13) == 0)
183                         nfs4_ksp_server = ksp_chain;
184                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v2", 12) == 0)
185                         nfs2_ksp_client = ksp_chain;
186                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v3", 12) == 0)
187                         nfs3_ksp_client = ksp_chain;
188                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v4", 12) == 0)
189                         nfs4_ksp_client = ksp_chain;
190         }
191 #endif
192
193         return (0);
194 } /* int nfs_init */
195 #endif
196
197 #define BUFSIZE 1024
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         strcpy (vl.host, hostname_g);
209         strcpy (vl.plugin, "nfs");
210         strncpy (vl.plugin_instance, plugin_instance,
211                         sizeof (vl.plugin_instance));
212
213         for (i = 0; i < len; i++)
214         {
215                 values[0].counter = val[i];
216                 strncpy (vl.type_instance, names[i],
217                                 sizeof (vl.type_instance));
218                 DBG ("%s-%s/nfs_procedure-%s = %llu",
219                                 vl.plugin, vl.plugin_instance,
220                                 vl.type_instance, val[i]);
221                 plugin_dispatch_values ("nfs_procedure", &vl);
222         }
223 } /* void nfs_procedures_submit */
224
225 #if KERNEL_LINUX
226 static void nfs_read_stats_file (FILE *fh, char *inst)
227 {
228         char buffer[BUFSIZE];
229
230         char plugin_instance[DATA_MAX_NAME_LEN];
231
232         char *fields[48];
233         int numfields = 0;
234
235         if (fh == NULL)
236                 return;
237
238         while (fgets (buffer, BUFSIZE, fh) != NULL)
239         {
240                 numfields = strsplit (buffer, fields, 48);
241
242                 if (((numfields - 2) != nfs2_procedures_names_num)
243                                 && ((numfields - 2)
244                                         != nfs3_procedures_names_num))
245                         continue;
246
247                 if (strcmp (fields[0], "proc2") == 0)
248                 {
249                         int i;
250                         unsigned long long *values;
251
252                         if ((numfields - 2) != nfs2_procedures_names_num)
253                         {
254                                 syslog (LOG_WARNING, "nfs plugin: Wrong "
255                                                 "number of fields (= %i) "
256                                                 "for NFSv2 statistics.",
257                                                 numfields - 2);
258                                 continue;
259                         }
260
261                         snprintf (plugin_instance, sizeof (plugin_instance),
262                                         "v2%s", inst);
263                         plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
264
265                         values = (unsigned long long *) malloc (nfs2_procedures_names_num * sizeof (unsigned long long));
266                         if (values == NULL)
267                         {
268                                 syslog (LOG_ERR, "nfs plugin: malloc "
269                                                 "failed: %s",
270                                                 strerror (errno));
271                                 continue;
272                         }
273
274                         for (i = 0; i < nfs2_procedures_names_num; i++)
275                                 values[i] = atoll (fields[i + 2]);
276
277                         nfs_procedures_submit (plugin_instance, values,
278                                         nfs2_procedures_names,
279                                         nfs2_procedures_names_num);
280
281                         free (values);
282                 }
283                 else if (strncmp (fields[0], "proc3", 5) == 0)
284                 {
285                         int i;
286                         unsigned long long *values;
287
288                         if ((numfields - 2) != nfs3_procedures_names_num)
289                         {
290                                 syslog (LOG_WARNING, "nfs plugin: Wrong "
291                                                 "number of fields (= %i) "
292                                                 "for NFSv3 statistics.",
293                                                 numfields - 2);
294                                 continue;
295                         }
296
297                         snprintf (plugin_instance, sizeof (plugin_instance),
298                                         "v3%s", inst);
299                         plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
300
301                         values = (unsigned long long *) malloc (nfs3_procedures_names_num * sizeof (unsigned long long));
302                         if (values == NULL)
303                         {
304                                 syslog (LOG_ERR, "nfs plugin: malloc "
305                                                 "failed: %s",
306                                                 strerror (errno));
307                                 continue;
308                         }
309
310                         for (i = 0; i < nfs3_procedures_names_num; i++)
311                                 values[i] = atoll (fields[i + 2]);
312
313                         nfs_procedures_submit (plugin_instance, values,
314                                         nfs3_procedures_names,
315                                         nfs3_procedures_names_num);
316
317                         free (values);
318                 }
319         } /* while (fgets (buffer, BUFSIZE, fh) != NULL) */
320 } /* void nfs_read_stats_file */
321 #endif /* defined(KERNEL_LINUX) */
322 #undef BUFSIZE
323
324 #if HAVE_LIBKSTAT && 0
325 static void nfs2_read_kstat (kstat_t *ksp, char *inst)
326 {
327         unsigned long long values[18];
328
329         values[0] = get_kstat_value (ksp, "null");
330         values[1] = get_kstat_value (ksp, "getattr");
331         values[2] = get_kstat_value (ksp, "setattr");
332         values[3] = get_kstat_value (ksp, "root");
333         values[4] = get_kstat_value (ksp, "lookup");
334         values[5] = get_kstat_value (ksp, "readlink");
335         values[6] = get_kstat_value (ksp, "read");
336         values[7] = get_kstat_value (ksp, "wrcache");
337         values[8] = get_kstat_value (ksp, "write");
338         values[9] = get_kstat_value (ksp, "create");
339         values[10] = get_kstat_value (ksp, "remove");
340         values[11] = get_kstat_value (ksp, "rename");
341         values[12] = get_kstat_value (ksp, "link");
342         values[13] = get_kstat_value (ksp, "symlink");
343         values[14] = get_kstat_value (ksp, "mkdir");
344         values[15] = get_kstat_value (ksp, "rmdir");
345         values[16] = get_kstat_value (ksp, "readdir");
346         values[17] = get_kstat_value (ksp, "statfs");
347
348         nfs2_procedures_submit (values, inst);
349 }
350 #endif
351
352 static int nfs_read (void)
353 {
354 #if KERNEL_LINUX
355         FILE *fh;
356
357         if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
358         {
359                 nfs_read_stats_file (fh, "client");
360                 fclose (fh);
361         }
362
363         if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
364         {
365                 nfs_read_stats_file (fh, "server");
366                 fclose (fh);
367         }
368
369 /* #endif defined(KERNEL_LINUX) */
370
371 #elif HAVE_LIBKSTAT && 0
372         if (nfs2_ksp_client != NULL)
373                 nfs2_read_kstat (nfs2_ksp_client, "client");
374         if (nfs2_ksp_server != NULL)
375                 nfs2_read_kstat (nfs2_ksp_server, "server");
376 #endif /* defined(HAVE_LIBKSTAT) */
377
378         return (0);
379 }
380 #endif /* NFS_HAVE_READ */
381
382 void module_register (void)
383 {
384         plugin_register_data_set (&procedure_ds);
385
386 #if NFS_HAVE_READ
387         plugin_register_read ("nfs", nfs_read);
388 #endif
389 }
390
391 #undef MODULE_NAME