xref: /freebsd/sys/netpfil/ipfw/dummynet.txt (revision 3416500aef140042c64bc149cb1ec6620483bc44)
1#
2# $FreeBSD$
3#
4
5Notes on the internal structure of dummynet (2010 version)
6by Riccardo Panicucci and Luigi Rizzo
7Work supported by the EC project ONELAB2
8
9
10*********
11* INDEX *
12*********
13Implementation of new dummynet
14    Internal structure
15    Files
16Packet arrival
17    The reconfiguration routine
18dummynet_task()
19Configuration
20    Add a pipe
21    Add a scheduler
22    Add a flowset
23Listing object
24Delete of object
25    Delete a pipe
26    Delete a flowset
27    Delete a scheduler
28Compatibility with FreeBSD7.2 and FreeBSD 8 ipfw binary
29    ip_dummynet_glue.c
30    ip_fw_glue.c
31How to configure dummynet
32How to implement a new scheduler
33
34
35
36OPEN ISSUES
37------------------------------
3820100131 deleting RR causes infinite loop
39	presumably in the rr_free_queue() call -- seems to hang
40	forever when deleting a live flow
41------------------------------
42
43Dummynet is a traffic shaper and network emulator. Packets are
44selected by an external filter such as ipfw, and passed to the emulator
45with a tag such as "pipe 10" or "queue 5" which tells what to
46do with the packet. As an example
47
48	ipfw add queue 5 icmp from 10.0.0.2 to all
49
50All packets with the same tag belong to a "flowset", or a set
51of flows which can be further partitioned according to a mask.
52Flowsets are then passed to a scheduler for processing. The
53association of flowsets and schedulers is configurable e.g.
54
55	ipfw queue 5 config sched 10 weight 3 flow_mask xxxx
56	ipfw queue 8 config sched 10 weight 1 ...
57	ipfw queue 3 config sched 20 weight 1 ...
58
59"sched 10" represents one or more scheduler instances,
60selected through a mask on the 5-tuple itself.
61
62	ipfw sched 20 config type FIFO sched_mask yyy ...
63
64There are in fact two masks applied to each packet:
65+ the "sched_mask" sends packets arriving to a scheduler_id to
66  one of many instances.
67+ the "flow_mask" together with the flowset_id is used to
68  collect packets into independent flows on each scheduler.
69
70As an example, we can have
71	ipfw queue 5 config sched 10 flow_mask src-ip 0x000000ff
72	ipfw sched 10 config type WF2Q+ sched_mask src-ip 0xffffff00
73
74means that sched 10 will have one instance per /24 source subnet,
75and within that, each individual source will be a flow.
76
77Internal structure
78-----------------
79Dummynet-related data is split into several data structures,
80part of them constituting the userland-kernel API, and others
81specific to the kernel.
82NOTE: for up-to-date details please look at the relevant source
83	headers (ip_dummynet.h, ip_dn_private.h, dn_sched.h)
84
85USERLAND-KERNEL API	(ip_dummynet.h)
86
87    struct dn_link:
88	contains data about the physical link such as
89	bandwidth, delay, burst size;
90
91    struct dn_fs:
92	describes a flowset, i.e. a template for queues.
93	Main parameters are the scheduler we attach to, a flow_mask,
94	buckets, queue size, plr, weight, and other scheduler-specific
95	parameters.
96
97    struct dn_flow
98	contains information on a flow, including masks and
99	statistics
100
101    struct dn_sch:
102	defines a scheduler (and a link attached to it).
103	Parameters include scheduler type, sched_mask, number of
104	buckets, and possibly other scheduler-specific parameters,
105
106    struct dn_profile:
107	fields to simulate a delay profile
108
109
110KERNEL REPRESENTATION	(ip_dn_private.h)
111
112    struct mq
113	a queue of mbufs with head and tail.
114
115    struct dn_queue
116	individual queue of packets, created by a flowset using
117	flow_mask and attached to a scheduler instance selected
118	through sched_mask.
119	A dn_queue has a pointer to the dn_fsk (which in turn counts
120	how many queues point to it), a pointer to the
121	dn_sch_inst it attaches to, and is in a hash table in the
122	flowset. scheduler instances also should store queues in
123	their own containers used for scheduling (lists, trees, etc.)
124	CREATE: done on packet arrivals when a flow matches a flowset.
125	DELETE: done only when deleting the parent dn_sch_inst
126		or draining memory.
127
128    struct dn_fsk
129	includes a dn_fs; a pointer to the dn_schk; a link field
130	for the list of dn_fsk attached to the same scheduler,
131	or for the unlinked list;
132	a refcount for the number of queues pointing to it;
133	The dn_fsk is in a hash table, fshash.
134	CREATE: done on configuration commands.
135	DELETE: on configuration commands.
136
137    struct dn_sch_inst
138	a scheduler instance, created from a dn_schk applying sched_mask.
139	Contains a delay line, a reference to the parent, and scheduler-
140	specific info.  Both dn_sch_inst and its delay line can be in the
141	evheap if they have events to be processed.
142	CREATE: created from a dn_schk applying sched_mask
143	DELETE: configuration command delete a scheduler which in turn
144		sweeps the hash table of instances deleting them
145
146    struct dn_schk
147	includes dn_sch, dn_link, a pointer to dn_profile,
148	a hash table of dn_sch_inst, a list of dn_fsk
149	attached to it.
150	CREATE: configuration command. If there are flowsets that
151		refer to this number, they are attached and moved
152		to the hash table
153	DELETE: manual, see dn_sch_inst
154
155
156	fshash                            schedhash
157      +---------------+   sched        +--------------+
158      |      sched-------------------->|      NEW_SCHK|
159  -<----*sch_chain    |<-----------------*fsk_list    |
160      |NEW_FSK        |<----.          | [dn_link]    |
161      +---------------+     |          +--------------+
162      |qht (hash)     |     |          |  siht(hash)  |
163      |   [dn_queue]  |     |          |  [dn_si]     |
164      |   [dn_queue]  |     |          |  [dn_si]     |
165      |     ...       |     |          |   ...        |
166      |   +--------+  |     |          | +---------+  |
167      |   |dn_queue|  |     |          | |dn_si    |  |
168      |  |    fs *----------'          | |         |  |
169      |  |    si *---------------------->|         |  |
170      |  +---------+  |                | +---------+  |
171      +---------------+                +--------------+
172
173The following global data structures contain all
174schedulers and flowsets.
175
176- schedhash[x]: contains all scheduler templates in the system.
177	Looked up only on manual configurations, where flowsets
178	are attached to matching schedulers.
179	We have one entry per 'sched X config' command
180	(plus one for each 'pipe X config').
181
182- fshash[x]: contains all flowsets.
183	We do a lookup on this for each packet.
184	We have one entry for each 'queue X config'
185	(plus one for each 'pipe X config').
186
187Additionally, a list that contains all unlinked flowset:
188- fsu:  contains flowset that are not linked with any scheduler.
189	Flowset are put in this list when they refer to a non
190	existing scheduler.
191	We don't need an efficient data structure as we never search
192	here on a packet arrivals.
193
194Scheduler instances and the delay lines associated with each scheduler
195instance need to be woken up at certain times. Because we have many
196such objects, we keep them in a priority heap (system_heap).
197
198Almost all objects in this implementation are preceded by a structure
199(struct dn_id) which makes it easier to identify them.
200
201
202Files
203-----
204The dummynet code is split in several files.
205All kernel code is in sys/netpfil/ipfw except ip_dummynet.h
206All userland code is in sbin/ipfw.
207Files are
208- sys/netpfil/ip_dummynet.h defines the kernel-userland API
209- ip_dn_private.h contains the kernel-specific APIs
210  and data structures
211- dn_sched.h defines the scheduler API
212- ip_dummynet.c cointains module glue and sockopt handlers, with all
213  functions to configure and list objects.
214- ip_dn_io.c contains the functions directly related to packet processing,
215  and run in the critical path. It also contains some functions
216  exported to the schedulers.
217- dn_heap.[ch] implement a binary heap and a generic hash table
218- dn_sched_* implement the various scheduler modules
219
220- dummynet.c is the file used to implement the user side of dummynet.
221  It contains the function to parsing command line, and functions to
222  show the output of dummynet objects.
223Moreover, there are two new file (ip_dummynet_glue.c and ip_fw_glue.c) that
224are used to allow compatibility with the "ipfw" binary from FreeBSD 7.2 and
225FreeBSD 8.
226
227LOCKING
228=======
229At the moment the entire processing occurs under a single lock
230which is expected to be acquired in exclusive mode
231DN_BH_WLOCK() / DN_BH_WUNLOCK().
232
233In perspective we aim at the following:
234- the 'busy' flag, 'pending' list and all structures modified by packet
235  arrivals and departures are protected by the BH_WLOCK.
236  This is normally acquired in exclusive mode by the packet processing
237  functions for short sections of code (exception -- the timer).
238  If 'busy' is not set, we can do regular packet processing.
239  If 'busy' is set, no pieces can be accessed.
240  We must enqueue the packet on 'pending' and return immediately.
241
242- the 'busy' flag is set/cleared by long sections of code as follows:
243	UH_WLOCK(); KASSERT(busy == 0);
244	BH_WLOCK(); busy=1; BH_WUNLOCK();
245	... do processing ...
246	BH_WLOCK(); busy=0; drain_queue(pending); BH_WUNLOCK();
247	UH_WUNLOCK();
248  this normally happens when the upper half has something heavy
249  to do. The prologue and epilogue are not in the critical path.
250
251- the main containers (fshash, schedhash, ...) are protected by
252  UH_WLOCK.
253
254Packet processing
255=================
256A packet enters dummynet through dummynet_io(). We first lookup
257the flowset number in fshash using dn_ht_find(), then find the scheduler
258instance using ipdn_si_find(), then possibly identify the correct
259queue with ipdn_q_find().
260If successful, we call the scheduler's enqueue function(), and
261if needed start I/O on the link calling serve_sched().
262If the packet can be returned immediately, this is done by
263leaving *m0 set. Otherwise, the packet is absorbed by dummynet
264and we simply return, possibly with some appropriate error code.
265
266Reconfiguration
267---------------
268Reconfiguration is the complex part of the system because we need to
269keep track of the various objects and containers.
270At the moment we do not use reference counts for objects so all
271processing must be done under a lock.
272
273The main entry points for configuration is the ip_dn_ctl() handler
274for the IP_DUMMYNET3 sockopt (others are provided only for backward
275compatibility). Modifications to the configuration call do_config().
276The argument is a sequence of blocks each starting with a  struct dn_id
277which specifies its content.
278The first dn_id must contain as obj.id the DN_API_VERSION
279The obj.type is DN_CMD_CONFIG (followed by actual objects),
280DN_CMD_DELETE (with the correct subtype and list of objects), or
281DN_CMD_FLUSH.
282
283DN_CMD_CONFIG is followed by objects to add/reconfigure. In general,
284if an object already exists it is reconfigured, otherwise it is
285created in a way that keeps the structure consistent.
286We have the following objects in the system, normally numbered with
287an identifier N between 1 and 65535. For certain objects we have
288"shadow" copies numbered I+NMAX and I+ 2*NMAX which are used to
289implement certain backward compatibility features.
290
291In general we have the following linking
292
293  TRADITIONAL DUMMYNET QUEUES "queue N config ... pipe M ..."
294	corresponds to a dn_fs object numbered N
295
296  TRADITIONAL DUMMYNET PIPES "pipe N config ..."
297	dn_fs N+2*NMAX --> dn_sch N+NMAX type FIFO --> dn_link N+NMAX
298
299  GENERIC SCHEDULER "sched N config ... "
300	[dn_fs N+NMAX] --> dn_sch N --> dn_link N
301	The flowset N+NMAX is created only if the scheduler is not
302	of type MULTIQUEUE.
303
304  DELAY PROFILE	"pipe N config profile ..."
305	it is always attached to an existing dn_link N
306
307Because traditional dummynet pipes actually configure both a
308'standalone' instance and one that can be used by queues,
309we do the following:
310
311    "pipe N config ..." configures:
312	dn_sched N type WF2Q+
313	dn_sched N+NMAX type FIFO
314	dn_fs N+2NMAX attached to dn_sched N+NMAX
315	dn_pipe N
316	dn_pipe N+NMAX
317
318    "queue N config" configures
319	dn_fs N
320
321    "sched N config" configures
322	dn_sched N type as desired
323	dn_fs N+NMAX attached to dn_sched N
324
325
326dummynet_task()
327===============
328The dummynet_task() function is the main dummynet processing function and is
329called every tick. This function first calculate the new current time, then
330it checks if it is the time to wake up object from the system_heap comparing
331the current time and the key of the heap. Two types of object (really the
332heap contains pointer to objects) are in the
333system_heap:
334
335- scheduler instance: if a scheduler instance is waked up, the dequeue()
336  function is called until it has credit. If the dequeue() returns packets,
337  the scheduler instance is inserted in the heap with a new key depending of
338  the data that will be send out. If the scheduler instance remains with
339  some credit, it means that is hasn't other packet to send and so the
340  instance is no longer inserted in the heap.
341
342  If the scheduler instance extracted from the heap has the DELETE flag set,
343  the dequeue() is not called and the instance is destroyed now.
344
345- delay line: when extracting a delay line, the function transmit_event() is
346  called to send out packet from delay line.
347
348  If the scheduler instance associated with this delay line doesn't exists,
349  the delay line will be delete now.
350
351Configuration
352=============
353To create a pipe, queue or scheduler, the user should type commands like:
354"ipfw pipe x config"
355"ipfw queue y config pipe x"
356"ipfw pipe x config sched <type>"
357
358The userland side of dummynet will prepare a buffer contains data to pass to
359kernel side.
360The buffer contains all struct needed to configure an object. In more detail,
361to configure a pipe all three structs (dn_link, dn_sch, dn_fs) are needed,
362plus the delay profile struct if the pipe has a delay profile.
363
364If configuring a scheduler only the struct dn_sch is wrote in the buffer,
365while if configuring a flowset only the dn_fs struct is wrote.
366
367The first struct in the buffer contains the type of command request, that is
368if it is configuring a pipe, a queue, or a scheduler. Then there are structs
369need to configure the object, and finally there is the struct that mark
370the end of the buffer.
371
372To support the insertion of pipe and queue using the old syntax, when adding
373a pipe it's necessary to create a FIFO flowset and a FIFO scheduler, which
374have a number x + DN_PIPEOFFSET.
375
376Add a pipe
377----------
378A pipe is only a template for a link.
379If the pipe already exists, parameters are updated. If a delay profile exists
380it is deleted and a new one is created.
381If the pipe doesn't exist a new one is created. After the creation, the
382flowset unlinked list is scanned to see if there are some flowset that would
383be linked with this pipe. If so, these flowset will be of wf2q+ type (for
384compatibility) and a new wf2q+ scheduler is created now.
385
386Add a scheduler
387---------------
388If the scheduler already exists, and the type and the mask are the same, the
389scheduler is simply reconfigured calling the config_scheduler() scheduler
390function with the RECONFIGURE flag active.
391If the type or the mask differ, it is necessary to delete the old scheduler
392and create a new one.
393If the scheduler doesn't exists, a new one is created. If the scheduler has
394a mask, the hash table is created to store pointers to scheduler instances.
395When a new scheduler is created, it is necessary to scan the unlinked
396flowset list to search eventually flowset that would be linked with this
397scheduler number. If some are found, flowsets became of the type of this
398scheduler and they are configured properly.
399
400Add a flowset
401-------------
402Flowset pointers are store in the system in two list. The unlinked flowset list
403contains all flowset that aren't linked with a scheduler, the flowset list
404contains flowset linked to a scheduler, and so they have a type.
405When adding a new flowset, first it is checked if the flowset exists (that is,
406it is in the flowset list) and if it doesn't exists a new flowset is created
407and added to unlinked flowset list if the scheduler which the flowset would be
408linked doesn't exists, or added in the flowset list and configured properly if
409the scheduler exists. If the flowset (before to be created) was in the
410unlinked flowset list, it is removed and deleted, and then recreated.
411If the flowset exists, to allow reconfiguration of this flowset, the
412scheduler number and types must match with the one in memory. If this isn't
413so, the flowset is deleted and a new one will be created. Really, the flowset
414it isn't deleted now, but it is removed from flowset list and it will be
415deleted later because there could be some queues that are using it.
416
417Listing of object
418=================
419The user can request a list of object present in dummynet through the command
420"ipfw [-v] pipe|queue [x] list|show"
421The kernel side of dummynet send a buffer to user side that contains all
422pipe, all scheduler, all flowset, plus all scheduler instances and all queues.
423The dummynet user land will format the output and show only the relevant
424information.
425The buffer sent start with all pipe from the system. The entire struct dn_link
426is passed, except the delay_profile struct that is useless in user space.
427After pipes, all flowset are wrote in the buffer. The struct contains
428scheduler flowset specific data is linked with the flowset writing the
429'obj' id of the extension into the 'alg_fs' pointer.
430Then schedulers are wrote. If a scheduler has one or more scheduler instance,
431these are linked to the parent scheduler writing the id of the parent in the
432'ptr_sched' pointer. If a scheduler instance has queues, there are wrote in
433the buffer and linked thorugh the 'obj' and 'sched_inst' pointer.
434Finally, flowsets in the unlinked flowset list  are write in the buffer, and
435then a struct gen in saved in the buffer to mark the last struct in the buffer.
436
437
438Delete of object
439================
440An object is usually removed by user through a command like
441"ipfw pipe|queue x delete". XXX sched?
442ipfw pass to the kernel a struct gen that contains the type and the number
443of the object to remove
444
445Delete of pipe x
446----------------
447A pipe can be deleted by the user through the command 'ipfw pipe x delete'.
448To delete a pipe, the pipe is removed from the pipe list, and then deleted.
449Also the scheduler associated with this pipe should be deleted.
450For compatibility with old dummynet syntax, the associated FIFO scheduler and
451FIFO flowset must be deleted.
452
453Delete of flowset x
454-------------------
455To remove a flowset, we must be sure that is no longer referenced by any object.
456If the flowset to remove is in the unlinked flowset list, there is not any
457issue, the flowset can be safely removed calling a free() (the flowset
458extension is not yet created if the flowset is in this list).
459If the flowset is in the flowset list, first we remove from it so new packet
460are discarded when arrive. Next, the flowset is marked as delete.
461Now we must check if some queue is using this flowset.
462To do this, a counter (active_f) is provided. This counter indicate how many
463queues exist using this flowset.
464The active_f counter is automatically incremented when a queue is created
465and decremented when a queue is deleted.
466If the counter is 0, the flowset can be safely deleted, and the delete_alg_fs()
467scheduler function is called before deallocate memory.
468If the counter is not 0, the flowset remain in memory until the counter become
469zero. When a queue is delete (by dn_delete_queue() function) it is checked if
470the linked flowset is deleting and if so the counter is decrementing. If the
471counter reaches 0, the flowset is deleted.
472The deletion of a queue can be done only by the scheduler, or when the scheduler
473is destroyed.
474
475Delete of scheduler x
476---------------------
477To delete a scheduler we must be sure that any scheduler instance of this type
478are in the system_heap. To do so, a counter (inst_counter) is provided.
479This counter is managed by the system: it is incremented every time it is
480inserted in the system_heap, and decremented every time it is extracted from it.
481To delete the scheduler, first we remove it from the scheduler list, so new
482packet are discarded when they arrive, and mark the scheduler as deleting.
483
484If the counter is 0, we can remove the scheduler safely calling the
485really_deletescheduler() function. This function will scan all scheduler
486instances and call the delete_scheduler_instance() function that will delete
487the instance. When all instance are deleted, the scheduler template is
488deleted calling the delete_scheduler_template(). If the delay line associate
489with the scheduler is empty, it is deleted now, else it will be deleted when
490it will became empy.
491If the counter was not 0, we wait for it. Every time the dummynet_task()
492function extract a scheduler from the system_heap, the counter is decremented.
493If the scheduler has the delete flag enabled the dequeue() is not called and
494delete_scheduler_instance() is called to delete the instance.
495Obviously this scheduler instance is no longer inserted in the system_heap.
496If the counter reaches 0, the delete_scheduler_template() function is called
497all memory is released.
498NOTE: Flowsets that belong to this scheduler are not deleted, so if a new
499      scheduler with the same number is inserted will use these flowsets.
500      To do so, the best approach would be insert these flowset in the
501      unlinked flowset list, but doing this now will be very expensive.
502      So flowsets will remain in memory and linked with a scheduler that no
503      longer exists until a packet belonging to this flowset arrives. When
504      this packet arrives, the reconfigure() function is called because the
505      generation number mismatch with one contains in the flowset and so
506      the flowset will be moved into the flowset unlinked list, or will be
507      linked with the new scheduler if a new one was created.
508
509
510COMPATIBILITY WITH FREEBSD 7.2 AND FREEBSD 8 'IPFW' BINARY
511==========================================================
512Dummynet is not compatible with old ipfw binary because internal structs are
513changed. Moreover, the old ipfw binary is not compatible with new kernels
514because the struct that represents a firewall rule has changed. So, if a user
515install a new kernel on a FreeBSD 7.2, the ipfw (and possibly many other
516commands) will not work.
517New dummynet uses a new socket option: IP_DUMMYNET3, used for both set and get.
518The old option can be used to allow compatibility with the 'ipfw' binary of
519older version (tested with 7.2 and 8.0) of FreeBSD.
520Two file are provided for this purpose:
521- ip_dummynet_glue.c translates old dummynet requests to the new ones,
522- ip_fw_glue.c converts the rule format between 7.2 and 8 versions.
523Let see in detail these two files.
524
525IP_DUMMYNET_GLUE.C
526------------------
527The internal structs of new dummynet are very different from the original.
528Because of there are some difference from between dummynet in FreeBSD 7.2 and
529dummynet in FreeBSD 8 (the FreeBSD 8 version includes support to pipe delay
530profile and burst option), I have to include both header files. I copied
531the revision 191715 (for version 7.2) and the revision 196045 (for version 8)
532and I appended a number to each struct to mark them.
533
534The main function of this file is ip_dummynet_compat() that is called by
535ip_dn_ctl() when it receive a request of old socket option.
536
537A global variabile ('is7') store the version of 'ipfw' that FreeBSD is using.
538This variable is set every time a request of configuration is done, because
539with this request we receive a buffer of which size depending of ipfw version.
540Because of in general the first action is a configuration, this variable is
541usually set accordly. If the first action is a request of listing of pipes
542or queues, the system cannot know the version of ipfw, and we suppose that
543version 7.2 is used. If version is wrong, the output can be senseless, but
544the application should not crash.
545
546There are four request for old dummynet:
547- IP_DUMMYNET_FLUSH: the flush options have no parameter, so simply the
548  dummynet_flush() function is called;
549- IP_DUMMYNET_DEL: the delete option need to be translate.
550  It is only necessary to extract the number and the type of the object
551  (pipe or queue) to delete from the buffer received and build a new struct
552  gen contains the right parameters, then call the delete_object() function;
553- IP_DUMMYNET_CONFIGURE: the configure command receive a buffer depending of
554  the ipfw version. After the properly extraction of all data, that depends
555  by the ipfw version used, new structures are filled and then the dummynet
556  config_link() function is properly called. Note that the 7.2 version does
557  not support some parameter as burst or delay profile.
558- IP_DUMMYNET_GET: The get command should send to the ipfw the correct buffer
559  depending of its version. There are two function that build the
560  corrected buffer, ip_dummynet_get7() and ip_dummynet_get8(). These
561  functions reproduce the buffer exactly as 'ipfw' expect. The only difference
562  is that the weight parameter for a queue is no longer sent by dummynet and so
563  it is set to 0.
564  Moreover, because of the internal structure has changed, the bucket size
565  of a queue could not be correct, because now all flowset share the hash
566  table.
567  If the version of ipfw is wrong, the output could be senseless or truncated,
568  but the application should not crash.
569
570IP_FW_GLUE.C
571------------
572The ipfw binary also is used to add rules to FreeBSD firewall. Because of the
573struct ip_fw is changed from FreeBsd 7.2 to FreeBSD 8, it is necessary
574to write some glue code to allow use ipfw from FreeBSD 7.2 with the kernel
575provided with FreeBSD 8.
576This file contains two functions to convert a rule from FreeBSD 7.2 format to
577FreeBSD 8 format, and viceversa.
578The conversion should be done when a rule passes from userspace to kernel space
579and viceversa.
580I have to modify the ip_fw2.c file to manage these two case, and added a
581variable (is7) to store the ipfw version used, using an approach like the
582previous file:
583- when a new rule is added (option IP_FW_ADD) the is7 variable is set if the
584  size of the rule received correspond to FreeBSD 7.2 ipfw version. If so, the
585  rule is converted to version 8 calling the function convert_rule_to_8().
586  Moreover, after the insertion of the rule, the rule is now reconverted to
587  version 7 because the ipfw binary will print it.
588- when the user request a list of rules (option IP_FW_GET) the is7 variable
589  should be set correctly because we suppose that a configure command was done,
590  else we suppose that the FreeBSD version is 8. The function ipfw_getrules()
591  in ip_fw2.c file return all rules, eventually converted to version 7 (if
592  the is7 is set) to the ipfw binary.
593The conversion of a rule is quite simple. The only difference between the
594two structures (struct ip_fw) is that in the new there is a new field
595(uint32_t id). So, I copy the entire rule in a buffer and the copy the rule in
596the right position in the new (or old) struct. The size of commands are not
597changed, and the copy is done into a cicle.
598
599How to configure dummynet
600=========================
601It is possible to configure dummynet through two main commands:
602'ipfw pipe' and 'ipfw queue'.
603To allow compatibility with old version, it is possible configure dummynet
604using the old command syntax. Doing so, obviously, it is only possible to
605configure a FIFO scheduler or a wf2q+ scheduler.
606A new command, 'ipfw pipe x config sched <type>' is supported to add a new
607scheduler to the system.
608
609- ipfw pipe x config ...
610  create a new pipe with the link parameters
611  create a new scheduler fifo (x + offset)
612  create a new flowset fifo (x + offset)
613  the mask is eventually stored in the FIFO scheduler
614
615- ipfw queue y config pipe x ...
616  create a new flowset y linked to sched x.
617    The type of flowset depends by the specified scheduler.
618    If the scheduler does not exist, this flowset is inserted in a special
619    list and will be not active.
620    If pipe x exists and sched does not exist, a new wf2q+ scheduler is
621    created and the flowset will be linked to this new scheduler (this is
622    done for compatibility with old syntax).
623
624- ipfw pipe x config sched <type> ...
625  create a new scheduler x of type <type>.
626  Search into the flowset unlinked list if there are some flowset that
627  should be linked with this new scheduler.
628
629- ipfw pipe x delete
630  delete the pipe x
631  delete the scheduler fifo (x + offset)
632  delete the scheduler x
633  delete the flowset fifo (x + offset)
634
635- ipfw queue x delete
636  delete the flowset x
637
638- ipfw sched x delete ///XXX
639  delete the scheduler x
640
641Follow now some examples to how configure dummynet:
642- Ex1:
643  ipfw pipe 10 config bw 1M delay 15 // create a pipe with band and delay
644                                        A FIFO flowset and scheduler is
645                                        also created
646  ipfw queue 5 config pipe 10 weight 56 // create a flowset. This flowset
647                                           will be of wf2q+ because a pipe 10
648                                           exists. Moreover, the wf2q+
649                                           scheduler is created now.
650- Ex2:
651  ipfw queue 5 config pipe 10 weight 56 // Create a flowset. Scheduler 10
652                                           does not exist, so this flowset
653                                           is inserted in the unlinked
654                                           flowset list.
655  ipfw pipe 10 config bw... // Create a pipe, a FIFO flowset and scheduler.
656                               Because of a flowset with 'pipe 10' exists,
657                               a wf2q+ scheduler is created now and that
658                               flowset is linked with this sceduler.
659
660- Ex3:
661  ipfw pipe 10 config bw...    // Create a pipe, a FIFO flowset and scheduler.
662  ipfw pipe 10 config sched rr // Create a scheduler of type RR, linked to
663                                  pipe 10
664  ipfw queue 5 config pipe 10 weight 56 // Create a flowset 5. This flowset
665                                           will belong to scheduler 10 and
666                                           it is of type RR
667
668- Ex4:
669  ipfw pipe 10 config sched rr // Create a scheduler of type RR, linked to
670                                  pipe 10 (not exist yet)
671  ipfw pipe 10 config bw... // Create a pipe, a FIFO flowset and scheduler.
672  ipfw queue 5 config pipe 10 weight 56 // Create a flowset 5.This flowset
673                                           will belong to scheduler 10 and
674                                           it is of type RR
675  ipfw pipe 10 config sched wf2q+ // Modify the type of scheduler 10. It
676                                     becomes a wf2q+ scheduler.
677                                     When a new packet of flowset 5 arrives,
678                                     the flowset 5 becomes to wf2q+ type.
679
680How to implement a new scheduler
681================================
682In dummynet, a scheduler algorithm is represented by two main structs, some
683functions and other minor structs.
684- A struct dn_sch_xyz (where xyz is the 'type' of scheduler algorithm
685  implemented) contains data relative to scheduler, as global parameter that
686  are common to all instances of the scheduler
687- A struct dn_sch_inst_xyz contains data relative to a single scheduler
688  instance, as local status variable depending for example by flows that
689  are linked with the scheduler, and so on.
690To add a scheduler to dummynet, the user should type a command like:
691'ipfw pipe x config sched <type> [mask ... ...]'
692This command creates a new struct dn_sch_xyz of type <type>, and
693store the optional parameter in that struct.
694
695The parameter mask determines how many scheduler instance of this
696scheduler may exist. For example, it is possible to divide traffic
697depending on the source port (or destination, or ip address...),
698so that every scheduler instance act as an independent scheduler.
699If the mask is not set, all traffic goes to the same instance.
700
701When a packet arrives to a scheduler, the system search the corrected
702scheduler instance, and if it does not exist it is created now (the
703struct dn_sch_inst_xyz is allocated by the system, and the scheduler
704fills the field correctly). It is a task of the scheduler to create
705the struct that contains all queues for a scheduler instance.
706Dummynet provides some function to create an hash table to store
707queues, but the schedule algorithm can choice the own struct.
708
709To link a flow to a scheduler, the user should type a command like:
710'ipfw queue z config pipe x [mask... ...]'
711
712This command creates a new 'dn_fs' struct that will be inserted
713in the system.  If the scheduler x exists, this flowset will be
714linked to that scheduler and the flowset type become the same as
715the scheduler type. At this point, the function create_alg_fs_xyz()
716is called to allow store eventually parameter for the flowset that
717depend by scheduler (for example the 'weight' parameter for a wf2q+
718scheduler, or some priority...). A parameter mask can be used for
719a flowset. If the mask parameter is set, the scheduler instance can
720separate packet according to its flow id (src and dst ip, ports...)
721and assign it to a separate queue. This is done by the scheduler,
722so it can ignore the mask if it wants.
723
724See now the two main structs:
725struct dn_sch_xyz {
726    struct gen g; /* important the name g */
727    /* global params */
728};
729struct dn_sch_inst_xyz {
730    struct gen g; /* important the name g */
731    /* params of the instance */
732};
733It is important to embed the struct gen as first parameter. The struct gen
734contains some values that the scheduler instance must fill (the 'type' of
735scheduler, the 'len' of the struct...)
736The function create_scheduler_xyz() should be implemented to initialize global
737parameters in the first struct, and if memory allocation is done it is
738mandatory to implement the delete_scheduler_template() function to free that
739memory.
740The function create_scheduler_instance_xyz() must be implemented even if the
741scheduler instance does not use extra parameters. In this function the struct
742gen fields must be filled with corrected infos. The
743delete_scheduler_instance_xyz() function must bu implemented if the instance
744has allocated some memory in the previous function.
745
746To store data belonging to a flowset the follow struct is used:
747struct alg_fs_xyz {
748    struct gen g;
749    /* fill correctly the gen struct
750     g.subtype = DN_XYZ;
751     g.len = sizeof(struct alg_fs_xyz)
752     ...
753     */
754    /* params for the flow */
755};
756The create_alg_fs_xyz() function is mandatory, because it must fill the struct
757gen, but the delete_alg_fs_xyz() is mandatory only if the previous function
758has allocated some memory.
759
760A struct dn_queue contains packets belonging to a queue and some statistical
761data. The scheduler could have to store data in this struct, so it must define
762a dn_queue_xyz struct:
763struct dn_queue_xyz {
764    struct dn_queue q;
765    /* parameter for a queue */
766}
767
768All structures are allocated by the system. To do so, the scheduler must
769set the size of its structs in the scheduler descriptor:
770scheduler_size:     sizeof(dn_sch_xyz)
771scheduler_i_size:   sizeof(dn_sch_inst_xyz)
772flowset_size:       sizeof(alg_fs_xyz)
773queue_size:         sizeof(dn_queue_xyz);
774The scheduler_size could be 0, but other struct must have at least a struct gen.
775
776
777After the definition of structs, it is necessary to implement the
778scheduler functions.
779
780- int (*config_scheduler)(char *command, void *sch, int reconfigure);
781    Configure a scheduler, or reconfigure if 'reconfigure' == 1.
782    This function performs additional allocation and initialization of global
783    parameter for this scheduler.
784    If memory is allocated here, the delete_scheduler_template() function
785    should be implemented to remove this memory.
786- int (*delete_scheduler_template)(void* sch);
787    Delete a scheduler template. This function is mandatory if the scheduler
788    uses extra data respect the struct dn_sch.
789- int (*create_scheduler_instance)(void *s);
790    Create a new scheduler instance. The system allocate the necessary memory
791    and the schedulet can access it using the 's' pointer.
792    The scheduler instance stores all queues, and to do this can use the
793    hash table provided by the system.
794- int (*delete_scheduler_instance)(void *s);
795    Delete a scheduler instance. It is important to free memory allocated
796    by create_scheduler_instance() function. The memory allocated by system
797    is freed by the system itself. The struct contains all queue also has
798    to be deleted.
799- int (*enqueue)(void *s, struct gen *f, struct mbuf *m,
800                 struct ipfw_flow_id *id);
801    Called when a packet arrives. The packet 'm' belongs to the scheduler
802    instance 's', has a flowset 'f' and the flowid 'id' has already been
803    masked. The enqueue() must call dn_queue_packet(q, m) function to really
804    enqueue packet in the queue q. The queue 'q' is chosen by the scheduler
805    and if it does not exist should be created calling the dn_create_queue()
806    function. If the schedule want to drop the packet, it must call the
807    dn_drop_packet() function and then return 1.
808- struct mbuf * (*dequeue)(void *s);
809    Called when the timer expires (or when a packet arrives and the scheduler
810    instance is idle).
811    This function is called when at least a packet can be send out. The
812    scheduler choices the packet and returns it; if no packet are in the
813    schedulerinstance, the function must return NULL.
814    Before return a packet, it is important to call the function
815    dn_return_packet() to update some statistic of the queue and update the
816    queue counters.
817- int (*drain_queue)(void *s, int flag);
818    The system request to scheduler to delete all queues that is not using
819    to free memory. The flag parameter indicate if a queue must be deleted
820    even if it is active.
821
822- int (*create_alg_fs)(char *command, struct gen *g, int reconfigure);
823    It is called when a flowset is linked with a scheduler. This is done
824    when the scheduler is defined, so we can know the type of flowset.
825    The function initialize the flowset paramenter parsing the command
826    line. The parameter will be stored in the g struct that have the right
827    size allocated by the system. If the reconfigure flag is set, it means
828    that the flowset is reconfiguring
829- int (*delete_alg_fs)(struct gen *f);
830    It is called when a flowset is deleting. Must remove the memory allocate
831    by the create_alg_fs() function.
832
833- int (*create_queue_alg)(struct dn_queue *q, struct gen *f);
834    Called when a queue is created. The function should link the queue
835    to the struct used by the scheduler instance to store all queues.
836- int (*delete_queue_alg)(struct dn_queue *q);
837    Called when a queue is deleting. The function should remove extra data
838    and update the struct contains all queues in the scheduler instance.
839
840The struct scheduler represent the scheduler descriptor that is passed to
841dummynet when a scheduler module is loaded.
842This struct contains the type of scheduler, the length of all structs and
843all function pointers.
844If a function is not implemented should be initialize to NULL. Some functions
845are mandatory, other are mandatory if some memory should be freed.
846Mandatory functions:
847- create_scheduler_instance()
848- enqueue()
849- dequeue()
850- create_alg_fs()
851- drain_queue()
852Optional functions:
853- config_scheduler()
854- create_queue_alg()
855Mandatory functions if the corresponding create...() has allocated memory:
856- delete_scheduler_template()
857- delete_scheduler_instance()
858- delete_alg_fs()
859- delete_queue_alg()
860
861