Linux内核-arp协议

从ip_finish_output2到dev_queue_xmit路径:

arping命令:

http://www.bluestep.cc/linux%e5%91%bd%e4%bb%a4arping-%e7%bd%91%e7%bb%9c%e7%ae%a1%e7%90%86-%e9%80%9a%e8%bf%87%e5%8f%91%e9%80%81arp%e5%8d%8f%e8%ae%ae%e6%8a%a5%e6%96%87%e6%b5%8b%e8%af%95%e7%bd%91%e7%bb%9c/

arp协议:

 

 arp报文结构:

(1).硬件类型:

硬件地址类型,该字段值一般为ARPHRD_ETHER,表示以太网。

F:\company\Linux\linux-4.1.45\linux-4.1.45\include\uapi\linux\if_arp.h
/* ARP protocol HARDWARE identifiers. */
#define ARPHRD_NETROM	0		/* from KA9Q: NET/ROM pseudo	*/
#define ARPHRD_ETHER 	1		/* Ethernet 10Mbps		*/
#define	ARPHRD_EETHER	2		/* Experimental Ethernet	*/
#define	ARPHRD_AX25	3		/* AX.25 Level 2		*/
#define	ARPHRD_PRONET	4		/* PROnet token ring		*/
#define	ARPHRD_CHAOS	5		/* Chaosnet			*/
#define	ARPHRD_IEEE802	6		/* IEEE 802.2 Ethernet/TR/TB	*/
#define	ARPHRD_ARCNET	7		/* ARCnet			*/
#define	ARPHRD_APPLETLK	8		/* APPLEtalk			*/
#define ARPHRD_DLCI	15		/* Frame Relay DLCI		*/
#define ARPHRD_ATM	19		/* ATM 				*/
...

 (2).协议类型:

表示三层地址使用的协议,该字段值一般为ETH_P_IP,表示IP协议

F:\company\Linux\linux-4.1.45\linux-4.1.45\include\uapi\linux\if_ether.h
#define ETH_P_LOOP	0x0060		/* Ethernet Loopback packet	*/
#define ETH_P_PUP	0x0200		/* Xerox PUP packet		*/
#define ETH_P_PUPAT	0x0201		/* Xerox PUP Addr Trans packet	*/
#define ETH_P_IP	0x0800		/* Internet Protocol packet	*/
#define ETH_P_X25	0x0805		/* CCITT X.25			*/
#define ETH_P_ARP	0x0806		/* Address Resolution packet	*/
...

(3)硬件地址长度,以太网MAC地址就是6;

(4)协议地址长度,IP地址就是4;

(5)操作码

常见的有四种,arp请求,arp相应,rarp请求,rarp相应。

F:\company\Linux\linux-4.1.45\linux-4.1.45\include\uapi\linux\if_arp.h
/* ARP protocol opcodes. */
#define	ARPOP_REQUEST	1		/* ARP request			*/
#define	ARPOP_REPLY	2		/* ARP reply			*/
#define	ARPOP_RREQUEST	3		/* RARP request			*/
#define	ARPOP_RREPLY	4		/* RARP reply			*/
#define	ARPOP_InREQUEST	8		/* InARP request		*/
#define	ARPOP_InREPLY	9		/* InARP reply			*/
#define	ARPOP_NAK	10		/* (ATM)ARP NAK			*/

(6)发送方硬件地址与IP地址,(7)目标硬件地址与目标IP地址。

arp头数据结构:

F:\company\Linux\linux-4.1.45\linux-4.1.45\include\uapi\linux\if_arp.h
/*
 *	This structure defines an ethernet arp header.
 */

struct arphdr {
	__be16		ar_hrd;		/* format of hardware address	*/
	__be16		ar_pro;		/* format of protocol address	*/
	unsigned char	ar_hln;		/* length of hardware address	*/
	unsigned char	ar_pln;		/* length of protocol address	*/
	__be16		ar_op;		/* ARP opcode (command)		*/

#if 0
	 /*
	  *	 Ethernet looks like this : This bit is variable sized however...
	  */
	unsigned char		ar_sha[ETH_ALEN];	/* sender hardware address	*/
	unsigned char		ar_sip[4];		/* sender IP address		*/
	unsigned char		ar_tha[ETH_ALEN];	/* target hardware address	*/
	unsigned char		ar_tip[4];		/* target IP address		*/
#endif

};

