|
Loopback adapter driver
1. The difference between the ordinary and the loopback adapter card is that he is not the actual physical virtual card, which is equivalent to the sending end and the receiving end of an ordinary card shorted together.
2. In the kernel source code of the program loopback adapter (drivers / net / loopback.c) is not given in the form of a module, but his initialize (loopback_net_init) and exit functions (loopback_dev_free) will be called to other parts of the kernel .
3. Referring to the flowchart NIC driver initialization design, which can not be assigned net_device structure alloc_etherdev function, because the function is assigned the structure of an Ethernet card, use alloc_netdev loopback adapter to assign a function to the structure. Refer to the kernel source code for others how to use this function alloc_netdev (0, "lo", loopback_setup); 0 represents the size of the first private members net_device this structure, generally choose 0, the second one is the name of the NIC, ifconfig displays name, and the third is the specific structure of the card initialization function pointer.
struct net_device * dev;
dev = alloc_netdev (0, "lo", loopback_setup);
Eventually calls to loopback_setup function. (As for the function pointer as a parameter when how to pass parameters, it is necessary to review the C language)
4. The loopback adapter does not need to initialize the hardware. So direct registration loopback adapter structure into kernel (third step). Finally, specify the loopback adapter is registered to the network subsystem.
net-> loopback_dev = dev; this step is critical.
5. The specific initialization (loopback_setup) (second step)
(1) base address, MAC address and interrupt numbers are need, mainly netdev_ops this structure, it contains the NIC supports.
(2) loopback adapter supports the maximum size of the received data packet, in addition to official data, as well as the first part of the relevant network protocols.
dev-> mtu = (16 * 1024) + 20 + 20 + 12; valid data is generally defined as 16KB.
(3) plus exclusive sign indicates loopback adapter.
dev-> flags = IFF_LOOPBACK;
,
(4) plus configuration header structure pointer, the structure members of this structure are numerous pointer constructor function pointers Ethernet packet header.
dev-> header_ops = & eth_header_ops;
Find the ideal can be seen
extern const struct header_ops eth_header_ops;
struct header_ops {
int (* create) (struct sk_buff * skb, struct net_device * dev,
unsigned short type, const void * daddr,
const void * saddr, unsigned len);
int (* parse) (const struct sk_buff * skb, unsigned char * haddr);
int (* rebuild) (struct sk_buff * skb);
#define HAVE_HEADER_CACHE
int (* cache) (const struct neighbour * neigh, struct hh_cache * hh);
void (* cache_update) (struct hh_cache * hh,
const struct net_device * dev,
const unsigned char * haddr);
};
6. The data transmission
static int loopback_net_xmit (struct sk_buff * skb, struct net_device * dev)
{
skb-> protocol = eth_type_trans (skb, dev);
packets ++;
bytes + = skb-> len;
netif_rx (skb);
return 0;
}
}
(1) The first parameter is the transport protocol stack to the loopback adapter packet data, the second argument is the structure of the loopback adapter.
(2) Stop sending queue
Notifies the upper suspend transmission data, so that data txd sent has been delivered, but does not involve hardware, so the loopback adapter can be ignored. Accordingly, data is written to register and send wake-up and the release queue can be ignored again.
(3) Information and Statistics, show that the upper layer protocol packet sent down
skb-> protocol = eth_type_trans (skb, dev);
(4) Statistical data sent over the size and the number of packages.
bytes + = skb-> len;
netif_rx (skb);
7. Since the protocol stack from storage data packets (skb) to txd, and txd do not need to send out, and txd rxd "connected" together, so a direct call netif_rx receiving portion of the common card in the transmission section (skb) function Therefore sent simultaneously to complete the reception. Meanwhile, we see more clearly at the time of transmission can not be released skb, otherwise there is no acceptable data.
Function 8. achieve access card status
static struct net_device_stats * loopback_get_stats (struct net_device * dev)
{
struct net_device_stats * stats = & dev-> stats;
stats-> rx_packets = packets;
stats-> tx_packets = packets;
stats-> rx_bytes = bytes;
stats-> tx_bytes = bytes;
return stats;
}
NIC status information can be obtained from this structure
/ * The main device statistics structure * /
struct rtnl_link_stats64 {
__u64 rx_packets; / * total packets received * /
__u64 tx_packets; / * total packets transmitted * /
__u64 rx_bytes; / * total bytes received * /
__u64 tx_bytes; / * total bytes transmitted * /
__u64 rx_errors; / * bad packets received * /
__u64 tx_errors; / * packet transmit problems * /
__u64 rx_dropped; / * no space in linux buffers * /
__u64 tx_dropped; / * no space available in linux * /
__u64 multicast; / * multicast packets received * /
__u64 collisions;
/ * Detailed rx_errors: * /
__u64 rx_length_errors;
__u64 rx_over_errors; / * receiver ring buff overflow * /
__u64 rx_crc_errors; / * recved pkt with crc error * /
__u64 rx_frame_errors; / * recv'd frame alignment error * /
__u64 rx_fifo_errors; / * recv'r fifo overrun * /
__u64 rx_missed_errors; / * receiver missed packet * /
/ * Detailed tx_errors * /
__u64 tx_aborted_errors;
__u64 tx_carrier_errors;
__u64 tx_fifo_errors;
__u64 tx_heartbeat_errors;
__u64 tx_window_errors;
/ * For cslip etc * /
__u64 rx_compressed;
__u64 tx_compressed;
};
This is mainly four members
stats-> rx_packets = packets;
stats-> tx_packets = packets;
stats-> rx_bytes = bytes;
stats-> tx_bytes = bytes;
. stats so members can define a struct net_device_stats stats point to a parameter passed in the time of rewriting the loopback adapter structure; in fact, they can override this function to obtain the status, because struct net_device * dev is a member of the struct net_device_stats stats also need to pay attention only to the members of the four members of the stats can be.
9. When exiting the drive is to cancel the registration of the structure. To achieve the purpose of cancellation of the card.
static __net_exit void loopback_net_exit (struct net * net)
{
struct net_device * dev = net-> loopback_dev;
unregister_netdev (dev);
}
The following is sample code
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include / * For the statistics structure. * /
#include / * For ARPHRD_ETHER * /
#include
#include
#include
#include
#include
unsigned long packets = 0;
unsigned long bytes = 0;
// Struct net_device * dev;
static __net_exit void loopback_net_exit (struct net * net)
{
struct net_device * dev = net-> loopback_dev;
unregister_netdev (dev);
}
static int loopback_net_xmit (struct sk_buff * skb, struct net_device * dev)
{
skb-> protocol = eth_type_trans (skb, dev);
packets ++;
bytes + = skb-> len;
netif_rx (skb);
return 0;
}
static struct net_device_stats * loopback_get_stats (struct net_device * dev)
{
struct net_device_stats * stats = & dev-> stats;
stats-> rx_packets = packets;
stats-> tx_packets = packets;
stats-> rx_bytes = bytes;
stats-> tx_bytes = bytes;
return stats;
}
static const struct net_device_ops loopback_ops =
{
.ndo_start_xmit = loopback_net_xmit,
.ndo_get_stats = loopback_get_stats,
};
/ *
* The loopback device is special. There is only one instance
* Per network namespace.
* /
static void loopback_setup (struct net_device * dev)
{
dev-> mtu = (16 * 1024) + 20 + 20 + 12;
dev-> flags = IFF_LOOPBACK;
dev-> header_ops = & eth_header_ops;
dev-> netdev_ops = & loopback_ops;
}
/ * Setup and register the loopback device. * /
static int loopback_net_init (struct net * net)
{
struct net_device * dev;
//1.
dev = alloc_netdev (0, "lo", loopback_setup);
// 4.
register_netdev (dev);
net-> loopback_dev = dev;
return 0;
}
/ * Registered in net / core / dev.c * /
struct pernet_operations __net_initdata loopback_net_ops = {
.init = loopback_net_init,
.exit = loopback_net_exit,
}; |
|
|
|