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@redhat.com Signed-off-by: Coiby Xu coxu@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