linux内核协议栈 邻居协议相关数据结构

linux内核协议栈 同时被 3 个专栏收录
78 篇文章 1 订阅
44 篇文章 0 订阅
7 篇文章 0 订阅

目录

前言

1 邻居基本状态

2 邻居组合状态

2.1 NUD_IN_TIMER

2.2 NUD_VALID

2.3 NUD_CONNECTED

3 邻居相关结构体

3.1 领居表项参数 struct neigh_parms

3.2 领居表项操作函数 struct neigh_ops

3.3 领居表项 struct neighbour

3.4 邻居表 struct neigh_table


前言

在linux代码中,对于不同的邻居项,抽象出了一个通用的模型,通用邻居层,主要是用来进行邻居项的创建、添加、删除、查找、更新等操作。对于通用邻居层,最主要的就是邻居项的状态机的设计,本部分先介绍相应的数据结构,在分析通用邻居处理函数时,会仔细分析邻居状态机。本部分会简要介绍状态机。

1 邻居基本状态

首先是邻居状态的定义,在通用邻居项中定义了以下邻居状态:

/*
 *	Neighbor Cache Entry States.
 */

#define NUD_INCOMPLETE	0x01 //未完成状态:表示正在解析地址,但邻居链路层地址尚未确定。
#define NUD_REACHABLE	0x02 //可达状态:表示地址解析成功,该邻居可达。
#define NUD_STALE	0x04 //失效状态: 表示可达时间耗尽,未确定邻居是否可达。
#define NUD_DELAY	0x08 //延迟状态:表示未确定邻居是否可达。DELAY状态不是一个稳定的状态,而是一个延时等待状态。
#define NUD_PROBE	0x10 //探测状态: 节点会向处于PROBE状态的邻居持续发送NS报文。
#define NUD_FAILED	0x20 //失败:垃圾回收

/* Dummy states */
//以下三个状态无需邻居探测
#define NUD_NOARP	0x40
#define NUD_PERMANENT	0x80
#define NUD_NONE	0x00

1、对于NUD_INCOMPLETE,当本机发送完arp 请求包后,还未收到应答时,即会进入该状态。进入该状态,即会启动定时器,如果在定时器到期后,还没有收到应答时:如果没有到达最大发包上限时,即会重新进行发送请求报文;如果超过最大发包上限还没有收到应答,则会将状态设置为failed

2、对于收到可到达性确认后,即会进入NUD_REACHABLE,当进入NUD_REACHABLE状态。当进入NUD_REACHABLE后,即会启动一个定时器,当定时器到时前,该邻居协议没有

被使用过,就会将邻居项的状态转换为NUD_STALE

3、对于进入NUD_STALE状态的邻居项,即会启动一个定时器。如果在定时器到时前,有数据需要发送,则直接将数据包发送出去,并将状态设置为NUD_DELAY;如果在定时器到时,没有数据需要发送,且该邻居项的引用计数为1,则会通过垃圾回收机制,释放该邻居项对应的缓存

4、处于NUD_DELAY状态的邻居项,如果在定时器到时后,没有收到可到达性确认,则会进入NUD_PROBE状态;如果在定时器到达之前,收到可到达性确认,则会进入NUD_REACHABLE (在该状态下的邻居项不会发送solicit请求,而只是等待可到达性应答。主要包括对以前的solicit请求的应答或者收到一个对于本设备以前发送的一个数据包的应答)

5、处于NUD_PROBE状态的邻居项,会发送arp solicit请求,并启动一个定时器。如果在定时器到时前,收到可到达性确认,则进入NUD_REACHABLE;如果在定时器到时后,没有收到可到达性确认:

       a)没有超过最大发包次数时,则继续发送solicit请求,并启动定时器

       b)如果超过最大发包次数,则将邻居项状态设置为failed

2 邻居组合状态

/*
 * NUD stands for "neighbor unreachability detection"
 */

#define NUD_IN_TIMER	(NUD_INCOMPLETE|NUD_REACHABLE|NUD_DELAY|NUD_PROBE)
#define NUD_VALID	(NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE|NUD_PROBE|NUD_STALE|NUD_DELAY)
#define NUD_CONNECTED	(NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE)

2.1 NUD_IN_TIMER

对于NUD_IN_TIMER,通过名称我们就知道,当邻居项处于该状态时,则会启动定时器。下面我们一一分析这几个邻居项状态,通过分析完这几个状态,我们就基本上会理解邻居项状态机中定时器处理函数neigh_timer_handler() 的设计逻辑了。

2.2 NUD_VALID

