diff mbox

system: Fix for NFS booting with interface config via DHCP

Message ID 1446841557.4553.32.camel@rtred1test09.kymeta.local
State Changes Requested
Headers show

Commit Message

Trent Piepho Nov. 6, 2015, 8:25 p.m. UTC
Configuring the network interface with DHCP via
/etc/network/interfaces generally does work when NFS booting.  The
DHCP configuration will initially bring the interface down and system
then hangs at that point as the root filesystem is no longer
accessable.  See bug 4709.

The system config option adds a script to if-pre-up.d that will check
for a NFS root filesystem and if the interface to be configured is
used for access to the NFS server.  If this is the case, then it
returns a failure code so that ifup will not configure the interface.
This works for DHCP and another config methods (static, bootp, etc.).
This system does detect if the interface to be configured isn't the
one used for NFS and doesn't skip it when that is the case.

NFS filesystems that aren't the root fs aren't considered.

Signed-off-by: Trent Piepho <tpiepho@kymetacorp.com>
---

Example when the interface is used for NFS:
# ifup eth0
Skipping eth0, used for NFS from 192.168.1.123
run-parts: /etc/network/if-pre-up.d/nfs_check: exit status 1

Example when the interface isn't used for NFS:
# ifup eth1
[brings interface up]

An alternative to putting the script in if-pre-up.d would be to add
pre-up lines to the interfaces file.  This would allow running the
script just for certain interfaces.  It also removes the "run-parts"
message to do it this way.

 package/skeleton/nfs_check   |  7 +++++++
 package/skeleton/skeleton.mk |  7 +++++++
 system/Config.in             | 19 +++++++++++++++++++
 3 files changed, 33 insertions(+)
 create mode 100755 package/skeleton/nfs_check

Comments

Arnout Vandecappelle Nov. 7, 2015, 12:55 a.m. UTC | #1
On 06-11-15 21:25, Trent Piepho wrote:
> Configuring the network interface with DHCP via
> /etc/network/interfaces generally does work when NFS booting.  The
> DHCP configuration will initially bring the interface down and system
> then hangs at that point as the root filesystem is no longer
> accessable.  See bug 4709.
> 
> The system config option adds a script to if-pre-up.d that will check
> for a NFS root filesystem and if the interface to be configured is
> used for access to the NFS server.  If this is the case, then it
> returns a failure code so that ifup will not configure the interface.
> This works for DHCP and another config methods (static, bootp, etc.).
> This system does detect if the interface to be configured isn't the
> one used for NFS and doesn't skip it when that is the case.
> 
> NFS filesystems that aren't the root fs aren't considered.
> 
> Signed-off-by: Trent Piepho <tpiepho@kymetacorp.com>

 Good one! A few small remarks below.

> ---
> 
> Example when the interface is used for NFS:
> # ifup eth0
> Skipping eth0, used for NFS from 192.168.1.123
> run-parts: /etc/network/if-pre-up.d/nfs_check: exit status 1
> 
> Example when the interface isn't used for NFS:
> # ifup eth1
> [brings interface up]
> 
> An alternative to putting the script in if-pre-up.d would be to add
> pre-up lines to the interfaces file.  This would allow running the
> script just for certain interfaces.  It also removes the "run-parts"
> message to do it this way.

 But I think ifup would still report an error, no?

> 
>  package/skeleton/nfs_check   |  7 +++++++
>  package/skeleton/skeleton.mk |  7 +++++++
>  system/Config.in             | 19 +++++++++++++++++++
>  3 files changed, 33 insertions(+)
>  create mode 100755 package/skeleton/nfs_check
> 
> diff --git a/package/skeleton/nfs_check b/package/skeleton/nfs_check
> new file mode 100755
> index 0000000..1914404
> --- /dev/null
> +++ b/package/skeleton/nfs_check
> @@ -0,0 +1,7 @@
> +#!/bin/sh
> +
> +nfsip=`awk '$3=="nfs" && $2=="/"{ sub(/:.*/,"",$1); print $1; }' /proc/mounts`

 sed is generally better-known so we prefer it if possible. Like

sed -n '/^\([0-9.]*\):[^ ]* \/ nfs .*/s//\1/p' /proc/mounts


 However, why don't we just check if the interface is already up? Like
ip link show $IFACE | cut -d ' ' -f 3 | grep -q UP

