Add pfil(9) hook to vtnet(4).

The patch could be simplier, using only the second chunk to
vtnet_rxq_eof(), that passes full mbufs to pfil(9). Packet
filter would m_free() them in case of returning PFIL_DROPPED.

However, we pretend to be a hardware driver, so we first try
to pass a memory buffer via PFIL_MEMPTR feature. This is mostly
done for debugging purposes, so that one can experiment in bhyve
with packet filters utilizing same features as a true driver.
This commit is contained in:
Gleb Smirnoff 2020-01-10 21:22:03 +00:00
parent 1cd24ac42b
commit ed6cbf4805
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=356613
2 changed files with 54 additions and 1 deletions

View File

@ -53,6 +53,7 @@ __FBSDID("$FreeBSD$");
#include <net/debugnet.h>
#include <net/ethernet.h>
#include <net/pfil.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/if_arp.h>
@ -935,6 +936,7 @@ static int
vtnet_setup_interface(struct vtnet_softc *sc)
{
device_t dev;
struct pfil_head_args pa;
struct ifnet *ifp;
dev = sc->vtnet_dev;
@ -1038,6 +1040,12 @@ vtnet_setup_interface(struct vtnet_softc *sc)
DEBUGNET_SET(ifp, vtnet);
pa.pa_version = PFIL_VERSION;
pa.pa_flags = PFIL_IN;
pa.pa_type = PFIL_TYPE_ETHERNET;
pa.pa_headname = ifp->if_xname;
sc->vtnet_pfil = pfil_head_register(&pa);
return (0);
}
@ -1773,9 +1781,11 @@ vtnet_rxq_eof(struct vtnet_rxq *rxq)
struct vtnet_softc *sc;
struct ifnet *ifp;
struct virtqueue *vq;
struct mbuf *m;
struct mbuf *m, *mr;
struct virtio_net_hdr_mrg_rxbuf *mhdr;
int len, deq, nbufs, adjsz, count;
pfil_return_t pfil;
bool pfil_done;
sc = rxq->vtnrx_sc;
vq = rxq->vtnrx_vq;
@ -1812,6 +1822,35 @@ vtnet_rxq_eof(struct vtnet_rxq *rxq)
adjsz = sizeof(struct virtio_net_hdr_mrg_rxbuf);
}
/*
* If we have enough data in first mbuf, run it through
* pfil as a memory buffer before dequeueing the rest.
*/
if (PFIL_HOOKED_IN(sc->vtnet_pfil) &&
len - adjsz >= ETHER_HDR_LEN + max_protohdr) {
pfil = pfil_run_hooks(sc->vtnet_pfil,
m->m_data + adjsz, ifp,
len - adjsz | PFIL_MEMPTR | PFIL_IN, NULL);
switch (pfil) {
case PFIL_REALLOCED:
mr = pfil_mem2mbuf(m->m_data + adjsz);
vtnet_rxq_input(rxq, mr, hdr);
/* FALLTHROUGH */
case PFIL_DROPPED:
case PFIL_CONSUMED:
vtnet_rxq_discard_buf(rxq, m);
if (nbufs > 1)
vtnet_rxq_discard_merged_bufs(rxq,
nbufs);
continue;
default:
KASSERT(pfil == PFIL_PASS,
("Filter returned %d!\n", pfil));
};
pfil_done = true;
} else
pfil_done = false;
if (vtnet_rxq_replace_buf(rxq, m, len) != 0) {
rxq->vtnrx_stats.vrxs_iqdrops++;
vtnet_rxq_discard_buf(rxq, m);
@ -1842,6 +1881,19 @@ vtnet_rxq_eof(struct vtnet_rxq *rxq)
memcpy(hdr, mtod(m, void *), sizeof(struct virtio_net_hdr));
m_adj(m, adjsz);
if (PFIL_HOOKED_IN(sc->vtnet_pfil) && pfil_done == false) {
pfil = pfil_run_hooks(sc->vtnet_pfil, &m, ifp, PFIL_IN,
NULL);
switch (pfil) {
case PFIL_DROPPED:
case PFIL_CONSUMED:
continue;
default:
KASSERT(pfil == PFIL_PASS,
("Filter returned %d!\n", pfil));
}
}
vtnet_rxq_input(rxq, m, hdr);
/* Must recheck after dropping the Rx lock. */

View File

@ -136,6 +136,7 @@ struct vtnet_softc {
struct ifnet *vtnet_ifp;
struct vtnet_rxq *vtnet_rxqs;
struct vtnet_txq *vtnet_txqs;
pfil_head_t vtnet_pfil;
uint32_t vtnet_flags;
#define VTNET_FLAG_SUSPENDED 0x0001