From 962153d817faba8fe1e74b4848f405e89ea7c991 Mon Sep 17 00:00:00 2001 From: Vlastimil Holer Date: Fri, 10 Sep 2021 13:28:30 +0200 Subject: [PATCH] F #227, #86: Various fixes --- pkg/postinstall | 35 ++-- ...#linux.one => one-context.conf##linux.one} | 0 .../pre-up.d/netplan-ipv6-privacy-off##deb | 44 +++++ ...ontext.conf##bsd => one-context.conf##bsd} | 0 src/etc/one-context.d/loc-10-network | 40 ++++- src/etc/one-context.d/loc-10-network-pci##one | 1 - .../one-context.d/loc-10-network.d/functions | 142 ++++++++++++++-- .../one-context.d/loc-10-network.d/netcfg-bsd | 49 ++++-- .../loc-10-network.d/netcfg-interfaces | 99 +++++++++-- .../loc-10-network.d/netcfg-netplan | 119 +++++++++++-- .../loc-10-network.d/netcfg-networkd | 35 +++- .../one-context.d/loc-10-network.d/netcfg-nm | 96 ++++++++--- .../loc-10-network.d/netcfg-scripts | 160 +++++++++++++++--- .../one-context-force.service##systemd.one | 1 + .../one-context-online.service##systemd.one | 12 +- ...t-reconfigure-delayed.service##systemd.one | 1 + ...e-context-reconfigure.service##systemd.one | 1 + .../system/one-context.service##systemd.one | 6 +- src/usr/sbin/one-context-run##one | 2 +- src/usr/sbin/one-contextd | 1 + 20 files changed, 703 insertions(+), 141 deletions(-) rename src/etc/NetworkManager/conf.d/{opennebula.conf##linux.one => one-context.conf##linux.one} (100%) create mode 100755 src/etc/NetworkManager/dispatcher.d/pre-up.d/netplan-ipv6-privacy-off##deb rename src/etc/devd/{context.conf##bsd => one-context.conf##bsd} (100%) diff --git a/pkg/postinstall b/pkg/postinstall index 030a6aa..2f56966 100755 --- a/pkg/postinstall +++ b/pkg/postinstall @@ -1,6 +1,5 @@ #!/usr/bin/env bash -NETWORK=${NETWORK:-yes} SERVICES=${SERVICES:-one-context-local one-context-online one-context} TIMERS=${TIMERS:-one-context-reconfigure.timer} @@ -73,8 +72,8 @@ fi ### Cleanup network configuration ########################## -if [ "${NETWORK}" != 'yes' ]; then - exit +if [ -f /etc/sysctl.d/50-one-context.conf ]; then + rm -f /etc/sysctl.d/50-one-context.conf fi # Debian based distros @@ -82,7 +81,6 @@ if [ -d /etc/network ]; then # Prepare network files cp /etc/network/interfaces "/etc/network/interfaces.$(date '+%s')" rm -rf /etc/network/interfaces.d - rm -rf /etc/netplan/* cat > /etc/network/interfaces <&2 exit 1 @@ -121,6 +152,7 @@ case "$action" in reconfigure) configure_network reload_network + # wait_online ;; *) echo "ERROR [!]: Unknown ACTION: ${action}" >&2 diff --git a/src/etc/one-context.d/loc-10-network-pci##one b/src/etc/one-context.d/loc-10-network-pci##one index d88269f..6c5bae1 100755 --- a/src/etc/one-context.d/loc-10-network-pci##one +++ b/src/etc/one-context.d/loc-10-network-pci##one @@ -63,7 +63,6 @@ for pci in $PCI_INTERFACES; do GATEWAY=$(get_iface_var "GATEWAY") METRIC=$(get_iface_var "METRIC") MTU=$(get_iface_var "MTU") - MTU=${MTU:-1500} VLAN_ID=$(get_iface_var "VLAN_ID") IP6=$(get_iface_var "IP6") diff --git a/src/etc/one-context.d/loc-10-network.d/functions b/src/etc/one-context.d/loc-10-network.d/functions index 9f64f72..2854ccc 100644 --- a/src/etc/one-context.d/loc-10-network.d/functions +++ b/src/etc/one-context.d/loc-10-network.d/functions @@ -38,8 +38,8 @@ initialize_network() ;; *) mkdir -p /etc/sysctl.d/ - rm -f /etc/sysctl.d/00-opennebula-netcfg.conf - sysctl -p + rm -f /etc/sysctl.d/50-one-context.conf + sysctl --system 2>/dev/null || sysctl -p ;; esac @@ -64,14 +64,17 @@ initialize_network() # network-scripts rm -f \ "/etc/sysconfig/network-scripts/route-${dev}" \ + "/etc/sysconfig/network-scripts/route6-${dev}" \ + "/etc/sysconfig/network-scripts/ifcfg-${dev}" \ "/etc/sysconfig/network/ifroute-${dev}" \ "/etc/sysconfig/network/ifsysctl-${dev}" \ - "/etc/sysconfig/network-scripts/ifcfg-${dev}" \ "/etc/sysconfig/network/ifcfg-${dev}" \ ; # networkd - rm -f "/etc/systemd/network/${dev}.network" + rm -f \ + "/etc/systemd/network/${dev}.network" \ + "/etc/systemd/network/${dev}.link" # nm (on RH systems it was deleted with ifcfg-*) for _nm_con in /etc/NetworkManager/system-connections/* ; do @@ -81,13 +84,70 @@ initialize_network() done done + # To avoid clashes when running legacy network-scripts and + # NetworkManager/networkd, we disable old-style networking + # on Red Hats and enable later back only if needed. + if [ -d /etc/sysconfig/network-scripts/ ]; then + touch /etc/sysconfig/network + sed -i -e '/^NETWORKING=/d' /etc/sysconfig/network + echo 'NETWORKING=no' >>/etc/sysconfig/network + fi + # interfaces if [ -e /etc/network/interfaces ] ; then - cat /dev/null > /etc/network/interfaces + cat </etc/network/interfaces +# Generated by one-context +auto lo +iface lo inet loopback + +EOT + + case "${os_id}" in + debian|ubuntu|devuan) + echo "source /etc/network/interfaces.d/*.cfg" >> /etc/network/interfaces + ;; + esac fi # netplan - rm -f /etc/netplan/00-opennebula-generated-network.yaml + rm -f /etc/netplan/50-one-context.yaml + + nm_disable +} + +nm_disable() { + if [ -d /etc/NetworkManager/conf.d/ ] && + ! [ -e /etc/NetworkManager/conf.d/50-unmanaged-devices.conf ]; + then + cat - </etc/NetworkManager/conf.d/50-unmanaged-devices.conf +# Generated by one-context + +# NOTE: NetworkManager was dynamically disabled by OpenNebula +# contextualization scripts because interfaces are managed by +# different network service! + +[keyfile] +unmanaged-devices=* +EOF + + if command -v systemctl >/dev/null; then + systemctl --no-block try-reload-or-restart NetworkManager.service 2>/dev/null + else + service NetworkManager reload 2>/dev/null + fi + fi +} + +nm_enable() { + if [ -e /etc/NetworkManager/conf.d/50-unmanaged-devices.conf ]; then + rm -f /etc/NetworkManager/conf.d/50-unmanaged-devices.conf + + if command -v systemctl >/dev/null; then + systemctl --no-block try-reload-or-restart NetworkManager.service 2>/dev/null + else + service NetworkManager reload 2>/dev/null + fi + fi } configure_network() @@ -141,6 +201,14 @@ detect_os() # shellcheck disable=SC1091 . /etc/os-release echo "$ID" | tr '[:upper:]' '[:lower:]' + + # check for legacy RHEL/CentOS 6 + elif [ -f /etc/centos-release ]; then + echo 'centos' + elif [ -f /etc/redhat-release ]; then + echo 'redhat' + + # fallback to uname (returns Linux, FreeBSD, ...) else uname | tr '[:upper:]' '[:lower:]' fi @@ -160,8 +228,42 @@ disable_ipv6() echo "ERROR [!]: Disabling of IPv6 on '${os_id}' is not supported" >&2 ;; *) - echo "net.ipv6.conf.${1}.disable_ipv6 = 1" >> /etc/sysctl.d/00-opennebula-netcfg.conf - sysctl -w "net.ipv6.conf.${1}.disable_ipv6=1" + # VH-TODO: do we suport runtime enable? + for S in \ + "net.ipv6.conf.${1}.disable_ipv6=1" \ + "net.ipv6.conf.${1}.autoconf=0" \ + "net.ipv6.conf.${1}.accept_ra=0"; + do + # don't duplicate entries on recontextualization + if ! grep -Fxq "${S}" /etc/sysctl.d/50-one-context.conf 2>/dev/null; then + echo "${S}" >> /etc/sysctl.d/50-one-context.conf + fi + + sysctl -w "${S}" >/dev/null + done + ;; + esac +) + +# arg: +disable_ipv6_privacy() +( + case "${os_id}" in + freebsd) + echo "ERROR [!]: Disabling of IPv6 privacy on '${os_id}' is not supported" >&2 + ;; + *) + # shellcheck disable=SC2066 + for S in \ + "net.ipv6.conf.${1}.use_tempaddr=0"; + do + # don't duplicate entries on recontextualization + if ! grep -Fxq "${S}" /etc/sysctl.d/50-one-context.conf 2>/dev/null; then + echo "${S}" >> /etc/sysctl.d/50-one-context.conf + fi + + sysctl -w "${S}" >/dev/null + done ;; esac ) @@ -186,13 +288,13 @@ skip_interface() _skip4=no ;; *) - echo "ERROR [!]: Unknown IPv4 method: ${method}" >&2 - exit 1 + echo "ERROR [!]: Unknown IPv4 method: ${method}, skipping" >&2 + _skip4=yes ;; esac _skip6= - case "${method6}" in + case "${ip6_method}" in ''|static) if [ -z "${ip6}" ] ; then _skip6=yes @@ -203,7 +305,7 @@ skip_interface() skip) _skip6=yes ;; - disabled) + disable) disable_ipv6 "${dev}" _skip6=yes ;; @@ -211,8 +313,8 @@ skip_interface() _skip6=no ;; *) - echo "ERROR [!]: Unknown IPv4 method: ${method6}" >&2 - exit 1 + echo "ERROR [!]: Unknown IPv6 method: ${ip6_method}" >&2 + _skip6=yes ;; esac @@ -296,6 +398,7 @@ get_mask() # arg: get_mtu() ( + # VH_TODO: drop default 1500, nekde se spoleha na tento default! _mtu=$(get_iface_var "$1" "MTU") echo "${_mtu:-1500}" ) @@ -391,14 +494,21 @@ setup_iface_vars() export mac=$(get_iface_var "$1" "MAC") export dev=$(get_dev "$_iface_mac" "$mac") - export mtu=$(get_mtu "$1") + #export mtu=$(get_mtu "$1") + export mtu=$(get_iface_var "$1" "MTU") export gateway=$(get_gateway "$1") export gateway6=$(get_gateway6 "$1") export metric=$(get_iface_var "$1" "METRIC") + export ip6_metric=$(get_iface_var "$1" "IP6_METRIC") export dns=$(get_dns "$1") export search_domains=$(get_search_domain "$1") export method=$(get_iface_var "$1" "METHOD") - export method6=$(get_iface_var "$1" "IP6_METHOD") + export ip6_method=$(get_iface_var "$1" "IP6_METHOD") + + # defaults + [ -z "$ip6_metric" ] && ip6_metric="${metric}" + [ -z "$method" ] && method='static' + [ -z "$ip6_method" ] && ip6_method="${method}" setup_ipadr_vars "$1" setup_ip6adr_vars "$1" diff --git a/src/etc/one-context.d/loc-10-network.d/netcfg-bsd b/src/etc/one-context.d/loc-10-network.d/netcfg-bsd index 6035828..7e50176 100644 --- a/src/etc/one-context.d/loc-10-network.d/netcfg-bsd +++ b/src/etc/one-context.d/loc-10-network.d/netcfg-bsd @@ -79,8 +79,9 @@ export mtu export gateway export gateway6 export method -export method6 +export ip6_method export metric +export ip6_metric export dns export search_domains export external @@ -106,6 +107,12 @@ gen_iface_conf() echo -n " mtu ${mtu}" fi + # WARNING: On FreeBSD the interface metrics are used only + # by routing daemons (see man 8 ifconfig) + if [ -n "${metric}" ]; then + echo -n " metric ${metric}" + fi + echo "\"" ### @@ -120,7 +127,7 @@ gen_dhcp_conf() echo -n "ifconfig_${dev}=\"DHCP" if [ -n "${mtu}" ]; then - echo -n " mtu ${mtu}" + echo -n " inet mtu ${mtu}" fi echo "\"" @@ -140,6 +147,12 @@ gen_iface6_conf() echo -n " mtu ${mtu}" fi + # WARNING: On FreeBSD the interface metrics are used only + # by routing daemons (see man 8 ifconfig) + if [ -n "${ip6_metric}" ]; then + echo -n " metric ${ip6_metric}" + fi + echo " -accept_rtadv\"" if [ -n "${ip6_ula}" ]; then @@ -156,14 +169,10 @@ gen_iface6_conf() gen_dhcp6_conf() { - echo -n "ifconfig_${dev}_ipv6=\"inet6" - - if [ -n "${mtu}" ]; then - echo -n " mtu ${mtu}" - fi + echo -n "ifconfig_${dev}_ipv6=\"" - if [ "${method6}" = "dhcp" ] ; then - echo -n " DHCP" + if [ "${ip6_method}" = "dhcp" ] ; then + echo -n "DHCP " # FreeBSD support for DHCP6 does not seem to be great: # https://forums.freebsd.org/threads/ipv6-dhcpv6-client-and-accept_rtadv-vs-rtsold.77421/ @@ -175,7 +184,13 @@ gen_dhcp6_conf() fi fi - echo " accept_rtadv\"" + echo -n "inet6 accept_rtadv" + + if [ -n "${mtu}" ]; then + echo -n " mtu ${mtu}" + fi + + echo "\"" # Enable Router Solicitation Deaemon # NOTE: It's not enough to just enable the daemon during the current @@ -198,6 +213,12 @@ gen_alias6_conf() echo -n " mtu ${mtu}" fi + # WARNING: On FreeBSD the interface metrics are used only + # by routing daemons (see man 8 ifconfig) + if [ -n "${ip6_metric}" ]; then + echo -n " metric ${ip6_metric}" + fi + echo " -accept_rtadv\"" fi @@ -210,7 +231,7 @@ gen_alias6_conf() gen_network_configuration() { # clean routing information - cat /dev/null > /etc/rc.conf.d/routing + echo '# Generated by one-context' | tee /etc/rc.conf.d/routing _context_interfaces=$(get_context_interfaces) @@ -228,20 +249,20 @@ gen_network_configuration() ;; esac - case "${method6}" in + case "${ip6_method}" in ''|static) [ -n "${ip6}" ] && gen_iface6_conf ;; auto|dhcp) gen_dhcp6_conf ;; - disabled) + disable) : ;; esac has_ip6="${ip6}" - _aliases=$(get_interface_alias) + _aliases=$(get_interface_alias "$_iface") alias_num=0 for _nic_alias in $_aliases; do diff --git a/src/etc/one-context.d/loc-10-network.d/netcfg-interfaces b/src/etc/one-context.d/loc-10-network.d/netcfg-interfaces index 371571e..62baea9 100644 --- a/src/etc/one-context.d/loc-10-network.d/netcfg-interfaces +++ b/src/etc/one-context.d/loc-10-network.d/netcfg-interfaces @@ -38,12 +38,6 @@ configure_network() { gen_resolvconf gen_network_configuration > /etc/network/interfaces - - case "${os_id}" in - debian|ubuntu|devuan) - echo "source /etc/network/interfaces.d/*.cfg" >> /etc/network/interfaces - ;; - esac } stop_network() @@ -136,8 +130,9 @@ export mtu export gateway export gateway6 export method -export method6 +export ip6_method export metric +export ip6_metric export dns export search_domains export external @@ -154,10 +149,6 @@ iface ${dev} inet static netmask ${mask} EOT - if [ -n "$mtu" ]; then - echo " mtu ${mtu}" - fi - if [ -n "$gateway" ]; then echo " gateway ${gateway}" @@ -166,12 +157,30 @@ EOT fi fi + if [ -n "$mtu" ]; then + echo " mtu ${mtu}" + fi + echo "" } gen_dhcp_conf() { echo "iface ${dev} inet dhcp" + + if [ -n "$mtu" ]; then + case "${os_id}" in + alpine) + echo " mtu ${mtu}" + ;; + debian|ubuntu|devuan) + echo " pre-up ip link set dev ${dev} mtu ${mtu}" + ;; + *) + exit 1 + ;; + esac + fi } gen_alias_conf() @@ -209,12 +218,36 @@ EOT ;; esac - if [ -n "${mtu}" ]; then - echo " mtu ${mtu}" - fi + # On Alpine Linux when using IPv6 gateway/metric options, + # they override the metric on IPv4 routes. We better configure + # default route via up script. + if [ "${os_id}" = 'alpine' ] && \ + [ -n "${gateway6}" ] && [ -n "${ip6_metric}" ]; + then + echo " up ip -6 route add default via ${gateway6} dev ${dev} metric ${ip6_metric}" - if [ -n "${gateway6}" ]; then + elif [ -n "${gateway6}" ]; then echo " gateway ${gateway6}" + + if [ -n "${ip6_metric}" ]; then + echo " metric ${ip6_metric}" + fi + fi + + if [ -n "${mtu}" ]; then + case "${os_id}" in + alpine) + echo " mtu ${mtu}" + ;; + debian|ubuntu|devuan) + # Ignores "mtu x", IPv6-only interfaces would not be configured + echo " pre-up ip link set dev ${dev} mtu ${mtu}" + echo " pre-up echo ${mtu} > /proc/sys/net/ipv6/conf/${dev}/mtu" + ;; + *) + exit 1 + ;; + esac fi if [ -n "${ip6_ula}" ]; then @@ -231,11 +264,34 @@ EOT gen_dhcp6_conf() { - if [ "${method6}" = "auto" ] ; then + if [ "${ip6_method}" = "auto" ] ; then echo "iface ${dev} inet6 auto" else echo "iface ${dev} inet6 dhcp" fi + + case "${os_id}" in + alpine) + if [ -n "${mtu}" ]; then + echo " mtu ${mtu}" + fi + + echo " pre-up echo 0 > /proc/sys/net/ipv6/conf/${dev}/use_tempaddr" + ;; + debian|ubuntu|devuan) + echo " privext 0" # this might not be effective in "dhcp" mode + echo " pre-up echo 0 > /proc/sys/net/ipv6/conf/${dev}/use_tempaddr" + + if [ -n "${mtu}" ]; then + # Ignores "mtu x", IPv6-only interfaces would not be configured + echo " pre-up ip link set dev ${dev} mtu ${mtu}" + echo " pre-up echo ${mtu} > /proc/sys/net/ipv6/conf/${dev}/mtu" + fi + ;; + *) + exit 1 + ;; + esac } gen_alias6_conf() @@ -272,6 +328,7 @@ EOT gen_network_configuration() { cat < /etc/netplan/00-opennebula-generated-network.yaml + gen_network_configuration > /etc/netplan/50-one-context.yaml netplan generate + nm_symlink_run_connections + + # On Debian 10 and Ubuntu 18.04 the initial netplan apply is needed to + # set some interface parameters (e.g., MTU). Unfortunately, this deadlocks + # booting of current systems, so we execute netplan apply on the background + case "${NETCFG_NETPLAN_RENDERER}" in + ''|networkd) + nohup netplan apply &>/dev/null & + ;; + esac } stop_network() @@ -41,14 +53,16 @@ stop_network() start_network() { - service networking start netplan generate + nm_symlink_run_connections + service networking start netplan apply } reload_network() { netplan generate + nm_symlink_run_connections netplan apply } @@ -73,8 +87,9 @@ export mtu export gateway export gateway6 export method -export method6 +export ip6_method export metric +export ip6_metric export dns export search_domains export external @@ -90,7 +105,7 @@ gen_addresses() ;; esac - case "${method6}" in + case "${ip6_method}" in ''|static) [ -n "${ip6}" ] && gen_addr6_conf ;; @@ -114,25 +129,35 @@ gen_addresses() gen_routes() { - if [ -n "${gateway}" ] ; then + if [ -n "${gateway}" ] && { [ -z "${method}" ] || [ "${method}" = 'static' ]; }; then cat </dev/null)" in + 1.14.*) # Debian 10 + echo "WARNING: Symlinking NM's ephemeral connections into /etc" >&2 + ;; + *) + return + ;; + esac + + # symlink Netplan connection files + for _src in /run/NetworkManager/system-connections/netplan-*; do + if [ -f "${_src}" ]; then + _dst="/etc/NetworkManager/system-connections/$(basename "${_src}")" + ln -s "${_src}" "${_dst}" + fi + done +} + init_netplan_renderer() { if [ -z "${NETCFG_NETPLAN_RENDERER}" ] ; then @@ -190,21 +249,40 @@ init_netplan_renderer() NETCFG_NETPLAN_RENDERER='networkd' elif command -v nmcli >/dev/null ; then NETCFG_NETPLAN_RENDERER='NetworkManager' + else + # fallback to networkd only not to leave the variable + # uninitialized, deployment most likely won't work! + NETCFG_NETPLAN_RENDERER='networkd' fi + else + # support alternative names for some configuration renderers + _netcfg_netplan_renderer=$(echo "$NETCFG_NETPLAN_RENDERER" | \ + sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//' | \ + tr '[:upper:]' '[:lower:]') + + # normalize renderer names and support alternatives + case "${_netcfg_netplan_renderer}" in + systemd-networkd|systemd-network|systemd|networkd) + NETCFG_NETPLAN_RENDERER='networkd' + ;; + networkmanager|nm) + NETCFG_NETPLAN_RENDERER='NetworkManager' + ;; + esac fi } gen_network_configuration() { - init_netplan_renderer + if [ "${NETCFG_NETPLAN_RENDERER}" = 'NetworkManager' ]; then + nm_enable + fi - # TODO: consider to change the default to more robust NetworkManager - the - # netplan's renderer default is networkd which may encounter issues with - # version 248 cat </dev/null || : } reload_network() { + # TODO: for newer systemd-networkd use + # networkctl reload && networkctl reconfigure ethX + # and fallback to service restart only if needed systemctl restart systemd-networkd.service + + # Dummy query waits until networkd is running + networkctl list &>/dev/null || : } # @@ -69,8 +78,9 @@ export mtu export gateway export gateway6 export method -export method6 +export ip6_method export metric +export ip6_metric export dns export search_domains export external @@ -157,6 +167,11 @@ EOT ;; esac + cat </dev/null || true # this is still necessary to really unconfigure the interface ip addr flush "$dev" @@ -278,6 +296,7 @@ gen_network_configuration() { cat </dev/null) ; then @@ -106,7 +111,7 @@ wait_for_nm() gen_iface_conf() { - nmcli con mod "${dev}" ipv4.method manual ipv4.addr "${ip}/${cidr}" + nmcli con mod "${dev}" ipv4.method manual ipv4.addresses "${ip}/${cidr}" if [ -n "$gateway" ]; then nmcli con mod "${dev}" ipv4.gateway "${gateway}" @@ -117,16 +122,19 @@ gen_iface_conf() if [ -n "$metric" ]; then nmcli con mod "${dev}" ipv4.route-metric "${metric}" else - nmcli con mod "${dev}" ipv4.route-metric "" + # Force default Linux IPv4 metric (man 8 route) to override + # automatic metrics calculation done by NetworkManager and unify + # behavior among different renderers. + nmcli con mod "${dev}" ipv4.route-metric "0" fi } reset_iface() { - # the order is significant - ip.addr cannot be erased while gateway is set + # the order is significant - ip.addresses cannot be erased while gateway is set nmcli con mod "${dev}" ipv4.route-metric "" nmcli con mod "${dev}" ipv4.gateway "" - nmcli con mod "${dev}" ipv4.addr "" + nmcli con mod "${dev}" ipv4.addresses "" } gen_dhcp_conf() @@ -139,16 +147,16 @@ gen_dhcp_conf() gen_alias_conf() { - nmcli con mod "${dev}" +ipv4.addr "${ip}/${cidr}" + nmcli con mod "${dev}" +ipv4.addresses "${ip}/${cidr}" } gen_iface6_conf() { nmcli con mod "${dev}" ipv6.method manual \ - ipv6.addr "${ip6}/${ip6_prefix_length:-64}" + ipv6.addresses "${ip6}/${ip6_prefix_length:-64}" if [ -n "$ip6_ula" ]; then - nmcli con mod "${dev}" +ipv6.addr "${ip6_ula}/64" + nmcli con mod "${dev}" +ipv6.addresses "${ip6_ula}/64" fi if [ -n "$gateway6" ]; then @@ -157,40 +165,53 @@ gen_iface6_conf() nmcli con mod "${dev}" ipv6.gateway "" fi - if [ -n "$metric" ]; then - nmcli con mod "${dev}" ipv6.route-metric "${metric}" + if [ -n "$ip6_metric" ]; then + nmcli con mod "${dev}" ipv6.route-metric "${ip6_metric}" else - nmcli con mod "${dev}" ipv6.route-metric "" + # Force default Linux IPv6 metric (man 8 route) to override + # automatic metrics calculation done by NetworkManager and unify + # behavior among different renderers. + nmcli con mod "${dev}" ipv6.route-metric "1" fi + + # We need this to ensure link-local address has expected form + nmcli con mod "${dev}" ipv6.addr-gen-mode eui64 } reset_iface6() { - # the order is significant - ip.addr cannot be erased while gateway is set + # the order is significant - ipv6.addresses cannot be erased while gateway is set nmcli con mod "${dev}" ipv6.route-metric "" nmcli con mod "${dev}" ipv6.gateway "" - nmcli con mod "${dev}" ipv6.addr "" + nmcli con mod "${dev}" ipv6.addresses "" } gen_alias6_conf() { - nmcli con mod "${dev}" +ipv6.addr "${ip6}/${ip6_prefix_length:-64}" + nmcli con mod "${dev}" +ipv6.addresses "${ip6}/${ip6_prefix_length:-64}" if [ -n "$ip6_ula" ]; then - nmcli con mod "${dev}" +ipv6.addr "${ip6_ula}/64" + nmcli con mod "${dev}" +ipv6.addresses "${ip6_ula}/64" fi } gen_dhcp6_conf() { - if [ "${method6}" = "auto" ] ; then - # TODO: is this really correct? Shouldn't be auto? + if [ "${ip6_method}" = "auto" ] ; then + # Method "ignore" relies only on SLAAC configured by the kernel, + # while the "auto" might optionally trigger also DHCPv6 client! + # https://unix.stackexchange.com/questions/440076/disable-dhcpv6-while-not-disabling-slaac-in-network-manager _dhcp=ignore else - _dhcp=dhcp + # Method "auto" optionally triggers DHCPv6 client if RA has relevant + # flags (also netplan+nm configures "auto")! Method "dhcp" could + # ignore RA. + _dhcp=auto fi nmcli con mod "${dev}" ipv6.method "${_dhcp}" + nmcli con mod "${dev}" ipv6.addr-gen-mode eui64 + nmcli con mod "${dev}" ipv6.ip6-privacy 0 # cleanup any leftover from the static method reset_iface6 @@ -199,6 +220,8 @@ gen_dhcp6_conf() # arg: nm_connection_exist() ( + # VH-TODO: We should be better checking across all connections, if there + # isn't any with our device to avoid clashes and drop/rename that one _iface=$(nmcli --field connection.interface-name con show "$1" | awk '{print $2}') if [ "${_iface}" = "$1" ] ; then return 0 @@ -216,8 +239,15 @@ gen_network_configuration() skip_interface && continue + # We might need to disable IPv6 and privacy directly by sysctl + _disable_ipv6='' + _disable_ipv6_privacy='' + if ! nm_connection_exist "${dev}" ; then - nmcli con add type ethernet con-name "${dev}" ifname "${dev}" + nmcli con add type ethernet \ + con-name "${dev}" ifname "${dev}" \ + ipv4.method disabled \ + ipv6.method ignore fi nmcli con mod "${dev}" connection.autoconnect yes @@ -237,15 +267,27 @@ gen_network_configuration() ;; esac - case "${method6}" in + case "${ip6_method}" in ''|static) [ -n "${ip6}" ] && gen_iface6_conf ;; - auto|dhcp) + auto) + gen_dhcp6_conf + + # NOTE: Hot plugged NICs configured with IPv6 method ignore + # doesn't have to properly update the IPv6 privacy. + # We better enforce them via direct sysctl. + # VH-TODO: limit only for reconfigure action? + _disable_ipv6_privacy='yes' + ;; + dhcp) gen_dhcp6_conf ;; - disabled) - nmcli con mod "${dev}" ipv6.method disabled + disable) + # NOTE: Older NMs don't support ipv6.method disabled, + # in that case we rely on hard disablemenets via sysctl + nmcli con mod "${dev}" ipv6.method disabled || + _disable_ipv6='yes' ;; esac @@ -266,5 +308,13 @@ gen_network_configuration() # 'nmcli con reload' is not enough nmcli con up "${dev}" + + if [ -n "${_disable_ipv6}" ]; then + disable_ipv6 "${dev}" + fi + + if [ -n "${_disable_ipv6_privacy}" ]; then + disable_ipv6_privacy "${dev}" + fi done } diff --git a/src/etc/one-context.d/loc-10-network.d/netcfg-scripts b/src/etc/one-context.d/loc-10-network.d/netcfg-scripts index 1a857f6..a3af540 100644 --- a/src/etc/one-context.d/loc-10-network.d/netcfg-scripts +++ b/src/etc/one-context.d/loc-10-network.d/netcfg-scripts @@ -22,9 +22,24 @@ is_network_supported() { - if [ -e /etc/sysconfig/network-scripts/ifup ] || \ - [ -e /etc/sysconfig/network/ifup ] ; - then + # Red Hat family + if [ -x /etc/sysconfig/network-scripts/ifup ]; then + # On EL8, the network-scripts (package) is legacy + # and network service is not even enabled by default. + # For safety we check if network service is enabled + # and if not, we better choose different renderer. + if command -v systemctl &>/dev/null; then + systemctl is-enabled network &>/dev/null && return 0 + + # NOTE: Probably not necesary test on old systems + elif chkconfig network --level 3 &>/dev/null || \ + chkconfig network --level 5 &>/dev/null; + then + return 0 + fi + + # SUSE family + elif [ -d /etc/sysconfig/network/ ]; then return 0 fi @@ -73,8 +88,9 @@ export mtu export gateway export gateway6 export method -export method6 +export ip6_method export metric +export ip6_metric export dns export search_domains export external @@ -85,16 +101,24 @@ export all_search_domains gen_iface_conf() { cat <> "${config_path}/ifroute-${dev}" - else + fi + + ### Red Hat family ### + else + echo 'BOOTPROTO=none' + + if [ -n "${gateway}" ]; then echo "default via ${gateway} dev ${dev} ${metric:+metric ${metric}}" \ >> "${config_path}/route-${dev}" fi @@ -107,7 +131,25 @@ EOT gen_dhcp_conf() { - echo "BOOTPROTO=dhcp" + ### SUSE family ### + if [ "${config_path}" = "/etc/sysconfig/network" ]; then + if [ "${ip6_method}" = 'dhcp' ]; then + echo 'BOOTPROTO=dhcp' + else + echo 'BOOTPROTO=dhcp4' + fi + + ### Red Hat family ### + else + cat <> "/etc/sysconfig/network/ifsysctl-${dev}" +net.ipv6.conf.\$SYSCTL_IF.mtu = ${mtu} +EOT + fi + + ### Red Hat family ### else cat <> "/etc/sysconfig/network/ifroute-${dev}" + echo "default ${gateway6} - ${dev} ${ip6_metric:+metric ${ip6_metric}}" \ + >> "/etc/sysconfig/network/ifroute-${dev}" else - echo "IPV6_DEFAULTGW=${gateway6}" + echo "default via ${gateway6} dev ${dev} ${ip6_metric:+metric ${ip6_metric}}" \ + >> "${config_path}/route6-${dev}" fi fi - - if [ -n "${mtu}" ]; then - echo "IPV6_MTU=${mtu}" - fi } gen_dhcp6_conf() { - if [ "${method6}" = "auto" ] ; then - cat <> "/etc/sysconfig/network/ifsysctl-${dev}" +net.ipv6.conf.\$SYSCTL_IF.autoconf = 1 +net.ipv6.conf.\$SYSCTL_IF.accept_ra = 1 +net.ipv6.conf.\$SYSCTL_IF.use_tempaddr = 0 +EOT + + if [ -n "${mtu}" ]; then + # place only if not set via IPv4 parts + if [ -z "${_set_ipv4}" ]; then + echo "MTU=${mtu}" + fi + + cat <> "/etc/sysconfig/network/ifsysctl-${dev}" +net.ipv6.conf.\$SYSCTL_IF.mtu = ${mtu} +EOT + fi + + ### Red Hat family ### + else + if [ "${ip6_method}" = "auto" ] ; then + cat <>/etc/sysconfig/network + fi + + ### SUSE family ### elif [ -d /etc/sysconfig/network ]; then config_path=/etc/sysconfig/network fi @@ -203,19 +307,27 @@ gen_network_configuration() skip_interface && continue + # in IPv6 sections we might need to know if + # any IPv4 configuration was already placed + _set_ipv4= + # cumulative variable ipv6addr_secondaries='' { rm -f "/etc/sysconfig/network-scripts/route-${dev}" + rm -f "/etc/sysconfig/network-scripts/route6-${dev}" rm -f "/etc/sysconfig/network/ifroute-${dev}" rm -f "/etc/sysconfig/network/ifsysctl-${dev}" cat <