> +if [ -n "$nfsip" ] && ip route get to "$nfsip" | grep -q "dev $IFACE"; then
> +  echo Skipping $IFACE, used for NFS from $nfsip
> +  exit 1
> +fi
> diff --git a/package/skeleton/skeleton.mk b/package/skeleton/skeleton.mk
> index d1b797d..059a0b9 100644
> --- a/package/skeleton/skeleton.mk
> +++ b/package/skeleton/skeleton.mk
> @@ -33,6 +33,12 @@ define SKELETON_USR_SYMLINKS_OR_DIRS
>  endef
>  endif
>  
> +ifeq ($(BR2_SYSTEM_IFUP_NFS_ROOT),y)
> +define SKELETON_INSTALL_NFS_CHECK
> +	$(INSTALL) -m 0755 -D package/skeleton/nfs_check $(TARGET_DIR)/etc/network/if-pre-up.d/nfs_check

 Please use $(SKELETON_PKGDIR) instead of package/skeleton in new code, and also
split this long line.

> +endef
> +endif
> +
>  define SKELETON_INSTALL_TARGET_CMDS
>  	rsync -a --ignore-times $(SYNC_VCS_EXCLUSIONS) \
>  		--chmod=u=rwX,go=rX --exclude .empty --exclude '*~' \
> @@ -98,6 +104,7 @@ define SET_NETWORK
>  	mkdir -p $(TARGET_DIR)/etc/network/
>  	$(SET_NETWORK_LOCALHOST)
>  	$(SET_NETWORK_DHCP)
> +	$(SKELETON_INSTALL_NFS_CHECK)
>  endef
>  
>  TARGET_FINALIZE_HOOKS += SET_NETWORK
> diff --git a/system/Config.in b/system/Config.in
> index 4d07010..cd0bbf7 100644
> --- a/system/Config.in
> +++ b/system/Config.in
> @@ -358,6 +358,25 @@ config BR2_SYSTEM_DHCP
>  	  For more complicated network setups use an overlay to overwrite
>  	  /etc/network/interfaces or add a networkd configuration file.
>  
> +config BR2_SYSTEM_IFUP_NFS_ROOT

 I wonder if it is useful to have this optional. The overhead of running this
extra script is minimal, and we know for sure that NFS-root will not boot
without it. So I'd always install it if BR2_SYSTEM_DHCP. And people who don't
want it can still get rid of it in an overlay.

 That said, we can always remove this option later.

 Great help text BTW.


 Regards,
 Arnout

> +	bool "Have network interface configuration cope with NFS root boot"
> +	default y
> +	depends on BR2_SYSTEM_DHCP != ""
> +	help
> +	  This allows NFS booting to work while also enabling the
> +	  option to configure the network interface via DHCP.
> +	  Otherwise, a NFS booted system will likely hang during DHCP
> +	  configuration.
> +
> +	  Attempting to configure the network interface used for NFS
> +	  will initially bring that network down.  Since the root
> +	  filesystem is accessed over this network, the system hangs.
> +
> +	  This option will add a script to the ifup system that will
> +	  attempt to detect if a NFS root mount uses the interface to
> +	  be configured, and if so does not configure it.  This should
> +	  allow the same build to be disk/flash booted or NFS booted.
> +
>  comment "automatic network configuration via DHCP is not compatible with networkd"
>  	depends on BR2_PACKAGE_SYSTEMD_NETWORKD
>  
>
Trent Piepho Nov. 7, 2015, 1:44 a.m. UTC | #2
On Sat, 2015-11-07 at 01:55 +0100, Arnout Vandecappelle wrote:

> > Example when the interface is used for NFS:
> > # ifup eth0
> > Skipping eth0, used for NFS from 192.168.1.123
> > run-parts: /etc/network/if-pre-up.d/nfs_check: exit status 1
> > 
> > Example when the interface isn't used for NFS:
> > # ifup eth1
> > [brings interface up]
> > 
> > An alternative to putting the script in if-pre-up.d would be to add
> > pre-up lines to the interfaces file.  This would allow running the
> > script just for certain interfaces.  It also removes the "run-parts"
> > message to do it this way.
> 
>  But I think ifup would still report an error, no?
Not really, error exit status but no message:

# ifup eth0 ; echo $?
Skipping eth0, used for NFS from 192.168.1.123
1

The skipping message is from my script.

> > +
> > +nfsip=`awk '$3=="nfs" && $2=="/"{ sub(/:.*/,"",$1); print $1; }' /proc/mounts`
> 
>  sed is generally better-known so we prefer it if possible. Like
> 
> sed -n '/^\([0-9.]*\):[^ ]* \/ nfs .*/s//\1/p' /proc/mounts

