Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Employ an approach that avoids copying contents of received network p…

…ackets.
  • Loading branch information...
commit fb0077acfc02e35f7f0f36b0a8c862df5df71618 1 parent ecb4a60
@pgj authored
View
89 packages/mirage-platform/lib/netif.ml
@@ -28,88 +28,19 @@
open Lwt
open Printf
-type sring = {
- buf: Io_page.t;
- header_size: int;
- slot_size: int;
- nr_ents: int;
-}
-
-let sring_hdr_size = 64 (* sizeof(struct sring_hdr) *)
-
-cstruct sring_hdr {
- uint16_t sr_cur;
- uint16_t sr_avail;
- uint16_t sr_size;
- uint16_t sr_slotsize;
- uint8_t sr_pad[56]
-} as little_endian
-
-let sslot_size = 2 (* sizeof(struct sslot) *)
-
-cstruct sslot {
- uint16_t ss_len
-} as little_endian
-
-let nr_ents sring = sring.nr_ents
-
-let avail_packet sring =
- let hdr = Io_page.sub sring.buf 0 sring.header_size in
- get_sring_hdr_sr_avail hdr
-
-let slot sring i =
- let idx = i land (sring.nr_ents - 1) in
- let off = sring.header_size + (idx * sslot_size) in
- let s = Io_page.sub sring.buf off sslot_size in
- let size = get_sslot_ss_len s in
- let off = sring.header_size + (sring.nr_ents * sslot_size) +
- (idx * sring.slot_size) in
- Io_page.sub sring.buf off size
-
-let top_packet sring = slot sring (get_sring_hdr_sr_cur (sring.buf))
-
-let pop_packet sring =
- let b = sring.buf in
- let i = get_sring_hdr_sr_cur b in
- let n = get_sring_hdr_sr_avail b in
- set_sring_hdr_sr_cur b ((i + 1) land (sring.nr_ents - 1));
- set_sring_hdr_sr_avail b (n - 1);
- return ()
-
-let of_buf buf slot_size =
- let power_of_2 x =
- let x = x lor (x lsr 1) in
- let x = x lor (x lsr 2) in
- let x = x lor (x lsr 4) in
- let x = x lor (x lsr 8) in
- let x = x lor (x lsr 16) in
- let x = x lor (x lsr 32) in
- x - (x lsr 1)
- in
- let header_size = sring_hdr_size in
- let total = Io_page.length buf in
- let free_bytes = total - header_size in
- let nr_ents = power_of_2 (free_bytes / slot_size) in
- assert (header_size + (nr_ents * (sslot_size + slot_size)) < total);
- set_sring_hdr_sr_cur buf 0;
- set_sring_hdr_sr_avail buf 0;
- set_sring_hdr_sr_size buf nr_ents;
- set_sring_hdr_sr_slotsize buf slot_size;
- { buf; header_size; slot_size; nr_ents }
-
type t = {
backend_id: int;
backend: string;
mac: string;
mutable active: bool;
- rx_ring: sring;
}
type id = string
external get_vifs: unit -> id list = "caml_get_vifs"
-external plug_vif: id -> Io_page.t -> bool * int * string = "caml_plug_vif"
+external plug_vif: id -> bool * int * string = "caml_plug_vif"
external unplug_vif: id -> unit = "caml_unplug_vif"
+external get_mbufs : int -> Io_page.t list = "caml_get_mbufs"
let devices : (id, t) Hashtbl.t = Hashtbl.create 1
@@ -128,10 +59,8 @@ let plug id =
return (Hashtbl.find devices id)
with Not_found ->
let backend = id in
- let buf = Io_page.get ~pages_per_block:33 () in
- let rx_ring = of_buf buf 2048 in
- let active,backend_id,mac = plug_vif id buf in
- let t = { backend_id; backend; mac; active; rx_ring } in
+ let active,backend_id,mac = plug_vif id in
+ let t = { backend_id; backend; mac; active } in
Hashtbl.add devices id t;
return t
@@ -161,10 +90,12 @@ let writev ifc pages =
return ()
let rx_poll ifc fn =
- while_lwt (avail_packet ifc.rx_ring > 0) do
- fn (top_packet ifc.rx_ring) >>
- pop_packet ifc.rx_ring
- done
+ let mbufs = get_mbufs ifc.backend_id in
+ Lwt_list.iter_s (fun m ->
+ try_lwt fn m
+ with exn ->
+ return (printf "Exception on receive: %s\n%!" (Printexc.to_string exn)))
+ mbufs
let listen ifc fn =
let rec poll_t () =
View
185 packages/mirage-platform/runtime/kernel/netif_stubs.c
@@ -29,12 +29,13 @@
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/param.h>
-#include <sys/mbuf.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/systm.h>
+#include <sys/mbuf.h>
#include <sys/libkern.h>
-#include <sys/sdt.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
#include <net/if.h>
#include <net/if_dl.h>
@@ -48,25 +49,9 @@
#include "caml/fail.h"
#include "caml/bigarray.h"
-#define MBUF_LEN(mb) ((mb)->m_pkthdr.len)
-
-SDT_PROVIDER_DECLARE(mirage);
-
-SDT_PROBE_DEFINE(mirage, kernel, netif, plug_vif, plug_vif);
-SDT_PROBE_ARGTYPE(mirage, kernel, netif, plug_vif, 0, "int");
-SDT_PROBE_ARGTYPE(mirage, kernel, netif, plug_vif, 1, "int");
-
-
-struct sring_hdr {
- uint16_t sr_cur;
- uint16_t sr_avail;
- uint16_t sr_size;
- uint16_t sr_slotsize;
- uint8_t sr_pad[56];
-};
-
-struct sslot {
- uint16_t ss_len;
+struct mbuf_entry {
+ LIST_ENTRY(mbuf_entry) me_next;
+ struct mbuf *me_m;
};
struct plugged_if {
@@ -76,7 +61,8 @@ struct plugged_if {
int pi_flags;
char pi_lladdr[32];
char pi_xname[IFNAMSIZ];
- void *pi_rx;
+ struct mtx pi_rx_lock;
+ LIST_HEAD(, mbuf_entry) pi_rx_head;
};
TAILQ_HEAD(plugged_ifhead, plugged_if) pihead =
@@ -87,13 +73,36 @@ int plugged = 0;
/* Currently only Ethernet interfaces are returned. */
CAMLprim value caml_get_vifs(value v_unit);
-CAMLprim value caml_plug_vif(value id, value rxring);
+CAMLprim value caml_plug_vif(value id);
CAMLprim value caml_unplug_vif(value id);
+CAMLprim value caml_get_mbufs(value id);
void netif_ether_input(struct ifnet *ifp, struct mbuf **mp);
int netif_ether_output(struct ifnet *ifp, struct mbuf **mp);
+static struct plugged_if *
+find_pi_by_index(u_short val)
+{
+ struct plugged_if *pip;
+
+ TAILQ_FOREACH(pip, &pihead, pi_next)
+ if (pip->pi_index == val)
+ return pip;
+ return NULL;
+}
+
+static struct plugged_if *
+find_pi_by_name(const char *val)
+{
+ struct plugged_if *pip;
+
+ TAILQ_FOREACH(pip, &pihead, pi_next)
+ if (strncmp(pip->pi_xname, val, IFNAMSIZ) == 0)
+ return pip;
+ return NULL;
+}
+
CAMLprim value
caml_get_vifs(value v_unit)
{
@@ -103,8 +112,7 @@ caml_get_vifs(value v_unit)
struct ifaddr *ifa;
struct sockaddr_dl *sdl;
- result = Val_emptylist
- CURVNET_SET(TD_TO_VNET(curthread));;
+ result = Val_emptylist;
IFNET_RLOCK_NOSLEEP();
TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
IF_ADDR_RLOCK(ifp);
@@ -124,14 +132,13 @@ caml_get_vifs(value v_unit)
IF_ADDR_RUNLOCK(ifp);
}
IFNET_RUNLOCK_NOSLEEP();
- CURVNET_RESTORE();
CAMLreturn(result);
}
CAMLprim value
-caml_plug_vif(value id, value rxring)
+caml_plug_vif(value id)
{
- CAMLparam2(id, rxring);
+ CAMLparam1(id);
CAMLlocal1(result);
struct ifnet *ifp;
struct ifaddr *ifa;
@@ -140,13 +147,12 @@ caml_plug_vif(value id, value rxring)
int found;
u_char lladdr[8];
- pip = malloc(sizeof(struct plugged_if), M_MIRAGE, M_NOWAIT);
+ pip = malloc(sizeof(struct plugged_if), M_MIRAGE, M_NOWAIT | M_ZERO);
if (pip == NULL)
caml_failwith("Out of memory");
found = 0;
- CURVNET_SET(TD_TO_VNET(curthread));
IFNET_WLOCK();
TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
IF_ADDR_RLOCK(ifp);
@@ -173,7 +179,6 @@ caml_plug_vif(value id, value rxring)
IF_ADDR_RUNLOCK(ifp);
}
IFNET_WUNLOCK();
- CURVNET_RESTORE();
if (!found) {
free(pip, M_MIRAGE);
@@ -183,11 +188,8 @@ caml_plug_vif(value id, value rxring)
sprintf(pip->pi_lladdr, "%02x:%02x:%02x:%02x:%02x:%02x", lladdr[0],
lladdr[1], lladdr[2], lladdr[3], lladdr[4], lladdr[5]);
- pip->pi_rx = Caml_ba_data_val(rxring);
-
- SDT_PROBE(mirage, kernel, netif, plug_vif,
- ((struct sring_hdr *) pip->pi_rx)->sr_size,
- ((struct sring_hdr *) pip->pi_rx)->sr_slotsize, 0, 0, 0);
+ mtx_init(&pip->pi_rx_lock, "plugged_if_rx", NULL, MTX_DEF);
+ LIST_INIT(&pip->pi_rx_head);
if (plugged == 0)
TAILQ_INIT(&pihead);
@@ -208,20 +210,12 @@ caml_unplug_vif(value id)
CAMLparam1(id);
struct plugged_if *pip;
struct ifnet *ifp;
- int found;
-
- found = 0;
- TAILQ_FOREACH(pip, &pihead, pi_next) {
- if (strncmp(pip->pi_xname, String_val(id), IFNAMSIZ) == 0) {
- found = 1;
- break;
- }
- }
+ struct mbuf_entry *e1, *e2;
- if (!found)
+ pip = find_pi_by_name(String_val(id));
+ if (pip == NULL)
CAMLreturn(Val_unit);
- CURVNET_SET(TD_TO_VNET(curthread));
IFNET_WLOCK();
TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
if (strncmp(ifp->if_xname, String_val(id), IFNAMSIZ) == 0) {
@@ -231,49 +225,100 @@ caml_unplug_vif(value id)
}
}
IFNET_WUNLOCK();
- CURVNET_RESTORE();
+
+ mtx_lock(&pip->pi_rx_lock);
+ e1 = LIST_FIRST(&pip->pi_rx_head);
+ while (e1 != NULL) {
+ e2 = LIST_NEXT(e1, me_next);
+ m_free(e1->me_m);
+ free(e1, M_MIRAGE);
+ e1 = e2;
+ }
+ LIST_INIT(&pip->pi_rx_head);
+ mtx_unlock(&pip->pi_rx_lock);
TAILQ_REMOVE(&pihead, pip, pi_next);
+ mtx_destroy(&pip->pi_rx_lock);
free(pip, M_MIRAGE);
plugged--;
CAMLreturn(Val_unit);
}
+static void
+netif_add_mbuf(struct plugged_if *pip, struct mbuf *m)
+{
+ struct mbuf_entry *e;
+ struct mbuf *sm;
+
+ for (sm = m; sm != NULL; sm = sm->m_next) {
+ e = (struct mbuf_entry *) malloc(sizeof(struct mbuf_entry),
+ M_MIRAGE, M_NOWAIT);
+ e->me_m = sm;
+ mtx_lock(&pip->pi_rx_lock);
+ LIST_INSERT_HEAD(&pip->pi_rx_head, e, me_next);
+ mtx_unlock(&pip->pi_rx_lock);
+ }
+}
+
/* Listening to incoming Ethernet frames. */
void
netif_ether_input(struct ifnet *ifp, struct mbuf **mp)
{
- u_int len;
struct plugged_if *pip;
- struct sring_hdr *h;
- struct sslot *s;
- char *r;
- int i, sz;
+ struct mbuf *m;
if (plugged == 0)
return;
- TAILQ_FOREACH(pip, &pihead, pi_next) {
- if (ifp->if_index == pip->pi_index) {
- h = pip->pi_rx;
- sz = (h->sr_size - 1);
- i = (h->sr_cur + h->sr_avail) & sz;
- r = (char *) pip->pi_rx + (h->sr_size *
- sizeof(struct sslot)) + (i * h->sr_slotsize);
- len = MBUF_LEN(*mp);
- s = (struct sslot *) ((char *) pip->pi_rx +
- sizeof(struct sring_hdr));
- s[i].ss_len = len;
- m_copydata(*mp, 0, len, r);
- h->sr_avail++;
- m_freem(*mp);
- *mp = NULL;
- break;
- }
+ pip = find_pi_by_index(ifp->if_index);
+ if (pip != NULL) {
+ for (m = *mp; m != NULL; m = m->m_nextpkt)
+ netif_add_mbuf(pip, m);
+ *mp = NULL;
}
}
+CAMLprim value
+caml_get_mbufs(value id)
+{
+ CAMLparam1(id);
+ CAMLlocal2(result, r);
+ struct plugged_if *pip;
+ struct mbuf_entry *e1, *e2;
+ struct mbuf *m;
+ long len;
+
+ result = Val_emptylist;
+
+ if (plugged == 0)
+ CAMLreturn(result);
+
+ pip = find_pi_by_index(Int_val(id));
+ if (pip == NULL)
+ CAMLreturn(result);
+
+ mtx_lock(&pip->pi_rx_lock);
+ e1 = LIST_FIRST(&pip->pi_rx_head);
+ while (e1 != NULL) {
+ m = e1->me_m;
+ len = m->m_len;
+ r = caml_alloc(2, 0);
+ Store_field(r, 0,
+ caml_ba_alloc_dims(CAML_BA_UINT8 | CAML_BA_C_LAYOUT
+ | CAML_BA_MBUF, 1, (void *) m, len));
+ Store_field(r, 1, result);
+ e2 = LIST_NEXT(e1, me_next);
+ free(e1, M_MIRAGE);
+ e1 = e2;
+ result = r;
+ }
+ LIST_INIT(&pip->pi_rx_head);
+ mtx_unlock(&pip->pi_rx_lock);
+
+ CAMLreturn(result);
+}
+
/* Generating outgoing Ethernet data. */
int
netif_ether_output(struct ifnet *ifp, struct mbuf **mp)
View
8 packages/mirage-platform/runtime/ocaml/bigarray.h
@@ -65,7 +65,12 @@ enum caml_ba_managed {
CAML_BA_EXTERNAL = 0, /* Data is not allocated by Caml */
CAML_BA_MANAGED = 0x200, /* Data is allocated by Caml */
CAML_BA_MAPPED_FILE = 0x400, /* Data is a memory mapped file */
+#ifdef _KERNEL
+ CAML_BA_MBUF = 0x800, /* Data is a FreeBSD mbuf(9) */
+ CAML_BA_MANAGED_MASK = 0xE00 /* Mask for "managed" bits in flags field */
+#else
CAML_BA_MANAGED_MASK = 0x600 /* Mask for "managed" bits in flags field */
+#endif
};
struct caml_ba_proxy {
@@ -76,6 +81,9 @@ struct caml_ba_proxy {
struct caml_ba_array {
void * data; /* Pointer to raw data */
+#ifdef _KERNEL
+ struct mbuf * m; /* Encapsulating mbuf(9) or NULL */
+#endif
intnat num_dims; /* Number of dimensions */
intnat flags; /* Kind of element array + memory layout + allocation status */
struct caml_ba_proxy * proxy; /* The proxy for sub-arrays, or NULL */
View
18 packages/mirage-platform/runtime/ocaml/bigarray_stubs.c
@@ -17,7 +17,9 @@
#include <sys/cdefs.h>
#include <machine/stdarg.h>
#include <sys/param.h>
+#include <sys/systm.h>
#include <sys/kernel.h>
+#include <sys/mbuf.h>
#include <sys/sdt.h>
#else
#include <stddef.h>
@@ -226,7 +228,18 @@ caml_ba_alloc(int flags, int num_dims, void * data, intnat * dim)
+ (num_dims - 1) * sizeof(intnat),
size, CAML_BA_MAX_MEMORY);
b = Caml_ba_array_val(res);
+#ifdef _KERNEL
+ if ((flags & CAML_BA_MANAGED_MASK) == CAML_BA_MBUF) {
+ b->m = (struct mbuf *) data;
+ b->data = mtod(b->m, void *);
+ }
+ else {
+ b->m = NULL;
+ b->data = data;
+ }
+#else
b->data = data;
+#endif
b->num_dims = num_dims;
b->flags = flags;
b->proxy = NULL;
@@ -606,6 +619,11 @@ static void caml_ba_finalize(value v)
case CAML_BA_MAPPED_FILE:
caml_failwith("CAML_BA_MAPPED_FILE: unsupported");
break;
+#ifdef _KERNEL
+ case CAML_BA_MBUF:
+ m_free(b->m);
+ break;
+#endif
}
}
View
18 packages/mirage-test/regress/basic/netif.ml
@@ -1,11 +1,23 @@
open Lwt
open Printf
+cstruct ethernet {
+ uint8_t dst[6];
+ uint8_t src[6];
+ uint16_t ethertype
+} as big_endian
+
let show_mac s =
sprintf "%02x:%02x:%02x:%02x:%02x:%02x"
(Char.code s.[0]) (Char.code s.[1]) (Char.code s.[2])
(Char.code s.[3]) (Char.code s.[4]) (Char.code s.[5])
+let resolve_type t = match t with
+ | 0x0806 -> "ARP"
+ | 0x0800 -> "IPv4"
+ | 0x86dd -> "IPv6"
+ | _ -> "unknown"
+
let main () =
lwt t = OS.Netif.create
(fun id netif ->
@@ -13,8 +25,10 @@ let main () =
(show_mac (OS.Netif.mac netif));
lwt _ = OS.Time.sleep 1000000 in
OS.Netif.listen netif
- (fun page ->
- eprintf "incoming %d\n%!" (Cstruct.len page);
+ (fun frame ->
+ eprintf "incoming frame of size %d\n%!" (Cstruct.len frame);
+ let tp = get_ethernet_ethertype frame in
+ eprintf "ethertype: %04X (%s)\n%!" tp (resolve_type tp);
return ()
)
)
Please sign in to comment.
Something went wrong with that request. Please try again.