common: Adding common library for sample vnf
[samplevnf.git] / common / vnf_common / config_parse_tm.c
1 /*
2 // Copyright (c) 2017 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16 #include <stdint.h>
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <ctype.h>
20 #include <getopt.h>
21 #include <errno.h>
22 #include <stdarg.h>
23 #include <string.h>
24 #include <libgen.h>
25 #include <unistd.h>
26
27 #include <rte_errno.h>
28 #include <rte_cfgfile.h>
29 #include <rte_string_fns.h>
30
31 #include "app.h"
32
33 static int
34 tm_cfgfile_load_sched_port(
35         struct rte_cfgfile *file,
36         struct rte_sched_port_params *port_params)
37 {
38         const char *entry;
39         int j;
40
41         entry = rte_cfgfile_get_entry(file, "port", "frame overhead");
42         if (entry)
43                 port_params->frame_overhead = (uint32_t)atoi(entry);
44
45         entry = rte_cfgfile_get_entry(file, "port", "mtu");
46         if (entry)
47                 port_params->mtu = (uint32_t)atoi(entry);
48
49         entry = rte_cfgfile_get_entry(file,
50                 "port",
51                 "number of subports per port");
52         if (entry)
53                 port_params->n_subports_per_port = (uint32_t) atoi(entry);
54
55         entry = rte_cfgfile_get_entry(file,
56                 "port",
57                 "number of pipes per subport");
58         if (entry)
59                 port_params->n_pipes_per_subport = (uint32_t) atoi(entry);
60
61         entry = rte_cfgfile_get_entry(file, "port", "queue sizes");
62         if (entry) {
63                 char *next;
64
65                 for (j = 0; j < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; j++) {
66                         port_params->qsize[j] = (uint16_t)
67                                 strtol(entry, &next, 10);
68                         if (next == NULL)
69                                 break;
70                         entry = next;
71                 }
72         }
73
74 #ifdef RTE_SCHED_RED
75         for (j = 0; j < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; j++) {
76                 char str[32];
77
78                 /* Parse WRED min thresholds */
79                 snprintf(str, sizeof(str), "tc %" PRId32 " wred min", j);
80                 entry = rte_cfgfile_get_entry(file, "red", str);
81                 if (entry) {
82                         char *next;
83                         int k;
84
85                         /* for each packet colour (green, yellow, red) */
86                         for (k = 0; k < e_RTE_METER_COLORS; k++) {
87                                 port_params->red_params[j][k].min_th
88                                         = (uint16_t)strtol(entry, &next, 10);
89                                 if (next == NULL)
90                                         break;
91                                 entry = next;
92                         }
93                 }
94
95                 /* Parse WRED max thresholds */
96                 snprintf(str, sizeof(str), "tc %" PRId32 " wred max", j);
97                 entry = rte_cfgfile_get_entry(file, "red", str);
98                 if (entry) {
99                         char *next;
100                         int k;
101
102                         /* for each packet colour (green, yellow, red) */
103                         for (k = 0; k < e_RTE_METER_COLORS; k++) {
104                                 port_params->red_params[j][k].max_th
105                                         = (uint16_t)strtol(entry, &next, 10);
106                                 if (next == NULL)
107                                         break;
108                                 entry = next;
109                         }
110                 }
111
112                 /* Parse WRED inverse mark probabilities */
113                 snprintf(str, sizeof(str), "tc %" PRId32 " wred inv prob", j);
114                 entry = rte_cfgfile_get_entry(file, "red", str);
115                 if (entry) {
116                         char *next;
117                         int k;
118
119                         /* for each packet colour (green, yellow, red) */
120                         for (k = 0; k < e_RTE_METER_COLORS; k++) {
121                                 port_params->red_params[j][k].maxp_inv
122                                         = (uint8_t)strtol(entry, &next, 10);
123
124                                 if (next == NULL)
125                                         break;
126                                 entry = next;
127                         }
128                 }
129
130                 /* Parse WRED EWMA filter weights */
131                 snprintf(str, sizeof(str), "tc %" PRId32 " wred weight", j);
132                 entry = rte_cfgfile_get_entry(file, "red", str);
133                 if (entry) {
134                         char *next;
135                         int k;
136
137                         /* for each packet colour (green, yellow, red) */
138                         for (k = 0; k < e_RTE_METER_COLORS; k++) {
139                                 port_params->red_params[j][k].wq_log2
140                                         = (uint8_t)strtol(entry, &next, 10);
141                                 if (next == NULL)
142                                         break;
143                                 entry = next;
144                         }
145                 }
146         }
147 #endif /* RTE_SCHED_RED */
148
149         return 0;
150 }
151
152 static int
153 tm_cfgfile_load_sched_pipe(
154         struct rte_cfgfile *file,
155         struct rte_sched_port_params *port_params,
156         struct rte_sched_pipe_params *pipe_params)
157 {
158         int i, j;
159         char *next;
160         const char *entry;
161         int profiles;
162
163         profiles = rte_cfgfile_num_sections(file,
164                 "pipe profile", sizeof("pipe profile") - 1);
165         port_params->n_pipe_profiles = profiles;
166
167         for (j = 0; j < profiles; j++) {
168                 char pipe_name[32];
169
170                 snprintf(pipe_name, sizeof(pipe_name),
171                         "pipe profile %" PRId32, j);
172
173                 entry = rte_cfgfile_get_entry(file, pipe_name, "tb rate");
174                 if (entry)
175                         pipe_params[j].tb_rate = (uint32_t) atoi(entry);
176
177                 entry = rte_cfgfile_get_entry(file, pipe_name, "tb size");
178                 if (entry)
179                         pipe_params[j].tb_size = (uint32_t) atoi(entry);
180
181                 entry = rte_cfgfile_get_entry(file, pipe_name, "tc period");
182                 if (entry)
183                         pipe_params[j].tc_period = (uint32_t) atoi(entry);
184
185                 entry = rte_cfgfile_get_entry(file, pipe_name, "tc 0 rate");
186                 if (entry)
187                         pipe_params[j].tc_rate[0] = (uint32_t) atoi(entry);
188
189                 entry = rte_cfgfile_get_entry(file, pipe_name, "tc 1 rate");
190                 if (entry)
191                         pipe_params[j].tc_rate[1] = (uint32_t) atoi(entry);
192
193                 entry = rte_cfgfile_get_entry(file, pipe_name, "tc 2 rate");
194                 if (entry)
195                         pipe_params[j].tc_rate[2] = (uint32_t) atoi(entry);
196
197                 entry = rte_cfgfile_get_entry(file, pipe_name, "tc 3 rate");
198                 if (entry)
199                         pipe_params[j].tc_rate[3] = (uint32_t) atoi(entry);
200
201 #ifdef RTE_SCHED_SUBPORT_TC_OV
202                 entry = rte_cfgfile_get_entry(file, pipe_name,
203                         "tc 3 oversubscription weight");
204                 if (entry)
205                         pipe_params[j].tc_ov_weight = (uint8_t)atoi(entry);
206 #endif
207
208                 entry = rte_cfgfile_get_entry(file,
209                         pipe_name,
210                         "tc 0 wrr weights");
211                 if (entry)
212                         for (i = 0; i < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; i++) {
213                                 pipe_params[j].wrr_weights[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE*0 + i] =
214                                         (uint8_t) strtol(entry, &next, 10);
215                                 if (next == NULL)
216                                         break;
217                                 entry = next;
218                         }
219
220                 entry = rte_cfgfile_get_entry(file, pipe_name, "tc 1 wrr weights");
221                 if (entry)
222                         for (i = 0; i < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; i++) {
223                                 pipe_params[j].wrr_weights[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE*1 + i] =
224                                         (uint8_t) strtol(entry, &next, 10);
225                                 if (next == NULL)
226                                         break;
227                                 entry = next;
228                         }
229
230                 entry = rte_cfgfile_get_entry(file, pipe_name, "tc 2 wrr weights");
231                 if (entry)
232                         for (i = 0; i < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; i++) {
233                                 pipe_params[j].wrr_weights[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE*2 + i] =
234                                         (uint8_t) strtol(entry, &next, 10);
235                                 if (next == NULL)
236                                         break;
237                                 entry = next;
238                         }
239
240                 entry = rte_cfgfile_get_entry(file, pipe_name, "tc 3 wrr weights");
241                 if (entry)
242                         for (i = 0; i < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; i++) {
243                                 pipe_params[j].wrr_weights[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE*3 + i] =
244                                         (uint8_t) strtol(entry, &next, 10);
245                                 if (next == NULL)
246                                         break;
247                                 entry = next;
248                         }
249         }
250         return 0;
251 }
252
253 static int
254 tm_cfgfile_load_sched_subport(
255         struct rte_cfgfile *file,
256         struct rte_sched_subport_params *subport_params,
257         int *pipe_to_profile)
258 {
259         const char *entry;
260         int i, j, k;
261
262         for (i = 0; i < APP_MAX_SCHED_SUBPORTS; i++) {
263                 char sec_name[CFG_NAME_LEN];
264
265                 snprintf(sec_name, sizeof(sec_name),
266                         "subport %" PRId32, i);
267
268                 if (rte_cfgfile_has_section(file, sec_name)) {
269                         entry = rte_cfgfile_get_entry(file,
270                                 sec_name,
271                                 "tb rate");
272                         if (entry)
273                                 subport_params[i].tb_rate =
274                                         (uint32_t) atoi(entry);
275
276                         entry = rte_cfgfile_get_entry(file,
277                                 sec_name,
278                                 "tb size");
279                         if (entry)
280                                 subport_params[i].tb_size =
281                                         (uint32_t) atoi(entry);
282
283                         entry = rte_cfgfile_get_entry(file,
284                                 sec_name,
285                                 "tc period");
286                         if (entry)
287                                 subport_params[i].tc_period =
288                                         (uint32_t) atoi(entry);
289
290                         entry = rte_cfgfile_get_entry(file,
291                                 sec_name,
292                                 "tc 0 rate");
293                         if (entry)
294                                 subport_params[i].tc_rate[0] =
295                                         (uint32_t) atoi(entry);
296
297                         entry = rte_cfgfile_get_entry(file,
298                                 sec_name,
299                                 "tc 1 rate");
300                         if (entry)
301                                 subport_params[i].tc_rate[1] =
302                                         (uint32_t) atoi(entry);
303
304                         entry = rte_cfgfile_get_entry(file,
305                                 sec_name,
306                                 "tc 2 rate");
307                         if (entry)
308                                 subport_params[i].tc_rate[2] =
309                                         (uint32_t) atoi(entry);
310
311                         entry = rte_cfgfile_get_entry(file,
312                                 sec_name,
313                                 "tc 3 rate");
314                         if (entry)
315                                 subport_params[i].tc_rate[3] =
316                                         (uint32_t) atoi(entry);
317
318                         int n_entries = rte_cfgfile_section_num_entries(file,
319                                 sec_name);
320                         struct rte_cfgfile_entry entries[n_entries];
321
322                         rte_cfgfile_section_entries(file,
323                                 sec_name,
324                                 entries,
325                                 n_entries);
326
327                         for (j = 0; j < n_entries; j++)
328                                 if (strncmp("pipe",
329                                         entries[j].name,
330                                         sizeof("pipe") - 1) == 0) {
331                                         int profile;
332                                         char *tokens[2] = {NULL, NULL};
333                                         int n_tokens;
334                                         int begin, end;
335                                         char name[CFG_NAME_LEN + 1];
336
337                                         profile = atoi(entries[j].value);
338                                         strncpy(name,
339                                                 entries[j].name,
340                                                 sizeof(name));
341                                         n_tokens = rte_strsplit(
342                                                 &name[sizeof("pipe")],
343                                                 strnlen(name, CFG_NAME_LEN),
344                                                         tokens, 2, '-');
345
346                                         begin =  atoi(tokens[0]);
347                                         if (n_tokens == 2)
348                                                 end = atoi(tokens[1]);
349                                         else
350                                                 end = begin;
351
352                                         if ((end >= APP_MAX_SCHED_PIPES) ||
353                                                 (begin > end))
354                                                 return -1;
355
356                                         for (k = begin; k <= end; k++) {
357                                                 char profile_name[CFG_NAME_LEN];
358
359                                                 snprintf(profile_name,
360                                                         sizeof(profile_name),
361                                                         "pipe profile %" PRId32,
362                                                         profile);
363                                                 if (rte_cfgfile_has_section(file, profile_name))
364                                                         pipe_to_profile[i * APP_MAX_SCHED_PIPES + k] = profile;
365                                                 else
366                                                         rte_exit(EXIT_FAILURE,
367                                                                 "Wrong pipe profile %s\n",
368                                                                 entries[j].value);
369                                         }
370                                 }
371                 }
372         }
373
374         return 0;
375 }
376
377 static int
378 tm_cfgfile_load(struct app_pktq_tm_params *tm)
379 {
380         struct rte_cfgfile *file;
381         uint32_t i;
382
383         memset(tm->sched_subport_params, 0, sizeof(tm->sched_subport_params));
384         memset(tm->sched_pipe_profiles, 0, sizeof(tm->sched_pipe_profiles));
385         memset(&tm->sched_port_params, 0, sizeof(tm->sched_port_params));
386         for (i = 0; i < APP_MAX_SCHED_SUBPORTS * APP_MAX_SCHED_PIPES; i++)
387                 tm->sched_pipe_to_profile[i] = -1;
388
389         tm->sched_port_params.pipe_profiles = &tm->sched_pipe_profiles[0];
390
391         if (tm->file_name[0] == '\0')
392                 return -1;
393
394         file = rte_cfgfile_load(tm->file_name, 0);
395         if (file == NULL)
396                 return -1;
397
398         tm_cfgfile_load_sched_port(file,
399                 &tm->sched_port_params);
400         tm_cfgfile_load_sched_subport(file,
401                 tm->sched_subport_params,
402                 tm->sched_pipe_to_profile);
403         tm_cfgfile_load_sched_pipe(file,
404                 &tm->sched_port_params,
405                 tm->sched_pipe_profiles);
406
407         rte_cfgfile_close(file);
408         return 0;
409 }
410
411 int
412 app_config_parse_tm(struct app_params *app)
413 {
414         uint32_t i;
415
416         for (i = 0; i < RTE_DIM(app->tm_params); i++) {
417                 struct app_pktq_tm_params *p = &app->tm_params[i];
418                 int status;
419
420                 if (!APP_PARAM_VALID(p))
421                         break;
422
423                 status = tm_cfgfile_load(p);
424                 APP_CHECK(status == 0,
425                         "Parse error for %s configuration file \"%s\"\n",
426                         p->name,
427                         p->file_name);
428         }
429
430         return 0;
431 }