Documentation/networking/netconsole.txt | 57 ++++++++ arch/i386/kernel/i386_ksyms.c | 8 + arch/i386/kernel/irq.c | 12 + drivers/net/Kconfig | 7 + drivers/net/Makefile | 1 drivers/net/netconsole.c | 217 ++++++++++++++++++++++++++++++++ include/asm-i386/netconsole.h | 6 net/Kconfig | 2 net/core/dev.c | 3 9 files changed, 311 insertions(+), 2 deletions(-) --- linux-2.6.0-test6/arch/i386/kernel/i386_ksyms.c~netconsole-over-netpoll 2003-10-14 17:44:04.000000000 +0400 +++ linux-2.6.0-test6-alexey/arch/i386/kernel/i386_ksyms.c 2003-10-14 17:45:08.000000000 +0400 @@ -34,7 +34,7 @@ #include #include #include - +#include extern void dump_thread(struct pt_regs *, struct user *); extern spinlock_t rtc_lock; @@ -211,6 +211,12 @@ EXPORT_SYMBOL(edd); EXPORT_SYMBOL(eddnr); #endif +#ifdef CONFIG_NETCONSOLE +EXPORT_SYMBOL(netconsole_sysrq_req); +EXPORT_SYMBOL(netconsole_do_sysrq); +EXPORT_SYMBOL(netif_in_poll); +#endif + #if defined(CONFIG_X86_SPEEDSTEP_SMI) || defined(CONFIG_X86_SPEEDSTEP_SMI_MODULE) EXPORT_SYMBOL(ist_info); #endif --- linux-2.6.0-test6/arch/i386/kernel/irq.c~netconsole-over-netpoll 2003-10-14 17:45:03.000000000 +0400 +++ linux-2.6.0-test6-alexey/arch/i386/kernel/irq.c 2003-10-14 17:45:08.000000000 +0400 @@ -45,6 +45,7 @@ #include #include #include +#include /* * Linux has a controller-independent x86 interrupt architecture. @@ -510,6 +511,17 @@ out: BREAKPOINT; } #endif +#ifdef CONFIG_NETCONSOLE + /* + * We need to do this after clearing out of all the interrupt + * machinery because kgdb will reenter the NIC driver and the IRQ + * system. synchronize_irq() (at least) will deadlock. + */ + if (netconsole_sysrq_req && !netif_in_poll) { + netconsole_sysrq_req = 0; + HANDLE_NETCONSOLE; + } +#endif return 1; } --- /dev/null 2003-01-30 13:24:37.000000000 +0300 +++ linux-2.6.0-test6-alexey/Documentation/networking/netconsole.txt 2003-10-14 17:45:08.000000000 +0400 @@ -0,0 +1,57 @@ + +started by Ingo Molnar , 2001.09.17 +2.6 port and netpoll api by Matt Mackall , Sep 9 2003 + +Please send bug reports to Matt Mackall + +This module logs kernel printk messages over UDP allowing debugging of +problem where disk logging fails and serial consoles are impractical. + +It can be used either built-in or as a module. As a built-in, +netconsole initializes immediately after NIC cards and will bring up +the specified interface as soon as possible. While this doesn't allow +capture of early kernel panics, it does capture most of the boot +process. + +It takes a string configuration parameter "netconsole" in the +following format: + + netconsole=[src-port]@[src-ip]/[],[tgt-port]@/[tgt-macaddr] + + where + src-port source for UDP packets (defaults to 6666) + src-ip source IP to use (interface address) + dev network interface (eth0) + tgt-port port for logging agent (514) + tgt-ip IP address for logging agent + tgt-macaddr ethernet MAC address for logging agent (broadcast) + +Examples: + + linux netconsole=4444@10.0.0.1/eth1,9353@10.0.0.2/12:34:56:78:9a:bc + + or + + insmod netconsole netconsole=@/,@10.0.0.2/ + +Built-in netconsole starts immediately after the TCP stack is +initialized and attempts to bring up the supplied dev at the supplied +address. + +The remote host can run either 'netcat -u -l -p ' or syslogd. + +WARNING: the default target ethernet setting uses the broadcast +ethernet address to send packets, which can cause increased load on +other systems on the same ethernet segment. + +NOTE: the network device (eth1 in the above case) can run any kind +of other network traffic, netconsole is not intrusive. Netconsole +might cause slight delays in other traffic if the volume of kernel +messages is high, but should have no other impact. + +Netconsole was designed to be as instantaneous as possible, to +enable the logging of even the most critical kernel bugs. It works +from IRQ contexts as well, and does not enable interrupts while +sending packets. Due to these unique needs, configuration can not +be more automatic, and some fundamental limitations will remain: +only IP networks, UDP packets and ethernet devices are supported. --- linux-2.6.0-test6/drivers/net/Kconfig~netconsole-over-netpoll 2003-10-14 17:44:05.000000000 +0400 +++ linux-2.6.0-test6-alexey/drivers/net/Kconfig 2003-10-14 17:45:08.000000000 +0400 @@ -2444,6 +2444,13 @@ config SHAPER config NET_POLL_CONTROLLER def_bool KGDB +config NETCONSOLE + tristate "Network console logging support" + depends on NETDEVICES + ---help--- + If you want to log kernel messages over the network, enable this. + See Documentation/networking/netconsole.txt for details. + source "drivers/net/wan/Kconfig" source "drivers/net/pcmcia/Kconfig" --- linux-2.6.0-test6/drivers/net/Makefile~netconsole-over-netpoll 2003-10-14 17:45:04.000000000 +0400 +++ linux-2.6.0-test6-alexey/drivers/net/Makefile 2003-10-14 17:45:08.000000000 +0400 @@ -109,6 +109,7 @@ ifeq ($(CONFIG_SLIP_COMPRESSED),y) endif # Must come after all NICs it might use obj-$(CONFIG_KGDB) += kgdb_eth.o +obj-$(CONFIG_NETCONSOLE) += netconsole.o obj-$(CONFIG_DUMMY) += dummy.o obj-$(CONFIG_DE600) += de600.o --- /dev/null 2003-01-30 13:24:37.000000000 +0300 +++ linux-2.6.0-test6-alexey/drivers/net/netconsole.c 2003-10-14 17:45:56.000000000 +0400 @@ -0,0 +1,217 @@ +/* + * linux/drivers/net/netconsole.c + * + * Copyright (C) 2001 Ingo Molnar + * + * This file contains the implementation of an IRQ-safe, crash-safe + * kernel console implementation that outputs kernel messages to the + * network. + * + * Modification history: + * + * 2001-09-17 started by Ingo Molnar. + * 2003-08-11 2.6 port by Matt Mackall + * simplified options + * generic card hooks + * works non-modular + * 2003-09-07 rewritten with netpoll api + * 2003-09-27 updated by wangdi + */ + +/**************************************************************** + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + ****************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Maintainer: Matt Mackall "); +MODULE_DESCRIPTION("Console driver for network interfaces"); +MODULE_LICENSE("GPL"); + +static char config[256]; +module_param_string(netconsole, config, 256, 0); +MODULE_PARM_DESC(netconsole, " netconsole=[src-port]@[src-ip]/[dev],[tgt-port]@/[tgt-macaddr]\n"); + +static void rx_hook(struct netpoll *np, int port, char *msg, int len); + +static int sysrq_mode = 0; + +static req_t req; +unsigned int netconsole_sysrq_req = 0; +unsigned int netif_in_poll = 0; +static unsigned int handle_sysrq_progress = 0; +#define Set_Sysrq_mode() (sysrq_mode = 1) +#define Clear_Sysrq_mode() (sysrq_mode = 0) + +static struct netpoll np = { + .name = "netconsole", + .dev_name = "eth0", + .rx_hook = rx_hook, + .local_port = 6666, + .remote_port = 6666, + .remote_mac = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, +}; + +#define MAX_PRINT_CHUNK 1000 +#define MAX_SEND_BUFFER_LEN (MAX_PRINT_CHUNK + 200) + +static char send_buf[MAX_SEND_BUFFER_LEN]; +static char send_cache[MAX_PRINT_CHUNK]; +static unsigned int send_cache_pos = 0; + +static void send_msg_buffer(struct netpoll *np, const char *msg, int len) +{ + reply_t reply; + + send_buf[0] = NETCONSOLE_VERSION; + reply.code = REPLY_LOG; + reply.nr = 0; + reply.info = 0; + + put_unaligned(htonl(reply.nr), (u32 *) (send_buf + 1)); + put_unaligned(htonl(reply.code), (u32 *) (send_buf + 5)); + put_unaligned(htonl(reply.info), (u32 *) (send_buf+ 9)); + + memcpy(send_buf + 1 + sizeof(reply_t), msg, len); + netpoll_send_udp(np, send_buf, len + 1 + sizeof(reply_t)); + return; +} +static void write_msg(struct console *con, const char *msg, unsigned int len) +{ + unsigned long total_len = send_cache_pos + len; + unsigned long left_len = len; + unsigned long flags; + + if (!sysrq_mode) + return; + if (!np.dev) + return; + while (total_len >= MAX_PRINT_CHUNK){ + unsigned long send_len = MAX_PRINT_CHUNK - send_cache_pos; + memcpy(send_cache + send_cache_pos, msg, send_len); + local_irq_save(flags); +#if 0 + for(left = send_len; left; ) { + frag = min(left, MAX_PRINT_CHUNK); + send_msg_buffer(&np, send_buffer, frag); + msg += frag; + left -= frag; + } +#endif + send_msg_buffer(&np, send_cache, MAX_PRINT_CHUNK); + send_cache_pos = 0; + local_irq_restore(flags); + total_len -= MAX_PRINT_CHUNK; + left_len -= send_len; + } + if (left_len > 0){ + memcpy(send_cache + send_cache_pos, msg + (len -left_len), left_len); + send_cache_pos += left_len; + } +} +void netconsole_do_sysrq() +{ + struct pt_regs regs; + unsigned long flags; + + handle_sysrq_progress = 1; + Set_Sysrq_mode(); + get_current_regs(®s); + handle_sysrq((int)req.from, ®s, NULL); + + if (send_cache_pos != 0){ + local_irq_save(flags); + send_msg_buffer(&np, send_cache, send_cache_pos); + send_cache_pos = 0; + local_irq_restore(flags); + } + + handle_sysrq_progress = 0; + Clear_Sysrq_mode(); +} +static void rx_hook(struct netpoll *np, int port, char *msg, int len) +{ + /* add sysrq support */ + req_t *__req; + + if (handle_sysrq_progress) + goto out; + __req = (req_t *)(msg); + if(len < (sizeof(req_t))) + goto out; + + if ((ntohl(__req->command) != COMM_SYSRQ)) + goto out; + /*FIXME should check magic, but did not have good ways*/ + + req.magic = ntohl(__req->magic); + req.command = ntohl(__req->command); + req.from = ntohl(__req->from); + req.to = ntohl(__req->to); + req.nr = ntohl(__req->nr); + netconsole_sysrq_req = 1; +out: + return ; +} + +static struct console netconsole = { + .flags = CON_ENABLED | CON_PRINTBUFFER, + .write = write_msg +}; + +static int option_setup(char *opt) +{ + return netpoll_parse_options(&np, opt); +} + +__setup("netconsole=", option_setup); + +static int init_netconsole(void) +{ + if(strlen(config) && option_setup(config)) + return 1; + + if(!np.remote_ip || netpoll_setup(&np)) + return 1; + register_console(&netconsole); + printk(KERN_INFO "netconsole: network logging started\n"); + return 0; +} + +static void cleanup_netconsole(void) +{ + unregister_console(&netconsole); + netpoll_cleanup(&np); +} + +module_init(init_netconsole); +module_exit(cleanup_netconsole); --- /dev/null 2003-01-30 13:24:37.000000000 +0300 +++ linux-2.6.0-test6-alexey/include/asm-i386/netconsole.h 2003-10-14 17:45:08.000000000 +0400 @@ -0,0 +1,6 @@ +extern unsigned int netconsole_sysrq_req; +extern void netconsole_do_sysrq(void); +extern unsigned int netif_in_poll; +#ifndef HANDLE_NETCONSOLE +#define HANDLE_NETCONSOLE netconsole_do_sysrq() +#endif --- linux-2.6.0-test6/net/core/dev.c~netconsole-over-netpoll 2003-10-14 17:45:03.000000000 +0400 +++ linux-2.6.0-test6-alexey/net/core/dev.c 2003-10-14 17:45:08.000000000 +0400 @@ -109,6 +109,7 @@ #include /* Note : will define WIRELESS_EXT */ #include #endif /* CONFIG_NET_RADIO */ +#include #include #ifdef CONFIG_KGDB @@ -1687,6 +1688,7 @@ static void net_rx_action(struct softirq preempt_disable(); local_irq_disable(); + netif_in_poll = 1; while (!list_empty(&queue->poll_list)) { struct net_device *dev; @@ -1711,6 +1713,7 @@ static void net_rx_action(struct softirq local_irq_disable(); } } + netif_in_poll = 0; out: local_irq_enable(); preempt_enable(); --- linux-2.6.0-test6/net/Kconfig~netconsole-over-netpoll 2003-10-14 17:45:03.000000000 +0400 +++ linux-2.6.0-test6-alexey/net/Kconfig 2003-10-14 17:45:08.000000000 +0400 @@ -671,6 +671,6 @@ source "net/irda/Kconfig" source "net/bluetooth/Kconfig" config NETPOLL - def_bool KGDB + def_bool KGDB || NETCONSOLE endmenu _