Skip to content

Commit

Permalink
Add replay-pcap-multi.lua to examples/pcap
Browse files Browse the repository at this point in the history
  • Loading branch information
qha committed Jun 9, 2022
1 parent 7746ff2 commit 9488d3e
Showing 1 changed file with 205 additions and 0 deletions.
205 changes: 205 additions & 0 deletions examples/pcap/replay-pcap-multi.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
--- Replay pcap files on multiple interfaces.
--
-- Please note that if your storage system bandwidth does not match or
-- exceed the combined bandwidth of the interfaces you want to replay
-- packets on make sure that your pcaps fit in memory.
--
-- Also note that you will want pcaps captured on named interfaces so
-- that they contain link layer headers rather than pcaps captured on
-- "any" interface with cooked link layer headers.
--
-- Optionally rewrite high port numbers (src or dst) in tcp/ip4
-- packets on retransmissions to keep exercising the connection
-- tracking in an ids under test.

local table = require "table"

local mg = require "moongen"
local device = require "device"
local memory = require "memory"
local stats = require "stats"
local log = require "log"
local pcap = require "pcap"
local limiter = require "software-ratecontrol"

local ip4 = require "proto.ip4"

function configure(parser)
parser:option("--dev", "Device to use.")
:args(1)
:count("1+")
:convert(tonumber)
:target("devs")
parser:argument("file", "File to replay, must be supplied"
.. " as many times as --dev.")
:args("1+")
:target("files")
parser:option("-r --rate-multiplier",
"Speed up or slow down replay,"
.. " 1 = use intervals from files,"
.. " default = replay as fast as possible.")
:default(0)
:convert(tonumber)
:target("rateMultiplier")
parser:option("-s --buffer-flush-time",
"Time to wait before stopping Moongen after enqueuing"
.. " all packets. Increase for pcaps with a very low"
.. " rate.")
:default(10)
:convert(tonumber)
:target("bufferFlushTime")
parser:flag("-l --loop", "Repeat pcap files until interrupted.")
parser:option("-i --iterations",
"Send pcap files this number of times")
:default(1)
:convert(tonumber)
parser:flag("-f --rewrite-high-port",
"Increment high port (src or dst) in tcp/ip4 packets "
.. " on repeated transmissions")
:target("rewritehighport")
local args = parser:parse()
if #args.devs ~= #args.files then
parser:error("Must name as many devs as files")
end
return args
end

function master(args)
local devs = {}
for ii, dev in ipairs(args.devs) do
table.insert(devs, device.config({port = dev}))
end
device.waitForLinks()
local rateLimiters = {}
if args.rateMultiplier > 0 then
for ii, dev in ipairs(devs) do
table.insert(rateLimiters, limiter:new(dev:getTxQueue(0), "custom"))
end
end
local replayers = {}
for ii, dev in ipairs(devs) do
table.insert(replayers,
mg.startTask("replay",
dev:getTxQueue(0),
args.files[ii],
args.loop,
args.iterations,
args.rewritehighport,
rateLimiters[ii],
args.rateMultiplier,
args.bufferFlushTime))
stats.startStatsTask{txDevices = {dev}}
end
for ii, replayer in ipairs(replayers) do
replayer:wait()
end
mg:stop()
mg.waitForTasks()
end

function replay(queue,
file,
loop,
iterations,
rewritehighport,
rateLimiter,
multiplier,
sleepTime)
local mempool = memory:createMemPool(4096)
local bufs = mempool:bufArray()
local pcapFile = pcap:newReader(file)
local linkSpeed = queue.dev:getLinkStatus().speed
local transmission = 0
log:info("Replaying %s on %s", file, queue.dev)
log:info("Link speed %s for %s", linkSpeed, queue.dev)

while mg.running() do
replayonce(queue, file, rewritehighport, rateLimiter, multiplier,
bufs, pcapFile, linkSpeed, transmission)

transmission = transmission + 1
if loop then
pcapFile:reset()
log:info("%s exhausted, starting %d transmission on %s",
file, transmission + 1, queue.dev)
elseif transmission < iterations then
pcapFile:reset()
log:info("%s exhausted, starting %d (of %d transmissions) on %s",
file, transmission + 1, iterations, queue.dev)
else
break
end
end

log:info("Replay on %s: Enqueued all packets,"
.. " waiting %d seconds for queues to flush",
queue.dev,
sleepTime)
mg.sleepMillisIdle(sleepTime * 1000)
pcapFile:close()
end



function replayonce(queue,
file,
rewritehighport,
rateLimiter,
multiplier,
bufs,
pcapFile,
linkSpeed,
transmission)
local uint16max = 0xffff
local prev = 0

while mg.running() do
local n = pcapFile:read(bufs)

if n > 0 then
-- Rewrite ephemeral port.
if rewritehighport and transmission > 0 then
for i = 1, n do
local buf = bufs[i]
local pkt = buf:getTcp4Packet()
if pkt.ip4:getProtocol() == ip4.PROTO_TCP then
if pkt.tcp:getSrcPort() < pkt.tcp:getDstPort() then
pkt.tcp:setDstPort((pkt.tcp:getDstPort() + transmission)
% uint16max)
elseif pkt.tcp:getDstPort() < pkt.tcp:getSrcPort() then
pkt.tcp:setSrcPort((pkt.tcp:getSrcPort() + transmission)
% uint16max)
end
end
buf:offloadTcpChecksum()
end
end

if rateLimiter ~= nil then
if prev == 0 then
prev = bufs.array[0].udata64
end
for i = 1, n do
local buf = bufs[i]
-- ts is in microseconds
local ts = buf.udata64
if prev > ts then
ts = prev
end
local delay = ts - prev
delay = tonumber(delay * 10^3) / multiplier -- nanoseconds
delay = delay / (8000 / linkSpeed) -- delay in bytes
buf:setDelay(delay)
prev = ts
end
end
else
break
end
if rateLimiter then
rateLimiter:sendN(bufs, n)
else
queue:sendN(bufs, n)
end
end
end

0 comments on commit 9488d3e

Please sign in to comment.