1. 从一个报错说起:为什么这个RPC连接问题值得单独聊
clnt_create: RPC: Port mapper failure - Unable to receive: errno 113 (No route to host)——这行报错,凡是在Linux环境下折腾过NFS挂载、做过RPC服务调试、或者维护过分布式存储集群的人,大概率都见过。它不像语法错误那样直白,也不像权限拒绝那样一目了然,而是卡在“网络可达性”和“服务注册”之间的灰色地带,让人第一反应往往是“网络没问题啊,能ping通”,然后陷入反复重启服务的死循环。
这个报错的核心含义其实很明确:客户端在尝试通过clnt_create创建一个RPC客户端句柄时,需要先联系目标主机上的port mapper(端口映射器,通常监听在TCP/UDP 111端口),由它来告知目标RPC服务实际监听的端口号。而errno 113 (No route to host)说明客户端在尝试接收port mapper的响应时,底层网络栈直接返回了“无法到达主机”。注意,这里的关键词是“Unable to receive”——不是连接被拒绝,不是超时,而是路由层面就已经不通了。
这篇文章适合三类人看:第一类是在运维岗位上突然遇到NFS挂载失败、被这个报错卡住的朋友;第二类是在开发RPC服务时,本地测试正常但跨主机调用就报这个错的工程师;第三类是想系统理解RPC调用链路、port mapper工作机制的技术爱好者。我会从原理拆到实操,把排查路径、参数配置、常见坑点全部铺开,尽量做到你看完就能直接上手定位问题,而不是对着报错发呆。
需要提前说明的是,errno 113这个错误码在不同场景下可能由不同原因触发,但围绕clnt_create和port mapper的组合出现时,排查思路是有规律可循的。下面我按“先理解机制、再拆解原因、最后落地排查”的顺序展开,中间会穿插我自己踩过的坑和实测有效的操作步骤。
2. 先把调用链路搞清楚:clnt_create到底做了什么
2.1 RPC调用中port mapper的角色定位
要理解这个报错,必须先搞清楚RPC服务在网络上是怎么“被找到”的。很多人习惯性地认为,我启动了NFS服务,它就应该监听在2049端口,客户端直接连2049就行了。但实际上,RPC体系的设计要复杂一层。
在RPC的经典实现中,服务端程序启动时,会先向本机的port mapper注册自己:“我是某个程序编号、某个版本号的服务,我现在监听在某个端口上。”port mapper本身固定监听在111端口,它的作用就像一个电话总机——你打总机,告诉它你要找哪个部门,它告诉你分机号是多少。
clnt_create这个函数做的事情就是:根据你提供的主机名、程序编号、版本号和协议类型,先联系目标主机的port mapper(111端口),查询目标服务实际监听的端口,然后创建一个指向该端口的客户端句柄。整个过程分两步:第一步是“问总机”,第二步是“拨分机”。
所以当报错信息里出现Port mapper failure时,说明问题出在第一步——连总机都没联系上。而errno 113 (No route to host)进一步说明,不是总机不接电话,而是你的电话线根本没通到那栋楼。
2.2 errno 113与常见网络错误的本质区别
很多人会把No route to host和Connection refused、Connection timed out混为一谈,觉得都是“连不上”。但它们在排查方向上有本质区别。
Connection refused意味着你的请求到达了目标主机,但目标端口上没有程序在监听,操作系统直接回了一个RST包。这说明网络是通的,问题在服务端。
Connection timed out意味着你的请求发出去了,但迟迟没有收到任何响应,通常是防火墙丢包或者目标主机宕机。这说明网络路径可能存在问题,但不确定。
No route to host则更底层——你的操作系统在尝试发送数据包时,路由表里找不到到达目标地址的路径,或者ARP解析失败,或者中间路由器返回了ICMP不可达消息。简单说,数据包还没出你的机器(或者刚出去就被打回来了),就已经知道“此路不通”。
这个区别非常关键。当你看到errno 113时,排查重点应该放在路由、ARP、防火墙规则、网卡状态这些层面,而不是去检查NFS服务有没有启动、port mapper有没有运行。方向错了,再怎么重启服务都是白费。
2.3 为什么“能ping通”不代表RPC能通
这是最容易被误导的地方。很多人的第一反应是ping一下目标主机,发现能通,就认定网络没问题。但ping走的是ICMP协议,而RPC的port mapper查询走的是TCP或UDP的111端口。这两条路径在以下情况下会出现分歧:
- 防火墙对ICMP放行,但对TCP/UDP 111端口做了限制或丢弃
- 目标主机有多张网卡,ICMP响应从A网卡回来,但RPC请求被路由到了B网卡
- 中间网络设备对ICMP和TCP/UDP的处理策略不同
- ARP缓存过期或错误,导致数据包无法正确封装
所以正确的做法是:不要只依赖ping,要用telnet、nc或者rpcinfo直接测试111端口的可达性。这一点我在后面会给出具体的命令。
3. 逐层拆解:errno 113在RPC场景下的六大触发原因
3.1 路由表缺失或错误导致数据包无法出站
这是最直接的原因。当你的主机路由表中没有到达目标网段的路由条目时,操作系统在发送数据包时会直接返回ENETUNREACH或EHOSTUNREACH,对应到errno就是113。
这种情况常见于:新配置的服务器没有设置默认网关、多网卡环境下路由优先级混乱、或者手动添加了错误的路由规则。排查方法是ip route get <目标IP>,看看操作系统实际会选择哪条路径。如果返回unreachable,那就说明路由表有问题。
我遇到过一次典型场景:一台测试机同时接入了办公网和实验网,默认路由指向办公网网关,但目标NFS服务器在实验网段。结果就是ping能通(因为ICMP走了实验网的直连路由),但RPC请求被默认路由带到了办公网网关,网关不知道怎么转发,直接回了ICMP不可达。
3.2 防火墙规则拦截了111端口的RPC查询
防火墙是另一个高频原因。很多环境的防火墙策略是“默认拒绝,按需放行”,管理员可能放行了NFS的2049端口,但忘了放行port mapper的111端口。这时候客户端尝试联系111端口,防火墙直接丢弃或拒绝,表现可能就是No route to host。
需要注意的是,不同防火墙的行为不同。iptables的DROP目标会导致超时,REJECT目标会返回ICMP不可达(可能表现为errno 113),而某些硬件防火墙可能直接返回ICMP host unreachable。所以看到errno 113时,不要假设防火墙一定是“拒绝”状态,也可能是“丢弃”状态被中间设备转换成了不可达消息。
3.3 ARP解析失败导致局域网内通信中断
如果目标主机和你在同一个局域网内,No route to host很可能意味着ARP解析失败了。操作系统需要知道目标IP对应的MAC地址才能封装以太网帧,如果ARP请求没有得到响应,数据包就发不出去。
ARP失败的原因包括:目标主机关机或网卡故障、ARP缓存中有错误的静态条目、VLAN配置不一致导致ARP请求无法到达目标、或者中间有ARP代理配置错误。排查方法是arp -n查看ARP缓存,或者用arping直接测试ARP层可达性。
3.4 网卡状态异常或链路层故障
物理层和链路层的问题也会表现为No route to host。比如网卡被down掉了、网线松动、交换机端口被禁用、VLAN配置错误等。这种情况下,操作系统可能仍然保留着路由表条目,但实际数据包无法通过网卡发送出去。
排查时用ip link show确认网卡状态是UP还是DOWN,用ethtool检查链路状态,用ip -s link查看是否有发送错误计数增长。
3.5 目标主机多网卡环境下的回程路由问题
这是一个比较隐蔽的原因。目标主机有两张网卡,A网卡在192.168.1.0/24网段,B网卡在10.0.0.0/24网段。你的客户端在10.0.0.0/24网段,请求发到了目标主机的B网卡。但目标主机在回复port mapper查询时,根据其路由表选择了A网卡作为出口。如果你的客户端无法从A网卡所在的网段被访问,回复包就到不了你手里。
这种情况下,ping可能正常(因为ICMP可能走了正确的路径),但RPC查询的回复包走了错误路径。排查方法是在目标主机上用ip route get <客户端IP>确认回程路由,必要时添加策略路由。
3.6 虚拟化与容器环境中的网络隔离
在虚拟机或容器环境中,No route to host还可能由虚拟网络配置引起。比如虚拟交换机的安全组规则、容器的网络命名空间隔离、overlay网络的隧道故障等。这类问题的排查需要结合具体的虚拟化平台工具,但基本思路仍然是:先确认二层可达,再确认三层路由,最后确认端口过滤。
4. 实操排查手册:从零定位errno 113
4.1 第一步:确认基础网络可达性
拿到报错后,不要急着改配置,先做最基础的连通性测试。我习惯按以下顺序执行:
# 1. 确认目标主机IP是否可达(ICMP层) ping -c 3 <目标IP> # 2. 确认路由路径 ip route get <目标IP> # 3. 确认ARP缓存(同网段场景) arp -n | grep <目标IP> # 4. 确认网卡状态 ip link show这四步能快速排除掉物理层、链路层和路由表层面的明显问题。如果ip route get返回unreachable,后面的测试就不用做了,直接去修路由。如果ping不通但路由存在,重点查ARP和防火墙。
提示:有些环境禁用了ICMP,
ping不通不代表网络有问题。这时候直接跳到端口测试。
4.2 第二步:直接测试111端口连通性
ping通不代表111端口通。用以下命令直接测试port mapper端口:
# 使用nc测试TCP 111端口 nc -zv <目标IP> 111 # 使用telnet测试 telnet <目标IP> 111 # 使用rpcinfo直接查询port mapper rpcinfo -p <目标IP>rpcinfo -p是最直接的验证方式,它做的就是clnt_create类似的事情——联系目标主机的port mapper并列出注册的服务。如果这个命令也报No route to host,说明问题确实在port mapper的可达性上。如果rpcinfo能成功但你的程序报错,那问题可能在程序使用的协议类型(TCP还是UDP)或者程序编号上。
4.3 第三步:检查本机防火墙与目标防火墙
防火墙排查要两头做。先看本机有没有出站限制:
# 查看本机iptables规则 iptables -L -n -v # 查看本机nftables规则(新版系统) nft list ruleset # 查看firewalld状态 firewall-cmd --list-all然后确认目标主机的入站规则。如果你能登录目标主机,检查其防火墙是否放行了111端口和RPC动态端口范围。RPC服务除了port mapper的111端口外,实际服务还会监听一个动态端口,这个端口也需要放行。
注意:很多教程只让你放行111和2049,但NFS相关的RPC服务(如mountd、statd)可能监听在随机端口上。生产环境建议在
/etc/sysconfig/nfs或/etc/nfs.conf中固定这些端口,然后在防火墙中精确放行。
4.4 第四步:用tcpdump抓包确认数据包走向
当以上步骤都无法定位时,抓包是最可靠的手段。在客户端和目标主机同时抓包,对比数据包的发送和接收情况:
# 在客户端抓取目标IP的111端口流量 tcpdump -i any -nn host <目标IP> and port 111 -w client.pcap # 在目标主机抓取来自客户端的流量 tcpdump -i any -nn host <客户端IP> and port 111 -w server.pcap分析要点:如果客户端有发送但没有收到任何回复,说明数据包在中间被丢弃了;如果客户端收到了ICMP unreachable消息,抓包中会显示;如果目标主机根本没收到包,问题在中间网络;如果目标主机收到了但没有回复,问题在目标主机的防火墙或port mapper服务状态。
4.5 第五步:验证port mapper服务本身状态
如果网络层确认没问题,接下来确认目标主机的port mapper是否正常运行:
# 在目标主机上检查rpcbind服务状态 systemctl status rpcbind # 确认111端口监听状态 ss -tlnp | grep 111 ss -ulnp | grep 111 # 本地查询port mapper rpcinfo -p localhost如果rpcbind没有运行,或者111端口没有监听,那客户端自然无法完成port mapper查询。但这种情况通常报的是Connection refused而不是No route to host,所以如果确认是errno 113,网络层问题的可能性更大。
5. 高频场景复盘:那些年我踩过的errno 113的坑
5.1 场景一:多网卡服务器路由优先级导致的“假连通”
某次在实验室环境部署一套分布式存储,三台服务器各有两张网卡,一张接管理网,一张接存储网。客户端在管理网,存储服务在存储网。ping管理网IP通,rpcinfo却报No route to host。
排查后发现:目标主机的默认路由指向管理网网关,但port mapper的回复包根据路由表选择了管理网网卡作为出口。而客户端实际上是通过存储网发起请求的,回复包从管理网出来后就找不到回客户端存储网IP的路径了。
解决办法是在目标主机上添加策略路由,让来自存储网段的请求从存储网网卡回复:
# 添加路由表 echo "200 storage" >> /etc/iproute2/rt_tables # 添加策略路由规则 ip rule add from <存储网IP> table storage ip route add default via <存储网网关> table storage这个坑的隐蔽性在于,ping测试的是管理网连通性,而实际RPC请求走的是存储网,两条路径的行为不一致。
5.2 场景二:防火墙REJECT规则伪装成“无路由”
某次在云主机上配置NFS,安全组只放行了2049端口,没有放行111端口。客户端报No route to host,第一反应是路由问题,查了半天路由表都正常。后来用tcpdump抓包发现,客户端发出的SYN包收到了ICMP port unreachable消息,但被系统转换成了EHOSTUNREACH。
云平台的安全组通常采用“静默丢弃”策略,但某些配置下会返回ICMP不可达。这种情况下,报错信息会误导排查方向。解决办法很简单:在安全组中放行TCP/UDP 111端口,以及RPC动态端口范围。
5.3 场景三:容器环境中的网络命名空间隔离
在容器中运行RPC客户端,连接宿主机或其他容器中的RPC服务时,如果容器使用了none网络模式或者自定义网络配置不当,也会出现No route to host。容器的网络命名空间与宿主机隔离,路由表和iptables规则都是独立的。
排查时需要在容器内部执行ip route和nc测试,而不是在宿主机上测试。如果容器使用的是bridge模式,确认容器有正确的默认网关,且宿主机的iptables没有拦截容器流量。
5.4 场景四:ARP缓存污染导致的间歇性失败
这个问题比较少见但确实存在。局域网中如果有两台设备配置了相同的IP(IP冲突),ARP缓存可能会在正确的MAC和错误的MAC之间来回切换。当ARP缓存指向错误的MAC时,数据包发到了错误的设备上,自然得不到响应。
表现是RPC调用时好时坏,arp -n查看时MAC地址会变化。解决办法是清除ARP缓存ip neigh flush all,然后找到IP冲突的设备并修正配置。
5.5 场景五:IPv6与IPv4双栈环境下的地址选择问题
在双栈环境中,主机名可能同时解析到IPv4和IPv6地址。如果clnt_create选择了IPv6地址,但IPv6路由不可达,就会报No route to host。而ping可能默认走IPv4,显示连通正常。
排查时用getent hosts <主机名>查看解析结果,确认程序实际使用的是哪个地址族。必要时在/etc/hosts中强制指定IPv4地址,或者调整gai.conf的优先级。
5.6 常见问题速查表
| 现象 | 可能原因 | 快速验证方法 | 解决方向 |
|---|---|---|---|
| ping通但rpcinfo报113 | 防火墙拦截111端口 | nc -zv <IP> 111 | 放行TCP/UDP 111 |
| 同网段报113 | ARP解析失败 | arping <IP> | 检查ARP缓存和VLAN |
| 跨网段报113 | 路由表缺失 | ip route get <IP> | 添加正确路由 |
| 多网卡环境报113 | 回程路由不对称 | 目标机ip route get <客户端IP> | 配置策略路由 |
| 容器内报113 | 网络命名空间隔离 | 容器内ip route | 检查容器网络配置 |
| 时好时坏报113 | ARP缓存污染或IP冲突 | arp -n观察MAC变化 | 清除ARP缓存,排查冲突 |
| 双栈环境报113 | IPv6路由不可达 | getent hosts <主机名> | 强制使用IPv4 |
6. 从修复到预防:让RPC连接稳定下来的配置建议
6.1 固定RPC服务端口范围
RPC服务的动态端口是很多问题的根源。防火墙管理员不知道要放行哪些端口,客户端也不知道服务实际监听在哪里。在生产环境中,我强烈建议固定RPC服务的端口范围。
对于NFS相关的RPC服务,可以在/etc/nfs.conf(新版)或/etc/sysconfig/nfs(旧版)中配置:
# /etc/nfs.conf 示例 [mountd] port=20048 [statd] port=32765 outgoing-port=32766 [lockd] port=32767 udp-port=32767配置完成后重启相关服务,然后用rpcinfo -p确认端口已经固定。这样防火墙只需要放行111、2049以及这几个固定端口即可,大大降低排查复杂度。
6.2 在防火墙中精确放行RPC相关端口
以firewalld为例,创建一个专门的服务定义:
# 创建自定义服务 firewall-cmd --permanent --new-service=nfs-rpc firewall-cmd --permanent --service=nfs-rpc --add-port=111/tcp firewall-cmd --permanent --service=nfs-rpc --add-port=111/udp firewall-cmd --permanent --service=nfs-rpc --add-port=2049/tcp firewall-cmd --permanent --service=nfs-rpc --add-port=2049/udp firewall-cmd --permanent --service=nfs-rpc --add-port=20048/tcp firewall-cmd --permanent --service=nfs-rpc --add-port=20048/udp firewall-cmd --permanent --service=nfs-rpc --add-port=32765-32767/tcp firewall-cmd --permanent --service=nfs-rpc --add-port=32765-32767/udp # 应用服务 firewall-cmd --permanent --add-service=nfs-rpc firewall-cmd --reload提示:如果使用
iptables,规则顺序很重要。确保放行规则在拒绝规则之前,并且注意ESTABLISHED,RELATED状态的连接跟踪规则要存在。
6.3 用rpcinfo做日常健康检查
与其等报错了再排查,不如把rpcinfo纳入日常监控。一个简单的检查脚本:
#!/bin/bash TARGET="<目标IP>" if rpcinfo -t "$TARGET" 100003 3 >/dev/null 2>&1; then echo "OK: NFS RPC service reachable" else echo "FAIL: Cannot reach NFS RPC service on $TARGET" # 进一步诊断 echo "--- Route info ---" ip route get "$TARGET" echo "--- Port 111 test ---" nc -zv -w 3 "$TARGET" 111 fi这个脚本可以放在cron中定时执行,也可以在部署脚本中作为前置检查。关键是它能在问题影响业务之前就发出告警。
6.4 多网卡环境下的路由配置规范
对于多网卡服务器,建议在/etc/iproute2/rt_tables中为每个网段定义独立的路由表,并配置策略路由规则。基本原则是:请求从哪个网卡进来,回复就从哪个网卡出去。
# 假设网卡eth1对应10.0.0.0/24网段 ip rule add from 10.0.0.100 table eth1_table ip route add 10.0.0.0/24 dev eth1 src 10.0.0.100 table eth1_table ip route add default via 10.0.0.1 table eth1_table配置完成后用ip route get 10.0.0.x from 10.0.0.100验证回程路径是否正确。
6.5 容器与虚拟化环境的网络检查清单
在容器或虚拟机中部署RPC客户端时,按以下清单逐项确认:
- 容器是否有独立的网络命名空间,路由表是否正确
- 容器到目标主机的111端口是否可达(在容器内执行
nc测试) - 宿主机的
iptables或nftables是否对容器流量做了额外限制 - 如果使用overlay网络,隧道是否正常,MTU是否匹配
- DNS解析在容器内是否正常,是否解析到了预期的IP地址
这些检查项看起来琐碎,但每一条都对应着我实际遇到过的故障场景。尤其是MTU不匹配的问题,在小包测试时正常,一旦RPC传输较大数据就失败,表现可能不是errno 113而是超时,但排查思路是相通的。
7. 几个容易被忽略的细节和我的个人经验
7.1 errno 113不一定意味着“完全不通”
有时候No route to host是间歇性的,尤其是在无线网络或负载均衡环境下。数据包可能通过某条路径时成功,通过另一条路径时失败。这种情况下,ping和nc的单次测试可能碰巧成功,让你误以为问题解决了。
我的做法是:用ping -c 100或者nc循环测试多次,观察失败率。如果失败率不是零,就说明存在路径或策略的不稳定因素,需要继续深挖。
7.2 注意区分TCP和UDP的port mapper查询
clnt_create默认可能使用UDP协议进行port mapper查询,而rpcinfo -p默认也使用UDP。但有些防火墙只放行了TCP 111而没有放行UDP 111,导致rpcinfo -t(TCP)成功但程序默认的UDP查询失败。
排查时两个协议都要测:
rpcinfo -t <目标IP> 100003 3 # TCP方式 rpcinfo -u <目标IP> 100003 3 # UDP方式如果TCP通而UDP不通,检查防火墙的UDP规则。反过来也一样。
7.3 主机名解析顺序可能影响结果
clnt_create的第一个参数是主机名,如果主机名解析到了错误的IP(比如/etc/hosts中有一条过期的记录),就会连接到错误的地址。排查时用getent hosts <主机名>确认解析结果,必要时直接在程序中使用IP地址绕过DNS。
7.4 系统日志中往往有更多线索
/var/log/messages或journalctl -xe中可能记录了内核层面的网络错误,比如martian source、ICMP host unreachable等。这些日志能帮你确认数据包是在本机被拦截的,还是在中间网络被丢弃的。
# 查看内核网络相关日志 dmesg | grep -i "route\|unreachable\|martian" journalctl -k --since "10 minutes ago" | grep -i "network\|route"7.5 最后再分享一个快速判断的小技巧
当你拿到clnt_create: RPC: Port mapper failure - Unable to receive: errno 113这个报错时,按以下顺序快速判断:
ip route get <目标IP>——如果返回unreachable,直接修路由,结束。arping <目标IP>(同网段)——如果无响应,查ARP和二层网络。nc -zv <目标IP> 111——如果失败但路由正常,查防火墙。rpcinfo -p <目标IP>——如果TCP通UDP不通,查UDP防火墙规则。- 在目标主机上
rpcinfo -p localhost——如果本地都查不到,查rpcbind服务状态。
这五步走下来,九成以上的errno 113问题都能定位到具体原因。剩下的疑难杂症,就需要抓包和策略路由分析了。我在实际运维中最大的体会是:不要被ping的结果迷惑,也不要一上来就重启服务,先把数据包的路径搞清楚,问题往往比想象中简单。