81f07937eb5f3c315c87756ac378df420ee24ea8
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 #define MODULE_NAME "nfs"
29 /* #if defined(KERNEL_LINUX) || defined(HAVE_LIBKSTAT) */
30 #if KERNEL_LINUX
31 # define NFS_HAVE_READ 1
32 #else
33 # define NFS_HAVE_READ 0
34 #endif
36 /*
37 see /proc/net/rpc/nfs
38 see http://www.missioncriticallinux.com/orph/NFS-Statistics
40 net x x x x
41 rpc_stat.netcnt Not used; always zero.
42 rpc_stat.netudpcnt Not used; always zero.
43 rpc_stat.nettcpcnt Not used; always zero.
44 rpc_stat.nettcpconn Not used; always zero.
46 rpc x x x
47 rpc_stat.rpccnt The number of RPC calls.
48 rpc_stat.rpcretrans The number of retransmitted RPC calls.
49 rpc_stat.rpcauthrefresh The number of credential refreshes.
51 proc2 x x x...
52 proc3 x x x...
54 Procedure NFS Version NFS Version 3
55 Number Procedures Procedures
57 0 null null
58 1 getattr getattr
59 2 setattr setattr
60 3 root lookup
61 4 lookup access
62 5 readlink readlink
63 6 read read
64 7 wrcache write
65 8 write create
66 9 create mkdir
67 10 remove symlink
68 11 rename mknod
69 12 link remove
70 13 symlink rmdir
71 14 mkdir rename
72 15 rmdir link
73 16 readdir readdir
74 17 fsstat readdirplus
75 18 fsstat
76 19 fsinfo
77 20 pathconf
78 21 commit
79 */
81 static data_source_t procedure_dsrc[1] =
82 {
83 {"value", DS_TYPE_COUNTER, 0, 4294967295.0}
84 };
86 static data_set_t procedure_ds =
87 {
88 "nfs_procedure", 1, procedure_dsrc
89 };
91 #if NFS_HAVE_READ
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 static void nfs_procedures_submit (const char *plugin_instance,
198 unsigned long long *val, const char **names, int len)
199 {
200 value_t values[1];
201 value_list_t vl = VALUE_LIST_INIT;
202 int i;
204 vl.values = values;
205 vl.values_len = 1;
206 vl.time = time (NULL);
207 strcpy (vl.host, hostname_g);
208 strcpy (vl.plugin, "nfs");
209 strncpy (vl.plugin_instance, plugin_instance,
210 sizeof (vl.plugin_instance));
212 for (i = 0; i < len; i++)
213 {
214 values[0].counter = val[i];
215 strncpy (vl.type_instance, names[i],
216 sizeof (vl.type_instance));
217 DEBUG ("%s-%s/nfs_procedure-%s = %llu",
218 vl.plugin, vl.plugin_instance,
219 vl.type_instance, val[i]);
220 plugin_dispatch_values ("nfs_procedure", &vl);
221 }
222 } /* void nfs_procedures_submit */
224 #if KERNEL_LINUX
225 static void nfs_read_stats_file (FILE *fh, char *inst)
226 {
227 char buffer[BUFSIZE];
229 char plugin_instance[DATA_MAX_NAME_LEN];
231 char *fields[48];
232 int numfields = 0;
234 if (fh == NULL)
235 return;
237 while (fgets (buffer, BUFSIZE, fh) != NULL)
238 {
239 numfields = strsplit (buffer, fields, 48);
241 if (((numfields - 2) != nfs2_procedures_names_num)
242 && ((numfields - 2)
243 != nfs3_procedures_names_num))
244 continue;
246 if (strcmp (fields[0], "proc2") == 0)
247 {
248 int i;
249 unsigned long long *values;
251 if ((numfields - 2) != nfs2_procedures_names_num)
252 {
253 WARNING ("nfs plugin: Wrong "
254 "number of fields (= %i) "
255 "for NFSv2 statistics.",
256 numfields - 2);
257 continue;
258 }
260 snprintf (plugin_instance, sizeof (plugin_instance),
261 "v2%s", inst);
262 plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
264 values = (unsigned long long *) malloc (nfs2_procedures_names_num * sizeof (unsigned long long));
265 if (values == NULL)
266 {
267 ERROR ("nfs plugin: malloc "
268 "failed: %s",
269 strerror (errno));
270 continue;
271 }
273 for (i = 0; i < nfs2_procedures_names_num; i++)
274 values[i] = atoll (fields[i + 2]);
276 nfs_procedures_submit (plugin_instance, values,
277 nfs2_procedures_names,
278 nfs2_procedures_names_num);
280 free (values);
281 }
282 else if (strncmp (fields[0], "proc3", 5) == 0)
283 {
284 int i;
285 unsigned long long *values;
287 if ((numfields - 2) != nfs3_procedures_names_num)
288 {
289 WARNING ("nfs plugin: Wrong "
290 "number of fields (= %i) "
291 "for NFSv3 statistics.",
292 numfields - 2);
293 continue;
294 }
296 snprintf (plugin_instance, sizeof (plugin_instance),
297 "v3%s", inst);
298 plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
300 values = (unsigned long long *) malloc (nfs3_procedures_names_num * sizeof (unsigned long long));
301 if (values == NULL)
302 {
303 ERROR ("nfs plugin: malloc "
304 "failed: %s",
305 strerror (errno));
306 continue;
307 }
309 for (i = 0; i < nfs3_procedures_names_num; i++)
310 values[i] = atoll (fields[i + 2]);
312 nfs_procedures_submit (plugin_instance, values,
313 nfs3_procedures_names,
314 nfs3_procedures_names_num);
316 free (values);
317 }
318 } /* while (fgets (buffer, BUFSIZE, fh) != NULL) */
319 } /* void nfs_read_stats_file */
320 #endif /* defined(KERNEL_LINUX) */
321 #undef BUFSIZE
323 #if HAVE_LIBKSTAT && 0
324 static void nfs2_read_kstat (kstat_t *ksp, char *inst)
325 {
326 unsigned long long values[18];
328 values[0] = get_kstat_value (ksp, "null");
329 values[1] = get_kstat_value (ksp, "getattr");
330 values[2] = get_kstat_value (ksp, "setattr");
331 values[3] = get_kstat_value (ksp, "root");
332 values[4] = get_kstat_value (ksp, "lookup");
333 values[5] = get_kstat_value (ksp, "readlink");
334 values[6] = get_kstat_value (ksp, "read");
335 values[7] = get_kstat_value (ksp, "wrcache");
336 values[8] = get_kstat_value (ksp, "write");
337 values[9] = get_kstat_value (ksp, "create");
338 values[10] = get_kstat_value (ksp, "remove");
339 values[11] = get_kstat_value (ksp, "rename");
340 values[12] = get_kstat_value (ksp, "link");
341 values[13] = get_kstat_value (ksp, "symlink");
342 values[14] = get_kstat_value (ksp, "mkdir");
343 values[15] = get_kstat_value (ksp, "rmdir");
344 values[16] = get_kstat_value (ksp, "readdir");
345 values[17] = get_kstat_value (ksp, "statfs");
347 nfs2_procedures_submit (values, inst);
348 }
349 #endif
351 static int nfs_read (void)
352 {
353 #if KERNEL_LINUX
354 FILE *fh;
356 if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
357 {
358 nfs_read_stats_file (fh, "client");
359 fclose (fh);
360 }
362 if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
363 {
364 nfs_read_stats_file (fh, "server");
365 fclose (fh);
366 }
368 /* #endif defined(KERNEL_LINUX) */
370 #elif HAVE_LIBKSTAT && 0
371 if (nfs2_ksp_client != NULL)
372 nfs2_read_kstat (nfs2_ksp_client, "client");
373 if (nfs2_ksp_server != NULL)
374 nfs2_read_kstat (nfs2_ksp_server, "server");
375 #endif /* defined(HAVE_LIBKSTAT) */
377 return (0);
378 }
379 #endif /* NFS_HAVE_READ */
381 void module_register (void)
382 {
383 plugin_register_data_set (&procedure_ds);
385 #if NFS_HAVE_READ
386 plugin_register_read ("nfs", nfs_read);
387 #endif
388 }
390 #undef MODULE_NAME