A netgraph node that can do different manipulations with
mbuf_tags(9) on packets. Submitted by: Vadim Goncharov <vadimnuclight tpu.ru> mdoc(7) reviewed by: ru
This commit is contained in:
parent
06c5d8fa73
commit
d473c9d543
@ -223,6 +223,7 @@ MAN= aac.4 \
|
||||
ng_sppp.4 \
|
||||
ng_sscfu.4 \
|
||||
ng_sscop.4 \
|
||||
ng_tag.4 \
|
||||
ng_tcpmss.4 \
|
||||
ng_tee.4 \
|
||||
ng_tty.4 \
|
||||
|
337
share/man/man4/ng_tag.4
Normal file
337
share/man/man4/ng_tag.4
Normal file
@ -0,0 +1,337 @@
|
||||
.\" Copyright (c) 2006 Vadim Goncharov <vadimnuclight@tpu.ru>
|
||||
.\" All rights reserved.
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd June 10, 2006
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ng_tag
|
||||
.Nd "mbuf tags manipulating netgraph node type"
|
||||
.Sh SYNOPSIS
|
||||
.In netgraph/ng_tag.h
|
||||
.Sh DESCRIPTION
|
||||
The
|
||||
.Nm tag
|
||||
node type allows mbuf packet tags (see
|
||||
.Xr mbuf_tags 9 )
|
||||
to be examined, stripped or applied to data travelling through a
|
||||
Netgraph network.
|
||||
Mbuf tags are used in many parts of the
|
||||
.Fx
|
||||
kernel network subsystem,
|
||||
including the storage of VLAN tags as described in
|
||||
.Xr vlan 4 ,
|
||||
Mandatory Access Control (MAC) labels as described in
|
||||
.Xr mac 9 ,
|
||||
IPsec policy information as described in
|
||||
.Xr ipsec 4 ,
|
||||
and packet filter tags used by
|
||||
.Xr pf 4 .
|
||||
One should also consider useful setting or checking
|
||||
.Xr ipfw 8
|
||||
tags, which are implemented as mbuf tags, too.
|
||||
.Pp
|
||||
Each node allows an arbitrary number of connections to arbitrarily
|
||||
named hooks.
|
||||
With each hook is associated a tag which will be searched in the list
|
||||
of all tags attached to a packet incoming to this hook, a destination hook
|
||||
for matching packets, a destination hook for non-matching packets,
|
||||
a tag which will be appended to data leaving node through this hook,
|
||||
and various statistics counters.
|
||||
.Pp
|
||||
The list of incoming packet's tags is traversed to find a tag with
|
||||
specified
|
||||
.Va type
|
||||
and
|
||||
.Va cookie
|
||||
values.
|
||||
Upon match, if specified
|
||||
.Va tag_len
|
||||
is non-zero,
|
||||
.Va tag_data
|
||||
of tag is checked to be identical to that specified in the hook structure.
|
||||
Packets with matched tags are forwarded to
|
||||
.Dq match
|
||||
destination hook, or forwarded to
|
||||
.Dq non-match
|
||||
hook otherwise.
|
||||
Either or both destination hooks can be an empty string, or may
|
||||
not exist, in which case the packet is dropped.
|
||||
.Pp
|
||||
Tag list of packets leaving the node is extended with a new tag
|
||||
specified in outgoing hook structure (it is possible to avoid appending
|
||||
a new tag to pass packet completely unchanged by specifying zero
|
||||
.Va type
|
||||
and
|
||||
.Va cookie
|
||||
values in the structure of the corresponding outgoing hook).
|
||||
Additionally,
|
||||
a tag can be stripped from incoming packet after match if
|
||||
.Va strip
|
||||
flag is set.
|
||||
This can be used for simple tag removal or tag replacement, if combined
|
||||
with tag addition on outgoing matching hook.
|
||||
Note that new tag is appended unconditionally, without checking if
|
||||
such a tag is already present in the list (it is up to user to check
|
||||
if this is a concern).
|
||||
.Pp
|
||||
New hooks are initially configured to drop all incoming packets
|
||||
(as all hook names are empty strings; zero values can be specified
|
||||
to forward all packets to non-matching hook),
|
||||
and to forward all outgoing packets without any tag appending.
|
||||
.Pp
|
||||
Data payload of packets passing through the node is completely
|
||||
unchanged, all operations can affect tag list only.
|
||||
.Sh HOOKS
|
||||
This node type supports any number of hooks having arbitrary names.
|
||||
In order to allow internal optimizations, user should never try to
|
||||
configure a hook with a structure pointing to hooks which do not exist yet.
|
||||
The safe way is to create all hooks first, then begin to configure them.
|
||||
.Sh CONTROL MESSAGES
|
||||
This node type supports the generic control messages, plus the following:
|
||||
.Bl -tag -width indent
|
||||
.It Dv NGM_TAG_SET_HOOKIN
|
||||
This command sets tag values which will be searched in the tag list of
|
||||
incoming packets on a hook.
|
||||
The following structure must be supplied as an argument:
|
||||
.Bd -literal -offset 4n
|
||||
struct ng_tag_hookin {
|
||||
char thisHook[NG_HOOKSIZ]; /* name of hook */
|
||||
char ifMatch[NG_HOOKSIZ]; /* match dest hook */
|
||||
char ifNotMatch[NG_HOOKSIZ]; /* !match dest hook */
|
||||
uint8_t strip; /* strip tag if found */
|
||||
uint32_t tag_cookie; /* ABI/Module ID */
|
||||
uint16_t tag_id; /* tag ID */
|
||||
uint16_t tag_len; /* length of data */
|
||||
uint8_t tag_data[0]; /* tag data */
|
||||
};
|
||||
.Ed
|
||||
.Pp
|
||||
The hook to be updated is specified in
|
||||
.Va thisHook .
|
||||
Data bytes of tag corresponding to specified
|
||||
.Va tag_id
|
||||
(type) and
|
||||
.Va tag_cookie
|
||||
are placed in the
|
||||
.Va tag_data
|
||||
array; there must be
|
||||
.Va tag_len
|
||||
of them.
|
||||
Matching and non-matching incoming packets are delivered out the hooks named
|
||||
.Va ifMatch
|
||||
and
|
||||
.Va ifNotMatch ,
|
||||
respectively.
|
||||
If
|
||||
.Va strip
|
||||
flag is non-zero, then found tag is deleted from list of packet tags.
|
||||
.It Dv NGM_TAG_GET_HOOKIN
|
||||
This command takes an
|
||||
.Tn ASCII
|
||||
string argument, the hook name, and returns the
|
||||
corresponding
|
||||
.Vt "struct ng_tag_hookin"
|
||||
as shown above.
|
||||
.It Dv NGM_TAG_SET_HOOKOUT
|
||||
This command sets tags values which will be applied to outgoing
|
||||
packets.
|
||||
The following structure must be supplied as an argument:
|
||||
.Bd -literal -offset 4n
|
||||
struct ng_tag_hookout {
|
||||
char thisHook[NG_HOOKSIZ]; /* name of hook */
|
||||
uint32_t tag_cookie; /* ABI/Module ID */
|
||||
uint16_t tag_id; /* tag ID */
|
||||
uint16_t tag_len; /* length of data */
|
||||
uint8_t tag_data[0]; /* tag data */
|
||||
};
|
||||
.Ed
|
||||
.Pp
|
||||
The hook to be updated is specified in
|
||||
.Va thisHook .
|
||||
Other variables mean basically the same as in
|
||||
.Vt "struct ng_tag_hookin"
|
||||
shown above, except used for setting values in a new tag.
|
||||
.It Dv NGM_TAG_GET_HOOKOUT
|
||||
This command takes an
|
||||
.Tn ASCII
|
||||
string argument, the hook name, and returns the
|
||||
corresponding
|
||||
.Vt "struct ng_tag_hookout"
|
||||
as shown above.
|
||||
.It Dv NGM_TAG_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_tag_hookstat" .
|
||||
.It Dv NGM_TAG_CLR_STATS
|
||||
This command takes an
|
||||
.Tn ASCII
|
||||
string argument, the hook name, and clears the
|
||||
statistics associated with the hook.
|
||||
.It Dv NGM_TAG_GETCLR_STATS
|
||||
This command is identical to
|
||||
.Dv NGM_TAG_GET_STATS ,
|
||||
except that the statistics are also atomically cleared.
|
||||
.El
|
||||
.Pp
|
||||
.Em Note:
|
||||
statistics counters as well as three statistics messages above work
|
||||
only if code was compiled with the
|
||||
.Dv NG_TAG_DEBUG
|
||||
option.
|
||||
The reason for this is that statistics is rarely used in practice,
|
||||
but still consumes CPU cycles for every packet.
|
||||
Moreover, it is even not accurate on SMP systems due to lack of
|
||||
syncronization between threads, as this is very expensive.
|
||||
.Sh SHUTDOWN
|
||||
This node shuts down upon receipt of a
|
||||
.Dv NGM_SHUTDOWN
|
||||
control message, or when all hooks have been disconnected.
|
||||
.Sh EXAMPLES
|
||||
It is possible to do a simple L7 filtering by using
|
||||
.Xr ipfw 8
|
||||
tags in conjunction with
|
||||
.Xr ng_bpf 4
|
||||
traffic analyzer.
|
||||
Let us suppose we need to filter DirectConnect P2P network data traffic,
|
||||
which cannot be done by usual means as it uses random ports.
|
||||
It is known that such data connection always contains a TCP packet with
|
||||
6-byte payload string "$Send|".
|
||||
So we will use ipfw's
|
||||
.Cm netgraph
|
||||
action to divert all TCP packets to an
|
||||
.Xr ng_bpf 4
|
||||
node which will check for the specified string and return non-matching
|
||||
packets to
|
||||
.Xr ipfw 8 .
|
||||
Matching packets are passed to
|
||||
.Xr ng_tag 4
|
||||
node, which will set a tag and pass them back to
|
||||
.Xr ng_bpf 4
|
||||
node on a hook programmed to accept all packets and pass them back to
|
||||
.Xr ipfw 8 .
|
||||
We will use a script provided in
|
||||
.Xr ng_bpf 4
|
||||
manual page for programming node.
|
||||
Note that packets diverted from
|
||||
.Xr ipfw 8
|
||||
to Netgraph have no link-level header, so offsets in
|
||||
.Xr tcpdump 1
|
||||
expressions must be altered accordingly.
|
||||
Thus, we will have expression
|
||||
.Dq Li "ether[40:2]=0x244c && ether[42:4]=0x6f636b20"
|
||||
on incoming from hook and empty expression to match all packets from
|
||||
.Xr ng_tag 4 .
|
||||
.Pp
|
||||
So, this is
|
||||
.Xr ngctl 8
|
||||
script for nodes creating and naming for easier access:
|
||||
.Bd -literal -offset 4n
|
||||
/usr/sbin/ngctl -f- <<-SEQ
|
||||
mkpeer ipfw: bpf 41 ipfw
|
||||
name ipfw:41 dcbpf
|
||||
mkpeer dcbpf: tag matched th1
|
||||
name dcbpf:matched ngdc
|
||||
SEQ
|
||||
.Ed
|
||||
.Pp
|
||||
Now
|
||||
.Dq Li ngdc
|
||||
node (which is of type
|
||||
.Nm )
|
||||
must be programmed to echo all packets received on the
|
||||
.Dq Li th1
|
||||
hook back, with the
|
||||
.Xr ipfw 8
|
||||
tag 412 attached.
|
||||
.Dv MTAG_IPFW
|
||||
value for
|
||||
.Va tag_cookie
|
||||
was taken from file
|
||||
.In netinet/ip_fw.h
|
||||
and value for
|
||||
.Va tag_id
|
||||
is tag number (412), with zero tag length:
|
||||
.Bd -literal -offset 4n
|
||||
ngctl msg ngdc: sethookin { thisHook=\e"th1\e" ifNotMatch=\e"th1\e" }
|
||||
ngctl msg ngdc: sethookout { thisHook=\e"th1\e" \e
|
||||
tag_cookie=1148380143 \e
|
||||
tag_id=412 }
|
||||
.Ed
|
||||
.Pp
|
||||
Don't forget to program
|
||||
.Xr ng_bpf 4
|
||||
.Dq Li ipfw
|
||||
hook with the above expression (see
|
||||
.Xr ng_bpf 4
|
||||
for script doing this) and
|
||||
.Dq Li matched
|
||||
hook with an empty expression:
|
||||
.Bd -literal -offset 4n
|
||||
ngctl msg dcbpf: setprogram { thisHook=\e"matched\e" ifMatch=\e"ipfw\e" \e
|
||||
bpf_prog_len=1 bpf_prog=[ { code=6 k=8192 } ] }
|
||||
.Ed
|
||||
.Pp
|
||||
After finishing with
|
||||
.Xr netgraph 4
|
||||
nodes, add
|
||||
.Xr ipfw 8
|
||||
rules to enable packet flow:
|
||||
.Bd -literal -offset 4n
|
||||
ipfw add 100 netgraph 41 tcp from any to any iplen 46
|
||||
ipfw add 110 reset tcp from any to any tagged 412
|
||||
.Ed
|
||||
.Pp
|
||||
Note: you should ensure that packets are returned to ipfw after processing
|
||||
inside
|
||||
.Xr netgraph 4 ,
|
||||
by setting appropriate
|
||||
.Xr sysctl 8
|
||||
variable:
|
||||
.Bd -literal -offset 4n
|
||||
sysctl net.inet.ip.fw.one_pass=0
|
||||
.Ed
|
||||
.Sh BUGS
|
||||
For manipulating any tags with data payload (that is, all tags with non-zero
|
||||
.Va tag_len )
|
||||
one should care about non-portable machine-dependent representation of
|
||||
tags on the low level as byte stream.
|
||||
Perhaps this should be done by another program rather than manually.
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Nm
|
||||
node type was implemented in
|
||||
.Fx 6.2 .
|
||||
.Sh SEE ALSO
|
||||
.Xr netgraph 4 ,
|
||||
.Xr ng_bpf 4 ,
|
||||
.Xr ng_ipfw 4 ,
|
||||
.Xr ipfw 8 ,
|
||||
.Xr ngctl 8 ,
|
||||
.Xr mbuf_tags 9
|
||||
.Sh AUTHORS
|
||||
.An Vadim Goncharov Aq vadimnuclight@tpu.ru
|
@ -567,6 +567,7 @@ options NETGRAPH_RFC1490
|
||||
options NETGRAPH_SOCKET
|
||||
options NETGRAPH_SPLIT
|
||||
options NETGRAPH_SPPP
|
||||
options NETGRAPH_TAG
|
||||
options NETGRAPH_TCPMSS
|
||||
options NETGRAPH_TEE
|
||||
options NETGRAPH_TTY
|
||||
|
@ -1662,6 +1662,7 @@ netgraph/ng_rfc1490.c optional netgraph_rfc1490
|
||||
netgraph/ng_socket.c optional netgraph_socket
|
||||
netgraph/ng_split.c optional netgraph_split
|
||||
netgraph/ng_sppp.c optional netgraph_sppp
|
||||
netgraph/ng_tag.c optional netgraph_tag
|
||||
netgraph/ng_tcpmss.c optional netgraph_tcpmss
|
||||
netgraph/ng_tee.c optional netgraph_tee
|
||||
netgraph/ng_tty.c optional netgraph_tty
|
||||
|
@ -439,6 +439,7 @@ NETGRAPH_RFC1490 opt_netgraph.h
|
||||
NETGRAPH_SOCKET opt_netgraph.h
|
||||
NETGRAPH_SPLIT opt_netgraph.h
|
||||
NETGRAPH_SPPP opt_netgraph.h
|
||||
NETGRAPH_TAG opt_netgraph.h
|
||||
NETGRAPH_TCPMSS opt_netgraph.h
|
||||
NETGRAPH_TEE opt_netgraph.h
|
||||
NETGRAPH_TTY opt_netgraph.h
|
||||
|
@ -42,6 +42,7 @@ SUBDIR= async \
|
||||
sppp \
|
||||
${_sync_ar} \
|
||||
${_sync_sr} \
|
||||
tag \
|
||||
tcpmss \
|
||||
tee \
|
||||
tty \
|
||||
|
6
sys/modules/netgraph/tag/Makefile
Normal file
6
sys/modules/netgraph/tag/Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
# $FreeBSD$
|
||||
|
||||
KMOD= ng_tag
|
||||
SRCS= ng_tag.c
|
||||
|
||||
.include <bsd.kmod.mk>
|
717
sys/netgraph/ng_tag.c
Normal file
717
sys/netgraph/ng_tag.c
Normal file
@ -0,0 +1,717 @@
|
||||
/*-
|
||||
* Copyright (c) 2006 Vadim Goncharov <vadimnuclight@tpu.ru>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice unmodified, this list of conditions, and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* Portions Copyright (c) 1999 Whistle Communications, Inc.
|
||||
* (ng_bpf by Archie Cobbs <archie@freebsd.org>)
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
/*
|
||||
* TAG NETGRAPH NODE TYPE
|
||||
*
|
||||
* This node type accepts an arbitrary number of hooks. Each hook can be
|
||||
* configured for an mbuf_tags(9) definition and two hook names: a hook
|
||||
* for matched packets, and a hook for packets, that didn't match. Incoming
|
||||
* packets are examined for configured tag, matched packets are delivered
|
||||
* out via first hook, and not matched out via second. If corresponding hook
|
||||
* is not configured, packets are dropped.
|
||||
*
|
||||
* A hook can also have an outgoing tag definition configured, so that
|
||||
* all packets leaving the hook will be unconditionally appended with newly
|
||||
* allocated tag.
|
||||
*
|
||||
* Both hooks can be set to null tag definitions (that is, with zeroed
|
||||
* fields), so that packet tags are unmodified on output or all packets
|
||||
* are unconditionally forwarded to non-matching hook on input. There is
|
||||
* also a possibility to replace tags by specifying strip flag on input
|
||||
* and replacing tag on corresponding output tag (or simply remove tag if
|
||||
* no tag specified on output).
|
||||
*
|
||||
* If compiled with NG_TAG_DEBUG, each hook also keeps statistics about
|
||||
* how many packets have matched, etc.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/mbuf.h>
|
||||
#include <sys/stddef.h>
|
||||
|
||||
#include <netgraph/ng_message.h>
|
||||
#include <netgraph/netgraph.h>
|
||||
#include <netgraph/ng_parse.h>
|
||||
#include <netgraph/ng_tag.h>
|
||||
|
||||
#ifdef NG_SEPARATE_MALLOC
|
||||
MALLOC_DEFINE(M_NETGRAPH_TAG, "netgraph_tag", "netgraph tag node ");
|
||||
#else
|
||||
#define M_NETGRAPH_TAG M_NETGRAPH
|
||||
#endif
|
||||
|
||||
#define ERROUT(x) do { error = (x); goto done; } while (0)
|
||||
|
||||
/*
|
||||
* Per hook private info.
|
||||
*
|
||||
* We've separated API and ABI here, to make easier changes in this node,
|
||||
* if needed. If you want to change representation, please do not break API.
|
||||
* We still keep API structures in memory to simplify access to them for
|
||||
* GET* messages, but most of data is accessed in internal representation
|
||||
* only. The reason for this is to speed things up - if data will be
|
||||
* accessed from API structures, there would be double pointer dereferencing
|
||||
* in the code, which almost necessarily leads to CPU cache misses and
|
||||
* reloads.
|
||||
*
|
||||
* We also do another optimization by using resolved pointers to
|
||||
* destination hooks instead of expensive ng_findhook().
|
||||
*/
|
||||
struct ng_tag_hookinfo {
|
||||
hook_p hi_match; /* matching hook pointer */
|
||||
hook_p hi_nonmatch; /* non-matching hook pointer */
|
||||
uint32_t in_tag_cookie;
|
||||
uint32_t out_tag_cookie;
|
||||
uint16_t in_tag_id;
|
||||
uint16_t in_tag_len;
|
||||
uint16_t out_tag_id;
|
||||
uint16_t out_tag_len;
|
||||
uint8_t strip;
|
||||
void *in_tag_data;
|
||||
void *out_tag_data;
|
||||
struct ng_tag_hookin *in;
|
||||
struct ng_tag_hookout *out;
|
||||
#ifdef NG_TAG_DEBUG
|
||||
struct ng_tag_hookstat stats;
|
||||
#endif
|
||||
};
|
||||
typedef struct ng_tag_hookinfo *hinfo_p;
|
||||
|
||||
/* Netgraph methods. */
|
||||
static ng_constructor_t ng_tag_constructor;
|
||||
static ng_rcvmsg_t ng_tag_rcvmsg;
|
||||
static ng_shutdown_t ng_tag_shutdown;
|
||||
static ng_newhook_t ng_tag_newhook;
|
||||
static ng_rcvdata_t ng_tag_rcvdata;
|
||||
static ng_disconnect_t ng_tag_disconnect;
|
||||
|
||||
/* Internal helper functions. */
|
||||
static int ng_tag_setdata_in(hook_p hook, const struct ng_tag_hookin *hp);
|
||||
static int ng_tag_setdata_out(hook_p hook, const struct ng_tag_hookout *hp);
|
||||
|
||||
/* Parse types for the field 'tag_data' in structs ng_tag_hookin and out. */
|
||||
static int
|
||||
ng_tag_hookinary_getLength(const struct ng_parse_type *type,
|
||||
const u_char *start, const u_char *buf)
|
||||
{
|
||||
const struct ng_tag_hookin *hp;
|
||||
|
||||
hp = (const struct ng_tag_hookin *)
|
||||
(buf - offsetof(struct ng_tag_hookin, tag_data));
|
||||
return (hp->tag_len);
|
||||
}
|
||||
|
||||
static int
|
||||
ng_tag_hookoutary_getLength(const struct ng_parse_type *type,
|
||||
const u_char *start, const u_char *buf)
|
||||
{
|
||||
const struct ng_tag_hookout *hp;
|
||||
|
||||
hp = (const struct ng_tag_hookout *)
|
||||
(buf - offsetof(struct ng_tag_hookout, tag_data));
|
||||
return (hp->tag_len);
|
||||
}
|
||||
|
||||
static const struct ng_parse_type ng_tag_hookinary_type = {
|
||||
&ng_parse_bytearray_type,
|
||||
&ng_tag_hookinary_getLength
|
||||
};
|
||||
|
||||
static const struct ng_parse_type ng_tag_hookoutary_type = {
|
||||
&ng_parse_bytearray_type,
|
||||
&ng_tag_hookoutary_getLength
|
||||
};
|
||||
|
||||
/* Parse type for struct ng_tag_hookin. */
|
||||
static const struct ng_parse_struct_field ng_tag_hookin_type_fields[]
|
||||
= NG_TAG_HOOKIN_TYPE_INFO(&ng_tag_hookinary_type);
|
||||
static const struct ng_parse_type ng_tag_hookin_type = {
|
||||
&ng_parse_struct_type,
|
||||
&ng_tag_hookin_type_fields
|
||||
};
|
||||
|
||||
/* Parse type for struct ng_tag_hookout. */
|
||||
static const struct ng_parse_struct_field ng_tag_hookout_type_fields[]
|
||||
= NG_TAG_HOOKOUT_TYPE_INFO(&ng_tag_hookoutary_type);
|
||||
static const struct ng_parse_type ng_tag_hookout_type = {
|
||||
&ng_parse_struct_type,
|
||||
&ng_tag_hookout_type_fields
|
||||
};
|
||||
|
||||
#ifdef NG_TAG_DEBUG
|
||||
/* Parse type for struct ng_tag_hookstat. */
|
||||
static const struct ng_parse_struct_field ng_tag_hookstat_type_fields[]
|
||||
= NG_TAG_HOOKSTAT_TYPE_INFO;
|
||||
static const struct ng_parse_type ng_tag_hookstat_type = {
|
||||
&ng_parse_struct_type,
|
||||
&ng_tag_hookstat_type_fields
|
||||
};
|
||||
#endif
|
||||
|
||||
/* List of commands and how to convert arguments to/from ASCII. */
|
||||
static const struct ng_cmdlist ng_tag_cmdlist[] = {
|
||||
{
|
||||
NGM_TAG_COOKIE,
|
||||
NGM_TAG_SET_HOOKIN,
|
||||
"sethookin",
|
||||
&ng_tag_hookin_type,
|
||||
NULL
|
||||
},
|
||||
{
|
||||
NGM_TAG_COOKIE,
|
||||
NGM_TAG_GET_HOOKIN,
|
||||
"gethookin",
|
||||
&ng_parse_hookbuf_type,
|
||||
&ng_tag_hookin_type
|
||||
},
|
||||
{
|
||||
NGM_TAG_COOKIE,
|
||||
NGM_TAG_SET_HOOKOUT,
|
||||
"sethookout",
|
||||
&ng_tag_hookout_type,
|
||||
NULL
|
||||
},
|
||||
{
|
||||
NGM_TAG_COOKIE,
|
||||
NGM_TAG_GET_HOOKOUT,
|
||||
"gethookout",
|
||||
&ng_parse_hookbuf_type,
|
||||
&ng_tag_hookout_type
|
||||
},
|
||||
#ifdef NG_TAG_DEBUG
|
||||
{
|
||||
NGM_TAG_COOKIE,
|
||||
NGM_TAG_GET_STATS,
|
||||
"getstats",
|
||||
&ng_parse_hookbuf_type,
|
||||
&ng_tag_hookstat_type
|
||||
},
|
||||
{
|
||||
NGM_TAG_COOKIE,
|
||||
NGM_TAG_CLR_STATS,
|
||||
"clrstats",
|
||||
&ng_parse_hookbuf_type,
|
||||
NULL
|
||||
},
|
||||
{
|
||||
NGM_TAG_COOKIE,
|
||||
NGM_TAG_GETCLR_STATS,
|
||||
"getclrstats",
|
||||
&ng_parse_hookbuf_type,
|
||||
&ng_tag_hookstat_type
|
||||
},
|
||||
#endif
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
/* Netgraph type descriptor. */
|
||||
static struct ng_type typestruct = {
|
||||
.version = NG_ABI_VERSION,
|
||||
.name = NG_TAG_NODE_TYPE,
|
||||
.constructor = ng_tag_constructor,
|
||||
.rcvmsg = ng_tag_rcvmsg,
|
||||
.shutdown = ng_tag_shutdown,
|
||||
.newhook = ng_tag_newhook,
|
||||
.rcvdata = ng_tag_rcvdata,
|
||||
.disconnect = ng_tag_disconnect,
|
||||
.cmdlist = ng_tag_cmdlist,
|
||||
};
|
||||
NETGRAPH_INIT(tag, &typestruct);
|
||||
|
||||
/*
|
||||
* This are default API structures (initialized to zeroes) which are
|
||||
* returned in response to GET* messages when no configuration was made.
|
||||
* One could ask why to have this structures at all when we have
|
||||
* ng_tag_hookinfo initialized to zero and don't need in and out structures
|
||||
* at all to operate. Unfortunatelly, we have to return thisHook field
|
||||
* in response to messages so the fastest and simpliest way is to have
|
||||
* this default structures and initialize thisHook once at hook creation
|
||||
* rather than to do it on every response.
|
||||
*/
|
||||
|
||||
/* Default tag values for a hook that matches nothing. */
|
||||
static const struct ng_tag_hookin ng_tag_default_in = {
|
||||
{ '\0' }, /* to be filled in at hook creation time */
|
||||
{ '\0' },
|
||||
{ '\0' },
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
/* Default tag values for a hook that adds nothing */
|
||||
static const struct ng_tag_hookout ng_tag_default_out = {
|
||||
{ '\0' }, /* to be filled in at hook creation time */
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
/*
|
||||
* Node constructor.
|
||||
*
|
||||
* We don't keep any per-node private data - we do it on per-hook basis.
|
||||
*/
|
||||
static int
|
||||
ng_tag_constructor(node_p node)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add a hook.
|
||||
*/
|
||||
static int
|
||||
ng_tag_newhook(node_p node, hook_p hook, const char *name)
|
||||
{
|
||||
hinfo_p hip;
|
||||
int error;
|
||||
|
||||
/* Create hook private structure. */
|
||||
MALLOC(hip, hinfo_p, sizeof(*hip), M_NETGRAPH_TAG, M_WAITOK | M_ZERO);
|
||||
/* M_WAITOK can't return NULL. */
|
||||
NG_HOOK_SET_PRIVATE(hook, hip);
|
||||
|
||||
/*
|
||||
* After M_ZERO both in and out hook pointers are set to NULL,
|
||||
* as well as all members and pointers to in and out API
|
||||
* structures, so we need to set explicitly only thisHook field
|
||||
* in that structures (after allocating them, of course).
|
||||
*/
|
||||
|
||||
/* Attach the default IN data. */
|
||||
if ((error = ng_tag_setdata_in(hook, &ng_tag_default_in)) != 0) {
|
||||
FREE(hip, M_NETGRAPH_TAG);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* Attach the default OUT data. */
|
||||
if ((error = ng_tag_setdata_out(hook, &ng_tag_default_out)) != 0) {
|
||||
FREE(hip, M_NETGRAPH_TAG);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set hook name. This is done only once at hook creation time
|
||||
* since hook name can't change, rather than to do it on every
|
||||
* response to messages requesting API structures with data who
|
||||
* we are etc.
|
||||
*/
|
||||
strncpy(hip->in->thisHook, name, sizeof(hip->in->thisHook) - 1);
|
||||
hip->in->thisHook[sizeof(hip->in->thisHook) - 1] = '\0';
|
||||
strncpy(hip->out->thisHook, name, sizeof(hip->out->thisHook) - 1);
|
||||
hip->out->thisHook[sizeof(hip->out->thisHook) - 1] = '\0';
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Receive a control message.
|
||||
*/
|
||||
static int
|
||||
ng_tag_rcvmsg(node_p node, item_p item, hook_p lasthook)
|
||||
{
|
||||
struct ng_mesg *msg;
|
||||
struct ng_mesg *resp = NULL;
|
||||
int error = 0;
|
||||
|
||||
NGI_GET_MSG(item, msg);
|
||||
switch (msg->header.typecookie) {
|
||||
case NGM_TAG_COOKIE:
|
||||
switch (msg->header.cmd) {
|
||||
case NGM_TAG_SET_HOOKIN:
|
||||
{
|
||||
struct ng_tag_hookin *const
|
||||
hp = (struct ng_tag_hookin *)msg->data;
|
||||
hook_p hook;
|
||||
|
||||
/* Sanity check. */
|
||||
if (msg->header.arglen < sizeof(*hp)
|
||||
|| msg->header.arglen !=
|
||||
NG_TAG_HOOKIN_SIZE(hp->tag_len))
|
||||
ERROUT(EINVAL);
|
||||
|
||||
/* Find hook. */
|
||||
if ((hook = ng_findhook(node, hp->thisHook)) == NULL)
|
||||
ERROUT(ENOENT);
|
||||
|
||||
/* Set new tag values. */
|
||||
if ((error = ng_tag_setdata_in(hook, hp)) != 0)
|
||||
ERROUT(error);
|
||||
break;
|
||||
}
|
||||
|
||||
case NGM_TAG_SET_HOOKOUT:
|
||||
{
|
||||
struct ng_tag_hookout *const
|
||||
hp = (struct ng_tag_hookout *)msg->data;
|
||||
hook_p hook;
|
||||
|
||||
/* Sanity check. */
|
||||
if (msg->header.arglen < sizeof(*hp)
|
||||
|| msg->header.arglen !=
|
||||
NG_TAG_HOOKOUT_SIZE(hp->tag_len))
|
||||
ERROUT(EINVAL);
|
||||
|
||||
/* Find hook. */
|
||||
if ((hook = ng_findhook(node, hp->thisHook)) == NULL)
|
||||
ERROUT(ENOENT);
|
||||
|
||||
/* Set new tag values. */
|
||||
if ((error = ng_tag_setdata_out(hook, hp)) != 0)
|
||||
ERROUT(error);
|
||||
break;
|
||||
}
|
||||
|
||||
case NGM_TAG_GET_HOOKIN:
|
||||
{
|
||||
struct ng_tag_hookin *hp;
|
||||
hook_p hook;
|
||||
|
||||
/* Sanity check. */
|
||||
if (msg->header.arglen == 0)
|
||||
ERROUT(EINVAL);
|
||||
msg->data[msg->header.arglen - 1] = '\0';
|
||||
|
||||
/* Find hook. */
|
||||
if ((hook = ng_findhook(node, msg->data)) == NULL)
|
||||
ERROUT(ENOENT);
|
||||
|
||||
/* Build response. */
|
||||
hp = ((hinfo_p)NG_HOOK_PRIVATE(hook))->in;
|
||||
NG_MKRESPONSE(resp, msg,
|
||||
NG_TAG_HOOKIN_SIZE(hp->tag_len), M_WAITOK);
|
||||
/* M_WAITOK can't return NULL. */
|
||||
bcopy(hp, resp->data,
|
||||
NG_TAG_HOOKIN_SIZE(hp->tag_len));
|
||||
break;
|
||||
}
|
||||
|
||||
case NGM_TAG_GET_HOOKOUT:
|
||||
{
|
||||
struct ng_tag_hookout *hp;
|
||||
hook_p hook;
|
||||
|
||||
/* Sanity check. */
|
||||
if (msg->header.arglen == 0)
|
||||
ERROUT(EINVAL);
|
||||
msg->data[msg->header.arglen - 1] = '\0';
|
||||
|
||||
/* Find hook. */
|
||||
if ((hook = ng_findhook(node, msg->data)) == NULL)
|
||||
ERROUT(ENOENT);
|
||||
|
||||
/* Build response. */
|
||||
hp = ((hinfo_p)NG_HOOK_PRIVATE(hook))->out;
|
||||
NG_MKRESPONSE(resp, msg,
|
||||
NG_TAG_HOOKOUT_SIZE(hp->tag_len), M_WAITOK);
|
||||
/* M_WAITOK can't return NULL. */
|
||||
bcopy(hp, resp->data,
|
||||
NG_TAG_HOOKOUT_SIZE(hp->tag_len));
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef NG_TAG_DEBUG
|
||||
case NGM_TAG_GET_STATS:
|
||||
case NGM_TAG_CLR_STATS:
|
||||
case NGM_TAG_GETCLR_STATS:
|
||||
{
|
||||
struct ng_tag_hookstat *stats;
|
||||
hook_p hook;
|
||||
|
||||
/* Sanity check. */
|
||||
if (msg->header.arglen == 0)
|
||||
ERROUT(EINVAL);
|
||||
msg->data[msg->header.arglen - 1] = '\0';
|
||||
|
||||
/* Find hook. */
|
||||
if ((hook = ng_findhook(node, msg->data)) == NULL)
|
||||
ERROUT(ENOENT);
|
||||
stats = &((hinfo_p)NG_HOOK_PRIVATE(hook))->stats;
|
||||
|
||||
/* Build response (if desired). */
|
||||
if (msg->header.cmd != NGM_TAG_CLR_STATS) {
|
||||
NG_MKRESPONSE(resp,
|
||||
msg, sizeof(*stats), M_WAITOK);
|
||||
/* M_WAITOK can't return NULL. */
|
||||
bcopy(stats, resp->data, sizeof(*stats));
|
||||
}
|
||||
|
||||
/* Clear stats (if desired). */
|
||||
if (msg->header.cmd != NGM_TAG_GET_STATS)
|
||||
bzero(stats, sizeof(*stats));
|
||||
break;
|
||||
}
|
||||
#endif /* NG_TAG_DEBUG */
|
||||
|
||||
default:
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error = EINVAL;
|
||||
break;
|
||||
}
|
||||
done:
|
||||
NG_RESPOND_MSG(error, node, item, resp);
|
||||
NG_FREE_MSG(msg);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Receive data on a hook.
|
||||
*
|
||||
* Apply the filter, and then drop or forward packet as appropriate.
|
||||
*/
|
||||
static int
|
||||
ng_tag_rcvdata(hook_p hook, item_p item)
|
||||
{
|
||||
struct mbuf *m;
|
||||
struct m_tag *tag = NULL;
|
||||
const hinfo_p hip = NG_HOOK_PRIVATE(hook);
|
||||
uint16_t type, tag_len;
|
||||
uint32_t cookie;
|
||||
hinfo_p dhip;
|
||||
hook_p dest;
|
||||
int totlen;
|
||||
int found = 0, error = 0;
|
||||
|
||||
m = NGI_M(item); /* 'item' still owns it.. we are peeking */
|
||||
totlen = m->m_pkthdr.len;
|
||||
|
||||
#ifdef NG_TAG_DEBUG
|
||||
hip->stats.recvFrames++;
|
||||
hip->stats.recvOctets += totlen;
|
||||
#endif
|
||||
|
||||
/* Looking up incoming tag. */
|
||||
cookie = hip->in_tag_cookie;
|
||||
type = hip->in_tag_id;
|
||||
tag_len = hip->in_tag_len;
|
||||
|
||||
/*
|
||||
* We treat case of all zeroes specially (that is, cookie and
|
||||
* type are equal to zero), as we assume that such tag
|
||||
* can never occur in the wild. So we don't waste time trying
|
||||
* to find such tag (for example, these are zeroes after hook
|
||||
* creation in default structures).
|
||||
*/
|
||||
if ((cookie != 0) || (type != 0)) {
|
||||
tag = m_tag_locate(m, cookie, type, NULL);
|
||||
while (tag != NULL) {
|
||||
if (memcmp((void *)(tag + 1),
|
||||
hip->in_tag_data, tag_len) == 0) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
tag = m_tag_locate(m, cookie, type, tag);
|
||||
}
|
||||
}
|
||||
|
||||
/* See if we got a match and find destination hook. */
|
||||
if (found) {
|
||||
#ifdef NG_TAG_DEBUG
|
||||
hip->stats.recvMatchFrames++;
|
||||
hip->stats.recvMatchOctets += totlen;
|
||||
#endif
|
||||
if (hip->strip)
|
||||
m_tag_delete(m, tag);
|
||||
dest = hip->hi_match;
|
||||
} else
|
||||
dest = hip->hi_nonmatch;
|
||||
if (dest == NULL) {
|
||||
NG_FREE_ITEM(item);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* Deliver frame out destination hook. */
|
||||
dhip = NG_HOOK_PRIVATE(dest);
|
||||
|
||||
#ifdef NG_TAG_DEBUG
|
||||
dhip->stats.xmitOctets += totlen;
|
||||
dhip->stats.xmitFrames++;
|
||||
#endif
|
||||
|
||||
cookie = dhip->out_tag_cookie;
|
||||
type = dhip->out_tag_id;
|
||||
tag_len = dhip->out_tag_len;
|
||||
|
||||
if ((cookie != 0) || (type != 0)) {
|
||||
tag = m_tag_alloc(cookie, type, tag_len, M_NOWAIT);
|
||||
/* XXX may be free the mbuf if tag allocation failed? */
|
||||
if (tag != NULL) {
|
||||
if (tag_len != 0) {
|
||||
/* copy tag data to its place */
|
||||
memcpy((void *)(tag + 1),
|
||||
dhip->out_tag_data, tag_len);
|
||||
}
|
||||
m_tag_prepend(m, tag);
|
||||
}
|
||||
}
|
||||
|
||||
NG_FWD_ITEM_HOOK(error, item, dest);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Shutdown processing.
|
||||
*/
|
||||
static int
|
||||
ng_tag_shutdown(node_p node)
|
||||
{
|
||||
NG_NODE_UNREF(node);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Hook disconnection.
|
||||
*
|
||||
* We must check all hooks, since they may reference this one.
|
||||
*/
|
||||
static int
|
||||
ng_tag_disconnect(hook_p hook)
|
||||
{
|
||||
const hinfo_p hip = NG_HOOK_PRIVATE(hook);
|
||||
node_p node = NG_HOOK_NODE(hook);
|
||||
hook_p hook2;
|
||||
|
||||
KASSERT(hip != NULL, ("%s: null info", __func__));
|
||||
|
||||
LIST_FOREACH(hook2, &node->nd_hooks, hk_hooks) {
|
||||
hinfo_p priv = NG_HOOK_PRIVATE(hook2);
|
||||
|
||||
if (priv->hi_match == hook)
|
||||
priv->hi_match = NULL;
|
||||
if (priv->hi_nonmatch == hook)
|
||||
priv->hi_nonmatch = NULL;
|
||||
}
|
||||
|
||||
FREE(hip->in, M_NETGRAPH_TAG);
|
||||
FREE(hip->out, M_NETGRAPH_TAG);
|
||||
FREE(hip, M_NETGRAPH_TAG);
|
||||
NG_HOOK_SET_PRIVATE(hook, NULL); /* for good measure */
|
||||
if ((NG_NODE_NUMHOOKS(NG_HOOK_NODE(hook)) == 0) &&
|
||||
(NG_NODE_IS_VALID(NG_HOOK_NODE(hook)))) {
|
||||
ng_rmnode_self(NG_HOOK_NODE(hook));
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
HELPER STUFF
|
||||
************************************************************************/
|
||||
|
||||
/*
|
||||
* Set the IN tag values associated with a hook.
|
||||
*/
|
||||
static int
|
||||
ng_tag_setdata_in(hook_p hook, const struct ng_tag_hookin *hp0)
|
||||
{
|
||||
const hinfo_p hip = NG_HOOK_PRIVATE(hook);
|
||||
struct ng_tag_hookin *hp;
|
||||
int size;
|
||||
|
||||
/* Make a copy of the tag values and data. */
|
||||
size = NG_TAG_HOOKIN_SIZE(hp0->tag_len);
|
||||
MALLOC(hp, struct ng_tag_hookin *, size, M_NETGRAPH_TAG, M_WAITOK);
|
||||
/* M_WAITOK can't return NULL. */
|
||||
bcopy(hp0, hp, size);
|
||||
|
||||
/* Free previous tag, if any, and assign new one. */
|
||||
if (hip->in != NULL)
|
||||
FREE(hip->in, M_NETGRAPH_TAG);
|
||||
hip->in = hp;
|
||||
|
||||
/*
|
||||
* Resolve hook names to pointers.
|
||||
*
|
||||
* As ng_findhook() is expensive operation to do it on every packet
|
||||
* after tag matching check, we do it here and use resolved pointers
|
||||
* where appropriate.
|
||||
*
|
||||
* XXX The drawback is that user can configure a hook to use
|
||||
* ifMatch/ifNotMatch hooks that do not yet exist and will be added
|
||||
* by user later, so that resolved pointers will be NULL even
|
||||
* if the hook already exists, causing node to drop packets and
|
||||
* user to report bugs. We could do check for this situation on
|
||||
* every hook creation with pointers correction, but that involves
|
||||
* re-resolving for all pointers in all hooks, up to O(n^2) operations,
|
||||
* so we better document this in man page for user not to do
|
||||
* configuration before creating all hooks.
|
||||
*/
|
||||
hip->hi_match = ng_findhook(NG_HOOK_NODE(hook), hip->in->ifMatch);
|
||||
hip->hi_nonmatch = ng_findhook(NG_HOOK_NODE(hook), hip->in->ifNotMatch);
|
||||
|
||||
/* Fill internal values from API structures. */
|
||||
hip->in_tag_cookie = hip->in->tag_cookie;
|
||||
hip->in_tag_id = hip->in->tag_id;
|
||||
hip->in_tag_len = hip->in->tag_len;
|
||||
hip->strip = hip->in->strip;
|
||||
hip->in_tag_data = (void*)(hip->in->tag_data);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the OUT tag values associated with a hook.
|
||||
*/
|
||||
static int
|
||||
ng_tag_setdata_out(hook_p hook, const struct ng_tag_hookout *hp0)
|
||||
{
|
||||
const hinfo_p hip = NG_HOOK_PRIVATE(hook);
|
||||
struct ng_tag_hookout *hp;
|
||||
int size;
|
||||
|
||||
/* Make a copy of the tag values and data. */
|
||||
size = NG_TAG_HOOKOUT_SIZE(hp0->tag_len);
|
||||
MALLOC(hp, struct ng_tag_hookout *, size, M_NETGRAPH_TAG, M_WAITOK);
|
||||
/* M_WAITOK can't return NULL. */
|
||||
bcopy(hp0, hp, size);
|
||||
|
||||
/* Free previous tag, if any, and assign new one. */
|
||||
if (hip->out != NULL)
|
||||
FREE(hip->out, M_NETGRAPH_TAG);
|
||||
hip->out = hp;
|
||||
|
||||
/* Fill internal values from API structures. */
|
||||
hip->out_tag_cookie = hip->out->tag_cookie;
|
||||
hip->out_tag_id = hip->out->tag_id;
|
||||
hip->out_tag_len = hip->out->tag_len;
|
||||
hip->out_tag_data = (void*)(hip->out->tag_data);
|
||||
return (0);
|
||||
}
|
||||
|
130
sys/netgraph/ng_tag.h
Normal file
130
sys/netgraph/ng_tag.h
Normal file
@ -0,0 +1,130 @@
|
||||
/*-
|
||||
* Copyright (c) 2006 Vadim Goncharov <vadimnuclight@tpu.ru>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice unmodified, this list of conditions, and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _NETGRAPH_NG_TAG_H_
|
||||
#define _NETGRAPH_NG_TAG_H_
|
||||
|
||||
/* Node type name and magic cookie. */
|
||||
#define NG_TAG_NODE_TYPE "tag"
|
||||
#define NGM_TAG_COOKIE 1149771193
|
||||
|
||||
/*
|
||||
* The types of tag_cookie, tag_len and tag_id in structures below
|
||||
* must be the same as corresponding members m_tag_cookie, m_tag_len
|
||||
* and m_tag_id in struct m_tag (defined in <sys/mbuf.h>).
|
||||
*/
|
||||
|
||||
/* Tag match structure for every (input) hook. */
|
||||
struct ng_tag_hookin {
|
||||
char thisHook[NG_HOOKSIZ]; /* name of hook */
|
||||
char ifMatch[NG_HOOKSIZ]; /* match dest hook */
|
||||
char ifNotMatch[NG_HOOKSIZ]; /* !match dest hook */
|
||||
uint8_t strip; /* strip tag if found */
|
||||
uint32_t tag_cookie; /* ABI/Module ID */
|
||||
uint16_t tag_id; /* tag ID */
|
||||
uint16_t tag_len; /* length of data */
|
||||
uint8_t tag_data[0]; /* tag data */
|
||||
};
|
||||
|
||||
/* Tag set structure for every (output) hook. */
|
||||
struct ng_tag_hookout {
|
||||
char thisHook[NG_HOOKSIZ]; /* name of hook */
|
||||
uint32_t tag_cookie; /* ABI/Module ID */
|
||||
uint16_t tag_id; /* tag ID */
|
||||
uint16_t tag_len; /* length of data */
|
||||
uint8_t tag_data[0]; /* tag data */
|
||||
};
|
||||
|
||||
#define NG_TAG_HOOKIN_SIZE(taglen) \
|
||||
(sizeof(struct ng_tag_hookin) + (taglen))
|
||||
|
||||
#define NG_TAG_HOOKOUT_SIZE(taglen) \
|
||||
(sizeof(struct ng_tag_hookout) + (taglen))
|
||||
|
||||
/* Keep this in sync with the above structures definitions. */
|
||||
#define NG_TAG_HOOKIN_TYPE_INFO(tdtype) { \
|
||||
{ "thisHook", &ng_parse_hookbuf_type }, \
|
||||
{ "ifMatch", &ng_parse_hookbuf_type }, \
|
||||
{ "ifNotMatch", &ng_parse_hookbuf_type }, \
|
||||
{ "strip", &ng_parse_uint8_type }, \
|
||||
{ "tag_cookie", &ng_parse_uint32_type }, \
|
||||
{ "tag_id", &ng_parse_uint16_type }, \
|
||||
{ "tag_len", &ng_parse_uint16_type }, \
|
||||
{ "tag_data", (tdtype) }, \
|
||||
{ NULL } \
|
||||
}
|
||||
|
||||
#define NG_TAG_HOOKOUT_TYPE_INFO(tdtype) { \
|
||||
{ "thisHook", &ng_parse_hookbuf_type }, \
|
||||
{ "tag_cookie", &ng_parse_uint32_type }, \
|
||||
{ "tag_id", &ng_parse_uint16_type }, \
|
||||
{ "tag_len", &ng_parse_uint16_type }, \
|
||||
{ "tag_data", (tdtype) }, \
|
||||
{ NULL } \
|
||||
}
|
||||
|
||||
#ifdef NG_TAG_DEBUG
|
||||
|
||||
/* Statistics structure for one hook. */
|
||||
struct ng_tag_hookstat {
|
||||
uint64_t recvFrames;
|
||||
uint64_t recvOctets;
|
||||
uint64_t recvMatchFrames;
|
||||
uint64_t recvMatchOctets;
|
||||
uint64_t xmitFrames;
|
||||
uint64_t xmitOctets;
|
||||
};
|
||||
|
||||
/* Keep this in sync with the above structure definition. */
|
||||
#define NG_TAG_HOOKSTAT_TYPE_INFO { \
|
||||
{ "recvFrames", &ng_parse_uint64_type }, \
|
||||
{ "recvOctets", &ng_parse_uint64_type }, \
|
||||
{ "recvMatchFrames", &ng_parse_uint64_type }, \
|
||||
{ "recvMatchOctets", &ng_parse_uint64_type }, \
|
||||
{ "xmitFrames", &ng_parse_uint64_type }, \
|
||||
{ "xmitOctets", &ng_parse_uint64_type }, \
|
||||
{ NULL } \
|
||||
}
|
||||
|
||||
#endif /* NG_TAG_DEBUG */
|
||||
|
||||
/* Netgraph commands. */
|
||||
enum {
|
||||
NGM_TAG_SET_HOOKIN = 1, /* supply a struct ng_tag_hookin */
|
||||
NGM_TAG_GET_HOOKIN, /* returns a struct ng_tag_hookin */
|
||||
NGM_TAG_SET_HOOKOUT, /* supply a struct ng_tag_hookout */
|
||||
NGM_TAG_GET_HOOKOUT, /* returns a struct ng_tag_hookout */
|
||||
#ifdef NG_TAG_DEBUG
|
||||
NGM_TAG_GET_STATS, /* supply name as char[NG_HOOKSIZ] */
|
||||
NGM_TAG_CLR_STATS, /* supply name as char[NG_HOOKSIZ] */
|
||||
NGM_TAG_GETCLR_STATS, /* supply name as char[NG_HOOKSIZ] */
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* _NETGRAPH_NG_TAG_H_ */
|
Loading…
Reference in New Issue
Block a user