Physical Address:
ChongQing,China.
WebSite:
之前有一篇文章讲过,我尝试将百度Apollo框架下的通信框架CyberRT移植到安卓系统。并且该安卓系统是作为一个虚拟机运行在Ubuntu系统上。基于Android Cuttlefish框架,安卓虚拟机借由CrosVM创建的虚拟网卡能够实现安卓Guest与Ubuntu Host之间的通信。但是移植完CyberRT之后我发现无法正常将CybertRT的测试用例跑过。原因归结到CyberRT通信过程中的多播路由问题,本篇博客将留作一个记录。
百度Apollo CyberRT 是一个开源的、高性能的运行时框架,专为自动驾驶场景而设计。针对自动驾驶的高并发、低延迟、高吞吐量进行了大幅优化。
在使用上,CyberRT支持服务发现以及订阅发布机制,并且支持跨进程、跨主机通信,还提供了共享内存能力。
在通信底层链路上,CyberRT基于UDP组播,中间借助FastDDS进行实时通信的控制。由于我对底层通信的了解并不是很多,此处略过不表。
为了便于理解,这里将会先介绍整个系统通信的拓卜结构:
在整个系统中,外部存在ADAS控制器,通过以太网网线连接到Ubuntu Host侧,在Ubuntu上,我们则运行Android Trout虚拟机。
在未设置多播路由转发的情况下,ADAS发出的cyberRT数据包只能到达Ubuntu Host侧,无法抵达Android Trout虚拟机内,反过来Android的cyberRT数据包亦无法抵达ADAS控制器。最终我们通过配置smcroute解决该问题。
你可以在Gitub上找到smcroute的官方仓库,以及获取使用相关的帮助信息。
以Ubuntu宿主机为例,我们使用apt来安装smcroute:
sudo apt-get update && sudo apt-get install smcroute
在安装完成后,我们需要配置smcroute来使其工作,smcroute依赖于/etc/smcroute.conf配置文件。在我们安装完成时,我们需要手动创建该文件并写入相关配置内容:
phyint enp0s31f6zai1
phyint cvd_wbr
mroute from enp0s31f6 group 239.255.0.1 to cvd-wbr
mroute from cvd-wbr group 239.255.0.1 to enp0s31f6
我们来解释一下配置文件中各行的含义:
phyint enp0s31f6zai1
phyint cvd_wbr
这两行用于设置多播路由中涉及到的网卡,其中enp0s31f6zai1是Ubuntu宿主机实际的物理网卡,接收由ADAS控制器发出的数据包,而cvd-wbr是由Trout CrosVM虚拟出来的虚拟网卡,用于Trout与Trout Host之间的网络通信。我们需要在smcroute配置中显式地指明涉及到转发的两个网卡。
为什么是cvd_wbr网卡呢,我们可以看看该网卡的信息:
cvd-wbr: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.96.1 netmask 255.255.255.0 broadcast 192.168.96.255
inet6 fe80::34f9:6bff:fe17:96ea prefixlen 64 scopeid 0x20<link>
ether 12:fe:dd:6a:99:49 txqueuelen 1000 (Ethernet)
RX packets 61436 bytes 6570811 (6.5 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 15383 bytes 5081012 (5.0 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
再进入宿主机内,查看网卡信息:
cvd-wbr: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.96.1 netmask 255.255.255.0 broadcast 192.168.96.255
inet6 fe80::34f9:6bff:fe17:96ea prefixlen 64 scopeid 0x20<link>
ether 12:fe:dd:6a:99:49 txqueuelen 1000 (Ethernet)
RX packets 61436 bytes 6570811 (6.5 MB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 15383 bytes 5081012 (5.0 MB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
这里我们可以看到Trout Host侧的cvd_wbr网卡与Trout内的eth2网卡是处于同一个网段的,也就是通过cvd_wbr将Host侧的网络数据包转发到了Trout内的eth2。所以我们需要将cvd_wbr囊括进来。
再看接下来两行:
mroute from enp0s31f6 group 239.255.0.1 to cvd-wbr
mroute from cvd-wbr group 239.255.0.1 to enp0s31f6
第一行表示从网卡设备enp0s31f6中将归属于239.255.0.1组的网络数据包转发至cvd-wbr。
第二行表示从网卡设备cvd-wbr中将归属于239.255.0.1组的网络数据包转发至enp0s31f6。
其中239.255.0.1的配置来源Apollo Cyber的组播地址设定。通过上述设定,完成组播数据的双向交互。
在完成上述设定后,我们使用如下命令重新启动smcroute:
systemctl restart smcroute
在工作正常的下情况下,我们可以使用tcpdump工具分别在Ubuntu Host侧与Trout内进行检测,观察是否存在对应的数据包传输。
tcpdump -i interface_name src SRC_IP
如两者都存在,则表明smcroute多播转发是正常工作的。
在某些情况下可能无法正常工作,可能的原因是smcroute本身在数据转发的过程中将ttl 值减1了,这可能会导致数据在路由过程中由于ttl=0而被丢弃,所以此时我们可以同iptables手动将ttl 加1:
iptables -t mangle -A PREROUTING -i enp0s31f6 -o cvd-wbr -d 239.255.0.1 -j TTL --ttl-inc 1
iptables -t mangle -A PREROUTING -i cvd-wbr -o enp0s31f6 -d 239.255.0.1 -j TTL --ttl-inc 1
从上面的配置来看,smcroute所起到的作用其实也就是转发。而外部的ADAS控制器在数据包传输过程中还需要知道如何将数据包传输到Android虚拟机内,此时则需要配置ADAS的路由表,如下所示:
route add -net 192.168.96.0/24 gw 10.28.10.41
上述命令则使ADAS数据包中目标IP地址为192.168.96.0/24段的数据通过10.28.10.41(Ubuntu Host的IP地址)进行路由。自此,两端即可正常通信。
在使用smcroute的过程中,还发现其在启动阶段会偶发性报错,具体提示如下:
Kernel MAXVIFS(32) too small for number of interfaces:Can't allocate memory
在我浏览了作者的issue区之后找到了解决办法,那就是更新版本;由于Ubuntu中打包的版本比较老,我选择手动编译最新版本进行安装更新,成功解决该问题。
HI sir ,
I have read most of your blogs here , and as android platform developer I learned a lot from your blogs .
I have a question about using virtual vm trout google reference and hyp crosvm.
id you succed to make some host devices accessible to guest android like bluetooth via virtio console without the passthrough ? Google web site gives just an illustration for the implementation https://source.android.com/docs/automotive/virtualization/architecture#bt
Thank you very much
Regards
Ahmed
I am not respnsible for Bluetooth but our team is working on Cuttlefish&Trout and my teamate has succeeded in connecting Bluetooth devices via virtio-console.
The HAL implementation is complete and what you should do is transfer data between Host VM and guest Android.If u need more info,maybe I can give u my teamate’s contact info.