Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 6 May 2018 00:38:29 +0000 (UTC)
From:      Mark Johnston <markj@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r333283 - in head: etc/mtree include share/man/man4 sys/conf sys/net sys/netinet/netdump
Message-ID:  <201805060038.w460cUTZ079439@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: markj
Date: Sun May  6 00:38:29 2018
New Revision: 333283
URL: https://svnweb.freebsd.org/changeset/base/333283

Log:
  Import the netdump client code.
  
  This is a component of a system which lets the kernel dump core to
  a remote host after a panic, rather than to a local storage device.
  The server component is available in the ports tree. netdump is
  particularly useful on diskless systems.
  
  The netdump(4) man page contains some details describing the protocol.
  Support for configuring netdump will be added to dumpon(8) in a future
  commit. To use netdump, the kernel must have been compiled with the
  NETDUMP option.
  
  The initial revision of netdump was written by Darrell Anderson and
  was integrated into Sandvine's OS, from which this version was derived.
  
  Reviewed by:	bdrewery, cem (earlier versions), julian, sbruno
  MFC after:	1 month
  X-MFC note:	use a spare field in struct ifnet
  Sponsored by:	Dell EMC Isilon
  Differential Revision:	https://reviews.freebsd.org/D15253

Added:
  head/share/man/man4/netdump.4   (contents, props changed)
  head/sys/netinet/netdump/
  head/sys/netinet/netdump/netdump.h   (contents, props changed)
  head/sys/netinet/netdump/netdump_client.c   (contents, props changed)
Modified:
  head/etc/mtree/BSD.include.dist
  head/include/Makefile
  head/share/man/man4/Makefile
  head/sys/conf/NOTES
  head/sys/conf/files
  head/sys/conf/options
  head/sys/net/if.c
  head/sys/net/if_var.h

Modified: head/etc/mtree/BSD.include.dist
==============================================================================
--- head/etc/mtree/BSD.include.dist	Sun May  6 00:22:38 2018	(r333282)
+++ head/etc/mtree/BSD.include.dist	Sun May  6 00:38:29 2018	(r333283)
@@ -290,6 +290,8 @@
     netinet
         cc
         ..
+        netdump
+        ..
     ..
     netinet6
     ..

Modified: head/include/Makefile
==============================================================================
--- head/include/Makefile	Sun May  6 00:22:38 2018	(r333282)
+++ head/include/Makefile	Sun May  6 00:38:29 2018	(r333283)
@@ -56,6 +56,7 @@ LSUBDIRS=	cam/ata cam/mmc cam/nvme cam/scsi \
 	net/altq \
 	netgraph/atm netgraph/netflow \
 	netinet/cc \
+	netinet/netdump \
 	security/audit \
 	security/mac_biba security/mac_bsdextended security/mac_lomac \
 	security/mac_mls security/mac_partition \

Modified: head/share/man/man4/Makefile
==============================================================================
--- head/share/man/man4/Makefile	Sun May  6 00:22:38 2018	(r333282)
+++ head/share/man/man4/Makefile	Sun May  6 00:38:29 2018	(r333283)
@@ -319,6 +319,7 @@ MAN=	aac.4 \
 	ncv.4 \
 	${_ndis.4} \
 	net80211.4 \
+	netdump.4 \
 	netfpga10g_nf10bmac.4 \
 	netgraph.4 \
 	netintro.4 \

