Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F110075241
D21421.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
105 KB
Referenced Files
None
Subscribers
None
D21421.diff
View Options
Index: sys/amd64/conf/GENERIC
===================================================================
--- sys/amd64/conf/GENERIC
+++ sys/amd64/conf/GENERIC
@@ -111,6 +111,7 @@
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
Index: sys/arm64/conf/GENERIC
===================================================================
--- sys/arm64/conf/GENERIC
+++ sys/arm64/conf/GENERIC
@@ -103,6 +103,7 @@
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
Index: sys/conf/NOTES
===================================================================
--- sys/conf/NOTES
+++ sys/conf/NOTES
@@ -1042,6 +1042,10 @@
# 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
Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -4079,6 +4079,8 @@
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
Index: sys/conf/options
===================================================================
--- sys/conf/options
+++ sys/conf/options
@@ -321,6 +321,8 @@
# 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
Index: sys/dev/alc/if_alc.c
===================================================================
--- sys/dev/alc/if_alc.c
+++ sys/dev/alc/if_alc.c
@@ -50,6 +50,7 @@
#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 @@
#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_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 @@
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 @@
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 @@
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 @@
}
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_txeof(sc);
return (alc_rxintr(sc, count));
}
-#endif /* NETDUMP */
+#endif /* DEBUGNET */
Index: sys/dev/bge/if_bge.c
===================================================================
--- sys/dev/bge/if_bge.c
+++ sys/dev/bge/if_bge.c
@@ -84,6 +84,7 @@
#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 @@
#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 @@
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 @@
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 @@
}
}
-#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 @@
}
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 @@
}
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_txeof(sc, tx_cons);
return (0);
}
-#endif /* NETDUMP */
+#endif /* DEBUGNET */
Index: sys/dev/bxe/bxe.h
===================================================================
--- sys/dev/bxe/bxe.h
+++ sys/dev/bxe/bxe.h
@@ -55,6 +55,7 @@
#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 @@
#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>
Index: sys/dev/bxe/bxe.c
===================================================================
--- sys/dev/bxe/bxe.c
+++ sys/dev/bxe/bxe.c
@@ -237,7 +237,7 @@
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 @@
/* 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 @@
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 @@
}
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 @@
(void)bxe_txeof(sc, &sc->fp[0]);
return (0);
}
-#endif /* NETDUMP */
+#endif /* DEBUGNET */
Index: sys/dev/cxgb/cxgb_adapter.h
===================================================================
--- sys/dev/cxgb/cxgb_adapter.h
+++ sys/dev/cxgb/cxgb_adapter.h
@@ -578,10 +578,10 @@
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
Index: sys/dev/cxgb/cxgb_main.c
===================================================================
--- sys/dev/cxgb/cxgb_main.c
+++ sys/dev/cxgb/cxgb_main.c
@@ -58,6 +58,7 @@
#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 @@
#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 @@
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 @@
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 @@
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 @@
}
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 @@
}
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 @@
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 @@
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 */
Index: sys/dev/cxgb/cxgb_sge.c
===================================================================
--- sys/dev/cxgb/cxgb_sge.c
+++ sys/dev/cxgb/cxgb_sge.c
@@ -390,9 +390,9 @@
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 @@
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 @@
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));
Index: sys/dev/mlx4/mlx4_en/en.h
===================================================================
--- sys/dev/mlx4/mlx4_en/en.h
+++ sys/dev/mlx4/mlx4_en/en.h
@@ -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>
Index: sys/dev/mlx4/mlx4_en/mlx4_en_netdev.c
===================================================================
--- sys/dev/mlx4/mlx4_en/mlx4_en_netdev.c
+++ sys/dev/mlx4/mlx4_en/mlx4_en_netdev.c
@@ -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);
@@ -2307,7 +2307,7 @@
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);
@@ -2891,27 +2891,27 @@
}
}
-#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;
@@ -2928,7 +2928,7 @@
}
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;
@@ -2940,4 +2940,4 @@
return (0);
}
-#endif /* NETDUMP */
+#endif /* DEBUGNET */
Index: sys/dev/re/if_re.c
===================================================================
--- sys/dev/re/if_re.c
+++ sys/dev/re/if_re.c
@@ -128,6 +128,7 @@
#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 @@
#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_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 @@
goto fail;
}
- NETDUMP_SET(ifp, re);
+ DEBUGNET_SET(ifp, re);
fail:
if (error)
@@ -4093,28 +4092,28 @@
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 @@
}
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 @@
return (error);
return (0);
}
-#endif /* NETDUMP */
+#endif /* DEBUGNET */
Index: sys/dev/virtio/network/if_vtnet.c
===================================================================
--- sys/dev/virtio/network/if_vtnet.c
+++ sys/dev/virtio/network/if_vtnet.c
@@ -51,6 +51,7 @@
#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 @@
#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 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_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 @@
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_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 @@
* 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 @@
}
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 @@
(void)vtnet_rxq_eof(&sc->vtnet_rxqs[i]);
return (0);
}
-#endif /* NETDUMP */
+#endif /* DEBUGNET */
Index: sys/i386/conf/GENERIC
===================================================================
--- sys/i386/conf/GENERIC
+++ sys/i386/conf/GENERIC
@@ -99,6 +99,7 @@
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
Index: sys/kern/kern_mbuf.c
===================================================================
--- sys/kern/kern_mbuf.c
+++ sys/kern/kern_mbuf.c
@@ -413,10 +413,10 @@
}
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 @@
* 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 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 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 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 @@
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 @@
}
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 @@
}
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 @@
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 @@
}
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 @@
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;
+}
+
+/*
+ * Callback invoked when a debugnet connection is closed/finished.
+ */
+void
+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 netdump mbuf+cluster pool and cache zones.
+ * Reinitialize the debugnet mbuf+cluster pool and cache zones.
*/
void
-netdump_mbuf_reinit(int nmbuf, int nclust, int clsize)
+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.
Index: sys/net/debugnet.h
===================================================================
--- /dev/null
+++ sys/net/debugnet.h
@@ -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 */
Index: sys/net/debugnet.c
===================================================================
--- /dev/null
+++ sys/net/debugnet.c
@@ -0,0 +1,654 @@
+/*-
+ * 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, (const 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);
Index: sys/net/debugnet_inet.c
===================================================================
--- /dev/null
+++ sys/net/debugnet_inet.c
@@ -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));
+}
Index: sys/net/debugnet_int.h
===================================================================
--- /dev/null
+++ sys/net/debugnet_int.h
@@ -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
Index: sys/net/if.c
===================================================================
--- sys/net/if.c
+++ sys/net/if.c
@@ -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>
@@ -2806,9 +2806,7 @@
if (error == 0) {
getmicrotime(&ifp->if_lastchange);
rt_ifmsg(ifp);
-#ifdef INET
- NETDUMP_REINIT(ifp);
-#endif
+ DEBUGNET_NOTIFY_MTU(ifp);
}
/*
* If the link MTU changed, do network layer specific procedure.
Index: sys/net/if_var.h
===================================================================
--- sys/net/if_var.h
+++ sys/net/if_var.h
@@ -70,7 +70,7 @@
struct vnet;
struct ifmedia;
struct netmap_adapter;
-struct netdump_methods;
+struct debugnet_methods;
#ifdef _KERNEL
#include <sys/_eventhandler.h>
@@ -417,9 +417,9 @@
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;
/*
Index: sys/net/iflib.c
===================================================================
--- sys/net/iflib.c
+++ sys/net/iflib.c
@@ -59,6 +59,7 @@
#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 @@
#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 @@
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>
@@ -4770,7 +4770,7 @@
}
*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);
@@ -6717,9 +6717,9 @@
}
#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;
@@ -6732,7 +6732,7 @@
}
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;
@@ -6744,7 +6744,7 @@
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++) {
@@ -6760,7 +6760,7 @@
}
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;
@@ -6779,7 +6779,7 @@
}
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;
@@ -6800,4 +6800,4 @@
(void)iflib_rxeof(&ctx->ifc_rxqs[i], 16 /* XXX */);
return (0);
}
-#endif /* NETDUMP */
+#endif /* DEBUGNET */
Index: sys/netinet/netdump/netdump.h
===================================================================
--- sys/netinet/netdump/netdump.h
+++ sys/netinet/netdump/netdump.h
@@ -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 @@
#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_ */
Index: sys/netinet/netdump/netdump_client.c
===================================================================
--- sys/netinet/netdump/netdump_client.c
+++ sys/netinet/netdump/netdump_client.c
@@ -49,6 +49,7 @@
#include <sys/protosw.h>
#include <sys/socket.h>
#include <sys/sysctl.h>
+#include <sys/syslog.h>
#include <sys/systm.h>
#include <net/ethernet.h>
@@ -57,6 +58,7 @@
#include <net/if_dl.h>
#include <net/if_types.h>
#include <net/if_var.h>
+#include <net/debugnet.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
@@ -71,57 +73,26 @@
#include <machine/in_cksum.h>
#include <machine/pcb.h>
-#define NETDDEBUG(f, ...) do { \
- if (nd_debug > 0) \
- printf(("%s: " f), __func__, ## __VA_ARGS__); \
-} while (0)
-#define NETDDEBUG_IF(i, f, ...) do { \
- if (nd_debug > 0) \
- if_printf((i), ("%s: " f), __func__, ## __VA_ARGS__); \
-} while (0)
#define NETDDEBUGV(f, ...) do { \
if (nd_debug > 1) \
printf(("%s: " f), __func__, ## __VA_ARGS__); \
} while (0)
-#define NETDDEBUGV_IF(i, f, ...) do { \
- if (nd_debug > 1) \
- if_printf((i), ("%s: " f), __func__, ## __VA_ARGS__); \
-} while (0)
-static int netdump_arp_gw(void);
-static void netdump_cleanup(void);
static int netdump_configure(struct diocskerneldump_arg *,
struct thread *);
static int netdump_dumper(void *priv __unused, void *virtual,
vm_offset_t physical __unused, off_t offset, size_t length);
static bool netdump_enabled(void);
static int netdump_enabled_sysctl(SYSCTL_HANDLER_ARGS);
-static int netdump_ether_output(struct mbuf *m, struct ifnet *ifp,
- struct ether_addr dst, u_short etype);
-static void netdump_handle_arp(struct mbuf **mb);
-static void netdump_handle_ip(struct mbuf **mb);
static int netdump_ioctl(struct cdev *dev __unused, u_long cmd,
caddr_t addr, int flags __unused, struct thread *td);
static int netdump_modevent(module_t mod, int type, void *priv);
-static void netdump_network_poll(void);
-static void netdump_pkt_in(struct ifnet *ifp, struct mbuf *m);
-static void netdump_reinit_internal(struct ifnet *ifp);
-static int netdump_send(uint32_t type, off_t offset, unsigned char *data,
- uint32_t datalen);
-static int netdump_send_arp(in_addr_t dst);
static int netdump_start(struct dumperinfo *di);
-static int netdump_udp_output(struct mbuf *m);
static void netdump_unconfigure(void);
/* Must be at least as big as the chunks dumpsys() gives us. */
static unsigned char nd_buf[MAXDUMPPGS * PAGE_SIZE];
-static uint32_t nd_seqno;
-static int dump_failed, have_gw_mac;
-static void (*drv_if_input)(struct ifnet *, struct mbuf *);
-static int restore_gw_addr;
-
-static uint64_t rcvd_acks;
-CTASSERT(sizeof(rcvd_acks) * NBBY == NETDUMP_MAX_IN_FLIGHT);
+static int dump_failed;
/* Configuration parameters. */
static struct {
@@ -131,6 +102,7 @@
union kd_ip ndc_gateway;
uint8_t ndc_af;
/* Runtime State */
+ struct debugnet_pcb *nd_pcb;
off_t nd_tx_off;
size_t nd_buf_len;
} nd_conf;
@@ -147,10 +119,8 @@
#define NETDUMP_RUNLOCK() sx_sunlock(&nd_conf_lk)
#define NETDUMP_ASSERT_WLOCKED() sx_assert(&nd_conf_lk, SA_XLOCKED)
#define NETDUMP_ASSERT_LOCKED() sx_assert(&nd_conf_lk, SA_LOCKED)
-static struct ether_addr nd_gw_mac;
static struct ifnet *nd_ifp;
static eventhandler_tag nd_detach_cookie;
-static uint16_t nd_server_port = NETDUMP_PORT;
FEATURE(netdump, "Netdump client support");
@@ -167,17 +137,18 @@
SYSCTL_STRING(_net_netdump, OID_AUTO, path, CTLFLAG_RW,
nd_path, sizeof(nd_path),
"Server path for output files");
-static int nd_polls = 2000;
+/*
+ * The following three variables were moved to debugnet(4), but these knobs
+ * were retained as aliases.
+ */
SYSCTL_INT(_net_netdump, OID_AUTO, polls, CTLFLAG_RWTUN,
- &nd_polls, 0,
+ &debugnet_npolls, 0,
"Number of times to poll before assuming packet loss (0.5ms per poll)");
-static int nd_retries = 10;
SYSCTL_INT(_net_netdump, OID_AUTO, retries, CTLFLAG_RWTUN,
- &nd_retries, 0,
+ &debugnet_nretries, 0,
"Number of retransmit attempts before giving up");
-static int nd_arp_retries = 3;
SYSCTL_INT(_net_netdump, OID_AUTO, arp_retries, CTLFLAG_RWTUN,
- &nd_arp_retries, 0,
+ &debugnet_arp_nretries, 0,
"Number of ARP attempts before giving up");
static bool
@@ -203,721 +174,6 @@
return (EPERM);
}
-/*
- * Checks for netdump support on a network interface
- *
- * Parameters:
- * ifp The network interface that is being tested for support
- *
- * Returns:
- * int 1 if the interface is supported, 0 if not
- */
-static bool
-netdump_supported_nic(struct ifnet *ifp)
-{
-
- return (ifp->if_netdump_methods != NULL);
-}
-
-/*-
- * Network specific primitives.
- * Following down the code they are divided ordered as:
- * - Packet buffer primitives
- * - Output primitives
- * - Input primitives
- * - Polling 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
- */
-static int
-netdump_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, "netdump_ether_output: interface isn't up\n");
- 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_netdump_methods->nd_transmit)(ifp, m));
-}
-
-/*
- * Unreliable transmission of an mbuf chain to the netdump server
- * Note: can't handle fragmentation; fails if the packet is larger than
- * nd_ifp->if_mtu after adding the UDP/IP headers
- *
- * Parameters:
- * m mbuf chain
- *
- * Returns:
- * int see errno.h, 0 for success
- */
-static int
-netdump_udp_output(struct mbuf *m)
-{
- struct udpiphdr *ui;
- struct ip *ip;
-
- MPASS(netdump_enabled());
-
- M_PREPEND(m, sizeof(struct udpiphdr), M_NOWAIT);
- if (m == NULL) {
- printf("%s: out of mbufs\n", __func__);
- return (ENOBUFS);
- }
-
- if (m->m_pkthdr.len > nd_ifp->if_mtu) {
- printf("netdump_udp_output: Packet is too big: %d > MTU %u\n",
- m->m_pkthdr.len, nd_ifp->if_mtu);
- m_freem(m);
- return (ENOBUFS);
- }
-
- ui = mtod(m, struct udpiphdr *);
- bzero(ui->ui_x1, sizeof(ui->ui_x1));
- ui->ui_pr = IPPROTO_UDP;
- ui->ui_len = htons(m->m_pkthdr.len - sizeof(struct ip));
- ui->ui_ulen = ui->ui_len;
- ui->ui_src = nd_client;
- ui->ui_dst = nd_server;
- /* Use this src port so that the server can connect() the socket */
- ui->ui_sport = htons(NETDUMP_ACKPORT);
- ui->ui_dport = htons(nd_server_port);
- ui->ui_sum = 0;
- if ((ui->ui_sum = in_cksum(m, m->m_pkthdr.len)) == 0)
- ui->ui_sum = 0xffff;
-
- ip = mtod(m, struct ip *);
- ip->ip_v = IPVERSION;
- ip->ip_hl = sizeof(struct 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 (netdump_ether_output(m, nd_ifp, nd_gw_mac, ETHERTYPE_IP));
-}
-
-/*
- * Builds and sends a single ARP request to locate the server
- *
- * Return value:
- * 0 on success
- * errno on error
- */
-static int
-netdump_send_arp(in_addr_t dst)
-{
- struct ether_addr bcast;
- struct mbuf *m;
- struct arphdr *ah;
- int pktlen;
-
- MPASS(netdump_enabled());
-
- /* Fill-up a broadcast address. */
- memset(&bcast, 0xFF, ETHER_ADDR_LEN);
- m = m_gethdr(M_NOWAIT, MT_DATA);
- if (m == NULL) {
- printf("netdump_send_arp: Out of mbufs\n");
- 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(nd_ifp), ETHER_ADDR_LEN);
- ((struct in_addr *)ar_spa(ah))->s_addr = nd_client.s_addr;
- bzero(ar_tha(ah), ETHER_ADDR_LEN);
- ((struct in_addr *)ar_tpa(ah))->s_addr = dst;
- return (netdump_ether_output(m, nd_ifp, bcast, ETHERTYPE_ARP));
-}
-
-/*
- * 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
- */
-static int
-netdump_arp_gw(void)
-{
- in_addr_t dst;
- int error, polls, retries;
-
- dst = nd_server.s_addr;
-restart:
- for (retries = 0; retries < nd_arp_retries && have_gw_mac == 0;
- retries++) {
- error = netdump_send_arp(dst);
- if (error != 0)
- return (error);
- for (polls = 0; polls < nd_polls && have_gw_mac == 0; polls++) {
- netdump_network_poll();
- DELAY(500);
- }
- if (have_gw_mac == 0)
- printf("(ARP retry)");
- }
- if (have_gw_mac != 0)
- return (0);
- if (dst == nd_server.s_addr && nd_server.s_addr != nd_gateway.s_addr) {
- printf("Failed to ARP server, trying to reach gateway...\n");
- dst = nd_gateway.s_addr;
- goto restart;
- }
-
- printf("\nARP timed out.\n");
- return (ETIMEDOUT);
-}
-
-/*
- * Dummy free function for netdump clusters.
- */
-static void
-netdump_mbuf_free(struct mbuf *m __unused)
-{
-}
-
-/*
- * Construct and reliably send a netdump 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 netdump packet type (HERALD, FINISHED, or VMCORE)
- * offset vmcore data offset (bytes)
- * data vmcore data
- * datalen vmcore data size (bytes)
- *
- * Returns:
- * int see errno.h, 0 for success
- */
-static int
-netdump_send(uint32_t type, off_t offset, unsigned char *data, uint32_t datalen)
-{
- struct netdump_msg_hdr *nd_msg_hdr;
- struct mbuf *m, *m2;
- uint64_t want_acks;
- uint32_t i, pktlen, sent_so_far;
- int retries, polls, error;
-
- want_acks = 0;
- rcvd_acks = 0;
- retries = 0;
-
- MPASS(netdump_enabled());
-
-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;
-
- /* First bound: the packet structure. */
- pktlen = min(pktlen, NETDUMP_DATASIZE);
-
- /* Second bound: the interface MTU (assume no IP options). */
- pktlen = min(pktlen, nd_ifp->if_mtu - sizeof(struct udpiphdr) -
- sizeof(struct netdump_msg_hdr));
-
- /*
- * Check if it is retransmitting and this has been ACKed
- * already.
- */
- if ((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("netdump_send: Out of mbufs\n");
- return (ENOBUFS);
- }
- m->m_len = sizeof(struct netdump_msg_hdr);
- m->m_pkthdr.len = sizeof(struct netdump_msg_hdr);
- MH_ALIGN(m, sizeof(struct netdump_msg_hdr));
- nd_msg_hdr = mtod(m, struct netdump_msg_hdr *);
- nd_msg_hdr->mh_seqno = htonl(nd_seqno + i);
- nd_msg_hdr->mh_type = htonl(type);
- nd_msg_hdr->mh_offset = htobe64(offset + sent_so_far);
- nd_msg_hdr->mh_len = htonl(pktlen);
- nd_msg_hdr->mh__pad = 0;
-
- if (pktlen != 0) {
- m2 = m_get(M_NOWAIT, MT_DATA);
- if (m2 == NULL) {
- m_freem(m);
- printf("netdump_send: Out of mbufs\n");
- return (ENOBUFS);
- }
- MEXTADD(m2, data + sent_so_far, pktlen,
- netdump_mbuf_free, NULL, NULL, 0, EXT_DISPOSABLE);
- m2->m_len = pktlen;
-
- m_cat(m, m2);
- m->m_pkthdr.len += pktlen;
- }
- error = netdump_udp_output(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 >= NETDUMP_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",
- NETDUMP_MAX_IN_FLIGHT, i);
-
- /*
- * Wait for acks. A *real* window would speed things up considerably.
- */
- polls = 0;
- while (rcvd_acks != want_acks) {
- if (polls++ > nd_polls) {
- if (retries++ > nd_retries)
- return (ETIMEDOUT);
- printf(". ");
- goto retransmit;
- }
- netdump_network_poll();
- DELAY(500);
- }
- nd_seqno += i;
- return (0);
-}
-
-/*
- * Handler for IP packets: checks their sanity and then processes any netdump
- * ACK packets it finds.
- *
- * It needs to replicate partially the behaviour of ip_input() and
- * udp_input().
- *
- * Parameters:
- * 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
- */
-static void
-netdump_handle_ip(struct mbuf **mb)
-{
- struct ip *ip;
- struct udpiphdr *udp;
- struct netdump_ack *nd_ack;
- struct mbuf *m;
- int rcv_ackno;
- unsigned short hlen;
-
- /* IP processing. */
- m = *mb;
- if (m->m_pkthdr.len < sizeof(struct ip)) {
- NETDDEBUG("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) {
- NETDDEBUG("m_pullup failed\n");
- return;
- }
- }
- ip = mtod(m, struct ip *);
-
- /* IP version. */
- if (ip->ip_v != IPVERSION) {
- NETDDEBUG("bad IP version %d\n", ip->ip_v);
- return;
- }
-
- /* Header length. */
- hlen = ip->ip_hl << 2;
- if (hlen < sizeof(struct ip)) {
- NETDDEBUG("bad IP header length (%hu)\n", hlen);
- return;
- }
- if (hlen > m->m_len) {
- m = m_pullup(m, hlen);
- *mb = m;
- if (m == NULL) {
- NETDDEBUG("m_pullup failed\n");
- return;
- }
- ip = mtod(m, struct ip *);
- }
- /* Ignore packets with IP options. */
- if (hlen > sizeof(struct ip)) {
- NETDDEBUG("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) {
- NETDDEBUG("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) {
- NETDDEBUG("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) {
- NETDDEBUG("IP packet smaller (%hu) than header (%hu)\n",
- ip->ip_len, hlen);
- return;
- }
- if (m->m_pkthdr.len < ip->ip_len) {
- NETDDEBUG("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 != nd_server.s_addr) {
- NETDDEBUG("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 != nd_client.s_addr) {
- NETDDEBUGV("drop packet not to our IP\n");
- return;
- }
-
- if (ip->ip_p != IPPROTO_UDP) {
- NETDDEBUG("drop non-UDP packet\n");
- return;
- }
-
- /* Do not deal with fragments. */
- if ((ip->ip_off & (IP_MF | IP_OFFMASK)) != 0) {
- NETDDEBUG("drop fragmented packet\n");
- return;
- }
-
- /* UDP custom is to have packet length not include IP header. */
- ip->ip_len -= hlen;
-
- /* UDP processing. */
-
- /* Get IP and UDP headers together, along with the netdump packet. */
- if (m->m_pkthdr.len <
- sizeof(struct udpiphdr) + sizeof(struct netdump_ack)) {
- NETDDEBUG("ignoring small packet\n");
- return;
- }
- if (m->m_len < sizeof(struct udpiphdr) + sizeof(struct netdump_ack)) {
- m = m_pullup(m, sizeof(struct udpiphdr) +
- sizeof(struct netdump_ack));
- *mb = m;
- if (m == NULL) {
- NETDDEBUG("m_pullup failed\n");
- return;
- }
- }
- udp = mtod(m, struct udpiphdr *);
-
- if (ntohs(udp->ui_u.uh_dport) != NETDUMP_ACKPORT) {
- NETDDEBUG("not on the netdump port.\n");
- return;
- }
-
- /* Netdump processing. */
-
- /*
- * Packet is meant for us. Extract the ack sequence number and the
- * port number if necessary.
- */
- nd_ack = (struct netdump_ack *)(mtod(m, caddr_t) +
- sizeof(struct udpiphdr));
- rcv_ackno = ntohl(nd_ack->na_seqno);
- if (nd_server_port == NETDUMP_PORT)
- nd_server_port = ntohs(udp->ui_u.uh_sport);
- if (rcv_ackno >= nd_seqno + NETDUMP_MAX_IN_FLIGHT)
- printf("%s: ACK %d too far in future!\n", __func__, rcv_ackno);
- else if (rcv_ackno >= nd_seqno) {
- /* We're interested in this ack. Record it. */
- rcvd_acks |= 1 << (rcv_ackno - nd_seqno);
- }
-}
-
-/*
- * 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:
- * 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
- */
-static void
-netdump_handle_arp(struct mbuf **mb)
-{
- char buf[INET_ADDRSTRLEN];
- struct in_addr isaddr, itaddr, myaddr;
- 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) {
- NETDDEBUG("runt packet: m_pullup failed\n");
- return;
- }
- }
-
- ah = mtod(m, struct arphdr *);
- if (ntohs(ah->ar_hrd) != ARPHRD_ETHER) {
- NETDDEBUG("unknown hardware address 0x%2D)\n",
- (unsigned char *)&ah->ar_hrd, "");
- return;
- }
- if (ntohs(ah->ar_pro) != ETHERTYPE_IP) {
- NETDDEBUG("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) {
- NETDDEBUG("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);
- myaddr = nd_client;
-
- if (memcmp(ar_sha(ah), enaddr, ifp->if_addrlen) == 0) {
- NETDDEBUG("ignoring ARP from myself\n");
- return;
- }
-
- if (isaddr.s_addr == nd_client.s_addr) {
- 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) {
- NETDDEBUG("ignoring ARP from broadcast address\n");
- return;
- }
-
- if (op == ARPOP_REPLY) {
- if (isaddr.s_addr != nd_gateway.s_addr &&
- isaddr.s_addr != nd_server.s_addr) {
- inet_ntoa_r(isaddr, buf);
- NETDDEBUG(
- "ignoring ARP reply from %s (not netdump server)\n",
- buf);
- return;
- }
- memcpy(nd_gw_mac.octet, ar_sha(ah),
- min(ah->ar_hln, ETHER_ADDR_LEN));
- have_gw_mac = 1;
- NETDDEBUG("got server MAC address %6D\n", nd_gw_mac.octet, ":");
- return;
- }
-
- if (op != ARPOP_REQUEST) {
- NETDDEBUG("ignoring ARP non-request/reply\n");
- return;
- }
-
- if (itaddr.s_addr != nd_client.s_addr) {
- NETDDEBUG("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);
- netdump_ether_output(m, ifp, dst, ETHERTYPE_ARP);
- *mb = NULL;
-}
-
-/*
- * 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 netdump_handle_ip or netdump_handle_arp.
- *
- * It needs to replicate partially the behaviour of ether_input() and
- * ether_demux().
- *
- * Parameters:
- * ifp the interface the packet came from (should be nd_ifp)
- * m an mbuf containing the packet received
- */
-static void
-netdump_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) {
- NETDDEBUG_IF(ifp, "discard frame without packet header\n");
- goto done;
- }
- if (m->m_len < ETHER_HDR_LEN) {
- NETDDEBUG_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) {
- NETDDEBUG_IF(ifp, "ignoring vlan packets\n");
- goto done;
- }
- if (if_gethwaddr(ifp, &ifr) != 0) {
- NETDDEBUG_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) {
- NETDDEBUG_IF(ifp,
- "discard frame with incorrect destination addr\n");
- goto done;
- }
-
- /* Done ethernet processing. Strip off the ethernet header. */
- m_adj(m, ETHER_HDR_LEN);
- switch (etype) {
- case ETHERTYPE_ARP:
- netdump_handle_arp(&m);
- break;
- case ETHERTYPE_IP:
- netdump_handle_ip(&m);
- break;
- default:
- NETDDEBUG_IF(ifp, "dropping unknown ethertype %hu\n", etype);
- break;
- }
-done:
- if (m != NULL)
- m_freem(m);
-}
-
-/*
- * After trapping, instead of assuming that most of the network stack is sane,
- * we just poll the driver directly for packets.
- */
-static void
-netdump_network_poll(void)
-{
-
- MPASS(netdump_enabled());
-
- nd_ifp->if_netdump_methods->nd_poll(nd_ifp, 1000);
-}
-
/*-
* Dumping specific primitives.
*/
@@ -932,8 +188,11 @@
error = 0;
if (nd_conf.nd_buf_len != 0) {
- error = netdump_send(NETDUMP_VMCORE, nd_conf.nd_tx_off,
- nd_buf, nd_conf.nd_buf_len);
+ struct debugnet_proto_aux auxdata = {
+ .dp_offset_start = nd_conf.nd_tx_off,
+ };
+ error = debugnet_send(nd_conf.nd_pcb, DEBUGNET_DATA, nd_buf,
+ nd_conf.nd_buf_len, &auxdata);
if (error == 0)
nd_conf.nd_buf_len = 0;
}
@@ -972,11 +231,13 @@
if (dump_failed != 0)
printf("failed to dump the kernel core\n");
- else if (netdump_send(NETDUMP_FINISHED, 0, NULL, 0) != 0)
+ else if (
+ debugnet_sendempty(nd_conf.nd_pcb, DEBUGNET_FINISHED) != 0)
printf("failed to close the transaction\n");
else
printf("\nnetdump finished.\n");
- netdump_cleanup();
+ debugnet_free(nd_conf.nd_pcb);
+ nd_conf.nd_pcb = NULL;
return (0);
}
if (length > sizeof(nd_buf))
@@ -1005,9 +266,9 @@
static int
netdump_start(struct dumperinfo *di)
{
- char *path;
+ struct debugnet_conn_params dcp;
+ struct debugnet_pcb *pcb;
char buf[INET_ADDRSTRLEN];
- uint32_t len;
int error;
error = 0;
@@ -1022,6 +283,8 @@
return (EINVAL);
}
+ memset(&dcp, 0, sizeof(dcp));
+
if (nd_server.s_addr == INADDR_ANY) {
printf("netdump_start: can't netdump; no server IP given\n");
return (EINVAL);
@@ -1034,54 +297,29 @@
/* We start dumping at offset 0. */
di->dumpoff = 0;
- nd_seqno = 1;
-
- /*
- * nd_server_port could have switched after the first ack the
- * first time it gets called. Adjust it accordingly.
- */
- nd_server_port = NETDUMP_PORT;
-
- /* Switch to the netdump mbuf zones. */
- netdump_mbuf_dump();
-
- nd_ifp->if_netdump_methods->nd_event(nd_ifp, NETDUMP_START);
+ dcp.dc_ifp = nd_ifp;
- /* Make the card use *our* receive callback. */
- drv_if_input = nd_ifp->if_input;
- nd_ifp->if_input = netdump_pkt_in;
+ dcp.dc_client = nd_client.s_addr;
+ dcp.dc_server = nd_server.s_addr;
+ dcp.dc_gateway = nd_gateway.s_addr;
- if (nd_gateway.s_addr == INADDR_ANY) {
- restore_gw_addr = 1;
- nd_gateway.s_addr = nd_server.s_addr;
- }
+ dcp.dc_herald_port = NETDUMP_PORT;
+ dcp.dc_client_ack_port = NETDUMP_ACKPORT;
- printf("netdump in progress. searching for server...\n");
- if (netdump_arp_gw()) {
- printf("failed to locate server MAC address\n");
- error = EINVAL;
- goto trig_abort;
- }
+ dcp.dc_herald_data = nd_path;
+ dcp.dc_herald_datalen = (nd_path[0] == 0) ? 0 : strlen(nd_path) + 1;
- if (nd_path[0] != '\0') {
- path = nd_path;
- len = strlen(path) + 1;
- } else {
- path = NULL;
- len = 0;
- }
- if (netdump_send(NETDUMP_HERALD, 0, path, len) != 0) {
+ error = debugnet_connect(&dcp, &pcb);
+ if (error != 0) {
printf("failed to contact netdump server\n");
- error = EINVAL;
- goto trig_abort;
+ /* Squash debugnet to something the dumper code understands. */
+ return (EINVAL);
}
+
printf("netdumping to %s (%6D)\n", inet_ntoa_r(nd_server, buf),
- nd_gw_mac.octet, ":");
+ debugnet_get_gw_mac(pcb), ":");
+ nd_conf.nd_pcb = pcb;
return (0);
-
-trig_abort:
- netdump_cleanup();
- return (error);
}
static int
@@ -1094,34 +332,18 @@
if (error != 0)
return (error);
memcpy(nd_buf, kdh, sizeof(*kdh));
- error = netdump_send(NETDUMP_KDH, 0, nd_buf, sizeof(*kdh));
+ error = debugnet_send(nd_conf.nd_pcb, NETDUMP_KDH, nd_buf,
+ sizeof(*kdh), NULL);
if (error == 0 && keysize > 0) {
if (keysize > sizeof(nd_buf))
return (EINVAL);
memcpy(nd_buf, key, keysize);
- error = netdump_send(NETDUMP_EKCD_KEY, 0, nd_buf, keysize);
+ error = debugnet_send(nd_conf.nd_pcb, NETDUMP_EKCD_KEY, nd_buf,
+ keysize, NULL);
}
return (error);
}
-/*
- * Cleanup routine for a possibly failed netdump.
- */
-static void
-netdump_cleanup(void)
-{
-
- if (restore_gw_addr != 0) {
- nd_gateway.s_addr = INADDR_ANY;
- restore_gw_addr = 0;
- }
- if (drv_if_input != NULL) {
- nd_ifp->if_input = drv_if_input;
- drv_if_input = NULL;
- }
- nd_ifp->if_netdump_methods->nd_event(nd_ifp, NETDUMP_END);
-}
-
/*-
* KLD specific code.
*/
@@ -1146,11 +368,12 @@
kda.kda_index = KDA_REMOVE_DEV;
(void)dumper_remove(nd_conf.ndc_iface, &kda);
- netdump_mbuf_drain();
-
if_rele(nd_ifp);
nd_ifp = NULL;
+ log(LOG_WARNING, "netdump: Lost configured interface %s\n",
+ nd_conf.ndc_iface);
+
bzero(&nd_conf, sizeof(nd_conf));
}
@@ -1185,7 +408,7 @@
if_rele(ifp);
return (ENXIO);
}
- if (!netdump_supported_nic(ifp) || ifp->if_type != IFT_ETHER) {
+ if (!DEBUGNET_SUPPORTED_NIC(ifp)) {
if_rele(ifp);
return (ENODEV);
}
@@ -1194,8 +417,6 @@
if_rele(nd_ifp);
nd_ifp = ifp;
- netdump_reinit_internal(ifp);
-
#define COPY_SIZED(elm) do { \
_Static_assert(sizeof(nd_conf.ndc_ ## elm) == \
sizeof(conf->kda_ ## elm), "elm " __XSTRING(elm) " mismatch"); \
@@ -1212,43 +433,6 @@
return (0);
}
-/*
- * Reinitialize the mbuf pool used by drivers while dumping. This is called
- * from the generic ioctl handler for SIOCSIFMTU after any NIC driver has
- * reconfigured itself. (I.e., it may not be a configured netdump interface.)
- */
-void
-netdump_reinit(struct ifnet *ifp)
-{
-
- NETDUMP_WLOCK();
- if (ifp != nd_ifp) {
- NETDUMP_WUNLOCK();
- return;
- }
- netdump_reinit_internal(ifp);
- NETDUMP_WUNLOCK();
-}
-
-static void
-netdump_reinit_internal(struct ifnet *ifp)
-{
- int clsize, nmbuf, ncl, nrxr;
-
- NETDUMP_ASSERT_WLOCKED();
-
- ifp->if_netdump_methods->nd_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;
- netdump_mbuf_reinit(nmbuf, ncl, clsize);
-}
-
/*
* ioctl(2) handler for the netdump device. This is currently only used to
* register netdump as a dump device.
Index: sys/powerpc/conf/GENERIC
===================================================================
--- sys/powerpc/conf/GENERIC
+++ sys/powerpc/conf/GENERIC
@@ -104,6 +104,7 @@
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
Index: sys/powerpc/conf/GENERIC64
===================================================================
--- sys/powerpc/conf/GENERIC64
+++ sys/powerpc/conf/GENERIC64
@@ -110,6 +110,7 @@
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
Index: sys/sparc64/conf/GENERIC
===================================================================
--- sys/sparc64/conf/GENERIC
+++ sys/sparc64/conf/GENERIC
@@ -94,6 +94,7 @@
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
Index: sys/sys/mbuf.h
===================================================================
--- sys/sys/mbuf.h
+++ sys/sys/mbuf.h
@@ -1501,11 +1501,12 @@
}
#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
Index: sys/sys/param.h
===================================================================
--- sys/sys/param.h
+++ sys/sys/param.h
@@ -60,7 +60,7 @@
* in the range 5 to 9.
*/
#undef __FreeBSD_version
-#define __FreeBSD_version 1300047 /* Master, propagated to newvers */
+#define __FreeBSD_version 1300999 /* Master, propagated to newvers */
/*
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Feb 14, 7:43 AM (19 h, 32 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
16639453
Default Alt Text
D21421.diff (105 KB)
Attached To
Mode
D21421: Split out a more generic debugnet(4) from netdump(4)
Attached
Detach File
Event Timeline
Log In to Comment