内核版本smdk 2.6.28.6

代码功能,编译后,形成test.ko,开发板加载模块后,出现结果:

===========================================

/ # lsmod

/ # insmod test.ko

/ # lsmod

test 2912 0 - Live 0xbf000000

/ # ifconfig -a

eth0      Link encap:Ethernet  HWaddr 00:E0:4A:BC:15:E7  

         inet addr:192.168.10.20  Bcast:192.168.10.255  Mask:255.255.255.0

         UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

         RX packets:1811 errors:0 dropped:0 overruns:0 frame:0

         TX packets:750 errors:0 dropped:0 overruns:0 carrier:0

         collisions:0 txqueuelen:1000

         RX bytes:2311076 (2.2 MiB)  TX bytes:125320 (122.3 KiB)

         Interrupt:108 Base address:0x300


lo        Link encap:Local Loopback  

         inet addr:127.0.0.1  Mask:255.0.0.0

         UP LOOPBACK RUNNING  MTU:16436  Metric:1

         RX packets:0 errors:0 dropped:0 overruns:0 frame:0

         TX packets:0 errors:0 dropped:0 overruns:0 carrier:0

         collisions:0 txqueuelen:0

         RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)


sx        Link encap:Local Loopback  

         LOOPBACK  MTU:16436  Metric:1

         RX packets:0 errors:0 dropped:0 overruns:0 frame:0

         TX packets:0 errors:0 dropped:0 overruns:0 carrier:0

         collisions:0 txqueuelen:0

         RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)


/ #

===========================================

代码如下:


#include <linux/kernel.h>

#include <linux/jiffies.h>

#include <linux/module.h>

#include <linux/interrupt.h>

#include <linux/fs.h>

#include <linux/types.h>

#include <linux/string.h>

#include <linux/socket.h>

#include <linux/errno.h>

#include <linux/fcntl.h>

#include <linux/in.h>

#include <linux/init.h>


#include <asm/system.h>

#include <asm/uaccess.h>

#include <asm/io.h>


#include <linux/inet.h>

#include <linux/netdevice.h>

#include <linux/etherdevice.h>

#include <linux/skbuff.h>

#include <linux/ethtool.h>

#include <net/sock.h>

#include <net/checksum.h>

#include <linux/if_ether.h>/* For the statistics structure. */

#include <linux/if_arp.h>/* For ARPHRD_ETHER */

#include <linux/ip.h>

#include <linux/tcp.h>

#include <linux/percpu.h>

#include <linux/etherdevice.h>

#include <net/net_namespace.h>


struct pcpu_lstats {

unsigned long packets;

unsigned long bytes;

};

extern int register_pernet_device(struct pernet_operations *ops);

// extern const struct header_ops eth_header_ops;


const struct header_ops eth_header_ops ____cacheline_aligned = {

.create= eth_header,

.parse= eth_header_parse,

.rebuild= eth_rebuild_header,

.cache= eth_header_cache,

.cache_update= eth_header_cache_update,

};




/*

* The higher levels take care of making this non-reentrant (it's

* called with bh's disabled).

*/

static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)

{

struct pcpu_lstats *pcpu_lstats, *lb_stats;


skb_orphan(skb);


skb->protocol = eth_type_trans(skb,dev);


dev->last_rx = jiffies;


/* it's OK to use per_cpu_ptr() because BHs are off */

pcpu_lstats = dev->ml_priv;

lb_stats = per_cpu_ptr(pcpu_lstats, smp_processor_id());

lb_stats->bytes += skb->len;

lb_stats->packets++;


netif_rx(skb);


return 0;

}


static struct net_device_stats *get_stats(struct net_device *dev)

{

const struct pcpu_lstats *pcpu_lstats;

struct net_device_stats *stats = &dev->stats;

unsigned long bytes = 0;

unsigned long packets = 0;

int i;


pcpu_lstats = dev->ml_priv;

for_each_possible_cpu(i) {

const struct pcpu_lstats *lb_stats;


lb_stats = per_cpu_ptr(pcpu_lstats, i);

bytes   += lb_stats->bytes;

packets += lb_stats->packets;

}

stats->rx_packets = packets;

stats->tx_packets = packets;

stats->rx_bytes = bytes;

stats->tx_bytes = bytes;

return stats;

}


static u32 always_on(struct net_device *dev)

{

return 1;

}


static const struct ethtool_ops loopback_ethtool_ops = {

.get_link= always_on,

.set_tso= ethtool_op_set_tso,

.get_tx_csum= always_on,

.get_sg= always_on,

.get_rx_csum= always_on,

};


static int loopback_dev_init(struct net_device *dev)

{

struct pcpu_lstats *lstats;


lstats = alloc_percpu(struct pcpu_lstats);

if (!lstats)

return -ENOMEM;


dev->ml_priv = lstats;

return 0;

}


static void loopback_dev_free(struct net_device *dev)

{

struct pcpu_lstats *lstats = dev->ml_priv;


free_percpu(lstats);

free_netdev(dev);

}


/*

* The loopback device is special. There is only one instance

* per network namespace.

*/

static void loopback_setup(struct net_device *dev)

{

dev->get_stats= &get_stats;

dev->mtu= (16 * 1024) + 20 + 20 + 12;

dev->hard_start_xmit= loopback_xmit;

dev->hard_header_len= ETH_HLEN;/* 14*/

dev->addr_len= ETH_ALEN;/* 6*/

dev->tx_queue_len= 0;

dev->type= ARPHRD_LOOPBACK;/* 0x0001*/

dev->flags= IFF_LOOPBACK;

dev->features = NETIF_F_SG | NETIF_F_FRAGLIST

| NETIF_F_TSO

| NETIF_F_NO_CSUM

| NETIF_F_HIGHDMA

| NETIF_F_LLTX

| NETIF_F_NETNS_LOCAL;

dev->ethtool_ops= &loopback_ethtool_ops;

dev->header_ops= &eth_header_ops;

dev->init = loopback_dev_init;

dev->destructor = loopback_dev_free;

}


/* Setup and register the loopback device. */

static __net_init int loopback_net_init(struct net *net)

{

struct net_device *dev;

int err;


err = -ENOMEM;

dev = alloc_netdev(0, "sx", loopback_setup);

if (!dev)

goto out;


dev_net_set(dev, net);

err = register_netdev(dev);

if (err)

goto out_free_netdev;


net->loopback_dev = dev;

return 0;



out_free_netdev:

free_netdev(dev);

out:

if (net == &init_net)

panic("loopback: Failed to register netdevice: %d\n", err);

return err;

}


static __net_exit void loopback_net_exit(struct net *net)

{

struct net_device *dev = net->loopback_dev;


unregister_netdev(dev);

}


static struct pernet_operations __net_initdata loopback_net_ops = {

      .init = loopback_net_init,

      .exit = loopback_net_exit,

};


static int __init loopback_init(void)

{

return register_pernet_device(&loopback_net_ops);

}


/* Loopback is special. It should be initialized before any other network

* device and network subsystem.

*/

fs_initcall(loopback_init);

// module_init(loopback_init);

module_exit(loopback_net_exit);

MODULE_LICENSE("GPL");



好的,今日实验到此结束