1128 lines
53 KiB
TeX
1128 lines
53 KiB
TeX
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
% Copyright (c) 2011, ETH Zurich.
|
|
% All rights reserved.
|
|
%
|
|
% This file is distributed under the terms in the attached LICENSE file.
|
|
% If you do not find this file, copies can be found by writing to:
|
|
% ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
\documentclass[a4paper,twoside]{report} % for a report (default)
|
|
|
|
\usepackage{bftn} % You need this
|
|
\usepackage{hyperref} % You need this
|
|
|
|
\title{Bulk Transfer} % title of report
|
|
\author{Pravin Shinde} % author
|
|
\tnnumber{014} % give the number of the tech report
|
|
\tnkey{Bulk Transport: Cross-domain transfer facility for large data}
|
|
% Short title, will appear in footer
|
|
|
|
% \date{Month Year} % Not needed - will be taken from version history
|
|
|
|
\begin{document}
|
|
\maketitle
|
|
|
|
%
|
|
% Include version history first
|
|
%
|
|
\begin{versionhistory}
|
|
\vhEntry{1.0}{11.08.2011}{TR}{Initial version}
|
|
\end{versionhistory}
|
|
|
|
% \intro{Abstract} % Insert abstract here
|
|
% \intro{Acknowledgements} % Uncomment (if needed) for acknowledgements
|
|
\tableofcontents % Uncomment (if needed) for final draft
|
|
% \listoffigures % Uncomment (if needed) for final draft
|
|
% \listoftables % Uncomment (if needed) for final draft
|
|
|
|
\chapter{Introduction}
|
|
\label{chap:intro}
|
|
This technical note is aimed to describe the design of suitable cross
|
|
domain bulk transport for Barrelfish. This chapter gives a motivation
|
|
for this design by providing the details about existing
|
|
implementations of bulk-transport in Barrelfish and reasoning
|
|
about why those are not good enough. The \autoref{chap:design}
|
|
contains the actual details about the design. So, if you are
|
|
already convinced of the need for better bulk-transport in
|
|
Barrelfish, then you can directly jump to the \autoref{chap:design}
|
|
|
|
|
|
\section{Existing implementation in Barrelfish}
|
|
There are two bulk transport mechanisms that exist in the current(as of August
|
|
2011) implementation of Barrelfish.
|
|
\texttt{$lib/barrelfish/bulk\_transfer.c$}
|
|
and \textit{pbufs} used in the network stack. We will discuss them briefly in
|
|
following two sub-sections.
|
|
|
|
\subsection{$bulk\_transfer.c/h$}
|
|
This is the official bulk transfer method supported by Barrelfish. In brief, this
|
|
facility works by sharing a continuous piece of memory (in form of capability)
|
|
between two domains. These domains then map this physical memory into their
|
|
virtual address-space. The virtual address where this shared memory is loaded
|
|
can be different. So, participating processes can't exchange the virtual
|
|
addresses directly. Bulk transfer mechanism works by dividing the entire
|
|
memory area into the blocks of fixed size. The domain which initiated the
|
|
bulk transfer is responsible for managing these blocks. This responsibility
|
|
includes following.
|
|
\begin{enumerate}
|
|
\item Allocation and deallocation of the blocks.
|
|
\item Maintaining the information about free and used blocks.
|
|
\end{enumerate}
|
|
So, this bulk transfer facility works in master-slave setup. The master
|
|
allocates the blocks and passes the index of the block to slave.
|
|
Once the block is passed to the slave, master should not touch it.
|
|
The slave can locate the block by adding the \texttt{(index*block-size)} to the
|
|
virtual address pointing to the beginning of the shared memory area.
|
|
Now slave can read/modify the contents in the memory area of this block. Once
|
|
the slave is done with accessing the block, it can pass the block-index
|
|
back to the master. Master can either access the block or release it
|
|
for future use.
|
|
|
|
\subsubsection{Limitations}
|
|
\paragraph{Security}
|
|
This transfer mechanism can only be used between domains which are
|
|
co-operative and willing to follow the protocol set for using the bulk
|
|
transfer mechanism. Malicious domain can corrupt the data in shared
|
|
memory by writing at random locations in it
|
|
or can refuse to return the blocks once passed to it.
|
|
|
|
\paragraph{More than two domains}
|
|
The design of this bulk transport does not stop you from using it with
|
|
more than two domains as long as the protocol is followed. But current
|
|
implementation does not track which domain is holding the buffer. So,
|
|
one can use the current implementation with multiple domains as long
|
|
as the domains are co-operative and applications are willing to deal
|
|
with added complexity of tracking which domains hold which buffers.
|
|
|
|
\paragraph{Current usage}
|
|
Due to the relatively simple nature of the implementation, its use is
|
|
limited only to few places. And hence it is not throughly tested in
|
|
various scenarios.
|
|
|
|
\subsection{pbufs}
|
|
The network stack uses its own custom bulk transport mechanisms. Lets
|
|
call them pbufs. These pbufs work in similar way to above mechanism,
|
|
but are more flexible. The application shares some piece of physical memory
|
|
with network driver which is used as shared memory. Then application
|
|
creates a list of pbuf structures, each one of them holding an offset
|
|
within shared memory, length, \textit{pbuf-id} and the shared memory id to
|
|
which they belong. The key difference here is that the these pbufs
|
|
may not hold consecutive memory locations even when \textit{pbuf-id}'s are
|
|
consecutive. In contrast with Barrelfish bulk-transfer where buffer-id
|
|
value is enough to find the location of buffer within shared memory,
|
|
pbuf needs to store the offset separately in another list. So,
|
|
pbufs provide another layer of indirection to allow more
|
|
flexible use of memory.
|
|
|
|
|
|
The way this mechanism currently works is that, application creates
|
|
pool of initial pbufs and registers them with network driver. Both,
|
|
application and network driver maintain the list of pbufs in their
|
|
private memory. This list is kept in synchronization by sending
|
|
explicit messages. Now each pbuf can in principle point to any
|
|
buffer of any size, located anywhere in the shared memory.
|
|
|
|
|
|
This flexibility is used by application when it receives a data from
|
|
the network driver. Application creates a new pbuf structure with
|
|
same pbuf-id but pointing at new buffer location and send it back to
|
|
the driver as new free pbuf to use. And the location of previous
|
|
buffer is used for processing the data. This way, application can
|
|
return the pbufs back to driver ASAP without getting affected by how
|
|
long does the data processing takes. When application is done with
|
|
processing the data in that buffer, it releases that buffer. This
|
|
released buffer is then used to create new pbuf which will be
|
|
registered again with driver in future.
|
|
|
|
\subsubsection{Limitations}
|
|
|
|
\paragraph{Needs more memory}
|
|
The shared memory needs to be bigger than the memory shared with
|
|
network driver in form of registered pbufs. This is because, at any
|
|
given point in time, some pbufs will be in application data processing
|
|
phase and hence can-not be used by driver to receive the new data.
|
|
|
|
\paragraph{Data corruption}
|
|
This bulk-transfer mechanism assumes co-operative domains. Both
|
|
domains have read/write access to the shared memory at all the time.
|
|
This means that if they do not follow the protocol correctly, they may
|
|
end up writing at same physical location, leading to data corruption.
|
|
|
|
\paragraph{Complicated memory reclamation}
|
|
The current implementation of pbufs assumes that application can have
|
|
multiple threads and all of them can access the data in pbufs which
|
|
are delivered to the application. This complicates the problem of
|
|
detecting when exactly all threads are done with accessing the
|
|
particular pbuf. The current implementation uses a reference count
|
|
mechanism for this detection. Even though this memory reclamation is
|
|
functional, it is complicated and one can easily get it wrong, leading
|
|
to memory leaks.
|
|
|
|
\paragraph{Supporting more than two domains}
|
|
In theory, this design can be used with more than two domains which
|
|
are co-operating with each other, but implementation is not designed
|
|
with such a case in mind. The problematic issues will be tracking
|
|
which memory buffer is with which domain, and when the memory buffer
|
|
can be reused.
|
|
|
|
\subsubsection{More issues with current network stack implementation}
|
|
Following issues are not exactly due to the bulk transfer mechanisms,
|
|
but are mainly the implementation issues of network stack. I am
|
|
documenting them here for sake of completeness. Also, knowing the
|
|
issues in current stack will help in understanding the design
|
|
decisions made.
|
|
|
|
\paragraph{Favors the setup with driver on different core}
|
|
It is optimized for the case where application and network driver are
|
|
running on separate core. It is reasonable to prefer such cases
|
|
for multicore architectures where presence of large number of cores is
|
|
assumed. This preference has resulted on overly dependence on
|
|
efficiency of UMP messages. Current implementation sends around 2
|
|
messages (send-packet, tx-done) for transmitting single packet
|
|
assuming that packet fits into one pbuf. Similarly on packet
|
|
receiving side, each received packet involves 2 messages
|
|
(register-pbuf, packet-received). The performance impact of these
|
|
messages is not strongly visible when application and driver are on
|
|
different core. But there are cases like SCC where you may end up
|
|
running the driver on same core as an application. In such scenarios
|
|
LMP's are used for communication which involves doing context-switch in
|
|
sending every message. This leads to lot of performance
|
|
in-efficiencies when current network stack implementation is used in
|
|
LMP contexts. Specially on those hardware where cost of
|
|
context-switch is relatively high.
|
|
|
|
|
|
%I have tried to measure the performance difference on \texttt{nos4-6}
|
|
%boxes with webserver cache loading test, but the performance
|
|
%difference was not significant. I have not investigated the reasons
|
|
%behind them yet, but my preliminary guess was that context switches on
|
|
%these machines are quite efficient or webserver cache loading test
|
|
%does not stress the network stack enough to see any significant
|
|
%difference.
|
|
|
|
|
|
%\section{Questions to be asked about bulk transfer mechanisms}
|
|
%\begin{enumerate}
|
|
% \item Does it uses memory efficiently?
|
|
% \item Can it be used with mutually non-trusting domains?
|
|
% \item Can it be used across more than two domains?
|
|
% \item Can consumer/producer put a back-pressure on other side?
|
|
% \item Can it support multiple producer and multiple consumers?
|
|
% \item Can it allow implementation of \textit{True Zero Copy}
|
|
% sending and receiving?
|
|
% \item Can it lead to deadlock if one domain is only sending without
|
|
% checking for arriving messages?
|
|
%\end{enumerate}
|
|
|
|
\section{Related work}
|
|
The issues of bulk-transport has been investigated quite a few times
|
|
in the past by work like \textit{F-bufs}, \textit{R-bufs} and
|
|
\textit{Beltway buffers} so the solution of this problem is known to
|
|
the large extent. What this document is aiming is to choose
|
|
right approach and right solution which will suit the
|
|
requirements of the Barrelfish.
|
|
|
|
|
|
%The work which has particularly influenced this design are
|
|
%\begin{enumerate}
|
|
% \item F-bufs: Helped in clearly understanding the problems in
|
|
% designing cross-domain transfer facility.
|
|
% \item R-bufs: Helped in understanding how to implement
|
|
% scatter-gather packet sending and receiving.
|
|
% \item Beltway buffers: Gave clear idea of how to design a
|
|
% system with multiple ring-buffer to get lot of flexibility.
|
|
% The problem with beltway buffers is that they are
|
|
% designed to be POSIX compatible and due to that, the whole
|
|
% functionality of these buffers is pushed into trusted OS code-base.
|
|
% The applications are unaware of these buffers. Also, these buffers
|
|
% can be used mostly to short-circuit the data path between different
|
|
% trusted kernel sub-systems. If applications are going to modify the
|
|
% data then beltway buffers don't help much.
|
|
%\end{enumerate}
|
|
|
|
\section{Requirements of Barrelfish}
|
|
Following are the ideal requirements from the bulk-transport
|
|
mechanism.
|
|
\begin{enumerate}
|
|
\item Avoid data copy as much as possible, if can't avoid,
|
|
then try to push it into user-space/user-core.
|
|
\item Ability to batch the notifications.
|
|
\item Should work with more than two domains.
|
|
\item Should work with multiple producers and multiple consumers.
|
|
\item True zero copy capability(scatter-gather packet
|
|
sending/receiving).
|
|
\end{enumerate}
|
|
The solution that we are trying to design tried to satisfy as many
|
|
of these requirements as possible.
|
|
|
|
\chapter{Design}
|
|
\label{chap:design}
|
|
This chapter discusses the design of bulk-transport mechanism
|
|
that will be implemented in future for Barrelfish network
|
|
stack.
|
|
|
|
|
|
\section{Bird's eye view of design}
|
|
We are aiming to design a cross domain bulk transport mechanism,
|
|
which supports following features.
|
|
\begin{enumerate}
|
|
\item Should reduce the data copy as much as possible.
|
|
\item Should exploit the fact that complete data-isolation
|
|
is not always needed.
|
|
\item More than two separate domains should be able to share
|
|
the data without copying it.
|
|
\item Number of explicit notifications needed should be low.
|
|
\item It should work in \textit{single producer, single consumer}
|
|
and \textit{single producer, multiple consumers}
|
|
\end{enumerate}
|
|
|
|
\section{Terminology used}
|
|
This section briefly explains the term used in the design
|
|
description. This should help in the understanding by reducing
|
|
the ambiguity of the terms.
|
|
\begin{enumerate}
|
|
\item \textbf{Generator:} An entity which is generating the data. It
|
|
can be software or hardware entity. For example, Network
|
|
Interface Card(NIC) is a generator, or the application code
|
|
which is generating the packets to send over the NIC.
|
|
\item \textbf{data-element:} The data-element is what generator
|
|
is generating. In case of NIC device, a packet will be a
|
|
data-element.
|
|
\item \textbf{Producer:} An entity which is managing the generated data.
|
|
This management contains providing access mitigation, notifying
|
|
interested consumers, reclaiming the memory when data-element
|
|
is consumed. The example of producer will be \textit{NIC device
|
|
driver}.
|
|
|
|
|
|
The distinction between generator and producer is
|
|
rather fine. They are intentionally kept separate because
|
|
generators can have hardware constraints which does not allow
|
|
it to provide all functionalities.
|
|
\item \textbf{Consumer:} An entity which is consuming the data-elements.
|
|
\item \textbf{Slot:} The contiguous piece of memory where data-element is
|
|
entirely or partially stored. A data-element can span over
|
|
more than one slots.
|
|
\item \textbf{Shared-pool:} A contiguous piece of memory accessible
|
|
in read/write mode to producer and accessible in read only mode to
|
|
consumers. Shared pools are divided into above slots.
|
|
\item \textbf{Production-pool:} It is a collection of all
|
|
shared-pools used by the particular producer. The initial
|
|
shared-pool is added by the producer, and later on every consumer
|
|
which joins the system contributes a new shared-pool to the
|
|
production-pool.
|
|
\item \textbf{Free slot:} A slot which is available, and can be given
|
|
to generator.
|
|
\item \textbf{In-generation slot:} A slot is given to generator. Only
|
|
the generator should read/write this slot now. This is the only
|
|
mode when data can be written in the slot.
|
|
\item \textbf{In-consumption slot:} One or more consumers are currently
|
|
consuming this slot. In this mode, slot is strictly read-only
|
|
no one should modify the data in slot in this mode.
|
|
\item \textbf{Slot-pointer:} A data-structure which holds enough
|
|
information to locate particular slot present in any shared-pool
|
|
with producer. These are typically used in cross domain
|
|
communication to identify the exact slot. A typical slot-pointer
|
|
should have a shared-pool-id and offset within shared-pool to
|
|
find the particular slot.
|
|
\item \textbf{Classification:} This term refers to the
|
|
classification of data-elements between consumers. In other words,
|
|
it is a process of deciding which consumers should receive this
|
|
particular data-element. In network stack parlance, this
|
|
classification will map to deciding which process should get the
|
|
received packet.
|
|
\end{enumerate}
|
|
|
|
\section{The Producer}
|
|
This section describes the producer and generator together with
|
|
their responsibilities. Even though producer and generator can
|
|
be a different entities internally, the consumers will only see
|
|
the producer interface.
|
|
|
|
\subsection{Generator}
|
|
Lets make a rough sketch of typical generator. Here we are aiming
|
|
for the NIC devices. Typically, these devices will have an
|
|
internal queue (RX-queue) of slots where the packet received
|
|
from wire will be copied. These generators are also capable
|
|
of generating a notification in form of interrupt. Now the
|
|
way RX-queues work on different devices differ in some way.
|
|
Few devices expect contiguous memory in the slots whereas
|
|
other devices are capable of DMAing the packet in non-contiguous
|
|
memory as well.
|
|
|
|
|
|
The software generators like application
|
|
logic which creates new packet to send out is much simpler than
|
|
NIC devices but can have quirky behavior like above described
|
|
NIC devices.
|
|
|
|
|
|
From bulk-transport point-of-view we will be treating the generator as
|
|
a part of producer.
|
|
|
|
\subsection{The Producer abstraction}
|
|
The producer abstraction is nothing but the combination of generator
|
|
and remaining producer functionalities.
|
|
The producer abstraction is what consumer sees and interacts with.
|
|
It is responsible for managing the data produced by generator and
|
|
using shared-pools to get that data till consumers. It is also
|
|
responsible for managing the shared-pool memory and co-ordinating
|
|
the access to this shared resource.
|
|
|
|
|
|
\subsection{Shared-pool}
|
|
Shared-pool is the area where producer will generate the data
|
|
and consumers will read it from. The producer breaks this
|
|
shared-pool into \textit{slots}. The size of slot
|
|
is based on the capability of generator and should be multiple of
|
|
cache-line size. The details of how to choose
|
|
the slot size and the side-effects of small or large size are
|
|
discussed in \autoref{sec:slotsize}.
|
|
|
|
|
|
The producer is responsible for managing these shared-pools, and it
|
|
does by maintaining the list of shared-pools. At the time of producer
|
|
initialization there will be only one shared-pool which is added by
|
|
the producer itself. As new consumers join the system, each one of
|
|
them will contribute an additional shared-pool.
|
|
|
|
|
|
\subsubsection{Releasing the shared-pool}
|
|
If any consumer decides to leave the system, then producer
|
|
stops using the shared-pool provided by him. The producer will
|
|
wait till all the slots in that shared-pool are free and then it will
|
|
ask all consumers who have mapped this shared-pool to release the
|
|
pool. Once all consumers release the pool then producer can also
|
|
release the pool and inform the consumer who contributed the
|
|
shared-pool about completion of the process.
|
|
|
|
This is rather long process and depends on all the consumers for it's
|
|
completion. But this process is not part of the critical path, it is
|
|
only part of the tear-down process so some inefficiency can be
|
|
tolerated here.
|
|
|
|
|
|
%The virtual address where the shared-pool is mapped need not be same for
|
|
%the producer and consumers.
|
|
|
|
|
|
\subsubsection{Ideal size of production-pool}
|
|
The production-pool is just a collection of all valid shared-pools
|
|
available at given time. Ideally, production-pool should be big enough
|
|
to accommodate the queue of the generator (ie. All the descriptors
|
|
in RX-queue of NIC device) and all the data-elements which are with
|
|
consumers and are not released back (in-consumption state).
|
|
So, the total memory size should be proportional to the capacity of
|
|
the generator(ie. NIC device) and number of consumers.
|
|
So, one way to look at this is that, producer will provide shared-pool
|
|
which can satisfy the needs of generator and each consumer will
|
|
contribute a shared-pool to allow in-consumption data-elements.
|
|
Each consumer is allowed to keep only fixed amount of
|
|
in-consumption data-elements based on the size of shared-pool it
|
|
contributed. This way, fixing the size of allowed pending
|
|
in-consumption data-elements limits the ability to consumers to
|
|
over-consume the slots from production-pool.
|
|
|
|
|
|
\subsection{A meta-slot structure}
|
|
This structure hold the additional information about each slot in
|
|
a shared-pool. It can be seen as index table on shared-pool.
|
|
This structure is private to producer and is used to manage the
|
|
slots within shared-pool. Following are the key elements of
|
|
this structure.
|
|
\begin{enumerate}
|
|
\item \textbf{slot-id:} The slot identifier.
|
|
\item \textbf{offset:} The location of slot within the shared pool.
|
|
\item \textbf{data-len:} Size of valid data in the slot.
|
|
\item \textbf{state:} The state of slot (Free, in-Generation,
|
|
in-Consumption)
|
|
\item \textbf{consumer-list:} Which consumers are accessing it?
|
|
\item \textbf{Next, prev:} Used to maintain the list (eg. Free slots)
|
|
\end{enumerate}
|
|
|
|
The producer maintains a separate meta-slot list for very shared-pool
|
|
available with the producer. This setup enables producer to track
|
|
every slot and its state.
|
|
|
|
Other than this, the producer also maintains the list of consumers who
|
|
have registered.
|
|
|
|
\subsection{shared and private data-structure}
|
|
This section briefly describes which of above data-structures are
|
|
private and which of them are shared with other entities.
|
|
|
|
\subsubsection{Private data-structures}
|
|
The producer maintains lot of state in private data-structures. It
|
|
includes following.
|
|
\begin{enumerate}
|
|
\item List of consumers connected. This list also maintains the
|
|
state of each consumer with respect to the communication with
|
|
producer.
|
|
\item List of shared-pool-meta-data. This meta-data includes
|
|
following information.
|
|
\begin{enumerate}
|
|
\item Consumers having access to this shared-pool.
|
|
\item meta-slot structure containing private information about
|
|
state of each slot in this shared-pool.
|
|
\item List of free slots in this shared-pool.
|
|
\item The generator-queue which is used by generator to create
|
|
data-elements is shared with generator. But as we treat generator as
|
|
internal entity, we mark this as private data instead of shared
|
|
data.
|
|
\end{enumerate}
|
|
\end{enumerate}
|
|
|
|
\subsubsection{Shared data-structures}
|
|
The producer shares following data-structures with different entities.
|
|
\begin{enumerate}
|
|
\item Shared-pools can be shared with any consumer.
|
|
\item For every consumer, a consumer-queue (see
|
|
\ref{sec:consumer-queue}) is pairwise shared with that consumer.
|
|
\end{enumerate}
|
|
|
|
\section{Consumer}
|
|
This section describes the internals of the consumer. Consumer mainly
|
|
consist of a consumer-queue data-structure which allows sharing of
|
|
slots between producer and consumer. Consumer also has read-only
|
|
access to the shared-pools.
|
|
|
|
|
|
\subsection{Consumer-queue}
|
|
\label{sec:consumer-queue}
|
|
This section describes the consumer-queue in details.
|
|
The consumer-queue is a shared data-structure between consumer and
|
|
producer and it is exclusive between each pair of consumer-producer.
|
|
This data-structure is also maintained on contiguous shared memory
|
|
which is read/writable by both consumer and producer. This
|
|
data-structure is shared ring-buffer with few virtual-registers
|
|
which are used to manage the access the ring-buffer.
|
|
|
|
\begin{enumerate}
|
|
\item \textbf{write-register:} This virtual register is the first
|
|
element in the consumer-queue. This element should be of size
|
|
cache-line to avoid any cache-conflicts. This element can be
|
|
modified only by the producer and consumer can only read it.
|
|
The value in this virtual-register contains the write-index for
|
|
consumer-queue. \textit{The write-index points to the slot-pointer within
|
|
consumer-queue that producer will provide next.}
|
|
|
|
\item \textbf{read-register:} This virtual register is the second
|
|
element in the consumer-queue. This element should be of size
|
|
cache-line to avoid any cache-conflicts. This element can be
|
|
modified only by the consumer and producer can only read it.
|
|
The value in this virtual-register contains the read-index for
|
|
consumer-queue. \textit{The read-index points to the slot-pointer within
|
|
consumer-queue that consumer will consume next.}
|
|
|
|
\item \textbf{queue-size-register:} This virtual register is the third
|
|
element in the consumer-queue. This element can be modified by
|
|
producer and consumer can only read it. The value in this
|
|
virtual-register indicate the number of slot-pointers which are
|
|
valid in the consumer-queue. This register allows dynamic adjustment queue-size
|
|
based on the current load. Similar feature is implemented in the
|
|
\textit{beltway buffers} with the claim that keeping the size of
|
|
queue as small as possible helps in cache friendliness. This
|
|
feature is actually optional and will be added in later stages.
|
|
To implement this feature, one also need to made decision like when
|
|
the queue size should be reduced and when it should be increased
|
|
again. Producer can make these decisions based on how much
|
|
preference it wants to give to this particular consumer over others.
|
|
|
|
\item \textbf{Slot-pointers:} After above three registers, the rest
|
|
of the space in consumer-queue is used for storing slot-pointers.
|
|
The slot pointers are used to point a particular slot in one of the
|
|
shared-pools within production-pool of the producer.
|
|
Slot-pointers have following information.
|
|
\begin{enumerate}
|
|
\item \texttt{shared-pool-id:} Id of the shared-pool which is
|
|
holding this particular slot. These id's are given by the
|
|
producer and will be unique within that particular producer for given
|
|
shared-pool. As the shared-pools within particular
|
|
producer may increase/decrease over time, the consumer may receive
|
|
a slot-pointer with shared-pool-id which it has not mapped yet.
|
|
In such a case, it should send a message to producer asking for
|
|
read-only access to this new shared-pool and then map it into
|
|
the virtual address-space. Once the shared memory frame
|
|
associated with shared-pool memory is mapped, consumer can
|
|
continue to access the slot using slot-pointer.
|
|
\item \texttt{slot-index:} The index of slot within that
|
|
shared-buffer. This value is only useful for producer as this
|
|
slot-index maps into the meta-slot structure which is private to
|
|
the producer. Consumer should not alter this value. In case
|
|
malicious consumer alters this value, the producer will be able
|
|
to detect it as meta-slot structure maintains the information
|
|
about which all consumers are currently consuming the slot and
|
|
whenever the producer reclaims the slots freed by consumer, it
|
|
validates if this consumer was consuming the slot being released.
|
|
The reason for maintaining this information in slot-index even
|
|
when it is not useful to consumer is because it speeds up the
|
|
producer in relocating the slot within shared-pool when it is
|
|
freed by the consumer.
|
|
\item \texttt{Offset:} The start of the slot within shared-buffer.
|
|
In case of fixed size slot, offset can be calculated by
|
|
slot-index.
|
|
\item \texttt{More:} As the data-element can span more than one
|
|
slots, this flag tells us if there are more slot-pointers
|
|
following which belongs to same data-element. This flag is
|
|
equivalent to the \textbf{More Fragments} bit in the \textbf{IP
|
|
protocol}. In contrast to IP protocol there is no fragment
|
|
identification number, but the slot-pointers belonging to same
|
|
data-elements are assumed to follow each other. So, the order in
|
|
which the slot-pointers are added to the consumer-queue is
|
|
important. As we have only one producer which is adding the
|
|
slot-pointers in \textit{available to consume} section and also
|
|
this producer is dealing with one data-element at one time,
|
|
maintaining this order is fairly simple.
|
|
\end{enumerate}
|
|
|
|
\end{enumerate}
|
|
|
|
|
|
\subsubsection{Conditions on consumer-queue registers}
|
|
|
|
\begin{enumerate}
|
|
\item Queue empty condition: read-index == write-index
|
|
\item Queue full condition: ((write-index + 1) \% size) == read-index
|
|
\item Elements available to consume \newline
|
|
(assuming queue not empty):\newline
|
|
if (write-index $>$ read-index) \newline
|
|
then \{[read-index, (write-index - 1)]\} \newline
|
|
else \{[read-index, (size - 1)], [0, (write-index - 1)]\} \newline
|
|
\item Elements which are already consumed and are now free. \newline
|
|
(assuming queue not empty): \newline
|
|
if (write-index $>$ read-index) \newline
|
|
then \{[write-index, (size - 1)], [0, (read-index - 1)]\} \newline
|
|
else \{[write-index, (read-index - 1)]\} \newline
|
|
\end{enumerate}
|
|
|
|
\subsection{shared and private data-structure}
|
|
This section briefly describes which of above data-structures are
|
|
private and which of them are shared with other entities.
|
|
|
|
\subsubsection{Private data-structures}
|
|
The consumer does not have to maintain lot of private state based on
|
|
which model of slot-consumption is used (refer
|
|
\ref{sec:memory-management}). When doing out-of-order consumption
|
|
it will have to maintain some state about which slots are in
|
|
consumption and which slots are free and ready to go back to producer.
|
|
Every consumer will also need some private state to remember the state
|
|
of the producer and the consumer-queue status. If this consumer is
|
|
directly communicating with other consumers then it will also need
|
|
to maintain some private state about that communication (refer
|
|
\ref{slot-forward}).
|
|
|
|
|
|
\subsubsection{Shared data-structures}
|
|
The consumer shares following data-structures with producer and other
|
|
consumers.
|
|
\begin{enumerate}
|
|
\item The shared-pool that it has contributed to producer and
|
|
potentially shared with all consumers.
|
|
\item The consumer-queue is exclusively shared with producer.
|
|
\end{enumerate}
|
|
|
|
|
|
|
|
\section{Events/notification/communication between consumer and
|
|
producer}
|
|
This section describes the communication between the consumer and the
|
|
producer.
|
|
|
|
\subsection{From Producer to Consumer}
|
|
This paragraph describes the events sent by producer to
|
|
consumers.
|
|
|
|
\begin{enumerate}
|
|
\item \textbf{More data arrived:} This notification is sent to
|
|
consumer whenever the consumer-queue is empty and new data-element
|
|
arrived. This callback is not triggered for every arrival of data,
|
|
but only when consumer is not explicitly polling for data. Whenever
|
|
new data arrives on the empty queue, producer can assume that
|
|
consumer is not polling the channel as queue is empty, and hence
|
|
producer should send this notification to consumer to wake it up.
|
|
In other case where queue is non-empty, consumer is already aware of
|
|
the presence of data-elements there. Consumers are expected to
|
|
deal with dynamically growing of queue-size and hence adding
|
|
more elements to non-empty queue without sending explicit
|
|
notifications should not break the consumer-logic.
|
|
|
|
\item \textbf{Consumer-queue full:} This notification is sent to
|
|
consumer whenever consumer-queue is full and producer is not able
|
|
to add new data-elements to the consumer-queue. Triggering of this
|
|
notification means that consumer is slow in consuming the data from
|
|
the consumer-queue. And result of this producer is going to drop
|
|
the data-elements which were aimed for this consumer till there
|
|
is more free space with this consumer. This message also means that
|
|
producer is not going to actively check if consumer-queue has a free
|
|
space or not. It is a responsibility of consumer to send
|
|
a notification to the producer whenever it is ready to receive more
|
|
data.
|
|
|
|
\item \textbf{Consumer-queue almost full:} This is an optional
|
|
notification and is designed as refinement of the basic approach.
|
|
This additional event can be
|
|
called when the number of free slot-pointers in the queue drops bellow
|
|
certain threshold. This notification can be used as a warning sign
|
|
to the consumer that either it takes some action to free up more
|
|
slot-pointers in consumer-queue, or producer will soon start dropping the
|
|
data-elements addressed to this consumer.
|
|
|
|
\item \textbf{Error event:} This notification is sent when something
|
|
unexpectedly goes wrong. The information and severity of the error
|
|
will inform the consumer that if the problem is transient or
|
|
permanent. And based on the problem type, consumer can take
|
|
corrective actions. Few samples of these errors are corruption of
|
|
consumer-queue, fetal error in producer, etc.
|
|
|
|
\item \textbf{Add shared-pool:} This is an optional notification which
|
|
allow producer to push the notifications about newly added
|
|
shared-pools. This message is optional because consumers
|
|
can lazily ask for these new shared-pools whenever they
|
|
encounter them as part of slot-pointer while consuming
|
|
data-elements. This notification is not considered as part of
|
|
critical path or part of the data-flow. This notification will be
|
|
generated only on the arrival of new consumer or if producer decides
|
|
to increase the available shared-pools. This can be classified as
|
|
setup or maintenance path.
|
|
|
|
\item \textbf{Remove shared-pool:} This notification is opposite of above
|
|
\textit{add shared-pool} call. It tells consumer is that producer
|
|
will not be using a particular shared-pool from now onwards
|
|
for whatever reason (eg. the consumer which gave that shared-pool
|
|
frame has terminated the connection with producer). So, every
|
|
consumer which receives this message should remove the mapping for
|
|
shared-pool from it's virtual memory. This notification is
|
|
also relatively rare and will be generated only when one of the
|
|
consumer decides to quit or if producer decides to reduce the number
|
|
of available shared-pool. So, this notification should not
|
|
be considered as part of critical-path or data-flow. It can be
|
|
classified into setup or maintenance path.
|
|
\end{enumerate}
|
|
|
|
\subsection{From Consumer to Producer}
|
|
This paragraph describes the notifications sent by consumer to the
|
|
producer.
|
|
|
|
\begin{enumerate}
|
|
\item \textbf{Consumer-queue space available:} This notification is
|
|
sent to the producer when consumer-queue is full and new free slot-pointer is
|
|
added creating new space. Once the queue is full, producer is not expected to check
|
|
the queue status until it receives this message saying that now
|
|
application has more space to receive packet. As an optimization,
|
|
consumer might wait till some more free-space is accumulated before
|
|
informing the producer to re-start the flow. This way the
|
|
inefficiency similar to \textit{silly window behavior} in TCP
|
|
flow control can be avoided.
|
|
|
|
\item \textbf{Get frame for shared-pool-id:} This notification is
|
|
sent to the producer when consumer receives a slot-pointer with
|
|
shared-pool-id which is not mapped by this consumer yet. By
|
|
sending this notification, consumer is asking for the read-only
|
|
access to this shared-pool. The producer should respond to
|
|
this message with either with valid capability or with error.
|
|
|
|
\item \textbf{Forwarding slot-pointer to other consumer:}
|
|
\label{slot-forward}
|
|
This message is related to the ability of consumers to forward
|
|
slot-pointers within each other. There are two cases here. In
|
|
first case, the consumer forwards the slot-pointer to other
|
|
consumer and then also collects it back before declaring it as free.
|
|
In this case, producer does not need to be informed at-all about
|
|
this sharing as consumer is taking responsibility of properly
|
|
freeing the slot. But in case where consumer just wants to forward the
|
|
slot-pointer and continue on it's own working without bothering
|
|
about when and how other consumer is going to stop accessing
|
|
that slot, then it should inform the producer that it has forwarded
|
|
that slot to some other consumer. It can be done with this
|
|
message. The reason we need this separate message is that,
|
|
because of sharing there will be two consumers which will be
|
|
releasing the slots and producer should be aware of them.
|
|
The information from this message is used to update the
|
|
meta-slot structure inside producer for given slot with one more consumer.
|
|
This message contains the slot identification information
|
|
and consumer identification information. The other consumer can
|
|
now release the slot whenever it is done using it's consumer-queue,
|
|
and producer can validate and account that operation correctly.
|
|
|
|
|
|
This forwarding has some more implications which are not fully
|
|
explored in this document. Here are few leads on that. Firstly,
|
|
this path allows consumer to receive the slots without being
|
|
initiated by producer and this slot will not be a part of
|
|
consumer-queue. So, the producer need to somehow account for these
|
|
slots so that it can maintain the fairness in the number of
|
|
outstanding slots per consumer. This mechanism also needs some way
|
|
by which two consumers can talk with each other and exchange the
|
|
information like consumer-id's, producer-id and slot-pointers.
|
|
Also, consumers should be careful in dealing this information as
|
|
consumer-id and slot-pointers are only valid in context of particular
|
|
producer.
|
|
\end{enumerate}
|
|
|
|
|
|
\subsection{The communication between producer and generator}
|
|
The communication between producer and generator is very
|
|
hardware dependent, and I am not sure if it should be part of this
|
|
document. Following are the generic notifications which are exchanged
|
|
between the producer and generator. These notifications are aimed to
|
|
maintain the generator-queue.
|
|
|
|
\begin{enumerate}
|
|
\item Add empty slot (from producer to generator): This message will
|
|
add a new free slot into generator-queue.
|
|
\item Data-element generated (from generator to producer): This
|
|
message informs the producer that there is new data-element in the
|
|
generator queue that should be handled. It is equivalent of
|
|
\textit{packet received interrupt} from NIC hardware to the device
|
|
driver.
|
|
\item Generator-queue full (from generator to producer): This
|
|
message tells the producer that there is no space left for generator
|
|
to create more data-elements.
|
|
\end{enumerate}
|
|
|
|
\subsection{The communication between consumers}
|
|
TBD: The communication between consumers is needed to share the
|
|
slot-pointers between them.
|
|
|
|
\section{Initialization}
|
|
\label{sec:initialization}
|
|
This section briefly provides the steps involved in initialization of
|
|
producer and consumers.
|
|
|
|
\subsection{Producer initialization}
|
|
At producer initialization, following steps will happen.
|
|
\begin{enumerate}
|
|
\item Create and initialize the empty list of shared-pools and meta-slots.
|
|
\item Create and add the initial shared-pool big enough to satisfy
|
|
generator needs.
|
|
\item Divide the shared-pool into slots, create a meta-slots list
|
|
for this shared-pool and add it to meta-slots list.
|
|
\item Create an empty list of consumers.
|
|
\item Initialize the generator (if needed). This might involve
|
|
populating the generator-queue with free slots so that generator can
|
|
start producing data.
|
|
\item Loop: wait for next event/message and process it accordingly.
|
|
\end{enumerate}
|
|
|
|
|
|
|
|
\subsection{Consumer registration}
|
|
As part of initialization process, consumer should register itself
|
|
with the producer. This initialization process includes following
|
|
steps.
|
|
\begin{enumerate}
|
|
\item Create a new contiguous memory frame and provide it to
|
|
producer as new shared-pool frame.
|
|
\item Get the list of registered shared-pools from producer and
|
|
map it as read-only in the virtual address-space of consumer.
|
|
\item Create a new contiguous memory block to maintain a
|
|
consumer-queue.
|
|
\item Initialize this memory block with consumer-queue
|
|
data-structure.
|
|
\item Share this memory block with producer.
|
|
\item Send a notification \textit{consumer-queue space available} to
|
|
the producer so that it will start sending data-elements.
|
|
\item Loop: wait for next event/message and process it accordingly.
|
|
\end{enumerate}
|
|
|
|
|
|
|
|
\section{Memory management (slot management)}
|
|
\label{sec:memory-management}
|
|
The slots are most important aspect of this bulk transport mechanism.
|
|
They hold the data which will be sent across the domains. Now lets
|
|
see how exactly these slots work.
|
|
|
|
|
|
\subsection{Slot state machine}
|
|
Slots are created by the producer in the memory provided by
|
|
shared-pools. Once created, slot remains valid until and unless the
|
|
shared-pool holding the slot needs to be freed. In the lifetime of
|
|
the slot, it goes through following states.
|
|
\begin{enumerate}
|
|
\item \textbf{Free:} This is the initial state, in this state slot
|
|
is free and ready to be used. The producer maintains a list of free
|
|
slots so that it can quickly find them whenever they are needed.
|
|
|
|
\item \textbf{In-generation:} This is the second stage of slot. In
|
|
this state, the slot is owned by the generator and no one should
|
|
access it(not even in read state!). This is the only state in which
|
|
the data will be written into the slot.
|
|
|
|
\item \textbf{In-classification:} This is the third and transient
|
|
state. This is the state when generator returns the slot after it
|
|
has generated the data. The producer will use the classification to
|
|
figure out which consumers this data-element should go. The
|
|
producer is free to use any type of classification that is needed.
|
|
The description of how that classification should happen is not in
|
|
the scope of this document. Once classified, the producer will
|
|
update the consumer-queues of each selected consumer with
|
|
slot-pointer and if needed, send them the notifications. Once the
|
|
slot-pointers are added into consumer-queue, the state of slot is
|
|
updated to the \textbf{in-consumption}.
|
|
|
|
If no consumer is interested, then the slot is marked as free and
|
|
added back to the list of free slots.
|
|
|
|
|
|
This is the stage where \textbf{zero copy data access} is achieved.
|
|
As instead of actually copying the data from the slot, slot-pointers
|
|
are provided to the consumers. These slot-pointers provide
|
|
zero-copy access and data-sharing capabilities.
|
|
|
|
|
|
\item \textbf{In-consumption:} This is the state in which data is
|
|
available to the consumers. Here, consumer has multiple options
|
|
about what to do with this slot.
|
|
\begin{itemize}
|
|
\item \textbf{In-order consumption:}
|
|
Consume the slot as quickly as possible, and once consumed
|
|
add it to freed slot by moving the read-index.
|
|
As consumer is dealing with one data-element at a time,
|
|
there is no need for complex state management and
|
|
free-slot management inside consumer-queue is sufficient enough
|
|
without needing any additional state machinery.
|
|
|
|
|
|
\item \textbf{Out-of-order consumption:}
|
|
Saves the newly arrived slot-pointer and replace it with one of
|
|
the other slot-pointers which has been previously consumed and then add this
|
|
replaced slot to freed slot by moving the read index. This method
|
|
allows you to consume the slots at leisure and you can have more
|
|
than one data-elements in consumption at any given moment of time.
|
|
It also allows you to
|
|
free up the slots which don't hold useful data quickly and release
|
|
the slots with important data later on. This method gives much
|
|
more flexibility but at cost of added free-slot management within
|
|
consumer. As consumer is releasing the slot in out-of-order of
|
|
their consumption, it has to maintain some state about which slots
|
|
are released and which are still in consumption.
|
|
|
|
\item \textbf{Private-mutable consumption:}
|
|
If the application needs a private access to the slots where it
|
|
can modify it then it should make copy of this slot in it's
|
|
private memory and release the actual slot. This way, application
|
|
is free to do anything it wants with the private slot. This
|
|
solution scales well with large number of private-mutable
|
|
consumers because the data-copy operation is performed by
|
|
consumers and not by producer. As data-copy operation is
|
|
typically most expensive, we want to push it out from producer
|
|
into consumers. If consumers are running on separate cores then
|
|
the data-copy operation of one consumer will not affect other
|
|
consumers.
|
|
\end{itemize}
|
|
|
|
|
|
Once the consumer is done with consumption, the slot will be
|
|
returned to the producer. And when all consumers who are sharing
|
|
the slot report that they are done with consumption then producer
|
|
can mark the slot as free and add it to the list of free slots for
|
|
future reuse.
|
|
\end{enumerate}
|
|
|
|
\subsection{Slot management inside producer}
|
|
The producer maintains a private meta-slot data-structure for each
|
|
slot to track these slots. It also maintains the list of free,
|
|
in-generation and in consumption slots.
|
|
|
|
\subsection{Slot management inside consumer}
|
|
The slot management is not needed in consumer if they are following
|
|
in-order or private-mutable consumption. In these two cases, the
|
|
consumer-queue implicitly does the slot management on behalf of consumers.
|
|
|
|
In case of out-of-order consumption, the consumer will have to
|
|
maintain the list of all slot-pointers which are currently accessible
|
|
and also the list of slot-pointers which are done with the use and can
|
|
be released as free slots.
|
|
|
|
\subsection{Freeing up the slots}
|
|
Whenever consumer is done with accessing/consuming the data-element,
|
|
it should be added back to the free-slot-pointers area of the consumer
|
|
queue. It is important to note that the order in which slots will be
|
|
freed by consumer need not match the order in which it consumed the
|
|
slots. This flexibility allows consumer to take longer time on
|
|
certain slots while quickly returning the slots which have arrived
|
|
afterwards. Consumer can hold back certain number of slots without
|
|
releasing them, but this number depends on the length of the consumer
|
|
queue. As the producer controls the consumer-queue length it can give
|
|
some consumers more slots than other based on the configurable
|
|
policies. The policy that initial implementation of this buffer will
|
|
be using is that, the size of consumer-queue will be directly
|
|
proportional to the size of shared-pool that particular consumer has
|
|
contributed.
|
|
|
|
\subsection{Slot size}
|
|
\label{sec:slotsize}
|
|
The size of the slot is greatly dictated by the capabilities of the
|
|
generator. If generator needs
|
|
continuous memory to produce data-element then the size of
|
|
slot will be the size of biggest data-element. If the
|
|
generator can DMA the data-element into multiple non-contiguous
|
|
memory locations then, the slot size should be based on
|
|
the average data-element size. In any case, the slot size
|
|
must alway be a multiple of cache size and every slot should
|
|
be cache aligned. This is mostly due to the fact that each
|
|
data element might get consumed by different consumer running
|
|
on different cores, and we do not want cache conflicts when
|
|
they are accessing different data-elements.
|
|
|
|
|
|
The dis-advantage of having slots of size of largest data-element
|
|
is that it leads to internal fragmentation and waste of memory
|
|
when packets are small. On other hand, when slot size is small,
|
|
we reduce the capacity of NIC hardware as typically RX-queue
|
|
will have limited number of entries, and by using small sized
|
|
slots, we will fill up the entries quickly.
|
|
|
|
\section{Security and trust model}
|
|
\label{sec:security-trust}
|
|
This section discusses the trust model assumed by this bulk transport
|
|
design and it's security implications.
|
|
|
|
\subsection{Slot access security}
|
|
\label{sec:slot-security}
|
|
This bulk transport mechanism works by sharing the memory and it
|
|
needs security against invalid memory accesses. This security is
|
|
provided by the slot-pointers. Slot-pointers are designed to be valid
|
|
across the virtual address-spaces of all consumers. Slot-pointers
|
|
contain information like shared-pool-id which can be used to find the
|
|
starting address and length of the pool. When consumer is calculating
|
|
actual pointer, it can always validate that the pointer lies within
|
|
shared-pool by making sure that offset is always smaller than
|
|
shared-pool size.
|
|
|
|
\subsection{Security against memory invalidation}
|
|
\label{sec:memory-security}
|
|
The more problematic case is when one of the consumer dies or
|
|
invalidate the memory given to producer without informing first.
|
|
This case can lead to invalid memory access in producer,
|
|
generator and other consumers as one of the shared-pool is not
|
|
accessible any longer. The protection against such a case
|
|
should be provided by operating system by not removing the memory
|
|
frame as long as it is mapped by at-least one domain/process. If
|
|
operating system does not provide such an assurance and if the
|
|
consumers are non-trustworthy then producer should somehow take the
|
|
complete ownership of the memory provided by the consumer, or provide
|
|
all the memory itself.
|
|
|
|
|
|
From above discussion, it can be seen that the trust mainly lies with
|
|
producer and not the consumer. Consumers can't do much damage to
|
|
producer as all the actions of consumers can be validated by the
|
|
producer. For example, when any consumer tries to free up the slot,
|
|
the producer can verify if the consumer really holds that slot or not.
|
|
|
|
|
|
\subsection{Security against data sniffing}
|
|
\label{sec:security-sniffing}
|
|
The only damage that consumer can do is to try and read the
|
|
data-elements which are not destined to it. Consumers can do this
|
|
as they have read-only access to entire production-pool. Performing
|
|
this type of snooping is not trivial as all the meta-data about the
|
|
slots is maintained in the private memory by the producer, so consumer
|
|
can only guess about location and type of data inside the other
|
|
visible slots. But nevertheless unauthorized data-sniffing between
|
|
consumers is theoretically possible in this design.
|
|
|
|
This shortcoming can be overcome by sharing the shared-pool pairwise
|
|
between consumer and producer and then by either adding the overhead
|
|
of performing data-copy, or by using generator capability to perform
|
|
early classification of data elements. The \ref{sec:privacy} will
|
|
give more details about these stricter privacy models.
|
|
|
|
\section{Privacy model}
|
|
\label{sec:privacy}
|
|
This bulk transport is designed to work in relaxed privacy model with
|
|
possibility of tightening the privacy model by either using early
|
|
classification capabilities of generator or at added cost of
|
|
data-copy. This section describes all of these modes.
|
|
|
|
\subsection{Relaxed privacy model}
|
|
\label{sec:relaxed-privacy}
|
|
The bulk-transport design described most of the above document is
|
|
based the relaxed privacy model. The reason for describing this model
|
|
in detail is that other models which gives better privacy (described
|
|
in \ref{sec:data-copy-privacy},
|
|
\ref{sec:generator-classification-privacy}) are sub-set of this model
|
|
hence they are easy to understand once this model is clear.
|
|
In this model, all consumers have read-only access to entire
|
|
production-pool. And hence in theory malicious consumers can sniff the
|
|
data-elements addressed to other consumers. The
|
|
\ref{sec:security-sniffing} gives some description of this issue from
|
|
the security perspective.
|
|
|
|
|
|
\subsection{Strict privacy model with additional data-copy}
|
|
\label{sec:data-copy-privacy}
|
|
In this model, shared-pools are not shared with all consumers, but
|
|
every shared-pool is pairwise shared between producer and with only
|
|
one consumer (one who has contributed that shared-pool). The initial
|
|
shared-pool contributed by the producer itself is shared between
|
|
producer and generator. This shared-pool will not be directly
|
|
accessible to any consumer. All the data generated in this pool which
|
|
is private to producer and generator and then based on the
|
|
classification of the data-element, it is explicitly copied into the
|
|
shared-pool of the selected consumers. This way, other consumers can
|
|
never see the data-elements which are not destined to them. This
|
|
stricter privacy policy comes with the cost of additional data-copy.
|
|
Also, as producer is performing this data-copy, this can adversely
|
|
affect the throughput of the whole system.
|
|
|
|
|
|
\subsection{Strict privacy model with early classification support
|
|
from generator}
|
|
\label{sec:generator-classification-privacy}
|
|
In this model as well, shared-pools are not shared with all
|
|
consumers, but every shared-pool is shared between
|
|
producer and with only one consumer.
|
|
This model depends on the capabilities of generator to provide
|
|
stricter privacy model. If the generator is smart enough and can
|
|
classify the data-elements before they are created, then these
|
|
data-elements can be directly created into the shared-pool of selected
|
|
consumer. This avoids additional copy from the producers pool to the
|
|
shared-pool of the consumer.
|
|
|
|
This is an ideal model which provides strict privacy without
|
|
compromising on the performance. But it needs smarter generators.
|
|
The recent NIC hardwares like \textbf{Solarflair} and \textbf{e10000}
|
|
are capable of performing such a classification.
|
|
|
|
|
|
\section{Adaptability with different hardware}
|
|
This section discusses the ability of this design to
|
|
adapt with different designs and features of NIC hardwares.
|
|
We believe that the interface
|
|
provided by the producer is generic enough to cover most of the
|
|
functionalities provided by the smarter generators. And as we can
|
|
control the integration between producer and generator without affecting
|
|
the consumers, we can easily adapt to exploit the different hardware
|
|
features provided by the generators. One of the example of such an
|
|
adaptation can be seen in \ref{sec:generator-classification-privacy},
|
|
the design discussed here easily adapted to exploit the early
|
|
classification capabilities of the generator to give stricter privacy
|
|
based zero copy bulk transport.
|
|
|
|
\section{Limitations}
|
|
This design still misses some good features in favor of keeping the
|
|
complexity reasonable. These features include support for
|
|
multiple-producer, multiple-consumer setup and ability for consumer to
|
|
specify where data-element should be generated (true zero copy
|
|
receive).
|
|
|
|
\section{Conclusion}
|
|
This chapter provides the details about the new cross-domain transfer
|
|
facility design. This facility allows zero-copy network
|
|
implementation which can support sharing between more than two domains
|
|
as well as multi-level sharing (sharing by consumers between
|
|
consumers). This solution also reduce the number of messages
|
|
exchanged by sending them only when it is absolutely necessary.
|
|
|
|
|
|
\end{document}
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
|
|
|