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