Permalink
Browse files

Add a draft implementation for listening to (and therefore receiving)…

… packets based on a shared ring buffer and stealing ng_ether(4) hooks.
  • Loading branch information...
1 parent 158c9e6 commit c10b740218fd0af10e7b8e424d4cdde191edb251 @pgj committed Aug 16, 2012
@@ -48,5 +48,11 @@ let run t =
(let t = Printexc.to_string exn in
let msg = Printf.sprintf "Top-level exception: \"%s\"!" t in
prerr_endline msg;
- true) in
- ignore (Callback.register "OS.Main.run" aux)
+ true)
+ in
+ let finalize () =
+ Lwt.cancel t;
+ Gc.compact ()
+ in
+ ignore (Callback.register "OS.Main.run" aux);
+ ignore (Callback.register "OS.Main.finalize" finalize)
@@ -28,30 +28,129 @@
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;
+ backend_id: int;
+ backend: string;
+ mac: string;
+ mutable active: bool;
+ rx_ring: sring;
}
type id = string
-external get_vifs: unit -> id list = "kern_get_vifs"
+external get_vifs: unit -> id list = "caml_get_vifs"
+external plug_vif: id -> Io_page.t -> bool * int * string = "caml_plug_vif"
+external unplug_vif: id -> unit = "caml_unplug_vif"
+
+let devices : (id, t) Hashtbl.t = Hashtbl.create 1
+
+let enumerate () =
+ let vifs = get_vifs () in
+ let rec read_vif l acc = match l with
+ | [] -> return acc
+ | (x::xs) ->
+ lwt sid = return x in
+ read_vif xs (sid :: acc)
+ in
+ read_vif vifs []
let plug id =
- Console.log (sprintf "Netif.plug %s: not implemented yet" id);
- lwt backend_id = return 0 in
- lwt backend = return id in
- let t = { backend_id; backend } in
- return t
+ try
+ 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
+ Hashtbl.add devices id t;
+ return t
let unplug id =
- Console.log (sprintf "Netif.unplug %s: not implemented yet" id);
- ()
+ try
+ let t = Hashtbl.find devices id in
+ t.active <- false;
+ Hashtbl.remove devices id;
+ unplug_vif id
+ with Not_found -> ()
let create f =
- Console.log (sprintf "Netif.create: not implemented yet");
- return ()
+ let th,_ = Lwt.task () in
+ Lwt.on_cancel th (fun _ -> Hashtbl.iter (fun id _ -> unplug id) devices);
+ lwt ids = enumerate () in
+ let pt = Lwt_list.iter_p (fun id ->
+ lwt t = plug id in
+ f id t) ids in
+ th <?> pt
let write ifc page =
Console.log (sprintf "Netif.write %s: not implemented yet" ifc.backend);
@@ -61,27 +160,37 @@ let writev ifc pages =
Console.log (sprintf "Netif.writev %s: not implemented yet" ifc.backend);
return ()
-let listen ifc fn =
- Console.log (sprintf "Netif.listen %s: not implemented yet" ifc.backend);
- 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 enumerate () =
- let vifs = get_vifs () in
- let rec read_vif l acc = match l with
- | [] -> return acc
- | (x::xs) ->
- lwt sid = return x in
- read_vif xs (sid :: acc)
+let listen ifc fn =
+ let rec poll_t () =
+ rx_poll ifc fn >>
+ Time.sleep 1000 >>
+ poll_t ()
in
- read_vif vifs []
+ match ifc.active with
+ | true -> poll_t ()
+ | false -> return ()
let mac ifc =
- Console.log (sprintf "Netif.mac %s: not implemented yet" ifc.backend);
- ""
+ let s = String.create 6 in
+ Scanf.sscanf ifc.mac "%02x:%02x:%02x:%02x:%02x:%02x"
+ (fun a b c d e f ->
+ s.[0] <- Char.chr a;
+ s.[1] <- Char.chr b;
+ s.[2] <- Char.chr c;
+ s.[3] <- Char.chr d;
+ s.[4] <- Char.chr e;
+ s.[5] <- Char.chr f;
+ );
+ s
-let ethid ifc =
- string_of_int ifc.backend_id
+let ethid ifc = string_of_int ifc.backend_id
let get_writebuf ifc =
- let page = Io_page.get() in
+ let page = Io_page.get () in
return page
@@ -39,7 +39,7 @@
#include <sys/systm.h>
#include <sys/malloc.h>
#include <sys/sysctl.h>
-#include <sys/kernel.h>
+#include <sys/mbuf.h>
#include <sys/sdt.h>
#include "caml/mlvalues.h"
@@ -68,32 +68,44 @@ enum thread_state {
};
static enum thread_state mirage_kthread_state = THR_NONE;
-
static struct thread *mirage_kthread = NULL;
+/* netgraph node hooks stolen from ng_ether(4) */
+extern void (*ng_ether_input_p)(struct ifnet *ifp, struct mbuf **mp);
+extern int (*ng_ether_output_p)(struct ifnet *ifp, struct mbuf **mp);
+void netif_ether_input(struct ifnet *ifp, struct mbuf **mp);
+int netif_ether_output(struct ifnet *ifp, struct mbuf **mp);
+
+
static void
mirage_kthread_body(void *arg __unused)
{
- value *v_main;
+ value *v_f;
int caml_completed = 0;
mirage_kthread_state = THR_RUNNING;
caml_startup(argv);
- v_main = caml_named_value("OS.Main.run");
+ v_f = caml_named_value("OS.Main.run");
- if (v_main == NULL) {
+ if (v_f == NULL) {
printf("[MIRAGE] Function 'OS.Main.run' could not be found.\n");
goto done;
}
SDT_PROBE(mirage, kernel, kthread_loop, start, 0, 0, 0, 0, 0);
for (; (caml_completed == 0) && (mirage_kthread_state == THR_RUNNING);) {
- caml_completed = Bool_val(caml_callback(*v_main, Val_unit));
+ caml_completed = Bool_val(caml_callback(*v_f, Val_unit));
}
SDT_PROBE(mirage, kernel, kthread_loop, stop, caml_completed,
(int) mirage_kthread_state, 0, 0, 0);
done:
+ v_f = caml_named_value("OS.Main.finalize");
+
+ if (v_f != NULL) {
+ caml_callback(*v_f, Val_unit);
+ }
+
if (mirage_kthread_state == THR_STOPPED)
wakeup(&mirage_kthread_state);
mirage_kthread_state = THR_NONE;
@@ -178,10 +190,18 @@ event_handler(struct module *module, int event, void *arg) {
switch (event) {
case MOD_LOAD:
printf("[MIRAGE] Kernel module is about to load.\n");
+ if (ng_ether_input_p != NULL || ng_ether_output_p != NULL) {
+ printf("[MIRAGE] ng_ether(4) is in use, please disable it.\n");
+ retval = EEXIST;
+ }
+ ng_ether_input_p = netif_ether_input;
+ ng_ether_output_p = netif_ether_output;
break;
case MOD_UNLOAD:
printf("[MIRAGE] Kernel module is about to unload.\n");
retval = mirage_kthread_deinit();
+ ng_ether_input_p = NULL;
+ ng_ether_output_p = NULL;
break;
default:
retval = EOPNOTSUPP;
Oops, something went wrong. Retry.

0 comments on commit c10b740

Please sign in to comment.