diff --git a/include/Makefile.am b/include/Makefile.am index 8815a6e..8824dfe 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -43,20 +43,18 @@ nobase_include_HEADERS = \ netlink/route/sch/sfq.h \ netlink/route/sch/tbf.h \ netlink/route/addr.h \ - netlink/route/class-modules.h \ netlink/route/class.h \ - netlink/route/classifier-modules.h \ netlink/route/classifier.h \ netlink/route/link.h \ netlink/route/neighbour.h \ netlink/route/neightbl.h \ netlink/route/nexthop.h \ - netlink/route/qdisc-modules.h \ netlink/route/qdisc.h \ netlink/route/route.h \ netlink/route/rtnl.h \ netlink/route/rule.h \ netlink/route/tc.h \ + netlink/route/tc-api.h \ netlink/socket.h \ netlink/types.h \ netlink/utils.h \ diff --git a/include/netlink-tc.h b/include/netlink-tc.h index 9e4bce9..3e44642 100644 --- a/include/netlink-tc.h +++ b/include/netlink-tc.h @@ -36,18 +36,6 @@ extern "C" { extern int tca_parse(struct nlattr **, int, struct rtnl_tc *, struct nla_policy *); -extern int tca_msg_parser(struct nlmsghdr *, struct rtnl_tc *); -extern void tca_free_data(struct rtnl_tc *); -extern int tca_clone(struct rtnl_tc *, struct rtnl_tc *); -extern void tca_dump_line(struct rtnl_tc *, const char *, - struct nl_dump_params *); -extern void tca_dump_details(struct rtnl_tc *, struct nl_dump_params *); -extern void tca_dump_stats(struct rtnl_tc *, struct nl_dump_params *); -extern int tca_compare(struct nl_object *, struct nl_object *, uint32_t, int); - -extern void tca_set_kind(struct rtnl_tc *, const char *); - -extern int tca_build_msg(struct rtnl_tc *, int, int, struct nl_msg **); #define RTNL_TC_RTABLE_SIZE 256 @@ -55,11 +43,6 @@ extern int rtnl_tc_build_rate_table(struct rtnl_tc *tc, struct rtnl_ratespec *, uint32_t *); -static inline void *tca_priv(struct rtnl_tc *tca) -{ - return tca->tc_subdata; -} - static inline void *tca_xstats(struct rtnl_tc *tca) { return tca->tc_xstats->d_data; diff --git a/include/netlink-types.h b/include/netlink-types.h index de17f9a..1cb7c0e 100644 --- a/include/netlink-types.h +++ b/include/netlink-types.h @@ -17,6 +17,7 @@ #include #include #include +#include #define NL_SOCK_BUFSIZE_SET (1<<0) #define NL_SOCK_PASSCRED (1<<1) @@ -441,7 +442,7 @@ struct rtnl_tstats #define TCKINDSIZ 32 -#define NL_TCA_GENERIC(pre) \ +#define NL_TC_GENERIC(pre) \ NLHDR_COMMON \ uint32_t pre ##_family; \ uint32_t pre ##_ifindex; \ @@ -457,31 +458,30 @@ struct rtnl_tstats uint64_t pre ##_stats[RTNL_TC_STATS_MAX+1]; \ struct nl_data * pre ##_xstats; \ struct nl_data * pre ##_subdata; \ - struct rtnl_link * pre ##_link + struct rtnl_link * pre ##_link; \ + struct rtnl_tc_ops * pre ##_ops; \ + enum rtnl_tc_type pre ##_type struct rtnl_tc { - NL_TCA_GENERIC(tc); + NL_TC_GENERIC(tc); }; struct rtnl_qdisc { - NL_TCA_GENERIC(q); - struct rtnl_qdisc_ops *q_ops; + NL_TC_GENERIC(q); }; struct rtnl_class { - NL_TCA_GENERIC(c); - struct rtnl_class_ops *c_ops; + NL_TC_GENERIC(c); }; struct rtnl_cls { - NL_TCA_GENERIC(c); + NL_TC_GENERIC(c); uint16_t c_prio; uint16_t c_protocol; - struct rtnl_cls_ops *c_ops; }; struct rtnl_u32 diff --git a/include/netlink/cli/class.h b/include/netlink/cli/class.h index 0141c21..5001e42 100644 --- a/include/netlink/cli/class.h +++ b/include/netlink/cli/class.h @@ -13,12 +13,9 @@ #define __NETLINK_CLI_CLASS_H_ #include -#include #include extern struct rtnl_class *nl_cli_class_alloc(void); extern struct nl_cache *nl_cli_class_alloc_cache(struct nl_sock *, int); -extern void nl_cli_class_parse_kind(struct rtnl_class *, char *); - #endif diff --git a/include/netlink/cli/cls.h b/include/netlink/cli/cls.h index cdcb17e..a2707b8 100644 --- a/include/netlink/cli/cls.h +++ b/include/netlink/cli/cls.h @@ -13,27 +13,12 @@ #define __NETLINK_CLI_CLS_H_ #include -#include #include -struct nl_cli_cls_module -{ - const char * cm_name; - struct rtnl_cls_ops * cm_ops; - int (*cm_parse_argv)(struct rtnl_cls *, int, char **); - struct nl_list_head cm_list; -}; - extern struct rtnl_cls * nl_cli_cls_alloc(void); extern struct nl_cache * nl_cli_cls_alloc_cache(struct nl_sock *, int, uint32_t); -extern void nl_cli_cls_parse_kind(struct rtnl_cls *, char *); extern void nl_cli_cls_parse_proto(struct rtnl_cls *, char *); extern struct rtnl_ematch_tree *nl_cli_cls_parse_ematch(struct rtnl_cls *, char *); -extern struct nl_cli_cls_module *nl_cli_cls_lookup(struct rtnl_cls_ops *); -extern void nl_cli_cls_register(struct nl_cli_cls_module *); -extern void nl_cli_cls_unregister(struct nl_cli_cls_module *); - - #endif diff --git a/include/netlink/cli/qdisc.h b/include/netlink/cli/qdisc.h index 00c7083..b102da4 100644 --- a/include/netlink/cli/qdisc.h +++ b/include/netlink/cli/qdisc.h @@ -6,36 +6,18 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2008-2010 Thomas Graf + * Copyright (c) 2008-2011 Thomas Graf */ #ifndef __NETLINK_CLI_QDISC_H_ #define __NETLINK_CLI_QDISC_H_ #include -#include #define nl_cli_qdisc_alloc_cache(sk) \ nl_cli_alloc_cache((sk), "queueing disciplines", \ rtnl_qdisc_alloc_cache) -struct nl_cli_qdisc_module -{ - const char * qm_name; - struct rtnl_qdisc_ops * qm_ops; - struct rtnl_class_ops * qm_class_ops; - void (*qm_parse_qdisc_argv)(struct rtnl_qdisc *, int, char **); - void (*qm_parse_class_argv)(struct rtnl_class *, int, char **); - struct nl_list_head qm_list; -}; - -extern struct nl_cli_qdisc_module *nl_cli_qdisc_lookup(struct rtnl_qdisc_ops *); -extern struct nl_cli_qdisc_module *nl_cli_qdisc_lookup_by_class(struct rtnl_class_ops *); -extern void nl_cli_qdisc_register(struct nl_cli_qdisc_module *); -extern void nl_cli_qdisc_unregister(struct nl_cli_qdisc_module *); - extern struct rtnl_qdisc *nl_cli_qdisc_alloc(void); -extern void nl_cli_qdisc_parse_kind(struct rtnl_qdisc *, char *); - #endif diff --git a/include/netlink/cli/tc.h b/include/netlink/cli/tc.h index 82f9a1d..85d2e30 100644 --- a/include/netlink/cli/tc.h +++ b/include/netlink/cli/tc.h @@ -6,13 +6,13 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2010 Thomas Graf + * Copyright (c) 2010-2011 Thomas Graf */ #ifndef __NETLINK_CLI_TC_H_ #define __NETLINK_CLI_TC_H_ -#include +#include extern void nl_cli_tc_parse_dev(struct rtnl_tc *, struct nl_cache *, char *); extern void nl_cli_tc_parse_parent(struct rtnl_tc *, char *); @@ -21,5 +21,19 @@ extern void nl_cli_tc_parse_mtu(struct rtnl_tc *, char *); extern void nl_cli_tc_parse_mpu(struct rtnl_tc *, char *); extern void nl_cli_tc_parse_overhead(struct rtnl_tc *, char *); extern void nl_cli_tc_parse_linktype(struct rtnl_tc *, char *); +extern void nl_cli_tc_parse_kind(struct rtnl_tc *, char *); + +struct nl_cli_tc_module +{ + const char * tm_name; + enum rtnl_tc_type tm_type; + struct rtnl_tc_ops * tm_ops; + void (*tm_parse_argv)(struct rtnl_tc *, int, char **); + struct nl_list_head tm_list; +}; + +extern struct nl_cli_tc_module *nl_cli_tc_lookup(struct rtnl_tc_ops *); +extern void nl_cli_tc_register(struct nl_cli_tc_module *); +extern void nl_cli_tc_unregister(struct nl_cli_tc_module *); #endif diff --git a/include/netlink/route/class-modules.h b/include/netlink/route/class-modules.h deleted file mode 100644 index 74a25c9..0000000 --- a/include/netlink/route/class-modules.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * netlink/route/class-modules.h Class Module API - * - * 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-2006 Thomas Graf - */ - -#ifndef NETLINK_CLASS_MODULES_H_ -#define NETLINK_CLASS_MODULES_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Class operations - * @ingroup class_api - */ -struct rtnl_class_ops -{ - /** - * Kind/Name of class - */ - char co_kind[32]; - - /** - * Dump callbacks - */ - void (*co_dump[NL_DUMP_MAX+1])(struct rtnl_class *, - struct nl_dump_params *); - - /** - * Must return the contents supposed to be in TCA_OPTIONS - */ - struct nl_msg *(*co_get_opts)(struct rtnl_class *); - - /** - * TCA_OPTIONS message parser - */ - int (*co_msg_parser)(struct rtnl_class *); - - /** - * Called before a class object gets destroyed - */ - void (*co_free_data)(struct rtnl_class *); - - /** - * Called whenever a class object needs to be cloned - */ - int (*co_clone)(struct rtnl_class *, struct rtnl_class *); - - /** - * INTERNAL (Do not use) - */ - struct rtnl_class_ops *co_next; -}; - -extern int rtnl_class_register(struct rtnl_class_ops *); -extern int rtnl_class_unregister(struct rtnl_class_ops *); -extern struct rtnl_class_ops * rtnl_class_lookup_ops(struct rtnl_class *); -extern struct rtnl_class_ops * __rtnl_class_lookup_ops(const char *); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/include/netlink/route/class.h b/include/netlink/route/class.h index 13a25d6..ad3bacf 100644 --- a/include/netlink/route/class.h +++ b/include/netlink/route/class.h @@ -22,8 +22,6 @@ extern "C" { struct rtnl_class; -extern struct nl_object_ops class_obj_ops; - 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, diff --git a/include/netlink/route/classifier-modules.h b/include/netlink/route/classifier-modules.h deleted file mode 100644 index 35cb06e..0000000 --- a/include/netlink/route/classifier-modules.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * netlink/route/classifier-modules.h Classifier Module API - * - * 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-2009 Thomas Graf - */ - -#ifndef NETLINK_CLASS_MODULES_H_ -#define NETLINK_CLASS_MODULES_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Classifier operations - * @ingroup cls_api - */ -struct rtnl_cls_ops -{ - /** - * Name of classifier module - */ - char co_kind[32]; - - - /** - * Size of private classifier data - */ - size_t co_size; - - /** - * Dump callbacks - */ - void (*co_dump[NL_DUMP_MAX+1])(struct rtnl_cls *, - struct nl_dump_params *); - /** - * Must return the contents supposed to be in TCA_OPTIONS - */ - int (*co_get_opts)(struct rtnl_cls *, struct nl_msg *); - - /** - * TCA_OPTIONS message parser - */ - int (*co_msg_parser)(struct rtnl_cls *); - - /** - * Called before a class object gets destroyed - */ - void (*co_free_data)(struct rtnl_cls *); - - /** - * Called whenever a classifier object needs to be cloned - */ - int (*co_clone)(struct rtnl_cls *, struct rtnl_cls *); - - /** - * INTERNAL (Do not use) - */ - struct rtnl_cls_ops *co_next; -}; - -extern int rtnl_cls_register(struct rtnl_cls_ops *); -extern int rtnl_cls_unregister(struct rtnl_cls_ops *); -extern struct rtnl_cls_ops * rtnl_cls_lookup_ops(struct rtnl_cls *); -extern struct rtnl_cls_ops * __rtnl_cls_lookup_ops(const char *kind); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/include/netlink/route/classifier.h b/include/netlink/route/classifier.h index 17c834b..23af837 100644 --- a/include/netlink/route/classifier.h +++ b/include/netlink/route/classifier.h @@ -21,8 +21,6 @@ extern "C" { #endif -extern struct nl_object_ops cls_obj_ops; - extern struct rtnl_cls *rtnl_cls_alloc(void); extern void rtnl_cls_put(struct rtnl_cls *); @@ -39,17 +37,12 @@ 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_set_kind(struct rtnl_cls *, const char *); -extern struct rtnl_cls_ops *rtnl_cls_get_ops(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_data(struct rtnl_cls *); - #ifdef __cplusplus } #endif diff --git a/include/netlink/route/qdisc-modules.h b/include/netlink/route/qdisc-modules.h deleted file mode 100644 index 769625e..0000000 --- a/include/netlink/route/qdisc-modules.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * netlink/route/qdisc-modules.h Qdisc Module API - * - * 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-2006 Thomas Graf - */ - -#ifndef NETLINK_QDISC_MODULES_H_ -#define NETLINK_QDISC_MODULES_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Qdisc Operations - * @ingroup qdisc - */ -struct rtnl_qdisc_ops -{ - /** - * Kind/Name of Qdisc - */ - char qo_kind[32]; - - /** - * Dump callbacks - */ - void (*qo_dump[NL_DUMP_MAX+1])(struct rtnl_qdisc *, - struct nl_dump_params *); - - /** - * Must return the contents supposed to be in TCA_OPTIONS - */ - struct nl_msg *(*qo_get_opts)(struct rtnl_qdisc *); - - int (*qo_build_msg)(struct rtnl_qdisc *, struct nl_msg *); - - /** - * TCA_OPTIONS message parser - */ - int (*qo_msg_parser)(struct rtnl_qdisc *); - - /** - * Called before a Qdisc object gets destroyed - */ - void (*qo_free_data)(struct rtnl_qdisc *); - - /** - * Called whenever a qdisc object needs to be cloned - */ - int (*qo_clone)(struct rtnl_qdisc *, struct rtnl_qdisc *); - - /** - * INTERNAL (Do not use) - */ - struct rtnl_qdisc_ops *qo_next; -}; - -extern int rtnl_qdisc_register(struct rtnl_qdisc_ops *); -extern int rtnl_qdisc_unregister(struct rtnl_qdisc_ops *); -extern struct rtnl_qdisc_ops * rtnl_qdisc_lookup_ops(struct rtnl_qdisc *); -extern struct rtnl_qdisc_ops * __rtnl_qdisc_lookup_ops(const char *); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/include/netlink/route/sch/netem.h b/include/netlink/route/sch/netem.h index c293777..ce56ee7 100644 --- a/include/netlink/route/sch/netem.h +++ b/include/netlink/route/sch/netem.h @@ -18,48 +18,48 @@ extern "C" { #endif -extern int rtnl_netem_set_limit(struct rtnl_qdisc *, int); +extern void rtnl_netem_set_limit(struct rtnl_qdisc *, int); extern int rtnl_netem_get_limit(struct rtnl_qdisc *); /* Packet Re-ordering */ -extern int rtnl_netem_set_gap(struct rtnl_qdisc *, int); +extern void rtnl_netem_set_gap(struct rtnl_qdisc *, int); extern int rtnl_netem_get_gap(struct rtnl_qdisc *); -extern int rtnl_netem_set_reorder_probability(struct rtnl_qdisc *, int); +extern void rtnl_netem_set_reorder_probability(struct rtnl_qdisc *, int); extern int rtnl_netem_get_reorder_probability(struct rtnl_qdisc *); -extern int rtnl_netem_set_reorder_correlation(struct rtnl_qdisc *, int); +extern void rtnl_netem_set_reorder_correlation(struct rtnl_qdisc *, int); extern int rtnl_netem_get_reorder_correlation(struct rtnl_qdisc *); /* Corruption */ -extern int rtnl_netem_set_corruption_probability(struct rtnl_qdisc *, int); +extern void rtnl_netem_set_corruption_probability(struct rtnl_qdisc *, int); extern int rtnl_netem_get_corruption_probability(struct rtnl_qdisc *); -extern int rtnl_netem_set_corruption_correlation(struct rtnl_qdisc *, int); +extern void rtnl_netem_set_corruption_correlation(struct rtnl_qdisc *, int); extern int rtnl_netem_get_corruption_correlation(struct rtnl_qdisc *); /* Packet Loss */ -extern int rtnl_netem_set_loss(struct rtnl_qdisc *, int); +extern void rtnl_netem_set_loss(struct rtnl_qdisc *, int); extern int rtnl_netem_get_loss(struct rtnl_qdisc *); -extern int rtnl_netem_set_loss_correlation(struct rtnl_qdisc *, int); +extern void rtnl_netem_set_loss_correlation(struct rtnl_qdisc *, int); extern int rtnl_netem_get_loss_correlation(struct rtnl_qdisc *); /* Packet Duplication */ -extern int rtnl_netem_set_duplicate(struct rtnl_qdisc *, int); +extern void rtnl_netem_set_duplicate(struct rtnl_qdisc *, int); extern int rtnl_netem_get_duplicate(struct rtnl_qdisc *); -extern int rtnl_netem_set_duplicate_correlation(struct rtnl_qdisc *, int); +extern void rtnl_netem_set_duplicate_correlation(struct rtnl_qdisc *, int); extern int rtnl_netem_get_duplicate_correlation(struct rtnl_qdisc *); /* Packet Delay */ -extern int rtnl_netem_set_delay(struct rtnl_qdisc *, int); +extern void rtnl_netem_set_delay(struct rtnl_qdisc *, int); extern int rtnl_netem_get_delay(struct rtnl_qdisc *); -extern int rtnl_netem_set_jitter(struct rtnl_qdisc *, int); +extern void rtnl_netem_set_jitter(struct rtnl_qdisc *, int); extern int rtnl_netem_get_jitter(struct rtnl_qdisc *); -extern int rtnl_netem_set_delay_correlation(struct rtnl_qdisc *, int); +extern void rtnl_netem_set_delay_correlation(struct rtnl_qdisc *, int); extern int rtnl_netem_get_delay_correlation(struct rtnl_qdisc *); /* Delay Distribution */ diff --git a/include/netlink/route/sch/prio.h b/include/netlink/route/sch/prio.h index ff35b07..f6fdc86 100644 --- a/include/netlink/route/sch/prio.h +++ b/include/netlink/route/sch/prio.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf + * Copyright (c) 2003-2011 Thomas Graf */ #ifndef NETLINK_PRIO_H_ @@ -38,7 +38,7 @@ extern "C" { /** @} */ -extern int rtnl_qdisc_prio_set_bands(struct rtnl_qdisc *, int); +extern void rtnl_qdisc_prio_set_bands(struct rtnl_qdisc *, int); extern int rtnl_qdisc_prio_get_bands(struct rtnl_qdisc *); extern int rtnl_qdisc_prio_set_priomap(struct rtnl_qdisc *, uint8_t[], int); extern uint8_t *rtnl_qdisc_prio_get_priomap(struct rtnl_qdisc *); diff --git a/include/netlink/route/sch/sfq.h b/include/netlink/route/sch/sfq.h index 19b3817..7cc0b3e 100644 --- a/include/netlink/route/sch/sfq.h +++ b/include/netlink/route/sch/sfq.h @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf + * Copyright (c) 2003-2011 Thomas Graf */ #ifndef NETLINK_SFQ_H_ @@ -18,13 +18,13 @@ extern "C" { #endif -extern int rtnl_sfq_set_quantum(struct rtnl_qdisc *, int); +extern void rtnl_sfq_set_quantum(struct rtnl_qdisc *, int); extern int rtnl_sfq_get_quantum(struct rtnl_qdisc *); -extern int rtnl_sfq_set_limit(struct rtnl_qdisc *, int); +extern void rtnl_sfq_set_limit(struct rtnl_qdisc *, int); extern int rtnl_sfq_get_limit(struct rtnl_qdisc *); -extern int rtnl_sfq_set_perturb(struct rtnl_qdisc *, int); +extern void rtnl_sfq_set_perturb(struct rtnl_qdisc *, int); extern int rtnl_sfq_get_perturb(struct rtnl_qdisc *); extern int rtnl_sfq_get_divisor(struct rtnl_qdisc *); diff --git a/include/netlink/route/sch/tbf.h b/include/netlink/route/sch/tbf.h index bb0e3b1..8a2144a 100644 --- a/include/netlink/route/sch/tbf.h +++ b/include/netlink/route/sch/tbf.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 + * Copyright (c) 2003-2011 Thomas Graf */ #ifndef NETLINK_TBF_H_ @@ -19,11 +19,11 @@ extern "C" { #endif -extern int rtnl_qdisc_tbf_set_limit(struct rtnl_qdisc *, int); +extern void rtnl_qdisc_tbf_set_limit(struct rtnl_qdisc *, int); extern int rtnl_qdisc_tbf_set_limit_by_latency(struct rtnl_qdisc *, int); extern int rtnl_qdisc_tbf_get_limit(struct rtnl_qdisc *); -extern int rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc *, int, int, int); +extern void rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc *, int, int, int); extern int rtnl_qdisc_tbf_get_rate(struct rtnl_qdisc *); extern int rtnl_qdisc_tbf_get_rate_bucket(struct rtnl_qdisc *); extern int rtnl_qdisc_tbf_get_rate_cell(struct rtnl_qdisc *); diff --git a/include/netlink/route/tc-api.h b/include/netlink/route/tc-api.h new file mode 100644 index 0000000..8ed940a --- /dev/null +++ b/include/netlink/route/tc-api.h @@ -0,0 +1,141 @@ +/* + * netlink/route/tc-api.h Traffic Control API + * + * 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) 2011 Thomas Graf + */ + +#ifndef NETLINK_TC_API_H_ +#define NETLINK_TC_API_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum rtnl_tc_type { + RTNL_TC_TYPE_QDISC, + RTNL_TC_TYPE_CLASS, + RTNL_TC_TYPE_CLS, + __RTNL_TC_TYPE_MAX, +}; + +#define RTNL_TC_TYPE_MAX (__RTNL_TC_TYPE_MAX - 1) + +/** + * Traffic control object operations + * @ingroup tc + * + * This structure holds function pointers and settings implementing + * the features of each traffic control object implementation. + */ +struct rtnl_tc_ops +{ + /** + * Name of traffic control module + */ + char *to_kind; + + /** + * Type of traffic control object + */ + enum rtnl_tc_type to_type; + + + /** + * Size of private data + */ + size_t to_size; + + /** + * Dump callbacks + */ + void (*to_dump[NL_DUMP_MAX+1])(struct rtnl_tc *, void *, + struct nl_dump_params *); + /** + * Used to fill the contents of TCA_OPTIONS + */ + int (*to_msg_fill)(struct rtnl_tc *, void *, struct nl_msg *); + + /** + * Uesd to to fill tc related messages, unlike with to_msg_fill, + * the contents is not encapsulated with a TCA_OPTIONS nested + * attribute. + */ + int (*to_msg_fill_raw)(struct rtnl_tc *, void *, struct nl_msg *); + + /** + * TCA_OPTIONS message parser + */ + int (*to_msg_parser)(struct rtnl_tc *, void *); + + /** + * Called before a tc object is destroyed + */ + void (*to_free_data)(struct rtnl_tc *, void *); + + /** + * Called whenever a classifier object needs to be cloned + */ + int (*to_clone)(void *, void *); + + /** + * Internal, don't touch + */ + struct nl_list_head to_list; +}; + +struct rtnl_tc_type_ops +{ + enum rtnl_tc_type tt_type; + + char *tt_dump_prefix; + + /** + * Dump callbacks + */ + void (*tt_dump[NL_DUMP_MAX+1])(struct rtnl_tc *, + struct nl_dump_params *); +}; + +extern int rtnl_tc_msg_parse(struct nlmsghdr *, + struct rtnl_tc *); +extern int rtnl_tc_msg_build(struct rtnl_tc *, int, + int, struct nl_msg **); + +extern void rtnl_tc_free_data(struct nl_object *); +extern int rtnl_tc_clone(struct nl_object *, + struct nl_object *); +extern void rtnl_tc_dump_line(struct nl_object *, + struct nl_dump_params *); +extern void rtnl_tc_dump_details(struct nl_object *, + struct nl_dump_params *); +extern void rtnl_tc_dump_stats(struct nl_object *, + struct nl_dump_params *); +extern int rtnl_tc_compare(struct nl_object *, + struct nl_object *, + uint32_t, int); + +extern void * rtnl_tc_data(struct rtnl_tc *); + +extern struct rtnl_tc_ops * rtnl_tc_lookup_ops(enum rtnl_tc_type, + const char *); +extern struct rtnl_tc_ops * rtnl_tc_get_ops(struct rtnl_tc *); +extern int rtnl_tc_register(struct rtnl_tc_ops *); +extern void rtnl_tc_unregister(struct rtnl_tc_ops *); + +extern void rtnl_tc_type_register(struct rtnl_tc_type_ops *); +extern void rtnl_tc_type_unregister(struct rtnl_tc_type_ops *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/netlink/route/tc.h b/include/netlink/route/tc.h index 4ba0e06..17021be 100644 --- a/include/netlink/route/tc.h +++ b/include/netlink/route/tc.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 + * Copyright (c) 2003-2011 Thomas Graf */ #ifndef NETLINK_TC_H_ @@ -23,12 +23,31 @@ extern "C" { #endif +/** + * Traffic control object + * @ingroup tc + */ struct rtnl_tc; /** + * Macro to cast qdisc/class/classifier to tc object * @ingroup tc + * + * @code + * rtnl_tc_set_mpu(TC_CAST(qdisc), 40); + * @endcode */ -enum rtnl_tc_stats_id { +#define TC_CAST(ptr) ((struct rtnl_tc *) (ptr)) + +/** + * Traffic control statistical identifier + * @ingroup tc + * + * @code + * uint64_t n = rtnl_tc_get_stat(TC_CAST(class), RTNL_TC_PACKETS); + * @endcode + */ +enum rtnl_tc_stat { RTNL_TC_PACKETS, /**< Number of packets seen */ RTNL_TC_BYTES, /**< Total bytes seen */ RTNL_TC_RATE_BPS, /**< Current bits/s (rate estimator) */ @@ -58,8 +77,9 @@ extern void rtnl_tc_set_handle(struct rtnl_tc *, uint32_t); extern uint32_t rtnl_tc_get_handle(struct rtnl_tc *); extern void rtnl_tc_set_parent(struct rtnl_tc *, uint32_t); extern uint32_t rtnl_tc_get_parent(struct rtnl_tc *); +extern int rtnl_tc_set_kind(struct rtnl_tc *, const char *); extern char * rtnl_tc_get_kind(struct rtnl_tc *); -extern uint64_t rtnl_tc_get_stat(struct rtnl_tc *, int ); +extern uint64_t rtnl_tc_get_stat(struct rtnl_tc *, enum rtnl_tc_stat); extern int rtnl_tc_calc_txtime(int, int); extern int rtnl_tc_calc_bufsize(int, int); diff --git a/lib/Makefile.am b/lib/Makefile.am index ccab7ca..25a7ac5 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -43,11 +43,10 @@ route/cls/ematch_syntax.c: route/cls/ematch_syntax.y libnl_route_la_LIBADD = libnl.la libnl_route_la_SOURCES = \ - route/addr.c route/class.c route/class_api.c route/class_obj.c \ - route/cls.c route/cls_api.c route/cls_obj.c route/link.c \ + route/addr.c route/class.c route/cls.c route/link.c \ route/neigh.c route/neightbl.c route/nexthop.c route/qdisc.c \ - route/qdisc_api.c route/qdisc_obj.c route/route.c route/route_obj.c \ - route/route_utils.c route/rtnl.c route/rule.c route/tc.c route/classid.c \ + route/route.c route/route_obj.c route/route_utils.c route/rtnl.c \ + route/rule.c route/tc.c route/classid.c \ \ route/cls/fw.c route/cls/police.c route/cls/u32.c route/cls/basic.c \ route/cls/cgroup.c \ diff --git a/lib/cli/cls/basic.c b/lib/cli/cls/basic.c index 9ec46ef..1939988 100644 --- a/lib/cli/cls/basic.c +++ b/lib/cli/cls/basic.c @@ -6,10 +6,11 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2010 Thomas Graf + * Copyright (c) 2010-2011 Thomas Graf */ #include +#include #include #include @@ -29,8 +30,9 @@ static void print_usage(void) " nl-cls-add --dev=eth0 --parent=q_root basic --target=c_default\n"); } -static int parse_argv(struct rtnl_cls *cls, int argc, char **argv) +static void parse_argv(struct rtnl_tc *tc, int argc, char **argv) { + struct rtnl_cls *cls = (struct rtnl_cls *) tc; struct rtnl_ematch_tree *tree; uint32_t target; int err; @@ -71,22 +73,21 @@ static int parse_argv(struct rtnl_cls *cls, int argc, char **argv) break; } } - - return 0; } -static struct nl_cli_cls_module basic_module = +static struct nl_cli_tc_module basic_module = { - .cm_name = "basic", - .cm_parse_argv = parse_argv, + .tm_name = "basic", + .tm_type = RTNL_TC_TYPE_CLS, + .tm_parse_argv = parse_argv, }; static void __init basic_init(void) { - nl_cli_cls_register(&basic_module); + nl_cli_tc_register(&basic_module); } static void __exit basic_exit(void) { - nl_cli_cls_unregister(&basic_module); + nl_cli_tc_unregister(&basic_module); } diff --git a/lib/cli/cls/cgroup.c b/lib/cli/cls/cgroup.c index 41920ea..fae6208 100644 --- a/lib/cli/cls/cgroup.c +++ b/lib/cli/cls/cgroup.c @@ -6,10 +6,11 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2010 Thomas Graf + * Copyright (c) 2010-2011 Thomas Graf */ #include +#include #include #include @@ -26,8 +27,9 @@ static void print_usage(void) " nl-cls-add --dev=eth0 --parent=q_root cgroup\n"); } -static int parse_argv(struct rtnl_cls *cls, int argc, char **argv) +static void parse_argv(struct rtnl_tc *tc, int argc, char **argv) { + struct rtnl_cls *cls = (struct rtnl_cls *) tc; struct rtnl_ematch_tree *tree; for (;;) { @@ -53,22 +55,21 @@ static int parse_argv(struct rtnl_cls *cls, int argc, char **argv) break; } } - - return 0; } -static struct nl_cli_cls_module cgroup_module = +static struct nl_cli_tc_module cgroup_module = { - .cm_name = "cgroup", - .cm_parse_argv = parse_argv, + .tm_name = "cgroup", + .tm_type = RTNL_TC_TYPE_CLS, + .tm_parse_argv = parse_argv, }; static void __init cgroup_init(void) { - nl_cli_cls_register(&cgroup_module); + nl_cli_tc_register(&cgroup_module); } static void __exit cgroup_exit(void) { - nl_cli_cls_unregister(&cgroup_module); + nl_cli_tc_unregister(&cgroup_module); } diff --git a/lib/cli/qdisc/bfifo.c b/lib/cli/qdisc/bfifo.c index 2f74659..710d6c4 100644 --- a/lib/cli/qdisc/bfifo.c +++ b/lib/cli/qdisc/bfifo.c @@ -6,11 +6,11 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2010 Thomas Graf + * Copyright (c) 2010-2011 Thomas Graf */ #include -#include +#include #include static void print_usage(void) @@ -27,8 +27,9 @@ static void print_usage(void) " nl-qdisc-add --dev=eth1 --parent=root bfifo --limit=4096\n"); } -static void bfifo_parse_argv(struct rtnl_qdisc *qdisc, int argc, char **argv) +static void bfifo_parse_argv(struct rtnl_tc *tc, int argc, char **argv) { + struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) tc; int limit; for (;;) { @@ -64,18 +65,19 @@ static void bfifo_parse_argv(struct rtnl_qdisc *qdisc, int argc, char **argv) } } -static struct nl_cli_qdisc_module bfifo_module = +static struct nl_cli_tc_module bfifo_module = { - .qm_name = "bfifo", - .qm_parse_qdisc_argv = bfifo_parse_argv, + .tm_name = "bfifo", + .tm_type = RTNL_TC_TYPE_QDISC, + .tm_parse_argv = bfifo_parse_argv, }; static void __init bfifo_init(void) { - nl_cli_qdisc_register(&bfifo_module); + nl_cli_tc_register(&bfifo_module); } static void __exit bfifo_exit(void) { - nl_cli_qdisc_unregister(&bfifo_module); + nl_cli_tc_unregister(&bfifo_module); } diff --git a/lib/cli/qdisc/blackhole.c b/lib/cli/qdisc/blackhole.c index 1eebb32..af9dc6d 100644 --- a/lib/cli/qdisc/blackhole.c +++ b/lib/cli/qdisc/blackhole.c @@ -6,11 +6,11 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2010 Thomas Graf + * Copyright (c) 2010-2011 Thomas Graf */ #include -#include +#include static void print_usage(void) { @@ -25,7 +25,7 @@ static void print_usage(void) " nl-qdisc-add --dev=eth1 --parent=root blackhole\n"); } -static void blackhole_parse_argv(struct rtnl_qdisc *qdisc, int argc, char **argv) +static void blackhole_parse_argv(struct rtnl_tc *tc, int argc, char **argv) { for (;;) { int c, optidx = 0; @@ -46,18 +46,19 @@ static void blackhole_parse_argv(struct rtnl_qdisc *qdisc, int argc, char **argv } } -static struct nl_cli_qdisc_module blackhole_module = +static struct nl_cli_tc_module blackhole_module = { - .qm_name = "blackhole", - .qm_parse_qdisc_argv = blackhole_parse_argv, + .tm_name = "blackhole", + .tm_type = RTNL_TC_TYPE_QDISC, + .tm_parse_argv = blackhole_parse_argv, }; static void __init blackhole_init(void) { - nl_cli_qdisc_register(&blackhole_module); + nl_cli_tc_register(&blackhole_module); } static void __exit blackhole_exit(void) { - nl_cli_qdisc_unregister(&blackhole_module); + nl_cli_tc_unregister(&blackhole_module); } diff --git a/lib/cli/qdisc/htb.c b/lib/cli/qdisc/htb.c index febf429..32ed272 100644 --- a/lib/cli/qdisc/htb.c +++ b/lib/cli/qdisc/htb.c @@ -6,11 +6,11 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2010 Thomas Graf + * Copyright (c) 2010-2011 Thomas Graf */ #include -#include +#include #include static void print_qdisc_usage(void) @@ -28,8 +28,10 @@ static void print_qdisc_usage(void) " nl-qdisc-add --dev=eth1 --parent=root --handle=1: htb --default=10\n"); } -static void htb_parse_qdisc_argv(struct rtnl_qdisc *qdisc, int argc, char **argv) +static void htb_parse_qdisc_argv(struct rtnl_tc *tc, int argc, char **argv) { + struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) tc; + for (;;) { int c, optidx = 0; enum { @@ -82,8 +84,9 @@ static void print_class_usage(void) " nl-class-add --dev=eth1 --parent=1: --classid=1:1 htb --rate=20mbit\n"); } -static void htb_parse_class_argv(struct rtnl_class *class, int argc, char **argv) +static void htb_parse_class_argv(struct rtnl_tc *tc, int argc, char **argv) { + struct rtnl_class *class = (struct rtnl_class *) tc; long rate; for (;;) { @@ -173,19 +176,28 @@ static void htb_parse_class_argv(struct rtnl_class *class, int argc, char **argv } } -static struct nl_cli_qdisc_module htb_module = +static struct nl_cli_tc_module htb_qdisc_module = { - .qm_name = "htb", - .qm_parse_qdisc_argv = htb_parse_qdisc_argv, - .qm_parse_class_argv = htb_parse_class_argv, + .tm_name = "htb", + .tm_type = RTNL_TC_TYPE_QDISC, + .tm_parse_argv = htb_parse_qdisc_argv, +}; + +static struct nl_cli_tc_module htb_class_module = +{ + .tm_name = "htb", + .tm_type = RTNL_TC_TYPE_CLASS, + .tm_parse_argv = htb_parse_class_argv, }; static void __init htb_init(void) { - nl_cli_qdisc_register(&htb_module); + nl_cli_tc_register(&htb_qdisc_module); + nl_cli_tc_register(&htb_class_module); } static void __exit htb_exit(void) { - nl_cli_qdisc_unregister(&htb_module); + nl_cli_tc_unregister(&htb_class_module); + nl_cli_tc_unregister(&htb_qdisc_module); } diff --git a/lib/cli/qdisc/pfifo.c b/lib/cli/qdisc/pfifo.c index 38cc97a..946aba6 100644 --- a/lib/cli/qdisc/pfifo.c +++ b/lib/cli/qdisc/pfifo.c @@ -7,11 +7,11 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2010 Thomas Graf + * Copyright (c) 2010-2011 Thomas Graf */ #include -#include +#include #include static void print_usage(void) @@ -28,8 +28,10 @@ static void print_usage(void) " nl-qdisc-add --dev=eth1 --parent=root pfifo --limit=32\n"); } -static void pfifo_parse_argv(struct rtnl_qdisc *qdisc, int argc, char **argv) +static void pfifo_parse_argv(struct rtnl_tc *tc, int argc, char **argv) { + struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) tc; + for (;;) { int c, optidx = 0; enum { @@ -57,18 +59,19 @@ static void pfifo_parse_argv(struct rtnl_qdisc *qdisc, int argc, char **argv) } } -static struct nl_cli_qdisc_module pfifo_module = +static struct nl_cli_tc_module pfifo_module = { - .qm_name = "pfifo", - .qm_parse_qdisc_argv = pfifo_parse_argv, + .tm_name = "pfifo", + .tm_type = RTNL_TC_TYPE_QDISC, + .tm_parse_argv = pfifo_parse_argv, }; static void __init pfifo_init(void) { - nl_cli_qdisc_register(&pfifo_module); + nl_cli_tc_register(&pfifo_module); } static void __exit pfifo_exit(void) { - nl_cli_qdisc_unregister(&pfifo_module); + nl_cli_tc_unregister(&pfifo_module); } diff --git a/lib/route/class.c b/lib/route/class.c index 9717d20..47356e2 100644 --- a/lib/route/class.c +++ b/lib/route/class.c @@ -18,44 +18,42 @@ #include #include #include -#include +#include #include -#include #include #include #include static struct nl_cache_ops rtnl_class_ops; +static struct nl_object_ops class_obj_ops; + +static void class_dump_details(struct rtnl_tc *tc, struct nl_dump_params *p) +{ + struct rtnl_class *class = (struct rtnl_class *) tc; + char buf[32]; + + if (class->c_info) + nl_dump(p, "child-qdisc %s ", + rtnl_tc_handle2str(class->c_info, buf, sizeof(buf))); +} + static int class_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, - struct nlmsghdr *n, struct nl_parser_param *pp) + struct nlmsghdr *nlh, struct nl_parser_param *pp) { - int err; struct rtnl_class *class; - struct rtnl_class_ops *cops; + int err; - class = rtnl_class_alloc(); - if (!class) { - err = -NLE_NOMEM; + if (!(class = rtnl_class_alloc())) + return -NLE_NOMEM; + + if ((err = rtnl_tc_msg_parse(nlh, TC_CAST(class))) < 0) goto errout; - } - class->ce_msgtype = n->nlmsg_type; - err = tca_msg_parser(n, (struct rtnl_tc *) class); - if (err < 0) - goto errout_free; - - cops = rtnl_class_lookup_ops(class); - if (cops && cops->co_msg_parser) { - err = cops->co_msg_parser(class); - if (err < 0) - goto errout_free; - } - - err = pp->pp_cb((struct nl_object *) class, pp); -errout_free: - rtnl_class_put(class); + err = pp->pp_cb(OBJ_CAST(class), pp); errout: + rtnl_class_put(class); + return err; } @@ -78,30 +76,7 @@ static int class_request_update(struct nl_cache *cache, struct nl_sock *sk) static int class_build(struct rtnl_class *class, int type, int flags, struct nl_msg **result) { - struct rtnl_class_ops *cops; - int err; - - err = tca_build_msg((struct rtnl_tc *) class, type, flags, result); - if (err < 0) - return err; - - cops = rtnl_class_lookup_ops(class); - if (cops && cops->co_get_opts) { - struct nl_msg *opts; - - opts = cops->co_get_opts(class); - if (opts) { - err = nla_put_nested(*result, TCA_OPTIONS, opts); - nlmsg_free(opts); - if (err < 0) - goto errout; - } - } - - return 0; -errout: - nlmsg_free(*result); - return err; + return rtnl_tc_msg_build(TC_CAST(class), type, flags, result); } /** @@ -213,6 +188,117 @@ int rtnl_class_delete(struct nl_sock *sk, struct rtnl_class *class) /** @} */ +/** + * @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 Leaf Qdisc + * @{ + */ + +/** + * 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 + */ +struct rtnl_qdisc *rtnl_class_leaf_qdisc(struct rtnl_class *class, + struct nl_cache *cache) +{ + struct rtnl_qdisc *leaf; + + if (!class->c_info) + return NULL; + + leaf = rtnl_qdisc_get_by_parent(cache, class->c_ifindex, + class->c_handle); + if (!leaf || leaf->q_handle != class->c_info) + return NULL; + + return leaf; +} + +/** @} */ + + +/** + * @name Iterators + * @{ + */ + +/** + * 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 * @{ @@ -276,6 +362,28 @@ struct rtnl_class *rtnl_class_get(struct nl_cache *cache, int ifindex, /** @} */ +static struct rtnl_tc_type_ops class_ops = { + .tt_type = RTNL_TC_TYPE_CLASS, + .tt_dump_prefix = "class", + .tt_dump = { + [NL_DUMP_DETAILS] = class_dump_details, + }, +}; + +static struct nl_object_ops class_obj_ops = { + .oo_name = "route/class", + .oo_size = sizeof(struct rtnl_class), + .oo_free_data = rtnl_tc_free_data, + .oo_clone = rtnl_tc_clone, + .oo_dump = { + [NL_DUMP_LINE] = rtnl_tc_dump_line, + [NL_DUMP_DETAILS] = rtnl_tc_dump_details, + [NL_DUMP_STATS] = rtnl_tc_dump_stats, + }, + .oo_compare = rtnl_tc_compare, + .oo_id_attrs = (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE), +}; + static struct nl_cache_ops rtnl_class_ops = { .co_name = "route/class", .co_hdrsize = sizeof(struct tcmsg), @@ -293,12 +401,14 @@ static struct nl_cache_ops rtnl_class_ops = { static void __init class_init(void) { + rtnl_tc_type_register(&class_ops); nl_cache_mngt_register(&rtnl_class_ops); } static void __exit class_exit(void) { nl_cache_mngt_unregister(&rtnl_class_ops); + rtnl_tc_type_unregister(&class_ops); } /** @} */ diff --git a/lib/route/class_api.c b/lib/route/class_api.c deleted file mode 100644 index 374cf0f..0000000 --- a/lib/route/class_api.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * lib/route/class_api.c Queueing Classes Module API - * - * 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 - */ - -/** - * @ingroup class - * @defgroup class_api Class Modules - * @{ - */ - -#include -#include -#include -#include -#include -#include -#include - -static struct rtnl_class_ops *class_ops_list; - -/** - * @name Module API - * @{ - */ - -/** - * Register a class module - * @arg cops class module operations - */ -int rtnl_class_register(struct rtnl_class_ops *cops) -{ - struct rtnl_class_ops *o, **op; - - if (!cops->co_kind[0]) - BUG(); - - for (op = &class_ops_list; (o = *op) != NULL; op = &o->co_next) - if (!strcasecmp(cops->co_kind, o->co_kind)) - return -NLE_EXIST; - - cops->co_next = NULL; - *op = cops; - - return 0; -} - -/** - * Unregister a class module - * @arg cops class module operations - */ -int rtnl_class_unregister(struct rtnl_class_ops *cops) -{ - struct rtnl_class_ops *o, **op; - - for (op = &class_ops_list; (o = *op) != NULL; op = &o->co_next) - if (!strcasecmp(cops->co_kind, o->co_kind)) - break; - - if (!o) - return -NLE_OBJ_NOTFOUND; - - *op = cops->co_next; - - return 0; -} - -struct rtnl_class_ops *__rtnl_class_lookup_ops(const char *kind) -{ - struct rtnl_class_ops *cops; - - for (cops = class_ops_list; cops; cops = cops->co_next) - if (!strcmp(kind, cops->co_kind)) - return cops; - - return NULL; -} - -/** - * Lookup class operations for a class object - * @arg class Class object. - * - * @return Class operations or NULL if not found. - */ -struct rtnl_class_ops *rtnl_class_lookup_ops(struct rtnl_class *class) -{ - if (!class->c_ops) - class->c_ops = __rtnl_class_lookup_ops(class->c_kind); - - return class->c_ops; -} - - -/** @} */ - -/** @} */ diff --git a/lib/route/class_obj.c b/lib/route/class_obj.c deleted file mode 100644 index 097db25..0000000 --- a/lib/route/class_obj.c +++ /dev/null @@ -1,240 +0,0 @@ -/* - * lib/route/class.c Queueing 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 - */ - -/** - * @ingroup class - * @defgroup class_obj Class Object - * @{ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static void class_free_data(struct nl_object *obj) -{ - struct rtnl_class *class = (struct rtnl_class *) obj; - struct rtnl_class_ops *cops; - - tca_free_data((struct rtnl_tc *) class); - - cops = rtnl_class_lookup_ops(class); - if (cops && cops->co_free_data) - cops->co_free_data(class); -} - -static int class_clone(struct nl_object *_dst, struct nl_object *_src) -{ - struct rtnl_class *dst = nl_object_priv(_dst); - struct rtnl_class *src = nl_object_priv(_src); - struct rtnl_class_ops *cops; - int err; - - err = tca_clone((struct rtnl_tc *) dst, (struct rtnl_tc *) src); - if (err < 0) - goto errout; - - cops = rtnl_class_lookup_ops(src); - if (cops && cops->co_clone) - err = cops->co_clone(dst, src); -errout: - return err; -} - -static void class_dump_line(struct nl_object *obj, struct nl_dump_params *p) -{ - struct rtnl_class *class = (struct rtnl_class *) obj; - struct rtnl_class_ops *cops; - - tca_dump_line((struct rtnl_tc *) class, "class", p); - - cops = rtnl_class_lookup_ops(class); - if (cops && cops->co_dump[NL_DUMP_LINE]) - cops->co_dump[NL_DUMP_LINE](class, p); - nl_dump(p, "\n"); -} - -static void class_dump_details(struct nl_object *obj, struct nl_dump_params *p) -{ - struct rtnl_class *class = (struct rtnl_class *) obj; - struct rtnl_class_ops *cops; - - class_dump_line(obj, p); - tca_dump_details((struct rtnl_tc *) class, p); - - if (class->c_info) { - char buf[32]; - nl_dump(p, "child-qdisc %s ", - rtnl_tc_handle2str(class->c_info, buf, sizeof(buf))); - } - - cops = rtnl_class_lookup_ops(class); - if (cops && cops->co_dump[NL_DUMP_DETAILS]) - cops->co_dump[NL_DUMP_DETAILS](class, p); - else if (!class->c_info) - nl_dump(p, "noop (no leaf qdisc)"); - - nl_dump(p, "\n"); -} - -static void class_dump_stats(struct nl_object *obj, struct nl_dump_params *p) -{ - struct rtnl_class *class = (struct rtnl_class *) obj; - struct rtnl_class_ops *cops; - - class_dump_details(obj, p); - tca_dump_stats((struct rtnl_tc *) class, p); - nl_dump(p, "\n"); - - cops = rtnl_class_lookup_ops(class); - if (cops && cops->co_dump[NL_DUMP_STATS]) - cops->co_dump[NL_DUMP_STATS](class, p); -} - -/** - * @name Allocation/Freeing - * @{ - */ - -struct rtnl_class *rtnl_class_alloc(void) -{ - return (struct rtnl_class *) nl_object_alloc(&class_obj_ops); -} - -void rtnl_class_put(struct rtnl_class *class) -{ - nl_object_put((struct nl_object *) class); -} - -/** @} */ - -/** - * @name Leaf Qdisc - * @{ - */ - -/** - * 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 - */ -struct rtnl_qdisc *rtnl_class_leaf_qdisc(struct rtnl_class *class, - struct nl_cache *cache) -{ - struct rtnl_qdisc *leaf; - - if (!class->c_info) - return NULL; - - leaf = rtnl_qdisc_get_by_parent(cache, class->c_ifindex, - class->c_handle); - if (!leaf || leaf->q_handle != class->c_info) - return NULL; - - return leaf; -} - -/** @} */ - - -/** - * @name Iterators - * @{ - */ - -/** - * 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((struct rtnl_tc *) filter, class->c_handle); - rtnl_tc_set_ifindex((struct rtnl_tc *) filter, class->c_ifindex); - rtnl_class_set_kind(filter, class->c_kind); - - nl_cache_foreach_filter(cache, (struct nl_object *) 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 Attributes - * @{ - */ - -void rtnl_class_set_kind(struct rtnl_class *class, const char *name) -{ - tca_set_kind((struct rtnl_tc *) class, name); - class->c_ops = __rtnl_class_lookup_ops(name); -} - -/** @} */ - -struct nl_object_ops class_obj_ops = { - .oo_name = "route/class", - .oo_size = sizeof(struct rtnl_class), - .oo_free_data = class_free_data, - .oo_clone = class_clone, - .oo_dump = { - [NL_DUMP_LINE] = class_dump_line, - [NL_DUMP_DETAILS] = class_dump_details, - [NL_DUMP_STATS] = class_dump_stats, - }, - .oo_compare = tca_compare, - .oo_id_attrs = (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE), -}; - -/** @} */ diff --git a/lib/route/cls.c b/lib/route/cls.c index 093b030..a041baa 100644 --- a/lib/route/cls.c +++ b/lib/route/cls.c @@ -28,66 +28,26 @@ #include #include #include -#include +#include #include -#include #include +/** @cond SKIP */ +#define CLS_ATTR_PRIO (TCA_ATTR_MAX << 1) +#define CLS_ATTR_PROTOCOL (TCA_ATTR_MAX << 2) +/** @endcond */ + +static struct nl_object_ops cls_obj_ops; static struct nl_cache_ops rtnl_cls_ops; -static int cls_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, - struct nlmsghdr *nlh, struct nl_parser_param *pp) -{ - struct rtnl_cls_ops *cops; - struct rtnl_cls *cls; - int err; - - cls = rtnl_cls_alloc(); - if (!cls) { - err = -NLE_NOMEM; - goto errout; - } - cls->ce_msgtype = nlh->nlmsg_type; - - err = tca_msg_parser(nlh, (struct rtnl_tc *) cls); - if (err < 0) - goto errout_free; - - cls->c_prio = TC_H_MAJ(cls->c_info) >> 16; - cls->c_protocol = ntohs(TC_H_MIN(cls->c_info)); - - cops = rtnl_cls_lookup_ops(cls); - if (cops && cops->co_msg_parser && (err = cops->co_msg_parser(cls)) < 0) - goto errout_free; - - err = pp->pp_cb((struct nl_object *) cls, pp); -errout_free: - rtnl_cls_put(cls); -errout: - return err; -} - -static int cls_request_update(struct nl_cache *cache, struct nl_sock *sk) -{ - struct tcmsg tchdr = { - .tcm_family = AF_UNSPEC, - .tcm_ifindex = cache->c_iarg1, - .tcm_parent = cache->c_iarg2, - }; - - return nl_send_simple(sk, RTM_GETTFILTER, NLM_F_DUMP, &tchdr, - sizeof(tchdr)); -} - static int cls_build(struct rtnl_cls *cls, int type, int flags, struct nl_msg **result) { - struct rtnl_cls_ops *cops; int err, prio, proto; struct tcmsg *tchdr; - err = tca_build_msg((struct rtnl_tc *) cls, type, flags, result); + err = rtnl_tc_msg_build(TC_CAST(cls), type, flags, result); if (err < 0) return err; @@ -96,27 +56,68 @@ static int cls_build(struct rtnl_cls *cls, int type, int flags, proto = rtnl_cls_get_protocol(cls); tchdr->tcm_info = TC_H_MAKE(prio << 16, htons(proto)); - cops = rtnl_cls_lookup_ops(cls); - if (cops && cops->co_get_opts) { - struct nlattr *opts; - - if (!(opts = nla_nest_start(*result, TCA_OPTIONS))) { - err = -NLE_NOMEM; - goto errout; - } - - if ((err = cops->co_get_opts(cls, *result)) < 0) - goto errout; - - nla_nest_end(*result, opts); - } - return 0; -errout: - nlmsg_free(*result); - return err; } +/** + * @name Allocation/Freeing + * @{ + */ + +struct rtnl_cls *rtnl_cls_alloc(void) +{ + struct rtnl_tc *tc; + + tc = TC_CAST(nl_object_alloc(&cls_obj_ops)); + if (tc) + tc->tc_type = RTNL_TC_TYPE_CLS; + + return (struct rtnl_cls *) tc; +} + +void rtnl_cls_put(struct rtnl_cls *cls) +{ + nl_object_put((struct nl_object *) cls); +} + +/** @} */ + +/** + * @name Attributes + * @{ + */ + +void rtnl_cls_set_prio(struct rtnl_cls *cls, uint16_t prio) +{ + cls->c_prio = prio; + cls->ce_mask |= CLS_ATTR_PRIO; +} + +uint16_t rtnl_cls_get_prio(struct rtnl_cls *cls) +{ + if (cls->ce_mask & CLS_ATTR_PRIO) + return cls->c_prio; + else + return 0; +} + +void rtnl_cls_set_protocol(struct rtnl_cls *cls, uint16_t protocol) +{ + cls->c_protocol = protocol; + cls->ce_mask |= CLS_ATTR_PROTOCOL; +} + +uint16_t rtnl_cls_get_protocol(struct rtnl_cls *cls) +{ + if (cls->ce_mask & CLS_ATTR_PROTOCOL) + return cls->c_protocol; + else + return ETH_P_ALL; +} + +/** @} */ + + /** * @name Classifier Addition/Modification/Deletion * @{ @@ -311,6 +312,57 @@ int rtnl_cls_alloc_cache(struct nl_sock *sk, int ifindex, uint32_t parent, st /** @} */ +static void cls_dump_line(struct rtnl_tc *tc, struct nl_dump_params *p) +{ + struct rtnl_cls *cls = (struct rtnl_cls *) tc; + char buf[32]; + + nl_dump(p, " prio %u protocol %s", cls->c_prio, + nl_ether_proto2str(cls->c_protocol, buf, sizeof(buf))); +} + +static int cls_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, + struct nlmsghdr *nlh, struct nl_parser_param *pp) +{ + struct rtnl_cls *cls; + int err; + + if (!(cls = rtnl_cls_alloc())) + return -NLE_NOMEM; + + if ((err = rtnl_tc_msg_parse(nlh, TC_CAST(cls))) < 0) + goto errout; + + cls->c_prio = TC_H_MAJ(cls->c_info) >> 16; + cls->c_protocol = ntohs(TC_H_MIN(cls->c_info)); + + err = pp->pp_cb(OBJ_CAST(cls), pp); +errout: + rtnl_cls_put(cls); + + return err; +} + +static int cls_request_update(struct nl_cache *cache, struct nl_sock *sk) +{ + struct tcmsg tchdr = { + .tcm_family = AF_UNSPEC, + .tcm_ifindex = cache->c_iarg1, + .tcm_parent = cache->c_iarg2, + }; + + return nl_send_simple(sk, RTM_GETTFILTER, NLM_F_DUMP, &tchdr, + sizeof(tchdr)); +} + +static struct rtnl_tc_type_ops cls_ops = { + .tt_type = RTNL_TC_TYPE_CLS, + .tt_dump_prefix = "cls", + .tt_dump = { + [NL_DUMP_LINE] = cls_dump_line, + }, +}; + static struct nl_cache_ops rtnl_cls_ops = { .co_name = "route/cls", .co_hdrsize = sizeof(struct tcmsg), @@ -326,14 +378,30 @@ static struct nl_cache_ops rtnl_cls_ops = { .co_obj_ops = &cls_obj_ops, }; +static struct nl_object_ops cls_obj_ops = { + .oo_name = "route/cls", + .oo_size = sizeof(struct rtnl_cls), + .oo_free_data = rtnl_tc_free_data, + .oo_clone = rtnl_tc_clone, + .oo_dump = { + [NL_DUMP_LINE] = rtnl_tc_dump_line, + [NL_DUMP_DETAILS] = rtnl_tc_dump_details, + [NL_DUMP_STATS] = rtnl_tc_dump_stats, + }, + .oo_compare = rtnl_tc_compare, + .oo_id_attrs = (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE), +}; + static void __init cls_init(void) { + rtnl_tc_type_register(&cls_ops); nl_cache_mngt_register(&rtnl_cls_ops); } static void __exit cls_exit(void) { nl_cache_mngt_unregister(&rtnl_cls_ops); + rtnl_tc_type_unregister(&cls_ops); } /** @} */ diff --git a/lib/route/cls/basic.c b/lib/route/cls/basic.c index 94f0cf7..9d7710a 100644 --- a/lib/route/cls/basic.c +++ b/lib/route/cls/basic.c @@ -6,12 +6,12 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2008-2010 Thomas Graf + * Copyright (c) 2008-2011 Thomas Graf */ /** * @ingroup cls - * @defgroup basic Basic Classifier + * @defgroup cls_basic Basic Classifier * * @par Introduction * The basic classifier is the simplest form of a classifier. It does @@ -25,8 +25,8 @@ #include #include #include +#include #include -#include #include #include @@ -47,50 +47,57 @@ static struct nla_policy basic_policy[TCA_BASIC_MAX+1] = { [TCA_BASIC_EMATCHES] = { .type = NLA_NESTED }, }; -static int basic_clone(struct rtnl_cls *_dst, struct rtnl_cls *_src) +static int basic_clone(void *_dst, void *_src) { return -NLE_OPNOTSUPP; } -static void basic_free_data(struct rtnl_cls *cls) +static void basic_free_data(struct rtnl_tc *tc, void *data) { - struct rtnl_basic *basic = rtnl_cls_data(cls); + struct rtnl_basic *b = data; - rtnl_ematch_tree_free(basic->b_ematch); + if (!b) + return; + + rtnl_ematch_tree_free(b->b_ematch); } -static int basic_msg_parser(struct rtnl_cls *cls) +static int basic_msg_parser(struct rtnl_tc *tc, void *data) { struct nlattr *tb[TCA_BASIC_MAX + 1]; - struct rtnl_basic *basic = rtnl_cls_data(cls); + struct rtnl_basic *b = data; int err; - err = tca_parse(tb, TCA_BASIC_MAX, (struct rtnl_tc *) cls, basic_policy); + err = tca_parse(tb, TCA_BASIC_MAX, tc, basic_policy); if (err < 0) return err; if (tb[TCA_BASIC_CLASSID]) { - basic->b_target = nla_get_u32(tb[TCA_BASIC_CLASSID]); - basic->b_mask |= BASIC_ATTR_TARGET; + b->b_target = nla_get_u32(tb[TCA_BASIC_CLASSID]); + b->b_mask |= BASIC_ATTR_TARGET; } if (tb[TCA_BASIC_EMATCHES]) { if ((err = rtnl_ematch_parse_attr(tb[TCA_BASIC_EMATCHES], - &basic->b_ematch)) < 0) + &b->b_ematch)) < 0) return err; - if (basic->b_ematch) - basic->b_mask |= BASIC_ATTR_EMATCH; + if (b->b_ematch) + b->b_mask |= BASIC_ATTR_EMATCH; } return 0; } -static void basic_dump_line(struct rtnl_cls *cls, struct nl_dump_params *p) +static void basic_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) { - struct rtnl_basic *b = rtnl_cls_data(cls); + struct rtnl_basic *b = data; char buf[32]; + if (!b) + return; + if (b->b_mask & BASIC_ATTR_EMATCH) nl_dump(p, " ematch"); else @@ -101,9 +108,13 @@ static void basic_dump_line(struct rtnl_cls *cls, struct nl_dump_params *p) rtnl_tc_handle2str(b->b_target, buf, sizeof(buf))); } -static void basic_dump_details(struct rtnl_cls *cls, struct nl_dump_params *p) +static void basic_dump_details(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) { - struct rtnl_basic *b = rtnl_cls_data(cls); + struct rtnl_basic *b = data; + + if (!b) + return; if (b->b_mask & BASIC_ATTR_EMATCH) { nl_dump_line(p, " ematch "); @@ -112,9 +123,13 @@ static void basic_dump_details(struct rtnl_cls *cls, struct nl_dump_params *p) nl_dump(p, "no options.\n"); } -static int basic_get_opts(struct rtnl_cls *cls, struct nl_msg *msg) +static int basic_msg_fill(struct rtnl_tc *tc, void *data, + struct nl_msg *msg) { - struct rtnl_basic *b = rtnl_cls_data(cls); + struct rtnl_basic *b = data; + + if (!b) + return 0; if (!(b->b_mask & BASIC_ATTR_TARGET)) return -NLE_MISSING_ATTR; @@ -138,7 +153,10 @@ nla_put_failure: void rtnl_basic_set_target(struct rtnl_cls *cls, uint32_t target) { - struct rtnl_basic *b = rtnl_cls_data(cls); + struct rtnl_basic *b; + + if (!(b = rtnl_tc_data(TC_CAST(cls)))) + return; b->b_target = target; b->b_mask |= BASIC_ATTR_TARGET; @@ -146,14 +164,20 @@ void rtnl_basic_set_target(struct rtnl_cls *cls, uint32_t target) uint32_t rtnl_basic_get_target(struct rtnl_cls *cls) { - struct rtnl_basic *b = rtnl_cls_data(cls); + struct rtnl_basic *b; + + if (!(b = rtnl_tc_data(TC_CAST(cls)))) + return 0; return b->b_target; } void rtnl_basic_set_ematch(struct rtnl_cls *cls, struct rtnl_ematch_tree *tree) { - struct rtnl_basic *b = rtnl_cls_data(cls); + struct rtnl_basic *b; + + if (!(b = rtnl_tc_data(TC_CAST(cls)))) + return; if (b->b_ematch) { rtnl_ematch_tree_free(b->b_ematch); @@ -168,19 +192,25 @@ void rtnl_basic_set_ematch(struct rtnl_cls *cls, struct rtnl_ematch_tree *tree) struct rtnl_ematch_tree *rtnl_basic_get_ematch(struct rtnl_cls *cls) { - return ((struct rtnl_basic *) rtnl_cls_data(cls))->b_ematch; + struct rtnl_basic *b; + + if (!(b = rtnl_tc_data(TC_CAST(cls)))) + return NULL; + + return b->b_ematch; } /** @} */ -static struct rtnl_cls_ops basic_ops = { - .co_kind = "basic", - .co_size = sizeof(struct rtnl_basic), - .co_msg_parser = basic_msg_parser, - .co_clone = basic_clone, - .co_free_data = basic_free_data, - .co_get_opts = basic_get_opts, - .co_dump = { +static struct rtnl_tc_ops basic_ops = { + .to_kind = "basic", + .to_type = RTNL_TC_TYPE_CLS, + .to_size = sizeof(struct rtnl_basic), + .to_msg_parser = basic_msg_parser, + .to_clone = basic_clone, + .to_free_data = basic_free_data, + .to_msg_fill = basic_msg_fill, + .to_dump = { [NL_DUMP_LINE] = basic_dump_line, [NL_DUMP_DETAILS] = basic_dump_details, }, @@ -188,12 +218,12 @@ static struct rtnl_cls_ops basic_ops = { static void __init basic_init(void) { - rtnl_cls_register(&basic_ops); + rtnl_tc_register(&basic_ops); } static void __exit basic_exit(void) { - rtnl_cls_unregister(&basic_ops); + rtnl_tc_unregister(&basic_ops); } /** @} */ diff --git a/lib/route/cls/cgroup.c b/lib/route/cls/cgroup.c index 751e385..230863b 100644 --- a/lib/route/cls/cgroup.c +++ b/lib/route/cls/cgroup.c @@ -6,12 +6,12 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2009-2010 Thomas Graf + * Copyright (c) 2009-2011 Thomas Graf */ /** - * @ingroup cls_api - * @defgroup cgroup Control Groups Classifier + * @ingroup cls + * @defgroup cls_cgroup Control Groups Classifier * * @{ */ @@ -21,8 +21,8 @@ #include #include #include +#include #include -#include #include #include @@ -34,26 +34,28 @@ static struct nla_policy cgroup_policy[TCA_CGROUP_MAX+1] = { [TCA_CGROUP_EMATCHES] = { .type = NLA_NESTED }, }; -static int cgroup_clone(struct rtnl_cls *_dst, struct rtnl_cls *_src) +static int cgroup_clone(void *dst, void *src) { return -NLE_OPNOTSUPP; } -static void cgroup_free_data(struct rtnl_cls *cls) +static void cgroup_free_data(struct rtnl_tc *tc, void *data) { - struct rtnl_cgroup *c = rtnl_cls_data(cls); + struct rtnl_cgroup *c = data; + + if (!c) + return; rtnl_ematch_tree_free(c->cg_ematch); } -static int cgroup_msg_parser(struct rtnl_cls *cls) +static int cgroup_msg_parser(struct rtnl_tc *tc, void *data) { - struct rtnl_cgroup *c = rtnl_cls_data(cls); struct nlattr *tb[TCA_CGROUP_MAX + 1]; + struct rtnl_cgroup *c = data; int err; - err = tca_parse(tb, TCA_CGROUP_MAX, (struct rtnl_tc *) cls, - cgroup_policy); + err = tca_parse(tb, TCA_CGROUP_MAX, tc, cgroup_policy); if (err < 0) return err; @@ -73,9 +75,13 @@ static int cgroup_msg_parser(struct rtnl_cls *cls) return 0; } -static void cgroup_dump_line(struct rtnl_cls *cls, struct nl_dump_params *p) +static void cgroup_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) { - struct rtnl_cgroup *c = rtnl_cls_data(cls); + struct rtnl_cgroup *c = data; + + if (!c) + return; if (c->cg_mask & CGROUP_ATTR_EMATCH) nl_dump(p, " ematch"); @@ -83,22 +89,34 @@ static void cgroup_dump_line(struct rtnl_cls *cls, struct nl_dump_params *p) nl_dump(p, " match-all"); } -static void cgroup_dump_details(struct rtnl_cls *cls, struct nl_dump_params *p) +static void cgroup_dump_details(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) { - struct rtnl_cgroup *c = rtnl_cls_data(cls); + struct rtnl_cgroup *c = data; + + if (!c) + return; if (c->cg_mask & CGROUP_ATTR_EMATCH) { nl_dump_line(p, " ematch "); - rtnl_ematch_tree_dump(c->cg_ematch, p); + + if (c->cg_ematch) + rtnl_ematch_tree_dump(c->cg_ematch, p); + else + nl_dump(p, ""); } else - nl_dump(p, "no options.\n"); + nl_dump(p, "no options"); } -static int cgroup_get_opts(struct rtnl_cls *cls, struct nl_msg *msg) +static int cgroup_fill_msg(struct rtnl_tc *tc, void *data, + struct nl_msg *msg) { - struct rtnl_cgroup *c = rtnl_cls_data(cls); + struct rtnl_cgroup *c = data; - if (!(cls->ce_mask & TCA_ATTR_HANDLE)) + if (!c) + BUG(); + + if (!(tc->ce_mask & TCA_ATTR_HANDLE)) return -NLE_MISSING_ATTR; if (c->cg_mask & CGROUP_ATTR_EMATCH) @@ -116,7 +134,10 @@ static int cgroup_get_opts(struct rtnl_cls *cls, struct nl_msg *msg) void rtnl_cgroup_set_ematch(struct rtnl_cls *cls, struct rtnl_ematch_tree *tree) { - struct rtnl_cgroup *c = rtnl_cls_data(cls); + struct rtnl_cgroup *c; + + if (!(c = rtnl_tc_data(TC_CAST(cls)))) + BUG(); if (c->cg_ematch) { rtnl_ematch_tree_free(c->cg_ematch); @@ -131,19 +152,25 @@ void rtnl_cgroup_set_ematch(struct rtnl_cls *cls, struct rtnl_ematch_tree *tree) struct rtnl_ematch_tree *rtnl_cgroup_get_ematch(struct rtnl_cls *cls) { - return ((struct rtnl_cgroup *) rtnl_cls_data(cls))->cg_ematch; + struct rtnl_cgroup *c; + + if (!(c = rtnl_tc_data(TC_CAST(cls)))) + BUG(); + + return c->cg_ematch; } /** @} */ -static struct rtnl_cls_ops cgroup_ops = { - .co_kind = "cgroup", - .co_size = sizeof(struct rtnl_cgroup), - .co_clone = cgroup_clone, - .co_msg_parser = cgroup_msg_parser, - .co_free_data = cgroup_free_data, - .co_get_opts = cgroup_get_opts, - .co_dump = { +static struct rtnl_tc_ops cgroup_ops = { + .to_kind = "cgroup", + .to_type = RTNL_TC_TYPE_CLS, + .to_size = sizeof(struct rtnl_cgroup), + .to_clone = cgroup_clone, + .to_msg_parser = cgroup_msg_parser, + .to_free_data = cgroup_free_data, + .to_msg_fill = cgroup_fill_msg, + .to_dump = { [NL_DUMP_LINE] = cgroup_dump_line, [NL_DUMP_DETAILS] = cgroup_dump_details, }, @@ -151,12 +178,12 @@ static struct rtnl_cls_ops cgroup_ops = { static void __init cgroup_init(void) { - rtnl_cls_register(&cgroup_ops); + rtnl_tc_register(&cgroup_ops); } static void __exit cgroup_exit(void) { - rtnl_cls_unregister(&cgroup_ops); + rtnl_tc_unregister(&cgroup_ops); } /** @} */ diff --git a/lib/route/cls/ematch.c b/lib/route/cls/ematch.c index e2719c2..8c9c3dd 100644 --- a/lib/route/cls/ematch.c +++ b/lib/route/cls/ematch.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include @@ -511,6 +510,9 @@ static void dump_ematch_sequence(struct nl_list_head *head, void rtnl_ematch_tree_dump(struct rtnl_ematch_tree *tree, struct nl_dump_params *p) { + if (!tree) + BUG(); + dump_ematch_sequence(&tree->et_list, p); nl_dump(p, "\n"); } diff --git a/lib/route/cls/fw.c b/lib/route/cls/fw.c index b8055fe..11c9c67 100644 --- a/lib/route/cls/fw.c +++ b/lib/route/cls/fw.c @@ -6,14 +6,14 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2009 Thomas Graf + * Copyright (c) 2003-2011 Thomas Graf * Copyright (c) 2006 Petr Gotthard * Copyright (c) 2006 Siemens AG Oesterreich */ /** - * @ingroup cls_api - * @defgroup fw Firewall Classifier + * @ingroup cls + * @defgroup cls_fw Firewall Classifier * * @{ */ @@ -21,8 +21,8 @@ #include #include #include +#include #include -#include #include /** @cond SKIP */ @@ -38,13 +38,13 @@ static struct nla_policy fw_policy[TCA_FW_MAX+1] = { .maxlen = IFNAMSIZ }, }; -static int fw_msg_parser(struct rtnl_cls *cls) +static int fw_msg_parser(struct rtnl_tc *tc, void *data) { - struct rtnl_fw *f = rtnl_cls_data(cls); struct nlattr *tb[TCA_FW_MAX + 1]; + struct rtnl_fw *f = data; int err; - err = tca_parse(tb, TCA_FW_MAX, (struct rtnl_tc *) cls, fw_policy); + err = tca_parse(tb, TCA_FW_MAX, tc, fw_policy); if (err < 0) return err; @@ -75,18 +75,17 @@ static int fw_msg_parser(struct rtnl_cls *cls) return 0; } -static void fw_free_data(struct rtnl_cls *cls) +static void fw_free_data(struct rtnl_tc *tc, void *data) { - struct rtnl_fw *f = rtnl_cls_data(cls); + struct rtnl_fw *f = data; nl_data_free(f->cf_act); nl_data_free(f->cf_police); } -static int fw_clone(struct rtnl_cls *_dst, struct rtnl_cls *_src) +static int fw_clone(void *_dst, void *_src) { - struct rtnl_fw *dst = rtnl_cls_data(_dst); - struct rtnl_fw *src = rtnl_cls_data(_src); + struct rtnl_fw *dst = _dst, *src = _src; if (src->cf_act && !(dst->cf_act = nl_data_clone(src->cf_act))) return -NLE_NOMEM; @@ -97,28 +96,35 @@ static int fw_clone(struct rtnl_cls *_dst, struct rtnl_cls *_src) return 0; } -static void fw_dump_line(struct rtnl_cls *cls, struct nl_dump_params *p) +static void fw_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) { - struct rtnl_fw *f = rtnl_cls_data(cls); - char buf[32]; + struct rtnl_fw *f = data; + + if (f && f->cf_mask & FW_ATTR_CLASSID) { + char buf[32]; - if (f->cf_mask & FW_ATTR_CLASSID) nl_dump(p, " target %s", rtnl_tc_handle2str(f->cf_classid, buf, sizeof(buf))); + } } -static void fw_dump_details(struct rtnl_cls *cls, struct nl_dump_params *p) +static void fw_dump_details(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) { - struct rtnl_fw *f = rtnl_cls_data(cls); + struct rtnl_fw *f = data; - if (f->cf_mask & FW_ATTR_INDEV) + if (f && f->cf_mask & FW_ATTR_INDEV) nl_dump(p, "indev %s ", f->cf_indev); } -static int fw_get_opts(struct rtnl_cls *cls, struct nl_msg *msg) +static int fw_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) { - struct rtnl_fw *f = rtnl_cls_data(cls); - + struct rtnl_fw *f = data; + + if (!f) + return 0; + if (f->cf_mask & FW_ATTR_CLASSID) NLA_PUT_U32(msg, TCA_FW_CLASSID, f->cf_classid); @@ -134,7 +140,7 @@ static int fw_get_opts(struct rtnl_cls *cls, struct nl_msg *msg) return 0; nla_put_failure: - return -NLE_NOMEM; + return -NLE_MSGSIZE; } /** @@ -144,7 +150,10 @@ nla_put_failure: int rtnl_fw_set_classid(struct rtnl_cls *cls, uint32_t classid) { - struct rtnl_fw *f = rtnl_cls_data(cls); + struct rtnl_fw *f; + + if (!(f = rtnl_tc_data(TC_CAST(cls)))) + return -NLE_NOMEM; f->cf_classid = classid; f->cf_mask |= FW_ATTR_CLASSID; @@ -154,14 +163,15 @@ int rtnl_fw_set_classid(struct rtnl_cls *cls, uint32_t classid) /** @} */ -static struct rtnl_cls_ops fw_ops = { - .co_kind = "fw", - .co_size = sizeof(struct rtnl_fw), - .co_msg_parser = fw_msg_parser, - .co_free_data = fw_free_data, - .co_clone = fw_clone, - .co_get_opts = fw_get_opts, - .co_dump = { +static struct rtnl_tc_ops fw_ops = { + .to_kind = "fw", + .to_type = RTNL_TC_TYPE_CLS, + .to_size = sizeof(struct rtnl_fw), + .to_msg_parser = fw_msg_parser, + .to_msg_fill = fw_msg_fill, + .to_free_data = fw_free_data, + .to_clone = fw_clone, + .to_dump = { [NL_DUMP_LINE] = fw_dump_line, [NL_DUMP_DETAILS] = fw_dump_details, }, @@ -169,12 +179,12 @@ static struct rtnl_cls_ops fw_ops = { static void __init fw_init(void) { - rtnl_cls_register(&fw_ops); + rtnl_tc_register(&fw_ops); } static void __exit fw_exit(void) { - rtnl_cls_unregister(&fw_ops); + rtnl_tc_unregister(&fw_ops); } /** @} */ diff --git a/lib/route/cls/police.c b/lib/route/cls/police.c index f2cd45a..d7ab26b 100644 --- a/lib/route/cls/police.c +++ b/lib/route/cls/police.c @@ -13,9 +13,8 @@ #include #include #include -#include +#include #include -#include #include /** diff --git a/lib/route/cls/u32.c b/lib/route/cls/u32.c index 38214c9..2016460 100644 --- a/lib/route/cls/u32.c +++ b/lib/route/cls/u32.c @@ -6,14 +6,14 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2009 Thomas Graf + * Copyright (c) 2003-2011 Thomas Graf * Copyright (c) 2005-2006 Petr Gotthard * Copyright (c) 2005-2006 Siemens AG Oesterreich */ /** - * @ingroup cls_api - * @defgroup u32 Universal 32-bit Classifier + * @ingroup cls + * @defgroup cls_u32 Universal 32-bit Classifier * * @{ */ @@ -23,9 +23,8 @@ #include #include #include -#include +#include #include -#include #include /** @cond SKIP */ @@ -64,13 +63,13 @@ static struct nla_policy u32_policy[TCA_U32_MAX+1] = { [TCA_U32_PCNT] = { .minlen = sizeof(struct tc_u32_pcnt) }, }; -static int u32_msg_parser(struct rtnl_cls *cls) +static int u32_msg_parser(struct rtnl_tc *tc, void *data) { - struct rtnl_u32 *u = rtnl_cls_data(cls); + struct rtnl_u32 *u = data; struct nlattr *tb[TCA_U32_MAX + 1]; int err; - err = tca_parse(tb, TCA_U32_MAX, (struct rtnl_tc *) cls, u32_policy); + err = tca_parse(tb, TCA_U32_MAX, tc, u32_policy); if (err < 0) return err; @@ -151,9 +150,9 @@ errout: return err; } -static void u32_free_data(struct rtnl_cls *cls) +static void u32_free_data(struct rtnl_tc *tc, void *data) { - struct rtnl_u32 *u = rtnl_cls_data(cls); + struct rtnl_u32 *u = data; nl_data_free(u->cu_selector); nl_data_free(u->cu_act); @@ -161,10 +160,9 @@ static void u32_free_data(struct rtnl_cls *cls) nl_data_free(u->cu_pcnt); } -static int u32_clone(struct rtnl_cls *_dst, struct rtnl_cls *_src) +static int u32_clone(void *_dst, void *_src) { - struct rtnl_u32 *dst = rtnl_cls_data(_dst); - struct rtnl_u32 *src = rtnl_cls_data(_src); + struct rtnl_u32 *dst = _dst, *src = _src; if (src->cu_selector && !(dst->cu_selector = nl_data_clone(src->cu_selector))) @@ -182,10 +180,14 @@ static int u32_clone(struct rtnl_cls *_dst, struct rtnl_cls *_src) return 0; } -static void u32_dump_line(struct rtnl_cls *cls, struct nl_dump_params *p) +static void u32_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) { - struct rtnl_u32 *u = rtnl_cls_data(cls); + struct rtnl_u32 *u = data; char buf[32]; + + if (!u) + return; if (u->cu_mask & U32_ATTR_DIVISOR) nl_dump(p, " divisor %u", u->cu_divisor); @@ -195,7 +197,7 @@ static void u32_dump_line(struct rtnl_cls *cls, struct nl_dump_params *p) } static void print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel, - struct rtnl_cls *cls, struct rtnl_u32 *u) + struct rtnl_u32 *u) { int i; struct tc_u32_key *key; @@ -253,11 +255,15 @@ static void print_selector(struct nl_dump_params *p, struct tc_u32_sel *sel, } } -static void u32_dump_details(struct rtnl_cls *cls, struct nl_dump_params *p) +static void u32_dump_details(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) { - struct rtnl_u32 *u = rtnl_cls_data(cls); + struct rtnl_u32 *u = data; struct tc_u32_sel *s; + if (!u) + return; + if (!(u->cu_mask & U32_ATTR_SELECTOR)) { nl_dump(p, "no-selector\n"); return; @@ -277,7 +283,7 @@ static void u32_dump_details(struct rtnl_cls *cls, struct nl_dump_params *p) if (u->cu_mask & U32_ATTR_INDEV) nl_dump(p, "indev %s ", u->cu_indev); - print_selector(p, s, cls, u); + print_selector(p, s, u); nl_dump(p, "\n"); #if 0 @@ -289,9 +295,13 @@ static void u32_dump_details(struct rtnl_cls *cls, struct nl_dump_params *p) #endif } -static void u32_dump_stats(struct rtnl_cls *cls, struct nl_dump_params *p) +static void u32_dump_stats(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) { - struct rtnl_u32 *u = rtnl_cls_data(cls); + struct rtnl_u32 *u = data; + + if (!u) + return; if (u->cu_mask & U32_ATTR_PCNT) { struct tc_u32_pcnt *pc = u->cu_pcnt->d_data; @@ -301,9 +311,12 @@ static void u32_dump_stats(struct rtnl_cls *cls, struct nl_dump_params *p) } } -static int u32_get_opts(struct rtnl_cls *cls, struct nl_msg *msg) +static int u32_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) { - struct rtnl_u32 *u = rtnl_cls_data(cls); + struct rtnl_u32 *u = data; + + if (!u) + return 0; if (u->cu_mask & U32_ATTR_DIVISOR) NLA_PUT_U32(msg, TCA_U32_DIVISOR, u->cu_divisor); @@ -350,7 +363,10 @@ void rtnl_u32_set_handle(struct rtnl_cls *cls, int htid, int hash, int rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid) { - struct rtnl_u32 *u = rtnl_cls_data(cls); + struct rtnl_u32 *u; + + if (!(u = rtnl_tc_data(TC_CAST(cls)))) + return -NLE_NOMEM; u->cu_classid = classid; u->cu_mask |= U32_ATTR_CLASSID; @@ -368,7 +384,10 @@ int rtnl_u32_set_classid(struct rtnl_cls *cls, uint32_t classid) int rtnl_u32_set_flags(struct rtnl_cls *cls, int flags) { struct tc_u32_sel *sel; - struct rtnl_u32 *u = rtnl_cls_data(cls); + struct rtnl_u32 *u; + + if (!(u = rtnl_tc_data(TC_CAST(cls)))) + return -NLE_NOMEM; sel = u32_selector_alloc(u); if (!sel) @@ -398,9 +417,12 @@ int rtnl_u32_add_key(struct rtnl_cls *cls, uint32_t val, uint32_t mask, int off, int offmask) { struct tc_u32_sel *sel; - struct rtnl_u32 *u = rtnl_cls_data(cls); + struct rtnl_u32 *u; int err; + if (!(u = rtnl_tc_data(TC_CAST(cls)))) + return -NLE_NOMEM; + sel = u32_selector_alloc(u); if (!sel) return -NLE_NOMEM; @@ -501,14 +523,15 @@ int rtnl_u32_add_key_in6_addr(struct rtnl_cls *cls, struct in6_addr *addr, /** @} */ -static struct rtnl_cls_ops u32_ops = { - .co_kind = "u32", - .co_size = sizeof(struct rtnl_u32), - .co_msg_parser = u32_msg_parser, - .co_free_data = u32_free_data, - .co_clone = u32_clone, - .co_get_opts = u32_get_opts, - .co_dump = { +static struct rtnl_tc_ops u32_ops = { + .to_kind = "u32", + .to_type = RTNL_TC_TYPE_CLS, + .to_size = sizeof(struct rtnl_u32), + .to_msg_parser = u32_msg_parser, + .to_free_data = u32_free_data, + .to_clone = u32_clone, + .to_msg_fill = u32_msg_fill, + .to_dump = { [NL_DUMP_LINE] = u32_dump_line, [NL_DUMP_DETAILS] = u32_dump_details, [NL_DUMP_STATS] = u32_dump_stats, @@ -517,12 +540,12 @@ static struct rtnl_cls_ops u32_ops = { static void __init u32_init(void) { - rtnl_cls_register(&u32_ops); + rtnl_tc_register(&u32_ops); } static void __exit u32_exit(void) { - rtnl_cls_unregister(&u32_ops); + rtnl_tc_unregister(&u32_ops); } /** @} */ diff --git a/lib/route/cls_api.c b/lib/route/cls_api.c deleted file mode 100644 index 73f05df..0000000 --- a/lib/route/cls_api.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - * lib/route/cls_api.c Classifier Module API - * - * 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 - */ - -/** - * @ingroup cls - * @defgroup cls_api Classifier Modules - * @{ - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -static struct rtnl_cls_ops *cls_ops_list; - -/** - * @name Classifier Module API - * @{ - */ - -/** - * Register a classifier module - * @arg cops classifier module operations - */ -int rtnl_cls_register(struct rtnl_cls_ops *cops) -{ - struct rtnl_cls_ops *o, **op; - - if (!cops->co_kind) - BUG(); - - for (op = &cls_ops_list; (o = *op) != NULL; op = &o->co_next) - if (!strcasecmp(cops->co_kind, o->co_kind)) - return -NLE_EXIST; - - cops->co_next = NULL; - *op = cops; - - return 0; -} - -/** - * Unregister a classifier module - * @arg cops classifier module operations - */ -int rtnl_cls_unregister(struct rtnl_cls_ops *cops) -{ - struct rtnl_cls_ops *o, **op; - - for (op = &cls_ops_list; (o = *op) != NULL; op = &o->co_next) - if (!strcasecmp(cops->co_kind, o->co_kind)) - break; - - if (!o) - return -NLE_OBJ_NOTFOUND; - - *op = cops->co_next; - - return 0; -} - -struct rtnl_cls_ops *__rtnl_cls_lookup_ops(const char *kind) -{ - struct rtnl_cls_ops *cops; - - for (cops = cls_ops_list; cops; cops = cops->co_next) - if (!strcmp(kind, cops->co_kind)) - return cops; - - return NULL; -} - -/** - * Lookup classifier operations for a classifier object - * @arg cls Classifier object. - * - * @return Classifier operations or NULL if not found. - */ -struct rtnl_cls_ops *rtnl_cls_lookup_ops(struct rtnl_cls *cls) -{ - if (!cls->c_ops) - cls->c_ops = __rtnl_cls_lookup_ops(cls->c_kind); - - return cls->c_ops; -} - - -/** @} */ - -/** @} */ diff --git a/lib/route/cls_obj.c b/lib/route/cls_obj.c deleted file mode 100644 index dcf97ed..0000000 --- a/lib/route/cls_obj.c +++ /dev/null @@ -1,228 +0,0 @@ -/* - * lib/route/cls_api.c Classifier Object - * - * 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 - */ - -/** - * @ingroup cls - * @defgroup cls_obj Classifier Object - * @{ - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/** @cond SKIP */ -#define CLS_ATTR_PRIO (TCA_ATTR_MAX << 1) -#define CLS_ATTR_PROTOCOL (TCA_ATTR_MAX << 2) -/** @endcond */ - -static void cls_free_data(struct nl_object *obj) -{ - struct rtnl_cls *cls = (struct rtnl_cls *) obj; - struct rtnl_cls_ops *cops; - - tca_free_data((struct rtnl_tc *) cls); - - cops = rtnl_cls_lookup_ops(cls); - if (cops && cops->co_free_data) - cops->co_free_data(cls); - - nl_data_free(cls->c_subdata); -} - -static int cls_clone(struct nl_object *_dst, struct nl_object *_src) -{ - struct rtnl_cls *dst = nl_object_priv(_dst); - struct rtnl_cls *src = nl_object_priv(_src); - struct rtnl_cls_ops *cops; - int err; - - err = tca_clone((struct rtnl_tc *) dst, (struct rtnl_tc *) src); - if (err < 0) - goto errout; - - if (src->c_subdata) { - if (!(dst->c_subdata = nl_data_clone(src->c_subdata))) { - err = -NLE_NOMEM; - goto errout; - } - } - - cops = rtnl_cls_lookup_ops(src); - if (cops && cops->co_clone) - err = cops->co_clone(dst, src); -errout: - return err; -} - -static void cls_dump_line(struct nl_object *obj, struct nl_dump_params *p) -{ - char buf[32]; - struct rtnl_cls *cls = (struct rtnl_cls *) obj; - struct rtnl_cls_ops *cops; - - tca_dump_line((struct rtnl_tc *) cls, "cls", p); - - nl_dump(p, " prio %u protocol %s", cls->c_prio, - nl_ether_proto2str(cls->c_protocol, buf, sizeof(buf))); - - cops = rtnl_cls_lookup_ops(cls); - if (cops && cops->co_dump[NL_DUMP_LINE]) - cops->co_dump[NL_DUMP_LINE](cls, p); - nl_dump(p, "\n"); -} - -static void cls_dump_details(struct nl_object *obj, struct nl_dump_params *p) -{ - struct rtnl_cls *cls = (struct rtnl_cls *) obj; - struct rtnl_cls_ops *cops; - - cls_dump_line(obj, p); - tca_dump_details((struct rtnl_tc *) cls, p); - - cops = rtnl_cls_lookup_ops(cls); - if (cops && cops->co_dump[NL_DUMP_DETAILS]) - cops->co_dump[NL_DUMP_DETAILS](cls, p); - else - nl_dump(p, "no options\n"); -} - -static void cls_dump_stats(struct nl_object *obj, struct nl_dump_params *p) -{ - struct rtnl_cls *cls = (struct rtnl_cls *) obj; - struct rtnl_cls_ops *cops; - - cls_dump_details(obj, p); - tca_dump_stats((struct rtnl_tc *) cls, p); - nl_dump(p, "\n"); - - cops = rtnl_cls_lookup_ops(cls); - if (cops && cops->co_dump[NL_DUMP_STATS]) - cops->co_dump[NL_DUMP_STATS](cls, p); -} - -/** - * @name Allocation/Freeing - * @{ - */ - -struct rtnl_cls *rtnl_cls_alloc(void) -{ - return (struct rtnl_cls *) nl_object_alloc(&cls_obj_ops); -} - -void rtnl_cls_put(struct rtnl_cls *cls) -{ - nl_object_put((struct nl_object *) cls); -} - -/** @} */ - - -/** - * @name Attributes - * @{ - */ - -int rtnl_cls_set_kind(struct rtnl_cls *cls, const char *kind) -{ - if (cls->ce_mask & TCA_ATTR_KIND) - return -NLE_EXIST; - - tca_set_kind((struct rtnl_tc *) cls, kind); - - /* Force allocation of data */ - rtnl_cls_data(cls); - - return 0; -} - -struct rtnl_cls_ops *rtnl_cls_get_ops(struct rtnl_cls *cls) -{ - return cls->c_ops; -} - -void rtnl_cls_set_prio(struct rtnl_cls *cls, uint16_t prio) -{ - cls->c_prio = prio; - cls->ce_mask |= CLS_ATTR_PRIO; -} - -uint16_t rtnl_cls_get_prio(struct rtnl_cls *cls) -{ - if (cls->ce_mask & CLS_ATTR_PRIO) - return cls->c_prio; - else - return 0; -} - -void rtnl_cls_set_protocol(struct rtnl_cls *cls, uint16_t protocol) -{ - cls->c_protocol = protocol; - cls->ce_mask |= CLS_ATTR_PROTOCOL; -} - -uint16_t rtnl_cls_get_protocol(struct rtnl_cls *cls) -{ - if (cls->ce_mask & CLS_ATTR_PROTOCOL) - return cls->c_protocol; - else - return ETH_P_ALL; -} - -void *rtnl_cls_data(struct rtnl_cls *cls) -{ - if (!cls->c_subdata) { - struct rtnl_cls_ops *ops = cls->c_ops; - - if (!ops) { - if (!cls->c_kind[0]) - BUG(); - - ops = __rtnl_cls_lookup_ops(cls->c_kind); - if (ops == NULL) - return NULL; - - cls->c_ops = ops; - } - - if (!ops->co_size) - BUG(); - - if (!(cls->c_subdata = nl_data_alloc(NULL, ops->co_size))) - return NULL; - } - - return nl_data_get(cls->c_subdata); -} - -/** @} */ - -struct nl_object_ops cls_obj_ops = { - .oo_name = "route/cls", - .oo_size = sizeof(struct rtnl_cls), - .oo_free_data = cls_free_data, - .oo_clone = cls_clone, - .oo_dump = { - [NL_DUMP_LINE] = cls_dump_line, - [NL_DUMP_DETAILS] = cls_dump_details, - [NL_DUMP_STATS] = cls_dump_stats, - }, - .oo_compare = tca_compare, - .oo_id_attrs = (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE), -}; - -/** @} */ diff --git a/lib/route/qdisc.c b/lib/route/qdisc.c index 2867e63..6ec3a40 100644 --- a/lib/route/qdisc.c +++ b/lib/route/qdisc.c @@ -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 */ /** @@ -87,44 +87,29 @@ #include #include #include -#include +#include #include #include #include -#include static struct nl_cache_ops rtnl_qdisc_ops; static int qdisc_msg_parser(struct nl_cache_ops *ops, struct sockaddr_nl *who, struct nlmsghdr *n, struct nl_parser_param *pp) { - int err; struct rtnl_qdisc *qdisc; - struct rtnl_qdisc_ops *qops; + int err; - qdisc = rtnl_qdisc_alloc(); - if (!qdisc) { - err = -NLE_NOMEM; + if (!(qdisc = rtnl_qdisc_alloc())) + return -NLE_NOMEM; + + if ((err = rtnl_tc_msg_parse(n, TC_CAST(qdisc))) < 0) goto errout; - } - qdisc->ce_msgtype = n->nlmsg_type; - - err = tca_msg_parser(n, (struct rtnl_tc *) qdisc); - if (err < 0) - goto errout_free; - - qops = rtnl_qdisc_lookup_ops(qdisc); - if (qops && qops->qo_msg_parser) { - err = qops->qo_msg_parser(qdisc); - if (err < 0) - goto errout_free; - } - - err = pp->pp_cb((struct nl_object *) qdisc, pp); -errout_free: - rtnl_qdisc_put(qdisc); + err = pp->pp_cb(OBJ_CAST(qdisc), pp); errout: + rtnl_qdisc_put(qdisc); + return err; } @@ -147,25 +132,9 @@ static int qdisc_request_update(struct nl_cache *c, struct nl_sock *sk) static int qdisc_build(struct rtnl_qdisc *qdisc, int type, int flags, struct nl_msg **result) { - struct rtnl_qdisc_ops *qops; - int err; + return rtnl_tc_msg_build(TC_CAST(qdisc), type, flags, result); - err = tca_build_msg((struct rtnl_tc *) qdisc, type, flags, result); - if (err < 0) - return err; - - qops = rtnl_qdisc_lookup_ops(qdisc); - if (qops && qops->qo_get_opts) { - struct nl_msg *opts; - - opts = qops->qo_get_opts(qdisc); - if (opts) { - err = nla_put_nested(*result, TCA_OPTIONS, opts); - nlmsg_free(opts); - if (err < 0) - goto errout; - } - } +#if 0 /* Some qdiscs don't accept properly nested messages (e.g. netem). To * accomodate for this, they can complete the message themselves. */ @@ -174,12 +143,7 @@ static int qdisc_build(struct rtnl_qdisc *qdisc, int type, int flags, if (err < 0) goto errout; } - - return 0; -errout: - nlmsg_free(*result); - - return err; +#endif } /** @@ -440,6 +404,101 @@ 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 Iterators + * @{ + */ + +/** + * Call a callback for each child class of a qdisc + * @arg qdisc the parent qdisc + * @arg cache a class cache including all classes of the interface + * the specified qdisc is attached to + * @arg cb callback function + * @arg arg argument to be passed to callback function + */ +void rtnl_qdisc_foreach_child(struct rtnl_qdisc *qdisc, 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), qdisc->q_handle); + rtnl_tc_set_ifindex(TC_CAST(filter), qdisc->q_ifindex); + rtnl_tc_set_kind(TC_CAST(filter), qdisc->q_kind); + + nl_cache_foreach_filter(cache, OBJ_CAST(filter), cb, arg); + + rtnl_class_put(filter); +} + +/** + * Call a callback for each filter attached to the qdisc + * @arg qdisc the parent qdisc + * @arg cache a filter cache including at least all the filters + * attached to the specified qdisc + * @arg cb callback function + * @arg arg argument to be passed to callback function + */ +void rtnl_qdisc_foreach_cls(struct rtnl_qdisc *qdisc, 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, qdisc->q_ifindex); + rtnl_tc_set_parent((struct rtnl_tc *) filter, qdisc->q_parent); + + nl_cache_foreach_filter(cache, (struct nl_object *) filter, cb, arg); + rtnl_cls_put(filter); +} + +/** @} */ + +static void qdisc_dump_details(struct rtnl_tc *tc, struct nl_dump_params *p) +{ + struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) tc; + + nl_dump(p, "refcnt %u ", qdisc->q_info); +} + +static struct rtnl_tc_type_ops qdisc_ops = { + .tt_type = RTNL_TC_TYPE_QDISC, + .tt_dump_prefix = "qdisc", + .tt_dump = { + [NL_DUMP_DETAILS] = qdisc_dump_details, + }, +}; + static struct nl_cache_ops rtnl_qdisc_ops = { .co_name = "route/qdisc", .co_hdrsize = sizeof(struct tcmsg), @@ -455,14 +514,30 @@ static struct nl_cache_ops rtnl_qdisc_ops = { .co_obj_ops = &qdisc_obj_ops, }; +struct nl_object_ops qdisc_obj_ops = { + .oo_name = "route/qdisc", + .oo_size = sizeof(struct rtnl_qdisc), + .oo_free_data = rtnl_tc_free_data, + .oo_clone = rtnl_tc_clone, + .oo_dump = { + [NL_DUMP_LINE] = rtnl_tc_dump_line, + [NL_DUMP_DETAILS] = rtnl_tc_dump_details, + [NL_DUMP_STATS] = rtnl_tc_dump_stats, + }, + .oo_compare = rtnl_tc_compare, + .oo_id_attrs = (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE), +}; + static void __init qdisc_init(void) { + rtnl_tc_type_register(&qdisc_ops); nl_cache_mngt_register(&rtnl_qdisc_ops); } static void __exit qdisc_exit(void) { nl_cache_mngt_unregister(&rtnl_qdisc_ops); + rtnl_tc_type_unregister(&qdisc_ops); } /** @} */ diff --git a/lib/route/qdisc_api.c b/lib/route/qdisc_api.c deleted file mode 100644 index 089f212..0000000 --- a/lib/route/qdisc_api.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * lib/route/qdisc_api.c Queueing Discipline Module API - * - * 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-2006 Thomas Graf - */ - -/** - * @ingroup qdisc - * @defgroup qdisc_api Queueing Discipline Modules - * @{ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct rtnl_qdisc_ops *qdisc_ops_list; - -/** - * @name Module API - * @{ - */ - -/** - * Register a qdisc module - * @arg qops qdisc module operations - */ -int rtnl_qdisc_register(struct rtnl_qdisc_ops *qops) -{ - struct rtnl_qdisc_ops *o, **op; - - if (!qops->qo_kind[0]) - BUG(); - - for (op = &qdisc_ops_list; (o = *op) != NULL; op = &o->qo_next) - if (!strcasecmp(qops->qo_kind, o->qo_kind)) - return -NLE_EXIST; - - qops->qo_next = NULL; - *op = qops; - - return 0; -} - -/** - * Unregister a qdisc module - * @arg qops qdisc module operations - */ -int rtnl_qdisc_unregister(struct rtnl_qdisc_ops *qops) -{ - struct rtnl_qdisc_ops *o, **op; - - for (op = &qdisc_ops_list; (o = *op) != NULL; op = &o->qo_next) - if (!strcasecmp(qops->qo_kind, o->qo_kind)) - break; - - if (!o) - return -NLE_OBJ_NOTFOUND; - - *op = qops->qo_next; - - return 0; -} - -struct rtnl_qdisc_ops *__rtnl_qdisc_lookup_ops(const char *kind) -{ - struct rtnl_qdisc_ops *qops; - - for (qops = qdisc_ops_list; qops; qops = qops->qo_next) - if (!strcmp(kind, qops->qo_kind)) - return qops; - - return NULL; -} - -struct rtnl_qdisc_ops *rtnl_qdisc_lookup_ops(struct rtnl_qdisc *qdisc) -{ - if (!qdisc->q_ops) - qdisc->q_ops = __rtnl_qdisc_lookup_ops(qdisc->q_kind); - - return qdisc->q_ops; -} - -/** @} */ - -/** @} */ diff --git a/lib/route/qdisc_obj.c b/lib/route/qdisc_obj.c deleted file mode 100644 index baa00b2..0000000 --- a/lib/route/qdisc_obj.c +++ /dev/null @@ -1,229 +0,0 @@ -/* - * lib/route/qdisc_obj.c Queueing Discipline Object - * - * 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-2006 Thomas Graf - */ - -/** - * @ingroup qdisc - * @defgroup qdisc_obj Queueing Discipline Object - * @{ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static void qdisc_free_data(struct nl_object *obj) -{ - struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) obj; - struct rtnl_qdisc_ops *qops; - - tca_free_data((struct rtnl_tc *) qdisc); - - qops = rtnl_qdisc_lookup_ops(qdisc); - if (qops && qops->qo_free_data) - qops->qo_free_data(qdisc); -} - -static int qdisc_clone(struct nl_object *_dst, struct nl_object *_src) -{ - struct rtnl_qdisc *dst = (struct rtnl_qdisc *) _dst; - struct rtnl_qdisc *src = (struct rtnl_qdisc *) _src; - struct rtnl_qdisc_ops *qops; - int err; - - err = tca_clone((struct rtnl_tc *) dst, (struct rtnl_tc *) src); - if (err < 0) - goto errout; - - qops = rtnl_qdisc_lookup_ops(src); - if (qops && qops->qo_clone) - err = qops->qo_clone(dst, src); -errout: - return err; -} - -static void qdisc_dump_line(struct nl_object *obj, struct nl_dump_params *p) -{ - struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) obj; - struct rtnl_qdisc_ops *qops; - - tca_dump_line((struct rtnl_tc *) qdisc, "qdisc", p); - - qops = rtnl_qdisc_lookup_ops(qdisc); - if (qops && qops->qo_dump[NL_DUMP_LINE]) - qops->qo_dump[NL_DUMP_LINE](qdisc, p); - - nl_dump(p, "\n"); -} - -static void qdisc_dump_details(struct nl_object *arg, struct nl_dump_params *p) -{ - struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) arg; - struct rtnl_qdisc_ops *qops; - - qdisc_dump_line(arg, p); - - tca_dump_details((struct rtnl_tc *) qdisc, p); - nl_dump(p, "refcnt %u ", qdisc->q_info); - - qops = rtnl_qdisc_lookup_ops(qdisc); - if (qops && qops->qo_dump[NL_DUMP_DETAILS]) - qops->qo_dump[NL_DUMP_DETAILS](qdisc, p); - - nl_dump(p, "\n"); -} - -static void qdisc_dump_stats(struct nl_object *arg, struct nl_dump_params *p) -{ - struct rtnl_qdisc *qdisc = (struct rtnl_qdisc *) arg; - struct rtnl_qdisc_ops *qops; - - qdisc_dump_details(arg, p); - tca_dump_stats((struct rtnl_tc *) qdisc, p); - nl_dump(p, "\n"); - - qops = rtnl_qdisc_lookup_ops(qdisc); - if (qops && qops->qo_dump[NL_DUMP_STATS]) - qops->qo_dump[NL_DUMP_STATS](qdisc, p); -} - -/** - * @name Allocation/Freeing - * @{ - */ - -struct rtnl_qdisc *rtnl_qdisc_alloc(void) -{ - return (struct rtnl_qdisc *) nl_object_alloc(&qdisc_obj_ops); -} - -void rtnl_qdisc_put(struct rtnl_qdisc *qdisc) -{ - nl_object_put((struct nl_object *) qdisc); -} - -/** @} */ - -/** - * @name Iterators - * @{ - */ - -/** - * Call a callback for each child class of a qdisc - * @arg qdisc the parent qdisc - * @arg cache a class cache including all classes of the interface - * the specified qdisc is attached to - * @arg cb callback function - * @arg arg argument to be passed to callback function - */ -void rtnl_qdisc_foreach_child(struct rtnl_qdisc *qdisc, 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((struct rtnl_tc *) filter, qdisc->q_handle); - rtnl_tc_set_ifindex((struct rtnl_tc *) filter, qdisc->q_ifindex); - rtnl_class_set_kind(filter, qdisc->q_kind); - - nl_cache_foreach_filter(cache, (struct nl_object *) filter, cb, arg); - - rtnl_class_put(filter); -} - -/** - * Call a callback for each filter attached to the qdisc - * @arg qdisc the parent qdisc - * @arg cache a filter cache including at least all the filters - * attached to the specified qdisc - * @arg cb callback function - * @arg arg argument to be passed to callback function - */ -void rtnl_qdisc_foreach_cls(struct rtnl_qdisc *qdisc, 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, qdisc->q_ifindex); - rtnl_tc_set_parent((struct rtnl_tc *) filter, qdisc->q_parent); - - nl_cache_foreach_filter(cache, (struct nl_object *) filter, cb, arg); - rtnl_cls_put(filter); -} - -/** @} */ - -/** - * @name Attributes - * @{ - */ - -void rtnl_qdisc_set_kind(struct rtnl_qdisc *qdisc, const char *name) -{ - tca_set_kind((struct rtnl_tc *) qdisc, name); - qdisc->q_ops = __rtnl_qdisc_lookup_ops(name); -} - -/** @} */ - -/** - * @name Qdisc Specific Options - * @{ - */ - -/** - * Return qdisc specific options for use in TCA_OPTIONS - * @arg qdisc qdisc carrying the optiosn - * - * @return new headerless netlink message carrying the options as payload - */ -struct nl_msg *rtnl_qdisc_get_opts(struct rtnl_qdisc *qdisc) -{ - struct rtnl_qdisc_ops *ops; - - ops = rtnl_qdisc_lookup_ops(qdisc); - if (ops && ops->qo_get_opts) - return ops->qo_get_opts(qdisc); - - return NULL; -} - -/** @} */ - -struct nl_object_ops qdisc_obj_ops = { - .oo_name = "route/qdisc", - .oo_size = sizeof(struct rtnl_qdisc), - .oo_free_data = qdisc_free_data, - .oo_clone = qdisc_clone, - .oo_dump = { - [NL_DUMP_LINE] = qdisc_dump_line, - [NL_DUMP_DETAILS] = qdisc_dump_details, - [NL_DUMP_STATS] = qdisc_dump_stats, - }, - .oo_compare = tca_compare, - .oo_id_attrs = (TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE), -}; - -/** @} */ diff --git a/lib/route/sch/blackhole.c b/lib/route/sch/blackhole.c index a30b693..064963e 100644 --- a/lib/route/sch/blackhole.c +++ b/lib/route/sch/blackhole.c @@ -6,33 +6,32 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2006 Thomas Graf + * Copyright (c) 2003-2011 Thomas Graf */ /** - * @ingroup qdisc_api - * @defgroup blackhole Blackhole + * @ingroup qdisc + * @defgroup qdisc_blackhole Blackhole * @{ */ #include -#include #include -#include -#include +#include -static struct rtnl_qdisc_ops blackhole_ops = { - .qo_kind = "blackhole", +static struct rtnl_tc_ops blackhole_ops = { + .to_kind = "blackhole", + .to_type = RTNL_TC_TYPE_QDISC, }; static void __init blackhole_init(void) { - rtnl_qdisc_register(&blackhole_ops); + rtnl_tc_register(&blackhole_ops); } static void __exit blackhole_exit(void) { - rtnl_qdisc_unregister(&blackhole_ops); + rtnl_tc_unregister(&blackhole_ops); } /** @} */ diff --git a/lib/route/sch/cbq.c b/lib/route/sch/cbq.c index 989745c..f750ccd 100644 --- a/lib/route/sch/cbq.c +++ b/lib/route/sch/cbq.c @@ -6,25 +6,24 @@ * 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 */ #include #include #include #include +#include #include -#include #include -#include #include #include #include /** - * @ingroup qdisc_api - * @ingroup class_api - * @defgroup cbq Class Based Queueing (CBQ) + * @ingroup qdisc + * @ingroup class + * @defgroup qdisc_cbq Class Based Queueing (CBQ) * @{ */ @@ -73,34 +72,16 @@ static struct nla_policy cbq_policy[TCA_CBQ_MAX+1] = { [TCA_CBQ_POLICE] = { .minlen = sizeof(struct tc_cbq_police) }, }; -static inline struct rtnl_cbq *cbq_qdisc(struct rtnl_tc *tca) -{ - return (struct rtnl_cbq *) tca->tc_subdata; -} - -static inline struct rtnl_cbq *cbq_alloc(struct rtnl_tc *tca) -{ - if (!tca->tc_subdata) - tca->tc_subdata = calloc(1, sizeof(struct rtnl_qdisc)); - - return cbq_qdisc(tca); -} - - -static int cbq_msg_parser(struct rtnl_tc *tca) +static int cbq_msg_parser(struct rtnl_tc *tc, void *data) { struct nlattr *tb[TCA_CBQ_MAX + 1]; - struct rtnl_cbq *cbq; + struct rtnl_cbq *cbq = data; int err; - err = tca_parse(tb, TCA_CBQ_MAX, tca, cbq_policy); + err = tca_parse(tb, TCA_CBQ_MAX, tc, cbq_policy); if (err < 0) return err; - cbq = cbq_alloc(tca); - if (!cbq) - return -NLE_NOMEM; - nla_memcpy(&cbq->cbq_lss, tb[TCA_CBQ_LSSOPT], sizeof(cbq->cbq_lss)); nla_memcpy(&cbq->cbq_rate, tb[TCA_CBQ_RATE], sizeof(cbq->cbq_rate)); nla_memcpy(&cbq->cbq_wrr, tb[TCA_CBQ_WRROPT], sizeof(cbq->cbq_wrr)); @@ -113,53 +94,13 @@ static int cbq_msg_parser(struct rtnl_tc *tca) return 0; } -static int cbq_qdisc_msg_parser(struct rtnl_qdisc *qdisc) +static void cbq_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) { - return cbq_msg_parser((struct rtnl_tc *) qdisc); -} - -static int cbq_class_msg_parser(struct rtnl_class *class) -{ - return cbq_msg_parser((struct rtnl_tc *) class); -} - -static void cbq_qdisc_free_data(struct rtnl_qdisc *qdisc) -{ - free(qdisc->q_subdata); -} - -static int cbq_clone(struct rtnl_tc *_dst, struct rtnl_tc *_src) -{ - struct rtnl_cbq *src = cbq_qdisc(_src); - - if (src && !cbq_alloc(_dst)) - return -NLE_NOMEM; - else - return 0; -} - -static int cbq_qdisc_clone(struct rtnl_qdisc *dst, struct rtnl_qdisc *src) -{ - return cbq_clone((struct rtnl_tc *) dst, (struct rtnl_tc *) src); -} - -static void cbq_class_free_data(struct rtnl_class *class) -{ - free(class->c_subdata); -} - -static int cbq_class_clone(struct rtnl_class *dst, struct rtnl_class *src) -{ - return cbq_clone((struct rtnl_tc *) dst, (struct rtnl_tc *) src); -} - -static void cbq_dump_line(struct rtnl_tc *tca, struct nl_dump_params *p) -{ - struct rtnl_cbq *cbq; + struct rtnl_cbq *cbq = data; double r, rbit; char *ru, *rubit; - cbq = cbq_qdisc(tca); if (!cbq) return; @@ -170,26 +111,14 @@ static void cbq_dump_line(struct rtnl_tc *tca, struct nl_dump_params *p) r, ru, rbit, rubit, cbq->cbq_wrr.priority); } -static void cbq_qdisc_dump_line(struct rtnl_qdisc *qdisc, - struct nl_dump_params *p) +static void cbq_dump_details(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) { - cbq_dump_line((struct rtnl_tc *) qdisc, p); -} - -static void cbq_class_dump_line(struct rtnl_class *class, - struct nl_dump_params *p) -{ - cbq_dump_line((struct rtnl_tc *) class, p); -} - -static void cbq_dump_details(struct rtnl_tc *tca, struct nl_dump_params *p) -{ - struct rtnl_cbq *cbq; + struct rtnl_cbq *cbq = data; char *unit, buf[32]; double w; uint32_t el; - cbq = cbq_qdisc(tca); if (!cbq) return; @@ -222,23 +151,12 @@ static void cbq_dump_details(struct rtnl_tc *tca, struct nl_dump_params *p) nl_police2str(cbq->cbq_police.police, buf, sizeof(buf))); } -static void cbq_qdisc_dump_details(struct rtnl_qdisc *qdisc, - struct nl_dump_params *p) +static void cbq_dump_stats(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) { - cbq_dump_details((struct rtnl_tc *) qdisc, p); -} - -static void cbq_class_dump_details(struct rtnl_class *class, - struct nl_dump_params *p) -{ - cbq_dump_details((struct rtnl_tc *) class, p); -} - -static void cbq_dump_stats(struct rtnl_tc *tca, struct nl_dump_params *p) -{ - struct tc_cbq_xstats *x = tca_xstats(tca); - - if (!x) + struct tc_cbq_xstats *x; + + if (!(x = tca_xstats(tc))) return; nl_dump_line(p, " borrows overact " @@ -247,52 +165,40 @@ static void cbq_dump_stats(struct rtnl_tc *tca, struct nl_dump_params *p) x->borrows, x->overactions, x->avgidle, x->undertime); } -static void cbq_qdisc_dump_stats(struct rtnl_qdisc *qdisc, - struct nl_dump_params *p) -{ - cbq_dump_stats((struct rtnl_tc *) qdisc, p); -} - -static void cbq_class_dump_stats(struct rtnl_class *class, - struct nl_dump_params *p) -{ - cbq_dump_stats((struct rtnl_tc *) class, p); -} - -static struct rtnl_qdisc_ops cbq_qdisc_ops = { - .qo_kind = "cbq", - .qo_msg_parser = cbq_qdisc_msg_parser, - .qo_free_data = cbq_qdisc_free_data, - .qo_clone = cbq_qdisc_clone, - .qo_dump = { - [NL_DUMP_LINE] = cbq_qdisc_dump_line, - [NL_DUMP_DETAILS] = cbq_qdisc_dump_details, - [NL_DUMP_STATS] = cbq_qdisc_dump_stats, +static struct rtnl_tc_ops cbq_qdisc_ops = { + .to_kind = "cbq", + .to_type = RTNL_TC_TYPE_QDISC, + .to_size = sizeof(struct rtnl_cbq), + .to_msg_parser = cbq_msg_parser, + .to_dump = { + [NL_DUMP_LINE] = cbq_dump_line, + [NL_DUMP_DETAILS] = cbq_dump_details, + [NL_DUMP_STATS] = cbq_dump_stats, }, }; -static struct rtnl_class_ops cbq_class_ops = { - .co_kind = "cbq", - .co_msg_parser = cbq_class_msg_parser, - .co_free_data = cbq_class_free_data, - .co_clone = cbq_class_clone, - .co_dump = { - [NL_DUMP_LINE] = cbq_class_dump_line, - [NL_DUMP_DETAILS] = cbq_class_dump_details, - [NL_DUMP_STATS] = cbq_class_dump_stats, +static struct rtnl_tc_ops cbq_class_ops = { + .to_kind = "cbq", + .to_type = RTNL_TC_TYPE_CLASS, + .to_size = sizeof(struct rtnl_cbq), + .to_msg_parser = cbq_msg_parser, + .to_dump = { + [NL_DUMP_LINE] = cbq_dump_line, + [NL_DUMP_DETAILS] = cbq_dump_details, + [NL_DUMP_STATS] = cbq_dump_stats, }, }; static void __init cbq_init(void) { - rtnl_qdisc_register(&cbq_qdisc_ops); - rtnl_class_register(&cbq_class_ops); + rtnl_tc_register(&cbq_qdisc_ops); + rtnl_tc_register(&cbq_class_ops); } static void __exit cbq_exit(void) { - rtnl_qdisc_unregister(&cbq_qdisc_ops); - rtnl_class_unregister(&cbq_class_ops); + rtnl_tc_unregister(&cbq_qdisc_ops); + rtnl_tc_unregister(&cbq_class_ops); } /** @} */ diff --git a/lib/route/sch/dsmark.c b/lib/route/sch/dsmark.c index a2e1628..372d0b6 100644 --- a/lib/route/sch/dsmark.c +++ b/lib/route/sch/dsmark.c @@ -6,13 +6,13 @@ * 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 */ /** - * @ingroup qdisc_api - * @ingroup class_api - * @defgroup dsmark Differentiated Services Marker (DSMARK) + * @ingroup qdisc + * @ingroup class + * @defgroup qdisc_dsmark Differentiated Services Marker (DSMARK) * @{ */ @@ -21,9 +21,8 @@ #include #include #include -#include +#include #include -#include #include /** @cond SKIP */ @@ -35,20 +34,6 @@ #define SCH_DSMARK_ATTR_VALUE 0x2 /** @endcond */ -static inline struct rtnl_dsmark_qdisc *dsmark_qdisc(struct rtnl_qdisc *qdisc) -{ - return (struct rtnl_dsmark_qdisc *) qdisc->q_subdata; -} - -static inline struct rtnl_dsmark_qdisc * -dsmark_qdisc_alloc(struct rtnl_qdisc *qdisc) -{ - if (!qdisc->q_subdata) - qdisc->q_subdata = calloc(1, sizeof(struct rtnl_dsmark_qdisc)); - - return dsmark_qdisc(qdisc); -} - static struct nla_policy dsmark_policy[TCA_DSMARK_MAX+1] = { [TCA_DSMARK_INDICES] = { .type = NLA_U16 }, [TCA_DSMARK_DEFAULT_INDEX] = { .type = NLA_U16 }, @@ -57,21 +42,16 @@ static struct nla_policy dsmark_policy[TCA_DSMARK_MAX+1] = { [TCA_DSMARK_MASK] = { .type = NLA_U8 }, }; -static int dsmark_qdisc_msg_parser(struct rtnl_qdisc *qdisc) +static int dsmark_qdisc_msg_parser(struct rtnl_tc *tc, void *data) { - int err; + struct rtnl_dsmark_qdisc *dsmark = data; struct nlattr *tb[TCA_DSMARK_MAX + 1]; - struct rtnl_dsmark_qdisc *dsmark; + int err; - err = tca_parse(tb, TCA_DSMARK_MAX, (struct rtnl_tc *) qdisc, - dsmark_policy); + err = tca_parse(tb, TCA_DSMARK_MAX, tc, dsmark_policy); if (err < 0) return err; - dsmark = dsmark_qdisc_alloc(qdisc); - if (!dsmark) - return -NLE_NOMEM; - if (tb[TCA_DSMARK_INDICES]) { dsmark->qdm_indices = nla_get_u16(tb[TCA_DSMARK_INDICES]); dsmark->qdm_mask |= SCH_DSMARK_ATTR_INDICES; @@ -91,35 +71,16 @@ static int dsmark_qdisc_msg_parser(struct rtnl_qdisc *qdisc) return 0; } -static inline struct rtnl_dsmark_class *dsmark_class(struct rtnl_class *class) +static int dsmark_class_msg_parser(struct rtnl_tc *tc, void *data) { - return (struct rtnl_dsmark_class *) class->c_subdata; -} - -static inline struct rtnl_dsmark_class * -dsmark_class_alloc(struct rtnl_class *class) -{ - if (!class->c_subdata) - class->c_subdata = calloc(1, sizeof(struct rtnl_dsmark_class)); - - return dsmark_class(class); -} - -static int dsmark_class_msg_parser(struct rtnl_class *class) -{ - int err; + struct rtnl_dsmark_class *dsmark = data; struct nlattr *tb[TCA_DSMARK_MAX + 1]; - struct rtnl_dsmark_class *dsmark; + int err; - err = tca_parse(tb, TCA_DSMARK_MAX, (struct rtnl_tc *) class, - dsmark_policy); + err = tca_parse(tb, TCA_DSMARK_MAX, tc, dsmark_policy); if (err < 0) return err; - dsmark = dsmark_class_alloc(class); - if (!dsmark) - return -NLE_NOMEM; - if (tb[TCA_DSMARK_MASK]) { dsmark->cdm_bmask = nla_get_u8(tb[TCA_DSMARK_MASK]); dsmark->cdm_mask |= SCH_DSMARK_ATTR_MASK; @@ -133,19 +94,19 @@ static int dsmark_class_msg_parser(struct rtnl_class *class) return 0; } -static void dsmark_qdisc_dump_line(struct rtnl_qdisc *qdisc, +static void dsmark_qdisc_dump_line(struct rtnl_tc *tc, void *data, struct nl_dump_params *p) { - struct rtnl_dsmark_qdisc *dsmark = dsmark_qdisc(qdisc); + struct rtnl_dsmark_qdisc *dsmark = data; if (dsmark && (dsmark->qdm_mask & SCH_DSMARK_ATTR_INDICES)) nl_dump(p, " indices 0x%04x", dsmark->qdm_indices); } -static void dsmark_qdisc_dump_details(struct rtnl_qdisc *qdisc, +static void dsmark_qdisc_dump_details(struct rtnl_tc *tc, void *data, struct nl_dump_params *p) { - struct rtnl_dsmark_qdisc *dsmark = dsmark_qdisc(qdisc); + struct rtnl_dsmark_qdisc *dsmark = data; if (!dsmark) return; @@ -157,10 +118,10 @@ static void dsmark_qdisc_dump_details(struct rtnl_qdisc *qdisc, nl_dump(p, " set-tc-index"); } -static void dsmark_class_dump_line(struct rtnl_class *class, +static void dsmark_class_dump_line(struct rtnl_tc *tc, void *data, struct nl_dump_params *p) { - struct rtnl_dsmark_class *dsmark = dsmark_class(class); + struct rtnl_dsmark_class *dsmark = data; if (!dsmark) return; @@ -172,17 +133,13 @@ static void dsmark_class_dump_line(struct rtnl_class *class, nl_dump(p, " mask 0x%02x", dsmark->cdm_bmask); } -static struct nl_msg *dsmark_qdisc_get_opts(struct rtnl_qdisc *qdisc) +static int dsmark_qdisc_msg_fill(struct rtnl_tc *tc, void *data, + struct nl_msg *msg) { - struct rtnl_dsmark_qdisc *dsmark = dsmark_qdisc(qdisc); - struct nl_msg *msg; + struct rtnl_dsmark_qdisc *dsmark = data; if (!dsmark) - return NULL; - - msg = nlmsg_alloc(); - if (!msg) - goto nla_put_failure; + return 0; if (dsmark->qdm_mask & SCH_DSMARK_ATTR_INDICES) NLA_PUT_U16(msg, TCA_DSMARK_INDICES, dsmark->qdm_indices); @@ -194,24 +151,19 @@ static struct nl_msg *dsmark_qdisc_get_opts(struct rtnl_qdisc *qdisc) if (dsmark->qdm_mask & SCH_DSMARK_ATTR_SET_TC_INDEX) NLA_PUT_FLAG(msg, TCA_DSMARK_SET_TC_INDEX); - return msg; + return 0; nla_put_failure: - nlmsg_free(msg); - return NULL; + return -NLE_MSGSIZE; } -static struct nl_msg *dsmark_class_get_opts(struct rtnl_class *class) +static int dsmark_class_msg_fill(struct rtnl_tc *tc, void *data, + struct nl_msg *msg) { - struct rtnl_dsmark_class *dsmark = dsmark_class(class); - struct nl_msg *msg; + struct rtnl_dsmark_class *dsmark = data; if (!dsmark) - return NULL; - - msg = nlmsg_alloc(); - if (!msg) - goto nla_put_failure; + return 0; if (dsmark->cdm_mask & SCH_DSMARK_ATTR_MASK) NLA_PUT_U8(msg, TCA_DSMARK_MASK, dsmark->cdm_bmask); @@ -219,11 +171,10 @@ static struct nl_msg *dsmark_class_get_opts(struct rtnl_class *class) if (dsmark->cdm_mask & SCH_DSMARK_ATTR_VALUE) NLA_PUT_U8(msg, TCA_DSMARK_VALUE, dsmark->cdm_value); - return msg; + return 0; nla_put_failure: - nlmsg_free(msg); - return NULL; + return -NLE_MSGSIZE; } /** @@ -241,8 +192,7 @@ int rtnl_class_dsmark_set_bitmask(struct rtnl_class *class, uint8_t mask) { struct rtnl_dsmark_class *dsmark; - dsmark = dsmark_class(class); - if (!dsmark) + if (!(dsmark = rtnl_tc_data(TC_CAST(class)))) return -NLE_NOMEM; dsmark->cdm_bmask = mask; @@ -259,9 +209,11 @@ int rtnl_class_dsmark_set_bitmask(struct rtnl_class *class, uint8_t mask) int rtnl_class_dsmark_get_bitmask(struct rtnl_class *class) { struct rtnl_dsmark_class *dsmark; + + if (!(dsmark = rtnl_tc_data(TC_CAST(class)))) + return -NLE_NOMEM; - dsmark = dsmark_class(class); - if (dsmark && dsmark->cdm_mask & SCH_DSMARK_ATTR_MASK) + if (dsmark->cdm_mask & SCH_DSMARK_ATTR_MASK) return dsmark->cdm_bmask; else return -NLE_NOATTR; @@ -276,9 +228,8 @@ int rtnl_class_dsmark_get_bitmask(struct rtnl_class *class) int rtnl_class_dsmark_set_value(struct rtnl_class *class, uint8_t value) { struct rtnl_dsmark_class *dsmark; - - dsmark = dsmark_class(class); - if (!dsmark) + + if (!(dsmark = rtnl_tc_data(TC_CAST(class)))) return -NLE_NOMEM; dsmark->cdm_value = value; @@ -295,9 +246,11 @@ int rtnl_class_dsmark_set_value(struct rtnl_class *class, uint8_t value) int rtnl_class_dsmark_get_value(struct rtnl_class *class) { struct rtnl_dsmark_class *dsmark; + + if (!(dsmark = rtnl_tc_data(TC_CAST(class)))) + return -NLE_NOMEM; - dsmark = dsmark_class(class); - if (dsmark && dsmark->cdm_mask & SCH_DSMARK_ATTR_VALUE) + if (dsmark->cdm_mask & SCH_DSMARK_ATTR_VALUE) return dsmark->cdm_value; else return -NLE_NOATTR; @@ -319,8 +272,7 @@ int rtnl_qdisc_dsmark_set_indices(struct rtnl_qdisc *qdisc, uint16_t indices) { struct rtnl_dsmark_qdisc *dsmark; - dsmark = dsmark_qdisc(qdisc); - if (!dsmark) + if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc)))) return -NLE_NOMEM; dsmark->qdm_indices = indices; @@ -338,8 +290,10 @@ int rtnl_qdisc_dsmark_get_indices(struct rtnl_qdisc *qdisc) { struct rtnl_dsmark_qdisc *dsmark; - dsmark = dsmark_qdisc(qdisc); - if (dsmark && dsmark->qdm_mask & SCH_DSMARK_ATTR_INDICES) + if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc)))) + return -NLE_NOMEM; + + if (dsmark->qdm_mask & SCH_DSMARK_ATTR_INDICES) return dsmark->qdm_indices; else return -NLE_NOATTR; @@ -356,8 +310,7 @@ int rtnl_qdisc_dsmark_set_default_index(struct rtnl_qdisc *qdisc, { struct rtnl_dsmark_qdisc *dsmark; - dsmark = dsmark_qdisc(qdisc); - if (!dsmark) + if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc)))) return -NLE_NOMEM; dsmark->qdm_default_index = default_index; @@ -375,8 +328,10 @@ int rtnl_qdisc_dsmark_get_default_index(struct rtnl_qdisc *qdisc) { struct rtnl_dsmark_qdisc *dsmark; - dsmark = dsmark_qdisc(qdisc); - if (dsmark && dsmark->qdm_mask & SCH_DSMARK_ATTR_DEFAULT_INDEX) + if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc)))) + return -NLE_NOMEM; + + if (dsmark->qdm_mask & SCH_DSMARK_ATTR_DEFAULT_INDEX) return dsmark->qdm_default_index; else return -NLE_NOATTR; @@ -392,8 +347,7 @@ int rtnl_qdisc_dsmark_set_set_tc_index(struct rtnl_qdisc *qdisc, int flag) { struct rtnl_dsmark_qdisc *dsmark; - dsmark = dsmark_qdisc(qdisc); - if (!dsmark) + if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc)))) return -NLE_NOMEM; dsmark->qdm_set_tc_index = !!flag; @@ -412,8 +366,10 @@ int rtnl_qdisc_dsmark_get_set_tc_index(struct rtnl_qdisc *qdisc) { struct rtnl_dsmark_qdisc *dsmark; - dsmark = dsmark_qdisc(qdisc); - if (dsmark && dsmark->qdm_mask & SCH_DSMARK_ATTR_SET_TC_INDEX) + if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc)))) + return -NLE_NOMEM; + + if (dsmark->qdm_mask & SCH_DSMARK_ATTR_SET_TC_INDEX) return dsmark->qdm_set_tc_index; else return -NLE_NOATTR; @@ -421,33 +377,37 @@ int rtnl_qdisc_dsmark_get_set_tc_index(struct rtnl_qdisc *qdisc) /** @} */ -static struct rtnl_qdisc_ops dsmark_qdisc_ops = { - .qo_kind = "dsmark", - .qo_msg_parser = dsmark_qdisc_msg_parser, - .qo_dump = { +static struct rtnl_tc_ops dsmark_qdisc_ops = { + .to_kind = "dsmark", + .to_type = RTNL_TC_TYPE_QDISC, + .to_size = sizeof(struct rtnl_dsmark_qdisc), + .to_msg_parser = dsmark_qdisc_msg_parser, + .to_dump = { [NL_DUMP_LINE] = dsmark_qdisc_dump_line, [NL_DUMP_DETAILS] = dsmark_qdisc_dump_details, }, - .qo_get_opts = dsmark_qdisc_get_opts, + .to_msg_fill = dsmark_qdisc_msg_fill, }; -static struct rtnl_class_ops dsmark_class_ops = { - .co_kind = "dsmark", - .co_msg_parser = dsmark_class_msg_parser, - .co_dump[NL_DUMP_LINE] = dsmark_class_dump_line, - .co_get_opts = dsmark_class_get_opts, +static struct rtnl_tc_ops dsmark_class_ops = { + .to_kind = "dsmark", + .to_type = RTNL_TC_TYPE_CLASS, + .to_size = sizeof(struct rtnl_dsmark_class), + .to_msg_parser = dsmark_class_msg_parser, + .to_dump[NL_DUMP_LINE] = dsmark_class_dump_line, + .to_msg_fill = dsmark_class_msg_fill, }; static void __init dsmark_init(void) { - rtnl_qdisc_register(&dsmark_qdisc_ops); - rtnl_class_register(&dsmark_class_ops); + rtnl_tc_register(&dsmark_qdisc_ops); + rtnl_tc_register(&dsmark_class_ops); } static void __exit dsmark_exit(void) { - rtnl_qdisc_unregister(&dsmark_qdisc_ops); - rtnl_class_unregister(&dsmark_class_ops); + rtnl_tc_unregister(&dsmark_qdisc_ops); + rtnl_tc_unregister(&dsmark_class_ops); } /** @} */ diff --git a/lib/route/sch/fifo.c b/lib/route/sch/fifo.c index 464af30..1399c0a 100644 --- a/lib/route/sch/fifo.c +++ b/lib/route/sch/fifo.c @@ -6,12 +6,12 @@ * 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 */ /** - * @ingroup qdisc_api - * @defgroup fifo Packet/Bytes FIFO (pfifo/bfifo) + * @ingroup qdisc + * @defgroup qdisc_fifo Packet/Bytes FIFO (pfifo/bfifo) * @brief * * The FIFO qdisc comes in two flavours: @@ -25,15 +25,15 @@ * * The configuration is exactly the same, the decision which of * the two variations is going to be used is made based on the - * kind of the qdisc (rtnl_qdisc_set_kind()). + * kind of the qdisc (rtnl_tc_set_kind()). * @{ */ #include #include #include +#include #include -#include #include #include @@ -41,88 +41,55 @@ #define SCH_FIFO_ATTR_LIMIT 1 /** @endcond */ -static inline struct rtnl_fifo *fifo_qdisc(struct rtnl_qdisc *qdisc) +static int fifo_msg_parser(struct rtnl_tc *tc, void *data) { - return (struct rtnl_fifo *) qdisc->q_subdata; -} - -static inline struct rtnl_fifo *fifo_alloc(struct rtnl_qdisc *qdisc) -{ - if (!qdisc->q_subdata) - qdisc->q_subdata = calloc(1, sizeof(struct rtnl_fifo)); - - return fifo_qdisc(qdisc); -} - -static int fifo_msg_parser(struct rtnl_qdisc *qdisc) -{ - struct rtnl_fifo *fifo; + struct rtnl_fifo *fifo = data; struct tc_fifo_qopt *opt; - if (qdisc->q_opts->d_size < sizeof(struct tc_fifo_qopt)) + if (tc->tc_opts->d_size < sizeof(struct tc_fifo_qopt)) return -NLE_INVAL; - fifo = fifo_alloc(qdisc); - if (!fifo) - return -NLE_NOMEM; - - opt = (struct tc_fifo_qopt *) qdisc->q_opts->d_data; + opt = (struct tc_fifo_qopt *) tc->tc_opts->d_data; fifo->qf_limit = opt->limit; fifo->qf_mask = SCH_FIFO_ATTR_LIMIT; return 0; } -static void fifo_free_data(struct rtnl_qdisc *qdisc) +static void pfifo_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) { - free(qdisc->q_subdata); -} - -static void pfifo_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p) -{ - struct rtnl_fifo *fifo = fifo_qdisc(qdisc); + struct rtnl_fifo *fifo = data; if (fifo) nl_dump(p, " limit %u packets", fifo->qf_limit); } -static void bfifo_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p) +static void bfifo_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) { - struct rtnl_fifo *fifo = fifo_qdisc(qdisc); + struct rtnl_fifo *fifo = data; + char *unit; + double r; - if (fifo) { - char *unit; - double r; + if (!fifo) + return; - r = nl_cancel_down_bytes(fifo->qf_limit, &unit); - nl_dump(p, " limit %.1f%s", r, unit); - } + r = nl_cancel_down_bytes(fifo->qf_limit, &unit); + nl_dump(p, " limit %.1f%s", r, unit); } -static struct nl_msg *fifo_get_opts(struct rtnl_qdisc *qdisc) +static int fifo_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) { - struct rtnl_fifo *fifo; - struct tc_fifo_qopt opts; - struct nl_msg *msg; + struct rtnl_fifo *fifo = data; + struct tc_fifo_qopt opts = {0}; - fifo = fifo_qdisc(qdisc); if (!fifo || !(fifo->qf_mask & SCH_FIFO_ATTR_LIMIT)) - return NULL; + return -NLE_INVAL; - msg = nlmsg_alloc(); - if (!msg) - goto errout; - - memset(&opts, 0, sizeof(opts)); opts.limit = fifo->qf_limit; - if (nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD) < 0) - goto errout; - - return msg; -errout: - nlmsg_free(msg); - return NULL; + return nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD); } /** @@ -140,8 +107,7 @@ int rtnl_qdisc_fifo_set_limit(struct rtnl_qdisc *qdisc, int limit) { struct rtnl_fifo *fifo; - fifo = fifo_alloc(qdisc); - if (!fifo) + if (!(fifo = rtnl_tc_data(TC_CAST(qdisc)))) return -NLE_NOMEM; fifo->qf_limit = limit; @@ -159,8 +125,10 @@ int rtnl_qdisc_fifo_get_limit(struct rtnl_qdisc *qdisc) { struct rtnl_fifo *fifo; - fifo = fifo_qdisc(qdisc); - if (fifo && fifo->qf_mask & SCH_FIFO_ATTR_LIMIT) + if (!(fifo = rtnl_tc_data(TC_CAST(qdisc)))) + return -NLE_NOMEM; + + if (fifo->qf_mask & SCH_FIFO_ATTR_LIMIT) return fifo->qf_limit; else return -NLE_NOATTR; @@ -168,32 +136,34 @@ int rtnl_qdisc_fifo_get_limit(struct rtnl_qdisc *qdisc) /** @} */ -static struct rtnl_qdisc_ops pfifo_ops = { - .qo_kind = "pfifo", - .qo_msg_parser = fifo_msg_parser, - .qo_free_data = fifo_free_data, - .qo_dump[NL_DUMP_LINE] = pfifo_dump_line, - .qo_get_opts = fifo_get_opts, +static struct rtnl_tc_ops pfifo_ops = { + .to_kind = "pfifo", + .to_type = RTNL_TC_TYPE_QDISC, + .to_size = sizeof(struct rtnl_fifo), + .to_msg_parser = fifo_msg_parser, + .to_dump[NL_DUMP_LINE] = pfifo_dump_line, + .to_msg_fill = fifo_msg_fill, }; -static struct rtnl_qdisc_ops bfifo_ops = { - .qo_kind = "bfifo", - .qo_msg_parser = fifo_msg_parser, - .qo_free_data = fifo_free_data, - .qo_dump[NL_DUMP_LINE] = bfifo_dump_line, - .qo_get_opts = fifo_get_opts, +static struct rtnl_tc_ops bfifo_ops = { + .to_kind = "bfifo", + .to_type = RTNL_TC_TYPE_QDISC, + .to_size = sizeof(struct rtnl_fifo), + .to_msg_parser = fifo_msg_parser, + .to_dump[NL_DUMP_LINE] = bfifo_dump_line, + .to_msg_fill = fifo_msg_fill, }; static void __init fifo_init(void) { - rtnl_qdisc_register(&pfifo_ops); - rtnl_qdisc_register(&bfifo_ops); + rtnl_tc_register(&pfifo_ops); + rtnl_tc_register(&bfifo_ops); } static void __exit fifo_exit(void) { - rtnl_qdisc_unregister(&pfifo_ops); - rtnl_qdisc_unregister(&bfifo_ops); + rtnl_tc_unregister(&pfifo_ops); + rtnl_tc_unregister(&bfifo_ops); } /** @} */ diff --git a/lib/route/sch/htb.c b/lib/route/sch/htb.c index 79a58be..7f2a384 100644 --- a/lib/route/sch/htb.c +++ b/lib/route/sch/htb.c @@ -6,15 +6,15 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2010 Thomas Graf + * Copyright (c) 2003-2011 Thomas Graf * Copyright (c) 2005-2006 Petr Gotthard * Copyright (c) 2005-2006 Siemens AG Oesterreich */ /** - * @ingroup qdisc_api - * @ingroup class_api - * @defgroup htb Hierachical Token Bucket (HTB) + * @ingroup qdisc + * @ingroup class + * @defgroup qdisc_htb Hierachical Token Bucket (HTB) * @{ */ @@ -23,11 +23,9 @@ #include #include #include -#include +#include #include -#include #include -#include #include #include @@ -43,236 +41,190 @@ #define SCH_HTB_HAS_QUANTUM 0x020 /** @endcond */ -static inline struct rtnl_htb_qdisc *htb_qdisc(struct rtnl_qdisc *qdisc) -{ - if (qdisc->q_subdata == NULL) - qdisc->q_subdata = calloc(1, sizeof(struct rtnl_htb_qdisc)); - - return (struct rtnl_htb_qdisc *) qdisc->q_subdata; -} - static struct nla_policy htb_policy[TCA_HTB_MAX+1] = { [TCA_HTB_INIT] = { .minlen = sizeof(struct tc_htb_glob) }, [TCA_HTB_PARMS] = { .minlen = sizeof(struct tc_htb_opt) }, }; -static int htb_qdisc_msg_parser(struct rtnl_qdisc *qdisc) +static int htb_qdisc_msg_parser(struct rtnl_tc *tc, void *data) { - int err; struct nlattr *tb[TCA_HTB_MAX + 1]; - struct rtnl_htb_qdisc *d; + struct rtnl_htb_qdisc *htb = data; + int err; - err = tca_parse(tb, TCA_HTB_MAX, (struct rtnl_tc *) qdisc, htb_policy); - if (err < 0) + if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0) return err; - d = htb_qdisc(qdisc); - if (tb[TCA_HTB_INIT]) { struct tc_htb_glob opts; nla_memcpy(&opts, tb[TCA_HTB_INIT], sizeof(opts)); - d->qh_rate2quantum = opts.rate2quantum; - d->qh_defcls = opts.defcls; + htb->qh_rate2quantum = opts.rate2quantum; + htb->qh_defcls = opts.defcls; - d->qh_mask = (SCH_HTB_HAS_RATE2QUANTUM | SCH_HTB_HAS_DEFCLS); + htb->qh_mask = (SCH_HTB_HAS_RATE2QUANTUM | SCH_HTB_HAS_DEFCLS); } return 0; } -static void htb_qdisc_free_data(struct rtnl_qdisc *qdisc) +static int htb_class_msg_parser(struct rtnl_tc *tc, void *data) { - free(qdisc->q_subdata); -} - -static inline struct rtnl_htb_class *htb_class(struct rtnl_class *class) -{ - if (class->c_subdata == NULL) - class->c_subdata = calloc(1, sizeof(struct rtnl_htb_class)); - - return (struct rtnl_htb_class *) class->c_subdata; -} - -static int htb_class_msg_parser(struct rtnl_class *class) -{ - int err; struct nlattr *tb[TCA_HTB_MAX + 1]; - struct rtnl_htb_class *d; - struct rtnl_tc *tc = (struct rtnl_tc *) class; + struct rtnl_htb_class *htb = data; + int err; - err = tca_parse(tb, TCA_HTB_MAX, (struct rtnl_tc *) class, htb_policy); - if (err < 0) + if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0) return err; - d = htb_class(class); - if (tb[TCA_HTB_PARMS]) { struct tc_htb_opt opts; nla_memcpy(&opts, tb[TCA_HTB_PARMS], sizeof(opts)); - d->ch_prio = opts.prio; - rtnl_copy_ratespec(&d->ch_rate, &opts.rate); - rtnl_copy_ratespec(&d->ch_ceil, &opts.ceil); - d->ch_rbuffer = rtnl_tc_calc_bufsize(opts.buffer, opts.rate.rate); - d->ch_cbuffer = rtnl_tc_calc_bufsize(opts.cbuffer, opts.ceil.rate); - d->ch_quantum = opts.quantum; + htb->ch_prio = opts.prio; + rtnl_copy_ratespec(&htb->ch_rate, &opts.rate); + rtnl_copy_ratespec(&htb->ch_ceil, &opts.ceil); + htb->ch_rbuffer = rtnl_tc_calc_bufsize(opts.buffer, opts.rate.rate); + htb->ch_cbuffer = rtnl_tc_calc_bufsize(opts.cbuffer, opts.ceil.rate); + htb->ch_quantum = opts.quantum; - rtnl_tc_set_mpu(tc, d->ch_rate.rs_mpu); - rtnl_tc_set_overhead(tc, d->ch_rate.rs_overhead); + rtnl_tc_set_mpu(tc, htb->ch_rate.rs_mpu); + rtnl_tc_set_overhead(tc, htb->ch_rate.rs_overhead); - d->ch_mask = (SCH_HTB_HAS_PRIO | SCH_HTB_HAS_RATE | - SCH_HTB_HAS_CEIL | SCH_HTB_HAS_RBUFFER | - SCH_HTB_HAS_CBUFFER | SCH_HTB_HAS_QUANTUM); + htb->ch_mask = (SCH_HTB_HAS_PRIO | SCH_HTB_HAS_RATE | + SCH_HTB_HAS_CEIL | SCH_HTB_HAS_RBUFFER | + SCH_HTB_HAS_CBUFFER | SCH_HTB_HAS_QUANTUM); } return 0; } -static void htb_class_free_data(struct rtnl_class *class) -{ - free(class->c_subdata); -} - -static void htb_qdisc_dump_line(struct rtnl_qdisc *qdisc, +static void htb_qdisc_dump_line(struct rtnl_tc *tc, void *data, struct nl_dump_params *p) { - struct rtnl_htb_qdisc *d = (struct rtnl_htb_qdisc *) qdisc->q_subdata; + struct rtnl_htb_qdisc *htb = data; - if (d == NULL) + if (!htb) return; - if (d->qh_mask & SCH_HTB_HAS_RATE2QUANTUM) - nl_dump(p, " r2q %u", d->qh_rate2quantum); + if (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM) + nl_dump(p, " r2q %u", htb->qh_rate2quantum); - if (d->qh_mask & SCH_HTB_HAS_DEFCLS) { + if (htb->qh_mask & SCH_HTB_HAS_DEFCLS) { char buf[32]; nl_dump(p, " default %s", - rtnl_tc_handle2str(d->qh_defcls, buf, sizeof(buf))); + rtnl_tc_handle2str(htb->qh_defcls, buf, sizeof(buf))); } } -static void htb_class_dump_line(struct rtnl_class *class, +static void htb_class_dump_line(struct rtnl_tc *tc, void *data, struct nl_dump_params *p) { - struct rtnl_htb_class *d = (struct rtnl_htb_class *) class->c_subdata; + struct rtnl_htb_class *htb = data; - if (d == NULL) + if (!htb) return; - if (d->ch_mask & SCH_HTB_HAS_RATE) { + if (htb->ch_mask & SCH_HTB_HAS_RATE) { double r, rbit; char *ru, *rubit; - r = nl_cancel_down_bytes(d->ch_rate.rs_rate, &ru); - rbit = nl_cancel_down_bits(d->ch_rate.rs_rate*8, &rubit); + r = nl_cancel_down_bytes(htb->ch_rate.rs_rate, &ru); + rbit = nl_cancel_down_bits(htb->ch_rate.rs_rate*8, &rubit); nl_dump(p, " rate %.2f%s/s (%.0f%s) log %u", - r, ru, rbit, rubit, 1<ch_rate.rs_cell_log); + r, ru, rbit, rubit, 1<ch_rate.rs_cell_log); } } -static void htb_class_dump_details(struct rtnl_class *class, +static void htb_class_dump_details(struct rtnl_tc *tc, void *data, struct nl_dump_params *p) { - struct rtnl_htb_class *d = (struct rtnl_htb_class *) class->c_subdata; + struct rtnl_htb_class *htb = data; - if (d == NULL) + if (!htb) return; /* line 1 */ - if (d->ch_mask & SCH_HTB_HAS_CEIL) { + if (htb->ch_mask & SCH_HTB_HAS_CEIL) { double r, rbit; char *ru, *rubit; - r = nl_cancel_down_bytes(d->ch_ceil.rs_rate, &ru); - rbit = nl_cancel_down_bits(d->ch_ceil.rs_rate*8, &rubit); + r = nl_cancel_down_bytes(htb->ch_ceil.rs_rate, &ru); + rbit = nl_cancel_down_bits(htb->ch_ceil.rs_rate*8, &rubit); - nl_dump(p, " ceil %.2f%s/s (%.0f%s) log %u", - r, ru, rbit, rubit, 1<ch_ceil.rs_cell_log); + nl_dump(p, " ceil %.2f%s/s (%.0f%s) log %u", + r, ru, rbit, rubit, 1<ch_ceil.rs_cell_log); } - if (d->ch_mask & SCH_HTB_HAS_PRIO) - nl_dump(p, " prio %u", d->ch_prio); + if (htb->ch_mask & SCH_HTB_HAS_PRIO) + nl_dump(p, " prio %u", htb->ch_prio); - if (d->ch_mask & SCH_HTB_HAS_RBUFFER) { + if (htb->ch_mask & SCH_HTB_HAS_RBUFFER) { double b; char *bu; - b = nl_cancel_down_bytes(d->ch_rbuffer, &bu); + b = nl_cancel_down_bytes(htb->ch_rbuffer, &bu); nl_dump(p, " rbuffer %.2f%s", b, bu); } - if (d->ch_mask & SCH_HTB_HAS_CBUFFER) { + if (htb->ch_mask & SCH_HTB_HAS_CBUFFER) { double b; char *bu; - b = nl_cancel_down_bytes(d->ch_cbuffer, &bu); + b = nl_cancel_down_bytes(htb->ch_cbuffer, &bu); nl_dump(p, " cbuffer %.2f%s", b, bu); } - if (d->ch_mask & SCH_HTB_HAS_QUANTUM) - nl_dump(p, " quantum %u", d->ch_quantum); + if (htb->ch_mask & SCH_HTB_HAS_QUANTUM) + nl_dump(p, " quantum %u", htb->ch_quantum); } -static struct nl_msg *htb_qdisc_get_opts(struct rtnl_qdisc *qdisc) +static int htb_qdisc_msg_fill(struct rtnl_tc *tc, void *data, + struct nl_msg *msg) { - struct rtnl_htb_qdisc *d = (struct rtnl_htb_qdisc *) qdisc->q_subdata; - struct tc_htb_glob opts; - struct nl_msg *msg; + struct rtnl_htb_qdisc *htb = data; + struct tc_htb_glob opts = {0}; - msg = nlmsg_alloc(); - if (msg == NULL) - return NULL; - - memset(&opts, 0, sizeof(opts)); opts.version = TC_HTB_PROTOVER; opts.rate2quantum = 10; - if (d) { - if (d->qh_mask & SCH_HTB_HAS_RATE2QUANTUM) - opts.rate2quantum = d->qh_rate2quantum; - if (d->qh_mask & SCH_HTB_HAS_DEFCLS) - opts.defcls = d->qh_defcls; + if (htb) { + if (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM) + opts.rate2quantum = htb->qh_rate2quantum; + + if (htb->qh_mask & SCH_HTB_HAS_DEFCLS) + opts.defcls = htb->qh_defcls; } - nla_put(msg, TCA_HTB_INIT, sizeof(opts), &opts); - - return msg; + return nla_put(msg, TCA_HTB_INIT, sizeof(opts), &opts); } -static struct nl_msg *htb_class_get_opts(struct rtnl_class *class) +static int htb_class_msg_fill(struct rtnl_tc *tc, void *data, + struct nl_msg *msg) { - struct rtnl_htb_class *d = (struct rtnl_htb_class *) class->c_subdata; + struct rtnl_htb_class *htb = data; uint32_t mtu, rtable[RTNL_TC_RTABLE_SIZE], ctable[RTNL_TC_RTABLE_SIZE]; struct tc_htb_opt opts; - struct nl_msg *msg; int buffer, cbuffer; - if (d == NULL) - return NULL; - - if (!(d->ch_mask & SCH_HTB_HAS_RATE)) + if (!htb || !(htb->ch_mask & SCH_HTB_HAS_RATE)) BUG(); - msg = nlmsg_alloc(); - if (!msg) - return NULL; + /* if not set, zero (0) is used as priority */ + if (htb->ch_mask & SCH_HTB_HAS_PRIO) + opts.prio = htb->ch_prio; memset(&opts, 0, sizeof(opts)); - /* if not set, zero (0) is used as priority */ - if (d->ch_mask & SCH_HTB_HAS_PRIO) - opts.prio = d->ch_prio; + mtu = rtnl_tc_get_mtu(tc); - mtu = rtnl_tc_get_mtu((struct rtnl_tc *) class); + rtnl_tc_build_rate_table(tc, &htb->ch_rate, rtable); + rtnl_rcopy_ratespec(&opts.rate, &htb->ch_rate); - rtnl_tc_build_rate_table((struct rtnl_tc *) class, &d->ch_rate, rtable); - rtnl_rcopy_ratespec(&opts.rate, &d->ch_rate); - - if (d->ch_mask & SCH_HTB_HAS_CEIL) { - rtnl_tc_build_rate_table((struct rtnl_tc *) class, &d->ch_ceil, ctable); - rtnl_rcopy_ratespec(&opts.ceil, &d->ch_ceil); + if (htb->ch_mask & SCH_HTB_HAS_CEIL) { + rtnl_tc_build_rate_table(tc, &htb->ch_ceil, ctable); + rtnl_rcopy_ratespec(&opts.ceil, &htb->ch_ceil); } else { /* * If not set, configured rate is used as ceil, which implies @@ -281,28 +233,31 @@ static struct nl_msg *htb_class_get_opts(struct rtnl_class *class) memcpy(&opts.ceil, &opts.rate, sizeof(struct tc_ratespec)); } - if (d->ch_mask & SCH_HTB_HAS_RBUFFER) - buffer = d->ch_rbuffer; + if (htb->ch_mask & SCH_HTB_HAS_RBUFFER) + buffer = htb->ch_rbuffer; else buffer = opts.rate.rate / nl_get_user_hz() + mtu; /* XXX */ opts.buffer = rtnl_tc_calc_txtime(buffer, opts.rate.rate); - if (d->ch_mask & SCH_HTB_HAS_CBUFFER) - cbuffer = d->ch_cbuffer; + if (htb->ch_mask & SCH_HTB_HAS_CBUFFER) + cbuffer = htb->ch_cbuffer; else cbuffer = opts.ceil.rate / nl_get_user_hz() + mtu; /* XXX */ opts.cbuffer = rtnl_tc_calc_txtime(cbuffer, opts.ceil.rate); - if (d->ch_mask & SCH_HTB_HAS_QUANTUM) - opts.quantum = d->ch_quantum; + if (htb->ch_mask & SCH_HTB_HAS_QUANTUM) + opts.quantum = htb->ch_quantum; - nla_put(msg, TCA_HTB_PARMS, sizeof(opts), &opts); - nla_put(msg, TCA_HTB_RTAB, sizeof(rtable), &rtable); - nla_put(msg, TCA_HTB_CTAB, sizeof(ctable), &ctable); + NLA_PUT(msg, TCA_HTB_PARMS, sizeof(opts), &opts); + NLA_PUT(msg, TCA_HTB_RTAB, sizeof(rtable), &rtable); + NLA_PUT(msg, TCA_HTB_CTAB, sizeof(ctable), &ctable); - return msg; + return 0; + +nla_put_failure: + return -NLE_MSGSIZE; } /** @@ -312,12 +267,13 @@ static struct nl_msg *htb_class_get_opts(struct rtnl_class *class) void rtnl_htb_set_rate2quantum(struct rtnl_qdisc *qdisc, uint32_t rate2quantum) { - struct rtnl_htb_qdisc *d = htb_qdisc(qdisc); - if (d == NULL) - return; + struct rtnl_htb_qdisc *htb; - d->qh_rate2quantum = rate2quantum; - d->qh_mask |= SCH_HTB_HAS_RATE2QUANTUM; + if (!(htb = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + htb->qh_rate2quantum = rate2quantum; + htb->qh_mask |= SCH_HTB_HAS_RATE2QUANTUM; } /** @@ -327,22 +283,24 @@ void rtnl_htb_set_rate2quantum(struct rtnl_qdisc *qdisc, uint32_t rate2quantum) */ void rtnl_htb_set_defcls(struct rtnl_qdisc *qdisc, uint32_t defcls) { - struct rtnl_htb_qdisc *d = htb_qdisc(qdisc); - if (d == NULL) - return; + struct rtnl_htb_qdisc *htb; - d->qh_defcls = defcls; - d->qh_mask |= SCH_HTB_HAS_DEFCLS; + if (!(htb = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + htb->qh_defcls = defcls; + htb->qh_mask |= SCH_HTB_HAS_DEFCLS; } void rtnl_htb_set_prio(struct rtnl_class *class, uint32_t prio) { - struct rtnl_htb_class *d = htb_class(class); - if (d == NULL) - return; + struct rtnl_htb_class *htb; - d->ch_prio = prio; - d->ch_mask |= SCH_HTB_HAS_PRIO; + if (!(htb = rtnl_tc_data(TC_CAST(class)))) + BUG(); + + htb->ch_prio = prio; + htb->ch_mask |= SCH_HTB_HAS_PRIO; } /** @@ -352,22 +310,24 @@ void rtnl_htb_set_prio(struct rtnl_class *class, uint32_t prio) */ void rtnl_htb_set_rate(struct rtnl_class *class, uint32_t rate) { - struct rtnl_htb_class *d = htb_class(class); - if (d == NULL) - return; + struct rtnl_htb_class *htb; - d->ch_rate.rs_cell_log = UINT8_MAX; /* use default value */ - d->ch_rate.rs_rate = rate; - d->ch_mask |= SCH_HTB_HAS_RATE; + if (!(htb = rtnl_tc_data(TC_CAST(class)))) + BUG(); + + htb->ch_rate.rs_cell_log = UINT8_MAX; /* use default value */ + htb->ch_rate.rs_rate = rate; + htb->ch_mask |= SCH_HTB_HAS_RATE; } uint32_t rtnl_htb_get_rate(struct rtnl_class *class) { - struct rtnl_htb_class *d = htb_class(class); - if (d == NULL) + struct rtnl_htb_class *htb; + + if (!(htb = rtnl_tc_data(TC_CAST(class)))) return 0; - return d->ch_rate.rs_rate; + return htb->ch_rate.rs_rate; } /** @@ -377,13 +337,14 @@ uint32_t rtnl_htb_get_rate(struct rtnl_class *class) */ void rtnl_htb_set_ceil(struct rtnl_class *class, uint32_t ceil) { - struct rtnl_htb_class *d = htb_class(class); - if (d == NULL) - return; + struct rtnl_htb_class *htb; - d->ch_ceil.rs_cell_log = UINT8_MAX; /* use default value */ - d->ch_ceil.rs_rate = ceil; - d->ch_mask |= SCH_HTB_HAS_CEIL; + if (!(htb = rtnl_tc_data(TC_CAST(class)))) + BUG(); + + htb->ch_ceil.rs_cell_log = UINT8_MAX; /* use default value */ + htb->ch_ceil.rs_rate = ceil; + htb->ch_mask |= SCH_HTB_HAS_CEIL; } /** @@ -393,12 +354,13 @@ void rtnl_htb_set_ceil(struct rtnl_class *class, uint32_t ceil) */ void rtnl_htb_set_rbuffer(struct rtnl_class *class, uint32_t rbuffer) { - struct rtnl_htb_class *d = htb_class(class); - if (d == NULL) - return; + struct rtnl_htb_class *htb; - d->ch_rbuffer = rbuffer; - d->ch_mask |= SCH_HTB_HAS_RBUFFER; + if (!(htb = rtnl_tc_data(TC_CAST(class)))) + BUG(); + + htb->ch_rbuffer = rbuffer; + htb->ch_mask |= SCH_HTB_HAS_RBUFFER; } /** @@ -408,12 +370,13 @@ void rtnl_htb_set_rbuffer(struct rtnl_class *class, uint32_t rbuffer) */ void rtnl_htb_set_cbuffer(struct rtnl_class *class, uint32_t cbuffer) { - struct rtnl_htb_class *d = htb_class(class); - if (d == NULL) - return; + struct rtnl_htb_class *htb; - d->ch_cbuffer = cbuffer; - d->ch_mask |= SCH_HTB_HAS_CBUFFER; + if (!(htb = rtnl_tc_data(TC_CAST(class)))) + BUG(); + + htb->ch_cbuffer = cbuffer; + htb->ch_mask |= SCH_HTB_HAS_CBUFFER; } /** @@ -423,45 +386,48 @@ void rtnl_htb_set_cbuffer(struct rtnl_class *class, uint32_t cbuffer) */ void rtnl_htb_set_quantum(struct rtnl_class *class, uint32_t quantum) { - struct rtnl_htb_class *d = htb_class(class); - if (d == NULL) - return; + struct rtnl_htb_class *htb; - d->ch_quantum = quantum; - d->ch_mask |= SCH_HTB_HAS_QUANTUM; + if (!(htb = rtnl_tc_data(TC_CAST(class)))) + BUG(); + + htb->ch_quantum = quantum; + htb->ch_mask |= SCH_HTB_HAS_QUANTUM; } /** @} */ -static struct rtnl_qdisc_ops htb_qdisc_ops = { - .qo_kind = "htb", - .qo_msg_parser = htb_qdisc_msg_parser, - .qo_free_data = htb_qdisc_free_data, - .qo_dump[NL_DUMP_LINE] = htb_qdisc_dump_line, - .qo_get_opts = htb_qdisc_get_opts, +static struct rtnl_tc_ops htb_qdisc_ops = { + .to_kind = "htb", + .to_type = RTNL_TC_TYPE_QDISC, + .to_size = sizeof(struct rtnl_htb_qdisc), + .to_msg_parser = htb_qdisc_msg_parser, + .to_dump[NL_DUMP_LINE] = htb_qdisc_dump_line, + .to_msg_fill = htb_qdisc_msg_fill, }; -static struct rtnl_class_ops htb_class_ops = { - .co_kind = "htb", - .co_msg_parser = htb_class_msg_parser, - .co_free_data = htb_class_free_data, - .co_dump = { +static struct rtnl_tc_ops htb_class_ops = { + .to_kind = "htb", + .to_type = RTNL_TC_TYPE_CLASS, + .to_size = sizeof(struct rtnl_htb_class), + .to_msg_parser = htb_class_msg_parser, + .to_dump = { [NL_DUMP_LINE] = htb_class_dump_line, [NL_DUMP_DETAILS] = htb_class_dump_details, }, - .co_get_opts = htb_class_get_opts, + .to_msg_fill = htb_class_msg_fill, }; static void __init htb_init(void) { - rtnl_qdisc_register(&htb_qdisc_ops); - rtnl_class_register(&htb_class_ops); + rtnl_tc_register(&htb_qdisc_ops); + rtnl_tc_register(&htb_class_ops); } static void __exit htb_exit(void) { - rtnl_qdisc_unregister(&htb_qdisc_ops); - rtnl_class_unregister(&htb_class_ops); + rtnl_tc_unregister(&htb_qdisc_ops); + rtnl_tc_unregister(&htb_class_ops); } /** @} */ diff --git a/lib/route/sch/netem.c b/lib/route/sch/netem.c index 18878a7..981d96e 100644 --- a/lib/route/sch/netem.c +++ b/lib/route/sch/netem.c @@ -6,12 +6,12 @@ * 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 */ /** - * @ingroup qdisc_api - * @defgroup netem Network Emulator + * @ingroup qdisc + * @defgroup qdisc_netem Network Emulator * @brief * * For further documentation see http://linux-net.osdl.org/index.php/Netem @@ -22,8 +22,8 @@ #include #include #include +#include #include -#include #include /** @cond SKIP */ @@ -43,39 +43,22 @@ #define SCH_NETEM_ATTR_DIST 0x2000 /** @endcond */ -static inline struct rtnl_netem *netem_qdisc(struct rtnl_qdisc *qdisc) -{ - return (struct rtnl_netem *) qdisc->q_subdata; -} - -static inline struct rtnl_netem *netem_alloc(struct rtnl_qdisc *qdisc) -{ - if (!qdisc->q_subdata) - qdisc->q_subdata = calloc(1, sizeof(struct rtnl_netem)); - - return netem_qdisc(qdisc); -} - static struct nla_policy netem_policy[TCA_NETEM_MAX+1] = { [TCA_NETEM_CORR] = { .minlen = sizeof(struct tc_netem_corr) }, [TCA_NETEM_REORDER] = { .minlen = sizeof(struct tc_netem_reorder) }, [TCA_NETEM_CORRUPT] = { .minlen = sizeof(struct tc_netem_corrupt) }, }; -static int netem_msg_parser(struct rtnl_qdisc *qdisc) +static int netem_msg_parser(struct rtnl_tc *tc, void *data) { - int len, err = 0; - struct rtnl_netem *netem; + struct rtnl_netem *netem = data; struct tc_netem_qopt *opts; + int len, err = 0; - if (qdisc->q_opts->d_size < sizeof(*opts)) + if (tc->tc_opts->d_size < sizeof(*opts)) return -NLE_INVAL; - netem = netem_alloc(qdisc); - if (!netem) - return -NLE_NOMEM; - - opts = (struct tc_netem_qopt *) qdisc->q_opts->d_data; + opts = (struct tc_netem_qopt *) tc->tc_opts->d_data; netem->qnm_latency = opts->latency; netem->qnm_limit = opts->limit; netem->qnm_loss = opts->loss; @@ -87,13 +70,13 @@ static int netem_msg_parser(struct rtnl_qdisc *qdisc) SCH_NETEM_ATTR_LOSS | SCH_NETEM_ATTR_GAP | SCH_NETEM_ATTR_DUPLICATE | SCH_NETEM_ATTR_JITTER); - len = qdisc->q_opts->d_size - sizeof(*opts); + len = tc->tc_opts->d_size - sizeof(*opts); if (len > 0) { struct nlattr *tb[TCA_NETEM_MAX+1]; err = nla_parse(tb, TCA_NETEM_MAX, (struct nlattr *) - (qdisc->q_opts->d_data + sizeof(*opts)), + (tc->tc_opts->d_data + sizeof(*opts)), len, netem_policy); if (err < 0) { free(netem); @@ -143,52 +126,45 @@ static int netem_msg_parser(struct rtnl_qdisc *qdisc) return 0; } -static void netem_free_data(struct rtnl_qdisc *qdisc) +static void netem_free_data(struct rtnl_tc *tc, void *data) { - struct rtnl_netem *netem; + struct rtnl_netem *netem = data; - if ( ! qdisc ) return; + if (!netem) + return; - netem = netem_qdisc(qdisc); - if ( ! netem ) return; - - if ( netem->qnm_dist.dist_data ) - free(netem->qnm_dist.dist_data); - - netem = NULL; - - free (qdisc->q_subdata); + free(netem->qnm_dist.dist_data); } -static void netem_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p) +static void netem_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) { - struct rtnl_netem *netem = netem_qdisc(qdisc); + struct rtnl_netem *netem = data; if (netem) nl_dump(p, "limit %d", netem->qnm_limit); } -int netem_build_msg(struct rtnl_qdisc *qdisc, struct nl_msg *msg) +int netem_msg_fill_raw(struct rtnl_tc *tc, void *data, struct nl_msg *msg) { int err = 0; struct tc_netem_qopt opts; struct tc_netem_corr cor; struct tc_netem_reorder reorder; struct tc_netem_corrupt corrupt; - struct rtnl_netem *netem; + struct rtnl_netem *netem = data; unsigned char set_correlation = 0, set_reorder = 0, set_corrupt = 0, set_dist = 0; + if (!netem) + BUG(); + memset(&opts, 0, sizeof(opts)); memset(&cor, 0, sizeof(cor)); memset(&reorder, 0, sizeof(reorder)); memset(&corrupt, 0, sizeof(corrupt)); - netem = netem_qdisc(qdisc); - if (!netem || !msg) - return EFAULT; - msg->nm_nlh->nlmsg_flags |= NLM_F_REQUEST; if ( netem->qnm_ro.nmro_probability != 0 ) { @@ -316,18 +292,15 @@ nla_put_failure: * @arg limit New limit in bytes. * @return 0 on success or a negative error code. */ -int rtnl_netem_set_limit(struct rtnl_qdisc *qdisc, int limit) +void rtnl_netem_set_limit(struct rtnl_qdisc *qdisc, int limit) { struct rtnl_netem *netem; - netem = netem_alloc(qdisc); - if (!netem) - return -NLE_NOMEM; + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); netem->qnm_limit = limit; netem->qnm_mask |= SCH_NETEM_ATTR_LIMIT; - - return 0; } /** @@ -339,8 +312,10 @@ int rtnl_netem_get_limit(struct rtnl_qdisc *qdisc) { struct rtnl_netem *netem; - netem = netem_qdisc(qdisc); - if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_LIMIT)) + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + return -NLE_NOMEM; + + if (netem->qnm_mask & SCH_NETEM_ATTR_LIMIT) return netem->qnm_limit; else return -NLE_NOATTR; @@ -359,18 +334,15 @@ int rtnl_netem_get_limit(struct rtnl_qdisc *qdisc) * @arg gap New gap in number of packets. * @return 0 on success or a negative error code. */ -int rtnl_netem_set_gap(struct rtnl_qdisc *qdisc, int gap) +void rtnl_netem_set_gap(struct rtnl_qdisc *qdisc, int gap) { struct rtnl_netem *netem; - netem = netem_alloc(qdisc); - if (!netem) - return -NLE_NOMEM; + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); netem->qnm_gap = gap; netem->qnm_mask |= SCH_NETEM_ATTR_GAP; - - return 0; } /** @@ -382,8 +354,10 @@ int rtnl_netem_get_gap(struct rtnl_qdisc *qdisc) { struct rtnl_netem *netem; - netem = netem_qdisc(qdisc); - if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_GAP)) + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + return -NLE_NOMEM; + + if (netem->qnm_mask & SCH_NETEM_ATTR_GAP) return netem->qnm_gap; else return -NLE_NOATTR; @@ -395,18 +369,15 @@ int rtnl_netem_get_gap(struct rtnl_qdisc *qdisc) * @arg prob New re-ordering probability. * @return 0 on success or a negative error code. */ -int rtnl_netem_set_reorder_probability(struct rtnl_qdisc *qdisc, int prob) +void rtnl_netem_set_reorder_probability(struct rtnl_qdisc *qdisc, int prob) { struct rtnl_netem *netem; - netem = netem_alloc(qdisc); - if (!netem) - return -NLE_NOMEM; + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); netem->qnm_ro.nmro_probability = prob; netem->qnm_mask |= SCH_NETEM_ATTR_RO_PROB; - - return 0; } /** @@ -418,8 +389,10 @@ int rtnl_netem_get_reorder_probability(struct rtnl_qdisc *qdisc) { struct rtnl_netem *netem; - netem = netem_qdisc(qdisc); - if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_RO_PROB)) + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + return -NLE_NOMEM; + + if (netem->qnm_mask & SCH_NETEM_ATTR_RO_PROB) return netem->qnm_ro.nmro_probability; else return -NLE_NOATTR; @@ -431,18 +404,15 @@ int rtnl_netem_get_reorder_probability(struct rtnl_qdisc *qdisc) * @arg prob New re-ordering correlation probability. * @return 0 on success or a negative error code. */ -int rtnl_netem_set_reorder_correlation(struct rtnl_qdisc *qdisc, int prob) +void rtnl_netem_set_reorder_correlation(struct rtnl_qdisc *qdisc, int prob) { struct rtnl_netem *netem; - netem = netem_alloc(qdisc); - if (!netem) - return -NLE_NOMEM; + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); netem->qnm_ro.nmro_correlation = prob; netem->qnm_mask |= SCH_NETEM_ATTR_RO_CORR; - - return 0; } /** @@ -454,8 +424,10 @@ int rtnl_netem_get_reorder_correlation(struct rtnl_qdisc *qdisc) { struct rtnl_netem *netem; - netem = netem_qdisc(qdisc); - if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_RO_CORR)) + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + return -NLE_NOMEM; + + if (netem->qnm_mask & SCH_NETEM_ATTR_RO_CORR) return netem->qnm_ro.nmro_correlation; else return -NLE_NOATTR; @@ -474,18 +446,15 @@ int rtnl_netem_get_reorder_correlation(struct rtnl_qdisc *qdisc) * @arg prob New corruption probability. * @return 0 on success or a negative error code. */ -int rtnl_netem_set_corruption_probability(struct rtnl_qdisc *qdisc, int prob) +void rtnl_netem_set_corruption_probability(struct rtnl_qdisc *qdisc, int prob) { struct rtnl_netem *netem; - netem = netem_alloc(qdisc); - if (!netem) - return -NLE_NOMEM; + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); netem->qnm_crpt.nmcr_probability = prob; netem->qnm_mask |= SCH_NETEM_ATTR_CORRUPT_PROB; - - return 0; } /** @@ -497,8 +466,10 @@ int rtnl_netem_get_corruption_probability(struct rtnl_qdisc *qdisc) { struct rtnl_netem *netem; - netem = netem_qdisc(qdisc); - if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_CORRUPT_PROB)) + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (netem->qnm_mask & SCH_NETEM_ATTR_CORRUPT_PROB) return netem->qnm_crpt.nmcr_probability; else return -NLE_NOATTR; @@ -510,18 +481,15 @@ int rtnl_netem_get_corruption_probability(struct rtnl_qdisc *qdisc) * @arg prob New corruption correlation probability. * @return 0 on success or a negative error code. */ -int rtnl_netem_set_corruption_correlation(struct rtnl_qdisc *qdisc, int prob) +void rtnl_netem_set_corruption_correlation(struct rtnl_qdisc *qdisc, int prob) { struct rtnl_netem *netem; - netem = netem_alloc(qdisc); - if (!netem) - return -NLE_NOMEM; + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); netem->qnm_crpt.nmcr_correlation = prob; netem->qnm_mask |= SCH_NETEM_ATTR_CORRUPT_CORR; - - return 0; } /** @@ -533,8 +501,10 @@ int rtnl_netem_get_corruption_correlation(struct rtnl_qdisc *qdisc) { struct rtnl_netem *netem; - netem = netem_qdisc(qdisc); - if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_CORRUPT_CORR)) + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (netem->qnm_mask & SCH_NETEM_ATTR_CORRUPT_CORR) return netem->qnm_crpt.nmcr_correlation; else return -NLE_NOATTR; @@ -553,18 +523,15 @@ int rtnl_netem_get_corruption_correlation(struct rtnl_qdisc *qdisc) * @arg prob New packet loss probability. * @return 0 on success or a negative error code. */ -int rtnl_netem_set_loss(struct rtnl_qdisc *qdisc, int prob) +void rtnl_netem_set_loss(struct rtnl_qdisc *qdisc, int prob) { struct rtnl_netem *netem; - netem = netem_alloc(qdisc); - if (!netem) - return -NLE_NOMEM; + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); netem->qnm_loss = prob; netem->qnm_mask |= SCH_NETEM_ATTR_LOSS; - - return 0; } /** @@ -576,8 +543,10 @@ int rtnl_netem_get_loss(struct rtnl_qdisc *qdisc) { struct rtnl_netem *netem; - netem = netem_qdisc(qdisc); - if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_LOSS)) + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (netem->qnm_mask & SCH_NETEM_ATTR_LOSS) return netem->qnm_loss; else return -NLE_NOATTR; @@ -589,18 +558,15 @@ int rtnl_netem_get_loss(struct rtnl_qdisc *qdisc) * @arg prob New packet loss correlation. * @return 0 on success or a negative error code. */ -int rtnl_netem_set_loss_correlation(struct rtnl_qdisc *qdisc, int prob) +void rtnl_netem_set_loss_correlation(struct rtnl_qdisc *qdisc, int prob) { struct rtnl_netem *netem; - netem = netem_alloc(qdisc); - if (!netem) - return -NLE_NOMEM; + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); netem->qnm_corr.nmc_loss = prob; netem->qnm_mask |= SCH_NETEM_ATTR_LOSS_CORR; - - return 0; } /** @@ -612,8 +578,10 @@ int rtnl_netem_get_loss_correlation(struct rtnl_qdisc *qdisc) { struct rtnl_netem *netem; - netem = netem_qdisc(qdisc); - if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_LOSS_CORR)) + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (netem->qnm_mask & SCH_NETEM_ATTR_LOSS_CORR) return netem->qnm_corr.nmc_loss; else return -NLE_NOATTR; @@ -632,18 +600,15 @@ int rtnl_netem_get_loss_correlation(struct rtnl_qdisc *qdisc) * @arg prob New packet duplication probability. * @return 0 on success or a negative error code. */ -int rtnl_netem_set_duplicate(struct rtnl_qdisc *qdisc, int prob) +void rtnl_netem_set_duplicate(struct rtnl_qdisc *qdisc, int prob) { struct rtnl_netem *netem; - netem = netem_alloc(qdisc); - if (!netem) - return -NLE_NOMEM; + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); netem->qnm_duplicate = prob; netem->qnm_mask |= SCH_NETEM_ATTR_DUPLICATE; - - return 0; } /** @@ -655,8 +620,10 @@ int rtnl_netem_get_duplicate(struct rtnl_qdisc *qdisc) { struct rtnl_netem *netem; - netem = netem_qdisc(qdisc); - if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_DUPLICATE)) + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (netem->qnm_mask & SCH_NETEM_ATTR_DUPLICATE) return netem->qnm_duplicate; else return -NLE_NOATTR; @@ -668,18 +635,15 @@ int rtnl_netem_get_duplicate(struct rtnl_qdisc *qdisc) * @arg prob New packet duplication correlation probability. * @return 0 on sucess or a negative error code. */ -int rtnl_netem_set_duplicate_correlation(struct rtnl_qdisc *qdisc, int prob) +void rtnl_netem_set_duplicate_correlation(struct rtnl_qdisc *qdisc, int prob) { struct rtnl_netem *netem; - netem = netem_alloc(qdisc); - if (!netem) - return -NLE_NOMEM; + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); netem->qnm_corr.nmc_duplicate = prob; netem->qnm_mask |= SCH_NETEM_ATTR_DUP_CORR; - - return 0; } /** @@ -691,8 +655,10 @@ int rtnl_netem_get_duplicate_correlation(struct rtnl_qdisc *qdisc) { struct rtnl_netem *netem; - netem = netem_qdisc(qdisc); - if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_DUP_CORR)) + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (netem->qnm_mask & SCH_NETEM_ATTR_DUP_CORR) return netem->qnm_corr.nmc_duplicate; else return -NLE_NOATTR; @@ -711,18 +677,15 @@ int rtnl_netem_get_duplicate_correlation(struct rtnl_qdisc *qdisc) * @arg delay New packet delay in micro seconds. * @return 0 on success or a negative error code. */ -int rtnl_netem_set_delay(struct rtnl_qdisc *qdisc, int delay) +void rtnl_netem_set_delay(struct rtnl_qdisc *qdisc, int delay) { struct rtnl_netem *netem; - netem = netem_alloc(qdisc); - if (!netem) - return -NLE_NOMEM; + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); netem->qnm_latency = nl_us2ticks(delay); netem->qnm_mask |= SCH_NETEM_ATTR_LATENCY; - - return 0; } /** @@ -734,8 +697,10 @@ int rtnl_netem_get_delay(struct rtnl_qdisc *qdisc) { struct rtnl_netem *netem; - netem = netem_qdisc(qdisc); - if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_LATENCY)) + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (netem->qnm_mask & SCH_NETEM_ATTR_LATENCY) return nl_ticks2us(netem->qnm_latency); else return -NLE_NOATTR; @@ -747,18 +712,15 @@ int rtnl_netem_get_delay(struct rtnl_qdisc *qdisc) * @arg jitter New packet delay jitter in micro seconds. * @return 0 on success or a negative error code. */ -int rtnl_netem_set_jitter(struct rtnl_qdisc *qdisc, int jitter) +void rtnl_netem_set_jitter(struct rtnl_qdisc *qdisc, int jitter) { struct rtnl_netem *netem; - netem = netem_alloc(qdisc); - if (!netem) - return -NLE_NOMEM; + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); netem->qnm_jitter = nl_us2ticks(jitter); netem->qnm_mask |= SCH_NETEM_ATTR_JITTER; - - return 0; } /** @@ -770,8 +732,10 @@ int rtnl_netem_get_jitter(struct rtnl_qdisc *qdisc) { struct rtnl_netem *netem; - netem = netem_qdisc(qdisc); - if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_JITTER)) + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (netem->qnm_mask & SCH_NETEM_ATTR_JITTER) return nl_ticks2us(netem->qnm_jitter); else return -NLE_NOATTR; @@ -782,18 +746,15 @@ int rtnl_netem_get_jitter(struct rtnl_qdisc *qdisc) * @arg qdisc Netem qdisc to be modified. * @arg prob New packet delay correlation probability. */ -int rtnl_netem_set_delay_correlation(struct rtnl_qdisc *qdisc, int prob) +void rtnl_netem_set_delay_correlation(struct rtnl_qdisc *qdisc, int prob) { struct rtnl_netem *netem; - netem = netem_alloc(qdisc); - if (!netem) - return -NLE_NOMEM; + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); netem->qnm_corr.nmc_delay = prob; netem->qnm_mask |= SCH_NETEM_ATTR_DELAY_CORR; - - return 0; } /** @@ -805,8 +766,10 @@ int rtnl_netem_get_delay_correlation(struct rtnl_qdisc *qdisc) { struct rtnl_netem *netem; - netem = netem_qdisc(qdisc); - if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_DELAY_CORR)) + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (netem->qnm_mask & SCH_NETEM_ATTR_DELAY_CORR) return netem->qnm_corr.nmc_delay; else return -NLE_NOATTR; @@ -821,8 +784,10 @@ int rtnl_netem_get_delay_distribution_size(struct rtnl_qdisc *qdisc) { struct rtnl_netem *netem; - netem = netem_qdisc(qdisc); - if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_DIST)) + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (netem->qnm_mask & SCH_NETEM_ATTR_DIST) return netem->qnm_dist.dist_size; else return -NLE_NOATTR; @@ -838,12 +803,13 @@ int rtnl_netem_get_delay_distribution(struct rtnl_qdisc *qdisc, int16_t **dist_p { struct rtnl_netem *netem; - netem = netem_qdisc(qdisc); - if (netem && (netem->qnm_mask & SCH_NETEM_ATTR_DIST)) { + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (netem->qnm_mask & SCH_NETEM_ATTR_DIST) { *dist_ptr = netem->qnm_dist.dist_data; return 0; - } - else + } else return -NLE_NOATTR; } @@ -856,9 +822,8 @@ int rtnl_netem_get_delay_distribution(struct rtnl_qdisc *qdisc, int16_t **dist_p int rtnl_netem_set_delay_distribution(struct rtnl_qdisc *qdisc, const char *dist_type) { struct rtnl_netem *netem; - netem = netem_alloc(qdisc); - if (!netem) - return -NLE_NOMEM; + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); FILE *f = NULL; int i, n = 0; @@ -917,23 +882,24 @@ int rtnl_netem_set_delay_distribution(struct rtnl_qdisc *qdisc, const char *dist /** @} */ -static struct rtnl_qdisc_ops netem_ops = { - .qo_kind = "netem", - .qo_msg_parser = netem_msg_parser, - .qo_free_data = netem_free_data, - .qo_dump[NL_DUMP_LINE] = netem_dump_line, - .qo_get_opts = 0, - .qo_build_msg = netem_build_msg +static struct rtnl_tc_ops netem_ops = { + .to_kind = "netem", + .to_type = RTNL_TC_TYPE_QDISC, + .to_size = sizeof(struct rtnl_netem), + .to_msg_parser = netem_msg_parser, + .to_free_data = netem_free_data, + .to_dump[NL_DUMP_LINE] = netem_dump_line, + .to_msg_fill_raw = netem_msg_fill_raw, }; static void __init netem_init(void) { - rtnl_qdisc_register(&netem_ops); + rtnl_tc_register(&netem_ops); } static void __exit netem_exit(void) { - rtnl_qdisc_unregister(&netem_ops); + rtnl_tc_unregister(&netem_ops); } /** @} */ diff --git a/lib/route/sch/prio.c b/lib/route/sch/prio.c index e08e117..6f8ff34 100644 --- a/lib/route/sch/prio.c +++ b/lib/route/sch/prio.c @@ -6,12 +6,12 @@ * 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 */ /** - * @ingroup qdisc_api - * @defgroup prio (Fast) Prio + * @ingroup qdisc + * @defgroup qdisc_prio (Fast) Prio * @brief * * @par 1) Typical PRIO configuration @@ -30,8 +30,8 @@ #include #include #include +#include #include -#include #include /** @cond SKIP */ @@ -39,32 +39,15 @@ #define SCH_PRIO_ATTR_PRIOMAP 2 /** @endcond */ -static inline struct rtnl_prio *prio_qdisc(struct rtnl_qdisc *qdisc) +static int prio_msg_parser(struct rtnl_tc *tc, void *data) { - return (struct rtnl_prio *) qdisc->q_subdata; -} - -static inline struct rtnl_prio *prio_alloc(struct rtnl_qdisc *qdisc) -{ - if (!qdisc->q_subdata) - qdisc->q_subdata = calloc(1, sizeof(struct rtnl_prio)); - - return prio_qdisc(qdisc); -} - -static int prio_msg_parser(struct rtnl_qdisc *qdisc) -{ - struct rtnl_prio *prio; + struct rtnl_prio *prio = data; struct tc_prio_qopt *opt; - if (qdisc->q_opts->d_size < sizeof(*opt)) + if (tc->tc_opts->d_size < sizeof(*opt)) return -NLE_INVAL; - prio = prio_alloc(qdisc); - if (!prio) - return -NLE_NOMEM; - - opt = (struct tc_prio_qopt *) qdisc->q_opts->d_data; + opt = (struct tc_prio_qopt *) tc->tc_opts->d_data; prio->qp_bands = opt->bands; memcpy(prio->qp_priomap, opt->priomap, sizeof(prio->qp_priomap)); prio->qp_mask = (SCH_PRIO_ATTR_BANDS | SCH_PRIO_ATTR_PRIOMAP); @@ -72,22 +55,19 @@ static int prio_msg_parser(struct rtnl_qdisc *qdisc) return 0; } -static void prio_free_data(struct rtnl_qdisc *qdisc) +static void prio_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) { - free(qdisc->q_subdata); -} - -static void prio_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p) -{ - struct rtnl_prio *prio = prio_qdisc(qdisc); + struct rtnl_prio *prio = data; if (prio) nl_dump(p, " bands %u", prio->qp_bands); } -static void prio_dump_details(struct rtnl_qdisc *qdisc,struct nl_dump_params *p) +static void prio_dump_details(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) { - struct rtnl_prio *prio = prio_qdisc(qdisc); + struct rtnl_prio *prio = data; int i, hp; if (!prio) @@ -121,32 +101,18 @@ static void prio_dump_details(struct rtnl_qdisc *qdisc,struct nl_dump_params *p) } } -static struct nl_msg *prio_get_opts(struct rtnl_qdisc *qdisc) +static int prio_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) { - struct rtnl_prio *prio; + struct rtnl_prio *prio = data; struct tc_prio_qopt opts; - struct nl_msg *msg; - prio = prio_qdisc(qdisc); - if (!prio || - !(prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP)) - goto errout; + if (!prio || !(prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP)) + BUG(); opts.bands = prio->qp_bands; memcpy(opts.priomap, prio->qp_priomap, sizeof(opts.priomap)); - msg = nlmsg_alloc(); - if (!msg) - goto errout; - - if (nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD) < 0) { - nlmsg_free(msg); - goto errout; - } - - return msg; -errout: - return NULL; + return nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD); } /** @@ -160,18 +126,15 @@ errout: * @arg bands New number of bands. * @return 0 on success or a negative error code. */ -int rtnl_qdisc_prio_set_bands(struct rtnl_qdisc *qdisc, int bands) +void rtnl_qdisc_prio_set_bands(struct rtnl_qdisc *qdisc, int bands) { struct rtnl_prio *prio; - - prio = prio_alloc(qdisc); - if (!prio) - return -NLE_NOMEM; + + if (!(prio = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); prio->qp_bands = bands; prio->qp_mask |= SCH_PRIO_ATTR_BANDS; - - return 0; } /** @@ -183,8 +146,10 @@ int rtnl_qdisc_prio_get_bands(struct rtnl_qdisc *qdisc) { struct rtnl_prio *prio; - prio = prio_qdisc(qdisc); - if (prio && prio->qp_mask & SCH_PRIO_ATTR_BANDS) + if (!(prio = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (prio->qp_mask & SCH_PRIO_ATTR_BANDS) return prio->qp_bands; else return -NLE_NOMEM; @@ -203,9 +168,8 @@ int rtnl_qdisc_prio_set_priomap(struct rtnl_qdisc *qdisc, uint8_t priomap[], struct rtnl_prio *prio; int i; - prio = prio_alloc(qdisc); - if (!prio) - return -NLE_NOMEM; + if (!(prio = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); if (!(prio->qp_mask & SCH_PRIO_ATTR_BANDS)) return -NLE_MISSING_ATTR; @@ -234,8 +198,10 @@ uint8_t *rtnl_qdisc_prio_get_priomap(struct rtnl_qdisc *qdisc) { struct rtnl_prio *prio; - prio = prio_qdisc(qdisc); - if (prio && prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP) + if (!(prio = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP) return prio->qp_priomap; else return NULL; @@ -289,38 +255,40 @@ int rtnl_str2prio(const char *name) /** @} */ -static struct rtnl_qdisc_ops prio_ops = { - .qo_kind = "prio", - .qo_msg_parser = prio_msg_parser, - .qo_free_data = prio_free_data, - .qo_dump = { +static struct rtnl_tc_ops prio_ops = { + .to_kind = "prio", + .to_type = RTNL_TC_TYPE_QDISC, + .to_size = sizeof(struct rtnl_prio), + .to_msg_parser = prio_msg_parser, + .to_dump = { [NL_DUMP_LINE] = prio_dump_line, [NL_DUMP_DETAILS] = prio_dump_details, }, - .qo_get_opts = prio_get_opts, + .to_msg_fill = prio_msg_fill, }; -static struct rtnl_qdisc_ops pfifo_fast_ops = { - .qo_kind = "pfifo_fast", - .qo_msg_parser = prio_msg_parser, - .qo_free_data = prio_free_data, - .qo_dump = { +static struct rtnl_tc_ops pfifo_fast_ops = { + .to_kind = "pfifo_fast", + .to_type = RTNL_TC_TYPE_QDISC, + .to_size = sizeof(struct rtnl_prio), + .to_msg_parser = prio_msg_parser, + .to_dump = { [NL_DUMP_LINE] = prio_dump_line, [NL_DUMP_DETAILS] = prio_dump_details, }, - .qo_get_opts = prio_get_opts, + .to_msg_fill = prio_msg_fill, }; static void __init prio_init(void) { - rtnl_qdisc_register(&prio_ops); - rtnl_qdisc_register(&pfifo_fast_ops); + rtnl_tc_register(&prio_ops); + rtnl_tc_register(&pfifo_fast_ops); } static void __exit prio_exit(void) { - rtnl_qdisc_unregister(&prio_ops); - rtnl_qdisc_unregister(&pfifo_fast_ops); + rtnl_tc_unregister(&prio_ops); + rtnl_tc_unregister(&pfifo_fast_ops); } /** @} */ diff --git a/lib/route/sch/red.c b/lib/route/sch/red.c index 727db17..5df3f3c 100644 --- a/lib/route/sch/red.c +++ b/lib/route/sch/red.c @@ -6,12 +6,12 @@ * 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 */ /** - * @ingroup qdisc_api - * @defgroup red Random Early Detection (RED) + * @ingroup qdisc + * @defgroup qdisc_red Random Early Detection (RED) * @brief * @{ */ @@ -20,8 +20,8 @@ #include #include #include +#include #include -#include #include /** @cond SKIP */ @@ -34,44 +34,27 @@ #define RED_ATTR_SCELL_LOG 0x40 /** @endcond */ -static inline struct rtnl_red *red_qdisc(struct rtnl_qdisc *qdisc) -{ - return (struct rtnl_red *) qdisc->q_subdata; -} - -static inline struct rtnl_red *red_alloc(struct rtnl_qdisc *qdisc) -{ - if (!qdisc->q_subdata) - qdisc->q_subdata = calloc(1, sizeof(struct rtnl_red)); - - return red_qdisc(qdisc); -} - static struct nla_policy red_policy[TCA_RED_MAX+1] = { [TCA_RED_PARMS] = { .minlen = sizeof(struct tc_red_qopt) }, }; -static int red_msg_parser(struct rtnl_qdisc *qdisc) +static int red_msg_parser(struct rtnl_tc *tc, void *data) { struct nlattr *tb[TCA_RED_MAX+1]; - struct rtnl_red *red; + struct rtnl_red *red = data; struct tc_red_qopt *opts; int err; - if (!(qdisc->ce_mask & TCA_ATTR_OPTS)) + if (!(tc->ce_mask & TCA_ATTR_OPTS)) return 0; - err = tca_parse(tb, TCA_RED_MAX, (struct rtnl_tc *) qdisc, red_policy); + err = tca_parse(tb, TCA_RED_MAX, tc, red_policy); if (err < 0) return err; if (!tb[TCA_RED_PARMS]) return -NLE_MISSING_ATTR; - red = red_alloc(qdisc); - if (!red) - return -NLE_NOMEM; - opts = nla_data(tb[TCA_RED_PARMS]); red->qr_limit = opts->limit; @@ -89,45 +72,42 @@ static int red_msg_parser(struct rtnl_qdisc *qdisc) return 0; } -static void red_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p) +static void red_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) { - struct rtnl_red *red = red_qdisc(qdisc); + struct rtnl_red *red = data; if (red) { /* XXX: limit, min, max, flags */ } } -static void red_dump_details(struct rtnl_qdisc *qdisc, struct nl_dump_params *p) +static void red_dump_details(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) { - struct rtnl_red *red = red_qdisc(qdisc); + struct rtnl_red *red = data; if (red) { /* XXX: wlog, plog, scell_log */ } } -static void red_dump_stats(struct rtnl_qdisc *qdisc, struct nl_dump_params *p) +static void red_dump_stats(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) { - struct rtnl_red *red = red_qdisc(qdisc); + struct rtnl_red *red = data; if (red) { /* XXX: xstats */ } } -static struct nl_msg *red_get_opts(struct rtnl_qdisc *qdisc) +static int red_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) { - struct rtnl_red *red; - struct nl_msg *msg; + struct rtnl_red *red = data; - red = red_qdisc(qdisc); if (!red) - return NULL; - - msg = nlmsg_alloc(); - if (!msg) - goto errout; + BUG(); #if 0 memset(&opts, 0, sizeof(opts)); @@ -139,10 +119,7 @@ static struct nl_msg *red_get_opts(struct rtnl_qdisc *qdisc) goto errout; #endif - return msg; -errout: - nlmsg_free(msg); - return NULL; + return -NLE_OPNOTSUPP; } /** @@ -156,18 +133,15 @@ errout: * @arg limit New limit in number of packets. * @return 0 on success or a negative error code. */ -int rtnl_red_set_limit(struct rtnl_qdisc *qdisc, int limit) +void rtnl_red_set_limit(struct rtnl_qdisc *qdisc, int limit) { struct rtnl_red *red; - red = red_alloc(qdisc); - if (!red) - return -NLE_NOMEM; + if (!(red = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); red->qr_limit = limit; red->qr_mask |= RED_ATTR_LIMIT; - - return 0; } /** @@ -179,8 +153,10 @@ int rtnl_red_get_limit(struct rtnl_qdisc *qdisc) { struct rtnl_red *red; - red = red_qdisc(qdisc); - if (red && (red->qr_mask & RED_ATTR_LIMIT)) + if (!(red = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (red->qr_mask & RED_ATTR_LIMIT) return red->qr_limit; else return -NLE_NOATTR; @@ -188,25 +164,27 @@ int rtnl_red_get_limit(struct rtnl_qdisc *qdisc) /** @} */ -static struct rtnl_qdisc_ops red_ops = { - .qo_kind = "red", - .qo_msg_parser = red_msg_parser, - .qo_dump = { +static struct rtnl_tc_ops red_ops = { + .to_kind = "red", + .to_type = RTNL_TC_TYPE_QDISC, + .to_size = sizeof(struct rtnl_red), + .to_msg_parser = red_msg_parser, + .to_dump = { [NL_DUMP_LINE] = red_dump_line, [NL_DUMP_DETAILS] = red_dump_details, [NL_DUMP_STATS] = red_dump_stats, }, - .qo_get_opts = red_get_opts, + .to_msg_fill = red_msg_fill, }; static void __init red_init(void) { - rtnl_qdisc_register(&red_ops); + rtnl_tc_register(&red_ops); } static void __exit red_exit(void) { - rtnl_qdisc_unregister(&red_ops); + rtnl_tc_unregister(&red_ops); } /** @} */ diff --git a/lib/route/sch/sfq.c b/lib/route/sch/sfq.c index cad99fd..e817a6a 100644 --- a/lib/route/sch/sfq.c +++ b/lib/route/sch/sfq.c @@ -6,12 +6,12 @@ * 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 */ /** - * @ingroup qdisc_api - * @defgroup sfq Stochastic Fairness Queueing (SFQ) + * @ingroup qdisc + * @defgroup qdisc_sfq Stochastic Fairness Queueing (SFQ) * @brief * * @par Parameter Description @@ -27,8 +27,8 @@ #include #include #include +#include #include -#include #include /** @cond SKIP */ @@ -39,35 +39,18 @@ #define SCH_SFQ_ATTR_FLOWS 0x10 /** @endcond */ -static inline struct rtnl_sfq *sfq_qdisc(struct rtnl_qdisc *qdisc) +static int sfq_msg_parser(struct rtnl_tc *tc, void *data) { - return (struct rtnl_sfq *) qdisc->q_subdata; -} - -static inline struct rtnl_sfq *sfq_alloc(struct rtnl_qdisc *qdisc) -{ - if (!qdisc->q_subdata) - qdisc->q_subdata = calloc(1, sizeof(struct rtnl_sfq)); - - return sfq_qdisc(qdisc); -} - -static int sfq_msg_parser(struct rtnl_qdisc *qdisc) -{ - struct rtnl_sfq *sfq; + struct rtnl_sfq *sfq = data; struct tc_sfq_qopt *opts; - if (!(qdisc->ce_mask & TCA_ATTR_OPTS)) + if (!(tc->ce_mask & TCA_ATTR_OPTS)) return 0; - if (qdisc->q_opts->d_size < sizeof(*opts)) + if (tc->tc_opts->d_size < sizeof(*opts)) return -NLE_INVAL; - sfq = sfq_alloc(qdisc); - if (!sfq) - return -NLE_NOMEM; - - opts = (struct tc_sfq_qopt *) qdisc->q_opts->d_data; + opts = (struct tc_sfq_qopt *) tc->tc_opts->d_data; sfq->qs_quantum = opts->quantum; sfq->qs_perturb = opts->perturb_period; @@ -82,55 +65,39 @@ static int sfq_msg_parser(struct rtnl_qdisc *qdisc) return 0; } -static void sfq_free_data(struct rtnl_qdisc *qdisc) +static void sfq_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) { - free(qdisc->q_subdata); -} - -static void sfq_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p) -{ - struct rtnl_sfq *sfq = sfq_qdisc(qdisc); + struct rtnl_sfq *sfq = data; if (sfq) nl_dump(p, " quantum %u perturb %us", sfq->qs_quantum, sfq->qs_perturb); } -static void sfq_dump_details(struct rtnl_qdisc *qdisc, struct nl_dump_params *p) +static void sfq_dump_details(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) { - struct rtnl_sfq *sfq = sfq_qdisc(qdisc); + struct rtnl_sfq *sfq = data; if (sfq) nl_dump(p, "limit %u divisor %u", sfq->qs_limit, sfq->qs_divisor); } -static struct nl_msg *sfq_get_opts(struct rtnl_qdisc *qdisc) +static int sfq_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) { - struct rtnl_sfq *sfq; - struct tc_sfq_qopt opts; - struct nl_msg *msg; + struct rtnl_sfq *sfq = data; + struct tc_sfq_qopt opts = {0}; - sfq = sfq_qdisc(qdisc); if (!sfq) - return NULL; + BUG(); - msg = nlmsg_alloc(); - if (!msg) - goto errout; - - memset(&opts, 0, sizeof(opts)); opts.quantum = sfq->qs_quantum; opts.perturb_period = sfq->qs_perturb; opts.limit = sfq->qs_limit; - if (nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD) < 0) - goto errout; - - return msg; -errout: - nlmsg_free(msg); - return NULL; + return nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD); } /** @@ -144,18 +111,15 @@ errout: * @arg quantum New quantum in bytes. * @return 0 on success or a negative error code. */ -int rtnl_sfq_set_quantum(struct rtnl_qdisc *qdisc, int quantum) +void rtnl_sfq_set_quantum(struct rtnl_qdisc *qdisc, int quantum) { struct rtnl_sfq *sfq; - sfq = sfq_alloc(qdisc); - if (!sfq) - return -NLE_NOMEM; + if (!(sfq = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); sfq->qs_quantum = quantum; sfq->qs_mask |= SCH_SFQ_ATTR_QUANTUM; - - return 0; } /** @@ -166,9 +130,11 @@ int rtnl_sfq_set_quantum(struct rtnl_qdisc *qdisc, int quantum) int rtnl_sfq_get_quantum(struct rtnl_qdisc *qdisc) { struct rtnl_sfq *sfq; + + if (!(sfq = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); - sfq = sfq_qdisc(qdisc); - if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_QUANTUM) + if (sfq->qs_mask & SCH_SFQ_ATTR_QUANTUM) return sfq->qs_quantum; else return -NLE_NOATTR; @@ -180,18 +146,15 @@ int rtnl_sfq_get_quantum(struct rtnl_qdisc *qdisc) * @arg limit New limit in number of packets. * @return 0 on success or a negative error code. */ -int rtnl_sfq_set_limit(struct rtnl_qdisc *qdisc, int limit) +void rtnl_sfq_set_limit(struct rtnl_qdisc *qdisc, int limit) { struct rtnl_sfq *sfq; - - sfq = sfq_alloc(qdisc); - if (!sfq) - return -NLE_NOMEM; + + if (!(sfq = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); sfq->qs_limit = limit; sfq->qs_mask |= SCH_SFQ_ATTR_LIMIT; - - return 0; } /** @@ -202,9 +165,11 @@ int rtnl_sfq_set_limit(struct rtnl_qdisc *qdisc, int limit) int rtnl_sfq_get_limit(struct rtnl_qdisc *qdisc) { struct rtnl_sfq *sfq; + + if (!(sfq = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); - sfq = sfq_qdisc(qdisc); - if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_LIMIT) + if (sfq->qs_mask & SCH_SFQ_ATTR_LIMIT) return sfq->qs_limit; else return -NLE_NOATTR; @@ -217,18 +182,15 @@ int rtnl_sfq_get_limit(struct rtnl_qdisc *qdisc) * @note A value of 0 disables perturbation altogether. * @return 0 on success or a negative error code. */ -int rtnl_sfq_set_perturb(struct rtnl_qdisc *qdisc, int perturb) +void rtnl_sfq_set_perturb(struct rtnl_qdisc *qdisc, int perturb) { struct rtnl_sfq *sfq; - - sfq = sfq_alloc(qdisc); - if (!sfq) - return -NLE_NOMEM; + + if (!(sfq = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); sfq->qs_perturb = perturb; sfq->qs_mask |= SCH_SFQ_ATTR_PERTURB; - - return 0; } /** @@ -239,9 +201,11 @@ int rtnl_sfq_set_perturb(struct rtnl_qdisc *qdisc, int perturb) int rtnl_sfq_get_perturb(struct rtnl_qdisc *qdisc) { struct rtnl_sfq *sfq; + + if (!(sfq = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); - sfq = sfq_qdisc(qdisc); - if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_PERTURB) + if (sfq->qs_mask & SCH_SFQ_ATTR_PERTURB) return sfq->qs_perturb; else return -NLE_NOATTR; @@ -255,9 +219,11 @@ int rtnl_sfq_get_perturb(struct rtnl_qdisc *qdisc) int rtnl_sfq_get_divisor(struct rtnl_qdisc *qdisc) { struct rtnl_sfq *sfq; + + if (!(sfq = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); - sfq = sfq_qdisc(qdisc); - if (sfq && sfq->qs_mask & SCH_SFQ_ATTR_DIVISOR) + if (sfq->qs_mask & SCH_SFQ_ATTR_DIVISOR) return sfq->qs_divisor; else return -NLE_NOATTR; @@ -265,25 +231,26 @@ int rtnl_sfq_get_divisor(struct rtnl_qdisc *qdisc) /** @} */ -static struct rtnl_qdisc_ops sfq_ops = { - .qo_kind = "sfq", - .qo_msg_parser = sfq_msg_parser, - .qo_free_data = sfq_free_data, - .qo_dump = { +static struct rtnl_tc_ops sfq_ops = { + .to_kind = "sfq", + .to_type = RTNL_TC_TYPE_QDISC, + .to_size = sizeof(struct rtnl_sfq), + .to_msg_parser = sfq_msg_parser, + .to_dump = { [NL_DUMP_LINE] = sfq_dump_line, [NL_DUMP_DETAILS] = sfq_dump_details, }, - .qo_get_opts = sfq_get_opts, + .to_msg_fill = sfq_msg_fill, }; static void __init sfq_init(void) { - rtnl_qdisc_register(&sfq_ops); + rtnl_tc_register(&sfq_ops); } static void __exit sfq_exit(void) { - rtnl_qdisc_unregister(&sfq_ops); + rtnl_tc_unregister(&sfq_ops); } /** @} */ diff --git a/lib/route/sch/tbf.c b/lib/route/sch/tbf.c index c61810e..8e76a5b 100644 --- a/lib/route/sch/tbf.c +++ b/lib/route/sch/tbf.c @@ -6,12 +6,12 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2010 Thomas Graf + * Copyright (c) 2003-2011 Thomas Graf */ /** - * @ingroup qdisc_api - * @defgroup tbf Token Bucket Filter (TBF) + * @ingroup qdisc + * @defgroup qdisc_tbf Token Bucket Filter (TBF) * @{ */ @@ -20,11 +20,9 @@ #include #include #include -#include +#include #include -#include #include -#include #include #include @@ -34,37 +32,19 @@ #define TBF_ATTR_PEAKRATE 0x10 /** @endcond */ -static inline struct rtnl_tbf *tbf_qdisc(struct rtnl_qdisc *qdisc) -{ - return (struct rtnl_tbf *) qdisc->q_subdata; -} - -static inline struct rtnl_tbf *tbf_alloc(struct rtnl_qdisc *qdisc) -{ - if (!qdisc->q_subdata) - qdisc->q_subdata = calloc(1, sizeof(struct rtnl_tbf)); - - return tbf_qdisc(qdisc); -} - static struct nla_policy tbf_policy[TCA_TBF_MAX+1] = { [TCA_TBF_PARMS] = { .minlen = sizeof(struct tc_tbf_qopt) }, }; -static int tbf_msg_parser(struct rtnl_qdisc *q) +static int tbf_msg_parser(struct rtnl_tc *tc, void *data) { - int err; struct nlattr *tb[TCA_TBF_MAX + 1]; - struct rtnl_tbf *tbf; + struct rtnl_tbf *tbf = data; + int err; - err = tca_parse(tb, TCA_TBF_MAX, (struct rtnl_tc *) q, tbf_policy); - if (err < 0) + if ((err = tca_parse(tb, TCA_TBF_MAX, tc, tbf_policy)) < 0) return err; - tbf = tbf_alloc(q); - if (!tbf) - return -NLE_NOMEM; - if (tb[TCA_TBF_PARMS]) { struct tc_tbf_qopt opts; int bufsize; @@ -84,8 +64,8 @@ static int tbf_msg_parser(struct rtnl_qdisc *q) opts.peakrate.rate); tbf->qt_peakrate_bucket = bufsize; - rtnl_tc_set_mpu((struct rtnl_tc *) q, tbf->qt_rate.rs_mpu); - rtnl_tc_set_overhead((struct rtnl_tc *) q, tbf->qt_rate.rs_overhead); + rtnl_tc_set_mpu(tc, tbf->qt_rate.rs_mpu); + rtnl_tc_set_overhead(tc, tbf->qt_rate.rs_overhead); tbf->qt_mask = (TBF_ATTR_LIMIT | TBF_ATTR_RATE | TBF_ATTR_PEAKRATE); } @@ -93,16 +73,12 @@ static int tbf_msg_parser(struct rtnl_qdisc *q) return 0; } -static void tbf_free_data(struct rtnl_qdisc *qdisc) -{ - free(qdisc->q_subdata); -} - -static void tbf_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p) +static void tbf_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) { double r, rbit, lim; char *ru, *rubit, *limu; - struct rtnl_tbf *tbf = tbf_qdisc(qdisc); + struct rtnl_tbf *tbf = data; if (!tbf) return; @@ -115,9 +91,10 @@ static void tbf_dump_line(struct rtnl_qdisc *qdisc, struct nl_dump_params *p) r, ru, rbit, rubit, lim, limu); } -static void tbf_dump_details(struct rtnl_qdisc *qdisc, struct nl_dump_params *p) +static void tbf_dump_details(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) { - struct rtnl_tbf *tbf = tbf_qdisc(qdisc); + struct rtnl_tbf *tbf = data; if (!tbf) return; @@ -151,51 +128,40 @@ static void tbf_dump_details(struct rtnl_qdisc *qdisc, struct nl_dump_params *p) } } -static struct nl_msg *tbf_get_opts(struct rtnl_qdisc *qdisc) +static int tbf_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) { - struct tc_tbf_qopt opts; - struct rtnl_tbf *tbf; - struct nl_msg *msg; uint32_t rtab[RTNL_TC_RTABLE_SIZE], ptab[RTNL_TC_RTABLE_SIZE]; + struct tc_tbf_qopt opts; + struct rtnl_tbf *tbf = data; int required = TBF_ATTR_RATE | TBF_ATTR_LIMIT; - memset(&opts, 0, sizeof(opts)); - - tbf = tbf_qdisc(qdisc); - if (!tbf) - return NULL; - if (!(tbf->qt_mask & required) != required) - return NULL; + return -NLE_MISSING_ATTR; + memset(&opts, 0, sizeof(opts)); opts.limit = tbf->qt_limit; opts.buffer = tbf->qt_rate_txtime; - rtnl_tc_build_rate_table((struct rtnl_tc *) qdisc, &tbf->qt_rate, rtab); + rtnl_tc_build_rate_table(tc, &tbf->qt_rate, rtab); rtnl_rcopy_ratespec(&opts.rate, &tbf->qt_rate); if (tbf->qt_mask & TBF_ATTR_PEAKRATE) { opts.mtu = tbf->qt_peakrate_txtime; - rtnl_tc_build_rate_table((struct rtnl_tc *) qdisc, &tbf->qt_peakrate, ptab); + rtnl_tc_build_rate_table(tc, &tbf->qt_peakrate, ptab); rtnl_rcopy_ratespec(&opts.peakrate, &tbf->qt_peakrate); } - msg = nlmsg_alloc(); - if (!msg) - goto nla_put_failure; - NLA_PUT(msg, TCA_TBF_PARMS, sizeof(opts), &opts); NLA_PUT(msg, TCA_TBF_RTAB, sizeof(rtab), rtab); if (tbf->qt_mask & TBF_ATTR_PEAKRATE) NLA_PUT(msg, TCA_TBF_PTAB, sizeof(ptab), ptab); - return msg; + return 0; nla_put_failure: - nlmsg_free(msg); - return NULL; + return -NLE_MSGSIZE; } /** @@ -209,18 +175,15 @@ nla_put_failure: * @arg limit New limit in bytes. * @return 0 on success or a negative error code. */ -int rtnl_qdisc_tbf_set_limit(struct rtnl_qdisc *qdisc, int limit) +void rtnl_qdisc_tbf_set_limit(struct rtnl_qdisc *qdisc, int limit) { struct rtnl_tbf *tbf; - tbf = tbf_alloc(qdisc); - if (!tbf) - return -NLE_NOMEM; + if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); tbf->qt_limit = limit; tbf->qt_mask |= TBF_ATTR_LIMIT; - - return 0; } static inline double calc_limit(struct rtnl_ratespec *spec, int latency, @@ -257,9 +220,8 @@ int rtnl_qdisc_tbf_set_limit_by_latency(struct rtnl_qdisc *qdisc, int latency) struct rtnl_tbf *tbf; double limit, limit2; - tbf = tbf_alloc(qdisc); - if (!tbf) - return -NLE_NOMEM; + if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); if (!(tbf->qt_mask & TBF_ATTR_RATE)) return -NLE_MISSING_ATTR; @@ -274,7 +236,9 @@ int rtnl_qdisc_tbf_set_limit_by_latency(struct rtnl_qdisc *qdisc, int latency) limit = limit2; } - return rtnl_qdisc_tbf_set_limit(qdisc, (int) limit); + rtnl_qdisc_tbf_set_limit(qdisc, (int) limit); + + return 0; } /** @@ -286,8 +250,10 @@ int rtnl_qdisc_tbf_get_limit(struct rtnl_qdisc *qdisc) { struct rtnl_tbf *tbf; - tbf = tbf_qdisc(qdisc); - if (tbf && (tbf->qt_mask & TBF_ATTR_LIMIT)) + if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (tbf->qt_mask & TBF_ATTR_LIMIT) return tbf->qt_limit; else return -NLE_NOATTR; @@ -307,15 +273,14 @@ static inline int calc_cell_log(int cell, int bucket) * @arg cell Size of a rate cell or 0 to get default value. * @return 0 on success or a negative error code. */ -int rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc *qdisc, int rate, int bucket, +void rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc *qdisc, int rate, int bucket, int cell) { struct rtnl_tbf *tbf; int cell_log; - tbf = tbf_alloc(qdisc); - if (!tbf) - return -NLE_NOMEM; + if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); if (!cell) cell_log = UINT8_MAX; @@ -327,8 +292,6 @@ int rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc *qdisc, int rate, int bucket, tbf->qt_rate.rs_cell_log = cell_log; tbf->qt_rate_txtime = rtnl_tc_calc_txtime(bucket, rate); tbf->qt_mask |= TBF_ATTR_RATE; - - return 0; } /** @@ -340,8 +303,10 @@ int rtnl_qdisc_tbf_get_rate(struct rtnl_qdisc *qdisc) { struct rtnl_tbf *tbf; - tbf = tbf_qdisc(qdisc); - if (tbf && (tbf->qt_mask & TBF_ATTR_RATE)) + if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (tbf->qt_mask & TBF_ATTR_RATE) return tbf->qt_rate.rs_rate; else return -1; @@ -356,8 +321,10 @@ int rtnl_qdisc_tbf_get_rate_bucket(struct rtnl_qdisc *qdisc) { struct rtnl_tbf *tbf; - tbf = tbf_qdisc(qdisc); - if (tbf && (tbf->qt_mask & TBF_ATTR_RATE)) + if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (tbf->qt_mask & TBF_ATTR_RATE) return tbf->qt_rate_bucket; else return -1; @@ -372,8 +339,10 @@ int rtnl_qdisc_tbf_get_rate_cell(struct rtnl_qdisc *qdisc) { struct rtnl_tbf *tbf; - tbf = tbf_qdisc(qdisc); - if (tbf && (tbf->qt_mask & TBF_ATTR_RATE)) + if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (tbf->qt_mask & TBF_ATTR_RATE) return (1 << tbf->qt_rate.rs_cell_log); else return -1; @@ -393,9 +362,8 @@ int rtnl_qdisc_tbf_set_peakrate(struct rtnl_qdisc *qdisc, int rate, int bucket, struct rtnl_tbf *tbf; int cell_log; - tbf = tbf_alloc(qdisc); - if (!tbf) - return -NLE_NOMEM; + if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); cell_log = calc_cell_log(cell, bucket); if (cell_log < 0) @@ -420,8 +388,10 @@ int rtnl_qdisc_tbf_get_peakrate(struct rtnl_qdisc *qdisc) { struct rtnl_tbf *tbf; - tbf = tbf_qdisc(qdisc); - if (tbf && (tbf->qt_mask & TBF_ATTR_PEAKRATE)) + if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (tbf->qt_mask & TBF_ATTR_PEAKRATE) return tbf->qt_peakrate.rs_rate; else return -1; @@ -436,8 +406,10 @@ int rtnl_qdisc_tbf_get_peakrate_bucket(struct rtnl_qdisc *qdisc) { struct rtnl_tbf *tbf; - tbf = tbf_qdisc(qdisc); - if (tbf && (tbf->qt_mask & TBF_ATTR_PEAKRATE)) + if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (tbf->qt_mask & TBF_ATTR_PEAKRATE) return tbf->qt_peakrate_bucket; else return -1; @@ -452,8 +424,10 @@ int rtnl_qdisc_tbf_get_peakrate_cell(struct rtnl_qdisc *qdisc) { struct rtnl_tbf *tbf; - tbf = tbf_qdisc(qdisc); - if (tbf && (tbf->qt_mask & TBF_ATTR_PEAKRATE)) + if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (tbf->qt_mask & TBF_ATTR_PEAKRATE) return (1 << tbf->qt_peakrate.rs_cell_log); else return -1; @@ -461,25 +435,26 @@ int rtnl_qdisc_tbf_get_peakrate_cell(struct rtnl_qdisc *qdisc) /** @} */ -static struct rtnl_qdisc_ops tbf_qdisc_ops = { - .qo_kind = "tbf", - .qo_msg_parser = tbf_msg_parser, - .qo_dump = { +static struct rtnl_tc_ops tbf_tc_ops = { + .to_kind = "tbf", + .to_type = RTNL_TC_TYPE_QDISC, + .to_size = sizeof(struct rtnl_tbf), + .to_msg_parser = tbf_msg_parser, + .to_dump = { [NL_DUMP_LINE] = tbf_dump_line, [NL_DUMP_DETAILS] = tbf_dump_details, }, - .qo_free_data = tbf_free_data, - .qo_get_opts = tbf_get_opts, + .to_msg_fill = tbf_msg_fill, }; static void __init tbf_init(void) { - rtnl_qdisc_register(&tbf_qdisc_ops); + rtnl_tc_register(&tbf_tc_ops); } static void __exit tbf_exit(void) { - rtnl_qdisc_unregister(&tbf_qdisc_ops); + rtnl_tc_unregister(&tbf_tc_ops); } /** @} */ diff --git a/lib/route/tc.c b/lib/route/tc.c index 6a0233a..e4faf92 100644 --- a/lib/route/tc.c +++ b/lib/route/tc.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2003-2010 Thomas Graf + * Copyright (c) 2003-2011 Thomas Graf */ /** @@ -22,9 +22,13 @@ #include #include #include +#include /** @cond SKIP */ +static struct nl_list_head tc_ops_list[__RTNL_TC_TYPE_MAX]; +static struct rtnl_tc_type_ops *tc_type_ops[__RTNL_TC_TYPE_MAX]; + static struct nla_policy tc_policy[TCA_MAX+1] = { [TCA_KIND] = { .type = NLA_STRING, .maxlen = TCKINDSIZ }, @@ -54,12 +58,16 @@ static struct nla_policy tc_stats2_policy[TCA_STATS_MAX+1] = { [TCA_STATS_QUEUE] = { .minlen = sizeof(struct gnet_stats_queue) }, }; -int tca_msg_parser(struct nlmsghdr *n, struct rtnl_tc *g) +int rtnl_tc_msg_parse(struct nlmsghdr *n, struct rtnl_tc *tc) { + struct rtnl_tc_ops *ops; struct nlattr *tb[TCA_MAX + 1]; + char kind[TCKINDSIZ]; struct tcmsg *tm; int err; + tc->ce_msgtype = n->nlmsg_type; + err = nlmsg_parse(n, sizeof(*tm), tb, TCA_MAX, tc_policy); if (err < 0) return err; @@ -67,25 +75,25 @@ int tca_msg_parser(struct nlmsghdr *n, struct rtnl_tc *g) if (tb[TCA_KIND] == NULL) return -NLE_MISSING_ATTR; - nla_strlcpy(g->tc_kind, tb[TCA_KIND], TCKINDSIZ); + nla_strlcpy(kind, tb[TCA_KIND], sizeof(kind)); + rtnl_tc_set_kind(tc, kind); tm = nlmsg_data(n); - g->tc_family = tm->tcm_family; - g->tc_ifindex = tm->tcm_ifindex; - g->tc_handle = tm->tcm_handle; - g->tc_parent = tm->tcm_parent; - g->tc_info = tm->tcm_info; + tc->tc_family = tm->tcm_family; + tc->tc_ifindex = tm->tcm_ifindex; + tc->tc_handle = tm->tcm_handle; + tc->tc_parent = tm->tcm_parent; + tc->tc_info = tm->tcm_info; - g->ce_mask = (TCA_ATTR_FAMILY | TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE | - TCA_ATTR_PARENT | TCA_ATTR_INFO | TCA_ATTR_KIND); + tc->ce_mask |= (TCA_ATTR_FAMILY | TCA_ATTR_IFINDEX | TCA_ATTR_HANDLE| + TCA_ATTR_PARENT | TCA_ATTR_INFO); if (tb[TCA_OPTIONS]) { - g->tc_opts = nl_data_alloc_attr(tb[TCA_OPTIONS]); - if (!g->tc_opts) + tc->tc_opts = nl_data_alloc_attr(tb[TCA_OPTIONS]); + if (!tc->tc_opts) return -NLE_NOMEM; - g->ce_mask |= TCA_ATTR_OPTS; + tc->ce_mask |= TCA_ATTR_OPTS; } - if (tb[TCA_STATS2]) { struct nlattr *tbs[TCA_STATS_MAX + 1]; @@ -99,34 +107,34 @@ int tca_msg_parser(struct nlmsghdr *n, struct rtnl_tc *g) struct gnet_stats_basic *bs; bs = nla_data(tbs[TCA_STATS_BASIC]); - g->tc_stats[RTNL_TC_BYTES] = bs->bytes; - g->tc_stats[RTNL_TC_PACKETS] = bs->packets; + tc->tc_stats[RTNL_TC_BYTES] = bs->bytes; + tc->tc_stats[RTNL_TC_PACKETS] = bs->packets; } if (tbs[TCA_STATS_RATE_EST]) { struct gnet_stats_rate_est *re; re = nla_data(tbs[TCA_STATS_RATE_EST]); - g->tc_stats[RTNL_TC_RATE_BPS] = re->bps; - g->tc_stats[RTNL_TC_RATE_PPS] = re->pps; + tc->tc_stats[RTNL_TC_RATE_BPS] = re->bps; + tc->tc_stats[RTNL_TC_RATE_PPS] = re->pps; } if (tbs[TCA_STATS_QUEUE]) { struct gnet_stats_queue *q; q = nla_data(tbs[TCA_STATS_QUEUE]); - g->tc_stats[RTNL_TC_QLEN] = q->qlen; - g->tc_stats[RTNL_TC_BACKLOG] = q->backlog; - g->tc_stats[RTNL_TC_DROPS] = q->drops; - g->tc_stats[RTNL_TC_REQUEUES] = q->requeues; - g->tc_stats[RTNL_TC_OVERLIMITS] = q->overlimits; + tc->tc_stats[RTNL_TC_QLEN] = q->qlen; + tc->tc_stats[RTNL_TC_BACKLOG] = q->backlog; + tc->tc_stats[RTNL_TC_DROPS] = q->drops; + tc->tc_stats[RTNL_TC_REQUEUES] = q->requeues; + tc->tc_stats[RTNL_TC_OVERLIMITS] = q->overlimits; } - g->ce_mask |= TCA_ATTR_STATS; + tc->ce_mask |= TCA_ATTR_STATS; if (tbs[TCA_STATS_APP]) { - g->tc_xstats = nl_data_alloc_attr(tbs[TCA_STATS_APP]); - if (g->tc_xstats == NULL) + tc->tc_xstats = nl_data_alloc_attr(tbs[TCA_STATS_APP]); + if (tc->tc_xstats == NULL) return -NLE_NOMEM; } else goto compat_xstats; @@ -134,159 +142,54 @@ int tca_msg_parser(struct nlmsghdr *n, struct rtnl_tc *g) if (tb[TCA_STATS]) { struct tc_stats *st = nla_data(tb[TCA_STATS]); - g->tc_stats[RTNL_TC_BYTES] = st->bytes; - g->tc_stats[RTNL_TC_PACKETS] = st->packets; - g->tc_stats[RTNL_TC_RATE_BPS] = st->bps; - g->tc_stats[RTNL_TC_RATE_PPS] = st->pps; - g->tc_stats[RTNL_TC_QLEN] = st->qlen; - g->tc_stats[RTNL_TC_BACKLOG] = st->backlog; - g->tc_stats[RTNL_TC_DROPS] = st->drops; - g->tc_stats[RTNL_TC_OVERLIMITS] = st->overlimits; + tc->tc_stats[RTNL_TC_BYTES] = st->bytes; + tc->tc_stats[RTNL_TC_PACKETS] = st->packets; + tc->tc_stats[RTNL_TC_RATE_BPS] = st->bps; + tc->tc_stats[RTNL_TC_RATE_PPS] = st->pps; + tc->tc_stats[RTNL_TC_QLEN] = st->qlen; + tc->tc_stats[RTNL_TC_BACKLOG] = st->backlog; + tc->tc_stats[RTNL_TC_DROPS] = st->drops; + tc->tc_stats[RTNL_TC_OVERLIMITS]= st->overlimits; - g->ce_mask |= TCA_ATTR_STATS; + tc->ce_mask |= TCA_ATTR_STATS; } compat_xstats: if (tb[TCA_XSTATS]) { - g->tc_xstats = nl_data_alloc_attr(tb[TCA_XSTATS]); - if (g->tc_xstats == NULL) + tc->tc_xstats = nl_data_alloc_attr(tb[TCA_XSTATS]); + if (tc->tc_xstats == NULL) return -NLE_NOMEM; - g->ce_mask |= TCA_ATTR_XSTATS; + tc->ce_mask |= TCA_ATTR_XSTATS; } } + ops = rtnl_tc_get_ops(tc); + if (ops && ops->to_msg_parser) { + void *data = rtnl_tc_data(tc); - return 0; -} - -void tca_free_data(struct rtnl_tc *tca) -{ - rtnl_link_put(tca->tc_link); - nl_data_free(tca->tc_opts); - nl_data_free(tca->tc_xstats); -} - -int tca_clone(struct rtnl_tc *dst, struct rtnl_tc *src) -{ - if (src->tc_link) { - dst->tc_link = (struct rtnl_link *) - nl_object_clone(OBJ_CAST(src->tc_link)); - if (!dst->tc_link) + if (!data) return -NLE_NOMEM; - } - if (src->tc_opts) { - dst->tc_opts = nl_data_clone(src->tc_opts); - if (!dst->tc_opts) - return -NLE_NOMEM; - } - - if (src->tc_xstats) { - dst->tc_xstats = nl_data_clone(src->tc_xstats); - if (!dst->tc_xstats) - return -NLE_NOMEM; + err = ops->to_msg_parser(tc, data); + if (err < 0) + return err; } return 0; } -void tca_dump_line(struct rtnl_tc *g, const char *type, - struct nl_dump_params *p) -{ - char handle[32], parent[32]; - struct nl_cache *link_cache; - - link_cache = nl_cache_mngt_require("route/link"); - - nl_dump_line(p, "%s %s ", type, g->tc_kind); - - if (link_cache) { - char buf[32]; - nl_dump(p, "dev %s ", - rtnl_link_i2name(link_cache, g->tc_ifindex, - buf, sizeof(buf))); - } else - nl_dump(p, "dev %u ", g->tc_ifindex); - - nl_dump(p, "id %s parent %s", - rtnl_tc_handle2str(g->tc_handle, handle, sizeof(handle)), - rtnl_tc_handle2str(g->tc_parent, parent, sizeof(parent))); -} - -void tca_dump_details(struct rtnl_tc *tc, struct nl_dump_params *p) -{ - nl_dump_line(p, " "); - - if (tc->ce_mask & TCA_ATTR_MTU) - nl_dump(p, " mtu %u", tc->tc_mtu); - - if (tc->ce_mask & TCA_ATTR_MPU) - nl_dump(p, " mput %u", tc->tc_mpu); - - if (tc->ce_mask & TCA_ATTR_OVERHEAD) - nl_dump(p, " overhead %u", tc->tc_overhead); -} - -void tca_dump_stats(struct rtnl_tc *g, struct nl_dump_params *p) -{ - char *unit, fmt[64]; - float res; - strcpy(fmt, " %7.2f %s %10u %10u %10u %10u %10u\n"); - - nl_dump_line(p, - " Stats: bytes packets drops overlimits" \ - " qlen backlog\n"); - - res = nl_cancel_down_bytes(g->tc_stats[RTNL_TC_BYTES], &unit); - if (*unit == 'B') - fmt[11] = '9'; - - nl_dump_line(p, fmt, res, unit, - g->tc_stats[RTNL_TC_PACKETS], - g->tc_stats[RTNL_TC_DROPS], - g->tc_stats[RTNL_TC_OVERLIMITS], - g->tc_stats[RTNL_TC_QLEN], - g->tc_stats[RTNL_TC_BACKLOG]); - - res = nl_cancel_down_bytes(g->tc_stats[RTNL_TC_RATE_BPS], &unit); - - strcpy(fmt, " %7.2f %s/s%9u pps"); - - if (*unit == 'B') - fmt[11] = '9'; - - nl_dump_line(p, fmt, res, unit, g->tc_stats[RTNL_TC_RATE_PPS]); -} - -int tca_compare(struct nl_object *_a, struct nl_object *_b, - uint32_t attrs, int flags) -{ - struct rtnl_tc *a = (struct rtnl_tc *) _a; - struct rtnl_tc *b = (struct rtnl_tc *) _b; - int diff = 0; - -#define TC_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, TCA_ATTR_##ATTR, a, b, EXPR) - - diff |= TC_DIFF(HANDLE, a->tc_handle != b->tc_handle); - diff |= TC_DIFF(PARENT, a->tc_parent != b->tc_parent); - diff |= TC_DIFF(IFINDEX, a->tc_ifindex != b->tc_ifindex); - diff |= TC_DIFF(KIND, strcmp(a->tc_kind, b->tc_kind)); - -#undef TC_DIFF - - return diff; -} - -int tca_build_msg(struct rtnl_tc *tca, int type, int flags, - struct nl_msg **result) +int rtnl_tc_msg_build(struct rtnl_tc *tc, int type, int flags, + struct nl_msg **result) { struct nl_msg *msg; + struct rtnl_tc_ops *ops; struct tcmsg tchdr = { .tcm_family = AF_UNSPEC, - .tcm_ifindex = tca->tc_ifindex, - .tcm_handle = tca->tc_handle, - .tcm_parent = tca->tc_parent, + .tcm_ifindex = tc->tc_ifindex, + .tcm_handle = tc->tc_handle, + .tcm_parent = tc->tc_parent, }; + int err = -NLE_MSGSIZE; msg = nlmsg_alloc_simple(type, flags); if (!msg) @@ -295,15 +198,29 @@ int tca_build_msg(struct rtnl_tc *tca, int type, int flags, if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0) goto nla_put_failure; - if (tca->ce_mask & TCA_ATTR_KIND) - NLA_PUT_STRING(msg, TCA_KIND, tca->tc_kind); + if (tc->ce_mask & TCA_ATTR_KIND) + NLA_PUT_STRING(msg, TCA_KIND, tc->tc_kind); + + ops = rtnl_tc_get_ops(tc); + if (ops && ops->to_msg_fill) { + struct nlattr *opts; + void *data = rtnl_tc_data(tc); + + if (!(opts = nla_nest_start(msg, TCA_OPTIONS))) + goto nla_put_failure; + + if ((err = ops->to_msg_fill(tc, data, msg)) < 0) + goto nla_put_failure; + + nla_nest_end(msg, opts); + } *result = msg; return 0; nla_put_failure: nlmsg_free(msg); - return -NLE_MSGSIZE; + return err; } void tca_set_kind(struct rtnl_tc *t, const char *kind) @@ -546,6 +463,27 @@ uint32_t rtnl_tc_get_parent(struct rtnl_tc *tc) return tc->tc_parent; } +/** + * Define the type of traffic control object + * @arg tc traffic control object + * @arg kind name of the tc object type + * + * @return 0 on success or a negative error code + */ +int rtnl_tc_set_kind(struct rtnl_tc *tc, const char *kind) +{ + if (tc->ce_mask & TCA_ATTR_KIND) + return -NLE_EXIST; + + strncpy(tc->tc_kind, kind, sizeof(tc->tc_kind) - 1); + tc->ce_mask |= TCA_ATTR_KIND; + + /* Force allocation of data */ + rtnl_tc_data(tc); + + return 0; +} + /** * Return kind of traffic control object * @arg tc traffic control object @@ -567,7 +505,7 @@ char *rtnl_tc_get_kind(struct rtnl_tc *tc) * * @return Value of requested statistic counter or 0. */ -uint64_t rtnl_tc_get_stat(struct rtnl_tc *tc, int id) +uint64_t rtnl_tc_get_stat(struct rtnl_tc *tc, enum rtnl_tc_stat id) { if (id < 0 || id > RTNL_TC_STATS_MAX) return 0; @@ -745,5 +683,312 @@ int rtnl_tc_build_rate_table(struct rtnl_tc *tc, struct rtnl_ratespec *spec, /** @} */ +/** + * @name TC implementation of cache functions + */ + +void rtnl_tc_free_data(struct nl_object *obj) +{ + struct rtnl_tc *tc = TC_CAST(obj); + struct rtnl_tc_ops *ops; + + rtnl_link_put(tc->tc_link); + nl_data_free(tc->tc_opts); + nl_data_free(tc->tc_xstats); + + if (tc->tc_subdata) { + ops = rtnl_tc_get_ops(tc); + if (ops && ops->to_free_data) + ops->to_free_data(tc, nl_data_get(tc->tc_subdata)); + + nl_data_free(tc->tc_subdata); + } +} + +int rtnl_tc_clone(struct nl_object *dstobj, struct nl_object *srcobj) +{ + struct rtnl_tc *dst = TC_CAST(dstobj); + struct rtnl_tc *src = TC_CAST(srcobj); + struct rtnl_tc_ops *ops; + + if (src->tc_link) { + dst->tc_link = (struct rtnl_link *) + nl_object_clone(OBJ_CAST(src->tc_link)); + if (!dst->tc_link) + return -NLE_NOMEM; + } + + if (src->tc_opts) { + dst->tc_opts = nl_data_clone(src->tc_opts); + if (!dst->tc_opts) + return -NLE_NOMEM; + } + + if (src->tc_xstats) { + dst->tc_xstats = nl_data_clone(src->tc_xstats); + if (!dst->tc_xstats) + return -NLE_NOMEM; + } + + if (src->tc_subdata) { + if (!(dst->tc_subdata = nl_data_clone(src->tc_subdata))) { + return -NLE_NOMEM; + } + } + + ops = rtnl_tc_get_ops(src); + if (ops && ops->to_clone) { + void *a = rtnl_tc_data(dst), *b = rtnl_tc_data(src); + + if (!a) + return 0; + else if (!b) + return -NLE_NOMEM; + + return ops->to_clone(a, b); + } + + return 0; +} + +static int tc_dump(struct rtnl_tc *tc, enum nl_dump_type type, + struct nl_dump_params *p) +{ + struct rtnl_tc_type_ops *type_ops; + struct rtnl_tc_ops *ops; + void *data = rtnl_tc_data(tc); + + type_ops = tc_type_ops[tc->tc_type]; + if (type_ops && type_ops->tt_dump[type]) + type_ops->tt_dump[type](tc, p); + + ops = rtnl_tc_get_ops(tc); + if (ops && ops->to_dump[type]) { + ops->to_dump[type](tc, data, p); + return 1; + } + + return 0; +} + +void rtnl_tc_dump_line(struct nl_object *obj, struct nl_dump_params *p) +{ + struct rtnl_tc_type_ops *type_ops; + struct rtnl_tc *tc = TC_CAST(obj); + struct nl_cache *link_cache; + char buf[32]; + + nl_new_line(p); + + type_ops = tc_type_ops[tc->tc_type]; + if (type_ops && type_ops->tt_dump_prefix) + nl_dump(p, "%s ", type_ops->tt_dump_prefix); + + nl_dump(p, "%s ", tc->tc_kind); + + if ((link_cache = nl_cache_mngt_require("route/link"))) { + nl_dump(p, "dev %s ", + rtnl_link_i2name(link_cache, tc->tc_ifindex, + buf, sizeof(buf))); + } else + nl_dump(p, "dev %u ", tc->tc_ifindex); + + nl_dump(p, "id %s ", + rtnl_tc_handle2str(tc->tc_handle, buf, sizeof(buf))); + + nl_dump(p, "parent %s", + rtnl_tc_handle2str(tc->tc_parent, buf, sizeof(buf))); + + tc_dump(tc, NL_DUMP_LINE, p); + nl_dump(p, "\n"); +} + +void rtnl_tc_dump_details(struct nl_object *obj, struct nl_dump_params *p) +{ + struct rtnl_tc *tc = TC_CAST(obj); + + rtnl_tc_dump_line(OBJ_CAST(tc), p); + + nl_dump_line(p, " "); + + if (tc->ce_mask & TCA_ATTR_MTU) + nl_dump(p, " mtu %u", tc->tc_mtu); + + if (tc->ce_mask & TCA_ATTR_MPU) + nl_dump(p, " mpu %u", tc->tc_mpu); + + if (tc->ce_mask & TCA_ATTR_OVERHEAD) + nl_dump(p, " overhead %u", tc->tc_overhead); + + if (!tc_dump(tc, NL_DUMP_DETAILS, p)) + nl_dump(p, "no options"); + nl_dump(p, "\n"); +} + +void rtnl_tc_dump_stats(struct nl_object *obj, struct nl_dump_params *p) +{ + struct rtnl_tc *tc = TC_CAST(obj); + char *unit, fmt[64]; + float res; + + rtnl_tc_dump_details(OBJ_CAST(tc), p); + + strcpy(fmt, " %7.2f %s %10u %10u %10u %10u %10u\n"); + + nl_dump_line(p, + " Stats: bytes packets drops overlimits" \ + " qlen backlog\n"); + + res = nl_cancel_down_bytes(tc->tc_stats[RTNL_TC_BYTES], &unit); + if (*unit == 'B') + fmt[11] = '9'; + + nl_dump_line(p, fmt, res, unit, + tc->tc_stats[RTNL_TC_PACKETS], + tc->tc_stats[RTNL_TC_DROPS], + tc->tc_stats[RTNL_TC_OVERLIMITS], + tc->tc_stats[RTNL_TC_QLEN], + tc->tc_stats[RTNL_TC_BACKLOG]); + + res = nl_cancel_down_bytes(tc->tc_stats[RTNL_TC_RATE_BPS], &unit); + + strcpy(fmt, " %7.2f %s/s%9u pps"); + + if (*unit == 'B') + fmt[11] = '9'; + + nl_dump_line(p, fmt, res, unit, tc->tc_stats[RTNL_TC_RATE_PPS]); + + tc_dump(tc, NL_DUMP_LINE, p); + nl_dump(p, "\n"); +} + +int rtnl_tc_compare(struct nl_object *aobj, struct nl_object *bobj, + uint32_t attrs, int flags) +{ + struct rtnl_tc *a = TC_CAST(aobj); + struct rtnl_tc *b = TC_CAST(bobj); + int diff = 0; + +#define TC_DIFF(ATTR, EXPR) ATTR_DIFF(attrs, TCA_ATTR_##ATTR, a, b, EXPR) + + diff |= TC_DIFF(HANDLE, a->tc_handle != b->tc_handle); + diff |= TC_DIFF(PARENT, a->tc_parent != b->tc_parent); + diff |= TC_DIFF(IFINDEX, a->tc_ifindex != b->tc_ifindex); + diff |= TC_DIFF(KIND, strcmp(a->tc_kind, b->tc_kind)); + +#undef TC_DIFF + + return diff; +} + +/** @} */ + +/** + * @name Modules API + */ + +struct rtnl_tc_ops *rtnl_tc_lookup_ops(enum rtnl_tc_type type, const char *kind) +{ + struct rtnl_tc_ops *ops; + + nl_list_for_each_entry(ops, &tc_ops_list[type], to_list) + if (!strcmp(kind, ops->to_kind)) + return ops; + + return NULL; +} + +struct rtnl_tc_ops *rtnl_tc_get_ops(struct rtnl_tc *tc) +{ + if (!tc->tc_ops) + tc->tc_ops = rtnl_tc_lookup_ops(tc->tc_type, tc->tc_kind); + + return tc->tc_ops; +} + +/** + * Register a traffic control module + * @arg ops traffic control module operations + */ +int rtnl_tc_register(struct rtnl_tc_ops *ops) +{ + static int init = 0; + + /* + * Initialiation hack, make sure list is initialized when + * the first tc module registers. Putting this in a + * separate __init would required correct ordering of init + * functions + */ + if (!init) { + int i; + + for (i = 0; i < __RTNL_TC_TYPE_MAX; i++) + nl_init_list_head(&tc_ops_list[i]); + + init = 1; + } + + if (!ops->to_kind || ops->to_type > RTNL_TC_TYPE_MAX) + BUG(); + + if (rtnl_tc_lookup_ops(ops->to_type, ops->to_kind)) + return -NLE_EXIST; + + nl_list_add_tail(&ops->to_list, &tc_ops_list[ops->to_type]); + + return 0; +} + +/** + * Unregister a traffic control module + * @arg ops traffic control module operations + */ +void rtnl_tc_unregister(struct rtnl_tc_ops *ops) +{ + nl_list_del(&ops->to_list); +} + +void *rtnl_tc_data(struct rtnl_tc *tc) +{ + if (!tc->tc_subdata) { + size_t size; + + if (!tc->tc_ops) { + if (!tc->tc_kind) + BUG(); + + if (!rtnl_tc_get_ops(tc)) + return NULL; + } + + if (!(size = tc->tc_ops->to_size)) + BUG(); + + if (!(tc->tc_subdata = nl_data_alloc(NULL, size))) + return NULL; + } + + return nl_data_get(tc->tc_subdata); +} + +void rtnl_tc_type_register(struct rtnl_tc_type_ops *ops) +{ + if (ops->tt_type > RTNL_TC_TYPE_MAX) + BUG(); + + tc_type_ops[ops->tt_type] = ops; +} + +void rtnl_tc_type_unregister(struct rtnl_tc_type_ops *ops) +{ + if (ops->tt_type > RTNL_TC_TYPE_MAX) + BUG(); + + tc_type_ops[ops->tt_type] = NULL; +} + +/** @} */ /** @} */ diff --git a/src/lib/class.c b/src/lib/class.c index c6b5525..96f60cd 100644 --- a/src/lib/class.c +++ b/src/lib/class.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2010 Thomas Graf + * Copyright (c) 2010-2011 Thomas Graf */ /** @@ -22,8 +22,7 @@ struct rtnl_class *nl_cli_class_alloc(void) { struct rtnl_class *class; - class = rtnl_class_alloc(); - if (!class) + if (!(class = rtnl_class_alloc())) nl_cli_fatal(ENOMEM, "Unable to allocate class object"); return class; @@ -43,9 +42,4 @@ struct nl_cache *nl_cli_class_alloc_cache(struct nl_sock *sock, int ifindex) return cache; } -void nl_cli_class_parse_kind(struct rtnl_class *class, char *arg) -{ - rtnl_class_set_kind(class, arg); -} - /** @} */ diff --git a/src/lib/cls.c b/src/lib/cls.c index 7ada3d6..86d775d 100644 --- a/src/lib/cls.c +++ b/src/lib/cls.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2010 Thomas Graf + * Copyright (c) 2010-2011 Thomas Graf */ /** @@ -23,8 +23,7 @@ struct rtnl_cls *nl_cli_cls_alloc(void) { struct rtnl_cls *cls; - cls = rtnl_cls_alloc(); - if (!cls) + if (!(cls = rtnl_cls_alloc())) nl_cli_fatal(ENOMEM, "Unable to allocate classifier object"); return cls; @@ -43,11 +42,6 @@ struct nl_cache *nl_cli_cls_alloc_cache(struct nl_sock *sock, int ifindex, return cache; } -void nl_cli_cls_parse_kind(struct rtnl_cls *cls, char *arg) -{ - rtnl_cls_set_kind(cls, arg); -} - void nl_cli_cls_parse_proto(struct rtnl_cls *cls, char *arg) { int proto; @@ -74,59 +68,4 @@ struct rtnl_ematch_tree *nl_cli_cls_parse_ematch(struct rtnl_cls *cls, char *arg return tree; } -static NL_LIST_HEAD(cls_modules); - -struct nl_cli_cls_module *__nl_cli_cls_lookup(struct rtnl_cls_ops *ops) -{ - struct nl_cli_cls_module *cm; - - nl_list_for_each_entry(cm, &cls_modules, cm_list) - if (cm->cm_ops == ops) - return cm; - - return NULL; -} - -struct nl_cli_cls_module *nl_cli_cls_lookup(struct rtnl_cls_ops *ops) -{ - struct nl_cli_cls_module *cm; - - if ((cm = __nl_cli_cls_lookup(ops))) - return cm; - - nl_cli_load_module("cli/cls", ops->co_kind); - - if (!(cm = __nl_cli_cls_lookup(ops))) { - nl_cli_fatal(EINVAL, "Application bug: The shared library for " - "the classifier \"%s\" was successfully loaded but it " - "seems that module did not register itself"); - } - - return cm; -} - -void nl_cli_cls_register(struct nl_cli_cls_module *cm) -{ - struct rtnl_cls_ops *ops; - - if (!(ops = __rtnl_cls_lookup_ops(cm->cm_name))) { - nl_cli_fatal(ENOENT, "Unable to register CLI classifier module " - "\"%s\": No matching libnl cls module found.", cm->cm_name); - } - - if (__nl_cli_cls_lookup(ops)) { - nl_cli_fatal(EEXIST, "Unable to register CLI classifier module " - "\"%s\": Module already registered.", cm->cm_name); - } - - cm->cm_ops = ops; - - nl_list_add_tail(&cm->cm_list, &cls_modules); -} - -void nl_cli_cls_unregister(struct nl_cli_cls_module *cm) -{ - nl_list_del(&cm->cm_list); -} - /** @} */ diff --git a/src/lib/qdisc.c b/src/lib/qdisc.c index 4c64e7b..ccf7d26 100644 --- a/src/lib/qdisc.c +++ b/src/lib/qdisc.c @@ -6,7 +6,7 @@ * License as published by the Free Software Foundation version 2.1 * of the License. * - * Copyright (c) 2008-2010 Thomas Graf + * Copyright (c) 2008-2011 Thomas Graf */ /** @@ -18,107 +18,15 @@ #include #include #include -#include struct rtnl_qdisc *nl_cli_qdisc_alloc(void) { struct rtnl_qdisc *qdisc; - qdisc = rtnl_qdisc_alloc(); - if (!qdisc) + if (!(qdisc = rtnl_qdisc_alloc())) nl_cli_fatal(ENOMEM, "Unable to allocate qdisc object"); return qdisc; } -void nl_cli_qdisc_parse_kind(struct rtnl_qdisc *qdisc, char *arg) -{ - rtnl_qdisc_set_kind(qdisc, arg); -} - -static NL_LIST_HEAD(qdisc_modules); - -struct nl_cli_qdisc_module *__nl_cli_qdisc_lookup(struct rtnl_qdisc_ops *ops) -{ - struct nl_cli_qdisc_module *qm; - - nl_list_for_each_entry(qm, &qdisc_modules, qm_list) - if (qm->qm_ops == ops) - return qm; - - return NULL; -} - -struct nl_cli_qdisc_module *__nl_cli_class_lookup(struct rtnl_class_ops *ops) -{ - struct nl_cli_qdisc_module *qm; - - nl_list_for_each_entry(qm, &qdisc_modules, qm_list) - if (qm->qm_class_ops == ops) - return qm; - - return NULL; -} - -struct nl_cli_qdisc_module *nl_cli_qdisc_lookup(struct rtnl_qdisc_ops *ops) -{ - struct nl_cli_qdisc_module *qm; - - if ((qm = __nl_cli_qdisc_lookup(ops))) - return qm; - - nl_cli_load_module("cli/qdisc", ops->qo_kind); - - if (!(qm = __nl_cli_qdisc_lookup(ops))) { - nl_cli_fatal(EINVAL, "Application bug: The shared library for " - "the qdisc \"%s\" was successfully loaded but it " - "seems that module did not register itself"); - } - - return qm; -} - -struct nl_cli_qdisc_module *nl_cli_qdisc_lookup_by_class(struct rtnl_class_ops *ops) -{ - struct nl_cli_qdisc_module *qm; - - if ((qm = __nl_cli_class_lookup(ops))) - return qm; - - nl_cli_load_module("cli/qdisc", ops->co_kind); - - if (!(qm = __nl_cli_class_lookup(ops))) { - nl_cli_fatal(EINVAL, "Application bug: The shared library for " - "the class \"%s\" was successfully loaded but it " - "seems that module did not register itself"); - } - - return qm; -} - -void nl_cli_qdisc_register(struct nl_cli_qdisc_module *qm) -{ - struct rtnl_qdisc_ops *ops; - - if (!(ops = __rtnl_qdisc_lookup_ops(qm->qm_name))) { - nl_cli_fatal(ENOENT, "Unable to register CLI qdisc module " - "\"%s\": No matching libnl qdisc module found.", qm->qm_name); - } - - if (__nl_cli_qdisc_lookup(ops)) { - nl_cli_fatal(EEXIST, "Unable to register CLI qdisc module " - "\"%s\": Module already registered.", qm->qm_name); - } - - qm->qm_ops = ops; - qm->qm_class_ops = __rtnl_class_lookup_ops(qm->qm_name); - - nl_list_add_tail(&qm->qm_list, &qdisc_modules); -} - -void nl_cli_qdisc_unregister(struct nl_cli_qdisc_module *qm) -{ - nl_list_del(&qm->qm_list); -} - /** @} */ diff --git a/src/lib/tc.c b/src/lib/tc.c index 72407cf..8d013f9 100644 --- a/src/lib/tc.c +++ b/src/lib/tc.c @@ -11,7 +11,7 @@ #include #include -#include +#include /** * @ingroup cli @@ -76,6 +76,11 @@ void nl_cli_tc_parse_overhead(struct rtnl_tc *tc, char *arg) rtnl_tc_set_overhead(tc, nl_cli_parse_u32(arg)); } +void nl_cli_tc_parse_kind(struct rtnl_tc *tc, char *arg) +{ + rtnl_tc_set_kind(tc, arg); +} + void nl_cli_tc_parse_linktype(struct rtnl_tc *tc, char *arg) { int type; @@ -87,4 +92,74 @@ void nl_cli_tc_parse_linktype(struct rtnl_tc *tc, char *arg) rtnl_tc_set_linktype(tc, type); } +static NL_LIST_HEAD(tc_modules); + +struct nl_cli_tc_module *__nl_cli_tc_lookup(struct rtnl_tc_ops *ops) +{ + struct nl_cli_tc_module *tm; + + nl_list_for_each_entry(tm, &tc_modules, tm_list) + if (tm->tm_ops == ops) + return tm; + + return NULL; +} + +struct nl_cli_tc_module *nl_cli_tc_lookup(struct rtnl_tc_ops *ops) +{ + struct nl_cli_tc_module *tm; + + if ((tm = __nl_cli_tc_lookup(ops))) + return tm; + + switch (ops->to_type) { + case RTNL_TC_TYPE_QDISC: + case RTNL_TC_TYPE_CLASS: + nl_cli_load_module("cli/qdisc", ops->to_kind); + break; + + case RTNL_TC_TYPE_CLS: + nl_cli_load_module("cli/cls", ops->to_kind); + break; + + default: + nl_cli_fatal(EINVAL, "BUG: unhandled TC object type %d", + ops->to_type); + } + + if (!(tm = __nl_cli_tc_lookup(ops))) { + nl_cli_fatal(EINVAL, "Application bug: The shared library for " + "the tc object \"%s\" was successfully loaded but it " + "seems that module did not register itself", + ops->to_kind); + } + + return tm; +} + +void nl_cli_tc_register(struct nl_cli_tc_module *tm) +{ + struct rtnl_tc_ops *ops; + + if (!(ops = rtnl_tc_lookup_ops(tm->tm_type, tm->tm_name))) { + nl_cli_fatal(ENOENT, "Unable to register CLI TC module " + "\"%s\": No matching libnl TC module found.", tm->tm_name); + } + + if (__nl_cli_tc_lookup(ops)) { + nl_cli_fatal(EEXIST, "Unable to register CLI TC module " + "\"%s\": Module already registered.", tm->tm_name); + } + + tm->tm_ops = ops; + + nl_list_add_tail(&tm->tm_list, &tc_modules); +} + +void nl_cli_tc_unregister(struct nl_cli_tc_module *tm) +{ + nl_list_del(&tm->tm_list); +} + + /** @} */ diff --git a/src/nl-class-add.c b/src/nl-class-add.c index 80ea826..9698f0d 100644 --- a/src/nl-class-add.c +++ b/src/nl-class-add.c @@ -56,8 +56,8 @@ int main(int argc, char *argv[]) .dp_type = NL_DUMP_DETAILS, .dp_fd = stdout, }; - struct nl_cli_qdisc_module *qm; - struct rtnl_class_ops *ops; + struct nl_cli_tc_module *tm; + struct rtnl_tc_ops *ops; int err, flags = NLM_F_CREATE | NLM_F_EXCL; char *kind, *id = NULL; @@ -131,15 +131,15 @@ int main(int argc, char *argv[]) } kind = argv[optind++]; - rtnl_class_set_kind(class, kind); + rtnl_tc_set_kind(tc, kind); - if (!(ops = rtnl_class_lookup_ops(class))) + if (!(ops = rtnl_tc_get_ops(tc))) nl_cli_fatal(ENOENT, "Unknown class \"%s\"", kind); - if (!(qm = nl_cli_qdisc_lookup_by_class(ops))) + if (!(tm = nl_cli_tc_lookup(ops))) nl_cli_fatal(ENOTSUP, "class type \"%s\" not supported.", kind); - qm->qm_parse_class_argv(class, argc, argv); + tm->tm_parse_argv(tc, argc, argv); if (!quiet) { printf("Adding "); diff --git a/src/nl-class-delete.c b/src/nl-class-delete.c index 3c5cdc1..3df5a9a 100644 --- a/src/nl-class-delete.c +++ b/src/nl-class-delete.c @@ -110,7 +110,7 @@ int main(int argc, char *argv[]) case 'd': nl_cli_tc_parse_dev(tc, link_cache, optarg); break; case 'p': nl_cli_tc_parse_parent(tc, optarg); break; case 'i': nl_cli_tc_parse_handle(tc, optarg, 0); break; - case 'k': nl_cli_class_parse_kind(class, optarg); break; + case 'k': nl_cli_tc_parse_kind(tc, optarg); break; } } diff --git a/src/nl-class-list.c b/src/nl-class-list.c index fccc512..44ca49b 100644 --- a/src/nl-class-list.c +++ b/src/nl-class-list.c @@ -104,7 +104,7 @@ int main(int argc, char *argv[]) case 'd': nl_cli_tc_parse_dev(tc, link_cache, optarg); break; case 'p': nl_cli_tc_parse_parent(tc, optarg); break; case 'i': nl_cli_tc_parse_handle(tc, optarg, 0); break; - case 'k': nl_cli_class_parse_kind(class, optarg); break; + case 'k': nl_cli_tc_parse_kind(tc, optarg); break; } } diff --git a/src/nl-cls-add.c b/src/nl-cls-add.c index fad9313..054bab3 100644 --- a/src/nl-cls-add.c +++ b/src/nl-cls-add.c @@ -5,7 +5,7 @@ * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation version 2 of the License. * - * Copyright (c) 2003-2010 Thomas Graf + * Copyright (c) 2003-2011 Thomas Graf */ #include @@ -56,8 +56,8 @@ int main(int argc, char *argv[]) .dp_type = NL_DUMP_DETAILS, .dp_fd = stdout, }; - struct nl_cli_cls_module *cm; - struct rtnl_cls_ops *ops; + struct nl_cli_tc_module *tm; + struct rtnl_tc_ops *ops; int err, flags = NLM_F_CREATE | NLM_F_EXCL; char *kind, *id = NULL; @@ -139,16 +139,15 @@ int main(int argc, char *argv[]) } kind = argv[optind++]; - rtnl_cls_set_kind(cls, kind); + rtnl_tc_set_kind(tc, kind); - if (!(ops = rtnl_cls_lookup_ops(cls))) + if (!(ops = rtnl_tc_get_ops(tc))) nl_cli_fatal(ENOENT, "Unknown classifier \"%s\".", kind); - if (!(cm = nl_cli_cls_lookup(ops))) + if (!(tm = nl_cli_tc_lookup(ops))) nl_cli_fatal(ENOTSUP, "Classifier type \"%s\" not supported.", kind); - if ((err = cm->cm_parse_argv(cls, argc, argv)) < 0) - nl_cli_fatal(err, "Unable to parse classifier options"); + tm->tm_parse_argv(tc, argc, argv); if (!quiet) { printf("Adding "); diff --git a/src/nl-cls-delete.c b/src/nl-cls-delete.c index 359d15e..7d998fd 100644 --- a/src/nl-cls-delete.c +++ b/src/nl-cls-delete.c @@ -135,7 +135,7 @@ int main(int argc, char *argv[]) case 'd': nl_cli_tc_parse_dev(tc, link_cache, optarg); break; case 'p': nl_cli_tc_parse_parent(tc, optarg); break; case 'i': nl_cli_tc_parse_handle(tc, optarg, 0); break; - case 'k': nl_cli_cls_parse_kind(cls, optarg); break; + case 'k': nl_cli_tc_parse_kind(tc, optarg); break; case ARG_PROTO: nl_cli_cls_parse_proto(cls, optarg); break; case ARG_PRIO: rtnl_cls_set_prio(cls, nl_cli_parse_u32(optarg)); diff --git a/src/nl-cls-list.c b/src/nl-cls-list.c index e7c9a12..fcb5dcb 100644 --- a/src/nl-cls-list.c +++ b/src/nl-cls-list.c @@ -112,7 +112,7 @@ int main(int argc, char *argv[]) case 'd': nl_cli_tc_parse_dev(tc, link_cache, optarg); break; case 'p': nl_cli_tc_parse_parent(tc, optarg); break; case 'i': nl_cli_tc_parse_handle(tc, optarg, 0); break; - case 'k': nl_cli_cls_parse_kind(cls, optarg); break; + case 'k': nl_cli_tc_parse_kind(tc, optarg); break; case ARG_PROTO: nl_cli_cls_parse_proto(cls, optarg); break; case ARG_PRIO: rtnl_cls_set_prio(cls, nl_cli_parse_u32(optarg)); diff --git a/src/nl-qdisc-add.c b/src/nl-qdisc-add.c index 9da0f18..dd2ed2b 100644 --- a/src/nl-qdisc-add.c +++ b/src/nl-qdisc-add.c @@ -53,8 +53,8 @@ int main(int argc, char *argv[]) .dp_type = NL_DUMP_DETAILS, .dp_fd = stdout, }; - struct nl_cli_qdisc_module *qm; - struct rtnl_qdisc_ops *ops; + struct nl_cli_tc_module *tm; + struct rtnl_tc_ops *ops; int err, flags = NLM_F_CREATE | NLM_F_EXCL; char *kind, *id = NULL; @@ -122,15 +122,15 @@ int main(int argc, char *argv[]) } kind = argv[optind++]; - rtnl_qdisc_set_kind(qdisc, kind); + rtnl_tc_set_kind(tc, kind); - if (!(ops = rtnl_qdisc_lookup_ops(qdisc))) + if (!(ops = rtnl_tc_get_ops(tc))) nl_cli_fatal(ENOENT, "Unknown qdisc \"%s\"", kind); - if (!(qm = nl_cli_qdisc_lookup(ops))) + if (!(tm = nl_cli_tc_lookup(ops))) nl_cli_fatal(ENOTSUP, "Qdisc type \"%s\" not supported.", kind); - qm->qm_parse_qdisc_argv(qdisc, argc, argv); + tm->tm_parse_argv(tc, argc, argv); if (!quiet) { printf("Adding "); diff --git a/src/nl-qdisc-delete.c b/src/nl-qdisc-delete.c index b230063..9c7ec14 100644 --- a/src/nl-qdisc-delete.c +++ b/src/nl-qdisc-delete.c @@ -123,7 +123,7 @@ int main(int argc, char *argv[]) break; case 'k': nfilter++; - nl_cli_qdisc_parse_kind(qdisc, optarg); + nl_cli_tc_parse_kind(tc, optarg); break; } } diff --git a/src/nl-qdisc-list.c b/src/nl-qdisc-list.c index 670fa3d..5b0a3f0 100644 --- a/src/nl-qdisc-list.c +++ b/src/nl-qdisc-list.c @@ -170,7 +170,7 @@ int main(int argc, char *argv[]) case 'd': nl_cli_tc_parse_dev(tc, link_cache, optarg); break; case 'p': nl_cli_tc_parse_parent(tc, optarg); break; case 'i': nl_cli_tc_parse_handle(tc, optarg, 0); break; - case 'k': nl_cli_qdisc_parse_kind(qdisc, optarg); break; + case 'k': nl_cli_tc_parse_kind(tc, optarg); break; } }