Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vpn #86

Closed
wants to merge 15 commits into from
Closed

Vpn #86

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 33 additions & 3 deletions src/apps/intel/intel10g.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ local C = ffi.C
local lib = require("core.lib")
local memory = require("core.memory")
local packet = require("core.packet")
local buffer = require("core.buffer")
local bus = require("lib.hardware.bus")
local register = require("lib.hardware.register")
require("apps.intel.intel_h")
Expand All @@ -23,6 +24,16 @@ local bits, bitset = lib.bits, lib.bitset
num_descriptors = 32 * 1024
--num_descriptors = 32

-- This value determines the maximum size that the payload of an
-- incoming frame can have to be accepted by the NIC. The actual
-- value that gets written to the corresponding hardware register
-- (MAXFRS) includes the Ethernet header and the CRC, i.e. 18
-- additional bytes. If the value is larger than 1500, support for
-- jumbo frames is enabled as well.
--
-- This should be settable per device through the constructor method.
MTU = 1500

--- ### Initialization

function new (pciaddress)
Expand Down Expand Up @@ -103,6 +114,21 @@ end
function init_receive (dev)
set_promiscuous_mode(dev) -- NB: don't need to program MAC address filter
dev.r.HLREG0:clr(bits({RXLNGTHERREN=27}))
if MTU ~= 1500 then
-- The actual MAXFRS includes the Ethernet header and the CRC
dev.r.MAXFRS:write(bit.lshift(MTU+18, 16))
if MTU > 1500 then
dev.r.HLREG0:set(bits({JUMBOEN=2}))
end
end
-- Set the buffer size. This is in units of 1KiB and should match
-- the value of core.buffer.size. Currently, this is a private
-- variable. We need a better way define global parameters like
-- this.
local b_size = math.floor(buffer.size/1024)
assert(b_size > 0)
dev.r.SRRCTL(bit.bor(bit.band(dev.r.SRRCTL(),0xFFFFFFF0),
math.min(15, b_size)))
dev.r.RDBAL(dev.rxdesc_phy % 2^32)
dev.r.RDBAH(dev.rxdesc_phy / 2^32)
dev.r.RDLEN(num_descriptors * ffi.sizeof("union rx"))
Expand Down Expand Up @@ -130,9 +156,10 @@ end

txdesc_flags = bits{eop=24,ifcs=25}
function transmit (dev, p)
assert(p.niovecs == 1, "only supports one-buffer packets")
if p.niovecs > 1 then
packet.coalesce(p)
end
local iov = p.iovecs[0]
assert(iov.offset == 0)
dev.txdesc[dev.tdt].data.address = iov.buffer.physical + iov.offset
dev.txdesc[dev.tdt].data.options = bit.bor(iov.length, txdesc_flags)
dev.txpackets[dev.tdt] = p
Expand Down Expand Up @@ -167,7 +194,8 @@ function receive (dev)
local b = dev.rxbuffers[dev.rxnext]
local wb = dev.rxdesc[dev.rxnext].wb
assert(wb.length > 0)
assert(bit.band(wb.status, 1) == 1) -- Descriptor Done
-- Multi-buffer packets are currently not supported
assert(bit.band(wb.status, 3) == 3) -- Descriptor Done & End Of Packet
packet.add_iovec(p, b, wb.length)
dev.rxnext = (dev.rxnext + 1) % num_descriptors
return p
Expand Down Expand Up @@ -251,13 +279,15 @@ DMATXCTL 0x04A80 - RW DMA Tx Control
EEC 0x10010 - RW EEPROM/Flash Control
FCTRL 0x05080 - RW Filter Control
HLREG0 0x04240 - RW MAC Core Control 0
MAXFRS 0x04268 - RW Max Frame Size
LINKS 0x042A4 - RO Link Status Register
RDBAL 0x01000 +0x40*0..63 RW Receive Descriptor Base Address Low
RDBAH 0x01004 +0x40*0..63 RW Receive Descriptor Base Address High
RDLEN 0x01008 +0x40*0..63 RW Receive Descriptor Length
RDH 0x01010 +0x40*0..63 RO Receive Descriptor Head
RDT 0x01018 +0x40*0..63 RW Receive Descriptor Tail
RXDCTL 0x01028 +0x40*0..63 RW Receive Descriptor Control
SRRCTL 0x01014 +0x40*0..63 RW Split Receive Control Register
RDRXCTL 0x02F00 - RW Receive DMA Control
RTTDCS 0x04900 - RW DCB Transmit Descriptor Plane Control
RXCTRL 0x03000 - RW Receive Control
Expand Down
5 changes: 3 additions & 2 deletions src/apps/intel/intel_app.lua
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ Intel82599 = {}
function Intel82599:new (pciaddress)
local a = { dev = intel10g.new(pciaddress) }
setmetatable(a, {__index = Intel82599 })
intel10g.open_for_loopback_test(a.dev)
return a
intel10g.open(a.dev)
intel10g.wait_linkup(a.dev)
return a
end

