summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2011-03-29 12:41:59 +0200
committerThomas Graf <tgraf@suug.ch>2011-03-29 12:41:59 +0200
commit7c620500bbca24c3d18b731756c375a45bb0fcba (patch)
treef5a507f13dc3039bff8e5fabcf054fbbc9a3adde
parent747b892c91de7a852664f015405d6d37ea2b66b6 (diff)
downloadlibnl-7c620500bbca24c3d18b731756c375a45bb0fcba.tar.gz
trafic class/classifer API improvements and documentation
- removed dead functions in header files - deprecated rtnl_class_foreach_*() functions due to their missing handling possibility of OOM situations - improved API documentation
-rw-r--r--include/netlink/route/class.h32
-rw-r--r--include/netlink/route/classifier.h33
-rw-r--r--lib/route/class.c368
-rw-r--r--lib/route/cls.c186
-rw-r--r--src/nl-tctree-list.c8
5 files changed, 361 insertions, 266 deletions
diff --git a/include/netlink/route/class.h b/include/netlink/route/class.h
index ad3bacf..e73b60a 100644
--- a/include/netlink/route/class.h
+++ b/include/netlink/route/class.h
@@ -1,12 +1,12 @@
/*
- * netlink/route/class.h Classes
+ * netlink/route/class.h Traffic Classes
*
* 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-2008 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
*/
#ifndef NETLINK_CLASS_H_
@@ -22,14 +22,17 @@ extern "C" {
struct rtnl_class;
-extern struct rtnl_class * rtnl_class_alloc(void);
+extern struct rtnl_class *
+ rtnl_class_alloc(void);
extern void rtnl_class_put(struct rtnl_class *);
+
extern int rtnl_class_alloc_cache(struct nl_sock *, int,
struct nl_cache **);
-extern struct rtnl_class *rtnl_class_get(struct nl_cache *, int, uint32_t);
+extern struct rtnl_class *
+ rtnl_class_get(struct nl_cache *, int, uint32_t);
-/* leaf qdisc access */
-extern struct rtnl_qdisc * rtnl_class_leaf_qdisc(struct rtnl_class *,
+extern struct rtnl_qdisc *
+ rtnl_class_leaf_qdisc(struct rtnl_class *,
struct nl_cache *);
extern int rtnl_class_build_add_request(struct rtnl_class *, int,
@@ -37,23 +40,24 @@ extern int rtnl_class_build_add_request(struct rtnl_class *, int,
extern int rtnl_class_add(struct nl_sock *, struct rtnl_class *,
int);
-extern int rtnl_class_build_delete_request(struct rtnl_class *,
- struct nl_msg **);
-extern int rtnl_class_delete(struct nl_sock *, struct rtnl_class *);
-
-extern void rtnl_class_set_kind(struct rtnl_class *, const char *);
+extern int rtnl_class_build_delete_request(struct rtnl_class *,
+ struct nl_msg **);
+extern int rtnl_class_delete(struct nl_sock *,
+ struct rtnl_class *);
-/* iterators */
+/* deprecated functions */
extern void rtnl_class_foreach_child(struct rtnl_class *,
struct nl_cache *,
void (*cb)(struct nl_object *,
void *),
- void *);
+ void *)
+ __attribute__((deprecated));
extern void rtnl_class_foreach_cls(struct rtnl_class *,
struct nl_cache *,
void (*cb)(struct nl_object *,
void *),
- void *);
+ void *)
+ __attribute__((deprecated));
#ifdef __cplusplus
}
diff --git a/include/netlink/route/classifier.h b/include/netlink/route/classifier.h
index 23af837..647bf1e 100644
--- a/include/netlink/route/classifier.h
+++ b/include/netlink/route/classifier.h
@@ -6,7 +6,7 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
- * Copyright (c) 2003-2010 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
*/
#ifndef NETLINK_CLASSIFIER_H_
@@ -22,26 +22,27 @@ extern "C" {
#endif
extern struct rtnl_cls *rtnl_cls_alloc(void);
-extern void rtnl_cls_put(struct rtnl_cls *);
+extern void rtnl_cls_put(struct rtnl_cls *);
-extern int rtnl_cls_alloc_cache(struct nl_sock *, int, uint32_t,
- struct nl_cache **);
+extern int rtnl_cls_alloc_cache(struct nl_sock *, int, uint32_t,
+ struct nl_cache **);
-extern int rtnl_cls_build_add_request(struct rtnl_cls *, int,
- struct nl_msg **);
-extern int rtnl_cls_add(struct nl_sock *, struct rtnl_cls *, int);
+extern int rtnl_cls_build_add_request(struct rtnl_cls *, int,
+ struct nl_msg **);
+extern int rtnl_cls_add(struct nl_sock *, struct rtnl_cls *, int);
-extern int rtnl_cls_build_change_request(struct rtnl_cls *, int,
- struct nl_msg **);
-extern int rtnl_cls_build_delete_request(struct rtnl_cls *, int,
- struct nl_msg **);
-extern int rtnl_cls_delete(struct nl_sock *, struct rtnl_cls *, int);
+extern int rtnl_cls_build_change_request(struct rtnl_cls *, int,
+ struct nl_msg **);
+extern int rtnl_cls_build_delete_request(struct rtnl_cls *, int,
+ struct nl_msg **);
+extern int rtnl_cls_delete(struct nl_sock *, struct rtnl_cls *,
+ int);
-extern void rtnl_cls_set_prio(struct rtnl_cls *, uint16_t);
-extern uint16_t rtnl_cls_get_prio(struct rtnl_cls *);
+extern void rtnl_cls_set_prio(struct rtnl_cls *, uint16_t);
+extern uint16_t rtnl_cls_get_prio(struct rtnl_cls *);
-extern void rtnl_cls_set_protocol(struct rtnl_cls *, uint16_t);
-extern uint16_t rtnl_cls_get_protocol(struct rtnl_cls *);
+extern void rtnl_cls_set_protocol(struct rtnl_cls *, uint16_t);
+extern uint16_t rtnl_cls_get_protocol(struct rtnl_cls *);
#ifdef __cplusplus
}
diff --git a/lib/route/class.c b/lib/route/class.c
index a0f3758..2a9606b 100644
--- a/lib/route/class.c
+++ b/lib/route/class.c
@@ -1,17 +1,17 @@
/*
- * lib/route/class.c Queueing Classes
+ * lib/route/class.c Traffic Classes
*
* 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-2010 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
*/
/**
* @ingroup tc
- * @defgroup class Queueing Classes
+ * @defgroup class Traffic Classes
* @{
*/
@@ -69,52 +69,104 @@ static int class_request_update(struct nl_cache *cache, struct nl_sock *sk)
}
/**
- * @name Addition/Modification
+ * @name Allocation/Freeing
+ * @{
+ */
+
+struct rtnl_class *rtnl_class_alloc(void)
+{
+ struct rtnl_tc *tc;
+
+ tc = TC_CAST(nl_object_alloc(&class_obj_ops));
+ if (tc)
+ tc->tc_type = RTNL_TC_TYPE_CLASS;
+
+ return (struct rtnl_class *) tc;
+}
+
+void rtnl_class_put(struct rtnl_class *class)
+{
+ nl_object_put((struct nl_object *) class);
+}
+
+/** @} */
+
+
+/**
+ * @name Addition/Modification/Deletion
* @{
*/
static int class_build(struct rtnl_class *class, int type, int flags,
struct nl_msg **result)
{
+ int needed = TCA_ATTR_PARENT | TCA_ATTR_HANDLE;
+
+ if ((class->ce_mask & needed) == needed &&
+ TC_H_MAJ(class->c_parent) && TC_H_MAJ(class->c_handle) &&
+ TC_H_MAJ(class->c_parent) != TC_H_MAJ(class->c_handle)) {
+ APPBUG("TC_H_MAJ(parent) must match TC_H_MAJ(handle)");
+ return -NLE_INVAL;
+ }
+
return rtnl_tc_msg_build(TC_CAST(class), type, flags, result);
}
/**
- * Build a netlink message to add a new class
- * @arg class class to add
- * @arg flags additional netlink message flags
- * @arg result Pointer to store resulting message.
+ * Build a netlink message requesting the addition of a traffic class
+ * @arg class Traffic class to add
+ * @arg flags Additional netlink message flags
+ * @arg result Pointer to store resulting netlink message
*
- * Builds a new netlink message requesting an addition of a class.
- * The netlink message header isn't fully equipped with all relevant
- * fields and must be sent out via nl_send_auto_complete() or
- * supplemented as needed.
+ * The behaviour of this function is identical to rtnl_class_add() with
+ * the exception that it will not send the message but return it int the
+ * provided return pointer instead.
*
- * Common message flags
- * - NLM_F_REPLACE - replace possibly existing classes
+ * @see rtnl_class_add()
*
* @return 0 on success or a negative error code.
*/
int rtnl_class_build_add_request(struct rtnl_class *class, int flags,
struct nl_msg **result)
{
- return class_build(class, RTM_NEWTCLASS, NLM_F_CREATE | flags, result);
+ return class_build(class, RTM_NEWTCLASS, flags, result);
}
/**
- * Add a new class
- * @arg sk Netlink socket.
- * @arg class class to delete
- * @arg flags additional netlink message flags
+ * Add/Update traffic class
+ * @arg sk Netlink socket
+ * @arg class Traffic class to add
+ * @arg flags Additional netlink message flags
+ *
+ * Builds a \c RTM_NEWTCLASS netlink message requesting the addition
+ * of a new traffic class and sends the message to the kernel. The
+ * configuration of the traffic class is derived from the attributes
+ * of the specified traffic class.
*
- * Builds a netlink message by calling rtnl_qdisc_build_add_request(),
- * sends the request to the kernel and waits for the next ACK to be
- * received and thus blocks until the request has been processed.
+ * The following flags may be specified:
+ * - \c NLM_F_CREATE: Create traffic class if it does not exist,
+ * otherwise -NLE_OBJ_NOTFOUND is returned.
+ * - \c NLM_F_EXCL: Return -NLE_EXISTS if a traffic class with
+ * matching handle exists already.
*
- * Common message flags
- * - NLM_F_REPLACE - replace possibly existing classes
+ * Existing traffic classes with matching handles will be updated,
+ * unless the flag \c NLM_F_EXCL is specified. If no matching traffic
+ * class exists, it will be created if the flag \c NLM_F_CREATE is set,
+ * otherwise the error -NLE_OBJ_NOTFOUND is returned.
*
- * @return 0 on success or a negative error code
+ * If the parent qdisc does not support classes, the error
+ * \c NLE_OPNOTSUPP is returned.
+ *
+ * After sending, the function will wait for the ACK or an eventual
+ * error message to be received and will therefore block until the
+ * operation has been completed.
+ *
+ * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
+ * this function to return immediately after sending. In this case,
+ * it is the responsibility of the caller to handle any error
+ * messages returned.
+ *
+ * @return 0 on success or a negative error code.
*/
int rtnl_class_add(struct nl_sock *sk, struct rtnl_class *class, int flags)
{
@@ -124,32 +176,44 @@ int rtnl_class_add(struct nl_sock *sk, struct rtnl_class *class, int flags)
if ((err = rtnl_class_build_add_request(class, flags, &msg)) < 0)
return err;
- err = nl_send_auto_complete(sk, msg);
- nlmsg_free(msg);
- if (err < 0)
- return err;
-
- return wait_for_ack(sk);
+ return nl_send_sync(sk, msg);
}
-int rtnl_class_build_delete_request(struct rtnl_class *class,
- struct nl_msg **result)
+/**
+ * Build netlink message requesting the deletion of a traffic class
+ * @arg class Traffic class to delete
+ * @arg result Pointer to store resulting netlink message
+ *
+ * The behaviour of this function is identical to rtnl_class_delete() with
+ * the exception that it will not send the message but return it in the
+ * provided return pointer instead.
+ *
+ * @see rtnl_class_delete()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_class_build_delete_request(struct rtnl_class *class, struct nl_msg **result)
{
struct nl_msg *msg;
struct tcmsg tchdr;
- int required = TCA_ATTR_IFINDEX | TCA_ATTR_PARENT;
+ int required = TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE;
- if ((class->ce_mask & required) != required)
- BUG();
+ if ((class->ce_mask & required) != required) {
+ APPBUG("ifindex and handle must be specified");
+ return -NLE_MISSING_ATTR;
+ }
- msg = nlmsg_alloc_simple(RTM_DELTCLASS, 0);
- if (!msg)
+ if (!(msg = nlmsg_alloc_simple(RTM_DELTCLASS, 0)))
return -NLE_NOMEM;
+ memset(&tchdr, 0, sizeof(tchdr));
tchdr.tcm_family = AF_UNSPEC;
- tchdr.tcm_handle = class->c_handle;
- tchdr.tcm_parent = class->c_parent;
tchdr.tcm_ifindex = class->c_ifindex;
+ tchdr.tcm_handle = class->c_handle;
+
+ if (class->ce_mask & TCA_ATTR_PARENT)
+ tchdr.tcm_parent = class->c_parent;
+
if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0) {
nlmsg_free(msg);
return -NLE_MSGSIZE;
@@ -160,15 +224,30 @@ int rtnl_class_build_delete_request(struct rtnl_class *class,
}
/**
- * Delete a class
- * @arg sk Netlink socket.
- * @arg class class to delete
+ * Delete traffic class
+ * @arg sk Netlink socket
+ * @arg class Traffic class to delete
+ *
+ * Builds a \c RTM_DELTCLASS netlink message requesting the deletion
+ * of a traffic class and sends the message to the kernel.
+ *
+ * The message is constructed out of the following attributes:
+ * - \c ifindex and \c handle (required)
+ * - \c parent (optional, must match if provided)
*
- * Builds a netlink message by calling rtnl_class_build_delete_request(),
- * sends the request to the kernel and waits for the ACK to be
- * received and thus blocks until the request has been processed.
+ * All other class attributes including all class type specific
+ * attributes are ignored.
*
- * @return 0 on success or a negative error code
+ * After sending, the function will wait for the ACK or an eventual
+ * error message to be received and will therefore block until the
+ * operation has been completed.
+ *
+ * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
+ * this function to return immediately after sending. In this case,
+ * it is the responsibility of the caller to handle any error
+ * messages returned.
+ *
+ * @return 0 on success or a negative error code.
*/
int rtnl_class_delete(struct nl_sock *sk, struct rtnl_class *class)
{
@@ -178,35 +257,7 @@ int rtnl_class_delete(struct nl_sock *sk, struct rtnl_class *class)
if ((err = rtnl_class_build_delete_request(class, &msg)) < 0)
return err;
- err = nl_send_auto_complete(sk, msg);
- nlmsg_free(msg);
- if (err < 0)
- return err;
-
- return wait_for_ack(sk);
-}
-
-/** @} */
-
-/**
- * @name Allocation/Freeing
- * @{
- */
-
-struct rtnl_class *rtnl_class_alloc(void)
-{
- struct rtnl_tc *tc;
-
- tc = TC_CAST(nl_object_alloc(&class_obj_ops));
- if (tc)
- tc->tc_type = RTNL_TC_TYPE_CLASS;
-
- return (struct rtnl_class *) tc;
-}
-
-void rtnl_class_put(struct rtnl_class *class)
-{
- nl_object_put((struct nl_object *) class);
+ return nl_send_sync(sk, msg);
}
/** @} */
@@ -217,11 +268,11 @@ void rtnl_class_put(struct rtnl_class *class)
*/
/**
- * Lookup the leaf qdisc of a class
- * @arg class the parent class
- * @arg cache a qdisc cache including at laest all qdiscs of the
- * interface the specified class is attached to
- * @return The qdisc from the cache or NULL if the class has no leaf qdisc
+ * Lookup the leaf qdisc of a traffic class
+ * @arg class the parent traffic class
+ * @arg cache a qdisc cache allocated using rtnl_qdisc_alloc_cache()
+ *
+ * @return Matching Qdisc or NULL if the traffic class has no leaf qdisc
*/
struct rtnl_qdisc *rtnl_class_leaf_qdisc(struct rtnl_class *class,
struct nl_cache *cache)
@@ -241,78 +292,20 @@ struct rtnl_qdisc *rtnl_class_leaf_qdisc(struct rtnl_class *class,
/** @} */
-
/**
- * @name Iterators
+ * @name Cache Related Functions
* @{
*/
/**
- * Call a callback for each child of a class
- * @arg class the parent class
- * @arg cache a class cache including all classes of the interface
- * the specified class is attached to
- * @arg cb callback function
- * @arg arg argument to be passed to callback function
- */
-void rtnl_class_foreach_child(struct rtnl_class *class, struct nl_cache *cache,
- void (*cb)(struct nl_object *, void *), void *arg)
-{
- struct rtnl_class *filter;
-
- filter = rtnl_class_alloc();
- if (!filter)
- return;
-
- rtnl_tc_set_parent(TC_CAST(filter), class->c_handle);
- rtnl_tc_set_ifindex(TC_CAST(filter), class->c_ifindex);
- rtnl_tc_set_kind(TC_CAST(filter), class->c_kind);
-
- nl_cache_foreach_filter(cache, OBJ_CAST(filter), cb, arg);
- rtnl_class_put(filter);
-}
-
-/**
- * Call a callback for each classifier attached to the class
- * @arg class the parent class
- * @arg cache a filter cache including at least all the filters
- * attached to the specified class
- * @arg cb callback function
- * @arg arg argument to be passed to callback function
- */
-void rtnl_class_foreach_cls(struct rtnl_class *class, struct nl_cache *cache,
- void (*cb)(struct nl_object *, void *), void *arg)
-{
- struct rtnl_cls *filter;
-
- filter = rtnl_cls_alloc();
- if (!filter)
- return;
-
- rtnl_tc_set_ifindex((struct rtnl_tc *) filter, class->c_ifindex);
- rtnl_tc_set_parent((struct rtnl_tc *) filter, class->c_parent);
-
- nl_cache_foreach_filter(cache, (struct nl_object *) filter, cb, arg);
- rtnl_cls_put(filter);
-}
-
-/** @} */
-
-
-/**
- * @name Cache Management
- * @{
- */
-
-/**
- * Build a class cache including all classes attached to the specified interface
- * @arg sk Netlink socket.
- * @arg ifindex interface index of the link the classes are
- * attached to.
- * @arg result Result pointer
+ * Allocate a cache and fill it with all configured traffic classes
+ * @arg sk Netlink socket
+ * @arg ifindex Interface index of the network device
+ * @arg result Pointer to store the created cache
*
- * Allocates a new cache, initializes it properly and updates it to
- * include all classes attached to the specified interface.
+ * Allocates a new traffic class cache and fills it with a list of all
+ * configured traffic classes on a specific network device. Release the
+ * cache with nl_cache_free().
*
* @return 0 on success or a negative error code.
*/
@@ -321,9 +314,13 @@ int rtnl_class_alloc_cache(struct nl_sock *sk, int ifindex,
{
struct nl_cache * cache;
int err;
+
+ if (!ifindex) {
+ APPBUG("ifindex must be specified");
+ return -NLE_INVAL;
+ }
- cache = nl_cache_alloc(&rtnl_class_ops);
- if (!cache)
+ if (!(cache = nl_cache_alloc(&rtnl_class_ops)))
return -NLE_NOMEM;
cache->c_iarg1 = ifindex;
@@ -338,14 +335,23 @@ int rtnl_class_alloc_cache(struct nl_sock *sk, int ifindex,
}
/**
- * Look up class by its handle in the provided cache
- * @arg cache class cache
- * @arg ifindex interface the class is attached to
- * @arg handle class handle
- * @return pointer to class inside the cache or NULL if no match was found.
+ * Search traffic class by interface index and handle
+ * @arg cache Traffic class cache
+ * @arg ifindex Interface index
+ * @arg handle ID of traffic class
+ *
+ * Searches a traffic class cache previously allocated with
+ * rtnl_class_alloc_cache() and searches for a traffi class matching
+ * the interface index and handle.
+ *
+ * The reference counter is incremented before returning the traffic
+ * class, therefore the reference must be given back with rtnl_class_put()
+ * after usage.
+ *
+ * @return Traffic class or NULL if no match was found.
*/
struct rtnl_class *rtnl_class_get(struct nl_cache *cache, int ifindex,
- uint32_t handle)
+ uint32_t handle)
{
struct rtnl_class *class;
@@ -363,6 +369,58 @@ struct rtnl_class *rtnl_class_get(struct nl_cache *cache, int ifindex,
/** @} */
+/**
+ * @name Deprecated Functions
+ * @{
+ */
+
+/**
+ * Call a callback for each child of a class
+ *
+ * @deprecated Use of this function is deprecated, it does not allow
+ * to handle the out of memory situation that can occur.
+ */
+void rtnl_class_foreach_child(struct rtnl_class *class, struct nl_cache *cache,
+ void (*cb)(struct nl_object *, void *), void *arg)
+{
+ struct rtnl_class *filter;
+
+ filter = rtnl_class_alloc();
+ if (!filter)
+ return;
+
+ rtnl_tc_set_parent(TC_CAST(filter), class->c_handle);
+ rtnl_tc_set_ifindex(TC_CAST(filter), class->c_ifindex);
+ rtnl_tc_set_kind(TC_CAST(filter), class->c_kind);
+
+ nl_cache_foreach_filter(cache, OBJ_CAST(filter), cb, arg);
+ rtnl_class_put(filter);
+}
+
+/**
+ * Call a callback for each classifier attached to the class
+ *
+ * @deprecated Use of this function is deprecated, it does not allow
+ * to handle the out of memory situation that can occur.
+ */
+void rtnl_class_foreach_cls(struct rtnl_class *class, struct nl_cache *cache,
+ void (*cb)(struct nl_object *, void *), void *arg)
+{
+ struct rtnl_cls *filter;
+
+ filter = rtnl_cls_alloc();
+ if (!filter)
+ return;
+
+ rtnl_tc_set_ifindex((struct rtnl_tc *) filter, class->c_ifindex);
+ rtnl_tc_set_parent((struct rtnl_tc *) filter, class->c_parent);
+
+ nl_cache_foreach_filter(cache, (struct nl_object *) filter, cb, arg);
+ rtnl_cls_put(filter);
+}
+
+/** @} */
+
static struct rtnl_tc_type_ops class_ops = {
.tt_type = RTNL_TC_TYPE_CLASS,
.tt_dump_prefix = "class",
diff --git a/lib/route/cls.c b/lib/route/cls.c
index a041baa..aa79b09 100644
--- a/lib/route/cls.c
+++ b/lib/route/cls.c
@@ -6,21 +6,12 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
- * Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch>
+ * Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
*/
/**
* @ingroup tc
* @defgroup cls Classifiers
- *
- * @par Classifier Identification
- * - protocol
- * - priority
- * - parent
- * - interface
- * - kind
- * - handle
- *
* @{
*/
@@ -46,6 +37,12 @@ static int cls_build(struct rtnl_cls *cls, int type, int flags,
{
int err, prio, proto;
struct tcmsg *tchdr;
+ int required = TCA_ATTR_IFINDEX;
+
+ if ((cls->ce_mask & required) != required) {
+ APPBUG("ifindex must be specified");
+ return -NLE_MISSING_ATTR;
+ }
err = rtnl_tc_msg_build(TC_CAST(cls), type, flags, result);
if (err < 0)
@@ -119,42 +116,70 @@ uint16_t rtnl_cls_get_protocol(struct rtnl_cls *cls)
/**
- * @name Classifier Addition/Modification/Deletion
+ * @name Addition/Modification/Deletion
* @{
*/
/**
- * Build a netlink message to add a new classifier
- * @arg cls classifier to add
- * @arg flags additional netlink message flags
- * @arg result Pointer to store resulting message.
+ * Build a netlink message requesting the addition of a classifier
+ * @arg cls Classifier to add
+ * @arg flags Additional netlink message flags
+ * @arg result Pointer to store resulting netlink message
+ *
+ * The behaviour of this function is identical to rtnl_cls_add() with
+ * the exception that it will not send the message but return it int the
+ * provided return pointer instead.
*
- * Builds a new netlink message requesting an addition of a classifier
- * The netlink message header isn't fully equipped with all relevant
- * fields and must be sent out via nl_send_auto_complete() or
- * supplemented as needed. \a classifier must contain the attributes of
- * the new classifier set via \c rtnl_cls_set_* functions. \a opts
- * may point to the clsasifier specific options.
+ * @see rtnl_cls_add()
*
* @return 0 on success or a negative error code.
*/
int rtnl_cls_build_add_request(struct rtnl_cls *cls, int flags,
struct nl_msg **result)
{
- return cls_build(cls, RTM_NEWTFILTER, NLM_F_CREATE | flags, result);
+ if (!(flags & NLM_F_CREATE) && !(cls->ce_mask & CLS_ATTR_PRIO)) {
+ APPBUG("prio must be specified if not a new classifier");
+ return -NLE_MISSING_ATTR;
+ }
+
+ return cls_build(cls, RTM_NEWTFILTER, flags, result);
}
/**
- * Add a new classifier
- * @arg sk Netlink socket.
- * @arg cls classifier to add
- * @arg flags additional netlink message flags
+ * Add/Update classifier
+ * @arg sk Netlink socket
+ * @arg cls Classifier to add/update
+ * @arg flags Additional netlink message flags
*
- * Builds a netlink message by calling rtnl_cls_build_add_request(),
- * sends the request to the kernel and waits for the next ACK to be
- * received and thus blocks until the request has been processed.
+ * Builds a \c RTM_NEWTFILTER netlink message requesting the addition
+ * of a new classifier and sends the message to the kernel. The
+ * configuration of the classifier is derived from the attributes of
+ * the specified traffic class.
*
- * @return 0 on sucess or a negative error if an error occured.
+ * The following flags may be specified:
+ * - \c NLM_F_CREATE: Create classifier if it does not exist,
+ * otherwise -NLE_OBJ_NOTFOUND is returned.
+ * - \c NLM_F_EXCL: Return -NLE_EXISTS if a classifier with
+ * matching handle exists already.
+ *
+ * Existing classifiers with matching handles will be updated, unless
+ * the flag \c NLM_F_EXCL is specified. If no matching classifier
+ * exists, it will be created if the flag \c NLM_F_CREATE is set,
+ * otherwise the error -NLE_OBJ_NOTFOUND is returned.
+ *
+ * If the parent qdisc does not support classes, the error
+ * \c NLE_OPNOTSUPP is returned.
+ *
+ * After sending, the function will wait for the ACK or an eventual
+ * error message to be received and will therefore block until the
+ * operation has been completed.
+ *
+ * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
+ * this function to return immediately after sending. In this case,
+ * it is the responsibility of the caller to handle any error
+ * messages returned.
+ *
+ * @return 0 on success or a negative error code.
*/
int rtnl_cls_add(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
{
@@ -163,13 +188,8 @@ int rtnl_cls_add(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
if ((err = rtnl_cls_build_add_request(cls, flags, &msg)) < 0)
return err;
-
- err = nl_send_auto_complete(sk, msg);
- nlmsg_free(msg);
- if (err < 0)
- return err;
- return nl_wait_for_ack(sk);
+ return nl_send_sync(sk, msg);
}
/**
@@ -211,45 +231,64 @@ int rtnl_cls_change(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
if ((err = rtnl_cls_build_change_request(cls, flags, &msg)) < 0)
return err;
- err = nl_send_auto_complete(sk, msg);
- nlmsg_free(msg);
- if (err < 0)
- return err;
-
- return nl_wait_for_ack(sk);
+ return nl_send_sync(sk, msg);
}
/**
- * Build a netlink request message to delete a classifier
- * @arg cls classifier to delete
- * @arg flags additional netlink message flags
- * @arg result Pointer to store resulting message.
+ * Build netlink message requesting the deletion of a classifier
+ * @arg cls Classifier to delete
+ * @arg result Pointer to store resulting netlink message
*
- * Builds a new netlink message requesting a deletion of a classifier.
- * The netlink message header isn't fully equipped with all relevant
- * fields and must thus be sent out via nl_send_auto_complete()
- * or supplemented as needed.
+ * The behaviour of this function is identical to rtnl_cls_delete() with
+ * the exception that it will not send the message but return it in the
+ * provided return pointer instead.
+ *
+ * @see rtnl_cls_delete()
*
* @return 0 on success or a negative error code.
*/
int rtnl_cls_build_delete_request(struct rtnl_cls *cls, int flags,
struct nl_msg **result)
{
+ int required = CLS_ATTR_PRIO;
+
+ if ((cls->ce_mask & required) != required) {
+ APPBUG("prio must be specified");
+ return -NLE_MISSING_ATTR;
+ }
+
return cls_build(cls, RTM_DELTFILTER, flags, result);
}
-
/**
- * Delete a classifier
- * @arg sk Netlink socket.
- * @arg cls classifier to delete
- * @arg flags additional netlink message flags
+ * Delete classifier
+ * @arg sk Netlink socket
+ * @arg cls Classifier to delete
*
- * Builds a netlink message by calling rtnl_cls_build_delete_request(),
- * sends the request to the kernel and waits for the next ACK to be
- * received and thus blocks until the request has been processed.
+ * Builds a \c RTM_DELTFILTER netlink message requesting the deletion
+ * of a classifier and sends the message to the kernel.
*
- * @return 0 on sucess or a negative error if an error occured.
+ * The message is constructed out of the following attributes:
+ * - \c ifindex (required)
+ * - \c prio (required)
+ * - \c protocol (required)
+ * - \c handle (required)
+ * - \c parent (optional, if not specified parent equals root-qdisc)
+ * - \c kind (optional, must match if provided)
+ *
+ * All other classifier attributes including all class type specific
+ * attributes are ignored.
+ *
+ * After sending, the function will wait for the ACK or an eventual
+ * error message to be received and will therefore block until the
+ * operation has been completed.
+ *
+ * @note Disabling auto-ack (nl_socket_disable_auto_ack()) will cause
+ * this function to return immediately after sending. In this case,
+ * it is the responsibility of the caller to handle any error
+ * messages returned.
+ *
+ * @return 0 on success or a negative error code.
*/
int rtnl_cls_delete(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
{
@@ -259,35 +298,28 @@ int rtnl_cls_delete(struct nl_sock *sk, struct rtnl_cls *cls, int flags)
if ((err = rtnl_cls_build_delete_request(cls, flags, &msg)) < 0)
return err;
- err = nl_send_auto_complete(sk, msg);
- nlmsg_free(msg);
- if (err < 0)
- return err;
-
- return nl_wait_for_ack(sk);
+ return nl_send_sync(sk, msg);
}
/** @} */
/**
- * @name Cache Management
+ * @name Cache Related Functions
* @{
*/
/**
- * Build a classifier cache including all classifiers attached to the
- * specified class/qdisc on eht specified interface.
- * @arg sk Netlink socket.
- * @arg ifindex interface index of the link the classes are
- * attached to.
- * @arg parent parent qdisc/class
- * @arg result Pointer to store resulting cache.
+ * Allocate a cache and fill it with all configured classifiers
+ * @arg sk Netlink socket
+ * @arg ifindex Interface index of the network device
+ * @arg parent Parent qdisc/traffic class class
+ * @arg result Pointer to store the created cache
*
- * Allocates a new cache, initializes it properly and updates it to
- * include all classes attached to the specified interface.
+ * Allocates a new classifier cache and fills it with a list of all
+ * configured classifier attached to the specified parent qdisc/traffic
+ * class on the specified network device. Release the cache with
+ * nl_cache_free().
*
- * @note The caller is responsible for destroying and freeing the
- * cache after using it.
* @return 0 on success or a negative error code.
*/
int rtnl_cls_alloc_cache(struct nl_sock *sk, int ifindex, uint32_t parent, struct nl_cache **result)
diff --git a/src/nl-tctree-list.c b/src/nl-tctree-list.c
index 9407345..d90cb28 100644
--- a/src/nl-tctree-list.c
+++ b/src/nl-tctree-list.c
@@ -23,6 +23,7 @@ static struct nl_dump_params params = {
static int ifindex;
static void print_qdisc(struct nl_object *, void *);
+static void print_tc_childs(struct rtnl_tc *, void *);
static void print_usage(void)
{
@@ -51,7 +52,7 @@ static void print_class(struct nl_object *obj, void *arg)
if (leaf)
print_qdisc((struct nl_object *) leaf, arg + 2);
- rtnl_class_foreach_child(class, class_cache, &print_class, arg + 2);
+ print_tc_childs(TC_CAST(class), arg + 2);
if (rtnl_cls_alloc_cache(sock, ifindex, parent, &cls_cache) < 0)
return;
@@ -61,9 +62,8 @@ static void print_class(struct nl_object *obj, void *arg)
nl_cache_free(cls_cache);
}
-static void print_qdisc_childs(struct rtnl_qdisc *qdisc, void *arg)
+static void print_tc_childs(struct rtnl_tc *tc, void *arg)
{
- struct rtnl_tc *tc = TC_CAST(qdisc);
struct rtnl_class *filter;
filter = nl_cli_class_alloc();
@@ -85,7 +85,7 @@ static void print_qdisc(struct nl_object *obj, void *arg)
params.dp_prefix = (int)(long) arg;
nl_object_dump(obj, &params);
- print_qdisc_childs(qdisc, arg + 2);
+ print_tc_childs(TC_CAST(qdisc), arg + 2);
if (rtnl_cls_alloc_cache(sock, ifindex, parent, &cls_cache) < 0)
return;