Code

autoconf info page mentions that including config.h has to be done this way.
[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 extern time_t curtime;
146 void nfs_init (void)
148 #ifdef HAVE_LIBKSTAT
149         kstat_t *ksp_chain;
151         nfs2_ksp_client = NULL;
152         nfs2_ksp_server = NULL;
153         nfs3_ksp_client = NULL;
154         nfs3_ksp_server = NULL;
155         nfs4_ksp_client = NULL;
156         nfs4_ksp_server = NULL;
157         
158         if (kc == NULL)
159                 return;
161         for (ksp_chain = kc->kc_chain; ksp_chain != NULL;
162                         ksp_chain = ksp_chain->ks_next)
163         {
164                 if (strncmp (ksp_chain->ks_module, "nfs", 3) != 0)
165                         continue;
166                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v2", 13) == 0)
167                         nfs2_ksp_server = ksp_chain;
168                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v3", 13) == 0)
169                         nfs3_ksp_server = ksp_chain;
170                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v4", 13) == 0)
171                         nfs4_ksp_server = ksp_chain;
172                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v2", 12) == 0)
173                         nfs2_ksp_client = ksp_chain;
174                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v3", 12) == 0)
175                         nfs3_ksp_client = ksp_chain;
176                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v4", 12) == 0)
177                         nfs4_ksp_client = ksp_chain;
178         }
179 #endif
181         return;
184 #define BUFSIZE 1024
185 void nfs2_procedures_write (char *host, char *inst, char *val)
187         char filename[BUFSIZE];
189         if (snprintf (filename, BUFSIZE, nfs2_procedures_file, inst) > BUFSIZE)
190                 return;
192         rrd_update_file (host, filename, val, nfs2_procedures_ds_def,
193                         nfs2_procedures_ds_num);
196 void nfs3_procedures_write (char *host, char *inst, char *val)
198         char filename[BUFSIZE];
200         if (snprintf (filename, BUFSIZE, nfs3_procedures_file, inst) > BUFSIZE)
201                 return;
203         rrd_update_file (host, filename, val, nfs3_procedures_ds_def,
204                         nfs3_procedures_ds_num);
207 void nfs2_procedures_submit (unsigned long long *val, char *inst)
209         char buf[BUFSIZE];
210         int retval = 0;
212         retval = snprintf (buf, BUFSIZE, "%u:%llu:%llu:%llu:%llu:%llu:%llu:"
213                         "%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:"
214                         "%llu:%llu:%llu", /* 18x %llu */
215                         (unsigned int) curtime,
216                         val[0], val[1], val[2], val[3], val[4], val[5], val[6],
217                         val[7], val[8], val[9], val[10], val[11], val[12],
218                         val[13], val[14], val[15], val[16], val[17]);
221         if (retval >= BUFSIZE)
222                 return;
223         else if (retval < 0)
224         {
225                 syslog (LOG_ERR, "nfs: snprintf's format failed: %s", strerror (errno));
226                 return;
227         }
229         plugin_submit ("nfs2_procedures", inst, buf);
232 void nfs3_procedures_submit (unsigned long long *val, char *inst)
234         char buf[BUFSIZE];
235         int retval = 0;
237         retval = snprintf(buf, BUFSIZE, "%u:%llu:%llu:%llu:%llu:%llu:%llu:"
238                         "%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:"
239                         "%llu:%llu:%llu:%llu:%llu:%llu:%llu", /* 22x %llu */
240                         (unsigned int) curtime,
241                         val[0], val[1], val[2], val[3], val[4], val[5], val[6],
242                         val[7], val[8], val[9], val[10], val[11], val[12],
243                         val[13], val[14], val[15], val[16], val[17], val[18],
244                         val[19], val[20], val[21]);
246         if (retval >= BUFSIZE)
247                 return;
248         else if (retval < 0)
249         {
250                 syslog (LOG_ERR, "nfs: snprintf's format failed: %s", strerror (errno));
251                 return;
252         }
254         plugin_submit("nfs3_procedures", inst, buf);
257 #if defined(KERNEL_LINUX)
258 void nfs_read_stats_file (FILE *fh, char *inst)
260         char buffer[BUFSIZE];
262         char *fields[48];
263         int numfields = 0;
265         if (fh == NULL)
266                 return;
268         while (fgets (buffer, BUFSIZE, fh) != NULL)
269         {
270                 numfields = strsplit (buffer, fields, 48);
272                 if (numfields < 2)
273                         continue;
275                 if (strncmp (fields[0], "proc2", 5) == 0)
276                 {
277                         int i;
278                         unsigned long long *values;
280                         if (numfields - 2 != nfs2_procedures_ds_num)
281                         {
282                                 syslog (LOG_WARNING, "nfs: Wrong number of fields (= %i) for NFS2 statistics.", numfields - 2);
283                                 continue;
284                         }
286                         if ((values = (unsigned long long *) malloc (nfs2_procedures_ds_num * sizeof (unsigned long long))) == NULL)
287                         {
288                                 syslog (LOG_ERR, "nfs: malloc: %s", strerror (errno));
289                                 continue;
290                         }
292                         for (i = 0; i < nfs2_procedures_ds_num; i++)
293                                 values[i] = atoll (fields[i + 2]);
295                         nfs2_procedures_submit (values, inst);
297                         free (values);
298                 }
299                 else if (strncmp (fields[0], "proc3", 5) == 0)
300                 {
301                         int i;
302                         unsigned long long *values;
304                         if (numfields - 2 != nfs3_procedures_ds_num)
305                         {
306                                 syslog (LOG_WARNING, "nfs: Wrong number of fields (= %i) for NFS3 statistics.", numfields - 2);
307                                 continue;
308                         }
310                         if ((values = (unsigned long long *) malloc (nfs3_procedures_ds_num * sizeof (unsigned long long))) == NULL)
311                         {
312                                 syslog (LOG_ERR, "nfs: malloc: %s", strerror (errno));
313                                 continue;
314                         }
316                         for (i = 0; i < nfs3_procedures_ds_num; i++)
317                                 values[i] = atoll (fields[i + 2]);
319                         nfs3_procedures_submit (values, inst);
321                         free (values);
322                 }
323         }
325 #endif /* defined(KERNEL_LINUX) */
326 #undef BUFSIZE
328 #ifdef HAVE_LIBKSTAT
329 void nfs2_read_kstat (kstat_t *ksp, char *inst)
331         unsigned long long values[18];
333         values[0] = get_kstat_value (ksp, "null");
334         values[1] = get_kstat_value (ksp, "getattr");
335         values[2] = get_kstat_value (ksp, "setattr");
336         values[3] = get_kstat_value (ksp, "root");
337         values[4] = get_kstat_value (ksp, "lookup");
338         values[5] = get_kstat_value (ksp, "readlink");
339         values[6] = get_kstat_value (ksp, "read");
340         values[7] = get_kstat_value (ksp, "wrcache");
341         values[8] = get_kstat_value (ksp, "write");
342         values[9] = get_kstat_value (ksp, "create");
343         values[10] = get_kstat_value (ksp, "remove");
344         values[11] = get_kstat_value (ksp, "rename");
345         values[12] = get_kstat_value (ksp, "link");
346         values[13] = get_kstat_value (ksp, "symlink");
347         values[14] = get_kstat_value (ksp, "mkdir");
348         values[15] = get_kstat_value (ksp, "rmdir");
349         values[16] = get_kstat_value (ksp, "readdir");
350         values[17] = get_kstat_value (ksp, "statfs");
352         nfs2_procedures_submit (values, inst);
354 #endif
356 void nfs_read (void)
358 #if defined(KERNEL_LINUX)
359         FILE *fh;
361         if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
362         {
363                 nfs_read_stats_file (fh, "client");
364                 fclose (fh);
365         }
367         if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
368         {
369                 nfs_read_stats_file (fh, "server");
370                 fclose (fh);
371         }
373 /* #endif defined(KERNEL_LINUX) */
375 #elif defined(HAVE_LIBKSTAT)
376         if (nfs2_ksp_client != NULL)
377                 nfs2_read_kstat (nfs2_ksp_client, "client");
378         if (nfs2_ksp_server != NULL)
379                 nfs2_read_kstat (nfs2_ksp_server, "server");
380 #endif /* defined(HAVE_LIBKSTAT) */
383 void module_register (void)
385     plugin_register (MODULE_NAME, nfs_init, nfs_read, NULL);
386     plugin_register ("nfs2_procedures", NULL, NULL, nfs2_procedures_write);
387     plugin_register ("nfs3_procedures", NULL, NULL, nfs3_procedures_write);
390 #undef MODULE_NAME
391 #endif /* COLLECT_LOAD */