diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/command.c | 3 | ||||
| -rw-r--r-- | lib/command.h | 1 | ||||
| -rw-r--r-- | lib/gitversion.pl | 2 | ||||
| -rw-r--r-- | lib/grammar_sandbox_main.c | 5 | ||||
| -rw-r--r-- | lib/libfrr.c | 290 | ||||
| -rw-r--r-- | lib/libfrr.h | 1 | ||||
| -rw-r--r-- | lib/libospf.h | 2 | ||||
| -rw-r--r-- | lib/log.c | 66 | ||||
| -rw-r--r-- | lib/log.h | 3 | ||||
| -rw-r--r-- | lib/monotime.h | 4 | ||||
| -rw-r--r-- | lib/privs.c | 17 | ||||
| -rw-r--r-- | lib/privs.h | 1 | ||||
| -rw-r--r-- | lib/pw.h | 52 | ||||
| -rw-r--r-- | lib/subdir.am | 21 | ||||
| -rw-r--r-- | lib/thread.c | 12 | ||||
| -rw-r--r-- | lib/vty.c | 142 | ||||
| -rw-r--r-- | lib/vty.h | 7 | ||||
| -rw-r--r-- | lib/zclient.c | 68 | ||||
| -rw-r--r-- | lib/zclient.h | 37 |
19 files changed, 629 insertions, 105 deletions
diff --git a/lib/command.c b/lib/command.c index f28a55ec6d..09ffa6ce56 100644 --- a/lib/command.c +++ b/lib/command.c @@ -110,6 +110,7 @@ const char *node_names[] = { "forwarding", // FORWARDING_NODE, "protocol", // PROTOCOL_NODE, "mpls", // MPLS_NODE, + "pw", // PW_NODE, "vty", // VTY_NODE, "link-params", // LINK_PARAMS_NODE, "bgp evpn vni", // BGP_EVPN_VNI_NODE, @@ -1253,6 +1254,7 @@ void cmd_exit(struct vty *vty) vty_config_unlock(vty); break; case INTERFACE_NODE: + case PW_NODE: case NS_NODE: case VRF_NODE: case ZEBRA_NODE: @@ -1338,6 +1340,7 @@ DEFUN (config_end, break; case CONFIG_NODE: case INTERFACE_NODE: + case PW_NODE: case NS_NODE: case VRF_NODE: case ZEBRA_NODE: diff --git a/lib/command.h b/lib/command.h index 5184b53a9f..d0c9f0eaf9 100644 --- a/lib/command.h +++ b/lib/command.h @@ -132,6 +132,7 @@ enum node_type { FORWARDING_NODE, /* IP forwarding node. */ PROTOCOL_NODE, /* protocol filtering node */ MPLS_NODE, /* MPLS config node */ + PW_NODE, /* Pseudowire config node */ VTY_NODE, /* Vty node. */ LINK_PARAMS_NODE, /* Link-parameters node */ BGP_EVPN_VNI_NODE, /* BGP EVPN VNI */ diff --git a/lib/gitversion.pl b/lib/gitversion.pl index 8ddd9ffa55..2718046d0b 100644 --- a/lib/gitversion.pl +++ b/lib/gitversion.pl @@ -4,7 +4,7 @@ use strict; my $dir = shift; chdir $dir || die "$dir: $!\n"; -my $gitdesc = `git describe --always --dirty || echo -- \"0-gUNKNOWN\"`; +my $gitdesc = `git describe --always --first-parent --tags --dirty --match 'frr-*' || echo -- \"0-gUNKNOWN\"`; chomp $gitdesc; my $gitsuffix = ($gitdesc =~ /([0-9a-fA-F]{7}(-dirty)?)$/) ? "-g$1" : "-gUNKNOWN"; diff --git a/lib/grammar_sandbox_main.c b/lib/grammar_sandbox_main.c index c236d2c7be..89b0993d1d 100644 --- a/lib/grammar_sandbox_main.c +++ b/lib/grammar_sandbox_main.c @@ -26,10 +26,11 @@ #include "command.h" #include "memory_vty.h" -static void vty_do_exit(void) +static void vty_do_exit(int isexit) { printf("\nend.\n"); - exit(0); + if (!isexit) + exit(0); } struct thread_master *master; diff --git a/lib/libfrr.c b/lib/libfrr.c index c901dcc229..e5573da900 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -21,8 +21,12 @@ #include <zebra.h> #include <sys/un.h> +#include <sys/types.h> +#include <sys/wait.h> + #include "libfrr.h" #include "getopt.h" +#include "privs.h" #include "vty.h" #include "command.h" #include "version.h" @@ -30,6 +34,7 @@ #include "zclient.h" #include "log_int.h" #include "module.h" +#include "network.h" DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm)) @@ -93,12 +98,15 @@ static const struct option lo_cfg_pid_dry[] = { {"pid_file", required_argument, NULL, 'i'}, {"config_file", required_argument, NULL, 'f'}, {"dryrun", no_argument, NULL, 'C'}, + {"terminal", no_argument, NULL, 't'}, {NULL}}; static const struct optspec os_cfg_pid_dry = { - "f:i:C", + "f:i:Ct", " -f, --config_file Set configuration file name\n" " -i, --pid_file Set process identifier file name\n" - " -C, --dryrun Check configuration for validity and exit\n", + " -C, --dryrun Check configuration for validity and exit\n" + " -t, --terminal Open terminal session on stdio\n" + " -d -t Daemonize after terminal session ends\n", lo_cfg_pid_dry}; @@ -344,6 +352,11 @@ static int frr_opt(int opt) return 1; di->dryrun = 1; break; + case 't': + if (di->flags & FRR_NO_CFG_PID_DRY) + return 1; + di->terminal = 1; + break; case 'z': if (di->flags & FRR_NO_ZCLIENT) return 1; @@ -434,6 +447,49 @@ int frr_getopt(int argc, char *const argv[], int *longindex) return opt; } +static void frr_mkdir(const char *path, bool strip) +{ + char buf[256]; + mode_t prev; + int ret; + struct zprivs_ids_t ids; + + if (strip) { + char *slash = strrchr(path, '/'); + size_t plen; + if (!slash) + return; + plen = slash - path; + if (plen > sizeof(buf) - 1) + return; + memcpy(buf, path, plen); + buf[plen] = '\0'; + path = buf; + } + + /* o+rx (..5) is needed for the frrvty group to work properly; + * without it, users in the frrvty group can't access the vty sockets. + */ + prev = umask(0022); + ret = mkdir(path, 0755); + umask(prev); + + if (ret != 0) { + /* if EEXIST, return without touching the permissions, + * so user-set custom permissions are left in place + */ + if (errno == EEXIST) + return; + + zlog_warn("failed to mkdir \"%s\": %s", path, strerror(errno)); + return; + } + + zprivs_get_ids(&ids); + if (chown(path, ids.uid_normal, ids.gid_normal)) + zlog_warn("failed to chown \"%s\": %s", path, strerror(errno)); +} + static struct thread_master *master; struct thread_master *frr_init(void) { @@ -449,6 +505,8 @@ struct thread_master *frr_init(void) snprintf(frr_protonameinst, sizeof(frr_protonameinst), "%s[%u]", di->logname, di->instance); + zprivs_preinit(di->privs); + openzlog(di->progname, di->logname, di->instance, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON); #if defined(HAVE_CUMULUS) @@ -462,6 +520,16 @@ struct thread_master *frr_init(void) exit(1); } + /* don't mkdir these as root... */ + if (!(di->flags & FRR_NO_PRIVSEP)) { + if (!di->pid_file || !di->vty_path) + frr_mkdir(frr_vtydir, false); + if (di->pid_file) + frr_mkdir(di->pid_file, true); + if (di->vty_path) + frr_mkdir(di->vty_path, true); + } + frrmod_init(di->module); while (modules) { modules = (oc = modules)->next; @@ -488,6 +556,134 @@ struct thread_master *frr_init(void) return master; } +static int rcvd_signal = 0; + +static void rcv_signal(int signum) +{ + rcvd_signal = signum; + /* poll() is interrupted by the signal; handled below */ +} + +static void frr_daemon_wait(int fd) +{ + struct pollfd pfd[1]; + int ret; + pid_t exitpid; + int exitstat; + sigset_t sigs, prevsigs; + + sigemptyset(&sigs); + sigaddset(&sigs, SIGTSTP); + sigaddset(&sigs, SIGQUIT); + sigaddset(&sigs, SIGINT); + sigprocmask(SIG_BLOCK, &sigs, &prevsigs); + + struct sigaction sa = { + .sa_handler = rcv_signal, .sa_flags = SA_RESETHAND, + }; + sigemptyset(&sa.sa_mask); + sigaction(SIGTSTP, &sa, NULL); + sigaction(SIGQUIT, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + + do { + char buf[1]; + ssize_t nrecv; + + pfd[0].fd = fd; + pfd[0].events = POLLIN; + + rcvd_signal = 0; + +#if defined(HAVE_PPOLL) + ret = ppoll(pfd, 1, NULL, &prevsigs); +#elif defined(HAVE_POLLTS) + ret = pollts(pfd, 1, NULL, &prevsigs); +#else + /* racy -- only used on FreeBSD 9 */ + sigset_t tmpsigs; + sigprocmask(SIG_SETMASK, &prevsigs, &tmpsigs); + ret = poll(pfd, 1, -1); + sigprocmask(SIG_SETMASK, &tmpsigs, NULL); +#endif + if (ret < 0 && errno != EINTR && errno != EAGAIN) { + perror("poll()"); + exit(1); + } + switch (rcvd_signal) { + case SIGTSTP: + send(fd, "S", 1, 0); + do { + nrecv = recv(fd, buf, sizeof(buf), 0); + } while (nrecv == -1 + && (errno == EINTR || errno == EAGAIN)); + + raise(SIGTSTP); + sigaction(SIGTSTP, &sa, NULL); + send(fd, "R", 1, 0); + break; + case SIGINT: + send(fd, "I", 1, 0); + break; + case SIGQUIT: + send(fd, "Q", 1, 0); + break; + } + } while (ret <= 0); + + exitpid = waitpid(-1, &exitstat, WNOHANG); + if (exitpid == 0) + /* child successfully went to main loop & closed socket */ + exit(0); + + /* child failed one way or another ... */ + if (WIFEXITED(exitstat)) + fprintf(stderr, "%s failed to start, exited %d\n", di->name, + WEXITSTATUS(exitstat)); + else if (WIFSIGNALED(exitstat)) + fprintf(stderr, "%s crashed in startup, signal %d\n", di->name, + WTERMSIG(exitstat)); + else + fprintf(stderr, "%s failed to start, unknown problem\n", + di->name); + exit(1); +} + +static int daemon_ctl_sock = -1; + +static void frr_daemonize(void) +{ + int fds[2]; + pid_t pid; + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds)) { + perror("socketpair() for daemon control"); + exit(1); + } + set_cloexec(fds[0]); + set_cloexec(fds[1]); + + pid = fork(); + if (pid < 0) { + perror("fork()"); + exit(1); + } + if (pid == 0) { + /* child */ + close(fds[0]); + if (setsid() < 0) { + perror("setsid()"); + exit(1); + } + + daemon_ctl_sock = fds[1]; + return; + } + + close(fds[1]); + frr_daemon_wait(fds[0]); +} + void frr_config_fork(void) { hook_call(frr_late_init, master); @@ -506,11 +702,8 @@ void frr_config_fork(void) if (di->dryrun) exit(0); - /* Daemonize. */ - if (di->daemon_mode && daemon(0, 0) < 0) { - zlog_err("Zebra daemon failed: %s", strerror(errno)); - exit(1); - } + if (di->daemon_mode || di->terminal) + frr_daemonize(); if (!di->pid_file) di->pid_file = pidfile_default; @@ -538,6 +731,67 @@ void frr_vty_serv(void) vty_serv_sock(di->vty_addr, di->vty_port, di->vty_path); } +static void frr_terminal_close(int isexit) +{ + if (daemon_ctl_sock != -1) { + close(daemon_ctl_sock); + daemon_ctl_sock = -1; + } + + if (!di->daemon_mode || isexit) { + printf("\n%s exiting\n", di->name); + if (!isexit) + raise(SIGINT); + return; + } else { + printf("\n%s daemonizing\n", di->name); + fflush(stdout); + } + + int nullfd = open("/dev/null", O_RDONLY | O_NOCTTY); + dup2(nullfd, 0); + dup2(nullfd, 1); + dup2(nullfd, 2); + close(nullfd); +} + +static struct thread *daemon_ctl_thread = NULL; + +static int frr_daemon_ctl(struct thread *t) +{ + char buf[1]; + ssize_t nr; + + nr = recv(daemon_ctl_sock, buf, sizeof(buf), 0); + if (nr < 0 && (errno == EINTR || errno == EAGAIN)) + goto out; + if (nr <= 0) + return 0; + + switch (buf[0]) { + case 'S': /* SIGTSTP */ + vty_stdio_suspend(); + send(daemon_ctl_sock, "s", 1, 0); + break; + case 'R': /* SIGTCNT [implicit] */ + vty_stdio_resume(); + break; + case 'I': /* SIGINT */ + di->daemon_mode = false; + raise(SIGINT); + break; + case 'Q': /* SIGQUIT */ + di->daemon_mode = true; + vty_stdio_close(); + break; + } + +out: + thread_add_read(master, frr_daemon_ctl, NULL, daemon_ctl_sock, + &daemon_ctl_thread); + return 0; +} + void frr_run(struct thread_master *master) { char instanceinfo[64] = ""; @@ -551,6 +805,28 @@ void frr_run(struct thread_master *master) zlog_notice("%s %s starting: %svty@%d%s", di->name, FRR_VERSION, instanceinfo, di->vty_port, di->startinfo); + if (di->terminal) { + vty_stdio(frr_terminal_close); + if (daemon_ctl_sock != -1) { + set_nonblocking(daemon_ctl_sock); + thread_add_read(master, frr_daemon_ctl, NULL, + daemon_ctl_sock, &daemon_ctl_thread); + } + } else { + int nullfd = open("/dev/null", O_RDONLY | O_NOCTTY); + dup2(nullfd, 0); + dup2(nullfd, 1); + dup2(nullfd, 2); + close(nullfd); + + if (daemon_ctl_sock != -1) + close(daemon_ctl_sock); + daemon_ctl_sock = -1; + } + + /* end fixed stderr startup logging */ + zlog_startup_stderr = false; + struct thread thread; while (thread_fetch(master, &thread)) thread_call(&thread); diff --git a/lib/libfrr.h b/lib/libfrr.h index 23516150ee..1710fc9a84 100644 --- a/lib/libfrr.h +++ b/lib/libfrr.h @@ -49,6 +49,7 @@ struct frr_daemon_info { char *vty_sock_path; bool dryrun; bool daemon_mode; + bool terminal; const char *config_file; const char *pid_file; const char *vty_path; diff --git a/lib/libospf.h b/lib/libospf.h index c9483a4c65..45aedb6a7d 100644 --- a/lib/libospf.h +++ b/lib/libospf.h @@ -34,7 +34,7 @@ /* Architectual Constants */ #ifdef DEBUG -#define OSPF_LS_REFRESH_TIME 60 +#define OSPF_LS_REFRESH_TIME 120 #else #define OSPF_LS_REFRESH_TIME 1800 #endif @@ -41,6 +41,7 @@ DEFINE_MTYPE_STATIC(LIB, ZLOG, "Logging") static int logfile_fd = -1; /* Used in signal handler. */ struct zlog *zlog_default = NULL; +bool zlog_startup_stderr = true; const char *zlog_priority[] = { "emergencies", "alerts", "critical", "errors", "warnings", @@ -172,6 +173,25 @@ static void time_print(FILE *fp, struct timestamp_control *ctl) } +static void vzlog_file(struct zlog *zl, struct timestamp_control *tsctl, + const char *proto_str, int record_priority, + int priority, FILE *fp, const char *format, + va_list args) +{ + va_list ac; + + time_print(fp, tsctl); + if (record_priority) + fprintf(fp, "%s: ", zlog_priority[priority]); + + fprintf(fp, "%s", proto_str); + va_copy(ac, args); + vfprintf(fp, format, ac); + va_end(ac); + fprintf(fp, "\n"); + fflush(fp); +} + /* va_list version of zlog. */ void vzlog(int priority, const char *format, va_list args) { @@ -210,32 +230,21 @@ void vzlog(int priority, const char *format, va_list args) sprintf(proto_str, "%s: ", zl->protoname); /* File output. */ - if ((priority <= zl->maxlvl[ZLOG_DEST_FILE]) && zl->fp) { - va_list ac; - time_print(zl->fp, &tsctl); - if (zl->record_priority) - fprintf(zl->fp, "%s: ", zlog_priority[priority]); - fprintf(zl->fp, "%s", proto_str); - va_copy(ac, args); - vfprintf(zl->fp, format, ac); - va_end(ac); - fprintf(zl->fp, "\n"); - fflush(zl->fp); - } - - /* stdout output. */ - if (priority <= zl->maxlvl[ZLOG_DEST_STDOUT]) { - va_list ac; - time_print(stdout, &tsctl); - if (zl->record_priority) - fprintf(stdout, "%s: ", zlog_priority[priority]); - fprintf(stdout, "%s", proto_str); - va_copy(ac, args); - vfprintf(stdout, format, ac); - va_end(ac); - fprintf(stdout, "\n"); - fflush(stdout); - } + if ((priority <= zl->maxlvl[ZLOG_DEST_FILE]) && zl->fp) + vzlog_file(zl, &tsctl, proto_str, zl->record_priority, + priority, zl->fp, format, args); + + /* fixed-config logging to stderr while we're stating up & haven't + * daemonized / reached mainloop yet + * + * note the "else" on stdout output -- we don't want to print the same + * message to both stderr and stdout. */ + if (zlog_startup_stderr && priority <= LOG_WARNING) + vzlog_file(zl, &tsctl, proto_str, 1, + priority, stderr, format, args); + else if (priority <= zl->maxlvl[ZLOG_DEST_STDOUT]) + vzlog_file(zl, &tsctl, proto_str, zl->record_priority, + priority, stdout, format, args); /* Terminal monitor. */ if (priority <= zl->maxlvl[ZLOG_DEST_MONITOR]) @@ -916,6 +925,11 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_MACIP_DEL), DESC_ENTRY(ZEBRA_REMOTE_MACIP_ADD), DESC_ENTRY(ZEBRA_REMOTE_MACIP_DEL), + DESC_ENTRY(ZEBRA_PW_ADD), + DESC_ENTRY(ZEBRA_PW_DELETE), + DESC_ENTRY(ZEBRA_PW_SET), + DESC_ENTRY(ZEBRA_PW_UNSET), + DESC_ENTRY(ZEBRA_PW_STATUS_UPDATE), }; #undef DESC_ENTRY @@ -24,6 +24,7 @@ #include <syslog.h> #include <stdint.h> +#include <stdbool.h> #include <stdio.h> /* Here is some guidance on logging levels to use: @@ -54,6 +55,8 @@ typedef enum { } zlog_dest_t; #define ZLOG_NUM_DESTS (ZLOG_DEST_FILE+1) +extern bool zlog_startup_stderr; + /* Message structure. */ struct message { int key; diff --git a/lib/monotime.h b/lib/monotime.h index 7bd3386498..8e50c1874a 100644 --- a/lib/monotime.h +++ b/lib/monotime.h @@ -49,6 +49,10 @@ static inline time_t monotime(struct timeval *tvo) return ts.tv_sec; } +#define ONE_DAY_SECOND 60*60*24 +#define ONE_WEEK_SECOND ONE_DAY_SECOND*7 +#define ONE_YEAR_SECOND ONE_DAY_SECOND*365 + /* the following two return microseconds, not time_t! * * also, they're negative forms of each other, but having both makes the diff --git a/lib/privs.c b/lib/privs.c index c971596117..eda3fb02d4 100644 --- a/lib/privs.c +++ b/lib/privs.c @@ -696,13 +696,10 @@ static int getgrouplist(const char *user, gid_t group, gid_t *groups, } #endif /* HAVE_GETGROUPLIST */ -void zprivs_init(struct zebra_privs_t *zprivs) +void zprivs_preinit(struct zebra_privs_t *zprivs) { struct passwd *pwentry = NULL; struct group *grentry = NULL; - gid_t groups[NGROUPS_MAX]; - int i, ngroups = 0; - int found = 0; if (!zprivs) { fprintf(stderr, "zprivs_init: called with NULL arg!\n"); @@ -751,6 +748,18 @@ void zprivs_init(struct zebra_privs_t *zprivs) zprivs_state.zgid = grentry->gr_gid; } +} + +void zprivs_init(struct zebra_privs_t *zprivs) +{ + gid_t groups[NGROUPS_MAX]; + int i, ngroups = 0; + int found = 0; + + /* NULL privs */ + if (!(zprivs->user || zprivs->group || zprivs->cap_num_p + || zprivs->cap_num_i)) + return; if (zprivs->user) { ngroups = sizeof(groups); diff --git a/lib/privs.h b/lib/privs.h index c18fe78add..7fe59328b2 100644 --- a/lib/privs.h +++ b/lib/privs.h @@ -74,6 +74,7 @@ struct zprivs_ids_t { }; /* initialise zebra privileges */ +extern void zprivs_preinit(struct zebra_privs_t *zprivs); extern void zprivs_init(struct zebra_privs_t *zprivs); /* drop all and terminate privileges */ extern void zprivs_terminate(struct zebra_privs_t *); diff --git a/lib/pw.h b/lib/pw.h new file mode 100644 index 0000000000..2cfaa47e5d --- /dev/null +++ b/lib/pw.h @@ -0,0 +1,52 @@ +/* Pseudowire definitions + * Copyright (C) 2016 Volta Networks, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifndef _FRR_PW_H +#define _FRR_PW_H + +/* L2VPN name length. */ +#define L2VPN_NAME_LEN 32 + +/* Pseudowire type - LDP and BGP use the same values. */ +#define PW_TYPE_ETHERNET_TAGGED 0x0004 /* RFC 4446 */ +#define PW_TYPE_ETHERNET 0x0005 /* RFC 4446 */ +#define PW_TYPE_WILDCARD 0x7FFF /* RFC 4863, RFC 6668 */ + +/* Pseudowire flags. */ +#define F_PSEUDOWIRE_CWORD 0x01 + +/* Pseudowire status. */ +#define PW_STATUS_DOWN 0 +#define PW_STATUS_UP 1 + +/* + * Protocol-specific information about the pseudowire. + */ +union pw_protocol_fields { + struct { + struct in_addr lsr_id; + uint32_t pwid; + char vpn_name[L2VPN_NAME_LEN]; + } ldp; + struct { + /* TODO */ + } bgp; +}; + +#endif /* _FRR_PW_H */ diff --git a/lib/subdir.am b/lib/subdir.am index 28a4ce5579..6a62cbb678 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -123,8 +123,8 @@ pkginclude_HEADERS += \ lib/prefix.h \ lib/privs.h \ lib/ptm_lib.h \ + lib/pw.h \ lib/qobj.h \ - lib/route_types.h \ lib/routemap.h \ lib/sbuf.h \ lib/sha256.h \ @@ -141,7 +141,6 @@ pkginclude_HEADERS += \ lib/termtable.h \ lib/thread.h \ lib/vector.h \ - lib/version.h \ lib/vlan.h \ lib/vrf.h \ lib/vrf_int.h \ @@ -154,6 +153,11 @@ pkginclude_HEADERS += \ lib/zebra.h \ # end +nodist_pkginclude_HEADERS += \ + lib/route_types.h \ + lib/version.h \ + # end + noinst_HEADERS += \ lib/clippy.h \ lib/log_int.h \ @@ -180,16 +184,22 @@ lib_libfrrsnmp_la_SOURCES = \ # CLI utilities # noinst_PROGRAMS += \ - lib/clippy \ lib/grammar_sandbox \ # end +if BUILD_CLIPPY +noinst_PROGRAMS += lib/clippy +else +$(HOSTTOOLS)lib/clippy: + @$(MAKE) -C $(top_builddir)/$(HOSTTOOLS) lib/route_types.h lib/clippy +endif + lib_grammar_sandbox_SOURCES = \ lib/grammar_sandbox_main.c lib_grammar_sandbox_LDADD = \ lib/libfrr.la -lib_clippy_CPPFLAGS = -D_GNU_SOURCE -I$(top_srcdir)/lib +lib_clippy_CPPFLAGS = $(AM_CPPFLAGS) -D_GNU_SOURCE lib_clippy_CFLAGS = $(PYTHON_CFLAGS) lib_clippy_LDADD = $(PYTHON_LIBS) lib_clippy_SOURCES = \ @@ -210,6 +220,7 @@ lib_clippy_SOURCES = \ # EXTRA_DIST += \ lib/command_lex.h \ + lib/command_parse.h \ lib/gitversion.pl \ lib/queue.h \ lib/route_types.pl \ @@ -217,8 +228,6 @@ EXTRA_DIST += \ # end BUILT_SOURCES += \ - lib/command_lex.h \ - lib/command_parse.h \ lib/gitversion.h \ lib/route_types.h \ # end diff --git a/lib/thread.c b/lib/thread.c index fd36eaf388..4a5c61d036 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -340,9 +340,6 @@ static void cancelreq_del(void *cr) /* initializer, only ever called once */ static void initializer() { - if (!masters) - masters = list_new(); - pthread_key_create(&thread_current, NULL); } @@ -415,9 +412,12 @@ struct thread_master *thread_master_create(const char *name) rv->handler.copy = XCALLOC(MTYPE_THREAD_MASTER, sizeof(struct pollfd) * rv->handler.pfdsize); - /* add to list */ + /* add to list of threadmasters */ pthread_mutex_lock(&masters_mtx); { + if (!masters) + masters = list_new(); + listnode_add(masters, rv); } pthread_mutex_unlock(&masters_mtx); @@ -551,6 +551,10 @@ void thread_master_free(struct thread_master *m) pthread_mutex_lock(&masters_mtx); { listnode_delete(masters, m); + if (masters->count == 0) { + list_free (masters); + masters = NULL; + } } pthread_mutex_unlock(&masters_mtx); @@ -684,6 +684,7 @@ static void vty_end_config(struct vty *vty) break; case CONFIG_NODE: case INTERFACE_NODE: + case PW_NODE: case ZEBRA_NODE: case RIP_NODE: case RIPNG_NODE: @@ -1094,6 +1095,7 @@ static void vty_stop_input(struct vty *vty) break; case CONFIG_NODE: case INTERFACE_NODE: + case PW_NODE: case ZEBRA_NODE: case RIP_NODE: case RIPNG_NODE: @@ -1661,24 +1663,82 @@ static struct vty *vty_create(int vty_sock, union sockunion *su) /* create vty for stdio */ static struct termios stdio_orig_termios; static struct vty *stdio_vty = NULL; -static void (*stdio_vty_atclose)(void); +static bool stdio_termios = false; +static void (*stdio_vty_atclose)(int isexit); -static void vty_stdio_reset(void) +static void vty_stdio_reset(int isexit) { if (stdio_vty) { - tcsetattr(0, TCSANOW, &stdio_orig_termios); + if (stdio_termios) + tcsetattr(0, TCSANOW, &stdio_orig_termios); + stdio_termios = false; + stdio_vty = NULL; if (stdio_vty_atclose) - stdio_vty_atclose(); + stdio_vty_atclose(isexit); stdio_vty_atclose = NULL; } } -struct vty *vty_stdio(void (*atclose)()) +static void vty_stdio_atexit(void) +{ + vty_stdio_reset(1); +} + +void vty_stdio_suspend(void) +{ + if (!stdio_vty) + return; + + if (stdio_vty->t_write) + thread_cancel(stdio_vty->t_write); + if (stdio_vty->t_read) + thread_cancel(stdio_vty->t_read); + if (stdio_vty->t_timeout) + thread_cancel(stdio_vty->t_timeout); + + if (stdio_termios) + tcsetattr(0, TCSANOW, &stdio_orig_termios); + stdio_termios = false; +} + +void vty_stdio_resume(void) +{ + if (!stdio_vty) + return; + + if (!tcgetattr(0, &stdio_orig_termios)) { + struct termios termios; + + termios = stdio_orig_termios; + termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR + | IGNCR | ICRNL | IXON); + termios.c_oflag &= ~OPOST; + termios.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN); + termios.c_cflag &= ~(CSIZE | PARENB); + termios.c_cflag |= CS8; + tcsetattr(0, TCSANOW, &termios); + stdio_termios = true; + } + + vty_prompt(stdio_vty); + + /* Add read/write thread. */ + vty_event(VTY_WRITE, 1, stdio_vty); + vty_event(VTY_READ, 0, stdio_vty); +} + +void vty_stdio_close(void) +{ + if (!stdio_vty) + return; + vty_close(stdio_vty); +} + +struct vty *vty_stdio(void (*atclose)(int isexit)) { struct vty *vty; - struct termios termios; /* refuse creating two vtys on stdio */ if (stdio_vty) @@ -1696,23 +1756,7 @@ struct vty *vty_stdio(void (*atclose)()) vty->v_timeout = 0; strcpy(vty->address, "console"); - if (!tcgetattr(0, &stdio_orig_termios)) { - termios = stdio_orig_termios; - termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR - | IGNCR | ICRNL | IXON); - termios.c_oflag &= ~OPOST; - termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); - termios.c_cflag &= ~(CSIZE | PARENB); - termios.c_cflag |= CS8; - tcsetattr(0, TCSANOW, &termios); - } - - vty_prompt(vty); - - /* Add read/write thread. */ - vty_event(VTY_WRITE, 1, vty); - vty_event(VTY_READ, 0, vty); - + vty_stdio_resume(); return vty; } @@ -1811,7 +1855,7 @@ static void vty_serv_sock_addrinfo(const char *hostname, unsigned short port) ret = getaddrinfo(hostname, port_str, &req, &ainfo); if (ret != 0) { - fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(ret)); + zlog_err("getaddrinfo failed: %s", gai_strerror(ret)); exit(1); } @@ -2161,7 +2205,7 @@ void vty_close(struct vty *vty) XFREE(MTYPE_VTY, vty); if (was_stdio) - vty_stdio_reset(); + vty_stdio_reset(0); } /* When time out occur output message then close connection. */ @@ -2211,23 +2255,22 @@ static void vty_read_file(FILE *confp) if (!((ret == CMD_SUCCESS) || (ret == CMD_ERR_NOTHING_TODO))) { const char *message = NULL; + char *nl; + switch (ret) { case CMD_ERR_AMBIGUOUS: - message = - "*** Error reading config: Ambiguous command."; + message = "Ambiguous command"; break; case CMD_ERR_NO_MATCH: - message = - "*** Error reading config: There is no such command."; + message = "No such command"; break; } - fprintf(stderr, "%s\n", message); - zlog_err("%s", message); - fprintf(stderr, - "*** Error occurred processing line %u, below:\n%s\n", - line_num, vty->error_buf); - zlog_err("*** Error occurred processing line %u, below:\n%s", - line_num, vty->error_buf); + + nl = strchr(vty->error_buf, '\n'); + if (nl) + *nl = '\0'; + zlog_err("ERROR: %s on config line %u: %s", + message, line_num, vty->error_buf); } vty_close(vty); @@ -2299,8 +2342,7 @@ void vty_read_config(const char *config_file, char *config_default_dir) if (config_file != NULL) { if (!IS_DIRECTORY_SEP(config_file[0])) { if (getcwd(cwd, MAXPATHLEN) == NULL) { - fprintf(stderr, - "Failure to determine Current Working Directory %d!\n", + zlog_err("Failure to determine Current Working Directory %d!", errno); exit(1); } @@ -2314,17 +2356,14 @@ void vty_read_config(const char *config_file, char *config_default_dir) confp = fopen(fullpath, "r"); if (confp == NULL) { - fprintf(stderr, - "%s: failed to open configuration file %s: %s\n", + zlog_err("%s: failed to open configuration file %s: %s", __func__, fullpath, safe_strerror(errno)); confp = vty_use_backup_config(fullpath); if (confp) - fprintf(stderr, - "WARNING: using backup configuration file!\n"); + zlog_warn("WARNING: using backup configuration file!"); else { - fprintf(stderr, - "can't open configuration file [%s]\n", + zlog_err("can't open configuration file [%s]", config_file); exit(1); } @@ -2359,19 +2398,16 @@ void vty_read_config(const char *config_file, char *config_default_dir) #endif /* VTYSH */ confp = fopen(config_default_dir, "r"); if (confp == NULL) { - fprintf(stderr, - "%s: failed to open configuration file %s: %s\n", + zlog_err("%s: failed to open configuration file %s: %s", __func__, config_default_dir, safe_strerror(errno)); confp = vty_use_backup_config(config_default_dir); if (confp) { - fprintf(stderr, - "WARNING: using backup configuration file!\n"); + zlog_warn("WARNING: using backup configuration file!"); fullpath = config_default_dir; } else { - fprintf(stderr, - "can't open configuration file [%s]\n", + zlog_err("can't open configuration file [%s]", config_default_dir); goto tmp_free_and_out; } @@ -2881,12 +2917,12 @@ static void vty_save_cwd(void) * Hence not worrying about it too much. */ if (!chdir(SYSCONFDIR)) { - fprintf(stderr, "Failure to chdir to %s, errno: %d\n", + zlog_err("Failure to chdir to %s, errno: %d", SYSCONFDIR, errno); exit(-1); } if (getcwd(cwd, MAXPATHLEN) == NULL) { - fprintf(stderr, "Failure to getcwd, errno: %d\n", + zlog_err("Failure to getcwd, errno: %d", errno); exit(-1); } @@ -2926,7 +2962,7 @@ void vty_init(struct thread_master *master_thread) vty_master = master_thread; - atexit(vty_stdio_reset); + atexit(vty_stdio_atexit); /* Initilize server thread vector. */ Vvty_serv_thread = vector_init(VECTOR_MIN_SIZE); @@ -257,7 +257,7 @@ extern void vty_init_vtysh(void); extern void vty_terminate(void); extern void vty_reset(void); extern struct vty *vty_new(void); -extern struct vty *vty_stdio(void (*atclose)(void)); +extern struct vty *vty_stdio(void (*atclose)(int isexit)); extern int vty_out(struct vty *, const char *, ...) PRINTF_ATTRIBUTE(2, 3); extern void vty_read_config(const char *, char *); extern void vty_time_print(struct vty *, int); @@ -273,6 +273,11 @@ extern int vty_shell(struct vty *); extern int vty_shell_serv(struct vty *); extern void vty_hello(struct vty *); +/* ^Z / SIGTSTP handling */ +extern void vty_stdio_suspend(void); +extern void vty_stdio_resume(void); +extern void vty_stdio_close(void); + /* Send a fixed-size message to all vty terminal monitors; this should be an async-signal-safe function. */ extern void vty_log_fixed(char *buf, size_t len); diff --git a/lib/zclient.c b/lib/zclient.c index 233d0359d5..24cb699196 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1778,6 +1778,69 @@ int lm_release_label_chunk(struct zclient *zclient, uint32_t start, return 0; } +int zebra_send_pw(struct zclient *zclient, int command, struct zapi_pw *pw) +{ + struct stream *s; + + /* Reset stream. */ + s = zclient->obuf; + stream_reset(s); + + zclient_create_header(s, command, VRF_DEFAULT); + stream_write(s, pw->ifname, IF_NAMESIZE); + stream_putl(s, pw->ifindex); + + /* Put type */ + stream_putl(s, pw->type); + + /* Put nexthop */ + stream_putl(s, pw->af); + switch (pw->af) { + case AF_INET: + stream_put_in_addr(s, &pw->nexthop.ipv4); + break; + case AF_INET6: + stream_write(s, (u_char *)&pw->nexthop.ipv6, 16); + break; + default: + zlog_err("%s: unknown af", __func__); + return -1; + } + + /* Put labels */ + stream_putl(s, pw->local_label); + stream_putl(s, pw->remote_label); + + /* Put flags */ + stream_putc(s, pw->flags); + + /* Protocol specific fields */ + stream_write(s, &pw->data, sizeof(union pw_protocol_fields)); + + /* Put length at the first point of the stream. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + return zclient_send_message(zclient); +} + +/* + * Receive PW status update from Zebra and send it to LDE process. + */ +void zebra_read_pw_status_update(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id, + struct zapi_pw_status *pw) +{ + struct stream *s; + + memset(pw, 0, sizeof(struct zapi_pw_status)); + s = zclient->ibuf; + + /* Get data. */ + stream_get(pw->ifname, s, IF_NAMESIZE); + pw->ifindex = stream_getl(s); + pw->status = stream_getl(s); +} + /* Zebra client message read function. */ static int zclient_read(struct thread *thread) { @@ -2005,6 +2068,11 @@ static int zclient_read(struct thread *thread) (*zclient->local_macip_del)(command, zclient, length, vrf_id); break; + case ZEBRA_PW_STATUS_UPDATE: + if (zclient->pw_status_update) + (*zclient->pw_status_update)(command, zclient, length, + vrf_id); + break; default: break; } diff --git a/lib/zclient.h b/lib/zclient.h index 2752acc281..5edb56f517 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -30,6 +30,12 @@ /* For vrf_bitmap_t. */ #include "vrf.h" +/* For union g_addr */ +#include "nexthop.h" + +/* For union pw_protocol_fields */ +#include "pw.h" + /* For input/output buffer to zebra. */ #define ZEBRA_MAX_PACKET_SIZ 4096 @@ -114,6 +120,11 @@ typedef enum { ZEBRA_MACIP_DEL, ZEBRA_REMOTE_MACIP_ADD, ZEBRA_REMOTE_MACIP_DEL, + ZEBRA_PW_ADD, + ZEBRA_PW_DELETE, + ZEBRA_PW_SET, + ZEBRA_PW_UNSET, + ZEBRA_PW_STATUS_UPDATE, } zebra_message_types_t; struct redist_proto { @@ -195,6 +206,7 @@ struct zclient { int (*local_vni_del)(int, struct zclient *, uint16_t, vrf_id_t); int (*local_macip_add)(int, struct zclient *, uint16_t, vrf_id_t); int (*local_macip_del)(int, struct zclient *, uint16_t, vrf_id_t); + int (*pw_status_update)(int, struct zclient *, uint16_t, vrf_id_t); }; /* Zebra API message flag. */ @@ -274,6 +286,25 @@ struct zapi_ipv4 { vrf_id_t vrf_id; }; +struct zapi_pw { + char ifname[IF_NAMESIZE]; + ifindex_t ifindex; + int type; + int af; + union g_addr nexthop; + uint32_t local_label; + uint32_t remote_label; + uint8_t flags; + union pw_protocol_fields data; + uint8_t protocol; +}; + +struct zapi_pw_status { + char ifname[IF_NAMESIZE]; + ifindex_t ifindex; + uint32_t status; +}; + /* Prototypes of zebra client service functions. */ extern struct zclient *zclient_new(struct thread_master *); extern void zclient_init(struct zclient *, int, u_short); @@ -344,6 +375,12 @@ extern int lm_get_label_chunk(struct zclient *zclient, u_char keep, uint32_t *end); extern int lm_release_label_chunk(struct zclient *zclient, uint32_t start, uint32_t end); +extern int zebra_send_pw(struct zclient *zclient, int command, + struct zapi_pw *pw); +extern void zebra_read_pw_status_update(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id, + struct zapi_pw_status *pw); + /* IPv6 prefix add and delete function prototype. */ struct zapi_ipv6 { |
