Completed first stage of PPI API specification
[senf.git] / PPI / Mainpage.dox
1 // Copyright (C) 2007 
2 // Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
3 // Kompetenzzentrum fuer Satelitenkommunikation (SatCom)
4 //     Stefan Bund <g0dil@berlios.de>
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 2 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the
18 // Free Software Foundation, Inc.,
19 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20
21 /** \mainpage libPPI : The Packet Processing Infrastructure
22
23     The PPI provides an infrastructure to create packet oriented network processin
24     applications. A PPI application is built by combining processing modules in a very flexible
25     manner.
26
27     \image html scenario.png Target Scenario
28     
29     The PPI concept is built around some key concepts
30
31     \li The PPI is based on processing \ref packets. It does not handle stream oriented channels.
32     \li The PPI is built around reusable \ref modules. Each module is completely independent.
33     \li Each module has an arbitrary number of \ref connectors, inputs and outputs.
34     \li The modules are connected to each other using flexible \ref connections.
35     \li Data flow throughout the network is governed via flexible automatic or manual \ref throttling.
36     \li Modules may register additional external \ref events (file descriptor events or timers).
37     
38     The PPI thereby builds on the facilities provided by the other components of the SENF
39     framework. 
40
41     Modules are divided roughly in to two categories: I/O modules provide packet sources and sinks
42     (network connection, writing packets to disk, generating new packets) whereas processing modules
43     process packets internally.  The target scenario above depicts a diffserv capable UDLR/ULE
44     router including performance optimizations for TCP traffic (PEP). This router is built by
45     combining several modules. In this scenario, <em>TAP</em>, <em>ASI Out</em>, <em>Raw Socket</em>
46     and in a limited way <em>Generator</em> are I/O modules whereas <em>PEP</em>, <em>DiffServ</em>,
47     <em>DVB Enc</em>, <em>GRE/UDLR</em>, <em>TCP Filter</em> and <em>Stuffer</em>are processing
48     modules. <em>ASI/MPEG</em> and <em>Net</em> are external I/O ports which are integrated via the
49     <em>TAP</em>, <em>ASI Out</em> and <em>Raw Sock</em> modules using external events.
50
51     \section design Design considerations
52
53     The PPI interface is designed to be as simple as possible. It provides sane defaults for all
54     configurable parameters to simplify getting started. It also automates all resource
55     management. Especially to simplify resource management, the PPI will take many configuration
56     objects by value. Even though this is not as efficient, it frees the user from most resource
57     management chores. This decision does not affect the runtime performance since it only applies
58     to the configuration part.
59
60     \section packets Packets
61
62     The PPI processes packets and uses the <a href="@TOPDIR@/Packets/doc/html/index.html">Packet
63     library</a> to handle them. All packets are passed around as generic Packet::ptr's, the PPI
64     does not enforce any packet type restrictions.
65
66     \section modules Modules
67
68     A module is represented by a class type. Each module has several components:
69
70     \li It may have any number of connectors (inputs and outputs)
71     \li Each module declares flow information which details the route packets take within the
72         module. This information does not define how the information is processed, it only tells,
73         where data arriving on some input will be directed at.
74     \li The module might take additional parameters.
75     \li The module might also register additional events.
76
77     \code
78       class RateStuffer 
79           : public senf::ppi::Module
80       {
81       public:
82           ActiveInput payload;
83           ActiveInput stuffing;
84           ActiveOutput output;
85
86           RateStuffer(unsigned packetsPerSecond)
87           {
88               route(payload, output);
89               route(stuffing, output);
90
91               registerEvent(&RateStuffer::tick, 
92                             senf::ppi::IntervalTimer(1000u, packetsPerSecond));
93           }
94
95       private:
96           void tick()
97           {
98               if (payload)
99                   output(payload());
100               else
101                   output(stuffing());
102           }
103       };
104     \endcode
105
106     This module declares three I/O connectors (see below): <tt>payload</tt>, <tt>stuffing</tt> and
107     <tt>output</tt>. These connectors are defined as <em>public</em> data members so they can be
108     accessed from the outside. This is important as we will see below.
109
110     On module instantiation, it will declare it's flow information with <tt>route</tt> (which
111     is inherited from <tt>senf::ppi::Module</tt>). Then the module registers an interval timer which
112     will fire <tt>packetsPerSecond</tt> times every <tt>1000</tt> milliseconds.
113
114     The processing of the module is very simple: Whenever a timer tick arrives a packet is sent. If
115     the <tt>payload</tt> input is ready (see throttling below), a payload packet is sent, otherwise
116     a stuffing packet is sent. The module will therefore provide a constant stream of packets at a
117     fixed rate on <tt>output</tt>
118     
119     An example module to generate the stuffing packets could be
120
121     \code
122       class CopyPacketGenerator
123           : public senf::ppi::Module
124       {
125       public:
126           PassiveOutput output;
127
128           CopyPacketGenerator(Packet::ptr template)
129               : template_ (template)
130           {
131               noroute(output);
132               output.onRequest(&CopyPacketGenerator::makePacket);
133           }
134
135       private:
136           Packet::ptr template_;
137
138           void makePacket()
139           {
140               output(template_.clone());
141           }
142       };
143     \endcode
144
145     This module just produces a copy of a given packet whenever output is requested.
146
147     \section connectors Connectors
148     
149     Inputs and Outputs can be active and passive. An \e active I/O is <em>activated by the
150     module</em> to send data or to poll for available packets. A \e passive I/O is <em>signaled by
151     the framework</em> to fetch data from the module or to pass data into the module.
152
153     To send or receive a packet (either actively or after packet reception has been signaled), the
154     module just calls the connector. This allows to generate or process multiple packets in one
155     iteration. However, reading will only succeed, as long as packets are available from the
156     connection.
157
158     Since a module is free to generate more than a single packet on incoming packet requests, all
159     input connectors incorporate a packet queue. This queue is exposed to the module and allows the
160     module to process packets in batches.
161
162     \section connections Connections
163
164     To make use of the modules, they have to be instantiated and connections have to be created
165     between the I/O connectors. It is possible to connect any pair of input/output connectors as
166     long as one of them is active and the other is passive.
167     
168     It is possible to connect two active connectors with each other using a special adaptor
169     module. This Module has a passive input and a passive output. It will queue any incoming packets
170     and automatically handle throttling events (see below). This adaptor is automatically added by
171     the connect method if needed.
172
173     To complete our simplified example: Lets say we have an <tt>ActiveSocketInput</tt> and a
174     <tt>PassiveUdpOutput</tt> module. We can then use our <tt>RateStuffer</tt> module to build an
175     application which will create a fixed-rate UDP stream:
176
177     \code
178       RateStuffer rateStuffer (10);
179
180       senf::Packet::ptr stuffingPacket = senf::Packet::create<...>(...); 
181       CopyPacketGenerator generator (stuffingPacket);
182
183       senf::UDPv4ClientSocketHandle inputSocket (1111);
184       senf::ppi::ActiveSocketInput udpInput (inputSocket);
185
186       senf::UDPv4ClientSocketHandle outputSocket ("2.3.4.5:2222");
187       senf::ppi::PassiveSocketOutput udpOutput (outputSocket);
188
189       senf::ppi::connect(udpInput.output, rateStuffer.payload, 
190                          dynamicModule<PassiveQueue>()
191                              -> qdisc(ThresholdQueueing(10,5)) );
192       senf::ppi::connect(generator.output, rateStuffer.stuffing);
193       senf::ppi::connect(rateStuffer.output, udpOutput.input);
194
195       senf::ppi::run();
196     \endcode
197
198     First all necessary modules are created. Then the connections between these modules are set
199     up. The buffering on the udpInput <-> rateStuffer adaptor is changed so the queue will begin to
200     throttle only if more than 10 packets are in the queue. The connection will be unthrottled as
201     soon as there are no more than 5 packets left in the queue. This application will read
202     udp-packts coming in on port 1111 and will forward them to port 2222 on host 2.3.4.5 with a
203     fixed rate of 10 packets / second.
204
205     \section throttling Throttling
206
207     If a passive connector cannot handle incoming requests, this connector may be \e
208     throttled. Throttling a request will forward a throttle notification to the module connected
209     to that connector. The module then must handle this throttle notification. If automatic
210     throttling is enabled for the module (which is the default), the notification will automatically
211     be forwarded to all dependent connectors as taken from the flow information. For there it will
212     be forwarded to further modules and so on.
213
214     A throttle notification reaching an I/O module will normally disable the input/output by
215     disabling any external I/O events registered by the module. When the passive connector which
216     originated the notification becomes active again, it creates an unthrottle notification which
217     will be forwarded in the same way. This notification will re-enable any registered I/O events.
218
219     The above discussion shows, that throttle events are always generated on passive connectors and
220     received on active connectors. To differentiate further, the throttling originating from a
221     passive input is called <em>backward throttling</em> since it is forwarded in the direction \e
222     opposite to the data flow. Backward throttling notifications are sent towards the input
223     modules. On the other hand, the throttling originating from a passive output is called
224     <em>forward throttling</em> since it is forwarded along the \e same direction the data
225     is. Forward throttling notifications are therefore sent towards the output modules.
226
227     Since throttling a passive input may not disable all further packet delivery immediately, any
228     passive input contains an input queue. In it's default configuration, the queue will send out
229     throttle notifications when it becomes non-empty and unthrottle notifications when it becomes
230     empty again. This automatic behavior may however be disabled. This allows a module to collect
231     incoming packets in it's input queue before processing a bunch of them in one go.
232
233     \section events Events
234
235     Modules may register additional events. These external events are very important since the drive
236     the PPI framework. Possible event sources are
237     \li time based events
238     \li file descriptors.
239
240     Here some example code implementing the ActiveSocketInput Module:
241
242     \code
243       class ActiveSocketInput 
244           : public senf::ppi::Module
245       {
246           static PacketParser<senf::DataPacket> defaultParser_;
247
248       public:
249           ActiveOutput output;
250
251           typedef senf::ClientSocketHandle<
252               senf::MakeSocketPolicy< senf::ReadablePolicy,
253                                       senf::DatagramFramingPolicy > > Socket;
254
255           // I hestitate taking parser by const & since a const & can be bound to
256           // a temporary even though a const & is all we need. The real implementation
257           // will probably make this a template arg. This simplifies the memory management
258           // from the users pov.
259           ActiveSocketInput(Socket socket, DataParser & parser = SocketInput::defaultParser_)
260               : socket_ (socket), 
261                 parser_ (parser)
262                 event_ (registerEvent( &ActiveSocketInput::data, 
263                                        senf::ppi::IOSignaler(socket, senf::ppi::IOSignaler::Read) ))
264           {
265               route(event_, output);
266           }
267       
268       private:
269           Socket socket_;
270           DataParser const & parser_;
271           senf::ppi:IOSignaler::EventBinding event_;
272     
273           void data()
274           {
275               std::string data;
276               socket_.read(data);
277               output(parser_(data));
278           }
279       };
280     \endcode
281
282     First we declare our own socket handle type which allows us to read packets. The constructor
283     then takes two arguments: A compatible socket and a parser object. This parser object gets
284     passed the packet data as read from the socket (an \c std::string) and returns a
285     senf::Packet::ptr. The \c PacketParser is a simple parser which interprets the data as specified
286     by the template argument.
287
288     We register an IOSignaler event. This event will be signaled whenever the socket is
289     readable. This event is routet to the output. This routing automates throttling for the socket:
290     Whenever the output receives a throttle notifications, the event will be temporarily disabled.
291
292     Processing arriving packets happens in the \c data() member: This member simple reads a packet
293     from the socket. It passes this packet to the \c parser_ and sends the generated packet out.
294
295     \implementation Generation of throttle notifications: Backward throttling notifications are
296         automatically generated (if this is not disabled) whenever the input queue is non-empty \e
297         after the event handler has finished processing. Forward throttling notifications are not
298         generated automatically within the connector. However, the Passive-Passive adaptor will
299         generate Forward-throttling notifications whenever the input queue is empty.
300
301     \note Open Issues
302       \li We need to clearly differentiate between auto-throttling and auto-throttle-forwarding,
303         between a connectors own throttling state and the forwarded state.
304       \li Exception handling
305       \li ActiveInputs also need a queue: This is necessary to allow a PassiveOutput to create more
306         than a single packet from a single 'onRequest' event. This greatly simplifies writing
307         modules which produce multiple output packets for a single input packet.
308       \li We need to clear up the throttled() member semantics: If the connector is throttled, does
309         it return so if there are still packets in the queue? Probably yes. However, it does not
310         forward throttling notifications until instructed by the qdisc. Throttling notifications are
311         also bound to onThrottle/onUnThrottle callbacks. The semantics are then clear: An active
312         connector emitting onThrottle cannot process any further request (for inputs, no data will
313         be available, for outputs the data will be queued in the peer input)
314  */
315
316 \f
317 // Local Variables:
318 // mode: c++
319 // fill-column: 100
320 // c-file-style: "senf"
321 // indent-tabs-mode: nil
322 // ispell-local-dictionary: "american"
323 // mode: flyspell
324 // mode: auto-fill
325 // End: