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 void netdump_cleanup(void);
89 static int netdump_configure(struct diocskerneldump_arg *,
91 static int netdump_dumper(void *priv __unused, void *virtual,
92 off_t offset, size_t length);
93 static bool netdump_enabled(void);
94 static int netdump_enabled_sysctl(SYSCTL_HANDLER_ARGS);
95 static int netdump_ioctl(struct cdev *dev __unused, u_long cmd,
96 caddr_t addr, int flags __unused, struct thread *td);
97 static int netdump_modevent(module_t mod, int type, void *priv);
98 static int netdump_start(struct dumperinfo *di, void *key,
100 static void netdump_unconfigure(void);
102 /* Must be at least as big as the chunks dumpsys() gives us. */
103 static unsigned char nd_buf[MAXDUMPPGS * PAGE_SIZE];
104 static int dump_failed;
106 /* Configuration parameters. */
108 char ndc_iface[IFNAMSIZ];
109 union kd_ip ndc_server;
110 union kd_ip ndc_client;
111 union kd_ip ndc_gateway;
114 struct debugnet_pcb *nd_pcb;
118 #define nd_server nd_conf.ndc_server.in4
119 #define nd_client nd_conf.ndc_client.in4
120 #define nd_gateway nd_conf.ndc_gateway.in4
122 /* General dynamic settings. */
123 static struct sx nd_conf_lk;
124 SX_SYSINIT(nd_conf, &nd_conf_lk, "netdump configuration lock");
125 #define NETDUMP_WLOCK() sx_xlock(&nd_conf_lk)
126 #define NETDUMP_WUNLOCK() sx_xunlock(&nd_conf_lk)
127 #define NETDUMP_RLOCK() sx_slock(&nd_conf_lk)
128 #define NETDUMP_RUNLOCK() sx_sunlock(&nd_conf_lk)
129 #define NETDUMP_ASSERT_WLOCKED() sx_assert(&nd_conf_lk, SA_XLOCKED)
130 #define NETDUMP_ASSERT_LOCKED() sx_assert(&nd_conf_lk, SA_LOCKED)
131 static struct ifnet *nd_ifp;
132 static eventhandler_tag nd_detach_cookie;
134 FEATURE(netdump, "Netdump client support");
136 static SYSCTL_NODE(_net, OID_AUTO, netdump, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
137 "netdump parameters");
140 SYSCTL_INT(_net_netdump, OID_AUTO, debug, CTLFLAG_RWTUN,
142 "Debug message verbosity");
143 SYSCTL_PROC(_net_netdump, OID_AUTO, enabled,
144 CTLFLAG_RD | CTLTYPE_INT | CTLFLAG_MPSAFE, NULL, 0,
145 netdump_enabled_sysctl, "I",
146 "netdump configuration status");
147 static char nd_path[MAXPATHLEN];
148 SYSCTL_STRING(_net_netdump, OID_AUTO, path, CTLFLAG_RW,
149 nd_path, sizeof(nd_path),
150 "Server path for output files");
152 * The following three variables were moved to debugnet(4), but these knobs
153 * were retained as aliases.
155 SYSCTL_INT(_net_netdump, OID_AUTO, polls, CTLFLAG_RWTUN,
157 "Number of times to poll before assuming packet loss (0.5ms per poll)");
158 SYSCTL_INT(_net_netdump, OID_AUTO, retries, CTLFLAG_RWTUN,
159 &debugnet_nretries, 0,
160 "Number of retransmit attempts before giving up");
161 SYSCTL_INT(_net_netdump, OID_AUTO, arp_retries, CTLFLAG_RWTUN,
162 &debugnet_arp_nretries, 0,
163 "Number of ARP attempts before giving up");
165 static bool nd_is_enabled;
167 netdump_enabled(void)
170 NETDUMP_ASSERT_LOCKED();
171 return (nd_is_enabled);
175 netdump_set_enabled(bool status)
178 NETDUMP_ASSERT_LOCKED();
179 nd_is_enabled = status;
183 netdump_enabled_sysctl(SYSCTL_HANDLER_ARGS)
188 en = netdump_enabled();
191 error = SYSCTL_OUT(req, &en, sizeof(en));
192 if (error != 0 || req->newptr == NULL)
198 * Dumping specific primitives.
202 * Flush any buffered vmcore data.
205 netdump_flush_buf(void)
210 if (nd_conf.nd_buf_len != 0) {
211 struct debugnet_proto_aux auxdata = {
212 .dp_offset_start = nd_conf.nd_tx_off,
214 error = debugnet_send(nd_conf.nd_pcb, DEBUGNET_DATA, nd_buf,
215 nd_conf.nd_buf_len, &auxdata);
217 nd_conf.nd_buf_len = 0;
223 * Callback from dumpsys() to dump a chunk of memory.
224 * Copies it out to our static buffer then sends it across the network.
225 * Detects the initial KDH and makes sure it is given a special packet type.
228 * priv Unused. Optional private pointer.
229 * virtual Virtual address (where to read the data from)
230 * offset Offset from start of core file
238 netdump_dumper(void *priv __unused, void *virtual, off_t offset, size_t length)
242 NETDDEBUGV("netdump_dumper(NULL, %p, NULL, %ju, %zu)\n",
243 virtual, (uintmax_t)offset, length);
245 if (virtual == NULL) {
246 error = netdump_flush_buf();
250 if (dump_failed != 0)
251 printf("failed to dump the kernel core\n");
253 debugnet_sendempty(nd_conf.nd_pcb, DEBUGNET_FINISHED) != 0)
254 printf("failed to close the transaction\n");
256 printf("\nnetdump finished.\n");
260 if (length > sizeof(nd_buf)) {
265 if (nd_conf.nd_buf_len + length > sizeof(nd_buf) ||
266 (nd_conf.nd_buf_len != 0 && nd_conf.nd_tx_off +
267 nd_conf.nd_buf_len != offset)) {
268 error = netdump_flush_buf();
274 nd_conf.nd_tx_off = offset;
277 memmove(nd_buf + nd_conf.nd_buf_len, virtual, length);
278 nd_conf.nd_buf_len += length;
284 * Perform any initialization needed prior to transmitting the kernel core.
287 netdump_start(struct dumperinfo *di, void *key, uint32_t keysize)
289 struct debugnet_conn_params dcp;
290 struct debugnet_pcb *pcb;
291 char buf[INET_ADDRSTRLEN];
296 /* Check if the dumping is allowed to continue. */
297 if (!netdump_enabled())
300 if (!KERNEL_PANICKED()) {
302 "netdump_start: netdump may only be used after a panic\n");
306 memset(&dcp, 0, sizeof(dcp));
308 if (nd_server.s_addr == INADDR_ANY) {
309 printf("netdump_start: can't netdump; no server IP given\n");
313 /* We start dumping at offset 0. */
318 dcp.dc_client = nd_client.s_addr;
319 dcp.dc_server = nd_server.s_addr;
320 dcp.dc_gateway = nd_gateway.s_addr;
322 dcp.dc_herald_port = NETDUMP_PORT;
323 dcp.dc_client_port = NETDUMP_ACKPORT;
325 dcp.dc_herald_data = nd_path;
326 dcp.dc_herald_datalen = (nd_path[0] == 0) ? 0 : strlen(nd_path) + 1;
328 error = debugnet_connect(&dcp, &pcb);
330 printf("failed to contact netdump server\n");
331 /* Squash debugnet to something the dumper code understands. */
335 printf("netdumping to %s (%6D)\n", inet_ntoa_r(nd_server, buf),
336 debugnet_get_gw_mac(pcb), ":");
337 nd_conf.nd_pcb = pcb;
339 /* Send the key before the dump so a partial dump is still usable. */
341 if (keysize > sizeof(nd_buf)) {
342 printf("crypto key is too large (%u)\n", keysize);
346 memcpy(nd_buf, key, keysize);
347 error = debugnet_send(pcb, NETDUMP_EKCD_KEY, nd_buf, keysize,
350 printf("error %d sending crypto key\n", error);
357 /* As above, squash errors. */
365 netdump_write_headers(struct dumperinfo *di, struct kerneldumpheader *kdh)
369 error = netdump_flush_buf();
372 memcpy(nd_buf, kdh, sizeof(*kdh));
373 error = debugnet_send(nd_conf.nd_pcb, NETDUMP_KDH, nd_buf,
382 * Cleanup routine for a possibly failed netdump.
385 netdump_cleanup(void)
387 if (nd_conf.nd_pcb != NULL) {
388 debugnet_free(nd_conf.nd_pcb);
389 nd_conf.nd_pcb = NULL;
397 static struct cdevsw netdump_cdevsw = {
398 .d_version = D_VERSION,
399 .d_ioctl = netdump_ioctl,
403 static struct cdev *netdump_cdev;
406 netdump_unconfigure(void)
408 struct diocskerneldump_arg kda;
410 NETDUMP_ASSERT_WLOCKED();
411 KASSERT(netdump_enabled(), ("%s: not enabled", __func__));
413 bzero(&kda, sizeof(kda));
414 kda.kda_index = KDA_REMOVE_DEV;
415 (void)dumper_remove(nd_conf.ndc_iface, &kda);
420 netdump_set_enabled(false);
422 log(LOG_WARNING, "netdump: Lost configured interface %s\n",
425 bzero(&nd_conf, sizeof(nd_conf));
429 netdump_ifdetach(void *arg __unused, struct ifnet *ifp)
434 netdump_unconfigure();
439 * td of NULL is a sentinel value that indicates a kernel caller (ddb(4) or
440 * modload-based tunable parameters).
443 netdump_configure(struct diocskerneldump_arg *conf, struct thread *td)
447 NETDUMP_ASSERT_WLOCKED();
449 if (conf->kda_iface[0] != 0) {
450 if (td != NULL && !IS_DEFAULT_VNET(TD_TO_VNET(td)))
453 ifp = ifunit_ref(conf->kda_iface);
455 if (!DEBUGNET_SUPPORTED_NIC(ifp)) {
465 netdump_set_enabled(true);
467 #define COPY_SIZED(elm) do { \
468 _Static_assert(sizeof(nd_conf.ndc_ ## elm) == \
469 sizeof(conf->kda_ ## elm), "elm " __XSTRING(elm) " mismatch"); \
470 memcpy(&nd_conf.ndc_ ## elm, &conf->kda_ ## elm, \
471 sizeof(nd_conf.ndc_ ## elm)); \
484 * ioctl(2) handler for the netdump device. This is currently only used to
485 * register netdump as a dump device.
489 * cmd, The ioctl to be handled.
490 * addr, The parameter for the ioctl.
492 * td, The thread invoking this ioctl.
495 * 0 on success, and an errno value on failure.
498 netdump_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr,
499 int flags __unused, struct thread *td)
501 struct diocskerneldump_arg *conf;
502 struct dumperinfo dumper;
503 uint8_t *encryptedkey;
511 case DIOCGKERNELDUMP:
514 * For now, index is ignored; netdump doesn't support multiple
515 * configurations (yet).
517 if (!netdump_enabled()) {
524 strlcpy(conf->kda_iface, nd_ifp->if_xname,
525 sizeof(conf->kda_iface));
526 memcpy(&conf->kda_server, &nd_server, sizeof(nd_server));
527 memcpy(&conf->kda_client, &nd_client, sizeof(nd_client));
528 memcpy(&conf->kda_gateway, &nd_gateway, sizeof(nd_gateway));
529 conf->kda_af = nd_conf.ndc_af;
532 case DIOCSKERNELDUMP:
536 /* Netdump only supports IP4 at this time. */
537 if (conf->kda_af != AF_INET) {
538 error = EPROTONOSUPPORT;
542 conf->kda_iface[sizeof(conf->kda_iface) - 1] = '\0';
543 if (conf->kda_index == KDA_REMOVE ||
544 conf->kda_index == KDA_REMOVE_DEV ||
545 conf->kda_index == KDA_REMOVE_ALL) {
546 if (netdump_enabled())
547 netdump_unconfigure();
548 if (conf->kda_index == KDA_REMOVE_ALL)
549 error = dumper_remove(NULL, conf);
553 error = netdump_configure(conf, td);
557 if (conf->kda_encryption != KERNELDUMP_ENC_NONE) {
558 if (conf->kda_encryptedkeysize <= 0 ||
559 conf->kda_encryptedkeysize >
560 KERNELDUMP_ENCKEY_MAX_SIZE) {
564 encryptedkey = malloc(conf->kda_encryptedkeysize,
566 error = copyin(conf->kda_encryptedkey, encryptedkey,
567 conf->kda_encryptedkeysize);
569 free(encryptedkey, M_TEMP);
573 conf->kda_encryptedkey = encryptedkey;
576 memset(&dumper, 0, sizeof(dumper));
577 dumper.dumper_start = netdump_start;
578 dumper.dumper_hdr = netdump_write_headers;
579 dumper.dumper = netdump_dumper;
581 dumper.blocksize = NETDUMP_DATASIZE;
582 dumper.maxiosize = MAXDUMPPGS * PAGE_SIZE;
583 dumper.mediaoffset = 0;
584 dumper.mediasize = 0;
586 error = dumper_insert(&dumper, conf->kda_iface, conf);
587 zfree(encryptedkey, M_TEMP);
589 netdump_unconfigure();
596 explicit_bzero(conf, sizeof(*conf));
602 * Called upon system init or kld load. Initializes the netdump parameters to
603 * sane defaults (locates the first available NIC and uses the first IPv4 IP on
604 * that card as the client IP). Leaves the server IP unconfigured.
608 * what, The module event type.
612 * int, An errno value if an error occurred, 0 otherwise.
615 netdump_modevent(module_t mod __unused, int what, void *priv __unused)
617 struct diocskerneldump_arg conf;
624 error = make_dev_p(MAKEDEV_WAITOK, &netdump_cdev,
625 &netdump_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "netdump");
629 nd_detach_cookie = EVENTHANDLER_REGISTER(ifnet_departure_event,
630 netdump_ifdetach, NULL, EVENTHANDLER_PRI_ANY);
632 if ((arg = kern_getenv("net.dump.iface")) != NULL) {
633 strlcpy(conf.kda_iface, arg, sizeof(conf.kda_iface));
636 if ((arg = kern_getenv("net.dump.server")) != NULL) {
637 inet_aton(arg, &conf.kda_server.in4);
640 if ((arg = kern_getenv("net.dump.client")) != NULL) {
641 inet_aton(arg, &conf.kda_client.in4);
644 if ((arg = kern_getenv("net.dump.gateway")) != NULL) {
645 inet_aton(arg, &conf.kda_gateway.in4);
648 conf.kda_af = AF_INET;
650 /* Ignore errors; we print a message to the console. */
652 (void)netdump_configure(&conf, NULL);
658 if (netdump_enabled()) {
659 printf("netdump: disabling dump device for unload\n");
660 netdump_unconfigure();
663 destroy_dev(netdump_cdev);
664 EVENTHANDLER_DEREGISTER(ifnet_departure_event,
674 static moduledata_t netdump_mod = {
680 MODULE_VERSION(netdump, 1);
681 DECLARE_MODULE(netdump, netdump_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
685 * Usage: netdump -s <server> [-g <gateway] -c <localip> -i <interface>
687 * Order is not significant.
689 * Currently, this command does not support configuring encryption or
692 DB_COMMAND_FLAGS(netdump, db_netdump_cmd, CS_OWN)
694 static struct diocskerneldump_arg conf;
695 static char blockbuf[NETDUMP_DATASIZE];
697 struct dumperinfo di;
698 /* For valid di_devname. */
699 char di_buf[sizeof(struct dumperinfo) + 1];
702 struct debugnet_ddb_config params;
705 error = debugnet_parse_ddb_cmd("netdump", ¶ms);
707 db_printf("Error configuring netdump: %d\n", error);
711 /* Translate to a netdump dumper config. */
712 memset(&conf, 0, sizeof(conf));
714 if (params.dd_ifp != NULL)
715 strlcpy(conf.kda_iface, if_name(params.dd_ifp),
716 sizeof(conf.kda_iface));
718 conf.kda_af = AF_INET;
719 conf.kda_server.in4 = (struct in_addr) { params.dd_server };
720 if (params.dd_has_client)
721 conf.kda_client.in4 = (struct in_addr) { params.dd_client };
723 conf.kda_client.in4 = (struct in_addr) { INADDR_ANY };
724 if (params.dd_has_gateway)
725 conf.kda_gateway.in4 = (struct in_addr) { params.dd_gateway };
727 conf.kda_gateway.in4 = (struct in_addr) { INADDR_ANY };
729 /* Set the global netdump config to these options. */
730 error = netdump_configure(&conf, NULL);
732 db_printf("Error enabling netdump: %d\n", error);
736 /* Fake the generic dump configuration list entry to avoid malloc. */
737 memset(&u.di_buf, 0, sizeof(u.di_buf));
738 u.di.dumper_start = netdump_start;
739 u.di.dumper_hdr = netdump_write_headers;
740 u.di.dumper = netdump_dumper;
742 u.di.blocksize = NETDUMP_DATASIZE;
743 u.di.maxiosize = MAXDUMPPGS * PAGE_SIZE;
744 u.di.mediaoffset = 0;
746 u.di.blockbuf = blockbuf;
748 dumper_ddb_insert(&u.di);
750 error = doadump(false);
752 dumper_ddb_remove(&u.di);
754 db_printf("Cannot dump: %d\n", error);