1. arp_init()

arp模块的初始化函数为arp_init(),这个函数在ipv4协议栈的初始化函数inet_init()中被调用。
1.初始化arp表arp_tbl;
2.注册arp协议类型;
3.建立arp相关proc文件,/proc/net/arp;
4.注册通知事件

F:\company\Linux\linux-4.1.45\linux-4.1.45\net\ipv4\arp.c
void __init arp_init(void)
{
	neigh_table_init(NEIGH_ARP_TABLE, &arp_tbl);//初始化arp协议的邻居表

	dev_add_pack(&arp_packet_type);//在协议栈中注册arp协议
	arp_proc_init();//建立proc对象
#ifdef CONFIG_SYSCTL
	neigh_sysctl_register(NULL, &arp_tbl.parms, NULL);
#endif
	register_netdevice_notifier(&arp_netdev_notifier);//注册通知事件
}

arp邻居项函数指针表:

F:\company\Linux\linux-4.1.45\linux-4.1.45\net\ipv4\arp.c
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,
};

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,
};

static const struct neigh_ops arp_direct_ops = {
	.family =		AF_INET,
	.output =		neigh_direct_output,
	.connected_output =	neigh_direct_output,
};

neigh_table:

一个neigh_table对应一种邻居协议,IPv4就是arp协议。用来存储于邻居协议相关的参数、功能函数、邻居项散列表等。

struct neigh_table {
	int			family;/*地址族,arp为AF_INET*/
	/*邻居项结构大小:sizeof(neighbour+4),因为neighbour结构最后一个成员0长数组,用于存储4字节长IP地址。*/
	int			entry_size;
	/*hash函数所使用的键值长度,就是IP地址长度,为4*/
	int			key_len;
	/*ETH_P_IP*/
	__be16			protocol;
	/*hash函数,arp_hash*/
	__u32			(*hash)(const void *pkey,
					const struct net_device *dev,
					__u32 *hash_rnd);
	bool			(*key_eq)(const struct neighbour *, const void *pkey);
	/*邻居表项初始化函数,用于初始化neighbour结构实例,即arp_constructor,在neigh_create中被调用*/
	int			(*constructor)(struct neighbour *);
	/*创建和释放一个代理项时被调用,代理先不管*/
	int			(*pconstructor)(struct pneigh_entry *);
	void			(*pdestructor)(struct pneigh_entry *);
	/*用来处理在proxy_queue缓存队列中的代理arp报文*/
	void			(*proxy_redo)(struct sk_buff *skb);
	/*用来分配neighbour结构实例的缓存区名,即arp_cache。*/
	char			*id;
	/*存储一些与协议相关的可调节参数,如超时重传时间,proxy_queue队列长度等*/
	struct neigh_parms	parms;
	struct list_head	parms_list;
	int			gc_interval;
	int			gc_thresh1;
	int			gc_thresh2;
	int			gc_thresh3;
	unsigned long		last_flush;
	struct delayed_work	gc_work;
	/*处理proxy_queue的定时器*/
	struct timer_list 	proxy_timer;
	/*对于接收到的需要进行代理的arp报文,先缓存到proxy_queue,在定时器处理函数中再对其进行处理。*/
	struct sk_buff_head	proxy_queue;
	/*邻居项条目数,在neigh_alloc()、neigh_destroy()中更新*/
	atomic_t		entries;
	rwlock_t		lock;
	unsigned long		last_rand;
	/*记录邻居表中有关邻居项的各类统计数据*/
	struct neigh_statistics	__percpu *stats;
	/*存储邻居项的散列表:hash表,用来存储邻居项*/
	struct neigh_hash_table __rcu *nht;
	/*存储arp代理三层协议地址的散列表*/
	struct pneigh_entry	**phash_buckets;
};

 neighbour

一个neighbour对应一个邻居项,就是一个arp条目

