From f94508d537432817619932074a5f98ea08d93055 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Harald=20Jens=C3=A5s?= Date: Wed, 30 Oct 2019 12:27:30 +0100 Subject: [PATCH] Add IPv6 support in dhcp-all-interfaces When the rdisc6 utility is available probe for router advertisement. configure eni and rhel-netscripts interfaces to do IPv6 address configuration according to the flags in the RA recived from the router. The systemd service file timeout is DIB_DHCP_TIMEOUT * 2, so that DHCPv4 can timout, and dhcpv6 run before the service times out. Retries are commented in dhclient.conf, without it we end up trying DIB_DHCP_TIMEOUT * 60 before the client move on to IPv6. WHEN: Stateful address conf. : No Stateful other conf. : No THEN: Do not run dhclient at all, autoconfiguration via SLAAC only. WHEN: Stateful address conf. : No Stateful other conf. : Yes THEN: Run "dhclient -6 -S", The ``-S`` option makes the dhcp client not request an address, only other options such as DNS servers and NTP servers from DHCPv6 server. WHEN: Stateful address conf. : Yes Stateful other conf. : Yes THEN: The dhcp client should request an address _and_ other options such as DNS servers and NTP servers from DHCPv6 server. NOTE: No IPv6 support added for suse-netscripts Closes-Bug: 1754219 Change-Id: Icdc79875c33f894ab7eaec8afdfb33a731efff99 --- .../install.d/50-dhcp-all-interfaces | 5 +- .../install.d/dhcp-all-interfaces.sh | 73 ++++++++++++++++++- .../dhcp-all-interfaces/package-installs.yaml | 1 + .../elements/dhcp-all-interfaces/pkg-map | 12 ++- 4 files changed, 84 insertions(+), 7 deletions(-) diff --git a/diskimage_builder/elements/dhcp-all-interfaces/install.d/50-dhcp-all-interfaces b/diskimage_builder/elements/dhcp-all-interfaces/install.d/50-dhcp-all-interfaces index 439a7900..0c180c01 100755 --- a/diskimage_builder/elements/dhcp-all-interfaces/install.d/50-dhcp-all-interfaces +++ b/diskimage_builder/elements/dhcp-all-interfaces/install.d/50-dhcp-all-interfaces @@ -21,6 +21,9 @@ if [ -f /etc/dhcp/dhclient.conf ] ; then else echo -e "# \"timeout\" Value set by dhcp-all-interfaces\ntimeout ${DIB_DHCP_TIMEOUT:-30};" >> /etc/dhcp/dhclient.conf fi + if grep -o "^retry " /etc/dhcp/dhclient.conf ; then + sed -i -e '/^retry/s/^/# \"retry\" Value commented by dhcp-all-interfaces\n# /g' /etc/dhcp/dhclient.conf + fi fi if [ "$DIB_INIT_SYSTEM" == "upstart" ]; then @@ -34,7 +37,7 @@ if [ "$DIB_INIT_SYSTEM" == "upstart" ]; then elif [ "$DIB_INIT_SYSTEM" == "systemd" ]; then install -D -g root -o root -m 0644 ${SCRIPTDIR}/dhcp-interface@.service /usr/lib/systemd/system/dhcp-interface@.service install -D -g root -o root -m 0644 ${SCRIPTDIR}/dhcp-all-interfaces-udev.rules /etc/udev/rules.d/99-dhcp-all-interfaces.rules - sed -i "s/TimeoutStartSec=DIB_DHCP_TIMEOUT/TimeoutStartSec=${DIB_DHCP_TIMEOUT:-30}s/" /usr/lib/systemd/system/dhcp-interface@.service + sed -i "s/TimeoutStartSec=DIB_DHCP_TIMEOUT/TimeoutStartSec=$(( ${DIB_DHCP_TIMEOUT:-30} * 2 ))s/" /usr/lib/systemd/system/dhcp-interface@.service elif [ "$DIB_INIT_SYSTEM" == "sysv" ]; then install -D -g root -o root -m 0755 ${SCRIPTDIR}/dhcp-all-interfaces.init /etc/init.d/dhcp-all-interfaces update-rc.d dhcp-all-interfaces defaults diff --git a/diskimage_builder/elements/dhcp-all-interfaces/install.d/dhcp-all-interfaces.sh b/diskimage_builder/elements/dhcp-all-interfaces/install.d/dhcp-all-interfaces.sh index 25113b71..1e534884 100755 --- a/diskimage_builder/elements/dhcp-all-interfaces/install.d/dhcp-all-interfaces.sh +++ b/diskimage_builder/elements/dhcp-all-interfaces/install.d/dhcp-all-interfaces.sh @@ -47,15 +47,54 @@ function get_if_type() { function enable_interface() { local interface=$1 + local ipv6_init=$2 + local ipv6_AdvManagedFlag=$3 + local ipv6_AdvOtherConfigFlag=$4 serialize_me if [ "$CONF_TYPE" == "eni" ]; then printf "auto $interface\niface $interface inet dhcp\n\n" >>$ENI_FILE + if [ "$ipv6_init" == "True" ]; then + # Make DUID-UUID Type 4 (RFC 6355) + echo "default-duid \"\\x00\\x04$(sed 's/.\{2\}/\\x&/g' < /etc/machine-id)\";" >"/var/lib/dhclient/dhclient6--$interface.lease" + if [ $ipv6_AdvManagedFlag == "Yes" ]; then + # IPv6 DHCPv6 Stateful address configuration + printf "iface $interface inet6 dhcp\n\n" >>$ENI_FILE + echo "DHCPv6 Stateful Configured." + elif [ $ipv6_AdvOtherConfigFlag == "Yes" ]; then + # IPv6 DHCPv6 Stateless address configursation + printf "iface $interface inet6 auto\n\tdhcp 1\n\n" >>$ENI_FILE + echo "DHCPv6 Stateless Configured." + else + # IPv6 Autoconfiguration (SLAAC) + printf "iface $interface inet6 auto\tdhcp 0\n\n" >>$ENI_FILE + echo "IPv6 SLAAC Configured" + fi + fi + printf "\n" >>$ENI_FILE elif [ "$CONF_TYPE" == "rhel-netscripts" ]; then if [ "$(get_if_type $interface)" == "32" ]; then printf "DEVICE=\"$interface\"\nBOOTPROTO=\"dhcp\"\nONBOOT=\"yes\"\nTYPE=\"InfiniBand\"\nCONNECTED_MODE=\"no\"\nDEFROUTE=\"yes\"\nPEERDNS=\"yes\"\nPEERROUTES=\"yes\"\nIPV4_FAILURE_FATAL=\"yes\"\nIPV6INIT=\"no\"" >"${SCRIPTS_PATH}ifcfg-$interface" else - printf "DEVICE=\"$interface\"\nBOOTPROTO=\"dhcp\"\nONBOOT=\"yes\"\nTYPE=\"Ethernet\"" >"${SCRIPTS_PATH}ifcfg-$interface" + printf "DEVICE=\"$interface\"\nBOOTPROTO=\"dhcp\"\nONBOOT=\"yes\"\nTYPE=\"Ethernet\"\n" >"${SCRIPTS_PATH}ifcfg-$interface" + if [ "$ipv6_init" == "True" ]; then + # Make DUID-UUID Type 4 (RFC 6355) + echo "default-duid \"\\x00\\x04$(sed 's/.\{2\}/\\x&/g' < /etc/machine-id)\";" >"/var/lib/dhclient/dhclient6--$interface.lease" + printf "IPV6INIT=\"yes\"\n" >>"${SCRIPTS_PATH}ifcfg-$interface" + if [ $ipv6_AdvManagedFlag == "Yes" ]; then + # IPv6 DHCPv6 Stateful address configuration + printf "IPV6_FORCE_ACCEPT_RA=\"yes\"\nDHCPV6C=\"yes\"\n" >>"${SCRIPTS_PATH}ifcfg-$interface" + echo "DHCPv6 Stateful Configured" + elif [ $ipv6_AdvOtherConfigFlag == "Yes" ]; then + # IPv6 DHCPv6 Stateless address configursation + printf "IPV6_AUTOCONF=\"yes\"\nDHCPV6C=\"yes\"\nDHCPV6C_OPTIONS=\"-S\"\n" >>"${SCRIPTS_PATH}ifcfg-$interface" + echo "DHCPv6 Stateless Configured" + else + # IPv6 Autoconfiguration (SLAAC) + printf "IPV6_AUTOCONF=\"yes\"\n" >>"${SCRIPTS_PATH}ifcfg-$interface" + echo "IPv6 SLAAC Configured" + fi + fi fi elif [ "$CONF_TYPE" == "suse-netscripts" ]; then printf "BOOTPROTO=\"dhcp\"\nSTARTMODE=\"auto\"" >"${SCRIPTS_PATH}ifcfg-$interface" @@ -106,7 +145,37 @@ function inspect_interface() { sleep 1 done if [ "$has_link" == "1" ]; then - enable_interface "$interface" + local ipv6_init=False + local ipv6_AdvManagedFlag=No + local ipv6_AdvOtherConfigFlag=No + if type rdisc6 &>/dev/null; then + # We have rdisc6, let's try to configure IPv6 autoconfig/dhcpv6 + tries=DIB_DHCP_TIMEOUT + for ((; tries > 0; tries--)); do + # Need to retry this, link-local-address required for + # Neighbor Discovery, DHCPv6 etc. + set +e # Do not exit on error, capture rdisc6 error codes. + RA=$(rdisc6 --retry 3 --single "$interface" 2>/dev/null) + local return_code=$? + set -e # Re-enable exit on error. + if [ $return_code -eq 0 ]; then + ipv6_init=True + ipv6_AdvManagedFlag=$(echo "$RA" | grep "Stateful address conf." | awk -F: '{ print $2 }') + ipv6_AdvOtherConfigFlag=$(echo "$RA" | grep "Stateful other conf." | awk -F: '{ print $2 }') + elif [ $return_code -eq 1 ]; then + sleep 1 + elif [ $return_code -eq 2 ]; then + # If rdisc6 does not receive any response after the + # specified number of attempts waiting for wait_ms + # (1000ms by default) milliseconds each time, it will + # exit with code 2. + break + fi + done + else + echo "rdisc6 not available, skipping IPv6 configuration." + fi + enable_interface "$interface" "$ipv6_init" "$ipv6_AdvManagedFlag" "$ipv6_AdvOtherConfigFlag" else echo "No link detected, skipping" fi diff --git a/diskimage_builder/elements/dhcp-all-interfaces/package-installs.yaml b/diskimage_builder/elements/dhcp-all-interfaces/package-installs.yaml index f7310872..eee9f212 100644 --- a/diskimage_builder/elements/dhcp-all-interfaces/package-installs.yaml +++ b/diskimage_builder/elements/dhcp-all-interfaces/package-installs.yaml @@ -1,2 +1,3 @@ dhcp-client: ifupdown: +ndisc6: diff --git a/diskimage_builder/elements/dhcp-all-interfaces/pkg-map b/diskimage_builder/elements/dhcp-all-interfaces/pkg-map index 080f6cd4..95416c86 100644 --- a/diskimage_builder/elements/dhcp-all-interfaces/pkg-map +++ b/diskimage_builder/elements/dhcp-all-interfaces/pkg-map @@ -1,20 +1,24 @@ { "family": { "redhat": { - "dhcp-client": "dhclient" + "dhcp-client": "dhclient", + "ndisc6": "ndisc6" }, "gentoo": { - "dhcp-client": "net-misc/dhcpcd" + "dhcp-client": "net-misc/dhcpcd", + "ndisc6": "net-misc/ndisc6" }, "suse": { "dhcp-client": "dhcp-client" }, "debian": { - "ifupdown": "ifupdown" + "ifupdown": "ifupdown", + "ndisc6": "ndisc6" } }, "default": { "dhcp-client": "isc-dhcp-client", - "ifupdown": "" + "ifupdown": "", + "ndisc6": "" } }