Code

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  **/
23 #include "collectd.h"
24 #include "common.h"
25 #include "plugin.h"
26 #include "utils_debug.h"
28 #define MODULE_NAME "nfs"
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
37 /*
38 see /proc/net/rpc/nfs
39 see http://www.missioncriticallinux.com/orph/NFS-Statistics
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.
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.
52 proc2 x x x...
53 proc3 x x x...
55 Procedure   NFS Version NFS Version 3
56 Number      Procedures  Procedures
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 */
82 static data_source_t procedure_dsrc[1] =
83 {
84         {"value", DS_TYPE_COUNTER, 0, 4294967295.0}
85 };
87 static data_set_t procedure_ds =
88 {
89         "nfs_procedure", 1, procedure_dsrc
90 };
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;
117 static const char *nfs3_procedures_names[] =
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;
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
155 /* Possibly TODO: NFSv4 statistics */
157 #if 0
158 static int nfs_init (void)
160 #if HAVE_LIBKSTAT && 0
161         kstat_t *ksp_chain;
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;
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
193         return (0);
194 } /* int nfs_init */
195 #endif
197 #define BUFSIZE 1024
198 static void nfs_procedures_submit (const char *plugin_instance,
199                 unsigned long long *val, const char **names, int len)
201         value_t values[1];
202         value_list_t vl = VALUE_LIST_INIT;
203         int i;
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));
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 */
225 #if KERNEL_LINUX
226 static void nfs_read_stats_file (FILE *fh, char *inst)
228         char buffer[BUFSIZE];
230         char plugin_instance[DATA_MAX_NAME_LEN];
232         char *fields[48];
233         int numfields = 0;
235         if (fh == NULL)
236                 return;
238         while (fgets (buffer, BUFSIZE, fh) != NULL)
239         {
240                 numfields = strsplit (buffer, fields, 48);
242                 if (((numfields - 2) != nfs2_procedures_names_num)
243                                 && ((numfields - 2)
244                                         != nfs3_procedures_names_num))
245                         continue;
247                 if (strcmp (fields[0], "proc2") == 0)
248                 {
249                         int i;
250                         unsigned long long *values;
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                         }
261                         snprintf (plugin_instance, sizeof (plugin_instance),
262                                         "v2%s", inst);
263                         plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
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                         }
274                         for (i = 0; i < nfs2_procedures_names_num; i++)
275                                 values[i] = atoll (fields[i + 2]);
277                         nfs_procedures_submit (plugin_instance, values,
278                                         nfs2_procedures_names,
279                                         nfs2_procedures_names_num);
281                         free (values);
282                 }
283                 else if (strncmp (fields[0], "proc3", 5) == 0)
284                 {
285                         int i;
286                         unsigned long long *values;
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                         }
297                         snprintf (plugin_instance, sizeof (plugin_instance),
298                                         "v3%s", inst);
299                         plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
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                         }
310                         for (i = 0; i < nfs3_procedures_names_num; i++)
311                                 values[i] = atoll (fields[i + 2]);
313                         nfs_procedures_submit (plugin_instance, values,
314                                         nfs3_procedures_names,
315                                         nfs3_procedures_names_num);
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
324 #if HAVE_LIBKSTAT && 0
325 static void nfs2_read_kstat (kstat_t *ksp, char *inst)
327         unsigned long long values[18];
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");
348         nfs2_procedures_submit (values, inst);
350 #endif
352 static int nfs_read (void)
354 #if KERNEL_LINUX
355         FILE *fh;
357         if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
358         {
359                 nfs_read_stats_file (fh, "client");
360                 fclose (fh);
361         }
363         if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
364         {
365                 nfs_read_stats_file (fh, "server");
366                 fclose (fh);
367         }
369 /* #endif defined(KERNEL_LINUX) */
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) */
378         return (0);
380 #endif /* NFS_HAVE_READ */
382 void module_register (void)
384         plugin_register_data_set (&procedure_ds);
386 #if NFS_HAVE_READ
387         plugin_register_read ("nfs", nfs_read);
388 #endif
391 #undef MODULE_NAME