dect
/
libnl
Archived
13
0
Fork 0

Unified TC API

Finally got rid of all the qdisc/class/cls code duplication in
the tc module API. The API takes care of allocation/freeing the
tc object specific data.

I hope I got it right this time.
This commit is contained in:
Thomas Graf 2011-03-21 15:51:52 +01:00
parent 5dc897d5de
commit 8eb5b5532e
64 changed files with 2143 additions and 3080 deletions

View File

@ -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 \

View File

@ -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;

View File

@ -17,6 +17,7 @@
#include <netlink/route/qdisc.h>
#include <netlink/route/rtnl.h>
#include <netlink/route/route.h>
#include <netlink/route/tc-api.h>
#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

View File

@ -13,12 +13,9 @@
#define __NETLINK_CLI_CLASS_H_
#include <netlink/route/class.h>
#include <netlink/route/class-modules.h>
#include <netlink/cli/tc.h>
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

View File

@ -13,27 +13,12 @@
#define __NETLINK_CLI_CLS_H_
#include <netlink/route/classifier.h>
#include <netlink/route/classifier-modules.h>
#include <netlink/cli/tc.h>
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

View File

@ -6,36 +6,18 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2008-2010 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2008-2011 Thomas Graf <tgraf@suug.ch>
*/
#ifndef __NETLINK_CLI_QDISC_H_
#define __NETLINK_CLI_QDISC_H_
#include <netlink/route/qdisc.h>
#include <netlink/route/qdisc-modules.h>
#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

View File

@ -6,13 +6,13 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2010 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2010-2011 Thomas Graf <tgraf@suug.ch>
*/
#ifndef __NETLINK_CLI_TC_H_
#define __NETLINK_CLI_TC_H_
#include <netlink/route/tc.h>
#include <netlink/route/tc-api.h>
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

View File

@ -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 <tgraf@suug.ch>
*/
#ifndef NETLINK_CLASS_MODULES_H_
#define NETLINK_CLASS_MODULES_H_
#include <netlink/netlink.h>
#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

View File

@ -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,

View File

@ -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 <tgraf@suug.ch>
*/
#ifndef NETLINK_CLASS_MODULES_H_
#define NETLINK_CLASS_MODULES_H_
#include <netlink/netlink.h>
#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

View File

@ -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

View File

@ -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 <tgraf@suug.ch>
*/
#ifndef NETLINK_QDISC_MODULES_H_
#define NETLINK_QDISC_MODULES_H_
#include <netlink/netlink.h>
#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

View File

@ -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 */

View File

@ -6,7 +6,7 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
*/
#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 *);

View File

@ -6,7 +6,7 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
*/
#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 *);

View File

@ -6,7 +6,7 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2003-2010 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
*/
#ifndef NETLINK_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 *);

View File

@ -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 <tgraf@suug.ch>
*/
#ifndef NETLINK_TC_API_H_
#define NETLINK_TC_API_H_
#include <netlink/netlink.h>
#include <netlink/msg.h>
#include <netlink/route/tc.h>
#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

View File

@ -6,7 +6,7 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2003-2010 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
*/
#ifndef NETLINK_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);

View File

@ -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 \

View File

@ -6,10 +6,11 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2010 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2010-2011 Thomas Graf <tgraf@suug.ch>
*/
#include <netlink/cli/utils.h>
#include <netlink/cli/tc.h>
#include <netlink/cli/cls.h>
#include <netlink/route/cls/basic.h>
@ -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);
}

View File

@ -6,10 +6,11 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2010 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2010-2011 Thomas Graf <tgraf@suug.ch>
*/
#include <netlink/cli/utils.h>
#include <netlink/cli/tc.h>
#include <netlink/cli/cls.h>
#include <netlink/route/cls/cgroup.h>
@ -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);
}

View File

@ -6,11 +6,11 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2010 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2010-2011 Thomas Graf <tgraf@suug.ch>
*/
#include <netlink/cli/utils.h>
#include <netlink/cli/qdisc.h>
#include <netlink/cli/tc.h>
#include <netlink/route/sch/fifo.h>
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);
}

View File

@ -6,11 +6,11 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2010 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2010-2011 Thomas Graf <tgraf@suug.ch>
*/
#include <netlink/cli/utils.h>
#include <netlink/cli/qdisc.h>
#include <netlink/cli/tc.h>
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);
}

View File

@ -6,11 +6,11 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2010 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2010-2011 Thomas Graf <tgraf@suug.ch>
*/
#include <netlink/cli/utils.h>
#include <netlink/cli/qdisc.h>
#include <netlink/cli/tc.h>
#include <netlink/route/sch/htb.h>
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);
}

