Still return to neigh_resolve_output () int neigh_resolve_output (struct sk_buff * SKB)
{
Struct dst_entry * DST = skb_dst (SKB );
Struct neighbor * neigh;
Int rc = 0;
If (! DST |! (Neigh = DST-> neighbor) Exits unexpectedly.
Goto discard;
_ Skb_pull (SKB, skb_network_offset (SKB ));
If (! Neigh_event_send (Neigh, SKB) {checks whether the neighbor item is available. If yes, the packet is sent out.
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-> neighbor: NULL );
Out_kfree_skb:
Rc =-einval;
Kfree_skb (SKB );
Goto out;
}
Let's look at the sending process when the neighbor item is available: struct net_device * Dev = neigh-> dev;
If (Dev-> header_ops-> cache &&! DST-> hh) {If hh is an empty neighbor
Write_lock_bh (& neigh-> lock );
If (! DST-> hh)
Neigh_hh_init (Neigh, DST, DST-> OPS-> Protocol); initializes HH.
Err = dev_hard_header (SKB, Dev, ntohs (SKB-> Protocol ),
Neigh-> HA, null, SKB-> Len); construct a Layer 2 header Based on HH Information
Write_unlock_bh (& neigh-> lock );
} When else {hh is not blank, the second-layer header is constructed based on the HH information.
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) is successfully output directly by adding a header.
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 neighbor * 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 = kzarloc (sizeof (* hh), gfp_atomic ))! = NULL) {apply if no result is found
Seqlock_init (& hh-> hh_lock );
Hh-> hh_type = protocol; protocol type assignment
Atomic_set (& hh-> hh_refcnt, 0 );
Hh-> hh_next = NULL;
If (Dev-> header_ops-> cache (n, HH) {this function is 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;
Select the output function based on the neighbor item status
}
}
If (HH ){
Atomic_inc (& hh-> hh_refcnt );
DST-> Hh = HH; hh value assignment
}
}
Int eth_header_cache (const struct neighbor * 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); fill in memcpy (ETH-> h_dest, neigh-> HA, eth_alen) of the L2 address source );
Hh-> hh_len = eth_hlen;
Return 0;
}
Hh_cache stores some information about the link header, which can speed up data packet transmission (because in some cases, you do not need to view the route table and directly view it in this buffer zone ). finally, let's look at the main data structure organization diagram of the neighbor subsystem from ulki. Additionally, this article provides a thorough analysis of ARP status transfer.
Http://blog.csdn.net/wearenoth/article/details/7794852