d6e8516812721898633d2903321426e79516eadc
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 static const char *nfs2_procedures_names[] =
93 {
94 "null",
95 "getattr",
96 "setattr",
97 "root",
98 "lookup",
99 "readlink",
100 "read",
101 "wrcache",
102 "write",
103 "create",
104 "remove",
105 "rename",
106 "link",
107 "symlink",
108 "mkdir",
109 "rmdir",
110 "readdir",
111 "fsstat",
112 NULL
113 };
114 static int nfs2_procedures_names_num = 18;
116 static const char *nfs3_procedures_names[] =
117 {
118 "null",
119 "getattr",
120 "setattr",
121 "lookup",
122 "access",
123 "readlink",
124 "read",
125 "write",
126 "create",
127 "mkdir",
128 "symlink",
129 "mknod",
130 "remove",
131 "rmdir",
132 "rename",
133 "link",
134 "readdir",
135 "readdirplus",
136 "fsstat",
137 "fsinfo",
138 "pathconf",
139 "commit",
140 NULL
141 };
142 static int nfs3_procedures_names_num = 22;
144 #if HAVE_LIBKSTAT && 0
145 extern kstat_ctl_t *kc;
146 static kstat_t *nfs2_ksp_client;
147 static kstat_t *nfs2_ksp_server;
148 static kstat_t *nfs3_ksp_client;
149 static kstat_t *nfs3_ksp_server;
150 static kstat_t *nfs4_ksp_client;
151 static kstat_t *nfs4_ksp_server;
152 #endif
154 /* Possibly TODO: NFSv4 statistics */
156 #if 0
157 static int nfs_init (void)
158 {
159 #if HAVE_LIBKSTAT && 0
160 kstat_t *ksp_chain;
162 nfs2_ksp_client = NULL;
163 nfs2_ksp_server = NULL;
164 nfs3_ksp_client = NULL;
165 nfs3_ksp_server = NULL;
166 nfs4_ksp_client = NULL;
167 nfs4_ksp_server = NULL;
169 if (kc == NULL)
170 return;
172 for (ksp_chain = kc->kc_chain; ksp_chain != NULL;
173 ksp_chain = ksp_chain->ks_next)
174 {
175 if (strncmp (ksp_chain->ks_module, "nfs", 3) != 0)
176 continue;
177 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v2", 13) == 0)
178 nfs2_ksp_server = ksp_chain;
179 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v3", 13) == 0)
180 nfs3_ksp_server = ksp_chain;
181 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v4", 13) == 0)
182 nfs4_ksp_server = ksp_chain;
183 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v2", 12) == 0)
184 nfs2_ksp_client = ksp_chain;
185 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v3", 12) == 0)
186 nfs3_ksp_client = ksp_chain;
187 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v4", 12) == 0)
188 nfs4_ksp_client = ksp_chain;
189 }
190 #endif
192 return (0);
193 } /* int nfs_init */
194 #endif
196 #define BUFSIZE 1024
197 #if NFS_HAVE_READ
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 /* FIXME: do this globally */
209 if (gethostname (vl.host, sizeof (vl.host)) != 0)
210 {
211 syslog (LOG_ERR, "load plugin: gethostname failed: %s",
212 strerror (errno));
213 return;
214 }
215 strcpy (vl.plugin, "nfs");
216 strncpy (vl.plugin_instance, plugin_instance,
217 sizeof (vl.plugin_instance));
219 for (i = 0; i < len; i++)
220 {
221 values[0].counter = val[i];
222 strncpy (vl.type_instance, names[i],
223 sizeof (vl.type_instance));
224 DBG ("%s-%s/nfs_procedure-%s = %llu",
225 vl.plugin, vl.plugin_instance,
226 vl.type_instance, val[i]);
227 plugin_dispatch_values ("nfs_procedure", &vl);
228 }
229 } /* void nfs_procedures_submit */
230 #endif /* NFS_HAVE_READ */
232 #if KERNEL_LINUX
233 static void nfs_read_stats_file (FILE *fh, char *inst)
234 {
235 char buffer[BUFSIZE];
237 char plugin_instance[DATA_MAX_NAME_LEN];
239 char *fields[48];
240 int numfields = 0;
242 if (fh == NULL)
243 return;
245 while (fgets (buffer, BUFSIZE, fh) != NULL)
246 {
247 numfields = strsplit (buffer, fields, 48);
249 if (((numfields - 2) != nfs2_procedures_names_num)
250 && ((numfields - 2)
251 != nfs3_procedures_names_num))
252 continue;
254 if (strcmp (fields[0], "proc2") == 0)
255 {
256 int i;
257 unsigned long long *values;
259 if ((numfields - 2) != nfs2_procedures_names_num)
260 {
261 syslog (LOG_WARNING, "nfs plugin: Wrong "
262 "number of fields (= %i) "
263 "for NFSv2 statistics.",
264 numfields - 2);
265 continue;
266 }
268 snprintf (plugin_instance, sizeof (plugin_instance),
269 "v2%s", inst);
270 plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
272 values = (unsigned long long *) malloc (nfs2_procedures_names_num * sizeof (unsigned long long));
273 if (values == NULL)
274 {
275 syslog (LOG_ERR, "nfs plugin: malloc "
276 "failed: %s",
277 strerror (errno));
278 continue;
279 }
281 for (i = 0; i < nfs2_procedures_names_num; i++)
282 values[i] = atoll (fields[i + 2]);
284 nfs_procedures_submit (plugin_instance, values,
285 nfs2_procedures_names,
286 nfs2_procedures_names_num);
288 free (values);
289 }
290 else if (strncmp (fields[0], "proc3", 5) == 0)
291 {
292 int i;
293 unsigned long long *values;
295 if ((numfields - 2) != nfs3_procedures_names_num)
296 {
297 syslog (LOG_WARNING, "nfs plugin: Wrong "
298 "number of fields (= %i) "
299 "for NFSv3 statistics.",
300 numfields - 2);
301 continue;
302 }
304 snprintf (plugin_instance, sizeof (plugin_instance),
305 "v3%s", inst);
306 plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
308 values = (unsigned long long *) malloc (nfs3_procedures_names_num * sizeof (unsigned long long));
309 if (values == NULL)
310 {
311 syslog (LOG_ERR, "nfs plugin: malloc "
312 "failed: %s",
313 strerror (errno));
314 continue;
315 }
317 for (i = 0; i < nfs3_procedures_names_num; i++)
318 values[i] = atoll (fields[i + 2]);
320 nfs_procedures_submit (plugin_instance, values,
321 nfs3_procedures_names,
322 nfs3_procedures_names_num);
324 free (values);
325 }
326 } /* while (fgets (buffer, BUFSIZE, fh) != NULL) */
327 } /* void nfs_read_stats_file */
328 #endif /* defined(KERNEL_LINUX) */
329 #undef BUFSIZE
331 #if HAVE_LIBKSTAT && 0
332 static void nfs2_read_kstat (kstat_t *ksp, char *inst)
333 {
334 unsigned long long values[18];
336 values[0] = get_kstat_value (ksp, "null");
337 values[1] = get_kstat_value (ksp, "getattr");
338 values[2] = get_kstat_value (ksp, "setattr");
339 values[3] = get_kstat_value (ksp, "root");
340 values[4] = get_kstat_value (ksp, "lookup");
341 values[5] = get_kstat_value (ksp, "readlink");
342 values[6] = get_kstat_value (ksp, "read");
343 values[7] = get_kstat_value (ksp, "wrcache");
344 values[8] = get_kstat_value (ksp, "write");
345 values[9] = get_kstat_value (ksp, "create");
346 values[10] = get_kstat_value (ksp, "remove");
347 values[11] = get_kstat_value (ksp, "rename");
348 values[12] = get_kstat_value (ksp, "link");
349 values[13] = get_kstat_value (ksp, "symlink");
350 values[14] = get_kstat_value (ksp, "mkdir");
351 values[15] = get_kstat_value (ksp, "rmdir");
352 values[16] = get_kstat_value (ksp, "readdir");
353 values[17] = get_kstat_value (ksp, "statfs");
355 nfs2_procedures_submit (values, inst);
356 }
357 #endif
359 #if NFS_HAVE_READ
360 static int nfs_read (void)
361 {
362 #if KERNEL_LINUX
363 FILE *fh;
365 if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
366 {
367 nfs_read_stats_file (fh, "client");
368 fclose (fh);
369 }
371 if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
372 {
373 nfs_read_stats_file (fh, "server");
374 fclose (fh);
375 }
377 /* #endif defined(KERNEL_LINUX) */
379 #elif HAVE_LIBKSTAT && 0
380 if (nfs2_ksp_client != NULL)
381 nfs2_read_kstat (nfs2_ksp_client, "client");
382 if (nfs2_ksp_server != NULL)
383 nfs2_read_kstat (nfs2_ksp_server, "server");
384 #endif /* defined(HAVE_LIBKSTAT) */
386 return (0);
387 }
388 #endif /* NFS_HAVE_READ */
390 void module_register (void)
391 {
392 plugin_register_data_set (&procedure_ds);
394 #if NFS_HAVE_READ
395 plugin_register_read ("nfs", nfs_read);
396 #endif
397 }
399 #undef MODULE_NAME