APID-based virtual switch for SpaceOS inter-guest routing
at main 132 lines 4.3 kB view raw
1open Cmdliner 2open Space_net 3 4let log_src = Logs.Src.create "space-net" 5 6module Log = (val Logs.src_log log_src) 7 8(* ============================================================================ 9 run — start the switch 10 ============================================================================ *) 11 12let v0_config socket_dir = 13 Config. 14 { 15 tenants = 16 [ 17 { 18 name = "camera"; 19 apids = apid_range 0x010 0x01F; 20 can_send_to = [ apid_range 0x020 0x02F ]; 21 }; 22 { 23 name = "processor"; 24 apids = apid_range 0x020 0x02F; 25 can_send_to = [ apid_range 0x010 0x01F ]; 26 }; 27 { name = "spaceos"; apids = apid_range 0x030 0x03F; can_send_to = [] }; 28 ]; 29 socket_dir; 30 } 31 32let run socket_dir () = 33 Eio_main.run @@ fun env -> 34 Eio.Switch.run @@ fun sw -> 35 let net = Eio.Stdenv.net env in 36 let config = v0_config socket_dir in 37 let switch = Switch.v ~config () in 38 Log.app (fun m -> 39 m "space-net starting: %d tenants, socket_dir=%s" 40 (List.length config.tenants) 41 config.socket_dir); 42 Switch.run switch ~sw ~net 43 44let socket_dir_arg = 45 let doc = "Directory for per-guest Unix sockets." in 46 Arg.( 47 value & opt string "/tmp/space-net" & info [ "socket-dir" ] ~docv:"DIR" ~doc) 48 49let run_cmd = 50 let doc = "Start the APID virtual switch." in 51 let info = Cmd.info "run" ~doc in 52 Cmd.v info Term.(const run $ socket_dir_arg $ Vlog.setup "space-net") 53 54(* ============================================================================ 55 inject — send a test frame 56 ============================================================================ *) 57 58let inject msg_type apid payload socket () = 59 Eio_main.run @@ fun _env -> 60 let typ = 61 match msg_type with 62 | "TM" | "tm" -> Space_wire.Msg.TM 63 | "TC" | "tc" -> Space_wire.Msg.TC 64 | "EVR" | "evr" -> Space_wire.Msg.EVR 65 | "DP" | "dp" -> Space_wire.Msg.DP 66 | "HEALTH" | "health" -> Space_wire.Msg.HEALTH 67 | "LOG" | "log" -> Space_wire.Msg.LOG 68 | s -> Fmt.failwith "unknown msg type: %s" s 69 in 70 let frame = Space_wire.Msg.v typ ~apid payload in 71 let buf = Bytes.make Space_wire.Msg.frame_size '\x00' in 72 Wire.Codec.encode Space_wire.Msg.codec frame buf 0; 73 let data = Bytes.unsafe_to_string buf in 74 let fd = Unix.socket Unix.PF_UNIX Unix.SOCK_STREAM 0 in 75 (try 76 Unix.connect fd (Unix.ADDR_UNIX socket); 77 let _n = Unix.write_substring fd data 0 (String.length data) in 78 Fmt.pr "injected %a to %s@." Space_wire.Msg.pp frame socket 79 with Unix.Unix_error (e, _, _) -> 80 Fmt.epr "error: %s@." (Unix.error_message e); 81 exit 1); 82 Unix.close fd 83 84let msg_type_arg = 85 let doc = "Message type (TM, TC, EVR, DP, HEALTH, LOG)." in 86 Arg.(value & opt string "TM" & info [ "t"; "type" ] ~docv:"TYPE" ~doc) 87 88let apid_arg = 89 let doc = "APID (0-2047)." in 90 Arg.(value & opt int 0x010 & info [ "a"; "apid" ] ~docv:"APID" ~doc) 91 92let payload_arg = 93 let doc = "Frame payload string." in 94 Arg.(value & opt string "test" & info [ "p"; "payload" ] ~docv:"DATA" ~doc) 95 96let socket_arg = 97 let doc = "Path to guest Unix socket." in 98 Arg.( 99 required & opt (some string) None & info [ "s"; "socket" ] ~docv:"PATH" ~doc) 100 101let inject_cmd = 102 let doc = "Inject a test frame into a guest socket." in 103 let info = Cmd.info "inject" ~doc in 104 Cmd.v info 105 Term.( 106 const inject $ msg_type_arg $ apid_arg $ payload_arg $ socket_arg 107 $ Vlog.setup "space-net") 108 109(* ============================================================================ 110 main 111 ============================================================================ *) 112 113let info = 114 let doc = "APID-based virtual switch for SpaceOS inter-guest routing" in 115 let man = 116 [ 117 `S Manpage.s_description; 118 `P 119 "space-net is the APID virtual switch that routes 256-byte wire frames \ 120 between guest VMs and space-dtn for uplink/downlink."; 121 `S Manpage.s_commands; 122 `P "$(b,space-net run) - Start the virtual switch"; 123 `P "$(b,space-net inject) - Inject a test frame"; 124 ] 125 in 126 Cmd.info "space-net" ~version:"0.1.0" ~doc ~man 127 128let default = Term.(ret (const (fun () -> `Help (`Pager, None)) $ const ())) 129 130let () = 131 let cmd = Cmd.group info ~default [ run_cmd; inject_cmd ] in 132 exit (Cmd.eval cmd)