]> granicus.if.org Git - libnl/commitdiff
trafic class/classifer API improvements and documentation
authorThomas Graf <tgraf@suug.ch>
Tue, 29 Mar 2011 10:41:59 +0000 (12:41 +0200)
committerThomas Graf <tgraf@suug.ch>
Tue, 29 Mar 2011 10:41:59 +0000 (12:41 +0200)
- removed dead functions in header files
- deprecated rtnl_class_foreach_*() functions due to their missing
  handling possibility of OOM situations
- improved API documentation

include/netlink/route/class.h
include/netlink/route/classifier.h
lib/route/class.c
lib/route/cls.c
src/nl-tctree-list.c

index ad3bacf6912520e5e33365aca4a13da2b6ce56b8..e73b60a7b709603efea2163387bc9f4c73918138 100644 (file)
@@ -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
 }
index 23af837fa35a38b076e0262673426828fb1163e1..647bf1e6e07d8913188f40f3fcfd38ff3d933bbc 100644 (file)
@@ -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
 }
index a0f3758b953bfdaecb8b2efc4931d8d1ff27413d..2a9606b9d11a6041918aadcd800040ca03259eb6 100644 (file)
@@ -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",
index a041baa6958f4b42b7a37c3d746f6ebf94a48995..aa79b095b07ca8cfca724d657f308a29d9875e50 100644 (file)
@@ -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)
index 9407345ad424976ce840c569e50d3f54dc8aacdf..d90cb28f0d9e9f2c2b6e11677e1a1ca47c7fe4b3 100644 (file)
@@ -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;