Skip to content

Commit

Permalink
Merge pull request #221 from lukego/merge-vpn-performancev2
Browse files Browse the repository at this point in the history
Merge vpn performancev2
  • Loading branch information
lukego committed Jul 2, 2014
2 parents 4058bf2 + f0edb8c commit e43188d
Show file tree
Hide file tree
Showing 30 changed files with 943 additions and 504 deletions.
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ language: c
compiler:
- gcc

before_install: "sudo apt-get update && sudo apt-get install -y linux-libc-dev"
before_install: "sudo apt-get update && sudo apt-get install -y linux-libc-dev libpcap-dev"

script:
- make && cd src && sudo make test_ci;
Expand Down
2 changes: 1 addition & 1 deletion src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ markdown: $(RMOBJS)

snabb: $(LUAOBJ) $(HOBJ) $(COBJ) $(ASMOBJ)
$(E) "LINK $@"
$(Q) gcc -Wl,-E -Werror -Wall -o $@ $^ \
$(Q) gcc -Wl,--no-as-needed -Wl,-E -Werror -Wall -o $@ $^ \
../deps/luajit/src/libluajit.a \
-lc -ldl -lm -lrt -lpthread
@echo -n "Firmware: "
Expand Down
98 changes: 58 additions & 40 deletions src/apps/ipv6/ns_responder.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
-- on which NS messages are expected. Non-NS packets are sent on
-- north. All packets received on the north port are passed south.

module(..., package.seeall)
local ffi = require("ffi")
local app = require("core.app")
local link = require("core.link")
Expand All @@ -13,53 +14,69 @@ 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 filter = require("lib.pcap.filter")

