Discussion:
systemd/hostnamed: setting the hostname and using it in the DHCP Discover
(too old to reply)
Lennart Poettering
2017-07-31 14:24:27 UTC
Permalink
Raw Message
I have an embedded target where the hostname is expected to be a
string derived in part from the MAC address of an Ethernet interface.
I've been looking at how to properly set the system's hostname and
also have systemd-networkd use it in the DHCP request it sends out,
however there seems to be an order of operations issue.
1. in systemd/core/main.c the /etc/hostname contents are unconditionally read
2. I can add a service that uses the special network-pre.target to
override /etc/hostname with my generated string and I see that while
the initial string is pickedup by systemd, the new hostname will in
fact be used
3. I then have a .network file specifying DHCP on that Ethernet interface
But then on initial boot I see that the DHCP Discover coming out has
option 12 set to the original hostname that systemd picked up in
main.c, even though the network-pre.target caused my unit to run. I
can then reboot the system and this time main.c picks up the "new"
hostname and option 12 is indeed set to this.
One workaround I found was to have my unit write the Hostname= option
to the .network file but that seems like the wrong approach.
Is there a correct way to replace or otherwise set the hostname and
have systemd use it from the beginning and ensure that the DHCP client
specifies it in option 12?
Hmm, I am not sure I follow. Do you want the hostname to be "sticky"?
i.e. if you boot up once, and your special hostname is not initialized
yet, you initialize from whatever the MAC address is, and then store
it to /etc/hostname, and from that point on and for all future boots
it's supposed to stay fixed? Or do you want it to be fully
dynamic: as soon as an ethernet device shows up, set the hostname,
and when no device has shown up the hostname should remain
uninitialized, and on subsequent boot everything starts from fresh,
with no previous data?

Under the assumption you want the latter: just drop /etc/hostname, so
that no static hostname is managed by systemd/hostnamed. In this case
the system will boot up with the fallback hostname (which is
"localhost" unless your distro overrides that at compile time). Then,
add a udev rule that is run when an interface shows up, and that
changes the hostname as necessary, maybe by invoking the
/usr/bin/hostname binary.

The DHCP client in networkd will query the hostname the instant it
starts setting up the DHCP session. It will use whatever is set at
that point in time. Hence, if you set the hostname from the udev rule
things should be properly race-free as networkd will only take
possession of any interface after the udev rule ran, and hence will
necessarily initialize its DHCP client at a point in time the hostname
is set to what you want it to be set to.

Lennart
--
Lennart Poettering, Red Hat
J Decker
2017-07-31 16:27:39 UTC
Permalink
Raw Message
On Mon, Jul 31, 2017 at 7:24 AM, Lennart Poettering
Post by Lennart Poettering
I have an embedded target where the hostname is expected to be a
string derived in part from the MAC address of an Ethernet interface.
I've been looking at how to properly set the system's hostname and
also have systemd-networkd use it in the DHCP request it sends out,
however there seems to be an order of operations issue.
1. in systemd/core/main.c the /etc/hostname contents are
unconditionally read
Post by Lennart Poettering
2. I can add a service that uses the special network-pre.target to
override /etc/hostname with my generated string and I see that while
the initial string is pickedup by systemd, the new hostname will in
fact be used
3. I then have a .network file specifying DHCP on that Ethernet
interface
Post by Lennart Poettering
But then on initial boot I see that the DHCP Discover coming out has
option 12 set to the original hostname that systemd picked up in
main.c, even though the network-pre.target caused my unit to run. I
can then reboot the system and this time main.c picks up the "new"
hostname and option 12 is indeed set to this.
One workaround I found was to have my unit write the Hostname= option
to the .network file but that seems like the wrong approach.
Is there a correct way to replace or otherwise set the hostname and
have systemd use it from the beginning and ensure that the DHCP client
specifies it in option 12?
Hmm, I am not sure I follow. Do you want the hostname to be "sticky"?
i.e. if you boot up once, and your special hostname is not initialized
yet, you initialize from whatever the MAC address is, and then store
it to /etc/hostname, and from that point on and for all future boots
it's supposed to stay fixed? Or do you want it to be fully
dynamic: as soon as an ethernet device shows up, set the hostname,
and when no device has shown up the hostname should remain
uninitialized, and on subsequent boot everything starts from fresh,
with no previous data?
Sorry, what I mean is the hostname is "sticky" but is always the same
(there's just the one built-in Ethernet interface, nothing is
dynamic), the trick is I always want that generated hostname used and
I never want to see a DHCP Discover go out with a default hostname
that isn't this generated string (it's a bit off but is meant to
maintain expected behavior from this device).
There's an option under [dhcp] section
https://www.freedesktop.org/software/systemd/man/systemd.network.html

