Code

ntpd branch: Changed the RRD files of the NTPd plugin to store seconds rather than...
[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 #if KERNEL_LINUX
32 # define NFS_HAVE_READ 1
33 #else
34 # define NFS_HAVE_READ 0
35 #endif
37 static char *nfs2_procedures_file  = "nfs2_procedures-%s.rrd";
38 static char *nfs3_procedures_file  = "nfs3_procedures-%s.rrd";
40 /*
41 see /proc/net/rpc/nfs
42 see http://www.missioncriticallinux.com/orph/NFS-Statistics
44 net x x x x
45 rpc_stat.netcnt         Not used; always zero.
46 rpc_stat.netudpcnt      Not used; always zero.
47 rpc_stat.nettcpcnt      Not used; always zero.
48 rpc_stat.nettcpconn     Not used; always zero.
50 rpc x x x
51 rpc_stat.rpccnt             The number of RPC calls.
52 rpc_stat.rpcretrans         The number of retransmitted RPC calls.
53 rpc_stat.rpcauthrefresh     The number of credential refreshes.
55 proc2 x x x...
56 proc3 x x x...
58 Procedure   NFS Version NFS Version 3
59 Number      Procedures  Procedures
61 0           null        null
62 1           getattr     getattr
63 2           setattr     setattr
64 3           root        lookup
65 4           lookup      access
66 5           readlink    readlink
67 6           read        read
68 7           wrcache     write
69 8           write       create
70 9           create      mkdir
71 10          remove      symlink
72 11          rename      mknod
73 12          link        remove
74 13          symlink     rmdir
75 14          mkdir       rename
76 15          rmdir       link
77 16          readdir     readdir
78 17          fsstat      readdirplus
79 18                      fsstat
80 19                      fsinfo
81 20                      pathconf
82 21                      commit
83 */
85 static char *nfs2_procedures_ds_def[] =
86 {
87         "DS:null:COUNTER:"COLLECTD_HEARTBEAT":0:U",
88         "DS:getattr:COUNTER:"COLLECTD_HEARTBEAT":0:U",
89         "DS:setattr:COUNTER:"COLLECTD_HEARTBEAT":0:U",
90         "DS:root:COUNTER:"COLLECTD_HEARTBEAT":0:U",
91         "DS:lookup:COUNTER:"COLLECTD_HEARTBEAT":0:U",
92         "DS:readlink:COUNTER:"COLLECTD_HEARTBEAT":0:U",
93         "DS:read:COUNTER:"COLLECTD_HEARTBEAT":0:U",
94         "DS:wrcache:COUNTER:"COLLECTD_HEARTBEAT":0:U",
95         "DS:write:COUNTER:"COLLECTD_HEARTBEAT":0:U",
96         "DS:create:COUNTER:"COLLECTD_HEARTBEAT":0:U",
97         "DS:remove:COUNTER:"COLLECTD_HEARTBEAT":0:U",
98         "DS:rename:COUNTER:"COLLECTD_HEARTBEAT":0:U",
99         "DS:link:COUNTER:"COLLECTD_HEARTBEAT":0:U",
100         "DS:symlink:COUNTER:"COLLECTD_HEARTBEAT":0:U",
101         "DS:mkdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
102         "DS:rmdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
103         "DS:readdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
104         "DS:fsstat:COUNTER:"COLLECTD_HEARTBEAT":0:U",
105         NULL
106 };
107 static int nfs2_procedures_ds_num = 18;
109 static char *nfs3_procedures_ds_def[] =
111         "DS:null:COUNTER:"COLLECTD_HEARTBEAT":0:U",
112         "DS:getattr:COUNTER:"COLLECTD_HEARTBEAT":0:U",
113         "DS:setattr:COUNTER:"COLLECTD_HEARTBEAT":0:U",
114         "DS:lookup:COUNTER:"COLLECTD_HEARTBEAT":0:U",
115         "DS:access:COUNTER:"COLLECTD_HEARTBEAT":0:U",
116         "DS:readlink:COUNTER:"COLLECTD_HEARTBEAT":0:U",
117         "DS:read:COUNTER:"COLLECTD_HEARTBEAT":0:U",
118         "DS:write:COUNTER:"COLLECTD_HEARTBEAT":0:U",
119         "DS:create:COUNTER:"COLLECTD_HEARTBEAT":0:U",
120         "DS:mkdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
121         "DS:symlink:COUNTER:"COLLECTD_HEARTBEAT":0:U",
122         "DS:mknod:COUNTER:"COLLECTD_HEARTBEAT":0:U",
123         "DS:remove:COUNTER:"COLLECTD_HEARTBEAT":0:U",
124         "DS:rmdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
125         "DS:rename:COUNTER:"COLLECTD_HEARTBEAT":0:U",
126         "DS:link:COUNTER:"COLLECTD_HEARTBEAT":0:U",
127         "DS:readdir:COUNTER:"COLLECTD_HEARTBEAT":0:U",
128         "DS:readdirplus:COUNTER:"COLLECTD_HEARTBEAT":0:U",
129         "DS:fsstat:COUNTER:"COLLECTD_HEARTBEAT":0:U",
130         "DS:fsinfo:COUNTER:"COLLECTD_HEARTBEAT":0:U",
131         "DS:pathconf:COUNTER:"COLLECTD_HEARTBEAT":0:U",
132         "DS:commit:COUNTER:"COLLECTD_HEARTBEAT":0:U",
133         NULL
134 };
135 static int nfs3_procedures_ds_num = 22;
137 #if HAVE_LIBKSTAT && 0
138 extern kstat_ctl_t *kc;
139 static kstat_t *nfs2_ksp_client;
140 static kstat_t *nfs2_ksp_server;
141 static kstat_t *nfs3_ksp_client;
142 static kstat_t *nfs3_ksp_server;
143 static kstat_t *nfs4_ksp_client;
144 static kstat_t *nfs4_ksp_server;
145 #endif
147 /* Possibly TODO: NFSv4 statistics */
149 static void nfs_init (void)
151 #if HAVE_LIBKSTAT && 0
152         kstat_t *ksp_chain;
154         nfs2_ksp_client = NULL;
155         nfs2_ksp_server = NULL;
156         nfs3_ksp_client = NULL;
157         nfs3_ksp_server = NULL;
158         nfs4_ksp_client = NULL;
159         nfs4_ksp_server = NULL;
160         
161         if (kc == NULL)
162                 return;
164         for (ksp_chain = kc->kc_chain; ksp_chain != NULL;
165                         ksp_chain = ksp_chain->ks_next)
166         {
167                 if (strncmp (ksp_chain->ks_module, "nfs", 3) != 0)
168                         continue;
169                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v2", 13) == 0)
170                         nfs2_ksp_server = ksp_chain;
171                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v3", 13) == 0)
172                         nfs3_ksp_server = ksp_chain;
173                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v4", 13) == 0)
174                         nfs4_ksp_server = ksp_chain;
175                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v2", 12) == 0)
176                         nfs2_ksp_client = ksp_chain;
177                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v3", 12) == 0)
178                         nfs3_ksp_client = ksp_chain;
179                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v4", 12) == 0)
180                         nfs4_ksp_client = ksp_chain;
181         }
182 #endif
184         return;
187 #define BUFSIZE 1024
188 static void nfs2_procedures_write (char *host, char *inst, char *val)
190         char filename[BUFSIZE];
192         if (snprintf (filename, BUFSIZE, nfs2_procedures_file, inst) > BUFSIZE)
193                 return;
195         rrd_update_file (host, filename, val, nfs2_procedures_ds_def,
196                         nfs2_procedures_ds_num);
199 static void nfs3_procedures_write (char *host, char *inst, char *val)
201         char filename[BUFSIZE];
203         if (snprintf (filename, BUFSIZE, nfs3_procedures_file, inst) > BUFSIZE)
204                 return;
206         rrd_update_file (host, filename, val, nfs3_procedures_ds_def,
207                         nfs3_procedures_ds_num);
210 #if NFS_HAVE_READ
211 static void nfs2_procedures_submit (unsigned long long *val, char *inst)
213         char buf[BUFSIZE];
214         int retval = 0;
216         retval = snprintf (buf, BUFSIZE, "%u:%llu:%llu:%llu:%llu:%llu:%llu:"
217                         "%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:"
218                         "%llu:%llu:%llu", /* 18x %llu */
219                         (unsigned int) curtime,
220                         val[0], val[1], val[2], val[3], val[4], val[5], val[6],
221                         val[7], val[8], val[9], val[10], val[11], val[12],
222                         val[13], val[14], val[15], val[16], val[17]);
225         if (retval >= BUFSIZE)
226                 return;
227         else if (retval < 0)
228         {
229                 syslog (LOG_ERR, "nfs: snprintf's format failed: %s", strerror (errno));
230                 return;
231         }
233         plugin_submit ("nfs2_procedures", inst, buf);
236 static void nfs3_procedures_submit (unsigned long long *val, char *inst)
238         char buf[BUFSIZE];
239         int retval = 0;
241         retval = snprintf(buf, BUFSIZE, "%u:%llu:%llu:%llu:%llu:%llu:%llu:"
242                         "%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:"
243                         "%llu:%llu:%llu:%llu:%llu:%llu:%llu", /* 22x %llu */
244                         (unsigned int) curtime,
245                         val[0], val[1], val[2], val[3], val[4], val[5], val[6],
246                         val[7], val[8], val[9], val[10], val[11], val[12],
247                         val[13], val[14], val[15], val[16], val[17], val[18],
248                         val[19], val[20], val[21]);
250         if (retval >= BUFSIZE)
251                 return;
252         else if (retval < 0)
253         {
254                 syslog (LOG_ERR, "nfs: snprintf's format failed: %s", strerror (errno));
255                 return;
256         }
258         plugin_submit("nfs3_procedures", inst, buf);
260 #endif /* NFS_HAVE_READ */
262 #if KERNEL_LINUX
263 static void nfs_read_stats_file (FILE *fh, char *inst)
265         char buffer[BUFSIZE];
267         char *fields[48];
268         int numfields = 0;
270         if (fh == NULL)
271                 return;
273         while (fgets (buffer, BUFSIZE, fh) != NULL)
274         {
275                 numfields = strsplit (buffer, fields, 48);
277                 if (numfields < 2)
278                         continue;
280                 if (strncmp (fields[0], "proc2", 5) == 0)
281                 {
282                         int i;
283                         unsigned long long *values;
285                         if (numfields - 2 != nfs2_procedures_ds_num)
286                         {
287                                 syslog (LOG_WARNING, "nfs: Wrong number of fields (= %i) for NFS2 statistics.", numfields - 2);
288                                 continue;
289                         }
291                         if ((values = (unsigned long long *) malloc (nfs2_procedures_ds_num * sizeof (unsigned long long))) == NULL)
292                         {
293                                 syslog (LOG_ERR, "nfs: malloc: %s", strerror (errno));
294                                 continue;
295                         }
297                         for (i = 0; i < nfs2_procedures_ds_num; i++)
298                                 values[i] = atoll (fields[i + 2]);
300                         nfs2_procedures_submit (values, inst);
302                         free (values);
303                 }
304                 else if (strncmp (fields[0], "proc3", 5) == 0)
305                 {
306                         int i;
307                         unsigned long long *values;
309                         if (numfields - 2 != nfs3_procedures_ds_num)
310                         {
311                                 syslog (LOG_WARNING, "nfs: Wrong number of fields (= %i) for NFS3 statistics.", numfields - 2);
312                                 continue;
313                         }
315                         if ((values = (unsigned long long *) malloc (nfs3_procedures_ds_num * sizeof (unsigned long long))) == NULL)
316                         {
317                                 syslog (LOG_ERR, "nfs: malloc: %s", strerror (errno));
318                                 continue;
319                         }
321                         for (i = 0; i < nfs3_procedures_ds_num; i++)
322                                 values[i] = atoll (fields[i + 2]);
324                         nfs3_procedures_submit (values, inst);
326                         free (values);
327                 }
328         }
330 #endif /* defined(KERNEL_LINUX) */
331 #undef BUFSIZE
333 #if HAVE_LIBKSTAT && 0
334 static void nfs2_read_kstat (kstat_t *ksp, char *inst)
336         unsigned long long values[18];
338         values[0] = get_kstat_value (ksp, "null");
339         values[1] = get_kstat_value (ksp, "getattr");
340         values[2] = get_kstat_value (ksp, "setattr");
341         values[3] = get_kstat_value (ksp, "root");
342         values[4] = get_kstat_value (ksp, "lookup");
343         values[5] = get_kstat_value (ksp, "readlink");
344         values[6] = get_kstat_value (ksp, "read");
345         values[7] = get_kstat_value (ksp, "wrcache");
346         values[8] = get_kstat_value (ksp, "write");
347         values[9] = get_kstat_value (ksp, "create");
348         values[10] = get_kstat_value (ksp, "remove");
349         values[11] = get_kstat_value (ksp, "rename");
350         values[12] = get_kstat_value (ksp, "link");
351         values[13] = get_kstat_value (ksp, "symlink");
352         values[14] = get_kstat_value (ksp, "mkdir");
353         values[15] = get_kstat_value (ksp, "rmdir");
354         values[16] = get_kstat_value (ksp, "readdir");
355         values[17] = get_kstat_value (ksp, "statfs");
357         nfs2_procedures_submit (values, inst);
359 #endif
361 #if NFS_HAVE_READ
362 static void nfs_read (void)
364 #if KERNEL_LINUX
365         FILE *fh;
367         if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
368         {
369                 nfs_read_stats_file (fh, "client");
370                 fclose (fh);
371         }
373         if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
374         {
375                 nfs_read_stats_file (fh, "server");
376                 fclose (fh);
377         }
379 /* #endif defined(KERNEL_LINUX) */
381 #elif HAVE_LIBKSTAT && 0
382         if (nfs2_ksp_client != NULL)
383                 nfs2_read_kstat (nfs2_ksp_client, "client");
384         if (nfs2_ksp_server != NULL)
385                 nfs2_read_kstat (nfs2_ksp_server, "server");
386 #endif /* defined(HAVE_LIBKSTAT) */
388 #else
389 # define nfs_read NULL
390 #endif /* NFS_HAVE_READ */
392 void module_register (void)
394         plugin_register (MODULE_NAME, nfs_init, nfs_read, NULL);
395         plugin_register ("nfs2_procedures", NULL, NULL, nfs2_procedures_write);
396         plugin_register ("nfs3_procedures", NULL, NULL, nfs3_procedures_write);
399 #undef MODULE_NAME