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