summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_nht.c5
-rw-r--r--bgpd/bgp_route.c4
-rw-r--r--bgpd/bgpd.c107
-rw-r--r--doc/user/ospfd.rst7
-rw-r--r--doc/user/overview.rst2
-rw-r--r--lib/mgmt_fe_client.c5
-rw-r--r--lib/mgmt_fe_client.h6
-rw-r--r--lib/routemap_northbound.c10
-rw-r--r--lib/vty.c6
-rw-r--r--lib/vty.h4
-rw-r--r--mgmtd/mgmt_fe_adapter.c8
-rw-r--r--mgmtd/mgmt_txn.c3
-rw-r--r--ospf6d/ospf6_flood.c4
-rw-r--r--ospf6d/ospf6_gr.c4
-rw-r--r--ospf6d/ospf6_gr_helper.c4
-rw-r--r--ospf6d/ospf6_lsa.c14
-rw-r--r--ospf6d/ospf6_lsa.h2
-rw-r--r--ospf6d/ospf6_lsdb.c10
-rw-r--r--ospf6d/ospf6_lsdb.h10
-rw-r--r--ospf6d/ospf6_message.c18
-rw-r--r--ospf6d/ospf6_neighbor.c3
-rw-r--r--ospfd/ospf_route.c4
-rw-r--r--ospfd/ospf_route.h2
-rw-r--r--ospfd/ospf_vty.c72
-rw-r--r--pimd/pim_ifchannel.c2
-rw-r--r--tests/lib/test_grpc.cpp10
-rw-r--r--tests/ospf6d/test_lsdb.c4
-rw-r--r--tests/topotests/babel_topo1/test_babel_topo1.py20
-rw-r--r--tests/topotests/bgp_route_map_on_match_next/__init__.py0
-rw-r--r--tests/topotests/bgp_route_map_on_match_next/r1/bgpd.conf10
-rw-r--r--tests/topotests/bgp_route_map_on_match_next/r1/zebra.conf6
-rw-r--r--tests/topotests/bgp_route_map_on_match_next/r2/bgpd.conf17
-rw-r--r--tests/topotests/bgp_route_map_on_match_next/r2/zebra.conf6
-rw-r--r--tests/topotests/bgp_route_map_on_match_next/test_bgp_route_map_on_match_next.py111
-rwxr-xr-xtests/topotests/conftest.py70
-rw-r--r--tests/topotests/lib/topotest.py105
-rw-r--r--tests/topotests/mgmt_config/r1/frr.conf15
-rw-r--r--tests/topotests/mgmt_config/test_regression.py53
-rw-r--r--tests/topotests/pytest.ini3
-rw-r--r--tools/etc/frr/support_bundle_commands.conf2
-rw-r--r--tools/frrinit.sh.in2
-rw-r--r--vtysh/vtysh.c8
-rw-r--r--vtysh/vtysh_config.c4
-rw-r--r--zebra/interface.c18
-rw-r--r--zebra/zebra_nhg.c16
-rw-r--r--zebra/zebra_rib.c7
-rw-r--r--zebra/zebra_routemap.c6
47 files changed, 627 insertions, 182 deletions
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c
index a46616803c..5a511eac1c 100644
--- a/bgpd/bgp_nht.c
+++ b/bgpd/bgp_nht.c
@@ -714,6 +714,11 @@ static void bgp_nht_ifp_table_handle(struct bgp *bgp,
{
struct bgp_nexthop_cache *bnc;
+ if (ifp->ifindex == IFINDEX_INTERNAL) {
+ zlog_warn("%s: The interface %s ignored", __func__, ifp->name);
+ return;
+ }
+
frr_each (bgp_nexthop_cache, table, bnc) {
if (bnc->ifindex != ifp->ifindex)
continue;
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 24be160656..c559be5c52 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -13834,11 +13834,11 @@ static int bgp_table_stats_single(struct vty *vty, struct bgp *bgp, afi_t afi,
json_bitlen = json_object_new_array();
for (i = 0; i <= bitlen; i++) {
- struct json_object *ind_bit = json_object_new_object();
-
if (!ts.prefix_len_count[i])
continue;
+ struct json_object *ind_bit = json_object_new_object();
+
snprintf(temp_buf, sizeof(temp_buf), "%u", i);
json_object_int_add(ind_bit, temp_buf,
ts.prefix_len_count[i]);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 5c97f90c55..00a5e190cb 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -5506,9 +5506,14 @@ int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi,
if (rmap) {
if (!peer->default_rmap[afi][safi].name
|| strcmp(rmap, peer->default_rmap[afi][safi].name) != 0) {
- if (peer->default_rmap[afi][safi].name)
+ struct route_map *map = NULL;
+
+ if (peer->default_rmap[afi][safi].name) {
+ map = route_map_lookup_by_name(
+ peer->default_rmap[afi][safi].name);
XFREE(MTYPE_ROUTE_MAP_NAME,
peer->default_rmap[afi][safi].name);
+ }
/*
* When there is a change in route-map policy,
@@ -5521,16 +5526,21 @@ int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi,
UNSET_FLAG(subgrp->sflags,
SUBGRP_STATUS_DEFAULT_ORIGINATE);
- route_map_counter_decrement(peer->default_rmap[afi][safi].map);
+ route_map_counter_decrement(map);
peer->default_rmap[afi][safi].name =
XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
peer->default_rmap[afi][safi].map = route_map;
route_map_counter_increment(route_map);
}
} else if (!rmap) {
- if (peer->default_rmap[afi][safi].name)
+ struct route_map *map = NULL;
+
+ if (peer->default_rmap[afi][safi].name) {
+ map = route_map_lookup_by_name(
+ peer->default_rmap[afi][safi].name);
XFREE(MTYPE_ROUTE_MAP_NAME,
peer->default_rmap[afi][safi].name);
+ }
/*
* This is triggered in case of route-map deletion.
@@ -5541,7 +5551,7 @@ int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi,
UNSET_FLAG(subgrp->sflags,
SUBGRP_STATUS_DEFAULT_ORIGINATE);
- route_map_counter_decrement(peer->default_rmap[afi][safi].map);
+ route_map_counter_decrement(map);
peer->default_rmap[afi][safi].name = NULL;
peer->default_rmap[afi][safi].map = NULL;
}
@@ -5573,11 +5583,16 @@ int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi,
SET_FLAG(member->af_flags[afi][safi],
PEER_FLAG_DEFAULT_ORIGINATE);
if (rmap) {
- if (member->default_rmap[afi][safi].name)
+ struct route_map *map = NULL;
+
+ if (member->default_rmap[afi][safi].name) {
+ map = route_map_lookup_by_name(
+ member->default_rmap[afi][safi].name);
XFREE(MTYPE_ROUTE_MAP_NAME,
member->default_rmap[afi][safi].name);
- route_map_counter_decrement(
- member->default_rmap[afi][safi].map);
+ }
+
+ route_map_counter_decrement(map);
member->default_rmap[afi][safi].name =
XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
member->default_rmap[afi][safi].map = route_map;
@@ -5611,13 +5626,18 @@ int peer_default_originate_unset(struct peer *peer, afi_t afi, safi_t safi)
PEER_ATTR_INHERIT(peer, peer->group,
default_rmap[afi][safi].map);
} else {
+ struct route_map *map = NULL;
+
/* Otherwise remove flag and configuration from peer. */
peer_af_flag_unset(peer, afi, safi,
PEER_FLAG_DEFAULT_ORIGINATE);
- if (peer->default_rmap[afi][safi].name)
+ if (peer->default_rmap[afi][safi].name) {
+ map = route_map_lookup_by_name(
+ peer->default_rmap[afi][safi].name);
XFREE(MTYPE_ROUTE_MAP_NAME,
peer->default_rmap[afi][safi].name);
- route_map_counter_decrement(peer->default_rmap[afi][safi].map);
+ }
+ route_map_counter_decrement(map);
peer->default_rmap[afi][safi].name = NULL;
peer->default_rmap[afi][safi].map = NULL;
}
@@ -5640,6 +5660,10 @@ int peer_default_originate_unset(struct peer *peer, afi_t afi, safi_t safi)
* they are explicitly overriding peer-group configuration.
*/
for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ struct route_map *map;
+
+ map = NULL;
+
/* Skip peers with overridden configuration. */
if (CHECK_FLAG(member->af_flags_override[afi][safi],
PEER_FLAG_DEFAULT_ORIGINATE))
@@ -5648,10 +5672,13 @@ int peer_default_originate_unset(struct peer *peer, afi_t afi, safi_t safi)
/* Remove flag and configuration on peer-group member. */
UNSET_FLAG(member->af_flags[afi][safi],
PEER_FLAG_DEFAULT_ORIGINATE);
- if (member->default_rmap[afi][safi].name)
+ if (member->default_rmap[afi][safi].name) {
+ map = route_map_lookup_by_name(
+ member->default_rmap[afi][safi].name);
XFREE(MTYPE_ROUTE_MAP_NAME,
member->default_rmap[afi][safi].name);
- route_map_counter_decrement(member->default_rmap[afi][safi].map);
+ }
+ route_map_counter_decrement(map);
member->default_rmap[afi][safi].name = NULL;
member->default_rmap[afi][safi].map = NULL;
@@ -7186,6 +7213,7 @@ int peer_route_map_set(struct peer *peer, afi_t afi, safi_t safi, int direct,
struct peer *member;
struct bgp_filter *filter;
struct listnode *node, *nnode;
+ struct route_map *map = NULL;
if (direct != RMAP_IN && direct != RMAP_OUT)
return BGP_ERR_INVALID_VALUE;
@@ -7199,9 +7227,10 @@ int peer_route_map_set(struct peer *peer, afi_t afi, safi_t safi, int direct,
if (strcmp(filter->map[direct].name, name) == 0)
return 0;
+ map = route_map_lookup_by_name(filter->map[direct].name);
XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name);
}
- route_map_counter_decrement(filter->map[direct].map);
+ route_map_counter_decrement(map);
filter->map[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
filter->map[direct].map = route_map;
route_map_counter_increment(route_map);
@@ -7223,6 +7252,7 @@ int peer_route_map_set(struct peer *peer, afi_t afi, safi_t safi, int direct,
* explicitly overriding peer-group configuration.
*/
for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ map = NULL;
/* Skip peers with overridden configuration. */
if (CHECK_FLAG(member->filter_override[afi][safi][direct],
PEER_FT_ROUTE_MAP))
@@ -7230,9 +7260,11 @@ int peer_route_map_set(struct peer *peer, afi_t afi, safi_t safi, int direct,
/* Set configuration on peer-group member. */
filter = &member->filter[afi][safi];
- if (filter->map[direct].name)
+ if (filter->map[direct].name) {
+ map = route_map_lookup_by_name(filter->map[direct].name);
XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name);
- route_map_counter_decrement(filter->map[direct].map);
+ }
+ route_map_counter_decrement(map);
filter->map[direct].name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
filter->map[direct].map = route_map;
route_map_counter_increment(route_map);
@@ -7265,11 +7297,16 @@ int peer_route_map_unset(struct peer *peer, afi_t afi, safi_t safi, int direct)
PEER_ATTR_INHERIT(peer, peer->group,
filter[afi][safi].map[direct].map);
} else {
+ struct route_map *map = NULL;
+
/* Otherwise remove configuration from peer. */
filter = &peer->filter[afi][safi];
- if (filter->map[direct].name)
+
+ if (filter->map[direct].name) {
+ map = route_map_lookup_by_name(filter->map[direct].name);
XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name);
- route_map_counter_decrement(filter->map[direct].map);
+ }
+ route_map_counter_decrement(map);
filter->map[direct].name = NULL;
filter->map[direct].map = NULL;
}
@@ -7289,6 +7326,10 @@ int peer_route_map_unset(struct peer *peer, afi_t afi, safi_t safi, int direct)
* explicitly overriding peer-group configuration.
*/
for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ struct route_map *map;
+
+ map = NULL;
+
/* Skip peers with overridden configuration. */
if (CHECK_FLAG(member->filter_override[afi][safi][direct],
PEER_FT_ROUTE_MAP))
@@ -7296,9 +7337,11 @@ int peer_route_map_unset(struct peer *peer, afi_t afi, safi_t safi, int direct)
/* Remove configuration on peer-group member. */
filter = &member->filter[afi][safi];
- if (filter->map[direct].name)
+ if (filter->map[direct].name) {
+ map = route_map_lookup_by_name(filter->map[direct].name);
XFREE(MTYPE_BGP_FILTER_NAME, filter->map[direct].name);
- route_map_counter_decrement(filter->map[direct].map);
+ }
+ route_map_counter_decrement(map);
filter->map[direct].name = NULL;
filter->map[direct].map = NULL;
@@ -7343,6 +7386,10 @@ int peer_unsuppress_map_set(struct peer *peer, afi_t afi, safi_t safi,
* explicitly overriding peer-group configuration.
*/
for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ struct route_map *map;
+
+ map = NULL;
+
/* Skip peers with overridden configuration. */
if (CHECK_FLAG(member->filter_override[afi][safi][0],
PEER_FT_UNSUPPRESS_MAP))
@@ -7350,9 +7397,11 @@ int peer_unsuppress_map_set(struct peer *peer, afi_t afi, safi_t safi,
/* Set configuration on peer-group member. */
filter = &member->filter[afi][safi];
- if (filter->usmap.name)
+ if (filter->usmap.name) {
+ map = route_map_lookup_by_name(filter->usmap.name);
XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
- route_map_counter_decrement(filter->usmap.map);
+ }
+ route_map_counter_decrement(map);
filter->usmap.name = XSTRDUP(MTYPE_BGP_FILTER_NAME, name);
filter->usmap.map = route_map;
route_map_counter_increment(route_map);
@@ -7382,11 +7431,15 @@ int peer_unsuppress_map_unset(struct peer *peer, afi_t afi, safi_t safi)
PEER_ATTR_INHERIT(peer, peer->group,
filter[afi][safi].usmap.map);
} else {
+ struct route_map *map = NULL;
+
/* Otherwise remove configuration from peer. */
filter = &peer->filter[afi][safi];
- if (filter->usmap.name)
+ if (filter->usmap.name) {
+ map = route_map_lookup_by_name(filter->usmap.name);
XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
- route_map_counter_decrement(filter->usmap.map);
+ }
+ route_map_counter_decrement(map);
filter->usmap.name = NULL;
filter->usmap.map = NULL;
}
@@ -7405,6 +7458,10 @@ int peer_unsuppress_map_unset(struct peer *peer, afi_t afi, safi_t safi)
* explicitly overriding peer-group configuration.
*/
for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ struct route_map *map;
+
+ map = NULL;
+
/* Skip peers with overridden configuration. */
if (CHECK_FLAG(member->filter_override[afi][safi][0],
PEER_FT_UNSUPPRESS_MAP))
@@ -7412,9 +7469,11 @@ int peer_unsuppress_map_unset(struct peer *peer, afi_t afi, safi_t safi)
/* Remove configuration on peer-group member. */
filter = &member->filter[afi][safi];
- if (filter->usmap.name)
+ if (filter->usmap.name) {
+ map = route_map_lookup_by_name(filter->usmap.name);
XFREE(MTYPE_BGP_FILTER_NAME, filter->usmap.name);
- route_map_counter_decrement(filter->usmap.map);
+ }
+ route_map_counter_decrement(map);
filter->usmap.name = NULL;
filter->usmap.map = NULL;
diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst
index 232b1c3934..4e30ef2aec 100644
--- a/doc/user/ospfd.rst
+++ b/doc/user/ospfd.rst
@@ -884,10 +884,11 @@ Showing Information
Show detailed information about the OSPF link-state database.
-.. clicmd:: show ip ospf route [json]
+.. clicmd:: show ip ospf route [detail] [json]
Show the OSPF routing table, as determined by the most recent SPF
- calculation.
+ calculation. When detail option is used, it shows more information
+ to the CLI like advertising router ID for each route, etc.
.. clicmd:: show ip ospf [vrf <NAME|all>] border-routers [json]
@@ -898,7 +899,7 @@ Showing Information
.. clicmd:: show ip ospf graceful-restart helper [detail] [json]
- Displays the Grcaeful Restart Helper details including helper
+ Displays the Graceful Restart Helper details including helper
config changes.
.. _opaque-lsa:
diff --git a/doc/user/overview.rst b/doc/user/overview.rst
index 33a1934628..a1cb0cc579 100644
--- a/doc/user/overview.rst
+++ b/doc/user/overview.rst
@@ -358,6 +358,8 @@ BGP
:t:`Outbound Route Filtering Capability. E. Chen, Y. Rekhter. August 2008.`
- :rfc:`5292`
:t:`Address-Prefix-Based Outbound Route Filter for BGP-4. E. Chen, S. Sangli. August 2008.`
+- :rfc:`5396`
+ :t:`Textual Representation of Autonomous System (AS) Numbers. G. Michaelson, G. Huston. December 2008.`
- :rfc:`5492`
:t:`Capabilities Advertisement with BGP-4. J. Scudder, R. Chandra. February 2009.`
- :rfc:`5575`
diff --git a/lib/mgmt_fe_client.c b/lib/mgmt_fe_client.c
index da19db463f..7e42e1c09e 100644
--- a/lib/mgmt_fe_client.c
+++ b/lib/mgmt_fe_client.c
@@ -629,6 +629,11 @@ uint mgmt_fe_client_session_count(struct mgmt_fe_client *client)
return mgmt_sessions_count(&client->sessions);
}
+bool mgmt_fe_client_current_msg_short_circuit(struct mgmt_fe_client *client)
+{
+ return client->client.conn.is_short_circuit;
+}
+
/*
* Create a new Session for a Frontend Client connection.
*/
diff --git a/lib/mgmt_fe_client.h b/lib/mgmt_fe_client.h
index 286141da44..349b7e4cf4 100644
--- a/lib/mgmt_fe_client.h
+++ b/lib/mgmt_fe_client.h
@@ -373,6 +373,12 @@ extern void mgmt_fe_client_destroy(struct mgmt_fe_client *client);
*/
extern uint mgmt_fe_client_session_count(struct mgmt_fe_client *client);
+/*
+ * True if the current handled message is being short-circuited
+ */
+extern bool
+mgmt_fe_client_current_msg_short_circuit(struct mgmt_fe_client *client);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/routemap_northbound.c b/lib/routemap_northbound.c
index 4659850994..5767e0aacf 100644
--- a/lib/routemap_northbound.c
+++ b/lib/routemap_northbound.c
@@ -353,6 +353,7 @@ static int
lib_route_map_entry_exit_policy_modify(struct nb_cb_modify_args *args)
{
struct route_map_index *rmi;
+ struct route_map *map;
int rm_action;
int policy;
@@ -382,6 +383,7 @@ lib_route_map_entry_exit_policy_modify(struct nb_cb_modify_args *args)
break;
case NB_EV_APPLY:
rmi = nb_running_get_entry(args->dnode, NULL, true);
+ map = rmi->map;
policy = yang_dnode_get_enum(args->dnode, NULL);
switch (policy) {
@@ -395,6 +397,14 @@ lib_route_map_entry_exit_policy_modify(struct nb_cb_modify_args *args)
rmi->exitpolicy = RMAP_GOTO;
break;
}
+
+ /* Execute event hook. */
+ if (route_map_master.event_hook) {
+ (*route_map_master.event_hook)(map->name);
+ route_map_notify_dependencies(map->name,
+ RMAP_EVENT_CALL_ADDED);
+ }
+
break;
}
diff --git a/lib/vty.c b/lib/vty.c
index c9de00a271..23aa2d1f38 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -3524,6 +3524,7 @@ static void vty_mgmt_ds_lock_notified(struct mgmt_fe_client *client,
char *errmsg_if_any)
{
struct vty *vty;
+ bool is_short_circuit = mgmt_fe_client_current_msg_short_circuit(client);
vty = (struct vty *)session_ctx;
@@ -3540,8 +3541,10 @@ static void vty_mgmt_ds_lock_notified(struct mgmt_fe_client *client,
vty->mgmt_locked_running_ds = lock_ds;
}
- if (vty->mgmt_req_pending_cmd)
+ if (!is_short_circuit && vty->mgmt_req_pending_cmd) {
+ assert(!strcmp(vty->mgmt_req_pending_cmd, "MESSAGE_LOCKDS_REQ"));
vty_mgmt_resume_response(vty, success);
+ }
}
static void vty_mgmt_set_config_result_notified(
@@ -3734,6 +3737,7 @@ int vty_mgmt_send_config_data(struct vty *vty, bool implicit_commit)
} else if (vty_mgmt_lock_running_inline(vty)) {
vty_out(vty,
"%% command failed, could not lock running DS\n");
+ vty_mgmt_unlock_candidate_inline(vty);
return -1;
}
}
diff --git a/lib/vty.h b/lib/vty.h
index ac3d2e5019..a8654f8b69 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -231,6 +231,10 @@ struct vty {
const char *mgmt_req_pending_cmd;
bool mgmt_locked_candidate_ds;
bool mgmt_locked_running_ds;
+ /* Need to track when we file-lock in vtysh to re-lock on end/conf t
+ * workaround
+ */
+ bool vtysh_file_locked;
};
static inline void vty_push_context(struct vty *vty, int node, uint64_t id)
diff --git a/mgmtd/mgmt_fe_adapter.c b/mgmtd/mgmt_fe_adapter.c
index c12d8646b1..2b2471c901 100644
--- a/mgmtd/mgmt_fe_adapter.c
+++ b/mgmtd/mgmt_fe_adapter.c
@@ -593,9 +593,8 @@ mgmt_fe_session_handle_lockds_req_msg(struct mgmt_fe_session_ctx *session,
}
if (lockds_req->lock) {
- if (mgmt_fe_session_write_lock_ds(lockds_req->ds_id,
- ds_ctx, session)
- != 0) {
+ if (mgmt_fe_session_write_lock_ds(lockds_req->ds_id, ds_ctx,
+ session)) {
fe_adapter_send_lockds_reply(
session, lockds_req->ds_id, lockds_req->req_id,
lockds_req->lock, false,
@@ -1160,8 +1159,7 @@ int mgmt_fe_send_set_cfg_reply(uint64_t session_id, uint64_t txn_id,
}
return fe_adapter_send_set_cfg_reply(session, ds_id, req_id,
- result == MGMTD_SUCCESS ? true
- : false,
+ result == MGMTD_SUCCESS,
error_if_any, implicit_commit);
}
diff --git a/mgmtd/mgmt_txn.c b/mgmtd/mgmt_txn.c
index eff3b7e34c..53b9b7df46 100644
--- a/mgmtd/mgmt_txn.c
+++ b/mgmtd/mgmt_txn.c
@@ -1380,8 +1380,7 @@ static int mgmt_txn_send_be_cfg_data(struct mgmt_txn_ctx *txn,
batch->batch_id,
cfg_req.cfgdata_reqs,
cfg_req.num_reqs,
- indx == num_batches ? true
- : false)) {
+ indx == num_batches)) {
(void)mgmt_txn_send_commit_cfg_reply(
txn, MGMTD_INTERNAL_ERROR,
"Internal Error! Could not send config data to backend!");
diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c
index a81d5222d6..fd5a4a426e 100644
--- a/ospf6d/ospf6_flood.c
+++ b/ospf6d/ospf6_flood.c
@@ -389,7 +389,7 @@ void ospf6_flood_interface(struct ospf6_neighbor *from, struct ospf6_lsa *lsa,
if (req == on->last_ls_req) {
/* sanity check refcount */
assert(req->lock >= 2);
- req = ospf6_lsa_unlock(req);
+ ospf6_lsa_unlock(&req);
on->last_ls_req = NULL;
}
if (req)
@@ -406,7 +406,7 @@ void ospf6_flood_interface(struct ospf6_neighbor *from, struct ospf6_lsa *lsa,
zlog_debug(
"Received is newer, remove requesting");
if (req == on->last_ls_req) {
- req = ospf6_lsa_unlock(req);
+ ospf6_lsa_unlock(&req);
on->last_ls_req = NULL;
}
if (req)
diff --git a/ospf6d/ospf6_gr.c b/ospf6d/ospf6_gr.c
index f39da91415..69230e572b 100644
--- a/ospf6d/ospf6_gr.c
+++ b/ospf6d/ospf6_gr.c
@@ -294,7 +294,7 @@ static int ospf6_router_lsa_contains_adj(struct ospf6_area *area,
continue;
if (lsdesc->neighbor_router_id == neighbor_router_id) {
- ospf6_lsa_unlock(lsa);
+ ospf6_lsa_unlock(&lsa);
return RTR_LSA_ADJ_FOUND;
}
}
@@ -514,7 +514,7 @@ static bool ospf6_gr_check_adjs(struct ospf6 *ospf6)
lsa_self)) {
found = true;
if (!ospf6_gr_check_adjs_lsa(area, lsa_self)) {
- ospf6_lsa_unlock(lsa_self);
+ ospf6_lsa_unlock(&lsa_self);
return false;
}
}
diff --git a/ospf6d/ospf6_gr_helper.c b/ospf6d/ospf6_gr_helper.c
index 216d78c1cc..8159ac0cd3 100644
--- a/ospf6d/ospf6_gr_helper.c
+++ b/ospf6d/ospf6_gr_helper.c
@@ -228,9 +228,9 @@ static bool ospf6_check_chg_in_rxmt_list(struct ospf6_neighbor *nbr)
lsa->header->adv_router, lsa->lsdb);
if (lsa_in_db && lsa_in_db->tobe_acknowledged) {
- ospf6_lsa_unlock(lsa);
+ ospf6_lsa_unlock(&lsa);
if (lsanext)
- ospf6_lsa_unlock(lsanext);
+ ospf6_lsa_unlock(&lsanext);
return OSPF6_TRUE;
}
diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c
index 2b806afe06..e745c6c577 100644
--- a/ospf6d/ospf6_lsa.c
+++ b/ospf6d/ospf6_lsa.c
@@ -797,17 +797,17 @@ struct ospf6_lsa *ospf6_lsa_lock(struct ospf6_lsa *lsa)
}
/* decrement reference counter of struct ospf6_lsa */
-struct ospf6_lsa *ospf6_lsa_unlock(struct ospf6_lsa *lsa)
+void ospf6_lsa_unlock(struct ospf6_lsa **lsa)
{
/* decrement reference counter */
- assert(lsa->lock > 0);
- lsa->lock--;
+ assert((*lsa)->lock > 0);
+ (*lsa)->lock--;
- if (lsa->lock != 0)
- return lsa;
+ if ((*lsa)->lock != 0)
+ return;
- ospf6_lsa_delete(lsa);
- return NULL;
+ ospf6_lsa_delete(*lsa);
+ *lsa = NULL;
}
diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h
index be7b94f3d3..c9ac27df88 100644
--- a/ospf6d/ospf6_lsa.h
+++ b/ospf6d/ospf6_lsa.h
@@ -239,7 +239,7 @@ extern void ospf6_lsa_delete(struct ospf6_lsa *lsa);
extern struct ospf6_lsa *ospf6_lsa_copy(struct ospf6_lsa *lsa);
extern struct ospf6_lsa *ospf6_lsa_lock(struct ospf6_lsa *lsa);
-extern struct ospf6_lsa *ospf6_lsa_unlock(struct ospf6_lsa *lsa);
+extern void ospf6_lsa_unlock(struct ospf6_lsa **lsa);
extern void ospf6_lsa_expire(struct event *thread);
extern void ospf6_lsa_refresh(struct event *thread);
diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c
index fa1a9a408d..355860f6b1 100644
--- a/ospf6d/ospf6_lsdb.c
+++ b/ospf6d/ospf6_lsdb.c
@@ -139,7 +139,7 @@ void ospf6_lsdb_add(struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb)
}
/* to free the lookup lock in node get*/
route_unlock_node(current);
- ospf6_lsa_unlock(old);
+ ospf6_lsa_unlock(&old);
}
ospf6_lsdb_count_assert(lsdb);
@@ -168,7 +168,7 @@ void ospf6_lsdb_remove(struct ospf6_lsa *lsa, struct ospf6_lsdb *lsdb)
route_unlock_node(node); /* to free the lookup lock */
route_unlock_node(node); /* to free the original lock */
- ospf6_lsa_unlock(lsa);
+ ospf6_lsa_unlock(&lsa);
ospf6_lsdb_count_assert(lsdb);
}
@@ -237,7 +237,7 @@ struct ospf6_lsa *ospf6_find_inter_prefix_lsa(struct ospf6 *ospf6,
ospf6_prefix_in6_addr(&prefix.u.prefix6, prefix_lsa,
&prefix_lsa->prefix);
if (prefix_same(p, &prefix)) {
- ospf6_lsa_unlock(lsa);
+ ospf6_lsa_unlock(&lsa);
return lsa;
}
}
@@ -328,7 +328,7 @@ struct ospf6_lsa *ospf6_lsdb_next(const struct route_node *iterend,
{
struct route_node *node = lsa->rn;
- ospf6_lsa_unlock(lsa);
+ ospf6_lsa_unlock(&lsa);
do
node = route_next_until(node, iterend);
@@ -361,7 +361,7 @@ void ospf6_lsdb_lsa_unlock(struct ospf6_lsa *lsa)
if (lsa != NULL) {
if (lsa->rn != NULL)
route_unlock_node(lsa->rn);
- ospf6_lsa_unlock(lsa);
+ ospf6_lsa_unlock(&lsa);
}
}
diff --git a/ospf6d/ospf6_lsdb.h b/ospf6d/ospf6_lsdb.h
index a2444f1c14..604406d75f 100644
--- a/ospf6d/ospf6_lsdb.h
+++ b/ospf6d/ospf6_lsdb.h
@@ -63,11 +63,11 @@ extern struct ospf6_lsa *ospf6_lsdb_next(const struct route_node *iterend,
* it really early.
*/
#define ALL_LSDB(lsdb, lsa, lsanext) \
- const struct route_node *iterend = \
- ospf6_lsdb_head(lsdb, 0, 0, 0, &lsa); \
- (lsa) != NULL && ospf6_lsa_lock(lsa) \
- && ((lsanext) = ospf6_lsdb_next(iterend, (lsa)), 1); \
- ospf6_lsa_unlock(lsa), (lsa) = (lsanext)
+ const struct route_node *iterend = ospf6_lsdb_head(lsdb, 0, 0, 0, \
+ &lsa); \
+ (lsa) != NULL && ospf6_lsa_lock(lsa) && \
+ ((lsanext) = ospf6_lsdb_next(iterend, (lsa)), 1); \
+ ospf6_lsa_unlock(&lsa), (lsa) = (lsanext)
extern void ospf6_lsdb_remove_all(struct ospf6_lsdb *lsdb);
extern void ospf6_lsdb_lsa_unlock(struct ospf6_lsa *lsa);
diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c
index cc00604f0a..e9b19ea0a6 100644
--- a/ospf6d/ospf6_message.c
+++ b/ospf6d/ospf6_message.c
@@ -2335,9 +2335,9 @@ static uint16_t ospf6_make_dbdesc(struct ospf6_neighbor *on, struct stream *s)
if ((length + sizeof(struct ospf6_lsa_header)
+ OSPF6_HEADER_SIZE)
> ospf6_packet_max(on->ospf6_if)) {
- ospf6_lsa_unlock(lsa);
+ ospf6_lsa_unlock(&lsa);
if (lsanext)
- ospf6_lsa_unlock(lsanext);
+ ospf6_lsa_unlock(&lsanext);
break;
}
stream_put(s, lsa->header,
@@ -2415,9 +2415,9 @@ void ospf6_dbdesc_send_newone(struct event *thread)
if (size + sizeof(struct ospf6_lsa_header)
> ospf6_packet_max(on->ospf6_if)) {
- ospf6_lsa_unlock(lsa);
+ ospf6_lsa_unlock(&lsa);
if (lsanext)
- ospf6_lsa_unlock(lsanext);
+ ospf6_lsa_unlock(&lsanext);
break;
}
@@ -2447,9 +2447,9 @@ static uint16_t ospf6_make_lsreq(struct ospf6_neighbor *on, struct stream *s)
for (ALL_LSDB(on->request_list, lsa, lsanext)) {
if ((length + OSPF6_HEADER_SIZE)
> ospf6_packet_max(on->ospf6_if)) {
- ospf6_lsa_unlock(lsa);
+ ospf6_lsa_unlock(&lsa);
if (lsanext)
- ospf6_lsa_unlock(lsanext);
+ ospf6_lsa_unlock(&lsanext);
break;
}
stream_putw(s, 0); /* reserved */
@@ -2462,7 +2462,7 @@ static uint16_t ospf6_make_lsreq(struct ospf6_neighbor *on, struct stream *s)
if (last_req != NULL) {
if (on->last_ls_req != NULL)
- on->last_ls_req = ospf6_lsa_unlock(on->last_ls_req);
+ ospf6_lsa_unlock(&on->last_ls_req);
ospf6_lsa_lock(last_req);
on->last_ls_req = last_req;
@@ -2944,9 +2944,9 @@ static uint16_t ospf6_make_lsack_interface(struct ospf6_interface *oi,
event_add_event(master, ospf6_lsack_send_interface, oi,
0, &oi->thread_send_lsack);
- ospf6_lsa_unlock(lsa);
+ ospf6_lsa_unlock(&lsa);
if (lsanext)
- ospf6_lsa_unlock(lsanext);
+ ospf6_lsa_unlock(&lsanext);
break;
}
ospf6_lsa_age_update_to_send(lsa, oi->transdelay);
diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c
index dc7abdd84c..e1aec06f8e 100644
--- a/ospf6d/ospf6_neighbor.c
+++ b/ospf6d/ospf6_neighbor.c
@@ -98,9 +98,10 @@ static void ospf6_neighbor_clear_ls_lists(struct ospf6_neighbor *on)
ospf6_lsdb_remove_all(on->summary_list);
if (on->last_ls_req) {
- ospf6_lsa_unlock(on->last_ls_req);
+ ospf6_lsa_unlock(&on->last_ls_req);
on->last_ls_req = NULL;
}
+
ospf6_lsdb_remove_all(on->request_list);
for (ALL_LSDB(on->retrans_list, lsa, lsanext)) {
ospf6_decrement_retrans_count(lsa);
diff --git a/ospfd/ospf_route.c b/ospfd/ospf_route.c
index cdb1eb0095..3ffa7c0bb1 100644
--- a/ospfd/ospf_route.c
+++ b/ospfd/ospf_route.c
@@ -48,6 +48,7 @@ struct ospf_route *ospf_route_new(void)
new->paths = list_new();
new->paths->del = (void (*)(void *))ospf_path_free;
+ new->u.std.transit = false;
return new;
}
@@ -500,6 +501,7 @@ void ospf_intra_add_transit(struct route_table *rt, struct vertex *v,
or->cost = v->distance;
or->type = OSPF_DESTINATION_NETWORK;
or->u.std.origin = (struct lsa_header *)lsa;
+ or->u.std.transit = true;
ospf_route_copy_nexthops_from_vertex(area, or, v);
@@ -851,7 +853,7 @@ void ospf_route_copy_nexthops_from_vertex(struct ospf_area *area,
|| area->spf_dry_run) {
path = ospf_path_new();
path->nexthop = nexthop->router;
- path->adv_router = v->id;
+ path->adv_router = v->lsa->adv_router;
if (oi) {
path->ifindex = oi->ifp->ifindex;
diff --git a/ospfd/ospf_route.h b/ospfd/ospf_route.h
index 7639a0049e..44e80216d7 100644
--- a/ospfd/ospf_route.h
+++ b/ospfd/ospf_route.h
@@ -69,6 +69,8 @@ struct route_standard {
/* */
uint8_t flags; /* From router-LSA */
+
+ bool transit; /* Transit network or not */
};
struct route_external {
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index 54fd60af23..a23802719b 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -10732,7 +10732,7 @@ static void config_write_stub_router(struct vty *vty, struct ospf *ospf)
static void show_ip_ospf_route_network(struct vty *vty, struct ospf *ospf,
struct route_table *rt,
- json_object *json)
+ json_object *json, bool detail)
{
struct route_node *rn;
struct ospf_route * or ;
@@ -10792,15 +10792,17 @@ static void show_ip_ospf_route_network(struct vty *vty, struct ospf *ospf,
if (json) {
json_object_string_add(json_route, "routeType",
"N");
+ json_object_boolean_add(json_route, "transit",
+ or->u.std.transit);
json_object_int_add(json_route, "cost",
or->cost);
json_object_string_addf(json_route, "area",
"%pI4",
&or->u.std.area_id);
} else {
- vty_out(vty, "N %-18s [%d] area: %pI4\n",
- buf1, or->cost,
- &or->u.std.area_id);
+ vty_out(vty, "N %s %-18s [%d] area: %pI4\n",
+ or->u.std.transit && detail ? "T" : " ",
+ buf1, or->cost, &or->u.std.area_id);
}
break;
default:
@@ -10857,6 +10859,11 @@ static void show_ip_ospf_route_network(struct vty *vty, struct ospf *ospf,
ifindex2ifname(
path->ifindex,
ospf->vrf_id));
+ json_object_string_addf(
+ json_nexthop,
+ "advertisedRouter",
+ "%pI4",
+ &path->adv_router);
} else {
vty_out(vty,
"%24s via %pI4, %s\n",
@@ -10866,6 +10873,11 @@ static void show_ip_ospf_route_network(struct vty *vty, struct ospf *ospf,
path->ifindex,
ospf->vrf_id));
}
+ if (detail && !json)
+ vty_out(vty,
+ "%24s adv %pI4\n",
+ "",
+ &path->adv_router);
}
}
}
@@ -11020,7 +11032,7 @@ static void show_ip_ospf_route_router(struct vty *vty, struct ospf *ospf,
static void show_ip_ospf_route_external(struct vty *vty, struct ospf *ospf,
struct route_table *rt,
- json_object *json)
+ json_object *json, bool detail)
{
struct route_node *rn;
struct ospf_route *er;
@@ -11124,6 +11136,11 @@ static void show_ip_ospf_route_external(struct vty *vty, struct ospf *ospf,
ifindex2ifname(
path->ifindex,
ospf->vrf_id));
+ json_object_string_addf(
+ json_nexthop,
+ "advertisedRouter",
+ "%pI4",
+ &path->adv_router);
} else {
vty_out(vty,
"%24s via %pI4, %s\n",
@@ -11133,6 +11150,10 @@ static void show_ip_ospf_route_external(struct vty *vty, struct ospf *ospf,
path->ifindex,
ospf->vrf_id));
}
+ if (detail && !json)
+ vty_out(vty,
+ "%24s adv %pI4\n", "",
+ &path->adv_router);
}
}
}
@@ -11419,7 +11440,8 @@ DEFUN (show_ip_ospf_instance_border_routers,
}
static int show_ip_ospf_route_common(struct vty *vty, struct ospf *ospf,
- json_object *json, uint8_t use_vrf)
+ json_object *json, uint8_t use_vrf,
+ bool detail)
{
json_object *json_vrf = NULL;
@@ -11446,8 +11468,15 @@ static int show_ip_ospf_route_common(struct vty *vty, struct ospf *ospf,
return CMD_SUCCESS;
}
+ if (detail && json == NULL) {
+ vty_out(vty, "Codes: N - network T - transitive\n");
+ vty_out(vty, " IA - inter-area E - external route\n");
+ vty_out(vty, " D - destination R - router\n\n");
+ }
+
/* Show Network routes. */
- show_ip_ospf_route_network(vty, ospf, ospf->new_table, json_vrf);
+ show_ip_ospf_route_network(vty, ospf, ospf->new_table, json_vrf,
+ detail);
/* Show Router routes. */
show_ip_ospf_route_router(vty, ospf, ospf->new_rtrs, json_vrf);
@@ -11458,7 +11487,7 @@ static int show_ip_ospf_route_common(struct vty *vty, struct ospf *ospf,
/* Show AS External routes. */
show_ip_ospf_route_external(vty, ospf, ospf->old_external_route,
- json_vrf);
+ json_vrf, detail);
if (json) {
if (use_vrf) {
@@ -11476,13 +11505,14 @@ static int show_ip_ospf_route_common(struct vty *vty, struct ospf *ospf,
DEFUN (show_ip_ospf_route,
show_ip_ospf_route_cmd,
- "show ip ospf [vrf <NAME|all>] route [json]",
+ "show ip ospf [vrf <NAME|all>] route [detail] [json]",
SHOW_STR
IP_STR
"OSPF information\n"
VRF_CMD_HELP_STR
"All VRFs\n"
"OSPF routing table\n"
+ "Detailed information\n"
JSON_STR)
{
struct ospf *ospf = NULL;
@@ -11491,14 +11521,19 @@ DEFUN (show_ip_ospf_route,
bool all_vrf = false;
int ret = CMD_SUCCESS;
int inst = 0;
+ int idx = 0;
int idx_vrf = 0;
uint8_t use_vrf = 0;
bool uj = use_json(argc, argv);
+ bool detail = false;
json_object *json = NULL;
if (uj)
json = json_object_new_object();
+ if (argv_find(argv, argc, "detail", &idx))
+ detail = true;
+
OSPF_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf);
/* vrf input is provided could be all or specific vrf*/
@@ -11512,8 +11547,8 @@ DEFUN (show_ip_ospf_route,
if (!ospf->oi_running)
continue;
ospf_output = true;
- ret = show_ip_ospf_route_common(vty, ospf, json,
- use_vrf);
+ ret = show_ip_ospf_route_common(
+ vty, ospf, json, use_vrf, detail);
}
if (uj) {
@@ -11550,7 +11585,8 @@ DEFUN (show_ip_ospf_route,
}
if (ospf) {
- ret = show_ip_ospf_route_common(vty, ospf, json, use_vrf);
+ ret = show_ip_ospf_route_common(vty, ospf, json, use_vrf,
+ detail);
/* Keep Non-pretty format */
if (uj)
vty_out(vty, "%s\n",
@@ -11566,16 +11602,22 @@ DEFUN (show_ip_ospf_route,
DEFUN (show_ip_ospf_instance_route,
show_ip_ospf_instance_route_cmd,
- "show ip ospf (1-65535) route",
+ "show ip ospf (1-65535) route [detail]",
SHOW_STR
IP_STR
"OSPF information\n"
"Instance ID\n"
- "OSPF routing table\n")
+ "OSPF routing table\n"
+ "Detailed information\n")
{
int idx_number = 3;
+ int idx = 0;
struct ospf *ospf;
unsigned short instance = 0;
+ bool detail = false;
+
+ if (argv_find(argv, argc, "detail", &idx))
+ detail = true;
instance = strtoul(argv[idx_number]->arg, NULL, 10);
if (instance != ospf_instance)
@@ -11585,7 +11627,7 @@ DEFUN (show_ip_ospf_instance_route,
if (!ospf || !ospf->oi_running)
return CMD_SUCCESS;
- return show_ip_ospf_route_common(vty, ospf, NULL, 0);
+ return show_ip_ospf_route_common(vty, ospf, NULL, 0, detail);
}
diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c
index bc6b84ff2c..da55189941 100644
--- a/pimd/pim_ifchannel.c
+++ b/pimd/pim_ifchannel.c
@@ -135,7 +135,7 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch)
* being inherited. So let's figure out what
* needs to be done here
*/
- if (!pim_addr_is_any(ch->sg.src) &&
+ if (!pim_addr_is_any(ch->sg.src) && ch->parent &&
pim_upstream_evaluate_join_desired_interface(
ch->upstream, ch, ch->parent))
pim_channel_add_oif(ch->upstream->channel_oil,
diff --git a/tests/lib/test_grpc.cpp b/tests/lib/test_grpc.cpp
index 87530d41d8..182c1d338d 100644
--- a/tests/lib/test_grpc.cpp
+++ b/tests/lib/test_grpc.cpp
@@ -34,8 +34,8 @@
#include <grpcpp/security/credentials.h>
#include "grpc/frr-northbound.grpc.pb.h"
-DEFINE_HOOK(frr_late_init, (struct event_loop * tm), (tm));
-DEFINE_KOOH(frr_fini, (), ());
+DEFINE_HOOK(test_grpc_late_init, (struct event_loop * tm), (tm));
+DEFINE_KOOH(test_grpc_fini, (), ());
struct vty *vty;
@@ -85,7 +85,7 @@ static void static_startup(void)
zprivs_init(&static_privs);
/* Load the server side module -- check libtool path first */
- std::string modpath = std::string(binpath) + std::string("../../../lib/.libs");
+ std::string modpath = std::string(binpath) + std::string("../../lib/.libs");
grpc_module = frrmod_load("grpc:50051", modpath.c_str(), 0, 0);
if (!grpc_module) {
modpath = std::string(binpath) + std::string("../../lib");
@@ -127,12 +127,12 @@ static void static_startup(void)
frr_pthread_init();
// frr_config_fork();
- hook_call(frr_late_init, master);
+ hook_call(test_grpc_late_init, master);
}
static void static_shutdown(void)
{
- hook_call(frr_fini);
+ hook_call(test_grpc_fini);
vty_close(vty);
vrf_terminate();
vty_terminate();
diff --git a/tests/ospf6d/test_lsdb.c b/tests/ospf6d/test_lsdb.c
index 4bc6e869b6..f9df73538a 100644
--- a/tests/ospf6d/test_lsdb.c
+++ b/tests/ospf6d/test_lsdb.c
@@ -59,7 +59,7 @@ DEFPY(lsa_set, lsa_set_cmd,
lsa_check_resize(idx + 1);
if (lsas[idx])
- ospf6_lsa_unlock(lsas[idx]);
+ ospf6_lsa_unlock(&lsas[idx]);
lsas[idx] = ospf6_lsa_create_headeronly(&hdr);
ospf6_lsa_lock(lsas[idx]);
return CMD_SUCCESS;
@@ -75,7 +75,7 @@ DEFPY(lsa_drop, lsa_drop_cmd,
return CMD_SUCCESS;
if (lsas[idx]->lock != 1)
vty_out(vty, "refcount at %u\n", lsas[idx]->lock);
- ospf6_lsa_unlock(lsas[idx]);
+ ospf6_lsa_unlock(&lsas[idx]);
lsas[idx] = NULL;
return CMD_SUCCESS;
}
diff --git a/tests/topotests/babel_topo1/test_babel_topo1.py b/tests/topotests/babel_topo1/test_babel_topo1.py
index 6a0297a7ee..decf0c2a6f 100644
--- a/tests/topotests/babel_topo1/test_babel_topo1.py
+++ b/tests/topotests/babel_topo1/test_babel_topo1.py
@@ -19,6 +19,7 @@ import re
import sys
import pytest
import json
+from functools import partial
pytestmark = [pytest.mark.babeld]
@@ -110,6 +111,17 @@ def test_converge_protocols():
topotest.sleep(10, "Waiting for BABEL convergence")
+def runit(router, assertmsg, cmd, expfile):
+ logger.info(expfile)
+
+ # Read expected result from file
+ expected = json.loads(open(expfile).read())
+
+ test_func = partial(topotest.router_json_cmp, router, cmd, expected)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, assertmsg
+
+
def test_zebra_ipv4_routingTable():
"Test 'show ip route'"
@@ -121,14 +133,12 @@ def test_zebra_ipv4_routingTable():
failures = 0
router_list = tgen.routers().values()
for router in router_list:
- output = router.vtysh_cmd("show ip route json", isjson=True)
- refTableFile = "{}/{}/show_ip_route.json_ref".format(CWD, router.name)
- expected = json.loads(open(refTableFile).read())
-
assertmsg = "Zebra IPv4 Routing Table verification failed for router {}".format(
router.name
)
- assert topotest.json_cmp(output, expected) is None, assertmsg
+ refTableFile = "{}/{}/show_ip_route.json_ref".format(CWD, router.name)
+ runit(router, assertmsg, "show ip route json", refTableFile)
+
def test_shutdown_check_stderr():
if os.environ.get("TOPOTESTS_CHECK_STDERR") is None:
diff --git a/tests/topotests/bgp_route_map_on_match_next/__init__.py b/tests/topotests/bgp_route_map_on_match_next/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_route_map_on_match_next/__init__.py
diff --git a/tests/topotests/bgp_route_map_on_match_next/r1/bgpd.conf b/tests/topotests/bgp_route_map_on_match_next/r1/bgpd.conf
new file mode 100644
index 0000000000..b858fffd81
--- /dev/null
+++ b/tests/topotests/bgp_route_map_on_match_next/r1/bgpd.conf
@@ -0,0 +1,10 @@
+!
+router bgp 65001
+ no bgp network import-check
+ neighbor 192.168.255.2 remote-as 65001
+ neighbor 192.168.255.2 timers 3 10
+ address-family ipv4 unicast
+ network 10.100.100.1/32
+ exit-address-family
+ !
+!
diff --git a/tests/topotests/bgp_route_map_on_match_next/r1/zebra.conf b/tests/topotests/bgp_route_map_on_match_next/r1/zebra.conf
new file mode 100644
index 0000000000..581e2e634f
--- /dev/null
+++ b/tests/topotests/bgp_route_map_on_match_next/r1/zebra.conf
@@ -0,0 +1,6 @@
+!
+interface r1-eth0
+ ip address 192.168.255.1/30
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_route_map_on_match_next/r2/bgpd.conf b/tests/topotests/bgp_route_map_on_match_next/r2/bgpd.conf
new file mode 100644
index 0000000000..518d63d692
--- /dev/null
+++ b/tests/topotests/bgp_route_map_on_match_next/r2/bgpd.conf
@@ -0,0 +1,17 @@
+!
+router bgp 65001
+ neighbor 192.168.255.1 remote-as 65001
+ neighbor 192.168.255.1 timers 3 10
+ address-family ipv4 unicast
+ neighbor 192.168.255.1 route-map RM in
+ exit-address-family
+ !
+!
+route-map RM permit 10
+ set weight 100
+exit
+!
+route-map RM permit 20
+ set metric 20
+exit
+!
diff --git a/tests/topotests/bgp_route_map_on_match_next/r2/zebra.conf b/tests/topotests/bgp_route_map_on_match_next/r2/zebra.conf
new file mode 100644
index 0000000000..fd45c48d6d
--- /dev/null
+++ b/tests/topotests/bgp_route_map_on_match_next/r2/zebra.conf
@@ -0,0 +1,6 @@
+!
+interface r2-eth0
+ ip address 192.168.255.2/30
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_route_map_on_match_next/test_bgp_route_map_on_match_next.py b/tests/topotests/bgp_route_map_on_match_next/test_bgp_route_map_on_match_next.py
new file mode 100644
index 0000000000..8fe45a3498
--- /dev/null
+++ b/tests/topotests/bgp_route_map_on_match_next/test_bgp_route_map_on_match_next.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+
+#
+# test_bgp_route_map_on_match_next.py
+#
+# Copyright (c) 2023 Rubicon Communications, LLC.
+#
+
+"""
+Test whether `on-match next` added to an existing route-map entry takes effect.
+"""
+
+import os
+import sys
+import json
+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
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ for routern in range(1, 3):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_route_map_on_match_next():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+
+ def _bgp_converge(router):
+ output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json"))
+ expected = {"192.168.255.1": {"bgpState": "Established"}}
+ return topotest.json_cmp(output, expected)
+
+ def _bgp_has_routes(router, metric, weight):
+ output = json.loads(
+ router.vtysh_cmd("show ip bgp neighbor 192.168.255.1 routes json")
+ )
+ expected = {
+ "routes": {"10.100.100.1/32": [{"metric": metric, "weight": weight}]}
+ }
+ return topotest.json_cmp(output, expected)
+
+ # Check thst session is established
+ test_func = functools.partial(_bgp_converge, router2)
+ success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+ assert result is None, "Failed bgp convergence on r2"
+
+ # Check that metric is 0 and weight is 100 for the received prefix
+ test_func = functools.partial(_bgp_has_routes, router2, 0, 100)
+ success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+ assert result is None, "r2 does not receive routes with metric 0 and weight 100"
+
+ # Update the route-map and add "on-match next" to entry 10
+ cmd = """
+ configure terminal
+ route-map RM permit 10
+ on-match next
+ exit
+ """
+ router2.vtysh_cmd(cmd)
+
+ # Check that metric is 20 and weight is 100 for the received prefix
+ test_func = functools.partial(_bgp_has_routes, router2, 20, 100)
+ success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+ assert result is None, "r2 does not receive routes with metric 20 and weight 100"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/conftest.py b/tests/topotests/conftest.py
index f829ed2d12..0afebde1cf 100755
--- a/tests/topotests/conftest.py
+++ b/tests/topotests/conftest.py
@@ -298,49 +298,53 @@ def check_for_memleaks():
def check_for_core_dumps():
- dumps = []
tgen = get_topogen() # pylint: disable=redefined-outer-name
- latest = []
+ if not tgen:
+ return
- if tgen is not None:
- logdir = tgen.logdir
- cores = glob.glob(os.path.join(logdir, "*/*.dmp"))
+ if not hasattr(tgen, "existing_core_files"):
+ tgen.existing_core_files = set()
+ existing = tgen.existing_core_files
- if cores:
- logger.error("Cores found:\n\t%s", "\n\t".join(cores))
- pytest.fail("Core files found")
+ cores = glob.glob(os.path.join(tgen.logdir, "*/*.dmp"))
+ latest = {x for x in cores if x not in existing}
+ if latest:
+ existing |= latest
+ tgen.existing_core_files = existing
+
+ emsg = "New core[s] found: " + ", ".join(latest)
+ logger.error(emsg)
+ pytest.fail(emsg)
def check_for_backtraces():
- backtraces = []
tgen = get_topogen() # pylint: disable=redefined-outer-name
- latest = []
- existing = []
- if tgen is not None:
- logdir = tgen.logdir
- if hasattr(tgen, "backtraces_existing_files"):
- existing = tgen.backtraces_existing_files
- latest = glob.glob(os.path.join(logdir, "*/*.log"))
+ if not tgen:
+ return
- daemons = []
+ if not hasattr(tgen, "existing_backtrace_files"):
+ tgen.existing_backtrace_files = {}
+ existing = tgen.existing_backtrace_files
+
+ latest = glob.glob(os.path.join(tgen.logdir, "*/*.log"))
+ backtraces = []
for vfile in latest:
- if vfile in existing:
- continue
with open(vfile, encoding="ascii") as vf:
vfcontent = vf.read()
- backtrace = vfcontent.count("Backtrace:")
- if backtrace:
- existing.append(vfile) # have backtrace don't check again
- emsg = "Backtrace found in {}, failing test".format(vfile)
- backtraces.append(emsg)
-
- if tgen is not None:
- tgen.backtrace_existing_files = existing
+ btcount = vfcontent.count("Backtrace:")
+ if not btcount:
+ continue
+ if vfile not in existing:
+ existing[vfile] = 0
+ if btcount == existing[vfile]:
+ continue
+ existing[vfile] = btcount
+ backtraces.append(vfile)
if backtraces:
- logger.error("Backtraces found in test suite, erroring")
- logger.error(backtraces)
- pytest.fail("Backtraces found")
+ emsg = "New backtraces found in: " + ", ".join(backtraces)
+ logger.error(emsg)
+ pytest.fail(emsg)
@pytest.fixture(autouse=True, scope="module")
@@ -366,8 +370,6 @@ def module_check_memtest(request):
if request.config.option.memleaks:
if get_topogen() is not None:
check_for_memleaks()
- check_for_backtraces()
- check_for_core_dumps()
#
@@ -397,9 +399,13 @@ def pytest_runtest_call(item: pytest.Item) -> None:
# Let the default pytest_runtest_call execute the test function
yield
+ check_for_backtraces()
+ check_for_core_dumps()
+
# Check for leaks if requested
if item.config.option.valgrind_memleaks:
check_for_valgrind_memleaks()
+
if item.config.option.memleaks:
check_for_memleaks()
diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py
index 7371230057..da24b45297 100644
--- a/tests/topotests/lib/topotest.py
+++ b/tests/topotests/lib/topotest.py
@@ -44,33 +44,89 @@ def get_logs_path(rundir):
def gdb_core(obj, daemon, corefiles):
- gdbcmds = """
- info threads
- bt full
- disassemble
- up
- disassemble
- up
- disassemble
- up
- disassemble
- up
- disassemble
- up
- disassemble
+ gdbcmds = r"""
+set print elements 1024
+echo -------\n
+echo threads\n
+echo -------\n
+info threads
+echo ---------\n
+echo registers\n
+echo ---------\n
+info registers
+echo ---------\n
+echo backtrace\n
+echo ---------\n
+bt
"""
gdbcmds = [["-ex", i.strip()] for i in gdbcmds.strip().split("\n")]
gdbcmds = [item for sl in gdbcmds for item in sl]
daemon_path = os.path.join(obj.daemondir, daemon)
- backtrace = subprocess.check_output(
- ["gdb", daemon_path, corefiles[0], "--batch"] + gdbcmds
+ p = subprocess.run(
+ ["gdb", daemon_path, corefiles[0], "--batch"] + gdbcmds,
+ encoding="utf-8",
+ errors="ignore",
+ capture_output=True,
)
+ backtrace = p.stdout
+
+ #
+ # Grab the disassemble of top couple frames
+ #
+ m = re.search(r"#(\d+) .*assert.*", backtrace)
+ if not m:
+ m = re.search(r"#(\d+) .*abort.*", backtrace)
+ frames = re.findall(r"\n#(\d+) ", backtrace)
+ if m:
+ frstart = -1
+ astart = int(m.group(1)) + 1
+ ocount = f"-{int(frames[-1]) - astart + 1}"
+ else:
+ astart = -1
+ frstart = 0
+ ocount = ""
+ m = re.search(r"#(\d+) .*core_handler.*", backtrace)
+ if m:
+ frstart = int(m.group(1)) + 2
+ ocount = f"-{int(frames[-1]) - frstart + 1}"
+
sys.stderr.write(
- "\n%s: %s crashed. Core file found - Backtrace follows:\n" % (obj.name, daemon)
+ f"\nCORE FOUND: {obj.name}: {daemon} crashed: see log for backtrace and more\n"
)
- sys.stderr.write("%s" % backtrace)
- return backtrace
+
+ gdbcmds = rf"""
+set print elements 1024
+echo -------------------------\n
+echo backtrace with local args\n
+echo -------------------------\n
+bt full {ocount}
+"""
+ if frstart >= 0:
+ gdbcmds += rf"""echo ---------------------------------------\n
+echo disassemble of failing funciton (guess)\n
+echo ---------------------------------------\n
+fr {frstart}
+disassemble /m
+"""
+
+ gdbcmds = [["-ex", i.strip()] for i in gdbcmds.strip().split("\n")]
+ gdbcmds = [item for sl in gdbcmds for item in sl]
+
+ daemon_path = os.path.join(obj.daemondir, daemon)
+ p = subprocess.run(
+ ["gdb", daemon_path, corefiles[0], "-q", "--batch"] + gdbcmds,
+ encoding="utf-8",
+ errors="ignore",
+ capture_output=True,
+ )
+ btdump = p.stdout
+
+ # sys.stderr.write(
+ # "\n%s: %s crashed. Core file found - Backtrace follows:\n" % (obj.name, daemon)
+ # )
+
+ return backtrace + btdump
class json_cmp_result(object):
@@ -1189,8 +1245,8 @@ def rlimit_atleast(rname, min_value, raises=False):
def fix_netns_limits(ns):
# Maximum read and write socket buffer sizes
- sysctl_atleast(ns, "net.ipv4.tcp_rmem", [10 * 1024, 87380, 16 * 2 ** 20])
- sysctl_atleast(ns, "net.ipv4.tcp_wmem", [10 * 1024, 87380, 16 * 2 ** 20])
+ sysctl_atleast(ns, "net.ipv4.tcp_rmem", [10 * 1024, 87380, 16 * 2**20])
+ sysctl_atleast(ns, "net.ipv4.tcp_wmem", [10 * 1024, 87380, 16 * 2**20])
sysctl_assure(ns, "net.ipv4.conf.all.rp_filter", 0)
sysctl_assure(ns, "net.ipv4.conf.default.rp_filter", 0)
@@ -1249,8 +1305,8 @@ def fix_host_limits():
sysctl_atleast(None, "net.core.netdev_max_backlog", 4 * 1024)
# Maximum read and write socket buffer sizes
- sysctl_atleast(None, "net.core.rmem_max", 16 * 2 ** 20)
- sysctl_atleast(None, "net.core.wmem_max", 16 * 2 ** 20)
+ sysctl_atleast(None, "net.core.rmem_max", 16 * 2**20)
+ sysctl_atleast(None, "net.core.wmem_max", 16 * 2**20)
# Garbage Collection Settings for ARP and Neighbors
sysctl_atleast(None, "net.ipv4.neigh.default.gc_thresh2", 4 * 1024)
@@ -2088,8 +2144,7 @@ class Router(Node):
backtrace = gdb_core(self, daemon, corefiles)
traces = (
traces
- + "\n%s: %s crashed. Core file found - Backtrace follows:\n%s"
- % (self.name, daemon, backtrace)
+ + f"\nCORE FOUND: {self.name}: {daemon} crashed. Backtrace follows:\n{backtrace}"
)
reportMade = True
elif reportLeaks:
diff --git a/tests/topotests/mgmt_config/r1/frr.conf b/tests/topotests/mgmt_config/r1/frr.conf
new file mode 100644
index 0000000000..076715c068
--- /dev/null
+++ b/tests/topotests/mgmt_config/r1/frr.conf
@@ -0,0 +1,15 @@
+debug northbound notifications
+! debug northbound libyang
+debug northbound events
+debug northbound callbacks
+debug mgmt backend datastore frontend transaction
+debug mgmt client backend
+debug mgmt client frontend
+
+log timestamp precision 6
+log file frr.log debug
+
+interface r1-eth0
+ ip address 101.0.0.1/24
+ ipv6 address 2101::1/64
+exit \ No newline at end of file
diff --git a/tests/topotests/mgmt_config/test_regression.py b/tests/topotests/mgmt_config/test_regression.py
new file mode 100644
index 0000000000..00c3e01724
--- /dev/null
+++ b/tests/topotests/mgmt_config/test_regression.py
@@ -0,0 +1,53 @@
+# -*- coding: utf-8 eval: (blacken-mode 1) -*-
+# SPDX-License-Identifier: ISC
+#
+# July 13 2023, Christian Hopps <chopps@labn.net>
+#
+# Copyright (c) 2023, LabN Consulting, L.L.C.
+#
+"""
+Test mgmtd regressions
+
+"""
+import pytest
+from lib.topogen import Topogen
+
+pytestmark = [pytest.mark.staticd]
+
+
+@pytest.fixture(scope="module")
+def tgen(request):
+ "Setup/Teardown the environment and provide tgen argument to tests"
+
+ topodef = {"s1": ("r1",)}
+ tgen = Topogen(topodef, request.module.__name__)
+ tgen.start_topology()
+ tgen.gears["r1"].load_frr_config("frr.conf")
+ tgen.start_router()
+ yield tgen
+ tgen.stop_topology()
+
+
+def test_regression_issue_13920(tgen):
+ """Issue #13920
+
+ ubuntu2204# conf t
+ ubuntu2204(config)# ip route 3.2.4.0/24 6.5.5.11 loop3
+ ubuntu2204(config)# nexthop-group nh2
+ ubuntu2204(config-nh-group)# nexthop 6.5.5.12
+ ubuntu2204(config-nh-group)# exi
+ ubuntu2204(config)# ip route 3.22.4.0/24 6.5.5.12
+ crash
+ """
+
+ r1 = tgen.gears["r1"]
+ r1.vtysh_multicmd(
+ """
+ conf t
+ nexthop-group nh2
+ exit
+ ip route 3.22.4.0/24 6.5.5.12
+ """
+ )
+ output = r1.net.checkRouterCores()
+ assert not output.strip()
diff --git a/tests/topotests/pytest.ini b/tests/topotests/pytest.ini
index 0062cf3de2..6c2d42ef40 100644
--- a/tests/topotests/pytest.ini
+++ b/tests/topotests/pytest.ini
@@ -6,7 +6,8 @@
# We always turn this on inside conftest.py, default shown
# addopts = --junitxml=<rundir>/topotests.xml
-log_level = DEBUG
+# This affects what gets dumped to the screen on test failure
+log_level = ERROR
log_format = %(asctime)s,%(msecs)03d %(levelname)s: %(name)s: %(message)s
log_date_format = %Y-%m-%d %H:%M:%S
diff --git a/tools/etc/frr/support_bundle_commands.conf b/tools/etc/frr/support_bundle_commands.conf
index 914363157a..a727f86a03 100644
--- a/tools/etc/frr/support_bundle_commands.conf
+++ b/tools/etc/frr/support_bundle_commands.conf
@@ -68,6 +68,8 @@ show ip nht vrf all
show ipv6 nht vrf all
show ip route vrf all
show ipv6 route vrf all
+show ip fib
+show ipv6 fib
show nexthop-group rib
show route-map
show memory
diff --git a/tools/frrinit.sh.in b/tools/frrinit.sh.in
index 42adefb9ea..428d57c55b 100644
--- a/tools/frrinit.sh.in
+++ b/tools/frrinit.sh.in
@@ -123,7 +123,7 @@ reload)
NEW_CONFIG_FILE="${2:-$C_PATH/frr.conf}"
[ ! -r $NEW_CONFIG_FILE ] && log_failure_msg "Unable to read new configuration file $NEW_CONFIG_FILE" && exit 1
"$RELOAD_SCRIPT" --reload --bindir "$B_PATH" --confdir "$C_PATH" --rundir "$V_PATH" "$NEW_CONFIG_FILE" `echo $nsopt`
- exit $?
+ exit 0
;;
*)
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index ee52a98adb..8b223d1aa4 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -2356,8 +2356,14 @@ static int vtysh_exit(struct vty *vty)
if (vty->node == CONFIG_NODE) {
/* resync in case one of the daemons is somewhere else */
vtysh_execute("end");
- vtysh_execute("configure terminal file-lock");
+ /* NOTE: a rather expensive thing to do, can we avoid it? */
+
+ if (vty->vtysh_file_locked)
+ vtysh_execute("configure terminal file-lock");
+ else
+ vtysh_execute("configure terminal");
}
+
return CMD_SUCCESS;
}
diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c
index a5f790bbc6..593de7ffbc 100644
--- a/vtysh/vtysh_config.c
+++ b/vtysh/vtysh_config.c
@@ -607,7 +607,8 @@ static int vtysh_read_file(FILE *confp, bool dry_run)
vty->node = CONFIG_NODE;
vtysh_execute_no_pager("enable");
- vtysh_execute_no_pager("configure terminal file-lock");
+ vtysh_execute_no_pager("conf term file-lock");
+ vty->vtysh_file_locked = true;
if (!dry_run)
vtysh_execute_no_pager("XFRR_start_configuration");
@@ -619,6 +620,7 @@ static int vtysh_read_file(FILE *confp, bool dry_run)
vtysh_execute_no_pager("XFRR_end_configuration");
vtysh_execute_no_pager("end");
+ vty->vtysh_file_locked = false;
vtysh_execute_no_pager("disable");
vty_close(vty);
diff --git a/zebra/interface.c b/zebra/interface.c
index 989763d13c..4006f9c574 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -787,6 +787,15 @@ void if_delete_update(struct interface **pifp)
/* Delete connected routes from the kernel. */
if_delete_connected(ifp);
+ /* if the ifp is in a vrf, move it to default so vrf can be deleted if
+ * desired. This operation is not done for netns implementation to avoid
+ * collision with interface with the same name in the default vrf (can
+ * occur with this implementation whereas it is not possible with
+ * vrf-lite).
+ */
+ if (ifp->vrf->vrf_id && !vrf_is_backend_netns())
+ if_handle_vrf_change(ifp, VRF_DEFAULT);
+
/* Send out notification on interface delete. */
zebra_interface_delete_update(ifp);
@@ -800,15 +809,6 @@ void if_delete_update(struct interface **pifp)
if_set_index(ifp, IFINDEX_INTERNAL);
ifp->node = NULL;
- /* if the ifp is in a vrf, move it to default so vrf can be deleted if
- * desired. This operation is not done for netns implementation to avoid
- * collision with interface with the same name in the default vrf (can
- * occur with this implementation whereas it is not possible with
- * vrf-lite).
- */
- if (ifp->vrf->vrf_id && !vrf_is_backend_netns())
- if_handle_vrf_change(ifp, VRF_DEFAULT);
-
UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK);
/* Reset some zebra interface params to default values. */
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index bb507893b0..977ea425d5 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -2366,17 +2366,18 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe,
if (is_default_prefix(&rn->p)
&& !rnh_resolve_via_default(zvrf, p.family)) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug(
- " :%s: Resolved against default route",
- __func__);
+ zlog_debug(" :%s: %pFX Resolved against default route",
+ __func__, &p);
return 0;
}
dest = rib_dest_from_rnode(rn);
- if (dest && dest->selected_fib
- && !CHECK_FLAG(dest->selected_fib->status,
- ROUTE_ENTRY_REMOVED)
- && dest->selected_fib->type != ZEBRA_ROUTE_TABLE)
+ if (dest && dest->selected_fib &&
+ (!CHECK_FLAG(dest->selected_fib->status,
+ ROUTE_ENTRY_REMOVED) ||
+ CHECK_FLAG(dest->selected_fib->status,
+ ROUTE_ENTRY_ROUTE_REPLACING)) &&
+ dest->selected_fib->type != ZEBRA_ROUTE_TABLE)
match = dest->selected_fib;
/* If there is no selected route or matched route is EGP, go up
@@ -2388,7 +2389,6 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe,
} while (rn && rn->info == NULL);
if (rn)
route_lock_node(rn);
-
continue;
}
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 93b33c9abd..a5e036fe48 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -2824,8 +2824,13 @@ static void process_subq_early_route_add(struct zebra_early_route *ere)
rib_addnode(rn, re, 1);
/* Free implicit route.*/
- if (same)
+ if (same) {
+ rib_dest_t *dest = rn->info;
+
+ if (same == dest->selected_fib)
+ SET_FLAG(same->status, ROUTE_ENTRY_ROUTE_REPLACING);
rib_delnode(rn, same);
+ }
/* See if we can remove some RE entries that are queued for
* removal, but won't be considered in rib processing.
diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c
index 142501b149..eb94e26c30 100644
--- a/zebra/zebra_routemap.c
+++ b/zebra/zebra_routemap.c
@@ -367,7 +367,7 @@ static int ip_nht_rm_add(struct zebra_vrf *zvrf, const char *rmap, int rtype,
route_map_counter_increment(NHT_RM_MAP(zvrf, afi, rtype));
if (NHT_RM_MAP(zvrf, afi, rtype))
- zebra_evaluate_rnh(zvrf, AFI_IP, 1, NULL, SAFI_UNICAST);
+ zebra_evaluate_rnh(zvrf, afi, 1, NULL, SAFI_UNICAST);
return CMD_SUCCESS;
}
@@ -388,7 +388,7 @@ static int ip_nht_rm_del(struct zebra_vrf *zvrf, const char *rmap, int rtype,
zvrf->vrf->vrf_id, rtype);
NHT_RM_MAP(zvrf, afi, rtype) = NULL;
- zebra_evaluate_rnh(zvrf, AFI_IP, 1, NULL, SAFI_UNICAST);
+ zebra_evaluate_rnh(zvrf, afi, 1, NULL, SAFI_UNICAST);
}
XFREE(MTYPE_ROUTE_MAP_NAME, NHT_RM_NAME(zvrf, afi, rtype));
}
@@ -1703,7 +1703,7 @@ static void zebra_nht_rm_update(const char *rmap)
afi_ipv6 = 1;
zebra_evaluate_rnh(
- zvrf, AFI_IP, 1, NULL,
+ zvrf, AFI_IP6, 1, NULL,
SAFI_UNICAST);
}
}