Skip to content

Commit

Permalink
Merge pull request #1201 from takikawa/ipfix-nfcapd-test
Browse files Browse the repository at this point in the history
Add an integration test for ipfix probe using an ipfix collector
  • Loading branch information
wingo committed Aug 9, 2017
2 parents 07bab30 + 78bdcae commit ab02d53
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 28 deletions.
20 changes: 9 additions & 11 deletions src/apps/ipv4/arp.lua
Expand Up @@ -196,17 +196,15 @@ function ARP:push()
end
end

for _ = 1, link.nreadable(inorth) do
local p = receive(inorth)
if not self.next_mac then
-- drop all southbound packets until the next hop's ethernet address is known
packet.free(p)
else
local e = ffi.cast(ether_header_ptr_t, p.data)
e.dhost = self.next_mac
e.shost = self.self_mac
transmit(osouth, p)
end
-- don't read southbound packets until the next hop's ethernet address is known
if self.next_mac then
for _ = 1, link.nreadable(inorth) do
local p = receive(inorth)
local e = ffi.cast(ether_header_ptr_t, p.data)
e.dhost = self.next_mac
e.shost = self.self_mac
transmit(osouth, p)
end
end
end

Expand Down
6 changes: 5 additions & 1 deletion src/program/ipfix/probe/README
Expand Up @@ -8,14 +8,18 @@ Available options:
Defaults to 10.0.0.1.
-c, --collector <ipaddr> The IP address of the flow collector.
Defaults to 10.0.0.2.
-i, --input-type <type> One of pcap, raw, or intel10g. Specifies
-i, --input-type <type> One of pcap, raw, tap, or intel10g. Specifies
how to interpret the <input> argument. Interprets
<input> as a pcap file path, device name, or
PCI address respectively. Defaults to intel10g.
-o, --output-type <type> Takes the same values as -i but for <output>.
-D, --duration <seconds> Duration to run (in seconds).
-p, --port <port> The port on the collector to send to. Defaults
to port 4739.
--active-timeout <secs> The timeout period for flows that are still receiving
packets (in seconds).
--idle-timeout <secs> The timeout period for flows with no recent activity
(in seconds).
--netflow-v9 Use the Netflow V9 protocol to communicate to the
flow collector.
--ipfix Use IPFIX to communicate with the flow collector.
Expand Down
61 changes: 45 additions & 16 deletions src/program/ipfix/probe/probe.lua
Expand Up @@ -5,33 +5,49 @@ module(..., package.seeall)
local now = require("core.app").now
local lib = require("core.lib")
local link = require("core.link")
local basic = require("apps.basic.basic_apps")
local arp = require("apps.ipv4.arp")
local ipfix = require("apps.ipfix.ipfix")
local ipv4 = require("lib.protocol.ipv4")
local ethernet = require("lib.protocol.ethernet")
local numa = require("lib.numa")

-- apps that can be used as an input or output for the exporter
in_out_apps = {}
local in_apps, out_apps = {}, {}

function in_out_apps.pcap (path)
function in_apps.pcap (path)
return { input = "input",
output = "output" },
{ require("apps.pcap.pcap").PcapReader, path }
end

function in_out_apps.raw (device)
function out_apps.pcap (path)
return { input = "input",
output = "output" },
{ require("apps.pcap.pcap").PcapWriter, path }
end

function in_apps.raw (device)
return { input = "rx",
output = "tx" },
{ require("apps.socket.raw").RawSocket, device }
end
out_apps.raw = in_apps.raw

function in_apps.tap (device)
return { input = "input",
output = "output" },
{ require("apps.tap.tap").Tap, device }
end
out_apps.tap = in_apps.tap

function in_out_apps.intel10g (device)
function in_apps.intel10g (device)
local conf = { pciaddr = device }
return { input = "rx",
output = "tx" },
{ require("apps.intel.intel_app").Intel82599, conf }
end
out_apps.intel10g = in_apps.intel10g

