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>
37 #include <sys/param.h>
40 #include <sys/endian.h>
41 #include <sys/eventhandler.h>
43 #include <sys/kernel.h>
44 #include <sys/kerneldump.h>
46 #include <sys/module.h>
49 #include <sys/protosw.h>
50 #include <sys/socket.h>
51 #include <sys/sysctl.h>
52 #include <sys/syslog.h>
53 #include <sys/systm.h>
57 #include <ddb/db_lex.h>
60 #include <net/ethernet.h>
62 #include <net/if_arp.h>
63 #include <net/if_dl.h>
64 #include <net/if_types.h>
65 #include <net/if_var.h>
66 #include <net/if_private.h>
67 #include <net/debugnet.h>
69 #include <netinet/in.h>
70 #include <netinet/in_systm.h>
71 #include <netinet/in_var.h>
72 #include <netinet/ip.h>
73 #include <netinet/ip_var.h>
74 #include <netinet/ip_options.h>
75 #include <netinet/udp.h>
76 #include <netinet/udp_var.h>
77 #include <netinet/netdump/netdump.h>
79 #include <machine/in_cksum.h>
80 #include <machine/pcb.h>
82 #define NETDDEBUGV(f, ...) do { \
84 printf(("%s: " f), __func__, ## __VA_ARGS__); \
87 static void netdump_cleanup(void);
88 static int netdump_configure(struct diocskerneldump_arg *,
90 static int netdump_dumper(void *priv __unused, void *virtual,
91 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, void *key,
99 static void netdump_unconfigure(void);
101 /* Must be at least as big as the chunks dumpsys() gives us. */
102 static unsigned char nd_buf[MAXDUMPPGS * PAGE_SIZE];
103 static int dump_failed;
105 /* Configuration parameters. */
107 char ndc_iface[IFNAMSIZ];
108 union kd_ip ndc_server;
109 union kd_ip ndc_client;
110 union kd_ip ndc_gateway;
113 struct debugnet_pcb *nd_pcb;
117 #define nd_server nd_conf.ndc_server.in4
118 #define nd_client nd_conf.ndc_client.in4
119 #define nd_gateway nd_conf.ndc_gateway.in4
121 /* General dynamic settings. */
122 static struct sx nd_conf_lk;
123 SX_SYSINIT(nd_conf, &nd_conf_lk, "netdump configuration lock");
124 #define NETDUMP_WLOCK() sx_xlock(&nd_conf_lk)
125 #define NETDUMP_WUNLOCK() sx_xunlock(&nd_conf_lk)
126 #define NETDUMP_RLOCK() sx_slock(&nd_conf_lk)
127 #define NETDUMP_RUNLOCK() sx_sunlock(&nd_conf_lk)
128 #define NETDUMP_ASSERT_WLOCKED() sx_assert(&nd_conf_lk, SA_XLOCKED)
129 #define NETDUMP_ASSERT_LOCKED() sx_assert(&nd_conf_lk, SA_LOCKED)
130 static struct ifnet *nd_ifp;
131 static eventhandler_tag nd_detach_cookie;
133 FEATURE(netdump, "Netdump client support");
135 static SYSCTL_NODE(_net, OID_AUTO, netdump, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
136 "netdump parameters");
139 SYSCTL_INT(_net_netdump, OID_AUTO, debug, CTLFLAG_RWTUN,
141 "Debug message verbosity");
142 SYSCTL_PROC(_net_netdump, OID_AUTO, enabled,
143 CTLFLAG_RD | CTLTYPE_INT | CTLFLAG_MPSAFE, NULL, 0,
144 netdump_enabled_sysctl, "I",
145 "netdump configuration status");
146 static char nd_path[MAXPATHLEN];
147 SYSCTL_STRING(_net_netdump, OID_AUTO, path, CTLFLAG_RW,
148 nd_path, sizeof(nd_path),
149 "Server path for output files");
151 * The following three variables were moved to debugnet(4), but these knobs
152 * were retained as aliases.
154 SYSCTL_INT(_net_netdump, OID_AUTO, polls, CTLFLAG_RWTUN,
156 "Number of times to poll before assuming packet loss (0.5ms per poll)");
157 SYSCTL_INT(_net_netdump, OID_AUTO, retries, CTLFLAG_RWTUN,
158 &debugnet_nretries, 0,
159 "Number of retransmit attempts before giving up");
160 SYSCTL_INT(_net_netdump, OID_AUTO, arp_retries, CTLFLAG_RWTUN,
161 &debugnet_arp_nretries, 0,
162 "Number of ARP attempts before giving up");
164 static bool nd_is_enabled;
166 netdump_enabled(void)
169 NETDUMP_ASSERT_LOCKED();
170 return (nd_is_enabled);
174 netdump_set_enabled(bool status)
177 NETDUMP_ASSERT_LOCKED();
178 nd_is_enabled = status;
182 netdump_enabled_sysctl(SYSCTL_HANDLER_ARGS)
187 en = netdump_enabled();
190 error = SYSCTL_OUT(req, &en, sizeof(en));
191 if (error != 0 || req->newptr == NULL)
197 * Dumping specific primitives.
201 * Flush any buffered vmcore data.
204 netdump_flush_buf(void)
209 if (nd_conf.nd_buf_len != 0) {
210 struct debugnet_proto_aux auxdata = {
211 .dp_offset_start = nd_conf.nd_tx_off,
213 error = debugnet_send(nd_conf.nd_pcb, DEBUGNET_DATA, nd_buf,
214 nd_conf.nd_buf_len, &auxdata);
216 nd_conf.nd_buf_len = 0;
222 * Callback from dumpsys() to dump a chunk of memory.
223 * Copies it out to our static buffer then sends it across the network.
224 * Detects the initial KDH and makes sure it is given a special packet type.
227 * priv Unused. Optional private pointer.
228 * virtual Virtual address (where to read the data from)
229 * offset Offset from start of core file
237 netdump_dumper(void *priv __unused, void *virtual, off_t offset, size_t length)
241 NETDDEBUGV("netdump_dumper(NULL, %p, NULL, %ju, %zu)\n",
242 virtual, (uintmax_t)offset, length);
244 if (virtual == NULL) {
245 error = netdump_flush_buf();
249 if (dump_failed != 0)
250 printf("failed to dump the kernel core\n");
252 debugnet_sendempty(nd_conf.nd_pcb, DEBUGNET_FINISHED) != 0)
253 printf("failed to close the transaction\n");
255 printf("\nnetdump finished.\n");
259 if (length > sizeof(nd_buf)) {
264 if (nd_conf.nd_buf_len + length > sizeof(nd_buf) ||
265 (nd_conf.nd_buf_len != 0 && nd_conf.nd_tx_off +
266 nd_conf.nd_buf_len != offset)) {
267 error = netdump_flush_buf();
273 nd_conf.nd_tx_off = offset;
276 memmove(nd_buf + nd_conf.nd_buf_len, virtual, length);
277 nd_conf.nd_buf_len += length;
283 * Perform any initialization needed prior to transmitting the kernel core.
286 netdump_start(struct dumperinfo *di, void *key, uint32_t keysize)
288 struct debugnet_conn_params dcp;
289 struct debugnet_pcb *pcb;
290 char buf[INET_ADDRSTRLEN];
295 /* Check if the dumping is allowed to continue. */
296 if (!netdump_enabled())
299 if (!KERNEL_PANICKED()) {
301 "netdump_start: netdump may only be used after a panic\n");
305 memset(&dcp, 0, sizeof(dcp));
307 if (nd_server.s_addr == INADDR_ANY) {
308 printf("netdump_start: can't netdump; no server IP given\n");
312 /* We start dumping at offset 0. */
317 dcp.dc_client = nd_client.s_addr;
318 dcp.dc_server = nd_server.s_addr;
319 dcp.dc_gateway = nd_gateway.s_addr;
321 dcp.dc_herald_port = NETDUMP_PORT;
322 dcp.dc_client_port = NETDUMP_ACKPORT;
324 dcp.dc_herald_data = nd_path;
325 dcp.dc_herald_datalen = (nd_path[0] == 0) ? 0 : strlen(nd_path) + 1;
327 error = debugnet_connect(&dcp, &pcb);
329 printf("failed to contact netdump server\n");
330 /* Squash debugnet to something the dumper code understands. */
334 printf("netdumping to %s (%6D)\n", inet_ntoa_r(nd_server, buf),
335 debugnet_get_gw_mac(pcb), ":");
336 nd_conf.nd_pcb = pcb;
338 /* Send the key before the dump so a partial dump is still usable. */
340 if (keysize > sizeof(nd_buf)) {
341 printf("crypto key is too large (%u)\n", keysize);
345 memcpy(nd_buf, key, keysize);
346 error = debugnet_send(pcb, NETDUMP_EKCD_KEY, nd_buf, keysize,
349 printf("error %d sending crypto key\n", error);
356 /* As above, squash errors. */
364 netdump_write_headers(struct dumperinfo *di, struct kerneldumpheader *kdh)
368 error = netdump_flush_buf();
371 memcpy(nd_buf, kdh, sizeof(*kdh));
372 error = debugnet_send(nd_conf.nd_pcb, NETDUMP_KDH, nd_buf,
381 * Cleanup routine for a possibly failed netdump.
384 netdump_cleanup(void)
386 if (nd_conf.nd_pcb != NULL) {
387 debugnet_free(nd_conf.nd_pcb);
388 nd_conf.nd_pcb = NULL;
396 static struct cdevsw netdump_cdevsw = {
397 .d_version = D_VERSION,
398 .d_ioctl = netdump_ioctl,
402 static struct cdev *netdump_cdev;
405 netdump_unconfigure(void)
407 struct diocskerneldump_arg kda;
409 NETDUMP_ASSERT_WLOCKED();
410 KASSERT(netdump_enabled(), ("%s: not enabled", __func__));
412 bzero(&kda, sizeof(kda));
413 kda.kda_index = KDA_REMOVE_DEV;
414 (void)dumper_remove(nd_conf.ndc_iface, &kda);
419 netdump_set_enabled(false);
421 log(LOG_WARNING, "netdump: Lost configured interface %s\n",
424 bzero(&nd_conf, sizeof(nd_conf));
428 netdump_ifdetach(void *arg __unused, struct ifnet *ifp)
433 netdump_unconfigure();
438 * td of NULL is a sentinel value that indicates a kernel caller (ddb(4) or
439 * modload-based tunable parameters).
442 netdump_configure(struct diocskerneldump_arg *conf, struct thread *td)
446 NETDUMP_ASSERT_WLOCKED();
448 if (conf->kda_iface[0] != 0) {
449 if (td != NULL && !IS_DEFAULT_VNET(TD_TO_VNET(td)))
452 ifp = ifunit_ref(conf->kda_iface);
456 if (!DEBUGNET_SUPPORTED_NIC(ifp)) {
466 netdump_set_enabled(true);
468 #define COPY_SIZED(elm) do { \
469 _Static_assert(sizeof(nd_conf.ndc_ ## elm) == \
470 sizeof(conf->kda_ ## elm), "elm " __XSTRING(elm) " mismatch"); \
471 memcpy(&nd_conf.ndc_ ## elm, &conf->kda_ ## elm, \
472 sizeof(nd_conf.ndc_ ## elm)); \
485 * ioctl(2) handler for the netdump device. This is currently only used to
486 * register netdump as a dump device.
490 * cmd, The ioctl to be handled.
491 * addr, The parameter for the ioctl.
493 * td, The thread invoking this ioctl.
496 * 0 on success, and an errno value on failure.
499 netdump_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr,
500 int flags __unused, struct thread *td)
502 struct diocskerneldump_arg *conf;
503 struct dumperinfo dumper;
504 uint8_t *encryptedkey;
512 case DIOCGKERNELDUMP:
515 * For now, index is ignored; netdump doesn't support multiple
516 * configurations (yet).
518 if (!netdump_enabled()) {
525 strlcpy(conf->kda_iface, nd_ifp->if_xname,
526 sizeof(conf->kda_iface));
527 memcpy(&conf->kda_server, &nd_server, sizeof(nd_server));
528 memcpy(&conf->kda_client, &nd_client, sizeof(nd_client));
529 memcpy(&conf->kda_gateway, &nd_gateway, sizeof(nd_gateway));
530 conf->kda_af = nd_conf.ndc_af;
533 case DIOCSKERNELDUMP:
537 /* Netdump only supports IP4 at this time. */
538 if (conf->kda_af != AF_INET) {
539 error = EPROTONOSUPPORT;
543 conf->kda_iface[sizeof(conf->kda_iface) - 1] = '\0';
544 if (conf->kda_index == KDA_REMOVE ||
545 conf->kda_index == KDA_REMOVE_DEV ||
546 conf->kda_index == KDA_REMOVE_ALL) {
547 if (netdump_enabled())
548 netdump_unconfigure();
549 if (conf->kda_index == KDA_REMOVE_ALL)
550 error = dumper_remove(NULL, conf);
554 error = netdump_configure(conf, td);
558 if (conf->kda_encryption != KERNELDUMP_ENC_NONE) {
559 if (conf->kda_encryptedkeysize <= 0 ||
560 conf->kda_encryptedkeysize >
561 KERNELDUMP_ENCKEY_MAX_SIZE) {
565 encryptedkey = malloc(conf->kda_encryptedkeysize,
567 error = copyin(conf->kda_encryptedkey, encryptedkey,
568 conf->kda_encryptedkeysize);
570 free(encryptedkey, M_TEMP);
574 conf->kda_encryptedkey = encryptedkey;
577 memset(&dumper, 0, sizeof(dumper));
578 dumper.dumper_start = netdump_start;
579 dumper.dumper_hdr = netdump_write_headers;
580 dumper.dumper = netdump_dumper;
582 dumper.blocksize = NETDUMP_DATASIZE;
583 dumper.maxiosize = MAXDUMPPGS * PAGE_SIZE;
584 dumper.mediaoffset = 0;
585 dumper.mediasize = 0;
587 error = dumper_insert(&dumper, conf->kda_iface, conf);
588 zfree(encryptedkey, M_TEMP);
590 netdump_unconfigure();
597 explicit_bzero(conf, sizeof(*conf));
603 * Called upon system init or kld load. Initializes the netdump parameters to
604 * sane defaults (locates the first available NIC and uses the first IPv4 IP on
605 * that card as the client IP). Leaves the server IP unconfigured.
609 * what, The module event type.
613 * int, An errno value if an error occurred, 0 otherwise.
616 netdump_modevent(module_t mod __unused, int what, void *priv __unused)
618 struct diocskerneldump_arg conf;
625 error = make_dev_p(MAKEDEV_WAITOK, &netdump_cdev,
626 &netdump_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "netdump");
630 nd_detach_cookie = EVENTHANDLER_REGISTER(ifnet_departure_event,
631 netdump_ifdetach, NULL, EVENTHANDLER_PRI_ANY);
633 if ((arg = kern_getenv("net.dump.iface")) != NULL) {
634 strlcpy(conf.kda_iface, arg, sizeof(conf.kda_iface));
637 if ((arg = kern_getenv("net.dump.server")) != NULL) {
638 inet_aton(arg, &conf.kda_server.in4);
641 if ((arg = kern_getenv("net.dump.client")) != NULL) {
642 inet_aton(arg, &conf.kda_client.in4);
645 if ((arg = kern_getenv("net.dump.gateway")) != NULL) {
646 inet_aton(arg, &conf.kda_gateway.in4);
649 conf.kda_af = AF_INET;
651 /* Ignore errors; we print a message to the console. */
653 (void)netdump_configure(&conf, NULL);
659 if (netdump_enabled()) {
660 printf("netdump: disabling dump device for unload\n");
661 netdump_unconfigure();
664 destroy_dev(netdump_cdev);
665 EVENTHANDLER_DEREGISTER(ifnet_departure_event,
675 static moduledata_t netdump_mod = {
681 MODULE_VERSION(netdump, 1);
682 DECLARE_MODULE(netdump, netdump_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
686 * Usage: netdump -s <server> [-g <gateway] -c <localip> -i <interface>
688 * Order is not significant.
690 * Currently, this command does not support configuring encryption or
693 DB_COMMAND_FLAGS(netdump, db_netdump_cmd, CS_OWN)
695 static struct diocskerneldump_arg conf;
696 static char blockbuf[NETDUMP_DATASIZE];
698 struct dumperinfo di;
699 /* For valid di_devname. */
700 char di_buf[sizeof(struct dumperinfo) + 1];
703 struct debugnet_ddb_config params;
706 error = debugnet_parse_ddb_cmd("netdump", ¶ms);
708 db_printf("Error configuring netdump: %d\n", error);
712 /* Translate to a netdump dumper config. */
713 memset(&conf, 0, sizeof(conf));
715 if (params.dd_ifp != NULL)
716 strlcpy(conf.kda_iface, if_name(params.dd_ifp),
717 sizeof(conf.kda_iface));
719 conf.kda_af = AF_INET;
720 conf.kda_server.in4 = (struct in_addr) { params.dd_server };
721 if (params.dd_has_client)
722 conf.kda_client.in4 = (struct in_addr) { params.dd_client };
724 conf.kda_client.in4 = (struct in_addr) { INADDR_ANY };
725 if (params.dd_has_gateway)
726 conf.kda_gateway.in4 = (struct in_addr) { params.dd_gateway };
728 conf.kda_gateway.in4 = (struct in_addr) { INADDR_ANY };
730 /* Set the global netdump config to these options. */
731 error = netdump_configure(&conf, NULL);
733 db_printf("Error enabling netdump: %d\n", error);
737 /* Fake the generic dump configuration list entry to avoid malloc. */
738 memset(&u.di_buf, 0, sizeof(u.di_buf));
739 u.di.dumper_start = netdump_start;
740 u.di.dumper_hdr = netdump_write_headers;
741 u.di.dumper = netdump_dumper;
743 u.di.blocksize = NETDUMP_DATASIZE;
744 u.di.maxiosize = MAXDUMPPGS * PAGE_SIZE;
745 u.di.mediaoffset = 0;
747 u.di.blockbuf = blockbuf;
749 dumper_ddb_insert(&u.di);
751 error = doadump(false);
753 dumper_ddb_remove(&u.di);
755 db_printf("Cannot dump: %d\n", error);