diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/buffer.c | 24 | ||||
| -rw-r--r-- | lib/command.c | 3 | ||||
| -rw-r--r-- | lib/command.h | 2 | ||||
| -rw-r--r-- | lib/csv.c | 3 | ||||
| -rw-r--r-- | lib/frr_zmq.c | 24 | ||||
| -rw-r--r-- | lib/libfrr.c | 6 | ||||
| -rw-r--r-- | lib/link_state.c | 12 | ||||
| -rw-r--r-- | lib/network.c | 3 | ||||
| -rw-r--r-- | lib/ntop.c | 14 | ||||
| -rw-r--r-- | lib/pbr.h | 6 | ||||
| -rw-r--r-- | lib/plist.c | 66 | ||||
| -rw-r--r-- | lib/plist.h | 15 | ||||
| -rw-r--r-- | lib/prefix.c | 3 | ||||
| -rw-r--r-- | lib/prefix.h | 32 | ||||
| -rw-r--r-- | lib/route_types.txt | 4 | ||||
| -rw-r--r-- | lib/routemap.h | 1 | ||||
| -rw-r--r-- | lib/routemap_cli.c | 5 | ||||
| -rw-r--r-- | lib/sockopt.c | 16 | ||||
| -rw-r--r-- | lib/stream.c | 8 | ||||
| -rw-r--r-- | lib/subdir.am | 17 | ||||
| -rw-r--r-- | lib/systemd.c | 173 | ||||
| -rw-r--r-- | lib/systemd.h | 10 | ||||
| -rw-r--r-- | lib/zclient.c | 6 |
23 files changed, 304 insertions, 149 deletions
diff --git a/lib/buffer.c b/lib/buffer.c index 7929b3709d..41b1adc9fc 100644 --- a/lib/buffer.c +++ b/lib/buffer.c @@ -357,7 +357,8 @@ buffer_status_t buffer_flush_window(struct buffer *b, int fd, int width, iov_size = ((iov_index > IOV_MAX) ? IOV_MAX : iov_index); - if ((nbytes = writev(fd, c_iov, iov_size)) < 0) { + nbytes = writev(fd, c_iov, iov_size); + if (nbytes < 0) { flog_err(EC_LIB_SOCKET, "%s: writev to fd %d failed: %s", __func__, fd, safe_strerror(errno)); @@ -370,7 +371,8 @@ buffer_status_t buffer_flush_window(struct buffer *b, int fd, int width, } } #else /* IOV_MAX */ - if ((nbytes = writev(fd, iov, iov_index)) < 0) + nbytes = writev(fd, iov, iov_index); + if (nbytes < 0) flog_err(EC_LIB_SOCKET, "%s: writev to fd %d failed: %s", __func__, fd, safe_strerror(errno)); #endif /* IOV_MAX */ @@ -472,13 +474,17 @@ buffer_status_t buffer_write(struct buffer *b, int fd, const void *p, /* Buffer is not empty, so do not attempt to write the new data. */ nbytes = 0; - else if ((nbytes = write(fd, p, size)) < 0) { - if (ERRNO_IO_RETRY(errno)) - nbytes = 0; - else { - flog_err(EC_LIB_SOCKET, "%s: write error on fd %d: %s", - __func__, fd, safe_strerror(errno)); - return BUFFER_ERROR; + else { + nbytes = write(fd, p, size); + if (nbytes < 0) { + if (ERRNO_IO_RETRY(errno)) + nbytes = 0; + else { + flog_err(EC_LIB_SOCKET, + "%s: write error on fd %d: %s", + __func__, fd, safe_strerror(errno)); + return BUFFER_ERROR; + } } } /* Add any remaining data to the buffer. */ diff --git a/lib/command.c b/lib/command.c index 122e189342..422544b70b 100644 --- a/lib/command.c +++ b/lib/command.c @@ -160,6 +160,9 @@ static bool vty_check_node_for_xpath_decrement(enum node_type target_node, || node == BGP_FLOWSPECV6_NODE)) return false; + if (target_node == INTERFACE_NODE && node == LINK_PARAMS_NODE) + return false; + return true; } diff --git a/lib/command.h b/lib/command.h index 13bd61e9fd..2b50bc2374 100644 --- a/lib/command.h +++ b/lib/command.h @@ -438,6 +438,8 @@ struct cmd_node { #define BFD_PROFILE_STR "BFD profile.\n" #define BFD_PROFILE_NAME_STR "BFD profile name.\n" #define SHARP_STR "Sharp Routing Protocol\n" +#define OSPF_GR_STR \ + "OSPF non-stop forwarding (NSF) also known as OSPF Graceful Restart\n" #define CMD_VNI_RANGE "(1-16777215)" #define CONF_BACKUP_EXT ".sav" @@ -641,7 +641,8 @@ static int get_memory_usage(pid_t pid) char *vm; snprintf(status_child, sizeof(status_child), "/proc/%d/status", pid); - if ((fd = open(status_child, O_RDONLY)) < 0) + fd = open(status_child, O_RDONLY); + if (fd < 0) return -1; read(fd, buf, 4095); diff --git a/lib/frr_zmq.c b/lib/frr_zmq.c index ce52848a25..ea9c828f7c 100644 --- a/lib/frr_zmq.c +++ b/lib/frr_zmq.c @@ -17,6 +17,14 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +/* + * IF YOU MODIFY THIS FILE PLEASE RUN `make check` and ensure that + * the test_zmq.c unit test is still working. There are dependancies + * between the two that are extremely fragile. My understanding + * is that there is specialized ownership of the cb pointer based + * upon what is happening. Those assumptions are supposed to be + * tested in the test_zmq.c + */ #include <zebra.h> #include <zmq.h> @@ -309,8 +317,22 @@ void frrzmq_thread_cancel(struct frrzmq_cb **cb, struct cb_core *core) core->cancelled = true; thread_cancel(&core->thread); + /* + * Looking at this code one would assume that FRR + * would want a `!(*cb)->write.thread. This was + * attempted in e08165def1c62beee0e87385 but this + * change caused `make check` to stop working + * which was not noticed because our CI system + * does not build with zeromq. Put this back + * to the code as written in 2017. e08165de.. + * was introduced in 2021. So someone was ok + * with frrzmq_thread_cancel for 4 years. This will + * allow those people doing `make check` to continue + * working. In the meantime if the people using + * this code see an issue they can fix it + */ if ((*cb)->read.cancelled && !(*cb)->read.thread - && (*cb)->write.cancelled && !(*cb)->write.thread) + && (*cb)->write.cancelled && (*cb)->write.thread) XFREE(MTYPE_ZEROMQ_CB, *cb); } diff --git a/lib/libfrr.c b/lib/libfrr.c index 0817182f7a..97dab74d9b 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -44,6 +44,7 @@ #include "frr_pthread.h" #include "defaults.h" #include "frrscript.h" +#include "systemd.h" DEFINE_HOOK(frr_late_init, (struct thread_master * tm), (tm)); DEFINE_HOOK(frr_config_pre, (struct thread_master * tm), (tm)); @@ -363,6 +364,11 @@ void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv) startup_fds |= UINT64_C(0x1) << (uint64_t)i; } + + /* note this doesn't do anything, it just grabs state, so doing it + * early in _preinit is perfect. + */ + systemd_init_env(); } bool frr_is_startup_fd(int fd) diff --git a/lib/link_state.c b/lib/link_state.c index e8a6b89f89..062384aac7 100644 --- a/lib/link_state.c +++ b/lib/link_state.c @@ -538,8 +538,6 @@ struct ls_edge *ls_edge_add(struct ls_ted *ted, /* Create Edge and add it to the TED */ new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_edge)); - if (!new) - return NULL; new->attributes = attributes; new->key = key; @@ -804,8 +802,6 @@ struct ls_ted *ls_ted_new(const uint32_t key, const char *name, struct ls_ted *new; new = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_ted)); - if (new == NULL) - return new; /* Set basic information for this ted */ new->key = key; @@ -1005,8 +1001,6 @@ static struct ls_node *ls_parse_node(struct stream *s) size_t len; node = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_node)); - if (node == NULL) - return NULL; STREAM_GET(&node->adv, s, sizeof(struct ls_node_id)); STREAM_GETW(s, node->flags); @@ -1051,8 +1045,6 @@ static struct ls_attributes *ls_parse_attributes(struct stream *s) size_t len; attr = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_attributes)); - if (attr == NULL) - return NULL; attr->srlgs = NULL; STREAM_GET(&attr->adv, s, sizeof(struct ls_node_id)); @@ -1157,8 +1149,6 @@ static struct ls_prefix *ls_parse_prefix(struct stream *s) size_t len; ls_pref = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_prefix)); - if (ls_pref == NULL) - return NULL; STREAM_GET(&ls_pref->adv, s, sizeof(struct ls_node_id)); STREAM_GETW(s, ls_pref->flags); @@ -1193,8 +1183,6 @@ struct ls_message *ls_parse_msg(struct stream *s) struct ls_message *msg; msg = XCALLOC(MTYPE_LS_DB, sizeof(struct ls_message)); - if (msg == NULL) - return NULL; /* Read LS Message header */ STREAM_GETC(s, msg->event); diff --git a/lib/network.c b/lib/network.c index 411661a5e1..b60ad9a57c 100644 --- a/lib/network.c +++ b/lib/network.c @@ -78,7 +78,8 @@ int set_nonblocking(int fd) /* According to the Single UNIX Spec, the return value for F_GETFL should never be negative. */ - if ((flags = fcntl(fd, F_GETFL)) < 0) { + flags = fcntl(fd, F_GETFL); + if (flags < 0) { flog_err(EC_LIB_SYSTEM_CALL, "fcntl(F_GETFL) failed for fd %d: %s", fd, safe_strerror(errno)); diff --git a/lib/ntop.c b/lib/ntop.c index ccbf8793d3..1b2dd7a6d1 100644 --- a/lib/ntop.c +++ b/lib/ntop.c @@ -40,14 +40,18 @@ static inline void putbyte(uint8_t bytex, char **posx) bool zero = false; int byte = bytex, tmp, a, b; - if ((tmp = byte - 200) >= 0) { + tmp = byte - 200; + if (tmp >= 0) { *pos++ = '2'; zero = true; byte = tmp; - } else if ((tmp = byte - 100) >= 0) { - *pos++ = '1'; - zero = true; - byte = tmp; + } else { + tmp = byte - 100; + if (tmp >= 0) { + *pos++ = '1'; + zero = true; + byte = tmp; + } } /* make sure the compiler knows the value range of "byte" */ @@ -49,7 +49,8 @@ struct pbr_filter { #define PBR_FILTER_PROTO (1 << 5) #define PBR_FILTER_SRC_PORT_RANGE (1 << 6) #define PBR_FILTER_DST_PORT_RANGE (1 << 7) -#define PBR_FILTER_DSFIELD (1 << 8) +#define PBR_FILTER_DSFIELD (1 << 8) +#define PBR_FILTER_IP_PROTOCOL (1 << 9) #define PBR_DSFIELD_DSCP (0xfc) /* Upper 6 bits of DS field: DSCP */ #define PBR_DSFIELD_ECN (0x03) /* Lower 2 bits of DS field: BCN */ @@ -67,6 +68,9 @@ struct pbr_filter { /* Filter with fwmark */ uint32_t fwmark; + + /* Filter with the ip protocol */ + uint8_t ip_proto; }; /* diff --git a/lib/plist.c b/lib/plist.c index 0ee02f8a0b..2b42c43764 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -750,7 +750,7 @@ static const char *prefix_list_type_str(struct prefix_list_entry *pentry) } static int prefix_list_entry_match(struct prefix_list_entry *pentry, - const struct prefix *p) + const struct prefix *p, bool address_mode) { int ret; @@ -761,6 +761,9 @@ static int prefix_list_entry_match(struct prefix_list_entry *pentry, if (!ret) return 0; + if (address_mode) + return 1; + /* In case of le nor ge is specified, exact match is performed. */ if (!pentry->le && !pentry->ge) { if (pentry->prefix.prefixlen != p->prefixlen) @@ -777,14 +780,15 @@ static int prefix_list_entry_match(struct prefix_list_entry *pentry, return 1; } -enum prefix_list_type prefix_list_apply_which_prefix( +enum prefix_list_type prefix_list_apply_ext( struct prefix_list *plist, - const struct prefix **which, - const void *object) + const struct prefix_list_entry **which, + union prefixconstptr object, + bool address_mode) { struct prefix_list_entry *pentry, *pbest = NULL; - const struct prefix *p = (const struct prefix *)object; + const struct prefix *p = object.p; const uint8_t *byte = p->u.val; size_t depth; size_t validbits = p->prefixlen; @@ -809,7 +813,7 @@ enum prefix_list_type prefix_list_apply_which_prefix( pentry = pentry->next_best) { if (pbest && pbest->seq < pentry->seq) continue; - if (prefix_list_entry_match(pentry, p)) + if (prefix_list_entry_match(pentry, p, address_mode)) pbest = pentry; } @@ -830,7 +834,7 @@ enum prefix_list_type prefix_list_apply_which_prefix( pentry = pentry->next_best) { if (pbest && pbest->seq < pentry->seq) continue; - if (prefix_list_entry_match(pentry, p)) + if (prefix_list_entry_match(pentry, p, address_mode)) pbest = pentry; } break; @@ -838,7 +842,7 @@ enum prefix_list_type prefix_list_apply_which_prefix( if (which) { if (pbest) - *which = &pbest->prefix; + *which = pbest; else *which = NULL; } @@ -1296,6 +1300,51 @@ DEFPY (clear_ipv6_prefix_list, return vty_clear_prefix_list(vty, AFI_IP6, prefix_list, prefix_str); } +DEFPY (debug_prefix_list_match, + debug_prefix_list_match_cmd, + "debug prefix-list WORD$prefix-list match <A.B.C.D/M|X:X::X:X/M>" + " [address-mode$addr_mode]", + DEBUG_STR + "Prefix-list test access\n" + "Name of a prefix list\n" + "Test prefix for prefix list result\n" + "Prefix to test in ip prefix-list\n" + "Prefix to test in ipv6 prefix-list\n" + "Use address matching mode (PIM RP)\n") +{ + struct prefix_list *plist; + const struct prefix_list_entry *entry = NULL; + enum prefix_list_type ret; + + plist = prefix_list_lookup(family2afi(match->family), prefix_list); + if (!plist) { + vty_out(vty, "%% no prefix list named %s for AFI %s\n", + prefix_list, afi2str(family2afi(match->family))); + return CMD_WARNING; + } + + ret = prefix_list_apply_ext(plist, &entry, match, !!addr_mode); + + vty_out(vty, "%s prefix list %s yields %s for %pFX, ", + afi2str(family2afi(match->family)), prefix_list, + ret == PREFIX_DENY ? "DENY" : "PERMIT", match); + + if (!entry) + vty_out(vty, "no match found\n"); + else { + vty_out(vty, "matching entry #%"PRId64": %pFX", entry->seq, + &entry->prefix); + if (entry->ge) + vty_out(vty, " ge %d", entry->ge); + if (entry->le) + vty_out(vty, " le %d", entry->le); + vty_out(vty, "\n"); + } + + /* allow using this in scripts for quick prefix-list member tests */ + return (ret == PREFIX_PERMIT) ? CMD_SUCCESS : CMD_WARNING; +} + struct stream *prefix_bgp_orf_entry(struct stream *s, struct prefix_list *plist, uint8_t init_flag, uint8_t permit_flag, uint8_t deny_flag) @@ -1537,6 +1586,7 @@ static void prefix_list_init_ipv6(void) install_element(VIEW_NODE, &show_ipv6_prefix_list_prefix_cmd); install_element(VIEW_NODE, &show_ipv6_prefix_list_summary_cmd); install_element(VIEW_NODE, &show_ipv6_prefix_list_detail_cmd); + install_element(VIEW_NODE, &debug_prefix_list_match_cmd); install_element(ENABLE_NODE, &clear_ipv6_prefix_list_cmd); } diff --git a/lib/plist.h b/lib/plist.h index 57eb763a68..c9507df57c 100644 --- a/lib/plist.h +++ b/lib/plist.h @@ -37,6 +37,7 @@ enum prefix_list_type { }; struct prefix_list; +struct prefix_list_entry; struct orf_prefix { uint32_t seq; @@ -63,12 +64,18 @@ extern struct prefix_list *prefix_list_lookup(afi_t, const char *); * * If no pointer is sent in, do not return anything. * If it is a empty plist return a NULL pointer. + * + * address_mode = the "prefix" being passed in is really an address, match + * regardless of prefix length (i.e. ge/le are ignored.) prefix->prefixlen + * must be /32. */ extern enum prefix_list_type -prefix_list_apply_which_prefix(struct prefix_list *plist, - const struct prefix **which, - const void *object); -#define prefix_list_apply(A, B) prefix_list_apply_which_prefix((A), NULL, (B)) +prefix_list_apply_ext(struct prefix_list *plist, + const struct prefix_list_entry **matches, + union prefixconstptr prefix, + bool address_mode); +#define prefix_list_apply(A, B) \ + prefix_list_apply_ext((A), NULL, (B), false) extern struct prefix_list *prefix_bgp_orf_lookup(afi_t, const char *); extern struct stream *prefix_bgp_orf_entry(struct stream *, diff --git a/lib/prefix.c b/lib/prefix.c index 1c57715e8f..ef7d2e59da 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -1034,7 +1034,8 @@ const char *prefix2str(union prefixconstptr pu, char *str, int size) l = strlen(buf); buf[l++] = '/'; byte = p->prefixlen; - if ((tmp = p->prefixlen - 100) >= 0) { + tmp = p->prefixlen - 100; + if (tmp >= 0) { buf[l++] = '1'; z = true; byte = tmp; diff --git a/lib/prefix.h b/lib/prefix.h index bc4cb7f441..944c94f57f 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -537,20 +537,32 @@ static inline int ipv4_martian(struct in_addr *addr) return 0; } -static inline int is_default_prefix(const struct prefix *p) +static inline bool is_default_prefix4(const struct prefix_ipv4 *p) { - if (!p) - return 0; + return p && p->family == AF_INET && p->prefixlen == 0 + && p->prefix.s_addr == INADDR_ANY; +} - if ((p->family == AF_INET) && (p->u.prefix4.s_addr == INADDR_ANY) - && (p->prefixlen == 0)) - return 1; +static inline bool is_default_prefix6(const struct prefix_ipv6 *p) +{ + return p && p->family == AF_INET6 && p->prefixlen == 0 + && memcmp(&p->prefix, &in6addr_any, sizeof(struct in6_addr)) + == 0; +} - if ((p->family == AF_INET6) && (p->prefixlen == 0) - && (!memcmp(&p->u.prefix6, &in6addr_any, sizeof(struct in6_addr)))) - return 1; +static inline bool is_default_prefix(const struct prefix *p) +{ + if (p == NULL) + return false; + + switch (p->family) { + case AF_INET: + return is_default_prefix4((const struct prefix_ipv4 *)p); + case AF_INET6: + return is_default_prefix6((const struct prefix_ipv6 *)p); + } - return 0; + return false; } static inline int is_host_route(const struct prefix *p) diff --git a/lib/route_types.txt b/lib/route_types.txt index c48391545d..77639070c9 100644 --- a/lib/route_types.txt +++ b/lib/route_types.txt @@ -1,4 +1,4 @@ -# Canonical Zserv route types information registry for Quagga. +# Canonical Zserv route types information registry for FRR. # # Used to construct route_types.c and route_types.h # @@ -60,7 +60,7 @@ ZEBRA_ROUTE_PIM, pim, pimd, 'P', 0, 0, 0, "PIM", pimd ZEBRA_ROUTE_EIGRP, eigrp, eigrpd, 'E', 1, 0, 1, "EIGRP", eigrpd ZEBRA_ROUTE_NHRP, nhrp, nhrpd, 'N', 1, 1, 1, "NHRP", nhrpd # HSLS and OLSR both are AFI independent (so: 1, 1), however -# we want to disable for them for general Quagga distribution. +# we want to disable for them for general FRR distribution. # This at least makes it trivial for users of these protocols # to 'switch on' redist support (direct numeric entry remaining # possible). diff --git a/lib/routemap.h b/lib/routemap.h index 4a40ec08b9..8af3b2c3c0 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -270,6 +270,7 @@ DECLARE_QOBJ_TYPE(route_map); /* BGP route-map match conditions */ #define IS_MATCH_LOCAL_PREF(C) \ (strmatch(C, "frr-bgp-route-map:match-local-preference")) +#define IS_MATCH_ALIAS(C) (strmatch(C, "frr-bgp-route-map:match-alias")) #define IS_MATCH_ORIGIN(C) \ (strmatch(C, "frr-bgp-route-map:match-origin")) #define IS_MATCH_RPKI(C) (strmatch(C, "frr-bgp-route-map:rpki")) diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c index bf982cfa2b..ec9033b3aa 100644 --- a/lib/routemap_cli.c +++ b/lib/routemap_cli.c @@ -634,6 +634,11 @@ void route_map_condition_show(struct vty *vty, struct lyd_node *dnode, yang_dnode_get_string( dnode, "./rmap-match-condition/frr-bgp-route-map:local-preference")); + } else if (IS_MATCH_ALIAS(condition)) { + vty_out(vty, " match alias %s\n", + yang_dnode_get_string( + dnode, + "./rmap-match-condition/frr-bgp-route-map:alias")); } else if (IS_MATCH_ORIGIN(condition)) { vty_out(vty, " match origin %s\n", yang_dnode_get_string( diff --git a/lib/sockopt.c b/lib/sockopt.c index 98bfda5079..150736e00c 100644 --- a/lib/sockopt.c +++ b/lib/sockopt.c @@ -379,14 +379,14 @@ static int setsockopt_ipv4_ifindex(int sock, ifindex_t val) int ret; #if defined(IP_PKTINFO) - if ((ret = setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val))) - < 0) + ret = setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val)); + if (ret < 0) flog_err(EC_LIB_SOCKET, "Can't set IP_PKTINFO option for fd %d to %d: %s", sock, val, safe_strerror(errno)); #elif defined(IP_RECVIF) - if ((ret = setsockopt(sock, IPPROTO_IP, IP_RECVIF, &val, sizeof(val))) - < 0) + ret = setsockopt(sock, IPPROTO_IP, IP_RECVIF, &val, sizeof(val)); + if (ret < 0) flog_err(EC_LIB_SOCKET, "Can't set IP_RECVIF option for fd %d to %d: %s", sock, val, safe_strerror(errno)); @@ -639,12 +639,8 @@ int sockopt_tcp_signature_ext(int sock, union sockunion *su, uint16_t prefixlen, #endif /* GNU_LINUX */ - if ((ret = setsockopt(sock, IPPROTO_TCP, optname, &md5sig, - sizeof(md5sig))) - < 0) { - /* ENOENT is harmless. It is returned when we clear a password - for which - one was not previously set. */ + ret = setsockopt(sock, IPPROTO_TCP, optname, &md5sig, sizeof(md5sig)); + if (ret < 0) { if (ENOENT == errno) ret = 0; else diff --git a/lib/stream.c b/lib/stream.c index 904ee73b10..1557500c60 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -1097,7 +1097,8 @@ ssize_t stream_read_try(struct stream *s, int fd, size_t size) return -1; } - if ((nbytes = read(fd, s->data + s->endp, size)) >= 0) { + nbytes = read(fd, s->data + s->endp, size); + if (nbytes >= 0) { s->endp += nbytes; return nbytes; } @@ -1126,9 +1127,8 @@ ssize_t stream_recvfrom(struct stream *s, int fd, size_t size, int flags, return -1; } - if ((nbytes = recvfrom(fd, s->data + s->endp, size, flags, from, - fromlen)) - >= 0) { + nbytes = recvfrom(fd, s->data + s->endp, size, flags, from, fromlen); + if (nbytes >= 0) { s->endp += nbytes; return nbytes; } diff --git a/lib/subdir.am b/lib/subdir.am index 90301d800a..714af43238 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -2,7 +2,7 @@ # libfrr # lib_LTLIBRARIES += lib/libfrr.la -lib_libfrr_la_LDFLAGS = -version-info 0:0:0 -Xlinker -e_libfrr_version +lib_libfrr_la_LDFLAGS = $(LIB_LDFLAGS) -version-info 0:0:0 -Xlinker -e_libfrr_version lib_libfrr_la_LIBADD = $(LIBCAP) $(UNWIND_LIBS) $(LIBYANG_LIBS) $(LUA_LIB) $(UST_LIBS) $(LIBM) lib_libfrr_la_SOURCES = \ @@ -322,7 +322,7 @@ lib_LTLIBRARIES += lib/libfrrsnmp.la endif lib_libfrrsnmp_la_CFLAGS = $(AM_CFLAGS) $(SNMP_CFLAGS) -std=gnu11 -lib_libfrrsnmp_la_LDFLAGS = -version-info 0:0:0 +lib_libfrrsnmp_la_LDFLAGS = $(LIB_LDFLAGS) -version-info 0:0:0 lib_libfrrsnmp_la_LIBADD = $(SNMP_LIBS) lib_libfrrsnmp_la_SOURCES = \ lib/agentx.c \ @@ -338,7 +338,7 @@ pkginclude_HEADERS += lib/resolver.h endif lib_libfrrcares_la_CFLAGS = $(AM_CFLAGS) $(CARES_CFLAGS) -lib_libfrrcares_la_LDFLAGS = -version-info 0:0:0 +lib_libfrrcares_la_LDFLAGS = $(LIB_LDFLAGS) -version-info 0:0:0 lib_libfrrcares_la_LIBADD = $(CARES_LIBS) lib_libfrrcares_la_SOURCES = \ lib/resolver.c \ @@ -353,7 +353,7 @@ pkginclude_HEADERS += lib/frr_zmq.h endif lib_libfrrzmq_la_CFLAGS = $(AM_CFLAGS) $(ZEROMQ_CFLAGS) -lib_libfrrzmq_la_LDFLAGS = -version-info 0:0:0 +lib_libfrrzmq_la_LDFLAGS = $(LIB_LDFLAGS) -version-info 0:0:0 lib_libfrrzmq_la_LIBADD = $(ZEROMQ_LIBS) lib_libfrrzmq_la_SOURCES = \ lib/frr_zmq.c \ @@ -367,7 +367,7 @@ module_LTLIBRARIES += lib/confd.la endif lib_confd_la_CFLAGS = $(AM_CFLAGS) $(CONFD_CFLAGS) -lib_confd_la_LDFLAGS = -avoid-version -module -shared -export-dynamic +lib_confd_la_LDFLAGS = $(MODULE_LDFLAGS) lib_confd_la_LIBADD = lib/libfrr.la $(CONFD_LIBS) lib_confd_la_SOURCES = lib/northbound_confd.c @@ -379,7 +379,7 @@ module_LTLIBRARIES += lib/sysrepo.la endif lib_sysrepo_la_CFLAGS = $(AM_CFLAGS) $(SYSREPO_CFLAGS) -lib_sysrepo_la_LDFLAGS = -avoid-version -module -shared -export-dynamic +lib_sysrepo_la_LDFLAGS = $(MODULE_LDFLAGS) lib_sysrepo_la_LIBADD = lib/libfrr.la $(SYSREPO_LIBS) lib_sysrepo_la_SOURCES = lib/northbound_sysrepo.c @@ -391,7 +391,7 @@ module_LTLIBRARIES += lib/grpc.la endif lib_grpc_la_CXXFLAGS = $(WERROR) $(GRPC_CFLAGS) -lib_grpc_la_LDFLAGS = -avoid-version -module -shared -export-dynamic +lib_grpc_la_LDFLAGS = $(MODULE_LDFLAGS) lib_grpc_la_LIBADD = lib/libfrr.la grpc/libfrrgrpc_pb.la $(GRPC_LIBS) lib_grpc_la_SOURCES = lib/northbound_grpc.cpp @@ -419,7 +419,8 @@ lib_grammar_sandbox_LDADD = \ lib_clippy_CPPFLAGS = $(CPPFLAGS_BASE) -D_GNU_SOURCE -DBUILDING_CLIPPY lib_clippy_CFLAGS = $(AC_CFLAGS) $(PYTHON_CFLAGS) lib_clippy_LDADD = $(PYTHON_LIBS) $(UST_LIBS) -lelf -lib_clippy_LDFLAGS = -export-dynamic +# no $(SAN_FLAGS) here +lib_clippy_LDFLAGS = -export-dynamic $(AC_LDFLAGS) $(AC_LDFLAGS_EXEC) lib_clippy_SOURCES = \ lib/jhash.c \ lib/clippy.c \ diff --git a/lib/systemd.c b/lib/systemd.c index c5cc3aa447..2238dc9f3d 100644 --- a/lib/systemd.c +++ b/lib/systemd.c @@ -20,68 +20,56 @@ */ #include <zebra.h> +#include <sys/un.h> #include "thread.h" #include "systemd.h" +#include "lib_errors.h" -#if defined HAVE_SYSTEMD -#include <systemd/sd-daemon.h> -#endif +/* these are cleared from env so they don't "leak" into things we fork(), + * particularly for watchfrr starting individual daemons + * + * watchdog_pid is currently not used since watchfrr starts forking. + * (TODO: handle that better, somehow?) + */ +static pid_t watchdog_pid = -1; +static intmax_t watchdog_msec; + +/* not used yet, but can trigger auto-switch to journald logging */ +bool sd_stdout_is_journal; +bool sd_stderr_is_journal; + +static char *notify_socket; -/* - * Wrapper this silliness if we - * don't have systemd +/* talk to whatever entity claims to be systemd ;) + * + * refer to sd_notify docs for messages systemd accepts over this socket. + * This function should be functionally equivalent to sd_notify(). */ static void systemd_send_information(const char *info) { -#if defined HAVE_SYSTEMD - sd_notify(0, info); -#else - return; -#endif -} + int sock; + struct sockaddr_un sun; -/* - * A return of 0 means that we are not watchdoged - */ -static int systemd_get_watchdog_time(int the_process) -{ -#if defined HAVE_SYSTEMD - uint64_t usec; - char *watchdog = NULL; - int ret; - - ret = sd_watchdog_enabled(0, &usec); - - /* - * If return is 0 -> we don't want watchdog - * if return is < 0, some sort of failure occurred - */ - if (ret < 0) - return 0; - - /* - * systemd can return that this process - * is not the expected sender of the watchdog timer - * If we set the_process = 0 then we expect to - * be able to send the watchdog to systemd - * irrelevant of the pid of this process. - */ - if (ret == 0 && the_process) - return 0; - - if (ret == 0 && !the_process) { - watchdog = getenv("WATCHDOG_USEC"); - if (!watchdog) - return 0; - - usec = atol(watchdog); - } + if (!notify_socket) + return; + + sock = socket(AF_UNIX, SOCK_DGRAM, 0); + if (sock < 0) + return; + + sun.sun_family = AF_UNIX; + strlcpy(sun.sun_path, notify_socket, sizeof(sun.sun_path)); - return (usec / 1000000) / 3; -#else - return 0; -#endif + /* linux abstract unix socket namespace */ + if (sun.sun_path[0] == '@') + sun.sun_path[0] = '\0'; + + /* nothing we can do if this errors out... */ + (void)sendto(sock, info, strlen(info), 0, (struct sockaddr *)&sun, + sizeof(sun)); + + close(sock); } void systemd_send_stopping(void) @@ -90,34 +78,27 @@ void systemd_send_stopping(void) systemd_send_information("STOPPING=1"); } -/* - * How many seconds should we wait between watchdog sends - */ -static int wsecs = 0; static struct thread_master *systemd_master = NULL; static int systemd_send_watchdog(struct thread *t) { systemd_send_information("WATCHDOG=1"); - thread_add_timer(systemd_master, systemd_send_watchdog, NULL, wsecs, - NULL); - + assert(watchdog_msec > 0); + thread_add_timer_msec(systemd_master, systemd_send_watchdog, NULL, + watchdog_msec, NULL); return 1; } -void systemd_send_started(struct thread_master *m, int the_process) +void systemd_send_started(struct thread_master *m) { assert(m != NULL); - wsecs = systemd_get_watchdog_time(the_process); systemd_master = m; systemd_send_information("READY=1"); - if (wsecs != 0) { - systemd_send_information("WATCHDOG=1"); - thread_add_timer(m, systemd_send_watchdog, m, wsecs, NULL); - } + if (watchdog_msec > 0) + systemd_send_watchdog(NULL); } void systemd_send_status(const char *status) @@ -127,3 +108,65 @@ void systemd_send_status(const char *status) snprintf(buffer, sizeof(buffer), "STATUS=%s", status); systemd_send_information(buffer); } + +static intmax_t getenv_int(const char *varname, intmax_t dflt) +{ + char *val, *err; + intmax_t intval; + + val = getenv(varname); + if (!val) + return dflt; + + intval = strtoimax(val, &err, 0); + if (*err || !*val) + return dflt; + return intval; +} + +void systemd_init_env(void) +{ + char *tmp; + uintmax_t dev, ino; + int len; + struct stat st; + + notify_socket = getenv("NOTIFY_SOCKET"); + + /* no point in setting up watchdog w/o notify socket */ + if (notify_socket) { + intmax_t watchdog_usec; + + watchdog_pid = getenv_int("WATCHDOG_PID", -1); + if (watchdog_pid <= 0) + watchdog_pid = -1; + + /* note this is the deadline, hence the divide by 3 */ + watchdog_usec = getenv_int("WATCHDOG_USEC", 0); + if (watchdog_usec >= 3000) + watchdog_msec = watchdog_usec / 3000; + else { + if (watchdog_usec != 0) + flog_err( + EC_LIB_UNAVAILABLE, + "systemd expects a %jd microsecond watchdog timer, but FRR only supports millisecond resolution!", + watchdog_usec); + watchdog_msec = 0; + } + } + + tmp = getenv("JOURNAL_STREAM"); + if (tmp && sscanf(tmp, "%ju:%ju%n", &dev, &ino, &len) == 2 + && (size_t)len == strlen(tmp)) { + if (fstat(1, &st) == 0 && st.st_dev == (dev_t)dev + && st.st_ino == (ino_t)ino) + sd_stdout_is_journal = true; + if (fstat(2, &st) == 0 && st.st_dev == (dev_t)dev + && st.st_ino == (ino_t)ino) + sd_stderr_is_journal = true; + } + + /* these should *not* be passed to any other process we start */ + unsetenv("WATCHDOG_PID"); + unsetenv("WATCHDOG_USEC"); +} diff --git a/lib/systemd.h b/lib/systemd.h index d9885c5d9c..1933f4f688 100644 --- a/lib/systemd.h +++ b/lib/systemd.h @@ -28,9 +28,6 @@ extern "C" { * * Design point is that if systemd is not being used on this system * then these functions becomes a no-op. - * - * To turn on systemd compilation, use --enable-systemd on - * configure run. */ void systemd_send_stopping(void); @@ -39,13 +36,18 @@ void systemd_send_stopping(void); * the_process - Should we send watchdog if we are not the requested * process? */ -void systemd_send_started(struct thread_master *master, int the_process); +void systemd_send_started(struct thread_master *master); /* * status - A status string to send to systemd */ void systemd_send_status(const char *status); +/* + * grab startup state from env vars + */ +void systemd_init_env(void); + #ifdef __cplusplus } #endif diff --git a/lib/zclient.c b/lib/zclient.c index 1b4ac080cd..0815e77d4e 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1537,7 +1537,7 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api) if (CHECK_FLAG(api->message, ZAPI_MESSAGE_OPAQUE)) { STREAM_GETW(s, api->opaque.length); - assert(api->opaque.length < ZAPI_MESSAGE_OPAQUE_LENGTH); + assert(api->opaque.length <= ZAPI_MESSAGE_OPAQUE_LENGTH); STREAM_GET(api->opaque.data, s, api->opaque.length); } @@ -3812,7 +3812,8 @@ static int zclient_read(struct thread *thread) zclient->t_read = NULL; /* Read zebra header (if we don't have it already). */ - if ((already = stream_get_endp(zclient->ibuf)) < ZEBRA_HEADER_SIZE) { + already = stream_get_endp(zclient->ibuf); + if (already < ZEBRA_HEADER_SIZE) { ssize_t nbyte; if (((nbyte = stream_read_try(zclient->ibuf, zclient->sock, ZEBRA_HEADER_SIZE - already)) @@ -3825,7 +3826,6 @@ static int zclient_read(struct thread *thread) return zclient_failed(zclient); } if (nbyte != (ssize_t)(ZEBRA_HEADER_SIZE - already)) { - /* Try again later. */ zclient_event(ZCLIENT_READ, zclient); return 0; } |
