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