Kernel Sockets
This component of the Volo project provides a socket interface that can be used within the kernel. A common usage case for kernel sockets would be a network based file system, for example, CIFS.
Features:
- Familiar socket interface
- Asynchronous event notification
- Zero-copy send
Interface
The kernel socket interface (found in <sys/ksocket.h>) should look familiar to anyone who has used sockets in the past:
int ksocket~_socket(ksocket~_t \*, int, int, int, int, struct cred \*)
int ksocket~_bind(ksocket~_t, struct sockaddr \*, socklen~_t, struct cred \*)
int ksocket~_listen(ksocket~_t, int, struct cred \*)
int ksocket~_accept(ksocket~_t, struct sockaddr \*, socklen~_t \*, ksocket~_t \*, struct cred \*)
int ksocket~_connect(ksocket~_t, const struct sockaddr \*, socklen~_t, struct cred \*)
int ksocket~_send(ksocket~_t, void \*, size~_t, int, size~_t \*, struct cred \*)
int ksocket~_sendto(ksocket~_t, void \*, size~_t, int, struct sockaddr \*, socklen~_t, size~_t \*, struct cred \*)
int ksocket~_sendmsg(ksocket~_t, struct nmsghdr \*, int, size~_t \*, struct cred \*)
int ksocket~_sendmblk(ksocket~_t, struct nmsghdr \*, int, mblk~_t \*\*, struct cred \*)
int ksocket~_recv(ksocket~_t, void \*, size~_t, int, size~_t \*, struct cred \*)
int ksocket~_recvfrom(ksocket~_t, void \*, size~_t, int, struct sockaddr \*, socklen~_t \*, size~_t \*, struct cred \*)
int ksocket~_recvmsg(ksocket~_t, struct nmsghdr \*, int, size~_t \*, struct cred \*)
int ksocket~_shutdown(ksocket~_t, int, struct cred \*)
int ksocket~_setsockopt(ksocket~_t, int, int, const void \*, int, struct cred \*)
int ksocket~_getsockopt(ksocket~_t, int, int, void \*, int \*, struct cred \*)
int ksocket~_getpeername(ksocket~_t, struct sockaddr \*, socklen~_t \*, struct cred \*)
int ksocket~_getsockname(ksocket~_t, struct sockaddr \*, socklen~_t \*, struct cred \*)
int ksocket~_ioctl(ksocket~_t, int, intptr~_t, int \*, struct cred \*)
int ksocket~_setcallbacks(ksocket~_t, ksocket~_callbacks~_t \*, void \*, struct cred \*)
int ksocket~_close(ksocket~_t, struct cred \*)
void ksocket~_hold(ksocket~_t)
void ksocket~_rele(ksocket~_t)
One small difference between userland and kernel sockets is that all of the above functions return a result code that indicates whether the operation was successful. If an error was encountered, then the errno is returned, otherwise 0 is returned. Some userland socket functions (e.g., socket() and send()) return information other than error/success, and the kernel socket variant of those functions take an additional result parameter.
So, for example, creating a new TCP socket would be done as follows:
ksocket~_t s;
if (ksocket~_socket(&s, AF~_INET, SOCK~_STREAM, 0, KSOCKET~_SLEEP, CRED()) != 0) {
/// failure ///
...
}
...
Buffers that are passed in to send and receive functions are assumed to be in kernel space unless the MSG_USERSPACE flag is specified.
Event Notification
Kernel sockets that are created with ksocket_socket() are blocking, however, the behavior can be controlled using the FIONBIO ioctl. Event notification happens asynchronously via callback functions, which are controlled by ksocket_setcallbacks(). A different callback function can be registered for each event.
9
The available events are:
| Event | Occurs when |
|---|---|
| CONNECTED | connect() has successfully completed |
| CONNECTFAILED | connect() failed to establish a connection |
| DISCONNECTED | socket has been disconnected |
| OOBDATA | out-of-band data is pending |
| NEWDATA | new data has arrived |
| NEWCONN | new connection is available |
| CANSEND | flow controlled socket is now able to send more data |
| CANTSENDMORE | no more data can be sent on the socket |
| CANTRECVMORE | no new data will arrive |
| ERROR | an error has occurred |
The callback function is defined as:
typedef void (\*ksocket~_callback~_t)(ksocket~_t, ksocket~_callback~_event~_t, void \*, uintptr\//t)
Where the third argument is a user cookie specified when the callback was registered, and the fourth argument is event specific.
Zero copy send
Like the userland interface, the ksocket//{send,sendto,sendmsg}() functions will all copy the data from the buffer being passed in. However, with kernel sockets the copy can be avoided by using ksocket_sendmblk() to pass mblks (msgb(9S)) to the protocol. mblks can be constructed from user-supplied buffers using esballoc(9F).