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 <hjen...@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.ro...@gmail.com _______________________________________________ Dnsmasq-discuss mailing list Dnsmasq-discuss@lists.thekelleys.org.uk http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss