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[] =
101 {
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[] =
129 {
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)
187 {
188 return (0);
189 }
190 /* #endif KERNEL_LINUX */
192 #elif HAVE_LIBKSTAT
193 static int nfs_init (void)
194 {
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)
233 {
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_secure (&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)
257 {
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);
281 }
283 static void nfs_read_linux (FILE *fh, char *inst)
284 {
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)
322 {
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, proc_names[i]);
337 nfs_procedures_submit (plugin_instance, proc_names, values,
338 proc_names_num);
339 }
340 #endif
342 #if KERNEL_LINUX
343 static int nfs_read (void)
344 {
345 FILE *fh;
347 if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
348 {
349 nfs_read_linux (fh, "client");
350 fclose (fh);
351 }
353 if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
354 {
355 nfs_read_linux (fh, "server");
356 fclose (fh);
357 }
359 return (0);
360 }
361 /* #endif KERNEL_LINUX */
363 #elif HAVE_LIBKSTAT
364 static int nfs_read (void)
365 {
366 nfs_read_kstat (nfs2_ksp_client, /* version = */ 2, "client",
367 nfs2_procedures_names, nfs2_procedures_names_num);
368 nfs_read_kstat (nfs2_ksp_server, /* version = */ 2, "server",
369 nfs2_procedures_names, nfs2_procedures_names_num);
370 nfs_read_kstat (nfs3_ksp_client, /* version = */ 3, "client",
371 nfs3_procedures_names, nfs3_procedures_names_num);
372 nfs_read_kstat (nfs3_ksp_server, /* version = */ 3, "server",
373 nfs3_procedures_names, nfs3_procedures_names_num);
374 nfs_read_kstat (nfs4_ksp_client, /* version = */ 4, "client",
375 nfs4_procedures_names, nfs4_procedures_names_num);
376 nfs_read_kstat (nfs4_ksp_server, /* version = */ 4, "server",
377 nfs4_procedures_names, nfs4_procedures_names_num);
379 return (0);
380 }
381 #endif /* HAVE_LIBKSTAT */
383 void module_register (void)
384 {
385 plugin_register_init ("nfs", nfs_init);
386 plugin_register_read ("nfs", nfs_read);
387 } /* void module_register */