* [PATCH v3 0/2] conf: Support CIDR notation for -a/--address option
@ 2025-12-18 22:22 Jon Maloy
2025-12-18 22:22 ` [PATCH v3 1/2] " Jon Maloy
2025-12-18 22:22 ` [PATCH v3 2/2] doc: Document CIDR notation support " Jon Maloy
0 siblings, 2 replies; 3+ messages in thread
From: Jon Maloy @ 2025-12-18 22:22 UTC (permalink / raw)
To: sbrivio, dgibson, david, jmaloy, passt-dev
conf: Support CIDR notation for -a/--address option
---
v3: Fixes after feedback from Laurent, David and Stefano
Notably, updated man page for the -a option
Jon Maloy (2):
conf: Support CIDR notation for -a/--address option
doc: Document CIDR notation support for -a/--address option
conf.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++---------
passt.1 | 10 ++++--
2 files changed, 87 insertions(+), 17 deletions(-)
--
2.52.0
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH v3 1/2] conf: Support CIDR notation for -a/--address option
2025-12-18 22:22 [PATCH v3 0/2] conf: Support CIDR notation for -a/--address option Jon Maloy
@ 2025-12-18 22:22 ` Jon Maloy
2025-12-18 22:22 ` [PATCH v3 2/2] doc: Document CIDR notation support " Jon Maloy
1 sibling, 0 replies; 3+ messages in thread
From: Jon Maloy @ 2025-12-18 22:22 UTC (permalink / raw)
To: sbrivio, dgibson, david, jmaloy, passt-dev
Extend the -a/--address option to accept addresses in CIDR notation
(e.g., 192.168.1.1/24 or 2001:db8::1/64) as an alternative to using
separate -a and -n options.
Add conf_addr_prefix_len() helper function that:
- Parses address strings with optional /prefix_len suffix using inany_pton()
- Validates prefix length based on address family (0-32 for IPv4,
0-128 for IPv6)
- Returns address family via union inany_addr output parameter
For IPv4, the prefix length is stored in ip4.prefix_len when provided.
Mixing -n and CIDR notation results in an error to catch likely user
mistakes.
Also fix a bug in conf_ip4_prefix() that was incorrectly using the
global 'optarg' instead of its 'arg' parameter.
Signed-off-by: Jon Maloy <jmaloy@redhat.com>
---
conf.c | 94 ++++++++++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 79 insertions(+), 15 deletions(-)
diff --git a/conf.c b/conf.c
index 2942c8c..81a6ca3 100644
--- a/conf.c
+++ b/conf.c
@@ -682,7 +682,7 @@ static int conf_ip4_prefix(const char *arg)
return -1;
} else {
errno = 0;
- len = strtoul(optarg, NULL, 0);
+ len = strtoul(arg, NULL, 0);
if (len > 32 || errno)
return -1;
}
@@ -690,6 +690,50 @@ static int conf_ip4_prefix(const char *arg)
return len;
}
+/**
+ * conf_addr_prefix_len() - Parse address with optional prefix length
+ * @arg: Address string, optionally with /prefix_len suffix (modified)
+ * @addr: Output for parsed address
+ * @prefix_len: Output for prefix length (0 if not specified)
+ *
+ * Return: AF_INET for IPv4, AF_INET6 for IPv6, -1 on error
+ */
+static int conf_addr_prefix_len(char *arg, union inany_addr *addr,
+ int *prefix_len)
+{
+ char *slash;
+
+ *prefix_len = 0;
+
+ /* Check for /prefix_len suffix */
+ slash = strchr(arg, '/');
+ if (slash) {
+ unsigned long len;
+ char *end;
+
+ *slash = '\0';
+ errno = 0;
+ len = strtoul(slash + 1, &end, 10);
+ if (errno || *end)
+ return -1;
+
+ *prefix_len = len;
+ }
+
+ if (!inany_pton(arg, addr))
+ return -1;
+
+ if (inany_v4(addr)) {
+ if (*prefix_len > 32)
+ return -1;
+ return AF_INET;
+ }
+
+ if (*prefix_len > 128)
+ return -1;
+ return AF_INET6;
+}
+
/**
* conf_ip4() - Verify or detect IPv4 support, get relevant addresses
* @ifi: Host interface to attempt (0 to determine one)
@@ -896,7 +940,7 @@ static void usage(const char *name, FILE *f, int status)
" a zero value disables assignment\n"
" default: 65520: maximum 802.3 MTU minus 802.3 header\n"
" length, rounded to 32 bits (IPv4 words)\n"
- " -a, --address ADDR Assign IPv4 or IPv6 address ADDR\n"
+ " -a, --address ADDR Assign IPv4 or IPv6 address ADDR[/PREFIXLEN]\n"
" can be specified zero to two times (for IPv4 and IPv6)\n"
" default: use addresses from interface with default route\n"
" -n, --netmask MASK Assign IPv4 MASK, dot-decimal or bits\n"
@@ -1499,6 +1543,7 @@ void conf(struct ctx *c, int argc, char **argv)
const char *logname = (c->mode == MODE_PASTA) ? "pasta" : "passt";
char userns[PATH_MAX] = { 0 }, netns[PATH_MAX] = { 0 };
bool copy_addrs_opt = false, copy_routes_opt = false;
+ bool prefix_from_cidr = false, prefix_from_opt = false;
enum fwd_ports_mode fwd_default = FWD_NONE;
bool v4_only = false, v6_only = false;
unsigned dns4_idx = 0, dns6_idx = 0;
@@ -1808,23 +1853,39 @@ void conf(struct ctx *c, int argc, char **argv)
c->mtu = mtu;
break;
}
- case 'a':
- 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) &&
- !IN6_IS_ADDR_V4COMPAT(&c->ip6.addr) &&
- !IN6_IS_ADDR_MULTICAST(&c->ip6.addr)) {
+ case 'a': {
+ union inany_addr addr;
+ const struct in_addr *a4;
+ int prefix_len = 0;
+ int af;
+
+ af = conf_addr_prefix_len(optarg, &addr, &prefix_len);
+
+ if (af == AF_INET6 &&
+ !IN6_IS_ADDR_UNSPECIFIED(&addr.a6) &&
+ !IN6_IS_ADDR_LOOPBACK(&addr.a6) &&
+ !IN6_IS_ADDR_V4MAPPED(&addr.a6) &&
+ !IN6_IS_ADDR_V4COMPAT(&addr.a6) &&
+ !IN6_IS_ADDR_MULTICAST(&addr.a6)) {
+ c->ip6.addr = addr.a6;
if (c->mode == MODE_PASTA)
c->ip6.no_copy_addrs = true;
break;
}
- 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) &&
- !IN4_IS_ADDR_MULTICAST(&c->ip4.addr)) {
+ a4 = inany_v4(&addr);
+ if (af == AF_INET && a4 &&
+ !IN4_IS_ADDR_UNSPECIFIED(a4) &&
+ !IN4_IS_ADDR_BROADCAST(a4) &&
+ !IN4_IS_ADDR_LOOPBACK(a4) &&
+ !IN4_IS_ADDR_MULTICAST(a4)) {
+ c->ip4.addr = *a4;
+ if (prefix_len) {
+ if (prefix_from_opt)
+ die("Can't use both -n and CIDR prefix length");
+ c->ip4.prefix_len = prefix_len;
+ prefix_from_cidr = true;
+ }
if (c->mode == MODE_PASTA)
c->ip4.no_copy_addrs = true;
break;
@@ -1832,11 +1893,14 @@ void conf(struct ctx *c, int argc, char **argv)
die("Invalid address: %s", optarg);
break;
+ }
case 'n':
+ if (prefix_from_cidr)
+ die("Can't use both -n and CIDR prefix length");
c->ip4.prefix_len = conf_ip4_prefix(optarg);
if (c->ip4.prefix_len < 0)
die("Invalid netmask: %s", optarg);
-
+ prefix_from_opt = true;
break;
case 'M':
parse_mac(c->our_tap_mac, optarg);
--
2.52.0
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH v3 2/2] doc: Document CIDR notation support for -a/--address option
2025-12-18 22:22 [PATCH v3 0/2] conf: Support CIDR notation for -a/--address option Jon Maloy
2025-12-18 22:22 ` [PATCH v3 1/2] " Jon Maloy
@ 2025-12-18 22:22 ` Jon Maloy
1 sibling, 0 replies; 3+ messages in thread
From: Jon Maloy @ 2025-12-18 22:22 UTC (permalink / raw)
To: sbrivio, dgibson, david, jmaloy, passt-dev
Update the man page to document the new CIDR notation support:
- Update -a/--address to show addr[/prefix_len] syntax
- Document that prefix length (0-32) can be appended for IPv4
- Note that mixing CIDR notation with -n results in an error
- Update -n/--netmask to mention CIDR alternative
Signed-off-by: Jon Maloy <jmaloy@redhat.com>
---
passt.1 | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/passt.1 b/passt.1
index db0d662..117239f 100644
--- a/passt.1
+++ b/passt.1
@@ -156,10 +156,14 @@ By default, the advertised MTU is 65520 bytes, that is, the maximum 802.3 MTU
minus the length of a 802.3 header, rounded to 32 bits (IPv4 words).
.TP
-.BR \-a ", " \-\-address " " \fIaddr
+.BR \-a ", " \-\-address " " \fIaddr\fR[\fB/\fR\fIprefix_len\fR]
Assign IPv4 \fIaddr\fR via DHCP (\fByiaddr\fR), or \fIaddr\fR via DHCPv6 (option
5) and an \fIaddr\fR-based prefix via NDP Router Advertisement (option type 3)
for an IPv6 \fIaddr\fR.
+For IPv4 addresses, an optional \fB/\fR\fIprefix_len\fR (0-32) can be
+appended in CIDR notation (e.g., 192.168.1.1/24). This is an alternative to
+using the \fB-n\fR, \fB--netmask\fR option. Mixing CIDR notation with
+\fB-n\fR results in an error.
This option can be specified zero (for defaults) to two times (once for IPv4,
once for IPv6).
By default, assigned IPv4 and IPv6 addresses are taken from the host interfaces
@@ -172,7 +176,9 @@ is assigned for IPv4, and no additional address will be assigned for IPv6.
.TP
.BR \-n ", " \-\-netmask " " \fImask
Assign IPv4 netmask \fImask\fR, expressed as dot-decimal or number of bits, via
-DHCP (option 1).
+DHCP (option 1). Alternatively, the prefix length can be specified using CIDR
+notation with the \fB-a\fR, \fB--address\fR option (e.g., \fB-a\fR 192.168.1.1/24).
+Mixing \fB-n\fR with CIDR notation results in an error.
By default, the netmask associated to the host address matching the assigned one
is used. If there's no matching address on the host, the netmask is determined
according to the CIDR block of the assigned address (RFC 4632).
--
2.52.0
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2025-12-18 22:22 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-12-18 22:22 [PATCH v3 0/2] conf: Support CIDR notation for -a/--address option Jon Maloy
2025-12-18 22:22 ` [PATCH v3 1/2] " Jon Maloy
2025-12-18 22:22 ` [PATCH v3 2/2] doc: Document CIDR notation support " Jon Maloy
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).