View File

@ -7,11 +7,11 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2010 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2010-2011 Thomas Graf <tgraf@suug.ch>
*/
#include <netlink/cli/utils.h>
#include <netlink/cli/qdisc.h>
#include <netlink/cli/tc.h>
#include <netlink/route/sch/fifo.h>
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);
}

View File

@ -18,44 +18,42 @@
#include <netlink-local.h>
#include <netlink-tc.h>
#include <netlink/netlink.h>
#include <netlink/route/tc.h>
#include <netlink/route/tc-api.h>
#include <netlink/route/class.h>
#include <netlink/route/class-modules.h>
#include <netlink/route/qdisc.h>
#include <netlink/route/classifier.h>
#include <netlink/utils.h>
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);
}
/** @} */

View File

@ -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 <tgraf@suug.ch>
*/
/**
* @ingroup class
* @defgroup class_api Class Modules
* @{
*/
#include <netlink-local.h>
#include <netlink-tc.h>
#include <netlink/netlink.h>
#include <netlink/route/tc.h>
#include <netlink/route/class.h>
#include <netlink/route/class-modules.h>
#include <netlink/utils.h>
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;
}
/** @} */
/** @} */

View File

@ -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 <tgraf@suug.ch>
*/
/**
* @ingroup class
* @defgroup class_obj Class Object
* @{
*/
#include <netlink-local.h>
#include <netlink-tc.h>
#include <netlink/netlink.h>
#include <netlink/route/tc.h>
#include <netlink/route/class.h>
#include <netlink/route/class-modules.h>
#include <netlink/route/qdisc.h>
#include <netlink/route/classifier.h>
#include <netlink/utils.h>
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),
};
/** @} */

View File

@ -28,66 +28,26 @@
#include <netlink-tc.h>
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/route/tc.h>
#include <netlink/route/tc-api.h>
#include <netlink/route/classifier.h>
#include <netlink/route/classifier-modules.h>
#include <netlink/route/link.h>
/** @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);
}
/** @} */

View File

@ -6,12 +6,12 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2008-2010 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2008-2011 Thomas Graf <tgraf@suug.ch>
*/
/**
* @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 <netlink-local.h>
#include <netlink-tc.h>
#include <netlink/netlink.h>
#include <netlink/route/tc-api.h>
#include <netlink/route/classifier.h>
#include <netlink/route/classifier-modules.h>
#include <netlink/route/cls/basic.h>
#include <netlink/route/cls/ematch.h>
@ -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);
}
/** @} */

View File

@ -6,12 +6,12 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2009-2010 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2009-2011 Thomas Graf <tgraf@suug.ch>
*/
/**
* @ingroup cls_api
* @defgroup cgroup Control Groups Classifier
* @ingroup cls
* @defgroup cls_cgroup Control Groups Classifier
*
* @{
*/
@ -21,8 +21,8 @@
#include <netlink/netlink.h>
#include <netlink/attr.h>
#include <netlink/utils.h>
#include <netlink/route/tc-api.h>
#include <netlink/route/classifier.h>
#include <netlink/route/classifier-modules.h>
#include <netlink/route/cls/cgroup.h>
#include <netlink/route/cls/ematch.h>
@ -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, "<no tree>");
} 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);
}
/** @} */

View File

@ -20,7 +20,6 @@
#include <netlink-tc.h>
#include <netlink/netlink.h>
#include <netlink/route/classifier.h>
#include <netlink/route/classifier-modules.h>
#include <netlink/route/cls/ematch.h>
#include <netlink/route/cls/ematch/cmp.h>
@ -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");
}

View File

@ -6,14 +6,14 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2006 Petr Gotthard <petr.gotthard@siemens.com>
* 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 <netlink-local.h>
#include <netlink-tc.h>
#include <netlink/netlink.h>
#include <netlink/route/tc-api.h>
#include <netlink/route/classifier.h>
#include <netlink/route/classifier-modules.h>
#include <netlink/route/cls/fw.h>
/** @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);
}
/** @} */

View File

@ -13,9 +13,8 @@
#include <netlink-tc.h>
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/route/tc.h>
#include <netlink/route/tc-api.h>
#include <netlink/route/classifier.h>
#include <netlink/route/classifier-modules.h>
#include <netlink/route/cls/police.h>
/**

View File

@ -6,14 +6,14 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2003-2009 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2005-2006 Petr Gotthard <petr.gotthard@siemens.com>
* 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 <netlink/netlink.h>
#include <netlink/attr.h>
#include <netlink/utils.h>
#include <netlink/route/tc.h>
#include <netlink/route/tc-api.h>
#include <netlink/route/classifier.h>
#include <netlink/route/classifier-modules.h>
#include <netlink/route/cls/u32.h>
/** @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);
}
/** @} */