Ok, that's simpler too.

> 
> 
>  However, why don't we just check if the interface is already up? Like
> ip link show $IFACE | cut -d ' ' -f 3 | grep -q UP

It's currently ok to call ifup on an interface that's already up.  It
will reconfigure it.  The interface, while up, might not have been
assigned an ip.

It wouldn't be tied to NFS at that point either.


>  I wonder if it is useful to have this optional. The overhead of running this
> extra script is minimal, and we know for sure that NFS-root will not boot
> without it. So I'd always install it if BR2_SYSTEM_DHCP. And people who don't
> want it can still get rid of it in an overlay.

I didn't think that being option was that useful either.  But it's
possible for NFS root to work without having this, if the NFS interface
is not the same one that is being configured with DHCP.
Thomas Petazzoni Nov. 8, 2015, 1:57 p.m. UTC | #3
Dear Trent Piepho,

Thanks for working on this issue and proposing a solution for it!

On Fri, 6 Nov 2015 20:25:56 +0000, Trent Piepho wrote:
> Configuring the network interface with DHCP via
> /etc/network/interfaces generally does work when NFS booting.  The

Isn't there a missing "not" in this sentence ?

> diff --git a/package/skeleton/nfs_check b/package/skeleton/nfs_check
> new file mode 100755
> index 0000000..1914404
> --- /dev/null
> +++ b/package/skeleton/nfs_check

I think this should be in the initscripts package, not the skeleton
package. The initscripts package is the one that installs S40network,
which is the initscript calling ifup.

However, it's true that the skeleton package is currently the one that
generates the 'interfaces' file. Does that make sense? Is systemd using
the interfaces file at all?

> @@ -0,0 +1,7 @@
> +#!/bin/sh
> +
> +nfsip=`awk '$3=="nfs" && $2=="/"{ sub(/:.*/,"",$1); print $1; }' /proc/mounts`
> +if [ -n "$nfsip" ] && ip route get to "$nfsip" | grep -q "dev $IFACE"; then
> +  echo Skipping $IFACE, used for NFS from $nfsip
> +  exit 1

I think we generally use tabs for indentation in shell scripts.

> +config BR2_SYSTEM_IFUP_NFS_ROOT
> +	bool "Have network interface configuration cope with NFS root boot"
> +	default y
> +	depends on BR2_SYSTEM_DHCP != ""
> +	help
> +	  This allows NFS booting to work while also enabling the
> +	  option to configure the network interface via DHCP.
> +	  Otherwise, a NFS booted system will likely hang during DHCP
> +	  configuration.
> +
> +	  Attempting to configure the network interface used for NFS
> +	  will initially bring that network down.  Since the root
> +	  filesystem is accessed over this network, the system hangs.
> +
> +	  This option will add a script to the ifup system that will
> +	  attempt to detect if a NFS root mount uses the interface to
> +	  be configured, and if so does not configure it.  This should
> +	  allow the same build to be disk/flash booted or NFS booted.

Like Arnout said, I'm not sure this option is really needed. Just
always install this script when DHCP is used. You can put this text as
a big comment at the beginning of the nfs-check script, or inside
the .mk file above the command that installs this script to TARGET_DIR.

Best regards,

Thomas
Arnout Vandecappelle Nov. 8, 2015, 11:44 p.m. UTC | #4
On 07-11-15 02:44, Trent Piepho wrote:
> On Sat, 2015-11-07 at 01:55 +0100, Arnout Vandecappelle wrote:
> 
>>> Example when the interface is used for NFS:
>>> # ifup eth0
>>> Skipping eth0, used for NFS from 192.168.1.123
>>> run-parts: /etc/network/if-pre-up.d/nfs_check: exit status 1
>>>
>>> Example when the interface isn't used for NFS:
>>> # ifup eth1
>>> [brings interface up]
>>>
>>> An alternative to putting the script in if-pre-up.d would be to add
>>> pre-up lines to the interfaces file.  This would allow running the
>>> script just for certain interfaces.  It also removes the "run-parts"
>>> message to do it this way.
>>
>>  But I think ifup would still report an error, no?
> Not really, error exit status but no message:
> 
> # ifup eth0 ; echo $?
> Skipping eth0, used for NFS from 192.168.1.123
> 1
> 
> The skipping message is from my script.

 In that case, a pre-up line seems better to me.


