Skip to content

Commit

Permalink
Merged Javier's new Intel 82599 driver with VMDq support.
Browse files Browse the repository at this point in the history
  • Loading branch information
lukego committed Apr 15, 2014
2 parents 3bfb10e + 2363edd commit 7f66da7
Show file tree
Hide file tree
Showing 8 changed files with 1,048 additions and 198 deletions.
815 changes: 661 additions & 154 deletions src/apps/intel/intel10g.lua

Large diffs are not rendered by default.

140 changes: 113 additions & 27 deletions src/apps/intel/intel_app.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,31 @@ local vfio = require("lib.hardware.vfio")
local config = require("core.config")

Intel82599 = {}
Intel82599.__index = Intel82599

-- table pciaddr => {pf, vflist}
local devices = {}


-- Create an Intel82599 App for the device with 'pciaddress'.
function Intel82599:new (pciaddress)
local a = { dev = intel10g.new(pciaddress) }
setmetatable(a, {__index = Intel82599 })
intel10g.open_for_loopback_test(a.dev)
return a
function Intel82599:new (args)
args = config.parse_app_arg(args)

if args.vmdq then
if devices[args.pciaddr] == nil then
devices[args.pciaddr] = {pf=intel10g.new_pf(args.pciaddr):open(), vflist={}}
end
local dev = devices[args.pciaddr]
local vf = dev.pf:new_vf(#dev.vflist)
dev.vflist[#dev.vflist+1] = vf
return setmetatable({dev=vf:open(args)}, Intel82599)
else
local dev = intel10g.new_sf(args.pciaddr)
:open()
:autonegotiate_sfi()
:wait_linkup()
return setmetatable({dev=dev}, Intel82599)
end
end

-- Allocate receive buffers from the given freelist.
Expand Down Expand Up @@ -67,34 +85,102 @@ end

-- Report on relevant status and statistics.
function Intel82599:report ()
print("report on intel device", self.dev.pciaddress)
print("report on intel device", self.dev.pciaddress or self.dev.pf.pciaddress)
--register.dump(self.dev.r)
register.dump(self.dev.s, true)
if self.dev.rxstats then
for name,v in pairs(self.dev:get_rxstats()) do
io.write(string.format('%30s: %d\n', 'rx '..name, v))
end
end
if self.dev.txstats then
for name,v in pairs(self.dev:get_txstats()) do
io.write(string.format('%30s: %d\n', 'tx '..name, v))
end
end
register.dump({
self.dev.r.TDH, self.dev.r.TDT,
self.dev.r.RDH, self.dev.r.RDT,
self.dev.r.AUTOC or self.dev.pf.r.AUTOC,
self.dev.r.AUTOC2 or self.dev.pf.r.AUTOC2,
self.dev.r.LINKS or self.dev.pf.r.LINKS,
self.dev.r.LINKS2 or self.dev.pf.r.LINKS2,
})
end

function selftest ()
-- Create a pieline:
-- Source --> Intel82599(loopback) --> Sink
-- and push packets through it.
vfio.bind_device_to_vfio("0000:01:00.0")
buffer.preallocate(100000)
sq_sq('0000:05:00.0', '0000:8a:00.0')
app.main({duration = 1, report={showlinks=true, showapps=false}})

mq_sq('0000:05:00.0', '0000:8a:00.0')
app.main({duration = 1, report={showlinks=true, showapps=false}})
end

-- open two singlequeue drivers on both ends of the wire
function sq_sq(pcidevA, pcidevB)
local c = config.new()
config.app(c, "intel10g", Intel82599, "0000:01:00.0")
config.app(c, "source", basic_apps.Source)
config.app(c, "sink", basic_apps.Sink)
config.link(c, "source.out -> intel10g.rx")
config.link(c, "intel10g.tx -> sink.in")
config.app(c, 'source1', basic_apps.Source)
config.app(c, 'source2', basic_apps.Source)
config.app(c, 'nicA', Intel82599, ([[{pciaddr='%s'}]]):format(pcidevA))
config.app(c, 'nicB', Intel82599, ([[{pciaddr='%s'}]]):format(pcidevB))
config.app(c, 'sink', basic_apps.Sink)
config.link(c, 'source1.out -> nicA.rx')
config.link(c, 'source2.out -> nicB.rx')
config.link(c, 'nicA.tx -> sink.in1')
config.link(c, 'nicB.tx -> sink.in2')
app.configure(c)
--[[
app.apps.intel10g = Intel82599:new("0000:01:00.0")
app.apps.source = app.new(basic_apps.Source)
app.apps.sink = app.new(basic_apps.Sink)
app.connect("source", "out", "intel10g", "rx")
app.connect("intel10g", "tx", "sink", "in")
app.relink()
--]]
buffer.preallocate(100000)
app.main({duration = 1})
-- repeat app.breathe() until deadline()
-- app.report()
end

-- one singlequeue driver and a multiqueue at the other end
function mq_sq(pcidevA, pcidevB)
d1 = lib.hexundump ([[
52:54:00:02:02:02 52:54:00:01:01:01 08 00 45 00
00 54 c3 cd 40 00 40 01 f3 23 c0 a8 01 66 c0 a8
01 01 08 00 57 ea 61 1a 00 06 5c ba 16 53 00 00
00 00 04 15 09 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
]], 98) -- src: As dst: Bm0
d2 = lib.hexundump ([[
52:54:00:03:03:03 52:54:00:01:01:01 08 00 45 00
00 54 c3 cd 40 00 40 01 f3 23 c0 a8 01 66 c0 a8
01 01 08 00 57 ea 61 1a 00 06 5c ba 16 53 00 00
00 00 04 15 09 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
]], 98) -- src: As dst: Bm1
local c = config.new()
config.app(c, 'source_ms', basic_apps.Join)
config.app(c, 'repeater_ms', basic_apps.Repeater)
config.app(c, 'nicAs', Intel82599, ([[{
-- Single App on NIC A
pciaddr = '%s',
macaddr = '52:54:00:01:01:01',
}]]):format(pcidevA))
config.app(c, 'nicBm0', Intel82599, ([[{
-- first VF on NIC B
pciaddr = '%s',
vmdq = true,
macaddr = '52:54:00:02:02:02',
}]]):format(pcidevB))
config.app(c, 'nicBm1', Intel82599, ([[{
-- second VF on NIC B
pciaddr = '%s',
vmdq = true,
macaddr = '52:54:00:03:03:03',
}]]):format(pcidevB))
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")
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')
config.link(c, 'nicAs.tx -> sink_ms.in1')
config.link(c, 'nicBm0.tx -> sink_ms.in2')
config.link(c, 'nicBm1.tx -> sink_ms.in3')
app.configure(c)
link.transmit(app.app_table.source_ms.output.out, packet.from_data(d1))
link.transmit(app.app_table.source_ms.output.out, packet.from_data(d2))
end
21 changes: 16 additions & 5 deletions src/core/app.lua
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ function main (options)
breathe()
if not no_timers then timer.run() end
until done and done()
report()
report(options.report)
end

function breathe ()
Expand All @@ -147,10 +147,21 @@ function breathe ()
until not progress -- Stop after no link had new data
end

function report ()
print("link report")
for name, l in pairs(link_table) do
print(lib.comma_value(tostring(tonumber(l.stats.txpackets))), "sent on", name)
function report (options)
if not options or options.showlinks then
print("link report")
for name, l in pairs(link_table) do
print(lib.comma_value(tostring(tonumber(l.stats.txpackets))), "sent on", name)
end
end
if options and options.showapps then
print ("apps report")
for name, a in pairs(app_table) do
if a.report then
print (name)
a:report()
end
end
end
end

Expand Down
45 changes: 45 additions & 0 deletions src/core/lib.lua
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,25 @@ function bitset (value, n)
return bit.band(value, bit.lshift(1, n)) ~= 0
end

--- Hex dump and undump functions

function hexdump(s)
if #s < 1 then return '' end
local frm = ('%02X '):rep(#s-1)..'%02X'
return string.format(frm, s:byte(1, #s))
end

function hexundump(h, n)
local buf = ffi.new('char[?]', n)
local i = 0
for b in h:gmatch('[0-9a-fA-F][0-9a-fA-F]') do
buf[i] = tonumber(b, 16)
i = i+1
if i >= n then break end
end
return ffi.string(buf, n)
end

function comma_value(n) -- credit http://richard.warburton.it
local left,num,right = string.match(n,'^([^%d]*%d)(%d*)(.-)$')
return left..(num:reverse():gsub('(%d%d%d)','%1,'):reverse())..right
Expand Down Expand Up @@ -205,5 +224,31 @@ function selftest ()
-- assert(readlink('/etc/rc2.d/S99rc.local') == '../init.d/rc.local', "bad readlink")
-- assert(dirname('/etc/rc2.d/S99rc.local') == '/etc/rc2.d', "wrong dirname")
-- assert(basename('/etc/rc2.d/S99rc.local') == 'S99rc.local', "wrong basename")
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")

local macA = new_mac('00-01-02-0a-0b-0c')
local macB = new_mac('0001020A0B0C')
local macC = new_mac('0A:0B:0C:00:01:02')
print ('macA', macA)
assert (tostring(macA) == '00:01:02:0A:0B:0C', "bad canonical MAC")
assert (macA == macB, "macA and macB should be equal")
assert (macA ~= macC, "macA and macC should be different")
assert (macA:subbits(0,31)==0x0a020100, "low A")
assert (macA:subbits(32,48)==0x0c0b, ("hi A (%X)"):format(macA:subbits(32,48)))
assert (macC:subbits(0,31)==0x000c0b0a, "low C")
assert (macC:subbits(32,48)==0x0201," hi C")

local ndx_set = new_index_set(4, 'test ndx')
assert (string.format('%d/%s', ndx_set:add('a'))=='0/true', "indexes start with 0, and is new")
assert (string.format('%d/%s', ndx_set:add('b'))=='1/true', "second new index")
assert (string.format('%d/%s', ndx_set:add('c'))=='2/true', "third new")
assert (string.format('%d/%s', ndx_set:add('b'))=='1/false', "that's an old one")
assert (string.format('%d/%s', ndx_set:add('a'))=='0/false', "the very first one")
assert (string.format('%d/%s', ndx_set:add('A'))=='3/true', "almost, but new")
assert (string.format('%s/%s', pcall(ndx_set.add, ndx_set,'B'))
:match('^false/core/lib.lua:%d+: test ndx overflow'), 'should overflow')
end

59 changes: 59 additions & 0 deletions src/core/packet.lua
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,24 @@ function add_iovec (p, b, length, offset)
p.length = p.length + length
end

-- fill's an allocated packet with data from a string
function fill_data (p, d, offset)
offset = offset or 0
local iovec = p.iovecs[0]
assert (offset+#d <= iovec.length, "can't fit on first iovec") -- TODO: handle more iovecs
ffi.copy (iovec.buffer.pointer + iovec.offset + offset, d, #d)
end

-- creates a packet from a given binary string
function from_data (d)
local p = allocate()
local b = buffer.allocate()
local size = math.min(#d, b.size)
add_iovec(p, b, size)
fill_data(p, d)
return p
end

-- Increase the reference count for packet p by n (default n=1).
function ref (p, n)
if p.refcount > 0 then
Expand Down Expand Up @@ -78,4 +96,45 @@ function free (p)
freelist.add(packets_fl, p)
end

function iovec_dump (iovec)
local b = iovec.buffer
local l = math.min(iovec.length, b.size-iovec.offset)
if l < 1 then return '' end
o={[-1]=string.format([[
offset: %d
length: %d
buffer.pointer: %s
buffer.physical: %X
buffer.size: %d
]], iovec.offset, iovec.length, b.pointer, tonumber(b.physical), b.size)}
for i = 0, l-1 do
o[i] = bit.tohex(b.pointer[i+iovec.offset], -2)
end
return table.concat(o, ' ', -1, l-1)
end

function report (p)
print (string.format([[
refcount: %d
fuel: %d
info.flags: %X
info.gso_flags: %X
info.hdr_len: %d
info.gso_size: %d
info.csum_start: %d
info.csum_offset: %d
niovecs: %d
length: %d
]],
p.refcount, p.fuel, p.info.flags, p.info.gso_flags,
p.info.hdr_len, p.info.gso_size, p.info.csum_start,
p.info.csum_offset, p.niovecs, p.length
))
for i = 0, p.niovecs-1 do
print(string.format([[
iovec #%d: %s
]], i, iovec_dump(p.iovecs[i])))
end
end

module_init()

1 comment on commit 7f66da7

@alexandergall
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

intel10g.M_sf:transmit() fails for multi-buffer packets

core/freelist.lua:14: freelist overflow
stack traceback:
        core/main.lua:105: in function 
        [C]: in function 'assert'
        core/freelist.lua:14: in function 'add'
        core/packet.lua:133: in function 'free'
        core/packet.lua:113: in function 'deref'
        apps/intel/intel10g.lua:191: in function 'sync_transmit'
        apps/intel/intel_app.lua:83: in function 'push'
        core/app.lua:142: in function 'breathe'
        core/app.lua:121: in function 'main'
        test/vpn10ge.lua:54: in main chunk
        [C]: in function 'require'
        core/main.lua:73: in function 
        [C]: in function 'xpcall'
        core/main.lua:110: in main chunk
        [C]: in function 'require'
        [string "require "core.main""]:1: in main chunk

Please sign in to comment.