Skip to content

Commit

Permalink
Merge pull request #1187 from hannesm/v6
Browse files Browse the repository at this point in the history
IPv6 stack support for the mirage utility
  • Loading branch information
hannesm committed Dec 2, 2020
2 parents 4a0ebcd + 5a38207 commit aefd9d1
Show file tree
Hide file tree
Showing 26 changed files with 1,000 additions and 335 deletions.
96 changes: 96 additions & 0 deletions CHANGES.md
@@ -1,3 +1,99 @@
### v3.10.0 (2020-12-02)

IPv6 and dual (IPv4 and IPv6) stack support #1187

Since a long time, IPv6 code was around in our TCP/IP stack (thanks to @nojb
who developed it in 2014). Some months ago, @hannesm and @MagnusS got excited
to use it. After we managed to fix some bugs and add some test cases, and
writing more code to setup IPv6-only and dual stacks, we are eager to share
this support for MirageOS in a released version. We expect there to be bugs
lingering around, but duplicate address detection (neighbour solicitation and
advertisements) has been implemented, and (unless
"--accept-router-advertisement=false") router advertisements are decoded and
used to configure the IPv6 part of the stack. Configuring a static IPv6 address
is also possible (with "--ipv6=2001::42/64").

While at it, we unified the boot arguments between the different targets:
namely, on Unix (when using the socket stack), you can now pass
"--ipv4=127.0.0.1/24" to the same effect as the direct stack: only listen
on 127.0.0.1 (the subnet mask is ignored for the Unix socket stack).

A dual stack unikernel has "--ipv4-only=BOOL" and "--ipv6-only=BOOL" parameters,
so a unikernel binary could support both Internet Protocol versions, while the
operator can decide which protocol version to use.

