From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail.ozlabs.org (mail.ozlabs.org [IPv6:2404:9400:2221:ea00::3]) by passt.top (Postfix) with ESMTPS id C2CA75A004F for ; Fri, 21 Jun 2024 02:56:04 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gibson.dropbear.id.au; s=202312; t=1718931360; bh=ieDWIB7q8kQeGOHc9EwCxkXPqcjgMOUn0WZF8TsDTOY=; h=Date:From:To:Cc:Subject:References:In-Reply-To:From; b=rptBZE9lzKBmASikRRCFVK6r0MAtRSYJRNJL6dUeT2TRIoaSXcnLb81DCpxfMAJoP +O2aEUGsnc4lywHb9diOwwQXsFPozmMv54tn7iBbdur9AVZGUN4patLPMi3sb9/0uG O6fJ7a+6b6iTmjZpoMV8oIJoHrz01DyvCjMRUQ7l2W0Kf4/dXIvfUdiv41zvPrMKsB t/xwCK7zXwGth2z8hOxV9mwnCHzSrS/1PVBl3GB0aQzW9Ro9SyRy3/2bNC1CtZW5b+ 9sDPLRpAJpmYb/EpCbW9nQrn0hudz+QCP2MfoZdk+6f4LguPnfgUDsGPi2vCO6mLoc ZcrxR4/M+fT1g== Received: by gandalf.ozlabs.org (Postfix, from userid 1007) id 4W4zSJ5pNMz4wc5; Fri, 21 Jun 2024 10:56:00 +1000 (AEST) Date: Fri, 21 Jun 2024 10:53:26 +1000 From: David Gibson To: Stefano Brivio Subject: Re: [PATCH v3] conf: Accept duplicate and conflicting options, the last one wins Message-ID: References: <20240620171921.179930-1-sbrivio@redhat.com> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha256; protocol="application/pgp-signature"; boundary="1xOZSlFghiCYrdq3" Content-Disposition: inline In-Reply-To: <20240620171921.179930-1-sbrivio@redhat.com> Message-ID-Hash: FKBKRELYA5GVHDVOAV4H2JU22C7NGT4C X-Message-ID-Hash: FKBKRELYA5GVHDVOAV4H2JU22C7NGT4C X-MailFrom: dgibson@gandalf.ozlabs.org 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, Paul Holzinger 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: --1xOZSlFghiCYrdq3 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On Thu, Jun 20, 2024 at 07:19:21PM +0200, Stefano Brivio wrote: > In multiple occasions, especially when passt(1) and pasta(1) are used > in integrations such as the one with Podman, the ability to override > earlier options on the command line with later one would have been > convenient. >=20 > Recently, to debug a number of issues happening with Podman, I would > have liked to ask users to share a debug log by passing --debug as > additional option, but pasta refuses --quiet (always passed by Podman) > and --debug at the same time. >=20 > On top of this, Podman lets users specify other pasta options in its > containers.conf(5) file, as well as on the command line. >=20 > The options from the configuration files are appended together with > the ones from the command line, which makes it impossible for users to > override options from the configuration file, if duplicated options > are refused, unless Podman takes care of sorting them, which is > clearly not sustainable. >=20 > For --debug and --trace, somebody took care of this on Podman side at: > https://github.com/containers/common/pull/2052 >=20 > but this doesn't fix the issue with other options, and we'll have > anyway older versions of Podman around, too. >=20 > I think there's some value in telling users about duplicated or > conflicting options, because that might reveal issues in integrations > or accidental misconfigurations, but by now I'm fairly convinced that > the downsides outweigh this. >=20 > Drop checks about duplicate options and mutually exclusive ones. In > some cases, we need to also undo a couple of initialisations caused > by earlier options, but this looks like a simplification, overall. >=20 > Notable exception: --stderr still conflicts with --log-file, because > users might have the expectation that they don't actually conflict. > But they do conflict in the existing implementation, so it's safer > to make sure that the users notice that. >=20 > Suggested-by: Paul Holzinger > Suggested-by: David Gibson > Signed-off-by: Stefano Brivio Reviewed-by: David Gibson > --- > v3: > - override --gateway and --dns-forward with the last given option > for a given address family, too >=20 > v2: > - report --log-file and --stderr as conflicting, but accept > multiple options if they don't conflict > - for --log-file and --pcap, make it clear in the man page that > the general principle still applies: only the last one (of each) > takes effect > - add some more context about Podman and how the list of pasta > options is built there, in the commit message >=20 > conf.c | 146 ++++++++++++++++---------------------------------------- > passt.1 | 17 +++++++ > 2 files changed, 59 insertions(+), 104 deletions(-) >=20 > diff --git a/conf.c b/conf.c > index 94b3ed6..4fff2b1 100644 > --- a/conf.c > +++ b/conf.c > @@ -517,9 +517,6 @@ static void conf_netns_opt(char *netns, const char *a= rg) > static void conf_pasta_ns(int *netns_only, char *userns, char *netns, > int optind, int argc, char *argv[]) > { > - if (*netns_only && *userns) > - die("Both --userns and --netns-only given"); > - > if (*netns && optind !=3D argc) > die("Both --netns and PID or command given"); > =20 > @@ -1204,7 +1201,6 @@ void conf(struct ctx *c, int argc, char **argv) > {"udp-ns", required_argument, NULL, 'U' }, > {"userns", required_argument, NULL, 2 }, > {"netns", required_argument, NULL, 3 }, > - {"netns-only", no_argument, &netns_only, 1 }, > {"ns-mac-addr", required_argument, NULL, 4 }, > {"dhcp-dns", no_argument, NULL, 5 }, > {"no-dhcp-dns", no_argument, NULL, 6 }, > @@ -1221,6 +1217,7 @@ void conf(struct ctx *c, int argc, char **argv) > {"config-net", no_argument, NULL, 17 }, > {"no-copy-routes", no_argument, NULL, 18 }, > {"no-copy-addrs", no_argument, NULL, 19 }, > + {"netns-only", no_argument, NULL, 20 }, > { 0 }, > }; > char userns[PATH_MAX] =3D { 0 }, netns[PATH_MAX] =3D { 0 }; > @@ -1265,6 +1262,8 @@ void conf(struct ctx *c, int argc, char **argv) > if (ret <=3D 0 || ret >=3D (int)sizeof(userns)) > die("Invalid userns: %s", optarg); > =20 > + netns_only =3D 0; > + > break; > case 3: > if (c->mode !=3D MODE_PASTA) > @@ -1303,14 +1302,12 @@ void conf(struct ctx *c, int argc, char **argv) > c->no_dhcp_dns_search =3D 1; > break; > case 9: > - if (IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns_match) && > - inet_pton(AF_INET6, optarg, &c->ip6.dns_match) && > + if (inet_pton(AF_INET6, optarg, &c->ip6.dns_match) && > !IN6_IS_ADDR_UNSPECIFIED(&c->ip6.dns_match) && > !IN6_IS_ADDR_LOOPBACK(&c->ip6.dns_match)) > break; > =20 > - if (IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns_match) && > - inet_pton(AF_INET, optarg, &c->ip4.dns_match) && > + if (inet_pton(AF_INET, optarg, &c->ip4.dns_match) && > !IN4_IS_ADDR_UNSPECIFIED(&c->ip4.dns_match) && > !IN4_IS_ADDR_BROADCAST(&c->ip4.dns_match) && > !IN4_IS_ADDR_LOOPBACK(&c->ip4.dns_match)) > @@ -1325,24 +1322,13 @@ void conf(struct ctx *c, int argc, char **argv) > c->no_netns_quit =3D 1; > break; > case 11: > - if (c->trace) > - die("Multiple --trace options given"); > - > - if (c->quiet) > - die("Either --trace or --quiet"); > - > c->trace =3D c->debug =3D 1; > + c->quiet =3D 0; > break; > case 12: > - if (runas) > - die("Multiple --runas options given"); > - > runas =3D optarg; > break; > case 13: > - if (logsize) > - die("Multiple --log-size options given"); > - > errno =3D 0; > logsize =3D strtol(optarg, NULL, 0); > =20 > @@ -1356,9 +1342,6 @@ void conf(struct ctx *c, int argc, char **argv) > fprintf(stdout, VERSION_BLOB); > exit(EXIT_SUCCESS); > case 15: > - if (*c->ip4.ifname_out) > - die("Redundant outbound interface: %s", optarg); > - > ret =3D snprintf(c->ip4.ifname_out, > sizeof(c->ip4.ifname_out), "%s", optarg); > if (ret <=3D 0 || ret >=3D (int)sizeof(c->ip4.ifname_out)) > @@ -1366,9 +1349,6 @@ void conf(struct ctx *c, int argc, char **argv) > =20 > break; > case 16: > - if (*c->ip6.ifname_out) > - die("Redundant outbound interface: %s", optarg); > - > ret =3D snprintf(c->ip6.ifname_out, > sizeof(c->ip6.ifname_out), "%s", optarg); > if (ret <=3D 0 || ret >=3D (int)sizeof(c->ip6.ifname_out)) > @@ -1395,62 +1375,47 @@ void conf(struct ctx *c, int argc, char **argv) > warn("--no-copy-addrs will be dropped soon"); > c->no_copy_addrs =3D copy_addrs_opt =3D true; > break; > - case 'd': > - if (c->debug) > - die("Multiple --debug options given"); > - > - if (c->quiet) > - die("Either --debug or --quiet"); > + case 20: > + if (c->mode !=3D MODE_PASTA) > + die("--netns-only is for pasta mode only"); > =20 > + netns_only =3D 1; > + *userns =3D 0; > + break; > + case 'd': > c->debug =3D 1; > + c->quiet =3D 0; > break; > case 'e': > if (logfile) > die("Can't log to both file and stderr"); > =20 > - if (c->force_stderr) > - die("Multiple --stderr options given"); > - > c->force_stderr =3D 1; > + logfile =3D NULL; > break; > case 'l': > if (c->force_stderr) > die("Can't log to both stderr and file"); > =20 > - if (logfile) > - die("Multiple --log-file options given"); > - > logfile =3D optarg; > + c->force_stderr =3D 0; > break; > case 'q': > - if (c->quiet) > - die("Multiple --quiet options given"); > - > - if (c->debug) > - die("Either --debug or --quiet"); > - > c->quiet =3D 1; > + c->debug =3D c->trace =3D 0; > break; > case 'f': > - if (c->foreground) > - die("Multiple --foreground options given"); > - > c->foreground =3D 1; > break; > case 's': > - if (*c->sock_path) > - die("Multiple --socket options given"); > - > ret =3D snprintf(c->sock_path, UNIX_SOCK_MAX - 1, "%s", > optarg); > if (ret <=3D 0 || ret >=3D (int)sizeof(c->sock_path)) > die("Invalid socket path: %s", optarg); > =20 > + c->fd_tap =3D -1; > break; > case 'F': > - if (c->fd_tap >=3D 0) > - die("Multiple --fd options given"); > - > errno =3D 0; > c->fd_tap =3D strtol(optarg, NULL, 0); > =20 > @@ -1458,12 +1423,9 @@ void conf(struct ctx *c, int argc, char **argv) > die("Invalid --fd: %s", optarg); > =20 > c->one_off =3D true; > - > + *c->sock_path =3D 0; > break; > case 'I': > - if (*c->pasta_ifn) > - die("Multiple --ns-ifname options given"); > - > ret =3D snprintf(c->pasta_ifn, IFNAMSIZ, "%s", > optarg); > if (ret <=3D 0 || ret >=3D IFNAMSIZ) > @@ -1471,18 +1433,12 @@ void conf(struct ctx *c, int argc, char **argv) > =20 > break; > case 'p': > - if (*c->pcap) > - die("Multiple --pcap options given"); > - > ret =3D snprintf(c->pcap, sizeof(c->pcap), "%s", optarg); > if (ret <=3D 0 || ret >=3D (int)sizeof(c->pcap)) > die("Invalid pcap path: %s", optarg); > =20 > break; > case 'P': > - if (*c->pidfile) > - die("Multiple --pid options given"); > - > ret =3D snprintf(c->pidfile, sizeof(c->pidfile), "%s", > optarg); > if (ret <=3D 0 || ret >=3D (int)sizeof(c->pidfile)) > @@ -1490,9 +1446,6 @@ void conf(struct ctx *c, int argc, char **argv) > =20 > break; > case 'm': > - if (c->mtu) > - die("Multiple --mtu options given"); > - > errno =3D 0; > c->mtu =3D strtol(optarg, NULL, 0); > =20 > @@ -1510,8 +1463,7 @@ void conf(struct ctx *c, int argc, char **argv) > if (c->mode =3D=3D MODE_PASTA) > c->no_copy_addrs =3D 1; > =20 > - if (IN6_IS_ADDR_UNSPECIFIED(&c->ip6.addr) && > - inet_pton(AF_INET6, optarg, &c->ip6.addr) && > + if (inet_pton(AF_INET6, optarg, &c->ip6.addr) && > !IN6_IS_ADDR_UNSPECIFIED(&c->ip6.addr) && > !IN6_IS_ADDR_LOOPBACK(&c->ip6.addr) && > !IN6_IS_ADDR_V4MAPPED(&c->ip6.addr) && > @@ -1519,8 +1471,7 @@ void conf(struct ctx *c, int argc, char **argv) > !IN6_IS_ADDR_MULTICAST(&c->ip6.addr)) > break; > =20 > - if (IN4_IS_ADDR_UNSPECIFIED(&c->ip4.addr) && > - inet_pton(AF_INET, optarg, &c->ip4.addr) && > + if (inet_pton(AF_INET, optarg, &c->ip4.addr) && > !IN4_IS_ADDR_UNSPECIFIED(&c->ip4.addr) && > !IN4_IS_ADDR_BROADCAST(&c->ip4.addr) && > !IN4_IS_ADDR_LOOPBACK(&c->ip4.addr) && > @@ -1542,14 +1493,12 @@ void conf(struct ctx *c, int argc, char **argv) > if (c->mode =3D=3D MODE_PASTA) > c->no_copy_routes =3D 1; > =20 > - if (IN6_IS_ADDR_UNSPECIFIED(&c->ip6.gw) && > - inet_pton(AF_INET6, optarg, &c->ip6.gw) && > + if (inet_pton(AF_INET6, optarg, &c->ip6.gw) && > !IN6_IS_ADDR_UNSPECIFIED(&c->ip6.gw) && > !IN6_IS_ADDR_LOOPBACK(&c->ip6.gw)) > break; > =20 > - if (IN4_IS_ADDR_UNSPECIFIED(&c->ip4.gw) && > - inet_pton(AF_INET, optarg, &c->ip4.gw) && > + if (inet_pton(AF_INET, optarg, &c->ip4.gw) && > !IN4_IS_ADDR_UNSPECIFIED(&c->ip4.gw) && > !IN4_IS_ADDR_BROADCAST(&c->ip4.gw) && > !IN4_IS_ADDR_LOOPBACK(&c->ip4.gw)) > @@ -1558,16 +1507,12 @@ void conf(struct ctx *c, int argc, char **argv) > die("Invalid gateway address: %s", optarg); > break; > case 'i': > - if (ifi4 || ifi6) > - die("Redundant interface: %s", optarg); > - > if (!(ifi4 =3D ifi6 =3D if_nametoindex(optarg))) > die("Invalid interface name %s: %s", optarg, > strerror(errno)); > break; > case 'o': > - if (IN6_IS_ADDR_UNSPECIFIED(&c->ip6.addr_out) && > - inet_pton(AF_INET6, optarg, &c->ip6.addr_out) && > + if (inet_pton(AF_INET6, optarg, &c->ip6.addr_out) && > !IN6_IS_ADDR_UNSPECIFIED(&c->ip6.addr_out) && > !IN6_IS_ADDR_LOOPBACK(&c->ip6.addr_out) && > !IN6_IS_ADDR_V4MAPPED(&c->ip6.addr_out) && > @@ -1575,8 +1520,7 @@ void conf(struct ctx *c, int argc, char **argv) > !IN6_IS_ADDR_MULTICAST(&c->ip6.addr_out)) > break; > =20 > - if (IN4_IS_ADDR_UNSPECIFIED(&c->ip4.addr_out) && > - inet_pton(AF_INET, optarg, &c->ip4.addr_out) && > + if (inet_pton(AF_INET, optarg, &c->ip4.addr_out) && > !IN4_IS_ADDR_UNSPECIFIED(&c->ip4.addr_out) && > !IN4_IS_ADDR_BROADCAST(&c->ip4.addr_out) && > !IN4_IS_ADDR_MULTICAST(&c->ip4.addr_out)) > @@ -1587,18 +1531,23 @@ void conf(struct ctx *c, int argc, char **argv) > break; > case 'D': > if (!strcmp(optarg, "none")) { > - if (c->no_dns) > - die("Redundant DNS options"); > + c->no_dns =3D 1; > =20 > - if (dns4 - c->ip4.dns || dns6 - c->ip6.dns) > - die("Conflicting DNS options"); > + dns4 =3D &c->ip4.dns[0]; > + memset(c->ip4.dns, 0, sizeof(c->ip4.dns)); > + c->ip4.dns[0] =3D (struct in_addr){ 0 }; > + c->ip4.dns_match =3D (struct in_addr){ 0 }; > + c->ip4.dns_host =3D (struct in_addr){ 0 }; > + > + dns6 =3D &c->ip6.dns[0]; > + memset(c->ip6.dns, 0, sizeof(c->ip6.dns)); > + c->ip6.dns_match =3D (struct in6_addr){ 0 }; > + c->ip6.dns_host =3D (struct in6_addr){ 0 }; > =20 > - c->no_dns =3D 1; > break; > } > =20 > - if (c->no_dns) > - die("Conflicting DNS options"); > + c->no_dns =3D 0; > =20 > if (dns4 - &c->ip4.dns[0] < ARRAY_SIZE(c->ip4.dns) && > inet_pton(AF_INET, optarg, &dns4_tmp)) { > @@ -1616,18 +1565,14 @@ void conf(struct ctx *c, int argc, char **argv) > break; > case 'S': > if (!strcmp(optarg, "none")) { > - if (c->no_dns_search) > - die("Redundant DNS search options"); > + c->no_dns_search =3D 1; > =20 > - if (dnss !=3D c->dns_search) > - die("Conflicting DNS search options"); > + memset(c->dns_search, 0, sizeof(c->dns_search)); > =20 > - c->no_dns_search =3D 1; > break; > } > =20 > - if (c->no_dns_search) > - die("Conflicting DNS search options"); > + c->no_dns_search =3D 0; > =20 > if (dnss - c->dns_search < ARRAY_SIZE(c->dns_search)) { > ret =3D snprintf(dnss->n, sizeof(*c->dns_search), > @@ -1643,17 +1588,16 @@ void conf(struct ctx *c, int argc, char **argv) > break; > case '4': > v4_only =3D true; > + v6_only =3D false; > break; > case '6': > v6_only =3D true; > + v4_only =3D false; > break; > case '1': > if (c->mode =3D=3D MODE_PASTA) > die("--one-off is for passt mode only"); > =20 > - if (c->one_off) > - die("Redundant --one-off option"); > - > c->one_off =3D true; > break; > case 't': > @@ -1672,12 +1616,6 @@ void conf(struct ctx *c, int argc, char **argv) > } > } while (name !=3D -1); > =20 > - if (v4_only && v6_only) > - die("Options ipv4-only and ipv6-only are mutually exclusive"); > - > - if (*c->sock_path && c->fd_tap >=3D 0) > - die("Options --socket and --fd are mutually exclusive"); > - > if (c->mode =3D=3D MODE_PASTA && !c->pasta_conf_ns) { > if (copy_routes_opt) > die("--no-copy-routes needs --config-net"); > diff --git a/passt.1 b/passt.1 > index 7676fe3..7b9915b 100644 > --- a/passt.1 > +++ b/passt.1 > @@ -73,6 +73,9 @@ for performance reasons. > =20 > .SH OPTIONS > =20 > +Unless otherwise noted below, \fBif conflicting or multiple options are = given, > +the last one takes effect.\fR > + > .TP > .BR \-d ", " \-\-debug > Be verbose, don't log to the system logger. > @@ -97,10 +100,21 @@ Log to standard error too. > Default is to log to the system logger only, if started from an interact= ive > terminal, and to both system logger and standard error otherwise. > =20 > +This option cannot be specified together with \fB--log-file\fR, because = there > +might be a reasonable expectation that messages are logged to standard e= rror as > +well as to a file, which is however not supported. > + > .TP > .BR \-l ", " \-\-log-file " " \fIPATH\fR > Log to file \fIPATH\fR, not to standard error, and not to the system log= ger. > =20 > +This option cannot be specified together with \fB--stderr\fR, because th= ere > +might be a reasonable expectation that messages are logged to a file as = well as > +to standard error, which is however not supported. > + > +Specifying this option multiple times does \fInot\fR lead to multiple lo= g files: > +the last given option takes effect. > + > .TP > .BR \-\-log-size " " \fISIZE\fR > Limit log file size to \fISIZE\fR bytes. When the log file is full, make= room > @@ -128,6 +142,9 @@ Show version and exit. > Capture tap-facing (that is, guest-side or namespace-side) network packe= ts to > \fIfile\fR in \fBpcap\fR format. > =20 > +Specifying this option multiple times does \fInot\fR lead to multiple ca= pture > +files: the last given option takes effect. > + > .TP > .BR \-P ", " \-\-pid " " \fIfile > Write own PID to \fIfile\fR once initialisation is done, before forking = to --=20 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 way | around. http://www.ozlabs.org/~dgibson --1xOZSlFghiCYrdq3 Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQIzBAEBCAAdFiEEO+dNsU4E3yXUXRK2zQJF27ox2GcFAmZ0zwUACgkQzQJF27ox 2Gd4zBAAla8B80tRfpVTLmUnU6G+36kb3y9yquM0NqZpG4doLki0HkMr+wzW6hoV LRaHcgvG0O529rYSAZ0Qv9QTOu23UhqHV0+eNMlKXlrs6/2afcbVYTAjVMe7+/Vr l9MvdxGxAScPMRMWSB+9pSfhXjLyghcZ3WZMXi/0LB/klH6pkB5g/WKsBroGC3Fl BG1+TLiXyxvd4eK/2XGY9pOADHyGG0gtXy3kRYsK483xzKxN0ClF0bGW1ez4w45P dXPJGSLq8PvYDx8Svapkn/4JVlm8qkOGSZHGRBFGLNWjHuNQdBlKMTj2BmR5bUlO DMMwDAawcnEHfnvdAVp0Vhd4cnnlfav5vlFoEtRv8aXtmOK/fGPX7xap6omkm6qq qo/IJb6xP/q1ctk1x9c/I7cuCQbAt+3e32uVtZ5EHOjNGo1rs0BeopI68yxMNyAL RpcNOUa+fWsIdtHVEG8BcghSibRNdHfgBPceflkA+yDKkPsEfadW1ucF17iL/M+X C9i+BmD2P4TYi5S2y9oylXKCfLJjKk0UGiioFnyqXewGN90McpkvAPzdHbgQmOUw QOYyzEo+DyedJv2S67taUxp38H+S7bnVtLQKNyOEY0UP51w6afp9l9b8PV7/ScPO 28a0SFFnpVtxjKu2OigoyEYEZ4ovOLbWJNmNER/8t2KD9Xfsy6w= =9vk/ -----END PGP SIGNATURE----- --1xOZSlFghiCYrdq3--