1 /* SPDX-License-Identifier: LGPL-2.1-or-later
2  * Copyright © 2019 VMware, Inc. */
3 
4 #include "alloc-util.h"
5 #include "extract-word.h"
6 #include "fileio.h"
7 #include "parse-util.h"
8 #include "percent-util.h"
9 #include "tc-util.h"
10 #include "time-util.h"
11 
tc_init(double * ret_ticks_in_usec,uint32_t * ret_hz)12 int tc_init(double *ret_ticks_in_usec, uint32_t *ret_hz) {
13         static double ticks_in_usec = -1;
14         static uint32_t hz;
15 
16         if (ticks_in_usec < 0) {
17                 uint32_t clock_resolution, ticks_to_usec, usec_to_ticks;
18                 _cleanup_free_ char *line = NULL;
19                 double clock_factor;
20                 int r;
21 
22                 r = read_one_line_file("/proc/net/psched", &line);
23                 if (r < 0)
24                         return r;
25 
26                 r = sscanf(line, "%08x%08x%08x%08x", &ticks_to_usec, &usec_to_ticks, &clock_resolution, &hz);
27                 if (r < 4)
28                         return -EIO;
29 
30                 clock_factor = (double) clock_resolution / USEC_PER_SEC;
31                 ticks_in_usec = (double) ticks_to_usec / usec_to_ticks * clock_factor;
32         }
33 
34         if (ret_ticks_in_usec)
35                 *ret_ticks_in_usec = ticks_in_usec;
36         if (ret_hz)
37                 *ret_hz = hz;
38 
39         return 0;
40 }
41 
tc_time_to_tick(usec_t t,uint32_t * ret)42 int tc_time_to_tick(usec_t t, uint32_t *ret) {
43         double ticks_in_usec;
44         usec_t a;
45         int r;
46 
47         assert(ret);
48 
49         r = tc_init(&ticks_in_usec, NULL);
50         if (r < 0)
51                 return r;
52 
53         a = t * ticks_in_usec;
54         if (a > UINT32_MAX)
55                 return -ERANGE;
56 
57         *ret = a;
58         return 0;
59 }
60 
parse_tc_percent(const char * s,uint32_t * ret_fraction)61 int parse_tc_percent(const char *s, uint32_t *ret_fraction) {
62         int r;
63 
64         assert(s);
65         assert(ret_fraction);
66 
67         r = parse_permyriad(s);
68         if (r < 0)
69                 return r;
70 
71         *ret_fraction = (double) r / 10000 * UINT32_MAX;
72         return 0;
73 }
74 
tc_transmit_time(uint64_t rate,uint32_t size,uint32_t * ret)75 int tc_transmit_time(uint64_t rate, uint32_t size, uint32_t *ret) {
76         return tc_time_to_tick(USEC_PER_SEC * ((double)size / (double)rate), ret);
77 }
78 
tc_fill_ratespec_and_table(struct tc_ratespec * rate,uint32_t * rtab,uint32_t mtu)79 int tc_fill_ratespec_and_table(struct tc_ratespec *rate, uint32_t *rtab, uint32_t mtu) {
80         uint32_t cell_log = 0;
81         int r;
82 
83         if (mtu == 0)
84                 mtu = 2047;
85 
86         while ((mtu >> cell_log) > 255)
87                 cell_log++;
88 
89         for (size_t i = 0; i < 256; i++) {
90                 uint32_t sz;
91 
92                 sz = (i + 1) << cell_log;
93                 if (sz < rate->mpu)
94                         sz = rate->mpu;
95                 r = tc_transmit_time(rate->rate, sz, &rtab[i]);
96                 if (r < 0)
97                         return r;
98         }
99 
100         rate->cell_align = -1;
101         rate->cell_log = cell_log;
102         rate->linklayer = TC_LINKLAYER_ETHERNET;
103         return 0;
104 }
105 
parse_handle(const char * t,uint32_t * ret)106 int parse_handle(const char *t, uint32_t *ret) {
107         _cleanup_free_ char *word = NULL;
108         uint16_t major, minor;
109         int r;
110 
111         assert(t);
112         assert(ret);
113 
114         /* Extract the major number. */
115         r = extract_first_word(&t, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
116         if (r < 0)
117                 return r;
118         if (r == 0)
119                 return -EINVAL;
120         if (!t)
121                 return -EINVAL;
122 
123         r = safe_atou16_full(word, 16, &major);
124         if (r < 0)
125                 return r;
126 
127         r = safe_atou16_full(t, 16, &minor);
128         if (r < 0)
129                 return r;
130 
131         *ret = ((uint32_t) major << 16) | minor;
132         return 0;
133 }
134