Recently, dracut-network drops depedency on dhcp-client which requires
ipcalc. Thus the dependency chain
"kexec-tools -> dracut-network -> dhcp-client -> ipcalc"
is broken. When NIC is configured to a static IP, kexec-tools depended
on "ipcalc -m" to get netmask. This commit implements the shell
equivalent of "ipcalc -m".
The following test code shows cal_netmask_by_prefix is consistent with
"ipcalc -m",
#!/bin/bash
. dracut-module-setup.sh
for i in {0..128}; do
mask_expected=$(ipcalc -m fe::/$i| cut -d"=" -f2)
mask_actual=$(cal_netmask_by_prefix $i true)
if [[ "$mask_expected" != "$mask_actual" ]]; then
echo $i, "expected=", $mask_expected, "acutal=",
$mask_actual
fi
done
for i in {0..32}; do
mask_expected=$(ipcalc -m 8.8.8.8/$i| cut -d"=" -f2)
mask_actual=$(cal_netmask_by_prefix $i false)
if [[ "$mask_expected" != "$mask_actual" ]]; then
echo $i, "expected=", $mask_expected, "acutal=",
$mask_actual
fi
done
Reported-by: Jie Li <jieli(a)redhat.com>
Signed-off-by: Coiby Xu <coxu(a)redhat.com>
---
dracut-module-setup.sh | 107 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 105 insertions(+), 2 deletions(-)
diff --git a/dracut-module-setup.sh b/dracut-module-setup.sh
index 21143b4..bf6acf9 100755
--- a/dracut-module-setup.sh
+++ b/dracut-module-setup.sh
@@ -121,17 +121,119 @@ kdump_setup_dns() {
done < "/etc/resolv.conf"
}
+# $1: repeat times
+# $2: string to be repeated
+# $3: separator
+repeatedly_join_str() {
+ local _count="$1"
+ local _str="$2"
+ local _separator="$3"
+ local i _res
+
+ if [[ "$_count" -le 0 ]]; then
+ echo -n ""
+ return
+ fi
+
+ i=0
+ _res="$_str"
+ ((_count--))
+
+ while [[ "$i" -lt "$_count" ]]; do
+ ((i++))
+ _res="${_res}${_separator}${_str}"
+ done
+ echo -n "$_res"
+}
+
+# $1: prefix
+# $2: ipv6 or not
+# Given a prefix, calculate the netmask (equivalent of "ipcalc -m")
+# by concatenating three parts,
+# 1) the groups with all bits set 1
+# 2) a group with partial bits set to 0
+# 3) the groups with all bits set to 0
+#
+cal_netmask_by_prefix() {
+ local _prefix="$1"
+ local _ipv6="$2"
+ local _bits_per_octet=8
+ local _count _res _octets_per_group _octets_total _seperator _total_groups
+ local _max_group_value _max_group_value_repr _bits_per_group _tmp _zero_bits
+
+ if "$_ipv6"; then
+ [ "$_prefix" -gt 128 ] || [ "$_prefix" -lt 0 ] && die
"Wrong IPv6 prefix $_prefix"
+ _octets_per_group=2
+ _octets_total=16
+ _seperator=":"
+ else
+ [ "$_prefix" -gt 32 ] || [ "$_prefix" -lt 0 ] && die
"Wrong IPv4 prefix $_prefix"
+ _octets_per_group=1
+ _octets_total=4
+ _seperator="."
+ fi
+
+ _total_groups=$((_octets_total/_octets_per_group))
+ _bits_per_group=$((_octets_per_group * _bits_per_octet))
+ _max_group_value=$(((1 << _bits_per_group) - 1))
+
+ if "$_ipv6"; then
+ _max_group_value_repr=$(printf "%x" $_max_group_value)
+ else
+ _max_group_value_repr="$_max_group_value"
+ fi
+
+ _count=$((_prefix/_octets_per_group/_bits_per_octet))
+ _first_part=$(repeatedly_join_str "$_count"
"$_max_group_value_repr" "$_seperator")
+ _res="$_first_part"
+
+ _tmp=$((_octets_total*_bits_per_octet-_prefix))
+ _zero_bits=$(expr $_tmp % $_bits_per_group)
+ if [[ "$_zero_bits" -ne 0 ]]; then
+ _second_part=$((_max_group_value >> _zero_bits << _zero_bits))
+ if "$_ipv6"; then
+ _second_part=$(printf "%x" $_second_part)
+ fi
+ ((_count++))
+ if [[ -z "$_first_part" ]]; then
+ _res="$_second_part"
+ else
+ _res="${_first_part}${_seperator}${_second_part}"
+ fi
+ fi
+
+ _count=$((_total_groups-_count))
+ if [[ "$_count" -eq 0 ]]; then
+ echo -n "$_res"
+ return
+ fi
+
+ if "$_ipv6" && [[ "$_count" -gt 1 ]] ; then
+ # use condensed notion for IPv6
+ _third_part=":"
+ else
+ _third_part=$(repeatedly_join_str "$_count" "0"
"$_seperator")
+ fi
+
+ if [[ -z "$_res" ]] && ! "$_ipv6" ; then
+ echo -n "${_third_part}"
+ else
+ echo -n "${_res}${_seperator}${_third_part}"
+ fi
+}
#$1: netdev name
#$2: srcaddr
#if it use static ip echo it, or echo null
kdump_static_ip() {
local _netdev="$1" _srcaddr="$2" _ipv6_flag
- local _netmask _gateway _ipaddr _target _nexthop
+ local _netmask _gateway _ipaddr _target _nexthop _prefix
+ local _ipv6=false
_ipaddr=$(ip addr show dev $_netdev permanent | awk "/ $_srcaddr\/.* /{print
\$2}")
if is_ipv6_address $_srcaddr; then
_ipv6_flag="-6"
+ _ipv6=true
fi
if [ -n "$_ipaddr" ]; then
@@ -144,7 +246,8 @@ kdump_static_ip() {
_srcaddr="[$_srcaddr]"
_gateway="[$_gateway]"
else
- _netmask=$(ipcalc -m $_ipaddr | cut -d'=' -f2)
+ _prefix=$(cut -d'/' -f2 <<< "$_ipaddr")
+ _netmask=$(cal_netmask_by_prefix "$_prefix" "$_ipv6")
fi
echo -n "${_srcaddr}::${_gateway}:${_netmask}::"
fi
--
2.31.0