-- Allocate receive buffers from the given freelist.
Expand Down
13 changes: 3 additions & 10 deletions src/apps/ipv6/ipv6.lua
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ function SimpleIPv6:push ()
ffi.copy(new_ipv6.smac, self.own_mac, 6)
new_ipv6.ethertype = 0xDD86
new_ipv6.flow_id = 0x60 -- version=6
new_ipv6.payload_length = htons(size.icmpv6expired + excerpt_len)
new_ipv6.payload_length = C.htons(size.icmpv6expired + excerpt_len)
new_ipv6.next_header = 58 -- icmpv6
new_ipv6.hop_limit = 255
ffi.copy(new_ipv6.src_ip, self.own_ip, 16)
Expand Down Expand Up @@ -165,16 +165,9 @@ function checksum_icmpv6 (ipv6, icmpv6, icmpv6_len)
csum = lib.update_csum(ipv6_ptr + ffi.offsetof(ipv6_t, 'payload_length'), 2, csum)
-- ICMPv6 checksum
icmpv6.checksum = 0
csum = lib.update_csum(icmpv6, htons(ipv6.payload_length), csum)
csum = lib.update_csum(icmpv6, C.htons(ipv6.payload_length), csum)
csum = csum + 58
icmpv6.checksum = htons(lib.finish_csum(csum))
end

function htons (n)
return bit.lshift(bit.band(n, 0xff), 8) + bit.rshift(n, 8)
end
function ntohs (n)
return htons(n)
icmpv6.checksum = C.htons(lib.finish_csum(csum))
end

function selftest ()
Expand Down
93 changes: 93 additions & 0 deletions src/apps/ipv6/ns_responder.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
-- This app acts as a responder for neighbor solicitaions for a
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love this design idea: to handle neighbor solicitation response as a small discrete app that "does one thing well" instead of adding it as a feature to the IPv6 next-hop-routing app.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case, the traffic going north->south is passed through untouched. Would it make sense to bypass the app in that direction to avoid the overhead?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder about that too. I suppose it will be worth doing that kind of stuff if the performance difference is significant in practice, once we are done with optimization. I hope we will have the basic app transmit/receive functionality so fast that we don't need to care.

-- specific target address and as a relay for all other packets. It
-- has two ports, north and south. The south port attaches to a port
-- on which NS messages are expected. Non-NS packets are sent on
-- north. All packets received on the north port are passed south.

local ffi = require("ffi")
local app = require("core.app")
local link = require("core.link")
local packet = require("core.packet")
local datagram = require("lib.protocol.datagram")
local ethernet = require("lib.protocol.ethernet")
local ipv6 = require("lib.protocol.ipv6")
local icmp = require("lib.protocol.icmp.header")
local ns = require("lib.protocol.icmp.nd.ns")

local ns_responder = subClass(nil)

function ns_responder:_init_new(config)
self._config = config
self._match = { { ethernet },
{ ipv6 },
{ icmp },
{ ns,
function(ns)
return(ns:target_eq(config.local_ip))
end } }
end

