1999-10-21 09:06:11 +00:00
|
|
|
.\" Copyright (c) 1996-1999 Whistle Communications, Inc.
|
|
|
|
.\" All rights reserved.
|
|
|
|
.\"
|
|
|
|
.\" Subject to the following obligations and disclaimer of warranty, use and
|
|
|
|
.\" redistribution of this software, in source or object code forms, with or
|
|
|
|
.\" without modifications are expressly permitted by Whistle Communications;
|
|
|
|
.\" provided, however, that:
|
|
|
|
.\" 1. Any and all reproductions of the source or object code must include the
|
|
|
|
.\" copyright notice above and the following disclaimer of warranties; and
|
|
|
|
.\" 2. No rights are granted, in any manner or form, to use Whistle
|
|
|
|
.\" Communications, Inc. trademarks, including the mark "WHISTLE
|
|
|
|
.\" COMMUNICATIONS" on advertising, endorsements, or otherwise except as
|
|
|
|
.\" such appears in the above copyright notice or in the software.
|
|
|
|
.\"
|
|
|
|
.\" THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
|
|
|
|
.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
|
|
|
|
.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
|
|
|
|
.\" INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
|
|
|
|
.\" MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
|
|
|
|
.\" WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
|
|
|
|
.\" REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
|
|
|
|
.\" SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
|
|
|
|
.\" IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
|
|
|
|
.\" RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
|
|
|
|
.\" WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
|
|
|
.\" PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
|
|
.\" SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
|
|
|
|
.\" OF SUCH DAMAGE.
|
|
|
|
.\"
|
2000-10-26 15:30:44 +00:00
|
|
|
.\" Authors: Julian Elischer <julian@FreeBSD.org>
|
|
|
|
.\" Archie Cobbs <archie@FreeBSD.org>
|
1999-10-21 09:06:11 +00:00
|
|
|
.\"
|
|
|
|
.\" $FreeBSD$
|
|
|
|
.\" $Whistle: netgraph.4,v 1.7 1999/01/28 23:54:52 julian Exp $
|
|
|
|
.\"
|
|
|
|
.Dd January 19, 1999
|
|
|
|
.Dt NETGRAPH 4
|
|
|
|
.Os FreeBSD
|
|
|
|
.Sh NAME
|
|
|
|
.Nm netgraph
|
|
|
|
.Nd graph based kernel networking subsystem
|
|
|
|
.Sh DESCRIPTION
|
|
|
|
The
|
|
|
|
.Nm
|
|
|
|
system provides a uniform and modular system for the implementation
|
|
|
|
of kernel objects which perform various networking functions. The objects,
|
|
|
|
known as
|
|
|
|
.Em nodes ,
|
|
|
|
can be arranged into arbitrarily complicated graphs. Nodes have
|
|
|
|
.Em hooks
|
|
|
|
which are used to connect two nodes together, forming the edges in the graph.
|
|
|
|
Nodes communicate along the edges to process data, implement protocols, etc.
|
|
|
|
.Pp
|
|
|
|
The aim of
|
|
|
|
.Nm
|
|
|
|
is to supplement rather than replace the existing kernel networking
|
1999-11-30 02:45:32 +00:00
|
|
|
infrastructure. It provides:
|
1999-10-21 09:06:11 +00:00
|
|
|
.Pp
|
|
|
|
.Bl -bullet -compact -offset 2n
|
|
|
|
.It
|
|
|
|
A flexible way of combining protocol and link level drivers
|
|
|
|
.It
|
|
|
|
A modular way to implement new protocols
|
|
|
|
.It
|
|
|
|
A common framework for kernel entities to inter-communicate
|
|
|
|
.It
|
|
|
|
A reasonably fast, kernel-based implementation
|
|
|
|
.El
|
|
|
|
.Sh Nodes and Types
|
|
|
|
The most fundamental concept in
|
|
|
|
.Nm
|
|
|
|
is that of a
|
|
|
|
.Em node .
|
|
|
|
All nodes implement a number of predefined methods which allow them
|
|
|
|
to interact with other nodes in a well defined manner.
|
|
|
|
.Pp
|
|
|
|
Each node has a
|
|
|
|
.Em type ,
|
|
|
|
which is a static property of the node determined at node creation time.
|
1999-12-21 01:25:21 +00:00
|
|
|
A node's type is described by a unique
|
|
|
|
.Tn ASCII
|
|
|
|
type name.
|
1999-10-21 09:06:11 +00:00
|
|
|
The type implies what the node does and how it may be connected
|
|
|
|
to other nodes.
|
|
|
|
.Pp
|
|
|
|
In object-oriented language, types are classes and nodes are instances
|
|
|
|
of their respective class. All node types are subclasses of the generic node
|
|
|
|
type, and hence inherit certain common functionality and capabilities
|
1999-12-21 01:25:21 +00:00
|
|
|
(e.g., the ability to have an
|
|
|
|
.Tn ASCII
|
|
|
|
name).
|
1999-10-21 09:06:11 +00:00
|
|
|
.Pp
|
1999-12-21 01:25:21 +00:00
|
|
|
Nodes may be assigned a globally unique
|
|
|
|
.Tn ASCII
|
|
|
|
name which can be
|
1999-10-21 09:06:11 +00:00
|
|
|
used to refer to the node.
|
1999-12-21 01:25:21 +00:00
|
|
|
The name must not contain the characters
|
2000-12-29 09:18:45 +00:00
|
|
|
.Dq .\&
|
1999-12-21 01:25:21 +00:00
|
|
|
or
|
|
|
|
.Dq \&:
|
|
|
|
and is limited to
|
1999-10-21 09:06:11 +00:00
|
|
|
.Dv "NG_NODELEN + 1"
|
|
|
|
characters (including NUL byte).
|
|
|
|
.Pp
|
|
|
|
Each node instance has a unique
|
|
|
|
.Em ID number
|
|
|
|
which is expressed as a 32-bit hex value. This value may be used to
|
1999-12-21 01:25:21 +00:00
|
|
|
refer to a node when there is no
|
|
|
|
.Tn ASCII
|
|
|
|
name assigned to it.
|
1999-10-21 09:06:11 +00:00
|
|
|
.Sh Hooks
|
|
|
|
Nodes are connected to other nodes by connecting a pair of
|
|
|
|
.Em hooks ,
|
|
|
|
one from each node. Data flows bidirectionally between nodes along
|
|
|
|
connected pairs of hooks. A node may have as many hooks as it
|
|
|
|
needs, and may assign whatever meaning it wants to a hook.
|
|
|
|
.Pp
|
|
|
|
Hooks have these properties:
|
|
|
|
.Pp
|
|
|
|
.Bl -bullet -compact -offset 2n
|
|
|
|
.It
|
1999-12-21 01:25:21 +00:00
|
|
|
A hook has an
|
|
|
|
.Tn ASCII
|
|
|
|
name which is unique among all hooks
|
1999-10-21 09:06:11 +00:00
|
|
|
on that node (other hooks on other nodes may have the same name).
|
1999-12-21 01:25:21 +00:00
|
|
|
The name must not contain a
|
2000-12-29 09:18:45 +00:00
|
|
|
.Dq .\&
|
1999-12-21 01:25:21 +00:00
|
|
|
or a
|
|
|
|
.Dq \&:
|
|
|
|
and is
|
1999-10-21 09:06:11 +00:00
|
|
|
limited to
|
|
|
|
.Dv "NG_HOOKLEN + 1"
|
|
|
|
characters (including NUL byte).
|
|
|
|
.It
|
|
|
|
A hook is always connected to another hook. That is, hooks are
|
|
|
|
created at the time they are connected, and breaking an edge by
|
|
|
|
removing either hook destroys both hooks.
|
2000-12-12 18:52:14 +00:00
|
|
|
.It
|
|
|
|
A hook can be set into a state where incoming packets are always queued
|
|
|
|
by the input queuing system, rather than being delivered directly. This
|
|
|
|
is used when the two joined nodes need to be decoupled, e.g. if they are
|
|
|
|
running at different processor priority levels. (spl)
|
1999-10-21 09:06:11 +00:00
|
|
|
.El
|
|
|
|
.Pp
|
|
|
|
A node may decide to assign special meaning to some hooks.
|
1999-12-21 01:25:21 +00:00
|
|
|
For example, connecting to the hook named
|
|
|
|
.Dq debug
|
|
|
|
might trigger
|
1999-10-21 09:06:11 +00:00
|
|
|
the node to start sending debugging information to that hook.
|
|
|
|
.Sh Data Flow
|
|
|
|
Two types of information flow between nodes: data messages and
|
|
|
|
control messages. Data messages are passed in mbuf chains along the edges
|
|
|
|
in the graph, one edge at a time. The first mbuf in a chain must have the
|
|
|
|
.Dv M_PKTHDR
|
|
|
|
flag set. Each node decides how to handle data coming in on its hooks.
|
|
|
|
.Pp
|
1999-11-30 02:45:32 +00:00
|
|
|
Control messages are type-specific C structures sent from one node
|
|
|
|
directly to some arbitrary other node. Control messages have a common
|
|
|
|
header format, followed by type-specific data, and are binary structures
|
|
|
|
for efficiency. However, node types also may support conversion of the
|
|
|
|
type specific data between binary and
|
1999-12-21 01:25:21 +00:00
|
|
|
.Tn ASCII
|
|
|
|
for debugging and human interface purposes (see the
|
1999-11-30 02:45:32 +00:00
|
|
|
.Dv NGM_ASCII2BINARY
|
|
|
|
and
|
|
|
|
.Dv NGM_BINARY2ASCII
|
|
|
|
generic control messages below). Nodes are not required to support
|
|
|
|
these conversions.
|
|
|
|
.Pp
|
2000-12-12 18:52:14 +00:00
|
|
|
There are three ways to address a control message. If
|
1999-10-21 09:06:11 +00:00
|
|
|
there is a sequence of edges connecting the two nodes, the message
|
1999-12-21 01:25:21 +00:00
|
|
|
may be
|
|
|
|
.Dq source routed
|
|
|
|
by specifying the corresponding sequence
|
2000-12-12 18:52:14 +00:00
|
|
|
of
|
|
|
|
.Tn ASCII
|
|
|
|
hook names as the destination address for the message (relative
|
|
|
|
addressing). If the destination is adjacent to the source, then the source
|
|
|
|
node may simply specify (as a pointer in the code) the hook across which the
|
|
|
|
message should be sent. Otherwise, the recipient node global
|
1999-12-21 01:25:21 +00:00
|
|
|
.Tn ASCII
|
|
|
|
name
|
1999-10-21 09:06:11 +00:00
|
|
|
(or equivalent ID based name) is used as the destination address
|
2000-12-12 18:52:14 +00:00
|
|
|
for the message (absolute addressing). The two types of
|
|
|
|
.Tn ASCII
|
|
|
|
addressing
|
1999-10-21 09:06:11 +00:00
|
|
|
may be combined, by specifying an absolute start node and a sequence
|
2000-12-12 18:52:14 +00:00
|
|
|
of hooks. Only the
|
|
|
|
.Tn ASCII
|
|
|
|
addressing modes are available to control programs outside the kernel,
|
|
|
|
as use of direct pointers is limited of course to kernel modules.
|
1999-10-21 09:06:11 +00:00
|
|
|
.Pp
|
|
|
|
Messages often represent commands that are followed by a reply message
|
|
|
|
in the reverse direction. To facilitate this, the recipient of a
|
1999-12-21 01:25:21 +00:00
|
|
|
control message is supplied with a
|
|
|
|
.Dq return address
|
2000-12-12 18:52:14 +00:00
|
|
|
that is suitable for addressing a reply.
|
1999-10-21 09:06:11 +00:00
|
|
|
.Pp
|
|
|
|
Each control message contains a 32 bit value called a
|
|
|
|
.Em typecookie
|
|
|
|
indicating the type of the message, i.e., how to interpret it.
|
|
|
|
Typically each type defines a unique typecookie for the messages
|
|
|
|
that it understands. However, a node may choose to recognize and
|
|
|
|
implement more than one type of message.
|
2000-04-30 10:01:11 +00:00
|
|
|
.Pp
|
2000-12-12 18:52:14 +00:00
|
|
|
If a message is delivered to an address that implies that it arrived
|
|
|
|
at that node through a particular hook, (as opposed to having been directly
|
|
|
|
addressed using its ID or global name), then that hook is identified to the
|
2000-04-30 10:01:11 +00:00
|
|
|
receiving node. This allows a message to be rerouted or passed on, should
|
2000-12-12 18:52:14 +00:00
|
|
|
a node decide that this is required, in much the same way that data packets
|
|
|
|
are passed around between nodes. A set of standard
|
|
|
|
messages for flow control and link management purposes are
|
|
|
|
defined by the base system that are usually
|
|
|
|
passed around in this manner. Flow control message would usually travel
|
|
|
|
in the opposite direction to the data to which they pertain.
|
2001-01-06 00:46:47 +00:00
|
|
|
.Sh Netgraph is (usually) Functional
|
1999-10-21 09:06:11 +00:00
|
|
|
In order to minimize latency, most
|
1999-12-21 01:25:21 +00:00
|
|
|
.Nm
|
1999-10-21 09:06:11 +00:00
|
|
|
operations are functional.
|
|
|
|
That is, data and control messages are delivered by making function
|
|
|
|
calls rather than by using queues and mailboxes. For example, if node
|
|
|
|
A wishes to send a data mbuf to neighboring node B, it calls the
|
|
|
|
generic
|
|
|
|
.Nm
|
|
|
|
data delivery function. This function in turn locates
|
1999-12-21 01:25:21 +00:00
|
|
|
node B and calls B's
|
|
|
|
.Dq receive data
|
2000-12-12 18:52:14 +00:00
|
|
|
method. There are exceptions to this.
|
2000-04-30 10:01:11 +00:00
|
|
|
.Pp
|
2001-01-06 00:46:47 +00:00
|
|
|
Each node has an input queue, and some operations can be considered to
|
|
|
|
be 'writers' in that they alter the state of the node. Obviously in an SMP
|
|
|
|
world it would be bad if the state of a node were changed while another
|
|
|
|
data packet were transiting the node. For this purpose, the input queue
|
|
|
|
implements a
|
|
|
|
.Em reader/writer
|
|
|
|
semantic so that when there is a writer in the node, all other requests
|
|
|
|
are queued, and while there are readers, a writer, and any following
|
|
|
|
packets are queued. In the case where there is no reason to queue the
|
|
|
|
data, the input method is called directly, as mentionned above.
|
|
|
|
.Pp
|
|
|
|
A node may declare that all requests should be considered as writers,
|
|
|
|
or that requests coming in over a particular hook should be considered to
|
|
|
|
be a writer, or even that packets leaving or entering across a particular
|
|
|
|
hook should always be queued, rather than delivered directly (often useful
|
|
|
|
for interrupt routines who want to get back to the hardware quickly).
|
|
|
|
By default, all controll message packets are considered to be writers
|
|
|
|
unless specifically declared to be a reader in their definition. (see
|
|
|
|
NGM_READONLY in ng_message.h)
|
2000-04-30 10:01:11 +00:00
|
|
|
.Pp
|
|
|
|
While this mode of operation
|
1999-10-21 09:06:11 +00:00
|
|
|
results in good performance, it has a few implications for node
|
|
|
|
developers:
|
|
|
|
.Pp
|
|
|
|
.Bl -bullet -compact -offset 2n
|
|
|
|
.It
|
|
|
|
Whenever a node delivers a data or control message, the node
|
2000-04-30 10:01:11 +00:00
|
|
|
may need to allow for the possibility of receiving a returning
|
|
|
|
message before the original delivery function call returns.
|
1999-10-21 09:06:11 +00:00
|
|
|
.It
|
|
|
|
Netgraph nodes and support routines generally run at
|
1999-12-21 01:25:21 +00:00
|
|
|
.Fn splnet .
|
1999-10-21 09:06:11 +00:00
|
|
|
However, some nodes may want to send data and control messages
|
2000-12-12 18:52:14 +00:00
|
|
|
from a different priority level. Netgraph supplies a mechanism which
|
|
|
|
utilizes the NETISR system to move message and data delivery to
|
1999-12-21 01:25:21 +00:00
|
|
|
.Fn splnet .
|
2000-04-30 10:01:11 +00:00
|
|
|
Nodes that run at other priorities (e.g. interfaces) can be directly
|
|
|
|
linked to other nodes so that the combination runs at the other priority,
|
2000-12-12 18:52:14 +00:00
|
|
|
however any interaction with nodes running at splnet MUST be achieved via the
|
2000-04-30 10:01:11 +00:00
|
|
|
queueing functions, (which use the
|
|
|
|
.Fn netisr
|
|
|
|
feature of the kernel).
|
1999-10-21 09:06:11 +00:00
|
|
|
Note that messages are always received at
|
1999-12-21 01:25:21 +00:00
|
|
|
.Fn splnet .
|
1999-10-21 09:06:11 +00:00
|
|
|
.It
|
|
|
|
It's possible for an infinite loop to occur if the graph contains cycles.
|
|
|
|
.El
|
|
|
|
.Pp
|
|
|
|
So far, these issues have not proven problematical in practice.
|
|
|
|
.Sh Interaction With Other Parts of the Kernel
|
|
|
|
A node may have a hidden interaction with other components of the
|
|
|
|
kernel outside of the
|
|
|
|
.Nm
|
|
|
|
subsystem, such as device hardware,
|
|
|
|
kernel protocol stacks, etc. In fact, one of the benefits of
|
|
|
|
.Nm
|
|
|
|
is the ability to join disparate kernel networking entities together in a
|
|
|
|
consistent communication framework.
|
|
|
|
.Pp
|
|
|
|
An example is the node type
|
|
|
|
.Em socket
|
|
|
|
which is both a netgraph node and a
|
|
|
|
.Xr socket 2
|
|
|
|
BSD socket in the protocol family
|
|
|
|
.Dv PF_NETGRAPH .
|
|
|
|
Socket nodes allow user processes to participate in
|
2000-11-20 18:41:33 +00:00
|
|
|
.Nm .
|
1999-10-21 09:06:11 +00:00
|
|
|
Other nodes communicate with socket nodes using the usual methods, and the
|
|
|
|
node hides the fact that it is also passing information to and from a
|
|
|
|
cooperating user process.
|
|
|
|
.Pp
|
|
|
|
Another example is a device driver that presents
|
|
|
|
a node interface to the hardware.
|
|
|
|
.Sh Node Methods
|
|
|
|
Nodes are notified of the following actions via function calls
|
|
|
|
to the following node methods (all at
|
1999-12-21 01:25:21 +00:00
|
|
|
.Fn splnet )
|
1999-10-21 09:06:11 +00:00
|
|
|
and may accept or reject that action (by returning the appropriate
|
|
|
|
error code):
|
|
|
|
.Bl -tag -width xxx
|
|
|
|
.It Creation of a new node
|
|
|
|
The constructor for the type is called. If creation of a new node is
|
|
|
|
allowed, the constructor must call the generic node creation
|
|
|
|
function (in object-oriented terms, the superclass constructor)
|
|
|
|
and then allocate any special resources it needs. For nodes that
|
|
|
|
correspond to hardware, this is typically done during the device
|
1999-12-21 01:25:21 +00:00
|
|
|
attach routine. Often a global
|
|
|
|
.Tn ASCII
|
|
|
|
name corresponding to the
|
1999-10-21 09:06:11 +00:00
|
|
|
device name is assigned here as well.
|
|
|
|
.It Creation of a new hook
|
|
|
|
The hook is created and tentatively
|
|
|
|
linked to the node, and the node is told about the name that will be
|
|
|
|
used to describe this hook. The node sets up any special data structures
|
|
|
|
it needs, or may reject the connection, based on the name of the hook.
|
|
|
|
.It Successful connection of two hooks
|
|
|
|
After both ends have accepted their
|
|
|
|
hooks, and the links have been made, the nodes get a chance to
|
|
|
|
find out who their peer is across the link and can then decide to reject
|
2000-12-12 18:52:14 +00:00
|
|
|
the connection. Tear-down is automatic. This is also the time at which
|
|
|
|
a node may decide whether to set a particular hook (or its peer) into
|
|
|
|
.Em queuing
|
|
|
|
mode.
|
1999-10-21 09:06:11 +00:00
|
|
|
.It Destruction of a hook
|
|
|
|
The node is notified of a broken connection. The node may consider some hooks
|
|
|
|
to be critical to operation and others to be expendable: the disconnection
|
|
|
|
of one hook may be an acceptable event while for another it
|
|
|
|
may effect a total shutdown for the node.
|
|
|
|
.It Shutdown of a node
|
|
|
|
This method allows a node to clean up
|
|
|
|
and to ensure that any actions that need to be performed
|
|
|
|
at this time are taken. The method must call the generic (i.e., superclass)
|
|
|
|
node destructor to get rid of the generic components of the node.
|
|
|
|
Some nodes (usually associated with a piece of hardware) may be
|
|
|
|
.Em persistent
|
|
|
|
in that a shutdown breaks all edges and resets the node,
|
|
|
|
but doesn't remove it, in which case the generic destructor is not called.
|
|
|
|
.El
|
|
|
|
.Sh Sending and Receiving Data
|
2000-12-12 18:52:14 +00:00
|
|
|
Two other methods are also supported by all nodes:
|
1999-10-21 09:06:11 +00:00
|
|
|
.Bl -tag -width xxx
|
|
|
|
.It Receive data message
|
2001-01-06 00:46:47 +00:00
|
|
|
A
|
|
|
|
.Em Netgraph queueable reqest item
|
|
|
|
(usually refered to as an
|
|
|
|
.Em item
|
|
|
|
is recieved by the function.
|
|
|
|
The item contains a pointer to an mbuf and metadata about the packet.
|
|
|
|
.Pp
|
|
|
|
The node is notified on which hook the item arrived,
|
1999-10-21 09:06:11 +00:00
|
|
|
and can use this information in its processing decision.
|
2000-04-30 10:01:11 +00:00
|
|
|
The receiving node must always
|
2001-01-06 00:46:47 +00:00
|
|
|
.Fn NG_FREE_M
|
|
|
|
the mbuf chain on completion or error, or pass it on to another node
|
1999-10-21 09:06:11 +00:00
|
|
|
(or kernel module) which will then be responsible for freeing it.
|
2001-01-06 00:46:47 +00:00
|
|
|
Similarly the
|
|
|
|
.Em item
|
|
|
|
must be freed if it is not to be passed on to another node, by using the
|
|
|
|
.Fn NG_FREE_ITEM
|
|
|
|
macro. If the item still holds references to mbufs or metadata at the time of
|
|
|
|
freeing then they will also be appropriatly freed.
|
|
|
|
Therefore, if there is any chance that the mbuf or metadata will be
|
|
|
|
changed or freed separatly from the item, it is very important
|
|
|
|
that these fields be retrieved using the
|
|
|
|
.Fn NGI_GET_M
|
|
|
|
and
|
|
|
|
.Fn NGI_GET_META
|
|
|
|
macros that also remove the reference within the item. (or multiple frees
|
|
|
|
of the same object will occur).
|
|
|
|
.Pp
|
|
|
|
If it is only required to examine the contents of the mbufs or the
|
|
|
|
metadata, then it is possible to use the
|
|
|
|
.Fn NGI_M
|
|
|
|
and
|
|
|
|
.Fn NGI_META
|
|
|
|
macros to both read and rewrite these fields.
|
1999-10-21 09:06:11 +00:00
|
|
|
.Pp
|
2001-01-06 00:46:47 +00:00
|
|
|
In addition to the mbuf chain itself there may also be a pointer to a
|
1999-10-21 09:06:11 +00:00
|
|
|
structure describing meta-data about the message
|
|
|
|
(e.g. priority information). This pointer may be
|
|
|
|
.Dv NULL
|
|
|
|
if there is no additional information. The format for this information is
|
|
|
|
described in
|
2000-12-12 18:52:14 +00:00
|
|
|
.Pa sys/netgraph/netgraph.h .
|
1999-10-21 09:06:11 +00:00
|
|
|
The memory for meta-data must allocated via
|
1999-12-21 01:25:21 +00:00
|
|
|
.Fn malloc
|
1999-10-21 09:06:11 +00:00
|
|
|
with type
|
2001-01-06 00:46:47 +00:00
|
|
|
.Dv M_NETGRAPH_META .
|
1999-10-21 09:06:11 +00:00
|
|
|
As with the data itself, it is the receiver's responsibility to
|
1999-12-21 01:25:21 +00:00
|
|
|
.Fn free
|
1999-10-21 09:06:11 +00:00
|
|
|
the meta-data. If the mbuf chain is freed the meta-data must
|
|
|
|
be freed at the same time. If the meta-data is freed but the
|
|
|
|
real data on is passed on, then a
|
|
|
|
.Dv NULL
|
2001-01-06 00:46:47 +00:00
|
|
|
pointer must be substituted. It is also the duty of the receiver to free
|
|
|
|
the request item itself, or to use it to pass the message on further.
|
1999-10-21 09:06:11 +00:00
|
|
|
.Pp
|
|
|
|
The receiving node may decide to defer the data by queueing it in the
|
|
|
|
.Nm
|
2000-12-12 18:52:14 +00:00
|
|
|
NETISR system (see below). It achieves this by setting the
|
|
|
|
.Dv HK_QUEUE
|
|
|
|
flag in the flags word of the hook on which that data will arrive.
|
|
|
|
The infrastructure will respect that bit and queue the data for delivery at
|
|
|
|
a later time, rather than deliver it directly. A node may decide to set
|
|
|
|
the bit on the
|
|
|
|
.Em peer
|
|
|
|
node, so that it's own output packets are queued. This is used
|
|
|
|
by device drivers running at different processor priorities to transfer
|
|
|
|
packet delivery to the splnet() level at which the bulk of
|
|
|
|
.Nm
|
|
|
|
runs.
|
1999-10-21 09:06:11 +00:00
|
|
|
.Pp
|
2000-12-12 18:52:14 +00:00
|
|
|
The structure and use of meta-data is still experimental, but is
|
|
|
|
presently used in frame-relay to indicate that management packets
|
|
|
|
should be queued for transmission
|
1999-10-21 09:06:11 +00:00
|
|
|
at a higher priority than data packets. This is required for
|
|
|
|
conformance with Frame Relay standards.
|
|
|
|
.It Receive control message
|
|
|
|
This method is called when a control message is addressed to the node.
|
2001-01-06 00:46:47 +00:00
|
|
|
As with the received data, an
|
|
|
|
.Em item
|
|
|
|
is reveived, with a pointer to the control message.
|
|
|
|
The message can be examined using the
|
|
|
|
.Fn NGI_MSG
|
|
|
|
macro, or completely extracted from the item using the
|
|
|
|
.Fn NGI_GET_MSG
|
|
|
|
which also removes the reference within the item.
|
|
|
|
If the Item still holds a reference to the message when it is freed
|
|
|
|
(using the
|
|
|
|
.Fn NG_FREE_ITEM
|
|
|
|
macro), then the message will also be freed appropriatly. If the
|
|
|
|
reference has been removed the node must free the message itself using the
|
|
|
|
.Fn NG_FREE_MSG
|
|
|
|
macro.
|
1999-10-21 09:06:11 +00:00
|
|
|
A return address is always supplied, giving the address of the node
|
|
|
|
that originated the message so a reply message can be sent anytime later.
|
2001-01-06 00:46:47 +00:00
|
|
|
The return address is retrieved from the
|
|
|
|
.Em item
|
|
|
|
using the
|
|
|
|
.Fn NGI_RETADDR
|
|
|
|
macro and is of type
|
|
|
|
.Em ng_ID_t.
|
|
|
|
All control messages and replies are
|
1999-10-21 09:06:11 +00:00
|
|
|
allocated with
|
1999-12-21 01:25:21 +00:00
|
|
|
.Fn malloc
|
1999-10-21 09:06:11 +00:00
|
|
|
type
|
2001-01-06 00:46:47 +00:00
|
|
|
.Dv M_NETGRAPH_MSG ,
|
|
|
|
however it is more usual to use the
|
|
|
|
.Fn NG_MKMESSAGE
|
|
|
|
and
|
|
|
|
.Fn NG_MKRESPONSE
|
|
|
|
macros to allocate and fill out a message.
|
|
|
|
Messages must be freed using the
|
|
|
|
.Fn NG_FREE_MSG
|
|
|
|
macro.
|
2000-04-30 10:01:11 +00:00
|
|
|
.Pp
|
|
|
|
If the message was delivered via a specific hook, that hook will
|
|
|
|
also be made known, which allows the use of such things as flow-control
|
|
|
|
messages, and status change messages, where the node may want to forward
|
|
|
|
the message out another hook to that on which it arrived.
|
1999-10-21 09:06:11 +00:00
|
|
|
.El
|
|
|
|
.Pp
|
|
|
|
Much use has been made of reference counts, so that nodes being
|
|
|
|
free'd of all references are automatically freed, and this behaviour
|
|
|
|
has been tested and debugged to present a consistent and trustworthy
|
1999-12-21 01:25:21 +00:00
|
|
|
framework for the
|
|
|
|
.Dq type module
|
|
|
|
writer to use.
|
1999-10-21 09:06:11 +00:00
|
|
|
.Sh Addressing
|
|
|
|
The
|
|
|
|
.Nm
|
|
|
|
framework provides an unambiguous and simple to use method of specifically
|
|
|
|
addressing any single node in the graph. The naming of a node is
|
|
|
|
independent of its type, in that another node, or external component
|
|
|
|
need not know anything about the node's type in order to address it so as
|
|
|
|
to send it a generic message type. Node and hook names should be
|
|
|
|
chosen so as to make addresses meaningful.
|
|
|
|
.Pp
|
|
|
|
Addresses are either absolute or relative. An absolute address begins
|
|
|
|
with a node name, (or ID), followed by a colon, followed by a sequence of hook
|
|
|
|
names separated by periods. This addresses the node reached by starting
|
|
|
|
at the named node and following the specified sequence of hooks.
|
|
|
|
A relative address includes only the sequence of hook names, implicitly
|
|
|
|
starting hook traversal at the local node.
|
|
|
|
.Pp
|
|
|
|
There are a couple of special possibilities for the node name.
|
1999-12-21 01:25:21 +00:00
|
|
|
The name
|
2000-12-29 09:18:45 +00:00
|
|
|
.Dq .\&
|
1999-12-21 01:25:21 +00:00
|
|
|
(referred to as
|
|
|
|
.Dq \&.: )
|
|
|
|
always refers to the local node.
|
1999-10-21 09:06:11 +00:00
|
|
|
Also, nodes that have no global name may be addressed by their ID numbers,
|
|
|
|
by enclosing the hex representation of the ID number within square brackets.
|
|
|
|
Here are some examples of valid netgraph addresses:
|
|
|
|
.Bd -literal -offset 4n -compact
|
|
|
|
|
|
|
|
.:
|
2001-01-06 00:46:47 +00:00
|
|
|
[3f]:
|
1999-10-21 09:06:11 +00:00
|
|
|
foo:
|
|
|
|
.:hook1
|
|
|
|
foo:hook1.hook2
|
2000-12-12 18:52:14 +00:00
|
|
|
[d80]:hook1
|
1999-10-21 09:06:11 +00:00
|
|
|
.Ed
|
|
|
|
.Pp
|
|
|
|
Consider the following set of nodes might be created for a site with
|
|
|
|
a single physical frame relay line having two active logical DLCI channels,
|
|
|
|
with RFC-1490 frames on DLCI 16 and PPP frames over DLCI 20:
|
|
|
|
.Pp
|
|
|
|
.Bd -literal
|
|
|
|
[type SYNC ] [type FRAME] [type RFC1490]
|
|
|
|
[ "Frame1" ](uplink)<-->(data)[<un-named>](dlci16)<-->(mux)[<un-named> ]
|
|
|
|
[ A ] [ B ](dlci20)<---+ [ C ]
|
|
|
|
|
|
|
|
|
| [ type PPP ]
|
|
|
|
+>(mux)[<un-named>]
|
|
|
|
[ D ]
|
|
|
|
.Ed
|
|
|
|
.Pp
|
|
|
|
One could always send a control message to node C from anywhere
|
|
|
|
by using the name
|
|
|
|
.Em "Frame1:uplink.dlci16" .
|
2000-04-30 10:01:11 +00:00
|
|
|
In this case, node C would also be notified that the message
|
|
|
|
reached it via its hook
|
|
|
|
.Dq mux .
|
1999-10-21 09:06:11 +00:00
|
|
|
Similarly,
|
|
|
|
.Em "Frame1:uplink.dlci20"
|
|
|
|
could reliably be used to reach node D, and node A could refer
|
|
|
|
to node B as
|
|
|
|
.Em ".:uplink" ,
|
|
|
|
or simply
|
|
|
|
.Em "uplink" .
|
|
|
|
Conversely, B can refer to A as
|
|
|
|
.Em "data" .
|
|
|
|
The address
|
|
|
|
.Em "mux.data"
|
|
|
|
could be used by both nodes C and D to address a message to node A.
|
|
|
|
.Pp
|
|
|
|
Note that this is only for
|
|
|
|
.Em control messages .
|
2000-04-30 10:01:11 +00:00
|
|
|
In each of these cases, where a relative addressing mode is
|
|
|
|
used, the recipient is notified of the hook on which the
|
|
|
|
message arrived, as well as
|
|
|
|
the originating node.
|
|
|
|
This allows the option of hop-by-hop distibution of messages and
|
|
|
|
state information.
|
|
|
|
Data messages are
|
|
|
|
.Em only
|
|
|
|
routed one hop at a time, by specifying the departing
|
|
|
|
hook, with each node making
|
|
|
|
the next routing decision. So when B receives a frame on hook
|
|
|
|
.Dq data
|
1999-10-21 09:06:11 +00:00
|
|
|
it decodes the frame relay header to determine the DLCI,
|
|
|
|
and then forwards the unwrapped frame to either C or D.
|
2000-12-12 18:52:14 +00:00
|
|
|
.Pp
|
|
|
|
In a similar way, flow control messages may be routed in the reverse
|
|
|
|
direction to outgoing data. For example a "buffer nearly full" message from
|
|
|
|
.Em "Frame1:
|
|
|
|
would be passed to node
|
|
|
|
.Em B
|
|
|
|
which might decide to send similar messages to both nodes
|
|
|
|
.Em C
|
|
|
|
and
|
|
|
|
.Em D .
|
|
|
|
The nodes would use
|
|
|
|
.Em "Direct hook pointer"
|
|
|
|
addressing to route the messages. The message may have travelled from
|
|
|
|
.Em "Frame1:
|
|
|
|
to
|
|
|
|
.Em B
|
|
|
|
as a synchronous reply, saving time and cycles.
|
1999-10-21 09:06:11 +00:00
|
|
|
.Pp
|
|
|
|
A similar graph might be used to represent multi-link PPP running
|
|
|
|
over an ISDN line:
|
|
|
|
.Pp
|
|
|
|
.Bd -literal
|
|
|
|
[ type BRI ](B1)<--->(link1)[ type MPP ]
|
|
|
|
[ "ISDN1" ](B2)<--->(link2)[ (no name) ]
|
|
|
|
[ ](D) <-+
|
|
|
|
|
|
|
|
|
+----------------+
|
|
|
|
|
|
|
|
|
+->(switch)[ type Q.921 ](term1)<---->(datalink)[ type Q.931 ]
|
|
|
|
[ (no name) ] [ (no name) ]
|
|
|
|
.Ed
|
|
|
|
.Sh Netgraph Structures
|
2001-01-06 00:46:47 +00:00
|
|
|
Structures are defined in
|
2000-12-12 18:52:14 +00:00
|
|
|
.Pa sys/netgraph/netgraph.h
|
2001-01-06 00:46:47 +00:00
|
|
|
(for kernel sructures only of interest to nodes)
|
|
|
|
and
|
|
|
|
.Pa sys/netgraph/ng_message.h
|
|
|
|
(for message definitions also of interest to user programs).
|
1999-10-21 09:06:11 +00:00
|
|
|
|
2001-01-06 00:46:47 +00:00
|
|
|
The following structures exist and have the following access
|
|
|
|
fields of interest to the node writers. If applicable I show the
|
|
|
|
access method for that information.
|
|
|
|
for their fields:
|
|
|
|
.Bl -tag -width xxx
|
|
|
|
./.Bl -bullet -compact -offset 2n
|
|
|
|
.It struct ng_node
|
|
|
|
typedef struct ng_node *node_p;
|
|
|
|
.Bl -tag -width xxx
|
|
|
|
.It char name[NG_NODELEN+1]
|
|
|
|
Optional globally unique name, null terminated string. If there
|
|
|
|
is a value in here, it is the name of the node.
|
|
|
|
.Pp
|
|
|
|
if (node->name[0]) ....
|
|
|
|
.Pp
|
|
|
|
.It void *private
|
|
|
|
Node implementation private info.
|
|
|
|
You may place anything you wish here.
|
|
|
|
.It int numhooks
|
|
|
|
Number of connected hooks.
|
|
|
|
.It hook_p hooks
|
|
|
|
Linked list of (connected) hooks.
|
|
|
|
.El
|
|
|
|
.It struct ng_hook
|
1999-10-21 09:06:11 +00:00
|
|
|
typedef struct ng_hook *hook_p;
|
2001-01-06 00:46:47 +00:00
|
|
|
.Bl -tag -width xxx
|
|
|
|
.It void *private;
|
|
|
|
Node implementation private info.
|
|
|
|
You may place anything you wish in this field.
|
|
|
|
.It struct ng_node *node;
|
|
|
|
The node this hook is attached to.
|
|
|
|
.It struct ng_hook *peer;
|
|
|
|
The other hook in this connected pair.
|
|
|
|
.It struct ng_hook *next;
|
|
|
|
Next in list of hooks for this node.
|
|
|
|
A hook list traversal method will be supplied so use of this field
|
|
|
|
directly will go away.
|
|
|
|
.El
|
1999-10-21 09:06:11 +00:00
|
|
|
.Pp
|
2001-01-06 00:46:47 +00:00
|
|
|
The maintenance of the names, reference counts, and linked list
|
1999-10-21 09:06:11 +00:00
|
|
|
of hooks for each node is handled automatically by the
|
|
|
|
.Nm
|
|
|
|
subsystem.
|
|
|
|
Typically a node's private info contains a back-pointer to the node or hook
|
2001-01-06 00:46:47 +00:00
|
|
|
structure, which counts as a new reference that must be included
|
|
|
|
in the reference count for the node. When the node constructor is called
|
|
|
|
there is already a reference for this calculated in, so that
|
|
|
|
when the node is destroyed, it should remember to do a
|
|
|
|
.Fn ng_unref
|
|
|
|
on the node.
|
1999-10-21 09:06:11 +00:00
|
|
|
.Pp
|
|
|
|
From a hook you can obtain the corresponding node, and from
|
2001-01-06 00:46:47 +00:00
|
|
|
a node, the list of all active hooks.
|
1999-10-21 09:06:11 +00:00
|
|
|
.Pp
|
2001-01-06 00:46:47 +00:00
|
|
|
A current example of how to define a node can always be seen in
|
|
|
|
.Em sys/netgraph/ng_sample.c
|
|
|
|
and should be used as a starting point for new node writers.
|
|
|
|
.Sh Netgraph Message Structure
|
1999-10-21 09:06:11 +00:00
|
|
|
Control messages have the following structure:
|
|
|
|
.Bd -literal
|
|
|
|
#define NG_CMDSTRLEN 15 /* Max command string (16 with null) */
|
|
|
|
|
|
|
|
struct ng_mesg {
|
|
|
|
struct ng_msghdr {
|
|
|
|
u_char version; /* Must equal NG_VERSION */
|
|
|
|
u_char spare; /* Pad to 2 bytes */
|
|
|
|
u_short arglen; /* Length of cmd/resp data */
|
|
|
|
u_long flags; /* Message status flags */
|
|
|
|
u_long token; /* Reply should have the same token */
|
|
|
|
u_long typecookie; /* Node type understanding this message */
|
|
|
|
u_long cmd; /* Command identifier */
|
|
|
|
u_char cmdstr[NG_CMDSTRLEN+1]; /* Cmd string (for debug) */
|
|
|
|
} header;
|
|
|
|
char data[0]; /* Start of cmd/resp data */
|
|
|
|
};
|
|
|
|
|
2000-12-18 20:03:32 +00:00
|
|
|
#define NG_ABI_VERSION 5 /* Netgraph kernel ABI version */
|
|
|
|
#define NG_VERSION 4 /* Netgraph message version */
|
1999-10-21 09:06:11 +00:00
|
|
|
#define NGF_ORIG 0x0000 /* Command */
|
|
|
|
#define NGF_RESP 0x0001 /* Response */
|
|
|
|
.Ed
|
|
|
|
.Pp
|
|
|
|
Control messages have the fixed header shown above, followed by a
|
|
|
|
variable length data section which depends on the type cookie
|
|
|
|
and the command. Each field is explained below:
|
|
|
|
.Bl -tag -width xxx
|
|
|
|
.It Dv version
|
2000-12-18 20:03:32 +00:00
|
|
|
Indicates the version of the netgraph message protocol itself. The current version is
|
1999-10-21 09:06:11 +00:00
|
|
|
.Dv NG_VERSION .
|
|
|
|
.It Dv arglen
|
|
|
|
This is the length of any extra arguments, which begin at
|
|
|
|
.Dv data .
|
|
|
|
.It Dv flags
|
|
|
|
Indicates whether this is a command or a response control message.
|
|
|
|
.It Dv token
|
|
|
|
The
|
|
|
|
.Dv token
|
|
|
|
is a means by which a sender can match a reply message to the
|
|
|
|
corresponding command message; the reply always has the same token.
|
|
|
|
.Pp
|
|
|
|
.It Dv typecookie
|
|
|
|
The corresponding node type's unique 32-bit value.
|
|
|
|
If a node doesn't recognize the type cookie it must reject the message
|
|
|
|
by returning
|
|
|
|
.Er EINVAL .
|
|
|
|
.Pp
|
|
|
|
Each type should have an include file that defines the commands,
|
|
|
|
argument format, and cookie for its own messages.
|
|
|
|
The typecookie
|
|
|
|
insures that the same header file was included by both sender and
|
|
|
|
receiver; when an incompatible change in the header file is made,
|
|
|
|
the typecookie
|
|
|
|
.Em must
|
|
|
|
be changed.
|
|
|
|
The de facto method for generating unique type cookies is to take the
|
|
|
|
seconds from the epoch at the time the header file is written
|
|
|
|
(i.e., the output of
|
1999-12-21 01:25:21 +00:00
|
|
|
.Dv "date -u +'%s'" ) .
|
1999-10-21 09:06:11 +00:00
|
|
|
.Pp
|
|
|
|
There is a predefined typecookie
|
|
|
|
.Dv NGM_GENERIC_COOKIE
|
1999-12-21 01:25:21 +00:00
|
|
|
for the
|
|
|
|
.Dq generic
|
|
|
|
node type, and
|
1999-10-21 09:06:11 +00:00
|
|
|
a corresponding set of generic messages which all nodes understand.
|
|
|
|
The handling of these messages is automatic.
|
|
|
|
.It Dv command
|
|
|
|
The identifier for the message command. This is type specific,
|
|
|
|
and is defined in the same header file as the typecookie.
|
|
|
|
.It Dv cmdstr
|
1999-12-21 01:25:21 +00:00
|
|
|
Room for a short human readable version of
|
|
|
|
.Dq command
|
|
|
|
(for debugging purposes only).
|
1999-10-21 09:06:11 +00:00
|
|
|
.El
|
|
|
|
.Pp
|
|
|
|
Some modules may choose to implement messages from more than one
|
|
|
|
of the header files and thus recognize more than one type cookie.
|
1999-11-30 02:45:32 +00:00
|
|
|
.Sh Control Message ASCII Form
|
|
|
|
Control messages are in binary format for efficiency. However, for
|
|
|
|
debugging and human interface purposes, and if the node type supports
|
1999-12-21 01:25:21 +00:00
|
|
|
it, control messages may be converted to and from an equivalent
|
|
|
|
.Tn ASCII
|
|
|
|
form. The
|
|
|
|
.Tn ASCII
|
|
|
|
form is similar to the binary form, with two exceptions:
|
1999-11-30 02:45:32 +00:00
|
|
|
.Pp
|
|
|
|
.Bl -tag -compact -width xxx
|
|
|
|
.It o
|
|
|
|
The
|
|
|
|
.Dv cmdstr
|
1999-12-21 01:25:21 +00:00
|
|
|
header field must contain the
|
|
|
|
.Tn ASCII
|
|
|
|
name of the command, corresponding to the
|
1999-11-30 02:45:32 +00:00
|
|
|
.Dv cmd
|
|
|
|
header field.
|
|
|
|
.It o
|
|
|
|
The
|
|
|
|
.Dv args
|
1999-12-21 01:25:21 +00:00
|
|
|
field contains a NUL-terminated
|
|
|
|
.Tn ASCII
|
|
|
|
string version of the message arguments.
|
1999-11-30 02:45:32 +00:00
|
|
|
.El
|
|
|
|
.Pp
|
|
|
|
In general, the arguments field of a control messgage can be any
|
|
|
|
arbitrary C data type. Netgraph includes parsing routines to support
|
1999-12-21 01:25:21 +00:00
|
|
|
some pre-defined datatypes in
|
|
|
|
.Tn ASCII
|
|
|
|
with this simple syntax:
|
1999-11-30 02:45:32 +00:00
|
|
|
.Pp
|
|
|
|
.Bl -tag -compact -width xxx
|
|
|
|
.It o
|
|
|
|
Integer types are represented by base 8, 10, or 16 numbers.
|
|
|
|
.It o
|
|
|
|
Strings are enclosed in double quotes and respect the normal
|
|
|
|
C language backslash escapes.
|
|
|
|
.It o
|
|
|
|
IP addresses have the obvious form.
|
|
|
|
.It o
|
|
|
|
Arrays are enclosed in square brackets, with the elements listed
|
|
|
|
consecutively starting at index zero. An element may have an optional
|
|
|
|
index and equals sign preceeding it. Whenever an element
|
|
|
|
does not have an explicit index, the index is implicitly the previous
|
|
|
|
element's index plus one.
|
|
|
|
.It o
|
|
|
|
Structures are enclosed in curly braces, and each field is specified
|
1999-12-21 01:25:21 +00:00
|
|
|
in the form
|
|
|
|
.Dq fieldname=value .
|
1999-11-30 02:45:32 +00:00
|
|
|
.It o
|
|
|
|
Any array element or structure field whose value is equal to its
|
1999-12-21 01:25:21 +00:00
|
|
|
.Dq default value
|
|
|
|
may be omitted. For integer types, the default value
|
1999-11-30 02:45:32 +00:00
|
|
|
is usually zero; for string types, the empty string.
|
|
|
|
.It o
|
|
|
|
Array elements and structure fields may be specified in any order.
|
|
|
|
.El
|
|
|
|
.Pp
|
|
|
|
Each node type may define its own arbitrary types by providing
|
1999-12-21 01:25:21 +00:00
|
|
|
the necessary routines to parse and unparse.
|
|
|
|
.Tn ASCII
|
|
|
|
forms defined
|
1999-11-30 02:45:32 +00:00
|
|
|
for a specific node type are documented in the documentation for
|
|
|
|
that node type.
|
1999-10-21 09:06:11 +00:00
|
|
|
.Sh Generic Control Messages
|
|
|
|
There are a number of standard predefined messages that will work
|
|
|
|
for any node, as they are supported directly by the framework itself.
|
|
|
|
These are defined in
|
1999-12-21 01:25:21 +00:00
|
|
|
.Pa ng_message.h
|
1999-10-21 09:06:11 +00:00
|
|
|
along with the basic layout of messages and other similar information.
|
|
|
|
.Bl -tag -width xxx
|
|
|
|
.It Dv NGM_CONNECT
|
|
|
|
Connect to another node, using the supplied hook names on either end.
|
|
|
|
.It Dv NGM_MKPEER
|
|
|
|
Construct a node of the given type and then connect to it using the
|
|
|
|
supplied hook names.
|
|
|
|
.It Dv NGM_SHUTDOWN
|
|
|
|
The target node should disconnect from all its neighbours and shut down.
|
|
|
|
Persistent nodes such as those representing physical hardware
|
1999-10-30 20:30:19 +00:00
|
|
|
might not disappear from the node namespace, but only reset themselves.
|
1999-10-21 09:06:11 +00:00
|
|
|
The node must disconnect all of its hooks.
|
|
|
|
This may result in neighbors shutting themselves down, and possibly a
|
|
|
|
cascading shutdown of the entire connected graph.
|
|
|
|
.It Dv NGM_NAME
|
|
|
|
Assign a name to a node. Nodes can exist without having a name, and this
|
|
|
|
is the default for nodes created using the
|
|
|
|
.Dv NGM_MKPEER
|
|
|
|
method. Such nodes can only be addressed relatively or by their ID number.
|
|
|
|
.It Dv NGM_RMHOOK
|
|
|
|
Ask the node to break a hook connection to one of its neighbours.
|
1999-12-21 01:25:21 +00:00
|
|
|
Both nodes will have their
|
|
|
|
.Dq disconnect
|
|
|
|
method invoked.
|
1999-10-21 09:06:11 +00:00
|
|
|
Either node may elect to totally shut down as a result.
|
|
|
|
.It Dv NGM_NODEINFO
|
|
|
|
Asks the target node to describe itself. The four returned fields
|
|
|
|
are the node name (if named), the node type, the node ID and the
|
|
|
|
number of hooks attached. The ID is an internal number unique to that node.
|
|
|
|
.It Dv NGM_LISTHOOKS
|
|
|
|
This returns the information given by
|
|
|
|
.Dv NGM_NODEINFO ,
|
|
|
|
but in addition
|
1999-10-30 20:30:19 +00:00
|
|
|
includes an array of fields describing each link, and the description for
|
1999-10-21 09:06:11 +00:00
|
|
|
the node at the far end of that link.
|
|
|
|
.It Dv NGM_LISTNAMES
|
|
|
|
This returns an array of node descriptions (as for
|
|
|
|
.Dv NGM_NODEINFO ")"
|
|
|
|
where each entry of the array describes a named node.
|
|
|
|
All named nodes will be described.
|
|
|
|
.It Dv NGM_LISTNODES
|
|
|
|
This is the same as
|
|
|
|
.Dv NGM_LISTNAMES
|
|
|
|
except that all nodes are listed regardless of whether they have a name or not.
|
|
|
|
.It Dv NGM_LISTTYPES
|
|
|
|
This returns a list of all currently installed netgraph types.
|
|
|
|
.It Dv NGM_TEXT_STATUS
|
|
|
|
The node may return a text formatted status message.
|
|
|
|
The status information is determined entirely by the node type.
|
|
|
|
It is the only "generic" message
|
|
|
|
that requires any support within the node itself and as such the node may
|
|
|
|
elect to not support this message. The text response must be less than
|
|
|
|
.Dv NG_TEXTRESPONSE
|
|
|
|
bytes in length (presently 1024). This can be used to return general
|
|
|
|
status information in human readable form.
|
1999-11-30 02:45:32 +00:00
|
|
|
.It Dv NGM_BINARY2ASCII
|
1999-12-21 01:25:21 +00:00
|
|
|
This message converts a binary control message to its
|
|
|
|
.Tn ASCII
|
|
|
|
form.
|
1999-11-30 02:45:32 +00:00
|
|
|
The entire control message to be converted is contained within the
|
|
|
|
arguments field of the
|
|
|
|
.Dv Dv NGM_BINARY2ASCII
|
|
|
|
message itself. If successful, the reply will contain the same control
|
1999-12-21 01:25:21 +00:00
|
|
|
message in
|
|
|
|
.Tn ASCII
|
|
|
|
form.
|
1999-11-30 02:45:32 +00:00
|
|
|
A node will typically only know how to translate messages that it
|
1999-11-30 06:47:54 +00:00
|
|
|
itself understands, so the target node of the
|
1999-11-30 02:45:32 +00:00
|
|
|
.Dv NGM_BINARY2ASCII
|
|
|
|
is often the same node that would actually receive that message.
|
|
|
|
.It Dv NGM_ASCII2BINARY
|
|
|
|
The opposite of
|
|
|
|
.Dv NGM_BINARY2ASCII .
|
1999-12-21 01:25:21 +00:00
|
|
|
The entire control message to be converted, in
|
|
|
|
.Tn ASCII
|
|
|
|
form, is contained
|
1999-11-30 02:45:32 +00:00
|
|
|
in the arguments section of the
|
|
|
|
.Dv NGM_ASCII2BINARY
|
|
|
|
and need only have the
|
|
|
|
.Dv flags ,
|
|
|
|
.Dv cmdstr ,
|
|
|
|
and
|
|
|
|
.Dv arglen
|
|
|
|
header fields filled in, plus the NUL-terminated string version of
|
|
|
|
the arguments in the arguments field. If successful, the reply
|
|
|
|
contains the binary version of the control message.
|
1999-10-21 09:06:11 +00:00
|
|
|
.El
|
2000-12-12 18:52:14 +00:00
|
|
|
.Sh Flow Control Messages
|
|
|
|
In addition to the control messages that affect nodes with respect to the
|
|
|
|
graph, there are also a number of
|
|
|
|
.Em Flow-control
|
|
|
|
messages defined. At present these are
|
|
|
|
.Em NOT
|
|
|
|
handled automatically by the system, so
|
|
|
|
nodes need to handle them if they are going to be used in a graph utilising
|
|
|
|
flow control, and will be in the likely path of these messages. The
|
|
|
|
default action of a node that doesn't understand these messages should
|
|
|
|
be to pass them onto the next node. Hopefully some helper functions
|
|
|
|
will assist in this eventually. These messages are also defined in
|
|
|
|
.Pa sys/netgraph/ng_message.h
|
|
|
|
and have a separate cookie
|
|
|
|
.Em NG_FLOW_COOKIE
|
|
|
|
to help identify them. They will not be covered in depth here.
|
1999-10-21 09:06:11 +00:00
|
|
|
.Sh Metadata
|
|
|
|
Data moving through the
|
|
|
|
.Nm
|
|
|
|
system can be accompanied by meta-data that describes some
|
|
|
|
aspect of that data. The form of the meta-data is a fixed header,
|
|
|
|
which contains enough information for most uses, and can optionally
|
1999-10-30 20:30:19 +00:00
|
|
|
be supplemented by trailing
|
1999-10-21 09:06:11 +00:00
|
|
|
.Em option
|
|
|
|
structures, which contain a
|
|
|
|
.Em cookie
|
|
|
|
(see the section on control messages), an identifier, a length and optional
|
|
|
|
data. If a node does not recognize the cookie associated with an option,
|
|
|
|
it should ignore that option.
|
|
|
|
.Pp
|
|
|
|
Meta data might include such things as priority, discard eligibility,
|
|
|
|
or special processing requirements. It might also mark a packet for
|
|
|
|
debug status, etc. The use of meta-data is still experimental.
|
|
|
|
.Sh INITIALIZATION
|
|
|
|
The base
|
|
|
|
.Nm
|
|
|
|
code may either be statically compiled
|
|
|
|
into the kernel or else loaded dynamically as a KLD via
|
|
|
|
.Xr kldload 8 .
|
|
|
|
In the former case, include
|
2000-12-29 09:18:45 +00:00
|
|
|
.Pp
|
|
|
|
.Dl options NETGRAPH
|
|
|
|
.Pp
|
1999-10-21 09:06:11 +00:00
|
|
|
in your kernel configuration file. You may also include selected
|
|
|
|
node types in the kernel compilation, for example:
|
2000-12-29 09:18:45 +00:00
|
|
|
.Bd -literal -offset indent
|
|
|
|
options NETGRAPH
|
|
|
|
options NETGRAPH_SOCKET
|
|
|
|
options NETGRAPH_ECHO
|
1999-10-21 09:06:11 +00:00
|
|
|
.Ed
|
|
|
|
.Pp
|
|
|
|
Once the
|
|
|
|
.Nm
|
|
|
|
subsystem is loaded, individual node types may be loaded at any time
|
|
|
|
as KLD modules via
|
|
|
|
.Xr kldload 8 .
|
|
|
|
Moreover,
|
|
|
|
.Nm
|
|
|
|
knows how to automatically do this; when a request to create a new
|
|
|
|
node of unknown type
|
|
|
|
.Em type
|
|
|
|
is made,
|
|
|
|
.Nm
|
|
|
|
will attempt to load the KLD module
|
1999-12-21 01:25:21 +00:00
|
|
|
.Pa ng_type.ko .
|
1999-10-21 09:06:11 +00:00
|
|
|
.Pp
|
|
|
|
Types can also be installed at boot time, as certain device drivers
|
|
|
|
may want to export each instance of the device as a netgraph node.
|
|
|
|
.Pp
|
|
|
|
In general, new types can be installed at any time from within the
|
|
|
|
kernel by calling
|
1999-12-21 01:25:21 +00:00
|
|
|
.Fn ng_newtype ,
|
1999-10-21 09:06:11 +00:00
|
|
|
supplying a pointer to the type's
|
|
|
|
.Dv struct ng_type
|
|
|
|
structure.
|
|
|
|
.Pp
|
|
|
|
The
|
1999-12-21 01:25:21 +00:00
|
|
|
.Fn NETGRAPH_INIT
|
1999-10-21 09:06:11 +00:00
|
|
|
macro automates this process by using a linker set.
|
|
|
|
.Sh EXISTING NODE TYPES
|
|
|
|
Several node types currently exist. Each is fully documented
|
|
|
|
in its own man page:
|
|
|
|
.Bl -tag -width xxx
|
|
|
|
.It SOCKET
|
|
|
|
The socket type implements two new sockets in the new protocol domain
|
|
|
|
.Dv PF_NETGRAPH .
|
|
|
|
The new sockets protocols are
|
|
|
|
.Dv NG_DATA
|
|
|
|
and
|
|
|
|
.Dv NG_CONTROL ,
|
|
|
|
both of type
|
|
|
|
.Dv SOCK_DGRAM .
|
|
|
|
Typically one of each is associated with a socket node.
|
|
|
|
When both sockets have closed, the node will shut down. The
|
|
|
|
.Dv NG_DATA
|
|
|
|
socket is used for sending and receiving data, while the
|
|
|
|
.Dv NG_CONTROL
|
|
|
|
socket is used for sending and receiving control messages.
|
|
|
|
Data and control messages are passed using the
|
|
|
|
.Xr sendto 2
|
|
|
|
and
|
|
|
|
.Xr recvfrom 2
|
|
|
|
calls, using a
|
|
|
|
.Dv struct sockaddr_ng
|
|
|
|
socket address.
|
|
|
|
.Pp
|
|
|
|
.It HOLE
|
1999-12-21 01:25:21 +00:00
|
|
|
Responds only to generic messages and is a
|
|
|
|
.Dq black hole
|
|
|
|
for data, Useful for testing. Always accepts new hooks.
|
1999-10-21 09:06:11 +00:00
|
|
|
.Pp
|
|
|
|
.It ECHO
|
|
|
|
Responds only to generic messages and always echoes data back through the
|
|
|
|
hook from which it arrived. Returns any non generic messages as their
|
|
|
|
own response. Useful for testing. Always accepts new hooks.
|
|
|
|
.Pp
|
|
|
|
.It TEE
|
1999-12-21 01:25:21 +00:00
|
|
|
This node is useful for
|
|
|
|
.Dq snooping .
|
|
|
|
It has 4 hooks:
|
1999-10-21 09:06:11 +00:00
|
|
|
.Dv left ,
|
|
|
|
.Dv right ,
|
|
|
|
.Dv left2right ,
|
|
|
|
and
|
|
|
|
.Dv right2left .
|
|
|
|
Data entering from the right is passed to the left and duplicated on
|
|
|
|
.Dv right2left,
|
|
|
|
and data entering from the left is passed to the right and
|
|
|
|
duplicated on
|
|
|
|
.Dv left2right .
|
|
|
|
Data entering from
|
|
|
|
.Dv left2right
|
|
|
|
is sent to the right and data from
|
|
|
|
.Dv right2left
|
|
|
|
to left.
|
|
|
|
.Pp
|
|
|
|
.It RFC1490 MUX
|
|
|
|
Encapsulates/de-encapsulates frames encoded according to RFC 1490.
|
1999-12-21 01:25:21 +00:00
|
|
|
Has a hook for the encapsulated packets
|
|
|
|
.Pq Dq downstream
|
|
|
|
and one hook
|
1999-10-21 09:06:11 +00:00
|
|
|
for each protocol (i.e., IP, PPP, etc.).
|
|
|
|
.Pp
|
|
|
|
.It FRAME RELAY MUX
|
|
|
|
Encapsulates/de-encapsulates Frame Relay frames.
|
1999-12-21 01:25:21 +00:00
|
|
|
Has a hook for the encapsulated packets
|
|
|
|
.Pq Dq downstream
|
|
|
|
and one hook
|
1999-10-21 09:06:11 +00:00
|
|
|
for each DLCI.
|
|
|
|
.Pp
|
|
|
|
.It FRAME RELAY LMI
|
|
|
|
Automatically handles frame relay
|
1999-12-21 01:25:21 +00:00
|
|
|
.Dq LMI
|
|
|
|
(link management interface) operations and packets.
|
1999-10-30 20:30:19 +00:00
|
|
|
Automatically probes and detects which of several LMI standards
|
1999-10-21 09:06:11 +00:00
|
|
|
is in use at the exchange.
|
|
|
|
.Pp
|
|
|
|
.It TTY
|
|
|
|
This node is also a line discipline. It simply converts between mbuf
|
|
|
|
frames and sequential serial data, allowing a tty to appear as a netgraph
|
1999-12-21 01:25:21 +00:00
|
|
|
node. It has a programmable
|
|
|
|
.Dq hotkey
|
|
|
|
character.
|
1999-10-21 09:06:11 +00:00
|
|
|
.Pp
|
|
|
|
.It ASYNC
|
|
|
|
This node encapsulates and de-encapsulates asynchronous frames
|
|
|
|
according to RFC 1662. This is used in conjunction with the TTY node
|
|
|
|
type for supporting PPP links over asynchronous serial lines.
|
|
|
|
.Pp
|
|
|
|
.It INTERFACE
|
|
|
|
This node is also a system networking interface. It has hooks representing
|
|
|
|
each protocol family (IP, AppleTalk, IPX, etc.) and appears in the output of
|
|
|
|
.Xr ifconfig 8 .
|
|
|
|
The interfaces are named
|
|
|
|
.Em ng0 ,
|
|
|
|
.Em ng1 ,
|
|
|
|
etc.
|
2000-12-12 18:52:14 +00:00
|
|
|
.It ONE2MANY
|
|
|
|
This node implements a simple round-robin multiplexer. It can be used
|
|
|
|
for example to make several LAN ports act together to get a higher speed
|
|
|
|
link between two machines.
|
|
|
|
.It Various PPP related nodes.
|
|
|
|
There is a full multilink PPP implementation that runs in Netgraph.
|
|
|
|
The
|
|
|
|
.Em Mpd
|
|
|
|
port can use these modules to make a very low latency high
|
|
|
|
capacity ppp system. It also supports
|
|
|
|
.Em PPTP
|
|
|
|
vpns using the
|
|
|
|
.Em PPTP
|
|
|
|
node.
|
|
|
|
.It PPPOE
|
|
|
|
A server and client side implememtation of PPPoE. Used in conjunction with
|
|
|
|
either
|
|
|
|
.Xr ppp 8
|
|
|
|
or the
|
|
|
|
.Em mpd port.
|
|
|
|
.It BRIDGE
|
|
|
|
This node, togther with the ethernet nodes allows a very flexible
|
|
|
|
bridging system to be implemented.
|
|
|
|
.It KSOCKET
|
|
|
|
This intriguing node looks like a socket to the system but diverts
|
|
|
|
all data to and from the netgraph system for further processing. This allows
|
|
|
|
such things as UDP tunnels to be almost trivially implemented from the
|
|
|
|
command line.
|
1999-10-21 09:06:11 +00:00
|
|
|
.El
|
2000-12-12 18:52:14 +00:00
|
|
|
.Pp
|
|
|
|
Refer to the section at the end of this man page for more nodes types.
|
1999-10-21 09:06:11 +00:00
|
|
|
.Sh NOTES
|
1999-10-30 20:30:19 +00:00
|
|
|
Whether a named node exists can be checked by trying to send a control message
|
1999-10-21 09:06:11 +00:00
|
|
|
to it (e.g.,
|
|
|
|
.Dv NGM_NODEINFO
|
|
|
|
).
|
|
|
|
If it does not exist,
|
|
|
|
.Er ENOENT
|
|
|
|
will be returned.
|
|
|
|
.Pp
|
|
|
|
All data messages are mbuf chains with the M_PKTHDR flag set.
|
|
|
|
.Pp
|
|
|
|
Nodes are responsible for freeing what they allocate.
|
|
|
|
There are three exceptions:
|
|
|
|
.Bl -tag -width xxxx
|
|
|
|
.It 1
|
2001-01-06 00:46:47 +00:00
|
|
|
Mbufs sent across a data link are never to be freed by the sender. In the
|
|
|
|
case of error, they should be considered freed.
|
1999-10-21 09:06:11 +00:00
|
|
|
.It 2
|
1999-10-30 20:30:19 +00:00
|
|
|
Any meta-data information traveling with the data has the same restriction.
|
1999-10-21 09:06:11 +00:00
|
|
|
It might be freed by any node the data passes through, and a
|
|
|
|
.Dv NULL
|
|
|
|
passed onwards, but the caller will never free it.
|
|
|
|
Two macros
|
1999-12-21 01:25:21 +00:00
|
|
|
.Fn NG_FREE_META "meta"
|
1999-10-21 09:06:11 +00:00
|
|
|
and
|
2001-01-06 00:46:47 +00:00
|
|
|
.Fn NG_FREE_M "m"
|
1999-10-21 09:06:11 +00:00
|
|
|
should be used if possible to free data and meta data (see
|
1999-12-21 01:25:21 +00:00
|
|
|
.Pa netgraph.h ) .
|
1999-10-21 09:06:11 +00:00
|
|
|
.It 3
|
|
|
|
Messages sent using
|
1999-12-21 01:25:21 +00:00
|
|
|
.Fn ng_send_message
|
2000-04-30 10:01:11 +00:00
|
|
|
are freed by the recipient. As in the case above, the addresses
|
1999-10-21 09:06:11 +00:00
|
|
|
associated with the message are freed by whatever allocated them so the
|
|
|
|
recipient should copy them if it wants to keep that information.
|
2001-01-06 00:46:47 +00:00
|
|
|
.It 4
|
|
|
|
Both control mesages and data are delivered and queued with
|
|
|
|
a netgraph
|
|
|
|
.Em item .
|
|
|
|
The item must be freed using
|
|
|
|
.Fn NG_FREE_ITEM "item"
|
|
|
|
or passed on to another node.
|
1999-10-21 09:06:11 +00:00
|
|
|
.El
|
|
|
|
.Sh FILES
|
|
|
|
.Bl -tag -width xxxxx -compact
|
|
|
|
.It Pa /sys/netgraph/netgraph.h
|
1999-10-30 20:30:19 +00:00
|
|
|
Definitions for use solely within the kernel by
|
1999-10-21 09:06:11 +00:00
|
|
|
.Nm
|
|
|
|
nodes.
|
|
|
|
.It Pa /sys/netgraph/ng_message.h
|
|
|
|
Definitions needed by any file that needs to deal with
|
|
|
|
.Nm
|
|
|
|
messages.
|
|
|
|
.It Pa /sys/netgraph/ng_socket.h
|
|
|
|
Definitions needed to use
|
|
|
|
.Nm
|
|
|
|
socket type nodes.
|
|
|
|
.It Pa /sys/netgraph/ng_{type}.h
|
|
|
|
Definitions needed to use
|
|
|
|
.Nm
|
|
|
|
{type}
|
|
|
|
nodes, including the type cookie definition.
|
|
|
|
.It Pa /modules/netgraph.ko
|
|
|
|
Netgraph subsystem loadable KLD module.
|
|
|
|
.It Pa /modules/ng_{type}.ko
|
|
|
|
Loadable KLD module for node type {type}.
|
2001-01-06 00:46:47 +00:00
|
|
|
.It Pa /sys/netgraph/ng_sample.c
|
|
|
|
Skeleton netgraph node. Use this as a starting point for new node types.
|
1999-10-21 09:06:11 +00:00
|
|
|
.El
|
|
|
|
.Sh USER MODE SUPPORT
|
|
|
|
There is a library for supporting user-mode programs that wish
|
|
|
|
to interact with the netgraph system. See
|
|
|
|
.Xr netgraph 3
|
|
|
|
for details.
|
|
|
|
.Pp
|
|
|
|
Two user-mode support programs,
|
|
|
|
.Xr ngctl 8
|
|
|
|
and
|
|
|
|
.Xr nghook 8 ,
|
|
|
|
are available to assist manual configuration and debugging.
|
|
|
|
.Pp
|
|
|
|
There are a few useful techniques for debugging new node types.
|
|
|
|
First, implementing new node types in user-mode first
|
|
|
|
makes debugging easier.
|
|
|
|
The
|
|
|
|
.Em tee
|
|
|
|
node type is also useful for debugging, especially in conjunction with
|
|
|
|
.Xr ngctl 8
|
|
|
|
and
|
|
|
|
.Xr nghook 8 .
|
2000-12-12 18:52:14 +00:00
|
|
|
.Pp
|
|
|
|
Also look in /usr/share/examples/netgraph for solutions to several
|
|
|
|
common networking problems, solved using
|
|
|
|
.Nm .
|
1999-10-21 09:06:11 +00:00
|
|
|
.Sh SEE ALSO
|
|
|
|
.Xr socket 2 ,
|
|
|
|
.Xr netgraph 3 ,
|
2000-05-04 17:54:37 +00:00
|
|
|
.Xr ng_async 4 ,
|
2000-12-12 18:52:14 +00:00
|
|
|
.Xr ng_bridge 4 ,
|
2000-05-04 17:54:37 +00:00
|
|
|
.Xr ng_bpf 4 ,
|
|
|
|
.Xr ng_cisco 4 ,
|
|
|
|
.Xr ng_ether 4 ,
|
|
|
|
.Xr ng_echo 4 ,
|
2000-12-12 18:52:14 +00:00
|
|
|
.Xr ng_ether 4 ,
|
2000-05-04 17:54:37 +00:00
|
|
|
.Xr ng_frame_relay 4 ,
|
|
|
|
.Xr ng_hole 4 ,
|
|
|
|
.Xr ng_iface 4 ,
|
|
|
|
.Xr ng_ksocket 4 ,
|
|
|
|
.Xr ng_lmi 4 ,
|
|
|
|
.Xr ng_mppc 4 ,
|
|
|
|
.Xr ng_ppp 4 ,
|
|
|
|
.Xr ng_pppoe 4 ,
|
2000-12-12 18:52:14 +00:00
|
|
|
.Xr ng_pptpgre 4 ,
|
2000-05-04 17:54:37 +00:00
|
|
|
.Xr ng_rfc1490 4 ,
|
|
|
|
.Xr ng_socket 4 ,
|
|
|
|
.Xr ng_tee 4 ,
|
|
|
|
.Xr ng_tty 4 ,
|
|
|
|
.Xr ng_UI 4 ,
|
|
|
|
.Xr ng_vjc 4 ,
|
|
|
|
.Xr ng_{type} 4 ,
|
1999-10-21 09:06:11 +00:00
|
|
|
.Xr ngctl 8 ,
|
2000-05-04 17:54:37 +00:00
|
|
|
.Xr nghook 8
|
1999-10-21 09:06:11 +00:00
|
|
|
.Sh HISTORY
|
|
|
|
The
|
|
|
|
.Nm
|
|
|
|
system was designed and first implemented at Whistle Communications, Inc.
|
2000-02-29 18:32:26 +00:00
|
|
|
in a version of
|
1999-12-21 01:25:21 +00:00
|
|
|
.Fx 2.2
|
|
|
|
customized for the Whistle InterJet.
|
2000-02-29 18:32:26 +00:00
|
|
|
It first made its debut in the main tree in
|
|
|
|
.Fx 3.4 .
|
1999-10-21 09:06:11 +00:00
|
|
|
.Sh AUTHORS
|
2000-11-22 09:35:58 +00:00
|
|
|
.An -nosplit
|
2000-10-26 15:30:44 +00:00
|
|
|
.An Julian Elischer Aq julian@FreeBSD.org ,
|
1999-12-21 01:25:21 +00:00
|
|
|
with contributions by
|
2000-10-26 15:30:44 +00:00
|
|
|
.An Archie Cobbs Aq archie@FreeBSD.org .
|