在领居协议的基本状态中,处于NUD_REACHABLE、NUD_PROBE、NUD_STALE、NUD_DELAY状态时,数据包是可以正常发送的,只是发送的函数不同。这样就不难理解NUD_VALID包含NUD_PERMANENT、NUD_NOARP、NUD_REACHABLE、NUD_PROBE、NUD_STALE、NUD_DELAY了

2.3 NUD_CONNECTED

主要是表示邻居是可达的状态,对于NUD_PERMANENT、NUD_NOARP状态的邻居项,其邻居状态是不会改变的,一直是有效的,除非删除该邻居项。对于NUD_REACHABLE我们在上面已经介绍过了。

3 邻居相关结构体

3.1 领居表项参数 struct neigh_parms

struct neigh_parms {
#ifdef CONFIG_NET_NS
	struct net *net;
#endif
	struct net_device *dev;
	struct neigh_parms *next;
	int	(*neigh_setup)(struct neighbour *);
	void	(*neigh_cleanup)(struct neighbour *);
	struct neigh_table *tbl;

	void	*sysctl_table;

	int dead;
	atomic_t refcnt;
	struct rcu_head rcu_head;

	int	base_reachable_time;//基本有效时间 ,对于arp默认为30s
	int	retrans_time;//solicit请求报文重发间隔时间
	int	gc_staletime;//闲置时间
	int	reachable_time;//确认有效时间超时长度,这个值每隔300s会更新一次
	int	delay_probe_time;//在nud_delay时,为delay的超时时间;在nud_reach状态时,用于判断是否需要进入delay状态的一个时间判断点

	int	queue_len_bytes;//缓存数据包的队列长度
	int	ucast_probes;//发送单播solicit请求的最大次数
	int	app_probes;
	int	mcast_probes;//发送广播solicit请求的最大次数
	int	anycast_delay;
	int	proxy_delay;
	int	proxy_qlen;
	int	locktime;
};

3.2 领居表项操作函数 struct neigh_ops

struct neigh_ops {
	int			family;//所属的地址簇,对于arp,则为AF_INET
	
	//发送邻居请求的函数指针
	void			(*solicit)(struct neighbour *, struct sk_buff *);

	//当有数据要传送,且邻居项不可达时,则调用该函数向三层发送错误信息
	void			(*error_report)(struct neighbour *, struct sk_buff *);

	//通用输出函数
	int			(*output)(struct neighbour *, struct sk_buff *);
	
	//当邻居项可达时,使用该函数发送数据包
	int			(*connected_output)(struct neighbour *, struct sk_buff *);
};

3.3 领居表项 struct neighbour

struct neighbour {
	struct neighbour __rcu	*next;
	struct neigh_table	*tbl;//指向该邻居项所属的邻居表
	struct neigh_parms	*parms;//执行相关参数
	unsigned long		confirmed;//connected状态确认时间
	unsigned long		updated;//邻居项更新时间
	rwlock_t		lock;
	atomic_t		refcnt;
	struct sk_buff_head	arp_queue;//数据包缓存队列,当有数据包要发送,但又没有目的ip地址对应的目的mac时,则会将数据包缓存在该队列中
	unsigned int		arp_queue_len_bytes;
	struct timer_list	timer;
	unsigned long		used;//邻居项使用时间
	atomic_t		probes;//记录邻居项发送的solicit请求的次数
	__u8			flags;
	__u8			nud_state;//邻居项状态值
	__u8			type;//邻居项地址的类型
	__u8			dead;
	seqlock_t		ha_lock;
	unsigned char		ha[ALIGN(MAX_ADDR_LEN, sizeof(unsigned long))];
	struct hh_cache		hh;//二层缓存头部指针,指向一个二层缓存头部
	int			(*output)(struct neighbour *, struct sk_buff *);
	const struct neigh_ops	*ops; //neighbour项的函数指针表,包含发送solicit请求函数,以及不同状态下对应的输出函数
	struct rcu_head		rcu;
	struct net_device	*dev;
	u8			primary_key[0];
};

3.4 邻居表 struct neigh_table

