[arch-projects] [netctl][PATCH 1/2] Factor out DHCP client support

Jouke Witteveen j.witteveen at gmail.com
Thu Feb 27 08:25:15 EST 2014


Support for additional DHCP clients is now easy to add.
---
 Makefile                   |  3 +-
 docs/netctl.profile.5.txt  | 16 +++++----
 src/lib/connections/README |  2 +-
 src/lib/dhcp/README        | 34 +++++++++++++++++++
 src/lib/dhcp/dhclient      | 27 +++++++++++++++
 src/lib/dhcp/dhcpcd        | 28 ++++++++++++++++
 src/lib/ip                 | 83 ++++++++++++++--------------------------------
 7 files changed, 126 insertions(+), 67 deletions(-)
 create mode 100644 src/lib/dhcp/README
 create mode 100644 src/lib/dhcp/dhclient
 create mode 100644 src/lib/dhcp/dhcpcd

diff --git a/Makefile b/Makefile
index b22fbe0..08ad462 100644
--- a/Makefile
+++ b/Makefile
@@ -15,9 +15,10 @@ install:
 	install -d $(DESTDIR)/etc/netctl/{examples,hooks,interfaces}
 	install -m644 docs/examples/* $(DESTDIR)/etc/netctl/examples/
 	# Libs
-	install -d $(DESTDIR)/usr/lib/network/connections
+	install -d $(DESTDIR)/usr/lib/network/{connections,dhcp}
 	install -m644 src/lib/{globals,ip,rfkill,wpa} $(DESTDIR)/usr/lib/network/
 	install -m644 src/lib/connections/* $(DESTDIR)/usr/lib/network/connections/
+	install -m644 src/lib/dhcp/* $(DESTDIR)/usr/lib/network/dhcp/
 	install -m755 src/lib/{auto.action,network} $(DESTDIR)/usr/lib/network/
 	# Scripts
 	install -d $(DESTDIR)/usr/bin
diff --git a/docs/netctl.profile.5.txt b/docs/netctl.profile.5.txt
index dfc13bb..2cf0285 100644
--- a/docs/netctl.profile.5.txt
+++ b/docs/netctl.profile.5.txt
@@ -137,18 +137,20 @@ network. In particular, these connection types are +ethernet+,
     An array of custom routes of the form +
     `**<address range>** via **<gateway>**'.
 
-'DHCPClient=' [requires a DHCP setting]::
-    The name of the preferred DHCP client. Supported options are
-    `dhcpcd' and `dhclient'. Defaults to `dhcpcd'.
+'DHCPClient=' [requires 'IP=dhcp']::
+    The name of the DHCP client to use. Clients may accept additional
+    options through client-specific variables. By default, *netctl*
+    comes with support for `dhcpcd' and `dhclient'. Defaults to
+    `++dhcpcd++'.
+
+'DHCP6Client=' [requires 'IP6=dhcp' or 'IP6=dhcp-noaddr']::
+    The name of the DHCPv6 client to use. By default, only `dhclient'
+    is supported. Defaults to `++dhclient++'.
 
 'DHCPReleaseOnStop='::
     Set to `++yes++' to release the DHCP lease when the profile is
     stopped.
 
-'DhcpcdOptions=', 'DhclientOptions=', 'DhclientOptions6='::
-    Additional options to be passed to the DHCP client. Do not use this
-    unless you know what you are doing.
-
 'IPCustom=()'::
     An array of argument lines to pass to `ip`. This can be used to
     achieve complicated configurations within the framework of *netctl*.
diff --git a/src/lib/connections/README b/src/lib/connections/README
index 6d8db9b..2dd4b7b 100644
--- a/src/lib/connections/README
+++ b/src/lib/connections/README
@@ -10,7 +10,7 @@ for the aviancarrier connection type will be provided by the file:
 Files that implement support for a connection type should NOT be
 executable. Such files should contain valid Bash code, among which two
 functions, namely <connection_type>_up and <connection_type>_down. For
-the aviancarrier file this would be:
+the aviancarrier file these would be:
 
   aviancarrier_up
   aviancarrier_down
diff --git a/src/lib/dhcp/README b/src/lib/dhcp/README
new file mode 100644
index 0000000..f55a06e
--- /dev/null
+++ b/src/lib/dhcp/README
@@ -0,0 +1,34 @@
+Support for dhcp clients is implemented by files in
+
+  /usr/lib/network/dhcp/
+
+The file name determines the name of the client for the profile, so
+support for a client named dhcpcd is provided by the file:
+
+  /usr/lib/network/connections/dhcpcd
+
+Files that implement support for a connection type should NOT be
+executable. Such files should contain valid Bash code, among which two
+functions, namely <client_name>_start and <client_name>_stop. For
+the client named dhcpcd these would be:
+
+  dhcpcd_start
+  dhcpcd_stop
+
+These functions are responsible for starting and stopping the dhcp
+client. When the functions are called, three bash files are already
+sourced, so all functions and variables in those files are available.
+The readily sourced files are:
+
+  /usr/lib/network/network
+  /usr/lib/network/globals
+  /etc/netctl/<profile>
+
+Here, <profile> is the profile file specifying the desired network
+configuration.
+
+When called, the start and stop functions get as their first argument
+the version of the IP protocol that the dhcp client is expected to use.
+In the case of starting the client for IPv6, an additional second
+argument 'noaddr' may be supplied, which indicates that the dhcp client
+should configure everything but an IP address.
diff --git a/src/lib/dhcp/dhclient b/src/lib/dhcp/dhclient
new file mode 100644
index 0000000..42b5f14
--- /dev/null
+++ b/src/lib/dhcp/dhclient
@@ -0,0 +1,27 @@
+type dhclient &> /dev/null || return
+
+dhclient_start() {
+    local options pidfile="/run/dhclient$1-$Interface.pid"
+    case $1 in
+      4) options=$DhclientOptions;;
+      6) options=$DhclientOptions6;;
+      *) return 1;;
+    esac
+    [[ $2 == "noaddr" ]] && options+=" -S"
+    rm -f "$pidfile"
+    if ! do_debug dhclient -$1 -q -e "TIMEOUT=${TimeoutDHCP:-30}" -pf "$pidfile" $options "$Interface"; then
+        report_error "DHCP IPv$1 lease attempt failed on interface '$Interface'"
+        return 1
+    fi
+}
+
+dhclient_stop() {
+    local stop="-x" pidfile="/run/dhclient$1-$Interface.pid"
+    if [[ -f $pidfile ]]; then
+        is_yes "${DHCPReleaseOnStop:-no}" && stop="-r"
+        do_debug dhclient -$1 -q $stop "$Interface" -pf "$pidfile" > /dev/null
+    fi
+}
+
+
+# vim: ft=sh ts=4 et sw=4:
diff --git a/src/lib/dhcp/dhcpcd b/src/lib/dhcp/dhcpcd
new file mode 100644
index 0000000..42f33ef
--- /dev/null
+++ b/src/lib/dhcp/dhcpcd
@@ -0,0 +1,28 @@
+type dhcpcd &> /dev/null || return
+
+dhcpcd_start() {
+    if [[ $1 != "4" ]]; then
+        report_error "Using 'dhcpcd' for IPv6 is currently not possible in netctl"
+        return 1
+    fi
+    rm -f "/run/dhcpcd-$Interface".{pid,cache}
+    # If using own dns, tell dhcpcd to NOT replace resolv.conf
+    [[ $DNS ]] && DhcpcdOptions+=" -C resolv.conf"
+    do_debug dhcpcd -4qL -t "${TimeoutDHCP:-30}" $DhcpcdOptions "$Interface" |& report_debug "$(cat)"
+    # The first array value of PIPESTATUS is the exit status of dhcpcd
+    if (( PIPESTATUS != 0 )); then
+        report_error "DHCP IP lease attempt failed on interface '$Interface'"
+        return 1
+    fi
+}
+
+dhcpcd_stop() {
+    local stop="-x"
+    if [[ -f "/run/dhcpcd-$Interface.pid" ]]; then
+        is_yes "${DHCPReleaseOnStop:-no}" && stop="-k"
+        do_debug dhcpcd -q $stop "$Interface" > /dev/null
+    fi
+}
+
+
+# vim: ft=sh ts=4 et sw=4:
diff --git a/src/lib/ip b/src/lib/ip
index 4698595..e737fc5 100644
--- a/src/lib/ip
+++ b/src/lib/ip
@@ -1,6 +1,26 @@
 ## /usr/lib/network/globals needs to be sourced before this file
 
 
+## Interface a DHCP client
+# $1: DHCP client
+# $2: command
+# $3...: additional arguments
+dhcp_call() {
+    local client="$1" command="$2"
+    shift 2
+
+    if [[ ! -r "$SUBR_DIR/dhcp/$client" ]]; then
+        report_error "DHCP client '$client' is unsupported"
+        return 127
+    fi
+    if ! source "$SUBR_DIR/dhcp/$client"; then
+        report_error "DHCP client '$client' is not installed or not ready"
+        return 127
+    fi
+    "${client}_$command" "$@"
+}
+
+
 ## Add resolv.conf entries for an interface
 # $1: interface name
 # $2...: entries, one line per variable
@@ -43,30 +63,7 @@ ip_set() {
 
     case $IP in
       dhcp)
-        case ${DHCPClient:-dhcpcd} in
-          dhcpcd)
-            rm -f "/run/dhcpcd-$Interface".{pid,cache}
-            # If using own dns, tell dhcpcd to NOT replace resolv.conf
-            [[ $DNS ]] && DhcpcdOptions+=" -C resolv.conf"
-            do_debug dhcpcd -4qL -t "${TimeoutDHCP:-30}" $DhcpcdOptions "$Interface" |& report_debug "$(cat)"
-            # The first array value of PIPESTATUS is the exit status of dhcpcd
-            if (( PIPESTATUS != 0 )); then
-                report_error "DHCP IP lease attempt failed on interface '$Interface'"
-                return 1
-            fi
-          ;;
-          dhclient)
-            rm -f "/run/dhclient-${Interface}.pid"
-            if ! do_debug dhclient -4 -q -e "TIMEOUT=${TimeoutDHCP:-30}" -pf "/run/dhclient-$Interface.pid" $DhclientOptions "$Interface"; then
-                report_error "DHCP IP lease attempt failed on interface '$Interface'"
-                return 1
-            fi
-          ;;
-          *)
-            report_error "Unsupported DHCP client: '$DHCPClient'"
-            return 1
-          ;;
-        esac
+        dhcp_call "${DHCPClient:-dhcpcd}" start 4 || return
       ;;
       static)
         for addr in "${Address[@]}"; do
@@ -103,17 +100,8 @@ ip_set() {
     fi
 
     case "$IP6" in
-      dhcp*)
-        if ! type dhclient &>/dev/null; then
-            report_error "You need to install dhclient to use DHCPv6"
-            return 1
-        fi
-        [[ $IP6 == "dhcp-noaddr" ]] && DhclientOptions6+=" -S"
-        rm -f "/run/dhclient6-${Interface}.pid"
-        if ! do_debug dhclient -6 -q -e "TIMEOUT=${TimeoutDHCP:-30}" -pf "/run/dhclient6-${Interface}.pid" $DhclientOptions6 "$Interface"; then
-            report_error "DHCPv6 IP lease attempt failed on interface '$Interface'"
-            return 1
-        fi
+      dhcp|dhcp-noaddr)
+        dhcp_call "${DHCP6Client:-dhclient}" start 6 ${IP6:5} || return
       ;;
       stateless|static)
         for addr in "${Address6[@]}"; do
@@ -179,29 +167,8 @@ ip_set() {
 # $IP: type of IPv4 configuration
 # $IP6: type of IPv6 configuration
 ip_unset() {
-    local stop="-x"
-    if [[ $IP == "dhcp" ]]; then
-        case ${DHCPClient:-dhcpcd} in
-          dhcpcd)
-            if [[ -f "/run/dhcpcd-$Interface.pid" ]]; then
-                is_yes "${DHCPReleaseOnStop:-no}" && stop="-k"
-                do_debug dhcpcd -q $stop "$Interface" >/dev/null
-            fi
-          ;;
-          dhclient)
-            if [[ -f "/run/dhclient-$Interface.pid" ]]; then
-                is_yes "${DHCPReleaseOnStop:-no}" && stop="-r"
-                do_debug dhclient -q $stop "$Interface" -pf "/run/dhclient-$Interface.pid" >/dev/null
-            fi
-          ;;
-        esac
-    fi
-    if [[ $IP6 == dhcp* ]]; then
-        if [[ -f "/run/dhclient6-$Interface.pid" ]]; then
-            do_debug dhclient -6 -q -x "$Interface" -pf "/run/dhclient6-$Interface.pid" >/dev/null
-        fi
-    fi
-
+    [[ $IP == "dhcp" ]] && dhcp_call "${DHCPClient:-dhcpcd}" stop 4
+    [[ $IP6 == dhcp* ]] && dhcp_call "${DHCP6Client:-dhclient}" stop 6
     [[ $DNS ]] && resolvconf -d "$Interface"
     ip route flush dev "$Interface" &>/dev/null
     ip -6 route flush dev "$Interface" &>/dev/null
-- 
1.9.0



More information about the arch-projects mailing list