Split out a more generic debugnet(4) from netdump(4)
Debugnet is a simplistic and specialized panic- or debug-time reliable datagram transport. It can drive a single connection at a time and is currently unidirectional (debug/panic machine transmit to remote server only). It is mostly a verbatim code lift from netdump(4). Netdump(4) remains the only consumer (until the rest of this patch series lands). The INET-specific logic has been extracted somewhat more thoroughly than previously in netdump(4), into debugnet_inet.c. UDP-layer logic and up, as much as possible as is protocol-independent, remains in debugnet.c. The separation is not perfect and future improvement is welcome. Supporting INET6 is a long-term goal. Much of the diff is "gratuitous" renaming from 'netdump_' or 'nd_' to 'debugnet_' or 'dn_' -- sorry. I thought keeping the netdump name on the generic module would be more confusing than the refactoring. The only functional change here is the mbuf allocation / tracking. Instead of initiating solely on netdump-configured interface(s) at dumpon(8) configuration time, we watch for any debugnet-enabled NIC for link activation and query it for mbuf parameters at that time. If they exceed the existing high-water mark allocation, we re-allocate and track the new high-water mark. Otherwise, we leave the pre-panic mbuf allocation alone. In a future patch in this series, this will allow initiating netdump from panic ddb(4) without pre-panic configuration. No other functional change intended. Reviewed by: markj (earlier version) Some discussion with: emaste, jhb Objection from: marius Differential Revision: https://reviews.freebsd.org/D21421
This commit is contained in:
parent
756368b68b
commit
7790c8c199
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=353685
@ -111,6 +111,7 @@ options VERBOSE_SYSINIT=0 # Support debug.verbose_sysinit, off by default
|
||||
options EKCD # Support for encrypted kernel dumps
|
||||
options GZIO # gzip-compressed kernel and user dumps
|
||||
options ZSTDIO # zstd-compressed kernel and user dumps
|
||||
options DEBUGNET # debugnet networking
|
||||
options NETDUMP # netdump(4) client support
|
||||
|
||||
# Make an SMP-capable kernel by default
|
||||
|
@ -103,6 +103,7 @@ options VERBOSE_SYSINIT=0 # Support debug.verbose_sysinit, off by default
|
||||
options EKCD # Support for encrypted kernel dumps
|
||||
options GZIO # gzip-compressed kernel and user dumps
|
||||
options ZSTDIO # zstd-compressed kernel and user dumps
|
||||
options DEBUGNET # debugnet networking
|
||||
options NETDUMP # netdump(4) client support
|
||||
|
||||
# SoC support
|
||||
|
@ -1042,6 +1042,10 @@ options DUMMYNET
|
||||
# This allows a panicking kernel to transmit a kernel dump to a remote host.
|
||||
options NETDUMP
|
||||
|
||||
# The DEBUGNET option enables a basic debug/panic-time networking API. It
|
||||
# is used by NETDUMP.
|
||||
options DEBUGNET
|
||||
|
||||
#####################################################################
|
||||
# FILESYSTEM OPTIONS
|
||||
|
||||
|
@ -4077,6 +4077,8 @@ net/mp_ring.c optional ether iflib
|
||||
net/mppcc.c optional netgraph_mppc_compression
|
||||
net/mppcd.c optional netgraph_mppc_compression
|
||||
net/netisr.c standard
|
||||
net/debugnet.c optional inet debugnet
|
||||
net/debugnet_inet.c optional inet debugnet
|
||||
net/pfil.c optional ether | inet
|
||||
net/radix.c standard
|
||||
net/radix_mpath.c standard
|
||||
|
@ -321,6 +321,8 @@ NETSMB opt_netsmb.h
|
||||
|
||||
# Enable netdump(4) client support.
|
||||
NETDUMP opt_global.h
|
||||
# Enable debugnet(4) networking support.
|
||||
DEBUGNET opt_global.h
|
||||
|
||||
# Options used only in subr_param.c.
|
||||
HZ opt_param.h
|
||||
|
@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/taskqueue.h>
|
||||
|
||||
#include <net/bpf.h>
|
||||
#include <net/debugnet.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_var.h>
|
||||
#include <net/if_arp.h>
|
||||
@ -64,7 +65,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/netdump/netdump.h>
|
||||
|
||||
#include <dev/mii/mii.h>
|
||||
#include <dev/mii/miivar.h>
|
||||
@ -215,7 +215,7 @@ static int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int);
|
||||
static int sysctl_hw_alc_proc_limit(SYSCTL_HANDLER_ARGS);
|
||||
static int sysctl_hw_alc_int_mod(SYSCTL_HANDLER_ARGS);
|
||||
|
||||
NETDUMP_DEFINE(alc);
|
||||
DEBUGNET_DEFINE(alc);
|
||||
|
||||
static device_method_t alc_methods[] = {
|
||||
/* Device interface. */
|
||||
@ -1657,8 +1657,8 @@ alc_attach(device_t dev)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Attach driver netdump methods. */
|
||||
NETDUMP_SET(ifp, alc);
|
||||
/* Attach driver debugnet methods. */
|
||||
DEBUGNET_SET(ifp, alc);
|
||||
|
||||
fail:
|
||||
if (error != 0)
|
||||
@ -4658,9 +4658,9 @@ sysctl_hw_alc_int_mod(SYSCTL_HANDLER_ARGS)
|
||||
ALC_IM_TIMER_MIN, ALC_IM_TIMER_MAX));
|
||||
}
|
||||
|
||||
#ifdef NETDUMP
|
||||
#ifdef DEBUGNET
|
||||
static void
|
||||
alc_netdump_init(struct ifnet *ifp, int *nrxr, int *ncl, int *clsize)
|
||||
alc_debugnet_init(struct ifnet *ifp, int *nrxr, int *ncl, int *clsize)
|
||||
{
|
||||
struct alc_softc *sc;
|
||||
|
||||
@ -4668,17 +4668,17 @@ alc_netdump_init(struct ifnet *ifp, int *nrxr, int *ncl, int *clsize)
|
||||
KASSERT(sc->alc_buf_size <= MCLBYTES, ("incorrect cluster size"));
|
||||
|
||||
*nrxr = ALC_RX_RING_CNT;
|
||||
*ncl = NETDUMP_MAX_IN_FLIGHT;
|
||||
*ncl = DEBUGNET_MAX_IN_FLIGHT;
|
||||
*clsize = MCLBYTES;
|
||||
}
|
||||
|
||||
static void
|
||||
alc_netdump_event(struct ifnet *ifp __unused, enum netdump_ev event __unused)
|
||||
alc_debugnet_event(struct ifnet *ifp __unused, enum debugnet_ev event __unused)
|
||||
{
|
||||
}
|
||||
|
||||
static int
|
||||
alc_netdump_transmit(struct ifnet *ifp, struct mbuf *m)
|
||||
alc_debugnet_transmit(struct ifnet *ifp, struct mbuf *m)
|
||||
{
|
||||
struct alc_softc *sc;
|
||||
int error;
|
||||
@ -4695,7 +4695,7 @@ alc_netdump_transmit(struct ifnet *ifp, struct mbuf *m)
|
||||
}
|
||||
|
||||
static int
|
||||
alc_netdump_poll(struct ifnet *ifp, int count)
|
||||
alc_debugnet_poll(struct ifnet *ifp, int count)
|
||||
{
|
||||
struct alc_softc *sc;
|
||||
|
||||
@ -4707,4 +4707,4 @@ alc_netdump_poll(struct ifnet *ifp, int count)
|
||||
alc_txeof(sc);
|
||||
return (alc_rxintr(sc, count));
|
||||
}
|
||||
#endif /* NETDUMP */
|
||||
#endif /* DEBUGNET */
|
||||
|
@ -84,6 +84,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/taskqueue.h>
|
||||
|
||||
#include <net/debugnet.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_var.h>
|
||||
#include <net/if_arp.h>
|
||||
@ -100,7 +101,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/netdump/netdump.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/resource.h>
|
||||
@ -519,7 +519,7 @@ static void bge_add_sysctl_stats(struct bge_softc *, struct sysctl_ctx_list *,
|
||||
struct sysctl_oid_list *);
|
||||
static int bge_sysctl_stats(SYSCTL_HANDLER_ARGS);
|
||||
|
||||
NETDUMP_DEFINE(bge);
|
||||
DEBUGNET_DEFINE(bge);
|
||||
|
||||
static device_method_t bge_methods[] = {
|
||||
/* Device interface */
|
||||
@ -3983,8 +3983,8 @@ bge_attach(device_t dev)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Attach driver netdump methods. */
|
||||
NETDUMP_SET(ifp, bge);
|
||||
/* Attach driver debugnet methods. */
|
||||
DEBUGNET_SET(ifp, bge);
|
||||
|
||||
fail:
|
||||
if (error)
|
||||
@ -6844,16 +6844,16 @@ bge_get_counter(if_t ifp, ift_counter cnt)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef NETDUMP
|
||||
#ifdef DEBUGNET
|
||||
static void
|
||||
bge_netdump_init(if_t ifp, int *nrxr, int *ncl, int *clsize)
|
||||
bge_debugnet_init(if_t ifp, int *nrxr, int *ncl, int *clsize)
|
||||
{
|
||||
struct bge_softc *sc;
|
||||
|
||||
sc = if_getsoftc(ifp);
|
||||
BGE_LOCK(sc);
|
||||
*nrxr = sc->bge_return_ring_cnt;
|
||||
*ncl = NETDUMP_MAX_IN_FLIGHT;
|
||||
*ncl = DEBUGNET_MAX_IN_FLIGHT;
|
||||
if ((sc->bge_flags & BGE_FLAG_JUMBO_STD) != 0 &&
|
||||
(if_getmtu(sc->bge_ifp) + ETHER_HDR_LEN + ETHER_CRC_LEN +
|
||||
ETHER_VLAN_ENCAP_LEN > (MCLBYTES - ETHER_ALIGN)))
|
||||
@ -6864,12 +6864,12 @@ bge_netdump_init(if_t ifp, int *nrxr, int *ncl, int *clsize)
|
||||
}
|
||||
|
||||
static void
|
||||
bge_netdump_event(if_t ifp __unused, enum netdump_ev event __unused)
|
||||
bge_debugnet_event(if_t ifp __unused, enum debugnet_ev event __unused)
|
||||
{
|
||||
}
|
||||
|
||||
static int
|
||||
bge_netdump_transmit(if_t ifp, struct mbuf *m)
|
||||
bge_debugnet_transmit(if_t ifp, struct mbuf *m)
|
||||
{
|
||||
struct bge_softc *sc;
|
||||
uint32_t prodidx;
|
||||
@ -6888,7 +6888,7 @@ bge_netdump_transmit(if_t ifp, struct mbuf *m)
|
||||
}
|
||||
|
||||
static int
|
||||
bge_netdump_poll(if_t ifp, int count)
|
||||
bge_debugnet_poll(if_t ifp, int count)
|
||||
{
|
||||
struct bge_softc *sc;
|
||||
uint32_t rx_prod, tx_cons;
|
||||
@ -6913,4 +6913,4 @@ bge_netdump_poll(if_t ifp, int count)
|
||||
bge_txeof(sc, tx_cons);
|
||||
return (0);
|
||||
}
|
||||
#endif /* NETDUMP */
|
||||
#endif /* DEBUGNET */
|
||||
|
@ -237,7 +237,7 @@ MODULE_DEPEND(bxe, pci, 1, 1, 1);
|
||||
MODULE_DEPEND(bxe, ether, 1, 1, 1);
|
||||
DRIVER_MODULE(bxe, pci, bxe_driver, bxe_devclass, 0, 0);
|
||||
|
||||
NETDUMP_DEFINE(bxe);
|
||||
DEBUGNET_DEFINE(bxe);
|
||||
|
||||
/* resources needed for unloading a previously loaded device */
|
||||
|
||||
@ -13124,8 +13124,8 @@ bxe_init_ifnet(struct bxe_softc *sc)
|
||||
/* attach to the Ethernet interface list */
|
||||
ether_ifattach(ifp, sc->link_params.mac_addr);
|
||||
|
||||
/* Attach driver netdump methods. */
|
||||
NETDUMP_SET(ifp, bxe);
|
||||
/* Attach driver debugnet methods. */
|
||||
DEBUGNET_SET(ifp, bxe);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -19533,27 +19533,27 @@ bxe_eioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
|
||||
return (rval);
|
||||
}
|
||||
|
||||
#ifdef NETDUMP
|
||||
#ifdef DEBUGNET
|
||||
static void
|
||||
bxe_netdump_init(struct ifnet *ifp, int *nrxr, int *ncl, int *clsize)
|
||||
bxe_debugnet_init(struct ifnet *ifp, int *nrxr, int *ncl, int *clsize)
|
||||
{
|
||||
struct bxe_softc *sc;
|
||||
|
||||
sc = if_getsoftc(ifp);
|
||||
BXE_CORE_LOCK(sc);
|
||||
*nrxr = sc->num_queues;
|
||||
*ncl = NETDUMP_MAX_IN_FLIGHT;
|
||||
*ncl = DEBUGNET_MAX_IN_FLIGHT;
|
||||
*clsize = sc->fp[0].mbuf_alloc_size;
|
||||
BXE_CORE_UNLOCK(sc);
|
||||
}
|
||||
|
||||
static void
|
||||
bxe_netdump_event(struct ifnet *ifp __unused, enum netdump_ev event __unused)
|
||||
bxe_debugnet_event(struct ifnet *ifp __unused, enum debugnet_ev event __unused)
|
||||
{
|
||||
}
|
||||
|
||||
static int
|
||||
bxe_netdump_transmit(struct ifnet *ifp, struct mbuf *m)
|
||||
bxe_debugnet_transmit(struct ifnet *ifp, struct mbuf *m)
|
||||
{
|
||||
struct bxe_softc *sc;
|
||||
int error;
|
||||
@ -19570,7 +19570,7 @@ bxe_netdump_transmit(struct ifnet *ifp, struct mbuf *m)
|
||||
}
|
||||
|
||||
static int
|
||||
bxe_netdump_poll(struct ifnet *ifp, int count)
|
||||
bxe_debugnet_poll(struct ifnet *ifp, int count)
|
||||
{
|
||||
struct bxe_softc *sc;
|
||||
int i;
|
||||
@ -19585,4 +19585,4 @@ bxe_netdump_poll(struct ifnet *ifp, int count)
|
||||
(void)bxe_txeof(sc, &sc->fp[0]);
|
||||
return (0);
|
||||
}
|
||||
#endif /* NETDUMP */
|
||||
#endif /* DEBUGNET */
|
||||
|
@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/taskqueue.h>
|
||||
#include <contrib/zlib/zlib.h>
|
||||
|
||||
#include <net/debugnet.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/if_arp.h>
|
||||
@ -70,7 +71,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/udp.h>
|
||||
#include <netinet/netdump/netdump.h>
|
||||
|
||||
#include <dev/pci/pcireg.h>
|
||||
#include <dev/pci/pcivar.h>
|
||||
|
@ -578,10 +578,10 @@ void cxgb_qflush(struct ifnet *ifp);
|
||||
void t3_iterate(void (*)(struct adapter *, void *), void *);
|
||||
void cxgb_refresh_stats(struct port_info *);
|
||||
|
||||
#ifdef NETDUMP
|
||||
int cxgb_netdump_encap(struct sge_qset *qs, struct mbuf **m);
|
||||
int cxgb_netdump_poll_rx(adapter_t *adap, struct sge_qset *qs);
|
||||
int cxgb_netdump_poll_tx(struct sge_qset *qs);
|
||||
#ifdef DEBUGNET
|
||||
int cxgb_debugnet_encap(struct sge_qset *qs, struct mbuf **m);
|
||||
int cxgb_debugnet_poll_rx(adapter_t *adap, struct sge_qset *qs);
|
||||
int cxgb_debugnet_poll_tx(struct sge_qset *qs);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
@ -58,6 +58,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/proc.h>
|
||||
|
||||
#include <net/bpf.h>
|
||||
#include <net/debugnet.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_var.h>
|
||||
@ -74,7 +75,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/udp.h>
|
||||
#include <netinet/netdump/netdump.h>
|
||||
|
||||
#include <dev/pci/pcireg.h>
|
||||
#include <dev/pci/pcivar.h>
|
||||
@ -218,7 +218,7 @@ static devclass_t cxgb_port_devclass;
|
||||
DRIVER_MODULE(cxgb, cxgbc, cxgb_port_driver, cxgb_port_devclass, 0, 0);
|
||||
MODULE_VERSION(cxgb, 1);
|
||||
|
||||
NETDUMP_DEFINE(cxgb);
|
||||
DEBUGNET_DEFINE(cxgb);
|
||||
|
||||
static struct mtx t3_list_lock;
|
||||
static SLIST_HEAD(, adapter) t3_list;
|
||||
@ -1053,8 +1053,8 @@ cxgb_port_attach(device_t dev)
|
||||
|
||||
ether_ifattach(ifp, p->hw_addr);
|
||||
|
||||
/* Attach driver netdump methods. */
|
||||
NETDUMP_SET(ifp, cxgb);
|
||||
/* Attach driver debugnet methods. */
|
||||
DEBUGNET_SET(ifp, cxgb);
|
||||
|
||||
#ifdef DEFAULT_JUMBO
|
||||
if (sc->params.nports <= 2)
|
||||
@ -3590,9 +3590,9 @@ cxgbc_mod_event(module_t mod, int cmd, void *arg)
|
||||
return (rc);
|
||||
}
|
||||
|
||||
#ifdef NETDUMP
|
||||
#ifdef DEBUGNET
|
||||
static void
|
||||
cxgb_netdump_init(struct ifnet *ifp, int *nrxr, int *ncl, int *clsize)
|
||||
cxgb_debugnet_init(struct ifnet *ifp, int *nrxr, int *ncl, int *clsize)
|
||||
{
|
||||
struct port_info *pi;
|
||||
adapter_t *adap;
|
||||
@ -3607,18 +3607,18 @@ cxgb_netdump_init(struct ifnet *ifp, int *nrxr, int *ncl, int *clsize)
|
||||
}
|
||||
|
||||
static void
|
||||
cxgb_netdump_event(struct ifnet *ifp, enum netdump_ev event)
|
||||
cxgb_debugnet_event(struct ifnet *ifp, enum debugnet_ev event)
|
||||
{
|
||||
struct port_info *pi;
|
||||
struct sge_qset *qs;
|
||||
int i;
|
||||
|
||||
pi = if_getsoftc(ifp);
|
||||
if (event == NETDUMP_START)
|
||||
if (event == DEBUGNET_START)
|
||||
for (i = 0; i < pi->adapter->nqsets; i++) {
|
||||
qs = &pi->adapter->sge.qs[i];
|
||||
|
||||
/* Need to reinit after netdump_mbuf_dump(). */
|
||||
/* Need to reinit after debugnet_mbuf_start(). */
|
||||
qs->fl[0].zone = zone_pack;
|
||||
qs->fl[1].zone = zone_clust;
|
||||
qs->lro.enabled = 0;
|
||||
@ -3626,7 +3626,7 @@ cxgb_netdump_event(struct ifnet *ifp, enum netdump_ev event)
|
||||
}
|
||||
|
||||
static int
|
||||
cxgb_netdump_transmit(struct ifnet *ifp, struct mbuf *m)
|
||||
cxgb_debugnet_transmit(struct ifnet *ifp, struct mbuf *m)
|
||||
{
|
||||
struct port_info *pi;
|
||||
struct sge_qset *qs;
|
||||
@ -3637,11 +3637,11 @@ cxgb_netdump_transmit(struct ifnet *ifp, struct mbuf *m)
|
||||
return (ENOENT);
|
||||
|
||||
qs = &pi->adapter->sge.qs[pi->first_qset];
|
||||
return (cxgb_netdump_encap(qs, &m));
|
||||
return (cxgb_debugnet_encap(qs, &m));
|
||||
}
|
||||
|
||||
static int
|
||||
cxgb_netdump_poll(struct ifnet *ifp, int count)
|
||||
cxgb_debugnet_poll(struct ifnet *ifp, int count)
|
||||
{
|
||||
struct port_info *pi;
|
||||
adapter_t *adap;
|
||||
@ -3653,8 +3653,8 @@ cxgb_netdump_poll(struct ifnet *ifp, int count)
|
||||
|
||||
adap = pi->adapter;
|
||||
for (i = 0; i < adap->nqsets; i++)
|
||||
(void)cxgb_netdump_poll_rx(adap, &adap->sge.qs[i]);
|
||||
(void)cxgb_netdump_poll_tx(&adap->sge.qs[pi->first_qset]);
|
||||
(void)cxgb_debugnet_poll_rx(adap, &adap->sge.qs[i]);
|
||||
(void)cxgb_debugnet_poll_tx(&adap->sge.qs[pi->first_qset]);
|
||||
return (0);
|
||||
}
|
||||
#endif /* NETDUMP */
|
||||
#endif /* DEBUGNET */
|
||||
|
@ -390,9 +390,9 @@ reclaim_completed_tx(struct sge_qset *qs, int reclaim_min, int queue)
|
||||
return (reclaim);
|
||||
}
|
||||
|
||||
#ifdef NETDUMP
|
||||
#ifdef DEBUGNET
|
||||
int
|
||||
cxgb_netdump_poll_tx(struct sge_qset *qs)
|
||||
cxgb_debugnet_poll_tx(struct sge_qset *qs)
|
||||
{
|
||||
|
||||
return (reclaim_completed_tx(qs, TX_RECLAIM_MAX, TXQ_ETH));
|
||||
@ -1595,9 +1595,9 @@ t3_encap(struct sge_qset *qs, struct mbuf **m)
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef NETDUMP
|
||||
#ifdef DEBUGNET
|
||||
int
|
||||
cxgb_netdump_encap(struct sge_qset *qs, struct mbuf **m)
|
||||
cxgb_debugnet_encap(struct sge_qset *qs, struct mbuf **m)
|
||||
{
|
||||
int error;
|
||||
|
||||
@ -3040,9 +3040,9 @@ process_responses_gts(adapter_t *adap, struct sge_rspq *rq)
|
||||
return (work);
|
||||
}
|
||||
|
||||
#ifdef NETDUMP
|
||||
#ifdef DEBUGNET
|
||||
int
|
||||
cxgb_netdump_poll_rx(adapter_t *adap, struct sge_qset *qs)
|
||||
cxgb_debugnet_poll_rx(adapter_t *adap, struct sge_qset *qs)
|
||||
{
|
||||
|
||||
return (process_responses_gts(adap, &qs->rspq));
|
||||
|
@ -53,8 +53,8 @@
|
||||
#include <dev/mlx4/doorbell.h>
|
||||
#include <dev/mlx4/cmd.h>
|
||||
|
||||
#include <net/debugnet.h>
|
||||
#include <netinet/tcp_lro.h>
|
||||
#include <netinet/netdump/netdump.h>
|
||||
|
||||
#include "en_port.h"
|
||||
#include <dev/mlx4/stats.h>
|
||||
|
@ -54,7 +54,7 @@
|
||||
#include "en.h"
|
||||
#include "en_port.h"
|
||||
|
||||
NETDUMP_DEFINE(mlx4_en);
|
||||
DEBUGNET_DEFINE(mlx4_en);
|
||||
|
||||
static void mlx4_en_sysctl_stat(struct mlx4_en_priv *priv);
|
||||
static void mlx4_en_sysctl_conf(struct mlx4_en_priv *priv);
|
||||
@ -2304,7 +2304,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
|
||||
ifmedia_add(&priv->media, IFM_ETHER | IFM_AUTO, 0, NULL);
|
||||
ifmedia_set(&priv->media, IFM_ETHER | IFM_AUTO);
|
||||
|
||||
NETDUMP_SET(dev, mlx4_en);
|
||||
DEBUGNET_SET(dev, mlx4_en);
|
||||
|
||||
en_warn(priv, "Using %d TX rings\n", prof->tx_ring_num);
|
||||
en_warn(priv, "Using %d RX rings\n", prof->rx_ring_num);
|
||||
@ -2888,27 +2888,27 @@ static void mlx4_en_sysctl_stat(struct mlx4_en_priv *priv)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef NETDUMP
|
||||
#ifdef DEBUGNET
|
||||
static void
|
||||
mlx4_en_netdump_init(struct ifnet *dev, int *nrxr, int *ncl, int *clsize)
|
||||
mlx4_en_debugnet_init(struct ifnet *dev, int *nrxr, int *ncl, int *clsize)
|
||||
{
|
||||
struct mlx4_en_priv *priv;
|
||||
|
||||
priv = if_getsoftc(dev);
|
||||
mutex_lock(&priv->mdev->state_lock);
|
||||
*nrxr = priv->rx_ring_num;
|
||||
*ncl = NETDUMP_MAX_IN_FLIGHT;
|
||||
*ncl = DEBUGNET_MAX_IN_FLIGHT;
|
||||
*clsize = priv->rx_mb_size;
|
||||
mutex_unlock(&priv->mdev->state_lock);
|
||||
}
|
||||
|
||||
static void
|
||||
mlx4_en_netdump_event(struct ifnet *dev, enum netdump_ev event)
|
||||
mlx4_en_debugnet_event(struct ifnet *dev, enum debugnet_ev event)
|
||||
{
|
||||
}
|
||||
|
||||
static int
|
||||
mlx4_en_netdump_transmit(struct ifnet *dev, struct mbuf *m)
|
||||
mlx4_en_debugnet_transmit(struct ifnet *dev, struct mbuf *m)
|
||||
{
|
||||
struct mlx4_en_priv *priv;
|
||||
int err;
|
||||
@ -2925,7 +2925,7 @@ mlx4_en_netdump_transmit(struct ifnet *dev, struct mbuf *m)
|
||||
}
|
||||
|
||||
static int
|
||||
mlx4_en_netdump_poll(struct ifnet *dev, int count)
|
||||
mlx4_en_debugnet_poll(struct ifnet *dev, int count)
|
||||
{
|
||||
struct mlx4_en_priv *priv;
|
||||
|
||||
@ -2937,4 +2937,4 @@ mlx4_en_netdump_poll(struct ifnet *dev, int count)
|
||||
|
||||
return (0);
|
||||
}
|
||||
#endif /* NETDUMP */
|
||||
#endif /* DEBUGNET */
|
||||
|
@ -128,6 +128,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/taskqueue.h>
|
||||
|
||||
#include <net/debugnet.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_var.h>
|
||||
#include <net/if_arp.h>
|
||||
@ -139,8 +140,6 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <net/bpf.h>
|
||||
|
||||
#include <netinet/netdump/netdump.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/resource.h>
|
||||
#include <sys/bus.h>
|
||||
@ -310,7 +309,7 @@ static void re_setwol (struct rl_softc *);
|
||||
static void re_clrwol (struct rl_softc *);
|
||||
static void re_set_linkspeed (struct rl_softc *);
|
||||
|
||||
NETDUMP_DEFINE(re);
|
||||
DEBUGNET_DEFINE(re);
|
||||
|
||||
#ifdef DEV_NETMAP /* see ixgbe.c for details */
|
||||
#include <dev/netmap/if_re_netmap.h>
|
||||
@ -1745,7 +1744,7 @@ re_attach(device_t dev)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
NETDUMP_SET(ifp, re);
|
||||
DEBUGNET_SET(ifp, re);
|
||||
|
||||
fail:
|
||||
if (error)
|
||||
@ -4093,28 +4092,28 @@ sysctl_hw_re_int_mod(SYSCTL_HANDLER_ARGS)
|
||||
RL_TIMER_MAX));
|
||||
}
|
||||
|
||||
#ifdef NETDUMP
|
||||
#ifdef DEBUGNET
|
||||
static void
|
||||
re_netdump_init(struct ifnet *ifp, int *nrxr, int *ncl, int *clsize)
|
||||
re_debugnet_init(struct ifnet *ifp, int *nrxr, int *ncl, int *clsize)
|
||||
{
|
||||
struct rl_softc *sc;
|
||||
|
||||
sc = if_getsoftc(ifp);
|
||||
RL_LOCK(sc);
|
||||
*nrxr = sc->rl_ldata.rl_rx_desc_cnt;
|
||||
*ncl = NETDUMP_MAX_IN_FLIGHT;
|
||||
*ncl = DEBUGNET_MAX_IN_FLIGHT;
|
||||
*clsize = (ifp->if_mtu > RL_MTU &&
|
||||
(sc->rl_flags & RL_FLAG_JUMBOV2) != 0) ? MJUM9BYTES : MCLBYTES;
|
||||
RL_UNLOCK(sc);
|
||||
}
|
||||
|
||||
static void
|
||||
re_netdump_event(struct ifnet *ifp __unused, enum netdump_ev event __unused)
|
||||
re_debugnet_event(struct ifnet *ifp __unused, enum debugnet_ev event __unused)
|
||||
{
|
||||
}
|
||||
|
||||
static int
|
||||
re_netdump_transmit(struct ifnet *ifp, struct mbuf *m)
|
||||
re_debugnet_transmit(struct ifnet *ifp, struct mbuf *m)
|
||||
{
|
||||
struct rl_softc *sc;
|
||||
int error;
|
||||
@ -4131,7 +4130,7 @@ re_netdump_transmit(struct ifnet *ifp, struct mbuf *m)
|
||||
}
|
||||
|
||||
static int
|
||||
re_netdump_poll(struct ifnet *ifp, int count)
|
||||
re_debugnet_poll(struct ifnet *ifp, int count)
|
||||
{
|
||||
struct rl_softc *sc;
|
||||
int error;
|
||||
@ -4147,4 +4146,4 @@ re_netdump_poll(struct ifnet *ifp, int count)
|
||||
return (error);
|
||||
return (0);
|
||||
}
|
||||
#endif /* NETDUMP */
|
||||
#endif /* DEBUGNET */
|
||||
|
@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <vm/uma.h>
|
||||
|
||||
#include <net/debugnet.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_var.h>
|
||||
@ -69,7 +70,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <netinet6/ip6_var.h>
|
||||
#include <netinet/udp.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/netdump/netdump.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
#include <machine/resource.h>
|
||||
@ -230,7 +230,7 @@ static void vtnet_disable_interrupts(struct vtnet_softc *);
|
||||
|
||||
static int vtnet_tunable_int(struct vtnet_softc *, const char *, int);
|
||||
|
||||
NETDUMP_DEFINE(vtnet);
|
||||
DEBUGNET_DEFINE(vtnet);
|
||||
|
||||
/* Tunables. */
|
||||
static SYSCTL_NODE(_hw, OID_AUTO, vtnet, CTLFLAG_RD, 0, "VNET driver parameters");
|
||||
@ -1025,7 +1025,7 @@ vtnet_setup_interface(struct vtnet_softc *sc)
|
||||
vtnet_set_rx_process_limit(sc);
|
||||
vtnet_set_tx_intr_threshold(sc);
|
||||
|
||||
NETDUMP_SET(ifp, vtnet);
|
||||
DEBUGNET_SET(ifp, vtnet);
|
||||
|
||||
return (0);
|
||||
}
|
||||
@ -3972,9 +3972,9 @@ vtnet_tunable_int(struct vtnet_softc *sc, const char *knob, int def)
|
||||
return (def);
|
||||
}
|
||||
|
||||
#ifdef NETDUMP
|
||||
#ifdef DEBUGNET
|
||||
static void
|
||||
vtnet_netdump_init(struct ifnet *ifp, int *nrxr, int *ncl, int *clsize)
|
||||
vtnet_debugnet_init(struct ifnet *ifp, int *nrxr, int *ncl, int *clsize)
|
||||
{
|
||||
struct vtnet_softc *sc;
|
||||
|
||||
@ -3982,7 +3982,7 @@ vtnet_netdump_init(struct ifnet *ifp, int *nrxr, int *ncl, int *clsize)
|
||||
|
||||
VTNET_CORE_LOCK(sc);
|
||||
*nrxr = sc->vtnet_max_vq_pairs;
|
||||
*ncl = NETDUMP_MAX_IN_FLIGHT;
|
||||
*ncl = DEBUGNET_MAX_IN_FLIGHT;
|
||||
*clsize = sc->vtnet_rx_clsize;
|
||||
VTNET_CORE_UNLOCK(sc);
|
||||
|
||||
@ -3992,17 +3992,17 @@ vtnet_netdump_init(struct ifnet *ifp, int *nrxr, int *ncl, int *clsize)
|
||||
* XXX add a separate zone like we do for mbufs? otherwise we may alloc
|
||||
* buckets
|
||||
*/
|
||||
uma_zone_reserve(vtnet_tx_header_zone, NETDUMP_MAX_IN_FLIGHT * 2);
|
||||
uma_prealloc(vtnet_tx_header_zone, NETDUMP_MAX_IN_FLIGHT * 2);
|
||||
uma_zone_reserve(vtnet_tx_header_zone, DEBUGNET_MAX_IN_FLIGHT * 2);
|
||||
uma_prealloc(vtnet_tx_header_zone, DEBUGNET_MAX_IN_FLIGHT * 2);
|
||||
}
|
||||
|
||||
static void
|
||||
vtnet_netdump_event(struct ifnet *ifp __unused, enum netdump_ev event __unused)
|
||||
vtnet_debugnet_event(struct ifnet *ifp __unused, enum debugnet_ev event __unused)
|
||||
{
|
||||
}
|
||||
|
||||
static int
|
||||
vtnet_netdump_transmit(struct ifnet *ifp, struct mbuf *m)
|
||||
vtnet_debugnet_transmit(struct ifnet *ifp, struct mbuf *m)
|
||||
{
|
||||
struct vtnet_softc *sc;
|
||||
struct vtnet_txq *txq;
|
||||
@ -4021,7 +4021,7 @@ vtnet_netdump_transmit(struct ifnet *ifp, struct mbuf *m)
|
||||
}
|
||||
|
||||
static int
|
||||
vtnet_netdump_poll(struct ifnet *ifp, int count)
|
||||
vtnet_debugnet_poll(struct ifnet *ifp, int count)
|
||||
{
|
||||
struct vtnet_softc *sc;
|
||||
int i;
|
||||
@ -4036,4 +4036,4 @@ vtnet_netdump_poll(struct ifnet *ifp, int count)
|
||||
(void)vtnet_rxq_eof(&sc->vtnet_rxqs[i]);
|
||||
return (0);
|
||||
}
|
||||
#endif /* NETDUMP */
|
||||
#endif /* DEBUGNET */
|
||||
|
@ -99,6 +99,7 @@ options VERBOSE_SYSINIT=0 # Support debug.verbose_sysinit, off by default
|
||||
options EKCD # Support for encrypted kernel dumps
|
||||
options GZIO # gzip-compressed kernel and user dumps
|
||||
options ZSTDIO # zstd-compressed kernel and user dumps
|
||||
options DEBUGNET # debugnet networking
|
||||
options NETDUMP # netdump(4) client support
|
||||
|
||||
# To make an SMP kernel, the next two lines are needed
|
||||
|
@ -413,10 +413,10 @@ mbuf_init(void *dummy)
|
||||
}
|
||||
SYSINIT(mbuf, SI_SUB_MBUF, SI_ORDER_FIRST, mbuf_init, NULL);
|
||||
|
||||
#ifdef NETDUMP
|
||||
#ifdef DEBUGNET
|
||||
/*
|
||||
* netdump makes use of a pre-allocated pool of mbufs and clusters. When
|
||||
* netdump is configured, we initialize a set of UMA cache zones which return
|
||||
* debugnet makes use of a pre-allocated pool of mbufs and clusters. When
|
||||
* debugnet is configured, we initialize a set of UMA cache zones which return
|
||||
* items from this pool. At panic-time, the regular UMA zone pointers are
|
||||
* overwritten with those of the cache zones so that drivers may allocate and
|
||||
* free mbufs and clusters without attempting to allocate physical memory.
|
||||
@ -424,18 +424,28 @@ SYSINIT(mbuf, SI_SUB_MBUF, SI_ORDER_FIRST, mbuf_init, NULL);
|
||||
* We keep mbufs and clusters in a pair of mbuf queues. In particular, for
|
||||
* the purpose of caching clusters, we treat them as mbufs.
|
||||
*/
|
||||
static struct mbufq nd_mbufq =
|
||||
{ STAILQ_HEAD_INITIALIZER(nd_mbufq.mq_head), 0, INT_MAX };
|
||||
static struct mbufq nd_clustq =
|
||||
{ STAILQ_HEAD_INITIALIZER(nd_clustq.mq_head), 0, INT_MAX };
|
||||
static struct mbufq dn_mbufq =
|
||||
{ STAILQ_HEAD_INITIALIZER(dn_mbufq.mq_head), 0, INT_MAX };
|
||||
static struct mbufq dn_clustq =
|
||||
{ STAILQ_HEAD_INITIALIZER(dn_clustq.mq_head), 0, INT_MAX };
|
||||
|
||||
static int nd_clsize;
|
||||
static uma_zone_t nd_zone_mbuf;
|
||||
static uma_zone_t nd_zone_clust;
|
||||
static uma_zone_t nd_zone_pack;
|
||||
static int dn_clsize;
|
||||
static uma_zone_t dn_zone_mbuf;
|
||||
static uma_zone_t dn_zone_clust;
|
||||
static uma_zone_t dn_zone_pack;
|
||||
|
||||
static struct debugnet_saved_zones {
|
||||
uma_zone_t dsz_mbuf;
|
||||
uma_zone_t dsz_clust;
|
||||
uma_zone_t dsz_pack;
|
||||
uma_zone_t dsz_jumbop;
|
||||
uma_zone_t dsz_jumbo9;
|
||||
uma_zone_t dsz_jumbo16;
|
||||
bool dsz_debugnet_zones_enabled;
|
||||
} dn_saved_zones;
|
||||
|
||||
static int
|
||||
nd_buf_import(void *arg, void **store, int count, int domain __unused,
|
||||
dn_buf_import(void *arg, void **store, int count, int domain __unused,
|
||||
int flags)
|
||||
{
|
||||
struct mbufq *q;
|
||||
@ -448,7 +458,7 @@ nd_buf_import(void *arg, void **store, int count, int domain __unused,
|
||||
m = mbufq_dequeue(q);
|
||||
if (m == NULL)
|
||||
break;
|
||||
trash_init(m, q == &nd_mbufq ? MSIZE : nd_clsize, flags);
|
||||
trash_init(m, q == &dn_mbufq ? MSIZE : dn_clsize, flags);
|
||||
store[i] = m;
|
||||
}
|
||||
KASSERT((flags & M_WAITOK) == 0 || i == count,
|
||||
@ -457,7 +467,7 @@ nd_buf_import(void *arg, void **store, int count, int domain __unused,
|
||||
}
|
||||
|
||||
static void
|
||||
nd_buf_release(void *arg, void **store, int count)
|
||||
dn_buf_release(void *arg, void **store, int count)
|
||||
{
|
||||
struct mbufq *q;
|
||||
struct mbuf *m;
|
||||
@ -472,7 +482,7 @@ nd_buf_release(void *arg, void **store, int count)
|
||||
}
|
||||
|
||||
static int
|
||||
nd_pack_import(void *arg __unused, void **store, int count, int domain __unused,
|
||||
dn_pack_import(void *arg __unused, void **store, int count, int domain __unused,
|
||||
int flags __unused)
|
||||
{
|
||||
struct mbuf *m;
|
||||
@ -483,12 +493,12 @@ nd_pack_import(void *arg __unused, void **store, int count, int domain __unused,
|
||||
m = m_get(MT_DATA, M_NOWAIT);
|
||||
if (m == NULL)
|
||||
break;
|
||||
clust = uma_zalloc(nd_zone_clust, M_NOWAIT);
|
||||
clust = uma_zalloc(dn_zone_clust, M_NOWAIT);
|
||||
if (clust == NULL) {
|
||||
m_free(m);
|
||||
break;
|
||||
}
|
||||
mb_ctor_clust(clust, nd_clsize, m, 0);
|
||||
mb_ctor_clust(clust, dn_clsize, m, 0);
|
||||
store[i] = m;
|
||||
}
|
||||
KASSERT((flags & M_WAITOK) == 0 || i == count,
|
||||
@ -497,7 +507,7 @@ nd_pack_import(void *arg __unused, void **store, int count, int domain __unused,
|
||||
}
|
||||
|
||||
static void
|
||||
nd_pack_release(void *arg __unused, void **store, int count)
|
||||
dn_pack_release(void *arg __unused, void **store, int count)
|
||||
{
|
||||
struct mbuf *m;
|
||||
void *clust;
|
||||
@ -506,109 +516,142 @@ nd_pack_release(void *arg __unused, void **store, int count)
|
||||
for (i = 0; i < count; i++) {
|
||||
m = store[i];
|
||||
clust = m->m_ext.ext_buf;
|
||||
uma_zfree(nd_zone_clust, clust);
|
||||
uma_zfree(nd_zone_mbuf, m);
|
||||
uma_zfree(dn_zone_clust, clust);
|
||||
uma_zfree(dn_zone_mbuf, m);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Free the pre-allocated mbufs and clusters reserved for netdump, and destroy
|
||||
* Free the pre-allocated mbufs and clusters reserved for debugnet, and destroy
|
||||
* the corresponding UMA cache zones.
|
||||
*/
|
||||
void
|
||||
netdump_mbuf_drain(void)
|
||||
debugnet_mbuf_drain(void)
|
||||
{
|
||||
struct mbuf *m;
|
||||
void *item;
|
||||
|
||||
if (nd_zone_mbuf != NULL) {
|
||||
uma_zdestroy(nd_zone_mbuf);
|
||||
nd_zone_mbuf = NULL;
|
||||
if (dn_zone_mbuf != NULL) {
|
||||
uma_zdestroy(dn_zone_mbuf);
|
||||
dn_zone_mbuf = NULL;
|
||||
}
|
||||
if (nd_zone_clust != NULL) {
|
||||
uma_zdestroy(nd_zone_clust);
|
||||
nd_zone_clust = NULL;
|
||||
if (dn_zone_clust != NULL) {
|
||||
uma_zdestroy(dn_zone_clust);
|
||||
dn_zone_clust = NULL;
|
||||
}
|
||||
if (nd_zone_pack != NULL) {
|
||||
uma_zdestroy(nd_zone_pack);
|
||||
nd_zone_pack = NULL;
|
||||
if (dn_zone_pack != NULL) {
|
||||
uma_zdestroy(dn_zone_pack);
|
||||
dn_zone_pack = NULL;
|
||||
}
|
||||
|
||||
while ((m = mbufq_dequeue(&nd_mbufq)) != NULL)
|
||||
while ((m = mbufq_dequeue(&dn_mbufq)) != NULL)
|
||||
m_free(m);
|
||||
while ((item = mbufq_dequeue(&nd_clustq)) != NULL)
|
||||
uma_zfree(m_getzone(nd_clsize), item);
|
||||
while ((item = mbufq_dequeue(&dn_clustq)) != NULL)
|
||||
uma_zfree(m_getzone(dn_clsize), item);
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback invoked immediately prior to starting a netdump.
|
||||
* Callback invoked immediately prior to starting a debugnet connection.
|
||||
*/
|
||||
void
|
||||
netdump_mbuf_dump(void)
|
||||
debugnet_mbuf_start(void)
|
||||
{
|
||||
|
||||
MPASS(!dn_saved_zones.dsz_debugnet_zones_enabled);
|
||||
|
||||
/* Save the old zone pointers to restore when debugnet is closed. */
|
||||
dn_saved_zones = (struct debugnet_saved_zones) {
|
||||
.dsz_debugnet_zones_enabled = true,
|
||||
.dsz_mbuf = zone_mbuf,
|
||||
.dsz_clust = zone_clust,
|
||||
.dsz_pack = zone_pack,
|
||||
.dsz_jumbop = zone_jumbop,
|
||||
.dsz_jumbo9 = zone_jumbo9,
|
||||
.dsz_jumbo16 = zone_jumbo16,
|
||||
};
|
||||
|
||||
/*
|
||||
* All cluster zones return buffers of the size requested by the
|
||||
* drivers. It's up to the driver to reinitialize the zones if the
|
||||
* MTU of a netdump-enabled interface changes.
|
||||
* MTU of a debugnet-enabled interface changes.
|
||||
*/
|
||||
printf("netdump: overwriting mbuf zone pointers\n");
|
||||
zone_mbuf = nd_zone_mbuf;
|
||||
zone_clust = nd_zone_clust;
|
||||
zone_pack = nd_zone_pack;
|
||||
zone_jumbop = nd_zone_clust;
|
||||
zone_jumbo9 = nd_zone_clust;
|
||||
zone_jumbo16 = nd_zone_clust;
|
||||
printf("debugnet: overwriting mbuf zone pointers\n");
|
||||
zone_mbuf = dn_zone_mbuf;
|
||||
zone_clust = dn_zone_clust;
|
||||
zone_pack = dn_zone_pack;
|
||||
zone_jumbop = dn_zone_clust;
|
||||
zone_jumbo9 = dn_zone_clust;
|
||||
zone_jumbo16 = dn_zone_clust;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reinitialize the netdump mbuf+cluster pool and cache zones.
|
||||
* Callback invoked when a debugnet connection is closed/finished.
|
||||
*/
|
||||
void
|
||||
netdump_mbuf_reinit(int nmbuf, int nclust, int clsize)
|
||||
debugnet_mbuf_finish(void)
|
||||
{
|
||||
|
||||
MPASS(dn_saved_zones.dsz_debugnet_zones_enabled);
|
||||
|
||||
printf("debugnet: restoring mbuf zone pointers\n");
|
||||
zone_mbuf = dn_saved_zones.dsz_mbuf;
|
||||
zone_clust = dn_saved_zones.dsz_clust;
|
||||
zone_pack = dn_saved_zones.dsz_pack;
|
||||
zone_jumbop = dn_saved_zones.dsz_jumbop;
|
||||
zone_jumbo9 = dn_saved_zones.dsz_jumbo9;
|
||||
zone_jumbo16 = dn_saved_zones.dsz_jumbo16;
|
||||
|
||||
memset(&dn_saved_zones, 0, sizeof(dn_saved_zones));
|
||||
}
|
||||
|
||||
/*
|
||||
* Reinitialize the debugnet mbuf+cluster pool and cache zones.
|
||||
*/
|
||||
void
|
||||
debugnet_mbuf_reinit(int nmbuf, int nclust, int clsize)
|
||||
{
|
||||
struct mbuf *m;
|
||||
void *item;
|
||||
|
||||
netdump_mbuf_drain();
|
||||
debugnet_mbuf_drain();
|
||||
|
||||
nd_clsize = clsize;
|
||||
dn_clsize = clsize;
|
||||
|
||||
nd_zone_mbuf = uma_zcache_create("netdump_" MBUF_MEM_NAME,
|
||||
dn_zone_mbuf = uma_zcache_create("debugnet_" MBUF_MEM_NAME,
|
||||
MSIZE, mb_ctor_mbuf, mb_dtor_mbuf,
|
||||
#ifdef INVARIANTS
|
||||
trash_init, trash_fini,
|
||||
#else
|
||||
NULL, NULL,
|
||||
#endif
|
||||
nd_buf_import, nd_buf_release,
|
||||
&nd_mbufq, UMA_ZONE_NOBUCKET);
|
||||
dn_buf_import, dn_buf_release,
|
||||
&dn_mbufq, UMA_ZONE_NOBUCKET);
|
||||
|
||||
nd_zone_clust = uma_zcache_create("netdump_" MBUF_CLUSTER_MEM_NAME,
|
||||
dn_zone_clust = uma_zcache_create("debugnet_" MBUF_CLUSTER_MEM_NAME,
|
||||
clsize, mb_ctor_clust,
|
||||
#ifdef INVARIANTS
|
||||
trash_dtor, trash_init, trash_fini,
|
||||
#else
|
||||
NULL, NULL, NULL,
|
||||
#endif
|
||||
nd_buf_import, nd_buf_release,
|
||||
&nd_clustq, UMA_ZONE_NOBUCKET);
|
||||
dn_buf_import, dn_buf_release,
|
||||
&dn_clustq, UMA_ZONE_NOBUCKET);
|
||||
|
||||
nd_zone_pack = uma_zcache_create("netdump_" MBUF_PACKET_MEM_NAME,
|
||||
dn_zone_pack = uma_zcache_create("debugnet_" MBUF_PACKET_MEM_NAME,
|
||||
MCLBYTES, mb_ctor_pack, mb_dtor_pack, NULL, NULL,
|
||||
nd_pack_import, nd_pack_release,
|
||||
dn_pack_import, dn_pack_release,
|
||||
NULL, UMA_ZONE_NOBUCKET);
|
||||
|
||||
while (nmbuf-- > 0) {
|
||||
m = m_get(MT_DATA, M_WAITOK);
|
||||
uma_zfree(nd_zone_mbuf, m);
|
||||
uma_zfree(dn_zone_mbuf, m);
|
||||
}
|
||||
while (nclust-- > 0) {
|
||||
item = uma_zalloc(m_getzone(nd_clsize), M_WAITOK);
|
||||
uma_zfree(nd_zone_clust, item);
|
||||
item = uma_zalloc(m_getzone(dn_clsize), M_WAITOK);
|
||||
uma_zfree(dn_zone_clust, item);
|
||||
}
|
||||
}
|
||||
#endif /* NETDUMP */
|
||||
#endif /* DEBUGNET */
|
||||
|
||||
/*
|
||||
* UMA backend page allocator for the jumbo frame zones.
|
||||
|
655
sys/net/debugnet.c
Normal file
655
sys/net/debugnet.c
Normal file
@ -0,0 +1,655 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2019 Isilon Systems, LLC.
|
||||
* Copyright (c) 2005-2014 Sandvine Incorporated. All rights reserved.
|
||||
* Copyright (c) 2000 Darrell Anderson
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "opt_inet.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/endian.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/if_var.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/in_var.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_var.h>
|
||||
#include <netinet/ip_options.h>
|
||||
#include <netinet/udp.h>
|
||||
#include <netinet/udp_var.h>
|
||||
|
||||
#include <machine/in_cksum.h>
|
||||
#include <machine/pcb.h>
|
||||
|
||||
#include <net/debugnet.h>
|
||||
#define DEBUGNET_INTERNAL
|
||||
#include <net/debugnet_int.h>
|
||||
|
||||
FEATURE(debugnet, "Debugnet support");
|
||||
|
||||
SYSCTL_NODE(_net, OID_AUTO, debugnet, CTLFLAG_RD, NULL,
|
||||
"debugnet parameters");
|
||||
|
||||
unsigned debugnet_debug;
|
||||
SYSCTL_UINT(_net_debugnet, OID_AUTO, debug, CTLFLAG_RWTUN,
|
||||
&debugnet_debug, 0,
|
||||
"Debug message verbosity (0: off; 1: on; 2: verbose)");
|
||||
|
||||
int debugnet_npolls = 2000;
|
||||
SYSCTL_INT(_net_debugnet, OID_AUTO, npolls, CTLFLAG_RWTUN,
|
||||
&debugnet_npolls, 0,
|
||||
"Number of times to poll before assuming packet loss (0.5ms per poll)");
|
||||
int debugnet_nretries = 10;
|
||||
SYSCTL_INT(_net_debugnet, OID_AUTO, nretries, CTLFLAG_RWTUN,
|
||||
&debugnet_nretries, 0,
|
||||
"Number of retransmit attempts before giving up");
|
||||
|
||||
static bool g_debugnet_pcb_inuse;
|
||||
static struct debugnet_pcb g_dnet_pcb;
|
||||
|
||||
/*
|
||||
* Simple accessors for opaque PCB.
|
||||
*/
|
||||
const unsigned char *
|
||||
debugnet_get_gw_mac(const struct debugnet_pcb *pcb)
|
||||
{
|
||||
MPASS(g_debugnet_pcb_inuse && pcb == &g_dnet_pcb &&
|
||||
pcb->dp_state >= DN_STATE_HAVE_GW_MAC);
|
||||
return (pcb->dp_gw_mac.octet);
|
||||
}
|
||||
|
||||
/*
|
||||
* Start of network primitives, beginning with output primitives.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Handles creation of the ethernet header, then places outgoing packets into
|
||||
* the tx buffer for the NIC
|
||||
*
|
||||
* Parameters:
|
||||
* m The mbuf containing the packet to be sent (will be freed by
|
||||
* this function or the NIC driver)
|
||||
* ifp The interface to send on
|
||||
* dst The destination ethernet address (source address will be looked
|
||||
* up using ifp)
|
||||
* etype The ETHERTYPE_* value for the protocol that is being sent
|
||||
*
|
||||
* Returns:
|
||||
* int see errno.h, 0 for success
|
||||
*/
|
||||
int
|
||||
debugnet_ether_output(struct mbuf *m, struct ifnet *ifp, struct ether_addr dst,
|
||||
u_short etype)
|
||||
{
|
||||
struct ether_header *eh;
|
||||
|
||||
if (((ifp->if_flags & (IFF_MONITOR | IFF_UP)) != IFF_UP) ||
|
||||
(ifp->if_drv_flags & IFF_DRV_RUNNING) != IFF_DRV_RUNNING) {
|
||||
if_printf(ifp, "%s: interface isn't up\n", __func__);
|
||||
m_freem(m);
|
||||
return (ENETDOWN);
|
||||
}
|
||||
|
||||
/* Fill in the ethernet header. */
|
||||
M_PREPEND(m, ETHER_HDR_LEN, M_NOWAIT);
|
||||
if (m == NULL) {
|
||||
printf("%s: out of mbufs\n", __func__);
|
||||
return (ENOBUFS);
|
||||
}
|
||||
eh = mtod(m, struct ether_header *);
|
||||
memcpy(eh->ether_shost, IF_LLADDR(ifp), ETHER_ADDR_LEN);
|
||||
memcpy(eh->ether_dhost, dst.octet, ETHER_ADDR_LEN);
|
||||
eh->ether_type = htons(etype);
|
||||
return (ifp->if_debugnet_methods->dn_transmit(ifp, m));
|
||||
}
|
||||
|
||||
/*
|
||||
* Unreliable transmission of an mbuf chain to the debugnet server
|
||||
* Note: can't handle fragmentation; fails if the packet is larger than
|
||||
* ifp->if_mtu after adding the UDP/IP headers
|
||||
*
|
||||
* Parameters:
|
||||
* pcb The debugnet context block
|
||||
* m mbuf chain
|
||||
*
|
||||
* Returns:
|
||||
* int see errno.h, 0 for success
|
||||
*/
|
||||
static int
|
||||
debugnet_udp_output(struct debugnet_pcb *pcb, struct mbuf *m)
|
||||
{
|
||||
struct udphdr *udp;
|
||||
|
||||
MPASS(pcb->dp_state >= DN_STATE_HAVE_GW_MAC);
|
||||
|
||||
M_PREPEND(m, sizeof(*udp), M_NOWAIT);
|
||||
if (m == NULL) {
|
||||
printf("%s: out of mbufs\n", __func__);
|
||||
return (ENOBUFS);
|
||||
}
|
||||
|
||||
udp = mtod(m, void *);
|
||||
udp->uh_ulen = htons(m->m_pkthdr.len);
|
||||
/* Use this src port so that the server can connect() the socket */
|
||||
udp->uh_sport = htons(pcb->dp_client_ack_port);
|
||||
udp->uh_dport = htons(pcb->dp_server_port);
|
||||
/* Computed later (protocol-dependent). */
|
||||
udp->uh_sum = 0;
|
||||
|
||||
return (debugnet_ip_output(pcb, m));
|
||||
}
|
||||
|
||||
/*
|
||||
* Dummy free function for debugnet clusters.
|
||||
*/
|
||||
static void
|
||||
debugnet_mbuf_free(struct mbuf *m __unused)
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct and reliably send a debugnet packet. May fail from a resource
|
||||
* shortage or extreme number of unacknowledged retransmissions. Wait for
|
||||
* an acknowledgement before returning. Splits packets into chunks small
|
||||
* enough to be sent without fragmentation (looks up the interface MTU)
|
||||
*
|
||||
* Parameters:
|
||||
* type debugnet packet type (HERALD, FINISHED, ...)
|
||||
* data data
|
||||
* datalen data size (bytes)
|
||||
* auxdata optional auxiliary information
|
||||
*
|
||||
* Returns:
|
||||
* int see errno.h, 0 for success
|
||||
*/
|
||||
int
|
||||
debugnet_send(struct debugnet_pcb *pcb, uint32_t type, const void *data,
|
||||
uint32_t datalen, const struct debugnet_proto_aux *auxdata)
|
||||
{
|
||||
struct debugnet_msg_hdr *dn_msg_hdr;
|
||||
struct mbuf *m, *m2;
|
||||
uint64_t want_acks;
|
||||
uint32_t i, pktlen, sent_so_far;
|
||||
int retries, polls, error;
|
||||
|
||||
want_acks = 0;
|
||||
pcb->dp_rcvd_acks = 0;
|
||||
retries = 0;
|
||||
|
||||
retransmit:
|
||||
/* Chunks can be too big to fit in packets. */
|
||||
for (i = sent_so_far = 0; sent_so_far < datalen ||
|
||||
(i == 0 && datalen == 0); i++) {
|
||||
pktlen = datalen - sent_so_far;
|
||||
|
||||
/* Bound: the interface MTU (assume no IP options). */
|
||||
pktlen = min(pktlen, pcb->dp_ifp->if_mtu -
|
||||
sizeof(struct udpiphdr) - sizeof(struct debugnet_msg_hdr));
|
||||
|
||||
/*
|
||||
* Check if it is retransmitting and this has been ACKed
|
||||
* already.
|
||||
*/
|
||||
if ((pcb->dp_rcvd_acks & (1 << i)) != 0) {
|
||||
sent_so_far += pktlen;
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get and fill a header mbuf, then chain data as an extended
|
||||
* mbuf.
|
||||
*/
|
||||
m = m_gethdr(M_NOWAIT, MT_DATA);
|
||||
if (m == NULL) {
|
||||
printf("%s: Out of mbufs\n", __func__);
|
||||
return (ENOBUFS);
|
||||
}
|
||||
m->m_len = sizeof(struct debugnet_msg_hdr);
|
||||
m->m_pkthdr.len = sizeof(struct debugnet_msg_hdr);
|
||||
MH_ALIGN(m, sizeof(struct debugnet_msg_hdr));
|
||||
dn_msg_hdr = mtod(m, struct debugnet_msg_hdr *);
|
||||
dn_msg_hdr->mh_seqno = htonl(pcb->dp_seqno + i);
|
||||
dn_msg_hdr->mh_type = htonl(type);
|
||||
dn_msg_hdr->mh_len = htonl(pktlen);
|
||||
|
||||
if (auxdata != NULL) {
|
||||
dn_msg_hdr->mh_offset =
|
||||
htobe64(auxdata->dp_offset_start + sent_so_far);
|
||||
dn_msg_hdr->mh_aux2 = htobe32(auxdata->dp_aux2);
|
||||
} else {
|
||||
dn_msg_hdr->mh_offset = htobe64(sent_so_far);
|
||||
dn_msg_hdr->mh_aux2 = 0;
|
||||
}
|
||||
|
||||
if (pktlen != 0) {
|
||||
m2 = m_get(M_NOWAIT, MT_DATA);
|
||||
if (m2 == NULL) {
|
||||
m_freem(m);
|
||||
printf("%s: Out of mbufs\n", __func__);
|
||||
return (ENOBUFS);
|
||||
}
|
||||
MEXTADD(m2, __DECONST(char *, data) + sent_so_far,
|
||||
pktlen, debugnet_mbuf_free, NULL, NULL, 0,
|
||||
EXT_DISPOSABLE);
|
||||
m2->m_len = pktlen;
|
||||
|
||||
m_cat(m, m2);
|
||||
m->m_pkthdr.len += pktlen;
|
||||
}
|
||||
error = debugnet_udp_output(pcb, m);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
/* Note that we're waiting for this packet in the bitfield. */
|
||||
want_acks |= (1 << i);
|
||||
sent_so_far += pktlen;
|
||||
}
|
||||
if (i >= DEBUGNET_MAX_IN_FLIGHT)
|
||||
printf("Warning: Sent more than %d packets (%d). "
|
||||
"Acknowledgements will fail unless the size of "
|
||||
"rcvd_acks/want_acks is increased.\n",
|
||||
DEBUGNET_MAX_IN_FLIGHT, i);
|
||||
|
||||
/*
|
||||
* Wait for acks. A *real* window would speed things up considerably.
|
||||
*/
|
||||
polls = 0;
|
||||
while (pcb->dp_rcvd_acks != want_acks) {
|
||||
if (polls++ > debugnet_npolls) {
|
||||
if (retries++ > debugnet_nretries)
|
||||
return (ETIMEDOUT);
|
||||
printf(". ");
|
||||
goto retransmit;
|
||||
}
|
||||
debugnet_network_poll(pcb->dp_ifp);
|
||||
DELAY(500);
|
||||
}
|
||||
pcb->dp_seqno += i;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Network input primitives.
|
||||
*/
|
||||
|
||||
static void
|
||||
debugnet_handle_ack(struct debugnet_pcb *pcb, struct mbuf **mb, uint16_t sport)
|
||||
{
|
||||
const struct debugnet_ack *dn_ack;
|
||||
struct mbuf *m;
|
||||
uint32_t rcv_ackno;
|
||||
|
||||
m = *mb;
|
||||
|
||||
if (m->m_pkthdr.len < sizeof(*dn_ack)) {
|
||||
DNETDEBUG("ignoring small ACK packet\n");
|
||||
return;
|
||||
}
|
||||
/* Get Ack. */
|
||||
if (m->m_len < sizeof(*dn_ack)) {
|
||||
m = m_pullup(m, sizeof(*dn_ack));
|
||||
*mb = m;
|
||||
if (m == NULL) {
|
||||
DNETDEBUG("m_pullup failed\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
dn_ack = mtod(m, const void *);
|
||||
|
||||
/* Debugnet processing. */
|
||||
/*
|
||||
* Packet is meant for us. Extract the ack sequence number and the
|
||||
* port number if necessary.
|
||||
*/
|
||||
rcv_ackno = ntohl(dn_ack->da_seqno);
|
||||
if (pcb->dp_state < DN_STATE_GOT_HERALD_PORT) {
|
||||
pcb->dp_server_port = sport;
|
||||
pcb->dp_state = DN_STATE_GOT_HERALD_PORT;
|
||||
}
|
||||
if (rcv_ackno >= pcb->dp_seqno + DEBUGNET_MAX_IN_FLIGHT)
|
||||
printf("%s: ACK %u too far in future!\n", __func__, rcv_ackno);
|
||||
else if (rcv_ackno >= pcb->dp_seqno) {
|
||||
/* We're interested in this ack. Record it. */
|
||||
pcb->dp_rcvd_acks |= 1 << (rcv_ackno - pcb->dp_seqno);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
debugnet_handle_udp(struct debugnet_pcb *pcb, struct mbuf **mb)
|
||||
{
|
||||
const struct udphdr *udp;
|
||||
struct mbuf *m;
|
||||
uint16_t sport;
|
||||
|
||||
/* UDP processing. */
|
||||
|
||||
m = *mb;
|
||||
if (m->m_pkthdr.len < sizeof(*udp)) {
|
||||
DNETDEBUG("ignoring small UDP packet\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get UDP headers. */
|
||||
if (m->m_len < sizeof(*udp)) {
|
||||
m = m_pullup(m, sizeof(*udp));
|
||||
*mb = m;
|
||||
if (m == NULL) {
|
||||
DNETDEBUG("m_pullup failed\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
udp = mtod(m, const void *);
|
||||
|
||||
/* For now, the only UDP packets we expect to receive are acks. */
|
||||
if (ntohs(udp->uh_dport) != pcb->dp_client_ack_port) {
|
||||
DNETDEBUG("not on the expected ACK port.\n");
|
||||
return;
|
||||
}
|
||||
sport = ntohs(udp->uh_sport);
|
||||
|
||||
m_adj(m, sizeof(*udp));
|
||||
debugnet_handle_ack(pcb, mb, sport);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handler for incoming packets directly from the network adapter
|
||||
* Identifies the packet type (IP or ARP) and passes it along to one of the
|
||||
* helper functions debugnet_handle_ip or debugnet_handle_arp.
|
||||
*
|
||||
* It needs to partially replicate the behaviour of ether_input() and
|
||||
* ether_demux().
|
||||
*
|
||||
* Parameters:
|
||||
* ifp the interface the packet came from
|
||||
* m an mbuf containing the packet received
|
||||
*/
|
||||
static void
|
||||
debugnet_pkt_in(struct ifnet *ifp, struct mbuf *m)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
struct ether_header *eh;
|
||||
u_short etype;
|
||||
|
||||
/* Ethernet processing. */
|
||||
if ((m->m_flags & M_PKTHDR) == 0) {
|
||||
DNETDEBUG_IF(ifp, "discard frame without packet header\n");
|
||||
goto done;
|
||||
}
|
||||
if (m->m_len < ETHER_HDR_LEN) {
|
||||
DNETDEBUG_IF(ifp,
|
||||
"discard frame without leading eth header (len %u pktlen %u)\n",
|
||||
m->m_len, m->m_pkthdr.len);
|
||||
goto done;
|
||||
}
|
||||
if ((m->m_flags & M_HASFCS) != 0) {
|
||||
m_adj(m, -ETHER_CRC_LEN);
|
||||
m->m_flags &= ~M_HASFCS;
|
||||
}
|
||||
eh = mtod(m, struct ether_header *);
|
||||
etype = ntohs(eh->ether_type);
|
||||
if ((m->m_flags & M_VLANTAG) != 0 || etype == ETHERTYPE_VLAN) {
|
||||
DNETDEBUG_IF(ifp, "ignoring vlan packets\n");
|
||||
goto done;
|
||||
}
|
||||
if (if_gethwaddr(ifp, &ifr) != 0) {
|
||||
DNETDEBUG_IF(ifp, "failed to get hw addr for interface\n");
|
||||
goto done;
|
||||
}
|
||||
if (memcmp(ifr.ifr_addr.sa_data, eh->ether_dhost,
|
||||
ETHER_ADDR_LEN) != 0) {
|
||||
DNETDEBUG_IF(ifp,
|
||||
"discard frame with incorrect destination addr\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
MPASS(g_debugnet_pcb_inuse);
|
||||
|
||||
/* Done ethernet processing. Strip off the ethernet header. */
|
||||
m_adj(m, ETHER_HDR_LEN);
|
||||
switch (etype) {
|
||||
case ETHERTYPE_ARP:
|
||||
debugnet_handle_arp(&g_dnet_pcb, &m);
|
||||
break;
|
||||
case ETHERTYPE_IP:
|
||||
debugnet_handle_ip(&g_dnet_pcb, &m);
|
||||
break;
|
||||
default:
|
||||
DNETDEBUG_IF(ifp, "dropping unknown ethertype %hu\n", etype);
|
||||
break;
|
||||
}
|
||||
done:
|
||||
if (m != NULL)
|
||||
m_freem(m);
|
||||
}
|
||||
|
||||
/*
|
||||
* Network polling primitive.
|
||||
*
|
||||
* Instead of assuming that most of the network stack is sane, we just poll the
|
||||
* driver directly for packets.
|
||||
*/
|
||||
void
|
||||
debugnet_network_poll(struct ifnet *ifp)
|
||||
{
|
||||
ifp->if_debugnet_methods->dn_poll(ifp, 1000);
|
||||
}
|
||||
|
||||
/*
|
||||
* Start of consumer API surface.
|
||||
*/
|
||||
void
|
||||
debugnet_free(struct debugnet_pcb *pcb)
|
||||
{
|
||||
struct ifnet *ifp;
|
||||
|
||||
MPASS(g_debugnet_pcb_inuse);
|
||||
MPASS(pcb == &g_dnet_pcb);
|
||||
|
||||
ifp = pcb->dp_ifp;
|
||||
ifp->if_input = pcb->dp_drv_input;
|
||||
ifp->if_debugnet_methods->dn_event(ifp, DEBUGNET_END);
|
||||
debugnet_mbuf_finish();
|
||||
|
||||
g_debugnet_pcb_inuse = false;
|
||||
memset(&g_dnet_pcb, 0xfd, sizeof(g_dnet_pcb));
|
||||
}
|
||||
|
||||
int
|
||||
debugnet_connect(const struct debugnet_conn_params *dcp,
|
||||
struct debugnet_pcb **pcb_out)
|
||||
{
|
||||
struct debugnet_pcb *pcb;
|
||||
struct ifnet *ifp;
|
||||
int error;
|
||||
|
||||
if (g_debugnet_pcb_inuse) {
|
||||
printf("%s: Only one connection at a time.\n", __func__);
|
||||
return (EBUSY);
|
||||
}
|
||||
|
||||
pcb = &g_dnet_pcb;
|
||||
*pcb = (struct debugnet_pcb) {
|
||||
.dp_state = DN_STATE_INIT,
|
||||
.dp_client = dcp->dc_client,
|
||||
.dp_server = dcp->dc_server,
|
||||
.dp_gateway = dcp->dc_gateway,
|
||||
.dp_server_port = dcp->dc_herald_port, /* Initially */
|
||||
.dp_client_ack_port = dcp->dc_client_ack_port,
|
||||
.dp_seqno = 1,
|
||||
.dp_ifp = dcp->dc_ifp,
|
||||
};
|
||||
|
||||
/* Switch to the debugnet mbuf zones. */
|
||||
debugnet_mbuf_start();
|
||||
|
||||
ifp = pcb->dp_ifp;
|
||||
ifp->if_debugnet_methods->dn_event(ifp, DEBUGNET_START);
|
||||
|
||||
/*
|
||||
* We maintain the invariant that g_debugnet_pcb_inuse is always true
|
||||
* while the debugnet ifp's if_input is overridden with
|
||||
* debugnet_pkt_in.
|
||||
*/
|
||||
g_debugnet_pcb_inuse = true;
|
||||
|
||||
/* Make the card use *our* receive callback. */
|
||||
pcb->dp_drv_input = ifp->if_input;
|
||||
ifp->if_input = debugnet_pkt_in;
|
||||
|
||||
printf("%s: searching for %s MAC...\n", __func__,
|
||||
(dcp->dc_gateway == INADDR_ANY) ? "server" : "gateway");
|
||||
|
||||
error = debugnet_arp_gw(pcb);
|
||||
if (error != 0) {
|
||||
printf("%s: failed to locate MAC address\n", __func__);
|
||||
goto cleanup;
|
||||
}
|
||||
MPASS(pcb->dp_state == DN_STATE_HAVE_GW_MAC);
|
||||
|
||||
error = debugnet_send(pcb, DEBUGNET_HERALD, dcp->dc_herald_data,
|
||||
dcp->dc_herald_datalen, NULL);
|
||||
if (error != 0) {
|
||||
printf("%s: failed to herald debugnet server\n", __func__);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
*pcb_out = pcb;
|
||||
return (0);
|
||||
|
||||
cleanup:
|
||||
debugnet_free(pcb);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pre-allocated dump-time mbuf tracking.
|
||||
*
|
||||
* We just track the high water mark we've ever seen and allocate appropriately
|
||||
* for that iface/mtu combo.
|
||||
*/
|
||||
static struct {
|
||||
int nmbuf;
|
||||
int ncl;
|
||||
int clsize;
|
||||
} dn_hwm;
|
||||
static struct mtx dn_hwm_lk;
|
||||
MTX_SYSINIT(debugnet_hwm_lock, &dn_hwm_lk, "Debugnet HWM lock", MTX_DEF);
|
||||
|
||||
static void
|
||||
dn_maybe_reinit_mbufs(int nmbuf, int ncl, int clsize)
|
||||
{
|
||||
bool any;
|
||||
|
||||
any = false;
|
||||
mtx_lock(&dn_hwm_lk);
|
||||
|
||||
if (nmbuf > dn_hwm.nmbuf) {
|
||||
any = true;
|
||||
dn_hwm.nmbuf = nmbuf;
|
||||
} else
|
||||
nmbuf = dn_hwm.nmbuf;
|
||||
|
||||
if (ncl > dn_hwm.ncl) {
|
||||
any = true;
|
||||
dn_hwm.ncl = ncl;
|
||||
} else
|
||||
ncl = dn_hwm.ncl;
|
||||
|
||||
if (clsize > dn_hwm.clsize) {
|
||||
any = true;
|
||||
dn_hwm.clsize = clsize;
|
||||
} else
|
||||
clsize = dn_hwm.clsize;
|
||||
|
||||
mtx_unlock(&dn_hwm_lk);
|
||||
|
||||
if (any)
|
||||
debugnet_mbuf_reinit(nmbuf, ncl, clsize);
|
||||
}
|
||||
|
||||
void
|
||||
debugnet_any_ifnet_update(struct ifnet *ifp)
|
||||
{
|
||||
int clsize, nmbuf, ncl, nrxr;
|
||||
|
||||
if (!DEBUGNET_SUPPORTED_NIC(ifp))
|
||||
return;
|
||||
|
||||
ifp->if_debugnet_methods->dn_init(ifp, &nrxr, &ncl, &clsize);
|
||||
KASSERT(nrxr > 0, ("invalid receive ring count %d", nrxr));
|
||||
|
||||
/*
|
||||
* We need two headers per message on the transmit side. Multiply by
|
||||
* four to give us some breathing room.
|
||||
*/
|
||||
nmbuf = ncl * (4 + nrxr);
|
||||
ncl *= nrxr;
|
||||
|
||||
dn_maybe_reinit_mbufs(nmbuf, ncl, clsize);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unfortunately, the ifnet_arrival_event eventhandler hook is mostly useless
|
||||
* for us because drivers tend to if_attach before invoking DEBUGNET_SET().
|
||||
*
|
||||
* On the other hand, hooking DEBUGNET_SET() itself may still be too early,
|
||||
* because the driver is still in attach. Since we cannot use down interfaces,
|
||||
* maybe hooking ifnet_event:IFNET_EVENT_UP is sufficient? ... Nope, at least
|
||||
* with vtnet and dhcpclient that event just never occurs.
|
||||
*
|
||||
* So that's how I've landed on the lower level ifnet_link_event.
|
||||
*/
|
||||
|
||||
static void
|
||||
dn_ifnet_event(void *arg __unused, struct ifnet *ifp, int link_state)
|
||||
{
|
||||
if (link_state == LINK_STATE_UP)
|
||||
debugnet_any_ifnet_update(ifp);
|
||||
}
|
||||
|
||||
static eventhandler_tag dn_attach_cookie;
|
||||
static void
|
||||
dn_evh_init(void *ctx __unused)
|
||||
{
|
||||
dn_attach_cookie = EVENTHANDLER_REGISTER(ifnet_link_event,
|
||||
dn_ifnet_event, NULL, EVENTHANDLER_PRI_ANY);
|
||||
}
|
||||
SYSINIT(dn_evh_init, SI_SUB_EVENTHANDLER + 1, SI_ORDER_ANY, dn_evh_init, NULL);
|
211
sys/net/debugnet.h
Normal file
211
sys/net/debugnet.h
Normal file
@ -0,0 +1,211 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2019 Isilon Systems, LLC.
|
||||
* Copyright (c) 2005-2014 Sandvine Incorporated
|
||||
* Copyright (c) 2000 Darrell Anderson <anderson@cs.duke.edu>
|
||||
* 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$
|
||||
*/
|
||||
|
||||
/*
|
||||
* Debugnet provides a reliable, bidirectional, UDP-encapsulated datagram
|
||||
* transport while a machine is in a debug state. (N-1 CPUs stopped,
|
||||
* interrupts disabled, may or may not be in a panic(9) state.) Only one
|
||||
* stream may be active at a time. A dedicated server must be running to
|
||||
* accept connections.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
/*
|
||||
* Debugnet protocol details.
|
||||
*/
|
||||
#define DEBUGNET_HERALD 1 /* Connection handshake. */
|
||||
#define DEBUGNET_FINISHED 2 /* Close the connection. */
|
||||
#define DEBUGNET_DATA 3 /* Contains data. */
|
||||
|
||||
struct debugnet_msg_hdr {
|
||||
uint32_t mh_type; /* Debugnet message type. */
|
||||
uint32_t mh_seqno; /* Match acks with msgs. */
|
||||
uint64_t mh_offset; /* Offset in fragment. */
|
||||
uint32_t mh_len; /* Attached data (bytes). */
|
||||
uint32_t mh_aux2; /* Consumer-specific. */
|
||||
} __packed;
|
||||
|
||||
struct debugnet_ack {
|
||||
uint32_t da_seqno; /* Match acks with msgs. */
|
||||
} __packed;
|
||||
|
||||
#define DEBUGNET_MAX_IN_FLIGHT 64
|
||||
|
||||
#ifdef _KERNEL
|
||||
/*
|
||||
* Hook API for network drivers.
|
||||
*/
|
||||
enum debugnet_ev {
|
||||
DEBUGNET_START,
|
||||
DEBUGNET_END,
|
||||
};
|
||||
|
||||
struct ifnet;
|
||||
struct mbuf;
|
||||
typedef void debugnet_init_t(struct ifnet *, int *nrxr, int *ncl, int *clsize);
|
||||
typedef void debugnet_event_t(struct ifnet *, enum debugnet_ev);
|
||||
typedef int debugnet_transmit_t(struct ifnet *, struct mbuf *);
|
||||
typedef int debugnet_poll_t(struct ifnet *, int);
|
||||
|
||||
struct debugnet_methods {
|
||||
debugnet_init_t *dn_init;
|
||||
debugnet_event_t *dn_event;
|
||||
debugnet_transmit_t *dn_transmit;
|
||||
debugnet_poll_t *dn_poll;
|
||||
};
|
||||
|
||||
#define DEBUGNET_SUPPORTED_NIC(ifp) \
|
||||
((ifp)->if_debugnet_methods != NULL && (ifp)->if_type == IFT_ETHER)
|
||||
|
||||
/*
|
||||
* Debugnet consumer API.
|
||||
*/
|
||||
struct debugnet_conn_params {
|
||||
struct ifnet *dc_ifp;
|
||||
in_addr_t dc_client;
|
||||
in_addr_t dc_server;
|
||||
in_addr_t dc_gateway;
|
||||
|
||||
uint16_t dc_herald_port;
|
||||
uint16_t dc_client_ack_port;
|
||||
|
||||
const void *dc_herald_data;
|
||||
uint32_t dc_herald_datalen;
|
||||
};
|
||||
|
||||
struct debugnet_pcb; /* opaque */
|
||||
|
||||
/*
|
||||
* Open a unidirectional stream to the specified server's herald port.
|
||||
*
|
||||
* If all goes well, the server will send ACK from a different port to our ack
|
||||
* port. This allows servers to somewhat gracefully handle multiple debugnet
|
||||
* clients. (Clients are limited to single connections.)
|
||||
*
|
||||
* Returns zero on success, or errno.
|
||||
*/
|
||||
int debugnet_connect(const struct debugnet_conn_params *,
|
||||
struct debugnet_pcb **pcb_out);
|
||||
|
||||
/*
|
||||
* Free a debugnet stream that was previously successfully opened.
|
||||
*
|
||||
* No attempt is made to cleanly terminate communication with the remote
|
||||
* server. Consumers should first send an empty DEBUGNET_FINISHED message, or
|
||||
* otherwise let the remote know they are signing off.
|
||||
*/
|
||||
void debugnet_free(struct debugnet_pcb *);
|
||||
|
||||
/*
|
||||
* Send a message, with common debugnet_msg_hdr header, to the connected remote
|
||||
* server.
|
||||
*
|
||||
* - mhtype translates directly to mh_type (e.g., DEBUGNET_DATA, or some other
|
||||
* protocol-specific type).
|
||||
* - Data and datalen describe the attached data; datalen may be zero.
|
||||
* - If auxdata is NULL, mh_offset's initial value and mh_aux2 will be zero.
|
||||
* Otherwise, mh_offset's initial value will be auxdata->dp_offset_start and
|
||||
* mh_aux2 will have the value of auxdata->dp_aux2.
|
||||
*
|
||||
* Returns zero on success, or an errno on failure.
|
||||
*/
|
||||
struct debugnet_proto_aux {
|
||||
uint64_t dp_offset_start;
|
||||
uint32_t dp_aux2;
|
||||
};
|
||||
int debugnet_send(struct debugnet_pcb *, uint32_t mhtype, const void *data,
|
||||
uint32_t datalen, const struct debugnet_proto_aux *auxdata);
|
||||
|
||||
/*
|
||||
* A simple wrapper around the above when no data or auxdata is needed.
|
||||
*/
|
||||
static inline int
|
||||
debugnet_sendempty(struct debugnet_pcb *pcb, uint32_t mhtype)
|
||||
{
|
||||
return (debugnet_send(pcb, mhtype, NULL, 0, NULL));
|
||||
}
|
||||
|
||||
/*
|
||||
* PCB accessors.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Get the 48-bit MAC address of the discovered next hop (gateway, or
|
||||
* destination server if it is on the same segment.
|
||||
*/
|
||||
const unsigned char *debugnet_get_gw_mac(const struct debugnet_pcb *);
|
||||
|
||||
/*
|
||||
* Callbacks from core mbuf code.
|
||||
*/
|
||||
void debugnet_any_ifnet_update(struct ifnet *);
|
||||
|
||||
/* Expose sysctl variables for netdump(4) to alias. */
|
||||
extern int debugnet_npolls;
|
||||
extern int debugnet_nretries;
|
||||
extern int debugnet_arp_nretries;
|
||||
|
||||
/*
|
||||
* Conditionally-defined macros for device drivers so we can avoid ifdef
|
||||
* wrappers in every single implementation.
|
||||
*/
|
||||
#ifdef DEBUGNET
|
||||
#define DEBUGNET_DEFINE(driver) \
|
||||
static debugnet_init_t driver##_debugnet_init; \
|
||||
static debugnet_event_t driver##_debugnet_event; \
|
||||
static debugnet_transmit_t driver##_debugnet_transmit; \
|
||||
static debugnet_poll_t driver##_debugnet_poll; \
|
||||
\
|
||||
static struct debugnet_methods driver##_debugnet_methods = { \
|
||||
.dn_init = driver##_debugnet_init, \
|
||||
.dn_event = driver##_debugnet_event, \
|
||||
.dn_transmit = driver##_debugnet_transmit, \
|
||||
.dn_poll = driver##_debugnet_poll, \
|
||||
}
|
||||
|
||||
#define DEBUGNET_NOTIFY_MTU(ifp) debugnet_any_ifnet_update(ifp)
|
||||
|
||||
#define DEBUGNET_SET(ifp, driver) \
|
||||
(ifp)->if_debugnet_methods = &driver##_debugnet_methods
|
||||
|
||||
#else /* !DEBUGNET || !INET */
|
||||
|
||||
#define DEBUGNET_DEFINE(driver)
|
||||
#define DEBUGNET_NOTIFY_MTU(ifp)
|
||||
#define DEBUGNET_SET(ifp, driver)
|
||||
|
||||
#endif /* DEBUGNET && INET */
|
||||
#endif /* _KERNEL */
|
485
sys/net/debugnet_inet.c
Normal file
485
sys/net/debugnet_inet.c
Normal file
@ -0,0 +1,485 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2019 Isilon Systems, LLC.
|
||||
* Copyright (c) 2005-2014 Sandvine Incorporated. All rights reserved.
|
||||
* Copyright (c) 2000 Darrell Anderson
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "opt_inet.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/systm.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if.h>
|
||||
#include <net/if_arp.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_types.h>
|
||||
#include <net/if_var.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/in_var.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_var.h>
|
||||
#include <netinet/ip_options.h>
|
||||
#include <netinet/udp.h>
|
||||
#include <netinet/udp_var.h>
|
||||
|
||||
#include <machine/in_cksum.h>
|
||||
#include <machine/pcb.h>
|
||||
|
||||
#include <net/debugnet.h>
|
||||
#define DEBUGNET_INTERNAL
|
||||
#include <net/debugnet_int.h>
|
||||
|
||||
int debugnet_arp_nretries = 3;
|
||||
SYSCTL_INT(_net_debugnet, OID_AUTO, arp_nretries, CTLFLAG_RWTUN,
|
||||
&debugnet_arp_nretries, 0,
|
||||
"Number of ARP attempts before giving up");
|
||||
|
||||
/*
|
||||
* Handler for IP packets: checks their sanity and then processes any debugnet
|
||||
* ACK packets it finds.
|
||||
*
|
||||
* It needs to partially replicate the behaviour of ip_input() and udp_input().
|
||||
*
|
||||
* Parameters:
|
||||
* pcb a pointer to the live debugnet PCB
|
||||
* mb a pointer to an mbuf * containing the packet received
|
||||
* Updates *mb if m_pullup et al change the pointer
|
||||
* Assumes the calling function will take care of freeing the mbuf
|
||||
*/
|
||||
void
|
||||
debugnet_handle_ip(struct debugnet_pcb *pcb, struct mbuf **mb)
|
||||
{
|
||||
struct ip *ip;
|
||||
struct mbuf *m;
|
||||
unsigned short hlen;
|
||||
|
||||
/* IP processing. */
|
||||
m = *mb;
|
||||
if (m->m_pkthdr.len < sizeof(struct ip)) {
|
||||
DNETDEBUG("dropping packet too small for IP header\n");
|
||||
return;
|
||||
}
|
||||
if (m->m_len < sizeof(struct ip)) {
|
||||
m = m_pullup(m, sizeof(struct ip));
|
||||
*mb = m;
|
||||
if (m == NULL) {
|
||||
DNETDEBUG("m_pullup failed\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
ip = mtod(m, struct ip *);
|
||||
|
||||
/* IP version. */
|
||||
if (ip->ip_v != IPVERSION) {
|
||||
DNETDEBUG("bad IP version %d\n", ip->ip_v);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Header length. */
|
||||
hlen = ip->ip_hl << 2;
|
||||
if (hlen < sizeof(struct ip)) {
|
||||
DNETDEBUG("bad IP header length (%hu)\n", hlen);
|
||||
return;
|
||||
}
|
||||
if (hlen > m->m_len) {
|
||||
m = m_pullup(m, hlen);
|
||||
*mb = m;
|
||||
if (m == NULL) {
|
||||
DNETDEBUG("m_pullup failed\n");
|
||||
return;
|
||||
}
|
||||
ip = mtod(m, struct ip *);
|
||||
}
|
||||
/* Ignore packets with IP options. */
|
||||
if (hlen > sizeof(struct ip)) {
|
||||
DNETDEBUG("drop packet with IP options\n");
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef INVARIANTS
|
||||
if ((IN_LOOPBACK(ntohl(ip->ip_dst.s_addr)) ||
|
||||
IN_LOOPBACK(ntohl(ip->ip_src.s_addr))) &&
|
||||
(m->m_pkthdr.rcvif->if_flags & IFF_LOOPBACK) == 0) {
|
||||
DNETDEBUG("Bad IP header (RFC1122)\n");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Checksum. */
|
||||
if ((m->m_pkthdr.csum_flags & CSUM_IP_CHECKED) != 0) {
|
||||
if ((m->m_pkthdr.csum_flags & CSUM_IP_VALID) == 0) {
|
||||
DNETDEBUG("bad IP checksum\n");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
/* XXX */ ;
|
||||
}
|
||||
|
||||
/* Convert fields to host byte order. */
|
||||
ip->ip_len = ntohs(ip->ip_len);
|
||||
if (ip->ip_len < hlen) {
|
||||
DNETDEBUG("IP packet smaller (%hu) than header (%hu)\n",
|
||||
ip->ip_len, hlen);
|
||||
return;
|
||||
}
|
||||
if (m->m_pkthdr.len < ip->ip_len) {
|
||||
DNETDEBUG("IP packet bigger (%hu) than ethernet packet (%d)\n",
|
||||
ip->ip_len, m->m_pkthdr.len);
|
||||
return;
|
||||
}
|
||||
if (m->m_pkthdr.len > ip->ip_len) {
|
||||
|
||||
/* Truncate the packet to the IP length. */
|
||||
if (m->m_len == m->m_pkthdr.len) {
|
||||
m->m_len = ip->ip_len;
|
||||
m->m_pkthdr.len = ip->ip_len;
|
||||
} else
|
||||
m_adj(m, ip->ip_len - m->m_pkthdr.len);
|
||||
}
|
||||
|
||||
ip->ip_off = ntohs(ip->ip_off);
|
||||
|
||||
/* Check that the source is the server's IP. */
|
||||
if (ip->ip_src.s_addr != pcb->dp_server) {
|
||||
DNETDEBUG("drop packet not from server (from 0x%x)\n",
|
||||
ip->ip_src.s_addr);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Check if the destination IP is ours. */
|
||||
if (ip->ip_dst.s_addr != pcb->dp_client) {
|
||||
DNETDEBUGV("drop packet not to our IP\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (ip->ip_p != IPPROTO_UDP) {
|
||||
DNETDEBUG("drop non-UDP packet\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Do not deal with fragments. */
|
||||
if ((ip->ip_off & (IP_MF | IP_OFFMASK)) != 0) {
|
||||
DNETDEBUG("drop fragmented packet\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* UDP custom is to have packet length not include IP header. */
|
||||
ip->ip_len -= hlen;
|
||||
|
||||
/* Checked above before decoding IP header. */
|
||||
MPASS(m->m_pkthdr.len >= sizeof(struct ipovly));
|
||||
|
||||
/* Put the UDP header at start of chain. */
|
||||
m_adj(m, sizeof(struct ipovly));
|
||||
debugnet_handle_udp(pcb, mb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Builds and sends a single ARP request to locate the L2 address for a given
|
||||
* INET address.
|
||||
*
|
||||
* Return value:
|
||||
* 0 on success
|
||||
* errno on error
|
||||
*/
|
||||
static int
|
||||
debugnet_send_arp(struct debugnet_pcb *pcb, in_addr_t dst)
|
||||
{
|
||||
struct ether_addr bcast;
|
||||
struct arphdr *ah;
|
||||
struct ifnet *ifp;
|
||||
struct mbuf *m;
|
||||
int pktlen;
|
||||
|
||||
ifp = pcb->dp_ifp;
|
||||
|
||||
/* Fill-up a broadcast address. */
|
||||
memset(&bcast, 0xFF, ETHER_ADDR_LEN);
|
||||
m = m_gethdr(M_NOWAIT, MT_DATA);
|
||||
if (m == NULL) {
|
||||
printf("%s: Out of mbufs\n", __func__);
|
||||
return (ENOBUFS);
|
||||
}
|
||||
pktlen = arphdr_len2(ETHER_ADDR_LEN, sizeof(struct in_addr));
|
||||
m->m_len = pktlen;
|
||||
m->m_pkthdr.len = pktlen;
|
||||
MH_ALIGN(m, pktlen);
|
||||
ah = mtod(m, struct arphdr *);
|
||||
ah->ar_hrd = htons(ARPHRD_ETHER);
|
||||
ah->ar_pro = htons(ETHERTYPE_IP);
|
||||
ah->ar_hln = ETHER_ADDR_LEN;
|
||||
ah->ar_pln = sizeof(struct in_addr);
|
||||
ah->ar_op = htons(ARPOP_REQUEST);
|
||||
memcpy(ar_sha(ah), IF_LLADDR(ifp), ETHER_ADDR_LEN);
|
||||
((struct in_addr *)ar_spa(ah))->s_addr = pcb->dp_client;
|
||||
bzero(ar_tha(ah), ETHER_ADDR_LEN);
|
||||
((struct in_addr *)ar_tpa(ah))->s_addr = dst;
|
||||
return (debugnet_ether_output(m, ifp, bcast, ETHERTYPE_ARP));
|
||||
}
|
||||
|
||||
/*
|
||||
* Handler for ARP packets: checks their sanity and then
|
||||
* 1. If the ARP is a request for our IP, respond with our MAC address
|
||||
* 2. If the ARP is a response from our server, record its MAC address
|
||||
*
|
||||
* It needs to replicate partially the behaviour of arpintr() and
|
||||
* in_arpinput().
|
||||
*
|
||||
* Parameters:
|
||||
* pcb a pointer to the live debugnet PCB
|
||||
* mb a pointer to an mbuf * containing the packet received
|
||||
* Updates *mb if m_pullup et al change the pointer
|
||||
* Assumes the calling function will take care of freeing the mbuf
|
||||
*/
|
||||
void
|
||||
debugnet_handle_arp(struct debugnet_pcb *pcb, struct mbuf **mb)
|
||||
{
|
||||
char buf[INET_ADDRSTRLEN];
|
||||
struct in_addr isaddr, itaddr;
|
||||
struct ether_addr dst;
|
||||
struct mbuf *m;
|
||||
struct arphdr *ah;
|
||||
struct ifnet *ifp;
|
||||
uint8_t *enaddr;
|
||||
int req_len, op;
|
||||
|
||||
m = *mb;
|
||||
ifp = m->m_pkthdr.rcvif;
|
||||
if (m->m_len < sizeof(struct arphdr)) {
|
||||
m = m_pullup(m, sizeof(struct arphdr));
|
||||
*mb = m;
|
||||
if (m == NULL) {
|
||||
DNETDEBUG("runt packet: m_pullup failed\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ah = mtod(m, struct arphdr *);
|
||||
if (ntohs(ah->ar_hrd) != ARPHRD_ETHER) {
|
||||
DNETDEBUG("unknown hardware address 0x%2D)\n",
|
||||
(unsigned char *)&ah->ar_hrd, "");
|
||||
return;
|
||||
}
|
||||
if (ntohs(ah->ar_pro) != ETHERTYPE_IP) {
|
||||
DNETDEBUG("drop ARP for unknown protocol %d\n",
|
||||
ntohs(ah->ar_pro));
|
||||
return;
|
||||
}
|
||||
req_len = arphdr_len2(ifp->if_addrlen, sizeof(struct in_addr));
|
||||
if (m->m_len < req_len) {
|
||||
m = m_pullup(m, req_len);
|
||||
*mb = m;
|
||||
if (m == NULL) {
|
||||
DNETDEBUG("runt packet: m_pullup failed\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
ah = mtod(m, struct arphdr *);
|
||||
|
||||
op = ntohs(ah->ar_op);
|
||||
memcpy(&isaddr, ar_spa(ah), sizeof(isaddr));
|
||||
memcpy(&itaddr, ar_tpa(ah), sizeof(itaddr));
|
||||
enaddr = (uint8_t *)IF_LLADDR(ifp);
|
||||
|
||||
if (memcmp(ar_sha(ah), enaddr, ifp->if_addrlen) == 0) {
|
||||
DNETDEBUG("ignoring ARP from myself\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (isaddr.s_addr == pcb->dp_client) {
|
||||
printf("%s: %*D is using my IP address %s!\n", __func__,
|
||||
ifp->if_addrlen, (u_char *)ar_sha(ah), ":",
|
||||
inet_ntoa_r(isaddr, buf));
|
||||
return;
|
||||
}
|
||||
|
||||
if (memcmp(ar_sha(ah), ifp->if_broadcastaddr, ifp->if_addrlen) == 0) {
|
||||
DNETDEBUG("ignoring ARP from broadcast address\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (op == ARPOP_REPLY) {
|
||||
if (isaddr.s_addr != pcb->dp_gateway &&
|
||||
isaddr.s_addr != pcb->dp_server) {
|
||||
inet_ntoa_r(isaddr, buf);
|
||||
DNETDEBUG("ignoring ARP reply from %s (not configured"
|
||||
" server or gateway)\n", buf);
|
||||
return;
|
||||
}
|
||||
memcpy(pcb->dp_gw_mac.octet, ar_sha(ah),
|
||||
min(ah->ar_hln, ETHER_ADDR_LEN));
|
||||
|
||||
DNETDEBUG("got server MAC address %6D\n",
|
||||
pcb->dp_gw_mac.octet, ":");
|
||||
|
||||
MPASS(pcb->dp_state == DN_STATE_INIT);
|
||||
pcb->dp_state = DN_STATE_HAVE_GW_MAC;
|
||||
return;
|
||||
}
|
||||
|
||||
if (op != ARPOP_REQUEST) {
|
||||
DNETDEBUG("ignoring ARP non-request/reply\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (itaddr.s_addr != pcb->dp_client) {
|
||||
DNETDEBUG("ignoring ARP not to our IP\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln);
|
||||
memcpy(ar_sha(ah), enaddr, ah->ar_hln);
|
||||
memcpy(ar_tpa(ah), ar_spa(ah), ah->ar_pln);
|
||||
memcpy(ar_spa(ah), &itaddr, ah->ar_pln);
|
||||
ah->ar_op = htons(ARPOP_REPLY);
|
||||
ah->ar_pro = htons(ETHERTYPE_IP);
|
||||
m->m_flags &= ~(M_BCAST|M_MCAST);
|
||||
m->m_len = arphdr_len(ah);
|
||||
m->m_pkthdr.len = m->m_len;
|
||||
|
||||
memcpy(dst.octet, ar_tha(ah), ETHER_ADDR_LEN);
|
||||
debugnet_ether_output(m, ifp, dst, ETHERTYPE_ARP);
|
||||
*mb = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sends ARP requests to locate the server and waits for a response.
|
||||
* We first try to ARP the server itself, and fall back to the provided
|
||||
* gateway if the server appears to be off-link.
|
||||
*
|
||||
* Return value:
|
||||
* 0 on success
|
||||
* errno on error
|
||||
*/
|
||||
int
|
||||
debugnet_arp_gw(struct debugnet_pcb *pcb)
|
||||
{
|
||||
in_addr_t dst;
|
||||
int error, polls, retries;
|
||||
|
||||
dst = pcb->dp_server;
|
||||
restart:
|
||||
for (retries = 0; retries < debugnet_arp_nretries; retries++) {
|
||||
error = debugnet_send_arp(pcb, dst);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
for (polls = 0; polls < debugnet_npolls &&
|
||||
pcb->dp_state < DN_STATE_HAVE_GW_MAC; polls++) {
|
||||
debugnet_network_poll(pcb->dp_ifp);
|
||||
DELAY(500);
|
||||
}
|
||||
if (pcb->dp_state >= DN_STATE_HAVE_GW_MAC)
|
||||
break;
|
||||
printf("(ARP retry)");
|
||||
}
|
||||
if (pcb->dp_state >= DN_STATE_HAVE_GW_MAC)
|
||||
return (0);
|
||||
if (dst == pcb->dp_server) {
|
||||
printf("\nFailed to ARP server");
|
||||
if (pcb->dp_gateway != INADDR_ANY) {
|
||||
printf(", trying to reach gateway...\n");
|
||||
dst = pcb->dp_gateway;
|
||||
goto restart;
|
||||
} else
|
||||
printf(".\n");
|
||||
} else
|
||||
printf("\nFailed to ARP gateway.\n");
|
||||
|
||||
return (ETIMEDOUT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Unreliable IPv4 transmission of an mbuf chain to the debugnet server
|
||||
* Note: can't handle fragmentation; fails if the packet is larger than
|
||||
* ifp->if_mtu after adding the UDP/IP headers
|
||||
*
|
||||
* Parameters:
|
||||
* pcb The debugnet context block
|
||||
* m mbuf chain
|
||||
*
|
||||
* Returns:
|
||||
* int see errno.h, 0 for success
|
||||
*/
|
||||
int
|
||||
debugnet_ip_output(struct debugnet_pcb *pcb, struct mbuf *m)
|
||||
{
|
||||
struct udphdr *udp;
|
||||
struct ifnet *ifp;
|
||||
struct ip *ip;
|
||||
|
||||
MPASS(pcb->dp_state >= DN_STATE_HAVE_GW_MAC);
|
||||
|
||||
ifp = pcb->dp_ifp;
|
||||
|
||||
M_PREPEND(m, sizeof(*ip), M_NOWAIT);
|
||||
if (m == NULL) {
|
||||
printf("%s: out of mbufs\n", __func__);
|
||||
return (ENOBUFS);
|
||||
}
|
||||
|
||||
if (m->m_pkthdr.len > ifp->if_mtu) {
|
||||
printf("%s: Packet is too big: %d > MTU %u\n", __func__,
|
||||
m->m_pkthdr.len, ifp->if_mtu);
|
||||
m_freem(m);
|
||||
return (ENOBUFS);
|
||||
}
|
||||
|
||||
ip = mtod(m, void *);
|
||||
udp = (void *)(ip + 1);
|
||||
|
||||
memset(ip, 0, offsetof(struct ip, ip_p));
|
||||
ip->ip_p = IPPROTO_UDP;
|
||||
ip->ip_sum = udp->uh_ulen;
|
||||
ip->ip_src = (struct in_addr) { pcb->dp_client };
|
||||
ip->ip_dst = (struct in_addr) { pcb->dp_server };
|
||||
|
||||
/* Compute UDP-IPv4 checksum. */
|
||||
udp->uh_sum = in_cksum(m, m->m_pkthdr.len);
|
||||
if (udp->uh_sum == 0)
|
||||
udp->uh_sum = 0xffff;
|
||||
|
||||
ip->ip_v = IPVERSION;
|
||||
ip->ip_hl = sizeof(*ip) >> 2;
|
||||
ip->ip_tos = 0;
|
||||
ip->ip_len = htons(m->m_pkthdr.len);
|
||||
ip->ip_id = 0;
|
||||
ip->ip_off = htons(IP_DF);
|
||||
ip->ip_ttl = 255;
|
||||
ip->ip_sum = 0;
|
||||
ip->ip_sum = in_cksum(m, sizeof(struct ip));
|
||||
|
||||
return (debugnet_ether_output(m, ifp, pcb->dp_gw_mac, ETHERTYPE_IP));
|
||||
}
|
91
sys/net/debugnet_int.h
Normal file
91
sys/net/debugnet_int.h
Normal file
@ -0,0 +1,91 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2019 Isilon Systems, LLC.
|
||||
*
|
||||
* 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$
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef DEBUGNET_INTERNAL
|
||||
#error "Don't include this"
|
||||
#endif
|
||||
|
||||
#define DNETDEBUG(f, ...) do { \
|
||||
if (debugnet_debug > 0) \
|
||||
printf(("%s: " f), __func__, ## __VA_ARGS__); \
|
||||
} while (0)
|
||||
#define DNETDEBUG_IF(i, f, ...) do { \
|
||||
if (debugnet_debug > 0) \
|
||||
if_printf((i), ("%s: " f), __func__, ## __VA_ARGS__); \
|
||||
} while (0)
|
||||
#define DNETDEBUGV(f, ...) do { \
|
||||
if (debugnet_debug > 1) \
|
||||
printf(("%s: " f), __func__, ## __VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
enum dnet_pcb_st {
|
||||
DN_STATE_INIT = 1,
|
||||
DN_STATE_HAVE_GW_MAC,
|
||||
DN_STATE_GOT_HERALD_PORT,
|
||||
};
|
||||
|
||||
struct debugnet_pcb {
|
||||
uint64_t dp_rcvd_acks;
|
||||
|
||||
in_addr_t dp_client;
|
||||
in_addr_t dp_server;
|
||||
in_addr_t dp_gateway;
|
||||
uint32_t dp_seqno;
|
||||
|
||||
struct ether_addr dp_gw_mac;
|
||||
uint16_t dp_server_port;
|
||||
|
||||
struct ifnet *dp_ifp;
|
||||
/* Saved driver if_input to restore on close. */
|
||||
void (*dp_drv_input)(struct ifnet *, struct mbuf *);
|
||||
|
||||
enum dnet_pcb_st dp_state;
|
||||
uint16_t dp_client_ack_port;
|
||||
};
|
||||
|
||||
/* TODO(CEM): Obviate this assertion by using a BITSET(9) for acks. */
|
||||
CTASSERT(sizeof(((struct debugnet_pcb *)0)->dp_rcvd_acks) * NBBY >=
|
||||
DEBUGNET_MAX_IN_FLIGHT);
|
||||
|
||||
extern unsigned debugnet_debug;
|
||||
SYSCTL_DECL(_net_debugnet);
|
||||
|
||||
int debugnet_ether_output(struct mbuf *, struct ifnet *, struct ether_addr,
|
||||
u_short);
|
||||
void debugnet_handle_udp(struct debugnet_pcb *, struct mbuf **);
|
||||
void debugnet_network_poll(struct ifnet *);
|
||||
|
||||
#ifdef INET
|
||||
int debugnet_arp_gw(struct debugnet_pcb *);
|
||||
void debugnet_handle_arp(struct debugnet_pcb *, struct mbuf **);
|
||||
void debugnet_handle_ip(struct debugnet_pcb *, struct mbuf **);
|
||||
int debugnet_ip_output(struct debugnet_pcb *, struct mbuf *);
|
||||
#endif
|
@ -88,8 +88,8 @@
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/ip_carp.h>
|
||||
#ifdef INET
|
||||
#include <net/debugnet.h>
|
||||
#include <netinet/if_ether.h>
|
||||
#include <netinet/netdump/netdump.h>
|
||||
#endif /* INET */
|
||||
#ifdef INET6
|
||||
#include <netinet6/in6_var.h>
|
||||
@ -2787,7 +2787,7 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
|
||||
getmicrotime(&ifp->if_lastchange);
|
||||
rt_ifmsg(ifp);
|
||||
#ifdef INET
|
||||
NETDUMP_REINIT(ifp);
|
||||
DEBUGNET_NOTIFY_MTU(ifp);
|
||||
#endif
|
||||
}
|
||||
/*
|
||||
|
@ -70,7 +70,7 @@ struct route; /* if_output */
|
||||
struct vnet;
|
||||
struct ifmedia;
|
||||
struct netmap_adapter;
|
||||
struct netdump_methods;
|
||||
struct debugnet_methods;
|
||||
|
||||
#ifdef _KERNEL
|
||||
#include <sys/_eventhandler.h>
|
||||
@ -417,9 +417,9 @@ struct ifnet {
|
||||
uint8_t if_pcp;
|
||||
|
||||
/*
|
||||
* Netdump hooks to be called while dumping.
|
||||
* Debugnet (Netdump) hooks to be called while in db/panic.
|
||||
*/
|
||||
struct netdump_methods *if_netdump_methods;
|
||||
struct debugnet_methods *if_debugnet_methods;
|
||||
struct epoch_context if_epoch_ctx;
|
||||
|
||||
/*
|
||||
|
@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <net/bpf.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <net/mp_ring.h>
|
||||
#include <net/debugnet.h>
|
||||
#include <net/pfil.h>
|
||||
#include <net/vnet.h>
|
||||
|
||||
@ -71,7 +72,6 @@ __FBSDID("$FreeBSD$");
|
||||
#include <netinet/ip6.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/ip_var.h>
|
||||
#include <netinet/netdump/netdump.h>
|
||||
#include <netinet6/ip6_var.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
@ -726,7 +726,7 @@ static struct mtx cpu_offset_mtx;
|
||||
MTX_SYSINIT(iflib_cpu_offset, &cpu_offset_mtx, "iflib_cpu_offset lock",
|
||||
MTX_DEF);
|
||||
|
||||
NETDUMP_DEFINE(iflib);
|
||||
DEBUGNET_DEFINE(iflib);
|
||||
|
||||
#ifdef DEV_NETMAP
|
||||
#include <sys/selinfo.h>
|
||||
@ -4775,7 +4775,7 @@ iflib_device_register(device_t dev, void *sc, if_shared_ctx_t sctx, if_ctx_t *ct
|
||||
}
|
||||
*ctxp = ctx;
|
||||
|
||||
NETDUMP_SET(ctx->ifc_ifp, iflib);
|
||||
DEBUGNET_SET(ctx->ifc_ifp, iflib);
|
||||
|
||||
if_setgetcounterfn(ctx->ifc_ifp, iflib_if_get_counter);
|
||||
iflib_add_device_sysctl_post(ctx);
|
||||
@ -6719,9 +6719,9 @@ iflib_fixup_rx(struct mbuf *m)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef NETDUMP
|
||||
#ifdef DEBUGNET
|
||||
static void
|
||||
iflib_netdump_init(if_t ifp, int *nrxr, int *ncl, int *clsize)
|
||||
iflib_debugnet_init(if_t ifp, int *nrxr, int *ncl, int *clsize)
|
||||
{
|
||||
if_ctx_t ctx;
|
||||
|
||||
@ -6734,7 +6734,7 @@ iflib_netdump_init(if_t ifp, int *nrxr, int *ncl, int *clsize)
|
||||
}
|
||||
|
||||
static void
|
||||
iflib_netdump_event(if_t ifp, enum netdump_ev event)
|
||||
iflib_debugnet_event(if_t ifp, enum debugnet_ev event)
|
||||
{
|
||||
if_ctx_t ctx;
|
||||
if_softc_ctx_t scctx;
|
||||
@ -6746,7 +6746,7 @@ iflib_netdump_event(if_t ifp, enum netdump_ev event)
|
||||
scctx = &ctx->ifc_softc_ctx;
|
||||
|
||||
switch (event) {
|
||||
case NETDUMP_START:
|
||||
case DEBUGNET_START:
|
||||
for (i = 0; i < scctx->isc_nrxqsets; i++) {
|
||||
rxq = &ctx->ifc_rxqs[i];
|
||||
for (j = 0; j < rxq->ifr_nfl; j++) {
|
||||
@ -6762,7 +6762,7 @@ iflib_netdump_event(if_t ifp, enum netdump_ev event)
|
||||
}
|
||||
|
||||
static int
|
||||
iflib_netdump_transmit(if_t ifp, struct mbuf *m)
|
||||
iflib_debugnet_transmit(if_t ifp, struct mbuf *m)
|
||||
{
|
||||
if_ctx_t ctx;
|
||||
iflib_txq_t txq;
|
||||
@ -6781,7 +6781,7 @@ iflib_netdump_transmit(if_t ifp, struct mbuf *m)
|
||||
}
|
||||
|
||||
static int
|
||||
iflib_netdump_poll(if_t ifp, int count)
|
||||
iflib_debugnet_poll(if_t ifp, int count)
|
||||
{
|
||||
if_ctx_t ctx;
|
||||
if_softc_ctx_t scctx;
|
||||
@ -6802,4 +6802,4 @@ iflib_netdump_poll(if_t ifp, int count)
|
||||
(void)iflib_rxeof(&ctx->ifc_rxqs[i], 16 /* XXX */);
|
||||
return (0);
|
||||
}
|
||||
#endif /* NETDUMP */
|
||||
#endif /* DEBUGNET */
|
||||
|
@ -37,28 +37,25 @@
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
/* Netdump wire protocol definitions are consumed by the ftp/netdumpd port. */
|
||||
#define NETDUMP_PORT 20023 /* Server UDP port for heralds. */
|
||||
#define NETDUMP_ACKPORT 20024 /* Client UDP port for acks. */
|
||||
|
||||
#define NETDUMP_HERALD 1 /* Broadcast before starting a dump. */
|
||||
#define NETDUMP_FINISHED 2 /* Send after finishing a dump. */
|
||||
#define NETDUMP_VMCORE 3 /* Contains dump data. */
|
||||
#define NETDUMP_HERALD DEBUGNET_HERALD
|
||||
#define NETDUMP_FINISHED DEBUGNET_FINISHED
|
||||
#define NETDUMP_VMCORE DEBUGNET_DATA
|
||||
#define NETDUMP_KDH 4 /* Contains kernel dump header. */
|
||||
#define NETDUMP_EKCD_KEY 5 /* Contains kernel dump key. */
|
||||
|
||||
#define NETDUMP_DATASIZE 4096 /* Arbitrary packet size limit. */
|
||||
|
||||
struct netdump_msg_hdr {
|
||||
uint32_t mh_type; /* Netdump message type. */
|
||||
uint32_t mh_seqno; /* Match acks with msgs. */
|
||||
uint64_t mh_offset; /* vmcore offset (bytes). */
|
||||
uint32_t mh_len; /* Attached data (bytes). */
|
||||
uint32_t mh__pad;
|
||||
} __packed;
|
||||
|
||||
struct netdump_ack {
|
||||
uint32_t na_seqno; /* Match acks with msgs. */
|
||||
} __packed;
|
||||
/* For netdumpd. */
|
||||
#ifndef _KERNEL
|
||||
#define netdump_msg_hdr debugnet_msg_hdr
|
||||
#define mh__pad mh_aux2
|
||||
#define netdump_ack debugnet_ack
|
||||
#define na_seqno da_seqno
|
||||
#endif /* !_KERNEL */
|
||||
|
||||
struct netdump_conf_freebsd12 {
|
||||
struct diocskerneldump_arg_freebsd12 ndc12_kda;
|
||||
@ -73,58 +70,4 @@ struct netdump_conf_freebsd12 {
|
||||
|
||||
#define _PATH_NETDUMP "/dev/netdump"
|
||||
|
||||
#ifdef _KERNEL
|
||||
#ifdef NETDUMP
|
||||
|
||||
#define NETDUMP_MAX_IN_FLIGHT 64
|
||||
|
||||
enum netdump_ev {
|
||||
NETDUMP_START,
|
||||
NETDUMP_END,
|
||||
};
|
||||
|
||||
struct ifnet;
|
||||
struct mbuf;
|
||||
|
||||
void netdump_reinit(struct ifnet *);
|
||||
|
||||
typedef void netdump_init_t(struct ifnet *, int *nrxr, int *ncl, int *clsize);
|
||||
typedef void netdump_event_t(struct ifnet *, enum netdump_ev);
|
||||
typedef int netdump_transmit_t(struct ifnet *, struct mbuf *);
|
||||
typedef int netdump_poll_t(struct ifnet *, int);
|
||||
|
||||
struct netdump_methods {
|
||||
netdump_init_t *nd_init;
|
||||
netdump_event_t *nd_event;
|
||||
netdump_transmit_t *nd_transmit;
|
||||
netdump_poll_t *nd_poll;
|
||||
};
|
||||
|
||||
#define NETDUMP_DEFINE(driver) \
|
||||
static netdump_init_t driver##_netdump_init; \
|
||||
static netdump_event_t driver##_netdump_event; \
|
||||
static netdump_transmit_t driver##_netdump_transmit; \
|
||||
static netdump_poll_t driver##_netdump_poll; \
|
||||
\
|
||||
static struct netdump_methods driver##_netdump_methods = { \
|
||||
.nd_init = driver##_netdump_init, \
|
||||
.nd_event = driver##_netdump_event, \
|
||||
.nd_transmit = driver##_netdump_transmit, \
|
||||
.nd_poll = driver##_netdump_poll, \
|
||||
}
|
||||
|
||||
#define NETDUMP_REINIT(ifp) netdump_reinit(ifp)
|
||||
|
||||
#define NETDUMP_SET(ifp, driver) \
|
||||
(ifp)->if_netdump_methods = &driver##_netdump_methods
|
||||
|
||||
#else /* !NETDUMP */
|
||||
|
||||
#define NETDUMP_DEFINE(driver)
|
||||
#define NETDUMP_REINIT(ifp)
|
||||
#define NETDUMP_SET(ifp, driver)
|
||||
|
||||
#endif /* NETDUMP */
|
||||
#endif /* _KERNEL */
|
||||
|
||||
#endif /* _NETINET_NETDUMP_H_ */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -104,6 +104,7 @@ options VERBOSE_SYSINIT=0 # Support debug.verbose_sysinit, off by default
|
||||
options EKCD # Support for encrypted kernel dumps
|
||||
options GZIO # gzip-compressed kernel and user dumps
|
||||
options ZSTDIO # zstd-compressed kernel and user dumps
|
||||
options DEBUGNET # debugnet networking
|
||||
options NETDUMP # netdump(4) client support
|
||||
|
||||
# Make an SMP-capable kernel by default
|
||||
|
@ -110,6 +110,7 @@ options VERBOSE_SYSINIT=0 # Support debug.verbose_sysinit, off by default
|
||||
options EKCD # Support for encrypted kernel dumps
|
||||
options GZIO # gzip-compressed kernel and user dumps
|
||||
options ZSTDIO # zstd-compressed kernel and user dumps
|
||||
options DEBUGNET # debugnet networking
|
||||
options NETDUMP # netdump(4) client support
|
||||
|
||||
# Make an SMP-capable kernel by default
|
||||
|
@ -94,6 +94,7 @@ options VERBOSE_SYSINIT=0 # Support debug.verbose_sysinit, off by default
|
||||
options EKCD # Support for encrypted kernel dumps
|
||||
options GZIO # gzip-compressed kernel and user dumps
|
||||
options ZSTDIO # zstd-compressed kernel and user dumps
|
||||
options DEBUGNET # debugnet networking
|
||||
options NETDUMP # netdump(4) client support
|
||||
|
||||
# Make an SMP-capable kernel by default
|
||||
|
@ -1501,11 +1501,12 @@ mbuf_tstmp2timespec(struct mbuf *m, struct timespec *ts)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef NETDUMP
|
||||
/* Invoked from the netdump client code. */
|
||||
void netdump_mbuf_drain(void);
|
||||
void netdump_mbuf_dump(void);
|
||||
void netdump_mbuf_reinit(int nmbuf, int nclust, int clsize);
|
||||
#ifdef DEBUGNET
|
||||
/* Invoked from the debugnet client code. */
|
||||
void debugnet_mbuf_drain(void);
|
||||
void debugnet_mbuf_start(void);
|
||||
void debugnet_mbuf_finish(void);
|
||||
void debugnet_mbuf_reinit(int nmbuf, int nclust, int clsize);
|
||||
#endif
|
||||
|
||||
static inline bool
|
||||
|
@ -60,7 +60,7 @@
|
||||
* in the range 5 to 9.
|
||||
*/
|
||||
#undef __FreeBSD_version
|
||||
#define __FreeBSD_version 1300050 /* Master, propagated to newvers */
|
||||
#define __FreeBSD_version 1300051 /* Master, propagated to newvers */
|
||||
|
||||
/*
|
||||
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
|
||||
|
Loading…
Reference in New Issue
Block a user