Split packet queues
This commit is contained in:
@@ -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
|
||||
|
||||
+13
-1
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user