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