diff options
52 files changed, 1069 insertions, 344 deletions
diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index ff5cfe05fb..37639f4bce 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -616,7 +616,8 @@ void bgp_path_info_mpath_update(struct bgp_dest *dest, all_paths_lb = false; if (debug) { bgp_path_info_path_with_addpath_rx_str( - cur_mpath, path_buf); + cur_mpath, path_buf, + sizeof(path_buf)); zlog_debug( "%pRN: %s is still multipath, cur count %d", bgp_dest_to_rnode(dest), @@ -626,7 +627,8 @@ void bgp_path_info_mpath_update(struct bgp_dest *dest, mpath_changed = 1; if (debug) { bgp_path_info_path_with_addpath_rx_str( - cur_mpath, path_buf); + cur_mpath, path_buf, + sizeof(path_buf)); zlog_debug( "%pRN: remove mpath %s nexthop %s, cur count %d", bgp_dest_to_rnode(dest), @@ -660,7 +662,7 @@ void bgp_path_info_mpath_update(struct bgp_dest *dest, mpath_changed = 1; if (debug) { bgp_path_info_path_with_addpath_rx_str( - cur_mpath, path_buf); + cur_mpath, path_buf, sizeof(path_buf)); zlog_debug( "%pRN: remove mpath %s nexthop %s, cur count %d", bgp_dest_to_rnode(dest), path_buf, @@ -710,7 +712,8 @@ void bgp_path_info_mpath_update(struct bgp_dest *dest, all_paths_lb = false; if (debug) { bgp_path_info_path_with_addpath_rx_str( - new_mpath, path_buf); + new_mpath, path_buf, + sizeof(path_buf)); zlog_debug( "%pRN: add mpath %s nexthop %s, cur count %d", bgp_dest_to_rnode(dest), diff --git a/bgpd/bgp_nb_config.c b/bgpd/bgp_nb_config.c index a3f58db88f..721ce5b5c6 100644 --- a/bgpd/bgp_nb_config.c +++ b/bgpd/bgp_nb_config.c @@ -69,7 +69,7 @@ int bgp_router_create(struct nb_cb_create_args *args) { const struct lyd_node *vrf_dnode; struct bgp *bgp; - struct vrf *vrf; + const char *vrf_name; const char *name = NULL; as_t as; enum bgp_instance_type inst_type; @@ -87,12 +87,12 @@ int bgp_router_create(struct nb_cb_create_args *args) case NB_EV_APPLY: vrf_dnode = yang_dnode_get_parent(args->dnode, "control-plane-protocol"); - vrf = nb_running_get_entry(vrf_dnode, NULL, true); + vrf_name = yang_dnode_get_string(vrf_dnode, "./vrf"); - if (strmatch(vrf->name, VRF_DEFAULT_NAME)) { + if (strmatch(vrf_name, VRF_DEFAULT_NAME)) { name = NULL; } else { - name = vrf->name; + name = vrf_name; inst_type = BGP_INSTANCE_TYPE_VRF; } diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 0f135985ed..18a0b3fb7d 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -525,13 +525,14 @@ static uint32_t bgp_med_value(struct attr *attr, struct bgp *bgp) } } -void bgp_path_info_path_with_addpath_rx_str(struct bgp_path_info *pi, char *buf) +void bgp_path_info_path_with_addpath_rx_str(struct bgp_path_info *pi, char *buf, + size_t buf_len) { if (pi->addpath_rx_id) - sprintf(buf, "path %s (addpath rxid %d)", pi->peer->host, - pi->addpath_rx_id); + snprintf(buf, buf_len, "path %s (addpath rxid %d)", + pi->peer->host, pi->addpath_rx_id); else - sprintf(buf, "path %s", pi->peer->host); + snprintf(buf, buf_len, "path %s", pi->peer->host); } /* Compare two bgp route entity. If 'new' is preferable over 'exist' return 1. @@ -582,7 +583,8 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, } if (debug) - bgp_path_info_path_with_addpath_rx_str(new, new_buf); + bgp_path_info_path_with_addpath_rx_str(new, new_buf, + sizeof(new_buf)); if (exist == NULL) { *reason = bgp_path_selection_first; @@ -593,7 +595,8 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, } if (debug) { - bgp_path_info_path_with_addpath_rx_str(exist, exist_buf); + bgp_path_info_path_with_addpath_rx_str(exist, exist_buf, + sizeof(exist_buf)); zlog_debug("%s: Comparing %s flags 0x%x with %s flags 0x%x", pfx_buf, new_buf, new->flags, exist_buf, exist->flags); @@ -621,10 +624,10 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, prefix2str( bgp_dest_get_prefix(new->net), pfx_buf, sizeof(*pfx_buf) * PREFIX2STR_BUFFER); - bgp_path_info_path_with_addpath_rx_str(new, - new_buf); bgp_path_info_path_with_addpath_rx_str( - exist, exist_buf); + new, new_buf, sizeof(new_buf)); + bgp_path_info_path_with_addpath_rx_str( + exist, exist_buf, sizeof(exist_buf)); } if (newattr->sticky && !existattr->sticky) { @@ -2348,7 +2351,7 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, if (debug) { bgp_path_info_path_with_addpath_rx_str( - new_select, path_buf); + new_select, path_buf, sizeof(path_buf)); zlog_debug( "%pBD: %s is the bestpath from AS %u", dest, path_buf, @@ -2422,8 +2425,8 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, */ if (debug) { if (new_select) - bgp_path_info_path_with_addpath_rx_str(new_select, - path_buf); + bgp_path_info_path_with_addpath_rx_str( + new_select, path_buf, sizeof(path_buf)); else snprintf(path_buf, sizeof(path_buf), "NONE"); zlog_debug( @@ -2438,7 +2441,7 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, if (debug) bgp_path_info_path_with_addpath_rx_str( - pi, path_buf); + pi, path_buf, sizeof(path_buf)); if (pi == new_select) { if (debug) @@ -6389,7 +6392,8 @@ DEFPY_YANG (bgp_network, bgp_network_cmd, int ret; ret = netmask_str2prefix_str(address_str, netmask_str, - addr_prefix_str); + addr_prefix_str, + sizeof(addr_prefix_str)); if (!ret) { vty_out(vty, "%% Inconsistent address and mask\n"); return CMD_WARNING_CONFIG_FAILED; @@ -7780,7 +7784,8 @@ DEFPY_YANG( char prefix_buf[PREFIX2STR_BUFFER]; if (addr_str) { - if (netmask_str2prefix_str(addr_str, mask_str, prefix_buf) + if (netmask_str2prefix_str(addr_str, mask_str, prefix_buf, + sizeof(prefix_buf)) == 0) { vty_out(vty, "%% Inconsistent address and mask\n"); return CMD_WARNING_CONFIG_FAILED; @@ -14398,7 +14403,7 @@ DEFUN (clear_ip_bgp_dampening_address_mask, char prefix_str[BUFSIZ]; ret = netmask_str2prefix_str(argv[idx_ipv4]->arg, argv[idx_ipv4_2]->arg, - prefix_str); + prefix_str, sizeof(prefix_str)); if (!ret) { vty_out(vty, "%% Inconsistent address and mask\n"); return CMD_WARNING; diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 1060d2e60d..766e5ade92 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -598,7 +598,7 @@ extern void bgp_path_info_set_flag(struct bgp_dest *dest, extern void bgp_path_info_unset_flag(struct bgp_dest *dest, struct bgp_path_info *path, uint32_t flag); extern void bgp_path_info_path_with_addpath_rx_str(struct bgp_path_info *pi, - char *buf); + char *buf, size_t buf_len); extern int bgp_nlri_parse_ip(struct peer *, struct attr *, struct bgp_nlri *); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 3dc2cfbd5c..b7f3289ffc 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -4315,13 +4315,15 @@ DEFUN (match_community, int idx_comm_list = 2; int ret; char *argstr; + size_t argstr_len; if (argc == 4) { - argstr = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, - strlen(argv[idx_comm_list]->arg) - + strlen("exact-match") + 2); + argstr_len = strlen(argv[idx_comm_list]->arg) + + strlen("exact-match") + 2; + argstr = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, argstr_len); - sprintf(argstr, "%s exact-match", argv[idx_comm_list]->arg); + snprintf(argstr, argstr_len, "%s exact-match", + argv[idx_comm_list]->arg); } else argstr = argv[idx_comm_list]->arg; @@ -4362,13 +4364,15 @@ DEFUN (match_lcommunity, int idx_lcomm_list = 2; int ret; char *argstr; + size_t argstr_len; if (argc == 4) { - argstr = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, - strlen(argv[idx_lcomm_list]->arg) - + strlen("exact-match") + 2); + argstr_len = strlen(argv[idx_lcomm_list]->arg) + + strlen("exact-match") + 2; + argstr = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, argstr_len); - sprintf(argstr, "%s exact-match", argv[idx_lcomm_list]->arg); + snprintf(argstr, argstr_len, "%s exact-match", + argv[idx_lcomm_list]->arg); } else argstr = argv[idx_lcomm_list]->arg; @@ -5252,6 +5256,7 @@ DEFUN (set_aggregator_as, int ret; struct in_addr address; char *argstr; + size_t argstr_len; ret = inet_aton(argv[idx_ipv4]->arg, &address); if (ret == 0) { @@ -5259,11 +5264,12 @@ DEFUN (set_aggregator_as, return CMD_WARNING_CONFIG_FAILED; } - argstr = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, - strlen(argv[idx_number]->arg) - + strlen(argv[idx_ipv4]->arg) + 2); + argstr_len = + strlen(argv[idx_number]->arg) + strlen(argv[idx_ipv4]->arg) + 2; + argstr = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, argstr_len); - sprintf(argstr, "%s %s", argv[idx_number]->arg, argv[idx_ipv4]->arg); + snprintf(argstr, argstr_len, "%s %s", argv[idx_number]->arg, + argv[idx_ipv4]->arg); ret = generic_set_add(vty, VTY_GET_CONTEXT(route_map_index), "aggregator as", argstr); @@ -5289,6 +5295,7 @@ DEFUN (no_set_aggregator_as, int ret; struct in_addr address; char *argstr; + size_t argstr_len; if (argc <= idx_asn) return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), @@ -5300,11 +5307,11 @@ DEFUN (no_set_aggregator_as, return CMD_WARNING_CONFIG_FAILED; } - argstr = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, - strlen(argv[idx_asn]->arg) + strlen(argv[idx_ip]->arg) - + 2); + argstr_len = strlen(argv[idx_asn]->arg) + strlen(argv[idx_ip]->arg) + 2; + argstr = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, argstr_len); - sprintf(argstr, "%s %s", argv[idx_asn]->arg, argv[idx_ip]->arg); + snprintf(argstr, argstr_len, "%s %s", argv[idx_asn]->arg, + argv[idx_ip]->arg); ret = generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index), "aggregator as", argstr); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index ab9e8af96d..9e8065691e 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -1483,8 +1483,26 @@ DEFUN_YANG(no_router_bgp, struct bgp *tmp_bgp; for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, tmp_bgp)) { - if (tmp_bgp->inst_type - == BGP_INSTANCE_TYPE_VRF) { + if (tmp_bgp->inst_type != BGP_INSTANCE_TYPE_VRF) + continue; + if (CHECK_FLAG(tmp_bgp->af_flags[AFI_IP][SAFI_UNICAST], + BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT) || + CHECK_FLAG(tmp_bgp->af_flags[AFI_IP6][SAFI_UNICAST], + BGP_CONFIG_MPLSVPN_TO_VRF_IMPORT) || + CHECK_FLAG(tmp_bgp->af_flags[AFI_IP][SAFI_UNICAST], + BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT) || + CHECK_FLAG(tmp_bgp->af_flags[AFI_IP6][SAFI_UNICAST], + BGP_CONFIG_VRF_TO_MPLSVPN_EXPORT) || + CHECK_FLAG(tmp_bgp->af_flags[AFI_IP][SAFI_UNICAST], + BGP_CONFIG_VRF_TO_VRF_EXPORT) || + CHECK_FLAG(tmp_bgp->af_flags[AFI_IP6][SAFI_UNICAST], + BGP_CONFIG_VRF_TO_VRF_EXPORT) || + (bgp == bgp_get_evpn() && + (CHECK_FLAG(tmp_bgp->af_flags[AFI_L2VPN][SAFI_EVPN], + BGP_L2VPN_EVPN_ADVERTISE_IPV4_UNICAST) || + CHECK_FLAG(tmp_bgp->af_flags[AFI_L2VPN][SAFI_EVPN], + BGP_L2VPN_EVPN_ADVERTISE_IPV6_UNICAST))) || + (tmp_bgp->vnihash && hashcount(tmp_bgp->vnihash))) { vty_out(vty, "%% Cannot delete default BGP instance. Dependent VRF instances exist\n"); return CMD_WARNING_CONFIG_FAILED; diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index b11fd5288a..07ca247ee6 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -5246,8 +5246,8 @@ int peer_timers_set(struct peer *peer, uint32_t keepalive, uint32_t holdtime) /* Set flag and configuration on peer-group member. */ SET_FLAG(member->flags, PEER_FLAG_TIMER); - PEER_ATTR_INHERIT(peer, peer->group, holdtime); - PEER_ATTR_INHERIT(peer, peer->group, keepalive); + PEER_ATTR_INHERIT(member, peer->group, holdtime); + PEER_ATTR_INHERIT(member, peer->group, keepalive); } return 0; diff --git a/doc/developer/tracing.rst b/doc/developer/tracing.rst index c194ae1270..71f7b4ac49 100644 --- a/doc/developer/tracing.rst +++ b/doc/developer/tracing.rst @@ -173,6 +173,78 @@ Example:: When using LTTng, you can also get zlogs as trace events by enabling the ``lttng_ust_tracelog:*`` event class. +To see available SystemTap USDT probes, run:: + + stap -L 'process("/usr/lib/frr/bgpd").mark("*")' + +Example:: + + root@host ~> stap -L 'process("/usr/lib/frr/bgpd").mark("*")' + process("/usr/lib/frr/bgpd").mark("capability_process") $arg1:long $arg2:long + process("/usr/lib/frr/bgpd").mark("input_filter") $arg1:long $arg2:long $arg3:long $arg4:long $arg5:long + process("/usr/lib/frr/bgpd").mark("keepalive_process") $arg1:long $arg2:long + process("/usr/lib/frr/bgpd").mark("notification_process") $arg1:long $arg2:long + process("/usr/lib/frr/bgpd").mark("open_process") $arg1:long $arg2:long + process("/usr/lib/frr/bgpd").mark("output_filter") $arg1:long $arg2:long $arg3:long $arg4:long $arg5:long + process("/usr/lib/frr/bgpd").mark("packet_read") $arg1:long $arg2:long + process("/usr/lib/frr/bgpd").mark("process_update") $arg1:long $arg2:long $arg3:long $arg4:long $arg5:long $arg6:long + process("/usr/lib/frr/bgpd").mark("refresh_process") $arg1:long $arg2:long + process("/usr/lib/frr/bgpd").mark("update_process") $arg1:long $arg2:long + +When using SystemTap, you can also easily attach to an existing function:: + + stap -L 'process("/usr/lib/frr/bgpd").function("bgp_update_receive")' + +Example:: + + root@host ~> stap -L 'process("/usr/lib/frr/bgpd").function("bgp_update_receive")' + process("/usr/lib/frr/bgpd").function("bgp_update_receive@bgpd/bgp_packet.c:1531") $peer:struct peer* $size:bgp_size_t $attr:struct attr $restart:_Bool $nlris:struct bgp_nlri[] $__func__:char const[] const + +Complete ``bgp.stp`` example using SystemTap to show BGP peer, prefix and aspath +using ``process_update`` USDT:: + + global pkt_size; + probe begin + { + ansi_clear_screen(); + println("Starting..."); + } + probe process("/usr/lib/frr/bgpd").function("bgp_update_receive") + { + pkt_size <<< $size; + } + probe process("/usr/lib/frr/bgpd").mark("process_update") + { + aspath = @cast($arg6, "attr")->aspath; + printf("> %s via %s (%s)\n", + user_string($arg2), + user_string(@cast($arg1, "peer")->host), + user_string(@cast(aspath, "aspath")->str)); + } + probe end + { + if (@count(pkt_size)) + print(@hist_linear(pkt_size, 0, 20, 2)); + } + +Output:: + + Starting... + > 192.168.0.0/24 via 192.168.0.1 (65534) + > 192.168.100.1/32 via 192.168.0.1 (65534) + > 172.16.16.1/32 via 192.168.0.1 (65534 65030) + ^Cvalue |-------------------------------------------------- count + 0 | 0 + 2 | 0 + 4 |@ 1 + 6 | 0 + 8 | 0 + ~ + 18 | 0 + 20 | 0 + >20 |@@@@@ 5 + + Concepts -------- diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index 41f56e3a03..abdbea5a9c 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -563,7 +563,7 @@ In general, code submitted into FRR will be rejected if it uses unsafe programming practices. While there is no enforced overall ruleset, the following requirements have achieved consensus: -- ``strcpy``, ``strcat`` and ``sprintf`` are inacceptable without exception. +- ``strcpy``, ``strcat`` and ``sprintf`` are unacceptable without exception. Use ``strlcpy``, ``strlcat`` and ``snprintf`` instead. (Rationale: even if you know the operation cannot overflow the buffer, a future code change may inadvertedly introduce an overflow.) diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index 6d2303817b..a17d9a6ae2 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -691,8 +691,8 @@ static void lsp_set_time(struct isis_lsp *lsp) stream_putw_at(lsp->pdu, 10, lsp->hdr.rem_lifetime); } -void lspid_print(uint8_t *lsp_id, char *dest, char dynhost, char frag, - struct isis *isis) +void lspid_print(uint8_t *lsp_id, char *dest, size_t dest_len, char dynhost, + char frag, struct isis *isis) { struct isis_dynhn *dyn = NULL; char id[SYSID_STRLEN]; @@ -710,10 +710,10 @@ void lspid_print(uint8_t *lsp_id, char *dest, char dynhost, char frag, memcpy(id, sysid_print(lsp_id), 15); if (frag) - sprintf(dest, "%s.%02x-%02x", id, LSP_PSEUDO_ID(lsp_id), - LSP_FRAGMENT(lsp_id)); + snprintf(dest, dest_len, "%s.%02x-%02x", id, + LSP_PSEUDO_ID(lsp_id), LSP_FRAGMENT(lsp_id)); else - sprintf(dest, "%s.%02x", id, LSP_PSEUDO_ID(lsp_id)); + snprintf(dest, dest_len, "%s.%02x", id, LSP_PSEUDO_ID(lsp_id)); } /* Convert the lsp attribute bits to attribute string */ @@ -747,7 +747,7 @@ void lsp_print(struct isis_lsp *lsp, struct vty *vty, char dynhost, char age_out[8]; char b[200]; - lspid_print(lsp->hdr.lsp_id, LSPid, dynhost, 1, isis); + lspid_print(lsp->hdr.lsp_id, LSPid, sizeof(LSPid), dynhost, 1, isis); vty_out(vty, "%-21s%c ", LSPid, lsp->own_lsp ? '*' : ' '); vty_out(vty, "%5hu ", lsp->hdr.pdu_len); vty_out(vty, "0x%08x ", lsp->hdr.seqno); diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h index 0783036e49..896d957607 100644 --- a/isisd/isis_lsp.h +++ b/isisd/isis_lsp.h @@ -116,8 +116,8 @@ void lsp_update(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr, struct isis_tlvs *tlvs, struct stream *stream, struct isis_area *area, int level, bool confusion); void lsp_inc_seqno(struct isis_lsp *lsp, uint32_t seqno); -void lspid_print(uint8_t *lsp_id, char *dest, char dynhost, char frag, - struct isis *isis); +void lspid_print(uint8_t *lsp_id, char *dest, size_t dest_len, char dynhost, + char frag, struct isis *isis); void lsp_print(struct isis_lsp *lsp, struct vty *vty, char dynhost, struct isis *isis); void lsp_print_detail(struct isis_lsp *lsp, struct vty *vty, char dynhost, diff --git a/isisd/isis_misc.c b/isisd/isis_misc.c index 6e9cbaf98e..d3d081d376 100644 --- a/isisd/isis_misc.c +++ b/isisd/isis_misc.c @@ -59,27 +59,30 @@ char nlpidstring[30]; const char *isonet_print(const uint8_t *from, int len) { int i = 0; - char *pos = isonet; + char tbuf[4]; + isonet[0] = '\0'; if (!from) return "unknown"; while (i < len) { if (i & 1) { - sprintf(pos, "%02x", *(from + i)); - pos += 2; + snprintf(tbuf, sizeof(tbuf), "%02x", *(from + i)); + strlcat(isonet, tbuf, sizeof(isonet)); } else { if (i == (len - 1)) { /* No dot at the end of address */ - sprintf(pos, "%02x", *(from + i)); - pos += 2; + snprintf(tbuf, sizeof(tbuf), "%02x", + *(from + i)); + strlcat(isonet, tbuf, sizeof(isonet)); } else { - sprintf(pos, "%02x.", *(from + i)); - pos += 3; + snprintf(tbuf, sizeof(tbuf), "%02x.", + *(from + i)); + strlcat(isonet, tbuf, sizeof(isonet)); } } i++; } - *(pos) = '\0'; + return isonet; } @@ -202,17 +205,18 @@ const char *nlpid2str(uint8_t nlpid) char *nlpid2string(struct nlpids *nlpids) { - char *pos = nlpidstring; int i; + char tbuf[256]; + nlpidstring[0] = '\0'; for (i = 0; i < nlpids->count; i++) { - pos += sprintf(pos, "%s", nlpid2str(nlpids->nlpids[i])); + snprintf(tbuf, sizeof(tbuf), "%s", + nlpid2str(nlpids->nlpids[i])); + strlcat(nlpidstring, tbuf, sizeof(nlpidstring)); if (nlpids->count - i > 1) - pos += sprintf(pos, ", "); + strlcat(nlpidstring, ", ", sizeof(nlpidstring)); } - *(pos) = '\0'; - return nlpidstring; } @@ -359,34 +363,47 @@ const char *isis_format_id(const uint8_t *id, size_t len) const char *time2string(uint32_t time) { - char *pos = datestring; uint32_t rest; + char tbuf[32]; + datestring[0] = '\0'; if (time == 0) return "-"; - if (time / SECS_PER_YEAR) - pos += sprintf(pos, "%uY", time / SECS_PER_YEAR); + if (time / SECS_PER_YEAR) { + snprintf(tbuf, sizeof(tbuf), "%uY", time / SECS_PER_YEAR); + strlcat(datestring, tbuf, sizeof(datestring)); + } rest = time % SECS_PER_YEAR; - if (rest / SECS_PER_MONTH) - pos += sprintf(pos, "%uM", rest / SECS_PER_MONTH); + if (rest / SECS_PER_MONTH) { + snprintf(tbuf, sizeof(tbuf), "%uM", rest / SECS_PER_MONTH); + strlcat(datestring, tbuf, sizeof(datestring)); + } rest = rest % SECS_PER_MONTH; - if (rest / SECS_PER_WEEK) - pos += sprintf(pos, "%uw", rest / SECS_PER_WEEK); + if (rest / SECS_PER_WEEK) { + snprintf(tbuf, sizeof(tbuf), "%uw", rest / SECS_PER_WEEK); + strlcat(datestring, tbuf, sizeof(datestring)); + } rest = rest % SECS_PER_WEEK; - if (rest / SECS_PER_DAY) - pos += sprintf(pos, "%ud", rest / SECS_PER_DAY); + if (rest / SECS_PER_DAY) { + snprintf(tbuf, sizeof(tbuf), "%ud", rest / SECS_PER_DAY); + strlcat(datestring, tbuf, sizeof(datestring)); + } rest = rest % SECS_PER_DAY; - if (rest / SECS_PER_HOUR) - pos += sprintf(pos, "%uh", rest / SECS_PER_HOUR); + if (rest / SECS_PER_HOUR) { + snprintf(tbuf, sizeof(tbuf), "%uh", rest / SECS_PER_HOUR); + strlcat(datestring, tbuf, sizeof(datestring)); + } rest = rest % SECS_PER_HOUR; - if (rest / SECS_PER_MINUTE) - pos += sprintf(pos, "%um", rest / SECS_PER_MINUTE); + if (rest / SECS_PER_MINUTE) { + snprintf(tbuf, sizeof(tbuf), "%um", rest / SECS_PER_MINUTE); + strlcat(datestring, tbuf, sizeof(datestring)); + } rest = rest % SECS_PER_MINUTE; - if (rest) - pos += sprintf(pos, "%us", rest); - - *(pos) = 0; + if (rest) { + snprintf(tbuf, sizeof(tbuf), "%us", rest); + strlcat(datestring, tbuf, sizeof(datestring)); + } return datestring; } diff --git a/isisd/isis_vty_fabricd.c b/isisd/isis_vty_fabricd.c index d0a411a8db..6055984195 100644 --- a/isisd/isis_vty_fabricd.c +++ b/isisd/isis_vty_fabricd.c @@ -118,7 +118,7 @@ static void lsp_print_flooding(struct vty *vty, struct isis_lsp *lsp, char lspid[255]; char buf[MONOTIME_STRLEN]; - lspid_print(lsp->hdr.lsp_id, lspid, true, true, isis); + lspid_print(lsp->hdr.lsp_id, lspid, sizeof(lspid), true, true, isis); vty_out(vty, "Flooding information for %s\n", lspid); if (!lsp->flooding_neighbors[TX_LSP_NORMAL]) { diff --git a/lib/agentx.c b/lib/agentx.c index 5351f8bda2..c8d7d75a81 100644 --- a/lib/agentx.c +++ b/lib/agentx.c @@ -36,6 +36,8 @@ XREF_SETUP() +DEFINE_HOOK(agentx_enabled, (), ()) + static int agentx_enabled = 0; static struct thread_master *agentx_tm; @@ -226,6 +228,7 @@ DEFUN (agentx_enable, events = list_new(); agentx_events_update(); agentx_enabled = 1; + hook_call(agentx_enabled); } return CMD_SUCCESS; @@ -259,6 +262,16 @@ void smux_init(struct thread_master *tm) install_element(CONFIG_NODE, &no_agentx_cmd); } +void smux_agentx_enable(void) +{ + if (!agentx_enabled) { + init_snmp(FRR_SMUX_NAME); + events = list_new(); + agentx_events_update(); + agentx_enabled = 1; + } +} + void smux_register_mib(const char *descr, struct variable *var, size_t width, int num, oid name[], size_t namelen) { diff --git a/lib/northbound.c b/lib/northbound.c index ecfa2c9d11..224951b22b 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -185,6 +185,25 @@ struct nb_node *nb_node_find(const char *xpath) return snode->priv; } +void nb_node_set_dependency_cbs(const char *dependency_xpath, + const char *dependant_xpath, + struct nb_dependency_callbacks *cbs) +{ + struct nb_node *dependency = nb_node_find(dependency_xpath); + struct nb_node *dependant = nb_node_find(dependant_xpath); + + if (!dependency || !dependant) + return; + + dependency->dep_cbs.get_dependant_xpath = cbs->get_dependant_xpath; + dependant->dep_cbs.get_dependency_xpath = cbs->get_dependency_xpath; +} + +bool nb_node_has_dependency(struct nb_node *node) +{ + return node->dep_cbs.get_dependency_xpath != NULL; +} + static int nb_node_validate_cb(const struct nb_node *nb_node, enum nb_operation operation, int callback_implemented, bool optional) @@ -532,8 +551,9 @@ int nb_candidate_edit(struct nb_config *candidate, const struct yang_data *previous, const struct yang_data *data) { - struct lyd_node *dnode; + struct lyd_node *dnode, *dep_dnode; char xpath_edit[XPATH_MAXLEN]; + char dep_xpath[XPATH_MAXLEN]; /* Use special notation for leaf-lists (RFC 6020, section 9.13.5). */ if (nb_node->snode->nodetype == LYS_LEAFLIST) @@ -549,9 +569,33 @@ int nb_candidate_edit(struct nb_config *candidate, dnode = lyd_new_path(candidate->dnode, ly_native_ctx, xpath_edit, (void *)data->value, 0, LYD_PATH_OPT_UPDATE); - if (!dnode && ly_errno) { - flog_warn(EC_LIB_LIBYANG, "%s: lyd_new_path() failed", - __func__); + if (dnode) { + /* + * create dependency + * + * dnode returned by the lyd_new_path may be from a + * different schema, so we need to update the nb_node + */ + nb_node = dnode->schema->priv; + if (nb_node->dep_cbs.get_dependency_xpath) { + nb_node->dep_cbs.get_dependency_xpath( + dnode, dep_xpath); + + ly_errno = 0; + dep_dnode = lyd_new_path(candidate->dnode, + ly_native_ctx, + dep_xpath, NULL, 0, + LYD_PATH_OPT_UPDATE); + if (!dep_dnode && ly_errno) { + flog_warn(EC_LIB_LIBYANG, + "%s: lyd_new_path(%s) failed", + __func__, dep_xpath); + return NB_ERR; + } + } + } else if (ly_errno) { + flog_warn(EC_LIB_LIBYANG, "%s: lyd_new_path(%s) failed", + __func__, xpath_edit); return NB_ERR; } break; @@ -563,6 +607,14 @@ int nb_candidate_edit(struct nb_config *candidate, * whether to ignore it or not. */ return NB_ERR_NOT_FOUND; + /* destroy dependant */ + if (nb_node->dep_cbs.get_dependant_xpath) { + nb_node->dep_cbs.get_dependant_xpath(dnode, dep_xpath); + + dep_dnode = yang_dnode_get(candidate->dnode, dep_xpath); + if (dep_dnode) + lyd_free(dep_dnode); + } lyd_free(dnode); break; case NB_OP_MOVE: diff --git a/lib/northbound.h b/lib/northbound.h index 8dd6b4c337..3e1342f985 100644 --- a/lib/northbound.h +++ b/lib/northbound.h @@ -509,6 +509,11 @@ struct nb_callbacks { void (*cli_show_end)(struct vty *vty, struct lyd_node *dnode); }; +struct nb_dependency_callbacks { + void (*get_dependant_xpath)(const struct lyd_node *dnode, char *xpath); + void (*get_dependency_xpath)(const struct lyd_node *dnode, char *xpath); +}; + /* * Northbound-specific data that is allocated for each schema node of the native * YANG modules. @@ -523,6 +528,8 @@ struct nb_node { /* Priority - lower priorities are processed first. */ uint32_t priority; + struct nb_dependency_callbacks dep_cbs; + /* Callbacks implemented for this node. */ struct nb_callbacks cbs; @@ -722,6 +729,12 @@ void nb_nodes_delete(void); */ extern struct nb_node *nb_node_find(const char *xpath); +extern void nb_node_set_dependency_cbs(const char *dependency_xpath, + const char *dependant_xpath, + struct nb_dependency_callbacks *cbs); + +bool nb_node_has_dependency(struct nb_node *node); + /* * Create a new northbound configuration. * diff --git a/lib/prefix.c b/lib/prefix.c index 663a87afde..c98e0c1c72 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -1160,7 +1160,7 @@ in_addr_t ipv4_broadcast_addr(in_addr_t hostaddr, int masklen) ex.) "1.1.0.0" "255.255.0.0" => "1.1.0.0/16" ex.) "1.0.0.0" NULL => "1.0.0.0/8" */ int netmask_str2prefix_str(const char *net_str, const char *mask_str, - char *prefix_str) + char *prefix_str, size_t prefix_str_len) { struct in_addr network; struct in_addr mask; @@ -1193,7 +1193,7 @@ int netmask_str2prefix_str(const char *net_str, const char *mask_str, return 0; } - sprintf(prefix_str, "%s/%d", net_str, prefixlen); + snprintf(prefix_str, prefix_str_len, "%s/%d", net_str, prefixlen); return 1; } diff --git a/lib/prefix.h b/lib/prefix.h index b7fdc26369..b2f3b0592f 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -491,7 +491,7 @@ extern void masklen2ip(const int, struct in_addr *); * special treatment for /31 according to RFC3021 section 3.3 */ extern in_addr_t ipv4_broadcast_addr(in_addr_t hostaddr, int masklen); -extern int netmask_str2prefix_str(const char *, const char *, char *); +extern int netmask_str2prefix_str(const char *, const char *, char *, size_t); extern struct prefix_ipv6 *prefix_ipv6_new(void); extern void prefix_ipv6_free(struct prefix_ipv6 **p); diff --git a/lib/routing_nb.h b/lib/routing_nb.h index d1b59ea29e..ffba631a10 100644 --- a/lib/routing_nb.h +++ b/lib/routing_nb.h @@ -15,10 +15,17 @@ int routing_control_plane_protocols_control_plane_protocol_destroy( #define FRR_ROUTING_KEY_XPATH \ "/frr-routing:routing/control-plane-protocols/" \ "control-plane-protocol[type='%s'][name='%s'][vrf='%s']" + +#define FRR_ROUTING_KEY_XPATH_VRF \ + "/frr-routing:routing/control-plane-protocols/" \ + "control-plane-protocol[vrf='%s']" + /* * callbacks for routing to handle configuration events * based on the control plane protocol */ DECLARE_HOOK(routing_conf_event, (struct nb_cb_create_args *args), (args)) +void routing_control_plane_protocols_register_vrf_dependency(void); + #endif /* _FRR_ROUTING_NB_H_ */ diff --git a/lib/routing_nb_config.c b/lib/routing_nb_config.c index b789e8494e..17698d2b87 100644 --- a/lib/routing_nb_config.c +++ b/lib/routing_nb_config.c @@ -45,15 +45,21 @@ int routing_control_plane_protocols_control_plane_protocol_create( case NB_EV_ABORT: break; case NB_EV_APPLY: - vrfname = yang_dnode_get_string(args->dnode, "./vrf"); - vrf = vrf_lookup_by_name(vrfname); - vrf = vrf ? vrf : vrf_get(VRF_UNKNOWN, vrfname); - if (!vrf) { - flog_warn(EC_LIB_NB_CB_CONFIG_APPLY, - "vrf creation %s failed", vrfname); - return NB_ERR; + /* + * If the daemon relies on the VRF pointer stored in this + * dnode, then it should register the dependency between this + * module and the VRF module using + * routing_control_plane_protocols_register_vrf_dependency. + * If such dependency is not registered, then nothing is + * stored in the dnode. If the dependency is registered, + * find the vrf and store the pointer. + */ + if (nb_node_has_dependency(args->dnode->schema->priv)) { + vrfname = yang_dnode_get_string(args->dnode, "./vrf"); + vrf = vrf_lookup_by_name(vrfname); + assert(vrf); + nb_running_set_entry(args->dnode, vrf); } - nb_running_set_entry(args->dnode, vrf); break; }; @@ -63,12 +69,45 @@ int routing_control_plane_protocols_control_plane_protocol_create( int routing_control_plane_protocols_control_plane_protocol_destroy( struct nb_cb_destroy_args *args) { - struct vrf *vrf __attribute__((unused)); - if (args->event != NB_EV_APPLY) return NB_OK; - vrf = nb_running_unset_entry(args->dnode); + /* + * If dependency on VRF module is registered, then VRF + * pointer was stored and must be cleared. + */ + if (nb_node_has_dependency(args->dnode->schema->priv)) + nb_running_unset_entry(args->dnode); return NB_OK; } + +static void vrf_to_control_plane_protocol(const struct lyd_node *dnode, + char *xpath) +{ + const char *vrf; + + vrf = yang_dnode_get_string(dnode, "./name"); + + snprintf(xpath, XPATH_MAXLEN, FRR_ROUTING_KEY_XPATH_VRF, vrf); +} + +static void control_plane_protocol_to_vrf(const struct lyd_node *dnode, + char *xpath) +{ + const char *vrf; + + vrf = yang_dnode_get_string(dnode, "./vrf"); + + snprintf(xpath, XPATH_MAXLEN, FRR_VRF_KEY_XPATH, vrf); +} + +void routing_control_plane_protocols_register_vrf_dependency(void) +{ + struct nb_dependency_callbacks cbs; + + cbs.get_dependant_xpath = vrf_to_control_plane_protocol; + cbs.get_dependency_xpath = control_plane_protocol_to_vrf; + + nb_node_set_dependency_cbs(FRR_VRF_XPATH, FRR_ROUTING_XPATH, &cbs); +} diff --git a/lib/smux.h b/lib/smux.h index 11c1becd60..a263478a2e 100644 --- a/lib/smux.h +++ b/lib/smux.h @@ -25,6 +25,7 @@ #include <net-snmp/agent/snmp_vars.h> #include "thread.h" +#include "hook.h" #ifdef __cplusplus extern "C" { @@ -103,6 +104,7 @@ struct index_oid { #define SNMP_IP6ADDRESS(V) (*var_len = sizeof(struct in6_addr), (uint8_t *)&V) extern void smux_init(struct thread_master *tm); +extern void smux_agentx_enable(void); extern void smux_register_mib(const char *, struct variable *, size_t, int, oid[], size_t); extern int smux_header_generic(struct variable *, oid[], size_t *, int, @@ -151,6 +153,8 @@ extern void oid_copy_int(oid oid[], int *val); extern void oid2string(oid oid[], int len, char *string); extern void oid_copy_str(oid oid[], const char *string, int len); +DECLARE_HOOK(agentx_enabled, (), ()) + #ifdef __cplusplus } #endif @@ -686,8 +686,8 @@ int vrf_handler_create(struct vty *vty, const char *vrfname, } if (vty) { - snprintf(xpath_list, sizeof(xpath_list), - "/frr-vrf:lib/vrf[name='%s']", vrfname); + snprintf(xpath_list, sizeof(xpath_list), FRR_VRF_KEY_XPATH, + vrfname); nb_cli_enqueue_change(vty, xpath_list, NB_OP_CREATE, NULL); ret = nb_cli_apply_changes(vty, xpath_list); @@ -821,8 +821,7 @@ DEFUN_YANG (no_vrf, return CMD_WARNING_CONFIG_FAILED; } - snprintf(xpath_list, sizeof(xpath_list), "/frr-vrf:lib/vrf[name='%s']", - vrfname); + snprintf(xpath_list, sizeof(xpath_list), FRR_VRF_KEY_XPATH, vrfname); nb_cli_enqueue_change(vty, xpath_list, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, xpath_list); @@ -52,6 +52,9 @@ enum { IFLA_VRF_UNSPEC, IFLA_VRF_TABLE, __IFLA_VRF_MAX }; #define VRF_ALL_CMD_HELP_STR "Specify the VRF\nAll VRFs\n" #define VRF_FULL_CMD_HELP_STR "Specify the VRF\nThe VRF name\nAll VRFs\n" +#define FRR_VRF_XPATH "/frr-vrf:lib/vrf" +#define FRR_VRF_KEY_XPATH "/frr-vrf:lib/vrf[name='%s']" + /* * Pass some OS specific data up through * to the daemons @@ -2427,9 +2427,9 @@ bool vty_read_config(struct nb_config *config, const char *config_file, __func__, errno); goto tmp_free_and_out; } - tmp = XMALLOC(MTYPE_TMP, - strlen(cwd) + strlen(config_file) + 2); - sprintf(tmp, "%s/%s", cwd, config_file); + size_t tmp_len = strlen(cwd) + strlen(config_file) + 2; + tmp = XMALLOC(MTYPE_TMP, tmp_len); + snprintf(tmp, tmp_len, "%s/%s", cwd, config_file); fullpath = tmp; } else fullpath = config_file; diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c index abcdb40547..f6a246500b 100644 --- a/ospf6d/ospf6_abr.c +++ b/ospf6d/ospf6_abr.c @@ -1292,6 +1292,7 @@ static char *ospf6_inter_area_prefix_lsa_get_prefix_str(struct ospf6_lsa *lsa, { struct ospf6_inter_prefix_lsa *prefix_lsa; struct in6_addr in6; + char tbuf[16]; if (lsa != NULL) { prefix_lsa = @@ -1301,8 +1302,9 @@ static char *ospf6_inter_area_prefix_lsa_get_prefix_str(struct ospf6_lsa *lsa, ospf6_prefix_in6_addr(&in6, prefix_lsa, &prefix_lsa->prefix); if (buf) { inet_ntop(AF_INET6, &in6, buf, buflen); - sprintf(&buf[strlen(buf)], "/%d", - prefix_lsa->prefix.prefix_length); + snprintf(tbuf, sizeof(tbuf), "/%d", + prefix_lsa->prefix.prefix_length); + strlcat(buf, tbuf, buflen); } } diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 3449f48267..d0c93dd577 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -1865,6 +1865,7 @@ static char *ospf6_as_external_lsa_get_prefix_str(struct ospf6_lsa *lsa, struct ospf6_as_external_lsa *external; struct in6_addr in6; int prefix_length = 0; + char tbuf[16]; if (lsa) { external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END( @@ -1885,9 +1886,11 @@ static char *ospf6_as_external_lsa_get_prefix_str(struct ospf6_lsa *lsa, } if (buf) { inet_ntop(AF_INET6, &in6, buf, buflen); - if (prefix_length) - sprintf(&buf[strlen(buf)], "/%d", - prefix_length); + if (prefix_length) { + snprintf(tbuf, sizeof(tbuf), "/%d", + prefix_length); + strlcat(buf, tbuf, buflen); + } } } return (buf); diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index 5394ba9786..2cffc3a397 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -84,7 +84,7 @@ static char *ospf6_router_lsa_get_nbr_id(struct ospf6_lsa *lsa, char *buf, sizeof(buf1)); inet_ntop(AF_INET, &lsdesc->neighbor_router_id, buf2, sizeof(buf2)); - sprintf(buf, "%s/%s", buf2, buf1); + snprintf(buf, buflen, "%s/%s", buf2, buf1); return buf; } @@ -866,6 +866,7 @@ static char *ospf6_intra_prefix_lsa_get_prefix_str(struct ospf6_lsa *lsa, struct in6_addr in6; int prefixnum, cnt = 0; struct ospf6_prefix *prefix; + char tbuf[16]; if (lsa) { intra_prefix_lsa = @@ -898,8 +899,9 @@ static char *ospf6_intra_prefix_lsa_get_prefix_str(struct ospf6_lsa *lsa, OSPF6_PREFIX_SPACE( prefix->prefix_length)); inet_ntop(AF_INET6, &in6, buf, buflen); - sprintf(&buf[strlen(buf)], "/%d", - prefix->prefix_length); + snprintf(tbuf, sizeof(tbuf), "/%d", + prefix->prefix_length); + strlcat(buf, tbuf, buflen); return (buf); } } diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c index b98852eeee..19829d4546 100644 --- a/ospfd/ospf_dump.c +++ b/ospfd/ospf_dump.c @@ -616,7 +616,7 @@ DEFUN (debug_ospf_packet, if (inst) // user passed instance ID { - if (!ospf_lookup_instance(strtoul(argv[2]->arg, NULL, 10))) + if (inst != ospf_instance) return CMD_NOT_MY_INSTANCE; } @@ -692,7 +692,7 @@ DEFUN (no_debug_ospf_packet, if (inst) // user passed instance ID { - if (!ospf_lookup_instance(strtoul(argv[3]->arg, NULL, 10))) + if (inst != ospf_instance) return CMD_NOT_MY_INSTANCE; } @@ -763,7 +763,7 @@ DEFUN (debug_ospf_ism, if (inst) // user passed instance ID { - if (!ospf_lookup_instance(strtoul(argv[2]->arg, NULL, 10))) + if (inst != ospf_instance) return CMD_NOT_MY_INSTANCE; } @@ -814,7 +814,7 @@ DEFUN (no_debug_ospf_ism, if (inst) // user passed instance ID { - if (!ospf_lookup_instance(strtoul(argv[3]->arg, NULL, 10))) + if (inst != ospf_instance) return CMD_NOT_MY_INSTANCE; } @@ -909,8 +909,8 @@ DEFUN (debug_ospf_instance_nsm, unsigned short instance = 0; instance = strtoul(argv[idx_number]->arg, NULL, 10); - if (!ospf_lookup_instance(instance)) - return CMD_SUCCESS; + if (instance != ospf_instance) + return CMD_NOT_MY_INSTANCE; return debug_ospf_nsm_common(vty, 4, argc, argv); } @@ -981,7 +981,7 @@ DEFUN (no_debug_ospf_instance_nsm, unsigned short instance = 0; instance = strtoul(argv[idx_number]->arg, NULL, 10); - if (!ospf_lookup_instance(instance)) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; return no_debug_ospf_nsm_common(vty, 5, argc, argv); @@ -1062,7 +1062,7 @@ DEFUN (debug_ospf_instance_lsa, unsigned short instance = 0; instance = strtoul(argv[idx_number]->arg, NULL, 10); - if (!ospf_lookup_instance(instance)) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; return debug_ospf_lsa_common(vty, 4, argc, argv); @@ -1145,7 +1145,7 @@ DEFUN (no_debug_ospf_instance_lsa, unsigned short instance = 0; instance = strtoul(argv[idx_number]->arg, NULL, 10); - if (!ospf_lookup_instance(instance)) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; return no_debug_ospf_lsa_common(vty, 5, argc, argv); @@ -1207,7 +1207,7 @@ DEFUN (debug_ospf_instance_zebra, unsigned short instance = 0; instance = strtoul(argv[idx_number]->arg, NULL, 10); - if (!ospf_lookup_instance(instance)) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; return debug_ospf_zebra_common(vty, 4, argc, argv); @@ -1271,8 +1271,8 @@ DEFUN (no_debug_ospf_instance_zebra, unsigned short instance = 0; instance = strtoul(argv[idx_number]->arg, NULL, 10); - if (!ospf_lookup_instance(instance)) - return CMD_SUCCESS; + if (instance != ospf_instance) + return CMD_NOT_MY_INSTANCE; return no_debug_ospf_zebra_common(vty, 5, argc, argv); } @@ -1317,8 +1317,8 @@ DEFUN (debug_ospf_instance_event, unsigned short instance = 0; instance = strtoul(argv[idx_number]->arg, NULL, 10); - if (!ospf_lookup_instance(instance)) - return CMD_SUCCESS; + if (instance != ospf_instance) + return CMD_NOT_MY_INSTANCE; if (vty->node == CONFIG_NODE) CONF_DEBUG_ON(event, EVENT); @@ -1339,8 +1339,8 @@ DEFUN (no_debug_ospf_instance_event, unsigned short instance = 0; instance = strtoul(argv[idx_number]->arg, NULL, 10); - if (!ospf_lookup_instance(instance)) - return CMD_SUCCESS; + if (instance != ospf_instance) + return CMD_NOT_MY_INSTANCE; if (vty->node == CONFIG_NODE) CONF_DEBUG_OFF(event, EVENT); @@ -1387,8 +1387,8 @@ DEFUN (debug_ospf_instance_nssa, unsigned short instance = 0; instance = strtoul(argv[idx_number]->arg, NULL, 10); - if (!ospf_lookup_instance(instance)) - return CMD_SUCCESS; + if (instance != ospf_instance) + return CMD_NOT_MY_INSTANCE; if (vty->node == CONFIG_NODE) CONF_DEBUG_ON(nssa, NSSA); @@ -1409,8 +1409,8 @@ DEFUN (no_debug_ospf_instance_nssa, unsigned short instance = 0; instance = strtoul(argv[idx_number]->arg, NULL, 10); - if (!ospf_lookup_instance(instance)) - return CMD_SUCCESS; + if (instance != ospf_instance) + return CMD_NOT_MY_INSTANCE; if (vty->node == CONFIG_NODE) CONF_DEBUG_OFF(nssa, NSSA); @@ -1625,12 +1625,12 @@ DEFUN (no_debug_ospf, return CMD_SUCCESS; } -static int show_debugging_ospf_common(struct vty *vty, struct ospf *ospf) +static int show_debugging_ospf_common(struct vty *vty) { int i; - if (ospf->instance) - vty_out(vty, "\nOSPF Instance: %d\n\n", ospf->instance); + if (ospf_instance) + vty_out(vty, "\nOSPF Instance: %d\n\n", ospf_instance); vty_out(vty, "OSPF debugging status:\n"); @@ -1742,13 +1742,7 @@ DEFUN_NOSH (show_debugging_ospf, DEBUG_STR OSPF_STR) { - struct ospf *ospf = NULL; - - ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); - if (ospf == NULL) - return CMD_SUCCESS; - - return show_debugging_ospf_common(vty, ospf); + return show_debugging_ospf_common(vty); } DEFUN_NOSH (show_debugging_ospf_instance, @@ -1760,14 +1754,13 @@ DEFUN_NOSH (show_debugging_ospf_instance, "Instance ID\n") { int idx_number = 3; - struct ospf *ospf; unsigned short instance = 0; instance = strtoul(argv[idx_number]->arg, NULL, 10); - if ((ospf = ospf_lookup_instance(instance)) == NULL) - return CMD_SUCCESS; + if (instance != ospf_instance) + return CMD_NOT_MY_INSTANCE; - return show_debugging_ospf_common(vty, ospf); + return show_debugging_ospf_common(vty); } static int config_write_debug(struct vty *vty); @@ -1790,16 +1783,11 @@ static int config_write_debug(struct vty *vty) "", " send", " recv", "", " detail", " send detail", " recv detail", " detail"}; - struct ospf *ospf; char str[16]; memset(str, 0, 16); - ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); - if (ospf == NULL) - return CMD_SUCCESS; - - if (ospf->instance) - snprintf(str, sizeof(str), " %u", ospf->instance); + if (ospf_instance) + snprintf(str, sizeof(str), " %u", ospf_instance); /* debug ospf ism (status|events|timers). */ if (IS_CONF_DEBUG_OSPF(ism, ISM) == OSPF_DEBUG_ISM) diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index 6be5486b55..6a90dbff11 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -146,9 +146,6 @@ FRR_DAEMON_INFO(ospfd, OSPF, .vty_port = OSPF_VTY_PORT, /* OSPFd main routine. */ int main(int argc, char **argv) { - unsigned short instance = 0; - bool created = false; - #ifdef SUPPORT_OSPF_API /* OSPF apiserver is disabled by default. */ ospf_apiserver_enable = 0; @@ -169,8 +166,8 @@ int main(int argc, char **argv) switch (opt) { case 'n': - ospfd_di.instance = instance = atoi(optarg); - if (instance < 1) + ospfd_di.instance = ospf_instance = atoi(optarg); + if (ospf_instance < 1) exit(0); break; case 0: @@ -208,7 +205,7 @@ int main(int argc, char **argv) /* OSPFd inits. */ ospf_if_init(); - ospf_zebra_init(master, instance); + ospf_zebra_init(master, ospf_instance); /* OSPF vty inits. */ ospf_vty_init(); @@ -227,17 +224,6 @@ int main(int argc, char **argv) /* OSPF errors init */ ospf_error_init(); - /* - * Need to initialize the default ospf structure, so the interface mode - * commands can be duly processed if they are received before 'router - * ospf', when ospfd is restarted - */ - if (instance && !ospf_get_instance(instance, &created)) { - flog_err(EC_OSPF_INIT_FAIL, "OSPF instance init failed: %s", - strerror(errno)); - exit(1); - } - frr_config_fork(); frr_run(master); diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 4132452069..2ff59ccf49 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -140,44 +140,37 @@ int ospf_oi_count(struct interface *ifp) all_vrf = strmatch(vrf_name, "all"); \ } -static struct ospf *ospf_cmd_lookup_ospf(struct vty *vty, - struct cmd_token *argv[], - const int argc, uint32_t enable, - unsigned short *instance) +static int ospf_router_cmd_parse(struct vty *vty, struct cmd_token *argv[], + const int argc, unsigned short *instance, + const char **vrf_name) { - struct ospf *ospf = NULL; int idx_vrf = 0, idx_inst = 0; - const char *vrf_name = NULL; - bool created = false; *instance = 0; - if (argv_find(argv, argc, "(1-65535)", &idx_inst)) + if (argv_find(argv, argc, "(1-65535)", &idx_inst)) { + if (ospf_instance == 0) { + vty_out(vty, + "%% OSPF is not running in instance mode\n"); + return CMD_WARNING_CONFIG_FAILED; + } + *instance = strtoul(argv[idx_inst]->arg, NULL, 10); + } + *vrf_name = NULL; if (argv_find(argv, argc, "vrf", &idx_vrf)) { - vrf_name = argv[idx_vrf + 1]->arg; - if (vrf_name == NULL || strmatch(vrf_name, VRF_DEFAULT_NAME)) - vrf_name = NULL; - if (enable) { - /* Allocate VRF aware instance */ - ospf = ospf_get(*instance, vrf_name, &created); - } else { - ospf = ospf_lookup_by_inst_name(*instance, vrf_name); - } - } else { - if (enable) { - ospf = ospf_get(*instance, NULL, &created); - } else { - ospf = ospf_lookup_instance(*instance); + if (ospf_instance != 0) { + vty_out(vty, + "%% VRF is not supported in instance mode\n"); + return CMD_WARNING_CONFIG_FAILED; } - } - if (created) { - if (DFLT_OSPF_LOG_ADJACENCY_CHANGES) - SET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_CHANGES); + *vrf_name = argv[idx_vrf + 1]->arg; + if (*vrf_name && strmatch(*vrf_name, VRF_DEFAULT_NAME)) + *vrf_name = NULL; } - return ospf; + return CMD_SUCCESS; } static void ospf_show_vrf_name(struct ospf *ospf, struct vty *vty, @@ -213,28 +206,35 @@ DEFUN_NOSH (router_ospf, "Instance ID\n" VRF_CMD_HELP_STR) { - struct ospf *ospf = NULL; - int ret = CMD_SUCCESS; - unsigned short instance = 0; + unsigned short instance; + const char *vrf_name; + bool created = false; + struct ospf *ospf; + int ret; - ospf = ospf_cmd_lookup_ospf(vty, argv, argc, 1, &instance); - if (!ospf) - return CMD_WARNING_CONFIG_FAILED; + ret = ospf_router_cmd_parse(vty, argv, argc, &instance, &vrf_name); + if (ret != CMD_SUCCESS) + return ret; - /* The following logic to set the vty qobj index is in place to be able - to ignore the commands which dont belong to this instance. */ - if (ospf->instance != instance) { + if (instance != ospf_instance) { VTY_PUSH_CONTEXT_NULL(OSPF_NODE); - ret = CMD_NOT_MY_INSTANCE; - } else { - if (IS_DEBUG_OSPF_EVENT) - zlog_debug( - "Config command 'router ospf %d' received, vrf %s id %u oi_running %u", - instance, ospf->name ? ospf->name : "NIL", - ospf->vrf_id, ospf->oi_running); - VTY_PUSH_CONTEXT(OSPF_NODE, ospf); + return CMD_NOT_MY_INSTANCE; } + ospf = ospf_get(instance, vrf_name, &created); + + if (created) + if (DFLT_OSPF_LOG_ADJACENCY_CHANGES) + SET_FLAG(ospf->config, OSPF_LOG_ADJACENCY_CHANGES); + + if (IS_DEBUG_OSPF_EVENT) + zlog_debug( + "Config command 'router ospf %d' received, vrf %s id %u oi_running %u", + ospf->instance, ospf->name ? ospf->name : "NIL", + ospf->vrf_id, ospf->oi_running); + + VTY_PUSH_CONTEXT(OSPF_NODE, ospf); + return ret; } @@ -247,19 +247,25 @@ DEFUN (no_router_ospf, "Instance ID\n" VRF_CMD_HELP_STR) { + unsigned short instance; + const char *vrf_name; struct ospf *ospf; - unsigned short instance = 0; + int ret; - ospf = ospf_cmd_lookup_ospf(vty, argv, argc, 0, &instance); - if (ospf == NULL) { - if (instance) - return CMD_NOT_MY_INSTANCE; - else - return CMD_WARNING; - } - ospf_finish(ospf); + ret = ospf_router_cmd_parse(vty, argv, argc, &instance, &vrf_name); + if (ret != CMD_SUCCESS) + return ret; - return CMD_SUCCESS; + if (instance != ospf_instance) + return CMD_NOT_MY_INSTANCE; + + ospf = ospf_lookup(instance, vrf_name); + if (ospf) + ospf_finish(ospf); + else + ret = CMD_WARNING_CONFIG_FAILED; + + return ret; } @@ -3381,11 +3387,11 @@ DEFUN (show_ip_ospf_instance, json_object *json = NULL; instance = strtoul(argv[idx_number]->arg, NULL, 10); - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; - if (!ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (!ospf || !ospf->oi_running) return CMD_SUCCESS; if (uj) @@ -4131,11 +4137,11 @@ DEFUN (show_ip_ospf_instance_interface, json_object *json = NULL; instance = strtoul(argv[idx_number]->arg, NULL, 10); - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; - if (!ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (!ospf || !ospf->oi_running) return CMD_SUCCESS; if (uj) @@ -4526,11 +4532,11 @@ DEFUN (show_ip_ospf_instance_neighbor, int ret = CMD_SUCCESS; instance = strtoul(argv[idx_number]->arg, NULL, 10); - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; - if (!ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (!ospf || !ospf->oi_running) return CMD_SUCCESS; if (uj) @@ -4741,11 +4747,11 @@ DEFUN (show_ip_ospf_instance_neighbor_all, int ret = CMD_SUCCESS; instance = strtoul(argv[idx_number]->arg, NULL, 10); - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; - if (!ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (!ospf || !ospf->oi_running) return CMD_SUCCESS; if (uj) json = json_object_new_object(); @@ -4881,11 +4887,11 @@ DEFUN (show_ip_ospf_instance_neighbor_int, show_ip_ospf_neighbour_header(vty); instance = strtoul(argv[idx_number]->arg, NULL, 10); - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; - if (!ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (!ospf || !ospf->oi_running) return CMD_SUCCESS; if (!uj) @@ -5359,11 +5365,11 @@ DEFPY (show_ip_ospf_instance_neighbor_id, { struct ospf *ospf; - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; - if (!ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (!ospf || !ospf->oi_running) return CMD_SUCCESS; return show_ip_ospf_neighbor_id_common(vty, ospf, &router_id, !!json, @@ -5532,11 +5538,11 @@ DEFUN (show_ip_ospf_instance_neighbor_detail, int ret = CMD_SUCCESS; instance = strtoul(argv[idx_number]->arg, NULL, 10); - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; - if (!ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (!ospf || !ospf->oi_running) return CMD_SUCCESS; if (uj) @@ -5727,11 +5733,11 @@ DEFUN (show_ip_ospf_instance_neighbor_detail_all, int ret = CMD_SUCCESS; instance = strtoul(argv[idx_number]->arg, NULL, 10); - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; - if (!ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (!ospf || !ospf->oi_running) return CMD_SUCCESS; if (uj) @@ -5859,11 +5865,11 @@ DEFUN (show_ip_ospf_instance_neighbor_int_detail, bool uj = use_json(argc, argv); instance = strtoul(argv[idx_number]->arg, NULL, 10); - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; - if (!ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (!ospf || !ospf->oi_running) return CMD_SUCCESS; return show_ip_ospf_neighbor_int_detail_common(vty, ospf, idx_ifname, @@ -7136,10 +7142,11 @@ DEFUN (show_ip_ospf_instance_database, if (argv_find(argv, argc, "(1-65535)", &idx)) { instance = strtoul(argv[idx]->arg, NULL, 10); - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; - if (!ospf->oi_running) + + ospf = ospf_lookup_instance(instance); + if (!ospf || !ospf->oi_running) return CMD_SUCCESS; return (show_ip_ospf_database_common( @@ -7212,15 +7219,12 @@ DEFUN (show_ip_ospf_instance_database_max, json = json_object_new_object(); instance = strtoul(argv[idx_number]->arg, NULL, 10); - - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; - if (!ospf->oi_running) { - vty_out(vty, "%% OSPF instance not found\n"); + ospf = ospf_lookup_instance(instance); + if (!ospf || !ospf->oi_running) return CMD_SUCCESS; - } show_ip_ospf_database_common(vty, ospf, 1, argc, argv, 0, json, uj); @@ -7355,13 +7359,12 @@ DEFUN (show_ip_ospf_instance_database_type_adv_router, if (argv_find(argv, argc, "(1-65535)", &idx)) { instance = strtoul(argv[idx]->arg, NULL, 10); - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; - if (!ospf->oi_running) { - vty_out(vty, "%% OSPF instance not found\n"); + + ospf = ospf_lookup_instance(instance); + if (!ospf || !ospf->oi_running) return CMD_SUCCESS; - } return (show_ip_ospf_database_type_adv_router_common( vty, ospf, idx ? 1 : 0, argc, argv, use_vrf, json, uj)); @@ -8819,7 +8822,7 @@ DEFUN (ip_ospf_area, else ospf = ospf_lookup_instance(instance); - if (instance && ospf == NULL) { + if (instance && instance != ospf_instance) { /* * At this point we know we have received * an instance and there is no ospf instance @@ -8944,7 +8947,7 @@ DEFUN (no_ip_ospf_area, else ospf = ospf_lookup_instance(instance); - if (instance && ospf == NULL) + if (instance && instance != ospf_instance) return CMD_NOT_MY_INSTANCE; argv_find(argv, argc, "area", &idx); @@ -10918,11 +10921,11 @@ DEFUN (show_ip_ospf_instance_border_routers, unsigned short instance = 0; instance = strtoul(argv[idx_number]->arg, NULL, 10); - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; - if (!ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (!ospf || !ospf->oi_running) return CMD_SUCCESS; return show_ip_ospf_border_routers_common(vty, ospf, 0); @@ -11086,11 +11089,11 @@ DEFUN (show_ip_ospf_instance_route, unsigned short instance = 0; instance = strtoul(argv[idx_number]->arg, NULL, 10); - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; - if (!ospf->oi_running) + ospf = ospf_lookup_instance(instance); + if (!ospf || !ospf->oi_running) return CMD_SUCCESS; return show_ip_ospf_route_common(vty, ospf, NULL, 0); @@ -11189,8 +11192,7 @@ DEFPY (clear_ip_ospf_neighbor, */ if (instance != 0) { /* This means clear only the particular ospf process */ - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; } @@ -11220,8 +11222,7 @@ DEFPY (clear_ip_ospf_process, /* Check if instance is not passed as an argument */ if (instance != 0) { /* This means clear only the particular ospf process */ - ospf = ospf_lookup_instance(instance); - if (ospf == NULL) + if (instance != ospf_instance) return CMD_NOT_MY_INSTANCE; } @@ -11545,7 +11546,6 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf) struct ospf_if_params *params; const char *auth_str; int write = 0; - struct ospf *ospf = vrf->info; FOR_ALL_INTERFACES (vrf, ifp) { @@ -11698,9 +11698,9 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf) /* Area print. */ if (OSPF_IF_PARAM_CONFIGURED(params, if_area)) { - if (ospf && ospf->instance) + if (ospf_instance) vty_out(vty, " ip ospf %d", - ospf->instance); + ospf_instance); else vty_out(vty, " ip ospf"); diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 04397d50a5..9590a9c73b 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -70,6 +70,8 @@ static struct ospf_master ospf_master; /* OSPF process wide configuration pointer to export. */ struct ospf_master *om; +unsigned short ospf_instance; + extern struct zclient *zclient; @@ -511,36 +513,28 @@ static void ospf_init(struct ospf *ospf) ospf_router_id_update(ospf); } -struct ospf *ospf_get(unsigned short instance, const char *name, bool *created) +struct ospf *ospf_lookup(unsigned short instance, const char *name) { struct ospf *ospf; - /* vrf name provided call inst and name based api - * in case of no name pass default ospf instance */ - if (name) + if (ospf_instance) { + ospf = ospf_lookup_instance(instance); + } else { ospf = ospf_lookup_by_inst_name(instance, name); - else - ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); - - *created = (ospf == NULL); - if (ospf == NULL) { - ospf = ospf_new(instance, name); - ospf_add(ospf); - - ospf_init(ospf); } return ospf; } -struct ospf *ospf_get_instance(unsigned short instance, bool *created) +struct ospf *ospf_get(unsigned short instance, const char *name, bool *created) { struct ospf *ospf; - ospf = ospf_lookup_instance(instance); + ospf = ospf_lookup(instance, name); + *created = (ospf == NULL); if (ospf == NULL) { - ospf = ospf_new(instance, NULL /* VRF_DEFAULT*/); + ospf = ospf_new(instance, name); ospf_add(ospf); ospf_init(ospf); diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h index 954a469b68..5148bf555c 100644 --- a/ospfd/ospfd.h +++ b/ospfd/ospfd.h @@ -633,6 +633,7 @@ struct ospf_nbr_nbma { /* Extern variables. */ extern struct ospf_master *om; +extern unsigned short ospf_instance; extern const int ospf_redistributed_proto_max; extern struct zclient *zclient; extern struct thread_master *master; @@ -642,10 +643,10 @@ extern struct zebra_privs_t ospfd_privs; /* Prototypes. */ extern const char *ospf_redist_string(unsigned int route_type); extern struct ospf *ospf_lookup_instance(unsigned short); +extern struct ospf *ospf_lookup(unsigned short instance, const char *name); extern struct ospf *ospf_get(unsigned short instance, const char *name, bool *created); extern struct ospf *ospf_new_alloc(unsigned short instance, const char *name); -extern struct ospf *ospf_get_instance(unsigned short, bool *created); extern struct ospf *ospf_lookup_by_inst_name(unsigned short instance, const char *name); extern struct ospf *ospf_lookup_by_vrf_id(vrf_id_t vrf_id); diff --git a/pimd/pim_main.c b/pimd/pim_main.c index 9c11cc47d5..5a09e7a8ee 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -145,6 +145,8 @@ int main(int argc, char **argv, char **envp) hook_register(routing_conf_event, routing_control_plane_protocols_name_validate); + routing_control_plane_protocols_register_vrf_dependency(); + frr_config_fork(); #ifdef PIM_DEBUG_BYDEFAULT diff --git a/staticd/static_main.c b/staticd/static_main.c index ac8f8ff029..560814771d 100644 --- a/staticd/static_main.c +++ b/staticd/static_main.c @@ -164,6 +164,8 @@ int main(int argc, char **argv, char **envp) hook_register(routing_conf_event, routing_control_plane_protocols_name_validate); + routing_control_plane_protocols_register_vrf_dependency(); + snprintf(backup_config_file, sizeof(backup_config_file), "%s/zebra.conf", frr_sysconfdir); staticd_di.backup_config_file = backup_config_file; diff --git a/tests/topotests/bgp-aggregator-zero/__init__.py b/tests/topotests/bgp-aggregator-zero/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp-aggregator-zero/__init__.py diff --git a/tests/topotests/bgp-aggregator-zero/exabgp.env b/tests/topotests/bgp-aggregator-zero/exabgp.env new file mode 100644 index 0000000000..28e642360a --- /dev/null +++ b/tests/topotests/bgp-aggregator-zero/exabgp.env @@ -0,0 +1,53 @@ +[exabgp.api] +encoder = text +highres = false +respawn = false +socket = '' + +[exabgp.bgp] +openwait = 60 + +[exabgp.cache] +attributes = true +nexthops = true + +[exabgp.daemon] +daemonize = true +pid = '/var/run/exabgp/exabgp.pid' +user = 'exabgp' +##daemonize = false + +[exabgp.log] +all = false +configuration = true +daemon = true +destination = '/var/log/exabgp.log' +enable = true +level = INFO +message = false +network = true +packets = false +parser = false +processes = true +reactor = true +rib = false +routes = false +short = false +timers = false + +[exabgp.pdb] +enable = false + +[exabgp.profile] +enable = false +file = '' + +[exabgp.reactor] +speed = 1.0 + +[exabgp.tcp] +acl = false +bind = '' +delay = 0 +once = false +port = 179 diff --git a/tests/topotests/bgp-aggregator-zero/peer1/exabgp.cfg b/tests/topotests/bgp-aggregator-zero/peer1/exabgp.cfg new file mode 100644 index 0000000000..b3f25272d2 --- /dev/null +++ b/tests/topotests/bgp-aggregator-zero/peer1/exabgp.cfg @@ -0,0 +1,18 @@ +neighbor 10.0.0.1 { + router-id 10.0.0.2; + local-address 10.0.0.2; + local-as 65001; + peer-as 65534; + + static { + route 192.168.100.101/32 { + aggregator (0:10.0.0.2); + next-hop 10.0.0.2; + } + + route 192.168.100.102/32 { + aggregator (65001:10.0.0.2); + next-hop 10.0.0.2; + } + } +} diff --git a/tests/topotests/bgp-aggregator-zero/r1/bgpd.conf b/tests/topotests/bgp-aggregator-zero/r1/bgpd.conf new file mode 100644 index 0000000000..002a5c78c0 --- /dev/null +++ b/tests/topotests/bgp-aggregator-zero/r1/bgpd.conf @@ -0,0 +1,6 @@ +! +router bgp 65534 + no bgp ebgp-requires-policy + neighbor 10.0.0.2 remote-as external + neighbor 10.0.0.2 timers 3 10 +! diff --git a/tests/topotests/bgp-aggregator-zero/r1/zebra.conf b/tests/topotests/bgp-aggregator-zero/r1/zebra.conf new file mode 100644 index 0000000000..22a26ac610 --- /dev/null +++ b/tests/topotests/bgp-aggregator-zero/r1/zebra.conf @@ -0,0 +1,6 @@ +! +interface r1-eth0 + ip address 10.0.0.1/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp-aggregator-zero/test_bgp_aggregator_zero.py b/tests/topotests/bgp-aggregator-zero/test_bgp_aggregator_zero.py new file mode 100644 index 0000000000..0db47da3f2 --- /dev/null +++ b/tests/topotests/bgp-aggregator-zero/test_bgp_aggregator_zero.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2021 by +# Donatas Abraitis <donatas.abraitis@gmail.com> +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +Test if BGP UPDATE with AGGREGATOR AS attribute with value zero (0) +is continued to be processed, but AGGREGATOR attribute is discarded. +""" + +import os +import sys +import json +import time +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from mininet.topo import Topo + + +class BgpAggregatorAsnZero(Topo): + def build(self, *_args, **_opts): + tgen = get_topogen(self) + + r1 = tgen.add_router("r1") + peer1 = tgen.add_exabgp_peer( + "peer1", ip="10.0.0.2", defaultRoute="via 10.0.0.1" + ) + + switch = tgen.add_switch("s1") + switch.add_link(r1) + switch.add_link(peer1) + + +def setup_module(mod): + tgen = Topogen(BgpAggregatorAsnZero, mod.__name__) + tgen.start_topology() + + router = tgen.gears["r1"] + router.load_config(TopoRouter.RD_ZEBRA, os.path.join(CWD, "r1/zebra.conf")) + router.load_config(TopoRouter.RD_BGP, os.path.join(CWD, "r1/bgpd.conf")) + router.start() + + peer = tgen.gears["peer1"] + peer.start(os.path.join(CWD, "peer1"), os.path.join(CWD, "exabgp.env")) + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_aggregator_zero(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + def _bgp_converge(): + output = json.loads( + tgen.gears["r1"].vtysh_cmd("show ip bgp neighbor 10.0.0.2 json") + ) + expected = { + "10.0.0.2": { + "bgpState": "Established", + "addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 2}}, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_converge) + success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + + assert result is None, 'Failed bgp convergence in "{}"'.format(tgen.gears["r1"]) + + def _bgp_has_correct_aggregator_route_with_asn_0(): + output = json.loads( + tgen.gears["r1"].vtysh_cmd("show ip bgp 192.168.100.101/32 json") + ) + + if "aggregatorAs" in output["paths"][0].keys(): + return False + else: + return True + + assert ( + _bgp_has_correct_aggregator_route_with_asn_0() is True + ), 'Aggregator AS attribute with ASN 0 found in "{}"'.format(tgen.gears["r1"]) + + def _bgp_has_correct_aggregator_route_with_good_asn(): + output = json.loads( + tgen.gears["r1"].vtysh_cmd("show ip bgp 192.168.100.102/32 json") + ) + expected = {"paths": [{"aggregatorAs": 65001, "aggregatorId": "10.0.0.2"}]} + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_has_correct_aggregator_route_with_good_asn) + success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + + assert result is None, 'Aggregator AS attribute not found in "{}"'.format( + tgen.gears["r1"] + ) + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index e026a28628..b41364c04d 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -2693,7 +2693,7 @@ static int show_per_daemon(struct vty *vty, struct cmd_token **argv, int argc, char *line = do_prepend(vty, argv, argc); for (i = 0; i < array_size(vtysh_client); i++) - if (vtysh_client[i].fd >= 0) { + if (vtysh_client[i].fd >= 0 || vtysh_client[i].next) { vty_out(vty, headline, vtysh_client[i].name); ret = vtysh_client_execute(&vtysh_client[i], line); vty_out(vty, "\n"); diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 00471b9645..3828f8800f 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -561,6 +561,8 @@ static void netlink_interface_update_l2info(struct interface *ifp, netlink_extract_vlan_info(link_data, &vlan_info); zebra_l2_vlanif_update(ifp, &vlan_info); + zebra_evpn_acc_bd_svi_set(ifp->info, NULL, + !!if_is_operative(ifp)); } else if (IS_ZEBRA_IF_VXLAN(ifp)) { struct zebra_l2info_vxlan vxlan_info; diff --git a/zebra/interface.c b/zebra/interface.c index fc34a6fb9e..f74030e4d8 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1183,6 +1183,11 @@ void zebra_if_update_all_links(void) zif->link?zif->link->name:"unk", zif->link_ifindex); } + + /* Update VLAN<=>SVI map */ + if (IS_ZEBRA_IF_VLAN(ifp)) + zebra_evpn_acc_bd_svi_set(zif, NULL, + !!if_is_operative(ifp)); } } diff --git a/zebra/irdp_interface.c b/zebra/irdp_interface.c index 2ab5fd3a4c..5352c6214d 100644 --- a/zebra/irdp_interface.c +++ b/zebra/irdp_interface.c @@ -93,10 +93,10 @@ static int irdp_if_delete(struct interface *ifp) return 0; } -static const char *inet_2a(uint32_t a, char *b) +static const char *inet_2a(uint32_t a, char *b, size_t b_len) { - sprintf(b, "%u.%u.%u.%u", (a)&0xFF, (a >> 8) & 0xFF, (a >> 16) & 0xFF, - (a >> 24) & 0xFF); + snprintf(b, b_len, "%u.%u.%u.%u", (a)&0xFF, (a >> 8) & 0xFF, + (a >> 16) & 0xFF, (a >> 24) & 0xFF); return b; } @@ -140,7 +140,8 @@ static int if_group(struct interface *ifp, int sock, uint32_t group, flog_err_sys(EC_LIB_SOCKET, "IRDP: %s can't setsockopt %s: %s", add_leave == IP_ADD_MEMBERSHIP ? "join group" : "leave group", - inet_2a(group, b1), safe_strerror(errno)); + inet_2a(group, b1, sizeof(b1)), + safe_strerror(errno)); return ret; } @@ -162,7 +163,8 @@ static int if_add_group(struct interface *ifp) if (irdp->flags & IF_DEBUG_MISC) zlog_debug("IRDP: Adding group %s for %s", - inet_2a(htonl(INADDR_ALLRTRS_GROUP), b1), ifp->name); + inet_2a(htonl(INADDR_ALLRTRS_GROUP), b1, sizeof(b1)), + ifp->name); return 0; } @@ -183,7 +185,8 @@ static int if_drop_group(struct interface *ifp) if (irdp->flags & IF_DEBUG_MISC) zlog_debug("IRDP: Leaving group %s for %s", - inet_2a(htonl(INADDR_ALLRTRS_GROUP), b1), ifp->name); + inet_2a(htonl(INADDR_ALLRTRS_GROUP), b1, sizeof(b1)), + ifp->name); return 0; } @@ -383,7 +386,8 @@ int irdp_config_write(struct vty *vty, struct interface *ifp) for (ALL_LIST_ELEMENTS_RO(irdp->AdvPrefList, node, adv)) vty_out(vty, " ip irdp address %s preference %d\n", - inet_2a(adv->ip.s_addr, b1), adv->pref); + inet_2a(adv->ip.s_addr, b1, sizeof(b1)), + adv->pref); vty_out(vty, " ip irdp holdtime %d\n", irdp->Lifetime); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 602805be3c..46a751ce69 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1132,8 +1132,8 @@ static int build_label_stack(struct mpls_label_stack *nh_label, if (IS_ZEBRA_DEBUG_KERNEL) { if (!num_labels) - sprintf(label_buf, "label %u", - nh_label->label[i]); + snprintf(label_buf, label_buf_size, "label %u", + nh_label->label[i]); else { snprintf(label_buf1, sizeof(label_buf1), "/%u", nh_label->label[i]); diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c index b232c664bc..d7076ccce6 100644 --- a/zebra/zebra_evpn.c +++ b/zebra/zebra_evpn.c @@ -151,6 +151,9 @@ void zebra_evpn_print(zebra_evpn_t *zevpn, void **ctxt) buf, sizeof(buf))); json_object_string_add(json, "advertiseGatewayMacip", zevpn->advertise_gw_macip ? "Yes" : "No"); + json_object_string_add(json, "advertiseSviMacip", + zevpn->advertise_svi_macip ? "Yes" + : "No"); json_object_int_add(json, "numMacs", num_macs); json_object_int_add(json, "numArpNd", num_neigh); } @@ -194,6 +197,8 @@ void zebra_evpn_print(zebra_evpn_t *zevpn, void **ctxt) num_neigh); vty_out(vty, " Advertise-gw-macip: %s\n", zevpn->advertise_gw_macip ? "Yes" : "No"); + vty_out(vty, " Advertise-svi-macip: %s\n", + zevpn->advertise_svi_macip ? "Yes" : "No"); } } @@ -429,7 +434,7 @@ int zebra_evpn_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn, vxl = &zif->l2info.vxl; if (zebra_evpn_mac_gw_macip_add(ifp, zevpn, ip, &mac, macaddr, - vxl->access_vlan) + vxl->access_vlan, true) != 0) return -1; @@ -569,7 +574,9 @@ void zebra_evpn_gw_macip_add_for_evpn_hash(struct hash_bucket *bucket, return; /* Add primary SVI MAC-IP */ - zebra_evpn_add_macip_for_intf(vlan_if, zevpn); + if (advertise_svi_macip_enabled(zevpn) + || advertise_gw_macip_enabled(zevpn)) + zebra_evpn_add_macip_for_intf(vlan_if, zevpn); if (advertise_gw_macip_enabled(zevpn)) { /* Add VRR MAC-IP - if any*/ @@ -925,14 +932,20 @@ void zebra_evpn_read_mac_neigh(zebra_evpn_t *zevpn, struct interface *ifp) macfdb_read_for_bridge(zns, ifp, zif->brslave_info.br_if); vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if); if (vlan_if) { + /* Add SVI MAC */ + zebra_evpn_acc_bd_svi_mac_add(vlan_if); /* Add SVI MAC-IP */ - zebra_evpn_add_macip_for_intf(vlan_if, zevpn); + if (advertise_svi_macip_enabled(zevpn) + || advertise_gw_macip_enabled(zevpn)) + zebra_evpn_add_macip_for_intf(vlan_if, zevpn); /* Add VRR MAC-IP - if any*/ - vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); - if (vrr_if) - zebra_evpn_add_macip_for_intf(vrr_if, zevpn); + if (advertise_gw_macip_enabled(zevpn)) { + vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); + if (vrr_if) + zebra_evpn_add_macip_for_intf(vrr_if, zevpn); + } neigh_read_for_vlan(zns, vlan_if); } diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c index 5227a480fc..90227aa597 100644 --- a/zebra/zebra_evpn_mac.c +++ b/zebra/zebra_evpn_mac.c @@ -221,8 +221,8 @@ void zebra_evpn_deref_ip2mac(zebra_evpn_t *zevpn, zebra_mac_t *mac) UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE); } - /* If no neighbors, delete the MAC. */ - if (list_isempty(mac->neigh_list)) + /* If no references, delete the MAC. */ + if (!zebra_evpn_mac_in_use(mac)) zebra_evpn_mac_del(zevpn, mac); } @@ -583,6 +583,9 @@ void zebra_evpn_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json) if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) json_object_boolean_true_add(json_mac, "stickyMac"); + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI)) + json_object_boolean_true_add(json_mac, "sviMac"); + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)) json_object_boolean_true_add(json_mac, "defaultGateway"); @@ -685,6 +688,9 @@ void zebra_evpn_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json) if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) vty_out(vty, " Sticky Mac "); + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI)) + vty_out(vty, " SVI-Mac "); + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_DEF_GW)) vty_out(vty, " Default-gateway Mac "); @@ -2376,7 +2382,8 @@ int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, zebra_mac_t *mac) int zebra_evpn_mac_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn, struct ipaddr *ip, zebra_mac_t **macp, - struct ethaddr *macaddr, vlanid_t vlan_id) + struct ethaddr *macaddr, vlanid_t vlan_id, + bool def_gw) { char buf[ETHER_ADDR_STRLEN]; zebra_mac_t *mac; @@ -2402,7 +2409,8 @@ int zebra_evpn_mac_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn, /* Set "local" forwarding info. */ SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); - SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW); + if (def_gw) + SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW); memset(&mac->fwd_info, 0, sizeof(mac->fwd_info)); mac->fwd_info.local.ifindex = ifp->ifindex; mac->fwd_info.local.ns_id = local_ns_id; @@ -2412,3 +2420,63 @@ int zebra_evpn_mac_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn, return 0; } + +void zebra_evpn_mac_svi_del(struct interface *ifp, zebra_evpn_t *zevpn) +{ + zebra_mac_t *mac; + struct ethaddr macaddr; + bool old_bgp_ready; + + if (!zebra_evpn_mh_do_adv_svi_mac()) + return; + + memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); + mac = zebra_evpn_mac_lookup(zevpn, &macaddr); + if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI)) { + if (IS_ZEBRA_DEBUG_EVPN_MH_ES) + zlog_debug("SVI %s mac free", ifp->name); + + old_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags); + UNSET_FLAG(mac->flags, ZEBRA_MAC_SVI); + zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, + false); + zebra_evpn_deref_ip2mac(mac->zevpn, mac); + } +} + +void zebra_evpn_mac_svi_add(struct interface *ifp, zebra_evpn_t *zevpn) +{ + zebra_mac_t *mac = NULL; + struct ethaddr macaddr; + struct zebra_if *zif = ifp->info; + bool old_bgp_ready; + bool new_bgp_ready; + + if (!zebra_evpn_mh_do_adv_svi_mac() + || !zebra_evpn_send_to_client_ok(zevpn)) + return; + + memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); + + /* dup check */ + mac = zebra_evpn_mac_lookup(zevpn, &macaddr); + if (mac && CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI)) + return; + + /* add/update mac */ + if (IS_ZEBRA_DEBUG_EVPN_MH_ES) + zlog_debug("SVI %s mac add", zif->ifp->name); + + old_bgp_ready = (mac && zebra_evpn_mac_is_ready_for_bgp(mac->flags)) + ? true + : false; + + mac = NULL; + zebra_evpn_mac_gw_macip_add(ifp, zevpn, NULL, &mac, &macaddr, 0, false); + if (mac) + SET_FLAG(mac->flags, ZEBRA_MAC_SVI); + + new_bgp_ready = zebra_evpn_mac_is_ready_for_bgp(mac->flags); + zebra_evpn_mac_send_add_del_to_client(mac, old_bgp_ready, + new_bgp_ready); +} diff --git a/zebra/zebra_evpn_mac.h b/zebra/zebra_evpn_mac.h index 242097907f..c021765843 100644 --- a/zebra/zebra_evpn_mac.h +++ b/zebra/zebra_evpn_mac.h @@ -80,6 +80,8 @@ struct zebra_mac_t_ { * to advertise it as locally attached but with a "proxy" flag */ #define ZEBRA_MAC_LOCAL_INACTIVE 0x800 +/* The MAC entry was created because of advertise_svi_mac */ +#define ZEBRA_MAC_SVI 0x1000 #define ZEBRA_MAC_ALL_LOCAL_FLAGS (ZEBRA_MAC_LOCAL | ZEBRA_MAC_LOCAL_INACTIVE) #define ZEBRA_MAC_ALL_PEER_FLAGS \ @@ -201,6 +203,12 @@ static inline void zebra_evpn_mac_clear_sync_info(zebra_mac_t *mac) zebra_evpn_mac_stop_hold_timer(mac); } +static inline bool zebra_evpn_mac_in_use(zebra_mac_t *mac) +{ + return !list_isempty(mac->neigh_list) + || CHECK_FLAG(mac->flags, ZEBRA_MAC_SVI); +} + struct hash *zebra_mac_db_create(const char *desc); uint32_t num_valid_macs(zebra_evpn_t *zevi); uint32_t num_dup_detected_macs(zebra_evpn_t *zevi); @@ -256,7 +264,10 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zebra_evpn_t *zevpn, int zebra_evpn_del_local_mac(zebra_evpn_t *zevpn, zebra_mac_t *mac); int zebra_evpn_mac_gw_macip_add(struct interface *ifp, zebra_evpn_t *zevpn, struct ipaddr *ip, zebra_mac_t **macp, - struct ethaddr *macaddr, vlanid_t vlan_id); + struct ethaddr *macaddr, vlanid_t vlan_id, + bool def_gw); +void zebra_evpn_mac_svi_add(struct interface *ifp, zebra_evpn_t *zevpn); +void zebra_evpn_mac_svi_del(struct interface *ifp, zebra_evpn_t *zevpn); #ifdef __cplusplus } diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c index 7e712bf1ee..0bb1ebb564 100644 --- a/zebra/zebra_evpn_mh.c +++ b/zebra/zebra_evpn_mh.c @@ -130,12 +130,6 @@ static struct zebra_evpn_es_evi *zebra_evpn_es_evi_new(struct zebra_evpn_es *es, return es_evi; } -/* returns TRUE if the EVPN is ready to be sent to BGP */ -static inline bool zebra_evpn_send_to_client_ok(zebra_evpn_t *zevpn) -{ - return !!(zevpn->flags & ZEVPN_READY_FOR_BGP); -} - /* Evaluate if the es_evi is ready to be sent BGP - * 1. If it is ready an add is sent to BGP * 2. If it is not ready a del is sent (if the ES had been previously added @@ -466,6 +460,9 @@ void zebra_evpn_update_all_es(zebra_evpn_t *zevpn) { struct zebra_evpn_es_evi *es_evi; struct listnode *node; + struct interface *vlan_if; + struct interface *vxlan_if; + struct zebra_if *vxlan_zif; /* the EVPN is now elgible as a base for EVPN-MH */ if (zebra_evpn_send_to_client_ok(zevpn)) @@ -475,6 +472,20 @@ void zebra_evpn_update_all_es(zebra_evpn_t *zevpn) for (ALL_LIST_ELEMENTS_RO(zevpn->local_es_evi_list, node, es_evi)) zebra_evpn_es_evi_re_eval_send_to_client(es_evi); + + /* reinstall SVI MAC */ + vxlan_if = zevpn->vxlan_if; + if (vxlan_if) { + vxlan_zif = vxlan_if->info; + if (if_is_operative(vxlan_if) + && vxlan_zif->brslave_info.br_if) { + vlan_if = zvni_map_to_svi( + vxlan_zif->l2info.vxl.access_vlan, + vxlan_zif->brslave_info.br_if); + if (vlan_if) + zebra_evpn_acc_bd_svi_mac_add(vlan_if); + } + } } /*****************************************************************************/ @@ -524,9 +535,11 @@ static struct zebra_evpn_access_bd *zebra_evpn_acc_vl_find(vlanid_t vid) /* A new broadcast domain can be created when a VLAN member or VLAN<=>VxLAN_IF * mapping is added. */ -static struct zebra_evpn_access_bd *zebra_evpn_acc_vl_new(vlanid_t vid) +static struct zebra_evpn_access_bd * +zebra_evpn_acc_vl_new(vlanid_t vid, struct interface *br_if) { struct zebra_evpn_access_bd *acc_bd; + struct interface *vlan_if; if (IS_ZEBRA_DEBUG_EVPN_MH_ES) zlog_debug("access vlan %d add", vid); @@ -544,6 +557,16 @@ static struct zebra_evpn_access_bd *zebra_evpn_acc_vl_new(vlanid_t vid) return NULL; } + /* check if an svi exists for the vlan */ + if (br_if) { + vlan_if = zvni_map_to_svi(vid, br_if); + if (vlan_if) { + if (IS_ZEBRA_DEBUG_EVPN_MH_ES) + zlog_debug("vlan %d SVI %s set", vid, + vlan_if->name); + acc_bd->vlan_zif = vlan_if->info; + } + } return acc_bd; } @@ -556,6 +579,9 @@ static void zebra_evpn_acc_vl_free(struct zebra_evpn_access_bd *acc_bd) if (IS_ZEBRA_DEBUG_EVPN_MH_ES) zlog_debug("access vlan %d del", acc_bd->vid); + if (acc_bd->vlan_zif && acc_bd->zevpn && acc_bd->zevpn->mac_table) + zebra_evpn_mac_svi_del(acc_bd->vlan_zif->ifp, acc_bd->zevpn); + /* cleanup resources maintained against the ES */ list_delete(&acc_bd->mbr_zifs); @@ -584,6 +610,59 @@ static void zebra_evpn_acc_bd_free_on_deref(struct zebra_evpn_access_bd *acc_bd) zebra_evpn_acc_vl_free(acc_bd); } +/* called when a SVI is goes up/down */ +void zebra_evpn_acc_bd_svi_set(struct zebra_if *vlan_zif, + struct zebra_if *br_zif, bool is_up) +{ + struct zebra_evpn_access_bd *acc_bd; + struct zebra_l2info_bridge *br; + uint16_t vid; + struct zebra_if *tmp_br_zif = br_zif; + + if (!tmp_br_zif) { + if (!vlan_zif->link || !vlan_zif->link->info) + return; + + tmp_br_zif = vlan_zif->link->info; + } + + br = &tmp_br_zif->l2info.br; + /* ignore vlan unaware bridges */ + if (!br->vlan_aware) + return; + + vid = vlan_zif->l2info.vl.vid; + acc_bd = zebra_evpn_acc_vl_find(vid); + if (!acc_bd) + return; + + if (is_up) { + if (IS_ZEBRA_DEBUG_EVPN_MH_ES) + zlog_debug("vlan %d SVI %s set", vid, + vlan_zif->ifp->name); + + acc_bd->vlan_zif = vlan_zif; + if (acc_bd->zevpn) + zebra_evpn_mac_svi_add(acc_bd->vlan_zif->ifp, + acc_bd->zevpn); + } else if (acc_bd->vlan_zif) { + if (IS_ZEBRA_DEBUG_EVPN_MH_ES) + zlog_debug("vlan %d SVI clear", vid); + acc_bd->vlan_zif = NULL; + if (acc_bd->zevpn && acc_bd->zevpn->mac_table) + zebra_evpn_mac_svi_del(vlan_zif->ifp, acc_bd->zevpn); + } +} + +/* On some events macs are force-flushed. This api can be used to reinstate + * the svi-mac after such cleanup-events. + */ +void zebra_evpn_acc_bd_svi_mac_add(struct interface *vlan_if) +{ + zebra_evpn_acc_bd_svi_set(vlan_if->info, NULL, + if_is_operative(vlan_if)); +} + /* called when a EVPN-L2VNI is set or cleared against a BD */ static void zebra_evpn_acc_bd_evpn_set(struct zebra_evpn_access_bd *acc_bd, zebra_evpn_t *zevpn, zebra_evpn_t *old_zevpn) @@ -604,6 +683,15 @@ static void zebra_evpn_acc_bd_evpn_set(struct zebra_evpn_access_bd *acc_bd, else if (old_zevpn) zebra_evpn_local_es_evi_del(zif->es_info.es, old_zevpn); } + + if (acc_bd->vlan_zif) { + if (zevpn) + zebra_evpn_mac_svi_add(acc_bd->vlan_zif->ifp, + acc_bd->zevpn); + else if (old_zevpn && old_zevpn->mac_table) + zebra_evpn_mac_svi_del(acc_bd->vlan_zif->ifp, + old_zevpn); + } } /* handle VLAN->VxLAN_IF association */ @@ -618,7 +706,8 @@ void zebra_evpn_vl_vxl_ref(uint16_t vid, struct zebra_if *vxlan_zif) acc_bd = zebra_evpn_acc_vl_find(vid); if (!acc_bd) - acc_bd = zebra_evpn_acc_vl_new(vid); + acc_bd = zebra_evpn_acc_vl_new(vid, + vxlan_zif->brslave_info.br_if); old_vxlan_zif = acc_bd->vxlan_zif; acc_bd->vxlan_zif = vxlan_zif; @@ -712,7 +801,7 @@ void zebra_evpn_vl_mbr_ref(uint16_t vid, struct zebra_if *zif) acc_bd = zebra_evpn_acc_vl_find(vid); if (!acc_bd) - acc_bd = zebra_evpn_acc_vl_new(vid); + acc_bd = zebra_evpn_acc_vl_new(vid, zif->brslave_info.br_if); if (listnode_lookup(acc_bd->mbr_zifs, zif)) return; @@ -756,6 +845,22 @@ void zebra_evpn_vl_mbr_deref(uint16_t vid, struct zebra_if *zif) zebra_evpn_acc_bd_free_on_deref(acc_bd); } +static void zebra_evpn_acc_vl_adv_svi_mac_cb(struct hash_bucket *bucket, + void *ctxt) +{ + struct zebra_evpn_access_bd *acc_bd = bucket->data; + + if (acc_bd->vlan_zif && acc_bd->zevpn) + zebra_evpn_mac_svi_add(acc_bd->vlan_zif->ifp, acc_bd->zevpn); +} + +/* called when advertise SVI MAC is enabled on the switch */ +static void zebra_evpn_acc_vl_adv_svi_mac_all(void) +{ + hash_iterate(zmh_info->evpn_vlan_table, + zebra_evpn_acc_vl_adv_svi_mac_cb, NULL); +} + static void zebra_evpn_acc_vl_json_fill(struct zebra_evpn_access_bd *acc_bd, json_object *json, bool detail) { @@ -800,6 +905,8 @@ static void zebra_evpn_acc_vl_show_entry_detail(struct vty *vty, vty_out(vty, " VxLAN Interface: %s\n", acc_bd->vxlan_zif ? acc_bd->vxlan_zif->ifp->name : "-"); + vty_out(vty, " SVI: %s\n", + acc_bd->vlan_zif ? acc_bd->vlan_zif->ifp->name : "-"); vty_out(vty, " L2-VNI: %d\n", acc_bd->zevpn ? acc_bd->zevpn->vni : 0); vty_out(vty, " Member Count: %d\n", @@ -817,12 +924,11 @@ static void zebra_evpn_acc_vl_show_entry(struct vty *vty, if (json) { zebra_evpn_acc_vl_json_fill(acc_bd, json, false); } else { - vty_out(vty, "%-5u %21s %-8d %u\n", - acc_bd->vid, - acc_bd->vxlan_zif ? - acc_bd->vxlan_zif->ifp->name : "-", - acc_bd->zevpn ? acc_bd->zevpn->vni : 0, - listcount(acc_bd->mbr_zifs)); + vty_out(vty, "%-5u %-15s %-8d %-15s %u\n", acc_bd->vid, + acc_bd->vlan_zif ? acc_bd->vlan_zif->ifp->name : "-", + acc_bd->zevpn ? acc_bd->zevpn->vni : 0, + acc_bd->vxlan_zif ? acc_bd->vxlan_zif->ifp->name : "-", + listcount(acc_bd->mbr_zifs)); } } @@ -856,8 +962,8 @@ void zebra_evpn_acc_vl_show(struct vty *vty, bool uj) wctx.detail = false; if (!uj) - vty_out(vty, "%-5s %21s %-8s %s\n", - "VLAN", "VxLAN-IF", "L2-VNI", "# Members"); + vty_out(vty, "%-5s %-15s %-8s %-15s %s\n", "VLAN", "SVI", + "L2-VNI", "VXLAN-IF", "# Members"); hash_iterate(zmh_info->evpn_vlan_table, zebra_evpn_acc_vl_show_hash, &wctx); @@ -1960,6 +2066,20 @@ static void zebra_evpn_mh_advertise_reach_neigh_only(void) */ } +/* On config of first local-ES turn on advertisement of local SVI-MAC */ +static void zebra_evpn_mh_advertise_svi_mac(void) +{ + if (zmh_info->flags & ZEBRA_EVPN_MH_ADV_SVI_MAC) + return; + + zmh_info->flags |= ZEBRA_EVPN_MH_ADV_SVI_MAC; + if (IS_ZEBRA_DEBUG_EVPN_MH_ES) + zlog_debug("evpn-mh: advertise SVI MAC"); + + /* walk through all SVIs and see if we need to advertise the MAC */ + zebra_evpn_acc_vl_adv_svi_mac_all(); +} + static int zebra_evpn_es_df_delay_exp_cb(struct thread *t) { struct zebra_evpn_es *es; @@ -1974,6 +2094,17 @@ static int zebra_evpn_es_df_delay_exp_cb(struct thread *t) return 0; } +/* currently there is no global config to turn on MH instead we use + * the addition of the first local Ethernet Segment as the trigger to + * init MH specific processing + */ +static void zebra_evpn_mh_on_first_local_es(void) +{ + zebra_evpn_mh_dup_addr_detect_off(); + zebra_evpn_mh_advertise_reach_neigh_only(); + zebra_evpn_mh_advertise_svi_mac(); +} + static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es, struct zebra_if *zif) { @@ -1984,8 +2115,7 @@ static void zebra_evpn_es_local_info_set(struct zebra_evpn_es *es, zlog_debug("local es %s add; nhg %u if %s", es->esi_str, es->nhg_id, zif->ifp->name); - zebra_evpn_mh_dup_addr_detect_off(); - zebra_evpn_mh_advertise_reach_neigh_only(); + zebra_evpn_mh_on_first_local_es(); es->flags |= ZEBRA_EVPNES_LOCAL; listnode_init(&es->local_es_listnode, es); diff --git a/zebra/zebra_evpn_mh.h b/zebra/zebra_evpn_mh.h index 81ae740d49..94de84ff14 100644 --- a/zebra/zebra_evpn_mh.h +++ b/zebra/zebra_evpn_mh.h @@ -180,6 +180,8 @@ struct zebra_evpn_access_bd { struct list *mbr_zifs; /* presence of zevpn activates the EVI on all the ESs in mbr_zifs */ zebra_evpn_t *zevpn; + /* SVI associated with the VLAN */ + struct zebra_if *vlan_zif; }; /* multihoming information stored in zrouter */ @@ -200,6 +202,10 @@ struct zebra_evpn_mh_info { * this flag when the first local ES is detected. */ #define ZEBRA_EVPN_MH_ADV_REACHABLE_NEIGH_ONLY (1 << 2) +/* If EVPN MH is enabled we advertise the SVI MAC address to avoid + * flooding of ARP replies rxed from the multi-homed host + */ +#define ZEBRA_EVPN_MH_ADV_SVI_MAC (1 << 3) /* RB tree of Ethernet segments (used for EVPN-MH) */ struct zebra_es_rb_head es_rb_tree; @@ -256,6 +262,12 @@ struct zebra_evpn_mh_info { enum protodown_reasons protodown_rc; }; +/* returns TRUE if the EVPN is ready to be sent to BGP */ +static inline bool zebra_evpn_send_to_client_ok(zebra_evpn_t *zevpn) +{ + return !!(zevpn->flags & ZEVPN_READY_FOR_BGP); +} + static inline bool zebra_evpn_mac_is_es_local(zebra_mac_t *mac) { return mac->es && (mac->es->flags & ZEBRA_EVPNES_LOCAL); @@ -285,6 +297,10 @@ static inline bool zebra_evpn_mh_do_adv_reachable_neigh_only(void) return !!(zmh_info->flags & ZEBRA_EVPN_MH_ADV_REACHABLE_NEIGH_ONLY); } +static inline bool zebra_evpn_mh_do_adv_svi_mac(void) +{ + return zmh_info && (zmh_info->flags & ZEBRA_EVPN_MH_ADV_SVI_MAC); +} /*****************************************************************************/ extern esi_t *zero_esi; @@ -357,5 +373,8 @@ extern bool zebra_evpn_is_es_bond_member(struct interface *ifp); extern void zebra_evpn_mh_print(struct vty *vty); extern void zebra_evpn_mh_json(json_object *json); extern void zebra_evpn_l2_nh_show(struct vty *vty, bool uj); +extern void zebra_evpn_acc_bd_svi_set(struct zebra_if *vlan_zif, + struct zebra_if *br_zif, bool is_up); +extern void zebra_evpn_acc_bd_svi_mac_add(struct interface *vlan_if); #endif /* _ZEBRA_EVPN_MH_H */ diff --git a/zebra/zebra_evpn_neigh.c b/zebra/zebra_evpn_neigh.c index 1f45b72e3a..834ad5381d 100644 --- a/zebra/zebra_evpn_neigh.c +++ b/zebra/zebra_evpn_neigh.c @@ -2464,7 +2464,7 @@ int zebra_evpn_neigh_del_ip(zebra_evpn_t *zevpn, struct ipaddr *ip) /* see if the AUTO mac needs to be deleted */ if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_AUTO) - && !listcount(zmac->neigh_list)) + && !zebra_evpn_mac_in_use(zmac)) zebra_evpn_mac_del(zevpn, zmac); return 0; diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 424c00d5eb..a4365e551f 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -3503,6 +3503,8 @@ void zebra_vxlan_print_evpn(struct vty *vty, bool uj) zvrf->advertise_gw_macip ? "Yes" : "No"); vty_out(vty, "Advertise svi mac-ip: %s\n", zvrf->advertise_svi_macip ? "Yes" : "No"); + vty_out(vty, "Advertise svi mac: %s\n", + zebra_evpn_mh_do_adv_svi_mac() ? "Yes" : "No"); vty_out(vty, "Duplicate address detection: %s\n", zebra_evpn_do_dup_addr_detect(zvrf) ? "Enable" : "Disable"); @@ -4493,6 +4495,16 @@ int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p, return -1; } + /* VRR IP is advertised only if gw-macip-adv-enabled */ + if (IS_ZEBRA_IF_MACVLAN(ifp)) { + if (!advertise_gw_macip_enabled(zevpn)) + return 0; + } else { + /* SVI IP is advertised if gw or svi macip-adv-enabled */ + if (!advertise_svi_macip_enabled(zevpn) + && !advertise_gw_macip_enabled(zevpn)) + return 0; + } memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); @@ -4539,10 +4551,14 @@ int zebra_vxlan_svi_down(struct interface *ifp, struct interface *link_if) } else { zebra_evpn_t *zevpn = NULL; + /* Unlink the SVI from the access VLAN */ + zebra_evpn_acc_bd_svi_set(ifp->info, link_if->info, false); + /* since we dont have svi corresponding to zevpn, we associate it * to default vrf. Note: the corresponding neigh entries on the * SVI would have already been deleted */ zevpn = zebra_evpn_from_svi(ifp, link_if); + if (zevpn) { zevpn->vrf_id = VRF_DEFAULT; @@ -4606,6 +4622,9 @@ int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if) n_wctx.zevpn = zevpn; hash_iterate(zevpn->neigh_table, zebra_evpn_install_neigh_hash, &n_wctx); + + /* Link the SVI from the access VLAN */ + zebra_evpn_acc_bd_svi_set(ifp->info, link_if->info, true); } return 0; |
