LOOPBACK网络回送设备
(1) 当从主机内部发送一个目标地址为本机地址的IP包时,
ip_route_output()将IP包的输出路由定向到回送设备.
回送设备的驱动程序可看成是最简单的以太网设备驱动程序, 它的硬件地址为零,
IP地址一般设定为标准回送地址127.0.0.1.
当包调度器启动回送设备的硬件发射操作(hard_start_xmit)时, 驱动程序将发送包作为接收包,
交给一般的接收过程(netif_rx)进行排队处理.
(2) 对回送设备来说, 根本无需硬件地址解析(ARP)过程来解析IP包的帧头目的地址.
所有指向回送设备的缓冲路由将共享同一邻居结构,
该邻居结构在ARP邻居缓冲表中以零地址来标识, 它的状态为NUD_NOARP, 属于NUD_CONNECT状态,
即为永久连接状态. 路由缓冲的输出口一开始仍指向邻居解析输出口(neigh_resolve_output),
当传送第一个包时, 解析口将绕过ARP过程立接建立路由的帧头缓冲结构,
使输出通过帧头缓冲直接指向包发射器(dev_queue_xmit), 该帧头缓冲结构将一直有效.
#define LOOPBACK_OVERHEAD (128 + MAX_HEADER + 16 + 16)
/*
* 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 net_device_stats *stats = (struct net_device_stats *)dev->priv;
/*
* Optimise so buffers with skb->free=1 are not copied but
* instead are lobbed from tx queue to rx queue
*/
if(atomic_read(&skb->users) != 1)
{
struct sk_buff *skb2=skb; 继承包的复制特性
skb=skb_clone(skb, GFP_ATOMIC); /* Clone the buffer */
if(skb==NULL) {
kfree_skb(skb2);
return 0;
}
kfree_skb(skb2);
}
else
skb_orphan(skb); 释放源套接字对该包的拥有
skb->protocol=eth_type_trans(skb,dev); 识别并去除硬件帧头
skb->dev=dev;
#ifndef LOOPBACK_MUST_CHECKSUM
skb->ip_summed = CHECKSUM_UNNECESSARY;
#endif
netif_rx(skb);
stats->rx_bytes+=skb->len; 对回送设备来说, 发送的字节数就是接收的字节数
stats->tx_bytes+=skb->len; 发送包的数量就是接收包的数量
stats->rx_packets++;
stats->tx_packets++;
return(0);
}
static struct net_device_stats *get_stats(struct net_device *dev)
{
return (struct net_device_stats *)dev->priv;
}
/* Initialize the rest of the LOOPBACK device. */
int __init loopback_init(struct net_device *dev)
{
dev->mtu = PAGE_SIZE - LOOPBACK_OVERHEAD; 使得包数据缓冲区不超过1页
dev->hard_start_xmit = loopback_xmit;
dev->hard_header = eth_header;
dev->hard_header_cache = eth_header_cache;
dev->header_cache_update= eth_header_cache_update;
dev->hard_header_len = ETH_HLEN; /* 14 */
dev->addr_len = ETH_ALEN; /* 6 */
dev->tx_queue_len = 0;
dev->type = ARPHRD_LOOPBACK; /* 0x0001 */
dev->rebuild_header = eth_rebuild_header;
dev->flags = IFF_LOOPBACK;
dev->priv = kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);
if (dev->priv == NULL)
return -ENOMEM;
memset(dev->priv, 0, sizeof(struct net_device_stats));
dev->get_stats = get_stats;
if (num_physpages >= ((128*1024*1024)>>PAGE_SHIFT)) 如果物理内存达到128M
dev->mtu = 4096*4 - LOOPBACK_OVERHEAD; 增大包数据缓冲区,使包缓冲区不超过4页
/*
* Fill in the generic fields of the device structure.
*/
dev_init_buffers(dev);
return(0);
};
阅读(675) | 评论(0) | 转发(0) |