1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//! [`Umem`](crate::umem::Umem) and [`Socket`](crate::socket::Socket)
//! configuration.

mod socket;
pub use socket::{
    BindFlags, Config as SocketConfig, ConfigBuilder as SocketConfigBuilder, Interface,
    LibbpfFlags, XdpFlags,
};

mod umem;
pub use umem::{
    Config as UmemConfig, ConfigBuildError as UmemConfigBuilderError,
    ConfigBuilder as UmemConfigBuilder,
};

use std::{convert::TryFrom, error, fmt};

use crate::util;

/// The minimum [`Umem`](crate::Umem) frame size.
///
/// Matches the constant of the same name defined in the linux source
/// at `net/xdp/xdp_umem.c`
pub const XDP_UMEM_MIN_CHUNK_SIZE: u32 = 2048;

/// A ring's buffer size. Must be a power of two.
#[derive(Debug, Clone, Copy)]
pub struct QueueSize(u32);

impl QueueSize {
    /// Create a new `QueueSize` instance. Fails if `size` is not a
    /// power of two.
    pub fn new(size: u32) -> Result<Self, QueueSizeError> {
        if !util::is_pow_of_two(size) {
            Err(QueueSizeError(size))
        } else {
            Ok(Self(size))
        }
    }

    /// The queue size.
    pub fn get(&self) -> u32 {
        self.0
    }
}

impl TryFrom<u32> for QueueSize {
    type Error = QueueSizeError;

    fn try_from(size: u32) -> Result<Self, Self::Error> {
        QueueSize::new(size)
    }
}

/// Error signifying incorrect queue size.
#[derive(Debug)]
pub struct QueueSizeError(u32);

impl fmt::Display for QueueSizeError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "expected a power of two as queue size, got {}", self.0)
    }
}

impl error::Error for QueueSizeError {}

/// The size of a [`Umem`](crate::umem::Umem) frame. Cannot be smaller
/// than [`XDP_UMEM_MIN_CHUNK_SIZE`].
#[derive(Debug, Clone, Copy)]
pub struct FrameSize(u32);

impl FrameSize {
    /// Create a new `FrameSize` instance. Fails if `size` is smaller
    /// than [`XDP_UMEM_MIN_CHUNK_SIZE`].
    pub fn new(size: u32) -> Result<Self, FrameSizeError> {
        if size < XDP_UMEM_MIN_CHUNK_SIZE {
            Err(FrameSizeError(size))
        } else {
            Ok(Self(size))
        }
    }

    /// The frame size.
    pub fn get(&self) -> u32 {
        self.0
    }
}

impl TryFrom<u32> for FrameSize {
    type Error = FrameSizeError;

    fn try_from(size: u32) -> Result<Self, Self::Error> {
        FrameSize::new(size)
    }
}

/// Error signifying incorrect frame size.
#[derive(Debug)]
pub struct FrameSizeError(u32);

impl fmt::Display for FrameSizeError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "expected frame size >= {}, got {}",
            XDP_UMEM_MIN_CHUNK_SIZE, self.0
        )
    }
}

impl error::Error for FrameSizeError {}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn queue_size_should_accept_only_non_zero_powers_of_two() {
        assert!(QueueSize::new(0).is_err());
        assert!(QueueSize::new(1).is_ok());
        assert!(QueueSize::new(2).is_ok());
        assert!(QueueSize::new(3).is_err());
        assert!(QueueSize::new(4).is_ok());
    }

    #[test]
    fn frame_size_should_reject_values_below_2048() {
        assert!(FrameSize::new(0).is_err());
        assert!(FrameSize::new(XDP_UMEM_MIN_CHUNK_SIZE - 1).is_err());
        assert!(FrameSize::new(XDP_UMEM_MIN_CHUNK_SIZE).is_ok());
        assert!(FrameSize::new(XDP_UMEM_MIN_CHUNK_SIZE + 1).is_ok())
    }
}