2 * Copyright (c) 2005-2014 Sandvine Incorporated. All rights reserved.
3 * Copyright (c) 2000 Darrell Anderson
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * FreeBSD subsystem supporting netdump network dumps.
31 * A dedicated server must be running to accept client dumps.
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
39 #include <sys/param.h>
42 #include <sys/endian.h>
43 #include <sys/eventhandler.h>
45 #include <sys/kernel.h>
46 #include <sys/kerneldump.h>
48 #include <sys/module.h>
51 #include <sys/protosw.h>
52 #include <sys/socket.h>
53 #include <sys/sysctl.h>
54 #include <sys/syslog.h>
55 #include <sys/systm.h>
59 #include <ddb/db_lex.h>
62 #include <net/ethernet.h>
64 #include <net/if_arp.h>
65 #include <net/if_dl.h>
66 #include <net/if_types.h>
67 #include <net/if_var.h>
68 #include <net/debugnet.h>
70 #include <netinet/in.h>
71 #include <netinet/in_systm.h>
72 #include <netinet/in_var.h>
73 #include <netinet/ip.h>
74 #include <netinet/ip_var.h>
75 #include <netinet/ip_options.h>
76 #include <netinet/udp.h>
77 #include <netinet/udp_var.h>
78 #include <netinet/netdump/netdump.h>
80 #include <machine/in_cksum.h>
81 #include <machine/pcb.h>
83 #define NETDDEBUGV(f, ...) do { \
85 printf(("%s: " f), __func__, ## __VA_ARGS__); \
88 static int netdump_configure(struct diocskerneldump_arg *,
90 static int netdump_dumper(void *priv __unused, void *virtual,
91 vm_offset_t physical __unused, off_t offset, size_t length);
92 static bool netdump_enabled(void);
93 static int netdump_enabled_sysctl(SYSCTL_HANDLER_ARGS);
94 static int netdump_ioctl(struct cdev *dev __unused, u_long cmd,
95 caddr_t addr, int flags __unused, struct thread *td);
96 static int netdump_modevent(module_t mod, int type, void *priv);
97 static int netdump_start(struct dumperinfo *di);
98 static void netdump_unconfigure(void);
100 /* Must be at least as big as the chunks dumpsys() gives us. */
101 static unsigned char nd_buf[MAXDUMPPGS * PAGE_SIZE];
102 static int dump_failed;
104 /* Configuration parameters. */
106 char ndc_iface[IFNAMSIZ];
107 union kd_ip ndc_server;
108 union kd_ip ndc_client;
109 union kd_ip ndc_gateway;
112 struct debugnet_pcb *nd_pcb;
116 #define nd_server nd_conf.ndc_server.in4
117 #define nd_client nd_conf.ndc_client.in4
118 #define nd_gateway nd_conf.ndc_gateway.in4
120 /* General dynamic settings. */
121 static struct sx nd_conf_lk;
122 SX_SYSINIT(nd_conf, &nd_conf_lk, "netdump configuration lock");
123 #define NETDUMP_WLOCK() sx_xlock(&nd_conf_lk)
124 #define NETDUMP_WUNLOCK() sx_xunlock(&nd_conf_lk)
125 #define NETDUMP_RLOCK() sx_slock(&nd_conf_lk)
126 #define NETDUMP_RUNLOCK() sx_sunlock(&nd_conf_lk)
127 #define NETDUMP_ASSERT_WLOCKED() sx_assert(&nd_conf_lk, SA_XLOCKED)
128 #define NETDUMP_ASSERT_LOCKED() sx_assert(&nd_conf_lk, SA_LOCKED)
129 static struct ifnet *nd_ifp;
130 static eventhandler_tag nd_detach_cookie;
132 FEATURE(netdump, "Netdump client support");
134 static SYSCTL_NODE(_net, OID_AUTO, netdump, CTLFLAG_RD, NULL,
135 "netdump parameters");
138 SYSCTL_INT(_net_netdump, OID_AUTO, debug, CTLFLAG_RWTUN,
140 "Debug message verbosity");
141 SYSCTL_PROC(_net_netdump, OID_AUTO, enabled, CTLFLAG_RD | CTLTYPE_INT, NULL, 0,
142 netdump_enabled_sysctl, "I", "netdump configuration status");
143 static char nd_path[MAXPATHLEN];
144 SYSCTL_STRING(_net_netdump, OID_AUTO, path, CTLFLAG_RW,
145 nd_path, sizeof(nd_path),
146 "Server path for output files");
148 * The following three variables were moved to debugnet(4), but these knobs
149 * were retained as aliases.
151 SYSCTL_INT(_net_netdump, OID_AUTO, polls, CTLFLAG_RWTUN,
153 "Number of times to poll before assuming packet loss (0.5ms per poll)");
154 SYSCTL_INT(_net_netdump, OID_AUTO, retries, CTLFLAG_RWTUN,
155 &debugnet_nretries, 0,
156 "Number of retransmit attempts before giving up");
157 SYSCTL_INT(_net_netdump, OID_AUTO, arp_retries, CTLFLAG_RWTUN,
158 &debugnet_arp_nretries, 0,
159 "Number of ARP attempts before giving up");
161 static bool nd_is_enabled;
163 netdump_enabled(void)
166 NETDUMP_ASSERT_LOCKED();
167 return (nd_is_enabled);
171 netdump_set_enabled(bool status)
174 NETDUMP_ASSERT_LOCKED();
175 nd_is_enabled = status;
179 netdump_enabled_sysctl(SYSCTL_HANDLER_ARGS)
184 en = netdump_enabled();
187 error = SYSCTL_OUT(req, &en, sizeof(en));
188 if (error != 0 || req->newptr == NULL)
194 * Dumping specific primitives.
198 * Flush any buffered vmcore data.
201 netdump_flush_buf(void)
206 if (nd_conf.nd_buf_len != 0) {
207 struct debugnet_proto_aux auxdata = {
208 .dp_offset_start = nd_conf.nd_tx_off,
210 error = debugnet_send(nd_conf.nd_pcb, DEBUGNET_DATA, nd_buf,
211 nd_conf.nd_buf_len, &auxdata);
213 nd_conf.nd_buf_len = 0;
219 * Callback from dumpsys() to dump a chunk of memory.
220 * Copies it out to our static buffer then sends it across the network.
221 * Detects the initial KDH and makes sure it is given a special packet type.
224 * priv Unused. Optional private pointer.
225 * virtual Virtual address (where to read the data from)
226 * physical Unused. Physical memory address.
227 * offset Offset from start of core file
235 netdump_dumper(void *priv __unused, void *virtual,
236 vm_offset_t physical __unused, off_t offset, size_t length)
240 NETDDEBUGV("netdump_dumper(NULL, %p, NULL, %ju, %zu)\n",
241 virtual, (uintmax_t)offset, length);
243 if (virtual == NULL) {
244 error = netdump_flush_buf();
248 if (dump_failed != 0)
249 printf("failed to dump the kernel core\n");
251 debugnet_sendempty(nd_conf.nd_pcb, DEBUGNET_FINISHED) != 0)
252 printf("failed to close the transaction\n");
254 printf("\nnetdump finished.\n");
255 debugnet_free(nd_conf.nd_pcb);
256 nd_conf.nd_pcb = NULL;
259 if (length > sizeof(nd_buf))
262 if (nd_conf.nd_buf_len + length > sizeof(nd_buf) ||
263 (nd_conf.nd_buf_len != 0 && nd_conf.nd_tx_off +
264 nd_conf.nd_buf_len != offset)) {
265 error = netdump_flush_buf();
270 nd_conf.nd_tx_off = offset;
273 memmove(nd_buf + nd_conf.nd_buf_len, virtual, length);
274 nd_conf.nd_buf_len += length;
280 * Perform any initalization needed prior to transmitting the kernel core.
283 netdump_start(struct dumperinfo *di)
285 struct debugnet_conn_params dcp;
286 struct debugnet_pcb *pcb;
287 char buf[INET_ADDRSTRLEN];
292 /* Check if the dumping is allowed to continue. */
293 if (!netdump_enabled())
296 if (panicstr == NULL) {
298 "netdump_start: netdump may only be used after a panic\n");
302 memset(&dcp, 0, sizeof(dcp));
304 if (nd_server.s_addr == INADDR_ANY) {
305 printf("netdump_start: can't netdump; no server IP given\n");
309 /* We start dumping at offset 0. */
314 dcp.dc_client = nd_client.s_addr;
315 dcp.dc_server = nd_server.s_addr;
316 dcp.dc_gateway = nd_gateway.s_addr;
318 dcp.dc_herald_port = NETDUMP_PORT;
319 dcp.dc_client_port = NETDUMP_ACKPORT;
321 dcp.dc_herald_data = nd_path;
322 dcp.dc_herald_datalen = (nd_path[0] == 0) ? 0 : strlen(nd_path) + 1;
324 error = debugnet_connect(&dcp, &pcb);
326 printf("failed to contact netdump server\n");
327 /* Squash debugnet to something the dumper code understands. */
331 printf("netdumping to %s (%6D)\n", inet_ntoa_r(nd_server, buf),
332 debugnet_get_gw_mac(pcb), ":");
333 nd_conf.nd_pcb = pcb;
338 netdump_write_headers(struct dumperinfo *di, struct kerneldumpheader *kdh,
339 void *key, uint32_t keysize)
343 error = netdump_flush_buf();
346 memcpy(nd_buf, kdh, sizeof(*kdh));
347 error = debugnet_send(nd_conf.nd_pcb, NETDUMP_KDH, nd_buf,
349 if (error == 0 && keysize > 0) {
350 if (keysize > sizeof(nd_buf))
352 memcpy(nd_buf, key, keysize);
353 error = debugnet_send(nd_conf.nd_pcb, NETDUMP_EKCD_KEY, nd_buf,
363 static struct cdevsw netdump_cdevsw = {
364 .d_version = D_VERSION,
365 .d_ioctl = netdump_ioctl,
369 static struct cdev *netdump_cdev;
372 netdump_unconfigure(void)
374 struct diocskerneldump_arg kda;
376 NETDUMP_ASSERT_WLOCKED();
377 KASSERT(netdump_enabled(), ("%s: not enabled", __func__));
379 bzero(&kda, sizeof(kda));
380 kda.kda_index = KDA_REMOVE_DEV;
381 (void)dumper_remove(nd_conf.ndc_iface, &kda);
386 netdump_set_enabled(false);
388 log(LOG_WARNING, "netdump: Lost configured interface %s\n",
391 bzero(&nd_conf, sizeof(nd_conf));
395 netdump_ifdetach(void *arg __unused, struct ifnet *ifp)
400 netdump_unconfigure();
405 * td of NULL is a sentinel value that indicates a kernel caller (ddb(4) or
406 * modload-based tunable parameters).
409 netdump_configure(struct diocskerneldump_arg *conf, struct thread *td)
413 NETDUMP_ASSERT_WLOCKED();
415 if (conf->kda_iface[0] != 0) {
416 if (td != NULL && !IS_DEFAULT_VNET(TD_TO_VNET(td)))
419 ifp = ifunit_ref(conf->kda_iface);
427 netdump_set_enabled(true);
429 #define COPY_SIZED(elm) do { \
430 _Static_assert(sizeof(nd_conf.ndc_ ## elm) == \
431 sizeof(conf->kda_ ## elm), "elm " __XSTRING(elm) " mismatch"); \
432 memcpy(&nd_conf.ndc_ ## elm, &conf->kda_ ## elm, \
433 sizeof(nd_conf.ndc_ ## elm)); \
446 * ioctl(2) handler for the netdump device. This is currently only used to
447 * register netdump as a dump device.
451 * cmd, The ioctl to be handled.
452 * addr, The parameter for the ioctl.
454 * td, The thread invoking this ioctl.
457 * 0 on success, and an errno value on failure.
460 netdump_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr,
461 int flags __unused, struct thread *td)
463 struct diocskerneldump_arg kda_copy, *conf;
464 struct dumperinfo dumper;
465 uint8_t *encryptedkey;
467 #ifdef COMPAT_FREEBSD11
470 #ifdef COMPAT_FREEBSD12
471 struct diocskerneldump_arg_freebsd12 *kda12;
472 struct netdump_conf_freebsd12 *conf12;
480 #ifdef COMPAT_FREEBSD11
481 case DIOCSKERNELDUMP_FREEBSD11:
482 gone_in(13, "11.x ABI compatibility");
488 if (netdump_enabled())
489 netdump_unconfigure();
492 #ifdef COMPAT_FREEBSD12
494 * Used by dumpon(8) in 12.x for clearing previous
495 * configuration -- then NETDUMPSCONF_FREEBSD12 is used to
496 * actually configure netdump.
498 case DIOCSKERNELDUMP_FREEBSD12:
499 gone_in(14, "12.x ABI compatibility");
501 kda12 = (void *)addr;
502 if (kda12->kda12_enable) {
506 if (netdump_enabled())
507 netdump_unconfigure();
510 case NETDUMPGCONF_FREEBSD12:
511 gone_in(14, "FreeBSD 12.x ABI compat");
512 conf12 = (void *)addr;
514 if (!netdump_enabled()) {
518 if (nd_conf.ndc_af != AF_INET) {
524 strlcpy(conf12->ndc12_iface, nd_ifp->if_xname,
525 sizeof(conf12->ndc12_iface));
526 memcpy(&conf12->ndc12_server, &nd_server,
527 sizeof(conf12->ndc12_server));
528 memcpy(&conf12->ndc12_client, &nd_client,
529 sizeof(conf12->ndc12_client));
530 memcpy(&conf12->ndc12_gateway, &nd_gateway,
531 sizeof(conf12->ndc12_gateway));
534 case DIOCGKERNELDUMP:
537 * For now, index is ignored; netdump doesn't support multiple
538 * configurations (yet).
540 if (!netdump_enabled()) {
547 strlcpy(conf->kda_iface, nd_ifp->if_xname,
548 sizeof(conf->kda_iface));
549 memcpy(&conf->kda_server, &nd_server, sizeof(nd_server));
550 memcpy(&conf->kda_client, &nd_client, sizeof(nd_client));
551 memcpy(&conf->kda_gateway, &nd_gateway, sizeof(nd_gateway));
552 conf->kda_af = nd_conf.ndc_af;
556 #ifdef COMPAT_FREEBSD12
557 case NETDUMPSCONF_FREEBSD12:
558 gone_in(14, "FreeBSD 12.x ABI compat");
560 conf12 = (struct netdump_conf_freebsd12 *)addr;
562 _Static_assert(offsetof(struct diocskerneldump_arg, kda_server)
563 == offsetof(struct netdump_conf_freebsd12, ndc12_server),
564 "simplifying assumption");
566 memset(&kda_copy, 0, sizeof(kda_copy));
567 memcpy(&kda_copy, conf12,
568 offsetof(struct diocskerneldump_arg, kda_server));
570 /* 12.x ABI could only configure IPv4 (INET) netdump. */
571 kda_copy.kda_af = AF_INET;
572 memcpy(&kda_copy.kda_server.in4, &conf12->ndc12_server,
573 sizeof(struct in_addr));
574 memcpy(&kda_copy.kda_client.in4, &conf12->ndc12_client,
575 sizeof(struct in_addr));
576 memcpy(&kda_copy.kda_gateway.in4, &conf12->ndc12_gateway,
577 sizeof(struct in_addr));
580 (conf12->ndc12_kda.kda12_enable ? 0 : KDA_REMOVE_ALL);
583 explicit_bzero(conf12, sizeof(*conf12));
586 case DIOCSKERNELDUMP:
588 if (cmd == DIOCSKERNELDUMP) {
590 memcpy(&kda_copy, conf, sizeof(kda_copy));
592 /* Netdump only supports IP4 at this time. */
593 if (conf->kda_af != AF_INET) {
594 error = EPROTONOSUPPORT;
598 conf->kda_iface[sizeof(conf->kda_iface) - 1] = '\0';
599 if (conf->kda_index == KDA_REMOVE ||
600 conf->kda_index == KDA_REMOVE_DEV ||
601 conf->kda_index == KDA_REMOVE_ALL) {
602 if (netdump_enabled())
603 netdump_unconfigure();
604 if (conf->kda_index == KDA_REMOVE_ALL)
605 error = dumper_remove(NULL, conf);
609 error = netdump_configure(conf, td);
613 if (conf->kda_encryption != KERNELDUMP_ENC_NONE) {
614 if (conf->kda_encryptedkeysize <= 0 ||
615 conf->kda_encryptedkeysize >
616 KERNELDUMP_ENCKEY_MAX_SIZE) {
620 encryptedkey = malloc(conf->kda_encryptedkeysize,
622 error = copyin(conf->kda_encryptedkey, encryptedkey,
623 conf->kda_encryptedkeysize);
625 free(encryptedkey, M_TEMP);
629 conf->kda_encryptedkey = encryptedkey;
632 memset(&dumper, 0, sizeof(dumper));
633 dumper.dumper_start = netdump_start;
634 dumper.dumper_hdr = netdump_write_headers;
635 dumper.dumper = netdump_dumper;
637 dumper.blocksize = NETDUMP_DATASIZE;
638 dumper.maxiosize = MAXDUMPPGS * PAGE_SIZE;
639 dumper.mediaoffset = 0;
640 dumper.mediasize = 0;
642 error = dumper_insert(&dumper, conf->kda_iface, conf);
643 if (encryptedkey != NULL) {
644 explicit_bzero(encryptedkey,
645 conf->kda_encryptedkeysize);
646 free(encryptedkey, M_TEMP);
649 netdump_unconfigure();
655 explicit_bzero(&kda_copy, sizeof(kda_copy));
657 explicit_bzero(conf, sizeof(*conf));
663 * Called upon system init or kld load. Initializes the netdump parameters to
664 * sane defaults (locates the first available NIC and uses the first IPv4 IP on
665 * that card as the client IP). Leaves the server IP unconfigured.
669 * what, The module event type.
673 * int, An errno value if an error occured, 0 otherwise.
676 netdump_modevent(module_t mod __unused, int what, void *priv __unused)
678 struct diocskerneldump_arg conf;
685 error = make_dev_p(MAKEDEV_WAITOK, &netdump_cdev,
686 &netdump_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "netdump");
690 nd_detach_cookie = EVENTHANDLER_REGISTER(ifnet_departure_event,
691 netdump_ifdetach, NULL, EVENTHANDLER_PRI_ANY);
693 if ((arg = kern_getenv("net.dump.iface")) != NULL) {
694 strlcpy(conf.kda_iface, arg, sizeof(conf.kda_iface));
697 if ((arg = kern_getenv("net.dump.server")) != NULL) {
698 inet_aton(arg, &conf.kda_server.in4);
701 if ((arg = kern_getenv("net.dump.client")) != NULL) {
702 inet_aton(arg, &conf.kda_client.in4);
705 if ((arg = kern_getenv("net.dump.gateway")) != NULL) {
706 inet_aton(arg, &conf.kda_gateway.in4);
709 conf.kda_af = AF_INET;
711 /* Ignore errors; we print a message to the console. */
713 (void)netdump_configure(&conf, NULL);
719 if (netdump_enabled()) {
720 printf("netdump: disabling dump device for unload\n");
721 netdump_unconfigure();
724 destroy_dev(netdump_cdev);
725 EVENTHANDLER_DEREGISTER(ifnet_departure_event,
735 static moduledata_t netdump_mod = {
741 MODULE_VERSION(netdump, 1);
742 DECLARE_MODULE(netdump, netdump_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
746 * Usage: netdump -s <server> [-g <gateway] -c <localip> -i <interface>
748 * Order is not significant.
750 * Currently, this command does not support configuring encryption or
753 DB_FUNC(netdump, db_netdump_cmd, db_cmd_table, CS_OWN, NULL)
755 static struct diocskerneldump_arg conf;
756 static char blockbuf[NETDUMP_DATASIZE];
758 struct dumperinfo di;
759 /* For valid di_devname. */
760 char di_buf[sizeof(struct dumperinfo) + 1];
763 struct debugnet_ddb_config params;
766 error = debugnet_parse_ddb_cmd("netdump", ¶ms);
768 db_printf("Error configuring netdump: %d\n", error);
772 /* Translate to a netdump dumper config. */
773 memset(&conf, 0, sizeof(conf));
775 if (params.dd_ifp != NULL)
776 strlcpy(conf.kda_iface, if_name(params.dd_ifp),
777 sizeof(conf.kda_iface));
779 conf.kda_af = AF_INET;
780 conf.kda_server.in4 = (struct in_addr) { params.dd_server };
781 if (params.dd_has_client)
782 conf.kda_client.in4 = (struct in_addr) { params.dd_client };
784 conf.kda_client.in4 = (struct in_addr) { INADDR_ANY };
785 if (params.dd_has_gateway)
786 conf.kda_gateway.in4 = (struct in_addr) { params.dd_gateway };
788 conf.kda_gateway.in4 = (struct in_addr) { INADDR_ANY };
790 /* Set the global netdump config to these options. */
791 error = netdump_configure(&conf, NULL);
793 db_printf("Error enabling netdump: %d\n", error);
797 /* Fake the generic dump configuration list entry to avoid malloc. */
798 memset(&u.di_buf, 0, sizeof(u.di_buf));
799 u.di.dumper_start = netdump_start;
800 u.di.dumper_hdr = netdump_write_headers;
801 u.di.dumper = netdump_dumper;
803 u.di.blocksize = NETDUMP_DATASIZE;
804 u.di.maxiosize = MAXDUMPPGS * PAGE_SIZE;
805 u.di.mediaoffset = 0;
807 u.di.blockbuf = blockbuf;
809 dumper_ddb_insert(&u.di);
811 error = doadump(false);
813 dumper_ddb_remove(&u.di);
815 db_printf("Cannot dump: %d\n", error);