Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
G
GNS3_unikernel_testbed
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
NGUYEN Do Duc Anh
GNS3_unikernel_testbed
Commits
fbb4942b
Commit
fbb4942b
authored
8 months ago
by
NGUYEN Do Duc Anh
Browse files
Options
Downloads
Patches
Plain Diff
update unikenel
parent
5bc2af77
No related branches found
No related tags found
No related merge requests found
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
simple-fw/unikernel.ml
+145
-0
145 additions, 0 deletions
simple-fw/unikernel.ml
with
145 additions
and
0 deletions
simple-fw/unikernel.ml
0 → 100644
+
145
−
0
View file @
fbb4942b
(* This unikernel is largely inspired by the example at https://github.com/mirage/mirage-nat/ *)
open
Lwt
.
Infix
module
Main
(* our unikernel is functorized over the physical, and ethernet modules
for the public and private interfaces, so each one shows up as a module
argument. *)
(
Public_net
:
Mirage_net
.
S
)
(
Private_net
:
Mirage_net
.
S
)
(
Public_ethernet
:
Ethernet
.
S
)
(
Private_ethernet
:
Ethernet
.
S
)
(
Random
:
Mirage_crypto_rng_mirage
.
S
)
(
Clock
:
Mirage_clock
.
MCLOCK
)
=
struct
(* configure logs, so we can use them later *)
let
log
=
Logs
.
Src
.
create
"fw"
~
doc
:
"FW device"
module
Log
=
(
val
Logs
.
src_log
log
:
Logs
.
LOG
)
(* the specific impls we're using show up as arguments to start. *)
let
start
public_netif
private_netif
_public_ethernet
_private_ethernet
_rng
()
=
(* Creates a set of rules (empty) and a default condition (accept) *)
let
filter_rules
=
Rules
.
init
false
in
(* Takes an IPv4 [packet], unmarshal it, check if we're the destination and
the payload is some sort of rule update, apply that, and if we're not the
destination, use the filter_rules to [out] the packet or not. *)
let
is_forwardable
packet
=
(* Handle IPv4 only... *)
match
Ipv4_packet
.
Unmarshal
.
of_cstruct
packet
with
|
Result
.
Error
s
->
Logs
.
err
(
fun
m
->
m
"Can't parse IPv4 packet: %s"
s
);
false
(* If the packet is a UDP packet to us, decode *)
(* | Result.Ok (ipv4_hdr, payload) when
Ipv4_packet.Unmarshal.int_to_protocol ipv4_hdr.Ipv4_packet.proto =
Some `UDP &&
(ipv4_hdr.dst = filter_rules.public_ipv4 || ipv4_hdr.dst = filter_rules.private_ipv4) &&
Rules.magic_is_present payload ->
Logs.info (fun m -> m "Got an update message from %a" Ipaddr.V4.pp ipv4_hdr.src);
Rules.update filter_rules payload ;
false
(* If the packet is a UDP packet to us but not an update packet, ignore *)
| Result.Ok (ipv4_hdr, _payload) when
(ipv4_hdr.dst = filter_rules.public_ipv4 || ipv4_hdr.dst = filter_rules.private_ipv4) ->
Logs.debug (fun m -> m "Got an message from %a but not an update packet" Ipaddr.V4.pp ipv4_hdr.src);
false *)
(* Otherwise try to forward (or not) the packet *)
|
Result
.
Ok
(
ipv4_hdr
,
payload
)
->
Rules
.
filter
filter_rules
(
ipv4_hdr
,
payload
)
in
(* Forward the (dest, packet) [packet] to the public interface, using [dest] to understand how to route *)
let
output_public
:
Cstruct
.
t
->
unit
Lwt
.
t
=
fun
packet
->
let
len
=
Cstruct
.
length
packet
in
Public_net
.
write
public_netif
~
size
:
len
(
fun
b
->
Cstruct
.
blit
packet
0
b
0
len
;
len
)
>|=
function
|
Ok
()
->
()
|
Error
e
->
Log
.
warn
(
fun
f
->
f
"netif write errored %a"
Public_net
.
pp_error
e
)
;
()
in
(* Forward the (dest, packet) [packet] to the private interface, using [dest] to understand how to route *)
let
output_private
:
Cstruct
.
t
->
unit
Lwt
.
t
=
fun
packet
->
(* For IPv4 only one prefix can be configured so the list is always of length 1 *)
let
len
=
Cstruct
.
length
packet
in
Private_net
.
write
private_netif
~
size
:
len
(
fun
b
->
Cstruct
.
blit
packet
0
b
0
len
;
len
)
>|=
function
|
Ok
()
->
()
|
Error
e
->
Log
.
warn
(
fun
f
->
f
"netif write errored %a"
Private_net
.
pp_error
e
)
;
()
in
(* we need to establish listeners for the private and public interfaces *)
(* we're interested in all traffic to the physical interface; we'd like to
send ARP traffic to the normal ARP listener and responder,
handle ipv4 traffic with the functions we've defined above for filtering,
and ignore all ipv6 traffic. *)
let
listen_public
=
let
header_size
=
Ethernet
.
Packet
.
sizeof_ethernet
and
input
frame
=
(* Takes an ethernet packet and send it to the relevant callback *)
match
Ethernet
.
Packet
.
of_cstruct
frame
with
|
Ok
(
header
,
payload
)
->
begin
match
header
.
Ethernet
.
Packet
.
ethertype
with
|
`ARP
->
output_private
frame
|
`IPv4
when
is_forwardable
payload
->
output_private
frame
|
_
->
Lwt
.
return_unit
end
|
Error
s
->
Log
.
debug
(
fun
f
->
f
"dropping Ethernet frame: %s"
s
);
Lwt
.
return_unit
in
Public_net
.
listen
~
header_size
public_netif
input
>>=
function
|
Error
e
->
Log
.
debug
(
fun
f
->
f
"public interface stopped: %a"
Public_net
.
pp_error
e
);
Lwt
.
return_unit
|
Ok
()
->
Log
.
debug
(
fun
f
->
f
"public interface terminated normally"
);
Lwt
.
return_unit
in
let
listen_private
=
let
header_size
=
Ethernet
.
Packet
.
sizeof_ethernet
and
input
frame
=
(* Takes an ethernet packet and send it to the relevant callback *)
match
Ethernet
.
Packet
.
of_cstruct
frame
with
|
Ok
(
header
,
payload
)
->
begin
match
header
.
Ethernet
.
Packet
.
ethertype
with
|
`ARP
->
output_public
frame
|
`IPv4
when
is_forwardable
payload
->
output_public
frame
|
_
->
Lwt
.
return_unit
end
|
Error
s
->
Log
.
debug
(
fun
f
->
f
"dropping Ethernet frame: %s"
s
);
Lwt
.
return_unit
in
Private_net
.
listen
~
header_size
private_netif
input
>>=
function
|
Error
e
->
Log
.
debug
(
fun
f
->
f
"private interface stopped: %a"
Private_net
.
pp_error
e
);
Lwt
.
return_unit
|
Ok
()
->
Log
.
debug
(
fun
f
->
f
"private interface terminated normally"
);
Lwt
.
return_unit
in
(* Notice how we haven't said anything about ICMP anywhere. The unikernel
doesn't know anything about it, so pinging this host on either interface
will just be ignored -- the only way this unikernel can be easily seen,
without sending traffic through it, is via ARP. The `arping` command
line utility might be useful in trying to see whether your unikernel is
up. *)
(* start both listeners, and continue as long as both are working. *)
Lwt
.
pick
[
listen_public
;
listen_private
;
]
end
\ No newline at end of file
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment