On Mon, 30 Mar 2026 23:57:10 +0200
Stefano Brivio
On Sat, 21 Mar 2026 20:43:22 -0400 Jon Maloy
wrote: [...]
+/** + * fwd_get_addr() - Get guest address entry matching criteria + * @c: Execution context + * @af: Address family (AF_INET, AF_INET6, or 0 for any) + * @incl: Flags that must be present (any-match) + * @excl: Flags that must not be present + * + * Return: first address entry matching criteria, or NULL + */ +const struct guest_addr *fwd_get_addr(const struct ctx *c, sa_family_t af, + uint8_t incl, uint8_t excl) +{ + const struct guest_addr *a; + + for_each_addr(a, c, af) { + if (incl && !(a->flags & incl)) + continue; + if (a->flags & excl) + continue;
Slightly less generic, but maybe good enough for this purpose: you could admit a set of flags, or a negation of a flag (for example ~CONF_ADDR_USER), in a single argument.
See how conn_flag_do() does that. Here it would be something like:
if (flags & (flags - 1)) { if (a->flags & ~flag) continue; } else { if (!(a->flags & flag)) continue; }
...it makes callers more readable in my opinion, for example:
a = fwd_get_addr(c, AF_INET6, ~CONF_ADDR_LINKLOCAL);
which makes it entirely clear you're selecting all addresses that are link-local, compared to:
a = fwd_get_addr(c, AF_INET6, 0, CONF_ADDR_LINKLOCAL);
which forces the reader to look up the prototype.
But again it's less generic, you can't exclude multiple flags like that. Unless... you define a reserved bit which is always 0 in that uint8_t, so that if you pass it as 1, you can conclude a negated set of flags was passed.
...at least until I finally reached 9/13 where you pass both matching and non-matching flags, and my trick doesn't work anymore. Oops, sorry. -- Stefano