1 /*
2 * Copyright 2024 The Netty Project
3 *
4 * The Netty Project licenses this file to you under the Apache License,
5 * version 2.0 (the "License"); you may not use this file except in compliance
6 * with the License. You may obtain a copy of the License at:
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations
14 * under the License.
15 */
16 package io.netty.channel.uring;
17
18 import io.netty.channel.IoOps;
19
20 /**
21 * {@link IoOps} for implementation for
22 * <a href="https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h">Io_uring</a>.
23 */
24 public final class IoUringIoOps implements IoOps {
25
26 private final byte opcode;
27 private final byte flags;
28 private final short ioPrio;
29 private final int fd;
30 private final long union1;
31 private final long union2;
32 private final int len;
33 private final int union3;
34 private final short data;
35 private final short personality;
36 private final short union4;
37 private final int union5;
38 private final long union6;
39
40 /**
41 * Create a new instance which represents the {@code io_uring_sqe} struct.
42 *
43 * <pre>{@code
44 * struct io_uring_sqe {
45 * __u8 opcode; // type of operation for this sqe
46 * __u8 flags; // IOSQE_ flags
47 * __u16 ioprio; // ioprio for the request
48 * __s32 fd; // file descriptor to do IO on
49 *
50 * union { // union1
51 * __u64 off; // offset into file
52 * __u64 addr2;
53 * struct {
54 * __u32 cmd_op;
55 * __u32 __pad1;
56 * };
57 * };
58 *
59 * union { // union2
60 * __u64 addr; // pointer to buffer or iovecs
61 * __u64 splice_off_in;
62 * struct {
63 * __u32 level;
64 * __u32 optname;
65 * };
66 * };
67 * __u32 len; // buffer size or number of iovecs
68 *
69 * union { // union3
70 * __kernel_rwf_t rw_flags;
71 * __u32 fsync_flags;
72 * __u16 poll_events; // compatibility
73 * __u32 poll32_events; // word-reversed for BE
74 * __u32 sync_range_flags;
75 * __u32 msg_flags;
76 * __u32 timeout_flags;
77 * __u32 accept_flags;
78 * __u32 cancel_flags;
79 * __u32 open_flags;
80 * __u32 statx_flags;
81 * __u32 fadvise_advice;
82 * __u32 splice_flags;
83 * __u32 rename_flags;
84 * __u32 unlink_flags;
85 * __u32 hardlink_flags;
86 * __u32 xeattr_flags;
87 * __u32 msg_ring_flags;
88 * __u32 uring_cmd_flags;
89 * __u32 waitid_flags;
90 * __u32 futex_flags;
91 * __u32 install_fd_flags;
92 * __u32 nop_flags;
93 * };
94 * __u64 user_data; // data to be passed back at completion time
95 * // pack this to avoid bogus arm OABI complaints
96 *
97 * union { // union4
98 *
99 * // index into fixed buffers, if used
100 * __u16 buf_index;
101 * // for grouped buffer selection
102 * __u16 buf_group;
103 * }__attribute__((packed));
104 * // personality to use, if used
105 * __u16 personality;
106 *
107 * union { // union5
108 *
109 * __s32 splice_fd_in;
110 * __u32 file_index;
111 * __u32 optlen;
112 * struct {
113 * __u16 addr_len;
114 * __u16 __pad3[ 1];
115 * };
116 * };
117 *
118 * union { // union6
119 *
120 * struct {
121 * __u64 addr3;
122 * __u64 __pad2[ 1];
123 * };
124 * __u64 optval;
125 * //
126 * // If the ring is initialized with IORING_SETUP_SQE128, then
127 * // this field is used for 80 bytes of arbitrary command data
128 * __u8 cmd[ 0];
129 * };
130 * };
131 * }
132 * </pre>
133 */
134 public IoUringIoOps(byte opcode, byte flags, short ioPrio, int fd, long union1, long union2, int len, int union3,
135 short data, short union4, short personality, int union5, long union6) {
136 this.opcode = opcode;
137 this.flags = flags;
138 this.ioPrio = ioPrio;
139 this.fd = fd;
140 this.union1 = union1;
141 this.union2 = union2;
142 this.len = len;
143 this.union3 = union3;
144 this.data = data;
145 this.union4 = union4;
146 this.personality = personality;
147 this.union5 = union5;
148 this.union6 = union6;
149 }
150
151 byte opcode() {
152 return opcode;
153 }
154
155 byte flags() {
156 return flags;
157 }
158
159 short ioPrio() {
160 return ioPrio;
161 }
162
163 int fd() {
164 return fd;
165 }
166
167 long union1() {
168 return union1;
169 }
170
171 long union2() {
172 return union2;
173 }
174
175 int len() {
176 return len;
177 }
178
179 int union3() {
180 return union3;
181 }
182
183 short data() {
184 return data;
185 }
186
187 short personality() {
188 return personality;
189 }
190
191 short union4() {
192 return union4;
193 }
194
195 int union5() {
196 return union5;
197 }
198
199 long union6() {
200 return union6;
201 }
202
203 @Override
204 public String toString() {
205 return "IOUringIoOps{" +
206 "opcode=" + opcode +
207 ", flags=" + flags +
208 ", ioPrio=" + ioPrio +
209 ", fd=" + fd +
210 ", union1=" + union1 +
211 ", union2=" + union2 +
212 ", len=" + len +
213 ", union3=" + union3 +
214 ", data=" + data +
215 ", union4=" + union4 +
216 ", personality=" + personality +
217 ", union5=" + union5 +
218 ", union6=" + union6 +
219 '}';
220 }
221
222 /**
223 * Returns a new {@code OP_ASYNC_CANCEL} {@link IoUringIoOps}.
224 *
225 * @param flags the flags.
226 * @param userData the user data that identify a previous submitted {@link IoUringIoOps} that should be cancelled.
227 * The value to use here is returned by {@link io.netty.channel.IoRegistration#submit(IoOps)}.
228 * @param data the data
229 * @return ops.
230 */
231 static IoUringIoOps newAsyncCancel(byte flags, long userData, short data) {
232 // Best effort to cancel the
233 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L679
234 return new IoUringIoOps(Native.IORING_OP_ASYNC_CANCEL, flags, (short) 0, -1, 0, userData, 0, 0,
235 data, (short) 0, (short) 0, 0, 0);
236 }
237
238 /**
239 * Returns a new {@code OP_CLOSE} {@link IoUringIoOps}.
240 *
241 * @param fd the filedescriptor
242 * @param flags the flags.
243 * @param data the data
244 * @return ops.
245 */
246 static IoUringIoOps newClose(int fd, byte flags, short data) {
247 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L764
248 return new IoUringIoOps(Native.IORING_OP_CLOSE, flags, (short) 0, fd, 0L, 0L, 0, 0, data,
249 (short) 0, (short) 0, 0, 0);
250 }
251
252 /**
253 * Returns a new {@code OP_POLL_ADD} {@link IoUringIoOps}.
254 *
255 * @param fd the filedescriptor
256 * @param flags the flags.
257 * @param mask the mask.
258 * @param len the len.
259 * @param data the data.
260 * @return ops.
261 */
262 static IoUringIoOps newPollAdd(int fd, byte flags, int mask, int len, short data) {
263 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L554
264 return new IoUringIoOps(Native.IORING_OP_POLL_ADD, flags, (short) 0, fd, 0L, 0L, len, mask, data,
265 (short) 0, (short) 0, 0, 0);
266 }
267
268 /**
269 * Returns a new {@code OP_SENDMSG} {@link IoUringIoOps}.
270 *
271 * @param fd the filedescriptor
272 * @param flags the flags.
273 * @param msgFlags the msg flags.
274 * @param data the data
275 * @return ops.
276 */
277 static IoUringIoOps newSendmsg(int fd, byte flags, int msgFlags, long address, short data) {
278 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L539
279 return new IoUringIoOps(Native.IORING_OP_SENDMSG, flags, (short) 0, fd, 0L, address, 1, msgFlags, data,
280 (short) 0, (short) 0, 0, 0);
281 }
282
283 /**
284 * Returns a new {@code OP_CONNECT} {@link IoUringIoOps}.
285 *
286 * @param fd the filedescriptor
287 * @param flags the flags.
288 * @param remoteMemoryAddress the memory address of the sockaddr_storage.
289 * @param data the data
290 * @return ops.
291 */
292 static IoUringIoOps newConnect(int fd, byte flags, long remoteMemoryAddress, short data) {
293 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L695
294 return newConnect(
295 fd, flags,
296 remoteMemoryAddress, Native.SIZEOF_SOCKADDR_STORAGE,
297 data
298 );
299 }
300
301 /**
302 * Returns a new {@code OP_CONNECT} {@link IoUringIoOps}.
303 *
304 * @param fd the filedescriptor
305 * @param flags the flags.
306 * @param remoteMemoryAddress the memory address of the sockaddr_storage.
307 * @param addrLen then remoteMemory storage length.
308 * @param data the data
309 * @return ops.
310 */
311 static IoUringIoOps newConnect(int fd, byte flags, long remoteMemoryAddress, int addrLen, short data) {
312 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L695
313 return new IoUringIoOps(Native.IORING_OP_CONNECT, flags, (short) 0, fd, addrLen,
314 remoteMemoryAddress, 0, 0, data, (short) 0, (short) 0, 0, 0);
315 }
316
317 /**
318 * Returns a new {@code OP_ACCEPT} {@link IoUringIoOps}.
319 *
320 * @param fd the filedescriptor
321 * @param flags the flags.
322 * @param acceptFlags the flags for ACCEPT itself
323 * @param ioPrio io_prio
324 * @param acceptedAddressMemoryAddress the memory address of the sockaddr_storage.
325 * @param acceptedAddressLengthMemoryAddress the memory address of the length that will be updated once a new
326 * connection was accepted.
327 * @param data the data
328 * @return ops.
329 */
330 static IoUringIoOps newAccept(int fd, byte flags, int acceptFlags, short ioPrio, long acceptedAddressMemoryAddress,
331 long acceptedAddressLengthMemoryAddress, short data) {
332 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L625
333 return new IoUringIoOps(Native.IORING_OP_ACCEPT, flags, ioPrio, fd, acceptedAddressLengthMemoryAddress,
334 acceptedAddressMemoryAddress, 0, acceptFlags, data, (short) 0, (short) 0, 0, 0);
335 }
336
337 /**
338 * Returns a new {@code OP_WRITEV} {@link IoUringIoOps}.
339 *
340 * @param fd the filedescriptor
341 * @param flags the flags.
342 * @param writevFlags the writev flags.
343 * @param memoryAddress the memory address of the io_vec array.
344 * @param length the length of the io_vec array.
345 * @param data the data
346 * @return ops.
347 */
348 static IoUringIoOps newWritev(int fd, byte flags, int writevFlags, long memoryAddress,
349 int length, short data) {
350 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L500
351 return new IoUringIoOps(Native.IORING_OP_WRITEV, flags, (short) 0, fd,
352 0, memoryAddress, length, writevFlags, data, (short) 0, (short) 0, 0, 0);
353 }
354
355 /**
356 * Returns a new {@code OP_WRITE} {@link IoUringIoOps}.
357 *
358 * @param fd the filedescriptor
359 * @param flags the flags.
360 * @param writeFlags the write flags.
361 * @param memoryAddress the memory address of the buffer
362 * @param length the length of the buffer.
363 * @param data the data
364 * @return ops.
365 */
366 static IoUringIoOps newWrite(
367 int fd, byte flags, int writeFlags, long memoryAddress, int length, short data) {
368 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L794
369 return new IoUringIoOps(Native.IORING_OP_WRITE, flags, (short) 0, fd,
370 0, memoryAddress, length, writeFlags, data, (short) 0, (short) 0, 0, 0);
371 }
372
373 /**
374 * Returns a new {@code OP_RECV} {@link IoUringIoOps}.
375 *
376 * @param fd the filedescriptor
377 * @param flags the flags.
378 * @param ioPrio the ioPrio.
379 * @param recvFlags the recv flags.
380 * @param memoryAddress the memory address of the buffer
381 * @param length the length of the buffer.
382 * @param data the data
383 * @return ops.
384 */
385 static IoUringIoOps newRecv(
386 int fd, byte flags, short ioPrio, int recvFlags, long memoryAddress, int length, short data) {
387 return newRecv(fd, flags, ioPrio, recvFlags, memoryAddress, length, data, (short) 0);
388 }
389
390 static IoUringIoOps newRecv(
391 int fd, byte flags, short ioPrio, int recvFlags, long memoryAddress, int length, short data, short bid) {
392 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L898
393 return new IoUringIoOps(Native.IORING_OP_RECV, flags, ioPrio, fd,
394 0, memoryAddress, length, recvFlags, data, bid, (short) 0, 0, 0);
395 }
396
397 static IoUringIoOps newSendZc(
398 int fd, long memoryAddress, int length,
399 int flags, short data, int zcFlags) {
400 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L867
401 return new IoUringIoOps(Native.IORING_OP_SEND_ZC, (byte) 0, (byte) zcFlags, fd,
402 0, memoryAddress, length, flags, data, (short) 0, (short) 0, 0, 0);
403 }
404
405 static IoUringIoOps newSendmsgZc(int fd, byte flags, int msgFlags, long address, short data) {
406 return new IoUringIoOps(Native.IORING_OP_SENDMSG_ZC, flags, (short) 0, fd, 0L, address, 1, msgFlags, data,
407 (short) 0, (short) 0, 0, 0);
408 }
409
410 /**
411 * Returns a new {@code OP_RECVMSG} {@link IoUringIoOps}.
412 *
413 * @param fd the filedescriptor
414 * @param flags the flags.
415 * @param msgFlags the recvmsg flags.
416 * @param memoryAddress the memory address of the msghdr struct
417 * @param data the data
418 * @return ops.
419 */
420 static IoUringIoOps newRecvmsg(int fd, byte flags, int msgFlags, long memoryAddress, short data) {
421 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L523
422 return new IoUringIoOps(
423 Native.IORING_OP_RECVMSG, flags, (short) 0, fd, 0L, memoryAddress, 1, msgFlags, data,
424 (short) 0, (short) 0, 0, 0);
425 }
426
427 /**
428 * Returns a new {@code OP_SEND} {@link IoUringIoOps}.
429 *
430 * @param fd the filedescriptor
431 * @param flags the flags.
432 * @param sendFlags the send flags.
433 * @param memoryAddress the memory address of the buffer.
434 * @param length the length of the buffer.
435 * @param data the data
436 * @return ops.
437 */
438 static IoUringIoOps newSend(
439 int fd, byte flags, int sendFlags, long memoryAddress, int length, short data) {
440 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L839
441 return new IoUringIoOps(Native.IORING_OP_SEND, flags, (short) 0, fd,
442 0, memoryAddress, length, sendFlags, data, (short) 0, (short) 0, 0, 0);
443 }
444
445 /**
446 * Returns a new {@code OP_SHUTDOWN} {@link IoUringIoOps}.
447 *
448 * @param fd the filedescriptor
449 * @param flags the flags.
450 * @param how how the shutdown will be done.
451 * @param data the data
452 * @return ops.
453 */
454 static IoUringIoOps newShutdown(int fd, byte flags, int how, short data) {
455 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L1023
456 return new IoUringIoOps(Native.IORING_OP_SHUTDOWN, flags, (short) 0, fd, 0, 0, how, 0, data,
457 (short) 0, (short) 0, 0, 0);
458 }
459
460 /**
461 *
462 * Returns a new {@code OP_SPLICE} {@link IoUringIoOps}.
463 *
464 * @param fd_in the filedescriptor
465 * @param off_in the filedescriptor offset
466 * @param fd_out the filedescriptor
467 * @param off_out the filedescriptor offset
468 * @param nbytes splice bytes
469 * @param splice_flags the flag
470 * @param data the data
471 * @return ops.
472 */
473 static IoUringIoOps newSplice(int fd_in, long off_in,
474 int fd_out, long off_out,
475 int nbytes,
476 int splice_flags,
477 short data) {
478 // See https://github.com/axboe/liburing/blob/liburing-2.8/src/include/liburing.h#L454
479 return new IoUringIoOps(
480 Native.IORING_OP_SPLICE, (byte) 0, (short) 0, fd_out, off_out, off_in,
481 nbytes, splice_flags, data, (short) 0, (short) 0, fd_in, 0
482 );
483 }
484 }