Maintain statistics about the received frames.

This commit is contained in:
Ruslan Ermilov 2004-05-19 11:26:33 +00:00
parent be28a6af38
commit 171e08dc7f
3 changed files with 167 additions and 6 deletions

View File

@ -35,7 +35,7 @@
.\" $FreeBSD$
.\" $Whistle: ng_hole.8,v 1.4 1999/01/25 23:46:26 archie Exp $
.\"
.Dd January 19, 1999
.Dd May 19, 2004
.Dt NG_HOLE 4
.Os
.Sh NAME
@ -54,8 +54,25 @@ A
node accepts any request to connect, regardless of the hook name,
as long as the name is unique.
.Sh CONTROL MESSAGES
This node type supports only the generic control messages.
Other control messages are silently discarded.
This node type supports the generic control messages, plus the
following:
.Bl -tag -width indent
.It Dv NGM_BPF_GET_STATS
This command takes an
.Tn ASCII
string argument, the hook name, and returns the statistics
associated with the hook as a
.Vt "struct ng_hole_hookstat" .
.It Dv NGM_BPF_CLR_STATS
This command takes an
.Tn ASCII
string argument, the hook name, and clears the statistics
associated with the hook.
.It Dv NGM_BPF_GETCLR_STATS
This command is identical to
.Dv NGM_BPF_GET_STATS ,
except that the statistics are also atomically cleared.
.El
.Sh SHUTDOWN
This node shuts down upon receipt of a
.Dv NGM_SHUTDOWN

View File

@ -51,10 +51,53 @@
#include <sys/mbuf.h>
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include <netgraph/ng_parse.h>
#include <netgraph/ng_hole.h>
/* Per hook private info. */
struct ng_hole_hookinfo {
struct ng_hole_hookstat stats;
};
typedef struct ng_hole_hookinfo *hinfo_p;
/* Parse type for struct ng_hole_hookstat. */
static const struct ng_parse_struct_field ng_hole_hookstat_type_fields[] =
NG_HOLE_HOOKSTAT_TYPE_INFO;
static const struct ng_parse_type ng_hole_hookstat_type = {
&ng_parse_struct_type,
&ng_hole_hookstat_type_fields
};
/* List of commands and how to convert arguments to/from ASCII. */
static const struct ng_cmdlist ng_hole_cmdlist[] = {
{
NGM_HOLE_COOKIE,
NGM_HOLE_GET_STATS,
"getstats",
&ng_parse_hookbuf_type,
&ng_hole_hookstat_type
},
{
NGM_HOLE_COOKIE,
NGM_HOLE_CLR_STATS,
"clrstats",
&ng_parse_hookbuf_type,
NULL
},
{
NGM_HOLE_COOKIE,
NGM_HOLE_GETCLR_STATS,
"getclrstats",
&ng_parse_hookbuf_type,
&ng_hole_hookstat_type
},
{ 0 }
};
/* Netgraph methods */
static ng_constructor_t ngh_cons;
static ng_rcvmsg_t ngh_rcvmsg;
static ng_newhook_t ngh_newhook;
static ng_rcvdata_t ngh_rcvdata;
static ng_disconnect_t ngh_disconnect;
@ -63,14 +106,14 @@ static struct ng_type typestruct = {
NG_HOLE_NODE_TYPE,
NULL, /* modeventhand_t */
ngh_cons, /* ng_constructor_t */
NULL, /* ng_rcvmsg_t */
ngh_rcvmsg, /* ng_rcvmsg_t */
NULL, /* ng_shutdown_t */
NULL, /* ng_newhook_t */
ngh_newhook, /* ng_newhook_t */
NULL, /* ng_findhook_t */
NULL, /* ng_connect_t */
ngh_rcvdata, /* ng_rcvdata_t */
ngh_disconnect, /* ng_disconnect_t */
NULL /* ng_cmdlist */
ng_hole_cmdlist /* ng_cmdlist */
};
NETGRAPH_INIT(hole, &typestruct);
@ -83,12 +126,91 @@ ngh_cons(node_p node)
return(0);
}
/*
* Add a hook.
*/
static int
ngh_newhook(node_p node, hook_p hook, const char *name)
{
hinfo_p hip;
/* Create hook private structure. */
MALLOC(hip, hinfo_p, sizeof(*hip), M_NETGRAPH, M_NOWAIT | M_ZERO);
if (hip == NULL)
return (ENOMEM);
NG_HOOK_SET_PRIVATE(hook, hip);
return (0);
}
/*
* Receive a control message.
*/
static int
ngh_rcvmsg(node_p node, item_p item, hook_p lasthook)
{
struct ng_mesg *msg;
struct ng_mesg *resp = NULL;
int error = 0;
struct ng_hole_hookstat *stats;
hook_p hook;
NGI_GET_MSG(item, msg);
switch (msg->header.typecookie) {
case NGM_HOLE_COOKIE:
switch (msg->header.cmd) {
case NGM_HOLE_GET_STATS:
case NGM_HOLE_CLR_STATS:
case NGM_HOLE_GETCLR_STATS:
/* Sanity check. */
if (msg->header.arglen != NG_HOOKLEN + 1) {
error = EINVAL;
break;
}
/* Find hook. */
hook = ng_findhook(node, (char *)msg->data);
if (hook == NULL) {
error = ENOENT;
break;
}
stats = &((hinfo_p)NG_HOOK_PRIVATE(hook))->stats;
/* Build response (if desired). */
if (msg->header.cmd != NGM_HOLE_CLR_STATS) {
NG_MKRESPONSE(resp, msg, sizeof(*stats),
M_NOWAIT);
if (resp == NULL) {
error = ENOMEM;
break;
}
bcopy(stats, resp->data, sizeof(*stats));
}
/* Clear stats (if desired). */
if (msg->header.cmd != NGM_HOLE_GET_STATS)
bzero(stats, sizeof(*stats));
break;
default: /* Unknown command. */
error = EINVAL;
break;
}
break;
default: /* Unknown type cookie. */
error = EINVAL;
break;
}
NG_RESPOND_MSG(error, node, item, resp);
NG_FREE_MSG(msg);
return (error);
}
/*
* Receive data
*/
static int
ngh_rcvdata(hook_p hook, item_p item)
{
const hinfo_p hip = NG_HOOK_PRIVATE(hook);
hip->stats.frames++;
hip->stats.octets += NGI_M(item)->m_pkthdr.len;
NG_FREE_ITEM(item);
return 0;
}
@ -99,6 +221,8 @@ ngh_rcvdata(hook_p hook, item_p item)
static int
ngh_disconnect(hook_p hook)
{
NG_HOOK_SET_PRIVATE(hook, NULL);
if (NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0)
ng_rmnode_self(NG_HOOK_NODE(hook));
return (0);

View File

@ -46,5 +46,25 @@
/* Node type name and magic cookie */
#define NG_HOLE_NODE_TYPE "hole"
#define NGM_HOLE_COOKIE 915433206
/* Statistics structure for one hook. */
struct ng_hole_hookstat {
uint64_t frames;
uint64_t octets;
};
/* Keep this in sync with the above structure definition. */
#define NG_HOLE_HOOKSTAT_TYPE_INFO { \
{ "frames", &ng_parse_uint64_type }, \
{ "octets", &ng_parse_uint64_type }, \
{ NULL } \
}
/* Netgraph commands. */
enum {
NGM_HOLE_GET_STATS = 1,
NGM_HOLE_CLR_STATS,
NGM_HOLE_GETCLR_STATS,
};
#endif /* _NETGRAPH_NG_HOLE_H_ */