2cd9212b636c57d55cb770443825735cd2beb7ef
[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 processing
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
36         throttling.
37     \li Modules may register additional external \ref events (file descriptor events or timers).
38     
39     The PPI thereby builds on the facilities provided by the other components of the SENF
40     framework. The target scenario above depicts a diffserv capable UDLR/ULE router including
41     performance optimizations for TCP traffic (PEP). This router is built by combining several
42     modules.
43
44     \section design Design considerations
45
46     The PPI interface is designed to be as simple as possible. It provides sane defaults for all
47     configurable parameters to simplify getting started. It also automates all resource
48     management. Especially to simplify resource management, the PPI will take many configuration
49     objects by value. Even though this is not as efficient, it frees the user from most resource
50     management chores. This decision does not affect the runtime performance since it only affects
51     the configuration step.
52
53     \section packets Packets
54
55     The PPI processes packets and uses the <a href="@TOPDIR@/Packets/doc/html/index.html">Packet
56     library</a> to handle them. All packets are passed around as generic Packet::ptr's, the PPI
57     does not enforce any packet type restrictions.
58
59     \section modules Modules
60
61     A module is represented by a class type. Each module has several components:
62
63     \li It may have any number of connectors (inputs and outputs)
64     \li Each module declares flow information which details the route packets take within the
65         module. This information does not define how the information is processed, it only tells,
66         where data arriving on some input will be directed at.
67     \li The module might take additional parameters.
68     \li The module might also register additional events.
69
70     Modules are divided roughly in to two categories: I/O modules provide packet sources and sinks
71     (network connection, writing packets to disk, generating new packets) whereas processing modules
72     process packets internally.  In the target scenario, <em>TAP</em>, <em>ASI Out</em>, <em>Raw
73     Socket</em> and in a limited way <em>Generator</em> are I/O modules whereas <em>PEP</em>,
74     <em>DiffServ</em>, <em>DVB Enc</em>, <em>GRE/UDLR</em>, <em>TCP Filter</em> and <em>Stuffer</em>
75     are processing modules. <em>ASI/MPEG</em> and <em>Net</em> are external I/O ports which are
76     integrated via the <em>TAP</em>, <em>ASI Out</em> and <em>Raw Sock</em> modules using external
77     events.
78
79     The following example module declares three I/O connectors (see below): <tt>payload</tt>,
80     <tt>stuffing</tt> and <tt>output</tt>. These connectors are defined as <em>public</em> data
81     members so they can be accessed from the outside. This is important as we will see below.
82
83     \code
84       class RateStuffer
85           : public senf::ppi::module::Module
86       {
87           senf::ppi::IntervalTimer timer_;
88
89       public:
90           senf::ppi::connector::ActiveInput payload;
91           senf::ppi::connector::ActiveInput stuffing;
92           senf::ppi::connector::ActiveOutput output;
93
94           RateStuffer(unsigned packetsPerSecond)
95               : timer_(1000u, packetsPerSecond)
96           {
97               route(payload, output);
98               route(stuffing, output);
99
100               registerEvent(&RateStuffer::tick, timer_);
101           }
102
103       private:
104           void tick()
105           {
106               if (payload)
107                   output(payload());
108               else
109                   output(stuffing());
110           }
111       };
112     \endcode
113
114     On module instantiation, it will declare it's flow information with <tt>route</tt> (which is
115     inherited from <tt>senf::ppi::module::Module</tt>). Then the module registers an interval timer
116     which will fire <tt>packetsPerSecond</tt> times every <tt>1000</tt> milliseconds.
117
118     The processing of the module is very simple: Whenever a timer tick arrives a packet is sent. If
119     the <tt>payload</tt> input is ready (see throttling below), a payload packet is sent, otherwise
120     a stuffing packet is sent. The module will therefore provide a constant stream of packets at a
121     fixed rate on <tt>output</tt>
122     
123     An example module to generate the stuffing packets could be
124
125     \code
126       class CopyPacketGenerator
127           : public senf::ppi::module::Module
128       {
129       public:
130           senf::ppi::connector::PassiveOutput output;
131
132           CopyPacketGenerator(Packet::ptr template)
133               : template_ (template)
134           {
135               noroute(output);
136               output.onRequest(&CopyPacketGenerator::makePacket);
137           }
138
139       private:
140           Packet::ptr template_;
141
142           void makePacket()
143           {
144               output(template_.clone());
145           }
146       };
147     \endcode
148
149     This module just produces a copy of a given packet whenever output is requested.
150
151     \section connectors Connectors
152     
153     Inputs and Outputs can be active and passive. An \e active I/O is <em>activated by the
154     module</em> to send data or to poll for available packets. A \e passive I/O is <em>signaled by
155     the framework</em> to fetch data from the module or to pass data into the module.
156
157     To send or receive a packet (either actively or after packet reception has been signaled), the
158     module just calls the connector. This allows to generate or process multiple packets in one
159     iteration. However, reading will only succeed, as long as packets are available from the
160     connection.
161
162     Since a module is free to generate more than a single packet on incoming packet requests, all
163     input connectors incorporate a packet queue. This queue is exposed to the module and allows the
164     module to process packets in batches.
165
166     \section connections Connections
167
168     \image html ratestuffer.png Simple RateStuffer
169
170     To make use of the modules, they have to be instantiated and connections have to be created
171     between the I/O connectors. It is possible to connect any pair of input/output connectors as
172     long as one of them is active and the other is passive.
173     
174     It is possible to connect two active connectors with each other using a special adaptor
175     module. This Module has a passive input and a passive output. It will queue any incoming packets
176     and automatically handle throttling events (see below). This adaptor is automatically added by
177     the connect method if needed.
178
179     To complete our simplified example: Lets say we have an <tt>ActiveSocketInput</tt> and a
180     <tt>PassiveUdpOutput</tt> module. We can then use our <tt>RateStuffer</tt> module to build an
181     application which will create a fixed-rate UDP stream:
182
183     \code
184       RateStuffer rateStuffer (10);
185
186       senf::Packet::ptr stuffingPacket = senf::Packet::create<...>(...); 
187       CopyPacketGenerator generator (stuffingPacket);
188
189       senf::UDPv4ClientSocketHandle inputSocket (1111);
190       senf::ppi::module::ActiveSocketReader udpInput (inputSocket);
191
192       senf::UDPv4ClientSocketHandle outputSocket ("2.3.4.5:2222");
193       senf::ppi::module::PassiveSocketWriter udpOutput (outputSocket);
194
195       senf::ppi::module::PassiveQueue adaptor;
196
197       senf::ppi::connect(udpInput.output, adaptor.input);
198       senf::ppi::connect(adaptor.output, rateStuffer.payload);
199       adaptor.qdisc(ThresholdQueueing(10,5));
200       senf::ppi::connect(generator.output, rateStuffer.stuffing);
201       senf::ppi::connect(rateStuffer.output, udpOutput.input);
202
203       senf::ppi::run();
204     \endcode
205
206     First all necessary modules are created. Then the connections between these modules are set
207     up. The buffering on the udpInput <-> rateStuffer adaptor is changed so the queue will begin to
208     throttle only if more than 10 packets are in the queue. The connection will be unthrottled as
209     soon as there are no more than 5 packets left in the queue. This application will read
210     udp-packets coming in on port 1111 and will forward them to port 2222 on host 2.3.4.5 with a
211     fixed rate of 10 packets / second.
212
213     \section throttling Throttling
214
215     If a passive connector cannot handle incoming requests, this connector may be \e
216     throttled. Throttling a request will forward a throttle notification to the module connected
217     to that connector. The module then must handle this throttle notification. If automatic
218     throttling is enabled for the module (which is the default), the notification will automatically
219     be forwarded to all dependent connectors as taken from the flow information. For there it will
220     be forwarded to further modules and so on.
221
222     A throttle notification reaching an I/O module will normally disable the input/output by
223     disabling any external I/O events registered by the module. When the passive connector which
224     originated the notification becomes active again, it creates an unthrottle notification which
225     will be forwarded in the same way. This notification will re-enable any registered I/O events.
226
227     The above discussion shows, that throttle events are always generated on passive connectors and
228     received on active connectors. To differentiate further, the throttling originating from a
229     passive input is called <em>backward throttling</em> since it is forwarded in the direction \e
230     opposite to the data flow. Backward throttling notifications are sent towards the input
231     modules. On the other hand, the throttling originating from a passive output is called
232     <em>forward throttling</em> since it is forwarded along the \e same direction the data
233     is. Forward throttling notifications are therefore sent towards the output modules.
234
235     Since throttling a passive input may not disable all further packet delivery immediately, all
236     inputs contains an input queue. In it's default configuration, the queue will send out throttle
237     notifications when it becomes non-empty and unthrottle notifications when it becomes empty
238     again. This automatic behavior may however be disabled. This allows a module to collect incoming
239     packets in it's input queue before processing a bunch of them in one go.
240
241     \section events Events
242
243     Modules may register additional events. These external events are very important since they
244     drive the PPI framework. Possible event sources are
245     \li time based events
246     \li file descriptors.
247     \li internal events (e.g. IdleEvent)
248
249     Here some example code implementing the ActiveSocketInput Module:
250
251     \code
252       class ActiveSocketReader
253           : public senf::ppi::module::Module
254       {
255           typedef senf::ClientSocketHandle<
256               senf::MakeSocketPolicy< senf::ReadablePolicy,
257                                       senf::DatagramFramingPolicy > > SocketHandle;
258           SocketHandle socket_;
259           DataParser const & parser_;
260           senf::ppi:IOSignaler event_;
261
262           static PacketParser<senf::DataPacket> defaultParser_;
263
264       public:
265           senf::ppi::connector::ActiveOutput output;
266
267           // I hestitate taking parser by const & since a const & can be bound to
268           // a temporary even though a const & is all we need. The real implementation
269           // will probably make this a template arg. This simplifies the memory management
270           // from the users pov.
271           ActiveSocketReader(SocketHandle socket, 
272                              DataParser & parser = ActiveSocketReader::defaultParser_)
273               : socket_ (socket), 
274                 parser_ (parser)
275                 event_ (socket, senf::ppi::IOSignaler::Read)
276           {
277               registerEvent( &ActiveSocketReader::data, event_ );
278               route(event_, output);
279           }
280       
281       private:
282     
283           void data()
284           {
285               std::string data;
286               socket_.read(data);
287               output(parser_(data));
288           }
289       };
290     \endcode
291
292     First we declare our own socket handle type which allows us to read packets. The constructor
293     then takes two arguments: A compatible socket and a parser object. This parser object gets
294     passed the packet data as read from the socket (an \c std::string) and returns a
295     senf::Packet::ptr. The \c PacketParser is a simple parser which interprets the data as specified
296     by the template argument.
297
298     We register an IOSignaler event. This event will be signaled whenever the socket is
299     readable. This event is routed to the output. This routing automates throttling for the socket:
300     Whenever the output receives a throttle notifications, the event will be temporarily disabled.
301
302     Processing arriving packets happens in the \c data() member: This member simple reads a packet
303     from the socket. It passes this packet to the \c parser_ and sends the generated packet out.
304
305     \section flows Information Flow
306
307     The above description conceptually introduces three different flow levels:
308      
309     \li The <em>data flow</em> is, where the packets are flowing. This flow always goes from output
310         to input connector.
311     \li The <em>execution flow</em> describes the flow of execution from one module to another. This
312         flow always proceeds from active to passive connector.
313     \li The <em>control flow</em> is the flow of throttling notifications. This flow always proceeds
314         \e opposite to the execution flow, from passive to active connector.
315
316     This is the outside view, from without any module. These flows are set up using
317     senf::ppi::connect() statements.
318
319     Within a module, the different flow levels are defined differently depending on the type of
320     flow:
321     
322     \li The <em>data flow</em> is defined by how data is processed. The different event and
323         connector callbacks will pass packets around and thereby define the data flow
324     \li Likewise, the <em>execution flow</em> is defined parallel to the data flow (however possible
325         in opposite direction) by how the handler of one connector calls other connectors.
326     \li The <em>control flow</em> is set up using senf::ppi::Module::route statements (as long as
327         automatic throttling is used. Manual throttling defines the control flow within the
328         respective callbacks).
329
330     In nearly all cases, these flows will be parallel. Therefore it makes sense to define the \c
331     route statement as defining the 'conceptual data flow' since this is also how control messages
332     should flow (sans the direction, which is defined by the connectors active/passive property).
333
334     \see \ref ppi_implementation \n
335         <a href="http://openfacts.berlios.de/index-en.phtml?title=SENF:_Packet_Processing_Infrastructure">Implementation plan</a>
336  */
337
338 /** \page ppi_implementation Implementation Overview
339     
340     \section processing Data Processing
341
342     The processing in the PPI is driven by events. Without events <em>nothing will happen</em>. When
343     an event is generated, the called module will probably call one of it's active connectors.
344
345     Calling an active connector will directly call the handler registered at the connected passive
346     connector. This way the call and data are handed across the connections until an I/O module will
347     finally handle the request (by not calling any other connectors).
348
349     Throttling is handled in the same way: Throttling a passive connector will call a corresponding
350     (internal) method of the connected active connector. This method will call registered handlers
351     and will analyze the routing information of the module for other (passive) connectors to call
352     and throttle. This will again create a call chain which terminates at the I/O modules. An event
353     which is called to be throttled will disable the event temporarily. Unthrottling works in the
354     same way.
355
356     This simple structure is complicated by the existence of the input queues. This affects both
357     data forwarding and throttling:
358     \li A data request will only be forwarded, if no data is available in the queue
359     \li The connection will only be throttled when the queue is empty
360     \li Handlers of passive input connectors must be called repeatedly until either the queue is
361         empty or the handler does not take any packets from the queue
362
363
364     \section logistics Managing the Data Structures
365
366     The PPI itself is a singleton. This simplifies many of the interfaces (We do not need to pass
367     the PPI instance). Should it be necessary to have several PPI systems working in parallel
368     (either by registering all events with the same event handler or by utilizing multiple threads),
369     we can still extend the API by adding an optional PPI instance argument.
370
371     Every module manages a collection of all it's connectors and every connector has a reference to
372     it's containing module. In addition, every connector maintains a collection of all it's routing
373     targets. 
374
375     All this data is initialized via the routing statements. This is, why \e every connector must
376     appear in at least one routing statement: These statements will as a side effect initialize the
377     connector with it's containing module.
378
379     Since all access to the PPI via the module is via it's base class, unbound member function
380     pointers can be provided as handler arguments: They will automatically be bound to the current
381     instance. This simplifies the PPI usage considerably. The same is true for the connectors: Since
382     they know the containing module, they can explicitly bind unbound member function pointers to
383     the instance.
384     
385
386     \section random_notes Random implementation notes
387     
388     Generation of throttle notifications: Backward throttling notifications are automatically
389     generated (if this is not disabled) whenever the input queue is non-empty \e after the event
390     handler has finished processing. Forward throttling notifications are not generated
391     automatically within the connector. However, the Passive-Passive adaptor will generate
392     Forward-throttling notifications whenever the input queue is empty.
393
394     \section class_diagram Class Diagram
395
396     \image html classes.png
397
398     \fixme Implement Spliters: PassiveSplitter, PrioritySplitter, CloneSplitter
399     \fixme Implement DiscardSink, CloneSource
400  */
401
402 \f
403 // Local Variables:
404 // mode: c++
405 // fill-column: 100
406 // c-file-style: "senf"
407 // indent-tabs-mode: nil
408 // ispell-local-dictionary: "american"
409 // mode: flyspell
410 // mode: auto-fill
411 // End:
412