documentation updates

This commit is contained in:
Thomas Graf 2011-07-14 12:48:00 +02:00
parent 21d52eabba
commit 63548f5664
28 changed files with 758 additions and 384 deletions

View file

@ -642,7 +642,7 @@ EXCLUDE_SYMBOLS =
# directories that contain example code fragments that are included (see
# the \include command).
EXAMPLE_PATH = src/examples
EXAMPLE_PATH = 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

View file

@ -1,17 +1,25 @@
# -*- Makefile -*-
.PHONY: gendoc
.PHONY: gendoc api_refs asciidoc
ASCIIDOCOPTS=-n -a pygments -a toc -a language=c -a icons \
ASCIIDOCOPTS=-a pygments -a language=c -a icons \
-a imagesdir="images/" \
-a stylesdir="${abs_srcdir}/stylesheets/"
gendoc:
%.html: %.txt
asciidoc $(ASCIIDOCOPTS) $<
./doxygen-link.py libnl.dict $@ > doxygen-link.tmp
mv doxygen-link.tmp $@
asciidoc: core.html route.html index.html link.html
api_ref:
doxygen Doxyfile;
./gen-tags.sh | ./tags2dict.sh > libnl.dict
asciidoc $(ASCIIDOCOPTS) core.txt
./doxygen-link.py libnl.dict core.html > core.tmp.html
mv core.tmp.html core.html
distclean-local:
rm -f api/* libnl.tags *.html;
gendoc:
$(MAKE) api_ref
$(MAKE) asciidoc
clean-local:
rm -f api/* libnl.dict *.html;

View file

@ -8,6 +8,8 @@ Netlink Core Library
====================
Thomas Graf <tgraf@suug.ch>
3.0, March 30 2011:
:toc:
:numbered:
== Introduction

16
doc/index.txt Normal file
View file

@ -0,0 +1,16 @@
libnl
=====
Thomas Graf <tgraf@suug.ch>
3.0, April 12 2011:
== Table of Contents
=== Libraries
- link:core.html[Core Library]
- link:route.html[Routing Family]
=== Tools
- link:link.html[Link Utility]
=== Python Packages
- netlink.core
- netlink.route.link

720
doc/route.txt Normal file
View file

@ -0,0 +1,720 @@
////
vim.syntax: asciidoc
Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
////
Netlink Routing Library
=======================
Thomas Graf <tgraf@suug.ch>
3.0, March 23 2011:
:toc:
:icons:
:numbered:
== Introduction
== Introduction to the Library
== Addresses
== Links / Interfaces
== Neighbouring
== Routing
== 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
[cols="a,a", options="header", frame="topbot"]
|====================================================================
| Attribute | C Interface
|
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);
-----
|
IfIndex::
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);
-----
|
LinkType::
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, Accessing Statistics>> 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, traffic control
object attributes>>.
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
[cols="a,a", options="header", frame="topbot"]
|====================================================================
| Attribute | C Interface
|
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
[cols="a,a", options="header", frame="topbot"]
|====================================================================
| Attribute | C Interface
|
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)
[[tc_classid_mngt]]
=== ClassID Management
[[tc_pktloc]]
=== Packet Location Aliasing (pktloc)
[[tc_api]]
=== Traffic Control Module API

View file

@ -1,15 +0,0 @@
#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;
}

View file

@ -1,51 +0,0 @@
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;
}

View file

@ -1,50 +0,0 @@
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;
}

View file

@ -1,11 +0,0 @@
#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);
}
}

View file

@ -1,14 +0,0 @@
#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);

View file

@ -1,11 +0,0 @@
#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));

View file

@ -1,7 +0,0 @@
/* 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 */

View file

@ -1,11 +0,0 @@
#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 */

View file

@ -1,16 +0,0 @@
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:
return -EMSGSIZE;
}

View file

@ -1,10 +0,0 @@
#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);
};

View file

@ -1,12 +0,0 @@
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]);
}

