Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Common I/O, take 2 #1068

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 84 additions & 0 deletions src/apps/io/common.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
-- Use of this source code is governed by the Apache 2.0 license; see COPYING.

-- config.app(c, "IO", IO, {type="pci", device="01:00.0",
-- queues={a = {...}, ...}})

module(..., package.seeall)

-- Maps type names to implementations
local type = {}


IO = {
config = {
type = {default='emu'},
device = {},
queues = {required=true}
}
}

function IO:configure (c, name, conf)
local impl = assert(type[conf.type], "Unknown IO type: "..conf.type)
impl(c, name, conf.device, conf.queues)
end


function type.emu (c, name, device, queues)
local FloodingBridge = require("apps.bridge.flooding").bridge
local Emu = require("apps.io.emu").Emu
local bridge = device or name
local ports, mod = {}, 1
for name, queue in pairs(queues) do
table.insert(ports, name)
if queue.hash then
mod = math.max(queue.hash, mod)
end
end
config.app(c, name, FloodingBridge, {ports=ports})
for name, queue in pairs(queues) do
config.app(c, name, Emu, queue)
config.link(c, name..".trunk -> "..bridge.."."..name)
config.link(c, bridge.."."..name.." -> "..name..".trunk")
end
end


-- Maps PCI driver to implementations
local driver = {}

function type.pci (c, name, device, queues)
local pci = require("lib.hardware.pci")
local impl = assert(driver[pci.device_info(device).driver],
"Unsupported PCI device: "..device)
impl(c, name, device, queues)
end

driver['apps.intel.intel_app'] = function (c, name, device, queues)
local Intel82599 = require("apps.intel.intel_app").Intel82599
local nqueues, vmdq = 0, false
for _ in pairs(queues) do
nqueues = nqueues + 1
if nqueues > 1 then vmdq = true; break end
end
for name, queue in pairs(queues) do
if not queue.macaddr and vmdq then
error(io..": multiple ports defined, "..
"but promiscuous mode requested for queue: "..name)
end
queue.pciaddr = device
queue.vmdq = vmdq or (not not queue.macaddr)
config.app(c, name, Intel82599, queue)
end
end


function selftest ()
require("apps.io.emu")
local c = config.new()
config.app(c, "IO", IO,
{queues = {a = {macaddr="60:50:40:40:20:10", hash=1},
b = {macaddr="60:50:40:40:20:10", hash=2}}})
engine.configure(c)
engine.report_apps()
engine.report_links()
end
67 changes: 67 additions & 0 deletions src/apps/io/emu.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
-- Use of this source code is governed by the Apache 2.0 license; see COPYING.

module(..., package.seeall)
local ethernet = require("lib.protocol.ethernet")
local ipv6 = require("lib.protocol.ipv6")
local murmur = require("lib.hash.murmur")
local C = require("ffi").C

Emu = {
config = {
macaddr = {},
hash = {default=1},
mod = {default=1},
}
}

function Emu:new (conf)
local o = {}
if conf.macaddr then
o.mac = ethernet:pton(conf.macaddr)
end
if conf.mod > 1 then
o.murmur = murmur.MurmurHash3_x86_32:new()
o.mod = conf.mod
o.hash = conf.hash
end
return setmetatable(o, {__index=Emu})
end

local ADDRESS_SIZE = 6
local SRC_OFFSET = ADDRESS_SIZE
local MIN_SIZE = ethernet:sizeof() + ipv6:sizeof()
local IP_SRC_DST_OFFSET = ethernet:sizeof() + 8
local IP_SRC_DST_SIZE = 2*16

function Emu:hash (p)
return self.murmur:hash(p.data+IP_SRC_DST_OFFSET, IP_SRC_DST_SIZE, 0ULL)
end

