Code

3321630ae991ab6dc9427865eccd3bb9b92eb3ca
[collectd.git] / src / nfs.c
1 /**
2  * collectd - src/nfs.c
3  * Copyright (C) 2005  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 "nfs.h"
26 #if COLLECT_NFS
27 #define MODULE_NAME "nfs"
29 #include "plugin.h"
30 #include "common.h"
32 static char *nfs2_procedures_file  = "nfs2_procedures-%s.rrd";
33 static char *nfs3_procedures_file  = "nfs3_procedures-%s.rrd";
35 /*
36 see /proc/net/rpc/nfs
37 see http://www.missioncriticallinux.com/orph/NFS-Statistics
39 net x x x x
40 rpc_stat.netcnt         Not used; always zero.
41 rpc_stat.netudpcnt      Not used; always zero.
42 rpc_stat.nettcpcnt      Not used; always zero.
43 rpc_stat.nettcpconn     Not used; always zero.
45 rpc x x x
46 rpc_stat.rpccnt             The number of RPC calls.
47 rpc_stat.rpcretrans         The number of retransmitted RPC calls.
48 rpc_stat.rpcauthrefresh     The number of credential refreshes.
50 proc2 x x x...
51 proc3 x x x...
53 Procedure   NFS Version NFS Version 3
54 Number      Procedures  Procedures
56 0           null        null
57 1           getattr     getattr
58 2           setattr     setattr
59 3           root        lookup
60 4           lookup      access
61 5           readlink    readlink
62 6           read        read
63 7           wrcache     write
64 8           write       create
65 9           create      mkdir
66 10          remove      symlink
67 11          rename      mknod
68 12          link        remove
69 13          symlink     rmdir
70 14          mkdir       rename
71 15          rmdir       link
72 16          readdir     readdir
73 17          fsstat      readdirplus
74 18                      fsstat
75 19                      fsinfo
76 20                      pathconf
77 21                      commit
78 */
80 static char *nfs2_procedures_ds_def[] =
81 {
82         "DS:null:COUNTER:25:0:U",
83         "DS:getattr:COUNTER:25:0:U",
84         "DS:setattr:COUNTER:25:0:U",
85         "DS:root:COUNTER:25:0:U",
86         "DS:lookup:COUNTER:25:0:U",
87         "DS:readlink:COUNTER:25:0:U",
88         "DS:read:COUNTER:25:0:U",
89         "DS:wrcache:COUNTER:25:0:U",
90         "DS:write:COUNTER:25:0:U",
91         "DS:create:COUNTER:25:0:U",
92         "DS:remove:COUNTER:25:0:U",
93         "DS:rename:COUNTER:25:0:U",
94         "DS:link:COUNTER:25:0:U",
95         "DS:symlink:COUNTER:25:0:U",
96         "DS:mkdir:COUNTER:25:0:U",
97         "DS:rmdir:COUNTER:25:0:U",
98         "DS:readdir:COUNTER:25:0:U",
99         "DS:fsstat:COUNTER:25:0:U",
100         NULL
101 };
102 static int nfs2_procedures_ds_num = 18;
104 static char *nfs3_procedures_ds_def[] =
106         "DS:null:COUNTER:25:0:U",
107         "DS:getattr:COUNTER:25:0:U",
108         "DS:setattr:COUNTER:25:0:U",
109         "DS:lookup:COUNTER:25:0:U",
110         "DS:access:COUNTER:25:0:U",
111         "DS:readlink:COUNTER:25:0:U",
112         "DS:read:COUNTER:25:0:U",
113         "DS:write:COUNTER:25:0:U",
114         "DS:create:COUNTER:25:0:U",
115         "DS:mkdir:COUNTER:25:0:U",
116         "DS:symlink:COUNTER:25:0:U",
117         "DS:mknod:COUNTER:25:0:U",
118         "DS:remove:COUNTER:25:0:U",
119         "DS:rmdir:COUNTER:25:0:U",
120         "DS:rename:COUNTER:25:0:U",
121         "DS:link:COUNTER:25:0:U",
122         "DS:readdir:COUNTER:25:0:U",
123         "DS:readdirplus:COUNTER:25:0:U",
124         "DS:fsstat:COUNTER:25:0:U",
125         "DS:fsinfo:COUNTER:25:0:U",
126         "DS:pathconf:COUNTER:25:0:U",
127         "DS:commit:COUNTER:25:0:U",
128         NULL
129 };
130 static int nfs3_procedures_ds_num = 22;
132 #ifdef HAVE_LIBKSTAT
133 extern kstat_ctl_t *kc;
134 static kstat_t *nfs2_ksp_client;
135 static kstat_t *nfs2_ksp_server;
136 static kstat_t *nfs3_ksp_client;
137 static kstat_t *nfs3_ksp_server;
138 static kstat_t *nfs4_ksp_client;
139 static kstat_t *nfs4_ksp_server;
140 #endif
142 /* Possibly TODO: NFSv4 statistics */
144 void nfs_init (void)
146 #ifdef HAVE_LIBKSTAT
147         kstat_t *ksp_chain;
149         nfs2_ksp_client = NULL;
150         nfs2_ksp_server = NULL;
151         nfs3_ksp_client = NULL;
152         nfs3_ksp_server = NULL;
153         nfs4_ksp_client = NULL;
154         nfs4_ksp_server = NULL;
155         
156         if (kc == NULL)
157                 return;
159         for (ksp_chain = kc->kc_chain; ksp_chain != NULL;
160                         ksp_chain = ksp_chain->ks_next)
161         {
162                 if (strncmp (ksp_chain->ks_module, "nfs", 3) != 0)
163                         continue;
164                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v2", 13) == 0)
165                         nfs2_ksp_server = ksp_chain;
166                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v3", 13) == 0)
167                         nfs3_ksp_server = ksp_chain;
168                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v4", 13) == 0)
169                         nfs4_ksp_server = ksp_chain;
170                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v2", 12) == 0)
171                         nfs2_ksp_client = ksp_chain;
172                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v3", 12) == 0)
173                         nfs3_ksp_client = ksp_chain;
174                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v4", 12) == 0)
175                         nfs4_ksp_client = ksp_chain;
176         }
177 #endif
179         return;
182 #define BUFSIZE 1024
183 void nfs2_procedures_write (char *host, char *inst, char *val)
185         char filename[BUFSIZE];
187         if (snprintf (filename, BUFSIZE, nfs2_procedures_file, inst) > BUFSIZE)
188                 return;
190         rrd_update_file (host, filename, val, nfs2_procedures_ds_def,
191                         nfs2_procedures_ds_num);
194 void nfs3_procedures_write (char *host, char *inst, char *val)
196         char filename[BUFSIZE];
198         if (snprintf (filename, BUFSIZE, nfs3_procedures_file, inst) > BUFSIZE)
199                 return;
201         rrd_update_file (host, filename, val, nfs3_procedures_ds_def,
202                         nfs3_procedures_ds_num);
205 void nfs2_procedures_submit (unsigned long long *val, char *inst)
207         char buf[BUFSIZE];
208         int retval = 0;
210         retval = snprintf (buf, BUFSIZE, "%u:%llu:%llu:%llu:%llu:%llu:%llu:"
211                         "%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:"
212                         "%llu:%llu:%llu", /* 18x %llu */
213                         (unsigned int) curtime,
214                         val[0], val[1], val[2], val[3], val[4], val[5], val[6],
215                         val[7], val[8], val[9], val[10], val[11], val[12],
216                         val[13], val[14], val[15], val[16], val[17]);
219         if (retval >= BUFSIZE)
220                 return;
221         else if (retval < 0)
222         {
223                 syslog (LOG_ERR, "nfs: snprintf's format failed: %s", strerror (errno));
224                 return;
225         }
227         plugin_submit ("nfs2_procedures", inst, buf);
230 void nfs3_procedures_submit (unsigned long long *val, char *inst)
232         char buf[BUFSIZE];
233         int retval = 0;
235         retval = snprintf(buf, BUFSIZE, "%u:%llu:%llu:%llu:%llu:%llu:%llu:"
236                         "%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:"
237                         "%llu:%llu:%llu:%llu:%llu:%llu:%llu", /* 22x %llu */
238                         (unsigned int) curtime,
239                         val[0], val[1], val[2], val[3], val[4], val[5], val[6],
240                         val[7], val[8], val[9], val[10], val[11], val[12],
241                         val[13], val[14], val[15], val[16], val[17], val[18],
242                         val[19], val[20], val[21]);
244         if (retval >= BUFSIZE)
245                 return;
246         else if (retval < 0)
247         {
248                 syslog (LOG_ERR, "nfs: snprintf's format failed: %s", strerror (errno));
249                 return;
250         }
252         plugin_submit("nfs3_procedures", inst, buf);
255 #if defined(KERNEL_LINUX)
256 void nfs_read_stats_file (FILE *fh, char *inst)
258         char buffer[BUFSIZE];
260         char *fields[48];
261         int numfields = 0;
263         if (fh == NULL)
264                 return;
266         while (fgets (buffer, BUFSIZE, fh) != NULL)
267         {
268                 numfields = strsplit (buffer, fields, 48);
270                 if (numfields < 2)
271                         continue;
273                 if (strncmp (fields[0], "proc2", 5) == 0)
274                 {
275                         int i;
276                         unsigned long long *values;
278                         if (numfields - 2 != nfs2_procedures_ds_num)
279                         {
280                                 syslog (LOG_WARNING, "nfs: Wrong number of fields (= %i) for NFS2 statistics.", numfields - 2);
281                                 continue;
282                         }
284                         if ((values = (unsigned long long *) malloc (nfs2_procedures_ds_num * sizeof (unsigned long long))) == NULL)
285                         {
286                                 syslog (LOG_ERR, "nfs: malloc: %s", strerror (errno));
287                                 continue;
288                         }
290                         for (i = 0; i < nfs2_procedures_ds_num; i++)
291                                 values[i] = atoll (fields[i + 2]);
293                         nfs2_procedures_submit (values, inst);
295                         free (values);
296                 }
297                 else if (strncmp (fields[0], "proc3", 5) == 0)
298                 {
299                         int i;
300                         unsigned long long *values;
302                         if (numfields - 2 != nfs3_procedures_ds_num)
303                         {
304                                 syslog (LOG_WARNING, "nfs: Wrong number of fields (= %i) for NFS3 statistics.", numfields - 2);
305                                 continue;
306                         }
308                         if ((values = (unsigned long long *) malloc (nfs3_procedures_ds_num * sizeof (unsigned long long))) == NULL)
309                         {
310                                 syslog (LOG_ERR, "nfs: malloc: %s", strerror (errno));
311                                 continue;
312                         }
314                         for (i = 0; i < nfs3_procedures_ds_num; i++)
315                                 values[i] = atoll (fields[i + 2]);
317                         nfs3_procedures_submit (values, inst);
319                         free (values);
320                 }
321         }
323 #endif /* defined(KERNEL_LINUX) */
324 #undef BUFSIZE
326 #ifdef HAVE_LIBKSTAT
327 void nfs2_read_kstat (kstat_t *ksp, char *inst)
329         unsigned long long values[18];
331         values[0] = get_kstat_value (ksp, "null");
332         values[1] = get_kstat_value (ksp, "getattr");
333         values[2] = get_kstat_value (ksp, "setattr");
334         values[3] = get_kstat_value (ksp, "root");
335         values[4] = get_kstat_value (ksp, "lookup");
336         values[5] = get_kstat_value (ksp, "readlink");
337         values[6] = get_kstat_value (ksp, "read");
338         values[7] = get_kstat_value (ksp, "wrcache");
339         values[8] = get_kstat_value (ksp, "write");
340         values[9] = get_kstat_value (ksp, "create");
341         values[10] = get_kstat_value (ksp, "remove");
342         values[11] = get_kstat_value (ksp, "rename");
343         values[12] = get_kstat_value (ksp, "link");
344         values[13] = get_kstat_value (ksp, "symlink");
345         values[14] = get_kstat_value (ksp, "mkdir");
346         values[15] = get_kstat_value (ksp, "rmdir");
347         values[16] = get_kstat_value (ksp, "readdir");
348         values[17] = get_kstat_value (ksp, "statfs");
350         nfs2_procedures_submit (values, inst);
352 #endif
354 void nfs_read (void)
356 #if defined(KERNEL_LINUX)
357         FILE *fh;
359         if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
360         {
361                 nfs_read_stats_file (fh, "client");
362                 fclose (fh);
363         }
365         if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
366         {
367                 nfs_read_stats_file (fh, "server");
368                 fclose (fh);
369         }
371 /* #endif defined(KERNEL_LINUX) */
373 #elif defined(HAVE_LIBKSTAT)
374         if (nfs2_ksp_client != NULL)
375                 nfs2_read_kstat (nfs2_ksp_client, "client");
376         if (nfs2_ksp_server != NULL)
377                 nfs2_read_kstat (nfs2_ksp_server, "server");
378 #endif /* defined(HAVE_LIBKSTAT) */
381 void module_register (void)
383     plugin_register (MODULE_NAME, nfs_init, nfs_read, NULL);
384     plugin_register ("nfs2_procedures", NULL, NULL, nfs2_procedures_write);
385     plugin_register ("nfs3_procedures", NULL, NULL, nfs3_procedures_write);
388 #undef MODULE_NAME
389 #endif /* COLLECT_LOAD */