133 lines
3.3 KiB
C
133 lines
3.3 KiB
C
/* SPDX-License-Identifier: LGPL-2.1+
|
|
* Copyright © 2019 VMware, Inc. */
|
|
|
|
#include "alloc-util.h"
|
|
#include "extract-word.h"
|
|
#include "fileio.h"
|
|
#include "parse-util.h"
|
|
#include "tc-util.h"
|
|
#include "time-util.h"
|
|
|
|
int tc_init(double *ret_ticks_in_usec, uint32_t *ret_hz) {
|
|
static double ticks_in_usec = -1;
|
|
static uint32_t hz;
|
|
|
|
if (ticks_in_usec < 0) {
|
|
uint32_t clock_resolution, ticks_to_usec, usec_to_ticks;
|
|
_cleanup_free_ char *line = NULL;
|
|
double clock_factor;
|
|
int r;
|
|
|
|
r = read_one_line_file("/proc/net/psched", &line);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
r = sscanf(line, "%08x%08x%08x%08x", &ticks_to_usec, &usec_to_ticks, &clock_resolution, &hz);
|
|
if (r < 4)
|
|
return -EIO;
|
|
|
|
clock_factor = (double) clock_resolution / USEC_PER_SEC;
|
|
ticks_in_usec = (double) ticks_to_usec / usec_to_ticks * clock_factor;
|
|
}
|
|
|
|
if (ret_ticks_in_usec)
|
|
*ret_ticks_in_usec = ticks_in_usec;
|
|
if (ret_hz)
|
|
*ret_hz = hz;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int tc_time_to_tick(usec_t t, uint32_t *ret) {
|
|
double ticks_in_usec;
|
|
usec_t a;
|
|
int r;
|
|
|
|
assert(ret);
|
|
|
|
r = tc_init(&ticks_in_usec, NULL);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
a = t * ticks_in_usec;
|
|
if (a > UINT32_MAX)
|
|
return -ERANGE;
|
|
|
|
*ret = a;
|
|
return 0;
|
|
}
|
|
|
|
int parse_tc_percent(const char *s, uint32_t *percent) {
|
|
int r;
|
|
|
|
assert(s);
|
|
assert(percent);
|
|
|
|
r = parse_permille(s);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
*percent = (double) r / 1000 * UINT32_MAX;
|
|
return 0;
|
|
}
|
|
|
|
int tc_transmit_time(uint64_t rate, uint32_t size, uint32_t *ret) {
|
|
return tc_time_to_tick(USEC_PER_SEC * ((double)size / (double)rate), ret);
|
|
}
|
|
|
|
int tc_fill_ratespec_and_table(struct tc_ratespec *rate, uint32_t *rtab, uint32_t mtu) {
|
|
uint32_t cell_log = 0;
|
|
int r;
|
|
|
|
if (mtu == 0)
|
|
mtu = 2047;
|
|
|
|
while ((mtu >> cell_log) > 255)
|
|
cell_log++;
|
|
|
|
for (size_t i = 0; i < 256; i++) {
|
|
uint32_t sz;
|
|
|
|
sz = (i + 1) << cell_log;
|
|
if (sz < rate->mpu)
|
|
sz = rate->mpu;
|
|
r = tc_transmit_time(rate->rate, sz, &rtab[i]);
|
|
if (r < 0)
|
|
return r;
|
|
}
|
|
|
|
rate->cell_align = -1;
|
|
rate->cell_log = cell_log;
|
|
rate->linklayer = TC_LINKLAYER_ETHERNET;
|
|
return 0;
|
|
}
|
|
|
|
int parse_handle(const char *t, uint32_t *ret) {
|
|
_cleanup_free_ char *word = NULL;
|
|
uint16_t major, minor;
|
|
int r;
|
|
|
|
assert(t);
|
|
assert(ret);
|
|
|
|
/* Extract the major number. */
|
|
r = extract_first_word(&t, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
|
|
if (r < 0)
|
|
return r;
|
|
if (r == 0)
|
|
return -EINVAL;
|
|
if (!t)
|
|
return -EINVAL;
|
|
|
|
r = safe_atou16_full(word, 16, &major);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
r = safe_atou16_full(t, 16, &minor);
|
|
if (r < 0)
|
|
return r;
|
|
|
|
*ret = ((uint32_t) major << 16) | minor;
|
|
return 0;
|
|
}
|