View File

@ -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 <tgraf@suug.ch>
*/
/**
* @ingroup cls
* @defgroup cls_api Classifier Modules
* @{
*/
#include <netlink-local.h>
#include <netlink-tc.h>
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/route/tc.h>
#include <netlink/route/classifier.h>
#include <netlink/route/classifier-modules.h>
#include <netlink/route/link.h>
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;
}
/** @} */
/** @} */

View File

@ -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 <tgraf@suug.ch>
*/
/**
* @ingroup cls
* @defgroup cls_obj Classifier Object
* @{
*/
#include <netlink-local.h>
#include <netlink-tc.h>
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/route/tc.h>
#include <netlink/route/classifier.h>
#include <netlink/route/classifier-modules.h>
#include <netlink/route/link.h>
/** @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),
};
/** @} */

View File

@ -6,7 +6,7 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
*/
/**
@ -87,44 +87,29 @@
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/route/link.h>
#include <netlink/route/tc.h>
#include <netlink/route/tc-api.h>
#include <netlink/route/qdisc.h>
#include <netlink/route/class.h>
#include <netlink/route/classifier.h>
#include <netlink/route/qdisc-modules.h>
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);
}
/** @} */

View File

@ -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 <tgraf@suug.ch>
*/
/**
* @ingroup qdisc
* @defgroup qdisc_api Queueing Discipline Modules
* @{
*/
#include <netlink-local.h>
#include <netlink-tc.h>
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/route/link.h>
#include <netlink/route/tc.h>
#include <netlink/route/qdisc.h>
#include <netlink/route/class.h>
#include <netlink/route/classifier.h>
#include <netlink/route/qdisc-modules.h>
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;
}
/** @} */
/** @} */

View File

@ -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 <tgraf@suug.ch>
*/
/**
* @ingroup qdisc
* @defgroup qdisc_obj Queueing Discipline Object
* @{
*/
#include <netlink-local.h>
#include <netlink-tc.h>
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/route/link.h>
#include <netlink/route/tc.h>
#include <netlink/route/qdisc.h>
#include <netlink/route/class.h>
#include <netlink/route/classifier.h>
#include <netlink/route/qdisc-modules.h>
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),
};
/** @} */

View File

@ -6,33 +6,32 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
*/
/**
* @ingroup qdisc_api
* @defgroup blackhole Blackhole
* @ingroup qdisc
* @defgroup qdisc_blackhole Blackhole
* @{
*/
#include <netlink-local.h>
#include <netlink-tc.h>
#include <netlink/netlink.h>
#include <netlink/route/qdisc.h>
#include <netlink/route/qdisc-modules.h>
#include <netlink/route/tc-api.h>
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);
}
/** @} */

View File

@ -6,25 +6,24 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
*/
#include <netlink-local.h>
#include <netlink-tc.h>
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/route/tc-api.h>
#include <netlink/route/qdisc.h>
#include <netlink/route/qdisc-modules.h>
#include <netlink/route/class.h>
#include <netlink/route/class-modules.h>
#include <netlink/route/link.h>
#include <netlink/route/sch/cbq.h>
#include <netlink/route/cls/police.h>
/**
* @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);
}
/** @} */

View File

@ -6,13 +6,13 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
*/
/**
* @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 <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/route/qdisc.h>
#include <netlink/route/qdisc-modules.h>
#include <netlink/route/tc-api.h>
#include <netlink/route/class.h>
#include <netlink/route/class-modules.h>
#include <netlink/route/sch/dsmark.h>
/** @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);
}
/** @} */

View File

@ -6,12 +6,12 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
*/
/**
* @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 <netlink-local.h>
#include <netlink-tc.h>
#include <netlink/netlink.h>
#include <netlink/route/tc-api.h>
#include <netlink/route/qdisc.h>
#include <netlink/route/qdisc-modules.h>
#include <netlink/route/sch/fifo.h>
#include <netlink/utils.h>
@ -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);
}
/** @} */

View File

