public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
From: Stefano Brivio <sbrivio@redhat.com>
To: Anshu Kumari <anskuma@redhat.com>
Cc: passt-dev@passt.top, lvivier@redhat.com
Subject: Re: [PATCH v7 6/7] dhcp: Add option overload
Date: Thu, 08 Oct 2026 00:06:34 +0200 (CEST)	[thread overview]
Message-ID: <20261008000633.6300886e@elisabeth> (raw)
In-Reply-To: <20261001131602.653553-7-anskuma@redhat.com>

On Thu,  1 Oct 2026 18:45:59 +0530
Anshu Kumari <anskuma@redhat.com> wrote:

> When the options field is full, overflow remaining DHCP options into
> the sname and file fields per RFC 2132 option 52.
> 
> Per RFC 2132, Section 9.5, the boot file name is always placed in the
> 'file' header field.  When a boot file is set, the file field is
> reserved from overload and overflow uses only the sname field.
> 
> Link: https://bugs.passt.top/show_bug.cgi?id=192
> Signed-off-by: Anshu Kumari <anskuma@redhat.com>
> ---
> 
> v7:
>   - Removed overload function parameter
>   - Added foreach_opt() macro to iterate option table
> 
> Till v6 both "patch 5/7" and "patch 6/7" were one.
> ---
>  dhcp.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++--------
>  1 file changed, 68 insertions(+), 10 deletions(-)
> 
> diff --git a/dhcp.c b/dhcp.c
> index 6f69fd62..63ac8e3d 100644
> --- a/dhcp.c
> +++ b/dhcp.c
> @@ -67,6 +67,8 @@ struct opt {
>  
>  static struct opt opts[256];
>  
> +#define foreach_opt(o)	for ((o) = 0; (size_t)(o) < ARRAY_SIZE(opts); (o)++)
> +
>  #define DHCPDISCOVER	1
>  #define DHCPOFFER	2
>  #define DHCPREQUEST	3
> @@ -440,13 +442,30 @@ static void fill_one(uint8_t *buf, size_t size, int o, int *offset)
>  }
>  
>  /**
> - * fill() - Fill options in message
> - * @m:		Message to fill
> + * enum dhcp_overload - DHCP option overload values (RFC 2132, Section 9.3)
> + * @DHCP_OVERLOAD_NONE:		No overload
> + * @DHCP_OVERLOAD_FILE:		file field carries options
> + * @DHCP_OVERLOAD_SNAME:	sname field carries options
> + */
> +enum dhcp_overload {
> +	DHCP_OVERLOAD_NONE  = 0,
> +	DHCP_OVERLOAD_FILE  = 1,
> +	DHCP_OVERLOAD_SNAME = 2,
> +};
> +
> +/**
> + * fill() - Fill options in message, with overload into file/sname if needed
> + * @m:			Message to fill
> + * @has_bootfile:	Reserve file field for boot file name
>   *
>   * Return: current size of options field
>   */
> -static int fill(struct msg *m)
> +static int fill(struct msg *m, bool has_bootfile)
>  {
> +	enum dhcp_overload overload = DHCP_OVERLOAD_NONE;
> +	int sname_off = 0, file_off = 0;
> +	/* Reserve 3 bytes for option 52 (overload) if needed */
> +	size_t size = OPT_MAX - 3;
>  	int i, o, offset = 0;
>  
>  	for (o = 0; o < 255; o++)
> @@ -457,17 +476,54 @@ static int fill(struct msg *m)
>  	 * Put it there explicitly, unless requested via option 55.
>  	 */
>  	if (opts[55].clen > 0 && !memchr(opts[55].c, 53, opts[55].clen))
> -		fill_one(m->o, OPT_MAX, 53, &offset);
> +		fill_one(m->o, size, 53, &offset);
>  
>  	for (i = 0; i < opts[55].clen; i++) {
>  		o = opts[55].c[i];
>  		if (opts[o].conf != OPT_UNSET)
> -			fill_one(m->o, OPT_MAX, o, &offset);
> +			fill_one(m->o, size, o, &offset);
>  	}
>  
>  	for (o = 0; o < 255; o++) {
>  		if (opts[o].conf != OPT_UNSET && !opts[o].sent)
> -			fill_one(m->o, OPT_MAX, o, &offset);
> +			fill_one(m->o, size, o, &offset);
> +	}
> +
> +	/* Overflow unsent options into sname, then file */
> +	foreach_opt(o) {

This comes from my suggestion on v6 but those were really subsequent
steps (building a more specialised iterator on top of foreach_opt()),
not alternatives. Look at flow_foreach() and flow_foreach_of_type()
as examples. That is, here you could use:

	foreach_unsent_opt(o)
		fill_one(m->sname, sizeof(m->sname) - 1, o, &sname_off);

with:

#define foreach_unset_opt(o)						     \
	foreach_opt((o))						     \
		/* NOLINTNEXTLINE(readability-inconsistent-ifelse-braces) */ \
		if (opts[(o)].conf != OPT_UNSET && !opts[(o)].sent)

...the option with the reverse condition and "continue; else" could also
work, I'm not sure what's the most practical here. The direct option
looks more... direct, to me.

The two loops below could use this iterator, and perhaps the one above
as well (I haven't tried).

Note that in 7/7 you could probably switch to this other iterator as
well, without the explicit need for the base foreach_opt(o) iterator,
but I would suggest to keep them as two different macros anyway, it's
clearer and more reusable.

> +		if (opts[o].conf == OPT_UNSET || opts[o].sent)
> +			continue;
> +		fill_one(m->sname, sizeof(m->sname) - 1, o, &sname_off);
> +	}
> +
> +	if (!has_bootfile) {
> +		foreach_opt(o) {
> +			if (opts[o].conf == OPT_UNSET || opts[o].sent)
> +				continue;
> +			fill_one(m->file, sizeof(m->file) - 1, o, &file_off);
> +		}
> +	}
> +
> +	/* Report any options that could not be sent */
> +	foreach_opt(o) {
> +		if (opts[o].conf != OPT_UNSET && !opts[o].sent)
> +			debug("DHCP: skipping option %i", o);
> +	}
> +
> +	if (sname_off) {
> +		m->sname[sname_off] = 255;
> +		overload |= DHCP_OVERLOAD_SNAME;
> +	}
> +
> +	if (file_off) {
> +		m->file[file_off] = 255;
> +		overload |= DHCP_OVERLOAD_FILE;
> +	}
> +
> +	if (overload) {
> +		m->o[offset++] = 52;
> +		m->o[offset++] = 1;
> +		m->o[offset++] = overload;
>  	}
>  
>  	m->o[offset++] = 255;
> @@ -761,16 +817,18 @@ int dhcp(const struct ctx *c, struct iov_tail *data)
>  		}
>  	}
>  
> -	if (!c->no_dhcp_dns_search)
> -		opt_set_dns_search(c, sizeof(m->o));
> +	if (!c->no_dhcp_dns_search) {
> +		/* 3 bytes reserved for option 52 (code, length, value) */
> +		opt_set_dns_search(c, OPT_MAX - 3);
> +	}
>  
>  	/* RFC 2132, Section 9.5: put boot file name in the 'file' header
> -	 * field.
> +	 * field.  Reserve the file field from overload.
>  	 */
>  	has_bootfile = opts[67].slen > 0 &&
>  		       (size_t)opts[67].slen < sizeof(reply.file);
>  
> -	dlen = offsetof(struct msg, o) + fill(&reply);
> +	dlen = offsetof(struct msg, o) + fill(&reply, has_bootfile);
>  
>  	if (has_bootfile)
>  		memcpy(reply.file, opts[67].s, opts[67].slen);

