diff --git a/src/apps/README.md.src b/src/apps/README.md.src index 23c8b3a374..54caa706c5 100644 --- a/src/apps/README.md.src +++ b/src/apps/README.md.src @@ -70,17 +70,3 @@ discards them. This can be handy in combination with a `Source`. | | +--------+ -## Buzz - -The `Buzz` app simply prints a message to standard output each time a -callback runs. This can be useful for observing the execution of the app -framework in a primitive way. - - DIAGRAM: Buzz - +--------+ - | | - | | - | Buzz | - | | - | | - +--------+ diff --git a/src/apps/basic/basic_apps.lua b/src/apps/basic/basic_apps.lua index 50b8d5ebbc..86083b09cd 100644 --- a/src/apps/basic/basic_apps.lua +++ b/src/apps/basic/basic_apps.lua @@ -29,8 +29,6 @@ Source = setmetatable({zone = "Source"}, {__index = Basic}) function Source:new(size) size = tonumber(size) or 60 local data = ffi.new("char[?]", size) - data[12] = 0x08 - data[13] = 0x00 local p = packet.from_pointer(data, size) return setmetatable({size=size, packet=p}, {__index=Source}) end @@ -39,14 +37,14 @@ function Source:pull () for _, o in ipairs(self.outputi) do for i = 1, link.nwritable(o) do transmit(o, packet.clone(self.packet)) - -- To repeatedly resend the same packet requires a - -- corresponding change in intel10g.lua sync_transmit() to - -- skip the call to packet.free() - --transmit(o, self.packet) end end end +function Source:stop () + packet.free(self.packet) +end + --- # `Join` app: Merge multiple inputs onto one output Join = setmetatable({zone = "Join"}, {__index = Basic}) @@ -100,26 +98,6 @@ function Sink:push () end end ---- ### `FastSink` app: Receive and discard packets - --- It is hacked Sink with very low packet processing overhead --- Only for test purpose, never use it in real world application --- Assumed to be used in pair with FastRepeater --- FastSink doesn't calculate rx statistics - -FastSink = setmetatable({zone = "FastSink"}, {__index = Basic}) - -function FastSink:new () - return setmetatable({}, {__index=Sink}) -end - -function FastSink:push () - local i = self.input.input - -- make link empty - i.read = 0 - i.write = 0 -end - --- ### `Tee` app: Send inputs to all outputs Tee = setmetatable({zone = "Tee"}, {__index = Basic}) @@ -141,7 +119,7 @@ function Tee:push () maxoutput = maxoutput - 1 do local outputi = self.outputi for k = 1, #outputi do - transmit(outputi[k], p) + transmit(outputi[k], k == #outputi and p or packet.clone(p)) end end end @@ -162,7 +140,6 @@ function Repeater:push () local i, o = self.input.input, self.output.output for _ = 1, link.nreadable(i) do local p = receive(i) --- packet.tenure(p) table.insert(self.packets, p) end local npackets = #self.packets @@ -175,59 +152,9 @@ function Repeater:push () end end ---- ### `FastRepeater` app: Send all received packets in a loop - --- It is hacked Repeater with very low packet processing overhead --- Only for test purpose, never use it in real world application --- Assumed to be used in pair with FastSink - -FastRepeater = setmetatable({zone = "FastRepeater"}, {__index = Basic}) - -function FastRepeater:new () - return setmetatable({init = true}, - {__index=FastRepeater}) -end - -do - local ring_size = C.LINK_RING_SIZE - local max_packets = C.LINK_MAX_PACKETS - - function FastRepeater:push () - local o = self.output.output - -- on first call read all packets - if self.init then - local i = self.input.input - local npackets = link.nreadable(i) - for index = 1, npackets do - local p = receive(i) - packet.tenure(p) - o.packets[index - 1] = p - end - -- and fullfil output link buffer - for index = npackets, max_packets do - o.packets[index] = o.packets[index % npackets] - end - o.stats.txpackets = ring_size - self.init = false - return - end - -- reset output link, make it full again - o.write = (o.write + link.nwritable(o)) % ring_size - -- assert(link.full(o)) -- hint how to debug - o.stats.txpackets = o.stats.txpackets + ring_size - -- intentionally don't calculate txbytes +function Repeater:stop () + for i = 1, #self.packets do + packet.free(self.packets[i]) end end ---- ### `Buzz` app: Print a debug message when called - -Buzz = setmetatable({zone = "Buzz"}, {__index = Basic}) - -function Buzz:new () - return setmetatable({}, {__index=Buzz}) -end - -function Buzz:pull () print "bzzz pull" end -function Buzz:push () print "bzzz push" end - - diff --git a/src/apps/fuzz/ethernet.lua b/src/apps/fuzz/ethernet.lua deleted file mode 100644 index ac3ac45dee..0000000000 --- a/src/apps/fuzz/ethernet.lua +++ /dev/null @@ -1,55 +0,0 @@ -module(...,package.seeall) - -local lib = require("core.lib") -local packet = require("core.packet") -local datagram = require("lib.protocol.datagram") -local ethernet = require("lib.protocol.ethernet") - -local ffi = require("ffi") -local C = ffi.C - --- Ethernet generator -g_ethernet = {} -g_ethernet.__index = g_ethernet - -function g_ethernet:new (data_list) - -- should be at least one layer before us - assert(data_list and #data_list > 0) - return setmetatable({ - data_list = data_list, - src = ethernet:pton("00:00:00:00:00:01"), - dst = ethernet:pton("00:00:00:00:00:02"), - match = {{ethernet}} - }, g_ethernet) -end - -function g_ethernet:single (data) - -- simple Etherent frame - source, destination, type - local new_p = packet.clone(data.dg:packet()) - local d = datagram:new(new_p, ethernet) - local eth = d:parse(self.match) - - eth:src(self.src) - eth:dst(self.dst) - eth:type(0xFFFF) --invalid - - return { - dg = d, - desc = "Ethernet", - ethernet = eth, - match = self.match, - valid = true, - } -end - -function g_ethernet:generate() - -- save the origin list to iterate over it - local origin = lib.array_copy(self.data_list) - local size = #self.data_list - for i=1,#origin do - size = size + 1 - self.data_list[size] = self:single(origin[i]) - end -end - -return g_ethernet diff --git a/src/apps/fuzz/fuzz.lua b/src/apps/fuzz/fuzz.lua deleted file mode 100644 index 07e472553d..0000000000 --- a/src/apps/fuzz/fuzz.lua +++ /dev/null @@ -1,88 +0,0 @@ -module(...,package.seeall) - -local app = require("core.app") -local basic_apps = require("apps.basic.basic_apps") -local buffer = require("core.buffer") -local freelist = require("core.freelist") -local generator = require("apps.fuzz.generator") -local matcher = require("apps.fuzz.matcher") -local lib = require("core.lib") -local packet = require("core.packet") -local datagram = require("lib.protocol.datagram") - -local link = require("core.link") - -local ffi = require("ffi") -local C = ffi.C - -fuzz = {} -fuzz.__index = fuzz - -function fuzz:new () - generated = generator:new():generate() - return setmetatable({ - zone="fuzz", - generated = generated, -- all generated packets - matcher = matcher:new(generated), - sent = 0 - }, fuzz) -end - --- Allocate receive buffers from the given freelist. -function fuzz:set_rx_buffer_freelist (fl) - assert(fl) - self.rx_buffer_freelist = fl -end - -function fuzz:get_next() - self.sent = self.sent + 1 - return self.generated[self.sent] -end - -function fuzz:receive(p) - -- send the received packet to the matcher - self.matcher:match(p) - packet.deref(p) -end - -function fuzz:pull () - local l = self.output.tx - if l == nil then return end - local d = self:get_next() - if d then - for _,p in ipairs(d.sg) do - --print(packet.report(p)) - packet.ref(p) -- ensure enough refs - link.transmit(l, p) - end - end -end - -function fuzz:push () - local l = self.input.rx - if l == nil then return end - while not link.empty(l) do - local p = link.receive(l) - self:receive(p) - packet.deref(p) - end -end - -function fuzz:report() - self.matcher:report() -end - -function selftest () - buffer.preallocate(100000) - - local c = config.new() - config.app(c, 'fuzz', fuzz) - config.app(c, 'tee', basic_apps.Tee) - config.link(c, 'fuzz.tx -> tee.in') - config.link(c, 'tee.out -> fuzz.rx') - engine.configure(c) - - local fuzz = app.app_table.fuzz - engine.main({duration = 1, report={showlinks=true, showapps=false}}) - fuzz:report() -end diff --git a/src/apps/fuzz/generator.lua b/src/apps/fuzz/generator.lua deleted file mode 100644 index 8903d99eba..0000000000 --- a/src/apps/fuzz/generator.lua +++ /dev/null @@ -1,124 +0,0 @@ -module(...,package.seeall) - -local buffer = require("core.buffer") -local freelist = require("core.freelist") -local lib = require("core.lib") -local packet = require("core.packet") -local datagram = require("lib.protocol.datagram") -local g_ethernet = require("apps.fuzz.ethernet") -local g_ipv4 = require("apps.fuzz.ipv4") -local g_ipv6 = require("apps.fuzz.ipv6") -local g_udp = require("apps.fuzz.udp") -local g_tcp = require("apps.fuzz.tcp") - -local ffi = require("ffi") -local C = ffi.C - -local uint16_t_size = ffi.sizeof("uint16_t") - --- The raw generator makes datagarams out of thin air -raw = {} -raw.__index = raw - -function raw:new (data_list) - -- we're the first in the chain - assert(data_list and #data_list == 0) - return setmetatable({ - data_list = data_list, - -- sizes explained - -- 64 - minimum ethernet size - -- 1514 - max ethernet - no vlan - -- 1518 - max ethernet - -- 2048 - jumbo frame - -- 4096 - jumbo frame - max buffer size we support - sizes = {64, 128, 256, 512, 1024, 1514, 1518, 2048, 4096} - }, raw) -end - -function raw:single (size) - local d = datagram:new() - d:payload(lib.random_data(size), size) - return d -end - -function raw:generate() - for _, s in ipairs(self.sizes) do - self.data_list[#self.data_list + 1] = { - dg = self:single(s), - desc = " Raw data", - valid = true - } - end -end - -all_generators = {raw, g_ethernet, g_ipv4, g_ipv6, g_udp, g_tcp} - -generator = {} -generator.__index = generator - -function generator:new (generators) - return setmetatable({ - zone="generator", - generators = generators or all_generators, - sg_patterns = { - -- one jumbo buffer - {{4096}}, - -- 1 byte | the rest - {{1}}, - -- 1 byte @ offset 4095 | the rest - {{1,4095}}, - -- 1 @ 4095 | 1 | the rest - {{1,4095},{1}}, - -- 1024 | 1 @ 4095 | the rest - {{1024}, {1,4095}}, - -- 64 | 1024 | the rest - {{64},{1024}}, - -- 15 (PACKET_IOVEC_MAX-1) times 10 byte chunks | the rest - {{10},{10},{10},{10},{10},{10},{10},{10},{10},{10},{10},{10},{10},{10},{10}} - } - }, generator) -end - -function generator:mark (dg, mark) - local payload, plen = dg:payload() - local pmark = ffi.cast("uint16_t*",payload + plen - uint16_t_size) - pmark[0] = C.htons(mark) -end - -function generator:scatter (data) - data.sg = {} - for _, sg in ipairs(self.sg_patterns) do - local p = data.dg:packet() - data.sg[#data.sg + 1] = packet.scatter(p, sg) - end -end - -function generator:reset_list(data_list) - for _, data in ipairs(data_list) do - data.received = 0 - end -end - -function generator:generate () - local data_list = {} - -- iterate over all registered payload generators - for _,class in ipairs(self.generators) do - local g = class:new(data_list) - g:generate() - end - - -- mark the generated packets - for i, data in ipairs(data_list) do - self:mark(data.dg, i) - end - - -- make the packet list out of the data list - for _, data in ipairs(data_list) do - self:scatter(data) - end - - self:reset_list(data_list) - return data_list -end - -return generator diff --git a/src/apps/fuzz/ipv4.lua b/src/apps/fuzz/ipv4.lua deleted file mode 100644 index 5d5c813d2c..0000000000 --- a/src/apps/fuzz/ipv4.lua +++ /dev/null @@ -1,88 +0,0 @@ -module(...,package.seeall) - -local lib = require("core.lib") -local packet = require("core.packet") -local datagram = require("lib.protocol.datagram") -local ethernet = require("lib.protocol.ethernet") -local ipv4 = require("lib.protocol.ipv4") - -local ffi = require("ffi") -local C = ffi.C - --- IPv4 generator -g_ipv4 = {} -g_ipv4.__index = g_ipv4 - -function g_ipv4:new (data_list) - -- should be at least one layer before us - assert(data_list and #data_list > 0) - return setmetatable({ - data_list = data_list, - src = ipv4:pton("192.168.0.1"), - dst = ipv4:pton("192.168.0.2"), - match = {{ethernet}, {ipv4}} - }, g_ipv4) -end - -function g_ipv4:clone (data) - local new_p = packet.clone(data.dg:packet()) - local d = datagram:new(new_p, ethernet) - -- ensure the ethernet frame is of IPv4 type - local eth = d:parse({{ethernet}}) - eth:type(0x0800) -- IPv4 - d:unparse(1) - - -- start all over again - d:parse(self.match) - local eth, ip = unpack(d:stack()) - - ip:version(4) - ip:ihl(ip:sizeof() / 4) - ip:dscp(0) - ip:ecn(0) - ip:total_length(new_p.length - eth:sizeof()) -- the length - ip:id(0) - ip:flags(0) - ip:frag_off(0) - ip:ttl(3) -- arbitrary - ip:protocol(0xff) -- invalid protocol, upper layers to set - ip:src(self.src) - ip:dst(self.dst) - local new_data = { - dg = d, - desc = data.desc.." IPv4", - ethernet = eth, - ipv4 = ip, - match = self.match, - valid = true - } - self.data_list[#self.data_list + 1] = new_data - return new_data -end - -function g_ipv4:single (data) - -- if ethernet header does not exist, leave - if not data.ethernet then return end - - -- default ipv4 packet - local new_data = self:clone (data) - - -- ecn - new_data = self:clone (data) - new_data.ipv4:ecn(0x3) - new_data.desc = new_data.desc.." ecn" - - -- don't fragment - new_data = self:clone (data) - new_data.ipv4:flags(0x2) - new_data.desc = new_data.desc.." df" -end - -function g_ipv4:generate() - local origin = lib.array_copy(self.data_list) - for i=1,#origin do - self:single(origin[i]) - end -end - -return g_ipv4 diff --git a/src/apps/fuzz/ipv6.lua b/src/apps/fuzz/ipv6.lua deleted file mode 100644 index e89d0b150d..0000000000 --- a/src/apps/fuzz/ipv6.lua +++ /dev/null @@ -1,82 +0,0 @@ -module(...,package.seeall) - -local lib = require("core.lib") -local packet = require("core.packet") -local datagram = require("lib.protocol.datagram") -local ethernet = require("lib.protocol.ethernet") -local ipv6 = require("lib.protocol.ipv6") - -local ffi = require("ffi") -local C = ffi.C - --- IPv6 generator -g_ipv6 = {} -g_ipv6.__index = g_ipv6 - -function g_ipv6:new (data_list) - -- should be at least one layer before us - assert(data_list and #data_list > 0) - return setmetatable({ - data_list = data_list, - src = ipv6:pton("0:0:0:0:0:0:0:1"), - dst = ipv6:pton("0:0:0:0:0:0:0:2"), - match = {{ethernet}, {ipv6}} - }, g_ipv6) -end - -function g_ipv6:clone (data) - local new_p = packet.clone(data.dg:packet()) - local d = datagram:new(new_p, ethernet) - -- ensure the ethernet frame is of IPv6 type - local eth = d:parse({{ethernet}}) - eth:type(0x86dd) -- IPv6 - d:unparse(1) - - -- start all over again - d:parse(self.match) - local eth, ip = unpack(d:stack()) - - ip:version(6) - ip:traffic_class(0) - ip:flow_label(0) - ip:payload_length(new_p.length - eth:sizeof() - ip:sizeof()) - ip:next_header(0xff) -- invalid - ip:hop_limit(3) -- arbitrary - ip:src(self.src) - ip:dst(self.dst) - local new_data = { - dg = d, - desc = data.desc.." IPv6", - ethernet = eth, - ipv6 = ip, - match = self.match, - valid = true - } - self.data_list[#self.data_list + 1] = new_data - return new_data -end - -function g_ipv6:single (data) - -- if ethernet header does not exist, - -- or IPv4 is already set, leave - if not data.ethernet or data.ipv4 then return end - - -- default ipv6 packet - local new_data = self:clone (data) - - -- ecn - new_data = self:clone (data) - new_data.ipv6:traffic_class(0x3) - new_data.desc = new_data.desc.." ecn" - -end - -function g_ipv6:generate() - -- save the origin list to iterate over it - local origin = lib.array_copy(self.data_list) - for i=1,#origin do - self:single(origin[i]) - end -end - -return g_ipv6 diff --git a/src/apps/fuzz/matcher.lua b/src/apps/fuzz/matcher.lua deleted file mode 100644 index 9c86ca8e69..0000000000 --- a/src/apps/fuzz/matcher.lua +++ /dev/null @@ -1,119 +0,0 @@ -module(...,package.seeall) - -local buffer = require("core.buffer") -local freelist = require("core.freelist") -local lib = require("core.lib") -local packet = require("core.packet") -local datagram = require("lib.protocol.datagram") -local ethernet = require("lib.protocol.ethernet") -local g_ethernet = require("apps.fuzz.ethernet") -local g_ipv4 = require("apps.fuzz.ipv4") -local g_ipv6 = require("apps.fuzz.ipv6") -local g_udp = require("apps.fuzz.udp") -local g_tcp = require("apps.fuzz.tcp") - -local ffi = require("ffi") -local C = ffi.C - -local uint16_t_size = ffi.sizeof("uint16_t") - -matcher = {} -matcher.__index = matcher - -function matcher:new (data_list) - return setmetatable({ - zone="matcher", - data_list = data_list, - }, matcher) -end - -function matcher:get_mark(p) - local iovec = p.iovecs[0] - local b = iovec.buffer - local offset = iovec.offset + iovec.length - uint16_t_size - local pmark = ffi.cast("uint16_t*",b.pointer + offset) - return C.ntohs(pmark[0]) -end - -function matcher:error(message) - print("--------------------------------------------------------------------------------") - print("[ERROR]"..message) - print("--------------------------------------------------------------------------------") - return -end - -function matcher:match(p) - - -- squash all data in iovecs[0] - packet.coalesce(p) - - local id = self:get_mark(p) - local match = self.data_list[id] - if not match then - self:error("can not find a match for the packet\n"..packet.report(p)) - return - end - - local iovec = p.iovecs[0] - local ptr = iovec.buffer.pointer + iovec.offset - local len = p.length - local match_stack = match.dg:stack() - - if #match_stack > 0 then - - -- determine the parse list - local d = datagram:new(p, ethernet) - if not d:parse(match.match) then - self:error("can not parse the packet\n"..packet.report(p)) - end - - local stack = d:stack() - - for k, header in ipairs(stack) do - local match_header = match_stack[k] - - if not match_header then - print("No match_header for "..tostring(k)) - end - - if not header then - print("No header for "..tostring(k)) - end - - if match_header and header then - if not match_header:eq(header) then - self:error("can not match") - return - end - end - end - -- update for payload compare - ptr, len = d:payload() - else - -- raw packet - end - - -- compare raw payload - if ffi.string(match.dg:payload()) ~= ffi.string(ptr, len) then - self:error("raw packet data does not match") - return - end - - -- if we got here, all checks passed and we'll increase the received counter - match.received = match.received + 1 -end - -function matcher:report() - local sent, received = 0,0 - for _,match in ipairs(self.data_list) do - if match.received ~= #match.sg then - print(string.format("Mismatch for packet %s. Generated %d, received %d.", - match.desc, #match.sg, match.received)) - end - sent = sent + #match.sg - received = received + match.received - end - print(string.format("Sent:\t\t%d\nReceived:\t%d", sent, received)) -end - -return matcher diff --git a/src/apps/fuzz/tcp.lua b/src/apps/fuzz/tcp.lua deleted file mode 100644 index 9a7c0c8663..0000000000 --- a/src/apps/fuzz/tcp.lua +++ /dev/null @@ -1,155 +0,0 @@ -module(...,package.seeall) - -local lib = require("core.lib") -local packet = require("core.packet") -local datagram = require("lib.protocol.datagram") -local ethernet = require("lib.protocol.ethernet") -local ipv6 = require("lib.protocol.ipv6") -local ipv4 = require("lib.protocol.ipv4") -local tcp = require("lib.protocol.tcp") - -local ffi = require("ffi") -local C = ffi.C - --- TCP generator -g_tcp = {} -g_tcp.__index = g_tcp - -function g_tcp:new (data_list) - -- should be at least one layer before us - assert(data_list and #data_list > 0) - return setmetatable({ - data_list = data_list, - mss = { - 32, 256, 512, 1024, -- arbitrary - 1472, -- MSS on 1514 MTU - 2048 -- jumbo - }, - src_port = 111, - dst_port = 222, - match4 = {{ethernet}, {ipv4}, {tcp}}, - match6 = {{ethernet}, {ipv6}, {tcp}} - }, g_tcp) -end - -function g_tcp:clone4 (data) - local new_p = packet.clone(data.dg:packet()) - local d = datagram:new(new_p, ethernet) - -- ensure the IPv4 packet is of TCP type - local ip = d:parse({{ethernet}, {ipv4}}) - ip:protocol(6) -- TCP - d:unparse(2) - - -- start all over again - d:parse(self.match4) - local eth, ip, tcp = unpack(d:stack()) - - tcp:src_port(self.src_port) - tcp:dst_port(self.dst_port) - tcp:seq_num(12345) -- arbitrary - tcp:ack_num(12345) -- arbitrary - tcp:offset(0) - tcp:flags(0) - tcp:window_size(4096) - - local new_data = { - dg = d, - desc = data.desc.." TCP", - ethernet = eth, - ipv4 = ip, - tcp = tcp, - match = self.match4, - valid = true - } - self.data_list[#self.data_list + 1] = new_data - return new_data -end - -function g_tcp:clone6 (data) - local new_p = packet.clone(data.dg:packet()) - local d = datagram:new(new_p, ethernet) - -- ensure the IPv6 packet is of TCP type - local ip = d:parse({{ethernet}, {ipv6}}) - ip:next_header(6) -- TCP - d:unparse(2) - - -- start all over again - d:parse(self.match6) - local eth, ip, tcp = unpack(d:stack()) - - tcp:src_port(self.src_port) - tcp:dst_port(self.dst_port) - tcp:seq_num(12345) -- arbitrary - tcp:ack_num(12345) -- arbitrary - tcp:offset(0) - tcp:flags(0) - tcp:window_size(4096) - - local new_data = { - dg = d, - desc = data.desc.." TCP", - ethernet = eth, - ipv6 = ip, - tcp = tcp, - match = self.match6, - valid = true - } - self.data_list[#self.data_list + 1] = new_data - return new_data -end - -function g_tcp:single (data) - -- generate packets for all supoprted MSS types - for _,mss in ipairs(self.mss) do - if data.ipv4 then - -- default ipv4 packet - local new_data = self:clone4 (data) - local p = new_data.dg:packet() - local info = p.info - - --checksum - info.flags = C.PACKET_NEEDS_CSUM - info.csum_start = new_data.ethernet:sizeof() + new_data.ipv4:sizeof() - info.csum_offset = 16 -- TCP offset is 6 bytes from the start - - -- segmentation - info.gso_flags = C.PACKET_GSO_TCPV4 - if new_data.ipv4:ecn() ~= 0 then - info.gso_flags = info.gso_flags + C.PACKET_GSO_ECN - end - info.gso_size = mss -- MSS - info.hdr_len = new_data.ethernet:sizeof() + new_data.ipv4:sizeof() + new_data.tcp:sizeof() - elseif data.ipv6 then - -- check if we can fit (eth + ipv6 + tcp + data) - if data.dg:packet().length > (14 + 40 + 20 + 2) then - -- default ipv6 packet - local new_data = self:clone6 (data) - local p = new_data.dg:packet() - local info = p.info - - --checksum - info.flags = C.PACKET_NEEDS_CSUM - info.csum_start = new_data.ethernet:sizeof() + new_data.ipv6:sizeof() - info.csum_offset = 16 -- TCP offset is 6 bytes from the start - - -- segmentation - info.gso_flags = C.PACKET_GSO_TCPV6 - if new_data.ipv6:ecn() ~= 0 then - info.gso_flags = info.gso_flags + C.PACKET_GSO_ECN - end - info.gso_size = mss -- MSS - info.hdr_len = new_data.ethernet:sizeof() + new_data.ipv6:sizeof() + new_data.tcp:sizeof() - end - end - end -end - -function g_tcp:generate() - -- save the origin list to iterate over it - local origin = lib.array_copy(self.data_list) - for i=1,#origin do - self:single(origin[i]) - end -end - -return g_tcp diff --git a/src/apps/fuzz/udp.lua b/src/apps/fuzz/udp.lua deleted file mode 100644 index 0493544037..0000000000 --- a/src/apps/fuzz/udp.lua +++ /dev/null @@ -1,137 +0,0 @@ -module(...,package.seeall) - -local lib = require("core.lib") -local packet = require("core.packet") -local datagram = require("lib.protocol.datagram") -local ethernet = require("lib.protocol.ethernet") -local ipv6 = require("lib.protocol.ipv6") -local ipv4 = require("lib.protocol.ipv4") -local udp = require("lib.protocol.udp") - -local ffi = require("ffi") -local C = ffi.C - --- UDP generator -g_udp = {} -g_udp.__index = g_udp - -function g_udp:new (data_list) - -- should be at least one layer before us - assert(data_list and #data_list > 0) - return setmetatable({ - data_list = data_list, - mss = { - 32, 256, 512, 1024, -- arbitrary - 1472, -- MSS on 1514 MTU - 2048 -- jumbo - }, - src_port = 111, - dst_port = 222, - match4 = {{ethernet}, {ipv4}, {udp}}, - match6 = {{ethernet}, {ipv6}, {udp}} - }, g_udp) -end - -function g_udp:clone4 (data) - local new_p = packet.clone(data.dg:packet()) - local d = datagram:new(new_p, ethernet) - -- ensure the IPv4 packet is of UDP type - local ip = d:parse({{ethernet}, {ipv4}}) - ip:protocol(17) -- UDP - d:unparse(2) - - -- start all over again - d:parse(self.match4) - local eth, ip, udp = unpack(d:stack()) - - udp:src_port(self.src_port) - udp:dst_port(self.dst_port) - udp:length(new_p.length - eth:sizeof() - ip:sizeof()) -- the length - - local new_data = { - dg = d, - desc = data.desc.." UDP", - ethernet = eth, - ipv4 = ip, - udp = udp, - match = self.match4, - valid = true - } - self.data_list[#self.data_list + 1] = new_data - return new_data -end - -function g_udp:clone6 (data) - local new_p = packet.clone(data.dg:packet()) - local d = datagram:new(new_p, ethernet) - -- ensure the IPv6 packet is of UDP type - local ip = d:parse({{ethernet}, {ipv6}}) - ip:next_header(17) -- UDP - d:unparse(2) - - -- start all over again - d:parse(self.match6) - local eth, ip, udp = unpack(d:stack()) - - udp:src_port(self.src_port) - udp:dst_port(self.dst_port) - udp:length(new_p.length - eth:sizeof() - ip:sizeof()) -- the length - - local new_data = { - dg = d, - desc = data.desc.." UDP", - ethernet = eth, - ipv6 = ip, - udp = udp, - match = self.match6, - valid = true - } - self.data_list[#self.data_list + 1] = new_data - return new_data -end - -function g_udp:single (data) - - if data.ipv4 then - -- generate packets for all supoprted MSS types - for _,mss in ipairs(self.mss) do - -- default ipv4 packet - local new_data = self:clone4 (data) - local p = new_data.dg:packet() - local info = p.info - - --checksum - info.flags = C.PACKET_NEEDS_CSUM - info.csum_start = new_data.ethernet:sizeof() + new_data.ipv4:sizeof() - info.csum_offset = 6 -- UDP offset is 6 bytes from the start - - -- segmentation - info.gso_flags = C.PACKET_GSO_UDPV4 - if new_data.ipv4:ecn() ~= 0 then - info.gso_flags = info.gso_flags + C.PACKET_GSO_ECN - end - info.gso_size = mss -- MSS - info.hdr_len = new_data.ethernet:sizeof() + new_data.ipv4:sizeof() + new_data.udp:sizeof() - end - elseif data.ipv6 then - -- default ipv6 packet - local new_data = self:clone6 (data) - local p = new_data.dg:packet() - local info = p.info - - --checksum - info.flags = C.PACKET_NEEDS_CSUM - info.csum_start = new_data.ethernet:sizeof() + new_data.ipv6:sizeof() - info.csum_offset = 6 -- UDP offset is 6 bytes from the start - end -end - -function g_udp:generate() - -- save the origin list to iterate over it - local origin = lib.array_copy(self.data_list) - for i=1,#origin do - self:single(origin[i]) - end -end - -return g_udp diff --git a/src/apps/intel/intel10g.lua b/src/apps/intel/intel10g.lua index e638a499d6..1fb022f911 100644 --- a/src/apps/intel/intel10g.lua +++ b/src/apps/intel/intel10g.lua @@ -131,7 +131,6 @@ function M_sf:init_receive () self.r.HLREG0(bits{ TXCRCEN=0, RXCRCSTRP=1, JUMBOEN=2, rsv2=3, TXPADEN=10, rsvd3=11, rsvd4=13, MDCSPD=16 - -- Temporarily disabled: RXLNGTHERREN=27 }) self.r.MAXFRS(lshift(9000+18, 16)) self:set_receive_descriptors() diff --git a/src/apps/intel/intel_app.lua b/src/apps/intel/intel_app.lua index 2706d21471..1c79b19ecd 100644 --- a/src/apps/intel/intel_app.lua +++ b/src/apps/intel/intel_app.lua @@ -139,30 +139,21 @@ function selftest () os.exit(engine.test_skipped_code) end --- zone('buffer') buffer.preallocate(100000) zone() - - sq_sq(pcideva, pcidevb) - local done = function () - return engine.app_table['nicA'].input.rx.stats.rxpackets >= 100e6 - end - engine.main({done=done, report={showlinks=true, showapps=false}}) - engine.report({showapps=true}) - if true then return end - mq_sw(pcideva) engine.main({duration = 1, report={showlinks=true, showapps=false}}) --- engine.report({showapps=true}) do local a0Sends = engine.app_table.nicAm0.input.rx.stats.txpackets local a1Gets = engine.app_table.nicAm1.output.tx.stats.rxpackets - if a1Gets < a0Sends/4 - or a1Gets > a0Sends*3/4 - then - print ('wrong proportion of packets passed/discarded') + -- Check propertions with some modest margin for error + if a1Gets < a0Sends * 0.45 or a1Gets > a0Sends * 0.55 then + print("mq_sw: wrong proportion of packets passed/discarded") os.exit(1) end end + sq_sq(pcideva, pcidevb) + engine.main({duration = 1, report={showlinks=true, showapps=false}}) + do local aSends = engine.app_table.nicA.input.rx.stats.txpackets local aGets = engine.app_table.nicA.output.tx.stats.rxpackets @@ -174,14 +165,13 @@ function selftest () or bGets < aGets/2 or aGets < bGets/2 then - print ('not enought packets somewhere') + print("sq_sq: missing packets") os.exit (1) end end mq_sq(pcideva, pcidevb) engine.main({duration = 1, report={showlinks=true, showapps=false}}) --- engine.report({showapps=true}) do local aSends = engine.app_table.nicAs.input.rx.stats.txpackets @@ -192,18 +182,19 @@ function selftest () b1Gets < b0Gets/2 or b0Gets+b1Gets < aSends/2 then - print ('not enought packets somewhere') + print("mq_sq: missing packets") os.exit (1) end end + print("selftest: ok") end -- open two singlequeue drivers on both ends of the wire function sq_sq(pcidevA, pcidevB) engine.configure(config.new()) local c = config.new() - print ('-------') - print ('just send a lot of packets through the wire') + print("-------") + print("Transmitting bidirectionally between nicA and nicB") config.app(c, 'source1', basic_apps.Source) config.app(c, 'source2', basic_apps.Source) config.app(c, 'nicA', Intel82599, {pciaddr=pcidevA}) @@ -254,9 +245,9 @@ function mq_sq(pcidevA, pcidevB) pciaddr = pcidevB, vmdq = true, macaddr = '52:54:00:03:03:03'}) - print ('-------') - print ("Send a bunch of from the SF on NIC A to the VFs on NIC B") - print ("half of them go to nicBm0 and nicBm0") + print("-------") + print("Send traffic from a nicA (SF) to nicB (two VFs)") + print("The packets should arrive evenly split between the VFs") config.app(c, 'sink_ms', basic_apps.Sink) config.link(c, 'source_ms.out -> repeater_ms.input') config.link(c, 'repeater_ms.output -> nicAs.rx') @@ -266,7 +257,6 @@ function mq_sq(pcidevA, pcidevB) engine.configure(c) link.transmit(engine.app_table.source_ms.output.out, packet.from_string(d1)) link.transmit(engine.app_table.source_ms.output.out, packet.from_string(d2)) --- engine.report({showapps=true}) end -- one multiqueue driver with two apps and do switch stuff @@ -314,5 +304,4 @@ function mq_sw(pcidevA) engine.configure(c) link.transmit(engine.app_table.source_ms.output.out, packet.from_string(d1)) link.transmit(engine.app_table.source_ms.output.out, packet.from_string(d2)) --- engine.report({showapps=true}) end diff --git a/src/apps/ipv6/ipv6.lua b/src/apps/ipv6/ipv6.lua deleted file mode 100644 index f1c3d0f1f1..0000000000 --- a/src/apps/ipv6/ipv6.lua +++ /dev/null @@ -1,215 +0,0 @@ -module(...,package.seeall) - -local ffi = require("ffi") -local C = ffi.C - -local app = require("core.app") -local link = require("core.link") -local config = require("core.config") -local lib = require("core.lib") -local packet = require("core.packet") -local buffer = require("core.buffer") -local ethernet = require("lib.protocol.ethernet") -local ipv6 = require("lib.protocol.ipv6") -local pcap = require("apps.pcap.pcap") -local Buzz = require("apps.basic.basic_apps").Buzz - -size = { eth = 14, ipv6 = 40, icmpv6expired = 8 } - -local ipv6_t = ffi.typeof[[ -struct { - // ethernet - char dmac[6]; - char smac[6]; - uint16_t ethertype; - // ipv6 - uint32_t flow_id; // version, tc, flow_id - int16_t payload_length; - int8_t next_header; - uint8_t hop_limit; - char src_ip[16]; - char dst_ip[16]; -} __attribute__((packed)) -]] - -local icmpv6_t = ffi.typeof[[ -struct { - uint8_t type; - uint8_t code; - int16_t checksum; - union { - struct { - uint16_t reserved; - char target_address[16]; - } solicit; - struct { - int r:1, s:1, o:1, reserved:29; - char target_address[16]; - } advert; - struct { - uint32_t unused; - char data[0]; - } timeout; - }; - // option: link layer address - struct { - uint8_t type; - uint8_t length; - char addr[6]; - } l2addr; -} __attribute__((packed)) -]] - -SimpleIPv6 = {} - -function SimpleIPv6:new (arg) - local conf = arg and config.parse_app_arg(arg) or {} - if type(conf.own_mac) == "string" then - conf.own_mac = ethernet:pton(conf.own_mac) - end - own_mac = conf.own_mac or "52:54:00:12:34:57" - if type(conf.own_ip) == "string" then - conf.own_ip = ipv6:pton(conf.own_ip) - end - own_ip = conf.own_ip or "2::1" - local o = {own_mac = own_mac, own_ip = own_ip} - return setmetatable(o, {__index = SimpleIPv6}) -end - -function SimpleIPv6:push () - for name, iport in pairs(self.input) do - -- Output to the port with the same name as the input port (e.g. "eth0") - local oport = self.output[name] - assert(oport, "output port not found") - for i = 1, link.nreadable(iport) do - local p = link.receive(iport) - assert(p.iovecs[0].length >= ffi.sizeof(ipv6_t)) - local ipv6 = ffi.cast(ffi.typeof("$*", ipv6_t), p.iovecs[0].buffer.pointer + p.iovecs[0].offset) - if ipv6.ethertype == 0xDD86 then -- IPv6 (host byte order) then - if ipv6.hop_limit > 1 then - if ipv6.next_header == 58 then -- ICMPv6 - print("Received ICMPv6") - --assert(p.iovecs[0].length >= ffi.sizeof(ipv6_t) + ffi.sizeof(icmpv6_t)) - local ptr = p.iovecs[0].buffer.pointer + p.iovecs[0].offset + 54 - local icmpv6 = ffi.cast(ffi.typeof("$*", icmpv6_t), ptr) - if icmpv6.type == 135 then -- neighbor solicitation - print(" Responding to neighbor solicitation.") - -- Convert the solicitation into an advertisment. - icmpv6.type = 136 -- neighbor adverisment - icmpv6.l2addr.type = 2 -- target address - ffi.copy(icmpv6.l2addr.addr, self.own_mac, 6) - ffi.copy(ipv6.dst_ip, ipv6.src_ip, 16) - ffi.copy(ipv6.src_ip, self.own_ip, 16) - ffi.copy(ipv6.dmac, ipv6.smac, 6) - ffi.copy(ipv6.smac, self.own_mac, 6) - checksum_icmpv6(ipv6, icmpv6) - -- Transmit - link.transmit(oport, p) - elseif icmpv6.type == 128 then -- echo - print(" Responding to ECHO request") - icmpv6.type = 129 -- echo response - ffi.copy(ipv6.dst_ip, ipv6.src_ip, 16) - ffi.copy(ipv6.src_ip, self.own_ip, 16) - ffi.copy(ipv6.dmac, ipv6.smac, 6) - ffi.copy(ipv6.smac, self.own_mac, 6) - checksum_icmpv6(ipv6, icmpv6) - link.transmit(oport, p) - end - elseif C.memcmp(self.own_mac, ipv6.dmac, 6) == 0 then - -- Example: "Route" packet back to source. - -- (rewrite dmac, decrement hop limit) - ffi.copy(ipv6.dmac, ipv6.smac, 6) - ipv6.hop_limit = ipv6.hop_limit - 1 - link.transmit(oport, p) - end - else - print(" Sending ICMPv6 Time Exceeded") - -- Out of hops! - local new_p = packet.allocate() - local new_b = buffer.allocate() - local new_ipv6 = ffi.cast(ffi.typeof("$*", ipv6_t), - new_b.pointer) - local excerpt_len = math.min(1280 - 62, p.iovecs[0].length - size.eth) - ffi.copy(new_ipv6.dmac, ipv6.smac, 6) - 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.next_header = 58 -- icmpv6 - new_ipv6.hop_limit = 255 - ffi.copy(new_ipv6.src_ip, self.own_ip, 16) - ffi.copy(new_ipv6.dst_ip, ipv6.src_ip, 16) - local new_icmpv6 = ffi.cast(ffi.typeof("$*", icmpv6_t), - new_b.pointer + size.eth + size.ipv6) - new_icmpv6.type = 3 - new_icmpv6.code = 0 - new_icmpv6.timeout.unused = 0 - -- copy excerpt - ffi.copy(new_b.pointer + size.eth + size.ipv6 + size.icmpv6expired, - p.iovecs[0].buffer.pointer + size.eth, - excerpt_len) - checksum_icmpv6(new_ipv6, new_icmpv6) - packet.add_iovec(new_p, new_b, size.eth + size.ipv6 + size.icmpv6expired + excerpt_len) - link.transmit(oport, new_p) - packet.deref(p) - end - else - print("unknown ethertype: " .. bit.tohex(ipv6.ethertype, 4)) - for i = 0, 5 do - print(ipv6.smac[i]) - end - -- Drop packet - packet.deref(p) - end - end - end -end - -function checksum_icmpv6 (ipv6, icmpv6, icmpv6_len) - -- IPv6 pseudo-checksum - local ipv6_ptr = ffi.cast("uint8_t*", ipv6) - local csum = lib.update_csum(ipv6_ptr + ffi.offsetof(ipv6_t, 'src_ip'), 32) - 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 = 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) -end - -function selftest () - print("selftest: ipv6") - local own_ip = "2::1" - local own_mac = "52:54:00:12:34:57" - local c = config.new() - config.app(c, "source", pcap.PcapReader, "apps/ipv6/selftest.cap.input") - config.app(c, "ipv6", SimpleIPv6, - { own_ip = "2::1", - own_mac = "52:54:00:12:34:57" }) - config.app(c, "sink", pcap.PcapWriter, "apps/ipv6/selftest.cap.output") - config.link(c, "source.output -> ipv6.eth0") - config.link(c, "ipv6.eth0 -> sink.input") - app.configure(c) - app.main({duration = 0.25}) -- should be long enough... - -- Check results - if io.open("apps/ipv6/selftest.cap.output"):read('*a') ~= - io.open("apps/ipv6/selftest.cap.expect"):read('*a') then - print([[file selftest.cap.output does not match selftest.cap.expect. -Check for the mismatch like this (example): - tshark -Vnr apps/ipv6/selftest.cap.output > /tmp/selftest.cap.output.txt - tshark -Vnr apps/ipv6/selftest.cap.expect > /tmp/selftest.cap.expect.txt - diff -u /tmp/selftest.cap.{output,expect}.txt | less ]]) - print("selftest failed.") - os.exit(1) - else - print("OK.") - end -end - diff --git a/src/apps/ipv6/selftest.cap.expect b/src/apps/ipv6/selftest.cap.expect deleted file mode 100644 index 68531bbae9..0000000000 Binary files a/src/apps/ipv6/selftest.cap.expect and /dev/null differ diff --git a/src/apps/ipv6/selftest.cap.input b/src/apps/ipv6/selftest.cap.input deleted file mode 100644 index 0c5020ce95..0000000000 Binary files a/src/apps/ipv6/selftest.cap.input and /dev/null differ diff --git a/src/apps/keyed_ipv6_tunnel/tunnel.lua b/src/apps/keyed_ipv6_tunnel/tunnel.lua index c878aca576..28d6902f6e 100644 --- a/src/apps/keyed_ipv6_tunnel/tunnel.lua +++ b/src/apps/keyed_ipv6_tunnel/tunnel.lua @@ -180,18 +180,10 @@ function SimpleKeyedTunnel:push() assert(l_in and l_out) while not link.empty(l_in) and not link.full(l_out) do - local p = packet.want_modify(link.receive(l_in)) - - local iovec = p.iovecs[0] - - local new_b = buffer.allocate() - ffi.copy(new_b.pointer, self.header, HEADER_SIZE) - - -- set payload size - local plength = ffi.cast(plength_ctype, new_b.pointer + LENGTH_OFFSET) - plength[0] = lib.htons(SESSION_COOKIE_SIZE + p.length) - - packet.prepend_iovec(p, new_b, HEADER_SIZE) + local p = link.receive(l_in) + packet.prepend(p, self.header, HEADER_SIZE) + local plength = ffi.cast(plength_ctype, p.data + LENGTH_OFFSET) + plength[0] = lib.htons(SESSION_COOKIE_SIZE + p.length - HEADER_SIZE) link.transmit(l_out, p) end @@ -200,48 +192,31 @@ function SimpleKeyedTunnel:push() l_out = self.output.decapsulated assert(l_in and l_out) while not link.empty(l_in) and not link.full(l_out) do - local p = packet.want_modify(link.receive(l_in)) - - local iovec = p.iovecs[0] - + local p = link.receive(l_in) -- match next header, cookie, src/dst addresses local drop = true repeat - -- support only a whole tunnel header in first iovec at the moment - if iovec.length < HEADER_SIZE then + if p.length < HEADER_SIZE then break end - - local next_header = ffi.cast( - next_header_ctype, - iovec.buffer.pointer + iovec.offset + NEXT_HEADER_OFFSET - ) + local next_header = ffi.cast(next_header_ctype, p.data + NEXT_HEADER_OFFSET) if next_header[0] ~= L2TPV3_NEXT_HEADER then break end - local cookie = ffi.cast( - pcookie_ctype, - iovec.buffer.pointer + iovec.offset + COOKIE_OFFSET - ) + local cookie = ffi.cast(pcookie_ctype, p.data + COOKIE_OFFSET) if cookie[0] ~= self.remote_cookie then break end - local remote_address = ffi.cast( - paddress_ctype, - iovec.buffer.pointer + iovec.offset + SRC_IP_OFFSET - ) + local remote_address = ffi.cast(paddress_ctype, p.data + SRC_IP_OFFSET) if remote_address[0] ~= self.remote_address[0] or remote_address[1] ~= self.remote_address[1] then break end - local local_address = ffi.cast( - paddress_ctype, - iovec.buffer.pointer + iovec.offset + DST_IP_OFFSET - ) + local local_address = ffi.cast(paddress_ctype, p.data + DST_IP_OFFSET) if local_address[0] ~= self.local_address[0] or local_address[1] ~= self.local_address[1] then @@ -253,11 +228,9 @@ function SimpleKeyedTunnel:push() if drop then -- discard packet - packet.deref(p) + packet.free(p) else - iovec.offset = iovec.offset + HEADER_SIZE - iovec.length = iovec.length - HEADER_SIZE - p.length = p.length - HEADER_SIZE + packet.shiftleft(p, HEADER_SIZE) link.transmit(l_out, p) end end @@ -280,7 +253,6 @@ function selftest () default_gateway_MAC = "a1:b2:c3:d4:e5:f6" } -- should be symmetric for local "loop-back" test - buffer.preallocate(10000) local c = config.new() config.app(c, "source", pcap.PcapReader, input_file) config.app(c, "tunnel", SimpleKeyedTunnel, tunnel_config) diff --git a/src/apps/packet_filter/packet_filter.lua b/src/apps/packet_filter/packet_filter.lua index 0ff4125f31..3710d0de8a 100644 --- a/src/apps/packet_filter/packet_filter.lua +++ b/src/apps/packet_filter/packet_filter.lua @@ -407,15 +407,11 @@ function PacketFilter:push () local p = link.receive(i) -- support the whole IP header in one iovec at the moment - if self.conform( - p.iovecs[0].buffer.pointer + p.iovecs[0].offset, - p.iovecs[0].length - ) - then + if self.conform(p.data, p.length) then link.transmit(o, p) else -- discard packet - packet.deref(p) + packet.free(p) end end end @@ -425,7 +421,6 @@ function selftest () -- Packet filter selftest is failing in. -- enable verbose logging for selftest verbose = true - buffer.preallocate(10000) local V6_RULE_ICMP_PACKETS = 3 -- packets within v6.pcap local V6_RULE_DNS_PACKETS = 3 -- packets within v6.pcap diff --git a/src/apps/packet_filter/packet_filter_benchmark.lua b/src/apps/packet_filter/packet_filter_benchmark.lua index e2d8670148..4c1a32fc61 100644 --- a/src/apps/packet_filter/packet_filter_benchmark.lua +++ b/src/apps/packet_filter/packet_filter_benchmark.lua @@ -4,14 +4,12 @@ local app = require("core.app") local link = require("core.link") local lib = require("core.lib") local config = require("core.config") -local buffer = require("core.buffer") local pcap = require("apps.pcap.pcap") local basic_apps = require("apps.basic.basic_apps") local packet_filter = require("apps.packet_filter.packet_filter") function selftest () - buffer.preallocate(100000) local v6_rules = { { @@ -39,13 +37,13 @@ function selftest () pcap.PcapReader, "apps/packet_filter/samples/v6.pcap" ) - config.app(c, "repeater", basic_apps.FastRepeater ) + config.app(c, "repeater", basic_apps.Repeater ) config.app(c, "packet_filter", packet_filter.PacketFilter, v6_rules ) - config.app(c, "sink", basic_apps.FastSink ) + config.app(c, "sink", basic_apps.Sink ) config.link(c, "source.output -> repeater.input") config.link(c, "repeater.output -> packet_filter.input") diff --git a/src/apps/pcap/pcap.lua b/src/apps/pcap/pcap.lua index 66b1a0fb4d..270f5bbb8f 100644 --- a/src/apps/pcap/pcap.lua +++ b/src/apps/pcap/pcap.lua @@ -20,10 +20,7 @@ function PcapReader:pull () while not self.done and not link.full(self.output.output) do local data, record, extra = self.iterator() if data then - local p = packet.allocate() - local b = buffer.allocate() - ffi.copy(b.pointer, data) - packet.add_iovec(p, b, string.len(data)) + local p = packet.from_string(data) link.transmit(self.output.output, p) else self.done = true @@ -43,13 +40,10 @@ function PcapWriter:push () while not link.empty(self.input.input) do local p = link.receive(self.input.input) pcap.write_record_header(self.file, p.length) - for i = 0, p.niovecs-1 do - local iov = p.iovecs[i] - -- XXX expensive to create interned Lua string. - self.file:write(ffi.string(iov.buffer.pointer + iov.offset, iov.length)) - end + -- XXX expensive to create interned Lua string. + self.file:write(ffi.string(p.data, p.length)) self.file:flush() - packet.deref(p) + packet.free(p) end end diff --git a/src/apps/rate_limiter/rate_limiter.lua b/src/apps/rate_limiter/rate_limiter.lua index 3ba7d06073..9811098df2 100644 --- a/src/apps/rate_limiter/rate_limiter.lua +++ b/src/apps/rate_limiter/rate_limiter.lua @@ -79,7 +79,7 @@ function RateLimiter:push () link.transmit(o, p) else -- discard packet - packet.deref(p) + packet.free(p) end end end @@ -93,7 +93,6 @@ end function selftest () print("Rate limiter selftest") - buffer.preallocate(10000) local c = config.new() config.app(c, "source", basic_apps.Source) diff --git a/src/core/freelist.lua b/src/core/freelist.lua index 56138f8925..5ba18ced8b 100644 --- a/src/core/freelist.lua +++ b/src/core/freelist.lua @@ -18,7 +18,7 @@ end function remove (freelist) if freelist.nfree == 0 then - return nil + error("no free packets") else freelist.nfree = freelist.nfree - 1 return freelist.list[freelist.nfree] diff --git a/src/core/link.lua b/src/core/link.lua index b686d8c939..1674124e2d 100644 --- a/src/core/link.lua +++ b/src/core/link.lua @@ -73,7 +73,6 @@ function selftest () print("selftest: link") local r = new() local p = packet.allocate() - packet.tenure(p) assert(r.stats.txpackets == 0 and empty(r) == true and full(r) == false) assert(nreadable(r) == 0) transmit(r, p) diff --git a/src/core/packet.lua b/src/core/packet.lua index 824985acd6..99d4cbe295 100644 --- a/src/core/packet.lua +++ b/src/core/packet.lua @@ -19,7 +19,7 @@ local header_size = 8 local max_payload = tonumber(C.PACKET_PAYLOAD_SIZE) -- Freelist containing empty packets ready for use. -local max_packets = 1024 +local max_packets = 10240 local packets_fl = freelist.new("struct packet *", max_packets) -- Return an empty packet. @@ -60,6 +60,13 @@ function prepend (p, ptr, len) return p end +-- Move packet data to the left. This shortens the packet by dropping +-- the header bytes at the front. +function shiftleft (p, bytes) + C.memmove(p.data, p.data+bytes, p.length-bytes) + p.length = p.length - bytes +end + -- Conveniently create a packet by copying some existing data. function from_pointer (ptr, len) return append(allocate(), ptr, len) end function from_string (d) return from_pointer(d, #d) end