mirror of
https://git.proxmox.com/git/mirror_iproute2
synced 2025-10-12 21:54:23 +00:00
Merge branch 'netem-slot-param' into iproute2-next
Yousuk Seung says: ==================== This series adds support for the new "slot" netem parameter for slotting. Slotting is an approximation of shared media that gather up packets within a varying delay window before delivering them nearly at once. ==================== Signed-off-by: David Ahern <dsahern@gmail.com>
This commit is contained in:
commit
b555ff737a
@ -46,6 +46,11 @@ void incomplete_command(void) __attribute__((noreturn));
|
|||||||
#define NEXT_ARG_FWD() do { argv++; argc--; } while(0)
|
#define NEXT_ARG_FWD() do { argv++; argc--; } while(0)
|
||||||
#define PREV_ARG() do { argv--; argc++; } while(0)
|
#define PREV_ARG() do { argv--; argc++; } while(0)
|
||||||
|
|
||||||
|
#define TIME_UNITS_PER_SEC 1000000
|
||||||
|
#define NSEC_PER_USEC 1000
|
||||||
|
#define NSEC_PER_MSEC 1000000
|
||||||
|
#define NSEC_PER_SEC 1000000000LL
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
__u16 flags;
|
__u16 flags;
|
||||||
@ -310,4 +315,11 @@ size_t strlcat(char *dst, const char *src, size_t size);
|
|||||||
|
|
||||||
void drop_cap(void);
|
void drop_cap(void);
|
||||||
|
|
||||||
|
int get_time(unsigned int *time, const char *str);
|
||||||
|
int get_time64(__s64 *time, const char *str);
|
||||||
|
void print_time(char *buf, int len, __u32 time);
|
||||||
|
void print_time64(char *buf, int len, __s64 time);
|
||||||
|
char *sprint_time(__u32 time, char *buf);
|
||||||
|
char *sprint_time64(__s64 time, char *buf);
|
||||||
|
|
||||||
#endif /* __UTILS_H__ */
|
#endif /* __UTILS_H__ */
|
||||||
|
101
lib/utils.c
101
lib/utils.c
@ -1633,3 +1633,104 @@ void drop_cap(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int get_time(unsigned int *time, const char *str)
|
||||||
|
{
|
||||||
|
double t;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
t = strtod(str, &p);
|
||||||
|
if (p == str)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (*p) {
|
||||||
|
if (strcasecmp(p, "s") == 0 || strcasecmp(p, "sec") == 0 ||
|
||||||
|
strcasecmp(p, "secs") == 0)
|
||||||
|
t *= TIME_UNITS_PER_SEC;
|
||||||
|
else if (strcasecmp(p, "ms") == 0 || strcasecmp(p, "msec") == 0 ||
|
||||||
|
strcasecmp(p, "msecs") == 0)
|
||||||
|
t *= TIME_UNITS_PER_SEC/1000;
|
||||||
|
else if (strcasecmp(p, "us") == 0 || strcasecmp(p, "usec") == 0 ||
|
||||||
|
strcasecmp(p, "usecs") == 0)
|
||||||
|
t *= TIME_UNITS_PER_SEC/1000000;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*time = t;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void print_time(char *buf, int len, __u32 time)
|
||||||
|
{
|
||||||
|
double tmp = time;
|
||||||
|
|
||||||
|
if (tmp >= TIME_UNITS_PER_SEC)
|
||||||
|
snprintf(buf, len, "%.1fs", tmp/TIME_UNITS_PER_SEC);
|
||||||
|
else if (tmp >= TIME_UNITS_PER_SEC/1000)
|
||||||
|
snprintf(buf, len, "%.1fms", tmp/(TIME_UNITS_PER_SEC/1000));
|
||||||
|
else
|
||||||
|
snprintf(buf, len, "%uus", time);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *sprint_time(__u32 time, char *buf)
|
||||||
|
{
|
||||||
|
print_time(buf, SPRINT_BSIZE-1, time);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 64 bit times are represented internally in nanoseconds */
|
||||||
|
int get_time64(__s64 *time, const char *str)
|
||||||
|
{
|
||||||
|
double nsec;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
nsec = strtod(str, &p);
|
||||||
|
if (p == str)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (*p) {
|
||||||
|
if (strcasecmp(p, "s") == 0 ||
|
||||||
|
strcasecmp(p, "sec") == 0 ||
|
||||||
|
strcasecmp(p, "secs") == 0)
|
||||||
|
nsec *= NSEC_PER_SEC;
|
||||||
|
else if (strcasecmp(p, "ms") == 0 ||
|
||||||
|
strcasecmp(p, "msec") == 0 ||
|
||||||
|
strcasecmp(p, "msecs") == 0)
|
||||||
|
nsec *= NSEC_PER_MSEC;
|
||||||
|
else if (strcasecmp(p, "us") == 0 ||
|
||||||
|
strcasecmp(p, "usec") == 0 ||
|
||||||
|
strcasecmp(p, "usecs") == 0)
|
||||||
|
nsec *= NSEC_PER_USEC;
|
||||||
|
else if (strcasecmp(p, "ns") == 0 ||
|
||||||
|
strcasecmp(p, "nsec") == 0 ||
|
||||||
|
strcasecmp(p, "nsecs") == 0)
|
||||||
|
nsec *= 1;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*time = nsec;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_time64(char *buf, int len, __s64 time)
|
||||||
|
{
|
||||||
|
double nsec = time;
|
||||||
|
|
||||||
|
if (time >= NSEC_PER_SEC)
|
||||||
|
snprintf(buf, len, "%.3fs", nsec/NSEC_PER_SEC);
|
||||||
|
else if (time >= NSEC_PER_MSEC)
|
||||||
|
snprintf(buf, len, "%.3fms", nsec/NSEC_PER_MSEC);
|
||||||
|
else if (time >= NSEC_PER_USEC)
|
||||||
|
snprintf(buf, len, "%.3fus", nsec/NSEC_PER_USEC);
|
||||||
|
else
|
||||||
|
snprintf(buf, len, "%lldns", time);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *sprint_time64(__s64 time, char *buf)
|
||||||
|
{
|
||||||
|
print_time64(buf, SPRINT_BSIZE-1, time);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
@ -8,7 +8,8 @@ NetEm \- Network Emulator
|
|||||||
.I OPTIONS
|
.I OPTIONS
|
||||||
|
|
||||||
.IR OPTIONS " := [ " LIMIT " ] [ " DELAY " ] [ " LOSS \
|
.IR OPTIONS " := [ " LIMIT " ] [ " DELAY " ] [ " LOSS \
|
||||||
" ] [ " CORRUPT " ] [ " DUPLICATION " ] [ " REORDERING " ][ " RATE " ]"
|
" ] [ " CORRUPT " ] [ " DUPLICATION " ] [ " REORDERING " ] [ " RATE \
|
||||||
|
" ] [ " SLOT " ]"
|
||||||
|
|
||||||
.IR LIMIT " := "
|
.IR LIMIT " := "
|
||||||
.B limit
|
.B limit
|
||||||
@ -51,6 +52,18 @@ NetEm \- Network Emulator
|
|||||||
.B rate
|
.B rate
|
||||||
.IR RATE " [ " PACKETOVERHEAD " [ " CELLSIZE " [ " CELLOVERHEAD " ]]]]"
|
.IR RATE " [ " PACKETOVERHEAD " [ " CELLSIZE " [ " CELLOVERHEAD " ]]]]"
|
||||||
|
|
||||||
|
.IR SLOT " := "
|
||||||
|
.BR slot " { "
|
||||||
|
.IR MIN_DELAY " [ " MAX_DELAY " ] |"
|
||||||
|
.br
|
||||||
|
.RB " " distribution " { "uniform " | " normal " | " pareto " | " paretonormal " | "
|
||||||
|
.IR FILE " } " DELAY " " JITTER " } "
|
||||||
|
.br
|
||||||
|
.RB " [ " packets
|
||||||
|
.IR PACKETS " ] [ "
|
||||||
|
.BR bytes
|
||||||
|
.IR BYTES " ]"
|
||||||
|
|
||||||
|
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
NetEm is an enhancement of the Linux traffic control facilities
|
NetEm is an enhancement of the Linux traffic control facilities
|
||||||
@ -162,6 +175,31 @@ granularity avoid a perfect shaping at a specific level. This will show up in
|
|||||||
an artificial packet compression (bursts). Another influence factor are network
|
an artificial packet compression (bursts). Another influence factor are network
|
||||||
adapter buffers which can also add artificial delay.
|
adapter buffers which can also add artificial delay.
|
||||||
|
|
||||||
|
.SS slot
|
||||||
|
defer delivering accumulated packets to within a slot. Each available slot can be
|
||||||
|
configured with a minimum delay to acquire, and an optional maximum delay.
|
||||||
|
Alternatively it can be configured with the distribution similar to
|
||||||
|
.BR distribution
|
||||||
|
for
|
||||||
|
.BR delay
|
||||||
|
option. Slot delays can be specified in nanoseconds, microseconds, milliseconds or seconds
|
||||||
|
(e.g. 800us). Values for the optional parameters
|
||||||
|
.I BYTES
|
||||||
|
will limit the number of bytes delivered per slot, and/or
|
||||||
|
.I PACKETS
|
||||||
|
will limit the number of packets delivered per slot.
|
||||||
|
|
||||||
|
These slot options can provide a crude approximation of bursty MACs such as
|
||||||
|
DOCSIS, WiFi, and LTE.
|
||||||
|
|
||||||
|
Note that slotting is limited by several factors: the kernel clock granularity,
|
||||||
|
as with a rate, and attempts to deliver many packets within a slot will be
|
||||||
|
smeared by the timer resolution, and by the underlying native bandwidth also.
|
||||||
|
|
||||||
|
It is possible to combine slotting with a rate, in which case complex behaviors
|
||||||
|
where either the rate, or the slot limits on bytes or packets per slot, govern
|
||||||
|
the actual delivered rate.
|
||||||
|
|
||||||
.SH LIMITATIONS
|
.SH LIMITATIONS
|
||||||
The main known limitation of Netem are related to timer granularity, since
|
The main known limitation of Netem are related to timer granularity, since
|
||||||
Linux is not a real-time operating system.
|
Linux is not a real-time operating system.
|
||||||
|
115
tc/q_netem.c
115
tc/q_netem.c
@ -40,7 +40,12 @@ static void explain(void)
|
|||||||
" [ loss gemodel PERCENT [R [1-H [1-K]]]\n" \
|
" [ loss gemodel PERCENT [R [1-H [1-K]]]\n" \
|
||||||
" [ ecn ]\n" \
|
" [ ecn ]\n" \
|
||||||
" [ reorder PRECENT [CORRELATION] [ gap DISTANCE ]]\n" \
|
" [ reorder PRECENT [CORRELATION] [ gap DISTANCE ]]\n" \
|
||||||
" [ rate RATE [PACKETOVERHEAD] [CELLSIZE] [CELLOVERHEAD]]\n");
|
" [ rate RATE [PACKETOVERHEAD] [CELLSIZE] [CELLOVERHEAD]]\n" \
|
||||||
|
" [ slot MIN_DELAY [MAX_DELAY] [packets MAX_PACKETS]" \
|
||||||
|
" [bytes MAX_BYTES]]\n" \
|
||||||
|
" [ slot distribution" \
|
||||||
|
" {uniform|normal|pareto|paretonormal|custom} DELAY JITTER" \
|
||||||
|
" [packets MAX_PACKETS] [bytes MAX_BYTES]]\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void explain1(const char *arg)
|
static void explain1(const char *arg)
|
||||||
@ -156,6 +161,7 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
|
|||||||
struct nlmsghdr *n, const char *dev)
|
struct nlmsghdr *n, const char *dev)
|
||||||
{
|
{
|
||||||
int dist_size = 0;
|
int dist_size = 0;
|
||||||
|
int slot_dist_size = 0;
|
||||||
struct rtattr *tail;
|
struct rtattr *tail;
|
||||||
struct tc_netem_qopt opt = { .limit = 1000 };
|
struct tc_netem_qopt opt = { .limit = 1000 };
|
||||||
struct tc_netem_corr cor = {};
|
struct tc_netem_corr cor = {};
|
||||||
@ -164,7 +170,9 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
|
|||||||
struct tc_netem_gimodel gimodel;
|
struct tc_netem_gimodel gimodel;
|
||||||
struct tc_netem_gemodel gemodel;
|
struct tc_netem_gemodel gemodel;
|
||||||
struct tc_netem_rate rate = {};
|
struct tc_netem_rate rate = {};
|
||||||
|
struct tc_netem_slot slot = {};
|
||||||
__s16 *dist_data = NULL;
|
__s16 *dist_data = NULL;
|
||||||
|
__s16 *slot_dist_data = NULL;
|
||||||
__u16 loss_type = NETEM_LOSS_UNSPEC;
|
__u16 loss_type = NETEM_LOSS_UNSPEC;
|
||||||
int present[__TCA_NETEM_MAX] = {};
|
int present[__TCA_NETEM_MAX] = {};
|
||||||
__u64 rate64 = 0;
|
__u64 rate64 = 0;
|
||||||
@ -412,6 +420,79 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (matches(*argv, "slot") == 0) {
|
||||||
|
if (NEXT_IS_NUMBER()) {
|
||||||
|
NEXT_ARG();
|
||||||
|
present[TCA_NETEM_SLOT] = 1;
|
||||||
|
if (get_time64(&slot.min_delay, *argv)) {
|
||||||
|
explain1("slot min_delay");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (NEXT_IS_NUMBER()) {
|
||||||
|
NEXT_ARG();
|
||||||
|
if (get_time64(&slot.max_delay, *argv) ||
|
||||||
|
slot.max_delay < slot.min_delay) {
|
||||||
|
explain1("slot max_delay");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
slot.max_delay = slot.min_delay;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
NEXT_ARG();
|
||||||
|
if (strcmp(*argv, "distribution") == 0) {
|
||||||
|
present[TCA_NETEM_SLOT] = 1;
|
||||||
|
NEXT_ARG();
|
||||||
|
slot_dist_data = calloc(sizeof(slot_dist_data[0]), MAX_DIST);
|
||||||
|
if (!slot_dist_data)
|
||||||
|
return -1;
|
||||||
|
slot_dist_size = get_distribution(*argv, slot_dist_data, MAX_DIST);
|
||||||
|
if (slot_dist_size <= 0) {
|
||||||
|
free(slot_dist_data);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
NEXT_ARG();
|
||||||
|
if (get_time64(&slot.dist_delay, *argv)) {
|
||||||
|
explain1("slot delay");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
NEXT_ARG();
|
||||||
|
if (get_time64(&slot.dist_jitter, *argv)) {
|
||||||
|
explain1("slot jitter");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (slot.dist_jitter <= 0) {
|
||||||
|
fprintf(stderr, "Non-positive jitter\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Unknown slot parameter: %s\n",
|
||||||
|
*argv);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (NEXT_ARG_OK() &&
|
||||||
|
matches(*(argv+1), "packets") == 0) {
|
||||||
|
NEXT_ARG();
|
||||||
|
if (!NEXT_ARG_OK() ||
|
||||||
|
get_s32(&slot.max_packets, *(argv+1), 0)) {
|
||||||
|
explain1("slot packets");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
NEXT_ARG();
|
||||||
|
}
|
||||||
|
if (NEXT_ARG_OK() &&
|
||||||
|
matches(*(argv+1), "bytes") == 0) {
|
||||||
|
unsigned int max_bytes;
|
||||||
|
NEXT_ARG();
|
||||||
|
if (!NEXT_ARG_OK() ||
|
||||||
|
get_size(&max_bytes, *(argv+1))) {
|
||||||
|
explain1("slot bytes");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
slot.max_bytes = (int) max_bytes;
|
||||||
|
NEXT_ARG();
|
||||||
|
}
|
||||||
} else if (strcmp(*argv, "help") == 0) {
|
} else if (strcmp(*argv, "help") == 0) {
|
||||||
explain();
|
explain();
|
||||||
return -1;
|
return -1;
|
||||||
@ -472,6 +553,10 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
|
|||||||
addattr_l(n, 1024, TCA_NETEM_CORRUPT, &corrupt, sizeof(corrupt)) < 0)
|
addattr_l(n, 1024, TCA_NETEM_CORRUPT, &corrupt, sizeof(corrupt)) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (present[TCA_NETEM_SLOT] &&
|
||||||
|
addattr_l(n, 1024, TCA_NETEM_SLOT, &slot, sizeof(slot)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
if (loss_type != NETEM_LOSS_UNSPEC) {
|
if (loss_type != NETEM_LOSS_UNSPEC) {
|
||||||
struct rtattr *start;
|
struct rtattr *start;
|
||||||
|
|
||||||
@ -512,6 +597,14 @@ static int netem_parse_opt(struct qdisc_util *qu, int argc, char **argv,
|
|||||||
return -1;
|
return -1;
|
||||||
free(dist_data);
|
free(dist_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (slot_dist_data) {
|
||||||
|
if (addattr_l(n, MAX_DIST * sizeof(slot_dist_data[0]),
|
||||||
|
TCA_NETEM_SLOT_DIST,
|
||||||
|
slot_dist_data, slot_dist_size * sizeof(slot_dist_data[0])) < 0)
|
||||||
|
return -1;
|
||||||
|
free(slot_dist_data);
|
||||||
|
}
|
||||||
tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
|
tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -526,6 +619,7 @@ static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
|
|||||||
int *ecn = NULL;
|
int *ecn = NULL;
|
||||||
struct tc_netem_qopt qopt;
|
struct tc_netem_qopt qopt;
|
||||||
const struct tc_netem_rate *rate = NULL;
|
const struct tc_netem_rate *rate = NULL;
|
||||||
|
const struct tc_netem_slot *slot = NULL;
|
||||||
int len;
|
int len;
|
||||||
__u64 rate64 = 0;
|
__u64 rate64 = 0;
|
||||||
|
|
||||||
@ -586,6 +680,11 @@ static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
|
|||||||
return -1;
|
return -1;
|
||||||
rate64 = rta_getattr_u64(tb[TCA_NETEM_RATE64]);
|
rate64 = rta_getattr_u64(tb[TCA_NETEM_RATE64]);
|
||||||
}
|
}
|
||||||
|
if (tb[TCA_NETEM_SLOT]) {
|
||||||
|
if (RTA_PAYLOAD(tb[TCA_NETEM_SLOT]) < sizeof(*slot))
|
||||||
|
return -1;
|
||||||
|
slot = RTA_DATA(tb[TCA_NETEM_SLOT]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(f, "limit %d", qopt.limit);
|
fprintf(f, "limit %d", qopt.limit);
|
||||||
@ -659,6 +758,20 @@ static int netem_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt)
|
|||||||
fprintf(f, " celloverhead %d", rate->cell_overhead);
|
fprintf(f, " celloverhead %d", rate->cell_overhead);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (slot) {
|
||||||
|
if (slot->dist_jitter > 0) {
|
||||||
|
fprintf(f, " slot distribution %s", sprint_time64(slot->dist_delay, b1));
|
||||||
|
fprintf(f, " %s", sprint_time64(slot->dist_jitter, b1));
|
||||||
|
} else {
|
||||||
|
fprintf(f, " slot %s", sprint_time64(slot->min_delay, b1));
|
||||||
|
fprintf(f, " %s", sprint_time64(slot->max_delay, b1));
|
||||||
|
}
|
||||||
|
if (slot->max_packets)
|
||||||
|
fprintf(f, " packets %d", slot->max_packets);
|
||||||
|
if (slot->max_bytes)
|
||||||
|
fprintf(f, " bytes %d", slot->max_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
if (ecn)
|
if (ecn)
|
||||||
fprintf(f, " ecn ");
|
fprintf(f, " ecn ");
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
#include "tc_core.h"
|
#include "tc_core.h"
|
||||||
#include "tc_cbq.h"
|
#include "tc_cbq.h"
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
#include "tc_core.h"
|
#include "tc_core.h"
|
||||||
#include <linux/atm.h>
|
#include <linux/atm.h>
|
||||||
|
|
||||||
|
@ -5,8 +5,6 @@
|
|||||||
#include <asm/types.h>
|
#include <asm/types.h>
|
||||||
#include <linux/pkt_sched.h>
|
#include <linux/pkt_sched.h>
|
||||||
|
|
||||||
#define TIME_UNITS_PER_SEC 1000000
|
|
||||||
|
|
||||||
enum link_layer {
|
enum link_layer {
|
||||||
LINKLAYER_UNSPEC,
|
LINKLAYER_UNSPEC,
|
||||||
LINKLAYER_ETHERNET,
|
LINKLAYER_ETHERNET,
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "utils.h"
|
||||||
#include "tc_core.h"
|
#include "tc_core.h"
|
||||||
|
|
||||||
int tc_setup_estimator(unsigned int A, unsigned int time_const, struct tc_estimator *est)
|
int tc_setup_estimator(unsigned int A, unsigned int time_const, struct tc_estimator *est)
|
||||||
|
46
tc/tc_util.c
46
tc/tc_util.c
@ -334,52 +334,6 @@ char *sprint_rate(__u64 rate, char *buf)
|
|||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_time(unsigned int *time, const char *str)
|
|
||||||
{
|
|
||||||
double t;
|
|
||||||
char *p;
|
|
||||||
|
|
||||||
t = strtod(str, &p);
|
|
||||||
if (p == str)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (*p) {
|
|
||||||
if (strcasecmp(p, "s") == 0 || strcasecmp(p, "sec") == 0 ||
|
|
||||||
strcasecmp(p, "secs") == 0)
|
|
||||||
t *= TIME_UNITS_PER_SEC;
|
|
||||||
else if (strcasecmp(p, "ms") == 0 || strcasecmp(p, "msec") == 0 ||
|
|
||||||
strcasecmp(p, "msecs") == 0)
|
|
||||||
t *= TIME_UNITS_PER_SEC/1000;
|
|
||||||
else if (strcasecmp(p, "us") == 0 || strcasecmp(p, "usec") == 0 ||
|
|
||||||
strcasecmp(p, "usecs") == 0)
|
|
||||||
t *= TIME_UNITS_PER_SEC/1000000;
|
|
||||||
else
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
*time = t;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void print_time(char *buf, int len, __u32 time)
|
|
||||||
{
|
|
||||||
double tmp = time;
|
|
||||||
|
|
||||||
if (tmp >= TIME_UNITS_PER_SEC)
|
|
||||||
snprintf(buf, len, "%.1fs", tmp/TIME_UNITS_PER_SEC);
|
|
||||||
else if (tmp >= TIME_UNITS_PER_SEC/1000)
|
|
||||||
snprintf(buf, len, "%.1fms", tmp/(TIME_UNITS_PER_SEC/1000));
|
|
||||||
else
|
|
||||||
snprintf(buf, len, "%uus", time);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *sprint_time(__u32 time, char *buf)
|
|
||||||
{
|
|
||||||
print_time(buf, SPRINT_BSIZE-1, time);
|
|
||||||
return buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
char *sprint_ticks(__u32 ticks, char *buf)
|
char *sprint_ticks(__u32 ticks, char *buf)
|
||||||
{
|
{
|
||||||
return sprint_time(tc_core_tick2time(ticks), buf);
|
return sprint_time(tc_core_tick2time(ticks), buf);
|
||||||
|
@ -81,13 +81,11 @@ int get_rate64(__u64 *rate, const char *str);
|
|||||||
int get_percent_rate64(__u64 *rate, const char *str, const char *dev);
|
int get_percent_rate64(__u64 *rate, const char *str, const char *dev);
|
||||||
int get_size(unsigned int *size, const char *str);
|
int get_size(unsigned int *size, const char *str);
|
||||||
int get_size_and_cell(unsigned int *size, int *cell_log, char *str);
|
int get_size_and_cell(unsigned int *size, int *cell_log, char *str);
|
||||||
int get_time(unsigned int *time, const char *str);
|
|
||||||
int get_linklayer(unsigned int *val, const char *arg);
|
int get_linklayer(unsigned int *val, const char *arg);
|
||||||
|
|
||||||
void print_rate(char *buf, int len, __u64 rate);
|
void print_rate(char *buf, int len, __u64 rate);
|
||||||
void print_size(char *buf, int len, __u32 size);
|
void print_size(char *buf, int len, __u32 size);
|
||||||
void print_qdisc_handle(char *buf, int len, __u32 h);
|
void print_qdisc_handle(char *buf, int len, __u32 h);
|
||||||
void print_time(char *buf, int len, __u32 time);
|
|
||||||
void print_linklayer(char *buf, int len, unsigned int linklayer);
|
void print_linklayer(char *buf, int len, unsigned int linklayer);
|
||||||
void print_devname(enum output_type type, int ifindex);
|
void print_devname(enum output_type type, int ifindex);
|
||||||
|
|
||||||
@ -95,7 +93,6 @@ char *sprint_rate(__u64 rate, char *buf);
|
|||||||
char *sprint_size(__u32 size, char *buf);
|
char *sprint_size(__u32 size, char *buf);
|
||||||
char *sprint_qdisc_handle(__u32 h, char *buf);
|
char *sprint_qdisc_handle(__u32 h, char *buf);
|
||||||
char *sprint_tc_classid(__u32 h, char *buf);
|
char *sprint_tc_classid(__u32 h, char *buf);
|
||||||
char *sprint_time(__u32 time, char *buf);
|
|
||||||
char *sprint_ticks(__u32 ticks, char *buf);
|
char *sprint_ticks(__u32 ticks, char *buf);
|
||||||
char *sprint_linklayer(unsigned int linklayer, char *buf);
|
char *sprint_linklayer(unsigned int linklayer, char *buf);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user