From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: passt.top; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: passt.top; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=hsYzWBhd; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by passt.top (Postfix) with ESMTPS id A26165A0265 for ; Thu, 28 May 2026 07:03:13 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779944592; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=u3c1rw1wa7HzzapHAufPwVefkMXRSGbks4iCeBAFesE=; b=hsYzWBhdZVkWDNiYweTfeS2KRrILDGrOFgNPle6ZfQl5MDCQXx1xBBWfdR5U4YNnLsxaUW g9s9dJCmHj+u5XN1KKLAEDPFvYaCc5l8fJMdjrTOLbZzuxeWHKbO2ELmvy8zSA3CcOCTC+ 5mqHCkI2dotqN8YFqNUG7f544UuD3r0= Received: from mail-lf1-f69.google.com (mail-lf1-f69.google.com [209.85.167.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-656-2-76m_SdOBm8He-5hzrY0w-1; Thu, 28 May 2026 01:03:09 -0400 X-MC-Unique: 2-76m_SdOBm8He-5hzrY0w-1 X-Mimecast-MFC-AGG-ID: 2-76m_SdOBm8He-5hzrY0w_1779944588 Received: by mail-lf1-f69.google.com with SMTP id 2adb3069b0e04-5a886da574eso8206736e87.0 for ; Wed, 27 May 2026 22:03:09 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779944588; x=1780549388; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=u3c1rw1wa7HzzapHAufPwVefkMXRSGbks4iCeBAFesE=; b=bT2ilpPFLAATkMn07RbGOwQGFDupPCIHEL5xBJGBJzWeidhXuFBBuEGMmRz62Otgi+ Lt0WZZlCBOLtAbFIGbPoshvhUOGJvcUta1HDGInzPQQd2jHul/L477Y3HEC4B1dFqmGo a0LZeikiowVjKuMuXz56o2vUiIMyKjLhGrLGyEw/20bKnzbY/O8IIPhAKKu1VEgiwS4+ eY62/D9M5WRmp6CTBxJX0yDs6pBEKUZiiIfPTdmgcukVLECBltdCkGmp32k7HklszCLU uoPWbuKQLQaUJSMK5v9A6Bvo7k8BzFXXtMn2moqDaFbP5QtqnJbiBcGVynEYsqEUoTDP PosQ== X-Gm-Message-State: AOJu0Yz8lwtu68ESRNdw1Snz2k/h1iMJtwLlIdmfLhTDCLdl8nwhWUMS MPAPDgdy3nW3fTN7IUsOVNNsn2UTvDLm/ZZpuzUGUUOHnZEzKQtQzjvTKmlh/QfI8Rl4EGuwUwf es9gNuogZ6ogyX0yU4dGpf+0uXhxGxsAHRyQ2xDifd5XIr/QP8q/Np0V/wbMq4MCJuqpqlQINWL besXBwvoTFDQgi09WQgIkUrO9wj99v X-Gm-Gg: Acq92OFCQFdFJWZp4U+WT1VpwthM/whdxZzNVggcVvfWjzzG5ABYgxA/RBMiJvzXpz0 T1QR9VcnzNv8AgBe955AzPPovI4iEtoSglzPcz5OW1uddwOz0I+AqGQqgeQwG6gLH5H80kWAiwa ruLJftQLUmhQ8LNmubTwPYwl92Ud8hsQIOjhnPwhU0zueV4O6V8IPTpLA3K/W8q6GxbwSQ2NG+Y uB8lJKN/E/hwv/Aqoj+YPa/ExRAuZhYdMJ8rxAnUmPxsTU2Lg== X-Received: by 2002:a05:6512:1094:b0:5a8:6799:efb1 with SMTP id 2adb3069b0e04-5aa3239b950mr9724607e87.25.1779944587971; Wed, 27 May 2026 22:03:07 -0700 (PDT) X-Received: by 2002:a05:6512:1094:b0:5a8:6799:efb1 with SMTP id 2adb3069b0e04-5aa3239b950mr9724589e87.25.1779944587344; Wed, 27 May 2026 22:03:07 -0700 (PDT) MIME-Version: 1.0 References: <20260526123115.1226166-1-anskuma@redhat.com> <20260526123115.1226166-2-anskuma@redhat.com> In-Reply-To: From: Anshu Kumari Date: Thu, 28 May 2026 10:32:54 +0530 X-Gm-Features: AVHnY4Iq9wCeIBGElZmzfvr0xjZbXDHlRHJktQAv5uVxTUxrmfTSpay5Sdsq0CE Message-ID: Subject: Re: [PATCH v2 1/6] conf: Add --dhcp-opt command-line option To: David Gibson X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: mbkWvx8g8HQ1dXIqN1bcSvRttpNGR9vKeq8BH_a9Y7s_1779944588 X-Mimecast-Originator: redhat.com Content-Type: multipart/alternative; boundary="000000000000d94dac0652d9a4c9" Message-ID-Hash: IO26LNCLQ3TBTEIEL3AWYKAD5B55IZXX X-Message-ID-Hash: IO26LNCLQ3TBTEIEL3AWYKAD5B55IZXX X-MailFrom: anskuma@redhat.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: passt-dev@passt.top, sbrivio@redhat.com, jmaloy@redhat.com, lvivier@redhat.com X-Mailman-Version: 3.3.8 Precedence: list List-Id: Development discussion and patches for passt Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: --000000000000d94dac0652d9a4c9 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Wed, May 27, 2026 at 8:56=E2=80=AFAM David Gibson wrote: > On Tue, May 26, 2026 at 06:01:08PM +0530, Anshu Kumari wrote: > > Introduce the --dhcp-opt flag that allows setting arbitrary DHCP > > options from command-line in the form of [Option CODE,VALUE]. > > This patch adds the option storage in struct ctx and CLI parsing; > > the type-aware value parser and DHCP reply injection follow > > in subsequent patches. > > > > Link: https://bugs.passt.top/show_bug.cgi?id=3D192 > > Signed-off-by: Anshu Kumari > > Mostly LGTM, but one query below. > > > --- > > v2: > > - Added kerneldoc for @custom_opts, @custom_opts.code, > @custom_opts.str, and @custom_opts_count in struct ctx > > - Removed len and val[255] fields from struct (moved to patch 3) > > - Removed braces from case 33, moved declarations (optcode, comma, > end) to function scope > > - Renamed code =E2=86=92 optcode to follow function-scope convention > > --- > > conf.c | 34 +++++++++++++++++++++++++++++++++- > > passt.h | 12 ++++++++++++ > > 2 files changed, 45 insertions(+), 1 deletion(-) > > > > diff --git a/conf.c b/conf.c > > index 029b9c7..89d2127 100644 > > --- a/conf.c > > +++ b/conf.c > > @@ -47,6 +47,7 @@ > > #include "lineread.h" > > #include "isolation.h" > > #include "log.h" > > +#include "dhcp.h" > > #include "vhost_user.h" > > #include "epoll_ctl.h" > > #include "conf.h" > > @@ -616,7 +617,8 @@ static void usage(const char *name, FILE *f, int > status) > > " -S, --search LIST Space-separated list, search > domains\n" > > " a single, empty option disables the DNS search list\= n" > > " -H, --hostname NAME Hostname to configure client > with\n" > > - " --fqdn NAME FQDN to configure client with\n")= ; > > + " --fqdn NAME FQDN to configure client with\n" > > + " --dhcp-opt CODE,VAL Set DHCP option by code\n"); > > if (strstr(name, "pasta")) > > FPRINTF(f, " default: don't use any search list\n"); > > else > > @@ -844,6 +846,10 @@ static void conf_print(const struct ctx *c) > > info(" router: %s", > > inet_ntop(AF_INET, &c->ip4.guest_gw, > > buf, sizeof(buf))); > > + for (i =3D 0; i < c->custom_opts_count; i++) > > + info(" option %u: %s", > > + c->custom_opts[i].code, > > + c->custom_opts[i].str); > > } > > > > for (i =3D 0; i < ARRAY_SIZE(c->ip4.dns); i++) { > > @@ -1233,6 +1239,7 @@ void conf(struct ctx *c, int argc, char **argv) > > {"migrate-no-linger", no_argument, NULL, 3= 0 > }, > > {"stats", required_argument, NULL, 3= 1 > }, > > {"conf-path", required_argument, NULL, > 'c' }, > > + {"dhcp-opt", required_argument, NULL, 3= 3 > }, > > { 0 }, > > }; > > const char *optstring =3D > "+dqfel:hs:c:F:I:p:P:m:a:n:M:g:i:o:D:S:H:461t:u:T:U:"; > > @@ -1248,10 +1255,13 @@ void conf(struct ctx *c, int argc, char **argv) > > uint8_t prefix_len_from_opt =3D 0; > > unsigned int ifi4 =3D 0, ifi6 =3D 0; > > const char *logfile =3D NULL; > > + unsigned long optcode; > > char *runas =3D NULL; > > size_t logsize =3D 0; > > + const char *comma; > > long fd_tap_opt; > > int name, ret; > > + char *end; > > uid_t uid; > > gid_t gid; > > > > @@ -1465,6 +1475,28 @@ void conf(struct ctx *c, int argc, char **argv) > > die("Can't display statistics if not > running in foreground"); > > c->stats =3D strtol(optarg, NULL, 0); > > break; > > + case 33: > > + comma =3D strchr(optarg, ','); > > + if (!comma) > > + die("--dhcp-opt requires Option CODE,VALU= E > format"); > > + > > + optcode =3D strtoul(optarg, &end, 0); > > + if (end !=3D comma || optcode < 1 || optcode > 25= 4) > > + die("DHCP option code must be 1-254: %s", > > + optarg); > > + > > + if (c->custom_opts_count >=3D MAX_CUSTOM_DHCP_OPT= S) > > + die("Too many --dhcp-opt entries (max %d)= ", > > + MAX_CUSTOM_DHCP_OPTS); > > + > > + c->custom_opts[c->custom_opts_count].code =3D > optcode; > > What happens if the user specifies the same DHCP option code multiple > times? > > I don't know off-hand if DHCP allows the same option to be presented > multiple times; I'm guessing not. In which case we probably want to > check for already-specified options and overwrite them, instead of > adding them to the array twice. > If a user specifies the same DHCP option code multiple times, the option value is overwritten. The last specified value is considered, like if we run below command ./passt -f --dhcp-opt 6,8.8.8.8,8.8.4.4 --dhcp-opt 6,1.1.1.1,9.9.9.9 then passt DHCP option stores the last value DHCP: assign: 192.168.1.9 mask: 255.255.255.0 router: 192.168.1.1 option 6: 1.1.1.1,9.9.9.9 > > > + if > (snprintf_check(c->custom_opts[c->custom_opts_count].str, > > + sizeof(c->custom_opts[0].str), > > + "%s", comma + 1)) > > + die("DHCP option value too long: %s", > > + comma + 1); > > + c->custom_opts_count++; > > + break; > > case 'd': > > c->debug =3D 1; > > c->quiet =3D 0; > > diff --git a/passt.h b/passt.h > > index 1726965..3a0816f 100644 > > --- a/passt.h > > +++ b/passt.h > > @@ -182,6 +182,10 @@ struct ip6_ctx { > > * @dns_search: DNS search list > > * @hostname: Guest hostname > > * @fqdn: Guest FQDN > > + * @custom_opts: User-specified DHCP options from --dhcp-opt > > + * @custom_opts.code: DHCP option code > > + * @custom_opts.str: Original string value from command line > > + * @custom_opts_count: Number of entries in @custom_opts > > * @ifi6: Template interface for IPv6, -1: none, 0: IPv6 > disabled > > * @ip6: IPv6 configuration > > * @pasta_ifn: Name of namespace interface for pasta > > @@ -263,6 +267,14 @@ struct ctx { > > char hostname[PASST_MAXDNAME]; > > char fqdn[PASST_MAXDNAME]; > > > > +#define MAX_CUSTOM_DHCP_OPTS 32 > > + > > + struct { > > + uint8_t code; > > + char str[256]; > > + } custom_opts[MAX_CUSTOM_DHCP_OPTS]; > > + int custom_opts_count; > > + > > int ifi6; > > struct ip6_ctx ip6; > > > > -- > > 2.54.0 > > > > -- > David Gibson (he or they) | I'll have my music baroque, and my code > david AT gibson.dropbear.id.au | minimalist, thank you, not the other wa= y > | around. > http://www.ozlabs.org/~dgibson > --000000000000d94dac0652d9a4c9 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable


On Wed, May 27,= 2026 at 8:56=E2=80=AFAM David Gibson <david@gibson.dropbear.id.au> wrote:
On Tue, May 26, 2026 at 06:01:08PM= +0530, Anshu Kumari wrote:
> Introduce the --dhcp-opt flag that allows setting arbitrary DHCP
> options from command-line in the form of [Option CODE,VALUE].
> This patch adds the option storage in struct ctx and CLI parsing;
> the type-aware value parser and DHCP reply injection follow
> in subsequent patches.
>
> Link: https://bugs.passt.top/show_bug.cgi?id=3D192<= /a>
> Signed-off-by: Anshu Kumari <
anskuma@redhat.com>

Mostly LGTM, but one query below.

> ---
> v2:
>=C2=A0 =C2=A0- Added kerneldoc for @custom_opts, @custom_opts.code, @cu= stom_opts.str, and @custom_opts_count in struct ctx
>=C2=A0 =C2=A0- Removed len and val[255] fields from struct (moved to pa= tch=C2=A03)
>=C2=A0 =C2=A0- Removed braces from case 33, moved declarations (optcode= , comma, end) to function scope
>=C2=A0 =C2=A0- Renamed code =E2=86=92 optcode to follow function-scope = convention
> ---
>=C2=A0 conf.c=C2=A0 | 34 +++++++++++++++++++++++++++++++++-
>=C2=A0 passt.h | 12 ++++++++++++
>=C2=A0 2 files changed, 45 insertions(+), 1 deletion(-)
>
> diff --git a/conf.c b/conf.c
> index 029b9c7..89d2127 100644
> --- a/conf.c
> +++ b/conf.c
> @@ -47,6 +47,7 @@
>=C2=A0 #include "lineread.h"
>=C2=A0 #include "isolation.h"
>=C2=A0 #include "log.h"
> +#include "dhcp.h"
>=C2=A0 #include "vhost_user.h"
>=C2=A0 #include "epoll_ctl.h"
>=C2=A0 #include "conf.h"
> @@ -616,7 +617,8 @@ static void usage(const char *name, FILE *f, int s= tatus)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0"=C2=A0 -S,= --search LIST=C2=A0 =C2=A0 Space-separated list, search domains\n" >=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0"=C2=A0 =C2= =A0 a single, empty option disables the DNS search list\n"
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0"=C2=A0 -H,= --hostname NAME=C2=A0 Hostname to configure client with\n"
> -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0"=C2=A0 --fqdn N= AME=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 FQDN to configure client with\n"= );
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0"=C2=A0 --fqdn N= AME=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 FQDN to configure client with\n"=
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0"=C2=A0 --dhcp-o= pt CODE,VAL=C2=A0 Set DHCP option by code\n");
>=C2=A0 =C2=A0 =C2=A0 =C2=A0if (strstr(name, "pasta"))
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0FPRINTF(f, "= ;=C2=A0 =C2=A0 default: don't use any search list\n");
>=C2=A0 =C2=A0 =C2=A0 =C2=A0else
> @@ -844,6 +846,10 @@ static void conf_print(const struct ctx *c)
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0info("=C2=A0 =C2=A0 router: %s",
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 inet_ntop(AF_INET, &c->ip4.guest_gw,
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 buf, sizeof(= buf)));
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0for (i =3D 0; i < c->custom_opts_count; i++)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0info("=C2=A0 =C2=A0 option %u: %s&q= uot;,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 c->custom_opts[i].code= ,
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 c->custom_opts[i].str)= ;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0}
>=C2=A0
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0for (i =3D 0; i = < ARRAY_SIZE(c->ip4.dns); i++) {
> @@ -1233,6 +1239,7 @@ void conf(struct ctx *c, int argc, char **argv)<= br> >=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{"migrate-n= o-linger", no_argument,=C2=A0 =C2=A0 =C2=A0 NULL,=C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A030 },
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{"stats&quo= t;, required_argument,=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 NULL,=C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A031 },
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{"conf-path= ",=C2=A0 =C2=A0required_argument,=C2=A0 =C2=A0 =C2=A0 NULL,=C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0'c' },
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{"dhcp-opt"= , required_argument,=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0NULL,=C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A033 },
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0{ 0 },
>=C2=A0 =C2=A0 =C2=A0 =C2=A0};
>=C2=A0 =C2=A0 =C2=A0 =C2=A0const char *optstring =3D "+dqfel:hs:c:= F:I:p:P:m:a:n:M:g:i:o:D:S:H:461t:u:T:U:";
> @@ -1248,10 +1255,13 @@ void conf(struct ctx *c, int argc, char **argv= )
>=C2=A0 =C2=A0 =C2=A0 =C2=A0uint8_t prefix_len_from_opt =3D 0;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0unsigned int ifi4 =3D 0, ifi6 =3D 0;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0const char *logfile =3D NULL;
> +=C2=A0 =C2=A0 =C2=A0unsigned long optcode;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0char *runas =3D NULL;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0size_t logsize =3D 0;
> +=C2=A0 =C2=A0 =C2=A0const char *comma;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0long fd_tap_opt;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0int name, ret;
> +=C2=A0 =C2=A0 =C2=A0char *end;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0uid_t uid;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0gid_t gid;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0
> @@ -1465,6 +1475,28 @@ void conf(struct ctx *c, int argc, char **argv)=
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0die("Can't display statis= tics if not running in foreground");
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0c->stats =3D strtol(optarg, NULL, 0);
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0break;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0case 33:
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0comma =3D strchr(optarg, ',');
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0if (!comma)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0die("--dhcp-opt requires Option COD= E,VALUE format");
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0optcode =3D strtoul(optarg, &end, 0);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0if (end !=3D comma || optcode < 1 || optcode > 254)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0die("DHCP option code must be 1-254= : %s",
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0optarg);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0if (c->custom_opts_count >=3D MAX_CUSTOM_DHCP_OPTS)
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0die("Too many --dhcp-opt entries (m= ax %d)",
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0MAX_CUSTOM_DHCP_OPTS);
> +
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0c->custom_opts[c->custom_opts_count].code =3D optcode;

What happens if the user specifies the same DHCP option code multiple
times?

I don't know off-hand if DHCP allows the same option to be presented multiple times; I'm guessing not.=C2=A0 In which case we probably want = to
check for already-specified options and overwrite them, instead of
adding them to the array twice.
=C2=A0
If a = user specifies the same DHCP option code multiple times, the option value i= s overwritten.
The last specified value is considered, like if we= run below command

=C2=A0./passt -f=C2=A0 --dhcp-opt 6,8.8.8.8,8.8.4= .4 --dhcp-opt 6,1.1.1.1,9.9.9.9

then passt DHCP option stores the la= st value
DHCP:
=C2=A0 =C2=A0 assign: 192.168.1.9
=C2=A0 =C2=A0 mas= k: 255.255.255.0
=C2=A0 =C2=A0 router: 192.168.1.1
=C2=A0 =C2=A0 opti= on 6: 1.1.1.1,9.9.9.9
=C2=A0=C2=A0

> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0if (snprintf_check(c->custom_opts[c->custom_opts_count].str, > +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 size= of(c->custom_opts[0].str),
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 &quo= t;%s", comma + 1))
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0die("DHCP option value too long: %s= ",
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0comma + 1);
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0c->custom_opts_count++;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0= =C2=A0break;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0case 'd'= :
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0c->debug =3D 1;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 =C2=A0c->quiet =3D 0;
> diff --git a/passt.h b/passt.h
> index 1726965..3a0816f 100644
> --- a/passt.h
> +++ b/passt.h
> @@ -182,6 +182,10 @@ struct ip6_ctx {
>=C2=A0 =C2=A0* @dns_search:=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 = =C2=A0 DNS search list
>=C2=A0 =C2=A0* @hostname:=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 Guest hostname
>=C2=A0 =C2=A0* @fqdn:=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Guest FQ= DN
> + * @custom_opts:=C2=A0 =C2=A0 =C2=A0User-specified DHCP options from = --dhcp-opt
> + * @custom_opts.code:=C2=A0 =C2=A0 =C2=A0 =C2=A0 DHCP option code
> + * @custom_opts.str: Original string value from command line
> + * @custom_opts_count:=C2=A0 =C2=A0 =C2=A0 =C2=A0Number of entries in= @custom_opts
>=C2=A0 =C2=A0* @ifi6:=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 Template= interface for IPv6, -1: none, 0: IPv6 disabled
>=C2=A0 =C2=A0* @ip6:=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0IPv= 6 configuration
>=C2=A0 =C2=A0* @pasta_ifn:=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0Name of namespace interface for pasta
> @@ -263,6 +267,14 @@ struct ctx {
>=C2=A0 =C2=A0 =C2=A0 =C2=A0char hostname[PASST_MAXDNAME];
>=C2=A0 =C2=A0 =C2=A0 =C2=A0char fqdn[PASST_MAXDNAME];
>=C2=A0
> +#define MAX_CUSTOM_DHCP_OPTS 32
> +
> +=C2=A0 =C2=A0 =C2=A0struct {
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0uint8_t code;
> +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0char str[256];
> +=C2=A0 =C2=A0 =C2=A0} custom_opts[MAX_CUSTOM_DHCP_OPTS];
> +=C2=A0 =C2=A0 =C2=A0int custom_opts_count;
> +
>=C2=A0 =C2=A0 =C2=A0 =C2=A0int ifi6;
>=C2=A0 =C2=A0 =C2=A0 =C2=A0struct ip6_ctx ip6;
>=C2=A0
> --
> 2.54.0
>

--
David Gibson (he or they)=C2=A0 =C2=A0 =C2=A0 =C2=A0| I'll have my musi= c baroque, and my code
david AT gibson.dropbear.id.au=C2=A0 | minimalist, thank you, not th= e other way
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 | around.
http://www.ozlabs.org/~dgibson
--000000000000d94dac0652d9a4c9--