]> git.proxmox.com Git - mirror_frr.git/blob - lib/defaults.c
Merge pull request #12851 from sri-mohan1/sri-mohan-ldp
[mirror_frr.git] / lib / defaults.c
1 // SPDX-License-Identifier: ISC
2 /*
3 * FRR switchable defaults.
4 * Copyright (c) 2017-2019 David Lamparter, for NetDEF, Inc.
5 */
6
7 #include <zebra.h>
8
9 #include "defaults.h"
10 #include "lib/version.h"
11
12 static char df_version[128] = FRR_VER_SHORT, df_profile[128] = DFLT_NAME;
13 static struct frr_default *dflt_first = NULL, **dflt_next = &dflt_first;
14
15 /* these are global for all FRR daemons. they have to be, since we write an
16 * integrated config with the same value for all daemons.
17 */
18 const char *frr_defaults_profiles[] = {
19 "traditional",
20 "datacenter",
21 NULL,
22 };
23
24 static int version_value(int ch)
25 {
26 /* non-ASCII shouldn't happen */
27 if (ch < 0 || ch >= 128)
28 return 2;
29
30 /* ~foo sorts older than nothing */
31 if (ch == '~')
32 return 0;
33 if (ch == '\0')
34 return 1;
35 if (isalpha(ch))
36 return 0x100 + tolower(ch);
37
38 /* punctuation and digits (and everything else) */
39 return 0x200 + ch;
40 }
41
42 int frr_version_cmp(const char *aa, const char *bb)
43 {
44 const char *apos = aa, *bpos = bb;
45
46 /* || is correct, we won't scan past the end of a string since that
47 * doesn't compare equal to anything else */
48 while (apos[0] || bpos[0]) {
49 if (isdigit((unsigned char)apos[0]) &&
50 isdigit((unsigned char)bpos[0])) {
51 unsigned long av, bv;
52 char *aend = NULL, *bend = NULL;
53
54 av = strtoul(apos, &aend, 10);
55 bv = strtoul(bpos, &bend, 10);
56 if (av < bv)
57 return -1;
58 if (av > bv)
59 return 1;
60
61 apos = aend;
62 bpos = bend;
63 continue;
64 }
65
66 int a = version_value(*apos++);
67 int b = version_value(*bpos++);
68
69 if (a < b)
70 return -1;
71 if (a > b)
72 return 1;
73 }
74 return 0;
75 }
76
77 static void frr_default_apply_one(struct frr_default *dflt, bool check);
78
79 void frr_default_add(struct frr_default *dflt)
80 {
81 dflt->next = NULL;
82 *dflt_next = dflt;
83 dflt_next = &dflt->next;
84
85 frr_default_apply_one(dflt, true);
86 }
87
88 static bool frr_match_version(const char *name, const char *vspec,
89 const char *version, bool check)
90 {
91 int cmp;
92 static const struct spec {
93 const char *str;
94 int dir, eq;
95 } specs[] = {
96 {"<=", -1, 1},
97 {">=", 1, 1},
98 {"==", 0, 1},
99 {"<", -1, 0},
100 {">", 1, 0},
101 {"=", 0, 1},
102 {NULL, 0, 0},
103 };
104 const struct spec *s;
105
106 if (!vspec)
107 /* NULL = all versions */
108 return true;
109
110 for (s = specs; s->str; s++)
111 if (!strncmp(s->str, vspec, strlen(s->str)))
112 break;
113 if (!s->str) {
114 if (check)
115 fprintf(stderr, "invalid version specifier for %s: %s",
116 name, vspec);
117 /* invalid version spec, never matches */
118 return false;
119 }
120
121 vspec += strlen(s->str);
122 while (isspace((unsigned char)*vspec))
123 vspec++;
124
125 cmp = frr_version_cmp(version, vspec);
126 if (cmp == s->dir || (s->eq && cmp == 0))
127 return true;
128
129 return false;
130 }
131
132 static void frr_default_apply_one(struct frr_default *dflt, bool check)
133 {
134 struct frr_default_entry *entry = dflt->entries;
135 struct frr_default_entry *dfltentry = NULL, *saveentry = NULL;
136
137 for (; entry->match_version || entry->match_profile; entry++) {
138 if (entry->match_profile
139 && strcmp(entry->match_profile, df_profile))
140 continue;
141
142 if (!dfltentry && frr_match_version(dflt->name,
143 entry->match_version, df_version, check))
144 dfltentry = entry;
145 if (!saveentry && frr_match_version(dflt->name,
146 entry->match_version, FRR_VER_SHORT, check))
147 saveentry = entry;
148
149 if (dfltentry && saveentry && !check)
150 break;
151 }
152 /* found default or arrived at last entry that has NULL,NULL spec */
153
154 if (!dfltentry)
155 dfltentry = entry;
156 if (!saveentry)
157 saveentry = entry;
158
159 if (dflt->dflt_bool)
160 *dflt->dflt_bool = dfltentry->val_bool;
161 if (dflt->dflt_str)
162 *dflt->dflt_str = dfltentry->val_str;
163 if (dflt->dflt_long)
164 *dflt->dflt_long = dfltentry->val_long;
165 if (dflt->dflt_ulong)
166 *dflt->dflt_ulong = dfltentry->val_ulong;
167 if (dflt->dflt_float)
168 *dflt->dflt_float = dfltentry->val_float;
169 if (dflt->save_bool)
170 *dflt->save_bool = saveentry->val_bool;
171 if (dflt->save_str)
172 *dflt->save_str = saveentry->val_str;
173 if (dflt->save_long)
174 *dflt->save_long = saveentry->val_long;
175 if (dflt->save_ulong)
176 *dflt->save_ulong = saveentry->val_ulong;
177 if (dflt->save_float)
178 *dflt->save_float = saveentry->val_float;
179 }
180
181 void frr_defaults_apply(void)
182 {
183 struct frr_default *dflt;
184
185 for (dflt = dflt_first; dflt; dflt = dflt->next)
186 frr_default_apply_one(dflt, false);
187 }
188
189 bool frr_defaults_profile_valid(const char *profile)
190 {
191 const char **p;
192
193 for (p = frr_defaults_profiles; *p; p++)
194 if (!strcmp(profile, *p))
195 return true;
196 return false;
197 }
198
199 const char *frr_defaults_version(void)
200 {
201 return df_version;
202 }
203
204 const char *frr_defaults_profile(void)
205 {
206 return df_profile;
207 }
208
209 void frr_defaults_version_set(const char *version)
210 {
211 strlcpy(df_version, version, sizeof(df_version));
212 frr_defaults_apply();
213 }
214
215 void frr_defaults_profile_set(const char *profile)
216 {
217 strlcpy(df_profile, profile, sizeof(df_profile));
218 frr_defaults_apply();
219 }