Linux IPv4 forward自动丢弃源IP为系统已绑定的IP的问题

A是路由,其上做了策略,一部分符合特定条件的流量,是要转发到B进行封装处理,A和B之间做了数个VLAN,B根据VLAN应用不同的策略。

不过这里的问题是,B的默认网关也是A(环路问题是不存在的,已经有对应规则处理),所以B自身发出的流量也会由A应用策略,转发回给B自己。而B收到src IP是local IP(系统已绑定的IP)的包时,kernel会直接丢弃数据包,所以除了B自己的数据包,B都能正常封装。

解决这个问题的一个方法,是让A在把数据包转发给B前,做一次SNAT,这样B收到的数据包,src IP就是A的IP了。其实SNAT并没有什么影响,A对NAT也有hardware offload,但这样操作实在觉得多此一举。

翻了下kernel ip sysctl部分的文档,发现个参数accept_local:

accept_local – BOOLEAN

Accept packets with local source addresses. In combination with suitable routing, this can be used to direct packets between two local interfaces over the wire and have them accepted properly. default FALSE

所以把这个参数置1就能不依赖SNAT解决问题了:

TCP Sendbuffer Size与RTT的问题

最近从A服务器下载数据时,发现如果走B服务器的VPN下载,速率只能跑到300KB左右,但是B从A直接下载却能跑到1MB+/s,B到本地的速度也远超过A到B的速度,其实一开始我以为是VPN实现的问题,有段时间在思考如何优化VPN,但是尝试了其它VPN实现,问题并没有解决。后来发现,走B的代理而不是VPN,速度正常。

本地到B的RTT大约160ms,B到A大约50ms。

Wireshark抓包,对tcp sequence number统计了下:

放大点看:

大概每传输60KB,就要等大约200ms才能继续。200ms刚好差不多等于本地走VPN到A的RTT。传这60KB,只花了大概10ms,忽略这10ms不算的话,每秒大概只能接收五次60KB,5*60KB=300KB,刚好接近走VPN的下载速度。

TCP要发送的数据包存放在send buffer中,send buffer已使用的空间,在收到ACK前是不能释放的,所以,如果这时send buffer满了而未收到ACK,那kernel就不会继续对外发送数据。

所以,走VPN慢的原因,是因为A设定的的send buffer太小,在本地发出的ACK送达A前,A的send buffer就满了。走B代理快,是因为B到A的RTT比较小,ACK是由B上的代理程序在接收到数据后发送给A的,所以A很快就能收到ACK而继续向B发送数据,B到本地没有send buffer过小的问题,所以B上的代理往本地发回数据的速率几乎与A到B的速率一致。

双路超线程物理服务器的QEMU CPU affinity调整

首先运行 virsh capabilities 查看物理机物理核心及其线程与逻辑处理器(线程)的关系:

其中的socket_id代表CPU的槽位,core_id代表CPU物理核心,siblings表示哪些逻辑处理器(线程)是属于同一个物理核心的。

例如id为0以及8的逻辑处理器,都属于同一个CPU槽位且属于同一个物理核心。

在这台物理机上建立的虚拟机,想得到最佳的性能,首先不要跨CPU插槽,其次,不要让多个虚拟机CPU共享同一个物理核心。

根据上面的信息,4核心8线程的虚拟机CPU亲和度配置如下:

其中vcpu 0和1在虚拟机中对应一个物理核心的两个线程,将其亲和度设定到逻辑处理器0和8,后面vcpu 2-7,同理。

启动虚拟机,通过 virsh vcpupin 进行验证:

到虚拟机中查看/proc/cpuinfo:

上面输出的信息可以确定设定无误,因为第一、二个逻辑核心对应了第一个物理核心,后面第三到第八个也同理。如果输出的core id与cputune处设定时所期望的顺序不对,调整cputune中的参数即可。

mdadm RAID1转RAID10

mdadm支持missing两个硬盘的情况下组RAID10,因此可以先通过两个新硬盘+两个missing组RAID10,然后把现有RAID1中的数据拷贝到新的RAID10中,再把现有RAID1中的两个分区加入到新的RAID10中,让mdadm自动重建数据。

下面假设现有的RAID1分区是/dev/sda5与/dev/sdb5,新的两个分区是/dev/sdc5与/dev/sdd5,最终目的是要使用/dev/sda5、/dev/sdb5、/dev/sdc5以级/dev/sdd5组RAID10。

首先备份数据。

如果操作的是系统分区,使用LiveCD操作即可。

通过两个新的分区+两个missing构建RAID10(这种情况下等于RAID0):

RAID10构建好后,把RAID1中的数据拷贝到RAID10中:

从RAID1中移除第一个分区,加入到RAID10中:

查看重建进度:

重建完成后,把RAID1中剩余的另一个分区也加入到RAID10中:

第二个分区重建完成后,编辑/etc/mdadm/mdadm.conf,把旧的RAID1删除,并把RAID10的信息存入/etc/mdadm/mdadm.conf中,更新initramfs:

如果是通过LiveCD操作的,最后重建完成后的步骤,chroot进系统盘操作。

L2TPv3 MTU

L2TPv3支持自动拆包,封装后的数据包如果超出裸线路的MTU也能正常运作。

拆包合包毕竟需要耗资源的,这种多余的操作,能避免的话当然最好。

要避免,首先确定好L2TPv3隧道的MTU。

图:

UDP封装模式:

L2TPv3隧道MTU = 裸线路MTU – IP头 – UDP头 – L2TPv3头 – 以太网头

经测试L2TPv3头在这种模式下是12字节,如果裸线路MTU是1500,那么隧道MTU = 1500 – 20 – 8 – 12 – 14 = 1446,TCP MSS = 1446 – 20 – 20 = 1406

IP封装模式:

L2TPv3隧道MTU = 裸线路MTU – IP头 –  L2TPv3头 – 以太网头

经测试L2TPv3头在这种模式下是8字节,如果裸线路MTU是1500,那么隧道MTU = 1500 – 20 – 8 – 14 = 1458,TCP MSS = 1458- 20 – 20 = 1418

 

以太网头不一定是14字节,根据实际使用情况自行调整。