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 #if !KERNEL_LINUX
28 # error "No applicable input method."
29 #endif
31 /*
32 see /proc/net/rpc/nfs
33 see http://www.missioncriticallinux.com/orph/NFS-Statistics
35 net x x x x
36 rpc_stat.netcnt Not used; always zero.
37 rpc_stat.netudpcnt Not used; always zero.
38 rpc_stat.nettcpcnt Not used; always zero.
39 rpc_stat.nettcpconn Not used; always zero.
41 rpc x x x
42 rpc_stat.rpccnt The number of RPC calls.
43 rpc_stat.rpcretrans The number of retransmitted RPC calls.
44 rpc_stat.rpcauthrefresh The number of credential refreshes.
46 proc2 x x x...
47 proc3 x x x...
49 Procedure NFS Version NFS Version 3
50 Number Procedures Procedures
52 0 null null
53 1 getattr getattr
54 2 setattr setattr
55 3 root lookup
56 4 lookup access
57 5 readlink readlink
58 6 read read
59 7 wrcache write
60 8 write create
61 9 create mkdir
62 10 remove symlink
63 11 rename mknod
64 12 link remove
65 13 symlink rmdir
66 14 mkdir rename
67 15 rmdir link
68 16 readdir readdir
69 17 fsstat readdirplus
70 18 fsstat
71 19 fsinfo
72 20 pathconf
73 21 commit
74 */
76 static const char *nfs2_procedures_names[] =
77 {
78 "null",
79 "getattr",
80 "setattr",
81 "root",
82 "lookup",
83 "readlink",
84 "read",
85 "wrcache",
86 "write",
87 "create",
88 "remove",
89 "rename",
90 "link",
91 "symlink",
92 "mkdir",
93 "rmdir",
94 "readdir",
95 "fsstat",
96 NULL
97 };
98 static int nfs2_procedures_names_num = 18;
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 NULL
125 };
126 static int nfs3_procedures_names_num = 22;
128 #if HAVE_LIBKSTAT && 0
129 extern kstat_ctl_t *kc;
130 static kstat_t *nfs2_ksp_client;
131 static kstat_t *nfs2_ksp_server;
132 static kstat_t *nfs3_ksp_client;
133 static kstat_t *nfs3_ksp_server;
134 static kstat_t *nfs4_ksp_client;
135 static kstat_t *nfs4_ksp_server;
136 #endif
138 /* Possibly TODO: NFSv4 statistics */
140 #if 0
141 static int nfs_init (void)
142 {
143 #if HAVE_LIBKSTAT && 0
144 kstat_t *ksp_chain;
146 nfs2_ksp_client = NULL;
147 nfs2_ksp_server = NULL;
148 nfs3_ksp_client = NULL;
149 nfs3_ksp_server = NULL;
150 nfs4_ksp_client = NULL;
151 nfs4_ksp_server = NULL;
153 if (kc == NULL)
154 return;
156 for (ksp_chain = kc->kc_chain; ksp_chain != NULL;
157 ksp_chain = ksp_chain->ks_next)
158 {
159 if (strncmp (ksp_chain->ks_module, "nfs", 3) != 0)
160 continue;
161 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v2", 13) == 0)
162 nfs2_ksp_server = ksp_chain;
163 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v3", 13) == 0)
164 nfs3_ksp_server = ksp_chain;
165 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v4", 13) == 0)
166 nfs4_ksp_server = ksp_chain;
167 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v2", 12) == 0)
168 nfs2_ksp_client = ksp_chain;
169 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v3", 12) == 0)
170 nfs3_ksp_client = ksp_chain;
171 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v4", 12) == 0)
172 nfs4_ksp_client = ksp_chain;
173 }
174 #endif
176 return (0);
177 } /* int nfs_init */
178 #endif
180 #define BUFSIZE 1024
181 static void nfs_procedures_submit (const char *plugin_instance,
182 unsigned long long *val, const char **names, int len)
183 {
184 value_t values[1];
185 value_list_t vl = VALUE_LIST_INIT;
186 int i;
188 vl.values = values;
189 vl.values_len = 1;
190 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
191 sstrncpy (vl.plugin, "nfs", sizeof (vl.plugin));
192 sstrncpy (vl.plugin_instance, plugin_instance,
193 sizeof (vl.plugin_instance));
194 sstrncpy (vl.type, "nfs_procedure", sizeof (vl.type));
196 for (i = 0; i < len; i++)
197 {
198 values[0].counter = val[i];
199 sstrncpy (vl.type_instance, names[i],
200 sizeof (vl.type_instance));
201 DEBUG ("%s-%s/nfs_procedure-%s = %llu",
202 vl.plugin, vl.plugin_instance,
203 vl.type_instance, val[i]);
204 plugin_dispatch_values (&vl);
205 }
206 } /* void nfs_procedures_submit */
208 static void nfs_read_stats_file (FILE *fh, char *inst)
209 {
210 char buffer[BUFSIZE];
212 char plugin_instance[DATA_MAX_NAME_LEN];
214 char *fields[48];
215 int numfields = 0;
217 if (fh == NULL)
218 return;
220 while (fgets (buffer, BUFSIZE, fh) != NULL)
221 {
222 numfields = strsplit (buffer, fields, 48);
224 if (((numfields - 2) != nfs2_procedures_names_num)
225 && ((numfields - 2)
226 != nfs3_procedures_names_num))
227 continue;
229 if (strcmp (fields[0], "proc2") == 0)
230 {
231 int i;
232 unsigned long long *values;
234 if ((numfields - 2) != nfs2_procedures_names_num)
235 {
236 WARNING ("nfs plugin: Wrong "
237 "number of fields (= %i) "
238 "for NFSv2 statistics.",
239 numfields - 2);
240 continue;
241 }
243 ssnprintf (plugin_instance, sizeof (plugin_instance),
244 "v2%s", inst);
246 values = (unsigned long long *) malloc (nfs2_procedures_names_num * sizeof (unsigned long long));
247 if (values == NULL)
248 {
249 char errbuf[1024];
250 ERROR ("nfs plugin: malloc "
251 "failed: %s",
252 sstrerror (errno, errbuf, sizeof (errbuf)));
253 continue;
254 }
256 for (i = 0; i < nfs2_procedures_names_num; i++)
257 values[i] = atoll (fields[i + 2]);
259 nfs_procedures_submit (plugin_instance, values,
260 nfs2_procedures_names,
261 nfs2_procedures_names_num);
263 free (values);
264 }
265 else if (strncmp (fields[0], "proc3", 5) == 0)
266 {
267 int i;
268 unsigned long long *values;
270 if ((numfields - 2) != nfs3_procedures_names_num)
271 {
272 WARNING ("nfs plugin: Wrong "
273 "number of fields (= %i) "
274 "for NFSv3 statistics.",
275 numfields - 2);
276 continue;
277 }
279 ssnprintf (plugin_instance, sizeof (plugin_instance),
280 "v3%s", inst);
282 values = (unsigned long long *) malloc (nfs3_procedures_names_num * sizeof (unsigned long long));
283 if (values == NULL)
284 {
285 char errbuf[1024];
286 ERROR ("nfs plugin: malloc "
287 "failed: %s",
288 sstrerror (errno, errbuf, sizeof (errbuf)));
289 continue;
290 }
292 for (i = 0; i < nfs3_procedures_names_num; i++)
293 values[i] = atoll (fields[i + 2]);
295 nfs_procedures_submit (plugin_instance, values,
296 nfs3_procedures_names,
297 nfs3_procedures_names_num);
299 free (values);
300 }
301 } /* while (fgets (buffer, BUFSIZE, fh) != NULL) */
302 } /* void nfs_read_stats_file */
303 #undef BUFSIZE
305 #if HAVE_LIBKSTAT && 0
306 static void nfs2_read_kstat (kstat_t *ksp, char *inst)
307 {
308 unsigned long long values[18];
310 values[0] = get_kstat_value (ksp, "null");
311 values[1] = get_kstat_value (ksp, "getattr");
312 values[2] = get_kstat_value (ksp, "setattr");
313 values[3] = get_kstat_value (ksp, "root");
314 values[4] = get_kstat_value (ksp, "lookup");
315 values[5] = get_kstat_value (ksp, "readlink");
316 values[6] = get_kstat_value (ksp, "read");
317 values[7] = get_kstat_value (ksp, "wrcache");
318 values[8] = get_kstat_value (ksp, "write");
319 values[9] = get_kstat_value (ksp, "create");
320 values[10] = get_kstat_value (ksp, "remove");
321 values[11] = get_kstat_value (ksp, "rename");
322 values[12] = get_kstat_value (ksp, "link");
323 values[13] = get_kstat_value (ksp, "symlink");
324 values[14] = get_kstat_value (ksp, "mkdir");
325 values[15] = get_kstat_value (ksp, "rmdir");
326 values[16] = get_kstat_value (ksp, "readdir");
327 values[17] = get_kstat_value (ksp, "statfs");
329 nfs2_procedures_submit (values, inst);
330 }
331 #endif
333 static int nfs_read (void)
334 {
335 FILE *fh;
337 if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
338 {
339 nfs_read_stats_file (fh, "client");
340 fclose (fh);
341 }
343 if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
344 {
345 nfs_read_stats_file (fh, "server");
346 fclose (fh);
347 }
349 #if HAVE_LIBKSTAT && 0
350 if (nfs2_ksp_client != NULL)
351 nfs2_read_kstat (nfs2_ksp_client, "client");
352 if (nfs2_ksp_server != NULL)
353 nfs2_read_kstat (nfs2_ksp_server, "server");
354 #endif /* defined(HAVE_LIBKSTAT) */
356 return (0);
357 }
359 void module_register (void)
360 {
361 plugin_register_read ("nfs", nfs_read);
362 } /* void module_register */