Code

Merge branch 'collectd-5.2'
[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  *   Cosmin Ioiart <cioiart at gmail.com>
22  **/
24 #include "collectd.h"
25 #include "common.h"
26 #include "plugin.h"
28 #if HAVE_KSTAT_H
29 #include <kstat.h>
30 #endif
32 /*
33 see /proc/net/rpc/nfs
34 see http://www.missioncriticallinux.com/orph/NFS-Statistics
36 net x x x x
37 rpc_stat.netcnt         Not used; always zero.
38 rpc_stat.netudpcnt      Not used; always zero.
39 rpc_stat.nettcpcnt      Not used; always zero.
40 rpc_stat.nettcpconn     Not used; always zero.
42 rpc x x x
43 rpc_stat.rpccnt             The number of RPC calls.
44 rpc_stat.rpcretrans         The number of retransmitted RPC calls.
45 rpc_stat.rpcauthrefresh     The number of credential refreshes.
47 proc2 x x x...
48 proc3 x x x...
50 Procedure   NFS Version NFS Version 3
51 Number      Procedures  Procedures
53 0           null        null
54 1           getattr     getattr
55 2           setattr     setattr
56 3           root        lookup
57 4           lookup      access
58 5           readlink    readlink
59 6           read        read
60 7           wrcache     write
61 8           write       create
62 9           create      mkdir
63 10          remove      symlink
64 11          rename      mknod
65 12          link        remove
66 13          symlink     rmdir
67 14          mkdir       rename
68 15          rmdir       link
69 16          readdir     readdir
70 17          fsstat      readdirplus
71 18                      fsstat
72 19                      fsinfo
73 20                      pathconf
74 21                      commit
75 */
77 static const char *nfs2_procedures_names[] =
78 {
79         "null",
80         "getattr",
81         "setattr",
82         "root",
83         "lookup",
84         "readlink",
85         "read",
86         "wrcache",
87         "write",
88         "create",
89         "remove",
90         "rename",
91         "link",
92         "symlink",
93         "mkdir",
94         "rmdir",
95         "readdir",
96         "fsstat"
97 };
98 static size_t nfs2_procedures_names_num = STATIC_ARRAY_SIZE (nfs2_procedures_names);
100 static const char *nfs3_procedures_names[] =
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 };
125 static size_t nfs3_procedures_names_num = STATIC_ARRAY_SIZE (nfs3_procedures_names);
127 #if HAVE_LIBKSTAT
128 static const char *nfs4_procedures_names[] =
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 };
170 static size_t nfs4_procedures_names_num = STATIC_ARRAY_SIZE (nfs4_procedures_names);
171 #endif
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
183 /* Possibly TODO: NFSv4 statistics */
185 #if KERNEL_LINUX
186 static int nfs_init (void)
188         return (0);
190 /* #endif KERNEL_LINUX */
192 #elif HAVE_LIBKSTAT
193 static int nfs_init (void)
195         kstat_t *ksp_chain = NULL;
197         nfs2_ksp_client = NULL;
198         nfs2_ksp_server = NULL;
199         nfs3_ksp_client = NULL;
200         nfs3_ksp_server = NULL;
201         nfs4_ksp_client = NULL;
202         nfs4_ksp_server = NULL;
204         if (kc == NULL)
205                 return (-1);
207         for (ksp_chain = kc->kc_chain; ksp_chain != NULL;
208                         ksp_chain = ksp_chain->ks_next)
209         {
210                 if (strncmp (ksp_chain->ks_module, "nfs", 3) != 0)
211                         continue;
212                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v2", 13) == 0)
213                         nfs2_ksp_server = ksp_chain;
214                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v3", 13) == 0)
215                         nfs3_ksp_server = ksp_chain;
216                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v4", 13) == 0)
217                         nfs4_ksp_server = ksp_chain;
218                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v2", 12) == 0)
219                         nfs2_ksp_client = ksp_chain;
220                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v3", 12) == 0)
221                         nfs3_ksp_client = ksp_chain;
222                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v4", 12) == 0)
223                         nfs4_ksp_client = ksp_chain;
224         }
226         return (0);
227 } /* int nfs_init */
228 #endif
230 static void nfs_procedures_submit (const char *plugin_instance,
231                 const char **type_instances,
232                 value_t *values, size_t values_num)
234         value_list_t vl = VALUE_LIST_INIT;
235         size_t i;
237         vl.values_len = 1;
238         sstrncpy (vl.host, hostname_g, sizeof (vl.host));
239         sstrncpy (vl.plugin, "nfs", sizeof (vl.plugin));
240         sstrncpy (vl.plugin_instance, plugin_instance,
241                         sizeof (vl.plugin_instance));
242         sstrncpy (vl.type, "nfs_procedure", sizeof (vl.type));
244         for (i = 0; i < values_num; i++)
245         {
246                 vl.values = values + i;
247                 sstrncpy (vl.type_instance, type_instances[i],
248                                 sizeof (vl.type_instance));
249                 plugin_dispatch_values (&vl);
250         }
251 } /* void nfs_procedures_submit */
253 #if KERNEL_LINUX
254 static int nfs_submit_fields (int nfs_version, const char *instance,
255                 char **fields, size_t fields_num,
256                 const char **proc_names, size_t proc_names_num)
258         char plugin_instance[DATA_MAX_NAME_LEN];
259         value_t values[fields_num];
260         size_t i;
262         if (fields_num != proc_names_num)
263         {
264                 WARNING ("nfs plugin: Wrong number of fields for "
265                                 "NFSv%i %s statistics. Expected %zu, got %zu.",
266                                 nfs_version, instance,
267                                 proc_names_num, fields_num);
268                 return (EINVAL);
269         }
271         ssnprintf (plugin_instance, sizeof (plugin_instance), "v%i%s",
272                         nfs_version, instance);
274         for (i = 0; i < proc_names_num; i++)
275                 (void) parse_value (fields[i], &values[i], DS_TYPE_DERIVE);
277         nfs_procedures_submit (plugin_instance, proc_names, values,
278                         proc_names_num);
280         return (0);
283 static void nfs_read_linux (FILE *fh, char *inst)
285         char buffer[1024];
287         char *fields[48];
288         int fields_num = 0;
290         if (fh == NULL)
291                 return;
293         while (fgets (buffer, sizeof (buffer), fh) != NULL)
294         {
295                 fields_num = strsplit (buffer,
296                                 fields, STATIC_ARRAY_SIZE (fields));
298                 if (fields_num < 3)
299                         continue;
301                 if (strcmp (fields[0], "proc2") == 0)
302                 {
303                         nfs_submit_fields (/* version = */ 2, inst,
304                                         fields + 2, (size_t) (fields_num - 2),
305                                         nfs2_procedures_names,
306                                         nfs2_procedures_names_num);
307                 }
308                 else if (strncmp (fields[0], "proc3", 5) == 0)
309                 {
310                         nfs_submit_fields (/* version = */ 3, inst,
311                                         fields + 2, (size_t) (fields_num - 2),
312                                         nfs3_procedures_names,
313                                         nfs3_procedures_names_num);
314                 }
315         } /* while (fgets) */
316 } /* void nfs_read_linux */
317 #endif /* KERNEL_LINUX */
319 #if HAVE_LIBKSTAT
320 static int nfs_read_kstat (kstat_t *ksp, int nfs_version, char *inst,
321                 const char **proc_names, size_t proc_names_num)
323         char plugin_instance[DATA_MAX_NAME_LEN];
324         value_t values[proc_names_num];
325         size_t i;
327         if (ksp == NULL)
328                 return (EINVAL);
330         ssnprintf (plugin_instance, sizeof (plugin_instance), "v%i%s",
331                         nfs_version, inst);
333         kstat_read(kc, ksp, NULL);
334         for (i = 0; i < proc_names_num; i++)
335                 values[i].counter = (derive_t) get_kstat_value (ksp,
336                                 (char *)proc_names[i]);
338         nfs_procedures_submit (plugin_instance, proc_names, values,
339                         proc_names_num);
340         return (0);
342 #endif
344 #if KERNEL_LINUX
345 static int nfs_read (void)
347         FILE *fh;
349         if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
350         {
351                 nfs_read_linux (fh, "client");
352                 fclose (fh);
353         }
355         if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
356         {
357                 nfs_read_linux (fh, "server");
358                 fclose (fh);
359         }
361         return (0);
363 /* #endif KERNEL_LINUX */
365 #elif HAVE_LIBKSTAT
366 static int nfs_read (void)
368         nfs_read_kstat (nfs2_ksp_client, /* version = */ 2, "client",
369                         nfs2_procedures_names, nfs2_procedures_names_num);
370         nfs_read_kstat (nfs2_ksp_server, /* version = */ 2, "server",
371                         nfs2_procedures_names, nfs2_procedures_names_num);
372         nfs_read_kstat (nfs3_ksp_client, /* version = */ 3, "client",
373                         nfs3_procedures_names, nfs3_procedures_names_num);
374         nfs_read_kstat (nfs3_ksp_server, /* version = */ 3, "server",
375                         nfs3_procedures_names, nfs3_procedures_names_num);
376         nfs_read_kstat (nfs4_ksp_client, /* version = */ 4, "client",
377                         nfs4_procedures_names, nfs4_procedures_names_num);
378         nfs_read_kstat (nfs4_ksp_server, /* version = */ 4, "server",
379                         nfs4_procedures_names, nfs4_procedures_names_num);
381         return (0);
383 #endif /* HAVE_LIBKSTAT */
385 void module_register (void)
387         plugin_register_init ("nfs", nfs_init);
388         plugin_register_read ("nfs", nfs_read);
389 } /* void module_register */