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"
26 #include "utils_debug.h"
28 #define MODULE_NAME "nfs"
30 /* #if defined(KERNEL_LINUX) || defined(HAVE_LIBKSTAT) */
31 #if KERNEL_LINUX
32 # define NFS_HAVE_READ 1
33 #else
34 # define NFS_HAVE_READ 0
35 #endif
37 /*
38 see /proc/net/rpc/nfs
39 see http://www.missioncriticallinux.com/orph/NFS-Statistics
41 net x x x x
42 rpc_stat.netcnt Not used; always zero.
43 rpc_stat.netudpcnt Not used; always zero.
44 rpc_stat.nettcpcnt Not used; always zero.
45 rpc_stat.nettcpconn Not used; always zero.
47 rpc x x x
48 rpc_stat.rpccnt The number of RPC calls.
49 rpc_stat.rpcretrans The number of retransmitted RPC calls.
50 rpc_stat.rpcauthrefresh The number of credential refreshes.
52 proc2 x x x...
53 proc3 x x x...
55 Procedure NFS Version NFS Version 3
56 Number Procedures Procedures
58 0 null null
59 1 getattr getattr
60 2 setattr setattr
61 3 root lookup
62 4 lookup access
63 5 readlink readlink
64 6 read read
65 7 wrcache write
66 8 write create
67 9 create mkdir
68 10 remove symlink
69 11 rename mknod
70 12 link remove
71 13 symlink rmdir
72 14 mkdir rename
73 15 rmdir link
74 16 readdir readdir
75 17 fsstat readdirplus
76 18 fsstat
77 19 fsinfo
78 20 pathconf
79 21 commit
80 */
82 static data_source_t procedure_dsrc[1] =
83 {
84 {"value", DS_TYPE_COUNTER, 0, 4294967295.0}
85 };
87 static data_set_t procedure_ds =
88 {
89 "nfs_procedure", 1, procedure_dsrc
90 };
92 #if NFS_HAVE_READ
93 static const char *nfs2_procedures_names[] =
94 {
95 "null",
96 "getattr",
97 "setattr",
98 "root",
99 "lookup",
100 "readlink",
101 "read",
102 "wrcache",
103 "write",
104 "create",
105 "remove",
106 "rename",
107 "link",
108 "symlink",
109 "mkdir",
110 "rmdir",
111 "readdir",
112 "fsstat",
113 NULL
114 };
115 static int nfs2_procedures_names_num = 18;
117 static const char *nfs3_procedures_names[] =
118 {
119 "null",
120 "getattr",
121 "setattr",
122 "lookup",
123 "access",
124 "readlink",
125 "read",
126 "write",
127 "create",
128 "mkdir",
129 "symlink",
130 "mknod",
131 "remove",
132 "rmdir",
133 "rename",
134 "link",
135 "readdir",
136 "readdirplus",
137 "fsstat",
138 "fsinfo",
139 "pathconf",
140 "commit",
141 NULL
142 };
143 static int nfs3_procedures_names_num = 22;
145 #if HAVE_LIBKSTAT && 0
146 extern kstat_ctl_t *kc;
147 static kstat_t *nfs2_ksp_client;
148 static kstat_t *nfs2_ksp_server;
149 static kstat_t *nfs3_ksp_client;
150 static kstat_t *nfs3_ksp_server;
151 static kstat_t *nfs4_ksp_client;
152 static kstat_t *nfs4_ksp_server;
153 #endif
155 /* Possibly TODO: NFSv4 statistics */
157 #if 0
158 static int nfs_init (void)
159 {
160 #if HAVE_LIBKSTAT && 0
161 kstat_t *ksp_chain;
163 nfs2_ksp_client = NULL;
164 nfs2_ksp_server = NULL;
165 nfs3_ksp_client = NULL;
166 nfs3_ksp_server = NULL;
167 nfs4_ksp_client = NULL;
168 nfs4_ksp_server = NULL;
170 if (kc == NULL)
171 return;
173 for (ksp_chain = kc->kc_chain; ksp_chain != NULL;
174 ksp_chain = ksp_chain->ks_next)
175 {
176 if (strncmp (ksp_chain->ks_module, "nfs", 3) != 0)
177 continue;
178 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v2", 13) == 0)
179 nfs2_ksp_server = ksp_chain;
180 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v3", 13) == 0)
181 nfs3_ksp_server = ksp_chain;
182 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v4", 13) == 0)
183 nfs4_ksp_server = ksp_chain;
184 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v2", 12) == 0)
185 nfs2_ksp_client = ksp_chain;
186 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v3", 12) == 0)
187 nfs3_ksp_client = ksp_chain;
188 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v4", 12) == 0)
189 nfs4_ksp_client = ksp_chain;
190 }
191 #endif
193 return (0);
194 } /* int nfs_init */
195 #endif
197 #define BUFSIZE 1024
198 static void nfs_procedures_submit (const char *plugin_instance,
199 unsigned long long *val, const char **names, int len)
200 {
201 value_t values[1];
202 value_list_t vl = VALUE_LIST_INIT;
203 int i;
205 vl.values = values;
206 vl.values_len = 1;
207 vl.time = time (NULL);
208 strcpy (vl.host, hostname);
209 strcpy (vl.plugin, "nfs");
210 strncpy (vl.plugin_instance, plugin_instance,
211 sizeof (vl.plugin_instance));
213 for (i = 0; i < len; i++)
214 {
215 values[0].counter = val[i];
216 strncpy (vl.type_instance, names[i],
217 sizeof (vl.type_instance));
218 DBG ("%s-%s/nfs_procedure-%s = %llu",
219 vl.plugin, vl.plugin_instance,
220 vl.type_instance, val[i]);
221 plugin_dispatch_values ("nfs_procedure", &vl);
222 }
223 } /* void nfs_procedures_submit */
225 #if KERNEL_LINUX
226 static void nfs_read_stats_file (FILE *fh, char *inst)
227 {
228 char buffer[BUFSIZE];
230 char plugin_instance[DATA_MAX_NAME_LEN];
232 char *fields[48];
233 int numfields = 0;
235 if (fh == NULL)
236 return;
238 while (fgets (buffer, BUFSIZE, fh) != NULL)
239 {
240 numfields = strsplit (buffer, fields, 48);
242 if (((numfields - 2) != nfs2_procedures_names_num)
243 && ((numfields - 2)
244 != nfs3_procedures_names_num))
245 continue;
247 if (strcmp (fields[0], "proc2") == 0)
248 {
249 int i;
250 unsigned long long *values;
252 if ((numfields - 2) != nfs2_procedures_names_num)
253 {
254 syslog (LOG_WARNING, "nfs plugin: Wrong "
255 "number of fields (= %i) "
256 "for NFSv2 statistics.",
257 numfields - 2);
258 continue;
259 }
261 snprintf (plugin_instance, sizeof (plugin_instance),
262 "v2%s", inst);
263 plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
265 values = (unsigned long long *) malloc (nfs2_procedures_names_num * sizeof (unsigned long long));
266 if (values == NULL)
267 {
268 syslog (LOG_ERR, "nfs plugin: malloc "
269 "failed: %s",
270 strerror (errno));
271 continue;
272 }
274 for (i = 0; i < nfs2_procedures_names_num; i++)
275 values[i] = atoll (fields[i + 2]);
277 nfs_procedures_submit (plugin_instance, values,
278 nfs2_procedures_names,
279 nfs2_procedures_names_num);
281 free (values);
282 }
283 else if (strncmp (fields[0], "proc3", 5) == 0)
284 {
285 int i;
286 unsigned long long *values;
288 if ((numfields - 2) != nfs3_procedures_names_num)
289 {
290 syslog (LOG_WARNING, "nfs plugin: Wrong "
291 "number of fields (= %i) "
292 "for NFSv3 statistics.",
293 numfields - 2);
294 continue;
295 }
297 snprintf (plugin_instance, sizeof (plugin_instance),
298 "v3%s", inst);
299 plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
301 values = (unsigned long long *) malloc (nfs3_procedures_names_num * sizeof (unsigned long long));
302 if (values == NULL)
303 {
304 syslog (LOG_ERR, "nfs plugin: malloc "
305 "failed: %s",
306 strerror (errno));
307 continue;
308 }
310 for (i = 0; i < nfs3_procedures_names_num; i++)
311 values[i] = atoll (fields[i + 2]);
313 nfs_procedures_submit (plugin_instance, values,
314 nfs3_procedures_names,
315 nfs3_procedures_names_num);
317 free (values);
318 }
319 } /* while (fgets (buffer, BUFSIZE, fh) != NULL) */
320 } /* void nfs_read_stats_file */
321 #endif /* defined(KERNEL_LINUX) */
322 #undef BUFSIZE
324 #if HAVE_LIBKSTAT && 0
325 static void nfs2_read_kstat (kstat_t *ksp, char *inst)
326 {
327 unsigned long long values[18];
329 values[0] = get_kstat_value (ksp, "null");
330 values[1] = get_kstat_value (ksp, "getattr");
331 values[2] = get_kstat_value (ksp, "setattr");
332 values[3] = get_kstat_value (ksp, "root");
333 values[4] = get_kstat_value (ksp, "lookup");
334 values[5] = get_kstat_value (ksp, "readlink");
335 values[6] = get_kstat_value (ksp, "read");
336 values[7] = get_kstat_value (ksp, "wrcache");
337 values[8] = get_kstat_value (ksp, "write");
338 values[9] = get_kstat_value (ksp, "create");
339 values[10] = get_kstat_value (ksp, "remove");
340 values[11] = get_kstat_value (ksp, "rename");
341 values[12] = get_kstat_value (ksp, "link");
342 values[13] = get_kstat_value (ksp, "symlink");
343 values[14] = get_kstat_value (ksp, "mkdir");
344 values[15] = get_kstat_value (ksp, "rmdir");
345 values[16] = get_kstat_value (ksp, "readdir");
346 values[17] = get_kstat_value (ksp, "statfs");
348 nfs2_procedures_submit (values, inst);
349 }
350 #endif
352 static int nfs_read (void)
353 {
354 #if KERNEL_LINUX
355 FILE *fh;
357 if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
358 {
359 nfs_read_stats_file (fh, "client");
360 fclose (fh);
361 }
363 if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
364 {
365 nfs_read_stats_file (fh, "server");
366 fclose (fh);
367 }
369 /* #endif defined(KERNEL_LINUX) */
371 #elif HAVE_LIBKSTAT && 0
372 if (nfs2_ksp_client != NULL)
373 nfs2_read_kstat (nfs2_ksp_client, "client");
374 if (nfs2_ksp_server != NULL)
375 nfs2_read_kstat (nfs2_ksp_server, "server");
376 #endif /* defined(HAVE_LIBKSTAT) */
378 return (0);
379 }
380 #endif /* NFS_HAVE_READ */
382 void module_register (void)
383 {
384 plugin_register_data_set (&procedure_ds);
386 #if NFS_HAVE_READ
387 plugin_register_read ("nfs", nfs_read);
388 #endif
389 }
391 #undef MODULE_NAME