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