diff options
42 files changed, 1089 insertions, 815 deletions
diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c index a200589bd3..1be7eff560 100644 --- a/bgpd/bgp_bfd.c +++ b/bgpd/bgp_bfd.c @@ -207,15 +207,9 @@ static void bgp_bfd_update_peer(struct peer *peer) */ void bgp_bfd_reset_peer(struct peer *peer) { - struct bfd_info *bfd_info; - if (!peer->bfd_info) return; - bfd_info = (struct bfd_info *)peer->bfd_info; - /* if status is not down, reset bfd */ - if (bfd_info->status != BFD_STATUS_DOWN) - bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_DEREGISTER); bgp_bfd_peer_sendmsg(peer, ZEBRA_BFD_DEST_REGISTER); } diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index 8902a8789a..fb4c50e3ef 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -859,7 +859,9 @@ static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags, { struct stream *hdr, *msg; struct timeval tv = { .tv_sec = uptime, .tv_usec = 0 }; + struct timeval uptime_real; + monotime_to_realtime(&tv, &uptime_real); if (attr) msg = bmp_update(p, peer, attr, afi, safi); else @@ -867,7 +869,7 @@ static void bmp_monitor(struct bmp *bmp, struct peer *peer, uint8_t flags, hdr = stream_new(BGP_MAX_PACKET_SIZE); bmp_common_hdr(hdr, BMP_VERSION_3, BMP_TYPE_ROUTE_MONITORING); - bmp_per_peer_hdr(hdr, peer, flags, &tv); + bmp_per_peer_hdr(hdr, peer, flags, &uptime_real); stream_putl_at(hdr, BMP_LENGTH_POS, stream_get_endp(hdr) + stream_get_endp(msg)); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index b0fbdbcf01..94a305760a 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -3239,6 +3239,9 @@ bool bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi, struct bgp_node *rn) { bool ret = false; + bool is_bgp_static_route = + (type == ZEBRA_ROUTE_BGP && stype == BGP_ROUTE_STATIC) ? true + : false; /* Only validated for unicast and multicast currently. */ /* Also valid for EVPN where the nexthop is an IP address. */ @@ -3247,7 +3250,7 @@ bool bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi, /* If NEXT_HOP is present, validate it. */ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) { - if (attr->nexthop.s_addr == INADDR_ANY + if ((attr->nexthop.s_addr == INADDR_ANY && !is_bgp_static_route) || IPV4_CLASS_DE(ntohl(attr->nexthop.s_addr)) || bgp_nexthop_self(bgp, afi, type, stype, attr, rn)) return true; @@ -3266,7 +3269,8 @@ bool bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi, switch (attr->mp_nexthop_len) { case BGP_ATTR_NHLEN_IPV4: case BGP_ATTR_NHLEN_VPNV4: - ret = (attr->mp_nexthop_global_in.s_addr == INADDR_ANY + ret = ((attr->mp_nexthop_global_in.s_addr == INADDR_ANY + && !is_bgp_static_route) || IPV4_CLASS_DE( ntohl(attr->mp_nexthop_global_in.s_addr)) || bgp_nexthop_self(bgp, afi, type, stype, attr, @@ -3275,12 +3279,14 @@ bool bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi, case BGP_ATTR_NHLEN_IPV6_GLOBAL: case BGP_ATTR_NHLEN_VPNV6_GLOBAL: - ret = (IN6_IS_ADDR_UNSPECIFIED(&attr->mp_nexthop_global) + ret = ((IN6_IS_ADDR_UNSPECIFIED( + &attr->mp_nexthop_global) + && !is_bgp_static_route) || IN6_IS_ADDR_LOOPBACK(&attr->mp_nexthop_global) || IN6_IS_ADDR_MULTICAST( - &attr->mp_nexthop_global) - || bgp_nexthop_self(bgp, afi, type, stype, - attr, rn)); + &attr->mp_nexthop_global) + || bgp_nexthop_self(bgp, afi, type, stype, attr, + rn)); break; case BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL: ret = (IN6_IS_ADDR_LOOPBACK(&attr->mp_nexthop_global) diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c index 1ba07e95e6..3228b38990 100644 --- a/bgpd/bgp_rpki.c +++ b/bgpd/bgp_rpki.c @@ -402,25 +402,23 @@ static int bgpd_sync_callback(struct thread *thread) if (!peer->bgp->rib[afi][safi]) continue; - struct list *matches = list_new(); - - matches->del = - (void (*)(void *))bgp_unlock_node; - - bgp_table_range_lookup( - peer->bgp->rib[afi][safi], prefix, - rec.max_len, matches); - - - struct bgp_node *bgp_node; - struct listnode *bgp_listnode; - - for (ALL_LIST_ELEMENTS_RO(matches, bgp_listnode, - bgp_node)) - revalidate_bgp_node(bgp_node, afi, - safi); - - list_delete(&matches); + struct bgp_node *match; + struct bgp_node *node; + + match = bgp_table_subtree_lookup( + peer->bgp->rib[afi][safi], prefix); + node = match; + + while (node) { + if (bgp_node_has_bgp_path_info_data( + node)) { + revalidate_bgp_node(node, afi, + safi); + } + + node = bgp_route_next_until(node, + match); + } } } } @@ -811,7 +809,7 @@ static int add_tcp_cache(const char *host, const char *port, { struct rtr_socket *rtr_socket; struct tr_tcp_config *tcp_config = - XMALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct tr_tcp_config)); + XCALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct tr_tcp_config)); struct tr_socket *tr_socket = XMALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct tr_socket)); struct cache *cache = @@ -845,7 +843,7 @@ static int add_ssh_cache(const char *host, const unsigned int port, const uint8_t preference) { struct tr_ssh_config *ssh_config = - XMALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct tr_ssh_config)); + XCALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct tr_ssh_config)); struct cache *cache = XMALLOC(MTYPE_BGP_RPKI_CACHE, sizeof(struct cache)); struct tr_socket *tr_socket = diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c index dcf9852a67..8acd42ffc0 100644 --- a/bgpd/bgp_table.c +++ b/bgpd/bgp_table.c @@ -164,90 +164,42 @@ void bgp_delete_listnode(struct bgp_node *node) } } -static struct bgp_node * -bgp_route_next_until_maxlen(struct bgp_node *node, const struct bgp_node *limit, - const uint8_t maxlen) +struct bgp_node *bgp_table_subtree_lookup(const struct bgp_table *table, + const struct prefix *p) { - const struct prefix *p = bgp_node_get_prefix(node); + struct bgp_node *node = bgp_node_from_rnode(table->route_table->top); + struct bgp_node *matched = NULL; - if (node->l_left) { - const struct prefix *left_p = - bgp_node_get_prefix(bgp_node_from_rnode(node->l_left)); + if (node == NULL) + return NULL; - if (p->prefixlen < maxlen && left_p->prefixlen <= maxlen) - return bgp_node_from_rnode(node->l_left); - } - if (node->l_right) { - const struct prefix *right_p = - bgp_node_get_prefix(bgp_node_from_rnode(node->l_right)); + while (node) { + const struct prefix *node_p = bgp_node_get_prefix(node); - if (p->prefixlen < maxlen && right_p->prefixlen <= maxlen) - return bgp_node_from_rnode(node->l_right); - } + if (node_p->prefixlen >= p->prefixlen) { + if (!prefix_match(p, node_p)) + return NULL; - while (node->parent && node != limit) { - if (bgp_node_from_rnode(node->parent->l_left) == node - && node->parent->l_right) { - return bgp_node_from_rnode(node->parent->l_right); + matched = node; + break; } - node = bgp_node_from_rnode(node->parent); - } - return NULL; -} -void bgp_table_range_lookup(const struct bgp_table *table, - const struct prefix *p, - uint8_t maxlen, struct list *matches) -{ - struct bgp_node *node = bgp_node_from_rnode(table->route_table->top); - struct bgp_node *matched = NULL; + if (!prefix_match(node_p, p)) + return NULL; - if (node == NULL) - return; - - const struct prefix *node_p = bgp_node_get_prefix(node); - - while (node && node_p->prefixlen <= p->prefixlen - && prefix_match(node_p, p)) { - if (bgp_node_has_bgp_path_info_data(node) - && node_p->prefixlen == p->prefixlen) { + if (node_p->prefixlen == p->prefixlen) { matched = node; break; } + node = bgp_node_from_rnode(node->link[prefix_bit( &p->u.prefix, node_p->prefixlen)]); - node_p = bgp_node_get_prefix(node); } - if (!node) - return; - - node_p = bgp_node_get_prefix(node); - if (matched == NULL && node_p->prefixlen <= maxlen - && prefix_match(p, node_p) && node->parent == NULL) - matched = node; - else if ((matched == NULL && node_p->prefixlen > maxlen) - || !node->parent) - return; - else if (matched == NULL && node->parent) - matched = node = bgp_node_from_rnode(node->parent); - if (!matched) - return; - - if (bgp_node_has_bgp_path_info_data(matched)) { - bgp_lock_node(matched); - listnode_add(matches, matched); - } + return NULL; - while ((node = bgp_route_next_until_maxlen(node, matched, maxlen))) { - node_p = bgp_node_get_prefix(node); - if (prefix_match(p, node_p)) { - if (bgp_node_has_bgp_path_info_data(node)) { - bgp_lock_node(node); - listnode_add(matches, node); - } - } - } + bgp_lock_node(matched); + return matched; } diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h index da2ca3181a..c35833e66b 100644 --- a/bgpd/bgp_table.h +++ b/bgpd/bgp_table.h @@ -347,9 +347,15 @@ static inline uint64_t bgp_table_version(struct bgp_table *table) return table->version; } -void bgp_table_range_lookup(const struct bgp_table *table, - const struct prefix *p, - uint8_t maxlen, struct list *matches); +/* Find the subtree of the prefix p + * + * This will return the first node that belongs the the subtree of p. Including + * p itself, if it is in the tree. + * + * If the subtree is not present in the table, NULL is returned. + */ +struct bgp_node *bgp_table_subtree_lookup(const struct bgp_table *table, + const struct prefix *p); static inline struct bgp_aggregate * diff --git a/configure.ac b/configure.ac index d4c652c6e5..3c65bc91a0 100755 --- a/configure.ac +++ b/configure.ac @@ -645,6 +645,9 @@ AC_ARG_WITH([crypto], AC_ARG_WITH([frr-format], AS_HELP_STRING([--with-frr-format[=<.../frr-format.so>]], [use frr-format GCC plugin])) +AC_ARG_ENABLE([version-build-config], + AS_HELP_STRING([--disable-version-build-config], [do not include build configs in show version command])) + #if openssl, else use the internal AS_IF([test "$with_crypto" = "openssl"], [ AC_CHECK_LIB([crypto], [EVP_DigestInit], [LIBS="$LIBS -lcrypto"], [], []) @@ -1682,6 +1685,10 @@ case "${enable_bmp}" in ;; esac +if test "$enable_version_build_config" != "no";then + AC_DEFINE([ENABLE_VERSION_BUILD_CONFIG], [1], [Report build configs in show version]) +fi + dnl ########################################################################## dnl LARGE if block if test "$enable_clippy_only" != "yes"; then diff --git a/doc/user/installation.rst b/doc/user/installation.rst index 9cd1210529..622af67b0f 100644 --- a/doc/user/installation.rst +++ b/doc/user/installation.rst @@ -279,6 +279,18 @@ options from the list below. With this option, we provide a way to strip out these characters for APK dev package builds. +..option:: --disable-version-build-config + + Remove the "configuerd with" field that has all of the build configuration + arguments when reporting the version string in `show version` command. + +..option:: --with-pkg-extra-version=VER + Add extra version field, for packagers/distributions + +..option:: --with-pkg-git-version + + Add git information to MOTD and build version string + .. option:: --enable-multipath=X Compile FRR with up to X way ECMP supported. This number can be from 0-999. diff --git a/doc/user/sharp.rst b/doc/user/sharp.rst index dd0e67d4b7..1c474193f2 100644 --- a/doc/user/sharp.rst +++ b/doc/user/sharp.rst @@ -125,3 +125,15 @@ keyword. At present, no sharp commands will be preserved in the config. single subtype. The messages must specify a protocol daemon by name, and can include optional zapi ``instance`` and ``session`` values. + +.. index:: sharp create session +.. clicmd:: sharp create session (1-1024) + + Create an additional zapi client session for testing, using the + specified session id. + +.. index:: sharp remove session +.. clicmd:: sharp remove session (1-1024) + + Remove a test zapi client session that was created with the + specified session id. diff --git a/isisd/isis_route.c b/isisd/isis_route.c index fa6af6c216..ffb5bdb357 100644 --- a/isisd/isis_route.c +++ b/isisd/isis_route.c @@ -355,7 +355,7 @@ static void isis_route_update(struct isis_area *area, struct prefix *prefix, if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) return; - isis_zebra_route_add_route(prefix, src_p, route_info); + isis_zebra_route_add_route(area->isis, prefix, src_p, route_info); hook_call(isis_route_update_hook, area, prefix, route_info); SET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); @@ -364,7 +364,7 @@ static void isis_route_update(struct isis_area *area, struct prefix *prefix, if (!CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED)) return; - isis_zebra_route_del_route(prefix, src_p, route_info); + isis_zebra_route_del_route(area->isis, prefix, src_p, route_info); hook_call(isis_route_update_hook, area, prefix, route_info); UNSET_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED); diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index db0efcaf5a..a80a18d887 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -151,7 +151,8 @@ static int isis_zebra_link_params(ZAPI_CALLBACK_ARGS) return 0; } -void isis_zebra_route_add_route(struct prefix *prefix, +void isis_zebra_route_add_route(struct isis *isis, + struct prefix *prefix, struct prefix_ipv6 *src_p, struct isis_route_info *route_info) { @@ -165,7 +166,7 @@ void isis_zebra_route_add_route(struct prefix *prefix, return; memset(&api, 0, sizeof(api)); - api.vrf_id = VRF_DEFAULT; + api.vrf_id = isis->vrf_id; api.type = PROTO_TYPE; api.safi = SAFI_UNICAST; api.prefix = *prefix; @@ -188,7 +189,7 @@ void isis_zebra_route_add_route(struct prefix *prefix, api_nh = &api.nexthops[count]; if (fabricd) SET_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK); - api_nh->vrf_id = VRF_DEFAULT; + api_nh->vrf_id = isis->vrf_id; switch (nexthop->family) { case AF_INET: @@ -226,7 +227,8 @@ void isis_zebra_route_add_route(struct prefix *prefix, zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); } -void isis_zebra_route_del_route(struct prefix *prefix, +void isis_zebra_route_del_route(struct isis *isis, + struct prefix *prefix, struct prefix_ipv6 *src_p, struct isis_route_info *route_info) { @@ -236,7 +238,7 @@ void isis_zebra_route_del_route(struct prefix *prefix, return; memset(&api, 0, sizeof(api)); - api.vrf_id = VRF_DEFAULT; + api.vrf_id = isis->vrf_id; api.type = PROTO_TYPE; api.safi = SAFI_UNICAST; api.prefix = *prefix; diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h index fd1c1df610..4449b63c2e 100644 --- a/isisd/isis_zebra.h +++ b/isisd/isis_zebra.h @@ -22,6 +22,8 @@ #ifndef _ZEBRA_ISIS_ZEBRA_H #define _ZEBRA_ISIS_ZEBRA_H +#include "isisd.h" + extern struct zclient *zclient; struct label_chunk { @@ -38,10 +40,12 @@ struct isis_route_info; struct sr_prefix; struct sr_adjacency; -void isis_zebra_route_add_route(struct prefix *prefix, +void isis_zebra_route_add_route(struct isis *isis, + struct prefix *prefix, struct prefix_ipv6 *src_p, struct isis_route_info *route_info); -void isis_zebra_route_del_route(struct prefix *prefix, +void isis_zebra_route_del_route(struct isis *isis, + struct prefix *prefix, struct prefix_ipv6 *src_p, struct isis_route_info *route_info); void isis_zebra_send_prefix_sid(int cmd, const struct sr_prefix *srp); diff --git a/ldpd/lde.c b/ldpd/lde.c index 3220278960..afcbe6cd44 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -206,6 +206,8 @@ lde_shutdown(void) free(iev_main_sync); log_info("label decision engine exiting"); + + zlog_fini(); exit(0); } diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index 56734a4f76..e3b6f4dfcc 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -495,7 +495,8 @@ start_child(enum ldpd_process p, char *argv0, int fd_async, int fd_sync) int argc = 0, nullfd; pid_t pid; - switch (pid = fork()) { + pid = fork(); + switch (pid) { case -1: fatal("cannot fork"); case 0: diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c index bae8a6e5c3..3f0a4fd33e 100644 --- a/ldpd/ldpe.c +++ b/ldpd/ldpe.c @@ -235,6 +235,9 @@ ldpe_shutdown(void) free(pkt_ptr); log_info("ldp engine exiting"); + + zlog_fini(); + exit(0); } diff --git a/lib/command.c b/lib/command.c index c9715965aa..80b75d9b23 100644 --- a/lib/command.c +++ b/lib/command.c @@ -144,7 +144,9 @@ void print_version(const char *progname) { printf("%s version %s\n", progname, FRR_VERSION); printf("%s\n", FRR_COPYRIGHT); +#ifdef ENABLE_VERSION_BUILD_CONFIG printf("configured with:\n\t%s\n", FRR_CONFIG_ARGS); +#endif } char *argv_concat(struct cmd_token **argv, int argc, int shift) @@ -1334,8 +1336,9 @@ DEFUN (show_version, vty_out(vty, "%s %s (%s).\n", FRR_FULL_NAME, FRR_VERSION, cmd_hostname_get() ? cmd_hostname_get() : ""); vty_out(vty, "%s%s\n", FRR_COPYRIGHT, GIT_INFO); +#ifdef ENABLE_VERSION_BUILD_CONFIG vty_out(vty, "configured with:\n %s\n", FRR_CONFIG_ARGS); - +#endif return CMD_SUCCESS; } diff --git a/lib/filter_cli.c b/lib/filter_cli.c index 0091d8b03f..fe8190d098 100644 --- a/lib/filter_cli.c +++ b/lib/filter_cli.c @@ -20,15 +20,16 @@ * 02110-1301 USA. */ +#include "zebra.h" #include "northbound.h" #include "prefix.h" -#include "zebra.h" #include "lib/command.h" #include "lib/filter.h" #include "lib/northbound_cli.h" #include "lib/plist.h" #include "lib/plist_int.h" +#include "lib/printfrr.h" #ifndef VTYSH_EXTRACT_PL #include "lib/filter_cli_clippy.c" @@ -197,11 +198,11 @@ DEFPY( if (seq_str == NULL) { /* Use XPath to find the next sequence number. */ sseq = acl_get_seq(vty, xpath); - snprintf(xpath_entry, sizeof(xpath_entry), - "%s/entry[sequence='%" PRId64 "']", xpath, sseq); + snprintfrr(xpath_entry, sizeof(xpath_entry), + "%s/entry[sequence='%" PRId64 "']", xpath, sseq); } else - snprintf(xpath_entry, sizeof(xpath_entry), - "%s/entry[sequence='%s']", xpath, seq_str); + snprintfrr(xpath_entry, sizeof(xpath_entry), + "%s/entry[sequence='%s']", xpath, seq_str); nb_cli_enqueue_change(vty, xpath_entry, NB_OP_CREATE, NULL); @@ -270,8 +271,8 @@ DEFPY( if (sseq == -1) return CMD_WARNING; - snprintf(xpath_entry, sizeof(xpath_entry), - "%s/entry[sequence='%" PRId64 "']", xpath, sseq); + snprintfrr(xpath_entry, sizeof(xpath_entry), + "%s/entry[sequence='%" PRId64 "']", xpath, sseq); nb_cli_enqueue_change(vty, xpath_entry, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); @@ -312,11 +313,11 @@ DEFPY( if (seq_str == NULL) { /* Use XPath to find the next sequence number. */ sseq = acl_get_seq(vty, xpath); - snprintf(xpath_entry, sizeof(xpath_entry), - "%s/entry[sequence='%" PRId64 "']", xpath, sseq); + snprintfrr(xpath_entry, sizeof(xpath_entry), + "%s/entry[sequence='%" PRId64 "']", xpath, sseq); } else - snprintf(xpath_entry, sizeof(xpath_entry), - "%s/entry[sequence='%s']", xpath, seq_str); + snprintfrr(xpath_entry, sizeof(xpath_entry), + "%s/entry[sequence='%s']", xpath, seq_str); nb_cli_enqueue_change(vty, xpath_entry, NB_OP_CREATE, NULL); @@ -376,7 +377,7 @@ DEFPY( /* If the user provided sequence number, then just go for it. */ if (seq_str != NULL) { - snprintf( + snprintfrr( xpath, sizeof(xpath), "/frr-filter:lib/access-list-legacy[number='%s']/entry[sequence='%s']", number_str, seq_str); @@ -421,8 +422,8 @@ DEFPY( if (sseq == -1) return CMD_WARNING; - snprintf(xpath_entry, sizeof(xpath_entry), - "%s/entry[sequence='%" PRId64 "']", xpath, sseq); + snprintfrr(xpath_entry, sizeof(xpath_entry), + "%s/entry[sequence='%" PRId64 "']", xpath, sseq); nb_cli_enqueue_change(vty, xpath_entry, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); @@ -577,11 +578,11 @@ DEFPY( if (seq_str == NULL) { /* Use XPath to find the next sequence number. */ sseq = acl_get_seq(vty, xpath); - snprintf(xpath_entry, sizeof(xpath_entry), - "%s/entry[sequence='%" PRId64 "']", xpath, sseq); + snprintfrr(xpath_entry, sizeof(xpath_entry), + "%s/entry[sequence='%" PRId64 "']", xpath, sseq); } else - snprintf(xpath_entry, sizeof(xpath_entry), - "%s/entry[sequence='%s']", xpath, seq_str); + snprintfrr(xpath_entry, sizeof(xpath_entry), + "%s/entry[sequence='%s']", xpath, seq_str); nb_cli_enqueue_change(vty, xpath_entry, NB_OP_CREATE, NULL); @@ -648,8 +649,8 @@ DEFPY( if (sseq == -1) return CMD_WARNING; - snprintf(xpath_entry, sizeof(xpath_entry), - "%s/entry[sequence='%" PRId64 "']", xpath, sseq); + snprintfrr(xpath_entry, sizeof(xpath_entry), + "%s/entry[sequence='%" PRId64 "']", xpath, sseq); nb_cli_enqueue_change(vty, xpath_entry, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); @@ -748,11 +749,11 @@ DEFPY( if (seq_str == NULL) { /* Use XPath to find the next sequence number. */ sseq = acl_get_seq(vty, xpath); - snprintf(xpath_entry, sizeof(xpath_entry), - "%s/entry[sequence='%" PRId64 "']", xpath, sseq); + snprintfrr(xpath_entry, sizeof(xpath_entry), + "%s/entry[sequence='%" PRId64 "']", xpath, sseq); } else - snprintf(xpath_entry, sizeof(xpath_entry), - "%s/entry[sequence='%s']", xpath, seq_str); + snprintfrr(xpath_entry, sizeof(xpath_entry), + "%s/entry[sequence='%s']", xpath, seq_str); nb_cli_enqueue_change(vty, xpath_entry, NB_OP_CREATE, NULL); @@ -820,8 +821,8 @@ DEFPY( if (sseq == -1) return CMD_WARNING; - snprintf(xpath_entry, sizeof(xpath_entry), - "%s/entry[sequence='%" PRId64 "']", xpath, sseq); + snprintfrr(xpath_entry, sizeof(xpath_entry), + "%s/entry[sequence='%" PRId64 "']", xpath, sseq); nb_cli_enqueue_change(vty, xpath_entry, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); @@ -923,11 +924,11 @@ DEFPY( if (seq_str == NULL) { /* Use XPath to find the next sequence number. */ sseq = acl_get_seq(vty, xpath); - snprintf(xpath_entry, sizeof(xpath_entry), - "%s/entry[sequence='%" PRId64 "']", xpath, sseq); + snprintfrr(xpath_entry, sizeof(xpath_entry), + "%s/entry[sequence='%" PRId64 "']", xpath, sseq); } else - snprintf(xpath_entry, sizeof(xpath_entry), - "%s/entry[sequence='%s']", xpath, seq_str); + snprintfrr(xpath_entry, sizeof(xpath_entry), + "%s/entry[sequence='%s']", xpath, seq_str); nb_cli_enqueue_change(vty, xpath_entry, NB_OP_CREATE, NULL); @@ -991,8 +992,8 @@ DEFPY( if (sseq == -1) return CMD_WARNING; - snprintf(xpath_entry, sizeof(xpath_entry), - "%s/entry[sequence='%" PRId64 "']", xpath, sseq); + snprintfrr(xpath_entry, sizeof(xpath_entry), + "%s/entry[sequence='%" PRId64 "']", xpath, sseq); nb_cli_enqueue_change(vty, xpath_entry, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); @@ -1231,8 +1232,8 @@ static int plist_remove(struct vty *vty, const char *iptype, const char *name, if (pentry == NULL) return CMD_WARNING; - snprintf(xpath_entry, sizeof(xpath_entry), - "%s/entry[sequence='%" PRId64 "']", xpath, pentry->seq); + snprintfrr(xpath_entry, sizeof(xpath_entry), + "%s/entry[sequence='%" PRId64 "']", xpath, pentry->seq); nb_cli_enqueue_change(vty, xpath_entry, NB_OP_DESTROY, NULL); rv = nb_cli_apply_changes(vty, NULL); @@ -1271,11 +1272,11 @@ DEFPY( if (seq_str == NULL) { /* Use XPath to find the next sequence number. */ sseq = acl_get_seq(vty, xpath); - snprintf(xpath_entry, sizeof(xpath_entry), - "%s/entry[sequence='%" PRId64 "']", xpath, sseq); + snprintfrr(xpath_entry, sizeof(xpath_entry), + "%s/entry[sequence='%" PRId64 "']", xpath, sseq); } else - snprintf(xpath_entry, sizeof(xpath_entry), - "%s/entry[sequence='%s']", xpath, seq_str); + snprintfrr(xpath_entry, sizeof(xpath_entry), + "%s/entry[sequence='%s']", xpath, seq_str); nb_cli_enqueue_change(vty, xpath_entry, NB_OP_CREATE, NULL); @@ -1431,11 +1432,11 @@ DEFPY( if (seq_str == NULL) { /* Use XPath to find the next sequence number. */ sseq = acl_get_seq(vty, xpath); - snprintf(xpath_entry, sizeof(xpath_entry), - "%s/entry[sequence='%" PRId64 "']", xpath, sseq); + snprintfrr(xpath_entry, sizeof(xpath_entry), + "%s/entry[sequence='%" PRId64 "']", xpath, sseq); } else - snprintf(xpath_entry, sizeof(xpath_entry), - "%s/entry[sequence='%s']", xpath, seq_str); + snprintfrr(xpath_entry, sizeof(xpath_entry), + "%s/entry[sequence='%s']", xpath, seq_str); nb_cli_enqueue_change(vty, xpath_entry, NB_OP_CREATE, NULL); diff --git a/lib/prefix.c b/lib/prefix.c index 112630e9c8..0900100be3 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -75,10 +75,10 @@ bool is_mcast_mac(const struct ethaddr *mac) return false; } -unsigned int prefix_bit(const uint8_t *prefix, const uint16_t prefixlen) +unsigned int prefix_bit(const uint8_t *prefix, const uint16_t bit_index) { - unsigned int offset = prefixlen / 8; - unsigned int shift = 7 - (prefixlen % 8); + unsigned int offset = bit_index / 8; + unsigned int shift = 7 - (bit_index % 8); return (prefix[offset] >> shift) & 1; } diff --git a/lib/prefix.h b/lib/prefix.h index 506efffb94..0bd457cc23 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -392,8 +392,16 @@ extern const char *family2str(int family); extern const char *safi2str(safi_t safi); extern const char *afi2str(afi_t afi); -/* Check bit of the prefix. */ -extern unsigned int prefix_bit(const uint8_t *prefix, const uint16_t prefixlen); +/* + * Check bit of the prefix. + * + * prefix + * byte buffer + * + * bit_index + * which bit to fetch from byte buffer, 0 indexed. + */ +extern unsigned int prefix_bit(const uint8_t *prefix, const uint16_t bit_index); extern struct prefix *prefix_new(void); extern void prefix_free(struct prefix **p); diff --git a/lib/stream.h b/lib/stream.h index 7cacf57d27..245f35db51 100644 --- a/lib/stream.h +++ b/lib/stream.h @@ -426,7 +426,7 @@ static inline const uint8_t *ptr_get_be32(const uint8_t *ptr, uint32_t *out) float r; \ uint32_t d; \ } _pval; \ - if (stream_getl2((S), &_pval.d)) \ + if (!stream_getl2((S), &_pval.d)) \ goto stream_failure; \ (P) = _pval.r; \ } while (0) diff --git a/lib/zclient.c b/lib/zclient.c index aa5fa082a1..793864243c 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -164,7 +164,7 @@ void zclient_stop(struct zclient *zclient) int i; if (zclient_debug) - zlog_debug("zclient stopped"); + zlog_debug("zclient %p stopped", zclient); /* Stop threads. */ THREAD_OFF(zclient->t_read); diff --git a/pimd/pim_mlag.c b/pimd/pim_mlag.c index 02f206144f..305dd5cf2c 100644 --- a/pimd/pim_mlag.c +++ b/pimd/pim_mlag.c @@ -41,8 +41,7 @@ extern struct zclient *zclient; "%s: add Dual-active Interface to %s " \ "to oil:%s", \ __func__, ch->interface->name, ch->sg_str); \ - pim_channel_add_oif(ch_oil, ch->interface, \ - PIM_OIF_FLAG_PROTO_IGMP, __func__); \ + pim_channel_update_oif_mute(ch_oil, ch->interface->info); \ } while (0) #define PIM_MLAG_DEL_OIF_TO_OIL(ch, ch_oil) \ @@ -52,8 +51,7 @@ extern struct zclient *zclient; "%s: del Dual-active Interface to %s " \ "to oil:%s", \ __func__, ch->interface->name, ch->sg_str); \ - pim_channel_del_oif(ch_oil, ch->interface, \ - PIM_OIF_FLAG_PROTO_IGMP, __func__); \ + pim_channel_update_oif_mute(ch_oil, ch->interface->info); \ } while (0) @@ -91,14 +89,36 @@ static void pim_mlag_inherit_mlag_flags(struct pim_upstream *up, bool is_df) { struct listnode *listnode; struct pim_upstream *child; + struct listnode *chnode; + struct listnode *chnextnode; + struct pim_ifchannel *ch; + struct pim_interface *pim_ifp = NULL; + struct channel_oil *ch_oil = NULL; - for (ALL_LIST_ELEMENTS_RO(up->sources, listnode, child)) { - PIM_UPSTREAM_FLAG_SET_MLAG_PEER(child->flags); - if (is_df) - PIM_UPSTREAM_FLAG_UNSET_MLAG_NON_DF(child->flags); - else - PIM_UPSTREAM_FLAG_SET_MLAG_NON_DF(child->flags); - pim_mlag_calculate_df_for_ifchannels(child, is_df); + if (PIM_DEBUG_MLAG) + zlog_debug("%s: Updating DF for uptream:%s childs", __func__, + up->sg_str); + + + for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) { + pim_ifp = (ch->interface) ? ch->interface->info : NULL; + if (!pim_ifp || !PIM_I_am_DualActive(pim_ifp)) + continue; + + for (ALL_LIST_ELEMENTS_RO(up->sources, listnode, child)) { + if (PIM_DEBUG_MLAG) + zlog_debug("%s: Updating DF for child:%s", + __func__, child->sg_str); + ch_oil = (child) ? child->channel_oil : NULL; + + if (!ch_oil) + continue; + + if (is_df) + PIM_MLAG_ADD_OIF_TO_OIL(ch, ch_oil); + else + PIM_MLAG_DEL_OIF_TO_OIL(ch, ch_oil); + } } } @@ -134,8 +154,8 @@ bool pim_mlag_up_df_role_update(struct pim_instance *pim, * Interface configuration */ if (PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up->flags)) { - pim_mlag_calculate_df_for_ifchannels(up, is_df); pim_mlag_inherit_mlag_flags(up, is_df); + pim_mlag_calculate_df_for_ifchannels(up, is_df); } /* If the DF role has changed check if ipmr-lo needs to be @@ -170,8 +190,7 @@ static bool pim_mlag_up_df_role_elect(struct pim_instance *pim, uint32_t local_cost; bool rv; - if (!pim_up_mlag_is_local(up) - && !PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up->flags)) + if (!pim_up_mlag_is_local(up)) return false; /* We are yet to rx a status update from the local MLAG daemon so @@ -501,8 +520,7 @@ static void pim_mlag_up_local_replay(void) RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) { pim = vrf->info; frr_each (rb_pim_upstream, &pim->upstream_head, up) { - if (pim_up_mlag_is_local(up) - || PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(up->flags)) + if (pim_up_mlag_is_local(up)) pim_mlag_up_local_add_send(pim, up); } } @@ -523,9 +541,7 @@ static void pim_mlag_up_local_reeval(bool mlagd_send, const char *reason_code) RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) { pim = vrf->info; frr_each (rb_pim_upstream, &pim->upstream_head, up) { - if (!pim_up_mlag_is_local(up) - && !PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE( - up->flags)) + if (!pim_up_mlag_is_local(up)) continue; /* if role changes re-send to peer */ if (pim_mlag_up_df_role_elect(pim, up) && @@ -985,6 +1001,10 @@ void pim_if_configure_mlag_dualactive(struct pim_interface *pim_ifp) if (!pim_ifp || !pim_ifp->pim || pim_ifp->activeactive == true) return; + if (PIM_DEBUG_MLAG) + zlog_debug("%s: Configuring active-active on Interface: %s", + __func__, "NULL"); + pim_ifp->activeactive = true; if (pim_ifp->pim) pim_ifp->pim->inst_mlag_intf_cnt++; @@ -1010,6 +1030,10 @@ void pim_if_unconfigure_mlag_dualactive(struct pim_interface *pim_ifp) if (!pim_ifp || !pim_ifp->pim || pim_ifp->activeactive == false) return; + if (PIM_DEBUG_MLAG) + zlog_debug("%s: UnConfiguring active-active on Interface: %s", + __func__, "NULL"); + pim_ifp->activeactive = false; pim_ifp->pim->inst_mlag_intf_cnt--; diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index 72e9c22f17..48220d1c9b 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -547,6 +547,34 @@ DEFPY (logpump, return CMD_SUCCESS; } +DEFPY (create_session, + create_session_cmd, + "sharp create session (1-1024)", + "Sharp Routing Protocol\n" + "Create data\n" + "Create a test session\n" + "Session ID\n") +{ + if (sharp_zclient_create(session) != 0) { + vty_out(vty, "%% Client session error\n"); + return CMD_WARNING; + } + + return CMD_SUCCESS; +} + +DEFPY (remove_session, + remove_session_cmd, + "sharp remove session (1-1024)", + "Sharp Routing Protocol\n" + "Remove data\n" + "Remove a test session\n" + "Session ID\n") +{ + sharp_zclient_delete(session); + return CMD_SUCCESS; +} + DEFPY (send_opaque, send_opaque_cmd, "sharp send opaque type (1-255) (1-1000)$count", @@ -626,6 +654,8 @@ void sharp_vty_init(void) install_element(ENABLE_NODE, &sharp_lsp_prefix_v4_cmd); install_element(ENABLE_NODE, &sharp_remove_lsp_prefix_v4_cmd); install_element(ENABLE_NODE, &logpump_cmd); + install_element(ENABLE_NODE, &create_session_cmd); + install_element(ENABLE_NODE, &remove_session_cmd); install_element(ENABLE_NODE, &send_opaque_cmd); install_element(ENABLE_NODE, &send_opaque_unicast_cmd); install_element(ENABLE_NODE, &send_opaque_reg_cmd); diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index 6ebc04b9eb..baa4e2ad5b 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -25,14 +25,9 @@ #include "command.h" #include "network.h" #include "prefix.h" -#include "routemap.h" -#include "table.h" #include "stream.h" #include "memory.h" #include "zclient.h" -#include "filter.h" -#include "plist.h" -#include "log.h" #include "nexthop.h" #include "nexthop_group.h" @@ -44,9 +39,41 @@ struct zclient *zclient = NULL; /* For registering threads. */ -extern struct thread_master *master; +struct thread_master *master; -/* Inteface addition message from zebra. */ +/* Privs info */ +struct zebra_privs_t sharp_privs; + +DEFINE_MTYPE_STATIC(SHARPD, ZC, "Test zclients"); + +/* Struct to hold list of test zclients */ +struct sharp_zclient { + struct sharp_zclient *prev; + struct sharp_zclient *next; + struct zclient *client; +}; + +/* Head of test zclient list */ +static struct sharp_zclient *sharp_clients_head; + +static int sharp_opaque_handler(ZAPI_CALLBACK_ARGS); + +/* Utility to add a test zclient struct to the list */ +static void add_zclient(struct zclient *client) +{ + struct sharp_zclient *node; + + node = XCALLOC(MTYPE_ZC, sizeof(struct sharp_zclient)); + + node->client = client; + + node->next = sharp_clients_head; + if (sharp_clients_head) + sharp_clients_head->prev = node; + sharp_clients_head = node; +} + +/* Interface addition message from zebra. */ static int sharp_ifp_create(struct interface *ifp) { return 0; @@ -480,6 +507,62 @@ static int sharp_redistribute_route(ZAPI_CALLBACK_ARGS) return 0; } +/* Add a zclient with a specified session id, for testing. */ +int sharp_zclient_create(uint32_t session_id) +{ + struct zclient *client; + struct sharp_zclient *node; + + /* Check for duplicates */ + for (node = sharp_clients_head; node != NULL; node = node->next) { + if (node->client->session_id == session_id) + return -1; + } + + client = zclient_new(master, &zclient_options_default); + client->sock = -1; + client->session_id = session_id; + + zclient_init(client, ZEBRA_ROUTE_SHARP, 0, &sharp_privs); + + /* Register handlers for messages we expect this session to see */ + client->opaque_msg_handler = sharp_opaque_handler; + + /* Enqueue on the list of test clients */ + add_zclient(client); + + return 0; +} + +/* Delete one of the extra test zclients */ +int sharp_zclient_delete(uint32_t session_id) +{ + struct sharp_zclient *node; + + /* Search for session */ + for (node = sharp_clients_head; node != NULL; node = node->next) { + if (node->client->session_id == session_id) { + /* Dequeue from list */ + if (node->next) + node->next->prev = node->prev; + if (node->prev) + node->prev->next = node->next; + if (node == sharp_clients_head) + sharp_clients_head = node->next; + + /* Clean up zclient */ + zclient_stop(node->client); + zclient_free(node->client); + + /* Free memory */ + XFREE(MTYPE_ZC, node); + break; + } + } + + return 0; +} + /* Handler for opaque messages */ static int sharp_opaque_handler(ZAPI_CALLBACK_ARGS) { @@ -491,7 +574,7 @@ static int sharp_opaque_handler(ZAPI_CALLBACK_ARGS) if (zclient_opaque_decode(s, &info) != 0) return -1; - zlog_debug("%s: [%d] received opaque type %u", __func__, + zlog_debug("%s: [%u] received opaque type %u", __func__, zclient->session_id, info.type); return 0; @@ -564,8 +647,6 @@ void sharp_opaque_reg_send(bool is_reg, uint32_t proto, uint32_t instance, } -extern struct zebra_privs_t sharp_privs; - void sharp_zebra_init(void) { struct zclient_options opt = {.receive_notify = true}; diff --git a/sharpd/sharp_zebra.h b/sharpd/sharp_zebra.h index 7604f4b0a4..cb2f38a6ab 100644 --- a/sharpd/sharp_zebra.h +++ b/sharpd/sharp_zebra.h @@ -24,6 +24,10 @@ extern void sharp_zebra_init(void); +/* Add and delete extra zapi client sessions, for testing */ +int sharp_zclient_create(uint32_t session_id); +int sharp_zclient_delete(uint32_t session_id); + extern void vrf_label_add(vrf_id_t vrf_id, afi_t afi, mpls_label_t label); extern void route_add(const struct prefix *p, vrf_id_t, uint8_t instance, const struct nexthop_group *nhg, diff --git a/tests/bgpd/test_bgp_table.c b/tests/bgpd/test_bgp_table.c index 79a8bb4408..7d81d42afb 100644 --- a/tests/bgpd/test_bgp_table.c +++ b/tests/bgpd/test_bgp_table.c @@ -73,70 +73,64 @@ static void add_node(struct bgp_table *table, const char *prefix_str) rn->info = node; } -static void print_range_result(struct list *list) +static bool prefix_in_array(const struct prefix *p, struct prefix *prefix_array, + size_t prefix_array_size) { - - struct listnode *listnode; - struct bgp_node *bnode; - - for (ALL_LIST_ELEMENTS_RO(list, listnode, bnode)) { - char buf[PREFIX2STR_BUFFER]; - - prefix2str(bgp_node_get_prefix(bnode), buf, PREFIX2STR_BUFFER); - printf("%s\n", buf); + for (size_t i = 0; i < prefix_array_size; ++i) { + if (prefix_same(p, &prefix_array[i])) + return true; } + return false; } -static void check_lookup_result(struct list *list, va_list arglist) +static void check_lookup_result(struct bgp_node *match, va_list arglist) { char *prefix_str; - unsigned int prefix_count = 0; + struct prefix *prefixes = NULL; + size_t prefix_count = 0; - printf("Searching results\n"); while ((prefix_str = va_arg(arglist, char *))) { - struct listnode *listnode; - struct bgp_node *bnode; - struct prefix p; - bool found = false; + ++prefix_count; + prefixes = realloc(prefixes, sizeof(*prefixes) * prefix_count); - prefix_count++; - printf("Searching for %s\n", prefix_str); - - if (str2prefix(prefix_str, &p) <= 0) + if (str2prefix(prefix_str, &prefixes[prefix_count - 1]) <= 0) assert(0); + } - for (ALL_LIST_ELEMENTS_RO(list, listnode, bnode)) { - if (prefix_same(bgp_node_get_prefix(bnode), &p)) - found = true; - } + /* check if the result is empty and if it is allowd to be empty */ + assert((prefix_count == 0 && !match) || prefix_count > 0); + if (!match) + return; - assert(found); - } + struct bgp_node *node = match; + + while ((node = bgp_route_next_until(node, match))) { + const struct prefix *node_p = bgp_node_get_prefix(node); - printf("Checking for unexpected result items\n"); - printf("Expecting %d found %d\n", prefix_count, listcount(list)); - assert(prefix_count == listcount(list)); + if (bgp_node_has_bgp_path_info_data(node) + && !prefix_in_array(node_p, prefixes, prefix_count)) { + char buf[PREFIX2STR_BUFFER]; + + prefix2str(node_p, buf, PREFIX2STR_BUFFER); + printf("prefix %s was not expected!\n", buf); + assert(0); + } + } } -static void do_test(struct bgp_table *table, const char *prefix, - uint32_t maxlen, ...) +static void do_test(struct bgp_table *table, const char *prefix, ...) { va_list arglist; - struct list *list = list_new(); struct prefix p; - list->del = (void (*)(void *))bgp_unlock_node; - va_start(arglist, maxlen); - printf("\nDoing lookup for %s-%d\n", prefix, maxlen); + va_start(arglist, prefix); + printf("\nDoing lookup for %s\n", prefix); if (str2prefix(prefix, &p) <= 0) assert(0); - bgp_table_range_lookup(table, &p, maxlen, list); - print_range_result(list); - - check_lookup_result(list, arglist); + struct bgp_node *node = bgp_table_subtree_lookup(table, &p); - list_delete(&list); + check_lookup_result(node, arglist); va_end(arglist); @@ -163,27 +157,22 @@ static void test_range_lookup(void) for (int i = 0; i < num_prefixes; i++) add_node(table, prefixes[i]); - do_test(table, "1.16.0.0/17", 20, "1.16.64.0/19", "1.16.32.0/20", NULL); - do_test(table, "1.16.128.0/17", 20, "1.16.128.0/18", "1.16.192.0/18", - "1.16.160.0/19", NULL); - - do_test(table, "1.16.128.0/17", 20, "1.16.128.0/18", "1.16.192.0/18", + do_test(table, "1.16.0.0/17", "1.16.64.0/19", "1.16.32.0/20", + "1.16.32.0/20", "1.16.32.0/21", NULL); + do_test(table, "1.16.128.0/17", "1.16.128.0/18", "1.16.192.0/18", "1.16.160.0/19", NULL); - do_test(table, "1.16.0.0/16", 18, "1.16.0.0/16", "1.16.128.0/18", - "1.16.192.0/18", NULL); - - do_test(table, "1.16.0.0/16", 21, "1.16.0.0/16", "1.16.128.0/18", + do_test(table, "1.16.0.0/16", "1.16.0.0/16", "1.16.128.0/18", "1.16.192.0/18", "1.16.64.0/19", "1.16.160.0/19", "1.16.32.0/20", "1.16.32.0/21", NULL); - do_test(table, "1.17.0.0/16", 20, NULL); + do_test(table, "1.17.0.0/16", NULL); - do_test(table, "128.0.0.0/8", 16, NULL); + do_test(table, "128.0.0.0/8", NULL); - do_test(table, "16.0.0.0/8", 16, "16.0.0.0/16", NULL); + do_test(table, "16.0.0.0/8", "16.0.0.0/16", NULL); - do_test(table, "0.0.0.0/2", 21, "1.16.0.0/16", "1.16.128.0/18", + do_test(table, "0.0.0.0/2", "1.16.0.0/16", "1.16.128.0/18", "1.16.192.0/18", "1.16.64.0/19", "1.16.160.0/19", "1.16.32.0/20", "1.16.32.0/21", "16.0.0.0/16", NULL); } diff --git a/tests/bgpd/test_bgp_table.py b/tests/bgpd/test_bgp_table.py index 4deaf08c22..53bd37233a 100644 --- a/tests/bgpd/test_bgp_table.py +++ b/tests/bgpd/test_bgp_table.py @@ -3,5 +3,5 @@ import frrtest class TestTable(frrtest.TestMultiOut): program = './test_bgp_table' -for i in range(9): +for i in range(7): TestTable.onesimple('Checks successfull') diff --git a/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py b/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py index eb4f0d4a83..b1f755ad06 100755 --- a/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py +++ b/tests/topotests/bfd-vrf-topo1/test_bfd_vrf_topo1.py @@ -129,14 +129,6 @@ def setup_module(mod): # Initialize all routers. tgen.start_router() - # Verify that we are using the proper version and that the BFD - # daemon exists. - for router in router_list.values(): - # Check for Version - if router.has_version("<", "5.1"): - tgen.set_error("Unsupported FRR version") - break - def teardown_module(_mod): "Teardown the pytest environment" @@ -176,7 +168,7 @@ def test_bfd_connection(): test_func = partial( topotest.router_json_cmp, router, "show bfd peers json", expected ) - _, result = topotest.run_and_expect(test_func, None, count=8, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=16, wait=1) assertmsg = '"{}" JSON output mismatches'.format(router.name) assert result is None, assertmsg @@ -220,7 +212,7 @@ def test_bgp_fast_convergence(): "show ip bgp vrf {}-cust1 json".format(router.name), expected, ) - _, res = topotest.run_and_expect(test_func, None, count=40, wait=0.5) + _, res = topotest.run_and_expect(test_func, None, count=40, wait=1) assertmsg = "{}: bgp did not converge".format(router.name) assert res is None, assertmsg @@ -262,7 +254,7 @@ def test_bfd_fast_convergence(): test_func = partial( topotest.router_json_cmp, router, "show bfd peers json", expected ) - _, res = topotest.run_and_expect(test_func, None, count=20, wait=0.5) + _, res = topotest.run_and_expect(test_func, None, count=40, wait=1) assertmsg = '"{}" JSON output mismatches'.format(router.name) assert res is None, assertmsg @@ -295,7 +287,7 @@ def test_bgp_fast_reconvergence(): "show ip bgp vrf {}-cust1 json".format(router.name), expected, ) - _, res = topotest.run_and_expect(test_func, None, count=3, wait=1) + _, res = topotest.run_and_expect(test_func, None, count=16, wait=1) assertmsg = "{}: bgp did not converge".format(router.name) assert res is None, assertmsg diff --git a/tools/frr-reload.py b/tools/frr-reload.py index bdba65ee2f..bf39dcc03f 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -146,9 +146,10 @@ class Vtysh(object): return stdout.decode('UTF-8') def mark_show_run(self, daemon = None): - cmd = 'show running-config no-header' + cmd = 'show running-config' if daemon: cmd += ' %s' % daemon + cmd += ' no-header' show_run = self._call_cmd(cmd, stdout=subprocess.PIPE) mark = self._call(['-m', '-f', '-'], stdin=show_run.stdout, stdout=subprocess.PIPE) @@ -504,7 +505,8 @@ end "table ", "username ", "zebra ", - "vrrp autoconfigure") + "vrrp autoconfigure", + "evpn mh") for line in self.lines: diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c index 88d5ab5cec..ef208bdc83 100644 --- a/zebra/dplane_fpm_nl.c +++ b/zebra/dplane_fpm_nl.c @@ -709,12 +709,13 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx) switch (op) { case DPLANE_OP_ROUTE_UPDATE: case DPLANE_OP_ROUTE_DELETE: - rv = netlink_route_multipath(RTM_DELROUTE, ctx, nl_buf, - sizeof(nl_buf), true, - fnc->use_nhg); + rv = netlink_route_multipath_msg_encode(RTM_DELROUTE, ctx, + nl_buf, sizeof(nl_buf), + true, fnc->use_nhg); if (rv <= 0) { - zlog_err("%s: netlink_route_multipath failed", - __func__); + zlog_err( + "%s: netlink_route_multipath_msg_encode failed", + __func__); return 0; } @@ -726,12 +727,13 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx) /* FALL THROUGH */ case DPLANE_OP_ROUTE_INSTALL: - rv = netlink_route_multipath( + rv = netlink_route_multipath_msg_encode( RTM_NEWROUTE, ctx, &nl_buf[nl_buf_len], sizeof(nl_buf) - nl_buf_len, true, fnc->use_nhg); if (rv <= 0) { - zlog_err("%s: netlink_route_multipath failed", - __func__); + zlog_err( + "%s: netlink_route_multipath_msg_encode failed", + __func__); return 0; } @@ -751,10 +753,11 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx) break; case DPLANE_OP_NH_DELETE: - rv = netlink_nexthop_encode(RTM_DELNEXTHOP, ctx, nl_buf, - sizeof(nl_buf)); + rv = netlink_nexthop_msg_encode(RTM_DELNEXTHOP, ctx, nl_buf, + sizeof(nl_buf)); if (rv <= 0) { - zlog_err("%s: netlink_nexthop_encode failed", __func__); + zlog_err("%s: netlink_nexthop_msg_encode failed", + __func__); return 0; } @@ -762,10 +765,11 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx) break; case DPLANE_OP_NH_INSTALL: case DPLANE_OP_NH_UPDATE: - rv = netlink_nexthop_encode(RTM_NEWNEXTHOP, ctx, nl_buf, - sizeof(nl_buf)); + rv = netlink_nexthop_msg_encode(RTM_NEWNEXTHOP, ctx, nl_buf, + sizeof(nl_buf)); if (rv <= 0) { - zlog_err("%s: netlink_nexthop_encode failed", __func__); + zlog_err("%s: netlink_nexthop_msg_encode failed", + __func__); return 0; } diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 7677db7efd..a29a810902 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -798,7 +798,7 @@ static int netlink_request_intf_addr(struct nlsock *netlink_cmd, int family, /* Include filter, if specified. */ if (filter_mask) - addattr32(&req.n, sizeof(req), IFLA_EXT_MASK, filter_mask); + nl_attr_put32(&req.n, sizeof(req), IFLA_EXT_MASK, filter_mask); return netlink_request(netlink_cmd, &req); } @@ -903,8 +903,8 @@ int kernel_interface_set_master(struct interface *master, req.ifa.ifi_index = slave->ifindex; - addattr_l(&req.n, sizeof(req), IFLA_MASTER, &master->ifindex, 4); - addattr_l(&req.n, sizeof(req), IFLA_LINK, &slave->ifindex, 4); + nl_attr_put32(&req.n, sizeof(req), IFLA_MASTER, master->ifindex); + nl_attr_put32(&req.n, sizeof(req), IFLA_LINK, slave->ifindex); return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0); @@ -942,20 +942,20 @@ static int netlink_address_ctx(const struct zebra_dplane_ctx *ctx) req.ifa.ifa_index = dplane_ctx_get_ifindex(ctx); - addattr_l(&req.n, sizeof(req), IFA_LOCAL, &p->u.prefix, bytelen); + nl_attr_put(&req.n, sizeof(req), IFA_LOCAL, &p->u.prefix, bytelen); if (p->family == AF_INET) { if (dplane_ctx_intf_is_connected(ctx)) { p = dplane_ctx_get_intf_dest(ctx); - addattr_l(&req.n, sizeof(req), IFA_ADDRESS, - &p->u.prefix, bytelen); + nl_attr_put(&req.n, sizeof(req), IFA_ADDRESS, + &p->u.prefix, bytelen); } else if (cmd == RTM_NEWADDR) { struct in_addr broad = { .s_addr = ipv4_broadcast_addr(p->u.prefix4.s_addr, p->prefixlen) }; - addattr_l(&req.n, sizeof(req), IFA_BROADCAST, - &broad, bytelen); + nl_attr_put(&req.n, sizeof(req), IFA_BROADCAST, &broad, + bytelen); } } @@ -967,8 +967,8 @@ static int netlink_address_ctx(const struct zebra_dplane_ctx *ctx) if (dplane_ctx_intf_has_label(ctx)) { label = dplane_ctx_get_intf_label(ctx); - addattr_l(&req.n, sizeof(req), IFA_LABEL, label, - strlen(label) + 1); + nl_attr_put(&req.n, sizeof(req), IFA_LABEL, label, + strlen(label) + 1); } return netlink_talk_info(netlink_talk_filter, &req.n, @@ -1520,8 +1520,8 @@ int netlink_protodown(struct interface *ifp, bool down) req.ifa.ifi_index = ifp->ifindex; - addattr_l(&req.n, sizeof(req), IFLA_PROTO_DOWN, &down, sizeof(down)); - addattr_l(&req.n, sizeof(req), IFLA_LINK, &ifp->ifindex, 4); + nl_attr_put(&req.n, sizeof(req), IFLA_PROTO_DOWN, &down, sizeof(down)); + nl_attr_put32(&req.n, sizeof(req), IFLA_LINK, ifp->ifindex); return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0); diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index a1f7014ce9..75a8e9f17d 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -527,8 +527,8 @@ void netlink_parse_rtattr_nested(struct rtattr **tb, int max, netlink_parse_rtattr(tb, max, RTA_DATA(rta), RTA_PAYLOAD(rta)); } -int addattr_l(struct nlmsghdr *n, unsigned int maxlen, int type, - const void *data, unsigned int alen) +bool nl_attr_put(struct nlmsghdr *n, unsigned int maxlen, int type, + const void *data, unsigned int alen) { int len; struct rtattr *rta; @@ -536,7 +536,7 @@ int addattr_l(struct nlmsghdr *n, unsigned int maxlen, int type, len = RTA_LENGTH(alen); if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len) > maxlen) - return -1; + return false; rta = (struct rtattr *)(((char *)n) + NLMSG_ALIGN(n->nlmsg_len)); rta->rta_type = type; @@ -549,72 +549,56 @@ int addattr_l(struct nlmsghdr *n, unsigned int maxlen, int type, n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len); - return 0; -} - -int rta_addattr_l(struct rtattr *rta, unsigned int maxlen, int type, - const void *data, unsigned int alen) -{ - unsigned int len; - struct rtattr *subrta; - - len = RTA_LENGTH(alen); - - if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) - return -1; - - subrta = (struct rtattr *)(((char *)rta) + RTA_ALIGN(rta->rta_len)); - subrta->rta_type = type; - subrta->rta_len = len; - - if (data) - memcpy(RTA_DATA(subrta), data, alen); - else - assert(alen == 0); - - rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len); - - return 0; + return true; } -int addattr16(struct nlmsghdr *n, unsigned int maxlen, int type, uint16_t data) +bool nl_attr_put16(struct nlmsghdr *n, unsigned int maxlen, int type, + uint16_t data) { - return addattr_l(n, maxlen, type, &data, sizeof(uint16_t)); + return nl_attr_put(n, maxlen, type, &data, sizeof(uint16_t)); } -int addattr32(struct nlmsghdr *n, unsigned int maxlen, int type, int data) +bool nl_attr_put32(struct nlmsghdr *n, unsigned int maxlen, int type, + uint32_t data) { - return addattr_l(n, maxlen, type, &data, sizeof(uint32_t)); + return nl_attr_put(n, maxlen, type, &data, sizeof(uint32_t)); } -struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type) +struct rtattr *nl_attr_nest(struct nlmsghdr *n, unsigned int maxlen, int type) { struct rtattr *nest = NLMSG_TAIL(n); - addattr_l(n, maxlen, type, NULL, 0); + if (!nl_attr_put(n, maxlen, type, NULL, 0)) + return NULL; + nest->rta_type |= NLA_F_NESTED; return nest; } -int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest) +int nl_attr_nest_end(struct nlmsghdr *n, struct rtattr *nest) { nest->rta_len = (uint8_t *)NLMSG_TAIL(n) - (uint8_t *)nest; return n->nlmsg_len; } -struct rtattr *rta_nest(struct rtattr *rta, int maxlen, int type) +struct rtnexthop *nl_attr_rtnh(struct nlmsghdr *n, unsigned int maxlen) { - struct rtattr *nest = RTA_TAIL(rta); + struct rtnexthop *rtnh = (struct rtnexthop *)NLMSG_TAIL(n); - rta_addattr_l(rta, maxlen, type, NULL, 0); - nest->rta_type |= NLA_F_NESTED; - return nest; + if (NLMSG_ALIGN(n->nlmsg_len) + RTNH_ALIGN(sizeof(struct rtnexthop)) + > maxlen) + return NULL; + + memset(rtnh, 0, sizeof(struct rtnexthop)); + n->nlmsg_len = + NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(sizeof(struct rtnexthop)); + + return rtnh; } -int rta_nest_end(struct rtattr *rta, struct rtattr *nest) +void nl_attr_rtnh_end(struct nlmsghdr *n, struct rtnexthop *rtnh) { - nest->rta_len = (uint8_t *)RTA_TAIL(rta) - (uint8_t *)nest; - return rta->rta_len; + rtnh->rtnh_len = (uint8_t *)NLMSG_TAIL(n) - (uint8_t *)rtnh; } const char *nl_msg_type_to_str(uint16_t msg_type) diff --git a/zebra/kernel_netlink.h b/zebra/kernel_netlink.h index 6a4077abf6..bd8159faf3 100644 --- a/zebra/kernel_netlink.h +++ b/zebra/kernel_netlink.h @@ -30,22 +30,57 @@ extern "C" { #define NL_RCV_PKT_BUF_SIZE 32768 #define NL_PKT_BUF_SIZE 8192 +/* + * nl_attr_put - add an attribute to the Netlink message. + * + * Returns true if the attribute could be added to the message (fits into the + * buffer), otherwise false is returned. + */ +extern bool nl_attr_put(struct nlmsghdr *n, unsigned int maxlen, int type, + const void *data, unsigned int alen); +extern bool nl_attr_put16(struct nlmsghdr *n, unsigned int maxlen, int type, + uint16_t data); +extern bool nl_attr_put32(struct nlmsghdr *n, unsigned int maxlen, int type, + uint32_t data); + +/* + * nl_attr_nest - start an attribute nest. + * + * Returns a valid pointer to the beginning of the nest if the attribute + * describing the nest could be added to the message (fits into the buffer), + * otherwise NULL is returned. + */ +extern struct rtattr *nl_attr_nest(struct nlmsghdr *n, unsigned int maxlen, + int type); + +/* + * nl_attr_nest_end - finalize nesting of attributes. + * + * Updates the length field of the attribute header to include the appeneded + * attributes. Returns a total length of the Netlink message. + */ +extern int nl_attr_nest_end(struct nlmsghdr *n, struct rtattr *nest); + +/* + * nl_attr_rtnh - append a rtnexthop record to the Netlink message. + * + * Returns a valid pointer to the rtnexthop struct if it could be added to + * the message (fits into the buffer), otherwise NULL is returned. + */ +extern struct rtnexthop *nl_attr_rtnh(struct nlmsghdr *n, unsigned int maxlen); + +/* + * nl_attr_rtnh_end - finalize adding a rtnexthop record. + * + * Updates the length field of the rtnexthop to include the appeneded + * attributes. + */ +extern void nl_attr_rtnh_end(struct nlmsghdr *n, struct rtnexthop *rtnh); + extern void netlink_parse_rtattr(struct rtattr **tb, int max, struct rtattr *rta, int len); extern void netlink_parse_rtattr_nested(struct rtattr **tb, int max, struct rtattr *rta); -extern int addattr_l(struct nlmsghdr *n, unsigned int maxlen, int type, - const void *data, unsigned int alen); -extern int rta_addattr_l(struct rtattr *rta, unsigned int maxlen, int type, - const void *data, unsigned int alen); -extern int addattr16(struct nlmsghdr *n, unsigned int maxlen, int type, - uint16_t data); -extern int addattr32(struct nlmsghdr *n, unsigned int maxlen, int type, - int data); -extern struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type); -extern int addattr_nest_end(struct nlmsghdr *n, struct rtattr *nest); -extern struct rtattr *rta_nest(struct rtattr *rta, int maxlen, int type); -extern int rta_nest_end(struct rtattr *rta, struct rtattr *nest); extern const char *nl_msg_type_to_str(uint16_t msg_type); extern const char *nl_rtproto_to_str(uint8_t rtproto); extern const char *nl_family_to_str(uint8_t family); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 095c5570a2..9883e73876 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1029,11 +1029,15 @@ int netlink_route_read(struct zebra_ns *zns) return 0; } -static void _netlink_route_nl_add_gateway_info(uint8_t route_family, - uint8_t gw_family, - struct nlmsghdr *nlmsg, - size_t req_size, int bytelen, - const struct nexthop *nexthop) +/* + * The function returns true if the gateway info could be added + * to the message, otherwise false is returned. + */ +static bool _netlink_route_add_gateway_info(uint8_t route_family, + uint8_t gw_family, + struct nlmsghdr *nlmsg, + size_t req_size, int bytelen, + const struct nexthop *nexthop) { if (route_family == AF_MPLS) { struct gw_family_t gw_fam; @@ -1043,45 +1047,22 @@ static void _netlink_route_nl_add_gateway_info(uint8_t route_family, memcpy(&gw_fam.gate.ipv4, &nexthop->gate.ipv4, bytelen); else memcpy(&gw_fam.gate.ipv6, &nexthop->gate.ipv6, bytelen); - addattr_l(nlmsg, req_size, RTA_VIA, &gw_fam.family, - bytelen + 2); + if (!nl_attr_put(nlmsg, req_size, RTA_VIA, &gw_fam.family, + bytelen + 2)) + return false; } else { - if (gw_family == AF_INET) - addattr_l(nlmsg, req_size, RTA_GATEWAY, - &nexthop->gate.ipv4, bytelen); - else - addattr_l(nlmsg, req_size, RTA_GATEWAY, - &nexthop->gate.ipv6, bytelen); + if (gw_family == AF_INET) { + if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY, + &nexthop->gate.ipv4, bytelen)) + return false; + } else { + if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY, + &nexthop->gate.ipv6, bytelen)) + return false; + } } -} - -static void _netlink_route_rta_add_gateway_info(uint8_t route_family, - uint8_t gw_family, - struct rtattr *rta, - struct rtnexthop *rtnh, - size_t req_size, int bytelen, - const struct nexthop *nexthop) -{ - if (route_family == AF_MPLS) { - struct gw_family_t gw_fam; - gw_fam.family = gw_family; - if (gw_family == AF_INET) - memcpy(&gw_fam.gate.ipv4, &nexthop->gate.ipv4, bytelen); - else - memcpy(&gw_fam.gate.ipv6, &nexthop->gate.ipv6, bytelen); - rta_addattr_l(rta, req_size, RTA_VIA, &gw_fam.family, - bytelen + 2); - rtnh->rtnh_len += RTA_LENGTH(bytelen + 2); - } else { - if (gw_family == AF_INET) - rta_addattr_l(rta, req_size, RTA_GATEWAY, - &nexthop->gate.ipv4, bytelen); - else - rta_addattr_l(rta, req_size, RTA_GATEWAY, - &nexthop->gate.ipv6, bytelen); - rtnh->rtnh_len += sizeof(struct rtattr) + bytelen; - } + return true; } static int build_label_stack(struct mpls_label_stack *nh_label, @@ -1114,6 +1095,86 @@ static int build_label_stack(struct mpls_label_stack *nh_label, return num_labels; } +static bool _netlink_route_encode_label_info(struct mpls_label_stack *nh_label, + struct nlmsghdr *nlmsg, + size_t buflen, struct rtmsg *rtmsg, + char *label_buf, + size_t label_buf_size) +{ + mpls_lse_t out_lse[MPLS_MAX_LABELS]; + int num_labels; + + /* + * label_buf is *only* currently used within debugging. + * As such when we assign it we are guarding it inside + * a debug test. If you want to change this make sure + * you fix this assumption + */ + label_buf[0] = '\0'; + + num_labels = + build_label_stack(nh_label, out_lse, label_buf, label_buf_size); + + if (num_labels) { + /* Set the BoS bit */ + out_lse[num_labels - 1] |= htonl(1 << MPLS_LS_S_SHIFT); + + if (rtmsg->rtm_family == AF_MPLS) { + if (!nl_attr_put(nlmsg, buflen, RTA_NEWDST, &out_lse, + num_labels * sizeof(mpls_lse_t))) + return false; + } else { + struct rtattr *nest; + + if (!nl_attr_put16(nlmsg, buflen, RTA_ENCAP_TYPE, + LWTUNNEL_ENCAP_MPLS)) + return false; + + nest = nl_attr_nest(nlmsg, buflen, RTA_ENCAP); + if (!nest) + return false; + + if (!nl_attr_put(nlmsg, buflen, MPLS_IPTUNNEL_DST, + &out_lse, + num_labels * sizeof(mpls_lse_t))) + return false; + nl_attr_nest_end(nlmsg, nest); + } + } + + return true; +} + +static bool _netlink_route_encode_nexthop_src(const struct nexthop *nexthop, + int family, + struct nlmsghdr *nlmsg, + size_t buflen, int bytelen) +{ + if (family == AF_INET) { + if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY) { + if (!nl_attr_put(nlmsg, buflen, RTA_PREFSRC, + &nexthop->rmap_src.ipv4, bytelen)) + return false; + } else if (nexthop->src.ipv4.s_addr != INADDR_ANY) { + if (!nl_attr_put(nlmsg, buflen, RTA_PREFSRC, + &nexthop->src.ipv4, bytelen)) + return false; + } + } else if (family == AF_INET6) { + if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6)) { + if (!nl_attr_put(nlmsg, buflen, RTA_PREFSRC, + &nexthop->rmap_src.ipv6, bytelen)) + return false; + } else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6)) { + if (!nl_attr_put(nlmsg, buflen, RTA_PREFSRC, + &nexthop->src.ipv6, bytelen)) + return false; + } + } + + return true; +} + /* This function takes a nexthop as argument and adds * the appropriate netlink attributes to an existing * netlink message. @@ -1124,8 +1185,11 @@ static int build_label_stack(struct mpls_label_stack *nh_label, * @param nexthop: Nexthop information * @param nlmsg: nlmsghdr structure to fill in. * @param req_size: The size allocated for the message. + * + * The function returns true if the nexthop could be added + * to the message, otherwise false is returned. */ -static void _netlink_route_build_singlepath(const struct prefix *p, +static bool _netlink_route_build_singlepath(const struct prefix *p, const char *routedesc, int bytelen, const struct nexthop *nexthop, struct nlmsghdr *nlmsg, @@ -1133,9 +1197,7 @@ static void _netlink_route_build_singlepath(const struct prefix *p, size_t req_size, int cmd) { - mpls_lse_t out_lse[MPLS_MAX_LABELS]; char label_buf[256]; - int num_labels = 0; struct vrf *vrf; char addrstr[INET6_ADDRSTRLEN]; @@ -1143,77 +1205,49 @@ static void _netlink_route_build_singlepath(const struct prefix *p, vrf = vrf_lookup_by_id(nexthop->vrf_id); - /* - * label_buf is *only* currently used within debugging. - * As such when we assign it we are guarding it inside - * a debug test. If you want to change this make sure - * you fix this assumption - */ - label_buf[0] = '\0'; - - num_labels = build_label_stack(nexthop->nh_label, out_lse, label_buf, - sizeof(label_buf)); - - if (num_labels) { - /* Set the BoS bit */ - out_lse[num_labels - 1] |= htonl(1 << MPLS_LS_S_SHIFT); - - if (rtmsg->rtm_family == AF_MPLS) - addattr_l(nlmsg, req_size, RTA_NEWDST, &out_lse, - num_labels * sizeof(mpls_lse_t)); - else { - struct rtattr *nest; - uint16_t encap = LWTUNNEL_ENCAP_MPLS; - - addattr_l(nlmsg, req_size, RTA_ENCAP_TYPE, &encap, - sizeof(uint16_t)); - nest = addattr_nest(nlmsg, req_size, RTA_ENCAP); - addattr_l(nlmsg, req_size, MPLS_IPTUNNEL_DST, &out_lse, - num_labels * sizeof(mpls_lse_t)); - addattr_nest_end(nlmsg, nest); - } - } + if (!_netlink_route_encode_label_info(nexthop->nh_label, nlmsg, + req_size, rtmsg, label_buf, + sizeof(label_buf))) + return false; if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) rtmsg->rtm_flags |= RTNH_F_ONLINK; if (is_route_v4_over_v6(rtmsg->rtm_family, nexthop->type)) { rtmsg->rtm_flags |= RTNH_F_ONLINK; - addattr_l(nlmsg, req_size, RTA_GATEWAY, &ipv4_ll, 4); - addattr32(nlmsg, req_size, RTA_OIF, nexthop->ifindex); - - if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY - && (cmd == RTM_NEWROUTE)) - addattr_l(nlmsg, req_size, RTA_PREFSRC, - &nexthop->rmap_src.ipv4, bytelen); - else if (nexthop->src.ipv4.s_addr != INADDR_ANY - && (cmd == RTM_NEWROUTE)) - addattr_l(nlmsg, req_size, RTA_PREFSRC, - &nexthop->src.ipv4, bytelen); + if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY, &ipv4_ll, 4)) + return false; + if (!nl_attr_put32(nlmsg, req_size, RTA_OIF, nexthop->ifindex)) + return false; + + if (cmd == RTM_NEWROUTE) { + if (!_netlink_route_encode_nexthop_src( + nexthop, AF_INET, nlmsg, req_size, bytelen)) + return false; + } if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("%s: 5549 (%s): %pFX nexthop via %s %s if %u vrf %s(%u)", __func__, routedesc, p, ipv4_ll_buf, label_buf, nexthop->ifindex, VRF_LOGNAME(vrf), nexthop->vrf_id); - return; + return true; } if (nexthop->type == NEXTHOP_TYPE_IPV4 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { /* Send deletes to the kernel without specifying the next-hop */ - if (cmd != RTM_DELROUTE) - _netlink_route_nl_add_gateway_info( - rtmsg->rtm_family, AF_INET, nlmsg, req_size, - bytelen, nexthop); + if (cmd != RTM_DELROUTE) { + if (!_netlink_route_add_gateway_info( + rtmsg->rtm_family, AF_INET, nlmsg, req_size, + bytelen, nexthop)) + return false; + } if (cmd == RTM_NEWROUTE) { - if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY) - addattr_l(nlmsg, req_size, RTA_PREFSRC, - &nexthop->rmap_src.ipv4, bytelen); - else if (nexthop->src.ipv4.s_addr != INADDR_ANY) - addattr_l(nlmsg, req_size, RTA_PREFSRC, - &nexthop->src.ipv4, bytelen); + if (!_netlink_route_encode_nexthop_src( + nexthop, AF_INET, nlmsg, req_size, bytelen)) + return false; } if (IS_ZEBRA_DEBUG_KERNEL) { @@ -1228,17 +1262,16 @@ static void _netlink_route_build_singlepath(const struct prefix *p, if (nexthop->type == NEXTHOP_TYPE_IPV6 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { - _netlink_route_nl_add_gateway_info(rtmsg->rtm_family, AF_INET6, - nlmsg, req_size, bytelen, - nexthop); + if (!_netlink_route_add_gateway_info(rtmsg->rtm_family, + AF_INET6, nlmsg, req_size, + bytelen, nexthop)) + return false; if (cmd == RTM_NEWROUTE) { - if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6)) - addattr_l(nlmsg, req_size, RTA_PREFSRC, - &nexthop->rmap_src.ipv6, bytelen); - else if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->src.ipv6)) - addattr_l(nlmsg, req_size, RTA_PREFSRC, - &nexthop->src.ipv6, bytelen); + if (!_netlink_route_encode_nexthop_src( + nexthop, AF_INET6, nlmsg, req_size, + bytelen)) + return false; } if (IS_ZEBRA_DEBUG_KERNEL) { @@ -1256,17 +1289,16 @@ static void _netlink_route_build_singlepath(const struct prefix *p, * This is especially useful if we are doing route * leaking. */ - if (nexthop->type != NEXTHOP_TYPE_BLACKHOLE) - addattr32(nlmsg, req_size, RTA_OIF, nexthop->ifindex); + if (nexthop->type != NEXTHOP_TYPE_BLACKHOLE) { + if (!nl_attr_put32(nlmsg, req_size, RTA_OIF, nexthop->ifindex)) + return false; + } if (nexthop->type == NEXTHOP_TYPE_IFINDEX) { if (cmd == RTM_NEWROUTE) { - if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY) - addattr_l(nlmsg, req_size, RTA_PREFSRC, - &nexthop->rmap_src.ipv4, bytelen); - else if (nexthop->src.ipv4.s_addr != INADDR_ANY) - addattr_l(nlmsg, req_size, RTA_PREFSRC, - &nexthop->src.ipv4, bytelen); + if (!_netlink_route_encode_nexthop_src( + nexthop, AF_INET, nlmsg, req_size, bytelen)) + return false; } if (IS_ZEBRA_DEBUG_KERNEL) @@ -1274,11 +1306,12 @@ static void _netlink_route_build_singlepath(const struct prefix *p, __func__, routedesc, p, nexthop->ifindex, VRF_LOGNAME(vrf), nexthop->vrf_id); } + + return true; } /* This function takes a nexthop as argument and - * appends to the given rtattr/rtnexthop pair the - * representation of the nexthop. If the nexthop + * appends to the given netlink msg. If the nexthop * defines a preferred source, the src parameter * will be modified to point to that src, otherwise * it will be kept unmodified. @@ -1287,77 +1320,45 @@ static void _netlink_route_build_singlepath(const struct prefix *p, * (direct/recursive, single-/multipath) * @param bytelen: Length of addresses in bytes. * @param nexthop: Nexthop information - * @param rta: rtnetlink attribute structure - * @param rtnh: pointer to an rtnetlink nexthop structure + * @param nlmsg: nlmsghdr structure to fill in. + * @param req_size: The size allocated for the message. * @param src: pointer pointing to a location where * the prefsrc should be stored. + * + * The function returns true if the nexthop could be added + * to the message, otherwise false is returned. */ -static void -_netlink_route_build_multipath(const struct prefix *p, const char *routedesc, - int bytelen, const struct nexthop *nexthop, - struct rtattr *rta, struct rtnexthop *rtnh, - struct rtmsg *rtmsg, const union g_addr **src) +static bool _netlink_route_build_multipath(const struct prefix *p, + const char *routedesc, int bytelen, + const struct nexthop *nexthop, + struct nlmsghdr *nlmsg, + size_t req_size, struct rtmsg *rtmsg, + const union g_addr **src) { - mpls_lse_t out_lse[MPLS_MAX_LABELS]; char label_buf[256]; - int num_labels = 0; struct vrf *vrf; + struct rtnexthop *rtnh; - rtnh->rtnh_len = sizeof(*rtnh); - rtnh->rtnh_flags = 0; - rtnh->rtnh_hops = 0; - rta->rta_len += rtnh->rtnh_len; + rtnh = nl_attr_rtnh(nlmsg, req_size); + if (rtnh == NULL) + return false; assert(nexthop); vrf = vrf_lookup_by_id(nexthop->vrf_id); - /* - * label_buf is *only* currently used within debugging. - * As such when we assign it we are guarding it inside - * a debug test. If you want to change this make sure - * you fix this assumption - */ - label_buf[0] = '\0'; - - num_labels = build_label_stack(nexthop->nh_label, out_lse, label_buf, - sizeof(label_buf)); - - if (num_labels) { - /* Set the BoS bit */ - out_lse[num_labels - 1] |= htonl(1 << MPLS_LS_S_SHIFT); - - if (rtmsg->rtm_family == AF_MPLS) { - rta_addattr_l(rta, NL_PKT_BUF_SIZE, RTA_NEWDST, - &out_lse, - num_labels * sizeof(mpls_lse_t)); - rtnh->rtnh_len += - RTA_LENGTH(num_labels * sizeof(mpls_lse_t)); - } else { - struct rtattr *nest; - uint16_t encap = LWTUNNEL_ENCAP_MPLS; - int len = rta->rta_len; - - rta_addattr_l(rta, NL_PKT_BUF_SIZE, RTA_ENCAP_TYPE, - &encap, sizeof(uint16_t)); - nest = rta_nest(rta, NL_PKT_BUF_SIZE, RTA_ENCAP); - rta_addattr_l(rta, NL_PKT_BUF_SIZE, MPLS_IPTUNNEL_DST, - &out_lse, - num_labels * sizeof(mpls_lse_t)); - rta_nest_end(rta, nest); - rtnh->rtnh_len += rta->rta_len - len; - } - } + if (!_netlink_route_encode_label_info(nexthop->nh_label, nlmsg, + req_size, rtmsg, label_buf, + sizeof(label_buf))) + return false; if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) rtnh->rtnh_flags |= RTNH_F_ONLINK; if (is_route_v4_over_v6(rtmsg->rtm_family, nexthop->type)) { - bytelen = 4; rtnh->rtnh_flags |= RTNH_F_ONLINK; - rta_addattr_l(rta, NL_PKT_BUF_SIZE, RTA_GATEWAY, &ipv4_ll, - bytelen); - rtnh->rtnh_len += sizeof(struct rtattr) + bytelen; + if (!nl_attr_put(nlmsg, req_size, RTA_GATEWAY, &ipv4_ll, 4)) + return false; rtnh->rtnh_ifindex = nexthop->ifindex; if (nexthop->weight) rtnh->rtnh_hops = nexthop->weight - 1; @@ -1373,14 +1374,17 @@ _netlink_route_build_multipath(const struct prefix *p, const char *routedesc, __func__, routedesc, p, ipv4_ll_buf, label_buf, nexthop->ifindex, VRF_LOGNAME(vrf), nexthop->vrf_id); - return; + nl_attr_rtnh_end(nlmsg, rtnh); + return true; } if (nexthop->type == NEXTHOP_TYPE_IPV4 || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { - _netlink_route_rta_add_gateway_info(rtmsg->rtm_family, AF_INET, - rta, rtnh, NL_PKT_BUF_SIZE, - bytelen, nexthop); + if (!_netlink_route_add_gateway_info(rtmsg->rtm_family, AF_INET, + nlmsg, req_size, bytelen, + nexthop)) + return false; + if (nexthop->rmap_src.ipv4.s_addr != INADDR_ANY) *src = &nexthop->rmap_src; else if (nexthop->src.ipv4.s_addr != INADDR_ANY) @@ -1394,9 +1398,10 @@ _netlink_route_build_multipath(const struct prefix *p, const char *routedesc, } if (nexthop->type == NEXTHOP_TYPE_IPV6 || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { - _netlink_route_rta_add_gateway_info(rtmsg->rtm_family, AF_INET6, - rta, rtnh, NL_PKT_BUF_SIZE, - bytelen, nexthop); + if (!_netlink_route_add_gateway_info(rtmsg->rtm_family, + AF_INET6, nlmsg, req_size, + bytelen, nexthop)) + return false; if (!IN6_IS_ADDR_UNSPECIFIED(&nexthop->rmap_src.ipv6)) *src = &nexthop->rmap_src; @@ -1433,9 +1438,12 @@ _netlink_route_build_multipath(const struct prefix *p, const char *routedesc, if (nexthop->weight) rtnh->rtnh_hops = nexthop->weight - 1; + + nl_attr_rtnh_end(nlmsg, rtnh); + return true; } -static inline void _netlink_mpls_build_singlepath(const struct prefix *p, +static inline bool _netlink_mpls_build_singlepath(const struct prefix *p, const char *routedesc, const zebra_nhlfe_t *nhlfe, struct nlmsghdr *nlmsg, @@ -1447,31 +1455,33 @@ static inline void _netlink_mpls_build_singlepath(const struct prefix *p, family = NHLFE_FAMILY(nhlfe); bytelen = (family == AF_INET ? 4 : 16); - _netlink_route_build_singlepath(p, routedesc, bytelen, nhlfe->nexthop, - nlmsg, rtmsg, req_size, cmd); + return _netlink_route_build_singlepath(p, routedesc, bytelen, + nhlfe->nexthop, nlmsg, rtmsg, + req_size, cmd); } -static inline void +static inline bool _netlink_mpls_build_multipath(const struct prefix *p, const char *routedesc, - const zebra_nhlfe_t *nhlfe, struct rtattr *rta, - struct rtnexthop *rtnh, struct rtmsg *rtmsg, - const union g_addr **src) + const zebra_nhlfe_t *nhlfe, + struct nlmsghdr *nlmsg, size_t req_size, + struct rtmsg *rtmsg, const union g_addr **src) { int bytelen; uint8_t family; family = NHLFE_FAMILY(nhlfe); bytelen = (family == AF_INET ? 4 : 16); - _netlink_route_build_multipath(p, routedesc, bytelen, nhlfe->nexthop, - rta, rtnh, rtmsg, src); + return _netlink_route_build_multipath(p, routedesc, bytelen, + nhlfe->nexthop, nlmsg, req_size, + rtmsg, src); } static void _netlink_mpls_debug(int cmd, uint32_t label, const char *routedesc) { if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("netlink_mpls_multipath() (%s): %s %u/20", routedesc, - nl_msg_type_to_str(cmd), label); + zlog_debug("netlink_mpls_multipath_msg_encode() (%s): %s %u/20", + routedesc, nl_msg_type_to_str(cmd), label); } static int netlink_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla, @@ -1498,10 +1508,10 @@ static int netlink_neigh_update(int cmd, int ifindex, uint32_t addr, char *lla, req.ndm.ndm_ifindex = ifindex; req.ndm.ndm_type = RTN_UNICAST; - addattr_l(&req.n, sizeof(req), - NDA_PROTOCOL, &protocol, sizeof(protocol)); - addattr_l(&req.n, sizeof(req), NDA_DST, &addr, 4); - addattr_l(&req.n, sizeof(req), NDA_LLADDR, lla, llalen); + nl_attr_put(&req.n, sizeof(req), NDA_PROTOCOL, &protocol, + sizeof(protocol)); + nl_attr_put32(&req.n, sizeof(req), NDA_DST, addr); + nl_attr_put(&req.n, sizeof(req), NDA_LLADDR, lla, llalen); return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0); @@ -1531,29 +1541,44 @@ static bool nexthop_set_src(const struct nexthop *nexthop, int family, return false; } -static void netlink_route_nexthop_encap(struct nlmsghdr *n, size_t nlen, - struct nexthop *nh) +/* + * The function returns true if the attribute could be added + * to the message, otherwise false is returned. + */ +static int netlink_route_nexthop_encap(struct nlmsghdr *n, size_t nlen, + struct nexthop *nh) { struct rtattr *nest; switch (nh->nh_encap_type) { case NET_VXLAN: - addattr_l(n, nlen, RTA_ENCAP_TYPE, &nh->nh_encap_type, - sizeof(uint16_t)); + if (!nl_attr_put16(n, nlen, RTA_ENCAP_TYPE, nh->nh_encap_type)) + return false; + + nest = nl_attr_nest(n, nlen, RTA_ENCAP); + if (!nest) + return false; - nest = addattr_nest(n, nlen, RTA_ENCAP); - addattr32(n, nlen, 0 /* VXLAN_VNI */, nh->nh_encap.vni); - addattr_nest_end(n, nest); + if (!nl_attr_put32(n, nlen, 0 /* VXLAN_VNI */, + nh->nh_encap.vni)) + return false; + nl_attr_nest_end(n, nest); break; } + + return true; } /* * Routing table change via netlink interface, using a dataplane context object + * + * Returns -1 on failure, 0 when the msg doesn't fit entirely in the buffer + * otherwise the number of bytes written to buf. */ -ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, - uint8_t *data, size_t datalen, bool fpm, - bool force_nhg) +ssize_t netlink_route_multipath_msg_encode(int cmd, + struct zebra_dplane_ctx *ctx, + uint8_t *data, size_t datalen, + bool fpm, bool force_nhg) { int bytelen; struct nexthop *nexthop = NULL; @@ -1573,6 +1598,9 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, p = dplane_ctx_get_dest(ctx); src_p = dplane_ctx_get_src(ctx); + if (datalen < sizeof(*req)) + return 0; + memset(req, 0, sizeof(*req)); bytelen = (p->family == AF_INET ? 4 : 16); @@ -1609,9 +1637,13 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, if (cmd != RTM_DELROUTE) req->r.rtm_type = RTN_UNICAST; - addattr_l(&req->n, datalen, RTA_DST, &p->u.prefix, bytelen); - if (src_p) - addattr_l(&req->n, datalen, RTA_SRC, &src_p->u.prefix, bytelen); + if (!nl_attr_put(&req->n, datalen, RTA_DST, &p->u.prefix, bytelen)) + return 0; + if (src_p) { + if (!nl_attr_put(&req->n, datalen, RTA_SRC, &src_p->u.prefix, + bytelen)) + return 0; + } /* Metric. */ /* Hardcode the metric for all routes coming from zebra. Metric isn't @@ -1620,7 +1652,9 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, * path(s) * by the routing protocol and for communicating with protocol peers. */ - addattr32(&req->n, datalen, RTA_PRIORITY, NL_DEFAULT_ROUTE_METRIC); + if (!nl_attr_put32(&req->n, datalen, RTA_PRIORITY, + NL_DEFAULT_ROUTE_METRIC)) + return 0; #if defined(SUPPORT_REALMS) { @@ -1631,8 +1665,10 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, else tag = dplane_ctx_get_tag(ctx); - if (tag > 0 && tag <= 255) - addattr32(&req->n, datalen, RTA_FLOW, tag); + if (tag > 0 && tag <= 255) { + if (!nl_attr_put32(&req->n, datalen, RTA_FLOW, tag)) + return 0; + } } #endif /* Table corresponding to this route. */ @@ -1641,7 +1677,8 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, req->r.rtm_table = table_id; else { req->r.rtm_table = RT_TABLE_UNSPEC; - addattr32(&req->n, datalen, RTA_TABLE, table_id); + if (!nl_attr_put32(&req->n, datalen, RTA_TABLE, table_id)) + return 0; } if (IS_ZEBRA_DEBUG_KERNEL) @@ -1657,33 +1694,34 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, * it. */ if (cmd == RTM_DELROUTE) - return req->n.nlmsg_len; + return NLMSG_ALIGN(req->n.nlmsg_len); if (dplane_ctx_get_mtu(ctx) || dplane_ctx_get_nh_mtu(ctx)) { - char buf[NL_PKT_BUF_SIZE]; - struct rtattr *rta = (void *)buf; + struct rtattr *nest; uint32_t mtu = dplane_ctx_get_mtu(ctx); uint32_t nexthop_mtu = dplane_ctx_get_nh_mtu(ctx); if (!mtu || (nexthop_mtu && nexthop_mtu < mtu)) mtu = nexthop_mtu; - rta->rta_type = RTA_METRICS; - rta->rta_len = RTA_LENGTH(0); - rta_addattr_l(rta, NL_PKT_BUF_SIZE, - RTAX_MTU, &mtu, sizeof(mtu)); - addattr_l(&req->n, datalen, RTA_METRICS, RTA_DATA(rta), - RTA_PAYLOAD(rta)); + + nest = nl_attr_nest(&req->n, datalen, RTA_METRICS); + if (nest == NULL) + return 0; + + if (!nl_attr_put(&req->n, datalen, RTAX_MTU, &mtu, sizeof(mtu))) + return 0; + nl_attr_nest_end(&req->n, nest); } if (kernel_nexthops_supported() || force_nhg) { /* Kernel supports nexthop objects */ if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug( - "netlink_route_multipath(): %pFX nhg_id is %u", - p, dplane_ctx_get_nhe_id(ctx)); + zlog_debug("%s: %pFX nhg_id is %u", __func__, p, + dplane_ctx_get_nhe_id(ctx)); - addattr32(&req->n, datalen, RTA_NH_ID, - dplane_ctx_get_nhe_id(ctx)); + if (!nl_attr_put32(&req->n, datalen, RTA_NH_ID, + dplane_ctx_get_nhe_id(ctx))) + return 0; /* Have to determine src still */ for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) { @@ -1694,15 +1732,18 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, } if (setsrc) { - if (p->family == AF_INET) - addattr_l(&req->n, datalen, RTA_PREFSRC, - &src.ipv4, bytelen); - else if (p->family == AF_INET6) - addattr_l(&req->n, datalen, RTA_PREFSRC, - &src.ipv6, bytelen); + if (p->family == AF_INET) { + if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC, + &src.ipv4, bytelen)) + return 0; + } else if (p->family == AF_INET6) { + if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC, + &src.ipv6, bytelen)) + return 0; + } } - return req->n.nlmsg_len; + return NLMSG_ALIGN(req->n.nlmsg_len); } /* Count overall nexthops so we can decide whether to use singlepath @@ -1741,7 +1782,7 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, req->r.rtm_type = RTN_BLACKHOLE; break; } - return req->n.nlmsg_len; + return NLMSG_ALIGN(req->n.nlmsg_len); } if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) { @@ -1759,9 +1800,10 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, ? "recursive, single-path" : "single-path"; - _netlink_route_build_singlepath( - p, routedesc, bytelen, nexthop, &req->n, - &req->r, datalen, cmd); + if (!_netlink_route_build_singlepath( + p, routedesc, bytelen, nexthop, + &req->n, &req->r, datalen, cmd)) + return 0; nexthop_num++; break; } @@ -1770,28 +1812,31 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, * Add encapsulation information when installing via * FPM. */ - if (fpm) - netlink_route_nexthop_encap(&req->n, datalen, - nexthop); + if (fpm) { + if (!netlink_route_nexthop_encap( + &req->n, datalen, nexthop)) + return 0; + } } if (setsrc) { - if (p->family == AF_INET) - addattr_l(&req->n, datalen, RTA_PREFSRC, - &src.ipv4, bytelen); - else if (p->family == AF_INET6) - addattr_l(&req->n, datalen, RTA_PREFSRC, - &src.ipv6, bytelen); + if (p->family == AF_INET) { + if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC, + &src.ipv4, bytelen)) + return 0; + } else if (p->family == AF_INET6) { + if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC, + &src.ipv6, bytelen)) + return 0; + } } } else { /* Multipath case */ - char buf[NL_PKT_BUF_SIZE]; - struct rtattr *rta = (void *)buf; - struct rtnexthop *rtnh; + struct rtattr *nest; const union g_addr *src1 = NULL; - rta->rta_type = RTA_MULTIPATH; - rta->rta_len = RTA_LENGTH(0); - rtnh = RTA_DATA(rta); + nest = nl_attr_nest(&req->n, datalen, RTA_MULTIPATH); + if (nest == NULL) + return 0; nexthop_num = 0; for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), nexthop)) { @@ -1812,10 +1857,10 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, : "multipath"; nexthop_num++; - _netlink_route_build_multipath( - p, routedesc, bytelen, nexthop, rta, - rtnh, &req->r, &src1); - rtnh = RTNH_NEXT(rtnh); + if (!_netlink_route_build_multipath( + p, routedesc, bytelen, nexthop, + &req->n, datalen, &req->r, &src1)) + return 0; if (!setsrc && src1) { if (p->family == AF_INET) @@ -1826,30 +1871,40 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, setsrc = 1; } } + } - /* - * Add encapsulation information when installing via - * FPM. - */ - if (fpm) - netlink_route_nexthop_encap(&req->n, datalen, - nexthop); + nl_attr_nest_end(&req->n, nest); + + /* + * Add encapsulation information when installing via + * FPM. + */ + if (fpm) { + for (ALL_NEXTHOPS_PTR(dplane_ctx_get_ng(ctx), + nexthop)) { + if (CHECK_FLAG(nexthop->flags, + NEXTHOP_FLAG_RECURSIVE)) + continue; + if (!netlink_route_nexthop_encap( + &req->n, datalen, nexthop)) + return 0; + } } + if (setsrc) { - if (p->family == AF_INET) - addattr_l(&req->n, datalen, RTA_PREFSRC, - &src.ipv4, bytelen); - else if (p->family == AF_INET6) - addattr_l(&req->n, datalen, RTA_PREFSRC, - &src.ipv6, bytelen); + if (p->family == AF_INET) { + if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC, + &src.ipv4, bytelen)) + return 0; + } else if (p->family == AF_INET6) { + if (!nl_attr_put(&req->n, datalen, RTA_PREFSRC, + &src.ipv6, bytelen)) + return 0; + } if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("Setting source"); } - - if (rta->rta_len > RTA_LENGTH(0)) - addattr_l(&req->n, datalen, RTA_MULTIPATH, - RTA_DATA(rta), RTA_PAYLOAD(rta)); } /* If there is no useful nexthop then return. */ @@ -1858,7 +1913,7 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, zlog_debug("%s: No useful nexthop.", __func__); } - return req->n.nlmsg_len; + return NLMSG_ALIGN(req->n.nlmsg_len); } int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in) @@ -1885,10 +1940,10 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in) req.ndm.ndm_family = RTNL_FAMILY_IPMR; req.n.nlmsg_type = RTM_GETROUTE; - addattr_l(&req.n, sizeof(req), RTA_IIF, &mroute->ifindex, 4); - addattr_l(&req.n, sizeof(req), RTA_OIF, &mroute->ifindex, 4); - addattr_l(&req.n, sizeof(req), RTA_SRC, &mroute->sg.src.s_addr, 4); - addattr_l(&req.n, sizeof(req), RTA_DST, &mroute->sg.grp.s_addr, 4); + nl_attr_put32(&req.n, sizeof(req), RTA_IIF, mroute->ifindex); + nl_attr_put32(&req.n, sizeof(req), RTA_OIF, mroute->ifindex); + nl_attr_put32(&req.n, sizeof(req), RTA_SRC, mroute->sg.src.s_addr); + nl_attr_put32(&req.n, sizeof(req), RTA_DST, mroute->sg.grp.s_addr); /* * What? * @@ -1905,7 +1960,7 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in) */ actual_table = (zvrf->table_id == RT_TABLE_MAIN) ? RT_TABLE_DEFAULT : zvrf->table_id; - addattr_l(&req.n, sizeof(req), RTA_TABLE, &actual_table, 4); + nl_attr_put32(&req.n, sizeof(req), RTA_TABLE, actual_table); suc = netlink_talk(netlink_route_change_read_multicast, &req.n, &zns->netlink_cmd, zns, 0); @@ -1917,7 +1972,7 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in) /* Char length to debug ID with */ #define ID_LENGTH 10 -static void _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size, +static bool _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size, uint32_t id, const struct nh_grp *z_grp, const uint8_t count) @@ -1947,11 +2002,15 @@ static void _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size, } } } - addattr_l(n, req_size, NHA_GROUP, grp, count * sizeof(*grp)); + if (!nl_attr_put(n, req_size, NHA_GROUP, grp, + count * sizeof(*grp))) + return false; } if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("%s: ID (%u): %s", __func__, id, buf); + + return true; } /** @@ -1962,10 +2021,12 @@ static void _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size, * \param[out] buf buffer to hold the packet. * \param[in] buflen amount of buffer bytes. * - * \returns -1 on failure or the number of bytes written to buf. + * \returns -1 on failure, 0 when the msg doesn't fit entirely in the buffer + * otherwise the number of bytes written to buf. */ -ssize_t netlink_nexthop_encode(uint16_t cmd, const struct zebra_dplane_ctx *ctx, - void *buf, size_t buflen) +ssize_t netlink_nexthop_msg_encode(uint16_t cmd, + const struct zebra_dplane_ctx *ctx, + void *buf, size_t buflen) { struct { struct nlmsghdr n; @@ -1979,7 +2040,10 @@ ssize_t netlink_nexthop_encode(uint16_t cmd, const struct zebra_dplane_ctx *ctx, label_buf[0] = '\0'; - memset(req, 0, buflen); + if (buflen < sizeof(*req)) + return 0; + + memset(req, 0, sizeof(*req)); req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg)); req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; @@ -2002,7 +2066,8 @@ ssize_t netlink_nexthop_encode(uint16_t cmd, const struct zebra_dplane_ctx *ctx, return -1; } - addattr32(&req->n, buflen, NHA_ID, id); + if (!nl_attr_put32(&req->n, buflen, NHA_ID, id)) + return 0; if (cmd == RTM_NEWNEXTHOP) { /* @@ -2011,12 +2076,13 @@ ssize_t netlink_nexthop_encode(uint16_t cmd, const struct zebra_dplane_ctx *ctx, * group is installed as an id that just refers to a list of * other ids. */ - if (dplane_ctx_get_nhe_nh_grp_count(ctx)) - _netlink_nexthop_build_group( - &req->n, buflen, id, - dplane_ctx_get_nhe_nh_grp(ctx), - dplane_ctx_get_nhe_nh_grp_count(ctx)); - else { + if (dplane_ctx_get_nhe_nh_grp_count(ctx)) { + if (!_netlink_nexthop_build_group( + &req->n, buflen, id, + dplane_ctx_get_nhe_nh_grp(ctx), + dplane_ctx_get_nhe_nh_grp_count(ctx))) + return 0; + } else { const struct nexthop *nh = dplane_ctx_get_nhe_ng(ctx)->nexthop; afi_t afi = dplane_ctx_get_nhe_afi(ctx); @@ -2029,17 +2095,22 @@ ssize_t netlink_nexthop_encode(uint16_t cmd, const struct zebra_dplane_ctx *ctx, switch (nh->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: - addattr_l(&req->n, buflen, NHA_GATEWAY, - &nh->gate.ipv4, IPV4_MAX_BYTELEN); + if (!nl_attr_put(&req->n, buflen, NHA_GATEWAY, + &nh->gate.ipv4, + IPV4_MAX_BYTELEN)) + return 0; break; case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: - addattr_l(&req->n, buflen, NHA_GATEWAY, - &nh->gate.ipv6, IPV6_MAX_BYTELEN); + if (!nl_attr_put(&req->n, buflen, NHA_GATEWAY, + &nh->gate.ipv6, + IPV6_MAX_BYTELEN)) + return 0; break; case NEXTHOP_TYPE_BLACKHOLE: - addattr_l(&req->n, buflen, NHA_BLACKHOLE, NULL, - 0); + if (!nl_attr_put(&req->n, buflen, NHA_BLACKHOLE, + NULL, 0)) + return 0; /* Blackhole shouldn't have anymore attributes */ goto nexthop_done; @@ -2055,7 +2126,9 @@ ssize_t netlink_nexthop_encode(uint16_t cmd, const struct zebra_dplane_ctx *ctx, return -1; } - addattr32(&req->n, buflen, NHA_OIF, nh->ifindex); + if (!nl_attr_put32(&req->n, buflen, NHA_OIF, + nh->ifindex)) + return 0; if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ONLINK)) req->nhm.nh_flags |= RTNH_F_ONLINK; @@ -2075,25 +2148,32 @@ ssize_t netlink_nexthop_encode(uint16_t cmd, const struct zebra_dplane_ctx *ctx, if (req->nhm.nh_family == AF_MPLS) goto nexthop_done; #if 0 - addattr_l(&req->n, buflen, NHA_NEWDST, + if (!nl_attr_put(&req->n, buflen, NHA_NEWDST, &out_lse, num_labels - * sizeof(mpls_lse_t)); + * sizeof(mpls_lse_t))) + return 0; #endif else { struct rtattr *nest; uint16_t encap = LWTUNNEL_ENCAP_MPLS; - addattr_l(&req->n, buflen, - NHA_ENCAP_TYPE, &encap, - sizeof(uint16_t)); - nest = addattr_nest(&req->n, buflen, + if (!nl_attr_put16(&req->n, buflen, + NHA_ENCAP_TYPE, + encap)) + return 0; + nest = nl_attr_nest(&req->n, buflen, NHA_ENCAP); - addattr_l(&req->n, buflen, - MPLS_IPTUNNEL_DST, &out_lse, - num_labels - * sizeof(mpls_lse_t)); - addattr_nest_end(&req->n, nest); + if (!nest) + return 0; + if (!nl_attr_put( + &req->n, buflen, + MPLS_IPTUNNEL_DST, &out_lse, + num_labels + * sizeof( + mpls_lse_t))) + return 0; + nl_attr_nest_end(&req->n, nest); } } @@ -2104,7 +2184,7 @@ nexthop_done: __func__, id, nh, nh->ifindex, vrf_id_to_name(nh->vrf_id), nh->vrf_id, label_buf); - } +} req->nhm.nh_protocol = zebra2proto(dplane_ctx_get_nhe_type(ctx)); @@ -2154,7 +2234,7 @@ enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx) if (!kernel_nexthops_supported()) return ZEBRA_DPLANE_REQUEST_SUCCESS; - if (netlink_nexthop_encode(cmd, ctx, buf, sizeof(buf)) > 0) + if (netlink_nexthop_msg_encode(cmd, ctx, buf, sizeof(buf)) > 0) ret = netlink_talk_info(netlink_talk_filter, (void *)&buf, dplane_ctx_get_ns(ctx), 0); else @@ -2195,12 +2275,14 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) */ if (RSYSTEM_ROUTE(dplane_ctx_get_type(ctx)) && !RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) { - netlink_route_multipath(RTM_DELROUTE, ctx, - nl_pkt, sizeof(nl_pkt), - false, false); - netlink_talk_info(netlink_talk_filter, - (struct nlmsghdr *)nl_pkt, - dplane_ctx_get_ns(ctx), 0); + if (netlink_route_multipath_msg_encode( + RTM_DELROUTE, ctx, nl_pkt, + sizeof(nl_pkt), false, false) + > 0) + netlink_talk_info( + netlink_talk_filter, + (struct nlmsghdr *)nl_pkt, + dplane_ctx_get_ns(ctx), 0); } } else { /* @@ -2216,12 +2298,14 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) * screwed. */ if (!RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) { - netlink_route_multipath(RTM_DELROUTE, ctx, - nl_pkt, sizeof(nl_pkt), - false, false); - netlink_talk_info(netlink_talk_filter, - (struct nlmsghdr *)nl_pkt, - dplane_ctx_get_ns(ctx), 0); + if (netlink_route_multipath_msg_encode( + RTM_DELROUTE, ctx, nl_pkt, + sizeof(nl_pkt), false, false) + > 0) + netlink_talk_info( + netlink_talk_filter, + (struct nlmsghdr *)nl_pkt, + dplane_ctx_get_ns(ctx), 0); } cmd = RTM_NEWROUTE; } @@ -2231,11 +2315,15 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) } if (!RSYSTEM_ROUTE(dplane_ctx_get_type(ctx))) { - netlink_route_multipath(cmd, ctx, nl_pkt, sizeof(nl_pkt), false, - false); - ret = netlink_talk_info(netlink_talk_filter, - (struct nlmsghdr *)nl_pkt, - dplane_ctx_get_ns(ctx), 0); + if (netlink_route_multipath_msg_encode( + cmd, ctx, nl_pkt, sizeof(nl_pkt), false, false) + > 0) + ret = netlink_talk_info(netlink_talk_filter, + (struct nlmsghdr *)nl_pkt, + dplane_ctx_get_ns(ctx), 0); + else + ret = -1; + } else ret = 0; if ((cmd == RTM_NEWROUTE) && (ret == 0)) { @@ -2559,8 +2647,8 @@ int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla, } /** - * netlink_update_neigh_ctx_internal() - Common helper api for evpn - * neighbor updates using dataplane context object. + * netlink_neigh_update_msg_encode() - Common helper api for encoding + * evpn neighbor update as netlink messages using dataplane context object. * Here, a neighbor refers to a bridge forwarding database entry for * either unicast forwarding or head-end replication or an IP neighbor * entry. @@ -2579,14 +2667,13 @@ int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla, * @data: data buffer pointer * @datalen: total amount of data buffer space * - * Return: Result status + * Return: 0 when the msg doesn't fit entirely in the buffer + * otherwise the number of bytes written to buf. */ -static ssize_t -netlink_update_neigh_ctx_internal(const struct zebra_dplane_ctx *ctx, - int cmd, const struct ethaddr *mac, - const struct ipaddr *ip, bool replace_obj, - uint8_t family, uint8_t type, uint8_t flags, - uint16_t state, void *data, size_t datalen) +static ssize_t netlink_neigh_update_msg_encode( + const struct zebra_dplane_ctx *ctx, int cmd, const struct ethaddr *mac, + const struct ipaddr *ip, bool replace_obj, uint8_t family, uint8_t type, + uint8_t flags, uint16_t state, void *data, size_t datalen) { uint8_t protocol = RTPROT_ZEBRA; struct { @@ -2597,6 +2684,8 @@ netlink_update_neigh_ctx_internal(const struct zebra_dplane_ctx *ctx, int ipa_len; enum dplane_op_e op; + if (datalen < sizeof(*req)) + return 0; memset(req, 0, datalen); op = dplane_ctx_get_op(ctx); @@ -2614,22 +2703,30 @@ netlink_update_neigh_ctx_internal(const struct zebra_dplane_ctx *ctx, req->ndm.ndm_flags = flags; req->ndm.ndm_ifindex = dplane_ctx_get_ifindex(ctx); - addattr_l(&req->n, sizeof(req), - NDA_PROTOCOL, &protocol, sizeof(protocol)); - if (mac) - addattr_l(&req->n, datalen, NDA_LLADDR, mac, 6); + if (!nl_attr_put(&req->n, sizeof(req), NDA_PROTOCOL, &protocol, + sizeof(protocol))) + return 0; + + if (mac) { + if (!nl_attr_put(&req->n, datalen, NDA_LLADDR, mac, 6)) + return 0; + } ipa_len = IS_IPADDR_V4(ip) ? IPV4_MAX_BYTELEN : IPV6_MAX_BYTELEN; - addattr_l(&req->n, datalen, NDA_DST, &ip->ip.addr, ipa_len); + if (!nl_attr_put(&req->n, datalen, NDA_DST, &ip->ip.addr, ipa_len)) + return 0; if (op == DPLANE_OP_MAC_INSTALL || op == DPLANE_OP_MAC_DELETE) { vlanid_t vid = dplane_ctx_mac_get_vlan(ctx); - if (vid > 0) - addattr16(&req->n, datalen, NDA_VLAN, vid); + if (vid > 0) { + if (!nl_attr_put16(&req->n, datalen, NDA_VLAN, vid)) + return 0; + } - addattr32(&req->n, datalen, NDA_MASTER, - dplane_ctx_mac_get_br_ifindex(ctx)); + if (!nl_attr_put32(&req->n, datalen, NDA_MASTER, + dplane_ctx_mac_get_br_ifindex(ctx))) + return 0; } return NLMSG_ALIGN(req->n.nlmsg_len); @@ -2645,10 +2742,12 @@ static int netlink_vxlan_flood_update_ctx(const struct zebra_dplane_ctx *ctx, struct ethaddr dst_mac = {.octet = {0}}; uint8_t nl_pkt[NL_PKT_BUF_SIZE]; - netlink_update_neigh_ctx_internal( - ctx, cmd, &dst_mac, dplane_ctx_neigh_get_ipaddr(ctx), false, - PF_BRIDGE, 0, NTF_SELF, (NUD_NOARP | NUD_PERMANENT), nl_pkt, - sizeof(nl_pkt)); + if (netlink_neigh_update_msg_encode( + ctx, cmd, &dst_mac, dplane_ctx_neigh_get_ipaddr(ctx), false, + PF_BRIDGE, 0, NTF_SELF, (NUD_NOARP | NUD_PERMANENT), nl_pkt, + sizeof(nl_pkt)) + <= 0) + return -1; return netlink_talk_info(netlink_talk_filter, (struct nlmsghdr *)nl_pkt, @@ -2845,7 +2944,7 @@ static int netlink_request_macs(struct nlsock *netlink_cmd, int family, req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); req.ifm.ifi_family = family; if (master_ifindex) - addattr32(&req.n, sizeof(req), IFLA_MASTER, master_ifindex); + nl_attr_put32(&req.n, sizeof(req), IFLA_MASTER, master_ifindex); return netlink_request(netlink_cmd, &req); } @@ -2934,13 +3033,13 @@ static int netlink_request_specific_mac_in_bridge(struct zebra_ns *zns, req.ndm.ndm_family = family; /* AF_BRIDGE */ /* req.ndm.ndm_state = NUD_REACHABLE; */ - addattr_l(&req.n, sizeof(req), NDA_LLADDR, mac, 6); + nl_attr_put(&req.n, sizeof(req), NDA_LLADDR, mac, 6); br_zif = (struct zebra_if *)br_if->info; if (IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(br_zif) && vid > 0) - addattr16(&req.n, sizeof(req), NDA_VLAN, vid); + nl_attr_put16(&req.n, sizeof(req), NDA_VLAN, vid); - addattr32(&req.n, sizeof(req), NDA_MASTER, br_if->ifindex); + nl_attr_put32(&req.n, sizeof(req), NDA_MASTER, br_if->ifindex); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( @@ -3026,9 +3125,9 @@ netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, uint8_t *data, ipaddr2str(&vtep_ip, ipbuf, sizeof(ipbuf))); } - total = netlink_update_neigh_ctx_internal( - ctx, cmd, dplane_ctx_mac_get_addr(ctx), &vtep_ip, - true, AF_BRIDGE, 0, flags, state, data, datalen); + total = netlink_neigh_update_msg_encode( + ctx, cmd, dplane_ctx_mac_get_addr(ctx), &vtep_ip, true, + AF_BRIDGE, 0, flags, state, data, datalen); return total; } @@ -3246,7 +3345,7 @@ static int netlink_request_neigh(struct nlsock *netlink_cmd, int family, req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ndmsg)); req.ndm.ndm_family = family; if (ifindex) - addattr32(&req.n, sizeof(req), NDA_IFINDEX, ifindex); + nl_attr_put32(&req.n, sizeof(req), NDA_IFINDEX, ifindex); return netlink_request(netlink_cmd, &req); } @@ -3325,7 +3424,7 @@ static int netlink_request_specific_neigh_in_vlan(struct zebra_ns *zns, req.ndm.ndm_family = AF_INET6; } - addattr_l(&req.n, sizeof(req), NDA_DST, &ip->ip.addr, ipa_len); + nl_attr_put(&req.n, sizeof(req), NDA_DST, &ip->ip.addr, ipa_len); if (IS_ZEBRA_DEBUG_KERNEL) { char buf[INET6_ADDRSTRLEN]; @@ -3444,9 +3543,11 @@ static int netlink_neigh_update_ctx(const struct zebra_dplane_ctx *ctx, flags, state); } - netlink_update_neigh_ctx_internal( - ctx, cmd, mac, ip, true, family, RTN_UNICAST, flags, - state, nl_pkt, sizeof(nl_pkt)); + if (netlink_neigh_update_msg_encode(ctx, cmd, mac, ip, true, family, + RTN_UNICAST, flags, state, nl_pkt, + sizeof(nl_pkt)) + <= 0) + return -1; return netlink_talk_info(netlink_talk_filter, (struct nlmsghdr *)nl_pkt, dplane_ctx_get_ns(ctx), 0); @@ -3501,7 +3602,8 @@ enum zebra_dplane_result kernel_neigh_update_ctx(struct zebra_dplane_ctx *ctx) * MPLS label forwarding table change via netlink interface, using dataplane * context information. */ -int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx) +ssize_t netlink_mpls_multipath_msg_encode(int cmd, struct zebra_dplane_ctx *ctx, + void *buf, size_t buflen) { mpls_lse_t lse; const struct nhlfe_list_head *head; @@ -3515,10 +3617,13 @@ int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx) struct { struct nlmsghdr n; struct rtmsg r; - char buf[NL_PKT_BUF_SIZE]; - } req; + char buf[0]; + } *req = buf; - memset(&req, 0, sizeof(req) - NL_PKT_BUF_SIZE); + if (buflen < sizeof(*req)) + return 0; + + memset(req, 0, sizeof(*req)); /* * Count # nexthops so we can decide whether to use singlepath @@ -3547,30 +3652,31 @@ int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx) (!dplane_ctx_get_best_nhlfe(ctx) && (cmd != RTM_DELROUTE))) return 0; - req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); - req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; - req.n.nlmsg_type = cmd; - req.n.nlmsg_pid = dplane_ctx_get_ns(ctx)->nls.snl.nl_pid; + req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); + req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; + req->n.nlmsg_type = cmd; + req->n.nlmsg_pid = dplane_ctx_get_ns(ctx)->nls.snl.nl_pid; - req.r.rtm_family = AF_MPLS; - req.r.rtm_table = RT_TABLE_MAIN; - req.r.rtm_dst_len = MPLS_LABEL_LEN_BITS; - req.r.rtm_scope = RT_SCOPE_UNIVERSE; - req.r.rtm_type = RTN_UNICAST; + req->r.rtm_family = AF_MPLS; + req->r.rtm_table = RT_TABLE_MAIN; + req->r.rtm_dst_len = MPLS_LABEL_LEN_BITS; + req->r.rtm_scope = RT_SCOPE_UNIVERSE; + req->r.rtm_type = RTN_UNICAST; if (cmd == RTM_NEWROUTE) { /* We do a replace to handle update. */ - req.n.nlmsg_flags |= NLM_F_REPLACE; + req->n.nlmsg_flags |= NLM_F_REPLACE; /* set the protocol value if installing */ route_type = re_type_from_lsp_type( dplane_ctx_get_best_nhlfe(ctx)->type); - req.r.rtm_protocol = zebra2proto(route_type); + req->r.rtm_protocol = zebra2proto(route_type); } /* Fill destination */ lse = mpls_lse_encode(dplane_ctx_get_in_label(ctx), 0, 0, 1); - addattr_l(&req.n, sizeof(req), RTA_DST, &lse, sizeof(mpls_lse_t)); + if (!nl_attr_put(&req->n, buflen, RTA_DST, &lse, sizeof(mpls_lse_t))) + return 0; /* Fill nexthops (paths) based on single-path or multipath. The paths * chosen depend on the operation. @@ -3596,23 +3702,22 @@ int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx) && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB)))) { /* Add the gateway */ - _netlink_mpls_build_singlepath( - &p, routedesc, nhlfe, &req.n, &req.r, - sizeof(req), cmd); + if (!_netlink_mpls_build_singlepath( + &p, routedesc, nhlfe, &req->n, + &req->r, buflen, cmd)) + return false; nexthop_num++; break; } } } else { /* Multipath case */ - char buf[NL_PKT_BUF_SIZE]; - struct rtattr *rta = (void *)buf; - struct rtnexthop *rtnh; + struct rtattr *nest; const union g_addr *src1 = NULL; - rta->rta_type = RTA_MULTIPATH; - rta->rta_len = RTA_LENGTH(0); - rtnh = RTA_DATA(rta); + nest = nl_attr_nest(&req->n, buflen, RTA_MULTIPATH); + if (!nest) + return 0; routedesc = "multipath"; _netlink_mpls_debug(cmd, dplane_ctx_get_in_label(ctx), @@ -3636,21 +3741,17 @@ int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx) nexthop_num++; /* Build the multipath */ - _netlink_mpls_build_multipath(&p, routedesc, - nhlfe, rta, rtnh, - &req.r, &src1); - rtnh = RTNH_NEXT(rtnh); + if (!_netlink_mpls_build_multipath( + &p, routedesc, nhlfe, &req->n, + buflen, &req->r, &src1)) + return 0; } } /* Add the multipath */ - if (rta->rta_len > RTA_LENGTH(0)) - addattr_l(&req.n, NL_PKT_BUF_SIZE, RTA_MULTIPATH, - RTA_DATA(rta), RTA_PAYLOAD(rta)); + nl_attr_nest_end(&req->n, nest); } - /* Talk to netlink socket. */ - return netlink_talk_info(netlink_talk_filter, &req.n, - dplane_ctx_get_ns(ctx), 0); + return NLMSG_ALIGN(req->n.nlmsg_len); } #endif /* HAVE_NETLINK */ diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h index c09609f47c..429ff0bf85 100644 --- a/zebra/rt_netlink.h +++ b/zebra/rt_netlink.h @@ -64,11 +64,14 @@ extern "C" { void rt_netlink_init(void); /* MPLS label forwarding table change, using dataplane context information. */ -extern int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx); +extern ssize_t netlink_mpls_multipath_msg_encode(int cmd, + struct zebra_dplane_ctx *ctx, + void *buf, size_t buflen); -extern ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, - uint8_t *data, size_t datalen, bool fpm, - bool force_nhg); +extern ssize_t netlink_route_multipath_msg_encode(int cmd, + struct zebra_dplane_ctx *ctx, + uint8_t *data, size_t datalen, + bool fpm, bool force_nhg); extern ssize_t netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, uint8_t *data, size_t datalen); @@ -78,9 +81,9 @@ extern int netlink_route_read(struct zebra_ns *zns); extern int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup); extern int netlink_nexthop_read(struct zebra_ns *zns); -extern ssize_t netlink_nexthop_encode(uint16_t cmd, - const struct zebra_dplane_ctx *ctx, - void *buf, size_t buflen); +extern ssize_t netlink_nexthop_msg_encode(uint16_t cmd, + const struct zebra_dplane_ctx *ctx, + void *buf, size_t buflen); extern int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id); extern int netlink_macfdb_read(struct zebra_ns *zns); diff --git a/zebra/rule_netlink.c b/zebra/rule_netlink.c index 9da008bb61..b7be398506 100644 --- a/zebra/rule_netlink.c +++ b/zebra/rule_netlink.c @@ -55,8 +55,8 @@ * * Encodes netlink RTM_ADDRULE/RTM_DELRULE message to buffer buf of size buflen. * - * Returns -1 on failure or the number of bytes - * written to buf. + * Returns -1 on failure, 0 when the msg doesn't fit entirely in the buffer + * or the number of bytes written to buf. */ static ssize_t netlink_rule_msg_encode( int cmd, const struct zebra_dplane_ctx *ctx, uint32_t filter_bm, @@ -87,36 +87,48 @@ static ssize_t netlink_rule_msg_encode( req->frh.family = family; req->frh.action = FR_ACT_TO_TBL; - addattr_l(&req->n, buflen, FRA_PROTOCOL, &protocol, sizeof(protocol)); + if (!nl_attr_put(&req->n, buflen, FRA_PROTOCOL, &protocol, + sizeof(protocol))) + return 0; /* rule's pref # */ - addattr32(&req->n, buflen, FRA_PRIORITY, priority); + if (!nl_attr_put32(&req->n, buflen, FRA_PRIORITY, priority)) + return 0; /* interface on which applied */ - addattr_l(&req->n, buflen, FRA_IFNAME, ifname, strlen(ifname) + 1); + if (!nl_attr_put(&req->n, buflen, FRA_IFNAME, ifname, + strlen(ifname) + 1)) + return 0; /* source IP, if specified */ if (filter_bm & PBR_FILTER_SRC_IP) { req->frh.src_len = src_ip->prefixlen; - addattr_l(&req->n, buflen, FRA_SRC, &src_ip->u.prefix, bytelen); + if (!nl_attr_put(&req->n, buflen, FRA_SRC, &src_ip->u.prefix, + bytelen)) + return 0; } /* destination IP, if specified */ if (filter_bm & PBR_FILTER_DST_IP) { req->frh.dst_len = dst_ip->prefixlen; - addattr_l(&req->n, buflen, FRA_DST, &dst_ip->u.prefix, bytelen); + if (!nl_attr_put(&req->n, buflen, FRA_DST, &dst_ip->u.prefix, + bytelen)) + return 0; } /* fwmark, if specified */ - if (filter_bm & PBR_FILTER_FWMARK) - addattr32(&req->n, buflen, FRA_FWMARK, fwmark); + if (filter_bm & PBR_FILTER_FWMARK) { + if (!nl_attr_put32(&req->n, buflen, FRA_FWMARK, fwmark)) + return 0; + } /* Route table to use to forward, if filter criteria matches. */ if (table < 256) req->frh.table = table; else { req->frh.table = RT_TABLE_UNSPEC; - addattr32(&req->n, buflen, FRA_TABLE, table); + if (!nl_attr_put32(&req->n, buflen, FRA_TABLE, table)) + return 0; } if (IS_ZEBRA_DEBUG_KERNEL) diff --git a/zebra/subdir.am b/zebra/subdir.am index d98ef52571..49e60820bc 100644 --- a/zebra/subdir.am +++ b/zebra/subdir.am @@ -44,6 +44,7 @@ endif zebra_zebra_LDADD = lib/libfrr.la $(LIBCAP) if HAVE_PROTOBUF3 zebra_zebra_LDADD += mlag/libmlag_pb.la $(PROTOBUF_C_LIBS) +zebra/zebra_mlag.$(OBJEXT): mlag/mlag.pb-c.h endif zebra_zebra_SOURCES = \ zebra/connected.c \ @@ -188,8 +189,10 @@ zebra_zebra_fpm_la_SOURCES += zebra/zebra_fpm_netlink.c if HAVE_PROTOBUF zebra_zebra_fpm_la_LIBADD += fpm/libfrrfpm_pb.la qpb/libfrr_pb.la $(PROTOBUF_C_LIBS) zebra_zebra_fpm_la_SOURCES += zebra/zebra_fpm_protobuf.c +zebra/zebra_fpm_protobuf.lo: fpm/fpm.pb-c.h qpb/qpb.pb-c.h if DEV_BUILD zebra_zebra_fpm_la_SOURCES += zebra/zebra_fpm_dt.c +zebra/zebra_fpm_dt.lo: fpm/fpm.pb-c.h qpb/qpb.pb-c.h endif endif diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c index b194f80fc7..a18885ddb7 100644 --- a/zebra/zebra_fpm_netlink.c +++ b/zebra/zebra_fpm_netlink.c @@ -361,9 +361,9 @@ static int netlink_route_info_encode(struct netlink_route_info *ri, size_t buf_offset; struct netlink_nh_info *nhi; enum fpm_nh_encap_type_t encap; - struct rtattr *nest; + struct rtattr *nest, *inner_nest; + struct rtnexthop *rtnh; struct vxlan_encap_info_t *vxlan; - int nest_len; struct { struct nlmsghdr n; @@ -400,20 +400,21 @@ static int netlink_route_info_encode(struct netlink_route_info *ri, req->r.rtm_table = ri->rtm_table; else { req->r.rtm_table = RT_TABLE_UNSPEC; - addattr32(&req->n, in_buf_len, RTA_TABLE, ri->rtm_table); + nl_attr_put32(&req->n, in_buf_len, RTA_TABLE, ri->rtm_table); } req->r.rtm_dst_len = ri->prefix->prefixlen; req->r.rtm_protocol = ri->rtm_protocol; req->r.rtm_scope = RT_SCOPE_UNIVERSE; - addattr_l(&req->n, in_buf_len, RTA_DST, &ri->prefix->u.prefix, bytelen); + nl_attr_put(&req->n, in_buf_len, RTA_DST, &ri->prefix->u.prefix, + bytelen); req->r.rtm_type = ri->rtm_type; /* Metric. */ if (ri->metric) - addattr32(&req->n, in_buf_len, RTA_PRIORITY, *ri->metric); + nl_attr_put32(&req->n, in_buf_len, RTA_PRIORITY, *ri->metric); if (ri->num_nhs == 0) goto done; @@ -422,12 +423,13 @@ static int netlink_route_info_encode(struct netlink_route_info *ri, nhi = &ri->nhs[0]; if (nhi->gateway) { - addattr_l(&req->n, in_buf_len, RTA_GATEWAY, - nhi->gateway, bytelen); + nl_attr_put(&req->n, in_buf_len, RTA_GATEWAY, + nhi->gateway, bytelen); } if (nhi->if_index) { - addattr32(&req->n, in_buf_len, RTA_OIF, nhi->if_index); + nl_attr_put32(&req->n, in_buf_len, RTA_OIF, + nhi->if_index); } encap = nhi->encap_info.encap_type; @@ -436,12 +438,13 @@ static int netlink_route_info_encode(struct netlink_route_info *ri, case FPM_NH_ENCAP_MAX: break; case FPM_NH_ENCAP_VXLAN: - addattr_l(&req->n, in_buf_len, RTA_ENCAP_TYPE, &encap, - sizeof(uint16_t)); + nl_attr_put16(&req->n, in_buf_len, RTA_ENCAP_TYPE, + encap); vxlan = &nhi->encap_info.vxlan_encap; - nest = addattr_nest(&req->n, in_buf_len, RTA_ENCAP); - addattr32(&req->n, in_buf_len, VXLAN_VNI, vxlan->vni); - addattr_nest_end(&req->n, nest); + nest = nl_attr_nest(&req->n, in_buf_len, RTA_ENCAP); + nl_attr_put32(&req->n, in_buf_len, VXLAN_VNI, + vxlan->vni); + nl_attr_nest_end(&req->n, nest); break; } @@ -451,28 +454,15 @@ static int netlink_route_info_encode(struct netlink_route_info *ri, /* * Multipath case. */ - char buf[NL_PKT_BUF_SIZE]; - struct rtattr *rta = (void *)buf; - struct rtnexthop *rtnh; - - rta->rta_type = RTA_MULTIPATH; - rta->rta_len = RTA_LENGTH(0); - rtnh = RTA_DATA(rta); + nest = nl_attr_nest(&req->n, in_buf_len, RTA_MULTIPATH); for (nexthop_num = 0; nexthop_num < ri->num_nhs; nexthop_num++) { + rtnh = nl_attr_rtnh(&req->n, in_buf_len); nhi = &ri->nhs[nexthop_num]; - rtnh->rtnh_len = sizeof(*rtnh); - rtnh->rtnh_flags = 0; - rtnh->rtnh_hops = 0; - rtnh->rtnh_ifindex = 0; - rta->rta_len += rtnh->rtnh_len; - - if (nhi->gateway) { - rta_addattr_l(rta, sizeof(buf), RTA_GATEWAY, - nhi->gateway, bytelen); - rtnh->rtnh_len += sizeof(struct rtattr) + bytelen; - } + if (nhi->gateway) + nl_attr_put(&req->n, in_buf_len, RTA_GATEWAY, + nhi->gateway, bytelen); if (nhi->if_index) { rtnh->rtnh_ifindex = nhi->if_index; @@ -484,31 +474,28 @@ static int netlink_route_info_encode(struct netlink_route_info *ri, case FPM_NH_ENCAP_MAX: break; case FPM_NH_ENCAP_VXLAN: - rta_addattr_l(rta, sizeof(buf), RTA_ENCAP_TYPE, - &encap, sizeof(uint16_t)); - rtnh->rtnh_len += sizeof(struct rtattr) + - sizeof(uint16_t); + nl_attr_put16(&req->n, in_buf_len, RTA_ENCAP_TYPE, + encap); vxlan = &nhi->encap_info.vxlan_encap; - nest = rta_nest(rta, sizeof(buf), RTA_ENCAP); - rta_addattr_l(rta, sizeof(buf), VXLAN_VNI, &vxlan->vni, - sizeof(uint32_t)); - nest_len = rta_nest_end(rta, nest); - rtnh->rtnh_len += nest_len; + inner_nest = + nl_attr_nest(&req->n, in_buf_len, RTA_ENCAP); + nl_attr_put32(&req->n, in_buf_len, VXLAN_VNI, + vxlan->vni); + nl_attr_nest_end(&req->n, inner_nest); break; } - rtnh = RTNH_NEXT(rtnh); + nl_attr_rtnh_end(&req->n, rtnh); } - assert(rta->rta_len > RTA_LENGTH(0)); - addattr_l(&req->n, in_buf_len, RTA_MULTIPATH, RTA_DATA(rta), - RTA_PAYLOAD(rta)); + nl_attr_nest_end(&req->n, nest); + assert(nest->rta_len > RTA_LENGTH(0)); done: if (ri->pref_src) { - addattr_l(&req->n, in_buf_len, RTA_PREFSRC, &ri->pref_src, - bytelen); + nl_attr_put(&req->n, in_buf_len, RTA_PREFSRC, &ri->pref_src, + bytelen); } assert(req->n.nlmsg_len < in_buf_len); @@ -614,10 +601,10 @@ int zfpm_netlink_encode_mac(struct fpm_mac_info_t *mac, char *in_buf, req->ndm.ndm_flags |= NTF_EXT_LEARNED; /* Add attributes */ - addattr_l(&req->hdr, in_buf_len, NDA_LLADDR, &mac->macaddr, 6); - addattr_l(&req->hdr, in_buf_len, NDA_DST, &mac->r_vtep_ip, 4); - addattr32(&req->hdr, in_buf_len, NDA_MASTER, mac->svi_if); - addattr32(&req->hdr, in_buf_len, NDA_VNI, mac->vni); + nl_attr_put(&req->hdr, in_buf_len, NDA_LLADDR, &mac->macaddr, 6); + nl_attr_put(&req->hdr, in_buf_len, NDA_DST, &mac->r_vtep_ip, 4); + nl_attr_put32(&req->hdr, in_buf_len, NDA_MASTER, mac->svi_if); + nl_attr_put32(&req->hdr, in_buf_len, NDA_VNI, mac->vni); assert(req->hdr.nlmsg_len < in_buf_len); diff --git a/zebra/zebra_mlag.c b/zebra/zebra_mlag.c index 8ba7998f50..3cf4ba8d39 100644 --- a/zebra/zebra_mlag.c +++ b/zebra/zebra_mlag.c @@ -33,6 +33,10 @@ #include "zebra/zapi_msg.h" #include "zebra/debug.h" +#ifdef HAVE_PROTOBUF_VERSION_3 +#include "mlag/mlag.pb-c.h" +#endif + DEFINE_HOOK(zebra_mlag_private_write_data, (uint8_t *data, uint32_t len), (data, len)) DEFINE_HOOK(zebra_mlag_private_monitor_state, (), ()) diff --git a/zebra/zebra_mlag.h b/zebra/zebra_mlag.h index 66f5c4c67e..d10a1f9157 100644 --- a/zebra/zebra_mlag.h +++ b/zebra/zebra_mlag.h @@ -26,10 +26,6 @@ #include "zclient.h" #include "zebra/zserv.h" -#ifdef HAVE_PROTOBUF_VERSION_3 -#include "mlag/mlag.pb-c.h" -#endif - #ifdef __cplusplus extern "C" { #endif diff --git a/zebra/zebra_mpls_netlink.c b/zebra/zebra_mpls_netlink.c index a9233530dc..c95a021639 100644 --- a/zebra/zebra_mpls_netlink.c +++ b/zebra/zebra_mpls_netlink.c @@ -26,13 +26,16 @@ #include "zebra/rt.h" #include "zebra/rt_netlink.h" #include "zebra/zebra_mpls.h" +#include "zebra/kernel_netlink.h" /* * LSP forwarding update using dataplane context information. */ enum zebra_dplane_result kernel_lsp_update(struct zebra_dplane_ctx *ctx) { - int cmd, ret = -1; + uint8_t nl_pkt[NL_PKT_BUF_SIZE]; + ssize_t ret = -1; + int cmd; /* Call to netlink layer based on type of update */ if (dplane_ctx_get_op(ctx) == DPLANE_OP_LSP_DELETE) { @@ -53,7 +56,13 @@ enum zebra_dplane_result kernel_lsp_update(struct zebra_dplane_ctx *ctx) /* Invalid op? */ goto done; - ret = netlink_mpls_multipath(cmd, ctx); + ret = netlink_mpls_multipath_msg_encode(cmd, ctx, nl_pkt, + sizeof(nl_pkt)); + if (ret <= 0) + return ZEBRA_DPLANE_REQUEST_FAILURE; + + ret = netlink_talk_info(netlink_talk_filter, (struct nlmsghdr *)nl_pkt, + dplane_ctx_get_ns(ctx), 0); done: diff --git a/zebra/zebra_netns_id.c b/zebra/zebra_netns_id.c index 0d86421b9e..79121bb086 100644 --- a/zebra/zebra_netns_id.c +++ b/zebra/zebra_netns_id.c @@ -216,8 +216,8 @@ ns_id_t zebra_ns_id_get(const char *netnspath, int fd_param) nlh->nlmsg_len += NETLINK_ALIGN(sizeof(struct rtgenmsg)); rt->rtgen_family = AF_UNSPEC; - addattr32(nlh, NETLINK_SOCKET_BUFFER_SIZE, NETNSA_FD, fd); - addattr32(nlh, NETLINK_SOCKET_BUFFER_SIZE, NETNSA_NSID, ns_id); + nl_attr_put32(nlh, NETLINK_SOCKET_BUFFER_SIZE, NETNSA_FD, fd); + nl_attr_put32(nlh, NETLINK_SOCKET_BUFFER_SIZE, NETNSA_NSID, ns_id); ret = send_receive(sock, nlh, seq, buf); if (ret < 0) { @@ -282,8 +282,9 @@ ns_id_t zebra_ns_id_get(const char *netnspath, int fd_param) nlh->nlmsg_len += NETLINK_ALIGN(sizeof(struct rtgenmsg)); rt->rtgen_family = AF_UNSPEC; - addattr32(nlh, NETLINK_SOCKET_BUFFER_SIZE, NETNSA_FD, fd); - addattr32(nlh, NETLINK_SOCKET_BUFFER_SIZE, NETNSA_NSID, ns_id); + nl_attr_put32(nlh, NETLINK_SOCKET_BUFFER_SIZE, NETNSA_FD, fd); + nl_attr_put32(nlh, NETLINK_SOCKET_BUFFER_SIZE, NETNSA_NSID, + ns_id); ret = send_receive(sock, nlh, seq, buf); if (ret < 0) { |
