From 747b892c91de7a852664f015405d6d37ea2b66b6 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Fri, 25 Mar 2011 18:13:19 +0100 Subject: Qdisc API improvements and documentation Deprecated the functions rtnl_qdisc_change() and rtnl_qdisc_build_change_request() for their lack of being able to specify flags. The new functions rtnl_qdisc_update() and rtnl_qdisc_build_update_request() may be used instead. The old functions are still available though. However, rtnl_qdisc_update() no longer implies NLM_F_REPLACE, it has to specified implicitely to allow updating a qdisc without risking to replace another qdisc. Included detailed documentation of qdisc addition/update/deletion. Introduced APPBUG() macro to let application developer know of API abuse. --- include/netlink-local.h | 9 +- include/netlink/route/qdisc.h | 29 ++- lib/route/qdisc.c | 488 +++++++++++++++++++++++------------------- lib/route/tc.c | 6 +- 4 files changed, 290 insertions(+), 242 deletions(-) diff --git a/include/netlink-local.h b/include/netlink-local.h index 9acc0e4..63dd661 100644 --- a/include/netlink-local.h +++ b/include/netlink-local.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2008 Thomas Graf + * Copyright (c) 2003-2011 Thomas Graf */ #ifndef NETLINK_LOCAL_H_ @@ -88,6 +88,13 @@ struct trans_list { assert(0); \ } while (0) +#define APPBUG(msg) \ + do { \ + fprintf(stderr, "APPLICATION BUG: %s:%d:%s: %s\n", \ + __FILE__, __LINE__, __PRETTY_FUNCTION__, msg); \ + assert(0); \ + } while(0) + extern int __nl_read_num_str_file(const char *path, int (*cb)(long, const char *)); diff --git a/include/netlink/route/qdisc.h b/include/netlink/route/qdisc.h index fbff666..10b85c5 100644 --- a/include/netlink/route/qdisc.h +++ b/include/netlink/route/qdisc.h @@ -38,24 +38,33 @@ extern int rtnl_qdisc_build_add_request(struct rtnl_qdisc *, int, struct nl_msg **); extern int rtnl_qdisc_add(struct nl_sock *, struct rtnl_qdisc *, int); -extern int rtnl_qdisc_build_change_request(struct rtnl_qdisc *, +extern int rtnl_qdisc_build_update_request(struct rtnl_qdisc *, struct rtnl_qdisc *, - struct nl_msg **); -extern int rtnl_qdisc_change(struct nl_sock *, struct rtnl_qdisc *, - struct rtnl_qdisc *); + int, struct nl_msg **); + +extern int rtnl_qdisc_update(struct nl_sock *, struct rtnl_qdisc *, + struct rtnl_qdisc *, int); extern int rtnl_qdisc_build_delete_request(struct rtnl_qdisc *, struct nl_msg **); extern int rtnl_qdisc_delete(struct nl_sock *, struct rtnl_qdisc *); /* Deprecated functions */ -extern void rtnl_qdisc_foreach_child(struct rtnl_qdisc *, struct nl_cache *, - void (*cb)(struct nl_object *, void *), - void *) __attribute__ ((deprecated)); +extern void rtnl_qdisc_foreach_child(struct rtnl_qdisc *, struct nl_cache *, + void (*cb)(struct nl_object *, void *), + void *) __attribute__ ((deprecated)); + +extern void rtnl_qdisc_foreach_cls(struct rtnl_qdisc *, struct nl_cache *, + void (*cb)(struct nl_object *, void *), + void *) __attribute__ ((deprecated)); + +extern int rtnl_qdisc_build_change_request(struct rtnl_qdisc *, + struct rtnl_qdisc *, + struct nl_msg **) + __attribute__ ((deprecated)); -extern void rtnl_qdisc_foreach_cls(struct rtnl_qdisc *, struct nl_cache *, - void (*cb)(struct nl_object *, void *), - void *) __attribute__ ((deprecated)); +extern int rtnl_qdisc_change(struct nl_sock *, struct rtnl_qdisc *, + struct rtnl_qdisc *) __attribute__ ((deprecated)); #ifdef __cplusplus } diff --git a/lib/route/qdisc.c b/lib/route/qdisc.c index 5257b9d..e5a8aa0 100644 --- a/lib/route/qdisc.c +++ b/lib/route/qdisc.c @@ -12,73 +12,6 @@ /** * @ingroup tc * @defgroup qdisc Queueing Disciplines - * - * @par Qdisc Handles - * In general, qdiscs are identified by the major part of a traffic control - * handle (the upper 16 bits). A few special values exist though: - * - \c TC_H_ROOT: root qdisc (directly attached to the device) - * - \c TC_H_INGRESS: ingress qdisc (directly attached to the device) - * - \c TC_H_UNSPEC: unspecified qdisc (no reference) - * - * @par 1) Adding a Qdisc - * @code - * // Allocate a new empty qdisc to be filled out - * struct rtnl_qdisc *qdisc = rtnl_qdisc_alloc(); - * - * // ... specify the kind of the Qdisc - * rtnl_qdisc_set_kind(qdisc, "pfifo"); - * - * // Specify the device the qdisc should be attached to - * rtnl_qdisc_set_ifindex(qdisc, ifindex); - * - * // ... specify the parent qdisc - * rtnl_qdisc_set_parent(qdisc, TC_H_ROOT); - * - * // Specifying the handle is not required but makes reidentifying easier - * // and may help to avoid adding a qdisc twice. - * rtnl_qdisc_set_handle(qdisc, 0x000A0000); - * - * // Now on to specify the qdisc specific options, see the relevant qdisc - * // modules for documentation, in this example we set the upper limit of - * // the packet fifo qdisc to 64 - * rtnl_qdisc_fifo_set_limit(qdisc, 64); - * - * rtnl_qdisc_add(handle, qdisc, NLM_R_REPLACE); - * - * // Free up the memory - * rtnl_qdisc_put(qdisc); - * @endcode - * - * @par 2) Deleting a Qdisc - * @code - * // Allocate a new empty qdisc to be filled out with the parameters - * // specifying the qdisc to be deleted. Alternatively a fully equiped - * // Qdisc object from a cache can be used. - * struct rtnl_qdisc *qdisc = rtnl_qdisc_alloc(); - * - * // The interface index of the device the qdisc is on and the parent handle - * // are the least required fields to be filled out. - * // Note: Specify TC_H_ROOT or TC_H_INGRESS as parent handle to delete the - * // root respectively root ingress qdisc. - * rtnl_qdisc_set_ifindex(qdisc, ifindex); - * rtnl_qdisc_set_parent(qdisc, parent_handle); - * - * // If required for identification, the handle can be specified as well. - * rtnl_qdisc_set_handle(qdisc, qdisc_handle); - * - * // Not required but maybe helpful as sanity check, the kind of the qdisc - * // can be specified to avoid mistakes. - * rtnl_qdisc_set_kind(qdisc, "pfifo"); - * - * // Finally delete the qdisc with rtnl_qdisc_delete(), alternatively - * // rtnl_qdisc_build_delete_request() can be invoked to generate an - * // appropritate netlink message to send out. - * rtnl_qdisc_delete(handle, qdisc); - * - * // Free up the memory - * rtnl_qdisc_put(qdisc); - * @endcode - * * @{ */ @@ -126,66 +59,107 @@ static int qdisc_request_update(struct nl_cache *c, struct nl_sock *sk) } /** - * @name QDisc Addition + * @name Allocation/Freeing * @{ */ -static int qdisc_build(struct rtnl_qdisc *qdisc, int type, int flags, - struct nl_msg **result) +struct rtnl_qdisc *rtnl_qdisc_alloc(void) { - return rtnl_tc_msg_build(TC_CAST(qdisc), type, flags, result); + struct rtnl_tc *tc; + + tc = TC_CAST(nl_object_alloc(&qdisc_obj_ops)); + if (tc) + tc->tc_type = RTNL_TC_TYPE_QDISC; + + return (struct rtnl_qdisc *) tc; +} + +void rtnl_qdisc_put(struct rtnl_qdisc *qdisc) +{ + nl_object_put((struct nl_object *) qdisc); +} + +/** @} */ + +/** + * @name Addition / Modification / Deletion + * @{ + */ -#if 0 - /* Some qdiscs don't accept properly nested messages (e.g. netem). To - * accomodate for this, they can complete the message themselves. - */ - else if (qops && qops->qo_build_msg) { - err = qops->qo_build_msg(qdisc, *result); - if (err < 0) - goto errout; +static int build_qdisc_msg(struct rtnl_qdisc *qdisc, int type, int flags, + struct nl_msg **result) +{ + if (!(qdisc->ce_mask & TCA_ATTR_IFINDEX)) { + APPBUG("ifindex must be specified"); + return -NLE_MISSING_ATTR; } -#endif + + return rtnl_tc_msg_build(TC_CAST(qdisc), type, flags, result); } /** - * Build a netlink message to add a new qdisc - * @arg qdisc qdisc to add - * @arg flags additional netlink message flags - * @arg result Pointer to store resulting message. + * Build a netlink message requesting the addition of a qdisc + * @arg qdisc Qdisc 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 qdisc. - * 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_qdisc_add() with + * the exception that it will not send the message but return it int the + * provided return pointer instead. * - * Common message flags used: - * - NLM_F_REPLACE - replace a potential existing qdisc + * @see rtnl_qdisc_add() * * @return 0 on success or a negative error code. */ int rtnl_qdisc_build_add_request(struct rtnl_qdisc *qdisc, int flags, struct nl_msg **result) { - return qdisc_build(qdisc, RTM_NEWQDISC, NLM_F_CREATE | flags, result); + if (!(qdisc->ce_mask & (TCA_ATTR_HANDLE | TCA_ATTR_PARENT))) { + APPBUG("handle or parent must be specified"); + return -NLE_MISSING_ATTR; + } + + return build_qdisc_msg(qdisc, RTM_NEWQDISC, flags, result); } /** - * Add a new qdisc - * @arg sk Netlink socket. - * @arg qdisc qdisc to delete - * @arg flags additional netlink message flags + * Add qdisc + * @arg sk Netlink socket + * @arg qdisc Qdisc to add + * @arg flags Additional netlink message flags + * + * Builds a \c RTM_NEWQDISC netlink message requesting the addition + * of a new qdisc and sends the message to the kernel. The configuration + * of the qdisc is derived from the attributes of the specified qdisc. + * + * The following flags may be specified: + * - \c NLM_F_CREATE: Create qdisc if it does not exist, otherwise + * -NLE_OBJ_NOTFOUND is returned. + * - \c NLM_F_REPLACE: If another qdisc is already attached to the + * parent, replace it even if the handles mismatch. + * - \c NLM_F_EXCL: Return -NLE_EXISTS if a qdisc with matching + * handle exists already. + * + * Existing qdiscs with matching handles will be updated, unless the + * flag \c NLM_F_EXCL is specified. If their handles do not match, the + * error -NLE_EXISTS is returned unless the flag \c NLM_F_REPLACE is + * specified in which case the existing qdisc is replaced with the new + * one. If no matching qdisc exists, it will be created if the flag + * \c NLM_F_CREATE is set, otherwise the error -NLE_OBJ_NOTFOUND 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. * - * Builds a netlink message by calling rtnl_qdisc_build_add_request(), - * sends the request to the kernel and waits for the ACK to be - * received and thus blocks until the request has been processed. - * - * Common message flags used: - * - NLM_F_REPLACE - replace a potential existing qdisc - * - * @return 0 on success or a negative error code + * @return 0 on success or a negative error code. */ -int rtnl_qdisc_add(struct nl_sock *sk, struct rtnl_qdisc *qdisc, - int flags) +int rtnl_qdisc_add(struct nl_sock *sk, struct rtnl_qdisc *qdisc, int flags) { struct nl_msg *msg; int err; @@ -193,86 +167,106 @@ int rtnl_qdisc_add(struct nl_sock *sk, struct rtnl_qdisc *qdisc, if ((err = rtnl_qdisc_build_add_request(qdisc, 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); } -/** @} */ - /** - * @name QDisc Modification - * @{ - */ - -/** - * Build a netlink message to change attributes of a existing qdisc - * @arg qdisc qdisc to change - * @arg new new qdisc attributes - * @arg result Pointer to store resulting message. + * Build netlink message requesting the update of a qdisc + * @arg qdisc Qdisc to update + * @arg new Qdisc with updated attributes + * @arg flags Additional netlink message flags + * @arg result Pointer to store resulting netlink message + * + * The behaviour of this function is identical to rtnl_qdisc_update() with + * the exception that it will not send the message but return it in the + * provided return pointer instead. * - * Builds a new netlink message requesting an change of qdisc - * attributes. 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. + * @see rtnl_qdisc_update() * * @return 0 on success or a negative error code. */ -int rtnl_qdisc_build_change_request(struct rtnl_qdisc *qdisc, - struct rtnl_qdisc *new, +int rtnl_qdisc_build_update_request(struct rtnl_qdisc *qdisc, + struct rtnl_qdisc *new, int flags, struct nl_msg **result) { - return qdisc_build(qdisc, RTM_NEWQDISC, NLM_F_REPLACE, result); + if (flags & (NLM_F_CREATE | NLM_F_EXCL)) { + APPBUG("NLM_F_CREATE and NLM_F_EXCL may not be used here, " + "use rtnl_qdisc_add()"); + return -NLE_INVAL; + } + + if (!(qdisc->ce_mask & TCA_ATTR_IFINDEX)) { + APPBUG("ifindex must be specified"); + return -NLE_MISSING_ATTR; + } + + if (!(qdisc->ce_mask & (TCA_ATTR_HANDLE | TCA_ATTR_PARENT))) { + APPBUG("handle or parent must be specified"); + return -NLE_MISSING_ATTR; + } + + rtnl_tc_set_ifindex(TC_CAST(new), qdisc->q_ifindex); + + if (qdisc->ce_mask & TCA_ATTR_HANDLE) + rtnl_tc_set_handle(TC_CAST(new), qdisc->q_handle); + + if (qdisc->ce_mask & TCA_ATTR_PARENT) + rtnl_tc_set_parent(TC_CAST(new), qdisc->q_parent); + + return build_qdisc_msg(new, RTM_NEWQDISC, flags, result); } /** - * Change attributes of a qdisc - * @arg sk Netlink socket. - * @arg qdisc qdisc to change - * @arg new new qdisc attributes - * - * Builds a netlink message by calling rtnl_qdisc_build_change_request(), - * sends the request to the kernel and waits for the ACK to be - * received and thus blocks until the request has been processed. + * Update qdisc + * @arg sk Netlink socket + * @arg qdisc Qdisc to update + * @arg new Qdisc with updated attributes + * @arg flags Additional netlink message flags + * + * Builds a \c RTM_NEWQDISC netlink message requesting the update + * of an existing qdisc and sends the message to the kernel. + * + * This function is a varation of rtnl_qdisc_add() to update qdiscs + * if the qdisc to be updated is available as qdisc object. The + * behaviour is identical to the one of rtnl_qdisc_add except that + * before constructing the message, it copies the \c ifindex, + * \c handle, and \c parent from the original \p qdisc to the \p new + * qdisc. + * + * 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 + * @return 0 on success or a negative error code. */ -int rtnl_qdisc_change(struct nl_sock *sk, struct rtnl_qdisc *qdisc, - struct rtnl_qdisc *new) +int rtnl_qdisc_update(struct nl_sock *sk, struct rtnl_qdisc *qdisc, + struct rtnl_qdisc *new, int flags) { struct nl_msg *msg; int err; - if ((err = rtnl_qdisc_build_change_request(qdisc, new, &msg)) < 0) - return err; - - err = nl_send_auto_complete(sk, msg); - nlmsg_free(msg); + err = rtnl_qdisc_build_update_request(qdisc, new, flags, &msg); if (err < 0) return err; - return wait_for_ack(sk); + return nl_send_sync(sk, msg); } -/** @} */ - -/** - * @name QDisc Deletion - * @{ - */ - /** - * Build a netlink request message to delete a qdisc - * @arg qdisc qdisc to delete - * @arg result Pointer to store resulting message. + * Build netlink message requesting the deletion of a qdisc + * @arg qdisc Qdisc to delete + * @arg result Pointer to store resulting netlink message + * + * The behaviour of this function is identical to rtnl_qdisc_delete() with + * the exception that it will not send the message but return it in the + * provided return pointer instead. * - * Builds a new netlink message requesting a deletion of a qdisc. - * 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. + * @see rtnl_qdisc_delete() * * @return 0 on success or a negative error code. */ @@ -283,36 +277,65 @@ int rtnl_qdisc_build_delete_request(struct rtnl_qdisc *qdisc, struct tcmsg tchdr; int required = TCA_ATTR_IFINDEX | TCA_ATTR_PARENT; - if ((qdisc->ce_mask & required) != required) - BUG(); + if ((qdisc->ce_mask & required) != required) { + APPBUG("ifindex and parent must be specified"); + return -NLE_MISSING_ATTR; + } - msg = nlmsg_alloc_simple(RTM_DELQDISC, 0); - if (!msg) + if (!(msg = nlmsg_alloc_simple(RTM_DELQDISC, 0))) return -NLE_NOMEM; + memset(&tchdr, 0, sizeof(tchdr)); + tchdr.tcm_family = AF_UNSPEC; - tchdr.tcm_handle = qdisc->q_handle; - tchdr.tcm_parent = qdisc->q_parent; tchdr.tcm_ifindex = qdisc->q_ifindex; - if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0) { - nlmsg_free(msg); - return -NLE_MSGSIZE; - } + tchdr.tcm_parent = qdisc->q_parent; + + if (qdisc->ce_mask & TCA_ATTR_HANDLE) + tchdr.tcm_handle = qdisc->q_handle; + + if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0) + goto nla_put_failure; + + if (qdisc->ce_mask & TCA_ATTR_KIND) + NLA_PUT_STRING(msg, TCA_KIND, qdisc->q_kind); *result = msg; return 0; + +nla_put_failure: + nlmsg_free(msg); + return -NLE_MSGSIZE; } /** - * Delete a qdisc - * @arg sk Netlink socket. - * @arg qdisc qdisc to delete + * Delete qdisc + * @arg sk Netlink socket + * @arg qdisc Qdisc to add + * + * Builds a \c RTM_NEWQDISC netlink message requesting the deletion + * of a qdisc and sends the message to the kernel. + * + * The message is constructed out of the following attributes: + * - \c ifindex and \c parent + * - \c handle (optional, must match if provided) + * - \c kind (optional, must match if provided) * - * Builds a netlink message by calling rtnl_qdisc_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 qdisc attributes including all qdisc 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 It is not possible to delete default qdiscs. + * + * @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_qdisc_delete(struct nl_sock *sk, struct rtnl_qdisc *qdisc) { @@ -322,29 +345,23 @@ int rtnl_qdisc_delete(struct nl_sock *sk, struct rtnl_qdisc *qdisc) if ((err = rtnl_qdisc_build_delete_request(qdisc, &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); } /** @} */ /** - * @name Qdisc Cache Management + * @name Cache Related Functions * @{ */ /** - * Build a qdisc cache including all qdiscs currently configured in - * the kernel - * @arg sk Netlink socket. - * @arg result Pointer to store resulting message. + * Allocate a cache and fill it with all configured qdiscs + * @arg sk Netlink socket + * @arg result Pointer to store the created cache * - * Allocates a new cache, initializes it properly and updates it to - * include all qdiscs currently configured in the kernel. + * Allocates a new qdisc cache and fills it with a list of all configured + * qdiscs on all network devices. Release the cache with nl_cache_free(). * * @return 0 on success or a negative error code. */ @@ -354,14 +371,21 @@ int rtnl_qdisc_alloc_cache(struct nl_sock *sk, struct nl_cache **result) } /** - * Look up qdisc by its parent in the provided cache - * @arg cache qdisc cache - * @arg ifindex interface the qdisc is attached to - * @arg parent parent handle + * Search qdisc by interface index and parent + * @arg cache Qdisc cache + * @arg ifindex Interface index + * @arg parent Handle of parent qdisc + * + * Searches a qdisc cache previously allocated with rtnl_qdisc_alloc_cache() + * and searches for a qdisc matching the interface index and parent qdisc. + * + * The reference counter is incremented before returning the qdisc, therefore + * the reference must be given back with rtnl_qdisc_put() after usage. + * * @return pointer to qdisc inside the cache or NULL if no match was found. */ -struct rtnl_qdisc * rtnl_qdisc_get_by_parent(struct nl_cache *cache, - int ifindex, uint32_t parent) +struct rtnl_qdisc *rtnl_qdisc_get_by_parent(struct nl_cache *cache, + int ifindex, uint32_t parent) { struct rtnl_qdisc *q; @@ -379,14 +403,21 @@ struct rtnl_qdisc * rtnl_qdisc_get_by_parent(struct nl_cache *cache, } /** - * Look up qdisc by its handle in the provided cache - * @arg cache qdisc cache - * @arg ifindex interface the qdisc is attached to - * @arg handle qdisc handle - * @return pointer to qdisc inside the cache or NULL if no match was found. + * Search qdisc by interface index and handle + * @arg cache Qdisc cache + * @arg ifindex Interface index + * @arg handle Handle + * + * Searches a qdisc cache previously allocated with rtnl_qdisc_alloc_cache() + * and searches for a qdisc matching the interface index and handle. + * + * The reference counter is incremented before returning the qdisc, therefore + * the reference must be given back with rtnl_qdisc_put() after usage. + * + * @return Qdisc or NULL if no match was found. */ -struct rtnl_qdisc * rtnl_qdisc_get(struct nl_cache *cache, - int ifindex, uint32_t handle) +struct rtnl_qdisc *rtnl_qdisc_get(struct nl_cache *cache, int ifindex, + uint32_t handle) { struct rtnl_qdisc *q; @@ -405,29 +436,6 @@ struct rtnl_qdisc * rtnl_qdisc_get(struct nl_cache *cache, /** @} */ -/** - * @name Allocation/Freeing - * @{ - */ - -struct rtnl_qdisc *rtnl_qdisc_alloc(void) -{ - struct rtnl_tc *tc; - - tc = TC_CAST(nl_object_alloc(&qdisc_obj_ops)); - if (tc) - tc->tc_type = RTNL_TC_TYPE_QDISC; - - return (struct rtnl_qdisc *) tc; -} - -void rtnl_qdisc_put(struct rtnl_qdisc *qdisc) -{ - nl_object_put((struct nl_object *) qdisc); -} - -/** @} */ - /** * @name Deprecated Functions * @{ @@ -478,6 +486,34 @@ void rtnl_qdisc_foreach_cls(struct rtnl_qdisc *qdisc, struct nl_cache *cache, rtnl_cls_put(filter); } +/** + * Build a netlink message requesting the update of a qdisc + * + * @deprecated Use of this function is deprecated in favour of + * rtnl_qdisc_build_update_request() due to the missing + * possibility of specifying additional flags. + */ +int rtnl_qdisc_build_change_request(struct rtnl_qdisc *qdisc, + struct rtnl_qdisc *new, + struct nl_msg **result) +{ + return rtnl_qdisc_build_update_request(qdisc, new, NLM_F_REPLACE, + result); +} + +/** + * Change attributes of a qdisc + * + * @deprecated Use of this function is deprecated in favour of + * rtnl_qdisc_update() due to the missing possibility of + * specifying additional flags. + */ +int rtnl_qdisc_change(struct nl_sock *sk, struct rtnl_qdisc *qdisc, + struct rtnl_qdisc *new) +{ + return rtnl_qdisc_update(sk, qdisc, new, NLM_F_REPLACE); +} + /** @} */ static void qdisc_dump_details(struct rtnl_tc *tc, struct nl_dump_params *p) diff --git a/lib/route/tc.c b/lib/route/tc.c index 09ae044..56aa410 100644 --- a/lib/route/tc.c +++ b/lib/route/tc.c @@ -189,11 +189,7 @@ int rtnl_tc_msg_build(struct rtnl_tc *tc, int type, int flags, .tcm_handle = tc->tc_handle, .tcm_parent = tc->tc_parent, }; - int req, err = -NLE_MSGSIZE; - - req = (TCA_ATTR_IFINDEX | TCA_ATTR_PARENT | TCA_ATTR_KIND); - if ((tc->ce_mask & req) != req) - return -NLE_MISSING_ATTR; + int err = -NLE_MSGSIZE; msg = nlmsg_alloc_simple(type, flags); if (!msg) -- cgit v1.2.1