Added safe-guard for kstat libraries
[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 #if HAVE_KSTAT_H
28 #include <kstat.h>
29 #endif
30
31 /*
32 see /proc/net/rpc/nfs
33 see http://www.missioncriticallinux.com/orph/NFS-Statistics
34
35 net x x x x
36 rpc_stat.netcnt         Not used; always zero.
37 rpc_stat.netudpcnt      Not used; always zero.
38 rpc_stat.nettcpcnt      Not used; always zero.
39 rpc_stat.nettcpconn     Not used; always zero.
40
41 rpc x x x
42 rpc_stat.rpccnt             The number of RPC calls.
43 rpc_stat.rpcretrans         The number of retransmitted RPC calls.
44 rpc_stat.rpcauthrefresh     The number of credential refreshes.
45
46 proc2 x x x...
47 proc3 x x x...
48
49 Procedure   NFS Version NFS Version 3
50 Number      Procedures  Procedures
51
52 0           null        null
53 1           getattr     getattr
54 2           setattr     setattr
55 3           root        lookup
56 4           lookup      access
57 5           readlink    readlink
58 6           read        read
59 7           wrcache     write
60 8           write       create
61 9           create      mkdir
62 10          remove      symlink
63 11          rename      mknod
64 12          link        remove
65 13          symlink     rmdir
66 14          mkdir       rename
67 15          rmdir       link
68 16          readdir     readdir
69 17          fsstat      readdirplus
70 18                      fsstat
71 19                      fsinfo
72 20                      pathconf
73 21                      commit
74 */
75
76 static const char *nfs2_procedures_names[] =
77 {
78         "null",
79         "getattr",
80         "setattr",
81         "root",
82         "lookup",
83         "readlink",
84         "read",
85         "wrcache",
86         "write",
87         "create",
88         "remove",
89         "rename",
90         "link",
91         "symlink",
92         "mkdir",
93         "rmdir",
94         "readdir",
95         "fsstat",
96         NULL
97 };
98 static int nfs2_procedures_names_num = 18;
99
100 static const char *nfs3_procedures_names[] =
101 {
102         "null",
103         "getattr",
104         "setattr",
105         "lookup",
106         "access",
107         "readlink",
108         "read",
109         "write",
110         "create",
111         "mkdir",
112         "symlink",
113         "mknod",
114         "remove",
115         "rmdir",
116         "rename",
117         "link",
118         "readdir",
119         "readdirplus",
120         "fsstat",
121         "fsinfo",
122         "pathconf",
123         "commit",
124         NULL
125 };
126 static int nfs3_procedures_names_num = 22;
127
128 static const char *nfs4_procedures_names[] =
129 {
130         "null",
131         "compound",
132         "reserved",
133         "access",
134         "close",
135         "commit",
136         "create",
137         "delegpurge",
138         "delegreturn",
139         "getattr",
140         "getfh",
141         "link",
142         "lock",
143         "lockt",
144         "locku",
145         "lookup",
146         "lookupp",
147         "nverify",
148         "open",
149         "openattr",
150         "open_confirm",
151         "open_downgrade",
152         "putfh",
153         "putpubfh",
154         "putrootfh",
155         "read",
156         "readdir",
157         "readlink",
158         "remove",
159         "rename",
160         "renew",
161         "restorefh",
162         "savefh",
163         "secinfo",
164         "setattr",
165         "setclientid",
166         "setclientid_confirm",
167         "verify",
168         "write",
169         NULL
170 };
171 static int nfs4_procedures_names_num = 39;
172
173 #if HAVE_LIBKSTAT
174 extern kstat_ctl_t *kc;
175 static kstat_t *nfs2_ksp_client;
176 static kstat_t *nfs2_ksp_server;
177 static kstat_t *nfs3_ksp_client;
178 static kstat_t *nfs3_ksp_server;
179 static kstat_t *nfs4_ksp_client;
180 static kstat_t *nfs4_ksp_server;
181 #endif
182
183 /* Possibly TODO: NFSv4 statistics */
184
185 #if HAVE_LIBKSTAT
186 static int nfs_init (void)
187 {
188         kstat_t *ksp_chain = NULL;
189
190         nfs2_ksp_client = NULL;
191         nfs2_ksp_server = NULL;
192         nfs3_ksp_client = NULL;
193         nfs3_ksp_server = NULL;
194         nfs4_ksp_client = NULL;
195         nfs4_ksp_server = NULL;
196
197         if (kc == NULL)
198                 return (-1);
199
200         for (ksp_chain = kc->kc_chain; ksp_chain != NULL;
201                         ksp_chain = ksp_chain->ks_next)
202         {
203                 if (strncmp (ksp_chain->ks_module, "nfs", 3) != 0)
204                         continue;
205                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v2", 13) == 0)
206                         nfs2_ksp_server = ksp_chain;
207                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v3", 13) == 0)
208                         nfs3_ksp_server = ksp_chain;
209                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v4", 13) == 0)
210                         nfs4_ksp_server = ksp_chain;
211                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v2", 12) == 0)
212                         nfs2_ksp_client = ksp_chain;
213                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v3", 12) == 0)
214                         nfs3_ksp_client = ksp_chain;
215                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v4", 12) == 0)
216                         nfs4_ksp_client = ksp_chain;
217         }
218
219         return (0);
220 } /* int nfs_init */
221 #endif
222
223 #define BUFSIZE 1024
224 #if HAVE_LIBKSTAT
225
226 static void nfs2_procedures_submit(unsigned long long *val,
227         const char *plugin_instance, char *nfs_ver, int len)
228 {
229         value_t values[1];
230         value_list_t vl = VALUE_LIST_INIT;
231         char pl_instance[30];
232         int i;
233
234         vl.values = values;
235         vl.values_len = 1;
236         sstrncpy(vl.host, hostname_g, sizeof (vl.host));
237         sstrncpy(vl.plugin, "nfs", sizeof (vl.plugin));
238         sstrncpy(pl_instance, nfs_ver, strlen(nfs_ver) + 1);
239         strcat(pl_instance, plugin_instance);
240         sstrncpy(vl.plugin_instance, pl_instance,
241                         sizeof (vl.plugin_instance));
242         sstrncpy(vl.type, "nfs_procedure", sizeof (vl.type));
243
244
245         for (i = 0; i < len; i++)
246         {
247                 values[0].derive = val[i];
248                 if (strcmp(nfs_ver, "nfs2") == 0)
249                         sstrncpy(vl.type_instance, nfs2_procedures_names[i],
250                                         sizeof (vl.type_instance));
251                 else if (strcmp(nfs_ver, "nfs3") == 0)
252                         sstrncpy(vl.type_instance, nfs3_procedures_names[i],
253                                         sizeof (vl.type_instance));
254                 else if (strcmp(nfs_ver, "nfs4") == 0) {
255                         sstrncpy(vl.type_instance, nfs4_procedures_names[i],
256                                         sizeof (vl.type_instance));
257                 }
258
259                 DEBUG("%s-%s/nfs_procedure-%s = %lld",
260                                 vl.plugin, vl.plugin_instance,
261                                 vl.type_instance, val[i]);
262                 plugin_dispatch_values (&vl);
263         }
264 }
265 #endif
266
267 static void nfs_procedures_submit (const char *plugin_instance,
268         unsigned long long *val, const char **names, int len)
269 {
270
271         value_t values[1];
272         value_list_t vl = VALUE_LIST_INIT;
273         int i;
274
275         vl.values = values;
276         vl.values_len = 1;
277         sstrncpy(vl.host, hostname_g, sizeof (vl.host));
278         sstrncpy(vl.plugin, "nfs", sizeof (vl.plugin));
279         sstrncpy(vl.plugin_instance, plugin_instance,
280                         sizeof (vl.plugin_instance));
281         sstrncpy(vl.type, "nfs_procedure", sizeof (vl.type));
282
283         for (i = 0; (val[i] != NULL) && (i < len); i++) {
284                 values[0].derive = val[i];
285                 sstrncpy(vl.type_instance, names[i],
286                                 sizeof (vl.type_instance));
287                 DEBUG("%s-%s/nfs_procedure-%s = %llu",
288                                 vl.plugin, vl.plugin_instance,
289                                 vl.type_instance, val[i]);
290                 plugin_dispatch_values(&vl);
291         }
292 } /* void nfs_procedures_submit */
293
294 static void nfs_read_stats_file (FILE *fh, char *inst)
295 {
296         char buffer[BUFSIZE];
297
298         char plugin_instance[DATA_MAX_NAME_LEN];
299
300         char *fields[48];
301         int numfields = 0;
302
303         if (fh == NULL)
304                 return;
305
306         while (fgets (buffer, BUFSIZE, fh) != NULL)
307         {
308                 numfields = strsplit (buffer, fields, 48);
309
310                 if (((numfields - 2) != nfs2_procedures_names_num)
311                                 && ((numfields - 2)
312                                         != nfs3_procedures_names_num))
313                         continue;
314
315                 if (strcmp (fields[0], "proc2") == 0)
316                 {
317                         int i;
318                         unsigned long long *values;
319
320                         if ((numfields - 2) != nfs2_procedures_names_num)
321                         {
322                                 WARNING ("nfs plugin: Wrong "
323                                                 "number of fields (= %i) "
324                                                 "for NFSv2 statistics.",
325                                                 numfields - 2);
326                                 continue;
327                         }
328
329                         ssnprintf (plugin_instance, sizeof (plugin_instance),
330                                         "v2%s", inst);
331
332                         values = (unsigned long long *) malloc (nfs2_procedures_names_num * sizeof (unsigned long long));
333                         if (values == NULL)
334                         {
335                                 char errbuf[1024];
336                                 ERROR ("nfs plugin: malloc "
337                                                 "failed: %s",
338                                                 sstrerror (errno, errbuf, sizeof (errbuf)));
339                                 continue;
340                         }
341
342                         for (i = 0; i < nfs2_procedures_names_num; i++)
343                                 values[i] = atoll (fields[i + 2]);
344
345                         nfs_procedures_submit (plugin_instance, values,
346                                         nfs2_procedures_names,
347                                         nfs2_procedures_names_num);
348
349                         free (values);
350                 }
351                 else if (strncmp (fields[0], "proc3", 5) == 0)
352                 {
353                         int i;
354                         unsigned long long *values;
355
356                         if ((numfields - 2) != nfs3_procedures_names_num)
357                         {
358                                 WARNING ("nfs plugin: Wrong "
359                                                 "number of fields (= %i) "
360                                                 "for NFSv3 statistics.",
361                                                 numfields - 2);
362                                 continue;
363                         }
364
365                         ssnprintf (plugin_instance, sizeof (plugin_instance),
366                                         "v3%s", inst);
367
368                         values = (unsigned long long *) malloc (nfs3_procedures_names_num * sizeof (unsigned long long));
369                         if (values == NULL)
370                         {
371                                 char errbuf[1024];
372                                 ERROR ("nfs plugin: malloc "
373                                                 "failed: %s",
374                                                 sstrerror (errno, errbuf, sizeof (errbuf)));
375                                 continue;
376                         }
377
378                         for (i = 0; i < nfs3_procedures_names_num; i++)
379                                 values[i] = atoll (fields[i + 2]);
380
381                         nfs_procedures_submit (plugin_instance, values,
382                                         nfs3_procedures_names,
383                                         nfs3_procedures_names_num);
384
385                         free (values);
386                 }
387         } /* while (fgets (buffer, BUFSIZE, fh) != NULL) */
388 } /* void nfs_read_stats_file */
389 #undef BUFSIZE
390
391 #if HAVE_LIBKSTAT
392 static void nfs2_read_kstat (kstat_t *ksp, char *inst)
393 {
394         unsigned long long values[nfs2_procedures_names_num];
395
396         kstat_read(kc, ksp, NULL);
397         values[0] = get_kstat_value (ksp, "null");
398         values[1] = get_kstat_value (ksp, "getattr");
399         values[2] = get_kstat_value (ksp, "setattr");
400         values[3] = get_kstat_value (ksp, "root");
401         values[4] = get_kstat_value (ksp, "lookup");
402         values[5] = get_kstat_value (ksp, "readlink");
403         values[6] = get_kstat_value (ksp, "read");
404         values[7] = get_kstat_value (ksp, "wrcache");
405         values[8] = get_kstat_value (ksp, "write");
406         values[9] = get_kstat_value (ksp, "create");
407         values[10] = get_kstat_value (ksp, "remove");
408         values[11] = get_kstat_value (ksp, "rename");
409         values[12] = get_kstat_value (ksp, "link");
410         values[13] = get_kstat_value (ksp, "symlink");
411         values[14] = get_kstat_value (ksp, "mkdir");
412         values[15] = get_kstat_value (ksp, "rmdir");
413         values[16] = get_kstat_value (ksp, "readdir");
414         values[17] = get_kstat_value (ksp, "statfs");
415
416         nfs2_procedures_submit (values, inst, "nfs2", nfs2_procedures_names_num);
417 }
418
419 static void nfs3_read_kstat(kstat_t *ksp, char *inst)
420 {
421         unsigned long long values[nfs3_procedures_names_num];
422
423         kstat_read(kc, ksp, NULL);
424         values[0] = get_kstat_value (ksp, "null");
425         values[1] = get_kstat_value (ksp, "getattr");
426         values[2] = get_kstat_value (ksp, "setattr");
427         values[3] = get_kstat_value (ksp, "lookup");
428         values[4] = get_kstat_value (ksp, "access");
429         values[5] = get_kstat_value (ksp, "readlink");
430         values[6] = get_kstat_value (ksp, "read");
431         values[7] = get_kstat_value (ksp, "write");
432         values[8] = get_kstat_value (ksp, "create");
433         values[9] = get_kstat_value (ksp, "mkdir");
434         values[10] = get_kstat_value (ksp, "symlink");
435         values[11] = get_kstat_value (ksp, "mknod");
436         values[12] = get_kstat_value (ksp, "remove");
437         values[13] = get_kstat_value (ksp, "rmdir");
438         values[14] = get_kstat_value (ksp, "rename");
439         values[15] = get_kstat_value (ksp, "link");
440         values[16] = get_kstat_value (ksp, "readdir");
441         values[17] = get_kstat_value (ksp, "readdirplus");
442         values[18] = get_kstat_value (ksp, "fsstat");
443         values[19] = get_kstat_value (ksp, "fsinfo");
444         values[20] = get_kstat_value (ksp, "pathconf");
445         values[21] = get_kstat_value (ksp, "commit");
446
447         nfs2_procedures_submit (values, inst, "nfs3", nfs3_procedures_names_num);
448 }
449
450 static void nfs4_read_kstat(kstat_t *ksp, char *inst)
451 {
452         unsigned long long values[nfs4_procedures_names_num];
453
454         kstat_read(kc, ksp, NULL);
455
456         values[0] = get_kstat_value (ksp, "null");
457         values[1] = get_kstat_value (ksp, "compound");
458         values[2] = get_kstat_value (ksp, "reserved");
459         values[3] = get_kstat_value (ksp, "access");
460         values[4] = get_kstat_value (ksp, "close");
461         values[5] = get_kstat_value (ksp, "commit");
462         values[6] = get_kstat_value (ksp, "create");
463         values[7] = get_kstat_value (ksp, "delegpurge");
464         values[8] = get_kstat_value (ksp, "delegreturn");
465         values[9] = get_kstat_value (ksp, "getattr");
466         values[10] = get_kstat_value (ksp, "getfh");
467         values[11] = get_kstat_value (ksp, "link");
468         values[12] = get_kstat_value (ksp, "lock");
469         values[13] = get_kstat_value (ksp, "lockt");
470         values[14] = get_kstat_value (ksp, "locku");
471         values[15] = get_kstat_value (ksp, "lookup");
472         values[16] = get_kstat_value (ksp, "lookupp");
473         values[17] = get_kstat_value (ksp, "nverify");
474         values[18] = get_kstat_value (ksp, "open");
475         values[19] = get_kstat_value (ksp, "openattr");
476         values[20] = get_kstat_value (ksp, "open_confirm");
477         values[21] = get_kstat_value (ksp, "open_downgrade");
478         values[22] = get_kstat_value (ksp, "putfh");
479         values[23] = get_kstat_value (ksp, "putpubfh");
480         values[24] = get_kstat_value (ksp, "putrootfh");
481         values[25] = get_kstat_value (ksp, "read");
482         values[26] = get_kstat_value (ksp, "readdir");
483         values[27] = get_kstat_value (ksp, "readlink");
484         values[28] = get_kstat_value (ksp, "remove");
485         values[29] = get_kstat_value (ksp, "rename");
486         values[30] = get_kstat_value (ksp, "renew");
487         values[31] = get_kstat_value (ksp, "restorefh");
488         values[32] = get_kstat_value (ksp, "savefh");
489         values[33] = get_kstat_value (ksp, "secinfo");
490         values[34] = get_kstat_value (ksp, "setattr");
491         values[35] = get_kstat_value (ksp, "setclientid");
492         values[36] = get_kstat_value (ksp, "setclientid_confirm");
493         values[37] = get_kstat_value (ksp, "verify");
494         values[38] = get_kstat_value (ksp, "write");
495
496         nfs2_procedures_submit (values, inst, "nfs4", nfs4_procedures_names_num);
497 }
498 #endif
499
500 static int nfs_read (void)
501 {
502         FILE *fh;
503
504         if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
505         {
506                 nfs_read_stats_file (fh, "client");
507                 fclose (fh);
508         }
509
510         if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
511         {
512                 nfs_read_stats_file (fh, "server");
513                 fclose (fh);
514         }
515
516 #if HAVE_LIBKSTAT
517         nfs_init ();
518         if (nfs2_ksp_client != NULL)
519                 nfs2_read_kstat (nfs2_ksp_client, "client");
520         if (nfs2_ksp_server != NULL)
521                 nfs2_read_kstat (nfs2_ksp_server, "server");
522         if (nfs3_ksp_client != NULL)
523                 nfs3_read_kstat (nfs3_ksp_client, "client");
524         if (nfs3_ksp_server != NULL)
525                 nfs3_read_kstat (nfs3_ksp_server, "server");
526         if (nfs4_ksp_client != NULL)
527                 nfs4_read_kstat (nfs4_ksp_client, "client");
528         if (nfs4_ksp_server != NULL)
529                 nfs4_read_kstat (nfs4_ksp_server, "server");
530         /* nfs_kstat(nfs3_ksp_client); */
531 #endif /* defined(HAVE_LIBKSTAT) */
532
533         return (0);
534 }
535
536 void module_register (void)
537 {
538         plugin_register_read ("nfs", nfs_read);
539 } /* void module_register */