OpenVSwitch实现浅谈(三)

Megaflow的规模越小,对应的hash table数量越少,相应的kernel datapath的转发性能更好。为了减少megaflow的规模,OpenVSwitch只有在有包上送到ovs-vswitchd之后,才会生成megaflow cache,也就是说,incoming packets驱动了megaflow cache的生成。这与早期的Microflow cache的生成方式一样。不同于早期的microflow cache的是,megaflow cache是一种模糊匹配,并且应该尽量模糊,因为这样可以匹配更多不同的网络连接,减少上送ovs-vswitchd的次数。但是又不能太模糊,因为这样会导致匹配出错。所以,怎么确定一条megaflow cache的匹配内容?

例如前面介绍的OpenFlow规则:

priority=200,ip,nw_dst=10.0.0.0/16 actions=output:1

匹配了Ethernet Type(IP)和IP header中目的IP地址的前16bit。对于下面的网络连接对应的网络数据包:

11.0.0.2:5742 -> 10.0.0.10:3306

上送ovs-vswitchd生成的megaflow cache如下,Megaflow会且仅会匹配在经过OpenFlow pipeline时,用到过的field(可以精确到field的某些bit,例如这里的目的IP前16bit)

ip,nw_dst=10.0.0.0/16 actions=output:1

这样,在其他类似网络连接到来时

11.0.0.2:5743 -> 10.0.0.10:3307
11.0.0.2:5744 -> 10.0.0.10:3308
11.0.0.3:5742 -> 10.0.0.10:3309

都不需要上送ovs-vswitchd,直接匹配这条megaflow cache就可以完成转发。在这个简单的例子里面,似乎没有问题。

如果增加一条OpenFlow规则:

priority=200,ip,nw_dst=10.0.0.0/16 actions=output:1
priority=100,ip,nw_dst=20.0.0.0/16,tcp_dst=22 actions=drop

相应的,在查找OpenFlow规则时,因为现在有两种Match,会生成两个hash table,因为要确保更高优先级的OpenFlow规则不被遗漏,所以两个hash table都会被查询,也就是说有的OpenFlow规则的match部分都会被用到。对于同样的网络连接:

11.0.0.2:5742 -> 10.0.0.10:3306

上送ovs-vswitchd生成的megaflow cache如下,这里,Megaflow还是会且仅会匹配在经过OpenFlow pipeline时,用到过的field。

ip,nw_dst=10.0.0.0/16,tcp_dst=3306 actions=output:1

尽管tcp_dst并不重要,但是因为查询OpenFlow规则时,它最终影响到了查询结果,所以在Megaflow cache中也会出现。当同样的其他网络连接到来时:

11.0.0.2:5743 -> 10.0.0.10:3307
11.0.0.2:5744 -> 10.0.0.10:3308
11.0.0.3:5742 -> 10.0.0.10:3309

因为匹配不了megaflow cache,都需要上送ovs-vswitchd。这样,仅仅因为一条无关的OpenFlow规则,使得megaflow的优势不复存在了,这明显不合理。因此OpenVSwitch针对megaflow cache的存在,优化了OpenFlow pipeline的查找方式。

Tuple Priority Sorting(优先级排序)

首先是针对OpenFlow的优先级做了优化。按照之前的介绍,如果查找一个OpenFlow Table,总是要查找这个OpenFlow Table对应的所有hash table。即使找到了一个匹配,因为不确定还有没有更高优的匹配,还需要继续查找。针对这点,OpenVSwitch对于一个OpenFlow Table生成的所有hash table,增加了一个属性:pri_max。它代表当前hash table中所有OpenFlow规则的最高优先级。在查找一个OpenFlow Table的所有hash table时,OpenVSwitch会根据pri_max从高到低依次遍历。这样,当匹配到某一条OpenFlow规则时,对应的优先级为priority_F,如果下一个hash table的pri_max < priority_F。意味着,接下来的所有hash table中,都不可能找到更高优先级的OpenFlow规则,也就没有必要查找接下来的hash table。

回到上面的例子,如果当前OpenFlow Table有两条规则:

