diff --git a/sys/kern/kern_shutdown.c b/sys/kern/kern_shutdown.c index 2a4610b217bf..03b49dfc80b4 100644 --- a/sys/kern/kern_shutdown.c +++ b/sys/kern/kern_shutdown.c @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include "opt_ddb.h" #include "opt_ekcd.h" #include "opt_kdb.h" +#include "opt_netdump.h" #include "opt_panic.h" #include "opt_sched.h" #include "opt_watchdog.h" @@ -190,6 +191,11 @@ SYSCTL_INT(_kern, OID_AUTO, kerneldump_gzlevel, CTLFLAG_RWTUN, &kerneldump_gzlevel, 0, "Kernel crash dump compression level"); +#ifdef NETDUMP +/* Defined in kern_mbuf.c. */ +void netdump_mbuf_drain(void); +#endif + /* * Variable panicstr contains argument to first call to panic; used as flag * to indicate that the kernel has already called panic. @@ -1106,6 +1112,11 @@ set_dumper(struct dumperinfo *di, const char *devname, struct thread *td, } explicit_bzero(&dumper, sizeof(dumper)); dumpdevname[0] = '\0'; + +#ifdef NETDUMP + netdump_mbuf_drain(); +#endif + return (error); } diff --git a/sys/netinet/netdump/netdump_client.c b/sys/netinet/netdump/netdump_client.c index f4a7b6371424..707299c38f04 100644 --- a/sys/netinet/netdump/netdump_client.c +++ b/sys/netinet/netdump/netdump_client.c @@ -34,6 +34,7 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_ddb.h" #include "opt_netdump.h" #include @@ -51,6 +52,11 @@ __FBSDID("$FreeBSD$"); #include #include +#ifdef DDB +#include +#include +#endif + #include #include #include @@ -94,12 +100,11 @@ __FBSDID("$FreeBSD$"); /* Defined in kern_mbuf.c. */ void netdump_mbuf_init(int nmbuf, int nclust); -void netdump_mbuf_drain(void); void netdump_mbuf_dump(void); static int netdump_arp_gw(void); static void netdump_cleanup(void); -static int netdump_configure(struct netdump_conf *); +static int netdump_configure(struct netdump_conf *, struct thread *td); 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, @@ -1034,23 +1039,10 @@ netdump_cleanup(void) nd_ifp->if_netdump_methods->nd_event(nd_ifp, NETDUMP_END); } -/*- - * KLD specific code. - */ - -static struct cdevsw netdump_cdevsw = { - .d_version = D_VERSION, - .d_ioctl = netdump_ioctl, - .d_name = "netdump", -}; - -static struct cdev *netdump_cdev; - -static int -netdump_configure(struct netdump_conf *conf) +static struct ifnet * +netdump_select_if(struct netdump_conf *conf) { struct ifnet *ifp; - int nmbuf, nclust; IFNET_RLOCK_NOSLEEP(); TAILQ_FOREACH(ifp, &V_ifnet, if_link) { @@ -1062,12 +1054,21 @@ netdump_configure(struct netdump_conf *conf) if (ifp == NULL) { printf("netdump: unknown interface '%s'\n", conf->ndc_iface); - return (1); + return (NULL); } else if (!netdump_supported_nic(ifp) || ifp->if_type != IFT_ETHER) { printf("netdump: unsupported interface '%s'\n", conf->ndc_iface); - return (1); + return (NULL); } + return (ifp); +} + +static int +netdump_configure(struct netdump_conf *conf, struct thread *td) +{ + struct dumperinfo dumper; + struct ifnet *ifp; + int error, nmbuf, nclust; /* * We need two headers per message. Multiply by four to give us some @@ -1075,15 +1076,45 @@ netdump_configure(struct netdump_conf *conf) */ nmbuf = NETDUMP_MAX_IN_FLIGHT * 4; nclust = 0; + + ifp = netdump_select_if(conf); + if (ifp == NULL) + return (EINVAL); ifp->if_netdump_methods->nd_init(ifp, &nmbuf, &nclust); netdump_mbuf_init(nmbuf, nclust); nd_ifp = ifp; memcpy(&nd_conf, conf, sizeof(nd_conf)); - nd_enabled = 1; - return (0); + + dumper.dumper_start = netdump_start; + dumper.dumper_hdr = netdump_write_headers; + dumper.dumper = netdump_dumper; + dumper.priv = NULL; + dumper.blocksize = NETDUMP_DATASIZE; + dumper.maxiosize = MAXDUMPPGS * PAGE_SIZE; + dumper.mediaoffset = 0; + dumper.mediasize = 0; + error = set_dumper(&dumper, conf->ndc_iface, td, + conf->ndc_kda.kda_compression, conf->ndc_kda.kda_encryption, + conf->ndc_kda.kda_key, conf->ndc_kda.kda_encryptedkeysize, + conf->ndc_kda.kda_encryptedkey); + if (error == 0) + nd_enabled = 1; + return (error); } +/*- + * KLD specific code. + */ + +static struct cdevsw netdump_cdevsw = { + .d_version = D_VERSION, + .d_ioctl = netdump_ioctl, + .d_name = "netdump", +}; + +static struct cdev *netdump_cdev; + /* * ioctl(2) handler for the netdump device. This is currently only used to * register netdump as a dump device. @@ -1102,7 +1133,6 @@ static int netdump_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr, int flags __unused, struct thread *td) { - struct dumperinfo dumper; struct netdump_conf *conf; int error; u_int u; @@ -1117,8 +1147,9 @@ netdump_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr, } if (nd_enabled) { + (void)set_dumper(NULL, NULL, curthread, 0, 0, + NULL, 0, NULL); nd_enabled = 0; - netdump_mbuf_drain(); } break; case NETDUMPGCONF: @@ -1142,33 +1173,14 @@ netdump_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t addr, conf = (struct netdump_conf *)addr; if (conf->ndc_kda.kda_enable == 0) { if (nd_enabled) { + (void)set_dumper(NULL, NULL, curthread, 0, 0, + NULL, 0, NULL); nd_enabled = 0; - netdump_mbuf_drain(); } break; } - if (netdump_configure(conf) != 0) { - error = EINVAL; - break; - } - - dumper.dumper_start = netdump_start; - dumper.dumper_hdr = netdump_write_headers; - dumper.dumper = netdump_dumper; - dumper.priv = NULL; - dumper.blocksize = NETDUMP_DATASIZE; - dumper.maxiosize = MAXDUMPPGS * PAGE_SIZE; - dumper.mediaoffset = 0; - dumper.mediasize = 0; - error = set_dumper(&dumper, conf->ndc_iface, td, - conf->ndc_kda.kda_compression, conf->ndc_kda.kda_encryption, - conf->ndc_kda.kda_key, conf->ndc_kda.kda_encryptedkeysize, - conf->ndc_kda.kda_encryptedkey); - if (error != 0) { - nd_enabled = 0; - netdump_mbuf_drain(); - } + error = netdump_configure(conf, td); break; default: error = EINVAL; @@ -1195,7 +1207,7 @@ netdump_modevent(module_t mod __unused, int what, void *priv __unused) { struct netdump_conf conf; char *arg; - int error; + int error, nmbuf, nclust; error = 0; switch (what) { @@ -1222,17 +1234,43 @@ netdump_modevent(module_t mod __unused, int what, void *priv __unused) freeenv(arg); } - /* Ignore errors; we print a message to the console. */ - (void)netdump_configure(&conf); + error = netdump_configure(&conf, curthread); + if (error != 0) + printf("netdump: configuration failed: %d\n", + error); + } else { + nmbuf = nclust = 0; + TUNABLE_INT_FETCH("net.dump.prealloc.nmbuf", &nmbuf); + TUNABLE_INT_FETCH("net.dump.prealloc.nclust", &nclust); + if (nmbuf > 0 && nclust > 0) { + struct dumperinfo dumper; + + memset(&conf, 0, sizeof(conf)); + strlcpy(conf.ndc_iface, "netdump", + sizeof(conf.ndc_iface)); + + dumper.dumper_start = netdump_start; + dumper.dumper_hdr = netdump_write_headers; + dumper.dumper = netdump_dumper; + dumper.priv = NULL; + dumper.blocksize = NETDUMP_DATASIZE; + dumper.maxiosize = MAXDUMPPGS * PAGE_SIZE; + dumper.mediaoffset = 0; + dumper.mediasize = 0; + error = set_dumper(&dumper, conf.ndc_iface, curthread, + conf.ndc_kda.kda_compression, conf.ndc_kda.kda_encryption, + conf.ndc_kda.kda_key, conf.ndc_kda.kda_encryptedkeysize, + conf.ndc_kda.kda_encryptedkey); + if (error == 0) + netdump_mbuf_init(nmbuf, nclust); + } } break; case MOD_UNLOAD: destroy_dev(netdump_cdev); - if (nd_enabled) { + if (nd_enabled) (void)set_dumper(NULL, NULL, curthread, 0, 0, NULL, 0, NULL); - netdump_mbuf_drain(); - } break; default: error = EOPNOTSUPP; @@ -1249,3 +1287,62 @@ static moduledata_t netdump_mod = { MODULE_VERSION(netdump, 1); DECLARE_MODULE(netdump, netdump_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); + +#ifdef DDB +static bool +parse_ip(struct in_addr *addr) +{ + db_expr_t octet; + int i, tok; + + memset(addr, 0, sizeof(*addr)); + + for (i = 0; i < 4; i++) { + tok = db_read_token(); + if (tok != tNUMBER) + return (false); + octet = db_tok_number; + if (octet < 0 || octet > 255) + return (false); + + addr->s_addr |= htonl(octet) << (i * 8); + + if (i == 4) + break; + tok = db_read_token(); + if (tok != tDOT) + return (false); + } + return (true); +} + +DB_FUNC(netdump, db_netdump, db_cmd_table, CS_OWN, NULL) +{ + struct netdump_conf conf; + int tok; + + memset(&conf, 0, sizeof(conf)); + + if (!parse_ip(&conf.ndc_server)) + goto usage; + if (!parse_ip(&conf.ndc_client)) + goto usage; + if (!parse_ip(&conf.ndc_gateway)) + goto usage; + + tok = db_read_token(); + if (tok != tIDENT) + goto usage; + + strlcpy(conf.ndc_iface, db_tok_string, sizeof(conf.ndc_iface)); + nd_ifp = netdump_select_if(&conf); + + printf("iface: %s\n", conf.ndc_iface); + return; + +usage: + db_skip_to_eol(); + db_printf( + "usage: netdump \n"); +} +#endif /* DDB */