|
若非展示完整代码,以下案例各语句,仍然是只体现我们尝试、排错思维的精简格式。
我只测试了红帽 9+ 的 NetworkManager 格式网络配置文件的操作,红帽 8 及之前 ip up down 格式文件的多 IPv6 写入操作不再考虑支持。
首先我们需要搞清楚,NetworkManager 配置有效的,多条 IPv6 的标准格式应该是什么:
[ol][ipv6]
addr-gen-mode=eui64
address1=2606:a8c0:3:6f::b/64,fd2e::
address2=2606:a8c0:3:6f::c/64,fd2e::
address3=2606:a8c0:3:6f::/64,fd2e::
dns=2606:4700:4700::1001;2001:4860:4860::8844;
method=manual[/ol]复制代码
只有以标准格式为目标,尝试去修改并达成,我们才能在 Kickstart post end 阶段,探索出适合的写入策略。
可以看到,NetworkManager 的 IPv6 配置特征如下:
多个 IPv6 地址,用“address序号”隔开,每个条目对应着 IPv6 地址/掩码后缀“英文逗号,”网关;多个 IPv6 dns 用英文分号隔开,最后一位必须要跟上一个英文分号;method 对应的 manual 和 auto ,分别对应着是以静态还是以动态配置网络。
于是,我尝试的写入过程如下:
“network”部分,仅配置 IPv4 网络,指定“--noipv6”,不配置 IPv6,后续阶段刷入多 IPv6 配置。
[ol]network IPv4 静态或动态配置 --noipv6[/ol]复制代码
系统安装完成后,观察到系统网络配置文件 /etc/NetworkManager/system-connections/eth0.nmconnection 中,IPv6 部分详情如下:
[ol][ipv6]
addr-gen-mode=eui64
method=disabled[/ol]复制代码
method 为 disabled ,显然 IPv6 的配置被禁用了,这个值不会使系统中的 IPv6 模块被彻底禁用,与在内核中添加“ipv6.disable=1”参数,禁止内核加载 IPv6 的作用不同。如果把 method 改为 auto 或 manual,并给出正确的 IPv6 配置,IPv6 网络仍能正常工作。
“addr-gen-mode=eui64”部分是 [ipv6] 项目下特有的,[ipv4] 部分无此条目,所以有一套可行的思路如下:
在“addr-gen-mode=eui64”条目下方,追加多行 IPv6 配置;把“method=disabled”改为“method=manual”。
由于系统安装时是优先以 IPv4 配置的,所以 IPv4 部分要么是“method=auto”,要么是“method=manual”,以“method=disabled”为关键字替换,不会干扰到 IPv4 的正常配置。于是,post end 部分的代码如下:
Kickstart 中指定的系统安装完成,重启前的后续阶段写入条目:
[ol]%post
sed -ri 's/method=disabled/method=manual/g' 网络配置文件
sed -i '/addr-gen-mode=eui64/a\address1=第一条 IPv6/掩码后缀,网关\naddress2=第二条 IPv6/掩码后缀,网关\ndns=第一个 IPv6 DNS;第二个 IPv6 DNS;' 网络配置文件
%end[/ol]复制代码
安装过程看起来很顺利,结果重启后连用本地宽带 IPv4 访问 ssh 也无法连接了,真的很令人扫兴,只能先进 VNC 里,看看网络配置如何:
[ol][ipv6]
addr-gen-mode=eui64
address1=2603:c020:a:6aa4:a787:6d4:3e72:4902/64,fe80::200:17ff:fe80:551d
method=disabled
method=ignore[/ol]复制代码
好家伙,[ipv6] 下额外添加了一条“method=ignore”,导致 IPv4 IPv6 双网挂掉的罪魁祸首或许就是它吧。因为我们在 Kickstart 阶段指定的是不配置 IPv6 网络,然后在安装完成阶段,又写入了一套 IPv6 静态配置,系统启动时,会发现两者产生冲突,于是将 IPv6 部分的配置方法标记成了“ignore”,然后使 IPv4 和 IPv6 所有部分的网络都不工作。
除非有一种手段,可以使 anaconda 在配置完系统后重启后,在新登录系统时,把“method=ignore”删除,这样才能使系统中所有网络都能工作,但仅修改网络配置文件是不行的,还要涉及给系统登陆时设置一个脚本,消除“method=ignore”,但此时系统网络还是不通的,还要让系统再重启一次。
这个路线显然是错误的。在“network”语句中,先配置一个 --ipv6 条目,然后把其余 IPv6 条目在后续阶段写进去。
这个主意也不咋地,代码也不放了,因为这样做又大大加深了复杂度,虽然我们通过用数组存储所有“IPv6 地址/掩码后缀”,将下标 0 (数组中的第一个元素)设置为在“network”中配置,然后把下标 1 及最后的元素在安装后续添加,但我们不能保证,被添加进去的那条 IPv6 是不依赖于母段就能独立运行的,比如:
添加的正好是 2606:a8c0:3:6f::/128 ,anaconda 环境中 IPv6 就能工作;如果添加的是 2606:a8c0:3:6f::11/64 ,由于 2606:a8c0:3:6f::/128 还未到后续阶段被写入,anaconda 环境中 IPv6 不能工作;经过实测发现,CentOS 9 stream 的 anaconda 环境中,如果同时接受了 IPv4 和 IPv6 参数,会对双网进行网络检查,并优先使用 IPv6 连接镜像源;如果添加的是 2606:a8c0:3:6f::11/64 ,系统就会卡在网络检查环节很久,并导致以 IPv6 连接镜像源失败。
继续死磕,没什么大不了的,如果总是害怕失败,我不会走到今天。network 语句给 IPv4 静态配置,不标记任何配置 IPv6 的参数,也不关闭 IPv6 配置,后续阶段刷入所有 IPv6 配置。
令人振奋的是,这次我们终于找对路了!
Kickstart 中,network 语句如果只配置 IPv4 部分,不输入任何有关配置 IPv6 的参数,重装后的系统中,NetworkManager 针对 IPv6 部分仍然会给一个默认的动态配置,内容如下:
[ol][ipv6]
addr-gen-mode=eui64
method=auto[/ol]复制代码
由于该节开始,我就强调了“只配置 IPv4 部分”,隐含的意义就是无论原机器的 IPv4 部分是 dhcp 还是 static ,在新安装的系统中,我们都将 IPv4 部分按静态配置,那么 NetworkManager 中,一定会存在以下条目,且来仅来自 IPv4 部分:
[ol]method=manual[/ol]复制代码
此时 IPv6 部分仍然为“method=auto”,而 IPv4 部分统一变成了“method=manual”,有这两条区分,就可以确保后续阶段刷入 IPv6,并改变其配置方法的时候,这种改动对 IPv4 部分不会造成任何影响。因为我们需要设置的替换起始关键词是“method=auto”,而此时 IPv4 部分永远是“method=manual”。
为了方便大家理解,我先以程序执行流程的顺序来讲解,首先是脚本内处理 “双栈机,且有多个 IPv6” ,生成 Kickstart 前,需要写入哪种“network”语句的情况:
[ol][[ "$i6AddrNum" -ge "2" ]] && NetConfigManually="network --device=$interface --bootproto=static --ip=$IPv4 --netmask=$actualIp4Subnet --gateway=$GATE --nameserver=$ipDNS --hostname=$(hostname) --onboot=on"[/ol]复制代码
"$i6AddrNum" -ge "2" 很好理解,发现本机拥有大于等于两个 IPv6 再进行的操作,这个判断式隶属于母条件式“elif [[ "$IPStackType" == "BiStack" ]]; then”下,即仅在双栈机,多 IPv6 环境下再进行处理,不用担心其会影响到仅 IPv6 栈服务器。
“NetConfigManually=” 对应的变量也很好懂,里面仅包含了令 anaconda 配置 IPv4 ,不包含任何配置 IPv6 的语句,这样做可以有效避免以上所述中,anaconda 由于接受了一个非母 IPv6 段,IPv6 并不能正常工作,导致连接源失败的情况。
以本实验机型为例,最终脚本为生成 Kickstart “network”语句的完整内容如下:
[ol]network --device=eth0 --bootproto=static --ip=104.36.84.237 --netmask=255.255.255.255 --gateway=104.36.84.1 --nameserver=1.0.0.1,8.8.4.4 --hostname=237 --onboot=on[/ol]复制代码
下面真正的骚操作才正式开始。
还记得刚才那个“writeMultipleIpv6Addresses”函数,“if [[ "$linux_relese" == 'debian' ]] || [[ "$linux_relese" == 'kali' ]]; then”是给 Debian 和 Kali 配置的,elif [[ "$linux_relese" == 'centos' ]] || [[ "$linux_relese" == 'rockylinux' ]] || [[ "$linux_relese" == 'almalinux' ]] || [[ "$linux_relese" == 'fedora' ]]; then 就是给红帽全系配置的,条件式内运行的代码如下:
[ol]for (( tmpI6Index=0; tmpI6Index复制代码
红帽系 Kickstart 由于不需要 Debian 系 preseed 中 "in-target" 那样的设定,所以接受的参数中不需要带 "$2" ,调用需要留空,后面会讲。
"$1" 参数对应的值为“$i6AddrNum”,即机器中所有 IPv6 数量,这个参数用于判断机器中有 2 个以上 IPv6 时该怎么做,不影响以上子判断式中的代码运行。 |
|