summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/conflicts.yml21
-rw-r--r--babeld/babel_zebra.c2
-rw-r--r--bfdd/bfdd_vty.c2
-rw-r--r--bgpd/bgp_attr.h8
-rw-r--r--bgpd/bgp_community.h27
-rw-r--r--bgpd/bgp_debug.c45
-rw-r--r--bgpd/bgp_debug.h3
-rw-r--r--bgpd/bgp_fsm.c3
-rw-r--r--bgpd/bgp_fsm.h2
-rw-r--r--bgpd/bgp_memory.c4
-rw-r--r--bgpd/bgp_memory.h2
-rw-r--r--bgpd/bgp_mplsvpn.c204
-rw-r--r--bgpd/bgp_mplsvpn.h5
-rw-r--r--bgpd/bgp_network.c26
-rw-r--r--bgpd/bgp_nexthop.c16
-rw-r--r--bgpd/bgp_nht.c3
-rw-r--r--bgpd/bgp_orr.c1176
-rw-r--r--bgpd/bgp_orr.h102
-rw-r--r--bgpd/bgp_route.c234
-rw-r--r--bgpd/bgp_route.h5
-rw-r--r--bgpd/bgp_rpki.c4
-rw-r--r--bgpd/bgp_table.h1
-rw-r--r--bgpd/bgp_updgrp_adv.c5
-rw-r--r--bgpd/bgp_vty.c224
-rw-r--r--bgpd/bgp_zebra.c57
-rw-r--r--bgpd/bgpd.c120
-rw-r--r--bgpd/bgpd.h68
-rw-r--r--bgpd/subdir.am2
-rw-r--r--configure.ac1
-rw-r--r--doc/user/bgp.rst341
-rw-r--r--doc/user/isisd.rst4
-rw-r--r--doc/user/ospfd.rst53
-rw-r--r--doc/user/zebra.rst2
-rw-r--r--eigrpd/eigrp_dump.c1
-rw-r--r--isisd/isis_cli.c41
-rw-r--r--isisd/isis_lsp.c31
-rw-r--r--isisd/isis_lsp.h1
-rw-r--r--isisd/isis_nb.c13
-rw-r--r--isisd/isis_nb.h6
-rw-r--r--isisd/isis_nb_config.c24
-rw-r--r--isisd/isisd.c115
-rw-r--r--isisd/isisd.h10
-rw-r--r--ldpd/ldp_vty_cmds.c6
-rw-r--r--lib/command.c6
-rw-r--r--lib/command.h7
-rw-r--r--lib/frrscript.c28
-rw-r--r--lib/frrscript.h5
-rw-r--r--lib/libfrr.c4
-rw-r--r--lib/orr_msg.h94
-rw-r--r--lib/routemap.c6
-rw-r--r--lib/routemap.h2
-rw-r--r--lib/sockopt.c49
-rw-r--r--lib/sockopt.h22
-rw-r--r--lib/subdir.am1
-rw-r--r--lib/typesafe.h9
-rw-r--r--lib/zclient.h6
-rw-r--r--nhrpd/nhrp_vty.c2
-rw-r--r--ospf6d/ospf6d.c2
-rw-r--r--ospfd/ospf_dump.c489
-rw-r--r--ospfd/ospf_dump.h5
-rw-r--r--ospfd/ospf_interface.c11
-rw-r--r--ospfd/ospf_lsa.c97
-rw-r--r--ospfd/ospf_lsa.h26
-rw-r--r--ospfd/ospf_lsdb.c9
-rw-r--r--ospfd/ospf_memory.c1
-rw-r--r--ospfd/ospf_memory.h1
-rw-r--r--ospfd/ospf_orr.c594
-rw-r--r--ospfd/ospf_orr.h58
-rw-r--r--ospfd/ospf_route.c4
-rw-r--r--ospfd/ospf_route.h3
-rw-r--r--ospfd/ospf_spf.c201
-rw-r--r--ospfd/ospf_spf.h3
-rw-r--r--ospfd/ospf_vty.c128
-rw-r--r--ospfd/ospf_zebra.c7
-rw-r--r--ospfd/ospfd.c1
-rw-r--r--ospfd/ospfd.h10
-rw-r--r--ospfd/subdir.am2
-rw-r--r--pathd/path_cli.c2
-rw-r--r--pbrd/pbr_vty.c2
-rw-r--r--pimd/pim6_cmd.c2
-rw-r--r--pimd/pim_cmd.c3
-rw-r--r--ripd/rip_debug.c2
-rw-r--r--ripd/ripd.c8
-rw-r--r--ripngd/ripng_debug.c2
-rw-r--r--ripngd/ripngd.c7
-rw-r--r--sharpd/sharp_vty.c2
-rw-r--r--snapcraft/snapcraft.yaml.in2
-rw-r--r--staticd/static_main.c1
-rw-r--r--staticd/static_vty.c2
-rw-r--r--tests/lib/test_typelist.h2
-rw-r--r--tests/topotests/bgp_accept_own/__init__.py0
-rw-r--r--tests/topotests/bgp_accept_own/ce1/bgpd.conf12
-rw-r--r--tests/topotests/bgp_accept_own/ce1/zebra.conf9
-rw-r--r--tests/topotests/bgp_accept_own/ce2/bgpd.conf12
-rw-r--r--tests/topotests/bgp_accept_own/ce2/zebra.conf9
-rw-r--r--tests/topotests/bgp_accept_own/pe1/bgpd.conf49
-rw-r--r--tests/topotests/bgp_accept_own/pe1/ldpd.conf12
-rw-r--r--tests/topotests/bgp_accept_own/pe1/ospfd.conf7
-rw-r--r--tests/topotests/bgp_accept_own/pe1/zebra.conf15
-rw-r--r--tests/topotests/bgp_accept_own/rr1/bgpd.conf25
-rw-r--r--tests/topotests/bgp_accept_own/rr1/ldpd.conf12
-rw-r--r--tests/topotests/bgp_accept_own/rr1/ospfd.conf7
-rw-r--r--tests/topotests/bgp_accept_own/rr1/zebra.conf9
-rw-r--r--tests/topotests/bgp_accept_own/test_bgp_accept_own.py198
-rw-r--r--tests/topotests/bgp_basic_functionality_topo1/test_bgp_basic_functionality.py14
-rw-r--r--tests/topotests/bgp_communities_topo1/test_bgp_communities.py13
-rw-r--r--tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py8
-rw-r--r--tests/topotests/bgp_ecmp_topo2/test_ebgp_ecmp_topo2.py14
-rw-r--r--tests/topotests/bgp_ecmp_topo2/test_ibgp_ecmp_topo2.py14
-rw-r--r--tests/topotests/bgp_ecmp_topo3/test_ibgp_ecmp_topo3.py17
-rw-r--r--tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-1.py28
-rw-r--r--tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-2.py2
-rw-r--r--tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-3.py87
-rw-r--r--tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py23
-rw-r--r--tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-1.py47
-rw-r--r--tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-2.py43
-rw-r--r--tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-3.py70
-rw-r--r--tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-4.py20
-rw-r--r--tests/topotests/bgp_gr_functionality_topo3/bgp_gr_functionality_topo3.py316
-rw-r--r--tests/topotests/bgp_gr_restart_retain_routes/__init__.py0
-rw-r--r--tests/topotests/bgp_gr_restart_retain_routes/r1/bgpd.conf11
-rw-r--r--tests/topotests/bgp_gr_restart_retain_routes/r1/zebra.conf7
-rw-r--r--tests/topotests/bgp_gr_restart_retain_routes/r2/bgpd.conf8
-rw-r--r--tests/topotests/bgp_gr_restart_retain_routes/r2/zebra.conf5
-rw-r--r--tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_restart_retain_routes.py131
-rw-r--r--tests/topotests/bgp_gshut_topo1/test_ebgp_gshut_topo1.py2
-rw-r--r--tests/topotests/bgp_gshut_topo1/test_ibgp_gshut_topo1.py2
-rw-r--r--tests/topotests/bgp_local_as/__init__.py0
-rw-r--r--tests/topotests/bgp_local_as/r1/bgpd.conf14
-rw-r--r--tests/topotests/bgp_local_as/r1/zebra.conf10
-rw-r--r--tests/topotests/bgp_local_as/r2/bgpd.conf6
-rw-r--r--tests/topotests/bgp_local_as/r2/zebra.conf4
-rw-r--r--tests/topotests/bgp_local_as/r3/bgpd.conf6
-rw-r--r--tests/topotests/bgp_local_as/r3/zebra.conf4
-rw-r--r--tests/topotests/bgp_local_as/test_bgp_local_as.py134
-rw-r--r--tests/topotests/bgp_max_med_on_startup/__init__.py0
-rw-r--r--tests/topotests/bgp_max_med_on_startup/r1/bgpd.conf11
-rw-r--r--tests/topotests/bgp_max_med_on_startup/r1/zebra.conf9
-rw-r--r--tests/topotests/bgp_max_med_on_startup/r2/bgpd.conf7
-rw-r--r--tests/topotests/bgp_max_med_on_startup/r2/zebra.conf6
-rw-r--r--tests/topotests/bgp_max_med_on_startup/test_bgp_max_med_on_startup.py114
-rw-r--r--tests/topotests/bgp_prefix_list_topo1/test_prefix_lists.py66
-rw-r--r--tests/topotests/bgp_route_map/test_route_map_topo1.py27
-rw-r--r--tests/topotests/bgp_route_map/test_route_map_topo2.py98
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/zebra.conf2
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/zebra.conf2
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/zebra.conf2
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/zebra.conf2
-rw-r--r--tests/topotests/isis_topo1/test_isis_topo1.py313
-rwxr-xr-xtools/frr-reload.py35
-rwxr-xr-xtools/frr.in18
-rwxr-xr-xtools/frrcommon.sh.in16
-rw-r--r--vrrpd/vrrp_vty.c2
-rw-r--r--watchfrr/watchfrr_vty.c2
-rw-r--r--yang/frr-isisd.yang22
-rw-r--r--zebra/debug.c3
-rw-r--r--zebra/main.c1
-rw-r--r--zebra/zebra_evpn_mh.c2
-rw-r--r--zebra/zebra_srv6_vty.c13
-rw-r--r--zebra/zebra_srv6_vty.h4
160 files changed, 6116 insertions, 1047 deletions
diff --git a/.github/workflows/conflicts.yml b/.github/workflows/conflicts.yml
new file mode 100644
index 000000000..18a8c0d15
--- /dev/null
+++ b/.github/workflows/conflicts.yml
@@ -0,0 +1,21 @@
+name: Add a conflict label is PR needs to rebase
+
+on:
+ push:
+ pull_request_target:
+ types: [synchronize]
+
+jobs:
+ conflicts:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ pull-requests: write
+ steps:
+ - name: Check if PRs need a rebase (have some conflicts)
+ uses: eps1lon/actions-label-merge-conflict@releases/2.x
+ with:
+ dirtyLabel: "conflicts"
+ removeOnDirtyLabel: "no_conflicts"
+ repoToken: "${{ secrets.GITHUB_TOKEN }}"
+ commentOnDirty: "This pull request has conflicts, please resolve those before we can evaluate the pull request."
diff --git a/babeld/babel_zebra.c b/babeld/babel_zebra.c
index d0da93e50..daaa870a6 100644
--- a/babeld/babel_zebra.c
+++ b/babeld/babel_zebra.c
@@ -225,6 +225,8 @@ DEFUN_NOSH (show_debugging_babel,
debug_babel_config_write(vty);
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c
index 21429f06c..4a2c5bf66 100644
--- a/bfdd/bfdd_vty.c
+++ b/bfdd/bfdd_vty.c
@@ -973,6 +973,8 @@ DEFUN_NOSH(show_debugging_bfd,
if (bglobal.debug_network)
vty_out(vty, " Network layer debugging is on.\n");
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index 4963ea64d..41ae6ef49 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -80,14 +80,6 @@
#define BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE 1
#define BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH 6
-/* SRv6 SID Structure default values */
-#define BGP_PREFIX_SID_SRV6_LOCATOR_BLOCK_LENGTH 40
-#define BGP_PREFIX_SID_SRV6_LOCATOR_NODE_LENGTH 24
-#define BGP_PREFIX_SID_SRV6_FUNCTION_LENGTH 16
-#define BGP_PREFIX_SID_SRV6_ARGUMENT_LENGTH 0
-#define BGP_PREFIX_SID_SRV6_TRANSPOSITION_LENGTH 16
-#define BGP_PREFIX_SID_SRV6_TRANSPOSITION_OFFSET 64
-
#define BGP_ATTR_NH_AFI(afi, attr) \
((afi != AFI_L2VPN) ? afi : \
((attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV4) ? AFI_IP : AFI_IP6))
diff --git a/bgpd/bgp_community.h b/bgpd/bgp_community.h
index 616ddb440..05a5d4486 100644
--- a/bgpd/bgp_community.h
+++ b/bgpd/bgp_community.h
@@ -23,6 +23,7 @@
#include "lib/json.h"
#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr.h"
/* Communities attribute. */
struct community {
@@ -109,4 +110,30 @@ extern void bgp_remove_comm_from_aggregate_hash(struct bgp_aggregate *aggregate,
struct community *community);
extern void bgp_aggr_community_remove(void *arg);
+/* This implies that when propagating routes into a VRF, the ACCEPT_OWN
+ * community SHOULD NOT be propagated.
+ */
+static inline void community_strip_accept_own(struct attr *attr)
+{
+ struct community *old_com = bgp_attr_get_community(attr);
+ struct community *new_com = NULL;
+ uint32_t val = COMMUNITY_ACCEPT_OWN;
+
+ if (old_com && community_include(old_com, val)) {
+ new_com = community_dup(old_com);
+ val = htonl(val);
+ community_del_val(new_com, &val);
+
+ if (!old_com->refcnt)
+ community_free(&old_com);
+
+ if (!new_com->size) {
+ community_free(&new_com);
+ bgp_attr_set_community(attr, NULL);
+ } else {
+ bgp_attr_set_community(attr, new_com);
+ }
+ }
+}
+
#endif /* _QUAGGA_BGP_COMMUNITY_H */
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index df7262be6..580c18b58 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -71,6 +71,7 @@ unsigned long conf_bgp_debug_graceful_restart;
unsigned long conf_bgp_debug_evpn_mh;
unsigned long conf_bgp_debug_bfd;
unsigned long conf_bgp_debug_cond_adv;
+unsigned long conf_bgp_debug_optimal_route_reflection;
unsigned long term_bgp_debug_as4;
unsigned long term_bgp_debug_neighbor_events;
@@ -92,6 +93,7 @@ unsigned long term_bgp_debug_graceful_restart;
unsigned long term_bgp_debug_evpn_mh;
unsigned long term_bgp_debug_bfd;
unsigned long term_bgp_debug_cond_adv;
+unsigned long term_bgp_debug_optimal_route_reflection;
struct list *bgp_debug_neighbor_events_peers = NULL;
struct list *bgp_debug_keepalive_peers = NULL;
@@ -2044,6 +2046,33 @@ DEFPY (debug_bgp_evpn_mh,
return CMD_SUCCESS;
}
+DEFPY (debug_bgp_optimal_route_reflection,
+ debug_bgp_optimal_route_reflection_cmd,
+ "[no$no] debug bgp optimal-route-reflection",
+ NO_STR
+ DEBUG_STR
+ BGP_STR
+ BGP_ORR_DEBUG)
+{
+ if (vty->node == CONFIG_NODE) {
+ if (no)
+ DEBUG_OFF(optimal_route_reflection, ORR);
+ else
+ DEBUG_ON(optimal_route_reflection, ORR);
+ } else {
+ if (no) {
+ TERM_DEBUG_OFF(optimal_route_reflection, ORR);
+ vty_out(vty,
+ "BGP Optimal Route Reflection debugging is off\n");
+ } else {
+ TERM_DEBUG_ON(optimal_route_reflection, ORR);
+ vty_out(vty,
+ "BGP Optimal Route Reflection debugging is on\n");
+ }
+ }
+ return CMD_SUCCESS;
+}
+
DEFUN (debug_bgp_labelpool,
debug_bgp_labelpool_cmd,
"debug bgp labelpool",
@@ -2182,6 +2211,7 @@ DEFUN (no_debug_bgp,
TERM_DEBUG_OFF(evpn_mh, EVPN_MH_RT);
TERM_DEBUG_OFF(bfd, BFD_LIB);
TERM_DEBUG_OFF(cond_adv, COND_ADV);
+ TERM_DEBUG_OFF(optimal_route_reflection, ORR);
vty_out(vty, "All possible debugging has been turned off\n");
@@ -2278,6 +2308,12 @@ DEFUN_NOSH (show_debugging_bgp,
vty_out(vty,
" BGP conditional advertisement debugging is on\n");
+ if (BGP_DEBUG(optimal_route_reflection, ORR))
+ vty_out(vty,
+ " BGP Optimal Route Reflection debugging is on\n");
+
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
@@ -2412,6 +2448,11 @@ static int bgp_config_write_debug(struct vty *vty)
write++;
}
+ if (CONF_BGP_DEBUG(optimal_route_reflection, ORR)) {
+ vty_out(vty, "debug bgp optimal-route-reflection\n");
+ write++;
+ }
+
return write;
}
@@ -2544,6 +2585,10 @@ void bgp_debug_init(void)
/* debug bgp conditional advertisement */
install_element(ENABLE_NODE, &debug_bgp_cond_adv_cmd);
install_element(CONFIG_NODE, &debug_bgp_cond_adv_cmd);
+
+ /* debug bgp optimal route reflection */
+ install_element(ENABLE_NODE, &debug_bgp_optimal_route_reflection_cmd);
+ install_element(CONFIG_NODE, &debug_bgp_optimal_route_reflection_cmd);
}
/* Return true if this prefix is on the per_prefix_list of prefixes to debug
diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h
index be5ed0afd..f7090260a 100644
--- a/bgpd/bgp_debug.h
+++ b/bgpd/bgp_debug.h
@@ -81,6 +81,7 @@ extern unsigned long conf_bgp_debug_graceful_restart;
extern unsigned long conf_bgp_debug_evpn_mh;
extern unsigned long conf_bgp_debug_bfd;
extern unsigned long conf_bgp_debug_cond_adv;
+extern unsigned long conf_bgp_debug_optimal_route_reflection;
extern unsigned long term_bgp_debug_as4;
extern unsigned long term_bgp_debug_neighbor_events;
@@ -100,6 +101,7 @@ extern unsigned long term_bgp_debug_graceful_restart;
extern unsigned long term_bgp_debug_evpn_mh;
extern unsigned long term_bgp_debug_bfd;
extern unsigned long term_bgp_debug_cond_adv;
+extern unsigned long term_bgp_debug_optimal_route_reflection;
extern struct list *bgp_debug_neighbor_events_peers;
extern struct list *bgp_debug_keepalive_peers;
@@ -138,6 +140,7 @@ struct bgp_debug_filter {
#define BGP_DEBUG_PBR_ERROR 0x02
#define BGP_DEBUG_EVPN_MH_ES 0x01
#define BGP_DEBUG_EVPN_MH_RT 0x02
+#define BGP_DEBUG_ORR 0x01
#define BGP_DEBUG_PACKET_SEND 0x01
#define BGP_DEBUG_PACKET_SEND_DETAIL 0x02
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index ddda10077..a85432a33 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -1330,6 +1330,9 @@ void bgp_fsm_change_status(struct peer *peer, int status)
&& bgp_update_delay_applicable(peer->bgp))
bgp_update_delay_process_status_change(peer);
+ /* BGP ORR : Update Active Root */
+ bgp_peer_update_orr_active_roots(peer);
+
if (bgp_debug_neighbor_events(peer))
zlog_debug("%s went from %s to %s", peer->host,
lookup_msg(bgp_status_msg, peer->ostatus, NULL),
diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h
index aaf6c480b..368c2c500 100644
--- a/bgpd/bgp_fsm.h
+++ b/bgpd/bgp_fsm.h
@@ -175,4 +175,6 @@ const char *print_peer_gr_cmd(enum peer_gr_command pr_gr_cmd);
const char *print_global_gr_mode(enum global_mode gl_mode);
const char *print_global_gr_cmd(enum global_gr_command gl_gr_cmd);
int bgp_peer_reg_with_nht(struct peer *peer);
+
+extern void bgp_peer_update_orr_active_roots(struct peer *peer);
#endif /* _QUAGGA_BGP_FSM_H */
diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c
index 850657d35..ced3e1890 100644
--- a/bgpd/bgp_memory.c
+++ b/bgpd/bgp_memory.c
@@ -134,8 +134,12 @@ DEFINE_MTYPE(BGPD, BGP_EVPN_VRF_IMPORT_RT, "BGP EVPN VRF Import RT");
DEFINE_MTYPE(BGPD, BGP_SRV6_L3VPN, "BGP prefix-sid srv6 l3vpn servcie");
DEFINE_MTYPE(BGPD, BGP_SRV6_VPN, "BGP prefix-sid srv6 vpn service");
+
DEFINE_MTYPE(BGPD, BGP_SRV6_SID, "BGP srv6 segment-id");
DEFINE_MTYPE(BGPD, BGP_SRV6_FUNCTION, "BGP srv6 function");
DEFINE_MTYPE(BGPD, EVPN_REMOTE_IP, "BGP EVPN Remote IP hash entry");
DEFINE_MTYPE(BGPD, BGP_NOTIFICATION, "BGP Notification Message");
+DEFINE_MTYPE(BGPD, BGP_ORR_GROUP, "BGP Optimal Route Reflection Group");
+DEFINE_MTYPE(BGPD, BGP_ORR_GROUP_NAME,
+ "BGP Optimal Route Reflection Group Name");
diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h
index 510cfa21c..990c6e1fa 100644
--- a/bgpd/bgp_memory.h
+++ b/bgpd/bgp_memory.h
@@ -137,5 +137,7 @@ DECLARE_MTYPE(BGP_SRV6_FUNCTION);
DECLARE_MTYPE(EVPN_REMOTE_IP);
DECLARE_MTYPE(BGP_NOTIFICATION);
+DECLARE_MTYPE(BGP_ORR_GROUP);
+DECLARE_MTYPE(BGP_ORR_GROUP_NAME);
#endif /* _QUAGGA_BGP_MEMORY_H */
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index d7fd4bc77..66eef1aa5 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -42,6 +42,7 @@
#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_vpn.h"
+#include "bgpd/bgp_community.h"
#include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_nexthop.h"
@@ -524,37 +525,77 @@ static bool sid_exist(struct bgp *bgp, const struct in6_addr *sid)
* else: try to allocate as auto-mode
*/
static uint32_t alloc_new_sid(struct bgp *bgp, uint32_t index,
- struct in6_addr *sid_locator,
+ struct srv6_locator_chunk *sid_locator_chunk,
struct in6_addr *sid)
{
+ int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
struct listnode *node;
struct srv6_locator_chunk *chunk;
bool alloced = false;
int label = 0;
uint8_t offset = 0;
- uint8_t len = 0;
+ uint8_t func_len = 0, shift_len = 0;
+ uint32_t index_max = 0;
- if (!bgp || !sid_locator || !sid)
+ if (!bgp || !sid_locator_chunk || !sid)
return false;
for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, chunk)) {
- *sid_locator = chunk->prefix.prefix;
+ if (chunk->function_bits_length >
+ BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH) {
+ if (debug)
+ zlog_debug(
+ "%s: invalid SRv6 Locator chunk (%pFX): Function Length must be less or equal to %d",
+ __func__, &chunk->prefix,
+ BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH);
+ continue;
+ }
+
+ index_max = (1 << chunk->function_bits_length) - 1;
+
+ if (index > index_max) {
+ if (debug)
+ zlog_debug(
+ "%s: skipped SRv6 Locator chunk (%pFX): Function Length is too short to support specified index (%u)",
+ __func__, &chunk->prefix, index);
+ continue;
+ }
+
*sid = chunk->prefix.prefix;
+ *sid_locator_chunk = *chunk;
offset = chunk->block_bits_length + chunk->node_bits_length;
- len = chunk->function_bits_length ?: 16;
+ func_len = chunk->function_bits_length;
+ shift_len = BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH - func_len;
if (index != 0) {
- label = index << 12;
- transpose_sid(sid, label, offset, len);
+ label = index << shift_len;
+ if (label < MPLS_LABEL_UNRESERVED_MIN) {
+ if (debug)
+ zlog_debug(
+ "%s: skipped to allocate SRv6 SID (%pFX): Label (%u) is too small to use",
+ __func__, &chunk->prefix,
+ label);
+ continue;
+ }
+
+ transpose_sid(sid, label, offset, func_len);
if (sid_exist(bgp, sid))
- return false;
+ continue;
alloced = true;
break;
}
- for (size_t i = 1; i < 255; i++) {
- label = i << 12;
- transpose_sid(sid, label, offset, len);
+ for (uint32_t i = 1; i < index_max; i++) {
+ label = i << shift_len;
+ if (label < MPLS_LABEL_UNRESERVED_MIN) {
+ if (debug)
+ zlog_debug(
+ "%s: skipped to allocate SRv6 SID (%pFX): Label (%u) is too small to use",
+ __func__, &chunk->prefix,
+ label);
+ continue;
+ }
+ transpose_sid(sid, label, offset, func_len);
if (sid_exist(bgp, sid))
continue;
alloced = true;
@@ -573,7 +614,8 @@ void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
char buf[256];
- struct in6_addr *tovpn_sid, *tovpn_sid_locator;
+ struct srv6_locator_chunk *tovpn_sid_locator;
+ struct in6_addr *tovpn_sid;
uint32_t tovpn_sid_index = 0, tovpn_sid_transpose_label;
bool tovpn_sid_auto = false;
@@ -607,8 +649,7 @@ void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)
return;
}
- tovpn_sid_locator =
- XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr));
+ tovpn_sid_locator = srv6_locator_chunk_alloc();
tovpn_sid = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr));
tovpn_sid_transpose_label = alloc_new_sid(bgp_vpn, tovpn_sid_index,
@@ -617,7 +658,7 @@ void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)
if (tovpn_sid_transpose_label == 0) {
zlog_debug("%s: not allocated new sid for vrf %s: afi %s",
__func__, bgp_vrf->name_pretty, afi2str(afi));
- XFREE(MTYPE_BGP_SRV6_SID, tovpn_sid_locator);
+ srv6_locator_chunk_free(tovpn_sid_locator);
XFREE(MTYPE_BGP_SRV6_SID, tovpn_sid);
return;
}
@@ -636,20 +677,30 @@ void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)
}
/*
- * This function shifts "label" 4 bits to the right and
- * embeds it by length "len", starting at offset "offset"
- * as seen from the MSB (Most Significant Bit) of "sid".
+ * This function embeds upper `len` bits of `label` in `sid`,
+ * starting at offset `offset` as seen from the MSB of `sid`.
*
- * e.g. if "label" is 0x1000 and "len" is 16, "label" is
- * embedded in "sid" as follows:
+ * e.g. Given that `label` is 0x12345 and `len` is 16,
+ * then `label` will be embedded in `sid` as follows:
*
* <---- len ----->
- * label: 0000 0001 0000 0000 0000
- * sid: .... 0000 0001 0000 0000
+ * label: 0001 0002 0003 0004 0005
+ * sid: .... 0001 0002 0003 0004
* <---- len ----->
* ^
* |
* offset from MSB
+ *
+ * e.g. Given that `label` is 0x12345 and `len` is 8,
+ * `label` will be embedded in `sid` as follows:
+ *
+ * <- len ->
+ * label: 0001 0002 0003 0004 0005
+ * sid: .... 0001 0002 0000 0000
+ * <- len ->
+ * ^
+ * |
+ * offset from MSB
*/
void transpose_sid(struct in6_addr *sid, uint32_t label, uint8_t offset,
uint8_t len)
@@ -657,7 +708,7 @@ void transpose_sid(struct in6_addr *sid, uint32_t label, uint8_t offset,
for (uint8_t idx = 0; idx < len; idx++) {
uint8_t tidx = offset + idx;
sid->s6_addr[tidx / 8] &= ~(0x1 << (7 - tidx % 8));
- if (label >> (len + 3 - idx) & 0x1)
+ if (label >> (19 - idx) & 0x1)
sid->s6_addr[tidx / 8] |= 0x1 << (7 - tidx % 8);
}
}
@@ -946,6 +997,9 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn,
if (nexthop_self_flag)
bgp_path_info_set_flag(bn, bpi, BGP_PATH_ANNC_NH_SELF);
+ if (CHECK_FLAG(source_bpi->flags, BGP_PATH_ACCEPT_OWN))
+ bgp_path_info_set_flag(bn, bpi, BGP_PATH_ACCEPT_OWN);
+
if (leak_update_nexthop_valid(to_bgp, bn, new_attr, afi, safi,
source_bpi, bpi, bgp_orig, p,
debug))
@@ -986,6 +1040,9 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn,
if (nexthop_self_flag)
bgp_path_info_set_flag(bn, new, BGP_PATH_ANNC_NH_SELF);
+ if (CHECK_FLAG(source_bpi->flags, BGP_PATH_ACCEPT_OWN))
+ bgp_path_info_set_flag(bn, new, BGP_PATH_ACCEPT_OWN);
+
bgp_path_info_extra_get(new);
/*
@@ -1167,6 +1224,8 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */
XFREE(MTYPE_ECOMMUNITY_STR, s);
}
+ community_strip_accept_own(&static_attr);
+
/* Nexthop */
/* if policy nexthop not set, use 0 */
if (CHECK_FLAG(from_bgp->vpn_policy[afi].flags,
@@ -1252,19 +1311,29 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */
static_attr.srv6_l3vpn->sid_flags = 0x00;
static_attr.srv6_l3vpn->endpoint_behavior = 0xffff;
static_attr.srv6_l3vpn->loc_block_len =
- BGP_PREFIX_SID_SRV6_LOCATOR_BLOCK_LENGTH;
+ from_bgp->vpn_policy[afi]
+ .tovpn_sid_locator->block_bits_length;
static_attr.srv6_l3vpn->loc_node_len =
- BGP_PREFIX_SID_SRV6_LOCATOR_NODE_LENGTH;
+ from_bgp->vpn_policy[afi]
+ .tovpn_sid_locator->node_bits_length;
static_attr.srv6_l3vpn->func_len =
- BGP_PREFIX_SID_SRV6_FUNCTION_LENGTH;
+ from_bgp->vpn_policy[afi]
+ .tovpn_sid_locator->function_bits_length;
static_attr.srv6_l3vpn->arg_len =
- BGP_PREFIX_SID_SRV6_ARGUMENT_LENGTH;
+ from_bgp->vpn_policy[afi]
+ .tovpn_sid_locator->argument_bits_length;
static_attr.srv6_l3vpn->transposition_len =
- BGP_PREFIX_SID_SRV6_TRANSPOSITION_LENGTH;
+ from_bgp->vpn_policy[afi]
+ .tovpn_sid_locator->function_bits_length;
static_attr.srv6_l3vpn->transposition_offset =
- BGP_PREFIX_SID_SRV6_TRANSPOSITION_OFFSET;
+ from_bgp->vpn_policy[afi]
+ .tovpn_sid_locator->block_bits_length +
+ from_bgp->vpn_policy[afi]
+ .tovpn_sid_locator->node_bits_length;
+ ;
memcpy(&static_attr.srv6_l3vpn->sid,
- from_bgp->vpn_policy[afi].tovpn_sid_locator,
+ &from_bgp->vpn_policy[afi]
+ .tovpn_sid_locator->prefix.prefix,
sizeof(struct in6_addr));
}
@@ -1302,7 +1371,7 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */
* because of loop checking.
*/
if (new_info)
- vpn_leak_to_vrf_update(from_bgp, new_info);
+ vpn_leak_to_vrf_update(from_bgp, new_info, NULL);
}
void vpn_leak_from_vrf_withdraw(struct bgp *to_bgp, /* to */
@@ -1458,10 +1527,40 @@ void vpn_leak_from_vrf_update_all(struct bgp *to_bgp, struct bgp *from_bgp,
}
}
-static bool
-vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
- struct bgp *from_bgp, /* from */
- struct bgp_path_info *path_vpn) /* route */
+static struct bgp *bgp_lookup_by_rd(struct bgp_path_info *bpi,
+ struct prefix_rd *rd, afi_t afi)
+{
+ struct listnode *node, *nnode;
+ struct bgp *bgp;
+
+ if (!rd)
+ return NULL;
+
+ /* If ACCEPT_OWN is not enabled for this path - return. */
+ if (!CHECK_FLAG(bpi->flags, BGP_PATH_ACCEPT_OWN))
+ return NULL;
+
+ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
+ if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
+ continue;
+
+ if (!CHECK_FLAG(bgp->vpn_policy[afi].flags,
+ BGP_VPN_POLICY_TOVPN_RD_SET))
+ continue;
+
+ /* Check if we have source VRF by RD value */
+ if (memcmp(&bgp->vpn_policy[afi].tovpn_rd.val, rd->val,
+ ECOMMUNITY_SIZE) == 0)
+ return bgp;
+ }
+
+ return NULL;
+}
+
+static bool vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
+ struct bgp *from_bgp, /* from */
+ struct bgp_path_info *path_vpn,
+ struct prefix_rd *prd)
{
const struct prefix *p = bgp_dest_get_prefix(path_vpn->net);
afi_t afi = family2afi(p->family);
@@ -1498,9 +1597,22 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
return false;
}
+ /* A route MUST NOT ever be accepted back into its source VRF, even if
+ * it carries one or more RTs that match that VRF.
+ */
+ if (prd && memcmp(&prd->val, &to_bgp->vpn_policy[afi].tovpn_rd.val,
+ ECOMMUNITY_SIZE) == 0) {
+ if (debug)
+ zlog_debug(
+ "%s: skipping import, match RD (%pRD) of src VRF (%s) and the prefix (%pFX)",
+ __func__, prd, to_bgp->name_pretty, p);
+
+ return false;
+ }
+
if (debug)
- zlog_debug("%s: updating %pFX to vrf %s", __func__, p,
- to_bgp->name_pretty);
+ zlog_debug("%s: updating RD %pRD, %pFX to vrf %s", __func__,
+ prd, p, to_bgp->name_pretty);
/* shallow copy */
static_attr = *path_vpn->attr;
@@ -1525,6 +1637,8 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
ecommunity_free(&old_ecom);
}
+ community_strip_accept_own(&static_attr);
+
/*
* Nexthop: stash and clear
*
@@ -1651,9 +1765,16 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
/*
* For VRF-2-VRF route-leaking,
* the source will be the originating VRF.
+ *
+ * If ACCEPT_OWN mechanism is enabled, then we SHOULD(?)
+ * get the source VRF (BGP) by looking at the RD.
*/
+ struct bgp *src_bgp = bgp_lookup_by_rd(path_vpn, prd, afi);
+
if (path_vpn->extra && path_vpn->extra->bgp_orig)
src_vrf = path_vpn->extra->bgp_orig;
+ else if (src_bgp)
+ src_vrf = src_bgp;
else
src_vrf = from_bgp;
@@ -1663,8 +1784,9 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
return true;
}
-bool vpn_leak_to_vrf_update(struct bgp *from_bgp, /* from */
- struct bgp_path_info *path_vpn) /* route */
+bool vpn_leak_to_vrf_update(struct bgp *from_bgp,
+ struct bgp_path_info *path_vpn,
+ struct prefix_rd *prd)
{
struct listnode *mnode, *mnnode;
struct bgp *bgp;
@@ -1681,7 +1803,7 @@ bool vpn_leak_to_vrf_update(struct bgp *from_bgp, /* from */
if (!path_vpn->extra
|| path_vpn->extra->bgp_orig != bgp) { /* no loop */
leak_success |= vpn_leak_to_vrf_update_onevrf(
- bgp, from_bgp, path_vpn);
+ bgp, from_bgp, path_vpn, prd);
}
}
return leak_success;
@@ -1837,7 +1959,7 @@ void vpn_leak_to_vrf_update_all(struct bgp *to_bgp, struct bgp *vpn_from,
continue;
vpn_leak_to_vrf_update_onevrf(to_bgp, vpn_from,
- bpi);
+ bpi, NULL);
}
}
}
diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h
index c5cc7d429..9af4cdf3a 100644
--- a/bgpd/bgp_mplsvpn.h
+++ b/bgpd/bgp_mplsvpn.h
@@ -41,6 +41,8 @@
#define V4_HEADER_OVERLAY \
" Network Next Hop EthTag Overlay Index RouterMac\n"
+#define BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH 20
+
extern void bgp_mplsvpn_init(void);
extern int bgp_nlri_parse_vpn(struct peer *, struct attr *, struct bgp_nlri *);
extern uint32_t decode_label(mpls_label_t *);
@@ -70,7 +72,8 @@ extern void vpn_leak_to_vrf_update_all(struct bgp *to_bgp, struct bgp *from_bgp,
afi_t afi);
extern bool vpn_leak_to_vrf_update(struct bgp *from_bgp,
- struct bgp_path_info *path_vpn);
+ struct bgp_path_info *path_vpn,
+ struct prefix_rd *prd);
extern void vpn_leak_to_vrf_withdraw(struct bgp *from_bgp,
struct bgp_path_info *path_vpn);
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index 9ecc2ae4e..9582ec01e 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -207,6 +207,25 @@ int bgp_md5_set(struct peer *peer)
return bgp_md5_set_password(peer, peer->password);
}
+static void bgp_update_setsockopt_tcp_keepalive(struct bgp *bgp, int fd)
+{
+ if (!bgp)
+ return;
+ if (bgp->tcp_keepalive_idle != 0) {
+ int ret;
+
+ ret = setsockopt_tcp_keepalive(fd, bgp->tcp_keepalive_idle,
+ bgp->tcp_keepalive_intvl,
+ bgp->tcp_keepalive_probes);
+ if (ret < 0)
+ zlog_err(
+ "Can't set TCP keepalive on socket %d, idle %u intvl %u probes %u",
+ fd, bgp->tcp_keepalive_idle,
+ bgp->tcp_keepalive_intvl,
+ bgp->tcp_keepalive_probes);
+ }
+}
+
int bgp_md5_unset(struct peer *peer)
{
/* Unset the password from listen socket. */
@@ -415,6 +434,9 @@ static void bgp_accept(struct thread *thread)
bgp_socket_set_buffer_size(bgp_sock);
+ /* Set TCP keepalive when TCP keepalive is enabled */
+ bgp_update_setsockopt_tcp_keepalive(bgp, bgp_sock);
+
/* Check remote IP address */
peer1 = peer_lookup(bgp, &su);
@@ -718,12 +740,16 @@ int bgp_connect(struct peer *peer)
bgp_socket_set_buffer_size(peer->fd);
+ /* Set TCP keepalive when TCP keepalive is enabled */
+ bgp_update_setsockopt_tcp_keepalive(peer->bgp, peer->fd);
+
if (bgp_set_socket_ttl(peer, peer->fd) < 0) {
peer->last_reset = PEER_DOWN_SOCKET_ERROR;
if (bgp_debug_neighbor_events(peer))
zlog_debug("%s: Failure to set socket ttl for connection to %s, error received: %s(%d)",
__func__, peer->host, safe_strerror(errno),
errno);
+
return -1;
}
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c
index 59b31072b..075350cd2 100644
--- a/bgpd/bgp_nexthop.c
+++ b/bgpd/bgp_nexthop.c
@@ -865,7 +865,6 @@ static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
}
tbuf = time(NULL) - (monotime(NULL) - bnc->last_update);
vty_out(vty, " Last update: %s", ctime(&tbuf));
- vty_out(vty, "\n");
/* show paths dependent on nexthop, if needed. */
if (specific)
@@ -912,6 +911,7 @@ static int show_ip_bgp_nexthop_table(struct vty *vty, const char *name,
struct prefix nhop;
struct bgp_nexthop_cache_head (*tree)[AFI_MAX];
struct bgp_nexthop_cache *bnc;
+ bool found = false;
if (!str2prefix(nhopip_str, &nhop)) {
vty_out(vty, "nexthop address is malformed\n");
@@ -919,12 +919,16 @@ static int show_ip_bgp_nexthop_table(struct vty *vty, const char *name,
}
tree = import_table ? &bgp->import_check_table
: &bgp->nexthop_cache_table;
- bnc = bnc_find(&(*tree)[family2afi(nhop.family)], &nhop, 0, 0);
- if (!bnc) {
- vty_out(vty, "specified nexthop does not have entry\n");
- return CMD_SUCCESS;
+ frr_each (bgp_nexthop_cache, &(*tree)[family2afi(nhop.family)],
+ bnc) {
+ if (prefix_cmp(&bnc->prefix, &nhop))
+ continue;
+ bgp_show_nexthop(vty, bgp, bnc, true);
+ found = true;
}
- bgp_show_nexthop(vty, bgp, bnc, true);
+ if (!found)
+ vty_out(vty, "nexthop %s does not have entry\n",
+ nhopip_str);
} else
bgp_show_nexthops(vty, bgp, import_table);
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c
index 7274bcdb2..7eeab373a 100644
--- a/bgpd/bgp_nht.c
+++ b/bgpd/bgp_nht.c
@@ -139,7 +139,8 @@ static int bgp_isvalid_nexthop_for_mpls(struct bgp_nexthop_cache *bnc,
*/
return (bgp_zebra_num_connects() == 0 ||
(bnc && (bnc->nexthop_num > 0 &&
- (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID) ||
+ (CHECK_FLAG(path->flags, BGP_PATH_ACCEPT_OWN) ||
+ CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID) ||
bnc->bgp->srv6_enabled ||
bgp_isvalid_nexthop_for_ebgp(bnc, path) ||
bgp_isvalid_nexthop_for_mplsovergre(bnc, path)))));
diff --git a/bgpd/bgp_orr.c b/bgpd/bgp_orr.c
new file mode 100644
index 000000000..7fed6b775
--- /dev/null
+++ b/bgpd/bgp_orr.c
@@ -0,0 +1,1176 @@
+/*
+ * BGP Optimal Route Reflection
+ * Copyright (C) 2021 Samsung R&D Institute India - Bangalore.
+ * Madhurilatha Kuruganti
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+#include "bgpd/bgpd.h"
+#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_orr.h"
+#include "bgpd/bgp_vty.h"
+#include "zclient.h"
+
+DEFINE_MTYPE_STATIC(BGPD, ORR_IGP_INFO, "ORR IGP Metric info");
+
+static inline bool is_orr_primary_root(struct bgp_orr_group *orr_group,
+ char *host)
+{
+ return orr_group->primary && strmatch(orr_group->primary->host, host);
+}
+
+static inline bool is_orr_secondary_root(struct bgp_orr_group *orr_group,
+ char *host)
+{
+ return orr_group->secondary &&
+ strmatch(orr_group->secondary->host, host);
+}
+
+static inline bool is_orr_tertiary_root(struct bgp_orr_group *orr_group,
+ char *host)
+{
+ return orr_group->tertiary && strmatch(orr_group->tertiary->host, host);
+}
+
+static inline bool is_orr_active_root(struct bgp_orr_group *orr_group,
+ char *host)
+{
+ return orr_group->active && strmatch(orr_group->active->host, host);
+}
+
+static inline bool is_orr_root_node(struct bgp_orr_group *orr_group, char *host)
+{
+ return is_orr_primary_root(orr_group, host) ||
+ is_orr_secondary_root(orr_group, host) ||
+ is_orr_tertiary_root(orr_group, host);
+}
+
+static inline bool is_peer_orr_group_member(struct peer *peer, afi_t afi,
+ safi_t safi, const char *name)
+{
+ return peer_af_flag_check(peer, afi, safi, PEER_FLAG_ORR_GROUP) &&
+ strmatch(peer->orr_group_name[afi][safi], name);
+}
+
+static inline bool is_peer_reachable(struct peer *peer, afi_t afi, safi_t safi)
+{
+ return peer && peer->afc_nego[afi][safi] && peer_established(peer);
+}
+
+static inline bool is_peer_active_eligible(struct peer *peer, afi_t afi,
+ safi_t safi, const char *name)
+{
+ return is_peer_reachable(peer, afi, safi) &&
+ is_peer_orr_group_member(peer, afi, safi, name);
+}
+
+static void bgp_orr_igp_metric_register(struct bgp_orr_group *orr_group,
+ bool reg);
+
+static void
+bgp_peer_update_orr_group_active_root(struct peer *peer, afi_t afi, safi_t safi,
+ struct bgp_orr_group *orr_group);
+
+static struct bgp_orr_group *bgp_orr_group_new(struct bgp *bgp, afi_t afi,
+ safi_t safi, const char *name)
+{
+ int ret;
+ struct list *orr_group_list = NULL;
+ struct bgp_orr_group *orr_group = NULL;
+
+ assert(bgp && name);
+
+ if (!bgp->orr_group[afi][safi])
+ bgp->orr_group[afi][safi] = list_new();
+
+ orr_group_list = bgp->orr_group[afi][safi];
+ orr_group = XCALLOC(MTYPE_BGP_ORR_GROUP, sizeof(struct bgp_orr_group));
+
+ listnode_add(orr_group_list, orr_group);
+
+ orr_group->name = XSTRDUP(MTYPE_BGP_ORR_GROUP_NAME, name);
+ orr_group->afi = afi;
+ orr_group->safi = safi;
+ orr_group->primary = orr_group->secondary = orr_group->tertiary = NULL;
+ orr_group->bgp = bgp;
+
+ /* Initialize ORR Group route table */
+ orr_group->route_table = bgp_table_init(bgp, afi, safi);
+ assert(orr_group->route_table);
+
+ /*
+ * Register for opaque messages from IGPs when first ORR group is
+ * configured.
+ */
+ if (!bgp->orr_group_count) {
+ ret = zclient_register_opaque(zclient, ORR_IGP_METRIC_UPDATE);
+ if (ret != ZCLIENT_SEND_SUCCESS)
+ bgp_orr_debug(
+ "%s: zclient_register_opaque failed with ret = %d",
+ __func__, ret);
+ }
+
+ bgp->orr_group_count++;
+
+ return orr_group;
+}
+
+static void bgp_orr_group_free(struct bgp_orr_group *orr_group)
+{
+ afi_t afi;
+ safi_t safi;
+ struct bgp *bgp;
+
+ assert(orr_group && orr_group->bgp && orr_group->name);
+
+ bgp_orr_debug("%s: Deleting ORR group %s", __func__, orr_group->name);
+
+ afi = orr_group->afi;
+ safi = orr_group->safi;
+ bgp = orr_group->bgp;
+
+ /*
+ * Unregister with IGP for metric calculation from specified location
+ * and delete igp_metric_info calculated for this group
+ */
+ bgp_orr_igp_metric_register(orr_group, false);
+
+ /* Free RR client list associated with this ORR group */
+ if (orr_group->rr_client_list)
+ list_delete(&orr_group->rr_client_list);
+
+ /* Free route table */
+ bgp_table_unlock(orr_group->route_table);
+ orr_group->route_table = NULL;
+
+ /* Unset ORR Group parameters */
+ XFREE(MTYPE_BGP_ORR_GROUP_NAME, orr_group->name);
+
+ listnode_delete(bgp->orr_group[afi][safi], orr_group);
+ XFREE(MTYPE_BGP_ORR_GROUP, orr_group);
+
+ bgp->orr_group_count--;
+
+ if (!bgp->orr_group[afi][safi]->count)
+ list_delete(&bgp->orr_group[afi][safi]);
+}
+
+struct bgp_orr_group *bgp_orr_group_lookup_by_name(struct bgp *bgp, afi_t afi,
+ safi_t safi,
+ const char *name)
+{
+ struct list *orr_group_list = NULL;
+ struct bgp_orr_group *group = NULL;
+ struct listnode *node;
+
+ assert(bgp);
+
+ orr_group_list = bgp->orr_group[afi][safi];
+ if (!orr_group_list)
+ return NULL;
+
+ for (ALL_LIST_ELEMENTS_RO(orr_group_list, node, group))
+ if (strmatch(group->name, name))
+ return group;
+
+ bgp_orr_debug("%s: For %s, ORR Group '%s' not found.", __func__,
+ get_afi_safi_str(afi, safi, false), name);
+
+ return NULL;
+}
+
+static char *bgp_orr_group_rrclient_lookup(struct bgp_orr_group *orr_group,
+ const char *rr_client_host)
+{
+ char *rrclient = NULL;
+ struct list *orr_group_rrclient_list = NULL;
+ struct listnode *node;
+
+ orr_group_rrclient_list = orr_group->rr_client_list;
+ if (!orr_group_rrclient_list)
+ return NULL;
+
+ for (ALL_LIST_ELEMENTS_RO(orr_group_rrclient_list, node, rrclient))
+ if (strmatch(rrclient, rr_client_host))
+ return rrclient;
+
+ bgp_orr_debug(
+ "%s: For %s, %s not found in ORR Group '%s' RR Client list",
+ __func__,
+ get_afi_safi_str(orr_group->afi, orr_group->safi, false),
+ rr_client_host, orr_group->name);
+
+ return NULL;
+}
+
+static void bgp_orr_group_rrclient_update(struct peer *peer, afi_t afi,
+ safi_t safi,
+ const char *orr_group_name, bool add)
+{
+ char *rr_client = NULL;
+ struct bgp_orr_group *orr_group = NULL;
+ struct list *rr_client_list = NULL;
+
+ assert(peer && peer->bgp && orr_group_name);
+
+ /* Get BGP ORR entry for the given address-family */
+ orr_group = bgp_orr_group_lookup_by_name(peer->bgp, afi, safi,
+ orr_group_name);
+ if (!orr_group) {
+ bgp_orr_debug("%s: For %s, ORR Group '%s' not found.", __func__,
+ get_afi_safi_str(afi, safi, false),
+ orr_group_name);
+ return;
+ }
+
+ /* Get BGP ORR client entry for the given RR client */
+ rr_client = bgp_orr_group_rrclient_lookup(orr_group, peer->host);
+
+ /* Nothing to do */
+ if ((rr_client && add) || (!rr_client && !add))
+ return;
+
+ if (add) {
+ /* Create BGP ORR RR client entry to the ORR Group */
+ if (!orr_group->rr_client_list)
+ orr_group->rr_client_list = list_new();
+ rr_client_list = orr_group->rr_client_list;
+ rr_client = XSTRDUP(MTYPE_BGP_PEER_HOST, peer->host);
+
+ listnode_add(rr_client_list, rr_client);
+
+ bgp_orr_debug(
+ "%s: For %s, %pBP is added to ORR Group '%s' RR Client list.",
+ __func__, get_afi_safi_str(afi, safi, false), peer,
+ orr_group_name);
+ } else {
+ /* Delete BGP ORR RR client entry from the ORR Group */
+ listnode_delete(orr_group->rr_client_list, rr_client);
+ XFREE(MTYPE_BGP_PEER_HOST, rr_client);
+ if (!orr_group->rr_client_list->count)
+ list_delete(&orr_group->rr_client_list);
+
+ bgp_orr_debug(
+ "%s: For %s, %pBP is removed from ORR Group '%s' RR Client list.",
+ __func__, get_afi_safi_str(afi, safi, false), peer,
+ orr_group_name);
+ }
+}
+
+/* Create/Update BGP Optimal Route Reflection Group */
+int bgp_afi_safi_orr_group_set(struct bgp *bgp, afi_t afi, safi_t safi,
+ const char *name, struct peer *primary,
+ struct peer *secondary, struct peer *tertiary)
+{
+ bool primary_eligible = false;
+ bool secondary_eligible = false;
+ bool tertiary_eligible = false;
+ struct bgp_orr_group *orr_group = NULL;
+
+ bgp_orr_debug(
+ "%s: For %s, ORR Group '%s' Primary %pBP Secondary %pBP Tertiary %pBP",
+ __func__, get_afi_safi_str(afi, safi, false), name, primary,
+ secondary, tertiary);
+
+ /* Get BGP ORR entry for the given address-family */
+ orr_group = bgp_orr_group_lookup_by_name(bgp, afi, safi, name);
+ if (!orr_group) {
+ /* Create BGP ORR entry for the given address-family */
+ orr_group = bgp_orr_group_new(bgp, afi, safi, name);
+ }
+
+ /* Compare and update Primary Root Address */
+ if (primary) {
+ if (!orr_group->primary ||
+ !strmatch(orr_group->primary->host, primary->host))
+ orr_group->primary = primary;
+ else
+ bgp_orr_debug("%s: No change in Primary Root",
+ __func__);
+
+ /*
+ * Update Active Root if there is a change and primary is
+ * reachable.
+ */
+ primary_eligible =
+ is_peer_active_eligible(primary, afi, safi, name);
+ if (!orr_group->active) {
+ orr_group->active = primary;
+ bgp_orr_igp_metric_register(orr_group, true);
+ } else if (orr_group->primary &&
+ !strmatch(orr_group->active->host,
+ orr_group->primary->host)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+ orr_group->active = primary;
+ bgp_orr_igp_metric_register(orr_group, true);
+ } else
+ bgp_orr_debug("%s: %s", __func__,
+ orr_group->primary
+ ? "No change in Active Root"
+ : "Primary Root is NULL");
+ } else {
+ if (orr_group->primary) {
+ if (orr_group->active &&
+ strmatch(orr_group->active->host,
+ orr_group->primary->host)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+
+ orr_group->active = NULL;
+ }
+ orr_group->primary = NULL;
+ }
+ }
+
+ /* Compare and update Secondary Root Address */
+ if (secondary) {
+ if (!orr_group->secondary ||
+ !strmatch(orr_group->secondary->host, secondary->host))
+ orr_group->secondary = secondary;
+ else
+ bgp_orr_debug("%s: No change in Secondary Root",
+ __func__);
+
+ /* Update Active Root if Primary is not reachable */
+ secondary_eligible =
+ is_peer_active_eligible(secondary, afi, safi, name);
+ if (!orr_group->active) {
+ orr_group->active = secondary;
+ bgp_orr_igp_metric_register(orr_group, true);
+ } else if (!primary_eligible && orr_group->secondary &&
+ !strmatch(orr_group->active->host,
+ orr_group->secondary->host)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+ orr_group->active = secondary;
+ bgp_orr_igp_metric_register(orr_group, true);
+ } else
+ bgp_orr_debug(
+ "%s: %s", __func__,
+ primary_eligible
+ ? "Primary is Active Root"
+ : orr_group->secondary
+ ? "No change in Active Root"
+ : "Secondary Root is NULL");
+ } else {
+ if (orr_group->secondary) {
+ if (orr_group->active &&
+ strmatch(orr_group->active->host,
+ orr_group->secondary->host)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+
+ orr_group->active = NULL;
+ }
+ orr_group->secondary = NULL;
+ }
+ }
+
+ /* Compare and update Tertiary Root Address */
+ if (tertiary) {
+ if (!orr_group->tertiary ||
+ !strmatch(orr_group->tertiary->host, tertiary->host))
+ orr_group->tertiary = tertiary;
+ else
+ bgp_orr_debug("%s: No change in Tertiay Root",
+ __func__);
+
+ /*
+ * Update Active Root if Primary & Secondary are not reachable
+ */
+ tertiary_eligible =
+ is_peer_active_eligible(tertiary, afi, safi, name);
+ if (!orr_group->active) {
+ orr_group->active = tertiary;
+ bgp_orr_igp_metric_register(orr_group, true);
+ } else if (!primary_eligible && !secondary_eligible &&
+ orr_group->tertiary &&
+ !strmatch(orr_group->active->host,
+ orr_group->tertiary->host)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+
+ orr_group->active = tertiary;
+ bgp_orr_igp_metric_register(orr_group, true);
+ } else
+ bgp_orr_debug(
+ "%s: %s", __func__,
+ primary_eligible
+ ? "Primary is Active Root"
+ : secondary_eligible
+ ? "Secondary is Active Root"
+ : !orr_group->tertiary
+ ? "Tertiary Root is NULL"
+ : "No change in Active Root");
+ } else {
+ if (orr_group->tertiary) {
+ if (orr_group->active &&
+ strmatch(orr_group->active->host,
+ orr_group->tertiary->host)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+
+ orr_group->active = NULL;
+ }
+ orr_group->tertiary = NULL;
+ }
+ }
+
+ if (orr_group->active && !primary_eligible && !secondary_eligible &&
+ !tertiary_eligible) {
+ bgp_orr_igp_metric_register(orr_group, false);
+
+ orr_group->active = NULL;
+ }
+
+ bgp_orr_debug("%s: For %s, ORR Group '%s' Active Root is %pBP",
+ __func__, get_afi_safi_str(afi, safi, false), name,
+ orr_group->active);
+
+ return CMD_SUCCESS;
+}
+
+/* Delete BGP Optimal Route Reflection Group */
+int bgp_afi_safi_orr_group_unset(struct bgp *bgp, afi_t afi, safi_t safi,
+ const char *name)
+{
+ struct bgp_orr_group *orr_group;
+
+ orr_group = bgp_orr_group_lookup_by_name(bgp, afi, safi, name);
+ if (!orr_group)
+ return CMD_WARNING;
+
+ /* Check if there are any neighbors configured with this ORR Group */
+ if (orr_group->rr_client_list) {
+ bgp_orr_debug(
+ "%s: For %s, ORR Group '%s' not removed as '%s' is configured on neighbor(s)",
+ __func__,
+ get_afi_safi_str(orr_group->afi, orr_group->safi,
+ false),
+ name, name);
+ return CMD_WARNING;
+ }
+
+ bgp_orr_group_free(orr_group);
+ return CMD_SUCCESS;
+}
+
+/* Set optimal route reflection group to the peer */
+static int peer_orr_group_set(struct peer *peer, afi_t afi, safi_t safi,
+ const char *orr_group_name)
+{
+ struct bgp_orr_group *orr_group = NULL;
+
+ if (!peer)
+ return CMD_WARNING;
+
+ /* Get BGP ORR entry for the given address-family */
+ orr_group = bgp_orr_group_lookup_by_name(peer->bgp, afi, safi,
+ orr_group_name);
+ if (!orr_group) {
+ /* Create BGP ORR entry for the given address-family */
+ orr_group =
+ bgp_orr_group_new(peer->bgp, afi, safi, orr_group_name);
+ }
+
+ /* Skip processing if there is no change in ORR Group */
+ if (peer_af_flag_check(peer, afi, safi, PEER_FLAG_ORR_GROUP)) {
+ if (strmatch(peer->orr_group_name[afi][safi], orr_group_name)) {
+ bgp_orr_debug(
+ "%s: For %s, ORR Group '%s' is already configured on %pBP",
+ __func__, get_afi_safi_str(afi, safi, false),
+ orr_group_name, peer);
+ return CMD_SUCCESS;
+ }
+ /* Remove the peer from ORR Group's peer list */
+ bgp_orr_group_rrclient_update(peer, afi, safi,
+ peer->orr_group_name[afi][safi],
+ false);
+ XFREE(MTYPE_BGP_ORR_GROUP_NAME,
+ peer->orr_group_name[afi][safi]);
+ }
+
+ peer->orr_group_name[afi][safi] =
+ XSTRDUP(MTYPE_BGP_ORR_GROUP_NAME, orr_group_name);
+ SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ORR_GROUP);
+
+ /* Add the peer to ORR Group's client list */
+ bgp_orr_group_rrclient_update(peer, afi, safi, orr_group_name, true);
+
+ /* Update ORR group active root and register with IGP */
+ bgp_peer_update_orr_group_active_root(peer, afi, safi, orr_group);
+
+ return CMD_SUCCESS;
+}
+
+/* Unset optimal route reflection group from the peer*/
+int peer_orr_group_unset(struct peer *peer, afi_t afi, safi_t safi,
+ const char *orr_group_name)
+{
+ struct bgp_orr_group *orr_group = NULL;
+
+ assert(peer && peer->bgp && orr_group_name);
+
+ if (!peer_af_flag_check(peer, afi, safi, PEER_FLAG_ORR_GROUP) ||
+ !strmatch(peer->orr_group_name[afi][safi], orr_group_name)) {
+ bgp_orr_debug(
+ "%s: For %s, ORR Group '%s' is not configured on %pBP",
+ __func__, get_afi_safi_str(afi, safi, false),
+ orr_group_name, peer);
+ return CMD_ERR_NO_MATCH;
+ }
+
+ /* Check if this RR Client is one of the root nodes */
+ orr_group = bgp_orr_group_lookup_by_name(peer->bgp, afi, safi,
+ orr_group_name);
+
+ /* Should not be Null when orr-group is enabled on peer */
+ assert(orr_group);
+
+ /* Check if the peer is one of the root nodes of the ORR group */
+ if (is_orr_root_node(orr_group, peer->host))
+ return CMD_WARNING;
+
+ /* Remove the peer from ORR Group's client list */
+ bgp_orr_group_rrclient_update(peer, afi, safi, orr_group_name, false);
+
+ /* Update ORR group active root and unregister with IGP */
+ bgp_peer_update_orr_group_active_root(peer, afi, safi, orr_group);
+
+ UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ORR_GROUP);
+ XFREE(MTYPE_BGP_ORR_GROUP_NAME, peer->orr_group_name[afi][safi]);
+
+ return CMD_SUCCESS;
+}
+
+int bgp_afi_safi_orr_group_set_vty(struct vty *vty, afi_t afi, safi_t safi,
+ const char *name, const char *primary_str,
+ const char *secondary_str,
+ const char *tertiary_str, bool unset)
+{
+ int ret = CMD_WARNING_CONFIG_FAILED;
+ struct bgp *bgp;
+ struct peer *primary = NULL, *secondary = NULL, *tertiary = NULL;
+
+ bgp = bgp_get_default();
+ if (!bgp) {
+ vty_out(vty, "%% No BGP process is configured\n");
+ return ret;
+ }
+
+ if (unset) {
+ ret = bgp_afi_safi_orr_group_unset(bgp, afi, safi, name);
+ if (ret != CMD_SUCCESS)
+ vty_out(vty,
+ "%% ORR Group %s not removed as '%s' is not found OR configured on neighbor(s)\n",
+ name, name);
+ return ret;
+ }
+
+ primary = peer_and_group_lookup_vty(vty, primary_str);
+ if (!primary || !peer_af_flag_check(primary, afi, safi,
+ PEER_FLAG_REFLECTOR_CLIENT)) {
+ vty_out(vty,
+ "%% Primary Root is not a Route Reflector Client\n");
+ return ret;
+ }
+
+ if (secondary_str) {
+ secondary = peer_and_group_lookup_vty(vty, secondary_str);
+ if (!secondary ||
+ !peer_af_flag_check(secondary, afi, safi,
+ PEER_FLAG_REFLECTOR_CLIENT)) {
+ vty_out(vty,
+ "%% Secondary Root is not a Route Reflector Client\n");
+ return ret;
+ }
+ }
+
+ if (tertiary_str) {
+ tertiary = peer_and_group_lookup_vty(vty, tertiary_str);
+ if (!tertiary ||
+ !peer_af_flag_check(tertiary, afi, safi,
+ PEER_FLAG_REFLECTOR_CLIENT)) {
+ vty_out(vty,
+ "%% Tertiary Root is not a Route Reflector Client\n");
+ return ret;
+ }
+ }
+ return bgp_afi_safi_orr_group_set(bgp, afi, safi, name, primary,
+ secondary, tertiary);
+}
+
+/* Set optimal route reflection group name to the peer. */
+int peer_orr_group_set_vty(struct vty *vty, const char *ip_str, afi_t afi,
+ safi_t safi, const char *orr_group_name, bool unset)
+{
+ int ret = CMD_WARNING_CONFIG_FAILED;
+ struct peer *peer;
+
+ peer = peer_and_group_lookup_vty(vty, ip_str);
+ if (!peer)
+ return ret;
+
+ if (!peer_af_flag_check(peer, afi, safi, PEER_FLAG_REFLECTOR_CLIENT)) {
+ vty_out(vty, "%% Neighbor %s is not a Route Reflector Client\n",
+ peer->host);
+ return ret;
+ }
+
+ if (!unset) {
+ ret = peer_orr_group_set(peer, afi, safi, orr_group_name);
+ if (ret != CMD_SUCCESS)
+ vty_out(vty, "%% ORR Group '%s' is not configured\n",
+ orr_group_name);
+ } else {
+ ret = peer_orr_group_unset(peer, afi, safi, orr_group_name);
+ if (ret == CMD_ERR_NO_MATCH)
+ vty_out(vty,
+ "%% ORR Group '%s' is not configured on %s\n",
+ orr_group_name, peer->host);
+ else if (ret == CMD_WARNING)
+ vty_out(vty,
+ "%% %s is one of the root nodes of ORR Group '%s'.\n",
+ peer->host, orr_group_name);
+ }
+ return bgp_vty_return(vty, ret);
+}
+
+void bgp_config_write_orr(struct vty *vty, struct bgp *bgp, afi_t afi,
+ safi_t safi)
+{
+ struct list *orr_group_list;
+ struct listnode *node;
+ struct bgp_orr_group *orr_group;
+
+ orr_group_list = bgp->orr_group[afi][safi];
+ if (!orr_group_list)
+ return;
+
+ for (ALL_LIST_ELEMENTS_RO(orr_group_list, node, orr_group)) {
+ /* optimal route reflection configuration */
+ vty_out(vty, " optimal-route-reflection %s", orr_group->name);
+ if (orr_group->primary)
+ vty_out(vty, " %s", orr_group->primary->host);
+ if (orr_group->secondary)
+ vty_out(vty, " %s", orr_group->secondary->host);
+ if (orr_group->tertiary)
+ vty_out(vty, " %s", orr_group->tertiary->host);
+ vty_out(vty, "\n");
+ }
+}
+
+static void bgp_show_orr_group(struct vty *vty, struct bgp_orr_group *orr_group,
+ afi_t afi, safi_t safi)
+{
+ char *rrclient = NULL;
+ struct listnode *node;
+ struct bgp_orr_igp_metric *igp_metric = NULL;
+ struct list *orr_group_rrclient_list = NULL;
+ struct list *orr_group_igp_metric_info = NULL;
+
+ if (!orr_group)
+ return;
+
+ vty_out(vty, "\nORR group: %s, %s\n", orr_group->name,
+ get_afi_safi_str(afi, safi, false));
+ vty_out(vty, "Configured root:");
+ vty_out(vty, " primary: %pBP,", orr_group->primary);
+ vty_out(vty, " secondary: %pBP,", orr_group->secondary);
+ vty_out(vty, " tertiary: %pBP\n", orr_group->tertiary);
+ vty_out(vty, "Active Root: %pBP\n", orr_group->active);
+
+ orr_group_rrclient_list = orr_group->rr_client_list;
+ if (!orr_group_rrclient_list)
+ return;
+
+ vty_out(vty, "\nRR Clients mapped:\n");
+
+ for (ALL_LIST_ELEMENTS_RO(orr_group_rrclient_list, node, rrclient))
+ vty_out(vty, "%s\n", rrclient);
+
+ vty_out(vty, "\nNumber of mapping entries: %d\n\n",
+ orr_group_rrclient_list->count);
+
+
+ orr_group_igp_metric_info = orr_group->igp_metric_info;
+ if (!orr_group_igp_metric_info)
+ return;
+ vty_out(vty, "Prefix\t\t\t\t\t\tCost\n");
+ for (ALL_LIST_ELEMENTS_RO(orr_group_igp_metric_info, node,
+ igp_metric)) {
+ vty_out(vty, "%pFX\t\t\t\t\t\t%d\n", &igp_metric->prefix,
+ igp_metric->igp_metric);
+ }
+ vty_out(vty, "\nNumber of mapping entries: %d\n\n",
+ orr_group_igp_metric_info->count);
+}
+
+int bgp_show_orr(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
+ const char *orr_group_name, uint8_t show_flags)
+{
+ struct listnode *node;
+ struct bgp_orr_group *orr_group = NULL;
+ struct list *orr_group_list = NULL;
+ int ret = 0;
+
+ assert(bgp);
+
+ /* Display the matching entries for the given ORR Group */
+ if (orr_group_name) {
+ orr_group = bgp_orr_group_lookup_by_name(bgp, afi, safi,
+ orr_group_name);
+ if (!orr_group) {
+ vty_out(vty, "%% ORR Group %s not found\n",
+ orr_group_name);
+ return CMD_WARNING;
+ }
+ bgp_show_orr_group(vty, orr_group, afi, safi);
+ return ret;
+ }
+ orr_group_list = bgp->orr_group[afi][safi];
+ if (!orr_group_list)
+ return ret;
+
+ for (ALL_LIST_ELEMENTS_RO(orr_group_list, node, orr_group))
+ bgp_show_orr_group(vty, orr_group, afi, safi);
+
+ return ret;
+}
+
+/* Check if the Route Reflector Client belongs to any ORR Group */
+bool peer_orr_rrclient_check(struct peer *peer, afi_t afi, safi_t safi)
+{
+ char *rrclient = NULL;
+ struct listnode *node;
+ struct list *orr_group_list = NULL;
+ struct list *orr_group_rrclient_list = NULL;
+ struct bgp_orr_group *orr_group = NULL;
+
+ assert(peer && peer->bgp);
+
+ orr_group_list = peer->bgp->orr_group[afi][safi];
+ if (!orr_group_list)
+ return false;
+
+ for (ALL_LIST_ELEMENTS_RO(orr_group_list, node, orr_group)) {
+ /* Check if peer configured as primary/secondary/tertiary root
+ */
+ if (is_orr_root_node(orr_group, peer->host))
+ return true;
+ /*
+ * Check if peer is mapped to any ORR Group in this
+ * Address Family.
+ */
+ orr_group_rrclient_list = orr_group->rr_client_list;
+ if (!orr_group_rrclient_list)
+ continue;
+
+ for (ALL_LIST_ELEMENTS_RO(orr_group_rrclient_list, node,
+ rrclient))
+ if (strmatch(rrclient, peer->host))
+ return true;
+ }
+ return false;
+}
+
+static void
+bgp_peer_update_orr_group_active_root(struct peer *peer, afi_t afi, safi_t safi,
+ struct bgp_orr_group *orr_group)
+{
+ assert(peer && orr_group);
+
+ /* Nothing to do if this peer is not one of the root nodes */
+ if (!is_orr_root_node(orr_group, peer->host))
+ return;
+
+ /* Root is reachable and group member, update Active Root if needed */
+ if (is_peer_active_eligible(peer, afi, safi, orr_group->name)) {
+ /* Nothing to do, if this is the current Active Root */
+ if (is_orr_active_root(orr_group, peer->host))
+ return;
+
+ /* If Active is null, update this node as Active Root */
+ if (!orr_group->active) {
+ orr_group->active = peer;
+ bgp_orr_igp_metric_register(orr_group, true);
+ return;
+ }
+
+ /* If this is Primary and current Active is not Primary */
+ if (is_orr_primary_root(orr_group, peer->host)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+ orr_group->active = peer;
+ bgp_orr_igp_metric_register(orr_group, true);
+ return;
+ }
+
+ /*
+ * If this is Secondary and current Active is not
+ * Primary/Secondary
+ */
+ if (is_orr_secondary_root(orr_group, peer->host)) {
+ if (is_orr_active_root(orr_group,
+ orr_group->primary->host))
+ return;
+ bgp_orr_igp_metric_register(orr_group, false);
+ orr_group->active = peer;
+ bgp_orr_igp_metric_register(orr_group, true);
+ return;
+ }
+ return;
+ }
+
+ /* Non Active Root is unreachable, so nothing to do */
+ if (!is_orr_active_root(orr_group, peer->host))
+ return;
+
+ if (is_orr_primary_root(orr_group, peer->host)) {
+ /* If secondary is reachable, update it as Active */
+ if (is_peer_active_eligible(orr_group->secondary, afi, safi,
+ orr_group->name)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+
+ orr_group->active = orr_group->secondary;
+ bgp_orr_igp_metric_register(orr_group, true);
+ return;
+ }
+
+ /* If tertiary is reachable, update it as Active */
+ if (is_peer_active_eligible(orr_group->tertiary, afi, safi,
+ orr_group->name)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+
+ orr_group->active = orr_group->tertiary;
+ bgp_orr_igp_metric_register(orr_group, true);
+ return;
+ }
+ } else {
+ if (is_orr_secondary_root(orr_group, peer->host)) {
+ /* If tertiary is reachable, update it as Active */
+ if (is_peer_active_eligible(orr_group->tertiary, afi,
+ safi, orr_group->name)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+
+ orr_group->active = orr_group->tertiary;
+ bgp_orr_igp_metric_register(orr_group, true);
+ return;
+ }
+ }
+ }
+
+ /* Assign Active as null */
+ bgp_orr_igp_metric_register(orr_group, false);
+ orr_group->active = NULL;
+
+ bgp_orr_debug("%s: For %s, ORR Group '%s' has no active root", __func__,
+ get_afi_safi_str(afi, safi, false),
+ peer->orr_group_name[afi][safi]);
+}
+
+void bgp_peer_update_orr_active_roots(struct peer *peer)
+{
+ afi_t afi;
+ safi_t safi;
+ struct bgp_orr_group *orr_group;
+
+ assert(peer && peer->bgp);
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (!peer->orr_group_name[afi][safi])
+ continue;
+
+ /* Get BGP ORR entry for the given address-family */
+ orr_group = bgp_orr_group_lookup_by_name(
+ peer->bgp, afi, safi, peer->orr_group_name[afi][safi]);
+ assert(orr_group);
+
+ /* Free ORR related memory. */
+ if (peer->status != Deleted) {
+ bgp_peer_update_orr_group_active_root(peer, afi, safi,
+ orr_group);
+ continue;
+ }
+
+ if (!is_orr_root_node(orr_group, peer->host)) {
+ peer_orr_group_unset(peer, afi, safi,
+ peer->orr_group_name[afi][safi]);
+ continue;
+ }
+
+ if (is_orr_primary_root(orr_group, peer->host)) {
+ orr_group->primary = orr_group->secondary;
+ orr_group->secondary = orr_group->tertiary;
+ } else if (is_orr_secondary_root(orr_group, peer->host))
+ orr_group->secondary = orr_group->tertiary;
+ orr_group->tertiary = NULL;
+
+ bgp_afi_safi_orr_group_set(peer->bgp, afi, safi,
+ orr_group->name, orr_group->primary,
+ orr_group->secondary,
+ orr_group->tertiary);
+ peer_orr_group_unset(peer, afi, safi,
+ peer->orr_group_name[afi][safi]);
+ }
+}
+
+/* IGP metric calculated from Active Root */
+static int bgp_orr_igp_metric_update(struct orr_igp_metric_info *table)
+{
+ afi_t afi;
+ safi_t safi;
+ bool add = false;
+ bool root_found = false;
+ uint32_t instId = 0;
+ uint32_t numEntries = 0;
+ uint32_t entry = 0;
+ uint8_t proto = ZEBRA_ROUTE_MAX;
+ struct bgp *bgp = NULL;
+ struct prefix pfx, root = {0};
+
+ struct list *orr_group_list = NULL;
+ struct bgp_orr_group *group = NULL;
+ struct listnode *node, *nnode;
+
+ struct bgp_orr_igp_metric *igp_metric = NULL;
+ struct list *bgp_orr_igp_metric = NULL;
+
+ bgp = bgp_get_default();
+ assert(bgp && table);
+
+ proto = table->proto;
+ afi = family2afi(table->root.family);
+ safi = table->safi;
+ instId = table->instId;
+ add = table->add;
+ numEntries = table->num_entries;
+ prefix_copy(&root, &table->root);
+
+ if ((proto != ZEBRA_ROUTE_OSPF) && (proto != ZEBRA_ROUTE_OSPF6) &&
+ (proto != ZEBRA_ROUTE_ISIS)) {
+ bgp_orr_debug("%s: Message received from unsupported protocol",
+ __func__);
+ return -1;
+ }
+
+ orr_group_list = bgp->orr_group[afi][safi];
+ if (!orr_group_list) {
+ bgp_orr_debug(
+ "%s: Address family %s has no ORR Groups configured",
+ __func__, get_afi_safi_str(afi, safi, false));
+ return -1;
+ }
+
+ if (BGP_DEBUG(optimal_route_reflection, ORR)) {
+ zlog_debug(
+ "[BGP-ORR] %s: Received metric update from protocol %s instance %d",
+ __func__,
+ proto == ZEBRA_ROUTE_ISIS
+ ? "ISIS"
+ : (proto == ZEBRA_ROUTE_OSPF ? "OSPF"
+ : "OSPF6"),
+ instId);
+ zlog_debug("[BGP-ORR] %s: Address family %s", __func__,
+ get_afi_safi_str(afi, safi, false));
+ zlog_debug("[BGP-ORR] %s: Root %pFX", __func__, &root);
+ zlog_debug("[BGP-ORR] %s: Number of entries to be %s %d",
+ __func__, add ? "added" : "deleted", numEntries);
+ zlog_debug("[BGP-ORR] %s: Prefix (Cost) :", __func__);
+ for (entry = 0; entry < numEntries; entry++)
+ zlog_debug("[BGP-ORR] %s: %pFX (%d)", __func__,
+ &table->nexthop[entry].prefix,
+ table->nexthop[entry].metric);
+ }
+ /*
+ * Update IGP metric info of all ORR Groups having this as active root
+ */
+ for (ALL_LIST_ELEMENTS_RO(orr_group_list, node, group)) {
+ if (str2prefix(group->active->host, &pfx) == 0) {
+ bgp_orr_debug("%s: Malformed prefix for %pBP", __func__,
+ group->active);
+ continue;
+ }
+ /*
+ * Copy IGP info if root matches with the active root of the
+ * group
+ */
+ if (prefix_cmp(&pfx, &root) == 0) {
+ if (add) {
+ /* Add new routes */
+ if (!group->igp_metric_info)
+ group->igp_metric_info = list_new();
+
+ bgp_orr_igp_metric = group->igp_metric_info;
+ if (!bgp_orr_igp_metric)
+ bgp_orr_igp_metric_register(group,
+ false);
+ assert(bgp_orr_igp_metric);
+
+ for (entry = 0; entry < numEntries; entry++) {
+ igp_metric = XCALLOC(
+ MTYPE_ORR_IGP_INFO,
+ sizeof(struct
+ bgp_orr_igp_metric));
+ if (!igp_metric)
+ bgp_orr_igp_metric_register(
+ group, false);
+
+ prefix_copy(
+ &igp_metric->prefix,
+ &table->nexthop[entry].prefix);
+ igp_metric->igp_metric =
+ table->nexthop[entry].metric;
+ listnode_add(bgp_orr_igp_metric,
+ igp_metric);
+ }
+ } else {
+ /* Delete old routes */
+ for (entry = 0; entry < numEntries; entry++) {
+ for (ALL_LIST_ELEMENTS(
+ group->igp_metric_info,
+ node, nnode, igp_metric)) {
+ if (prefix_cmp(
+ &igp_metric->prefix,
+ &table->nexthop[entry]
+ .prefix))
+ continue;
+ listnode_delete(
+ group->igp_metric_info,
+ igp_metric);
+ XFREE(MTYPE_ORR_IGP_INFO,
+ igp_metric);
+ }
+ }
+ }
+ root_found = true;
+ break;
+ }
+ }
+ /* Received IGP for root node thats not found in ORR active roots */
+ if (!root_found) {
+ bgp_orr_debug(
+ "%s: Received IGP SPF information for root %pFX which is not an ORR active root",
+ __func__, &root);
+ }
+ assert(root_found);
+ return 0;
+}
+
+/* Register with IGP for sending SPF info */
+static void bgp_orr_igp_metric_register(struct bgp_orr_group *orr_group,
+ bool reg)
+{
+ int ret;
+ struct orr_igp_metric_reg msg;
+ struct prefix p;
+ char *rr_client = NULL;
+
+ assert(orr_group);
+
+ if (!orr_group->active)
+ return;
+
+ memset(&msg, 0, sizeof(msg));
+ ret = str2prefix(orr_group->active->host, &p);
+
+ /* Malformed prefix */
+ assert(ret);
+
+ /* Check if the active root is part of this ORR group */
+ rr_client = bgp_orr_group_rrclient_lookup(orr_group,
+ orr_group->active->host);
+ if (reg && !rr_client) {
+ bgp_orr_debug(
+ "%s: active root %pBP is not part of this ORR group",
+ __func__, orr_group->active);
+ return;
+ }
+
+ msg.reg = reg;
+ msg.proto = ZEBRA_ROUTE_BGP;
+ msg.safi = orr_group->safi;
+ prefix_copy(&msg.prefix, &p);
+ strlcpy(msg.group_name, orr_group->name, sizeof(msg.group_name));
+
+ bgp_orr_debug(
+ "%s: %s with IGP for metric calculation from location %pFX",
+ __func__, reg ? "Register" : "Unregister", &msg.prefix);
+
+ if (zclient_send_opaque(zclient, ORR_IGP_METRIC_REGISTER,
+ (uint8_t *)&msg,
+ sizeof(msg)) == ZCLIENT_SEND_FAILURE)
+ zlog_warn("[BGP-ORR] %s: Failed to send message to IGP.",
+ __func__);
+
+ /* Free IGP metric info calculated from previous active location */
+ if (!reg && orr_group->igp_metric_info)
+ list_delete(&orr_group->igp_metric_info);
+}
+
+/* BGP ORR message processing */
+int bgg_orr_message_process(enum bgp_orr_msg_type msg_type, void *msg)
+{
+ int ret = 0;
+
+ assert(msg && msg_type > BGP_ORR_IMSG_INVALID &&
+ msg_type < BGP_ORR_IMSG_MAX);
+ switch (msg_type) {
+ case BGP_ORR_IMSG_GROUP_CREATE:
+ break;
+ case BGP_ORR_IMSG_GROUP_DELETE:
+ break;
+ case BGP_ORR_IMSG_GROUP_UPDATE:
+ break;
+ case BGP_ORR_IMSG_SET_ORR_ON_PEER:
+ break;
+ case BGP_ORR_IMSG_UNSET_ORR_ON_PEER:
+ break;
+ case BGP_ORR_IMSG_IGP_METRIC_UPDATE:
+ ret = bgp_orr_igp_metric_update(
+ (struct orr_igp_metric_info *)msg);
+ break;
+ case BGP_ORR_IMSG_SHOW_ORR:
+ /* bgp_show_orr */
+ break;
+ case BGP_ORR_IMSG_SHOW_ORR_GROUP:
+ /* bgp_show_orr_group */
+ break;
+ default:
+ break;
+ }
+
+ /* Free Memory */
+ return ret;
+}
+
+/*
+ * Cleanup ORR information - invoked at the time of bgpd exit or
+ * when the BGP instance (default) is being freed.
+ */
+void bgp_orr_cleanup(struct bgp *bgp)
+{
+ afi_t afi;
+ safi_t safi;
+ struct listnode *node, *nnode;
+ struct bgp_orr_group *orr_group;
+
+ assert(bgp);
+
+ if (!bgp->orr_group_count)
+ return;
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ for (ALL_LIST_ELEMENTS(bgp->orr_group[afi][safi], node, nnode,
+ orr_group))
+ bgp_orr_group_free(orr_group);
+ }
+}
diff --git a/bgpd/bgp_orr.h b/bgpd/bgp_orr.h
new file mode 100644
index 000000000..158de3034
--- /dev/null
+++ b/bgpd/bgp_orr.h
@@ -0,0 +1,102 @@
+/*
+ * BGP Optimal Route Reflection
+ * Copyright (C) 2021 Samsung R&D Institute India - Bangalore.
+ * Madhurilatha Kuruganti
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _FRR_BGP_ORR_H
+#define _FRR_BGP_ORR_H
+#include <zebra.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Macro to log debug message */
+#define bgp_orr_debug(...) \
+ do { \
+ if (BGP_DEBUG(optimal_route_reflection, ORR)) \
+ zlog_debug("[BGP-ORR] " __VA_ARGS__); \
+ } while (0)
+
+
+/* BGP ORR Message Type */
+enum bgp_orr_msg_type {
+ BGP_ORR_IMSG_INVALID = 0,
+
+ /* ORR group update */
+ BGP_ORR_IMSG_GROUP_CREATE = 1,
+ BGP_ORR_IMSG_GROUP_DELETE,
+ BGP_ORR_IMSG_GROUP_UPDATE,
+
+ /* ORR group update on a BGP RR Client */
+ BGP_ORR_IMSG_SET_ORR_ON_PEER = 4,
+ BGP_ORR_IMSG_UNSET_ORR_ON_PEER,
+
+ /* ORR IGP Metric Update from IGP from requested Location */
+ BGP_ORR_IMSG_IGP_METRIC_UPDATE = 6,
+
+ /* ORR Group Related Information display */
+ BGP_ORR_IMSG_SHOW_ORR = 7,
+ BGP_ORR_IMSG_SHOW_ORR_GROUP,
+
+ /* Invalid Message Type*/
+ BGP_ORR_IMSG_MAX
+};
+
+extern struct zclient *zclient;
+
+extern void bgp_config_write_orr(struct vty *vty, struct bgp *bgp, afi_t afi,
+ safi_t safi);
+
+extern int bgp_afi_safi_orr_group_set_vty(struct vty *vty, afi_t afi,
+ safi_t safi, const char *name,
+ const char *primary_str,
+ const char *secondary_str,
+ const char *tertiary_str, bool unset);
+extern int peer_orr_group_unset(struct peer *peer, afi_t afi, safi_t safi,
+ const char *orr_group_name);
+extern int peer_orr_group_set_vty(struct vty *vty, const char *ip_str,
+ afi_t afi, safi_t safi,
+ const char *orr_group_name, bool unset);
+extern bool peer_orr_rrclient_check(struct peer *peer, afi_t afi, safi_t safi);
+
+extern int bgp_show_orr(struct vty *vty, struct bgp *bgp, afi_t afi,
+ safi_t safi, const char *orr_group_name,
+ uint8_t show_flags);
+
+extern int bgp_afi_safi_orr_group_set(struct bgp *bgp, afi_t afi, safi_t safi,
+ const char *name, struct peer *primary,
+ struct peer *secondary,
+ struct peer *tertiary);
+extern int bgp_afi_safi_orr_group_unset(struct bgp *bgp, afi_t afi, safi_t safi,
+ const char *name);
+
+extern void bgp_peer_update_orr_active_roots(struct peer *peer);
+
+extern int bgg_orr_message_process(enum bgp_orr_msg_type msg_type, void *msg);
+
+extern struct bgp_orr_group *bgp_orr_group_lookup_by_name(struct bgp *bgp,
+ afi_t afi,
+ safi_t safi,
+ const char *name);
+extern void bgp_orr_cleanup(struct bgp *bgp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FRR_BGP_ORR_H */
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 7d4110029..f6b6cb93d 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -72,6 +72,7 @@
#include "bgpd/bgp_addpath.h"
#include "bgpd/bgp_mac.h"
#include "bgpd/bgp_network.h"
+#include "bgpd/bgp_orr.h"
#include "bgpd/bgp_trace.h"
#include "bgpd/bgp_rpki.h"
@@ -102,10 +103,6 @@ DEFINE_HOOK(bgp_rpki_prefix_status,
const struct prefix *prefix),
(peer, attr, prefix));
-/* Render dest to prefix_rd based on safi */
-static const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest,
- safi_t safi);
-
/* Extern from bgp_dump.c */
extern const char *bgp_origin_str[];
extern const char *bgp_origin_long_str[];
@@ -567,6 +564,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
enum bgp_path_selection_reason *reason)
{
const struct prefix *new_p;
+ struct prefix exist_p;
struct attr *newattr, *existattr;
enum bgp_peer_sort new_sort;
enum bgp_peer_sort exist_sort;
@@ -599,6 +597,11 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
bool new_origin, exist_origin;
struct bgp_path_info *bpi_ultimate;
+ struct bgp_orr_group *orr_group = NULL;
+ struct listnode *node;
+ struct bgp_orr_igp_metric *igp_metric = NULL;
+ struct list *orr_group_igp_metric_info = NULL;
+
*paths_eq = 0;
/* 0. Null check. */
@@ -874,6 +877,49 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
return 0;
}
+ /* If a BGP speaker supports ACCEPT_OWN and is configured for the
+ * extensions defined in this document, the following step is inserted
+ * after the LOCAL_PREF comparison step in the BGP decision process:
+ * When comparing a pair of routes for a BGP destination, the
+ * route with the ACCEPT_OWN community attached is preferred over
+ * the route that does not have the community.
+ * This extra step MUST only be invoked during the best path selection
+ * process of VPN-IP routes.
+ */
+ if (safi == SAFI_MPLS_VPN &&
+ (CHECK_FLAG(new->peer->af_flags[afi][safi], PEER_FLAG_ACCEPT_OWN) ||
+ CHECK_FLAG(exist->peer->af_flags[afi][safi],
+ PEER_FLAG_ACCEPT_OWN))) {
+ bool new_accept_own = false;
+ bool exist_accept_own = false;
+ uint32_t accept_own = COMMUNITY_ACCEPT_OWN;
+
+ if (newattr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))
+ new_accept_own = community_include(
+ bgp_attr_get_community(newattr), accept_own);
+ if (existattr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))
+ exist_accept_own = community_include(
+ bgp_attr_get_community(existattr), accept_own);
+
+ if (new_accept_own && !exist_accept_own) {
+ *reason = bgp_path_selection_accept_own;
+ if (debug)
+ zlog_debug(
+ "%s: %s wins over %s due to accept-own",
+ pfx_buf, new_buf, exist_buf);
+ return 1;
+ }
+
+ if (!new_accept_own && exist_accept_own) {
+ *reason = bgp_path_selection_accept_own;
+ if (debug)
+ zlog_debug(
+ "%s: %s loses to %s due to accept-own",
+ pfx_buf, new_buf, exist_buf);
+ return 0;
+ }
+ }
+
/* 3. Local route check. We prefer:
* - BGP_ROUTE_STATIC
* - BGP_ROUTE_AGGREGATE
@@ -1061,6 +1107,49 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
if (exist->extra)
existm = exist->extra->igpmetric;
+ if (new->peer->orr_group_name[afi][safi]) {
+ ret = str2prefix(new->peer->host, &exist_p);
+ orr_group = bgp_orr_group_lookup_by_name(
+ bgp, afi, safi, new->peer->orr_group_name[afi][safi]);
+ if (orr_group) {
+ orr_group_igp_metric_info = orr_group->igp_metric_info;
+ if (orr_group_igp_metric_info) {
+ for (ALL_LIST_ELEMENTS_RO(
+ orr_group_igp_metric_info, node,
+ igp_metric)) {
+ if (ret &&
+ prefix_cmp(&exist_p,
+ &igp_metric->prefix) ==
+ 0) {
+ newm = igp_metric->igp_metric;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (exist->peer->orr_group_name[afi][safi]) {
+ ret = str2prefix(exist->peer->host, &exist_p);
+ orr_group = bgp_orr_group_lookup_by_name(
+ bgp, afi, safi, exist->peer->orr_group_name[afi][safi]);
+ if (orr_group) {
+ orr_group_igp_metric_info = orr_group->igp_metric_info;
+ if (orr_group_igp_metric_info) {
+ for (ALL_LIST_ELEMENTS_RO(
+ orr_group_igp_metric_info, node,
+ igp_metric)) {
+ if (ret &&
+ prefix_cmp(&exist_p,
+ &igp_metric->prefix) ==
+ 0) {
+ existm = igp_metric->igp_metric;
+ break;
+ }
+ }
+ }
+ }
+ }
+
if (newm < existm) {
if (debug && peer_sort_ret < 0)
zlog_debug(
@@ -3833,6 +3922,60 @@ static void bgp_attr_add_no_export_community(struct attr *attr)
bgp_attr_set_community(attr, new);
}
+static bool bgp_accept_own(struct peer *peer, afi_t afi, safi_t safi,
+ struct attr *attr, const struct prefix *prefix,
+ int *sub_type)
+{
+ struct listnode *node, *nnode;
+ struct bgp *bgp;
+ bool accept_own_found = false;
+
+ if (safi != SAFI_MPLS_VPN)
+ return false;
+
+ /* Processing of the ACCEPT_OWN community is enabled by configuration */
+ if (!CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ACCEPT_OWN))
+ return false;
+
+ /* The route in question carries the ACCEPT_OWN community */
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)) {
+ struct community *comm = bgp_attr_get_community(attr);
+
+ if (community_include(comm, COMMUNITY_ACCEPT_OWN))
+ accept_own_found = true;
+ }
+
+ /* The route in question is targeted to one or more destination VRFs
+ * on the router (as determined by inspecting the Route Target(s)).
+ */
+ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
+ if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
+ continue;
+
+ if (accept_own_found &&
+ ecommunity_include(
+ bgp->vpn_policy[afi]
+ .rtlist[BGP_VPN_POLICY_DIR_TOVPN],
+ bgp_attr_get_ecommunity(attr))) {
+ if (bgp_debug_update(peer, prefix, NULL, 1))
+ zlog_debug(
+ "%pBP prefix %pFX has ORIGINATOR_ID, but it's accepted due to ACCEPT_OWN",
+ peer, prefix);
+
+ /* Treat this route as imported, because it's leaked
+ * already from another VRF, and we got an updated
+ * version from route-reflector with ACCEPT_OWN
+ * community.
+ */
+ *sub_type = BGP_ROUTE_IMPORTED;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
struct attr *attr, afi_t afi, safi_t safi, int type,
int sub_type, struct prefix_rd *prd, mpls_label_t *label,
@@ -3854,8 +3997,6 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
int do_loop_check = 1;
int has_valid_label = 0;
afi_t nh_afi;
- uint8_t pi_type = 0;
- uint8_t pi_sub_type = 0;
bool force_evpn_import = false;
safi_t orig_safi = safi;
bool leak_success = true;
@@ -3948,12 +4089,20 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
}
}
- /* Route reflector originator ID check. */
+ /* Route reflector originator ID check. If ACCEPT_OWN mechanism is
+ * enabled, then take care of that too.
+ */
+ bool accept_own = false;
+
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)
&& IPV4_ADDR_SAME(&bgp->router_id, &attr->originator_id)) {
- peer->stat_pfx_originator_loop++;
- reason = "originator is us;";
- goto filtered;
+ accept_own =
+ bgp_accept_own(peer, afi, safi, attr, p, &sub_type);
+ if (!accept_own) {
+ peer->stat_pfx_originator_loop++;
+ reason = "originator is us;";
+ goto filtered;
+ }
}
/* Route reflector cluster ID check. */
@@ -4059,15 +4208,10 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
bgp_attr_add_gshut_community(&new_attr);
}
- if (pi) {
- pi_type = pi->type;
- pi_sub_type = pi->sub_type;
- }
-
/* next hop check. */
- if (!CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD)
- && bgp_update_martian_nexthop(bgp, afi, safi, pi_type, pi_sub_type,
- &new_attr, dest)) {
+ if (!CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD) &&
+ bgp_update_martian_nexthop(bgp, afi, safi, type, sub_type,
+ &new_attr, dest)) {
peer->stat_pfx_nh_invalid++;
reason = "martian or self next-hop;";
bgp_attr_flush(&new_attr);
@@ -4456,8 +4600,13 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
bgp_path_info_unset_flag(dest, pi,
BGP_PATH_VALID);
}
- } else
+ } else {
+ if (accept_own)
+ bgp_path_info_set_flag(dest, pi,
+ BGP_PATH_ACCEPT_OWN);
+
bgp_path_info_set_flag(dest, pi, BGP_PATH_VALID);
+ }
#ifdef ENABLE_BGP_VNC
if (safi == SAFI_MPLS_VPN) {
@@ -4507,8 +4656,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
}
if ((SAFI_MPLS_VPN == safi)
&& (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
-
- leak_success = vpn_leak_to_vrf_update(bgp, pi);
+ leak_success = vpn_leak_to_vrf_update(bgp, pi, prd);
}
#ifdef ENABLE_BGP_VNC
@@ -4616,8 +4764,12 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
}
bgp_path_info_unset_flag(dest, new, BGP_PATH_VALID);
}
- } else
+ } else {
+ if (accept_own)
+ bgp_path_info_set_flag(dest, new, BGP_PATH_ACCEPT_OWN);
+
bgp_path_info_set_flag(dest, new, BGP_PATH_VALID);
+ }
/* Addpath ID */
new->addpath_rx_id = addpath_id;
@@ -4663,7 +4815,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
}
if ((SAFI_MPLS_VPN == safi)
&& (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
- leak_success = vpn_leak_to_vrf_update(bgp, new);
+ leak_success = vpn_leak_to_vrf_update(bgp, new, prd);
}
#ifdef ENABLE_BGP_VNC
if (SAFI_MPLS_VPN == safi) {
@@ -6384,7 +6536,8 @@ static void bgp_static_update_safi(struct bgp *bgp, const struct prefix *p,
if (SAFI_MPLS_VPN == safi
&& bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
- vpn_leak_to_vrf_update(bgp, pi);
+ vpn_leak_to_vrf_update(bgp, pi,
+ &bgp_static->prd);
}
#ifdef ENABLE_BGP_VNC
rfapiProcessUpdate(pi->peer, NULL, p, &bgp_static->prd,
@@ -6424,7 +6577,7 @@ static void bgp_static_update_safi(struct bgp *bgp, const struct prefix *p,
if (SAFI_MPLS_VPN == safi
&& bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
- vpn_leak_to_vrf_update(bgp, new);
+ vpn_leak_to_vrf_update(bgp, new, &bgp_static->prd);
}
#ifdef ENABLE_BGP_VNC
rfapiProcessUpdate(new->peer, NULL, p, &bgp_static->prd, new->attr, afi,
@@ -8783,6 +8936,8 @@ const char *bgp_path_selection_reason2str(enum bgp_path_selection_reason reason)
return "Weight";
case bgp_path_selection_local_pref:
return "Local Pref";
+ case bgp_path_selection_accept_own:
+ return "Accept Own";
case bgp_path_selection_local_route:
return "Local Route";
case bgp_path_selection_confed_as_path:
@@ -11859,8 +12014,8 @@ static void bgp_show_path_info(const struct prefix_rd *pfx_rd,
/*
* Return rd based on safi
*/
-static const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest,
- safi_t safi)
+const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest,
+ safi_t safi)
{
switch (safi) {
case SAFI_MPLS_VPN:
@@ -11869,7 +12024,6 @@ static const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest,
return (struct prefix_rd *)(bgp_dest_get_prefix(dest));
default:
return NULL;
-
}
}
@@ -12203,8 +12357,10 @@ DEFUN (show_ip_bgp_large_community,
return CMD_WARNING;
if (argv_find(argv, argc, "AA:BB:CC", &idx)) {
- if (argv_find(argv, argc, "exact-match", &idx))
+ if (argv_find(argv, argc, "exact-match", &idx)) {
+ argc--;
exact_match = 1;
+ }
return bgp_show_lcommunity(vty, bgp, argc, argv,
exact_match, afi, safi, uj);
} else
@@ -12411,6 +12567,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
|alias ALIAS_NAME\
|A.B.C.D/M longer-prefixes\
|X:X::X:X/M longer-prefixes\
+ |optimal-route-reflection [WORD$orr_group_name]\
] [json$uj [detail$detail] | wide$wide]",
SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR BGP_AFI_HELP_STR
BGP_SAFI_WITH_LABEL_HELP_STR
@@ -12459,6 +12616,8 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
"Display route and more specific routes\n"
"IPv6 prefix\n"
"Display route and more specific routes\n"
+ "Display Optimal Route Reflection RR Clients\n"
+ "ORR Group name\n"
JSON_STR
"Display detailed version of JSON output\n"
"Increase table width for longer prefixes\n")
@@ -12475,6 +12634,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
uint16_t show_flags = 0;
enum rpki_states rpki_target_state = RPKI_NOT_BEING_USED;
struct prefix p;
+ bool orr_group = false;
if (uj) {
argc--;
@@ -12649,12 +12809,18 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
output_arg = &p;
}
+ if (argv_find(argv, argc, "optimal-route-reflection", &idx))
+ orr_group = true;
+
if (!all) {
/* show bgp: AFI_IP6, show ip bgp: AFI_IP */
if (community)
return bgp_show_community(vty, bgp, community,
exact_match, afi, safi,
show_flags);
+ else if (orr_group)
+ return bgp_show_orr(vty, bgp, afi, safi, orr_group_name,
+ show_flags);
else
return bgp_show(vty, bgp, afi, safi, sh_type,
output_arg, show_flags,
@@ -12700,6 +12866,11 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
vty, abgp, community,
exact_match, afi, safi,
show_flags);
+ else if (orr_group)
+ bgp_show_orr(vty, bgp, afi,
+ safi,
+ orr_group_name,
+ show_flags);
else
bgp_show(vty, abgp, afi, safi,
sh_type, output_arg,
@@ -12739,6 +12910,11 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
vty, abgp, community,
exact_match, afi, safi,
show_flags);
+ else if (orr_group)
+ bgp_show_orr(vty, bgp, afi,
+ safi,
+ orr_group_name,
+ show_flags);
else
bgp_show(vty, abgp, afi, safi,
sh_type, output_arg,
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index ddef4ca1b..22d28ecd0 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -289,7 +289,7 @@ struct bgp_path_info {
int lock;
/* BGP information status. */
- uint16_t flags;
+ uint32_t flags;
#define BGP_PATH_IGP_CHANGED (1 << 0)
#define BGP_PATH_DAMPED (1 << 1)
#define BGP_PATH_HISTORY (1 << 2)
@@ -306,6 +306,7 @@ struct bgp_path_info {
#define BGP_PATH_RIB_ATTR_CHG (1 << 13)
#define BGP_PATH_ANNC_NH_SELF (1 << 14)
#define BGP_PATH_LINK_BW_CHG (1 << 15)
+#define BGP_PATH_ACCEPT_OWN (1 << 16)
/* BGP route type. This can be static, RIP, OSPF, BGP etc. */
uint8_t type;
@@ -852,4 +853,6 @@ extern void subgroup_announce_reset_nhop(uint8_t family, struct attr *attr);
const char *
bgp_path_selection_reason2str(enum bgp_path_selection_reason reason);
extern bool bgp_addpath_encode_rx(struct peer *peer, afi_t afi, safi_t safi);
+extern const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest,
+ safi_t safi);
#endif /* _QUAGGA_BGP_ROUTE_H */
diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c
index b90c09c68..cb7afd896 100644
--- a/bgpd/bgp_rpki.c
+++ b/bgpd/bgp_rpki.c
@@ -592,7 +592,7 @@ static int bgp_rpki_module_init(void)
hook_register(bgp_rpki_prefix_status, rpki_validate_prefix);
hook_register(frr_late_init, bgp_rpki_init);
- hook_register(frr_early_fini, &bgp_rpki_fini);
+ hook_register(frr_early_fini, bgp_rpki_fini);
return 0;
}
@@ -1688,7 +1688,7 @@ DEFUN_YANG (no_match_rpki,
const char *xpath =
"./match-condition[condition='frr-bgp-route-map:rpki']";
- nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(vty, NULL);
}
diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h
index 86cd4f3da..91d92ebd6 100644
--- a/bgpd/bgp_table.h
+++ b/bgpd/bgp_table.h
@@ -63,6 +63,7 @@ enum bgp_path_selection_reason {
bgp_path_selection_evpn_lower_ip,
bgp_path_selection_weight,
bgp_path_selection_local_pref,
+ bgp_path_selection_accept_own,
bgp_path_selection_local_route,
bgp_path_selection_confed_as_path,
bgp_path_selection_as_path,
diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c
index 27e367770..72e70ebf9 100644
--- a/bgpd/bgp_updgrp_adv.c
+++ b/bgpd/bgp_updgrp_adv.c
@@ -355,6 +355,11 @@ static int update_group_announce_walkcb(struct update_group *updgrp, void *arg)
struct update_subgroup *subgrp;
UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
+ /* Avoid supressing duplicate routes later
+ * when processing in subgroup_announce_table().
+ */
+ SET_FLAG(subgrp->sflags, SUBGRP_STATUS_FORCE_UPDATES);
+
subgroup_announce_all(subgrp);
}
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 9a4e4b7af..e574ae780 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -78,6 +78,8 @@
#ifdef ENABLE_BGP_VNC
#include "bgpd/rfapi/bgp_rfapi_cfg.h"
#endif
+#include "bgpd/bgp_orr.h"
+
FRR_CFG_DEFAULT_BOOL(BGP_IMPORT_CHECK,
{
@@ -295,10 +297,9 @@ static int bgp_srv6_locator_unset(struct bgp *bgp)
{
int ret;
struct listnode *node, *nnode;
- struct srv6_locator_chunk *chunk;
+ struct srv6_locator_chunk *chunk, *tovpn_sid_locator;
struct bgp_srv6_function *func;
struct bgp *bgp_vrf;
- struct in6_addr *tovpn_sid;
/* release chunk notification via ZAPI */
ret = bgp_zebra_srv6_manager_release_locator_chunk(
@@ -324,16 +325,12 @@ static int bgp_srv6_locator_unset(struct bgp *bgp)
continue;
/* refresh vpnv4 tovpn_sid */
- tovpn_sid = bgp_vrf->vpn_policy[AFI_IP].tovpn_sid;
- if (tovpn_sid)
- XFREE(MTYPE_BGP_SRV6_SID,
- bgp_vrf->vpn_policy[AFI_IP].tovpn_sid);
+ XFREE(MTYPE_BGP_SRV6_SID,
+ bgp_vrf->vpn_policy[AFI_IP].tovpn_sid);
/* refresh vpnv6 tovpn_sid */
- tovpn_sid = bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid;
- if (tovpn_sid)
- XFREE(MTYPE_BGP_SRV6_SID,
- bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid);
+ XFREE(MTYPE_BGP_SRV6_SID,
+ bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid);
}
/* update vpn bgp processes */
@@ -345,12 +342,20 @@ static int bgp_srv6_locator_unset(struct bgp *bgp)
continue;
/* refresh vpnv4 tovpn_sid_locator */
- XFREE(MTYPE_BGP_SRV6_SID,
- bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_locator);
+ tovpn_sid_locator =
+ bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_locator;
+ if (tovpn_sid_locator) {
+ srv6_locator_chunk_free(tovpn_sid_locator);
+ bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_locator = NULL;
+ }
/* refresh vpnv6 tovpn_sid_locator */
- XFREE(MTYPE_BGP_SRV6_SID,
- bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_locator);
+ tovpn_sid_locator =
+ bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_locator;
+ if (tovpn_sid_locator) {
+ srv6_locator_chunk_free(tovpn_sid_locator);
+ bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_locator = NULL;
+ }
}
/* clear locator name */
@@ -873,9 +878,6 @@ int bgp_vty_return(struct vty *vty, enum bgp_create_error_code ret)
case BGP_ERR_REMOVE_PRIVATE_AS:
str = "remove-private-AS cannot be configured for IBGP peers";
break;
- case BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP:
- str = "Local-AS allowed only for EBGP peers";
- break;
case BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS:
str = "Cannot have local-as same as BGP AS number";
break;
@@ -936,9 +938,6 @@ int bgp_vty_return(struct vty *vty, enum bgp_create_error_code ret)
case BGP_ERR_AF_UNCONFIGURED:
str = "AFI/SAFI specified is not currently configured.";
break;
- case BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS_REMOTE_AS:
- str = "AS specified for local as is the same as the remote as and this is not allowed.";
- break;
case BGP_ERR_INVALID_AS:
str = "Confederation AS specified is the same AS as our AS.";
break;
@@ -948,6 +947,9 @@ int bgp_vty_return(struct vty *vty, enum bgp_create_error_code ret)
case BGP_ERR_INVALID_INTERNAL_ROLE:
str = "External roles can be set only on eBGP session";
break;
+ case BGP_ERR_PEER_ORR_CONFIGURED:
+ str = "Deconfigure optimal-route-reflection on this peer first";
+ break;
}
if (str) {
vty_out(vty, "%% %s\n", str);
@@ -2354,6 +2356,15 @@ void bgp_config_write_coalesce_time(struct vty *vty, struct bgp *bgp)
vty_out(vty, " coalesce-time %u\n", bgp->coalesce_time);
}
+/* BGP TCP keepalive */
+static void bgp_config_tcp_keepalive(struct vty *vty, struct bgp *bgp)
+{
+ if (bgp->tcp_keepalive_idle) {
+ vty_out(vty, " bgp tcp-keepalive %u %u %u\n",
+ bgp->tcp_keepalive_idle, bgp->tcp_keepalive_intvl,
+ bgp->tcp_keepalive_probes);
+ }
+}
DEFUN (bgp_coalesce_time,
bgp_coalesce_time_cmd,
@@ -2577,6 +2588,38 @@ DEFUN(no_bgp_minimum_holdtime, no_bgp_minimum_holdtime_cmd,
return CMD_SUCCESS;
}
+DEFPY(bgp_tcp_keepalive, bgp_tcp_keepalive_cmd,
+ "bgp tcp-keepalive (1-65535)$idle (1-65535)$intvl (1-30)$probes",
+ BGP_STR
+ "TCP keepalive parameters\n"
+ "TCP keepalive idle time (seconds)\n"
+ "TCP keepalive interval (seconds)\n"
+ "TCP keepalive maximum probes\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ bgp_tcp_keepalive_set(bgp, (uint16_t)idle, (uint16_t)intvl,
+ (uint16_t)probes);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(no_bgp_tcp_keepalive, no_bgp_tcp_keepalive_cmd,
+ "no bgp tcp-keepalive [(1-65535) (1-65535) (1-30)]",
+ NO_STR
+ BGP_STR
+ "TCP keepalive parameters\n"
+ "TCP keepalive idle time (seconds)\n"
+ "TCP keepalive interval (seconds)\n"
+ "TCP keepalive maximum probes\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ bgp_tcp_keepalive_unset(bgp);
+
+ return CMD_SUCCESS;
+}
+
DEFUN (bgp_client_to_client_reflection,
bgp_client_to_client_reflection_cmd,
"bgp client-to-client reflection",
@@ -6163,6 +6206,43 @@ ALIAS_HIDDEN(no_neighbor_route_reflector_client,
NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
"Configure a neighbor as Route Reflector client\n")
+/* optimal-route-reflection Root Routers configuration */
+DEFPY (optimal_route_reflection,
+ optimal_route_reflection_cmd,
+ "[no$no] optimal-route-reflection WORD$orr_group [<A.B.C.D|X:X::X:X>$primary [<A.B.C.D|X:X::X:X>$secondary [<A.B.C.D|X:X::X:X>$tertiary]]]",
+ NO_STR
+ "Create ORR group and assign root router(s)\n"
+ "ORR Group name\n"
+ "Primary Root address\n"
+ "Primary Root IPv6 address\n"
+ "Secondary Root address\n"
+ "Secondary Root IPv6 address\n"
+ "Tertiary Root address\n"
+ "Tertiary Root IPv6 address\n")
+{
+ if (!no && !primary) {
+ vty_out(vty, "%% Specify Primary Root address\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ return bgp_afi_safi_orr_group_set_vty(
+ vty, bgp_node_afi(vty), bgp_node_safi(vty), orr_group,
+ primary_str, secondary_str, tertiary_str, !!no);
+}
+
+/* neighbor optimal-route-reflection group*/
+DEFPY (neighbor_optimal_route_reflection,
+ neighbor_optimal_route_reflection_cmd,
+ "[no$no] neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor optimal-route-reflection WORD$orr_group",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Apply ORR group configuration to the neighbor\n"
+ "ORR group name\n")
+{
+ return peer_orr_group_set_vty(vty, neighbor, bgp_node_afi(vty),
+ bgp_node_safi(vty), orr_group, !!no);
+}
+
/* neighbor route-server-client. */
DEFUN (neighbor_route_server_client,
neighbor_route_server_client_cmd,
@@ -8247,6 +8327,32 @@ ALIAS_HIDDEN(
"Only give warning message when limit is exceeded\n"
"Force checking all received routes not only accepted\n")
+/* "neighbor accept-own" */
+DEFPY (neighbor_accept_own,
+ neighbor_accept_own_cmd,
+ "[no$no] neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor accept-own",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Enable handling of self-originated VPN routes containing ACCEPT_OWN community\n")
+{
+ struct peer *peer;
+ afi_t afi = bgp_node_afi(vty);
+ safi_t safi = bgp_node_safi(vty);
+ int ret;
+
+ peer = peer_and_group_lookup_vty(vty, neighbor);
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ if (no)
+ ret = peer_af_flag_unset(peer, afi, safi, PEER_FLAG_ACCEPT_OWN);
+ else
+ ret = peer_af_flag_set(peer, afi, safi, PEER_FLAG_ACCEPT_OWN);
+
+ return bgp_vty_return(vty, ret);
+}
+
/* "neighbor soo" */
DEFPY (neighbor_soo,
neighbor_soo_cmd,
@@ -8860,7 +8966,7 @@ DEFPY (af_label_vpn_export,
DEFPY (af_sid_vpn_export,
af_sid_vpn_export_cmd,
- "[no] sid vpn export <(1-255)$sid_idx|auto$sid_auto>",
+ "[no] sid vpn export <(1-1048575)$sid_idx|auto$sid_auto>",
NO_STR
"sid value for VRF\n"
"Between current address-family and vpn\n"
@@ -9637,11 +9743,7 @@ DEFPY (show_bgp_srv6,
struct listnode *node;
struct srv6_locator_chunk *chunk;
struct bgp_srv6_function *func;
- struct in6_addr *tovpn4_sid;
- struct in6_addr *tovpn6_sid;
char buf[256];
- char buf_tovpn4_sid[256];
- char buf_tovpn6_sid[256];
bgp = bgp_get_default();
if (!bgp)
@@ -9664,19 +9766,10 @@ DEFPY (show_bgp_srv6,
vty_out(vty, "- name: %s\n",
bgp->name ? bgp->name : "default");
- tovpn4_sid = bgp->vpn_policy[AFI_IP].tovpn_sid;
- tovpn6_sid = bgp->vpn_policy[AFI_IP6].tovpn_sid;
- if (tovpn4_sid)
- inet_ntop(AF_INET6, tovpn4_sid, buf_tovpn4_sid,
- sizeof(buf_tovpn4_sid));
- if (tovpn6_sid)
- inet_ntop(AF_INET6, tovpn6_sid, buf_tovpn6_sid,
- sizeof(buf_tovpn6_sid));
-
- vty_out(vty, " vpn_policy[AFI_IP].tovpn_sid: %s\n",
- tovpn4_sid ? buf_tovpn4_sid : "none");
- vty_out(vty, " vpn_policy[AFI_IP6].tovpn_sid: %s\n",
- tovpn6_sid ? buf_tovpn6_sid : "none");
+ vty_out(vty, " vpn_policy[AFI_IP].tovpn_sid: %pI6\n",
+ bgp->vpn_policy[AFI_IP].tovpn_sid);
+ vty_out(vty, " vpn_policy[AFI_IP6].tovpn_sid: %pI6\n",
+ bgp->vpn_policy[AFI_IP6].tovpn_sid);
}
return CMD_SUCCESS;
@@ -12363,6 +12456,11 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi,
if (CHECK_FLAG(p->af_flags[afi][safi],
PEER_FLAG_RSERVER_CLIENT))
vty_out(vty, " Route-Server Client\n");
+
+ if (peer_af_flag_check(p, afi, safi, PEER_FLAG_ORR_GROUP))
+ vty_out(vty, " ORR group (configured) : %s\n",
+ p->orr_group_name[afi][safi]);
+
if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG))
vty_out(vty,
" Inbound soft reconfiguration allowed\n");
@@ -17290,6 +17388,10 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
}
}
+ /* accept-own */
+ if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_ACCEPT_OWN))
+ vty_out(vty, " neighbor %s accept-own\n", addr);
+
/* soo */
if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_SOO)) {
char *soo_str = ecommunity_ecom2str(
@@ -17339,6 +17441,10 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
: "");
}
}
+
+ if (peer_af_flag_check(peer, afi, safi, PEER_FLAG_ORR_GROUP))
+ vty_out(vty, " neighbor %s optimal-route-reflection %s\n",
+ addr, peer->orr_group_name[afi][safi]);
}
static void bgp_vpn_config_write(struct vty *vty, struct bgp *bgp, afi_t afi,
@@ -17445,6 +17551,9 @@ static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi,
}
}
+ /* Optimal Route Reflection */
+ bgp_config_write_orr(vty, bgp, afi, safi);
+
vty_endframe(vty, " exit-address-family\n");
}
@@ -17717,6 +17826,9 @@ int bgp_config_write(struct vty *vty)
vty_out(vty,
" bgp graceful-restart preserve-fw-state\n");
+ /* BGP TCP keepalive */
+ bgp_config_tcp_keepalive(vty, bgp);
+
/* Stale timer for RIB */
if (bgp->rib_stale_time != BGP_DEFAULT_RIB_STALE_TIME)
vty_out(vty,
@@ -18951,6 +19063,34 @@ void bgp_vty_init(void)
install_element(BGP_EVPN_NODE, &neighbor_route_reflector_client_cmd);
install_element(BGP_EVPN_NODE, &no_neighbor_route_reflector_client_cmd);
+ /* "optimal-route-reflection" commands */
+ install_element(BGP_IPV4_NODE, &optimal_route_reflection_cmd);
+ install_element(BGP_IPV4M_NODE, &optimal_route_reflection_cmd);
+ install_element(BGP_IPV4L_NODE, &optimal_route_reflection_cmd);
+ install_element(BGP_IPV6_NODE, &optimal_route_reflection_cmd);
+ install_element(BGP_IPV6M_NODE, &optimal_route_reflection_cmd);
+ install_element(BGP_IPV6L_NODE, &optimal_route_reflection_cmd);
+ install_element(BGP_VPNV4_NODE, &optimal_route_reflection_cmd);
+ install_element(BGP_VPNV6_NODE, &optimal_route_reflection_cmd);
+ install_element(BGP_FLOWSPECV4_NODE, &optimal_route_reflection_cmd);
+ install_element(BGP_FLOWSPECV6_NODE, &optimal_route_reflection_cmd);
+ install_element(BGP_EVPN_NODE, &optimal_route_reflection_cmd);
+
+ /* "neighbor optimal-route-reflection" commands */
+ install_element(BGP_IPV4_NODE, &neighbor_optimal_route_reflection_cmd);
+ install_element(BGP_IPV4M_NODE, &neighbor_optimal_route_reflection_cmd);
+ install_element(BGP_IPV4L_NODE, &neighbor_optimal_route_reflection_cmd);
+ install_element(BGP_IPV6_NODE, &neighbor_optimal_route_reflection_cmd);
+ install_element(BGP_IPV6M_NODE, &neighbor_optimal_route_reflection_cmd);
+ install_element(BGP_IPV6L_NODE, &neighbor_optimal_route_reflection_cmd);
+ install_element(BGP_VPNV4_NODE, &neighbor_optimal_route_reflection_cmd);
+ install_element(BGP_VPNV6_NODE, &neighbor_optimal_route_reflection_cmd);
+ install_element(BGP_FLOWSPECV4_NODE,
+ &neighbor_optimal_route_reflection_cmd);
+ install_element(BGP_FLOWSPECV6_NODE,
+ &neighbor_optimal_route_reflection_cmd);
+ install_element(BGP_EVPN_NODE, &neighbor_optimal_route_reflection_cmd);
+
/* "neighbor route-server" commands.*/
install_element(BGP_NODE, &neighbor_route_server_client_hidden_cmd);
install_element(BGP_NODE, &no_neighbor_route_server_client_hidden_cmd);
@@ -19461,6 +19601,10 @@ void bgp_vty_init(void)
install_element(BGP_EVPN_NODE, &neighbor_allowas_in_cmd);
install_element(BGP_EVPN_NODE, &no_neighbor_allowas_in_cmd);
+ /* neighbor accept-own */
+ install_element(BGP_VPNV4_NODE, &neighbor_accept_own_cmd);
+ install_element(BGP_VPNV6_NODE, &neighbor_accept_own_cmd);
+
/* "neighbor soo" */
install_element(BGP_IPV4_NODE, &neighbor_soo_cmd);
install_element(BGP_IPV4_NODE, &no_neighbor_soo_cmd);
@@ -19596,6 +19740,10 @@ void bgp_vty_init(void)
install_element(BGP_NODE, &neighbor_ttl_security_cmd);
install_element(BGP_NODE, &no_neighbor_ttl_security_cmd);
+ /* "bgp tcp-keepalive" commands */
+ install_element(BGP_NODE, &bgp_tcp_keepalive_cmd);
+ install_element(BGP_NODE, &no_bgp_tcp_keepalive_cmd);
+
/* "show [ip] bgp memory" commands. */
install_element(VIEW_NODE, &show_bgp_memory_cmd);
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 57a859c61..b5c13fddd 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -67,10 +67,13 @@
#include "bgpd/bgp_trace.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_lcommunity.h"
+#include "bgpd/bgp_orr.h"
/* All information about zebra. */
struct zclient *zclient = NULL;
+static int bgp_opaque_msg_handler(ZAPI_CALLBACK_ARGS);
+
/* hook to indicate vrf status change for SNMP */
DEFINE_HOOK(bgp_vrf_status_changed, (struct bgp *bgp, struct interface *ifp),
(bgp, ifp));
@@ -3255,10 +3258,10 @@ static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
struct srv6_locator loc = {};
struct bgp *bgp = bgp_get_default();
struct listnode *node, *nnode;
- struct srv6_locator_chunk *chunk;
+ struct srv6_locator_chunk *chunk, *tovpn_sid_locator;
struct bgp_srv6_function *func;
struct bgp *bgp_vrf;
- struct in6_addr *tovpn_sid, *tovpn_sid_locator;
+ struct in6_addr *tovpn_sid;
struct prefix_ipv6 tmp_prefi;
if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0)
@@ -3327,10 +3330,13 @@ static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
if (tovpn_sid_locator) {
tmp_prefi.family = AF_INET6;
tmp_prefi.prefixlen = IPV6_MAX_BITLEN;
- tmp_prefi.prefix = *tovpn_sid_locator;
+ tmp_prefi.prefix = tovpn_sid_locator->prefix.prefix;
if (prefix_match((struct prefix *)&loc.prefix,
- (struct prefix *)&tmp_prefi))
- XFREE(MTYPE_BGP_SRV6_SID, tovpn_sid_locator);
+ (struct prefix *)&tmp_prefi)) {
+ srv6_locator_chunk_free(tovpn_sid_locator);
+ bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_locator =
+ NULL;
+ }
}
/* refresh vpnv6 tovpn_sid_locator */
@@ -3339,10 +3345,13 @@ static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
if (tovpn_sid_locator) {
tmp_prefi.family = AF_INET6;
tmp_prefi.prefixlen = IPV6_MAX_BITLEN;
- tmp_prefi.prefix = *tovpn_sid_locator;
+ tmp_prefi.prefix = tovpn_sid_locator->prefix.prefix;
if (prefix_match((struct prefix *)&loc.prefix,
- (struct prefix *)&tmp_prefi))
- XFREE(MTYPE_BGP_SRV6_SID, tovpn_sid_locator);
+ (struct prefix *)&tmp_prefi)) {
+ srv6_locator_chunk_free(tovpn_sid_locator);
+ bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_locator =
+ NULL;
+ }
}
}
@@ -3382,6 +3391,7 @@ static zclient_handler *const bgp_handlers[] = {
[ZEBRA_SRV6_LOCATOR_DELETE] = bgp_zebra_process_srv6_locator_delete,
[ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] =
bgp_zebra_process_srv6_locator_chunk,
+ [ZEBRA_OPAQUE_MESSAGE] = bgp_opaque_msg_handler,
};
static int bgp_if_new_hook(struct interface *ifp)
@@ -3836,3 +3846,34 @@ int bgp_zebra_srv6_manager_release_locator_chunk(const char *name)
{
return srv6_manager_release_locator_chunk(zclient, name);
}
+
+/*
+ * ORR messages between processes
+ */
+static int bgp_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
+{
+ struct stream *s;
+ struct zapi_opaque_msg info;
+ struct orr_igp_metric_info table;
+ int ret = 0;
+
+ s = zclient->ibuf;
+
+ if (zclient_opaque_decode(s, &info) != 0) {
+ bgp_orr_debug("%s: opaque decode failed", __func__);
+ return -1;
+ }
+
+ switch (info.type) {
+ case ORR_IGP_METRIC_UPDATE:
+ STREAM_GET(&table, s, sizeof(table));
+ ret = bgg_orr_message_process(BGP_ORR_IMSG_IGP_METRIC_UPDATE,
+ (void *)&table);
+ break;
+ default:
+ break;
+ }
+
+stream_failure:
+ return ret;
+}
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index b2427d730..40e6c90df 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -92,6 +92,7 @@
#include "bgpd/bgp_evpn_private.h"
#include "bgpd/bgp_evpn_mh.h"
#include "bgpd/bgp_mac.h"
+#include "bgpd/bgp_orr.h"
DEFINE_MTYPE_STATIC(BGPD, PEER_TX_SHUTDOWN_MSG, "Peer shutdown message (TX)");
DEFINE_MTYPE_STATIC(BGPD, BGP_EVPN_INFO, "BGP EVPN instance information");
@@ -551,6 +552,21 @@ void bgp_timers_unset(struct bgp *bgp)
bgp->default_delayopen = BGP_DEFAULT_DELAYOPEN;
}
+void bgp_tcp_keepalive_set(struct bgp *bgp, uint16_t keepalive_idle,
+ uint16_t keepalive_intvl, uint16_t keepalive_probes)
+{
+ bgp->tcp_keepalive_idle = keepalive_idle;
+ bgp->tcp_keepalive_intvl = keepalive_intvl;
+ bgp->tcp_keepalive_probes = keepalive_probes;
+}
+
+void bgp_tcp_keepalive_unset(struct bgp *bgp)
+{
+ bgp->tcp_keepalive_idle = 0;
+ bgp->tcp_keepalive_intvl = 0;
+ bgp->tcp_keepalive_probes = 0;
+}
+
/* BGP confederation configuration. */
void bgp_confederation_id_set(struct bgp *bgp, as_t as)
{
@@ -997,9 +1013,15 @@ void peer_af_flag_inherit(struct peer *peer, afi_t afi, safi_t safi,
static inline enum bgp_peer_sort peer_calc_sort(struct peer *peer)
{
struct bgp *bgp;
+ as_t local_as;
bgp = peer->bgp;
+ if (peer->change_local_as)
+ local_as = peer->change_local_as;
+ else
+ local_as = peer->local_as;
+
/* Peer-group */
if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
if (peer->as_type == AS_INTERNAL)
@@ -1010,8 +1032,8 @@ static inline enum bgp_peer_sort peer_calc_sort(struct peer *peer)
else if (peer->as_type == AS_SPECIFIED && peer->as) {
assert(bgp);
- return (bgp->as == peer->as ? BGP_PEER_IBGP
- : BGP_PEER_EBGP);
+ return (local_as == peer->as ? BGP_PEER_IBGP
+ : BGP_PEER_EBGP);
}
else {
@@ -1028,17 +1050,17 @@ static inline enum bgp_peer_sort peer_calc_sort(struct peer *peer)
/* Normal peer */
if (bgp && CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)) {
- if (peer->local_as == 0)
+ if (local_as == 0)
return BGP_PEER_INTERNAL;
- if (peer->local_as == peer->as) {
+ if (local_as == peer->as) {
if (bgp->as == bgp->confed_id) {
- if (peer->local_as == bgp->as)
+ if (local_as == bgp->as)
return BGP_PEER_IBGP;
else
return BGP_PEER_EBGP;
} else {
- if (peer->local_as == bgp->confed_id)
+ if (local_as == bgp->confed_id)
return BGP_PEER_EBGP;
else
return BGP_PEER_IBGP;
@@ -1056,8 +1078,7 @@ static inline enum bgp_peer_sort peer_calc_sort(struct peer *peer)
&& (peer->group->conf->as_type != AS_UNSPECIFIED)) {
if (peer->group->conf->as_type
== AS_SPECIFIED) {
- if (peer->local_as
- == peer->group->conf->as)
+ if (local_as == peer->group->conf->as)
return BGP_PEER_IBGP;
else
return BGP_PEER_EBGP;
@@ -1073,9 +1094,8 @@ static inline enum bgp_peer_sort peer_calc_sort(struct peer *peer)
return (peer->as_type == AS_INTERNAL ? BGP_PEER_IBGP
: BGP_PEER_EBGP);
- return (peer->local_as == 0
- ? BGP_PEER_INTERNAL
- : peer->local_as == peer->as ? BGP_PEER_IBGP
+ return (local_as == 0 ? BGP_PEER_INTERNAL
+ : local_as == peer->as ? BGP_PEER_IBGP
: BGP_PEER_EBGP);
}
}
@@ -1820,6 +1840,8 @@ bool bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi)
/* Change peer's AS number. */
void peer_as_change(struct peer *peer, as_t as, int as_specified)
{
+ afi_t afi;
+ safi_t safi;
enum bgp_peer_sort origtype, newtype;
/* Stop peer. */
@@ -1858,6 +1880,11 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified)
/* reflector-client reset */
if (newtype != BGP_PEER_IBGP) {
+
+ FOREACH_AFI_SAFI (afi, safi)
+ UNSET_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_ORR_GROUP);
+
UNSET_FLAG(peer->af_flags[AFI_IP][SAFI_UNICAST],
PEER_FLAG_REFLECTOR_CLIENT);
UNSET_FLAG(peer->af_flags[AFI_IP][SAFI_MULTICAST],
@@ -1885,14 +1912,6 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified)
UNSET_FLAG(peer->af_flags[AFI_L2VPN][SAFI_EVPN],
PEER_FLAG_REFLECTOR_CLIENT);
}
-
- /* local-as reset */
- if (newtype != BGP_PEER_EBGP) {
- peer->change_local_as = 0;
- peer_flag_unset(peer, PEER_FLAG_LOCAL_AS);
- peer_flag_unset(peer, PEER_FLAG_LOCAL_AS_NO_PREPEND);
- peer_flag_unset(peer, PEER_FLAG_LOCAL_AS_REPLACE_AS);
- }
}
/* If peer does not exist, create new one. If peer already exists,
@@ -2760,6 +2779,21 @@ void peer_notify_unconfig(struct peer *peer)
BGP_NOTIFY_CEASE_PEER_UNCONFIG);
}
+static void peer_notify_shutdown(struct peer *peer)
+{
+ if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer)) {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug(
+ "%pBP configured Graceful-Restart, skipping shutdown notification",
+ peer);
+ return;
+ }
+
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
+ bgp_notify_send(peer, BGP_NOTIFY_CEASE,
+ BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN);
+}
+
void peer_group_notify_unconfig(struct peer_group *group)
{
struct peer *peer, *other;
@@ -3018,17 +3052,6 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer,
/* ebgp-multihop reset */
if (gtype == BGP_PEER_IBGP)
group->conf->ttl = MAXTTL;
-
- /* local-as reset */
- if (gtype != BGP_PEER_EBGP) {
- group->conf->change_local_as = 0;
- peer_flag_unset(group->conf,
- PEER_FLAG_LOCAL_AS);
- peer_flag_unset(group->conf,
- PEER_FLAG_LOCAL_AS_NO_PREPEND);
- peer_flag_unset(group->conf,
- PEER_FLAG_LOCAL_AS_REPLACE_AS);
- }
}
SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
@@ -3182,6 +3205,7 @@ static struct bgp *bgp_create(as_t *as, const char *name,
bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF;
bgp->default_subgroup_pkt_queue_max =
BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX;
+ bgp_tcp_keepalive_unset(bgp);
bgp_timers_unset(bgp);
bgp->default_min_holdtime = 0;
bgp->restart_time = BGP_DEFAULT_RESTART_TIME;
@@ -3676,11 +3700,8 @@ int bgp_delete(struct bgp *bgp)
}
/* Inform peers we're going down. */
- for (ALL_LIST_ELEMENTS(bgp->peer, node, next, peer)) {
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN);
- }
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, next, peer))
+ peer_notify_shutdown(peer);
/* Delete static routes (networks). */
bgp_static_delete(bgp);
@@ -3837,6 +3858,8 @@ void bgp_free(struct bgp *bgp)
ecommunity_free(&bgp->vpn_policy[afi].rtlist[dir]);
}
+ bgp_orr_cleanup(bgp);
+
XFREE(MTYPE_BGP, bgp->name);
XFREE(MTYPE_BGP, bgp->name_pretty);
XFREE(MTYPE_BGP, bgp->snmp_stats);
@@ -4290,6 +4313,7 @@ static const struct peer_flag_action peer_af_flag_action_list[] = {
{PEER_FLAG_WEIGHT, 0, peer_change_reset_in},
{PEER_FLAG_DISABLE_ADDPATH_RX, 0, peer_change_reset},
{PEER_FLAG_SOO, 0, peer_change_reset},
+ {PEER_FLAG_ACCEPT_OWN, 0, peer_change_reset},
{0, 0, 0}};
/* Proper action set. */
@@ -4620,6 +4644,11 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi,
if (flag & PEER_FLAG_REFLECTOR_CLIENT && ptype != BGP_PEER_IBGP)
return BGP_ERR_NOT_INTERNAL_PEER;
+ /* Do not remove reflector client when ORR is configured on this peer */
+ if (flag & PEER_FLAG_REFLECTOR_CLIENT && !set &&
+ peer_orr_rrclient_check(peer, afi, safi))
+ return BGP_ERR_PEER_ORR_CONFIGURED;
+
/* Special check for remove-private-AS. */
if (flag & PEER_FLAG_REMOVE_PRIVATE_AS && ptype == BGP_PEER_IBGP)
return BGP_ERR_REMOVE_PRIVATE_AS;
@@ -6109,17 +6138,10 @@ int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend,
struct bgp *bgp = peer->bgp;
struct peer *member;
struct listnode *node, *nnode;
- enum bgp_peer_sort ptype = peer_sort(peer);
-
- if (ptype != BGP_PEER_EBGP && ptype != BGP_PEER_INTERNAL)
- return BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP;
if (bgp->as == as)
return BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS;
- if (peer->as == as)
- return BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS_REMOTE_AS;
-
/* Save previous flag states. */
old_no_prepend =
!!CHECK_FLAG(peer->flags, PEER_FLAG_LOCAL_AS_NO_PREPEND);
@@ -6135,6 +6157,7 @@ int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend,
&& old_replace_as == replace_as)
return 0;
peer->change_local_as = as;
+ (void)peer_sort(peer);
/* Check if handling a regular peer. */
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
@@ -8088,11 +8111,18 @@ void bgp_terminate(void)
/* reverse bgp_master_init */
for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
bgp_close_vrf_socket(bgp);
- for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer))
- if (peer_established(peer) || peer->status == OpenSent
- || peer->status == OpenConfirm)
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+ if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer)) {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug(
+ "%pBP configured Graceful-Restart, skipping unconfig notification",
+ peer);
+ continue;
+ }
+ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status))
bgp_notify_send(peer, BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_PEER_UNCONFIG);
+ }
}
if (bm->listen_sockets)
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 2c6618e40..44e225b04 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -47,6 +47,7 @@
#include "bgp_io.h"
#include "lib/bfd.h"
+#include "lib/orr_msg.h"
#define BGP_MAX_HOSTNAME 64 /* Linux max, is larger than most other sys */
#define BGP_PEER_MAX_HASH_SIZE 16384
@@ -132,6 +133,7 @@ struct bgp_master {
/* Various BGP global configuration. */
uint8_t options;
+
#define BGP_OPT_NO_FIB (1 << 0)
#define BGP_OPT_NO_LISTEN (1 << 1)
#define BGP_OPT_NO_ZEBRA (1 << 2)
@@ -196,6 +198,40 @@ struct bgp_redist {
struct bgp_rmap rmap;
};
+struct bgp_orr_igp_metric {
+ struct prefix prefix;
+ uint32_t igp_metric;
+};
+
+struct bgp_orr_group {
+ /* Name of this ORR group */
+ char *name;
+
+ /* Address Family Identifiers */
+ afi_t afi;
+ safi_t safi;
+
+ /* Pointer to BGP */
+ struct bgp *bgp;
+
+ /* Root Routers of the group */
+ struct peer *primary;
+ struct peer *secondary;
+ struct peer *tertiary;
+
+ /* Active Root Router of the group */
+ struct peer *active;
+
+ /* RR clients belong to this group */
+ struct list *rr_client_list;
+
+ /* IGP metric data from active root */
+ struct list *igp_metric_info;
+
+ /* Route table calculated from active root for this group */
+ struct bgp_table *route_table;
+};
+
enum vpn_policy_direction {
BGP_VPN_POLICY_DIR_FROMVPN = 0,
BGP_VPN_POLICY_DIR_TOVPN = 1,
@@ -238,7 +274,7 @@ struct vpn_policy {
*/
uint32_t tovpn_sid_index; /* unset => set to 0 */
struct in6_addr *tovpn_sid;
- struct in6_addr *tovpn_sid_locator;
+ struct srv6_locator_chunk *tovpn_sid_locator;
uint32_t tovpn_sid_transpose_label;
struct in6_addr *tovpn_zebra_vrf_sid_last_sent;
};
@@ -768,12 +804,20 @@ struct bgp {
char srv6_locator_name[SRV6_LOCNAME_SIZE];
struct list *srv6_locator_chunks;
struct list *srv6_functions;
+ /* TCP keepalive parameters for BGP connection */
+ uint16_t tcp_keepalive_idle;
+ uint16_t tcp_keepalive_intvl;
+ uint16_t tcp_keepalive_probes;
struct timeval ebgprequirespolicywarning;
#define FIFTEENMINUTE2USEC (int64_t)15 * 60 * 1000000
bool allow_martian;
+ /* BGP optimal route reflection group and Root Router configuration */
+ uint32_t orr_group_count;
+ struct list *orr_group[AFI_MAX][SAFI_MAX];
+
QOBJ_FIELDS;
};
DECLARE_QOBJ_TYPE(bgp);
@@ -1417,6 +1461,11 @@ struct peer {
#define PEER_FLAG_MAX_PREFIX_FORCE (1ULL << 28)
#define PEER_FLAG_DISABLE_ADDPATH_RX (1ULL << 29)
#define PEER_FLAG_SOO (1ULL << 30)
+#define PEER_FLAG_ORR_GROUP (1ULL << 31) /* Optimal-Route-Reflection */
+#define PEER_FLAG_ACCEPT_OWN (1ULL << 32)
+
+ /* BGP Optimal Route Reflection Group name */
+ char *orr_group_name[AFI_MAX][SAFI_MAX];
enum bgp_addpath_strat addpath_type[AFI_MAX][SAFI_MAX];
@@ -2004,13 +2053,11 @@ enum bgp_create_error_code {
BGP_ERR_AF_UNCONFIGURED = -15,
BGP_ERR_SOFT_RECONFIG_UNCONFIGURED = -16,
BGP_ERR_INSTANCE_MISMATCH = -17,
- BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP = -18,
BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS = -19,
BGP_ERR_TCPSIG_FAILED = -20,
BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK = -21,
BGP_ERR_NO_IBGP_WITH_TTLHACK = -22,
BGP_ERR_NO_INTERFACE_CONFIG = -23,
- BGP_ERR_CANNOT_HAVE_LOCAL_AS_SAME_AS_REMOTE_AS = -24,
BGP_ERR_AS_OVERRIDE = -25,
BGP_ERR_INVALID_DYNAMIC_NEIGHBORS_LIMIT = -26,
BGP_ERR_DYNAMIC_NEIGHBORS_RANGE_EXISTS = -27,
@@ -2026,7 +2073,10 @@ enum bgp_create_error_code {
/*BGP Open Policy ERRORS */
BGP_ERR_INVALID_ROLE_NAME = -35,
- BGP_ERR_INVALID_INTERNAL_ROLE = -36
+ BGP_ERR_INVALID_INTERNAL_ROLE = -36,
+
+ /* BGP ORR ERRORS */
+ BGP_ERR_PEER_ORR_CONFIGURED = -37,
};
/*
@@ -2078,6 +2128,7 @@ extern struct peer_group *peer_group_lookup_dynamic_neighbor(struct bgp *,
extern struct peer *peer_lookup_dynamic_neighbor(struct bgp *,
union sockunion *);
+extern bool peer_orr_rrclient_check(struct peer *peer, afi_t afi, safi_t safi);
/*
* Peers are incredibly easy to memory leak
* due to the various ways that they are actually used
@@ -2215,6 +2266,9 @@ extern int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi,
const char *rmap,
struct route_map *route_map);
extern int peer_default_originate_unset(struct peer *, afi_t, safi_t);
+extern void bgp_tcp_keepalive_set(struct bgp *bgp, uint16_t idle,
+ uint16_t interval, uint16_t probes);
+extern void bgp_tcp_keepalive_unset(struct bgp *bgp);
extern void peer_port_set(struct peer *, uint16_t);
extern void peer_port_unset(struct peer *);
@@ -2325,6 +2379,12 @@ extern void bgp_shutdown_disable(struct bgp *bgp);
extern void bgp_close(void);
extern void bgp_free(struct bgp *);
void bgp_gr_apply_running_config(void);
+extern int bgp_afi_safi_orr_group_set(struct bgp *bgp, afi_t afi, safi_t safi,
+ const char *name, struct peer *primary,
+ struct peer *secondary,
+ struct peer *tertiary);
+extern int bgp_afi_safi_orr_group_unset(struct bgp *bgp, afi_t afi, safi_t safi,
+ const char *name);
/* BGP GR */
int bgp_global_gr_init(struct bgp *bgp);
diff --git a/bgpd/subdir.am b/bgpd/subdir.am
index b1eeb937e..765650313 100644
--- a/bgpd/subdir.am
+++ b/bgpd/subdir.am
@@ -103,6 +103,7 @@ bgpd_libbgp_a_SOURCES = \
bgpd/bgp_vty.c \
bgpd/bgp_zebra.c \
bgpd/bgpd.c \
+ bgpd/bgp_orr.c \
bgpd/bgp_trace.c \
# end
@@ -183,6 +184,7 @@ noinst_HEADERS += \
bgpd/bgp_vty.h \
bgpd/bgp_zebra.h \
bgpd/bgpd.h \
+ bgpd/bgp_orr.h \
bgpd/bgp_trace.h \
\
bgpd/rfapi/bgp_rfapi_cfg.h \
diff --git a/configure.ac b/configure.ac
index 4e1080045..4cbdfe0fc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2631,6 +2631,7 @@ AC_DEFINE_UNQUOTED([ZEBRA_SERV_PATH], ["$frr_statedir%s%s/zserv.api"], [zebra ap
AC_DEFINE_UNQUOTED([BFDD_CONTROL_SOCKET], ["$frr_statedir%s%s/bfdd.sock"], [bfdd control socket])
AC_DEFINE_UNQUOTED([OSPFD_GR_STATE], ["$frr_statedir%s/ospfd-gr.json"], [ospfd GR state information])
AC_DEFINE_UNQUOTED([OSPF6D_GR_STATE], ["$frr_statedir/ospf6d-gr.json"], [ospf6d GR state information])
+AC_DEFINE_UNQUOTED([ISISD_RESTART], ["$frr_statedir%s/isid-restart.json"], [isisd restart information])
AC_DEFINE_UNQUOTED([OSPF6_AUTH_SEQ_NUM_FILE], ["$frr_statedir/ospf6d-at-seq-no.dat"], [ospf6d AT Sequence number information])
AC_DEFINE_UNQUOTED([DAEMON_VTY_DIR], ["$frr_statedir%s%s"], [daemon vty directory])
AC_DEFINE_UNQUOTED([DAEMON_DB_DIR], ["$frr_statedir"], [daemon database directory])
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index f136ea4ae..8a16c57e6 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -1670,6 +1670,23 @@ Configuring Peers
turning on this command will allow BGP to install v4 routes with
v6 nexthops if you do not have v4 configured on interfaces.
+.. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> accept-own
+
+ Enable handling of self-originated VPN routes containing ``accept-own`` community.
+
+ This feature allows you to handle self-originated VPN routes, which a BGP speaker
+ receives from a route-reflector. A 'self-originated' route is one that was
+ originally advertised by the speaker itself. As per :rfc:`4271`, a BGP speaker rejects
+ advertisements that originated the speaker itself. However, the BGP ACCEPT_OWN
+ mechanism enables a router to accept the prefixes it has advertised, when reflected
+ from a route-reflector that modifies certain attributes of the prefix.
+
+ A special community called ``accept-own`` is attached to the prefix by the
+ route-reflector, which is a signal to the receiving router to bypass the ORIGINATOR_ID
+ and NEXTHOP/MP_REACH_NLRI check.
+
+ Default: disabled.
+
.. clicmd:: bgp fast-external-failover
This command causes bgp to take down ebgp peers immediately
@@ -1790,6 +1807,13 @@ Configuring Peers
with lower holdtime less than configured minimum holdtime.
When this command is not set, minimum holdtime does not work.
+.. clicmd:: bgp tcp-keepalive (1-65535) (1-65535) (1-30)
+
+ This command allows user to configure TCP keepalive with new BGP peers.
+ Each parameter respectively stands for TCP keepalive idle timer (seconds),
+ interval (seconds), and maximum probes. By default, TCP keepalive is
+ disabled.
+
Displaying Information about Peers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -3471,6 +3495,319 @@ When default route is not present in R2'2 BGP table, 10.139.224.0/20 and 192.0.2
Total number of prefixes 3
Router2#
+.. _bgp-optimal-route-reflection:
+
+BGP Optimal Route Reflection
+----------------------------
+BGP Route Reflectors (RRs) are used to improve network scalability by reducing
+or eliminating the need for a full-mesh of IBGP sessions.
+
+When a BGP RR receives multiple paths for the same IP prefix, it typically
+selects a single best path to send for all its clients.
+If the RR has multiple nearly-equal best paths and the tie-break is determined
+by the next-hop cost, the RR advertises the path based on its view of next-hop
+costs, which leads to a non-optimal routing.
+The advertised route may differ from the path that a client would select
+if it had the visibility of the same set of candidate paths and used
+its own view of next-hop costs.
+
+Non-optimal advertisements by the RR can be a problem in hot-potato routing.
+Hot-potato routing aims to hand off traffic to the next AS using the closest
+possible exit point from the local AS.
+In this context, the closest exit point implies minimum IGP cost to
+reach the BGP next-hop.
+
+The BGP Optimal Route Reflection allows the RR to choose and send a different
+best path to a different or a set of RR clients.
+
+A link-state protocol is required. It can be OSPF or IS-IS.
+Current implementation of BGP ORR is based on the IGP cost to the BGP next hop,
+and not based on some configured policy.
+
+RR runs Shortest Path First (SPF) calculation with the selected
+router as the root of the tree and calculates the cost to every other router.
+
+This special SPF calculation with another router as the root, is referred to as
+a Reverse SPF (rSPF). This can only be done if the RR learns all the BGP paths
+from all the BGP border routers.
+
+There could be as many rSPFs run as there are RR clients.
+This will increase the CPU load somewhat on the RR.
+
+Current implementation allows up to three root nodes for the rSPF calculation.
+There is no need to configure each RR client as a root and run rSPF.
+Current implementation allows to configure three, the primary, the secondary,
+and the tertiary root, per set of RR clients, for redundancy purposes.
+For the BGP ORR feature to apply to any RR client, that RR client must be
+configured to be part of an ORR policy group.
+
+The BGP ORR feature is enabled per address family.
+
+The minimal configuration needed:
+
+1. ORR needs to be enabled for specific groups of BGP neighbors.
+2. For each group of BGP neighbors, at least one root needs to be configured.
+ Optionally, a secondary and tertiary root can be configured.
+3. For OSPF, the root routers(RR clients) need additional configuration
+ to make BGP ORR work.
+ i.e. The MPLS TE configuration on the root router needs to have the minimal
+ configuration for MPLS TE enabled so that OSPF advertises the MPLS TE
+ router ID in an opaque-area LSA (type 10).
+ Once the RR has an opaque-area LSA with the MPLS TE router-ID matching the
+ configured root router address, rSPF can run and BGP on the RR can
+ advertise the optimal route.
+
+.. clicmd:: neighbor A.B.C.D optimal-route-reflection NAME
+
+ This command allows the neighbor to be part of the ORR group.
+
+.. clicmd:: optimal-route-reflection orr-1 A.B.C.D [A.B.C.D] [A.B.C.D]
+
+ This command creates an ORR group with a mandatory primary root
+ and optional secondary and/or tertiary roots.
+ When primary is reachable it will be the active root.
+ when primary goes down, secondary followed by tertiary takes over
+ the active root's role.
+ Always rSPF calculation runs active root as the root.
+ Which means the RR advertises the path based on active root's
+ view of next-hop costs.
+
+Sample Configuration
+^^^^^^^^^^^^^^^^^^^^
+
+Sample configuration on Route Reflector
+
+.. code-block:: frr
+
+ !
+ debug ospf 8 orr
+ debug bgp optimal-route-reflection
+ !
+ interface enp0s8
+ ip address 10.10.68.8/24
+ ip ospf 8 area 0
+ exit
+ !
+ interface lo
+ ip address 10.100.1.8/32
+ ip ospf 8 area 0
+ exit
+ !
+ router bgp 1
+ neighbor 10.100.1.1 remote-as 1
+ neighbor 10.100.1.1 update-source lo
+ neighbor 10.100.1.2 remote-as 1
+ neighbor 10.100.1.2 update-source lo
+ neighbor 10.100.1.3 remote-as 1
+ neighbor 10.100.1.3 update-source lo
+ neighbor 10.100.1.4 remote-as 1
+ neighbor 10.100.1.4 update-source lo
+ !
+ address-family ipv4 unicast
+ neighbor 10.100.1.1 route-reflector-client
+ neighbor 10.100.1.1 optimal-route-reflection orr-1
+ neighbor 10.100.1.2 route-reflector-client
+ neighbor 10.100.1.2 optimal-route-reflection orr-1
+ neighbor 10.100.1.3 route-reflector-client
+ neighbor 10.100.1.3 optimal-route-reflection orr-1
+ neighbor 10.100.1.4 route-reflector-client
+ neighbor 10.100.1.4 optimal-route-reflection orr-1
+ optimal-route-reflection orr-1 10.100.1.4 10.100.1.3 10.100.1.1
+ exit-address-family
+ exit
+ !
+ router ospf 8
+ ospf router-id 8.8.8.8
+ area 0 authentication
+ capability opaque
+ exit
+ !
+ end
+
+Sample configuration on RR clients
+
+.. code-block:: frr
+
+ interface enp0s8
+ ip address 10.10.34.4/24
+ ip ospf 4 area 0
+ link-params
+ enable
+ exit-link-params
+ exit
+ !
+ interface enp0s9
+ ip address 10.10.74.4/24
+ ip ospf 4 area 0
+ link-params
+ enable
+ exit-link-params
+ exit
+ !
+ interface lo
+ ip address 10.100.1.4/32
+ ip ospf 4 area 0
+ exit
+ !
+ router bgp 1
+ neighbor 10.100.1.8 remote-as 1
+ neighbor 10.100.1.8 update-source lo
+ !
+ address-family ipv4 unicast
+ neighbor 10.100.1.8 soft-reconfiguration inbound
+ exit-address-family
+ exit
+ !
+ router ospf 4
+ ospf router-id 4.4.4.4
+ area 0 authentication
+ capability opaque
+ mpls-te on
+ mpls-te router-address 10.100.1.4
+ mpls-te inter-as area 0.0.0.0
+ mpls-te export
+ exit
+ !
+ end
+
+Sample Output
+^^^^^^^^^^^^^
+
+When Optimal Route Reflection is not enabled on RR, it sends 10.100.1.1 as the best path to its clients.
+
+.. code-block:: frr
+
+ Router-RR# show ip bgp neighbors 10.100.1.4
+
+ !--- Output suppressed.
+
+ For address family: IPv4 Unicast
+ Update group 2, subgroup 2
+ Packet Queue length 0
+ Route-Reflector Client
+ Community attribute sent to this neighbor(all)
+ 0 accepted prefixes
+
+ !--- Output suppressed.
+
+ Router-RR#
+ Router-RR# show ip bgp
+ BGP table version is 3, local router ID is 10.100.1.8, vrf id 0
+ Default local pref 100, local AS 1
+ Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
+ i internal, r RIB-failure, S Stale, R Removed
+ Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
+ Origin codes: i - IGP, e - EGP, ? - incomplete
+ RPKI validation codes: V valid, I invalid, N Not found
+
+ Network Next Hop Metric LocPrf Weight Path
+ * i203.0.113.0/24 10.100.1.2 0 100 0 i
+ *>i 10.100.1.1 0 100 0 i
+ *=i 10.100.1.3 0 100 0 i
+
+ Displayed 1 routes and 3 total paths
+ Router-RR#
+
+ Router-PE4# show ip bgp
+ BGP table version is 5, local router ID is 10.100.1.4, vrf id 0
+ Default local pref 100, local AS 1
+ Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
+ i internal, r RIB-failure, S Stale, R Removed
+ Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
+ Origin codes: i - IGP, e - EGP, ? - incomplete
+ RPKI validation codes: V valid, I invalid, N Not found
+
+ Network Next Hop Metric LocPrf Weight Path
+ *>i203.0.113.0/24 10.100.1.1 0 100 0 i
+
+ Displayed 1 routes and 1 total paths
+ Router-PE4#
+
+When Optimal Route Reflection is enabled on RR, it sends 10.100.1.3 as the best path to its clients.
+
+.. code-block:: frr
+
+ Router-RR# show ip bgp neighbors 10.100.1.4
+
+ !--- Output suppressed.
+
+ For address family: IPv4 Unicast
+ Update group 1, subgroup 1
+ Packet Queue length 0
+ Route-Reflector Client
+ ORR group (configured) : orr-1
+ Community attribute sent to this neighbor(all)
+ 0 accepted prefixes
+
+ !--- Output suppressed.
+
+ Router-RR#
+ Router-RR# show ip bgp
+ BGP table version is 1, local router ID is 10.100.1.8, vrf id 0
+ Default local pref 100, local AS 1
+ Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
+ i internal, r RIB-failure, S Stale, R Removed
+ Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
+ Origin codes: i - IGP, e - EGP, ? - incomplete
+ RPKI validation codes: V valid, I invalid, N Not found
+
+ Network Next Hop Metric LocPrf Weight Path
+ * i203.0.113.0/24 10.100.1.2 0 100 0 i
+ *>i 10.100.1.3 0 100 0 i
+ * i 10.100.1.1 0 100 0 i
+
+ Displayed 1 routes and 3 total paths
+ Router-RR#
+
+ Router-RR# show ip bgp optimal-route-reflection
+
+ ORR group: orr-1, IPv4 Unicast
+ Configured root: primary: 10.100.1.4(Router-PE4), secondary: 10.100.1.3(Router-PE3), tertiary: 10.100.1.1(Router-PE1)
+ Active Root: 10.100.1.4(Router-PE4)
+
+ RR Clients mapped:
+ 10.100.1.1
+ 10.100.1.2
+ 10.100.1.3
+ 10.100.1.4
+
+ Number of mapping entries: 4
+
+ Prefix Cost
+ 10.10.34.0/24 100
+ 10.10.61.0/24 300
+ 10.10.63.0/24 200
+ 10.10.67.0/24 200
+ 10.10.68.0/24 300
+ 10.10.72.0/24 200
+ 10.10.74.0/24 100
+ 10.100.1.1/32 300
+ 10.100.1.2/32 200
+ 10.100.1.3/32 100
+ 10.100.1.4/32 0
+ 10.100.1.6/32 200
+ 10.100.1.7/32 100
+ 10.100.1.8/32 300
+
+ Number of mapping entries: 14
+
+ Router-RR#
+
+ Router-PE4# show ip bgp
+ BGP table version is 3, local router ID is 10.100.1.4, vrf id 0
+ Default local pref 100, local AS 1
+ Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
+ i internal, r RIB-failure, S Stale, R Removed
+ Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
+ Origin codes: i - IGP, e - EGP, ? - incomplete
+ RPKI validation codes: V valid, I invalid, N Not found
+
+ Network Next Hop Metric LocPrf Weight Path
+ *>i203.0.113.0/24 10.100.1.3 0 100 0 i
+
+ Displayed 1 routes and 1 total paths
+ Router-PE4#
+
.. _bgp-debugging:
Debugging
@@ -3536,6 +3873,10 @@ Debugging
Enable or disable debugging of communications between *bgpd* and *zebra*.
+.. clicmd:: debug bgp optimal-route-reflection
+
+ Enable or disable debugging of BGP Optimal Route Reflection.
+
Dumping Messages and Routing Tables
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst
index 9ccb5ba4b..2b114ad12 100644
--- a/doc/user/isisd.rst
+++ b/doc/user/isisd.rst
@@ -83,6 +83,10 @@ writing, *isisd* does not support multiple ISIS processes.
Set overload bit to avoid any transit traffic.
+.. clicmd:: set-overload-bit on-startup (0-86400)
+
+ Set overload bit on startup for the specified duration, in seconds. Reference: :rfc:`3277`
+
.. clicmd:: purge-originator
Enable or disable :rfc:`6232` purge originator identification.
diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst
index 26810bd88..3aa3d47f3 100644
--- a/doc/user/ospfd.rst
+++ b/doc/user/ospfd.rst
@@ -831,6 +831,12 @@ Showing Information
Show the OSPF routing table, as determined by the most recent SPF
calculation.
+.. clicmd:: show ip ospf (1-65535) route orr [NAME]
+
+.. clicmd:: show ip ospf [vrf <NAME|all>] route orr [NAME]
+
+ Show the OSPF routing table, calculated from the active root of all ORR groups or specified ORR group.
+
.. clicmd:: show ip ospf graceful-restart helper [detail] [json]
Displays the Grcaeful Restart Helper details including helper
@@ -1060,78 +1066,87 @@ TI-LFA requires a proper Segment Routing configuration.
Debugging OSPF
==============
-.. clicmd:: debug ospf bfd
+.. clicmd:: debug ospf [(1-65535)] bfd
Enable or disable debugging for BFD events. This will show BFD integration
library messages and OSPF BFD integration messages that are mostly state
transitions and validation problems.
-.. clicmd:: debug ospf client-api
+.. clicmd:: debug ospf [(1-65535)] client-api
Show debug information for the OSPF opaque data client API.
-.. clicmd:: debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]
+.. clicmd:: debug ospf [(1-65535)] default-information
+ Show debug information of default information
- Dump Packet for debugging
+.. clicmd:: debug ospf [(1-65535)] packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]
-.. clicmd:: debug ospf ism
-.. clicmd:: debug ospf ism (status|events|timers)
+ Dump Packet for debugging
+.. clicmd:: debug ospf [(1-65535)] ism [status|events|timers]
- Show debug information of Interface State Machine
-.. clicmd:: debug ospf nsm
+ Show debug information of Interface State Machine
-.. clicmd:: debug ospf nsm (status|events|timers)
+.. clicmd:: debug ospf [(1-65535)] nsm [status|events|timers]
Show debug information of Network State Machine
-.. clicmd:: debug ospf event
+.. clicmd:: debug ospf [(1-65535)] event
Show debug information of OSPF event
-.. clicmd:: debug ospf nssa
+.. clicmd:: debug ospf [(1-65535)] nssa
Show debug information about Not So Stub Area
-.. clicmd:: debug ospf lsa
+.. clicmd:: debug ospf [(1-65535)] ldp-sync
+
+ Show debug information about LDP-Sync
-.. clicmd:: debug ospf lsa (generate|flooding|refresh)
+.. clicmd:: debug ospf [(1-65535)] lsa [aggregate|flooding|generate|install|refresh]
Show debug detail of Link State messages
-.. clicmd:: debug ospf te
+.. clicmd:: debug ospf [(1-65535)] sr
+
+ Show debug information about Segment Routing
+
+.. clicmd:: debug ospf [(1-65535)] te
Show debug information about Traffic Engineering LSA
-.. clicmd:: debug ospf zebra
+.. clicmd:: debug ospf [(1-65535)] ti-lfa
+
+ Show debug information about SR TI-LFA
-.. clicmd:: debug ospf zebra (interface|redistribute)
+.. clicmd:: debug ospf [(1-65535)] zebra [interface|redistribute]
Show debug information of ZEBRA API
-.. clicmd:: debug ospf graceful-restart helper
+.. clicmd:: debug ospf [(1-65535)] graceful-restart
Enable/disable debug information for OSPF Graceful Restart Helper
.. clicmd:: show debugging ospf
-.. clicmd:: debug ospf lsa aggregate
- Debug commnd to enable/disable external route summarisation specific debugs.
+.. clicmd:: debug ospf orr
+
+ Enable or disable debugging of BGP Optimal Route Reflection.
Sample Configuration
diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst
index 05990e252..01cf5316a 100644
--- a/doc/user/zebra.rst
+++ b/doc/user/zebra.rst
@@ -745,7 +745,7 @@ and this section also helps that case.
Create a new locator. If the name of an existing locator is specified,
move to specified locator's configuration node to change the settings it.
-.. clicmd:: prefix X:X::X:X/M [func-bits 32]
+.. clicmd:: prefix X:X::X:X/M [func-bits (0-64)]
Set the ipv6 prefix block of the locator. SRv6 locator is defined by
RFC8986. The actual routing protocol specifies the locator and allocates a
diff --git a/eigrpd/eigrp_dump.c b/eigrpd/eigrp_dump.c
index e1ad51a9d..b0d34f55e 100644
--- a/eigrpd/eigrp_dump.c
+++ b/eigrpd/eigrp_dump.c
@@ -322,6 +322,7 @@ DEFUN_NOSH (show_debugging_eigrp,
}
}
+ cmd_show_lib_debugs(vty);
return CMD_SUCCESS;
}
diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c
index a673cb8c1..9db867e2c 100644
--- a/isisd/isis_cli.c
+++ b/isisd/isis_cli.c
@@ -404,7 +404,7 @@ DEFPY_YANG(set_overload_bit, set_overload_bit_cmd, "[no] set-overload-bit",
"Reset overload bit to accept transit traffic\n"
"Set overload bit to avoid any transit traffic\n")
{
- nb_cli_enqueue_change(vty, "./overload", NB_OP_MODIFY,
+ nb_cli_enqueue_change(vty, "./overload/enabled", NB_OP_MODIFY,
no ? "false" : "true");
return nb_cli_apply_changes(vty, NULL);
@@ -419,6 +419,42 @@ void cli_show_isis_overload(struct vty *vty, const struct lyd_node *dnode,
}
/*
+ * XPath: /frr-isisd:isis/instance/overload/on-startup
+ */
+DEFPY_YANG(set_overload_bit_on_startup, set_overload_bit_on_startup_cmd,
+ "set-overload-bit on-startup (0-86400)$val",
+ "Set overload bit to avoid any transit traffic\n"
+ "Set overload bit on startup\n"
+ "Set overload time in seconds\n")
+{
+ nb_cli_enqueue_change(vty, "./overload/on-startup", NB_OP_MODIFY,
+ val_str);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY_YANG(no_set_overload_bit_on_startup, no_set_overload_bit_on_startup_cmd,
+ "no set-overload-bit on-startup [(0-86400)$val]",
+ NO_STR
+ "Reset overload bit to accept transit traffic\n"
+ "Set overload bit on startup\n"
+ "Set overload time in seconds\n")
+{
+ nb_cli_enqueue_change(vty, "./overload/on-startup", NB_OP_DESTROY,
+ NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_isis_overload_on_startup(struct vty *vty,
+ const struct lyd_node *dnode,
+ bool show_defaults)
+{
+ vty_out(vty, " set-overload-bit on-startup %s\n",
+ yang_dnode_get_string(dnode, NULL));
+}
+
+/*
* XPath: /frr-isisd:isis/instance/attach-send
*/
DEFPY_YANG(attached_bit_send, attached_bit_send_cmd, "[no] attached-bit send",
@@ -3107,6 +3143,9 @@ void isis_cli_init(void)
install_element(ISIS_NODE, &dynamic_hostname_cmd);
install_element(ISIS_NODE, &set_overload_bit_cmd);
+ install_element(ISIS_NODE, &set_overload_bit_on_startup_cmd);
+ install_element(ISIS_NODE, &no_set_overload_bit_on_startup_cmd);
+
install_element(ISIS_NODE, &attached_bit_send_cmd);
install_element(ISIS_NODE, &attached_bit_receive_ignore_cmd);
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index 5387f3703..63b4edb1e 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -68,6 +68,8 @@ static void lsp_l2_refresh_pseudo(struct thread *thread);
static void lsp_destroy(struct isis_lsp *lsp);
+static bool device_startup;
+
int lsp_id_cmp(uint8_t *id1, uint8_t *id2)
{
return memcmp(id1, id2, ISIS_SYS_ID_LEN + 2);
@@ -437,6 +439,21 @@ bool isis_level2_adj_up(struct isis_area *area)
return false;
}
+/*
+ * Unset the overload bit after the timer expires
+ */
+void set_overload_on_start_timer(struct thread *thread)
+{
+ struct isis_area *area = THREAD_ARG(thread);
+ assert(area);
+
+ area->t_overload_on_startup_timer = NULL;
+
+ /* Check if set-overload-bit is not currently configured */
+ if (!area->overload_configured)
+ isis_area_overload_bit_set(area, false);
+}
+
static void isis_reset_attach_bit(struct isis_adjacency *adj)
{
struct isis_area *area = adj->circuit->area;
@@ -1355,6 +1372,7 @@ int lsp_generate(struct isis_area *area, int level)
uint32_t seq_num = 0;
uint8_t lspid[ISIS_SYS_ID_LEN + 2];
uint16_t rem_lifetime, refresh_time;
+ uint32_t overload_time;
if ((area == NULL) || (area->is_type & level) != level)
return ISIS_ERROR;
@@ -1363,6 +1381,18 @@ int lsp_generate(struct isis_area *area, int level)
memcpy(&lspid, area->isis->sysid, ISIS_SYS_ID_LEN);
+ /* Check if device should be overloaded on startup */
+ if (device_startup) {
+ overload_time = isis_restart_read_overload_time(area);
+ if (overload_time > 0) {
+ isis_area_overload_bit_set(area, true);
+ thread_add_timer(master, set_overload_on_start_timer,
+ area, overload_time,
+ &area->t_overload_on_startup_timer);
+ }
+ device_startup = false;
+ }
+
/* only builds the lsp if the area shares the level */
oldlsp = lsp_search(&area->lspdb[level - 1], lspid);
if (oldlsp) {
@@ -2373,6 +2403,7 @@ int isis_lsp_iterate_is_reach(struct isis_lsp *lsp, uint16_t mtid,
void lsp_init(void)
{
+ device_startup = true;
hook_register(isis_adj_state_change_hook,
lsp_handle_adj_state_change);
}
diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h
index b13b2a35e..d7762324d 100644
--- a/isisd/isis_lsp.h
+++ b/isisd/isis_lsp.h
@@ -66,6 +66,7 @@ DECLARE_RBTREE_UNIQ(lspdb, struct isis_lsp, dbe, lspdb_compare);
void lsp_db_init(struct lspdb_head *head);
void lsp_db_fini(struct lspdb_head *head);
void lsp_tick(struct thread *thread);
+void set_overload_on_start_timer(struct thread *thread);
int lsp_generate(struct isis_area *area, int level);
#define lsp_regenerate_schedule(area, level, all_pseudo) \
diff --git a/isisd/isis_nb.c b/isisd/isis_nb.c
index a2ba33d07..4f4e6dc73 100644
--- a/isisd/isis_nb.c
+++ b/isisd/isis_nb.c
@@ -81,11 +81,18 @@ const struct frr_yang_module_info frr_isisd_info = {
},
},
{
- .xpath = "/frr-isisd:isis/instance/overload",
+ .xpath = "/frr-isisd:isis/instance/overload/enabled",
.cbs = {
.cli_show = cli_show_isis_overload,
- .modify = isis_instance_overload_modify,
- },
+ .modify = isis_instance_overload_enabled_modify,
+ }
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/overload/on-startup",
+ .cbs = {
+ .cli_show = cli_show_isis_overload_on_startup,
+ .modify = isis_instance_overload_on_startup_modify,
+ }
},
{
.xpath = "/frr-isisd:isis/instance/metric-style",
diff --git a/isisd/isis_nb.h b/isisd/isis_nb.h
index 00ca8be3b..a9f2eaea9 100644
--- a/isisd/isis_nb.h
+++ b/isisd/isis_nb.h
@@ -37,7 +37,8 @@ int isis_instance_dynamic_hostname_modify(struct nb_cb_modify_args *args);
int isis_instance_attached_send_modify(struct nb_cb_modify_args *args);
int isis_instance_attached_receive_modify(struct nb_cb_modify_args *args);
int isis_instance_attached_modify(struct nb_cb_modify_args *args);
-int isis_instance_overload_modify(struct nb_cb_modify_args *args);
+int isis_instance_overload_enabled_modify(struct nb_cb_modify_args *args);
+int isis_instance_overload_on_startup_modify(struct nb_cb_modify_args *args);
int isis_instance_metric_style_modify(struct nb_cb_modify_args *args);
int isis_instance_purge_originator_modify(struct nb_cb_modify_args *args);
int isis_instance_lsp_mtu_modify(struct nb_cb_modify_args *args);
@@ -442,6 +443,9 @@ void cli_show_isis_attached_receive(struct vty *vty,
bool show_defaults);
void cli_show_isis_overload(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults);
+void cli_show_isis_overload_on_startup(struct vty *vty,
+ const struct lyd_node *dnode,
+ bool show_defaults);
void cli_show_isis_metric_style(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults);
void cli_show_isis_area_pwd(struct vty *vty, const struct lyd_node *dnode,
diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c
index e0decf48f..1b7663fcf 100644
--- a/isisd/isis_nb_config.c
+++ b/isisd/isis_nb_config.c
@@ -336,9 +336,9 @@ int isis_instance_attached_modify(struct nb_cb_modify_args *args)
}
/*
- * XPath: /frr-isisd:isis/instance/overload
+ * XPath: /frr-isisd:isis/instance/overload/enabled
*/
-int isis_instance_overload_modify(struct nb_cb_modify_args *args)
+int isis_instance_overload_enabled_modify(struct nb_cb_modify_args *args)
{
struct isis_area *area;
bool overload;
@@ -348,12 +348,32 @@ int isis_instance_overload_modify(struct nb_cb_modify_args *args)
area = nb_running_get_entry(args->dnode, NULL, true);
overload = yang_dnode_get_bool(args->dnode, NULL);
+ area->overload_configured = overload;
+
isis_area_overload_bit_set(area, overload);
return NB_OK;
}
/*
+ * XPath: /frr-isisd:isis/instance/overload/on-startup
+ */
+int isis_instance_overload_on_startup_modify(struct nb_cb_modify_args *args)
+{
+ struct isis_area *area;
+ uint32_t overload_time;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ overload_time = yang_dnode_get_uint32(args->dnode, NULL);
+ area = nb_running_get_entry(args->dnode, NULL, true);
+ isis_area_overload_on_startup_set(area, overload_time);
+
+ return NB_OK;
+}
+
+/*
* XPath: /frr-isisd:isis/instance/metric-style
*/
int isis_instance_metric_style_modify(struct nb_cb_modify_args *args)
diff --git a/isisd/isisd.c b/isisd/isisd.c
index 54e6be597..efea1e5d5 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -1700,6 +1700,8 @@ DEFUN_NOSH (show_debugging,
if (IS_DEBUG_LFA)
print_debug(vty, DEBUG_LFA, 1);
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
@@ -3196,9 +3198,15 @@ void isis_area_overload_bit_set(struct isis_area *area, bool overload_bit)
if (new_overload_bit != area->overload_bit) {
area->overload_bit = new_overload_bit;
-
- if (new_overload_bit)
+ if (new_overload_bit) {
area->overload_counter++;
+ } else {
+ /* Cancel overload on startup timer if it's running */
+ if (area->t_overload_on_startup_timer) {
+ THREAD_OFF(area->t_overload_on_startup_timer);
+ area->t_overload_on_startup_timer = NULL;
+ }
+ }
#ifndef FABRICD
hook_call(isis_hook_db_overload, area);
@@ -3211,6 +3219,109 @@ void isis_area_overload_bit_set(struct isis_area *area, bool overload_bit)
#endif /* ifndef FABRICD */
}
+void isis_area_overload_on_startup_set(struct isis_area *area,
+ uint32_t startup_time)
+{
+ if (area->overload_on_startup_time != startup_time) {
+ area->overload_on_startup_time = startup_time;
+ isis_restart_write_overload_time(area, startup_time);
+ }
+}
+
+/*
+ * Returns the path of the file (non-volatile memory) that contains restart
+ * information.
+ */
+char *isis_restart_filepath()
+{
+ static char filepath[MAXPATHLEN];
+ snprintf(filepath, sizeof(filepath), ISISD_RESTART, "");
+ return filepath;
+}
+
+/*
+ * Record in non-volatile memory the overload on startup time.
+ */
+void isis_restart_write_overload_time(struct isis_area *isis_area,
+ uint32_t overload_time)
+{
+ char *filepath;
+ const char *area_name;
+ json_object *json;
+ json_object *json_areas;
+ json_object *json_area;
+
+ filepath = isis_restart_filepath();
+ area_name = isis_area->area_tag;
+
+ json = json_object_from_file(filepath);
+ if (json == NULL)
+ json = json_object_new_object();
+
+ json_object_object_get_ex(json, "areas", &json_areas);
+ if (!json_areas) {
+ json_areas = json_object_new_object();
+ json_object_object_add(json, "areas", json_areas);
+ }
+
+ json_object_object_get_ex(json_areas, area_name, &json_area);
+ if (!json_area) {
+ json_area = json_object_new_object();
+ json_object_object_add(json_areas, area_name, json_area);
+ }
+
+ json_object_int_add(json_area, "overload_time",
+ isis_area->overload_on_startup_time);
+ json_object_to_file_ext(filepath, json, JSON_C_TO_STRING_PRETTY);
+ json_object_free(json);
+}
+
+/*
+ * Fetch from non-volatile memory the overload on startup time.
+ */
+uint32_t isis_restart_read_overload_time(struct isis_area *isis_area)
+{
+ char *filepath;
+ const char *area_name;
+ json_object *json;
+ json_object *json_areas;
+ json_object *json_area;
+ json_object *json_overload_time;
+ uint32_t overload_time = 0;
+
+ filepath = isis_restart_filepath();
+ area_name = isis_area->area_tag;
+
+ json = json_object_from_file(filepath);
+ if (json == NULL)
+ json = json_object_new_object();
+
+ json_object_object_get_ex(json, "areas", &json_areas);
+ if (!json_areas) {
+ json_areas = json_object_new_object();
+ json_object_object_add(json, "areas", json_areas);
+ }
+
+ json_object_object_get_ex(json_areas, area_name, &json_area);
+ if (!json_area) {
+ json_area = json_object_new_object();
+ json_object_object_add(json_areas, area_name, json_area);
+ }
+
+ json_object_object_get_ex(json_area, "overload_time",
+ &json_overload_time);
+ if (json_overload_time) {
+ overload_time = json_object_get_int(json_overload_time);
+ }
+
+ json_object_object_del(json_areas, area_name);
+
+ json_object_to_file_ext(filepath, json, JSON_C_TO_STRING_PRETTY);
+ json_object_free(json);
+
+ return overload_time;
+}
+
void isis_area_attached_bit_send_set(struct isis_area *area, bool attached_bit)
{
diff --git a/isisd/isisd.h b/isisd/isisd.h
index 4951e5809..a9c1d6043 100644
--- a/isisd/isisd.h
+++ b/isisd/isisd.h
@@ -142,6 +142,7 @@ struct isis_area {
struct flags flags;
struct thread *t_tick; /* LSP walker */
struct thread *t_lsp_refresh[ISIS_LEVELS];
+ struct thread *t_overload_on_startup_timer;
struct timeval last_lsp_refresh_event[ISIS_LEVELS];
struct thread *t_rlfa_rib_update;
/* t_lsp_refresh is used in two ways:
@@ -180,7 +181,9 @@ struct isis_area {
char is_type; /* level-1 level-1-2 or level-2-only */
/* are we overloaded? */
char overload_bit;
+ bool overload_configured;
uint32_t overload_counter;
+ uint32_t overload_on_startup_time;
/* L1/L2 router identifier for inter-area traffic */
char attached_bit_send;
char attached_bit_rcv_ignore;
@@ -290,6 +293,8 @@ void isis_area_invalidate_routes(struct isis_area *area, int levels);
void isis_area_verify_routes(struct isis_area *area);
void isis_area_overload_bit_set(struct isis_area *area, bool overload_bit);
+void isis_area_overload_on_startup_set(struct isis_area *area,
+ uint32_t startup_time);
void isis_area_attached_bit_send_set(struct isis_area *area, bool attached_bit);
void isis_area_attached_bit_receive_set(struct isis_area *area,
bool attached_bit);
@@ -315,7 +320,10 @@ void show_isis_database_lspdb_json(struct json_object *json,
void show_isis_database_lspdb_vty(struct vty *vty, struct isis_area *area,
int level, struct lspdb_head *lspdb,
const char *argv, int ui_level);
-
+char *isis_restart_filepath(void);
+void isis_restart_write_overload_time(struct isis_area *isis_area,
+ uint32_t overload_time);
+uint32_t isis_restart_read_overload_time(struct isis_area *isis_area);
/* YANG paths */
#define ISIS_INSTANCE "/frr-isisd:isis/instance"
#define ISIS_SR "/frr-isisd:isis/instance/segment-routing"
diff --git a/ldpd/ldp_vty_cmds.c b/ldpd/ldp_vty_cmds.c
index f1fc74406..3d11d3137 100644
--- a/ldpd/ldp_vty_cmds.c
+++ b/ldpd/ldp_vty_cmds.c
@@ -774,7 +774,11 @@ DEFPY_NOSH (ldp_show_debugging_mpls_ldp,
"MPLS information\n"
"Label Distribution Protocol\n")
{
- return (ldp_vty_show_debugging(vty));
+ ldp_vty_show_debugging(vty);
+
+ cmd_show_lib_debugs(vty);
+
+ return CMD_SUCCESS;
}
static void
diff --git a/lib/command.c b/lib/command.c
index e555404c1..1fae32a04 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -48,6 +48,7 @@
#include "lib_errors.h"
#include "northbound_cli.h"
#include "network.h"
+#include "routemap.h"
#include "frrscript.h"
@@ -2442,6 +2443,11 @@ const char *host_config_get(void)
return host.config;
}
+void cmd_show_lib_debugs(struct vty *vty)
+{
+ route_map_show_debug(vty);
+}
+
void install_default(enum node_type node)
{
_install_element(node, &config_exit_cmd);
diff --git a/lib/command.h b/lib/command.h
index cde10a0a3..f4168dedd 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -401,6 +401,7 @@ struct cmd_node {
#define BGP_SOFT_IN_STR "Send route-refresh unless using 'soft-reconfiguration inbound'\n"
#define BGP_SOFT_OUT_STR "Resend all outbound updates\n"
#define BGP_SOFT_RSCLIENT_RIB_STR "Soft reconfig for rsclient RIB\n"
+#define BGP_ORR_DEBUG "Enable Optimal Route Reflection Debugging logs\n"
#define OSPF_STR "OSPF information\n"
#define NEIGHBOR_STR "Specify neighbor router\n"
#define DEBUG_STR "Debugging functions\n"
@@ -633,6 +634,12 @@ extern char *cmd_variable_comp2str(vector comps, unsigned short cols);
extern void command_setup_early_logging(const char *dest, const char *level);
+/*
+ * Allow a mechanism for `debug XXX` commands that live
+ * under the lib directory to output their debug status
+ */
+extern void cmd_show_lib_debugs(struct vty *vty);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/frrscript.c b/lib/frrscript.c
index a19bd0c3d..2e5693261 100644
--- a/lib/frrscript.c
+++ b/lib/frrscript.c
@@ -184,13 +184,14 @@ static void *codec_alloc(void *arg)
return e;
}
-#if 0
-static void codec_free(struct codec *c)
+static void codec_free(void *data)
{
- XFREE(MTYPE_TMP, c->typename);
- XFREE(MTYPE_TMP, c);
+ struct frrscript_codec *c = data;
+ char *constworkaroundandihateit = (char *)c->typename;
+
+ XFREE(MTYPE_SCRIPT, constworkaroundandihateit);
+ XFREE(MTYPE_SCRIPT, c);
}
-#endif
/* Lua function hash utils */
@@ -212,17 +213,18 @@ bool lua_function_hash_cmp(const void *d1, const void *d2)
void *lua_function_alloc(void *arg)
{
struct lua_function_state *tmp = arg;
-
struct lua_function_state *lfs =
XCALLOC(MTYPE_SCRIPT, sizeof(struct lua_function_state));
+
lfs->name = tmp->name;
lfs->L = tmp->L;
return lfs;
}
-static void lua_function_free(struct hash_bucket *b, void *data)
+static void lua_function_free(void *data)
{
- struct lua_function_state *lfs = (struct lua_function_state *)b->data;
+ struct lua_function_state *lfs = data;
+
lua_close(lfs->L);
XFREE(MTYPE_SCRIPT, lfs);
}
@@ -409,7 +411,8 @@ fail:
void frrscript_delete(struct frrscript *fs)
{
- hash_iterate(fs->lua_function_hash, lua_function_free, NULL);
+ hash_clean(fs->lua_function_hash, lua_function_free);
+ hash_free(fs->lua_function_hash);
XFREE(MTYPE_SCRIPT, fs->name);
XFREE(MTYPE_SCRIPT, fs);
}
@@ -425,4 +428,11 @@ void frrscript_init(const char *sd)
frrscript_register_type_codecs(frrscript_codecs_lib);
}
+void frrscript_fini(void)
+{
+ hash_clean(codec_hash, codec_free);
+ hash_free(codec_hash);
+
+ frrscript_names_destroy();
+}
#endif /* HAVE_SCRIPTING */
diff --git a/lib/frrscript.h b/lib/frrscript.h
index 4db3e6f1b..7fa01f70d 100644
--- a/lib/frrscript.h
+++ b/lib/frrscript.h
@@ -162,6 +162,11 @@ void frrscript_register_type_codecs(struct frrscript_codec *codecs);
void frrscript_init(const char *scriptdir);
/*
+ * On shutdown clean up memory associated with the scripting subsystem
+ */
+void frrscript_fini(void);
+
+/*
* This macro is mapped to every (name, value) in frrscript_call,
* so this in turn maps them onto their encoders
*/
diff --git a/lib/libfrr.c b/lib/libfrr.c
index f5aecd9f7..aee698185 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -1219,6 +1219,10 @@ void frr_fini(void)
db_close();
#endif
log_ref_fini();
+
+#ifdef HAVE_SCRIPTING
+ frrscript_fini();
+#endif
frr_pthread_finish();
zprivs_terminate(di->privs);
/* signal_init -> nothing needed */
diff --git a/lib/orr_msg.h b/lib/orr_msg.h
new file mode 100644
index 000000000..b0c4c48df
--- /dev/null
+++ b/lib/orr_msg.h
@@ -0,0 +1,94 @@
+/*
+ * Structures common to BGP, OSPF and ISIS for BGP Optimal Route Reflection
+ * Copyright (C) 2021 Samsung R&D Institute India - Bangalore.
+ * Madhurilatha Kuruganti
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _FRR_ORR_MSG_H
+#define _FRR_ORR_MSG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* REVISIT: Need to check if we can use zero length array */
+#define ORR_MAX_PREFIX 100
+#define ORR_GROUP_NAME_SIZE 32
+
+struct orr_prefix_metric {
+ struct prefix prefix;
+ uint32_t metric;
+};
+
+/* BGP-IGP Register for IGP metric */
+struct orr_igp_metric_reg {
+ bool reg;
+ uint8_t proto;
+ safi_t safi;
+ struct prefix prefix;
+ char group_name[ORR_GROUP_NAME_SIZE];
+};
+
+/* IGP-BGP message structures */
+struct orr_igp_metric_info {
+ /* IGP instance data. */
+ uint8_t proto;
+ uint32_t instId;
+
+ safi_t safi;
+
+ /* Add or delete routes */
+ bool add;
+
+ /* IGP metric from Active Root. */
+ struct prefix root;
+ uint32_t num_entries;
+ struct orr_prefix_metric nexthop[ORR_MAX_PREFIX];
+};
+
+/* BGP ORR Root node */
+struct orr_root {
+ afi_t afi;
+ safi_t safi;
+
+ char group_name[ORR_GROUP_NAME_SIZE];
+
+ /* MPLS_TE prefix and router ID */
+ struct prefix prefix;
+ struct in_addr router_id;
+
+ /* Advertising OSPF Router ID. */
+ struct in_addr adv_router;
+
+ /* BGP-ORR Received LSAs */
+ struct ospf_lsa *router_lsa_rcvd;
+
+ /* Routing tables from root node */
+ struct route_table *old_table; /* Old routing table. */
+ struct route_table *new_table; /* Current routing table. */
+
+ struct route_table *old_rtrs; /* Old ABR/ASBR RT. */
+ struct route_table *new_rtrs; /* New ABR/ASBR RT. */
+};
+
+/* Prototypes. */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FRR_ORR_MSG_H */
diff --git a/lib/routemap.c b/lib/routemap.c
index 3cc010c14..3a9279999 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -3174,6 +3174,12 @@ static struct cmd_node rmap_debug_node = {
.config_write = rmap_config_write_debug,
};
+void route_map_show_debug(struct vty *vty)
+{
+ if (rmap_debug)
+ vty_out(vty, "debug route-map\n");
+}
+
/* Configuration write function. */
static int rmap_config_write_debug(struct vty *vty)
{
diff --git a/lib/routemap.h b/lib/routemap.h
index a36592585..c2e9de6cf 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -1015,6 +1015,8 @@ extern void route_map_optimization_disabled_show(struct vty *vty,
bool show_defaults);
extern void route_map_cli_init(void);
+extern void route_map_show_debug(struct vty *vty);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/sockopt.c b/lib/sockopt.c
index 7a2b8a1c8..de11a9eab 100644
--- a/lib/sockopt.c
+++ b/lib/sockopt.c
@@ -693,3 +693,52 @@ int sockopt_tcp_mss_get(int sock)
return tcp_maxseg;
}
+
+int setsockopt_tcp_keepalive(int sock, uint16_t keepalive_idle,
+ uint16_t keepalive_intvl,
+ uint16_t keepalive_probes)
+{
+ int val = 1;
+
+ if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) < 0) {
+ flog_err_sys(EC_LIB_SYSTEM_CALL,
+ "%s failed: setsockopt SO_KEEPALIVE (%d): %s",
+ __func__, sock, safe_strerror(errno));
+ return -1;
+ }
+
+#if defined __OpenBSD__
+ return 0;
+#else
+ /* Send first probe after keepalive_idle seconds */
+ val = keepalive_idle;
+ if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)) <
+ 0) {
+ flog_err_sys(EC_LIB_SYSTEM_CALL,
+ "%s failed: setsockopt TCP_KEEPIDLE (%d): %s",
+ __func__, sock, safe_strerror(errno));
+ return -1;
+ }
+
+ /* Set interval between two probes */
+ val = keepalive_intvl;
+ if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val)) <
+ 0) {
+ flog_err_sys(EC_LIB_SYSTEM_CALL,
+ "%s failed: setsockopt TCP_KEEPINTVL (%d): %s",
+ __func__, sock, safe_strerror(errno));
+ return -1;
+ }
+
+ /* Set maximum probes */
+ val = keepalive_probes;
+ if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)) < 0) {
+ flog_err_sys(EC_LIB_SYSTEM_CALL,
+ "%s failed: setsockopt TCP_KEEPCNT (%d): %s",
+ __func__, sock, safe_strerror(errno));
+ return -1;
+ }
+
+ return 0;
+#endif
+}
diff --git a/lib/sockopt.h b/lib/sockopt.h
index 6c80841e3..694edf763 100644
--- a/lib/sockopt.h
+++ b/lib/sockopt.h
@@ -153,6 +153,28 @@ extern int sockopt_tcp_mss_set(int sock, int tcp_maxseg);
* Socket to get max segement size.
*/
extern int sockopt_tcp_mss_get(int sock);
+
+/*
+ * Configure TCP keepalive for a given socket
+ *
+ * sock
+ * Socket to enable keepalive option on.
+ *
+ * keepalive_idle
+ * number of seconds a connection needs to be idle
+ * before sending out keep-alive proves
+ *
+ * keepalive_intvl
+ * number of seconds between TCP keep-alive probes
+ *
+ * keepalive_probes
+ * max number of probers to send before giving up
+ * and killing tcp connection
+ */
+extern int setsockopt_tcp_keepalive(int sock, uint16_t keepalive_idle,
+ uint16_t keepalive_intvl,
+ uint16_t keepalive_probes);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/subdir.am b/lib/subdir.am
index d6defd714..e04e700eb 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -245,6 +245,7 @@ pkginclude_HEADERS += \
lib/ns.h \
lib/openbsd-queue.h \
lib/openbsd-tree.h \
+ lib/orr_msg.h \
lib/plist.h \
lib/prefix.h \
lib/printfrr.h \
diff --git a/lib/typesafe.h b/lib/typesafe.h
index 50c410ad2..8aeabb34e 100644
--- a/lib/typesafe.h
+++ b/lib/typesafe.h
@@ -850,9 +850,12 @@ macro_inline type *prefix ## _add(struct prefix##_head *h, type *item) \
struct thash_item **np = &h->hh.entries[hbits]; \
while (*np && (*np)->hashval < hval) \
np = &(*np)->next; \
- if (*np && cmpfn(container_of(*np, type, field.hi), item) == 0) { \
- h->hh.count--; \
- return container_of(*np, type, field.hi); \
+ while (*np && (*np)->hashval == hval) { \
+ if (cmpfn(container_of(*np, type, field.hi), item) == 0) { \
+ h->hh.count--; \
+ return container_of(*np, type, field.hi); \
+ } \
+ np = &(*np)->next; \
} \
item->field.hi.next = *np; \
*np = &item->field.hi; \
diff --git a/lib/zclient.h b/lib/zclient.h
index c3ea2a16f..fb5da9aad 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -100,6 +100,8 @@ enum zserv_client_capabilities {
extern struct sockaddr_storage zclient_addr;
extern socklen_t zclient_addr_len;
+#define ZAPI_ORR_FLAG_UNICAST 0x01
+
/* Zebra message types. */
typedef enum {
ZEBRA_INTERFACE_ADD,
@@ -1229,6 +1231,10 @@ enum zapi_opaque_registry {
LDP_RLFA_UNREGISTER_ALL = 8,
/* Announce LDP labels associated to a previously registered RLFA */
LDP_RLFA_LABELS = 9,
+ /* Register for IGP METRIC with OSPF/ISIS */
+ ORR_IGP_METRIC_REGISTER = 10,
+ /* Send SPF data to BGP */
+ ORR_IGP_METRIC_UPDATE = 11
};
/* Send the hello message.
diff --git a/nhrpd/nhrp_vty.c b/nhrpd/nhrp_vty.c
index 3a8baa234..53ba9eb12 100644
--- a/nhrpd/nhrp_vty.c
+++ b/nhrpd/nhrp_vty.c
@@ -126,6 +126,8 @@ DEFUN_NOSH(show_debugging_nhrp, show_debugging_nhrp_cmd,
debug_flags_desc[i].str);
}
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c
index a16f4f73e..fe742b912 100644
--- a/ospf6d/ospf6d.c
+++ b/ospf6d/ospf6d.c
@@ -115,6 +115,8 @@ DEFUN_NOSH (show_debugging_ospf6,
config_write_ospf6_debug(vty);
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c
index 258a93fb1..59f95c5da 100644
--- a/ospfd/ospf_dump.c
+++ b/ospfd/ospf_dump.c
@@ -54,15 +54,16 @@ unsigned long conf_debug_ospf_nsm = 0;
unsigned long conf_debug_ospf_lsa = 0;
unsigned long conf_debug_ospf_zebra = 0;
unsigned long conf_debug_ospf_nssa = 0;
-unsigned long conf_debug_ospf_te = 0;
+unsigned long conf_debug_ospf_te;
unsigned long conf_debug_ospf_ext = 0;
-unsigned long conf_debug_ospf_sr = 0;
-unsigned long conf_debug_ospf_ti_lfa = 0;
-unsigned long conf_debug_ospf_defaultinfo = 0;
-unsigned long conf_debug_ospf_ldp_sync = 0;
-unsigned long conf_debug_ospf_gr = 0;
+unsigned long conf_debug_ospf_sr;
+unsigned long conf_debug_ospf_ti_lfa;
+unsigned long conf_debug_ospf_defaultinfo;
+unsigned long conf_debug_ospf_ldp_sync;
+unsigned long conf_debug_ospf_gr;
unsigned long conf_debug_ospf_bfd;
unsigned long conf_debug_ospf_client_api;
+unsigned long conf_debug_ospf_orr;
/* Enable debug option variables -- valid only session. */
unsigned long term_debug_ospf_packet[5] = {0, 0, 0, 0, 0};
@@ -72,15 +73,16 @@ unsigned long term_debug_ospf_nsm = 0;
unsigned long term_debug_ospf_lsa = 0;
unsigned long term_debug_ospf_zebra = 0;
unsigned long term_debug_ospf_nssa = 0;
-unsigned long term_debug_ospf_te = 0;
+unsigned long term_debug_ospf_te;
unsigned long term_debug_ospf_ext = 0;
-unsigned long term_debug_ospf_sr = 0;
-unsigned long term_debug_ospf_ti_lfa = 0;
+unsigned long term_debug_ospf_sr;
+unsigned long term_debug_ospf_ti_lfa;
unsigned long term_debug_ospf_defaultinfo;
unsigned long term_debug_ospf_ldp_sync;
-unsigned long term_debug_ospf_gr = 0;
+unsigned long term_debug_ospf_gr;
unsigned long term_debug_ospf_bfd;
unsigned long term_debug_ospf_client_api;
+unsigned long term_debug_ospf_orr;
const char *ospf_redist_string(unsigned int route_type)
{
@@ -628,84 +630,9 @@ void ospf_packet_dump(struct stream *s)
stream_set_getp(s, gp);
}
-DEFUN (debug_ospf_packet,
+DEFPY (debug_ospf_packet,
debug_ospf_packet_cmd,
- "debug ospf [(1-65535)] packet <hello|dd|ls-request|ls-update|ls-ack|all> [<send [detail]|recv [detail]|detail>]",
- DEBUG_STR
- OSPF_STR
- "Instance ID\n"
- "OSPF packets\n"
- "OSPF Hello\n"
- "OSPF Database Description\n"
- "OSPF Link State Request\n"
- "OSPF Link State Update\n"
- "OSPF Link State Acknowledgment\n"
- "OSPF all packets\n"
- "Packet sent\n"
- "Detail Information\n"
- "Packet received\n"
- "Detail Information\n"
- "Detail Information\n")
-{
- int inst = (argv[2]->type == RANGE_TKN) ? 1 : 0;
- int detail = strmatch(argv[argc - 1]->text, "detail");
- int send = strmatch(argv[argc - (1 + detail)]->text, "send");
- int recv = strmatch(argv[argc - (1 + detail)]->text, "recv");
- char *packet = argv[3 + inst]->text;
-
- if (inst) // user passed instance ID
- {
- if (inst != ospf_instance)
- return CMD_NOT_MY_INSTANCE;
- }
-
- int type = 0;
- int flag = 0;
- int i;
-
- /* Check packet type. */
- if (strmatch(packet, "hello"))
- type = OSPF_DEBUG_HELLO;
- else if (strmatch(packet, "dd"))
- type = OSPF_DEBUG_DB_DESC;
- else if (strmatch(packet, "ls-request"))
- type = OSPF_DEBUG_LS_REQ;
- else if (strmatch(packet, "ls-update"))
- type = OSPF_DEBUG_LS_UPD;
- else if (strmatch(packet, "ls-ack"))
- type = OSPF_DEBUG_LS_ACK;
- else if (strmatch(packet, "all"))
- type = OSPF_DEBUG_ALL;
-
- /* Cases:
- * (none) = send + recv
- * detail = send + recv + detail
- * recv = recv
- * send = send
- * recv detail = recv + detail
- * send detail = send + detail
- */
- if (!send && !recv)
- send = recv = 1;
-
- flag |= (send) ? OSPF_DEBUG_SEND : 0;
- flag |= (recv) ? OSPF_DEBUG_RECV : 0;
- flag |= (detail) ? OSPF_DEBUG_DETAIL : 0;
-
- for (i = 0; i < 5; i++)
- if (type & (0x01 << i)) {
- if (vty->node == CONFIG_NODE)
- DEBUG_PACKET_ON(i, flag);
- else
- TERM_DEBUG_PACKET_ON(i, flag);
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN (no_debug_ospf_packet,
- no_debug_ospf_packet_cmd,
- "no debug ospf [(1-65535)] packet <hello|dd|ls-request|ls-update|ls-ack|all> [<send [detail]|recv [detail]|detail>]",
+ "[no$no] debug ospf [(1-65535)$inst] packet <hello|dd|ls-request|ls-update|ls-ack|all>$packet [<send$send [detail$detail]|recv$recv [detail$detail]|detail$detail>]",
NO_STR
DEBUG_STR
OSPF_STR
@@ -723,22 +650,13 @@ DEFUN (no_debug_ospf_packet,
"Detail Information\n"
"Detail Information\n")
{
- int inst = (argv[3]->type == RANGE_TKN) ? 1 : 0;
- int detail = strmatch(argv[argc - 1]->text, "detail");
- int send = strmatch(argv[argc - (1 + detail)]->text, "send");
- int recv = strmatch(argv[argc - (1 + detail)]->text, "recv");
- char *packet = argv[4 + inst]->text;
-
- if (inst) // user passed instance ID
- {
- if (inst != ospf_instance)
- return CMD_NOT_MY_INSTANCE;
- }
-
int type = 0;
int flag = 0;
int i;
+ if (inst && inst != ospf_instance)
+ return CMD_NOT_MY_INSTANCE;
+
/* Check packet type. */
if (strmatch(packet, "hello"))
type = OSPF_DEBUG_HELLO;
@@ -761,8 +679,10 @@ DEFUN (no_debug_ospf_packet,
* recv detail = recv + detail
* send detail = send + detail
*/
- if (!send && !recv)
- send = recv = 1;
+ if (!send && !recv) {
+ flag |= OSPF_DEBUG_SEND;
+ flag |= OSPF_DEBUG_RECV;
+ }
flag |= (send) ? OSPF_DEBUG_SEND : 0;
flag |= (recv) ? OSPF_DEBUG_RECV : 0;
@@ -770,10 +690,17 @@ DEFUN (no_debug_ospf_packet,
for (i = 0; i < 5; i++)
if (type & (0x01 << i)) {
- if (vty->node == CONFIG_NODE)
- DEBUG_PACKET_OFF(i, flag);
- else
- TERM_DEBUG_PACKET_OFF(i, flag);
+ if (vty->node == CONFIG_NODE) {
+ if (no)
+ DEBUG_PACKET_OFF(i, flag);
+ else
+ DEBUG_PACKET_ON(i, flag);
+ } else {
+ if (no)
+ TERM_DEBUG_PACKET_OFF(i, flag);
+ else
+ TERM_DEBUG_PACKET_ON(i, flag);
+ }
}
#ifdef DEBUG
@@ -1457,194 +1384,248 @@ DEFUN (no_debug_ospf_instance_nssa,
return CMD_SUCCESS;
}
-DEFUN (debug_ospf_te,
+DEFPY (debug_ospf_te,
debug_ospf_te_cmd,
- "debug ospf te",
- DEBUG_STR
- OSPF_STR
- "OSPF-TE information\n")
-{
- if (vty->node == CONFIG_NODE)
- CONF_DEBUG_ON(te, TE);
- TERM_DEBUG_ON(te, TE);
- return CMD_SUCCESS;
-}
-
-DEFUN (no_debug_ospf_te,
- no_debug_ospf_te_cmd,
- "no debug ospf te",
+ "[no$no] debug ospf [(1-65535)$instance] te",
NO_STR
DEBUG_STR
OSPF_STR
+ "Instance ID\n"
"OSPF-TE information\n")
{
- if (vty->node == CONFIG_NODE)
- CONF_DEBUG_OFF(te, TE);
- TERM_DEBUG_OFF(te, TE);
+ if (instance && instance != ospf_instance)
+ return CMD_NOT_MY_INSTANCE;
+
+ if (vty->node == CONFIG_NODE) {
+ if (no)
+ DEBUG_OFF(te, TE);
+ else
+ DEBUG_ON(te, TE);
+ } else {
+ if (no)
+ TERM_DEBUG_OFF(te, TE);
+ else
+ TERM_DEBUG_ON(te, TE);
+ }
+
return CMD_SUCCESS;
}
-DEFUN (debug_ospf_sr,
+DEFPY (debug_ospf_sr,
debug_ospf_sr_cmd,
- "debug ospf sr",
+ "[no$no] debug ospf [(1-65535)$instance] sr",
+ NO_STR
DEBUG_STR
OSPF_STR
+ "Instance ID\n"
"OSPF-SR information\n")
{
- if (vty->node == CONFIG_NODE)
- CONF_DEBUG_ON(sr, SR);
- TERM_DEBUG_ON(sr, SR);
+ if (instance && instance != ospf_instance)
+ return CMD_NOT_MY_INSTANCE;
+
+ if (vty->node == CONFIG_NODE) {
+ if (no)
+ DEBUG_OFF(sr, SR);
+ else
+ DEBUG_ON(sr, SR);
+ } else {
+ if (no)
+ TERM_DEBUG_OFF(sr, SR);
+ else
+ TERM_DEBUG_ON(sr, SR);
+ }
+
return CMD_SUCCESS;
}
-DEFUN (no_debug_ospf_sr,
- no_debug_ospf_sr_cmd,
- "no debug ospf sr",
+DEFPY (debug_ospf_ti_lfa,
+ debug_ospf_ti_lfa_cmd,
+ "[no$no] debug ospf [(1-65535)$instance] ti-lfa",
NO_STR
DEBUG_STR
OSPF_STR
- "OSPF-SR information\n")
+ "Instance ID\n"
+ "OSPF-SR TI-LFA information\n")
{
- if (vty->node == CONFIG_NODE)
- CONF_DEBUG_OFF(sr, SR);
- TERM_DEBUG_OFF(sr, SR);
- return CMD_SUCCESS;
-}
+ if (instance && instance != ospf_instance)
+ return CMD_NOT_MY_INSTANCE;
-DEFUN(debug_ospf_ti_lfa, debug_ospf_ti_lfa_cmd, "debug ospf ti-lfa",
- DEBUG_STR OSPF_STR "OSPF-SR TI-LFA information\n")
-{
- if (vty->node == CONFIG_NODE)
- CONF_DEBUG_ON(ti_lfa, TI_LFA);
- TERM_DEBUG_ON(ti_lfa, TI_LFA);
- return CMD_SUCCESS;
-}
+ if (vty->node == CONFIG_NODE) {
+ if (no)
+ DEBUG_OFF(ti_lfa, TI_LFA);
+ else
+ DEBUG_ON(ti_lfa, TI_LFA);
+ } else {
+ if (no)
+ TERM_DEBUG_OFF(ti_lfa, TI_LFA);
+ else
+ TERM_DEBUG_ON(ti_lfa, TI_LFA);
+ }
-DEFUN(no_debug_ospf_ti_lfa, no_debug_ospf_ti_lfa_cmd, "no debug ospf ti-lfa",
- NO_STR DEBUG_STR OSPF_STR "OSPF-SR TI-LFA information\n")
-{
- if (vty->node == CONFIG_NODE)
- CONF_DEBUG_OFF(ti_lfa, TI_LFA);
- TERM_DEBUG_OFF(ti_lfa, TI_LFA);
return CMD_SUCCESS;
}
-DEFUN (debug_ospf_default_info,
+DEFPY (debug_ospf_default_info,
debug_ospf_default_info_cmd,
- "debug ospf default-information",
+ "[no$no] debug ospf [(1-65535)$instance] default-information",
+ NO_STR
DEBUG_STR
OSPF_STR
+ "Instance ID\n"
"OSPF default information\n")
{
- if (vty->node == CONFIG_NODE)
- CONF_DEBUG_ON(defaultinfo, DEFAULTINFO);
- TERM_DEBUG_ON(defaultinfo, DEFAULTINFO);
+ if (instance && instance != ospf_instance)
+ return CMD_NOT_MY_INSTANCE;
+
+ if (vty->node == CONFIG_NODE) {
+ if (no)
+ DEBUG_OFF(defaultinfo, DEFAULTINFO);
+ else
+ DEBUG_ON(defaultinfo, DEFAULTINFO);
+ } else {
+ if (no)
+ TERM_DEBUG_OFF(defaultinfo, DEFAULTINFO);
+ else
+ TERM_DEBUG_ON(defaultinfo, DEFAULTINFO);
+ }
+
return CMD_SUCCESS;
}
-DEFUN (no_debug_ospf_default_info,
- no_debug_ospf_default_info_cmd,
- "no debug ospf default-information",
+DEFPY (debug_ospf_ldp_sync,
+ debug_ospf_ldp_sync_cmd,
+ "[no$no] debug ospf [(1-65535)$instance] ldp-sync",
NO_STR
DEBUG_STR
OSPF_STR
- "OSPF default information\n")
-{
- if (vty->node == CONFIG_NODE)
- CONF_DEBUG_OFF(defaultinfo, DEFAULTINFO);
- TERM_DEBUG_OFF(defaultinfo, DEFAULTINFO);
- return CMD_SUCCESS;
-}
-
-DEFUN(debug_ospf_ldp_sync,
- debug_ospf_ldp_sync_cmd,
- "debug ospf ldp-sync",
- DEBUG_STR OSPF_STR
- "OSPF LDP-Sync information\n")
+ "Instance ID\n"
+ "OSPF LDP-Sync information\n")
{
- if (vty->node == CONFIG_NODE)
- CONF_DEBUG_ON(ldp_sync, LDP_SYNC);
- TERM_DEBUG_ON(ldp_sync, LDP_SYNC);
- return CMD_SUCCESS;
-}
+ if (instance && instance != ospf_instance)
+ return CMD_NOT_MY_INSTANCE;
-DEFUN(no_debug_ospf_ldp_sync,
- no_debug_ospf_ldp_sync_cmd,
- "no debug ospf ldp-sync",
- NO_STR
- DEBUG_STR
- OSPF_STR
- "OSPF LDP-Sync information\n")
-{
- if (vty->node == CONFIG_NODE)
- CONF_DEBUG_OFF(ldp_sync, LDP_SYNC);
- TERM_DEBUG_OFF(ldp_sync, LDP_SYNC);
+ if (vty->node == CONFIG_NODE) {
+ if (no)
+ DEBUG_OFF(ldp_sync, LDP_SYNC);
+ else
+ DEBUG_ON(ldp_sync, LDP_SYNC);
+ } else {
+ if (no)
+ TERM_DEBUG_OFF(ldp_sync, LDP_SYNC);
+ else
+ TERM_DEBUG_ON(ldp_sync, LDP_SYNC);
+ }
return CMD_SUCCESS;
}
-DEFPY(debug_ospf_gr, debug_ospf_gr_cmd, "[no$no] debug ospf graceful-restart",
- NO_STR DEBUG_STR OSPF_STR "OSPF Graceful Restart\n")
+DEFPY (debug_ospf_gr,
+ debug_ospf_gr_cmd,
+ "[no$no] debug ospf [(1-65535)$instance] graceful-restart",
+ NO_STR
+ DEBUG_STR
+ OSPF_STR
+ "Instance ID\n"
+ "OSPF Graceful Restart\n")
{
- if (vty->node == CONFIG_NODE)
- CONF_DEBUG_ON(gr, GR);
+ if (instance && instance != ospf_instance)
+ return CMD_NOT_MY_INSTANCE;
- if (!no)
- TERM_DEBUG_ON(gr, GR);
- else
+ if (vty->node == CONFIG_NODE) {
+ if (no)
+ CONF_DEBUG_OFF(gr, GR);
+ else
+ CONF_DEBUG_ON(gr, GR);
+ }
+
+ if (no)
TERM_DEBUG_OFF(gr, GR);
+ else
+ TERM_DEBUG_ON(gr, GR);
return CMD_SUCCESS;
}
-DEFPY(debug_ospf_bfd, debug_ospf_bfd_cmd,
- "[no] debug ospf bfd",
- NO_STR
- DEBUG_STR
- OSPF_STR
- "Bidirection Forwarding Detection\n")
+DEFPY (debug_ospf_bfd,
+ debug_ospf_bfd_cmd,
+ "[no] debug ospf [(1-65535)$instance] bfd",
+ NO_STR
+ DEBUG_STR
+ OSPF_STR
+ "Instance ID\n"
+ "Bidirection Forwarding Detection\n")
{
+ if (instance && instance != ospf_instance)
+ return CMD_NOT_MY_INSTANCE;
+
if (vty->node == CONFIG_NODE) {
if (no) {
bfd_protocol_integration_set_debug(false);
- CONF_DEBUG_OFF(bfd, BFD_LIB);
+ DEBUG_OFF(bfd, BFD_LIB);
} else {
bfd_protocol_integration_set_debug(true);
- CONF_DEBUG_ON(bfd, BFD_LIB);
+ DEBUG_ON(bfd, BFD_LIB);
}
+ } else {
+ if (no)
+ TERM_DEBUG_OFF(bfd, BFD_LIB);
+ else
+ TERM_DEBUG_ON(bfd, BFD_LIB);
}
- if (no)
- TERM_DEBUG_OFF(bfd, BFD_LIB);
- else
- TERM_DEBUG_ON(bfd, BFD_LIB);
-
return CMD_SUCCESS;
}
-DEFUN(debug_ospf_client_api,
- debug_ospf_client_api_cmd,
- "debug ospf client-api",
- DEBUG_STR OSPF_STR
- "OSPF client API information\n")
+DEFPY (debug_ospf_client_api,
+ debug_ospf_client_api_cmd,
+ "[no$no] debug ospf [(1-65535)$instance] client-api",
+ NO_STR
+ DEBUG_STR
+ OSPF_STR
+ "Instance ID\n"
+ "OSPF client API information\n")
{
- if (vty->node == CONFIG_NODE)
- CONF_DEBUG_ON(client_api, CLIENT_API);
- TERM_DEBUG_ON(client_api, CLIENT_API);
+ if (instance && instance != ospf_instance)
+ return CMD_NOT_MY_INSTANCE;
+
+ if (vty->node == CONFIG_NODE) {
+ if (no)
+ DEBUG_OFF(client_api, CLIENT_API);
+ else
+ DEBUG_ON(client_api, CLIENT_API);
+ } else {
+ if (no)
+ TERM_DEBUG_OFF(client_api, CLIENT_API);
+ else
+ TERM_DEBUG_ON(client_api, CLIENT_API);
+ }
+
return CMD_SUCCESS;
}
-DEFUN(no_debug_ospf_client_api,
- no_debug_ospf_client_api_cmd,
- "no debug ospf client-api",
- NO_STR
- DEBUG_STR
- OSPF_STR
- "OSPF client API information\n")
+DEFPY (debug_ospf_orr,
+ debug_ospf_orr_cmd,
+ "[no$no] debug ospf [(1-65535)$instance] orr",
+ NO_STR
+ DEBUG_STR
+ OSPF_STR
+ "Instance ID\n"
+ "OSPF ORR information\n")
{
- if (vty->node == CONFIG_NODE)
- CONF_DEBUG_OFF(client_api, CLIENT_API);
- TERM_DEBUG_OFF(client_api, CLIENT_API);
+ if (instance && instance != ospf_instance)
+ return CMD_NOT_MY_INSTANCE;
+
+ if (vty->node == CONFIG_NODE) {
+ if (no)
+ DEBUG_OFF(orr, ORR);
+ else
+ DEBUG_ON(orr, ORR);
+ } else {
+ if (no)
+ TERM_DEBUG_OFF(orr, ORR);
+ else
+ TERM_DEBUG_ON(orr, ORR);
+ }
return CMD_SUCCESS;
}
@@ -1691,6 +1672,8 @@ DEFUN (no_debug_ospf,
for (i = 0; i < 5; i++)
DEBUG_PACKET_OFF(i, flag);
+
+ DEBUG_OFF(orr, ORR);
}
for (i = 0; i < 5; i++)
@@ -1721,6 +1704,7 @@ DEFUN (no_debug_ospf,
TERM_DEBUG_OFF(ti_lfa, TI_LFA);
TERM_DEBUG_OFF(bfd, BFD_LIB);
TERM_DEBUG_OFF(client_api, CLIENT_API);
+ TERM_DEBUG_OFF(orr, ORR);
return CMD_SUCCESS;
}
@@ -1816,7 +1800,7 @@ static int show_debugging_ospf_common(struct vty *vty)
}
if (IS_DEBUG_OSPF(defaultinfo, DEFAULTINFO) == OSPF_DEBUG_DEFAULTINFO)
- vty_out(vty, "OSPF default information is on\n");
+ vty_out(vty, " OSPF default information is on\n");
/* Show debug status for NSSA. */
if (IS_DEBUG_OSPF(nssa, NSSA) == OSPF_DEBUG_NSSA)
@@ -1850,6 +1834,12 @@ static int show_debugging_ospf_common(struct vty *vty)
if (IS_DEBUG_OSPF(client_api, CLIENT_API) == OSPF_DEBUG_CLIENT_API)
vty_out(vty, " OSPF client-api debugging is on\n");
+ /* Show debug status for ORR. */
+ if (IS_DEBUG_OSPF(orr, ORR) == OSPF_DEBUG_ORR)
+ vty_out(vty, " OSPF ORR debugging is on\n");
+
+ vty_out(vty, "\n");
+
return CMD_SUCCESS;
}
@@ -1860,7 +1850,11 @@ DEFUN_NOSH (show_debugging_ospf,
DEBUG_STR
OSPF_STR)
{
- return show_debugging_ospf_common(vty);
+ show_debugging_ospf_common(vty);
+
+ cmd_show_lib_debugs(vty);
+
+ return CMD_SUCCESS;
}
DEFUN_NOSH (show_debugging_ospf_instance,
@@ -1878,7 +1872,11 @@ DEFUN_NOSH (show_debugging_ospf_instance,
if (instance != ospf_instance)
return CMD_NOT_MY_INSTANCE;
- return show_debugging_ospf_common(vty);
+ show_debugging_ospf_common(vty);
+
+ cmd_show_lib_debugs(vty);
+
+ return CMD_SUCCESS;
}
static int config_write_debug(struct vty *vty);
@@ -1978,7 +1976,7 @@ static int config_write_debug(struct vty *vty)
& (OSPF_DEBUG_SEND_RECV | OSPF_DEBUG_DETAIL);
if (r == (OSPF_DEBUG_SEND_RECV | OSPF_DEBUG_DETAIL)) {
vty_out(vty, "debug ospf%s packet all detail\n", str);
- return 1;
+ write = 1;
}
/* debug ospf packet all. */
@@ -1991,7 +1989,7 @@ static int config_write_debug(struct vty *vty)
if (conf_debug_ospf_packet[i] & OSPF_DEBUG_DETAIL)
vty_out(vty, "debug ospf%s packet %s detail\n",
str, type_str[i]);
- return 1;
+ write = 1;
}
/* debug ospf packet (hello|dd|ls-request|ls-update|ls-ack)
@@ -2047,6 +2045,19 @@ static int config_write_debug(struct vty *vty)
write = 1;
}
+ /* debug ospf default-information */
+ if (IS_CONF_DEBUG_OSPF(defaultinfo, DEFAULTINFO) ==
+ OSPF_DEBUG_DEFAULTINFO) {
+ vty_out(vty, "debug ospf%s default-information\n", str);
+ write = 1;
+ }
+
+ /* debug ospf orr */
+ if (IS_CONF_DEBUG_OSPF(orr, ORR) == OSPF_DEBUG_ORR) {
+ vty_out(vty, "debug ospf%s orr\n", str);
+ write = 1;
+ }
+
return write;
}
@@ -2068,24 +2079,18 @@ void ospf_debug_init(void)
install_element(ENABLE_NODE, &debug_ospf_default_info_cmd);
install_element(ENABLE_NODE, &debug_ospf_ldp_sync_cmd);
install_element(ENABLE_NODE, &debug_ospf_client_api_cmd);
+ install_element(ENABLE_NODE, &debug_ospf_orr_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_ism_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_nsm_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_lsa_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_zebra_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_event_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_nssa_cmd);
- install_element(ENABLE_NODE, &no_debug_ospf_te_cmd);
- install_element(ENABLE_NODE, &no_debug_ospf_sr_cmd);
- install_element(ENABLE_NODE, &no_debug_ospf_ti_lfa_cmd);
- install_element(ENABLE_NODE, &no_debug_ospf_default_info_cmd);
- install_element(ENABLE_NODE, &no_debug_ospf_ldp_sync_cmd);
- install_element(ENABLE_NODE, &no_debug_ospf_client_api_cmd);
install_element(ENABLE_NODE, &debug_ospf_gr_cmd);
install_element(ENABLE_NODE, &debug_ospf_bfd_cmd);
install_element(ENABLE_NODE, &show_debugging_ospf_instance_cmd);
install_element(ENABLE_NODE, &debug_ospf_packet_cmd);
- install_element(ENABLE_NODE, &no_debug_ospf_packet_cmd);
install_element(ENABLE_NODE, &debug_ospf_instance_nsm_cmd);
install_element(ENABLE_NODE, &debug_ospf_instance_lsa_cmd);
@@ -2100,7 +2105,6 @@ void ospf_debug_init(void)
install_element(ENABLE_NODE, &no_debug_ospf_cmd);
install_element(CONFIG_NODE, &debug_ospf_packet_cmd);
- install_element(CONFIG_NODE, &no_debug_ospf_packet_cmd);
install_element(CONFIG_NODE, &debug_ospf_ism_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_ism_cmd);
@@ -2115,17 +2119,12 @@ void ospf_debug_init(void)
install_element(CONFIG_NODE, &debug_ospf_default_info_cmd);
install_element(CONFIG_NODE, &debug_ospf_ldp_sync_cmd);
install_element(CONFIG_NODE, &debug_ospf_client_api_cmd);
+ install_element(CONFIG_NODE, &debug_ospf_orr_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_nsm_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_lsa_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_zebra_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_event_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_nssa_cmd);
- install_element(CONFIG_NODE, &no_debug_ospf_te_cmd);
- install_element(CONFIG_NODE, &no_debug_ospf_sr_cmd);
- install_element(CONFIG_NODE, &no_debug_ospf_ti_lfa_cmd);
- install_element(CONFIG_NODE, &no_debug_ospf_default_info_cmd);
- install_element(CONFIG_NODE, &no_debug_ospf_ldp_sync_cmd);
- install_element(CONFIG_NODE, &no_debug_ospf_client_api_cmd);
install_element(CONFIG_NODE, &debug_ospf_gr_cmd);
install_element(CONFIG_NODE, &debug_ospf_bfd_cmd);
diff --git a/ospfd/ospf_dump.h b/ospfd/ospf_dump.h
index 251be7c8d..e9ba8fc79 100644
--- a/ospfd/ospf_dump.h
+++ b/ospfd/ospf_dump.h
@@ -70,6 +70,8 @@
#define OSPF_DEBUG_CLIENT_API 0x01
+#define OSPF_DEBUG_ORR 0x01
+
/* Macro for setting debug option. */
#define CONF_DEBUG_PACKET_ON(a, b) conf_debug_ospf_packet[a] |= (b)
#define CONF_DEBUG_PACKET_OFF(a, b) conf_debug_ospf_packet[a] &= ~(b)
@@ -129,6 +131,8 @@
#define AREA_NAME(A) ospf_area_name_string ((A))
#define IF_NAME(I) ospf_if_name_string ((I))
+#define IS_DEBUG_OSPF_ORR IS_DEBUG_OSPF(orr, ORR)
+
/* Extern debug flag. */
extern unsigned long term_debug_ospf_packet[];
extern unsigned long term_debug_ospf_event;
@@ -146,6 +150,7 @@ extern unsigned long term_debug_ospf_ldp_sync;
extern unsigned long term_debug_ospf_gr;
extern unsigned long term_debug_ospf_bfd;
extern unsigned long term_debug_ospf_client_api;
+extern unsigned long term_debug_ospf_orr;
/* Message Strings. */
extern char *ospf_lsa_type_str[];
diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c
index 646d31836..a0b14e73e 100644
--- a/ospfd/ospf_interface.c
+++ b/ospfd/ospf_interface.c
@@ -461,13 +461,13 @@ struct ospf_interface *ospf_if_lookup_recv_if(struct ospf *ospf,
{
struct route_node *rn;
struct prefix_ipv4 addr;
- struct ospf_interface *oi, *match;
+ struct ospf_interface *oi, *match, *unnumbered_match;
addr.family = AF_INET;
addr.prefix = src;
addr.prefixlen = IPV4_MAX_BITLEN;
- match = NULL;
+ match = unnumbered_match = NULL;
for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) {
oi = rn->info;
@@ -482,7 +482,7 @@ struct ospf_interface *ospf_if_lookup_recv_if(struct ospf *ospf,
continue;
if (CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED))
- match = oi;
+ unnumbered_match = oi;
else if (prefix_match(CONNECTED_PREFIX(oi->connected),
(struct prefix *)&addr)) {
if ((match == NULL) || (match->address->prefixlen
@@ -491,7 +491,10 @@ struct ospf_interface *ospf_if_lookup_recv_if(struct ospf *ospf,
}
}
- return match;
+ if (match)
+ return match;
+
+ return unnumbered_match;
}
void ospf_interface_fifo_flush(struct ospf_interface *oi)
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
index 0df0072f6..c67181cba 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -52,6 +52,8 @@
#include "ospfd/ospf_zebra.h"
#include "ospfd/ospf_abr.h"
#include "ospfd/ospf_errors.h"
+#include "ospfd/ospf_te.h"
+#include "ospfd/ospf_orr.h"
static struct ospf_lsa *ospf_handle_summarylsa_lsId_chg(struct ospf *ospf,
struct prefix_ipv4 *p,
@@ -2640,6 +2642,13 @@ ospf_router_lsa_install(struct ospf *ospf, struct ospf_lsa *new, int rt_recalc)
ospf_refresher_register_lsa(ospf, new);
}
+ /* For BGP ORR SPF should be calculated from specified root(s) */
+ else if (ospf->orr_spf_request) {
+ ospf_lsa_unlock(&area->router_lsa_rcvd);
+ area->router_lsa_rcvd = ospf_lsa_lock(new);
+ ospf_orr_root_update_rcvd_lsa(area->router_lsa_rcvd);
+ }
+
if (rt_recalc)
ospf_spf_calculate_schedule(ospf, SPF_FLAG_ROUTER_LSA_INSTALL);
return new;
@@ -2651,7 +2660,6 @@ static struct ospf_lsa *ospf_network_lsa_install(struct ospf *ospf,
struct ospf_lsa *new,
int rt_recalc)
{
-
/* RFC 2328 Section 13.2 Router-LSAs and network-LSAs
The entire routing table must be recalculated, starting with
the shortest path calculations for each area (not just the
@@ -3400,6 +3408,82 @@ struct ospf_lsa *ospf_lsa_lookup_by_id(struct ospf_area *area, uint32_t type,
return NULL;
}
+struct ospf_lsa *ospf_lsa_lookup_by_adv_rid(struct ospf_area *area,
+ uint32_t type, struct in_addr id)
+{
+ struct ospf_lsa *lsa = NULL;
+ struct route_node *rn = NULL;
+
+ switch (type) {
+ case OSPF_ROUTER_LSA:
+ for (rn = route_top(ROUTER_LSDB(area)); rn;
+ rn = route_next(rn)) {
+ lsa = rn->info;
+ if (lsa) {
+ if (IPV4_ADDR_SAME(&lsa->data->adv_router,
+ &id)) {
+ route_unlock_node(rn);
+ return lsa;
+ }
+ }
+ }
+ break;
+ case OSPF_NETWORK_LSA:
+ case OSPF_SUMMARY_LSA:
+ case OSPF_ASBR_SUMMARY_LSA:
+ case OSPF_AS_EXTERNAL_LSA:
+ case OSPF_AS_NSSA_LSA:
+ case OSPF_OPAQUE_LINK_LSA:
+ case OSPF_OPAQUE_AREA_LSA:
+ case OSPF_OPAQUE_AS_LSA:
+ /* Currently not used. */
+ break;
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+struct ospf_lsa *ospf_lsa_lookup_by_mpls_te_rid(struct ospf_area *area,
+ uint32_t type,
+ struct in_addr id)
+{
+ struct ospf_lsa *lsa = NULL;
+ struct route_node *rn = NULL;
+ struct lsa_header *lsah = NULL;
+ uint32_t lsid;
+ uint8_t opaque_type;
+ struct tlv_header *tlvh = NULL;
+ struct te_tlv_router_addr *router_addr = NULL;
+
+ if (type != OSPF_OPAQUE_AREA_LSA)
+ return NULL;
+
+ for (rn = route_top(OPAQUE_AREA_LSDB(area)); rn; rn = route_next(rn)) {
+ lsa = rn->info;
+ if (lsa) {
+ lsah = lsa->data;
+ lsid = ntohl(lsah->id.s_addr);
+ opaque_type = GET_OPAQUE_TYPE(lsid);
+ if (opaque_type != OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA)
+ continue;
+
+ tlvh = TLV_HDR_TOP(lsah);
+ if (!tlvh ||
+ (ntohs(tlvh->type) != TE_TLV_ROUTER_ADDR) ||
+ (ntohs(tlvh->length) != TE_LINK_SUBTLV_DEF_SIZE))
+ continue;
+ router_addr = (struct te_tlv_router_addr *)tlvh;
+ if (IPV4_ADDR_SAME(&router_addr->value, &id)) {
+ route_unlock_node(rn);
+ return lsa;
+ }
+ }
+ }
+ return NULL;
+}
+
struct ospf_lsa *ospf_lsa_lookup_by_header(struct ospf_area *area,
struct lsa_header *lsah)
{
@@ -3823,8 +3907,9 @@ struct ospf_lsa *ospf_lsa_refresh(struct ospf *ospf, struct ospf_lsa *lsa)
struct as_external_lsa *al;
struct prefix_ipv4 p;
- assert(CHECK_FLAG(lsa->flags, OSPF_LSA_SELF));
- assert(IS_LSA_SELF(lsa));
+ if (!CHECK_FLAG(lsa->flags, OSPF_LSA_SELF) && !IS_LSA_SELF(lsa) &&
+ !IS_LSA_ORR(lsa))
+ return NULL;
assert(lsa->lock > 0);
switch (lsa->data->type) {
@@ -3894,7 +3979,8 @@ void ospf_refresher_register_lsa(struct ospf *ospf, struct ospf_lsa *lsa)
uint16_t index, current_index;
assert(lsa->lock > 0);
- assert(IS_LSA_SELF(lsa));
+ if (!IS_LSA_SELF(lsa) && !IS_LSA_ORR(lsa))
+ return;
if (lsa->refresh_list < 0) {
int delay;
@@ -3943,7 +4029,8 @@ void ospf_refresher_register_lsa(struct ospf *ospf, struct ospf_lsa *lsa)
void ospf_refresher_unregister_lsa(struct ospf *ospf, struct ospf_lsa *lsa)
{
assert(lsa->lock > 0);
- assert(IS_LSA_SELF(lsa));
+ if (!IS_LSA_SELF(lsa) || !IS_LSA_ORR(lsa))
+ return;
if (lsa->refresh_list >= 0) {
struct list *refresh_list =
ospf->lsa_refresh_queue.qs[lsa->refresh_list];
diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h
index 97c15d1e3..a2a2393c9 100644
--- a/ospfd/ospf_lsa.h
+++ b/ospfd/ospf_lsa.h
@@ -74,15 +74,16 @@ struct vertex;
/* OSPF LSA. */
struct ospf_lsa {
/* LSA origination flag. */
- uint8_t flags;
-#define OSPF_LSA_SELF 0x01
-#define OSPF_LSA_SELF_CHECKED 0x02
-#define OSPF_LSA_RECEIVED 0x04
-#define OSPF_LSA_APPROVED 0x08
-#define OSPF_LSA_DISCARD 0x10
-#define OSPF_LSA_LOCAL_XLT 0x20
-#define OSPF_LSA_PREMATURE_AGE 0x40
-#define OSPF_LSA_IN_MAXAGE 0x80
+ uint16_t flags;
+#define OSPF_LSA_SELF 0x0001
+#define OSPF_LSA_SELF_CHECKED 0x0002
+#define OSPF_LSA_RECEIVED 0x0004
+#define OSPF_LSA_APPROVED 0x0008
+#define OSPF_LSA_DISCARD 0x0010
+#define OSPF_LSA_LOCAL_XLT 0x0020
+#define OSPF_LSA_PREMATURE_AGE 0x0040
+#define OSPF_LSA_IN_MAXAGE 0x0080
+#define OSPF_LSA_ORR 0x0100
/* LSA data. and size */
struct lsa_header *data;
@@ -222,6 +223,7 @@ enum lsid_status { LSID_AVAILABLE = 0, LSID_CHANGE, LSID_NOT_AVAILABLE };
#define IS_LSA_MAXAGE(L) (LS_AGE ((L)) == OSPF_LSA_MAXAGE)
#define IS_LSA_MAX_SEQ(L) \
((L)->data->ls_seqnum == htonl(OSPF_MAX_SEQUENCE_NUMBER))
+#define IS_LSA_ORR(L) (CHECK_FLAG ((L)->flags, OSPF_LSA_ORR))
#define OSPF_LSA_UPDATE_DELAY 2
@@ -292,6 +294,12 @@ extern struct ospf_lsa *ospf_lsa_lookup(struct ospf *ospf, struct ospf_area *,
struct in_addr);
extern struct ospf_lsa *ospf_lsa_lookup_by_id(struct ospf_area *, uint32_t,
struct in_addr);
+extern struct ospf_lsa *ospf_lsa_lookup_by_adv_rid(struct ospf_area *area,
+ uint32_t type,
+ struct in_addr id);
+extern struct ospf_lsa *ospf_lsa_lookup_by_mpls_te_rid(struct ospf_area *area,
+ uint32_t type,
+ struct in_addr id);
extern struct ospf_lsa *ospf_lsa_lookup_by_header(struct ospf_area *,
struct lsa_header *);
extern int ospf_lsa_more_recent(struct ospf_lsa *, struct ospf_lsa *);
diff --git a/ospfd/ospf_lsdb.c b/ospfd/ospf_lsdb.c
index f4fb858a5..3c65ac388 100644
--- a/ospfd/ospf_lsdb.c
+++ b/ospfd/ospf_lsdb.c
@@ -30,6 +30,7 @@
#include "ospfd/ospf_asbr.h"
#include "ospfd/ospf_lsa.h"
#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_orr.h"
struct ospf_lsdb *ospf_lsdb_new(void)
{
@@ -87,6 +88,10 @@ static void ospf_lsdb_delete_entry(struct ospf_lsdb *lsdb,
assert(rn->table == lsdb->type[lsa->data->type].db);
+ /* Update ORR Root table MPLS-TE Router address's advertise router */
+ if (lsa->data->type == OSPF_OPAQUE_AREA_LSA)
+ ospf_orr_root_table_update(lsa, false);
+
if (IS_LSA_SELF(lsa))
lsdb->type[lsa->data->type].count_self--;
lsdb->type[lsa->data->type].count--;
@@ -134,6 +139,10 @@ void ospf_lsdb_add(struct ospf_lsdb *lsdb, struct ospf_lsa *lsa)
#endif /* MONITOR_LSDB_CHANGE */
lsdb->type[lsa->data->type].checksum += ntohs(lsa->data->checksum);
rn->info = ospf_lsa_lock(lsa); /* lsdb */
+
+ /* Update ORR Root table MPLS-TE Router address's advertise router */
+ if (lsa->data->type == OSPF_OPAQUE_AREA_LSA)
+ ospf_orr_root_table_update(lsa, true);
}
void ospf_lsdb_delete(struct ospf_lsdb *lsdb, struct ospf_lsa *lsa)
diff --git a/ospfd/ospf_memory.c b/ospfd/ospf_memory.c
index 283844389..5577a291b 100644
--- a/ospfd/ospf_memory.c
+++ b/ospfd/ospf_memory.c
@@ -60,3 +60,4 @@ DEFINE_MTYPE(OSPFD, OSPF_GR_HELPER, "OSPF Graceful Restart Helper");
DEFINE_MTYPE(OSPFD, OSPF_EXTERNAL_RT_AGGR, "OSPF External Route Summarisation");
DEFINE_MTYPE(OSPFD, OSPF_P_SPACE, "OSPF TI-LFA P-Space");
DEFINE_MTYPE(OSPFD, OSPF_Q_SPACE, "OSPF TI-LFA Q-Space");
+DEFINE_MTYPE(OSPFD, OSPF_ORR_ROOT, "OSPF ORR Root");
diff --git a/ospfd/ospf_memory.h b/ospfd/ospf_memory.h
index 9bd0a844a..3d2133b11 100644
--- a/ospfd/ospf_memory.h
+++ b/ospfd/ospf_memory.h
@@ -59,5 +59,6 @@ DECLARE_MTYPE(OSPF_GR_HELPER);
DECLARE_MTYPE(OSPF_EXTERNAL_RT_AGGR);
DECLARE_MTYPE(OSPF_P_SPACE);
DECLARE_MTYPE(OSPF_Q_SPACE);
+DECLARE_MTYPE(OSPF_ORR_ROOT);
#endif /* _QUAGGA_OSPF_MEMORY_H */
diff --git a/ospfd/ospf_orr.c b/ospfd/ospf_orr.c
new file mode 100644
index 000000000..eed948b19
--- /dev/null
+++ b/ospfd/ospf_orr.c
@@ -0,0 +1,594 @@
+/*
+ * OSPF BGP-IGP IGP metric update handling routines
+ * Copyright (C) 2021 Samsung R&D Institute India - Bangalore.
+ * Madhurilatha Kuruganti
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+#include <string.h>
+
+#include "monotime.h"
+#include "memory.h"
+#include "thread.h"
+#include "prefix.h"
+#include "table.h"
+#include "vty.h"
+#include "command.h"
+#include "plist.h"
+#include "log.h"
+#include "zclient.h"
+#include <lib/json.h>
+#include "defaults.h"
+#include "orr_msg.h"
+
+#include "ospfd.h"
+#include "ospf_asbr.h"
+#include "ospf_dump.h"
+#include "ospf_lsa.h"
+#include "ospf_orr.h"
+#include "ospf_route.h"
+#include "ospf_spf.h"
+#include "ospf_te.h"
+
+static void ospf_show_orr_root(struct orr_root *root);
+static void ospf_show_orr(struct ospf *ospf, afi_t afi, safi_t safi);
+static struct orr_root *ospf_orr_root_new(struct ospf *ospf, afi_t afi,
+ safi_t safi, struct prefix *p,
+ char *group_name)
+{
+ struct list *orr_root_list = NULL;
+ struct orr_root *root = NULL;
+
+ if (!ospf->orr_root[afi][safi])
+ ospf->orr_root[afi][safi] = list_new();
+
+ orr_root_list = ospf->orr_root[afi][safi];
+ root = XCALLOC(MTYPE_OSPF_ORR_ROOT, sizeof(struct orr_root));
+
+ listnode_add(orr_root_list, root);
+
+ root->afi = afi;
+ root->safi = safi;
+ prefix_copy(&root->prefix, p);
+ IPV4_ADDR_COPY(&root->router_id, &p->u.prefix4);
+ strlcpy(root->group_name, group_name, sizeof(root->group_name));
+ root->new_rtrs = NULL;
+ root->new_table = NULL;
+
+ ospf_orr_debug(
+ "%s: For %s %s, ORR Group %s, created ORR Root entry %pFX.",
+ __func__, afi2str(afi), safi2str(safi), root->group_name, p);
+
+ return root;
+}
+
+static struct orr_root *ospf_orr_root_lookup(struct ospf *ospf, afi_t afi,
+ safi_t safi, struct in_addr *rid)
+{
+ struct list *orr_root_list = NULL;
+ struct orr_root *root = NULL;
+ struct listnode *node;
+
+ orr_root_list = ospf->orr_root[afi][safi];
+ if (!orr_root_list)
+ return NULL;
+
+ for (ALL_LIST_ELEMENTS_RO(orr_root_list, node, root))
+ if (IPV4_ADDR_SAME(&root->router_id, rid))
+ return root;
+
+ ospf_orr_debug("%s: For %s %s, ORR Root '%pI4' not found.", __func__,
+ afi2str(afi), safi2str(safi), rid);
+
+ return NULL;
+}
+
+static struct orr_root *ospf_orr_root_lookup_by_adv_rid(struct ospf *ospf,
+ afi_t afi, safi_t safi,
+ struct in_addr *rid)
+{
+ struct list *orr_root_list = NULL;
+ struct orr_root *root = NULL;
+ struct listnode *node;
+
+ orr_root_list = ospf->orr_root[afi][safi];
+ if (!orr_root_list)
+ return NULL;
+
+ for (ALL_LIST_ELEMENTS_RO(orr_root_list, node, root))
+ if (IPV4_ADDR_SAME(&root->adv_router, rid))
+ return root;
+
+ return NULL;
+}
+
+/*
+ * Lookup each area's LSDB if is there is any opaque area LSA received and
+ * update the root database with the advertising router.
+ */
+static struct ospf_lsa *
+ospf_orr_lookup_opaque_area_lsa_by_id(struct in_addr rid)
+{
+ struct ospf_lsa *lsa = NULL;
+ struct ospf_area *area = NULL;
+ struct ospf *ospf = NULL;
+ struct listnode *node = NULL, *nnode = NULL;
+
+ /* if ospf is not enabled ignore */
+ ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+ if (!ospf)
+ return NULL;
+
+ /* Lookup for Opaque area LSA in each area. */
+ for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) {
+ lsa = ospf_lsa_lookup_by_mpls_te_rid(area, OSPF_OPAQUE_AREA_LSA,
+ rid);
+ if (!lsa)
+ continue;
+ ospf_orr_debug(
+ "%s: Opaque Area LSA found in area %pI4 for %pI4",
+ __func__, &area->area_id, &rid);
+ return lsa;
+ }
+ return NULL;
+}
+
+/*
+ * Lookup each area's LSDB if is there is any opaque area LSA received and
+ * update the root database with the advertising router.
+ */
+static struct ospf_lsa *ospf_orr_lookup_router_lsa_by_id(struct in_addr rid)
+{
+ struct ospf_lsa *lsa = NULL;
+ struct ospf_area *area = NULL;
+ struct ospf *ospf = NULL;
+ struct listnode *node = NULL, *nnode = NULL;
+
+ /* if ospf is not enabled ignore */
+ ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+ if (!ospf)
+ return NULL;
+
+ /* Lookup for Router LSA in each area. */
+ for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) {
+ lsa = ospf_lsa_lookup_by_adv_rid(area, OSPF_ROUTER_LSA, rid);
+ if (!lsa)
+ continue;
+ ospf_orr_debug("%s: Router LSA found in area %pI4 for %pI4",
+ __func__, &area->area_id, &rid);
+ return lsa;
+ }
+ return NULL;
+}
+
+/*
+ * BGP-IGP IGP metric msg between BGP and IGP
+ */
+int ospf_orr_igp_metric_register(struct orr_igp_metric_reg msg)
+{
+ afi_t afi;
+ safi_t safi;
+ struct ospf *ospf = NULL;
+ struct ospf_lsa *lsa = NULL;
+ struct orr_root *root = NULL;
+
+ /* if ospf is not enabled ignore */
+ ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+ if (!ospf)
+ return -1;
+
+ if (msg.proto != ZEBRA_ROUTE_BGP)
+ return -1;
+
+ afi = family2afi(msg.prefix.family);
+ safi = msg.safi;
+
+ ospf_orr_debug(
+ "%s: Received IGP metric %s message from BGP for ORR Group %s from location %pFX",
+ __func__, msg.reg ? "Register" : "Unregister", msg.group_name,
+ &msg.prefix);
+
+ /* Get ORR Root entry for the given address-family */
+ root = ospf_orr_root_lookup(ospf, afi, safi, &msg.prefix.u.prefix4);
+
+ /* Should not hit this condition */
+ if ((root && msg.reg) || (!root && !msg.reg))
+ return -1;
+
+ /* Create ORR Root entry and calculate SPF from root */
+ if (!root) {
+ root = ospf_orr_root_new(ospf, afi, safi, &msg.prefix,
+ msg.group_name);
+ if (!root) {
+ ospf_orr_debug(
+ "%s: For %s %s, Failed to create ORR Root entry %pFX.",
+ __func__, afi2str(afi), safi2str(safi),
+ &msg.prefix);
+ return -1;
+ }
+ ospf->orr_spf_request++;
+
+ lsa = ospf_orr_lookup_opaque_area_lsa_by_id(root->router_id);
+ if (!lsa || !lsa->data)
+ return -1;
+
+ IPV4_ADDR_COPY(&root->adv_router, &lsa->data->adv_router);
+
+ /* Lookup LSDB for Router LSA */
+ if (!root->router_lsa_rcvd) {
+ lsa = ospf_orr_lookup_router_lsa_by_id(
+ root->adv_router);
+ if (!lsa || !lsa->data)
+ return -1;
+ root->router_lsa_rcvd = lsa;
+ }
+
+ /* Compute SPF for all root nodes */
+ ospf_orr_spf_calculate_schedule(ospf);
+ }
+ /* Delete ORR Root entry. SPF calculation not required. */
+ else {
+ listnode_delete(ospf->orr_root[afi][safi], root);
+ XFREE(MTYPE_OSPF_ORR_ROOT, root);
+
+ /* If last node is deleted in the list */
+ if (!ospf->orr_root[afi][safi]->count)
+ list_delete(&ospf->orr_root[afi][safi]);
+
+ ospf->orr_spf_request--;
+ }
+
+ if (IS_DEBUG_OSPF_ORR)
+ ospf_show_orr(ospf, afi, safi);
+
+ return 0;
+}
+
+void ospf_orr_igp_metric_send_update_add(struct orr_root *root,
+ unsigned short instance)
+{
+ int ret;
+ uint8_t count = 0;
+ struct route_node *rn;
+ struct ospf_route *or;
+ struct orr_igp_metric_info msg;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.proto = ZEBRA_ROUTE_OSPF;
+ msg.safi = root->safi;
+ msg.instId = instance;
+ msg.add = true;
+ prefix_copy(&msg.root, &root->prefix);
+
+ /* Update prefix table from ORR Route table */
+ for (rn = route_top(root->new_table); rn; rn = route_next(rn)) {
+ or = rn->info;
+ if (!or)
+ continue;
+
+ if (or->type != OSPF_DESTINATION_NETWORK &&
+ or->type != OSPF_DESTINATION_DISCARD)
+ continue;
+
+ if (ospf_route_match_same(root->old_table,
+ (struct prefix_ipv4 *)&rn->p, or))
+ continue;
+
+ if (count < ORR_MAX_PREFIX) {
+ prefix_copy(&msg.nexthop[count].prefix,
+ (struct prefix_ipv4 *)&rn->p);
+ msg.nexthop[count].metric = or->cost;
+ count++;
+ } else {
+ msg.num_entries = count;
+ ret = zclient_send_opaque(zclient,
+ ORR_IGP_METRIC_UPDATE,
+ (uint8_t *)&msg, sizeof(msg));
+ if (ret != ZCLIENT_SEND_SUCCESS)
+ ospf_orr_debug(
+ "%s: Failed to send message to BGP.",
+ __func__);
+ count = 0;
+ prefix_copy(&msg.nexthop[count].prefix,
+ (struct prefix_ipv4 *)&rn->p);
+ msg.nexthop[count].metric = or->cost;
+ count++;
+ }
+ }
+ if (count > 0 && count <= ORR_MAX_PREFIX) {
+ msg.num_entries = count;
+ ret = zclient_send_opaque(zclient, ORR_IGP_METRIC_UPDATE,
+ (uint8_t *)&msg, sizeof(msg));
+ if (ret != ZCLIENT_SEND_SUCCESS)
+ ospf_orr_debug("%s: Failed to send message to BGP.",
+ __func__);
+ }
+}
+
+void ospf_orr_igp_metric_send_update_delete(struct orr_root *root,
+ unsigned short instance)
+{
+ int ret;
+ uint8_t count = 0;
+ struct route_node *rn;
+ struct ospf_route *or;
+ struct orr_igp_metric_info msg;
+
+ if (!root->old_table)
+ return;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.proto = ZEBRA_ROUTE_OSPF;
+ msg.instId = instance;
+ msg.safi = root->safi;
+ msg.add = false;
+ prefix_copy(&msg.root, &root->prefix);
+
+ /* Update prefix table from ORR Route table */
+ for (rn = route_top(root->old_table); rn; rn = route_next(rn)) {
+ or = rn->info;
+ if (!or)
+ continue;
+
+ if (or->path_type != OSPF_PATH_INTRA_AREA &&
+ or->path_type != OSPF_PATH_INTER_AREA)
+ continue;
+
+ if (or->type != OSPF_DESTINATION_NETWORK &&
+ or->type != OSPF_DESTINATION_DISCARD)
+ continue;
+
+ if (ospf_route_exist_new_table(root->new_table,
+ (struct prefix_ipv4 *)&rn->p))
+ continue;
+
+ if (count < ORR_MAX_PREFIX) {
+ prefix_copy(&msg.nexthop[count].prefix,
+ (struct prefix_ipv4 *)&rn->p);
+ msg.nexthop[count].metric = or->cost;
+ count++;
+ } else {
+ msg.num_entries = count;
+ ret = zclient_send_opaque(zclient,
+ ORR_IGP_METRIC_UPDATE,
+ (uint8_t *)&msg, sizeof(msg));
+ if (ret != ZCLIENT_SEND_SUCCESS)
+ ospf_orr_debug(
+ "%s: Failed to send message to BGP.",
+ __func__);
+ count = 0;
+ prefix_copy(&msg.nexthop[count].prefix,
+ (struct prefix_ipv4 *)&rn->p);
+ msg.nexthop[count].metric = or->cost;
+ count++;
+ }
+ }
+ if (count > 0 && count <= ORR_MAX_PREFIX) {
+ msg.num_entries = count;
+ ret = zclient_send_opaque(zclient, ORR_IGP_METRIC_UPDATE,
+ (uint8_t *)&msg, sizeof(msg));
+ if (ret != ZCLIENT_SEND_SUCCESS)
+ ospf_orr_debug("%s: Failed to send message to BGP.",
+ __func__);
+ }
+}
+
+static void ospf_show_orr_root(struct orr_root *root)
+{
+ if (!root)
+ return;
+
+ ospf_orr_debug("%s: Address Family: %s %s", __func__,
+ afi2str(root->afi), safi2str(root->safi));
+ ospf_orr_debug("%s: ORR Group: %s", __func__, root->group_name);
+ ospf_orr_debug("%s: Router-Address: %pI4:", __func__, &root->router_id);
+ ospf_orr_debug("%s: Advertising Router: %pI4:", __func__,
+ &root->adv_router);
+}
+
+static void ospf_show_orr(struct ospf *ospf, afi_t afi, safi_t safi)
+{
+ struct listnode *node = NULL;
+ struct orr_root *orr_root = NULL;
+ struct list *orr_root_list = NULL;
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ orr_root_list = ospf->orr_root[afi][safi];
+ if (!orr_root_list)
+ return;
+
+ for (ALL_LIST_ELEMENTS_RO(orr_root_list, node, orr_root))
+ ospf_show_orr_root(orr_root);
+ }
+}
+
+void ospf_orr_root_table_update(struct ospf_lsa *lsa, bool add)
+{
+ afi_t afi;
+ safi_t safi;
+ struct lsa_header *lsah = lsa->data;
+ uint32_t lsid = ntohl(lsah->id.s_addr);
+ uint8_t opaque_type = GET_OPAQUE_TYPE(lsid);
+ uint32_t opaque_id = GET_OPAQUE_ID(lsid);
+ struct tlv_header *tlvh = TLV_HDR_TOP(lsah);
+ struct te_tlv_router_addr *router_addr = NULL;
+ struct orr_root *root = NULL;
+ struct ospf *ospf = NULL;
+
+ /* if ospf is not enabled ignore */
+ ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+ if (!ospf)
+ return;
+
+ if (opaque_type != OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA)
+ return;
+
+ if (!tlvh || (ntohs(tlvh->type) != TE_TLV_ROUTER_ADDR) ||
+ (ntohs(tlvh->length) != TE_LINK_SUBTLV_DEF_SIZE))
+ return;
+
+ router_addr = (struct te_tlv_router_addr *)tlvh;
+ if (IS_DEBUG_OSPF_ORR) {
+ zlog_debug("[OSPF-ORR] %s: Opaque-area LSA %s LSDB", __func__,
+ add ? "added to" : "deleted from");
+ zlog_debug("[OSPF-ORR] %s: Opaque-Type %u (%s)", __func__,
+ opaque_type, "Traffic Engineering LSA");
+ zlog_debug("[OSPF-ORR] %s: Opaque-ID 0x%x", __func__,
+ opaque_id);
+ zlog_debug("[OSPF-ORR] %s: Opaque-Info: %u octets of data%s",
+ __func__, ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE,
+ VALID_OPAQUE_INFO_LEN(lsah) ? ""
+ : "(Invalid length?)");
+ zlog_debug("[OSPF-ORR] %s: Router-Address: %pI4", __func__,
+ &router_addr->value);
+ zlog_debug("[OSPF-ORR] %s: Advertising Router: %pI4", __func__,
+ &lsa->data->adv_router);
+ }
+ /*
+ * When Opaque LSA is added or removed from LSDB check if there is any
+ * change in MPLS-TE Router address and Advertising router address and
+ * update the table accordingly if there is no change in the mapping
+ * ignore update
+ *
+ * Get ORR Root entry for the given address-family
+ */
+ FOREACH_AFI_SAFI (afi, safi) {
+ root = ospf_orr_root_lookup(ospf, afi, safi,
+ &router_addr->value);
+ if (root) {
+ IPV4_ADDR_COPY(&root->adv_router,
+ &lsa->data->adv_router);
+ if (IS_DEBUG_OSPF_ORR)
+ ospf_show_orr(ospf, afi, safi);
+ break;
+ }
+ }
+}
+
+void ospf_orr_root_update_rcvd_lsa(struct ospf_lsa *lsa)
+{
+ afi_t afi;
+ safi_t safi;
+ struct orr_root *root = NULL;
+
+ if (!lsa || !lsa->area || !lsa->area->ospf)
+ return;
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ root = ospf_orr_root_lookup_by_adv_rid(
+ lsa->area->ospf, afi, safi, &lsa->data->adv_router);
+ if (root) {
+ SET_FLAG(lsa->flags, OSPF_LSA_ORR);
+ ospf_refresher_register_lsa(lsa->area->ospf, lsa);
+ root->router_lsa_rcvd = lsa;
+ }
+
+ ospf_orr_debug("%s: Received LSA[Type%d:%pI4]", __func__,
+ lsa->data->type, &lsa->data->adv_router);
+
+ /* Compute SPF for all root nodes */
+ ospf_orr_spf_calculate_schedule(lsa->area->ospf);
+ return;
+ }
+}
+
+/* Do not Install routes to root table. Just update table ponters */
+void ospf_orr_route_install(struct orr_root *root, struct route_table *rt,
+ unsigned short instance)
+{
+ /*
+ * rt contains new routing table, new_table contains an old one.
+ * updating pointers
+ */
+ if (root->old_table)
+ ospf_route_table_free(root->old_table);
+
+ root->old_table = root->new_table;
+ root->new_table = rt;
+
+ /* Send update to BGP to delete old routes. */
+ ospf_orr_igp_metric_send_update_delete(root, instance);
+
+ /* REVISIT: Skipping external route table for now */
+
+ /* Send update to BGP to add new routes. */
+ ospf_orr_igp_metric_send_update_add(root, instance);
+}
+
+void ospf_orr_spf_calculate_schedule(struct ospf *ospf)
+{
+ /* OSPF instance does not exist. */
+ if (ospf == NULL)
+ return;
+
+ /* No roots nodes rgistered for rSPF */
+ if (!ospf->orr_spf_request)
+ return;
+
+ /* ORR SPF calculation timer is already scheduled. */
+ if (ospf->t_orr_calc) {
+ ospf_orr_debug(
+ "SPF: calculation timer is already scheduled: %p",
+ (void *)ospf->t_orr_calc);
+ return;
+ }
+
+ ospf->t_orr_calc = NULL;
+
+ ospf_orr_debug("%s: SPF: calculation timer scheduled", __func__);
+
+ thread_add_timer(master, ospf_orr_spf_calculate_schedule_worker, ospf,
+ OSPF_ORR_CALC_INTERVAL, &ospf->t_orr_calc);
+}
+
+void ospf_orr_spf_calculate_area(struct ospf *ospf, struct ospf_area *area,
+ struct route_table *new_table,
+ struct route_table *all_rtrs,
+ struct route_table *new_rtrs,
+ struct ospf_lsa *lsa_rcvd)
+{
+ ospf_spf_calculate(area, lsa_rcvd, new_table, all_rtrs, new_rtrs, false,
+ true);
+}
+
+void ospf_orr_spf_calculate_areas(struct ospf *ospf,
+ struct route_table *new_table,
+ struct route_table *all_rtrs,
+ struct route_table *new_rtrs,
+ struct ospf_lsa *lsa_rcvd)
+{
+ struct ospf_area *area;
+ struct listnode *node, *nnode;
+
+ /* Calculate SPF for each area. */
+ for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) {
+ /*
+ * Do backbone last, so as to first discover intra-area paths
+ * for any back-bone virtual-links
+ */
+ if (ospf->backbone && ospf->backbone == area)
+ continue;
+
+ ospf_orr_spf_calculate_area(ospf, area, new_table, all_rtrs,
+ new_rtrs, lsa_rcvd);
+ }
+
+ /* SPF for backbone, if required */
+ if (ospf->backbone)
+ ospf_orr_spf_calculate_area(ospf, ospf->backbone, new_table,
+ all_rtrs, new_rtrs, lsa_rcvd);
+}
diff --git a/ospfd/ospf_orr.h b/ospfd/ospf_orr.h
new file mode 100644
index 000000000..d0a6f6e79
--- /dev/null
+++ b/ospfd/ospf_orr.h
@@ -0,0 +1,58 @@
+/*
+ * OSPF BGP-IGP IGP metric update handling routines
+ * Copyright (C) 2021 Samsung R&D Institute India - Bangalore.
+ * Madhurilatha Kuruganti
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _ZEBRA_OSPF_ORR_H
+#define _ZEBRA_OSPF_ORR_H
+
+#define BGP_OSPF_LSINFINITY 65535
+#define OSPF_ORR_CALC_INTERVAL 1
+
+/* Macro to log debug message */
+#define ospf_orr_debug(...) \
+ do { \
+ if (IS_DEBUG_OSPF_ORR) \
+ zlog_debug("[OSPF-ORR] "__VA_ARGS__); \
+ } while (0)
+
+extern struct zclient *zclient;
+
+extern int ospf_orr_igp_metric_register(struct orr_igp_metric_reg orr_reg);
+extern void ospf_orr_igp_metric_send_update_add(struct orr_root *root,
+ unsigned short instance);
+extern void ospf_orr_igp_metric_send_update_delete(struct orr_root *root,
+ unsigned short instance);
+extern void ospf_orr_root_table_update(struct ospf_lsa *lsa, bool add);
+extern void ospf_orr_root_update_rcvd_lsa(struct ospf_lsa *lsa);
+extern void ospf_orr_route_install(struct orr_root *root,
+ struct route_table *rt,
+ unsigned short instance);
+extern void ospf_orr_spf_calculate_schedule(struct ospf *ospf);
+extern void ospf_orr_spf_calculate_area(struct ospf *ospf,
+ struct ospf_area *area,
+ struct route_table *new_table,
+ struct route_table *all_rtrs,
+ struct route_table *new_rtrs,
+ struct ospf_lsa *lsa_rcvd);
+extern void ospf_orr_spf_calculate_areas(struct ospf *ospf,
+ struct route_table *new_table,
+ struct route_table *all_rtrs,
+ struct route_table *new_rtrs,
+ struct ospf_lsa *lsa_rcvd);
+#endif /* _ZEBRA_OSPF_ORR_H */
diff --git a/ospfd/ospf_route.c b/ospfd/ospf_route.c
index 6360d8ec6..26f593f08 100644
--- a/ospfd/ospf_route.c
+++ b/ospfd/ospf_route.c
@@ -151,8 +151,8 @@ void ospf_route_table_free(struct route_table *rt)
otherwise return 0. Since the ZEBRA-RIB does an implicit
withdraw, it is not necessary to send a delete, an add later
will act like an implicit delete. */
-static int ospf_route_exist_new_table(struct route_table *rt,
- struct prefix_ipv4 *prefix)
+int ospf_route_exist_new_table(struct route_table *rt,
+ struct prefix_ipv4 *prefix)
{
struct route_node *rn;
diff --git a/ospfd/ospf_route.h b/ospfd/ospf_route.h
index fa9478fce..e7e2b651c 100644
--- a/ospfd/ospf_route.h
+++ b/ospfd/ospf_route.h
@@ -172,5 +172,6 @@ extern void ospf_delete_discard_route(struct ospf *, struct route_table *,
struct prefix_ipv4 *);
extern int ospf_route_match_same(struct route_table *, struct prefix_ipv4 *,
struct ospf_route *);
-
+extern int ospf_route_exist_new_table(struct route_table *rt,
+ struct prefix_ipv4 *prefix);
#endif /* _ZEBRA_OSPF_ROUTE_H */
diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c
index 4edc1de81..74213d7de 100644
--- a/ospfd/ospf_spf.c
+++ b/ospfd/ospf_spf.c
@@ -53,6 +53,8 @@
#include "ospfd/ospf_apiserver.h"
#endif
+#include "ospfd/ospf_orr.h"
+
/* Variables to ensure a SPF scheduled log message is printed only once */
static unsigned int spf_reason_flags = 0;
@@ -1824,6 +1826,36 @@ void ospf_spf_calculate_areas(struct ospf *ospf, struct route_table *new_table,
all_rtrs, new_rtrs);
}
+/* Print Reason for SPF calculation */
+static void ospf_spf_calculation_reason2str(char *rbuf)
+{
+ rbuf[0] = '\0';
+ if (spf_reason_flags) {
+ if (spf_reason_flags & (1 << SPF_FLAG_ROUTER_LSA_INSTALL))
+ strlcat(rbuf, "R, ", sizeof(rbuf));
+ if (spf_reason_flags & (1 << SPF_FLAG_NETWORK_LSA_INSTALL))
+ strlcat(rbuf, "N, ", sizeof(rbuf));
+ if (spf_reason_flags & (1 << SPF_FLAG_SUMMARY_LSA_INSTALL))
+ strlcat(rbuf, "S, ", sizeof(rbuf));
+ if (spf_reason_flags & (1 << SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL))
+ strlcat(rbuf, "AS, ", sizeof(rbuf));
+ if (spf_reason_flags & (1 << SPF_FLAG_ABR_STATUS_CHANGE))
+ strlcat(rbuf, "ABR, ", sizeof(rbuf));
+ if (spf_reason_flags & (1 << SPF_FLAG_ASBR_STATUS_CHANGE))
+ strlcat(rbuf, "ASBR, ", sizeof(rbuf));
+ if (spf_reason_flags & (1 << SPF_FLAG_MAXAGE))
+ strlcat(rbuf, "M, ", sizeof(rbuf));
+ if (spf_reason_flags & (1 << SPF_FLAG_ORR_ROOT_CHANGE))
+ strlcat(rbuf, "ORR, ", sizeof(rbuf));
+
+ size_t rbuflen = strlen(rbuf);
+ if (rbuflen >= 2)
+ rbuf[rbuflen - 2] = '\0'; /* skip the last ", " */
+ else
+ rbuf[0] = '\0';
+ }
+}
+
/* Worker for SPF calculation scheduler. */
static void ospf_spf_calculate_schedule_worker(struct thread *thread)
{
@@ -1879,6 +1911,8 @@ static void ospf_spf_calculate_schedule_worker(struct thread *thread)
ospf_ase_calculate_schedule(ospf);
ospf_ase_calculate_timer_add(ospf);
+ ospf_orr_spf_calculate_schedule(ospf);
+
if (IS_DEBUG_OSPF_EVENT)
zlog_debug(
"%s: ospf install new route, vrf %s id %u new_table count %lu",
@@ -1901,7 +1935,6 @@ static void ospf_spf_calculate_schedule_worker(struct thread *thread)
#ifdef SUPPORT_OSPF_API
ospf_apiserver_notify_reachable(ospf->oall_rtrs, ospf->all_rtrs);
#endif
-
/* Free old ABR/ASBR routing table */
if (ospf->old_rtrs)
/* ospf_route_delete (ospf->old_rtrs); */
@@ -1926,31 +1959,7 @@ static void ospf_spf_calculate_schedule_worker(struct thread *thread)
total_spf_time =
monotime_since(&spf_start_time, &ospf->ts_spf_duration);
- rbuf[0] = '\0';
- if (spf_reason_flags) {
- if (spf_reason_flags & (1 << SPF_FLAG_ROUTER_LSA_INSTALL))
- strlcat(rbuf, "R, ", sizeof(rbuf));
- if (spf_reason_flags & (1 << SPF_FLAG_NETWORK_LSA_INSTALL))
- strlcat(rbuf, "N, ", sizeof(rbuf));
- if (spf_reason_flags & (1 << SPF_FLAG_SUMMARY_LSA_INSTALL))
- strlcat(rbuf, "S, ", sizeof(rbuf));
- if (spf_reason_flags & (1 << SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL))
- strlcat(rbuf, "AS, ", sizeof(rbuf));
- if (spf_reason_flags & (1 << SPF_FLAG_ABR_STATUS_CHANGE))
- strlcat(rbuf, "ABR, ", sizeof(rbuf));
- if (spf_reason_flags & (1 << SPF_FLAG_ASBR_STATUS_CHANGE))
- strlcat(rbuf, "ASBR, ", sizeof(rbuf));
- if (spf_reason_flags & (1 << SPF_FLAG_MAXAGE))
- strlcat(rbuf, "M, ", sizeof(rbuf));
- if (spf_reason_flags & (1 << SPF_FLAG_GR_FINISH))
- strlcat(rbuf, "GR, ", sizeof(rbuf));
-
- size_t rbuflen = strlen(rbuf);
- if (rbuflen >= 2)
- rbuf[rbuflen - 2] = '\0'; /* skip the last ", " */
- else
- rbuf[0] = '\0';
- }
+ ospf_spf_calculation_reason2str(rbuf);
if (IS_DEBUG_OSPF_EVENT) {
zlog_info("SPF Processing Time(usecs): %ld", total_spf_time);
@@ -1967,6 +1976,145 @@ static void ospf_spf_calculate_schedule_worker(struct thread *thread)
ospf_clear_spf_reason_flags();
}
+/* Worker for ORR SPF calculation scheduler. */
+void ospf_orr_spf_calculate_schedule_worker(struct thread *thread)
+{
+ afi_t afi;
+ safi_t safi;
+ struct ospf *ospf = THREAD_ARG(thread);
+ struct route_table *new_table, *new_rtrs;
+ struct route_table *all_rtrs = NULL;
+ struct timeval start_time, spf_start_time;
+ unsigned long ia_time, rt_time;
+ unsigned long abr_time, total_spf_time, spf_time;
+ struct listnode *rnode;
+ struct list *orr_root_list;
+ struct orr_root *root;
+ char rbuf[32]; /* reason_buf */
+
+ ospf_orr_debug("%s: SPF: Timer (SPF calculation expire)", __func__);
+
+ ospf->t_orr_calc = NULL;
+
+ /* Execute SPF for each ORR Root node */
+ FOREACH_AFI_SAFI (afi, safi) {
+ orr_root_list = ospf->orr_root[afi][safi];
+ if (!orr_root_list)
+ continue;
+ for (ALL_LIST_ELEMENTS_RO(orr_root_list, rnode, root)) {
+ if (!root || !root->router_lsa_rcvd)
+ continue;
+ ospf_orr_debug(
+ "%s: For %s %s, MPLS TE Router address %pI4 advertised by %pI4",
+ __func__, afi2str(afi), safi2str(safi),
+ &root->router_id, &root->adv_router);
+
+ ospf_vl_unapprove(ospf);
+
+ /*
+ * Execute SPF for each area including backbone, see RFC
+ * 2328 16.1.
+ */
+ monotime(&spf_start_time);
+ new_table = route_table_init(); /* routing table */
+ new_rtrs =
+ route_table_init(); /* ABR/ASBR routing table */
+
+ /*
+ * If we have opaque enabled then track all router
+ * reachability
+ */
+ if (CHECK_FLAG(ospf->opaque,
+ OPAQUE_OPERATION_READY_BIT))
+ all_rtrs = route_table_init();
+ ospf_orr_spf_calculate_areas(ospf, new_table, all_rtrs,
+ new_rtrs,
+ root->router_lsa_rcvd);
+
+ spf_time = monotime_since(&spf_start_time, NULL);
+
+ ospf_vl_shut_unapproved(ospf);
+
+ /* Calculate inter-area routes, see RFC 2328 16.2. */
+ monotime(&start_time);
+ ospf_ia_routing(ospf, new_table, new_rtrs);
+ ia_time = monotime_since(&start_time, NULL);
+
+ /*
+ * REVISIT :
+ * Pruning of unreachable networks, routers skipped.
+ */
+
+ /* Note: RFC 2328 16.3. is apparently missing. */
+ /* Calculate AS external routes, see RFC 2328 16.4.
+ * There is a dedicated routing table for external
+ * routes which is not handled here directly
+ */
+ ospf_ase_calculate_schedule(ospf);
+ ospf_ase_calculate_timer_add(ospf);
+
+ ospf_orr_debug(
+ "%s: ospf install new route, vrf %s id %u new_table count %lu",
+ __func__, ospf_vrf_id_to_name(ospf->vrf_id),
+ ospf->vrf_id, new_table->count);
+
+ /* Update routing table. */
+ monotime(&start_time);
+ ospf_orr_route_install(root, new_table, ospf->instance);
+ rt_time = monotime_since(&start_time, NULL);
+
+ /*
+ * REVISIT :
+ * Freeing up and Updating old all routers routing table
+ * skipped.
+ */
+
+ /* Free old ABR/ASBR routing table */
+ if (root->old_rtrs)
+ /* ospf_route_delete (ospf->old_rtrs); */
+ ospf_rtrs_free(root->old_rtrs);
+
+ /* Update ABR/ASBR routing table */
+ root->old_rtrs = root->new_rtrs;
+ root->new_rtrs = new_rtrs;
+
+ /*
+ * ABRs may require additional changes, see RFC
+ * 2328 16.7.
+ */
+ monotime(&start_time);
+ if (IS_OSPF_ABR(ospf)) {
+ if (ospf->anyNSSA)
+ ospf_abr_nssa_check_status(ospf);
+ ospf_abr_task(ospf);
+ }
+ abr_time = monotime_since(&start_time, NULL);
+
+ /* Schedule Segment Routing update */
+ ospf_sr_update_task(ospf);
+
+ total_spf_time = monotime_since(&spf_start_time,
+ &ospf->ts_spf_duration);
+
+ ospf_spf_calculation_reason2str(rbuf);
+
+ if (IS_DEBUG_OSPF_ORR) {
+ zlog_info("SPF Processing Time(usecs): %ld",
+ total_spf_time);
+ zlog_info(" SPF Time: %ld",
+ spf_time);
+ zlog_info(" InterArea: %ld", ia_time);
+ zlog_info(" RouteInstall: %ld", rt_time);
+ if (IS_OSPF_ABR(ospf))
+ zlog_info(
+ " ABR: %ld (%d areas)",
+ abr_time, ospf->areas->count);
+ zlog_info("Reason(s) for SPF: %s", rbuf);
+ }
+ } /* ALL_LIST_ELEMENTS_RO() */
+ } /* FOREACH_AFI_SAFI() */
+}
+
/*
* Add schedule for SPF calculation. To avoid frequenst SPF calc, we set timer
* for SPF calc.
@@ -2025,6 +2173,7 @@ void ospf_spf_calculate_schedule(struct ospf *ospf, ospf_spf_reason_t reason)
zlog_debug("SPF: calculation timer delay = %ld msec", delay);
ospf->t_spf_calc = NULL;
+
thread_add_timer_msec(master, ospf_spf_calculate_schedule_worker, ospf,
delay, &ospf->t_spf_calc);
}
diff --git a/ospfd/ospf_spf.h b/ospfd/ospf_spf.h
index 834bfd0bb..2578051c2 100644
--- a/ospfd/ospf_spf.h
+++ b/ospfd/ospf_spf.h
@@ -70,8 +70,10 @@ typedef enum {
SPF_FLAG_ASBR_STATUS_CHANGE,
SPF_FLAG_CONFIG_CHANGE,
SPF_FLAG_GR_FINISH,
+ SPF_FLAG_ORR_ROOT_CHANGE,
} ospf_spf_reason_t;
+extern unsigned int ospf_get_spf_reason_flags(void);
extern void ospf_spf_calculate_schedule(struct ospf *, ospf_spf_reason_t);
extern void ospf_spf_calculate(struct ospf_area *area,
struct ospf_lsa *root_lsa,
@@ -103,5 +105,6 @@ extern int vertex_parent_cmp(void *aa, void *bb);
extern void ospf_spf_print(struct vty *vty, struct vertex *v, int i);
extern void ospf_restart_spf(struct ospf *ospf);
+extern void ospf_orr_spf_calculate_schedule_worker(struct thread *thread);
/* void ospf_spf_calculate_timer_add (); */
#endif /* _QUAGGA_OSPF_SPF_H */
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index c957c8c01..4f0fa6194 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -55,6 +55,7 @@
#include "ospfd/ospf_dump.h"
#include "ospfd/ospf_bfd.h"
#include "ospfd/ospf_ldp_sync.h"
+#include "ospfd/ospf_orr.h"
FRR_CFG_DEFAULT_BOOL(OSPF_LOG_ADJACENCY_CHANGES,
@@ -10982,6 +10983,131 @@ static void show_ip_ospf_route_external(struct vty *vty, struct ospf *ospf,
vty_out(vty, "\n");
}
+static void show_ip_ospf_route_orr_root(struct vty *vty, struct ospf *ospf,
+ struct orr_root *root, bool use_vrf)
+{
+ if (ospf->instance)
+ vty_out(vty, "\nOSPF Instance: %d\n", ospf->instance);
+
+ ospf_show_vrf_name(ospf, vty, NULL, use_vrf);
+
+ vty_out(vty, "ORR Group: %s\n", root->group_name);
+ vty_out(vty, "Active Root: %pI4\n\n", &root->router_id);
+ vty_out(vty, "SPF calculated from %pI4\n\n", &root->router_id);
+
+ if (root->new_table)
+ show_ip_ospf_route_network(vty, ospf, root->new_table, NULL);
+
+ if (root->new_rtrs)
+ show_ip_ospf_route_router(vty, ospf, root->new_rtrs, NULL);
+
+ vty_out(vty, "\n");
+}
+
+static void show_ip_ospf_route_orr_common(struct vty *vty, struct ospf *ospf,
+ const char *orr_group, bool use_vrf)
+{
+ afi_t afi;
+ safi_t safi;
+ struct orr_root *root = NULL;
+ struct listnode *node = NULL;
+ struct list *orr_root_list = NULL;
+
+ if (!ospf->orr_spf_request)
+ return;
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ orr_root_list = ospf->orr_root[afi][safi];
+ if (!orr_root_list)
+ continue;
+ for (ALL_LIST_ELEMENTS_RO(orr_root_list, node, root)) {
+ if (orr_group) {
+ if (!strmatch(root->group_name, orr_group))
+ continue;
+ show_ip_ospf_route_orr_root(vty, ospf, root,
+ use_vrf);
+ } else
+ show_ip_ospf_route_orr_root(vty, ospf, root,
+ use_vrf);
+ }
+ }
+}
+
+DEFPY (show_ip_ospf_instance_route_orr,
+ show_ip_ospf_instance_route_orr_cmd,
+ "show ip ospf (1-65535)$instance route orr [WORD$orr_group]",
+ SHOW_STR
+ IP_STR
+ OSPF_STR
+ "Instance ID\n"
+ "OSPF routing table\n"
+ "Optimal Route Reflection\n"
+ "ORR Group name\n")
+{
+ struct ospf *ospf;
+
+ if (instance != ospf_instance)
+ return CMD_NOT_MY_INSTANCE;
+
+ ospf = ospf_lookup_instance(instance);
+ if (!ospf || !ospf->oi_running)
+ return CMD_SUCCESS;
+
+ show_ip_ospf_route_orr_common(vty, ospf, orr_group, false);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (show_ip_ospf_route_orr,
+ show_ip_ospf_route_orr_cmd,
+ "show ip ospf [vrf <NAME$vrf_name|all$all_vrf>] route orr [WORD$orr_group]",
+ SHOW_STR
+ IP_STR
+ OSPF_STR
+ VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "OSPF routing table\n"
+ "Optimal Route Reflection\n"
+ "ORR Group name\n")
+{
+ struct ospf *ospf = NULL;
+ struct listnode *node = NULL;
+ int ret = CMD_SUCCESS;
+ int inst = 0;
+ bool use_vrf = vrf_name || all_vrf;
+
+ if (all_vrf) {
+ bool ospf_output = false;
+
+ for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) {
+ if (!ospf->oi_running)
+ continue;
+ ospf_output = true;
+
+ show_ip_ospf_route_orr_common(vty, ospf, orr_group,
+ use_vrf);
+ }
+ if (!ospf_output)
+ vty_out(vty, "%% OSPF is not enabled\n");
+ return ret;
+ }
+
+ if (vrf_name)
+ ospf = ospf_lookup_by_inst_name(inst, vrf_name);
+ else
+ ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+
+ if (!ospf || !ospf->oi_running) {
+ vty_out(vty, "%% OSPF is not enabled in vrf %s\n",
+ vrf_name ? vrf_name : "default");
+ return CMD_SUCCESS;
+ }
+
+ show_ip_ospf_route_orr_common(vty, ospf, orr_group, use_vrf);
+
+ return ret;
+}
+
static int show_ip_ospf_reachable_routers_common(struct vty *vty,
struct ospf *ospf,
uint8_t use_vrf)
@@ -12694,11 +12820,13 @@ void ospf_vty_show_init(void)
install_element(VIEW_NODE, &show_ip_ospf_route_cmd);
install_element(VIEW_NODE, &show_ip_ospf_border_routers_cmd);
install_element(VIEW_NODE, &show_ip_ospf_reachable_routers_cmd);
+ install_element(VIEW_NODE, &show_ip_ospf_route_orr_cmd);
install_element(VIEW_NODE, &show_ip_ospf_instance_route_cmd);
install_element(VIEW_NODE, &show_ip_ospf_instance_border_routers_cmd);
install_element(VIEW_NODE,
&show_ip_ospf_instance_reachable_routers_cmd);
+ install_element(VIEW_NODE, &show_ip_ospf_instance_route_orr_cmd);
/* "show ip ospf vrfs" commands. */
install_element(VIEW_NODE, &show_ip_ospf_vrfs_cmd);
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
index 1754512b5..461586424 100644
--- a/ospfd/ospf_zebra.c
+++ b/ospfd/ospf_zebra.c
@@ -53,6 +53,7 @@
#include "ospfd/ospf_te.h"
#include "ospfd/ospf_sr.h"
#include "ospfd/ospf_ldp_sync.h"
+#include "ospfd/ospf_orr.h"
DEFINE_MTYPE_STATIC(OSPFD, OSPF_EXTERNAL, "OSPF External route table");
DEFINE_MTYPE_STATIC(OSPFD, OSPF_REDISTRIBUTE, "OSPF Redistriute");
@@ -2081,6 +2082,7 @@ static void ospf_zebra_connected(struct zclient *zclient)
bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT);
zclient_send_reg_requests(zclient, VRF_DEFAULT);
+ zclient_register_opaque(zclient, ORR_IGP_METRIC_REGISTER);
}
/*
@@ -2093,6 +2095,7 @@ static int ospf_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
struct ldp_igp_sync_if_state state;
struct ldp_igp_sync_announce announce;
struct zapi_opaque_reg_info dst;
+ struct orr_igp_metric_reg orr_reg;
int ret = 0;
s = zclient->ibuf;
@@ -2116,6 +2119,10 @@ static int ospf_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
STREAM_GET(&announce, s, sizeof(announce));
ret = ospf_ldp_sync_announce_update(announce);
break;
+ case ORR_IGP_METRIC_REGISTER:
+ STREAM_GET(&orr_reg, s, sizeof(orr_reg));
+ ret = ospf_orr_igp_metric_register(orr_reg);
+ break;
default:
break;
}
diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c
index e0c36d86f..3f82d8692 100644
--- a/ospfd/ospfd.c
+++ b/ospfd/ospfd.c
@@ -795,6 +795,7 @@ static void ospf_finish_final(struct ospf *ospf)
THREAD_OFF(ospf->t_write);
THREAD_OFF(ospf->t_spf_calc);
THREAD_OFF(ospf->t_ase_calc);
+ THREAD_OFF(ospf->t_orr_calc);
THREAD_OFF(ospf->t_maxage);
THREAD_OFF(ospf->t_maxage_walker);
THREAD_OFF(ospf->t_abr_task);
diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h
index 3a43010f8..c7735136b 100644
--- a/ospfd/ospfd.h
+++ b/ospfd/ospfd.h
@@ -35,6 +35,8 @@
#include "ospf_memory.h"
#include "ospf_dump_api.h"
+#include "orr_msg.h"
+
#define OSPF_VERSION 2
/* VTY port number. */
@@ -261,6 +263,7 @@ struct ospf {
struct thread *t_distribute_update; /* Distirbute list update timer. */
struct thread *t_spf_calc; /* SPF calculation timer. */
struct thread *t_ase_calc; /* ASE calculation timer. */
+ struct thread *t_orr_calc; /* ORR calculation timer. */
struct thread
*t_opaque_lsa_self; /* Type-11 Opaque-LSAs origin event. */
struct thread *t_sr_update; /* Segment Routing update timer */
@@ -406,6 +409,10 @@ struct ospf {
bool ti_lfa_enabled;
enum protection_type ti_lfa_protection_type;
+ /* BGP ORR Root node list */
+ uint32_t orr_spf_request;
+ struct list *orr_root[AFI_MAX][SAFI_MAX];
+
QOBJ_FIELDS;
};
DECLARE_QOBJ_TYPE(ospf);
@@ -591,6 +598,9 @@ struct ospf_area {
uint32_t act_ints; /* Active interfaces. */
uint32_t full_nbrs; /* Fully adjacent neighbors. */
uint32_t full_vls; /* Fully adjacent virtual neighbors. */
+
+ /* BGP-ORR Received LSAs */
+ struct ospf_lsa *router_lsa_rcvd;
};
/* OSPF config network structure. */
diff --git a/ospfd/subdir.am b/ospfd/subdir.am
index 4f9cbc7b1..78688fac9 100644
--- a/ospfd/subdir.am
+++ b/ospfd/subdir.am
@@ -48,6 +48,7 @@ ospfd_libfrrospf_a_SOURCES = \
ospfd/ospf_network.c \
ospfd/ospf_nsm.c \
ospfd/ospf_opaque.c \
+ ospfd/ospf_orr.c \
ospfd/ospf_packet.c \
ospfd/ospf_ri.c \
ospfd/ospf_route.c \
@@ -101,6 +102,7 @@ noinst_HEADERS += \
ospfd/ospf_memory.h \
ospfd/ospf_neighbor.h \
ospfd/ospf_network.h \
+ ospfd/ospf_orr.h \
ospfd/ospf_packet.h \
ospfd/ospf_ri.h \
ospfd/ospf_gr.h \
diff --git a/pathd/path_cli.c b/pathd/path_cli.c
index 4775aa36f..13e52ac86 100644
--- a/pathd/path_cli.c
+++ b/pathd/path_cli.c
@@ -1092,6 +1092,8 @@ DEFPY_NOSH(show_debugging_pathd, show_debugging_pathd_cmd,
"State of each debugging option\n"
"pathd module debugging\n")
{
+
+ cmd_show_lib_debugs(vty);
/* nothing to do here */
return CMD_SUCCESS;
}
diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c
index a2b3431b9..6f53adb33 100644
--- a/pbrd/pbr_vty.c
+++ b/pbrd/pbr_vty.c
@@ -1243,6 +1243,8 @@ DEFUN_NOSH(show_debugging_pbr,
pbr_debug_config_write_helper(vty, false);
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
diff --git a/pimd/pim6_cmd.c b/pimd/pim6_cmd.c
index 49248798b..f6b370cee 100644
--- a/pimd/pim6_cmd.c
+++ b/pimd/pim6_cmd.c
@@ -1558,6 +1558,8 @@ DEFUN_NOSH (show_debugging_pimv6,
pim_debug_config_write(vty);
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index f3830eaf1..ab0689a15 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -963,7 +963,7 @@ static void pim_show_bsm_db(struct pim_instance *pim, struct vty *vty, bool uj)
bsm_rpinfo = (struct bsmmsg_rpinfo *)buf;
/* unaligned, again */
- memcpy(&rp_addr, &bsm_rpinfo->rpaddr,
+ memcpy(&rp_addr, &bsm_rpinfo->rpaddr.addr,
sizeof(rp_addr));
buf += sizeof(struct bsmmsg_rpinfo);
@@ -4906,6 +4906,7 @@ DEFUN_NOSH (show_debugging_pim,
pim_debug_config_write(vty);
+ cmd_show_lib_debugs(vty);
return CMD_SUCCESS;
}
diff --git a/ripd/rip_debug.c b/ripd/rip_debug.c
index 871ee8e87..ded62812a 100644
--- a/ripd/rip_debug.c
+++ b/ripd/rip_debug.c
@@ -55,6 +55,8 @@ DEFUN_NOSH (show_debugging_rip,
if (IS_RIP_DEBUG_ZEBRA)
vty_out(vty, " RIP zebra debugging is on\n");
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
diff --git a/ripd/ripd.c b/ripd/ripd.c
index 8a321d9a9..8e02f1a6c 100644
--- a/ripd/ripd.c
+++ b/ripd/ripd.c
@@ -3551,10 +3551,18 @@ static int rip_vrf_new(struct vrf *vrf)
static int rip_vrf_delete(struct vrf *vrf)
{
+ struct rip *rip;
+
if (IS_RIP_DEBUG_EVENT)
zlog_debug("%s: VRF deleted: %s(%u)", __func__, vrf->name,
vrf->vrf_id);
+ rip = rip_lookup_by_vrf_name(vrf->name);
+ if (!rip)
+ return 0;
+
+ rip_clean(rip);
+
return 0;
}
diff --git a/ripngd/ripng_debug.c b/ripngd/ripng_debug.c
index 539c01b3e..d36327cb7 100644
--- a/ripngd/ripng_debug.c
+++ b/ripngd/ripng_debug.c
@@ -56,6 +56,8 @@ DEFUN_NOSH (show_debugging_ripng,
if (IS_RIPNG_DEBUG_ZEBRA)
vty_out(vty, " RIPng zebra debugging is on\n");
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c
index 1e7a13d7d..755debd0a 100644
--- a/ripngd/ripngd.c
+++ b/ripngd/ripngd.c
@@ -2581,10 +2581,17 @@ static int ripng_vrf_new(struct vrf *vrf)
static int ripng_vrf_delete(struct vrf *vrf)
{
+ struct ripng *ripng;
+
if (IS_RIPNG_DEBUG_EVENT)
zlog_debug("%s: VRF deleted: %s(%u)", __func__, vrf->name,
vrf->vrf_id);
+ ripng = ripng_lookup_by_vrf_name(vrf->name);
+ if (!ripng)
+ return 0;
+
+ ripng_clean(ripng);
return 0;
}
diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c
index 3853df7cb..9b900fccd 100644
--- a/sharpd/sharp_vty.c
+++ b/sharpd/sharp_vty.c
@@ -615,6 +615,8 @@ DEFUN_NOSH (show_debugging_sharpd,
{
vty_out(vty, "Sharp debugging status:\n");
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
diff --git a/snapcraft/snapcraft.yaml.in b/snapcraft/snapcraft.yaml.in
index 9729be7b9..f634b59c7 100644
--- a/snapcraft/snapcraft.yaml.in
+++ b/snapcraft/snapcraft.yaml.in
@@ -272,7 +272,7 @@ parts:
- zlib1g
prime:
- lib/librtr.so*
- - usr/lib/x86_64-linux-gnu/libssh.so*
+ - usr/lib/$SNAPCRAFT_ARCH_TRIPLET/libssh.so*
source: https://github.com/rtrlib/rtrlib.git
source-type: git
source-tag: v0.8.0
diff --git a/staticd/static_main.c b/staticd/static_main.c
index 7badd5004..79686158c 100644
--- a/staticd/static_main.c
+++ b/staticd/static_main.c
@@ -79,6 +79,7 @@ static void sigint(void)
static_vrf_terminate();
+ static_zebra_stop();
frr_fini();
exit(0);
diff --git a/staticd/static_vty.c b/staticd/static_vty.c
index c0ace0e25..c0638f4bc 100644
--- a/staticd/static_vty.c
+++ b/staticd/static_vty.c
@@ -1301,6 +1301,8 @@ DEFUN_NOSH (show_debugging_static,
static_debug_status_write(vty);
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
diff --git a/tests/lib/test_typelist.h b/tests/lib/test_typelist.h
index e3579c67a..feb42909a 100644
--- a/tests/lib/test_typelist.h
+++ b/tests/lib/test_typelist.h
@@ -74,7 +74,7 @@ static uint32_t list_hash(const struct item *a)
{
#ifdef SHITTY_HASH
/* crappy hash to get some hash collisions */
- return a->val ^ (a->val << 29) ^ 0x55AA0000U;
+ return (a->val & 0xFF) ^ (a->val << 29) ^ 0x55AA0000U;
#else
return jhash_1word(a->val, 0xdeadbeef);
#endif
diff --git a/tests/topotests/bgp_accept_own/__init__.py b/tests/topotests/bgp_accept_own/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/bgp_accept_own/__init__.py
diff --git a/tests/topotests/bgp_accept_own/ce1/bgpd.conf b/tests/topotests/bgp_accept_own/ce1/bgpd.conf
new file mode 100644
index 000000000..fa53a4291
--- /dev/null
+++ b/tests/topotests/bgp_accept_own/ce1/bgpd.conf
@@ -0,0 +1,12 @@
+!
+debug bgp updates
+!
+router bgp 65010
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.2 remote-as external
+ neighbor 192.168.1.2 timers 1 3
+ neighbor 192.168.1.2 timers connect 1
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_accept_own/ce1/zebra.conf b/tests/topotests/bgp_accept_own/ce1/zebra.conf
new file mode 100644
index 000000000..7863ae165
--- /dev/null
+++ b/tests/topotests/bgp_accept_own/ce1/zebra.conf
@@ -0,0 +1,9 @@
+!
+interface lo
+ ip address 172.16.255.1/32
+!
+interface ce1-eth0
+ ip address 192.168.1.1/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_accept_own/ce2/bgpd.conf b/tests/topotests/bgp_accept_own/ce2/bgpd.conf
new file mode 100644
index 000000000..cdf8898c9
--- /dev/null
+++ b/tests/topotests/bgp_accept_own/ce2/bgpd.conf
@@ -0,0 +1,12 @@
+!
+debug bgp updates
+!
+router bgp 65020
+ no bgp ebgp-requires-policy
+ neighbor 192.168.2.2 remote-as external
+ neighbor 192.168.2.2 timers 1 3
+ neighbor 192.168.2.2 timers connect 1
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_accept_own/ce2/zebra.conf b/tests/topotests/bgp_accept_own/ce2/zebra.conf
new file mode 100644
index 000000000..829967e36
--- /dev/null
+++ b/tests/topotests/bgp_accept_own/ce2/zebra.conf
@@ -0,0 +1,9 @@
+!
+interface lo
+ ip address 172.16.255.2/32
+!
+interface ce2-eth0
+ ip address 192.168.2.1/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_accept_own/pe1/bgpd.conf b/tests/topotests/bgp_accept_own/pe1/bgpd.conf
new file mode 100644
index 000000000..863129373
--- /dev/null
+++ b/tests/topotests/bgp_accept_own/pe1/bgpd.conf
@@ -0,0 +1,49 @@
+!
+debug bgp updates
+debug bgp vpn leak-from-vrf
+debug bgp vpn leak-to-vrf
+debug bgp nht
+!
+router bgp 65001
+ bgp router-id 10.10.10.10
+ no bgp ebgp-requires-policy
+ no bgp default ipv4-unicast
+ neighbor 10.10.10.101 remote-as internal
+ neighbor 10.10.10.101 update-source 10.10.10.10
+ neighbor 10.10.10.101 timers 1 3
+ neighbor 10.10.10.101 timers connect 1
+ address-family ipv4 vpn
+ neighbor 10.10.10.101 activate
+ neighbor 10.10.10.101 attribute-unchanged
+ exit-address-family
+!
+router bgp 65001 vrf Customer
+ bgp router-id 192.168.1.2
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.1 remote-as external
+ neighbor 192.168.1.1 timers 1 3
+ neighbor 192.168.1.1 timers connect 1
+ address-family ipv4 unicast
+ label vpn export 10
+ rd vpn export 192.168.1.2:2
+ rt vpn import 192.168.1.2:2
+ rt vpn export 192.168.1.2:2
+ export vpn
+ import vpn
+ exit-address-family
+!
+router bgp 65001 vrf Service
+ bgp router-id 192.168.2.2
+ no bgp ebgp-requires-policy
+ neighbor 192.168.2.1 remote-as external
+ neighbor 192.168.2.1 timers 1 3
+ neighbor 192.168.2.1 timers connect 1
+ address-family ipv4 unicast
+ label vpn export 20
+ rd vpn export 192.168.2.2:2
+ rt vpn import 192.168.2.2:2
+ rt vpn export 192.168.2.2:2
+ export vpn
+ import vpn
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_accept_own/pe1/ldpd.conf b/tests/topotests/bgp_accept_own/pe1/ldpd.conf
new file mode 100644
index 000000000..7c1ea33a3
--- /dev/null
+++ b/tests/topotests/bgp_accept_own/pe1/ldpd.conf
@@ -0,0 +1,12 @@
+mpls ldp
+ router-id 10.10.10.10
+ !
+ address-family ipv4
+ discovery transport-address 10.10.10.10
+ !
+ interface pe1-eth2
+ exit
+ !
+ exit-address-family
+ !
+exit
diff --git a/tests/topotests/bgp_accept_own/pe1/ospfd.conf b/tests/topotests/bgp_accept_own/pe1/ospfd.conf
new file mode 100644
index 000000000..1a5e1a06b
--- /dev/null
+++ b/tests/topotests/bgp_accept_own/pe1/ospfd.conf
@@ -0,0 +1,7 @@
+interface pe1-eth2
+ ip ospf dead-interval 4
+ ip ospf hello-interval 1
+!
+router ospf
+ router-id 10.10.10.10
+ network 0.0.0.0/0 area 0
diff --git a/tests/topotests/bgp_accept_own/pe1/zebra.conf b/tests/topotests/bgp_accept_own/pe1/zebra.conf
new file mode 100644
index 000000000..71476d2ae
--- /dev/null
+++ b/tests/topotests/bgp_accept_own/pe1/zebra.conf
@@ -0,0 +1,15 @@
+!
+interface lo
+ ip address 10.10.10.10/32
+!
+interface pe1-eth0 vrf Customer
+ ip address 192.168.1.2/24
+!
+interface pe1-eth1 vrf Service
+ ip address 192.168.2.2/24
+!
+interface pe1-eth2
+ ip address 10.0.1.1/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_accept_own/rr1/bgpd.conf b/tests/topotests/bgp_accept_own/rr1/bgpd.conf
new file mode 100644
index 000000000..4f0a6ab0f
--- /dev/null
+++ b/tests/topotests/bgp_accept_own/rr1/bgpd.conf
@@ -0,0 +1,25 @@
+!
+debug bgp updates
+!
+router bgp 65001
+ bgp router-id 10.10.10.101
+ bgp route-reflector allow-outbound-policy
+ no bgp ebgp-requires-policy
+ no bgp default ipv4-unicast
+ neighbor 10.10.10.10 remote-as internal
+ neighbor 10.10.10.10 update-source 10.10.10.101
+ neighbor 10.10.10.10 timers 1 3
+ neighbor 10.10.10.10 timers connect 1
+ address-family ipv4 vpn
+ neighbor 10.10.10.10 activate
+ neighbor 10.10.10.10 route-reflector-client
+ neighbor 10.10.10.10 route-map pe1 out
+ exit-address-family
+!
+route-map pe1 permit 10
+ set extcommunity rt 192.168.1.2:2 192.168.2.2:2
+ set community 65001:111 accept-own additive
+ set ip next-hop unchanged
+route-map pe1 permit 20
+exit
+!
diff --git a/tests/topotests/bgp_accept_own/rr1/ldpd.conf b/tests/topotests/bgp_accept_own/rr1/ldpd.conf
new file mode 100644
index 000000000..036990186
--- /dev/null
+++ b/tests/topotests/bgp_accept_own/rr1/ldpd.conf
@@ -0,0 +1,12 @@
+mpls ldp
+ router-id 10.10.10.101
+ !
+ address-family ipv4
+ discovery transport-address 10.10.10.101
+ !
+ interface rr1-eth0
+ exit
+ !
+ exit-address-family
+ !
+exit
diff --git a/tests/topotests/bgp_accept_own/rr1/ospfd.conf b/tests/topotests/bgp_accept_own/rr1/ospfd.conf
new file mode 100644
index 000000000..b598246ef
--- /dev/null
+++ b/tests/topotests/bgp_accept_own/rr1/ospfd.conf
@@ -0,0 +1,7 @@
+interface rr1-eth0
+ ip ospf dead-interval 4
+ ip ospf hello-interval 1
+!
+router ospf
+ router-id 10.10.10.101
+ network 0.0.0.0/0 area 0
diff --git a/tests/topotests/bgp_accept_own/rr1/zebra.conf b/tests/topotests/bgp_accept_own/rr1/zebra.conf
new file mode 100644
index 000000000..aa3f633bf
--- /dev/null
+++ b/tests/topotests/bgp_accept_own/rr1/zebra.conf
@@ -0,0 +1,9 @@
+!
+interface lo
+ ip address 10.10.10.101/32
+!
+interface rr1-eth0
+ ip address 10.0.1.2/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_accept_own/test_bgp_accept_own.py b/tests/topotests/bgp_accept_own/test_bgp_accept_own.py
new file mode 100644
index 000000000..161530b48
--- /dev/null
+++ b/tests/topotests/bgp_accept_own/test_bgp_accept_own.py
@@ -0,0 +1,198 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2022 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+# 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.
+#
+
+"""
+
+"""
+
+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
+from lib.common_config import step
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ tgen.add_router("ce1")
+ tgen.add_router("ce2")
+ tgen.add_router("pe1")
+ tgen.add_router("rr1")
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["ce1"])
+ switch.add_link(tgen.gears["pe1"])
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["ce2"])
+ switch.add_link(tgen.gears["pe1"])
+
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["pe1"])
+ switch.add_link(tgen.gears["rr1"])
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ pe1 = tgen.gears["pe1"]
+ rr1 = tgen.gears["rr1"]
+
+ pe1.run("ip link add Customer type vrf table 1001")
+ pe1.run("ip link set up dev Customer")
+ pe1.run("ip link set pe1-eth0 master Customer")
+ pe1.run("ip link add Service type vrf table 1002")
+ pe1.run("ip link set up dev Service")
+ pe1.run("ip link set pe1-eth1 master Service")
+ pe1.run("sysctl -w net.mpls.conf.pe1-eth2.input=1")
+ rr1.run("sysctl -w net.mpls.conf.rr1-eth0.input=1")
+
+ 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))
+ )
+ router.load_config(
+ TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_LDP, os.path.join(CWD, "{}/ldpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_accept_own():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ pe1 = tgen.gears["pe1"]
+ ce2 = tgen.gears["ce2"]
+
+ step("Check if routes are not installed in PE1 from RR1 (due to ORIGINATOR_ID)")
+
+ def _bgp_check_received_routes_due_originator_id():
+ output = json.loads(pe1.vtysh_cmd("show bgp ipv4 vpn summary json"))
+ expected = {"peers": {"10.10.10.101": {"pfxRcd": 0, "pfxSnt": 4}}}
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_check_received_routes_due_originator_id)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
+ assert result is None, "Failed, received routes from RR1 regardless ORIGINATOR_ID"
+
+ step("Enable ACCEPT_OWN for RR1")
+
+ pe1.vtysh_cmd(
+ """
+ configure terminal
+ router bgp 65001
+ address-family ipv4 vpn
+ neighbor 10.10.10.101 accept-own
+ """
+ )
+
+ step("Check if we received routes due to ACCEPT_OWN from RR1")
+
+ def _bgp_check_received_routes_with_modified_rts():
+ output = json.loads(pe1.vtysh_cmd("show bgp ipv4 vpn summary json"))
+ expected = {"peers": {"10.10.10.101": {"pfxRcd": 4, "pfxSnt": 4}}}
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_check_received_routes_with_modified_rts)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
+ assert (
+ result is None
+ ), "Failed, didn't receive routes from RR1 with ACCEPT_OWN enabled"
+
+ step(
+ "Check if 172.16.255.1/32 is imported into vrf Service due to modified RT list at RR1"
+ )
+
+ def _bgp_check_received_routes_with_changed_rts():
+ output = json.loads(
+ pe1.vtysh_cmd("show bgp vrf Service ipv4 unicast 172.16.255.1/32 json")
+ )
+ expected = {
+ "paths": [
+ {
+ "community": {
+ "string": "65001:111"
+ },
+ "extendedCommunity": {
+ "string": "RT:192.168.1.2:2 RT:192.168.2.2:2"
+ },
+ }
+ ]
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_check_received_routes_with_changed_rts)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
+ assert (
+ result is None
+ ), "Failed, routes are not imported from RR1 with modified RT list"
+
+ step("Check if 172.16.255.1/32 is announced to CE2")
+
+ def _bgp_check_received_routes_from_pe():
+ output = json.loads(ce2.vtysh_cmd("show ip route 172.16.255.1/32 json"))
+ expected = {
+ "172.16.255.1/32": [
+ {
+ "protocol": "bgp",
+ "installed": True,
+ "nexthops": [{"ip": "192.168.2.2"}],
+ }
+ ]
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_check_received_routes_from_pe)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
+ assert (
+ result is None
+ ), "Failed, didn't receive 172.16.255.1/32 from PE1"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_basic_functionality_topo1/test_bgp_basic_functionality.py b/tests/topotests/bgp_basic_functionality_topo1/test_bgp_basic_functionality.py
index b18e32f6b..42b9b8adb 100644
--- a/tests/topotests/bgp_basic_functionality_topo1/test_bgp_basic_functionality.py
+++ b/tests/topotests/bgp_basic_functionality_topo1/test_bgp_basic_functionality.py
@@ -121,7 +121,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.15")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >=4.15")
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
@@ -1148,9 +1148,9 @@ def test_bgp_with_loopback_with_same_subnet_p1(request):
tgen, addr_type, dut, input_dict_r1, expected=False
) # pylint: disable=E1123
assert result is not True, (
- "Testcase {} : Failed \n".format(tc_name)
- + "Expected behavior: routes should not present in fib \n"
- + "Error: {}".format(result)
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
step("Verify Ipv4 and Ipv6 network installed in r3 RIB but not in FIB")
@@ -1169,9 +1169,9 @@ def test_bgp_with_loopback_with_same_subnet_p1(request):
tgen, addr_type, dut, input_dict_r1, expected=False
) # pylint: disable=E1123
assert result is not True, (
- "Testcase {} : Failed \n".format(tc_name)
- + "Expected behavior: routes should not present in fib \n"
- + "Error: {}".format(result)
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
write_test_footer(tc_name)
diff --git a/tests/topotests/bgp_communities_topo1/test_bgp_communities.py b/tests/topotests/bgp_communities_topo1/test_bgp_communities.py
index e4c25ff5c..1c1a5cdfe 100644
--- a/tests/topotests/bgp_communities_topo1/test_bgp_communities.py
+++ b/tests/topotests/bgp_communities_topo1/test_bgp_communities.py
@@ -83,7 +83,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.15")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >= 4.15")
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
@@ -317,17 +317,18 @@ def test_bgp_no_advertise_community_p0(request):
)
result = verify_bgp_rib(tgen, addr_type, dut, input_dict, expected=False)
- assert result is not True, "Testcase {} : Failed \n ".format(
- tc_name
- ) + " Routes still present in R3 router. Error: {}".format(result)
+ assert result is not True, (
+ "Testcase {} : Failed \n Expected: "
+ "Routes still present in {} router. Found: {}".format(tc_name, dut, result)
+ )
result = verify_rib(
tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
)
assert (
result is not True
- ), "Testcase {} : Failed \n Routes still present in R3 router. Error: {}".format(
- tc_name, result
+ ), "Testcase {} : Failed \n Expected: Routes still present in {} router. Found: {}".format(
+ tc_name, dut, result
)
step("Remove and Add no advertise community")
diff --git a/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py b/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py
index f6ee9ea79..a93061740 100644
--- a/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py
+++ b/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py
@@ -87,7 +87,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.14")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >= 4.14")
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
@@ -305,8 +305,10 @@ def test_bgp_no_export_local_as_and_internet_communities_p0(request):
],
expected=False,
)
- assert result is not True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes are still present in rib of r3 \n "
+ "Found: {}".format(tc_name, result)
)
step("Remove route-map from redistribute static on R1")
diff --git a/tests/topotests/bgp_ecmp_topo2/test_ebgp_ecmp_topo2.py b/tests/topotests/bgp_ecmp_topo2/test_ebgp_ecmp_topo2.py
index 2784e956f..8fd0120dd 100644
--- a/tests/topotests/bgp_ecmp_topo2/test_ebgp_ecmp_topo2.py
+++ b/tests/topotests/bgp_ecmp_topo2/test_ebgp_ecmp_topo2.py
@@ -90,7 +90,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.15")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >=4.15")
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
@@ -436,7 +436,9 @@ def test_ecmp_remove_redistribute_static(request):
)
assert (
result is not True
- ), "Testcase {} : Failed \n Routes still" " present in RIB".format(tc_name)
+ ), "Testcase {} : Failed \n Expected: Routes still present in {} RIB. Found: {}".format(
+ tc_name, dut, result
+ )
logger.info("Enable redistribute static")
input_dict_2 = {
@@ -621,7 +623,9 @@ def test_ecmp_remove_static_route(request):
)
assert (
result is not True
- ), "Testcase {} : Failed \n Routes still" " present in RIB".format(tc_name)
+ ), "Testcase {} : Failed \n Expected: Routes still present in {} RIB. Found: {}".format(
+ tc_name, dut, result
+ )
for addr_type in ADDR_TYPES:
# Enable static routes
@@ -727,7 +731,9 @@ def test_ecmp_remove_nw_advertise(request):
)
assert (
result is not True
- ), "Testcase {} : Failed \n Routes still" " present in RIB".format(tc_name)
+ ), "Testcase {} : Failed \n Expected: Routes still present in {} RIB. Found: {}".format(
+ tc_name, dut, result
+ )
static_or_nw(tgen, topo, tc_name, "advertise_nw", "r2")
for addr_type in ADDR_TYPES:
diff --git a/tests/topotests/bgp_ecmp_topo2/test_ibgp_ecmp_topo2.py b/tests/topotests/bgp_ecmp_topo2/test_ibgp_ecmp_topo2.py
index 704e8fdf0..185a08683 100644
--- a/tests/topotests/bgp_ecmp_topo2/test_ibgp_ecmp_topo2.py
+++ b/tests/topotests/bgp_ecmp_topo2/test_ibgp_ecmp_topo2.py
@@ -90,7 +90,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.15")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >=4.15")
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
@@ -437,7 +437,9 @@ def test_ecmp_remove_redistribute_static(request):
)
assert (
result is not True
- ), "Testcase {} : Failed \n Routes still" " present in RIB".format(tc_name)
+ ), "Testcase {} : Failed \n Expected: Routes still present in {} RIB. Found: {}".format(
+ tc_name, dut, result
+ )
logger.info("Enable redistribute static")
input_dict_2 = {
@@ -622,7 +624,9 @@ def test_ecmp_remove_static_route(request):
)
assert (
result is not True
- ), "Testcase {} : Failed \n Routes still" " present in RIB".format(tc_name)
+ ), "Testcase {} : Failed \n Expected: Routes still present in {} RIB. Found: {}".format(
+ tc_name, dut, result
+ )
for addr_type in ADDR_TYPES:
# Enable static routes
@@ -730,7 +734,9 @@ def test_ecmp_remove_nw_advertise(request):
)
assert (
result is not True
- ), "Testcase {} : Failed \n Routes still" " present in RIB".format(tc_name)
+ ), "Testcase {} : Failed \n Expected: Routes still present in {} RIB. Found: {}".format(
+ tc_name, dut, result
+ )
static_or_nw(tgen, topo, tc_name, "advertise_nw", "r2")
for addr_type in ADDR_TYPES:
diff --git a/tests/topotests/bgp_ecmp_topo3/test_ibgp_ecmp_topo3.py b/tests/topotests/bgp_ecmp_topo3/test_ibgp_ecmp_topo3.py
index 2a51dc83e..9b6480c0d 100644
--- a/tests/topotests/bgp_ecmp_topo3/test_ibgp_ecmp_topo3.py
+++ b/tests/topotests/bgp_ecmp_topo3/test_ibgp_ecmp_topo3.py
@@ -240,17 +240,18 @@ def test_ecmp_fast_convergence(request, test_type, tgen, topo):
logger.info("Ensure BGP has processed the cli")
r2 = tgen.gears["r2"]
output = r2.vtysh_cmd("show run")
- verify = re.search(r"fast-convergence", output )
- assert verify is not None, (
- "r2 does not have the fast convergence command yet")
+ verify = re.search(r"fast-convergence", output)
+ assert verify is not None, "r2 does not have the fast convergence command yet"
logger.info("Shutdown one link b/w r2 and r3")
shutdown_bringup_interface(tgen, "r2", intf1, False)
logger.info("Verify bgp neighbors goes down immediately")
result = verify_bgp_convergence(tgen, topo, dut="r2", expected=False)
- assert result is not True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: BGP should not be converged for {} \n "
+ "Found: {}".format(tc_name, "r2", result)
)
logger.info("Shutdown second link b/w r2 and r3")
@@ -258,8 +259,10 @@ def test_ecmp_fast_convergence(request, test_type, tgen, topo):
logger.info("Verify bgp neighbors goes down immediately")
result = verify_bgp_convergence(tgen, topo, dut="r2", expected=False)
- assert result is not True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: BGP should not be converged for {} \n "
+ "Found: {}".format(tc_name, "r2", result)
)
write_test_footer(tc_name)
diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-1.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-1.py
index f15532550..deca4bcfd 100644
--- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-1.py
+++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-1.py
@@ -160,7 +160,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.16")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >=4.16")
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
@@ -1033,11 +1033,9 @@ def test_BGP_GR_TC_4_p0(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
# Verifying RIB routes
result = verify_rib(
@@ -1045,9 +1043,9 @@ def test_BGP_GR_TC_4_p0(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
logger.info("[Phase 5] : R2 is about to come up now ")
start_router_daemons(tgen, "r2", ["bgpd"])
@@ -1506,10 +1504,10 @@ def test_BGP_GR_TC_6_1_2_p1(request):
result = verify_r_bit(
tgen, topo, addr_type, input_dict, dut="r2", peer="r1", expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n " "r2: R-bit is set to True\n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: R-bit should not be set to True in r2\n"
+ "Found: {}".format(tc_name, result)
)
logger.info("Restart BGPd on R2 ")
@@ -1528,10 +1526,10 @@ def test_BGP_GR_TC_6_1_2_p1(request):
result = verify_r_bit(
tgen, topo, addr_type, input_dict, dut="r2", peer="r1", expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n " "r2: R-bit is set to True\n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: R-bit should not be set to True in r2\n"
+ "Found: {}".format(tc_name, result)
)
write_test_footer(tc_name)
diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-2.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-2.py
index dda3bd4b3..a92fde2d0 100644
--- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-2.py
+++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-2.py
@@ -160,7 +160,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.16")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >=4.16")
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-3.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-3.py
index e4b533b29..b0166033d 100644
--- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-3.py
+++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-3.py
@@ -160,7 +160,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.16")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >=4.16")
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
@@ -829,11 +829,9 @@ def test_BGP_GR_TC_20_p1(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
# Verifying RIB routes
result = verify_rib(
@@ -841,9 +839,9 @@ def test_BGP_GR_TC_20_p1(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
logger.info("[Phase 5] : R2 is about to come up now ")
@@ -1117,7 +1115,8 @@ def test_BGP_GR_TC_31_1_p1(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
logger.info("[Phase 4] : R1 is about to come up now ")
@@ -1599,11 +1598,9 @@ def test_BGP_GR_TC_9_p1(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
# Verifying RIB routes
protocol = "bgp"
@@ -1612,9 +1609,9 @@ def test_BGP_GR_TC_9_p1(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
logger.info("[Phase 5] : R2 is about to come up now ")
start_router_daemons(tgen, "r2", ["bgpd"])
@@ -1643,10 +1640,10 @@ def test_BGP_GR_TC_9_p1(request):
result = verify_f_bit(
tgen, topo, addr_type, input_dict, dut="r1", peer="r2", expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n " "r1: F-bit is set to True\n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: F-bit should not be set to True in r1\n"
+ "Found: {}".format(tc_name, result)
)
write_test_footer(tc_name)
@@ -1781,11 +1778,9 @@ def test_BGP_GR_TC_17_p1(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
# Verifying RIB routes
protocol = "bgp"
@@ -1794,9 +1789,9 @@ def test_BGP_GR_TC_17_p1(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
logger.info("[Phase 5] : R2 is about to come up now ")
start_router_daemons(tgen, "r2", ["bgpd"])
@@ -1817,10 +1812,10 @@ def test_BGP_GR_TC_17_p1(request):
result = verify_r_bit(
tgen, topo, addr_type, input_dict, dut="r1", peer="r2", expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n " "r1: R-bit is set to True\n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: R-bit should not be set to True in r1\n"
+ "Found: {}".format(tc_name, result)
)
# Verifying BGP RIB routes
@@ -2026,10 +2021,10 @@ def test_BGP_GR_TC_43_p1(request):
result = verify_rib(
tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} :Failed \n Routes are still present \n Error {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
dut = "r2"
@@ -2043,18 +2038,18 @@ def test_BGP_GR_TC_43_p1(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r2: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
+
protocol = "bgp"
result = verify_rib(
tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} :Failed \n Routes are still present \n Error {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
step(
@@ -2353,17 +2348,17 @@ def test_BGP_GR_TC_44_p1(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
+
result = verify_rib(
tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} :Failed \n Routes are still present \n Error {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
step("Bring up BGPd on R2 and remove GR related config from R1 in global level")
diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py
index 835ef41de..f408ff485 100644
--- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py
+++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py
@@ -160,7 +160,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.16")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >=4.16")
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
@@ -1157,7 +1157,8 @@ def test_BGP_GR_TC_48_p1(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
dut = "r2"
@@ -1171,16 +1172,17 @@ def test_BGP_GR_TC_48_p1(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r2: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
+
result = verify_rib(
tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r2: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
step("Bring up BGP on R1 and remove Peer-level GR config from R1")
@@ -1542,16 +1544,17 @@ def BGP_GR_TC_52_p1(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
+
result = verify_rib(
tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
step("Bring up BGP on R2 and remove Peer-level GR config from R1")
diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-1.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-1.py
index 3afe38857..293f3042e 100644
--- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-1.py
+++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-1.py
@@ -155,7 +155,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.16")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >=4.16")
global ADDR_TYPES
@@ -528,10 +528,10 @@ def test_BGP_GR_TC_3_p0(request):
result = verify_eor(
tgen, topo, addr_type, input_dict, dut="r2", peer="r1", expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n " "r2: EOR is set to True\n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: EOR should not be set to True in r2\n"
+ "Found: {}".format(tc_name, result)
)
logger.info(
@@ -675,10 +675,10 @@ def test_BGP_GR_TC_11_p0(request):
result = verify_eor(
tgen, topo, addr_type, input_dict, dut="r1", peer="r3", expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n " "r1: EOR is set to True\n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: EOR should not be set to True in r1\n"
+ "Found: {}".format(tc_name, result)
)
logger.info(
@@ -706,10 +706,10 @@ def test_BGP_GR_TC_11_p0(request):
result = verify_eor(
tgen, topo, addr_type, input_dict, dut="r3", peer="r1", expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n " "r3: EOR is set to True\n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: EOR should not be set to True in r3\n"
+ "Found: {}".format(tc_name, result)
)
write_test_footer(tc_name)
@@ -1474,38 +1474,33 @@ def test_BGP_GR_18_p1(request):
result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
- "r6: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
# Verifying RIB routes before shutting down BGPd daemon
result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
- "r6: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
# Verifying BGP RIB routes
dut = "r2"
- result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
- "r2: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
# Verifying RIB routes before shutting down BGPd daemon
result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
- "r6: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
write_test_footer(tc_name)
diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-2.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-2.py
index 535f272ef..fe885372d 100644
--- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-2.py
+++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-2.py
@@ -155,7 +155,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.16")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >=4.16")
global ADDR_TYPES
@@ -726,19 +726,17 @@ def test_BGP_GR_chaos_29_p1(request):
result = verify_bgp_rib(tgen, addr_type, dut, input_dict, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
- "r3: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
# Verifying RIB routes before shutting down BGPd daemon
result = verify_rib(tgen, addr_type, dut, input_dict, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
- "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
logger.info("[Step 4] : Start BGPd daemon on R1..")
@@ -981,11 +979,9 @@ def test_BGP_GR_chaos_33_p1(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r3: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
if addr_type == "ipv6":
if "link_local" in PREFERRED_NEXT_HOP:
@@ -998,11 +994,9 @@ def test_BGP_GR_chaos_33_p1(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r3: routes are still present in ZEBRA\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
logger.info("[Step 4] : Start BGPd daemon on R1 and R4..")
@@ -1182,31 +1176,28 @@ def test_BGP_GR_chaos_34_2_p1(request):
result = verify_f_bit(
tgen, topo, addr_type, input_dict, "r3", "r1", expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n " "r3: F-bit is set to True\n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: F-bit should not be set to True in r3\n"
+ "Found: {}".format(tc_name, result)
)
- logger.info(" Expected behavior: {}".format(result))
# Verifying BGP RIB routes after starting BGPd daemon
input_dict_1 = {key: topo["routers"][key] for key in ["r1"]}
result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
- "r3: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
# Verifying RIB routes
result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
- "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
write_test_footer(tc_name)
diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-3.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-3.py
index e60552ed1..4ff62a978 100644
--- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-3.py
+++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-3.py
@@ -155,7 +155,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.16")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >=4.16")
global ADDR_TYPES
@@ -380,12 +380,11 @@ def test_BGP_GR_chaos_34_1_p1(request):
result = verify_f_bit(
tgen, topo, addr_type, input_dict_2, "r3", "r1", expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n " "r3: F-bit is set to True\n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: F-bit should not be set to True in r3\n"
+ "Found: {}".format(tc_name, result)
)
- logger.info(" Expected behavior: {}".format(result))
logger.info("[Step 3] : Kill BGPd daemon on R1..")
@@ -402,19 +401,17 @@ def test_BGP_GR_chaos_34_1_p1(request):
result = verify_bgp_rib(tgen, addr_type, dut, input_dict, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
- "r3: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
# Verifying RIB routes
result = verify_rib(tgen, addr_type, dut, input_dict, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
- "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
# Start BGPd daemon on R1
start_router_daemons(tgen, "r1", ["bgpd"])
@@ -587,31 +584,28 @@ def test_BGP_GR_chaos_32_p1(request):
result = verify_eor(
tgen, topo, addr_type, input_dict_3, dut="r5", peer="r1", expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n " "r5: EOR is set to TRUE\n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: EOR should not be set to True in r5\n"
+ "Found: {}".format(tc_name, result)
)
- logger.info(" Expected behavior: {}".format(result))
# Verifying BGP RIB routes after starting BGPd daemon
input_dict_1 = {key: topo["routers"][key] for key in ["r5"]}
result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
- "r3: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
# Verifying RIB routes
result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
- "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
write_test_footer(tc_name)
@@ -716,12 +710,11 @@ def test_BGP_GR_chaos_37_p1(request):
result = verify_eor(
tgen, topo, addr_type, input_dict, dut="r3", peer="r1", expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n " "r3: EOR is set to True\n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: EOR should not be set to True in r3\n"
+ "Found: {}".format(tc_name, result)
)
- logger.info(" Expected behavior: {}".format(result))
# Verifying BGP RIB routes after starting BGPd daemon
dut = "r1"
@@ -783,10 +776,10 @@ def test_BGP_GR_chaos_37_p1(request):
result = verify_eor(
tgen, topo, addr_type, input_dict_3, dut="r1", peer="r3", expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n " "r1: EOR is set to True\n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: EOR should not be set to True in r1\n"
+ "Found: {}".format(tc_name, result)
)
write_test_footer(tc_name)
@@ -941,19 +934,17 @@ def test_BGP_GR_chaos_30_p1(request):
result = verify_bgp_rib(tgen, addr_type, dut, input_dict, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
# Verifying RIB routes before shutting down BGPd daemon
result = verify_rib(tgen, addr_type, dut, input_dict, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
write_test_footer(tc_name)
@@ -1356,7 +1347,8 @@ def BGP_GR_TC_7_p1(request):
result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
write_test_footer(tc_name)
diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-4.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-4.py
index 1df77ebeb..fd1ef097c 100644
--- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-4.py
+++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-4.py
@@ -157,7 +157,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.16")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >=4.16")
global ADDR_TYPES
@@ -420,10 +420,10 @@ def test_BGP_GR_TC_23_p1(request):
result = verify_eor(
tgen, topo, addr_type, input_dict, dut="r1", peer="r2", expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n " "r1: EOR is set to True\n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: EOR should not be set to True in r2\n"
+ "Found: {}".format(tc_name, result)
)
# Verifying BGP RIB routes received from router R1
@@ -547,19 +547,17 @@ def test_BGP_GR_20_p1(request):
result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
- "r3: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
# Verifying RIB routes before shutting down BGPd daemon
result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
- "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
# Start BGPd daemon on R1
start_router_daemons(tgen, "r1", ["bgpd"])
diff --git a/tests/topotests/bgp_gr_functionality_topo3/bgp_gr_functionality_topo3.py b/tests/topotests/bgp_gr_functionality_topo3/bgp_gr_functionality_topo3.py
index 6bf8b9630..76522206a 100644
--- a/tests/topotests/bgp_gr_functionality_topo3/bgp_gr_functionality_topo3.py
+++ b/tests/topotests/bgp_gr_functionality_topo3/bgp_gr_functionality_topo3.py
@@ -56,15 +56,20 @@ from lib.bgp import (
verify_graceful_restart_timers,
verify_bgp_convergence_from_running_config,
)
+
# Import common_config to use commomnly used APIs
-from lib.common_config import (create_common_configuration,
- InvalidCLIError, retry,
- generate_ips, FRRCFG_FILE,
- find_interface_with_greater_ip,
- check_address_types,
- validate_ip_address,
- run_frr_cmd,
- get_frr_ipv6_linklocal)
+from lib.common_config import (
+ create_common_configuration,
+ InvalidCLIError,
+ retry,
+ generate_ips,
+ FRRCFG_FILE,
+ find_interface_with_greater_ip,
+ check_address_types,
+ validate_ip_address,
+ run_frr_cmd,
+ get_frr_ipv6_linklocal,
+)
from lib.common_config import (
write_test_header,
@@ -108,8 +113,7 @@ NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
PREFERRED_NEXT_HOP = "link_local"
-def configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name,
- dut, peer):
+def configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut, peer):
"""
result = configure_gr_followed_by_clear(tgen, topo, dut)
assert result is True, \
@@ -118,8 +122,7 @@ def configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name,
"""
result = create_router_bgp(tgen, topo, input_dict)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
for addr_type in ADDR_TYPES:
clear_bgp(tgen, addr_type, dut)
@@ -131,6 +134,7 @@ def configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name,
return True
+
def verify_stale_routes_list(tgen, addr_type, dut, input_dict):
"""
This API is use verify Stale routes on refering the network with next hop value
@@ -175,8 +179,8 @@ def verify_stale_routes_list(tgen, addr_type, dut, input_dict):
command = "show bgp"
# Static routes
sleep(2)
- logger.info('Checking router {} BGP RIB:'.format(dut))
- if 'static_routes' in input_dict[routerInput]:
+ logger.info("Checking router {} BGP RIB:".format(dut))
+ if "static_routes" in input_dict[routerInput]:
static_routes = input_dict[routerInput]["static_routes"]
for static_route in static_routes:
found_routes = []
@@ -185,30 +189,27 @@ def verify_stale_routes_list(tgen, addr_type, dut, input_dict):
nh_found = False
vrf = static_route.setdefault("vrf", None)
community = static_route.setdefault("community", None)
- largeCommunity = \
- static_route.setdefault("largeCommunity", None)
+ largeCommunity = static_route.setdefault("largeCommunity", None)
if vrf:
- cmd = "{} vrf {} {}".\
- format(command, vrf, addr_type)
+ cmd = "{} vrf {} {}".format(command, vrf, addr_type)
if community:
- cmd = "{} community {}".\
- format(cmd, community)
+ cmd = "{} community {}".format(cmd, community)
if largeCommunity:
- cmd = "{} large-community {}".\
- format(cmd, largeCommunity)
+ cmd = "{} large-community {}".format(cmd, largeCommunity)
else:
- cmd = "{} {}".\
- format(command, addr_type)
+ cmd = "{} {}".format(command, addr_type)
cmd = "{} json".format(cmd)
rib_routes_json = run_frr_cmd(rnode, cmd, isjson=True)
# Verifying output dictionary rib_routes_json is not empty
if bool(rib_routes_json) == False:
- errormsg = "[DUT: {}]: No route found in rib of router". \
- format(router)
+ errormsg = "[DUT: {}]: No route found in rib of router".format(
+ router
+ )
return errormsg
elif "warning" in rib_routes_json:
- errormsg = "[DUT: {}]: {}". \
- format(router, rib_routes_json["warning"])
+ errormsg = "[DUT: {}]: {}".format(
+ router, rib_routes_json["warning"]
+ )
return errormsg
network = static_route["network"]
if "no_of_ip" in static_route:
@@ -227,15 +228,18 @@ def verify_stale_routes_list(tgen, addr_type, dut, input_dict):
st_found = True
found_routes.append(st_rt)
- for mnh in range(0, len(rib_routes_json[
- 'routes'][st_rt])):
- found_hops.append([rib_r[
- "ip"] for rib_r in rib_routes_json[
- 'routes'][st_rt][
- mnh]["nexthops"]])
+ for mnh in range(0, len(rib_routes_json["routes"][st_rt])):
+ found_hops.append(
+ [
+ rib_r["ip"]
+ for rib_r in rib_routes_json["routes"][st_rt][
+ mnh
+ ]["nexthops"]
+ ]
+ )
return found_hops
else:
- return 'error msg - no hops found'
+ return "error msg - no hops found"
def setup_module(mod):
@@ -248,7 +252,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.16")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >=4.16")
global ADDR_TYPES
@@ -302,6 +306,8 @@ def teardown_module(mod):
"Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
)
logger.info("=" * 40)
+
+
################################################################################
#
# TEST CASES
@@ -318,175 +324,160 @@ def test_bgp_gr_stale_routes(request):
step("Creating 5 static Routes in Router R3 with NULL0 as Next hop")
for addr_type in ADDR_TYPES:
- input_dict_1 = {
- "r3": {
- "static_routes": [{
- "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
- "next_hop": NEXT_HOP_IP[addr_type]
- },
- {
- "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
- "next_hop": NEXT_HOP_IP[addr_type]
- },
- {
- "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
- "next_hop": NEXT_HOP_IP[addr_type]
- },
- {
- "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
- "next_hop": NEXT_HOP_IP[addr_type]
- },
- {
- "network": [NETWORK5_1[addr_type]] + [NETWORK5_2[addr_type]],
- "next_hop": NEXT_HOP_IP[addr_type]
- }]
- }
+ input_dict_1 = {
+ "r3": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [NETWORK5_1[addr_type]] + [NETWORK5_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ ]
}
- result = create_static_routes(tgen, input_dict_1)
- assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
- tc_name, result)
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
step("verifying Created Route at R3 in VRF default")
for addr_type in ADDR_TYPES:
- dut = 'r3'
- input_dict_1= {'r3': topo['routers']['r3']}
+ dut = "r3"
+ input_dict_1 = {"r3": topo["routers"]["r3"]}
result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
- assert result is True, \
- "Testcase {} :Failed \n Error {}". \
- format(tc_name, result)
- #done
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+ # done
step("verifying Created Route at R2 in VRF default")
for addr_type in ADDR_TYPES:
- dut = 'r2'
- input_dict_1= {'r2': topo['routers']['r2']}
+ dut = "r2"
+ input_dict_1 = {"r2": topo["routers"]["r2"]}
result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
- assert result is True, \
- "Testcase {} :Failed \n Error {}". \
- format(tc_name, result)
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
step("importing vrf RED on R2 under Address Family")
for addr_type in ADDR_TYPES:
- input_import_vrf={
+ input_import_vrf = {
"r2": {
"bgp": [
{
"local_as": 200,
"vrf": "RED",
- "address_family": {addr_type: {"unicast": {"import": {"vrf": "default"}}}},
+ "address_family": {
+ addr_type: {"unicast": {"import": {"vrf": "default"}}}
+ },
}
]
}
}
- result = create_router_bgp(tgen, topo,input_import_vrf)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
- #done
+ result = create_router_bgp(tgen, topo, input_import_vrf)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ # done
step("verifying static Routes at R2 in VRF RED")
for addr_type in ADDR_TYPES:
- dut = 'r2'
- input_dict_1= {'r2': topo['routers']['r2']}
+ dut = "r2"
+ input_dict_1 = {"r2": topo["routers"]["r2"]}
result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
- assert result is True, \
- "Testcase {} :Failed \n Error {}". \
- format(tc_name, result)
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
step("verifying static Routes at R1 in VRF RED")
for addr_type in ADDR_TYPES:
- dut = 'r1'
- input_dict_1= {'r1': topo['routers']['r1']}
+ dut = "r1"
+ input_dict_1 = {"r1": topo["routers"]["r1"]}
result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
- assert result is True, \
- "Testcase {} :Failed \n Error {}". \
- format(tc_name, result)
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
step("Configuring Graceful restart at R2 and R3 ")
input_dict = {
"r2": {
-
"bgp": {
"local_as": "200",
"graceful-restart": {
"graceful-restart": True,
- }
+ },
}
},
"r3": {
- "bgp": {
- "local_as": "300",
- "graceful-restart": {
- "graceful-restart": True
- }
- }
- }
+ "bgp": {"local_as": "300", "graceful-restart": {"graceful-restart": True}}
+ },
}
- configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name,dut='r2', peer='r3')
-
-
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r2", peer="r3")
step("verify Graceful restart at R2")
for addr_type in ADDR_TYPES:
- result = verify_graceful_restart(tgen, topo, addr_type, input_dict,
- dut='r2', peer='r3')
- assert result is True, \
- "Testcase {} :Failed \n Error {}". \
- format(tc_name, result)
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r2", peer="r3"
+ )
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
step("verify Graceful restart at R3")
for addr_type in ADDR_TYPES:
- result = verify_graceful_restart(tgen, topo, addr_type, input_dict,
- dut='r3', peer='r2')
- assert result is True, \
- "Testcase {} :Failed \n Error {}". \
- format(tc_name, result)
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r3", peer="r2"
+ )
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
step("Configuring Graceful-restart-disable at R3")
input_dict = {
"r2": {
-
"bgp": {
"local_as": "200",
"graceful-restart": {
"graceful-restart": False,
- }
+ },
}
},
"r3": {
- "bgp": {
- "local_as": "300",
- "graceful-restart": {
- "graceful-restart": False
- }
- }
- }
+ "bgp": {"local_as": "300", "graceful-restart": {"graceful-restart": False}}
+ },
}
- configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name,dut='r3', peer='r2')
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r3", peer="r2")
step("Verify Graceful-restart-disable at R3")
for addr_type in ADDR_TYPES:
- result = verify_graceful_restart(tgen, topo, addr_type, input_dict,
- dut='r3', peer='r2')
- assert result is True, \
- "Testcase {} :Failed \n Error {}". \
- format(tc_name, result)
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r3", peer="r2"
+ )
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
for iteration in range(5):
step("graceful-restart-disable:True at R3")
input_dict = {
- "r3": {
- "bgp": {
- "graceful-restart": {
- "graceful-restart-disable": True,
+ "r3": {
+ "bgp": {
+ "graceful-restart": {
+ "graceful-restart-disable": True,
+ }
}
}
- }
}
- configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name,
- dut='r3', peer='r2')
+ configure_gr_followed_by_clear(
+ tgen, topo, input_dict, tc_name, dut="r3", peer="r2"
+ )
step("Verifying Routes at R2 on enabling GRD")
- dut = 'r2'
+ dut = "r2"
for addr_type in ADDR_TYPES:
- input_dict_1= {'r2': topo['routers']['r2']}
+ input_dict_1 = {"r2": topo["routers"]["r2"]}
result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
- assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+ assert result is True, "Testcase {} :Failed \n Error {}".format(
+ tc_name, result
+ )
step("Verify stale Routes in Router R2 enabling GRD")
for addr_type in ADDR_TYPES:
@@ -495,39 +486,45 @@ def test_bgp_gr_stale_routes(request):
verify_nh_for_static_rtes = {
"r3": {
"static_routes": [
-
{
"network": [NETWORK1_1[addr_type]],
"no_of_ip": 2,
- "vrf": "RED"
+ "vrf": "RED",
}
]
}
}
bgp_rib_next_hops = verify_stale_routes_list(
- tgen, addr_type, dut, verify_nh_for_static_rtes)
- assert (len(bgp_rib_next_hops)== 1) is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, bgp_rib_next_hops,expected=True)
+ tgen, addr_type, dut, verify_nh_for_static_rtes
+ )
+ assert (
+ len(bgp_rib_next_hops) == 1
+ ) is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, bgp_rib_next_hops, expected=True
+ )
step("graceful-restart-disable:False at R3")
input_dict = {
- "r3": {
- "bgp": {
- "graceful-restart": {
- "graceful-restart-disable": False,
+ "r3": {
+ "bgp": {
+ "graceful-restart": {
+ "graceful-restart-disable": False,
+ }
}
}
- }
}
- configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name,
- dut='r3', peer='r2')
+ configure_gr_followed_by_clear(
+ tgen, topo, input_dict, tc_name, dut="r3", peer="r2"
+ )
step("Verifying Routes at R2 on disabling GRD")
- dut = 'r2'
+ dut = "r2"
for addr_type in ADDR_TYPES:
- input_dict_1= {'r2': topo['routers']['r2']}
+ input_dict_1 = {"r2": topo["routers"]["r2"]}
result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
- assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+ assert result is True, "Testcase {} :Failed \n Error {}".format(
+ tc_name, result
+ )
step("Verify stale Routes in Router R2 on disabling GRD")
for addr_type in ADDR_TYPES:
@@ -536,19 +533,22 @@ def test_bgp_gr_stale_routes(request):
verify_nh_for_static_rtes = {
"r3": {
"static_routes": [
-
{
"network": [NETWORK1_1[addr_type]],
"no_of_ip": 2,
- "vrf": "RED"
+ "vrf": "RED",
}
]
}
}
- bgp_rib_next_hops = verify_stale_routes_list(tgen, addr_type, dut, verify_nh_for_static_rtes)
-
- stale_route_status=len(bgp_rib_next_hops)== 1
- assert stale_route_status is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, stale_route_status,expected=True)
+ bgp_rib_next_hops = verify_stale_routes_list(
+ tgen, addr_type, dut, verify_nh_for_static_rtes
+ )
+
+ stale_route_status = len(bgp_rib_next_hops) == 1
+ assert (
+ stale_route_status is True
+ ), "Testcase {} : Failed \n Error: {}".format(
+ tc_name, stale_route_status, expected=True
+ )
write_test_footer(tc_name)
-
diff --git a/tests/topotests/bgp_gr_restart_retain_routes/__init__.py b/tests/topotests/bgp_gr_restart_retain_routes/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/bgp_gr_restart_retain_routes/__init__.py
diff --git a/tests/topotests/bgp_gr_restart_retain_routes/r1/bgpd.conf b/tests/topotests/bgp_gr_restart_retain_routes/r1/bgpd.conf
new file mode 100644
index 000000000..50d158387
--- /dev/null
+++ b/tests/topotests/bgp_gr_restart_retain_routes/r1/bgpd.conf
@@ -0,0 +1,11 @@
+router bgp 65001
+ no bgp ebgp-requires-policy
+ bgp graceful-restart
+ bgp graceful-restart preserve-fw-state
+ neighbor 192.168.255.2 remote-as external
+ neighbor 192.168.255.2 timers 1 3
+ neighbor 192.168.255.2 timers connect 1
+ address-family ipv4
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_gr_restart_retain_routes/r1/zebra.conf b/tests/topotests/bgp_gr_restart_retain_routes/r1/zebra.conf
new file mode 100644
index 000000000..e65bfb2c3
--- /dev/null
+++ b/tests/topotests/bgp_gr_restart_retain_routes/r1/zebra.conf
@@ -0,0 +1,7 @@
+!
+interface lo
+ ip address 172.16.255.1/32
+!
+interface r1-eth0
+ ip address 192.168.255.1/24
+!
diff --git a/tests/topotests/bgp_gr_restart_retain_routes/r2/bgpd.conf b/tests/topotests/bgp_gr_restart_retain_routes/r2/bgpd.conf
new file mode 100644
index 000000000..97418ca9a
--- /dev/null
+++ b/tests/topotests/bgp_gr_restart_retain_routes/r2/bgpd.conf
@@ -0,0 +1,8 @@
+router bgp 65002
+ no bgp ebgp-requires-policy
+ bgp graceful-restart
+ bgp graceful-restart preserve-fw-state
+ neighbor 192.168.255.1 remote-as external
+ neighbor 192.168.255.1 timers 1 3
+ neighbor 192.168.255.1 timers connect 1
+!
diff --git a/tests/topotests/bgp_gr_restart_retain_routes/r2/zebra.conf b/tests/topotests/bgp_gr_restart_retain_routes/r2/zebra.conf
new file mode 100644
index 000000000..758d797ad
--- /dev/null
+++ b/tests/topotests/bgp_gr_restart_retain_routes/r2/zebra.conf
@@ -0,0 +1,5 @@
+no zebra nexthop kernel enable
+!
+interface r2-eth0
+ ip address 192.168.255.2/24
+!
diff --git a/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_restart_retain_routes.py b/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_restart_retain_routes.py
new file mode 100644
index 000000000..52ce0d5b5
--- /dev/null
+++ b/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_restart_retain_routes.py
@@ -0,0 +1,131 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2022 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+# 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 routes are retained during BGP restarts.
+"""
+
+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
+from lib.common_config import step, stop_router
+
+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_gr_restart_retain_routes():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+ r2 = tgen.gears["r2"]
+
+ def _bgp_converge():
+ output = json.loads(r2.vtysh_cmd("show bgp ipv4 neighbors 192.168.255.1 json"))
+ expected = {
+ "192.168.255.1": {
+ "bgpState": "Established",
+ "addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 2}},
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ def _bgp_check_bgp_retained_routes():
+ output = json.loads(r2.vtysh_cmd("show bgp ipv4 unicast 172.16.255.1/32 json"))
+ expected = {"paths": [{"stale": True}]}
+ return topotest.json_cmp(output, expected)
+
+ def _bgp_check_kernel_retained_routes():
+ output = (
+ r2.cmd("ip route show 172.16.255.1/32 proto bgp dev r2-eth0")
+ .replace("\n", "")
+ .rstrip()
+ )
+ expected = "172.16.255.1 via 192.168.255.1 metric 20"
+ diff = topotest.get_textdiff(
+ output, expected, "Actual IP Routing Table", "Expected IP RoutingTable"
+ )
+ if diff:
+ return False
+ return True
+
+ step("Initial BGP converge")
+ test_func = functools.partial(_bgp_converge)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Failed to see BGP convergence on R2"
+
+ step("Restart R1")
+ stop_router(tgen, "r1")
+
+ step("Check if routes (BGP) are retained at R2")
+ test_func = functools.partial(_bgp_check_bgp_retained_routes)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Failed to see BGP retained routes on R2"
+
+ step("Check if routes (Kernel) are retained at R2")
+ assert _bgp_check_kernel_retained_routes() == True
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_gshut_topo1/test_ebgp_gshut_topo1.py b/tests/topotests/bgp_gshut_topo1/test_ebgp_gshut_topo1.py
index 58133c44a..684d2fcb5 100644
--- a/tests/topotests/bgp_gshut_topo1/test_ebgp_gshut_topo1.py
+++ b/tests/topotests/bgp_gshut_topo1/test_ebgp_gshut_topo1.py
@@ -92,7 +92,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.16")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >=4.16")
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
diff --git a/tests/topotests/bgp_gshut_topo1/test_ibgp_gshut_topo1.py b/tests/topotests/bgp_gshut_topo1/test_ibgp_gshut_topo1.py
index a79ce0e3a..16572a796 100644
--- a/tests/topotests/bgp_gshut_topo1/test_ibgp_gshut_topo1.py
+++ b/tests/topotests/bgp_gshut_topo1/test_ibgp_gshut_topo1.py
@@ -87,7 +87,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.16")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >=4.16")
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
diff --git a/tests/topotests/bgp_local_as/__init__.py b/tests/topotests/bgp_local_as/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/bgp_local_as/__init__.py
diff --git a/tests/topotests/bgp_local_as/r1/bgpd.conf b/tests/topotests/bgp_local_as/r1/bgpd.conf
new file mode 100644
index 000000000..fa147d867
--- /dev/null
+++ b/tests/topotests/bgp_local_as/r1/bgpd.conf
@@ -0,0 +1,14 @@
+router bgp 65001
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.2 remote-as 65002
+ neighbor 192.168.1.2 local-as 65002
+ neighbor 192.168.1.2 timers 1 3
+ neighbor 192.168.1.2 timers connect 1
+ neighbor PG peer-group
+ neighbor PG remote-as 65003
+ neighbor PG local-as 65003
+ neighbor 192.168.2.2 peer-group PG
+ address-family ipv4
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_local_as/r1/zebra.conf b/tests/topotests/bgp_local_as/r1/zebra.conf
new file mode 100644
index 000000000..5b32faeb4
--- /dev/null
+++ b/tests/topotests/bgp_local_as/r1/zebra.conf
@@ -0,0 +1,10 @@
+!
+interface lo
+ ip address 172.16.255.1/32
+!
+interface r1-eth0
+ ip address 192.168.1.1/24
+!
+interface r1-eth1
+ ip address 192.168.2.1/24
+!
diff --git a/tests/topotests/bgp_local_as/r2/bgpd.conf b/tests/topotests/bgp_local_as/r2/bgpd.conf
new file mode 100644
index 000000000..9c25bdfdd
--- /dev/null
+++ b/tests/topotests/bgp_local_as/r2/bgpd.conf
@@ -0,0 +1,6 @@
+router bgp 65002
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.1 remote-as internal
+ neighbor 192.168.1.1 timers 1 3
+ neighbor 192.168.1.1 timers connect 1
+!
diff --git a/tests/topotests/bgp_local_as/r2/zebra.conf b/tests/topotests/bgp_local_as/r2/zebra.conf
new file mode 100644
index 000000000..0c9565666
--- /dev/null
+++ b/tests/topotests/bgp_local_as/r2/zebra.conf
@@ -0,0 +1,4 @@
+!
+interface r2-eth0
+ ip address 192.168.1.2/24
+!
diff --git a/tests/topotests/bgp_local_as/r3/bgpd.conf b/tests/topotests/bgp_local_as/r3/bgpd.conf
new file mode 100644
index 000000000..54ccd90f3
--- /dev/null
+++ b/tests/topotests/bgp_local_as/r3/bgpd.conf
@@ -0,0 +1,6 @@
+router bgp 65003
+ no bgp ebgp-requires-policy
+ neighbor 192.168.2.1 remote-as internal
+ neighbor 192.168.2.1 timers 1 3
+ neighbor 192.168.2.1 timers connect 1
+!
diff --git a/tests/topotests/bgp_local_as/r3/zebra.conf b/tests/topotests/bgp_local_as/r3/zebra.conf
new file mode 100644
index 000000000..d28deddfc
--- /dev/null
+++ b/tests/topotests/bgp_local_as/r3/zebra.conf
@@ -0,0 +1,4 @@
+!
+interface r3-eth0
+ ip address 192.168.2.2/24
+!
diff --git a/tests/topotests/bgp_local_as/test_bgp_local_as.py b/tests/topotests/bgp_local_as/test_bgp_local_as.py
new file mode 100644
index 000000000..525d44220
--- /dev/null
+++ b/tests/topotests/bgp_local_as/test_bgp_local_as.py
@@ -0,0 +1,134 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2022 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+# 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.
+#
+
+"""
+
+"""
+
+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
+from lib.common_config import step
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ for routern in range(1, 4):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r3"])
+
+
+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_local_as_same_remote_as():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ def _bgp_check_local_as_same_remote_as():
+ output = json.loads(
+ tgen.gears["r2"].vtysh_cmd("show bgp ipv4 unicast 172.16.255.1/32 json")
+ )
+ expected = {
+ "paths": [
+ {
+ "valid": True,
+ "aspath": {"string": "Local"},
+ "nexthops": [{"ip": "192.168.1.1", "hostname": "r1"}],
+ }
+ ]
+ }
+ return topotest.json_cmp(output, expected)
+
+ step("Check if iBGP works when local-as == remote-as")
+ test_func = functools.partial(_bgp_check_local_as_same_remote_as)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Failed to see BGP prefixes on R2"
+
+
+def test_bgp_peer_group_local_as_same_remote_as():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ def _bgp_check_local_as_same_remote_as():
+ output = json.loads(
+ tgen.gears["r3"].vtysh_cmd("show bgp ipv4 unicast 172.16.255.1/32 json")
+ )
+ expected = {
+ "paths": [
+ {
+ "valid": True,
+ "aspath": {"string": "Local"},
+ "nexthops": [{"ip": "192.168.2.1", "hostname": "r1"}],
+ }
+ ]
+ }
+ return topotest.json_cmp(output, expected)
+
+ step("Initial BGP converge")
+ test_func = functools.partial(_bgp_check_local_as_same_remote_as)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Failed to see BGP prefixes on R3"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_max_med_on_startup/__init__.py b/tests/topotests/bgp_max_med_on_startup/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/bgp_max_med_on_startup/__init__.py
diff --git a/tests/topotests/bgp_max_med_on_startup/r1/bgpd.conf b/tests/topotests/bgp_max_med_on_startup/r1/bgpd.conf
new file mode 100644
index 000000000..41bf96344
--- /dev/null
+++ b/tests/topotests/bgp_max_med_on_startup/r1/bgpd.conf
@@ -0,0 +1,11 @@
+!
+router bgp 65001
+ bgp max-med on-startup 5 777
+ no bgp ebgp-requires-policy
+ neighbor 192.168.255.2 remote-as 65001
+ neighbor 192.168.255.2 timers 3 10
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+ !
+!
diff --git a/tests/topotests/bgp_max_med_on_startup/r1/zebra.conf b/tests/topotests/bgp_max_med_on_startup/r1/zebra.conf
new file mode 100644
index 000000000..7c2ed09b8
--- /dev/null
+++ b/tests/topotests/bgp_max_med_on_startup/r1/zebra.conf
@@ -0,0 +1,9 @@
+!
+interface lo
+ ip address 172.16.255.254/32
+!
+interface r1-eth0
+ ip address 192.168.255.1/30
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_max_med_on_startup/r2/bgpd.conf b/tests/topotests/bgp_max_med_on_startup/r2/bgpd.conf
new file mode 100644
index 000000000..187713d08
--- /dev/null
+++ b/tests/topotests/bgp_max_med_on_startup/r2/bgpd.conf
@@ -0,0 +1,7 @@
+!
+router bgp 65001
+ no bgp ebgp-requires-policy
+ neighbor 192.168.255.1 remote-as 65001
+ neighbor 192.168.255.1 timers 3 10
+ !
+!
diff --git a/tests/topotests/bgp_max_med_on_startup/r2/zebra.conf b/tests/topotests/bgp_max_med_on_startup/r2/zebra.conf
new file mode 100644
index 000000000..fd45c48d6
--- /dev/null
+++ b/tests/topotests/bgp_max_med_on_startup/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_max_med_on_startup/test_bgp_max_med_on_startup.py b/tests/topotests/bgp_max_med_on_startup/test_bgp_max_med_on_startup.py
new file mode 100644
index 000000000..a83d43310
--- /dev/null
+++ b/tests/topotests/bgp_max_med_on_startup/test_bgp_max_med_on_startup.py
@@ -0,0 +1,114 @@
+#!/usr/bin/env python
+
+#
+# test_bgp_max_med_on_startup.py
+#
+# Copyright (c) 2022 Rubicon Communications, LLC.
+#
+# 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 whether `bgp max-med on-startup (5-86400) [(0-4294967295)]` is working
+correctly.
+"""
+
+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_max_med_on_startup():
+ 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):
+ output = json.loads(
+ router.vtysh_cmd("show ip bgp neighbor 192.168.255.1 routes json")
+ )
+ expected = {"routes": {"172.16.255.254/32": [{"metric": metric}]}}
+ return topotest.json_cmp(output, expected)
+
+ # Check 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 metric has value of max-med
+ test_func = functools.partial(_bgp_has_routes, router2, 777)
+ 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 777"
+
+ # Check that when the max-med timer expires, metric is updated
+ test_func = functools.partial(_bgp_has_routes, router2, 0)
+ success, result = topotest.run_and_expect(test_func, None, count=16, wait=0.5)
+ assert result is None, "r2 does not receive routes with metric 0"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_prefix_list_topo1/test_prefix_lists.py b/tests/topotests/bgp_prefix_list_topo1/test_prefix_lists.py
index 2dc95cee2..5131a89ce 100644
--- a/tests/topotests/bgp_prefix_list_topo1/test_prefix_lists.py
+++ b/tests/topotests/bgp_prefix_list_topo1/test_prefix_lists.py
@@ -346,9 +346,12 @@ def test_ip_prefix_lists_out_permit(request):
result = verify_rib(
tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n Error: Routes still" " present in RIB".format(tc_name)
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
+ )
+
write_test_footer(tc_name)
@@ -444,9 +447,11 @@ def test_ip_prefix_lists_in_deny_and_permit_any(request):
result = verify_rib(
tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n Error: Routes still" " present in RIB".format(tc_name)
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
+ )
write_test_footer(tc_name)
@@ -644,9 +649,12 @@ def test_ip_prefix_lists_out_deny_and_permit_any(request):
result = verify_rib(
tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n Error: Routes still" " present in RIB".format(tc_name)
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
+ )
+
write_test_footer(tc_name)
@@ -778,9 +786,11 @@ def test_modify_prefix_lists_in_permit_to_deny(request):
result = verify_rib(
tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n Error: Routes still" " present in RIB".format(tc_name)
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
+ )
write_test_footer(tc_name)
@@ -882,9 +892,11 @@ def test_modify_prefix_lists_in_deny_to_permit(request):
result = verify_rib(
tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n Error: Routes still" " present in RIB".format(tc_name)
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
+ )
# Modify ip prefix list
input_dict_1 = {
@@ -1051,9 +1063,11 @@ def test_modify_prefix_lists_out_permit_to_deny(request):
result = verify_rib(
tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n Error: Routes still" " present in RIB".format(tc_name)
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
+ )
write_test_footer(tc_name)
@@ -1157,9 +1171,11 @@ def test_modify_prefix_lists_out_deny_to_permit(request):
result = verify_rib(
tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n Error: Routes still" " present in RIB".format(tc_name)
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
+ )
# Modify ip prefix list
input_dict_1 = {
@@ -1324,9 +1340,11 @@ def test_ip_prefix_lists_implicit_deny(request):
result = verify_rib(
tgen, "ipv4", dut, input_dict_1, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n Error: Routes still" " present in RIB".format(tc_name)
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
+ )
write_test_footer(tc_name)
diff --git a/tests/topotests/bgp_route_map/test_route_map_topo1.py b/tests/topotests/bgp_route_map/test_route_map_topo1.py
index 655a3dc89..77bddbe33 100644
--- a/tests/topotests/bgp_route_map/test_route_map_topo1.py
+++ b/tests/topotests/bgp_route_map/test_route_map_topo1.py
@@ -444,12 +444,11 @@ def test_route_map_inbound_outbound_same_neighbor_p0(request):
result = verify_rib(
tgen, adt, dut, input_dict_2, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \nroutes are not present in rib \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info("Expected behaviour: {}".format(result))
# Verifying RIB routes
dut = "r4"
@@ -467,12 +466,11 @@ def test_route_map_inbound_outbound_same_neighbor_p0(request):
result = verify_rib(
tgen, adt, dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \nroutes are not present in rib \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info("Expected behaviour: {}".format(result))
write_test_footer(tc_name)
@@ -666,12 +664,11 @@ def test_route_map_with_action_values_combination_of_prefix_action_p0(
result = verify_rib(
tgen, adt, dut, input_dict_2, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \nRoutes are still present \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info("Expected behaviour: {}".format(result))
else:
result = verify_rib(tgen, adt, dut, input_dict_2, protocol=protocol)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
diff --git a/tests/topotests/bgp_route_map/test_route_map_topo2.py b/tests/topotests/bgp_route_map/test_route_map_topo2.py
index 4da7eeb2f..589482d6a 100644
--- a/tests/topotests/bgp_route_map/test_route_map_topo2.py
+++ b/tests/topotests/bgp_route_map/test_route_map_topo2.py
@@ -1022,12 +1022,11 @@ def test_modify_prefix_list_referenced_by_rmap_p0():
result = verify_rib(
tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \nroutes are not present \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info("Expected behaviour: {}".format(result))
# Verifying RIB routes
dut = "r4"
@@ -1036,10 +1035,10 @@ def test_modify_prefix_list_referenced_by_rmap_p0():
result = verify_rib(
tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \nExpected behaviour: routes are not present \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
write_test_footer(tc_name)
@@ -1293,12 +1292,11 @@ def test_remove_prefix_list_referenced_by_rmap_p0():
result = verify_rib(
tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \nroutes are not present \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info("Expected behaviour: {}".format(result))
# Verifying RIB routes
dut = "r4"
@@ -1307,12 +1305,11 @@ def test_remove_prefix_list_referenced_by_rmap_p0():
result = verify_rib(
tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \nroutes are not present \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info("Expected behaviour: {}".format(result))
write_test_footer(tc_name)
@@ -2139,12 +2136,11 @@ def test_add_remove_rmap_to_specific_neighbor_p0():
result = verify_rib(
tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n Error Routes are still present: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info("Expected behaviour: {}".format(result))
# Remove applied rmap from neighbor
input_dict_4 = {
@@ -2553,12 +2549,11 @@ def test_rmap_without_match_and_set_clause_p0():
result = verify_rib(
tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \nroutes are not present \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info("Expected behaviour: {}".format(result))
write_test_footer(tc_name)
# Uncomment next line for debugging
@@ -2801,12 +2796,11 @@ def test_set_localpref_weight_to_ebgp_and_med_to_ibgp_peers_p0():
input_dict_3_addr_type[addr_type],
expected=False,
)
- assert (
- result is not True
- ), "Testcase {} : Failed \nAttributes are not set \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: BGP attributes should not be set in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info("Expected behaviour: {}".format(result))
# Verifying RIB routes
dut = "r5"
@@ -2835,12 +2829,11 @@ def test_set_localpref_weight_to_ebgp_and_med_to_ibgp_peers_p0():
input_dict_3_addr_type[addr_type],
expected=False,
)
- assert (
- result is not True
- ), "Testcase {} : Failed \nAttributes are not set \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: BGP attributes should not be set in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info("Expected behaviour: {}".format(result))
write_test_footer(tc_name)
@@ -3644,12 +3637,11 @@ def test_create_rmap_match_prefix_list_to_deny_in_and_outbound_prefixes_p0():
result = verify_rib(
tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \nroutes are not present \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info("Expected behaviour: {}".format(result))
# Verifying RIB routes
dut = "r4"
@@ -3658,12 +3650,11 @@ def test_create_rmap_match_prefix_list_to_deny_in_and_outbound_prefixes_p0():
result = verify_rib(
tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \nroutes are not present \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info("Expected behaviour: {}".format(result))
write_test_footer(tc_name)
@@ -3963,12 +3954,11 @@ def test_create_rmap_to_match_tag_deny_outbound_prefixes_p0():
result = verify_rib(
tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \nroutes are denied \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info("Expected behaviour: {}".format(result))
write_test_footer(tc_name)
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/zebra.conf
index 8defa0125..8ccf7a2a3 100644
--- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/zebra.conf
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/zebra.conf
@@ -27,7 +27,7 @@ segment-routing
srv6
locators
locator loc1
- prefix 2001:db8:1:1::/64
+ prefix 2001:db8:1:1::/64 func-bits 8
!
!
!
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/zebra.conf
index 51d9c9223..839454d8a 100644
--- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/zebra.conf
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/zebra.conf
@@ -27,7 +27,7 @@ segment-routing
srv6
locators
locator loc1
- prefix 2001:db8:2:2::/64
+ prefix 2001:db8:2:2::/64 func-bits 8
!
!
!
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/zebra.conf
index a43cec20e..a9319a6ae 100644
--- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/zebra.conf
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/zebra.conf
@@ -28,7 +28,7 @@ segment-routing
srv6
locators
locator loc1
- prefix 2001:db8:1:1::/64
+ prefix 2001:db8:1:1::/64 func-bits 8
!
!
!
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/zebra.conf
index 71ddedf6f..9e5fa0ac0 100644
--- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/zebra.conf
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/zebra.conf
@@ -27,7 +27,7 @@ segment-routing
srv6
locators
locator loc1
- prefix 2001:db8:2:2::/64
+ prefix 2001:db8:2:2::/64 func-bits 8
!
!
!
diff --git a/tests/topotests/isis_topo1/test_isis_topo1.py b/tests/topotests/isis_topo1/test_isis_topo1.py
index 014722387..8b6c3772b 100644
--- a/tests/topotests/isis_topo1/test_isis_topo1.py
+++ b/tests/topotests/isis_topo1/test_isis_topo1.py
@@ -25,7 +25,7 @@
"""
test_isis_topo1.py: Test ISIS topology.
"""
-
+import datetime
import functools
import json
import os
@@ -38,6 +38,11 @@ sys.path.append(os.path.join(CWD, "../"))
# pylint: disable=C0413
from lib import topotest
+from lib.common_config import (
+ retry,
+ stop_router,
+ start_router,
+)
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.topolog import logger
@@ -248,10 +253,12 @@ def test_isis_summary_json():
for rname, router in tgen.routers().items():
logger.info("Checking router %s", rname)
json_output = tgen.gears[rname].vtysh_cmd("show isis summary json", isjson=True)
- assertmsg = "Test isis summary json failed in '{}' data '{}'".format(rname, json_output)
- assert json_output['vrf'] == "default", assertmsg
- assert json_output['areas'][0]['area'] == "1", assertmsg
- assert json_output['areas'][0]['levels'][0]['id'] != '3', assertmsg
+ assertmsg = "Test isis summary json failed in '{}' data '{}'".format(
+ rname, json_output
+ )
+ assert json_output["vrf"] == "default", assertmsg
+ assert json_output["areas"][0]["area"] == "1", assertmsg
+ assert json_output["areas"][0]["levels"][0]["id"] != "3", assertmsg
def test_isis_interface_json():
@@ -265,15 +272,29 @@ def test_isis_interface_json():
logger.info("Checking 'show isis interface json'")
for rname, router in tgen.routers().items():
logger.info("Checking router %s", rname)
- json_output = tgen.gears[rname].vtysh_cmd("show isis interface json", isjson=True)
- assertmsg = "Test isis interface json failed in '{}' data '{}'".format(rname, json_output)
- assert json_output['areas'][0]['circuits'][0]['interface']['name'] == rname+"-eth0", assertmsg
+ json_output = tgen.gears[rname].vtysh_cmd(
+ "show isis interface json", isjson=True
+ )
+ assertmsg = "Test isis interface json failed in '{}' data '{}'".format(
+ rname, json_output
+ )
+ assert (
+ json_output["areas"][0]["circuits"][0]["interface"]["name"]
+ == rname + "-eth0"
+ ), assertmsg
for rname, router in tgen.routers().items():
logger.info("Checking router %s", rname)
- json_output = tgen.gears[rname].vtysh_cmd("show isis interface detail json", isjson=True)
- assertmsg = "Test isis interface json failed in '{}' data '{}'".format(rname, json_output)
- assert json_output['areas'][0]['circuits'][0]['interface']['name'] == rname+"-eth0", assertmsg
+ json_output = tgen.gears[rname].vtysh_cmd(
+ "show isis interface detail json", isjson=True
+ )
+ assertmsg = "Test isis interface json failed in '{}' data '{}'".format(
+ rname, json_output
+ )
+ assert (
+ json_output["areas"][0]["circuits"][0]["interface"]["name"]
+ == rname + "-eth0"
+ ), assertmsg
def test_isis_neighbor_json():
@@ -284,19 +305,32 @@ def test_isis_neighbor_json():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- #tgen.mininet_cli()
+ # tgen.mininet_cli()
logger.info("Checking 'show isis neighbor json'")
for rname, router in tgen.routers().items():
logger.info("Checking router %s", rname)
- json_output = tgen.gears[rname].vtysh_cmd("show isis neighbor json", isjson=True)
- assertmsg = "Test isis neighbor json failed in '{}' data '{}'".format(rname, json_output)
- assert json_output['areas'][0]['circuits'][0]['interface'] == rname+"-eth0", assertmsg
+ json_output = tgen.gears[rname].vtysh_cmd(
+ "show isis neighbor json", isjson=True
+ )
+ assertmsg = "Test isis neighbor json failed in '{}' data '{}'".format(
+ rname, json_output
+ )
+ assert (
+ json_output["areas"][0]["circuits"][0]["interface"] == rname + "-eth0"
+ ), assertmsg
for rname, router in tgen.routers().items():
logger.info("Checking router %s", rname)
- json_output = tgen.gears[rname].vtysh_cmd("show isis neighbor detail json", isjson=True)
- assertmsg = "Test isis neighbor json failed in '{}' data '{}'".format(rname, json_output)
- assert json_output['areas'][0]['circuits'][0]['interface']['name'] == rname+"-eth0", assertmsg
+ json_output = tgen.gears[rname].vtysh_cmd(
+ "show isis neighbor detail json", isjson=True
+ )
+ assertmsg = "Test isis neighbor json failed in '{}' data '{}'".format(
+ rname, json_output
+ )
+ assert (
+ json_output["areas"][0]["circuits"][0]["interface"]["name"]
+ == rname + "-eth0"
+ ), assertmsg
def test_isis_database_json():
@@ -307,21 +341,246 @@ def test_isis_database_json():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- #tgen.mininet_cli()
+ # tgen.mininet_cli()
logger.info("Checking 'show isis database json'")
for rname, router in tgen.routers().items():
logger.info("Checking router %s", rname)
- json_output = tgen.gears[rname].vtysh_cmd("show isis database json", isjson=True)
- assertmsg = "Test isis database json failed in '{}' data '{}'".format(rname, json_output)
- assert json_output['areas'][0]['area']['name'] == "1", assertmsg
- assert json_output['areas'][0]['levels'][0]['id'] != '3', assertmsg
+ json_output = tgen.gears[rname].vtysh_cmd(
+ "show isis database json", isjson=True
+ )
+ assertmsg = "Test isis database json failed in '{}' data '{}'".format(
+ rname, json_output
+ )
+ assert json_output["areas"][0]["area"]["name"] == "1", assertmsg
+ assert json_output["areas"][0]["levels"][0]["id"] != "3", assertmsg
for rname, router in tgen.routers().items():
logger.info("Checking router %s", rname)
- json_output = tgen.gears[rname].vtysh_cmd("show isis database detail json", isjson=True)
- assertmsg = "Test isis database json failed in '{}' data '{}'".format(rname, json_output)
- assert json_output['areas'][0]['area']['name'] == "1", assertmsg
- assert json_output['areas'][0]['levels'][0]['id'] != '3', assertmsg
+ json_output = tgen.gears[rname].vtysh_cmd(
+ "show isis database detail json", isjson=True
+ )
+ assertmsg = "Test isis database json failed in '{}' data '{}'".format(
+ rname, json_output
+ )
+ assert json_output["areas"][0]["area"]["name"] == "1", assertmsg
+ assert json_output["areas"][0]["levels"][0]["id"] != "3", assertmsg
+
+
+def test_isis_overload_on_startup():
+ "Check that overload on startup behaves as expected"
+
+ tgen = get_topogen()
+ net = get_topogen().net
+ overload_time = 120
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Testing overload on startup behavior")
+
+ # Configure set-overload-bit on-startup on r3
+ r3 = tgen.gears["r3"]
+ r3.vtysh_cmd(
+ f"""
+ configure
+ router isis 1
+ set-overload-bit on-startup {overload_time}
+ """
+ )
+ # Restart r3
+ logger.info("Stop router")
+ stop_router(tgen, "r3")
+ logger.info("Start router")
+
+ tstamp_before_start_router = datetime.datetime.now()
+ start_router(tgen, "r3")
+ tstamp_after_start_router = datetime.datetime.now()
+ startup_router_time = (
+ tstamp_after_start_router - tstamp_before_start_router
+ ).total_seconds()
+
+ # Check that the overload bit is set in r3's LSP
+ check_lsp_overload_bit("r3", "r3.00-00", "0/0/1")
+ check_lsp_overload_bit("r1", "r3.00-00", "0/0/1")
+
+ # Attempt to unset overload bit while timer is still running
+ r3.vtysh_cmd(
+ """
+ configure
+ router isis 1
+ no set-overload-bit on-startup
+ no set-overload-bit
+ """
+ )
+
+ # Check overload bit is still set
+ check_lsp_overload_bit("r1", "r3.00-00", "0/0/1")
+
+ # Check that overload bit is unset after timer completes
+ check_lsp_overload_bit("r3", "r3.00-00", "0/0/0")
+ tstamp_after_bit_unset = datetime.datetime.now()
+ check_lsp_overload_bit("r1", "r3.00-00", "0/0/0")
+
+ # Collect time overloaded
+ time_overloaded = (
+ tstamp_after_bit_unset - tstamp_after_start_router
+ ).total_seconds()
+ logger.info(f"Time Overloaded: {time_overloaded}")
+
+ # Use time it took to startup router as lower bound
+ logger.info(
+ f"Assert that overload time falls in range: {overload_time - startup_router_time} < {time_overloaded} <= {overload_time}"
+ )
+ result = overload_time - startup_router_time < time_overloaded <= overload_time
+ assert result
+
+
+def test_isis_overload_on_startup_cancel_timer():
+ "Check that overload on startup timer is cancelled when overload bit is set/unset"
+
+ tgen = get_topogen()
+ net = get_topogen().net
+ overload_time = 90
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info(
+ "Testing overload on startup behavior with set overload bit: cancel timer"
+ )
+
+ # Configure set-overload-bit on-startup on r3
+ r3 = tgen.gears["r3"]
+ r3.vtysh_cmd(
+ f"""
+ configure
+ router isis 1
+ set-overload-bit on-startup {overload_time}
+ set-overload-bit
+ """
+ )
+ # Restart r3
+ logger.info("Stop router")
+ stop_router(tgen, "r3")
+ logger.info("Start router")
+ start_router(tgen, "r3")
+
+ # Check that the overload bit is set in r3's LSP
+ check_lsp_overload_bit("r3", "r3.00-00", "0/0/1")
+
+ # Check that overload timer is running
+ check_overload_timer("r3", True)
+
+ # Unset overload bit while timer is running
+ r3.vtysh_cmd(
+ """
+ configure
+ router isis 1
+ no set-overload-bit
+ """
+ )
+
+ # Check that overload timer is cancelled
+ check_overload_timer("r3", False)
+
+ # Check overload bit is unset
+ check_lsp_overload_bit("r3", "r3.00-00", "0/0/0")
+
+
+def test_isis_overload_on_startup_override_timer():
+ "Check that overload bit remains set after overload timer expires if overload bit is configured"
+
+ tgen = get_topogen()
+ net = get_topogen().net
+ overload_time = 60
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info(
+ "Testing overload on startup behavior with set overload bit: override timer"
+ )
+
+ # Configure set-overload-bit on-startup on r3
+ r3 = tgen.gears["r3"]
+ r3.vtysh_cmd(
+ f"""
+ configure
+ router isis 1
+ set-overload-bit on-startup {overload_time}
+ set-overload-bit
+ """
+ )
+ # Restart r3
+ logger.info("Stop router")
+ stop_router(tgen, "r3")
+ logger.info("Start router")
+ start_router(tgen, "r3")
+
+ # Check that the overload bit is set in r3's LSP
+ check_lsp_overload_bit("r3", "r3.00-00", "0/0/1")
+
+ # Check that overload timer is running
+ check_overload_timer("r3", True)
+
+ # Check that overload timer expired
+ check_overload_timer("r3", False)
+
+ # Check overload bit is still set
+ check_lsp_overload_bit("r3", "r3.00-00", "0/0/1")
+
+
+@retry(retry_timeout=200)
+def _check_lsp_overload_bit(router, overloaded_router_lsp, att_p_ol_expected):
+ "Verfiy overload bit in router's LSP"
+
+ tgen = get_topogen()
+ router = tgen.gears[router]
+ logger.info(f"check_overload_bit {router}")
+ isis_database_output = router.vtysh_cmd(
+ "show isis database {} json".format(overloaded_router_lsp)
+ )
+
+ database_json = json.loads(isis_database_output)
+ att_p_ol = database_json["areas"][0]["levels"][1]["att-p-ol"]
+ if att_p_ol == att_p_ol_expected:
+ return True
+ return "{} peer with expected att_p_ol {} got {} ".format(
+ router.name, att_p_ol_expected, att_p_ol
+ )
+
+
+def check_lsp_overload_bit(router, overloaded_router_lsp, att_p_ol_expected):
+ "Verfiy overload bit in router's LSP"
+
+ assertmsg = _check_lsp_overload_bit(
+ router, overloaded_router_lsp, att_p_ol_expected
+ )
+ assert assertmsg is True, assertmsg
+
+
+@retry(retry_timeout=200)
+def _check_overload_timer(router, timer_expected):
+ "Verfiy overload bit in router's LSP"
+
+ tgen = get_topogen()
+ router = tgen.gears[router]
+ thread_output = router.vtysh_cmd("show thread timers")
+
+ timer_running = "set_overload_on_start_timer" in thread_output
+ if timer_running == timer_expected:
+ return True
+ return "Expected timer running status: {}".format(timer_expected)
+
+
+def check_overload_timer(router, timer_expected):
+ "Verfiy overload bit in router's LSP"
+
+ assertmsg = _check_overload_timer(router, timer_expected)
+ assert assertmsg is True, assertmsg
def test_memory_leak():
diff --git a/tools/frr-reload.py b/tools/frr-reload.py
index 32f9a7884..7c5d91d4d 100755
--- a/tools/frr-reload.py
+++ b/tools/frr-reload.py
@@ -890,7 +890,7 @@ def bgp_remove_neighbor_cfg(lines_to_del, del_nbr_dict):
):
if ctx_keys[0] in del_nbr_dict:
for nbr in del_nbr_dict[ctx_keys[0]]:
- re_nbr_pg = re.search('neighbor (\S+) .*peer-group (\S+)', line)
+ re_nbr_pg = re.search("neighbor (\S+) .*peer-group (\S+)", line)
nb_exp = "neighbor %s .*" % nbr
if not re_nbr_pg:
re_nb = re.search(nb_exp, line)
@@ -997,7 +997,7 @@ def delete_move_lines(lines_to_add, lines_to_del):
# 'no neighbor peer [interface] peer-group <>' is in lines_to_del
# copy the neighbor and look for all config removal lines associated
# to neighbor and delete them from the lines_to_del
- re_nbr_pg = re.search('neighbor (\S+) .*peer-group (\S+)', line)
+ re_nbr_pg = re.search("neighbor (\S+) .*peer-group (\S+)", line)
if re_nbr_pg:
if ctx_keys[0] not in del_nbr_dict:
del_nbr_dict[ctx_keys[0]] = list()
@@ -1376,6 +1376,37 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
lines_to_add.append((add_cmd, None))
lines_to_del_to_del.append((ctx_keys, None))
+ # bgp community-list, large-community-list, extcommunity-list can be
+ # specified without a seq number. However, the running config always
+ # adds `seq X` (sequence number). So, ignore such lines as well.
+ # Examples:
+ # bgp community-list standard clist seq 5 permit 222:213
+ # bgp large-community-list standard llist seq 5 permit 65001:65001:1
+ # bgp extcommunity-list standard elist seq 5 permit soo 123:123
+ re_bgp_lists = re.search(
+ "^(bgp )(community-list|large-community-list|extcommunity-list)(\s+\S+\s+)(\S+\s+)(seq \d+\s+)(permit|deny)(.*)$",
+ ctx_keys[0],
+ )
+ if re_bgp_lists:
+ found = False
+ tmpline = (
+ re_bgp_lists.group(1)
+ + re_bgp_lists.group(2)
+ + re_bgp_lists.group(3)
+ + re_bgp_lists.group(4)
+ + re_bgp_lists.group(6)
+ + re_bgp_lists.group(7)
+ )
+ for ctx in lines_to_add:
+ if ctx[0][0] == tmpline:
+ lines_to_del_to_del.append((ctx_keys, None))
+ lines_to_add_to_del.append(((tmpline,), None))
+ found = True
+ if found is False:
+ add_cmd = ("no " + ctx_keys[0],)
+ lines_to_add.append((add_cmd, None))
+ lines_to_del_to_del.append((ctx_keys, None))
+
if (
len(ctx_keys) == 3
and ctx_keys[0].startswith("router bgp")
diff --git a/tools/frr.in b/tools/frr.in
index 27b2c0ab8..f0c665fde 100755
--- a/tools/frr.in
+++ b/tools/frr.in
@@ -53,13 +53,6 @@ vtyfile()
echo "$V_PATH/$1.vty"
}
-chownfrr()
-{
- test -n "$FRR_USER" && chown "$FRR_USER" "$1"
- test -n "$FRR_GROUP" && chgrp "$FRR_GROUP" "$1"
- test -n "$FRR_CONFIG_MODE" && chmod "$FRR_CONFIG_MODE" "$1"
-}
-
# Check if daemon is started by using the pidfile.
started()
{
@@ -103,12 +96,10 @@ check_daemon()
# check for config file
if [ -n "$2" ]; then
if [ ! -r "$C_PATH/$1-$2.conf" ]; then
- touch "$C_PATH/$1-$2.conf"
- chownfrr "$C_PATH/$1-$2.conf"
+ install -g "$FRR_GROUP" -o "$FRR_USER" -m "$FRR_CONFIG_MODE" /dev/null "$C_PATH/$1-$2.conf"
fi
elif [ ! -r "$C_PATH/$1.conf" ]; then
- touch "$C_PATH/$1.conf"
- chownfrr "$C_PATH/$1.conf"
+ install -g "$FRR_GROUP" -o "$FRR_USER" -m "$FRR_CONFIG_MODE" /dev/null "$C_PATH/$1.conf"
fi
fi
return 0
@@ -533,9 +524,8 @@ convert_daemon_prios
if [ ! -d $V_PATH ]; then
echo "Creating $V_PATH"
- mkdir -p $V_PATH
- chownfrr $V_PATH
- chmod 755 /$V_PATH
+ install -g "$FRR_GROUP" -o "$FRR_USER" -m "$FRR_CONFIG_MODE" -d /proc "$V_PATH"
+ chmod gu+x "${V_PATH}"
fi
if [ -n "$3" ] && [ "$3" != "all" ]; then
diff --git a/tools/frrcommon.sh.in b/tools/frrcommon.sh.in
index b589ced96..469b9c5d8 100755
--- a/tools/frrcommon.sh.in
+++ b/tools/frrcommon.sh.in
@@ -62,15 +62,6 @@ debug() {
printf '\n' >&2
}
-chownfrr() {
- [ -n "$FRR_USER" ] && chown "$FRR_USER" "$1"
- [ -n "$FRR_GROUP" ] && chgrp "$FRR_GROUP" "$1"
- [ -n "$FRR_CONFIG_MODE" ] && chmod "$FRR_CONFIG_MODE" "$1"
- if [ -d "$1" ]; then
- chmod gu+x "$1"
- fi
-}
-
vtysh_b () {
[ "$1" = "watchfrr" ] && return 0
if [ ! -r "$C_PATH/frr.conf" ]; then
@@ -152,8 +143,7 @@ daemon_prep() {
cfg="$C_PATH/$daemon${inst:+-$inst}.conf"
if [ ! -r "$cfg" ]; then
- touch "$cfg"
- chownfrr "$cfg"
+ install -g "$FRR_GROUP" -o "$FRR_USER" -m "$FRR_CONFIG_MODE" /dev/null "$cfg"
fi
return 0
}
@@ -171,8 +161,8 @@ daemon_start() {
[ "$MAX_FDS" != "" ] && ulimit -n "$MAX_FDS" > /dev/null 2> /dev/null
daemon_prep "$daemon" "$inst" || return 1
if test ! -d "$V_PATH"; then
- mkdir -p "$V_PATH"
- chownfrr "$V_PATH"
+ install -g "$FRR_GROUP" -o "$FRR_USER" -m "$FRR_CONFIG_MODE" -d /proc "$V_PATH"
+ chmod gu+x "${V_PATH}"
fi
eval wrap="\$${daemon}_wrap"
diff --git a/vrrpd/vrrp_vty.c b/vrrpd/vrrp_vty.c
index 35b81dfd8..aea7d9abc 100644
--- a/vrrpd/vrrp_vty.c
+++ b/vrrpd/vrrp_vty.c
@@ -710,6 +710,8 @@ DEFUN_NOSH (show_debugging_vrrp,
vrrp_debug_status_write(vty);
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
diff --git a/watchfrr/watchfrr_vty.c b/watchfrr/watchfrr_vty.c
index 1492ee37b..e5cc43754 100644
--- a/watchfrr/watchfrr_vty.c
+++ b/watchfrr/watchfrr_vty.c
@@ -125,6 +125,8 @@ DEFUN_NOSH (show_debugging_watchfrr,
DEBUG_STR
WATCHFRR_STR)
{
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang
index 0812c86fa..380fce385 100644
--- a/yang/frr-isisd.yang
+++ b/yang/frr-isisd.yang
@@ -1066,11 +1066,25 @@ module frr-isisd {
"If true, identify as L1/L2 router for inter-area traffic.";
}
- leaf overload {
- type boolean;
- default "false";
+ container overload {
description
- "If true, avoid any transit traffic.";
+ "Overload bit configuration.";
+ leaf enabled {
+ type boolean;
+ default "false";
+ description
+ "If true, avoid any transit traffic.";
+ }
+
+ leaf on-startup {
+ type uint32 {
+ range "0..86400";
+ }
+ units "seconds";
+ default "0";
+ description
+ "The duration the overload bit should be set on startup.";
+ }
}
leaf metric-style {
diff --git a/zebra/debug.c b/zebra/debug.c
index 69aaed33a..25102145d 100644
--- a/zebra/debug.c
+++ b/zebra/debug.c
@@ -137,6 +137,9 @@ DEFUN_NOSH (show_debugging_zebra,
vty_out(vty, " Zebra PBR debugging is on\n");
hook_call(zebra_debug_show_debugging, vty);
+
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
diff --git a/zebra/main.c b/zebra/main.c
index 46cf2eea7..3de97943f 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -229,6 +229,7 @@ void zebra_finalize(struct thread *dummy)
zebra_router_terminate();
+ ns_terminate();
frr_fini();
exit(0);
}
diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c
index 043ea0f24..064c91b72 100644
--- a/zebra/zebra_evpn_mh.c
+++ b/zebra/zebra_evpn_mh.c
@@ -4028,4 +4028,6 @@ void zebra_evpn_mh_terminate(void)
hash_free(zmh_info->nhg_table);
hash_free(zmh_info->nh_ip_table);
bf_free(zmh_info->nh_id_bitmap);
+
+ XFREE(MTYPE_ZMH_INFO, zrouter.mh_info);
}
diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c
index 62ce17326..daac4cade 100644
--- a/zebra/zebra_srv6_vty.c
+++ b/zebra/zebra_srv6_vty.c
@@ -271,7 +271,7 @@ DEFUN (no_srv6_locator,
DEFPY (locator_prefix,
locator_prefix_cmd,
- "prefix X:X::X:X/M$prefix [func-bits (16-64)$func_bit_len]",
+ "prefix X:X::X:X/M$prefix [func-bits (0-64)$func_bit_len]",
"Configure SRv6 locator prefix\n"
"Specify SRv6 locator prefix\n"
"Configure SRv6 locator function length in bits\n"
@@ -281,7 +281,14 @@ DEFPY (locator_prefix,
struct srv6_locator_chunk *chunk = NULL;
struct listnode *node = NULL;
+ if (prefix->prefixlen != 64) {
+ vty_out(vty,
+ "%% Invalid argument: Unsupported locator format\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
locator->prefix = *prefix;
+ func_bit_len = func_bit_len ?: ZEBRA_SRV6_FUNCTION_LENGTH;
/*
* TODO(slankdev): please support variable node-bit-length.
@@ -298,8 +305,8 @@ DEFPY (locator_prefix,
* user should use a pattern of zeros as a filler.
* (3) The Node Id portion (LSBs) cannot exceed 24 bits.
*/
- locator->block_bits_length = prefix->prefixlen - 24;
- locator->node_bits_length = 24;
+ locator->block_bits_length = ZEBRA_SRV6_LOCATOR_BLOCK_LENGTH;
+ locator->node_bits_length = ZEBRA_SRV6_LOCATOR_NODE_LENGTH;
locator->function_bits_length = func_bit_len;
locator->argument_bits_length = 0;
diff --git a/zebra/zebra_srv6_vty.h b/zebra/zebra_srv6_vty.h
index 42d6aefa9..2f8b5048d 100644
--- a/zebra/zebra_srv6_vty.h
+++ b/zebra/zebra_srv6_vty.h
@@ -20,6 +20,10 @@
#ifndef _ZEBRA_SRV6_VTY_H
#define _ZEBRA_SRV6_VTY_H
+#define ZEBRA_SRV6_LOCATOR_BLOCK_LENGTH 40
+#define ZEBRA_SRV6_LOCATOR_NODE_LENGTH 24
+#define ZEBRA_SRV6_FUNCTION_LENGTH 16
+
extern void zebra_srv6_vty_init(void);
#endif /* _ZEBRA_SRV6_VTY_H */