linux网络协议栈分析笔记10-arp邻居子系统3
2013-04-12 19:41
1096 查看
还是回到neigh_resolve_output()
int neigh_resolve_output(struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
struct neighbour *neigh;
int rc = 0;
if (!dst || !(neigh = dst->neighbour)) 异常退出
goto discard;
__skb_pull(skb, skb_network_offset(skb));
if (!neigh_event_send(neigh, skb)) { 判断邻居项是否有可用状态,如果可用,则把数据包发送出去
int err;
struct net_device *dev = neigh->dev;
if (dev->header_ops->cache && !dst->hh) {
write_lock_bh(&neigh->lock);
if (!dst->hh)
neigh_hh_init(neigh, dst, dst->ops->protocol);
err = dev_hard_header(skb, dev, ntohs(skb->protocol),
neigh->ha, NULL, skb->len);
write_unlock_bh(&neigh->lock);
} else {
read_lock_bh(&neigh->lock);
err = dev_hard_header(skb, dev, ntohs(skb->protocol),
neigh->ha, NULL, skb->len);
read_unlock_bh(&neigh->lock);
}
if (err >= 0)
rc = neigh->ops->queue_xmit(skb);
else
goto out_kfree_skb;
}
out:
return rc;
discard:
NEIGH_PRINTK1("neigh_resolve_output: dst=%p neigh=%p\n",
dst, dst ? dst->neighbour : NULL);
out_kfree_skb:
rc = -EINVAL;
kfree_skb(skb);
goto out;
}
我们看邻居项可用的情况下的发送过程:
struct net_device *dev = neigh->dev;
if (dev->header_ops->cache && !dst->hh) { 如果hh为空 邻居项的高速缓存
write_lock_bh(&neigh->lock);
if (!dst->hh)
neigh_hh_init(neigh, dst, dst->ops->protocol); 进行hh的初始化
err = dev_hard_header(skb, dev, ntohs(skb->protocol),
neigh->ha, NULL, skb->len); 根据HH的信息构造二层头
write_unlock_bh(&neigh->lock);
} else { hh不为空时,直接根据HH的信息构造二层头
read_lock_bh(&neigh->lock);
err = dev_hard_header(skb, dev, ntohs(skb->protocol),
neigh->ha, NULL, skb->len);
read_unlock_bh(&neigh->lock);
}
if (err >= 0) 加头成功直接输出
rc = neigh->ops->queue_xmit(skb);
else
goto out_kfree_skb;
static const struct neigh_ops arp_hh_ops = {
.family = AF_INET,
.solicit = arp_solicit,
.error_report = arp_error_report,
.output = neigh_resolve_output,
.connected_output = neigh_resolve_output,
.hh_output = dev_queue_xmit,
.queue_xmit = dev_queue_xmit,
};
static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst,
__be16 protocol)
{
struct hh_cache *hh;
struct net_device *dev = dst->dev;
for (hh = n->hh; hh; hh = hh->hh_next) 从路由的协议下手找
if (hh->hh_type == protocol)
break;
if (!hh && (hh = kzalloc(sizeof(*hh), GFP_ATOMIC)) != NULL) { 找不到则申请
seqlock_init(&hh->hh_lock);
hh->hh_type = protocol; 协议类型赋值
atomic_set(&hh->hh_refcnt, 0);
hh->hh_next = NULL;
if (dev->header_ops->cache(n, hh)) { 该函数为eth_header_cache
kfree(hh);
hh = NULL;
} else {
atomic_inc(&hh->hh_refcnt);
hh->hh_next = n->hh;
n->hh = hh;
if (n->nud_state & NUD_CONNECTED)
hh->hh_output = n->ops->hh_output;
else
hh->hh_output = n->ops->output;
根据邻居项的状态选择输出函数
}
}
if (hh) {
atomic_inc(&hh->hh_refcnt);
dst->hh = hh; hh赋值
}
}
int eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh)
{
__be16 type = hh->hh_type;
struct ethhdr *eth;
const struct net_device *dev = neigh->dev;
eth = (struct ethhdr *)
(((u8 *) hh->hh_data) + (HH_DATA_OFF(sizeof(*eth))));
if (type == htons(ETH_P_802_3))
return -1;
eth->h_proto = type;
memcpy(eth->h_source, dev->dev_addr, ETH_ALEN); 填充二层地址源 目的
memcpy(eth->h_dest, neigh->ha, ETH_ALEN);
hh->hh_len = ETH_HLEN;
return 0;
}
hh_cache中存储的是链路头的一些相关信息,可以加快数据包的传输(因为有些情况下不用查看路由表,直接到此缓冲区查看).
最后再来一张邻居子系统的主要数据结构组织图 from ULKI
另附:这篇文章对arp状态转移分析得很透彻 http://blog.csdn.net/wearenoth/article/details/7794852
int neigh_resolve_output(struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
struct neighbour *neigh;
int rc = 0;
if (!dst || !(neigh = dst->neighbour)) 异常退出
goto discard;
__skb_pull(skb, skb_network_offset(skb));
if (!neigh_event_send(neigh, skb)) { 判断邻居项是否有可用状态,如果可用,则把数据包发送出去
int err;
struct net_device *dev = neigh->dev;
if (dev->header_ops->cache && !dst->hh) {
write_lock_bh(&neigh->lock);
if (!dst->hh)
neigh_hh_init(neigh, dst, dst->ops->protocol);
err = dev_hard_header(skb, dev, ntohs(skb->protocol),
neigh->ha, NULL, skb->len);
write_unlock_bh(&neigh->lock);
} else {
read_lock_bh(&neigh->lock);
err = dev_hard_header(skb, dev, ntohs(skb->protocol),
neigh->ha, NULL, skb->len);
read_unlock_bh(&neigh->lock);
}
if (err >= 0)
rc = neigh->ops->queue_xmit(skb);
else
goto out_kfree_skb;
}
out:
return rc;
discard:
NEIGH_PRINTK1("neigh_resolve_output: dst=%p neigh=%p\n",
dst, dst ? dst->neighbour : NULL);
out_kfree_skb:
rc = -EINVAL;
kfree_skb(skb);
goto out;
}
我们看邻居项可用的情况下的发送过程:
struct net_device *dev = neigh->dev;
if (dev->header_ops->cache && !dst->hh) { 如果hh为空 邻居项的高速缓存
write_lock_bh(&neigh->lock);
if (!dst->hh)
neigh_hh_init(neigh, dst, dst->ops->protocol); 进行hh的初始化
err = dev_hard_header(skb, dev, ntohs(skb->protocol),
neigh->ha, NULL, skb->len); 根据HH的信息构造二层头
write_unlock_bh(&neigh->lock);
} else { hh不为空时,直接根据HH的信息构造二层头
read_lock_bh(&neigh->lock);
err = dev_hard_header(skb, dev, ntohs(skb->protocol),
neigh->ha, NULL, skb->len);
read_unlock_bh(&neigh->lock);
}
if (err >= 0) 加头成功直接输出
rc = neigh->ops->queue_xmit(skb);
else
goto out_kfree_skb;
static const struct neigh_ops arp_hh_ops = {
.family = AF_INET,
.solicit = arp_solicit,
.error_report = arp_error_report,
.output = neigh_resolve_output,
.connected_output = neigh_resolve_output,
.hh_output = dev_queue_xmit,
.queue_xmit = dev_queue_xmit,
};
static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst,
__be16 protocol)
{
struct hh_cache *hh;
struct net_device *dev = dst->dev;
for (hh = n->hh; hh; hh = hh->hh_next) 从路由的协议下手找
if (hh->hh_type == protocol)
break;
if (!hh && (hh = kzalloc(sizeof(*hh), GFP_ATOMIC)) != NULL) { 找不到则申请
seqlock_init(&hh->hh_lock);
hh->hh_type = protocol; 协议类型赋值
atomic_set(&hh->hh_refcnt, 0);
hh->hh_next = NULL;
if (dev->header_ops->cache(n, hh)) { 该函数为eth_header_cache
kfree(hh);
hh = NULL;
} else {
atomic_inc(&hh->hh_refcnt);
hh->hh_next = n->hh;
n->hh = hh;
if (n->nud_state & NUD_CONNECTED)
hh->hh_output = n->ops->hh_output;
else
hh->hh_output = n->ops->output;
根据邻居项的状态选择输出函数
}
}
if (hh) {
atomic_inc(&hh->hh_refcnt);
dst->hh = hh; hh赋值
}
}
int eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh)
{
__be16 type = hh->hh_type;
struct ethhdr *eth;
const struct net_device *dev = neigh->dev;
eth = (struct ethhdr *)
(((u8 *) hh->hh_data) + (HH_DATA_OFF(sizeof(*eth))));
if (type == htons(ETH_P_802_3))
return -1;
eth->h_proto = type;
memcpy(eth->h_source, dev->dev_addr, ETH_ALEN); 填充二层地址源 目的
memcpy(eth->h_dest, neigh->ha, ETH_ALEN);
hh->hh_len = ETH_HLEN;
return 0;
}
hh_cache中存储的是链路头的一些相关信息,可以加快数据包的传输(因为有些情况下不用查看路由表,直接到此缓冲区查看).
最后再来一张邻居子系统的主要数据结构组织图 from ULKI
另附:这篇文章对arp状态转移分析得很透彻 http://blog.csdn.net/wearenoth/article/details/7794852
相关文章推荐
- linux网络协议栈分析笔记9-arp邻居子系统2
- linux网络协议栈(四)链路层 (3)邻居子系统&ARP
- linux网络协议栈分析笔记8-arp邻居子系统1
- linux网络协议栈(四)链路层 (3)邻居子系统&ARP
- 网络配置过程分析(linux网络协议栈笔记)
- linux网络协议栈:邻居子系统
- 网络配置过程分析二(linux网络协议栈笔记)
- linux网络协议栈分析笔记11-路由1-路由缓存
- FIB系统分析二(linux网络协议栈笔记)
- linux网络协议栈分析笔记2-网桥1
- 【Linux4.1.12源码分析】邻居子系统实现分析 - ARP - ip_finish_output2()
- linux网络协议栈分析笔记1-接入部分
- linux网络协议栈分析笔记12-路由2-FIB1
- linux网络协议栈分析笔记5-IP层的处理1
- linux网络协议栈分析笔记3-网桥2
- linux网络协议栈分析笔记4-网桥3
- linux 2.6源代码情景分析笔记之进程10
- LINUX 网络协议栈实现分析-SKBUFF 的实现
- Linux网络协议栈分析——从设备驱动到链路层
- Linux内核--网络协议栈深入分析(三)--BSD socket和传输层sock