3 * Copyright (C) 2005,2006 Jason Pepas
4 * Copyright (C) 2012,2013 Florian Forster
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.
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.
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
20 * Jason Pepas <cell at ices.utexas.edu>
21 * Florian octo Forster <octo at collectd.org>
22 * Cosmin Ioiart <cioiart at gmail.com>
36 see http://www.missioncriticallinux.com/orph/NFS-Statistics
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.
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.
52 Procedure NFS Version NFS Version 3
53 Number Procedures Procedures
79 static const char *nfs2_procedures_names[] =
100 static size_t nfs2_procedures_names_num = STATIC_ARRAY_SIZE (nfs2_procedures_names);
102 static const char *nfs3_procedures_names[] =
127 static size_t nfs3_procedures_names_num = STATIC_ARRAY_SIZE (nfs3_procedures_names);
130 static const char *nfs4_procedures_names[] =
168 "setclientid_confirm",
172 static size_t nfs4_procedures_names_num = STATIC_ARRAY_SIZE (nfs4_procedures_names);
176 static const char *nfs4_server40_procedures_names[] =
220 static size_t nfs4_server40_procedures_names_num = STATIC_ARRAY_SIZE (nfs4_server40_procedures_names);
222 static const char *nfs4_server41_procedures_names[] =
225 "bind_conn_to_session",
230 "get_dir_delegation",
245 static size_t nfs4_server41_procedures_names_num = STATIC_ARRAY_SIZE (nfs4_server41_procedures_names);
247 #define NFS4_SERVER40_NUM_PROC ( \
248 STATIC_ARRAY_SIZE (nfs4_server40_procedures_names) )
250 #define NFS4_SERVER41_NUM_PROC ( \
251 STATIC_ARRAY_SIZE (nfs4_server40_procedures_names) + \
252 STATIC_ARRAY_SIZE (nfs4_server41_procedures_names) )
254 #define NFS4_SERVER_MAX_PROC (NFS4_SERVER41_NUM_PROC)
256 static const char *nfs4_client40_procedures_names[] =
271 "setclientid_confirm",
292 "fs_locations", /* |35| 2.6.18 */
293 "release_lockowner", /* |42| 2.6.36 */
294 "secinfo", /* |46| 2.6.39 */
295 "fsid_present" /* |54| 3.13 */
298 static const char *nfs4_client41_procedures_names[] =
300 "exchange_id", /* |40| 2.6.30 */
301 "create_session", /* |40| 2.6.30 */
302 "destroy_session", /* |40| 2.6.30 */
303 "sequence", /* |40| 2.6.30 */
304 "get_lease_time", /* |40| 2.6.30 */
305 "reclaim_complete", /* |41| 2.6.33 */
306 "layoutget", /* |44| 2.6.37 */
307 "getdeviceinfo", /* |44| 2.6.37 */
308 "layoutcommit", /* |46| 2.6.39 */
309 "layoutreturn", /* |47| 3.0 */
310 "secinfo_no_name", /* |51| 3.1 */
311 "test_stateid", /* |51| 3.1 */
312 "free_stateid", /* |51| 3.1 */
313 "getdevicelist", /* |51| 3.1 */
314 "bind_conn_to_session", /* |53| 3.5 */
315 "destroy_clientid" /* |53| 3.5 */
318 #define NFS4_CLIENT40_NUM_PROC ( \
319 STATIC_ARRAY_SIZE (nfs4_client40_procedures_names) )
321 #define NFS4_CLIENT41_NUM_PROC ( \
322 STATIC_ARRAY_SIZE (nfs4_client40_procedures_names) + \
323 STATIC_ARRAY_SIZE (nfs4_client41_procedures_names) )
325 #define NFS4_CLIENT_MAX_PROC (NFS4_CLIENT41_NUM_PROC)
330 extern kstat_ctl_t *kc;
331 static kstat_t *nfs2_ksp_client;
332 static kstat_t *nfs2_ksp_server;
333 static kstat_t *nfs3_ksp_client;
334 static kstat_t *nfs3_ksp_server;
335 static kstat_t *nfs4_ksp_client;
336 static kstat_t *nfs4_ksp_server;
340 static int nfs_init (void)
344 /* #endif KERNEL_LINUX */
347 static int nfs_init (void)
349 kstat_t *ksp_chain = NULL;
351 nfs2_ksp_client = NULL;
352 nfs2_ksp_server = NULL;
353 nfs3_ksp_client = NULL;
354 nfs3_ksp_server = NULL;
355 nfs4_ksp_client = NULL;
356 nfs4_ksp_server = NULL;
361 for (ksp_chain = kc->kc_chain; ksp_chain != NULL;
362 ksp_chain = ksp_chain->ks_next)
364 if (strncmp (ksp_chain->ks_module, "nfs", 3) != 0)
366 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v2", 13) == 0)
367 nfs2_ksp_server = ksp_chain;
368 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v3", 13) == 0)
369 nfs3_ksp_server = ksp_chain;
370 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v4", 13) == 0)
371 nfs4_ksp_server = ksp_chain;
372 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v2", 12) == 0)
373 nfs2_ksp_client = ksp_chain;
374 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v3", 12) == 0)
375 nfs3_ksp_client = ksp_chain;
376 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v4", 12) == 0)
377 nfs4_ksp_client = ksp_chain;
384 static void nfs_procedures_submit (const char *plugin_instance,
385 const char **type_instances,
386 value_t *values, size_t values_num)
388 value_list_t vl = VALUE_LIST_INIT;
392 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
393 sstrncpy (vl.plugin, "nfs", sizeof (vl.plugin));
394 sstrncpy (vl.plugin_instance, plugin_instance,
395 sizeof (vl.plugin_instance));
396 sstrncpy (vl.type, "nfs_procedure", sizeof (vl.type));
398 for (i = 0; i < values_num; i++)
400 vl.values = values + i;
401 sstrncpy (vl.type_instance, type_instances[i],
402 sizeof (vl.type_instance));
403 plugin_dispatch_values (&vl);
405 } /* void nfs_procedures_submit */
408 static void nfs_submit_fields (int nfs_version, const char *instance,
409 char **fields, size_t fields_num, const char **proc_names)
411 char plugin_instance[DATA_MAX_NAME_LEN];
412 value_t values[fields_num];
415 ssnprintf (plugin_instance, sizeof (plugin_instance), "v%i%s",
416 nfs_version, instance);
418 for (i = 0; i < fields_num; i++)
419 (void) parse_value (fields[i], &values[i], DS_TYPE_DERIVE);
421 nfs_procedures_submit (plugin_instance, proc_names, values,
425 static int nfs_submit_fields_safe (int nfs_version, const char *instance,
426 char **fields, size_t fields_num,
427 const char **proc_names, size_t proc_names_num)
429 if (fields_num != proc_names_num)
431 WARNING ("nfs plugin: Wrong number of fields for "
432 "NFSv%i %s statistics. Expected %zu, got %zu.",
433 nfs_version, instance,
434 proc_names_num, fields_num);
438 nfs_submit_fields (nfs_version, instance, fields, fields_num,
444 static int nfs_submit_nfs4_server (const char *instance, char **fields,
447 static int suppress_warning = 0;
449 if (fields_num != NFS4_SERVER40_NUM_PROC &&
450 fields_num != NFS4_SERVER41_NUM_PROC)
452 if (!suppress_warning)
454 WARNING ("nfs plugin: Unexpected number of fields for "
455 "NFSv4 %s statistics: %zu. ",
456 instance, fields_num);
459 if (fields_num > NFS4_SERVER_MAX_PROC)
461 fields_num = NFS4_SERVER_MAX_PROC;
462 suppress_warning = 1;
470 nfs_submit_fields (4, instance, fields,
471 nfs4_server40_procedures_names_num,
472 nfs4_server40_procedures_names);
474 if (fields_num >= NFS4_SERVER41_NUM_PROC)
476 fields += nfs4_server40_procedures_names_num;
478 nfs_submit_fields (4, instance, fields,
479 nfs4_server41_procedures_names_num,
480 nfs4_server41_procedures_names);
486 static int nfs_submit_nfs4_client (const char *instance, char **fields,
489 size_t proc40_names_num, proc41_names_num;
491 static int suppress_warning = 0;
500 /* 4.0-only configuration */
501 proc40_names_num = fields_num;
505 proc40_names_num = 35;
509 proc40_names_num = 36;
515 proc40_names_num = 37;
518 proc40_names_num = 38;
521 if (!suppress_warning)
523 WARNING ("nfs plugin: Unexpected number of "
524 "fields for NFSv4 %s "
526 instance, fields_num);
531 /* safe fallback to basic nfs40 procedures */
533 proc40_names_num = 34;
535 suppress_warning = 1;
543 nfs_submit_fields (4, instance, fields, proc40_names_num,
544 nfs4_client40_procedures_names);
546 if (fields_num > proc40_names_num)
548 proc41_names_num = fields_num - proc40_names_num;
549 fields += proc40_names_num;
551 nfs_submit_fields (4, instance, fields,proc41_names_num,
552 nfs4_client41_procedures_names);
558 static void nfs_read_linux (FILE *fh, const char *inst)
568 while (fgets (buffer, sizeof (buffer), fh) != NULL)
570 fields_num = strsplit (buffer,
571 fields, STATIC_ARRAY_SIZE (fields));
576 if (strcmp (fields[0], "proc2") == 0)
578 nfs_submit_fields_safe (/* version = */ 2, inst,
579 fields + 2, (size_t) (fields_num - 2),
580 nfs2_procedures_names,
581 nfs2_procedures_names_num);
583 else if (strncmp (fields[0], "proc3", 5) == 0)
585 nfs_submit_fields_safe (/* version = */ 3, inst,
586 fields + 2, (size_t) (fields_num - 2),
587 nfs3_procedures_names,
588 nfs3_procedures_names_num);
590 else if (strcmp (fields[0], "proc4ops") == 0)
593 nfs_submit_nfs4_server (inst, fields + 2,
594 (size_t) (fields_num - 2));
596 else if (strcmp (fields[0], "proc4") == 0)
599 nfs_submit_nfs4_client (inst, fields + 2,
600 (size_t) (fields_num - 2));
602 } /* while (fgets) */
603 } /* void nfs_read_linux */
604 #endif /* KERNEL_LINUX */
607 static int nfs_read_kstat (kstat_t *ksp, int nfs_version, const char *inst,
608 char const **proc_names, size_t proc_names_num)
610 char plugin_instance[DATA_MAX_NAME_LEN];
611 value_t values[proc_names_num];
617 ssnprintf (plugin_instance, sizeof (plugin_instance), "v%i%s",
620 kstat_read(kc, ksp, NULL);
621 for (i = 0; i < proc_names_num; i++)
623 /* The name passed to kstat_data_lookup() doesn't have the
624 * "const" modifier, so we need to copy the name here. */
626 sstrncpy (name, proc_names[i], sizeof (name));
628 values[i].counter = (derive_t) get_kstat_value (ksp, name);
631 nfs_procedures_submit (plugin_instance, proc_names, values,
638 static int nfs_read (void)
642 if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
644 nfs_read_linux (fh, "client");
648 if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
650 nfs_read_linux (fh, "server");
656 /* #endif KERNEL_LINUX */
659 static int nfs_read (void)
661 nfs_read_kstat (nfs2_ksp_client, /* version = */ 2, "client",
662 nfs2_procedures_names, nfs2_procedures_names_num);
663 nfs_read_kstat (nfs2_ksp_server, /* version = */ 2, "server",
664 nfs2_procedures_names, nfs2_procedures_names_num);
665 nfs_read_kstat (nfs3_ksp_client, /* version = */ 3, "client",
666 nfs3_procedures_names, nfs3_procedures_names_num);
667 nfs_read_kstat (nfs3_ksp_server, /* version = */ 3, "server",
668 nfs3_procedures_names, nfs3_procedures_names_num);
669 nfs_read_kstat (nfs4_ksp_client, /* version = */ 4, "client",
670 nfs4_procedures_names, nfs4_procedures_names_num);
671 nfs_read_kstat (nfs4_ksp_server, /* version = */ 4, "server",
672 nfs4_procedures_names, nfs4_procedures_names_num);
676 #endif /* HAVE_LIBKSTAT */
678 void module_register (void)
680 plugin_register_init ("nfs", nfs_init);
681 plugin_register_read ("nfs", nfs_read);
682 } /* void module_register */