[Dnsmasq-discuss] [PATCH] DHCPv6 - Multiple reservations for single host
Pali Rohár
pali.rohar at gmail.com
Tue Jan 7 09:51:02 GMT 2020
Hi Harald! What are differences between your patch and mine which adds
support for it too (plus honor assignment based on MAC address)?
http://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2019q4/013545.html
On Tuesday 07 January 2020 10:01:59 Harald Jensås wrote:
> Reposting this, as it seems my e-mail client mangled the patch by
> inserting line-breaks etc.
>
> On Mon, 2019-12-23 at 12:24 +0100, Harald Jensas wrote:
> > Hi,
> >
> > The patch below is a slight alteration to a possible solution
> > discussed in
> > http://lists.thekelleys.org.uk/pipermail/dnsmasq-discuss/2017q1/011289.html
> > .
> >
> > My approach here does not require making dhcp-host conditional on a
> > tag. However, making dhcp-host conditional on a tag would be a nice
> > addition that could be introduced as a follow up to this to have a
> > match on the tag of the final OS to keep the provisioned system
> > consistently configured with a specific address can be very handy.
> > For
> > the Openstack use-case I am working in, this however is'nt necessary.
> >
> > I have confirmed that the patch below together with a small change in
> > Openstack Ironic (see: https://review.opendev.org/700002) solved the
> > long standing issue when doing network booting and node provisioning
> > in combination with static only dhcp configuration.
> >
> > We are looking forward to comments and feedback regarding this
> > approach.
> >
> > Thank you!
> >
> > Regards
> > Harald Jensås
> >
>
> From 8b238dcf99dcf3332ec1c76fbb5af283db65a637 Mon Sep 17 00:00:00 2001
> From: Harald Jensås <hjensas at redhat.com>
> Date: Wed, 18 Dec 2019 23:59:11 +0100
> Subject: [PATCH] DHCPv6 - Multiple reservations for single host
>
> This change adds support for multiple dhcpv6 host
> reservations. The same clid or hwaddr can be used in
> multiple --dhcp-host entries.
>
> When receiving a request and a config containing an ip
> address is found, a test is done to see if the address is
> already leased to a different CLID/IAID. In case the ip
> address in the config was already used, skip_entry is
> incremented and find_config() is re-executed. find_config()
> will now skip the first config it finds, and continue
> looking for another config entry to return. This repeats
> until all possible config entries has been exhausted.
>
> Using multiple reservations for a single host makes it
> possible to maintain a static leases only configuration
> which support network booting systems with UEFI firmware
> that request a new address (a new SOLICIT with a new IA_NA
> option using a new IAID) for different boot modes, for
> instance 'PXE over IPv6', and HTTP-Boot over IPv6. Open
> Virtual Machine Firmware (OVMF) and most UEFI firmware
> build on the EDK2 code base exhibit this behaviour.
>
> RFC 8415 which updates RFC 3315 describes a single client
> request multiple IA's of any kind. These clients do this,
> using a new SOLICIT to request each IA. The clients could
> pack all IA's in one SOLICIT, but doing it individually as
> the above mentioned implementations do should not be a
> problem.
> ---
> src/dhcp-common.c | 19 ++++++++++++++++---
> src/dnsmasq.h | 3 ++-
> src/lease.c | 2 +-
> src/rfc2131.c | 6 +++---
> src/rfc3315.c | 29 +++++++++++++++++++++++------
> 5 files changed, 45 insertions(+), 14 deletions(-)
>
> diff --git a/src/dhcp-common.c b/src/dhcp-common.c
> index 602873e..5e770de 100644
> --- a/src/dhcp-common.c
> +++ b/src/dhcp-common.c
> @@ -299,7 +299,8 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
> struct dhcp_context *context,
> unsigned char *clid, int clid_len,
> unsigned char *hwaddr, int hw_len,
> - int hw_type, char *hostname)
> + int hw_type, char *hostname,
> + int skip_entries)
> {
> int count, new;
> struct dhcp_config *config, *candidate;
> @@ -312,15 +313,23 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
> if (config->clid_len == clid_len &&
> memcmp(config->clid, clid, clid_len) == 0 &&
> is_config_in_context(context, config))
> + {
> + if (--skip_entries > 0)
> + continue;
> return config;
> -
> + }
> +
> /* dhcpcd prefixes ASCII client IDs by zero which is wrong, but we try and
> cope with that here. This is IPv4 only. context==NULL implies IPv4,
> see lease_update_from_configs() */
> if ((!context || !(context->flags & CONTEXT_V6)) && *clid == 0 && config->clid_len == clid_len-1 &&
> memcmp(config->clid, clid+1, clid_len-1) == 0 &&
> is_config_in_context(context, config))
> + {
> + if (--skip_entries > 0)
> + continue;
> return config;
> + }
> }
>
>
> @@ -328,7 +337,11 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
> for (config = configs; config; config = config->next)
> if (config_has_mac(config, hwaddr, hw_len, hw_type) &&
> is_config_in_context(context, config))
> - return config;
> + {
> + if (--skip_entries > 0)
> + continue;
> + return config;
> + }
>
> if (hostname && context)
> for (config = configs; config; config = config->next)
> diff --git a/src/dnsmasq.h b/src/dnsmasq.h
> index 8e047fc..8760517 100644
> --- a/src/dnsmasq.h
> +++ b/src/dnsmasq.h
> @@ -1563,7 +1563,8 @@ struct dhcp_config *find_config(struct dhcp_config *configs,
> struct dhcp_context *context,
> unsigned char *clid, int clid_len,
> unsigned char *hwaddr, int hw_len,
> - int hw_type, char *hostname);
> + int hw_type, char *hostname,
> + int skip_entries);
> int config_has_mac(struct dhcp_config *config, unsigned char *hwaddr, int len, int type);
> #ifdef HAVE_LINUX_NETWORK
> char *whichdevice(void);
> diff --git a/src/lease.c b/src/lease.c
> index 081d90e..c34b90a 100644
> --- a/src/lease.c
> +++ b/src/lease.c
> @@ -230,7 +230,7 @@ void lease_update_from_configs(void)
> if (lease->flags & (LEASE_TA | LEASE_NA))
> continue;
> else if ((config = find_config(daemon->dhcp_conf, NULL, lease->clid, lease->clid_len,
> - lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL)) &&
> + lease->hwaddr, lease->hwaddr_len, lease->hwaddr_type, NULL, 0)) &&
> (config->flags & CONFIG_NAME) &&
> (!(config->flags & CONFIG_ADDR) || config->addr.s_addr == lease->addr.s_addr))
> lease_set_hostname(lease, config->hostname, 1, get_domain(lease->addr), NULL);
> diff --git a/src/rfc2131.c b/src/rfc2131.c
> index 033c5db..a7179c3 100644
> --- a/src/rfc2131.c
> +++ b/src/rfc2131.c
> @@ -504,7 +504,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
> mess->op = BOOTREPLY;
>
> config = find_config(daemon->dhcp_conf, context, clid, clid_len,
> - mess->chaddr, mess->hlen, mess->htype, NULL);
> + mess->chaddr, mess->hlen, mess->htype, NULL, 0);
>
> /* set "known" tag for known hosts */
> if (config)
> @@ -514,7 +514,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
> netid = &known_id;
> }
> else if (find_config(daemon->dhcp_conf, NULL, clid, clid_len,
> - mess->chaddr, mess->hlen, mess->htype, NULL))
> + mess->chaddr, mess->hlen, mess->htype, NULL, 0))
> {
> known_id.net = "known-othernet";
> known_id.next = netid;
> @@ -781,7 +781,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
> to avoid impersonation by name. */
> struct dhcp_config *new = find_config(daemon->dhcp_conf, context, NULL, 0,
> mess->chaddr, mess->hlen,
> - mess->htype, hostname);
> + mess->htype, hostname, 0);
> if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
> {
> config = new;
> diff --git a/src/rfc3315.c b/src/rfc3315.c
> index 2ef9073..97672b9 100644
> --- a/src/rfc3315.c
> +++ b/src/rfc3315.c
> @@ -535,10 +535,27 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
> }
> }
> }
> -
> - if (state->clid &&
> - (config = find_config(daemon->dhcp_conf, state->context, state->clid, state->clid_len, state->mac, state->mac_len, state->mac_type, NULL)) &&
> - have_config(config, CONFIG_NAME))
> +
> + if (state->clid)
> + {
> + /* Loop to find config that is not already used*/
> + int skip_entries = 0;
> + do {
> + config = find_config(daemon->dhcp_conf, state->context, state->clid,
> + state->clid_len, state->mac, state->mac_len,
> + state->mac_type, NULL, skip_entries);
> + /* Always use config with no address */
> + if (config && !&config->addr6)
> + break;
> + /* Check if address not leased to another CLID/IAID */
> + if (config && check_address(state, &config->addr6))
> + break;
> + /* Skip one more entry in the next find_config pass */
> + skip_entries++;
> + } while (config != NULL);
> + }
> +
> + if (state->clid && config && have_config(config, CONFIG_NAME))
> {
> state->hostname = config->hostname;
> state->domain = config->domain;
> @@ -557,7 +574,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
> /* Search again now we have a hostname.
> Only accept configs without CLID here, (it won't match)
> to avoid impersonation by name. */
> - struct dhcp_config *new = find_config(daemon->dhcp_conf, state->context, NULL, 0, NULL, 0, 0, state->hostname);
> + struct dhcp_config *new = find_config(daemon->dhcp_conf, state->context, NULL, 0, NULL, 0, 0, state->hostname, 0);
> if (new && !have_config(new, CONFIG_CLID) && !new->hwaddr)
> config = new;
> }
> @@ -583,7 +600,7 @@ static int dhcp6_no_relay(struct state *state, int msg_type, void *inbuff, size_
> ignore = 1;
> }
> else if (state->clid &&
> - find_config(daemon->dhcp_conf, NULL, state->clid, state->clid_len, state->mac, state->mac_len, state->mac_type, NULL))
> + find_config(daemon->dhcp_conf, NULL, state->clid, state->clid_len, state->mac, state->mac_len, state->mac_type, NULL, 0))
> {
> known_id.net = "known-othernet";
> known_id.next = state->tags;
--
Pali Rohár
pali.rohar at gmail.com
More information about the Dnsmasq-discuss
mailing list