]> git.proxmox.com Git - mirror_frr.git/blame - lib/defaults.c
Merge pull request #13649 from donaldsharp/unlock_the_node_or_else
[mirror_frr.git] / lib / defaults.c
CommitLineData
acddc0ed 1// SPDX-License-Identifier: ISC
96673e06
DL
2/*
3 * FRR switchable defaults.
4 * Copyright (c) 2017-2019 David Lamparter, for NetDEF, Inc.
96673e06
DL
5 */
6
7#include <zebra.h>
8
9#include "defaults.h"
09781197 10#include "lib/version.h"
96673e06 11
ac4adef4
DL
12static char df_version[128] = FRR_VER_SHORT, df_profile[128] = DFLT_NAME;
13static 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 */
18const char *frr_defaults_profiles[] = {
19 "traditional",
20 "datacenter",
21 NULL,
22};
23
96673e06
DL
24static 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
42int 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}
ac4adef4
DL
76
77static void frr_default_apply_one(struct frr_default *dflt, bool check);
78
79void 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
88static bool frr_match_version(const char *name, const char *vspec,
89 const char *version, bool check)
90{
91 int cmp;
d29c01db 92 static const struct spec {
ac4adef4 93 const char *str;
7b8c2b3d 94 int dir, eq;
d29c01db 95 } specs[] = {
ac4adef4
DL
96 {"<=", -1, 1},
97 {">=", 1, 1},
98 {"==", 0, 1},
99 {"<", -1, 0},
100 {">", 1, 0},
101 {"=", 0, 1},
102 {NULL, 0, 0},
103 };
d29c01db 104 const struct spec *s;
ac4adef4
DL
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
132static 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
f210b3e3
DL
159 if (dflt->dflt_bool)
160 *dflt->dflt_bool = dfltentry->val_bool;
ac4adef4
DL
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;
f210b3e3
DL
169 if (dflt->save_bool)
170 *dflt->save_bool = saveentry->val_bool;
ac4adef4
DL
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
181void 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
189bool 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
199const char *frr_defaults_version(void)
200{
201 return df_version;
202}
203
204const char *frr_defaults_profile(void)
205{
206 return df_profile;
207}
208
209void frr_defaults_version_set(const char *version)
210{
211 strlcpy(df_version, version, sizeof(df_version));
212 frr_defaults_apply();
213}
214
215void frr_defaults_profile_set(const char *profile)
216{
217 strlcpy(df_profile, profile, sizeof(df_profile));
218 frr_defaults_apply();
219}