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