On Thu, Nov 14, 2024 at 6:13 PM Stefano Brivio
<sbrivio(a)redhat.com> wrote:
On Thu, 14 Nov 2024 09:47:27 +0100
Enrique Llorente <ellorent(a)redhat.com> wrote:
Both DHCPv4 and DHCPv6 has the capability to pass
the hostname to
clients, the DHCPv4 uses option 12 (hostname) while the DHCPv6 uses option 39
(client fqdn), for some virt deployments like kubevirt is expected to
have the VirtualMachine name as the guest hostname.
This change add the -H --hostname to configure the DHCPv4 and DHCPv6
options to will send hostname to clients.
Signed-off-by: Enrique Llorente <ellorent(a)redhat.com>
---
conf.c | 13 ++++++++++---
dhcp.c | 8 +++++++-
dhcpv6.c | 44 +++++++++++++++++++++++++++++++++++++++++++-
passt.h | 2 ++
test/lib/setup | 10 +++++-----
test/passt.mbuto | 1 +
test/passt/dhcp | 11 ++++++++++-
7 files changed, 78 insertions(+), 11 deletions(-)
diff --git a/conf.c b/conf.c
index 14411b4..ddb585c 100644
--- a/conf.c
+++ b/conf.c
@@ -847,7 +847,8 @@ static void usage(const char *name, FILE *f, int status)
" --freebind Bind to any address for forwarding\n"
" --no-map-gw Don't map gateway address to
host\n"
" -4, --ipv4-only Enable IPv4 operation only\n"
- " -6, --ipv6-only Enable IPv6 operation only\n");
+ " -6, --ipv6-only Enable IPv6 operation only\n"
+ " -H, --hostname NAME Hostname to configure client with\n");
Use one tab instead of one space between "NAME" and "Hostname" so
that
the output (and the code itself) is aligned.
if (strstr(name, "pasta"))
goto pasta_opts;
@@ -1303,6 +1304,7 @@ void conf(struct ctx *c, int argc, char **argv)
{"map-guest-addr", required_argument, NULL, 22 },
{"host-lo-to-ns-lo", no_argument, NULL, 23 },
{"dns-host", required_argument, NULL, 24 },
+ {"hostname", required_argument, NULL,
'H' },
Maybe this could go a bit more up, just after the "dns" and "search"
options. Two reasons: we have all the options without a short version
at the end, and this logically belongs together with other name-related
stuff we send to the guest.
{ 0 },
};
const char *logname = (c->mode == MODE_PASTA) ? "pasta" :
"passt";
@@ -1325,9 +1327,9 @@ void conf(struct ctx *c, int argc, char **argv)
if (c->mode == MODE_PASTA) {
c->no_dhcp_dns = c->no_dhcp_dns_search = 1;
fwd_default = FWD_AUTO;
- optstring = "+dqfel:hF:I:p:P:m:a:n:M:g:i:o:D:S:46t:u:T:U:";
+ optstring = "+dqfel:hF:I:p:P:m:a:n:M:g:i:o:D:S:46t:u:T:U:H:";
Same here: maybe after S: it makes more sense.
} else {
- optstring = "+dqfel:hs:F:p:P:m:a:n:M:g:i:o:D:S:461t:u:";
+ optstring = "+dqfel:hs:F:p:P:m:a:n:M:g:i:o:D:S:461t:u:H:";
}
c->tcp.fwd_in.mode = c->tcp.fwd_out.mode = FWD_UNSET;
@@ -1680,6 +1682,11 @@ void conf(struct ctx *c, int argc, char **argv)
c->one_off = true;
break;
+ case 'H':
+ ret = snprintf(c->hostname.n, sizeof(c->hostname.n),
"%s", optarg);
We (generally) wrap lines at 80 columns where doable:
ret = snprintf(c->hostname.n, sizeof(c->hostname.n),
"%s", optarg);
+ if (ret <= 0 || ret
>= (int)sizeof(c->hostname.n))
+ die("Invalid hostname: %s", optarg);
+ break;
case 't':
case 'u':
case 'T':
diff --git a/dhcp.c b/dhcp.c
index a06f143..ec7e78a 100644
--- a/dhcp.c
+++ b/dhcp.c
@@ -275,7 +275,7 @@ static void opt_set_dns_search(const struct ctx *c, size_t max_len)
*/
int dhcp(const struct ctx *c, const struct pool *p)
{
- size_t mlen, dlen, offset = 0, opt_len, opt_off = 0;
+ size_t mlen, dlen, offset = 0, opt_len, opt_off = 0, hostname_len;
char macstr[ETH_ADDRSTRLEN];
const struct ethhdr *eh;
const struct iphdr *iph;
@@ -375,6 +375,12 @@ int dhcp(const struct ctx *c, const struct pool *p)
opts[6].slen += sizeof(uint32_t);
}
+ hostname_len = strlen(c->hostname.n);
+ if ( hostname_len > 0 ) {
No space around parentheses in expressions:
if (hostname_len > 0) {
+ opts[12].slen = hostname_len;
+ memcpy(opts[12].s, &c->hostname.n, hostname_len);
+ }
+
if (!c->no_dhcp_dns_search)
opt_set_dns_search(c, sizeof(m->o));
diff --git a/dhcpv6.c b/dhcpv6.c
index 14a5c7e..190dc0e 100644
--- a/dhcpv6.c
+++ b/dhcpv6.c
@@ -48,6 +48,7 @@ struct opt_hdr {
# define STATUS_NOTONLINK htons_constant(4)
# define OPT_DNS_SERVERS htons_constant(23)
# define OPT_DNS_SEARCH htons_constant(24)
+# define OPT_CLIENT_FQDN htons_constant(39)
One tab instead of spaces.
#define STR_NOTONLINK
"Prefix not appropriate for link."
uint16_t l;
@@ -163,6 +164,18 @@ struct opt_dns_search {
char list[MAXDNSRCH * NS_MAXDNAME];
} __attribute__((packed));
+/**
+ * struct opt_client_fqdn - Client FQDN option (RFC 4704)
+ * @hdr: Option header
+ * @flags: Flags as stated at RFC 4704
s/stated at/described by/
Maybe mention that we don't really use those ("always zero for us").
+ * @hostname: Client fqdn
A hostname is not necessarily a fully-qualified domain name. The RFC
calls this "domain name", so we could at least call this 'domain' in
the struct to make it clear we're referring to that.
As to what it should contain: RFC 4702 defines option 81 (FQDN) for
DHCP, which is equivalent to DHCPv6's option 39 (RFC 4704). Should we
just call this whole thing "FQDN" and switch to option 81 for DHCP
instead? Would this work for KubeVirt?
Or introduce two options: -H / --hostname (option 12, DHCP only), and
--fqdn (setting both DHCP option 81 and DHCPv6 option 39)?
Let me experiment with DHCPv4 option 81 with kubevirt machines, if it's enough
we use 81 instead of 12 and call it --fqdn.
If not we go with --fqdn and --hostname, but in this case it's not
clear to me what kubevirt/libvirt
has to pass though, also is this going to be expose at the domain xml
or libvirt will directly pass always
the vm name as one of them ? (for dual stack or single stack ipv4
hostname is enough, problem is single stack ipv6)