local function process(self, dgram)
if dgram:parse(self._match) then
local eth, ipv6, icmp, ns = unpack(dgram:stack())
local option = ns:options(dgram:payload())
if not (#option == 1 and option[1]:type() == 1) then
-- Invalid NS, ignore
return nil
end
-- Turn this message into a solicited neighbor
-- advertisement with target ll addr option

-- Ethernet
eth:swap()
eth:src(self._config.local_mac)

-- IPv6
ipv6:dst(ipv6:src())
ipv6:src(self._config.local_ip)

-- ICMP
option[1]:type(2)
option[1]:option():addr(self._config.local_mac)
icmp:type(136)
-- Undo/redo icmp and ns headers to get
-- payload and set solicited flag
dgram:unparse(2)
dgram:parse() -- icmp
local payload, length = dgram:payload()
dgram:parse():solicited(1)
icmp:checksum(payload, length, ipv6)
return true
end
return false
end

function ns_responder:push()
local l_in = self.input.north
local l_out = self.output.south
assert(l_in and l_out)
while not link.empty(l_in) and not link.full(l_out) do
-- Pass everything on north -> south
link.transmit(l_out, link.receive(l_in))
end
l_in = self.input.south
l_out = self.output.north
local l_reply = self.output.south
while not link.empty(l_in) and not link.full(l_out) do
local p = link.receive(l_in)
local datagram = datagram:new(p, ethernet)
local status = process(self, datagram)
if status == nil then
-- Discard
packet.deref(p)
elseif status == true then
-- Send NA back south
link.transmit(l_reply, p)
else
-- Send transit traffic up north
link.transmit(l_out, p)
end
end
end

return ns_responder
47 changes: 47 additions & 0 deletions src/apps/socket/dev.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
module(...,package.seeall)

local ffi = require("ffi")
local C = ffi.C

local buffer = require("core.buffer")
local packet = require("core.packet")
require("lib.raw.raw_h")
require("apps.socket.io_h")

dev = {}

function dev:new(ifname)
assert(ifname)
self.__index = self
local dev = { fd = C.open_raw(ifname) }
return setmetatable(dev, self)
end

function dev:transmit(p)
assert(self.fd)
assert(C.send_packet(self.fd, p) ~= -1)
end

function dev:can_transmit()
return C.can_transmit(self.fd) == 1
end

function dev:receive()
assert(self.fd)
local size = C.msg_size(self.fd)
assert(size ~= -1)
local p = packet.allocate()
local nbuffers = math.ceil(size/buffer.size)
assert(nbuffers <= C.PACKET_IOVEC_MAX)
for i = 1, nbuffers do
local b = buffer.allocate()
packet.add_iovec(p, b, 0)
end
local s = C.receive_packet(self.fd, p)
assert(s ~= -1)
return p
end

function dev:can_receive()
return C.can_receive(self.fd) == 1
end
105 changes: 105 additions & 0 deletions src/apps/socket/io.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdint.h>
#include <strings.h>
#include <stdio.h>
#include <errno.h>
#include "core/packet.h"

int send_packet(int fd, struct packet *p) {
struct msghdr msg;
struct iovec iovecs[PACKET_IOVEC_MAX];
int i, n = p->niovecs;

bzero(&msg, sizeof(msg));
for (i=0; i < n; i++) {
struct packet_iovec *piov = &p->iovecs[i];
struct iovec *iov = &iovecs[i];

iov->iov_base = piov->buffer->pointer + piov->offset;
iov->iov_len = piov->length;
}
msg.msg_iov = &iovecs[0];
msg.msg_iovlen = n;

if (sendmsg(fd, &msg, 0) == -1) {
perror("sendmsg");
return(-1);
}
return(0);
}

int receive_packet(int fd, struct packet *p) {
struct msghdr msg;
struct iovec iovecs[p->niovecs];
int i;
ssize_t s, len;

bzero(&msg, sizeof(msg));
for (i=0; i<p->niovecs; i++) {
iovecs[i].iov_base = p->iovecs[i].buffer->pointer;
iovecs[i].iov_len = p->iovecs[i].buffer->size;
}
msg.msg_iov = iovecs;
msg.msg_iovlen = p->niovecs;
if ((s = recvmsg(fd, &msg, 0)) == -1) {
perror("recvmsg");
return(-1);
}
if (msg.msg_flags && MSG_TRUNC) {
printf("truncated\n");
return(-1);
}
len = s;
for (i=0; i<p->niovecs; i++) {
ssize_t iov_len = msg.msg_iov[i].iov_len;
if (len > iov_len) {
p->iovecs[i].length = iov_len;
len -= iov_len;
} else {
p->iovecs[i].length = len;
}
}
p->length = s;
return(s);
}

int msg_size(int fd) {
int size;
if (ioctl(fd, FIONREAD, &size) == -1) {
perror("get message size");
return(-1);
}
return(size);
}

int can_receive(int fd) {
fd_set fds;
struct timeval tv = { .tv_sec = 0, .tv_usec = 0 };
int result;

FD_ZERO(&fds);
FD_SET(fd, &fds);
if ((result = select(fd+1, &fds, NULL, NULL, &tv)) == -1) {
perror("select");
return(-1);
}
return(result);
}

int can_transmit(int fd) {
fd_set fds;
struct timeval tv = { .tv_sec = 0, .tv_usec = 0 };
int result;

FD_ZERO(&fds);
FD_SET(fd, &fds);
if ((result = select(fd+1, NULL, &fds, NULL, &tv)) == -1) {
perror("select");
return(-1);
}
return(result);
}
5 changes: 5 additions & 0 deletions src/apps/socket/io.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
int send_packet(int, struct packet *);
int receive_packet(int, struct packet *);
int can_transmit(int);
int can_receive(int);
int msg_size(int);
Loading