WSL2 Mirrored 模式下 Synopsys License 启动失败:localhost 路由异常修复记录

前言

之前我在 WSL2 Ubuntu 中运行 Synopsys 工具,并通过 FlexNet License Server 提供 License。

在 WSL2 默认 NAT 网络模式下,Synopsys License 可以正常启动,但 WSL 无法方便地使用 Windows 主机上的代理。将 WSL 切换到mirrored网络模式后,代理恢复正常,但 Synopsys License Server 无法启动,Verdi、VCS 等工具也无法获取 License。

最终定位发现,这并不是 License 文件、HostID 或 DNS 配置错误,而是 WSL Mirrored 模式下的 localhost 策略路由异常。

本文记录问题原因和最终解决方法。


一、问题现象

License 文件中的服务器配置如下:

SERVER LAPTOP-CEUP9426 00155dec9c9b 27000 DAEMON snpslmd /home/synopsys/scl/2018.06/linux64/bin/snpslmd

启动 License 服务后,lmgrd能够正常运行并监听27000端口:

ps-ef|grep-E'[l]mgrd|[s]npslmd'

只能看到:

/home/synopsys/scl/2018.06/linux64/bin/lmgrd ...

但看不到snpslmd进程。

查看 systemd 日志:

journalctl-usynopsys-license.service-b-n30--no-pager

可以看到:

snpslmd exited with status 76 (Not able to resolve local host) This error probably results from: 1. DNS server not able to resolve localhost. 2. /etc/hosts file does not contain an entry for localhost.

从日志看,似乎是localhost或 DNS 配置存在问题。

但实际检查发现,主机名和 localhost 都可以正常解析:

getent ahostsv4 localhost getent ahostsv4 LAPTOP-CEUP9426

输出类似:

127.0.0.1 STREAM localhost 127.0.1.1 STREAM LAPTOP-CEUP9426

License 对应的 HostID 也能被正确识别:

/home/synopsys/scl/2018.06/linux64/bin/lmhostid-ether

输出中包含:

00155dec9c9b

因此问题并不是 HostID 或/etc/hosts配置错误。


二、真正原因

为了确认snpslmd退出前究竟做了什么,使用strace跟踪 License Server:

strace-ff-s256\-o/tmp/synopsys.trace\-etrace=network,ioctl,file,process\/home/synopsys/scl/2018.06/linux64/bin/lmgrd\-z\-c/home/synopsys/scl/2018.06/admin/license/Synopsys.dat

在跟踪结果中发现了关键错误:

connect( 53, { sa_family=AF_INET, sin_port=htons(45116), sin_addr=inet_addr("127.0.0.1") }, 16 ) = -1 EHOSTUNREACH (No route to host)

snpslmd启动时会进行一次本地网络自检:

启动一个本地 TCP 监听端口 ↓ 连接 127.0.0.1 上的该端口 ↓ 检查本机回环网络是否正常

但在当前 WSL Mirrored 模式下,连接127.0.0.1返回了:

No route to host

为了进一步确认,使用 Python 创建一个只监听127.0.0.1的服务,再从本机连接:

importsocket server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)server.bind(("127.0.0.1",0))server.listen(1)port=server.getsockname()[1]client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)client.connect(("127.0.0.1",port))

结果同样失败:

OSError: [Errno 113] No route to host

这说明问题并不是 Synopsys License 特有问题,而是当前 WSL 中最基本的 IPv4 localhost 通信已经异常。


三、WSL Mirrored 的策略路由异常

查看访问127.0.0.1时使用的路由:

iproute get127.0.0.1

异常情况下输出为:

127.0.0.1 via 169.254.73.152 dev loopback0 table 127

正常的 Linux localhost 流量应该走:

local 127.0.0.1 dev lo table local

继续查看策略路由:

iprule show

可以看到 Mirrored 模式生成了下面的规则:

1: from all ipproto tcp lookup 127 1: from all ipproto udp lookup 127 2: from all lookup local

