net: Add a protocol 'bypass' command for convs
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 16 Dec 2016 15:05:56 +0000 (10:05 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 10 Jan 2017 00:01:40 +0000 (19:01 -0500)
commit0134bfe0d88058d69e4e0afdaf34e875e0526714
tree59c76850c9ba1e94378ce0749ece62778d3bd75d
parent8f73842c8fcdc44eed0a81544180f959f2bb8a7f
net: Add a protocol 'bypass' command for convs

This allows userspace to claim a {protocol, port} tuple, and the kernel
bypasses its protocol layer, delivering the raw IP packets to userspace.
It actually doesn't need to be a specific port - just so long as the
protocol knows how to match inbound flows to the conversations at input
time.

Userspace can then either do its own protocol processing (e.g., user-level
TCP on a port-by-port basis), or it can forward it on to a VM.  This is a
building block for a simple NAT that we can build in the VMM.

The kernel still handles IP, like a router, and will send packets to any
IP.  The IP stack still runs - the outbound packets will have Akaros's TTL,
TOS, and fragment bits set.  There actually is a little protocol processing
that goes on during input, specific to the actual protocol.  For instance,
TCP and UDP check the checksum.  I can turn this off if we want, but doing
it like this allows us to use the NIC's xsum calculations.  Not a big deal.

Here's an example of a simple UDP echo server in action (in Qemu, TUN/TAP
networking):

(request, linux->akaros)
56:f3:f8:db:83:ba > 52:54:00:12:34:56, ethertype IPv4 (0x0800), length 48:
(tos 0x0, ttl 64, id 7607, offset 0, flags [DF], proto UDP (17), length 34)
    10.0.2.2.23 > 10.0.2.243.23: UDP, length 6

0x0000:  4500 0022 1db7 4000 4011 0420 0a00 0202  E.."..@.@.......
0x0010:  0a00 02f3 0017 0017 000e 1914 6865 6c6c  ............hell
0x0020:  6f0a                                     o.

(response, akaros->linux)
52:54:00:12:34:56 > 56:f3:f8:db:83:ba, ethertype IPv4 (0x0800), length 64:
(tos 0x0, ttl 255, id 4, offset 0, flags [none], proto UDP (17), length 50)
    10.0.2.243.23 > 10.0.2.2.23: UDP, length 6

0x0000:  4500 0032 0004 0000 ff11 a2c2 0a00 02f3  E..2............
0x0010:  0a00 0202 0017 0017 000e a2d3 6865 6c6c  ............hell
0x0020:  6f0a 0000 0000 0000 0000 0000 0000 0000  o...............
0x0030:  0000                                     ..

Interesting tidbits:
- We use the default TTL of akaros/Plan 9, not of whatever userspace gave
  us.  Same goes for TOS.

- Plan 9 didn't set the Dont_Frag bits.  That actually got zeroed before it
  went to userspace, and never got set on the way back.  Probably an
idiosyncrasy of the networking stack.

- The length of the IP packet is 50 for the response (64 with ethernet),
  but it was 34 for the request (48 with ether).  Akaros userspace got that
50 bytes on the inbound packet.  Userspace read 50 bytes, then it responded
with 50 bytes (of IP).  That 64 bytes of ethernet is set pretty early on,
in the NIC.  It's actually what the NIC (igbe) sees for the packet's
length.  Maybe it was QEMU's virtualization or the TUN/TAP that did that.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/include/ip.h
kern/src/net/devip.c
kern/src/net/tcp.c
kern/src/net/udp.c