local long_opts = {
help = "h",
Expand Down Expand Up @@ -73,11 +89,11 @@ function run (args)
duration = assert(tonumber(arg), "expected number for duration")
end,
i = function (arg)
assert(in_out_apps[arg], "unknown input type")
assert(in_apps[arg], "unknown input type")
input_type = arg
end,
o = function (arg)
assert(in_out_apps[arg], "unknown output type")
assert(out_apps[arg], "unknown output type")
output_type = arg
end,
p = function (arg)
Expand Down Expand Up @@ -119,10 +135,10 @@ function run (args)
main.exit(1)
end

local in_link, in_app = in_out_apps[input_type](args[1])
local out_link, out_app = in_out_apps[output_type](args[2])
local in_link, in_app = in_apps[input_type](args[1])
local out_link, out_app = out_apps[output_type](args[2])

local arp_config = { self_mac = host_mac and ethernet:pton(self_mac),
local arp_config = { self_mac = host_mac and ethernet:pton(host_mac),
self_ip = ipv4:pton(host_ip),
next_ip = ipv4:pton(collector_ip) }
local ipfix_config = { active_timeout = active_timeout,
Expand All @@ -133,15 +149,28 @@ function run (args)
collector_port = port }
local c = config.new()

config.app(c, "source", unpack(in_app))
config.app(c, "arp", arp.ARP, arp_config)
config.app(c, "in", unpack(in_app))
config.app(c, "ipfix", ipfix.IPFIX, ipfix_config)
config.app(c, "sink", unpack(out_app))
config.app(c, "out", unpack(out_app))

-- use ARP for link-layer concerns unless the output is connected
-- to a pcap writer
if output_type ~= "pcap" then
config.app(c, "arp", arp.ARP, arp_config)
config.app(c, "sink", basic.Sink)

config.link(c, "source." .. in_link.output .. " -> arp.south")
config.link(c, "arp.north -> ipfix.input")
config.link(c, "ipfix.output -> arp.north")
config.link(c, "arp.south -> sink." .. out_link.input)
config.link(c, "in." .. in_link.output .. " -> ipfix.input")
config.link(c, "out." .. out_link.output .. " -> arp.south")

-- with UDP, ipfix doesn't need to handle packets from the collector
config.link(c, "arp.north -> sink.input")

config.link(c, "ipfix.output -> arp.north")
config.link(c, "arp.south -> out." .. out_link.input)
else
config.link(c, "in." .. in_link.output .. " -> ipfix.input")
config.link(c, "ipfix.output -> out." .. out_link.input)
end

local done
if not duration then
Expand Down
39 changes: 39 additions & 0 deletions src/program/ipfix/tests/collector-test.sh
@@ -0,0 +1,39 @@
#! /usr/bin/env nix-shell
#! nix-shell -i bash -p nfdump
#
# This is a test script for the IPFIX probe program that tests the
# export process with an actual flow collector.

DURATION=10
FLOWDIR=`mktemp -d`
PCAP=program/wall/tests/data/http.cap

# tap interface setup
ip tuntap add tap-snabb-ipfix mode tap
ip addr add 10.0.0.2 dev tap-snabb-ipfix
ip link set dev tap-snabb-ipfix up

# Run the flow collector, output in $FLOWDIR
nfcapd -b 10.0.0.2 -p 4739 -l $FLOWDIR &
CAPD=$!

# Run probe first
./snabb ipfix probe -D $DURATION -a 10.0.0.1 -c 10.0.0.2\
--active-timeout 5 --idle-timeout 5 -o tap $SNABB_PCI0 tap-snabb-ipfix &
sleep 0.5

# ... then feed it some packets
./snabb packetblaster replay -D $DURATION --no-loop $PCAP $SNABB_PCI1 > /dev/null

kill $CAPD

# Analyze with nfdump
DUMPFILE=`ls -1 $FLOWDIR | head -n 1`
nfdump -r $FLOWDIR/$DUMPFILE | grep "total flows: 6, total bytes: 24609, total packets: 43" > /dev/null
STATUS=$?

# teardown
ip link del tap-snabb-ipfix
rm -r $FLOWDIR

exit $STATUS

0 comments on commit ab02d53

Please sign in to comment.