Please also note that the default IPv4 network configuration no longer uses
10.0.0.1 as default gateway (since there was no way to unset the default
gateway #1147).

For unikernel developers, there are some API changes in the Mirage module
- New "v4v6" types for IP protocols and stacks
- The ipv6_config record was adjusted in the same fashion as the ipv4_config
type: it is now a record of a network (V6.Prefix.t) and gateway (V6.t option)

Some parts of the Mirage_key module were unified as well:
- Arp.ip_address is available (for a dual Ipaddr.t)
- Arg.ipv6_address replaces Arg.ipv6 (for an Ipaddr.V6.t)
- Arg.ipv6 replaces Arg.ipv6_prefix (for a Ipaddr.V6.Prefix.t)
- V6.network and V6.gateway are available, mirroring the V4 submodule

If you're ready to experiment with the dual stack, here's a diff for our basic
network example (from mirage-skeleton/device-usage/network) replacing IPv4
with a dual stack:

```
diff --git a/device-usage/network/config.ml b/device-usage/network/config.ml
index c425edb..eabc9d6 100644
--- a/device-usage/network/config.ml
+++ b/device-usage/network/config.ml
@@ -4,9 +4,9 @@ let port =
let doc = Key.Arg.info ~doc:"The TCP port on which to listen for incoming connections." ["port"] in
Key.(create "port" Arg.(opt int 8080 doc))
-let main = foreign ~keys:[Key.abstract port] "Unikernel.Main" (stackv4 @-> job)
+let main = foreign ~keys:[Key.abstract port] "Unikernel.Main" (stackv4v6 @-> job)
-let stack = generic_stackv4 default_network
+let stack = generic_stackv4v6 default_network
let () =
register "network" [
diff --git a/device-usage/network/unikernel.ml b/device-usage/network/unikernel.ml
index 5d29111..1bf1228 100644
--- a/device-usage/network/unikernel.ml
+++ b/device-usage/network/unikernel.ml
@@ -1,19 +1,19 @@
open Lwt.Infix
-module Main (S: Mirage_stack.V4) = struct
+module Main (S: Mirage_stack.V4V6) = struct
let start s =
let port = Key_gen.port () in
- S.listen_tcpv4 s ~port (fun flow ->
- let dst, dst_port = S.TCPV4.dst flow in
+ S.listen_tcp s ~port (fun flow ->
+ let dst, dst_port = S.TCP.dst flow in
Logs.info (fun f -> f "new tcp connection from IP %s on port %d"
- (Ipaddr.V4.to_string dst) dst_port);
- S.TCPV4.read flow >>= function
+ (Ipaddr.to_string dst) dst_port);
+ S.TCP.read flow >>= function
| Ok `Eof -> Logs.info (fun f -> f "Closing connection!"); Lwt.return_unit
- | Error e -> Logs.warn (fun f -> f "Error reading data from established connection: %a" S.TCPV4.pp_error e); Lwt.return_unit
+ | Error e -> Logs.warn (fun f -> f "Error reading data from established connection: %a" S.TCP.pp_error e); Lwt.return_unit
| Ok (`Data b) ->
Logs.debug (fun f -> f "read: %d bytes:\n%s" (Cstruct.len b) (Cstruct.to_string b));
- S.TCPV4.close flow
+ S.TCP.close flow
);
S.listen s
```

Other bug fixes include #1188 (in #1201) and adapt to charrua 1.3.0 and
arp 2.3.0 changes (#1199).

### v3.9.0 (2020-10-24)

The Xen backend is a minimal legacy-free re-write: Solo5 (since 0.6.6) provides
Expand Down
53 changes: 39 additions & 14 deletions lib/mirage.ml
Expand Up @@ -97,50 +97,75 @@ let arp = Mirage_impl_arpv4.arp

type v4 = Mirage_impl_ip.v4
type v6 = Mirage_impl_ip.v6
type v4v6 = Mirage_impl_ip.v4v6
type 'a ip = 'a Mirage_impl_ip.ip
type ipv4 = Mirage_impl_ip.ipv4
type ipv6 = Mirage_impl_ip.ipv6
type ipv4v6 = Mirage_impl_ip.ipv4v6
let ipv4 = Mirage_impl_ip.ipv4
let ipv6 = Mirage_impl_ip.ipv6
let ipv4v6 = Mirage_impl_ip.ipv4v6
let ipv4_qubes = Mirage_impl_ip.ipv4_qubes
let create_ipv4 = Mirage_impl_ip.create_ipv4
let create_ipv6 = Mirage_impl_ip.create_ipv6
let create_ipv4v6 = Mirage_impl_ip.create_ipv4v6
type ipv4_config = Mirage_impl_ip.ipv4_config = {
network : Ipaddr.V4.Prefix.t;
gateway : Ipaddr.V4.t option;
}
type ipv6_config = Mirage_impl_ip.ipv6_config = {
addresses : Ipaddr.V6.t list;
netmasks : Ipaddr.V6.Prefix.t list;
gateways : Ipaddr.V6.t list;
network : Ipaddr.V6.Prefix.t;
gateway : Ipaddr.V6.t option;
}

type 'a udp = 'a Mirage_impl_udp.udp
let udp = Mirage_impl_udp.udp
type udpv4 = Mirage_impl_udp.udpv4
type udpv6 = Mirage_impl_udp.udpv6
type udpv4v6 = Mirage_impl_udp.udpv4v6
let udpv4 = Mirage_impl_udp.udpv4
let udpv6 = Mirage_impl_udp.udpv6
let udpv4v6 = Mirage_impl_udp.udpv4v6
let direct_udp = Mirage_impl_udp.direct_udp
let socket_udpv4 = Mirage_impl_udp.socket_udpv4
let socket_udpv6 = Mirage_impl_udp.socket_udpv6
let socket_udpv4v6 = Mirage_impl_udp.socket_udpv4v6

type 'a tcp = 'a Mirage_impl_tcp.tcp
let tcp = Mirage_impl_tcp.tcp
type tcpv4 = Mirage_impl_tcp.tcpv4
type tcpv6 = Mirage_impl_tcp.tcpv6
type tcpv4v6 = Mirage_impl_tcp.tcpv4v6
let tcpv4 = Mirage_impl_tcp.tcpv4
let tcpv6 = Mirage_impl_tcp.tcpv6
let tcpv4v6 = Mirage_impl_tcp.tcpv4v6
let direct_tcp = Mirage_impl_tcp.direct_tcp
let socket_tcpv4 = Mirage_impl_tcp.socket_tcpv4

type stackv4 = Mirage_impl_stackv4.stackv4
let stackv4 = Mirage_impl_stackv4.stackv4
let generic_stackv4 = Mirage_impl_stackv4.generic_stackv4
let static_ipv4_stack = Mirage_impl_stackv4.static_ipv4_stack
let dhcp_ipv4_stack = Mirage_impl_stackv4.dhcp_ipv4_stack
let qubes_ipv4_stack = Mirage_impl_stackv4.qubes_ipv4_stack
let direct_stackv4 = Mirage_impl_stackv4.direct_stackv4
let socket_stackv4 = Mirage_impl_stackv4.socket_stackv4
let socket_tcpv6 = Mirage_impl_tcp.socket_tcpv6
let socket_tcpv4v6 = Mirage_impl_tcp.socket_tcpv4v6

type stackv4 = Mirage_impl_stack.stackv4
let stackv4 = Mirage_impl_stack.stackv4
let generic_stackv4 = Mirage_impl_stack.generic_stackv4
let static_ipv4_stack = Mirage_impl_stack.static_ipv4_stack
let dhcp_ipv4_stack = Mirage_impl_stack.dhcp_ipv4_stack
let qubes_ipv4_stack = Mirage_impl_stack.qubes_ipv4_stack
let direct_stackv4 = Mirage_impl_stack.direct_stackv4
let socket_stackv4 = Mirage_impl_stack.socket_stackv4

type stackv6 = Mirage_impl_stack.stackv6
let stackv6 = Mirage_impl_stack.stackv6
let generic_stackv6 = Mirage_impl_stack.generic_stackv6
let static_ipv6_stack = Mirage_impl_stack.static_ipv6_stack
let direct_stackv6 = Mirage_impl_stack.direct_stackv6
let socket_stackv6 = Mirage_impl_stack.socket_stackv6

type stackv4v6 = Mirage_impl_stack.stackv4v6
let stackv4v6 = Mirage_impl_stack.stackv4v6
let generic_stackv4v6 = Mirage_impl_stack.generic_stackv4v6
let static_ipv4v6_stack = Mirage_impl_stack.static_ipv4v6_stack
let direct_stackv4v6 = Mirage_impl_stack.direct_stackv4v6
let socket_stackv4v6 = Mirage_impl_stack.socket_stackv4v6

type conduit = Mirage_impl_conduit.conduit
let conduit = Mirage_impl_conduit.conduit
Expand All @@ -158,7 +183,7 @@ let syslog_tcp = Mirage_impl_syslog.syslog_tcp
let syslog_udp = Mirage_impl_syslog.syslog_udp
type syslog_config = Mirage_impl_syslog.syslog_config =
{ hostname : string;
server : Ipaddr.V4.t option;
server : Ipaddr.t option;
port : int option;
truncate : int option;
}
Expand Down Expand Up @@ -219,7 +244,7 @@ module Project = struct
]
method! packages =
(* XXX: use %%VERSION_NUM%% here instead of hardcoding a version? *)
let min = "3.9.0" and max = "3.10.0" in
let min = "3.10.0" and max = "3.11.0" in
let common = [
package ~build:true ~min:"4.08.0" "ocaml";
package "lwt";
Expand Down

0 comments on commit aefd9d1

Please sign in to comment.