ARP初始化

  (以下内容都基于linux内核2.4.0源码)
  
    地址解析协议ARP负责映射IP地址到mac地址。ARP邻居是主机系统或单跳可达路由并用于链路层(MAC)
寻址以代替网络层IP寻址。

1、ARP数据结构
    ARP数据结构的根(root)结构是neigh_table结构,它定义在include/net/neighbour.h。neigh_table结
构及其字段所指向的结构都用于arp缓存内部实现。每个使用ARP的网络层协议都有一个关联的neigh_table
结构实例。
 139 struct neigh_table
 140 {
 141 struct neigh_table *next;
 142 int family;
 143 int entry_size;
 144 int key_len;
 145 __u32 (*hash)(void *pkey, struct net_device *);
 146 int (*constructor)(struct neighbour *);
 147 int (*pconstructor)(struct pneigh_entry *);
 148 void (*pdestructor)(struct pneigh_entry *);
 149 void (*proxy_redo)(struct sk_buff *skb);
 150 char *id;
 151 struct neigh_parms parms;
 152 /* HACK. gc_* shoul follow parms without a gap! */
 153 int gc_interval;
 154 int gc_thresh1;
 155 int gc_thresh2;
 156 int gc_thresh3;
 157 unsigned long last_flush;
 158 struct timer_list gc_timer;
 159 struct timer_list proxy_timer;
 160 struct sk_buff_head proxy_queue;
 161 int entries;
 162 rwlock_t lock;
 163 unsigned long last_rand;
 164 struct neigh_parms *parms_list;
 165 kmem_cache_t *kmem_cachep;
 166 struct tasklet_struct gc_task;
 167 struct neigh_statistics stats;
 168 struct neighbour *hash_buckets[NEIGH_HASHMASK+1];
 169 struct pneigh_entry *phash_buckets[PNEIGH_HASHMASK+1];
 170 };
 171

结构主要字段的功能:
 next: 用于连接到邻居链表。neigh_tables指向此链表的第一个结构。似乎除了IPV4,
       仅有DECNET和IPV6注册邻居表。
 family: 协议簇(PF_INET).
 id: arp缓存表的符号名
 hash: 用于映射下一跳IP地址到特殊的哈希队列的哈希函数。对IP地址解析协议,这个函数是arp_hash()。
 entry_size: neighbour结构大小+4(应该是key长度)。
 key_len: 用于哈希函数的key长度(字节),由于IP地址就是贝用作key,所以对ARP而言,这个值就是4。
 constructor: 初始化新的neighbour结构实例。ARP缓存中,每个元素都有个neighbour结构的条目。对于
   IPV4的ARP而言,这个函数是arp_constructor()。
 kmem_cache_p: 指向neighbour结构类型的slab缓存。
 hash_buckets: neighbour结构的哈希队列。这里的哈希查找key就是下一跳的IP地址。
 phash_buckets:pneigh_entry结构的哈希队列。这个可能用于ARP代理
 gc_thresh*: 定义了邻居协议授权给缓存的neighbour条目内存使用的不同限制级别,ARP缓存增长得太
     大时这些值用于减少缓存尺寸。

总共有32个neighbor结构的哈希队列和16个pneigh的哈希队列(include/net/neighbour.h):
 131 #define NEIGH_HASHMASK 0x1F
 132 #define PNEIGH_HASHMASK 0xF

2、IPv4邻居表
IPV4 ARP协议的邻居表静态定义,如下(net/ipv4/arp.c):
 184 struct neigh_table arp_tbl =
 185 {
 186 NULL,
 187 AF_INET,
 188 sizeof(struct neighbour) + 4,
 189 4,
 190 arp_hash,
 191 arp_constructor,
 192 NULL,
 193 NULL,
 194 parp_redo,
 195 "arp_cache",
        196 { NULL, NULL, &arp_tbl, 0, NULL, NULL,
 197    30*HZ, 1*HZ, 60*HZ, 30*HZ, 5*HZ, 3, 3, 0, 3, 1*HZ, (8*HZ)/10, 64, 1*HZ },
 198 30*HZ, 128, 512, 1024,
 199 };
 
    entry_size字段设置成sizeof(struct neighbour) + 4,neighbour结构的最后的字段primary_key[0]被定
