Code

Copied missing files from the subversion repository.
[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; either version 2 of the License, or (at your
8  * option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18  *
19  * Authors:
20  *   Jason Pepas <cell at ices.utexas.edu>
21  *   Florian octo Forster <octo at verplant.org>
22  **/
24 #include "collectd.h"
25 #include "common.h"
26 #include "plugin.h"
28 #define MODULE_NAME "nfs"
30 #if defined(KERNEL_LINUX) || defined(HAVE_LIBKSTAT)
31 # define NFS_HAVE_READ 1
32 #else
33 # define NFS_HAVE_READ 0
34 #endif
36 static char *nfs2_procedures_file  = "nfs2_procedures-%s.rrd";
37 static char *nfs3_procedures_file  = "nfs3_procedures-%s.rrd";
39 /*
40 see /proc/net/rpc/nfs
41 see http://www.missioncriticallinux.com/orph/NFS-Statistics
43 net x x x x
44 rpc_stat.netcnt         Not used; always zero.
45 rpc_stat.netudpcnt      Not used; always zero.
46 rpc_stat.nettcpcnt      Not used; always zero.
47 rpc_stat.nettcpconn     Not used; always zero.
49 rpc x x x
50 rpc_stat.rpccnt             The number of RPC calls.
51 rpc_stat.rpcretrans         The number of retransmitted RPC calls.
52 rpc_stat.rpcauthrefresh     The number of credential refreshes.
54 proc2 x x x...
55 proc3 x x x...
57 Procedure   NFS Version NFS Version 3
58 Number      Procedures  Procedures
60 0           null        null
61 1           getattr     getattr
62 2           setattr     setattr
63 3           root        lookup
64 4           lookup      access
65 5           readlink    readlink
66 6           read        read
67 7           wrcache     write
68 8           write       create
69 9           create      mkdir
70 10          remove      symlink
71 11          rename      mknod
72 12          link        remove
73 13          symlink     rmdir
74 14          mkdir       rename
75 15          rmdir       link
76 16          readdir     readdir
77 17          fsstat      readdirplus
78 18                      fsstat
79 19                      fsinfo
80 20                      pathconf
81 21                      commit
82 */
84 static char *nfs2_procedures_ds_def[] =
85 {
86         "DS:null:COUNTER:"COLLECTD_HEARTBEAT":0:U",
87         "DS:getattr:COUNTER:"COLLECTD_HEARTBEAT":0:U",
88         "DS:setattr:COUNTER:"COLLECTD_HEARTBEAT":0:U",
89         "DS:root:COUNTER:"COLLECTD_HEARTBEAT":0:U",
90         "DS:lookup:COUNTER:"COLLECTD_HEARTBEAT":0:U",
91         "DS:readlink:COUNTER:"COLLECTD_HEARTBEAT":0:U",
92         "DS:read:COUNTER:"COLLECTD_HEARTBEAT":0:U",
93         "DS:wrcache:COUNTER:"COLLECTD_HEARTBEAT":0:U",
94         "DS:write:COUNTER:"COLLECTD_HEARTBEAT":0:U",
95         "DS:create:COUNTER:"COLLECTD_HEARTBEAT":0:U",
96         "DS:remove:COUNTER:"COLLECTD_HEARTBEAT":0:U",
97         "DS:rename:COUNTER:"COLLECTD_HEARTBEAT":0:U",
98         "DS:link:COUNTER:"COLLECTD_HEARTBEAT":0:U",
99         "DS:symlink:COUNTER:"COLLECTD_HEARTBEAT":0:U",
100         "DS:mkdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
101         "DS:rmdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
102         "DS:readdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
103         "DS:fsstat:COUNTER:"COLLECTD_HEARTBEAT":0:U",
104         NULL
105 };
106 static int nfs2_procedures_ds_num = 18;
108 static char *nfs3_procedures_ds_def[] =
110         "DS:null:COUNTER:"COLLECTD_HEARTBEAT":0:U",
111         "DS:getattr:COUNTER:"COLLECTD_HEARTBEAT":0:U",
112         "DS:setattr:COUNTER:"COLLECTD_HEARTBEAT":0:U",
113         "DS:lookup:COUNTER:"COLLECTD_HEARTBEAT":0:U",
114         "DS:access:COUNTER:"COLLECTD_HEARTBEAT":0:U",
115         "DS:readlink:COUNTER:"COLLECTD_HEARTBEAT":0:U",
116         "DS:read:COUNTER:"COLLECTD_HEARTBEAT":0:U",
117         "DS:write:COUNTER:"COLLECTD_HEARTBEAT":0:U",
118         "DS:create:COUNTER:"COLLECTD_HEARTBEAT":0:U",
119         "DS:mkdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
120         "DS:symlink:COUNTER:"COLLECTD_HEARTBEAT":0:U",
121         "DS:mknod:COUNTER:"COLLECTD_HEARTBEAT":0:U",
122         "DS:remove:COUNTER:"COLLECTD_HEARTBEAT":0:U",
123         "DS:rmdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
124         "DS:rename:COUNTER:"COLLECTD_HEARTBEAT":0:U",
125         "DS:link:COUNTER:"COLLECTD_HEARTBEAT":0:U",
126         "DS:readdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
127         "DS:readdirplus:COUNTER:"COLLECTD_HEARTBEAT":0:U",
128         "DS:fsstat:COUNTER:"COLLECTD_HEARTBEAT":0:U",
129         "DS:fsinfo:COUNTER:"COLLECTD_HEARTBEAT":0:U",
130         "DS:pathconf:COUNTER:"COLLECTD_HEARTBEAT":0:U",
131         "DS:commit:COUNTER:"COLLECTD_HEARTBEAT":0:U",
132         NULL
133 };
134 static int nfs3_procedures_ds_num = 22;
136 #ifdef HAVE_LIBKSTAT
137 extern kstat_ctl_t *kc;
138 static kstat_t *nfs2_ksp_client;
139 static kstat_t *nfs2_ksp_server;
140 static kstat_t *nfs3_ksp_client;
141 static kstat_t *nfs3_ksp_server;
142 static kstat_t *nfs4_ksp_client;
143 static kstat_t *nfs4_ksp_server;
144 #endif
146 /* Possibly TODO: NFSv4 statistics */
148 static void nfs_init (void)
150 #ifdef HAVE_LIBKSTAT
151         kstat_t *ksp_chain;
153         nfs2_ksp_client = NULL;
154         nfs2_ksp_server = NULL;
155         nfs3_ksp_client = NULL;
156         nfs3_ksp_server = NULL;
157         nfs4_ksp_client = NULL;
158         nfs4_ksp_server = NULL;
159         
160         if (kc == NULL)
161                 return;
163         for (ksp_chain = kc->kc_chain; ksp_chain != NULL;
164                         ksp_chain = ksp_chain->ks_next)
165         {
166                 if (strncmp (ksp_chain->ks_module, "nfs", 3) != 0)
167                         continue;
168                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v2", 13) == 0)
169                         nfs2_ksp_server = ksp_chain;
170                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v3", 13) == 0)
171                         nfs3_ksp_server = ksp_chain;
172                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v4", 13) == 0)
173                         nfs4_ksp_server = ksp_chain;
174                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v2", 12) == 0)
175                         nfs2_ksp_client = ksp_chain;
176                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v3", 12) == 0)
177                         nfs3_ksp_client = ksp_chain;
178                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v4", 12) == 0)
179                         nfs4_ksp_client = ksp_chain;
180         }
181 #endif
183         return;
186 #define BUFSIZE 1024
187 static void nfs2_procedures_write (char *host, char *inst, char *val)
189         char filename[BUFSIZE];
191         if (snprintf (filename, BUFSIZE, nfs2_procedures_file, inst) > BUFSIZE)
192                 return;
194         rrd_update_file (host, filename, val, nfs2_procedures_ds_def,
195                         nfs2_procedures_ds_num);
198 static void nfs3_procedures_write (char *host, char *inst, char *val)
200         char filename[BUFSIZE];
202         if (snprintf (filename, BUFSIZE, nfs3_procedures_file, inst) > BUFSIZE)
203                 return;
205         rrd_update_file (host, filename, val, nfs3_procedures_ds_def,
206                         nfs3_procedures_ds_num);
209 #if NFS_HAVE_READ
210 static void nfs2_procedures_submit (unsigned long long *val, char *inst)
212         char buf[BUFSIZE];
213         int retval = 0;
215         retval = snprintf (buf, BUFSIZE, "%u:%llu:%llu:%llu:%llu:%llu:%llu:"
216                         "%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:"
217                         "%llu:%llu:%llu", /* 18x %llu */
218                         (unsigned int) curtime,
219                         val[0], val[1], val[2], val[3], val[4], val[5], val[6],
220                         val[7], val[8], val[9], val[10], val[11], val[12],
221                         val[13], val[14], val[15], val[16], val[17]);
224         if (retval >= BUFSIZE)
225                 return;
226         else if (retval < 0)
227         {
228                 syslog (LOG_ERR, "nfs: snprintf's format failed: %s", strerror (errno));
229                 return;
230         }
232         plugin_submit ("nfs2_procedures", inst, buf);
235 static void nfs3_procedures_submit (unsigned long long *val, char *inst)
237         char buf[BUFSIZE];
238         int retval = 0;
240         retval = snprintf(buf, BUFSIZE, "%u:%llu:%llu:%llu:%llu:%llu:%llu:"
241                         "%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:"
242                         "%llu:%llu:%llu:%llu:%llu:%llu:%llu", /* 22x %llu */
243                         (unsigned int) curtime,
244                         val[0], val[1], val[2], val[3], val[4], val[5], val[6],
245                         val[7], val[8], val[9], val[10], val[11], val[12],
246                         val[13], val[14], val[15], val[16], val[17], val[18],
247                         val[19], val[20], val[21]);
249         if (retval >= BUFSIZE)
250                 return;
251         else if (retval < 0)
252         {
253                 syslog (LOG_ERR, "nfs: snprintf's format failed: %s", strerror (errno));
254                 return;
255         }
257         plugin_submit("nfs3_procedures", inst, buf);
259 #endif /* NFS_HAVE_READ */
261 #if defined(KERNEL_LINUX)
262 static void nfs_read_stats_file (FILE *fh, char *inst)
264         char buffer[BUFSIZE];
266         char *fields[48];
267         int numfields = 0;
269         if (fh == NULL)
270                 return;
272         while (fgets (buffer, BUFSIZE, fh) != NULL)
273         {
274                 numfields = strsplit (buffer, fields, 48);
276                 if (numfields < 2)
277                         continue;
279                 if (strncmp (fields[0], "proc2", 5) == 0)
280                 {
281                         int i;
282                         unsigned long long *values;
284                         if (numfields - 2 != nfs2_procedures_ds_num)
285                         {
286                                 syslog (LOG_WARNING, "nfs: Wrong number of fields (= %i) for NFS2 statistics.", numfields - 2);
287                                 continue;
288                         }
290                         if ((values = (unsigned long long *) malloc (nfs2_procedures_ds_num * sizeof (unsigned long long))) == NULL)
291                         {
292                                 syslog (LOG_ERR, "nfs: malloc: %s", strerror (errno));
293                                 continue;
294                         }
296                         for (i = 0; i < nfs2_procedures_ds_num; i++)
297                                 values[i] = atoll (fields[i + 2]);
299                         nfs2_procedures_submit (values, inst);
301                         free (values);
302                 }
303                 else if (strncmp (fields[0], "proc3", 5) == 0)
304                 {
305                         int i;
306                         unsigned long long *values;
308                         if (numfields - 2 != nfs3_procedures_ds_num)
309                         {
310                                 syslog (LOG_WARNING, "nfs: Wrong number of fields (= %i) for NFS3 statistics.", numfields - 2);
311                                 continue;
312                         }
314                         if ((values = (unsigned long long *) malloc (nfs3_procedures_ds_num * sizeof (unsigned long long))) == NULL)
315                         {
316                                 syslog (LOG_ERR, "nfs: malloc: %s", strerror (errno));
317                                 continue;
318                         }
320                         for (i = 0; i < nfs3_procedures_ds_num; i++)
321                                 values[i] = atoll (fields[i + 2]);
323                         nfs3_procedures_submit (values, inst);
325                         free (values);
326                 }
327         }
329 #endif /* defined(KERNEL_LINUX) */
330 #undef BUFSIZE
332 #ifdef HAVE_LIBKSTAT
333 static void nfs2_read_kstat (kstat_t *ksp, char *inst)
335         unsigned long long values[18];
337         values[0] = get_kstat_value (ksp, "null");
338         values[1] = get_kstat_value (ksp, "getattr");
339         values[2] = get_kstat_value (ksp, "setattr");
340         values[3] = get_kstat_value (ksp, "root");
341         values[4] = get_kstat_value (ksp, "lookup");
342         values[5] = get_kstat_value (ksp, "readlink");
343         values[6] = get_kstat_value (ksp, "read");
344         values[7] = get_kstat_value (ksp, "wrcache");
345         values[8] = get_kstat_value (ksp, "write");
346         values[9] = get_kstat_value (ksp, "create");
347         values[10] = get_kstat_value (ksp, "remove");
348         values[11] = get_kstat_value (ksp, "rename");
349         values[12] = get_kstat_value (ksp, "link");
350         values[13] = get_kstat_value (ksp, "symlink");
351         values[14] = get_kstat_value (ksp, "mkdir");
352         values[15] = get_kstat_value (ksp, "rmdir");
353         values[16] = get_kstat_value (ksp, "readdir");
354         values[17] = get_kstat_value (ksp, "statfs");
356         nfs2_procedures_submit (values, inst);
358 #endif
360 #if NFS_HAVE_READ
361 static void nfs_read (void)
363 #if defined(KERNEL_LINUX)
364         FILE *fh;
366         if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
367         {
368                 nfs_read_stats_file (fh, "client");
369                 fclose (fh);
370         }
372         if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
373         {
374                 nfs_read_stats_file (fh, "server");
375                 fclose (fh);
376         }
378 /* #endif defined(KERNEL_LINUX) */
380 #elif defined(HAVE_LIBKSTAT)
381         if (nfs2_ksp_client != NULL)
382                 nfs2_read_kstat (nfs2_ksp_client, "client");
383         if (nfs2_ksp_server != NULL)
384                 nfs2_read_kstat (nfs2_ksp_server, "server");
385 #endif /* defined(HAVE_LIBKSTAT) */
387 #else
388 # define nfs_read NULL
389 #endif /* NFS_HAVE_READ */
391 void module_register (void)
393         plugin_register (MODULE_NAME, nfs_init, nfs_read, NULL);
394         plugin_register ("nfs2_procedures", NULL, NULL, nfs2_procedures_write);
395         plugin_register ("nfs3_procedures", NULL, NULL, nfs3_procedures_write);
398 #undef MODULE_NAME