Code

Cleaned up all the modules, unified define order and the like..
[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 "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:25:0:U",
87         "DS:getattr:COUNTER:25:0:U",
88         "DS:setattr:COUNTER:25:0:U",
89         "DS:root:COUNTER:25:0:U",
90         "DS:lookup:COUNTER:25:0:U",
91         "DS:readlink:COUNTER:25:0:U",
92         "DS:read:COUNTER:25:0:U",
93         "DS:wrcache:COUNTER:25:0:U",
94         "DS:write:COUNTER:25:0:U",
95         "DS:create:COUNTER:25:0:U",
96         "DS:remove:COUNTER:25:0:U",
97         "DS:rename:COUNTER:25:0:U",
98         "DS:link:COUNTER:25:0:U",
99         "DS:symlink:COUNTER:25:0:U",
100         "DS:mkdir:COUNTER:25:0:U",
101         "DS:rmdir:COUNTER:25:0:U",
102         "DS:readdir:COUNTER:25:0:U",
103         "DS:fsstat:COUNTER:25:0:U",
104         NULL
105 };
106 static int nfs2_procedures_ds_num = 18;
108 static char *nfs3_procedures_ds_def[] =
110         "DS:null:COUNTER:25:0:U",
111         "DS:getattr:COUNTER:25:0:U",
112         "DS:setattr:COUNTER:25:0:U",
113         "DS:lookup:COUNTER:25:0:U",
114         "DS:access:COUNTER:25:0:U",
115         "DS:readlink:COUNTER:25:0:U",
116         "DS:read:COUNTER:25:0:U",
117         "DS:write:COUNTER:25:0:U",
118         "DS:create:COUNTER:25:0:U",
119         "DS:mkdir:COUNTER:25:0:U",
120         "DS:symlink:COUNTER:25:0:U",
121         "DS:mknod:COUNTER:25:0:U",
122         "DS:remove:COUNTER:25:0:U",
123         "DS:rmdir:COUNTER:25:0:U",
124         "DS:rename:COUNTER:25:0:U",
125         "DS:link:COUNTER:25:0:U",
126         "DS:readdir:COUNTER:25:0:U",
127         "DS:readdirplus:COUNTER:25:0:U",
128         "DS:fsstat:COUNTER:25:0:U",
129         "DS:fsinfo:COUNTER:25:0:U",
130         "DS:pathconf:COUNTER:25:0:U",
131         "DS:commit:COUNTER:25: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 static void nfs2_procedures_submit (unsigned long long *val, char *inst)
211         char buf[BUFSIZE];
212         int retval = 0;
214         retval = snprintf (buf, BUFSIZE, "%u:%llu:%llu:%llu:%llu:%llu:%llu:"
215                         "%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:"
216                         "%llu:%llu:%llu", /* 18x %llu */
217                         (unsigned int) curtime,
218                         val[0], val[1], val[2], val[3], val[4], val[5], val[6],
219                         val[7], val[8], val[9], val[10], val[11], val[12],
220                         val[13], val[14], val[15], val[16], val[17]);
223         if (retval >= BUFSIZE)
224                 return;
225         else if (retval < 0)
226         {
227                 syslog (LOG_ERR, "nfs: snprintf's format failed: %s", strerror (errno));
228                 return;
229         }
231         plugin_submit ("nfs2_procedures", inst, buf);
234 static void nfs3_procedures_submit (unsigned long long *val, char *inst)
236         char buf[BUFSIZE];
237         int retval = 0;
239         retval = snprintf(buf, BUFSIZE, "%u:%llu:%llu:%llu:%llu:%llu:%llu:"
240                         "%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:%llu:"
241                         "%llu:%llu:%llu:%llu:%llu:%llu:%llu", /* 22x %llu */
242                         (unsigned int) curtime,
243                         val[0], val[1], val[2], val[3], val[4], val[5], val[6],
244                         val[7], val[8], val[9], val[10], val[11], val[12],
245                         val[13], val[14], val[15], val[16], val[17], val[18],
246                         val[19], val[20], val[21]);
248         if (retval >= BUFSIZE)
249                 return;
250         else if (retval < 0)
251         {
252                 syslog (LOG_ERR, "nfs: snprintf's format failed: %s", strerror (errno));
253                 return;
254         }
256         plugin_submit("nfs3_procedures", inst, buf);
259 #if defined(KERNEL_LINUX)
260 static void nfs_read_stats_file (FILE *fh, char *inst)
262         char buffer[BUFSIZE];
264         char *fields[48];
265         int numfields = 0;
267         if (fh == NULL)
268                 return;
270         while (fgets (buffer, BUFSIZE, fh) != NULL)
271         {
272                 numfields = strsplit (buffer, fields, 48);
274                 if (numfields < 2)
275                         continue;
277                 if (strncmp (fields[0], "proc2", 5) == 0)
278                 {
279                         int i;
280                         unsigned long long *values;
282                         if (numfields - 2 != nfs2_procedures_ds_num)
283                         {
284                                 syslog (LOG_WARNING, "nfs: Wrong number of fields (= %i) for NFS2 statistics.", numfields - 2);
285                                 continue;
286                         }
288                         if ((values = (unsigned long long *) malloc (nfs2_procedures_ds_num * sizeof (unsigned long long))) == NULL)
289                         {
290                                 syslog (LOG_ERR, "nfs: malloc: %s", strerror (errno));
291                                 continue;
292                         }
294                         for (i = 0; i < nfs2_procedures_ds_num; i++)
295                                 values[i] = atoll (fields[i + 2]);
297                         nfs2_procedures_submit (values, inst);
299                         free (values);
300                 }
301                 else if (strncmp (fields[0], "proc3", 5) == 0)
302                 {
303                         int i;
304                         unsigned long long *values;
306                         if (numfields - 2 != nfs3_procedures_ds_num)
307                         {
308                                 syslog (LOG_WARNING, "nfs: Wrong number of fields (= %i) for NFS3 statistics.", numfields - 2);
309                                 continue;
310                         }
312                         if ((values = (unsigned long long *) malloc (nfs3_procedures_ds_num * sizeof (unsigned long long))) == NULL)
313                         {
314                                 syslog (LOG_ERR, "nfs: malloc: %s", strerror (errno));
315                                 continue;
316                         }
318                         for (i = 0; i < nfs3_procedures_ds_num; i++)
319                                 values[i] = atoll (fields[i + 2]);
321                         nfs3_procedures_submit (values, inst);
323                         free (values);
324                 }
325         }
327 #endif /* defined(KERNEL_LINUX) */
328 #undef BUFSIZE
330 #ifdef HAVE_LIBKSTAT
331 static void nfs2_read_kstat (kstat_t *ksp, char *inst)
333         unsigned long long values[18];
335         values[0] = get_kstat_value (ksp, "null");
336         values[1] = get_kstat_value (ksp, "getattr");
337         values[2] = get_kstat_value (ksp, "setattr");
338         values[3] = get_kstat_value (ksp, "root");
339         values[4] = get_kstat_value (ksp, "lookup");
340         values[5] = get_kstat_value (ksp, "readlink");
341         values[6] = get_kstat_value (ksp, "read");
342         values[7] = get_kstat_value (ksp, "wrcache");
343         values[8] = get_kstat_value (ksp, "write");
344         values[9] = get_kstat_value (ksp, "create");
345         values[10] = get_kstat_value (ksp, "remove");
346         values[11] = get_kstat_value (ksp, "rename");
347         values[12] = get_kstat_value (ksp, "link");
348         values[13] = get_kstat_value (ksp, "symlink");
349         values[14] = get_kstat_value (ksp, "mkdir");
350         values[15] = get_kstat_value (ksp, "rmdir");
351         values[16] = get_kstat_value (ksp, "readdir");
352         values[17] = get_kstat_value (ksp, "statfs");
354         nfs2_procedures_submit (values, inst);
356 #endif
358 #if NFS_HAVE_READ
359 static void nfs_read (void)
361 #if defined(KERNEL_LINUX)
362         FILE *fh;
364         if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
365         {
366                 nfs_read_stats_file (fh, "client");
367                 fclose (fh);
368         }
370         if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
371         {
372                 nfs_read_stats_file (fh, "server");
373                 fclose (fh);
374         }
376 /* #endif defined(KERNEL_LINUX) */
378 #elif defined(HAVE_LIBKSTAT)
379         if (nfs2_ksp_client != NULL)
380                 nfs2_read_kstat (nfs2_ksp_client, "client");
381         if (nfs2_ksp_server != NULL)
382                 nfs2_read_kstat (nfs2_ksp_server, "server");
383 #endif /* defined(HAVE_LIBKSTAT) */
385 #else
386 # define nfs_read NULL
387 #endif /* NFS_HAVE_READ */
389 void module_register (void)
391         plugin_register (MODULE_NAME, nfs_init, nfs_read, NULL);
392         plugin_register ("nfs2_procedures", NULL, NULL, nfs2_procedures_write);
393         plugin_register ("nfs3_procedures", NULL, NULL, nfs3_procedures_write);
396 #undef MODULE_NAME