义为一个0长度数组,entry_size字段中额外的4字节确保当结构动态分配时,包含primary_key[0]的实际尺寸空间。
    parms定义了一些可操作的超时定时器。在标准的X86 Linux系统中时钟滴答每10毫秒一次,每秒中的滴答数
    HZ=100。(include/asm-i386)
 4 #ifndef HZ
 5 #define HZ 100
 6 #endif

3、neigh_parms结构
    neigh_parms定义在include/net/neighbour.h.包含此结构实例或指针的是有neigh_table, neighbour,
和in_device结构.
 53 struct neigh_parms
 54 {
 55 struct neigh_parms *next;
 56 int (*neigh_setup)(struct neighbour *);
 57 struct neigh_table *tbl;
 58 int entries;
 59 void *priv;
 60
 61 void *sysctl_table;
 62
 63 int base_reachable_time;
 64 int retrans_time;
 65 int gc_staletime;
 66 int reachable_time;
 67 int delay_probe_time;
 68
 69 int queue_len;
 70 int ucast_probes;
 71 int app_probes;
 72 int mcast_probes;
 73 int anycast_delay;
 74 int proxy_delay;
 75 int proxy_qlen;
 76 int locktime;
 77 };

4、neighbour结构   
    结构定义了单个ARP缓存元素的内容(include/net/neighbour.h)。
 87 struct neighbour
 88 {
 89 struct neighbour *next;
 90 struct neigh_table *tbl;
 91 struct neigh_parms *parms;
 92 struct net_device *dev;
 93 unsigned long used;
 94 unsigned long confirmed;
 95 unsigned long updated;
 96 __u8 flags;
 97 __u8 nud_state;
 98 __u8 type;
 99 __u8 dead;
 100 atomic_t probes;
 101 rwlock_t lock;
 102 unsigned char ha[(MAX_ADDR_LEN+sizeof(unsigned long)-1)&~(sizeof(unsigned long)-1)];
 103 struct hh_cache *hh;
 104 atomic_t refcnt;
 105 int (*output)(struct sk_buff *skb);
 106 struct sk_buff_head arp_queue;
 107 struct timer_list timer;
 108 struct neigh_ops *ops;
 109 u8 primary_key[0];
 110 };

结构主要字段的功能:
next:用于连接到特殊的hash_bucket的元素.
tbl: 向后指向拥有此结构的neigh_table结构.
parms: 向后指向其父亲neigh_table结构的成员parms组件的指针。
primary_key: 放置哈希函数使用的32位目标IP地址。其实际空间是动态分配的。
ha: 远端连接的网络设备的硬件(MAC)地址.
hh_cache: 指向目标节点的。
output: 指向用于发包的函数.当ARP缓存条目是NUD_REACHABLE状态其指向dev_queue_xmit();
 否则指向neigh_resolve_output().
arp_queue: 所拥有的sk_buffs链表。
dev: 指向与ARP缓存相关联接口所对应的net_device结构.
timer_list: 用于管理各种超时情况的内核定时器。
ops: 指向不同输出的函数指针表。

5、hh_cache结构
    硬件头缓存元素包含输出包必须的第一跳硬件头(include/linux/netdevice.h)
 179 struct hh_cache
 180 {
 181 struct hh_cache *hh_next; /* Next entry        */
 182 atomic_t hh_refcnt; /* number of users                   */
 183 unsigned short  hh_type; /* protocol identifier, f.e ETH_P_IP */
 184 int  hh_len;  /* length of header */
 185 int  (*hh_output)(struct sk_buff *skb);
 186 rwlock_t hh_lock;
 187 /* cached hardware header; allow for machine alignment needs.        */
 188 unsigned long hh_data[16/sizeof(unsigned long)];
 189 };
结构主要字段的功能:
hh_next: 链接到下一个hh_cache结构.
hh_refcnt: 控制是否删除的引用计数
hh_len: MAC层的包头长度
hh_data: 用于放硬件头.
hh_output: 指向dev_queue_xmit()函数.

