79 if_rxq, rq_entries, area) {}
92 rq_entries, area, 0) {}
111 if_rxq, rq_entries, area) {}
123 : ring_(&runtime.ring_internal()), flags_(0) {
127 io_uring_zcrx_area_reg area_reg = {};
128 area_reg.addr = area.
offset;
129 area_reg.len = area.
size;
130 area_reg.flags = IORING_ZCRX_AREA_DMABUF;
132 register_ifq_(if_idx, if_rxq, rq_entries, area_reg,
133 sysconf(_SC_PAGESIZE));
137 [[maybe_unused]]
int r;
138 if (area_size_ > 0) {
139 assert(area_ptr_ !=
nullptr);
140 r = munmap(area_ptr_, area_size_);
143 assert(rq_ring_.ring_ptr !=
nullptr);
144 r = munmap(rq_ring_.ring_ptr, ring_size_);
154 uint32_t rq_entries,
const ZeroCopyRxArea &area,
156 : ring_(&ring), flags_(flags) {
157 const size_t page_size = sysconf(_SC_PAGESIZE);
159 if (area.addr ==
nullptr) {
160 area_size_ = detail::align_up(area.size, page_size);
161 area_ptr_ = mmap(
nullptr, area_size_, PROT_READ | PROT_WRITE,
162 MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
163 if (area_ptr_ == MAP_FAILED) {
164 throw detail::make_system_error(
"mmap");
166 auto d = detail::defer([&]() { munmap(area_ptr_, area_size_); });
168 io_uring_zcrx_area_reg area_reg = {};
169 area_reg.addr =
reinterpret_cast<uint64_t
>(area_ptr_);
170 area_reg.len = area_size_;
173 register_ifq_(if_idx, if_rxq, rq_entries, area_reg, page_size);
179 area_ptr_ = area.addr;
181 io_uring_zcrx_area_reg area_reg = {};
182 area_reg.addr =
reinterpret_cast<uint64_t
>(area_ptr_);
183 area_reg.len = area.size;
186 register_ifq_(if_idx, if_rxq, rq_entries, area_reg, page_size);
191 uint32_t zcrx_id() const noexcept {
return zcrx_id_; }
193 ZeroCopyRxBuffer handle_finish(io_uring_cqe *cqe)
noexcept {
194 assert(ring_->check_cqe32(cqe) &&
"Expected big CQE for ZeroCopyRx");
197 return ZeroCopyRxBuffer();
199 io_uring_zcrx_cqe *rcqe =
200 reinterpret_cast<io_uring_zcrx_cqe *
>(cqe->big_cqe);
201 void *data =
static_cast<char *
>(area_ptr_) +
202 (rcqe->off & ~IORING_ZCRX_AREA_MASK);
203 size_t size =
static_cast<size_t>(cqe->res);
204 return ZeroCopyRxBuffer(data, size,
this);
207 void add_buffer_back(
void *ptr,
size_t size)
noexcept {
208 rq_enqueue_(ptr, size);
213 void register_ifq_(uint32_t if_idx, uint32_t if_rxq, uint32_t rq_entries,
214 io_uring_zcrx_area_reg &area_reg,
size_t page_size) {
215 rq_entries = std::bit_ceil(rq_entries);
216 io_uring_region_desc region_reg = {};
217 ring_size_ = get_refill_ring_size_(rq_entries, page_size);
218 region_reg.user_addr = 0;
219 region_reg.size = ring_size_;
220 region_reg.flags = 0;
222 io_uring_zcrx_ifq_reg reg = {};
225 reg.rq_entries = rq_entries;
226 reg.area_ptr =
reinterpret_cast<uint64_t
>(&area_reg);
227 reg.region_ptr =
reinterpret_cast<uint64_t
>(®ion_reg);
230 int r = io_uring_register_ifq(ring_->ring(), ®);
232 throw detail::make_system_error(
"io_uring_register_ifq", -r);
237 void *ring_ptr = mmap(
nullptr, ring_size_, PROT_READ | PROT_WRITE,
238 MAP_SHARED | MAP_POPULATE, ring_->ring()->ring_fd,
239 static_cast<off_t
>(region_reg.mmap_offset));
240 if (ring_ptr == MAP_FAILED) {
241 throw detail::make_system_error(
"mmap");
243 rq_ring_.khead = (
unsigned int *)((
char *)ring_ptr + reg.offsets.head);
244 rq_ring_.ktail = (
unsigned int *)((
char *)ring_ptr + reg.offsets.tail);
246 (
struct io_uring_zcrx_rqe *)((
char *)ring_ptr + reg.offsets.rqes);
247 rq_ring_.rq_tail = 0;
248 rq_ring_.ring_entries = reg.rq_entries;
249 rq_ring_.ring_ptr = ring_ptr;
251 zcrx_id_ = reg.zcrx_id;
252 area_token_ = area_reg.rq_area_token;
255 static size_t get_refill_ring_size_(uint32_t rq_entries,
256 size_t page_size)
noexcept {
257 size_t ring_size = rq_entries *
sizeof(io_uring_zcrx_rqe);
258 ring_size += page_size;
259 ring_size = detail::align_up(ring_size, page_size);
263 size_t rq_nr_queued_() const noexcept {
264 return rq_ring_.rq_tail - io_uring_smp_load_acquire(rq_ring_.khead);
267 void rq_enqueue_(
void *ptr,
size_t size)
noexcept {
268 assert(rq_nr_queued_() < rq_ring_.ring_entries);
269 io_uring_zcrx_rqe *rqe;
270 unsigned rq_mask = rq_ring_.ring_entries - 1;
271 rqe = &rq_ring_.rqes[rq_ring_.rq_tail & rq_mask];
272 rqe->off = (
static_cast<char *
>(ptr) -
static_cast<char *
>(area_ptr_)) |
274 rqe->len =
static_cast<uint32_t
>(size);
275 io_uring_smp_store_release(rq_ring_.ktail, ++rq_ring_.rq_tail);
278 void flush_rq_() noexcept {
280 ctrl.zcrx_id = zcrx_id_;
281 ctrl.op = ZCRX_CTRL_FLUSH_RQ;
282 [[maybe_unused]]
int r =
283 io_uring_register_zcrx_ctrl(ring_->ring(), &ctrl);
287 void maybe_flush_rq_() noexcept {
288 if (rq_nr_queued_() >= rq_ring_.ring_entries ||
289 (flags_ & ZCRX_REG_NODEV)) {
299 io_uring_zcrx_rq rq_ring_;
301 uint64_t area_token_;