struct neigh_table {
	struct neigh_table	*next;//指向下一个邻居协议对应的邻居表
	int			family;//该邻居协议对应的地址簇
	int			entry_size;/该邻接表所能包含的邻居项的最大值
	int			key_len;//关键字的大小,对于arp协议,是4个字节大小
	__u32			(*hash)(const void *pkey,
					const struct net_device *dev,
					__u32 *hash_rnd);//hash函数
	int			(*constructor)(struct neighbour *);//该邻居协议所对应的邻居项的邻居初始化 函数,初始化与该邻居协议相关的成员值
	int			(*pconstructor)(struct pneigh_entry *);
	void			(*pdestructor)(struct pneigh_entry *);
	void			(*proxy_redo)(struct sk_buff *skb);
	char			*id;
	struct neigh_parms	parms;
	/* HACK. gc_* should follow parms without a gap! */
	int			gc_interval;//垃圾回收处理邻居项的时间间隔
	int			gc_thresh1;//当邻居项的数量少于该值时,不会进行垃圾回收
	int			gc_thresh2;//如果邻居项的数目超过这个值,则在新建邻居项时,若超过5秒未进行刷新,则刷新并强制垃圾回收
	int			gc_thresh3;//当超过这个值时,则在创建新邻居项时,强制进行垃圾回收
	unsigned long		last_flush;//记录最新一次刷新邻居表项的时间
	struct delayed_work	gc_work;
	struct timer_list 	proxy_timer;
	struct sk_buff_head	proxy_queue;
	atomic_t		entries;//已创建邻居表项的数据
	rwlock_t		lock;
	unsigned long		last_rand;//记录neigh_parms中reach_time成员的最近更新时间
	struct neigh_statistics	__percpu *stats;//统计
	struct neigh_hash_table __rcu *nht;//存储邻居项的hash表
	struct pneigh_entry	**phash_buckets;
};

 

 

 

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
<p style="color:#666666;"> <span style="font-size:14px;">本门课程重实战,将基础知识拆解到项目里,让你在项目情境里学知识。</span> </p> <p style="color:#666666;"> <span style="font-size:14px;">这样的学习方式能让你保持兴趣、充满动力,时刻知道学的东西能用在哪、能怎么用。</span> </p> <p style="color:#666666;"> <span style="font-size:14px;">平时不明白的知识点,放在项目里去理解就恍然大悟了。</span> </p> <p style="color:#666666;"> <span></span> </p> <p style="color:#666666;"> <span style="font-size:14px;"> </span> </p> <p style="color:#666666;"> <span style="color:#FF0000;font-size:14px;"><strong>一、融汇贯通</strong></span> </p> <p style="color:#666666;"> <span style="font-size:14px;">本视频采用了前后端分离的开发模式,前端使用Vue.js+Element UI实现了Web页面的呈现,后端使用Python 的Django框架实现了数据访问的接口,前端通过Axios访问后端接口获得数据。在学习完本章节后,真正理解前后端的各自承担的工作。</span> </p> <p style="color:#666666;"> <span style="font-size:14px;"> </span> </p> <p style="color:#666666;"> <span style="color:#FF0000;font-size:14px;"><strong>二、贴近实战</strong></span> </p> <p style="color:#666666;"> <span style="font-size:14px;">本系列课程为练手项目实战:学生管理系统v4.0的开发,项目包含了如下几个内容:项目的总体介绍、基本功能的演示、Vuejs的初始化、Element UI的使用、在Django中实现针对数据的增删改查的接口、在Vuejs中实现前端增删改查的调用、实现文件的上传、实现表格的分页、实现导出数据到Excel、实现通过Excel导入数据、实现针对表格的批量化操作等等,所有的功能都通过演示完成、贴近了实战</span> </p> <p style="color:#666666;"> <span style="font-size:14px;"> </span> </p> <p style="color:#666666;"> <span style="color:#FF0000;font-size:14px;"><strong>三、课程亮点</strong></span> </p> <p style="color:#666666;"> <span style="font-size:14px;">在本案例中,最大的亮点在于前后端做了分离,真正理解前后端的各自承担的工作。前端如何和后端交互</span> </p> <p style="color:#666666;"> <span style="font-size:14px;"> </span> </p> <p style="color:#666666;"> <span style="color:#FF0000;font-size:14px;"><strong>适合人群:</strong></span> </p> <p style="color:#666666;"> <span style="font-size:14px;">1、有Python语言基础、web前端基础,想要深入学习Python Web框架的朋友;</span> </p> <p style="color:#666666;"> <span style="font-size:14px;">2、有Django基础,但是想学习企业级项目实战的朋友;</span> </p> <p style="color:#666666;"> <span style="font-size:14px;">3、有MySQL数据库基础的朋友</span> </p> <p style="color:#666666;"> <span style="font-size:14px;"> </span> </p> <p style="color:#666666;"> <span style="font-size:14px;"><img alt="" src="https://img-bss.csdnimg.cn/202009070752197496.png" /><br /> </span> </p> <p style="color:#666666;"> <span style="font-size:14px;"><br /> </span> </p>
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值