您的位置:首页 > 理论基础 > 计算机网络

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: