]> git.proxmox.com Git - mirror_frr.git/blame - lib/libfrr.c
Merge pull request #410 from dslicenc/rdnbrd-vrr
[mirror_frr.git] / lib / libfrr.c
CommitLineData
4f04a76b
DL
1/*
2 * libfrr overall management functions
3 *
4 * Copyright (C) 2016 David Lamparter for NetDEF, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
18 * Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include <zebra.h>
22
23#include "libfrr.h"
24#include "getopt.h"
25#include "vty.h"
26#include "command.h"
27#include "version.h"
857b5446 28#include "memory_vty.h"
eb05883f 29#include "zclient.h"
cf7466ac 30#include "log_int.h"
30771d65 31#include "module.h"
eb05883f 32
a5b38c5b
DL
33DEFINE_HOOK(frr_late_init, (struct thread_master *tm), (tm))
34
eb05883f
DL
35const char frr_sysconfdir[] = SYSCONFDIR;
36const char frr_vtydir[] = DAEMON_VTY_DIR;
80b4df3b 37const char frr_moduledir[] = MODULE_PATH;
eb05883f
DL
38
39char config_default[256];
40static char pidfile_default[256];
41static char vtypath_default[256];
4f04a76b
DL
42
43static char comb_optstr[256];
44static struct option comb_lo[64];
45static struct option *comb_next_lo = &comb_lo[0];
46static char comb_helpstr[4096];
47
48struct optspec {
49 const char *optstr;
50 const char *helpstr;
51 const struct option *longopts;
52};
53
54static void opt_extend(const struct optspec *os)
55{
56 const struct option *lo;
57
58 strcat(comb_optstr, os->optstr);
59 strcat(comb_helpstr, os->helpstr);
60 for (lo = os->longopts; lo->name; lo++)
61 memcpy(comb_next_lo++, lo, sizeof(*lo));
62}
63
64
80b4df3b
MW
65#define OPTION_VTYSOCK 1000
66#define OPTION_MODULEDIR 1002
4f04a76b
DL
67
68static const struct option lo_always[] = {
eb05883f
DL
69 { "help", no_argument, NULL, 'h' },
70 { "version", no_argument, NULL, 'v' },
71 { "daemon", no_argument, NULL, 'd' },
30771d65 72 { "module", no_argument, NULL, 'M' },
eb05883f 73 { "vty_socket", required_argument, NULL, OPTION_VTYSOCK },
80b4df3b 74 { "moduledir", required_argument, NULL, OPTION_MODULEDIR },
4f04a76b
DL
75 { NULL }
76};
77static const struct optspec os_always = {
30771d65 78 "hvdM:",
4f04a76b
DL
79 " -h, --help Display this help and exit\n"
80 " -v, --version Print program version\n"
eb05883f 81 " -d, --daemon Runs in daemon mode\n"
30771d65 82 " -M, --module Load specified module\n"
80b4df3b
MW
83 " --vty_socket Override vty socket path\n"
84 " --moduledir Override modules directory\n",
4f04a76b
DL
85 lo_always
86};
87
88
eb05883f
DL
89static const struct option lo_cfg_pid_dry[] = {
90 { "pid_file", required_argument, NULL, 'i' },
91 { "config_file", required_argument, NULL, 'f' },
92 { "dryrun", no_argument, NULL, 'C' },
93 { NULL }
94};
95static const struct optspec os_cfg_pid_dry = {
96 "f:i:C",
97 " -f, --config_file Set configuration file name\n"
98 " -i, --pid_file Set process identifier file name\n"
99 " -C, --dryrun Check configuration for validity and exit\n",
100 lo_cfg_pid_dry
101};
102
103
104static const struct option lo_zclient[] = {
105 { "socket", required_argument, NULL, 'z' },
106 { NULL }
107};
108static const struct optspec os_zclient = {
109 "z:",
110 " -z, --socket Set path of zebra socket\n",
111 lo_zclient
112};
113
114
4f04a76b
DL
115static const struct option lo_vty[] = {
116 { "vty_addr", required_argument, NULL, 'A'},
117 { "vty_port", required_argument, NULL, 'P'},
118 { NULL }
119};
120static const struct optspec os_vty = {
121 "A:P:",
122 " -A, --vty_addr Set vty's bind address\n"
123 " -P, --vty_port Set vty's port number\n",
124 lo_vty
125};
126
127
128static const struct option lo_user[] = {
129 { "user", required_argument, NULL, 'u'},
130 { "group", required_argument, NULL, 'g'},
131 { NULL }
132};
133static const struct optspec os_user = {
134 "u:g:",
135 " -u, --user User to run as\n"
136 " -g, --group Group to run as\n",
137 lo_user
138};
139
140
141static struct frr_daemon_info *di = NULL;
142
143void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv)
144{
145 di = daemon;
146
147 /* basename(), opencoded. */
148 char *p = strrchr(argv[0], '/');
149 di->progname = p ? p + 1 : argv[0];
150
151 umask(0027);
152
153 opt_extend(&os_always);
eb05883f
DL
154 if (!(di->flags & FRR_NO_CFG_PID_DRY))
155 opt_extend(&os_cfg_pid_dry);
4f04a76b
DL
156 if (!(di->flags & FRR_NO_PRIVSEP))
157 opt_extend(&os_user);
eb05883f
DL
158 if (!(di->flags & FRR_NO_ZCLIENT))
159 opt_extend(&os_zclient);
4f04a76b
DL
160 if (!(di->flags & FRR_NO_TCPVTY))
161 opt_extend(&os_vty);
eb05883f
DL
162
163 snprintf(config_default, sizeof(config_default), "%s/%s.conf",
164 frr_sysconfdir, di->name);
165 snprintf(pidfile_default, sizeof(pidfile_default), "%s/%s.pid",
166 frr_vtydir, di->name);
4f04a76b
DL
167}
168
169void frr_opt_add(const char *optstr, const struct option *longopts,
170 const char *helpstr)
171{
172 const struct optspec main_opts = { optstr, helpstr, longopts };
173 opt_extend(&main_opts);
174}
175
176void frr_help_exit(int status)
177{
178 FILE *target = status ? stderr : stdout;
179
180 if (status != 0)
181 fprintf(stderr, "Invalid options.\n\n");
182
183 if (di->printhelp)
184 di->printhelp(target);
185 else
186 fprintf(target, "Usage: %s [OPTION...]\n\n%s%s%s\n\n%s",
187 di->progname,
188 di->proghelp,
189 di->copyright ? "\n\n" : "",
190 di->copyright ? di->copyright : "",
191 comb_helpstr);
192 fprintf(target, "\nReport bugs to %s\n", FRR_BUG_ADDRESS);
193 exit(status);
194}
195
30771d65
DL
196struct option_chain {
197 struct option_chain *next;
198 const char *arg;
199};
80b4df3b 200
30771d65 201static struct option_chain *modules = NULL, **modnext = &modules;
4f04a76b
DL
202static int errors = 0;
203
204static int frr_opt(int opt)
205{
206 static int vty_port_set = 0;
207 static int vty_addr_set = 0;
30771d65 208 struct option_chain *oc;
4f04a76b
DL
209 char *err;
210
211 switch (opt) {
212 case 'h':
213 frr_help_exit(0);
214 break;
215 case 'v':
216 print_version(di->progname);
217 exit(0);
218 break;
eb05883f
DL
219 case 'd':
220 di->daemon_mode = 1;
221 break;
30771d65
DL
222 case 'M':
223 oc = XMALLOC(MTYPE_TMP, sizeof(*oc));
224 oc->arg = optarg;
225 oc->next = NULL;
226 *modnext = oc;
227 modnext = &oc->next;
228 break;
eb05883f
DL
229 case 'i':
230 if (di->flags & FRR_NO_CFG_PID_DRY)
231 return 1;
232 di->pid_file = optarg;
233 break;
234 case 'f':
235 if (di->flags & FRR_NO_CFG_PID_DRY)
236 return 1;
237 di->config_file = optarg;
238 break;
239 case 'C':
240 if (di->flags & FRR_NO_CFG_PID_DRY)
241 return 1;
242 di->dryrun = 1;
243 break;
244 case 'z':
245 if (di->flags & FRR_NO_ZCLIENT)
246 return 1;
247 zclient_serv_path_set(optarg);
248 break;
4f04a76b
DL
249 case 'A':
250 if (di->flags & FRR_NO_TCPVTY)
251 return 1;
252 if (vty_addr_set) {
253 fprintf(stderr, "-A option specified more than once!\n");
254 errors++;
255 break;
256 }
257 vty_addr_set = 1;
258 di->vty_addr = optarg;
259 break;
260 case 'P':
261 if (di->flags & FRR_NO_TCPVTY)
262 return 1;
263 if (vty_port_set) {
264 fprintf(stderr, "-P option specified more than once!\n");
265 errors++;
266 break;
267 }
268 vty_port_set = 1;
269 di->vty_port = strtoul(optarg, &err, 0);
270 if (*err || !*optarg) {
271 fprintf(stderr, "invalid port number \"%s\" for -P option\n",
272 optarg);
273 errors++;
274 break;
275 }
276 break;
277 case OPTION_VTYSOCK:
278 if (di->vty_sock_path) {
279 fprintf(stderr, "--vty_socket option specified more than once!\n");
280 errors++;
281 break;
282 }
283 di->vty_sock_path = optarg;
284 break;
80b4df3b
MW
285 case OPTION_MODULEDIR:
286 if (di->module_path) {
287 fprintf(stderr, "----moduledir option specified more than once!\n");
288 errors++;
289 break;
290 }
291 di->module_path = optarg;
292 break;
4f04a76b
DL
293 case 'u':
294 if (di->flags & FRR_NO_PRIVSEP)
295 return 1;
296 di->privs->user = optarg;
297 break;
298 case 'g':
299 if (di->flags & FRR_NO_PRIVSEP)
300 return 1;
301 di->privs->group = optarg;
302 break;
303 default:
304 return 1;
305 }
306 return 0;
307}
308
309int frr_getopt(int argc, char * const argv[], int *longindex)
310{
311 int opt;
312 int lidx;
313
314 comb_next_lo->name = NULL;
315
316 do {
317 opt = getopt_long(argc, argv, comb_optstr, comb_lo, &lidx);
318 if (frr_opt(opt))
319 break;
320 } while (opt != -1);
321
322 if (opt == -1 && errors)
323 frr_help_exit(1);
324 if (longindex)
325 *longindex = lidx;
326 return opt;
327}
328
a5b38c5b 329static struct thread_master *master;
4f04a76b
DL
330struct thread_master *frr_init(void)
331{
30771d65
DL
332 struct option_chain *oc;
333 struct frrmod_runtime *module;
334 char moderr[256];
80b4df3b
MW
335 const char *dir;
336 dir = di->module_path ? di->module_path : frr_moduledir;
4f04a76b
DL
337
338 srandom(time(NULL));
339
bf1013e6 340 openzlog (di->progname, di->logname, di->instance,
4f04a76b
DL
341 LOG_CONS|LOG_NDELAY|LOG_PID, LOG_DAEMON);
342#if defined(HAVE_CUMULUS)
cf7466ac 343 zlog_set_level (ZLOG_DEST_SYSLOG, zlog_default->default_lvl);
4f04a76b
DL
344#endif
345
30771d65
DL
346 frrmod_init(di->module);
347 while (modules) {
348 modules = (oc = modules)->next;
80b4df3b 349 module = frrmod_load(oc->arg, dir, moderr, sizeof(moderr));
30771d65
DL
350 if (!module) {
351 fprintf(stderr, "%s\n", moderr);
352 exit(1);
353 }
354 XFREE(MTYPE_TMP, oc);
355 }
356
4f04a76b
DL
357 zprivs_init(di->privs);
358
359 master = thread_master_create();
360 signal_init(master, di->n_signals, di->signals);
361
857b5446
DL
362 if (di->flags & FRR_LIMITED_CLI)
363 cmd_init(-1);
364 else
365 cmd_init(1);
366 vty_init(master);
367 memory_init();
368
4f04a76b
DL
369 return master;
370}
371
eb05883f 372void frr_config_fork(void)
4f04a76b 373{
a5b38c5b
DL
374 hook_call(frr_late_init, master);
375
eb05883f
DL
376 if (di->instance) {
377 snprintf(config_default, sizeof(config_default), "%s/%s-%d.conf",
378 frr_sysconfdir, di->name, di->instance);
379 snprintf(pidfile_default, sizeof(pidfile_default), "%s/%s-%d.pid",
380 frr_vtydir, di->name, di->instance);
381 }
382
383 vty_read_config(di->config_file, config_default);
384
385 /* Don't start execution if we are in dry-run mode */
386 if (di->dryrun)
387 exit(0);
388
389 /* Daemonize. */
390 if (di->daemon_mode && daemon (0, 0) < 0) {
391 zlog_err("Zebra daemon failed: %s", strerror(errno));
392 exit(1);
393 }
394
395 if (!di->pid_file)
396 di->pid_file = pidfile_default;
397 pid_output (di->pid_file);
398}
399
400void frr_vty_serv(void)
401{
402 /* allow explicit override of vty_path in the future
403 * (not currently set anywhere) */
404 if (!di->vty_path) {
405 const char *dir;
406 dir = di->vty_sock_path ? di->vty_sock_path : frr_vtydir;
407
408 if (di->instance)
409 snprintf(vtypath_default, sizeof(vtypath_default),
410 "%s/%s-%d.vty",
411 dir, di->name, di->instance);
412 else
413 snprintf(vtypath_default, sizeof(vtypath_default),
414 "%s/%s.vty", dir, di->name);
415
416 di->vty_path = vtypath_default;
417 }
418
419 vty_serv_sock(di->vty_addr, di->vty_port, di->vty_path);
4f04a76b
DL
420}
421
16077f2f
DL
422void frr_run(struct thread_master *master)
423{
424 char instanceinfo[64] = "";
425
426 frr_vty_serv();
427
428 if (di->instance)
429 snprintf(instanceinfo, sizeof(instanceinfo), "instance %u ",
430 di->instance);
431
432 zlog_notice("%s %s starting: %svty@%d%s",
433 di->name,
434 FRR_VERSION,
435 instanceinfo,
436 di->vty_port,
437 di->startinfo);
438
439 struct thread thread;
440 while (thread_fetch(master, &thread))
441 thread_call(&thread);
442}