>>> +
>>> +nfsip=`awk '$3=="nfs" && $2=="/"{ sub(/:.*/,"",$1); print $1; }' /proc/mounts`
>>
>>  sed is generally better-known so we prefer it if possible. Like
>>
>> sed -n '/^\([0-9.]*\):[^ ]* \/ nfs .*/s//\1/p' /proc/mounts
> 
> Ok, that's simpler too.
> 
>>
>>
>>  However, why don't we just check if the interface is already up? Like
>> ip link show $IFACE | cut -d ' ' -f 3 | grep -q UP
> 
> It's currently ok to call ifup on an interface that's already up.  It
> will reconfigure it.  The interface, while up, might not have been
> assigned an ip.
> 
> It wouldn't be tied to NFS at that point either.

 Right, so your approach is better then.

 BTW are we sure that /proc/mounts contains the IP address and not the host name?


 Regards,
 Arnout


>>  I wonder if it is useful to have this optional. The overhead of running this
>> extra script is minimal, and we know for sure that NFS-root will not boot
>> without it. So I'd always install it if BR2_SYSTEM_DHCP. And people who don't
>> want it can still get rid of it in an overlay.
> 
> I didn't think that being option was that useful either.  But it's
> possible for NFS root to work without having this, if the NFS interface
> is not the same one that is being configured with DHCP.
>
Trent Piepho Nov. 9, 2015, 8:37 p.m. UTC | #5
On Sun, 2015-11-08 at 14:57 +0100, Thomas Petazzoni wrote:
> Dear Trent Piepho,
> 
> Thanks for working on this issue and proposing a solution for it!
> 
> On Fri, 6 Nov 2015 20:25:56 +0000, Trent Piepho wrote:
> > Configuring the network interface with DHCP via
> > /etc/network/interfaces generally does work when NFS booting.  The
> 
> Isn't there a missing "not" in this sentence ?

yes

> 
> > diff --git a/package/skeleton/nfs_check b/package/skeleton/nfs_check
> > new file mode 100755
> > index 0000000..1914404
> > --- /dev/null
> > +++ b/package/skeleton/nfs_check
> 
> I think this should be in the initscripts package, not the skeleton
> package. The initscripts package is the one that installs S40network,
> which is the initscript calling ifup.
> 
> However, it's true that the skeleton package is currently the one that
> generates the 'interfaces' file. Does that make sense? Is systemd using
> the interfaces file at all?

It seems like since the script was optional, and the option to control
it was part of skeleton, that it should be there too.  But if it's not
optional, then I suppose it could go into initscripts.  The
autogenerated interfaces file in the skeleton package would need to add
the pre-up line.

I haven't looked into systemd yet so I can't saw how that works.  I
don't see any code in skeleton to generate a different configuration for
systemd, so I guess either it uses that file or it doesn't work.

> 
> > @@ -0,0 +1,7 @@
> > +#!/bin/sh
> > +
> > +nfsip=`awk '$3=="nfs" && $2=="/"{ sub(/:.*/,"",$1); print $1; }' /proc/mounts`
> > +if [ -n "$nfsip" ] && ip route get to "$nfsip" | grep -q "dev $IFACE"; then
> > +  echo Skipping $IFACE, used for NFS from $nfsip
> > +  exit 1
> 
> I think we generally use tabs for indentation in shell scripts.
> 
> > +config BR2_SYSTEM_IFUP_NFS_ROOT
> > +	bool "Have network interface configuration cope with NFS root boot"
> > +	default y
> > +	depends on BR2_SYSTEM_DHCP != ""
> > +	help
> > +	  This allows NFS booting to work while also enabling the
> > +	  option to configure the network interface via DHCP.
> > +	  Otherwise, a NFS booted system will likely hang during DHCP
> > +	  configuration.
> > +
> > +	  Attempting to configure the network interface used for NFS
> > +	  will initially bring that network down.  Since the root
> > +	  filesystem is accessed over this network, the system hangs.
> > +
> > +	  This option will add a script to the ifup system that will
> > +	  attempt to detect if a NFS root mount uses the interface to
> > +	  be configured, and if so does not configure it.  This should
> > +	  allow the same build to be disk/flash booted or NFS booted.
> 
> Like Arnout said, I'm not sure this option is really needed. Just
> always install this script when DHCP is used. You can put this text as

If the script is only installed when DHCP is used, then wouldn't it make
sense to put it in skeleton since the other code that depends on
BR2_SYSTEM_DHCP is there.

