Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 39 additions & 2 deletions pingora-core/src/listeners/l4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ use super::connection_filter::ConnectionFilter;
#[cfg(feature = "connection_filter")]
use crate::listeners::AcceptAllFilter;

#[cfg(target_os = "linux")]
use crate::protocols::l4::ext::set_ip_transparent;
use crate::protocols::l4::ext::{set_dscp, set_recv_buf, set_snd_buf, set_tcp_fastopen_backlog};
use crate::protocols::l4::listener::Listener;
pub use crate::protocols::l4::stream::Stream;
Expand Down Expand Up @@ -113,6 +115,14 @@ pub struct TcpSocketOptions {
/// This is useful for load balancing across multiple worker processes.
/// See the [man page](https://man7.org/linux/man-pages/man7/socket.7.html) for more information.
pub so_reuseport: Option<bool>,
/// Enable transparent proxying with `IP_TRANSPARENT` (IPv4) or
/// `IPV6_TRANSPARENT` (IPv6) on Linux.
///
/// Setting this to `true` requires `CAP_NET_ADMIN` or `CAP_NET_RAW`, plus
/// the routing/firewall configuration needed to deliver transparent
/// traffic. Inherited listener fds keep their existing socket options.
#[cfg(target_os = "linux")]
pub ip_transparent: Option<bool>,
/// Set the send buffer size for accepted connections. See
/// [SO_SNDBUF](https://man7.org/linux/man-pages/man7/socket.7.html).
pub tcp_snd_buf: Option<usize>,
Expand Down Expand Up @@ -180,7 +190,11 @@ mod uds {
}

// currently, these options can only apply on sockets prior to calling bind()
fn apply_tcp_socket_options(sock: &TcpSocket, opt: Option<&TcpSocketOptions>) -> Result<()> {
fn apply_tcp_socket_options(
sock: &TcpSocket,
_addr: &SocketAddr,
opt: Option<&TcpSocketOptions>,
) -> Result<()> {
let Some(opt) = opt else {
return Ok(());
};
Expand All @@ -200,6 +214,14 @@ fn apply_tcp_socket_options(sock: &TcpSocket, opt: Option<&TcpSocketOptions>) ->
.or_err(BindError, "failed to set SO_REUSEPORT")?;
}

#[cfg(target_os = "linux")]
if let Some(transparent) = opt.ip_transparent {
set_ip_transparent(sock.as_raw_fd(), _addr.is_ipv6(), transparent).or_err(
BindError,
"failed to set IP_TRANSPARENT (enabling it requires CAP_NET_ADMIN or CAP_NET_RAW)",
)?;
}

#[cfg(unix)]
let raw = sock.as_raw_fd();
#[cfg(windows)]
Expand Down Expand Up @@ -262,7 +284,7 @@ async fn bind_tcp(addr: &str, opt: Option<TcpSocketOptions>) -> Result<Listener>
.set_reuseaddr(true)
.or_err(BindError, "fail to set_reuseaddr(true)")?;

apply_tcp_socket_options(&listener_socket, opt.as_ref())?;
apply_tcp_socket_options(&listener_socket, &sock_addr, opt.as_ref())?;

match listener_socket.bind(sock_addr) {
Ok(()) => {
Expand Down Expand Up @@ -585,6 +607,21 @@ mod test {
.expect("can connect to UDS listener");
}

#[cfg(target_os = "linux")]
#[test]
fn test_tcp_ip_transparent_false() {
let options = TcpSocketOptions {
ip_transparent: Some(false),
..Default::default()
};
let v4 = TcpSocket::new_v4().unwrap();
apply_tcp_socket_options(&v4, &"127.0.0.1:0".parse().unwrap(), Some(&options)).unwrap();

if let Ok(v6) = TcpSocket::new_v6() {
apply_tcp_socket_options(&v6, &"[::1]:0".parse().unwrap(), Some(&options)).unwrap();
}
}

#[cfg(unix)]
#[tokio::test]
async fn test_tcp_so_reuseport() {
Expand Down
10 changes: 10 additions & 0 deletions pingora-core/src/protocols/l4/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,16 @@ fn ip_bind_addr_no_port(_fd: RawFd, _val: bool) -> io::Result<()> {
Ok(())
}

#[cfg(target_os = "linux")]
pub(crate) fn set_ip_transparent(fd: RawFd, ipv6: bool, val: bool) -> io::Result<()> {
let (level, name) = if ipv6 {
(libc::IPPROTO_IPV6, libc::IPV6_TRANSPARENT)
} else {
(libc::IPPROTO_IP, libc::IP_TRANSPARENT)
};
set_opt(fd, level, name, val as c_int)
}

/// IP_LOCAL_PORT_RANGE is only supported on Linux 6.3 and higher,
/// ip_local_port_range() is a no-op on unsupported versions.
/// See the [man page](https://man7.org/linux/man-pages/man7/ip.7.html) for more details.
Expand Down
Loading