key_vector详解

key_vector是linux网络路由时,非常重要的一个结构,其定义如下:

struct key_vector {

t_key key;

unsigned char pos; /* 2log(KEYLENGTH) bits needed */

unsigned char bits; /* 2log(KEYLENGTH) bits needed */

unsigned char slen; 子网长度

union {

/* This list pointer if valid if (pos | bits) == 0 (LEAF) */

struct hlist_head leaf;

/* This array is valid if (pos | bits) > 0 (TNODE) */

struct key_vector __rcu *tnode[0];

};

};

先不解释结构中几个字段的含义,首先用一段代码,将系统中顶层的key_vector,及其下层的key_vector中的数据打印出来。


void PrintKeyVector(struct key_vector* p_kv)
{
	int n_count;
	int i;
	if (NULL == p_kv)
	{
		return;
	}

	printk("----------\n");
	printk("key: %lx\n", p_kv->key);
	printk("pos: %x\n", p_kv->pos);
	printk("bit: %x\n", p_kv->bits);
	printk("slen: %x\n", p_kv->slen);
}

static int hello_open(struct inode* inode, struct file*filep)
{
	struct task_struct *tsk = current;
	struct fib_table *tb;

	struct trie *t;
	struct key_vector *n, *pn;

	int i = 0;
	int n_count;

	// 主表-254 RT_TABLE_MAIN
	// 本地表-255 RT_TABLE_LOCAL
	tb = fib_get_table(tsk->nsproxy->net_ns, RT_TABLE_MAIN);
	printk("fib_table tb_id: %d\n", tb->tb_id); 

	printk("fib_table tb_num_default: %d\n", tb->tb_num_default); 

	t = (struct trie *) tb->tb_data;

	pn = t->kv;

	n = get_child_rcu(pn, 0);
	PrintKeyVector(n);

	n_count = 1 << n->bits;
	for (; i < n_count; ++i)
	{
		struct key_vector* pkv = n->tnode[i];
		printk("index = %d\n", i);
		PrintKeyVector(pkv);
	}
	return 0;
}

打印的日志:

[  227.486538] fib_table tb_id: 254
[  227.486540] fib_table tb_num_default: 1
[  227.486540] ----------
[  227.486541] key: 0
[  227.486542] pos: 1d
[  227.486542] bit: 3
[  227.486543] slen: 20
[  227.486544] index = 0
[  227.486544] ----------
[  227.486545] key: 0
[  227.486545] pos: 0
[  227.486546] bit: 0
[  227.486546] slen: 20
[  227.486547] index = 1
[  227.486548] index = 2
[  227.486548] index = 3
[  227.486549] ----------
[  227.486549] key: 7f000000
[  227.486550] pos: 16
[  227.486550] bit: 2
[  227.486551] slen: 18
[  227.486551] index = 4
[  227.486552] index = 5
[  227.486552] ----------
[  227.486553] key: a8000000
[  227.486554] pos: 19
[  227.486554] bit: 2
[  227.486555] slen: 19
[  227.486555] index = 6
[  227.486556] ----------
[  227.486556] key: c0a80000
[  227.486557] pos: 6
[  227.486557] bit: 2
[  227.486558] slen: 8
[  227.486559] index = 7 

 根据打印的日志,整理了下面的结构图:

key_vector详解_第1张图片

图1

 中间是上层的key_vector,两边的4个属于其下层。

key_vector各字段介绍

1. key

key表示的是IP地址或IP地址段,如key=0,表示的地址是0.0.0.0;key=0xc0a80000,表示的地址是192.168.0.0。

2. bit

bit用来表示下层有几个key_vector,下层对象的指针,存放在tnode指向的数组中。用2的bit次方,可以计算出下层key_vector的数量。中间key_vector的bit为3,表示其下面有8个key_vector。

3. pos

pos需要和bit一块使用,从pos开始的bit个位,表示了下层vector在本层vector的tnode数组中存放的位置。

中间vector的pos为29,bit为3,说明下层key_vector的key,从29开始的3位(已标红的3位),表识了在中间key_vector数组的索引。

如:key为0xc0a80000(即192.168.0.0)的key_vector,对应的3位为0x110,该对象的指针,存放在中间key_vector数组的索引为6的位置。

4. slen

slen为后缀长度。

次层key_vector

用上面同样的方法,将192.168.0.0的下层key_vector打印出来。

key_vector详解_第2张图片

图2

 上层pos为6,bits为2,因此下层key中从第6位开始的2位,标识了下层在上次数组中的索引。

 路由查找过程

#define get_cindex(key, kv) (((key) ^ (kv)->key) >> (kv)->pos)

get_cindex用于计算地址在tnode数组中的索引。

本机ip是192.168.0.106,下面分析下查找192.168.0.100路由的过程。

1层路由:

目的地址 addr = 0xc0a80064

key_vector对应图1中间那个,pos为29,key为0,调用get_cindex计算出索引为6,则次层为图1中左下角的key_vector。

2层路由

目的地址 addr =  0xc0a80064

key_vector对应图2中左上角那个,pos为6,key为0xc0a80000,调用get_cindex计算出索引为1,则再下一层为图2右下角那个,也是查找的目的节点。

 理解了上面的内容,再看内核fib_table_lookup的代码时,就清晰多了。

你可能感兴趣的:(网络,linux,内核,网络,路由)