> a big comment at the beginning of the nfs-check script, or inside
> the .mk file above the command that installs this script to TARGET_DIR.
> 
> Best regards,
> 
> Thomas
Trent Piepho Nov. 9, 2015, 9:29 p.m. UTC | #6
On Mon, 2015-11-09 at 00:44 +0100, Arnout Vandecappelle wrote:
> >>
> >>  However, why don't we just check if the interface is already up? Like
> >> ip link show $IFACE | cut -d ' ' -f 3 | grep -q UP
> > 
> > It's currently ok to call ifup on an interface that's already up.  It
> > will reconfigure it.  The interface, while up, might not have been
> > assigned an ip.
> > 
> > It wouldn't be tied to NFS at that point either.
> 
>  Right, so your approach is better then.
> 
>  BTW are we sure that /proc/mounts contains the IP address and not the host name?

I believe the nfsroot mount option only allows IP addresses and not
hostnames.  Since the kernel would have to do the DNS lookup.  And the
kernel docs say "<server-ip>", which seems to imply only an IP will
work.  It didn't work when I tried it.  And the busybox mount command
appears to only accept an IP ("mount: bad address 'hostname'").

But the util linux mount does accept a hostname and it does show up
in /proc/mounts as a hostname.

So you can get a hostname, but I don't think it's possible in a NFS root
case.  The mount options also in /proc/mounts will have addr=<ip>, which
is a way to get the numeric ip even if the hostname is present.  It does
make the sed parsing harder to get the value from there.
diff mbox

Patch

diff --git a/package/skeleton/nfs_check b/package/skeleton/nfs_check
new file mode 100755
index 0000000..1914404
--- /dev/null
+++ b/package/skeleton/nfs_check
@@ -0,0 +1,7 @@ 
+#!/bin/sh
+
+nfsip=`awk '$3=="nfs" && $2=="/"{ sub(/:.*/,"",$1); print $1; }' /proc/mounts`
+if [ -n "$nfsip" ] && ip route get to "$nfsip" | grep -q "dev $IFACE"; then
+  echo Skipping $IFACE, used for NFS from $nfsip
+  exit 1
+fi
diff --git a/package/skeleton/skeleton.mk b/package/skeleton/skeleton.mk
index d1b797d..059a0b9 100644
--- a/package/skeleton/skeleton.mk
+++ b/package/skeleton/skeleton.mk
@@ -33,6 +33,12 @@  define SKELETON_USR_SYMLINKS_OR_DIRS
 endef
 endif
 
+ifeq ($(BR2_SYSTEM_IFUP_NFS_ROOT),y)
+define SKELETON_INSTALL_NFS_CHECK
+	$(INSTALL) -m 0755 -D package/skeleton/nfs_check $(TARGET_DIR)/etc/network/if-pre-up.d/nfs_check
+endef
+endif
+
 define SKELETON_INSTALL_TARGET_CMDS
 	rsync -a --ignore-times $(SYNC_VCS_EXCLUSIONS) \
 		--chmod=u=rwX,go=rX --exclude .empty --exclude '*~' \
@@ -98,6 +104,7 @@  define SET_NETWORK
 	mkdir -p $(TARGET_DIR)/etc/network/
 	$(SET_NETWORK_LOCALHOST)
 	$(SET_NETWORK_DHCP)
+	$(SKELETON_INSTALL_NFS_CHECK)
 endef
 
 TARGET_FINALIZE_HOOKS += SET_NETWORK
diff --git a/system/Config.in b/system/Config.in
index 4d07010..cd0bbf7 100644
--- a/system/Config.in
+++ b/system/Config.in
@@ -358,6 +358,25 @@  config BR2_SYSTEM_DHCP
 	  For more complicated network setups use an overlay to overwrite
 	  /etc/network/interfaces or add a networkd configuration file.
 
+config BR2_SYSTEM_IFUP_NFS_ROOT
+	bool "Have network interface configuration cope with NFS root boot"
+	default y
+	depends on BR2_SYSTEM_DHCP != ""
+	help
+	  This allows NFS booting to work while also enabling the
+	  option to configure the network interface via DHCP.
+	  Otherwise, a NFS booted system will likely hang during DHCP
+	  configuration.
+
+	  Attempting to configure the network interface used for NFS
+	  will initially bring that network down.  Since the root
+	  filesystem is accessed over this network, the system hangs.
+
+	  This option will add a script to the ifup system that will
+	  attempt to detect if a NFS root mount uses the interface to
+	  be configured, and if so does not configure it.  This should
+	  allow the same build to be disk/flash booted or NFS booted.
+
 comment "automatic network configuration via DHCP is not compatible with networkd"
 	depends on BR2_PACKAGE_SYSTEMD_NETWORKD