From 0b4d8f1e38ea1dbade4d2f714775608b379e992e Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Tue, 18 Apr 2017 12:04:44 -0300 Subject: [PATCH 01/16] ldpd: split log.c into two files This is basically to keep in sync with OpenBSD's ldpd(8) where the same change was done. Signed-off-by: Renato Westphal --- ldpd/Makefile.am | 2 +- ldpd/lde.c | 1 + ldpd/ldpd.c | 1 + ldpd/ldpd.h | 30 +++ ldpd/ldpe.c | 1 + ldpd/log.c | 477 +--------------------------------------------- ldpd/log.h | 66 +++---- ldpd/logmsg.c | 487 +++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 549 insertions(+), 516 deletions(-) create mode 100644 ldpd/logmsg.c diff --git a/ldpd/Makefile.am b/ldpd/Makefile.am index 19f819ae36..b760b44573 100644 --- a/ldpd/Makefile.am +++ b/ldpd/Makefile.am @@ -16,7 +16,7 @@ EXTRA_DIST += ldp_vty.xml libldp_a_SOURCES = \ accept.c address.c adjacency.c control.c hello.c init.c interface.c \ keepalive.c l2vpn.c labelmapping.c lde.c lde_lib.c ldpd.c \ - ldpe.c log.c neighbor.c notification.c packet.c pfkey.c \ + ldpe.c log.c logmsg.c neighbor.c notification.c packet.c pfkey.c \ socket.c util.c ldp_vty_cmds.c ldp_vty_conf.c ldp_vty_exec.c \ ldp_debug.c ldp_zebra.c diff --git a/ldpd/lde.c b/ldpd/lde.c index 36998e7cf8..c4a610b6d3 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -163,6 +163,7 @@ lde(const char *user, const char *group, u_short instance) setproctitle("label decision engine"); #endif ldpd_process = PROC_LDE_ENGINE; + log_procname = log_procnames[PROC_LDE_ENGINE]; /* drop privileges */ if (user) diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index def3d2e2f3..8da830ccef 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -208,6 +208,7 @@ main(int argc, char *argv[]) const char *instance_char = NULL; ldpd_process = PROC_MAIN; + log_procname = log_procnames[ldpd_process]; saved_argv0 = argv[0]; if (saved_argv0 == NULL) diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h index 10742cf0dc..759f1d0da5 100644 --- a/ldpd/ldpd.h +++ b/ldpd/ldpd.h @@ -439,6 +439,12 @@ enum ldpd_process { PROC_LDE_ENGINE } ldpd_process; +static const char * const log_procnames[] = { + "parent", + "ldpe", + "lde" +}; + enum socket_type { LDP_SOCKET_DISC, LDP_SOCKET_EDISC, @@ -762,6 +768,30 @@ int sock_set_ipv6_mcast_hops(int, int); int sock_set_ipv6_mcast(struct iface *); int sock_set_ipv6_mcast_loop(int); +/* logmsg.h */ +struct in6_addr; +union ldpd_addr; +struct hello_source; +struct fec; + +const char *log_sockaddr(void *); +const char *log_in6addr(const struct in6_addr *); +const char *log_in6addr_scope(const struct in6_addr *, unsigned int); +const char *log_addr(int, const union ldpd_addr *); +char *log_label(uint32_t); +const char *log_time(time_t); +char *log_hello_src(const struct hello_source *); +const char *log_map(const struct map *); +const char *log_fec(const struct fec *); +const char *af_name(int); +const char *socket_name(int); +const char *nbr_state_name(int); +const char *if_state_name(int); +const char *if_type_name(enum iface_type); +const char *msg_name(uint16_t); +const char *status_code_name(uint32_t); +const char *pw_type_name(uint16_t); + /* quagga */ extern struct thread_master *master; extern char ctl_sock_path[MAXPATHLEN]; diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c index 1bec3d2a95..e82416276b 100644 --- a/ldpd/ldpe.c +++ b/ldpd/ldpe.c @@ -113,6 +113,7 @@ ldpe(const char *user, const char *group, const char *ctl_path) setproctitle("ldp engine"); #endif ldpd_process = PROC_LDP_ENGINE; + log_procname = log_procnames[ldpd_process]; LIST_INIT(&global.addr_list); RB_INIT(&global.adj_tree); diff --git a/ldpd/log.c b/ldpd/log.c index 407668bb03..408aaeb699 100644 --- a/ldpd/log.c +++ b/ldpd/log.c @@ -25,15 +25,8 @@ #include #include -#include "mpls.h" -static const char * const procnames[] = { - "parent", - "ldpe", - "lde" -}; - -void vlog(int, const char *, va_list); +const char *log_procname; void logit(int pri, const char *fmt, ...) @@ -133,15 +126,15 @@ void fatal(const char *emsg) { if (emsg == NULL) - logit(LOG_CRIT, "fatal in %s: %s", procnames[ldpd_process], + logit(LOG_CRIT, "fatal in %s: %s", log_procname, strerror(errno)); else if (errno) logit(LOG_CRIT, "fatal in %s: %s: %s", - procnames[ldpd_process], emsg, strerror(errno)); + log_procname, emsg, strerror(errno)); else logit(LOG_CRIT, "fatal in %s: %s", - procnames[ldpd_process], emsg); + log_procname, emsg); exit(1); } @@ -152,465 +145,3 @@ fatalx(const char *emsg) errno = 0; fatal(emsg); } - -#define NUM_LOGS 4 -const char * -log_sockaddr(void *vp) -{ - static char buf[NUM_LOGS][NI_MAXHOST]; - static int round = 0; - struct sockaddr *sa = vp; - - round = (round + 1) % NUM_LOGS; - - if (getnameinfo(sa, sockaddr_len(sa), buf[round], NI_MAXHOST, NULL, 0, - NI_NUMERICHOST)) - return ("(unknown)"); - else - return (buf[round]); -} - -const char * -log_in6addr(const struct in6_addr *addr) -{ - struct sockaddr_in6 sa_in6; - - memset(&sa_in6, 0, sizeof(sa_in6)); -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - sa_in6.sin6_len = sizeof(sa_in6); -#endif - sa_in6.sin6_family = AF_INET6; - sa_in6.sin6_addr = *addr; - - recoverscope(&sa_in6); - - return (log_sockaddr(&sa_in6)); -} - -const char * -log_in6addr_scope(const struct in6_addr *addr, unsigned int ifindex) -{ - struct sockaddr_in6 sa_in6; - - memset(&sa_in6, 0, sizeof(sa_in6)); -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - sa_in6.sin6_len = sizeof(sa_in6); -#endif - sa_in6.sin6_family = AF_INET6; - sa_in6.sin6_addr = *addr; - - addscope(&sa_in6, ifindex); - - return (log_sockaddr(&sa_in6)); -} - -const char * -log_addr(int af, const union ldpd_addr *addr) -{ - static char buf[NUM_LOGS][INET6_ADDRSTRLEN]; - static int round = 0; - - switch (af) { - case AF_INET: - round = (round + 1) % NUM_LOGS; - if (inet_ntop(AF_INET, &addr->v4, buf[round], - sizeof(buf[round])) == NULL) - return ("???"); - return (buf[round]); - case AF_INET6: - return (log_in6addr(&addr->v6)); - default: - break; - } - - return ("???"); -} - -#define TF_BUFS 4 -#define TF_LEN 32 - -char * -log_label(uint32_t label) -{ - char *buf; - static char tfbuf[TF_BUFS][TF_LEN]; /* ring buffer */ - static int idx = 0; - - buf = tfbuf[idx++]; - if (idx == TF_BUFS) - idx = 0; - - switch (label) { - case NO_LABEL: - snprintf(buf, TF_LEN, "-"); - break; - case MPLS_LABEL_IMPLNULL: - snprintf(buf, TF_LEN, "imp-null"); - break; - case MPLS_LABEL_IPV4NULL: - case MPLS_LABEL_IPV6NULL: - snprintf(buf, TF_LEN, "exp-null"); - break; - default: - snprintf(buf, TF_LEN, "%u", label); - break; - } - - return (buf); -} - -const char * -log_time(time_t t) -{ - char *buf; - static char tfbuf[TF_BUFS][TF_LEN]; /* ring buffer */ - static int idx = 0; - unsigned int sec, min, hrs, day, week; - - buf = tfbuf[idx++]; - if (idx == TF_BUFS) - idx = 0; - - week = t; - - sec = week % 60; - week /= 60; - min = week % 60; - week /= 60; - hrs = week % 24; - week /= 24; - day = week % 7; - week /= 7; - - if (week > 0) - snprintf(buf, TF_LEN, "%02uw%01ud%02uh", week, day, hrs); - else if (day > 0) - snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min); - else - snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec); - - return (buf); -} - -char * -log_hello_src(const struct hello_source *src) -{ - static char buf[64]; - - switch (src->type) { - case HELLO_LINK: - snprintf(buf, sizeof(buf), "iface %s", - src->link.ia->iface->name); - break; - case HELLO_TARGETED: - snprintf(buf, sizeof(buf), "source %s", - log_addr(src->target->af, &src->target->addr)); - break; - } - - return (buf); -} - -const char * -log_map(const struct map *map) -{ - static char buf[128]; - - switch (map->type) { - case MAP_TYPE_WILDCARD: - if (snprintf(buf, sizeof(buf), "wildcard") < 0) - return ("???"); - break; - case MAP_TYPE_PREFIX: - if (snprintf(buf, sizeof(buf), "%s/%u", - log_addr(map->fec.prefix.af, &map->fec.prefix.prefix), - map->fec.prefix.prefixlen) == -1) - return ("???"); - break; - case MAP_TYPE_PWID: - if (snprintf(buf, sizeof(buf), "pw-id %u group-id %u (%s)", - map->fec.pwid.pwid, map->fec.pwid.group_id, - pw_type_name(map->fec.pwid.type)) == -1) - return ("???"); - break; - case MAP_TYPE_TYPED_WCARD: - if (snprintf(buf, sizeof(buf), "typed wildcard") < 0) - return ("???"); - switch (map->fec.twcard.type) { - case MAP_TYPE_PREFIX: - if (snprintf(buf + strlen(buf), sizeof(buf) - - strlen(buf), " (prefix, address-family %s)", - af_name(map->fec.twcard.u.prefix_af)) < 0) - return ("???"); - break; - case MAP_TYPE_PWID: - if (snprintf(buf + strlen(buf), sizeof(buf) - - strlen(buf), " (pwid, type %s)", - pw_type_name(map->fec.twcard.u.pw_type)) < 0) - return ("???"); - break; - default: - if (snprintf(buf + strlen(buf), sizeof(buf) - - strlen(buf), " (unknown type)") < 0) - return ("???"); - break; - } - break; - default: - return ("???"); - } - - return (buf); -} - -const char * -log_fec(const struct fec *fec) -{ - static char buf[64]; - union ldpd_addr addr; - - switch (fec->type) { - case FEC_TYPE_IPV4: - addr.v4 = fec->u.ipv4.prefix; - if (snprintf(buf, sizeof(buf), "ipv4 %s/%u", - log_addr(AF_INET, &addr), fec->u.ipv4.prefixlen) == -1) - return ("???"); - break; - case FEC_TYPE_IPV6: - addr.v6 = fec->u.ipv6.prefix; - if (snprintf(buf, sizeof(buf), "ipv6 %s/%u", - log_addr(AF_INET6, &addr), fec->u.ipv6.prefixlen) == -1) - return ("???"); - break; - case FEC_TYPE_PWID: - if (snprintf(buf, sizeof(buf), - "pwid %u (%s) - %s", - fec->u.pwid.pwid, pw_type_name(fec->u.pwid.type), - inet_ntoa(fec->u.pwid.lsr_id)) == -1) - return ("???"); - break; - default: - return ("???"); - } - - return (buf); -} - -/* names */ -const char * -af_name(int af) -{ - switch (af) { - case AF_INET: - return ("ipv4"); - case AF_INET6: - return ("ipv6"); -#ifdef AF_MPLS - case AF_MPLS: - return ("mpls"); -#endif - default: - return ("UNKNOWN"); - } -} - -const char * -socket_name(int type) -{ - switch (type) { - case LDP_SOCKET_DISC: - return ("discovery"); - case LDP_SOCKET_EDISC: - return ("extended discovery"); - case LDP_SOCKET_SESSION: - return ("session"); - default: - return ("UNKNOWN"); - } -} - -const char * -nbr_state_name(int state) -{ - switch (state) { - case NBR_STA_PRESENT: - return ("PRESENT"); - case NBR_STA_INITIAL: - return ("INITIALIZED"); - case NBR_STA_OPENREC: - return ("OPENREC"); - case NBR_STA_OPENSENT: - return ("OPENSENT"); - case NBR_STA_OPER: - return ("OPERATIONAL"); - default: - return ("UNKNOWN"); - } -} - -const char * -if_state_name(int state) -{ - switch (state) { - case IF_STA_DOWN: - return ("DOWN"); - case IF_STA_ACTIVE: - return ("ACTIVE"); - default: - return ("UNKNOWN"); - } -} - -const char * -if_type_name(enum iface_type type) -{ - switch (type) { - case IF_TYPE_POINTOPOINT: - return ("POINTOPOINT"); - case IF_TYPE_BROADCAST: - return ("BROADCAST"); - } - /* NOTREACHED */ - return ("UNKNOWN"); -} - -const char * -msg_name(uint16_t msg) -{ - static char buf[16]; - - switch (msg) { - case MSG_TYPE_NOTIFICATION: - return ("notification"); - case MSG_TYPE_HELLO: - return ("hello"); - case MSG_TYPE_INIT: - return ("initialization"); - case MSG_TYPE_KEEPALIVE: - return ("keepalive"); - case MSG_TYPE_CAPABILITY: - return ("capability"); - case MSG_TYPE_ADDR: - return ("address"); - case MSG_TYPE_ADDRWITHDRAW: - return ("address withdraw"); - case MSG_TYPE_LABELMAPPING: - return ("label mapping"); - case MSG_TYPE_LABELREQUEST: - return ("label request"); - case MSG_TYPE_LABELWITHDRAW: - return ("label withdraw"); - case MSG_TYPE_LABELRELEASE: - return ("label release"); - case MSG_TYPE_LABELABORTREQ: - default: - snprintf(buf, sizeof(buf), "[%08x]", msg); - return (buf); - } -} - -const char * -status_code_name(uint32_t status) -{ - static char buf[16]; - - switch (status) { - case S_SUCCESS: - return ("Success"); - case S_BAD_LDP_ID: - return ("Bad LDP Identifier"); - case S_BAD_PROTO_VER: - return ("Bad Protocol Version"); - case S_BAD_PDU_LEN: - return ("Bad PDU Length"); - case S_UNKNOWN_MSG: - return ("Unknown Message Type"); - case S_BAD_MSG_LEN: - return ("Bad Message Length"); - case S_UNKNOWN_TLV: - return ("Unknown TLV"); - case S_BAD_TLV_LEN: - return ("Bad TLV Length"); - case S_BAD_TLV_VAL: - return ("Malformed TLV Value"); - case S_HOLDTIME_EXP: - return ("Hold Timer Expired"); - case S_SHUTDOWN: - return ("Shutdown"); - case S_LOOP_DETECTED: - return ("Loop Detected"); - case S_UNKNOWN_FEC: - return ("Unknown FEC"); - case S_NO_ROUTE: - return ("No Route"); - case S_NO_LABEL_RES: - return ("No Label Resources"); - case S_AVAILABLE: - return ("Label Resources Available"); - case S_NO_HELLO: - return ("Session Rejected, No Hello"); - case S_PARM_ADV_MODE: - return ("Rejected Advertisement Mode Parameter"); - case S_MAX_PDU_LEN: - return ("Rejected Max PDU Length Parameter"); - case S_PARM_L_RANGE: - return ("Rejected Label Range Parameter"); - case S_KEEPALIVE_TMR: - return ("KeepAlive Timer Expired"); - case S_LAB_REQ_ABRT: - return ("Label Request Aborted"); - case S_MISS_MSG: - return ("Missing Message Parameters"); - case S_UNSUP_ADDR: - return ("Unsupported Address Family"); - case S_KEEPALIVE_BAD: - return ("Bad KeepAlive Time"); - case S_INTERN_ERR: - return ("Internal Error"); - case S_ILLEGAL_CBIT: - return ("Illegal C-Bit"); - case S_WRONG_CBIT: - return ("Wrong C-Bit"); - case S_INCPT_BITRATE: - return ("Incompatible bit-rate"); - case S_CEP_MISCONF: - return ("CEP-TDM mis-configuration"); - case S_PW_STATUS: - return ("PW Status"); - case S_UNASSIGN_TAI: - return ("Unassigned/Unrecognized TAI"); - case S_MISCONF_ERR: - return ("Generic Misconfiguration Error"); - case S_WITHDRAW_MTHD: - return ("Label Withdraw PW Status Method"); - case S_UNSSUPORTDCAP: - return ("Unsupported Capability"); - case S_ENDOFLIB: - return ("End-of-LIB"); - case S_TRANS_MISMTCH: - return ("Transport Connection Mismatch"); - case S_DS_NONCMPLNCE: - return ("Dual-Stack Noncompliance"); - default: - snprintf(buf, sizeof(buf), "[%08x]", status); - return (buf); - } -} - -const char * -pw_type_name(uint16_t pw_type) -{ - static char buf[64]; - - switch (pw_type) { - case PW_TYPE_ETHERNET_TAGGED: - return ("Eth Tagged"); - case PW_TYPE_ETHERNET: - return ("Ethernet"); - case PW_TYPE_WILDCARD: - return ("Wildcard"); - default: - snprintf(buf, sizeof(buf), "[%0x]", pw_type); - return (buf); - } -} diff --git a/ldpd/log.h b/ldpd/log.h index 4d6da43cac..8c236ff5fe 100644 --- a/ldpd/log.h +++ b/ldpd/log.h @@ -16,50 +16,32 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -#ifndef _LOG_H_ -#define _LOG_H_ +#ifndef LOG_H +#define LOG_H #include -struct in6_addr; -union ldpd_addr; -struct hello_source; -struct fec; +extern const char *log_procname; -void logit(int, const char *, ...) - __attribute__((__format__ (printf, 2, 3))); -void log_warn(const char *, ...) - __attribute__((__format__ (printf, 1, 2))); -void log_warnx(const char *, ...) - __attribute__((__format__ (printf, 1, 2))); -void log_info(const char *, ...) - __attribute__((__format__ (printf, 1, 2))); -void log_notice(const char *, ...) - __attribute__((__format__ (printf, 1, 2))); -void log_debug(const char *, ...) - __attribute__((__format__ (printf, 1, 2))); -void fatal(const char *) - __attribute__ ((noreturn)) - __attribute__((__format__ (printf, 1, 0))); -void fatalx(const char *) - __attribute__ ((noreturn)) - __attribute__((__format__ (printf, 1, 0))); -const char *log_sockaddr(void *); -const char *log_in6addr(const struct in6_addr *); -const char *log_in6addr_scope(const struct in6_addr *, unsigned int); -const char *log_addr(int, const union ldpd_addr *); -char *log_label(uint32_t); -const char *log_time(time_t); -char *log_hello_src(const struct hello_source *); -const char *log_map(const struct map *); -const char *log_fec(const struct fec *); -const char *af_name(int); -const char *socket_name(int); -const char *nbr_state_name(int); -const char *if_state_name(int); -const char *if_type_name(enum iface_type); -const char *msg_name(uint16_t); -const char *status_code_name(uint32_t); -const char *pw_type_name(uint16_t); +void logit(int, const char *, ...) + __attribute__((__format__ (printf, 2, 3))); +void vlog(int, const char *, va_list) + __attribute__((__format__ (printf, 2, 0))); +void log_warn(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void log_warnx(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void log_info(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void log_notice(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void log_debug(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +void fatal(const char *) + __attribute__ ((noreturn)) + __attribute__((__format__ (printf, 1, 0))); +void fatalx(const char *) + __attribute__ ((noreturn)) + __attribute__((__format__ (printf, 1, 0))); -#endif /* _LOG_H_ */ +#endif /* LOG_H */ diff --git a/ldpd/logmsg.c b/ldpd/logmsg.c new file mode 100644 index 0000000000..c819b33b43 --- /dev/null +++ b/ldpd/logmsg.c @@ -0,0 +1,487 @@ +/* $OpenBSD$ */ + +/* + * Copyright (c) 2003, 2004 Henning Brauer + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include + +#include "mpls.h" + +#include "ldpd.h" +#include "ldpe.h" +#include "lde.h" + +#define NUM_LOGS 4 +const char * +log_sockaddr(void *vp) +{ + static char buf[NUM_LOGS][NI_MAXHOST]; + static int round = 0; + struct sockaddr *sa = vp; + + round = (round + 1) % NUM_LOGS; + + if (getnameinfo(sa, sockaddr_len(sa), buf[round], NI_MAXHOST, NULL, 0, + NI_NUMERICHOST)) + return ("(unknown)"); + else + return (buf[round]); +} + +const char * +log_in6addr(const struct in6_addr *addr) +{ + struct sockaddr_in6 sa_in6; + + memset(&sa_in6, 0, sizeof(sa_in6)); +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN + sa_in6.sin6_len = sizeof(sa_in6); +#endif + sa_in6.sin6_family = AF_INET6; + sa_in6.sin6_addr = *addr; + + recoverscope(&sa_in6); + + return (log_sockaddr(&sa_in6)); +} + +const char * +log_in6addr_scope(const struct in6_addr *addr, unsigned int ifindex) +{ + struct sockaddr_in6 sa_in6; + + memset(&sa_in6, 0, sizeof(sa_in6)); +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN + sa_in6.sin6_len = sizeof(sa_in6); +#endif + sa_in6.sin6_family = AF_INET6; + sa_in6.sin6_addr = *addr; + + addscope(&sa_in6, ifindex); + + return (log_sockaddr(&sa_in6)); +} + +const char * +log_addr(int af, const union ldpd_addr *addr) +{ + static char buf[NUM_LOGS][INET6_ADDRSTRLEN]; + static int round = 0; + + switch (af) { + case AF_INET: + round = (round + 1) % NUM_LOGS; + if (inet_ntop(AF_INET, &addr->v4, buf[round], + sizeof(buf[round])) == NULL) + return ("???"); + return (buf[round]); + case AF_INET6: + return (log_in6addr(&addr->v6)); + default: + break; + } + + return ("???"); +} + +#define TF_BUFS 4 +#define TF_LEN 32 + +char * +log_label(uint32_t label) +{ + char *buf; + static char tfbuf[TF_BUFS][TF_LEN]; /* ring buffer */ + static int idx = 0; + + buf = tfbuf[idx++]; + if (idx == TF_BUFS) + idx = 0; + + switch (label) { + case NO_LABEL: + snprintf(buf, TF_LEN, "-"); + break; + case MPLS_LABEL_IMPLNULL: + snprintf(buf, TF_LEN, "imp-null"); + break; + case MPLS_LABEL_IPV4NULL: + case MPLS_LABEL_IPV6NULL: + snprintf(buf, TF_LEN, "exp-null"); + break; + default: + snprintf(buf, TF_LEN, "%u", label); + break; + } + + return (buf); +} + +const char * +log_time(time_t t) +{ + char *buf; + static char tfbuf[TF_BUFS][TF_LEN]; /* ring buffer */ + static int idx = 0; + unsigned int sec, min, hrs, day, week; + + buf = tfbuf[idx++]; + if (idx == TF_BUFS) + idx = 0; + + week = t; + + sec = week % 60; + week /= 60; + min = week % 60; + week /= 60; + hrs = week % 24; + week /= 24; + day = week % 7; + week /= 7; + + if (week > 0) + snprintf(buf, TF_LEN, "%02uw%01ud%02uh", week, day, hrs); + else if (day > 0) + snprintf(buf, TF_LEN, "%01ud%02uh%02um", day, hrs, min); + else + snprintf(buf, TF_LEN, "%02u:%02u:%02u", hrs, min, sec); + + return (buf); +} + +char * +log_hello_src(const struct hello_source *src) +{ + static char buf[64]; + + switch (src->type) { + case HELLO_LINK: + snprintf(buf, sizeof(buf), "iface %s", + src->link.ia->iface->name); + break; + case HELLO_TARGETED: + snprintf(buf, sizeof(buf), "source %s", + log_addr(src->target->af, &src->target->addr)); + break; + } + + return (buf); +} + +const char * +log_map(const struct map *map) +{ + static char buf[128]; + + switch (map->type) { + case MAP_TYPE_WILDCARD: + if (snprintf(buf, sizeof(buf), "wildcard") < 0) + return ("???"); + break; + case MAP_TYPE_PREFIX: + if (snprintf(buf, sizeof(buf), "%s/%u", + log_addr(map->fec.prefix.af, &map->fec.prefix.prefix), + map->fec.prefix.prefixlen) == -1) + return ("???"); + break; + case MAP_TYPE_PWID: + if (snprintf(buf, sizeof(buf), "pw-id %u group-id %u (%s)", + map->fec.pwid.pwid, map->fec.pwid.group_id, + pw_type_name(map->fec.pwid.type)) == -1) + return ("???"); + break; + case MAP_TYPE_TYPED_WCARD: + if (snprintf(buf, sizeof(buf), "typed wildcard") < 0) + return ("???"); + switch (map->fec.twcard.type) { + case MAP_TYPE_PREFIX: + if (snprintf(buf + strlen(buf), sizeof(buf) - + strlen(buf), " (prefix, address-family %s)", + af_name(map->fec.twcard.u.prefix_af)) < 0) + return ("???"); + break; + case MAP_TYPE_PWID: + if (snprintf(buf + strlen(buf), sizeof(buf) - + strlen(buf), " (pwid, type %s)", + pw_type_name(map->fec.twcard.u.pw_type)) < 0) + return ("???"); + break; + default: + if (snprintf(buf + strlen(buf), sizeof(buf) - + strlen(buf), " (unknown type)") < 0) + return ("???"); + break; + } + break; + default: + return ("???"); + } + + return (buf); +} + +const char * +log_fec(const struct fec *fec) +{ + static char buf[64]; + union ldpd_addr addr; + + switch (fec->type) { + case FEC_TYPE_IPV4: + addr.v4 = fec->u.ipv4.prefix; + if (snprintf(buf, sizeof(buf), "ipv4 %s/%u", + log_addr(AF_INET, &addr), fec->u.ipv4.prefixlen) == -1) + return ("???"); + break; + case FEC_TYPE_IPV6: + addr.v6 = fec->u.ipv6.prefix; + if (snprintf(buf, sizeof(buf), "ipv6 %s/%u", + log_addr(AF_INET6, &addr), fec->u.ipv6.prefixlen) == -1) + return ("???"); + break; + case FEC_TYPE_PWID: + if (snprintf(buf, sizeof(buf), + "pwid %u (%s) - %s", + fec->u.pwid.pwid, pw_type_name(fec->u.pwid.type), + inet_ntoa(fec->u.pwid.lsr_id)) == -1) + return ("???"); + break; + default: + return ("???"); + } + + return (buf); +} + +/* names */ +const char * +af_name(int af) +{ + switch (af) { + case AF_INET: + return ("ipv4"); + case AF_INET6: + return ("ipv6"); +#ifdef AF_MPLS + case AF_MPLS: + return ("mpls"); +#endif + default: + return ("UNKNOWN"); + } +} + +const char * +socket_name(int type) +{ + switch (type) { + case LDP_SOCKET_DISC: + return ("discovery"); + case LDP_SOCKET_EDISC: + return ("extended discovery"); + case LDP_SOCKET_SESSION: + return ("session"); + default: + return ("UNKNOWN"); + } +} + +const char * +nbr_state_name(int state) +{ + switch (state) { + case NBR_STA_PRESENT: + return ("PRESENT"); + case NBR_STA_INITIAL: + return ("INITIALIZED"); + case NBR_STA_OPENREC: + return ("OPENREC"); + case NBR_STA_OPENSENT: + return ("OPENSENT"); + case NBR_STA_OPER: + return ("OPERATIONAL"); + default: + return ("UNKNOWN"); + } +} + +const char * +if_state_name(int state) +{ + switch (state) { + case IF_STA_DOWN: + return ("DOWN"); + case IF_STA_ACTIVE: + return ("ACTIVE"); + default: + return ("UNKNOWN"); + } +} + +const char * +if_type_name(enum iface_type type) +{ + switch (type) { + case IF_TYPE_POINTOPOINT: + return ("POINTOPOINT"); + case IF_TYPE_BROADCAST: + return ("BROADCAST"); + } + /* NOTREACHED */ + return ("UNKNOWN"); +} + +const char * +msg_name(uint16_t msg) +{ + static char buf[16]; + + switch (msg) { + case MSG_TYPE_NOTIFICATION: + return ("notification"); + case MSG_TYPE_HELLO: + return ("hello"); + case MSG_TYPE_INIT: + return ("initialization"); + case MSG_TYPE_KEEPALIVE: + return ("keepalive"); + case MSG_TYPE_CAPABILITY: + return ("capability"); + case MSG_TYPE_ADDR: + return ("address"); + case MSG_TYPE_ADDRWITHDRAW: + return ("address withdraw"); + case MSG_TYPE_LABELMAPPING: + return ("label mapping"); + case MSG_TYPE_LABELREQUEST: + return ("label request"); + case MSG_TYPE_LABELWITHDRAW: + return ("label withdraw"); + case MSG_TYPE_LABELRELEASE: + return ("label release"); + case MSG_TYPE_LABELABORTREQ: + default: + snprintf(buf, sizeof(buf), "[%08x]", msg); + return (buf); + } +} + +const char * +status_code_name(uint32_t status) +{ + static char buf[16]; + + switch (status) { + case S_SUCCESS: + return ("Success"); + case S_BAD_LDP_ID: + return ("Bad LDP Identifier"); + case S_BAD_PROTO_VER: + return ("Bad Protocol Version"); + case S_BAD_PDU_LEN: + return ("Bad PDU Length"); + case S_UNKNOWN_MSG: + return ("Unknown Message Type"); + case S_BAD_MSG_LEN: + return ("Bad Message Length"); + case S_UNKNOWN_TLV: + return ("Unknown TLV"); + case S_BAD_TLV_LEN: + return ("Bad TLV Length"); + case S_BAD_TLV_VAL: + return ("Malformed TLV Value"); + case S_HOLDTIME_EXP: + return ("Hold Timer Expired"); + case S_SHUTDOWN: + return ("Shutdown"); + case S_LOOP_DETECTED: + return ("Loop Detected"); + case S_UNKNOWN_FEC: + return ("Unknown FEC"); + case S_NO_ROUTE: + return ("No Route"); + case S_NO_LABEL_RES: + return ("No Label Resources"); + case S_AVAILABLE: + return ("Label Resources Available"); + case S_NO_HELLO: + return ("Session Rejected, No Hello"); + case S_PARM_ADV_MODE: + return ("Rejected Advertisement Mode Parameter"); + case S_MAX_PDU_LEN: + return ("Rejected Max PDU Length Parameter"); + case S_PARM_L_RANGE: + return ("Rejected Label Range Parameter"); + case S_KEEPALIVE_TMR: + return ("KeepAlive Timer Expired"); + case S_LAB_REQ_ABRT: + return ("Label Request Aborted"); + case S_MISS_MSG: + return ("Missing Message Parameters"); + case S_UNSUP_ADDR: + return ("Unsupported Address Family"); + case S_KEEPALIVE_BAD: + return ("Bad KeepAlive Time"); + case S_INTERN_ERR: + return ("Internal Error"); + case S_ILLEGAL_CBIT: + return ("Illegal C-Bit"); + case S_WRONG_CBIT: + return ("Wrong C-Bit"); + case S_INCPT_BITRATE: + return ("Incompatible bit-rate"); + case S_CEP_MISCONF: + return ("CEP-TDM mis-configuration"); + case S_PW_STATUS: + return ("PW Status"); + case S_UNASSIGN_TAI: + return ("Unassigned/Unrecognized TAI"); + case S_MISCONF_ERR: + return ("Generic Misconfiguration Error"); + case S_WITHDRAW_MTHD: + return ("Label Withdraw PW Status Method"); + case S_UNSSUPORTDCAP: + return ("Unsupported Capability"); + case S_ENDOFLIB: + return ("End-of-LIB"); + case S_TRANS_MISMTCH: + return ("Transport Connection Mismatch"); + case S_DS_NONCMPLNCE: + return ("Dual-Stack Noncompliance"); + default: + snprintf(buf, sizeof(buf), "[%08x]", status); + return (buf); + } +} + +const char * +pw_type_name(uint16_t pw_type) +{ + static char buf[64]; + + switch (pw_type) { + case PW_TYPE_ETHERNET_TAGGED: + return ("Eth Tagged"); + case PW_TYPE_ETHERNET: + return ("Ethernet"); + case PW_TYPE_WILDCARD: + return ("Wildcard"); + default: + snprintf(buf, sizeof(buf), "[%0x]", pw_type); + return (buf); + } +} From 9785dbcbca1a09806217e20b033a71789a89623b Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Tue, 18 Apr 2017 12:14:15 -0300 Subject: [PATCH 02/16] ldpd: fix log level of log_warn() and log_warnx() The log_warn() and log_warnx() functions indicate non-critical warnings and errors, so use LOG_ERR instead of LOG_CRIT. Keep using LOG_CRIT only in fatal() and fatalx() since these functions indicate critical errors (when the program needs to exit). Signed-off-by: Renato Westphal --- ldpd/log.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ldpd/log.c b/ldpd/log.c index 408aaeb699..fc8c995ba3 100644 --- a/ldpd/log.c +++ b/ldpd/log.c @@ -66,16 +66,16 @@ log_warn(const char *emsg, ...) /* best effort to even work in out of memory situations */ if (emsg == NULL) - logit(LOG_CRIT, "%s", strerror(errno)); + logit(LOG_ERR, "%s", strerror(errno)); else { va_start(ap, emsg); if (asprintf(&nfmt, "%s: %s", emsg, strerror(errno)) == -1) { /* we tried it... */ - vlog(LOG_CRIT, emsg, ap); - logit(LOG_CRIT, "%s", strerror(errno)); + vlog(LOG_ERR, emsg, ap); + logit(LOG_ERR, "%s", strerror(errno)); } else { - vlog(LOG_CRIT, nfmt, ap); + vlog(LOG_ERR, nfmt, ap); free(nfmt); } va_end(ap); @@ -88,7 +88,7 @@ log_warnx(const char *emsg, ...) va_list ap; va_start(ap, emsg); - vlog(LOG_CRIT, emsg, ap); + vlog(LOG_ERR, emsg, ap); va_end(ap); } From e0d7c8996d6fe3bc39a1b9fd0310f17ff272ec1a Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Tue, 18 Apr 2017 12:17:30 -0300 Subject: [PATCH 03/16] ldpd: call openzlog() in the child processes as well Signed-off-by: Renato Westphal --- ldpd/ldpd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index 8da830ccef..5fbdf52ec2 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -282,14 +282,14 @@ main(int argc, char *argv[]) exit(1); } + openzlog(ldpd_di.progname, "LDP", 0, + LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON); + if (lflag) lde(user, group, instance); else if (eflag) ldpe(user, group, ctl_sock_path); - openzlog(ldpd_di.progname, "LDP", 0, - LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON); - if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_parent2ldpe) == -1) fatal("socketpair"); if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, From e75f810c2f6d3322e981c3e50f7d87f181005461 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Tue, 18 Apr 2017 22:03:35 -0300 Subject: [PATCH 04/16] ldpd: simplify initialization of the child processes In order to have separate ASLR/cookies per process, ldpd calls exec() in the child processes after fork() (this is also known as the fork+exec model). This is an important security feature but it makes the initialization of the child processes a bit more complicated as they're not a copy of the parent anymore, so all parameters given via command line are lost. To solve this problem, we were creating an argv array by hand with all necessary parameters and providing it to the exec() syscall. This works but it's a very ugly solution. This patch introduces a different approach to solve the problem: send an IMSG_INIT message to the child processes with all parameters they need in order to initialize properly. This makes adding additional initialization parameters much more convenient and less error prone. Signed-off-by: Renato Westphal Conflicts: ldpd/ldpd.c ldpd/ldpd.h --- ldpd/control.c | 18 +++++------ ldpd/control.h | 4 +-- ldpd/lde.c | 60 ++++++++++++++++++++-------------- ldpd/lde.h | 3 +- ldpd/ldpd.c | 65 ++++++++++--------------------------- ldpd/ldpd.h | 13 ++++++-- ldpd/ldpe.c | 88 ++++++++++++++++++++++++++++---------------------- ldpd/ldpe.h | 3 +- 8 files changed, 127 insertions(+), 127 deletions(-) diff --git a/ldpd/control.c b/ldpd/control.c index 5c530e1b70..d40e0342c1 100644 --- a/ldpd/control.c +++ b/ldpd/control.c @@ -37,7 +37,7 @@ struct ctl_conns ctl_conns; static int control_fd; int -control_init(void) +control_init(char *path) { struct sockaddr_un s_un; int fd; @@ -51,28 +51,28 @@ control_init(void) memset(&s_un, 0, sizeof(s_un)); s_un.sun_family = AF_UNIX; - strlcpy(s_un.sun_path, ctl_sock_path, sizeof(s_un.sun_path)); + strlcpy(s_un.sun_path, path, sizeof(s_un.sun_path)); - if (unlink(ctl_sock_path) == -1) + if (unlink(path) == -1) if (errno != ENOENT) { - log_warn("%s: unlink %s", __func__, ctl_sock_path); + log_warn("%s: unlink %s", __func__, path); close(fd); return (-1); } old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); if (bind(fd, (struct sockaddr *)&s_un, sizeof(s_un)) == -1) { - log_warn("%s: bind: %s", __func__, ctl_sock_path); + log_warn("%s: bind: %s", __func__, path); close(fd); umask(old_umask); return (-1); } umask(old_umask); - if (chmod(ctl_sock_path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) { + if (chmod(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) == -1) { log_warn("%s: chmod", __func__); close(fd); - (void)unlink(ctl_sock_path); + (void)unlink(path); return (-1); } @@ -93,11 +93,11 @@ control_listen(void) } void -control_cleanup(void) +control_cleanup(char *path) { accept_del(control_fd); close(control_fd); - unlink(ctl_sock_path); + unlink(path); } /* ARGSUSED */ diff --git a/ldpd/control.h b/ldpd/control.h index 32c49fdf87..0e66a1636a 100644 --- a/ldpd/control.h +++ b/ldpd/control.h @@ -29,9 +29,9 @@ TAILQ_HEAD(ctl_conns, ctl_conn); extern struct ctl_conns ctl_conns; -int control_init(void); +int control_init(char *); int control_listen(void); -void control_cleanup(void); +void control_cleanup(char *); int control_imsg_relay(struct imsg *); #endif /* _CONTROL_H_ */ diff --git a/ldpd/lde.c b/ldpd/lde.c index c4a610b6d3..ed8274bec7 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -152,12 +152,9 @@ zclient_sync_init(u_short instance) /* label decision engine */ void -lde(const char *user, const char *group, u_short instance) +lde(void) { struct thread thread; - struct timeval now; - - ldeconf = config_new_empty(); #ifdef HAVE_SETPROCTITLE setproctitle("label decision engine"); @@ -165,18 +162,6 @@ lde(const char *user, const char *group, u_short instance) ldpd_process = PROC_LDE_ENGINE; log_procname = log_procnames[PROC_LDE_ENGINE]; - /* drop privileges */ - if (user) - lde_privs.user = user; - if (group) - lde_privs.group = group; - zprivs_init(&lde_privs); - -#ifdef HAVE_PLEDGE - if (pledge("stdio recvfd unix", NULL) == -1) - fatal("pledge"); -#endif - master = thread_master_create(); /* setup signal handler */ @@ -195,21 +180,38 @@ lde(const char *user, const char *group, u_short instance) fatal(NULL); imsg_init(&iev_main_sync->ibuf, LDPD_FD_SYNC); - /* start the LIB garbage collector */ - lde_gc_start_timer(); - - gettimeofday(&now, NULL); - global.uptime = now.tv_sec; - - /* Init synchronous zclient and label list */ - zclient_sync_init(instance); - lde_label_list_init(); + /* create base configuration */ + ldeconf = config_new_empty(); /* Fetch next active thread. */ while (thread_fetch(master, &thread)) thread_call(&thread); } +void +lde_init(struct ldpd_init *init) +{ + /* drop privileges */ + if (init->user) + lde_privs.user = init->user; + if (init->group) + lde_privs.group = init->group; + zprivs_init(&lde_privs); + +#ifdef HAVE_PLEDGE + if (pledge("stdio recvfd unix", NULL) == -1) + fatal("pledge"); +#endif + + /* start the LIB garbage collector */ + lde_gc_start_timer(); + + /* Init synchronous zclient and label list */ + zclient_serv_path_set(init->zclient_serv_path); + zclient_sync_init(init->instance); + lde_label_list_init(); +} + static void lde_shutdown(void) { @@ -553,6 +555,14 @@ lde_dispatch_parent(struct thread *thread) iev_ldpe->handler_write = ldp_write_handler; iev_ldpe->ev_write = NULL; break; + case IMSG_INIT: + if (imsg.hdr.len != IMSG_HEADER_SIZE + + sizeof(struct ldpd_init)) + fatalx("INIT imsg with wrong len"); + + memcpy(&init, imsg.data, sizeof(init)); + lde_init(&init); + break; case IMSG_RECONF_CONF: if ((nconf = malloc(sizeof(struct ldpd_conf))) == NULL) diff --git a/ldpd/lde.h b/ldpd/lde.h index 57791cd1b0..3349d4ca00 100644 --- a/ldpd/lde.h +++ b/ldpd/lde.h @@ -139,7 +139,8 @@ extern struct nbr_tree lde_nbrs; extern struct thread *gc_timer; /* lde.c */ -void lde(const char *, const char *, u_short instance); +void lde(void); +void lde_init(struct ldpd_init *); int lde_imsg_compose_parent(int, pid_t, void *, uint16_t); int lde_imsg_compose_ldpe(int, uint32_t, pid_t, void *, uint16_t); int lde_acl_check(char *, int, union ldpd_addr *, uint8_t); diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index 5fbdf52ec2..bdf7097323 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -44,8 +44,7 @@ #include "libfrr.h" static void ldpd_shutdown(void); -static pid_t start_child(enum ldpd_process, char *, int, int, - const char *, const char *, const char *, const char *); +static pid_t start_child(enum ldpd_process, char *, int, int); static int main_dispatch_ldpe(struct thread *); static int main_dispatch_lde(struct thread *); static int main_imsg_send_ipc_sockets(struct imsgbuf *, @@ -77,6 +76,7 @@ DEFINE_QOBJ_TYPE(l2vpn) DEFINE_QOBJ_TYPE(ldpd_conf) struct ldpd_global global; +struct ldpd_init init; struct ldpd_conf *ldpd_conf, *vty_conf; static struct imsgev *iev_ldpe, *iev_ldpe_sync; @@ -200,12 +200,7 @@ main(int argc, char *argv[]) int lflag = 0, eflag = 0; int pipe_parent2ldpe[2], pipe_parent2ldpe_sync[2]; int pipe_parent2lde[2], pipe_parent2lde_sync[2]; - char *ctl_sock_custom_path = NULL; char *ctl_sock_name; - const char *user = NULL; - const char *group = NULL; - u_short instance = 0; - const char *instance_char = NULL; ldpd_process = PROC_MAIN; log_procname = log_procnames[ldpd_process]; @@ -242,17 +237,14 @@ main(int argc, char *argv[]) * sensible config */ ctl_sock_name = (char *)LDPD_SOCKET; - ctl_sock_custom_path = optarg; - strlcpy(ctl_sock_path, ctl_sock_custom_path, - sizeof(ctl_sock_path)); + strlcpy(ctl_sock_path, optarg, sizeof(ctl_sock_path)); strlcat(ctl_sock_path, "/", sizeof(ctl_sock_path)); strlcat(ctl_sock_path, ctl_sock_name, sizeof(ctl_sock_path)); break; case 'n': - instance = atoi(optarg); - instance_char = optarg; - if (instance < 1) + init.instance = atoi(optarg); + if (init.instance < 1) exit(0); break; case 'L': @@ -267,8 +259,11 @@ main(int argc, char *argv[]) } } - user = ldpd_privs.user; - group = ldpd_privs.group; + strlcpy(init.user, ldpd_privs.user, sizeof(init.user)); + strlcpy(init.group, ldpd_privs.group, sizeof(init.group)); + strlcpy(init.ctl_sock_path, ctl_sock_path, sizeof(init.ctl_sock_path)); + strlcpy(init.zclient_serv_path, zclient_serv_path_get(), + sizeof(init.zclient_serv_path)); argc -= optind; argv += optind; @@ -286,9 +281,9 @@ main(int argc, char *argv[]) LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON); if (lflag) - lde(user, group, instance); + lde(); else if (eflag) - ldpe(user, group, ctl_sock_path); + ldpe(); if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_parent2ldpe) == -1) fatal("socketpair"); @@ -317,11 +312,9 @@ main(int argc, char *argv[]) /* start children */ lde_pid = start_child(PROC_LDE_ENGINE, saved_argv0, - pipe_parent2lde[1], pipe_parent2lde_sync[1], - user, group, ctl_sock_custom_path, instance_char); + pipe_parent2lde[1], pipe_parent2lde_sync[1]); ldpe_pid = start_child(PROC_LDP_ENGINE, saved_argv0, - pipe_parent2ldpe[1], pipe_parent2ldpe_sync[1], - user, group, ctl_sock_custom_path, instance_char); + pipe_parent2ldpe[1], pipe_parent2ldpe_sync[1]); /* drop privileges */ zprivs_init(&ldpd_privs); @@ -389,6 +382,7 @@ main(int argc, char *argv[]) if (main_imsg_send_ipc_sockets(&iev_ldpe->ibuf, &iev_lde->ibuf)) fatal("could not establish imsg links"); + main_imsg_compose_both(IMSG_INIT, &init, sizeof(init)); main_imsg_compose_both(IMSG_DEBUG_UPDATE, &ldp_debug, sizeof(ldp_debug)); main_imsg_send_config(ldpd_conf); @@ -453,11 +447,9 @@ ldpd_shutdown(void) } static pid_t -start_child(enum ldpd_process p, char *argv0, int fd_async, int fd_sync, - const char *user, const char *group, const char *ctl_sock_custom_path, - const char *instance) +start_child(enum ldpd_process p, char *argv0, int fd_async, int fd_sync) { - char *argv[13]; + char *argv[3]; int argc = 0; pid_t pid; @@ -488,29 +480,6 @@ start_child(enum ldpd_process p, char *argv0, int fd_async, int fd_sync, argv[argc++] = (char *)"-E"; break; } - if (user) { - argv[argc++] = (char *)"-u"; - argv[argc++] = (char *)user; - } - if (group) { - argv[argc++] = (char *)"-g"; - argv[argc++] = (char *)group; - } - if (ctl_sock_custom_path) { - argv[argc++] = (char *)"--ctl_socket"; - argv[argc++] = (char *)ctl_sock_custom_path; - } - /* zclient serv path */ -#ifdef HAVE_TCP_ZEBRA -#else - argv[argc++] = (char *)"-z"; - argv[argc++] = (char *)zclient_serv_path_get(); -#endif - /* instance */ - if (instance) { - argv[argc++] = (char *)"-n"; - argv[argc++] = (char *)instance; - } argv[argc++] = NULL; execvp(argv0, argv); diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h index 759f1d0da5..97239ed08e 100644 --- a/ldpd/ldpd.h +++ b/ldpd/ldpd.h @@ -147,7 +147,16 @@ enum imsg_type { IMSG_LOG, IMSG_ACL_CHECK, IMSG_GET_LABEL_CHUNK, - IMSG_RELEASE_LABEL_CHUNK + IMSG_RELEASE_LABEL_CHUNK, + IMSG_INIT +}; + +struct ldpd_init { + char user[256]; + char group[256]; + char ctl_sock_path[MAXPATHLEN]; + char zclient_serv_path[MAXPATHLEN]; + u_short instance; }; union ldpd_addr { @@ -510,7 +519,6 @@ struct ldpd_af_global { struct ldpd_global { int cmd_opts; int sighup; - time_t uptime; struct in_addr rtr_id; struct ldpd_af_global ipv4; struct ldpd_af_global ipv6; @@ -655,6 +663,7 @@ struct ctl_pw { extern struct ldpd_conf *ldpd_conf, *vty_conf; extern struct ldpd_global global; +extern struct ldpd_init init; /* parse.y */ struct ldpd_conf *parse_config(char *); diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c index e82416276b..1248d4f86e 100644 --- a/ldpd/ldpe.c +++ b/ldpd/ldpe.c @@ -103,47 +103,17 @@ static struct quagga_signal_t ldpe_signals[] = /* label distribution protocol engine */ void -ldpe(const char *user, const char *group, const char *ctl_path) +ldpe(void) { struct thread thread; - leconf = config_new_empty(); - #ifdef HAVE_SETPROCTITLE setproctitle("ldp engine"); #endif ldpd_process = PROC_LDP_ENGINE; log_procname = log_procnames[ldpd_process]; - LIST_INIT(&global.addr_list); - RB_INIT(&global.adj_tree); - TAILQ_INIT(&global.pending_conns); - if (inet_pton(AF_INET, AllRouters_v4, &global.mcast_addr_v4) != 1) - fatal("inet_pton"); - if (inet_pton(AF_INET6, AllRouters_v6, &global.mcast_addr_v6) != 1) - fatal("inet_pton"); -#ifdef __OpenBSD__ - global.pfkeysock = pfkey_init(); -#endif - - /* drop privileges */ - if (user) - ldpe_privs.user = user; - if (group) - ldpe_privs.group = group; - zprivs_init(&ldpe_privs); - - strlcpy(ctl_sock_path, ctl_path, sizeof(ctl_sock_path)); - if (control_init() == -1) - fatalx("control socket setup failed"); - -#ifdef HAVE_PLEDGE - if (pledge("stdio cpath inet mcast recvfd", NULL) == -1) - fatal("pledge"); -#endif - master = thread_master_create(); - accept_init(); /* setup signal handler */ signal_init(master, array_size(ldpe_signals), ldpe_signals); @@ -161,7 +131,45 @@ ldpe(const char *user, const char *group, const char *ctl_path) fatal(NULL); imsg_init(&iev_main_sync->ibuf, LDPD_FD_SYNC); + /* create base configuration */ + leconf = config_new_empty(); + + /* Fetch next active thread. */ + while (thread_fetch(master, &thread)) + thread_call(&thread); +} + +void +ldpe_init(struct ldpd_init *init) +{ + /* drop privileges */ + if (init->user) + ldpe_privs.user = init->user; + if (init->group) + ldpe_privs.group = init->group; + zprivs_init(&ldpe_privs); + + /* listen on ldpd control socket */ + strlcpy(ctl_sock_path, init->ctl_sock_path, sizeof(ctl_sock_path)); + if (control_init(ctl_sock_path) == -1) + fatalx("control socket setup failed"); + TAILQ_INIT(&ctl_conns); + control_listen(); + +#ifdef HAVE_PLEDGE + if (pledge("stdio cpath inet mcast recvfd", NULL) == -1) + fatal("pledge"); +#endif + + LIST_INIT(&global.addr_list); + RB_INIT(&global.adj_tree); + TAILQ_INIT(&global.pending_conns); + if (inet_pton(AF_INET, AllRouters_v4, &global.mcast_addr_v4) != 1) + fatal("inet_pton"); + if (inet_pton(AF_INET6, AllRouters_v6, &global.mcast_addr_v6) != 1) + fatal("inet_pton"); #ifdef __OpenBSD__ + global.pfkeysock = pfkey_init(); if (sysdep.no_pfkey == 0) pfkey_ev = thread_add_read(master, ldpe_dispatch_pfkey, NULL, global.pfkeysock); @@ -175,16 +183,10 @@ ldpe(const char *user, const char *group, const char *ctl_path) global.ipv6.ldp_edisc_socket = -1; global.ipv6.ldp_session_socket = -1; - /* listen on ldpd control socket */ - TAILQ_INIT(&ctl_conns); - control_listen(); - if ((pkt_ptr = calloc(1, IBUF_READ_SIZE)) == NULL) fatal(__func__); - /* Fetch next active thread. */ - while (thread_fetch(master, &thread)) - thread_call(&thread); + accept_init(); } static void @@ -203,7 +205,7 @@ ldpe_shutdown(void) msgbuf_clear(&iev_main_sync->ibuf.w); close(iev_main_sync->ibuf.fd); - control_cleanup(); + control_cleanup(ctl_sock_path); config_clear(leconf); #ifdef __OpenBSD__ @@ -352,6 +354,14 @@ ldpe_dispatch_main(struct thread *thread) iev_lde->handler_write = ldp_write_handler; iev_lde->ev_write = NULL; break; + case IMSG_INIT: + if (imsg.hdr.len != IMSG_HEADER_SIZE + + sizeof(struct ldpd_init)) + fatalx("INIT imsg with wrong len"); + + memcpy(&init, imsg.data, sizeof(init)); + ldpe_init(&init); + break; case IMSG_CLOSE_SOCKETS: af = imsg.hdr.peerid; diff --git a/ldpd/ldpe.h b/ldpd/ldpe.h index a3f41a8b9f..2c1ba46c6b 100644 --- a/ldpd/ldpe.h +++ b/ldpd/ldpe.h @@ -195,7 +195,8 @@ int tlv_decode_fec_elm(struct nbr *, struct ldp_msg *, char *, uint16_t, struct map *); /* ldpe.c */ -void ldpe(const char *, const char *, const char *); +void ldpe(void); +void ldpe_init(struct ldpd_init *); int ldpe_imsg_compose_parent(int, pid_t, void *, uint16_t); int ldpe_imsg_compose_lde(int, uint32_t, pid_t, void *, From b3121cd7d14f28cad53d39d9fbf09b036d3e95c9 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Wed, 19 Apr 2017 15:15:56 -0300 Subject: [PATCH 05/16] ldpd: fix segfault after failed initialization When ldpd fails to start for some reason, like failing to create a pid file, the child processes call their shutdown functions without being completely initialized. This patch adds some protections to prevent a segmentation fault on such circumstances. Signed-off-by: Renato Westphal --- ldpd/lde.c | 9 ++++++--- ldpd/ldpe.c | 11 +++++++---- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/ldpd/lde.c b/ldpd/lde.c index ed8274bec7..3dfcd8f885 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -216,8 +216,10 @@ static void lde_shutdown(void) { /* close pipes */ - msgbuf_clear(&iev_ldpe->ibuf.w); - close(iev_ldpe->ibuf.fd); + if (iev_ldpe) { + msgbuf_clear(&iev_ldpe->ibuf.w); + close(iev_ldpe->ibuf.fd); + } msgbuf_clear(&iev_main->ibuf.w); close(iev_main->ibuf.fd); msgbuf_clear(&iev_main_sync->ibuf.w); @@ -229,7 +231,8 @@ lde_shutdown(void) config_clear(ldeconf); - free(iev_ldpe); + if (iev_ldpe) + free(iev_ldpe); free(iev_main); free(iev_main_sync); diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c index 1248d4f86e..bd0f9dbd6f 100644 --- a/ldpd/ldpe.c +++ b/ldpd/ldpe.c @@ -196,9 +196,11 @@ ldpe_shutdown(void) struct adj *adj; /* close pipes */ - msgbuf_write(&iev_lde->ibuf.w); - msgbuf_clear(&iev_lde->ibuf.w); - close(iev_lde->ibuf.fd); + if (iev_lde) { + msgbuf_write(&iev_lde->ibuf.w); + msgbuf_clear(&iev_lde->ibuf.w); + close(iev_lde->ibuf.fd); + } msgbuf_write(&iev_main->ibuf.w); msgbuf_clear(&iev_main->ibuf.w); close(iev_main->ibuf.fd); @@ -226,7 +228,8 @@ ldpe_shutdown(void) adj_del(adj, S_SHUTDOWN); /* clean up */ - free(iev_lde); + if (iev_lde) + free(iev_lde); free(iev_main); free(iev_main_sync); free(pkt_ptr); From 30f35e856608b29c7e4f091c7a22f4a3b4019258 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Wed, 19 Apr 2017 15:28:43 -0300 Subject: [PATCH 06/16] ldpd: remove unnecessary checks if a signal was caught Signed-off-by: Renato Westphal --- ldpd/lde.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/ldpd/lde.c b/ldpd/lde.c index 3dfcd8f885..426af8dbe8 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -119,13 +119,6 @@ static struct quagga_signal_t lde_signals[] = }, }; -static void -lde_sleep (void) -{ - sleep(1); - if (lde_signals[0].caught || lde_signals[1].caught) - lde_shutdown(); -} struct zclient *zclient_sync = NULL; static void zclient_sync_init(u_short instance) @@ -138,7 +131,7 @@ zclient_sync_init(u_short instance) zclient_sync->instance = instance; while (zclient_socket_connect (zclient_sync) < 0) { fprintf(stderr, "Error connecting synchronous zclient!\n"); - lde_sleep(); + sleep(1); } /* make socket non-blocking */ sock_set_nonblock(zclient_sync->sock); @@ -146,7 +139,7 @@ zclient_sync_init(u_short instance) /* Connect to label manager */ while (lm_label_manager_connect (zclient_sync) != 0) { fprintf(stderr, "Error connecting to label manager!\n"); - lde_sleep(); + sleep(1); } } @@ -1628,7 +1621,7 @@ lde_label_list_init(void) /* get first chunk */ while (lde_get_label_chunk () != 0) { fprintf(stderr, "Error getting first label chunk!\n"); - lde_sleep(); + sleep(1); } } From d8292558bde9802b8267deff44dabb87b12b885f Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Wed, 19 Apr 2017 16:59:50 -0300 Subject: [PATCH 07/16] ldpd: use synchronous channels for sending log messages This is necessary to guarantee that all log messages sent from the child processes are received in the parent process right away. Without this patch, when a child process calls fatal() or fatalx(), the log messages don't make it to the parent because the child doesn't have a chance to flush its buffers before exiting. Signed-off-by: Renato Westphal --- ldpd/lde.c | 13 ++++++++++--- ldpd/lde.h | 1 + ldpd/ldpe.c | 7 +++++++ ldpd/ldpe.h | 1 + ldpd/log.c | 6 ++++-- 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/ldpd/lde.c b/ldpd/lde.c index 426af8dbe8..1c7458ce73 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -130,7 +130,7 @@ zclient_sync_init(u_short instance) zclient_sync->redist_default = ZEBRA_ROUTE_LDP; zclient_sync->instance = instance; while (zclient_socket_connect (zclient_sync) < 0) { - fprintf(stderr, "Error connecting synchronous zclient!\n"); + log_warnx("Error connecting synchronous zclient!"); sleep(1); } /* make socket non-blocking */ @@ -138,7 +138,7 @@ zclient_sync_init(u_short instance) /* Connect to label manager */ while (lm_label_manager_connect (zclient_sync) != 0) { - fprintf(stderr, "Error connecting to label manager!\n"); + log_warnx("Error connecting to label manager!"); sleep(1); } } @@ -240,6 +240,13 @@ lde_imsg_compose_parent(int type, pid_t pid, void *data, uint16_t datalen) return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen)); } +void +lde_imsg_compose_parent_sync(int type, pid_t pid, void *data, uint16_t datalen) +{ + imsg_compose_event(iev_main_sync, type, 0, pid, -1, data, datalen); + imsg_flush(&iev_main_sync->ibuf); +} + int lde_imsg_compose_ldpe(int type, uint32_t peerid, pid_t pid, void *data, uint16_t datalen) @@ -1620,7 +1627,7 @@ lde_label_list_init(void) /* get first chunk */ while (lde_get_label_chunk () != 0) { - fprintf(stderr, "Error getting first label chunk!\n"); + log_warnx("Error getting first label chunk!"); sleep(1); } } diff --git a/ldpd/lde.h b/ldpd/lde.h index 3349d4ca00..c1d66f9fff 100644 --- a/ldpd/lde.h +++ b/ldpd/lde.h @@ -142,6 +142,7 @@ extern struct thread *gc_timer; void lde(void); void lde_init(struct ldpd_init *); int lde_imsg_compose_parent(int, pid_t, void *, uint16_t); +void lde_imsg_compose_parent_sync(int, pid_t, void *, uint16_t); int lde_imsg_compose_ldpe(int, uint32_t, pid_t, void *, uint16_t); int lde_acl_check(char *, int, union ldpd_addr *, uint8_t); uint32_t lde_update_label(struct fec_node *); diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c index bd0f9dbd6f..20cc9f7444 100644 --- a/ldpd/ldpe.c +++ b/ldpd/ldpe.c @@ -245,6 +245,13 @@ ldpe_imsg_compose_parent(int type, pid_t pid, void *data, uint16_t datalen) return (imsg_compose_event(iev_main, type, 0, pid, -1, data, datalen)); } +void +ldpe_imsg_compose_parent_sync(int type, pid_t pid, void *data, uint16_t datalen) +{ + imsg_compose_event(iev_main_sync, type, 0, pid, -1, data, datalen); + imsg_flush(&iev_main_sync->ibuf); +} + int ldpe_imsg_compose_lde(int type, uint32_t peerid, pid_t pid, void *data, uint16_t datalen) diff --git a/ldpd/ldpe.h b/ldpd/ldpe.h index 2c1ba46c6b..d34ca4dc24 100644 --- a/ldpd/ldpe.h +++ b/ldpd/ldpe.h @@ -199,6 +199,7 @@ void ldpe(void); void ldpe_init(struct ldpd_init *); int ldpe_imsg_compose_parent(int, pid_t, void *, uint16_t); +void ldpe_imsg_compose_parent_sync(int, pid_t, void *, uint16_t); int ldpe_imsg_compose_lde(int, uint32_t, pid_t, void *, uint16_t); int ldpe_acl_check(char *, int, union ldpd_addr *, uint8_t); diff --git a/ldpd/log.c b/ldpd/log.c index fc8c995ba3..b138e5754a 100644 --- a/ldpd/log.c +++ b/ldpd/log.c @@ -46,11 +46,13 @@ vlog(int pri, const char *fmt, va_list ap) switch (ldpd_process) { case PROC_LDE_ENGINE: vsnprintf(buf, sizeof(buf), fmt, ap); - lde_imsg_compose_parent(IMSG_LOG, pri, buf, strlen(buf) + 1); + lde_imsg_compose_parent_sync(IMSG_LOG, pri, buf, + strlen(buf) + 1); break; case PROC_LDP_ENGINE: vsnprintf(buf, sizeof(buf), fmt, ap); - ldpe_imsg_compose_parent(IMSG_LOG, pri, buf, strlen(buf) + 1); + ldpe_imsg_compose_parent_sync(IMSG_LOG, pri, buf, + strlen(buf) + 1); break; case PROC_MAIN: vzlog(pri, fmt, ap); From 3dcdcbb478d760208e7d82241bbdc359e9479475 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Wed, 19 Apr 2017 17:12:35 -0300 Subject: [PATCH 08/16] ldpd: minor changes in the output of some show commands Signed-off-by: Renato Westphal --- ldpd/ldp_vty_exec.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ldpd/ldp_vty_exec.c b/ldpd/ldp_vty_exec.c index a149b7fe35..ffd20abb4a 100644 --- a/ldpd/ldp_vty_exec.c +++ b/ldpd/ldp_vty_exec.c @@ -517,8 +517,7 @@ show_nbr_msg(struct vty *vty, struct imsg *imsg, struct show_params *params) nbr_state_name(nbr->nbr_state), addr); if (strlen(addr) > 15) vty_out(vty, "%s%48s", VTY_NEWLINE, " "); - vty_out(vty, " %8s%s", nbr->uptime == 0 ? "-" : - log_time(nbr->uptime), VTY_NEWLINE); + vty_out(vty, " %8s%s", log_time(nbr->uptime), VTY_NEWLINE); break; case IMSG_CTL_END: return (1); @@ -909,6 +908,7 @@ show_nbr_capabilities_msg(struct vty *vty, struct imsg *imsg, struct show_params vty_out(vty, "Peer LDP Identifier: %s:0%s", inet_ntoa(nbr->id), VTY_NEWLINE); show_nbr_capabilities(vty, nbr); + vty_out(vty, "%s", VTY_NEWLINE); break; case IMSG_CTL_END: vty_out(vty, "%s", VTY_NEWLINE); From 9b2868bc019b15a878b3b08d165194b8c00b0e63 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Wed, 19 Apr 2017 19:31:19 -0300 Subject: [PATCH 09/16] ldpd: accept notifications during the session establishment process If we don't do this, we'll never trigger the backoff exponential timer since it's impossible to distinguish between Initialization NAK's and general errors. Also: * Implement some missing bits from RFC 5036; * remove superfluous log message in session_shutdown() (send_notification() logs that we're sending a fatal notification). Regression introduced by commit 8819fc3. Fixes the following ANVL LDP regressions: 6.19 and 6.21. Signed-off-by: Renato Westphal --- ldpd/notification.c | 10 ++++++++++ ldpd/packet.c | 4 ++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/ldpd/notification.c b/ldpd/notification.c index f10faa4a54..4a5f3c8fa4 100644 --- a/ldpd/notification.c +++ b/ldpd/notification.c @@ -237,6 +237,16 @@ recv_notification(struct nbr *nbr, char *buf, uint16_t len) if (nbr->state == NBR_STA_OPENSENT) nbr_start_idtimer(nbr); + /* + * RFC 5036 - Section 3.5.1.1: + * "When an LSR receives a Shutdown message during session + * initialization, it SHOULD transmit a Shutdown message and + * then close the transport connection". + */ + if (nbr->state != NBR_STA_OPER && nm.status_code == S_SHUTDOWN) + send_notification(nbr->tcp, S_SHUTDOWN, + msg.id, msg.type); + nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); return (-1); } diff --git a/ldpd/packet.c b/ldpd/packet.c index 46893b992b..75e1a9a027 100644 --- a/ldpd/packet.c +++ b/ldpd/packet.c @@ -519,6 +519,8 @@ session_read(struct thread *thread) return (0); } break; + case MSG_TYPE_NOTIFICATION: + break; default: if (nbr->state != NBR_STA_OPER) { session_shutdown(nbr, S_SHUTDOWN, @@ -661,8 +663,6 @@ session_shutdown(struct nbr *nbr, uint32_t status, uint32_t msg_id, case NBR_STA_OPENREC: case NBR_STA_OPENSENT: case NBR_STA_OPER: - log_debug("%s: lsr-id %s", __func__, inet_ntoa(nbr->id)); - send_notification(nbr->tcp, status, msg_id, msg_type); nbr_fsm(nbr, NBR_EVT_CLOSE_SESSION); From a8e8b867974cfbc37aeabe34b067f10448690bd2 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 21 Apr 2017 15:41:14 -0300 Subject: [PATCH 10/16] ldpd: be more conservative with labels On unstable networks, routes can be lost and relearned very often. If we deallocate the input label every time a route is lost and allocate a new one when the route is relearned, a lot of changes are made in vain. This patch introduces a logic in which labels are preserved for at least five minutes before being deallocated by the LIB garbage collector. This is consistent with what other implementations do. Signed-off-by: Renato Westphal --- ldpd/lde_lib.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c index db2682a173..b074bf3498 100644 --- a/ldpd/lde_lib.c +++ b/ldpd/lde_lib.c @@ -383,20 +383,23 @@ lde_kernel_update(struct fec *fec) if (LIST_EMPTY(&fn->nexthops)) { RB_FOREACH(ln, nbr_tree, &lde_nbrs) lde_send_labelwithdraw(ln, fn, NULL, NULL); - fn->local_label = NO_LABEL; fn->data = NULL; + + /* + * Do not deallocate the local label now, do that only in the + * LIB garbage collector. This will prevent ldpd from changing + * the input label of some prefixes too often when running on + * an unstable network. Also, restart the garbage collector + * timer so that labels are deallocated only when the network + * is stabilized. + */ + lde_gc_start_timer(); } else { - uint32_t previous_label; - - previous_label = fn->local_label; fn->local_label = lde_update_label(fn); - - if (fn->local_label != NO_LABEL && - fn->local_label != previous_label) { + if (fn->local_label != NO_LABEL && RB_EMPTY(&fn->upstream)) /* FEC.1: perform lsr label distribution procedure */ RB_FOREACH(ln, nbr_tree, &lde_nbrs) lde_send_labelmapping(ln, fn, 1); - } } LIST_FOREACH(fnh, &fn->nexthops, entry) { From 79f62ef746f4cc6e1f9c233a4f1afab86d928d46 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 21 Apr 2017 19:39:11 -0300 Subject: [PATCH 11/16] ldpd: improve ldp_zebra_read_route() Log deleted routes and simplify the code a bit. Signed-off-by: Renato Westphal --- ldpd/ldp_zebra.c | 41 +++++++++++++++-------------------------- 1 file changed, 15 insertions(+), 26 deletions(-) diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c index fde6e56c64..3320238a05 100644 --- a/ldpd/ldp_zebra.c +++ b/ldpd/ldp_zebra.c @@ -360,6 +360,7 @@ ldp_zebra_read_route(int command, struct zclient *zclient, zebra_size_t length, struct kroute kr; int nhnum = 0, nhlen; size_t nhmark; + int add = 0; memset(&kr, 0, sizeof(kr)); s = zclient->ibuf; @@ -426,21 +427,14 @@ ldp_zebra_read_route(int command, struct zclient *zclient, zebra_size_t length, if (CHECK_FLAG(message_flags, ZAPI_MESSAGE_NEXTHOP)) stream_set_getp(s, nhmark); - if (nhnum == 0) { - switch (command) { - case ZEBRA_REDISTRIBUTE_IPV4_ADD: - case ZEBRA_REDISTRIBUTE_IPV6_ADD: - return (0); - case ZEBRA_REDISTRIBUTE_IPV4_DEL: - case ZEBRA_REDISTRIBUTE_IPV6_DEL: - debug_zebra_in("route delete %s/%d (%s)", - log_addr(kr.af, &kr.prefix), kr.prefixlen, - zebra_route_string(type)); - break; - default: - fatalx("ldp_zebra_read_route: unknown command"); - } - } + if (command == ZEBRA_REDISTRIBUTE_IPV4_ADD || + command == ZEBRA_REDISTRIBUTE_IPV6_ADD) + add = 1; + + if (nhnum == 0) + debug_zebra_in("route %s %s/%d (%s)", (add) ? "add" : "delete", + log_addr(kr.af, &kr.prefix), kr.prefixlen, + zebra_route_string(type)); /* loop through all the nexthops */ for (; nhnum > 0; nhnum--) { @@ -457,19 +451,14 @@ ldp_zebra_read_route(int command, struct zclient *zclient, zebra_size_t length, stream_getc(s); /* ifindex_num, unused. */ kr.ifindex = stream_getl(s); - switch (command) { - case ZEBRA_REDISTRIBUTE_IPV4_ADD: - case ZEBRA_REDISTRIBUTE_IPV6_ADD: - debug_zebra_in("route add %s/%d nexthop %s " - "ifindex %u (%s)", log_addr(kr.af, &kr.prefix), - kr.prefixlen, log_addr(kr.af, &kr.nexthop), - kr.ifindex, zebra_route_string(type)); + debug_zebra_in("route %s %s/%d nexthop %s ifindex %u (%s)", + (add) ? "add" : "delete", log_addr(kr.af, &kr.prefix), + kr.prefixlen, log_addr(kr.af, &kr.nexthop), kr.ifindex, + zebra_route_string(type)); + + if (add) main_imsg_compose_lde(IMSG_NETWORK_ADD, 0, &kr, sizeof(kr)); - break; - default: - break; - } } main_imsg_compose_lde(IMSG_NETWORK_UPDATE, 0, &kr, sizeof(kr)); From abb160061189c9e4a1a8ab28aea4acbd64c32066 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 21 Apr 2017 22:10:42 -0300 Subject: [PATCH 12/16] ldpd: schedule the sending of label messages when necessary Once we send a Label Withdraw, we can't send a Label Mapping for the same FEC until we receive a Label Release from the peer. This is due to some limitations in the LDP algorithms described in Appendix A. ("LDP Label Distribution Procedures") of RFC 5036. To workaround this issue, make it possible to schedule the sending of a Label Mapping as soon as a Label Release is received for the same FEC. The easiest way to test this patch is by typing the "label local advertise explicit-null" command. ldpd will withdraw all null labels using a Wildcard FEC and then send new Label Mappings as soon the corresponding Label Releases are received. Signed-off-by: Renato Westphal --- ldpd/lde.c | 47 +++++++++++++++++++++++++++++++++++++++++++---- ldpd/lde.h | 3 +++ ldpd/lde_lib.c | 36 ++++++++++++++++++++++++++---------- 3 files changed, 72 insertions(+), 14 deletions(-) diff --git a/ldpd/lde.c b/ldpd/lde.c index 1c7458ce73..e5d1402832 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -917,10 +917,23 @@ lde_map2fec(struct map *map, struct in_addr lsr_id, struct fec *fec) void lde_send_labelmapping(struct lde_nbr *ln, struct fec_node *fn, int single) { - struct lde_req *lre; - struct lde_map *me; - struct map map; - struct l2vpn_pw *pw; + struct lde_wdraw *lw; + struct lde_map *me; + struct lde_req *lre; + struct map map; + struct l2vpn_pw *pw; + + /* + * We shouldn't send a new label mapping if we have a pending + * label release to receive. In this case, schedule to send a + * label mapping as soon as a label release is received. + */ + lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec); + if (lw) { + if (!fec_find(&ln->sent_map_pending, &fn->fec)) + lde_map_pending_add(ln, fn); + return; + } /* * This function skips SL.1 - 3 and SL.9 - 14 because the label @@ -1226,6 +1239,7 @@ lde_nbr_new(uint32_t peerid, struct lde_nbr *new) ln->peerid = peerid; fec_init(&ln->recv_map); fec_init(&ln->sent_map); + fec_init(&ln->sent_map_pending); fec_init(&ln->recv_req); fec_init(&ln->sent_req); fec_init(&ln->sent_wdraw); @@ -1281,6 +1295,7 @@ lde_nbr_del(struct lde_nbr *ln) fec_clear(&ln->recv_map, lde_map_free); fec_clear(&ln->sent_map, lde_map_free); + fec_clear(&ln->sent_map_pending, free); fec_clear(&ln->recv_req, free); fec_clear(&ln->sent_req, free); fec_clear(&ln->sent_wdraw, free); @@ -1431,6 +1446,30 @@ lde_map_free(void *ptr) free(map); } +struct fec * +lde_map_pending_add(struct lde_nbr *ln, struct fec_node *fn) +{ + struct fec *map; + + map = calloc(1, sizeof(*map)); + if (map == NULL) + fatal(__func__); + + *map = fn->fec; + if (fec_insert(&ln->sent_map_pending, map)) + log_warnx("failed to add %s to sent map (pending)", + log_fec(map)); + + return (map); +} + +void +lde_map_pending_del(struct lde_nbr *ln, struct fec *map) +{ + fec_remove(&ln->sent_map_pending, map); + free(map); +} + struct lde_req * lde_req_add(struct lde_nbr *ln, struct fec *fec, int sent) { diff --git a/ldpd/lde.h b/ldpd/lde.h index c1d66f9fff..1cce483832 100644 --- a/ldpd/lde.h +++ b/ldpd/lde.h @@ -95,6 +95,7 @@ struct lde_nbr { struct fec_tree sent_req; struct fec_tree recv_map; struct fec_tree sent_map; + struct fec_tree sent_map_pending; struct fec_tree sent_wdraw; TAILQ_HEAD(, lde_addr) addr_list; }; @@ -171,6 +172,8 @@ struct lde_nbr *lde_nbr_find_by_lsrid(struct in_addr); struct lde_nbr *lde_nbr_find_by_addr(int, union ldpd_addr *); struct lde_map *lde_map_add(struct lde_nbr *, struct fec_node *, int); void lde_map_del(struct lde_nbr *, struct lde_map *, int); +struct fec *lde_map_pending_add(struct lde_nbr *, struct fec_node *); +void lde_map_pending_del(struct lde_nbr *, struct fec *); struct lde_req *lde_req_add(struct lde_nbr *, struct fec *, int); void lde_req_del(struct lde_nbr *, struct lde_req *, int); struct lde_wdraw *lde_wdraw_add(struct lde_nbr *, struct fec_node *); diff --git a/ldpd/lde_lib.c b/ldpd/lde_lib.c index b074bf3498..37a670bc8c 100644 --- a/ldpd/lde_lib.c +++ b/ldpd/lde_lib.c @@ -662,6 +662,7 @@ lde_check_release(struct map *map, struct lde_nbr *ln) struct fec_node *fn; struct lde_wdraw *lw; struct lde_map *me; + struct fec *pending_map; /* wildcard label release */ if (map->type == MAP_TYPE_WILDCARD || @@ -677,17 +678,24 @@ lde_check_release(struct map *map, struct lde_nbr *ln) if (fn == NULL) return; + /* LRl.6: check sent map list and remove it if available */ + me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec); + if (me && (map->label == NO_LABEL || map->label == me->map.label)) + lde_map_del(ln, me, 1); + /* LRl.3: first check if we have a pending withdraw running */ lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec); if (lw && (map->label == NO_LABEL || map->label == lw->label)) { /* LRl.4: delete record of outstanding label withdraw */ lde_wdraw_del(ln, lw); - } - /* LRl.6: check sent map list and remove it if available */ - me = (struct lde_map *)fec_find(&ln->sent_map, &fn->fec); - if (me && (map->label == NO_LABEL || map->label == me->map.label)) - lde_map_del(ln, me, 1); + /* send pending label mapping if any */ + pending_map = fec_find(&ln->sent_map_pending, &fn->fec); + if (pending_map) { + lde_send_labelmapping(ln, fn, 1); + lde_map_pending_del(ln, pending_map); + } + } /* * LRl.11 - 13 are unnecessary since we remove the label from @@ -702,6 +710,7 @@ lde_check_release_wcard(struct map *map, struct lde_nbr *ln) struct fec_node *fn; struct lde_wdraw *lw; struct lde_map *me; + struct fec *pending_map; RB_FOREACH(f, fec_tree, &ft) { fn = (struct fec_node *)f; @@ -711,17 +720,24 @@ lde_check_release_wcard(struct map *map, struct lde_nbr *ln) if (lde_wildcard_apply(map, &fn->fec, me) == 0) continue; + /* LRl.6: check sent map list and remove it if available */ + if (me && + (map->label == NO_LABEL || map->label == me->map.label)) + lde_map_del(ln, me, 1); + /* LRl.3: first check if we have a pending withdraw running */ lw = (struct lde_wdraw *)fec_find(&ln->sent_wdraw, &fn->fec); if (lw && (map->label == NO_LABEL || map->label == lw->label)) { /* LRl.4: delete record of outstanding lbl withdraw */ lde_wdraw_del(ln, lw); - } - /* LRl.6: check sent map list and remove it if available */ - if (me && - (map->label == NO_LABEL || map->label == me->map.label)) - lde_map_del(ln, me, 1); + /* send pending label mapping if any */ + pending_map = fec_find(&ln->sent_map_pending, &fn->fec); + if (pending_map) { + lde_send_labelmapping(ln, fn, 1); + lde_map_pending_del(ln, pending_map); + } + } /* * LRl.11 - 13 are unnecessary since we remove the label from From cb7426d40354d69a2705ee01240aef8a211cf3db Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Sat, 22 Apr 2017 10:55:27 -0300 Subject: [PATCH 13/16] ldpd: allow targeted neighbors over any interface It's doesn't make sense to enforce that a targeted-hello is received on an LDP-enabled interface. It should be possible, for example, to use LDP only to signal pseudowires and other another protocol (e.g. RSVP-TE) to create end-to-end LSPs. Signed-off-by: Renato Westphal --- ldpd/packet.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/ldpd/packet.c b/ldpd/packet.c index 75e1a9a027..df6bd8e57a 100644 --- a/ldpd/packet.c +++ b/ldpd/packet.c @@ -27,7 +27,7 @@ #include "sockopt.h" static struct iface *disc_find_iface(unsigned int, int, - union ldpd_addr *, int); + union ldpd_addr *); static int session_read(struct thread *); static int session_write(struct thread *); static ssize_t session_get_pdu(struct ibuf_read *, char **); @@ -134,7 +134,7 @@ disc_recv_packet(struct thread *thread) int af; union ldpd_addr src; unsigned int ifindex = 0; - struct iface *iface; + struct iface *iface = NULL; uint16_t len; struct ldp_hdr ldp_hdr; uint16_t pdu_len; @@ -212,9 +212,11 @@ disc_recv_packet(struct thread *thread) ifindex = getsockopt_ifindex(af, &m); /* find a matching interface */ - iface = disc_find_iface(ifindex, af, &src, multicast); - if (iface == NULL) - return (0); + if (multicast) { + iface = disc_find_iface(ifindex, af, &src); + if (iface == NULL) + return (0); + } /* check packet size */ len = (uint16_t)r; @@ -280,8 +282,7 @@ disc_recv_packet(struct thread *thread) } static struct iface * -disc_find_iface(unsigned int ifindex, int af, union ldpd_addr *src, - int multicast) +disc_find_iface(unsigned int ifindex, int af, union ldpd_addr *src) { struct iface *iface; struct iface_af *ia; @@ -299,7 +300,7 @@ disc_find_iface(unsigned int ifindex, int af, union ldpd_addr *src, * "Link-local IPv6 address MUST be used as the source IP address in * IPv6 LDP Link Hellos". */ - if (multicast && af == AF_INET6 && !IN6_IS_ADDR_LINKLOCAL(&src->v6)) + if (af == AF_INET6 && !IN6_IS_ADDR_LINKLOCAL(&src->v6)) return (NULL); return (iface); From 602c726ef2a37597d9cba1f0adafc9bc4fc7e3db Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Sat, 22 Apr 2017 12:03:14 -0300 Subject: [PATCH 14/16] ldpd: fix bug when changing the transport address When the transport address is changed, all interfaces and targeted neighbors are temporary disabled in the ldpe process until new sockets bound to the new transport address are received from the parent. This patch fixes a problem in which adjacencies weren't being removed after the associated targeted neighbors were disabled. This was causing ldpd not to set some MD5 sockoptions for new neighbors are thus preventing MD5-protected sessions to come up after a change in the transport-address. Signed-off-by: Renato Westphal --- ldpd/adjacency.c | 31 ++++++++++++++++++++++--------- ldpd/interface.c | 9 +++++---- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/ldpd/adjacency.c b/ldpd/adjacency.c index 8659202ee4..3ec57f1589 100644 --- a/ldpd/adjacency.c +++ b/ldpd/adjacency.c @@ -29,6 +29,8 @@ static __inline int adj_compare(struct adj *, struct adj *); static int adj_itimer(struct thread *); static __inline int tnbr_compare(struct tnbr *, struct tnbr *); static void tnbr_del(struct ldpd_conf *, struct tnbr *); +static void tnbr_start(struct tnbr *); +static void tnbr_stop(struct tnbr *); static int tnbr_hello_timer(struct thread *); static void tnbr_start_hello_timer(struct tnbr *); static void tnbr_stop_hello_timer(struct tnbr *); @@ -245,9 +247,7 @@ tnbr_new(int af, union ldpd_addr *addr) static void tnbr_del(struct ldpd_conf *xconf, struct tnbr *tnbr) { - tnbr_stop_hello_timer(tnbr); - if (tnbr->adj) - adj_del(tnbr->adj, S_SHUTDOWN); + tnbr_stop(tnbr); RB_REMOVE(tnbr_head, &xconf->tnbr_tree, tnbr); free(tnbr); } @@ -273,6 +273,23 @@ tnbr_check(struct ldpd_conf *xconf, struct tnbr *tnbr) return (tnbr); } +static void +tnbr_start(struct tnbr *tnbr) +{ + send_hello(HELLO_TARGETED, NULL, tnbr); + tnbr_start_hello_timer(tnbr); + tnbr->state = TNBR_STA_ACTIVE; +} + +static void +tnbr_stop(struct tnbr *tnbr) +{ + tnbr_stop_hello_timer(tnbr); + if (tnbr->adj) + adj_del(tnbr->adj, S_SHUTDOWN); + tnbr->state = TNBR_STA_DOWN; +} + void tnbr_update(struct tnbr *tnbr) { @@ -292,16 +309,12 @@ tnbr_update(struct tnbr *tnbr) if (!socket_ok || !rtr_id_ok) return; - tnbr->state = TNBR_STA_ACTIVE; - send_hello(HELLO_TARGETED, NULL, tnbr); - - tnbr_start_hello_timer(tnbr); + tnbr_start(tnbr); } else if (tnbr->state == TNBR_STA_ACTIVE) { if (socket_ok && rtr_id_ok) return; - tnbr->state = TNBR_STA_DOWN; - tnbr_stop_hello_timer(tnbr); + tnbr_stop(tnbr); } } diff --git a/ldpd/interface.c b/ldpd/interface.c index 7be8be755e..440bb2dca0 100644 --- a/ldpd/interface.c +++ b/ldpd/interface.c @@ -287,8 +287,9 @@ if_start(struct iface *iface, int af) } send_hello(HELLO_LINK, ia, NULL); - if_start_hello_timer(ia); + ia->state = IF_STA_ACTIVE; + return (0); } @@ -318,9 +319,11 @@ if_reset(struct iface *iface, int af) if_leave_ipv6_group(iface, &global.mcast_addr_v6); break; default: - fatalx("if_start: unknown af"); + fatalx("if_reset: unknown af"); } + ia->state = IF_STA_DOWN; + return (0); } @@ -367,14 +370,12 @@ if_update_af(struct iface_af *ia) !socket_ok || !rtr_id_ok) return; - ia->state = IF_STA_ACTIVE; if_start(ia->iface, ia->af); } else if (ia->state == IF_STA_ACTIVE) { if (ia->enabled && ia->iface->operative && addr_ok && socket_ok && rtr_id_ok) return; - ia->state = IF_STA_DOWN; if_reset(ia->iface, ia->af); } } From 6bbf78cf5278c2b011bcb4f22fd92dbefd113e0e Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Thu, 27 Apr 2017 08:56:15 -0300 Subject: [PATCH 15/16] ldpd: fix issues detected by Coverity Scan Signed-off-by: Renato Westphal --- ldpd/lde.c | 10 ++-------- ldpd/ldpe.c | 10 ++-------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/ldpd/lde.c b/ldpd/lde.c index e5d1402832..0cfc02d5ba 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -80,10 +80,6 @@ static zebra_capabilities_t _caps_p [] = static struct zebra_privs_t lde_privs = { -#if defined(FRR_USER) && defined(FRR_GROUP) - .user = FRR_USER, - .group = FRR_GROUP, -#endif #if defined(VTY_GROUP) .vty_group = VTY_GROUP, #endif @@ -185,10 +181,8 @@ void lde_init(struct ldpd_init *init) { /* drop privileges */ - if (init->user) - lde_privs.user = init->user; - if (init->group) - lde_privs.group = init->group; + lde_privs.user = init->user; + lde_privs.group = init->group; zprivs_init(&lde_privs); #ifdef HAVE_PLEDGE diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c index 20cc9f7444..017eec2502 100644 --- a/ldpd/ldpe.c +++ b/ldpd/ldpe.c @@ -66,10 +66,6 @@ static zebra_capabilities_t _caps_p [] = struct zebra_privs_t ldpe_privs = { -#if defined(FRR_USER) && defined(FRR_GROUP) - .user = FRR_USER, - .group = FRR_GROUP, -#endif #if defined(VTY_GROUP) .vty_group = VTY_GROUP, #endif @@ -143,10 +139,8 @@ void ldpe_init(struct ldpd_init *init) { /* drop privileges */ - if (init->user) - ldpe_privs.user = init->user; - if (init->group) - ldpe_privs.group = init->group; + ldpe_privs.user = init->user; + ldpe_privs.group = init->group; zprivs_init(&ldpe_privs); /* listen on ldpd control socket */ From c18ac4c29a829edd98591931ba4ed827b3569095 Mon Sep 17 00:00:00 2001 From: Renato Westphal Date: Fri, 2 Jun 2017 11:14:54 -0300 Subject: [PATCH 16/16] ldpd: fix bug in pseudowire control-word negotiation Bingen discovered a bug in the pseudowire control-word negotiation that might happen when the "control-word exclude" command is used. Under some very specific conditions, ldpd might ignore a PWID label mapping when it shouldn't. This patch removes a wrong optimization that was preventing ldpd to call l2vpn_pw_reset() every time we change the configuration of a pseudowire. Signed-off-by: Renato Westphal --- ldpd/ldpd.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index bdf7097323..f9e44012ef 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -1679,8 +1679,7 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl) session_shutdown(nbr, S_SHUTDOWN, 0, 0); } } - if (ldpd_process == PROC_LDE_ENGINE && - !reset_nbr && reinstall_pwfec) + if (ldpd_process == PROC_LDE_ENGINE && reinstall_pwfec) l2vpn_pw_exit(pw); pw->lsr_id = xp->lsr_id; pw->af = xp->af; @@ -1702,8 +1701,7 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl) pw->flags &= ~F_PW_STATIC_NBR_ADDR; if (ldpd_process == PROC_LDP_ENGINE && reinstall_tnbr) ldpe_l2vpn_pw_init(pw); - if (ldpd_process == PROC_LDE_ENGINE && - !reset_nbr && reinstall_pwfec) { + if (ldpd_process == PROC_LDE_ENGINE && reinstall_pwfec) { l2vpn->pw_type = xl->pw_type; l2vpn->mtu = xl->mtu; l2vpn_pw_init(pw);