1 /*
2 * Copyright (C) Mellanox Technologies Ltd. 2001-2019. ALL RIGHTS RESERVED.
3 *
4 * See file LICENSE for terms.
5 */
6 
7 #ifndef UCS_CONFIG_PARSER_H
8 #define UCS_CONFIG_PARSER_H
9 
10 #include "types.h"
11 
12 #include <ucs/datastruct/list.h>
13 #include <ucs/type/status.h>
14 #include <ucs/sys/stubs.h>
15 
16 #include <stdio.h>
17 
18 
19 #define UCS_DEFAULT_ENV_PREFIX "UCX_"
20 #define UCS_CONFIG_ARRAY_MAX   128
21 
22 BEGIN_C_DECLS
23 
24 /** @file parser.h */
25 
26 /*
27  * Configuration varaibles syntax:
28  *
29  * name: <env_prefix><table_prefix><field_name>
30  *
31  * - env_prefix:     supplied by user to ucs_config_read_XXX() API
32  * - table_prefix:   defined in sub-tables. e.g IB_, UD_, ...
33  * - field_name:     field_name as defined in the table. e.g ZCOPY_THRESH
34  *
35  * Examples of full variable names:
36  *   - UCS_CIB_RNDV_THRESH
37  *   - UCS_IB_TX_MODERATION
38  */
39 
40 typedef struct ucs_config_parser {
41     int                      (*read) (const char *buf, void *dest, const void *arg);
42     int                      (*write)(char *buf, size_t max,
43                                       const void *src, const void *arg);
44     ucs_status_t             (*clone)(const void *src, void *dest, const void *arg);
45     void                     (*release)(void *ptr, const void *arg);
46     void                     (*help)(char *buf, size_t max, const void *arg);
47     const void               *arg;
48 } ucs_config_parser_t;
49 
50 
51 typedef struct ucs_config_array {
52     size_t                   elem_size;
53     ucs_config_parser_t      parser;
54 } ucs_config_array_t;
55 
56 
57 typedef struct ucs_config_field {
58     const char               *name;
59     const char               *dfl_value;
60     const char               *doc;
61     size_t                   offset;
62     ucs_config_parser_t      parser;
63 } ucs_config_field_t;
64 
65 
66 typedef struct ucs_ib_port_spec {
67     char                     *device_name;
68     unsigned                 port_num;
69 } ucs_ib_port_spec_t;
70 
71 
72 typedef struct ucs_range_spec {
73     unsigned                 first;  /* the first value in the range */
74     unsigned                 last;   /* the last value in the range */
75 } ucs_range_spec_t;
76 
77 
78 typedef struct ucs_config_global_list_entry {
79     const char               *name;    /* configuration table name */
80     const char               *prefix;  /* configuration prefix */
81     ucs_config_field_t       *table;   /* array of configuration fields */
82     size_t                   size;     /* size of config structure */
83     ucs_list_link_t          list;     /* entry in global list */
84 } ucs_config_global_list_entry_t;
85 
86 
87 typedef struct ucs_config_bw_spec {
88     char                     *name;
89     double                   bw;
90 } ucs_config_bw_spec_t;
91 
92 
93 #define UCS_CONFIG_EMPTY_GLOBAL_LIST_ENTRY \
94     { \
95         .name        = "", \
96         .prefix      = "", \
97         .table       = NULL, \
98         .size        = 0, \
99     }
100 
101 
102 #define UCS_CONFIG_REGISTER_TABLE_ENTRY(_entry) \
103     UCS_STATIC_INIT { \
104         ucs_list_add_tail(&ucs_config_global_list, &(_entry)->list); \
105     } \
106     \
107     UCS_STATIC_CLEANUP { \
108         ucs_list_del(&(_entry)->list); \
109     }
110 
111 #define UCS_CONFIG_REGISTER_TABLE(_table, _name, _prefix, _type) \
112     static ucs_config_global_list_entry_t _table##_config_entry = { \
113         .table  = _table, \
114         .name   = _name, \
115         .prefix = _prefix, \
116         .size   = sizeof(_type) \
117     }; \
118     UCS_CONFIG_REGISTER_TABLE_ENTRY(&_table##_config_entry);
119 
120 extern ucs_list_link_t ucs_config_global_list;
121 
122 /*
123  * Parsing and printing different data types
124  */
125 
126 int ucs_config_sscanf_string(const char *buf, void *dest, const void *arg);
127 int ucs_config_sprintf_string(char *buf, size_t max, const void *src, const void *arg);
128 ucs_status_t ucs_config_clone_string(const void *src, void *dest, const void *arg);
129 void ucs_config_release_string(void *ptr, const void *arg);
130 
131 int ucs_config_sscanf_int(const char *buf, void *dest, const void *arg);
132 int ucs_config_sprintf_int(char *buf, size_t max, const void *src, const void *arg);
133 ucs_status_t ucs_config_clone_int(const void *src, void *dest, const void *arg);
134 
135 int ucs_config_sscanf_uint(const char *buf, void *dest, const void *arg);
136 int ucs_config_sprintf_uint(char *buf, size_t max, const void *src, const void *arg);
137 ucs_status_t ucs_config_clone_uint(const void *src, void *dest, const void *arg);
138 
139 int ucs_config_sscanf_ulong(const char *buf, void *dest, const void *arg);
140 int ucs_config_sprintf_ulong(char *buf, size_t max, const void *src, const void *arg);
141 ucs_status_t ucs_config_clone_ulong(const void *src, void *dest, const void *arg);
142 
143 int ucs_config_sscanf_double(const char *buf, void *dest, const void *arg);
144 int ucs_config_sprintf_double(char *buf, size_t max, const void *src, const void *arg);
145 ucs_status_t ucs_config_clone_double(const void *src, void *dest, const void *arg);
146 
147 int ucs_config_sscanf_hex(const char *buf, void *dest, const void *arg);
148 int ucs_config_sprintf_hex(char *buf, size_t max, const void *src, const void *arg);
149 
150 int ucs_config_sscanf_bool(const char *buf, void *dest, const void *arg);
151 int ucs_config_sprintf_bool(char *buf, size_t max, const void *src, const void *arg);
152 
153 int ucs_config_sscanf_ternary(const char *buf, void *dest, const void *arg);
154 int ucs_config_sprintf_ternary(char *buf, size_t max, const void *src, const void *arg);
155 
156 int ucs_config_sscanf_on_off(const char *buf, void *dest, const void *arg);
157 
158 int ucs_config_sscanf_on_off_auto(const char *buf, void *dest, const void *arg);
159 int ucs_config_sprintf_on_off_auto(char *buf, size_t max, const void *src, const void *arg);
160 
161 int ucs_config_sscanf_enum(const char *buf, void *dest, const void *arg);
162 int ucs_config_sprintf_enum(char *buf, size_t max, const void *src, const void *arg);
163 void ucs_config_help_enum(char *buf, size_t max, const void *arg);
164 
165 int ucs_config_sscanf_bitmap(const char *buf, void *dest, const void *arg);
166 int ucs_config_sprintf_bitmap(char *buf, size_t max, const void *src, const void *arg);
167 void ucs_config_help_bitmap(char *buf, size_t max, const void *arg);
168 
169 int ucs_config_sscanf_bitmask(const char *buf, void *dest, const void *arg);
170 int ucs_config_sprintf_bitmask(char *buf, size_t max, const void *src, const void *arg);
171 
172 int ucs_config_sscanf_time(const char *buf, void *dest, const void *arg);
173 int ucs_config_sprintf_time(char *buf, size_t max, const void *src, const void *arg);
174 
175 int ucs_config_sscanf_bw(const char *buf, void *dest, const void *arg);
176 int ucs_config_sprintf_bw(char *buf, size_t max, const void *src, const void *arg);
177 
178 int ucs_config_sscanf_bw_spec(const char *buf, void *dest, const void *arg);
179 int ucs_config_sprintf_bw_spec(char *buf, size_t max, const void *src, const void *arg);
180 ucs_status_t ucs_config_clone_bw_spec(const void *src, void *dest, const void *arg);
181 void ucs_config_release_bw_spec(void *ptr, const void *arg);
182 
183 int ucs_config_sscanf_signo(const char *buf, void *dest, const void *arg);
184 int ucs_config_sprintf_signo(char *buf, size_t max, const void *src, const void *arg);
185 
186 int ucs_config_sscanf_memunits(const char *buf, void *dest, const void *arg);
187 int ucs_config_sprintf_memunits(char *buf, size_t max, const void *src, const void *arg);
188 
189 int ucs_config_sscanf_ulunits(const char *buf, void *dest, const void *arg);
190 int ucs_config_sprintf_ulunits(char *buf, size_t max, const void *src, const void *arg);
191 
192 int ucs_config_sscanf_range_spec(const char *buf, void *dest, const void *arg);
193 int ucs_config_sprintf_range_spec(char *buf, size_t max, const void *src, const void *arg);
194 ucs_status_t ucs_config_clone_range_spec(const void *src, void *dest, const void *arg);
195 
196 int ucs_config_sscanf_array(const char *buf, void *dest, const void *arg);
197 int ucs_config_sprintf_array(char *buf, size_t max, const void *src, const void *arg);
198 ucs_status_t ucs_config_clone_array(const void *src, void *dest, const void *arg);
199 void ucs_config_release_array(void *ptr, const void *arg);
200 void ucs_config_help_array(char *buf, size_t max, const void *arg);
201 
202 int ucs_config_sscanf_table(const char *buf, void *dest, const void *arg);
203 ucs_status_t ucs_config_clone_table(const void *src, void *dest, const void *arg);
204 void ucs_config_release_table(void *ptr, const void *arg);
205 void ucs_config_help_table(char *buf, size_t max, const void *arg);
206 
207 ucs_status_t ucs_config_clone_log_comp(const void *src, void *dst, const void *arg);
208 
209 void ucs_config_release_nop(void *ptr, const void *arg);
210 void ucs_config_help_generic(char *buf, size_t max, const void *arg);
211 
212 #define UCS_CONFIG_DEPRECATED_FIELD_OFFSET SIZE_MAX
213 
214 /* Forward declaration of array. Should be in header file. */
215 #define UCS_CONFIG_DECLARE_ARRAY(_name) \
216     extern ucs_config_array_t ucs_config_array_##_name;
217 
218 /* Definition of array of specific type. Should be in source file. */
219 #define UCS_CONFIG_DEFINE_ARRAY(_name, _elem_size, ...) \
220     ucs_config_array_t ucs_config_array_##_name = {_elem_size, __VA_ARGS__};
221 
222 #define UCS_CONFIG_TYPE_STRING     {ucs_config_sscanf_string,    ucs_config_sprintf_string, \
223                                     ucs_config_clone_string,     ucs_config_release_string, \
224                                     ucs_config_help_generic,     "string"}
225 
226 #define UCS_CONFIG_TYPE_INT        {ucs_config_sscanf_int,       ucs_config_sprintf_int, \
227                                     ucs_config_clone_int,        ucs_config_release_nop, \
228                                     ucs_config_help_generic,     "integer"}
229 
230 #define UCS_CONFIG_TYPE_UINT       {ucs_config_sscanf_uint,      ucs_config_sprintf_uint, \
231                                     ucs_config_clone_uint,       ucs_config_release_nop, \
232                                     ucs_config_help_generic,     "unsigned integer"}
233 
234 #define UCS_CONFIG_TYPE_ULONG      {ucs_config_sscanf_ulong,     ucs_config_sprintf_ulong, \
235                                     ucs_config_clone_ulong,      ucs_config_release_nop, \
236                                     ucs_config_help_generic,     "unsigned long"}
237 
238 #define UCS_CONFIG_TYPE_ULUNITS    {ucs_config_sscanf_ulunits,   ucs_config_sprintf_ulunits, \
239                                     ucs_config_clone_ulong,      ucs_config_release_nop, \
240                                     ucs_config_help_generic, \
241                                     "unsigned long: <number>, \"inf\", or \"auto\""}
242 
243 #define UCS_CONFIG_TYPE_DOUBLE     {ucs_config_sscanf_double,    ucs_config_sprintf_double, \
244                                     ucs_config_clone_double,     ucs_config_release_nop, \
245                                     ucs_config_help_generic,     "floating point number"}
246 
247 #define UCS_CONFIG_TYPE_HEX        {ucs_config_sscanf_hex,       ucs_config_sprintf_hex, \
248                                     ucs_config_clone_uint,       ucs_config_release_nop, \
249                                     ucs_config_help_generic, \
250                                     "hex representation of a number or \"auto\""}
251 
252 #define UCS_CONFIG_TYPE_BOOL       {ucs_config_sscanf_bool,      ucs_config_sprintf_bool, \
253                                     ucs_config_clone_int,        ucs_config_release_nop, \
254                                     ucs_config_help_generic,     "<y|n>"}
255 
256 #define UCS_CONFIG_TYPE_TERNARY    {ucs_config_sscanf_ternary,   ucs_config_sprintf_ternary, \
257                                     ucs_config_clone_int,        ucs_config_release_nop, \
258                                     ucs_config_help_generic,     "<yes|no|try>"}
259 
260 #define UCS_CONFIG_TYPE_ON_OFF     {ucs_config_sscanf_on_off,    ucs_config_sprintf_on_off_auto, \
261                                     ucs_config_clone_int,        ucs_config_release_nop, \
262                                     ucs_config_help_generic,     "<on|off>"}
263 
264 #define UCS_CONFIG_TYPE_ON_OFF_AUTO {ucs_config_sscanf_on_off_auto, ucs_config_sprintf_on_off_auto, \
265                                      ucs_config_clone_int,          ucs_config_release_nop, \
266                                      ucs_config_help_generic,       "<on|off|auto>"}
267 
268 #define UCS_CONFIG_TYPE_ENUM(t)    {ucs_config_sscanf_enum,      ucs_config_sprintf_enum, \
269                                     ucs_config_clone_uint,       ucs_config_release_nop, \
270                                     ucs_config_help_enum,        t}
271 
272 #define UCS_CONFIG_TYPE_BITMAP(t)  {ucs_config_sscanf_bitmap,    ucs_config_sprintf_bitmap, \
273                                     ucs_config_clone_uint,       ucs_config_release_nop, \
274                                     ucs_config_help_bitmap,      t}
275 
276 #define UCS_CONFIG_TYPE_BITMASK    {ucs_config_sscanf_bitmask,   ucs_config_sprintf_bitmask, \
277                                     ucs_config_clone_uint,       ucs_config_release_nop, \
278                                     ucs_config_help_generic,     "bit count"}
279 
280 #define UCS_CONFIG_TYPE_TIME       {ucs_config_sscanf_time,      ucs_config_sprintf_time, \
281                                     ucs_config_clone_double,     ucs_config_release_nop, \
282                                     ucs_config_help_generic,     "time value: <number>[s|us|ms|ns]"}
283 
284 #define UCS_CONFIG_TYPE_BW         {ucs_config_sscanf_bw,        ucs_config_sprintf_bw, \
285                                     ucs_config_clone_double,     ucs_config_release_nop, \
286                                     ucs_config_help_generic,     \
287                                     "bandwidth value: <number>[T|G|M|K]B|b[[p|/]s] or \"auto\""}
288 
289 #define UCS_CONFIG_TYPE_BW_SPEC    {ucs_config_sscanf_bw_spec,   ucs_config_sprintf_bw_spec, \
290                                     ucs_config_clone_bw_spec,    ucs_config_release_bw_spec, \
291                                     ucs_config_help_generic,     \
292                                     "device_name:<number>[T|G|M|K]B|b[[p|/]s] or device_name:auto"}
293 
294 #define UCS_CONFIG_TYPE_LOG_COMP   {ucs_config_sscanf_enum,      ucs_config_sprintf_enum, \
295                                     ucs_config_clone_log_comp,   ucs_config_release_nop, \
296                                     ucs_config_help_enum,        ucs_log_level_names}
297 
298 #define UCS_CONFIG_TYPE_SIGNO      {ucs_config_sscanf_signo,     ucs_config_sprintf_signo, \
299                                     ucs_config_clone_int,        ucs_config_release_nop, \
300                                     ucs_config_help_generic,     "system signal (number or SIGxxx)"}
301 
302 #define UCS_CONFIG_TYPE_MEMUNITS   {ucs_config_sscanf_memunits,  ucs_config_sprintf_memunits, \
303                                     ucs_config_clone_ulong,      ucs_config_release_nop, \
304                                     ucs_config_help_generic,     \
305                                     "memory units: <number>[b|kb|mb|gb], \"inf\", or \"auto\""}
306 
307 #define UCS_CONFIG_TYPE_ARRAY(a)   {ucs_config_sscanf_array,     ucs_config_sprintf_array, \
308                                     ucs_config_clone_array,      ucs_config_release_array, \
309                                     ucs_config_help_array,       &ucs_config_array_##a}
310 
311 #define UCS_CONFIG_TYPE_TABLE(t)   {ucs_config_sscanf_table,     NULL, \
312                                     ucs_config_clone_table,      ucs_config_release_table, \
313                                     ucs_config_help_table,       t}
314 
315 #define UCS_CONFIG_TYPE_RANGE_SPEC {ucs_config_sscanf_range_spec,ucs_config_sprintf_range_spec, \
316                                     ucs_config_clone_range_spec, ucs_config_release_nop, \
317                                     ucs_config_help_generic,     "numbers range: <number>-<number>"}
318 
319 #define UCS_CONFIG_TYPE_DEPRECATED {(ucs_field_type(ucs_config_parser_t, read))   ucs_empty_function_do_assert, \
320                                     (ucs_field_type(ucs_config_parser_t, write))  ucs_empty_function_do_assert, \
321                                     (ucs_field_type(ucs_config_parser_t, clone))  ucs_empty_function_do_assert, \
322                                     (ucs_field_type(ucs_config_parser_t, release))ucs_empty_function_do_assert, \
323                                     (ucs_field_type(ucs_config_parser_t, help))   ucs_empty_function_do_assert, \
324                                     ""}
325 
326 /**
327  * Helpers for using an array of strings
328  */
329 #define UCS_CONFIG_TYPE_STRING_ARRAY \
330     UCS_CONFIG_TYPE_ARRAY(string)
331 
332 UCS_CONFIG_DECLARE_ARRAY(string)
333 
334 
335 /**
336  * Helpers for Bandwidth units (see UCS_CONFIG_TYPE_BW)
337  */
338 #define UCS_CONFIG_BW_AUTO            ((double)-2)
339 #define UCS_CONFIG_BW_IS_AUTO(_value) ((ssize_t)(_value) == UCS_CONFIG_BW_AUTO)
340 
341 
342 /**
343  * Set default values for options.
344  *
345  * @param opts   User-defined options structure to fill.
346  * @param fields Array of fields which define how to parse.
347  */
348 ucs_status_t
349 ucs_config_parser_set_default_values(void *opts, ucs_config_field_t *fields);
350 
351 
352 /**
353  * Fill existing opts structure.
354  *
355  * @param opts           User-defined options structure to fill.
356  * @param fields         Array of fields which define how to parse.
357  * @param env_prefix     Prefix to add to all environment variables,
358  *                       env_prefix may consist of multiple sub preifxes
359  * @param table_prefix   Optional prefix to add to the variables of top-level table.
360  * @param ignore_errors  Whether to ignore parsing errors and continue parsing
361  *                       other fields.
362  */
363 ucs_status_t ucs_config_parser_fill_opts(void *opts, ucs_config_field_t *fields,
364                                          const char *env_prefix,
365                                          const char *table_prefix,
366                                          int ignore_errors);
367 
368 /**
369  * Perform deep copy of the options structure.
370  *
371  * @param src    User-defined options structure to copy from.
372  * @param dst    User-defined options structure to copy to.
373  * @param table  Array of fields which define the structure of the options.
374  */
375 ucs_status_t ucs_config_parser_clone_opts(const void *src, void *dst,
376                                           ucs_config_field_t *fields);
377 
378 /**
379  * Release the options fields.
380  * NOTE: Does not release the structure itself.
381  *
382  * @param opts   User-defined options structure.
383  * @param table  Array of fields which define the options.
384  */
385 void ucs_config_parser_release_opts(void *opts, ucs_config_field_t *fields);
386 
387 /**
388  * Print the options - names, values, documentation.
389  *
390  * @param stream         Output stream to print to.
391  * @param opts           User-defined options structure.
392  * @param fields         Array of fields which define the options.
393  * @param table_prefix   Optional prefix to add to the variables of top-level table.
394  * @param prefix         Prefix to add to all environment variables.
395  * @param flags          Flags which control the output.
396  */
397 void ucs_config_parser_print_opts(FILE *stream, const char *title, const void *opts,
398                                   ucs_config_field_t *fields, const char *table_prefix,
399                                   const char *prefix, ucs_config_print_flags_t flags);
400 
401 /**
402  * Print all options defined in the library - names, values, documentation.
403  *
404  * @param stream         Output stream to print to.
405  * @param prefix         Prefix to add to all environment variables.
406  * @param flags          Flags which control the output.
407  */
408 void ucs_config_parser_print_all_opts(FILE *stream, const char *prefix,
409                                       ucs_config_print_flags_t flags);
410 
411 /**
412  * Read a value from options structure.
413  *
414  * @param opts       User-defined options structure.
415  * @param fields     Array of fields which define how to parse.
416  * @param name       Option name including subtable prefixes.
417  * @param value      Filled with option value (as a string).
418  * @param max        Number of bytes reserved in 'value'.
419  */
420 ucs_status_t ucs_config_parser_get_value(void *opts, ucs_config_field_t *fields,
421                                         const char *name, char *value, size_t max);
422 
423 /**
424  * Modify existing opts structure with new setting.
425  *
426  * @param opts       User-defined options structure.
427  * @param fields     Array of fields which define how to parse.
428  * @param name       Option name to modify.
429  * @param value      Value to assign.
430  */
431 ucs_status_t ucs_config_parser_set_value(void *opts, ucs_config_field_t *fields,
432                                          const char *name, const char *value);
433 
434 /**
435  * Wrapper for `ucs_config_parser_warn_unused_env_vars`
436  * that ensures that this is called once
437  *
438  * @param env_prefix     Environment variable prefix.
439  *                       env_prefix may consist of multiple sub prefixex
440  */
441 
442 void ucs_config_parser_warn_unused_env_vars_once(const char *env_prefix);
443 
444 /**
445  * Translate configuration value of "MEMUNITS" type to actual value.
446  *
447  * @param config_size  Size specified by configuration.
448  * @param auto_size    Default size when configured to 'auto'.
449  * @param max_size     Maximal size to trim "inf".
450  */
451 size_t ucs_config_memunits_get(size_t config_size, size_t auto_size,
452                                size_t max_size);
453 
454 /**
455  * Look for a string in config names array.
456  *
457  * @param config_names     lookup array of counters patterns.
458  * @param str              string to search.
459  */
460 int ucs_config_names_search(ucs_config_names_array_t config_names,
461                             const char *str);
462 
463 END_C_DECLS
464 
465 #endif
466