diff --git a/src/README.md b/src/README.md index 56712a2e1d..283f64a27f 100644 --- a/src/README.md +++ b/src/README.md @@ -877,14 +877,14 @@ Returns a copy of *array*. *Array* must not be a "sparse array". — Function **lib.htons** *n* Host to network byte order conversion functions for 32 and 16 bit -integers *n* respectively. +integers *n* respectively. Unsigned. — Function **lib.ntohl** *n* — Function **lib.ntohs** *n* Network to host byte order conversion functions for 32 and 16 bit -integers *n* respectively. +integers *n* respectively. Unsigned. — Function **lib.parse** *arg*, *config* diff --git a/src/apps/basic/basic_apps.lua b/src/apps/basic/basic_apps.lua index 94eb669272..e98956331e 100644 --- a/src/apps/basic/basic_apps.lua +++ b/src/apps/basic/basic_apps.lua @@ -42,7 +42,7 @@ end function Join:push () for _, inport in ipairs(self.input) do while not link.empty(inport) do - transmit(self.output.out, receive(inport)) + transmit(self.output.output, receive(inport)) end end end diff --git a/src/apps/intel/intel10g.lua b/src/apps/intel/intel10g.lua index 1c60171d69..fd3c1d11a7 100644 --- a/src/apps/intel/intel10g.lua +++ b/src/apps/intel/intel10g.lua @@ -23,7 +23,18 @@ local timer = require("core.timer") local bits, bitset = lib.bits, lib.bitset local band, bor, lshift = bit.band, bit.bor, bit.lshift -num_descriptors = 1024 +local num_descriptors = 1024 +function ring_buffer_size (arg) + if not arg then return num_descriptors end + local ring_size = assert(tonumber(arg), "bad ring size: " .. arg) + if ring_size > 32*1024 then + error("ring size too large for hardware: " .. ring_size) + end + if math.log(ring_size)/math.log(2) % 1 ~= 0 then + error("ring size is not a power of two: " .. arg) + end + num_descriptors = assert(tonumber(arg)) +end -- Defaults for configurable items local default = { diff --git a/src/apps/intel/intel_app.lua b/src/apps/intel/intel_app.lua index 2c11a66542..5f4b8a63ff 100644 --- a/src/apps/intel/intel_app.lua +++ b/src/apps/intel/intel_app.lua @@ -388,14 +388,14 @@ function mq_sq(pcidevA, pcidevB) 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, 'source_ms.output -> repeater_ms.input') config.link(c, 'repeater_ms.output -> nicAs.input') config.link(c, 'nicAs.output -> sink_ms.in1') config.link(c, 'nicBm0.output -> sink_ms.in2') config.link(c, 'nicBm1.output -> sink_ms.in3') 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)) + link.transmit(engine.app_table.source_ms.output.output, packet.from_string(d1)) + link.transmit(engine.app_table.source_ms.output.output, packet.from_string(d2)) end -- one multiqueue driver with two apps and do switch stuff @@ -436,13 +436,13 @@ function mq_sw(pcidevA) print ("Send a bunch of packets from Am0") print ("half of them go to nicAm1 and half go nowhere") config.app(c, 'sink_ms', basic_apps.Sink) - config.link(c, 'source_ms.out -> repeater_ms.input') + config.link(c, 'source_ms.output -> repeater_ms.input') config.link(c, 'repeater_ms.output -> nicAm0.input') config.link(c, 'nicAm0.output -> sink_ms.in1') config.link(c, 'nicAm1.output -> sink_ms.in2') 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)) + link.transmit(engine.app_table.source_ms.output.output, packet.from_string(d1)) + link.transmit(engine.app_table.source_ms.output.output, packet.from_string(d2)) end function manyreconf(pcidevA, pcidevB, n, do_pf) @@ -488,14 +488,14 @@ function manyreconf(pcidevA, pcidevB, n, do_pf) vlan = 100+i, }) config.app(c, 'sink_ms', basic_apps.Sink) - config.link(c, 'source_ms.out -> repeater_ms.input') + config.link(c, 'source_ms.output -> repeater_ms.input') config.link(c, 'repeater_ms.output -> nicAm0.input') config.link(c, 'nicAm0.output -> sink_ms.in1') config.link(c, 'nicAm1.output -> sink_ms.in2') if do_pf then engine.configure(config.new()) end 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)) + link.transmit(engine.app_table.source_ms.output.output, packet.from_string(d1)) + link.transmit(engine.app_table.source_ms.output.output, packet.from_string(d2)) engine.main({duration = 0.1, no_report=true}) cycles = cycles + 1 redos = redos + engine.app_table.nicAm1.dev.pf.redos diff --git a/src/apps/intel/loadgen.lua b/src/apps/intel/loadgen.lua index dba5b6363c..874cf63fa7 100644 --- a/src/apps/intel/loadgen.lua +++ b/src/apps/intel/loadgen.lua @@ -31,7 +31,7 @@ function disable_tx_descriptor_writeback (dev) -- Disable writeback of transmit descriptors. -- That way our transmit descriptors stay fresh and reusable. -- Tell hardware write them to this other memory instead. - local bytes = intel10g.num_descriptors * ffi.sizeof(intel10g.rxdesc_t) + local bytes = intel10g.ring_buffer_size() * ffi.sizeof(intel10g.rxdesc_t) local ptr, phy = memory.dma_alloc(bytes) dev.r.TDWBAL(phy % 2^32) dev.r.TDWBAH(phy / 2^32) @@ -40,7 +40,7 @@ end function zero_descriptors (dev) -- Clear unused descriptors local b = memory.dma_alloc(4096) - for i = 0, intel10g.num_descriptors-1 do + for i = 0, intel10g.ring_buffer_size()-1 do -- Make each descriptors point to valid DMA memory but be 0 bytes long. dev.txdesc[i].address = memory.virtual_to_physical(b) dev.txdesc[i].options = bit.lshift(1, 24) -- End of Packet flag @@ -64,7 +64,7 @@ function LoadGen:pull () if dev.tdt == 0 then return end C.full_memory_barrier() if tdh == 0 then - dev.r.TDT(intel10g.num_descriptors) + dev.r.TDT(intel10g.ring_buffer_size()) else dev.r.TDT(tdh - 1) end diff --git a/src/apps/socket/raw.lua b/src/apps/socket/raw.lua index 30e8c66897..dfbc4d4471 100644 --- a/src/apps/socket/raw.lua +++ b/src/apps/socket/raw.lua @@ -12,13 +12,6 @@ local ethernet = require("lib.protocol.ethernet") local ffi = require("ffi") local C = ffi.C ---ljsyscall returns error as a a cdata instead of a string, ---and the standard assert() doesn't use tostring() on it. -local function assert(v, ...) - if not v then error(tostring(... or 'assertion failed'), 2) end - return v, ... -end - local c, t = S.c, S.types.t RawSocket = {} diff --git a/src/apps/socket/unix.lua b/src/apps/socket/unix.lua index 7bb416c479..8cfc072360 100644 --- a/src/apps/socket/unix.lua +++ b/src/apps/socket/unix.lua @@ -9,13 +9,6 @@ local link = require("core.link") local packet = require("core.packet") local S = require("syscall") ---ljsyscall returns error as a a cdata instead of a string, ---and the standard assert() doesn't use tostring() on it. -local function assert(v, ...) - if not v then error(tostring(... or 'assertion failed'), 2) end - return v, ... -end - UnixSocket = {} UnixSocket.__index = UnixSocket diff --git a/src/apps/tap/tap.lua b/src/apps/tap/tap.lua index c1bd5fdd8c..884393f241 100644 --- a/src/apps/tap/tap.lua +++ b/src/apps/tap/tap.lua @@ -40,35 +40,34 @@ function Tap:new (name) sock:close() error("Error opening /dev/net/tun: " .. tostring(err)) end - return setmetatable({sock = sock, name = name}, {__index = Tap}) + return setmetatable({sock = sock, name = name, pkt = packet.allocate()}, + {__index = Tap}) end function Tap:pull () local l = self.output.output if l == nil then return end for i=1,engine.pull_npackets do - local p = packet.allocate() - local len, err = S.read(self.sock, p.data, C.PACKET_PAYLOAD_SIZE) + local len, err = S.read(self.sock, self.pkt.data, C.PACKET_PAYLOAD_SIZE) -- errno == EAGAIN indicates that the read would of blocked as there is no -- packet waiting. It is not a failure. if not len and err.errno == const.E.AGAIN then - packet.free(p) return end if not len then - packet.free(p) error("Failed read on " .. self.name .. ": " .. tostring(err)) end - p.length = len - link.transmit(l, p) + self.pkt.length = len + link.transmit(l, self.pkt) counter.add(self.shm.input_bytes, len) counter.add(self.shm.input_packets) - if ethernet:is_mcast(p.data) then + if ethernet:is_mcast(self.pkt.data) then counter.add(self.shm.input_mcast) end - if ethernet:is_bcast(p.data) then + if ethernet:is_bcast(self.pkt.data) then counter.add(self.shm.input_bcast) end + self.pkt = packet.allocate() end end diff --git a/src/apps/test/match.lua b/src/apps/test/match.lua index dee1aacff9..7517d0d342 100644 --- a/src/apps/test/match.lua +++ b/src/apps/test/match.lua @@ -91,7 +91,7 @@ function selftest() config.app(c, "join", basic_apps.Join) config.link(c, "src.output -> join.src") config.link(c, "garbage.output -> join.garbage") - config.link(c, "join.out -> sink.input") + config.link(c, "join.output -> sink.input") engine.configure(c) engine.main({duration=0.0001}) assert(#engine.app_table.sink:errors() == 0) diff --git a/src/apps/vlan/vlan.lua b/src/apps/vlan/vlan.lua index 056056ecec..64434b389c 100644 --- a/src/apps/vlan/vlan.lua +++ b/src/apps/vlan/vlan.lua @@ -147,6 +147,29 @@ function VlanMux:transmit(o, pkt) end end +function test_tag_untag () + local pkt = packet.from_string(lib.hexundump([[ + 02:aa:aa:aa:aa:aa 02:99:99:99:99:99 08 00 45 00 + 00 54 43 58 40 00 40 01 7c 5c c0 a8 0d 28 ac 14 + 01 10 08 00 9c d4 07 c0 00 01 bc fa e3 57 00 00 + 00 00 f3 44 01 00 00 00 00 00 10 11 12 13 14 15 + 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 + 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 34 35 + 36 37 + ]], 82)) + local payload = pkt.data + o_ethernet_ethertype + local vid = 0 + for i=0,15 do + for j=0,255 do + local tag = build_tag(vid) + push_tag(pkt, tag) + assert(cast(uint32_ptr_t, payload)[0] == tag) + vid = vid + 1 + end + end + assert(vid == 4096) + print("Sucessfully tagged/untagged all potential VLAN tags (0-4095)") +end function selftest() local app = require("core.app") @@ -164,4 +187,6 @@ function selftest() print("source sent: " .. link.stats(app.app_table.source.output.output).input_packets) print("sink received: " .. link.stats(app.app_table.sink.input.input).output_packets) + + test_tag_untag() end diff --git a/src/core/lib.lua b/src/core/lib.lua index a86206a257..68f782a3dd 100644 --- a/src/core/lib.lua +++ b/src/core/lib.lua @@ -10,6 +10,8 @@ require("core.clib_h") local bit = require("bit") local band, bor, bnot, lshift, rshift, bswap = bit.band, bit.bor, bit.bnot, bit.lshift, bit.rshift, bit.bswap +local tonumber = tonumber -- Yes, this makes a performance difference. +local cast = ffi.cast -- Returns true if x and y are structurally similar (isomorphic). function equal (x, y) @@ -373,7 +375,8 @@ if ffi.abi("be") then function htonl(b) return b end function htons(b) return b end else - function htonl(b) return bswap(b) end + -- htonl is unsigned, matching the C version and expectations. + function htonl(b) return tonumber(cast('uint32_t', bswap(b))) end function htons(b) return rshift(bswap(b), 16) end end ntohl = htonl @@ -760,7 +763,12 @@ function selftest () assert(hexdump('\x45\x00\xb6\x7d\x00\xFA\x40\x00\x40\x11'):upper() :match('^45.00.B6.7D.00.FA.40.00.40.11$'), "wrong hex dump") assert(hexundump('4500 B67D 00FA400040 11', 10) - =='\x45\x00\xb6\x7d\x00\xFA\x40\x00\x40\x11', "wrong hex undump") + =='\x45\x00\xb6\x7d\x00\xFA\x40\x00\x40\x11', "wrong hex undump") + print("Testing ntohl") + local raw_val = 0xf0d0b0f0 + assert(ntohl(raw_val) > 0, "ntohl must be unsigned") + assert(ntohl(ntohl(raw_val)) == raw_val, + "calling ntohl twice must return the original value") -- test parse print("Testing parse") diff --git a/src/core/main.lua b/src/core/main.lua index 5930142313..611f167152 100644 --- a/src/core/main.lua +++ b/src/core/main.lua @@ -19,6 +19,13 @@ local S = require("syscall") require("lib.lua.strict") require("lib.lua.class") +-- ljsyscall returns error as a cdata instead of a string, and the standard +-- assert doesn't use tostring on it. +_G.assert = function (v, ...) + if v then return v, ... end + error(tostring(... or "assertion failed!")) +end + -- Reserve names that we want to use for global module. -- (This way we avoid errors from the 'strict' module.) _G.config, _G.engine, _G.memory, _G.link, _G.packet, _G.timer, @@ -164,7 +171,7 @@ function selftest () end -- Fork into worker process and supervisor -local worker_pid = S.fork() +local worker_pid = assert(S.fork()) if worker_pid == 0 then -- Worker: Use prctl to ensure we are killed (SIGHUP) when our parent quits -- and run main. @@ -179,16 +186,14 @@ else while true do -- Read signals from signalfd. Only process the first signal because any -- signal causes shutdown. - local signals, err = S.util.signalfd_read(signalfd) - assert(signals, tostring(err)) + local signals = assert(S.util.signalfd_read(signalfd)) for i = 1, #signals do local exit_status if signals[i].chld then -- SIGCHILD means worker state changed: retrieve its status using -- waitpid and set exit status accordingly. - local status, err, worker = - S.waitpid(worker_pid, "stopped,continued") - assert(status, tostring(err)) + local status, _, worker = + assert(S.waitpid(worker_pid, "stopped,continued")) if worker.WIFEXITED then exit_status = worker.EXITSTATUS elseif worker.WIFSIGNALED then exit_status = 128 + worker.WTERMSIG -- WIFSTOPPED and WIFCONTINUED are ignored. diff --git a/src/core/memory.lua b/src/core/memory.lua index ecfba556e1..30f8cc49e9 100644 --- a/src/core/memory.lua +++ b/src/core/memory.lua @@ -57,8 +57,7 @@ end --- ### HugeTLB: Allocate contiguous memory in bulk from Linux function allocate_hugetlb_chunk () - local fd, err = syscall.open("/proc/sys/vm/nr_hugepages","rdonly") - assert(fd, tostring(err)) + local fd = assert(syscall.open("/proc/sys/vm/nr_hugepages","rdonly")) fd:flock("ex") for i =1, 3 do local page = C.allocate_huge_page(huge_page_size) diff --git a/src/doc/default.nix b/src/doc/default.nix index 673d319931..216ab49790 100644 --- a/src/doc/default.nix +++ b/src/doc/default.nix @@ -13,8 +13,8 @@ stdenv.mkDerivation rec { buildInputs = [ ditaa pandoc git (texlive.combine { - inherit (texlive) scheme-small luatex luatexbase sectsty titlesec cprotect bigfoot titling droid; - }) + inherit (texlive) scheme-small luatex luatexbase sectsty titlesec cprotect bigfoot titling droid collection-luatex; + }) ]; patchPhase = '' diff --git a/src/lib/hardware/pci.lua b/src/lib/hardware/pci.lua index de34a4d5d7..3c3fdf0c09 100644 --- a/src/lib/hardware/pci.lua +++ b/src/lib/hardware/pci.lua @@ -142,15 +142,12 @@ function map_pci_memory (device, n, lock) if lock then assert(f:flock("ex, nb"), "failed to lock " .. filepath) end - local st, err = f:stat() - assert(st, tostring(err)) - local mem, err = f:mmap(nil, st.size, "read, write", "shared", 0) - assert(mem, tostring(err)) + local st = assert(f:stat()) + local mem = assert(f:mmap(nil, st.size, "read, write", "shared", 0)) return ffi.cast("uint32_t *", mem), f end function close_pci_resource (fd, base) - local st, err = fd:stat() - assert(st, tostring(err)) + local st = assert(fd:stat()) S.munmap(base, st.size) fd:close() end @@ -159,8 +156,7 @@ end --- mastering is enabled. function set_bus_master (device, enable) root_check() - local f,err = S.open(path(device).."/config", "rdwr") - assert(f, tostring(err)) + local f = assert(S.open(path(device).."/config", "rdwr")) local fd = f:getfd() local value = ffi.new("uint16_t[1]") diff --git a/src/program/firehose/firehose.lua b/src/program/firehose/firehose.lua index 0354f1a0ec..6ee05d8e6a 100644 --- a/src/program/firehose/firehose.lua +++ b/src/program/firehose/firehose.lua @@ -39,13 +39,6 @@ function run (args) end function opt.r (arg) ring_size = tonumber(arg) - if type(ring_size) ~= 'number' then fatal("bad ring size: " .. arg) end - if ring_size > 32*1024 then - fatal("ring size too large for hardware: " .. ring_size) - end - if math.log(ring_size)/math.log(2) % 1 ~= 0 then - fatal("ring size is not a power of two: " .. arg) - end end args = lib.dogetopt(args, opt, "hHet:i:r:", long_opts) if #pciaddresses == 0 then @@ -79,7 +72,7 @@ int firehose_callback_v1(const char *pciaddr, char **packets, void *rxring, local intel10g = require("apps.intel.intel10g") -- Maximum buffers to avoid packet drops - intel10g.num_descriptors = ring_size + intel10g.ring_buffer_size(ring_size) local nic = intel10g.new_sf({pciaddr=pciaddr}) nic:open() diff --git a/src/program/lisper/lisper.lua b/src/program/lisper/lisper.lua index 2b0a5b93b3..953ffef0d7 100644 --- a/src/program/lisper/lisper.lua +++ b/src/program/lisper/lisper.lua @@ -28,11 +28,6 @@ local ntohl = lib.ntohl local getenv = lib.getenv local hexdump = lib.hexdump -local function assert(v, ...) --assert overload because - if v then return v, ... end - error(tostring((...) or "Assertion failed"), 2) -end - local function parsehex(s) return (s:gsub("[0-9a-fA-F][0-9a-fA-F]", function(cc) return string.char(tonumber(cc, 16)) diff --git a/src/program/packetblaster/packetblaster.lua b/src/program/packetblaster/packetblaster.lua index 4b1c11b77f..ec78197c27 100644 --- a/src/program/packetblaster/packetblaster.lua +++ b/src/program/packetblaster/packetblaster.lua @@ -4,10 +4,10 @@ module(..., package.seeall) local engine = require("core.app") local timer = require("core.timer") -local intel10g = require("apps.intel.intel10g") local lib = require("core.lib") local pci = require("lib.hardware.pci") local LoadGen = require("apps.intel.loadgen").LoadGen +local Intel82599 = require("apps.intel.intel_app").Intel82599 local function is_device_suitable (pcidev, patterns) if not pcidev.usable or pcidev.driver ~= 'apps.intel.intel_app' then @@ -23,40 +23,55 @@ local function is_device_suitable (pcidev, patterns) end end -function run_loadgen (c, patterns, duration) - local nics = 0 - pci.scan_devices() - for _,device in ipairs(pci.devices) do - if is_device_suitable(device, patterns) then - nics = nics + 1 - local name = "nic"..nics - config.app(c, name, LoadGen, device.pciaddress) - config.link(c, "source."..tostring(nics).."->"..name..".input") - end - end - assert(nics > 0, " matches no suitable devices.") - engine.busywait = true - engine.configure(c) - local fn = function () - print("Transmissions (last 1 sec):") - engine.report_apps() - end - local t = timer.new("report", fn, 1e9, 'repeating') - timer.activate(t) - if duration then engine.main({duration=duration}) - else engine.main() end +function run_loadgen (c, patterns, opts) + assert(type(opts) == "table") + local use_loadgen = opts.loop == nil or opts.loop + local nics = 0 + pci.scan_devices() + for _,device in ipairs(pci.devices) do + if is_device_suitable(device, patterns) then + nics = nics + 1 + local name = "nic"..nics + if use_loadgen then + config.app(c, name, LoadGen, device.pciaddress) + config.link(c, "source."..tostring(nics).."->"..name..".input") + else + config.app(c, name, Intel82599, {pciaddr = device.pciaddress}) + config.link(c, "source."..tostring(nics).."->"..name..".output") + end + end + end + assert(nics > 0, " matches no suitable devices.") + engine.busywait = true + engine.configure(c) + + local report = {} + if use_loadgen then + local fn = function () + print("Transmissions (last 1 sec):") + engine.report_apps() + end + local t = timer.new("report", fn, 1e9, 'repeating') + timer.activate(t) + else + report = {showlinks = true} + end + + if opts.duration then engine.main({duration=opts.duration, report=report}) + else engine.main() end end + local function show_usage(exit_code) - print(require("program.packetblaster.README_inc")) - main.exit(exit_code) + print(require("program.packetblaster.README_inc")) + main.exit(exit_code) end function run(args) - if #args == 0 then show_usage(1) end - local command = string.gsub(table.remove(args, 1), "-", "_") - local modname = ("program.packetblaster.%s.%s"):format(command, command) - if not lib.have_module(modname) then - show_usage(1) - end - require(modname).run(args) + if #args == 0 then show_usage(1) end + local command = string.gsub(table.remove(args, 1), "-", "_") + local modname = ("program.packetblaster.%s.%s"):format(command, command) + if not lib.have_module(modname) then + show_usage(1) + end + require(modname).run(args) end diff --git a/src/program/packetblaster/replay/README b/src/program/packetblaster/replay/README index 4bc2a3fe40..64d64da1a2 100644 --- a/src/program/packetblaster/replay/README +++ b/src/program/packetblaster/replay/README @@ -2,7 +2,9 @@ Usage: packetblaster replay [OPTIONS] ... -D DURATION, --duration DURATION Run for DURATION seconds. - Default: unlimited + Default: unlimited + --no-loop Do not loop through . + Duration is one second if not set. -h, --help Print usage information. diff --git a/src/program/packetblaster/replay/replay.lua b/src/program/packetblaster/replay/replay.lua index 53f7715e3b..150e654152 100644 --- a/src/program/packetblaster/replay/replay.lua +++ b/src/program/packetblaster/replay/replay.lua @@ -9,32 +9,45 @@ local PcapReader = require("apps.pcap.pcap").PcapReader local lib = require("core.lib") local packetblaster = require("program.packetblaster.packetblaster") -local usage = require("program.packetblaster.replay.README_inc") local long_opts = { duration = "D", - help = "h" + help = "h", + ["no-loop"] = 0, } +local function show_usage (code) + print(require("program.packetblaster.replay.README_inc")) + main.exit(code) +end + function run (args) - local opt = {} - local duration local c = config.new() - function opt.D (arg) - duration = assert(tonumber(arg), "duration is not a number!") + local handlers = {} + local opts = { loop = true } + function handlers.D (arg) + opts.duration = assert(tonumber(arg), "duration is not a number!") end - function opt.h (arg) - print(usage) - main.exit(1) + function handlers.h () + show_usage(0) + end + handlers["no-loop"] = function () + opts.loop = false end - args = lib.dogetopt(args, opt, "hD:", long_opts) + args = lib.dogetopt(args, handlers, "hD:", long_opts) + if #args < 2 then show_usage(1) end local filename = table.remove(args, 1) print (string.format("filename=%s", filename)) config.app(c, "pcap", PcapReader, filename) - config.app(c, "loop", basic_apps.Repeater) config.app(c, "source", basic_apps.Tee) - config.link(c, "pcap.output -> loop.input") - config.link(c, "loop.output -> source.input") - packetblaster.run_loadgen(c, args, duration) + if opts.loop then + config.app(c, "loop", basic_apps.Repeater) + config.link(c, "pcap.output -> loop.input") + config.link(c, "loop.output -> source.input") + else + config.link(c, "pcap.output -> source.input") + if not opts.duration then opts.duration = 1 end + end + packetblaster.run_loadgen(c, args, opts) end diff --git a/src/program/packetblaster/synth/README b/src/program/packetblaster/synth/README index 77630edd71..7109fc09b4 100644 --- a/src/program/packetblaster/synth/README +++ b/src/program/packetblaster/synth/README @@ -2,17 +2,17 @@ Usage: packetblaster synth [OPTIONS] ... -s SOURCE, --src SOURCE Source MAC-Address. - Default: 00:00:00:00:00:00 + Default: 00:00:00:00:00:00 -d DESTINATION, --dst DESTINATION Destination MAC-Address. - Default: 00:00:00:00:00:00 + Default: 00:00:00:00:00:00 -S SIZES, --sizes SIZES A comma separated list of numbers. Send packets of SIZES bytes. Default: 64 -D DURATION, --duration DURATION Run for DURATION seconds. - Default: unlimited + Default: unlimited -h, --help Print usage information. diff --git a/src/program/packetblaster/synth/synth.lua b/src/program/packetblaster/synth/synth.lua index d657d5b654..e820c8ce49 100644 --- a/src/program/packetblaster/synth/synth.lua +++ b/src/program/packetblaster/synth/synth.lua @@ -8,42 +8,45 @@ local Synth = require("apps.test.synth").Synth local lib = require("core.lib") local packetblaster = require("program.packetblaster.packetblaster") -local usage = require("program.packetblaster.synth.README_inc") local long_opts = { duration = "D", help = "h", src = "s", dst = "d", - sizes = "S" + sizes = "S", } +local function show_usage (code) + print(require("program.packetblaster.synth.README_inc")) + main.exit(code) +end + function run (args) - local opt = {} - local duration local c = config.new() - function opt.D (arg) - duration = assert(tonumber(arg), "duration is not a number!") + local handlers = {} + local opts = {} + function handlers.D (arg) + opts.duration = assert(tonumber(arg), "duration is not a number!") end - function opt.h (arg) - print(usage) - main.exit(1) + function handlers.h () + show_usage(0) end local source local destination local sizes - function opt.s (arg) source = arg end - function opt.d (arg) destination = arg end - function opt.S (arg) - sizes = {} - for size in string.gmatch(arg, "%d+") do - sizes[#sizes+1] = tonumber(size) - end + function handlers.s (arg) source = arg end + function handlers.d (arg) destination = arg end + function handlers.S (arg) + sizes = {} + for size in string.gmatch(arg, "%d+") do + sizes[#sizes+1] = tonumber(size) + end end - args = lib.dogetopt(args, opt, "hD:s:d:S:", long_opts) + args = lib.dogetopt(args, handlers, "hD:s:d:S:", long_opts) config.app(c, "source", Synth, { sizes = sizes, - src = source, dst = destination }) - packetblaster.run_loadgen(c, args, duration) + src = source, dst = destination }) + packetblaster.run_loadgen(c, args, opts) end