netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RESEND PATCH v1 wireguard-tools] ipc: linux: Support incremental allowed ips updates
@ 2025-05-17 19:29 Jordan Rife
  2025-05-17 19:29 ` [RESEND PATCH v3 net-next] wireguard: allowedips: Add WGALLOWEDIP_F_REMOVE_ME flag Jordan Rife
  2025-05-20 20:14 ` [RESEND PATCH v1 wireguard-tools] ipc: linux: Support incremental allowed ips updates Jason A. Donenfeld
  0 siblings, 2 replies; 15+ messages in thread
From: Jordan Rife @ 2025-05-17 19:29 UTC (permalink / raw)
  To: wireguard, Jason A. Donenfeld
  Cc: Jordan Rife, netdev, Jakub Kicinski, Daniel Borkmann

Extend the interface of `wg set` to leverage the WGALLOWEDIP_F_REMOVE_ME
flag, a direct way of removing a single allowed ip from a peer,
allowing for incremental updates to a peer's configuration. By default,
allowed-ips fully replaces a peer's allowed ips using
WGPEER_REPLACE_ALLOWEDIPS under the hood. When '+' or '-' is prepended
to any ip in the list, wg clears WGPEER_F_REPLACE_ALLOWEDIPS and sets
the WGALLOWEDIP_F_REMOVE_ME flag on any ip prefixed with '-'.

$ wg set wg0 peer <PUBKEY> allowed-ips +192.168.88.0/24,-192.168.0.1/32

This command means "add 192.168.88.0/24 to this peer's allowed ips if
not present, and remove 192.168.0.1/32 if present".

Use -isystem so that headers in uapi/ take precedence over system
headers; otherwise, the build will fail on systems running kernels
without the WGALLOWEDIP_F_REMOVE_ME flag.

Note that this patch is meant to be merged alongside the kernel patch
that introduces the flag.

Signed-off-by: Jordan Rife <jordan@jrife.io>
---
 src/Makefile                     |  2 +-
 src/config.c                     | 27 +++++++++++++++++++++++++++
 src/containers.h                 |  5 +++++
 src/ipc-linux.h                  |  2 ++
 src/man/wg.8                     |  8 ++++++--
 src/set.c                        |  2 +-
 src/uapi/linux/linux/wireguard.h |  9 +++++++++
 7 files changed, 51 insertions(+), 4 deletions(-)

diff --git a/src/Makefile b/src/Makefile
index 0533910..1c4b3f6 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -39,7 +39,7 @@ PLATFORM ?= $(shell uname -s | tr '[:upper:]' '[:lower:]')
 
 CFLAGS ?= -O3
 ifneq ($(wildcard uapi/$(PLATFORM)/.),)
-CFLAGS += -idirafter uapi/$(PLATFORM)
+CFLAGS += -isystem uapi/$(PLATFORM)
 endif
 CFLAGS += -std=gnu99 -D_GNU_SOURCE
 CFLAGS += -Wall -Wextra
diff --git a/src/config.c b/src/config.c
index 81ccb47..b740f73 100644
--- a/src/config.c
+++ b/src/config.c
@@ -337,6 +337,29 @@ static bool validate_netmask(struct wgallowedip *allowedip)
 	return true;
 }
 
