From 42c49e8c3bc4f8dc8cf63511201675ba6da7c1e8 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Fri, 10 Apr 2026 11:02:59 +1000 Subject: conf: Rework stepping through chunks of port specifiers Port specifier strings are made up of ',' separated chunks. Rework the logic we use to step through the chunks. Specifically, maintain a pointer to the end of each chunk as well as the start. This is not really used yet, but will be useful in future. This also has side effect on semantics. Previously an empty specifier (0 chunks) was not accepted. Now it is, and will be treated as an "exclude only" spec which excludes only ephemeral ports. This seems a bit odd, and I don't expect it to be (directly) used in practice. However, it falls naturally out of the existing semantics, and will combine well with some upcoming changes. Signed-off-by: David Gibson Signed-off-by: Stefano Brivio --- conf.c | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/conf.c b/conf.c index 18d9223..91a6f80 100644 --- a/conf.c +++ b/conf.c @@ -65,21 +65,6 @@ const char *pasta_default_ifn = "tap0"; -/** - * next_chunk() - Return the next piece of a string delimited by a character - * @s: String to search - * @c: Delimiter character - * - * Return: if another @c is found in @s, returns a pointer to the - * character *after* the delimiter, if no further @c is in @s, - * return NULL - */ -static const char *next_chunk(const char *s, char c) -{ - char *sep = strchr(s, c); - return sep ? sep + 1 : NULL; -} - /** * port_range() - Represents a non-empty range of ports * @first: First port number in the range @@ -232,6 +217,18 @@ fail: fwd_rule_fmt(&rule, rulestr, sizeof(rulestr))); } +/* + * for_each_chunk - Step through delimited chunks of a string + * @p_: Pointer to start of each chunk (updated) + * @ep_: Pointer to end of each chunk (updated) + * @s_: String to step through + * @sep_: String of all allowed delimiters + */ +#define for_each_chunk(p_, ep_, s_, sep_) \ + for ((p_) = (s_); \ + (ep_) = (p_) + strcspn((p_), (sep_)), *(p_); \ + (p_) = *(ep_) ? (ep_) + 1 : (ep_)) + /** * conf_ports_spec() - Parse port range(s) specifier * @c: Execution context @@ -251,12 +248,11 @@ static void conf_ports_spec(const struct ctx *c, { uint8_t exclude[PORT_BITMAP_SIZE] = { 0 }; bool exclude_only = true; - const char *p; + const char *p, *ep; unsigned i; /* Mark all exclusions first, they might be given after base ranges */ - p = spec; - do { + for_each_chunk(p, ep, spec, ",") { struct port_range xrange; if (*p != '~') { @@ -273,7 +269,7 @@ static void conf_ports_spec(const struct ctx *c, for (i = xrange.first; i <= xrange.last; i++) bitmap_set(exclude, i); - } while ((p = next_chunk(p, ','))); + } if (exclude_only) { /* Exclude ephemeral ports */ @@ -287,8 +283,7 @@ static void conf_ports_spec(const struct ctx *c, } /* Now process base ranges, skipping exclusions */ - p = spec; - do { + for_each_chunk(p, ep, spec, ",") { struct port_range orig_range, mapped_range; if (*p == '~') @@ -321,7 +316,7 @@ static void conf_ports_spec(const struct ctx *c, orig_range.first, orig_range.last, exclude, mapped_range.first, 0); - } while ((p = next_chunk(p, ','))); + } return; bad: -- cgit v1.2.3