查看 table 127:

iproute show table127

输出:

127.0.0.1 via 169.254.73.152 dev loopback0

而正常的 local 路由表中实际上存在:

iproute show tablelocal
local 127.0.0.1 dev lo

问题就在于策略路由的优先级。

访问127.0.0.1时,系统先匹配:

lookup 127

因此流量被送往:

loopback0

而不是标准的 Linux 回环接口:

lo

最终导致:

127.0.0.1 ↓ table 127 ↓ loopback0 ↓ No route to host

snpslmd检测到本地自连接失败后退出,并给出了比较具有误导性的错误:

Not able to resolve local host

所以真正的问题不是 DNS,而是:

WSL Mirrored 模式下,访问127.0.0.1的策略路由优先进入了 table 127,导致 localhost 流量没有走标准的 lo 回环接口。


四、临时修复方法

添加三条优先级更高的规则,让127.0.0.0/8优先查询标准的 local 路由表:

sudoipruleaddpref0to127.0.0.0/8 lookuplocalsudoipruleaddpref0\to127.0.0.0/8\ipproto tcp\lookuplocalsudoipruleaddpref0\to127.0.0.0/8\ipproto udp\lookuplocalsudoiproute flush cache

重新检查路由:

iproute get127.0.0.1

此时输出恢复正常:

local 127.0.0.1 dev lo table local src 127.0.0.1

再次启动 Synopsys License:

sudosystemctl start synopsys-license.service

查看进程:

ps-ef|grep-E'[l]mgrd|[s]npslmd'

可以同时看到:

lmgrd snpslmd

检查 License 状态:

/home/synopsys/scl/2018.06/linux64/bin/lmstat\-a\-c27000@localhost

输出:

license server UP (MASTER) Vendor daemon status: snpslmd: UP

此时 Verdi、VCS 等 Synopsys 工具已经可以正常打开。


五、创建自动修复脚本

上面的ip rule在执行wsl --shutdown后会消失,因此需要配置开机自动恢复。

创建脚本:

sudonvim /usr/local/sbin/fix-wsl-mirrored-loopback.sh

写入:

#!/usr/bin/env bashset-euopipefailadd_rule_if_missing(){localrule="$1"if!iprule show|grep-Fq"$rule";thenipruleaddpref0$rulefi}# 让 127.0.0.0/8 优先查询 Linux 标准 local 路由表。add_rule_if_missing"to 127.0.0.0/8 lookup local"add_rule_if_missing\"to 127.0.0.0/8 ipproto tcp lookup local"add_rule_if_missing\"to 127.0.0.0/8 ipproto udp lookup local"iproute flush cache# 将最终路由输出到 systemd 日志中,便于检查。iproute get127.0.0.1

增加执行权限:

sudochmod755\/usr/local/sbin/fix-wsl-mirrored-loopback.sh

手动测试:

sudo/usr/local/sbin/fix-wsl-mirrored-loopback.sh

因为脚本会先检查规则是否存在,所以可以重复执行,不会不断添加重复规则。

检查规则:

iprule show|grep'127.0.0.0/8'

输出:

0: from all to 127.0.0.0/8 lookup local 0: from all to 127.0.0.0/8 ipproto tcp lookup local 0: from all to 127.0.0.0/8 ipproto udp lookup local

六、创建 systemd 服务

创建服务文件:

sudonvim\/etc/systemd/system/wsl-mirrored-loopback-fix.service

内容如下:

[Unit] Description=Fix WSL Mirrored localhost routing Wants=network-online.target After=network-online.target Before=synopsys-license.service [Service] Type=oneshot ExecStart=/usr/local/sbin/fix-wsl-mirrored-loopback.sh RemainAfterExit=yes [Install] WantedBy=multi-user.target

重新加载并启用服务:

sudosystemctl daemon-reloadsudosystemctlenable--now\wsl-mirrored-loopback-fix.service

检查状态:

systemctl status\wsl-mirrored-loopback-fix.service\--no-pager-l

