2025-03-04, 01:33:48 +0100, Antonio Quartulli wrote: > A peer connected via UDP may change its IP address without reconnecting > (float). Should that trigger a reset of the peer->dst_cache? And same when userspace updates the remote address? Otherwise it seems we could be stuck with a cached dst that cannot reach the peer. > +void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb) > +{ > + struct hlist_nulls_head *nhead; > + struct sockaddr_storage ss; > + const u8 *local_ip = NULL; > + struct sockaddr_in6 *sa6; > + struct sockaddr_in *sa; > + struct ovpn_bind *bind; > + size_t salen = 0; > + > + spin_lock_bh(&peer->lock); > + bind = rcu_dereference_protected(peer->bind, > + lockdep_is_held(&peer->lock)); > + if (unlikely(!bind)) > + goto unlock; > + > + switch (skb->protocol) { > + case htons(ETH_P_IP): > + /* float check */ > + if (unlikely(!ovpn_bind_skb_src_match(bind, skb))) { > + if (bind->remote.in4.sin_family == AF_INET) > + local_ip = (u8 *)&bind->local; If I'm reading this correctly, we always reuse the existing local address when we have to re-create the bind, even if it doesn't match the skb? The "local endpoint update" chunk below is doing that, but only if we're keeping the same remote? It'll get updated the next time we receive a packet and call ovpn_peer_endpoints_update. That might irritate the RPF check on the other side, if we still use our "old" source to talk to the new dest? > + sa = (struct sockaddr_in *)&ss; > + sa->sin_family = AF_INET; > + sa->sin_addr.s_addr = ip_hdr(skb)->saddr; > + sa->sin_port = udp_hdr(skb)->source; > + salen = sizeof(*sa); > + break; > + } > + > + /* local endpoint update */ > + if (unlikely(bind->local.ipv4.s_addr != ip_hdr(skb)->daddr)) { > + net_dbg_ratelimited("%s: learning local IPv4 for peer %d (%pI4 -> %pI4)\n", > + netdev_name(peer->ovpn->dev), > + peer->id, &bind->local.ipv4.s_addr, > + &ip_hdr(skb)->daddr); > + bind->local.ipv4.s_addr = ip_hdr(skb)->daddr; > + } > + break; [...] > + if (peer->ovpn->mode == OVPN_MODE_MP) { > + spin_lock_bh(&peer->ovpn->lock); > + spin_lock_bh(&peer->lock); > + bind = rcu_dereference_protected(peer->bind, > + lockdep_is_held(&peer->lock)); > + if (unlikely(!bind)) { > + spin_unlock_bh(&peer->lock); > + spin_unlock_bh(&peer->ovpn->lock); > + return; > + } > + > + /* his function may be invoked concurrently, therefore another typo: ^ This [...] > -/* variable name __tbl2 needs to be different from __tbl1 > - * in the macro below to avoid confusing clang > - */ > -#define ovpn_get_hash_slot(_tbl, _key, _key_len) ({ \ > - typeof(_tbl) *__tbl2 = &(_tbl); \ > - jhash(_key, _key_len, 0) % HASH_SIZE(*__tbl2); \ > -}) > - > -#define ovpn_get_hash_head(_tbl, _key, _key_len) ({ \ > - typeof(_tbl) *__tbl1 = &(_tbl); \ > - &(*__tbl1)[ovpn_get_hash_slot(*__tbl1, _key, _key_len)];\ > -}) > - > /** > * ovpn_peer_get_by_vpn_addr4 - retrieve peer by its VPN IPv4 address > * @ovpn: the openvpn instance to search > @@ -522,51 +694,6 @@ static void ovpn_peer_remove(struct ovpn_peer *peer, > llist_add(&peer->release_entry, release_list); > } > > -/** > - * ovpn_peer_update_local_endpoint - update local endpoint for peer > - * @peer: peer to update the endpoint for > - * @skb: incoming packet to retrieve the destination address (local) from > - */ > -void ovpn_peer_update_local_endpoint(struct ovpn_peer *peer, > - struct sk_buff *skb) > -{ > - struct ovpn_bind *bind; > - > - rcu_read_lock(); > - bind = rcu_dereference(peer->bind); > - if (unlikely(!bind)) > - goto unlock; > - > - spin_lock_bh(&peer->lock); > - switch (skb->protocol) { > - case htons(ETH_P_IP): > - if (unlikely(bind->local.ipv4.s_addr != ip_hdr(skb)->daddr)) { > - net_dbg_ratelimited("%s: learning local IPv4 for peer %d (%pI4 -> %pI4)\n", > - netdev_name(peer->ovpn->dev), > - peer->id, &bind->local.ipv4.s_addr, > - &ip_hdr(skb)->daddr); > - bind->local.ipv4.s_addr = ip_hdr(skb)->daddr; > - } > - break; > - case htons(ETH_P_IPV6): > - if (unlikely(!ipv6_addr_equal(&bind->local.ipv6, > - &ipv6_hdr(skb)->daddr))) { > - net_dbg_ratelimited("%s: learning local IPv6 for peer %d (%pI6c -> %pI6c\n", > - netdev_name(peer->ovpn->dev), > - peer->id, &bind->local.ipv6, > - &ipv6_hdr(skb)->daddr); > - bind->local.ipv6 = ipv6_hdr(skb)->daddr; > - } > - break; > - default: > - break; > - } > - spin_unlock_bh(&peer->lock); > - > -unlock: > - rcu_read_unlock(); > -} I guess you could squash this and the previous patch into one to reduce the churn (and get a little bit closer to the 15-patch limit :)) -- Sabrina