@ -6,15 +6,15 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2003-2010 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2005-2006 Petr Gotthard <petr.gotthard@siemens.com>
* 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 <netlink/netlink.h>
#include <netlink/cache.h>
#include <netlink/utils.h>
#include <netlink/route/tc.h>
#include <netlink/route/tc-api.h>
#include <netlink/route/qdisc.h>
#include <netlink/route/qdisc-modules.h>
#include <netlink/route/class.h>
#include <netlink/route/class-modules.h>
#include <netlink/route/link.h>
#include <netlink/route/sch/htb.h>
@ -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<<d->ch_rate.rs_cell_log);
r, ru, rbit, rubit, 1<<htb->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<<d->ch_ceil.rs_cell_log);
nl_dump(p, " ceil %.2f%s/s (%.0f%s) log %u",
r, ru, rbit, rubit, 1<<htb->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);
}
/** @} */

View File

@ -6,12 +6,12 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
*/
/**
* @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 <netlink-tc.h>
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/route/tc-api.h>
#include <netlink/route/qdisc.h>
#include <netlink/route/qdisc-modules.h>
#include <netlink/route/sch/netem.h>
/** @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);
}
/** @} */

View File

@ -6,12 +6,12 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
*/
/**
* @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 <netlink-tc.h>
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/route/tc-api.h>
#include <netlink/route/qdisc.h>
#include <netlink/route/qdisc-modules.h>
#include <netlink/route/sch/prio.h>
/** @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);
}
/** @} */

View File

@ -6,12 +6,12 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
*/
/**
* @ingroup qdisc_api
* @defgroup red Random Early Detection (RED)
* @ingroup qdisc
* @defgroup qdisc_red Random Early Detection (RED)
* @brief
* @{
*/
@ -20,8 +20,8 @@
#include <netlink-tc.h>
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/route/tc-api.h>
#include <netlink/route/qdisc.h>
#include <netlink/route/qdisc-modules.h>
#include <netlink/route/sch/red.h>
/** @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);
}
/** @} */

View File

@ -6,12 +6,12 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2003-2008 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
*/
/**
* @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 <netlink-tc.h>
#include <netlink/netlink.h>
#include <netlink/utils.h>
#include <netlink/route/tc-api.h>
#include <netlink/route/qdisc.h>
#include <netlink/route/qdisc-modules.h>
#include <netlink/route/sch/sfq.h>
/** @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);
}
/** @} */

View File

@ -6,12 +6,12 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2003-2010 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
*/
/**
* @ingroup qdisc_api
* @defgroup tbf Token Bucket Filter (TBF)
* @ingroup qdisc
* @defgroup qdisc_tbf Token Bucket Filter (TBF)
* @{
*/
@ -20,11 +20,9 @@
#include <netlink/netlink.h>
#include <netlink/cache.h>
#include <netlink/utils.h>
#include <netlink/route/tc.h>
#include <netlink/route/tc-api.h>
#include <netlink/route/qdisc.h>
#include <netlink/route/qdisc-modules.h>
#include <netlink/route/class.h>
#include <netlink/route/class-modules.h>
#include <netlink/route/link.h>
#include <netlink/route/sch/tbf.h>
@ -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);
}
/** @} */

View File

@ -6,7 +6,7 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2003-2010 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
*/
/**
@ -22,9 +22,13 @@
#include <netlink/route/rtnl.h>
#include <netlink/route/link.h>
#include <netlink/route/tc.h>
#include <netlink/route/tc-api.h>
/** @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;
}
/** @} */
/** @} */

View File

@ -6,7 +6,7 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2010 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2010-2011 Thomas Graf <tgraf@suug.ch>
*/
/**
@ -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);
}
/** @} */

View File

@ -6,7 +6,7 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2010 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2010-2011 Thomas Graf <tgraf@suug.ch>
*/
/**
@ -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);
}
/** @} */

View File

@ -6,7 +6,7 @@
* License as published by the Free Software Foundation version 2.1
* of the License.
*
* Copyright (c) 2008-2010 Thomas Graf <tgraf@suug.ch>
* Copyright (c) 2008-2011 Thomas Graf <tgraf@suug.ch>
*/
/**
@ -18,107 +18,15 @@
#include <netlink/cli/utils.h>
#include <netlink/cli/qdisc.h>
#include <netlink/route/class.h>
#include <netlink/route/class-modules.h>
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);
}
/** @} */

View File

@ -11,7 +11,7 @@
#include <netlink/cli/utils.h>
#include <netlink/cli/tc.h>
#include <netlink/route/tc.h>
#include <netlink/route/tc-api.h>
/**
* @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);
}
/** @} */

View File

@ -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 ");

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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 <tgraf@suug.ch>
* Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
*/
#include <netlink/cli/utils.h>
@ -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 ");

View File

@ -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));

View File

@ -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));

View File

@ -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 ");

View File

@ -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;
}
}

View File

@ -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;
}
}