struct neighbour {
	struct neighbour __rcu	*next;
	struct neigh_table	*tbl;/*指向arp_tbl*/
	struct neigh_parms	*parms;
	unsigned long		confirmed;
	unsigned long		updated;
	rwlock_t		lock;
	atomic_t		refcnt;/*引用计数*/
	struct sk_buff_head	arp_queue;/*用来缓存待发送的报文*/
	unsigned int		arp_queue_len_bytes;
	struct timer_list	timer;/*定时器*/
	unsigned long		used;
	atomic_t		probes;
	__u8			flags;
	__u8			nud_state;/*邻居项状态*/
	__u8			type;/*邻居地址类型,例如单播、组播、广播等*/
	/*生存标志,为1时,表示该邻居项正在被删除,最终通过垃圾回收将其删除*/
	__u8			dead;
	seqlock_t		ha_lock;
	/*邻居项MAC地址*/
	unsigned char		ha[ALIGN(MAX_ADDR_LEN, sizeof(unsigned long))];
	/*缓存二层报头,包括目的MAC地址*/
	struct hh_cache		hh;
	/*输出函数,用来将报文输出到该邻居*/
	int			(*output)(struct neighbour *, struct sk_buff *);
	/*邻居项函数指针*/
	const struct neigh_ops	*ops;
	struct rcu_head		rcu;
	struct net_device	*dev;/*通过该设备访问邻居项*/
	u8			primary_key[0];/*存储IP地址*/
};

邻居项函数指针表,实现三层和二层的dev_queue_xmit()之间的跳转。

struct neigh_ops {
	int			family;//AF_INET
	/*发送arp报文*/
	void			(*solicit)(struct neighbour *, struct sk_buff *);
	/*向三层报告错误*/
	void			(*error_report)(struct neighbour *, struct sk_buff *);
	/*通用的输出函数,实现了完整的输出过程,存在较多的操作。*/
	int			(*output)(struct neighbour *, struct sk_buff *);
	/*确定邻居可达,即状态为NUD_CONNETCTE时的输出函数,由于所有输出所需要的信息都已具备,
	该函数只是简单地添加二层首部,发送*/
	int			(*connected_output)(struct neighbour *, struct sk_buff *);
};

neigh_statistics

用来存储统计信息,一个结构实例对应一个网络设备上的一种邻居协议。

struct neigh_statistics {
	unsigned long allocs;		/* number of allocated neighs */
	unsigned long destroys;		/* number of destroyed neighs */
	unsigned long hash_grows;	/* number of hash resizes */

	unsigned long res_failed;	/* number of failed resolutions */

	unsigned long lookups;		/* number of lookups */
	unsigned long hits;		/* number of hits (among lookups) */

	unsigned long rcv_probes_mcast;	/* number of received mcast ipv6 */
	unsigned long rcv_probes_ucast; /* number of received ucast ipv6 */

	unsigned long periodic_gc_runs;	/* number of periodic GC runs */
	unsigned long forced_gc_runs;	/* number of forced GC runs */

	unsigned long unres_discards;	/* number of unresolved drops */
};

arp表结构:arp_tbl

F:\company\Linux\linux-4.1.45\linux-4.1.45\net\ipv4\arp.c
struct neigh_table arp_tbl = {
	.family		= AF_INET,
	.key_len	= 4,
	.protocol	= cpu_to_be16(ETH_P_IP),
	.hash		= arp_hash,
	.key_eq		= arp_key_eq,
	.constructor	= arp_constructor,
	.proxy_redo	= parp_redo,
	.id		= "arp_cache",
	.parms		= {
		.tbl			= &arp_tbl,
		.reachable_time		= 30 * HZ,
		.data	= {
			[NEIGH_VAR_MCAST_PROBES] = 3,
			[NEIGH_VAR_UCAST_PROBES] = 3,
			[NEIGH_VAR_RETRANS_TIME] = 1 * HZ,
			[NEIGH_VAR_BASE_REACHABLE_TIME] = 30 * HZ,
			[NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ,
			[NEIGH_VAR_GC_STALETIME] = 60 * HZ,
			[NEIGH_VAR_QUEUE_LEN_BYTES] = 64 * 1024,
			[NEIGH_VAR_PROXY_QLEN] = 64,
			[NEIGH_VAR_ANYCAST_DELAY] = 1 * HZ,
			[NEIGH_VAR_PROXY_DELAY]	= (8 * HZ) / 10,
			[NEIGH_VAR_LOCKTIME] = 1 * HZ,
		},
	},
	.gc_interval	= 30 * HZ,
	.gc_thresh1	= 128,
	.gc_thresh2	= 512,
	.gc_thresh3	= 1024,
};

dev_add_pack()

注册arp报文类型:dev_ad

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值