diff --git a/share/man/man4/udp.4 b/share/man/man4/udp.4 --- a/share/man/man4/udp.4 +++ b/share/man/man4/udp.4 @@ -25,7 +25,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd August 1, 2022 +.Dd January 20, 2025 .Dt UDP 4 .Os .Sh NAME @@ -107,6 +107,19 @@ .Tn UDP_ENCAP_ESPINUDP from RFC 3948, defined in .In netinet/udp.h . +.Sh FIB support +UDP sockets are FIB-aware. +They inherit the FIB of the process which created the socket. +By default, a UDP socket bound to an address can receive datagrams originating +from any FIB. +If the +.Va net.inet.udp.bind_all_fibs +tunable is set to 0, all UDP sockets will receive only datagrams originating +from the same FIB as the socket. +In this mode, multiple sockets can be bound to the same address, so long as +each socket belongs to a different FIB, similar to the behavior of the +.Dv SO_REUSEPORT +option. .Sh MIB (sysctl) Variables The .Nm diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c --- a/sys/netinet/udp_usrreq.c +++ b/sys/netinet/udp_usrreq.c @@ -105,6 +105,11 @@ * Per RFC 3828, July, 2004. */ +VNET_DEFINE(int, udp_bind_all_fibs) = 1; +SYSCTL_INT(_net_inet_udp, OID_AUTO, bind_all_fibs, CTLFLAG_VNET | CTLFLAG_RDTUN, + &VNET_NAME(udp_bind_all_fibs), 0, + "Bound sockets receive traffic from all FIBs"); + /* * BSD 4.2 defaulted the udp checksum to be off. Turning off udp checksums * removes the only data integrity mechanism for packets and malformed @@ -453,7 +458,7 @@ struct sockaddr_in udp_in[2]; struct mbuf *m; struct m_tag *fwd_tag; - int cscov_partial, iphlen; + int cscov_partial, iphlen, lookupflags; m = *mp; iphlen = *offp; @@ -575,7 +580,11 @@ /* * Locate pcb for datagram. - * + */ + lookupflags = INPLOOKUP_RLOCKPCB | + (V_udp_bind_all_fibs ? 0 : INPLOOKUP_FIB); + + /* * Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. */ if ((m->m_flags & M_IP_NEXTHOP) && @@ -589,7 +598,7 @@ * Already got one like this? */ inp = in_pcblookup_mbuf(pcbinfo, ip->ip_src, uh->uh_sport, - ip->ip_dst, uh->uh_dport, INPLOOKUP_RLOCKPCB, ifp, m); + ip->ip_dst, uh->uh_dport, lookupflags, ifp, m); if (!inp) { /* * It's new. Try to find the ambushing socket. @@ -599,8 +608,8 @@ inp = in_pcblookup(pcbinfo, ip->ip_src, uh->uh_sport, next_hop->sin_addr, next_hop->sin_port ? htons(next_hop->sin_port) : - uh->uh_dport, INPLOOKUP_WILDCARD | - INPLOOKUP_RLOCKPCB, ifp); + uh->uh_dport, INPLOOKUP_WILDCARD | lookupflags, + ifp); } /* Remove the tag from the packet. We don't need it anymore. */ m_tag_delete(m, fwd_tag); @@ -608,7 +617,7 @@ } else inp = in_pcblookup_mbuf(pcbinfo, ip->ip_src, uh->uh_sport, ip->ip_dst, uh->uh_dport, INPLOOKUP_WILDCARD | - INPLOOKUP_RLOCKPCB, ifp, m); + lookupflags, ifp, m); if (inp == NULL) { if (V_udp_log_in_vain) { char src[INET_ADDRSTRLEN]; @@ -1242,8 +1251,8 @@ inp->inp_vflag &= ~INP_IPV6; } INP_HASH_WLOCK(pcbinfo); - error = in_pcbbind_setup(inp, &src, &laddr.s_addr, &lport, 0, - td->td_ucred); + error = in_pcbbind_setup(inp, &src, &laddr.s_addr, &lport, + V_udp_bind_all_fibs ? 0 : INPBIND_FIB, td->td_ucred); INP_HASH_WUNLOCK(pcbinfo); if ((flags & PRUS_IPV6) != 0) inp->inp_vflag = vflagsav; @@ -1592,7 +1601,8 @@ INP_WLOCK(inp); INP_HASH_WLOCK(pcbinfo); - error = in_pcbbind(inp, sinp, 0, td->td_ucred); + error = in_pcbbind(inp, sinp, V_udp_bind_all_fibs ? 0 : INPBIND_FIB, + td->td_ucred); INP_HASH_WUNLOCK(pcbinfo); INP_WUNLOCK(inp); return (error); diff --git a/sys/netinet/udp_var.h b/sys/netinet/udp_var.h --- a/sys/netinet/udp_var.h +++ b/sys/netinet/udp_var.h @@ -155,13 +155,15 @@ extern u_long udp_sendspace; extern u_long udp_recvspace; -VNET_DECLARE(int, udp_cksum); +VNET_DECLARE(int, udp_bind_all_fibs); VNET_DECLARE(int, udp_blackhole); VNET_DECLARE(bool, udp_blackhole_local); +VNET_DECLARE(int, udp_cksum); VNET_DECLARE(int, udp_log_in_vain); -#define V_udp_cksum VNET(udp_cksum) +#define V_udp_bind_all_fibs VNET(udp_bind_all_fibs) #define V_udp_blackhole VNET(udp_blackhole) #define V_udp_blackhole_local VNET(udp_blackhole_local) +#define V_udp_cksum VNET(udp_cksum) #define V_udp_log_in_vain VNET(udp_log_in_vain) VNET_DECLARE(int, zero_checksum_port); diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c --- a/sys/netinet6/udp6_usrreq.c +++ b/sys/netinet6/udp6_usrreq.c @@ -357,6 +357,7 @@ int off = *offp; int cscov_partial; int plen, ulen; + int lookupflags; struct sockaddr_in6 fromsa[2]; struct m_tag *fwd_tag; uint16_t uh_sum; @@ -454,6 +455,8 @@ /* * Locate pcb for datagram. */ + lookupflags = INPLOOKUP_RLOCKPCB | + (V_udp_bind_all_fibs ? 0 : INPLOOKUP_FIB); /* * Grab info from PACKET_TAG_IPFORWARD tag prepended to the chain. @@ -470,7 +473,7 @@ */ inp = in6_pcblookup_mbuf(pcbinfo, &ip6->ip6_src, uh->uh_sport, &ip6->ip6_dst, uh->uh_dport, - INPLOOKUP_RLOCKPCB, m->m_pkthdr.rcvif, m); + lookupflags, m->m_pkthdr.rcvif, m); if (!inp) { /* * It's new. Try to find the ambushing socket. @@ -480,8 +483,8 @@ inp = in6_pcblookup(pcbinfo, &ip6->ip6_src, uh->uh_sport, &next_hop6->sin6_addr, next_hop6->sin6_port ? htons(next_hop6->sin6_port) : - uh->uh_dport, INPLOOKUP_WILDCARD | - INPLOOKUP_RLOCKPCB, m->m_pkthdr.rcvif); + uh->uh_dport, INPLOOKUP_WILDCARD | lookupflags, + m->m_pkthdr.rcvif); } /* Remove the tag from the packet. We don't need it anymore. */ m_tag_delete(m, fwd_tag); @@ -489,7 +492,7 @@ } else inp = in6_pcblookup_mbuf(pcbinfo, &ip6->ip6_src, uh->uh_sport, &ip6->ip6_dst, uh->uh_dport, - INPLOOKUP_WILDCARD | INPLOOKUP_RLOCKPCB, + INPLOOKUP_WILDCARD | lookupflags, m->m_pkthdr.rcvif, m); if (inp == NULL) { if (V_udp_log_in_vain) { @@ -1058,13 +1061,16 @@ in6_sin6_2_sin(&sin, sin6_p); inp->inp_vflag |= INP_IPV4; inp->inp_vflag &= ~INP_IPV6; - error = in_pcbbind(inp, &sin, 0, td->td_ucred); + error = in_pcbbind(inp, &sin, + V_udp_bind_all_fibs ? 0 : INPBIND_FIB, + td->td_ucred); goto out; } #endif } - error = in6_pcbbind(inp, sin6_p, 0, td->td_ucred); + error = in6_pcbbind(inp, sin6_p, V_udp_bind_all_fibs ? 0 : INPBIND_FIB, + td->td_ucred); #ifdef INET out: #endif