1. 从一个报错说起为什么这个RPC连接问题值得单独聊clnt_create: RPC: Port mapper failure - Unable to receive: errno 113 (No route to host)——这行报错凡是在Linux环境下折腾过NFS挂载、NIS认证、或者自己写过RPC服务的人大概率都见过。它不像段错误那样直接崩给你看也不像权限拒绝那样明明白白告诉你“你不够格”。它更像是一个沉默的门卫你敲门没人应你甚至不确定门后面到底有没有人。这个报错的本质是RPC客户端在尝试联系服务端的port mapper端口映射器时网络层直接告诉你“路由不可达”。注意是网络层的问题不是RPC协议本身的问题。errno 113在Linux的errno.h里定义为EHOSTUNREACH意思是“没有到目标主机的路由”。换句话说你的机器连目标主机的网络都到不了后面的RPC握手、端口查询、服务调用全都是空中楼阁。这篇文章适合三类人看第一类运维工程师半夜被NFS挂载失败告警叫醒看到这行报错一脸懵第二类后端开发自己搭了一套基于RPC的微服务或者测试环境客户端死活连不上第三类嵌入式或工控方向的从业者设备之间通过RPC通信现场调试时遇到这个问题。不管你是哪一类这篇文章会从网络层一路往上拆到RPC层把每一个可能导致这个报错的环节都摊开讲清楚并且给出可以直接抄的排查命令和修复方案。我自己的经历里这个问题出现过不下十次每次原因都不一样有一次是防火墙把port mapper的111端口给挡了有一次是路由表里少了一条静态路由还有一次最离谱——目标机器的网卡驱动挂了但系统没报任何硬件错误只是网络不通。所以别指望一个命令就能解决所有情况关键是要有一套系统的排查思路。2. 拆解报错链路从clnt_create到errno 113到底发生了什么2.1 RPC调用中port mapper的角色定位要理解这个报错得先搞清楚RPC的调用流程。以NFS为例客户端要挂载一个远程目录它并不是直接去连NFS服务端的2049端口。实际上NFS服务端在启动时会先向本地的port mapper注册自己“我是NFS服务我监听在2049端口”。port mapper本身固定监听在111端口TCP和UDP都是111。客户端的clnt_create函数做的事情是这样的第一步根据你传入的主机名或IP尝试建立到目标主机111端口的连接第二步通过RPC协议向port mapper查询“NFS服务在哪个端口”第三步拿到端口号后再连接到那个端口进行实际的RPC调用。所以当报错说“Port mapper failure”时问题出在第一步或第二步。而errno 113 (No route to host)明确告诉你问题出在第一步的网络连接上——客户端根本没能和目标的111端口建立通信。这里有个容易混淆的点No route to host和Connection refused是两码事。Connection refused意味着你的包到了目标主机但目标主机的111端口没有服务在监听内核直接回了一个RST。而No route to host意味着你的包压根就没送到目标主机可能是在本地路由查找阶段就失败了也可能是在网络中间被 ICMP 不可达消息给拒绝了。2.2 errno 113在不同操作系统上的表现差异虽然errno 113在Linux上统一表示EHOSTUNREACH但在不同系统上触发这个错误的底层原因和表现形式有细微差别。比如在某些Unix系统上如果目标主机被防火墙静默丢弃DROP而不是拒绝REJECT客户端可能会先超时然后才报No route to host。而在Linux上如果本地路由表里没有匹配的路由条目内核会立刻返回EHOSTUNREACH不需要等待超时。另外如果你用的是容器环境比如Docker或KubernetesNo route to host还可能是因为容器网络插件的路由规则没有正确下发。这种情况下从容器内部ping目标主机可能通但RPC调用就是不行因为RPC走的端口或者协议族TCP/UDP被特殊处理了。注意不要看到No route to host就只盯着路由表看。防火墙的REJECT策略、SELinux的网络访问控制、甚至网卡的MTU设置都可能导致这个报错。3. 系统化排查手册从底层网络到RPC服务的完整检查清单3.1 第一步永远是确认基础网络连通性遇到这个报错先别急着改RPC配置。打开终端按顺序执行下面这几条命令。我把它叫做“网络三层检查法”第一层物理层和链路层。用ip link show确认网卡状态是UP还是DOWN。如果网卡是DOWN的那后面都不用看了先解决网卡问题。如果是虚拟机检查虚拟网卡是否被正确桥接或NAT。第二层网络层。用ip addr show确认本机IP配置正确然后用ip route show查看路由表。重点看默认网关是否存在以及到目标网段是否有明确的路由条目。比如目标主机是192.168.1.100你的路由表里应该有一条192.168.1.0/24 dev eth0或者一条默认路由default via 192.168.1.1。第三层传输层。用ping测试ICMP连通性但要注意很多防火墙会禁ICMP所以ping不通不代表网络不通。更可靠的是用nc -zv 目标IP 111或者telnet 目标IP 111来测试TCP 111端口的可达性。如果这一步报No route to host那问题基本锁定在网络层或防火墙。这里有个实操心得如果ping通但nc报No route to host大概率是中间有防火墙对特定端口做了REJECT而且REJECT时携带了ICMP host-unreachable消息。这种情况下你需要检查目标主机的iptables/nftables规则或者中间网络设备的ACL策略。3.2 防火墙与SELinux的隐蔽陷阱防火墙是导致这个报错的头号嫌疑犯。在Linux上iptables和firewalld的规则如果配置不当会直接导致No route to host。比如下面这条规则iptables -A INPUT -p tcp --dport 111 -j REJECT --reject-with icmp-host-unreachable这条规则会让客户端收到ICMP host-unreachable消息然后RPC库就会报errno 113。注意如果是-j DROP客户端会一直重试直到超时报的可能是Connection timed out而不是No route to host。所以看到errno 113反而说明有设备主动发了ICMP不可达消息这其实是个线索——至少说明你的包到达了某个能做出响应的节点。SELinux方面如果你的RPC服务运行在 enforcing 模式下SELinux可能会阻止port mapper绑定111端口或者阻止客户端连接。用ausearch -m avc -ts recent查看最近的AVC拒绝记录。如果确实有SELinux拦截可以临时用setenforce 0测试但生产环境不建议直接关闭应该用semanage port -a添加正确的端口标签。3.3 port mapper服务本身的健康检查如果网络层没问题下一步就是确认目标主机的port mapper服务是否正常运行。在目标主机上执行systemctl status rpcbind # 或者 rpcinfo -p localhostrpcinfo -p会列出所有注册到port mapper的RPC服务及其端口。如果这个命令本身都报错那说明rpcbind服务有问题。常见的情况是rpcbind没启动或者启动后因为配置文件错误而崩溃。另外注意rpcbind同时监听TCP和UDP的111端口。有些防火墙只放行了TCP 111但RPC的某些查询走的是UDP。所以确保两个协议都放行。用ss -tulnp | grep 111可以查看rpcbind的监听状态。提示在某些发行版上rpcbind服务默认只监听127.0.0.1。如果你需要远程客户端连接必须修改/etc/hosts.allow或者rpcbind的启动参数让它监听0.0.0.0。这个坑我踩过明明服务在跑rpcinfo -p localhost也正常但远程就是连不上最后发现是绑定地址的问题。4. 实战复现与修复三个真实场景的完整操作记录4.1 场景一防火墙REJECT策略导致的RPC连接失败这是最常见的情况。我在一个测试环境里客户端是CentOS 7服务端是Ubuntu 20.04。客户端执行showmount -e 192.168.1.50直接报clnt_create: RPC: Port mapper failure - Unable to receive: errno 113。排查过程先在客户端ping 192.168.1.50通。然后nc -zv 192.168.1.50 111报No route to host。这就奇怪了ping通但端口不通。登录服务端检查iptables规则iptables -L -n --line-numbers发现有一条规则REJECT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:111 reject-with icmp-host-unreachable。这条规则是之前有人为了“安全加固”加上的但忘了NFS需要port mapper。修复方法删除这条规则或者添加一条允许规则。我选择添加允许规则保留原有的REJECT作为默认策略iptables -I INPUT 1 -p tcp --dport 111 -j ACCEPT iptables -I INPUT 1 -p udp --dport 111 -j ACCEPT然后客户端重新执行showmount -e成功列出共享目录。这里的关键点是REJECT和DROP的区别。REJECT会返回ICMP错误让客户端快速失败并报errno 113DROP会让客户端超时报错信息不同。所以如果你看到errno 113优先检查是否有REJECT规则。4.2 场景二路由表缺失导致的跨网段RPC失败这个场景发生在两个不同网段之间。客户端在10.0.1.0/24服务端在10.0.2.0/24。客户端能ping通服务端的网关但ping不通服务端本身。ip route show显示只有一条默认路由指向10.0.1.1但没有到10.0.2.0/24的特定路由。问题在于默认网关10.0.1.1可能没有配置到10.0.2.0/24的回程路由或者中间的路由器没有正确转发。这种情况下客户端的包发出去了但中间路由器不知道往哪转发返回ICMP host-unreachable客户端就报errno 113。修复方法在客户端添加一条静态路由ip route add 10.0.2.0/24 via 10.0.1.1 dev eth0或者在服务端和中间路由器上检查路由配置。这个场景的教训是不要假设默认网关能处理所有网段。在复杂的网络拓扑里静态路由或者动态路由协议如OSPF是必须的。4.3 场景三容器网络插件路由规则异常在Kubernetes环境里Pod之间的RPC调用也可能报这个错。我遇到过一次两个Pod在同一个节点上但一个Pod访问另一个Pod的RPC服务时报No route to host。检查Pod的IP和路由kubectl exec -it pod-a -- ip route发现Pod-a的路由表里到Pod-b的IP没有匹配的路由条目只有一条默认路由指向cni0网桥。但cni0网桥的IP转发规则可能被误删了。检查节点的iptables规则发现CNI插件的链被清空了。修复方法重启CNI插件比如Calico或Flannel让它重新下发路由规则。或者手动添加路由ip route add pod-b-ip/32 dev cni0这个场景的排查难点在于容器网络是虚拟的ping和nc的行为可能和物理机不一样。建议在容器里用traceroute或者mtr来确认包到底走到了哪一跳。5. 常见问题速查表与避坑经验汇总5.1 报错信息与可能原因的对照表报错信息可能原因排查命令修复方向No route to host 111端口不通防火墙REJECT规则iptables -L -n放行TCP/UDP 111No route to host ping不通路由表缺失或错误ip route show添加静态路由No route to host 仅特定网段中间网络设备ACLtraceroute联系网络管理员No route to host 容器环境CNI插件路由异常kubectl exec -- ip route重启CNI插件Connection refusedrpcbind未启动systemctl status rpcbind启动rpcbind服务Connection timed out防火墙DROP规则iptables -L -n改为ACCEPT或删除DROP5.2 那些文档里不会写的避坑技巧技巧一用rpcinfo -T tcp和rpcinfo -T udp分别测试。很多人只用默认的rpcinfo -p它可能走UDP。如果你的防火墙只放行了TCPUDP查询就会失败但报错信息可能一样。显式指定协议可以快速定位问题。技巧二检查/etc/hosts和DNS解析。有时候clnt_create传入的是主机名如果DNS解析到了错误的IP或者/etc/hosts里有陈旧的条目就会连到一台不存在的机器上报No route to host。用getent hosts 主机名确认解析结果。技巧三注意MTU和分片问题。在某些网络环境下MTU设置不当会导致大包被丢弃但小包如ping能通。RPC的某些查询包可能比较大触发分片然后被中间设备丢弃。用ping -M do -s 1472 目标IP测试MTU。技巧四查看/var/log/messages或dmesg。有时候内核会记录“martian packet”或者“ICMP host unreachable”的日志这些日志能直接告诉你哪个设备发了不可达消息。注意如果你在云环境里安全组规则和网络ACL是两层独立的防火墙。安全组作用于实例级别网络ACL作用于子网级别。两者都要检查别只改了一个就以为万事大吉。6. 从修复到预防让RPC连接更稳定的几个习惯6.1 配置管理上的建议与其每次出问题再排查不如在部署阶段就把隐患堵住。我的习惯是在部署任何依赖RPC的服务NFS、NIS、自定义RPC服务之前先写一个检查脚本把下面这些项目过一遍确认rpcbind服务已启动并且监听在正确的地址和端口上。确认防火墙规则里TCP和UDP的111端口都已放行并且规则顺序正确ACCEPT在REJECT之前。确认路由表里到客户端网段的路由是明确的不依赖默认网关的“猜测”。确认SELinux要么是permissive模式要么已经添加了正确的端口标签。确认/etc/hosts和DNS解析一致没有陈旧的IP映射。这个脚本可以在每次变更后跑一遍花不了两分钟但能省下半夜被叫醒的麻烦。6.2 监控与告警的切入点对于生产环境建议对port mapper的可用性做主动监控。用rpcinfo -p 目标IP作为监控项如果连续两次失败就触发告警。注意监控项要同时覆盖TCP和UDP因为有些RPC服务只注册了UDP。另外可以在客户端侧监控clnt_create的失败率。如果你有自己的RPC客户端代码可以在调用clnt_create之后检查返回值如果失败记录下errno和当时的网络状态比如路由表快照方便事后分析。6.3 最后分享一个我常用的快速诊断命令组合当你再次看到clnt_create: RPC: Port mapper failure - Unable to receive: errno 113时别慌按顺序执行下面这组命令基本能在五分钟内定位到问题# 1. 确认目标主机可达性 ping -c 2 目标IP # 2. 确认111端口TCP可达性 nc -zv -w 2 目标IP 111 # 3. 确认111端口UDP可达性 nc -zuv -w 2 目标IP 111 # 4. 查看本地路由表 ip route get 目标IP # 5. 查看本地防火墙规则 iptables -L -n | grep 111 # 6. 在目标主机上确认rpcbind状态 rpcinfo -p localhost这六条命令跑完问题基本就水落石出了。如果还是不行那就用tcpdump抓包看看包到底发出去没有以及中间有没有ICMP不可达消息回来。抓包命令tcpdump -i any -nn host 目标IP and port 111 -c 20这个命令会抓20个包足够你判断是请求没发出去还是响应没回来。根据我的经验大部分情况下问题都出在防火墙规则或者路由表上真正是RPC协议本身出问题的概率极低。所以把排查重心放在网络层往往能事半功倍。