@@ -14,6 +14,10 @@ use crate::fd::BorrowedFd;
14
14
use crate :: ffi:: CStr ;
15
15
use crate :: io;
16
16
use crate :: net:: sockopt:: Timeout ;
17
+ #[ cfg( target_os = "linux" ) ]
18
+ use crate :: net:: xdp:: {
19
+ XdpMmapOffsets , XdpOptionsFlags , XdpRingFlags , XdpRingOffset , XdpStatistics , XdpUmemReg ,
20
+ } ;
17
21
#[ cfg( not( any(
18
22
apple,
19
23
windows,
@@ -67,12 +71,15 @@ use alloc::borrow::ToOwned;
67
71
target_os = "illumos"
68
72
) ) ]
69
73
use alloc:: string:: String ;
74
+ use bitflags:: Flags ;
70
75
#[ cfg( apple) ]
71
76
use c:: TCP_KEEPALIVE as TCP_KEEPIDLE ;
72
77
#[ cfg( not( any( apple, target_os = "openbsd" , target_os = "haiku" , target_os = "nto" ) ) ) ]
73
78
use c:: TCP_KEEPIDLE ;
74
79
use core:: mem:: { size_of, MaybeUninit } ;
75
80
use core:: time:: Duration ;
81
+ #[ cfg( target_os = "linux" ) ]
82
+ use linux_raw_sys:: xdp:: { xdp_mmap_offsets, xdp_statistics, xdp_statistics_v1} ;
76
83
#[ cfg( windows) ]
77
84
use windows_sys:: Win32 :: Foundation :: BOOL ;
78
85
@@ -963,6 +970,170 @@ pub(crate) fn get_socket_peercred(fd: BorrowedFd<'_>) -> io::Result<UCred> {
963
970
getsockopt ( fd, c:: SOL_SOCKET , c:: SO_PEERCRED )
964
971
}
965
972
973
+ #[ cfg( target_os = "linux" ) ]
974
+ #[ inline]
975
+ pub ( crate ) fn set_xdp_umem_reg ( fd : BorrowedFd < ' _ > , value : XdpUmemReg ) -> io:: Result < ( ) > {
976
+ setsockopt ( fd, c:: SOL_XDP , c:: XDP_UMEM_REG , value)
977
+ }
978
+
979
+ #[ cfg( target_os = "linux" ) ]
980
+ #[ inline]
981
+ pub ( crate ) fn set_xdp_umem_fill_ring_size ( fd : BorrowedFd < ' _ > , value : u32 ) -> io:: Result < ( ) > {
982
+ setsockopt ( fd, c:: SOL_XDP , c:: XDP_UMEM_FILL_RING , value)
983
+ }
984
+
985
+ #[ cfg( target_os = "linux" ) ]
986
+ #[ inline]
987
+ pub ( crate ) fn set_xdp_umem_completion_ring_size ( fd : BorrowedFd < ' _ > , value : u32 ) -> io:: Result < ( ) > {
988
+ setsockopt ( fd, c:: SOL_XDP , c:: XDP_UMEM_COMPLETION_RING , value)
989
+ }
990
+
991
+ #[ cfg( target_os = "linux" ) ]
992
+ #[ inline]
993
+ pub ( crate ) fn set_xdp_tx_ring_size ( fd : BorrowedFd < ' _ > , value : u32 ) -> io:: Result < ( ) > {
994
+ setsockopt ( fd, c:: SOL_XDP , c:: XDP_TX_RING , value)
995
+ }
996
+
997
+ #[ cfg( target_os = "linux" ) ]
998
+ #[ inline]
999
+ pub ( crate ) fn set_xdp_rx_ring_size ( fd : BorrowedFd < ' _ > , value : u32 ) -> io:: Result < ( ) > {
1000
+ setsockopt ( fd, c:: SOL_XDP , c:: XDP_RX_RING , value)
1001
+ }
1002
+
1003
+ #[ cfg( target_os = "linux" ) ]
1004
+ #[ inline]
1005
+ pub ( crate ) fn get_xdp_mmap_offsets ( fd : BorrowedFd < ' _ > ) -> io:: Result < XdpMmapOffsets > {
1006
+ // The kernel will write `xdp_mmap_offsets` or `xdp_mmap_offsets_v1` to the supplied pointer,
1007
+ // depending on the kernel version. Both structs only contain u64 values.
1008
+ // By using the larger of both as the parameter, we can shuffle the values to the non-v1 version
1009
+ // returned by `get_xdp_mmap_offsets` while keeping the return type unaffected by the kernel
1010
+ // version. This works because C will layout all struct members one after the other.
1011
+
1012
+ let mut optlen = core:: mem:: size_of :: < xdp_mmap_offsets > ( ) . try_into ( ) . unwrap ( ) ;
1013
+ debug_assert ! (
1014
+ optlen as usize >= core:: mem:: size_of:: <c:: c_int>( ) ,
1015
+ "Socket APIs don't ever use `bool` directly"
1016
+ ) ;
1017
+ let mut value = MaybeUninit :: < xdp_mmap_offsets > :: zeroed ( ) ;
1018
+ getsockopt_raw ( fd, c:: SOL_XDP , c:: XDP_MMAP_OFFSETS , & mut value, & mut optlen) ?;
1019
+
1020
+ if optlen as usize == core:: mem:: size_of :: < c:: xdp_mmap_offsets_v1 > ( ) {
1021
+ // Safety: All members of xdp_mmap_offsets are u64 and thus are correctly initialized
1022
+ // by `MaybeUninit::<xdp_statistics>::zeroed()`
1023
+ let xpd_mmap_offsets = unsafe { value. assume_init ( ) } ;
1024
+ Ok ( XdpMmapOffsets {
1025
+ rx : XdpRingOffset {
1026
+ producer : xpd_mmap_offsets. rx . producer ,
1027
+ consumer : xpd_mmap_offsets. rx . consumer ,
1028
+ desc : xpd_mmap_offsets. rx . desc ,
1029
+ flags : None ,
1030
+ } ,
1031
+ tx : XdpRingOffset {
1032
+ producer : xpd_mmap_offsets. rx . flags ,
1033
+ consumer : xpd_mmap_offsets. tx . producer ,
1034
+ desc : xpd_mmap_offsets. tx . consumer ,
1035
+ flags : None ,
1036
+ } ,
1037
+ fr : XdpRingOffset {
1038
+ producer : xpd_mmap_offsets. tx . desc ,
1039
+ consumer : xpd_mmap_offsets. tx . flags ,
1040
+ desc : xpd_mmap_offsets. fr . producer ,
1041
+ flags : None ,
1042
+ } ,
1043
+ cr : XdpRingOffset {
1044
+ producer : xpd_mmap_offsets. fr . consumer ,
1045
+ consumer : xpd_mmap_offsets. fr . desc ,
1046
+ desc : xpd_mmap_offsets. fr . flags ,
1047
+ flags : None ,
1048
+ } ,
1049
+ } )
1050
+ } else {
1051
+ assert_eq ! (
1052
+ optlen as usize ,
1053
+ core:: mem:: size_of:: <xdp_mmap_offsets>( ) ,
1054
+ "unexpected getsockopt size"
1055
+ ) ;
1056
+ // Safety: All members of xdp_mmap_offsets are u64 and thus are correctly initialized
1057
+ // by `MaybeUninit::<xdp_statistics>::zeroed()`
1058
+ let xpd_mmap_offsets = unsafe { value. assume_init ( ) } ;
1059
+ Ok ( XdpMmapOffsets {
1060
+ rx : XdpRingOffset {
1061
+ producer : xpd_mmap_offsets. rx . producer ,
1062
+ consumer : xpd_mmap_offsets. rx . consumer ,
1063
+ desc : xpd_mmap_offsets. rx . desc ,
1064
+ flags : Some ( XdpRingFlags :: from_bits_retain ( xpd_mmap_offsets. rx . flags ) ) ,
1065
+ } ,
1066
+ tx : XdpRingOffset {
1067
+ producer : xpd_mmap_offsets. tx . producer ,
1068
+ consumer : xpd_mmap_offsets. tx . consumer ,
1069
+ desc : xpd_mmap_offsets. tx . desc ,
1070
+ flags : Some ( XdpRingFlags :: from_bits_retain ( xpd_mmap_offsets. tx . flags ) ) ,
1071
+ } ,
1072
+ fr : XdpRingOffset {
1073
+ producer : xpd_mmap_offsets. fr . producer ,
1074
+ consumer : xpd_mmap_offsets. fr . consumer ,
1075
+ desc : xpd_mmap_offsets. fr . desc ,
1076
+ flags : Some ( XdpRingFlags :: from_bits_retain ( xpd_mmap_offsets. fr . flags ) ) ,
1077
+ } ,
1078
+ cr : XdpRingOffset {
1079
+ producer : xpd_mmap_offsets. cr . producer ,
1080
+ consumer : xpd_mmap_offsets. cr . consumer ,
1081
+ desc : xpd_mmap_offsets. cr . desc ,
1082
+ flags : Some ( XdpRingFlags :: from_bits_retain ( xpd_mmap_offsets. cr . flags ) ) ,
1083
+ } ,
1084
+ } )
1085
+ }
1086
+ }
1087
+
1088
+ #[ cfg( target_os = "linux" ) ]
1089
+ #[ inline]
1090
+ pub ( crate ) fn get_xdp_statistics ( fd : BorrowedFd < ' _ > ) -> io:: Result < XdpStatistics > {
1091
+ let mut optlen = core:: mem:: size_of :: < xdp_statistics > ( ) . try_into ( ) . unwrap ( ) ;
1092
+ debug_assert ! (
1093
+ optlen as usize >= core:: mem:: size_of:: <c:: c_int>( ) ,
1094
+ "Socket APIs don't ever use `bool` directly"
1095
+ ) ;
1096
+ let mut value = MaybeUninit :: < xdp_statistics > :: zeroed ( ) ;
1097
+ getsockopt_raw ( fd, c:: SOL_XDP , c:: XDP_STATISTICS , & mut value, & mut optlen) ?;
1098
+
1099
+ if optlen as usize == core:: mem:: size_of :: < xdp_statistics_v1 > ( ) {
1100
+ // Safety: All members of xdp_statistics are u64 and thus are correctly initialized
1101
+ // by `MaybeUninit::<xdp_statistics>::zeroed()`
1102
+ let xdp_statistics = unsafe { value. assume_init ( ) } ;
1103
+ Ok ( XdpStatistics {
1104
+ rx_dropped : xdp_statistics. rx_dropped ,
1105
+ rx_invalid_descs : xdp_statistics. rx_dropped ,
1106
+ tx_invalid_descs : xdp_statistics. rx_dropped ,
1107
+ rx_ring_full : None ,
1108
+ rx_fill_ring_empty_descs : None ,
1109
+ tx_ring_empty_descs : None ,
1110
+ } )
1111
+ } else {
1112
+ assert_eq ! (
1113
+ optlen as usize ,
1114
+ core:: mem:: size_of:: <xdp_statistics>( ) ,
1115
+ "unexpected getsockopt size"
1116
+ ) ;
1117
+ // Safety: All members of xdp_statistics are u64 and thus are correctly initialized
1118
+ // by `MaybeUninit::<xdp_statistics>::zeroed()`
1119
+ let xdp_statistics = unsafe { value. assume_init ( ) } ;
1120
+ Ok ( XdpStatistics {
1121
+ rx_dropped : xdp_statistics. rx_dropped ,
1122
+ rx_invalid_descs : xdp_statistics. rx_invalid_descs ,
1123
+ tx_invalid_descs : xdp_statistics. tx_invalid_descs ,
1124
+ rx_ring_full : Some ( xdp_statistics. rx_ring_full ) ,
1125
+ rx_fill_ring_empty_descs : Some ( xdp_statistics. rx_fill_ring_empty_descs ) ,
1126
+ tx_ring_empty_descs : Some ( xdp_statistics. tx_ring_empty_descs ) ,
1127
+ } )
1128
+ }
1129
+ }
1130
+
1131
+ #[ cfg( target_os = "linux" ) ]
1132
+ #[ inline]
1133
+ pub ( crate ) fn get_xdp_options ( fd : BorrowedFd < ' _ > ) -> io:: Result < XdpOptionsFlags > {
1134
+ getsockopt ( fd, c:: SOL_XDP , c:: XDP_OPTIONS )
1135
+ }
1136
+
966
1137
#[ inline]
967
1138
fn to_ip_mreq ( multiaddr : & Ipv4Addr , interface : & Ipv4Addr ) -> c:: ip_mreq {
968
1139
c:: ip_mreq {
0 commit comments