1 /*
2  * FRR switchable defaults.
3  * Copyright (C) 2017-2019  David Lamparter for NetDEF, Inc.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #ifndef _FRR_DEFAULTS_H
19 #define _FRR_DEFAULTS_H
20 
21 #include <stdbool.h>
22 
23 #include "compiler.h"
24 
25 #ifdef __cplusplus
26 extern "C" {
27 #endif
28 
29 /* frr_default wraps information about a default that has different
30  * values depending on FRR version or default-set
31  *
32  * frr_default_entry describes one match rule and the resulting value;
33  * entries are evaluated in order and the first matching is used.
34  *
35  * If both match_version and match_profile are specified, they must both
36  * match.  A NULL value matches everything.
37  */
38 struct frr_default_entry {
39 	/* syntax: "(<|<=|==|>=|>) [whitespace] version", e.g.
40 	 *   ">= 6.1-dev" "<6.0"
41 	 */
42 	const char *match_version;
43 	/* exact profile string to compare against */
44 	const char *match_profile;
45 
46 	/* value to use */
47 	bool val_bool;
48 	const char *val_str;
49 	long val_long;
50 	unsigned long val_ulong;
51 	float val_float;
52 };
53 
54 /* one struct frr_default exists for each malleable default value */
55 struct frr_default {
56 	struct frr_default *next;
57 
58 	/* for UI/debug use */
59 	const char *name;
60 
61 	/* the following two sets of variables differ because the written
62 	 * config always targets the *current* FRR version
63 	 *
64 	 * e.g. if you load a config that has "frr version 5.0" on 6.0
65 	 *   *dflt_long => set to the default value in 5.0
66 	 *   *save_long => set to the default value in 6.0
67 	 * config save will write "frr version 6.0" with 6.0 defaults
68 	 */
69 
70 	/* variable holding the default value for reading/use */
71 	bool *dflt_bool;
72 	const char **dflt_str;
73 	long *dflt_long;
74 	unsigned long *dflt_ulong;
75 	float *dflt_float;
76 
77 	/* variable to use when comparing for config save */
78 	bool *save_bool;
79 	const char **save_str;
80 	long *save_long;
81 	unsigned long *save_ulong;
82 	float *save_float;
83 
84 	struct frr_default_entry entries[];
85 };
86 
87 #define _FRR_CFG_DEFAULT(type, typname, varname, ...) \
88 	static type DFLT_##varname;                                            \
89 	static type SAVE_##varname;                                            \
90 	static struct frr_default _dflt_##varname = {                          \
91 		.name = #varname,                                              \
92 		.dflt_##typname = &DFLT_##varname,                             \
93 		.save_##typname = &SAVE_##varname,                             \
94 		.entries = { __VA_ARGS__ },                                    \
95 	};                                                                     \
96 	static void _dfltinit_##varname(void)                                  \
97 		__attribute__((_CONSTRUCTOR(1000)));                           \
98 	static void _dfltinit_##varname(void)                                  \
99 	{                                                                      \
100 		frr_default_add(&_dflt_##varname);                             \
101 	}
102 
103 /* use:
104  *   FRR_CFG_DEFAULT_LONG(SHARP_BLUNTNESS,
105  *	{ .val_long = 2, .match_version = ">= 10.0" },
106  *	{ .val_long = 1, .match_profile = "datacenter" },
107  *	{ .val_long = 0 },
108  *   )
109  *
110  * This will create DFLT_SHARP_BLUNTNESS and SAVE_SHARP_BLUNTNESS variables.
111  *
112  * Note: preprocessor defines cannot be used as variable names because they
113  * will be expanded and blow up with a compile error.  Use an enum or add an
114  * extra _ at the beginning (e.g. _SHARP_BLUNTNESS => DFLT__SHARP_BLUNTNESS)
115  */
116 #define FRR_CFG_DEFAULT_BOOL(varname, ...) \
117 	_FRR_CFG_DEFAULT(bool, bool, varname, ## __VA_ARGS__)
118 #define FRR_CFG_DEFAULT_LONG(varname, ...) \
119 	_FRR_CFG_DEFAULT(long, long, varname, ## __VA_ARGS__)
120 #define FRR_CFG_DEFAULT_ULONG(varname, ...) \
121 	_FRR_CFG_DEFAULT(unsigned long, ulong, varname, ## __VA_ARGS__)
122 #define FRR_CFG_DEFAULT_FLOAT(varname, ...) \
123 	_FRR_CFG_DEFAULT(float, float, varname, ## __VA_ARGS__)
124 #define FRR_CFG_DEFAULT_STR(varname, ...) \
125 	_FRR_CFG_DEFAULT(const char *, str, varname, ## __VA_ARGS__)
126 
127 
128 /* daemons don't need to call any of these, libfrr handles that */
129 extern void frr_default_add(struct frr_default *dflt);
130 extern void frr_defaults_version_set(const char *version);
131 extern void frr_defaults_profile_set(const char *profile);
132 extern const char *frr_defaults_version(void);
133 extern const char *frr_defaults_profile(void);
134 extern void frr_defaults_apply(void);
135 
136 extern const char *frr_defaults_profiles[];
137 extern bool frr_defaults_profile_valid(const char *profile);
138 
139 /* like strcmp(), but with version ordering */
140 extern int frr_version_cmp(const char *aa, const char *bb);
141 
142 #ifdef __cplusplus
143 }
144 #endif
145 
146 #endif /* _FRR_DEFAULTS_H */
147