f585b974d227cbedc006446e32c584b07509e169
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 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 */
224 #endif /* NFS_HAVE_READ */
226 #if KERNEL_LINUX
227 static void nfs_read_stats_file (FILE *fh, char *inst)
228 {
229 char buffer[BUFSIZE];
231 char plugin_instance[DATA_MAX_NAME_LEN];
233 char *fields[48];
234 int numfields = 0;
236 if (fh == NULL)
237 return;
239 while (fgets (buffer, BUFSIZE, fh) != NULL)
240 {
241 numfields = strsplit (buffer, fields, 48);
243 if (((numfields - 2) != nfs2_procedures_names_num)
244 && ((numfields - 2)
245 != nfs3_procedures_names_num))
246 continue;
248 if (strcmp (fields[0], "proc2") == 0)
249 {
250 int i;
251 unsigned long long *values;
253 if ((numfields - 2) != nfs2_procedures_names_num)
254 {
255 syslog (LOG_WARNING, "nfs plugin: Wrong "
256 "number of fields (= %i) "
257 "for NFSv2 statistics.",
258 numfields - 2);
259 continue;
260 }
262 snprintf (plugin_instance, sizeof (plugin_instance),
263 "v2%s", inst);
264 plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
266 values = (unsigned long long *) malloc (nfs2_procedures_names_num * sizeof (unsigned long long));
267 if (values == NULL)
268 {
269 syslog (LOG_ERR, "nfs plugin: malloc "
270 "failed: %s",
271 strerror (errno));
272 continue;
273 }
275 for (i = 0; i < nfs2_procedures_names_num; i++)
276 values[i] = atoll (fields[i + 2]);
278 nfs_procedures_submit (plugin_instance, values,
279 nfs2_procedures_names,
280 nfs2_procedures_names_num);
282 free (values);
283 }
284 else if (strncmp (fields[0], "proc3", 5) == 0)
285 {
286 int i;
287 unsigned long long *values;
289 if ((numfields - 2) != nfs3_procedures_names_num)
290 {
291 syslog (LOG_WARNING, "nfs plugin: Wrong "
292 "number of fields (= %i) "
293 "for NFSv3 statistics.",
294 numfields - 2);
295 continue;
296 }
298 snprintf (plugin_instance, sizeof (plugin_instance),
299 "v3%s", inst);
300 plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
302 values = (unsigned long long *) malloc (nfs3_procedures_names_num * sizeof (unsigned long long));
303 if (values == NULL)
304 {
305 syslog (LOG_ERR, "nfs plugin: malloc "
306 "failed: %s",
307 strerror (errno));
308 continue;
309 }
311 for (i = 0; i < nfs3_procedures_names_num; i++)
312 values[i] = atoll (fields[i + 2]);
314 nfs_procedures_submit (plugin_instance, values,
315 nfs3_procedures_names,
316 nfs3_procedures_names_num);
318 free (values);
319 }
320 } /* while (fgets (buffer, BUFSIZE, fh) != NULL) */
321 } /* void nfs_read_stats_file */
322 #endif /* defined(KERNEL_LINUX) */
323 #undef BUFSIZE
325 #if HAVE_LIBKSTAT && 0
326 static void nfs2_read_kstat (kstat_t *ksp, char *inst)
327 {
328 unsigned long long values[18];
330 values[0] = get_kstat_value (ksp, "null");
331 values[1] = get_kstat_value (ksp, "getattr");
332 values[2] = get_kstat_value (ksp, "setattr");
333 values[3] = get_kstat_value (ksp, "root");
334 values[4] = get_kstat_value (ksp, "lookup");
335 values[5] = get_kstat_value (ksp, "readlink");
336 values[6] = get_kstat_value (ksp, "read");
337 values[7] = get_kstat_value (ksp, "wrcache");
338 values[8] = get_kstat_value (ksp, "write");
339 values[9] = get_kstat_value (ksp, "create");
340 values[10] = get_kstat_value (ksp, "remove");
341 values[11] = get_kstat_value (ksp, "rename");
342 values[12] = get_kstat_value (ksp, "link");
343 values[13] = get_kstat_value (ksp, "symlink");
344 values[14] = get_kstat_value (ksp, "mkdir");
345 values[15] = get_kstat_value (ksp, "rmdir");
346 values[16] = get_kstat_value (ksp, "readdir");
347 values[17] = get_kstat_value (ksp, "statfs");
349 nfs2_procedures_submit (values, inst);
350 }
351 #endif
353 #if NFS_HAVE_READ
354 static int nfs_read (void)
355 {
356 #if KERNEL_LINUX
357 FILE *fh;
359 if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
360 {
361 nfs_read_stats_file (fh, "client");
362 fclose (fh);
363 }
365 if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
366 {
367 nfs_read_stats_file (fh, "server");
368 fclose (fh);
369 }
371 /* #endif defined(KERNEL_LINUX) */
373 #elif HAVE_LIBKSTAT && 0
374 if (nfs2_ksp_client != NULL)
375 nfs2_read_kstat (nfs2_ksp_client, "client");
376 if (nfs2_ksp_server != NULL)
377 nfs2_read_kstat (nfs2_ksp_server, "server");
378 #endif /* defined(HAVE_LIBKSTAT) */
380 return (0);
381 }
382 #endif /* NFS_HAVE_READ */
384 void module_register (void)
385 {
386 plugin_register_data_set (&procedure_ds);
388 #if NFS_HAVE_READ
389 plugin_register_read ("nfs", nfs_read);
390 #endif
391 }
393 #undef MODULE_NAME