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 defined(KERNEL_LINUX) || defined(HAVE_LIBKSTAT) */
28 #if KERNEL_LINUX
29 # define NFS_HAVE_READ 1
30 #else
31 # define NFS_HAVE_READ 0
32 #endif
34 /*
35 see /proc/net/rpc/nfs
36 see http://www.missioncriticallinux.com/orph/NFS-Statistics
38 net x x x x
39 rpc_stat.netcnt Not used; always zero.
40 rpc_stat.netudpcnt Not used; always zero.
41 rpc_stat.nettcpcnt Not used; always zero.
42 rpc_stat.nettcpconn Not used; always zero.
44 rpc x x x
45 rpc_stat.rpccnt The number of RPC calls.
46 rpc_stat.rpcretrans The number of retransmitted RPC calls.
47 rpc_stat.rpcauthrefresh The number of credential refreshes.
49 proc2 x x x...
50 proc3 x x x...
52 Procedure NFS Version NFS Version 3
53 Number Procedures Procedures
55 0 null null
56 1 getattr getattr
57 2 setattr setattr
58 3 root lookup
59 4 lookup access
60 5 readlink readlink
61 6 read read
62 7 wrcache write
63 8 write create
64 9 create mkdir
65 10 remove symlink
66 11 rename mknod
67 12 link remove
68 13 symlink rmdir
69 14 mkdir rename
70 15 rmdir link
71 16 readdir readdir
72 17 fsstat readdirplus
73 18 fsstat
74 19 fsinfo
75 20 pathconf
76 21 commit
77 */
79 #if NFS_HAVE_READ
80 static const char *nfs2_procedures_names[] =
81 {
82 "null",
83 "getattr",
84 "setattr",
85 "root",
86 "lookup",
87 "readlink",
88 "read",
89 "wrcache",
90 "write",
91 "create",
92 "remove",
93 "rename",
94 "link",
95 "symlink",
96 "mkdir",
97 "rmdir",
98 "readdir",
99 "fsstat",
100 NULL
101 };
102 static int nfs2_procedures_names_num = 18;
104 static const char *nfs3_procedures_names[] =
105 {
106 "null",
107 "getattr",
108 "setattr",
109 "lookup",
110 "access",
111 "readlink",
112 "read",
113 "write",
114 "create",
115 "mkdir",
116 "symlink",
117 "mknod",
118 "remove",
119 "rmdir",
120 "rename",
121 "link",
122 "readdir",
123 "readdirplus",
124 "fsstat",
125 "fsinfo",
126 "pathconf",
127 "commit",
128 NULL
129 };
130 static int nfs3_procedures_names_num = 22;
132 #if HAVE_LIBKSTAT && 0
133 extern kstat_ctl_t *kc;
134 static kstat_t *nfs2_ksp_client;
135 static kstat_t *nfs2_ksp_server;
136 static kstat_t *nfs3_ksp_client;
137 static kstat_t *nfs3_ksp_server;
138 static kstat_t *nfs4_ksp_client;
139 static kstat_t *nfs4_ksp_server;
140 #endif
142 /* Possibly TODO: NFSv4 statistics */
144 #if 0
145 static int nfs_init (void)
146 {
147 #if HAVE_LIBKSTAT && 0
148 kstat_t *ksp_chain;
150 nfs2_ksp_client = NULL;
151 nfs2_ksp_server = NULL;
152 nfs3_ksp_client = NULL;
153 nfs3_ksp_server = NULL;
154 nfs4_ksp_client = NULL;
155 nfs4_ksp_server = NULL;
157 if (kc == NULL)
158 return;
160 for (ksp_chain = kc->kc_chain; ksp_chain != NULL;
161 ksp_chain = ksp_chain->ks_next)
162 {
163 if (strncmp (ksp_chain->ks_module, "nfs", 3) != 0)
164 continue;
165 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v2", 13) == 0)
166 nfs2_ksp_server = ksp_chain;
167 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v3", 13) == 0)
168 nfs3_ksp_server = ksp_chain;
169 else if (strncmp (ksp_chain->ks_name, "rfsproccnt_v4", 13) == 0)
170 nfs4_ksp_server = ksp_chain;
171 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v2", 12) == 0)
172 nfs2_ksp_client = ksp_chain;
173 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v3", 12) == 0)
174 nfs3_ksp_client = ksp_chain;
175 else if (strncmp (ksp_chain->ks_name, "rfsreqcnt_v4", 12) == 0)
176 nfs4_ksp_client = ksp_chain;
177 }
178 #endif
180 return (0);
181 } /* int nfs_init */
182 #endif
184 #define BUFSIZE 1024
185 static void nfs_procedures_submit (const char *plugin_instance,
186 unsigned long long *val, const char **names, int len)
187 {
188 value_t values[1];
189 value_list_t vl = VALUE_LIST_INIT;
190 int i;
192 vl.values = values;
193 vl.values_len = 1;
194 vl.time = time (NULL);
195 strcpy (vl.host, hostname_g);
196 strcpy (vl.plugin, "nfs");
197 strncpy (vl.plugin_instance, plugin_instance,
198 sizeof (vl.plugin_instance));
200 for (i = 0; i < len; i++)
201 {
202 values[0].counter = val[i];
203 strncpy (vl.type_instance, names[i],
204 sizeof (vl.type_instance));
205 DEBUG ("%s-%s/nfs_procedure-%s = %llu",
206 vl.plugin, vl.plugin_instance,
207 vl.type_instance, val[i]);
208 plugin_dispatch_values ("nfs_procedure", &vl);
209 }
210 } /* void nfs_procedures_submit */
212 #if KERNEL_LINUX
213 static void nfs_read_stats_file (FILE *fh, char *inst)
214 {
215 char buffer[BUFSIZE];
217 char plugin_instance[DATA_MAX_NAME_LEN];
219 char *fields[48];
220 int numfields = 0;
222 if (fh == NULL)
223 return;
225 while (fgets (buffer, BUFSIZE, fh) != NULL)
226 {
227 numfields = strsplit (buffer, fields, 48);
229 if (((numfields - 2) != nfs2_procedures_names_num)
230 && ((numfields - 2)
231 != nfs3_procedures_names_num))
232 continue;
234 if (strcmp (fields[0], "proc2") == 0)
235 {
236 int i;
237 unsigned long long *values;
239 if ((numfields - 2) != nfs2_procedures_names_num)
240 {
241 WARNING ("nfs plugin: Wrong "
242 "number of fields (= %i) "
243 "for NFSv2 statistics.",
244 numfields - 2);
245 continue;
246 }
248 snprintf (plugin_instance, sizeof (plugin_instance),
249 "v2%s", inst);
250 plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
252 values = (unsigned long long *) malloc (nfs2_procedures_names_num * sizeof (unsigned long long));
253 if (values == NULL)
254 {
255 char errbuf[1024];
256 ERROR ("nfs plugin: malloc "
257 "failed: %s",
258 sstrerror (errno, errbuf, sizeof (errbuf)));
259 continue;
260 }
262 for (i = 0; i < nfs2_procedures_names_num; i++)
263 values[i] = atoll (fields[i + 2]);
265 nfs_procedures_submit (plugin_instance, values,
266 nfs2_procedures_names,
267 nfs2_procedures_names_num);
269 free (values);
270 }
271 else if (strncmp (fields[0], "proc3", 5) == 0)
272 {
273 int i;
274 unsigned long long *values;
276 if ((numfields - 2) != nfs3_procedures_names_num)
277 {
278 WARNING ("nfs plugin: Wrong "
279 "number of fields (= %i) "
280 "for NFSv3 statistics.",
281 numfields - 2);
282 continue;
283 }
285 snprintf (plugin_instance, sizeof (plugin_instance),
286 "v3%s", inst);
287 plugin_instance[DATA_MAX_NAME_LEN - 1] = '\0';
289 values = (unsigned long long *) malloc (nfs3_procedures_names_num * sizeof (unsigned long long));
290 if (values == NULL)
291 {
292 char errbuf[1024];
293 ERROR ("nfs plugin: malloc "
294 "failed: %s",
295 sstrerror (errno, errbuf, sizeof (errbuf)));
296 continue;
297 }
299 for (i = 0; i < nfs3_procedures_names_num; i++)
300 values[i] = atoll (fields[i + 2]);
302 nfs_procedures_submit (plugin_instance, values,
303 nfs3_procedures_names,
304 nfs3_procedures_names_num);
306 free (values);
307 }
308 } /* while (fgets (buffer, BUFSIZE, fh) != NULL) */
309 } /* void nfs_read_stats_file */
310 #endif /* defined(KERNEL_LINUX) */
311 #undef BUFSIZE
313 #if HAVE_LIBKSTAT && 0
314 static void nfs2_read_kstat (kstat_t *ksp, char *inst)
315 {
316 unsigned long long values[18];
318 values[0] = get_kstat_value (ksp, "null");
319 values[1] = get_kstat_value (ksp, "getattr");
320 values[2] = get_kstat_value (ksp, "setattr");
321 values[3] = get_kstat_value (ksp, "root");
322 values[4] = get_kstat_value (ksp, "lookup");
323 values[5] = get_kstat_value (ksp, "readlink");
324 values[6] = get_kstat_value (ksp, "read");
325 values[7] = get_kstat_value (ksp, "wrcache");
326 values[8] = get_kstat_value (ksp, "write");
327 values[9] = get_kstat_value (ksp, "create");
328 values[10] = get_kstat_value (ksp, "remove");
329 values[11] = get_kstat_value (ksp, "rename");
330 values[12] = get_kstat_value (ksp, "link");
331 values[13] = get_kstat_value (ksp, "symlink");
332 values[14] = get_kstat_value (ksp, "mkdir");
333 values[15] = get_kstat_value (ksp, "rmdir");
334 values[16] = get_kstat_value (ksp, "readdir");
335 values[17] = get_kstat_value (ksp, "statfs");
337 nfs2_procedures_submit (values, inst);
338 }
339 #endif
341 static int nfs_read (void)
342 {
343 #if KERNEL_LINUX
344 FILE *fh;
346 if ((fh = fopen ("/proc/net/rpc/nfs", "r")) != NULL)
347 {
348 nfs_read_stats_file (fh, "client");
349 fclose (fh);
350 }
352 if ((fh = fopen ("/proc/net/rpc/nfsd", "r")) != NULL)
353 {
354 nfs_read_stats_file (fh, "server");
355 fclose (fh);
356 }
358 /* #endif defined(KERNEL_LINUX) */
360 #elif HAVE_LIBKSTAT && 0
361 if (nfs2_ksp_client != NULL)
362 nfs2_read_kstat (nfs2_ksp_client, "client");
363 if (nfs2_ksp_server != NULL)
364 nfs2_read_kstat (nfs2_ksp_server, "server");
365 #endif /* defined(HAVE_LIBKSTAT) */
367 return (0);
368 }
369 #endif /* NFS_HAVE_READ */
371 void module_register (void)
372 {
373 #if NFS_HAVE_READ
374 plugin_register_read ("nfs", nfs_read);
375 #endif
376 } /* void module_register */