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:
parent
1cd24ac42b
commit
ed6cbf4805
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=356613
@ -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. */
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user