Added: head/share/man/man4/netdump.4
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/share/man/man4/netdump.4	Sun May  6 00:38:29 2018	(r333283)
@@ -0,0 +1,127 @@
+.\"-
+.\" Copyright (c) 2018 Mark Johnston <markj@FreeBSD.org>
+.\"
+.\" 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$
+.\"
+.Dd May 4, 2018
+.Dt NETDUMP 4
+.Os
+.Sh NAME
+.Nm netdump
+.Nd protocol for transmitting kernel dumps to a remote server
+.Sh SYNOPSIS
+To compile netdump client support into the kernel, place the following line in
+your kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "options NETDUMP"
+.Ed
+.Pp
+Debug output can be enabled by adding the following line:
+.Bd -ragged -offset indent
+.Cd "options NETDUMP_DEBUG"
+.Ed
+.Sh DESCRIPTION
+netdump is a UDP-based protocol for transmitting kernel dumps to a remote host.
+A netdump client is a panicking kernel, and a netdump server is a host
+running the
+.Nm
+daemon, available in ports as
+.Pa ports/ftp/netdumpd .
+.Nm
+clients are configured using the
+.Xr dumpon 8
+utility.
+.Pp
+.Nm
+client messages consist of a fixed-size header followed by a variable-sized
+payload.
+The header contains the message type, a sequence number, the offset of
+the payload data in the kernel dump, and the length of the payload data
+(not including the header).
+The message types are
+.Dv HERALD , FINISHED , KDH , VMCORE ,
+and
+.Dv EKCD_KEY .
+.Nm
+server messages have a fixed size and contain only the sequence number of
+the client message.
+These messages indicate that the server has successfully processed the
+client message with the corresponding sequence number.
+All client messages are acknowledged this way.
+Server messages are always sent to port 20024 of the client.
+.Pp
+To initiate a
+.Nm ,
+the client sends a
+.Dv HERALD
+message to the server at port 20023.
+The client may include a relative path in its payload, in which case the
+.Nm
+server should attempt to save the dump at that path relative to its configured
+dump directory.
+The server will acknowledge the
+.Dv HERALD
+using a random source port, and the client must send all subsequent messages
+to that port.
+.Pp
+The
+.Dv KDH , VMCORE ,
+and
+.Dv EKCD_KEY
+message payloads contain the kernel dump header, dump contents, and
+dump encryption key respectively.
+The offset in the message header should be treated as a seek offset
+in the corresponding file.
+There are no ordering requirements for these messages.
+.Pp
+A
+.Nm
+is completed by sending the
+.Dv FINISHED
+message to the server.
+.Pp
+The following network drivers support netdump:
+.Xr alc 4 ,
+.Xr bge 4 ,
+.Xr bxe 4 ,
+.Xr cxgb 4 ,
+.Xr em 4 ,
+.Xr igb 4 ,
+.Xr ix 4 ,
+.Xr mlx4en 4 ,
+.Xr re 4 ,
+.Xr vtnet 4 .
+.Sh SEE ALSO
+.Xr decryptcore 8 ,
+.Xr dumpon 8 ,
+.Xr savecore 8
+.Sh HISTORY
+.Nm
+client support first appeared in
+.Fx 12.0 .
+.Sh BUGS
+Only IPv4 is supported.
+.Pp
+.Nm
+may only be used after the kernel has panicked.

Modified: head/sys/conf/NOTES
==============================================================================
--- head/sys/conf/NOTES	Sun May  6 00:22:38 2018	(r333282)
+++ head/sys/conf/NOTES	Sun May  6 00:38:29 2018	(r333283)
@@ -1025,6 +1025,10 @@ options 	TCP_SIGNATURE		#include support for RFC 2385
 # a smooth scheduling of the traffic.
 options 	DUMMYNET
 
+# The NETDUMP option enables netdump(4) client support in the kernel.
+# This allows a panicking kernel to transmit a kernel dump to a remote host.
+options 	NETDUMP
+
 #####################################################################
 # FILESYSTEM OPTIONS
 

Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files	Sun May  6 00:22:38 2018	(r333282)
+++ head/sys/conf/files	Sun May  6 00:38:29 2018	(r333283)
@@ -4372,6 +4372,7 @@ netinet/libalias/alias_mod.c	optional libalias | netgr
 netinet/libalias/alias_proxy.c	optional libalias inet | netgraph_nat inet
 netinet/libalias/alias_util.c	optional libalias inet | netgraph_nat inet
 netinet/libalias/alias_sctp.c	optional libalias inet | netgraph_nat inet
+netinet/netdump/netdump_client.c optional inet netdump
 netinet6/dest6.c		optional inet6
 netinet6/frag6.c		optional inet6
 netinet6/icmp6.c		optional inet6

Modified: head/sys/conf/options
==============================================================================
--- head/sys/conf/options	Sun May  6 00:22:38 2018	(r333282)
+++ head/sys/conf/options	Sun May  6 00:38:29 2018	(r333283)
@@ -313,6 +313,9 @@ NFS_ROOT	opt_nfsroot.h
 # SMB/CIFS requester
 NETSMB		opt_netsmb.h
 
+# Enable netdump(4) client support.
+NETDUMP 	opt_global.h
+
 # Options used only in subr_param.c.
 HZ		opt_param.h
 MAXFILES	opt_param.h

Modified: head/sys/net/if.c
==============================================================================
--- head/sys/net/if.c	Sun May  6 00:22:38 2018	(r333282)
+++ head/sys/net/if.c	Sun May  6 00:38:29 2018	(r333283)
@@ -87,6 +87,7 @@
 #include <netinet/ip_carp.h>
 #ifdef INET
 #include <netinet/if_ether.h>
+#include <netinet/netdump/netdump.h>
 #endif /* INET */
 #ifdef INET6
 #include <netinet6/in6_var.h>
@@ -2769,6 +2770,9 @@ ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data,
 		if (error == 0) {
 			getmicrotime(&ifp->if_lastchange);
 			rt_ifmsg(ifp);
+#ifdef INET
+			NETDUMP_REINIT(ifp);
+#endif
 		}
 		/*
 		 * If the link MTU changed, do network layer specific procedure.

Modified: head/sys/net/if_var.h
==============================================================================
--- head/sys/net/if_var.h	Sun May  6 00:22:38 2018	(r333282)
+++ head/sys/net/if_var.h	Sun May  6 00:38:29 2018	(r333283)
@@ -70,6 +70,7 @@ struct	route;			/* if_output */
 struct	vnet;
 struct	ifmedia;
 struct	netmap_adapter;
