Add ETHER_ALIGN support to ng_device(4).

This adds a new ng_device command, NGM_DEVICE_ETHERALIGN, which has no
associated args.  After the command arrives, the device begins adjusting all
packets sent out its hook to have ETHER_ALIGN bytes of padding at the
beginning of the packet.  The ETHER_ALIGN padding is added only when
running on an architecture that requires strict alignment of IP headers
(based on the __NO_STRICT_ALIGNMENT macro, which is only #define'd on
x86 as of this writing).

This also adds ascii <-> binary command translation to ng_device, both for
the existing NGM_DEVICE_GET_DEVNAME and the new ETHERALIGN command.

This also gives a name to every ng_device node when it is constructed, using
the cdev device name (ngd0, ngd1, etc).  This makes it easier to address
command msgs to the device using ngctl(8).

Reviewed by:	donner, ray, adrian
Differential Revision:	https://reviews.freebsd.org/D32905
MFC after:   1 week

(cherry picked from commit 44aae623ab)
This commit is contained in:
Ian Lepore 2021-11-09 15:34:06 +01:00 committed by Emmanuel Vadot
parent 1e2a0cef6b
commit 1a86aab86a
3 changed files with 51 additions and 5 deletions

View File

@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd October 19, 2004
.Dd November 8, 2021
.Dt NG_DEVICE 4
.Os
.Sh NAME
@ -48,7 +48,7 @@ etc.
.Pp
The first node is created as
.Pa /dev/ngd0 ,
all subsequent nodes
subsequent nodes are
.Pa /dev/ngd1 , /dev/ngd2 ,
etc.
.Sh HOOKS
@ -64,10 +64,18 @@ will be forwarded to the hook.
.Sh CONTROL MESSAGES
The
.Nm device
node supports one non-generic control message:
node supports the generic control messages, plus the following:
.Bl -tag -width 3n
.It Dv NGM_DEVICE_GET_DEVNAME
Returns device name corresponding to a node.
Returns the device name corresponding to the node.
.It Dv NGM_DEVICE_ETHERALIGN
Apply the system ETHER_ALIGN offset to mbufs sent out the node's hook,
if running on an architecture that requires strict alignment.
Use this option when the data being injected via the device node ultimately
ends up being fed into the protocol stack as ethernet packets (e.g., via
an
.Xr ng_eiface 4
node).
.El
.\" Additionally, the node accepts
.\" .Xr ioctl 2 Ns s

View File

@ -50,10 +50,12 @@
#include <sys/epoch.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/syslog.h>
#include <sys/systm.h>
#include <sys/uio.h>
#include <sys/vnode.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_var.h>
#include <netinet/in.h>
@ -63,6 +65,7 @@
#include <netgraph/ng_message.h>
#include <netgraph/netgraph.h>
#include <netgraph/ng_device.h>
#include <netgraph/ng_parse.h>
#define ERROUT(x) do { error = (x); goto done; } while (0)
@ -75,6 +78,25 @@ static ng_newhook_t ng_device_newhook;
static ng_rcvdata_t ng_device_rcvdata;
static ng_disconnect_t ng_device_disconnect;
/* List of commands and how to convert arguments to/from ASCII. */
static const struct ng_cmdlist ng_device_cmds[] = {
{
NGM_DEVICE_COOKIE,
NGM_DEVICE_GET_DEVNAME,
"getdevname",
NULL,
&ng_parse_string_type
},
{
NGM_DEVICE_COOKIE,
NGM_DEVICE_ETHERALIGN,
"etheralign",
NULL,
NULL
},
{ 0 }
};
/* Netgraph type */
static struct ng_type ngd_typestruct = {
.version = NG_ABI_VERSION,
@ -86,6 +108,7 @@ static struct ng_type ngd_typestruct = {
.newhook = ng_device_newhook,
.rcvdata = ng_device_rcvdata,
.disconnect = ng_device_disconnect,
.cmdlist = ng_device_cmds,
};
NETGRAPH_INIT(device, &ngd_typestruct);
@ -97,6 +120,7 @@ struct ngd_private {
struct cdev *ngddev;
struct mtx ngd_mtx;
int unit;
int ether_align;
uint16_t flags;
#define NGDF_OPEN 0x0001
#define NGDF_RWAIT 0x0002
@ -194,6 +218,11 @@ ng_device_constructor(node_p node)
/* XXX: race here? */
priv->ngddev->si_drv1 = priv;
/* Give this node the same name as the device (if possible). */
if (ng_name_node(node, devtoname(priv->ngddev)) != 0)
log(LOG_WARNING, "%s: can't acquire netgraph name\n",
devtoname(priv->ngddev));
return(0);
}
@ -226,6 +255,13 @@ ng_device_rcvmsg(node_p node, item_p item, hook_p lasthook)
strlcpy((char *)resp->data, dn, strlen(dn) + 1);
break;
case NGM_DEVICE_ETHERALIGN:
/* Use ETHER_ALIGN on arches that require it. */
#ifndef __NO_STRICT_ALIGNMENT
priv->ether_align = ETHER_ALIGN;
#endif
break;
default:
error = EINVAL;
break;
@ -468,7 +504,8 @@ ngdwrite(struct cdev *dev, struct uio *uio, int flag)
if (uio->uio_resid < 0 || uio->uio_resid > IP_MAXPACKET)
return (EIO);
if ((m = m_uiotombuf(uio, M_NOWAIT, 0, 0, M_PKTHDR)) == NULL)
m = m_uiotombuf(uio, M_NOWAIT, 0, priv->ether_align, M_PKTHDR);
if (m == NULL)
return (ENOBUFS);
NET_EPOCH_ENTER(et);

View File

@ -39,6 +39,7 @@
/* Netgraph control messages */
enum {
NGM_DEVICE_GET_DEVNAME,
NGM_DEVICE_ETHERALIGN,
};
#if 0