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 vl.time = time (NULL);
191 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
192 sstrncpy (vl.plugin, "nfs", sizeof (vl.plugin));
193 sstrncpy (vl.plugin_instance, plugin_instance,
194 sizeof (vl.plugin_instance));
195 sstrncpy (vl.type, "nfs_procedure", sizeof (vl.type));
197 for (i = 0; i < len; i++)
198 {
199 values[0].counter = val[i];
200 sstrncpy (vl.type_instance, names[i],
201 sizeof (vl.type_instance));
202 DEBUG ("%s-%s/nfs_procedure-%s = %llu",
203 vl.plugin, vl.plugin_instance,
204 vl.type_instance, val[i]);
205 plugin_dispatch_values (&vl);
206 }
207 } /* void nfs_procedures_submit */
209 static void nfs_read_stats_file (FILE *fh, char *inst)
210 {
211 char buffer[BUFSIZE];
213 char plugin_instance[DATA_MAX_NAME_LEN];
215 char *fields[48];
216 int numfields = 0;
218 if (fh == NULL)
219 return;
221 while (fgets (buffer, BUFSIZE, fh) != NULL)
222 {
223 numfields = strsplit (buffer, fields, 48);
225 if (((numfields - 2) != nfs2_procedures_names_num)
226 && ((numfields - 2)
227 != nfs3_procedures_names_num))
228 continue;
230 if (strcmp (fields[0], "proc2") == 0)
231 {
232 int i;
233 unsigned long long *values;
235 if ((numfields - 2) != nfs2_procedures_names_num)
236 {
237 WARNING ("nfs plugin: Wrong "
238 "number of fields (= %i) "
239 "for NFSv2 statistics.",
240 numfields - 2);
241 continue;
242 }
244 ssnprintf (plugin_instance, sizeof (plugin_instance),
245 "v2%s", inst);
247 values = (unsigned long long *) malloc (nfs2_procedures_names_num * sizeof (unsigned long long));
248 if (values == NULL)
249 {
250 char errbuf[1024];
251 ERROR ("nfs plugin: malloc "
252 "failed: %s",
253 sstrerror (errno, errbuf, sizeof (errbuf)));
254 continue;
255 }
257 for (i = 0; i < nfs2_procedures_names_num; i++)
258 values[i] = atoll (fields[i + 2]);
260 nfs_procedures_submit (plugin_instance, values,
261 nfs2_procedures_names,
262 nfs2_procedures_names_num);
264 free (values);
265 }
266 else if (strncmp (fields[0], "proc3", 5) == 0)
267 {
268 int i;
269 unsigned long long *values;
271 if ((numfields - 2) != nfs3_procedures_names_num)
272 {
273 WARNING ("nfs plugin: Wrong "
274 "number of fields (= %i) "
275 "for NFSv3 statistics.",
276 numfields - 2);
277 continue;
278 }
280 ssnprintf (plugin_instance, sizeof (plugin_instance),
281 "v3%s", inst);
283 values = (unsigned long long *) malloc (nfs3_procedures_names_num * sizeof (unsigned long long));
284 if (values == NULL)
285 {
286 char errbuf[1024];
287 ERROR ("nfs plugin: malloc "
288 "failed: %s",
289 sstrerror (errno, errbuf, sizeof (errbuf)));
290 continue;
291 }
293 for (i = 0; i < nfs3_procedures_names_num; i++)
294 values[i] = atoll (fields[i + 2]);
296 nfs_procedures_submit (plugin_instance, values,
297 nfs3_procedures_names,
298 nfs3_procedures_names_num);
300 free (values);
301 }
302 } /* while (fgets (buffer, BUFSIZE, fh) != NULL) */
303 } /* void nfs_read_stats_file */
304 #undef BUFSIZE
306 #if HAVE_LIBKSTAT && 0
307 static void nfs2_read_kstat (kstat_t *ksp, char *inst)
308 {
309 unsigned long long values[18];
311 values[0] = get_kstat_value (ksp, "null");
312 values[1] = get_kstat_value (ksp, "getattr");
313 values[2] = get_kstat_value (ksp, "setattr");
314 values[3] = get_kstat_value (ksp, "root");
315 values[4] = get_kstat_value (ksp, "lookup");
316 values[5] = get_kstat_value (ksp, "readlink");
317 values[6] = get_kstat_value (ksp, "read");
318 values[7] = get_kstat_value (ksp, "wrcache");
319 values[8] = get_kstat_value (ksp, "write");
320 values[9] = get_kstat_value (ksp, "create");
321 values[10] = get_kstat_value (ksp, "remove");
322 values[11] = get_kstat_value (ksp, "rename");
323 values[12] = get_kstat_value (ksp, "link");
324 values[13] = get_kstat_value (ksp, "symlink");
325 values[14] = get_kstat_value (ksp, "mkdir");
326 values[15] = get_kstat_value (ksp, "rmdir");
327 values[16] = get_kstat_value (ksp, "readdir");
328 values[17] = get_kstat_value (ksp, "statfs");
330 nfs2_procedures_submit (values, inst);
331 }
332 #endif
334 static int nfs_read (void)
335 {
336 FILE *fh;
338 if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
339 {
340 nfs_read_stats_file (fh, "client");
341 fclose (fh);
342 }
344 if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
345 {
346 nfs_read_stats_file (fh, "server");
347 fclose (fh);
348 }
350 #if HAVE_LIBKSTAT && 0
351 if (nfs2_ksp_client != NULL)
352 nfs2_read_kstat (nfs2_ksp_client, "client");
353 if (nfs2_ksp_server != NULL)
354 nfs2_read_kstat (nfs2_ksp_server, "server");
355 #endif /* defined(HAVE_LIBKSTAT) */
357 return (0);
358 }
360 void module_register (void)
361 {
362 plugin_register_read ("nfs", nfs_read);
363 } /* void module_register */