From 45941f9d5f5f141e67cf2b6688c287aa5b52a4fd Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Mon, 21 Mar 2011 16:47:42 +0100 Subject: rename sch -> qdisc --- include/Makefile.am | 18 +- include/netlink/route/qdisc/cbq.h | 30 ++ include/netlink/route/qdisc/dsmark.h | 41 ++ include/netlink/route/qdisc/fifo.h | 28 ++ include/netlink/route/qdisc/htb.h | 39 ++ include/netlink/route/qdisc/netem.h | 75 +++ include/netlink/route/qdisc/prio.h | 53 ++ include/netlink/route/qdisc/red.h | 17 + include/netlink/route/qdisc/sfq.h | 36 ++ include/netlink/route/qdisc/tbf.h | 40 ++ include/netlink/route/sch/cbq.h | 30 -- include/netlink/route/sch/dsmark.h | 41 -- include/netlink/route/sch/fifo.h | 28 -- include/netlink/route/sch/htb.h | 39 -- include/netlink/route/sch/netem.h | 75 --- include/netlink/route/sch/prio.h | 53 -- include/netlink/route/sch/red.h | 17 - include/netlink/route/sch/sfq.h | 36 -- include/netlink/route/sch/tbf.h | 40 -- lib/Makefile.am | 7 +- lib/cli/qdisc/bfifo.c | 2 +- lib/cli/qdisc/htb.c | 2 +- lib/cli/qdisc/pfifo.c | 2 +- lib/route/qdisc/blackhole.c | 37 ++ lib/route/qdisc/cbq.c | 204 ++++++++ lib/route/qdisc/dsmark.c | 413 ++++++++++++++++ lib/route/qdisc/fifo.c | 169 +++++++ lib/route/qdisc/htb.c | 433 +++++++++++++++++ lib/route/qdisc/netem.c | 905 +++++++++++++++++++++++++++++++++++ lib/route/qdisc/prio.c | 294 ++++++++++++ lib/route/qdisc/red.c | 190 ++++++++ lib/route/qdisc/sfq.c | 256 ++++++++++ lib/route/qdisc/tbf.c | 460 ++++++++++++++++++ lib/route/sch/blackhole.c | 37 -- lib/route/sch/cbq.c | 204 -------- lib/route/sch/dsmark.c | 413 ---------------- lib/route/sch/fifo.c | 169 ------- lib/route/sch/htb.c | 433 ----------------- lib/route/sch/netem.c | 905 ----------------------------------- lib/route/sch/prio.c | 294 ------------ lib/route/sch/red.c | 190 -------- lib/route/sch/sfq.c | 256 ---------- lib/route/sch/tbf.c | 460 ------------------ 43 files changed, 3736 insertions(+), 3735 deletions(-) create mode 100644 include/netlink/route/qdisc/cbq.h create mode 100644 include/netlink/route/qdisc/dsmark.h create mode 100644 include/netlink/route/qdisc/fifo.h create mode 100644 include/netlink/route/qdisc/htb.h create mode 100644 include/netlink/route/qdisc/netem.h create mode 100644 include/netlink/route/qdisc/prio.h create mode 100644 include/netlink/route/qdisc/red.h create mode 100644 include/netlink/route/qdisc/sfq.h create mode 100644 include/netlink/route/qdisc/tbf.h delete mode 100644 include/netlink/route/sch/cbq.h delete mode 100644 include/netlink/route/sch/dsmark.h delete mode 100644 include/netlink/route/sch/fifo.h delete mode 100644 include/netlink/route/sch/htb.h delete mode 100644 include/netlink/route/sch/netem.h delete mode 100644 include/netlink/route/sch/prio.h delete mode 100644 include/netlink/route/sch/red.h delete mode 100644 include/netlink/route/sch/sfq.h delete mode 100644 include/netlink/route/sch/tbf.h create mode 100644 lib/route/qdisc/blackhole.c create mode 100644 lib/route/qdisc/cbq.c create mode 100644 lib/route/qdisc/dsmark.c create mode 100644 lib/route/qdisc/fifo.c create mode 100644 lib/route/qdisc/htb.c create mode 100644 lib/route/qdisc/netem.c create mode 100644 lib/route/qdisc/prio.c create mode 100644 lib/route/qdisc/red.c create mode 100644 lib/route/qdisc/sfq.c create mode 100644 lib/route/qdisc/tbf.c delete mode 100644 lib/route/sch/blackhole.c delete mode 100644 lib/route/sch/cbq.c delete mode 100644 lib/route/sch/dsmark.c delete mode 100644 lib/route/sch/fifo.c delete mode 100644 lib/route/sch/htb.c delete mode 100644 lib/route/sch/netem.c delete mode 100644 lib/route/sch/prio.c delete mode 100644 lib/route/sch/red.c delete mode 100644 lib/route/sch/sfq.c delete mode 100644 lib/route/sch/tbf.c diff --git a/include/Makefile.am b/include/Makefile.am index 8824dfe..e7f1206 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -33,15 +33,15 @@ nobase_include_HEADERS = \ netlink/route/cls/u32.h \ netlink/route/link/info-api.h \ netlink/route/link/vlan.h \ - netlink/route/sch/cbq.h \ - netlink/route/sch/dsmark.h \ - netlink/route/sch/fifo.h \ - netlink/route/sch/htb.h \ - netlink/route/sch/netem.h \ - netlink/route/sch/prio.h \ - netlink/route/sch/red.h \ - netlink/route/sch/sfq.h \ - netlink/route/sch/tbf.h \ + netlink/route/qdisc/cbq.h \ + netlink/route/qdisc/dsmark.h \ + netlink/route/qdisc/fifo.h \ + netlink/route/qdisc/htb.h \ + netlink/route/qdisc/netem.h \ + netlink/route/qdisc/prio.h \ + netlink/route/qdisc/red.h \ + netlink/route/qdisc/sfq.h \ + netlink/route/qdisc/tbf.h \ netlink/route/addr.h \ netlink/route/class.h \ netlink/route/classifier.h \ diff --git a/include/netlink/route/qdisc/cbq.h b/include/netlink/route/qdisc/cbq.h new file mode 100644 index 0000000..3dbdd2d --- /dev/null +++ b/include/netlink/route/qdisc/cbq.h @@ -0,0 +1,30 @@ +/* + * netlink/route/sch/cbq.h Class Based Queueing + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2006 Thomas Graf + */ + +#ifndef NETLINK_CBQ_H_ +#define NETLINK_CBQ_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern char * nl_ovl_strategy2str(int, char *, size_t); +extern int nl_str2ovl_strategy(const char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/netlink/route/qdisc/dsmark.h b/include/netlink/route/qdisc/dsmark.h new file mode 100644 index 0000000..de65496 --- /dev/null +++ b/include/netlink/route/qdisc/dsmark.h @@ -0,0 +1,41 @@ +/* + * netlink/route/sch/dsmark.h DSMARK + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2006 Thomas Graf + */ + +#ifndef NETLINK_DSMARK_H_ +#define NETLINK_DSMARK_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern int rtnl_class_dsmark_set_bmask(struct rtnl_class *, uint8_t); +extern int rtnl_class_dsmark_get_bmask(struct rtnl_class *); + +extern int rtnl_class_dsmark_set_value(struct rtnl_class *, uint8_t); +extern int rtnl_class_dsmark_get_value(struct rtnl_class *); + +extern int rtnl_qdisc_dsmark_set_indices(struct rtnl_qdisc *, uint16_t); +extern int rtnl_qdisc_dsmark_get_indices(struct rtnl_qdisc *); + +extern int rtnl_qdisc_dsmark_set_default_index(struct rtnl_qdisc *, + uint16_t); +extern int rtnl_qdisc_dsmark_get_default_index(struct rtnl_qdisc *); + +extern int rtnl_qdisc_dsmark_set_set_tc_index(struct rtnl_qdisc *, int); +extern int rtnl_qdisc_dsmark_get_set_tc_index(struct rtnl_qdisc *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/netlink/route/qdisc/fifo.h b/include/netlink/route/qdisc/fifo.h new file mode 100644 index 0000000..c18dd79 --- /dev/null +++ b/include/netlink/route/qdisc/fifo.h @@ -0,0 +1,28 @@ +/* + * netlink/route/sch/fifo.c FIFO Qdisc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2006 Thomas Graf + */ + +#ifndef NETLINK_FIFO_H_ +#define NETLINK_FIFO_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern int rtnl_qdisc_fifo_set_limit(struct rtnl_qdisc *, int); +extern int rtnl_qdisc_fifo_get_limit(struct rtnl_qdisc *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/netlink/route/qdisc/htb.h b/include/netlink/route/qdisc/htb.h new file mode 100644 index 0000000..9061b9b --- /dev/null +++ b/include/netlink/route/qdisc/htb.h @@ -0,0 +1,39 @@ +/* + * netlink/route/sch/htb.h HTB Qdisc + * + * 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 + * Copyright (c) 2005 Petr Gotthard + * Copyright (c) 2005 Siemens AG Oesterreich + */ + +#ifndef NETLINK_HTB_H_ +#define NETLINK_HTB_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void rtnl_htb_set_rate2quantum(struct rtnl_qdisc *, uint32_t); +extern void rtnl_htb_set_defcls(struct rtnl_qdisc *, uint32_t); + +extern void rtnl_htb_set_prio(struct rtnl_class *, uint32_t); +extern void rtnl_htb_set_rate(struct rtnl_class *, uint32_t); +extern uint32_t rtnl_htb_get_rate(struct rtnl_class *); +extern void rtnl_htb_set_ceil(struct rtnl_class *, uint32_t); +extern void rtnl_htb_set_rbuffer(struct rtnl_class *, uint32_t); +extern void rtnl_htb_set_cbuffer(struct rtnl_class *, uint32_t); +extern void rtnl_htb_set_quantum(struct rtnl_class *, uint32_t quantum); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/netlink/route/qdisc/netem.h b/include/netlink/route/qdisc/netem.h new file mode 100644 index 0000000..ce56ee7 --- /dev/null +++ b/include/netlink/route/qdisc/netem.h @@ -0,0 +1,75 @@ +/* + * netlink/route/sch/netem.h Network Emulator Qdisc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2006 Thomas Graf + */ + +#ifndef NETLINK_NETEM_H_ +#define NETLINK_NETEM_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void rtnl_netem_set_limit(struct rtnl_qdisc *, int); +extern int rtnl_netem_get_limit(struct rtnl_qdisc *); + +/* Packet Re-ordering */ +extern void rtnl_netem_set_gap(struct rtnl_qdisc *, int); +extern int rtnl_netem_get_gap(struct rtnl_qdisc *); + +extern void rtnl_netem_set_reorder_probability(struct rtnl_qdisc *, int); +extern int rtnl_netem_get_reorder_probability(struct rtnl_qdisc *); + +extern void rtnl_netem_set_reorder_correlation(struct rtnl_qdisc *, int); +extern int rtnl_netem_get_reorder_correlation(struct rtnl_qdisc *); + +/* Corruption */ +extern void rtnl_netem_set_corruption_probability(struct rtnl_qdisc *, int); +extern int rtnl_netem_get_corruption_probability(struct rtnl_qdisc *); + +extern void rtnl_netem_set_corruption_correlation(struct rtnl_qdisc *, int); +extern int rtnl_netem_get_corruption_correlation(struct rtnl_qdisc *); + +/* Packet Loss */ +extern void rtnl_netem_set_loss(struct rtnl_qdisc *, int); +extern int rtnl_netem_get_loss(struct rtnl_qdisc *); + +extern void rtnl_netem_set_loss_correlation(struct rtnl_qdisc *, int); +extern int rtnl_netem_get_loss_correlation(struct rtnl_qdisc *); + +/* Packet Duplication */ +extern void rtnl_netem_set_duplicate(struct rtnl_qdisc *, int); +extern int rtnl_netem_get_duplicate(struct rtnl_qdisc *); + +extern void rtnl_netem_set_duplicate_correlation(struct rtnl_qdisc *, int); +extern int rtnl_netem_get_duplicate_correlation(struct rtnl_qdisc *); + +/* Packet Delay */ +extern void rtnl_netem_set_delay(struct rtnl_qdisc *, int); +extern int rtnl_netem_get_delay(struct rtnl_qdisc *); + +extern void rtnl_netem_set_jitter(struct rtnl_qdisc *, int); +extern int rtnl_netem_get_jitter(struct rtnl_qdisc *); + +extern void rtnl_netem_set_delay_correlation(struct rtnl_qdisc *, int); +extern int rtnl_netem_get_delay_correlation(struct rtnl_qdisc *); + +/* Delay Distribution */ +#define MAXDIST 65536 +extern int rtnl_netem_set_delay_distribution(struct rtnl_qdisc *, const char *); +extern int rtnl_netem_get_delay_distribution_size(struct rtnl_qdisc *); +extern int rtnl_netem_get_delay_distribution(struct rtnl_qdisc *, int16_t **); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/netlink/route/qdisc/prio.h b/include/netlink/route/qdisc/prio.h new file mode 100644 index 0000000..f6fdc86 --- /dev/null +++ b/include/netlink/route/qdisc/prio.h @@ -0,0 +1,53 @@ +/* + * netlink/route/sch/prio.c PRIO Qdisc + * + * 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-2011 Thomas Graf + */ + +#ifndef NETLINK_PRIO_H_ +#define NETLINK_PRIO_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @name Default Values + * @{ + */ + +/** + * Default number of bands. + * @ingroup prio + */ +#define QDISC_PRIO_DEFAULT_BANDS 3 + +/** + * Default priority mapping. + * @ingroup prio + */ +#define QDISC_PRIO_DEFAULT_PRIOMAP \ + { 1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 } + +/** @} */ + +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 *); + +extern char * rtnl_prio2str(int, char *, size_t); +extern int rtnl_str2prio(const char *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/netlink/route/qdisc/red.h b/include/netlink/route/qdisc/red.h new file mode 100644 index 0000000..a4e8642 --- /dev/null +++ b/include/netlink/route/qdisc/red.h @@ -0,0 +1,17 @@ +/* + * netlink/route/sch/red.h RED Qdisc + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * Copyright (c) 2003-2006 Thomas Graf + */ + +#ifndef NETLINK_RED_H_ +#define NETLINK_RED_H_ + +#include + +#endif diff --git a/include/netlink/route/qdisc/sfq.h b/include/netlink/route/qdisc/sfq.h new file mode 100644 index 0000000..7cc0b3e --- /dev/null +++ b/include/netlink/route/qdisc/sfq.h @@ -0,0 +1,36 @@ +/* + * netlink/route/sch/sfq.c SFQ Qdisc + * + * 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-2011 Thomas Graf + */ + +#ifndef NETLINK_SFQ_H_ +#define NETLINK_SFQ_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void rtnl_sfq_set_quantum(struct rtnl_qdisc *, int); +extern int rtnl_sfq_get_quantum(struct rtnl_qdisc *); + +extern void rtnl_sfq_set_limit(struct rtnl_qdisc *, int); +extern int rtnl_sfq_get_limit(struct rtnl_qdisc *); + +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 *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/netlink/route/qdisc/tbf.h b/include/netlink/route/qdisc/tbf.h new file mode 100644 index 0000000..8a2144a --- /dev/null +++ b/include/netlink/route/qdisc/tbf.h @@ -0,0 +1,40 @@ +/* + * netlink/route/sch/tbf.h TBF Qdisc + * + * 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-2011 Thomas Graf + */ + +#ifndef NETLINK_TBF_H_ +#define NETLINK_TBF_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +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 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 *); + +extern int rtnl_qdisc_tbf_set_peakrate(struct rtnl_qdisc *, int, int, int); +extern int rtnl_qdisc_tbf_get_peakrate(struct rtnl_qdisc *); +extern int rtnl_qdisc_tbf_get_peakrate_bucket(struct rtnl_qdisc *); +extern int rtnl_qdisc_tbf_get_peakrate_cell(struct rtnl_qdisc *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/netlink/route/sch/cbq.h b/include/netlink/route/sch/cbq.h deleted file mode 100644 index 3dbdd2d..0000000 --- a/include/netlink/route/sch/cbq.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * netlink/route/sch/cbq.h Class Based Queueing - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2003-2006 Thomas Graf - */ - -#ifndef NETLINK_CBQ_H_ -#define NETLINK_CBQ_H_ - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -extern char * nl_ovl_strategy2str(int, char *, size_t); -extern int nl_str2ovl_strategy(const char *); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/include/netlink/route/sch/dsmark.h b/include/netlink/route/sch/dsmark.h deleted file mode 100644 index de65496..0000000 --- a/include/netlink/route/sch/dsmark.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * netlink/route/sch/dsmark.h DSMARK - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2003-2006 Thomas Graf - */ - -#ifndef NETLINK_DSMARK_H_ -#define NETLINK_DSMARK_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -extern int rtnl_class_dsmark_set_bmask(struct rtnl_class *, uint8_t); -extern int rtnl_class_dsmark_get_bmask(struct rtnl_class *); - -extern int rtnl_class_dsmark_set_value(struct rtnl_class *, uint8_t); -extern int rtnl_class_dsmark_get_value(struct rtnl_class *); - -extern int rtnl_qdisc_dsmark_set_indices(struct rtnl_qdisc *, uint16_t); -extern int rtnl_qdisc_dsmark_get_indices(struct rtnl_qdisc *); - -extern int rtnl_qdisc_dsmark_set_default_index(struct rtnl_qdisc *, - uint16_t); -extern int rtnl_qdisc_dsmark_get_default_index(struct rtnl_qdisc *); - -extern int rtnl_qdisc_dsmark_set_set_tc_index(struct rtnl_qdisc *, int); -extern int rtnl_qdisc_dsmark_get_set_tc_index(struct rtnl_qdisc *); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/include/netlink/route/sch/fifo.h b/include/netlink/route/sch/fifo.h deleted file mode 100644 index c18dd79..0000000 --- a/include/netlink/route/sch/fifo.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * netlink/route/sch/fifo.c FIFO Qdisc - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2003-2006 Thomas Graf - */ - -#ifndef NETLINK_FIFO_H_ -#define NETLINK_FIFO_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -extern int rtnl_qdisc_fifo_set_limit(struct rtnl_qdisc *, int); -extern int rtnl_qdisc_fifo_get_limit(struct rtnl_qdisc *); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/include/netlink/route/sch/htb.h b/include/netlink/route/sch/htb.h deleted file mode 100644 index 9061b9b..0000000 --- a/include/netlink/route/sch/htb.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * netlink/route/sch/htb.h HTB Qdisc - * - * 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 - * Copyright (c) 2005 Petr Gotthard - * Copyright (c) 2005 Siemens AG Oesterreich - */ - -#ifndef NETLINK_HTB_H_ -#define NETLINK_HTB_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -extern void rtnl_htb_set_rate2quantum(struct rtnl_qdisc *, uint32_t); -extern void rtnl_htb_set_defcls(struct rtnl_qdisc *, uint32_t); - -extern void rtnl_htb_set_prio(struct rtnl_class *, uint32_t); -extern void rtnl_htb_set_rate(struct rtnl_class *, uint32_t); -extern uint32_t rtnl_htb_get_rate(struct rtnl_class *); -extern void rtnl_htb_set_ceil(struct rtnl_class *, uint32_t); -extern void rtnl_htb_set_rbuffer(struct rtnl_class *, uint32_t); -extern void rtnl_htb_set_cbuffer(struct rtnl_class *, uint32_t); -extern void rtnl_htb_set_quantum(struct rtnl_class *, uint32_t quantum); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/include/netlink/route/sch/netem.h b/include/netlink/route/sch/netem.h deleted file mode 100644 index ce56ee7..0000000 --- a/include/netlink/route/sch/netem.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * netlink/route/sch/netem.h Network Emulator Qdisc - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2003-2006 Thomas Graf - */ - -#ifndef NETLINK_NETEM_H_ -#define NETLINK_NETEM_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -extern void rtnl_netem_set_limit(struct rtnl_qdisc *, int); -extern int rtnl_netem_get_limit(struct rtnl_qdisc *); - -/* Packet Re-ordering */ -extern void rtnl_netem_set_gap(struct rtnl_qdisc *, int); -extern int rtnl_netem_get_gap(struct rtnl_qdisc *); - -extern void rtnl_netem_set_reorder_probability(struct rtnl_qdisc *, int); -extern int rtnl_netem_get_reorder_probability(struct rtnl_qdisc *); - -extern void rtnl_netem_set_reorder_correlation(struct rtnl_qdisc *, int); -extern int rtnl_netem_get_reorder_correlation(struct rtnl_qdisc *); - -/* Corruption */ -extern void rtnl_netem_set_corruption_probability(struct rtnl_qdisc *, int); -extern int rtnl_netem_get_corruption_probability(struct rtnl_qdisc *); - -extern void rtnl_netem_set_corruption_correlation(struct rtnl_qdisc *, int); -extern int rtnl_netem_get_corruption_correlation(struct rtnl_qdisc *); - -/* Packet Loss */ -extern void rtnl_netem_set_loss(struct rtnl_qdisc *, int); -extern int rtnl_netem_get_loss(struct rtnl_qdisc *); - -extern void rtnl_netem_set_loss_correlation(struct rtnl_qdisc *, int); -extern int rtnl_netem_get_loss_correlation(struct rtnl_qdisc *); - -/* Packet Duplication */ -extern void rtnl_netem_set_duplicate(struct rtnl_qdisc *, int); -extern int rtnl_netem_get_duplicate(struct rtnl_qdisc *); - -extern void rtnl_netem_set_duplicate_correlation(struct rtnl_qdisc *, int); -extern int rtnl_netem_get_duplicate_correlation(struct rtnl_qdisc *); - -/* Packet Delay */ -extern void rtnl_netem_set_delay(struct rtnl_qdisc *, int); -extern int rtnl_netem_get_delay(struct rtnl_qdisc *); - -extern void rtnl_netem_set_jitter(struct rtnl_qdisc *, int); -extern int rtnl_netem_get_jitter(struct rtnl_qdisc *); - -extern void rtnl_netem_set_delay_correlation(struct rtnl_qdisc *, int); -extern int rtnl_netem_get_delay_correlation(struct rtnl_qdisc *); - -/* Delay Distribution */ -#define MAXDIST 65536 -extern int rtnl_netem_set_delay_distribution(struct rtnl_qdisc *, const char *); -extern int rtnl_netem_get_delay_distribution_size(struct rtnl_qdisc *); -extern int rtnl_netem_get_delay_distribution(struct rtnl_qdisc *, int16_t **); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/include/netlink/route/sch/prio.h b/include/netlink/route/sch/prio.h deleted file mode 100644 index f6fdc86..0000000 --- a/include/netlink/route/sch/prio.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * netlink/route/sch/prio.c PRIO Qdisc - * - * 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-2011 Thomas Graf - */ - -#ifndef NETLINK_PRIO_H_ -#define NETLINK_PRIO_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @name Default Values - * @{ - */ - -/** - * Default number of bands. - * @ingroup prio - */ -#define QDISC_PRIO_DEFAULT_BANDS 3 - -/** - * Default priority mapping. - * @ingroup prio - */ -#define QDISC_PRIO_DEFAULT_PRIOMAP \ - { 1, 2, 2, 2, 1, 2, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 } - -/** @} */ - -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 *); - -extern char * rtnl_prio2str(int, char *, size_t); -extern int rtnl_str2prio(const char *); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/include/netlink/route/sch/red.h b/include/netlink/route/sch/red.h deleted file mode 100644 index a4e8642..0000000 --- a/include/netlink/route/sch/red.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * netlink/route/sch/red.h RED Qdisc - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation version 2.1 - * of the License. - * - * Copyright (c) 2003-2006 Thomas Graf - */ - -#ifndef NETLINK_RED_H_ -#define NETLINK_RED_H_ - -#include - -#endif diff --git a/include/netlink/route/sch/sfq.h b/include/netlink/route/sch/sfq.h deleted file mode 100644 index 7cc0b3e..0000000 --- a/include/netlink/route/sch/sfq.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * netlink/route/sch/sfq.c SFQ Qdisc - * - * 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-2011 Thomas Graf - */ - -#ifndef NETLINK_SFQ_H_ -#define NETLINK_SFQ_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -extern void rtnl_sfq_set_quantum(struct rtnl_qdisc *, int); -extern int rtnl_sfq_get_quantum(struct rtnl_qdisc *); - -extern void rtnl_sfq_set_limit(struct rtnl_qdisc *, int); -extern int rtnl_sfq_get_limit(struct rtnl_qdisc *); - -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 *); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/include/netlink/route/sch/tbf.h b/include/netlink/route/sch/tbf.h deleted file mode 100644 index 8a2144a..0000000 --- a/include/netlink/route/sch/tbf.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * netlink/route/sch/tbf.h TBF Qdisc - * - * 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-2011 Thomas Graf - */ - -#ifndef NETLINK_TBF_H_ -#define NETLINK_TBF_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -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 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 *); - -extern int rtnl_qdisc_tbf_set_peakrate(struct rtnl_qdisc *, int, int, int); -extern int rtnl_qdisc_tbf_get_peakrate(struct rtnl_qdisc *); -extern int rtnl_qdisc_tbf_get_peakrate_bucket(struct rtnl_qdisc *); -extern int rtnl_qdisc_tbf_get_peakrate_cell(struct rtnl_qdisc *); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/lib/Makefile.am b/lib/Makefile.am index 25a7ac5..ccedf43 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -60,9 +60,10 @@ libnl_route_la_SOURCES = \ route/link/api.c route/link/vlan.c \ route/link/bridge.c route/link/inet6.c route/link/inet.c \ \ - route/sch/blackhole.c route/sch/cbq.c route/sch/dsmark.c \ - route/sch/fifo.c route/sch/htb.c route/sch/netem.c route/sch/prio.c \ - route/sch/red.c route/sch/sfq.c route/sch/tbf.c \ + route/qdisc/blackhole.c route/qdisc/cbq.c route/qdisc/dsmark.c \ + route/qdisc/fifo.c route/qdisc/htb.c route/qdisc/netem.c \ + route/qdisc/prio.c route/qdisc/red.c route/qdisc/sfq.c \ + route/qdisc/tbf.c \ \ fib_lookup/lookup.c fib_lookup/request.c \ \ diff --git a/lib/cli/qdisc/bfifo.c b/lib/cli/qdisc/bfifo.c index 710d6c4..1ee4777 100644 --- a/lib/cli/qdisc/bfifo.c +++ b/lib/cli/qdisc/bfifo.c @@ -11,7 +11,7 @@ #include #include -#include +#include static void print_usage(void) { diff --git a/lib/cli/qdisc/htb.c b/lib/cli/qdisc/htb.c index 32ed272..1751595 100644 --- a/lib/cli/qdisc/htb.c +++ b/lib/cli/qdisc/htb.c @@ -11,7 +11,7 @@ #include #include -#include +#include static void print_qdisc_usage(void) { diff --git a/lib/cli/qdisc/pfifo.c b/lib/cli/qdisc/pfifo.c index 946aba6..02c4d22 100644 --- a/lib/cli/qdisc/pfifo.c +++ b/lib/cli/qdisc/pfifo.c @@ -12,7 +12,7 @@ #include #include -#include +#include static void print_usage(void) { diff --git a/lib/route/qdisc/blackhole.c b/lib/route/qdisc/blackhole.c new file mode 100644 index 0000000..06f5380 --- /dev/null +++ b/lib/route/qdisc/blackhole.c @@ -0,0 +1,37 @@ +/* + * lib/route/qdisc/blackhole.c Blackhole Qdisc + * + * 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-2011 Thomas Graf + */ + +/** + * @ingroup qdisc + * @defgroup qdisc_blackhole Blackhole + * @{ + */ + +#include +#include +#include + +static struct rtnl_tc_ops blackhole_ops = { + .to_kind = "blackhole", + .to_type = RTNL_TC_TYPE_QDISC, +}; + +static void __init blackhole_init(void) +{ + rtnl_tc_register(&blackhole_ops); +} + +static void __exit blackhole_exit(void) +{ + rtnl_tc_unregister(&blackhole_ops); +} + +/** @} */ diff --git a/lib/route/qdisc/cbq.c b/lib/route/qdisc/cbq.c new file mode 100644 index 0000000..e791a10 --- /dev/null +++ b/lib/route/qdisc/cbq.c @@ -0,0 +1,204 @@ +/* + * lib/route/qdisc/cbq.c Class Based Queueing + * + * 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-2011 Thomas Graf + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * @ingroup qdisc + * @ingroup class + * @defgroup qdisc_cbq Class Based Queueing (CBQ) + * @{ + */ + +static const struct trans_tbl ovl_strategies[] = { + __ADD(TC_CBQ_OVL_CLASSIC,classic) + __ADD(TC_CBQ_OVL_DELAY,delay) + __ADD(TC_CBQ_OVL_LOWPRIO,lowprio) + __ADD(TC_CBQ_OVL_DROP,drop) + __ADD(TC_CBQ_OVL_RCLASSIC,rclassic) +}; + +/** + * Convert a CBQ OVL strategy to a character string + * @arg type CBQ OVL strategy + * @arg buf destination buffer + * @arg len length of destination buffer + * + * Converts a CBQ OVL strategy to a character string and stores in the + * provided buffer. Returns the destination buffer or the type + * encoded in hex if no match was found. + */ +char *nl_ovl_strategy2str(int type, char *buf, size_t len) +{ + return __type2str(type, buf, len, ovl_strategies, + ARRAY_SIZE(ovl_strategies)); +} + +/** + * Convert a string to a CBQ OVL strategy + * @arg name CBQ OVL stragegy name + * + * Converts a CBQ OVL stragegy name to it's corresponding CBQ OVL strategy + * type. Returns the type or -1 if none was found. + */ +int nl_str2ovl_strategy(const char *name) +{ + return __str2type(name, ovl_strategies, ARRAY_SIZE(ovl_strategies)); +} + +static struct nla_policy cbq_policy[TCA_CBQ_MAX+1] = { + [TCA_CBQ_LSSOPT] = { .minlen = sizeof(struct tc_cbq_lssopt) }, + [TCA_CBQ_RATE] = { .minlen = sizeof(struct tc_ratespec) }, + [TCA_CBQ_WRROPT] = { .minlen = sizeof(struct tc_cbq_wrropt) }, + [TCA_CBQ_OVL_STRATEGY] = { .minlen = sizeof(struct tc_cbq_ovl) }, + [TCA_CBQ_FOPT] = { .minlen = sizeof(struct tc_cbq_fopt) }, + [TCA_CBQ_POLICE] = { .minlen = sizeof(struct tc_cbq_police) }, +}; + +static int cbq_msg_parser(struct rtnl_tc *tc, void *data) +{ + struct nlattr *tb[TCA_CBQ_MAX + 1]; + struct rtnl_cbq *cbq = data; + int err; + + err = tca_parse(tb, TCA_CBQ_MAX, tc, cbq_policy); + if (err < 0) + return err; + + 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)); + nla_memcpy(&cbq->cbq_fopt, tb[TCA_CBQ_FOPT], sizeof(cbq->cbq_fopt)); + nla_memcpy(&cbq->cbq_ovl, tb[TCA_CBQ_OVL_STRATEGY], + sizeof(cbq->cbq_ovl)); + nla_memcpy(&cbq->cbq_police, tb[TCA_CBQ_POLICE], + sizeof(cbq->cbq_police)); + + return 0; +} + +static void cbq_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_cbq *cbq = data; + double r, rbit; + char *ru, *rubit; + + if (!cbq) + return; + + r = nl_cancel_down_bytes(cbq->cbq_rate.rate, &ru); + rbit = nl_cancel_down_bits(cbq->cbq_rate.rate * 8, &rubit); + + nl_dump(p, " rate %.2f%s/s (%.0f%s) prio %u", + r, ru, rbit, rubit, cbq->cbq_wrr.priority); +} + +static void cbq_dump_details(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_cbq *cbq = data; + char *unit, buf[32]; + double w; + uint32_t el; + + if (!cbq) + return; + + w = nl_cancel_down_bits(cbq->cbq_wrr.weight * 8, &unit); + + nl_dump(p, "avgpkt %u mpu %u cell %u allot %u weight %.0f%s\n", + cbq->cbq_lss.avpkt, + cbq->cbq_rate.mpu, + 1 << cbq->cbq_rate.cell_log, + cbq->cbq_wrr.allot, w, unit); + + el = cbq->cbq_lss.ewma_log; + nl_dump_line(p, " minidle %uus maxidle %uus offtime " + "%uus level %u ewma_log %u\n", + nl_ticks2us(cbq->cbq_lss.minidle >> el), + nl_ticks2us(cbq->cbq_lss.maxidle >> el), + nl_ticks2us(cbq->cbq_lss.offtime >> el), + cbq->cbq_lss.level, + cbq->cbq_lss.ewma_log); + + nl_dump_line(p, " penalty %uus strategy %s ", + nl_ticks2us(cbq->cbq_ovl.penalty), + nl_ovl_strategy2str(cbq->cbq_ovl.strategy, buf, sizeof(buf))); + + nl_dump(p, "split %s defmap 0x%08x ", + rtnl_tc_handle2str(cbq->cbq_fopt.split, buf, sizeof(buf)), + cbq->cbq_fopt.defmap); + + nl_dump(p, "police %s", + nl_police2str(cbq->cbq_police.police, buf, sizeof(buf))); +} + +static void cbq_dump_stats(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct tc_cbq_xstats *x; + + if (!(x = tca_xstats(tc))) + return; + + nl_dump_line(p, " borrows overact " + " avgidle undertime\n"); + nl_dump_line(p, " %10u %10u %10u %10u\n", + x->borrows, x->overactions, x->avgidle, x->undertime); +} + +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_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_tc_register(&cbq_qdisc_ops); + rtnl_tc_register(&cbq_class_ops); +} + +static void __exit cbq_exit(void) +{ + rtnl_tc_unregister(&cbq_qdisc_ops); + rtnl_tc_unregister(&cbq_class_ops); +} + +/** @} */ diff --git a/lib/route/qdisc/dsmark.c b/lib/route/qdisc/dsmark.c new file mode 100644 index 0000000..b5fd0d6 --- /dev/null +++ b/lib/route/qdisc/dsmark.c @@ -0,0 +1,413 @@ +/* + * lib/route/qdisc/dsmark.c DSMARK + * + * 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-2011 Thomas Graf + */ + +/** + * @ingroup qdisc + * @ingroup class + * @defgroup qdisc_dsmark Differentiated Services Marker (DSMARK) + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define SCH_DSMARK_ATTR_INDICES 0x1 +#define SCH_DSMARK_ATTR_DEFAULT_INDEX 0x2 +#define SCH_DSMARK_ATTR_SET_TC_INDEX 0x4 + +#define SCH_DSMARK_ATTR_MASK 0x1 +#define SCH_DSMARK_ATTR_VALUE 0x2 +/** @endcond */ + +static struct nla_policy dsmark_policy[TCA_DSMARK_MAX+1] = { + [TCA_DSMARK_INDICES] = { .type = NLA_U16 }, + [TCA_DSMARK_DEFAULT_INDEX] = { .type = NLA_U16 }, + [TCA_DSMARK_SET_TC_INDEX] = { .type = NLA_FLAG }, + [TCA_DSMARK_VALUE] = { .type = NLA_U8 }, + [TCA_DSMARK_MASK] = { .type = NLA_U8 }, +}; + +static int dsmark_qdisc_msg_parser(struct rtnl_tc *tc, void *data) +{ + struct rtnl_dsmark_qdisc *dsmark = data; + struct nlattr *tb[TCA_DSMARK_MAX + 1]; + int err; + + err = tca_parse(tb, TCA_DSMARK_MAX, tc, dsmark_policy); + if (err < 0) + return err; + + if (tb[TCA_DSMARK_INDICES]) { + dsmark->qdm_indices = nla_get_u16(tb[TCA_DSMARK_INDICES]); + dsmark->qdm_mask |= SCH_DSMARK_ATTR_INDICES; + } + + if (tb[TCA_DSMARK_DEFAULT_INDEX]) { + dsmark->qdm_default_index = + nla_get_u16(tb[TCA_DSMARK_DEFAULT_INDEX]); + dsmark->qdm_mask |= SCH_DSMARK_ATTR_DEFAULT_INDEX; + } + + if (tb[TCA_DSMARK_SET_TC_INDEX]) { + dsmark->qdm_set_tc_index = 1; + dsmark->qdm_mask |= SCH_DSMARK_ATTR_SET_TC_INDEX; + } + + return 0; +} + +static int dsmark_class_msg_parser(struct rtnl_tc *tc, void *data) +{ + struct rtnl_dsmark_class *dsmark = data; + struct nlattr *tb[TCA_DSMARK_MAX + 1]; + int err; + + err = tca_parse(tb, TCA_DSMARK_MAX, tc, dsmark_policy); + if (err < 0) + return err; + + if (tb[TCA_DSMARK_MASK]) { + dsmark->cdm_bmask = nla_get_u8(tb[TCA_DSMARK_MASK]); + dsmark->cdm_mask |= SCH_DSMARK_ATTR_MASK; + } + + if (tb[TCA_DSMARK_VALUE]) { + dsmark->cdm_value = nla_get_u8(tb[TCA_DSMARK_VALUE]); + dsmark->cdm_mask |= SCH_DSMARK_ATTR_VALUE; + } + + return 0; +} + +static void dsmark_qdisc_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + 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_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_dsmark_qdisc *dsmark = data; + + if (!dsmark) + return; + + if (dsmark->qdm_mask & SCH_DSMARK_ATTR_DEFAULT_INDEX) + nl_dump(p, " default index 0x%04x", dsmark->qdm_default_index); + + if (dsmark->qdm_mask & SCH_DSMARK_ATTR_SET_TC_INDEX) + nl_dump(p, " set-tc-index"); +} + +static void dsmark_class_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_dsmark_class *dsmark = data; + + if (!dsmark) + return; + + if (dsmark->cdm_mask & SCH_DSMARK_ATTR_VALUE) + nl_dump(p, " value 0x%02x", dsmark->cdm_value); + + if (dsmark->cdm_mask & SCH_DSMARK_ATTR_MASK) + nl_dump(p, " mask 0x%02x", dsmark->cdm_bmask); +} + +static int dsmark_qdisc_msg_fill(struct rtnl_tc *tc, void *data, + struct nl_msg *msg) +{ + struct rtnl_dsmark_qdisc *dsmark = data; + + if (!dsmark) + return 0; + + if (dsmark->qdm_mask & SCH_DSMARK_ATTR_INDICES) + NLA_PUT_U16(msg, TCA_DSMARK_INDICES, dsmark->qdm_indices); + + if (dsmark->qdm_mask & SCH_DSMARK_ATTR_DEFAULT_INDEX) + NLA_PUT_U16(msg, TCA_DSMARK_DEFAULT_INDEX, + dsmark->qdm_default_index); + + if (dsmark->qdm_mask & SCH_DSMARK_ATTR_SET_TC_INDEX) + NLA_PUT_FLAG(msg, TCA_DSMARK_SET_TC_INDEX); + + return 0; + +nla_put_failure: + return -NLE_MSGSIZE; +} + +static int dsmark_class_msg_fill(struct rtnl_tc *tc, void *data, + struct nl_msg *msg) +{ + struct rtnl_dsmark_class *dsmark = data; + + if (!dsmark) + return 0; + + if (dsmark->cdm_mask & SCH_DSMARK_ATTR_MASK) + NLA_PUT_U8(msg, TCA_DSMARK_MASK, dsmark->cdm_bmask); + + if (dsmark->cdm_mask & SCH_DSMARK_ATTR_VALUE) + NLA_PUT_U8(msg, TCA_DSMARK_VALUE, dsmark->cdm_value); + + return 0; + +nla_put_failure: + return -NLE_MSGSIZE; +} + +/** + * @name Class Attribute Access + * @{ + */ + +/** + * Set bitmask of DSMARK class. + * @arg class DSMARK class to be modified. + * @arg mask New bitmask. + * @return 0 on success or a negative error code. + */ +int rtnl_class_dsmark_set_bitmask(struct rtnl_class *class, uint8_t mask) +{ + struct rtnl_dsmark_class *dsmark; + + if (!(dsmark = rtnl_tc_data(TC_CAST(class)))) + return -NLE_NOMEM; + + dsmark->cdm_bmask = mask; + dsmark->cdm_mask |= SCH_DSMARK_ATTR_MASK; + + return 0; +} + +/** + * Get bitmask of DSMARK class. + * @arg class DSMARK class. + * @return Bitmask or a negative error code. + */ +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; + + if (dsmark->cdm_mask & SCH_DSMARK_ATTR_MASK) + return dsmark->cdm_bmask; + else + return -NLE_NOATTR; +} + +/** + * Set value of DSMARK class. + * @arg class DSMARK class to be modified. + * @arg value New value. + * @return 0 on success or a negative errror code. + */ +int rtnl_class_dsmark_set_value(struct rtnl_class *class, uint8_t value) +{ + struct rtnl_dsmark_class *dsmark; + + if (!(dsmark = rtnl_tc_data(TC_CAST(class)))) + return -NLE_NOMEM; + + dsmark->cdm_value = value; + dsmark->cdm_mask |= SCH_DSMARK_ATTR_VALUE; + + return 0; +} + +/** + * Get value of DSMARK class. + * @arg class DSMARK class. + * @return Value or a negative error code. + */ +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; + + if (dsmark->cdm_mask & SCH_DSMARK_ATTR_VALUE) + return dsmark->cdm_value; + else + return -NLE_NOATTR; +} + +/** @} */ + +/** + * @name Qdisc Attribute Access + * @{ + */ + +/** + * Set indices of DSMARK qdisc. + * @arg qdisc DSMARK qdisc to be modified. + * @arg indices New indices. + */ +int rtnl_qdisc_dsmark_set_indices(struct rtnl_qdisc *qdisc, uint16_t indices) +{ + struct rtnl_dsmark_qdisc *dsmark; + + if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc)))) + return -NLE_NOMEM; + + dsmark->qdm_indices = indices; + dsmark->qdm_mask |= SCH_DSMARK_ATTR_INDICES; + + return 0; +} + +/** + * Get indices of DSMARK qdisc. + * @arg qdisc DSMARK qdisc. + * @return Indices or a negative error code. + */ +int rtnl_qdisc_dsmark_get_indices(struct rtnl_qdisc *qdisc) +{ + struct rtnl_dsmark_qdisc *dsmark; + + 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; +} + +/** + * Set default index of DSMARK qdisc. + * @arg qdisc DSMARK qdisc to be modified. + * @arg default_index New default index. + * @return 0 on success or a negative error code. + */ +int rtnl_qdisc_dsmark_set_default_index(struct rtnl_qdisc *qdisc, + uint16_t default_index) +{ + struct rtnl_dsmark_qdisc *dsmark; + + if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc)))) + return -NLE_NOMEM; + + dsmark->qdm_default_index = default_index; + dsmark->qdm_mask |= SCH_DSMARK_ATTR_DEFAULT_INDEX; + + return 0; +} + +/** + * Get default index of DSMARK qdisc. + * @arg qdisc DSMARK qdisc. + * @return Default index or a negative error code. + */ +int rtnl_qdisc_dsmark_get_default_index(struct rtnl_qdisc *qdisc) +{ + struct rtnl_dsmark_qdisc *dsmark; + + 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; +} + +/** + * Set set-tc-index flag of DSMARK qdisc. + * @arg qdisc DSMARK qdisc to be modified. + * @arg flag Flag indicating whether to enable or disable. + * @return 0 on success or a negative error code. + */ +int rtnl_qdisc_dsmark_set_set_tc_index(struct rtnl_qdisc *qdisc, int flag) +{ + struct rtnl_dsmark_qdisc *dsmark; + + if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc)))) + return -NLE_NOMEM; + + dsmark->qdm_set_tc_index = !!flag; + dsmark->qdm_mask |= SCH_DSMARK_ATTR_SET_TC_INDEX; + + return 0; +} + +/** + * Get set-tc-index flag of DSMARK qdisc. + * @arg qdisc DSMARK qdisc to be modified. + * @return 1 or 0 to indicate wehther the flag is enabled or a negative + * error code. + */ +int rtnl_qdisc_dsmark_get_set_tc_index(struct rtnl_qdisc *qdisc) +{ + struct rtnl_dsmark_qdisc *dsmark; + + 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; +} + +/** @} */ + +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, + }, + .to_msg_fill = dsmark_qdisc_msg_fill, +}; + +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_tc_register(&dsmark_qdisc_ops); + rtnl_tc_register(&dsmark_class_ops); +} + +static void __exit dsmark_exit(void) +{ + rtnl_tc_unregister(&dsmark_qdisc_ops); + rtnl_tc_unregister(&dsmark_class_ops); +} + +/** @} */ diff --git a/lib/route/qdisc/fifo.c b/lib/route/qdisc/fifo.c new file mode 100644 index 0000000..e87c79a --- /dev/null +++ b/lib/route/qdisc/fifo.c @@ -0,0 +1,169 @@ +/* + * lib/route/qdisc/fifo.c (p|b)fifo + * + * 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-2011 Thomas Graf + */ + +/** + * @ingroup qdisc + * @defgroup qdisc_fifo Packet/Bytes FIFO (pfifo/bfifo) + * @brief + * + * The FIFO qdisc comes in two flavours: + * @par bfifo (Byte FIFO) + * Allows enqueuing until the currently queued volume in bytes exceeds + * the configured limit.backlog contains currently enqueued volume in bytes. + * + * @par pfifo (Packet FIFO) + * Allows enquueing until the currently queued number of packets + * exceeds the configured limit. + * + * 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_tc_set_kind()). + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define SCH_FIFO_ATTR_LIMIT 1 +/** @endcond */ + +static int fifo_msg_parser(struct rtnl_tc *tc, void *data) +{ + struct rtnl_fifo *fifo = data; + struct tc_fifo_qopt *opt; + + if (tc->tc_opts->d_size < sizeof(struct tc_fifo_qopt)) + return -NLE_INVAL; + + 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 pfifo_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_fifo *fifo = data; + + if (fifo) + nl_dump(p, " limit %u packets", fifo->qf_limit); +} + +static void bfifo_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_fifo *fifo = data; + char *unit; + double r; + + if (!fifo) + return; + + r = nl_cancel_down_bytes(fifo->qf_limit, &unit); + nl_dump(p, " limit %.1f%s", r, unit); +} + +static int fifo_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) +{ + struct rtnl_fifo *fifo = data; + struct tc_fifo_qopt opts = {0}; + + if (!fifo || !(fifo->qf_mask & SCH_FIFO_ATTR_LIMIT)) + return -NLE_INVAL; + + opts.limit = fifo->qf_limit; + + return nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD); +} + +/** + * @name Attribute Modification + * @{ + */ + +/** + * Set limit of FIFO qdisc. + * @arg qdisc FIFO qdisc to be modified. + * @arg limit New limit. + * @return 0 on success or a negative error code. + */ +int rtnl_qdisc_fifo_set_limit(struct rtnl_qdisc *qdisc, int limit) +{ + struct rtnl_fifo *fifo; + + if (!(fifo = rtnl_tc_data(TC_CAST(qdisc)))) + return -NLE_NOMEM; + + fifo->qf_limit = limit; + fifo->qf_mask |= SCH_FIFO_ATTR_LIMIT; + + return 0; +} + +/** + * Get limit of a FIFO qdisc. + * @arg qdisc FIFO qdisc. + * @return Numeric limit or a negative error code. + */ +int rtnl_qdisc_fifo_get_limit(struct rtnl_qdisc *qdisc) +{ + struct rtnl_fifo *fifo; + + 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; +} + +/** @} */ + +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_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_tc_register(&pfifo_ops); + rtnl_tc_register(&bfifo_ops); +} + +static void __exit fifo_exit(void) +{ + rtnl_tc_unregister(&pfifo_ops); + rtnl_tc_unregister(&bfifo_ops); +} + +/** @} */ diff --git a/lib/route/qdisc/htb.c b/lib/route/qdisc/htb.c new file mode 100644 index 0000000..94185de --- /dev/null +++ b/lib/route/qdisc/htb.c @@ -0,0 +1,433 @@ +/* + * lib/route/qdisc/htb.c HTB Qdisc + * + * 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-2011 Thomas Graf + * Copyright (c) 2005-2006 Petr Gotthard + * Copyright (c) 2005-2006 Siemens AG Oesterreich + */ + +/** + * @ingroup qdisc + * @ingroup class + * @defgroup qdisc_htb Hierachical Token Bucket (HTB) + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define SCH_HTB_HAS_RATE2QUANTUM 0x01 +#define SCH_HTB_HAS_DEFCLS 0x02 + +#define SCH_HTB_HAS_PRIO 0x001 +#define SCH_HTB_HAS_RATE 0x002 +#define SCH_HTB_HAS_CEIL 0x004 +#define SCH_HTB_HAS_RBUFFER 0x008 +#define SCH_HTB_HAS_CBUFFER 0x010 +#define SCH_HTB_HAS_QUANTUM 0x020 +/** @endcond */ + +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_tc *tc, void *data) +{ + struct nlattr *tb[TCA_HTB_MAX + 1]; + struct rtnl_htb_qdisc *htb = data; + int err; + + if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0) + return err; + + if (tb[TCA_HTB_INIT]) { + struct tc_htb_glob opts; + + nla_memcpy(&opts, tb[TCA_HTB_INIT], sizeof(opts)); + htb->qh_rate2quantum = opts.rate2quantum; + htb->qh_defcls = opts.defcls; + + htb->qh_mask = (SCH_HTB_HAS_RATE2QUANTUM | SCH_HTB_HAS_DEFCLS); + } + + return 0; +} + +static int htb_class_msg_parser(struct rtnl_tc *tc, void *data) +{ + struct nlattr *tb[TCA_HTB_MAX + 1]; + struct rtnl_htb_class *htb = data; + int err; + + if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0) + return err; + + if (tb[TCA_HTB_PARMS]) { + struct tc_htb_opt opts; + + nla_memcpy(&opts, tb[TCA_HTB_PARMS], sizeof(opts)); + 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, htb->ch_rate.rs_mpu); + rtnl_tc_set_overhead(tc, htb->ch_rate.rs_overhead); + + 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_qdisc_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_htb_qdisc *htb = data; + + if (!htb) + return; + + if (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM) + nl_dump(p, " r2q %u", htb->qh_rate2quantum); + + if (htb->qh_mask & SCH_HTB_HAS_DEFCLS) { + char buf[32]; + nl_dump(p, " default %s", + rtnl_tc_handle2str(htb->qh_defcls, buf, sizeof(buf))); + } +} + +static void htb_class_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_htb_class *htb = data; + + if (!htb) + return; + + if (htb->ch_mask & SCH_HTB_HAS_RATE) { + double r, rbit; + char *ru, *rubit; + + r = nl_cancel_down_bytes(htb->ch_rate.rs_rate, &ru); + rbit = nl_cancel_down_bits(htb->ch_rate.rs_rate*8, &rubit); + + nl_dump(p, " rate %.2f%s/s (%.0f%s) log %u", + r, ru, rbit, rubit, 1<ch_rate.rs_cell_log); + } +} + +static void htb_class_dump_details(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_htb_class *htb = data; + + if (!htb) + return; + + /* line 1 */ + if (htb->ch_mask & SCH_HTB_HAS_CEIL) { + double r, rbit; + char *ru, *rubit; + + r = nl_cancel_down_bytes(htb->ch_ceil.rs_rate, &ru); + rbit = nl_cancel_down_bits(htb->ch_ceil.rs_rate*8, &rubit); + + nl_dump(p, " ceil %.2f%s/s (%.0f%s) log %u", + r, ru, rbit, rubit, 1<ch_ceil.rs_cell_log); + } + + if (htb->ch_mask & SCH_HTB_HAS_PRIO) + nl_dump(p, " prio %u", htb->ch_prio); + + if (htb->ch_mask & SCH_HTB_HAS_RBUFFER) { + double b; + char *bu; + + b = nl_cancel_down_bytes(htb->ch_rbuffer, &bu); + nl_dump(p, " rbuffer %.2f%s", b, bu); + } + + if (htb->ch_mask & SCH_HTB_HAS_CBUFFER) { + double b; + char *bu; + + b = nl_cancel_down_bytes(htb->ch_cbuffer, &bu); + nl_dump(p, " cbuffer %.2f%s", b, bu); + } + + if (htb->ch_mask & SCH_HTB_HAS_QUANTUM) + nl_dump(p, " quantum %u", htb->ch_quantum); +} + +static int htb_qdisc_msg_fill(struct rtnl_tc *tc, void *data, + struct nl_msg *msg) +{ + struct rtnl_htb_qdisc *htb = data; + struct tc_htb_glob opts = {0}; + + opts.version = TC_HTB_PROTOVER; + opts.rate2quantum = 10; + + 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; + } + + return nla_put(msg, TCA_HTB_INIT, sizeof(opts), &opts); +} + +static int htb_class_msg_fill(struct rtnl_tc *tc, void *data, + struct nl_msg *msg) +{ + struct rtnl_htb_class *htb = data; + uint32_t mtu, rtable[RTNL_TC_RTABLE_SIZE], ctable[RTNL_TC_RTABLE_SIZE]; + struct tc_htb_opt opts; + int buffer, cbuffer; + + if (!htb || !(htb->ch_mask & SCH_HTB_HAS_RATE)) + BUG(); + + /* 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)); + + mtu = rtnl_tc_get_mtu(tc); + + rtnl_tc_build_rate_table(tc, &htb->ch_rate, rtable); + rtnl_rcopy_ratespec(&opts.rate, &htb->ch_rate); + + 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 + * no borrowing. + */ + memcpy(&opts.ceil, &opts.rate, sizeof(struct tc_ratespec)); + } + + 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 (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 (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); + + return 0; + +nla_put_failure: + return -NLE_MSGSIZE; +} + +/** + * @name Attribute Modifications + * @{ + */ + +void rtnl_htb_set_rate2quantum(struct rtnl_qdisc *qdisc, uint32_t rate2quantum) +{ + struct rtnl_htb_qdisc *htb; + + if (!(htb = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + htb->qh_rate2quantum = rate2quantum; + htb->qh_mask |= SCH_HTB_HAS_RATE2QUANTUM; +} + +/** + * Set default class of the htb qdisc to the specified value + * @arg qdisc qdisc to change + * @arg defcls new default class + */ +void rtnl_htb_set_defcls(struct rtnl_qdisc *qdisc, uint32_t defcls) +{ + struct rtnl_htb_qdisc *htb; + + 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 *htb; + + if (!(htb = rtnl_tc_data(TC_CAST(class)))) + BUG(); + + htb->ch_prio = prio; + htb->ch_mask |= SCH_HTB_HAS_PRIO; +} + +/** + * Set rate of HTB class. + * @arg class HTB class to be modified. + * @arg rate New rate in bytes per second. + */ +void rtnl_htb_set_rate(struct rtnl_class *class, uint32_t rate) +{ + struct rtnl_htb_class *htb; + + 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 *htb; + + if (!(htb = rtnl_tc_data(TC_CAST(class)))) + return 0; + + return htb->ch_rate.rs_rate; +} + +/** + * Set ceil of HTB class. + * @arg class HTB class to be modified. + * @arg ceil New ceil in bytes per second. + */ +void rtnl_htb_set_ceil(struct rtnl_class *class, uint32_t ceil) +{ + struct rtnl_htb_class *htb; + + 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; +} + +/** + * Set size of the rate bucket of HTB class. + * @arg class HTB class to be modified. + * @arg rbuffer New size in bytes. + */ +void rtnl_htb_set_rbuffer(struct rtnl_class *class, uint32_t rbuffer) +{ + struct rtnl_htb_class *htb; + + if (!(htb = rtnl_tc_data(TC_CAST(class)))) + BUG(); + + htb->ch_rbuffer = rbuffer; + htb->ch_mask |= SCH_HTB_HAS_RBUFFER; +} + +/** + * Set size of the ceil bucket of HTB class. + * @arg class HTB class to be modified. + * @arg cbuffer New size in bytes. + */ +void rtnl_htb_set_cbuffer(struct rtnl_class *class, uint32_t cbuffer) +{ + struct rtnl_htb_class *htb; + + if (!(htb = rtnl_tc_data(TC_CAST(class)))) + BUG(); + + htb->ch_cbuffer = cbuffer; + htb->ch_mask |= SCH_HTB_HAS_CBUFFER; +} + +/** + * Set how much bytes to serve from leaf at once of HTB class {use r2q}. + * @arg class HTB class to be modified. + * @arg quantum New size in bytes. + */ +void rtnl_htb_set_quantum(struct rtnl_class *class, uint32_t quantum) +{ + struct rtnl_htb_class *htb; + + if (!(htb = rtnl_tc_data(TC_CAST(class)))) + BUG(); + + htb->ch_quantum = quantum; + htb->ch_mask |= SCH_HTB_HAS_QUANTUM; +} + +/** @} */ + +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_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, + }, + .to_msg_fill = htb_class_msg_fill, +}; + +static void __init htb_init(void) +{ + rtnl_tc_register(&htb_qdisc_ops); + rtnl_tc_register(&htb_class_ops); +} + +static void __exit htb_exit(void) +{ + rtnl_tc_unregister(&htb_qdisc_ops); + rtnl_tc_unregister(&htb_class_ops); +} + +/** @} */ diff --git a/lib/route/qdisc/netem.c b/lib/route/qdisc/netem.c new file mode 100644 index 0000000..c86af56 --- /dev/null +++ b/lib/route/qdisc/netem.c @@ -0,0 +1,905 @@ +/* + * lib/route/qdisc/netem.c Network Emulator Qdisc + * + * 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-2011 Thomas Graf + */ + +/** + * @ingroup qdisc + * @defgroup qdisc_netem Network Emulator + * @brief + * + * For further documentation see http://linux-net.osdl.org/index.php/Netem + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define SCH_NETEM_ATTR_LATENCY 0x0001 +#define SCH_NETEM_ATTR_LIMIT 0x0002 +#define SCH_NETEM_ATTR_LOSS 0x0004 +#define SCH_NETEM_ATTR_GAP 0x0008 +#define SCH_NETEM_ATTR_DUPLICATE 0x0010 +#define SCH_NETEM_ATTR_JITTER 0x0020 +#define SCH_NETEM_ATTR_DELAY_CORR 0x0040 +#define SCH_NETEM_ATTR_LOSS_CORR 0x0080 +#define SCH_NETEM_ATTR_DUP_CORR 0x0100 +#define SCH_NETEM_ATTR_RO_PROB 0x0200 +#define SCH_NETEM_ATTR_RO_CORR 0x0400 +#define SCH_NETEM_ATTR_CORRUPT_PROB 0x0800 +#define SCH_NETEM_ATTR_CORRUPT_CORR 0x1000 +#define SCH_NETEM_ATTR_DIST 0x2000 +/** @endcond */ + +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_tc *tc, void *data) +{ + struct rtnl_netem *netem = data; + struct tc_netem_qopt *opts; + int len, err = 0; + + if (tc->tc_opts->d_size < sizeof(*opts)) + return -NLE_INVAL; + + 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; + netem->qnm_gap = opts->gap; + netem->qnm_duplicate = opts->duplicate; + netem->qnm_jitter = opts->jitter; + + netem->qnm_mask = (SCH_NETEM_ATTR_LATENCY | SCH_NETEM_ATTR_LIMIT | + SCH_NETEM_ATTR_LOSS | SCH_NETEM_ATTR_GAP | + SCH_NETEM_ATTR_DUPLICATE | SCH_NETEM_ATTR_JITTER); + + 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 *) + (tc->tc_opts->d_data + sizeof(*opts)), + len, netem_policy); + if (err < 0) { + free(netem); + return err; + } + + if (tb[TCA_NETEM_CORR]) { + struct tc_netem_corr cor; + + nla_memcpy(&cor, tb[TCA_NETEM_CORR], sizeof(cor)); + netem->qnm_corr.nmc_delay = cor.delay_corr; + netem->qnm_corr.nmc_loss = cor.loss_corr; + netem->qnm_corr.nmc_duplicate = cor.dup_corr; + + netem->qnm_mask |= (SCH_NETEM_ATTR_DELAY_CORR | + SCH_NETEM_ATTR_LOSS_CORR | + SCH_NETEM_ATTR_DUP_CORR); + } + + if (tb[TCA_NETEM_REORDER]) { + struct tc_netem_reorder ro; + + nla_memcpy(&ro, tb[TCA_NETEM_REORDER], sizeof(ro)); + netem->qnm_ro.nmro_probability = ro.probability; + netem->qnm_ro.nmro_correlation = ro.correlation; + + netem->qnm_mask |= (SCH_NETEM_ATTR_RO_PROB | + SCH_NETEM_ATTR_RO_CORR); + } + + if (tb[TCA_NETEM_CORRUPT]) { + struct tc_netem_corrupt corrupt; + + nla_memcpy(&corrupt, tb[TCA_NETEM_CORRUPT], sizeof(corrupt)); + netem->qnm_crpt.nmcr_probability = corrupt.probability; + netem->qnm_crpt.nmcr_correlation = corrupt.correlation; + + netem->qnm_mask |= (SCH_NETEM_ATTR_CORRUPT_PROB | + SCH_NETEM_ATTR_CORRUPT_CORR); + } + + /* sch_netem does not currently dump TCA_NETEM_DELAY_DIST */ + netem->qnm_dist.dist_data = NULL; + netem->qnm_dist.dist_size = 0; + } + + return 0; +} + +static void netem_free_data(struct rtnl_tc *tc, void *data) +{ + struct rtnl_netem *netem = data; + + if (!netem) + return; + + free(netem->qnm_dist.dist_data); +} + +static void netem_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_netem *netem = data; + + if (netem) + nl_dump(p, "limit %d", netem->qnm_limit); +} + +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 = 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)); + + msg->nm_nlh->nlmsg_flags |= NLM_F_REQUEST; + + if ( netem->qnm_ro.nmro_probability != 0 ) { + if (netem->qnm_latency == 0) { + return -NLE_MISSING_ATTR; + } + if (netem->qnm_gap == 0) netem->qnm_gap = 1; + } + else if ( netem->qnm_gap ) { + return -NLE_MISSING_ATTR; + } + + if ( netem->qnm_corr.nmc_delay != 0 ) { + if ( netem->qnm_latency == 0 || netem->qnm_jitter == 0) { + return -NLE_MISSING_ATTR; + } + set_correlation = 1; + } + + if ( netem->qnm_corr.nmc_loss != 0 ) { + if ( netem->qnm_loss == 0 ) { + return -NLE_MISSING_ATTR; + } + set_correlation = 1; + } + + if ( netem->qnm_corr.nmc_duplicate != 0 ) { + if ( netem->qnm_duplicate == 0 ) { + return -NLE_MISSING_ATTR; + } + set_correlation = 1; + } + + if ( netem->qnm_ro.nmro_probability != 0 ) set_reorder = 1; + else if ( netem->qnm_ro.nmro_correlation != 0 ) { + return -NLE_MISSING_ATTR; + } + + if ( netem->qnm_crpt.nmcr_probability != 0 ) set_corrupt = 1; + else if ( netem->qnm_crpt.nmcr_correlation != 0 ) { + return -NLE_MISSING_ATTR; + } + + if ( netem->qnm_dist.dist_data && netem->qnm_dist.dist_size ) { + if (netem->qnm_latency == 0 || netem->qnm_jitter == 0) { + return -NLE_MISSING_ATTR; + } + else { + /* Resize to accomodate the large distribution table */ + int new_msg_len = msg->nm_size + netem->qnm_dist.dist_size * + sizeof(netem->qnm_dist.dist_data[0]); + + msg->nm_nlh = (struct nlmsghdr *) realloc(msg->nm_nlh, new_msg_len); + if ( msg->nm_nlh == NULL ) + return -NLE_NOMEM; + msg->nm_size = new_msg_len; + set_dist = 1; + } + } + + opts.latency = netem->qnm_latency; + opts.limit = netem->qnm_limit ? netem->qnm_limit : 1000; + opts.loss = netem->qnm_loss; + opts.gap = netem->qnm_gap; + opts.duplicate = netem->qnm_duplicate; + opts.jitter = netem->qnm_jitter; + + NLA_PUT(msg, TCA_OPTIONS, sizeof(opts), &opts); + + if ( set_correlation ) { + cor.delay_corr = netem->qnm_corr.nmc_delay; + cor.loss_corr = netem->qnm_corr.nmc_loss; + cor.dup_corr = netem->qnm_corr.nmc_duplicate; + + NLA_PUT(msg, TCA_NETEM_CORR, sizeof(cor), &cor); + } + + if ( set_reorder ) { + reorder.probability = netem->qnm_ro.nmro_probability; + reorder.correlation = netem->qnm_ro.nmro_correlation; + + NLA_PUT(msg, TCA_NETEM_REORDER, sizeof(reorder), &reorder); + } + + if ( set_corrupt ) { + corrupt.probability = netem->qnm_crpt.nmcr_probability; + corrupt.correlation = netem->qnm_crpt.nmcr_correlation; + + NLA_PUT(msg, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt); + } + + if ( set_dist ) { + NLA_PUT(msg, TCA_NETEM_DELAY_DIST, + netem->qnm_dist.dist_size * sizeof(netem->qnm_dist.dist_data[0]), + netem->qnm_dist.dist_data); + } + + /* Length specified in the TCA_OPTIONS section must span the entire + * remainder of the message. That's just the way that sch_netem expects it. + * Maybe there's a more succinct way to do this at a higher level. + */ + struct nlattr* head = (struct nlattr *)(NLMSG_DATA(msg->nm_nlh) + + NLMSG_LENGTH(sizeof(struct tcmsg)) - NLMSG_ALIGNTO); + + struct nlattr* tail = (struct nlattr *)(((void *) (msg->nm_nlh)) + + NLMSG_ALIGN(msg->nm_nlh->nlmsg_len)); + + int old_len = head->nla_len; + head->nla_len = (void *)tail - (void *)head; + msg->nm_nlh->nlmsg_len += (head->nla_len - old_len); + + return err; +nla_put_failure: + return -NLE_MSGSIZE; +} + +/** + * @name Queue Limit + * @{ + */ + +/** + * Set limit of netem qdisc. + * @arg qdisc Netem qdisc to be modified. + * @arg limit New limit in bytes. + * @return 0 on success or a negative error code. + */ +void rtnl_netem_set_limit(struct rtnl_qdisc *qdisc, int limit) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + netem->qnm_limit = limit; + netem->qnm_mask |= SCH_NETEM_ATTR_LIMIT; +} + +/** + * Get limit of netem qdisc. + * @arg qdisc Netem qdisc. + * @return Limit in bytes or a negative error code. + */ +int rtnl_netem_get_limit(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + 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; +} + +/** @} */ + +/** + * @name Packet Re-ordering + * @{ + */ + +/** + * Set re-ordering gap of netem qdisc. + * @arg qdisc Netem qdisc to be modified. + * @arg gap New gap in number of packets. + * @return 0 on success or a negative error code. + */ +void rtnl_netem_set_gap(struct rtnl_qdisc *qdisc, int gap) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + netem->qnm_gap = gap; + netem->qnm_mask |= SCH_NETEM_ATTR_GAP; +} + +/** + * Get re-ordering gap of netem qdisc. + * @arg qdisc Netem qdisc. + * @return Re-ordering gap in packets or a negative error code. + */ +int rtnl_netem_get_gap(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + 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; +} + +/** + * Set re-ordering probability of netem qdisc. + * @arg qdisc Netem qdisc to be modified. + * @arg prob New re-ordering probability. + * @return 0 on success or a negative error code. + */ +void rtnl_netem_set_reorder_probability(struct rtnl_qdisc *qdisc, int prob) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + netem->qnm_ro.nmro_probability = prob; + netem->qnm_mask |= SCH_NETEM_ATTR_RO_PROB; +} + +/** + * Get re-ordering probability of netem qdisc. + * @arg qdisc Netem qdisc. + * @return Re-ordering probability or a negative error code. + */ +int rtnl_netem_get_reorder_probability(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + 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; +} + +/** + * Set re-order correlation probability of netem qdisc. + * @arg qdisc Netem qdisc to be modified. + * @arg prob New re-ordering correlation probability. + * @return 0 on success or a negative error code. + */ +void rtnl_netem_set_reorder_correlation(struct rtnl_qdisc *qdisc, int prob) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + netem->qnm_ro.nmro_correlation = prob; + netem->qnm_mask |= SCH_NETEM_ATTR_RO_CORR; +} + +/** + * Get re-ordering correlation probability of netem qdisc. + * @arg qdisc Netem qdisc. + * @return Re-ordering correlation probability or a negative error code. + */ +int rtnl_netem_get_reorder_correlation(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + 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; +} + +/** @} */ + +/** + * @name Corruption + * @{ + */ + +/** + * Set corruption probability of netem qdisc. + * @arg qdisc Netem qdisc to be modified. + * @arg prob New corruption probability. + * @return 0 on success or a negative error code. + */ +void rtnl_netem_set_corruption_probability(struct rtnl_qdisc *qdisc, int prob) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + netem->qnm_crpt.nmcr_probability = prob; + netem->qnm_mask |= SCH_NETEM_ATTR_CORRUPT_PROB; +} + +/** + * Get corruption probability of netem qdisc. + * @arg qdisc Netem qdisc. + * @return Corruption probability or a negative error code. + */ +int rtnl_netem_get_corruption_probability(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + 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; +} + +/** + * Set corruption correlation probability of netem qdisc. + * @arg qdisc Netem qdisc to be modified. + * @arg prob New corruption correlation probability. + * @return 0 on success or a negative error code. + */ +void rtnl_netem_set_corruption_correlation(struct rtnl_qdisc *qdisc, int prob) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + netem->qnm_crpt.nmcr_correlation = prob; + netem->qnm_mask |= SCH_NETEM_ATTR_CORRUPT_CORR; +} + +/** + * Get corruption correlation probability of netem qdisc. + * @arg qdisc Netem qdisc. + * @return Corruption correlation probability or a negative error code. + */ +int rtnl_netem_get_corruption_correlation(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + 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; +} + +/** @} */ + +/** + * @name Packet Loss + * @{ + */ + +/** + * Set packet loss probability of netem qdisc. + * @arg qdisc Netem qdisc to be modified. + * @arg prob New packet loss probability. + * @return 0 on success or a negative error code. + */ +void rtnl_netem_set_loss(struct rtnl_qdisc *qdisc, int prob) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + netem->qnm_loss = prob; + netem->qnm_mask |= SCH_NETEM_ATTR_LOSS; +} + +/** + * Get packet loss probability of netem qdisc. + * @arg qdisc Netem qdisc. + * @return Packet loss probability or a negative error code. + */ +int rtnl_netem_get_loss(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + 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; +} + +/** + * Set packet loss correlation probability of netem qdisc. + * @arg qdisc Netem qdisc to be modified. + * @arg prob New packet loss correlation. + * @return 0 on success or a negative error code. + */ +void rtnl_netem_set_loss_correlation(struct rtnl_qdisc *qdisc, int prob) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + netem->qnm_corr.nmc_loss = prob; + netem->qnm_mask |= SCH_NETEM_ATTR_LOSS_CORR; +} + +/** + * Get packet loss correlation probability of netem qdisc. + * @arg qdisc Netem qdisc. + * @return Packet loss correlation probability or a negative error code. + */ +int rtnl_netem_get_loss_correlation(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + 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; +} + +/** @} */ + +/** + * @name Packet Duplication + * @{ + */ + +/** + * Set packet duplication probability of netem qdisc. + * @arg qdisc Netem qdisc to be modified. + * @arg prob New packet duplication probability. + * @return 0 on success or a negative error code. + */ +void rtnl_netem_set_duplicate(struct rtnl_qdisc *qdisc, int prob) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + netem->qnm_duplicate = prob; + netem->qnm_mask |= SCH_NETEM_ATTR_DUPLICATE; +} + +/** + * Get packet duplication probability of netem qdisc. + * @arg qdisc Netem qdisc. + * @return Packet duplication probability or a negative error code. + */ +int rtnl_netem_get_duplicate(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + 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; +} + +/** + * Set packet duplication correlation probability of netem qdisc. + * @arg qdisc Netem qdisc to be modified. + * @arg prob New packet duplication correlation probability. + * @return 0 on sucess or a negative error code. + */ +void rtnl_netem_set_duplicate_correlation(struct rtnl_qdisc *qdisc, int prob) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + netem->qnm_corr.nmc_duplicate = prob; + netem->qnm_mask |= SCH_NETEM_ATTR_DUP_CORR; +} + +/** + * Get packet duplication correlation probability of netem qdisc. + * @arg qdisc Netem qdisc. + * @return Packet duplication correlation probability or a negative error code. + */ +int rtnl_netem_get_duplicate_correlation(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + 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; +} + +/** @} */ + +/** + * @name Packet Delay + * @{ + */ + +/** + * Set packet delay of netem qdisc. + * @arg qdisc Netem qdisc to be modified. + * @arg delay New packet delay in micro seconds. + * @return 0 on success or a negative error code. + */ +void rtnl_netem_set_delay(struct rtnl_qdisc *qdisc, int delay) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + netem->qnm_latency = nl_us2ticks(delay); + netem->qnm_mask |= SCH_NETEM_ATTR_LATENCY; +} + +/** + * Get packet delay of netem qdisc. + * @arg qdisc Netem qdisc. + * @return Packet delay in micro seconds or a negative error code. + */ +int rtnl_netem_get_delay(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + 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; +} + +/** + * Set packet delay jitter of netem qdisc. + * @arg qdisc Netem qdisc to be modified. + * @arg jitter New packet delay jitter in micro seconds. + * @return 0 on success or a negative error code. + */ +void rtnl_netem_set_jitter(struct rtnl_qdisc *qdisc, int jitter) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + netem->qnm_jitter = nl_us2ticks(jitter); + netem->qnm_mask |= SCH_NETEM_ATTR_JITTER; +} + +/** + * Get packet delay jitter of netem qdisc. + * @arg qdisc Netem qdisc. + * @return Packet delay jitter in micro seconds or a negative error code. + */ +int rtnl_netem_get_jitter(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + 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; +} + +/** + * Set packet delay correlation probability of netem qdisc. + * @arg qdisc Netem qdisc to be modified. + * @arg prob New packet delay correlation probability. + */ +void rtnl_netem_set_delay_correlation(struct rtnl_qdisc *qdisc, int prob) +{ + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + netem->qnm_corr.nmc_delay = prob; + netem->qnm_mask |= SCH_NETEM_ATTR_DELAY_CORR; +} + +/** + * Get packet delay correlation probability of netem qdisc. + * @arg qdisc Netem qdisc. + * @return Packet delay correlation probability or a negative error code. + */ +int rtnl_netem_get_delay_correlation(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + 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; +} + +/** + * Get the size of the distribution table. + * @arg qdisc Netem qdisc. + * @return Distribution table size or a negative error code. + */ +int rtnl_netem_get_delay_distribution_size(struct rtnl_qdisc *qdisc) +{ + struct rtnl_netem *netem; + + 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; +} + +/** + * Get a pointer to the distribution table. + * @arg qdisc Netem qdisc. + * @arg dist_ptr The pointer to set. + * @return Negative error code on failure or 0 on success. + */ +int rtnl_netem_get_delay_distribution(struct rtnl_qdisc *qdisc, int16_t **dist_ptr) +{ + struct rtnl_netem *netem; + + 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 + return -NLE_NOATTR; +} + +/** + * Set the delay distribution. Latency/jitter must be set before applying. + * @arg qdisc Netem qdisc. + * @arg dist_type The name of the distribution (type, file, path/file). + * @return 0 on success, error code on failure. + */ +int rtnl_netem_set_delay_distribution(struct rtnl_qdisc *qdisc, const char *dist_type) { + struct rtnl_netem *netem; + + if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + FILE *f = NULL; + int i, n = 0; + size_t len = 2048; + char *line; + char name[NAME_MAX]; + char dist_suffix[] = ".dist"; + + /* If the given filename already ends in .dist, don't append it later */ + char *test_suffix = strstr(dist_type, dist_suffix); + if (test_suffix != NULL && strlen(test_suffix) == 5) + strcpy(dist_suffix, ""); + + /* Check several locations for the dist file */ + char *test_path[] = { "", "./", "/usr/lib/tc/", "/usr/local/lib/tc/" }; + + for (i = 0; i < sizeof(test_path) && f == NULL; i++) { + snprintf(name, NAME_MAX, "%s%s%s", test_path[i], dist_type, dist_suffix); + f = fopen(name, "r"); + } + + if ( f == NULL ) + return -nl_syserr2nlerr(errno); + + netem->qnm_dist.dist_data = (int16_t *) calloc (MAXDIST, sizeof(int16_t)); + + line = (char *) calloc (sizeof(char), len + 1); + + while (getline(&line, &len, f) != -1) { + char *p, *endp; + + if (*line == '\n' || *line == '#') + continue; + + for (p = line; ; p = endp) { + long x = strtol(p, &endp, 0); + if (endp == p) break; + + if (n >= MAXDIST) { + free(line); + fclose(f); + return -NLE_INVAL; + } + netem->qnm_dist.dist_data[n++] = x; + } + } + + free(line); + + netem->qnm_dist.dist_size = n; + netem->qnm_mask |= SCH_NETEM_ATTR_DIST; + + fclose(f); + return 0; +} + +/** @} */ + +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_tc_register(&netem_ops); +} + +static void __exit netem_exit(void) +{ + rtnl_tc_unregister(&netem_ops); +} + +/** @} */ diff --git a/lib/route/qdisc/prio.c b/lib/route/qdisc/prio.c new file mode 100644 index 0000000..2433c61 --- /dev/null +++ b/lib/route/qdisc/prio.c @@ -0,0 +1,294 @@ +/* + * lib/route/qdisc/prio.c PRIO Qdisc/Class + * + * 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-2011 Thomas Graf + */ + +/** + * @ingroup qdisc + * @defgroup qdisc_prio (Fast) Prio + * @brief + * + * @par 1) Typical PRIO configuration + * @code + * // Specify the maximal number of bands to be used for this PRIO qdisc. + * rtnl_qdisc_prio_set_bands(qdisc, QDISC_PRIO_DEFAULT_BANDS); + * + * // Provide a map assigning each priority to a band number. + * uint8_t map[] = QDISC_PRIO_DEFAULT_PRIOMAP; + * rtnl_qdisc_prio_set_priomap(qdisc, map, sizeof(map)); + * @endcode + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define SCH_PRIO_ATTR_BANDS 1 +#define SCH_PRIO_ATTR_PRIOMAP 2 +/** @endcond */ + +static int prio_msg_parser(struct rtnl_tc *tc, void *data) +{ + struct rtnl_prio *prio = data; + struct tc_prio_qopt *opt; + + if (tc->tc_opts->d_size < sizeof(*opt)) + return -NLE_INVAL; + + 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); + + return 0; +} + +static void prio_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_prio *prio = data; + + if (prio) + nl_dump(p, " bands %u", prio->qp_bands); +} + +static void prio_dump_details(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_prio *prio = data; + int i, hp; + + if (!prio) + return; + + nl_dump(p, "priomap ["); + + for (i = 0; i <= TC_PRIO_MAX; i++) + nl_dump(p, "%u%s", prio->qp_priomap[i], + i < TC_PRIO_MAX ? " " : ""); + + nl_dump(p, "]\n"); + nl_new_line(p); + + hp = (((TC_PRIO_MAX/2) + 1) & ~1); + + for (i = 0; i < hp; i++) { + char a[32]; + nl_dump(p, " %18s => %u", + rtnl_prio2str(i, a, sizeof(a)), + prio->qp_priomap[i]); + if (hp+i <= TC_PRIO_MAX) { + nl_dump(p, " %18s => %u", + rtnl_prio2str(hp+i, a, sizeof(a)), + prio->qp_priomap[hp+i]); + if (i < (hp - 1)) { + nl_dump(p, "\n"); + nl_new_line(p); + } + } + } +} + +static int prio_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) +{ + struct rtnl_prio *prio = data; + struct tc_prio_qopt opts; + + if (!prio || !(prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP)) + BUG(); + + opts.bands = prio->qp_bands; + memcpy(opts.priomap, prio->qp_priomap, sizeof(opts.priomap)); + + return nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD); +} + +/** + * @name Attribute Modification + * @{ + */ + +/** + * Set number of bands of PRIO qdisc. + * @arg qdisc PRIO qdisc to be modified. + * @arg bands New number of bands. + * @return 0 on success or a negative error code. + */ +void rtnl_qdisc_prio_set_bands(struct rtnl_qdisc *qdisc, int bands) +{ + struct rtnl_prio *prio; + + if (!(prio = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + prio->qp_bands = bands; + prio->qp_mask |= SCH_PRIO_ATTR_BANDS; +} + +/** + * Get number of bands of PRIO qdisc. + * @arg qdisc PRIO qdisc. + * @return Number of bands or a negative error code. + */ +int rtnl_qdisc_prio_get_bands(struct rtnl_qdisc *qdisc) +{ + struct rtnl_prio *prio; + + 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; +} + +/** + * Set priomap of the PRIO qdisc. + * @arg qdisc PRIO qdisc to be modified. + * @arg priomap New priority mapping. + * @arg len Length of priomap (# of elements). + * @return 0 on success or a negative error code. + */ +int rtnl_qdisc_prio_set_priomap(struct rtnl_qdisc *qdisc, uint8_t priomap[], + int len) +{ + struct rtnl_prio *prio; + int i; + + if (!(prio = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (!(prio->qp_mask & SCH_PRIO_ATTR_BANDS)) + return -NLE_MISSING_ATTR; + + if ((len / sizeof(uint8_t)) > (TC_PRIO_MAX+1)) + return -NLE_RANGE; + + for (i = 0; i <= TC_PRIO_MAX; i++) { + if (priomap[i] > prio->qp_bands) + return -NLE_RANGE; + } + + memcpy(prio->qp_priomap, priomap, len); + prio->qp_mask |= SCH_PRIO_ATTR_PRIOMAP; + + return 0; +} + +/** + * Get priomap of a PRIO qdisc. + * @arg qdisc PRIO qdisc. + * @return Priority mapping as array of size TC_PRIO_MAX+1 + * or NULL if an error occured. + */ +uint8_t *rtnl_qdisc_prio_get_priomap(struct rtnl_qdisc *qdisc) +{ + struct rtnl_prio *prio; + + if (!(prio = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP) + return prio->qp_priomap; + else + return NULL; +} + +/** @} */ + +/** + * @name Priority Band Translations + * @{ + */ + +static const struct trans_tbl prios[] = { + __ADD(TC_PRIO_BESTEFFORT,besteffort) + __ADD(TC_PRIO_FILLER,filler) + __ADD(TC_PRIO_BULK,bulk) + __ADD(TC_PRIO_INTERACTIVE_BULK,interactive_bulk) + __ADD(TC_PRIO_INTERACTIVE,interactive) + __ADD(TC_PRIO_CONTROL,control) +}; + +/** + * Convert priority to character string. + * @arg prio Priority. + * @arg buf Destination buffer + * @arg size Size of destination buffer. + * + * Converts a priority to a character string and stores the result in + * the specified destination buffer. + * + * @return Name of priority as character string. + */ +char * rtnl_prio2str(int prio, char *buf, size_t size) +{ + return __type2str(prio, buf, size, prios, ARRAY_SIZE(prios)); +} + +/** + * Convert character string to priority. + * @arg name Name of priority. + * + * Converts the provided character string specifying a priority + * to the corresponding numeric value. + * + * @return Numeric priority or a negative value if no match was found. + */ +int rtnl_str2prio(const char *name) +{ + return __str2type(name, prios, ARRAY_SIZE(prios)); +} + +/** @} */ + +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, + }, + .to_msg_fill = prio_msg_fill, +}; + +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, + }, + .to_msg_fill = prio_msg_fill, +}; + +static void __init prio_init(void) +{ + rtnl_tc_register(&prio_ops); + rtnl_tc_register(&pfifo_fast_ops); +} + +static void __exit prio_exit(void) +{ + rtnl_tc_unregister(&prio_ops); + rtnl_tc_unregister(&pfifo_fast_ops); +} + +/** @} */ diff --git a/lib/route/qdisc/red.c b/lib/route/qdisc/red.c new file mode 100644 index 0000000..0480282 --- /dev/null +++ b/lib/route/qdisc/red.c @@ -0,0 +1,190 @@ +/* + * lib/route/qdisc/red.c RED Qdisc + * + * 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-2011 Thomas Graf + */ + +/** + * @ingroup qdisc + * @defgroup qdisc_red Random Early Detection (RED) + * @brief + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define RED_ATTR_LIMIT 0x01 +#define RED_ATTR_QTH_MIN 0x02 +#define RED_ATTR_QTH_MAX 0x04 +#define RED_ATTR_FLAGS 0x08 +#define RED_ATTR_WLOG 0x10 +#define RED_ATTR_PLOG 0x20 +#define RED_ATTR_SCELL_LOG 0x40 +/** @endcond */ + +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_tc *tc, void *data) +{ + struct nlattr *tb[TCA_RED_MAX+1]; + struct rtnl_red *red = data; + struct tc_red_qopt *opts; + int err; + + if (!(tc->ce_mask & TCA_ATTR_OPTS)) + return 0; + + err = tca_parse(tb, TCA_RED_MAX, tc, red_policy); + if (err < 0) + return err; + + if (!tb[TCA_RED_PARMS]) + return -NLE_MISSING_ATTR; + + opts = nla_data(tb[TCA_RED_PARMS]); + + red->qr_limit = opts->limit; + red->qr_qth_min = opts->qth_min; + red->qr_qth_max = opts->qth_max; + red->qr_flags = opts->flags; + red->qr_wlog = opts->Wlog; + red->qr_plog = opts->Plog; + red->qr_scell_log = opts->Scell_log; + + red->qr_mask = (RED_ATTR_LIMIT | RED_ATTR_QTH_MIN | RED_ATTR_QTH_MAX | + RED_ATTR_FLAGS | RED_ATTR_WLOG | RED_ATTR_PLOG | + RED_ATTR_SCELL_LOG); + + return 0; +} + +static void red_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_red *red = data; + + if (red) { + /* XXX: limit, min, max, flags */ + } +} + +static void red_dump_details(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_red *red = data; + + if (red) { + /* XXX: wlog, plog, scell_log */ + } +} + +static void red_dump_stats(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_red *red = data; + + if (red) { + /* XXX: xstats */ + } +} + +static int red_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) +{ + struct rtnl_red *red = data; + + if (!red) + BUG(); + +#if 0 + 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; +#endif + + return -NLE_OPNOTSUPP; +} + +/** + * @name Attribute Access + * @{ + */ + +/** + * Set limit of RED qdisc. + * @arg qdisc RED qdisc to be modified. + * @arg limit New limit in number of packets. + * @return 0 on success or a negative error code. + */ +void rtnl_red_set_limit(struct rtnl_qdisc *qdisc, int limit) +{ + struct rtnl_red *red; + + if (!(red = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + red->qr_limit = limit; + red->qr_mask |= RED_ATTR_LIMIT; +} + +/** + * Get limit of RED qdisc. + * @arg qdisc RED qdisc. + * @return Limit or a negative error code. + */ +int rtnl_red_get_limit(struct rtnl_qdisc *qdisc) +{ + struct rtnl_red *red; + + if (!(red = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (red->qr_mask & RED_ATTR_LIMIT) + return red->qr_limit; + else + return -NLE_NOATTR; +} + +/** @} */ + +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, + }, + .to_msg_fill = red_msg_fill, +}; + +static void __init red_init(void) +{ + rtnl_tc_register(&red_ops); +} + +static void __exit red_exit(void) +{ + rtnl_tc_unregister(&red_ops); +} + +/** @} */ diff --git a/lib/route/qdisc/sfq.c b/lib/route/qdisc/sfq.c new file mode 100644 index 0000000..207140f --- /dev/null +++ b/lib/route/qdisc/sfq.c @@ -0,0 +1,256 @@ +/* + * lib/route/qdisc/sfq.c SFQ Qdisc + * + * 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-2011 Thomas Graf + */ + +/** + * @ingroup qdisc + * @defgroup qdisc_sfq Stochastic Fairness Queueing (SFQ) + * @brief + * + * @par Parameter Description + * - \b Quantum: Number of bytes to send out per slot and round. + * - \b Perturbation: Timer period between changing the hash function. + * - \b Limit: Upper limit of queue in number of packets before SFQ starts + * dropping packets. + * - \b Divisor: Hash table divisor, i.e. size of hash table. + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define SCH_SFQ_ATTR_QUANTUM 0x01 +#define SCH_SFQ_ATTR_PERTURB 0x02 +#define SCH_SFQ_ATTR_LIMIT 0x04 +#define SCH_SFQ_ATTR_DIVISOR 0x08 +#define SCH_SFQ_ATTR_FLOWS 0x10 +/** @endcond */ + +static int sfq_msg_parser(struct rtnl_tc *tc, void *data) +{ + struct rtnl_sfq *sfq = data; + struct tc_sfq_qopt *opts; + + if (!(tc->ce_mask & TCA_ATTR_OPTS)) + return 0; + + if (tc->tc_opts->d_size < sizeof(*opts)) + return -NLE_INVAL; + + opts = (struct tc_sfq_qopt *) tc->tc_opts->d_data; + + sfq->qs_quantum = opts->quantum; + sfq->qs_perturb = opts->perturb_period; + sfq->qs_limit = opts->limit; + sfq->qs_divisor = opts->divisor; + sfq->qs_flows = opts->flows; + + sfq->qs_mask = (SCH_SFQ_ATTR_QUANTUM | SCH_SFQ_ATTR_PERTURB | + SCH_SFQ_ATTR_LIMIT | SCH_SFQ_ATTR_DIVISOR | + SCH_SFQ_ATTR_FLOWS); + + return 0; +} + +static void sfq_dump_line(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + 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_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_sfq *sfq = data; + + if (sfq) + nl_dump(p, "limit %u divisor %u", + sfq->qs_limit, sfq->qs_divisor); +} + +static int sfq_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) +{ + struct rtnl_sfq *sfq = data; + struct tc_sfq_qopt opts = {0}; + + if (!sfq) + BUG(); + + opts.quantum = sfq->qs_quantum; + opts.perturb_period = sfq->qs_perturb; + opts.limit = sfq->qs_limit; + + return nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD); +} + +/** + * @name Attribute Access + * @{ + */ + +/** + * Set quantum of SFQ qdisc. + * @arg qdisc SFQ qdisc to be modified. + * @arg quantum New quantum in bytes. + * @return 0 on success or a negative error code. + */ +void rtnl_sfq_set_quantum(struct rtnl_qdisc *qdisc, int quantum) +{ + struct rtnl_sfq *sfq; + + if (!(sfq = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + sfq->qs_quantum = quantum; + sfq->qs_mask |= SCH_SFQ_ATTR_QUANTUM; +} + +/** + * Get quantum of SFQ qdisc. + * @arg qdisc SFQ qdisc. + * @return Quantum in bytes or a negative error code. + */ +int rtnl_sfq_get_quantum(struct rtnl_qdisc *qdisc) +{ + struct rtnl_sfq *sfq; + + if (!(sfq = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (sfq->qs_mask & SCH_SFQ_ATTR_QUANTUM) + return sfq->qs_quantum; + else + return -NLE_NOATTR; +} + +/** + * Set limit of SFQ qdisc. + * @arg qdisc SFQ qdisc to be modified. + * @arg limit New limit in number of packets. + * @return 0 on success or a negative error code. + */ +void rtnl_sfq_set_limit(struct rtnl_qdisc *qdisc, int limit) +{ + struct rtnl_sfq *sfq; + + if (!(sfq = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + sfq->qs_limit = limit; + sfq->qs_mask |= SCH_SFQ_ATTR_LIMIT; +} + +/** + * Get limit of SFQ qdisc. + * @arg qdisc SFQ qdisc. + * @return Limit or a negative error code. + */ +int rtnl_sfq_get_limit(struct rtnl_qdisc *qdisc) +{ + struct rtnl_sfq *sfq; + + if (!(sfq = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (sfq->qs_mask & SCH_SFQ_ATTR_LIMIT) + return sfq->qs_limit; + else + return -NLE_NOATTR; +} + +/** + * Set perturbation interval of SFQ qdisc. + * @arg qdisc SFQ qdisc to be modified. + * @arg perturb New perturbation interval in seconds. + * @note A value of 0 disables perturbation altogether. + * @return 0 on success or a negative error code. + */ +void rtnl_sfq_set_perturb(struct rtnl_qdisc *qdisc, int perturb) +{ + struct rtnl_sfq *sfq; + + if (!(sfq = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + sfq->qs_perturb = perturb; + sfq->qs_mask |= SCH_SFQ_ATTR_PERTURB; +} + +/** + * Get perturbation interval of SFQ qdisc. + * @arg qdisc SFQ qdisc. + * @return Perturbation interval in seconds or a negative error code. + */ +int rtnl_sfq_get_perturb(struct rtnl_qdisc *qdisc) +{ + struct rtnl_sfq *sfq; + + if (!(sfq = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (sfq->qs_mask & SCH_SFQ_ATTR_PERTURB) + return sfq->qs_perturb; + else + return -NLE_NOATTR; +} + +/** + * Get divisor of SFQ qdisc. + * @arg qdisc SFQ qdisc. + * @return Divisor in number of entries or a negative error code. + */ +int rtnl_sfq_get_divisor(struct rtnl_qdisc *qdisc) +{ + struct rtnl_sfq *sfq; + + if (!(sfq = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (sfq->qs_mask & SCH_SFQ_ATTR_DIVISOR) + return sfq->qs_divisor; + else + return -NLE_NOATTR; +} + +/** @} */ + +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, + }, + .to_msg_fill = sfq_msg_fill, +}; + +static void __init sfq_init(void) +{ + rtnl_tc_register(&sfq_ops); +} + +static void __exit sfq_exit(void) +{ + rtnl_tc_unregister(&sfq_ops); +} + +/** @} */ diff --git a/lib/route/qdisc/tbf.c b/lib/route/qdisc/tbf.c new file mode 100644 index 0000000..8a6c400 --- /dev/null +++ b/lib/route/qdisc/tbf.c @@ -0,0 +1,460 @@ +/* + * lib/route/qdisc/tbf.c TBF Qdisc + * + * 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-2011 Thomas Graf + */ + +/** + * @ingroup qdisc + * @defgroup qdisc_tbf Token Bucket Filter (TBF) + * @{ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** @cond SKIP */ +#define TBF_ATTR_LIMIT 0x01 +#define TBF_ATTR_RATE 0x02 +#define TBF_ATTR_PEAKRATE 0x10 +/** @endcond */ + +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_tc *tc, void *data) +{ + struct nlattr *tb[TCA_TBF_MAX + 1]; + struct rtnl_tbf *tbf = data; + int err; + + if ((err = tca_parse(tb, TCA_TBF_MAX, tc, tbf_policy)) < 0) + return err; + + if (tb[TCA_TBF_PARMS]) { + struct tc_tbf_qopt opts; + int bufsize; + + nla_memcpy(&opts, tb[TCA_TBF_PARMS], sizeof(opts)); + tbf->qt_limit = opts.limit; + + rtnl_copy_ratespec(&tbf->qt_rate, &opts.rate); + tbf->qt_rate_txtime = opts.buffer; + bufsize = rtnl_tc_calc_bufsize(nl_ticks2us(opts.buffer), + opts.rate.rate); + tbf->qt_rate_bucket = bufsize; + + rtnl_copy_ratespec(&tbf->qt_peakrate, &opts.peakrate); + tbf->qt_peakrate_txtime = opts.mtu; + bufsize = rtnl_tc_calc_bufsize(nl_ticks2us(opts.mtu), + opts.peakrate.rate); + tbf->qt_peakrate_bucket = bufsize; + + 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); + } + + return 0; +} + +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 = data; + + if (!tbf) + return; + + r = nl_cancel_down_bytes(tbf->qt_rate.rs_rate, &ru); + rbit = nl_cancel_down_bits(tbf->qt_rate.rs_rate*8, &rubit); + lim = nl_cancel_down_bytes(tbf->qt_limit, &limu); + + nl_dump(p, " rate %.2f%s/s (%.0f%s) limit %.2f%s", + r, ru, rbit, rubit, lim, limu); +} + +static void tbf_dump_details(struct rtnl_tc *tc, void *data, + struct nl_dump_params *p) +{ + struct rtnl_tbf *tbf = data; + + if (!tbf) + return; + + if (1) { + char *bu, *cu; + double bs = nl_cancel_down_bytes(tbf->qt_rate_bucket, &bu); + double cl = nl_cancel_down_bytes(1 << tbf->qt_rate.rs_cell_log, + &cu); + + nl_dump(p, "rate-bucket-size %1.f%s " + "rate-cell-size %.1f%s\n", + bs, bu, cl, cu); + + } + + if (tbf->qt_mask & TBF_ATTR_PEAKRATE) { + char *pru, *prbu, *bsu, *clu; + double pr, prb, bs, cl; + + pr = nl_cancel_down_bytes(tbf->qt_peakrate.rs_rate, &pru); + prb = nl_cancel_down_bits(tbf->qt_peakrate.rs_rate * 8, &prbu); + bs = nl_cancel_down_bits(tbf->qt_peakrate_bucket, &bsu); + cl = nl_cancel_down_bits(1 << tbf->qt_peakrate.rs_cell_log, + &clu); + + nl_dump_line(p, " peak-rate %.2f%s/s (%.0f%s) " + "bucket-size %.1f%s cell-size %.1f%s" + "latency %.1f%s", + pr, pru, prb, prbu, bs, bsu, cl, clu); + } +} + +static int tbf_msg_fill(struct rtnl_tc *tc, void *data, 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; + + if (!(tbf->qt_mask & required) != required) + 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(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(tc, &tbf->qt_peakrate, ptab); + rtnl_rcopy_ratespec(&opts.peakrate, &tbf->qt_peakrate); + + } + + 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 0; + +nla_put_failure: + return -NLE_MSGSIZE; +} + +/** + * @name Attribute Access + * @{ + */ + +/** + * Set limit of TBF qdisc. + * @arg qdisc TBF qdisc to be modified. + * @arg limit New limit in bytes. + * @return 0 on success or a negative error code. + */ +void rtnl_qdisc_tbf_set_limit(struct rtnl_qdisc *qdisc, int limit) +{ + struct rtnl_tbf *tbf; + + if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + tbf->qt_limit = limit; + tbf->qt_mask |= TBF_ATTR_LIMIT; +} + +static inline double calc_limit(struct rtnl_ratespec *spec, int latency, + int bucket) +{ + double limit; + + limit = (double) spec->rs_rate * ((double) latency / 1000000.); + limit += bucket; + + return limit; +} + +/** + * Set limit of TBF qdisc by latency. + * @arg qdisc TBF qdisc to be modified. + * @arg latency Latency in micro seconds. + * + * Calculates and sets the limit based on the desired latency and the + * configured rate and peak rate. In order for this operation to succeed, + * the rate and if required the peak rate must have been set in advance. + * + * @f[ + * limit_n = \frac{{rate_n} \times {latency}}{10^6}+{bucketsize}_n + * @f] + * @f[ + * limit = min(limit_{rate},limit_{peak}) + * @f] + * + * @return 0 on success or a negative error code. + */ +int rtnl_qdisc_tbf_set_limit_by_latency(struct rtnl_qdisc *qdisc, int latency) +{ + struct rtnl_tbf *tbf; + double limit, limit2; + + if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (!(tbf->qt_mask & TBF_ATTR_RATE)) + return -NLE_MISSING_ATTR; + + limit = calc_limit(&tbf->qt_rate, latency, tbf->qt_rate_bucket); + + if (tbf->qt_mask & TBF_ATTR_PEAKRATE) { + limit2 = calc_limit(&tbf->qt_peakrate, latency, + tbf->qt_peakrate_bucket); + + if (limit2 < limit) + limit = limit2; + } + + rtnl_qdisc_tbf_set_limit(qdisc, (int) limit); + + return 0; +} + +/** + * Get limit of TBF qdisc. + * @arg qdisc TBF qdisc. + * @return Limit in bytes or a negative error code. + */ +int rtnl_qdisc_tbf_get_limit(struct rtnl_qdisc *qdisc) +{ + struct rtnl_tbf *tbf; + + if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (tbf->qt_mask & TBF_ATTR_LIMIT) + return tbf->qt_limit; + else + return -NLE_NOATTR; +} + +static inline int calc_cell_log(int cell, int bucket) +{ + cell = rtnl_tc_calc_cell_log(cell); + return cell; +} + +/** + * Set rate of TBF qdisc. + * @arg qdisc TBF qdisc to be modified. + * @arg rate New rate in bytes per second. + * @arg bucket Size of bucket in bytes. + * @arg cell Size of a rate cell or 0 to get default value. + * @return 0 on success or a negative error code. + */ +void rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc *qdisc, int rate, int bucket, + int cell) +{ + struct rtnl_tbf *tbf; + int cell_log; + + if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (!cell) + cell_log = UINT8_MAX; + else + cell_log = rtnl_tc_calc_cell_log(cell); + + tbf->qt_rate.rs_rate = rate; + tbf->qt_rate_bucket = 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; +} + +/** + * Get rate of TBF qdisc. + * @arg qdisc TBF qdisc. + * @return Rate in bytes per seconds or a negative error code. + */ +int rtnl_qdisc_tbf_get_rate(struct rtnl_qdisc *qdisc) +{ + struct rtnl_tbf *tbf; + + 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; +} + +/** + * Get rate bucket size of TBF qdisc. + * @arg qdisc TBF qdisc. + * @return Size of rate bucket or a negative error code. + */ +int rtnl_qdisc_tbf_get_rate_bucket(struct rtnl_qdisc *qdisc) +{ + struct rtnl_tbf *tbf; + + if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (tbf->qt_mask & TBF_ATTR_RATE) + return tbf->qt_rate_bucket; + else + return -1; +} + +/** + * Get rate cell size of TBF qdisc. + * @arg qdisc TBF qdisc. + * @return Size of rate cell in bytes or a negative error code. + */ +int rtnl_qdisc_tbf_get_rate_cell(struct rtnl_qdisc *qdisc) +{ + struct rtnl_tbf *tbf; + + 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; +} + +/** + * Set peak rate of TBF qdisc. + * @arg qdisc TBF qdisc to be modified. + * @arg rate New peak rate in bytes per second. + * @arg bucket Size of peakrate bucket. + * @arg cell Size of a peakrate cell or 0 to get default value. + * @return 0 on success or a negative error code. + */ +int rtnl_qdisc_tbf_set_peakrate(struct rtnl_qdisc *qdisc, int rate, int bucket, + int cell) +{ + struct rtnl_tbf *tbf; + int cell_log; + + if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + cell_log = calc_cell_log(cell, bucket); + if (cell_log < 0) + return cell_log; + + tbf->qt_peakrate.rs_rate = rate; + tbf->qt_peakrate_bucket = bucket; + tbf->qt_peakrate.rs_cell_log = cell_log; + tbf->qt_peakrate_txtime = rtnl_tc_calc_txtime(bucket, rate); + + tbf->qt_mask |= TBF_ATTR_PEAKRATE; + + return 0; +} + +/** + * Get peak rate of TBF qdisc. + * @arg qdisc TBF qdisc. + * @return Peak rate in bytes per seconds or a negative error code. + */ +int rtnl_qdisc_tbf_get_peakrate(struct rtnl_qdisc *qdisc) +{ + struct rtnl_tbf *tbf; + + 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; +} + +/** + * Get peak rate bucket size of TBF qdisc. + * @arg qdisc TBF qdisc. + * @return Size of peak rate bucket or a negative error code. + */ +int rtnl_qdisc_tbf_get_peakrate_bucket(struct rtnl_qdisc *qdisc) +{ + struct rtnl_tbf *tbf; + + if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) + BUG(); + + if (tbf->qt_mask & TBF_ATTR_PEAKRATE) + return tbf->qt_peakrate_bucket; + else + return -1; +} + +/** + * Get peak rate cell size of TBF qdisc. + * @arg qdisc TBF qdisc. + * @return Size of peak rate cell in bytes or a negative error code. + */ +int rtnl_qdisc_tbf_get_peakrate_cell(struct rtnl_qdisc *qdisc) +{ + struct rtnl_tbf *tbf; + + 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; +} + +/** @} */ + +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, + }, + .to_msg_fill = tbf_msg_fill, +}; + +static void __init tbf_init(void) +{ + rtnl_tc_register(&tbf_tc_ops); +} + +static void __exit tbf_exit(void) +{ + rtnl_tc_unregister(&tbf_tc_ops); +} + +/** @} */ diff --git a/lib/route/sch/blackhole.c b/lib/route/sch/blackhole.c deleted file mode 100644 index 064963e..0000000 --- a/lib/route/sch/blackhole.c +++ /dev/null @@ -1,37 +0,0 @@ -/* - * lib/route/sch/blackhole.c Blackhole Qdisc - * - * 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-2011 Thomas Graf - */ - -/** - * @ingroup qdisc - * @defgroup qdisc_blackhole Blackhole - * @{ - */ - -#include -#include -#include - -static struct rtnl_tc_ops blackhole_ops = { - .to_kind = "blackhole", - .to_type = RTNL_TC_TYPE_QDISC, -}; - -static void __init blackhole_init(void) -{ - rtnl_tc_register(&blackhole_ops); -} - -static void __exit blackhole_exit(void) -{ - rtnl_tc_unregister(&blackhole_ops); -} - -/** @} */ diff --git a/lib/route/sch/cbq.c b/lib/route/sch/cbq.c deleted file mode 100644 index f750ccd..0000000 --- a/lib/route/sch/cbq.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * lib/route/sch/cbq.c Class Based Queueing - * - * 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-2011 Thomas Graf - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * @ingroup qdisc - * @ingroup class - * @defgroup qdisc_cbq Class Based Queueing (CBQ) - * @{ - */ - -static const struct trans_tbl ovl_strategies[] = { - __ADD(TC_CBQ_OVL_CLASSIC,classic) - __ADD(TC_CBQ_OVL_DELAY,delay) - __ADD(TC_CBQ_OVL_LOWPRIO,lowprio) - __ADD(TC_CBQ_OVL_DROP,drop) - __ADD(TC_CBQ_OVL_RCLASSIC,rclassic) -}; - -/** - * Convert a CBQ OVL strategy to a character string - * @arg type CBQ OVL strategy - * @arg buf destination buffer - * @arg len length of destination buffer - * - * Converts a CBQ OVL strategy to a character string and stores in the - * provided buffer. Returns the destination buffer or the type - * encoded in hex if no match was found. - */ -char *nl_ovl_strategy2str(int type, char *buf, size_t len) -{ - return __type2str(type, buf, len, ovl_strategies, - ARRAY_SIZE(ovl_strategies)); -} - -/** - * Convert a string to a CBQ OVL strategy - * @arg name CBQ OVL stragegy name - * - * Converts a CBQ OVL stragegy name to it's corresponding CBQ OVL strategy - * type. Returns the type or -1 if none was found. - */ -int nl_str2ovl_strategy(const char *name) -{ - return __str2type(name, ovl_strategies, ARRAY_SIZE(ovl_strategies)); -} - -static struct nla_policy cbq_policy[TCA_CBQ_MAX+1] = { - [TCA_CBQ_LSSOPT] = { .minlen = sizeof(struct tc_cbq_lssopt) }, - [TCA_CBQ_RATE] = { .minlen = sizeof(struct tc_ratespec) }, - [TCA_CBQ_WRROPT] = { .minlen = sizeof(struct tc_cbq_wrropt) }, - [TCA_CBQ_OVL_STRATEGY] = { .minlen = sizeof(struct tc_cbq_ovl) }, - [TCA_CBQ_FOPT] = { .minlen = sizeof(struct tc_cbq_fopt) }, - [TCA_CBQ_POLICE] = { .minlen = sizeof(struct tc_cbq_police) }, -}; - -static int cbq_msg_parser(struct rtnl_tc *tc, void *data) -{ - struct nlattr *tb[TCA_CBQ_MAX + 1]; - struct rtnl_cbq *cbq = data; - int err; - - err = tca_parse(tb, TCA_CBQ_MAX, tc, cbq_policy); - if (err < 0) - return err; - - 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)); - nla_memcpy(&cbq->cbq_fopt, tb[TCA_CBQ_FOPT], sizeof(cbq->cbq_fopt)); - nla_memcpy(&cbq->cbq_ovl, tb[TCA_CBQ_OVL_STRATEGY], - sizeof(cbq->cbq_ovl)); - nla_memcpy(&cbq->cbq_police, tb[TCA_CBQ_POLICE], - sizeof(cbq->cbq_police)); - - return 0; -} - -static void cbq_dump_line(struct rtnl_tc *tc, void *data, - struct nl_dump_params *p) -{ - struct rtnl_cbq *cbq = data; - double r, rbit; - char *ru, *rubit; - - if (!cbq) - return; - - r = nl_cancel_down_bytes(cbq->cbq_rate.rate, &ru); - rbit = nl_cancel_down_bits(cbq->cbq_rate.rate * 8, &rubit); - - nl_dump(p, " rate %.2f%s/s (%.0f%s) prio %u", - r, ru, rbit, rubit, cbq->cbq_wrr.priority); -} - -static void cbq_dump_details(struct rtnl_tc *tc, void *data, - struct nl_dump_params *p) -{ - struct rtnl_cbq *cbq = data; - char *unit, buf[32]; - double w; - uint32_t el; - - if (!cbq) - return; - - w = nl_cancel_down_bits(cbq->cbq_wrr.weight * 8, &unit); - - nl_dump(p, "avgpkt %u mpu %u cell %u allot %u weight %.0f%s\n", - cbq->cbq_lss.avpkt, - cbq->cbq_rate.mpu, - 1 << cbq->cbq_rate.cell_log, - cbq->cbq_wrr.allot, w, unit); - - el = cbq->cbq_lss.ewma_log; - nl_dump_line(p, " minidle %uus maxidle %uus offtime " - "%uus level %u ewma_log %u\n", - nl_ticks2us(cbq->cbq_lss.minidle >> el), - nl_ticks2us(cbq->cbq_lss.maxidle >> el), - nl_ticks2us(cbq->cbq_lss.offtime >> el), - cbq->cbq_lss.level, - cbq->cbq_lss.ewma_log); - - nl_dump_line(p, " penalty %uus strategy %s ", - nl_ticks2us(cbq->cbq_ovl.penalty), - nl_ovl_strategy2str(cbq->cbq_ovl.strategy, buf, sizeof(buf))); - - nl_dump(p, "split %s defmap 0x%08x ", - rtnl_tc_handle2str(cbq->cbq_fopt.split, buf, sizeof(buf)), - cbq->cbq_fopt.defmap); - - nl_dump(p, "police %s", - nl_police2str(cbq->cbq_police.police, buf, sizeof(buf))); -} - -static void cbq_dump_stats(struct rtnl_tc *tc, void *data, - struct nl_dump_params *p) -{ - struct tc_cbq_xstats *x; - - if (!(x = tca_xstats(tc))) - return; - - nl_dump_line(p, " borrows overact " - " avgidle undertime\n"); - nl_dump_line(p, " %10u %10u %10u %10u\n", - x->borrows, x->overactions, x->avgidle, x->undertime); -} - -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_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_tc_register(&cbq_qdisc_ops); - rtnl_tc_register(&cbq_class_ops); -} - -static void __exit cbq_exit(void) -{ - rtnl_tc_unregister(&cbq_qdisc_ops); - rtnl_tc_unregister(&cbq_class_ops); -} - -/** @} */ diff --git a/lib/route/sch/dsmark.c b/lib/route/sch/dsmark.c deleted file mode 100644 index 372d0b6..0000000 --- a/lib/route/sch/dsmark.c +++ /dev/null @@ -1,413 +0,0 @@ -/* - * lib/route/sch/dsmark.c DSMARK - * - * 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-2011 Thomas Graf - */ - -/** - * @ingroup qdisc - * @ingroup class - * @defgroup qdisc_dsmark Differentiated Services Marker (DSMARK) - * @{ - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/** @cond SKIP */ -#define SCH_DSMARK_ATTR_INDICES 0x1 -#define SCH_DSMARK_ATTR_DEFAULT_INDEX 0x2 -#define SCH_DSMARK_ATTR_SET_TC_INDEX 0x4 - -#define SCH_DSMARK_ATTR_MASK 0x1 -#define SCH_DSMARK_ATTR_VALUE 0x2 -/** @endcond */ - -static struct nla_policy dsmark_policy[TCA_DSMARK_MAX+1] = { - [TCA_DSMARK_INDICES] = { .type = NLA_U16 }, - [TCA_DSMARK_DEFAULT_INDEX] = { .type = NLA_U16 }, - [TCA_DSMARK_SET_TC_INDEX] = { .type = NLA_FLAG }, - [TCA_DSMARK_VALUE] = { .type = NLA_U8 }, - [TCA_DSMARK_MASK] = { .type = NLA_U8 }, -}; - -static int dsmark_qdisc_msg_parser(struct rtnl_tc *tc, void *data) -{ - struct rtnl_dsmark_qdisc *dsmark = data; - struct nlattr *tb[TCA_DSMARK_MAX + 1]; - int err; - - err = tca_parse(tb, TCA_DSMARK_MAX, tc, dsmark_policy); - if (err < 0) - return err; - - if (tb[TCA_DSMARK_INDICES]) { - dsmark->qdm_indices = nla_get_u16(tb[TCA_DSMARK_INDICES]); - dsmark->qdm_mask |= SCH_DSMARK_ATTR_INDICES; - } - - if (tb[TCA_DSMARK_DEFAULT_INDEX]) { - dsmark->qdm_default_index = - nla_get_u16(tb[TCA_DSMARK_DEFAULT_INDEX]); - dsmark->qdm_mask |= SCH_DSMARK_ATTR_DEFAULT_INDEX; - } - - if (tb[TCA_DSMARK_SET_TC_INDEX]) { - dsmark->qdm_set_tc_index = 1; - dsmark->qdm_mask |= SCH_DSMARK_ATTR_SET_TC_INDEX; - } - - return 0; -} - -static int dsmark_class_msg_parser(struct rtnl_tc *tc, void *data) -{ - struct rtnl_dsmark_class *dsmark = data; - struct nlattr *tb[TCA_DSMARK_MAX + 1]; - int err; - - err = tca_parse(tb, TCA_DSMARK_MAX, tc, dsmark_policy); - if (err < 0) - return err; - - if (tb[TCA_DSMARK_MASK]) { - dsmark->cdm_bmask = nla_get_u8(tb[TCA_DSMARK_MASK]); - dsmark->cdm_mask |= SCH_DSMARK_ATTR_MASK; - } - - if (tb[TCA_DSMARK_VALUE]) { - dsmark->cdm_value = nla_get_u8(tb[TCA_DSMARK_VALUE]); - dsmark->cdm_mask |= SCH_DSMARK_ATTR_VALUE; - } - - return 0; -} - -static void dsmark_qdisc_dump_line(struct rtnl_tc *tc, void *data, - struct nl_dump_params *p) -{ - 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_tc *tc, void *data, - struct nl_dump_params *p) -{ - struct rtnl_dsmark_qdisc *dsmark = data; - - if (!dsmark) - return; - - if (dsmark->qdm_mask & SCH_DSMARK_ATTR_DEFAULT_INDEX) - nl_dump(p, " default index 0x%04x", dsmark->qdm_default_index); - - if (dsmark->qdm_mask & SCH_DSMARK_ATTR_SET_TC_INDEX) - nl_dump(p, " set-tc-index"); -} - -static void dsmark_class_dump_line(struct rtnl_tc *tc, void *data, - struct nl_dump_params *p) -{ - struct rtnl_dsmark_class *dsmark = data; - - if (!dsmark) - return; - - if (dsmark->cdm_mask & SCH_DSMARK_ATTR_VALUE) - nl_dump(p, " value 0x%02x", dsmark->cdm_value); - - if (dsmark->cdm_mask & SCH_DSMARK_ATTR_MASK) - nl_dump(p, " mask 0x%02x", dsmark->cdm_bmask); -} - -static int dsmark_qdisc_msg_fill(struct rtnl_tc *tc, void *data, - struct nl_msg *msg) -{ - struct rtnl_dsmark_qdisc *dsmark = data; - - if (!dsmark) - return 0; - - if (dsmark->qdm_mask & SCH_DSMARK_ATTR_INDICES) - NLA_PUT_U16(msg, TCA_DSMARK_INDICES, dsmark->qdm_indices); - - if (dsmark->qdm_mask & SCH_DSMARK_ATTR_DEFAULT_INDEX) - NLA_PUT_U16(msg, TCA_DSMARK_DEFAULT_INDEX, - dsmark->qdm_default_index); - - if (dsmark->qdm_mask & SCH_DSMARK_ATTR_SET_TC_INDEX) - NLA_PUT_FLAG(msg, TCA_DSMARK_SET_TC_INDEX); - - return 0; - -nla_put_failure: - return -NLE_MSGSIZE; -} - -static int dsmark_class_msg_fill(struct rtnl_tc *tc, void *data, - struct nl_msg *msg) -{ - struct rtnl_dsmark_class *dsmark = data; - - if (!dsmark) - return 0; - - if (dsmark->cdm_mask & SCH_DSMARK_ATTR_MASK) - NLA_PUT_U8(msg, TCA_DSMARK_MASK, dsmark->cdm_bmask); - - if (dsmark->cdm_mask & SCH_DSMARK_ATTR_VALUE) - NLA_PUT_U8(msg, TCA_DSMARK_VALUE, dsmark->cdm_value); - - return 0; - -nla_put_failure: - return -NLE_MSGSIZE; -} - -/** - * @name Class Attribute Access - * @{ - */ - -/** - * Set bitmask of DSMARK class. - * @arg class DSMARK class to be modified. - * @arg mask New bitmask. - * @return 0 on success or a negative error code. - */ -int rtnl_class_dsmark_set_bitmask(struct rtnl_class *class, uint8_t mask) -{ - struct rtnl_dsmark_class *dsmark; - - if (!(dsmark = rtnl_tc_data(TC_CAST(class)))) - return -NLE_NOMEM; - - dsmark->cdm_bmask = mask; - dsmark->cdm_mask |= SCH_DSMARK_ATTR_MASK; - - return 0; -} - -/** - * Get bitmask of DSMARK class. - * @arg class DSMARK class. - * @return Bitmask or a negative error code. - */ -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; - - if (dsmark->cdm_mask & SCH_DSMARK_ATTR_MASK) - return dsmark->cdm_bmask; - else - return -NLE_NOATTR; -} - -/** - * Set value of DSMARK class. - * @arg class DSMARK class to be modified. - * @arg value New value. - * @return 0 on success or a negative errror code. - */ -int rtnl_class_dsmark_set_value(struct rtnl_class *class, uint8_t value) -{ - struct rtnl_dsmark_class *dsmark; - - if (!(dsmark = rtnl_tc_data(TC_CAST(class)))) - return -NLE_NOMEM; - - dsmark->cdm_value = value; - dsmark->cdm_mask |= SCH_DSMARK_ATTR_VALUE; - - return 0; -} - -/** - * Get value of DSMARK class. - * @arg class DSMARK class. - * @return Value or a negative error code. - */ -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; - - if (dsmark->cdm_mask & SCH_DSMARK_ATTR_VALUE) - return dsmark->cdm_value; - else - return -NLE_NOATTR; -} - -/** @} */ - -/** - * @name Qdisc Attribute Access - * @{ - */ - -/** - * Set indices of DSMARK qdisc. - * @arg qdisc DSMARK qdisc to be modified. - * @arg indices New indices. - */ -int rtnl_qdisc_dsmark_set_indices(struct rtnl_qdisc *qdisc, uint16_t indices) -{ - struct rtnl_dsmark_qdisc *dsmark; - - if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc)))) - return -NLE_NOMEM; - - dsmark->qdm_indices = indices; - dsmark->qdm_mask |= SCH_DSMARK_ATTR_INDICES; - - return 0; -} - -/** - * Get indices of DSMARK qdisc. - * @arg qdisc DSMARK qdisc. - * @return Indices or a negative error code. - */ -int rtnl_qdisc_dsmark_get_indices(struct rtnl_qdisc *qdisc) -{ - struct rtnl_dsmark_qdisc *dsmark; - - 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; -} - -/** - * Set default index of DSMARK qdisc. - * @arg qdisc DSMARK qdisc to be modified. - * @arg default_index New default index. - * @return 0 on success or a negative error code. - */ -int rtnl_qdisc_dsmark_set_default_index(struct rtnl_qdisc *qdisc, - uint16_t default_index) -{ - struct rtnl_dsmark_qdisc *dsmark; - - if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc)))) - return -NLE_NOMEM; - - dsmark->qdm_default_index = default_index; - dsmark->qdm_mask |= SCH_DSMARK_ATTR_DEFAULT_INDEX; - - return 0; -} - -/** - * Get default index of DSMARK qdisc. - * @arg qdisc DSMARK qdisc. - * @return Default index or a negative error code. - */ -int rtnl_qdisc_dsmark_get_default_index(struct rtnl_qdisc *qdisc) -{ - struct rtnl_dsmark_qdisc *dsmark; - - 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; -} - -/** - * Set set-tc-index flag of DSMARK qdisc. - * @arg qdisc DSMARK qdisc to be modified. - * @arg flag Flag indicating whether to enable or disable. - * @return 0 on success or a negative error code. - */ -int rtnl_qdisc_dsmark_set_set_tc_index(struct rtnl_qdisc *qdisc, int flag) -{ - struct rtnl_dsmark_qdisc *dsmark; - - if (!(dsmark = rtnl_tc_data(TC_CAST(qdisc)))) - return -NLE_NOMEM; - - dsmark->qdm_set_tc_index = !!flag; - dsmark->qdm_mask |= SCH_DSMARK_ATTR_SET_TC_INDEX; - - return 0; -} - -/** - * Get set-tc-index flag of DSMARK qdisc. - * @arg qdisc DSMARK qdisc to be modified. - * @return 1 or 0 to indicate wehther the flag is enabled or a negative - * error code. - */ -int rtnl_qdisc_dsmark_get_set_tc_index(struct rtnl_qdisc *qdisc) -{ - struct rtnl_dsmark_qdisc *dsmark; - - 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; -} - -/** @} */ - -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, - }, - .to_msg_fill = dsmark_qdisc_msg_fill, -}; - -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_tc_register(&dsmark_qdisc_ops); - rtnl_tc_register(&dsmark_class_ops); -} - -static void __exit dsmark_exit(void) -{ - rtnl_tc_unregister(&dsmark_qdisc_ops); - rtnl_tc_unregister(&dsmark_class_ops); -} - -/** @} */ diff --git a/lib/route/sch/fifo.c b/lib/route/sch/fifo.c deleted file mode 100644 index 1399c0a..0000000 --- a/lib/route/sch/fifo.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * lib/route/sch/fifo.c (p|b)fifo - * - * 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-2011 Thomas Graf - */ - -/** - * @ingroup qdisc - * @defgroup qdisc_fifo Packet/Bytes FIFO (pfifo/bfifo) - * @brief - * - * The FIFO qdisc comes in two flavours: - * @par bfifo (Byte FIFO) - * Allows enqueuing until the currently queued volume in bytes exceeds - * the configured limit.backlog contains currently enqueued volume in bytes. - * - * @par pfifo (Packet FIFO) - * Allows enquueing until the currently queued number of packets - * exceeds the configured limit. - * - * 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_tc_set_kind()). - * @{ - */ - -#include -#include -#include -#include -#include -#include -#include - -/** @cond SKIP */ -#define SCH_FIFO_ATTR_LIMIT 1 -/** @endcond */ - -static int fifo_msg_parser(struct rtnl_tc *tc, void *data) -{ - struct rtnl_fifo *fifo = data; - struct tc_fifo_qopt *opt; - - if (tc->tc_opts->d_size < sizeof(struct tc_fifo_qopt)) - return -NLE_INVAL; - - 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 pfifo_dump_line(struct rtnl_tc *tc, void *data, - struct nl_dump_params *p) -{ - struct rtnl_fifo *fifo = data; - - if (fifo) - nl_dump(p, " limit %u packets", fifo->qf_limit); -} - -static void bfifo_dump_line(struct rtnl_tc *tc, void *data, - struct nl_dump_params *p) -{ - struct rtnl_fifo *fifo = data; - char *unit; - double r; - - if (!fifo) - return; - - r = nl_cancel_down_bytes(fifo->qf_limit, &unit); - nl_dump(p, " limit %.1f%s", r, unit); -} - -static int fifo_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) -{ - struct rtnl_fifo *fifo = data; - struct tc_fifo_qopt opts = {0}; - - if (!fifo || !(fifo->qf_mask & SCH_FIFO_ATTR_LIMIT)) - return -NLE_INVAL; - - opts.limit = fifo->qf_limit; - - return nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD); -} - -/** - * @name Attribute Modification - * @{ - */ - -/** - * Set limit of FIFO qdisc. - * @arg qdisc FIFO qdisc to be modified. - * @arg limit New limit. - * @return 0 on success or a negative error code. - */ -int rtnl_qdisc_fifo_set_limit(struct rtnl_qdisc *qdisc, int limit) -{ - struct rtnl_fifo *fifo; - - if (!(fifo = rtnl_tc_data(TC_CAST(qdisc)))) - return -NLE_NOMEM; - - fifo->qf_limit = limit; - fifo->qf_mask |= SCH_FIFO_ATTR_LIMIT; - - return 0; -} - -/** - * Get limit of a FIFO qdisc. - * @arg qdisc FIFO qdisc. - * @return Numeric limit or a negative error code. - */ -int rtnl_qdisc_fifo_get_limit(struct rtnl_qdisc *qdisc) -{ - struct rtnl_fifo *fifo; - - 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; -} - -/** @} */ - -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_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_tc_register(&pfifo_ops); - rtnl_tc_register(&bfifo_ops); -} - -static void __exit fifo_exit(void) -{ - rtnl_tc_unregister(&pfifo_ops); - rtnl_tc_unregister(&bfifo_ops); -} - -/** @} */ diff --git a/lib/route/sch/htb.c b/lib/route/sch/htb.c deleted file mode 100644 index 7f2a384..0000000 --- a/lib/route/sch/htb.c +++ /dev/null @@ -1,433 +0,0 @@ -/* - * lib/route/sch/htb.c HTB Qdisc - * - * 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-2011 Thomas Graf - * Copyright (c) 2005-2006 Petr Gotthard - * Copyright (c) 2005-2006 Siemens AG Oesterreich - */ - -/** - * @ingroup qdisc - * @ingroup class - * @defgroup qdisc_htb Hierachical Token Bucket (HTB) - * @{ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** @cond SKIP */ -#define SCH_HTB_HAS_RATE2QUANTUM 0x01 -#define SCH_HTB_HAS_DEFCLS 0x02 - -#define SCH_HTB_HAS_PRIO 0x001 -#define SCH_HTB_HAS_RATE 0x002 -#define SCH_HTB_HAS_CEIL 0x004 -#define SCH_HTB_HAS_RBUFFER 0x008 -#define SCH_HTB_HAS_CBUFFER 0x010 -#define SCH_HTB_HAS_QUANTUM 0x020 -/** @endcond */ - -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_tc *tc, void *data) -{ - struct nlattr *tb[TCA_HTB_MAX + 1]; - struct rtnl_htb_qdisc *htb = data; - int err; - - if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0) - return err; - - if (tb[TCA_HTB_INIT]) { - struct tc_htb_glob opts; - - nla_memcpy(&opts, tb[TCA_HTB_INIT], sizeof(opts)); - htb->qh_rate2quantum = opts.rate2quantum; - htb->qh_defcls = opts.defcls; - - htb->qh_mask = (SCH_HTB_HAS_RATE2QUANTUM | SCH_HTB_HAS_DEFCLS); - } - - return 0; -} - -static int htb_class_msg_parser(struct rtnl_tc *tc, void *data) -{ - struct nlattr *tb[TCA_HTB_MAX + 1]; - struct rtnl_htb_class *htb = data; - int err; - - if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0) - return err; - - if (tb[TCA_HTB_PARMS]) { - struct tc_htb_opt opts; - - nla_memcpy(&opts, tb[TCA_HTB_PARMS], sizeof(opts)); - 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, htb->ch_rate.rs_mpu); - rtnl_tc_set_overhead(tc, htb->ch_rate.rs_overhead); - - 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_qdisc_dump_line(struct rtnl_tc *tc, void *data, - struct nl_dump_params *p) -{ - struct rtnl_htb_qdisc *htb = data; - - if (!htb) - return; - - if (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM) - nl_dump(p, " r2q %u", htb->qh_rate2quantum); - - if (htb->qh_mask & SCH_HTB_HAS_DEFCLS) { - char buf[32]; - nl_dump(p, " default %s", - rtnl_tc_handle2str(htb->qh_defcls, buf, sizeof(buf))); - } -} - -static void htb_class_dump_line(struct rtnl_tc *tc, void *data, - struct nl_dump_params *p) -{ - struct rtnl_htb_class *htb = data; - - if (!htb) - return; - - if (htb->ch_mask & SCH_HTB_HAS_RATE) { - double r, rbit; - char *ru, *rubit; - - r = nl_cancel_down_bytes(htb->ch_rate.rs_rate, &ru); - rbit = nl_cancel_down_bits(htb->ch_rate.rs_rate*8, &rubit); - - nl_dump(p, " rate %.2f%s/s (%.0f%s) log %u", - r, ru, rbit, rubit, 1<ch_rate.rs_cell_log); - } -} - -static void htb_class_dump_details(struct rtnl_tc *tc, void *data, - struct nl_dump_params *p) -{ - struct rtnl_htb_class *htb = data; - - if (!htb) - return; - - /* line 1 */ - if (htb->ch_mask & SCH_HTB_HAS_CEIL) { - double r, rbit; - char *ru, *rubit; - - r = nl_cancel_down_bytes(htb->ch_ceil.rs_rate, &ru); - rbit = nl_cancel_down_bits(htb->ch_ceil.rs_rate*8, &rubit); - - nl_dump(p, " ceil %.2f%s/s (%.0f%s) log %u", - r, ru, rbit, rubit, 1<ch_ceil.rs_cell_log); - } - - if (htb->ch_mask & SCH_HTB_HAS_PRIO) - nl_dump(p, " prio %u", htb->ch_prio); - - if (htb->ch_mask & SCH_HTB_HAS_RBUFFER) { - double b; - char *bu; - - b = nl_cancel_down_bytes(htb->ch_rbuffer, &bu); - nl_dump(p, " rbuffer %.2f%s", b, bu); - } - - if (htb->ch_mask & SCH_HTB_HAS_CBUFFER) { - double b; - char *bu; - - b = nl_cancel_down_bytes(htb->ch_cbuffer, &bu); - nl_dump(p, " cbuffer %.2f%s", b, bu); - } - - if (htb->ch_mask & SCH_HTB_HAS_QUANTUM) - nl_dump(p, " quantum %u", htb->ch_quantum); -} - -static int htb_qdisc_msg_fill(struct rtnl_tc *tc, void *data, - struct nl_msg *msg) -{ - struct rtnl_htb_qdisc *htb = data; - struct tc_htb_glob opts = {0}; - - opts.version = TC_HTB_PROTOVER; - opts.rate2quantum = 10; - - 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; - } - - return nla_put(msg, TCA_HTB_INIT, sizeof(opts), &opts); -} - -static int htb_class_msg_fill(struct rtnl_tc *tc, void *data, - struct nl_msg *msg) -{ - struct rtnl_htb_class *htb = data; - uint32_t mtu, rtable[RTNL_TC_RTABLE_SIZE], ctable[RTNL_TC_RTABLE_SIZE]; - struct tc_htb_opt opts; - int buffer, cbuffer; - - if (!htb || !(htb->ch_mask & SCH_HTB_HAS_RATE)) - BUG(); - - /* 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)); - - mtu = rtnl_tc_get_mtu(tc); - - rtnl_tc_build_rate_table(tc, &htb->ch_rate, rtable); - rtnl_rcopy_ratespec(&opts.rate, &htb->ch_rate); - - 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 - * no borrowing. - */ - memcpy(&opts.ceil, &opts.rate, sizeof(struct tc_ratespec)); - } - - 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 (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 (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); - - return 0; - -nla_put_failure: - return -NLE_MSGSIZE; -} - -/** - * @name Attribute Modifications - * @{ - */ - -void rtnl_htb_set_rate2quantum(struct rtnl_qdisc *qdisc, uint32_t rate2quantum) -{ - struct rtnl_htb_qdisc *htb; - - if (!(htb = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - htb->qh_rate2quantum = rate2quantum; - htb->qh_mask |= SCH_HTB_HAS_RATE2QUANTUM; -} - -/** - * Set default class of the htb qdisc to the specified value - * @arg qdisc qdisc to change - * @arg defcls new default class - */ -void rtnl_htb_set_defcls(struct rtnl_qdisc *qdisc, uint32_t defcls) -{ - struct rtnl_htb_qdisc *htb; - - 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 *htb; - - if (!(htb = rtnl_tc_data(TC_CAST(class)))) - BUG(); - - htb->ch_prio = prio; - htb->ch_mask |= SCH_HTB_HAS_PRIO; -} - -/** - * Set rate of HTB class. - * @arg class HTB class to be modified. - * @arg rate New rate in bytes per second. - */ -void rtnl_htb_set_rate(struct rtnl_class *class, uint32_t rate) -{ - struct rtnl_htb_class *htb; - - 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 *htb; - - if (!(htb = rtnl_tc_data(TC_CAST(class)))) - return 0; - - return htb->ch_rate.rs_rate; -} - -/** - * Set ceil of HTB class. - * @arg class HTB class to be modified. - * @arg ceil New ceil in bytes per second. - */ -void rtnl_htb_set_ceil(struct rtnl_class *class, uint32_t ceil) -{ - struct rtnl_htb_class *htb; - - 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; -} - -/** - * Set size of the rate bucket of HTB class. - * @arg class HTB class to be modified. - * @arg rbuffer New size in bytes. - */ -void rtnl_htb_set_rbuffer(struct rtnl_class *class, uint32_t rbuffer) -{ - struct rtnl_htb_class *htb; - - if (!(htb = rtnl_tc_data(TC_CAST(class)))) - BUG(); - - htb->ch_rbuffer = rbuffer; - htb->ch_mask |= SCH_HTB_HAS_RBUFFER; -} - -/** - * Set size of the ceil bucket of HTB class. - * @arg class HTB class to be modified. - * @arg cbuffer New size in bytes. - */ -void rtnl_htb_set_cbuffer(struct rtnl_class *class, uint32_t cbuffer) -{ - struct rtnl_htb_class *htb; - - if (!(htb = rtnl_tc_data(TC_CAST(class)))) - BUG(); - - htb->ch_cbuffer = cbuffer; - htb->ch_mask |= SCH_HTB_HAS_CBUFFER; -} - -/** - * Set how much bytes to serve from leaf at once of HTB class {use r2q}. - * @arg class HTB class to be modified. - * @arg quantum New size in bytes. - */ -void rtnl_htb_set_quantum(struct rtnl_class *class, uint32_t quantum) -{ - struct rtnl_htb_class *htb; - - if (!(htb = rtnl_tc_data(TC_CAST(class)))) - BUG(); - - htb->ch_quantum = quantum; - htb->ch_mask |= SCH_HTB_HAS_QUANTUM; -} - -/** @} */ - -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_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, - }, - .to_msg_fill = htb_class_msg_fill, -}; - -static void __init htb_init(void) -{ - rtnl_tc_register(&htb_qdisc_ops); - rtnl_tc_register(&htb_class_ops); -} - -static void __exit htb_exit(void) -{ - rtnl_tc_unregister(&htb_qdisc_ops); - rtnl_tc_unregister(&htb_class_ops); -} - -/** @} */ diff --git a/lib/route/sch/netem.c b/lib/route/sch/netem.c deleted file mode 100644 index 981d96e..0000000 --- a/lib/route/sch/netem.c +++ /dev/null @@ -1,905 +0,0 @@ -/* - * lib/route/sch/netem.c Network Emulator Qdisc - * - * 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-2011 Thomas Graf - */ - -/** - * @ingroup qdisc - * @defgroup qdisc_netem Network Emulator - * @brief - * - * For further documentation see http://linux-net.osdl.org/index.php/Netem - * @{ - */ - -#include -#include -#include -#include -#include -#include -#include - -/** @cond SKIP */ -#define SCH_NETEM_ATTR_LATENCY 0x0001 -#define SCH_NETEM_ATTR_LIMIT 0x0002 -#define SCH_NETEM_ATTR_LOSS 0x0004 -#define SCH_NETEM_ATTR_GAP 0x0008 -#define SCH_NETEM_ATTR_DUPLICATE 0x0010 -#define SCH_NETEM_ATTR_JITTER 0x0020 -#define SCH_NETEM_ATTR_DELAY_CORR 0x0040 -#define SCH_NETEM_ATTR_LOSS_CORR 0x0080 -#define SCH_NETEM_ATTR_DUP_CORR 0x0100 -#define SCH_NETEM_ATTR_RO_PROB 0x0200 -#define SCH_NETEM_ATTR_RO_CORR 0x0400 -#define SCH_NETEM_ATTR_CORRUPT_PROB 0x0800 -#define SCH_NETEM_ATTR_CORRUPT_CORR 0x1000 -#define SCH_NETEM_ATTR_DIST 0x2000 -/** @endcond */ - -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_tc *tc, void *data) -{ - struct rtnl_netem *netem = data; - struct tc_netem_qopt *opts; - int len, err = 0; - - if (tc->tc_opts->d_size < sizeof(*opts)) - return -NLE_INVAL; - - 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; - netem->qnm_gap = opts->gap; - netem->qnm_duplicate = opts->duplicate; - netem->qnm_jitter = opts->jitter; - - netem->qnm_mask = (SCH_NETEM_ATTR_LATENCY | SCH_NETEM_ATTR_LIMIT | - SCH_NETEM_ATTR_LOSS | SCH_NETEM_ATTR_GAP | - SCH_NETEM_ATTR_DUPLICATE | SCH_NETEM_ATTR_JITTER); - - 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 *) - (tc->tc_opts->d_data + sizeof(*opts)), - len, netem_policy); - if (err < 0) { - free(netem); - return err; - } - - if (tb[TCA_NETEM_CORR]) { - struct tc_netem_corr cor; - - nla_memcpy(&cor, tb[TCA_NETEM_CORR], sizeof(cor)); - netem->qnm_corr.nmc_delay = cor.delay_corr; - netem->qnm_corr.nmc_loss = cor.loss_corr; - netem->qnm_corr.nmc_duplicate = cor.dup_corr; - - netem->qnm_mask |= (SCH_NETEM_ATTR_DELAY_CORR | - SCH_NETEM_ATTR_LOSS_CORR | - SCH_NETEM_ATTR_DUP_CORR); - } - - if (tb[TCA_NETEM_REORDER]) { - struct tc_netem_reorder ro; - - nla_memcpy(&ro, tb[TCA_NETEM_REORDER], sizeof(ro)); - netem->qnm_ro.nmro_probability = ro.probability; - netem->qnm_ro.nmro_correlation = ro.correlation; - - netem->qnm_mask |= (SCH_NETEM_ATTR_RO_PROB | - SCH_NETEM_ATTR_RO_CORR); - } - - if (tb[TCA_NETEM_CORRUPT]) { - struct tc_netem_corrupt corrupt; - - nla_memcpy(&corrupt, tb[TCA_NETEM_CORRUPT], sizeof(corrupt)); - netem->qnm_crpt.nmcr_probability = corrupt.probability; - netem->qnm_crpt.nmcr_correlation = corrupt.correlation; - - netem->qnm_mask |= (SCH_NETEM_ATTR_CORRUPT_PROB | - SCH_NETEM_ATTR_CORRUPT_CORR); - } - - /* sch_netem does not currently dump TCA_NETEM_DELAY_DIST */ - netem->qnm_dist.dist_data = NULL; - netem->qnm_dist.dist_size = 0; - } - - return 0; -} - -static void netem_free_data(struct rtnl_tc *tc, void *data) -{ - struct rtnl_netem *netem = data; - - if (!netem) - return; - - free(netem->qnm_dist.dist_data); -} - -static void netem_dump_line(struct rtnl_tc *tc, void *data, - struct nl_dump_params *p) -{ - struct rtnl_netem *netem = data; - - if (netem) - nl_dump(p, "limit %d", netem->qnm_limit); -} - -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 = 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)); - - msg->nm_nlh->nlmsg_flags |= NLM_F_REQUEST; - - if ( netem->qnm_ro.nmro_probability != 0 ) { - if (netem->qnm_latency == 0) { - return -NLE_MISSING_ATTR; - } - if (netem->qnm_gap == 0) netem->qnm_gap = 1; - } - else if ( netem->qnm_gap ) { - return -NLE_MISSING_ATTR; - } - - if ( netem->qnm_corr.nmc_delay != 0 ) { - if ( netem->qnm_latency == 0 || netem->qnm_jitter == 0) { - return -NLE_MISSING_ATTR; - } - set_correlation = 1; - } - - if ( netem->qnm_corr.nmc_loss != 0 ) { - if ( netem->qnm_loss == 0 ) { - return -NLE_MISSING_ATTR; - } - set_correlation = 1; - } - - if ( netem->qnm_corr.nmc_duplicate != 0 ) { - if ( netem->qnm_duplicate == 0 ) { - return -NLE_MISSING_ATTR; - } - set_correlation = 1; - } - - if ( netem->qnm_ro.nmro_probability != 0 ) set_reorder = 1; - else if ( netem->qnm_ro.nmro_correlation != 0 ) { - return -NLE_MISSING_ATTR; - } - - if ( netem->qnm_crpt.nmcr_probability != 0 ) set_corrupt = 1; - else if ( netem->qnm_crpt.nmcr_correlation != 0 ) { - return -NLE_MISSING_ATTR; - } - - if ( netem->qnm_dist.dist_data && netem->qnm_dist.dist_size ) { - if (netem->qnm_latency == 0 || netem->qnm_jitter == 0) { - return -NLE_MISSING_ATTR; - } - else { - /* Resize to accomodate the large distribution table */ - int new_msg_len = msg->nm_size + netem->qnm_dist.dist_size * - sizeof(netem->qnm_dist.dist_data[0]); - - msg->nm_nlh = (struct nlmsghdr *) realloc(msg->nm_nlh, new_msg_len); - if ( msg->nm_nlh == NULL ) - return -NLE_NOMEM; - msg->nm_size = new_msg_len; - set_dist = 1; - } - } - - opts.latency = netem->qnm_latency; - opts.limit = netem->qnm_limit ? netem->qnm_limit : 1000; - opts.loss = netem->qnm_loss; - opts.gap = netem->qnm_gap; - opts.duplicate = netem->qnm_duplicate; - opts.jitter = netem->qnm_jitter; - - NLA_PUT(msg, TCA_OPTIONS, sizeof(opts), &opts); - - if ( set_correlation ) { - cor.delay_corr = netem->qnm_corr.nmc_delay; - cor.loss_corr = netem->qnm_corr.nmc_loss; - cor.dup_corr = netem->qnm_corr.nmc_duplicate; - - NLA_PUT(msg, TCA_NETEM_CORR, sizeof(cor), &cor); - } - - if ( set_reorder ) { - reorder.probability = netem->qnm_ro.nmro_probability; - reorder.correlation = netem->qnm_ro.nmro_correlation; - - NLA_PUT(msg, TCA_NETEM_REORDER, sizeof(reorder), &reorder); - } - - if ( set_corrupt ) { - corrupt.probability = netem->qnm_crpt.nmcr_probability; - corrupt.correlation = netem->qnm_crpt.nmcr_correlation; - - NLA_PUT(msg, TCA_NETEM_CORRUPT, sizeof(corrupt), &corrupt); - } - - if ( set_dist ) { - NLA_PUT(msg, TCA_NETEM_DELAY_DIST, - netem->qnm_dist.dist_size * sizeof(netem->qnm_dist.dist_data[0]), - netem->qnm_dist.dist_data); - } - - /* Length specified in the TCA_OPTIONS section must span the entire - * remainder of the message. That's just the way that sch_netem expects it. - * Maybe there's a more succinct way to do this at a higher level. - */ - struct nlattr* head = (struct nlattr *)(NLMSG_DATA(msg->nm_nlh) + - NLMSG_LENGTH(sizeof(struct tcmsg)) - NLMSG_ALIGNTO); - - struct nlattr* tail = (struct nlattr *)(((void *) (msg->nm_nlh)) + - NLMSG_ALIGN(msg->nm_nlh->nlmsg_len)); - - int old_len = head->nla_len; - head->nla_len = (void *)tail - (void *)head; - msg->nm_nlh->nlmsg_len += (head->nla_len - old_len); - - return err; -nla_put_failure: - return -NLE_MSGSIZE; -} - -/** - * @name Queue Limit - * @{ - */ - -/** - * Set limit of netem qdisc. - * @arg qdisc Netem qdisc to be modified. - * @arg limit New limit in bytes. - * @return 0 on success or a negative error code. - */ -void rtnl_netem_set_limit(struct rtnl_qdisc *qdisc, int limit) -{ - struct rtnl_netem *netem; - - if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - netem->qnm_limit = limit; - netem->qnm_mask |= SCH_NETEM_ATTR_LIMIT; -} - -/** - * Get limit of netem qdisc. - * @arg qdisc Netem qdisc. - * @return Limit in bytes or a negative error code. - */ -int rtnl_netem_get_limit(struct rtnl_qdisc *qdisc) -{ - struct rtnl_netem *netem; - - 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; -} - -/** @} */ - -/** - * @name Packet Re-ordering - * @{ - */ - -/** - * Set re-ordering gap of netem qdisc. - * @arg qdisc Netem qdisc to be modified. - * @arg gap New gap in number of packets. - * @return 0 on success or a negative error code. - */ -void rtnl_netem_set_gap(struct rtnl_qdisc *qdisc, int gap) -{ - struct rtnl_netem *netem; - - if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - netem->qnm_gap = gap; - netem->qnm_mask |= SCH_NETEM_ATTR_GAP; -} - -/** - * Get re-ordering gap of netem qdisc. - * @arg qdisc Netem qdisc. - * @return Re-ordering gap in packets or a negative error code. - */ -int rtnl_netem_get_gap(struct rtnl_qdisc *qdisc) -{ - struct rtnl_netem *netem; - - 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; -} - -/** - * Set re-ordering probability of netem qdisc. - * @arg qdisc Netem qdisc to be modified. - * @arg prob New re-ordering probability. - * @return 0 on success or a negative error code. - */ -void rtnl_netem_set_reorder_probability(struct rtnl_qdisc *qdisc, int prob) -{ - struct rtnl_netem *netem; - - if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - netem->qnm_ro.nmro_probability = prob; - netem->qnm_mask |= SCH_NETEM_ATTR_RO_PROB; -} - -/** - * Get re-ordering probability of netem qdisc. - * @arg qdisc Netem qdisc. - * @return Re-ordering probability or a negative error code. - */ -int rtnl_netem_get_reorder_probability(struct rtnl_qdisc *qdisc) -{ - struct rtnl_netem *netem; - - 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; -} - -/** - * Set re-order correlation probability of netem qdisc. - * @arg qdisc Netem qdisc to be modified. - * @arg prob New re-ordering correlation probability. - * @return 0 on success or a negative error code. - */ -void rtnl_netem_set_reorder_correlation(struct rtnl_qdisc *qdisc, int prob) -{ - struct rtnl_netem *netem; - - if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - netem->qnm_ro.nmro_correlation = prob; - netem->qnm_mask |= SCH_NETEM_ATTR_RO_CORR; -} - -/** - * Get re-ordering correlation probability of netem qdisc. - * @arg qdisc Netem qdisc. - * @return Re-ordering correlation probability or a negative error code. - */ -int rtnl_netem_get_reorder_correlation(struct rtnl_qdisc *qdisc) -{ - struct rtnl_netem *netem; - - 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; -} - -/** @} */ - -/** - * @name Corruption - * @{ - */ - -/** - * Set corruption probability of netem qdisc. - * @arg qdisc Netem qdisc to be modified. - * @arg prob New corruption probability. - * @return 0 on success or a negative error code. - */ -void rtnl_netem_set_corruption_probability(struct rtnl_qdisc *qdisc, int prob) -{ - struct rtnl_netem *netem; - - if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - netem->qnm_crpt.nmcr_probability = prob; - netem->qnm_mask |= SCH_NETEM_ATTR_CORRUPT_PROB; -} - -/** - * Get corruption probability of netem qdisc. - * @arg qdisc Netem qdisc. - * @return Corruption probability or a negative error code. - */ -int rtnl_netem_get_corruption_probability(struct rtnl_qdisc *qdisc) -{ - struct rtnl_netem *netem; - - 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; -} - -/** - * Set corruption correlation probability of netem qdisc. - * @arg qdisc Netem qdisc to be modified. - * @arg prob New corruption correlation probability. - * @return 0 on success or a negative error code. - */ -void rtnl_netem_set_corruption_correlation(struct rtnl_qdisc *qdisc, int prob) -{ - struct rtnl_netem *netem; - - if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - netem->qnm_crpt.nmcr_correlation = prob; - netem->qnm_mask |= SCH_NETEM_ATTR_CORRUPT_CORR; -} - -/** - * Get corruption correlation probability of netem qdisc. - * @arg qdisc Netem qdisc. - * @return Corruption correlation probability or a negative error code. - */ -int rtnl_netem_get_corruption_correlation(struct rtnl_qdisc *qdisc) -{ - struct rtnl_netem *netem; - - 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; -} - -/** @} */ - -/** - * @name Packet Loss - * @{ - */ - -/** - * Set packet loss probability of netem qdisc. - * @arg qdisc Netem qdisc to be modified. - * @arg prob New packet loss probability. - * @return 0 on success or a negative error code. - */ -void rtnl_netem_set_loss(struct rtnl_qdisc *qdisc, int prob) -{ - struct rtnl_netem *netem; - - if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - netem->qnm_loss = prob; - netem->qnm_mask |= SCH_NETEM_ATTR_LOSS; -} - -/** - * Get packet loss probability of netem qdisc. - * @arg qdisc Netem qdisc. - * @return Packet loss probability or a negative error code. - */ -int rtnl_netem_get_loss(struct rtnl_qdisc *qdisc) -{ - struct rtnl_netem *netem; - - 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; -} - -/** - * Set packet loss correlation probability of netem qdisc. - * @arg qdisc Netem qdisc to be modified. - * @arg prob New packet loss correlation. - * @return 0 on success or a negative error code. - */ -void rtnl_netem_set_loss_correlation(struct rtnl_qdisc *qdisc, int prob) -{ - struct rtnl_netem *netem; - - if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - netem->qnm_corr.nmc_loss = prob; - netem->qnm_mask |= SCH_NETEM_ATTR_LOSS_CORR; -} - -/** - * Get packet loss correlation probability of netem qdisc. - * @arg qdisc Netem qdisc. - * @return Packet loss correlation probability or a negative error code. - */ -int rtnl_netem_get_loss_correlation(struct rtnl_qdisc *qdisc) -{ - struct rtnl_netem *netem; - - 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; -} - -/** @} */ - -/** - * @name Packet Duplication - * @{ - */ - -/** - * Set packet duplication probability of netem qdisc. - * @arg qdisc Netem qdisc to be modified. - * @arg prob New packet duplication probability. - * @return 0 on success or a negative error code. - */ -void rtnl_netem_set_duplicate(struct rtnl_qdisc *qdisc, int prob) -{ - struct rtnl_netem *netem; - - if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - netem->qnm_duplicate = prob; - netem->qnm_mask |= SCH_NETEM_ATTR_DUPLICATE; -} - -/** - * Get packet duplication probability of netem qdisc. - * @arg qdisc Netem qdisc. - * @return Packet duplication probability or a negative error code. - */ -int rtnl_netem_get_duplicate(struct rtnl_qdisc *qdisc) -{ - struct rtnl_netem *netem; - - 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; -} - -/** - * Set packet duplication correlation probability of netem qdisc. - * @arg qdisc Netem qdisc to be modified. - * @arg prob New packet duplication correlation probability. - * @return 0 on sucess or a negative error code. - */ -void rtnl_netem_set_duplicate_correlation(struct rtnl_qdisc *qdisc, int prob) -{ - struct rtnl_netem *netem; - - if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - netem->qnm_corr.nmc_duplicate = prob; - netem->qnm_mask |= SCH_NETEM_ATTR_DUP_CORR; -} - -/** - * Get packet duplication correlation probability of netem qdisc. - * @arg qdisc Netem qdisc. - * @return Packet duplication correlation probability or a negative error code. - */ -int rtnl_netem_get_duplicate_correlation(struct rtnl_qdisc *qdisc) -{ - struct rtnl_netem *netem; - - 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; -} - -/** @} */ - -/** - * @name Packet Delay - * @{ - */ - -/** - * Set packet delay of netem qdisc. - * @arg qdisc Netem qdisc to be modified. - * @arg delay New packet delay in micro seconds. - * @return 0 on success or a negative error code. - */ -void rtnl_netem_set_delay(struct rtnl_qdisc *qdisc, int delay) -{ - struct rtnl_netem *netem; - - if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - netem->qnm_latency = nl_us2ticks(delay); - netem->qnm_mask |= SCH_NETEM_ATTR_LATENCY; -} - -/** - * Get packet delay of netem qdisc. - * @arg qdisc Netem qdisc. - * @return Packet delay in micro seconds or a negative error code. - */ -int rtnl_netem_get_delay(struct rtnl_qdisc *qdisc) -{ - struct rtnl_netem *netem; - - 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; -} - -/** - * Set packet delay jitter of netem qdisc. - * @arg qdisc Netem qdisc to be modified. - * @arg jitter New packet delay jitter in micro seconds. - * @return 0 on success or a negative error code. - */ -void rtnl_netem_set_jitter(struct rtnl_qdisc *qdisc, int jitter) -{ - struct rtnl_netem *netem; - - if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - netem->qnm_jitter = nl_us2ticks(jitter); - netem->qnm_mask |= SCH_NETEM_ATTR_JITTER; -} - -/** - * Get packet delay jitter of netem qdisc. - * @arg qdisc Netem qdisc. - * @return Packet delay jitter in micro seconds or a negative error code. - */ -int rtnl_netem_get_jitter(struct rtnl_qdisc *qdisc) -{ - struct rtnl_netem *netem; - - 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; -} - -/** - * Set packet delay correlation probability of netem qdisc. - * @arg qdisc Netem qdisc to be modified. - * @arg prob New packet delay correlation probability. - */ -void rtnl_netem_set_delay_correlation(struct rtnl_qdisc *qdisc, int prob) -{ - struct rtnl_netem *netem; - - if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - netem->qnm_corr.nmc_delay = prob; - netem->qnm_mask |= SCH_NETEM_ATTR_DELAY_CORR; -} - -/** - * Get packet delay correlation probability of netem qdisc. - * @arg qdisc Netem qdisc. - * @return Packet delay correlation probability or a negative error code. - */ -int rtnl_netem_get_delay_correlation(struct rtnl_qdisc *qdisc) -{ - struct rtnl_netem *netem; - - 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; -} - -/** - * Get the size of the distribution table. - * @arg qdisc Netem qdisc. - * @return Distribution table size or a negative error code. - */ -int rtnl_netem_get_delay_distribution_size(struct rtnl_qdisc *qdisc) -{ - struct rtnl_netem *netem; - - 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; -} - -/** - * Get a pointer to the distribution table. - * @arg qdisc Netem qdisc. - * @arg dist_ptr The pointer to set. - * @return Negative error code on failure or 0 on success. - */ -int rtnl_netem_get_delay_distribution(struct rtnl_qdisc *qdisc, int16_t **dist_ptr) -{ - struct rtnl_netem *netem; - - 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 - return -NLE_NOATTR; -} - -/** - * Set the delay distribution. Latency/jitter must be set before applying. - * @arg qdisc Netem qdisc. - * @arg dist_type The name of the distribution (type, file, path/file). - * @return 0 on success, error code on failure. - */ -int rtnl_netem_set_delay_distribution(struct rtnl_qdisc *qdisc, const char *dist_type) { - struct rtnl_netem *netem; - - if (!(netem = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - FILE *f = NULL; - int i, n = 0; - size_t len = 2048; - char *line; - char name[NAME_MAX]; - char dist_suffix[] = ".dist"; - - /* If the given filename already ends in .dist, don't append it later */ - char *test_suffix = strstr(dist_type, dist_suffix); - if (test_suffix != NULL && strlen(test_suffix) == 5) - strcpy(dist_suffix, ""); - - /* Check several locations for the dist file */ - char *test_path[] = { "", "./", "/usr/lib/tc/", "/usr/local/lib/tc/" }; - - for (i = 0; i < sizeof(test_path) && f == NULL; i++) { - snprintf(name, NAME_MAX, "%s%s%s", test_path[i], dist_type, dist_suffix); - f = fopen(name, "r"); - } - - if ( f == NULL ) - return -nl_syserr2nlerr(errno); - - netem->qnm_dist.dist_data = (int16_t *) calloc (MAXDIST, sizeof(int16_t)); - - line = (char *) calloc (sizeof(char), len + 1); - - while (getline(&line, &len, f) != -1) { - char *p, *endp; - - if (*line == '\n' || *line == '#') - continue; - - for (p = line; ; p = endp) { - long x = strtol(p, &endp, 0); - if (endp == p) break; - - if (n >= MAXDIST) { - free(line); - fclose(f); - return -NLE_INVAL; - } - netem->qnm_dist.dist_data[n++] = x; - } - } - - free(line); - - netem->qnm_dist.dist_size = n; - netem->qnm_mask |= SCH_NETEM_ATTR_DIST; - - fclose(f); - return 0; -} - -/** @} */ - -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_tc_register(&netem_ops); -} - -static void __exit netem_exit(void) -{ - rtnl_tc_unregister(&netem_ops); -} - -/** @} */ diff --git a/lib/route/sch/prio.c b/lib/route/sch/prio.c deleted file mode 100644 index 6f8ff34..0000000 --- a/lib/route/sch/prio.c +++ /dev/null @@ -1,294 +0,0 @@ -/* - * lib/route/sch/prio.c PRIO Qdisc/Class - * - * 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-2011 Thomas Graf - */ - -/** - * @ingroup qdisc - * @defgroup qdisc_prio (Fast) Prio - * @brief - * - * @par 1) Typical PRIO configuration - * @code - * // Specify the maximal number of bands to be used for this PRIO qdisc. - * rtnl_qdisc_prio_set_bands(qdisc, QDISC_PRIO_DEFAULT_BANDS); - * - * // Provide a map assigning each priority to a band number. - * uint8_t map[] = QDISC_PRIO_DEFAULT_PRIOMAP; - * rtnl_qdisc_prio_set_priomap(qdisc, map, sizeof(map)); - * @endcode - * @{ - */ - -#include -#include -#include -#include -#include -#include -#include - -/** @cond SKIP */ -#define SCH_PRIO_ATTR_BANDS 1 -#define SCH_PRIO_ATTR_PRIOMAP 2 -/** @endcond */ - -static int prio_msg_parser(struct rtnl_tc *tc, void *data) -{ - struct rtnl_prio *prio = data; - struct tc_prio_qopt *opt; - - if (tc->tc_opts->d_size < sizeof(*opt)) - return -NLE_INVAL; - - 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); - - return 0; -} - -static void prio_dump_line(struct rtnl_tc *tc, void *data, - struct nl_dump_params *p) -{ - struct rtnl_prio *prio = data; - - if (prio) - nl_dump(p, " bands %u", prio->qp_bands); -} - -static void prio_dump_details(struct rtnl_tc *tc, void *data, - struct nl_dump_params *p) -{ - struct rtnl_prio *prio = data; - int i, hp; - - if (!prio) - return; - - nl_dump(p, "priomap ["); - - for (i = 0; i <= TC_PRIO_MAX; i++) - nl_dump(p, "%u%s", prio->qp_priomap[i], - i < TC_PRIO_MAX ? " " : ""); - - nl_dump(p, "]\n"); - nl_new_line(p); - - hp = (((TC_PRIO_MAX/2) + 1) & ~1); - - for (i = 0; i < hp; i++) { - char a[32]; - nl_dump(p, " %18s => %u", - rtnl_prio2str(i, a, sizeof(a)), - prio->qp_priomap[i]); - if (hp+i <= TC_PRIO_MAX) { - nl_dump(p, " %18s => %u", - rtnl_prio2str(hp+i, a, sizeof(a)), - prio->qp_priomap[hp+i]); - if (i < (hp - 1)) { - nl_dump(p, "\n"); - nl_new_line(p); - } - } - } -} - -static int prio_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) -{ - struct rtnl_prio *prio = data; - struct tc_prio_qopt opts; - - if (!prio || !(prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP)) - BUG(); - - opts.bands = prio->qp_bands; - memcpy(opts.priomap, prio->qp_priomap, sizeof(opts.priomap)); - - return nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD); -} - -/** - * @name Attribute Modification - * @{ - */ - -/** - * Set number of bands of PRIO qdisc. - * @arg qdisc PRIO qdisc to be modified. - * @arg bands New number of bands. - * @return 0 on success or a negative error code. - */ -void rtnl_qdisc_prio_set_bands(struct rtnl_qdisc *qdisc, int bands) -{ - struct rtnl_prio *prio; - - if (!(prio = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - prio->qp_bands = bands; - prio->qp_mask |= SCH_PRIO_ATTR_BANDS; -} - -/** - * Get number of bands of PRIO qdisc. - * @arg qdisc PRIO qdisc. - * @return Number of bands or a negative error code. - */ -int rtnl_qdisc_prio_get_bands(struct rtnl_qdisc *qdisc) -{ - struct rtnl_prio *prio; - - 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; -} - -/** - * Set priomap of the PRIO qdisc. - * @arg qdisc PRIO qdisc to be modified. - * @arg priomap New priority mapping. - * @arg len Length of priomap (# of elements). - * @return 0 on success or a negative error code. - */ -int rtnl_qdisc_prio_set_priomap(struct rtnl_qdisc *qdisc, uint8_t priomap[], - int len) -{ - struct rtnl_prio *prio; - int i; - - if (!(prio = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - if (!(prio->qp_mask & SCH_PRIO_ATTR_BANDS)) - return -NLE_MISSING_ATTR; - - if ((len / sizeof(uint8_t)) > (TC_PRIO_MAX+1)) - return -NLE_RANGE; - - for (i = 0; i <= TC_PRIO_MAX; i++) { - if (priomap[i] > prio->qp_bands) - return -NLE_RANGE; - } - - memcpy(prio->qp_priomap, priomap, len); - prio->qp_mask |= SCH_PRIO_ATTR_PRIOMAP; - - return 0; -} - -/** - * Get priomap of a PRIO qdisc. - * @arg qdisc PRIO qdisc. - * @return Priority mapping as array of size TC_PRIO_MAX+1 - * or NULL if an error occured. - */ -uint8_t *rtnl_qdisc_prio_get_priomap(struct rtnl_qdisc *qdisc) -{ - struct rtnl_prio *prio; - - if (!(prio = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - if (prio->qp_mask & SCH_PRIO_ATTR_PRIOMAP) - return prio->qp_priomap; - else - return NULL; -} - -/** @} */ - -/** - * @name Priority Band Translations - * @{ - */ - -static const struct trans_tbl prios[] = { - __ADD(TC_PRIO_BESTEFFORT,besteffort) - __ADD(TC_PRIO_FILLER,filler) - __ADD(TC_PRIO_BULK,bulk) - __ADD(TC_PRIO_INTERACTIVE_BULK,interactive_bulk) - __ADD(TC_PRIO_INTERACTIVE,interactive) - __ADD(TC_PRIO_CONTROL,control) -}; - -/** - * Convert priority to character string. - * @arg prio Priority. - * @arg buf Destination buffer - * @arg size Size of destination buffer. - * - * Converts a priority to a character string and stores the result in - * the specified destination buffer. - * - * @return Name of priority as character string. - */ -char * rtnl_prio2str(int prio, char *buf, size_t size) -{ - return __type2str(prio, buf, size, prios, ARRAY_SIZE(prios)); -} - -/** - * Convert character string to priority. - * @arg name Name of priority. - * - * Converts the provided character string specifying a priority - * to the corresponding numeric value. - * - * @return Numeric priority or a negative value if no match was found. - */ -int rtnl_str2prio(const char *name) -{ - return __str2type(name, prios, ARRAY_SIZE(prios)); -} - -/** @} */ - -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, - }, - .to_msg_fill = prio_msg_fill, -}; - -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, - }, - .to_msg_fill = prio_msg_fill, -}; - -static void __init prio_init(void) -{ - rtnl_tc_register(&prio_ops); - rtnl_tc_register(&pfifo_fast_ops); -} - -static void __exit prio_exit(void) -{ - rtnl_tc_unregister(&prio_ops); - rtnl_tc_unregister(&pfifo_fast_ops); -} - -/** @} */ diff --git a/lib/route/sch/red.c b/lib/route/sch/red.c deleted file mode 100644 index 5df3f3c..0000000 --- a/lib/route/sch/red.c +++ /dev/null @@ -1,190 +0,0 @@ -/* - * lib/route/sch/red.c RED Qdisc - * - * 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-2011 Thomas Graf - */ - -/** - * @ingroup qdisc - * @defgroup qdisc_red Random Early Detection (RED) - * @brief - * @{ - */ - -#include -#include -#include -#include -#include -#include -#include - -/** @cond SKIP */ -#define RED_ATTR_LIMIT 0x01 -#define RED_ATTR_QTH_MIN 0x02 -#define RED_ATTR_QTH_MAX 0x04 -#define RED_ATTR_FLAGS 0x08 -#define RED_ATTR_WLOG 0x10 -#define RED_ATTR_PLOG 0x20 -#define RED_ATTR_SCELL_LOG 0x40 -/** @endcond */ - -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_tc *tc, void *data) -{ - struct nlattr *tb[TCA_RED_MAX+1]; - struct rtnl_red *red = data; - struct tc_red_qopt *opts; - int err; - - if (!(tc->ce_mask & TCA_ATTR_OPTS)) - return 0; - - err = tca_parse(tb, TCA_RED_MAX, tc, red_policy); - if (err < 0) - return err; - - if (!tb[TCA_RED_PARMS]) - return -NLE_MISSING_ATTR; - - opts = nla_data(tb[TCA_RED_PARMS]); - - red->qr_limit = opts->limit; - red->qr_qth_min = opts->qth_min; - red->qr_qth_max = opts->qth_max; - red->qr_flags = opts->flags; - red->qr_wlog = opts->Wlog; - red->qr_plog = opts->Plog; - red->qr_scell_log = opts->Scell_log; - - red->qr_mask = (RED_ATTR_LIMIT | RED_ATTR_QTH_MIN | RED_ATTR_QTH_MAX | - RED_ATTR_FLAGS | RED_ATTR_WLOG | RED_ATTR_PLOG | - RED_ATTR_SCELL_LOG); - - return 0; -} - -static void red_dump_line(struct rtnl_tc *tc, void *data, - struct nl_dump_params *p) -{ - struct rtnl_red *red = data; - - if (red) { - /* XXX: limit, min, max, flags */ - } -} - -static void red_dump_details(struct rtnl_tc *tc, void *data, - struct nl_dump_params *p) -{ - struct rtnl_red *red = data; - - if (red) { - /* XXX: wlog, plog, scell_log */ - } -} - -static void red_dump_stats(struct rtnl_tc *tc, void *data, - struct nl_dump_params *p) -{ - struct rtnl_red *red = data; - - if (red) { - /* XXX: xstats */ - } -} - -static int red_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) -{ - struct rtnl_red *red = data; - - if (!red) - BUG(); - -#if 0 - 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; -#endif - - return -NLE_OPNOTSUPP; -} - -/** - * @name Attribute Access - * @{ - */ - -/** - * Set limit of RED qdisc. - * @arg qdisc RED qdisc to be modified. - * @arg limit New limit in number of packets. - * @return 0 on success or a negative error code. - */ -void rtnl_red_set_limit(struct rtnl_qdisc *qdisc, int limit) -{ - struct rtnl_red *red; - - if (!(red = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - red->qr_limit = limit; - red->qr_mask |= RED_ATTR_LIMIT; -} - -/** - * Get limit of RED qdisc. - * @arg qdisc RED qdisc. - * @return Limit or a negative error code. - */ -int rtnl_red_get_limit(struct rtnl_qdisc *qdisc) -{ - struct rtnl_red *red; - - if (!(red = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - if (red->qr_mask & RED_ATTR_LIMIT) - return red->qr_limit; - else - return -NLE_NOATTR; -} - -/** @} */ - -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, - }, - .to_msg_fill = red_msg_fill, -}; - -static void __init red_init(void) -{ - rtnl_tc_register(&red_ops); -} - -static void __exit red_exit(void) -{ - rtnl_tc_unregister(&red_ops); -} - -/** @} */ diff --git a/lib/route/sch/sfq.c b/lib/route/sch/sfq.c deleted file mode 100644 index e817a6a..0000000 --- a/lib/route/sch/sfq.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - * lib/route/sch/sfq.c SFQ Qdisc - * - * 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-2011 Thomas Graf - */ - -/** - * @ingroup qdisc - * @defgroup qdisc_sfq Stochastic Fairness Queueing (SFQ) - * @brief - * - * @par Parameter Description - * - \b Quantum: Number of bytes to send out per slot and round. - * - \b Perturbation: Timer period between changing the hash function. - * - \b Limit: Upper limit of queue in number of packets before SFQ starts - * dropping packets. - * - \b Divisor: Hash table divisor, i.e. size of hash table. - * @{ - */ - -#include -#include -#include -#include -#include -#include -#include - -/** @cond SKIP */ -#define SCH_SFQ_ATTR_QUANTUM 0x01 -#define SCH_SFQ_ATTR_PERTURB 0x02 -#define SCH_SFQ_ATTR_LIMIT 0x04 -#define SCH_SFQ_ATTR_DIVISOR 0x08 -#define SCH_SFQ_ATTR_FLOWS 0x10 -/** @endcond */ - -static int sfq_msg_parser(struct rtnl_tc *tc, void *data) -{ - struct rtnl_sfq *sfq = data; - struct tc_sfq_qopt *opts; - - if (!(tc->ce_mask & TCA_ATTR_OPTS)) - return 0; - - if (tc->tc_opts->d_size < sizeof(*opts)) - return -NLE_INVAL; - - opts = (struct tc_sfq_qopt *) tc->tc_opts->d_data; - - sfq->qs_quantum = opts->quantum; - sfq->qs_perturb = opts->perturb_period; - sfq->qs_limit = opts->limit; - sfq->qs_divisor = opts->divisor; - sfq->qs_flows = opts->flows; - - sfq->qs_mask = (SCH_SFQ_ATTR_QUANTUM | SCH_SFQ_ATTR_PERTURB | - SCH_SFQ_ATTR_LIMIT | SCH_SFQ_ATTR_DIVISOR | - SCH_SFQ_ATTR_FLOWS); - - return 0; -} - -static void sfq_dump_line(struct rtnl_tc *tc, void *data, - struct nl_dump_params *p) -{ - 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_tc *tc, void *data, - struct nl_dump_params *p) -{ - struct rtnl_sfq *sfq = data; - - if (sfq) - nl_dump(p, "limit %u divisor %u", - sfq->qs_limit, sfq->qs_divisor); -} - -static int sfq_msg_fill(struct rtnl_tc *tc, void *data, struct nl_msg *msg) -{ - struct rtnl_sfq *sfq = data; - struct tc_sfq_qopt opts = {0}; - - if (!sfq) - BUG(); - - opts.quantum = sfq->qs_quantum; - opts.perturb_period = sfq->qs_perturb; - opts.limit = sfq->qs_limit; - - return nlmsg_append(msg, &opts, sizeof(opts), NL_DONTPAD); -} - -/** - * @name Attribute Access - * @{ - */ - -/** - * Set quantum of SFQ qdisc. - * @arg qdisc SFQ qdisc to be modified. - * @arg quantum New quantum in bytes. - * @return 0 on success or a negative error code. - */ -void rtnl_sfq_set_quantum(struct rtnl_qdisc *qdisc, int quantum) -{ - struct rtnl_sfq *sfq; - - if (!(sfq = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - sfq->qs_quantum = quantum; - sfq->qs_mask |= SCH_SFQ_ATTR_QUANTUM; -} - -/** - * Get quantum of SFQ qdisc. - * @arg qdisc SFQ qdisc. - * @return Quantum in bytes or a negative error code. - */ -int rtnl_sfq_get_quantum(struct rtnl_qdisc *qdisc) -{ - struct rtnl_sfq *sfq; - - if (!(sfq = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - if (sfq->qs_mask & SCH_SFQ_ATTR_QUANTUM) - return sfq->qs_quantum; - else - return -NLE_NOATTR; -} - -/** - * Set limit of SFQ qdisc. - * @arg qdisc SFQ qdisc to be modified. - * @arg limit New limit in number of packets. - * @return 0 on success or a negative error code. - */ -void rtnl_sfq_set_limit(struct rtnl_qdisc *qdisc, int limit) -{ - struct rtnl_sfq *sfq; - - if (!(sfq = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - sfq->qs_limit = limit; - sfq->qs_mask |= SCH_SFQ_ATTR_LIMIT; -} - -/** - * Get limit of SFQ qdisc. - * @arg qdisc SFQ qdisc. - * @return Limit or a negative error code. - */ -int rtnl_sfq_get_limit(struct rtnl_qdisc *qdisc) -{ - struct rtnl_sfq *sfq; - - if (!(sfq = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - if (sfq->qs_mask & SCH_SFQ_ATTR_LIMIT) - return sfq->qs_limit; - else - return -NLE_NOATTR; -} - -/** - * Set perturbation interval of SFQ qdisc. - * @arg qdisc SFQ qdisc to be modified. - * @arg perturb New perturbation interval in seconds. - * @note A value of 0 disables perturbation altogether. - * @return 0 on success or a negative error code. - */ -void rtnl_sfq_set_perturb(struct rtnl_qdisc *qdisc, int perturb) -{ - struct rtnl_sfq *sfq; - - if (!(sfq = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - sfq->qs_perturb = perturb; - sfq->qs_mask |= SCH_SFQ_ATTR_PERTURB; -} - -/** - * Get perturbation interval of SFQ qdisc. - * @arg qdisc SFQ qdisc. - * @return Perturbation interval in seconds or a negative error code. - */ -int rtnl_sfq_get_perturb(struct rtnl_qdisc *qdisc) -{ - struct rtnl_sfq *sfq; - - if (!(sfq = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - if (sfq->qs_mask & SCH_SFQ_ATTR_PERTURB) - return sfq->qs_perturb; - else - return -NLE_NOATTR; -} - -/** - * Get divisor of SFQ qdisc. - * @arg qdisc SFQ qdisc. - * @return Divisor in number of entries or a negative error code. - */ -int rtnl_sfq_get_divisor(struct rtnl_qdisc *qdisc) -{ - struct rtnl_sfq *sfq; - - if (!(sfq = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - if (sfq->qs_mask & SCH_SFQ_ATTR_DIVISOR) - return sfq->qs_divisor; - else - return -NLE_NOATTR; -} - -/** @} */ - -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, - }, - .to_msg_fill = sfq_msg_fill, -}; - -static void __init sfq_init(void) -{ - rtnl_tc_register(&sfq_ops); -} - -static void __exit sfq_exit(void) -{ - rtnl_tc_unregister(&sfq_ops); -} - -/** @} */ diff --git a/lib/route/sch/tbf.c b/lib/route/sch/tbf.c deleted file mode 100644 index 8e76a5b..0000000 --- a/lib/route/sch/tbf.c +++ /dev/null @@ -1,460 +0,0 @@ -/* - * lib/route/sch/tbf.c TBF Qdisc - * - * 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-2011 Thomas Graf - */ - -/** - * @ingroup qdisc - * @defgroup qdisc_tbf Token Bucket Filter (TBF) - * @{ - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** @cond SKIP */ -#define TBF_ATTR_LIMIT 0x01 -#define TBF_ATTR_RATE 0x02 -#define TBF_ATTR_PEAKRATE 0x10 -/** @endcond */ - -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_tc *tc, void *data) -{ - struct nlattr *tb[TCA_TBF_MAX + 1]; - struct rtnl_tbf *tbf = data; - int err; - - if ((err = tca_parse(tb, TCA_TBF_MAX, tc, tbf_policy)) < 0) - return err; - - if (tb[TCA_TBF_PARMS]) { - struct tc_tbf_qopt opts; - int bufsize; - - nla_memcpy(&opts, tb[TCA_TBF_PARMS], sizeof(opts)); - tbf->qt_limit = opts.limit; - - rtnl_copy_ratespec(&tbf->qt_rate, &opts.rate); - tbf->qt_rate_txtime = opts.buffer; - bufsize = rtnl_tc_calc_bufsize(nl_ticks2us(opts.buffer), - opts.rate.rate); - tbf->qt_rate_bucket = bufsize; - - rtnl_copy_ratespec(&tbf->qt_peakrate, &opts.peakrate); - tbf->qt_peakrate_txtime = opts.mtu; - bufsize = rtnl_tc_calc_bufsize(nl_ticks2us(opts.mtu), - opts.peakrate.rate); - tbf->qt_peakrate_bucket = bufsize; - - 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); - } - - return 0; -} - -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 = data; - - if (!tbf) - return; - - r = nl_cancel_down_bytes(tbf->qt_rate.rs_rate, &ru); - rbit = nl_cancel_down_bits(tbf->qt_rate.rs_rate*8, &rubit); - lim = nl_cancel_down_bytes(tbf->qt_limit, &limu); - - nl_dump(p, " rate %.2f%s/s (%.0f%s) limit %.2f%s", - r, ru, rbit, rubit, lim, limu); -} - -static void tbf_dump_details(struct rtnl_tc *tc, void *data, - struct nl_dump_params *p) -{ - struct rtnl_tbf *tbf = data; - - if (!tbf) - return; - - if (1) { - char *bu, *cu; - double bs = nl_cancel_down_bytes(tbf->qt_rate_bucket, &bu); - double cl = nl_cancel_down_bytes(1 << tbf->qt_rate.rs_cell_log, - &cu); - - nl_dump(p, "rate-bucket-size %1.f%s " - "rate-cell-size %.1f%s\n", - bs, bu, cl, cu); - - } - - if (tbf->qt_mask & TBF_ATTR_PEAKRATE) { - char *pru, *prbu, *bsu, *clu; - double pr, prb, bs, cl; - - pr = nl_cancel_down_bytes(tbf->qt_peakrate.rs_rate, &pru); - prb = nl_cancel_down_bits(tbf->qt_peakrate.rs_rate * 8, &prbu); - bs = nl_cancel_down_bits(tbf->qt_peakrate_bucket, &bsu); - cl = nl_cancel_down_bits(1 << tbf->qt_peakrate.rs_cell_log, - &clu); - - nl_dump_line(p, " peak-rate %.2f%s/s (%.0f%s) " - "bucket-size %.1f%s cell-size %.1f%s" - "latency %.1f%s", - pr, pru, prb, prbu, bs, bsu, cl, clu); - } -} - -static int tbf_msg_fill(struct rtnl_tc *tc, void *data, 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; - - if (!(tbf->qt_mask & required) != required) - 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(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(tc, &tbf->qt_peakrate, ptab); - rtnl_rcopy_ratespec(&opts.peakrate, &tbf->qt_peakrate); - - } - - 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 0; - -nla_put_failure: - return -NLE_MSGSIZE; -} - -/** - * @name Attribute Access - * @{ - */ - -/** - * Set limit of TBF qdisc. - * @arg qdisc TBF qdisc to be modified. - * @arg limit New limit in bytes. - * @return 0 on success or a negative error code. - */ -void rtnl_qdisc_tbf_set_limit(struct rtnl_qdisc *qdisc, int limit) -{ - struct rtnl_tbf *tbf; - - if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - tbf->qt_limit = limit; - tbf->qt_mask |= TBF_ATTR_LIMIT; -} - -static inline double calc_limit(struct rtnl_ratespec *spec, int latency, - int bucket) -{ - double limit; - - limit = (double) spec->rs_rate * ((double) latency / 1000000.); - limit += bucket; - - return limit; -} - -/** - * Set limit of TBF qdisc by latency. - * @arg qdisc TBF qdisc to be modified. - * @arg latency Latency in micro seconds. - * - * Calculates and sets the limit based on the desired latency and the - * configured rate and peak rate. In order for this operation to succeed, - * the rate and if required the peak rate must have been set in advance. - * - * @f[ - * limit_n = \frac{{rate_n} \times {latency}}{10^6}+{bucketsize}_n - * @f] - * @f[ - * limit = min(limit_{rate},limit_{peak}) - * @f] - * - * @return 0 on success or a negative error code. - */ -int rtnl_qdisc_tbf_set_limit_by_latency(struct rtnl_qdisc *qdisc, int latency) -{ - struct rtnl_tbf *tbf; - double limit, limit2; - - if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - if (!(tbf->qt_mask & TBF_ATTR_RATE)) - return -NLE_MISSING_ATTR; - - limit = calc_limit(&tbf->qt_rate, latency, tbf->qt_rate_bucket); - - if (tbf->qt_mask & TBF_ATTR_PEAKRATE) { - limit2 = calc_limit(&tbf->qt_peakrate, latency, - tbf->qt_peakrate_bucket); - - if (limit2 < limit) - limit = limit2; - } - - rtnl_qdisc_tbf_set_limit(qdisc, (int) limit); - - return 0; -} - -/** - * Get limit of TBF qdisc. - * @arg qdisc TBF qdisc. - * @return Limit in bytes or a negative error code. - */ -int rtnl_qdisc_tbf_get_limit(struct rtnl_qdisc *qdisc) -{ - struct rtnl_tbf *tbf; - - if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - if (tbf->qt_mask & TBF_ATTR_LIMIT) - return tbf->qt_limit; - else - return -NLE_NOATTR; -} - -static inline int calc_cell_log(int cell, int bucket) -{ - cell = rtnl_tc_calc_cell_log(cell); - return cell; -} - -/** - * Set rate of TBF qdisc. - * @arg qdisc TBF qdisc to be modified. - * @arg rate New rate in bytes per second. - * @arg bucket Size of bucket in bytes. - * @arg cell Size of a rate cell or 0 to get default value. - * @return 0 on success or a negative error code. - */ -void rtnl_qdisc_tbf_set_rate(struct rtnl_qdisc *qdisc, int rate, int bucket, - int cell) -{ - struct rtnl_tbf *tbf; - int cell_log; - - if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - if (!cell) - cell_log = UINT8_MAX; - else - cell_log = rtnl_tc_calc_cell_log(cell); - - tbf->qt_rate.rs_rate = rate; - tbf->qt_rate_bucket = 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; -} - -/** - * Get rate of TBF qdisc. - * @arg qdisc TBF qdisc. - * @return Rate in bytes per seconds or a negative error code. - */ -int rtnl_qdisc_tbf_get_rate(struct rtnl_qdisc *qdisc) -{ - struct rtnl_tbf *tbf; - - 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; -} - -/** - * Get rate bucket size of TBF qdisc. - * @arg qdisc TBF qdisc. - * @return Size of rate bucket or a negative error code. - */ -int rtnl_qdisc_tbf_get_rate_bucket(struct rtnl_qdisc *qdisc) -{ - struct rtnl_tbf *tbf; - - if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - if (tbf->qt_mask & TBF_ATTR_RATE) - return tbf->qt_rate_bucket; - else - return -1; -} - -/** - * Get rate cell size of TBF qdisc. - * @arg qdisc TBF qdisc. - * @return Size of rate cell in bytes or a negative error code. - */ -int rtnl_qdisc_tbf_get_rate_cell(struct rtnl_qdisc *qdisc) -{ - struct rtnl_tbf *tbf; - - 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; -} - -/** - * Set peak rate of TBF qdisc. - * @arg qdisc TBF qdisc to be modified. - * @arg rate New peak rate in bytes per second. - * @arg bucket Size of peakrate bucket. - * @arg cell Size of a peakrate cell or 0 to get default value. - * @return 0 on success or a negative error code. - */ -int rtnl_qdisc_tbf_set_peakrate(struct rtnl_qdisc *qdisc, int rate, int bucket, - int cell) -{ - struct rtnl_tbf *tbf; - int cell_log; - - if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - cell_log = calc_cell_log(cell, bucket); - if (cell_log < 0) - return cell_log; - - tbf->qt_peakrate.rs_rate = rate; - tbf->qt_peakrate_bucket = bucket; - tbf->qt_peakrate.rs_cell_log = cell_log; - tbf->qt_peakrate_txtime = rtnl_tc_calc_txtime(bucket, rate); - - tbf->qt_mask |= TBF_ATTR_PEAKRATE; - - return 0; -} - -/** - * Get peak rate of TBF qdisc. - * @arg qdisc TBF qdisc. - * @return Peak rate in bytes per seconds or a negative error code. - */ -int rtnl_qdisc_tbf_get_peakrate(struct rtnl_qdisc *qdisc) -{ - struct rtnl_tbf *tbf; - - 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; -} - -/** - * Get peak rate bucket size of TBF qdisc. - * @arg qdisc TBF qdisc. - * @return Size of peak rate bucket or a negative error code. - */ -int rtnl_qdisc_tbf_get_peakrate_bucket(struct rtnl_qdisc *qdisc) -{ - struct rtnl_tbf *tbf; - - if (!(tbf = rtnl_tc_data(TC_CAST(qdisc)))) - BUG(); - - if (tbf->qt_mask & TBF_ATTR_PEAKRATE) - return tbf->qt_peakrate_bucket; - else - return -1; -} - -/** - * Get peak rate cell size of TBF qdisc. - * @arg qdisc TBF qdisc. - * @return Size of peak rate cell in bytes or a negative error code. - */ -int rtnl_qdisc_tbf_get_peakrate_cell(struct rtnl_qdisc *qdisc) -{ - struct rtnl_tbf *tbf; - - 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; -} - -/** @} */ - -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, - }, - .to_msg_fill = tbf_msg_fill, -}; - -static void __init tbf_init(void) -{ - rtnl_tc_register(&tbf_tc_ops); -} - -static void __exit tbf_exit(void) -{ - rtnl_tc_unregister(&tbf_tc_ops); -} - -/** @} */ -- cgit v1.2.1