unslung-kernel: added kernel module netconsole
authorMike Westerhof <mwester@dls.net>
Tue, 28 Feb 2006 18:11:38 +0000 (18:11 +0000)
committerOpenEmbedded Project <openembedded-devel@lists.openembedded.org>
Tue, 28 Feb 2006 18:11:38 +0000 (18:11 +0000)
packages/linux/unslung-kernel/defconfig
packages/linux/unslung-kernel/netconsole.patch [new file with mode: 0644]
packages/linux/unslung-kernel_2.4.22.l2.3r63.bb

index 877397c..027dbfb 100644 (file)
@@ -512,6 +512,11 @@ CONFIG_NETDEVICES=y
 CONFIG_TUN=m
 CONFIG_ETHERTAP=m
 
+#
+# Netconsole support
+#
+CONFIG_NETCONSOLE=m
+
 #
 # Ethernet (10 or 100Mbit)
 #
diff --git a/packages/linux/unslung-kernel/netconsole.patch b/packages/linux/unslung-kernel/netconsole.patch
new file mode 100644 (file)
index 0000000..c54f4d1
--- /dev/null
@@ -0,0 +1,383 @@
+diff -Naur linux-2.4.22/drivers/net/Config.in.orig linux-2.4.22/drivers/net/Config.in
+--- linux-2.4.22/drivers/net/Config.in.orig    2006-02-26 11:49:28.000000000 -0600
++++ linux-2.4.22/drivers/net/Config.in 2006-02-26 11:40:31.000000000 -0600
+@@ -338,6 +338,8 @@
+    dep_tristate '  SysKonnect FDDI PCI support' CONFIG_SKFP $CONFIG_PCI
+ fi
++dep_tristate 'Network logging support' CONFIG_NETCONSOLE
++
+ if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+    if [ "$CONFIG_INET" = "y" ]; then
+       bool 'HIPPI driver support (EXPERIMENTAL)' CONFIG_HIPPI
+diff -Naur linux-2.4.22/drivers/net/Makefile.orig linux-2.4.22/drivers/net/Makefile
+--- linux-2.4.22/drivers/net/Makefile.orig     2006-02-26 11:49:45.000000000 -0600
++++ linux-2.4.22/drivers/net/Makefile  2006-02-26 11:38:58.000000000 -0600
+@@ -272,6 +272,8 @@
+ obj-y         += ../acorn/net/acorn-net.o
+ endif
++obj-$(CONFIG_NETCONSOLE) += netconsole.o
++
+ #
+ # HIPPI adapters
+ #
+diff -Naur linux-2.4.22/drivers/net/netconsole.c.orig linux-2.4.22/drivers/net/netconsole.c
+--- linux-2.4.22/drivers/net/netconsole.c.orig 1969-12-31 18:00:00.000000000 -0600
++++ linux-2.4.22/drivers/net/netconsole.c      2006-02-26 16:16:23.000000000 -0600
+@@ -0,0 +1,342 @@
++/*  linux/drivers/net/netconsole.c
++ *
++ *  Copyright (C) 2001  Ingo Molnar <mingo@redhat.com>
++ *
++ *  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.
++ * 2006-02-26    very minor modifications to suit the NSLU2 w/Unslung -- Mike Westerhof.
++ */
++
++/****************************************************************
++ *      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 <net/tcp.h>
++#include <net/udp.h>
++#include <linux/mm.h>
++#include <linux/tty.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <asm/unaligned.h>
++#include <linux/console.h>
++#include <linux/smp_lock.h>
++#include <linux/netdevice.h>
++#include <linux/tty_driver.h>
++#include <linux/etherdevice.h>
++
++static struct net_device *netconsole_dev;
++static u16 source_port, target_port;
++static u32 source_ip, target_ip;
++static unsigned char daddr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} ;
++
++#define NETCONSOLE_VERSION 0x01
++#define HEADER_LEN 5
++
++#define MAX_UDP_CHUNK 1460
++#define MAX_PRINT_CHUNK (MAX_UDP_CHUNK-HEADER_LEN)
++
++/*
++ * We maintain a small pool of fully-sized skbs,
++ * to make sure the message gets out even in
++ * extreme OOM situations.
++ */
++#define MAX_NETCONSOLE_SKBS 32
++
++static spinlock_t netconsole_lock = SPIN_LOCK_UNLOCKED;
++static int nr_netconsole_skbs;
++static struct sk_buff *netconsole_skbs;
++
++#define MAX_SKB_SIZE \
++              (MAX_UDP_CHUNK + sizeof(struct udphdr) + \
++                              sizeof(struct iphdr) + sizeof(struct ethhdr))
++
++static void __refill_netconsole_skbs(void)
++{
++      struct sk_buff *skb;
++      unsigned long flags;
++
++      spin_lock_irqsave(&netconsole_lock, flags);
++      while (nr_netconsole_skbs < MAX_NETCONSOLE_SKBS) {
++              skb = alloc_skb(MAX_SKB_SIZE, GFP_ATOMIC);
++              if (!skb)
++                      break;
++              if (netconsole_skbs)
++                      skb->next = netconsole_skbs;
++              else
++                      skb->next = NULL;
++              netconsole_skbs = skb;
++              nr_netconsole_skbs++;
++      }
++      spin_unlock_irqrestore(&netconsole_lock, flags);
++}
++
++static struct sk_buff * get_netconsole_skb(void)
++{
++      struct sk_buff *skb;
++
++      unsigned long flags;
++
++      spin_lock_irqsave(&netconsole_lock, flags);
++      skb = netconsole_skbs;
++      if (skb)
++              netconsole_skbs = skb->next;
++      skb->next = NULL;
++      nr_netconsole_skbs--;
++      spin_unlock_irqrestore(&netconsole_lock, flags);
++
++      return skb;
++}
++
++static spinlock_t sequence_lock = SPIN_LOCK_UNLOCKED;
++static unsigned int offset;
++
++static void send_netconsole_skb(struct net_device *dev, const char *msg, unsigned int msg_len)
++{
++      int total_len, eth_len, ip_len, udp_len;
++      unsigned long flags;
++      struct sk_buff *skb;
++      struct udphdr *udph;
++      struct iphdr *iph;
++      struct ethhdr *eth;
++
++      udp_len = msg_len + HEADER_LEN + sizeof(*udph);
++      ip_len = eth_len = udp_len + sizeof(*iph);
++      total_len = eth_len + ETH_HLEN;
++
++      if (nr_netconsole_skbs < MAX_NETCONSOLE_SKBS)
++              __refill_netconsole_skbs();
++
++      skb = alloc_skb(total_len, GFP_ATOMIC);
++      if (!skb) {
++              skb = get_netconsole_skb();
++              if (!skb)
++                      /* tough! */
++                      return;
++      }
++
++      atomic_set(&skb->users, 1);
++      skb_reserve(skb, total_len - msg_len - HEADER_LEN);
++      skb->data[0] = NETCONSOLE_VERSION;
++
++      spin_lock_irqsave(&sequence_lock, flags);
++      put_unaligned(htonl(offset), (u32 *) (skb->data + 1));
++      offset += msg_len;
++      spin_unlock_irqrestore(&sequence_lock, flags);
++
++      memcpy(skb->data + HEADER_LEN, msg, msg_len);
++      skb->len += msg_len + HEADER_LEN;
++
++      udph = (struct udphdr *) skb_push(skb, sizeof(*udph));
++      udph->source = source_port;
++      udph->dest = target_port;
++      udph->len = htons(udp_len);
++      udph->check = 0;
++
++      iph = (struct iphdr *)skb_push(skb, sizeof(*iph));
++
++      iph->version  = 4;
++      iph->ihl      = 5;
++      iph->tos      = 0;
++        iph->tot_len  = htons(ip_len);
++      iph->id       = 0;
++      iph->frag_off = 0;
++      iph->ttl      = 64;
++        iph->protocol = IPPROTO_UDP;
++      iph->check    = 0;
++        iph->saddr    = source_ip;
++        iph->daddr    = target_ip;
++      iph->check    = ip_fast_csum((unsigned char *)iph, iph->ihl);
++
++      eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
++
++      eth->h_proto = htons(ETH_P_IP);
++      memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
++      memcpy(eth->h_dest, daddr, dev->addr_len);
++
++repeat:
++      spin_lock(&dev->xmit_lock);
++      dev->xmit_lock_owner = smp_processor_id();
++
++      if (netif_queue_stopped(dev)) {
++              dev->xmit_lock_owner = -1;
++              spin_unlock(&dev->xmit_lock);
++
++              dev->poll_controller(dev);
++              goto repeat;
++      }
++
++      dev->hard_start_xmit(skb, dev);
++
++      dev->xmit_lock_owner = -1;
++      spin_unlock(&dev->xmit_lock);
++}
++
++static void write_netconsole_msg(struct console *con, const char *msg, unsigned int msg_len)
++{
++      int len, left;
++      struct net_device *dev;
++
++      dev = netconsole_dev;
++      if (!dev)
++              return;
++
++      if (dev->poll_controller && netif_running(dev)) {
++              unsigned long flags;
++
++              __save_flags(flags);
++              __cli();
++              left = msg_len;
++repeat:
++              if (left > MAX_PRINT_CHUNK)
++                      len = MAX_PRINT_CHUNK;
++              else
++                      len = left;
++              send_netconsole_skb(dev, msg, len);
++              msg += len;
++              left -= len;
++              if (left)
++                      goto repeat;
++              __restore_flags(flags);
++      }
++}
++
++static char *dev;
++static int target_eth_byte0 = 255;
++static int target_eth_byte1 = 255;
++static int target_eth_byte2 = 255;
++static int target_eth_byte3 = 255;
++static int target_eth_byte4 = 255;
++static int target_eth_byte5 = 255;
++
++MODULE_AUTHOR("Ingo Molnar <mingo@redhat.com>");
++MODULE_DESCRIPTION("kernel network console implementation");
++MODULE_LICENSE("GPL");
++MODULE_PARM(target_ip, "i");
++MODULE_PARM(target_eth_byte0, "i");
++MODULE_PARM(target_eth_byte1, "i");
++MODULE_PARM(target_eth_byte2, "i");
++MODULE_PARM(target_eth_byte3, "i");
++MODULE_PARM(target_eth_byte4, "i");
++MODULE_PARM(target_eth_byte5, "i");
++MODULE_PARM(source_port, "h");
++MODULE_PARM(target_port, "h");
++MODULE_PARM(dev, "s");
++
++static struct console netconsole =
++       { flags: CON_ENABLED, write: write_netconsole_msg };
++
++static int init_netconsole(void)
++{
++      struct net_device *ndev = NULL;
++      struct in_device *in_dev;
++
++      // Set some reasonable defaults, at least for the NSLU2 device
++      if (!target_port)
++              target_port = 6666;
++      if (!source_port)
++              source_port = 6666;
++      if (!dev)
++              dev = "ixp0";
++
++      printk(KERN_INFO "netconsole: using network device <%s>\n", dev);
++      // this will be valid once the device goes up.
++      if (dev)
++              ndev = dev_get_by_name(dev);
++      if (!ndev) {
++              printk(KERN_ERR "netconsole: network device %s does not exist, aborting.\n", dev);
++              return -1;
++      }
++      if (!ndev->poll_controller) {
++              printk(KERN_ERR "netconsole: %s's network driver does not implement netlogging yet, aborting.\n", dev);
++              return -1;
++      }
++        in_dev = in_dev_get(ndev);
++      if (!in_dev) {
++              printk(KERN_ERR "netconsole: network device %s is not an IP protocol device, aborting.\n", dev);
++              return -1;
++      }
++      source_ip = ntohl(in_dev->ifa_list->ifa_local);
++      if (!source_ip) {
++              printk(KERN_ERR "netconsole: network device %s has no local address, aborting.\n", dev);
++              return -1;
++      }
++      source_ip = htonl(source_ip);
++#define IP(x) ((char *)&source_ip)[x]
++      printk(KERN_INFO "netconsole: using source IP %i.%i.%i.%i\n",
++              IP(0), IP(1), IP(2), IP(3));
++#undef IP
++      if (!target_ip) {
++              printk(KERN_ERR "netconsole: target_ip parameter not specified, aborting.\n");
++              return -1;
++      }
++      target_ip = htonl(target_ip);
++#define IP(x) ((char *)&target_ip)[x]
++      printk(KERN_INFO "netconsole: using target IP %i.%i.%i.%i\n",
++              IP(0), IP(1), IP(2), IP(3));
++#undef IP
++      if (!source_port) {
++              printk(KERN_ERR "netconsole: source_port parameter not specified, aborting.\n");
++              return -1;
++      }
++      printk(KERN_INFO "netconsole: using source UDP port: %i\n", source_port);
++      source_port = htons(source_port);
++      if (!target_port) {
++              printk(KERN_ERR "netconsole: target_port parameter not specified, aborting.\n");
++              return -1;
++      }
++      printk(KERN_INFO "netconsole: using target UDP port: %i\n", target_port);
++      target_port = htons(target_port);
++
++      daddr[0] = target_eth_byte0;
++      daddr[1] = target_eth_byte1;
++      daddr[2] = target_eth_byte2;
++      daddr[3] = target_eth_byte3;
++      daddr[4] = target_eth_byte4;
++      daddr[5] = target_eth_byte5;
++
++      if ((daddr[0] & daddr[1] & daddr[2] & daddr[3] & daddr[4] & daddr[5]) == 255)
++              printk(KERN_INFO "netconsole: using broadcast ethernet frames to send packets.\n");
++      else
++              printk(KERN_INFO "netconsole: using target ethernet address %02x:%02x:%02x:%02x:%02x:%02x.\n", daddr[0], daddr[1], daddr[2], daddr[3], daddr[4], daddr[5]);
++              
++      netconsole_dev = ndev;
++#define STARTUP_MSG "[...network console startup...]\n"
++      write_netconsole_msg(NULL, STARTUP_MSG, strlen(STARTUP_MSG));
++
++      register_console(&netconsole);
++      printk(KERN_INFO "netconsole: network logging started up successfully!\n");
++      return 0;
++}
++
++static void cleanup_netconsole(void)
++{
++      printk(KERN_INFO "netconsole: network logging shut down.\n");
++      unregister_console(&netconsole);
++
++#define SHUTDOWN_MSG "[...network console shutdown...]\n"
++      write_netconsole_msg(NULL, SHUTDOWN_MSG, strlen(SHUTDOWN_MSG));
++      netconsole_dev = NULL;
++}
++
++module_init(init_netconsole);
++module_exit(cleanup_netconsole);
++
++int dummy = MAX_SKB_SIZE;
+diff -Naur linux-2.4.22/include/linux/netdevice.h.orig linux-2.4.22/include/linux/netdevice.h
+--- linux-2.4.22/include/linux/netdevice.h.orig        2006-02-26 11:50:24.000000000 -0600
++++ linux-2.4.22/include/linux/netdevice.h     2006-02-26 11:37:14.000000000 -0600
+@@ -428,6 +428,9 @@
+       int                     (*neigh_setup)(struct net_device *dev, struct neigh_parms *);
+       int                     (*accept_fastpath)(struct net_device *, struct dst_entry*);
++#define HAVE_POLL_CONTROLLER
++      void                    (*poll_controller)(struct net_device *dev);
++
+       /* open/release and usage marking */
+       struct module *owner;
index 3332e54..e935ac5 100644 (file)
@@ -4,7 +4,7 @@ include nslu2-linksys-kernel_2.4.22.bb
 
 DESCRIPTION = "Unslung kernel for the Linksys NSLU2 device"
 MAINTAINER = "NSLU2 Linux <www.nlsu2-linux.org>"
-PR = "r9"
+PR = "r10"
 
 KERNEL_SUFFIX = "unslung"