SendHostname=
When true (the default), the machine's hostname will be sent to the DHCP
server.

UseHostname=
When true (the default), the hostname received from the DHCP server will be
set as the transient hostname of the system

Hostname=
Use this value for the hostname which is sent to the DHCP server, instead
of machine's hostname.


would think if you set your name there it won't matter what /etc/hostname
is?
Post by Lennart Poettering
Under the assumption you want the latter: just drop /etc/hostname, so
that no static hostname is managed by systemd/hostnamed. In this case
the system will boot up with the fallback hostname (which is
"localhost" unless your distro overrides that at compile time). Then,
add a udev rule that is run when an interface shows up, and that
changes the hostname as necessary, maybe by invoking the
/usr/bin/hostname binary.
I didn't think of that, thank you! That makes a lot of sense.
Post by Lennart Poettering
The DHCP client in networkd will query the hostname the instant it
starts setting up the DHCP session. It will use whatever is set at
that point in time. Hence, if you set the hostname from the udev rule
things should be properly race-free as networkd will only take
possession of any interface after the udev rule ran, and hence will
necessarily initialize its DHCP client at a point in time the hostname
is set to what you want it to be set to.
Got it. Thank you for taking the time to answer my weird question, I
really appreciate it.
_______________________________________________
systemd-devel mailing list
https://lists.freedesktop.org/mailman/listinfo/systemd-devel
Andrey Yurovsky
2017-07-31 16:32:50 UTC
Permalink
Raw Message
Post by J Decker
There's an option under [dhcp] section
https://www.freedesktop.org/software/systemd/man/systemd.network.html
SendHostname=
When true (the default), the machine's hostname will be sent to the DHCP
server.
UseHostname=
When true (the default), the hostname received from the DHCP server will be
set as the transient hostname of the system
Hostname=
Use this value for the hostname which is sent to the DHCP server, instead of
machine's hostname.
would think if you set your name there it won't matter what /etc/hostname
is?
Yeah, that's the workaround I'm currently using and it does work (set
the desired string in Hostname=, leave the rest as defaults), however
what Lennart suggested is more thorough as the actual hostname will be
set to what I need and I won't be swapping or editing my .network
files. In my case the hostname is partially based on the MAC of this
fixed Ethernet interface so it's a safe bet to use udev to trigger
settings things up.
Andrey Yurovsky
2017-07-29 15:36:37 UTC
Permalink
Raw Message
However I see the DHCP client use the original hostname the first time
my target boots (I captured traffic and checked the DHCP Discover
contents). When I reboot the newly-booted system, /etc/hostname is
already updated so everything looks right on the wire. It feels like
systemd-networkd is using the hostname that was read at systemd init
(in main.c) rather than checking what it's set to, but that's just
speculation (I need to dig in further).
In that case, could you try setting it via `hostnamectl` instead?
I've tried that but hostnamectl wants to talk to systemd1 and
hostnamed so I either try invoking it too early and communication
fails or too late and hostnamectl succeeds but the original hostname
is still used in the DHCP Discover.

The documentation for hostnamectl instructs me to use
systemd-firstboot to initialize the hostname but at this time that
facility isn't a good fit for my system so I'm hoping there's some
reasonable way to do this on startup. It's very likely that I'm
missing something obvious here but I don't yet understand the sequence
of events between systemd initializing and reading /etc/hostname, my
own call to hostname(2) via the shell, hostnamed actually starting,
and what systemd-networkd chooses to put in the Hostname field of the
DHCP DIscover packet.

Loading...