+struct	netdump_methods;
 
 #ifdef _KERNEL
 #include <sys/mbuf.h>		/* ifqueue only? */
@@ -367,6 +368,11 @@ struct ifnet {
 
 	/* Ethernet PCP */
 	uint8_t if_pcp;
+
+	/*
+	 * Netdump hooks to be called while dumping.
+	 */
+	struct netdump_methods *if_netdump_methods;
 
 	/*
 	 * Spare fields to be added before branching a stable branch, so

Added: head/sys/netinet/netdump/netdump.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/netinet/netdump/netdump.h	Sun May  6 00:38:29 2018	(r333283)
@@ -0,0 +1,130 @@
+/*-
+ * 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$
+ */
+
+#ifndef _NETINET_NETDUMP_H_
+#define	_NETINET_NETDUMP_H_
+
+#include <sys/types.h>
+#include <sys/disk.h>
+#include <sys/ioccom.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+
+#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_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;
+
+struct netdump_conf {
+	struct diocskerneldump_arg ndc_kda;
+	char		ndc_iface[IFNAMSIZ];
+	struct in_addr	ndc_server;
+	struct in_addr	ndc_client;
+	struct in_addr	ndc_gateway;
+};
+
+#define	_PATH_NETDUMP	"/dev/netdump"
+
+#define	NETDUMPGCONF	_IOR('n', 1, struct netdump_conf)
+#define	NETDUMPSCONF	_IOW('n', 2, struct netdump_conf)
+
+#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_ */

Added: head/sys/netinet/netdump/netdump_client.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/netinet/netdump/netdump_client.c	Sun May  6 00:38:29 2018	(r333283)
@@ -0,0 +1,1296 @@
+/*-
+ * 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.
+ */
+
+/*
+ * netdump_client.c
+ * FreeBSD subsystem supporting netdump network dumps.
+ * A dedicated server must be running to accept client dumps.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/disk.h>
+#include <sys/endian.h>
+#include <sys/kernel.h>
+#include <sys/kerneldump.h>
+#include <sys/mbuf.h>
+#include <sys/module.h>
+#include <sys/priv.h>
+#include <sys/proc.h>
+#include <sys/protosw.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+#include <sys/systm.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 <netinet/netdump/netdump.h>
+
+#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 netdump_conf *);
+static int	 netdump_dumper(void *priv __unused, void *virtual,
+		    vm_offset_t physical __unused, off_t offset, size_t length);
+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 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);
+
+/* 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);
+
+/*
+ * Times to poll the NIC (0.5ms each poll) before assuming packetloss
+ * occurred (default to 1s).
+ */
+static int nd_polls = 2000;
+
+/* Times to retransmit lost packets. */
+static int nd_retries = 10;
+
+/* Number of ARP retries. */
+static int nd_arp_retries = 3;
+
+/* Configuration parameters. */
+static struct netdump_conf nd_conf;
+#define	nd_server	nd_conf.ndc_server
+#define	nd_client	nd_conf.ndc_client
+#define	nd_gateway	nd_conf.ndc_gateway
+
+/* General dynamic settings. */
+static struct ether_addr nd_gw_mac;
+static struct ifnet *nd_ifp;
+static uint16_t nd_server_port = NETDUMP_PORT;
+
+FEATURE(netdump, "Netdump client support");
+
+static SYSCTL_NODE(_net, OID_AUTO, netdump, CTLFLAG_RD, NULL,
+    "netdump parameters");
+
+static int nd_debug;
+SYSCTL_INT(_net_netdump, OID_AUTO, debug, CTLFLAG_RWTUN,
+    &nd_debug, 0,
+    "Debug message verbosity");
+static int nd_enabled;
+SYSCTL_INT(_net_netdump, OID_AUTO, enabled, CTLFLAG_RD,
+    &nd_enabled, 0,
+    "netdump configuration status");
+static char nd_path[MAXPATHLEN];
+SYSCTL_STRING(_net_netdump, OID_AUTO, path, CTLFLAG_RW,
+    nd_path, sizeof(nd_path),
+    "Server path for output files");
+
+/*
+ * 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(nd_ifp != NULL);
+
+	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(nd_ifp != NULL);
+
+	/* 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(nd_ifp != NULL);
+
+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 (((ntohl(ip->ip_dst.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET ||
+	    (ntohl(ip->ip_src.s_addr) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET) &&
+	    (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;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201805060038.w460cUTZ079439>