priority=200,ip,nw_dst=10.0.0.0/16 actions=output:1
priority=100,ip,nw_dst=20.0.0.0/16,tcp_dst=22 actions=drop

当下面的网络包上送到ovs-vswitchd时,

11.0.0.2:5742 -> 10.0.0.10:3306

因为在第一个Hash table(pri_max=200)就可以完成匹配,并且匹配的OpenFlow规则优先级为200,这样没有必要查找第二个Hash table(pri_max=100)。所以在查找OpenFlow规则时,tcp_dst并没有被用到,生成的megaflow cache如下:

ip,nw_dst=10.0.0.0/16 actions=output:1

这样,前面提出的问题被解决了,Megaflow cache的匹配又足够模糊了。为了发挥Tuple Priority Sorting的最大作用:在下发OpenFlow规则时,应当尽量将相同Match的OpenFlow规则配置相同的优先级,并且一个OpenFlow Table中,优先级应当尽量少(OpenFlow定义的优先级是16bit整数)。

Staged Lookup(分段查找)

如果将之前的OpenFlow规则稍作修改:

priority=200,ip,nw_dst=10.0.0.0/16 actions=output:1
priority=300,ip,nw_dst=20.0.0.0/16,tcp_dst=22 actions=drop

这个时候,Tuple Priority Sorting的优势就不存在了,因为带有tcp_dst的OpenFlow规则优先级更高,总是会被先查询到。当下面的网络包上送到ovs-vswitchd时,

11.0.0.2:5742 -> 10.0.0.10:3306

相应的生成的megaflow规则中总是要匹配tcp_dst。所以在下发OpenFlow规则时,似乎应当将带有tcp_dst的OpenFlow规则设置成更低优先级,但是这又没有道理。

其实不仅是传输层端口号,为了发挥Tuple Priority Sorting 的优势,匹配了容易变化的field的OpenFlow规则应该低优先级,而匹配了不容易变化的field的OpenFlow规则应该高优先级。这样可以尽量生成只匹配不容易变化的field的megaflow cache,这样的megaflow cache满足尽量的模糊,从而在kernel datapath匹配更多的网络连接。但是这增加了OpenFlow逻辑实现的难度,因为相当于在逻辑实现层面需要考虑底层实现。

另一个办法就是对于具体的OpenFlow规则,先匹配其不容易变化的部分,如果这部分不匹配,就没有必要再去匹配1111111111111111111111111111111111111111容易变化的部分。但是TSS基于hash table的实现使得区分field变得困难,因为所有相关的field都被hash成一个散列值,没有办法从这个散列值中找出一些field的子集。因此,OpenVSwitch在实现OpenFlow的TSS时,按照field是否容易变化,将原来的一个Hash table分成了四个hash table。第一个hash table只包括metadata,例如ingress port,第二个Hash table包括metadata 和 L2 field,第三个Hash table 包括metadata,L2 field和L3 field,第四个包括metadata,L2 field,L3 field和L4 field,也就是所有的field。最后一个hash table就是之前介绍的Hash table。现在在进行TSS时,原来查找Hash table的部分,会变成顺序的查找这4个Hash table,如果哪个不匹配,就立刻返回,这样可以避免查询不必要的field。这么划分的依据是,在TCP/IP中,外层报文的头部总是比内层报文的头部变化更多。这就是Staged lookup。

所以对应于上面的OpenFlow规则,如果下面的网络包上送到ovs-vswitchd,

11.0.0.2:5742 -> 10.0.0.10:3306

对于priority=300的OpenFlow规则对应的Hash table,因为不匹配metadata,所以没有第一个Hash table。在匹配第三个Hash table时,因为目的IP地址不匹配,可以立即终止,此时只用到了Ethernet Type(IP)和IP header中的目的IP地址的前16bit,tcp_dst并未用到,所以生成的megaflow cache自然也不会匹配tcp_dst。Staged Lookup本质是优先匹配更不容易变化的field,可以看做是Tuple Priority Sorting的升级版。