View file

@ -1,14 +0,0 @@
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);
}

View file

@ -1,7 +0,0 @@
#include <netlink/msg.h>
struct nlmsghdr *hdr;
nlmsg_for_each(hdr, stream, length) {
/* do something with message */
}

View file

@ -1,29 +0,0 @@
#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]));
}
}

View file

@ -1,31 +0,0 @@
#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 |
* +--------+---------+
*/

View file

@ -1,43 +0,0 @@
#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);
/*
* 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);

View file

@ -1,10 +0,0 @@
/**
* \cond skip
* vim:syntax=doxygen
* \endcond
\page genl_doc Generic Netlink Library (-lnl-genl)
\section genl_intro Introduction
*/

View file

@ -1,10 +0,0 @@
/**
* \cond skip
* vim:syntax=doxygen
* \endcond
\page nf_doc Netfilter Netlink Library (-lnl-nf)
\section nf_intro Introduction
*/

View file

@ -1,10 +0,0 @@
/**
* \cond skip
* vim:syntax=doxygen
* \endcond
\page route_doc Routing Netlink Library (-lnl-route)
\section route_intro Introduction
*/

View file

@ -13,7 +13,7 @@ provide APIs on different levels of abstraction. The core library libnl.so
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. \ref route_doc "nl-route.so", \ref genl_doc "nl-genl.so", ...).
libraries (e.g. "nl-route.so", "nl-genl.so", ...).
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
@ -28,11 +28,6 @@ version is used with a considerably older kernel.
\section main_toc Table of Contents
- \subpage core_doc "1. Netlink Core Library (-lnl)"
- \subpage route_doc "2. Routing Netlink Library (-lnl-route)"
- \subpage genl_doc "3. Generic Netlink Library (-lnl-genl)"
- \subpage nf_doc "4. Netfilter Netlink Library (-lnl-nf)"
\section main_trees GIT Trees
\subsection tree_dev Development Tree

View file

@ -181,8 +181,6 @@ static void __init init_msg_size(void)
* Calculates size of netlink message based on payload length.
* @arg payload Length of payload
*
* See \ref core_msg_fmt_align for more information on alignment.
*
* @return size of netlink message without padding.
*/
int nlmsg_size(int payload)
@ -201,8 +199,6 @@ int nlmsg_msg_size(int payload)
*
* This function is idential to nlmsg_size() + nlmsg_padlen().
*
* See \ref core_msg_fmt_align for more information on alignment.
*
* @return Size of netlink message including padding.
*/
int nlmsg_total_size(int payload)
@ -218,8 +214,6 @@ int nlmsg_total_size(int payload)
* the end of the message to ensure that the next netlink message header begins
* properly aligned to NLMSG_ALIGNTO.
*
* See \ref core_msg_fmt_align for more information on alignment.
*
* @return Number of bytes of padding needed.
*/
int nlmsg_padlen(int payload)

View file

@ -237,6 +237,7 @@ int rtnl_cls_change(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
/**
* Build netlink message requesting the deletion of a classifier
* @arg cls Classifier to delete
* @arg flags Additional netlink message flags
* @arg result Pointer to store resulting netlink message
*
* The behaviour of this function is identical to rtnl_cls_delete() with
@ -264,6 +265,7 @@ int rtnl_cls_build_delete_request(struct rtnl_cls *cls, int flags,
* Delete classifier
* @arg sk Netlink socket
* @arg cls Classifier to delete
* @arg flags Additional netlink message flags
*
* Builds a \c RTM_DELTFILTER netlink message requesting the deletion
* of a classifier and sends the message to the kernel.

View file

@ -307,7 +307,6 @@ void rtnl_tc_set_link(struct rtnl_tc *tc, struct rtnl_link *link)
/**
* Get link of traffic control object
* @arg tc traffic control object
* @arg link link object
*
* Returns the link of a traffic control object. The link is only
* returned if it has been set before via rtnl_tc_set_link() or