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=gGBvsEvc; dkim-atps=neutral Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by passt.top (Postfix) with ESMTPS id 016B15A0624 for ; Wed, 21 Jan 2026 09:15:24 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1768983324; 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: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=VypAclOeY5KPdbIzgOv2/NXZi4LZMMJcR5RZO8Q9GEM=; b=gGBvsEvcy70i0bBKNj6ts1SQrcjZXiMQLP6RS6Yy9SoEjWklrui6wNhpXeagfePe6oB2ki 1waKsavB/WO34RM1zZvIi17yx/50em6NvUlKCsAgvd5ahdtU517h2od/CFOBI9jTlsjuYt 2C7tcIAYl2AsYOpasJcL9CRAsyGeE7M= Received: from mail-wr1-f69.google.com (mail-wr1-f69.google.com [209.85.221.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-315-Swc8xc1YNVWwBMauRp1l1g-1; Wed, 21 Jan 2026 03:15:21 -0500 X-MC-Unique: Swc8xc1YNVWwBMauRp1l1g-1 X-Mimecast-MFC-AGG-ID: Swc8xc1YNVWwBMauRp1l1g_1768983321 Received: by mail-wr1-f69.google.com with SMTP id ffacd0b85a97d-430fd96b2f5so5963562f8f.3 for ; Wed, 21 Jan 2026 00:15:21 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1768983320; x=1769588120; h=content-transfer-encoding:mime-version:organization:references :in-reply-to:message-id:subject:cc:to:from:date:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=VypAclOeY5KPdbIzgOv2/NXZi4LZMMJcR5RZO8Q9GEM=; b=m4mkZzxN0IMhMjZp6vEOYufdcXCPd9fAP51qb8Z3CpSGt+A+054Ho9VGIpUu6Z2s1g YHyIE63S0ld8QxHtcSeQn/dIHflYqK6AEzTow8eD3YEjhg6nMN5lzGeZx3HJ3G7jhYZa HYw+AO/R1YwLxyttwCvcCmjKWqQXWcdhlDKyFKT4WdbBdgkeSAxQJdO068qofk4ljpKk 28MK1tvggi0TuroBwE+g8W4m16bJXZs2X6s75Tl0hIPoiK3AyoARaUkSwWiqtFnMAXQJ 5zotwpJjobLWjIN4yHdz2/JAX+IaeiN5hPGAHRxr5J0etKnQ+d28tSrYjiU7xrsjCVRB lVHQ== X-Forwarded-Encrypted: i=1; AJvYcCVUKqjR4wbHJQ25JrH7BQ1SKgx/Wgn3+2iSnniQdKarsxd8Pa6avx0D4aROc25m0uUr4rV0OrBJH+s=@passt.top X-Gm-Message-State: AOJu0YzMrV5WWSIs1qyEiPhQhWOcV2/oeZPoDXlNMT9zIh7WA4JodFni VNARmixfSO5rvTMKfU2uOxB21m8Aohcm7DMfTyoY2wB2jh+3+fQqLRWrabRAGFavEEI9JO9Cm0A OxwlQ3ddH6TcIc9RFnI5+j28sgZfKZUP9hSUbeiUIiRk2xas4EENY2g== X-Gm-Gg: AZuq6aJKZWRP23lZY7Wr9sXlSoma0RI3VobjHDgfSa9i9QTiOjOtOpts6weL40QS5oQ lY7hk0rLV16NAXjZARgPPmAKxGDbzLnWTMW/V+K7B6ZrOmJsoYMZ7+foZv2cGSEBsl7qPveocFh C9g+jwOTbpZr7yq60xElKp5Ey0YsDreEcuZKAwnzLCRkf6bFlzI4WzPLd3JCPVghUnzFw60EaJC DAMG2Ba+PwPGpl3I+AZJaYORusz9BTKkOB7CJSJGATKtBAarlDYSZk7SyFqn1aKTFp7bYxb6eYO 4vr9RVoWndCzhsn5LmVWLGNsyVRnb7GPdIK2bUsGG6dMK4hpasa6enO6C9/l2sIVQgMngwWY7Kh ZFmu6KS8GwzrZ0raU7yvnHy/yK0hWVOG2m3yQpw== X-Received: by 2002:a05:6000:26ce:b0:430:fd69:9920 with SMTP id ffacd0b85a97d-4358ff2af6fmr6544596f8f.16.1768983320214; Wed, 21 Jan 2026 00:15:20 -0800 (PST) X-Received: by 2002:a05:6000:26ce:b0:430:fd69:9920 with SMTP id ffacd0b85a97d-4358ff2af6fmr6544530f8f.16.1768983319380; Wed, 21 Jan 2026 00:15:19 -0800 (PST) Received: from maya.myfinge.rs (ifcgrfdd.trafficplex.cloud. [176.103.220.4]) by smtp.gmail.com with ESMTPSA id ffacd0b85a97d-4356996cefdsm33608270f8f.24.2026.01.21.00.15.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 21 Jan 2026 00:15:18 -0800 (PST) Date: Wed, 21 Jan 2026 09:15:17 +0100 From: Stefano Brivio To: Jon Maloy Subject: Re: [PATCH v2 1/9] conf: Support CIDR notation for -a/--address option Message-ID: <20260121091517.626962f1@elisabeth> In-Reply-To: <20260118221612.2115386-2-jmaloy@redhat.com> References: <20260118221612.2115386-1-jmaloy@redhat.com> <20260118221612.2115386-2-jmaloy@redhat.com> Organization: Red Hat X-Mailer: Claws Mail 4.2.0 (GTK 3.24.49; x86_64-pc-linux-gnu) MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: qM_73z9uicEt_tyyMnwlQzBim6z2OQTSfbZYEvTJiMQ_1768983321 X-Mimecast-Originator: redhat.com Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Message-ID-Hash: 732EHJEO6YJGKSWWFKMFC7Q2I6XD2EBD X-Message-ID-Hash: 732EHJEO6YJGKSWWFKMFC7Q2I6XD2EBD X-MailFrom: sbrivio@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: dgibson@redhat.com, david@gibson.dropbear.id.au, passt-dev@passt.top 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: On Sun, 18 Jan 2026 17:16:04 -0500 Jon Maloy wrote: > 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. > > We add a new conf_addr_prefix_len() helper function that: > - Parses address strings with optional /prefix_len suffix > - Validates prefix length based on address family (0-32 for IPv4, > 0-128 for IPv6), including handling of IPv4-to-IPv6 mapping case. > - 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 > > --- > v3: Fixes after feedback from Laurent, David and Stefano > Notably, updated man page for the -a option > > v4: Fixes based on feedback from David G: > - Handling prefix length adjustment when IPv4-to-IPv6 mapping > - Removed redundant !IN6_IS_ADDR_V4MAPPED(&addr.a6) test > - Simplified tests of acceptable address types > - Merged documentation and code commits > - Some documentation text clarifications > --- > conf.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++---------- > inany.c | 29 +++++++++++++++++ > inany.h | 1 + > ip.c | 21 +++++++++++++ > ip.h | 2 ++ > passt.1 | 17 +++++++--- > 6 files changed, 145 insertions(+), 22 deletions(-) > > diff --git a/conf.c b/conf.c > index 2942c8c..7178a0e 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,52 @@ 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) Nit: ^ this should be a tab, not a space > + * > + * 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) cppcheck reports: conf.c:710:39: style: Parameter 'arg' can be declared as pointer to const [constParameterPointer] static int conf_addr_prefix_len(char *arg, union inany_addr *addr, ^ > +{ > + 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_prefix_pton(arg, addr, prefix_len)) > + 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 +942,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 +1545,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; Nit: this should go one line above. > enum fwd_ports_mode fwd_default = FWD_NONE; > bool v4_only = false, v6_only = false; > unsigned dns4_idx = 0, dns6_idx = 0; > @@ -1808,35 +1855,51 @@ 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); conf_addr_prefix_len() returns -1 on error, but it's not checked here, and there are no other callers. > + > + if (inany_is_unspecified(&addr) || ...as a result of not checking for that, clang-tidy here complains that: /home/sbrivio/passt/inany.h:94:7: error: The left operand of '==' is a garbage value [clang-analyzer-core.UndefinedBinaryOperatorResult,-warnings-as-errors] 94 | if (!IN6_IS_ADDR_V4MAPPED(&addr->a6)) | ^ /usr/include/netinet/in.h:464:35: note: expanded from macro 'IN6_IS_ADDR_V4MAPPED' 464 | __a->__in6_u.__u6_addr32[0] == 0 \ | ^ /home/sbrivio/passt/conf.c:1571:25: note: Assuming field 'mode' is not equal to MODE_PASTA 1571 | const char *logname = (c->mode == MODE_PASTA) ? "pasta" : "passt"; | ^~~~~~~~~~~~~~~~~~~~~ /home/sbrivio/passt/conf.c:1571:24: note: '?' condition is false 1571 | const char *logname = (c->mode == MODE_PASTA) ? "pasta" : "passt"; | ^ /home/sbrivio/passt/conf.c:1589:9: note: Field 'mode' is not equal to MODE_PASTA 1589 | if (c->mode == MODE_PASTA) { | ^ /home/sbrivio/passt/conf.c:1589:2: note: Taking false branch 1589 | if (c->mode == MODE_PASTA) { | ^ /home/sbrivio/passt/conf.c:1594:6: note: Assuming the condition is false 1594 | if (tap_l2_max_len(c) - ETH_HLEN < max_mtu) | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /home/sbrivio/passt/conf.c:1594:2: note: Taking false branch 1594 | if (tap_l2_max_len(c) - ETH_HLEN < max_mtu) | ^ /home/sbrivio/passt/conf.c:1605:3: note: Control jumps to 'case 97:' at line 1884 1605 | switch (name) { | ^ /home/sbrivio/passt/conf.c:1890:9: note: Calling 'conf_addr_prefix_len' 1890 | af = conf_addr_prefix_len(optarg, &addr, &prefix_len); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /home/sbrivio/passt/conf.c:719:6: note: Assuming 'slash' is non-null 719 | if (slash) { | ^~~~~ /home/sbrivio/passt/conf.c:719:2: note: Taking true branch 719 | if (slash) { | ^ /home/sbrivio/passt/conf.c:726:7: note: Assuming the condition is true 726 | if (errno || *end) | ^ /usr/include/errno.h:38:16: note: expanded from macro 'errno' 38 | # define errno (*__errno_location ()) | ^~~~~~~~~~~~~~~~~~~~~~ /home/sbrivio/passt/conf.c:726:13: note: Left side of '||' is true 726 | if (errno || *end) | ^ /home/sbrivio/passt/conf.c:1890:9: note: Returning from 'conf_addr_prefix_len' 1890 | af = conf_addr_prefix_len(optarg, &addr, &prefix_len); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /home/sbrivio/passt/conf.c:1892:8: note: Calling 'inany_is_unspecified' 1892 | if (inany_is_unspecified(&addr) || | ^~~~~~~~~~~~~~~~~~~~~~~~~~~ /home/sbrivio/passt/inany.h:197:9: note: Calling 'inany_is_unspecified4' 197 | return inany_is_unspecified4(a) || inany_is_unspecified6(a); | ^~~~~~~~~~~~~~~~~~~~~~~~ /home/sbrivio/passt/inany.h:175:29: note: Calling 'inany_v4' 175 | const struct in_addr *v4 = inany_v4(a); | ^~~~~~~~~~~ /home/sbrivio/passt/inany.h:94:7: note: The left operand of '==' is a garbage value 94 | if (!IN6_IS_ADDR_V4MAPPED(&addr->a6)) | ^ /usr/include/netinet/in.h:464:35: note: expanded from macro 'IN6_IS_ADDR_V4MAPPED' 464 | __a->__in6_u.__u6_addr32[0] == 0 \ | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^ Suppressed 473708 warnings (473687 in non-user code, 21 NOLINT). Use -header-filter=.* to display errors from all non-system headers. Use -system-headers to display errors from system headers as well. 1 warning treated as error make: *** [Makefile:176: clang-tidy] Error 1 > + inany_is_multicast(&addr) || > + inany_is_loopback(&addr) || > + IN6_IS_ADDR_V4COMPAT(&addr.a6)) > + die("Invalid address: %s", optarg); This is already modified though, so: $ ./pasta -a 2001:db8::1/129 Invalid address: 2001:db8::1 which isn't really correct: it's invalid only because of the /129. > + > + if (af == AF_INET6) { > + 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)) { > - if (c->mode == MODE_PASTA) > - c->ip4.no_copy_addrs = true; Why is c->ip4.no_copy_addrs not set for -a anymore? The IPv6 equivalent still (correctly) is. > + a4 = inany_v4(&addr); > + if (af == AF_INET && a4) { > + c->ip4.addr = *a4; > + if (prefix_len) { > + if (prefix_from_opt) > + die("Can't mix CIDR with -n"); > + prefix_from_cidr = true; > + } else { > + prefix_len = ip4_default_prefix_len(a4); > + } > + c->ip4.prefix_len = prefix_len; > break; > } > > 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); > diff --git a/inany.c b/inany.c > index 7680439..f142a76 100644 > --- a/inany.c > +++ b/inany.c > @@ -57,3 +57,32 @@ int inany_pton(const char *src, union inany_addr *dst) > > return 0; > } > + > +/** inany_prefix_pton - Parse an IPv[46] address with prefix length adjustment > + * @src: IPv[46] address string > + * @dst: output buffer, filled with parsed address > + * @prefix_len: pointer to prefix length Nit: ^ this should be a tab, not a space > + * > + * Return: on success, 1, if no parseable address is found, 0 I think it's a bit difficult to read like this, what about "1 on success, 0 if no parsable address is found"? > + */ > +int inany_prefix_pton(const char *src, union inany_addr *dst, int *prefix_len) > +{ > + /* First try parsing as plain IPv4 */ > + if (inet_pton(AF_INET, src, &dst->v4mapped.a4)) { > + memset(&dst->v4mapped.zero, 0, sizeof(dst->v4mapped.zero)); > + memset(&dst->v4mapped.one, 0xff, sizeof(dst->v4mapped.one)); > + return 1; > + } > + > + /* Try parsing as IPv6, adjust prefix length if mapped IPv4 address */ > + if (inet_pton(AF_INET6, src, &dst->a6)) { > + if (inany_v4(dst) && prefix_len && *prefix_len > 0) { > + if (*prefix_len < 96) > + return 0; > + *prefix_len -= 96; > + } > + return 1; > + } > + > + return 0; > +} > diff --git a/inany.h b/inany.h > index 61b36fb..36865f9 100644 > --- a/inany.h > +++ b/inany.h > @@ -295,5 +295,6 @@ static inline void inany_siphash_feed(struct siphash_state *state, > > const char *inany_ntop(const union inany_addr *src, char *dst, socklen_t size); > int inany_pton(const char *src, union inany_addr *dst); > +int inany_prefix_pton(const char *src, union inany_addr *dst, int *prefix_len); > > #endif /* INANY_H */ > diff --git a/ip.c b/ip.c > index 9a7f4c5..2519c71 100644 > --- a/ip.c > +++ b/ip.c > @@ -13,6 +13,8 @@ > */ > > #include > +#include > + > #include "util.h" > #include "ip.h" > > @@ -67,3 +69,22 @@ found: > *proto = nh; > return true; > } > + > +/** > + * ip4_default_prefix_len() - Get default prefix length for IPv4 address > + * @addr: IPv4 address > + * > + * Return: prefix length based on address class (8/16/24), or 32 for other > + */ > +int ip4_default_prefix_len(const struct in_addr *addr) > +{ > + in_addr_t a = ntohl(addr->s_addr); > + > + if (IN_CLASSA(a)) > + return 8; This is defined as IN_CLASSA_NSHIFT, and there are similar constants defined for the values below. See conf_ip4(), which should now be changed to use this function instead. > + if (IN_CLASSB(a)) > + return 16; > + if (IN_CLASSC(a)) > + return 24; > + return 32; > +} > diff --git a/ip.h b/ip.h > index 5830b92..e5f5198 100644 > --- a/ip.h > +++ b/ip.h > @@ -135,4 +135,6 @@ static const struct in_addr in4addr_broadcast = { 0xffffffff }; > #define IPV6_MIN_MTU 1280 > #endif > > +int ip4_default_prefix_len(const struct in_addr *addr); > + > #endif /* IP_H */ > diff --git a/passt.1 b/passt.1 > index db0d662..7ca03be 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] \fB\fR\fI: 1. sets a bold typeface 2. resets the formatting (clearing the bold typeface) 3. sets an italic typeface 1. and 2. can be dropped. > 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. > +An optional \fB/\fR\fIprefix_len\fR (0-32 for IPv4, 0-128 for IPv6) can be Same here. /0 is accepted, but the address isn't actually set (just tried with IPv4). > +appended in CIDR notation (e.g., 192.168.1.1/24). This is an alternative to Redundant comma after e.g., example addresses should be from TEST-NET blocks (RFC 5373, e.g. 192.0.2.1). > +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,10 +176,13 @@ 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). > -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). > +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. > +If no address is indicated, the netmask associated with the adopted host address, > +if any, is used. If an address is indicated, but without a prefix length, the > +netmask is determined based on the corresponding network class. In all other > +cases, the netmask is determined by using the indicated prefix length. > > .TP > .BR \-M ", " \-\-mac-addr " " \fIaddr I'll need a bit longer to review the rest of the series. -- Stefano