From 8954fa8fefa660af87e2d99a1f8eefe5ffa76b4e Mon Sep 17 00:00:00 2001 From: Mark Date: Fri, 20 Mar 2020 22:12:51 +0200 Subject: [PATCH] Split packet queues --- etc/make/conf.mk | 1 + include/net/packet.h | 14 +++++++- include/net/raw.h | 16 +++++++++ include/user/socket.h | 4 +++ net/net.c | 81 ++++++++++++++++++++++++++++++++----------- net/raw.c | 43 +++++++++++++++++++++++ net/udp.c | 13 ++++--- 7 files changed, 144 insertions(+), 28 deletions(-) create mode 100644 include/net/raw.h create mode 100644 net/raw.c diff --git a/etc/make/conf.mk b/etc/make/conf.mk index b610cef..11772d3 100644 --- a/etc/make/conf.mk +++ b/etc/make/conf.mk @@ -102,6 +102,7 @@ OBJS+=$(O)/sys/sys_net.o \ $(O)/net/inet.o \ $(O)/net/icmp.o \ $(O)/net/udp.o \ + $(O)/net/raw.o \ $(O)/net/if.o \ $(O)/net/util.o DIRS+=$(O)/net diff --git a/include/net/packet.h b/include/net/packet.h index 1f6e1e8..de8fa4b 100644 --- a/include/net/packet.h +++ b/include/net/packet.h @@ -6,11 +6,23 @@ struct netdev; #define PACKET_DATA_MAX (4056) struct packet { size_t size; - struct packet *prev, *next; struct netdev *dev; size_t refcount; char data[PACKET_DATA_MAX]; }; +struct packet_qh { + struct packet *packet; + struct packet_qh *prev, *next; +}; + +struct packet_queue { + struct packet_qh *head, *tail; +}; + void packet_ref(struct packet *p); void packet_unref(struct packet *p); + +void packet_queue_init(struct packet_queue *q); +void packet_queue_push(struct packet_queue *q, struct packet *p); +struct packet *packet_queue_pop(struct packet_queue *q); diff --git a/include/net/raw.h b/include/net/raw.h new file mode 100644 index 0000000..b1a5fd6 --- /dev/null +++ b/include/net/raw.h @@ -0,0 +1,16 @@ +#pragma once +#include "sys/types.h" + +struct vfs_ioctx; +struct ofile; +struct sockaddr; +struct packet; + +int raw_socket_open(struct vfs_ioctx *ioctx, struct ofile *fd, int dom, int type, int proto); +ssize_t raw_socket_send(struct vfs_ioctx *ioctx, struct ofile *fd, const void *buf, size_t lim, struct sockaddr *sa, size_t salen); +ssize_t raw_socket_recv(struct vfs_ioctx *ioctx, struct ofile *fd, void *buf, size_t lim, struct sockaddr *sa, size_t *salen); +int raw_socket_bind(struct vfs_ioctx *ioctx, struct ofile *fd, struct sockaddr *sa, size_t len); +int raw_setsockopt(struct vfs_ioctx *ioctx, struct ofile *fd, int optname, void *optval, size_t optlen); +void raw_socket_close(struct vfs_ioctx *ioctx, struct ofile *fd); + +void raw_packet_handle(struct packet *p); diff --git a/include/user/socket.h b/include/user/socket.h index bf3d50e..c675d41 100644 --- a/include/user/socket.h +++ b/include/user/socket.h @@ -5,9 +5,13 @@ #define PF_INET 2 #define AF_INET PF_INET +#define PF_PACKET 17 +#define AF_PACKET PF_PACKET + /* Socket types */ #define SOCK_STREAM 1 #define SOCK_DGRAM 2 +#define SOCK_RAW 3 /* sockopts */ #define SO_BINDTODEVICE 25 diff --git a/net/net.c b/net/net.c index 07c199d..ba0dca6 100644 --- a/net/net.c +++ b/net/net.c @@ -9,17 +9,19 @@ #include "sys/panic.h" #include "sys/debug.h" #include "fs/ofile.h" +#include "sys/heap.h" #include "sys/spin.h" #include "net/packet.h" #include "net/eth.h" #include "net/udp.h" +#include "net/raw.h" #include "net/net.h" #include "net/if.h" static struct thread netd_thread = {0}; static spin_t g_rxq_lock = 0; -static struct packet *g_rxq_head, *g_rxq_tail; +static struct packet_queue g_rxq; static struct packet *packet_create(void); static void packet_free(struct packet *p); @@ -27,6 +29,8 @@ static void packet_free(struct packet *p); static inline void net_handle_packet(struct packet *p) { // TODO: check if interface sends packet not in ethernet format eth_handle_frame(p); + // Notify all raw sockets + raw_packet_handle(p); } static void net_daemon(void) { @@ -34,7 +38,7 @@ static void net_daemon(void) { uintptr_t irq; while (1) { - if (!g_rxq_head) { + if (!g_rxq.head) { // qword writes are atomic (when storing new head) // so I guess checking if ANYTHING is present // before locking is a good idea to avoid unnecessary @@ -45,14 +49,8 @@ static void net_daemon(void) { } spin_lock_irqsave(&g_rxq_lock, &irq); - _assert(g_rxq_head); - p = g_rxq_head; - g_rxq_head = g_rxq_head->next; - if (!g_rxq_head) { - g_rxq_tail = NULL; - } else { - g_rxq_head->prev = NULL; - } + p = packet_queue_pop(&g_rxq); + _assert(p); spin_release_irqrestore(&g_rxq_lock, &irq); net_handle_packet(p); @@ -61,6 +59,43 @@ static void net_daemon(void) { } } +static inline struct packet_qh *packet_qh_create(struct packet *p) { + struct packet_qh *qh = kmalloc(sizeof(struct packet_qh)); + _assert(qh); + qh->packet = p; + return qh; +} + +void packet_queue_push(struct packet_queue *pq, struct packet *p) { + struct packet_qh *qh = packet_qh_create(p); + + if (pq->tail) { + pq->tail->next = qh; + } else { + pq->head = qh; + } + qh->prev = pq->tail; + qh->next = NULL; + pq->tail = qh; +} + +struct packet *packet_queue_pop(struct packet_queue *pq) { + struct packet_qh *qh = pq->head; + _assert(qh); + pq->head = qh->next; + if (!pq->head) { + pq->tail = NULL; + } + struct packet *p = qh->packet; + kfree(qh); + return p; +} + +void packet_queue_init(struct packet_queue *pq) { + pq->head = NULL; + pq->tail = NULL; +} + static struct packet *packet_create(void) { struct packet *packet; uintptr_t page = amd64_phys_alloc_page(); @@ -101,20 +136,15 @@ int net_receive(struct netdev *dev, const void *data, size_t len) { packet_ref(p); spin_lock(&g_rxq_lock); - p->next = NULL; - p->prev = g_rxq_tail; - if (g_rxq_tail) { - g_rxq_tail->next = p; - } else { - g_rxq_head = p; - } - g_rxq_tail = p; + packet_queue_push(&g_rxq, p); spin_release(&g_rxq_lock); return 0; } void net_daemon_start(void) { + packet_queue_init(&g_rxq); + _assert(thread_init(&netd_thread, (uintptr_t) net_daemon, NULL, 0) == 0); netd_thread.pid = thread_alloc_pid(0); sched_queue(&netd_thread); @@ -124,15 +154,26 @@ int net_socket_open(struct vfs_ioctx *ioctx, struct ofile *fd, int dom, int type _assert(fd); fd->flags = OF_SOCKET; - if (dom == AF_INET) { + switch (dom) { + case AF_INET: switch (type) { case SOCK_DGRAM: return udp_socket_open(ioctx, fd, dom, type, proto); default: break; } + break; + case AF_PACKET: + switch (type) { + case SOCK_RAW: + return raw_socket_open(ioctx, fd, dom, type, proto); + default: + break; + } + break; + default: + break; } - return -EINVAL; } diff --git a/net/raw.c b/net/raw.c new file mode 100644 index 0000000..dd5a7c8 --- /dev/null +++ b/net/raw.c @@ -0,0 +1,43 @@ +#include "user/socket.h" +#include "sys/assert.h" +#include "net/packet.h" +#include "fs/ofile.h" +#include "sys/heap.h" +#include "net/raw.h" + +struct raw_socket { + struct packet_queue queue; + struct raw_socket *prev, *next; +}; + +static struct raw_socket *g_raw_sockets = NULL; + +int raw_socket_open(struct vfs_ioctx *ioctx, struct ofile *fd, int dom, int type, int proto) { + // TODO: check your privilege + struct raw_socket *r_sock = kmalloc(sizeof(struct raw_socket)); + _assert(r_sock); + + packet_queue_init(&r_sock->queue); + r_sock->prev = NULL; + r_sock->next = g_raw_sockets; + g_raw_sockets = r_sock; + + fd->flags |= OF_SOCKET; + fd->socket.sock = r_sock; + fd->socket.domain = PF_PACKET; + fd->socket.type = SOCK_RAW; + + return 0; +} + +void raw_socket_close(struct vfs_ioctx *ioctx, struct ofile *fd) { + // Do nothing, I guess +} + +void raw_packet_handle(struct packet *p) { + // Queue the packet for all the sockets + for (struct raw_socket *r = g_raw_sockets; r; r = r->next) { + packet_ref(p); + packet_queue_push(&r->queue, p); + } +} diff --git a/net/udp.c b/net/udp.c index 06ad30d..de211b7 100644 --- a/net/udp.c +++ b/net/udp.c @@ -30,7 +30,7 @@ struct udp_socket { uint32_t recv_inaddr; struct netdev *bound; // Bound interface (all packets go to this interface if set) struct thread *owner; // Thread to suspend on blocking operation - struct packet *pending; + struct packet_queue pending; }; static uint16_t udp_eph_port = 32768; @@ -48,8 +48,8 @@ struct udp_socket *udp_socket_create(void) { sock->port = 0; sock->recv_port = 0; sock->owner = NULL; - sock->pending = NULL; sock->bound = NULL; + packet_queue_init(&sock->pending); return sock; } @@ -74,7 +74,7 @@ ssize_t udp_socket_recv(struct vfs_ioctx *ioctx, struct ofile *fd, void *buf, si sock->owner = t; - if (!sock->pending) { + if (!sock->pending.head) { sock->flags |= UDP_SOCKET_PENDING; while ((sock->flags & UDP_SOCKET_PENDING)) { @@ -84,8 +84,8 @@ ssize_t udp_socket_recv(struct vfs_ioctx *ioctx, struct ofile *fd, void *buf, si } // Read a single packet - p = sock->pending; - sock->pending = p->next; + p = packet_queue_pop(&sock->pending); + _assert(p); size_t f_size = sizeof(struct eth_frame) + sizeof(struct inet_frame) + sizeof(struct udp_frame); const void *p_data = p->data + f_size; @@ -221,8 +221,7 @@ void udp_handle_frame(struct packet *p, struct eth_frame *eth, struct inet_frame if (sock) { // Add "pending" packet for this socket packet_ref(p); - p->next = sock->pending; - sock->pending = p; + packet_queue_push(&sock->pending, p); if (sock->flags & UDP_SOCKET_PENDING) { sock->flags &= ~UDP_SOCKET_PENDING;