From 855a6dc522d92ad530b05c1608bba4a9c4a5d700 Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Tue, 20 Jan 2015 17:59:12 +0100 Subject: [PATCH 01/14] core.link: Fix selftest() for new packet API --- src/core/link.lua | 1 - 1 file changed, 1 deletion(-) 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) From 57180d740e3883c15bb0551a67d742552aaa527a Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Tue, 20 Jan 2015 18:05:22 +0100 Subject: [PATCH 02/14] ipv6.lua: Removed this old example This is obsolete. We already decided to exclude it from the manual, and the selftest fails with the new packet API. --- src/apps/ipv6/ipv6.lua | 215 ------------------------------ src/apps/ipv6/selftest.cap.expect | Bin 4286 -> 0 bytes src/apps/ipv6/selftest.cap.input | Bin 4014 -> 0 bytes 3 files changed, 215 deletions(-) delete mode 100644 src/apps/ipv6/ipv6.lua delete mode 100644 src/apps/ipv6/selftest.cap.expect delete mode 100644 src/apps/ipv6/selftest.cap.input 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 68531bbae96af76b76ffd1b97c17c39b4d335870..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4286 zcmca|c+)~A1{MYw`2U}Qff2?5(p^yeOyEkSp>I$KgOEvh+ua0^iV&;+3``&f95DWC zfUutkT>1YGsGgajGzBD*03uWvFy#NE>KC(OU+1>aajgYE(-vek^mwsNO4(6KTrn~hRd*tA-UEMs0oCzxK;wwwLpa^po5`&8CU={ zyx_brpd<)mFGy?Lc{o#HF;r7Z&&~N4syC6lpsr$ux$55qR9A%o!wZBVF$f`{eJ`S8qy=asI7V1twkY35wPhe; mgs`iq;dhRIP`|Stfu_cpF9+W5gk6Q|ca%Oi6?=2T!4?48^hALG diff --git a/src/apps/ipv6/selftest.cap.input b/src/apps/ipv6/selftest.cap.input deleted file mode 100644 index 0c5020ce9550faced304ee33879b533cc752af85..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4014 zcmc&%X-ia57=F*aBedW$meZ74Q<_<6rDNOJ2T6!BDiASR2qA(93F^ayCLy*M5n?SIrEW)Bb)Q7~7nVxqR$9rd-xpEzP;auk2bKmEA-sPNo$MNKT zyF>=^naf2aFgbqsNMV_MCT+oQ9#$(Z($_f0o~#|`-j`rPaWA_J);!eqc?qbTG=P(2mj zRORfs}NLC!7L?w;h0tHe0!purxV@ox$-%w25K^LqREa$9zoRP z*@OyRQq4sr)onJGkzh1tNd_WYoH2gR+yv7+^ZW&gNy!TrSr#uzNnM(@EPeTkl^L0< zRt;%W46JMo&ss@j?3^%_^n@sqY5e{ zMq?ENzow?58Gb`!`c;hCp+aUfR&fW2Y+7^C0zY$`=hU3^?ZMDP?38B#*-u% zjc<;&dX}`RXocVK75yqk-$I4NXv}{Xh-_L_w85|Gs(uv(Z=gbEG-f{lL^iD|+TmB! zD~H}Af$y?_itO()R*+ycX3qyAn^qMa@azAhU&Tl{R7i}*>^(qa)2gBqe$6BLRoKd) zLS{5(KL|uNttuYE?^ Date: Tue, 20 Jan 2015 18:19:15 +0100 Subject: [PATCH 03/14] apps.pcap: Updated to new packet API --- src/apps/pcap/pcap.lua | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) 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 From ec92fb1c9c80226c3ba7a65631b098c75b7d0702 Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Tue, 20 Jan 2015 18:19:24 +0100 Subject: [PATCH 04/14] apps.packet_filter: Updated to new packet API --- src/apps/packet_filter/packet_filter.lua | 9 ++------- src/apps/packet_filter/packet_filter_benchmark.lua | 2 -- 2 files changed, 2 insertions(+), 9 deletions(-) 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..c8217d80f2 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 = { { From 20a9915d0b980820aa16f396816ad98d1b6f64e9 Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Tue, 20 Jan 2015 18:22:51 +0100 Subject: [PATCH 05/14] apps.fuzz: Removed - obsoleted by new packet API This fuzz tester is not needed with the new packet API. The main design intention has been to exercise edge cases in the older more complex design. (Too bad that we never really used it.) --- src/apps/fuzz/ethernet.lua | 55 ------------- src/apps/fuzz/fuzz.lua | 88 -------------------- src/apps/fuzz/generator.lua | 124 ----------------------------- src/apps/fuzz/ipv4.lua | 88 -------------------- src/apps/fuzz/ipv6.lua | 82 ------------------- src/apps/fuzz/matcher.lua | 119 --------------------------- src/apps/fuzz/tcp.lua | 155 ------------------------------------ src/apps/fuzz/udp.lua | 137 ------------------------------- 8 files changed, 848 deletions(-) delete mode 100644 src/apps/fuzz/ethernet.lua delete mode 100644 src/apps/fuzz/fuzz.lua delete mode 100644 src/apps/fuzz/generator.lua delete mode 100644 src/apps/fuzz/ipv4.lua delete mode 100644 src/apps/fuzz/ipv6.lua delete mode 100644 src/apps/fuzz/matcher.lua delete mode 100644 src/apps/fuzz/tcp.lua delete mode 100644 src/apps/fuzz/udp.lua 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 From 1e5fd549dcc3d1c9d14c5bcd884d125a0a315961 Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Wed, 21 Jan 2015 06:22:54 +0100 Subject: [PATCH 06/14] Added packet.shiftleft(p, bytes) This shortens the packet by dropping the header bytes at the front. Useful to strip away encapsulation headers, for example. --- src/core/packet.lua | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/core/packet.lua b/src/core/packet.lua index 824985acd6..e98e745c6d 100644 --- a/src/core/packet.lua +++ b/src/core/packet.lua @@ -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 From d18a43fc8cbdfbc3fd0c2e2d300ebf31e114b87d Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Wed, 21 Jan 2015 04:47:05 +0100 Subject: [PATCH 07/14] apps.keyed_ipv6_tunnel: Updated to new packet API --- src/apps/keyed_ipv6_tunnel/tunnel.lua | 52 +++++++-------------------- 1 file changed, 12 insertions(+), 40 deletions(-) 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) From 3f8205c528d0f77268768b5b3b958a4ca1f275ac Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Wed, 21 Jan 2015 04:48:44 +0100 Subject: [PATCH 08/14] apps.rate_limiter: Updated to new packet API --- src/apps/rate_limiter/rate_limiter.lua | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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) From bc04a1142deaa3320f05156c73d8daedf0a71d21 Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Wed, 21 Jan 2015 05:53:45 +0100 Subject: [PATCH 09/14] intel10g: Keep RXLNGTHERREN disabled That feature will automatically drop packets that seem to be the wrong length. This complicates testing when we would quite like to be able to send garbage packets. There is no obvious benefit for us. basic_apps.Source also simplified to skip setting an IP protocol. That was only a workaround to prevent his feature from dropping packets. --- src/apps/basic/basic_apps.lua | 2 -- src/apps/intel/intel10g.lua | 1 - 2 files changed, 3 deletions(-) diff --git a/src/apps/basic/basic_apps.lua b/src/apps/basic/basic_apps.lua index 50b8d5ebbc..a17805c09b 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 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() From d2ef558b98ba6adf89489c0aac702cdf3e47bab6 Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Wed, 21 Jan 2015 06:10:07 +0100 Subject: [PATCH 10/14] basic_apps: Remove Buzz app This is currently neither used nor useful. --- src/apps/README.md.src | 14 -------------- src/apps/basic/basic_apps.lua | 12 ------------ 2 files changed, 26 deletions(-) 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 a17805c09b..6c54092064 100644 --- a/src/apps/basic/basic_apps.lua +++ b/src/apps/basic/basic_apps.lua @@ -217,15 +217,3 @@ do 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 - - From 84e177e1c874903659d5e35063a10530fd0a6996 Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Wed, 21 Jan 2015 06:13:25 +0100 Subject: [PATCH 11/14] packet: Increase max_packets (1024 -> 10240), error on exhaustion The intel driver is greedy for packets to populate its receive buffers. Even 10240 is too little, really, but sufficient for intel_app selftest. --- src/core/freelist.lua | 2 +- src/core/packet.lua | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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/packet.lua b/src/core/packet.lua index e98e745c6d..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. From 5a5d549124569b497480471b524d50eb707ba705 Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Wed, 21 Jan 2015 06:18:12 +0100 Subject: [PATCH 12/14] packet_filter_benchmark: Use normal Sink and Repeater Had used a special FastRepeater and FastSink. I prefer to remove those to simplify the code. --- src/apps/packet_filter/packet_filter_benchmark.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/apps/packet_filter/packet_filter_benchmark.lua b/src/apps/packet_filter/packet_filter_benchmark.lua index c8217d80f2..4c1a32fc61 100644 --- a/src/apps/packet_filter/packet_filter_benchmark.lua +++ b/src/apps/packet_filter/packet_filter_benchmark.lua @@ -37,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") From b27ae3e56448a62096685713d6a2916bd5aa2d03 Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Wed, 21 Jan 2015 06:19:16 +0100 Subject: [PATCH 13/14] basic_apps: Completed update to new packet API --- src/apps/basic/basic_apps.lua | 75 ++++------------------------------- 1 file changed, 8 insertions(+), 67 deletions(-) diff --git a/src/apps/basic/basic_apps.lua b/src/apps/basic/basic_apps.lua index 6c54092064..86083b09cd 100644 --- a/src/apps/basic/basic_apps.lua +++ b/src/apps/basic/basic_apps.lua @@ -37,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}) @@ -98,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}) @@ -139,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 @@ -160,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 @@ -173,47 +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 From 5807cb63b329cbd395176c417487debb17497fc7 Mon Sep 17 00:00:00 2001 From: Luke Gorrie Date: Wed, 21 Jan 2015 06:35:29 +0100 Subject: [PATCH 14/14] intel_app: Restore selftest function Now tests the same functionality as the selftest on master. Revised printouts with some more information and some grammar improvements. Tightened the success criteria for the mq_sw test case. If this causes false-negative test results then we may need to relax it again. --- src/apps/intel/intel_app.lua | 39 +++++++++++++----------------------- 1 file changed, 14 insertions(+), 25 deletions(-) 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