1 #define _GNU_SOURCE
2
3 #include "libxlu_internal.h"
4
5 static const char *vif_bytes_per_sec_re = "^[0-9]+[GMK]?[Bb]/s$";
6 static const char *vif_internal_usec_re = "^[0-9]+[mu]?s?$";
7
xlu__vif_err(XLU_Config * cfg,const char * msg,const char * rate)8 static void xlu__vif_err(XLU_Config *cfg, const char *msg, const char *rate) {
9 fprintf(cfg->report,
10 "%s: config parsing error in vif: %s in `%s'\n",
11 cfg->config_source, msg, rate);
12 }
13
vif_parse_rate_bytes_per_sec(XLU_Config * cfg,const char * bytes,uint64_t * bytes_per_sec)14 static int vif_parse_rate_bytes_per_sec(XLU_Config *cfg, const char *bytes,
15 uint64_t *bytes_per_sec)
16 {
17 regex_t rec;
18 uint64_t tmp = 0;
19 const char *p;
20 int rc = 0;
21
22 regcomp(&rec, vif_bytes_per_sec_re, REG_EXTENDED|REG_NOSUB);
23 if (regexec(&rec, bytes, 0, NULL, 0)) {
24 xlu__vif_err(cfg, "invalid rate", bytes);
25 rc = EINVAL;
26 goto out;
27 }
28
29 p = bytes;
30 tmp = strtoull(p, (char**)&p, 0);
31 if (tmp == 0 || tmp > UINT32_MAX || errno == ERANGE) {
32 xlu__vif_err(cfg, "rate overflow", bytes);
33 rc = EOVERFLOW;
34 goto out;
35 }
36
37 if (*p == 'G')
38 tmp *= 1000 * 1000 * 1000;
39 else if (*p == 'M')
40 tmp *= 1000 * 1000;
41 else if (*p == 'K')
42 tmp *= 1000;
43 if (*p == 'b' || *(p+1) == 'b')
44 tmp /= 8;
45
46 *bytes_per_sec = tmp;
47
48 out:
49 regfree(&rec);
50 return rc;
51 }
52
vif_parse_rate_interval_usecs(XLU_Config * cfg,const char * interval,uint32_t * interval_usecs)53 static int vif_parse_rate_interval_usecs(XLU_Config *cfg, const char *interval,
54 uint32_t *interval_usecs)
55 {
56 regex_t rec;
57 uint64_t tmp = 0;
58 const char *p;
59 int rc = 0;
60
61 regcomp(&rec, vif_internal_usec_re, REG_EXTENDED|REG_NOSUB);
62 if (regexec(&rec, interval, 0, NULL, 0)) {
63 xlu__vif_err(cfg, "invalid replenishment interval", interval);
64 rc = EINVAL;
65 goto out;
66 }
67
68 p = interval;
69 tmp = strtoull(p, (char**)&p, 0);
70 if (tmp == 0 || tmp > UINT32_MAX || errno == ERANGE) {
71 xlu__vif_err(cfg, "replenishment interval overflow", interval);
72 rc = EOVERFLOW;
73 goto out;
74 }
75
76 if (*p == 's' || *p == '\0')
77 tmp *= 1000 * 1000;
78 else if (*p == 'm')
79 tmp *= 1000;
80
81 if (tmp > UINT32_MAX) {
82 xlu__vif_err(cfg, "replenishment interval overflow", interval);
83 rc = EOVERFLOW;
84 goto out;
85 }
86
87 *interval_usecs = (uint32_t) tmp;
88
89 out:
90 regfree(&rec);
91 return rc;
92 }
93
xlu_vif_parse_rate(XLU_Config * cfg,const char * rate,libxl_device_nic * nic)94 int xlu_vif_parse_rate(XLU_Config *cfg, const char *rate, libxl_device_nic *nic)
95 {
96 uint64_t bytes_per_sec = 0;
97 uint64_t bytes_per_interval = 0;
98 uint32_t interval_usecs = 50000UL; /* Default to 50ms */
99 char *p, *tmprate;
100 int rc = 0;
101
102 tmprate = strdup(rate);
103 if (tmprate == NULL) {
104 rc = ENOMEM;
105 goto out;
106 }
107
108 p = strchr(tmprate, '@');
109 if (p != NULL)
110 *p++ = 0;
111
112 if (!strcmp(tmprate,"")) {
113 xlu__vif_err(cfg, "no rate specified", rate);
114 rc = EINVAL;
115 goto out;
116 }
117
118 rc = vif_parse_rate_bytes_per_sec(cfg, tmprate, &bytes_per_sec);
119 if (rc) goto out;
120
121 if (p != NULL) {
122 rc = vif_parse_rate_interval_usecs(cfg, p, &interval_usecs);
123 if (rc) goto out;
124 }
125
126 if (interval_usecs != 0 && (bytes_per_sec > (UINT64_MAX / interval_usecs))) {
127 xlu__vif_err(cfg, "rate overflow", rate);
128 rc = EOVERFLOW;
129 goto out;
130 }
131
132 bytes_per_interval =
133 (((uint64_t) bytes_per_sec * (uint64_t) interval_usecs) / 1000000UL);
134
135 nic->rate_interval_usecs = interval_usecs;
136 nic->rate_bytes_per_interval = bytes_per_interval;
137
138 out:
139 free(tmprate);
140 return rc;
141 }
142
143 /*
144 * Local variables:
145 * mode: C
146 * c-basic-offset: 4
147 * indent-tabs-mode: nil
148 * End:
149 */
150