-
Notifications
You must be signed in to change notification settings - Fork 299
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
base: master
Are you sure you want to change the base?
Common I/O, take 2 #1068
Conversation
# Conflicts: # src/apps/io/io.lua
Great to be making this really happen! I am really liking the uniform interface towards so many different I/O drivers (each PCI driver, tap, raw socket, emulated). This is definitely what I want as a user. The implementation is a bit sophisticated for my caveman tastes :-). It feels like a lot of cognitive load to take on new concepts like formula and virtual table, to have a Lua driver interface between modules in addition to the app interface, and to use fancy mechanisms like weak tables. Could we solve this problem in a stupider and more low-brow way? Just dreaming for a moment... one thought in the back of my head is that the IO app is basically a macro. It's a placeholder where a more specific app (or apps) should be substituted at configuration time. This seems like a substitution that could be made in some simple local way along the lines of For context here is the approach I am taking on the Mellanox driver. The controller app initializes the NIC with the necessary queues and then creates shm frames containing all of the necessary information for a queue handler to attach and perform IO. Snippet: -- Create shared memory objects containing all of the
-- information needed to access the send and receive queues.
--
-- Snabb processes will use this information to take ownership
-- of the queue to send and receive packets.
local basepath = "/pci/"..pciaddress.."/"..queuename
local sendpath = basepath.."/send"
local recvpath = basepath.."/recv"
local u64 = function (x) return ffi.cast("uint64_t", x) end
shm.create_frame(sendpath,
{lock = {counter},
sqn = {counter, sqn},
wq = {counter, u64(swq)},
wqsize = {counter, sendq_size},
cqn = {counter, send_cq.cqn},
cqe = {counter, u64(send_cq.cqe)},
doorbell = {counter, u64(wq_doorbell)},
uar_page = {counter, uar},
rlkey = {counter, rlkey}})
shm.create_frame(recvpath,
{lock = {counter},
rqn = {counter, rqn},
wq = {counter, u64(rwq)},
wqsize = {counter, recvq_size},
cqn = {counter, recv_cq.cqn},
cqe = {counter, u64(recv_cq.cqe)},
doorbell = {counter, u64(wq_doorbell)},
uar_page = {counter, uar},
rlkey = {counter, rlkey}}) So in this case there is no need for the IO abstraction to share any state between apps via the Lua heap ( On reflection I suppose that this approach would have more impact on the existing drivers. For example if Hard problem! |
One use case that I find interesting: Can the IO framework provide a simple and uniform way for users to specify how to do IO on the command line? For example supposed we had a snabb tcpdump tap=tap0
snabb tcpdump raw=eth0
snabb tcpdump pci=01:00.0
snabb tcpdump pci=01:00.0,rss=4 # four worker processes
snabb tcpdump synth=64,100,250,1500 # synthetic traffic mix Can we cook up a good syntax for this? And a straightforward mapping onto a collection of Could be that solving this problem will lead us to the optimal interface for the IO apps. I am not sure. |
... Just continuing the same train of thought. On the one hand we could have a syntax for specifying a whole tree of processes:
and on the other hand we could specify each process separately:
and it may even make sense to support both styles. Snabb could internally operate as a collection of discrete processes, like in the second example, but Snabb programs may want to provide a simple command-line syntax that automatically spawns the processes just to save the user extra typing, like in the first example. EDIT: Could also make sense to add CPU core assignments to this example since that is also an aspect that we have suggested making the user assign explicitly. |
Just continuing to continue... Could also be that command-line syntax is the past and we should start looking to YANG based configuration files now. I wonder if that would be sensible or overkill for applications like |
(The reason for this digression into command-line and application configuration is that I see this as the primary user of the |
Regarding YANG and snabbmark -- I don't know :) I don't see it for snabbmark, but I could be missing something. How would you see that working? Command-line stuff is nice for developers I think; YANG is nice internally for parsing, serialization, validation (somewhat), compilation, and binary loading of configuration data from users; but if the interface is from a developer perhaps it is overkill? I don't know. I must also say that I am at my limit for hackpower over the next 3/4 weeks and so I am going to be ignoring more things than usual, even meritorious hacks like this one :) |
@lukego You’re right, what a complicated mess. I simplified and came up with this imho sane approach:
|
The GitHub diff view is broken right now... |
Actually its not, my mistake. I reverted the leftovers and now its looking good. |
Wow! I really like this new Looks to me like the user-facing API for creating apps is exactly the same but behind the scenes each app class now has the possibility to customize how it is instantiated. So when you write:
this can call This seems like a tasteful choice of mechanism. The alternatives would be to make the user explicitly call the Question: Could we put all of the smarts directly into (Could also be worth spinning out the |
I also like the |
I assume that |
@wingo In concept yes, the idea is to allow the configure method to call |
@lukego I refactored all the framework bits to be centralized in apps.io.common, I agree that its less intrusive that way. |
Prepare v3.1.10 release
Second iteration on my quest to find a shared abstraction for I/O apps. This supersedes #1043, and splits the responsibilities between two apps:
IOControl
andIO
. Again these make use of a newconfigure
callback to act as configuration “macros”. The convention of drivers providing adriver
variable is extended to cover a “control driver”, and apps.io.io contains the glue code that is needed to support existing (virtual) drivers with minimal changes. In theory (not fully tested) this PR already supports the Intel10G and Solarflare drivers, emulation I/O, RawSocket, Tap, and VhostUser.The IOControl and IO macro apps implement the following interface:
All keys except
queues
,id
,buckets
,queue
, andbucket
are driver dependent.To add support for a PCI driver module it must be registered in
lib.hardware.pci
. To add support for a virtual driver module it must be registered in thevirtual_module
table below.The driver module must expose a
driver
variable that contains the app thatimplements the queue driver. If a control app is required for queue setup,
the driver must expose a
control
variable that contains the respectiveapp, which must accept the configuration argument passed to IOControl.
Note that the
buckets
andbucket
properties must default to 1.Finally, a configuration
formula
for the driver must be selected. See howthe
formula
table is populated.FURTHER USAGE EXAMPLES:
This PR is marked WIP because it lacks documentation, and further testing. One known caveat is that the new emulation layer
apps.io.emu
is most likely more of a bottleneck thanvirtual_ether_mux
.Cc @lukego