Code

dpdkstat: use portable format strings
[collectd.git] / src / nfs.c
1 /**
2  * collectd - src/nfs.c
3  * Copyright (C) 2005,2006  Jason Pepas
4  * Copyright (C) 2012,2013  Florian Forster
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the
8  * Free Software Foundation; only version 2 of the License is applicable.
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 collectd.org>
22  *   Cosmin Ioiart <cioiart at gmail.com>
23  **/
25 #include "collectd.h"
27 #include "common.h"
28 #include "plugin.h"
30 #if HAVE_KSTAT_H
31 #include <kstat.h>
32 #endif
34 /*
35 see /proc/net/rpc/nfs
36 see http://www.missioncriticallinux.com/orph/NFS-Statistics
38 net x x x x
39 rpc_stat.netcnt         Not used; always zero.
40 rpc_stat.netudpcnt      Not used; always zero.
41 rpc_stat.nettcpcnt      Not used; always zero.
42 rpc_stat.nettcpconn     Not used; always zero.
44 rpc x x x
45 rpc_stat.rpccnt             The number of RPC calls.
46 rpc_stat.rpcretrans         The number of retransmitted RPC calls.
47 rpc_stat.rpcauthrefresh     The number of credential refreshes.
49 proc2 x x x...
50 proc3 x x x...
52 Procedure   NFS Version NFS Version 3
53 Number      Procedures  Procedures
55 0           null        null
56 1           getattr     getattr
57 2           setattr     setattr
58 3           root        lookup
59 4           lookup      access
60 5           readlink    readlink
61 6           read        read
62 7           wrcache     write
63 8           write       create
64 9           create      mkdir
65 10          remove      symlink
66 11          rename      mknod
67 12          link        remove
68 13          symlink     rmdir
69 14          mkdir       rename
70 15          rmdir       link
71 16          readdir     readdir
72 17          fsstat      readdirplus
73 18                      fsstat
74 19                      fsinfo
75 20                      pathconf
76 21                      commit
77 */
79 static const char *nfs2_procedures_names[] = {
80     "null", "getattr", "setattr", "root",   "lookup",  "readlink",
81     "read", "wrcache", "write",   "create", "remove",  "rename",
82     "link", "symlink", "mkdir",   "rmdir",  "readdir", "fsstat"};
83 static size_t nfs2_procedures_names_num =
84     STATIC_ARRAY_SIZE(nfs2_procedures_names);
86 static const char *nfs3_procedures_names[] = {
87     "null",   "getattr", "setattr",  "lookup", "access",  "readlink",
88     "read",   "write",   "create",   "mkdir",  "symlink", "mknod",
89     "remove", "rmdir",   "rename",   "link",   "readdir", "readdirplus",
90     "fsstat", "fsinfo",  "pathconf", "commit"};
91 static size_t nfs3_procedures_names_num =
92     STATIC_ARRAY_SIZE(nfs3_procedures_names);
94 #if HAVE_LIBKSTAT
95 static const char *nfs4_procedures_names[] = {"null",
96                                               "compound",
97                                               "reserved",
98                                               "access",
99                                               "close",
100                                               "commit",
101                                               "create",
102                                               "delegpurge",
103                                               "delegreturn",
104                                               "getattr",
105                                               "getfh",
106                                               "link",
107                                               "lock",
108                                               "lockt",
109                                               "locku",
110                                               "lookup",
111                                               "lookupp",
112                                               "nverify",
113                                               "open",
114                                               "openattr",
115                                               "open_confirm",
116                                               "open_downgrade",
117                                               "putfh",
118                                               "putpubfh",
119                                               "putrootfh",
120                                               "read",
121                                               "readdir",
122                                               "readlink",
123                                               "remove",
124                                               "rename",
125                                               "renew",
126                                               "restorefh",
127                                               "savefh",
128                                               "secinfo",
129                                               "setattr",
130                                               "setclientid",
131                                               "setclientid_confirm",
132                                               "verify",
133                                               "write"};
134 static size_t nfs4_procedures_names_num =
135     STATIC_ARRAY_SIZE(nfs4_procedures_names);
136 #endif
138 #if KERNEL_LINUX
139 static const char *nfs4_server40_procedures_names[] = {"null",
140                                                        "compound",
141                                                        "reserved",
142                                                        "access",
143                                                        "close",
144                                                        "commit",
145                                                        "create",
146                                                        "delegpurge",
147                                                        "delegreturn",
148                                                        "getattr",
149                                                        "getfh",
150                                                        "link",
151                                                        "lock",
152                                                        "lockt",
153                                                        "locku",
154                                                        "lookup",
155                                                        "lookupp",
156                                                        "nverify",
157                                                        "open",
158                                                        "openattr",
159                                                        "open_confirm",
160                                                        "open_downgrade",
161                                                        "putfh",
162                                                        "putpubfh",
163                                                        "putrootfh",
164                                                        "read",
165                                                        "readdir",
166                                                        "readlink",
167                                                        "remove",
168                                                        "rename",
169                                                        "renew",
170                                                        "restorefh",
171                                                        "savefh",
172                                                        "secinfo",
173                                                        "setattr",
174                                                        "setclientid",
175                                                        "setcltid_confirm",
176                                                        "verify",
177                                                        "write",
178                                                        "release_lockowner"};
180 static size_t nfs4_server40_procedures_names_num =
181     STATIC_ARRAY_SIZE(nfs4_server40_procedures_names);
183 static const char *nfs4_server41_procedures_names[] = {
184     "backchannel_ctl",
185     "bind_conn_to_session",
186     "exchange_id",
187     "create_session",
188     "destroy_session",
189     "free_stateid",
190     "get_dir_delegation",
191     "getdeviceinfo",
192     "getdevicelist",
193     "layoutcommit",
194     "layoutget",
195     "layoutreturn",
196     "secinfo_no_name",
197     "sequence",
198     "set_ssv",
199     "test_stateid",
200     "want_delegation",
201     "destroy_clientid",
202     "reclaim_complete",
203 };
205 static size_t nfs4_server41_procedures_names_num =
206     STATIC_ARRAY_SIZE(nfs4_server41_procedures_names);
208 #define NFS4_SERVER40_NUM_PROC                                                 \
209   (STATIC_ARRAY_SIZE(nfs4_server40_procedures_names))
211 #define NFS4_SERVER41_NUM_PROC                                                 \
212   (STATIC_ARRAY_SIZE(nfs4_server40_procedures_names) +                         \
213    STATIC_ARRAY_SIZE(nfs4_server41_procedures_names))
215 #define NFS4_SERVER_MAX_PROC (NFS4_SERVER41_NUM_PROC)
217 static const char *nfs4_client40_procedures_names[] = {
218     "null",
219     "read",
220     "write",
221     "commit",
222     "open",
223     "open_confirm",
224     "open_noattr",
225     "open_downgrade",
226     "close",
227     "setattr",
228     "fsinfo",
229     "renew",
230     "setclientid",
231     "setclientid_confirm",
232     "lock",
233     "lockt",
234     "locku",
235     "access",
236     "getattr",
237     "lookup",
238     "lookupp",
239     "remove",
240     "rename",
241     "link",
242     "symlink",
243     "create",
244     "pathconf",
245     "statfs",
246     "readlink",
247     "readdir",
248     "server_caps",
249     "delegreturn",
250     "getacl",
251     "setacl",
252     "fs_locations",      /* |35| 2.6.18 */
253     "release_lockowner", /* |42| 2.6.36 */
254     "secinfo",           /* |46| 2.6.39 */
255     "fsid_present"       /* |54| 3.13 */
256 };
258 static const char *nfs4_client41_procedures_names[] = {
259     "exchange_id",          /* |40| 2.6.30 */
260     "create_session",       /* |40| 2.6.30 */
261     "destroy_session",      /* |40| 2.6.30 */
262     "sequence",             /* |40| 2.6.30 */
263     "get_lease_time",       /* |40| 2.6.30 */
264     "reclaim_complete",     /* |41| 2.6.33 */
265     "layoutget",            /* |44| 2.6.37 */
266     "getdeviceinfo",        /* |44| 2.6.37 */
267     "layoutcommit",         /* |46| 2.6.39 */
268     "layoutreturn",         /* |47| 3.0 */
269     "secinfo_no_name",      /* |51| 3.1 */
270     "test_stateid",         /* |51| 3.1 */
271     "free_stateid",         /* |51| 3.1 */
272     "getdevicelist",        /* |51| 3.1 */
273     "bind_conn_to_session", /* |53| 3.5 */
274     "destroy_clientid"      /* |53| 3.5 */
275 };
277 #define NFS4_CLIENT40_NUM_PROC                                                 \
278   (STATIC_ARRAY_SIZE(nfs4_client40_procedures_names))
280 #define NFS4_CLIENT41_NUM_PROC                                                 \
281   (STATIC_ARRAY_SIZE(nfs4_client40_procedures_names) +                         \
282    STATIC_ARRAY_SIZE(nfs4_client41_procedures_names))
284 #define NFS4_CLIENT_MAX_PROC (NFS4_CLIENT41_NUM_PROC)
286 #endif
288 #if HAVE_LIBKSTAT
289 extern kstat_ctl_t *kc;
290 static kstat_t *nfs2_ksp_client;
291 static kstat_t *nfs2_ksp_server;
292 static kstat_t *nfs3_ksp_client;
293 static kstat_t *nfs3_ksp_server;
294 static kstat_t *nfs4_ksp_client;
295 static kstat_t *nfs4_ksp_server;
296 #endif
298 #if KERNEL_LINUX
299 static int nfs_init(void) { return (0); }
300 /* #endif KERNEL_LINUX */
302 #elif HAVE_LIBKSTAT
303 static int nfs_init(void) {
304   nfs2_ksp_client = NULL;
305   nfs2_ksp_server = NULL;
306   nfs3_ksp_client = NULL;
307   nfs3_ksp_server = NULL;
308   nfs4_ksp_client = NULL;
309   nfs4_ksp_server = NULL;
311   if (kc == NULL)
312     return (-1);
314   for (kstat_t *ksp_chain = kc->kc_chain; ksp_chain != NULL;
315        ksp_chain = ksp_chain->ks_next) {
316     if (strncmp(ksp_chain->ks_module, "nfs", 3) != 0)
317       continue;
318     else if (strncmp(ksp_chain->ks_name, "rfsproccnt_v2", 13) == 0)
319       nfs2_ksp_server = ksp_chain;
320     else if (strncmp(ksp_chain->ks_name, "rfsproccnt_v3", 13) == 0)
321       nfs3_ksp_server = ksp_chain;
322     else if (strncmp(ksp_chain->ks_name, "rfsproccnt_v4", 13) == 0)
323       nfs4_ksp_server = ksp_chain;
324     else if (strncmp(ksp_chain->ks_name, "rfsreqcnt_v2", 12) == 0)
325       nfs2_ksp_client = ksp_chain;
326     else if (strncmp(ksp_chain->ks_name, "rfsreqcnt_v3", 12) == 0)
327       nfs3_ksp_client = ksp_chain;
328     else if (strncmp(ksp_chain->ks_name, "rfsreqcnt_v4", 12) == 0)
329       nfs4_ksp_client = ksp_chain;
330   }
332   return (0);
333 } /* int nfs_init */
334 #endif
336 static void nfs_procedures_submit(const char *plugin_instance,
337                                   const char **type_instances, value_t *values,
338                                   size_t values_num) {
339   value_list_t vl = VALUE_LIST_INIT;
341   vl.values_len = 1;
342   sstrncpy(vl.plugin, "nfs", sizeof(vl.plugin));
343   sstrncpy(vl.plugin_instance, plugin_instance, sizeof(vl.plugin_instance));
344   sstrncpy(vl.type, "nfs_procedure", sizeof(vl.type));
346   for (size_t i = 0; i < values_num; i++) {
347     vl.values = values + i;
348     sstrncpy(vl.type_instance, type_instances[i], sizeof(vl.type_instance));
349     plugin_dispatch_values(&vl);
350   }
351 } /* void nfs_procedures_submit */
353 #if KERNEL_LINUX
354 static void nfs_submit_fields(int nfs_version, const char *instance,
355                               char **fields, size_t fields_num,
356                               const char **proc_names) {
357   char plugin_instance[DATA_MAX_NAME_LEN];
358   value_t values[fields_num];
360   ssnprintf(plugin_instance, sizeof(plugin_instance), "v%i%s", nfs_version,
361             instance);
363   for (size_t i = 0; i < fields_num; i++)
364     (void)parse_value(fields[i], &values[i], DS_TYPE_DERIVE);
366   nfs_procedures_submit(plugin_instance, proc_names, values, fields_num);
369 static int nfs_submit_fields_safe(int nfs_version, const char *instance,
370                                   char **fields, size_t fields_num,
371                                   const char **proc_names,
372                                   size_t proc_names_num) {
373   if (fields_num != proc_names_num) {
374     WARNING("nfs plugin: Wrong number of fields for "
375             "NFSv%i %s statistics. Expected %zu, got %zu.",
376             nfs_version, instance, proc_names_num, fields_num);
377     return (EINVAL);
378   }
380   nfs_submit_fields(nfs_version, instance, fields, fields_num, proc_names);
382   return (0);
385 static int nfs_submit_nfs4_server(const char *instance, char **fields,
386                                   size_t fields_num) {
387   static int suppress_warning = 0;
389   if (fields_num != NFS4_SERVER40_NUM_PROC &&
390       fields_num != NFS4_SERVER41_NUM_PROC) {
391     if (!suppress_warning) {
392       WARNING("nfs plugin: Unexpected number of fields for "
393               "NFSv4 %s statistics: %zu. ",
394               instance, fields_num);
395     }
397     if (fields_num > NFS4_SERVER_MAX_PROC) {
398       fields_num = NFS4_SERVER_MAX_PROC;
399       suppress_warning = 1;
400     } else {
401       return (EINVAL);
402     }
403   }
405   nfs_submit_fields(4, instance, fields, nfs4_server40_procedures_names_num,
406                     nfs4_server40_procedures_names);
408   if (fields_num >= NFS4_SERVER41_NUM_PROC) {
409     fields += nfs4_server40_procedures_names_num;
411     nfs_submit_fields(4, instance, fields, nfs4_server41_procedures_names_num,
412                       nfs4_server41_procedures_names);
413   }
415   return (0);
418 static int nfs_submit_nfs4_client(const char *instance, char **fields,
419                                   size_t fields_num) {
420   size_t proc40_names_num, proc41_names_num;
422   static int suppress_warning = 0;
424   switch (fields_num) {
425   case 34:
426   case 35:
427   case 36:
428   case 37:
429   case 38:
430     /* 4.0-only configuration */
431     proc40_names_num = fields_num;
432     break;
433   case 40:
434   case 41:
435     proc40_names_num = 35;
436     break;
437   case 42:
438   case 44:
439     proc40_names_num = 36;
440     break;
441   case 46:
442   case 47:
443   case 51:
444   case 53:
445     proc40_names_num = 37;
446     break;
447   case 54:
448     proc40_names_num = 38;
449     break;
450   default:
451     if (!suppress_warning) {
452       WARNING("nfs plugin: Unexpected number of "
453               "fields for NFSv4 %s "
454               "statistics: %zu. ",
455               instance, fields_num);
456     }
458     if (fields_num > 34) {
459       /* safe fallback to basic nfs40 procedures */
460       fields_num = 34;
461       proc40_names_num = 34;
463       suppress_warning = 1;
464     } else {
465       return (EINVAL);
466     }
467   }
469   nfs_submit_fields(4, instance, fields, proc40_names_num,
470                     nfs4_client40_procedures_names);
472   if (fields_num > proc40_names_num) {
473     proc41_names_num = fields_num - proc40_names_num;
474     fields += proc40_names_num;
476     nfs_submit_fields(4, instance, fields, proc41_names_num,
477                       nfs4_client41_procedures_names);
478   }
480   return (0);
483 static void nfs_read_linux(FILE *fh, const char *inst) {
484   char buffer[1024];
486   char *fields[64];
487   int fields_num = 0;
489   if (fh == NULL)
490     return;
492   while (fgets(buffer, sizeof(buffer), fh) != NULL) {
493     fields_num = strsplit(buffer, fields, STATIC_ARRAY_SIZE(fields));
495     if (fields_num < 3)
496       continue;
498     if (strcmp(fields[0], "proc2") == 0) {
499       nfs_submit_fields_safe(/* version = */ 2, inst, fields + 2,
500                              (size_t)(fields_num - 2), nfs2_procedures_names,
501                              nfs2_procedures_names_num);
502     } else if (strncmp(fields[0], "proc3", 5) == 0) {
503       nfs_submit_fields_safe(/* version = */ 3, inst, fields + 2,
504                              (size_t)(fields_num - 2), nfs3_procedures_names,
505                              nfs3_procedures_names_num);
506     } else if (strcmp(fields[0], "proc4ops") == 0) {
507       if (inst[0] == 's')
508         nfs_submit_nfs4_server(inst, fields + 2, (size_t)(fields_num - 2));
509     } else if (strcmp(fields[0], "proc4") == 0) {
510       if (inst[0] == 'c')
511         nfs_submit_nfs4_client(inst, fields + 2, (size_t)(fields_num - 2));
512     }
513   } /* while (fgets) */
514 } /* void nfs_read_linux */
515 #endif /* KERNEL_LINUX */
517 #if HAVE_LIBKSTAT
518 static int nfs_read_kstat(kstat_t *ksp, int nfs_version, const char *inst,
519                           char const **proc_names, size_t proc_names_num) {
520   char plugin_instance[DATA_MAX_NAME_LEN];
521   value_t values[proc_names_num];
523   if (ksp == NULL)
524     return (EINVAL);
526   ssnprintf(plugin_instance, sizeof(plugin_instance), "v%i%s", nfs_version,
527             inst);
529   kstat_read(kc, ksp, NULL);
530   for (size_t i = 0; i < proc_names_num; i++) {
531     /* The name passed to kstat_data_lookup() doesn't have the
532      * "const" modifier, so we need to copy the name here. */
533     char name[32];
534     sstrncpy(name, proc_names[i], sizeof(name));
536     values[i].counter = (derive_t)get_kstat_value(ksp, name);
537   }
539   nfs_procedures_submit(plugin_instance, proc_names, values, proc_names_num);
540   return (0);
542 #endif
544 #if KERNEL_LINUX
545 static int nfs_read(void) {
546   FILE *fh;
548   if ((fh = fopen("/proc/net/rpc/nfs", "r")) != NULL) {
549     nfs_read_linux(fh, "client");
550     fclose(fh);
551   }
553   if ((fh = fopen("/proc/net/rpc/nfsd", "r")) != NULL) {
554     nfs_read_linux(fh, "server");
555     fclose(fh);
556   }
558   return (0);
560 /* #endif KERNEL_LINUX */
562 #elif HAVE_LIBKSTAT
563 static int nfs_read(void) {
564   nfs_read_kstat(nfs2_ksp_client, /* version = */ 2, "client",
565                  nfs2_procedures_names, nfs2_procedures_names_num);
566   nfs_read_kstat(nfs2_ksp_server, /* version = */ 2, "server",
567                  nfs2_procedures_names, nfs2_procedures_names_num);
568   nfs_read_kstat(nfs3_ksp_client, /* version = */ 3, "client",
569                  nfs3_procedures_names, nfs3_procedures_names_num);
570   nfs_read_kstat(nfs3_ksp_server, /* version = */ 3, "server",
571                  nfs3_procedures_names, nfs3_procedures_names_num);
572   nfs_read_kstat(nfs4_ksp_client, /* version = */ 4, "client",
573                  nfs4_procedures_names, nfs4_procedures_names_num);
574   nfs_read_kstat(nfs4_ksp_server, /* version = */ 4, "server",
575                  nfs4_procedures_names, nfs4_procedures_names_num);
577   return (0);
579 #endif /* HAVE_LIBKSTAT */
581 void module_register(void) {
582   plugin_register_init("nfs", nfs_init);
583   plugin_register_read("nfs", nfs_read);
584 } /* void module_register */