Code

src/utils_ovs.c: Random coding style improvements.
[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 static const char *config_keys[] = {"ReportV2", "ReportV3", "ReportV4"};
35 static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
36 static _Bool report_v2 = 1;
37 static _Bool report_v3 = 1;
38 static _Bool report_v4 = 1;
40 /*
41 see /proc/net/rpc/nfs
42 see http://www.missioncriticallinux.com/orph/NFS-Statistics
44 net x x x x
45 rpc_stat.netcnt         Not used; always zero.
46 rpc_stat.netudpcnt      Not used; always zero.
47 rpc_stat.nettcpcnt      Not used; always zero.
48 rpc_stat.nettcpconn     Not used; always zero.
50 rpc x x x
51 rpc_stat.rpccnt             The number of RPC calls.
52 rpc_stat.rpcretrans         The number of retransmitted RPC calls.
53 rpc_stat.rpcauthrefresh     The number of credential refreshes.
55 proc2 x x x...
56 proc3 x x x...
58 Procedure   NFS Version NFS Version 3
59 Number      Procedures  Procedures
61 0           null        null
62 1           getattr     getattr
63 2           setattr     setattr
64 3           root        lookup
65 4           lookup      access
66 5           readlink    readlink
67 6           read        read
68 7           wrcache     write
69 8           write       create
70 9           create      mkdir
71 10          remove      symlink
72 11          rename      mknod
73 12          link        remove
74 13          symlink     rmdir
75 14          mkdir       rename
76 15          rmdir       link
77 16          readdir     readdir
78 17          fsstat      readdirplus
79 18                      fsstat
80 19                      fsinfo
81 20                      pathconf
82 21                      commit
83 */
85 static const char *nfs2_procedures_names[] = {
86     "null", "getattr", "setattr", "root",   "lookup",  "readlink",
87     "read", "wrcache", "write",   "create", "remove",  "rename",
88     "link", "symlink", "mkdir",   "rmdir",  "readdir", "fsstat"};
89 static size_t nfs2_procedures_names_num =
90     STATIC_ARRAY_SIZE(nfs2_procedures_names);
92 static const char *nfs3_procedures_names[] = {
93     "null",   "getattr", "setattr",  "lookup", "access",  "readlink",
94     "read",   "write",   "create",   "mkdir",  "symlink", "mknod",
95     "remove", "rmdir",   "rename",   "link",   "readdir", "readdirplus",
96     "fsstat", "fsinfo",  "pathconf", "commit"};
97 static size_t nfs3_procedures_names_num =
98     STATIC_ARRAY_SIZE(nfs3_procedures_names);
100 #if HAVE_LIBKSTAT
101 static const char *nfs4_procedures_names[] = {"null",
102                                               "compound",
103                                               "reserved",
104                                               "access",
105                                               "close",
106                                               "commit",
107                                               "create",
108                                               "delegpurge",
109                                               "delegreturn",
110                                               "getattr",
111                                               "getfh",
112                                               "link",
113                                               "lock",
114                                               "lockt",
115                                               "locku",
116                                               "lookup",
117                                               "lookupp",
118                                               "nverify",
119                                               "open",
120                                               "openattr",
121                                               "open_confirm",
122                                               "open_downgrade",
123                                               "putfh",
124                                               "putpubfh",
125                                               "putrootfh",
126                                               "read",
127                                               "readdir",
128                                               "readlink",
129                                               "remove",
130                                               "rename",
131                                               "renew",
132                                               "restorefh",
133                                               "savefh",
134                                               "secinfo",
135                                               "setattr",
136                                               "setclientid",
137                                               "setclientid_confirm",
138                                               "verify",
139                                               "write"};
140 static size_t nfs4_procedures_names_num =
141     STATIC_ARRAY_SIZE(nfs4_procedures_names);
142 #endif
144 #if KERNEL_LINUX
145 static const char *nfs4_server40_procedures_names[] = {"null",
146                                                        "compound",
147                                                        "reserved",
148                                                        "access",
149                                                        "close",
150                                                        "commit",
151                                                        "create",
152                                                        "delegpurge",
153                                                        "delegreturn",
154                                                        "getattr",
155                                                        "getfh",
156                                                        "link",
157                                                        "lock",
158                                                        "lockt",
159                                                        "locku",
160                                                        "lookup",
161                                                        "lookupp",
162                                                        "nverify",
163                                                        "open",
164                                                        "openattr",
165                                                        "open_confirm",
166                                                        "open_downgrade",
167                                                        "putfh",
168                                                        "putpubfh",
169                                                        "putrootfh",
170                                                        "read",
171                                                        "readdir",
172                                                        "readlink",
173                                                        "remove",
174                                                        "rename",
175                                                        "renew",
176                                                        "restorefh",
177                                                        "savefh",
178                                                        "secinfo",
179                                                        "setattr",
180                                                        "setclientid",
181                                                        "setcltid_confirm",
182                                                        "verify",
183                                                        "write",
184                                                        "release_lockowner"};
186 static size_t nfs4_server40_procedures_names_num =
187     STATIC_ARRAY_SIZE(nfs4_server40_procedures_names);
189 static const char *nfs4_server4x_procedures_names[] = {
190     /* NFS 4.1 */
191     "backchannel_ctl", "bind_conn_to_session", "exchange_id", "create_session",
192     "destroy_session", "free_stateid", "get_dir_delegation", "getdeviceinfo",
193     "getdevicelist", "layoutcommit", "layoutget", "layoutreturn",
194     "secinfo_no_name", "sequence", "set_ssv", "test_stateid", "want_delegation",
195     "destroy_clientid", "reclaim_complete",
196     /* NFS 4.2 */
197     "allocate",      /* 3.18 */
198     "copy",          /* 3.18 */
199     "copy_notify",   /* 3.18 */
200     "deallocate",    /* 3.18 */
201     "ioadvise",      /* 3.18 */
202     "layouterror",   /* 3.18 */
203     "layoutstats",   /* 3.18 */
204     "offloadcancel", /* 3.18 */
205     "offloadstatus", /* 3.18 */
206     "readplus",      /* 3.18 */
207     "seek",          /* 3.18 */
208     "write_same",    /* 3.18 */
209     "clone"          /* 4.5 */
210 };
212 #define NFS4_SERVER40_NUM_PROC                                                 \
213   (STATIC_ARRAY_SIZE(nfs4_server40_procedures_names))
215 #define NFS4_SERVER4X_NUM_PROC                                                 \
216   (STATIC_ARRAY_SIZE(nfs4_server40_procedures_names) +                         \
217    STATIC_ARRAY_SIZE(nfs4_server4x_procedures_names))
219 #define NFS4_SERVER_MAX_PROC (NFS4_SERVER4X_NUM_PROC)
221 static const char *nfs4_client40_procedures_names[] = {
222     "null",
223     "read",
224     "write",
225     "commit",
226     "open",
227     "open_confirm",
228     "open_noattr",
229     "open_downgrade",
230     "close",
231     "setattr",
232     "fsinfo",
233     "renew",
234     "setclientid",
235     "setclientid_confirm",
236     "lock",
237     "lockt",
238     "locku",
239     "access",
240     "getattr",
241     "lookup",
242     "lookupp",
243     "remove",
244     "rename",
245     "link",
246     "symlink",
247     "create",
248     "pathconf",
249     "statfs",
250     "readlink",
251     "readdir",
252     "server_caps",
253     "delegreturn",
254     "getacl",
255     "setacl",
256     "fs_locations",      /* |35| 2.6.18 */
257     "release_lockowner", /* |42| 2.6.36 */
258     "secinfo",           /* |46| 2.6.39 */
259     "fsid_present"       /* |54| 3.13 */
260 };
262 static const char *nfs4_client4x_procedures_names[] = {
263     /* NFS 4.1 */
264     "exchange_id",          /* |40| 2.6.30 */
265     "create_session",       /* |40| 2.6.30 */
266     "destroy_session",      /* |40| 2.6.30 */
267     "sequence",             /* |40| 2.6.30 */
268     "get_lease_time",       /* |40| 2.6.30 */
269     "reclaim_complete",     /* |41| 2.6.33 */
270     "layoutget",            /* |44| 2.6.37 */
271     "getdeviceinfo",        /* |44| 2.6.37 */
272     "layoutcommit",         /* |46| 2.6.39 */
273     "layoutreturn",         /* |47| 3.0 */
274     "secinfo_no_name",      /* |51| 3.1 */
275     "test_stateid",         /* |51| 3.1 */
276     "free_stateid",         /* |51| 3.1 */
277     "getdevicelist",        /* |51| 3.1 */
278     "bind_conn_to_session", /* |53| 3.5 */
279     "destroy_clientid",     /* |53| 3.5 */
280     /* NFS 4.2 */
281     "seek",        /* |55| 3.18 */
282     "allocate",    /* |57| 3.19 */
283     "deallocate",  /* |57| 3.19 */
284     "layoutstats", /* |58| 4.2 */
285     "clone",       /* |59| 4.4 */
286     "copy"         /* |60| 4.7 */
287 };
289 #define NFS4_CLIENT40_NUM_PROC                                                 \
290   (STATIC_ARRAY_SIZE(nfs4_client40_procedures_names))
292 #define NFS4_CLIENT4X_NUM_PROC                                                 \
293   (STATIC_ARRAY_SIZE(nfs4_client40_procedures_names) +                         \
294    STATIC_ARRAY_SIZE(nfs4_client4x_procedures_names))
296 #define NFS4_CLIENT_MAX_PROC (NFS4_CLIENT4X_NUM_PROC)
298 #endif
300 #if HAVE_LIBKSTAT
301 extern kstat_ctl_t *kc;
302 static kstat_t *nfs2_ksp_client;
303 static kstat_t *nfs2_ksp_server;
304 static kstat_t *nfs3_ksp_client;
305 static kstat_t *nfs3_ksp_server;
306 static kstat_t *nfs4_ksp_client;
307 static kstat_t *nfs4_ksp_server;
308 #endif
310 static int nfs_config(const char *key, const char *value) {
311   if (strcasecmp(key, "ReportV2") == 0)
312     report_v2 = IS_TRUE(value);
313   else if (strcasecmp(key, "ReportV3") == 0)
314     report_v3 = IS_TRUE(value);
315   else if (strcasecmp(key, "ReportV4") == 0)
316     report_v4 = IS_TRUE(value);
317   else
318     return -1;
320   return 0;
323 #if KERNEL_LINUX
324 static int nfs_init(void) { return 0; }
325 /* #endif KERNEL_LINUX */
327 #elif HAVE_LIBKSTAT
328 static int nfs_init(void) {
329   nfs2_ksp_client = NULL;
330   nfs2_ksp_server = NULL;
331   nfs3_ksp_client = NULL;
332   nfs3_ksp_server = NULL;
333   nfs4_ksp_client = NULL;
334   nfs4_ksp_server = NULL;
336   if (kc == NULL)
337     return -1;
339   for (kstat_t *ksp_chain = kc->kc_chain; ksp_chain != NULL;
340        ksp_chain = ksp_chain->ks_next) {
341     if (strncmp(ksp_chain->ks_module, "nfs", 3) != 0)
342       continue;
343     else if (strncmp(ksp_chain->ks_name, "rfsproccnt_v2", 13) == 0)
344       nfs2_ksp_server = ksp_chain;
345     else if (strncmp(ksp_chain->ks_name, "rfsproccnt_v3", 13) == 0)
346       nfs3_ksp_server = ksp_chain;
347     else if (strncmp(ksp_chain->ks_name, "rfsproccnt_v4", 13) == 0)
348       nfs4_ksp_server = ksp_chain;
349     else if (strncmp(ksp_chain->ks_name, "rfsreqcnt_v2", 12) == 0)
350       nfs2_ksp_client = ksp_chain;
351     else if (strncmp(ksp_chain->ks_name, "rfsreqcnt_v3", 12) == 0)
352       nfs3_ksp_client = ksp_chain;
353     else if (strncmp(ksp_chain->ks_name, "rfsreqcnt_v4", 12) == 0)
354       nfs4_ksp_client = ksp_chain;
355   }
357   return 0;
358 } /* int nfs_init */
359 #endif
361 static void nfs_procedures_submit(const char *plugin_instance,
362                                   const char **type_instances, value_t *values,
363                                   size_t values_num) {
364   value_list_t vl = VALUE_LIST_INIT;
366   vl.values_len = 1;
367   sstrncpy(vl.plugin, "nfs", sizeof(vl.plugin));
368   sstrncpy(vl.plugin_instance, plugin_instance, sizeof(vl.plugin_instance));
369   sstrncpy(vl.type, "nfs_procedure", sizeof(vl.type));
371   for (size_t i = 0; i < values_num; i++) {
372     vl.values = values + i;
373     sstrncpy(vl.type_instance, type_instances[i], sizeof(vl.type_instance));
374     plugin_dispatch_values(&vl);
375   }
376 } /* void nfs_procedures_submit */
378 #if KERNEL_LINUX
379 static void nfs_submit_fields(int nfs_version, const char *instance,
380                               char **fields, size_t fields_num,
381                               const char **proc_names) {
382   char plugin_instance[DATA_MAX_NAME_LEN];
383   value_t values[fields_num];
385   snprintf(plugin_instance, sizeof(plugin_instance), "v%i%s", nfs_version,
386            instance);
388   for (size_t i = 0; i < fields_num; i++)
389     (void)parse_value(fields[i], &values[i], DS_TYPE_DERIVE);
391   nfs_procedures_submit(plugin_instance, proc_names, values, fields_num);
394 static int nfs_submit_fields_safe(int nfs_version, const char *instance,
395                                   char **fields, size_t fields_num,
396                                   const char **proc_names,
397                                   size_t proc_names_num) {
398   if (fields_num != proc_names_num) {
399     WARNING("nfs plugin: Wrong number of fields for "
400             "NFSv%i %s statistics. Expected %zu, got %zu.",
401             nfs_version, instance, proc_names_num, fields_num);
402     return EINVAL;
403   }
405   nfs_submit_fields(nfs_version, instance, fields, fields_num, proc_names);
407   return 0;
410 static int nfs_submit_nfs4_server(const char *instance, char **fields,
411                                   size_t fields_num) {
412   static int suppress_warning = 0;
413   size_t proc4x_names_num;
415   switch (fields_num) {
416   case NFS4_SERVER40_NUM_PROC:
417   case NFS4_SERVER40_NUM_PROC + 19: /* NFS 4.1 */
418   case NFS4_SERVER40_NUM_PROC + 31: /* NFS 4.2 */
419   case NFS4_SERVER40_NUM_PROC + 32: /* NFS 4.2 */
420     break;
421   default:
422     if (!suppress_warning) {
423       WARNING("nfs plugin: Unexpected number of fields for "
424               "NFSv4 %s statistics: %zu. ",
425               instance, fields_num);
426     }
428     if (fields_num > NFS4_SERVER_MAX_PROC) {
429       fields_num = NFS4_SERVER_MAX_PROC;
430       suppress_warning = 1;
431     } else {
432       return EINVAL;
433     }
434   }
436   nfs_submit_fields(4, instance, fields, nfs4_server40_procedures_names_num,
437                     nfs4_server40_procedures_names);
439   if (fields_num > nfs4_server40_procedures_names_num) {
440     proc4x_names_num = fields_num - nfs4_server40_procedures_names_num;
441     fields += nfs4_server40_procedures_names_num;
443     nfs_submit_fields(4, instance, fields, proc4x_names_num,
444                       nfs4_server4x_procedures_names);
445   }
447   return 0;
450 static int nfs_submit_nfs4_client(const char *instance, char **fields,
451                                   size_t fields_num) {
452   size_t proc40_names_num, proc4x_names_num;
454   static int suppress_warning = 0;
456   switch (fields_num) {
457   case 34:
458   case 35:
459   case 36:
460   case 37:
461   case 38:
462     /* 4.0-only configuration */
463     proc40_names_num = fields_num;
464     break;
465   case 40:
466   case 41:
467     proc40_names_num = 35;
468     break;
469   case 42:
470   case 44:
471     proc40_names_num = 36;
472     break;
473   case 46:
474   case 47:
475   case 51:
476   case 53:
477     proc40_names_num = 37;
478     break;
479   case 54:
480   case 55:
481   case 57:
482   case 58:
483   case 59:
484   case 60:
485     proc40_names_num = 38;
486     break;
487   default:
488     if (!suppress_warning) {
489       WARNING("nfs plugin: Unexpected number of "
490               "fields for NFSv4 %s "
491               "statistics: %zu. ",
492               instance, fields_num);
493     }
495     if (fields_num > 34) {
496       /* safe fallback to basic nfs40 procedures */
497       fields_num = 34;
498       proc40_names_num = 34;
500       suppress_warning = 1;
501     } else {
502       return EINVAL;
503     }
504   }
506   nfs_submit_fields(4, instance, fields, proc40_names_num,
507                     nfs4_client40_procedures_names);
509   if (fields_num > proc40_names_num) {
510     proc4x_names_num = fields_num - proc40_names_num;
511     fields += proc40_names_num;
513     nfs_submit_fields(4, instance, fields, proc4x_names_num,
514                       nfs4_client4x_procedures_names);
515   }
517   return 0;
520 static void nfs_read_linux(FILE *fh, const char *inst) {
521   char buffer[1024];
523   char *fields[64];
524   int fields_num = 0;
526   if (fh == NULL)
527     return;
529   while (fgets(buffer, sizeof(buffer), fh) != NULL) {
530     fields_num = strsplit(buffer, fields, STATIC_ARRAY_SIZE(fields));
532     if (fields_num < 3)
533       continue;
535     if (strcmp(fields[0], "proc2") == 0 && report_v2) {
536       nfs_submit_fields_safe(/* version = */ 2, inst, fields + 2,
537                              (size_t)(fields_num - 2), nfs2_procedures_names,
538                              nfs2_procedures_names_num);
539     } else if (strncmp(fields[0], "proc3", 5) == 0 && report_v3) {
540       nfs_submit_fields_safe(/* version = */ 3, inst, fields + 2,
541                              (size_t)(fields_num - 2), nfs3_procedures_names,
542                              nfs3_procedures_names_num);
543     } else if (strcmp(fields[0], "proc4ops") == 0 && report_v4) {
544       if (inst[0] == 's')
545         nfs_submit_nfs4_server(inst, fields + 2, (size_t)(fields_num - 2));
546     } else if (strcmp(fields[0], "proc4") == 0 && report_v4) {
547       if (inst[0] == 'c')
548         nfs_submit_nfs4_client(inst, fields + 2, (size_t)(fields_num - 2));
549     }
550   } /* while (fgets) */
551 } /* void nfs_read_linux */
552 #endif /* KERNEL_LINUX */
554 #if HAVE_LIBKSTAT
555 static int nfs_read_kstat(kstat_t *ksp, int nfs_version, const char *inst,
556                           char const **proc_names, size_t proc_names_num) {
557   char plugin_instance[DATA_MAX_NAME_LEN];
558   value_t values[proc_names_num];
560   if (ksp == NULL)
561     return EINVAL;
563   snprintf(plugin_instance, sizeof(plugin_instance), "v%i%s", nfs_version,
564            inst);
566   kstat_read(kc, ksp, NULL);
567   for (size_t i = 0; i < proc_names_num; i++) {
568     /* The name passed to kstat_data_lookup() doesn't have the
569      * "const" modifier, so we need to copy the name here. */
570     char name[32];
571     sstrncpy(name, proc_names[i], sizeof(name));
573     values[i].counter = (derive_t)get_kstat_value(ksp, name);
574   }
576   nfs_procedures_submit(plugin_instance, proc_names, values, proc_names_num);
577   return 0;
579 #endif
581 #if KERNEL_LINUX
582 static int nfs_read(void) {
583   FILE *fh;
585   if ((fh = fopen("/proc/net/rpc/nfs", "r")) != NULL) {
586     nfs_read_linux(fh, "client");
587     fclose(fh);
588   }
590   if ((fh = fopen("/proc/net/rpc/nfsd", "r")) != NULL) {
591     nfs_read_linux(fh, "server");
592     fclose(fh);
593   }
595   return 0;
597 /* #endif KERNEL_LINUX */
599 #elif HAVE_LIBKSTAT
600 static int nfs_read(void) {
601   if (report_v2) {
602     nfs_read_kstat(nfs2_ksp_client, /* version = */ 2, "client",
603                    nfs2_procedures_names, nfs2_procedures_names_num);
604     nfs_read_kstat(nfs2_ksp_server, /* version = */ 2, "server",
605                    nfs2_procedures_names, nfs2_procedures_names_num);
606   }
607   if (report_v3) {
608     nfs_read_kstat(nfs3_ksp_client, /* version = */ 3, "client",
609                    nfs3_procedures_names, nfs3_procedures_names_num);
610     nfs_read_kstat(nfs3_ksp_server, /* version = */ 3, "server",
611                    nfs3_procedures_names, nfs3_procedures_names_num);
612   }
613   if (report_v4) {
614     nfs_read_kstat(nfs4_ksp_client, /* version = */ 4, "client",
615                    nfs4_procedures_names, nfs4_procedures_names_num);
616     nfs_read_kstat(nfs4_ksp_server, /* version = */ 4, "server",
617                    nfs4_procedures_names, nfs4_procedures_names_num);
618   }
620   return 0;
622 #endif /* HAVE_LIBKSTAT */
624 void module_register(void) {
625   plugin_register_config("nfs", nfs_config, config_keys, config_keys_num);
626   plugin_register_init("nfs", nfs_init);
627   plugin_register_read("nfs", nfs_read);
628 } /* void module_register */