diff options
Diffstat (limited to 'doc')
73 files changed, 11264 insertions, 951 deletions
diff --git a/doc/.gitignore b/doc/.gitignore new file mode 100644 index 00000000..f7cb70da --- /dev/null +++ b/doc/.gitignore @@ -0,0 +1,8 @@ +*.html +libnl.dict +Doxyfile +/aclocal.m4 +/autom4te.cache/ +/build-aux/ +/config.* +/configure diff --git a/doc/AUTHORS b/doc/AUTHORS new file mode 100644 index 00000000..26e3cb40 --- /dev/null +++ b/doc/AUTHORS @@ -0,0 +1 @@ +Thomas Graf <tgraf@suug.ch> diff --git a/doc/COPYING b/doc/COPYING new file mode 100644 index 00000000..94a9ed02 --- /dev/null +++ b/doc/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index 8e311e3b..50e8f0c9 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -1,203 +1,268 @@ -# Doxyfile 1.5.2 +# Doxyfile 1.8.1.1 # This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project +# doxygen (www.doxygen.org) for a project. # -# All text after a hash (#) is considered a comment and will be ignored +# All text after a hash (#) is considered a comment and will be ignored. # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") +# Values that contain spaces should be placed between quotes (" "). #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- -# This tag specifies the encoding used for all characters in the config file that -# follow. The default is UTF-8 which is also the encoding used for all text before -# the first occurrence of this tag. Doxygen uses libiconv (or the iconv built into -# libc) for the transcoding. See http://www.gnu.org/software/libiconv for the list of -# possible encodings. +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. DOXYFILE_ENCODING = UTF-8 -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. PROJECT_NAME = libnl -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = @PACKAGE_VERSION@ -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = ./ -# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create -# 4096 sub-directories (in 2 levels) under the output directory of each output -# format and will distribute the generated files over these directories. -# Enabling this option can be useful when feeding doxygen a huge amount of -# source files, where putting all generated files in the same directory would +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would # otherwise cause performance problems for the file system. CREATE_SUBDIRS = NO -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, -# Croatian, Czech, Danish, Dutch, Finnish, French, German, Greek, Hungarian, -# Italian, Japanese, Japanese-en (Japanese with English messages), Korean, -# Korean-en, Lithuanian, Norwegian, Polish, Portuguese, Romanian, Russian, -# Serbian, Slovak, Slovene, Spanish, Swedish, and Ukrainian. +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. OUTPUT_LANGUAGE = English -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. -REPEAT_BRIEF = NO +REPEAT_BRIEF = YES -# This tag implements a quasi-intelligent brief description abbreviator -# that is used to form the text in various listings. Each string -# in this list, if found as the leading text of the brief description, will be -# stripped from the text and the result after processing the whole list, is -# used as the annotated text. Otherwise, the brief description is used as-is. -# If left blank, the following values are used ("$name" is automatically -# replaced with the name of the entity): "The $name class" "The $name widget" -# "The $name file" "is" "provides" "specifies" "contains" +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" # "represents" "a" "an" "the" -ABBREVIATE_BRIEF = +ABBREVIATE_BRIEF = -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief # description. -ALWAYS_DETAILED_SEC = YES +ALWAYS_DETAILED_SEC = NO -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all -# inherited members of a class in the documentation of that class as if those -# members were ordinary class members. Constructors, destructors and assignment +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment # operators of the base classes will not be shown. INLINE_INHERITED_MEMB = YES -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = YES -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user-defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. The tag can be used to show relative paths in the file list. -# If left blank the directory from which doxygen is run is used as the +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the # path to strip. -STRIP_FROM_PATH = +STRIP_FROM_PATH = -# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of -# the path mentioned in the documentation of a class, which tells -# the reader which header file to include in order to use a class. -# If left blank only the name of the header file containing the class -# definition is used. Otherwise one should specify the include paths that +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that # are normally passed to the compiler using the -I flag. -STRIP_FROM_INC_PATH = +STRIP_FROM_INC_PATH = -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system # doesn't support long names like on DOS, Mac, or CD-ROM. SHORT_NAMES = NO -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like the Qt-style comments (thus requiring an -# explicit @brief command for a brief description. +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) JAVADOC_AUTOBRIEF = YES -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) -MULTILINE_CPP_IS_BRIEF = NO +QT_AUTOBRIEF = NO -# If the DETAILS_AT_TOP tag is set to YES then Doxygen -# will output the detailed description near the top, like JavaDoc. -# If set to NO, the detailed description appears after the member -# documentation. +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. -DETAILS_AT_TOP = YES +MULTILINE_CPP_IS_BRIEF = NO -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it # re-implements. INHERIT_DOCS = NO -# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce -# a new page for each member. If set to NO, the documentation of a member will +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will # be part of the file/class/namespace that contains it. SEPARATE_MEMBER_PAGES = NO -# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user-defined paragraph with heading "Side Effects:". +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. -ALIASES = arg=\param - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C -# sources only. Doxygen will then generate output that is more tailored for C. -# For instance, some of the names that are used will be different. The list +ALIASES = arg=\param \ + "ref_asciidoc{3}=<a href=\"../\1.html#\2\"><b>\3</b></a>" \ + "ref_core{2}=\ref_asciidoc{core,\1,\2 (Netlink Core Library Development Guide)}" \ + "ref_route{2}=\ref_asciidoc{route,\1,\2 (Netlink Routing Development Guide)}" \ + "ref_idiagnl{2}=\ref_asciidoc{idiag,\1,\2 (Netlink Inet Diag Development Guide)}" \ + "core_doc{2}=\ref_core{\1,\2}" \ + "route_doc{2}=\ref_route{\1,\2}" \ + "idiagnl_doc{2}=\ref_idiagnl{\1,\2}" \ + "callback=\par Callback Invocation:\n" \ + "lowlevel=\copydoc low_level_api" + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list # of all members will be omitted, etc. OPTIMIZE_OUTPUT_FOR_C = YES -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java -# sources only. Doxygen will then generate output that is more tailored for Java. -# For instance, namespaces will be presented as packages, qualified scopes -# will look different, etc. +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. OPTIMIZE_OUTPUT_JAVA = NO -# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want to -# include (a tag file for) the STL sources as input, then you should -# set this tag to YES in order to let doxygen match functions declarations and -# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. -# func(std::string) {}). This also make the inheritance and collaboration +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration # diagrams that involve STL classes more complete and accurate. BUILTIN_STL_SUPPORT = NO @@ -207,396 +272,551 @@ BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = NO + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO -# Set the SUBGROUPING tag to YES (the default) to allow class member groups of -# the same type (for instance a group of public functions) to be put as a -# subgroup of that type (e.g. under the Public Functions section). Set it to -# NO to prevent subgrouping. Alternatively, this can be done per class using +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using # the \nosubgrouping command. SUBGROUPING = YES +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +SYMBOL_CACHE_SIZE = 0 + +# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +# their name and scope. Since this can be an expensive process and often the +# same symbol appear multiple times in the code, doxygen keeps a cache of +# pre-resolved symbols. If the cache is too small doxygen will become slower. +# If the cache is too large, memory is wasted. The cache size is given by this +# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +LOOKUP_CACHE_SIZE = 0 + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = NO -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = YES -# If the EXTRACT_STATIC tag is set to YES all static members of a file +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = NO -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. # If set to NO only classes defined in header files are included. EXTRACT_LOCAL_CLASSES = YES -# This flag is only useful for Objective-C code. When set to YES local -# methods, which are defined in the implementation section but not in -# the interface are included in the documentation. +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. # If set to NO (the default) only methods in the interface are included. EXTRACT_LOCAL_METHODS = YES -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these classes will be included in the various +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the # documentation. HIDE_FRIEND_COMPOUNDS = NO -# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any -# documentation blocks found inside the body of a function. -# If set to NO (the default) these blocks will be appended to the +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the # function's detailed documentation block. HIDE_IN_BODY_DOCS = NO -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower-case letters. If set to YES upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows # and Mac users are advised to set this option to NO. CASE_SENSE_NAMES = YES -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put a list of the files that are included by a file in the documentation +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = NO -# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the -# brief documentation of file, namespace and class members alphabetically -# by member name. If set to NO (the default) the members will appear in +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in # declaration order. SORT_BRIEF_DOCS = NO -# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be -# sorted by fully-qualified names, including namespaces. If set to -# NO (the default), the class list will be sorted only by class name, -# not including the namespace part. +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = YES + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. # Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. -# Note: This option applies only to the class list, not to the +# Note: This option applies only to the class list, not to the # alphabetical list. SORT_BY_SCOPE_NAME = NO -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = NO -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = NO -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug # commands in the documentation. -GENERATE_BUGLIST = NO +GENERATE_BUGLIST = YES -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting # \deprecated commands in the documentation. -GENERATE_DEPRECATEDLIST= NO +GENERATE_DEPRECATEDLIST= YES -# The ENABLED_SECTIONS tag can be used to enable conditional +# The ENABLED_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. -ENABLED_SECTIONS = +ENABLED_SECTIONS = -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consists of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and defines in the -# documentation can be controlled using \showinitializer or \hideinitializer +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer # command in the documentation regardless of this setting. MAX_INITIALIZER_LINES = 30 -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the # list will mention the files that were used to generate the documentation. SHOW_USED_FILES = NO -# If the sources in your project are distributed over multiple directories -# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy -# in the documentation. The default is NO. +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = NO + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. -SHOW_DIRECTORIES = NO +SHOW_NAMESPACES = YES -# The FILE_VERSION_FILTER tag can be used to specify a program or script that -# doxygen should invoke to get the current version for each file (typically from the -# version control system). Doxygen will invoke the program by executing (via -# popen()) the command <command> <input-file>, where <command> is the value of -# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file -# provided by doxygen. Whatever the program writes to standard output +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command <command> <input-file>, where <command> is the value of +# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file +# provided by doxygen. Whatever the program writes to standard output # is used as the file version. See the manual for examples. -FILE_VERSION_FILTER = +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. To create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = DoxygenLayout.xml + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. + +CITE_BIB_FILES = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- -# The QUIET tag can be used to turn on/off the messages that are generated +# The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = YES -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = NO -# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some -# parameters in a documented function, or documenting parameters that +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that # don't exist or using markup commands wrongly. WARN_IF_DOC_ERROR = YES -# This WARN_NO_PARAMDOC option can be abled to get warnings for -# functions that are documented, but have no documentation for their parameters -# or return value. If set to NO (the default) doxygen will only warn about -# wrong or incomplete parameter documentation, but not about the absence of +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of # documentation. WARN_NO_PARAMDOC = NO -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. Optionally the format may contain -# $version, which will be replaced by the version of the file (if it could +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could # be obtained via FILE_VERSION_FILTER) WARN_FORMAT = "$file:$line: $text" -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written # to stderr. -WARN_LOGFILE = +WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = ../lib \ - ../src/lib \ - ../include/netlink +INPUT = @top_srcdir@/../lib \ + @top_srcdir@/../src/lib \ + @top_srcdir@/../include/netlink \ + @top_srcdir@/../src \ + @top_srcdir@/../doc/src -# This tag can be used to specify the character encoding of the source files that -# doxygen parses. Internally doxygen uses the UTF-8 encoding, which is also the default -# input encoding. Doxygen uses libiconv (or the iconv built into libc) for the transcoding. -# See http://www.gnu.org/software/libiconv for the list of possible encodings. +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. INPUT_ENCODING = UTF-8 -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx -# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl FILE_PATTERNS = *.c \ *.h -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. EXCLUDE = SCCS -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or -# directories that are symbolic links (a Unix filesystem feature) are excluded +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded # from the input. EXCLUDE_SYMLINKS = NO -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. Note that the wildcards are matched -# against the file with absolute path, so to exclude all test directories +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories # for example use the pattern */test/* -EXCLUDE_PATTERNS = +EXCLUDE_PATTERNS = -# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names -# (namespaces, classes, functions, etc.) that should be excluded from the output. -# The symbol name can be a fully qualified name, a word, or if the wildcard * is used, -# a substring. Examples: ANamespace, AClass, AClass::ANamespace, ANamespace::*Test +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test -EXCLUDE_SYMBOLS = +EXCLUDE_SYMBOLS = -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see # the \include command). -EXAMPLE_PATH = +EXAMPLE_PATH = @top_srcdir@/src -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left # blank all files are included. -EXAMPLE_PATTERNS = +EXAMPLE_PATTERNS = -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. # Possible values are YES and NO. If left blank NO is used. EXAMPLE_RECURSIVE = NO -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see # the \image command). -IMAGE_PATH = +IMAGE_PATH = -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command <filter> <input-file>, where <filter> -# is the value of the INPUT_FILTER tag, and <input-file> is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. If FILTER_PATTERNS is specified, this tag will be +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be # ignored. -INPUT_FILTER = +INPUT_FILTER = -# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern -# basis. Doxygen will compare the file name with each pattern and apply the -# filter if there is a match. The filters are a list of the form: -# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further -# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER -# is applied to all files. +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. -FILTER_PATTERNS = +FILTER_PATTERNS = -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source # files to browse (i.e. when SOURCE_BROWSER is set to YES). FILTER_SOURCE_FILES = NO +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + #--------------------------------------------------------------------------- # configuration options related to source browsing #--------------------------------------------------------------------------- -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. -# Note: To get rid of all source code in the generated output, make sure also +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also # VERBATIM_HEADERS is set to NO. SOURCE_BROWSER = YES -# Setting the INLINE_SOURCES tag to YES will include the body +# Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C, C++ and Fortran comments will always remain visible. STRIP_CODE_COMMENTS = NO -# If the REFERENCED_BY_RELATION tag is set to YES (the default) -# then for each documented function all documented +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented # functions referencing it will be listed. REFERENCED_BY_RELATION = YES -# If the REFERENCES_RELATION tag is set to YES (the default) -# then for each documented function all documented entities +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities # called/used by that function will be listed. REFERENCES_RELATION = YES @@ -604,43 +824,44 @@ REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES (the default) # and SOURCE_BROWSER tag is set to YES, then the hyperlinks from # functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will -# link to the source code. Otherwise they will link to the documentstion. +# link to the source code. +# Otherwise they will link to the documentation. REFERENCES_LINK_SOURCE = YES -# If the USE_HTAGS tag is set to YES then the references to source code -# will point to the HTML generated by the htags(1) tool instead of doxygen -# built-in source browser. The htags tool is part of GNU's global source -# tagging system (see http://www.gnu.org/software/global/global.html). You +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You # will need version 4.8.6 or higher. USE_HTAGS = NO -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. -VERBATIM_HEADERS = NO +VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. -ALPHABETICAL_INDEX = NO +ALPHABETICAL_INDEX = YES -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = nl_ @@ -649,256 +870,524 @@ IGNORE_PREFIX = nl_ # configuration options related to the HTML output #--------------------------------------------------------------------------- -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. -HTML_OUTPUT = html +HTML_OUTPUT = api -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank # doxygen will generate files with .html extension. HTML_FILE_EXTENSION = .html -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. -HTML_HEADER = +HTML_FOOTER = -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# style sheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = @srcdir@/libnl.css + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. -HTML_FOOTER = +HTML_COLORSTYLE_SAT = 100 -# The HTML_STYLESHEET tag can be used to specify a user-defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet. Note that doxygen will try to copy -# the style sheet file to the HTML output directory, so don't put your own -# stylesheet in the HTML output directory as well, or it will be erased! +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. -HTML_STYLESHEET = +HTML_COLORSTYLE_GAMMA = 80 -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to -# NO a bullet list will be used. +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. -HTML_ALIGN_MEMBERS = YES +HTML_TIMESTAMP = YES -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. + +HTML_DYNAMIC_SECTIONS = YES + +# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of +# entries shown in the various tree structured indices initially; the user +# can expand and collapse entries dynamically later on. Doxygen will expand +# the tree to such a level that at most the specified number of entries are +# visible (unless a fully collapsed tree already exceeds this amount). +# So setting the number of entries 1 will produce a full collapsed tree by +# default. 0 is a special value representing an infinite number of entries +# and will result in a full expanded tree by default. + +HTML_INDEX_NUM_ENTRIES = 100 + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be # written to the html output directory. -CHM_FILE = +CHM_FILE = -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run # the HTML help compiler on the generated index.hhp. -HHC_LOCATION = +HHC_LOCATION = -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that # it should be included in the master .chm file (NO). GENERATE_CHI = NO -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a # normal table of contents (NO) in the .chm file. BINARY_TOC = NO -# The TOC_EXPAND flag can be set to YES to add extra items for group members +# The TOC_EXPAND flag can be set to YES to add extra items for group members # to the contents of the HTML help documentation and to the tree view. TOC_EXPAND = NO -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters"> +# Qt Help Project / Custom Filters</a>. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes"> +# Qt Help Project / Filter Attributes</a>. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.infradead.libnl + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. DISABLE_INDEX = NO -# This tag can be used to set the number of enum values (range [1..20]) -# that doxygen will group on one line in the generated HTML documentation. +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. -ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = YES -# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be -# generated containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, -# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are -# probably better off using the HTML help feature. +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. -GENERATE_TREEVIEW = NO +ENUM_VALUES_PER_LINE = 1 -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree # is shown. -TREEVIEW_WIDTH = 250 +TREEVIEW_WIDTH = 205 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you may also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. +# However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = NO + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. LATEX_CMD_NAME = latex -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the # default command name. MAKEINDEX_CMD_NAME = makeindex -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, a4wide, letter, legal and +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. -EXTRA_PACKAGES = +EXTRA_PACKAGES = -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! -LATEX_HEADER = +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO -# If LATEX_HIDE_INDICES is set to YES then doxygen will not -# include the index chapters (such as File Index, Compound Index, etc.) +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) # in the output. LATEX_HIDE_INDICES = NO +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimized for Word 97 and may not look very pretty with +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO -# Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assignments. You only have to provide +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide # replacements, missing definitions are set to their default value. -RTF_STYLESHEET_FILE = +RTF_STYLESHEET_FILE = -# Set optional variables used in the generation of an rtf document. +# Set optional variables used in the generation of an rtf document. # Syntax is similar to doxygen's config file. -RTF_EXTENSIONS_FILE = +RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man -# The MAN_EXTENSION tag determines the extension that is added to +# The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command # would be unable to find the correct page. The default is NO. MAN_LINKS = NO @@ -907,33 +1396,33 @@ MAN_LINKS = NO # configuration options related to the XML output #--------------------------------------------------------------------------- -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of # the code including all documentation. GENERATE_XML = NO -# The XML_OUTPUT tag is used to specify where the XML pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `xml' will be used as the default path. XML_OUTPUT = xml -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the # syntax of the XML files. -XML_SCHEMA = +XML_SCHEMA = -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the # syntax of the XML files. -XML_DTD = +XML_DTD = -# If the XML_PROGRAMLISTING tag is set to YES Doxygen will -# dump the program listings (including syntax highlighting -# and cross-referencing information) to the XML output. Note that +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that # enabling this will significantly increase the size of the XML output. XML_PROGRAMLISTING = YES @@ -942,10 +1431,10 @@ XML_PROGRAMLISTING = YES # configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental # and incomplete at the moment. GENERATE_AUTOGEN_DEF = NO @@ -954,307 +1443,364 @@ GENERATE_AUTOGEN_DEF = NO # configuration options related to the Perl module output #--------------------------------------------------------------------------- -# If the GENERATE_PERLMOD tag is set to YES Doxygen will -# generate a Perl module file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the # moment. GENERATE_PERLMOD = NO -# If the PERLMOD_LATEX tag is set to YES Doxygen will generate -# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able # to generate PDF and DVI output from the Perl module output. PERLMOD_LATEX = NO -# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be -# nicely formatted so it can be parsed by a human reader. This is useful -# if you want to understand what is going on. On the other hand, if this -# tag is set to NO the size of the Perl module output will be much smaller +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller # and Perl will parse it just the same. PERLMOD_PRETTY = YES -# The names of the make variables in the generated doxyrules.make file -# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. -# This is useful so different doxyrules.make files included by the same +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same # Makefile don't overwrite each other's variables. -PERLMOD_MAKEVAR_PREFIX = +PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- -# Configuration options related to the preprocessor +# Configuration options related to the preprocessor #--------------------------------------------------------------------------- -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_DEFINED tags. EXPAND_ONLY_PREDEF = NO -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# in the INCLUDE_PATH (see below) will be search if a #include is found. +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. SEARCH_INCLUDES = NO -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by # the preprocessor. -INCLUDE_PATH = +INCLUDE_PATH = -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. -INCLUDE_FILE_PATTERNS = +INCLUDE_FILE_PATTERNS = -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. To prevent a macro definition from being -# undefined via #undef or recursively expanded use the := operator +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator # instead of the = operator. -PREDEFINED = +PREDEFINED = -# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition. +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. -EXPAND_AS_DEFINED = +EXPAND_AS_DEFINED = -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all function-like macros that are alone -# on a line, have an all uppercase name, and do not end with a semicolon. Such -# function macros are typically used for boiler-plate code, and will confuse -# the parser if not removed. +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- -# Configuration::additions related to external references +# Configuration::additions related to external references #--------------------------------------------------------------------------- -# The TAGFILES option can be used to specify one or more tagfiles. -# Optionally an initial location of the external documentation -# can be added for each tagfile. The format of a tag file without -# this location is as follows: -# TAGFILES = file1 file2 ... -# Adding location for the tag files is done as follows: -# TAGFILES = file1=loc1 "file2 = loc2" ... -# where "loc1" and "loc2" can be relative or absolute paths or -# URLs. If a location is present for each tag, the installdox tool -# does not have to be run to correct the links. -# Note that each tag file must have a unique name -# (where the name does NOT include the path) -# If a tag file is not located in the directory in which doxygen -# is run, you must also specify the path to the tagfile here. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# The TAGFILES option can be used to specify one or more tagfiles. For each +# tag file the location of the external documentation should be added. The +# format of a tag file without this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. -GENERATE_TAGFILE = +GENERATE_TAGFILE = -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = YES -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will # be listed. EXTERNAL_GROUPS = YES -# The PERL_PATH should be the absolute path and name of the perl script +# The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- -# Configuration options related to the dot tool +# Configuration options related to the dot tool #--------------------------------------------------------------------------- -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base -# or super classes. Setting the tag to NO turns the diagrams off. Note that -# this option is superseded by the HAVE_DOT option below. This is only a -# fallback. It is recommended to install and use dot, since it yields more -# powerful graphs. +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. CLASS_DIAGRAMS = NO -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see http://www.mcternan.me.uk/mscgen/) to -# produce the chart and insert it in the documentation. The MSCGEN_PATH tag allows you to -# specify the directory where the mscgen tool resides. If left empty the tool is assumed to -# be found in the default search path. +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. -MSCGEN_PATH = +MSCGEN_PATH = -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented # or is not a class. HIDE_UNDOC_RELATIONS = YES -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = YES -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = FreeSans.ttf + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = NO -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = NO -# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen # will generate a graph for groups, showing the direct groups dependencies GROUP_GRAPHS = NO -# If the UML_LOOK tag is set to YES doxygen will generate inheritance and -# collaboration diagrams in a style similar to the OMG's Unified Modeling +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling # Language. UML_LOOK = YES -# If set to YES, the inheritance and collaboration graphs will show the +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# managable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + +# If set to YES, the inheritance and collaboration graphs will show the # relations between templates and their instances. TEMPLATE_RELATIONS = NO -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with # other documented files. INCLUDE_GRAPH = NO -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or # indirectly include this file. INCLUDED_BY_GRAPH = NO -# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will -# generate a call dependency graph for every global function or class method. -# Note that enabling this option will significantly increase the time of a run. -# So in most cases it will be better to enable call graphs for selected -# functions only using the \callgraph command. +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. -CALL_GRAPH = NO +CALL_GRAPH = YES -# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then doxygen will -# generate a caller dependency graph for every global function or class method. -# Note that enabling this option will significantly increase the time of a run. -# So in most cases it will be better to enable caller graphs for selected -# functions only using the \callergraph command. +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. -CALLER_GRAPH = NO +CALLER_GRAPH = YES -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will graphical hierarchy of all classes instead of a textual one. +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES -# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES -# then doxygen will show the dependencies a directory has on other directories +# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories # in a graphical way. The dependency relations are determined by the #include # relations between the files in the directories. -DIRECTORY_GRAPH = NO +DIRECTORY_GRAPH = YES -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are png, jpg, or gif -# If left blank png will be used. +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). DOT_IMAGE_FORMAT = png -# The tag DOT_PATH can be used to specify the path where the dot tool can be +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. -DOT_PATH = +DOT_PATH = -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the # \dotfile command). -DOTFILE_DIRS = +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = -# The MAX_DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of -# nodes that will be shown in the graph. If the number of nodes in a graph -# becomes larger than this value, doxygen will truncate the graph, which is -# visualized by representing a node as a red box. Note that doxygen will always -# show the root nodes and its direct children regardless of this setting. +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. -DOT_GRAPH_MAX_NODES = 50 +DOT_GRAPH_MAX_NODES = 100 -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, which results in a white background. -# Warning: Depending on the platform used, enabling this option may lead to -# badly anti-aliased labels on the edges of a graph (i.e. they become hard to -# read). +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). DOT_TRANSPARENT = NO -# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output -# files in one run (i.e. multiple -o and -T options on the command line). This -# makes dot run faster, but since only newer versions of dot (>1.8.10) +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) # support this, this feature is disabled by default. DOT_MULTI_TARGETS = NO -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermediate dot files that are used to generate +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate # the various graphs. DOT_CLEANUP = YES - -#--------------------------------------------------------------------------- -# Configuration::additions related to the search engine -#--------------------------------------------------------------------------- - -# The SEARCHENGINE tag specifies whether or not a search engine should be -# used. If set to NO the values of all tags below this one will be ignored. - -SEARCHENGINE = NO diff --git a/doc/DoxygenLayout.xml b/doc/DoxygenLayout.xml new file mode 100644 index 00000000..589d0f10 --- /dev/null +++ b/doc/DoxygenLayout.xml @@ -0,0 +1,187 @@ +<doxygenlayout version="1.0"> + <!-- Navigation index tabs for HTML output --> + <navindex> + <tab type="mainpage" visible="yes" title=""/> + <tab type="pages" visible="yes" title="" intro=""/> + <tab type="modules" visible="yes" title="" intro=""/> + <tab type="namespaces" visible="yes" title=""> + <tab type="namespacelist" visible="yes" title="" intro=""/> + <tab type="namespacemembers" visible="yes" title="" intro=""/> + </tab> + <tab type="classes" visible="yes" title=""> + <tab type="classlist" visible="yes" title="" intro=""/> + <tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/> + <tab type="hierarchy" visible="yes" title="" intro=""/> + <tab type="classmembers" visible="yes" title="" intro=""/> + </tab> + <tab type="files" visible="yes" title=""> + <tab type="filelist" visible="yes" title="" intro=""/> + <tab type="globals" visible="yes" title="" intro=""/> + </tab> + <tab type="examples" visible="yes" title="" intro=""/> + </navindex> + + <!-- Layout definition for a class page --> + <class> + <briefdescription visible="yes"/> + <includes visible="$SHOW_INCLUDE_FILES"/> + <inheritancegraph visible="$CLASS_GRAPH"/> + <collaborationgraph visible="$COLLABORATION_GRAPH"/> + <allmemberslink visible="yes"/> + <memberdecl> + <nestedclasses visible="yes" title=""/> + <publictypes title=""/> + <publicslots title=""/> + <signals title=""/> + <publicmethods title=""/> + <publicstaticmethods title=""/> + <publicattributes title=""/> + <publicstaticattributes title=""/> + <protectedtypes title=""/> + <protectedslots title=""/> + <protectedmethods title=""/> + <protectedstaticmethods title=""/> + <protectedattributes title=""/> + <protectedstaticattributes title=""/> + <packagetypes title=""/> + <packagemethods title=""/> + <packagestaticmethods title=""/> + <packageattributes title=""/> + <packagestaticattributes title=""/> + <properties title=""/> + <events title=""/> + <privatetypes title=""/> + <privateslots title=""/> + <privatemethods title=""/> + <privatestaticmethods title=""/> + <privateattributes title=""/> + <privatestaticattributes title=""/> + <friends title=""/> + <related title="" subtitle=""/> + <membergroups visible="yes"/> + </memberdecl> + <detaileddescription title=""/> + <memberdef> + <inlineclasses title=""/> + <typedefs title=""/> + <enums title=""/> + <constructors title=""/> + <functions title=""/> + <related title=""/> + <variables title=""/> + <properties title=""/> + <events title=""/> + </memberdef> + <usedfiles visible="$SHOW_USED_FILES"/> + <authorsection visible="yes"/> + </class> + + <!-- Layout definition for a namespace page --> + <namespace> + <briefdescription visible="yes"/> + <memberdecl> + <nestednamespaces visible="yes" title=""/> + <classes visible="yes" title=""/> + <typedefs title=""/> + <enums title=""/> + <functions title=""/> + <variables title=""/> + <membergroups visible="yes"/> + </memberdecl> + <detaileddescription title=""/> + <memberdef> + <inlineclasses title=""/> + <typedefs title=""/> + <enums title=""/> + <functions title=""/> + <variables title=""/> + </memberdef> + <authorsection visible="yes"/> + </namespace> + + <!-- Layout definition for a file page --> + <file> + <briefdescription visible="yes"/> + <includes visible="$SHOW_INCLUDE_FILES"/> + <includegraph visible="$INCLUDE_GRAPH"/> + <includedbygraph visible="$INCLUDED_BY_GRAPH"/> + <sourcelink visible="yes"/> + <memberdecl> + <classes visible="yes" title=""/> + <namespaces visible="yes" title=""/> + <defines title=""/> + <typedefs title=""/> + <enums title=""/> + <functions title=""/> + <variables title=""/> + <membergroups visible="yes"/> + </memberdecl> + <detaileddescription title=""/> + <memberdef> + <inlineclasses title=""/> + <defines title=""/> + <typedefs title=""/> + <enums title=""/> + <functions title=""/> + <variables title=""/> + </memberdef> + <authorsection/> + </file> + + <!-- Layout definition for a group page --> + <group> + <briefdescription visible="yes"/> + <groupgraph visible="$GROUP_GRAPHS"/> + <memberdecl> + <nestedgroups visible="yes" title=""/> + <dirs visible="yes" title=""/> + <files visible="yes" title=""/> + <namespaces visible="yes" title=""/> + <classes visible="yes" title=""/> + <defines title=""/> + <typedefs title=""/> + <enums title=""/> + <enumvalues title=""/> + <functions title=""/> + <variables title=""/> + <signals title=""/> + <publicslots title=""/> + <protectedslots title=""/> + <privateslots title=""/> + <events title=""/> + <properties title=""/> + <friends title=""/> + <membergroups visible="yes"/> + </memberdecl> + <detaileddescription title=""/> + <memberdef> + <pagedocs/> + <inlineclasses title=""/> + <defines title=""/> + <typedefs title=""/> + <enums title=""/> + <enumvalues title=""/> + <functions title=""/> + <variables title=""/> + <signals title=""/> + <publicslots title=""/> + <protectedslots title=""/> + <privateslots title=""/> + <events title=""/> + <properties title=""/> + <friends title=""/> + </memberdef> + <authorsection visible="yes"/> + </group> + + <!-- Layout definition for a directory page --> + <directory> + <briefdescription visible="yes"/> + <directorygraph visible="yes"/> + <memberdecl> + <dirs visible="yes"/> + <files visible="yes"/> + </memberdecl> + <detaileddescription title=""/> + </directory> +</doxygenlayout> diff --git a/doc/Makefile.am b/doc/Makefile.am index 040ff877..338f0772 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -1,9 +1,73 @@ # -*- Makefile -*- -.PHONY: gendoc +.PHONY: gendoc api_ref asciidoc -gendoc: +ASCIIDOCOPTS=-a pygments -a language=c -a icons \ + -a toc2 \ + -a numbered \ + -a imagesdir="./images/" \ + -a iconsdir="./images/icons" \ + -a stylesdir="${abs_srcdir}/stylesheets/" + +EXTRA_DIST = \ + core.txt \ + core.html \ + route.txt \ + route.html \ + index.txt \ + index.html \ + libnl.css \ + stylesheets \ + images \ + api + +dist-hook: + rm -f $(distdir)/aclocal.m4 + rm -f $(distdir)/configure + rm -f $(distdir)/configure.in + rm -rf $(distdir)/m4 + rm -f $(distdir)/README + rm -f $(distdir)/missing + rm -f $(distdir)/Doxyfile.in + rm -f $(distdir)/Makefile.am + rm -f $(distdir)/Makefile.in + +link_doc: +if LINK_DOC + ./gen-tags.sh > libnl.dict +else + @echo "Warning: Linking to API reference is disabled, check configure output" +endif + + +%.html: %.txt link_doc + ./resolve-asciidoc-refs.py $< > asciidoc.tmp + asciidoc $(ASCIIDOCOPTS) -o $@ asciidoc.tmp +if LINK_DOC + ./doxygen-link.py libnl.dict $@ > asciidoc.tmp + mv asciidoc.tmp $@ +endif + +asciidoc: core.html route.html index.html + +api_ref: doxygen Doxyfile; -distclean-local: - rm -f html/*; +gendoc: +if GENERATE_DOC +if HAVE_DOXYGEN + $(MAKE) api_ref +else + @echo "Warning: Building of API reference (doxygen) is disabled, check autoconf logs" +endif +if HAVE_ASCIIDOC + $(MAKE) asciidoc +else + @echo "Warning: Building of asciidoc files is disabled, check autoconf logs" +endif +else + @echo "Warning: Building of documentation disabled by user or autoconf" +endif + +clean-local: + rm -f api/* libnl.dict *.html; diff --git a/doc/README b/doc/README new file mode 100644 index 00000000..ddcdf14f --- /dev/null +++ b/doc/README @@ -0,0 +1,13 @@ +Requirements to build documentation + +mscgen + http://www.mcternan.me.uk/mscgen/ + +mscgen-filter-1.2 + http://code.google.com/p/asciidoc-mscgen-filter/ + +asciidoc > 8.6.x +doxygen > 1.8.0 + +Building the documentation: +make gendoc diff --git a/doc/api/.gitignore b/doc/api/.gitignore new file mode 100644 index 00000000..e57ca889 --- /dev/null +++ b/doc/api/.gitignore @@ -0,0 +1,8 @@ +*.html +*.png +*.css +*.map +*.md5 +*.js +formula.repository +jquery.js diff --git a/doc/autogen.sh b/doc/autogen.sh new file mode 100755 index 00000000..a5696148 --- /dev/null +++ b/doc/autogen.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +autoreconf -fi; +rm -Rf autom4te.cache; diff --git a/doc/configure.ac b/doc/configure.ac new file mode 100644 index 00000000..d4cda857 --- /dev/null +++ b/doc/configure.ac @@ -0,0 +1,107 @@ +# +# configure.in +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation version 2.1 +# of the License. +# +# Copyright (c) 2003-2013 Thomas Graf <tgraf@suug.ch> +# + +AC_INIT(libnl-doc, [3.2.25], [http://www.infradead.org/~tgr/libnl/]) +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_AUX_DIR([build-aux]) +AM_INIT_AUTOMAKE([foreign]) +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES(yes)], []) + +m4_include([m4/ax_python.m4]) + +# +# Generating the documentation +# +AC_ARG_ENABLE([doc], + AS_HELP_STRING([--disable-doc], [Do not generate documentation]), + [generate_doc="$enableval"], [generate_doc=auto]) + +AX_PYTHON + +if test "x$generate_doc" != "xno"; then + AC_PROG_SED + AC_PROG_EGREP + + AC_CHECK_PROG(HAVE_DOXYGEN, [doxygen], yes, no) + if test "x$HAVE_DOXYGEN" = "xno" -a "x$generate_doc" = "xyes"; then + AC_MSG_ERROR([*** doxygen package required to generate documentation]) + fi + + AC_CHECK_PROG(HAVE_DOT, [dot], yes, no) + if test "x$HAVE_DOT" = "xno"; then + if test "x$generate_doc" = "xyes"; then + AC_MSG_ERROR([*** graphviz package required to generate documentation]) + else + AC_MSG_WARN([*** graphviz not found, disabling building of API reference]) + HAVE_DOXYGEN=no + fi + fi + + AC_CHECK_PROG(HAVE_ASCIIDOC, [asciidoc], yes, no) + if test "x$HAVE_ASCIIDOC" = "xno"; then + if test "x$generate_doc" = "xyes"; then + AC_MSG_ERROR([*** asciidoc package required to generate documentation]) + else + AC_MSG_WARN([*** asciidoc not found, disabling building of guides]) + fi + fi + + AC_CHECK_PROG(HAVE_SOURCE_HIGHLIGHT, [source-highlight], yes, no) + if test "x$HAVE_SOURCE_HIGHLIGHT" = "xno"; then + if test "x$generate_doc" = "xyes"; then + AC_MSG_ERROR([*** source-highlight required to generate documentation]) + else + AC_MSG_WARN([*** source-highlight not found, disabling building of guides]) + HAVE_ASCIIDOC=no + fi + fi + + AC_CHECK_PROG(HAVE_MSCGEN, [mscgen], yes, no) + if test "x$HAVE_MSCGEN" = "xno"; then + AC_MSG_WARN([*** mscgen not found, get it at http://www.mcternan.me.uk/mscgen/]) + if test "x$generate_doc" = "xyes"; then + AC_MSG_ERROR([*** mscgen package required to generate documentation]) + else + AC_MSG_WARN([*** Disabling building of guides]) + HAVE_ASCIIDOC=no + HAVE_DOXYGEN=no + fi + fi + + AC_CHECK_PROG(HAVE_PYGMENTIZE, [pygmentize], yes, no) + if test "x$HAVE_PYGMENTIZE" = "xno"; then + if test "x$generate_doc" = "xyes"; then + AC_MSG_ERROR([*** pygmentize package required to generate documentation]) + else + AC_MSG_WARN([*** Disabling building of guides]) + HAVE_ASCIIDOC=no + fi + fi + + link_doc=yes + if test "x$HAVE_DOXYGEN" = "xno"; then + AC_MSG_WARN([*** Disabling API linking due to missing doxygen package]) + link_doc=no + fi +fi + +AM_CONDITIONAL([LINK_DOC], [test "x$link_doc" = "xyes"]) +AM_CONDITIONAL([HAVE_DOXYGEN], [test "x$HAVE_DOXYGEN" = "xyes"]) +AM_CONDITIONAL([HAVE_ASCIIDOC], [test "x$HAVE_ASCIIDOC" = "xyes"]) + +AM_CONDITIONAL([GENERATE_DOC], [test "x$generate_doc" != "xno"]) + +AC_CONFIG_FILES([ +Doxyfile +Makefile +]) + +AC_OUTPUT diff --git a/doc/core.txt b/doc/core.txt new file mode 100644 index 00000000..042369d3 --- /dev/null +++ b/doc/core.txt @@ -0,0 +1,3017 @@ +//// + vim.syntax: asciidoc + + Copyright (c) 2011 Thomas Graf <tgraf@suug.ch> +//// + +Netlink Library (libnl) +======================= +Thomas Graf <tgraf@suug.ch> +3.2, May 9 2011: +:numbered: + +== Introduction + +The core library contains the fundamentals required to communicate +over netlink sockets. It deals with connecting and disconnectng of +sockets, sending and receiving of data, construction and parsing of +messages, provides a customizeable receiving state machine, and +provides a abstract data type framework which eases the implementation +of object based netlink protocols where objects are added, removed, or +modified using a netlink based protocol. + +.Library Hierarchy + +The suite is split into multiple libraries: + +image:library_overview.png["Library Hierarchy"] + +link:core.html[Netlink Library] (libnl):: +Socket handling, sending and receiving, message construction and parsing, ... + +link:route.html[Routing Family Library] (libnl-route):: +Adresses, links, neighbours, routing, traffic control, neighbour tables, ... + +Netfilter Library (libnl-nf):: +Connection tracking, logging, queueing + +Generic Netlink Library (libnl-genl):: +Controller API, family and command registration + + +=== How To Read This Documentation + +The libraries provide a broad set of APIs of which most applications only +require a small subset of it. Depending on the type of application, some +users may only be interested in the low level netlink messaging API while +others wish to make heavy use of the high level API. + +In any case it is recommended to get familiar with the netlink protocol +first. + +- <<core_netlink_fundamentals>> + +The low level APIs are described in: + +- <<core_sockets>> +- <<core_send_recv>> + + +=== Linking to this Library + +.Checking the presence of the library using autoconf + +Projects using autoconf may use +PKG_CHECK_MODULES()+ to check if +a specific version of libnl is available on the system. The example +below also shows how to retrieve the +CFLAGS+ and linking dependencies +required to link against the library. + +The following example shows how to check for a specific version of libnl. If +found, it extends the `CFLAGS` and `LIBS` variable appropriately: + +[source] +---- +PKG_CHECK_MODULES(LIBNL3, libnl-3.0 >= 3.1, [have_libnl3=yes], [have_libnl3=no]) +if (test "${have_libnl3}" = "yes"); then + CFLAGS+="$LIBNL3_CFLAGS" + LIBS+="$LIBNL3_LIBS" +fi +---- + +NOTE: The pkgconfig file is named +libnl-3.0.pc+ for historic reasons, it also + covers library versions >= 3.1. + +.Header Files + +The main header file is `<netlink/netlink.h>`. Additional headers may need to +be included in your sources depending on the subsystems and components your +program makes use of. + +[source,c] +----- +#include <netlink/netlink.h> +#include <netlink/cache.h> +#include <netlink/route/link.h> +----- + +.Version Dependent Code + +If your code wishes to be capable to link against multiple versions of libnl +you may have direct the compiler to only include portions on the code depending +on the version of libnl that it is compiled against. + +[source,c] +----- +#include <netlink/version.h> + +#if LIBNL_VER_NUM >= LIBNL_VER(3,1) + /* include code if compiled with libnl version >= 3.1 */ +#endif +----- + +.Linking +----- +$ gcc myprogram.c -o myprogram $(pkgconfig --cflags --libs libnl-3.0) +----- + +=== Debugging + +The library has been compiled with debugging statements enabled it will +print debug information to +stderr+ if the environment variable +NLDBG+ +is set to > 0. + +----- +$ NLDBG=2 ./myprogram +----- + +.Debugging Levels +[options="header", width="80%", cols="1,5", align="center"] +|=============================================================== +| Level | Description +| 0 | Debugging disabled (default) +| 1 | Warnings, important events and notifications +| 2 | More or less important debugging messages +| 3 | Repetitive events causing a flood of debugging messages +| 4 | Even less important messages +|=============================================================== + +.Debugging the Netlink Protocol + +It is often useful to peek into the stream of netlink messages exchanged +with other sockets. Setting the environment variable +NLCB=debug+ will +cause the debugging message handlers to be used which in turn print the +netlink messages exchanged in a human readable format to to +stderr+: + +----- +$ NLCB=debug ./myprogram +-- Debug: Sent Message: +-------------------------- BEGIN NETLINK MESSAGE --------------------------- + [HEADER] 16 octets + .nlmsg_len = 20 + .nlmsg_type = 18 <route/link::get> + .nlmsg_flags = 773 <REQUEST,ACK,ROOT,MATCH> + .nlmsg_seq = 1301410712 + .nlmsg_pid = 20014 + [PAYLOAD] 16 octets + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +--------------------------- END NETLINK MESSAGE --------------------------- +-- Debug: Received Message: +-------------------------- BEGIN NETLINK MESSAGE --------------------------- + [HEADER] 16 octets + .nlmsg_len = 996 + .nlmsg_type = 16 <route/link::new> + .nlmsg_flags = 2 <MULTI> + .nlmsg_seq = 1301410712 + .nlmsg_pid = 20014 + [PAYLOAD] 16 octets + 00 00 04 03 01 00 00 00 49 00 01 00 00 00 00 00 ........I....... + [ATTR 03] 3 octets + 6c 6f 00 lo. + [PADDING] 1 octets + 00 . + [ATTR 13] 4 octets + 00 00 00 00 .... + [ATTR 16] 1 octets + 00 . + [PADDING] 3 octets + 00 00 00 ... + [ATTR 17] 1 octets + 00 . + [...] +--------------------------- END NETLINK MESSAGE --------------------------- + +----- + +[[core_netlink_fundamentals]] +== Netlink Protocol Fundamentals + +The netlink protocol is a socket based IPC mechanism used for +communication between userspace processes and the kernel or between +userspace processes themselves. The netlink protocol is based on BSD +sockets and uses the +AF_NETLINK+ address family. Every netlink +protocol uses its own protocol number (e.g. +NETLINK_ROUTE+, ++NETLINK_NETFILTER+, etc). Its addressing schema is based on a 32 bit +port number, formerly referred to as PID, which uniquely identifies +each peer. + +[[core_addressing]] +=== Addressing + +The netlink address (port) consists of a 32bit integer. Port 0 (zero) +is reserved for the kernel and refers to the kernel side socket of each +netlink protocol family. Other port numbers usually refer to user space +owned sockets, although this is not enforced. + +NOTE: In the beginning, it was common practice to use the process + identifier (PID) as the local port number. This became unpractical + with the introduction of threaded netlink applications and + applications requiring multiple sockets. Therefore libnl generates + unique port numbers based on the process identifier and adds an + offset to it allowing for multiple sockets to be used. The initial + socket will still equal to the process identifier for backwards + compatibility reasons. + +image:addressing.png["Addressing Example"] + +The above figure illustrates three applications and the kernel side +exposing two kernel side sockets. It shows the common netlink use +cases: + + * User space to kernel + * User space to user space + * Listening to kernel multicast notifications + +.User Space to Kernel + +The most common form of netlink usage is for a user space application +to send requests to the kernel and process the reply which is either +an error message or a success notification. + +["mscgen"] +-------- +msc { + App1,App2,Kernel; + App1=>Kernel [label="request (src=11, dst=0)"]; + App1<=Kernel [label="reply (src=0, dst=11)"]; + ...; + App2=>Kernel [label="request (src=21, dst=0)"]; + App2<=Kernel [label="reply (src=0, dst=21)"]; +} +-------- + +.User Space to User Space + +Netlink may also be used as an IPC mechanism to communicate between user +space applications directly. Communication is not limited to two peers, +any number of peers may communicate with each other and multicasting +capabilities allow to reach multiple peers with a single message. + +In order for the sockets to be visible to each other, both sockets must +be created for the same netlink protocol family. + +["mscgen"] +-------- +msc { + App2,App3; + App2=>App3 [label="request (src=22, dst=31)"]; + App2<=App3 [label="reply (src=31, dst=22)"]; + ...; +} +-------- + +.User space listening to kernel notifications + +This form of netlink communication is typically found in user space +daemons that need to act on certain kernel events. Such daemons will +typically maintain a netlink socket subscribed to a multicast group that +is used by the kernel to notify interested user space parties about +specific events. + +["mscgen"] +-------- +msc { + Kernel,App3; + Kernel=>App3 [label="notification (src=0, group=foo)"]; + ...; +} +-------- + +Use of multicasting is preferred over direct addressing due to the +flexibility in exchanging the user space component at any time without +the kernel noticing. + +[[core_msg_format]] +=== Message Format + +A netlink protocol is typically based on messages and consists of the +netlink message header (+struct nlmsghdr+) plus the payload attached +to it. The payload can consist of arbitrary data but usually contains +a fixed size protocol specific header followed by a stream of +attributes. + +.Netlink message header (struct nlmsghdr) + +image:nlmsghdr.png[align="center", alt="Netlink Message Header"] + +Total Length (32bit):: +Total length of the message in bytes including the netlink message header. + +Message Type (16bit):: +The message type specifies the type of payload the message is carrying. +Several standard message types are defined by the netlink protocol. +Additional message types may be defined by each protocol family. See +<<core_msg_types>> for additional information. + +Message Flags (16bit):: +The message flags may be used to modify the behaviour of a message type. +See section <<core_msg_flags>> for a list of standard message flags. + +Sequence Number (32bit):: +The sequence number is optional and may be used to allow referring to +a previous message, e.g. an error message can refer to the original +request causing the error. + +Port Number (32bit):: +The port number specifies the peer to which the message should be delivered +to. If not specified, the message will be delivered to the first matching +kernel side socket of the same protocol family. + +[[core_msg_types]] +=== Message Types + +Netlink differs between requests, notifications, and replies. Requests +are messages which have the +NLM_F_REQUEST+ flag set and are meant to +request an action from the receiver. A request is typically sent from +a userspace process to the kernel. While not strictly enforced, requests +should carry a sequence number incremented for each request sent. + +Depending on the nature of the request, the receiver may reply to the +request with another netlink message. The sequence number of a reply +must match the sequence number of the request it relates to. + +Notifications are of informal nature and no reply is expected, therefore +the sequence number is typically set to 0. + +["mscgen"] +-------- +msc { + A,B; + A=>B [label="GET (seq=1, NLM_F_REQUEST)"]; + A<=B [label="PUT (seq=1)"]; + ...; + A<=B [label="NOTIFY (seq=0)"]; +} +-------- + + +The type of message is primarly identified by its 16 bit message type set +in the message header. The following standard message types are defined: + +- +NLMSG_NOOP+ - No operation, message must be discarded +- +NLMSG_ERROR+ - Error message or ACK, see <<core_errmsg>> + respectively <<core_msg_ack>> +- +NLMSG_DONE+ - End of multipart sequence, see <<core_multipart>> +- +NLMSG_OVERRUN+ - Overrun notification (Error) + +Every netlink protocol is free to define own message types. Note that +message type values +< NLMSG_MIN_TYPE (0x10)+ are reserved and may +not be used. + +It is common practice to use own message types to implement RPC schemas. +Suppose the goal of the netlink protocol you are implementing is allow +configuration of a particular network device, therefore you want to +provide read/write access to various configuration options. The typical +"netlink way" of doing this would be to define two message types ++MSG_SETCFG+, +MSG_GETCFG+: + +[source,c] +-------- +#define MSG_SETCFG 0x11 +#define MSG_GETCFG 0x12 +-------- + +Sending a +MSG_GETCFG+ request message will typically trigger a reply +with the message type +MSG_SETCFG+ containing the current configuration. +In object oriented terms one would describe this as "the kernel sets +the local copy of the configuration in userspace". + +["mscgen"] +-------- +msc { + A,B; + A=>B [label="MSG_GETCFG (seq=1, NLM_F_REQUEST)"]; + A<=B [label="MSG_SETCFG (seq=1)"]; +} +-------- + +The configuration may be changed by sending a +MSG_SETCFG+ which will +be responded to with either a ACK (see <<core_msg_ack>>) +or a error message (see <<core_errmsg>>). + +["mscgen"] +-------- +msc { + A,B; + A=>B [label="MSG_SETCFG (seq=1, NLM_F_REQUEST, NLM_F_ACK)"]; + A<=B [label="ACK (seq=1)"]; +} +-------- + +Optionally, the kernel may send out notifications for configuration +changes allowing userspace to listen for changes instead of polling +frequently. Notifications typically reuse an existing message type +and rely on the application using a separate socket to differ between +requests and notifications but you may also specify a separate message +type. + +["mscgen"] +-------- +msc { + A,B; + A<=B [label="MSG_SETCFG (seq=0)"]; +} +-------- + +[[core_multipart]] +==== Multipart Messages + +Although in theory a netlink message can be up to 4GiB in size. The socket +buffers are very likely not large enough to hold message of such sizes. +Therefore it is common to limit messages to one page size (PAGE_SIZE) and +use the multipart mechanism to split large pieces of data into several +messages. A multipart message has the flag +NLM_F_MULTI+ set and the +receiver is expected to continue receiving and parsing until the special +message type +NLMSG_DONE+ is received. + +Multipart messages unlike fragmented ip packets must not be reassmbled +even though it is perfectly legal to do so if the protocols wishes to +work this way. Often multipart message are used to send lists or trees +of objects were each multipart message simply carries multiple objects +allow for each message to be parsed independently. + +["mscgen"] +-------- +msc { + A,B; + A=>B [label="GET (seq=1, NLM_F_REQUEST)"]; + A<=B [label="PUT (seq=1, NLM_F_MULTI)"]; + ...; + A<=B [label="PUT (seq=1, NLM_F_MULTI)"]; + A<=B [label="NLMSG_DONE (seq=1)"]; +} +-------- + +[[core_errmsg]] +==== Error Message + +Error messages can be sent in response to a request. Error messages must +use the standard message type +NLMSG_ERROR+. The payload consists of a +error code and the original netlink mesage header of the request. + +image:nlmsgerr.png["Netlink Errror Message header"] + +Error messages should set the sequence number to the sequence number +of the request which caused the error. + +["mscgen"] +-------- +msc { + A,B; + A=>B [label="GET (seq=1, NLM_F_REQUEST)"]; + A<=B [label="NLMSG_ERROR code=EINVAL (seq=1)"]; +} +-------- + +[[core_msg_ack]] +==== ACKs + +A sender can request an ACK message to be sent back for each request +processed by setting the +NLM_F_ACK+ flag in the request. This is typically +used to allow the sender to synchronize further processing until the +request has been processed by the receiver. + +["mscgen"] +-------- +msc { + A,B; + A=>B [label="GET (seq=1, NLM_F_REQUEST | NLM_F_ACK)"]; + A<=B [label="ACK (seq=1)"]; +} +-------- + +ACK messages also use the message type +NLMSG_ERROR+ and payload +format but the error code is set to 0. + +[[core_msg_flags]] +==== Message Flags + +The following standard flags are defined + +[source,c] +-------- +#define NLM_F_REQUEST 1 +#define NLM_F_MULTI 2 +#define NLM_F_ACK 4 +#define NLM_F_ECHO 8 +-------- + +- `NLM_F_REQUEST` - Message is a request, see <<core_msg_types>>. +- `NLM_F_MULTI` - Multipart message, see <<core_multipart>> +- `NLM_F_ACK` - ACK message requested, see <<core_msg_ack>>. +- `NLM_F_ECHO` - Request to echo the request. + +The flag +NLM_F_ECHO+ is similar to the `NLM_F_ACK` flag. It can be +used in combination with `NLM_F_REQUEST` and causes a notification +which is sent as a result of a request to also be sent to the sender +regardless of whether the sender has subscribed to the corresponding +multicast group or not. See <<core_multicast>> + +Additional universal message flags are defined which only apply for ++GET+ requests: + +[source,c] +-------- +#define NLM_F_ROOT 0x100 +#define NLM_F_MATCH 0x200 +#define NLM_F_ATOMIC 0x400 +#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH) +-------- + +- `NLM_F_ROOT` - Return based on root of tree. +- `NLM_F_MATCH` - Return all matching entries. +- `NLM_F_ATOMIC` - Obsoleted, once used to request an atomic operation. +- `NLM_F_DUMP` - Return a list of all objects + (`NLM_F_ROOT`|`NLM_F_MATCH`). + +Use of these flags is completely optional and many netlink protocols only +make use of the `NLM_F_DUMP` flag which typically requests the receiver +to send a list of all objects in the context of the message type as a +sequence of multipart messages (see <<core_multipart>>). + +Another set of flags exist related to `NEW` or `SET` requests. These +flags are mutually exclusive to the `GET` flags: + +[source,c] +-------- +#define NLM_F_REPLACE 0x100 +#define NLM_F_EXCL 0x200 +#define NLM_F_CREATE 0x400 +#define NLM_F_APPEND 0x800 +-------- + +- `NLM_F_REPLACE` - Replace an existing object if it exists. +- `NLM_F_EXCL` - Do not update object if it exists already. +- `NLM_F_CREATE` - Create object if it does not exist yet. +- `NLM_F_APPEND` - Add object at end of list. + +Behaviour of these flags may differ slightly between different netlink +protocols. + +[[core_seq_num]] +=== Sequence Numbers + +Netlink allows the use of sequence numbers to help relate replies to +requests. It should be noted that unlike in protocols such as TCP +there is no strict enforcment of the sequence number. The sole purpose +of sequence numbers is to assist a sender in relating replies to the +corresponding requests. See <<core_msg_types>> for more information. + +Sequence numbers are managed on a per socket basis, see +<<core_sk_seq_num>> for more information on how to use sequence numbers. + +[[core_multicast]] +=== Multicast Groups + +TODO + +See <<core_sk_multicast>> + +[[core_sockets]] +== Netlink Sockets + +In order to use the netlink protocol, a netlink socket is required. +Each socket defines an independent context for sending and receiving of +messages. An application may make use multiple sockets, e.g. a socket to +send requests and receive the replies and another socket subscribed to a +multicast group to receive notifications. + +=== Socket structure (struct nl_sock) + +The netlink socket and all related attributes including the actual file +descriptor are represented by +struct nl_sock+. + +[source,c] +-------- +#include <netlink/socket.h> + +struct nl_sock *nl_socket_alloc(void) +void nl_socket_free(struct nl_sock *sk) +-------- + +The application must allocate an instance of +struct nl_sock+ for each +netlink socket it wishes to use. + +[[core_sk_seq_num]] +=== Sequence Numbers + +The library will automatically take care of sequence number handling +for the application. A sequence number counter is stored in the +socket structure which is used and incremented automatically when a +message needs to be sent which is expected to generate a reply such as +an error or any other message type that needs to be related to the +original message. + +Alternatively, the counter can be used directly via the function +nl_socket_use_seq(). It will return the current value of the counter +and increment it by one afterwards. + +[source,c] +-------- +#include <netlink/socket.h> + +unsigned int nl_socket_use_seq(struct nl_sock *sk); +-------- + +Most applications will not want to deal with sequence number handling +themselves though. When using nl_send_auto() the sequence number is +filled in automatically and matched again when a reply is received. See +section <<core_send_recv>> for more information. + +This behaviour can and must be disabled if the netlink protocol +implemented does not use a request/reply model, e.g. when a socket is +used to receive notification messages. + +[source,c] +-------- +#include <netlink/socket.h> + +void nl_socket_disable_seq_check(struct nl_sock *sk); +-------- + +For more information on the theory behind netlink sequence numbers, +see section <<core_seq_num>>. + +[[core_sk_multicast]] +=== Multicast Group Subscriptions + +Each socket can subscribe to any number of multicast groups of the +netlink protocol it is connected to. The socket will then receive a +copy of each message sent to any of the groups. Multicast groups are +commonly used to implement event notifications. + +Prior to kernel 2.6.14 the group subscription was performed using a +bitmask which limited the number of groups per protocol family to 32. +This outdated interface can still be accessed via the function +nl_join_groups() even though it is not recommended for new code. + +[source,c] +-------- +#include <netlink/socket.h> + +void nl_join_groups(struct nl_sock *sk, int bitmask); +-------- + +Starting with 2.6.14 a new method was introduced which supports subscribing +to an almost infinite number of multicast groups. + +[source,c] +-------- +#include <netlink/socket.h> + +int nl_socket_add_memberships(struct nl_sock *sk, int group, ...); +int nl_socket_drop_memberships(struct nl_sock *sk, int group, ...); +-------- + +==== Multicast Example + +[source,c] +-------- +#include <netlink/netlink.h> +#include <netlink/socket.h> +#include <netlink/msg.h> + +/* + * This function will be called for each valid netlink message received + * in nl_recvmsgs_default() + */ +static int my_func(struct nl_msg *msg, void *arg) +{ + return 0; +} + +struct nl_sock *sk; + +/* Allocate a new socket */ +sk = nl_socket_alloc(); + +/* + * Notifications do not use sequence numbers, disable sequence number + * checking. + */ +nl_socket_disable_seq_check(sk); + +/* + * Define a callback function, which will be called for each notification + * received + */ +nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, my_func, NULL); + +/* Connect to routing netlink protocol */ +nl_connect(sk, NETLINK_ROUTE); + +/* Subscribe to link notifications group */ +nl_socket_add_memberships(sk, RTNLGRP_LINK, 0); + +/* + * Start receiving messages. The function nl_recvmsgs_default() will block + * until one or more netlink messages (notification) are received which + * will be passed on to my_func(). + */ +while (1) + nl_recvmsgs_default(sock); +-------- + +[[core_sk_cb]] +=== Modifiying Socket Callback Configuration + +See <<core_cb>> for more information on +callback hooks and overwriting capabilities. + +Each socket is assigned a callback configuration which controls the +behaviour of the socket. This is f.e. required to have a separate +message receive function per socket. It is perfectly legal to share +callback configurations between sockets though. + +The following functions can be used to access and set the callback +configuration of a socket: + +[source,c] +-------- +#include <netlink/socket.h> + +struct nl_cb *nl_socket_get_cb(const struct nl_sock *sk); +void nl_socket_set_cb(struct nl_sock *sk, struct nl_cb *cb); +-------- + +Additionaly a shortcut exists to modify the callback configuration +assigned to a socket directly: + +[source,c] +-------- +#include <netlink/socket.h> + +int nl_socket_modify_cb(struct nl_sock *sk, enum nl_cb_type type, enum nl_cb_kind kind, + nl_recvmsg_msg_cb_t func, void *arg); +-------- + +.Example: +[source,c] +-------- +#include <netlink/socket.h> + +// Call my_input() for all valid messages received in socket sk +nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, my_input, NULL); +-------- + +=== Socket Attributes + +.Local Port + +The local port number uniquely identifies the socket and is used to +address it. A unique local port is generated automatically when the +socket is allocated. It will consist of the Process ID (22 bits) and a +random number (10 bits) thus allowing up to 1024 sockets per process. + +[source,c] +-------- +#include <netlink/socket.h> + +uint32_t nl_socket_get_local_port(const struct nl_sock *sk); +void nl_socket_set_local_port(struct nl_sock *sk, uint32_t port); +-------- + +See section <<core_addressing>> for more information on port numbers. + +CAUTION: Overwriting the local port is possible but you have to ensure +that the provided value is unique and no other socket in any other +application is using the same value. + +.Peer Port + +A peer port can be assigned to the socket which will result in all +unicast messages sent over the socket to be addresses to the peer. If +no peer is specified, the message is sent to the kernel which will try +to automatically bind the socket to a kernel side socket of the same +netlink protocol family. It is common practice not to bind the socket +to a peer port as typically only one kernel side socket exists per +netlink protocol family. + +[source,c] +-------- +#include <netlink/socket.h> + +uint32_t nl_socket_get_peer_port(const struct nl_sock *sk); +void nl_socket_set_peer_port(struct nl_sock *sk, uint32_t port); +-------- + +See section <<core_addressing>> for more information on port numbers. + +.File Descriptor + +Netlink uses the BSD socket interface, therefore a file descriptor is +behind each socket and you may use it directly. + +[source,c] +-------- +#include <netlink/socket.h> + +int nl_socket_get_fd(const struct nl_sock *sk); +-------- + +If a socket is used to only receive notifications it usually is best +to put the socket in non-blocking mode and periodically poll for new +notifications. + +[source,c] +-------- +#include <netlink/socket.h> + +int nl_socket_set_nonblocking(const struct nl_sock *sk); +-------- + +.Send/Receive Buffer Size + +The socket buffer is used to queue netlink messages between sender and +receiver. The size of these buffers specifies the maximum size you +will be able to write() to a netlink socket, i.e. it will indirectly +define the maximum message size. The default is 32KiB. + +[source,c] +-------- +#include <netlink/socket.h> + +int nl_socket_set_buffer_size(struct nl_sock *sk, int rx, int tx); +-------- + +[[core_sk_cred]] +.Enable/Disable Credentials + +TODO + +[source,c] +-------- +#include <netlink/socket.h> + +int nl_socket_set_passcred(struct nl_sock *sk, int state); +-------- + +.Enable/Disable Auto-ACK Mode + +The following functions allow to enable/disable Auto-ACK mode on a socket. +See <<core_auto_ack>> for more information on what implications that has. +Auto-ACK mode is enabled by default. + +[source,c] +-------- +#include <netlink/socket.h> + +void nl_socket_enable_auto_ack(struct nl_sock *sk); +void nl_socket_disable_auto_ack(struct nl_sock *sk); +-------- + +.Enable/Disable Message Peeking + +If enabled, message peeking causes nl_recv() to try and use MSG_PEEK +to retrieve the size of the next message received and allocate a +buffer of that size. Message peeking is enabled by default but can be +disabled using the following function: + +[source,c] +-------- +#include <netlink/socket.h> + +void nl_socket_enable_msg_peek(struct nl_sock *sk); +void nl_socket_disable_msg_peek(struct nl_sock *sk); +-------- + +.Enable/Disable Receival of Packet Information + +If enabled, each received netlink message from the kernel will include +an additional struct nl_pktinfo in the control message. The following +function can be used to enable/disable receival of packet information. + +[source,c] +-------- +#include <netlink/socket.h> + +int nl_socket_recv_pktinfo(struct nl_sock *sk, int state); +-------- + +CAUTION: Processing of NETLINK_PKTINFO has not been implemented yet. + +[[core_send_recv]] +== Sending and Receiving of Messages / Data + +[[core_send]] +=== Sending Messages + +The standard method of sending a netlink message over a netlink socket +is to use the function nl_send_auto(). It will automatically complete +the netlink message by filling the missing bits and pieces in the +netlink message header and will deal with addressing based on the +options and address set in the netlink socket. The message is then +passed on to nl_send(). + +If the default sending semantics implemented by nl_send() do not suit +the application, it may overwrite the sending function nl_send() by +specifying an own implementation using the function +nl_cb_overwrite_send(). + +[source,c] +-------- + nl_send_auto(sk, msg) + | + |-----> nl_complete_msg(sk, msg) + | + | + | Own send function specified via nl_cb_overwrite_send() + |- - - - - - - - - - - - - - - - - - - - + v v + nl_send(sk, msg) send_func() +-------- + +.Using nl_send() + +If you do not require any of the automatic message completion +functionality you may use nl_send() directly but beware that any +internal calls to nl_send_auto() by the library to send netlink +messages will still use nl_send(). Therefore if you wish to use any +higher level interfaces and the behaviour of nl_send() is to your +dislike then you must overwrite the nl_send() function via +nl_cb_overwrite_send() + +The purpose of nl_send() is to embed the netlink message into a iovec +structure and pass it on to nl_send_iovec(). + +[source,c] +-------- + nl_send(sk, msg) + | + v + nl_send_iovec(sk, msg, iov, iovlen) +-------- + +.Using nl_send_iovec() + +nl_send_iovec() expects a finalized netlink message and fills out the +struct msghdr used for addressing. It will first check if the struct +nl_msg is addressed to a specific peer (see nlmsg_set_dst()). If not, +it will try to fall back to the peer address specified in the socket +(see nl_socket_set_peer_port(). Otherwise the message will be sent +unaddressed and it is left to the kernel to find the correct peer. + +nl_send_iovec() also adds credentials if present and enabled +(see <<core_sk_cred>>). + +The message is then passed on to nl_sendmsg(). + +[source,c] +-------- + nl_send_iovec(sk, msg, iov, iovlen) + | + v + nl_sendmsg(sk, msg, msghdr) +-------- + +.Using nl_sendmsg() + +nl_sendmsg() expects a finalized netlink message and an optional +struct msghdr containing the peer address. It will copy the local +address as defined in the socket (see nl_socket_set_local_port()) into +the netlink message header. + +At this point, construction of the message finished and it is ready to +be sent. + +[source,c] +-------- + nl_sendmsg(sk, msg, msghdr) + |- - - - - - - - - - - - - - - - - - - - v + | NL_CB_MSG_OUT() + |<- - - - - - - - - - - - - - - - - - - -+ + v + sendmsg() +-------- + +Before sending the application has one last chance to modify the +message. It is passed to the NL_CB_MSG_OUT callback function which +may inspect or modify the message and return an error code. If this +error code is NL_OK the message is sent using sendmsg() resulting in +the number of bytes written being returned. Otherwise the message +sending process is aborted and the error code specified by the +callback function is returned. See <<core_sk_cb>> for more information +on how to set callbacks. + +.Sending Raw Data with nl_sendto() + +If you wish to send raw data over a netlink socket, the following +function will pass on any buffer provided to it directly to sendto(): + +[source,c] +-------- +#include <netlink/netlink.h> + +int nl_sendto(struct nl_sock *sk, void *buf, size_t size); +-------- + +.Sending of Simple Messages + +A special interface exists for sending of trivial messages. The function +expects the netlink message type, optional netlink message flags, and an +optional data buffer and data length. +[source,c] +-------- +#include <netlink/netlink.h> + +int nl_send_simple(struct nl_sock *sk, int type, int flags, + void *buf, size_t size); +-------- + +The function will construct a netlink message header based on the message +type and flags provided and append the data buffer as message payload. The +newly constructed message is sent with nl_send_auto(). + +The following example will send a netlink request message causing the +kernel to dump a list of all network links to userspace: + +[source,c] +-------- +#include <netlink/netlink.h> + +struct nl_sock *sk; +struct rtgenmsg rt_hdr = { + .rtgen_family = AF_UNSPEC, +}; + +sk = nl_socket_alloc(); +nl_connect(sk, NETLINK_ROUTE); + +nl_send_simple(sock, RTM_GETLINK, NLM_F_DUMP, &rt_hdr, sizeof(rt_hdr)); +-------- + +[[core_recv]] +=== Receiving Messages + +The easiest method to receive netlink messages is to call nl_recvmsgs_default(). +It will receive messages based on the semantics defined in the socket. The +application may customize these in detail although the default behaviour will +probably suit most applications. + +nl_recvmsgs_default() will also be called internally by the library whenever +it needs to receive and parse a netlink message. + +The function will fetch the callback configuration stored in the socket and +call nl_recvmsgs(): + +[source,c] +-------- + nl_recvmsgs_default(sk) + | + | cb = nl_socket_get_cb(sk) + v + nl_recvmsgs(sk, cb) +-------- + +.Using nl_recvmsgs() + +nl_recvmsgs() implements the actual receiving loop, it blocks until a +netlink message has been received unless the socket has been put into +non-blocking mode. + +For the unlikely scenario that certain required receive characteristics +can not be achieved by fine tuning the internal recvmsgs function using +the callback configuration (see <<core_sk_cb>>) the application may provide +a complete own implementation of it and overwrite all calls to nl_recvmsgs() +with the function nl_cb_overwrite_recvmsgs(). + +[source,c] +-------- + nl_recvmsgs(sk, cb) + | + | Own recvmsgs function specified via nl_cb_overwrite_recvmsgs() + |- - - - - - - - - - - - - - - - - - - - + v v + internal_recvmsgs() my_recvmsgs() +-------- + +[[core_recv_character]] +.Receive Characteristics + +If the application does not provide its own recvmsgs() implementation +with the function nl_cb_overwrite_recvmsgs() the following characteristics +apply while receiving data from a netlink socket: + +[source,c] +-------- + internal_recvmsgs() + | ++-------------->| Own recv function specified with nl_cb_overwrite_recv() +| |- - - - - - - - - - - - - - - - +| v v +| nl_recv() my_recv() +| |<- - - - - - - - - - - - - - -+ +| |<-------------+ +| v | More data to parse? (nlmsg_next()) +| Parse Message | +| |--------------+ +| v ++------- NLM_F_MULTI set? + | + v + (SUCCESS) +-------- + +The function nl_recv() is invoked first to receive data from the +netlink socket. This function may be overwritten by the application +by an own implementation using the function nl_cb_overwrite_recv(). +This may be useful if the netlink byte stream is in fact not received +from a socket directly but is read from a file or another source. + +If data has been read, it will be attemped to parse the data. This +will be done repeately until the parser returns NL_STOP, an error was +returned or all data has been parsed. + +In case the last message parsed successfully was a multipart message +(see <<core_multipart>>) and the parser did not +quit due to either an error or NL_STOP nl_recv() respectively the +applications own implementation will be called again and the parser +starts all over. + +See <<core_parse_character>> for information on how to extract valid +netlink messages from the parser and on how to control the behaviour +of it. + +[[core_parse_character]] +.Parsing Characteristics + +The internal parser is invoked for each netlink message received from +a netlink socket. It is typically fed by nl_recv() (see +<<core_recv_character>>). + +The parser will first ensure that the length of the data stream +provided is sufficient to contain a netlink message header and that +the message length as specified in the message header does not exceed +it. + +If this criteria is met, a new struct nl_msg is allocated and the +message is passed on to the the callback function NL_CB_MSG_IN if one +is set. Like any other callback function, it may return NL_SKIP to +skip the current message but continue parsing the next message or +NL_STOP to stop parsing completely. + +The next step is to check the sequence number of the message against +the currently expected sequence number. The application may provide +its own sequence number checking algorithm by setting the callback +function NL_CB_SEQ_CHECK to its own implementation. In fact, calling +nl_socket_disable_seq_check() to disable sequence number checking will +do nothing more than set the NL_CB_SEQ_CHECK hook to a function which +always returns NL_OK. + +Another callback hook NL_CB_SEND_ACK exists which is called if the +message has the NLM_F_ACK flag set. Although I am not aware of any +userspace netlink socket doing this, the application may want to send +an ACK message back to the sender (see <<core_msg_ack>>). + +[source,c] +-------- + parse() + | + v + nlmsg_ok() --> Ignore + | + |- - - - - - - - - - - - - - - v + | NL_CB_MSG_IN() + |<- - - - - - - - - - - - - - -+ + | + |- - - - - - - - - - - - - - - v + Sequence Check NL_CB_SEQ_CHECK() + |<- - - - - - - - - - - - - - -+ + | + | Message has NLM_F_ACK set + |- - - - - - - - - - - - - - - v + | NL_CB_SEND_ACK() + |<- - - - - - - - - - - - - - -+ + | + Handle Message Type +-------- + +[[core_auto_ack]] +=== Auto-ACK Mode + +TODO + +== Message Parsing & Construction + +=== Message Format + +See <<core_netlink_fundamentals>> for an introduction to the netlink +protocol and its message format. + +.Alignment + +Most netlink protocols enforce a strict alignment policy for all +boundries. The alignment value is defined by NLMSG_ALIGNTO and is +fixed to 4 bytes. Therefore all netlink message headers, begin of +payload sections, protocol specific headers, and attribute sections +must start at an offset which is a multiple of NLMSG_ALIGNTO. + +[source,c] +-------- +#include <netlink/msg.h> + +int nlmsg_size(int payloadlen); +int nlmsg_total_size(int payloadlen); +-------- + +The library provides a set of function to handle alignment +requirements automatically. The function nlmsg_total_size() returns +the total size of a netlink message including the padding to ensure +the next message header is aligned correctly. + +[source,c] +-------- + <----------- nlmsg_total_size(len) ------------> + <----------- nlmsg_size(len) ------------> + +-------------------+- - -+- - - - - - - - +- - -+-------------------+- - - + | struct nlmsghdr | Pad | Payload | Pad | struct nlsmghdr | + +-------------------+- - -+- - - - - - - - +- - -+-------------------+- - - + <---- NLMSG_HDRLEN -----> <- NLMSG_ALIGN(len) -> <---- NLMSG_HDRLEN --- +-------- + +If you need to know if padding needs to be added at the end of a +message, nlmsg_padlen() returns the number of padding bytes that need +to be added for a specific payload length. + +[source,c] +-------- +#include <netlink/msg.h> +int nlmsg_padlen(int payloadlen); +-------- + +=== Parsing a Message + +The library offers two different methods of parsing netlink messages. +It offers a low level interface for applications which want to do all +the parsing manually. This method is described below. Alternatively +the library also offers an interface to implement a parser as part of +a cache operations set which is especially useful when your protocol +deals with objects of any sort such as network links, routes, etc. +This high level interface is described in <<core_cache>>. + +.Splitting a byte stream into separate messages + +What you receive from a netlink socket is typically a stream of +messages. You will be given a buffer and its length, the buffer may +contain any number of netlink messages. + +The first message header starts at the beginning of message stream. +Any subsequent message headers are access by calling nlmsg_next() on +the previous header. + +[source,c] +-------- +#include <netlink/msg.h> + +struct nlmsghdr *nlmsg_next(struct nlmsghdr *hdr, int *remaining); +-------- + +The function nlmsg_next() will automatically substract the size of the +previous message from the remaining number of bytes. + +Please note, there is no indication in the previous message whether +another message follows or not. You must assume that more messages +follow until all bytes of the message stream have been processed. + +To simplify this, the function nlmsg_ok() exists which returns true if +another message fits into the remaining number of bytes in the message +stream. nlmsg_valid_hdr() is similar, it checks whether a specific +netlink message contains at least a minimum of payload. + +[source,c] +-------- +#include <netlink/msg.h> + +int nlmsg_valid_hdr(const struct nlmsghdr *hdr, int payloadlen); +int nlmsg_ok(const struct nlmsghdr *hdr, int remaining); +-------- + +A typical use of these functions looks like this: + +[source,c] +-------- +#include <netlink/msg.h> + +void my_parse(void *stream, int length) +{ + struct nlmsghdr *hdr = stream; + + while (nlmsg_ok(hdr, length)) { + // Parse message here + hdr = nlmsg_next(hdr, &length); + } +} +-------- + +CAUTION: nlmsg_ok() only returns true if the *complete* message including + the message payload fits into the remaining buffer length. It will + return false if only a part of it fits. + +The above can also be written using the iterator nlmsg_for_each(): + +[source,c] +-------- +#include <netlink/msg.h> + +struct nlmsghdr *hdr; + +nlmsg_for_each(hdr, stream, length) { + /* do something with message */ +} +-------- + +.Message Payload + +The message payload is appended to the message header and is guranteed +to start at a multiple of +NLMSG_ALIGNTO+. Padding at the end of the +message header is added if necessary to ensure this. The function +nlmsg_data() will calculate the necessary offset based on the message +and returns a pointer to the start of the message payload. + +[source,c] +-------- +#include <netlink/msg.h> + +void *nlmsg_data(const struct nlmsghdr *nlh); +void *nlmsg_tail(const struct nlmsghdr *nlh); +int nlmsg_datalen(const struct nlmsghdr *nlh); +-------- + +The length of the message payload is returned by nlmsg_datalen(). + +[source,c] +-------- + <--- nlmsg_datalen(nlh) ---> + +-------------------+- - -+----------------------------+- - -+ + | struct nlmsghdr | Pad | Payload | Pad | + +-------------------+- - -+----------------------------+- - -+ +nlmsg_data(nlh) ---------------^ ^ +nlmsg_tail(nlh) --------------------------------------------------^ +-------- + +The payload may consist of arbitary data but may have strict alignment +and formatting rules depening on the actual netlink protocol. + +[[core_msg_attr]] +.Message Attributes + +Most netlink protocols use netlink attributes. It not only makes the +protocol self documenting but also gives flexibility in expanding the +protocol at a later point. New attributes can be added at any time and +older attributes can be obsoleted by newer ones without breaking +binary compatibility of the protocol. + +[source,c] +-------- + <---------------------- payload -------------------------> + <----- hdrlen ----> <- nlmsg_attrlen(nlh, hdrlen) -> + +-------------------+- - -+----- ------------+- - -+--------------------------------+- - -+ + | struct nlmsghdr | Pad | Protocol Header | Pad | Attributes | Pad | + +-------------------+- - -+-------------------+- - -+--------------------------------+- - -+ +nlmsg_attrdata(nlh, hdrlen) -----------------------------^ +-------- + +The function nlmsg_attrdata() returns a pointer to the begin of the +attributes section. The length of the attributes section is returned +by the function nlmsg_attrlen(). + +[source,c] +-------- +#include <netlink/msg.h> + +struct nlattr *nlmsg_attrdata(const struct nlmsghdr *hdr, int hdrlen); +int nlmsg_attrlen(const struct nlmsghdr *hdr, int hdrlen); +-------- + +See <<core_attr>> for more information on how to use netlink attributes. + +.Parsing a Message the Easy Way + +The function nlmsg_parse() validate a complete netlink message in one +step. If +hdrlen > 0+ it will first call nlmsg_valid_hdr() to check +if the protocol header fits into the message. If there is more payload +to parse, it will assume it to be attributes and parse the payload +accordingly. The function behaves exactly like nla_parse() when +parsing attributes, see <<core_attr_parse_easy>>. + +[source,c] +-------- +int nlmsg_parse(struct nlmsghdr *hdr, int hdrlen, struct nlattr **attrs, + int maxtype, struct nla_policy *policy); +-------- + +The function nlmsg_validate() is based on nla_validate() and behaves +exactly the same as nlmsg_parse() except that it only validates and +will not fill a array with pointers to each attribute. + +[source,c] +-------- +int nlmsg_validate(struct nlmsghdr *hdr, int hdrlen, intmaxtype, + struct nla_policy *policy); +-------- + +See <<core_attr_parse_easy>> for an example and more information on +attribute parsing. + +=== Construction of a Message + +See <<core_msg_format>> for information on the netlink message format +and alignment requirements. + +Message construction is based on struct nl_msg which uses an internal +buffer to store the actual netlink message. struct nl_msg +does not+ +point to the netlink message header. Use nlmsg_hdr() to retrieve a +pointer to the netlink message header. + +At allocation time, a maximum message size is specified. It defaults +to a page (PAGE_SIZE). The application constructing the message will +reserve space out of this maximum message size repeatedly for each +header or attribute added. This allows construction of messages across +various layers of code where lower layers do not need to know about +the space requirements of upper layers. + ++Why is setting the maximum message size necessary?+ This +question is often raised in combination with the proposed solution of +reallocating the message payload buffer on the fly using realloc(). +While it is possible to reallocate the buffer during construction +using nlmsg_expand() it will make all pointers into the message buffer +become stale. This breaks usage of nlmsg_hdr(), nla_nest_start(), and +nla_nest_end() and is therefore not acceptable as default behaviour. + +.Allocating struct nl_msg + +The first step in constructing a new netlink message it to allocate a +`struct nl_msg` to hold the message header and payload. Several +functions exist to simplify various tasks. + +[source,c] +-------- +#include <netlink/msg.h> + +struct nl_msg *nlmsg_alloc(void); +void nlmsg_free(struct nl_msg *msg); +-------- + +The function nlmsg_alloc() is the default message allocation function. +It allocates a new message using the default maximum message size which +equals to one page (PAGE_SIZE). The application can change the default +size for messages by calling nlmsg_set_default_size(): + +[source,c] +-------- +void nlmsg_set_default_size(size_t); +-------- + +CAUTION: Calling nlmsg_set_default_size() does not change the maximum + message size of already allocated messages. + +[source,c] +-------- +struct nl_msg *nlmsg_alloc_size(size_t max); +-------- + +Instead of changing the default message size, the function +nlmsg_alloc_size() can be used to allocate a message with a individual +maximum message size. + + +If the netlink message header is already known at allocation time, the +application may sue nlmsg_inherit(). It will allocate a message using +the default maximum message size and copy the header into the message. +Calling nlmsg_inherit with +set+ to NULL is equivalent to calling +nlmsg_alloc(). + +[source,c] +-------- +struct nl_msg *nlmsg_inherit(struct nlmsghdr *hdr); +-------- + +Alternatively nlmsg_alloc_simple() takes a netlink message type and +netlink message flags. It is equivalent to nlmsg_inherit() except that it +takes the two common header fields as arguments instead of a complete +header. + +[source,c] +-------- +#include <netlink/msg.h> + +struct nl_msg *nlmsg_alloc_simple(int nlmsg_type, int flags); +-------- + +.Appending the netlink message header + +After allocating struct nl_msg, the netlink message header needs to be +added unless one of the function nlmsg_alloc_simple() or nlmsg_inherit() +have been used for allocation in which case this step will replace the +netlink message header already in place. + +[source,c] +-------- +#include <netlink/msg.h> + +struct nlmsghdr *nlmsg_put(struct nl_msg *msg, uint32_t port, uint32_t seqnr, + int nlmsg_type, int payload, int nlmsg_flags); +-------- + +The function nlmsg_put() will build a netlink message header out of ++nlmsg_type+, +nlmsg_flags+, +seqnr+, and +port+ and copy it into the +netlink message. +seqnr+ can be set to +NL_AUTO_SEQ+ to indiciate +that the next possible sequence number should be used automatically. +To use this feature, the message must be sent using the function +nl_send_auto(). Like +port+, the argument +seqnr+ can be set to ++NL_AUTO_PORT+ indicating that the local port assigned to the socket +should be used as source port. This is generally a good idea unless +you are replying to a request. See <<core_netlink_fundamentals>> +for more information on how to fill the header. + +NOTE: The argument +payload+ can be used by the application to reserve + room for additional data after the header. A value of > 0 is + equivalent to calling +nlmsg_reserve(msg, payload, NLMSG_ALIGNTO)+. + See <<core_msg_reserve>> for more information on reserving room for + data. + +.Example +[source,c] +-------- +#include <netlink/msg.h> + +struct nlmsghdr *hdr; +struct nl_msg *msg; +struct myhdr { + uint32_t foo1, foo2; +} hdr = { 10, 20 }; + +/* Allocate a message with the default maximum message size */ +msg = nlmsg_alloc(); + +/* + * Add header with message type MY_MSGTYPE, the flag NLM_F_CREATE, + * let library fill port and sequence number, and reserve room for + * struct myhdr + */ +hdr = nlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, MY_MSGTYPE, sizeof(hdr), NLM_F_CREATE); + +/* Copy own header into newly reserved payload section */ +memcpy(nlmsg_data(hdr), &hdr, sizeof(hdr)); + +/* + * The message will now look like this: + * +-------------------+- - -+----------------+- - -+ + * | struct nlmsghdr | Pad | struct myhdr | Pad | + * +-------------------+-----+----------------+- - -+ + * nlh -^ / \ + * +--------+---------+ + * | foo1 | foo2 | + * +--------+---------+ + */ +-------- + +[[core_msg_reserve]] +.Reserving room at the end of the message + +Most functions described later on will automatically take care of +reserving room for the data that is added to the end of the netlink +message. In some situations it may be requried for the application +to reserve room directly though. + +[source,c] +-------- +#include <netlink/msg.h> + +void *nlmsg_reserve(struct nl_msg *msg, size_t len, int pad); +-------- + +The function nlmsg_reserve() reserves +len+ bytes at the end of the +netlink message and returns a pointer to the start of the reserved area. +The +pad+ argument can be used to request +len+ to be aligned to any +number of bytes prior to reservation. + +The following example requests to reserve a 17 bytes area at the end of +message aligned to 4 bytes. Therefore a total of 20 bytes will be +reserved. + +[source,c] +-------- +#include <netlink/msg.h> + +void *buf = nlmsg_reserve(msg, 17, 4); +-------- + +NOTE: `nlmsg_reserve()` will *not* align the start of the buffer. Any + alignment requirements must be provided by the owner of the + previous message section. + +.Appending data at the end of the message + +The function `nlmsg_append()` appends `len` bytes at the end of the +message, padding it if requested and necessary. + +[source,c] +-------- +#include <netlink/msg.h> + +int nlmsg_append(struct nl_msg *msg, void *data, size_t len, int pad); +-------- + +It is equivalent to calling `nlmsg_reserve()` and `memcpy()`ing the +data into the freshly reserved data section. + +NOTE: `nlmsg_append()` will *not* align the start of the data. Any + alignment requirements must be provided by the owner of the + previous message section. + +.Adding attribtues to a message + +Construction of attributes and addition of attribtues to the message is +covereted in section <<core_attr>>. + +[[core_attr]] +== Attributes + +Any form of payload should be encoded as netlink attributes whenever +possible. Use of attributes allows to extend any netlink protocol in +the future without breaking binary compatibility. F.e. Suppose your +device may currently be using 32 bit counters for statistics but years +later the device switches to maintaining 64 bit counters to account +for faster network hardware. If your protocol is using attributes the +move to 64 bit counters is trivial and only involves in sending an +additional attribute containing the 64 bit variants while still +providing the old legacy 32 bit counters. If your protocol is not using +attributes you will not be able to switch data types without breaking +all existing users of the protocol. + +The concept of nested attributes also allows for subsystems of your +protocol to implement and maintain their own attribute schemas. Suppose +a new generation of network device is introduced which requires a +completely new set of configuration settings which was unthinkable when +the netlink protocol was initially designed. Using attributes the new +generation of devices may define a new attribute and fill it with its +own new structure of attributes which extend or even obsolete the old +attributes. + +Therefore, _always_ use attributes even if you are almost certain that +the message format will never ever change in the future. + +[[core_attr_format]] +=== Attribute Format + +Netlink attributes allow for any number of data chunks of arbitary +length to be attached to a netlink message. See <<core_msg_attr>> +for more information on where attributes are stored in the message. + +The format of the attributes data returned by nlmsg_attrdata() is as +follows: + +[source,c] +-------- + <----------- nla_total_size(payload) -----------> + <---------- nla_size(payload) -----------> + +-----------------+- - -+- - - - - - - - - +- - -+-----------------+- - - + | struct nlattr | Pad | Payload | Pad | struct nlattr | + +-----------------+- - -+- - - - - - - - - +- - -+-----------------+- - - + <---- NLA_HDRLEN -----> <--- NLA_ALIGN(len) ---> <---- NLA_HDRLEN --- +-------- + +Every attribute must start at an offset which is a multiple of ++NLA_ALIGNTO+ (4 bytes). If you need to know whether an attribute needs +to be padded at the end, the function nla_padlen() returns the number +of padding bytes that will or need to be added. + +image:attribute_hdr.png["Netlink Attribute Header"] + +Every attribute is encoded with a type and length field, both 16 bits, +stored in the attribute header (struct nlattr) preceding the attribute +payload. The length of an attribute is used to calculate the offset to +the next attribute. + +[[core_attr_parse]] +=== Parsing Attributes + +[[core_attr_parse_split]] +.Splitting an Attributes Stream into Attributes + +Although most applications will use one of the functions from the +nlmsg_parse() family (See <<core_attr_parse_easy>>) an interface exists +to split the attributes stream manually. + +As described in <<core_attr_format>> the attributes section contains a +infinite sequence or stream of attributes. The pointer returned by +nlmsg_attrdata() (See <<core_msg_attr>>) points to the first attribute +header. Any subsequent attribute is accessed with the function nla_next() +based on the previous header. + +[source,c] +-------- +#include <netlink/attr.h> + +struct nlattr *nla_next(const struct nlattr *attr, int *remaining); +-------- + +The semantics are equivalent to nlmsg_next() and thus nla_next() will also +subtract the size of the previous attribute from the remaining number of +bytes in the attributes stream. + +Like messages, attributes do not contain an indicator whether another +attribute follows or not. The only indication is the number of bytes left +in the attribute stream. The function nla_ok() exists to determine whether +another attribute fits into the remaining number of bytes or not. + +[source,c] +-------- +#include <netlink/attr.h> + +int nla_ok(const struct nlattr *attr, int remaining); +-------- + +A typical use of nla_ok() and nla_next() looks like this: + +.nla_ok()/nla_next() usage +[source,c] +-------- +#include <netlink/msg.h> +#include <netlink/attr.h> + +struct nlattr *hdr = nlmsg_attrdata(msg, 0); +int remaining = nlmsg_attrlen(msg, 0); + +while (nla_ok(hdr, remaining)) { + /* parse attribute here */ + hdr = nla_next(hdr, &remaining); +}; +-------- + +NOTE: `nla_ok()` only returns true if the *complete* attributes + including the attribute payload fits into the remaining number + of bytes. + +.Accessing Attribute Header and Payload + +Once the individual attributes have been sorted out by either splitting +the attributes stream or using another interface the attribute header +and payload can be accessed. + +[source,c] +-------- + <- nla_len(hdr) -> + +-----------------+- - -+- - - - - - - - - +- - -+ + | struct nlattr | Pad | Payload | Pad | + +-----------------+- - -+- - - - - - - - - +- - -+ +nla_data(hdr) ---------------^ +-------- + +The functions nla_len() and nla_type() can be used to access the attribute +header. nla_len() will return the length of the payload not including +eventual padding bytes. nla_type returns the attribute type. + +[source,c] +-------- +#include <netlink/attr.h> + +int nla_len(const struct nlattr *hdr); +int nla_type(const struct nlattr *hdr); +-------- + +The function nla_data() will return a pointer to the attribute +payload. Please note that due to +NLA_ALIGNTO+ being 4 bytes it may +not be safe to cast and dereference the pointer for any datatype +larger than 32 bit depending on the architecture the application is +run on. + +[source,c] +-------- +#include <netlink/attr.h> + +void *nla_data(const struct nlattr *hdr); +-------- + +[NOTE] +Never rely on the size of a payload being what you expect it to be. +_Always_ verify the payload size and make sure that it matches your +expectations. See <<core_attr_validation>> + +[[core_attr_validation]] +.Attribute Validation + +When receiving netlink attributes, the receiver has certain expections +on how the attributes should look like. These expectations must be +defined to make sure the sending side meets our expecations. For this +purpose, a attribute validation interface exists which must be used +prior to accessing any payload. + +All functions providing attribute validation functionality are based +on struct nla_policy: + +[source,c] +-------- +struct nla_policy { + uint16_t type; + uint16_t minlen; + uint16_t maxlen; +}; +-------- + +The +type+ member specifies the datatype of the attribute, e.g. ++NLA_U32+, +NLA_STRING+, +NLA_FLAG+. The default is +NLA_UNSPEC+. The ++minlen+ member defines the minmum payload length of an attribute to +be considered a valid attribute. The value for +minlen+ is implicit +for most basic datatypes such as integers or flags. The +maxlen+ +member can be used to define a maximum payload length for an +attribute to still be considered valid. + +NOTE: Specyfing a maximum payload length is not recommended when + encoding structures in an attribute as it will prevent any + extension of the structure in the future. Something that is + frequently done in netlink protocols and does not break + backwards compatibility. + +One of the functions which use struct nla_policy is nla_validate(). +The function expects an array of struct nla_policy and will access the +array using the attribute type as index. If an attribute type is out +of bounds the attribute is assumed to be valid. This is intentional +behaviour to allow older applications not yet aware of recently +introduced attributes to continue functioning. + +[source,c] +-------- +#include <netlink/attr.h> + +int nla_validate(struct nlattr *head, int len, int maxtype, struct nla_policy *policy); +-------- + +The function nla_validate() returns 0 if all attributes are valid, +otherwise a validation failure specific error code is returned. + +Most applications will rarely use nla_validate() directly but use +nla_parse() instead which takes care of validation in the same way but +also parses the the attributes in the same step. See +<<core_attr_parse_easy>> for an example and more information. + +The validation process in detail: + +. If attribute type is 0 or exceeds +maxtype+ attribute is + considered valid, 0 is returned. +. If payload length is < +minlen+, +-NLE_ERANGE+ is returned. +. If +maxlen+ is defined and payload exceeds it, +-NLE_ERANGE+ + is returned. +. Datatype specific requirements rules, see <<core_attr_types>> +. If all is ok, 0 is returned. + +[[core_attr_parse_easy]] +.Parsing Attributes the Easy Way + +Most applications will not want to deal with splitting attribute +streams themselves as described in <<core_attr_parse_split>> +A much easier method is to use nla_parse(). + +[source,c] +-------- +#include <netlink/attr.h> + +int nla_parse(struct nlattr **attrs, int maxtype, struct nlattr *head, + int len, struct nla_policy *policy); +-------- + +The function nla_parse() will iterate over a stream of attributes, +validate each attribute as described in <<core_attr_validation>> +If the validation of all attributes succeeds, a pointer to each attribute +is stored in the +attrs+ array at `attrs[nla_type(attr)]`. + +As an alernative to nla_parse() the function nlmsg_parse() can be used +to parse the message and its attributes in one step. See +<<core_attr_parse_easy>> for information on how to use these functions. + +.Example: + +The following example demonstrates how to parse a netlink message sent +over a netlink protocol which does not use protocol headers. The example +does enforce a attribute policy however, the attribute MY_ATTR_FOO must +be a 32 bit integer, and the attribute MY_ATTR_BAR must be a string with +a maximum length of 16 characters. + +[source,c] +--------- +#include <netlink/msg.h> +#include <netlink/attr.h> + +enum { + MY_ATTR_FOO = 1, + MY_ATTR_BAR, + __MY_ATTR_MAX, +}; + +#define MY_ATTR_MAX (__MY_ATTR_MAX - 1) + +static struct nla_policy my_policy[MY_ATTR_MAX+1] = { + [MY_ATTR_FOO] = { .type = NLA_U32 }, + [MY_ATTR_BAR] = { .type = NLA_STRING, + .maxlen = 16 }, +}; + +void parse_msg(struct nlmsghdr *nlh) +{ + struct nlattr *attrs[MY_ATTR_MAX+1]; + + if (nlmsg_parse(nlh, 0, attrs, MY_ATTR_MAX, my_policy) < 0) + /* error */ + + if (attrs[MY_ATTR_FOO]) { + /* MY_ATTR_FOO is present in message */ + printf("value: %u\n", nla_get_u32(attrs[MY_ATTR_FOO])); + } +} +--------- + +.Locating a Single Attribute + +An application only interested in a single attribute can use one of the +functions nla_find() or nlmsg_find_attr(). These function will iterate +over all attributes, search for a matching attribute and return a pointer +to the corresponding attribute header. + +[source,c] +-------- +#include <netlink/attr.h> + +struct nlattr *nla_find(struct nlattr *head, int len, int attrtype); +-------- + +[source,c] +-------- +#include <netlink/msg.h> + +struct nlattr *nlmsg_find_attr(struct nlmsghdr *hdr, int hdrlen, int attrtype); +-------- + +NOTE: `nla_find()` and `nlmsg_find_attr()` will *not* search in nested + attributes recursively, see <<core_attr_nested>>. + +==== Iterating over a Stream of Attributes + +In some situations it does not make sense to assign a unique attribute +type to each attribute in the attribute stream. For example a list may +be transferd using a stream of attributes and even if the attribute type +is incremented for each attribute it may not make sense to use the +nlmsg_parse() or nla_parse() function to fill an array. + +Therefore methods exist to iterate over a stream of attributes: + +[source,c] +-------- +#include <netlink/attr.h> + +nla_for_each_attr(attr, head, len, remaining) +-------- + +nla_for_each_attr() is a macro which can be used in front of a code +block: + +[source,c] +-------- +#include <netlink/attr.h> + +struct nalttr *nla; +int rem; + +nla_for_each_attr(nla, attrstream, streamlen, rem) { + /* validate & parse attribute */ +} + +if (rem > 0) + /* unparsed attribute data */ +-------- + +[[core_attr_constr]] +=== Attribute Construction + +The interface to add attributes to a netlink message is based on the +regular message construction interface. It assumes that the message +header and an eventual protocol header has been added to the message +already. + +[source,c] +-------- +struct nlattr *nla_reserve(struct nl_msg *msg, int attrtype, int len); +-------- + +The function nla_reserve() adds an attribute header at the end of the +message and reserves room for +len+ bytes of payload. The function +returns a pointer to the attribute payload section inside the message. +Padding is added at the end of the attribute to ensure the next +attribute is properly aligned. + +[source,c] +-------- +int nla_put(struct nl_msg *msg, int attrtype, int attrlen, const void *data); +-------- + +The function nla_put() is base don nla_reserve() but takes an additional +pointer +data+ pointing to a buffer containing the attribute payload. +It will copy the buffer into the message automatically. + +.Example: + +[source,c] +-------- +struct my_attr_struct { + uint32_t a; + uint32_t b; +}; + +int my_put(struct nl_msg *msg) +{ + struct my_attr_struct obj = { + .a = 10, + .b = 20, + }; + + return nla_put(msg, ATTR_MY_STRUCT, sizeof(obj), &obj); +} +-------- + +See <<core_attr_types>> for datatype specific attribute construction +functions. + +.Exception Based Attribute Construction + +Like in the kernel API an exception based construction interface is +provided. The behaviour of the macros is identical to their regular +function counterparts except that in case of an error, the target +`nla_put_failure` is jumped. + +.Example: +[source,c] +-------- +#include <netlink/msg.h> +#include <netlink/attr.h> + +void construct_attrs(struct nl_msg *msg) +{ + NLA_PUT_STRING(msg, MY_ATTR_FOO1, "some text"); + NLA_PUT_U32(msg, MY_ATTR_FOO1, 0x1010); + NLA_PUT_FLAG(msg, MY_ATTR_FOO3, 1); + + return 0; + +nla_put_failure: + /* NLA_PUT* macros jump here in case of an error */ + return -EMSGSIZE; +} +-------- + +See <<core_attr_types>> for more information on the datatype specific +exception based variants. + +[[core_attr_types]] +=== Attribute Data Types + +A number of basic data types have been defined to simplify access and +validation of attributes. The datatype is not encoded in the +attribute, therefore bthe sender and receiver are required to use the +same definition on what attribute is of what type. + +[options="header", cols="1m,5"] +|================================================ +| Type | Description +| NLA_UNSPEC | Unspecified attribute +| NLA_U{8\|16\|32} | Integers +| NLA_STRING | String +| NLA_FLAG | Flag +| NLA_NESTED | Nested attribute +|================================================ + +Besides simplified access to the payload of such datatypes, the major +advantage is the automatic validation of each attribute based on a +policy. The validation ensures safe access to the payload by checking +for minimal payload size and can also be used to enforce maximum +payload size for some datatypes. + +==== Integer Attributes + +The most frequently used datatypes are integers. Integers come in four +different sizes: +[horizontal] +NLA_U8:: 8bit integer +NLA_U16:: 16bit integer +NLA_U32:: 32bit integer +NLA_U64:: 64bit integer + +Note that due to the alignment requirements of attributes the integer +attribtue +NLA_u8+ and +NLA_U16+ will not result in space savings in +the netlink message. Their use is intended to limit the range of +values. + +.Parsing Integer Attributes + +[source,c] +-------- +#include <netlink/attr.h> + +uint8_t nla_get_u8(struct nlattr *hdr); +uint16_t nla_get_u16(struct nlattr *hdr); +uint32_t nla_get_u32(struct nlattr *hdr); +uint64_t nla_get_u64(struct nlattr *hdr); +-------- + +Example: + +[source,c] +-------- +if (attrs[MY_ATTR_FOO]) + uint32_t val = nla_get_u32(attrs[MY_ATTR_FOO]); +-------- + +.Constructing Integer Attributes + +[source,c] +-------- +#include <netlink/attr.h> + +int nla_put_u8(struct nl_msg *msg, int attrtype, uint8_t value); +int nla_put_u16(struct nl_msg *msg, int attrtype, uint16_t value); +int nla_put_u32(struct nl_msg *msg, int attrtype, uint32_t value); +int nla_put_u64(struct nl_msg *msg, int attrtype, uint64_t value); +-------- + +Exception based: + +[source,c] +-------- +NLA_PUT_U8(msg, attrtype, value) +NLA_PUT_U16(msg, attrtype, value) +NLA_PUT_U32(msg, attrtype, value) +NLA_PUT_U64(msg, attrtype, value) +-------- + +.Validation + +Use +NLA_U8+, +NLA_U16+, +NLA_U32+, or +NLA_U64+ to define the type of +integer when filling out a struct nla_policy array. It will +automatically enforce the correct minimum payload length policy. + +Validation does not differ between signed and unsigned integers, only +the size matters. If the appliaction wishes to enforce particular value +ranges it must do so itself. + +[source,c] +-------- +static struct nla_policy my_policy[ATTR_MAX+1] = { + [ATTR_FOO] = { .type = NLA_U32 }, + [ATTR_BAR] = { .type = NLA_U8 }, +}; +-------- + +The above is equivalent to: +[source,c] +-------- +static struct nla_policy my_policy[ATTR_MAX+1] = { + [ATTR_FOO] = { .minlen = sizeof(uint32_t) }, + [ATTR_BAR] = { .minlen = sizeof(uint8_t) }, +}; +-------- + +==== String Attributes + +The string datatype represents a NUL termianted character string of +variable length. It is not intended for binary data streams. + +The payload of string attributes can be accessed with the function +nla_get_string(). nla_strdup() calls strdup() on the payload and returns +the newly allocated string. + +[source,c] +-------- +#include <netlink/attr.h> + +char *nla_get_string(struct nlattr *hdr); +char *nla_strdup(struct nlattr *hdr); +-------- + +String attributes are constructed with the function +nla_put_string()+ +respectively +NLA_PUT_STRING()+. The length of the payload will be +strlen()+1, the trailing NUL byte is included. + +[source,c] +-------- +int nla_put_string(struct nl_msg *msg, int attrtype, const char *data); + +NLA_PUT_STRING(msg, attrtype, data) +-------- + +For validation purposes the type +NLA_STRING+ can be used in ++struct nla_policy+ definitions. It implies a minimum payload length +of 1 byte and checks for a trailing NUL byte. Optionally the +maxlen+ +member defines the maximum length of a character string (including the +trailing NUL byte). + +[source,c] +-------- +static struct nla_policy my_policy[] = { + [ATTR_FOO] = { .type = NLA_STRING, + .maxlen = IFNAMSIZ }, +}; +-------- + +==== Flag Attributes + +The flag attribute represents a boolean datatype. The presence of the +attribute implies a value of +true+, the absence of the attribute +implies the value +false+. Therefore the payload length of flag +attributes is always 0. + +[source,c] +-------- +int nla_get_flag(struct nlattr *hdr); +int nla_put_flag(struct nl_msg *msg, int attrtype); +-------- + +The type +NLA_FLAG+ is used for validation purposes. It implies a ++maxlen+ value of 0 and thus enforces a maximum payload length of 0. + +.Example: +[source,c] +-------- +/* nla_put_flag() appends a zero sized attribute to the message. */ +nla_put_flag(msg, ATTR_FLAG); + +/* There is no need for a receival function, the presence is the value. */ +if (attrs[ATTR_FLAG]) + /* flag is present */ +-------- + +[[core_attr_nested]] +==== Nested Attributes + +As described in <<core_attr>>, attributes can be nested allowing for +complex tree structures of attributes. It is commonly used to delegate +the responsibility of a subsection of the message to a subsystem. +Nested attributes are also commonly used for transmitting list of objects. + +When nesting attributes, the nested attributes are included as payload +of a container attribute. + +NOTE: When validating the attributes using nlmsg_validate(), + nlmsg_parse(), nla_validate(), or nla_parse() only the + attributes on the first level are being validated. None of these + functions will validate attributes recursively. Therefore you + must explicitely call nla_validate() or use nla_parse_nested() + for each level of nested attributes. + +The type +NLA_NESTED+ should be used when defining nested attributes +in a struct nla_policy definition. It will not enforce any minimum +payload length unless +minlen+ is specified explicitely. This is +because some netlink protocols implicitely allow empty container +attributes. + +[source,c] +-------- +static struct nla_policy my_policy[] = { + [ATTR_OPTS] = { .type = NLA_NESTED }, +}; +-------- + +.Parsing of Nested Attributes + +The function nla_parse_nested() is used to parse nested attributes. +Its behaviour is identical to nla_parse() except that it takes a +struct nlattr as argument and will use the payload as stream of +attributes. + +[source,c] +-------- +if (attrs[ATTR_OPTS]) { + struct nlattr *nested[NESTED_MAX+1]; + struct nla_policy nested_policy[] = { + [NESTED_FOO] = { .type = NLA_U32 }, + }; + + if (nla_parse_nested(nested, NESTED_MAX, attrs[ATTR_OPTS], nested_policy) < 0) + /* error */ + + if (nested[NESTED_FOO]) + uint32_t val = nla_get_u32(nested[NESTED_FOO]); +} +-------- + +.Construction of Nested Attributes + +Attributes are nested by surrounding them with calls to nla_nest_start() +and nla_nest_end(). nla_nest_start() will add a attribute header to +the message but no actual payload. All data added to the message from +this point on will be part of the container attribute until nla_nest_end() +is called which "closes" the attribute, correcting its payload length to +include all data length. + +[source,c] +-------- +int put_opts(struct nl_msg *msg) +{ + struct nlattr *opts; + + if (!(opts = nla_nest_start(msg, ATTR_OPTS))) + goto nla_put_failure; + + NLA_PUT_U32(msg, NESTED_FOO, 123); + NLA_PUT_STRING(msg, NESTED_BAR, "some text"); + + nla_nest_end(msg, opts); + return 0; + +nla_put_failure: + nla_nest_cancel(msg, opts); + return -EMSGSIZE; +} +-------- + +==== Unspecified Attribute + +This is the default attribute type and used when none of the basic +datatypes is suitable. It represents data of arbitary type and length. + +See <<core_addr_alloc, Address Allocation>> for a more information on +a special interface allowing the allocation of abstract address object +based on netlink attributes which carry some form of network address. + +See <<core_data_alloc, Abstract Data Allocation>> for more information +on how to allocate abstract data objects based on netlink attributes. + +Use the function nla_get() and nla_put() to access the payload and +construct attributes. See <<core_attr_constr, Attribute Construction>> +for an example. + +=== Examples + +==== Constructing a Netlink Message with Attributes + +[source,c] +-------- +struct nl_msg *build_msg(int ifindex, struct nl_addr *lladdr, int mtu) +{ + struct nl_msg *msg; + struct nlattr *info, *vlan; + struct ifinfomsg ifi = { + .ifi_family = AF_INET, + .ifi_index = ifindex, + }; + + /* Allocate a default sized netlink message */ + if (!(msg = nlmsg_alloc_simple(RTM_SETLINK, 0))) + return NULL; + + /* Append the protocol specific header (struct ifinfomsg)*/ + if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0) + goto nla_put_failure + + /* Append a 32 bit integer attribute to carry the MTU */ + NLA_PUT_U32(msg, IFLA_MTU, mtu); + + /* Append a unspecific attribute to carry the link layer address */ + NLA_PUT_ADDR(msg, IFLA_ADDRESS, lladdr); + + /* Append a container for nested attributes to carry link information */ + if (!(info = nla_nest_start(msg, IFLA_LINKINFO))) + goto nla_put_failure; + + /* Put a string attribute into the container */ + NLA_PUT_STRING(msg, IFLA_INFO_KIND, "vlan"); + + /* + * Append another container inside the open container to carry + * vlan specific attributes + */ + if (!(vlan = nla_nest_start(msg, IFLA_INFO_DATA))) + goto nla_put_failure; + + /* add vlan specific info attributes here... */ + + /* Finish nesting the vlan attributes and close the second container. */ + nla_nest_end(msg, vlan); + + /* Finish nesting the link info attribute and close the first container. */ + nla_nest_end(msg, info); + + return msg; + +nla_put_failure: + nlmsg_free(msg); + return NULL; +} +------ + +==== Parsing a Netlink Message with Attributes + +[source,c] +-------- +int parse_message(struct nlmsghdr *hdr) +{ + /* + * The policy defines two attributes: a 32 bit integer and a container + * for nested attributes. + */ + struct nla_policy attr_policy[] = { + [ATTR_FOO] = { .type = NLA_U32 }, + [ATTR_BAR] = { .type = NLA_NESTED }, + }; + struct nlattr *attrs[ATTR_MAX+1]; + int err; + + /* + * The nlmsg_parse() function will make sure that the message contains + * enough payload to hold the header (struct my_hdr), validates any + * attributes attached to the messages and stores a pointer to each + * attribute in the attrs[] array accessable by attribute type. + */ + if ((err = nlmsg_parse(hdr, sizeof(struct my_hdr), attrs, ATTR_MAX, + attr_policy)) < 0) + goto errout; + + if (attrs[ATTR_FOO]) { + /* + * It is safe to directly access the attribute payload without + * any further checks since nlmsg_parse() enforced the policy. + */ + uint32_t foo = nla_get_u32(attrs[ATTR_FOO]); + } + + if (attrs[ATTR_BAR]) { + struct *nested[NESTED_MAX+1]; + + /* + * Attributes nested in a container can be parsed the same way + * as top level attributes. + */ + err = nla_parse_nested(nested, NESTED_MAX, attrs[ATTR_BAR], + nested_policy); + if (err < 0) + goto errout; + + // Process nested attributes here. + } + + err = 0; +errout: + return err; +} +-------- + +[[core_cb]] +== Callback Configurations + +Callback hooks and overwriting capabilities are provided in various places +inside library to control the behaviour of several functions. All the +callback and overwrite functions are packed together in struct nl_cb which +is attached to a netlink socket or passed on to functions directly. + +=== Callback Hooks + +Callback hooks are spread across the library to provide entry points for +message processing and to take action upon certain events. + +Callback functions may return the following return codes: +[options="header", cols="1m,4"] +|======================================================================== +| Return Code | Description +| NL_OK | Proceed. +| NL_SKIP | Skip message currently being processed and continue + parsing the receive buffer. +| NL_STOP | Stop parsing and discard all remaining data in the + receive buffer. +|======================================================================== + +.Default Callback Implementations + +The library provides three sets of default callback implementations: +* +NL_CB_DEFAULT+ This is the default set. It implets the default behaviour. + See the table below for more information on the return codes of each + function. +* +NL_CB_VERBOSE+ This set is based on the default set but will cause an + error message to be printed to stderr for error messages, invalid + messages, message overruns and unhandled valid messages. The + +arg+ pointer in nl_cb_set() and nl_cb_err() can be used to + provide a FILE * which overwrites stderr. +* +NL_CB_DEBUG+ This set is intended for debugging purposes. It is + based on the verbose set but will decode and dump each message sent + or received to the console. + +.Message Processing Callbacks + +.nl_sendmsg() callback hooks: +[cols="2m,4e,1m", options="header"] +|============================================================================ +| Callback ID | Description | Default Return Value +| NL_CB_MSG_OUT | Each message sent | NL_OK +|============================================================================ + +Any function called by NL_CB_MSG_OUT may return a negative error code to +prevent the message from being sent and the error code being returned. + +nl_recvmsgs() callback hooks (ordered by priority): +[cols="2m,4e,1m", options="header"] +|============================================================================ +| Callback ID | Description | Default Return Value +| NL_CB_MSG_IN | Each message received | NL_OK +| NL_CB_SEQ_CHECK | May overwrite sequence check algo | NL_OK +| NL_CB_INVALID | Invalid messages | NL_STOP +| NL_CB_SEND_ACK | Messages with NLM_F_ACK flag set | NL_OK +| NL_CB_FINISH | Messages of type NLMSG_DONE | NL_STOP +| NL_CB_SKIPPED | Messages of type NLMSG_NOOP | NL_SKIP +| NL_CB_OVERRUN | Messages of type NLMSG_OVERRUN | NL_STOP +| NL_CB_ACK | ACK Messages | NL_STOP +| NL_CB_VALID | Each valid message | NL_OK +|============================================================================ + +Any of these functions may return NL_OK, NL_SKIP, or NL_STOP. + +Message processing callback functions are set with nl_cb_set(): +[source,c] +-------- +#include <netlink/handlers.h> + +int nl_cb_set(struct nl_cb *cb, enum nl_cb_type type, enum nl_cb_kind kind, + nl_recvmsg_msg_cb_t func, void *arg); + +typedef int (*nl_recvmsg_msg_cb_t)(struct nl_msg *msg, void *arg); +-------- + +.Callback for Error Messages + +A special function prototype is used for the error message callback hook: + +[source,c] +-------- +#include <netlink/handlers.h> + +int nl_cb_err(struct nl_cb *cb, enum nl_cb_kind kind, nl_recvmsg_err_cb_t func, void *arg); + +typedef int(* nl_recvmsg_err_cb_t)(struct sockaddr_nl *nla, struct nlmsgerr *nlerr, void *arg); +-------- + +.Example: Setting up a callback set +[source,c] +-------- +#include <netlink/handlers.h> + +/* Allocate a callback set and initialize it to the verbose default set */ +struct nl_cb *cb = nl_cb_alloc(NL_CB_VERBOSE); + +/* Modify the set to call my_func() for all valid messages */ +nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, my_func, NULL); + +/* + * Set the error message handler to the verbose default implementation + * and direct it to print all errors to the given file descriptor. + */ +FILE *file = fopen(...); +nl_cb_err(cb, NL_CB_VERBOSE, NULL, file); +-------- + +=== Overwriting of Internal Functions + +When the library needs to send or receive netlink messages in high level +interfaces it does so by calling its own low level API. In the case the +default characteristics are not sufficient for the application, it may +overwrite several internal function calls with own implementations. + +.Overwriting recvmsgs() + +See <<core_recv, Receiving Netlink Messages>> for more information on +how and when recvmsgs() is called internally. + +[source,c] +-------- +#include <netlink/handlers.h> + +void nl_cb_overwrite_recvmsgs(struct nl_cb *cb, + int (*func)(struct nl_sock *sk, struct nl_cb *cb)); +-------- + +The following criteras must be met if a recvmsgs() implementation is +supposed to work with high level interfaces: + +- MUST respect the callback configuration +cb+, therefore: + - MUST call +NL_CB_VALID+ for all valid messages, passing on + - MUST call +NL_CB_ACK+ for all ACK messages + - MUST correctly handle multipart messages, calling NL_CB_VALID for + each message until a NLMSG_DONE message is received. +- MUST report error code if a NLMSG_ERROR or NLMSG_OVERRUN mesasge is + received. + +.Overwriting nl_recv() + +Often it is sufficient to overwrite `nl_recv()` which is responsible +from receiving the actual data from the socket instead of replacing +the complete `recvmsgs()` logic. + +See <<core_recv_character, Receive Characteristics>> for more +information on how and when `nl_recv()` is called internally. + +[source,c] +-------- +#include <netlink/handlers.h> + +void nl_cb_overwrite_recv(struct nl_cb *cb, + int (*func)(struct nl_sock * sk, + struct sockaddr_nl *addr, + unsigned char **buf, + struct ucred **cred)); +-------- + +The following criteras must be met for an own `nl_recv()` +implementation: + + - *MUST* return the number of bytes read or a negative error code if + an error occured. The function may also return 0 to indicate that + no data has been read. + - *MUST* set `*buf` to a buffer containing the data read. It must be + safe for the caller to access the number of bytes read returned as + return code. + - *MAY* fill out `*addr` with the netlink address of the peer the + data has been received from. + - *MAY* set `*cred` to a newly allocated struct ucred containg + credentials. + +.Overwriting nl_send() + +See <<core_send, Sending Netlink Messages>> for more information on +how and when nl_send() is called internally. + +[source,c] +-------- +#include <netlink/handlers.h> + +void nl_cb_overwrite_send(struct nl_cb *cb, int (*func)(struct nl_sock *sk, + struct nl_msg *msg)); +-------- + +Own implementations must send the netlink message and return 0 on success +or a negative error code. + +[[core_cache]] +== Cache System + +=== Allocation of Caches + +Almost all subsystem provide a function to allocate a new cache +of some form. The function usually looks like this: +[source,c] +-------- +struct nl_cache *<object name>_alloc_cache(struct nl_sock *sk); +-------- + +These functions allocate a new cache for the own object type, +initializes it properly and updates it to represent the current +state of their master, e.g. a link cache would include all +links currently configured in the kernel. + +Some of the allocation functions may take additional arguments +to further specify what will be part of the cache. + +All such functions return a newly allocated cache or NULL +in case of an error. + +=== Cache Manager + +The purpose of a cache manager is to keep track of caches and +automatically receive event notifications to keep the caches +up to date with the kernel state. Each manager has exactly one +netlink socket assigned which limits the scope of each manager +to exactly one netlink family. Therefore all caches committed +to a manager must be part of the same netlink family. Due to the +nature of a manager, it is not possible to have a cache maintain +two instances of the same cache type. The socket is subscribed +to the event notification group of each cache and also put into +non-blocking mode. Functions exist to poll() on the socket to +wait for new events to be received. + + +---- + App libnl Kernel + | | + +-----------------+ [ notification, link change ] + | | Cache Manager | | [ (IFF_UP | IFF_RUNNING) ] + | | | + | | +------------+| | | [ notification, new addr ] + <-------|---| route/link |<-------(async)--+ [ 10.0.1.1/32 dev eth1 ] + | | +------------+| | | + | +------------+| | + <---|---|---| route/addr |<------|-(async)--------------+ + | +------------+| + | | +------------+| | + <-------|---| ... || + | | +------------+| | + +-----------------+ + | | +---- + +.Creating a new cache manager + +[source,c] +---- +struct nl_cache_mngr *mngr; + +// Allocate a new cache manager for RTNETLINK and automatically +// provide the caches added to the manager. +err = nl_cache_mngr_alloc(NULL, NETLINK_ROUTE, NL_AUTO_PROVIDE, &mngr); +---- + +.Keep track of a cache + +[source,c] +---- +struct nl_cache *cache; + +// Create a new cache for links/interfaces and ask the manager to +// keep it up to date for us. This will trigger a full dump request +// to initially fill the cache. +cache = nl_cache_mngr_add(mngr, "route/link"); +----- + +.Make the manager receive updates + +[source,c] +---- +// Give the manager the ability to receive updates, will call poll() +// with a timeout of 5 seconds. +if (nl_cache_mngr_poll(mngr, 5000) > 0) { + // Manager received at least one update, dump cache? + nl_cache_dump(cache, ...); +} +---- + +.Release cache manager + +[source,c] +---- +nl_cache_mngr_free(mngr); +---- + +== Abstract Data Types + +A few high level abstract data types which are used by a majority netlink +protocols are implemented in the core library. More may be added in the +future if the need arises. + +=== Abstract Address + +Most netlink protocols deal with networking related topics and thus +dealing with network addresses is a common task. + +Currently the following address families are supported: + +[options="compact"] + * `AF_INET` + * `AF_INET6` + * `AF_LLC` + * `AF_DECnet` + * `AF_UNSPEC` + +[[core_addr_alloc]] +.Address Allocation + +The function nl_addr_alloc() allocates a new empty address. The ++maxsize+ argument defines the maximum length of an address in bytes. +The size of an address is address family specific. If the address +family and address data are known at allocation time the function +nl_addr_build() can be used alternatively. You may also clone +an address by calling nl_addr_clone() + +[source,c] +-------- +#include <netlink/addr.h> + +struct nl_addr *nl_addr_alloc(size_t maxsize); +struct nl_addr *nl_addr_clone(struct nl_addr *addr); +struct nl_addr *nl_addr_build(int family, void *addr, size_t size); +-------- + +If the address is transported in a netlink attribute, the function +nl_addr_alloc_attr() allocates a new address based on the payload +of the attribute provided. The +family+ argument is used to specify +the address family of the address, set to +AF_UNSPEC+ if unknown. + +[source,c] +-------- +#include <netlink/addr.h> + +struct nl_addr *nl_addr_alloc_attr(struct nlattr *attr, int family); +-------- + +If the address is provided by a user, it is usually stored in a human +readable format. The function nl_addr_parse() parses a character +string representing an address and allocates a new address based on +it. + +[source,c] +-------- +#include <netlink/addr.h> + +int nl_addr_parse(const char *addr, int hint, struct nl_addr **result); +-------- + +If parsing succeeds the function returns 0 and the allocated address +is stored in +*result+. + +NOTE: Make sure to return the reference to an address using + `nl_addr_put()` after usage to allow memory being freed. + +.Example: Transform character string to abstract address +[source,c] +----- +struct nl_addr *a = nl_addr_parse("::1", AF_UNSPEC); +printf("Address family: %s\n", nl_af2str(nl_addr_get_family(a))); +nl_addr_put(a); +a = nl_addr_parse("11:22:33:44:55:66", AF_UNSPEC); +printf("Address family: %s\n", nl_af2str(nl_addr_get_family(a))); +nl_addr_put(a); +----- + +.Address References + +Abstract addresses use reference counting to account for all users of +a particular address. After the last user has returned the reference +the address is freed. + +If you pass on a address object to another function and you are not +sure how long it will be used, make sure to call nl_addr_get() to +acquire an additional reference and have that function or code path +call nl_addr_put() as soon as it has finished using the address. + +[source,c] +-------- +#include <netlink/addr.h> + +struct nl_addr *nl_addr_get(struct nl_addr *addr); +void nl_addr_put(struct nl_addr *addr); +int nl_addr_shared(struct nl_addr *addr); +-------- + +You may call nl_addr_shared() at any time to check if you are the only +user of an address. + +.Address Attributes + +The address is usually set at allocation time. If it was unknown at that +time it can be specified later by calling nl_addr_set_family() and is +accessed with the function nl_addr_get_family(). + +[source,c] +-------- +#include <netlink/addr.h> + +void nl_addr_set_family(struct nl_addr *addr, int family); +int nl_addr_get_family(struct nl_addr *addr); +-------- + +The same is true for the actual address data. It is typically present +at allocation time. For exceptions it can be specified later or +overwritten with the function `nl_addr_set_binary_addr()`. Beware that +the length of the address may not exceed `maxlen` specified at +allocation time. The address data is returned by the function +`nl_addr_get_binary_addr()` and its length by the function +`nl_addr_get_len()`. + +[source,c] +-------- +#include <netlink/addr.h> + +int nl_addr_set_binary_addr(struct nl_addr *addr, void *data, size_t size); +void *nl_addr_get_binary_addr(struct nl_addr *addr); +unsigned int nl_addr_get_len(struct nl_addr *addr); +-------- + +If you only want to check if the address data consists of all zeros +the function `nl_addr_iszero()` is a shortcut to that. + +[source,c] +-------- +#include <netlink/addr.h> + +int nl_addr_iszero(struct nl_addr *addr); +-------- + +==== Address Prefix Length + +Although this functionality is somewhat specific to routing it has +been implemented here. Addresses can have a prefix length assigned +which implies that only the first n bits are of importance. This is +f.e. used to implement subnets. + +Use set functions `nl_addr_set_prefixlen()` and +`nl_addr_get_prefixlen()` to work with prefix lengths. + +[source,c] +-------- +#include <netlink/addr.h> + +void nl_addr_set_prefixlen(struct nl_addr *addr, int n); +unsigned int nl_addr_get_prefixlen(struct nl_addr *addr); +-------- + +NOTE: The default prefix length is set to (address length * 8) + +.Address Helpers + +Several functions exist to help when dealing with addresses. The +function `nl_addr_cmp()` compares two addresses and returns an integer +less than, equal to or greater than zero without considering the +prefix length at all. If you want to consider the prefix length, use +the function `nl_addr_cmp_prefix()`. + +[source,c] +-------- +#include <netlink/addr.h> + +int nl_addr_cmp(struct nl_addr *addr, struct nl_addr *addr); +int nl_addr_cmp_prefix(struct nl_addr *addr, struct nl_addr *addr); +-------- + +If an abstract address needs to presented to the user it should be +done in a human readable format which differs depending on the address +family. The function `nl_addr2str()` takes care of this by calling the +appropriate conversion functions internaly. It expects a `buf` of +length `size` to write the character string into and returns a pointer +to `buf` for easy `printf()` usage. + +[source,c] +-------- +#include <netlink/addr.h> + +char *nl_addr2str(struct nl_addr *addr, char *buf, size_t size); +-------- + +If the address family is unknown, the address data will be printed in +hexadecimal format `AA:BB:CC:DD:...` + +Often the only way to figure out the address family is by looking at +the length of the address. The function `nl_addr_guess_family()` does +just this and returns the address family guessed based on the address +size. + +[source,c] +-------- +#include <netlink/addr.h> + +int nl_addr_guess_family(struct nl_addr *addr); +-------- + +Before allocating an address you may want to check if the character +string actually represents a valid address of the address family you +are expecting. The function `nl_addr_valid()` can be used for that, it +returns 1 if the supplised `addr` is a valid address in the context of +`family`. See `inet_pton(3)`, `dnet_pton(3)` for more information on +valid adddress formats. + +[source,c] +-------- +#include <netlink/addr.h> + +int nl_addr_valid(char *addr, int family); +-------- + +=== Abstract Data + +The abstract data type is a trivial datatype with the primary purpose +to simplify usage of netlink attributes of arbitary length. + +[[core_data_alloc]] +.Allocation of a Data Object +The function `nl_data_alloc()` alloctes a new abstract data object and +fill it with the provided data. `nl_data_alloc_attr()` does the same +but bases the data on the payload of a netlink attribute. New data +objects can also be allocated by cloning existing ones by using +`nl_data_clone()`. + +[source,c] +-------- +struct nl_data *nl_data_alloc(void *buf, size_t size); +struct nl_data *nl_data_alloc_attr(struct nlattr *attr); +struct nl_data *nl_data_clone(struct nl_data *data); +void nl_data_free(struct nl_data *data); +-------- + +.Access to Data + +The function `nl_data_get()` returns a pointer to the data, the size +of data is returned by `nl_data_get_size()`. + +[source,c] +-------- +void *nl_data_get(struct nl_data *data); +size_t nl_data_get_size(struct nl_data *data); +-------- + +.Data Helpers + +The function nl_data_append() reallocates the internal data buffers +and appends the specified `buf` to the existing data. + +[source,c] +-------- +int nl_data_append(struct nl_data *data, void *buf, size_t size); +-------- + +CAUTION: Any call to `nl_data_append()` invalidates all pointers + returned by `nl_data_get()` of the same data object. + +[source,c] +-------- +int nl_data_cmp(struct nl_data *data, struct nl_data *data); +-------- diff --git a/doc/doxygen-link.py b/doc/doxygen-link.py new file mode 100755 index 00000000..910b8f8d --- /dev/null +++ b/doc/doxygen-link.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +from __future__ import print_function +import fileinput +import re +import sys + + +rc_script = re.compile(r'\s*(.*\S)?\s*') + +def parse_dict(filename): + links = {} + for line in open(filename, 'r'): + m = re.match('^([^=]+)=([^\n]+)$', line); + if not m: + continue + name = m.group(1) + value = m.group(2) + + # strip leading and trailing whitespace + m = rc_script.match(name) + if m: + name = m.group(1) + + # skip special names + if name == '': + continue + if name == '\\': + continue + + links[name] = "<a href=\"" + value + "\" class=\"dg\">" + name + "</a>" + return links + +links = parse_dict(sys.argv[1]) + +def translate(match): + return links[match.group(1)] + +# match for all names, with word boundaries \b +rc = re.compile(r'\b(' + '|'.join(map(re.escape, sorted(links, reverse=True))) + r')\b') + +for line in open(sys.argv[2], 'r'): + print(rc.sub(translate, line), end='') diff --git a/doc/gen-tags.sh b/doc/gen-tags.sh new file mode 100755 index 00000000..862ec090 --- /dev/null +++ b/doc/gen-tags.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +# +# Based on a script found on the englinemtn-devel mailinglist +# written by Carsten Haitzler <ras...@rasterman.com> +# + +for f in api/group__*.html +do + bf=$(basename $f) + + grep -oE "href=\"$bf#[a-z0-9]+\">[^<]+</a>" $f | + sed 's/href="\([^"]*\)">\([^<]*\)<\/a>/\2=api\/\1/' +done diff --git a/doc/html/.gitignore b/doc/html/.gitignore deleted file mode 100644 index 72e8ffc0..00000000 --- a/doc/html/.gitignore +++ /dev/null @@ -1 +0,0 @@ -* diff --git a/doc/images/.gitignore b/doc/images/.gitignore new file mode 100644 index 00000000..efcc7e23 --- /dev/null +++ b/doc/images/.gitignore @@ -0,0 +1,3 @@ +core__* +asciidoc__*.png +*.odg diff --git a/doc/images/addressing.png b/doc/images/addressing.png Binary files differnew file mode 100644 index 00000000..9dcaaffd --- /dev/null +++ b/doc/images/addressing.png diff --git a/doc/images/attribute_hdr.png b/doc/images/attribute_hdr.png Binary files differnew file mode 100644 index 00000000..0e6cfdad --- /dev/null +++ b/doc/images/attribute_hdr.png diff --git a/doc/images/classful_qdisc.png b/doc/images/classful_qdisc.png Binary files differnew file mode 100644 index 00000000..7e77350f --- /dev/null +++ b/doc/images/classful_qdisc.png diff --git a/doc/images/classless_qdisc.png b/doc/images/classless_qdisc.png Binary files differnew file mode 100644 index 00000000..bcf2c1ce --- /dev/null +++ b/doc/images/classless_qdisc.png diff --git a/doc/images/classless_qdisc_nbands.png b/doc/images/classless_qdisc_nbands.png Binary files differnew file mode 100644 index 00000000..14cb0260 --- /dev/null +++ b/doc/images/classless_qdisc_nbands.png diff --git a/doc/images/icons/README b/doc/images/icons/README new file mode 100644 index 00000000..f12b2a73 --- /dev/null +++ b/doc/images/icons/README @@ -0,0 +1,5 @@ +Replaced the plain DocBook XSL admonition icons with Jimmac's DocBook +icons (http://jimmac.musichall.cz/ikony.php3). I dropped transparency +from the Jimmac icons to get round MS IE and FOP PNG incompatibilies. + +Stuart Rackham diff --git a/doc/images/icons/callouts/1.png b/doc/images/icons/callouts/1.png Binary files differnew file mode 100644 index 00000000..7d473430 --- /dev/null +++ b/doc/images/icons/callouts/1.png diff --git a/doc/images/icons/callouts/10.png b/doc/images/icons/callouts/10.png Binary files differnew file mode 100644 index 00000000..997bbc82 --- /dev/null +++ b/doc/images/icons/callouts/10.png diff --git a/doc/images/icons/callouts/11.png b/doc/images/icons/callouts/11.png Binary files differnew file mode 100644 index 00000000..ce47dac3 --- /dev/null +++ b/doc/images/icons/callouts/11.png diff --git a/doc/images/icons/callouts/12.png b/doc/images/icons/callouts/12.png Binary files differnew file mode 100644 index 00000000..31daf4e2 --- /dev/null +++ b/doc/images/icons/callouts/12.png diff --git a/doc/images/icons/callouts/13.png b/doc/images/icons/callouts/13.png Binary files differnew file mode 100644 index 00000000..14021a89 --- /dev/null +++ b/doc/images/icons/callouts/13.png diff --git a/doc/images/icons/callouts/14.png b/doc/images/icons/callouts/14.png Binary files differnew file mode 100644 index 00000000..64014b75 --- /dev/null +++ b/doc/images/icons/callouts/14.png diff --git a/doc/images/icons/callouts/15.png b/doc/images/icons/callouts/15.png Binary files differnew file mode 100644 index 00000000..0d65765f --- /dev/null +++ b/doc/images/icons/callouts/15.png diff --git a/doc/images/icons/callouts/2.png b/doc/images/icons/callouts/2.png Binary files differnew file mode 100644 index 00000000..5d09341b --- /dev/null +++ b/doc/images/icons/callouts/2.png diff --git a/doc/images/icons/callouts/3.png b/doc/images/icons/callouts/3.png Binary files differnew file mode 100644 index 00000000..ef7b7004 --- /dev/null +++ b/doc/images/icons/callouts/3.png diff --git a/doc/images/icons/callouts/4.png b/doc/images/icons/callouts/4.png Binary files differnew file mode 100644 index 00000000..adb8364e --- /dev/null +++ b/doc/images/icons/callouts/4.png diff --git a/doc/images/icons/callouts/5.png b/doc/images/icons/callouts/5.png Binary files differnew file mode 100644 index 00000000..4d7eb460 --- /dev/null +++ b/doc/images/icons/callouts/5.png diff --git a/doc/images/icons/callouts/6.png b/doc/images/icons/callouts/6.png Binary files differnew file mode 100644 index 00000000..0ba694af --- /dev/null +++ b/doc/images/icons/callouts/6.png diff --git a/doc/images/icons/callouts/7.png b/doc/images/icons/callouts/7.png Binary files differnew file mode 100644 index 00000000..472e96f8 --- /dev/null +++ b/doc/images/icons/callouts/7.png diff --git a/doc/images/icons/callouts/8.png b/doc/images/icons/callouts/8.png Binary files differnew file mode 100644 index 00000000..5e60973c --- /dev/null +++ b/doc/images/icons/callouts/8.png diff --git a/doc/images/icons/callouts/9.png b/doc/images/icons/callouts/9.png Binary files differnew file mode 100644 index 00000000..a0676d26 --- /dev/null +++ b/doc/images/icons/callouts/9.png diff --git a/doc/images/icons/caution.png b/doc/images/icons/caution.png Binary files differnew file mode 100644 index 00000000..9a8c515a --- /dev/null +++ b/doc/images/icons/caution.png diff --git a/doc/images/icons/example.png b/doc/images/icons/example.png Binary files differnew file mode 100644 index 00000000..1199e864 --- /dev/null +++ b/doc/images/icons/example.png diff --git a/doc/images/icons/home.png b/doc/images/icons/home.png Binary files differnew file mode 100644 index 00000000..37a5231b --- /dev/null +++ b/doc/images/icons/home.png diff --git a/doc/images/icons/important.png b/doc/images/icons/important.png Binary files differnew file mode 100644 index 00000000..be685cc4 --- /dev/null +++ b/doc/images/icons/important.png diff --git a/doc/images/icons/next.png b/doc/images/icons/next.png Binary files differnew file mode 100644 index 00000000..64e126bd --- /dev/null +++ b/doc/images/icons/next.png diff --git a/doc/images/icons/note.png b/doc/images/icons/note.png Binary files differnew file mode 100644 index 00000000..7c1f3e2f --- /dev/null +++ b/doc/images/icons/note.png diff --git a/doc/images/icons/prev.png b/doc/images/icons/prev.png Binary files differnew file mode 100644 index 00000000..3e8f12fe --- /dev/null +++ b/doc/images/icons/prev.png diff --git a/doc/images/icons/tip.png b/doc/images/icons/tip.png Binary files differnew file mode 100644 index 00000000..f087c73b --- /dev/null +++ b/doc/images/icons/tip.png diff --git a/doc/images/icons/up.png b/doc/images/icons/up.png Binary files differnew file mode 100644 index 00000000..2db1ce62 --- /dev/null +++ b/doc/images/icons/up.png diff --git a/doc/images/icons/warning.png b/doc/images/icons/warning.png Binary files differnew file mode 100644 index 00000000..d41edb9a --- /dev/null +++ b/doc/images/icons/warning.png diff --git a/doc/images/ifinfomsg.png b/doc/images/ifinfomsg.png Binary files differnew file mode 100644 index 00000000..fb94cf7b --- /dev/null +++ b/doc/images/ifinfomsg.png diff --git a/doc/images/library_overview.png b/doc/images/library_overview.png Binary files differnew file mode 100644 index 00000000..dd9d5fe9 --- /dev/null +++ b/doc/images/library_overview.png diff --git a/doc/images/nlmsgerr.png b/doc/images/nlmsgerr.png Binary files differnew file mode 100644 index 00000000..58e53d55 --- /dev/null +++ b/doc/images/nlmsgerr.png diff --git a/doc/images/nlmsghdr.png b/doc/images/nlmsghdr.png Binary files differnew file mode 100644 index 00000000..dd39b9ca --- /dev/null +++ b/doc/images/nlmsghdr.png diff --git a/doc/images/qdisc_default.png b/doc/images/qdisc_default.png Binary files differnew file mode 100644 index 00000000..a7ba1678 --- /dev/null +++ b/doc/images/qdisc_default.png diff --git a/doc/images/qdisc_mq.png b/doc/images/qdisc_mq.png Binary files differnew file mode 100644 index 00000000..c6318b28 --- /dev/null +++ b/doc/images/qdisc_mq.png diff --git a/doc/images/tc_obj.png b/doc/images/tc_obj.png Binary files differnew file mode 100644 index 00000000..bfc81452 --- /dev/null +++ b/doc/images/tc_obj.png diff --git a/doc/images/tc_overview.png b/doc/images/tc_overview.png Binary files differnew file mode 100644 index 00000000..ce23e67b --- /dev/null +++ b/doc/images/tc_overview.png diff --git a/doc/index.txt b/doc/index.txt new file mode 100644 index 00000000..c207b448 --- /dev/null +++ b/doc/index.txt @@ -0,0 +1,22 @@ +Documentation Overview - libnl Suite +==================================== + +== Libraries + +image:library_overview.png["Library Hierarchy"] + +link:core.html[Netlink Library] (libnl):: +Socket handling, sending and receiving, message construction and parsing, ... + +link:route.html[Routing Family Library] (libnl-route):: +Adresses, links, neighbours, routing, traffic control, neighbour tables, ... + +Netfilter Library (libnl-nf):: +Connection tracking, logging, queueing + +Generic Netlink Library (libnl-genl):: +Controller API, family and command registration + +== Python Packages + - netlink.core + - netlink.route.link diff --git a/doc/libnl.css b/doc/libnl.css index 22c48430..85894507 100644 --- a/doc/libnl.css +++ b/doc/libnl.css @@ -1,473 +1,1156 @@ -BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV { - font-family: Geneva, Arial, Helvetica, sans-serif; +/* The standard CSS for doxygen */ + +body, table, div, p, dl { + font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif; + font-size: 13px; + line-height: 1.3; } -BODY,TD { - font-size: 90%; + +/* @group Heading Levels */ + +h1 { + font-size: 150%; } -H1 { - text-align: center; - font-size: 160%; + +.title { + font-size: 150%; + font-weight: bold; + margin: 10px 2px; } -H2 { + +h2 { font-size: 120%; } -H3 { + +h3 { font-size: 100%; } -CAPTION { - font-weight: bold + +h1, h2, h3, h4, h5, h6 { + -webkit-transition: text-shadow 0.5s linear; + -moz-transition: text-shadow 0.5s linear; + -ms-transition: text-shadow 0.5s linear; + -o-transition: text-shadow 0.5s linear; + transition: text-shadow 0.5s linear; + margin-right: 15px; } -DIV.qindex { - width: 100%; - background-color: #e8eef2; - border: 1px solid #84b0c7; + +h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow { + text-shadow: 0 0 15px cyan; +} + +dt { + font-weight: bold; +} + +div.multicol { + -moz-column-gap: 1em; + -webkit-column-gap: 1em; + -moz-column-count: 3; + -webkit-column-count: 3; +} + +p.startli, p.startdd, p.starttd { + margin-top: 2px; +} + +p.endli { + margin-bottom: 0px; +} + +p.enddd { + margin-bottom: 4px; +} + +p.endtd { + margin-bottom: 2px; +} + +/* @end */ + +caption { + font-weight: bold; +} + +span.legend { + font-size: 70%; + text-align: center; +} + +h3.version { + font-size: 90%; + text-align: center; +} + +div.qindex, div.navtab{ + background-color: #EBEFF6; + border: 1px solid #A3B4D7; text-align: center; - margin: 2px; - padding: 2px; - line-height: 140%; } -DIV.navpath { + +div.qindex, div.navpath { width: 100%; - background-color: #e8eef2; - border: 1px solid #84b0c7; - text-align: center; - margin: 2px; - padding: 2px; line-height: 140%; } -DIV.navtab { - background-color: #e8eef2; - border: 1px solid #84b0c7; - text-align: center; - margin: 2px; - margin-right: 15px; - padding: 2px; + +div.navtab { + margin-right: 15px; } -TD.navtab { - font-size: 70%; + +/* @group Link Styling */ + +a { + color: #3D578C; + font-weight: normal; + text-decoration: none; } -A.qindex { - text-decoration: none; - font-weight: bold; - color: #1A419D; + +.contents a:visited { + color: #4665A2; } -A.qindex:visited { - text-decoration: none; - font-weight: bold; - color: #1A419D + +a:hover { + text-decoration: underline; } -A.qindex:hover { - text-decoration: none; - background-color: #ddddff; + +a.qindex { + font-weight: bold; } -A.qindexHL { - text-decoration: none; + +a.qindexHL { font-weight: bold; - background-color: #6666cc; + background-color: #9CAFD4; color: #ffffff; - border: 1px double #9295C2; + border: 1px double #869DCA; } -A.qindexHL:hover { - text-decoration: none; - background-color: #6666cc; - color: #ffffff; + +.contents a.qindexHL:visited { + color: #ffffff; +} + +a.el { + font-weight: bold; } -A.qindexHL:visited { - text-decoration: none; - background-color: #6666cc; - color: #ffffff + +a.elRef { } -A.el { - text-decoration: none; - font-weight: bold + +a.code, a.code:visited { + color: #4665A2; } -A.elRef { - font-weight: bold + +a.codeRef, a.codeRef:visited { + color: #4665A2; } -A.code:link { - text-decoration: none; - font-weight: normal; - color: #0000FF + +/* @end */ + +dl.el { + margin-left: -1cm; } -A.code:visited { - text-decoration: none; - font-weight: normal; - color: #0000FF + +pre.fragment { + border: 1px solid #C4CFE5; + background-color: #FBFCFD; + padding: 4px 6px; + margin: 4px 8px 4px 2px; + overflow: auto; + word-wrap: break-word; + font-size: 9pt; + line-height: 125%; + font-family: monospace, fixed; + font-size: 105%; } -A.codeRef:link { - font-weight: normal; - color: #0000FF + +div.fragment { + padding: 4px; + margin: 4px; + background-color: #FBFCFD; + border: 1px solid #C4CFE5; } -A.codeRef:visited { - font-weight: normal; - color: #0000FF + +div.line { + font-family: monospace, fixed; + font-size: 13px; + min-height: 13px; + line-height: 1.0; + text-wrap: unrestricted; + white-space: -moz-pre-wrap; /* Moz */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: pre-wrap; /* CSS3 */ + word-wrap: break-word; /* IE 5.5+ */ + text-indent: -53px; + padding-left: 53px; + padding-bottom: 0px; + margin: 0px; + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; } -A:hover { - text-decoration: none; - background-color: #f2f2ff + +div.line.glow { + background-color: cyan; + box-shadow: 0 0 10px cyan; } -DL.el { - margin-left: -1cm + + +span.lineno { + padding-right: 4px; + text-align: right; + border-right: 2px solid #0F0; + background-color: #E8E8E8; + white-space: pre; } -.fragment { - font-family: monospace, fixed; - font-size: 95%; +span.lineno a { + background-color: #D8D8D8; } -PRE.fragment { - border: 1px solid #CCCCCC; - background-color: #f5f5f5; - margin-top: 4px; - margin-bottom: 4px; - margin-left: 2px; - margin-right: 8px; - padding-left: 6px; - padding-right: 6px; - padding-top: 4px; - padding-bottom: 4px; + +span.lineno a:hover { + background-color: #C8C8C8; } -DIV.ah { - background-color: black; - font-weight: bold; - color: #ffffff; - margin-bottom: 3px; - margin-top: 3px + +div.ah { + background-color: black; + font-weight: bold; + color: #ffffff; + margin-bottom: 3px; + margin-top: 3px; + padding: 0.2em; + border: solid thin #333; + border-radius: 0.5em; + -webkit-border-radius: .5em; + -moz-border-radius: .5em; + box-shadow: 2px 2px 3px #999; + -webkit-box-shadow: 2px 2px 3px #999; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); + background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000); } -DIV.groupHeader { - margin-left: 16px; - margin-top: 12px; - margin-bottom: 6px; - font-weight: bold; +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + font-weight: bold; } -DIV.groupText { - margin-left: 16px; - font-style: italic; - font-size: 90% + +div.groupText { + margin-left: 16px; + font-style: italic; } -BODY { - background: white; + +body { + background-color: white; color: black; - margin-right: 20px; - margin-left: 20px; + margin: 0; } -TD.indexkey { - background-color: #e8eef2; + +div.contents { + margin-top: 10px; + margin-left: 12px; + margin-right: 8px; +} + +td.indexkey { + background-color: #EBEFF6; font-weight: bold; - padding-right : 10px; - padding-top : 2px; - padding-left : 10px; - padding-bottom : 2px; - margin-left : 0px; - margin-right : 0px; - margin-top : 2px; - margin-bottom : 2px; - border: 1px solid #CCCCCC; -} -TD.indexvalue { - background-color: #e8eef2; - font-style: italic; - padding-right : 10px; - padding-top : 2px; - padding-left : 10px; - padding-bottom : 2px; - margin-left : 0px; - margin-right : 0px; - margin-top : 2px; - margin-bottom : 2px; - border: 1px solid #CCCCCC; -} -TR.memlist { - background-color: #f0f0f0; -} -P.formulaDsp { - text-align: center; -} -IMG.formulaDsp { -} -IMG.formulaInl { - vertical-align: middle; -} -SPAN.keyword { color: #008000 } -SPAN.keywordtype { color: #604020 } -SPAN.keywordflow { color: #e08000 } -SPAN.comment { color: #800000 } -SPAN.preprocessor { color: #806020 } -SPAN.stringliteral { color: #002080 } -SPAN.charliteral { color: #008080 } -SPAN.vhdldigit { color: #ff00ff } -SPAN.vhdlchar { color: #000000 } -SPAN.vhdlkeyword { color: #700070 } -SPAN.vhdllogic { color: #ff0000 } - -.mdescLeft { - padding: 0px 8px 4px 8px; - font-size: 80%; - font-style: italic; - background-color: #FAFAFA; - border-top: 1px none #E0E0E0; - border-right: 1px none #E0E0E0; - border-bottom: 1px none #E0E0E0; - border-left: 1px none #E0E0E0; - margin: 0px; + border: 1px solid #C4CFE5; + margin: 2px 0px 2px 0; + padding: 2px 10px; + white-space: nowrap; + vertical-align: top; } -.mdescRight { - padding: 0px 8px 4px 8px; - font-size: 80%; - font-style: italic; - background-color: #FAFAFA; - border-top: 1px none #E0E0E0; - border-right: 1px none #E0E0E0; - border-bottom: 1px none #E0E0E0; - border-left: 1px none #E0E0E0; - margin: 0px; + +td.indexvalue { + background-color: #EBEFF6; + border: 1px solid #C4CFE5; + padding: 2px 10px; + margin: 2px 0px; } -.memItemLeft { - padding: 1px 0px 0px 8px; - margin: 4px; - border-top-width: 1px; - border-right-width: 1px; - border-bottom-width: 1px; - border-left-width: 1px; - border-top-color: #E0E0E0; - border-right-color: #E0E0E0; - border-bottom-color: #E0E0E0; - border-left-color: #E0E0E0; - border-top-style: solid; - border-right-style: none; - border-bottom-style: none; - border-left-style: none; - background-color: #FAFAFA; - font-size: 80%; + +tr.memlist { + background-color: #EEF1F7; } -.memItemRight { - padding: 1px 8px 0px 8px; - margin: 4px; - border-top-width: 1px; - border-right-width: 1px; - border-bottom-width: 1px; - border-left-width: 1px; - border-top-color: #E0E0E0; - border-right-color: #E0E0E0; - border-bottom-color: #E0E0E0; - border-left-color: #E0E0E0; - border-top-style: solid; - border-right-style: none; - border-bottom-style: none; - border-left-style: none; - background-color: #FAFAFA; - font-size: 80%; + +p.formulaDsp { + text-align: center; } -.memTemplItemLeft { - padding: 1px 0px 0px 8px; - margin: 4px; - border-top-width: 1px; - border-right-width: 1px; - border-bottom-width: 1px; - border-left-width: 1px; - border-top-color: #E0E0E0; - border-right-color: #E0E0E0; - border-bottom-color: #E0E0E0; - border-left-color: #E0E0E0; - border-top-style: none; - border-right-style: none; - border-bottom-style: none; - border-left-style: none; - background-color: #FAFAFA; - font-size: 80%; + +img.formulaDsp { + } -.memTemplItemRight { - padding: 1px 8px 0px 8px; - margin: 4px; - border-top-width: 1px; - border-right-width: 1px; - border-bottom-width: 1px; - border-left-width: 1px; - border-top-color: #E0E0E0; - border-right-color: #E0E0E0; - border-bottom-color: #E0E0E0; - border-left-color: #E0E0E0; - border-top-style: none; - border-right-style: none; - border-bottom-style: none; - border-left-style: none; - background-color: #FAFAFA; - font-size: 80%; + +img.formulaInl { + vertical-align: middle; } -.memTemplParams { - padding: 1px 0px 0px 8px; - margin: 4px; - border-top-width: 1px; - border-right-width: 1px; - border-bottom-width: 1px; - border-left-width: 1px; - border-top-color: #E0E0E0; - border-right-color: #E0E0E0; - border-bottom-color: #E0E0E0; - border-left-color: #E0E0E0; - border-top-style: solid; - border-right-style: none; - border-bottom-style: none; - border-left-style: none; - color: #606060; - background-color: #FAFAFA; - font-size: 80%; + +div.center { + text-align: center; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; +} + +div.center img { + border: 0px; +} + +address.footer { + text-align: right; + padding-right: 12px; +} + +img.footer { + border: 0px; + vertical-align: middle; +} + +/* @group Code Colorization */ + +span.keyword { + color: #008000 +} + +span.keywordtype { + color: #604020 +} + +span.keywordflow { + color: #e08000 +} + +span.comment { + color: #800000 +} + +span.preprocessor { + color: #806020 +} + +span.stringliteral { + color: #002080 +} + +span.charliteral { + color: #008080 +} + +span.vhdldigit { + color: #ff00ff +} + +span.vhdlchar { + color: #000000 +} + +span.vhdlkeyword { + color: #700070 +} + +span.vhdllogic { + color: #ff0000 +} + +blockquote { + background-color: #F7F8FB; + border-left: 2px solid #9CAFD4; + margin: 0 24px 0 4px; + padding: 0 12px 0 16px; } -.search { + +/* @end */ + +/* +.search { color: #003399; font-weight: bold; } -FORM.search { + +form.search { margin-bottom: 0px; margin-top: 0px; } -INPUT.search { + +input.search { font-size: 75%; color: #000080; font-weight: normal; background-color: #e8eef2; } -TD.tiny { +*/ + +td.tiny { font-size: 75%; } -a { - color: #1A41A8; -} -a:visited { - color: #2A3798; -} -.dirtab { + +.dirtab { padding: 4px; border-collapse: collapse; - border: 1px solid #84b0c7; + border: 1px solid #A3B4D7; } -TH.dirtab { - background: #e8eef2; + +th.dirtab { + background: #EBEFF6; font-weight: bold; } -HR { + +hr { + height: 0px; + border: none; + border-top: 1px solid #4A6AAA; +} + +hr.footer { height: 1px; +} + +/* @group Member Descriptions */ + +table.memberdecls { + border-spacing: 0px; + padding: 0px; +} + +.memberdecls td { + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +.memberdecls td.glow { + background-color: cyan; + box-shadow: 0 0 15px cyan; +} + +.mdescLeft, .mdescRight, +.memItemLeft, .memItemRight, +.memTemplItemLeft, .memTemplItemRight, .memTemplParams { + background-color: #F9FAFC; border: none; - border-top: 1px solid black; + margin: 4px; + padding: 1px 0 0 8px; +} + +.mdescLeft, .mdescRight { + padding: 0px 8px 4px 8px; + color: #555; +} + +.memItemLeft, .memItemRight, .memTemplParams { + border-top: 1px solid #C4CFE5; +} + +.memItemLeft, .memTemplItemLeft { + white-space: nowrap; +} + +.memItemRight { + width: 100%; } -/* Style for detailed member documentation */ +.memTemplParams { + color: #4665A2; + white-space: nowrap; +} + +/* @end */ + +/* @group Member Details */ + +/* Styles for detailed member documentation */ + .memtemplate { font-size: 80%; - color: #606060; + color: #4665A2; font-weight: normal; - margin-left: 3px; -} -.memnav { - background-color: #e8eef2; - border: 1px solid #84b0c7; + margin-left: 9px; +} + +.memnav { + background-color: #EBEFF6; + border: 1px solid #A3B4D7; text-align: center; margin: 2px; margin-right: 15px; padding: 2px; } + +.mempage { + width: 100%; +} + .memitem { - padding: 4px; - background-color: #eef3f5; - border-width: 1px; - border-style: solid; - border-color: #dedeee; - -moz-border-radius: 8px 8px 8px 8px; + padding: 0; + margin-bottom: 10px; + margin-right: 5px; + -webkit-transition: box-shadow 0.5s linear; + -moz-transition: box-shadow 0.5s linear; + -ms-transition: box-shadow 0.5s linear; + -o-transition: box-shadow 0.5s linear; + transition: box-shadow 0.5s linear; + display: table !important; + width: 100%; +} + +.memitem.glow { + box-shadow: 0 0 15px cyan; } + .memname { - white-space: nowrap; - font-weight: bold; + font-weight: bold; + margin-left: 6px; } -.memdoc{ - padding-left: 10px; + +.memname td { + vertical-align: bottom; } -.memproto { - background-color: #d5e1e8; - width: 100%; - border-width: 1px; - border-style: solid; - border-color: #84b0c7; - font-weight: bold; - -moz-border-radius: 8px 8px 8px 8px; + +.memproto, dl.reflist dt { + border-top: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 6px 0px 6px 0px; + color: #253555; + font-weight: bold; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #E2E8F2; + /* opera specific markup */ + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + border-top-right-radius: 4px; + border-top-left-radius: 4px; + /* firefox specific markup */ + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + -moz-border-radius-topright: 4px; + -moz-border-radius-topleft: 4px; + /* webkit specific markup */ + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + -webkit-border-top-right-radius: 4px; + -webkit-border-top-left-radius: 4px; + } + +.memdoc, dl.reflist dd { + border-bottom: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 6px 10px 2px 10px; + background-color: #FBFCFD; + border-top-width: 0; + background-image:url('nav_g.png'); + background-repeat:repeat-x; + background-color: #FFFFFF; + /* opera specific markup */ + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + /* firefox specific markup */ + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-bottomright: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + /* webkit specific markup */ + -webkit-border-bottom-left-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); +} + +dl.reflist dt { + padding: 5px; +} + +dl.reflist dd { + margin: 0px 0px 10px 0px; + padding: 5px; +} + .paramkey { text-align: right; } + .paramtype { white-space: nowrap; } + .paramname { color: #602020; - font-style: italic; white-space: nowrap; } -/* End Styling for detailed member documentation */ +.paramname em { + font-style: normal; +} +.paramname code { + line-height: 14px; +} + +.params, .retval, .exception, .tparams { + margin-left: 0px; + padding-left: 0px; +} -/* for the tree view */ -.ftvtree { - font-family: sans-serif; - margin:0.5em; +.params .paramname, .retval .paramname { + font-weight: bold; + vertical-align: top; +} + +.params .paramtype { + font-style: italic; + vertical-align: top; +} + +.params .paramdir { + font-family: "courier new",courier,monospace; + vertical-align: top; } -/* these are for tree view when used as main index */ -.directory { - font-size: 9pt; - font-weight: bold; + +table.mlabels { + border-spacing: 0px; } -.directory h3 { - margin: 0px; - margin-top: 1em; - font-size: 11pt; + +td.mlabels-left { + width: 100%; + padding: 0px; } -/* The following two styles can be used to replace the root node title */ -/* with an image of your choice. Simply uncomment the next two styles, */ -/* specify the name of your image and be sure to set 'height' to the */ -/* proper pixel height of your image. */ +td.mlabels-right { + vertical-align: bottom; + padding: 0px; + white-space: nowrap; +} -/* .directory h3.swap { */ -/* height: 61px; */ -/* background-repeat: no-repeat; */ -/* background-image: url("yourimage.gif"); */ -/* } */ -/* .directory h3.swap span { */ -/* display: none; */ -/* } */ +span.mlabels { + margin-left: 8px; +} -.directory > h3 { - margin-top: 0; +span.mlabel { + background-color: #728DC1; + border-top:1px solid #5373B4; + border-left:1px solid #5373B4; + border-right:1px solid #C4CFE5; + border-bottom:1px solid #C4CFE5; + text-shadow: none; + color: white; + margin-right: 4px; + padding: 2px 3px; + border-radius: 3px; + font-size: 7pt; + white-space: nowrap; } -.directory p { - margin: 0px; - white-space: nowrap; + + + +/* @end */ + +/* these are for tree view when not used as main index */ + +div.directory { + margin: 10px 0px; + border-top: 1px solid #A8B8D9; + border-bottom: 1px solid #A8B8D9; + width: 100%; +} + +.directory table { + border-collapse:collapse; } -.directory div { - display: none; - margin: 0px; + +.directory td { + margin: 0px; + padding: 0px; + vertical-align: top; } -.directory img { - vertical-align: -30%; + +.directory td.entry { + white-space: nowrap; + padding-right: 6px; } -/* these are for tree view when not used as main index */ -.directory-alt { - font-size: 100%; - font-weight: bold; + +.directory td.entry a { + outline:none; +} + +.directory td.entry a img { + border: none; +} + +.directory td.desc { + width: 100%; + padding-left: 6px; + padding-right: 6px; + border-left: 1px solid rgba(0,0,0,0.05); +} + +.directory tr.even { + padding-left: 6px; + background-color: #F7F8FB; +} + +.directory img { + vertical-align: -30%; +} + +.directory .levels { + white-space: nowrap; + width: 100%; + text-align: right; + font-size: 9pt; +} + +.directory .levels span { + cursor: pointer; + padding-left: 2px; + padding-right: 2px; + color: #3D578C; +} + +div.dynheader { + margin-top: 8px; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +address { + font-style: normal; + color: #2A3D61; +} + +table.doxtable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.doxtable td, table.doxtable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +table.doxtable th { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +table.fieldtable { + width: 100%; + margin-bottom: 10px; + border: 1px solid #A8B8D9; + border-spacing: 0px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); + box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); +} + +.fieldtable td, .fieldtable th { + padding: 3px 7px 2px; } -.directory-alt h3 { - margin: 0px; - margin-top: 1em; - font-size: 11pt; + +.fieldtable td.fieldtype, .fieldtable td.fieldname { + white-space: nowrap; + border-right: 1px solid #A8B8D9; + border-bottom: 1px solid #A8B8D9; + vertical-align: top; +} + +.fieldtable td.fielddoc { + border-bottom: 1px solid #A8B8D9; + width: 100%; +} + +.fieldtable tr:last-child td { + border-bottom: none; +} + +.fieldtable th { + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #E2E8F2; + font-size: 90%; + color: #253555; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; + -moz-border-radius-topleft: 4px; + -moz-border-radius-topright: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom: 1px solid #A8B8D9; } -.directory-alt > h3 { - margin-top: 0; + + +.tabsearch { + top: 0px; + left: 10px; + height: 36px; + background-image: url('tab_b.png'); + z-index: 101; + overflow: hidden; + font-size: 13px; } -.directory-alt p { - margin: 0px; - white-space: nowrap; + +.navpath ul +{ + font-size: 11px; + background-image:url('tab_b.png'); + background-repeat:repeat-x; + height:30px; + line-height:30px; + color:#8AA0CC; + border:solid 1px #C2CDE4; + overflow:hidden; + margin:0px; + padding:0px; } -.directory-alt div { - display: none; - margin: 0px; + +.navpath li +{ + list-style-type:none; + float:left; + padding-left:10px; + padding-right:15px; + background-image:url('bc_s.png'); + background-repeat:no-repeat; + background-position:right; + color:#364D7C; } -.directory-alt img { - vertical-align: -30%; + +.navpath li.navelem a +{ + height:32px; + display:block; + text-decoration: none; + outline: none; +} + +.navpath li.navelem a:hover +{ + color:#6884BD; +} + +.navpath li.footer +{ + list-style-type:none; + float:right; + padding-left:10px; + padding-right:15px; + background-image:none; + background-repeat:no-repeat; + background-position:right; + color:#364D7C; + font-size: 8pt; +} + + +div.summary +{ + float: right; + font-size: 8pt; + padding-right: 5px; + width: 50%; + text-align: right; +} + +div.summary a +{ + white-space: nowrap; +} + +div.ingroups +{ + font-size: 8pt; + width: 50%; + text-align: left; +} + +div.ingroups a +{ + white-space: nowrap; +} + +div.header +{ + background-image:url('nav_h.png'); + background-repeat:repeat-x; + background-color: #F9FAFC; + margin: 0px; + border-bottom: 1px solid #C4CFE5; +} + +div.headertitle +{ + padding: 5px 5px 5px 7px; +} + +dl +{ + padding: 0 0 0 10px; +} + +/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug */ +dl.section +{ + margin-left: 0px; + padding-left: 0px; +} + +dl.note +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #D0C000; +} + +dl.warning, dl.attention +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #FF0000; +} + +dl.pre, dl.post, dl.invariant +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #00D000; +} + +dl.deprecated +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #505050; +} + +dl.todo +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #00C0E0; +} + +dl.test +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #3030E0; +} + +dl.bug +{ + margin-left:-7px; + padding-left: 3px; + border-left:4px solid; + border-color: #C08050; +} + +dl.section dd { + margin-bottom: 6px; +} + + +#projectlogo +{ + text-align: center; + vertical-align: bottom; + border-collapse: separate; +} + +#projectlogo img +{ + border: 0px none; +} + +#projectname +{ + font: 300% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 2px 0px; +} + +#projectbrief +{ + font: 120% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#projectnumber +{ + font: 50% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#titlearea +{ + padding: 0px; + margin: 0px; + width: 100%; + border-bottom: 1px solid #5373B4; +} + +.image +{ + text-align: center; +} + +.dotgraph +{ + text-align: center; +} + +.mscgraph +{ + text-align: center; +} + +.caption +{ + font-weight: bold; +} + +div.zoom +{ + border: 1px solid #90A5CE; +} + +dl.citelist { + margin-bottom:50px; +} + +dl.citelist dt { + color:#334975; + float:left; + font-weight:bold; + margin-right:10px; + padding:5px; +} + +dl.citelist dd { + margin:2px 0; + padding:5px 0; +} + +div.toc { + padding: 14px 25px; + background-color: #F4F6FA; + border: 1px solid #D8DFEE; + border-radius: 7px 7px 7px 7px; + float: right; + height: auto; + margin: 0 20px 10px 10px; + width: 200px; +} + +div.toc li { + background: url("bdwn.png") no-repeat scroll 0 5px transparent; + font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif; + margin-top: 5px; + padding-left: 10px; + padding-top: 2px; +} + +div.toc h3 { + font: bold 12px/1.2 Arial,FreeSans,sans-serif; + color: #4665A2; + border-bottom: 0 none; + margin: 0; +} + +div.toc ul { + list-style: none outside none; + border: medium none; + padding: 0px; +} + +div.toc li.level1 { + margin-left: 0px; +} + +div.toc li.level2 { + margin-left: 15px; +} + +div.toc li.level3 { + margin-left: 30px; +} + +div.toc li.level4 { + margin-left: 45px; +} + +.inherit_header { + font-weight: bold; + color: gray; + cursor: pointer; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.inherit_header td { + padding: 6px 0px 2px 5px; +} + +.inherit { + display: none; +} + +tr.heading h2 { + margin-top: 12px; + margin-bottom: 4px; +} + +@media print +{ + #top { display: none; } + #side-nav { display: none; } + #nav-path { display: none; } + body { overflow:visible; } + h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } + .summary { display: none; } + .memitem { page-break-inside: avoid; } + #doc-content + { + margin-left:0 !important; + height:auto !important; + width:auto !important; + overflow:inherit; + display:inline; + } } diff --git a/doc/m4/ax_python.m4 b/doc/m4/ax_python.m4 new file mode 100644 index 00000000..f9a51359 --- /dev/null +++ b/doc/m4/ax_python.m4 @@ -0,0 +1,97 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_python.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_PYTHON +# +# DESCRIPTION +# +# This macro does a complete Python development environment check. +# +# It recurses through several python versions (from 2.1 to 2.6 in this +# version), looking for an executable. When it finds an executable, it +# looks to find the header files and library. +# +# It sets PYTHON_BIN to the name of the python executable, +# PYTHON_INCLUDE_DIR to the directory holding the header files, and +# PYTHON_LIB to the name of the Python library. +# +# This macro calls AC_SUBST on PYTHON_BIN (via AC_CHECK_PROG), +# PYTHON_INCLUDE_DIR and PYTHON_LIB. +# +# LICENSE +# +# Copyright (c) 2008 Michael Tindal +# +# This program is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the +# Free Software Foundation; either version 2 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see <http://www.gnu.org/licenses/>. +# +# As a special exception, the respective Autoconf Macro's copyright owner +# gives unlimited permission to copy, distribute and modify the configure +# scripts that are the output of Autoconf when processing the Macro. You +# need not follow the terms of the GNU General Public License when using +# or distributing such scripts, even though portions of the text of the +# Macro appear in them. The GNU General Public License (GPL) does govern +# all other use of the material that constitutes the Autoconf Macro. +# +# This special exception to the GPL applies to versions of the Autoconf +# Macro released by the Autoconf Archive. When you make and distribute a +# modified version of the Autoconf Macro, you may extend this special +# exception to the GPL to apply to your modified version as well. + +#serial 9 + +AC_DEFUN([AX_PYTHON], +[AC_MSG_CHECKING(for python build information) +AC_MSG_RESULT([]) +for python in python3.3 python3.2 python3.1 python3.0 python2.7 python2.6 python2.5 python2.4 python2.3 python2.2 python2.1 python; do +AC_CHECK_PROGS(PYTHON_BIN, [$python]) +ax_python_bin=$PYTHON_BIN +if test x$ax_python_bin != x; then + AC_CHECK_LIB($ax_python_bin, main, ax_python_lib=$ax_python_bin, ax_python_lib=no) + AC_CHECK_HEADER([$ax_python_bin/Python.h], + [[ax_python_header=`locate $ax_python_bin/Python.h | sed -e s,/Python.h,,`]], + ax_python_header=no) + if test x$ax_python_lib != xno; then + if test x$ax_python_header != xno; then + break; + fi + fi +fi +done +if test x$ax_python_bin = x; then + ax_python_bin=no +fi +if test x$ax_python_header = x; then + ax_python_header=no +fi +if test x$ax_python_lib = x; then + ax_python_lib=no +fi + +AC_MSG_RESULT([ results of the Python check:]) +AC_MSG_RESULT([ Binary: $ax_python_bin]) +AC_MSG_RESULT([ Library: $ax_python_lib]) +AC_MSG_RESULT([ Include Dir: $ax_python_header]) + +if test x$ax_python_header != xno; then + PYTHON_INCLUDE_DIR=$ax_python_header + AC_SUBST(PYTHON_INCLUDE_DIR) +fi +if test x$ax_python_lib != xno; then + PYTHON_LIB=$ax_python_lib + AC_SUBST(PYTHON_LIB) +fi +])dnl diff --git a/doc/resolve-asciidoc-refs.py b/doc/resolve-asciidoc-refs.py new file mode 100755 index 00000000..54187473 --- /dev/null +++ b/doc/resolve-asciidoc-refs.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python + +import fileinput +import re +import sys + +refs = {} +complete_file = "" + +for line in open(sys.argv[1], 'r'): + complete_file += line + +for m in re.findall('\[\[(.+)\]\]\n=+ ([^\n]+)', complete_file): + ref, title = m + refs["<<" + ref + ">>"] = "<<" + ref + ", " + title + ">>" + +def translate(match): + try: + return refs[match.group(0)] + except KeyError: + return "" + +rc = re.compile('|'.join(map(re.escape, sorted(refs, reverse=True)))) +for line in open(sys.argv[1], 'r'): + print rc.sub(translate, line), diff --git a/doc/route.txt b/doc/route.txt new file mode 100644 index 00000000..d9f88e13 --- /dev/null +++ b/doc/route.txt @@ -0,0 +1,1889 @@ +//// + vim.syntax: asciidoc + + Copyright (c) 2011 Thomas Graf <tgraf@suug.ch> +//// + +Routing Family Netlink Library (libnl-route) +============================================ +Thomas Graf <tgraf@suug.ch> +3.1, Aug 11 2011: + +== Introduction + +This library provides APIs to the kernel interfaces of the routing family. + + +NOTE: Work in progress. + +== Addresses + +[[route_link]] +== Links (Network Devices) + +The link configuration interface is part of the +NETLINK_ROUTE+ protocol +family and implements the following netlink message types: + +- View and modify the configuration of physical and virtual network devices. +- Create and delete virtual network devices (e.g. dummy devices, VLAN devices, + tun devices, bridging devices, ...) +- View and modify per link network configuration settings (e.g. + +net.ipv6.conf.eth0.accept_ra+, +net.ipv4.conf.eth1.forwarding+, ...) + +.Naming Convention (network device, link, interface) + +In networking several terms are commonly used to refer to network devices. +While they have distinct meanings they have been used interchangeably in +the past. Within the Linux kernel, the term _network device_ or _netdev_ is +commonly used In user space the term _network interface_ is very common. +The routing netlink protocol uses the term _link_ and so does the _iproute2_ +utility and most routing daemons. + +=== Netlink Protocol + +This section describes the protocol semantics of the netlink based link +configuration interface. The following messages are defined: + +[options="header", cols="1,2,2"] +|============================================================================== +| Message Type | User -> Kernel | Kernel -> User +| +RTM_NEWLINK+ | Create or update virtual network device +| Reply to +RTM_GETLINK+ request or notification of link added or updated +| +RTM_DELLINK+ | Delete virtual network device +| Notification of link deleted or disappeared +| +RTM_GETLINK+ | Retrieve link configuration and statistics | +| +RTM_SETLINK+ | Modify link configuration | +|============================================================================== + +See link:core.html#core_msg_types[Netlink Library - Message Types] for more +information on common semantics of these message types. + +==== Link Message Format + +All netlink link messages share a common header (+struct ifinfomsg+) which +is appended after the netlink header (+struct nlmsghdr+). + +image:ifinfomsg.png["Link Message Header"] + +The meaning of each field may differ depending on the message type. A ++struct ifinfomsg+ is defined in +<linux/rtnetlink.h>+ to represent the +header. + +Address Family (8bit):: +The address family is usually set to +AF_UNSPEC+ but may be specified in ++RTM_GETLINK+ requests to limit the returned links to a specific address +family. + +Link Layer Type (16bit):: +Currently only used in kernel->user messages to report the link layer type +of a link. The value corresponds to the +ARPHRD_*+ defines found in ++<linux/if_arp.h>+. Translation from/to strings can be done using the +functions nl_llproto2str()/nl_str2llproto(). + +Link Index (32bit):: +Carries the interface index and is used to identify existing links. + +Flags (32bit):: +In kernel->user messages the value of this field represents the current +state of the link flags. In user->kernel messages this field is used to +change flags or set the initial flag state of new links. Note that in order +to change a flag, the flag must also be set in the _Flags Change Mask_ field. + +Flags Change Mask (32bit):: +The primary use of this field is to specify a mask of flags that should be +changed based on the value of the _Flags_ field. A special meaning is given +to this field when present in link notifications, see TODO. + +Attributes (variable):: +All link message types may carry netlink attributes. They are defined in the +header file <linux/if_link.h> and share the prefix +IFLA_+. + +==== Link Message Types + +.RTM_GETLINK (user->kernel) + +Lookup link by 1. interface index or 2. link name (+IFLA_IFNAME+) and return +a single +RTM_NEWLINK+ message containing the link configuration and statistics +or a netlink error message if no such link was found. + +*Parameters:* + +* *Address family* +** If the address family is set to +PF_BRIDGE+, only bridging devices will be + returned. +** If the address family is set to +PF_INET6+, only ipv6 enabled devices will + be returned. + +*Flags:* + +* +NLM_F_DUMP+ If set, all links will be returned in form of a multipart + message. + +*Returns:* + +* +EINVAL+ if neither interface nor link name are set +* +ENODEV+ if no link was found +* +ENOBUFS+ if allocation failed + +.RTM_NEWLINK (user->kernel) + +Creates a new or updates an existing link. Only virtual links may be created +but all links may be updated. + +*Flags:* + +- +NLM_F_CREATE+ Create link if it does not exist +- +NLM_F_EXCL+ Return +EEXIST+ if link already exists + +*Returns:* + +- +EINVAL+ malformed message or invalid configuration parameters +- +EAFNOSUPPORT+ if a address family specific configuration (+IFLA_AF_SPEC+) + is not supported. +- +EOPNOTSUPP+ if the link does not support modification of parameters +- +EEXIST+ if +NLM_F_EXCL+ was set and the link exists alraedy +- +ENODEV+ if the link does not exist and +NLM_F_CREATE+ is not set + +.RTM_NEWLINK (kernel->user) + +This message type is used in reply to a +RTM_GETLINK+ request and carries +the configuration and statistics of a link. If multiple links need to +be sent, the messages will be sent in form of a multipart message. + +The message type is also used for notifications sent by the kernel to the +multicast group +RTNLGRP_LINK+ to inform about various link events. It is +therefore recommended to always use a separate link socket for link +notifications in order to separate between the two message types. + +TODO: document how to detect different notifications + +.RTM_DELLINK (user->kernel) + +Lookup link by 1. interface index or 2. link name (+IFLA_IFNAME+) and delete +the virtual link. + +*Returns:* + +* +EINVAL+ if neither interface nor link name are set +* +ENODEV+ if no link was found +* +ENOTSUPP+ if the operation is not supported (not a virtual link) + +.RTM_DELLINK (kernel->user) + +Notification sent by the kernel to the multicast group +RTNLGRP_LINK+ when + +a. a network device was unregistered (change == ~0) +b. a bridging device was deleted (address family will be +PF_BRIDGE+) + +=== Get / List + +[[link_list]] +==== Get list of links + +To retrieve the list of links in the kernel, allocate a new link cache +using +rtnl_link_alloc_cache()+ to hold the links. It will automatically +construct and send a +RTM_GETLINK+ message requesting a dump of all links +from the kernel and feed the returned +RTM_NEWLINK+ to the internal link +message parser which adds the returned links to the cache. + +[source,c] +----- +#include <netlink/route/link.h> + +int rtnl_link_alloc_cache(struct nl_sock *sk, int family, struct nl_cache **result) +----- + +The cache will contain link objects (+struct rtnl_link+, see <<link_object>>) +and can be accessed using the standard cache functions. By setting the ++family+ parameter to an address familly other than +AF_UNSPEC+, the resulting +cache will only contain links supporting the specified address family. + +The following direct search functions are provided to search by interface +index and by link name: + +[source,c] +----- +#include <netlink/route/link.h> + +struct rtnl_link *rtnl_link_get(struct nl_cache *cache, int ifindex); +struct rtnl_link *rtnl_link_get_by_name(struct nl_cache *cache, const char *name); +----- + +.Example: Link Cache + +[source,c] +----- +struct nl_cache *cache; +struct rtnl_link *link; + +if (rtnl_link_alloc_cache(sock, AF_UNSPEC, &cache)) < 0) + /* error */ + +if (!(link = rtnl_link_get_by_name(cache, "eth1"))) + /* link does not exist */ + +/* do something with link */ + +rtnl_link_put(link); +nl_cache_put(cache); +----- + +[[link_direct_lookup]] +==== Lookup Single Link (Direct Lookup) + +If only a single link is of interest, the link can be looked up directly +without the use of a link cache using the function +rtnl_link_get_kernel()+. + +[source,c] +----- +#include <netlink/route/link.h> + +int rtnl_link_get_kernel(struct nl_sock *sk, int ifindex, const char *name, struct rtnl_link **result); +----- + +It will construct and send a +RTM_GETLINK+ request using the parameters +provided and wait for a +RTM_NEWLINK+ or netlink error message sent in +return. If the link exists, the link is returned as link object +(see <<link_object>>). + +.Example: Direct link lookup +[source,c] +----- +struct rtnl_link *link; + +if (rtnl_link_get_kernel(sock, 0, "eth1", &link) < 0) + /* error */ + +/* do something with link */ + +rtnl_link_put(link); +----- + +NOTE: While using this function can save a substantial amount of bandwidth + on the netlink socket, the result will not be cached, subsequent calls + to rtnl_link_get_kernel() will always trigger sending a +RTM_GETLINK+ + request. + +[[link_translate_ifindex]] +==== Translating interface index to link name + +Applications which require to translate interface index to a link name or +vice verase may use the following functions to do so. Both functions require +a filled link cache to work with. + +[source,c] +----- +char *rtnl_link_i2name (struct nl_cache *cache, int ifindex, char *dst, size_t len); +int rtnl_link_name2i (struct nl_cache *cache, const char *name); +----- + +=== Add / Modify + +Several types of virtual link can be added on the fly using the function ++rtnl_link_add()+. + +[source,c] +----- +#include <netlink/route/link.h> + +int rtnl_link_add(struct nl_sock *sk, struct rtnl_link *link, int flags); +----- + +=== Delete + +The deletion of virtual links such as VLAN devices or dummy devices is done +using the function +rtnl_link_delete()+. The link passed on to the function +can be a link from a link cache or it can be construct with the minimal +attributes needed to identify the link. + +[source,c] +----- +#include <netlink/route/link.h> + +int rtnl_link_delete(struct nl_sock *sk, const struct rtnl_link *link); +----- + +The function will construct and send a +RTM_DELLINK+ request message and +returns any errors returned by the kernel. + +.Example: Delete link by name +[source,c] +----- +struct rtnl_link *link; + +if (!(link = rtnl_link_alloc())) + /* error */ + +rtnl_link_set_name(link, "my_vlan"); + +if (rtnl_link_delete(sock, link) < 0) + /* error */ + +rtnl_link_put(link); +----- + +[[link_object]] +=== Link Object + +A link is represented by the structure +struct rtnl_link+. Instances may be +created with the function +rtnl_link_alloc()+ or via a link cache (see +<<link_list>>) and are freed again using the function +rtnl_link_put()+. + +[source,c] +----- +#include <netlink/route/link.h> + +struct rtnl_link *rtnl_link_alloc(void); +void rtnl_link_put(struct rtnl_link *link); +----- + +[[link_attr_name]] +==== Name +The name serves as unique, human readable description of the link. By +default, links are named based on their type and then enumerated, e.g. +eth0, eth1, ethn but they may be renamed at any time. + +Kernels >= 2.6.11 support identification by link name. + +[source,c] +----- +#include <netlink/route/link.h> + +void rtnl_link_set_name(struct rtnl_link *link, const char *name); +char *rtnl_link_get_name(struct rtnl_link *link); +----- + +*Accepted link name format:* +[^ /]*+ (maximum length: 15 characters) + +[[link_attr_ifindex]] +==== Interface Index (Identifier) +The interface index is an integer uniquely identifying a link. If present +in any link message, it will be used to identify an existing link. + +[source,c] +----- +#include <netlink/route/link.h> + +void rtnl_link_set_ifindex(struct rtnl_link *link, int ifindex); +int rtnl_link_get_ifindex(struct rtnl_link *link); +----- + +[[link_attr_group]] +==== Group +Each link can be assigned a numeric group identifier to group a bunch of links +together and apply a set of changes to a group instead of just a single link. + + +[source,c] +----- +#include <netlink/route/link.h> + +void rtnl_link_set_group(struct rtnl_link *link, uint32_t group); +uint32_t rtnl_link_get_group(struct rtnl_link *link); +----- + +[[link_attr_address]] +==== Link Layer Address +The link layer address (e.g. MAC address). + +[source,c] +----- +#include <netlink/route/link.h> + +void rtnl_link_set_addr(struct rtnl_link *link, struct nl_addr *addr); +struct nl_addr *rtnl_link_get_addr(struct rtnl_link *link); +----- + +[[link_attr_broadcast]] +==== Broadcast Address +The link layer broadcast address + +[source,c] +----- +#include <netlink/route/link.h> + +void rtnl_link_set_broadcast(struct rtnl_link *link, struct nl_addr *addr); +struct nl_addr *rtnl_link_get_broadcast(struct rtnl_link *link); +----- + +[[link_attr_mtu]] +==== MTU (Maximum Transmission Unit) +The maximum transmission unit specifies the maximum packet size a network +device can transmit or receive. This value may be lower than the capability +of the physical network device. + +[source,c] +----- +#include <netlink/route/link.h> + +void rtnl_link_set_mtu(struct rtnl_link *link, unsigned int mtu); +unsigned int rtnl_link_get_mtu(struct rtnl_link *link); +----- + +[[link_attr_flags]] +==== Flags +The flags of a link enable or disable various link features or inform about +the state of the link. + +[source,c] +----- +#include <netlink/route/link.h> + +void rtnl_link_set_flags(struct rtnl_link *link, unsigned int flags); +void rtnl_link_unset_flags(struct rtnl_link *link, unsigned int flags); +unsigned int rtnl_link_get_flags(struct rtnl_link *link); +----- + +[options="compact"] +[horizontal] +IFF_UP:: Link is up (administratively) +IFF_RUNNING:: Link is up and carrier is OK (RFC2863 OPER_UP) +IFF_LOWER_UP:: Link layer is operational +IFF_DORMANT:: Driver signals dormant +IFF_BROADCAST:: Link supports broadcasting +IFF_MULTICAST:: Link supports multicasting +IFF_ALLMULTI:: Link supports multicast routing +IFF_DEBUG:: Tell driver to do debugging (currently unused) +IFF_LOOPBACK:: Link loopback network +IFF_POINTOPOINT:: Point-to-point link +IFF_NOARP:: ARP is not supported +IFF_PROMISC:: Status of promiscious mode +IFF_MASTER:: Master of a load balancer (bonding) +IFF_SLAVE:: Slave to a master link +IFF_PORTSEL:: Driver supports setting media type (only used by ARM ethernet) +IFF_AUTOMEDIA:: Link selects port automatically (only used by ARM ethernet) +IFF_ECHO:: Echo sent packets (testing feature, CAN only) +IFF_DYNAMIC:: Unused (BSD compatibility) +IFF_NOTRAILERS:: Unused (BSD compatibility) + +To translate a link flag to a link flag name or vice versa: + +[source,c] +----- +#include <netlink/route/link.h> + +char *rtnl_link_flags2str(int flags, char *buf, size_t size); +int rtnl_link_str2flags(const char *flag_name); +----- + +[[link_attr_txqlen]] +==== Transmission Queue Length + +The transmission queue holds packets before packets are delivered to +the driver for transmission. It is usually specified in number of +packets but the unit may be specific to the link type. + +[source,c] +----- +#include <netlink/route/link.h> + +void rtnl_link_set_txqlen(struct rtnl_link *link, unsigned int txqlen); +unsigned int rtnl_link_get_txqlen(struct rtnl_link *link); +----- + +[[link_attr_operstate]] +==== Operational Status +The operational status has been introduced to provide extended information +on the link status. Traditionally the link state has been described using +the link flags +IFF_UP, IFF_RUNNING, IFF_LOWER_UP+, and +IFF_DORMANT+ which +was no longer sufficient for some link types. + +[source,c] +----- +#include <netlink/route/link.h> + +void rtnl_link_set_operstate(struct rtnl_link *link, uint8_t state); +uint8_t rtnl_link_get_operstate(struct rtnl_link *link); +----- + +[options="compact"] +[horizontal] +IF_OPER_UNKNOWN:: Unknown state +IF_OPER_NOTPRESENT:: Link not present +IF_OPER_DOWN:: Link down +IF_OPER_LOWERLAYERDOWN:: L1 down +IF_OPER_TESTING:: Testing +IF_OPER_DORMANT:: Dormant +IF_OPER_UP:: Link up + +Translation of operational status code to string and vice versa: + +[source,c] +----- +#include <netlink/route/link.h> + +char *rtnl_link_operstate2str(uint8_t state, char *buf, size_t size); +int rtnl_link_str2operstate(const char *name); +----- + +[[link_attr_mode]] +==== Mode +Currently known link modes are: + +[options="compact"] +[horizontal] +IF_LINK_MODE_DEFAULT:: Default link mode +IF_LINK_MODE_DORMANT:: Limit upward transition to dormant + +[source,c] +----- +#include <netlink/route/link.h> + +void rtnl_link_set_linkmode(struct rtnl_link *link, uint8_t mode); +uint8_t rtnl_link_get_linkmode(struct rtnl_link *link); +----- + +Translation of link mode to string and vice versa: + +[source,c] +----- +char *rtnl_link_mode2str(uint8_t mode, char *buf, size_t len); +uint8_t rtnl_link_str2mode(const char *name); +----- + +[[link_attr_alias]] +==== IfAlias +Alternative name for the link, primarly used for SNMP IfAlias. + +[source,c] +----- +#include <netlink/route/link.h> + +const char *rtnl_link_get_ifalias(struct rtnl_link *link); +void rtnl_link_set_ifalias(struct rtnl_link *link, const char *alias); +----- + +*Length limit:* 256 + +[[link_attr_arptype]] +==== Hardware Type + +[source,c] +----- +#include <netlink/route/link.h> +#include <linux/if_arp.h> + +void rtnl_link_set_arptype(struct rtnl_link *link, unsigned int arptype); +unsigned int rtnl_link_get_arptype(struct rtnl_link *link); +---- + +Translation of hardware type to character string and vice versa: + +[source,c] +----- +#include <netlink/utils.h> + +char *nl_llproto2str(int arptype, char *buf, size_t len); +int nl_str2llproto(const char *name); +----- + +[[link_attr_qdisc]] +==== Qdisc +The name of the queueing discipline used by the link is of informational +nature only. It is a read-only attribute provided by the kernel and cannot +be modified. The set function is provided solely for the purpose of creating +link objects to be used for comparison. + +For more information on how to modify the qdisc of a link, see section +<<route_tc>>. + +[source,c] +----- +#include <netlink/route/link.h> + +void rtnl_link_set_qdisc(struct rtnl_link *link, const char *name); +char *rtnl_link_get_qdisc(struct rtnl_link *link); +----- + +[[link_attr_promiscuity]] +==== Promiscuity +The number of subsystem currently depending on the link being promiscuous mode. +A value of 0 indicates that the link is not in promiscuous mode. It is a +read-only attribute provided by the kernel and cannot be modified. The set +function is provided solely for the purpose of creating link objects to be +used for comparison. + +[source,c] +----- +#include <netlink/route/link.h> + +void rtnl_link_set_promiscuity(struct rtnl_link *link, uint32_t count); +uint32_t rtnl_link_get_promiscuity(struct rtnl_link *link); +----- + +[[link_num_rxtx_queues]] +==== RX/TX Queues +The number of RX/TX queues the link provides. The attribute is writable but +will only be considered when creating a new network device via netlink. + +[source,c] +----- +#include <netlink/route/link.h> + +void rtnl_link_set_num_tx_queues(struct rtnl_link *link, uint32_t nqueues); +uint32_t rtnl_link_get_num_tx_queues(struct rtnl_link *link); + +void rtnl_link_set_num_rx_queues(struct rtnl_link *link, uint32_t nqueues); +uint32_t rtnl_link_get_num_rx_queues(struct rtnl_link *link); +----- + +[[link_attr_weight]] +==== Weight +This attribute is unused and obsoleted in all recent kernels. + + +[[link_modules]] +=== Modules + +[[link_bonding]] +==== Bonding + +.Example: Add bonding link +[source,c] +----- +#include <netlink/route/link.h> + +struct rtnl_link *link; + +link = rtnl_link_bond_alloc(); +rtnl_link_set_name(link, "my_bond"); + +/* requires admin privileges */ +if (rtnl_link_add(sk, link, NLM_F_CREATE) < 0) + /* error */ + +rtnl_link_put(link); +----- + +[[link_vlan]] +==== VLAN + +[source,c] +----- +extern char * rtnl_link_vlan_flags2str(int, char *, size_t); +extern int rtnl_link_vlan_str2flags(const char *); + +extern int rtnl_link_vlan_set_id(struct rtnl_link *, int); +extern int rtnl_link_vlan_get_id(struct rtnl_link *); + +extern int rtnl_link_vlan_set_flags(struct rtnl_link *, + unsigned int); +extern int rtnl_link_vlan_unset_flags(struct rtnl_link *, + unsigned int); +extern unsigned int rtnl_link_vlan_get_flags(struct rtnl_link *); + +extern int rtnl_link_vlan_set_ingress_map(struct rtnl_link *, + int, uint32_t); +extern uint32_t * rtnl_link_vlan_get_ingress_map(struct rtnl_link *); + +extern int rtnl_link_vlan_set_egress_map(struct rtnl_link *, + uint32_t, int); +extern struct vlan_map *rtnl_link_vlan_get_egress_map(struct rtnl_link *, + int *); +----- + +.Example: Add a VLAN device +[source,c] +----- +struct rtnl_link *link; +int master_index; + +/* lookup interface index of eth0 */ +if (!(master_index = rtnl_link_name2i(link_cache, "eth0"))) + /* error */ + +/* allocate new link object of type vlan */ +link = rtnl_link_vlan_alloc(); + +/* set eth0 to be our master device */ +rtnl_link_set_link(link, master_index); + +rtnl_link_vlan_set_id(link, 10); + +if ((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0) + /* error */ + +rtnl_link_put(link); +----- + +[[link_macvlan]] +==== MACVLAN + +[source,c] +----- +extern struct rtnl_link *rtnl_link_macvlan_alloc(void); + +extern int rtnl_link_is_macvlan(struct rtnl_link *); + +extern char * rtnl_link_macvlan_mode2str(int, char *, size_t); +extern int rtnl_link_macvlan_str2mode(const char *); + +extern char * rtnl_link_macvlan_flags2str(int, char *, size_t); +extern int rtnl_link_macvlan_str2flags(const char *); + +extern int rtnl_link_macvlan_set_mode(struct rtnl_link *, + uint32_t); +extern uint32_t rtnl_link_macvlan_get_mode(struct rtnl_link *); + +extern int rtnl_link_macvlan_set_flags(struct rtnl_link *, + uint16_t); +extern int rtnl_link_macvlan_unset_flags(struct rtnl_link *, + uint16_t); +extern uint16_t rtnl_link_macvlan_get_flags(struct rtnl_link *); +----- + +.Example: Add a MACVLAN device +[source,c] +----- +struct rtnl_link *link; +int master_index; +struct nl_addr* addr; + +/* lookup interface index of eth0 */ +if (!(master_index = rtnl_link_name2i(link_cache, "eth0"))) + /* error */ + +/* allocate new link object of type macvlan */ +link = rtnl_link_macvlan_alloc(); + +/* set eth0 to be our master device */ +rtnl_link_set_link(link, master_index); + +/* set address of virtual interface */ +addr = nl_addr_build(AF_LLC, ether_aton("00:11:22:33:44:55"), ETH_ALEN); +rtnl_link_set_addr(link, addr); +nl_addr_put(addr); + +/* set mode of virtual interface */ +rtnl_link_macvlan_set_mode(link, rtnl_link_macvlan_str2mode("bridge")); + +if ((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0) + /* error */ + +rtnl_link_put(link); +----- + +[[link_vxlan]] +==== VXLAN + +[source,c] +----- +extern struct rtnl_link *rtnl_link_vxlan_alloc(void); + +extern int rtnl_link_is_vxlan(struct rtnl_link *); + +extern int rtnl_link_vxlan_set_id(struct rtnl_link *, uint32_t); +extern int rtnl_link_vxlan_get_id(struct rtnl_link *, uint32_t *); + +extern int rtnl_link_vxlan_set_group(struct rtnl_link *, struct nl_addr *); +extern int rtnl_link_vxlan_get_group(struct rtnl_link *, struct nl_addr **); + +extern int rtnl_link_vxlan_set_link(struct rtnl_link *, uint32_t); +extern int rtnl_link_vxlan_get_link(struct rtnl_link *, uint32_t *); + +extern int rtnl_link_vxlan_set_local(struct rtnl_link *, struct nl_addr *); +extern int rtnl_link_vxlan_get_local(struct rtnl_link *, struct nl_addr **); + +extern int rtnl_link_vxlan_set_ttl(struct rtnl_link *, uint8_t); +extern int rtnl_link_vxlan_get_ttl(struct rtnl_link *); + +extern int rtnl_link_vxlan_set_tos(struct rtnl_link *, uint8_t); +extern int rtnl_link_vxlan_get_tos(struct rtnl_link *); + +extern int rtnl_link_vxlan_set_learning(struct rtnl_link *, uint8_t); +extern int rtnl_link_vxlan_get_learning(struct rtnl_link *); +extern int rtnl_link_vxlan_enable_learning(struct rtnl_link *); +extern int rtnl_link_vxlan_disable_learning(struct rtnl_link *); + +extern int rtnl_link_vxlan_set_ageing(struct rtnl_link *, uint32_t); +extern int rtnl_link_vxlan_get_ageing(struct rtnl_link *, uint32_t *); + +extern int rtnl_link_vxlan_set_limit(struct rtnl_link *, uint32_t); +extern int rtnl_link_vxlan_get_limit(struct rtnl_link *, uint32_t *); + +extern int rtnl_link_vxlan_set_port_range(struct rtnl_link *, + struct ifla_vxlan_port_range *); +extern int rtnl_link_vxlan_get_port_range(struct rtnl_link *, + struct ifla_vxlan_port_range *); + +extern int rtnl_link_vxlan_set_proxy(struct rtnl_link *, uint8_t); +extern int rtnl_link_vxlan_get_proxy(struct rtnl_link *); +extern int rtnl_link_vxlan_enable_proxy(struct rtnl_link *); +extern int rtnl_link_vxlan_disable_proxy(struct rtnl_link *); + +extern int rtnl_link_vxlan_set_rsc(struct rtnl_link *, uint8_t); +extern int rtnl_link_vxlan_get_rsc(struct rtnl_link *); +extern int rtnl_link_vxlan_enable_rsc(struct rtnl_link *); +extern int rtnl_link_vxlan_disable_rsc(struct rtnl_link *); + +extern int rtnl_link_vxlan_set_l2miss(struct rtnl_link *, uint8_t); +extern int rtnl_link_vxlan_get_l2miss(struct rtnl_link *); +extern int rtnl_link_vxlan_enable_l2miss(struct rtnl_link *); +extern int rtnl_link_vxlan_disable_l2miss(struct rtnl_link *); + +extern int rtnl_link_vxlan_set_l3miss(struct rtnl_link *, uint8_t); +extern int rtnl_link_vxlan_get_l3miss(struct rtnl_link *); +extern int rtnl_link_vxlan_enable_l3miss(struct rtnl_link *); +extern int rtnl_link_vxlan_disable_l3miss(struct rtnl_link *); +----- + +.Example: Add a VXLAN device +[source,c] +----- +struct rtnl_link *link; +struct nl_addr* addr; + +/* allocate new link object of type vxlan */ +link = rtnl_link_vxlan_alloc(); + +/* set interface name */ +rtnl_link_set_name(link, "vxlan128"); + +/* set VXLAN network identifier */ +if ((err = rtnl_link_vxlan_set_id(link, 128)) < 0) + /* error */ + +/* set multicast address to join */ +if ((err = nl_addr_parse("239.0.0.1", AF_INET, &addr)) < 0) + /* error */ + +if ((err = rtnl_link_set_group(link, addr)) < 0) + /* error */ + +nl_addr_put(addr); + +if ((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0) + /* error */ + +rtnl_link_put(link); +----- + +[[link_ipip]] +==== IPIP + +[source,c] +----- +extern struct rtnl_link *rtnl_link_ipip_alloc(void); +extern int rtnl_link_ipip_add(struct nl_sock *sk, const char *name); + +extern int rtnl_link_ipip_set_link(struct rtnl_link *link, uint32_t index); +extern uint32_t rtnl_link_ipip_get_link(struct rtnl_link *link); + +extern int rtnl_link_ipip_set_local(struct rtnl_link *link, uint32_t addr); +extern uint32_t rtnl_link_ipip_get_local(struct rtnl_link *link); + +extern int rtnl_link_ipip_set_remote(struct rtnl_link *link, uint32_t addr); +extern uint32_t rtnl_link_ipip_get_remote(struct rtnl_link *link); + +extern int rtnl_link_ipip_set_ttl(struct rtnl_link *link, uint8_t ttl); +extern uint8_t rtnl_link_ipip_get_ttl(struct rtnl_link *link); + +extern int rtnl_link_ipip_set_tos(struct rtnl_link *link, uint8_t tos); +extern uint8_t rtnl_link_ipip_get_tos(struct rtnl_link *link); + +extern int rtnl_link_ipip_set_pmtudisc(struct rtnl_link *link, uint8_t pmtudisc); +extern uint8_t rtnl_link_ipip_get_pmtudisc(struct rtnl_link *link); + +----- + +.Example: Add a ipip tunnel device +[source,c] +----- +struct rtnl_link *link +struct in_addr addr + +/* allocate new link object of type vxlan */ +if(!(link = rtnl_link_ipip_alloc())) + /* error */ + +/* set ipip tunnel name */ +if ((err = rtnl_link_set_name(link, "ipip-tun")) < 0) + /* error */ + +/* set link index */ +if ((err = rtnl_link_ipip_set_link(link, if_index)) < 0) + /* error */ + +/* set local address */ +inet_pton(AF_INET, "192.168.254.12", &addr.s_addr); +if ((err = rtnl_link_ipip_set_local(link, addr.s_addr)) < 0) + /* error */ + +/* set remote address */ +inet_pton(AF_INET, "192.168.254.13", &addr.s_addr +if ((err = rtnl_link_ipip_set_remote(link, addr.s_addr)) < 0) + /* error */ + +/* set tunnel ttl */ +if ((err = rtnl_link_ipip_set_ttl(link, 64)) < 0) + /* error */ + +if((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0) + /* error */ + +rtnl_link_put(link); +----- + +[[link_ipgre]] +==== IPGRE + +[source,c] +----- +extern struct rtnl_link *rtnl_link_ipgre_alloc(void); +extern int rtnl_link_ipgre_add(struct nl_sock *sk, const char *name); + +extern int rtnl_link_ipgre_set_link(struct rtnl_link *link, uint32_t index); +extern uint32_t rtnl_link_ipgre_get_link(struct rtnl_link *link); + +extern int rtnl_link_ipgre_set_iflags(struct rtnl_link *link, uint16_t iflags); +extern uint16_t rtnl_link_get_iflags(struct rtnl_link *link); + +extern int rtnl_link_ipgre_set_oflags(struct rtnl_link *link, uint16_t oflags); +extern uint16_t rtnl_link_get_oflags(struct rtnl_link *link); + +extern int rtnl_link_ipgre_set_ikey(struct rtnl_link *link, uint32_t ikey); +extern uint32_t rtnl_link_get_ikey(struct rtnl_link *link); + +extern int rtnl_link_ipgre_set_okey(struct rtnl_link *link, uint32_t okey); +extern uint32_t rtnl_link_get_okey(struct rtnl_link *link) + +extern int rtnl_link_ipgre_set_local(struct rtnl_link *link, uint32_t addr); +extern uint32_t rtnl_link_ipgre_get_local(struct rtnl_link *link); + +extern int rtnl_link_ipgre_set_remote(struct rtnl_link *link, uint32_t addr); +extern uint32_t rtnl_link_ipgre_get_remote(struct rtnl_link *link); + +extern int rtnl_link_ipgre_set_ttl(struct rtnl_link *link, uint8_t ttl); +extern uint8_t rtnl_link_ipgre_get_ttl(struct rtnl_link *link); + +extern int rtnl_link_ipgre_set_tos(struct rtnl_link *link, uint8_t tos); +extern uint8_t rtnl_link_ipgre_get_tos(struct rtnl_link *link); + +extern int rtnl_link_ipgre_set_pmtudisc(struct rtnl_link *link, uint8_t pmtudisc); +extern uint8_t rtnl_link_ipgre_get_pmtudisc(struct rtnl_link *link); + +----- + +.Example: Add a ipgre tunnel device +[source,c] +----- +struct rtnl_link *link +struct in_addr addr + +/* allocate new link object of type vxlan */ +if(!(link = rtnl_link_ipgre_alloc())) + /* error */ + +/* set ipgre tunnel name */ +if ((err = rtnl_link_set_name(link, "ipgre-tun")) < 0) + /* error */ + +/* set link index */ +if ((err = rtnl_link_ipgre_set_link(link, if_index)) < 0) + /* error */ + +/* set local address */ +inet_pton(AF_INET, "192.168.254.12", &addr.s_addr); +if ((err = rtnl_link_ipgre_set_local(link, addr.s_addr)) < 0) + /* error */ + +/* set remote address */ +inet_pton(AF_INET, "192.168.254.13", &addr.s_addr +if ((err = rtnl_link_ipgre_set_remote(link, addr.s_addr)) < 0) + /* error */ + +/* set tunnel ttl */ +if ((err = rtnl_link_ipgre_set_ttl(link, 64)) < 0) + /* error */ + +if((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0) + /* error */ + +rtnl_link_put(link); +----- + +[[link_sit]] +==== SIT + +[source,c] +----- +extern struct rtnl_link *rtnl_link_sit_alloc(void); +extern int rtnl_link_sit_add(struct nl_sock *sk, const char *name); + +extern int rtnl_link_sit_set_link(struct rtnl_link *link, uint32_t index); +extern uint32_t rtnl_link_sit_get_link(struct rtnl_link *link); + +extern int rtnl_link_sit_set_iflags(struct rtnl_link *link, uint16_t iflags); +extern uint16_t rtnl_link_get_iflags(struct rtnl_link *link); + +extern int rtnl_link_sit_set_oflags(struct rtnl_link *link, uint16_t oflags); +extern uint16_t rtnl_link_get_oflags(struct rtnl_link *link); + +extern int rtnl_link_sit_set_ikey(struct rtnl_link *link, uint32_t ikey); +extern uint32_t rtnl_link_get_ikey(struct rtnl_link *link); + +extern int rtnl_link_sit_set_okey(struct rtnl_link *link, uint32_t okey); +extern uint32_t rtnl_link_get_okey(struct rtnl_link *link) + +extern int rtnl_link_sit_set_local(struct rtnl_link *link, uint32_t addr); +extern uint32_t rtnl_link_sit_get_local(struct rtnl_link *link); + +extern int rtnl_link_sit_set_remote(struct rtnl_link *link, uint32_t addr); +extern uint32_t rtnl_link_sit_get_remote(struct rtnl_link *link); + +extern int rtnl_link_sit_set_ttl(struct rtnl_link *link, uint8_t ttl); +extern uint8_t rtnl_link_sit_get_ttl(struct rtnl_link *link); + +extern int rtnl_link_sit_set_tos(struct rtnl_link *link, uint8_t tos); +extern uint8_t rtnl_link_sit_get_tos(struct rtnl_link *link); + +extern int rtnl_link_sit_set_pmtudisc(struct rtnl_link *link, uint8_t pmtudisc); +extern uint8_t rtnl_link_sit_get_pmtudisc(struct rtnl_link *link); + +----- + +.Example: Add a sit tunnel device +[source,c] +----- +struct rtnl_link *link +struct in_addr addr + +/* allocate new link object of type vxlan */ +if(!(link = rtnl_link_sit_alloc())) + /* error */ + +/* set sit tunnel name */ +if ((err = rtnl_link_set_name(link, "sit-tun")) < 0) + /* error */ + +/* set link index */ +if ((err = rtnl_link_sit_set_link(link, if_index)) < 0) + /* error */ + +/* set local address */ +inet_pton(AF_INET, "192.168.254.12", &addr.s_addr); +if ((err = rtnl_link_sit_set_local(link, addr.s_addr)) < 0) + /* error */ + +/* set remote address */ +inet_pton(AF_INET, "192.168.254.13", &addr.s_addr +if ((err = rtnl_link_sit_set_remote(link, addr.s_addr)) < 0) + /* error */ + +/* set tunnel ttl */ +if ((err = rtnl_link_sit_set_ttl(link, 64)) < 0) + /* error */ + +if((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0) + /* error */ + +rtnl_link_put(link); +----- + + +[[link_ipvti]] +==== IPVTI + +[source,c] +----- +extern struct rtnl_link *rtnl_link_ipvti_alloc(void); +extern int rtnl_link_ipvti_add(struct nl_sock *sk, const char *name); + +extern int rtnl_link_ipvti_set_link(struct rtnl_link *link, uint32_t index); +extern uint32_t rtnl_link_ipvti_get_link(struct rtnl_link *link); + +extern int rtnl_link_ipvti_set_ikey(struct rtnl_link *link, uint32_t ikey); +extern uint32_t rtnl_link_get_ikey(struct rtnl_link *link); + +extern int rtnl_link_ipvti_set_okey(struct rtnl_link *link, uint32_t okey); +extern uint32_t rtnl_link_get_okey(struct rtnl_link *link) + +extern int rtnl_link_ipvti_set_local(struct rtnl_link *link, uint32_t addr); +extern uint32_t rtnl_link_ipvti_get_local(struct rtnl_link *link); + +extern int rtnl_link_ipvti_set_remote(struct rtnl_link *link, uint32_t addr); +extern uint32_t rtnl_link_ipvti_get_remote(struct rtnl_link *link); + +----- + +.Example: Add a ipvti tunnel device +[source,c] +----- +struct rtnl_link *link +struct in_addr addr + +/* allocate new link object of type vxlan */ +if(!(link = rtnl_link_ipvti_alloc())) + /* error */ + +/* set ipvti tunnel name */ +if ((err = rtnl_link_set_name(link, "ipvti-tun")) < 0) + /* error */ + +/* set link index */ +if ((err = rtnl_link_ipvti_set_link(link, if_index)) < 0) + /* error */ + +/* set local address */ +inet_pton(AF_INET, "192.168.254.12", &addr.s_addr); +if ((err = rtnl_link_ipvti_set_local(link, addr.s_addr)) < 0) + /* error */ + +/* set remote address */ +inet_pton(AF_INET, "192.168.254.13", &addr.s_addr +if ((err = rtnl_link_ipvti_set_remote(link, addr.s_addr)) < 0) + /* error */ + +if((err = rtnl_link_add(sk, link, NLM_F_CREATE)) < 0) + /* error */ + +rtnl_link_put(link); +----- + +[[link_ip6tnl]] +==== IP6TNL + +[source,c] +----- +extern struct rtnl_link *rtnl_link_ip6_tnl_alloc(void); +extern int rtnl_link_ip6_tnl_add(struct nl_sock *sk, const char *name); + +extern int rtnl_link_ip6_tnl_set_link(struct rtnl_link *link, uint32_t index); +extern uint32_t rtnl_link_ip6_tnl_get_link(struct rtnl_link *link); + +extern int rtnl_link_ip6_tnl_set_local(struct rtnl_link *link, struct in6_addr *); +extern int rtnl_link_ip6_tnl_get_local(struct rtnl_link *link, struct in6_addr *); + +extern int rtnl_link_ip6_tnl_set_remote(struct rtnl_link *link, struct in6_addr *); +extern int rtnl_link_ip6_tnl_get_remote(struct rtnl_link *link, struct in6_addr *); + +extern int rtnl_link_ip6_tnl_set_ttl(struct rtnl_link *link, uint8_t ttl); +extern uint8_t rtnl_link_ip6_tnl_get_ttl(struct rtnl_link *link); + +extern int rtnl_link_ip6_tnl_set_tos(struct rtnl_link *link, uint8_t tos); +extern uint8_t rtnl_link_ip6_tnl_get_tos(struct rtnl_link *link); + +extern int rtnl_link_ip6_tnl_set_encaplimit(struct rtnl_link *link, uint8_t encap_limit); +extern uint8_t rtnl_link_ip6_tnl_get_encaplimit(struct rtnl_link *link); + +extern int rtnl_link_ip6_tnl_set_flags(struct rtnl_link *link, uint32_t flags); +extern uint32_t rtnl_link_ip6_tnl_get_flags(struct rtnl_link *link); + +extern uint32_t rtnl_link_ip6_tnl_get_flowinfo(struct rtnl_link *link); +extern int rtnl_link_ip6_tnl_set_flowinfo(struct rtnl_link *link, uint32_t flowinfo); + +extern int rtnl_link_ip6_tnl_set_proto(struct rtnl_link *link, uint8_t proto); +extern uint8_t rtnl_link_ip6_tnl_get_proto(struct rtnl_link *link); + +----- + +.Example: Add a ip6tnl tunnel device +[source,c] +----- +struct rtnl_link *link +struct in6_addr addr + +link = rtnl_link_ip6_tnl_alloc(); + +rtnl_link_set_name(link, "ip6tnl-tun"); +rtnl_link_ip6_tnl_set_link(link, if_index); + +inet_pton(AF_INET6, "2607:f0d0:1002:51::4", &addr); +rtnl_link_ip6_tnl_set_local(link, &addr); + +inet_pton(AF_INET6, "2607:f0d0:1002:52::5", &addr); +rtnl_link_ip6_tnl_set_remote(link, &addr); + +rtnl_link_add(sk, link, NLM_F_CREATE); +rtnl_link_put(link); + +----- + + +== Neighbouring + +== Routing + +[[route_tc]] +== Traffic Control + +The traffic control architecture allows the queueing and +prioritization of packets before they are enqueued to the network +driver. To a limited degree it is also possible to take control of +network traffic as it enters the network stack. + +The architecture consists of three different types of modules: + +- *Queueing disciplines (qdisc)* provide a mechanism to enqueue packets + in different forms. They may be used to implement fair queueing, + prioritization of differentiated services, enforce bandwidth + limitations, or even to simulate network behaviour such as packet + loss and packet delay. Qdiscs can be classful in which case they + allow traffic classes described in the next paragraph to be attached + to them. + +- *Traffic classes (class)* are supported by several qdiscs to build + a tree structure for different types of traffic. Each class may be + assigned its own set of attributes such as bandwidth limits or + queueing priorities. Some qdiscs even allow borrowing of bandwidth + between classes. + +- *Classifiers (cls)* are used to decide which qdisc/class the packet + should be enqueued to. Different types of classifiers exists, + ranging from classification based on protocol header values to + classification based on packet priority or firewall marks. + Additionally most classifiers support *extended matches (ematch)* + which allow extending classifiers by a set of matcher modules, and + *actions* which allow classifiers to take actions such as mangling, + mirroring, or even rerouting of packets. + +.Default Qdisc + +The default qdisc used on all network devices is `pfifo_fast`. +Network devices which do not require a transmit queue such as the +loopback device do not have a default qdisc attached. The `pfifo_fast` +qdisc provides three bands to prioritize interactive traffic over bulk +traffic. Classification is based on the packet priority (diffserv). + +image:qdisc_default.png["Default Qdisc"] + +.Multiqueue Default Qdisc + +If the network device provides multiple transmit queues the `mq` +qdisc is used by default. It will automatically create a separate +class for each transmit queue available and will also replace +the single per device tx lock with a per queue lock. + +image:qdisc_mq.png["Multiqueue default Qdisc"] + +.Example of a customized classful qdisc setup + +The following figure illustrates a possible combination of different +queueing and classification modules to implement quality of service +needs. + +image:tc_overview.png["Classful Qdisc diagram"] + +=== Traffic Control Object + +Each type traffic control module (qdisc, class, classifier) is +represented by its own structure. All of them are based on the traffic +control object represented by `struct rtnl_tc` which itself is based +on the generic object `struct nl_object` to make it cacheable. The +traffic control object contains all attributes, implementation details +and statistics that are shared by all of the traffic control object +types. + +image:tc_obj.png["struct rtnl_tc hierarchy"] + +It is not possible to allocate a `struct rtnl_tc` object, instead the +actual tc object types must be allocated directly using +`rtnl_qdisc_alloc()`, `rtnl_class_alloc()`, `rtnl_cls_alloc()` and +then casted to `struct rtnl_tc` using the `TC_CAST()` macro. + +.Usage Example: Allocation, Casting, Freeing +[source,c] +----- +#include <netlink/route/tc.h> +#include <netlink/route/qdisc.h> + +struct rtnl_qdisc *qdisc; + +/* Allocation of a qdisc object */ +qdisc = rtnl_qdisc_alloc(); + +/* Cast the qdisc to a tc object using TC_CAST() to use rtnl_tc_ functions. */ +rtnl_tc_set_mpu(TC_CAST(qdisc), 64); + +/* Free the qdisc object */ +rtnl_qdisc_put(qdisc); +----- + +[[tc_attr]] +==== Attributes + +Handle:: +The handle uniquely identifies a tc object and is used to refer +to other tc objects when constructing tc trees. ++ +[source,c] +----- +void rtnl_tc_set_handle(struct rtnl_tc *tc, uint32_t handle); +uint32_t rtnl_tc_get_handle(struct rtnl_tc *tc); +----- + +Interface Index:: +The interface index specifies the network device the traffic object +is attached to. The function `rtnl_tc_set_link()` should be preferred +when setting the interface index. It stores the reference to the link +object in the tc object and allows retrieving the `mtu` and `linktype` +automatically. ++ +[source,c] +----- +void rtnl_tc_set_ifindex(struct rtnl_tc *tc, int ifindex); +void rtnl_tc_set_link(struct rtnl_tc *tc, struct rtnl_link *link); +int rtnl_tc_get_ifindex(struct rtnl_tc *tc); +----- + +Link Type:: +The link type specifies the kind of link that is used by the network +device (e.g. ethernet, ATM, ...). It is derived automatically when +the network device is specified with `rtnl_tc_set_link()`. +The default fallback is `ARPHRD_ETHER` (ethernet). ++ +[source,c] +----- +void rtnl_tc_set_linktype(struct rtnl_tc *tc, uint32_t type); +uint32_t rtnl_tc_get_linktype(struct rtnl_tc *tc); +----- + +Kind:: +The kind character string specifies the type of qdisc, class, +classifier. Setting the kind results in the module specific +structure being allocated. Therefore it is imperative to call +`rtnl_tc_set_kind()` before using any type specific API functions +such as `rtnl_htb_set_rate()`. ++ +[source,c] +----- +int rtnl_tc_set_kind(struct rtnl_tc *tc, const char *kind); +char *rtnl_tc_get_kind(struct rtnl_tc *tc); +----- + +MPU:: +The Minimum Packet Unit specifies the minimum packet size which will +be transmitted +ever be seen by this traffic control object. This value is used for +rate calculations. Not all object implementations will make use of +this value. The default value is 0. ++ +[source,c] +----- +void rtnl_tc_set_mpu(struct rtnl_tc *tc, uint32_t mpu); +uint32_t rtnl_tc_get_mpu(struct rtnl_tc *tc); +----- + +MTU:: +The Maximum Transmission Unit specifies the maximum packet size which +will be transmitted. The value is derived from the link specified +with `rtnl_tc_set_link()` if not overwritten with `rtnl_tc_set_mtu()`. +If no link and MTU is specified, the value defaults to 1500 +(ethernet). ++ +[source,c] +----- +void rtnl_tc_set_mtu(struct rtnl_tc *tc, uint32_t mtu); +uint32_t rtnl_tc_get_mtu(struct rtnl_tc *tc); +----- + +Overhead:: +The overhead specifies the additional overhead per packet caused by +the network layer. This value can be used to correct packet size +calculations if the packet size on the wire does not match the packet +size seen by the kernel. The default value is 0. ++ +[source,c] +----- +void rtnl_tc_set_overhead(struct rtnl_tc *tc, uint32_t overhead); +uint32_t rtnl_tc_get_overhead(struct rtnl_tc *tc); +----- + +Parent:: +Specifies the parent traffic control object. The parent is identifier +by its handle. Special values are: +- `TC_H_ROOT`: attach tc object directly to network device (root + qdisc, root classifier) +- `TC_H_INGRESS`: same as `TC_H_ROOT` but on the ingress side of the + network stack. ++ +[source,c] +----- +void rtnl_tc_set_parent(struct rtnl_tc *tc, uint32_t parent); +uint32_t rtnl_tc_get_parent(struct rtnl_tc *tc); +----- + +Statistics:: +Generic statistics, see <<tc_stats>> for additional information. ++ +[source,c] +----- +uint64_t rtnl_tc_get_stat(struct rtnl_tc *tc, enum rtnl_tc_stat id); +----- + +[[tc_stats]] +==== Accessing Statistics + +The traffic control object holds a set of generic statistics. Not all +traffic control modules will make use of all of these statistics. Some +modules may provide additional statistics via their own APIs. + +.Statistic identifiers `(enum rtnl_tc_stat)` +[cols="m,,", options="header", frame="topbot"] +|==================================================================== +| ID | Type | Description +| RTNL_TC_PACKETS | Counter | Total # of packets transmitted +| RTNL_TC_BYTES | Counter | Total # of bytes transmitted +| RTNL_TC_RATE_BPS | Rate | Current bytes/s rate +| RTNL_TC_RATE_PPS | Rate | Current packets/s rate +| RTNL_TC_QLEN | Rate | Current length of the queue +| RTNL_TC_BACKLOG | Rate | # of packets currently backloged +| RTNL_TC_DROPS | Counter | # of packets dropped +| RTNL_TC_REQUEUES | Counter | # of packets requeued +| RTNL_TC_OVERLIMITS | Counter | # of packets that exceeded the limit +|==================================================================== + +NOTE: `RTNL_TC_RATE_BPS` and `RTNL_TC_RATE_PPS` only return meaningful + values if a rate estimator has been configured. + +.Usage Example: Retrieving tc statistics +[source,c] +------- +#include <netlink/route/tc.h> + +uint64_t drops, qlen; + +drops = rtnl_tc_get_stat(TC_CAST(qdisc), RTNL_TC_DROPS); +qlen = rtnl_tc_get_stat(TC_CAST(qdisc), RTNL_TC_QLEN); +------- + +==== Rate Table Calculations + +[[tc_qdisc]] +=== Queueing Discipline (qdisc) + +.Classless Qdisc + +The queueing discipline (qdisc) is used to implement fair queueing, +priorization or rate control. It provides a _enqueue()_ and +_dequeue()_ operation. Whenever a network packet leaves the networking +stack over a network device, be it a physical or virtual device, it +will be enqueued to a qdisc unless the device is queueless. The +_enqueue()_ operation is followed by an immediate call to _dequeue()_ +for the same qdisc to eventually retrieve a packet which can be +scheduled for transmission by the driver. Additionally, the networking +stack runs a watchdog which polls the qdisc regularly to dequeue and +send packets even if no new packets are being enqueued. + +This additional watchdog is required due to the fact that qdiscs may +hold on to packets and not return any packets upon _dequeue()_ in +order to enforce bandwidth restrictions. + +image:classless_qdisc_nbands.png[alt="Multiband Qdisc", float="right"] + +The figure illustrates a trivial example of a classless qdisc +consisting of three bands (queues). Use of multiple bands is a common +technique in qdiscs to implement fair queueing between flows or +prioritize differentiated services. + +Classless qdiscs can be regarded as a blackbox, their inner workings +can only be steered using the configuration parameters provided by the +qdisc. There is no way of taking influence on the structure of its +internal queues itself. + +.Classful Qdisc + +Classful qdiscs allow for the queueing structure and classification +process to be created by the user. + +image:classful_qdisc.png["Classful Qdisc"] + +The figure above shows a classful qdisc with a classifier attached to +it which will make the decision whether to enqueue a packet to traffic +class +1:1+ or +1:2+. Unlike with classless qdiscs, classful qdiscs +allow the classification process and the structure of the queues to be +defined by the user. This allows for complex traffic class rules to +be applied. + +.List of Qdisc Implementations +[options="header", frame="topbot", cols="2,1^,8"] +|====================================================================== +| Qdisc | Classful | Description +| ATM | Yes | FIXME +| Blackhole | No | This qdisc will drop all packets passed to it. +| CBQ | Yes | +The CBQ (Class Based Queueing) is a classful qdisc which allows +creating traffic classes and enforce bandwidth limitations for each +class. +| DRR | Yes | +The DRR (Deficit Round Robin) scheduler is a classful qdisc +impelemting fair queueing. Each class is assigned a quantum specyfing +the maximum number of bytes that can be served per round. Unused +quantum at the end of the round is carried over to the next round. +| DSMARK | Yes | FIXME +| FIFO | No | FIXME +| GRED | No | FIXME +| HFSC | Yes | FIXME +| HTB | Yes | FIXME +| mq | Yes | FIXME +| multiq | Yes | FIXME +| netem | No | FIXME +| Prio | Yes | FIXME +| RED | Yes | FIXME +| SFQ | Yes | FIXME +| TBF | Yes | FIXME +| teql | No | FIXME +|====================================================================== + + +.QDisc API Overview +[cols="a,a", options="header", frame="topbot"] +|==================================================================== +| Attribute | C Interface +| +Allocation / Freeing:: +| +[source,c] +----- +struct rtnl_qdisc *rtnl_qdisc_alloc(void); +void rtnl_qdisc_put(struct rtnl_qdisc *qdisc); +----- +| +Addition:: +| +[source,c] +----- +int rtnl_qdisc_build_add_request(struct rtnl_qdisc *qdisc, int flags, + struct nl_msg **result); +int rtnl_qdisc_add(struct nl_sock *sock, struct rtnl_qdisc *qdisc, + int flags); +----- +| +Modification:: +| +[source,c] +----- +int rtnl_qdisc_build_change_request(struct rtnl_qdisc *old, + struct rtnl_qdisc *new, + struct nl_msg **result); +int rtnl_qdisc_change(struct nl_sock *sock, struct rtnl_qdisc *old, + struct rtnl_qdisc *new); +----- +| +Deletion:: +| +[source,c] +----- +int rtnl_qdisc_build_delete_request(struct rtnl_qdisc *qdisc, + struct nl_msg **result); +int rtnl_qdisc_delete(struct nl_sock *sock, struct rtnl_qdisc *qdisc); +----- +| +Cache:: +| +[source,c] +----- +int rtnl_qdisc_alloc_cache(struct nl_sock *sock, + struct nl_cache **cache); +struct rtnl_qdisc *rtnl_qdisc_get(struct nl_cache *cache, int, uint32_t); + +struct rtnl_qdisc *rtnl_qdisc_get_by_parent(struct nl_cache *, int, uint32_t); +----- +|==================================================================== + +[[qdisc_get]] +==== Retrieving Qdisc Configuration + +The function rtnl_qdisc_alloc_cache() is used to retrieve the current +qdisc configuration in the kernel. It will construct a +RTM_GETQDISC+ +netlink message, requesting the complete list of qdiscs configured in +the kernel. + +[source,c] +------- +#include <netlink/route/qdisc.h> + +struct nl_cache *all_qdiscs; + +if (rtnl_link_alloc_cache(sock, &all_qdiscs) < 0) + /* error while retrieving qdisc cfg */ +------- + +The cache can be accessed using the following functions: + +- Search qdisc with matching ifindex and handle: ++ +[source,c] +-------- +struct rtnl_qdisc *rtnl_qdisc_get(struct nl_cache *cache, int ifindex, uint32_t handle); +-------- +- Search qdisc with matching ifindex and parent: ++ +[source,c] +-------- +struct rtnl_qdisc *rtnl_qdisc_get_by_parent(struct nl_cache *cache, int ifindex , uint32_t parent); +-------- +- Or any of the generic cache functions (e.g. nl_cache_search(), nl_cache_dump(), etc.) + +.Example: Search and print qdisc +[source,c] +------- +struct rtnl_qdisc *qdisc; +int ifindex; + +ifindex = rtnl_link_get_ifindex(eth0_obj); + +/* search for qdisc on eth0 with handle 1:0 */ +if (!(qdisc = rtnl_qdisc_get(all_qdiscs, ifindex, TC_HANDLE(1, 0)))) + /* no such qdisc found */ + +nl_object_dump(OBJ_CAST(qdisc), NULL); + +rtnl_qdisc_put(qdisc); +------- + +[[qdisc_add]] +==== Adding a Qdisc + +In order to add a new qdisc to the kernel, a qdisc object needs to be +allocated. It will hold all attributes of the new qdisc. + +[source,c] +----- +#include <netlink/route/qdisc.h> + +struct rtnl_qdisc *qdisc; + +if (!(qdisc = rtnl_qdisc_alloc())) + /* OOM error */ +----- + +The next step is to specify all generic qdisc attributes using the tc +object interface described in the section <<tc_attr>>. + +The following attributes must be specified: +- IfIndex +- Parent +- Kind + +[source,c] +----- +/* Attach qdisc to device eth0 */ +rtnl_tc_set_link(TC_CAST(qdisc), eth0_obj); + +/* Make this the root qdisc */ +rtnl_tc_set_parent(TC_CAST(qdisc), TC_H_ROOT); + +/* Set qdisc identifier to 1:0, if left unspecified, a handle will be generated by the kernel. */ +rtnl_tc_set_handle(TC_CAST(qdisc), TC_HANDLE(1, 0)); + +/* Make this a HTB qdisc */ +rtnl_tc_set_kind(TC_CAST(qdisc), "htb"); +----- + +After specyfing the qdisc kind (rtnl_tc_set_kind()) the qdisc type +specific interface can be used to set attributes which are specific +to the respective qdisc implementations: + +[source,c] +------ +/* HTB feature: Make unclassified packets go to traffic class 1:5 */ +rtnl_htb_set_defcls(qdisc, TC_HANDLE(1, 5)); +------ + +Finally, the qdisc is ready to be added and can be passed on to the +function rntl_qdisc_add() which takes care of constructing a netlink +message requesting the addition of the new qdisc, sends the message to +the kernel and waits for the response by the kernel. The function +returns 0 if the qdisc has been added or updated successfully or a +negative error code if an error occured. + +CAUTION: The kernel operation for updating and adding a qdisc is the + same. Therefore when calling rtnl_qdisc_add() any existing + qdisc with matching handle will be updated unless the flag + NLM_F_EXCL is specified. + +The following flags may be specified: +[horizontal] +NLM_F_CREATE:: Create qdisc if it does not exist, otherwise + -NLE_OBJ_NOTFOUND is returned. +NLM_F_REPLACE:: If another qdisc is already attached to the same + parent and their handles mismatch, replace the qdisc + instead of returning -EEXIST. +NLM_F_EXCL:: Return -NLE_EXISTS if a qdisc with matching handles + exists already. + +WARNING: The function rtnl_qdisc_add() requires administrator + privileges. + +[source,c] +------ +/* Submit request to kernel and wait for response */ +err = rtnl_qdisc_add(sock, qdisc, NLM_F_CREATE); + +/* Return the qdisc object to free memory resources */ +rtnl_qdisc_put(qdisc); + +if (err < 0) { + fprintf(stderr, "Unable to add qdisc: %s\n", nl_geterror(err)); + return err; +} +------ + +==== Deleting a qdisc + +[source,c] +------ +#include <netlink/route/qdisc.h> + +struct rtnl_qdisc *qdisc; + +qdisc = rtnl_qdisc_alloc(); + +rtnl_tc_set_link(TC_CAST(qdisc), eth0_obj); +rtnl_tc_set_parent(TC_CAST(qdisc), TC_H_ROOT); + +rtnl_qdisc_delete(sock, qdisc) + +rtnl_qdisc_put(qdisc); +------ + +WARNING: The function rtnl_qdisc_delete() requires administrator + privileges. + + +[[qdisc_htb]] +==== HTB - Hierarchical Token Bucket + +.HTB Qdisc Attributes + +Default Class:: +The default class is the fallback class to which all traffic which +remained unclassified is directed to. If no default class or an +invalid default class is specified, packets are transmitted directly +to the next layer (direct transmissions). ++ +[source,c] +----- +uint32_t rtnl_htb_get_defcls(struct rtnl_qdisc *qdisc); +int rtnl_htb_set_defcls(struct rtnl_qdisc *qdisc, uint32_t defcls); +----- + +Rate to Quantum (r2q):: +TODO ++ +[source,c] +----- +uint32_t rtnl_htb_get_rate2quantum(struct rtnl_qdisc *qdisc); +int rtnl_htb_set_rate2quantum(struct rtnl_qdisc *qdisc, uint32_t rate2quantum); +----- + + +.HTB Class Attributes + +Priority:: ++ +[source,c] +----- +uint32_t rtnl_htb_get_prio(struct rtnl_class *class); +int rtnl_htb_set_prio(struct rtnl_class *class, uint32_t prio); +----- + +Rate:: +The rate (bytes/s) specifies the maximum bandwidth an invidivual class +can use without borrowing. The rate of a class should always be greater +or erqual than the rate of its children. ++ +[source,c] +----- +uint32_t rtnl_htb_get_rate(struct rtnl_class *class); +int rtnl_htb_set_rate(struct rtnl_class *class, uint32_t ceil); +----- + +Ceil Rate:: +The ceil rate specifies the maximum bandwidth an invidivual class +can use. This includes bandwidth that is being borrowed from other +classes. Ceil defaults to the class rate implying that by default +the class will not borrow. The ceil rate of a class should always +be greater or erqual than the ceil rate of its children. ++ +[source,c] +----- +uint32_t rtnl_htb_get_ceil(struct rtnl_class *class); +int rtnl_htb_set_ceil(struct rtnl_class *class, uint32_t ceil); +----- + +Burst:: +TODO ++ +[source,c] +----- +uint32_t rtnl_htb_get_rbuffer(struct rtnl_class *class); +int rtnl_htb_set_rbuffer(struct rtnl_class *class, uint32_t burst); +----- + +Ceil Burst:: +TODO ++ +[source,c] +----- +uint32_t rtnl_htb_get_bbuffer(struct rtnl_class *class); +int rtnl_htb_set_bbuffer(struct rtnl_class *class, uint32_t burst); +----- + +Quantum:: +TODO ++ +[source,c] +----- +int rtnl_htb_set_quantum(struct rtnl_class *class, uint32_t quantum); +----- + +extern int rtnl_htb_set_cbuffer(struct rtnl_class *, uint32_t); + + + + +[[tc_class]] +=== Class + +[options="header", cols="s,a,a,a,a"] +|======================================================================= +| | UNSPEC | TC_H_ROOT | 0:pY | pX:pY +| UNSPEC 3+^| +[horizontal] +qdisc =:: root-qdisc +class =:: root-qdisc:0 +| +[horizontal] +qdisc =:: pX:0 +class =:: pX:0 +| 0:hY 3+^| +[horizontal] +qdisc =:: root-qdisc +class =:: root-qdisc:hY +| +[horizontal] +qdisc =:: pX:0 +class =:: pX:hY +| hX:hY 3+^| +[horizontal] +qdisc =:: hX: +class =:: hX:hY +| +if pX != hX + return -EINVAL +[horizontal] +qdisc =:: hX: +class =:: hX:hY +|======================================================================= + +[[tc_cls]] +=== Classifier (cls) + +TODO + +[[tc_classid_mngt]] +=== ClassID Management + +TODO + +[[tc_pktloc]] +=== Packet Location Aliasing (pktloc) + +TODO + +[[tc_api]] +=== Traffic Control Module API + +TODO diff --git a/doc/src/hidden.c b/doc/src/hidden.c new file mode 100644 index 00000000..a63621d7 --- /dev/null +++ b/doc/src/hidden.c @@ -0,0 +1,42 @@ +/** + * \cond skip + * vim:syntax=doxygen + * \endcond + +\page auto_ack_warning Disabling Auto-ACK + +\attention Disabling Auto-ACK (nl_socket_disable_auto_ack()) will cause this + function to return immediately after sending the netlink message. + The function will not wait for an eventual error message. It is + the responsibility of the caller to handle any error messages or + ACKs returned. + +\page pointer_lifetime_warning Pointer Lifetime + +\attention The reference counter of the returned object is not incremented. + Therefore, the returned pointer is only valid during the lifetime + of the parent object. Increment the reference counter if the object + is supposed to stay around after the parent object was freed. + +\page private_struct Private Structure + +\note The definition of this structure is private to allow modification + without breaking API. Use the designated accessor functions to + access individual object attributes. + +\page read_only_attribute Read-Only Attribute + +\note The attribute this accessor is modifying is a read-only attribute + which can not be modified in the kernel. Any changes to the + attribute only have an effect on the local copy of the object. The + accessor function is provided solely for the purpose of creating + objects for comparison and filtering. + +\page low_level_api Low Level API + +\note This is a low level API function. A high level function implementing + the same functionality with a simplified usage pattern exists. This + function is available as an alternative if the default library + behaviour is not desirable. + +*/ diff --git a/doc/src/toc.c b/doc/src/toc.c new file mode 100644 index 00000000..a91c2a71 --- /dev/null +++ b/doc/src/toc.c @@ -0,0 +1,54 @@ +/** + * \cond skip + * vim:syntax=doxygen + * \endcond + +\mainpage + +\section main_intro Introduction + +libnl is a set of libraries to deal with the netlink protocol and some +of the high level protocols implemented on top of it. The goal is to +provide APIs on different levels of abstraction. The core library libnl +provides a fundamental set of functions to deal with sockets, construct +messages, and send/receive those messages. Additional high level interfaces +for several individual netlink protocols are provided in separate +libraries (e.g. "nl-route", "nl-genl", ...). + +The library is designed to ensure that all components are optional, i.e. +even though the core library provides a caching system which allows to +easly manage objects of any kind, no application is required to use this +caching system if it has no need for it. + +The library was developed and tested on 2.6.x and 3.x kernel releases. It +may or may not work with older kernel series. Also, although all netlink +protocols are required to maintain backwards compatibility, this has not +always achieved and undesired side effects can occur if a recent libnl +version is used with a considerably older kernel. + +\section main_toc Table of Contents + +\section main_trees GIT Trees + +\subsection tree_dev Development Tree + +@code +git://git.infradead.org/users/tgr/libnl.git +@endcode +- Web: http://git.infradead.org/users/tgr/libnl.git + +\section main_website Website + +- http://www.infradead.org/~tgr/libnl/ + +\section main_mailinglist Mailinglist + +Please post questions and patches to the libnl mailinglist: + +@code +libnl@lists.infradead.org +@endcode + +- Archives: http://canuck.infradead.org/pipermail/libnl/ + +*/ diff --git a/doc/stylesheets/asciidoc-manpage.css b/doc/stylesheets/asciidoc-manpage.css new file mode 100644 index 00000000..45eba236 --- /dev/null +++ b/doc/stylesheets/asciidoc-manpage.css @@ -0,0 +1,18 @@ +/* Overrides for manpage documents */ +h1 { + padding-top: 0.5em; + padding-bottom: 0.5em; + border-top: 2px solid silver; + border-bottom: 2px solid silver; +} +h2 { + border-style: none; +} +div.sectionbody { + margin-left: 3em; +} + +@media print { + div#toc { display: none; } +} + diff --git a/doc/stylesheets/asciidoc.css b/doc/stylesheets/asciidoc.css new file mode 100644 index 00000000..2852168b --- /dev/null +++ b/doc/stylesheets/asciidoc.css @@ -0,0 +1,526 @@ +/* Shared CSS for AsciiDoc xhtml11 and html5 backends */ + +/* Default font. */ +body { + font-family: Georgia,serif; +} + +/* Title font. */ +h1, h2, h3, h4, h5, h6, +div.title, caption.title, +thead, p.table.header, +#toctitle, +#author, #revnumber, #revdate, #revremark, +#footer { + /* OLD: font-family: Arial,Helvetica,sans-serif; */ + font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif; +} + +body { + margin: 1em 5% 1em 5%; +} + +a { + /* color: blue; */ + color: #990000; + text-decoration: none; +} +a:visited { + /* color: fuchsia; */ +} + +a:hover { + text-decoration: underline; +} + +em { + font-style: italic; + /* color: navy; */ +} + +strong { + font-weight: bold; + color: black; + /* color: #083194; */ +} + +h1, h2, h3, h4, h5, h6 { + /* color: #527bbd; */ + color: #990000; + margin-top: 1.2em; + margin-bottom: 0.5em; + line-height: 1.3; +} + +h1, h2, h3 { + border-bottom: 2px solid silver; +} +h2 { + padding-top: 0.5em; +} +h3 { + float: left; +} +h3 + * { + clear: left; +} +h5 { + font-size: 1.0em; +} + +div.sectionbody { + margin-left: 0; +} + +hr { + border: 1px solid silver; +} + +p { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +ul, ol, li > p { + margin-top: 0; +} +ul > li { color: #aaa; } +ul > li > * { color: black; } + +pre { + padding: 0; + margin: 0; +} + +#author { + /* color: #527bbd; */ + font-weight: bold; + font-size: 1.1em; +} +#email { +} +#revnumber, #revdate, #revremark { +} + +#footer { + font-size: small; + border-top: 2px solid silver; + padding-top: 0.5em; + margin-top: 4.0em; +} +#footer-text { + float: left; + padding-bottom: 0.5em; +} +#footer-badges { + float: right; + padding-bottom: 0.5em; +} + +#preamble { + margin-top: 1.5em; + margin-bottom: 1.5em; +} +div.imageblock, div.exampleblock, div.verseblock, +div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock, +div.admonitionblock { + margin-top: 1.0em; + margin-bottom: 1.5em; +} +div.admonitionblock { + margin-top: 2.0em; + margin-bottom: 2.0em; + margin-right: 10%; + /* color: #606060; */ +} + +div.content { /* Block element content. */ + padding: 0; +} + +/* Block element titles. */ +div.title, caption.title { + /* OLD: color: #527bbd; */ + color: #990000; + font-weight: bold; + text-align: left; + margin-top: 1.0em; + margin-bottom: 0.5em; +} +div.title + * { + margin-top: 0; +} + +td div.title:first-child { + margin-top: 0.0em; +} +div.content div.title:first-child { + margin-top: 0.0em; +} +div.content + div.title { + margin-top: 0.0em; +} + +div.sidebarblock > div.content { + background: #ffffee; + border: 1px solid #dddddd; + border-left: 4px solid #f0f0f0; + padding: 0.5em; +} + +div.listingblock > div.content { + border: 1px solid #dddddd; + /* border-left: 5px solid #f0f0f0; */ + background: #f8f8f8; + padding: 0.5em; +} + +div.quoteblock, div.verseblock { + padding-left: 1.0em; + margin-left: 1.0em; + margin-right: 10%; + border-left: 5px solid #f0f0f0; + color: #777777; +} + +div.quoteblock > div.attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock > pre.content { + font-family: inherit; + font-size: inherit; +} +div.verseblock > div.attribution { + padding-top: 0.75em; + text-align: left; +} +/* DEPRECATED: Pre version 8.2.7 verse style literal block. */ +div.verseblock + div.attribution { + text-align: left; +} + +div.admonitionblock .icon { + vertical-align: top; + font-size: 1.1em; + font-weight: bold; + text-decoration: underline; + /* OLD: color: #527bbd; */ + color: #990000; + padding-right: 0.5em; +} +div.admonitionblock td.content { + padding-left: 0.5em; + border-left: 3px solid #dddddd; +} + +div.exampleblock > div.content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +div.imageblock div.content { padding-left: 0; } +span.image img { border-style: none; } +a.image:visited { color: white; } + +dl { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +dt { + margin-top: 0.5em; + margin-bottom: 0; + font-style: normal; + color: navy; +} +dd > *:first-child { + margin-top: 0.1em; +} + +ul, ol { + list-style-position: outside; +} +ol.arabic { + list-style-type: decimal; +} +ol.loweralpha { + list-style-type: lower-alpha; +} +ol.upperalpha { + list-style-type: upper-alpha; +} +ol.lowerroman { + list-style-type: lower-roman; +} +ol.upperroman { + list-style-type: upper-roman; +} + +div.compact ul, div.compact ol, +div.compact p, div.compact p, +div.compact div, div.compact div { + margin-top: 0.1em; + margin-bottom: 0.1em; +} + +tfoot { + font-weight: bold; +} +td > div.verse { + white-space: pre; +} + +div.hdlist { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +div.hdlist tr { + padding-bottom: 15px; +} +dt.hdlist1.strong, td.hdlist1.strong { + font-weight: bold; +} +td.hdlist1 { + vertical-align: top; + font-style: normal; + padding-right: 0.8em; + /* color: navy; */ + color: #990000; +} +td.hdlist2 { + vertical-align: top; +} +div.hdlist.compact tr { + margin: 0; + padding-bottom: 0; +} + +.comment { + background: yellow; +} + +.footnote, .footnoteref { + font-size: 0.8em; +} + +span.footnote, span.footnoteref { + vertical-align: super; +} + +#footnotes { + margin: 20px 0 20px 0; + padding: 7px 0 0 0; +} + +#footnotes div.footnote { + margin: 0 0 5px 0; +} + +#footnotes hr { + border: none; + border-top: 1px solid silver; + height: 1px; + text-align: left; + margin-left: 0; + width: 20%; + min-width: 100px; +} + +div.colist td { + padding-right: 0.5em; + padding-bottom: 0.3em; + vertical-align: top; +} +div.colist td img { + margin-top: 0.3em; +} + +@media print { + #footer-badges { display: none; } +} + +#toc { + margin-bottom: 2.5em; +} + +#toctitle { + /* color: #527bbd; */ + color: #990000; + font-size: 1.1em; + font-weight: bold; + margin-top: 1.0em; + margin-bottom: 0.1em; +} + +div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 { + margin-top: 0; + margin-bottom: 0; +} +div.toclevel2 { + margin-left: 2em; + font-size: 0.9em; +} +div.toclevel3 { + margin-left: 4em; + font-size: 0.9em; +} +div.toclevel4 { + margin-left: 6em; + font-size: 0.9em; +} + +span.aqua { color: aqua; } +span.black { color: black; } +span.blue { color: blue; } +span.fuchsia { color: fuchsia; } +span.gray { color: gray; } +span.green { color: green; } +span.lime { color: lime; } +span.maroon { color: maroon; } +span.navy { color: navy; } +span.olive { color: olive; } +span.purple { color: purple; } +span.red { color: red; } +span.silver { color: silver; } +span.teal { color: teal; } +span.white { color: white; } +span.yellow { color: yellow; } + +span.aqua-background { background: aqua; } +span.black-background { background: black; } +span.blue-background { background: blue; } +span.fuchsia-background { background: fuchsia; } +span.gray-background { background: gray; } +span.green-background { background: green; } +span.lime-background { background: lime; } +span.maroon-background { background: maroon; } +span.navy-background { background: navy; } +span.olive-background { background: olive; } +span.purple-background { background: purple; } +span.red-background { background: red; } +span.silver-background { background: silver; } +span.teal-background { background: teal; } +span.white-background { background: white; } +span.yellow-background { background: yellow; } + +span.big { font-size: 2em; } +span.small { font-size: 0.6em; } + +span.underline { text-decoration: underline; } +span.overline { text-decoration: overline; } +span.line-through { text-decoration: line-through; } + + +/* + * xhtml11 specific + * + * */ + +tt { + font-family: monospace; + font-size: inherit; + /* color: navy; */ + color: black; +} + +div.tableblock { + margin-top: 1.0em; + margin-bottom: 1.5em; +} +div.tableblock > table { + /* border: 3px solid #527bbd; */ + border: 2px solid #990000; +} +thead, p.table.header { + font-weight: bold; + /* color: #527bbd; */ + color: #990000; +} +p.table { + margin-top: 0; +} +/* Because the table frame attribute is overriden by CSS in most browsers. */ +div.tableblock > table[frame="void"] { + border-style: none; +} +div.tableblock > table[frame="hsides"] { + border-left-style: none; + border-right-style: none; +} +div.tableblock > table[frame="vsides"] { + border-top-style: none; + border-bottom-style: none; +} + + +/* + * html5 specific + * + * */ + +.monospaced { + font-family: monospace; + font-size: inherit; + color: navy; +} + +table.tableblock { + margin-top: 1.0em; + margin-bottom: 1.5em; +} +thead, p.tableblock.header { + font-weight: bold; + /* color: #527bbd; */ + color: #990000; +} +p.tableblock { + margin-top: 0; +} +table.tableblock { + border-width: 3px; + border-spacing: 0px; + border-style: solid; + /* border-color: #527bbd; */ + border-color: #990000; + border-collapse: collapse; +} +th.tableblock, td.tableblock { + border-width: 1px; + padding: 4px; + border-style: solid; + /* border-color: #527bbd; */ + border-color: #990000; +} + +table.tableblock.frame-topbot { + border-left-style: hidden; + border-right-style: hidden; +} +table.tableblock.frame-sides { + border-top-style: hidden; + border-bottom-style: hidden; +} +table.tableblock.frame-none { + border-style: hidden; +} + +th.tableblock.halign-left, td.tableblock.halign-left { + text-align: left; +} +th.tableblock.halign-center, td.tableblock.halign-center { + text-align: center; +} +th.tableblock.halign-right, td.tableblock.halign-right { + text-align: right; +} + +th.tableblock.valign-top, td.tableblock.valign-top { + vertical-align: top; +} +th.tableblock.valign-middle, td.tableblock.valign-middle { + vertical-align: middle; +} +th.tableblock.valign-bottom, td.tableblock.valign-bottom { + vertical-align: bottom; +} diff --git a/doc/stylesheets/docbook-xsl.css b/doc/stylesheets/docbook-xsl.css new file mode 100644 index 00000000..6df2944f --- /dev/null +++ b/doc/stylesheets/docbook-xsl.css @@ -0,0 +1,322 @@ +/* + CSS stylesheet for XHTML produced by DocBook XSL stylesheets. + Tested with XSL stylesheets 1.61.2, 1.67.2 +*/ + +span.strong { + font-weight: bold; +} + +body blockquote { + margin-top: .75em; + line-height: 1.5; + margin-bottom: .75em; +} + +html body { + margin: 1em 5% 1em 5%; + line-height: 1.2; +} + +body div { + margin: 0; +} + +h1, h2, h3, h4, h5, h6 +{ + color: #527bbd; + font-family: tahoma, verdana, sans-serif; +} + +div.toc p:first-child, +div.list-of-figures p:first-child, +div.list-of-tables p:first-child, +div.list-of-examples p:first-child, +div.example p.title, +div.sidebar p.title +{ + font-weight: bold; + color: #527bbd; + font-family: tahoma, verdana, sans-serif; + margin-bottom: 0.2em; +} + +body h1 { + margin: .0em 0 0 -4%; + line-height: 1.3; + border-bottom: 2px solid silver; +} + +body h2 { + margin: 0.5em 0 0 -4%; + line-height: 1.3; + border-bottom: 2px solid silver; +} + +body h3 { + margin: .8em 0 0 -3%; + line-height: 1.3; +} + +body h4 { + margin: .8em 0 0 -3%; + line-height: 1.3; +} + +body h5 { + margin: .8em 0 0 -2%; + line-height: 1.3; +} + +body h6 { + margin: .8em 0 0 -1%; + line-height: 1.3; +} + +body hr { + border: none; /* Broken on IE6 */ +} +div.footnotes hr { + border: 1px solid silver; +} + +div.navheader th, div.navheader td, div.navfooter td { + font-family: sans-serif; + font-size: 0.9em; + font-weight: bold; + color: #527bbd; +} +div.navheader img, div.navfooter img { + border-style: none; +} +div.navheader a, div.navfooter a { + font-weight: normal; +} +div.navfooter hr { + border: 1px solid silver; +} + +body td { + line-height: 1.2 +} + +body th { + line-height: 1.2; +} + +ol { + line-height: 1.2; +} + +ul, body dir, body menu { + line-height: 1.2; +} + +html { + margin: 0; + padding: 0; +} + +body h1, body h2, body h3, body h4, body h5, body h6 { + margin-left: 0 +} + +body pre { + margin: 0.5em 10% 0.5em 1em; + line-height: 1.0; + color: navy; +} + +tt.literal, code.literal { + color: navy; +} + +.programlisting, .screen { + border: 1px solid silver; + background: #f4f4f4; + margin: 0.5em 10% 0.5em 0; + padding: 0.5em 1em; +} + +div.sidebar { + background: #ffffee; + margin: 1.0em 10% 0.5em 0; + padding: 0.5em 1em; + border: 1px solid silver; +} +div.sidebar * { padding: 0; } +div.sidebar div { margin: 0; } +div.sidebar p.title { + margin-top: 0.5em; + margin-bottom: 0.2em; +} + +div.bibliomixed { + margin: 0.5em 5% 0.5em 1em; +} + +div.glossary dt { + font-weight: bold; +} +div.glossary dd p { + margin-top: 0.2em; +} + +dl { + margin: .8em 0; + line-height: 1.2; +} + +dt { + margin-top: 0.5em; +} + +dt span.term { + font-style: normal; + color: navy; +} + +div.variablelist dd p { + margin-top: 0; +} + +div.itemizedlist li, div.orderedlist li { + margin-left: -0.8em; + margin-top: 0.5em; +} + +ul, ol { + list-style-position: outside; +} + +div.sidebar ul, div.sidebar ol { + margin-left: 2.8em; +} + +div.itemizedlist p.title, +div.orderedlist p.title, +div.variablelist p.title +{ + margin-bottom: -0.8em; +} + +div.revhistory table { + border-collapse: collapse; + border: none; +} +div.revhistory th { + border: none; + color: #527bbd; + font-family: tahoma, verdana, sans-serif; +} +div.revhistory td { + border: 1px solid silver; +} + +/* Keep TOC and index lines close together. */ +div.toc dl, div.toc dt, +div.list-of-figures dl, div.list-of-figures dt, +div.list-of-tables dl, div.list-of-tables dt, +div.indexdiv dl, div.indexdiv dt +{ + line-height: normal; + margin-top: 0; + margin-bottom: 0; +} + +/* + Table styling does not work because of overriding attributes in + generated HTML. +*/ +div.table table, +div.informaltable table +{ + margin-left: 0; + margin-right: 5%; + margin-bottom: 0.8em; +} +div.informaltable table +{ + margin-top: 0.4em +} +div.table thead, +div.table tfoot, +div.table tbody, +div.informaltable thead, +div.informaltable tfoot, +div.informaltable tbody +{ + /* No effect in IE6. */ + border-top: 3px solid #527bbd; + border-bottom: 3px solid #527bbd; +} +div.table thead, div.table tfoot, +div.informaltable thead, div.informaltable tfoot +{ + font-weight: bold; +} + +div.mediaobject img { + margin-bottom: 0.8em; +} +div.figure p.title, +div.table p.title +{ + margin-top: 1em; + margin-bottom: 0.4em; +} + +div.calloutlist p +{ + margin-top: 0em; + margin-bottom: 0.4em; +} + +a img { + border-style: none; +} + +@media print { + div.navheader, div.navfooter { display: none; } +} + +span.aqua { color: aqua; } +span.black { color: black; } +span.blue { color: blue; } +span.fuchsia { color: fuchsia; } +span.gray { color: gray; } +span.green { color: green; } +span.lime { color: lime; } +span.maroon { color: maroon; } +span.navy { color: navy; } +span.olive { color: olive; } +span.purple { color: purple; } +span.red { color: red; } +span.silver { color: silver; } +span.teal { color: teal; } +span.white { color: white; } +span.yellow { color: yellow; } + +span.aqua-background { background: aqua; } +span.black-background { background: black; } +span.blue-background { background: blue; } +span.fuchsia-background { background: fuchsia; } +span.gray-background { background: gray; } +span.green-background { background: green; } +span.lime-background { background: lime; } +span.maroon-background { background: maroon; } +span.navy-background { background: navy; } +span.olive-background { background: olive; } +span.purple-background { background: purple; } +span.red-background { background: red; } +span.silver-background { background: silver; } +span.teal-background { background: teal; } +span.white-background { background: white; } +span.yellow-background { background: yellow; } + +span.big { font-size: 2em; } +span.small { font-size: 0.6em; } + +span.underline { text-decoration: underline; } +span.overline { text-decoration: overline; } +span.line-through { text-decoration: line-through; } diff --git a/doc/stylesheets/flask-manpage.css b/doc/stylesheets/flask-manpage.css new file mode 100644 index 00000000..75a2dda0 --- /dev/null +++ b/doc/stylesheets/flask-manpage.css @@ -0,0 +1 @@ +/* Empty placeholder file */ diff --git a/doc/stylesheets/flask.css b/doc/stylesheets/flask.css new file mode 100644 index 00000000..8d33bc49 --- /dev/null +++ b/doc/stylesheets/flask.css @@ -0,0 +1,584 @@ +/* + * AsciiDoc 'flask' theme for xhtml11 and html5 backends. A shameless knock-off + * of the Flask website styling (http://flask.pocoo.org/docs/). + * + * The implementation is straight-forward, consisting of the asciidoc.css file + * followed by theme specific overrides. + * + * */ + + +/* Shared CSS for AsciiDoc xhtml11 and html5 backends */ + +/* Default font. */ +body { + font-family: Georgia,serif; +} + +/* Title font. */ +h1, h2, h3, h4, h5, h6, +div.title, caption.title, +thead, p.table.header, +#toctitle, +#author, #revnumber, #revdate, #revremark, +#footer { + font-family: Arial,Helvetica,sans-serif; +} + +body { + margin: 1em 5% 1em 5%; +} + +a { + color: blue; + text-decoration: underline; +} +a:visited { + color: fuchsia; +} + +em { + font-style: italic; + color: navy; +} + +strong { + font-weight: bold; + color: #083194; +} + +h1, h2, h3, h4, h5, h6 { + color: #527bbd; + margin-top: 1.2em; + margin-bottom: 0.5em; + line-height: 1.3; +} + +h1, h2, h3 { + border-bottom: 2px solid silver; +} +h2 { + padding-top: 0.5em; +} +h3 { + float: left; +} +h3 + * { + clear: left; +} +h5 { + font-size: 1.0em; +} + +div.sectionbody { + margin-left: 0; +} + +hr { + border: 1px solid silver; +} + +p { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +ul, ol, li > p { + margin-top: 0; +} +ul > li { color: #aaa; } +ul > li > * { color: black; } + +pre { + padding: 0; + margin: 0; +} + +#author { + color: #527bbd; + font-weight: bold; + font-size: 1.1em; +} +#email { +} +#revnumber, #revdate, #revremark { +} + +#footer { + font-size: small; + border-top: 2px solid silver; + padding-top: 0.5em; + margin-top: 4.0em; +} +#footer-text { + float: left; + padding-bottom: 0.5em; +} +#footer-badges { + float: right; + padding-bottom: 0.5em; +} + +#preamble { + margin-top: 1.5em; + margin-bottom: 1.5em; +} +div.imageblock, div.exampleblock, div.verseblock, +div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock, +div.admonitionblock { + margin-top: 1.0em; + margin-bottom: 1.5em; +} +div.admonitionblock { + margin-top: 2.0em; + margin-bottom: 2.0em; + margin-right: 10%; + color: #606060; +} + +div.content { /* Block element content. */ + padding: 0; +} + +/* Block element titles. */ +div.title, caption.title { + color: #527bbd; + font-weight: bold; + text-align: left; + margin-top: 1.0em; + margin-bottom: 0.5em; +} +div.title + * { + margin-top: 0; +} + +td div.title:first-child { + margin-top: 0.0em; +} +div.content div.title:first-child { + margin-top: 0.0em; +} +div.content + div.title { + margin-top: 0.0em; +} + +div.sidebarblock > div.content { + background: #ffffee; + border: 1px solid #dddddd; + border-left: 4px solid #f0f0f0; + padding: 0.5em; +} + +div.listingblock > div.content { + border: 1px solid #dddddd; + border-left: 5px solid #f0f0f0; + background: #f8f8f8; + padding: 0.5em; +} + +div.quoteblock, div.verseblock { + padding-left: 1.0em; + margin-left: 1.0em; + margin-right: 10%; + border-left: 5px solid #f0f0f0; + color: #777777; +} + +div.quoteblock > div.attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock > pre.content { + font-family: inherit; + font-size: inherit; +} +div.verseblock > div.attribution { + padding-top: 0.75em; + text-align: left; +} +/* DEPRECATED: Pre version 8.2.7 verse style literal block. */ +div.verseblock + div.attribution { + text-align: left; +} + +div.admonitionblock .icon { + vertical-align: top; + font-size: 1.1em; + font-weight: bold; + text-decoration: underline; + color: #527bbd; + padding-right: 0.5em; +} +div.admonitionblock td.content { + padding-left: 0.5em; + border-left: 3px solid #dddddd; +} + +div.exampleblock > div.content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +div.imageblock div.content { padding-left: 0; } +span.image img { border-style: none; } +a.image:visited { color: white; } + +dl { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +dt { + margin-top: 0.5em; + margin-bottom: 0; + font-style: normal; + color: navy; +} +dd > *:first-child { + margin-top: 0.1em; +} + +ul, ol { + list-style-position: outside; +} +ol.arabic { + list-style-type: decimal; +} +ol.loweralpha { + list-style-type: lower-alpha; +} +ol.upperalpha { + list-style-type: upper-alpha; +} +ol.lowerroman { + list-style-type: lower-roman; +} +ol.upperroman { + list-style-type: upper-roman; +} + +div.compact ul, div.compact ol, +div.compact p, div.compact p, +div.compact div, div.compact div { + margin-top: 0.1em; + margin-bottom: 0.1em; +} + +tfoot { + font-weight: bold; +} +td > div.verse { + white-space: pre; +} + +div.hdlist { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +div.hdlist tr { + padding-bottom: 15px; +} +dt.hdlist1.strong, td.hdlist1.strong { + font-weight: bold; +} +td.hdlist1 { + vertical-align: top; + font-style: normal; + padding-right: 0.8em; + color: navy; +} +td.hdlist2 { + vertical-align: top; +} +div.hdlist.compact tr { + margin: 0; + padding-bottom: 0; +} + +.comment { + background: yellow; +} + +.footnote, .footnoteref { + font-size: 0.8em; +} + +span.footnote, span.footnoteref { + vertical-align: super; +} + +#footnotes { + margin: 20px 0 20px 0; + padding: 7px 0 0 0; +} + +#footnotes div.footnote { + margin: 0 0 5px 0; +} + +#footnotes hr { + border: none; + border-top: 1px solid silver; + height: 1px; + text-align: left; + margin-left: 0; + width: 20%; + min-width: 100px; +} + +div.colist td { + padding-right: 0.5em; + padding-bottom: 0.3em; + vertical-align: top; +} +div.colist td img { + margin-top: 0.3em; +} + +@media print { + #footer-badges { display: none; } +} + +#toc { + margin-bottom: 2.5em; +} + +#toctitle { + color: #527bbd; + font-size: 1.1em; + font-weight: bold; + margin-top: 1.0em; + margin-bottom: 0.1em; +} + +div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 { + margin-top: 0; + margin-bottom: 0; +} +div.toclevel2 { + margin-left: 2em; + font-size: 0.9em; +} +div.toclevel3 { + margin-left: 4em; + font-size: 0.9em; +} +div.toclevel4 { + margin-left: 6em; + font-size: 0.9em; +} + +span.aqua { color: aqua; } +span.black { color: black; } +span.blue { color: blue; } +span.fuchsia { color: fuchsia; } +span.gray { color: gray; } +span.green { color: green; } +span.lime { color: lime; } +span.maroon { color: maroon; } +span.navy { color: navy; } +span.olive { color: olive; } +span.purple { color: purple; } +span.red { color: red; } +span.silver { color: silver; } +span.teal { color: teal; } +span.white { color: white; } +span.yellow { color: yellow; } + +span.aqua-background { background: aqua; } +span.black-background { background: black; } +span.blue-background { background: blue; } +span.fuchsia-background { background: fuchsia; } +span.gray-background { background: gray; } +span.green-background { background: green; } +span.lime-background { background: lime; } +span.maroon-background { background: maroon; } +span.navy-background { background: navy; } +span.olive-background { background: olive; } +span.purple-background { background: purple; } +span.red-background { background: red; } +span.silver-background { background: silver; } +span.teal-background { background: teal; } +span.white-background { background: white; } +span.yellow-background { background: yellow; } + +span.big { font-size: 2em; } +span.small { font-size: 0.6em; } + +span.underline { text-decoration: underline; } +span.overline { text-decoration: overline; } +span.line-through { text-decoration: line-through; } + + +/* + * xhtml11 specific + * + * */ + +tt { + font-family: monospace; + font-size: inherit; + color: navy; +} + +div.tableblock { + margin-top: 1.0em; + margin-bottom: 1.5em; +} +div.tableblock > table { + border: 3px solid #527bbd; +} +thead, p.table.header { + font-weight: bold; + color: #527bbd; +} +p.table { + margin-top: 0; +} +/* Because the table frame attribute is overriden by CSS in most browsers. */ +div.tableblock > table[frame="void"] { + border-style: none; +} +div.tableblock > table[frame="hsides"] { + border-left-style: none; + border-right-style: none; +} +div.tableblock > table[frame="vsides"] { + border-top-style: none; + border-bottom-style: none; +} + + +/* + * html5 specific + * + * */ + +.monospaced { + font-family: monospace; + font-size: inherit; + color: navy; +} + +table.tableblock { + margin-top: 1.0em; + margin-bottom: 1.5em; +} +thead, p.tableblock.header { + font-weight: bold; + color: #527bbd; +} +p.tableblock { + margin-top: 0; +} +table.tableblock { + border-width: 3px; + border-spacing: 0px; + border-style: solid; + border-color: #527bbd; + border-collapse: collapse; +} +th.tableblock, td.tableblock { + border-width: 1px; + padding: 4px; + border-style: solid; + border-color: #527bbd; +} + +table.tableblock.frame-topbot { + border-left-style: hidden; + border-right-style: hidden; +} +table.tableblock.frame-sides { + border-top-style: hidden; + border-bottom-style: hidden; +} +table.tableblock.frame-none { + border-style: hidden; +} + +th.tableblock.halign-left, td.tableblock.halign-left { + text-align: left; +} +th.tableblock.halign-center, td.tableblock.halign-center { + text-align: center; +} +th.tableblock.halign-right, td.tableblock.halign-right { + text-align: right; +} + +th.tableblock.valign-top, td.tableblock.valign-top { + vertical-align: top; +} +th.tableblock.valign-middle, td.tableblock.valign-middle { + vertical-align: middle; +} +th.tableblock.valign-bottom, td.tableblock.valign-bottom { + vertical-align: bottom; +} + + +/* + * Theme specific overrides of the preceding (asciidoc.css) CSS. + * + */ +body { + font-family: Garamond, Georgia, serif; + font-size: 17px; + color: #3E4349; + line-height: 1.3em; +} +h1, h2, h3, h4, h5, h6, +div.title, caption.title, +thead, p.table.header, +#toctitle, +#author, #revnumber, #revdate, #revremark, +#footer { + font-family: Garmond, Georgia, serif; + font-weight: normal; + border-bottom-width: 0; + color: #3E4349; +} +div.title, caption.title { color: #596673; font-weight: bold; } +h1 { font-size: 240%; } +h2 { font-size: 180%; } +h3 { font-size: 150%; } +h4 { font-size: 130%; } +h5 { font-size: 100%; } +h6 { font-size: 100%; } +#header h1 { margin-top: 0; } +#toc { + color: #444444; + line-height: 1.5; + padding-top: 1.5em; +} +#toctitle { + font-size: 20px; +} +#toc a { + border-bottom: 1px dotted #999999; + color: #444444 !important; + text-decoration: none !important; +} +#toc a:hover { + border-bottom: 1px solid #6D4100; + color: #6D4100 !important; + text-decoration: none !important; +} +div.toclevel1 { margin-top: 0.2em; font-size: 16px; } +div.toclevel2 { margin-top: 0.15em; font-size: 14px; } +em, dt, td.hdlist1 { color: black; } +strong { color: #3E4349; } +a { color: #004B6B; text-decoration: none; border-bottom: 1px dotted #004B6B; } +a:visited { color: #615FA0; border-bottom: 1px dotted #615FA0; } +a:hover { color: #6D4100; border-bottom: 1px solid #6D4100; } +div.tableblock > table, table.tableblock { border: 3px solid #E8E8E8; } +th.tableblock, td.tableblock { border: 1px solid #E8E8E8; } +ul > li > * { color: #3E4349; } +pre, tt, .monospaced { font-family: Consolas,Menlo,'Deja Vu Sans Mono','Bitstream Vera Sans Mono',monospace; } +tt, .monospaced { font-size: 0.9em; color: black; +} +div.exampleblock > div.content, div.sidebarblock > div.content, div.listingblock > div.content { border-width: 0 0 0 3px; border-color: #E8E8E8; } +div.verseblock { border-left-width: 0; margin-left: 3em; } +div.quoteblock { border-left-width: 3px; margin-left: 0; margin-right: 0;} +div.admonitionblock td.content { border-left: 3px solid #E8E8E8; } diff --git a/doc/stylesheets/pygments.css b/doc/stylesheets/pygments.css new file mode 100644 index 00000000..9ca3659c --- /dev/null +++ b/doc/stylesheets/pygments.css @@ -0,0 +1,66 @@ +/* + pygmentize filter +*/ +.highlight .hll { background-color: #ffffcc } +.highlight { background: #f4f4f4; } +.highlight .c { color: #008800; font-style: italic } /* Comment */ +.highlight .err { border: 1px solid #FF0000 } /* Error */ +.highlight .k { color: #AA22FF; font-weight: bold } /* Keyword */ +.highlight .o { color: #666666 } /* Operator */ +.highlight .cm { color: #008800; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #008800 } /* Comment.Preproc */ +.highlight .c1 { color: #008800; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #008800; font-weight: bold } /* Comment.Special */ +.highlight .gd { color: #A00000 } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #FF0000 } /* Generic.Error */ +.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.highlight .gi { color: #00A000 } /* Generic.Inserted */ +.highlight .go { color: #808080 } /* Generic.Output */ +.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.highlight .gt { color: #0040D0 } /* Generic.Traceback */ +.highlight .kc { color: #AA22FF; font-weight: bold } /* Keyword.Constant */ +.highlight .kd { color: #AA22FF; font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { color: #AA22FF; font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { color: #AA22FF } /* Keyword.Pseudo */ +.highlight .kr { color: #AA22FF; font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #00BB00; font-weight: bold } /* Keyword.Type */ +.highlight .m { color: #666666 } /* Literal.Number */ +.highlight .s { color: #BB4444 } /* Literal.String */ +.highlight .na { color: #BB4444 } /* Name.Attribute */ +.highlight .nb { color: #AA22FF } /* Name.Builtin */ +.highlight .nc { color: #0000FF } /* Name.Class */ +.highlight .no { color: #880000 } /* Name.Constant */ +.highlight .nd { color: #AA22FF } /* Name.Decorator */ +.highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */ +.highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #00A000 } /* Name.Function */ +.highlight .nl { color: #A0A000 } /* Name.Label */ +.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ +.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */ +.highlight .nv { color: #B8860B } /* Name.Variable */ +.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mf { color: #666666 } /* Literal.Number.Float */ +.highlight .mh { color: #666666 } /* Literal.Number.Hex */ +.highlight .mi { color: #666666 } /* Literal.Number.Integer */ +.highlight .mo { color: #666666 } /* Literal.Number.Oct */ +.highlight .sb { color: #BB4444 } /* Literal.String.Backtick */ +.highlight .sc { color: #BB4444 } /* Literal.String.Char */ +.highlight .sd { color: #BB4444; font-style: italic } /* Literal.String.Doc */ +.highlight .s2 { color: #BB4444 } /* Literal.String.Double */ +.highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ +.highlight .sh { color: #BB4444 } /* Literal.String.Heredoc */ +.highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ +.highlight .sx { color: #008000 } /* Literal.String.Other */ +.highlight .sr { color: #BB6688 } /* Literal.String.Regex */ +.highlight .s1 { color: #BB4444 } /* Literal.String.Single */ +.highlight .ss { color: #B8860B } /* Literal.String.Symbol */ +.highlight .bp { color: #AA22FF } /* Name.Builtin.Pseudo */ +.highlight .vc { color: #B8860B } /* Name.Variable.Class */ +.highlight .vg { color: #B8860B } /* Name.Variable.Global */ +.highlight .vi { color: #B8860B } /* Name.Variable.Instance */ +.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */ + diff --git a/doc/stylesheets/slidy.css b/doc/stylesheets/slidy.css new file mode 100644 index 00000000..bbb790e7 --- /dev/null +++ b/doc/stylesheets/slidy.css @@ -0,0 +1,445 @@ +/* slidy.css + + Copyright (c) 2005-2010 W3C (MIT, ERCIM, Keio), All Rights Reserved. + W3C liability, trademark, document use and software licensing + rules apply, see: + + http://www.w3.org/Consortium/Legal/copyright-documents + http://www.w3.org/Consortium/Legal/copyright-software +*/ + +/* + SJR: 2010-09-29: Modified for AsciiDoc slidy backend. + Mostly just commented out stuff that is handled by AsciiDoc's CSS files. +*/ + +body +{ + margin: 0 0 0 0; + padding: 0 0 0 0; + width: 100%; + height: 100%; + color: black; + background-color: white; +/* + font-family: "Gill Sans MT", "Gill Sans", GillSans, sans-serif; +*/ + font-size: 14pt; +} + +div.toolbar { + position: fixed; z-index: 200; + top: auto; bottom: 0; left: 0; right: 0; + height: 1.2em; text-align: right; + padding-left: 1em; + padding-right: 1em; + font-size: 60%; + color: red; + background-color: rgb(240,240,240); + border-top: solid 1px rgb(180,180,180); +} + +div.toolbar span.copyright { + color: black; + margin-left: 0.5em; +} + +div.initial_prompt { + position: absolute; + z-index: 1000; + bottom: 1.2em; + width: 90%; + background-color: rgb(200,200,200); + opacity: 0.35; + background-color: rgb(200,200,200, 0.35); + cursor: pointer; +} + +div.initial_prompt p.help { + text-align: center; +} + +div.initial_prompt p.close { + text-align: right; + font-style: italic; +} + +div.slidy_toc { + position: absolute; + z-index: 300; + width: 60%; + max-width: 30em; + height: 30em; + overflow: auto; + top: auto; + right: auto; + left: 4em; + bottom: 4em; + padding: 1em; + background: rgb(240,240,240); + border-style: solid; + border-width: 2px; + font-size: 60%; +} + +div.slidy_toc .toc_heading { + text-align: center; + width: 100%; + margin: 0; + margin-bottom: 1em; + border-bottom-style: solid; + border-bottom-color: rgb(180,180,180); + border-bottom-width: 1px; +} + +div.slide { + z-index: 20; + margin: 0 0 0 0; + padding-top: 0; + padding-bottom: 0; + padding-left: 20px; + padding-right: 20px; + border-width: 0; + clear: both; + top: 0; + bottom: 0; + left: 0; + right: 0; + line-height: 120%; + background-color: transparent; +} + +div.background { + display: none; +} + +div.handout { + margin-left: 20px; + margin-right: 20px; +} + +div.slide.titlepage { + text-align: center; +} + +div.slide.titlepage.h1 { + padding-top: 10%; +} + +div.slide h1 { + padding-left: 0; + padding-right: 20pt; + padding-top: 4pt; + padding-bottom: 4pt; + margin-top: 0; + margin-left: 0; + margin-right: 60pt; + margin-bottom: 0.5em; + display: block; + font-size: 160%; + line-height: 1.2em; + background: transparent; +} + +div.toc { + position: absolute; + top: auto; + bottom: 4em; + left: 4em; + right: auto; + width: 60%; + max-width: 30em; + height: 30em; + border: solid thin black; + padding: 1em; + background: rgb(240,240,240); + color: black; + z-index: 300; + overflow: auto; + display: block; + visibility: visible; +} + +div.toc-heading { + width: 100%; + border-bottom: solid 1px rgb(180,180,180); + margin-bottom: 1em; + text-align: center; +} + +/* +pre { + font-size: 80%; + font-weight: bold; + line-height: 120%; + padding-top: 0.2em; + padding-bottom: 0.2em; + padding-left: 1em; + padding-right: 1em; + border-style: solid; + border-left-width: 1em; + border-top-width: thin; + border-right-width: thin; + border-bottom-width: thin; + border-color: #95ABD0; + color: #00428C; + background-color: #E4E5E7; +} +*/ + +/* +li pre { margin-left: 0; } + +blockquote { font-style: italic } + +img { background-color: transparent } + +p.copyright { font-size: smaller } +*/ + +.center { text-align: center } +.footnote { font-size: smaller; margin-left: 2em; } + +/* +a img { border-width: 0; border-style: none } +*/ + +a:visited { color: navy } +a:link { color: navy } +a:hover { color: red; text-decoration: underline } +a:active { color: red; text-decoration: underline } + +a {text-decoration: none} +.navbar a:link {color: white} +.navbar a:visited {color: yellow} +.navbar a:active {color: red} +.navbar a:hover {color: red} + +/* +ul { list-style-type: square; } +ul ul { list-style-type: disc; } +ul ul ul { list-style-type: circle; } +ul ul ul ul { list-style-type: disc; } +li { margin-left: 0.5em; margin-top: 0.5em; } +li li { font-size: 85%; font-style: italic } +li li li { font-size: 85%; font-style: normal } +*/ + +div dt +{ + margin-left: 0; + margin-top: 1em; + margin-bottom: 0.5em; + font-weight: bold; +} +div dd +{ + margin-left: 2em; + margin-bottom: 0.5em; +} + + +/* +p,pre,ul,ol,blockquote,h2,h3,h4,h5,h6,dl,table { + margin-left: 1em; + margin-right: 1em; +} +*/ + +p.subhead { font-weight: bold; margin-top: 2em; } + +.smaller { font-size: smaller } +.bigger { font-size: 130% } + +/* +td,th { padding: 0.2em } +*/ + +ul { + margin: 0.5em 1.5em 0.5em 1.5em; + padding: 0; +} + +ol { + margin: 0.5em 1.5em 0.5em 1.5em; + padding: 0; +} + +ul { list-style-type: square; } +ul ul { list-style-type: disc; } +ul ul ul { list-style-type: circle; } +ul ul ul ul { list-style-type: disc; } + +/* +ul li { + list-style: square; + margin: 0.1em 0em 0.6em 0; + padding: 0 0 0 0; + line-height: 140%; +} + +ol li { + margin: 0.1em 0em 0.6em 1.5em; + padding: 0 0 0 0px; + line-height: 140%; + list-style-type: decimal; +} + +li ul li { + font-size: 85%; + font-style: italic; + list-style-type: disc; + background: transparent; + padding: 0 0 0 0; +} +li li ul li { + font-size: 85%; + font-style: normal; + list-style-type: circle; + background: transparent; + padding: 0 0 0 0; +} +li li li ul li { + list-style-type: disc; + background: transparent; + padding: 0 0 0 0; +} + +li ol li { + list-style-type: decimal; +} + + +li li ol li { + list-style-type: decimal; +} +*/ + +/* + setting class="outline" on ol or ul makes it behave as an + ouline list where blocklevel content in li elements is + hidden by default and can be expanded or collapsed with + mouse click. Set class="expand" on li to override default +*/ + +ol.outline li:hover { cursor: pointer } +ol.outline li.nofold:hover { cursor: default } + +ul.outline li:hover { cursor: pointer } +ul.outline li.nofold:hover { cursor: default } + +ol.outline { list-style:decimal; } +ol.outline ol { list-style-type:lower-alpha } + +ol.outline li.nofold { + padding: 0 0 0 20px; + background: transparent url(../graphics/nofold-dim.gif) no-repeat 0px 0.5em; +} +ol.outline li.unfolded { + padding: 0 0 0 20px; + background: transparent url(../graphics/fold-dim.gif) no-repeat 0px 0.5em; +} +ol.outline li.folded { + padding: 0 0 0 20px; + background: transparent url(../graphics/unfold-dim.gif) no-repeat 0px 0.5em; +} +ol.outline li.unfolded:hover { + padding: 0 0 0 20px; + background: transparent url(../graphics/fold.gif) no-repeat 0px 0.5em; +} +ol.outline li.folded:hover { + padding: 0 0 0 20px; + background: transparent url(../graphics/unfold.gif) no-repeat 0px 0.5em; +} + +ul.outline li.nofold { + padding: 0 0 0 20px; + background: transparent url(../graphics/nofold-dim.gif) no-repeat 0px 0.5em; +} +ul.outline li.unfolded { + padding: 0 0 0 20px; + background: transparent url(../graphics/fold-dim.gif) no-repeat 0px 0.5em; +} +ul.outline li.folded { + padding: 0 0 0 20px; + background: transparent url(../graphics/unfold-dim.gif) no-repeat 0px 0.5em; +} +ul.outline li.unfolded:hover { + padding: 0 0 0 20px; + background: transparent url(../graphics/fold.gif) no-repeat 0px 0.5em; +} +ul.outline li.folded:hover { + padding: 0 0 0 20px; + background: transparent url(../graphics/unfold.gif) no-repeat 0px 0.5em; +} + +/* for slides with class "title" in table of contents */ +a.titleslide { font-weight: bold; font-style: italic } + +/* + hide images for work around for save as bug + where browsers fail to save images used by CSS +*/ +img.hidden { display: none; visibility: hidden } +div.initial_prompt { display: none; visibility: hidden } + + div.slide { + visibility: visible; + position: inherit; + } + div.handout { + border-top-style: solid; + border-top-width: thin; + border-top-color: black; + } + +@media screen { + .hidden { display: none; visibility: visible } + + div.slide.hidden { display: block; visibility: visible } + div.handout.hidden { display: block; visibility: visible } + div.background { display: none; visibility: hidden } + body.single_slide div.initial_prompt { display: block; visibility: visible } + body.single_slide div.background { display: block; visibility: visible } + body.single_slide div.background.hidden { display: none; visibility: hidden } + body.single_slide .invisible { visibility: hidden } + body.single_slide .hidden { display: none; visibility: hidden } + body.single_slide div.slide { position: absolute } + body.single_slide div.handout { display: none; visibility: hidden } +} + +@media print { + .hidden { display: block; visibility: visible } + +/* + div.slide pre { font-size: 60%; padding-left: 0.5em; } +*/ + div.toolbar { display: none; visibility: hidden; } + div.slidy_toc { display: none; visibility: hidden; } + div.background { display: none; visibility: hidden; } + div.slide { page-break-before: always } + /* :first-child isn't reliable for print media */ + div.slide.first-slide { page-break-before: avoid } +} + + +/* SJR: AsciiDoc slidy backend tweaks */ + +ol, ul { + margin: 0.8em 1.5em 0.8em 1.8em; +} +li > ul, li > ol { + margin-top: 0.5em; +} + +.outline > li.folded, +.outline > li.unfolded { + color: #527bbd; +} +ul > li{ color: #aaa; } +ul > li > *, ol > li > * { color: black; } + +li { + margin-top: 0.5em; + margin-bottom: 0.5em; +} diff --git a/doc/stylesheets/toc2.css b/doc/stylesheets/toc2.css new file mode 100644 index 00000000..a1e368bc --- /dev/null +++ b/doc/stylesheets/toc2.css @@ -0,0 +1,34 @@ +@media screen { + body { + max-width: 50em; /* approximately 80 characters wide */ + margin-left: 16em; + } + + #toc { + position: fixed; + top: 0; + left: 0; + bottom: 0; + width: 13em; + padding: 0.5em; + padding-bottom: 1.5em; + margin: 0; + overflow: auto; + border-right: 3px solid #f8f8f8; + } + + #toc .toclevel1 { + margin-top: 0.5em; + } + + #toc .toclevel2 { + margin-top: 0.25em; + display: list-item; + /* OLD color: #aaaaaa; */ + color: #990000; + } + + #toctitle { + margin-top: 0.5em; + } +} diff --git a/doc/stylesheets/volnitsky-manpage.css b/doc/stylesheets/volnitsky-manpage.css new file mode 100644 index 00000000..75a2dda0 --- /dev/null +++ b/doc/stylesheets/volnitsky-manpage.css @@ -0,0 +1 @@ +/* Empty placeholder file */ diff --git a/doc/stylesheets/volnitsky.css b/doc/stylesheets/volnitsky.css new file mode 100644 index 00000000..b6c4a156 --- /dev/null +++ b/doc/stylesheets/volnitsky.css @@ -0,0 +1,435 @@ +/* + * AsciiDoc 'volnitsky' theme for xhtml11 and html5 backends. + * Based on css from http://volnitsky.com, which was in turn based on default + * theme from AsciiDoc + * + * FIXME: The stlying is still a bit rough in places. + * + */ + +/* Default font. */ +body { + font-family: Georgia,"Times New Roman",Times,serif; +} + +/* Title font. */ +h1, h2, h3, h4, h5, h6, +div.title, caption.title, +thead, p.table.header, +#toctitle, +#author, #revnumber, #revdate, #revremark, +#footer { + font-family: Candara,Arial,sans-serif; +} + + +#toc a { + border-bottom: 1px dotted #999999; + color: #3A3A4D !important; + text-decoration: none !important; +} +#toc a:hover { + border-bottom: 1px solid #6D4100; + color: #6D4100 !important; + text-decoration: none !important; +} +a { color: #666688; text-decoration: none; border-bottom: 1px dotted #666688; } +a:visited { color: #615FA0; border-bottom: 1px dotted #615FA0; } +a:hover { color: #6D4100; border-bottom: 1px solid #6D4100; } + +em { + font-style: italic; + color: #444466; +} + +strong { + font-weight: bold; + color: #444466; +} + +h1, h2, h3, h4, h5, h6 { + color: #666688; + margin-bottom: 0.5em; + line-height: 1.3; + letter-spacing:+0.15em; +} + +h1, h2, h3 { border-bottom: 2px solid #ccd; } +h2 { padding-top: 0.5em; } +h3 { float: left; } +h3 + * { clear: left; } + +div.sectionbody { + margin-left: 0; +} + +hr { + border: 1px solid #444466; +} + +p { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +ul, ol, li > p { + margin-top: 0; +} + +pre { + padding: 0; + margin: 0; +} + +#author { + color: #444466; + font-weight: bold; + font-size: 1.1em; +} + +#footer { + font-size: small; + border-top: 2px solid silver; + padding-top: 0.5em; + margin-top: 4.0em; +} + +#footer-text { + float: left; + padding-bottom: 0.5em; +} + +#footer-badges { + float: right; + padding-bottom: 0.5em; +} + +#preamble { + margin-top: 1.5em; + margin-bottom: 1.5em; +} + +div.tableblock, div.imageblock, div.exampleblock, div.verseblock, +div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock, +div.admonitionblock { + margin-top: 1.5em; + margin-bottom: 1.5em; +} + +div.admonitionblock { + margin-top: 2.5em; + margin-bottom: 2.5em; +} + +div.content { /* Block element content. */ + padding: 0; +} + +/* Block element titles. */ +div.title, caption.title { + color: #444466; + font-weight: bold; + text-align: left; + margin-top: 1.0em; + margin-bottom: 0.5em; +} +div.title + * { + margin-top: 0; +} + +td div.title:first-child { + margin-top: 0.0em; +} +div.content div.title:first-child { + margin-top: 0.0em; +} +div.content + div.title { + margin-top: 0.0em; +} + +div.sidebarblock > div.content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} + +div.listingblock > div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock { + padding-left: 2.0em; + margin-right: 10%; +} +div.quoteblock > div.attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock { + padding-left: 2.0em; + margin-right: 10%; +} +div.verseblock > pre.content { + font-family: inherit; +} +div.verseblock > div.attribution { + padding-top: 0.75em; + text-align: left; +} +/* DEPRECATED: Pre version 8.2.7 verse style literal block. */ +div.verseblock + div.attribution { + text-align: left; +} + +div.admonitionblock .icon { + vertical-align: top; + font-size: 1.1em; + font-weight: bold; + text-decoration: underline; + color: #444466; + padding-right: 0.5em; +} +div.admonitionblock td.content { + padding-left: 0.5em; + border-left: 2px solid silver; +} + +div.exampleblock > div.content { + border-left: 2px solid silver; + padding: 0.5em; +} + +div.imageblock div.content { padding-left: 0; } +span.image img { border-style: none; } +a.image:visited { color: white; } + +dl { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +dt { + margin-top: 0.5em; + margin-bottom: 0; + font-style: normal; + color: #444466; +} +dd > *:first-child { + margin-top: 0.1em; +} + +ul, ol { + list-style-position: outside; +} +ol.arabic { + list-style-type: decimal; +} +ol.loweralpha { + list-style-type: lower-alpha; +} +ol.upperalpha { + list-style-type: upper-alpha; +} +ol.lowerroman { + list-style-type: lower-roman; +} +ol.upperroman { + list-style-type: upper-roman; +} + +div.compact ul, div.compact ol, +div.compact p, div.compact p, +div.compact div, div.compact div { + margin-top: 0.1em; + margin-bottom: 0.1em; +} + +div.tableblock > table { + border: 3px solid #444466; +} +thead { + font-weight: bold; + color: #444466; +} +tfoot { + font-weight: bold; +} +td > div.verse { + white-space: pre; +} +p.table { + margin-top: 0; +} +/* Because the table frame attribute is overriden by CSS in most browsers. */ +div.tableblock > table[frame="void"] { + border-style: none; +} +div.tableblock > table[frame="hsides"] { + border-left-style: none; + border-right-style: none; +} +div.tableblock > table[frame="vsides"] { + border-top-style: none; + border-bottom-style: none; +} + + +div.hdlist { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +div.hdlist tr { + padding-bottom: 15px; +} +dt.hdlist1.strong, td.hdlist1.strong { + font-weight: bold; +} +td.hdlist1 { + vertical-align: top; + font-style: normal; + padding-right: 0.8em; + color: #444466; +} +td.hdlist2 { + vertical-align: top; +} +div.hdlist.compact tr { + margin: 0; + padding-bottom: 0; +} + +.comment { + background: yellow; +} + +@media print { + #footer-badges { display: none; } +} + +#toctitle { + color: #666688; + font-size: 1.2em; + font-weight: bold; + margin-top: 1.0em; + margin-bottom: 0.1em; +} + +div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 { margin-top: 0; margin-bottom: 0; } +div.toclevel1 { margin-top: 0.3em; margin-left: 0; font-size: 1.0em; } +div.toclevel2 { margin-top: 0.25em; margin-left: 2em; font-size: 0.9em; } +div.toclevel3 { margin-left: 4em; font-size: 0.8em; } +div.toclevel4 { margin-left: 6em; font-size: 0.8em; } + +body { + margin: 1em 5%; + max-width: 55em; + padding-left: 0; + +} + +.monospaced, tt, div.listingblock > div.content { + font-family: Consolas, "Andale Mono", "Courier New", monospace; + color: #004400; + background: #f4f4f4; + max-width: 80em; + line-height: 1.2em; +} + +.paragraph p { + line-height: 1.5em; + margin-top: 1em; +} + +.paragraph p, li, dd, .content { max-width: 45em; } +.admonitionblock { max-width: 35em; } + +div.sectionbody div.ulist > ul > li { + list-style-type: square; + color: #aaa; +} + div.sectionbody div.ulist > ul > li > * { + color: black; + /*font-size: 50%;*/ + } + + +div.sectionbody div.ulist > ul > li div.ulist > ul > li { + color: #ccd ; +} + div.sectionbody div.ulist > ul > li div.ulist > ul > li > * { + color: black ; + } + +em { + font-style: normal ! important; + font-weight: bold ! important; + color: #662222 ! important; + letter-spacing:+0.08em ! important; +} + + +/* + * html5 specific + * + * */ + +table.tableblock { + margin-top: 1.0em; + margin-bottom: 1.5em; +} +thead, p.tableblock.header { + font-weight: bold; + color: #666688; +} +p.tableblock { + margin-top: 0; +} +table.tableblock { + border-width: 3px; + border-spacing: 0px; + border-style: solid; + border-color: #444466; + border-collapse: collapse; +} +th.tableblock, td.tableblock { + border-width: 1px; + padding: 4px; + border-style: solid; + border-color: #444466; +} + +table.tableblock.frame-topbot { + border-left-style: hidden; + border-right-style: hidden; +} +table.tableblock.frame-sides { + border-top-style: hidden; + border-bottom-style: hidden; +} +table.tableblock.frame-none { + border-style: hidden; +} + +th.tableblock.halign-left, td.tableblock.halign-left { + text-align: left; +} +th.tableblock.halign-center, td.tableblock.halign-center { + text-align: center; +} +th.tableblock.halign-right, td.tableblock.halign-right { + text-align: right; +} + +th.tableblock.valign-top, td.tableblock.valign-top { + vertical-align: top; +} +th.tableblock.valign-middle, td.tableblock.valign-middle { + vertical-align: middle; +} +th.tableblock.valign-bottom, td.tableblock.valign-bottom { + vertical-align: bottom; +} + + diff --git a/doc/stylesheets/xhtml11-quirks.css b/doc/stylesheets/xhtml11-quirks.css new file mode 100644 index 00000000..b3b46d2a --- /dev/null +++ b/doc/stylesheets/xhtml11-quirks.css @@ -0,0 +1,43 @@ +/* Workarounds for IE6's broken and incomplete CSS2. */ + +div.sidebar-content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} +div.sidebar-title, div.image-title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + margin-top: 0.0em; + margin-bottom: 0.5em; +} + +div.listingblock div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock-attribution { + padding-top: 0.5em; + text-align: right; +} + +pre.verseblock-content { + font-family: inherit; +} +div.verseblock-attribution { + padding-top: 0.75em; + text-align: left; +} + +div.exampleblock-content { + border-left: 3px solid #dddddd; + padding-left: 0.5em; +} + +div.imageblock.latex div.image-title { margin-top: 0.5em; } + +/* IE6 sets dynamically generated links as visited. */ +div#toc a:visited { color: blue; } diff --git a/doc/stylesheets/xhtml11.css b/doc/stylesheets/xhtml11.css new file mode 100644 index 00000000..1e6bf5a4 --- /dev/null +++ b/doc/stylesheets/xhtml11.css @@ -0,0 +1,333 @@ +/* Debug borders */ +p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 { +/* + border: 1px solid red; +*/ +} + +body { + margin: 1em 5% 1em 5%; +} + +a { + color: blue; + text-decoration: underline; +} +a:visited { + color: fuchsia; +} + +em { + font-style: italic; + color: navy; +} + +strong { + font-weight: bold; + color: #083194; +} + +tt { + color: navy; +} + +h1, h2, h3, h4, h5, h6 { + color: #527bbd; + font-family: sans-serif; + margin-top: 1.2em; + margin-bottom: 0.5em; + line-height: 1.3; +} + +h1, h2, h3 { + border-bottom: 2px solid silver; +} +h2 { + padding-top: 0.5em; +} +h3 { + float: left; +} +h3 + * { + clear: left; +} + +div.sectionbody { + font-family: serif; + margin-left: 0; +} + +hr { + border: 1px solid silver; +} + +p { + margin-top: 0.5em; + margin-bottom: 0.5em; +} + +ul, ol, li > p { + margin-top: 0; +} + +pre { + padding: 0; + margin: 0; +} + +span#author { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + font-size: 1.1em; +} +span#email { +} +span#revnumber, span#revdate, span#revremark { + font-family: sans-serif; +} + +div#footer { + font-family: sans-serif; + font-size: small; + border-top: 2px solid silver; + padding-top: 0.5em; + margin-top: 4.0em; +} +div#footer-text { + float: left; + padding-bottom: 0.5em; +} +div#footer-badges { + float: right; + padding-bottom: 0.5em; +} + +div#preamble { + margin-top: 1.5em; + margin-bottom: 1.5em; +} +div.tableblock, div.imageblock, div.exampleblock, div.verseblock, +div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock, +div.admonitionblock { + margin-top: 1.5em; + margin-bottom: 1.5em; +} +div.admonitionblock { + margin-top: 2.5em; + margin-bottom: 2.5em; +} + +div.content { /* Block element content. */ + padding: 0; +} + +/* Block element titles. */ +div.title, caption.title { + color: #527bbd; + font-family: sans-serif; + font-weight: bold; + text-align: left; + margin-top: 1.0em; + margin-bottom: 0.5em; +} +div.title + * { + margin-top: 0; +} + +td div.title:first-child { + margin-top: 0.0em; +} +div.content div.title:first-child { + margin-top: 0.0em; +} +div.content + div.title { + margin-top: 0.0em; +} + +div.sidebarblock > div.content { + background: #ffffee; + border: 1px solid silver; + padding: 0.5em; +} + +div.listingblock > div.content { + border: 1px solid silver; + background: #f4f4f4; + padding: 0.5em; +} + +div.quoteblock { + padding-left: 2.0em; + margin-right: 10%; +} +div.quoteblock > div.attribution { + padding-top: 0.5em; + text-align: right; +} + +div.verseblock { + padding-left: 2.0em; + margin-right: 10%; +} +div.verseblock > div.content { + white-space: pre; +} +div.verseblock > div.attribution { + padding-top: 0.75em; + text-align: left; +} +/* DEPRECATED: Pre version 8.2.7 verse style literal block. */ +div.verseblock + div.attribution { + text-align: left; +} + +div.admonitionblock .icon { + vertical-align: top; + font-size: 1.1em; + font-weight: bold; + text-decoration: underline; + color: #527bbd; + padding-right: 0.5em; +} +div.admonitionblock td.content { + padding-left: 0.5em; + border-left: 2px solid silver; +} + +div.exampleblock > div.content { + border-left: 2px solid silver; + padding: 0.5em; +} + +div.imageblock div.content { padding-left: 0; } +span.image img { border-style: none; } +a.image:visited { color: white; } + +dl { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +dt { + margin-top: 0.5em; + margin-bottom: 0; + font-style: normal; + color: navy; +} +dd > *:first-child { + margin-top: 0.1em; +} + +ul, ol { + list-style-position: outside; +} +ol.arabic { + list-style-type: decimal; +} +ol.loweralpha { + list-style-type: lower-alpha; +} +ol.upperalpha { + list-style-type: upper-alpha; +} +ol.lowerroman { + list-style-type: lower-roman; +} +ol.upperroman { + list-style-type: upper-roman; +} + +div.compact ul, div.compact ol, +div.compact p, div.compact p, +div.compact div, div.compact div { + margin-top: 0.1em; + margin-bottom: 0.1em; +} + +div.tableblock > table { + border: 3px solid #527bbd; +} +thead { + font-family: sans-serif; + font-weight: bold; +} +tfoot { + font-weight: bold; +} +td > div.verse { + white-space: pre; +} +p.table { + margin-top: 0; +} +/* Because the table frame attribute is overriden by CSS in most browsers. */ +div.tableblock > table[frame="void"] { + border-style: none; +} +div.tableblock > table[frame="hsides"] { + border-left-style: none; + border-right-style: none; +} +div.tableblock > table[frame="vsides"] { + border-top-style: none; + border-bottom-style: none; +} + + +div.hdlist { + margin-top: 0.8em; + margin-bottom: 0.8em; +} +div.hdlist tr { + padding-bottom: 15px; +} +dt.hdlist1.strong, td.hdlist1.strong { + font-weight: bold; +} +td.hdlist1 { + vertical-align: top; + font-style: normal; + padding-right: 0.8em; + color: navy; +} +td.hdlist2 { + vertical-align: top; +} +div.hdlist.compact tr { + margin: 0; + padding-bottom: 0; +} + +.comment { + background: yellow; +} + +@media print { + div#footer-badges { display: none; } +} + +div#toctitle { + color: #527bbd; + font-family: sans-serif; + font-size: 1.1em; + font-weight: bold; + margin-top: 1.0em; + margin-bottom: 0.1em; +} + +div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 { + margin-top: 0; + margin-bottom: 0; +} +div.toclevel2 { + margin-left: 2em; + font-size: 0.9em; +} +div.toclevel3 { + margin-left: 4em; + font-size: 0.9em; +} +div.toclevel4 { + margin-left: 6em; + font-size: 0.9em; +} |