local ns_responder = subClass(nil)
ns_responder._name = "ipv6 neighbor solicitation responder"

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 } }
function ns_responder:new(config)
local o = ns_responder:superClass().new(self)
o._config = config
o._match_ns = function(ns)
return(ns:target_eq(config.local_ip))
end
local filter, errmsg = filter:new("icmp6 and ip6[40] = 135")
assert(filter, errmsg and ffi.string(errmsg))
o._filter = filter
return o
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
if not self._filter:match(dgram:payload()) then
return false
end
-- Parse the ethernet, ipv6 amd icmp headers
dgram:parse_n(3)
local eth, ipv6, icmp = unpack(dgram:stack())
local payload, length = dgram:payload()
if not icmp:checksum_check(payload, length, ipv6) then
print(self:name()..": bad icmp checksum")
return nil
end
-- Parse the neighbor solicitation and check if it contains our own
-- address as target
local ns = dgram:parse(nil, self._match_ns)
if not ns then
return nil
end
local option = ns:options(dgram:payload())
if not (#option == 1 and option[1]:type() == 1) then
-- Invalid NS, ignore
return nil
end
return false
-- 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

function ns_responder:push()
Expand Down Expand Up @@ -88,6 +105,7 @@ function ns_responder:push()
-- Send transit traffic up north
link.transmit(l_out, p)
end
datagram:free()
end
end

Expand Down
Binary file added src/apps/vpn/vpws-selftest-customer.cap.expect
Binary file not shown.
Binary file added src/apps/vpn/vpws-selftest-customer.cap.input
Binary file not shown.
Binary file added src/apps/vpn/vpws-selftest-uplink.cap.expect
Binary file not shown.
Binary file added src/apps/vpn/vpws-selftest-uplink.cap.input
Binary file not shown.
105 changes: 83 additions & 22 deletions src/apps/vpn/vpws.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
-- frames encapsulated in IP/GRE. The push() method performs the
-- appropriate operation depending on the input port.

module(..., package.seeall)
local ffi = require("ffi")
local C = ffi.C
local lib = require("core.lib")
Expand All @@ -16,31 +17,29 @@ local ethernet = require("lib.protocol.ethernet")
local ipv6 = require("lib.protocol.ipv6")
local gre = require("lib.protocol.gre")
local packet = require("core.packet")
local filter = require("lib.pcap.filter")
local pcap = require("apps.pcap.pcap")

local vpws = subClass(nil)
local in_to_out = { customer = 'uplink', uplink = 'customer' }

function vpws:_init_new(config)
self._config = config
self._encap = {
function vpws:new(config)
local o = vpws:superClass().new(self)
o._config = config
o._name = config.name
o._encap = {
ether = ethernet:new({ src = config.local_mac, dst = config.remote_mac, type = 0x86dd }),
ipv6 = ipv6:new({ next_header = 47, hop_limit = 64, src = config.local_vpn_ip,
dst = config.remote_vpn_ip}),
gre = gre:new({ protocol = 0x6558, key = config.label })
gre = gre:new({ protocol = 0x6558, checksum = config.checksum, key = config.label })
}
self._match = { { ethernet },
{ ipv6,
function(ipv6)
return(ipv6:dst_eq(config.local_vpn_ip))
end },
{ gre,
function(gre)
return(not gre:use_key() or gre:key() == config.label)
end } }
end

function vpws:name()
return self.config.name
-- Pre-computed size of combined Ethernet and IPv6 header
o._eth_ipv6_size = ethernet:sizeof() + ipv6:sizeof()
local program = "ip6 and dst host "..ipv6:ntop(config.local_vpn_ip) .." and ip6 proto 47"
local filter, errmsg = filter:new(program)
assert(filter, errmsg and ffi.string(errmsg))
o._filter = filter
return o
end

function vpws:push()
Expand All @@ -57,7 +56,7 @@ function vpws:push()
-- IPv6 payload length consist of the size of the GRE header plus
-- the size of the original packet
encap.ipv6:payload_length(encap.gre:sizeof() + p.length)
if encap.gre:use_checksum() then
if encap.gre:checksum() then
encap.gre:checksum(datagram:payload())
end
-- Copy the finished headers into the packet
Expand All @@ -66,23 +65,85 @@ function vpws:push()
datagram:push(encap.gre)
else
-- Check for encapsulated frame coming in on uplink
if datagram:parse(self._match) then
if self._filter:match(datagram:payload()) then
-- Remove encapsulation to restore the original
-- Ethernet frame
datagram:pop(3)
datagram:pop_raw(self._eth_ipv6_size, gre)
local valid = true
local gre = datagram:parse()
if gre then
if not gre:checksum_check(datagram:payload()) then
print(self:name()..": GRE bad checksum")
valid = false
else
local key = gre:key()
if ((self._config.label and key and key == self._config.label) or
not (self._config.label or key)) then
datagram:pop()
else
print(self:name()..": GRE key mismatch: local "
..(self._config.label or 'none')..", remote "..(gre:key() or 'none'))
valid = false
end
end
else
-- Unsupported GRE options or flags
valid = false
end
if not valid then
packet.deref(p)
p = nil
end
else
-- Packet doesn't belong to VPN, discard
packet.deref(p)
p = nil
end
end
if p then link.transmit(l_out, p) end
datagram:free()
end
end
end

function vpws.selftest()
print("vpws selftest not implemented")
function selftest()
local local_mac = ethernet:pton("90:e2:ba:62:86:e5")
local remote_mac = ethernet:pton("28:94:0f:fd:49:40")
local local_ip = ipv6:pton("2001:620:0:C101:0:0:0:2")
local local_vpn_ip = ipv6:pton("2001:620:0:C000:0:0:0:FC")
local remote_vpn_ip = ipv6:pton("2001:620:0:C000:0:0:0:FE")
local c = config.new()

config.app(c, "from_uplink", pcap.PcapReader, "apps/vpn/vpws-selftest-uplink.cap.input")
config.app(c, "from_customer", pcap.PcapReader, "apps/vpn/vpws-selftest-customer.cap.input")
config.app(c, "to_customer", pcap.PcapWriter, "apps/vpn/vpws-selftest-customer.cap.output")
config.app(c, "to_uplink", pcap.PcapWriter, "apps/vpn/vpws-selftest-uplink.cap.output")
config.app(c, "vpntp", vpws, { name = "vpntp1",
checksum = true,
label = 0x12345678,
local_vpn_ip = local_vpn_ip,
remote_vpn_ip = remote_vpn_ip,
local_ip = local_ip,
local_mac = local_mac,
remote_mac = remote_mac })
config.link(c, "from_uplink.output -> vpntp.uplink")
config.link(c, "vpntp.customer -> to_customer.input")
config.link(c, "from_customer.output -> vpntp.customer")
config.link(c, "vpntp.uplink -> to_uplink.input")
app.configure(c)
app.main({duration = 1})
if (io.open("apps/vpn/vpws-selftest-customer.cap.output"):read('*a') ~=
io.open("apps/vpn/vpws-selftest-customer.cap.expect"):read('*a')) then
print('vpws decapsulation selftest failed.')
os.exit(1)
end
if (io.open("apps/vpn/vpws-selftest-uplink.cap.output"):read('*a') ~=
io.open("apps/vpn/vpws-selftest-uplink.cap.expect"):read('*a')) then
print('vpws encapsulation selftest failed.')
os.exit(1)
end
end

vpws.selftest = selftest

return vpws
1 change: 1 addition & 0 deletions src/core/buffer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ function new_buffer ()
local pointer, physical, bytes = memory.dma_alloc(buffersize)
local b = lib.malloc("struct buffer")
b.pointer, b.physical, b.size = pointer, physical, buffersize
b.origin.type = C.BUFFER_ORIGIN_UNKNOWN
return b
end

Expand Down
2 changes: 1 addition & 1 deletion src/core/lib.lua
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ function update_csum (ptr, len, csum0)
for i = 0, len-2, 2 do
sum = sum + bit.lshift(ptr[i], 8) + ptr[i+1]
end
if len % 2 == 1 then sum = sum + bit.lshift(ptr[len-1]) end
if len % 2 == 1 then sum = sum + bit.lshift(ptr[len-1], 1) end
return sum
end

Expand Down
Loading

0 comments on commit e43188d

Please sign in to comment.