正常情况下显示:

Active: active (exited)

这是正常现象,因为该服务类型是:

Type=oneshot

脚本执行完成后进程会退出,但 systemd 会记录服务已经成功完成。


七、让 License 服务等待路由修复完成

为了保证每次启动 License 前 localhost 路由都已修复,可以为 License 服务增加 systemd 依赖。

创建 drop-in 目录:

sudomkdir-p\/etc/systemd/system/synopsys-license.service.d

创建依赖配置:

sudonvim\/etc/systemd/system/synopsys-license.service.d/10-loopback-fix.conf

写入:

[Unit] Requires=wsl-mirrored-loopback-fix.service After=wsl-mirrored-loopback-fix.service

这样 systemd 会按照下面的顺序执行:

WSL Mirrored 网络启动 ↓ wsl-mirrored-loopback-fix.service ↓ 修复 localhost 路由 ↓ synopsys-license.service ↓ lmgrd 和 snpslmd

重新加载:

sudosystemctl daemon-reload

八、增加 License 重启间隔

在测试过程中发现,如果连续多次执行:

sudosystemctl restart synopsys-license.service

旧的lmgrd可能还没有完全释放27000端口,systemd 就启动了新实例,从而出现:

Failed to open the TCP port number in the license.

可以为 License 服务增加重启延迟。

创建:

sudonvim\/etc/systemd/system/synopsys-license.service.d/20-restart-delay.conf

内容:

[Service] Restart=on-failure RestartSec=3

重新加载:

sudosystemctl daemon-reload

检查配置:

systemctl show synopsys-license.service\-pRestart\-pRestartUSec

预期输出:

Restart=on-failure RestartUSec=3s

如果需要手动重启 License,建议使用:

sudosystemctl stop synopsys-license.servicesleep2sudosystemctl start synopsys-license.service

相比连续执行restart,这种方式可以给旧进程和端口留出释放时间。


九、冷启动验证

完成配置后,在 Windows PowerShell 中执行:

wsl--shutdown

重新打开 Ubuntu。

检查路由修复服务:

systemctl status\wsl-mirrored-loopback-fix.service\--no-pager-l

输出:

Active: active (exited)

检查 localhost 路由:

iproute get127.0.0.1

输出:

local 127.0.0.1 dev lo table local src 127.0.0.1

检查自动生成的规则:

iprule show|grep'127.0.0.0/8'

输出:

0: from all to 127.0.0.0/8 lookup local 0: from all to 127.0.0.0/8 ipproto tcp lookup local 0: from all to 127.0.0.0/8 ipproto udp lookup local

检查 License 进程:

ps-ef|grep-E'[l]mgrd|[s]npslmd'

能够同时看到:

lmgrd snpslmd

最后检查 License 状态:

/home/synopsys/scl/2018.06/linux64/bin/lmstat\-a\-c27000@localhost

输出:

license server UP (MASTER) snpslmd: UP

说明冷启动自动修复和 License 自动启动都已经成功。


十、总结

本次问题表面上的报错是:

Not able to resolve local host

但实际原因并不是 DNS、/etc/hosts、License 文件或 HostID 配置错误。

真正原因是:

WSL2 Mirrored 模式生成的策略路由优先将127.0.0.1发送到 table 127 和 loopback0,导致 Linux 本机 localhost TCP 自连接返回No route to host

而 Synopsys 的snpslmd在启动过程中需要通过127.0.0.1进行本地自连接检查,因此检查失败后直接退出。

最终解决方式是:

为 127.0.0.0/8 添加更高优先级的 local 路由规则 ↓ 通过 systemd 在 WSL 启动后自动执行修复脚本 ↓ 让 Synopsys License 服务依赖路由修复服务

最终实现了以下功能同时正常使用:

  • WSL2 Mirrored 网络模式;
  • Windows 代理自动继承;
  • Synopsys FlexNet License;
  • Verdi、VCS 等 Synopsys EDA 工具。