-- 
Stefano


  reply	other threads:[~2026-10-07 22:06 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-01 13:15 [PATCH v7 0/7] Add --dhcp-boot and --dhcp-opt options Anshu Kumari
2026-10-01 13:15 ` [PATCH v7 1/7] dhcp: Refactor fill_one() to operate on a generic buffer Anshu Kumari
2026-10-01 13:15 ` [PATCH v7 2/7] dhcp: Add option configuration tracking with enum opt_conf Anshu Kumari
2026-10-07 22:06   ` Stefano Brivio
2026-10-01 13:15 ` [PATCH v7 3/7] dhcp: Add --dhcp-opt with option table and value parser Anshu Kumari
2026-10-07 22:06   ` Stefano Brivio
2026-10-01 13:15 ` [PATCH v7 4/7] dhcp: Add --dhcp-boot command-line option Anshu Kumari
2026-10-07 22:06   ` Stefano Brivio
2026-10-01 13:15 ` [PATCH v7 5/7] dhcp: Change fill_one() to return void Anshu Kumari
2026-10-07 22:06   ` Stefano Brivio
2026-10-01 13:15 ` [PATCH v7 6/7] dhcp: Add option overload Anshu Kumari
2026-10-07 22:06   ` Stefano Brivio [this message]
2026-10-01 13:16 ` [PATCH v7 7/7] dhcp: Add RFC 3396 option splitting for concatenation-requiring options Anshu Kumari
2026-10-07 22:06   ` Stefano Brivio
2026-10-07 22:06 ` [PATCH v7 0/7] Add --dhcp-boot and --dhcp-opt options Stefano Brivio

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261008000633.6300886e@elisabeth \
    --to=sbrivio@redhat.com \
    --cc=anskuma@redhat.com \
    --cc=lvivier@redhat.com \
    --cc=passt-dev@passt.top \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://passt.top/passt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for IMAP folder(s).