6、pneigh_entry结构
结构pneigh_entry可能描述邻居代理(include/net/neighbour.h).
 124 struct pneigh_entry
 125 {
 126 struct pneigh_entry *next;
 127 struct net_device *dev;
 128 u8 key[0];
 129 };

7、Neighbour操作            
    每个neighbour结构通过都neigh_ops定义了一组操作函数集,neigh_ops结构都由其父亲neigh_table定
义的构造函数填充(include/net/neighbour.h).
 112 struct neigh_ops
 113 {
 114 int family;
 115 void (*destructor)(struct neighbour *);
 116 void (*solicit)(struct neighbour *, struct sk_buff*);
 117 void (*error_report)(struct neighbour *, struct sk_buff*);
 118 int (*output)(struct sk_buff*);
 119 int (*connected_output)(struct sk_buff*);
 120 int (*hh_output)(struct sk_buff*);
 121 int (*queue_xmit)(struct sk_buff*);
 122 };
    arp_constructor()函数设置邻居的neigh_ops结构,用以下几个定义在net/ipv4/arp.c中实例.
通用neigh_ops结构.
 136 static struct neigh_ops arp_generic_ops =
 137 {
 138 AF_INET,
 139 NULL,
 140 arp_solicit,
 141 arp_error_report,
 142 neigh_resolve_output,
 143 neigh_connected_output,
 144 dev_queue_xmit,
 145 dev_queue_xmit
 146 };

请求硬件头的设备的neigh_ops结构. 这种结构用于以太网设备.
 148 static struct neigh_ops arp_hh_ops =
 149 {
 150 AF_INET,
 151 NULL,
 152 arp_solicit,
 153 arp_error_report,
 154 neigh_resolve_output,
 155 neigh_resolve_output,
 156 dev_queue_xmit,
 157 dev_queue_xmit
 158 };

不请求ARP的邻居的neigh_ops结构.
 160 static struct neigh_ops arp_direct_ops =
 161{
 162 AF_INET,
 163 NULL,
 164 NULL,
 165 NULL,
 166 dev_queue_xmit,
 167 dev_queue_xmit,
 168 dev_queue_xmit,
 169 dev_queue_xmit
 170 };
 
用于使用旧有代码的设备(如业余无线电设备或某些WAN卡)的neigh_ops结构.
 172 struct neigh_ops arp_broken_ops =
 173{
 174 AF_INET,
 175 NULL,
 176 arp_solicit,
 177 arp_error_report,
 178 neigh_compat_output,
 179 neigh_compat_output,
 180 dev_queue_xmit,
 181 dev_queue_xmit,
 182 };

8、arp_init()函数
    定义在net/ipv4/arp.c
    被inet_init()调用
包含的操作:
    建立ARP缓存.
    注册内核ARP包类型.
    创建/proc/net/arp.
   
1156 void __init arp_init (void)
1157 {
1158 neigh_table_init(&arp_tbl);
1159
1160 dev_add_pack(&arp_packet_type);
1161
1162 proc_net_create ("arp", 0, arp_get_info);
1163
1164 #ifdef CONFIG_SYSCTL
1165 neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4, NET_IPV4_NEIGH, "ipv4");
1166 #endif
1167 }

8.1、邻居表初始化
    每个主协议簇都可以提供它自己的地址解析服务和邻居表。目前IPV6和DECNET提供它们自己的服务,
IPV4用通用的ARP。
    neigh_table_init()函数在net/core/neighbour.c中定义.
1114 void neigh_table_init(struct neigh_table *tbl)
1115 {
1116 unsigned long now = jiffies;
1117
这里reachable_time的值被统一设置成下面的随机值:
 [base_reachable_time / 2, 3 x base_reachable_time]
重调用时base_reachable_time是30秒.
1118 tbl->parms.reachable_time =neigh_rand_reach_time(tbl->parms.base_reachable_time);
arp_cache被创建. 邻居对象将被从slab缓存中分配.entry_size先前已经被设置成sizeof(struct neighbor) + 4.
1120 if (tbl->kmem_cachep == NULL)
1121  tbl->kmem_cachep = kmem_cache_create(tbl->id,
1122      (tbl->entry_size+15)&~15,
1123      0, SLAB_HWCACHE_ALIGN,
1124      NULL, NULL);
1125

ARP用内核定时器驱动用于检测超时条件的出口函数。每个定时器结构包含下面的数据元素(include/linux/timer.h):
20 struct timer_list {
21 struct list_head list;
22 unsigned long expires;
23 unsigned long data;
24 void (*function)(unsigned long);
25 };
data: 传给定时器出口函数的任意值
function: 被调用的出口函数的地址
expires: 基于jiffies的时间值,到此时间时出口函数被调用.
init_timer()函数简单初始化timer_list结构的字段.调用add_timer()将此定时器加入定时器队列.
 下面是neigh_table结构的gc_timer定时器字段的初始化,其超时值设置成30 * HZ + (~30 * HZ)
 约等于1分钟.
1129 init_timer(&tbl->gc_timer);
1130 tbl->lock = RW_LOCK_UNLOCKED;
1131 tbl->gc_timer.data = (unsigned long)tbl;
1132 tbl->gc_timer.function = neigh_periodic_timer;
1133 tbl->gc_timer.expires = now + tbl->gc_interval +tbl->parms.reachable_time;
1134 add_timer(&tbl->gc_timer);
1135

代理定时器初始化但并不链入定时器队列,直到代理ARP元素都建立
1136 init_timer(&tbl->proxy_timer);
1137 tbl->proxy_timer.data = (unsigned long)tbl;
1138 tbl->proxy_timer.function = neigh_proxy_process;
1139 skb_queue_head_init(&tbl->proxy_queue);
1140
1141 tbl->last_flush = now;
1142 tbl->last_rand = now + tbl->parms.reachable_time*20;
初始化后的邻居表(arp_tbl)被插入到全局变量neigh_tables所指的邻居表链表队列.
1143 write_lock(&neigh_tbl_lock);
1144 tbl->next = neigh_tables;
1145 neigh_tables = tbl;
1146 write_unlock(&neigh_tbl_lock);
1147 }

8.2、注册ARP包类型
    设置了ARP缓存后,arp_init()必须注册ARP包类型到链路层,这是通过调用dev_add_pack()实现.
1160 dev_add_pack(&arp_packet_type);
arp_packet_type静态定义如下
1147 static struct packet_type arp_packet_type =
1148 {
1149 __constant_htons(ETH_P_ARP),
1150 NULL,  /* All devices */
1151 arp_rcv,
1152 (void*)1,
1153 NULL
1154 };
arp_rcv()是接收到ARP包时被调用的包处理函数.传递给它的参数如下:
573 int arp_rcv(struct sk_buff *skb, struct net_device *dev,struct packet_type *pt)

8.3、创建/proc/net/arp项
注册ARP包类型后,arp_init()创建proc项以通过arp_get_info()函数显示ARP缓存的内容.
 arp_get_info()显示hash_buckets和phash_buckets中的条目.
1162 proc_net_create ("arp", 0, arp_get_info);
1163
1164 #ifdef CONFIG_SYSCTL
1165 neigh_sysctl_register(NULL, &arp_tbl.parms,NET_IPV4, NET_IPV4_NEIGH, "ipv4");
1166 #endif
1167 }
下表中,最后三个条目被代理:
/proc/net ==> cat arp
IP address HW type Flags HW address Mask Device
192.168.2.4 0x1 0x2 00:00:77:97:C3:A5 * lec0
192.168.2.5 0x1 0x2 00:00:77:88:A4:95 * lec0
192.168.2.6 0x1 0x2 00:00:77:88:A1:15 * lec0
192.168.2.35 0x1 0x2 00:50:DA:31:3F:4A * eth0
192.168.2.7 0x1 0x2 00:00:77:88:A5:A5 * lec0
192.168.2.1 0x1 0x2 00:20:48:2E:00:EE * lec0
130.127.48.184 0x1 0xc 00:00:00:00:00:00 * lec0
192.168.2.66 0x1 0xc 00:00:00:00:00:00 * lec0
192.168.2.35 0x1 0xc 00:00:00:00:00:00 * lec0
 

你可能感兴趣的:(timer,struct,table,null,Constructor,output)