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