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

Merge vpn performancev2 #221

Merged
merged 15 commits into from
Jul 2, 2014
Merged
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
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