+#if defined(__linux__)
+static inline void parse_ip_prefix(struct wgpeer *peer, uint32_t *flags, char **mask)
+{
+	/* If the IP is prefixed with either '+' or '-' consider
+	 * this an incremental change. Disable WGPEER_REPLACE_ALLOWEDIPS.
+	 */
+	switch ((*mask)[0]) {
+	case '-':
+		*flags |= WGALLOWEDIP_REMOVE_ME;
+		/* fall through */
+	case '+':
+		peer->flags &= ~WGPEER_REPLACE_ALLOWEDIPS;
+		(*mask)++;
+	}
+}
+#else
+static inline void parse_ip_prefix(struct wgpeer *peer __attribute__ ((unused)),
+				   uint32_t *flags     __attribute__ ((unused)),
+				   char **mask         __attribute__ ((unused)))
+{
+}
+#endif
+
 static inline bool parse_allowedips(struct wgpeer *peer, struct wgallowedip **last_allowedip, const char *value)
 {
 	struct wgallowedip *allowedip = *last_allowedip, *new_allowedip;
@@ -353,9 +376,12 @@ static inline bool parse_allowedips(struct wgpeer *peer, struct wgallowedip **la
 	}
 	sep = mutable;
 	while ((mask = strsep(&sep, ","))) {
+		uint32_t flags = 0;
 		unsigned long cidr;
 		char *end, *ip;
 
+		parse_ip_prefix(peer, &flags, &mask);
+
 		saved_entry = strdup(mask);
 		ip = strsep(&mask, "/");
 
@@ -387,6 +413,7 @@ static inline bool parse_allowedips(struct wgpeer *peer, struct wgallowedip **la
 		else
 			goto err;
 		new_allowedip->cidr = cidr;
+		new_allowedip->flags = flags;
 
 		if (!validate_netmask(new_allowedip))
 			fprintf(stderr, "Warning: AllowedIP has nonzero host part: %s/%s\n", ip, mask);
diff --git a/src/containers.h b/src/containers.h
index a82e8dd..8fd813a 100644
--- a/src/containers.h
+++ b/src/containers.h
@@ -28,6 +28,10 @@ struct timespec64 {
 	int64_t tv_nsec;
 };
 
+enum {
+	WGALLOWEDIP_REMOVE_ME = 1U << 0,
+};
+
 struct wgallowedip {
 	uint16_t family;
 	union {
@@ -35,6 +39,7 @@ struct wgallowedip {
 		struct in6_addr ip6;
 	};
 	uint8_t cidr;
+	uint32_t flags;
 	struct wgallowedip *next_allowedip;
 };
 
diff --git a/src/ipc-linux.h b/src/ipc-linux.h
index d29c0c5..01247f1 100644
--- a/src/ipc-linux.h
+++ b/src/ipc-linux.h
@@ -228,6 +228,8 @@ again:
 				}
 				if (!mnl_attr_put_u8_check(nlh, SOCKET_BUFFER_SIZE, WGALLOWEDIP_A_CIDR_MASK, allowedip->cidr))
 					goto toobig_allowedips;
+				if (allowedip->flags && !mnl_attr_put_u32_check(nlh, SOCKET_BUFFER_SIZE, WGALLOWEDIP_A_FLAGS, allowedip->flags))
+					goto toobig_allowedips;
 				mnl_attr_nest_end(nlh, allowedip_nest);
 				allowedip_nest = NULL;
 			}
diff --git a/src/man/wg.8 b/src/man/wg.8
index 7984539..1ec68df 100644
--- a/src/man/wg.8
+++ b/src/man/wg.8
@@ -55,7 +55,7 @@ transfer-rx, transfer-tx, persistent-keepalive.
 Shows the current configuration of \fI<interface>\fP in the format described
 by \fICONFIGURATION FILE FORMAT\fP below.
 .TP
-\fBset\fP \fI<interface>\fP [\fIlisten-port\fP \fI<port>\fP] [\fIfwmark\fP \fI<fwmark>\fP] [\fIprivate-key\fP \fI<file-path>\fP] [\fIpeer\fP \fI<base64-public-key>\fP [\fIremove\fP] [\fIpreshared-key\fP \fI<file-path>\fP] [\fIendpoint\fP \fI<ip>:<port>\fP] [\fIpersistent-keepalive\fP \fI<interval seconds>\fP] [\fIallowed-ips\fP \fI<ip1>/<cidr1>\fP[,\fI<ip2>/<cidr2>\fP]...] ]...
+\fBset\fP \fI<interface>\fP [\fIlisten-port\fP \fI<port>\fP] [\fIfwmark\fP \fI<fwmark>\fP] [\fIprivate-key\fP \fI<file-path>\fP] [\fIpeer\fP \fI<base64-public-key>\fP [\fIremove\fP] [\fIpreshared-key\fP \fI<file-path>\fP] [\fIendpoint\fP \fI<ip>:<port>\fP] [\fIpersistent-keepalive\fP \fI<interval seconds>\fP] [\fIallowed-ips\fP \fI[+|-]<ip1>/<cidr1>\fP[,\fI[+|-]<ip2>/<cidr2>\fP]...] ]...
 Sets configuration values for the specified \fI<interface>\fP. Multiple
 \fIpeer\fPs may be specified, and if the \fIremove\fP argument is given
 for a peer, that peer is removed, not configured. If \fIlisten-port\fP
@@ -72,7 +72,11 @@ the device. The use of \fIpreshared-key\fP is optional, and may be omitted;
 it adds an additional layer of symmetric-key cryptography to be mixed into
 the already existing public-key cryptography, for post-quantum resistance.
 If \fIallowed-ips\fP is specified, but the value is the empty string, all
-allowed ips are removed from the peer. The use of \fIpersistent-keepalive\fP
+allowed ips are removed from the peer. By default, \fIallowed-ips\fP replaces
+a peer's allowed ips. (Linux only) If + or - is prepended to any of the ips then
+the update is incremental; ips prefixed with '+' or '' are added to the peer's
+allowed ips if not present while ips prefixed with '-' are removed if present.
+The use of \fIpersistent-keepalive\fP
 is optional and is by default off; setting it to 0 or "off" disables it.
 Otherwise it represents, in seconds, between 1 and 65535 inclusive, how often
 to send an authenticated empty packet to the peer, for the purpose of keeping
diff --git a/src/set.c b/src/set.c
index 75560fd..992ffa2 100644
--- a/src/set.c
+++ b/src/set.c
@@ -18,7 +18,7 @@ int set_main(int argc, const char *argv[])
 	int ret = 1;
 
 	if (argc < 3) {
-		fprintf(stderr, "Usage: %s %s <interface> [listen-port <port>] [fwmark <mark>] [private-key <file path>] [peer <base64 public key> [remove] [preshared-key <file path>] [endpoint <ip>:<port>] [persistent-keepalive <interval seconds>] [allowed-ips <ip1>/<cidr1>[,<ip2>/<cidr2>]...] ]...\n", PROG_NAME, argv[0]);
+		fprintf(stderr, "Usage: %s %s <interface> [listen-port <port>] [fwmark <mark>] [private-key <file path>] [peer <base64 public key> [remove] [preshared-key <file path>] [endpoint <ip>:<port>] [persistent-keepalive <interval seconds>] [allowed-ips [+|-]<ip1>/<cidr1>[,[+|-]<ip2>/<cidr2>]...] ]...\n", PROG_NAME, argv[0]);
 		return 1;
 	}
 
diff --git a/src/uapi/linux/linux/wireguard.h b/src/uapi/linux/linux/wireguard.h
index 0efd52c..6ca266a 100644
--- a/src/uapi/linux/linux/wireguard.h
+++ b/src/uapi/linux/linux/wireguard.h
@@ -101,6 +101,10 @@
  *                    WGALLOWEDIP_A_FAMILY: NLA_U16
  *                    WGALLOWEDIP_A_IPADDR: struct in_addr or struct in6_addr
  *                    WGALLOWEDIP_A_CIDR_MASK: NLA_U8
+ *                    WGALLOWEDIP_A_FLAGS: NLA_U32, WGALLOWEDIP_F_REMOVE_ME if
+ *                                         the specified IP should be removed;
+ *                                         otherwise, this IP will be added if
+ *                                         it is not already present.
  *                0: NLA_NESTED
  *                    ...
  *                0: NLA_NESTED
@@ -184,11 +188,16 @@ enum wgpeer_attribute {
 };
 #define WGPEER_A_MAX (__WGPEER_A_LAST - 1)
 
+enum wgallowedip_flag {
+	WGALLOWEDIP_F_REMOVE_ME = 1U << 0,
+	__WGALLOWEDIP_F_ALL = WGALLOWEDIP_F_REMOVE_ME
+};
 enum wgallowedip_attribute {
 	WGALLOWEDIP_A_UNSPEC,
 	WGALLOWEDIP_A_FAMILY,
 	WGALLOWEDIP_A_IPADDR,
 	WGALLOWEDIP_A_CIDR_MASK,
+	WGALLOWEDIP_A_FLAGS,
 	__WGALLOWEDIP_A_LAST
 };
 #define WGALLOWEDIP_A_MAX (__WGALLOWEDIP_A_LAST - 1)
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [RESEND PATCH v3 net-next] wireguard: allowedips: Add WGALLOWEDIP_F_REMOVE_ME flag
  2025-05-17 19:29 [RESEND PATCH v1 wireguard-tools] ipc: linux: Support incremental allowed ips updates Jordan Rife
@ 2025-05-17 19:29 ` Jordan Rife
  2025-05-20 21:47   ` Jason A. Donenfeld
                     ` (2 more replies)
  2025-05-20 20:14 ` [RESEND PATCH v1 wireguard-tools] ipc: linux: Support incremental allowed ips updates Jason A. Donenfeld
  1 sibling, 3 replies; 15+ messages in thread
From: Jordan Rife @ 2025-05-17 19:29 UTC (permalink / raw)
  To: wireguard, Jason A. Donenfeld
  Cc: Jordan Rife, netdev, Jakub Kicinski, Daniel Borkmann

The current netlink API for WireGuard does not directly support removal
of allowed ips from a peer. A user can remove an allowed ip from a peer
in one of two ways:

1. By using the WGPEER_F_REPLACE_ALLOWEDIPS flag and providing a new
   list of allowed ips which omits the allowed ip that is to be removed.
2. By reassigning an allowed ip to a "dummy" peer then removing that
   peer with WGPEER_F_REMOVE_ME.

With the first approach, the driver completely rebuilds the allowed ip
list for a peer. If my current configuration is such that a peer has
allowed ips 192.168.0.2 and 192.168.0.3 and I want to remove 192.168.0.2
the actual transition looks like this.

[192.168.0.2, 192.168.0.3] <-- Initial state
[]                         <-- Step 1: Allowed ips removed for peer
[192.168.0.3]              <-- Step 2: Allowed ips added back for peer

This is true even if the allowed ip list is small and the update does
not need to be batched into multiple WG_CMD_SET_DEVICE requests, as the
removal and subsequent addition of ips is non-atomic within a single
request. Consequently, wg_allowedips_lookup_dst and
wg_allowedips_lookup_src may return NULL while reconfiguring a peer even
for packets bound for ips a user did not intend to remove leading to
unintended interruptions in connectivity. This presents in userspace as
failed calls to sendto and sendmsg for UDP sockets. In my case, I ran
netperf while repeatedly reconfiguring the allowed ips for a peer with
wg.

/usr/local/bin/netperf -H 10.102.73.72 -l 10m -t UDP_STREAM -- -R 1 -m 1024
send_data: data send error: No route to host (errno 113)
netperf: send_omni: send_data failed: No route to host

While this may not be of particular concern for environments where peers
and allowed ips are mostly static, systems like Cilium manage peers and
allowed ips in a dynamic environment where peers (i.e. Kubernetes nodes)
and allowed ips (i.e. pods running on those nodes) can frequently
change making WGPEER_F_REPLACE_ALLOWEDIPS problematic.

The second approach avoids any possible connectivity interruptions
but is hacky and less direct, requiring the creation of a temporary
peer just to dispose of an allowed ip.

Introduce a new flag called WGALLOWEDIP_F_REMOVE_ME which in the same
way that WGPEER_F_REMOVE_ME allows a user to remove a single peer from
a WireGuard device's configuration allows a user to remove an ip from a
peer's set of allowed ips. This enables incremental updates to a
device's configuration without any connectivity blips or messy
workarounds.

A corresponding patch for wg extends the existing `wg set` interface to
leverage this feature.

$ wg set wg0 peer <PUBKEY> allowed-ips +192.168.88.0/24,-192.168.0.1/32

When '+' or '-' is prepended to any ip in the list, wg clears
WGPEER_F_REPLACE_ALLOWEDIPS and sets the WGALLOWEDIP_F_REMOVE_ME flag on
any ip prefixed with '-'.

v2->v3
------
* Revert WG_GENL_VERSION back to 1 (Jason).
* Rename _remove() to remove_node() (Jason).
* Remove unnecessary !peer guard from remove() (Jason).
* Adjust line length for calls to wg_allowedips_(remove|insert)_v(4|6)
  (Jason).
* Fix punctuation inside uapi docs for WGALLOWEDIP_A_FLAGS (Jason).
* Get rid of remove-ip program and use wg instead in selftests (Jason).
* Use NLA_POLICY_MASK for WGALLOWEDIP_A_FLAGS validation (Jakub).

v1->v2
------
* Fixed some Sparse warnings.

Link: https://lore.kernel.org/netdev/20240905200551.4099064-1-jrife@google.com/
Signed-off-by: Jordan Rife <jordan@jrife.io>
---
 drivers/net/wireguard/allowedips.c          | 106 ++++++++++++++------
 drivers/net/wireguard/allowedips.h          |   4 +
 drivers/net/wireguard/netlink.c             |  37 ++++---
 drivers/net/wireguard/selftest/allowedips.c |  48 +++++++++
 include/uapi/linux/wireguard.h              |   9 ++
 tools/testing/selftests/wireguard/netns.sh  |  32 ++++++
 6 files changed, 193 insertions(+), 43 deletions(-)

diff --git a/drivers/net/wireguard/allowedips.c b/drivers/net/wireguard/allowedips.c
index 4b8528206cc8..dcf068ba2881 100644
--- a/drivers/net/wireguard/allowedips.c
+++ b/drivers/net/wireguard/allowedips.c
@@ -249,6 +249,56 @@ static int add(struct allowedips_node __rcu **trie, u8 bits, const u8 *key,
 	return 0;
 }
 
+static void remove_node(struct allowedips_node *node, struct mutex *lock)
+{
+	struct allowedips_node *child, **parent_bit, *parent;
+	bool free_parent;
+
+	list_del_init(&node->peer_list);
+	RCU_INIT_POINTER(node->peer, NULL);
+	if (node->bit[0] && node->bit[1])
+		return;
+	child = rcu_dereference_protected(node->bit[!rcu_access_pointer(node->bit[0])],
+					  lockdep_is_held(lock));
+	if (child)
+		child->parent_bit_packed = node->parent_bit_packed;
+	parent_bit = (struct allowedips_node **)(node->parent_bit_packed & ~3UL);
+	*parent_bit = child;
+	parent = (void *)parent_bit -
+			offsetof(struct allowedips_node, bit[node->parent_bit_packed & 1]);
+	free_parent = !rcu_access_pointer(node->bit[0]) &&
+			!rcu_access_pointer(node->bit[1]) &&
+			(node->parent_bit_packed & 3) <= 1 &&
+			!rcu_access_pointer(parent->peer);
+	if (free_parent)
+		child = rcu_dereference_protected(parent->bit[!(node->parent_bit_packed & 1)],
+						  lockdep_is_held(lock));
+	call_rcu(&node->rcu, node_free_rcu);
+	if (!free_parent)
+		return;
+	if (child)
+		child->parent_bit_packed = parent->parent_bit_packed;
+	*(struct allowedips_node **)(parent->parent_bit_packed & ~3UL) = child;
+	call_rcu(&parent->rcu, node_free_rcu);
+}
+
+static int remove(struct allowedips_node __rcu **trie, u8 bits, const u8 *key,
+		  u8 cidr, struct wg_peer *peer, struct mutex *lock)
+{
+	struct allowedips_node *node;
+
+	if (unlikely(cidr > bits))
+		return -EINVAL;
+	if (!rcu_access_pointer(*trie) ||
+	    !node_placement(*trie, key, cidr, bits, &node, lock) ||
+	    peer != rcu_access_pointer(node->peer))
+		return 0;
+
+	remove_node(node, lock);
+
+	return 0;
+}
+
 void wg_allowedips_init(struct allowedips *table)
 {
 	table->root4 = table->root6 = NULL;
@@ -300,44 +350,38 @@ int wg_allowedips_insert_v6(struct allowedips *table, const struct in6_addr *ip,
 	return add(&table->root6, 128, key, cidr, peer, lock);
 }
 
+int wg_allowedips_remove_v4(struct allowedips *table, const struct in_addr *ip,
+			    u8 cidr, struct wg_peer *peer, struct mutex *lock)
+{
+	/* Aligned so it can be passed to fls */
+	u8 key[4] __aligned(__alignof(u32));
+
+	++table->seq;
+	swap_endian(key, (const u8 *)ip, 32);
+	return remove(&table->root4, 32, key, cidr, peer, lock);
+}
+
+int wg_allowedips_remove_v6(struct allowedips *table, const struct in6_addr *ip,
+			    u8 cidr, struct wg_peer *peer, struct mutex *lock)
+{
+	/* Aligned so it can be passed to fls64 */
+	u8 key[16] __aligned(__alignof(u64));
+
+	++table->seq;
+	swap_endian(key, (const u8 *)ip, 128);
+	return remove(&table->root6, 128, key, cidr, peer, lock);
+}
+
 void wg_allowedips_remove_by_peer(struct allowedips *table,
 				  struct wg_peer *peer, struct mutex *lock)
 {
-	struct allowedips_node *node, *child, **parent_bit, *parent, *tmp;
-	bool free_parent;
+	struct allowedips_node *node, *tmp;
 
 	if (list_empty(&peer->allowedips_list))
 		return;
 	++table->seq;
-	list_for_each_entry_safe(node, tmp, &peer->allowedips_list, peer_list) {
-		list_del_init(&node->peer_list);
-		RCU_INIT_POINTER(node->peer, NULL);
-		if (node->bit[0] && node->bit[1])
-			continue;
-		child = rcu_dereference_protected(node->bit[!rcu_access_pointer(node->bit[0])],
-						  lockdep_is_held(lock));
-		if (child)
-			child->parent_bit_packed = node->parent_bit_packed;
-		parent_bit = (struct allowedips_node **)(node->parent_bit_packed & ~3UL);
-		*parent_bit = child;
-		parent = (void *)parent_bit -
-			 offsetof(struct allowedips_node, bit[node->parent_bit_packed & 1]);
-		free_parent = !rcu_access_pointer(node->bit[0]) &&
-			      !rcu_access_pointer(node->bit[1]) &&
-			      (node->parent_bit_packed & 3) <= 1 &&
-			      !rcu_access_pointer(parent->peer);
-		if (free_parent)
-			child = rcu_dereference_protected(
-					parent->bit[!(node->parent_bit_packed & 1)],
-					lockdep_is_held(lock));
-		call_rcu(&node->rcu, node_free_rcu);
-		if (!free_parent)
-			continue;
-		if (child)
-			child->parent_bit_packed = parent->parent_bit_packed;
-		*(struct allowedips_node **)(parent->parent_bit_packed & ~3UL) = child;
-		call_rcu(&parent->rcu, node_free_rcu);
-	}
+	list_for_each_entry_safe(node, tmp, &peer->allowedips_list, peer_list)
+		remove_node(node, lock);
 }
 
 int wg_allowedips_read_node(struct allowedips_node *node, u8 ip[16], u8 *cidr)
diff --git a/drivers/net/wireguard/allowedips.h b/drivers/net/wireguard/allowedips.h
index 2346c797eb4d..931958cb6e10 100644
--- a/drivers/net/wireguard/allowedips.h
+++ b/drivers/net/wireguard/allowedips.h
@@ -38,6 +38,10 @@ int wg_allowedips_insert_v4(struct allowedips *table, const struct in_addr *ip,
 			    u8 cidr, struct wg_peer *peer, struct mutex *lock);
 int wg_allowedips_insert_v6(struct allowedips *table, const struct in6_addr *ip,
 			    u8 cidr, struct wg_peer *peer, struct mutex *lock);
+int wg_allowedips_remove_v4(struct allowedips *table, const struct in_addr *ip,
+			    u8 cidr, struct wg_peer *peer, struct mutex *lock);
+int wg_allowedips_remove_v6(struct allowedips *table, const struct in6_addr *ip,
+			    u8 cidr, struct wg_peer *peer, struct mutex *lock);
 void wg_allowedips_remove_by_peer(struct allowedips *table,
 				  struct wg_peer *peer, struct mutex *lock);
 /* The ip input pointer should be __aligned(__alignof(u64))) */
diff --git a/drivers/net/wireguard/netlink.c b/drivers/net/wireguard/netlink.c
index f7055180ba4a..386f65042072 100644
--- a/drivers/net/wireguard/netlink.c
+++ b/drivers/net/wireguard/netlink.c
@@ -46,7 +46,8 @@ static const struct nla_policy peer_policy[WGPEER_A_MAX + 1] = {
 static const struct nla_policy allowedip_policy[WGALLOWEDIP_A_MAX + 1] = {
 	[WGALLOWEDIP_A_FAMILY]		= { .type = NLA_U16 },
 	[WGALLOWEDIP_A_IPADDR]		= NLA_POLICY_MIN_LEN(sizeof(struct in_addr)),
-	[WGALLOWEDIP_A_CIDR_MASK]	= { .type = NLA_U8 }
+	[WGALLOWEDIP_A_CIDR_MASK]	= { .type = NLA_U8 },
+	[WGALLOWEDIP_A_FLAGS]		= NLA_POLICY_MASK(NLA_U32, __WGALLOWEDIP_F_ALL),
 };
 
 static struct wg_device *lookup_interface(struct nlattr **attrs,
@@ -329,6 +330,7 @@ static int set_port(struct wg_device *wg, u16 port)
 static int set_allowedip(struct wg_peer *peer, struct nlattr **attrs)
 {
 	int ret = -EINVAL;
+	u32 flags = 0;
 	u16 family;
 	u8 cidr;
 
@@ -337,19 +339,30 @@ static int set_allowedip(struct wg_peer *peer, struct nlattr **attrs)
 		return ret;
 	family = nla_get_u16(attrs[WGALLOWEDIP_A_FAMILY]);
 	cidr = nla_get_u8(attrs[WGALLOWEDIP_A_CIDR_MASK]);
+	if (attrs[WGALLOWEDIP_A_FLAGS])
+		flags = nla_get_u32(attrs[WGALLOWEDIP_A_FLAGS]);
 
 	if (family == AF_INET && cidr <= 32 &&
-	    nla_len(attrs[WGALLOWEDIP_A_IPADDR]) == sizeof(struct in_addr))
-		ret = wg_allowedips_insert_v4(
-			&peer->device->peer_allowedips,
-			nla_data(attrs[WGALLOWEDIP_A_IPADDR]), cidr, peer,
-			&peer->device->device_update_lock);
-	else if (family == AF_INET6 && cidr <= 128 &&
-		 nla_len(attrs[WGALLOWEDIP_A_IPADDR]) == sizeof(struct in6_addr))
-		ret = wg_allowedips_insert_v6(
-			&peer->device->peer_allowedips,
-			nla_data(attrs[WGALLOWEDIP_A_IPADDR]), cidr, peer,
-			&peer->device->device_update_lock);
+	    nla_len(attrs[WGALLOWEDIP_A_IPADDR]) == sizeof(struct in_addr)) {
+		if (flags & WGALLOWEDIP_F_REMOVE_ME)
+			ret = wg_allowedips_remove_v4(&peer->device->peer_allowedips,
+						      nla_data(attrs[WGALLOWEDIP_A_IPADDR]), cidr,
+						      peer, &peer->device->device_update_lock);
+		else
+			ret = wg_allowedips_insert_v4(&peer->device->peer_allowedips,
+						      nla_data(attrs[WGALLOWEDIP_A_IPADDR]), cidr,
+						      peer, &peer->device->device_update_lock);
+	} else if (family == AF_INET6 && cidr <= 128 &&
+		   nla_len(attrs[WGALLOWEDIP_A_IPADDR]) == sizeof(struct in6_addr)) {
+		if (flags & WGALLOWEDIP_F_REMOVE_ME)
+			ret = wg_allowedips_remove_v6(&peer->device->peer_allowedips,
+						      nla_data(attrs[WGALLOWEDIP_A_IPADDR]), cidr,
+						      peer, &peer->device->device_update_lock);
+		else
+			ret = wg_allowedips_insert_v6(&peer->device->peer_allowedips,
+						      nla_data(attrs[WGALLOWEDIP_A_IPADDR]), cidr,
+						      peer, &peer->device->device_update_lock);
+	}
 
 	return ret;
 }
diff --git a/drivers/net/wireguard/selftest/allowedips.c b/drivers/net/wireguard/selftest/allowedips.c
index 25de7058701a..41837efa70cb 100644
--- a/drivers/net/wireguard/selftest/allowedips.c
+++ b/drivers/net/wireguard/selftest/allowedips.c
@@ -460,6 +460,10 @@ static __init struct wg_peer *init_peer(void)
 	wg_allowedips_insert_v##version(&t, ip##version(ipa, ipb, ipc, ipd), \
 					cidr, mem, &mutex)
 
+#define remove(version, mem, ipa, ipb, ipc, ipd, cidr)                      \
+	wg_allowedips_remove_v##version(&t, ip##version(ipa, ipb, ipc, ipd), \
+					cidr, mem, &mutex)
+
 #define maybe_fail() do {                                               \
 		++i;                                                    \
 		if (!_s) {                                              \
@@ -585,6 +589,50 @@ bool __init wg_allowedips_selftest(void)
 	test_negative(4, a, 192, 0, 0, 0);
 	test_negative(4, a, 255, 0, 0, 0);
 
+	insert(4, a, 1, 0, 0, 0, 32);
+	insert(4, a, 192, 0, 0, 0, 24);
+	insert(6, a, 0x24446801, 0x40e40800, 0xdeaebeef, 0xdefbeef, 128);
+	insert(6, a, 0x24446800, 0xf0e40800, 0xeeaebeef, 0, 98);
+	test(4, a, 1, 0, 0, 0);
+	test(4, a, 192, 0, 0, 1);
+	test(6, a, 0x24446801, 0x40e40800, 0xdeaebeef, 0xdefbeef);
+	test(6, a, 0x24446800, 0xf0e40800, 0xeeaebeef, 0x10101010);
+	/* Must be an exact match to remove */
+	remove(4, a, 192, 0, 0, 0, 32);
+	test(4, a, 192, 0, 0, 1);
+	/* NULL peer should have no effect and return 0 */
+	test_boolean(!remove(4, NULL, 192, 0, 0, 0, 24));
+	test(4, a, 192, 0, 0, 1);
+	/* different peer should have no effect and return 0 */
+	test_boolean(!remove(4, b, 192, 0, 0, 0, 24));
+	test(4, a, 192, 0, 0, 1);
+	/* invalid CIDR should have no effect and return -EINVAL */
+	test_boolean(remove(4, b, 192, 0, 0, 0, 33) == -EINVAL);
+	test(4, a, 192, 0, 0, 1);
+	remove(4, a, 192, 0, 0, 0, 24);
+	test_negative(4, a, 192, 0, 0, 1);
+	remove(4, a, 1, 0, 0, 0, 32);
+	test_negative(4, a, 1, 0, 0, 0);
+	/* Must be an exact match to remove */
+	remove(6, a, 0x24446801, 0x40e40800, 0xdeaebeef, 0xdefbeef, 96);
+	test(6, a, 0x24446801, 0x40e40800, 0xdeaebeef, 0xdefbeef);
+	/* NULL peer should have no effect and return 0 */
+	test_boolean(!remove(6, NULL, 0x24446801, 0x40e40800, 0xdeaebeef, 0xdefbeef, 128));
+	test(6, a, 0x24446801, 0x40e40800, 0xdeaebeef, 0xdefbeef);
+	/* different peer should have no effect and return 0 */
+	test_boolean(!remove(6, b, 0x24446801, 0x40e40800, 0xdeaebeef, 0xdefbeef, 128));
+	test(6, a, 0x24446801, 0x40e40800, 0xdeaebeef, 0xdefbeef);
+	/* invalid CIDR should have no effect and return -EINVAL */
+	test_boolean(remove(6, a, 0x24446801, 0x40e40800, 0xdeaebeef, 0xdefbeef, 129)  == -EINVAL);
+	test(6, a, 0x24446801, 0x40e40800, 0xdeaebeef, 0xdefbeef);
+	remove(6, a, 0x24446801, 0x40e40800, 0xdeaebeef, 0xdefbeef, 128);
+	test_negative(6, a, 0x24446801, 0x40e40800, 0xdeaebeef, 0xdefbeef);
+	/* Must match the peer to remove */
+	remove(6, b, 0x24446800, 0xf0e40800, 0xeeaebeef, 0, 98);
+	test(6, a, 0x24446800, 0xf0e40800, 0xeeaebeef, 0x10101010);
+	remove(6, a, 0x24446800, 0xf0e40800, 0xeeaebeef, 0, 98);
+	test_negative(6, a, 0x24446800, 0xf0e40800, 0xeeaebeef, 0x10101010);
+
 	wg_allowedips_free(&t, &mutex);
 	wg_allowedips_init(&t);
 	insert(4, a, 192, 168, 0, 0, 16);
diff --git a/include/uapi/linux/wireguard.h b/include/uapi/linux/wireguard.h
index ae88be14c947..8c26391196d5 100644
--- a/include/uapi/linux/wireguard.h
+++ b/include/uapi/linux/wireguard.h
@@ -101,6 +101,10 @@
  *                    WGALLOWEDIP_A_FAMILY: NLA_U16
  *                    WGALLOWEDIP_A_IPADDR: struct in_addr or struct in6_addr
  *                    WGALLOWEDIP_A_CIDR_MASK: NLA_U8
+ *                    WGALLOWEDIP_A_FLAGS: NLA_U32, WGALLOWEDIP_F_REMOVE_ME if
+ *                                         the specified IP should be removed;
+ *                                         otherwise, this IP will be added if
+ *                                         it is not already present.
  *                0: NLA_NESTED
  *                    ...
  *                0: NLA_NESTED
@@ -184,11 +188,16 @@ enum wgpeer_attribute {
 };
 #define WGPEER_A_MAX (__WGPEER_A_LAST - 1)
 
+enum wgallowedip_flag {
+	WGALLOWEDIP_F_REMOVE_ME = 1U << 0,
+	__WGALLOWEDIP_F_ALL = WGALLOWEDIP_F_REMOVE_ME
+};
 enum wgallowedip_attribute {
 	WGALLOWEDIP_A_UNSPEC,
 	WGALLOWEDIP_A_FAMILY,
 	WGALLOWEDIP_A_IPADDR,
 	WGALLOWEDIP_A_CIDR_MASK,
+	WGALLOWEDIP_A_FLAGS,
 	__WGALLOWEDIP_A_LAST
 };
 #define WGALLOWEDIP_A_MAX (__WGALLOWEDIP_A_LAST - 1)
diff --git a/tools/testing/selftests/wireguard/netns.sh b/tools/testing/selftests/wireguard/netns.sh
index 55500f901fbc..70248c77ce11 100755
--- a/tools/testing/selftests/wireguard/netns.sh
+++ b/tools/testing/selftests/wireguard/netns.sh
@@ -611,6 +611,38 @@ n0 wg set wg0 peer "$pub2" allowed-ips "$allowedips"
 } < <(n0 wg show wg0 allowed-ips)
 ip0 link del wg0
 
+# Test IP removal
+allowedips=( )
+for i in {1..197}; do
+        allowedips+=( 192.168.0.$i )
+        allowedips+=( abcd::$i )
+done
+saved_ifs="$IFS"
+IFS=,
+allowedips="${allowedips[*]}"
+IFS="$saved_ifs"
+ip0 link add wg0 type wireguard
+n0 wg set wg0 peer "$pub1" allowed-ips "$allowedips"
+pub1_hex=$(echo "$pub1" | base64 -d | xxd -p -c 50)
+n0 wg set wg0 peer "$pub1" allowed-ips -192.168.0.1/32,-192.168.0.20/32,-192.168.0.100/32,-abcd::1/128,-abcd::20/128,-abcd::100/128
+n0 wg show wg0 allowed-ips
+{
+	read -r pub allowedips
+	[[ $pub == "$pub1" ]]
+	i=0
+	for ip in $allowedips; do
+		[[ "$ip" != "192.168.0.1" ]]
+		[[ "$ip" != "192.168.0.20" ]]
+		[[ "$ip" != "192.168.0.100" ]]
+		[[ "$ip" != "abcd::1" ]]
+		[[ "$ip" != "abcd::20" ]]
+		[[ "$ip" != "abcd::100" ]]
+		((++i))
+	done
+	((i == 388))
+} < <(n0 wg show wg0 allowed-ips)
+ip0 link del wg0
+
 ! n0 wg show doesnotexist || false
 
 ip0 link add wg0 type wireguard
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [RESEND PATCH v1 wireguard-tools] ipc: linux: Support incremental allowed ips updates
  2025-05-17 19:29 [RESEND PATCH v1 wireguard-tools] ipc: linux: Support incremental allowed ips updates Jordan Rife
  2025-05-17 19:29 ` [RESEND PATCH v3 net-next] wireguard: allowedips: Add WGALLOWEDIP_F_REMOVE_ME flag Jordan Rife
@ 2025-05-20 20:14 ` Jason A. Donenfeld
  2025-05-20 21:10   ` Jason A. Donenfeld
  1 sibling, 1 reply; 15+ messages in thread
From: Jason A. Donenfeld @ 2025-05-20 20:14 UTC (permalink / raw)
  To: Jordan Rife; +Cc: wireguard, netdev, Jakub Kicinski, Daniel Borkmann

On Sat, May 17, 2025 at 12:29:51PM -0700, Jordan Rife wrote:
> Extend the interface of `wg set` to leverage the WGALLOWEDIP_F_REMOVE_ME
> flag, a direct way of removing a single allowed ip from a peer,
> allowing for incremental updates to a peer's configuration. By default,
> allowed-ips fully replaces a peer's allowed ips using
> WGPEER_REPLACE_ALLOWEDIPS under the hood. When '+' or '-' is prepended
> to any ip in the list, wg clears WGPEER_F_REPLACE_ALLOWEDIPS and sets
> the WGALLOWEDIP_F_REMOVE_ME flag on any ip prefixed with '-'.
> 
> $ wg set wg0 peer <PUBKEY> allowed-ips +192.168.88.0/24,-192.168.0.1/32
> 
> This command means "add 192.168.88.0/24 to this peer's allowed ips if
> not present, and remove 192.168.0.1/32 if present".
> 
> Use -isystem so that headers in uapi/ take precedence over system
> headers; otherwise, the build will fail on systems running kernels
> without the WGALLOWEDIP_F_REMOVE_ME flag.
> 
> Note that this patch is meant to be merged alongside the kernel patch
> that introduces the flag.

Merged here:
https://git.zx2c4.com/wireguard-tools/commit/?id=0788f90810efde88cfa07ed96e7eca77c7f2eedd

With a followup here:
https://git.zx2c4.com/wireguard-tools/commit/?id=dce8ac6e2fa30f8b07e84859f244f81b3c6b2353

Sorry for the delay. Next, the kernel changes.

Regards,
Jason

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RESEND PATCH v1 wireguard-tools] ipc: linux: Support incremental allowed ips updates
  2025-05-20 20:14 ` [RESEND PATCH v1 wireguard-tools] ipc: linux: Support incremental allowed ips updates Jason A. Donenfeld
@ 2025-05-20 21:10   ` Jason A. Donenfeld
  2025-05-21 23:02     ` Jordan Rife
  0 siblings, 1 reply; 15+ messages in thread
From: Jason A. Donenfeld @ 2025-05-20 21:10 UTC (permalink / raw)
  To: Jordan Rife; +Cc: wireguard, netdev, Jakub Kicinski, Daniel Borkmann

On Tue, May 20, 2025 at 10:14:38PM +0200, Jason A. Donenfeld wrote:
> On Sat, May 17, 2025 at 12:29:51PM -0700, Jordan Rife wrote:
> > Extend the interface of `wg set` to leverage the WGALLOWEDIP_F_REMOVE_ME
> > flag, a direct way of removing a single allowed ip from a peer,
> > allowing for incremental updates to a peer's configuration. By default,
> > allowed-ips fully replaces a peer's allowed ips using
> > WGPEER_REPLACE_ALLOWEDIPS under the hood. When '+' or '-' is prepended
> > to any ip in the list, wg clears WGPEER_F_REPLACE_ALLOWEDIPS and sets
> > the WGALLOWEDIP_F_REMOVE_ME flag on any ip prefixed with '-'.
> > 
> > $ wg set wg0 peer <PUBKEY> allowed-ips +192.168.88.0/24,-192.168.0.1/32
> > 
> > This command means "add 192.168.88.0/24 to this peer's allowed ips if
> > not present, and remove 192.168.0.1/32 if present".
> > 
> > Use -isystem so that headers in uapi/ take precedence over system
> > headers; otherwise, the build will fail on systems running kernels
> > without the WGALLOWEDIP_F_REMOVE_ME flag.
> > 
> > Note that this patch is meant to be merged alongside the kernel patch
> > that introduces the flag.
> 
> Merged here:
> https://git.zx2c4.com/wireguard-tools/commit/?id=0788f90810efde88cfa07ed96e7eca77c7f2eedd
> 
> With a followup here:
> https://git.zx2c4.com/wireguard-tools/commit/?id=dce8ac6e2fa30f8b07e84859f244f81b3c6b2353

Also,
https://git.zx2c4.com/wireguard-go/commit/?id=256bcbd70d5b4eaae2a9f21a9889498c0f89041c

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RESEND PATCH v3 net-next] wireguard: allowedips: Add WGALLOWEDIP_F_REMOVE_ME flag
  2025-05-17 19:29 ` [RESEND PATCH v3 net-next] wireguard: allowedips: Add WGALLOWEDIP_F_REMOVE_ME flag Jordan Rife
@ 2025-05-20 21:47   ` Jason A. Donenfeld
  2025-05-20 22:00     ` Jason A. Donenfeld
  2025-05-20 21:50   ` Jason A. Donenfeld
  2025-05-20 23:25   ` Jason A. Donenfeld
  2 siblings, 1 reply; 15+ messages in thread
From: Jason A. Donenfeld @ 2025-05-20 21:47 UTC (permalink / raw)
  To: Jordan Rife; +Cc: wireguard, netdev, Jakub Kicinski, Daniel Borkmann

Hi Jakub, Jordan,

On Sat, May 17, 2025 at 12:29:52PM -0700, Jordan Rife wrote:
> * Use NLA_POLICY_MASK for WGALLOWEDIP_A_FLAGS validation (Jakub).
[...]
> +	[WGALLOWEDIP_A_FLAGS]		= NLA_POLICY_MASK(NLA_U32, __WGALLOWEDIP_F_ALL),

I wonder... Can we update, in a separate patch, these to also use
NLA_POLICY_MASK?

   ...
        [WGDEVICE_A_FLAGS]              = { .type = NLA_U32 },
   ...
        [WGPEER_A_FLAGS]                = { .type = NLA_U32 },
   ...

Some consistency would be nice.

Regards,
Jason

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RESEND PATCH v3 net-next] wireguard: allowedips: Add WGALLOWEDIP_F_REMOVE_ME flag
  2025-05-17 19:29 ` [RESEND PATCH v3 net-next] wireguard: allowedips: Add WGALLOWEDIP_F_REMOVE_ME flag Jordan Rife
  2025-05-20 21:47   ` Jason A. Donenfeld
@ 2025-05-20 21:50   ` Jason A. Donenfeld
  2025-05-20 23:25   ` Jason A. Donenfeld
  2 siblings, 0 replies; 15+ messages in thread
From: Jason A. Donenfeld @ 2025-05-20 21:50 UTC (permalink / raw)
  To: Jordan Rife; +Cc: wireguard, netdev, Jakub Kicinski, Daniel Borkmann

On Sat, May 17, 2025 at 12:29:52PM -0700, Jordan Rife wrote:
> +pub1_hex=$(echo "$pub1" | base64 -d | xxd -p -c 50)

There's no xxd or base64 commands on the test harness vm, but also this
line isn't used, so I'll just nix it on commit.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RESEND PATCH v3 net-next] wireguard: allowedips: Add WGALLOWEDIP_F_REMOVE_ME flag
  2025-05-20 21:47   ` Jason A. Donenfeld
@ 2025-05-20 22:00     ` Jason A. Donenfeld
  2025-05-21 23:11       ` Jordan Rife
  0 siblings, 1 reply; 15+ messages in thread
From: Jason A. Donenfeld @ 2025-05-20 22:00 UTC (permalink / raw)
  To: Jordan Rife; +Cc: wireguard, netdev, Jakub Kicinski, Daniel Borkmann

On Tue, May 20, 2025 at 11:47:56PM +0200, Jason A. Donenfeld wrote:
> Hi Jakub, Jordan,
> 
> On Sat, May 17, 2025 at 12:29:52PM -0700, Jordan Rife wrote:
> > * Use NLA_POLICY_MASK for WGALLOWEDIP_A_FLAGS validation (Jakub).
> [...]
> > +	[WGALLOWEDIP_A_FLAGS]		= NLA_POLICY_MASK(NLA_U32, __WGALLOWEDIP_F_ALL),
> 
> I wonder... Can we update, in a separate patch, these to also use
> NLA_POLICY_MASK?
> 
>    ...
>         [WGDEVICE_A_FLAGS]              = { .type = NLA_U32 },
>    ...
>         [WGPEER_A_FLAGS]                = { .type = NLA_U32 },
>    ...
> 
> Some consistency would be nice.

Perhaps I'll commit something like this?

From 22b6d15ad2a2e38bc80ebf65694106ff554b572f Mon Sep 17 00:00:00 2001
From: "Jason A. Donenfeld" <Jason@zx2c4.com>
Date: Tue, 20 May 2025 23:56:18 +0200
Subject: [PATCH] wireguard: netlink: use NLA_POLICY_MASK where possible

Rather than manually validating flags against the various __ALL_*
constants, put this in the netlink policy description and have the upper
layer machinery check it for us.

Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
---
 drivers/net/wireguard/netlink.c | 10 ++--------
 1 file changed, 2 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireguard/netlink.c b/drivers/net/wireguard/netlink.c
index f7055180ba4a..b82266da949a 100644
--- a/drivers/net/wireguard/netlink.c
+++ b/drivers/net/wireguard/netlink.c
@@ -24,7 +24,7 @@ static const struct nla_policy device_policy[WGDEVICE_A_MAX + 1] = {
 	[WGDEVICE_A_IFNAME]		= { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 },
 	[WGDEVICE_A_PRIVATE_KEY]	= NLA_POLICY_EXACT_LEN(NOISE_PUBLIC_KEY_LEN),
 	[WGDEVICE_A_PUBLIC_KEY]		= NLA_POLICY_EXACT_LEN(NOISE_PUBLIC_KEY_LEN),
-	[WGDEVICE_A_FLAGS]		= { .type = NLA_U32 },
+	[WGDEVICE_A_FLAGS]		= { .type = NLA_POLICY_MASK(NLA_U32, __WGDEVICE_F_ALL) },
 	[WGDEVICE_A_LISTEN_PORT]	= { .type = NLA_U16 },
 	[WGDEVICE_A_FWMARK]		= { .type = NLA_U32 },
 	[WGDEVICE_A_PEERS]		= { .type = NLA_NESTED }
@@ -33,7 +33,7 @@ static const struct nla_policy device_policy[WGDEVICE_A_MAX + 1] = {
 static const struct nla_policy peer_policy[WGPEER_A_MAX + 1] = {
 	[WGPEER_A_PUBLIC_KEY]				= NLA_POLICY_EXACT_LEN(NOISE_PUBLIC_KEY_LEN),
 	[WGPEER_A_PRESHARED_KEY]			= NLA_POLICY_EXACT_LEN(NOISE_SYMMETRIC_KEY_LEN),
-	[WGPEER_A_FLAGS]				= { .type = NLA_U32 },
+	[WGPEER_A_FLAGS]				= { .type = NLA_POLICY_MASK(NLA_U32, __WGPEER_F_ALL) },
 	[WGPEER_A_ENDPOINT]				= NLA_POLICY_MIN_LEN(sizeof(struct sockaddr)),
 	[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]	= { .type = NLA_U16 },
 	[WGPEER_A_LAST_HANDSHAKE_TIME]			= NLA_POLICY_EXACT_LEN(sizeof(struct __kernel_timespec)),
@@ -373,9 +373,6 @@ static int set_peer(struct wg_device *wg, struct nlattr **attrs)

 	if (attrs[WGPEER_A_FLAGS])
 		flags = nla_get_u32(attrs[WGPEER_A_FLAGS]);
-	ret = -EOPNOTSUPP;
-	if (flags & ~__WGPEER_F_ALL)
-		goto out;

 	ret = -EPFNOSUPPORT;
 	if (attrs[WGPEER_A_PROTOCOL_VERSION]) {
@@ -506,9 +503,6 @@ static int wg_set_device(struct sk_buff *skb, struct genl_info *info)

 	if (info->attrs[WGDEVICE_A_FLAGS])
 		flags = nla_get_u32(info->attrs[WGDEVICE_A_FLAGS]);
-	ret = -EOPNOTSUPP;
-	if (flags & ~__WGDEVICE_F_ALL)
-		goto out;

 	if (info->attrs[WGDEVICE_A_LISTEN_PORT] || info->attrs[WGDEVICE_A_FWMARK]) {
 		struct net *net;
--
2.48.1

^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [RESEND PATCH v3 net-next] wireguard: allowedips: Add WGALLOWEDIP_F_REMOVE_ME flag
  2025-05-17 19:29 ` [RESEND PATCH v3 net-next] wireguard: allowedips: Add WGALLOWEDIP_F_REMOVE_ME flag Jordan Rife
  2025-05-20 21:47   ` Jason A. Donenfeld
  2025-05-20 21:50   ` Jason A. Donenfeld
@ 2025-05-20 23:25   ` Jason A. Donenfeld
  2025-05-21 23:13     ` Jordan Rife
  2 siblings, 1 reply; 15+ messages in thread
From: Jason A. Donenfeld @ 2025-05-20 23:25 UTC (permalink / raw)
  To: Jordan Rife; +Cc: wireguard, netdev, Jakub Kicinski, Daniel Borkmann

On Sat, May 17, 2025 at 12:29:52PM -0700, Jordan Rife wrote:
> Introduce a new flag called WGALLOWEDIP_F_REMOVE_ME which in the same
> way that WGPEER_F_REMOVE_ME allows a user to remove a single peer from
> a WireGuard device's configuration allows a user to remove an ip from a
> peer's set of allowed ips. This enables incremental updates to a
> device's configuration without any connectivity blips or messy
> workarounds.
 
Applied as:
  https://git.zx2c4.com/wireguard-linux/commit/?h=devel&id=8f697b71a615c5dfff98fe93554036a2643d1976

And the userspace changes have been released already:
  https://lists.zx2c4.com/pipermail/wireguard/2025-May/008789.html

Thanks for this! And sorry it took so long to get it applied. I'll send
this up via net-next in a few days after a bunch of testing.

Jason

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RESEND PATCH v1 wireguard-tools] ipc: linux: Support incremental allowed ips updates
  2025-05-20 21:10   ` Jason A. Donenfeld
@ 2025-05-21 23:02     ` Jordan Rife
  2025-05-21 23:51       ` Jason A. Donenfeld
  0 siblings, 1 reply; 15+ messages in thread
From: Jordan Rife @ 2025-05-21 23:02 UTC (permalink / raw)
  To: Jason A. Donenfeld; +Cc: wireguard, netdev, Jakub Kicinski, Daniel Borkmann

> > Merged here:
> > https://git.zx2c4.com/wireguard-tools/commit/?id=0788f90810efde88cfa07ed96e7eca77c7f2eedd
> > 
> > With a followup here:
> > https://git.zx2c4.com/wireguard-tools/commit/?id=dce8ac6e2fa30f8b07e84859f244f81b3c6b2353
> 
> Also,
> https://git.zx2c4.com/wireguard-go/commit/?id=256bcbd70d5b4eaae2a9f21a9889498c0f89041c

Nice, cool to see this extended to wireguard-go as well. As a follow up,
I was planning to also create a patch for golang.zx2c4.com/wireguard/wgctrl
so the feature can be used from there too.

Jordan

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RESEND PATCH v3 net-next] wireguard: allowedips: Add WGALLOWEDIP_F_REMOVE_ME flag
  2025-05-20 22:00     ` Jason A. Donenfeld
@ 2025-05-21 23:11       ` Jordan Rife
  0 siblings, 0 replies; 15+ messages in thread
From: Jordan Rife @ 2025-05-21 23:11 UTC (permalink / raw)
  To: Jason A. Donenfeld; +Cc: wireguard, netdev, Jakub Kicinski, Daniel Borkmann

On Wed, May 21, 2025 at 12:00:00AM +0200, Jason A. Donenfeld wrote:
> On Tue, May 20, 2025 at 11:47:56PM +0200, Jason A. Donenfeld wrote:
> > Hi Jakub, Jordan,
> > 
> > On Sat, May 17, 2025 at 12:29:52PM -0700, Jordan Rife wrote:
> > > * Use NLA_POLICY_MASK for WGALLOWEDIP_A_FLAGS validation (Jakub).
> > [...]
> > > +	[WGALLOWEDIP_A_FLAGS]		= NLA_POLICY_MASK(NLA_U32, __WGALLOWEDIP_F_ALL),
> > 
> > I wonder... Can we update, in a separate patch, these to also use
> > NLA_POLICY_MASK?
> > 
> >    ...
> >         [WGDEVICE_A_FLAGS]              = { .type = NLA_U32 },
> >    ...
> >         [WGPEER_A_FLAGS]                = { .type = NLA_U32 },
> >    ...
> > 
> > Some consistency would be nice.
> 
> Perhaps I'll commit something like this?
> 
> From 22b6d15ad2a2e38bc80ebf65694106ff554b572f Mon Sep 17 00:00:00 2001
> From: "Jason A. Donenfeld" <Jason@zx2c4.com>
> Date: Tue, 20 May 2025 23:56:18 +0200
> Subject: [PATCH] wireguard: netlink: use NLA_POLICY_MASK where possible
> 
> Rather than manually validating flags against the various __ALL_*
> constants, put this in the netlink policy description and have the upper
> layer machinery check it for us.
> 
> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
> ---
>  drivers/net/wireguard/netlink.c | 10 ++--------
>  1 file changed, 2 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/net/wireguard/netlink.c b/drivers/net/wireguard/netlink.c
> index f7055180ba4a..b82266da949a 100644
> --- a/drivers/net/wireguard/netlink.c
> +++ b/drivers/net/wireguard/netlink.c
> @@ -24,7 +24,7 @@ static const struct nla_policy device_policy[WGDEVICE_A_MAX + 1] = {
>  	[WGDEVICE_A_IFNAME]		= { .type = NLA_NUL_STRING, .len = IFNAMSIZ - 1 },
>  	[WGDEVICE_A_PRIVATE_KEY]	= NLA_POLICY_EXACT_LEN(NOISE_PUBLIC_KEY_LEN),
>  	[WGDEVICE_A_PUBLIC_KEY]		= NLA_POLICY_EXACT_LEN(NOISE_PUBLIC_KEY_LEN),
> -	[WGDEVICE_A_FLAGS]		= { .type = NLA_U32 },
> +	[WGDEVICE_A_FLAGS]		= { .type = NLA_POLICY_MASK(NLA_U32, __WGDEVICE_F_ALL) },
>  	[WGDEVICE_A_LISTEN_PORT]	= { .type = NLA_U16 },
>  	[WGDEVICE_A_FWMARK]		= { .type = NLA_U32 },
>  	[WGDEVICE_A_PEERS]		= { .type = NLA_NESTED }
> @@ -33,7 +33,7 @@ static const struct nla_policy device_policy[WGDEVICE_A_MAX + 1] = {
>  static const struct nla_policy peer_policy[WGPEER_A_MAX + 1] = {
>  	[WGPEER_A_PUBLIC_KEY]				= NLA_POLICY_EXACT_LEN(NOISE_PUBLIC_KEY_LEN),
>  	[WGPEER_A_PRESHARED_KEY]			= NLA_POLICY_EXACT_LEN(NOISE_SYMMETRIC_KEY_LEN),
> -	[WGPEER_A_FLAGS]				= { .type = NLA_U32 },
> +	[WGPEER_A_FLAGS]				= { .type = NLA_POLICY_MASK(NLA_U32, __WGPEER_F_ALL) },
>  	[WGPEER_A_ENDPOINT]				= NLA_POLICY_MIN_LEN(sizeof(struct sockaddr)),
>  	[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]	= { .type = NLA_U16 },
>  	[WGPEER_A_LAST_HANDSHAKE_TIME]			= NLA_POLICY_EXACT_LEN(sizeof(struct __kernel_timespec)),
> @@ -373,9 +373,6 @@ static int set_peer(struct wg_device *wg, struct nlattr **attrs)
> 
>  	if (attrs[WGPEER_A_FLAGS])
>  		flags = nla_get_u32(attrs[WGPEER_A_FLAGS]);
> -	ret = -EOPNOTSUPP;
> -	if (flags & ~__WGPEER_F_ALL)
> -		goto out;
> 
>  	ret = -EPFNOSUPPORT;
>  	if (attrs[WGPEER_A_PROTOCOL_VERSION]) {
> @@ -506,9 +503,6 @@ static int wg_set_device(struct sk_buff *skb, struct genl_info *info)
> 
>  	if (info->attrs[WGDEVICE_A_FLAGS])
>  		flags = nla_get_u32(info->attrs[WGDEVICE_A_FLAGS]);
> -	ret = -EOPNOTSUPP;
> -	if (flags & ~__WGDEVICE_F_ALL)
> -		goto out;
> 
>  	if (info->attrs[WGDEVICE_A_LISTEN_PORT] || info->attrs[WGDEVICE_A_FWMARK]) {
>  		struct net *net;
> --
> 2.48.1

This changes the error code returned in userspace in these cases from
EOPNOTSUPP to EINVAL I think, but if there's nothing relying on that
behavior then it seems like a nice cleanup to me.

Jordan

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RESEND PATCH v3 net-next] wireguard: allowedips: Add WGALLOWEDIP_F_REMOVE_ME flag
  2025-05-20 23:25   ` Jason A. Donenfeld
@ 2025-05-21 23:13     ` Jordan Rife
  0 siblings, 0 replies; 15+ messages in thread
From: Jordan Rife @ 2025-05-21 23:13 UTC (permalink / raw)
  To: Jason A. Donenfeld; +Cc: wireguard, netdev, Jakub Kicinski, Daniel Borkmann

On Wed, May 21, 2025 at 01:25:04AM +0200, Jason A. Donenfeld wrote:
> On Sat, May 17, 2025 at 12:29:52PM -0700, Jordan Rife wrote:
> > Introduce a new flag called WGALLOWEDIP_F_REMOVE_ME which in the same
> > way that WGPEER_F_REMOVE_ME allows a user to remove a single peer from
> > a WireGuard device's configuration allows a user to remove an ip from a
> > peer's set of allowed ips. This enables incremental updates to a
> > device's configuration without any connectivity blips or messy
> > workarounds.
>  
> Applied as:
>   https://git.zx2c4.com/wireguard-linux/commit/?h=devel&id=8f697b71a615c5dfff98fe93554036a2643d1976
> 
> And the userspace changes have been released already:
>   https://lists.zx2c4.com/pipermail/wireguard/2025-May/008789.html
> 
> Thanks for this! And sorry it took so long to get it applied. I'll send
> this up via net-next in a few days after a bunch of testing.
> 
> Jason

No problem, we all get busy :). Thanks for applying.

Jordan

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RESEND PATCH v1 wireguard-tools] ipc: linux: Support incremental allowed ips updates
  2025-05-21 23:02     ` Jordan Rife
@ 2025-05-21 23:51       ` Jason A. Donenfeld
  2025-06-26  3:37         ` Kyle Evans
  0 siblings, 1 reply; 15+ messages in thread
From: Jason A. Donenfeld @ 2025-05-21 23:51 UTC (permalink / raw)
  To: Jordan Rife; +Cc: wireguard, netdev, Jakub Kicinski, Daniel Borkmann

On Thu, May 22, 2025 at 1:02 AM Jordan Rife <jordan@jrife.io> wrote:
> > > Merged here:
> > > https://git.zx2c4.com/wireguard-tools/commit/?id=0788f90810efde88cfa07ed96e7eca77c7f2eedd
> > >
> > > With a followup here:
> > > https://git.zx2c4.com/wireguard-tools/commit/?id=dce8ac6e2fa30f8b07e84859f244f81b3c6b2353
> >
> > Also,
> > https://git.zx2c4.com/wireguard-go/commit/?id=256bcbd70d5b4eaae2a9f21a9889498c0f89041c
>
> Nice, cool to see this extended to wireguard-go as well. As a follow up,
> I was planning to also create a patch for golang.zx2c4.com/wireguard/wgctrl
> so the feature can be used from there too.

Wonderful, please do! Looking forward to merging that.

There's already an open PR in FreeBSD too.

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RESEND PATCH v1 wireguard-tools] ipc: linux: Support incremental allowed ips updates
  2025-05-21 23:51       ` Jason A. Donenfeld
@ 2025-06-26  3:37         ` Kyle Evans
  2025-06-28 16:05           ` Jordan Rife
  0 siblings, 1 reply; 15+ messages in thread
From: Kyle Evans @ 2025-06-26  3:37 UTC (permalink / raw)
  To: Jason A. Donenfeld, Jordan Rife
  Cc: wireguard, netdev, Jakub Kicinski, Daniel Borkmann

On 5/21/25 18:51, Jason A. Donenfeld wrote:
> On Thu, May 22, 2025 at 1:02 AM Jordan Rife <jordan@jrife.io> wrote:
>>>> Merged here:
>>>> https://git.zx2c4.com/wireguard-tools/commit/?id=0788f90810efde88cfa07ed96e7eca77c7f2eedd
>>>>
>>>> With a followup here:
>>>> https://git.zx2c4.com/wireguard-tools/commit/?id=dce8ac6e2fa30f8b07e84859f244f81b3c6b2353
>>>
>>> Also,
>>> https://git.zx2c4.com/wireguard-go/commit/?id=256bcbd70d5b4eaae2a9f21a9889498c0f89041c
>>
>> Nice, cool to see this extended to wireguard-go as well. As a follow up,
>> I was planning to also create a patch for golang.zx2c4.com/wireguard/wgctrl
>> so the feature can be used from there too.
> 
> Wonderful, please do! Looking forward to merging that.
> 
> There's already an open PR in FreeBSD too.

FreeBSD support landed as of:

https://cgit.freebsd.org/src/commit/?id=f6d9e22982a

It will be available in FreeBSD 15.0 and probably 14.4 (to be released 
next year) as well.  I have pushed a branch, ke/fbsd_aip, to the 
wireguard-tools repository for your consideration.

Aside: this is a really neat feature.

Thanks!

Kyle Evans

^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RESEND PATCH v1 wireguard-tools] ipc: linux: Support incremental allowed ips updates
  2025-06-26  3:37         ` Kyle Evans
@ 2025-06-28 16:05           ` Jordan Rife
  2025-06-30  1:44             ` Kyle Evans
  0 siblings, 1 reply; 15+ messages in thread
From: Jordan Rife @ 2025-06-28 16:05 UTC (permalink / raw)
  To: Kyle Evans
  Cc: Jason A. Donenfeld, wireguard, netdev, Jakub Kicinski,
	Daniel Borkmann

On Wed, Jun 25, 2025 at 10:37:55PM -0500, Kyle Evans wrote:
> On 5/21/25 18:51, Jason A. Donenfeld wrote:
> > On Thu, May 22, 2025 at 1:02 AM Jordan Rife <jordan@jrife.io> wrote:
> > > > > Merged here:
> > > > > https://git.zx2c4.com/wireguard-tools/commit/?id=0788f90810efde88cfa07ed96e7eca77c7f2eedd
> > > > > 
> > > > > With a followup here:
> > > > > https://git.zx2c4.com/wireguard-tools/commit/?id=dce8ac6e2fa30f8b07e84859f244f81b3c6b2353
> > > > 
> > > > Also,
> > > > https://git.zx2c4.com/wireguard-go/commit/?id=256bcbd70d5b4eaae2a9f21a9889498c0f89041c
> > > 
> > > Nice, cool to see this extended to wireguard-go as well. As a follow up,
> > > I was planning to also create a patch for golang.zx2c4.com/wireguard/wgctrl
> > > so the feature can be used from there too.
> > 
> > Wonderful, please do! Looking forward to merging that.
> > 
> > There's already an open PR in FreeBSD too.
> 
> FreeBSD support landed as of:
> 
> https://cgit.freebsd.org/src/commit/?id=f6d9e22982a
> 
> It will be available in FreeBSD 15.0 and probably 14.4 (to be released next
> year) as well.  I have pushed a branch, ke/fbsd_aip, to the wireguard-tools
> repository for your consideration.
> 
> Aside: this is a really neat feature.
> 
> Thanks!
> 
> Kyle Evans

That's great news. It's nice to see this feature percolating through
the WireGuard ecosystem.

I was working on adding support for direct IP removal to wgctrl-go too,
a Go library for controlling WireGuard devices:

https://github.com/WireGuard/wgctrl-go/pull/156

While I'm at it, I'll try to add native support for IP removal on
FreeBSD if I can get a dev build working with the latest and greatest
( I am a FreeBSD noob :) ).

Jordan


^ permalink raw reply	[flat|nested] 15+ messages in thread

* Re: [RESEND PATCH v1 wireguard-tools] ipc: linux: Support incremental allowed ips updates
  2025-06-28 16:05           ` Jordan Rife
@ 2025-06-30  1:44             ` Kyle Evans
  0 siblings, 0 replies; 15+ messages in thread
From: Kyle Evans @ 2025-06-30  1:44 UTC (permalink / raw)
  To: Jordan Rife
  Cc: Jason A. Donenfeld, wireguard, netdev, Jakub Kicinski,
	Daniel Borkmann

On 6/28/25 11:05, Jordan Rife wrote:
> On Wed, Jun 25, 2025 at 10:37:55PM -0500, Kyle Evans wrote:
>> On 5/21/25 18:51, Jason A. Donenfeld wrote:
>>> On Thu, May 22, 2025 at 1:02 AM Jordan Rife <jordan@jrife.io> wrote:
>>>>>> Merged here:
>>>>>> https://git.zx2c4.com/wireguard-tools/commit/?id=0788f90810efde88cfa07ed96e7eca77c7f2eedd
>>>>>>
>>>>>> With a followup here:
>>>>>> https://git.zx2c4.com/wireguard-tools/commit/?id=dce8ac6e2fa30f8b07e84859f244f81b3c6b2353
>>>>>
>>>>> Also,
>>>>> https://git.zx2c4.com/wireguard-go/commit/?id=256bcbd70d5b4eaae2a9f21a9889498c0f89041c
>>>>
>>>> Nice, cool to see this extended to wireguard-go as well. As a follow up,
>>>> I was planning to also create a patch for golang.zx2c4.com/wireguard/wgctrl
>>>> so the feature can be used from there too.
>>>
>>> Wonderful, please do! Looking forward to merging that.
>>>
>>> There's already an open PR in FreeBSD too.
>>
>> FreeBSD support landed as of:
>>
>> https://cgit.freebsd.org/src/commit/?id=f6d9e22982a
>>
>> It will be available in FreeBSD 15.0 and probably 14.4 (to be released next
>> year) as well.  I have pushed a branch, ke/fbsd_aip, to the wireguard-tools
>> repository for your consideration.
>>
>> Aside: this is a really neat feature.
>>
>> Thanks!
>>
>> Kyle Evans
> 
> That's great news. It's nice to see this feature percolating through
> the WireGuard ecosystem.
> 
> I was working on adding support for direct IP removal to wgctrl-go too,
> a Go library for controlling WireGuard devices:
> 
> https://github.com/WireGuard/wgctrl-go/pull/156
 >

Ah, neat!

> While I'm at it, I'll try to add native support for IP removal on
> FreeBSD if I can get a dev build working with the latest and greatest
> ( I am a FreeBSD noob :) ).
> 
Feel free to shoot me an e-mail off-list if you need any assistance 
there, more than happy to lend a hand for the cause.

Thanks,

Kyle Evans

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2025-06-30  1:44 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-05-17 19:29 [RESEND PATCH v1 wireguard-tools] ipc: linux: Support incremental allowed ips updates Jordan Rife
2025-05-17 19:29 ` [RESEND PATCH v3 net-next] wireguard: allowedips: Add WGALLOWEDIP_F_REMOVE_ME flag Jordan Rife
2025-05-20 21:47   ` Jason A. Donenfeld
2025-05-20 22:00     ` Jason A. Donenfeld
2025-05-21 23:11       ` Jordan Rife
2025-05-20 21:50   ` Jason A. Donenfeld
2025-05-20 23:25   ` Jason A. Donenfeld
2025-05-21 23:13     ` Jordan Rife
2025-05-20 20:14 ` [RESEND PATCH v1 wireguard-tools] ipc: linux: Support incremental allowed ips updates Jason A. Donenfeld
2025-05-20 21:10   ` Jason A. Donenfeld
2025-05-21 23:02     ` Jordan Rife
2025-05-21 23:51       ` Jason A. Donenfeld
2025-06-26  3:37         ` Kyle Evans
2025-06-28 16:05           ` Jordan Rife
2025-06-30  1:44             ` Kyle Evans

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 NNTP newsgroup(s).