Code

Merge remote-tracking branch 'github/pr/387'
[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"
26 #include "common.h"
27 #include "plugin.h"
29 #if HAVE_KSTAT_H
30 #include <kstat.h>
31 #endif
33 /*
34 see /proc/net/rpc/nfs
35 see http://www.missioncriticallinux.com/orph/NFS-Statistics
37 net x x x x
38 rpc_stat.netcnt         Not used; always zero.
39 rpc_stat.netudpcnt      Not used; always zero.
40 rpc_stat.nettcpcnt      Not used; always zero.
41 rpc_stat.nettcpconn     Not used; always zero.
43 rpc x x x
44 rpc_stat.rpccnt             The number of RPC calls.
45 rpc_stat.rpcretrans         The number of retransmitted RPC calls.
46 rpc_stat.rpcauthrefresh     The number of credential refreshes.
48 proc2 x x x...
49 proc3 x x x...
51 Procedure   NFS Version NFS Version 3
52 Number      Procedures  Procedures
54 0           null        null
55 1           getattr     getattr
56 2           setattr     setattr
57 3           root        lookup
58 4           lookup      access
59 5           readlink    readlink
60 6           read        read
61 7           wrcache     write
62 8           write       create
63 9           create      mkdir
64 10          remove      symlink
65 11          rename      mknod
66 12          link        remove
67 13          symlink     rmdir
68 14          mkdir       rename
69 15          rmdir       link
70 16          readdir     readdir
71 17          fsstat      readdirplus
72 18                      fsstat
73 19                      fsinfo
74 20                      pathconf
75 21                      commit
76 */
78 static const char *nfs2_procedures_names[] =
79 {
80         "null",
81         "getattr",
82         "setattr",
83         "root",
84         "lookup",
85         "readlink",
86         "read",
87         "wrcache",
88         "write",
89         "create",
90         "remove",
91         "rename",
92         "link",
93         "symlink",
94         "mkdir",
95         "rmdir",
96         "readdir",
97         "fsstat"
98 };
99 static size_t nfs2_procedures_names_num = STATIC_ARRAY_SIZE (nfs2_procedures_names);
101 static const char *nfs3_procedures_names[] =
103         "null",
104         "getattr",
105         "setattr",
106         "lookup",
107         "access",
108         "readlink",
109         "read",
110         "write",
111         "create",
112         "mkdir",
113         "symlink",
114         "mknod",
115         "remove",
116         "rmdir",
117         "rename",
118         "link",
119         "readdir",
120         "readdirplus",
121         "fsstat",
122         "fsinfo",
123         "pathconf",
124         "commit"
125 };
126 static size_t nfs3_procedures_names_num = STATIC_ARRAY_SIZE (nfs3_procedures_names);
128 #if HAVE_LIBKSTAT
129 static const char *nfs4_procedures_names[] =
131         "null",
132         "compound",
133         "reserved",
134         "access",
135         "close",
136         "commit",
137         "create",
138         "delegpurge",
139         "delegreturn",
140         "getattr",
141         "getfh",
142         "link",
143         "lock",
144         "lockt",
145         "locku",
146         "lookup",
147         "lookupp",
148         "nverify",
149         "open",
150         "openattr",
151         "open_confirm",
152         "open_downgrade",
153         "putfh",
154         "putpubfh",
155         "putrootfh",
156         "read",
157         "readdir",
158         "readlink",
159         "remove",
160         "rename",
161         "renew",
162         "restorefh",
163         "savefh",
164         "secinfo",
165         "setattr",
166         "setclientid",
167         "setclientid_confirm",
168         "verify",
169         "write"
170 };
171 static size_t nfs4_procedures_names_num = STATIC_ARRAY_SIZE (nfs4_procedures_names);
172 #endif
174 #if HAVE_LIBKSTAT
175 extern kstat_ctl_t *kc;
176 static kstat_t *nfs2_ksp_client;
177 static kstat_t *nfs2_ksp_server;
178 static kstat_t *nfs3_ksp_client;
179 static kstat_t *nfs3_ksp_server;
180 static kstat_t *nfs4_ksp_client;
181 static kstat_t *nfs4_ksp_server;
182 #endif
184 /* Possibly TODO: NFSv4 statistics */
186 #if KERNEL_LINUX
187 static int nfs_init (void)
189         return (0);
191 /* #endif KERNEL_LINUX */
193 #elif HAVE_LIBKSTAT
194 static int nfs_init (void)
196         kstat_t *ksp_chain = NULL;
198         nfs2_ksp_client = NULL;
199         nfs2_ksp_server = NULL;
200         nfs3_ksp_client = NULL;
201         nfs3_ksp_server = NULL;
202         nfs4_ksp_client = NULL;
203         nfs4_ksp_server = NULL;
205         if (kc == NULL)
206                 return (-1);
208         for (ksp_chain = kc->kc_chain; ksp_chain != NULL;
209                         ksp_chain = ksp_chain->ks_next)
210         {
211                 if (strncmp (ksp_chain->ks_module, "nfs", 3) != 0)
212                         continue;
213                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v2", 13) == 0)
214                         nfs2_ksp_server = ksp_chain;
215                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v3", 13) == 0)
216                         nfs3_ksp_server = ksp_chain;
217                 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v4", 13) == 0)
218                         nfs4_ksp_server = ksp_chain;
219                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v2", 12) == 0)
220                         nfs2_ksp_client = ksp_chain;
221                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v3", 12) == 0)
222                         nfs3_ksp_client = ksp_chain;
223                 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v4", 12) == 0)
224                         nfs4_ksp_client = ksp_chain;
225         }
227         return (0);
228 } /* int nfs_init */
229 #endif
231 static void nfs_procedures_submit (const char *plugin_instance,
232                 const char **type_instances,
233                 value_t *values, size_t values_num)
235         value_list_t vl = VALUE_LIST_INIT;
236         size_t i;
238         vl.values_len = 1;
239         sstrncpy (vl.host, hostname_g, sizeof (vl.host));
240         sstrncpy (vl.plugin, "nfs", sizeof (vl.plugin));
241         sstrncpy (vl.plugin_instance, plugin_instance,
242                         sizeof (vl.plugin_instance));
243         sstrncpy (vl.type, "nfs_procedure", sizeof (vl.type));
245         for (i = 0; i < values_num; i++)
246         {
247                 vl.values = values + i;
248                 sstrncpy (vl.type_instance, type_instances[i],
249                                 sizeof (vl.type_instance));
250                 plugin_dispatch_values (&vl);
251         }
252 } /* void nfs_procedures_submit */
254 #if KERNEL_LINUX
255 static int nfs_submit_fields (int nfs_version, const char *instance,
256                 char **fields, size_t fields_num,
257                 const char **proc_names, size_t proc_names_num)
259         char plugin_instance[DATA_MAX_NAME_LEN];
260         value_t values[fields_num];
261         size_t i;
263         if (fields_num != proc_names_num)
264         {
265                 WARNING ("nfs plugin: Wrong number of fields for "
266                                 "NFSv%i %s statistics. Expected %zu, got %zu.",
267                                 nfs_version, instance,
268                                 proc_names_num, fields_num);
269                 return (EINVAL);
270         }
272         ssnprintf (plugin_instance, sizeof (plugin_instance), "v%i%s",
273                         nfs_version, instance);
275         for (i = 0; i < proc_names_num; i++)
276                 (void) parse_value (fields[i], &values[i], DS_TYPE_DERIVE);
278         nfs_procedures_submit (plugin_instance, proc_names, values,
279                         proc_names_num);
281         return (0);
284 static void nfs_read_linux (FILE *fh, char *inst)
286         char buffer[1024];
288         char *fields[48];
289         int fields_num = 0;
291         if (fh == NULL)
292                 return;
294         while (fgets (buffer, sizeof (buffer), fh) != NULL)
295         {
296                 fields_num = strsplit (buffer,
297                                 fields, STATIC_ARRAY_SIZE (fields));
299                 if (fields_num < 3)
300                         continue;
302                 if (strcmp (fields[0], "proc2") == 0)
303                 {
304                         nfs_submit_fields (/* version = */ 2, inst,
305                                         fields + 2, (size_t) (fields_num - 2),
306                                         nfs2_procedures_names,
307                                         nfs2_procedures_names_num);
308                 }
309                 else if (strncmp (fields[0], "proc3", 5) == 0)
310                 {
311                         nfs_submit_fields (/* version = */ 3, inst,
312                                         fields + 2, (size_t) (fields_num - 2),
313                                         nfs3_procedures_names,
314                                         nfs3_procedures_names_num);
315                 }
316         } /* while (fgets) */
317 } /* void nfs_read_linux */
318 #endif /* KERNEL_LINUX */
320 #if HAVE_LIBKSTAT
321 static int nfs_read_kstat (kstat_t *ksp, int nfs_version, char *inst,
322                 char const **proc_names, size_t proc_names_num)
324         char plugin_instance[DATA_MAX_NAME_LEN];
325         value_t values[proc_names_num];
326         size_t i;
328         if (ksp == NULL)
329                 return (EINVAL);
331         ssnprintf (plugin_instance, sizeof (plugin_instance), "v%i%s",
332                         nfs_version, inst);
334         kstat_read(kc, ksp, NULL);
335         for (i = 0; i < proc_names_num; i++)
336         {
337                 /* The name passed to kstat_data_lookup() doesn't have the
338                  * "const" modifier, so we need to copy the name here. */
339                 char name[32];
340                 sstrncpy (name, proc_names[i], sizeof (name));
342                 values[i].counter = (derive_t) get_kstat_value (ksp, name);
343         }
345         nfs_procedures_submit (plugin_instance, proc_names, values,
346                         proc_names_num);
347         return (0);
349 #endif
351 #if KERNEL_LINUX
352 static int nfs_read (void)
354         FILE *fh;
356         if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
357         {
358                 nfs_read_linux (fh, "client");
359                 fclose (fh);
360         }
362         if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
363         {
364                 nfs_read_linux (fh, "server");
365                 fclose (fh);
366         }
368         return (0);
370 /* #endif KERNEL_LINUX */
372 #elif HAVE_LIBKSTAT
373 static int nfs_read (void)
375         nfs_read_kstat (nfs2_ksp_client, /* version = */ 2, "client",
376                         nfs2_procedures_names, nfs2_procedures_names_num);
377         nfs_read_kstat (nfs2_ksp_server, /* version = */ 2, "server",
378                         nfs2_procedures_names, nfs2_procedures_names_num);
379         nfs_read_kstat (nfs3_ksp_client, /* version = */ 3, "client",
380                         nfs3_procedures_names, nfs3_procedures_names_num);
381         nfs_read_kstat (nfs3_ksp_server, /* version = */ 3, "server",
382                         nfs3_procedures_names, nfs3_procedures_names_num);
383         nfs_read_kstat (nfs4_ksp_client, /* version = */ 4, "client",
384                         nfs4_procedures_names, nfs4_procedures_names_num);
385         nfs_read_kstat (nfs4_ksp_server, /* version = */ 4, "server",
386                         nfs4_procedures_names, nfs4_procedures_names_num);
388         return (0);
390 #endif /* HAVE_LIBKSTAT */
392 void module_register (void)
394         plugin_register_init ("nfs", nfs_init);
395         plugin_register_read ("nfs", nfs_read);
396 } /* void module_register */