function Emu:push ()
local mac, hash, mod = self.max, self.hash, self.mod
local l_in = assert(self.input.trunk, "No input link on trunk.")
local l_out = assert(self.output.tx, "No output link on tx.")
for i = 1, link.nreadable(l_in) do
local p = link.receive(l_in)
if p.length < MIN_SIZE
or (mac and C.memcmp(mac, p.data, ADDRESS_SIZE) ~= 0)
or (hash and 1 + (self:hash(p) % mod) ~= hash)
then
packet.free(p)
else
link.transmit(l_out, p)
end
end
local l_in = assert(self.input.rx, "No input link on rx.")
local l_out = assert(self.output.trunk, "No output link on trunk.")
for i = 1, link.nreadable(l_in) do
local p = link.receive(l_in)
if p.length < MIN_SIZE
or (mac and C.memcmp(mac, p.data+SRC_OFFSET, ADDRESS_SIZE) ~= 0)
then
packet.free(p)
else
link.transmit(l_out, p)
end
end
end
6 changes: 5 additions & 1 deletion src/core/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ function app (config, name, class, arg)
if status then arg = result
else error("failed to configure '"..name.."': "..result) end
end
config.apps[name] = { class = class, arg = arg}
if class.configure then
class:configure(config, name, arg)
else
config.apps[name] = { class = class, arg = arg}
end
end

-- API: Add a link to the configuration.
Expand Down
97 changes: 0 additions & 97 deletions src/lib/io/virtual_ether_mux.lua

This file was deleted.

30 changes: 22 additions & 8 deletions src/program/snabbnfv/nfvconfig.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

module(...,package.seeall)

local IO = require("apps.io.common").IO
local VhostUser = require("apps.vhost.vhost_user").VhostUser
local PcapFilter = require("apps.packet_filter.pcap_filter").PcapFilter
local RateLimiter = require("apps.rate_limiter.rate_limiter").RateLimiter
local nd_light = require("apps.ipv6.nd_light").nd_light
local L2TPv3 = require("apps.keyed_ipv6_tunnel.tunnel").SimpleKeyedTunnel
local AES128gcm = require("apps.ipsec.esp").AES128gcm
local virtual_ether_mux = require("lib.io.virtual_ether_mux")
local Synth = require("apps.test.synth").Synth
local Sink = require("apps.basic.basic_apps").Sink
local pci = require("lib.hardware.pci")
local ffi = require("ffi")
local C = ffi.C
Expand All @@ -24,12 +26,22 @@ end
function load (file, pciaddr, sockpath, soft_bench)
local ports = lib.load_conf(file)
local c = config.new()
local io_links
if pciaddr then
io_links = virtual_ether_mux.configure(c, ports, {pci = pciaddr})
else
io_links = virtual_ether_mux.configure(c, ports, {bench = soft_bench})
local NIC_suffix = "_NIC"
local queues = {}
for _, port in ipairs(ports) do
local NIC = port_name(port)..NIC_suffix
queues[NIC] = {macaddr = port.mac_address, vlan = port.vlan}
end
-- Set up virtual packet generator if requested.
if soft_bench then
assert(not queues["__SoftBench"])
queues["__SoftBench"] {macaddr = soft_bench.src}
config.app(c, "BenchSource", Synth, io.bench)
config.app(c, "BenchSink", Sink)
config.link(c, "BenchSource.output -> __SoftBench.rx")
config.link(c, "__SoftBench.tx -> BenchSink.input")
end
config.app(c, "IO", IO, {type=(pciaddr and 'pci'), device=pciaddr, queues=queues})
for i,t in ipairs(ports) do
-- Backwards compatibity / deprecated fields
for deprecated, current in pairs({tx_police_gbps = "tx_police",
Expand Down Expand Up @@ -114,8 +126,10 @@ function load (file, pciaddr, sockpath, soft_bench)
config.link(c, RxLimit..".output -> "..VM_rx)
VM_rx = RxLimit..".input"
end
config.link(c, io_links[i].output.." -> "..VM_rx)
config.link(c, VM_tx.." -> "..io_links[i].input)
-- Finally, connect ends to I/O port
local NIC = name..NIC_suffix
config.link(c, NIC..".tx".." -> "..VM_rx)
config.link(c, VM_tx.." -> "..NIC..".rx")
end

-- Return configuration c.
Expand Down