虽然有了Staged Lookup,但是之前查找一个Hash table变成了要查找4个hash table,直观感受是查找性能要下降。但是实际性能差不多,因为大部分的不匹配在查找前两个Hash table就能返回。而前两个hash table的所需要的hash值,计算起来比计算完整的hash值要更节约时间。并且4个Hash table,后面的包含了前面的所有field,而散列值的计算可以是增量计算,就算查找到了第4个Hash table,计算散列值的消耗与拆分前是一样的。

Staged Lookup要发挥作用,在下发OpenFlow规则时,如果匹配包含了tcp_dst这类易变化的field,应当尽量包含一些metadata,L2 field,或者L3 field。

Prefix Tracking

如果现在OpenFlow规则如下:

priority=200,ip,nw_dst=10.0.0.0/16 actions=output:1
priority=300,ip,nw_dst=20.0.0.2/32,tcp_dst=22 actions=drop

那么当下面的网络包上送到ovs-vswitchd时:

11.0.0.2:5742 -> 10.0.0.10:3306

虽然有Tuple Priority Sorting和Staged Lookup,但是因为priority=300的OpenFlow规则匹配的是32位的目的IP地址,在遍历其对应的4个Hash table时,在第3个Hash table不匹配返回,再去查找别的OpenFlow规则对应的Hash table,最终生成的megaflow cache如下所示:

ip,nw_dst=10.0.0.10/32 actions=output:1

因为在pri_max=300的Hash Table中,最终用到了目的IP地址的整个32bit。当其他的网络连接到来时:

11.0.0.2:5743 -> 10.0.0.11:3307
11.0.0.2:5744 -> 10.0.0.12:3308
11.0.0.3:5742 -> 10.0.0.13:3309

因为目的IP地址不匹配,都需要上送到ovs-vswitchd重新生成megaflow cache,所以这里也有一些优化空间。OpenVSwitch用了一个Trie 树来管理一个OpenFlow Table中的所有IP地址匹配,实际实现的时候是按照bit生成树。这里为了描述简单,用byte来生成树。之前的OpenFlow对应的Trie树如下所示:

在执行TSS之前,OpenVSwitch会遍历Trie 树来执行LPM(Longest Prefix Match)。通过这个遍历,可以确定(1)生成megaflow cache所需要的IP prefix长度;(2)避免一些不必要的Hash table查找。

回到刚刚那个网络包:

11.0.0.2:5742 -> 10.0.0.10:3306

通过遍历Trie树可以知道,为了匹配目的IP地址(10.0.0.10),可以遍历到10->0节点,因此只需要匹配前16bit的IP地址就可以在当前OpenFlow Table找到匹配。因此对于这个网络包,生成的megaflow,只需要匹配目的IP地址的前16bit。

另一方面,对于下面的网络包:

11.0.0.2:5742 -> 30.0.0.10:3306

通过遍历Trie树可以知道必然不能匹配目的IP地址,所以也没有必要执行TSS来查找相应的Hash table。

Prefix Tracking是非常有必要的,因为通过OpenFlow实现路由表时,为了实现LPM,通常带有更长的prefix的OpenFlow规则会有更高的优先级,而配合前面的Tuple Priority Sorting,会导致一个OpenFlow Table生成的megaflow cache总是匹配最长的prefix(例如这一小节的例子)。通过Prefix Tracking,可以使得生成的megaflow只匹配足够的IP地址bit数。

不仅对于IP地址,对于传输层端口号,OpenVSwitch也实现了类似的Prefix Tracking,这样当OpenFlow Table中如果出现了只匹配传输层端口号的OpenFlow规则时,生成的megaflow也不用精确匹配传输层端口的16bit,只需要匹配相应的bit位就可以。这样的最终目的还是为了让megaflow足够模糊。

OpenVSwitch还有一些其他的优化手段,但是整体而言,都是为了让生成的megaflow cache尽量模糊,以减少上送ovs-vswitchd的次数,以提升OpenVSwitch的转发性能。

二手游戏转让地图

posted @ 2021-09-28 09:39  ludongguoa  阅读(198)  评论(0编辑  收藏  举报