When IP data is transmitted over Ethernet, Ethernet devices cannot identify 32-bit IP addresses, but transmit Ethernet data packets at 48-bit Ethernet addresses. Therefore, IP datagram must be encapsulated as an Ethernet frame before transmission over the Ethernet, And the destination address of the Ethernet frame is obtained through querying the destination IP address of the IP datagram. Therefore, there is a ing between the IP address and the ethernet address. You can view the ARP table to obtain the ing between the two addresses. Address Resolution Protocol (ARP) is the protocol used to determine these mappings.
ARP protocol processing involves the following files:
Include/Linux/if_arp.h defines the structure, Macro, and function prototype of ARP packets.
Net/IPv4/arp. c ARP Protocol Implementation
ARP packet format
Refer to TCP/IP protocol study notes (4) ARP & RARP
Define the structure of the ARP packet header
struct arphdr{__be16ar_hrd;/* format of hardware address*/__be16ar_pro;/* format of protocol address*/unsigned charar_hln;/* length of hardware address*/unsigned charar_pln;/* length of protocol address*/__be16ar_op;/* ARP opcode (command)*/#if 0 /* * Ethernet looks like this : This bit is variable sized however... */unsigned charar_sha[ETH_ALEN];/* sender hardware address*/unsigned charar_sip[4];/* sender IP address*/unsigned charar_tha[ETH_ALEN];/* target hardware address*/unsigned charar_tip[4];/* target IP address*/#endif};Because the MAC address lengths of different network media are different, the structure of ARP packets cannot contain the content following the operation code. Here we only list the ARP definitions on Ethernet.
ARP is not only used by IPv4, but also represented by SIP and tip in the kernel's network module code.
Register the ARP packet type
Like IP datagram, ARP packets are also sent as data encapsulated in Ethernet frames. ARP packets are received and processed by arp_rcv (). During ARP module initialization, you must register the type of ARP packets in the protocol stack.
/* *Called once on startup. */static struct packet_type arp_packet_type __read_mostly = {.type =cpu_to_be16(ETH_P_ARP),.func =arp_rcv,};
ARP Initialization
ARP module initialization is completed by arp_init (). This function is called by the IPv4 protocol stack initialization function inet_init (). First, the ARP Protocol neighbor table is initialized, then register the ARP protocol in the protocol stack, and finally establish the proc object to register the event notification.
void __init arp_init(void){neigh_table_init(&arp_tbl);dev_add_pack(&arp_packet_type);arp_proc_init();#ifdef CONFIG_SYSCTLneigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4, NET_IPV4_NEIGH, "ipv4", NULL, NULL);#endifregister_netdevice_notifier(&arp_netdev_notifier);}ARP neighbor function finger table
In ARP, instances of various neighbor function pointers are provided based on different media, such as general arp_generic_ops. arp_hh_ops is the cache hardware header, arp_direct_ops of ARP and arp_broken_ops of amateur radio devices are not supported. Except for the two output function pointers output and connected_output, these neighbor function pointer table instances are not much different.
static const struct neigh_ops arp_generic_ops = {.family =AF_INET,.solicit =arp_solicit,.error_report =arp_error_report,.output =neigh_resolve_output,.connected_output =neigh_connected_output,.hh_output =dev_queue_xmit,.queue_xmit =dev_queue_xmit,};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 const struct neigh_ops arp_direct_ops = {.family =AF_INET,.output =dev_queue_xmit,.connected_output =dev_queue_xmit,.hh_output =dev_queue_xmit,.queue_xmit =dev_queue_xmit,};const struct neigh_ops arp_broken_ops = {.family =AF_INET,.solicit =arp_solicit,.error_report =arp_error_report,.output =neigh_compat_output,.connected_output =neigh_compat_output,.hh_output =dev_queue_xmit,.queue_xmit =dev_queue_xmit,};ARP table
The ARP neighbor table is arp_tbl, wherein the fields related to the Protocol characteristics are: the address family is af_inet; the neighbor item size is the neighbor structure + 4 (the IPv4 address length ); the hash algorithm is arp_hash (), the ARP initialization function is arp_constructor (), the routine for processing the proxy ARP packet is parp_redo (), and the parameters for adjusting the ARP table features.
struct neigh_table arp_tbl = {.family =AF_INET,.entry_size =sizeof(struct neighbour) + 4,.key_len =4,.hash =arp_hash,.constructor =arp_constructor,.proxy_redo =parp_redo,.id ="arp_cache",.parms = {.tbl =&arp_tbl,.base_reachable_time =30 * HZ,.retrans_time =1 * HZ,.gc_staletime =60 * HZ,.reachable_time =30 * HZ,.delay_probe_time =5 * HZ,.queue_len =3,.ucast_probes =3,.mcast_probes =3,.anycast_delay =1 * HZ,.proxy_delay =(8 * HZ) / 10,.proxy_qlen =64,.locktime =1 * HZ,},.gc_interval =30 * HZ,.gc_thresh1 =128,.gc_thresh2 =512,.gc_thresh3 =1024,};
Initialize neighbor items in IPv4
Arp_constructor () is the neighbor initialization function of ARP. It is used to create a new neighbor structure instance and called in the neigh_create () function of the neighbor table creation.
static int arp_constructor(struct neighbour *neigh){__be32 addr = *(__be32*)neigh->primary_key;struct net_device *dev = neigh->dev;struct in_device *in_dev;struct neigh_parms *parms;rcu_read_lock();in_dev = __in_dev_get_rcu(dev);if (in_dev == NULL) {rcu_read_unlock();return -EINVAL;}neigh->type = inet_addr_type(dev_net(dev), addr);parms = in_dev->arp_parms;__neigh_parms_put(neigh->parms);neigh->parms = neigh_parms_clone(parms);rcu_read_unlock();if (!dev->header_ops) {neigh->nud_state = NUD_NOARP;neigh->ops = &arp_direct_ops;neigh->output = neigh->ops->queue_xmit;} else {/* Good devices (checked by reading texts, but only Ethernet is tested) ARPHRD_ETHER: (ethernet, apfddi) ARPHRD_FDDI: (fddi) ARPHRD_IEEE802: (tr) ARPHRD_METRICOM: (strip) ARPHRD_ARCNET: etc. etc. etc. ARPHRD_IPDDP will also work, if author repairs it. I did not it, because this driver does not work even in old paradigm. */#if 1/* So... these "amateur" devices are hopeless. The only thing, that I can say now: It is very sad that we need to keep ugly obsolete code to make them happy. They should be moved to more reasonable state, now they use rebuild_header INSTEAD OF hard_start_xmit!!! Besides that, they are sort of out of date (a lot of redundant clones/copies, useless in 2.1), I wonder why people believe that they work. */switch (dev->type) {default:break;case ARPHRD_ROSE:#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)case ARPHRD_AX25:#if defined(CONFIG_NETROM) || defined(CONFIG_NETROM_MODULE)case ARPHRD_NETROM:#endifneigh->ops = &arp_broken_ops;neigh->output = neigh->ops->output;return 0;#endif;}#endifif (neigh->type == RTN_MULTICAST) {neigh->nud_state = NUD_NOARP;arp_mc_map(addr, neigh->ha, dev, 1);} else if (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) {neigh->nud_state = NUD_NOARP;memcpy(neigh->ha, dev->dev_addr, dev->addr_len);} else if (neigh->type == RTN_BROADCAST || dev->flags&IFF_POINTOPOINT) {neigh->nud_state = NUD_NOARP;memcpy(neigh->ha, dev->broadcast, dev->addr_len);}if (dev->header_ops->cache)neigh->ops = &arp_hh_ops;elseneigh->ops = &arp_generic_ops;if (neigh->nud_state&NUD_VALID)neigh->output = neigh->ops->connected_output;elseneigh->output = neigh->ops->output;}return 0;}
ARP output
Arp_send () creates an ARP packet. If it is successfully created, it is sent out. The parameter of this function is the same as that of arp_create ().
/* *Create and send an arp packet. */void arp_send(int type, int ptype, __be32 dest_ip, struct net_device *dev, __be32 src_ip, const unsigned char *dest_hw, const unsigned char *src_hw, const unsigned char *target_hw){struct sk_buff *skb;/* *No arp on this interface. */if (dev->flags&IFF_NOARP)return;skb = arp_create(type, ptype, dest_ip, dev, src_ip, dest_hw, src_hw, target_hw);if (skb == NULL) {return;}arp_xmit(skb);}
ARP Input
Arp_rcv () is used to receive and process an ARP packet from Layer 2.
/* *Receive an arp request from the device layer. */static int arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev){struct arphdr *arp;/* ARP header, plus 2 device addresses, plus 2 IP addresses. */if (!pskb_may_pull(skb, arp_hdr_len(dev)))goto freeskb;arp = arp_hdr(skb);if (arp->ar_hln != dev->addr_len || dev->flags & IFF_NOARP || skb->pkt_type == PACKET_OTHERHOST || skb->pkt_type == PACKET_LOOPBACK || arp->ar_pln != 4)goto freeskb;if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)goto out_of_mem;memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb));return NF_HOOK(NFPROTO_ARP, NF_ARP_IN, skb, dev, NULL, arp_process);freeskb:kfree_skb(skb);out_of_mem:return 0;}
Binding route table items to neighbor items
In the routing module, whenever an output route or unicast forwarding route is added, the route is bound to the neighbor item corresponding to the destination address of the route. Arp_bind_neighbour () enables you to bind a route table entry to a neighbor. During the binding process, if the corresponding neighbor item does not exist, a neighbor item is created and the route entry is bound to it. After binding, the output function can be found through the routing cache when the packet is output.
ARP: address parsing protocol implementation Learning