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:
parent
5dc897d5de
commit
8eb5b5532e
64 changed files with 2143 additions and 3080 deletions
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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,
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
|
@ -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 *);
|
||||
|
|
|
@ -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 *);
|
||||
|
|
|
@ -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 *);
|
||||
|
|
141
include/netlink/route/tc-api.h
Normal file
141
include/netlink/route/tc-api.h
Normal 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
|
|
@ -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);
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
/** @} */
|
||||
|
||||
/** @} */
|
|
@ -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),
|
||||
};
|
||||
|
||||
/** @} */
|
200
lib/route/cls.c
200
lib/route/cls.c
|
@ -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);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -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>
|
||||
|
||||
/**
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
/** @} */
|
||||
|
||||
/** @} */
|
|
@ -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),
|
||||
};
|
||||
|
||||
/** @} */
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
/** @} */
|
|
@ -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),
|
||||
};
|
||||
|
||||
/** @} */
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
567
lib/route/tc.c
567
lib/route/tc.c
|
@ -6,7 +6,7 @@
|
|||
* License as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* Copyright (c) 2003-2010 Thomas Graf <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;
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
|
|
77
src/lib/tc.c
77
src/lib/tc.c
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
/** @} */
|
||||
|
|
|
@ -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 ");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 ");
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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 ");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue