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 **/
23 #include "collectd.h"
24 #include "common.h"
25 #include "plugin.h"
27 #if HAVE_KSTAT_H
28 #include <kstat.h>
29 #endif
31 /*
32 see /proc/net/rpc/nfs
33 see http://www.missioncriticallinux.com/orph/NFS-Statistics
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.
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.
46 proc2 x x x...
47 proc3 x x x...
49 Procedure NFS Version NFS Version 3
50 Number Procedures Procedures
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 */
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);
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);
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
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
182 /* Possibly TODO: NFSv4 statistics */
184 #if KERNEL_LINUX
185 static int nfs_init (void)
186 {
187 return (0);
188 }
189 /* #endif KERNEL_LINUX */
191 #elif HAVE_LIBKSTAT
192 static int nfs_init (void)
193 {
194 kstat_t *ksp_chain = NULL;
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;
203 if (kc == NULL)
204 return (-1);
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 }
225 return (0);
226 } /* int nfs_init */
227 #endif
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;
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));
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 */
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;
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 }
270 ssnprintf (plugin_instance, sizeof (plugin_instance), "v%i%s",
271 nfs_version, instance);
273 for (i = 0; i < proc_names_num; i++)
274 (void) parse_value (fields[i], &values[i], DS_TYPE_DERIVE);
276 nfs_procedures_submit (plugin_instance, proc_names, values,
277 proc_names_num);
279 return (0);
280 }
282 static void nfs_read_linux (FILE *fh, char *inst)
283 {
284 char buffer[1024];
286 char *fields[48];
287 int fields_num = 0;
289 if (fh == NULL)
290 return;
292 while (fgets (buffer, sizeof (buffer), fh) != NULL)
293 {
294 fields_num = strsplit (buffer,
295 fields, STATIC_ARRAY_SIZE (fields));
297 if (fields_num < 3)
298 continue;
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 */
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;
326 if (ksp == NULL)
327 return (EINVAL);
329 ssnprintf (plugin_instance, sizeof (plugin_instance), "v%i%s",
330 nfs_version, inst);
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]);
336 nfs_procedures_submit (plugin_instance, proc_names, values,
337 proc_names_num);
338 }
339 #endif
341 #if KERNEL_LINUX
342 static int nfs_read (void)
343 {
344 FILE *fh;
346 if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
347 {
348 nfs_read_linux (fh, "client");
349 fclose (fh);
350 }
352 if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
353 {
354 nfs_read_linux (fh, "server");
355 fclose (fh);
356 }
358 return (0);
359 }
360 /* #endif KERNEL_LINUX */
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);
378 return (0);
379 }
380 #endif /* HAVE_LIBKSTAT */
382 void module_register (void)
383 {
384 plugin_register_init ("nfs", nfs_init);
385 plugin_register_read ("nfs", nfs_read);
386 } /* void module_register */