Replace all syslog-calls with one of the new logging-macros.
[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; only version 2 of the License is applicable.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
17  *
18  * Authors:
19  *   Jason Pepas <cell at ices.utexas.edu>
20  *   Florian octo Forster <octo at verplant.org>
21  **/
22
23 #include "collectd.h"
24 #include "common.h"
25 #include "plugin.h"
26
27 #define MODULE_NAME "nfs"
28
29 /* #if defined(KERNEL_LINUX) || defined(HAVE_LIBKSTAT) */
30 #if KERNEL_LINUX
31 # define NFS_HAVE_READ 1
32 #else
33 # define NFS_HAVE_READ 0
34 #endif
35
36 /*
37 see /proc/net/rpc/nfs
38 see http://www.missioncriticallinux.com/orph/NFS-Statistics
39
40 net x x x x
41 rpc_stat.netcnt         Not used; always zero.
42 rpc_stat.netudpcnt      Not used; always zero.
43 rpc_stat.nettcpcnt      Not used; always zero.
44 rpc_stat.nettcpconn     Not used; always zero.
45
46 rpc x x x
47 rpc_stat.rpccnt             The number of RPC calls.
48 rpc_stat.rpcretrans         The number of retransmitted RPC calls.
49 rpc_stat.rpcauthrefresh     The number of credential refreshes.
50
51 proc2 x x x...
52 proc3 x x x...
53
54 Procedure   NFS Version NFS Version 3
55 Number      Procedures  Procedures
56
57 0           null        null
58 1           getattr     getattr
59 2           setattr     setattr
60 3           root        lookup
61 4           lookup      access
62 5           readlink    readlink
63 6           read        read
64 7           wrcache     write
65 8           write       create
66 9           create      mkdir
67 10          remove      symlink
68 11          rename      mknod
69 12          link        remove
70 13          symlink     rmdir
71 14          mkdir       rename
72 15          rmdir       link
73 16          readdir     readdir
74 17          fsstat      readdirplus
75 18                      fsstat
76 19                      fsinfo
77 20                      pathconf
78 21                      commit
79 */
80
81 static data_source_t procedure_dsrc[1] =
82 {
83         {"value", DS_TYPE_COUNTER, 0, 4294967295.0}
84 };
85
86 static data_set_t procedure_ds =
87 {
88         "nfs_procedure", 1, procedure_dsrc
89 };
90
91 #if NFS_HAVE_READ
92 static const char *nfs2_procedures_names[] =
93 {
94         "null",
95         "getattr",
96         "setattr",
97         "root",
98         "lookup",
99         "readlink",
100         "read",
101         "wrcache",
102         "write",
103         "create",
104         "remove",
105         "rename",
106         "link",
107         "symlink",
108         "mkdir",
109         "rmdir",
110         "readdir",
111         "fsstat",
112         NULL
113 };
114 static int nfs2_procedures_names_num = 18;
115
116 static const char *nfs3_procedures_names[] =
117 {
118         "null",
119         "getattr",
120         "setattr",
121         "lookup",
122         "access",
123         "readlink",
124         "read",
125         "write",
126         "create",
127         "mkdir",
128         "symlink",
129         "mknod",
130         "remove",
131         "rmdir",
132         "rename",
133         "link",
134         "readdir",
135         "readdirplus",
136         "fsstat",
137         "fsinfo",
138         "pathconf",
139         "commit",
140         NULL
141 };
142 static int nfs3_procedures_names_num = 22;
143
144 #if HAVE_LIBKSTAT && 0
145 extern kstat_ctl_t *kc;
146 static kstat_t *nfs2_ksp_client;
147 static kstat_t *nfs2_ksp_server;
148 static kstat_t *nfs3_ksp_client;
149 static kstat_t *nfs3_ksp_server;
150 static kstat_t *nfs4_ksp_client;
151 static kstat_t *nfs4_ksp_server;
152 #endif
153
154 /* Possibly TODO: NFSv4 statistics */
155
156 #if 0
157 static int nfs_init (void)
158 {
159 #if HAVE_LIBKSTAT && 0
160         kstat_t *ksp_chain;
161
162         nfs2_ksp_client = NULL;
163         nfs2_ksp_server = NULL;
164         nfs3_ksp_client = NULL;
165         nfs3_ksp_server = NULL;
166         nfs4_ksp_client = NULL;
167         nfs4_ksp_server = NULL;
168         
169         if (kc == NULL)
170                 return;
171
172         for (ksp_chain = kc->kc_chain; ksp_chain != NULL;
173                         ksp_chain = ksp_chain->ks_next)
174         {
175                 if (strncmp (ksp_chain->ks_module, "nfs", 3) != 0)
176                         continue;
177                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v2", 13) == 0)
178                         nfs2_ksp_server = ksp_chain;
179                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v3", 13) == 0)
180                         nfs3_ksp_server = ksp_chain;
181                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v4", 13) == 0)
182                         nfs4_ksp_server = ksp_chain;
183                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v2", 12) == 0)
184                         nfs2_ksp_client = ksp_chain;
185                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v3", 12) == 0)
186                         nfs3_ksp_client = ksp_chain;
187                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v4", 12) == 0)
188                         nfs4_ksp_client = ksp_chain;
189         }
190 #endif
191
192         return (0);
193 } /* int nfs_init */
194 #endif
195
196 #define BUFSIZE 1024
197 static void nfs_procedures_submit (const char *plugin_instance,
198                 unsigned long long *val, const char **names, int len)
199 {
200         value_t values[1];
201         value_list_t vl = VALUE_LIST_INIT;
202         int i;
203
204         vl.values = values;
205         vl.values_len = 1;
206         vl.time = time (NULL);
207         strcpy (vl.host, hostname_g);
208         strcpy (vl.plugin, "nfs");
209         strncpy (vl.plugin_instance, plugin_instance,
210                         sizeof (vl.plugin_instance));
211
212         for (i = 0; i < len; i++)
213         {
214                 values[0].counter = val[i];
215                 strncpy (vl.type_instance, names[i],
216                                 sizeof (vl.type_instance));
217                 DEBUG ("%s-%s/nfs_procedure-%s = %llu",
218                                 vl.plugin, vl.plugin_instance,
219                                 vl.type_instance, val[i]);
220                 plugin_dispatch_values ("nfs_procedure", &vl);
221         }
222 } /* void nfs_procedures_submit */
223
224 #if KERNEL_LINUX
225 static void nfs_read_stats_file (FILE *fh, char *inst)
226 {
227         char buffer[BUFSIZE];
228
229         char plugin_instance[DATA_MAX_NAME_LEN];
230
231         char *fields[48];
232         int numfields = 0;
233
234         if (fh == NULL)
235                 return;
236
237         while (fgets (buffer, BUFSIZE, fh) != NULL)
238         {
239                 numfields = strsplit (buffer, fields, 48);
240
241                 if (((numfields - 2) != nfs2_procedures_names_num)
242                                 && ((numfields - 2)
243                                         != nfs3_procedures_names_num))
244                         continue;
245
246                 if (strcmp (fields[0], "proc2") == 0)
247                 {
248                         int i;
249                         unsigned long long *values;
250
251                         if ((numfields - 2) != nfs2_procedures_names_num)
252                         {
253                                 WARNING ("nfs plugin: Wrong "
254                                                 "number of fields (= %i) "
255                                                 "for NFSv2 statistics.",
256                                                 numfields - 2);
257                                 continue;
258                         }
259
260                         snprintf (plugin_instance, sizeof (plugin_instance),
261                                         "v2%s", inst);
262                         plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
263
264                         values = (unsigned long long *) malloc (nfs2_procedures_names_num * sizeof (unsigned long long));
265                         if (values == NULL)
266                         {
267                                 ERROR ("nfs plugin: malloc "
268                                                 "failed: %s",
269                                                 strerror (errno));
270                                 continue;
271                         }
272
273                         for (i = 0; i < nfs2_procedures_names_num; i++)
274                                 values[i] = atoll (fields[i + 2]);
275
276                         nfs_procedures_submit (plugin_instance, values,
277                                         nfs2_procedures_names,
278                                         nfs2_procedures_names_num);
279
280                         free (values);
281                 }
282                 else if (strncmp (fields[0], "proc3", 5) == 0)
283                 {
284                         int i;
285                         unsigned long long *values;
286
287                         if ((numfields - 2) != nfs3_procedures_names_num)
288                         {
289                                 WARNING ("nfs plugin: Wrong "
290                                                 "number of fields (= %i) "
291                                                 "for NFSv3 statistics.",
292                                                 numfields - 2);
293                                 continue;
294                         }
295
296                         snprintf (plugin_instance, sizeof (plugin_instance),
297                                         "v3%s", inst);
298                         plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
299
300                         values = (unsigned long long *) malloc (nfs3_procedures_names_num * sizeof (unsigned long long));
301                         if (values == NULL)
302                         {
303                                 ERROR ("nfs plugin: malloc "
304                                                 "failed: %s",
305                                                 strerror (errno));
306                                 continue;
307                         }
308
309                         for (i = 0; i < nfs3_procedures_names_num; i++)
310                                 values[i] = atoll (fields[i + 2]);
311
312                         nfs_procedures_submit (plugin_instance, values,
313                                         nfs3_procedures_names,
314                                         nfs3_procedures_names_num);
315
316                         free (values);
317                 }
318         } /* while (fgets (buffer, BUFSIZE, fh) != NULL) */
319 } /* void nfs_read_stats_file */
320 #endif /* defined(KERNEL_LINUX) */
321 #undef BUFSIZE
322
323 #if HAVE_LIBKSTAT && 0
324 static void nfs2_read_kstat (kstat_t *ksp, char *inst)
325 {
326         unsigned long long values[18];
327
328         values[0] = get_kstat_value (ksp, "null");
329         values[1] = get_kstat_value (ksp, "getattr");
330         values[2] = get_kstat_value (ksp, "setattr");
331         values[3] = get_kstat_value (ksp, "root");
332         values[4] = get_kstat_value (ksp, "lookup");
333         values[5] = get_kstat_value (ksp, "readlink");
334         values[6] = get_kstat_value (ksp, "read");
335         values[7] = get_kstat_value (ksp, "wrcache");
336         values[8] = get_kstat_value (ksp, "write");
337         values[9] = get_kstat_value (ksp, "create");
338         values[10] = get_kstat_value (ksp, "remove");
339         values[11] = get_kstat_value (ksp, "rename");
340         values[12] = get_kstat_value (ksp, "link");
341         values[13] = get_kstat_value (ksp, "symlink");
342         values[14] = get_kstat_value (ksp, "mkdir");
343         values[15] = get_kstat_value (ksp, "rmdir");
344         values[16] = get_kstat_value (ksp, "readdir");
345         values[17] = get_kstat_value (ksp, "statfs");
346
347         nfs2_procedures_submit (values, inst);
348 }
349 #endif
350
351 static int nfs_read (void)
352 {
353 #if KERNEL_LINUX
354         FILE *fh;
355
356         if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
357         {
358                 nfs_read_stats_file (fh, "client");
359                 fclose (fh);
360         }
361
362         if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
363         {
364                 nfs_read_stats_file (fh, "server");
365                 fclose (fh);
366         }
367
368 /* #endif defined(KERNEL_LINUX) */
369
370 #elif HAVE_LIBKSTAT && 0
371         if (nfs2_ksp_client != NULL)
372                 nfs2_read_kstat (nfs2_ksp_client, "client");
373         if (nfs2_ksp_server != NULL)
374                 nfs2_read_kstat (nfs2_ksp_server, "server");
375 #endif /* defined(HAVE_LIBKSTAT) */
376
377         return (0);
378 }
379 #endif /* NFS_HAVE_READ */
380
381 void module_register (void)
382 {
383         plugin_register_data_set (&procedure_ds);
384
385 #if NFS_HAVE_READ
386         plugin_register_read ("nfs", nfs_read);
387 #endif
388 }
389
390 #undef MODULE_NAME