mirage/mirage-tcpip

Multicast Listening on Unikernel?

gabrik opened this issue · 1 comments

Hi all,
I'm not sure this is an issue.
There is the possibility to listen on some multicast address when using mirage-tcpip inside an unikernel?
I see some ~group parameter in dhcp_ipv4_stack but I'm not sure is used for multicast groups.
I'm trying to modify the simple TCP example to be able to listen also to UDP multicast.

config.ml:

open Mirage

let main = foreign ~packages: [package "duration"; package "fmt"] "Unikernel.Main"  (stackv4 @-> console @-> job)
let stack = dhcp_ipv4_stack ~group:"239.0.0.5" default_network
let () =
  register "services" [ main $ stack $ default_console]

unikernel.ml:

open Lwt.Infix

module Main (S: Mirage_types_lwt.STACKV4) (C: Mirage_types_lwt.CONSOLE) = struct
  let report_and_close flow pp e message =
    let ip, port = S.TCPV4.dst flow in
    Logs.warn
      (fun m -> m "closing connection from %a:%d due to error %a while %s"
          Ipaddr.V4.pp_hum ip port pp e message);
    S.TCPV4.close flow

  let task duration marker =
    ignore @@ OS.Time.sleep_ns (Duration.of_sec duration);
    Lwt.return @@ marker ^ marker

  let listener console udp port ~src ~dst ~src_port buf =
    let s = Format.asprintf "Data from %s to %s" (Ipaddr.V4.to_string src) (Ipaddr.V4.to_string dst) in
    ignore @@ C.log console s;
    let src' = (Ipaddr.V4 dst), port in
    let dst' = (Ipaddr.V4 src), src_port in
    S.UDPV4.write ~src_port:port ~dst:src ~dst_port:src_port udp buf >>= function
          | Ok () -> Lwt.return_unit
          | Error e -> Lwt.return_unit
          
 
  let rec echo flow =
    S.TCPV4.read flow >>= function
    | Error e -> report_and_close flow S.TCPV4.pp_error e "reading in Echo"
    | Ok `Eof -> report_and_close flow Fmt.string "end of file" "reading in Echo"
    | Ok (`Data buf) ->

      Lwt.choose[(task 1 "+");(task 2 "=")] >>= (
        fun x ->
          let b = Cstruct.of_string x
          in
          S.TCPV4.write flow b >>= function
          | Ok () -> echo flow
          | Error e -> report_and_close flow S.TCPV4.pp_write_error e "writing in Echo")

  let start s c =
   
    S.listen_udpv4 s ~port:7 (listener c (S.udpv4 s) 7);
    S.listen_tcpv4 s ~port:7 echo;
    S.listen s

end

These is a way to do that?
I need a new direct stack with UDP?

Dear @gabrik, thanks for your report. The "group" argument of dhcp_ipv4_stack is just a name (used for command-line / boot arguments), and has no relation with multicast.

The mirage-tcpip stack does not have appropriate multicast support. From the Static_ipv4 module on the receiving side:

      let of_interest ip =
        Ipaddr.V4.(compare ip (Prefix.address t.cidr) = 0
                   || compare ip broadcast = 0
                   || compare ip (Prefix.broadcast t.cidr) = 0)
      in
      if not (of_interest packet.dst) then begin
        Log.debug (fun m -> m "dropping IP fragment not for us or broadcast %a"
                      Ipv4_packet.pp packet);
        Lwt.return_unit

This means that all packets which are not broadcast or unicast to the configured IP address are dropped.

If you're interested in implementing multicast into tcpip, please let us know and we can help where which changes would be necessary.