summaryrefslogtreecommitdiff
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/IMPLEMENTATION.txt168
-rw-r--r--bgpd/bgp_attr.c2
-rw-r--r--bgpd/bgp_attr.h8
-rw-r--r--bgpd/bgp_community.h27
-rw-r--r--bgpd/bgp_conditional_adv.c199
-rw-r--r--bgpd/bgp_conditional_adv.h19
-rw-r--r--bgpd/bgp_debug.c92
-rw-r--r--bgpd/bgp_debug.h6
-rw-r--r--bgpd/bgp_ecommunity.c2
-rw-r--r--bgpd/bgp_evpn_mh.c50
-rw-r--r--bgpd/bgp_evpn_vty.c59
-rw-r--r--bgpd/bgp_fsm.c8
-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.c216
-rw-r--r--bgpd/bgp_mplsvpn.h5
-rw-r--r--bgpd/bgp_network.c26
-rw-r--r--bgpd/bgp_nexthop.c30
-rw-r--r--bgpd/bgp_nht.c17
-rw-r--r--bgpd/bgp_open.c62
-rw-r--r--bgpd/bgp_orr.c1176
-rw-r--r--bgpd/bgp_orr.h102
-rw-r--r--bgpd/bgp_packet.c36
-rw-r--r--bgpd/bgp_rd.c14
-rw-r--r--bgpd/bgp_route.c293
-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.c249
-rw-r--r--bgpd/bgp_zebra.c104
-rw-r--r--bgpd/bgpd.c305
-rw-r--r--bgpd/bgpd.conf.sample277
-rw-r--r--bgpd/bgpd.h72
-rw-r--r--bgpd/rfapi/bgp_rfapi_cfg.c22
-rw-r--r--bgpd/rfapi/rfapi.c21
-rw-r--r--bgpd/rfapi/rfapi_import.c42
-rw-r--r--bgpd/rfapi/rfapi_rib.c38
-rw-r--r--bgpd/rfapi/rfapi_vty.c10
-rw-r--r--bgpd/rfapi/rfapi_vty.h2
-rw-r--r--bgpd/subdir.am2
-rw-r--r--configure.ac2
-rw-r--r--debian/changelog6
-rw-r--r--doc/user/bgp.rst354
-rw-r--r--doc/user/ospfd.rst53
-rw-r--r--doc/user/overview.rst73
-rw-r--r--doc/user/pimv6.rst16
-rw-r--r--doc/user/setup.rst2
-rw-r--r--doc/user/vtysh.rst6
-rw-r--r--doc/user/zebra.rst2
-rw-r--r--docker/alpine/Dockerfile26
-rwxr-xr-xdocker/alpine/build.sh12
-rw-r--r--eigrpd/eigrp_dump.c1
-rw-r--r--include/linux/rtnetlink.h12
-rw-r--r--isisd/fabricd.c14
-rw-r--r--isisd/isis_nb_config.c2
-rw-r--r--isisd/isisd.c8
-rw-r--r--isisd/isisd.h1
-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/prefix.h1
-rw-r--r--lib/routemap.c7
-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_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.c173
-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--pathd/path_ted.c20
-rw-r--r--pbrd/pbr_vty.c2
-rw-r--r--pimd/pim6_cmd.c97
-rw-r--r--pimd/pim6_main.c4
-rw-r--r--pimd/pim6_mld.c93
-rw-r--r--pimd/pim_addr.h2
-rw-r--r--pimd/pim_cmd.c3
-rw-r--r--pimd/pim_cmd_common.c233
-rw-r--r--pimd/pim_hello.c16
-rw-r--r--pimd/pim_iface.c15
-rw-r--r--pimd/pim_igmp.c13
-rw-r--r--pimd/pim_igmp.h12
-rw-r--r--pimd/pim_nb_config.c7
-rw-r--r--pimd/pim_tlv.c12
-rw-r--r--pimd/pim_tlv.h2
-rw-r--r--pimd/pim_vty.c24
-rw-r--r--pimd/pimd.h21
-rw-r--r--redhat/frr.spec.in2
-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_conditional_advertisement/test_bgp_conditional_advertisement.py144
-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_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py196
-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--tools/coccinelle/route_map_apply.cocci15
-rwxr-xr-xtools/frr-reload.py35
-rwxr-xr-xtools/frr.in18
-rw-r--r--tools/frr.service.in2
-rw-r--r--tools/frr@.service.in2
-rwxr-xr-xtools/frrcommon.sh.in16
-rw-r--r--vrrpd/vrrp_vty.c2
-rw-r--r--vtysh/vtysh_config.c10
-rw-r--r--watchfrr/watchfrr_vty.c2
-rw-r--r--zebra/debug.c3
-rw-r--r--zebra/if_ioctl.c4
-rw-r--r--zebra/if_netlink.c26
-rw-r--r--zebra/if_sysctl.c4
-rw-r--r--zebra/kernel_socket.c7
-rw-r--r--zebra/main.c1
-rw-r--r--zebra/rib.h1
-rw-r--r--zebra/rtadv.c35
-rw-r--r--zebra/zebra_evpn_mh.c2
-rw-r--r--zebra/zebra_fpm.c27
-rw-r--r--zebra/zebra_rib.c5
-rw-r--r--zebra/zebra_srv6_vty.c13
-rw-r--r--zebra/zebra_srv6_vty.h4
207 files changed, 7028 insertions, 2070 deletions
diff --git a/.github/workflows/conflicts.yml b/.github/workflows/conflicts.yml
new file mode 100644
index 0000000000..18a8c0d15d
--- /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 d0da93e507..daaa870a64 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 21429f06cf..4a2c5bf662 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/IMPLEMENTATION.txt b/bgpd/IMPLEMENTATION.txt
deleted file mode 100644
index 5822dbba82..0000000000
--- a/bgpd/IMPLEMENTATION.txt
+++ /dev/null
@@ -1,168 +0,0 @@
-$Id: IMPLEMENTATION.txt,v 1.2 2005/02/15 17:10:03 gdt Exp $
-
-This file contains notes about the internals of the BGP
-implementation. The initial impetus is understanding the memory usage
-of Quagga'a BGP implementation. There may be some inaccuracies; it is
-in the repository in the hopes that it will be significantly more
-helpful than not.
-
-* FILES
-
-bgp_advertise.[hc]:
- data structures: advertised prefixes, attributes
-
-bgp_aspath.[hc]:
- struct aspath:
- These are stored in a hash, apparently in wire format.
-
-bgp_attr.[hc]:
- struct attr: contains all attributes
- size(ILP32) 26 words/104 bytes (poor packing, v6/multicast is 10)
-
- bgp_attr_parse: origin, aspath, next hop probably most of interest
- bgp_attr_origin: set flag bit
- bgp_attr_aspath: put in refcounted hash table, so share pointer
- bgp_attr_nexthop: store in attribute structure
-
-bgp_btoa.c: ? test program
-
-bgp_clist.[hc]:
- data structures: community lists (including permit/deny state)
-
-bgp_community.[hc]:
- data structures: community atttributes (multiple communities per struct)
-
-bgp_damp.[hc]:
- per-route damping data, and damping control information
-
-bgp_debug.[hc]:
- debugging support (vty config, dump of packets)
-
-bgp_dump.[hc]:
- MRT-compatible dump format routines
-
-bgp_ecommunity.[hc]:
- Extended communities attributes (multiple ecommmunities per struct)
-
-bgp_filter.[hc]:
- AS path access list filtering
-
-bgp_fsm.[hc]:
- Per-peer state machine for TCP connection, hold time, etc.
-
-bgp_main.c:
- Daemon startup.
-
-bgp_mplsvpn.[hc]:
- parsing of attribute structures for MPLS VPNs [need better description]
-
-bgp_network.[hc]:
- Opening and binding of sockets, finding addresses for interfaces
-
-bgp_nexthop.[hc]:
- data structures: Nexthop cache [not clear how used, if truly cache
- in sense of memoization, or something else]
-
- importing EGP routes into IGP (thread created)
- "scanning" (thread created)
- bgp_scan: has useful clues to data structure complexity. Scanning
- process iterates over database of received advertisements, and
- builds 'cache' structure.
-
-bgp_open.[ch]:
- Open messages, and capability negotiation
-
-bgp_packet.[hc]
- sending and receiving of UPDATE/WITHDRAW
- collision resolution for simultanteous opens
- bgp_read: top-level read routine: reads whole packet (nonblocking)
- and dispatches to per-message-type receive
-
- bgp_update_receive:
- calls bgp_attr_parse
- reads nrli into struct bgp_nrli update
-
- uninterning of aspath, community, ecommmunity, cluster,
- transit which were interned in bgp_attr_parse
-
-bgp_regex.[ch]:
- Glue to convert BGP regexps to standard (_ means many things).
-
-bgp_route.[hc]:
- data structures: routes as received, static routes
- Application of filters. Lots of route processing.
-
- bgp_nlri_parse:
- sanity checks, then calls bgp_update with peer, prefix, attributes pointer
-
- bgp_update: bgp_update_main, then RS processing
-
- bgp_update_main:
- find 'struct bgp_node *' for this afi/safi
- look for route in table, then 'intern' attributes
- ** interning is process of
- looking for data in hash table, and putting there if missing, refcnt
- using pointer to existing data
- many validity checks
- get new struct bgp_path_info
- call bgp_path_info_add with rn and bgp_path_info
- call bgp_process
-
-bgp_routemap.c
- implementation of route maps (match and set)
-
-bgp_snmp.c
- SNMP glue. Not particularly interesting except to add variables or
- debug SNMP.
-
-bgp_table.[hc]
- data structures: struct bgp_table, struct bgp_node
- allocation/lookup/utility operations - not a lot of protocol processin
-
-bgp_vty.[hc]
- protocol-wide vty hooks
-
-bgp_zebra.[hc]
- Processing interface events from zebra, redistribution of routes.
-
-bgpd.h
- struct bgp_master: daemon main data structure
- struct bgp: per-instance structure
- struct peer_group
- struct bgp_notify: (in-core representation of wire format?)
- struct bgp_nexthop: (v4 and v6 addresses, *ifp)
- struct bgp_filter: distribute, prefix, aslist, route_maps
- struct peer: neighbor structure (very rich/complex)
- struct bgp_nlri: reference to wire format
- #define of protocol constants
- attribute type codes
- fsm states/events
- timer values
-
-bgpd.c
- instance/peer allocation
- configuration
- initialization/termination
-
-* DATA STRUCTURE SIZES
-
-Question: How much memory does quagga's bgpd use as a function of
-state received from peers?
-
-It seems that a struct bgp_path_info is kept for each prefix. The "struct
-attr *" is interned, and variables within that are interned. So, 40
-bytes are kept per received prefix, plus interned shared values. This
-could be 36 if 'int suppress' where changed to a u_char and moved to
-be with the other u_chars. Without MPLS, this could be 32 bytes.
-Note that 8 bytes of this is linked list overhead, meaning that 24
-bytes are the raw per-prefix storage requirements.
-
-Also, a struct bgp_damp_info is apparently maintained per route; this
-is fairly large (about 44 bytes).
-
-[TODO: the role of struct bgp_node.]
-
-* TIME COMPLEXITY
-
-It appears that received prefixes from each peer are stored in a
-linked list.
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index d91c717f37..b7d0958bac 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -983,7 +983,7 @@ struct attr *bgp_attr_aggregate_intern(
{
struct attr attr;
struct attr *new;
- int ret;
+ route_map_result_t ret;
memset(&attr, 0, sizeof(attr));
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index 4963ea64d0..41ae6ef49c 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 616ddb4405..05a5d4486a 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_conditional_adv.c b/bgpd/bgp_conditional_adv.c
index fc44e86cbc..2598361ad2 100644
--- a/bgpd/bgp_conditional_adv.c
+++ b/bgpd/bgp_conditional_adv.c
@@ -53,18 +53,16 @@ bgp_check_rmap_prefixes_in_bgp_table(struct bgp_table *table,
if (ret == RMAP_PERMITMATCH) {
bgp_dest_unlock_node(dest);
- if (BGP_DEBUG(update, UPDATE_OUT))
- zlog_debug(
- "%s: Condition map routes present in BGP table",
- __func__);
+ bgp_cond_adv_debug(
+ "%s: Condition map routes present in BGP table",
+ __func__);
return ret;
}
}
}
- if (BGP_DEBUG(update, UPDATE_OUT))
- zlog_debug("%s: Condition map routes not present in BGP table",
+ bgp_cond_adv_debug("%s: Condition map routes not present in BGP table",
__func__);
return ret;
@@ -98,8 +96,7 @@ static void bgp_conditional_adv_routes(struct peer *peer, afi_t afi,
subgrp->pscount = 0;
SET_FLAG(subgrp->sflags, SUBGRP_STATUS_TABLE_REPARSING);
- if (BGP_DEBUG(update, UPDATE_OUT))
- zlog_debug("%s: %s routes to/from %s for %s", __func__,
+ bgp_cond_adv_debug("%s: %s routes to/from %s for %s", __func__,
update_type == UPDATE_TYPE_ADVERTISE ? "Advertise"
: "Withdraw",
peer->host, get_afi_safi_str(afi, safi, false));
@@ -224,7 +221,7 @@ static void bgp_conditional_adv_timer(struct thread *t)
&& !peer->advmap_table_change)
continue;
- if (BGP_DEBUG(update, UPDATE_OUT)) {
+ if (BGP_DEBUG(cond_adv, COND_ADV)) {
if (peer->advmap_table_change)
zlog_debug(
"%s: %s - routes changed in BGP table.",
@@ -269,10 +266,9 @@ static void bgp_conditional_adv_timer(struct thread *t)
.advmap.update_type !=
filter->advmap.update_type)) {
/* Handle change to peer advmap */
- if (BGP_DEBUG(update, UPDATE_OUT))
- zlog_debug(
- "%s: advmap.update_type changed for peer %s, adjusting update_group.",
- __func__, peer->host);
+ bgp_cond_adv_debug(
+ "%s: advmap.update_type changed for peer %s, adjusting update_group.",
+ __func__, peer->host);
update_group_adjust_peer(paf);
}
@@ -283,12 +279,10 @@ static void bgp_conditional_adv_timer(struct thread *t)
*/
if (peer->advmap_config_change[afi][safi]) {
- if (BGP_DEBUG(update, UPDATE_OUT))
- zlog_debug(
- "%s: Configuration is changed on peer %s for %s, send the normal update first.",
- __func__, peer->host,
- get_afi_safi_str(afi, safi,
- false));
+ bgp_cond_adv_debug(
+ "%s: Configuration is changed on peer %s for %s, send the normal update first.",
+ __func__, peer->host,
+ get_afi_safi_str(afi, safi, false));
if (paf) {
update_subgroup_split_peer(paf, NULL);
subgrp = paf->subgroup;
@@ -325,8 +319,7 @@ void bgp_conditional_adv_enable(struct peer *peer, afi_t afi, safi_t safi)
* neighbors (AFI/SAFI). So just increment the counter.
*/
if (++bgp->condition_filter_count > 1) {
- if (BGP_DEBUG(update, UPDATE_OUT))
- zlog_debug("%s: condition_filter_count %d", __func__,
+ bgp_cond_adv_debug("%s: condition_filter_count %d", __func__,
bgp->condition_filter_count);
return;
@@ -349,8 +342,7 @@ void bgp_conditional_adv_disable(struct peer *peer, afi_t afi, safi_t safi)
* So there's nothing to do except decrementing the counter.
*/
if (--bgp->condition_filter_count != 0) {
- if (BGP_DEBUG(update, UPDATE_OUT))
- zlog_debug("%s: condition_filter_count %d", __func__,
+ bgp_cond_adv_debug("%s: condition_filter_count %d", __func__,
bgp->condition_filter_count);
return;
@@ -359,3 +351,164 @@ void bgp_conditional_adv_disable(struct peer *peer, afi_t afi, safi_t safi)
/* Last filter removed. So cancel conditional routes polling thread. */
THREAD_OFF(bgp->t_condition_check);
}
+
+static void peer_advertise_map_filter_update(struct peer *peer, afi_t afi,
+ safi_t safi, const char *amap_name,
+ struct route_map *amap,
+ const char *cmap_name,
+ struct route_map *cmap,
+ bool condition, bool set)
+{
+ struct bgp_filter *filter;
+ bool filter_exists = false;
+
+ filter = &peer->filter[afi][safi];
+
+ /* advertise-map is already configured. */
+ if (filter->advmap.aname) {
+ filter_exists = true;
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->advmap.aname);
+ XFREE(MTYPE_BGP_FILTER_NAME, filter->advmap.cname);
+ }
+
+ route_map_counter_decrement(filter->advmap.amap);
+
+ /* Removed advertise-map configuration */
+ if (!set) {
+ memset(&filter->advmap, 0, sizeof(filter->advmap));
+
+ /* decrement condition_filter_count delete timer if
+ * this is the last advertise-map to be removed.
+ */
+ if (filter_exists)
+ bgp_conditional_adv_disable(peer, afi, safi);
+
+ /* Process peer route updates. */
+ peer_on_policy_change(peer, afi, safi, 1);
+
+ return;
+ }
+
+ /* Update filter data with newly configured values. */
+ filter->advmap.aname = XSTRDUP(MTYPE_BGP_FILTER_NAME, amap_name);
+ filter->advmap.cname = XSTRDUP(MTYPE_BGP_FILTER_NAME, cmap_name);
+ filter->advmap.amap = amap;
+ filter->advmap.cmap = cmap;
+ filter->advmap.condition = condition;
+ route_map_counter_increment(filter->advmap.amap);
+ peer->advmap_config_change[afi][safi] = true;
+
+ /* Increment condition_filter_count and/or create timer. */
+ if (!filter_exists) {
+ filter->advmap.update_type = UPDATE_TYPE_ADVERTISE;
+ bgp_conditional_adv_enable(peer, afi, safi);
+ }
+
+ /* Process peer route updates. */
+ peer_on_policy_change(peer, afi, safi, 1);
+}
+
+/* Set advertise-map to the peer. */
+int peer_advertise_map_set(struct peer *peer, afi_t afi, safi_t safi,
+ const char *advertise_name,
+ struct route_map *advertise_map,
+ const char *condition_name,
+ struct route_map *condition_map, bool condition)
+{
+ struct peer *member;
+ struct listnode *node, *nnode;
+
+ /* Set configuration on peer. */
+ peer_advertise_map_filter_update(peer, afi, safi, advertise_name,
+ advertise_map, condition_name,
+ condition_map, condition, true);
+
+ /* Check if handling a regular peer & Skip peer-group mechanics. */
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Set override-flag and process peer route updates. */
+ SET_FLAG(peer->filter_override[afi][safi][RMAP_OUT],
+ PEER_FT_ADVERTISE_MAP);
+ return 0;
+ }
+
+ /*
+ * Set configuration on all peer-group members, unless they are
+ * explicitly overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->filter_override[afi][safi][RMAP_OUT],
+ PEER_FT_ADVERTISE_MAP))
+ continue;
+
+ /* Set configuration on peer-group member. */
+ peer_advertise_map_filter_update(
+ member, afi, safi, advertise_name, advertise_map,
+ condition_name, condition_map, condition, true);
+ }
+
+ return 0;
+}
+
+/* Unset advertise-map from the peer. */
+int peer_advertise_map_unset(struct peer *peer, afi_t afi, safi_t safi,
+ const char *advertise_name,
+ struct route_map *advertise_map,
+ const char *condition_name,
+ struct route_map *condition_map, bool condition)
+{
+ struct peer *member;
+ struct listnode *node, *nnode;
+
+ /* advertise-map is not configured */
+ if (!peer->filter[afi][safi].advmap.aname)
+ return 0;
+
+ /* Unset override-flag unconditionally. */
+ UNSET_FLAG(peer->filter_override[afi][safi][RMAP_OUT],
+ PEER_FT_ADVERTISE_MAP);
+
+ /* Inherit configuration from peer-group if peer is member. */
+ if (peer_group_active(peer)) {
+ PEER_STR_ATTR_INHERIT(peer, peer->group,
+ filter[afi][safi].advmap.aname,
+ MTYPE_BGP_FILTER_NAME);
+ PEER_ATTR_INHERIT(peer, peer->group,
+ filter[afi][safi].advmap.amap);
+ } else
+ peer_advertise_map_filter_update(
+ peer, afi, safi, advertise_name, advertise_map,
+ condition_name, condition_map, condition, false);
+
+ /* Check if handling a regular peer and skip peer-group mechanics. */
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
+ /* Process peer route updates. */
+ bgp_cond_adv_debug("%s: Send normal update to %s for %s",
+ __func__, peer->host,
+ get_afi_safi_str(afi, safi, false));
+
+ return 0;
+ }
+
+ /*
+ * Remove configuration on all peer-group members, unless they are
+ * explicitly overriding peer-group configuration.
+ */
+ for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
+ /* Skip peers with overridden configuration. */
+ if (CHECK_FLAG(member->filter_override[afi][safi][RMAP_OUT],
+ PEER_FT_ADVERTISE_MAP))
+ continue;
+ /* Remove configuration on peer-group member. */
+ peer_advertise_map_filter_update(
+ member, afi, safi, advertise_name, advertise_map,
+ condition_name, condition_map, condition, false);
+
+ /* Process peer route updates. */
+ bgp_cond_adv_debug("%s: Send normal update to %s for %s ",
+ __func__, member->host,
+ get_afi_safi_str(afi, safi, false));
+ }
+
+ return 0;
+}
diff --git a/bgpd/bgp_conditional_adv.h b/bgpd/bgp_conditional_adv.h
index 371ae856c2..a4f1403a44 100644
--- a/bgpd/bgp_conditional_adv.h
+++ b/bgpd/bgp_conditional_adv.h
@@ -33,6 +33,13 @@
extern "C" {
#endif
+/* Macro to log debug message */
+#define bgp_cond_adv_debug(...) \
+ do { \
+ if (BGP_DEBUG(cond_adv, COND_ADV)) \
+ zlog_debug("" __VA_ARGS__); \
+ } while (0)
+
/* Polling time for monitoring condition-map routes in route table */
#define DEFAULT_CONDITIONAL_ROUTES_POLL_TIME 60
@@ -40,6 +47,18 @@ extern void bgp_conditional_adv_enable(struct peer *peer, afi_t afi,
safi_t safi);
extern void bgp_conditional_adv_disable(struct peer *peer, afi_t afi,
safi_t safi);
+extern int peer_advertise_map_set(struct peer *peer, afi_t afi, safi_t safi,
+ const char *advertise_name,
+ struct route_map *advertise_map,
+ const char *condition_name,
+ struct route_map *condition_map,
+ bool condition);
+extern int peer_advertise_map_unset(struct peer *peer, afi_t afi, safi_t safi,
+ const char *advertise_name,
+ struct route_map *advertise_map,
+ const char *condition_name,
+ struct route_map *condition_map,
+ bool condition);
#ifdef __cplusplus
}
#endif
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index d0ab88ee1b..580c18b58d 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -70,6 +70,8 @@ unsigned long conf_bgp_debug_pbr;
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;
@@ -90,6 +92,8 @@ unsigned long term_bgp_debug_pbr;
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;
@@ -2042,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",
@@ -2108,6 +2139,33 @@ DEFPY(debug_bgp_bfd, debug_bgp_bfd_cmd,
return CMD_SUCCESS;
}
+DEFPY (debug_bgp_cond_adv,
+ debug_bgp_cond_adv_cmd,
+ "[no$no] debug bgp conditional-advertisement",
+ NO_STR
+ DEBUG_STR
+ BGP_STR
+ "BGP conditional advertisement\n")
+{
+ if (vty->node == CONFIG_NODE) {
+ if (no)
+ DEBUG_OFF(cond_adv, COND_ADV);
+ else
+ DEBUG_ON(cond_adv, COND_ADV);
+ } else {
+ if (no) {
+ TERM_DEBUG_OFF(cond_adv, COND_ADV);
+ vty_out(vty,
+ "BGP conditional advertisement debugging is off\n");
+ } else {
+ TERM_DEBUG_ON(cond_adv, COND_ADV);
+ vty_out(vty,
+ "BGP conditional advertisement debugging is on\n");
+ }
+ }
+ return CMD_SUCCESS;
+}
+
DEFUN (no_debug_bgp,
no_debug_bgp_cmd,
"no debug bgp",
@@ -2152,6 +2210,8 @@ DEFUN (no_debug_bgp,
TERM_DEBUG_OFF(evpn_mh, EVPN_MH_ES);
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");
@@ -2244,6 +2304,16 @@ DEFUN_NOSH (show_debugging_bgp,
if (BGP_DEBUG(bfd, BFD_LIB))
vty_out(vty, " BGP BFD library debugging is on\n");
+ if (BGP_DEBUG(cond_adv, COND_ADV))
+ 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;
}
@@ -2373,6 +2443,16 @@ static int bgp_config_write_debug(struct vty *vty)
write++;
}
+ if (CONF_BGP_DEBUG(cond_adv, COND_ADV)) {
+ vty_out(vty, "debug bgp conditional-advertisement\n");
+ write++;
+ }
+
+ if (CONF_BGP_DEBUG(optimal_route_reflection, ORR)) {
+ vty_out(vty, "debug bgp optimal-route-reflection\n");
+ write++;
+ }
+
return write;
}
@@ -2501,6 +2581,14 @@ void bgp_debug_init(void)
/* debug bgp bfd */
install_element(ENABLE_NODE, &debug_bgp_bfd_cmd);
install_element(CONFIG_NODE, &debug_bgp_bfd_cmd);
+
+ /* 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
@@ -2662,7 +2750,6 @@ const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi,
struct bgp_route_evpn *overlay_index,
char *str, int size)
{
- char rd_buf[RD_ADDRSTRLEN];
char tag_buf[30];
char overlay_index_buf[INET6_ADDRSTRLEN + 14];
const struct prefix_evpn *evp;
@@ -2720,8 +2807,7 @@ const char *bgp_debug_rdpfxpath2str(afi_t afi, safi_t safi,
}
if (prd)
- snprintfrr(str, size, "RD %s %pFX%s%s%s %s %s",
- prefix_rd2str(prd, rd_buf, sizeof(rd_buf)), pu.p,
+ snprintfrr(str, size, "RD %pRD %pFX%s%s%s %s %s", prd, pu.p,
overlay_index_buf, tag_buf, pathid_buf, afi2str(afi),
safi2str(safi));
else if (safi == SAFI_FLOWSPEC) {
diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h
index 62f5340dfd..f7090260ac 100644
--- a/bgpd/bgp_debug.h
+++ b/bgpd/bgp_debug.h
@@ -80,6 +80,8 @@ extern unsigned long conf_bgp_debug_pbr;
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;
@@ -98,6 +100,8 @@ extern unsigned long term_bgp_debug_pbr;
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;
@@ -136,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
@@ -143,6 +148,7 @@ struct bgp_debug_filter {
#define BGP_DEBUG_GRACEFUL_RESTART 0x01
#define BGP_DEBUG_BFD_LIB 0x01
+#define BGP_DEBUG_COND_ADV 0x01
#define CONF_DEBUG_ON(a, b) (conf_bgp_debug_ ## a |= (BGP_DEBUG_ ## b))
#define CONF_DEBUG_OFF(a, b) (conf_bgp_debug_ ## a &= ~(BGP_DEBUG_ ## b))
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c
index f57e9ae88b..589d9af1e5 100644
--- a/bgpd/bgp_ecommunity.c
+++ b/bgpd/bgp_ecommunity.c
@@ -1383,7 +1383,7 @@ bool ecommunity_del_val(struct ecommunity *ecom, struct ecommunity_val *eval)
XFREE(MTYPE_ECOMMUNITY_VAL, ecom->val);
ecom->val = p;
} else
- ecom->val = NULL;
+ XFREE(MTYPE_ECOMMUNITY_VAL, ecom->val);
return true;
}
diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c
index de63618580..1d40664aeb 100644
--- a/bgpd/bgp_evpn_mh.c
+++ b/bgpd/bgp_evpn_mh.c
@@ -2402,16 +2402,13 @@ static void bgp_evpn_es_json_frag_fill(json_object *json_frags,
struct bgp_evpn_es *es)
{
json_object *json_frag;
- char buf1[RD_ADDRSTRLEN];
struct listnode *node;
struct bgp_evpn_es_frag *es_frag;
for (ALL_LIST_ELEMENTS_RO(es->es_frag_list, node, es_frag)) {
json_frag = json_object_new_object();
- json_object_string_add(
- json_frag, "rd",
- prefix_rd2str(&es_frag->prd, buf1, sizeof(buf1)));
+ json_object_string_addf(json_frag, "rd", "%pRD", &es_frag->prd);
json_object_int_add(json_frag, "eviCount",
listcount(es_frag->es_evi_frag_list));
@@ -2423,12 +2420,10 @@ static void bgp_evpn_es_frag_show_detail(struct vty *vty,
struct bgp_evpn_es *es)
{
struct listnode *node;
- char buf1[RD_ADDRSTRLEN];
struct bgp_evpn_es_frag *es_frag;
for (ALL_LIST_ELEMENTS_RO(es->es_frag_list, node, es_frag)) {
- vty_out(vty, " %s EVIs: %d\n",
- prefix_rd2str(&es_frag->prd, buf1, sizeof(buf1)),
+ vty_out(vty, " %pRD EVIs: %d\n", &es_frag->prd,
listcount(es_frag->es_evi_frag_list));
}
}
@@ -2533,7 +2528,6 @@ static void bgp_evpn_es_vteps_show_detail(struct vty *vty,
static void bgp_evpn_es_show_entry(struct vty *vty,
struct bgp_evpn_es *es, json_object *json)
{
- char buf1[RD_ADDRSTRLEN];
struct listnode *node;
struct bgp_evpn_es_vtep *es_vtep;
@@ -2543,10 +2537,8 @@ static void bgp_evpn_es_show_entry(struct vty *vty,
json_object_string_add(json, "esi", es->esi_str);
if (es->es_base_frag)
- json_object_string_add(
- json, "rd",
- prefix_rd2str(&es->es_base_frag->prd, buf1,
- sizeof(buf1)));
+ json_object_string_addf(json, "rd", "%pRD",
+ &es->es_base_frag->prd);
if (es->flags & (BGP_EVPNES_LOCAL | BGP_EVPNES_REMOTE)) {
json_types = json_object_new_array();
@@ -2583,15 +2575,9 @@ static void bgp_evpn_es_show_entry(struct vty *vty,
bgp_evpn_es_vteps_str(vtep_str, es, sizeof(vtep_str));
- if (es->es_base_frag)
- prefix_rd2str(&es->es_base_frag->prd, buf1,
- sizeof(buf1));
- else
- strlcpy(buf1, "-", sizeof(buf1));
-
- vty_out(vty, "%-30s %-5s %-21s %-8d %s\n",
- es->esi_str, type_str, buf1,
- listcount(es->es_evi_list), vtep_str);
+ vty_out(vty, "%-30s %-5s %-21pRD %-8d %s\n", es->esi_str,
+ type_str, &es->es_base_frag->prd,
+ listcount(es->es_evi_list), vtep_str);
}
}
@@ -2657,7 +2643,6 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty,
} else {
char incons_str[BGP_EVPNES_INCONS_STR_SZ];
char type_str[4];
- char buf1[RD_ADDRSTRLEN];
type_str[0] = '\0';
if (es->flags & BGP_EVPNES_LOCAL)
@@ -2665,15 +2650,9 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty,
if (es->flags & BGP_EVPNES_REMOTE)
strlcat(type_str, "R", sizeof(type_str));
- if (es->es_base_frag)
- prefix_rd2str(&es->es_base_frag->prd, buf1,
- sizeof(buf1));
- else
- strlcpy(buf1, "-", sizeof(buf1));
-
vty_out(vty, "ESI: %s\n", es->esi_str);
vty_out(vty, " Type: %s\n", type_str);
- vty_out(vty, " RD: %s\n", buf1);
+ vty_out(vty, " RD: %pRD\n", &es->es_base_frag->prd);
vty_out(vty, " Originator-IP: %pI4\n", &es->originator_ip);
if (es->flags & BGP_EVPNES_LOCAL)
vty_out(vty, " Local ES DF preference: %u\n",
@@ -4032,18 +4011,14 @@ static void bgp_evpn_es_evi_show_entry(struct vty *vty,
static void bgp_evpn_es_evi_show_entry_detail(struct vty *vty,
struct bgp_evpn_es_evi *es_evi, json_object *json)
{
- char buf1[RD_ADDRSTRLEN];
-
if (json) {
json_object *json_flags;
/* Add the "brief" info first */
bgp_evpn_es_evi_show_entry(vty, es_evi, json);
if (es_evi->es_frag)
- json_object_string_add(
- json, "esFragmentRd",
- prefix_rd2str(&es_evi->es_frag->prd, buf1,
- sizeof(buf1)));
+ json_object_string_addf(json, "esFragmentRd", "%pRD",
+ &es_evi->es_frag->prd);
if (es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST) {
json_flags = json_object_new_array();
json_array_string_add(json_flags, "es-vtep-mismatch");
@@ -4067,9 +4042,8 @@ static void bgp_evpn_es_evi_show_entry_detail(struct vty *vty,
es_evi->vpn->vni, es_evi->es->esi_str);
vty_out(vty, " Type: %s\n", type_str);
if (es_evi->es_frag)
- vty_out(vty, " ES fragment RD: %s\n",
- prefix_rd2str(&es_evi->es_frag->prd, buf1,
- sizeof(buf1)));
+ vty_out(vty, " ES fragment RD: %pRD\n",
+ &es_evi->es_frag->prd);
vty_out(vty, " Inconsistencies: %s\n",
(es_evi->flags & BGP_EVPNES_EVI_INCONS_VTEP_LIST) ?
"es-vtep-mismatch":"-");
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index f6b87dccdb..5ad5cf8bff 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -386,9 +386,7 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
json_object_int_add(json, "vni", bgp_vrf->l3vni);
json_object_string_add(json, "type", "L3");
json_object_string_add(json, "inKernel", "True");
- json_object_string_add(
- json, "rd",
- prefix_rd2str(&bgp_vrf->vrf_prd, buf1, RD_ADDRSTRLEN));
+ json_object_string_addf(json, "rd", "%pRD", &bgp_vrf->vrf_prd);
json_object_string_addf(json, "originatorIp", "%pI4",
&bgp_vrf->originator_ip);
json_object_string_add(json, "advertiseGatewayMacip", "n/a");
@@ -412,8 +410,7 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
vty_out(vty, " Type: %s\n", "L3");
vty_out(vty, " Tenant VRF: %s\n",
vrf_id_to_name(bgp_vrf->vrf_id));
- vty_out(vty, " RD: %s\n",
- prefix_rd2str(&bgp_vrf->vrf_prd, buf1, RD_ADDRSTRLEN));
+ vty_out(vty, " RD: %pRD\n", &bgp_vrf->vrf_prd);
vty_out(vty, " Originator IP: %pI4\n",
&bgp_vrf->originator_ip);
vty_out(vty, " Advertise-gw-macip : %s\n", "n/a");
@@ -471,7 +468,6 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
{
- char buf1[RD_ADDRSTRLEN];
char *ecom_str;
struct listnode *node, *nnode;
struct ecommunity *ecom;
@@ -488,9 +484,7 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
json_object_string_add(json, "type", "L2");
json_object_string_add(json, "inKernel",
is_vni_live(vpn) ? "True" : "False");
- json_object_string_add(
- json, "rd",
- prefix_rd2str(&vpn->prd, buf1, sizeof(buf1)));
+ json_object_string_addf(json, "rd", "%pRD", &vpn->prd);
json_object_string_addf(json, "originatorIp", "%pI4",
&vpn->originator_ip);
json_object_string_addf(json, "mcastGroup", "%pI4",
@@ -531,8 +525,7 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json)
vty_out(vty, " Type: %s\n", "L2");
vty_out(vty, " Tenant-Vrf: %s\n",
vrf_id_to_name(vpn->tenant_vrf_id));
- vty_out(vty, " RD: %s\n",
- prefix_rd2str(&vpn->prd, buf1, sizeof(buf1)));
+ vty_out(vty, " RD: %pRD\n", &vpn->prd);
vty_out(vty, " Originator IP: %pI4\n", &vpn->originator_ip);
vty_out(vty, " Mcast group: %pI4\n", &vpn->mcast_grp);
if (!vpn->advertise_gw_macip &&
@@ -941,9 +934,7 @@ static void show_l3vni_entry(struct vty *vty, struct bgp *bgp,
json_object_string_add(json_vni, "inKernel", "True");
json_object_string_addf(json_vni, "originatorIp", "%pI4",
&bgp->originator_ip);
- json_object_string_add(
- json_vni, "rd",
- prefix_rd2str(&bgp->vrf_prd, buf2, RD_ADDRSTRLEN));
+ json_object_string_addf(json_vni, "rd", "%pRD", &bgp->vrf_prd);
json_object_string_add(json_vni, "advertiseGatewayMacip",
"n/a");
json_object_string_add(json_vni, "advertiseSviMacIp", "n/a");
@@ -959,8 +950,8 @@ static void show_l3vni_entry(struct vty *vty, struct bgp *bgp,
json_vni, "rmac",
prefix_mac2str(&bgp->rmac, buf2, sizeof(buf2)));
} else {
- vty_out(vty, "%-1s %-10u %-4s %-21s", buf1, bgp->l3vni, "L3",
- prefix_rd2str(&bgp->vrf_prd, buf2, RD_ADDRSTRLEN));
+ vty_out(vty, "%-1s %-10u %-4s %-21pRD", buf1, bgp->l3vni, "L3",
+ &bgp->vrf_prd);
}
for (ALL_LIST_ELEMENTS(bgp->vrf_import_rtl, node, nnode, ecom)) {
@@ -1038,7 +1029,6 @@ static void show_vni_entry(struct hash_bucket *bucket, void *args[])
json_object *json_export_rtl = NULL;
struct bgpevpn *vpn = (struct bgpevpn *)bucket->data;
char buf1[10];
- char buf2[RD_ADDRSTRLEN];
char rt_buf[25];
char *ecom_str;
struct listnode *node, *nnode;
@@ -1065,9 +1055,7 @@ static void show_vni_entry(struct hash_bucket *bucket, void *args[])
json_object_string_add(json_vni, "type", "L2");
json_object_string_add(json_vni, "inKernel",
is_vni_live(vpn) ? "True" : "False");
- json_object_string_add(
- json_vni, "rd",
- prefix_rd2str(&vpn->prd, buf2, sizeof(buf2)));
+ json_object_string_addf(json_vni, "rd", "%pRD", &vpn->prd);
json_object_string_addf(json_vni, "originatorIp", "%pI4",
&vpn->originator_ip);
json_object_string_addf(json_vni, "mcastGroup", "%pI4",
@@ -1097,8 +1085,8 @@ static void show_vni_entry(struct hash_bucket *bucket, void *args[])
json_object_string_add(json_vni, "advertiseSviMacIp",
"Disabled");
} else {
- vty_out(vty, "%-1s %-10u %-4s %-21s", buf1, vpn->vni, "L2",
- prefix_rd2str(&vpn->prd, buf2, RD_ADDRSTRLEN));
+ vty_out(vty, "%-1s %-10u %-4s %-21pRD", buf1, vpn->vni, "L2",
+ &vpn->prd);
}
for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode, ecom)) {
@@ -2629,7 +2617,6 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
afi_t afi;
safi_t safi;
uint32_t prefix_cnt, path_cnt;
- char rd_str[RD_ADDRSTRLEN];
json_object *json_rd = NULL;
int add_rd_to_json = 0;
@@ -2637,8 +2624,6 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
safi = SAFI_EVPN;
prefix_cnt = path_cnt = 0;
- prefix_rd2str(prd, rd_str, sizeof(rd_str));
-
rd_dest = bgp_node_lookup(bgp->rib[afi][safi], (struct prefix *)prd);
if (!rd_dest)
return;
@@ -2651,7 +2636,7 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
if (json) {
json_rd = json_object_new_object();
- json_object_string_add(json_rd, "rd", rd_str);
+ json_object_string_addf(json_rd, "rd", "%pRD", prd);
}
bgp_dest_unlock_node(rd_dest);
@@ -2732,7 +2717,7 @@ static void evpn_show_route_rd(struct vty *vty, struct bgp *bgp,
if (json) {
if (add_rd_to_json)
- json_object_object_add(json, rd_str, json_rd);
+ json_object_object_addf(json, json_rd, "%pRD", prd);
else {
json_object_free(json_rd);
json_rd = NULL;
@@ -3307,7 +3292,6 @@ static void evpn_unset_advertise_autort_rfc8365(struct bgp *bgp)
static void write_vni_config(struct vty *vty, struct bgpevpn *vpn)
{
- char buf1[RD_ADDRSTRLEN];
char *ecom_str;
struct listnode *node, *nnode;
struct ecommunity *ecom;
@@ -3315,8 +3299,7 @@ static void write_vni_config(struct vty *vty, struct bgpevpn *vpn)
if (is_vni_configured(vpn)) {
vty_out(vty, " vni %d\n", vpn->vni);
if (is_rd_configured(vpn))
- vty_out(vty, " rd %s\n",
- prefix_rd2str(&vpn->prd, buf1, sizeof(buf1)));
+ vty_out(vty, " rd %pRD\n", &vpn->prd);
if (is_import_rt_configured(vpn)) {
for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode,
@@ -5697,7 +5680,6 @@ DEFUN (show_bgp_vrf_l3vni_info,
JSON_STR)
{
char buf[ETHER_ADDR_STRLEN];
- char buf1[INET6_ADDRSTRLEN];
int idx_vrf = 3;
const char *name = NULL;
struct bgp *bgp = NULL;
@@ -5761,8 +5743,7 @@ DEFUN (show_bgp_vrf_l3vni_info,
for (ALL_LIST_ELEMENTS_RO(bgp->vrf_import_rtl, node, ecom))
vty_out(vty, "%s ", ecommunity_str(ecom));
vty_out(vty, "\n");
- vty_out(vty, " RD: %s\n",
- prefix_rd2str(&bgp->vrf_prd, buf1, RD_ADDRSTRLEN));
+ vty_out(vty, " RD: %pRD\n", &bgp->vrf_prd);
} else {
json_object_string_add(json, "vrf", name);
json_object_string_addf(json, "local-ip", "%pI4",
@@ -5796,9 +5777,7 @@ DEFUN (show_bgp_vrf_l3vni_info,
json_import_rts,
json_object_new_string(ecommunity_str(ecom)));
json_object_object_add(json, "import-rts", json_import_rts);
- json_object_string_add(
- json, "rd",
- prefix_rd2str(&bgp->vrf_prd, buf1, RD_ADDRSTRLEN));
+ json_object_string_addf(json, "rd", "%pRD", &bgp->vrf_prd);
}
if (uj)
@@ -6031,6 +6010,7 @@ DEFUN(no_bgp_evpn_ead_es_rt, no_bgp_evpn_ead_es_rt_cmd,
if (!bgp_evpn_rt_matches_existing(bgp_mh_info->ead_es_export_rtl,
ecomdel)) {
+ ecommunity_free(&ecomdel);
vty_out(vty,
"%% RT specified does not match EAD-ES RT configuration\n");
return CMD_WARNING;
@@ -6165,6 +6145,7 @@ DEFUN (no_bgp_evpn_vni_rt,
if (rt_type == RT_TYPE_IMPORT) {
if (!bgp_evpn_rt_matches_existing(vpn->import_rtl, ecomdel)) {
+ ecommunity_free(&ecomdel);
vty_out(vty,
"%% RT specified does not match configuration for this VNI\n");
return CMD_WARNING;
@@ -6172,6 +6153,7 @@ DEFUN (no_bgp_evpn_vni_rt,
evpn_unconfigure_import_rt(bgp, vpn, ecomdel);
} else if (rt_type == RT_TYPE_EXPORT) {
if (!bgp_evpn_rt_matches_existing(vpn->export_rtl, ecomdel)) {
+ ecommunity_free(&ecomdel);
vty_out(vty,
"%% RT specified does not match configuration for this VNI\n");
return CMD_WARNING;
@@ -6191,6 +6173,7 @@ DEFUN (no_bgp_evpn_vni_rt,
}
if (!found_ecomdel) {
+ ecommunity_free(&ecomdel);
vty_out(vty,
"%% RT specified does not match configuration for this VNI\n");
return CMD_WARNING;
@@ -6267,7 +6250,6 @@ static int vni_cmp(const void **a, const void **b)
void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
safi_t safi)
{
- char buf1[RD_ADDRSTRLEN];
char buf2[INET6_ADDRSTRLEN];
if (bgp->advertise_all_vni)
@@ -6433,8 +6415,7 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
}
}
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_RD_CFGD))
- vty_out(vty, " rd %s\n",
- prefix_rd2str(&bgp->vrf_prd, buf1, sizeof(buf1)));
+ vty_out(vty, " rd %pRD\n", &bgp->vrf_prd);
/* import route-target */
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_RT_CFGD)) {
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index a8accc25f5..a85432a33b 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),
@@ -1464,6 +1467,11 @@ int bgp_stop(struct peer *peer)
/* There is no pending EOR message */
if (gr_info->eor_required == 0) {
+ if (gr_info->t_select_deferral) {
+ void *info = THREAD_ARG(
+ gr_info->t_select_deferral);
+ XFREE(MTYPE_TMP, info);
+ }
THREAD_OFF(gr_info->t_select_deferral);
gr_info->eor_received = 0;
}
diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h
index aaf6c480b2..368c2c5001 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 850657d35e..ced3e1890e 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 510cfa21c9..990c6e1faa 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 5a039b25bc..66eef1aa52 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);
}
}
}
@@ -1988,9 +2110,15 @@ void vpn_handle_router_id_update(struct bgp *bgp, bool withdraw,
bgp->vpn_policy[afi].tovpn_rd = bgp->vrf_prd_auto;
prefix_rd2str(&bgp->vpn_policy[afi].tovpn_rd, buf,
sizeof(buf));
- bgp->vpn_policy[afi].rtlist[edir] =
- ecommunity_str2com(buf,
- ECOMMUNITY_ROUTE_TARGET, 0);
+
+ /* free up pre-existing memory if any and allocate
+ * the ecommunity attribute with new RD/RT
+ */
+ if (bgp->vpn_policy[afi].rtlist[edir])
+ ecommunity_free(
+ &bgp->vpn_policy[afi].rtlist[edir]);
+ bgp->vpn_policy[afi].rtlist[edir] = ecommunity_str2com(
+ buf, ECOMMUNITY_ROUTE_TARGET, 0);
/* Update import_vrf rt_list */
ecom = bgp->vpn_policy[afi].rtlist[edir];
diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h
index c5cc7d4294..9af4cdf3a2 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 9ecc2ae4e4..9582ec01ed 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 971b1817c8..075350cd2b 100644
--- a/bgpd/bgp_nexthop.c
+++ b/bgpd/bgp_nexthop.c
@@ -743,7 +743,6 @@ static void bgp_show_nexthop_paths(struct vty *vty, struct bgp *bgp,
safi_t safi;
struct bgp_table *table;
struct bgp *bgp_path;
- char buf1[BUFSIZ];
vty_out(vty, " Paths:\n");
LIST_FOREACH (path, &(bnc->paths), nh_thread) {
@@ -754,12 +753,13 @@ static void bgp_show_nexthop_paths(struct vty *vty, struct bgp *bgp,
safi = table->safi;
bgp_path = table->bgp;
- if (dest->pdest) {
- prefix_rd2str((struct prefix_rd *)bgp_dest_get_prefix(dest->pdest),
- buf1, sizeof(buf1));
- vty_out(vty, " %d/%d %pBD RD %s %s flags 0x%x\n",
- afi, safi, dest, buf1, bgp_path->name_pretty, path->flags);
- } else
+ if (dest->pdest)
+ vty_out(vty, " %d/%d %pBD RD %pRD %s flags 0x%x\n",
+ afi, safi, dest,
+ (struct prefix_rd *)bgp_dest_get_prefix(
+ dest->pdest),
+ bgp_path->name_pretty, path->flags);
+ else
vty_out(vty, " %d/%d %pBD %s flags 0x%x\n",
afi, safi, dest, bgp_path->name_pretty, path->flags);
}
@@ -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 b38e5b7a9a..7eeab373a0 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)))));
@@ -1145,16 +1146,14 @@ void evaluate_paths(struct bgp_nexthop_cache *bnc)
}
if (BGP_DEBUG(nht, NHT)) {
- char buf1[RD_ADDRSTRLEN];
-
- if (dest->pdest) {
- prefix_rd2str((struct prefix_rd *)bgp_dest_get_prefix(dest->pdest),
- buf1, sizeof(buf1));
+ if (dest->pdest)
zlog_debug(
- "... eval path %d/%d %pBD RD %s %s flags 0x%x",
- afi, safi, dest, buf1,
+ "... eval path %d/%d %pBD RD %pRD %s flags 0x%x",
+ afi, safi, dest,
+ (struct prefix_rd *)bgp_dest_get_prefix(
+ dest->pdest),
bgp_path->name_pretty, path->flags);
- } else
+ else
zlog_debug(
"... eval path %d/%d %pBD %s flags 0x%x",
afi, safi, dest, bgp_path->name_pretty,
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index 7248f034a5..d1667fac26 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -1185,15 +1185,30 @@ as_t peek_for_as4_capability(struct peer *peer, uint16_t length)
uint8_t opt_type;
uint16_t opt_length;
- /* Check the length. */
- if (stream_get_getp(s) + 2 > end)
+ /* Ensure we can read the option type */
+ if (stream_get_getp(s) + 1 > end)
goto end;
- /* Fetch option type and length. */
+ /* Fetch the option type */
opt_type = stream_getc(s);
- opt_length = BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(peer)
- ? stream_getw(s)
- : stream_getc(s);
+
+ /*
+ * Check the length and fetch the opt_length
+ * If the peer is BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(peer)
+ * then we do a getw which is 2 bytes. So we need to
+ * ensure that we can read that as well
+ */
+ if (BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(peer)) {
+ if (stream_get_getp(s) + 2 > end)
+ goto end;
+
+ opt_length = stream_getw(s);
+ } else {
+ if (stream_get_getp(s) + 1 > end)
+ goto end;
+
+ opt_length = stream_getc(s);
+ }
/* Option length check. */
if (stream_get_getp(s) + opt_length > end)
@@ -1263,19 +1278,40 @@ int bgp_open_option_parse(struct peer *peer, uint16_t length,
uint8_t opt_type;
uint16_t opt_length;
- /* Must have at least an OPEN option header */
- if (STREAM_READABLE(s) < 2) {
+ /*
+ * Check that we can read the opt_type and fetch it
+ */
+ if (STREAM_READABLE(s) < 1) {
zlog_info("%s Option length error", peer->host);
bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR,
BGP_NOTIFY_OPEN_MALFORMED_ATTR);
return -1;
}
-
- /* Fetch option type and length. */
opt_type = stream_getc(s);
- opt_length = BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(peer)
- ? stream_getw(s)
- : stream_getc(s);
+
+ /*
+ * Check the length of the stream to ensure that
+ * FRR can properly read the opt_length. Then read it
+ */
+ if (BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(peer)) {
+ if (STREAM_READABLE(s) < 2) {
+ zlog_info("%s Option length error", peer->host);
+ bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR,
+ BGP_NOTIFY_OPEN_MALFORMED_ATTR);
+ return -1;
+ }
+
+ opt_length = stream_getw(s);
+ } else {
+ if (STREAM_READABLE(s) < 1) {
+ zlog_info("%s Option length error", peer->host);
+ bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR,
+ BGP_NOTIFY_OPEN_MALFORMED_ATTR);
+ return -1;
+ }
+
+ opt_length = stream_getc(s);
+ }
/* Option length check. */
if (STREAM_READABLE(s) < opt_length) {
diff --git a/bgpd/bgp_orr.c b/bgpd/bgp_orr.c
new file mode 100644
index 0000000000..7fed6b775e
--- /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 0000000000..158de30342
--- /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_packet.c b/bgpd/bgp_packet.c
index 90695219a7..8ae31bf2e6 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -360,6 +360,31 @@ int bgp_nlri_parse(struct peer *peer, struct attr *attr,
return BGP_NLRI_PARSE_ERROR;
}
+
+/*
+ * Check if route-refresh request from peer is pending (received before EoR),
+ * and process it now.
+ */
+static void bgp_process_pending_refresh(struct peer *peer, afi_t afi,
+ safi_t safi)
+{
+ if (CHECK_FLAG(peer->af_sflags[afi][safi],
+ PEER_STATUS_REFRESH_PENDING)) {
+ UNSET_FLAG(peer->af_sflags[afi][safi],
+ PEER_STATUS_REFRESH_PENDING);
+ bgp_route_refresh_send(peer, afi, safi, 0, 0, 0,
+ BGP_ROUTE_REFRESH_BORR);
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug(
+ "%pBP sending route-refresh (BoRR) for %s/%s (for pending REQUEST)",
+ peer, afi2str(afi), safi2str(safi));
+
+ SET_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_BORR_SEND);
+ UNSET_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_EORR_SEND);
+ bgp_announce_route(peer, afi, safi, true);
+ }
+}
+
/*
* Checks a variety of conditions to determine whether the peer needs to be
* rescheduled for packet generation again, and does so if necessary.
@@ -558,6 +583,9 @@ void bgp_generate_updgrp_packets(struct thread *thread)
BGP_UPDATE_EOR_PKT(
peer, afi, safi,
s);
+ bgp_process_pending_refresh(
+ peer, afi,
+ safi);
}
}
}
@@ -2026,6 +2054,11 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size)
gr_info->eor_required,
"EOR RCV",
gr_info->eor_received);
+ if (gr_info->t_select_deferral) {
+ void *info = THREAD_ARG(
+ gr_info->t_select_deferral);
+ XFREE(MTYPE_TMP, info);
+ }
THREAD_OFF(gr_info->t_select_deferral);
gr_info->eor_required = 0;
gr_info->eor_received = 0;
@@ -2564,6 +2597,9 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
"%pBP rcvd route-refresh (REQUEST) for %s/%s before EoR",
peer, afi2str(afi),
safi2str(safi));
+ /* Can't send BoRR now, postpone after EoR */
+ SET_FLAG(peer->af_sflags[afi][safi],
+ PEER_STATUS_REFRESH_PENDING);
return BGP_PACKET_NOOP;
}
diff --git a/bgpd/bgp_rd.c b/bgpd/bgp_rd.c
index 9ab48aedc6..b4bcbdb804 100644
--- a/bgpd/bgp_rd.c
+++ b/bgpd/bgp_rd.c
@@ -211,3 +211,17 @@ void form_auto_rd(struct in_addr router_id,
snprintfrr(buf, sizeof(buf), "%pI4:%hu", &router_id, rd_id);
(void)str2prefix_rd(buf, prd);
}
+
+printfrr_ext_autoreg_p("RD", printfrr_prd);
+static ssize_t printfrr_prd(struct fbuf *buf, struct printfrr_eargs *ea,
+ const void *ptr)
+{
+ char rd_buf[RD_ADDRSTRLEN];
+
+ if (!ptr)
+ return bputs(buf, "(null)");
+
+ prefix_rd2str(ptr, rd_buf, sizeof(rd_buf));
+
+ return bputs(buf, rd_buf);
+}
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 162a7ed881..f6b6cb93db 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) {
@@ -5620,8 +5772,8 @@ void bgp_set_stale_route(struct peer *peer, afi_t afi, safi_t safi)
if (bgp_debug_neighbor_events(
peer))
zlog_debug(
- "%s: route-refresh for %s/%s, marking prefix %pFX as stale",
- peer->host,
+ "%pBP route-refresh for %s/%s, marking prefix %pFX as stale",
+ peer,
afi2str(afi),
safi2str(safi),
bgp_dest_get_prefix(
@@ -5649,9 +5801,8 @@ void bgp_set_stale_route(struct peer *peer, afi_t afi, safi_t safi)
BGP_PATH_UNUSEABLE)) {
if (bgp_debug_neighbor_events(peer))
zlog_debug(
- "%s: route-refresh for %s/%s, marking prefix %pFX as stale",
- peer->host,
- afi2str(afi),
+ "%pBP route-refresh for %s/%s, marking prefix %pFX as stale",
+ peer, afi2str(afi),
safi2str(safi),
bgp_dest_get_prefix(
dest));
@@ -6014,6 +6165,7 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p,
/* Unintern original. */
aspath_unintern(&attr.aspath);
bgp_static_withdraw(bgp, p, afi, safi);
+ bgp_dest_unlock_node(dest);
return;
}
@@ -6340,6 +6492,7 @@ static void bgp_static_update_safi(struct bgp *bgp, const struct prefix *p,
aspath_unintern(&attr.aspath);
bgp_static_withdraw_safi(bgp, p, afi, safi,
&bgp_static->prd);
+ bgp_dest_unlock_node(dest);
return;
}
@@ -6383,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,
@@ -6423,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,
@@ -8782,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:
@@ -10081,14 +10237,12 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
dest = parent_ri->net;
if (dest && dest->pdest) {
pdest = dest->pdest;
- prefix_rd2str(
- (struct prefix_rd *)bgp_dest_get_prefix(
- pdest),
- buf1, sizeof(buf1));
if (is_pi_family_evpn(parent_ri)) {
vty_out(vty,
- " Imported from %s:%pFX, VNI %s",
- buf1,
+ " Imported from %pRD:%pFX, VNI %s",
+ (struct prefix_rd *)
+ bgp_dest_get_prefix(
+ pdest),
(struct prefix_evpn *)
bgp_dest_get_prefix(
dest),
@@ -10103,8 +10257,10 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
} else
vty_out(vty,
- " Imported from %s:%pFX\n",
- buf1,
+ " Imported from %pRD:%pFX\n",
+ (struct prefix_rd *)
+ bgp_dest_get_prefix(
+ pdest),
(struct prefix_evpn *)
bgp_dest_get_prefix(
dest));
@@ -10286,11 +10442,17 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
/* Display the IGP cost or 'inaccessible' */
if (!CHECK_FLAG(path->flags, BGP_PATH_VALID)) {
- if (json_paths)
+ bool import = CHECK_FLAG(bgp->flags, BGP_FLAG_IMPORT_CHECK);
+
+ if (json_paths) {
json_object_boolean_false_add(json_nexthop_global,
"accessible");
- else
- vty_out(vty, " (inaccessible)");
+ json_object_boolean_add(json_nexthop_global,
+ "importCheckEnabled", import);
+ } else {
+ vty_out(vty, " (inaccessible%s)",
+ import ? ", import-check enabled" : "");
+ }
} else {
if (path->extra && path->extra->igpmetric) {
if (json_paths)
@@ -11798,7 +11960,6 @@ static void bgp_show_path_info(const struct prefix_rd *pfx_rd,
{
struct bgp_path_info *pi;
int header = 1;
- char rdbuf[RD_ADDRSTRLEN];
json_object *json_header = NULL;
json_object *json_paths = NULL;
const struct prefix *p = bgp_dest_get_prefix(bgp_node);
@@ -11817,10 +11978,9 @@ static void bgp_show_path_info(const struct prefix_rd *pfx_rd,
if (json && !json_paths) {
/* Instantiate json_paths only if path is valid */
json_paths = json_object_new_array();
- if (pfx_rd) {
- prefix_rd2str(pfx_rd, rdbuf, sizeof(rdbuf));
+ if (pfx_rd)
json_header = json_object_new_object();
- } else
+ else
json_header = json;
}
@@ -11846,15 +12006,16 @@ static void bgp_show_path_info(const struct prefix_rd *pfx_rd,
json_object_object_add(json_header, "paths", json_paths);
if (pfx_rd)
- json_object_object_add(json, rdbuf, json_header);
+ json_object_object_addf(json, json_header, "%pRD",
+ 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:
@@ -11863,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;
-
}
}
@@ -12197,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
@@ -12405,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
@@ -12453,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")
@@ -12469,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--;
@@ -12643,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,
@@ -12694,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,
@@ -12733,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,
@@ -15195,7 +15377,6 @@ static void bgp_config_write_network_vpn(struct vty *vty, struct bgp *bgp,
const struct prefix_rd *prd;
struct bgp_static *bgp_static;
mpls_label_t label;
- char rdbuf[RD_ADDRSTRLEN];
/* Network configuration. */
for (pdest = bgp_table_top(bgp->route[afi][safi]); pdest;
@@ -15215,10 +15396,9 @@ static void bgp_config_write_network_vpn(struct vty *vty, struct bgp *bgp,
pdest);
/* "network" configuration display. */
- prefix_rd2str(prd, rdbuf, sizeof(rdbuf));
label = decode_label(&bgp_static->label);
- vty_out(vty, " network %pFX rd %s", p, rdbuf);
+ vty_out(vty, " network %pFX rd %pRD", p, prd);
if (safi == SAFI_MPLS_VPN)
vty_out(vty, " label %u", label);
@@ -15245,7 +15425,6 @@ static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp,
struct bgp_static *bgp_static;
char buf[PREFIX_STRLEN * 2];
char buf2[SU_ADDRSTRLEN];
- char rdbuf[RD_ADDRSTRLEN];
char esi_buf[ESI_STR_LEN];
/* Network configuration. */
@@ -15273,7 +15452,6 @@ static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp,
prd = (struct prefix_rd *)bgp_dest_get_prefix(pdest);
/* "network" configuration display. */
- prefix_rd2str(prd, rdbuf, sizeof(rdbuf));
if (p->u.prefix_evpn.route_type == 5) {
char local_buf[PREFIX_STRLEN];
uint8_t family = is_evpn_prefix_ipaddr_v4((
@@ -15296,9 +15474,8 @@ static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp,
&bgp_static->gatewayIp.u.prefix, buf2,
sizeof(buf2));
vty_out(vty,
- " network %s rd %s ethtag %u label %u esi %s gwip %s routermac %s\n",
- buf, rdbuf,
- p->u.prefix_evpn.prefix_addr.eth_tag,
+ " network %s rd %pRD ethtag %u label %u esi %s gwip %s routermac %s\n",
+ buf, prd, p->u.prefix_evpn.prefix_addr.eth_tag,
decode_label(&bgp_static->label), esi_buf, buf2,
macrouter);
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index ddef4ca1bb..22d28ecd00 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 b90c09c68b..cb7afd8967 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 86cd4f3da1..91d92ebd6d 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 27e3677702..72e70ebf9f 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 d84d0919f7..b85f3707b6 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");
@@ -14735,7 +14833,7 @@ static int bgp_show_neighbor_vty(struct vty *vty, const char *name,
/* "show [ip] bgp neighbors graceful-restart" commands. */
-DEFUN (show_ip_bgp_neighbors_gracrful_restart,
+DEFUN (show_ip_bgp_neighbors_graceful_restart,
show_ip_bgp_neighbors_graceful_restart_cmd,
"show bgp [<ipv4|ipv6>] neighbors [<A.B.C.D|X:X::X:X|WORD>] graceful-restart [json]",
SHOW_STR
@@ -14993,7 +15091,6 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name,
struct bgp *bgp;
struct listnode *node;
char *vname;
- char buf1[INET6_ADDRSTRLEN];
char *ecom_str;
enum vpn_policy_direction dir;
@@ -15058,9 +15155,9 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name,
json_object_new_string(vname));
json_object_object_add(json, "exportToVrfs",
json_export_vrfs);
- json_object_string_add(json, "routeDistinguisher",
- prefix_rd2str(&bgp->vpn_policy[afi].tovpn_rd,
- buf1, RD_ADDRSTRLEN));
+ json_object_string_addf(json, "routeDistinguisher",
+ "%pRD",
+ &bgp->vpn_policy[afi].tovpn_rd);
dir = BGP_VPN_POLICY_DIR_TOVPN;
if (bgp->vpn_policy[afi].rtlist[dir]) {
@@ -15129,9 +15226,8 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name,
node, vname))
vty_out(vty, " %s\n", vname);
- vty_out(vty, "RD: %s\n",
- prefix_rd2str(&bgp->vpn_policy[afi].tovpn_rd,
- buf1, RD_ADDRSTRLEN));
+ vty_out(vty, "RD: %pRD\n",
+ &bgp->vpn_policy[afi].tovpn_rd);
dir = BGP_VPN_POLICY_DIR_TOVPN;
if (bgp->vpn_policy[afi].rtlist[dir]) {
@@ -16621,13 +16717,10 @@ static void bgp_vpn_policy_config_write_afi(struct vty *vty, struct bgp *bgp,
tovpn_sid_index);
}
- if (CHECK_FLAG(bgp->vpn_policy[afi].flags,
- BGP_VPN_POLICY_TOVPN_RD_SET)) {
- char buf[RD_ADDRSTRLEN];
- vty_out(vty, "%*srd vpn export %s\n", indent, "",
- prefix_rd2str(&bgp->vpn_policy[afi].tovpn_rd, buf,
- sizeof(buf)));
- }
+ if (CHECK_FLAG(bgp->vpn_policy[afi].flags, BGP_VPN_POLICY_TOVPN_RD_SET))
+ vty_out(vty, "%*srd vpn export %pRD\n", indent, "",
+ &bgp->vpn_policy[afi].tovpn_rd);
+
if (CHECK_FLAG(bgp->vpn_policy[afi].flags,
BGP_VPN_POLICY_TOVPN_NEXTHOP_SET)) {
@@ -17295,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(
@@ -17344,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,
@@ -17450,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");
}
@@ -17722,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,
@@ -18956,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);
@@ -19466,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);
@@ -19601,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 7dfb5046dd..b5c13fddd0 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));
@@ -307,6 +310,11 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS)
{
struct connected *ifc;
struct bgp *bgp;
+ struct peer *peer;
+ struct prefix *addr;
+ struct listnode *node, *nnode;
+ afi_t afi;
+ safi_t safi;
bgp = bgp_lookup_by_vrf_id(vrf_id);
@@ -332,6 +340,48 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS)
if (IN6_IS_ADDR_LINKLOCAL(&ifc->address->u.prefix6)
&& !list_isempty(ifc->ifp->nbr_connected))
bgp_start_interface_nbrs(bgp, ifc->ifp);
+ else {
+ addr = ifc->address;
+
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+ if (addr->family == AF_INET)
+ continue;
+
+ /*
+ * If the Peer's interface name matches the
+ * interface name for which BGP received the
+ * update and if the received interface address
+ * is a globalV6 and if the peer is currently
+ * using a v4-mapped-v6 addr or a link local
+ * address, then copy the Rxed global v6 addr
+ * into peer's v6_global and send updates out
+ * with new nexthop addr.
+ */
+ if ((peer->conf_if &&
+ (strcmp(peer->conf_if, ifc->ifp->name) ==
+ 0)) &&
+ !IN6_IS_ADDR_LINKLOCAL(&addr->u.prefix6) &&
+ ((IS_MAPPED_IPV6(
+ &peer->nexthop.v6_global)) ||
+ IN6_IS_ADDR_LINKLOCAL(
+ &peer->nexthop.v6_global))) {
+
+ if (bgp_debug_zebra(ifc->address)) {
+ zlog_debug(
+ "Update peer %pBP's current intf addr %pI6 and send updates",
+ peer,
+ &peer->nexthop
+ .v6_global);
+ }
+ memcpy(&peer->nexthop.v6_global,
+ &addr->u.prefix6,
+ IPV6_MAX_BYTELEN);
+ FOREACH_AFI_SAFI (afi, safi)
+ bgp_announce_route(peer, afi,
+ safi, true);
+ }
+ }
+ }
}
return 0;
@@ -3208,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)
@@ -3280,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 */
@@ -3292,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;
+ }
}
}
@@ -3335,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)
@@ -3789,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 4c151b2d37..40e6c90dfc 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,
@@ -2374,8 +2393,10 @@ void peer_nsf_stop(struct peer *peer)
UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT);
UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE);
- FOREACH_AFI_SAFI_NSF (afi, safi)
+ FOREACH_AFI_SAFI_NSF (afi, safi) {
peer->nsf[afi][safi] = 0;
+ THREAD_OFF(peer->t_llgr_stale[afi][safi]);
+ }
if (peer->t_gr_restart) {
THREAD_OFF(peer->t_gr_restart);
@@ -2758,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;
@@ -3016,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);
@@ -3180,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;
@@ -3615,6 +3641,7 @@ int bgp_delete(struct bgp *bgp)
hook_call(bgp_inst_delete, bgp);
+ THREAD_OFF(bgp->t_condition_check);
THREAD_OFF(bgp->t_startup);
THREAD_OFF(bgp->t_maxmed_onstartup);
THREAD_OFF(bgp->t_update_delay);
@@ -3630,7 +3657,12 @@ int bgp_delete(struct bgp *bgp)
gr_info = &bgp->gr_info[afi][safi];
if (!gr_info)
continue;
+ t = gr_info->t_select_deferral;
+ if (t) {
+ void *info = THREAD_ARG(t);
+ XFREE(MTYPE_TMP, info);
+ }
THREAD_OFF(gr_info->t_select_deferral);
t = gr_info->t_route_select;
@@ -3668,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);
@@ -3713,6 +3742,17 @@ int bgp_delete(struct bgp *bgp)
bgp->vpn_policy[afi].import_redirect_rtlist = NULL;
}
+ /* Free any memory allocated to holding routemap references */
+ for (afi = 0; afi < AFI_MAX; ++afi) {
+ for (enum vpn_policy_direction dir = 0;
+ dir < BGP_VPN_POLICY_DIR_MAX; ++dir) {
+ if (bgp->vpn_policy[afi].rmap_name[dir])
+ XFREE(MTYPE_ROUTE_MAP_NAME,
+ bgp->vpn_policy[afi].rmap_name[dir]);
+ bgp->vpn_policy[afi].rmap[dir] = NULL;
+ }
+ }
+
/* Deregister from Zebra, if needed */
if (IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) {
if (BGP_DEBUG(zebra, ZEBRA))
@@ -3818,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);
@@ -4271,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. */
@@ -4601,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;
@@ -5457,8 +5505,8 @@ void peer_tcp_mss_unset(struct peer *peer)
* being used by a peer has changed (AF specific). Automatically
* initiates inbound or outbound processing as needed.
*/
-static void peer_on_policy_change(struct peer *peer, afi_t afi, safi_t safi,
- int outbound)
+void peer_on_policy_change(struct peer *peer, afi_t afi, safi_t safi,
+ int outbound)
{
if (outbound) {
update_group_adjust_peer(peer_af_find(peer, afi, safi));
@@ -6090,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);
@@ -6116,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)) {
@@ -7200,166 +7242,6 @@ int peer_unsuppress_map_unset(struct peer *peer, afi_t afi, safi_t safi)
return 0;
}
-static void peer_advertise_map_filter_update(struct peer *peer, afi_t afi,
- safi_t safi, const char *amap_name,
- struct route_map *amap,
- const char *cmap_name,
- struct route_map *cmap,
- bool condition, bool set)
-{
- struct bgp_filter *filter;
- bool filter_exists = false;
-
- filter = &peer->filter[afi][safi];
-
- /* advertise-map is already configured. */
- if (filter->advmap.aname) {
- filter_exists = true;
- XFREE(MTYPE_BGP_FILTER_NAME, filter->advmap.aname);
- XFREE(MTYPE_BGP_FILTER_NAME, filter->advmap.cname);
- }
-
- route_map_counter_decrement(filter->advmap.amap);
-
- /* Removed advertise-map configuration */
- if (!set) {
- memset(&filter->advmap, 0, sizeof(filter->advmap));
-
- /* decrement condition_filter_count delete timer if
- * this is the last advertise-map to be removed.
- */
- if (filter_exists)
- bgp_conditional_adv_disable(peer, afi, safi);
-
- return;
- }
-
- /* Update filter data with newly configured values. */
- filter->advmap.aname = XSTRDUP(MTYPE_BGP_FILTER_NAME, amap_name);
- filter->advmap.cname = XSTRDUP(MTYPE_BGP_FILTER_NAME, cmap_name);
- filter->advmap.amap = amap;
- filter->advmap.cmap = cmap;
- filter->advmap.condition = condition;
- route_map_counter_increment(filter->advmap.amap);
- peer->advmap_config_change[afi][safi] = true;
-
- /* Increment condition_filter_count and/or create timer. */
- if (!filter_exists) {
- filter->advmap.update_type = UPDATE_TYPE_ADVERTISE;
- bgp_conditional_adv_enable(peer, afi, safi);
- }
-
- /* Process peer route updates. */
- peer_on_policy_change(peer, afi, safi, 1);
-}
-
-/* Set advertise-map to the peer. */
-int peer_advertise_map_set(struct peer *peer, afi_t afi, safi_t safi,
- const char *advertise_name,
- struct route_map *advertise_map,
- const char *condition_name,
- struct route_map *condition_map, bool condition)
-{
- struct peer *member;
- struct listnode *node, *nnode;
-
- /* Set configuration on peer. */
- peer_advertise_map_filter_update(peer, afi, safi, advertise_name,
- advertise_map, condition_name,
- condition_map, condition, true);
-
- /* Check if handling a regular peer & Skip peer-group mechanics. */
- if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
- /* Set override-flag and process peer route updates. */
- SET_FLAG(peer->filter_override[afi][safi][RMAP_OUT],
- PEER_FT_ADVERTISE_MAP);
- return 0;
- }
-
- /*
- * Set configuration on all peer-group members, unless they are
- * explicitly overriding peer-group configuration.
- */
- for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
- /* Skip peers with overridden configuration. */
- if (CHECK_FLAG(member->filter_override[afi][safi][RMAP_OUT],
- PEER_FT_ADVERTISE_MAP))
- continue;
-
- /* Set configuration on peer-group member. */
- peer_advertise_map_filter_update(
- member, afi, safi, advertise_name, advertise_map,
- condition_name, condition_map, condition, true);
- }
-
- return 0;
-}
-
-/* Unset advertise-map from the peer. */
-int peer_advertise_map_unset(struct peer *peer, afi_t afi, safi_t safi,
- const char *advertise_name,
- struct route_map *advertise_map,
- const char *condition_name,
- struct route_map *condition_map, bool condition)
-{
- struct peer *member;
- struct listnode *node, *nnode;
-
- /* advertise-map is not configured */
- if (!peer->filter[afi][safi].advmap.aname)
- return 0;
-
- /* Unset override-flag unconditionally. */
- UNSET_FLAG(peer->filter_override[afi][safi][RMAP_OUT],
- PEER_FT_ADVERTISE_MAP);
-
- /* Inherit configuration from peer-group if peer is member. */
- if (peer_group_active(peer)) {
- PEER_STR_ATTR_INHERIT(peer, peer->group,
- filter[afi][safi].advmap.aname,
- MTYPE_BGP_FILTER_NAME);
- PEER_ATTR_INHERIT(peer, peer->group,
- filter[afi][safi].advmap.amap);
- } else
- peer_advertise_map_filter_update(
- peer, afi, safi, advertise_name, advertise_map,
- condition_name, condition_map, condition, false);
-
- /* Check if handling a regular peer and skip peer-group mechanics. */
- if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
- /* Process peer route updates. */
- if (BGP_DEBUG(update, UPDATE_OUT))
- zlog_debug("%s: Send normal update to %s for %s",
- __func__, peer->host,
- get_afi_safi_str(afi, safi, false));
-
- return 0;
- }
-
- /*
- * Remove configuration on all peer-group members, unless they are
- * explicitly overriding peer-group configuration.
- */
- for (ALL_LIST_ELEMENTS(peer->group->peer, node, nnode, member)) {
- /* Skip peers with overridden configuration. */
- if (CHECK_FLAG(member->filter_override[afi][safi][RMAP_OUT],
- PEER_FT_ADVERTISE_MAP))
- continue;
- /* Remove configuration on peer-group member. */
- peer_advertise_map_filter_update(
- member, afi, safi, advertise_name, advertise_map,
- condition_name, condition_map, condition, false);
-
- /* Process peer route updates. */
- if (BGP_DEBUG(update, UPDATE_OUT))
- zlog_debug("%s: Send normal update to %s for %s ",
- __func__, member->host,
- get_afi_safi_str(afi, safi, false));
- }
-
- return 0;
-}
-
static bool peer_maximum_prefix_clear_overflow(struct peer *peer)
{
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW))
@@ -8229,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.conf.sample2 b/bgpd/bgpd.conf.sample2
deleted file mode 100644
index d376ad25bc..0000000000
--- a/bgpd/bgpd.conf.sample2
+++ /dev/null
@@ -1,77 +0,0 @@
-!
-! Zebra configuration saved from vty
-! 2002/07/01 03:16:33
-!
-hostname bgpd
-password zebra
-log file bgpd.log
-log stdout
-!
-router bgp 7675
- no bgp default ipv4-unicast
- neighbor 3ffe:506:1000::2 remote-as 7675
- neighbor fe80::200:c0ff:fe30:9be3 remote-as 9377
- neighbor fe80::200:c0ff:fe30:9be3 interface sit3
- neighbor fe80::210:5aff:fe6b:3cee remote-as 7675
- neighbor fe80::210:5aff:fe6b:3cee interface eth0
- neighbor fe80::290:27ff:fe51:84c7 remote-as 4691
- neighbor fe80::290:27ff:fe51:84c7 description DTI
- neighbor fe80::290:27ff:fe51:84c7 interface sit7
- neighbor fe80::2a0:c9ff:fec8:82ec remote-as 7530
- neighbor fe80::2a0:c9ff:fec8:82ec description IRI
- neighbor fe80::2a0:c9ff:fec8:82ec interface sit8
- neighbor fe80::2e0:18ff:fe98:2725 remote-as 2500
- neighbor fe80::2e0:18ff:fe98:2725 description WIDE
- neighbor fe80::2e0:18ff:fe98:2725 interface sit5
- neighbor fe80::2e0:18ff:fea8:bf5 remote-as 65000
- neighbor fe80::2e0:18ff:fea8:bf5 interface sit6
-!
- address-family ipv6
- network 3ffe:506::/33
- network 3ffe:1800:e800::/40
- aggregate-address 3ffe:506::/32
- redistribute connected
- neighbor 3ffe:506:1000::2 activate
- neighbor fe80::200:c0ff:fe30:9be3 activate
- neighbor fe80::200:c0ff:fe30:9be3 route-map set-nexthop out
- neighbor fe80::210:5aff:fe6b:3cee activate
- neighbor fe80::290:27ff:fe51:84c7 activate
- neighbor fe80::290:27ff:fe51:84c7 route-map set-nexthop out
- neighbor fe80::2a0:c9ff:fec8:82ec activate
- neighbor fe80::2a0:c9ff:fec8:82ec route-map set-nexthop out
- neighbor fe80::2e0:18ff:fe98:2725 activate
- neighbor fe80::2e0:18ff:fe98:2725 distribute-list nla1 out
- neighbor fe80::2e0:18ff:fe98:2725 route-map set-nexthop out
- neighbor fe80::2e0:18ff:fea8:bf5 activate
- neighbor fe80::2e0:18ff:fea8:bf5 route-map set-nexthop out
- exit-address-family
-!
-ipv6 access-list all permit any
-ipv6 access-list nla1 deny 3ffe:506::/33
-ipv6 access-list nla1 permit 3ffe:506::/32
-ipv6 access-list nla1 deny any
-ipv6 access-list ntt-nla1 permit 3ffe:1800:0:ffff::c/127
-ipv6 access-list ntt-nla1 deny 3ffe:1800:e800::/41
-ipv6 access-list ntt-nla1 permit 3ffe:1800:e800::/40
-ipv6 access-list ntt-nla1 deny any
-!
-ipv6 prefix-list 6bone-filter seq 5 permit 3ffe::/17 ge 24 le 24
-ipv6 prefix-list 6bone-filter seq 10 permit 3ffe:8000::/17 ge 28 le 28
-ipv6 prefix-list 6bone-filter seq 12 deny 3ffe::/16
-ipv6 prefix-list 6bone-filter seq 15 permit 2000::/3 ge 16 le 16
-ipv6 prefix-list 6bone-filter seq 20 permit 2001::/16 ge 35 le 35
-!
-route-map set-nexthop permit 10
- match ipv6 address all
- set ipv6 next-hop global 3ffe:506::1
- set ipv6 next-hop local fe80::cbb5:591a
- set ip next-hop 203.181.89.26
- set community 7675:0
-!
-route-map set-link-local permit 10
- match ipv6 address all
- set ipv6 next-hop local fe80::cbb5:591a
- set ipv6 next-hop global 3ffe:1800:0:ffff::d
-!
-line vty
-!
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 28883c9e7c..44e225b043 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];
@@ -1456,6 +1505,7 @@ struct peer {
#define PEER_STATUS_EORR_RECEIVED (1U << 10) /* EoRR received from peer */
/* LLGR aware peer */
#define PEER_STATUS_LLGR_WAIT (1U << 11)
+#define PEER_STATUS_REFRESH_PENDING (1U << 12) /* refresh request from peer */
/* Configured timer values. */
_Atomic uint32_t holdtime;
@@ -2003,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,
@@ -2025,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,
};
/*
@@ -2077,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
@@ -2214,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 *);
@@ -2324,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);
@@ -2575,7 +2636,8 @@ void peer_tcp_mss_unset(struct peer *peer);
extern void bgp_recalculate_afi_safi_bestpaths(struct bgp *bgp, afi_t afi,
safi_t safi);
-
+extern void peer_on_policy_change(struct peer *peer, afi_t afi, safi_t safi,
+ int outbound);
#ifdef _FRR_ATTRIBUTE_PRINTFRR
/* clang-format off */
#pragma FRR printfrr_ext "%pBP" (struct peer *)
diff --git a/bgpd/rfapi/bgp_rfapi_cfg.c b/bgpd/rfapi/bgp_rfapi_cfg.c
index 831f92996a..eae9859ba1 100644
--- a/bgpd/rfapi/bgp_rfapi_cfg.c
+++ b/bgpd/rfapi/bgp_rfapi_cfg.c
@@ -3913,8 +3913,6 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
}
if (rfg->rd.prefixlen) {
- char buf[RD_ADDRSTRLEN];
-
if (AF_UNIX == rfg->rd.family) {
uint16_t value = 0;
@@ -3927,9 +3925,7 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
value);
} else
- vty_out(vty, " rd %s\n",
- prefix_rd2str(&rfg->rd, buf,
- sizeof(buf)));
+ vty_out(vty, " rd %pRD\n", &rfg->rd);
}
if (rfg->rt_import_list && rfg->rt_export_list
@@ -4137,8 +4133,6 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
vty_out(vty, " vnc defaults\n");
if (hc->default_rd.prefixlen) {
- char buf[RD_ADDRSTRLEN];
-
if (AF_UNIX == hc->default_rd.family) {
uint16_t value = 0;
@@ -4151,10 +4145,8 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
value);
} else
- vty_out(vty, " rd %s\n",
- prefix_rd2str(&hc->default_rd,
- buf,
- sizeof(buf)));
+ vty_out(vty, " rd %pRD\n",
+ &hc->default_rd);
}
if (hc->default_response_lifetime
!= BGP_VNC_DEFAULT_RESPONSE_LIFETIME_DEFAULT) {
@@ -4219,8 +4211,6 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
if (rfg->rd.prefixlen) {
- char buf[RD_ADDRSTRLEN];
-
if (AF_UNIX == rfg->rd.family) {
uint16_t value = 0;
@@ -4235,10 +4225,8 @@ int bgp_rfapi_cfg_write(struct vty *vty, struct bgp *bgp)
value);
} else
- vty_out(vty, " rd %s\n",
- prefix_rd2str(
- &rfg->rd, buf,
- sizeof(buf)));
+ vty_out(vty, " rd %pRD\n",
+ &rfg->rd);
}
if (rfg->flags & RFAPI_RFG_RESPONSE_LIFETIME) {
vty_out(vty, " response-lifetime ");
diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c
index a34c10d842..ed0714ce2d 100644
--- a/bgpd/rfapi/rfapi.c
+++ b/bgpd/rfapi/rfapi.c
@@ -362,7 +362,6 @@ void del_vnc_route(struct rfapi_descriptor *rfd,
afi_t afi; /* of the VN address */
struct bgp_dest *bn;
struct bgp_path_info *bpi;
- char buf2[RD_ADDRSTRLEN];
struct prefix_rd prd0;
afi = family2afi(p->family);
@@ -377,9 +376,9 @@ void del_vnc_route(struct rfapi_descriptor *rfd,
bn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, p, prd);
vnc_zlog_debug_verbose(
- "%s: peer=%p, prefix=%pFX, prd=%s afi=%d, safi=%d bn=%p, bn->info=%p",
- __func__, peer, p, prefix_rd2str(prd, buf2, sizeof(buf2)), afi,
- safi, bn, (bn ? bgp_dest_get_bgp_path_info(bn) : NULL));
+ "%s: peer=%p, prefix=%pFX, prd=%pRD afi=%d, safi=%d bn=%p, bn->info=%p",
+ __func__, peer, p, prd, afi, safi, bn,
+ (bn ? bgp_dest_get_bgp_path_info(bn) : NULL));
for (bpi = (bn ? bgp_dest_get_bgp_path_info(bn) : NULL); bpi;
bpi = bpi->next) {
@@ -577,7 +576,6 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
struct bgp_attr_encap_subtlv *encaptlv;
char buf[PREFIX_STRLEN];
- char buf2[RD_ADDRSTRLEN];
struct rfapi_nexthop *lnh = NULL; /* local nexthop */
struct rfapi_vn_option *vo;
@@ -616,8 +614,6 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
else
label_val = MPLS_LABEL_IMPLICIT_NULL;
- prefix_rd2str(prd, buf2, sizeof(buf2));
-
afi = family2afi(p->family);
assert(afi == AFI_IP || afi == AFI_IP6);
@@ -1070,8 +1066,8 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
bgp_process(bgp, bn, afi, safi);
vnc_zlog_debug_any(
- "%s: Added route (safi=%s) at prefix %s (bn=%p, prd=%s)",
- __func__, safi2str(safi), buf, bn, buf2);
+ "%s: Added route (safi=%s) at prefix %s (bn=%p, prd=%pRD)",
+ __func__, safi2str(safi), buf, bn, prd);
done:
/* Loop back to import tables */
@@ -3724,12 +3720,7 @@ int rfapi_set_autord_from_vn(struct prefix_rd *rd, struct rfapi_ip_addr *vn)
memcpy(rd->val + 2, &vn->addr.v6.s6_addr32[3],
4); /* low order 4 bytes */
}
- {
- char buf[RD_ADDRSTRLEN];
-
- vnc_zlog_debug_verbose("%s: auto-RD is set to %s", __func__,
- prefix_rd2str(rd, buf, sizeof(buf)));
- }
+ vnc_zlog_debug_verbose("%s: auto-RD is set to %pRD", __func__, rd);
return 0;
}
diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c
index be64153cef..1dd623d3f3 100644
--- a/bgpd/rfapi/rfapi_import.c
+++ b/bgpd/rfapi/rfapi_import.c
@@ -2091,14 +2091,8 @@ static void rfapiItBiIndexAdd(struct agg_node *rn, /* Import table VPN node */
assert(bpi);
assert(bpi->extra);
- {
- char buf[RD_ADDRSTRLEN];
-
- vnc_zlog_debug_verbose("%s: bpi %p, peer %p, rd %s", __func__,
- bpi, bpi->peer,
- prefix_rd2str(&bpi->extra->vnc.import.rd,
- buf, sizeof(buf)));
- }
+ vnc_zlog_debug_verbose("%s: bpi %p, peer %p, rd %pRD", __func__, bpi,
+ bpi->peer, &bpi->extra->vnc.import.rd);
sl = RFAPI_RDINDEX_W_ALLOC(rn);
if (!sl) {
@@ -2164,7 +2158,6 @@ static struct bgp_path_info *rfapiItBiIndexSearch(
#ifdef DEBUG_BI_SEARCH
{
- char buf[RD_ADDRSTRLEN];
char buf_aux_pfx[PREFIX_STRLEN];
if (aux_prefix) {
@@ -2173,10 +2166,9 @@ static struct bgp_path_info *rfapiItBiIndexSearch(
} else
strlcpy(buf_aux_pfx, "(nil)", sizeof(buf_aux_pfx));
- vnc_zlog_debug_verbose("%s want prd=%s, peer=%p, aux_prefix=%s",
- __func__,
- prefix_rd2str(prd, buf, sizeof(buf)),
- peer, buf_aux_pfx);
+ vnc_zlog_debug_verbose(
+ "%s want prd=%pRD, peer=%p, aux_prefix=%s", __func__,
+ prd, peer, buf_aux_pfx);
rfapiItBiIndexDump(rn);
}
#endif
@@ -2190,16 +2182,10 @@ static struct bgp_path_info *rfapiItBiIndexSearch(
for (bpi_result = rn->info; bpi_result;
bpi_result = bpi_result->next) {
#ifdef DEBUG_BI_SEARCH
- {
- char buf[RD_ADDRSTRLEN];
-
- vnc_zlog_debug_verbose(
- "%s: bpi has prd=%s, peer=%p", __func__,
- prefix_rd2str(&bpi_result->extra->vnc
- .import.rd,
- buf, sizeof(buf)),
- bpi_result->peer);
- }
+ vnc_zlog_debug_verbose(
+ "%s: bpi has prd=%pRD, peer=%p", __func__,
+ &bpi_result->extra->vnc.import.rd,
+ bpi_result->peer);
#endif
if (peer == bpi_result->peer
&& !prefix_cmp((struct prefix *)&bpi_result->extra
@@ -2261,14 +2247,8 @@ static void rfapiItBiIndexDel(struct agg_node *rn, /* Import table VPN node */
struct skiplist *sl;
int rc;
- {
- char buf[RD_ADDRSTRLEN];
-
- vnc_zlog_debug_verbose("%s: bpi %p, peer %p, rd %s", __func__,
- bpi, bpi->peer,
- prefix_rd2str(&bpi->extra->vnc.import.rd,
- buf, sizeof(buf)));
- }
+ vnc_zlog_debug_verbose("%s: bpi %p, peer %p, rd %pRD", __func__, bpi,
+ bpi->peer, &bpi->extra->vnc.import.rd);
sl = RFAPI_RDINDEX(rn);
assert(sl);
diff --git a/bgpd/rfapi/rfapi_rib.c b/bgpd/rfapi/rfapi_rib.c
index 9e13c48134..50a10c3b1d 100644
--- a/bgpd/rfapi/rfapi_rib.c
+++ b/bgpd/rfapi/rfapi_rib.c
@@ -1104,9 +1104,6 @@ static void process_pending_node(struct bgp *bgp, struct rfapi_descriptor *rfd,
__func__, ri);
} else {
-
- char buf_rd[RD_ADDRSTRLEN];
-
/* not found: add new route to RIB */
ori = rfapi_info_new();
ori->rk = ri->rk;
@@ -1129,16 +1126,9 @@ static void process_pending_node(struct bgp *bgp, struct rfapi_descriptor *rfd,
}
skiplist_insert(slRibPt, &ori->rk, ori);
-#if DEBUG_RIB_SL_RD
- prefix_rd2str(&ori->rk.rd, buf_rd,
- sizeof(buf_rd));
-#else
- buf_rd[0] = 0;
-#endif
-
vnc_zlog_debug_verbose(
- "%s: nomatch lPendCost item %p in slRibPt, added (rd=%s)",
- __func__, ri, buf_rd);
+ "%s: nomatch lPendCost item %p in slRibPt, added (rd=%pRD)",
+ __func__, ri, &ori->rk.rd);
}
/*
@@ -1378,17 +1368,9 @@ callback:
0, delete_list->count);
ri->last_sent_time = monotime(NULL);
#if DEBUG_RIB_SL_RD
- {
- char buf_rd[RD_ADDRSTRLEN];
-
- vnc_zlog_debug_verbose(
- "%s: move route to recently deleted list, rd=%s",
- __func__,
- prefix_rd2str(
- &ri->rk.rd,
- buf_rd,
- sizeof(buf_rd)));
- }
+ vnc_zlog_debug_verbose(
+ "%s: move route to recently deleted list, rd=%pRD",
+ __func__, &ri->rk.rd);
#endif
} else {
@@ -2256,7 +2238,6 @@ static int print_rib_sl(int (*fp)(void *, const char *, ...), struct vty *vty,
char str_lifetime[BUFSIZ];
char str_age[BUFSIZ];
char *p;
- char str_rd[RD_ADDRSTRLEN];
++routes_displayed;
@@ -2284,14 +2265,9 @@ static int print_rib_sl(int (*fp)(void *, const char *, ...), struct vty *vty,
}
#endif
- str_rd[0] = 0; /* start empty */
-#if DEBUG_RIB_SL_RD
- prefix_rd2str(&ri->rk.rd, str_rd, sizeof(str_rd));
-#endif
-
- fp(out, " %c %-20s %-15s %-15s %-4u %-8s %-8s %s\n",
+ fp(out, " %c %-20s %-15s %-15s %-4u %-8s %-8s %pRD\n",
deleted ? 'r' : ' ', *printedprefix ? "" : str_pfx, str_vn,
- str_un, ri->cost, str_lifetime, str_age, str_rd);
+ str_un, ri->cost, str_lifetime, str_age, &ri->rk.rd);
if (!*printedprefix)
*printedprefix = 1;
diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c
index a8ab618417..23f43fa7d3 100644
--- a/bgpd/rfapi/rfapi_vty.c
+++ b/bgpd/rfapi/rfapi_vty.c
@@ -1537,14 +1537,6 @@ void rfapiPrintRfapiIpPrefix(void *stream, struct rfapi_ip_prefix *p)
fp(out, "?/?:?");
}
-void rfapiPrintRd(struct vty *vty, struct prefix_rd *prd)
-{
- char buf[RD_ADDRSTRLEN];
-
- prefix_rd2str(prd, buf, sizeof(buf));
- vty_out(vty, "%s", buf);
-}
-
void rfapiPrintAdvertisedInfo(struct vty *vty, struct rfapi_descriptor *rfd,
safi_t safi, struct prefix *p)
{
@@ -1615,7 +1607,7 @@ void rfapiPrintDescriptor(struct vty *vty, struct rfapi_descriptor *rfd)
vty_out(vty, " ");
rfapiPrintRfapiIpAddr(vty, &rfd->vn_addr);
vty_out(vty, " %p %p ", rfd->response_cb, rfd->cookie);
- rfapiPrintRd(vty, &rfd->rd);
+ vty_out(vty, "%pRD", &rfd->rd);
vty_out(vty, " %d", rfd->response_lifetime);
vty_out(vty, " %s", (rfd->rfg ? rfd->rfg->name : "<orphaned>"));
vty_out(vty, "%s", HVTYNL);
diff --git a/bgpd/rfapi/rfapi_vty.h b/bgpd/rfapi/rfapi_vty.h
index b5e1c38b0d..09e1b3c4c4 100644
--- a/bgpd/rfapi/rfapi_vty.h
+++ b/bgpd/rfapi/rfapi_vty.h
@@ -93,8 +93,6 @@ extern void rfapiPrintRfapiIpAddr(void *stream, struct rfapi_ip_addr *a);
extern void rfapiPrintRfapiIpPrefix(void *stream, struct rfapi_ip_prefix *p);
-void rfapiPrintRd(struct vty *vty, struct prefix_rd *prd);
-
extern void rfapiPrintAdvertisedInfo(struct vty *vty,
struct rfapi_descriptor *rfd, safi_t safi,
struct prefix *p);
diff --git a/bgpd/subdir.am b/bgpd/subdir.am
index b1eeb937e1..765650313b 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 00251fa38b..4cbdfe0fcc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -7,7 +7,7 @@
##
AC_PREREQ([2.69])
-AC_INIT([frr], [8.4-dev], [https://github.com/frrouting/frr/issues])
+AC_INIT([frr], [8.5-dev], [https://github.com/frrouting/frr/issues])
PACKAGE_URL="https://frrouting.org/"
AC_SUBST([PACKAGE_URL])
PACKAGE_FULLNAME="FRRouting"
diff --git a/debian/changelog b/debian/changelog
index 9c14270b66..ad43f13e33 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+frr (8.5~dev-1) UNRELEASED; urgency=medium
+
+ * FRR Dev 8.5
+
+ -- Donatas Abraitis <donatas@opensourcerouting.org> Tue, 04 Oct 2022 16:00:00 +0500
+
frr (8.4~dev-1) UNRELEASED; urgency=medium
* FRR Dev 8.4
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index bd5767beba..8a16c57e6c 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
@@ -1775,12 +1792,28 @@ Configuring Peers
default, the DelayOpenTimer is disabled. The timer interval may be set to a
duration of 1 to 240 seconds.
+.. clicmd:: neighbor PEER extended-optional-parameters
+
+ Force the extended optional parameters format for OPEN messages. By default,
+ optional parameters length is 255 octets. With more and more BGP capabilities
+ implemented on top of BGP, this is needed to extend this value.
+
+ This is turned off by default, but it's automatically enabled when this limit
+ is hit. You can force this new encoding to be enabled with this command.
+
.. clicmd:: bgp minimum-holdtime (1-65535)
This command allows user to prevent session establishment with BGP 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
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -3462,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
@@ -3488,6 +3834,10 @@ Debugging
library messages and BGP BFD integration messages that are mostly state
transitions and validation problems.
+.. clicmd:: debug bgp conditional-advertisement
+
+ Enable or disable debugging of BGP conditional advertisement.
+
.. clicmd:: debug bgp neighbor-events
Enable or disable debugging for neighbor events. This provides general
@@ -3523,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/ospfd.rst b/doc/user/ospfd.rst
index 26810bd883..3aa3d47f35 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/overview.rst b/doc/user/overview.rst
index 70bfee2835..4a24fa52be 100644
--- a/doc/user/overview.rst
+++ b/doc/user/overview.rst
@@ -310,41 +310,64 @@ BGP
:t:`Autonomous System Confederations for BGP. P. Traina. June 1996.`
- :rfc:`1997`
:t:`BGP Communities Attribute. R. Chandra, P. Traina & T. Li. August 1996.`
+- :rfc:`1998`
+ :t:`An Application of the BGP Community Attribute in Multi-home Routing. E. Chen, T. Bates. August 1996.`
+- :rfc:`2385`
+ :t:`Protection of BGP Sessions via the TCP MD5 Signature Option. A. Heffernan. August 1998.`
- :rfc:`2439`
:t:`BGP Route Flap Damping. C. Villamizar, R. Chandra, R. Govindan. November 1998.`
- :rfc:`2545`
- :t:`Use of BGP-4 Multiprotocol Extensions for IPv6 Inter-Domain Routing. P.
- Marques, F. Dupont. March 1999.`
+ :t:`Use of BGP-4 Multiprotocol Extensions for IPv6 Inter-Domain Routing. P. Marques, F. Dupont. March 1999.`
- :rfc:`2796`
:t:`BGP Route Reflection An alternative to full mesh IBGP. T. Bates & R. Chandrasekeran. June 1996.`
- :rfc:`2842`
:t:`Capabilities Advertisement with BGP-4. R. Chandra, J. Scudder. May 2000.`
- :rfc:`2858`
- :t:`Multiprotocol Extensions for BGP-4. T. Bates, Y. Rekhter, R. Chandra, D.`
+ :t:`Multiprotocol Extensions for BGP-4. T. Bates, Y. Rekhter, R. Chandra, D. Katz. June 2000.`
+- :rfc:`2918`
+ :t:`Route Refresh Capability for BGP-4. E. Chen, September 2000.`
- :rfc:`3107`
:t:`Carrying Label Information in BGP-4. Y. Rekhter & E. Rosen. May 2001.`
- :rfc:`3765`
- :t:`NOPEER Community for Border Gateway Protocol (BGP) Route Scope Control. G.Huston, April 2001.`
+ :t:`NOPEER Community for Border Gateway Protocol (BGP) Route Scope Control. G.Huston. April 2001.`
- :rfc:`4271`
:t:`A Border Gateway Protocol 4 (BGP-4). Updates RFC1771. Y. Rekhter, T. Li & S. Hares. January 2006.`
+- :rfc:`4360`
+ :t:`BGP Extended Communities Attribute. S. Sangli, D. Tappan, Y. Rekhter. February 2006.`
- :rfc:`4364`
- :t:`BGP/MPLS IP Virtual Private Networks (VPNs). Y. Rekhter. Feb 2006.`
+ :t:`BGP/MPLS IP Virtual Private Networks (VPNs). Y. Rekhter. February 2006.`
+- :rfc:`4456`
+ :t:`BGP Route Reflection An alternative to full mesh IBGP. T. Bates, E. Chen, R. Chandra. April 2006.`
- :rfc:`4486`
:t:`Subcodes for BGP Cease Notification Message. E. Chen, V. Gillet. April 2006.`
- :rfc:`4659`
:t:`BGP-MPLS IP Virtual Private Network (VPN) Extension for IPv6 VPN. J. De Clercq, D. Ooms, M. Carugi, F. Le Faucheur. September 2006.`
+- :rfc:`4724`
+ :t:`Graceful Restart Mechanism for BGP. S. Sangli, E. Chen, R. Fernando, J. Scudder, Y. Rekhter. January 2007.`
+- :rfc:`4760`
+ :t:`Multiprotocol Extensions for BGP-4. T. Bates, R. Chandra, D. Katz, Y. Rekhter. January 2007.`
- :rfc:`4893`
:t:`BGP Support for Four-octet AS Number Space. Q. Vohra, E. Chen May 2007.`
- :rfc:`5004`
:t:`Avoid BGP Best Path Transitions from One External to Another. E. Chen & S. Sangli. September 2007 (Partial support).`
+- :rfc:`5065`
+ :t:`Autonomous System Confederations for BGP. P. Traina, D. McPherson, J. Scudder. August 2007.`
- :rfc:`5082`
:t:`The Generalized TTL Security Mechanism (GTSM). V. Gill, J. Heasley, D. Meyer, P. Savola, C. Pingnataro. October 2007.`
+- :rfc:`5291`
+ :t:`Outbound Route Filtering Capability. E. Chen, Y. Rekhter. August 2008.`
+- :rfc:`5292`
+ :t:`Address-Prefix-Based Outbound Route Filter for BGP-4. E. Chen, S. Sangli. August 2008.`
+- :rfc:`5492`
+ :t:`Capabilities Advertisement with BGP-4. J. Scudder, R. Chandra. February 2009.`
- :rfc:`5575`
- :t:`Dissemination of Flow Specification Rules. P. Marques, N. Sheth, R. Raszuk, B. Greene, J. Mauch, D. McPherson. August 2009`
+ :t:`Dissemination of Flow Specification Rules. P. Marques, N. Sheth, R. Raszuk, B. Greene, J. Mauch, D. McPherson. August 2009.`
- :rfc:`5668`
- :t:`4-Octet AS Specific BGP Extended Community. Y. Rekhter, S. Sangli, D. Tappan October 2009`
+ :t:`4-Octet AS Specific BGP Extended Community. Y. Rekhter, S. Sangli, D. Tappan October 2009.`
- :rfc:`6286`
- :t:`Autonomous-System-Wide Unique BGP Identifier for BGP-4. E. Chen, J. Yuan, June 2011.`
+ :t:`Autonomous-System-Wide Unique BGP Identifier for BGP-4. E. Chen, J. Yuan. June 2011.`
+- :rfc:`6472`
+ :t:`Recommendation for Not Using AS_SET and AS_CONFED_SET in BGP. W. Kumari, K. Sriram. December 2011.`
- :rfc:`6608`
:t:`Subcodes for BGP Finite State Machine Error. J. Dong, M. Chen, Huawei Technologies, A. Suryanarayana, Cisco Systems. May 2012.`
- :rfc:`6810`
@@ -353,6 +376,8 @@ BGP
:t:`BGP Prefix Origin Validation. P. Mohapatra, J. Scudder, D. Ward, R. Bush, R. Austein. January 2013.`
- :rfc:`6938`
:t:`Deprecation of BGP Path Attributes: DPA, ADVERTISER, and RCID_PATH / CLUSTER_ID. J. Scudder. May 2013.`
+- :rfc:`6996`
+ :t:`Autonomous System (AS) Reservation for Private Use. J. Mitchell. July 2013.`
- :rfc:`7196`
:t:`Making Route Flap Damping Usable. C. Pelsser, R. Bush, K. Patel, P. Mohapatra, O. Maennel. May 2014.`
- :rfc:`7300`
@@ -365,30 +390,40 @@ BGP
:t:`Codification of AS 0 Processing. W. Kumari, R. Bush, H. Schiller, K. Patel. August 2015.`
- :rfc:`7611`
:t:`BGP ACCEPT_OWN Community Attribute. J. Uttaro, P. Mohapatra, D. Smith, R. Raszuk, J. Scudder. August 2015.`
+- :rfc:`7911`
+ :t:`Advertisement of Multiple Paths in BGP. D. Walton, A. Retana, E. Chen, J. Scudder. July 2016.`
+- :rfc:`7947`
+ :t:`Internet Exchange BGP Route Server. E. Jasinska, N. Hilliard, R. Raszuk, N. Bakker. September 2016.`
- :rfc:`7999`
- :t:`BLACKHOLE Community. T. King, C. Dietzel, J. Snijders, G. Doering, G. Hankins. Oct 2016.`
+ :t:`BLACKHOLE Community. T. King, C. Dietzel, J. Snijders, G. Doering, G. Hankins. October 2016.`
+- :rfc:`8050`
+ :t:`Multi-Threaded Routing Toolkit (MRT) Routing Information Export Format with BGP Additional Path Extensions. C. Petrie, T. King. May 2017.`
- :rfc:`8092`
- :t:`BGP Large Communities Attribute. J. Heitz, Ed., J. Snijders, Ed, K. Patel, I. Bagdonas, N. Hilliard. February 2017`
+ :t:`BGP Large Communities Attribute. J. Heitz, Ed., J. Snijders, Ed, K. Patel, I. Bagdonas, N. Hilliard. February 2017.`
+- :rfc:`8093`
+ :t:`Deprecation of BGP Path Attribute Values 30, 31, 129, 241, 242, and 243. J. Snijders. February 2017.`
- :rfc:`8097`
- :t:`BGP Prefix Origin Validation State Extended Community. P. Mohapatra, K. Patel, J. Scudder, D. Ward, R. Bush. March 2017`
+ :t:`BGP Prefix Origin Validation State Extended Community. P. Mohapatra, K. Patel, J. Scudder, D. Ward, R. Bush. March 2017.`
- :rfc:`8195`
- :t:`Use of BGP Large Communities. J. Snijders, J. Heasley, M. Schmidt, June 2017`
+ :t:`Use of BGP Large Communities. J. Snijders, J. Heasley, M. Schmidt. June 2017.`
- :rfc:`8203`
:t:`BGP Administrative Shutdown Communication. J. Snijders, J. Heitz, J. Scudder. July 2017.`
- :rfc:`8212`
- :t:`Default External BGP (EBGP) Route Propagation Behavior without Policies. J. Mauch, J. Snijders, G. Hankins. July 2017`
+ :t:`Default External BGP (EBGP) Route Propagation Behavior without Policies. J. Mauch, J. Snijders, G. Hankins. July 2017.`
- :rfc:`8277`
- :t:`Using BGP to Bind MPLS Labels to Address Prefixes. E. Rosen. October 2017`
+ :t:`Using BGP to Bind MPLS Labels to Address Prefixes. E. Rosen. October 2017.`
- :rfc:`8538`
- :t:`Notification Message Support for BGP Graceful Restart. K. Patel, R. Fernando, J. Scudder, J. Haas. March 2019`
+ :t:`Notification Message Support for BGP Graceful Restart. K. Patel, R. Fernando, J. Scudder, J. Haas. March 2019.`
- :rfc:`8654`
- :t:`Extended Message Support for BGP. R. Bush, K. Patel, D. Ward. October 2019`
+ :t:`Extended Message Support for BGP. R. Bush, K. Patel, D. Ward. October 2019.`
- :rfc:`9003`
- :t:`Extended BGP Administrative Shutdown Communication. J. Snijders, J. Heitz, J. Scudder, A. Azimov. January 2021`
+ :t:`Extended BGP Administrative Shutdown Communication. J. Snijders, J. Heitz, J. Scudder, A. Azimov. January 2021.`
+- :rfc:`9012`
+ :t:`The BGP Tunnel Encapsulation Attribute. K. Patel, G. Van de Velde, S. Sangli, J. Scudder. April 2021.`
- :rfc:`9072`
- :t:`Extended Optional Parameters Length for BGP OPEN Message. E. Chen, J. Scudder. July 2021`
+ :t:`Extended Optional Parameters Length for BGP OPEN Message. E. Chen, J. Scudder. July 2021.`
- :rfc:`9234`
- :t:`Route Leak Prevention and Detection Using Roles in UPDATE and OPEN Messages. A. Azimov, E. Bogomazov, R. Bush, K. Patel, K. Sriram. May 2022`
+ :t:`Route Leak Prevention and Detection Using Roles in UPDATE and OPEN Messages. A. Azimov, E. Bogomazov, R. Bush, K. Patel, K. Sriram. May 2022.`
OSPF
----
diff --git a/doc/user/pimv6.rst b/doc/user/pimv6.rst
index 843734e217..b242f4fe17 100644
--- a/doc/user/pimv6.rst
+++ b/doc/user/pimv6.rst
@@ -416,6 +416,10 @@ configure CLI mode. If you specify debug commands in the configuration cli
mode, the debug commands can be persistent across restarts of the FRR pim6d if
the config was written out.
+.. clicmd:: debug mld
+
+ This turns on debugging for MLD protocol activity.
+
.. clicmd:: debug pimv6 events
This turns on debugging for PIMv6 system events. Especially timers.
@@ -456,3 +460,15 @@ the config was written out.
.. clicmd:: debug mroute6 detail
This turns on detailed debugging for PIMv6 interaction with kernel MFC cache.
+
+.. clicmd:: debug mld events
+
+ This turns on debugging for MLD system events.
+
+.. clicmd:: debug mld packets
+
+ This turns on information about MLD protocol packets handling.
+
+.. clicmd:: debug mld trace [detail]
+
+ This traces mld code and how it is running.
diff --git a/doc/user/setup.rst b/doc/user/setup.rst
index 25934df9cb..dcc7607e48 100644
--- a/doc/user/setup.rst
+++ b/doc/user/setup.rst
@@ -111,7 +111,7 @@ reasons touched on in the VTYSH documentation and should generally be enabled.
This allows the operator to control the number of open file descriptors
each daemon is allowed to start with. The current assumed value on
most operating systems is 1024. If the operator plans to run bgp with
-several thousands of peers than this is where we would modify FRR to
+several thousands of peers then this is where we would modify FRR to
allow this to happen.
::
diff --git a/doc/user/vtysh.rst b/doc/user/vtysh.rst
index 97b3863ef5..1ab54f09ab 100644
--- a/doc/user/vtysh.rst
+++ b/doc/user/vtysh.rst
@@ -177,11 +177,7 @@ Writing the configuration can be triggered directly by invoking *vtysh -w*.
This may be useful for scripting. Note this command should be run as either the
superuser or the FRR user.
-We recommend you do not mix the use of the two types of files. Further, it is
-better not to use the integrated :file:`frr.conf` file, as any syntax error in
-it can lead to /all/ of your daemons being unable to start up. Per daemon files
-are more robust as impact of errors in configuration are limited to the daemon
-in whose file the error is made.
+We recommend you do not mix the use of the two types of files.
.. clicmd:: service integrated-vtysh-config
diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst
index 05990e2523..01cf5316a3 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/docker/alpine/Dockerfile b/docker/alpine/Dockerfile
index 187b528524..b9278dbb88 100644
--- a/docker/alpine/Dockerfile
+++ b/docker/alpine/Dockerfile
@@ -12,16 +12,6 @@ RUN apk add \
&& echo 'builder ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers
RUN adduser -D -G abuild builder && su builder -c 'abuild-keygen -a -n'
-# This stage builds a libyang APK from source
-FROM alpine-builder as libyang-builder
-RUN mkdir -p /libyang && chown -R builder /pkgs /libyang
-# -- Not currently needed - libyang currently available in Alpine upstream
-# COPY docker/alpine/libyang/ /libyang
-# USER builder
-# RUN cd /libyang \
-# && abuild checksum \
-# && abuild -r -P /pkgs/apk
-
# This stage builds a dist tarball from the source
FROM alpine:3.15 as source-builder
@@ -36,14 +26,7 @@ RUN source /src/alpine/APKBUILD.in \
py-pip \
rtrlib \
&& pip install pytest
-
RUN mkdir -p /pkgs/apk
-# -- Not needed while libyang is not built
-# COPY --from=libyang-builder /pkgs/apk/ /pkgs/apk/
-# RUN apk add \
-# --no-cache \
-# --allow-untrusted /pkgs/apk/*/*.apk \
-
COPY . /src
ARG PKGVER
RUN cd /src \
@@ -54,12 +37,7 @@ RUN cd /src \
&& make dist
# This stage builds an APK from the dist tarball
-FROM alpine-builder as frr-apk-builder
-# -- Not needed while libyang is not built
-# COPY --from=libyang-builder /pkgs/apk/ /pkgs/apk/
-# RUN apk add \
-# --no-cache \
-# --allow-untrusted /pkgs/apk/*/*.apk
+FROM alpine-builder as alpine-apk-builder
COPY --from=source-builder /src/frr-*.tar.gz /src/alpine/* /dist/
RUN find /pkgs/apk -type f -name APKINDEX.tar.gz -delete
RUN chown -R builder /dist /pkgs
@@ -72,7 +50,7 @@ RUN cd /dist \
# This stage installs frr from the apk
FROM alpine:3.15
RUN mkdir -p /pkgs/apk
-COPY --from=frr-apk-builder /pkgs/apk/ /pkgs/apk/
+COPY --from=alpine-apk-builder /pkgs/apk/ /pkgs/apk/
RUN apk add \
--no-cache \
--update-cache \
diff --git a/docker/alpine/build.sh b/docker/alpine/build.sh
index 3132feb9f1..80ee81c821 100755
--- a/docker/alpine/build.sh
+++ b/docker/alpine/build.sh
@@ -25,7 +25,16 @@ docker build \
--target=alpine-builder \
.
-CONTAINER_ID="$(docker create "frr:alpine-builder-$GITREV")"
+# Keep .apk files for debugging purposes, docker image as well.
+docker build \
+ --pull \
+ --file=docker/alpine/Dockerfile \
+ --build-arg="PKGVER=$PKGVER" \
+ --tag="frr:alpine-apk-builder-$GITREV" \
+ --target=alpine-apk-builder \
+ .
+
+CONTAINER_ID="$(docker create "frr:alpine-apk-builder-$GITREV")"
docker cp "${CONTAINER_ID}:/pkgs/" docker/alpine
docker rm "${CONTAINER_ID}"
@@ -36,3 +45,4 @@ docker build \
.
docker rmi "frr:alpine-builder-$GITREV"
+docker rmi "frr:alpine-apk-builder-$GITREV"
diff --git a/eigrpd/eigrp_dump.c b/eigrpd/eigrp_dump.c
index e1ad51a9db..b0d34f55e6 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/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index b15b72a262..71ad7bf69e 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -188,12 +188,12 @@ enum {
RTM_SETHWFLAGS = 119,
#define RTM_SETHWFLAGS RTM_SETHWFLAGS
- RTM_NEWTUNNEL = 120,
-#define RTM_NEWTUNNEL RTM_NEWTUNNEL
- RTM_DELTUNNEL,
-#define RTM_DELTUNNEL RTM_DELTUNNEL
- RTM_GETTUNNEL,
-#define RTM_GETTUNNEL RTM_GETTUNNEL
+ RTM_NEWTUNNEL = 120,
+#define RTM_NEWTUNNEL RTM_NEWTUNNEL
+ RTM_DELTUNNEL,
+#define RTM_DELTUNNEL RTM_DELTUNNEL
+ RTM_GETTUNNEL,
+#define RTM_GETTUNNEL RTM_GETTUNNEL
__RTM_MAX,
#define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1)
diff --git a/isisd/fabricd.c b/isisd/fabricd.c
index a37cda1ce1..be035b623d 100644
--- a/isisd/fabricd.c
+++ b/isisd/fabricd.c
@@ -254,8 +254,10 @@ static void fabricd_initial_sync_timeout(struct thread *thread)
{
struct fabricd *f = THREAD_ARG(thread);
- zlog_info("OpenFabric: Initial synchronization on %s timed out!",
- f->initial_sync_circuit->interface->name);
+ if (IS_DEBUG_ADJ_PACKETS)
+ zlog_debug(
+ "OpenFabric: Initial synchronization on %s timed out!",
+ f->initial_sync_circuit->interface->name);
f->initial_sync_state = FABRICD_SYNC_PENDING;
f->initial_sync_circuit = NULL;
}
@@ -282,9 +284,11 @@ void fabricd_initial_sync_hello(struct isis_circuit *circuit)
timeout, &f->initial_sync_timeout);
f->initial_sync_start = monotime(NULL);
- zlog_info("OpenFabric: Started initial synchronization with %s on %s",
- sysid_print(circuit->u.p2p.neighbor->sysid),
- circuit->interface->name);
+ if (IS_DEBUG_ADJ_PACKETS)
+ zlog_debug(
+ "OpenFabric: Started initial synchronization with %s on %s",
+ sysid_print(circuit->u.p2p.neighbor->sysid),
+ circuit->interface->name);
}
bool fabricd_initial_sync_is_in_progress(struct isis_area *area)
diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c
index 214209e647..1b7663fcfd 100644
--- a/isisd/isis_nb_config.c
+++ b/isisd/isis_nb_config.c
@@ -54,8 +54,6 @@
#include "isisd/isis_dr.h"
#include "isisd/isis_zebra.h"
-DEFINE_MTYPE_STATIC(ISISD, ISIS_PLIST_NAME, "ISIS prefix-list name");
-
/*
* XPath: /frr-isisd:isis/instance
*/
diff --git a/isisd/isisd.c b/isisd/isisd.c
index 7dd08cb13b..efea1e5d5e 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -90,6 +90,7 @@ DEFINE_MTYPE_STATIC(ISISD, ISIS_NAME, "ISIS process name");
DEFINE_MTYPE_STATIC(ISISD, ISIS_AREA, "ISIS area");
DEFINE_MTYPE(ISISD, ISIS_AREA_ADDR, "ISIS area address");
DEFINE_MTYPE(ISISD, ISIS_ACL_NAME, "ISIS access-list name");
+DEFINE_MTYPE(ISISD, ISIS_PLIST_NAME, "ISIS prefix-list name");
DEFINE_QOBJ_TYPE(isis_area);
@@ -565,6 +566,11 @@ void isis_area_destroy(struct isis_area *area)
area_mt_finish(area);
+ if (area->rlfa_plist_name[0])
+ XFREE(MTYPE_ISIS_PLIST_NAME, area->rlfa_plist_name[0]);
+ if (area->rlfa_plist_name[1])
+ XFREE(MTYPE_ISIS_PLIST_NAME, area->rlfa_plist_name[1]);
+
XFREE(MTYPE_ISIS_AREA, area);
}
@@ -1694,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;
}
diff --git a/isisd/isisd.h b/isisd/isisd.h
index bc1aa12956..a9c1d60439 100644
--- a/isisd/isisd.h
+++ b/isisd/isisd.h
@@ -254,6 +254,7 @@ DECLARE_QOBJ_TYPE(isis_area);
DECLARE_MTYPE(ISIS_ACL_NAME); /* isis_area->spf_prefix_prioritites */
DECLARE_MTYPE(ISIS_AREA_ADDR); /* isis_area->area_addrs */
+DECLARE_MTYPE(ISIS_PLIST_NAME);
DECLARE_HOOK(isis_area_overload_bit_update, (struct isis_area * area), (area));
diff --git a/ldpd/ldp_vty_cmds.c b/ldpd/ldp_vty_cmds.c
index 11d6930f06..3795cdaf38 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 a23afb1e43..7e171cb309 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"
@@ -2446,6 +2447,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 70e52708a7..42b4406212 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -417,6 +417,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"
@@ -649,6 +650,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 a19bd0c3db..2e56932613 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 4db3e6f1b2..7fa01f70d1 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 f5aecd9f75..aee6981854 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 0000000000..b0c4c48df8
--- /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/prefix.h b/lib/prefix.h
index 7b2f889874..b904311539 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -674,6 +674,7 @@ static inline bool ipv4_mcast_ssm(const struct in_addr *addr)
#pragma FRR printfrr_ext "%pFX" (struct prefix_eth *)
#pragma FRR printfrr_ext "%pFX" (struct prefix_evpn *)
#pragma FRR printfrr_ext "%pFX" (struct prefix_fs *)
+#pragma FRR printfrr_ext "%pRD" (struct prefix_rd *)
#pragma FRR printfrr_ext "%pPSG4" (struct prefix_sg *)
#endif
diff --git a/lib/routemap.c b/lib/routemap.c
index e6310465e3..3a92799991 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -1059,7 +1059,6 @@ static int vty_show_route_map(struct vty *vty, const char *name, bool use_json)
if (map) {
vty_show_route_map_entry(vty, map, json_proto);
- return CMD_SUCCESS;
} else if (!use_json) {
vty_out(vty, "%s: 'route-map %s' not found\n",
frr_protonameinst, name);
@@ -3175,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 a365925854..c2e9de6cfb 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 7a2b8a1c83..de11a9eab3 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 6c80841e3c..694edf7638 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 d6defd7149..e04e700eb6 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 50c410ad24..8aeabb34e6 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 c3ea2a16ff..fb5da9aad2 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 3a8baa2342..53ba9eb12f 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 a16f4f73eb..fe742b912f 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 258a93fb16..59f95c5da2 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 251be7c8d1..e9ba8fc798 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_lsa.c b/ospfd/ospf_lsa.c
index 0df0072f6d..c67181cba6 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 97c15d1e3c..a2a2393c90 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 f4fb858a5f..3c65ac388d 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 2838443892..5577a291be 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 9bd0a844af..3d2133b11a 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 0000000000..eed948b190
--- /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 0000000000..d0a6f6e790
--- /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 6360d8ec60..26f593f089 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 fa9478fced..e7e2b651c5 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 4edc1de811..74213d7de2 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 834bfd0bb0..2578051c2c 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 2a0016ea19..4f0fa6194a 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,
@@ -9892,49 +9893,6 @@ DEFPY(no_ospf_gr_helper_enable,
return CMD_SUCCESS;
}
-#if CONFDATE > 20220921
-CPP_NOTICE(
- "Time to remove the deprecated \"[no] graceful-restart helper-only\" commands")
-#endif
-
-DEFPY_HIDDEN(ospf_gr_helper_only, ospf_gr_helper_only_cmd,
- "graceful-restart helper-only [A.B.C.D]",
- "OSPF Graceful Restart\n"
- "Enable Helper support\n"
- "Advertising router id\n")
-{
- VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf);
- struct in_addr addr;
- int ret;
-
- vty_out(vty,
- "%% This command is deprecated. Please, use `graceful-restart helper enable` instead.\n");
-
- if (argc == 3) {
- ret = inet_aton(argv[2]->arg, &addr);
- if (!ret) {
- vty_out(vty,
- "Please specify the valid routerid address.\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- ospf_gr_helper_support_set_per_routerid(ospf, &addr, OSPF_GR_TRUE);
- return CMD_SUCCESS;
- }
-
- ospf_gr_helper_support_set(ospf, OSPF_GR_TRUE);
-
- return CMD_SUCCESS;
-}
-
-ALIAS_HIDDEN(no_ospf_gr_helper_enable,
- no_ospf_gr_helper_only_cmd,
- "no graceful-restart helper-only [A.B.C.D]",
- NO_STR
- "OSPF Graceful Restart\n"
- "Disable Helper support\n"
- "Advertising router id\n")
-
DEFPY(ospf_gr_helper_enable_lsacheck,
ospf_gr_helper_enable_lsacheck_cmd,
"graceful-restart helper strict-lsa-checking",
@@ -11025,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)
@@ -12737,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);
@@ -12862,8 +12947,6 @@ static void ospf_vty_zebra_init(void)
/*Ospf garcefull restart helper configurations */
install_element(OSPF_NODE, &ospf_gr_helper_enable_cmd);
install_element(OSPF_NODE, &no_ospf_gr_helper_enable_cmd);
- install_element(OSPF_NODE, &ospf_gr_helper_only_cmd);
- install_element(OSPF_NODE, &no_ospf_gr_helper_only_cmd);
install_element(OSPF_NODE, &ospf_gr_helper_enable_lsacheck_cmd);
install_element(OSPF_NODE, &no_ospf_gr_helper_enable_lsacheck_cmd);
install_element(OSPF_NODE, &ospf_gr_helper_supported_grace_time_cmd);
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
index 1754512b5b..4615864244 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 e0c36d86fe..3f82d86921 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 3a43010f85..c7735136bc 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 4f9cbc7b1e..78688fac95 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 4775aa36fb..13e52ac86b 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/pathd/path_ted.c b/pathd/path_ted.c
index 270c664daf..316255a97e 100644
--- a/pathd/path_ted.c
+++ b/pathd/path_ted.c
@@ -243,16 +243,16 @@ uint32_t path_ted_query_type_f(struct ipaddr *local, struct ipaddr *remote)
}
break;
case IPADDR_V6:
- key = (uint64_t)(local->ip._v6_addr.s6_addr32[0] & 0xffffffff)
- | ((uint64_t)local->ip._v6_addr.s6_addr32[1] << 32);
+ key = (uint64_t)ntohl(local->ip._v6_addr.s6_addr32[2]) << 32 |
+ (uint64_t)ntohl(local->ip._v6_addr.s6_addr32[3]);
edge = ls_find_edge_by_key(ted_state_g.ted, key);
if (edge) {
- if ((memcmp(&edge->attributes->standard.remote6,
- &remote->ip._v6_addr,
- sizeof(remote->ip._v6_addr))
- && CHECK_FLAG(edge->attributes->flags,
- LS_ATTR_ADJ_SID))) {
- sid = edge->attributes->adj_sid[0]
+ if ((0 == memcmp(&edge->attributes->standard.remote6,
+ &remote->ip._v6_addr,
+ sizeof(remote->ip._v6_addr)) &&
+ CHECK_FLAG(edge->attributes->flags,
+ LS_ATTR_ADJ_SID6))) {
+ sid = edge->attributes->adj_sid[ADJ_PRI_IPV6]
.sid; /* from primary */
break;
}
@@ -385,7 +385,7 @@ DEFUN (no_path_ted,
"Disable the TE Database functionality\n")
/* clang-format on */
{
- if (ted_state_g.enabled) {
+ if (!ted_state_g.enabled) {
PATH_TED_DEBUG("%s: PATHD-TED: OFF -> OFF", __func__);
return CMD_SUCCESS;
}
@@ -462,7 +462,7 @@ DEFPY (show_pathd_ted_db,
json_object *json = NULL;
if (!ted_state_g.enabled) {
- vty_out(vty, "PATHD TED database is not enabled\n");
+ vty_out(vty, "Traffic Engineering database is not enabled\n");
return CMD_WARNING;
}
if (strcmp(ver_json, "json") == 0) {
diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c
index a2b3431b94..6f53adb334 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 dc84de6bfd..f6b370cee3 100644
--- a/pimd/pim6_cmd.c
+++ b/pimd/pim6_cmd.c
@@ -1558,6 +1558,93 @@ DEFUN_NOSH (show_debugging_pimv6,
pim_debug_config_write(vty);
+ cmd_show_lib_debugs(vty);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (debug_mld,
+ debug_mld_cmd,
+ "[no] debug mld",
+ NO_STR
+ DEBUG_STR
+ DEBUG_MLD_STR)
+{
+ if (!no) {
+ PIM_DO_DEBUG_GM_EVENTS;
+ PIM_DO_DEBUG_GM_PACKETS;
+ PIM_DO_DEBUG_GM_TRACE;
+ } else {
+ PIM_DONT_DEBUG_GM_EVENTS;
+ PIM_DONT_DEBUG_GM_PACKETS;
+ PIM_DONT_DEBUG_GM_TRACE;
+ }
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (debug_mld_events,
+ debug_mld_events_cmd,
+ "[no] debug mld events",
+ NO_STR
+ DEBUG_STR
+ DEBUG_MLD_STR
+ DEBUG_MLD_EVENTS_STR)
+{
+ if (!no)
+ PIM_DO_DEBUG_GM_EVENTS;
+ else
+ PIM_DONT_DEBUG_GM_EVENTS;
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (debug_mld_packets,
+ debug_mld_packets_cmd,
+ "[no] debug mld packets",
+ NO_STR
+ DEBUG_STR
+ DEBUG_MLD_STR
+ DEBUG_MLD_PACKETS_STR)
+{
+ if (!no)
+ PIM_DO_DEBUG_GM_PACKETS;
+ else
+ PIM_DONT_DEBUG_GM_PACKETS;
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (debug_mld_trace,
+ debug_mld_trace_cmd,
+ "[no] debug mld trace",
+ NO_STR
+ DEBUG_STR
+ DEBUG_MLD_STR
+ DEBUG_MLD_TRACE_STR)
+{
+ if (!no)
+ PIM_DO_DEBUG_GM_TRACE;
+ else
+ PIM_DONT_DEBUG_GM_TRACE;
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (debug_mld_trace_detail,
+ debug_mld_trace_detail_cmd,
+ "[no] debug mld trace detail",
+ NO_STR
+ DEBUG_STR
+ DEBUG_MLD_STR
+ DEBUG_MLD_TRACE_STR
+ "detailed\n")
+{
+ if (!no)
+ PIM_DO_DEBUG_GM_TRACE_DETAIL;
+ else
+ PIM_DONT_DEBUG_GM_TRACE_DETAIL;
+
return CMD_SUCCESS;
}
@@ -1693,6 +1780,11 @@ void pim_cmd_init(void)
install_element(ENABLE_NODE, &debug_pimv6_zebra_cmd);
install_element(ENABLE_NODE, &debug_mroute6_cmd);
install_element(ENABLE_NODE, &debug_mroute6_detail_cmd);
+ install_element(ENABLE_NODE, &debug_mld_cmd);
+ install_element(ENABLE_NODE, &debug_mld_events_cmd);
+ install_element(ENABLE_NODE, &debug_mld_packets_cmd);
+ install_element(ENABLE_NODE, &debug_mld_trace_cmd);
+ install_element(ENABLE_NODE, &debug_mld_trace_detail_cmd);
install_element(CONFIG_NODE, &debug_pimv6_cmd);
install_element(CONFIG_NODE, &debug_pimv6_nht_cmd);
@@ -1706,4 +1798,9 @@ void pim_cmd_init(void)
install_element(CONFIG_NODE, &debug_pimv6_zebra_cmd);
install_element(CONFIG_NODE, &debug_mroute6_cmd);
install_element(CONFIG_NODE, &debug_mroute6_detail_cmd);
+ install_element(CONFIG_NODE, &debug_mld_cmd);
+ install_element(CONFIG_NODE, &debug_mld_events_cmd);
+ install_element(CONFIG_NODE, &debug_mld_packets_cmd);
+ install_element(CONFIG_NODE, &debug_mld_trace_cmd);
+ install_element(CONFIG_NODE, &debug_mld_trace_detail_cmd);
}
diff --git a/pimd/pim6_main.c b/pimd/pim6_main.c
index e0b5a87e05..7ac22fd025 100644
--- a/pimd/pim6_main.c
+++ b/pimd/pim6_main.c
@@ -119,9 +119,7 @@ static const struct frr_yang_module_info *const pim6d_yang_modules[] = {
/* clang-format off */
FRR_DAEMON_INFO(pim6d, PIM6,
- .vty_port = 0,
- .flags = FRR_NO_SPLIT_CONFIG,
-
+ .vty_port = PIM6D_VTY_PORT,
.proghelp = "Protocol Independent Multicast (RFC7761) for IPv6",
.signals = pim6d_signals,
diff --git a/pimd/pim6_mld.c b/pimd/pim6_mld.c
index b9c3aec30c..23042ef14e 100644
--- a/pimd/pim6_mld.c
+++ b/pimd/pim6_mld.c
@@ -1609,7 +1609,7 @@ static void gm_t_recv(struct thread *t)
char rxbuf[2048];
struct msghdr mh[1] = {};
struct iovec iov[1];
- struct sockaddr_in6 pkt_src[1];
+ struct sockaddr_in6 pkt_src[1] = {};
ssize_t nread;
size_t pktlen;
@@ -2122,15 +2122,47 @@ static void gm_start(struct interface *ifp)
}
}
-void gm_ifp_teardown(struct interface *ifp)
+void gm_group_delete(struct gm_if *gm_ifp)
{
- struct pim_interface *pim_ifp = ifp->info;
- struct gm_if *gm_ifp;
+ struct gm_sg *sg;
struct gm_packet_state *pkt;
struct gm_grp_pending *pend_grp;
struct gm_gsq_pending *pend_gsq;
struct gm_subscriber *subscriber;
- struct gm_sg *sg;
+
+ while ((pkt = gm_packet_expires_first(gm_ifp->expires)))
+ gm_packet_drop(pkt, false);
+
+ while ((pend_grp = gm_grp_pends_pop(gm_ifp->grp_pends))) {
+ THREAD_OFF(pend_grp->t_expire);
+ XFREE(MTYPE_GM_GRP_PENDING, pend_grp);
+ }
+
+ while ((pend_gsq = gm_gsq_pends_pop(gm_ifp->gsq_pends))) {
+ THREAD_OFF(pend_gsq->t_send);
+ XFREE(MTYPE_GM_GSQ_PENDING, pend_gsq);
+ }
+
+ while ((sg = gm_sgs_pop(gm_ifp->sgs))) {
+ THREAD_OFF(sg->t_sg_expire);
+ assertf(!gm_packet_sg_subs_count(sg->subs_negative), "%pSG",
+ &sg->sgaddr);
+ assertf(!gm_packet_sg_subs_count(sg->subs_positive), "%pSG",
+ &sg->sgaddr);
+
+ gm_sg_free(sg);
+ }
+ while ((subscriber = gm_subscribers_pop(gm_ifp->subscribers))) {
+ assertf(!gm_packets_count(subscriber->packets), "%pPA",
+ &subscriber->addr);
+ XFREE(MTYPE_GM_SUBSCRIBER, subscriber);
+ }
+}
+
+void gm_ifp_teardown(struct interface *ifp)
+{
+ struct pim_interface *pim_ifp = ifp->info;
+ struct gm_if *gm_ifp;
if (!pim_ifp || !pim_ifp->mld)
return;
@@ -2161,34 +2193,7 @@ void gm_ifp_teardown(struct interface *ifp)
gm_vrf_socket_decref(gm_ifp->pim);
- while ((pkt = gm_packet_expires_first(gm_ifp->expires)))
- gm_packet_drop(pkt, false);
-
- while ((pend_grp = gm_grp_pends_pop(gm_ifp->grp_pends))) {
- THREAD_OFF(pend_grp->t_expire);
- XFREE(MTYPE_GM_GRP_PENDING, pend_grp);
- }
-
- while ((pend_gsq = gm_gsq_pends_pop(gm_ifp->gsq_pends))) {
- THREAD_OFF(pend_gsq->t_send);
- XFREE(MTYPE_GM_GSQ_PENDING, pend_gsq);
- }
-
- while ((sg = gm_sgs_pop(gm_ifp->sgs))) {
- THREAD_OFF(sg->t_sg_expire);
- assertf(!gm_packet_sg_subs_count(sg->subs_negative), "%pSG",
- &sg->sgaddr);
- assertf(!gm_packet_sg_subs_count(sg->subs_positive), "%pSG",
- &sg->sgaddr);
-
- gm_sg_free(sg);
- }
-
- while ((subscriber = gm_subscribers_pop(gm_ifp->subscribers))) {
- assertf(!gm_packets_count(subscriber->packets), "%pPA",
- &subscriber->addr);
- XFREE(MTYPE_GM_SUBSCRIBER, subscriber);
- }
+ gm_group_delete(gm_ifp);
gm_grp_pends_fini(gm_ifp->grp_pends);
gm_packet_expires_fini(gm_ifp->expires);
@@ -2308,22 +2313,6 @@ void gm_ifp_update(struct interface *ifp)
}
}
-void gm_group_delete(struct gm_if *gm_ifp)
-{
- struct gm_sg *sg, *sg_start;
-
- sg_start = gm_sgs_first(gm_ifp->sgs);
-
- /* clean up all mld groups */
- frr_each_from (gm_sgs, gm_ifp->sgs, sg, sg_start) {
- THREAD_OFF(sg->t_sg_expire);
- if (sg->oil)
- pim_channel_oil_del(sg->oil, __func__);
- gm_sgs_del(gm_ifp->sgs, sg);
- gm_sg_free(sg);
- }
-}
-
/*
* CLI (show commands only)
*/
@@ -2441,6 +2430,8 @@ static void gm_show_if_one(struct vty *vty, struct interface *ifp,
gm_ifp->t_other_querier);
json_object_int_add(js_if, "timerRobustnessValue",
gm_ifp->cur_qrv);
+ json_object_int_add(js_if, "lastMemberQueryCount",
+ gm_ifp->cur_lmqc);
json_object_int_add(js_if, "timerQueryIntervalMsec",
gm_ifp->cur_query_intv);
json_object_int_add(js_if, "timerQueryResponseTimerMsec",
@@ -2504,13 +2495,13 @@ static void gm_show_if(struct vty *vty, struct vrf *vrf, const char *ifname,
DEFPY(gm_show_interface,
gm_show_interface_cmd,
- "show ipv6 mld [vrf <VRF|all>$vrf_str] interface [IFNAME] [detail$detail|json$json]",
- DEBUG_STR
+ "show ipv6 mld [vrf <VRF|all>$vrf_str] interface [IFNAME | detail$detail] [json$json]",
SHOW_STR
IPV6_STR
MLD_STR
VRF_FULL_CMD_HELP_STR
"MLD interface information\n"
+ "Interface name\n"
"Detailed output\n"
JSON_STR)
{
diff --git a/pimd/pim_addr.h b/pimd/pim_addr.h
index 7852d1788a..d15e978855 100644
--- a/pimd/pim_addr.h
+++ b/pimd/pim_addr.h
@@ -37,6 +37,7 @@ typedef struct in_addr pim_addr;
#define PIM_MAX_BITLEN IPV4_MAX_BITLEN
#define PIM_AF_NAME "ip"
#define PIM_AF_DBG "pim"
+#define GM_AF_DBG "igmp"
#define PIM_MROUTE_DBG "mroute"
#define PIMREG "pimreg"
#define GM "IGMP"
@@ -65,6 +66,7 @@ typedef struct in6_addr pim_addr;
#define PIM_MAX_BITLEN IPV6_MAX_BITLEN
#define PIM_AF_NAME "ipv6"
#define PIM_AF_DBG "pimv6"
+#define GM_AF_DBG "mld"
#define PIM_MROUTE_DBG "mroute6"
#define PIMREG "pim6reg"
#define GM "MLD"
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index c2f7396c18..1ac22f38a3 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/pimd/pim_cmd_common.c b/pimd/pim_cmd_common.c
index 70c1544717..9283016d08 100644
--- a/pimd/pim_cmd_common.c
+++ b/pimd/pim_cmd_common.c
@@ -1027,6 +1027,11 @@ void pim_show_state(struct pim_instance *pim, struct vty *vty,
json_object *json)
{
struct channel_oil *c_oil;
+#if PIM_IPV != 4
+ struct ttable *tt = NULL;
+ char *table = NULL;
+#endif
+ char flag[50];
json_object *json_group = NULL;
json_object *json_ifp_in = NULL;
json_object *json_ifp_out = NULL;
@@ -1038,9 +1043,18 @@ void pim_show_state(struct pim_instance *pim, struct vty *vty,
if (!json) {
vty_out(vty,
- "Codes: J -> Pim Join, I -> " GM " Report, S -> Source, * -> Inherited from (*,G), V -> VxLAN, M -> Muted");
+ "Codes: J -> Pim Join, I -> " GM " Report, S -> Source, * -> Inherited from (*,G), V -> VxLAN, M -> Muted\n");
+#if PIM_IPV == 4
vty_out(vty,
- "\nActive Source Group RPT IIF OIL\n");
+ "Active Source Group RPT IIF OIL\n");
+#else
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(tt, "Active|Source|Group|RPT|IIF|OIL");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
+#endif
}
frr_each (rb_pim_oil, &pim->channel_oil_head, c_oil) {
@@ -1153,11 +1167,14 @@ void pim_show_state(struct pim_instance *pim, struct vty *vty,
"wrongInterface",
c_oil->cc.wrong_if);
}
- } else
+ }
+#if PIM_IPV == 4
+ else
vty_out(vty, "%-6d %-15pPAs %-15pPAs %-3s %-16s ",
c_oil->installed, oil_origin(c_oil),
oil_mcastgrp(c_oil), isRpt ? "y" : "n",
in_ifname);
+#endif
for (oif_vif_index = 0; oif_vif_index < MAXVIFS;
++oif_vif_index) {
@@ -1199,72 +1216,72 @@ void pim_show_state(struct pim_instance *pim, struct vty *vty,
json_object_object_add(json_ifp_in, out_ifname,
json_ifp_out);
} else {
+ flag[0] = '\0';
+ snprintf(flag, sizeof(flag), "(%c%c%c%c%c)",
+ (c_oil->oif_flags[oif_vif_index] &
+ PIM_OIF_FLAG_PROTO_GM)
+ ? 'I'
+ : ' ',
+ (c_oil->oif_flags[oif_vif_index] &
+ PIM_OIF_FLAG_PROTO_PIM)
+ ? 'J'
+ : ' ',
+ (c_oil->oif_flags[oif_vif_index] &
+ PIM_OIF_FLAG_PROTO_VXLAN)
+ ? 'V'
+ : ' ',
+ (c_oil->oif_flags[oif_vif_index] &
+ PIM_OIF_FLAG_PROTO_STAR)
+ ? '*'
+ : ' ',
+ (c_oil->oif_flags[oif_vif_index] &
+ PIM_OIF_FLAG_MUTE)
+ ? 'M'
+ : ' ');
+
if (first_oif) {
first_oif = 0;
- vty_out(vty, "%s(%c%c%c%c%c)",
- out_ifname,
- (c_oil->oif_flags
- [oif_vif_index] &
- PIM_OIF_FLAG_PROTO_GM)
- ? 'I'
- : ' ',
- (c_oil->oif_flags
- [oif_vif_index] &
- PIM_OIF_FLAG_PROTO_PIM)
- ? 'J'
- : ' ',
- (c_oil->oif_flags
- [oif_vif_index] &
- PIM_OIF_FLAG_PROTO_VXLAN)
- ? 'V'
- : ' ',
- (c_oil->oif_flags
- [oif_vif_index] &
- PIM_OIF_FLAG_PROTO_STAR)
- ? '*'
- : ' ',
- (c_oil->oif_flags
- [oif_vif_index] &
- PIM_OIF_FLAG_MUTE)
- ? 'M'
- : ' ');
- } else
- vty_out(vty, ", %s(%c%c%c%c%c)",
- out_ifname,
- (c_oil->oif_flags
- [oif_vif_index] &
- PIM_OIF_FLAG_PROTO_GM)
- ? 'I'
- : ' ',
- (c_oil->oif_flags
- [oif_vif_index] &
- PIM_OIF_FLAG_PROTO_PIM)
- ? 'J'
- : ' ',
- (c_oil->oif_flags
- [oif_vif_index] &
- PIM_OIF_FLAG_PROTO_VXLAN)
- ? 'V'
- : ' ',
- (c_oil->oif_flags
- [oif_vif_index] &
- PIM_OIF_FLAG_PROTO_STAR)
- ? '*'
- : ' ',
- (c_oil->oif_flags
- [oif_vif_index] &
- PIM_OIF_FLAG_MUTE)
- ? 'M'
- : ' ');
+#if PIM_IPV == 4
+ vty_out(vty, "%s%s", out_ifname, flag);
+#else
+ ttable_add_row(
+ tt, "%d|%pPAs|%pPAs|%s|%s|%s%s",
+ c_oil->installed,
+ oil_origin(c_oil),
+ oil_mcastgrp(c_oil),
+ isRpt ? "y" : "n", in_ifname,
+ out_ifname, flag);
+#endif
+ } else {
+#if PIM_IPV == 4
+ vty_out(vty, ", %s%s", out_ifname,
+ flag);
+#else
+ ttable_add_row(tt,
+ "%c|%c|%c|%c|%c|%s%s",
+ ' ', ' ', ' ', ' ', ' ',
+ out_ifname, flag);
+#endif
+ }
}
}
-
+#if PIM_IPV == 4
if (!json)
vty_out(vty, "\n");
+#endif
}
- if (!json)
+ /* Dump the generated table. */
+ if (!json) {
+#if PIM_IPV == 4
vty_out(vty, "\n");
+#else
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+ ttable_del(tt);
+#endif
+ }
}
/* pim statistics - just adding only bsm related now.
@@ -1655,9 +1672,9 @@ void pim_show_upstream_rpf(struct pim_instance *pim, struct vty *vty, bool uj)
}
}
-static void pim_show_join_helper(struct vty *vty, struct pim_interface *pim_ifp,
+static void pim_show_join_helper(struct pim_interface *pim_ifp,
struct pim_ifchannel *ch, json_object *json,
- time_t now)
+ time_t now, struct ttable *tt)
{
json_object *json_iface = NULL;
json_object *json_row = NULL;
@@ -1724,8 +1741,8 @@ static void pim_show_join_helper(struct vty *vty, struct pim_interface *pim_ifp,
json_object_object_addf(json_grp, json_row, "%pPAs",
&ch->sg.src);
} else {
- vty_out(vty,
- "%-16s %-15pPAs %-15pPAs %-15pPAs %-10s %8s %-6s %5s\n",
+ ttable_add_row(
+ tt, "%s|%pPAs|%pPAs|%pPAs|%s|%s|%s|%s",
ch->interface->name, &ifaddr, &ch->sg.src, &ch->sg.grp,
pim_ifchannel_ifjoin_name(ch->ifjoin_state, ch->flags),
uptime, expire, prune);
@@ -1806,12 +1823,21 @@ void pim_show_join(struct pim_instance *pim, struct vty *vty, pim_sgaddr *sg,
struct pim_ifchannel *ch;
struct interface *ifp;
time_t now;
+ struct ttable *tt = NULL;
+ char *table = NULL;
now = pim_time_monotonic_sec();
- if (!json)
- vty_out(vty,
- "Interface Address Source Group State Uptime Expire Prune\n");
+ if (!json) {
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(
+ tt,
+ "Interface|Address|Source|Group|State|Uptime|Expire|Prune");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
+ }
FOR_ALL_INTERFACES (pim->vrf, ifp) {
pim_ifp = ifp->info;
@@ -1822,9 +1848,16 @@ void pim_show_join(struct pim_instance *pim, struct vty *vty, pim_sgaddr *sg,
if (!pim_sgaddr_match(ch->sg, *sg))
continue;
- pim_show_join_helper(vty, pim_ifp, ch, json, now);
+ pim_show_join_helper(pim_ifp, ch, json, now, tt);
} /* scan interface channels */
}
+ /* Dump the generated table. */
+ if (!json) {
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+ ttable_del(tt);
+ }
}
static void pim_show_jp_agg_helper(struct interface *ifp,
@@ -1953,6 +1986,8 @@ void pim_show_membership(struct pim_instance *pim, struct vty *vty, bool uj)
enum json_type type;
json_object *json = NULL;
json_object *json_tmp = NULL;
+ struct ttable *tt = NULL;
+ char *table = NULL;
json = json_object_new_object();
@@ -1969,8 +2004,12 @@ void pim_show_membership(struct pim_instance *pim, struct vty *vty, bool uj)
if (uj) {
vty_json(vty, json);
} else {
- vty_out(vty,
- "Interface Address Source Group Membership\n");
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(tt, "Interface|Address|Source|Group|Membership");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
/*
* Example of the json data we are traversing
@@ -2007,34 +2046,40 @@ void pim_show_membership(struct pim_instance *pim, struct vty *vty, bool uj)
type = json_object_get_type(if_field_val);
if (type == json_type_object) {
- vty_out(vty, "%-16s ", key);
+ const char *address, *source,
+ *localMembership;
json_object_object_get_ex(
val, "address", &json_tmp);
- vty_out(vty, "%-15s ",
- json_object_get_string(
- json_tmp));
+ address = json_object_get_string(
+ json_tmp);
json_object_object_get_ex(if_field_val,
"source",
&json_tmp);
- vty_out(vty, "%-15s ",
- json_object_get_string(
- json_tmp));
-
- /* Group */
- vty_out(vty, "%-15s ", if_field_key);
+ source = json_object_get_string(
+ json_tmp);
json_object_object_get_ex(
if_field_val, "localMembership",
&json_tmp);
- vty_out(vty, "%-10s\n",
+ localMembership =
json_object_get_string(
- json_tmp));
+ json_tmp);
+
+ ttable_add_row(tt, "%s|%s|%s|%s|%s",
+ key, address, source,
+ if_field_key,
+ localMembership);
}
}
}
json_object_free(json);
+ /* Dump the generated table. */
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+ ttable_del(tt);
}
}
@@ -3179,6 +3224,8 @@ void pim_show_neighbors(struct pim_instance *pim, struct vty *vty,
struct interface *ifp;
struct pim_interface *pim_ifp;
struct pim_neighbor *neigh;
+ struct ttable *tt = NULL;
+ char *table = NULL;
time_t now;
char uptime[10];
char expire[10];
@@ -3189,8 +3236,12 @@ void pim_show_neighbors(struct pim_instance *pim, struct vty *vty,
now = pim_time_monotonic_sec();
if (!json) {
- vty_out(vty,
- "Interface Neighbor Uptime Holdtime DR Pri\n");
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(tt, "Interface|Neighbor|Uptime|Holdtime|DR Pri");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
}
FOR_ALL_INTERFACES (pim->vrf, ifp) {
@@ -3232,9 +3283,10 @@ void pim_show_neighbors(struct pim_instance *pim, struct vty *vty,
neigh_src_str, json_row);
} else {
- vty_out(vty, "%-16s %15s %8s %8s %6d\n",
- ifp->name, neigh_src_str, uptime,
- expire, neigh->dr_priority);
+ ttable_add_row(tt, "%s|%pPAs|%s|%s|%d",
+ ifp->name, &neigh->source_addr,
+ uptime, expire,
+ neigh->dr_priority);
}
}
@@ -3243,6 +3295,13 @@ void pim_show_neighbors(struct pim_instance *pim, struct vty *vty,
json_ifp_rows = NULL;
}
}
+ /* Dump the generated table. */
+ if (!json) {
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+ ttable_del(tt);
+ }
}
int gm_process_query_max_response_time_cmd(struct vty *vty,
diff --git a/pimd/pim_hello.c b/pimd/pim_hello.c
index 833103c27f..03ce8687e5 100644
--- a/pimd/pim_hello.c
+++ b/pimd/pim_hello.c
@@ -389,8 +389,10 @@ int pim_hello_build_tlv(struct interface *ifp, uint8_t *tlv_buf,
uint8_t *curr = tlv_buf;
uint8_t *pastend = tlv_buf + tlv_buf_size;
uint8_t *tmp;
+#if PIM_IPV == 4
struct pim_interface *pim_ifp = ifp->info;
struct pim_instance *pim = pim_ifp->pim;
+#endif
/*
* Append options
@@ -452,19 +454,20 @@ int pim_hello_build_tlv(struct interface *ifp, uint8_t *tlv_buf,
/* Secondary Address List */
if (ifp->connected->count) {
- curr = pim_tlv_append_addrlist_ucast(curr, pastend,
- ifp->connected, AF_INET);
+ curr = pim_tlv_append_addrlist_ucast(curr, pastend, ifp,
+ PIM_AF);
if (!curr) {
if (PIM_DEBUG_PIM_HELLO) {
zlog_debug(
- "%s: could not set PIM hello v4 Secondary Address List option for interface %s",
- __func__, ifp->name);
+ "%s: could not set PIM hello %s Secondary Address List option for interface %s",
+ __func__, PIM_AF_NAME, ifp->name);
}
return -4;
}
+#if PIM_IPV == 4
if (pim->send_v6_secondary) {
- curr = pim_tlv_append_addrlist_ucast(
- curr, pastend, ifp->connected, AF_INET6);
+ curr = pim_tlv_append_addrlist_ucast(curr, pastend, ifp,
+ AF_INET6);
if (!curr) {
if (PIM_DEBUG_PIM_HELLO) {
zlog_debug(
@@ -474,6 +477,7 @@ int pim_hello_build_tlv(struct interface *ifp, uint8_t *tlv_buf,
return -4;
}
}
+#endif
}
return curr - tlv_buf;
diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c
index 40c4c2306d..6f272f0085 100644
--- a/pimd/pim_iface.c
+++ b/pimd/pim_iface.c
@@ -131,13 +131,13 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool gm, bool pim,
pim_ifp->igmp_version = IGMP_DEFAULT_VERSION;
pim_ifp->mld_version = MLD_DEFAULT_VERSION;
pim_ifp->gm_default_robustness_variable =
- IGMP_DEFAULT_ROBUSTNESS_VARIABLE;
- pim_ifp->gm_default_query_interval = IGMP_GENERAL_QUERY_INTERVAL;
+ GM_DEFAULT_ROBUSTNESS_VARIABLE;
+ pim_ifp->gm_default_query_interval = GM_GENERAL_QUERY_INTERVAL;
pim_ifp->gm_query_max_response_time_dsec =
- IGMP_QUERY_MAX_RESPONSE_TIME_DSEC;
+ GM_QUERY_MAX_RESPONSE_TIME_DSEC;
pim_ifp->gm_specific_query_max_response_time_dsec =
- IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC;
- pim_ifp->gm_last_member_query_count = IGMP_DEFAULT_ROBUSTNESS_VARIABLE;
+ GM_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC;
+ pim_ifp->gm_last_member_query_count = GM_DEFAULT_ROBUSTNESS_VARIABLE;
/* BSM config on interface: true by default */
pim_ifp->bsm_enable = true;
@@ -222,6 +222,9 @@ void pim_if_delete(struct interface *ifp)
list_delete(&pim_ifp->upstream_switch_list);
list_delete(&pim_ifp->sec_addr_list);
+ if (pim_ifp->bfd_config.profile)
+ XFREE(MTYPE_TMP, pim_ifp->bfd_config.profile);
+
XFREE(MTYPE_PIM_INTERFACE, pim_ifp->boundary_oil_plist);
XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
@@ -880,7 +883,7 @@ pim_addr pim_find_primary_addr(struct interface *ifp)
return pim_ifp->update_source;
#if PIM_IPV == 6
- if (pim_ifp)
+ if (pim_ifp && !pim_addr_is_any(pim_ifp->ll_highest))
return pim_ifp->ll_highest;
pim_addr best_addr = PIMADDR_ANY;
diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c
index 57ae15079b..308cba0697 100644
--- a/pimd/pim_igmp.c
+++ b/pimd/pim_igmp.c
@@ -610,10 +610,17 @@ static int igmp_recv_query(struct gm_sock *igmp, int query_version,
ntohl(igmp->ifaddr.s_addr), from_str,
ntohl(from.s_addr));
}
- if (ntohl(from.s_addr) < ntohl(igmp->querier_addr.s_addr))
+ /* Reset the other querier timer only if query is received from
+ * the previously elected querier or a better new querier
+ * This will make sure that non-querier elects the new querier
+ * whose ip address is higher than the old querier
+ * in case the old querier goes down via other querier present
+ * timer expiry
+ */
+ if (ntohl(from.s_addr) <= ntohl(igmp->querier_addr.s_addr)) {
igmp->querier_addr.s_addr = from.s_addr;
-
- pim_igmp_other_querier_timer_on(igmp);
+ pim_igmp_other_querier_timer_on(igmp);
+ }
}
/* IGMP version 3 is the only one where we process the RXed query */
diff --git a/pimd/pim_igmp.h b/pimd/pim_igmp.h
index a642469f27..9ce3a2a17f 100644
--- a/pimd/pim_igmp.h
+++ b/pimd/pim_igmp.h
@@ -56,18 +56,6 @@
#define IGMP_V3_GROUP_RECORD_SOURCE_OFFSET (8)
#define IGMP_CHECKSUM_OFFSET (2)
-/* RFC 3376: 8.1. Robustness Variable - Default: 2 */
-#define IGMP_DEFAULT_ROBUSTNESS_VARIABLE (2)
-
-/* RFC 3376: 8.2. Query Interval - Default: 125 seconds */
-#define IGMP_GENERAL_QUERY_INTERVAL (125)
-
-/* RFC 3376: 8.3. Query Response Interval - Default: 100 deciseconds */
-#define IGMP_QUERY_MAX_RESPONSE_TIME_DSEC (100)
-
-/* RFC 3376: 8.8. Last Member Query Interval - Default: 10 deciseconds */
-#define IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC (10)
-
#define IGMP_DEFAULT_VERSION (3)
#define IGMP_GET_INT16(ptr, output) \
diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c
index 5c81f9b814..12f8ffedfe 100644
--- a/pimd/pim_nb_config.c
+++ b/pimd/pim_nb_config.c
@@ -2844,6 +2844,9 @@ int lib_interface_gmp_address_family_last_member_query_interval_modify(
yang_dnode_get_uint16(args->dnode, NULL);
pim_ifp->gm_specific_query_max_response_time_dsec =
last_member_query_interval;
+#if PIM_IPV == 6
+ gm_ifp_update(ifp);
+#endif
break;
}
@@ -2872,7 +2875,9 @@ int lib_interface_gmp_address_family_robustness_variable_modify(
last_member_query_count =
yang_dnode_get_uint8(args->dnode, NULL);
pim_ifp->gm_last_member_query_count = last_member_query_count;
-
+#if PIM_IPV == 6
+ gm_ifp_update(ifp);
+#endif
break;
}
diff --git a/pimd/pim_tlv.c b/pimd/pim_tlv.c
index 65975ce146..c9caf0016e 100644
--- a/pimd/pim_tlv.c
+++ b/pimd/pim_tlv.c
@@ -29,6 +29,8 @@
#include "pim_tlv.h"
#include "pim_str.h"
#include "pim_msg.h"
+#include "pim_iface.h"
+#include "pim_addr.h"
#if PIM_IPV == 4
#define PIM_MSG_ADDRESS_FAMILY PIM_MSG_ADDRESS_FAMILY_IPV4
@@ -226,12 +228,15 @@ int pim_encode_addr_group(uint8_t *buf, afi_t afi, int bidir, int scope,
}
uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, const uint8_t *buf_pastend,
- struct list *ifconnected, int family)
+ struct interface *ifp, int family)
{
struct listnode *node;
uint16_t option_len = 0;
uint8_t *curr;
size_t uel;
+ struct list *ifconnected = ifp->connected;
+ struct pim_interface *pim_ifp = ifp->info;
+ pim_addr addr;
node = listhead(ifconnected);
@@ -252,7 +257,10 @@ uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, const uint8_t *buf_pastend,
struct prefix *p = ifc->address;
int l_encode;
- if (!CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY))
+ addr = pim_addr_from_prefix(p);
+ if (!pim_addr_cmp(pim_ifp->primary_address, addr))
+ /* don't add the primary address
+ * into the secondary address list */
continue;
if ((curr + uel) > buf_pastend)
diff --git a/pimd/pim_tlv.h b/pimd/pim_tlv.h
index 64b3a0b6ba..63bd2c41f6 100644
--- a/pimd/pim_tlv.h
+++ b/pimd/pim_tlv.h
@@ -82,7 +82,7 @@ uint8_t *pim_tlv_append_2uint16(uint8_t *buf, const uint8_t *buf_pastend,
uint8_t *pim_tlv_append_uint32(uint8_t *buf, const uint8_t *buf_pastend,
uint16_t option_type, uint32_t option_value);
uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, const uint8_t *buf_pastend,
- struct list *ifconnected, int family);
+ struct interface *ifp, int family);
int pim_tlv_parse_holdtime(const char *ifname, pim_addr src_addr,
pim_hello_options *hello_options,
diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c
index d01cb0c873..9021f1e12f 100644
--- a/pimd/pim_vty.c
+++ b/pimd/pim_vty.c
@@ -59,20 +59,20 @@ int pim_debug_config_write(struct vty *vty)
++writes;
}
if (PIM_DEBUG_GM_EVENTS) {
- vty_out(vty, "debug igmp events\n");
+ vty_out(vty, "debug " GM_AF_DBG " events\n");
++writes;
}
if (PIM_DEBUG_GM_PACKETS) {
- vty_out(vty, "debug igmp packets\n");
+ vty_out(vty, "debug " GM_AF_DBG " packets\n");
++writes;
}
/* PIM_DEBUG_GM_TRACE catches _DETAIL too */
if (router->debugs & PIM_MASK_GM_TRACE) {
- vty_out(vty, "debug igmp trace\n");
+ vty_out(vty, "debug " GM_AF_DBG " trace\n");
++writes;
}
if (PIM_DEBUG_GM_TRACE_DETAIL) {
- vty_out(vty, "debug igmp trace detail\n");
+ vty_out(vty, "debug " GM_AF_DBG " trace detail\n");
++writes;
}
@@ -314,14 +314,14 @@ static int gm_config_write(struct vty *vty, int writes,
/* IF ip igmp query-max-response-time */
if (pim_ifp->gm_query_max_response_time_dsec !=
- IGMP_QUERY_MAX_RESPONSE_TIME_DSEC) {
+ GM_QUERY_MAX_RESPONSE_TIME_DSEC) {
vty_out(vty, " ip igmp query-max-response-time %d\n",
pim_ifp->gm_query_max_response_time_dsec);
++writes;
}
/* IF ip igmp query-interval */
- if (pim_ifp->gm_default_query_interval != IGMP_GENERAL_QUERY_INTERVAL) {
+ if (pim_ifp->gm_default_query_interval != GM_GENERAL_QUERY_INTERVAL) {
vty_out(vty, " ip igmp query-interval %d\n",
pim_ifp->gm_default_query_interval);
++writes;
@@ -329,7 +329,7 @@ static int gm_config_write(struct vty *vty, int writes,
/* IF ip igmp last-member_query-count */
if (pim_ifp->gm_last_member_query_count !=
- IGMP_DEFAULT_ROBUSTNESS_VARIABLE) {
+ GM_DEFAULT_ROBUSTNESS_VARIABLE) {
vty_out(vty, " ip igmp last-member-query-count %d\n",
pim_ifp->gm_last_member_query_count);
++writes;
@@ -337,7 +337,7 @@ static int gm_config_write(struct vty *vty, int writes,
/* IF ip igmp last-member_query-interval */
if (pim_ifp->gm_specific_query_max_response_time_dsec !=
- IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC) {
+ GM_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC) {
vty_out(vty, " ip igmp last-member-query-interval %d\n",
pim_ifp->gm_specific_query_max_response_time_dsec);
++writes;
@@ -381,23 +381,23 @@ static int gm_config_write(struct vty *vty, int writes,
/* IF ipv6 mld query-max-response-time */
if (pim_ifp->gm_query_max_response_time_dsec !=
- IGMP_QUERY_MAX_RESPONSE_TIME_DSEC)
+ GM_QUERY_MAX_RESPONSE_TIME_DSEC)
vty_out(vty, " ipv6 mld query-max-response-time %d\n",
pim_ifp->gm_query_max_response_time_dsec);
- if (pim_ifp->gm_default_query_interval != IGMP_GENERAL_QUERY_INTERVAL)
+ if (pim_ifp->gm_default_query_interval != GM_GENERAL_QUERY_INTERVAL)
vty_out(vty, " ipv6 mld query-interval %d\n",
pim_ifp->gm_default_query_interval);
/* IF ipv6 mld last-member_query-count */
if (pim_ifp->gm_last_member_query_count !=
- IGMP_DEFAULT_ROBUSTNESS_VARIABLE)
+ GM_DEFAULT_ROBUSTNESS_VARIABLE)
vty_out(vty, " ipv6 mld last-member-query-count %d\n",
pim_ifp->gm_last_member_query_count);
/* IF ipv6 mld last-member_query-interval */
if (pim_ifp->gm_specific_query_max_response_time_dsec !=
- IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC)
+ GM_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC)
vty_out(vty, " ipv6 mld last-member-query-interval %d\n",
pim_ifp->gm_specific_query_max_response_time_dsec);
diff --git a/pimd/pimd.h b/pimd/pimd.h
index 06fcec2b6e..3a80c24f7c 100644
--- a/pimd/pimd.h
+++ b/pimd/pimd.h
@@ -32,9 +32,8 @@
#include "pim_memory.h"
#include "pim_assert.h"
-#define PIMD_PROGNAME "pimd"
-#define PIMD_DEFAULT_CONFIG "pimd.conf"
#define PIMD_VTY_PORT 2611
+#define PIM6D_VTY_PORT 2622
#define PIM_IP_PROTO_IGMP (2)
#define PIM_IP_PROTO_PIM (103)
@@ -261,6 +260,24 @@ extern uint8_t qpim_ecmp_rebalance_enable;
#define PIM_DONT_DEBUG_VXLAN (router->debugs &= ~PIM_MASK_VXLAN)
#define PIM_DONT_DEBUG_BSM (router->debugs &= ~PIM_MASK_BSM_PROC)
+/* RFC 3376: 8.1. Robustness Variable - Default: 2 for IGMP */
+/* RFC 2710: 7.1. Robustness Variable - Default: 2 for MLD */
+#define GM_DEFAULT_ROBUSTNESS_VARIABLE 2
+
+/* RFC 3376: 8.2. Query Interval - Default: 125 seconds for IGMP */
+/* RFC 2710: 7.2. Query Interval - Default: 125 seconds for MLD */
+#define GM_GENERAL_QUERY_INTERVAL 125
+
+/* RFC 3376: 8.3. Query Response Interval - Default: 100 deciseconds for IGMP */
+/* RFC 2710: 7.3. Query Response Interval - Default: 100 deciseconds for MLD */
+#define GM_QUERY_MAX_RESPONSE_TIME_DSEC 100
+
+/* RFC 3376: 8.8. Last Member Query Interval - Default: 10 deciseconds for IGMP
+ */
+/* RFC 2710: 7.8. Last Listener Query Interval - Default: 10 deciseconds for MLD
+ */
+#define GM_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC 10
+
void pim_router_init(void);
void pim_router_terminate(void);
diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in
index 962541405f..8f469d2a07 100644
--- a/redhat/frr.spec.in
+++ b/redhat/frr.spec.in
@@ -795,6 +795,8 @@ sed -i 's/ -M rpki//' %{_sysconfdir}/frr/daemons
* Wed Jul 20 2022 Martin Winter <mwinter@opensourcerouting.org> - %{version}
+* Tue Oct 04 2022 Donatas Abraitis <donatas@opensourcerouting.org> - 8.4
+
* Wed Jul 13 2022 Jafar Al-Gharaibeh <jafar@atcorp.com> - 8.3
- General:
- Add camelcase json keys in addition to pascalcase (Wrong JSON keys will be depracated)
diff --git a/ripd/rip_debug.c b/ripd/rip_debug.c
index 871ee8e87e..ded62812a7 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 8a321d9a91..8e02f1a6c1 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 539c01b3ec..d36327cb76 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 1e7a13d7dc..755debd0a4 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 3853df7cb0..9b900fccd2 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 9729be7b92..f634b59c75 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 7badd50049..79686158cf 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 c0ace0e258..c0638f4bc4 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 e3579c67a2..feb42909a8 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 0000000000..e69de29bb2
--- /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 0000000000..fa53a42919
--- /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 0000000000..7863ae1650
--- /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 0000000000..cdf8898c90
--- /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 0000000000..829967e361
--- /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 0000000000..8631293730
--- /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 0000000000..7c1ea33a31
--- /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 0000000000..1a5e1a06bc
--- /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 0000000000..71476d2aef
--- /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 0000000000..4f0a6ab0f1
--- /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 0000000000..0369901862
--- /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 0000000000..b598246ef0
--- /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 0000000000..aa3f633bf5
--- /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 0000000000..161530b483
--- /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 b18e32f6bd..42b9b8adb9 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 e4c25ff5cb..1c1a5cdfe4 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 f6ee9ea795..a93061740f 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_conditional_advertisement/test_bgp_conditional_advertisement.py b/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py
index 1097be3d70..0e16b97e4a 100644
--- a/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py
+++ b/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py
@@ -43,10 +43,15 @@ TC21: exist-map routes present in R2's BGP table.
advertise-map routes present in R2's BGP table are advertised to R3.
TC22: exist-map routes not present in R2's BGP table
advertise-map routes present in R2's BGP table are withdrawn from R3.
+TC23: advertise-map with exist-map configuration is removed from a peer
+ send normal BGP update to advertise previously withdrawn routes if any.
+
TC31: non-exist-map routes not present in R2's BGP table
advertise-map routes present in R2's BGP table are advertised to R3.
TC32: non-exist-map routes present in R2's BGP table
advertise-map routes present in R2's BGP table are withdrawn from R3.
+TC33: advertise-map with non-exist-map configuration is removed from a peer
+ send normal BGP update to advertisepreviously withdrawn routes if any.
TC41: non-exist-map route-map configuration removed in R2.
advertise-map routes present in R2's BGP table are advertised to R3.
@@ -221,6 +226,18 @@ def all_routes_withdrawn(router):
return topotest.json_cmp(output, expected)
+def default_route_withdrawn(router):
+ output = json.loads(router.vtysh_cmd("show ip route json"))
+ expected = {
+ "0.0.0.0/0": None,
+ "192.0.2.1/32": [{"protocol": "bgp"}],
+ "192.0.2.5/32": [{"protocol": "bgp"}],
+ "10.139.224.0/20": [{"protocol": "bgp"}],
+ "203.0.113.1/32": [{"protocol": "bgp"}],
+ }
+ return topotest.json_cmp(output, expected)
+
+
# BGP conditional advertisement with route-maps
# EXIST-MAP, ADV-MAP-1 and RMAP-1
def exist_map_routes_present(router):
@@ -252,15 +269,7 @@ def non_exist_map_routes_present(router):
def non_exist_map_routes_not_present(router):
- output = json.loads(router.vtysh_cmd("show ip route json"))
- expected = {
- "0.0.0.0/0": None,
- "192.0.2.1/32": [{"protocol": "bgp"}],
- "192.0.2.5/32": [{"protocol": "bgp"}],
- "10.139.224.0/20": [{"protocol": "bgp"}],
- "203.0.113.1/32": [{"protocol": "bgp"}],
- }
- return topotest.json_cmp(output, expected)
+ return default_route_withdrawn(router)
def exist_map_no_condition_route_map(router):
@@ -389,7 +398,7 @@ passed = "PASSED!!!"
failed = "FAILED!!!"
-def test_bgp_conditional_advertisement_step1():
+def test_bgp_conditional_advertisement_tc_1_1():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
@@ -409,7 +418,7 @@ def test_bgp_conditional_advertisement_step1():
logger.info(msg + passed)
-def test_bgp_conditional_advertisement_step2():
+def test_bgp_conditional_advertisement_tc_2_1():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
@@ -438,7 +447,7 @@ def test_bgp_conditional_advertisement_step2():
logger.info(msg + passed)
-def test_bgp_conditional_advertisement_step3():
+def test_bgp_conditional_advertisement_tc_2_2():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
@@ -467,7 +476,36 @@ def test_bgp_conditional_advertisement_step3():
logger.info(msg + passed)
-def test_bgp_conditional_advertisement_step4():
+def test_bgp_conditional_advertisement_tc_2_3():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
+ # TC23: advertise-map with exist-map configuration is removed from a peer
+ # send normal BGP update to advertise previously withdrawn routes if any.
+ router2.vtysh_cmd(
+ """
+ configure terminal
+ router bgp 2
+ address-family ipv4 unicast
+ no neighbor 10.10.20.3 advertise-map ADV-MAP-1 exist-map EXIST-MAP
+ """
+ )
+
+ test_func = functools.partial(default_route_withdrawn, router3)
+ success, result = topotest.run_and_expect(test_func, None, count=90, wait=1)
+
+ msg = "TC23: advertise-map with exist-map configuration is removed from peer - "
+ assert result is None, msg + failed
+
+ logger.info(msg + passed)
+
+
+def test_bgp_conditional_advertisement_tc_3_1():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
@@ -496,7 +534,7 @@ def test_bgp_conditional_advertisement_step4():
logger.info(msg + passed)
-def test_bgp_conditional_advertisement_step5():
+def test_bgp_conditional_advertisement_tc_3_2():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
@@ -525,7 +563,38 @@ def test_bgp_conditional_advertisement_step5():
logger.info(msg + passed)
-def test_bgp_conditional_advertisement_step6():
+def test_bgp_conditional_advertisement_tc_3_3():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+ router3 = tgen.gears["r3"]
+
+ # TC33: advertise-map with non-exist-map configuration is removed from a peer
+ # send normal BGP update to advertisepreviously withdrawn routes if any.
+ router2.vtysh_cmd(
+ """
+ configure terminal
+ router bgp 2
+ address-family ipv4 unicast
+ no neighbor 10.10.20.3 advertise-map ADV-MAP-1 non-exist-map EXIST-MAP
+ """
+ )
+
+ test_func = functools.partial(all_routes_advertised, router3)
+ success, result = topotest.run_and_expect(test_func, None, count=90, wait=1)
+
+ msg = (
+ "TC33: advertise-map with non-exist-map configuration is removed from a peer - "
+ )
+ assert result is None, msg + failed
+
+ logger.info(msg + passed)
+
+
+def test_bgp_conditional_advertisement_tc_4_1():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
@@ -539,6 +608,9 @@ def test_bgp_conditional_advertisement_step6():
router2.vtysh_cmd(
"""
configure terminal
+ router bgp 2
+ address-family ipv4 unicast
+ neighbor 10.10.20.3 advertise-map ADV-MAP-1 non-exist-map EXIST-MAP
no route-map EXIST-MAP permit 10
"""
)
@@ -552,7 +624,7 @@ def test_bgp_conditional_advertisement_step6():
logger.info(msg + passed)
-def test_bgp_conditional_advertisement_step7():
+def test_bgp_conditional_advertisement_tc_4_2():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
@@ -581,7 +653,7 @@ def test_bgp_conditional_advertisement_step7():
logger.info(msg + passed)
-def test_bgp_conditional_advertisement_step8():
+def test_bgp_conditional_advertisement_tc_5_1():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
@@ -614,7 +686,7 @@ def test_bgp_conditional_advertisement_step8():
logger.info(msg + passed)
-def test_bgp_conditional_advertisement_step9():
+def test_bgp_conditional_advertisement_tc_5_2():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
@@ -643,7 +715,7 @@ def test_bgp_conditional_advertisement_step9():
logger.info(msg + passed)
-def test_bgp_conditional_advertisement_step10():
+def test_bgp_conditional_advertisement_tc_5_3():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
@@ -673,7 +745,7 @@ def test_bgp_conditional_advertisement_step10():
logger.info(msg + passed)
-def test_bgp_conditional_advertisement_step11():
+def test_bgp_conditional_advertisement_tc_5_4():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
@@ -702,7 +774,7 @@ def test_bgp_conditional_advertisement_step11():
logger.info(msg + passed)
-def test_bgp_conditional_advertisement_step12():
+def test_bgp_conditional_advertisement_tc_6_1():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
@@ -740,7 +812,7 @@ def test_bgp_conditional_advertisement_step12():
logger.info(msg + passed)
-def test_bgp_conditional_advertisement_step13():
+def test_bgp_conditional_advertisement_tc_6_2():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
@@ -769,7 +841,7 @@ def test_bgp_conditional_advertisement_step13():
logger.info(msg + passed)
-def test_bgp_conditional_advertisement_step14():
+def test_bgp_conditional_advertisement_tc_6_3():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
@@ -799,7 +871,7 @@ def test_bgp_conditional_advertisement_step14():
logger.info(msg + passed)
-def test_bgp_conditional_advertisement_step15():
+def test_bgp_conditional_advertisement_tc_6_4():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
@@ -830,7 +902,7 @@ def test_bgp_conditional_advertisement_step15():
logger.info(msg + passed)
-def test_bgp_conditional_advertisement_step16():
+def test_bgp_conditional_advertisement_tc_7_1():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
@@ -868,7 +940,7 @@ def test_bgp_conditional_advertisement_step16():
logger.info(msg + passed)
-def test_bgp_conditional_advertisement_step17():
+def test_bgp_conditional_advertisement_tc_7_2():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
@@ -897,7 +969,7 @@ def test_bgp_conditional_advertisement_step17():
logger.info(msg + passed)
-def test_bgp_conditional_advertisement_step18():
+def test_bgp_conditional_advertisement_tc_7_3():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
@@ -927,7 +999,7 @@ def test_bgp_conditional_advertisement_step18():
logger.info(msg + passed)
-def test_bgp_conditional_advertisement_step19():
+def test_bgp_conditional_advertisement_tc_7_4():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
@@ -956,7 +1028,7 @@ def test_bgp_conditional_advertisement_step19():
logger.info(msg + passed)
-def test_bgp_conditional_advertisement_step20():
+def test_bgp_conditional_advertisement_tc_8_1():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
@@ -994,7 +1066,7 @@ def test_bgp_conditional_advertisement_step20():
logger.info(msg + passed)
-def test_bgp_conditional_advertisement_step21():
+def test_bgp_conditional_advertisement_tc_8_2():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
@@ -1023,7 +1095,7 @@ def test_bgp_conditional_advertisement_step21():
logger.info(msg + passed)
-def test_bgp_conditional_advertisement_step22():
+def test_bgp_conditional_advertisement_tc_8_3():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
@@ -1055,7 +1127,7 @@ def test_bgp_conditional_advertisement_step22():
logger.info(msg + passed)
-def test_bgp_conditional_advertisement_step23():
+def test_bgp_conditional_advertisement_tc_8_4():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
@@ -1086,7 +1158,7 @@ def test_bgp_conditional_advertisement_step23():
logger.info(msg + passed)
-def test_bgp_conditional_advertisement_step24():
+def test_bgp_conditional_advertisement_tc_9_1():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
@@ -1124,7 +1196,7 @@ def test_bgp_conditional_advertisement_step24():
logger.info(msg + passed)
-def test_bgp_conditional_advertisement_step25():
+def test_bgp_conditional_advertisement_tc_9_2():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
@@ -1153,7 +1225,7 @@ def test_bgp_conditional_advertisement_step25():
logger.info(msg + passed)
-def test_bgp_conditional_advertisement_step26():
+def test_bgp_conditional_advertisement_tc_9_3():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
@@ -1193,7 +1265,7 @@ def test_bgp_conditional_advertisement_step26():
logger.info(msg + passed)
-def test_bgp_conditional_advertisement_step27():
+def test_bgp_conditional_advertisement_tc_9_4():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
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 2784e956fa..8fd0120dd8 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 704e8fdf04..185a086838 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 2a51dc83ef..9b6480c0d3 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 f155325502..deca4bcfd7 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 dda3bd4b30..a92fde2d0d 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 e4b533b295..b0166033df 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 835ef41de1..f408ff4854 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 3afe38857b..293f3042eb 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 535f272ef4..fe885372d5 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 e60552ed10..4ff62a9785 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 1df77ebeb2..fd1ef097c4 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 6bf8b96309..76522206a4 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 0000000000..e69de29bb2
--- /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 0000000000..50d1583873
--- /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 0000000000..e65bfb2c3a
--- /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 0000000000..97418ca9a0
--- /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 0000000000..758d797ad6
--- /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 0000000000..52ce0d5b57
--- /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 58133c44a9..684d2fcb57 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 a79ce0e3a0..16572a7967 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_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py b/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py
index 4105c3fe63..c070904353 100644
--- a/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py
+++ b/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py
@@ -26,13 +26,17 @@ import os
import sys
import time
import pytest
+import functools
+import json
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
sys.path.append(os.path.join(CWD, "../../"))
-from lib.topogen import Topogen, get_topogen
+
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.common_config import (
write_test_header,
@@ -288,7 +292,6 @@ def test_unnumbered_loopback_ebgp_nbr_p0(request):
" received on R2 BGP and routing table , "
"verify using show ip bgp, show ip route for IPv4 routes ."
)
-
llip = get_llip("r1", "r2-link0")
assert llip is not None, "Testcase {} : Failed \n Error: {}".format(tc_name, llip)
@@ -582,6 +585,195 @@ def test_restart_frr_p2(request):
write_test_footer(tc_name)
+def test_configure_gua_on_unnumbered_intf(request):
+ """
+ Configure a global V6 address on an unnumbered interface on R1
+
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ reset_config_on_routers(tgen)
+
+ step("Configure IPv6 EBGP Unnumbered session between R1 and R2")
+ step("Enable capability extended-nexthop on both the IPv6 BGP peers")
+ step("Activate same IPv6 nbr from IPv4 unicast family")
+ step("Enable cap ext nh on r1 and r2 and activate in ipv4 addr family")
+ step("Verify bgp convergence as ipv6 nbr is enabled on ipv4 addr family.")
+ bgp_convergence = verify_bgp_convergence(tgen, topo)
+ assert bgp_convergence is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, bgp_convergence
+ )
+
+ step(" Configure 5 IPv4 static" " routes on R1, Nexthop as different links of R0")
+ for rte in range(0, NO_OF_RTES):
+ # Create Static routes
+ input_dict = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": NETWORK["ipv4"][rte],
+ "no_of_ip": 1,
+ "next_hop": NEXT_HOP["ipv4"][rte],
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Advertise static routes from IPv4 unicast family and IPv6 "
+ "unicast family respectively from R1 using red static cmd "
+ "Advertise loopback from IPv4 unicast family using network command "
+ "from R1"
+ )
+
+ configure_bgp_on_r1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [{"redist_type": "static"}],
+ "advertise_networks": [
+ {"network": NETWORK_CMD_IP, "no_of_network": 1}
+ ],
+ }
+ },
+ "ipv6": {"unicast": {"redistribute": [{"redist_type": "static"}]}},
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, configure_bgp_on_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ r2 = tgen.gears["r2"]
+
+ def bgp_prefix_received_gua_nh(router):
+ output = json.loads(router.vtysh_cmd("show bgp ipv4 unicast 11.0.20.1/32 json"))
+ expected = {
+ "prefix": "11.0.20.1/32",
+ "paths": [
+ {
+ "nexthops": [
+ {
+ "ip": "5001:dead:beef::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "scope": "global",
+ }
+ ]
+ }
+ ],
+ }
+ return topotest.json_cmp(output, expected)
+
+ def bgp_prefix_received_v4_mapped_v6_nh(router):
+ output = json.loads(router.vtysh_cmd("show bgp ipv4 unicast 11.0.20.1/32 json"))
+ expected = {
+ "prefix": "11.0.20.1/32",
+ "paths": [
+ {
+ "nexthops": [
+ {
+ "ip": "::ffff:a00:501",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "scope": "global",
+ }
+ ]
+ }
+ ],
+ }
+ return topotest.json_cmp(output, expected)
+
+ step("Configure a global V6 address on an unnumbered interface on R1")
+ output = tgen.gears["r1"].vtysh_cmd(
+ """
+ configure terminal
+ interface r1-r2-eth5
+ ipv6 address 5001:dead:beef::1/126
+ !
+ """
+ )
+
+ # verify that r2 has received prefix with GUA as nexthop
+ test_func = functools.partial(bgp_prefix_received_gua_nh, r2)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert (
+ result is None
+ ), "Testcase {} : Failed \n Error: Nexthop for prefix 11.0.20.1 \
+ is not 5001:dead:beef::1".format(
+ tc_name
+ )
+
+ step("Configure a secondary global V6 address on an unnumbered interface on R1")
+ output = tgen.gears["r1"].vtysh_cmd(
+ """
+ configure terminal
+ interface r1-r2-eth5
+ ipv6 address 7771:dead:beef::1/126
+ !
+ """
+ )
+ # verify that r1 did not readvertise the prefix with secondary V6 address as the nexthop
+ test_func = functools.partial(bgp_prefix_received_gua_nh, r2)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert (
+ result is None
+ ), "Testcase {} : Failed \n Error: Nexthop for prefix 11.0.20.1 \
+ is not 5001:dead:beef::1".format(
+ tc_name
+ )
+
+ step("Unconfigure the secondary global V6 address from unnumbered interface on R1")
+ output = tgen.gears["r1"].vtysh_cmd(
+ """
+ configure terminal
+ interface r1-r2-eth5
+ no ipv6 address 7771:dead:beef::1/126
+ !
+ """
+ )
+ # verify that r1 still has the prefix with primary GUA as the nexthop
+ test_func = functools.partial(bgp_prefix_received_gua_nh, r2)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert (
+ result is None
+ ), "Testcase {} : Failed \n Error: Nexthop for prefix 11.0.20.1 \
+ is not 5001:dead:beef::1".format(
+ tc_name
+ )
+
+ step("Unconfigure the primary global V6 address from unnumbered interface on R1")
+ output = tgen.gears["r1"].vtysh_cmd(
+ """
+ configure terminal
+ interface r1-r2-eth5
+ no ipv6 address 5001:dead:beef::1/126
+ !
+ """
+ )
+ # verify that r1 has rcvd the prefix with v4-mapped-v6 address as the nexthop
+ test_func = functools.partial(bgp_prefix_received_v4_mapped_v6_nh, r2)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert (
+ result is None
+ ), "Testcase {} : Failed \n Error: Nexthop for prefix 11.0.20.1 \
+ is not ::ffff:a00:501".format(
+ tc_name
+ )
+
+ write_test_footer(tc_name)
+
+
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_local_as/__init__.py b/tests/topotests/bgp_local_as/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /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 0000000000..fa147d8673
--- /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 0000000000..5b32faeb44
--- /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 0000000000..9c25bdfdd3
--- /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 0000000000..0c95656663
--- /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 0000000000..54ccd90f3f
--- /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 0000000000..d28deddfcd
--- /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 0000000000..525d44220f
--- /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 0000000000..e69de29bb2
--- /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 0000000000..41bf96344a
--- /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 0000000000..7c2ed09b81
--- /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 0000000000..187713d089
--- /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 0000000000..fd45c48d6d
--- /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 0000000000..a83d43310b
--- /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 2dc95cee21..5131a89ce8 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 655a3dc899..77bddbe337 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 4da7eeb2ff..589482d6a5 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 8defa0125a..8ccf7a2a34 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 51d9c92235..839454d8a8 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 a43cec20ef..a9319a6aed 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 71ddedf6ff..9e5fa0ac07 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/tools/coccinelle/route_map_apply.cocci b/tools/coccinelle/route_map_apply.cocci
new file mode 100644
index 0000000000..ccca619d7e
--- /dev/null
+++ b/tools/coccinelle/route_map_apply.cocci
@@ -0,0 +1,15 @@
+@rmap@
+identifier ret;
+position p;
+@@
+
+int ret@p;
+...
+* ret = route_map_apply(...);
+
+@script:python@
+p << rmap.p;
+@@
+
+msg = "ERROR: Invalid type of return value variable for route_map_apply_ext()"
+coccilib.report.print_report(p[0], msg)
diff --git a/tools/frr-reload.py b/tools/frr-reload.py
index 32f9a78841..7c5d91d4dc 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 27b2c0ab84..f0c665fdee 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/frr.service.in b/tools/frr.service.in
index df1e4f3b08..1e958dd93e 100644
--- a/tools/frr.service.in
+++ b/tools/frr.service.in
@@ -15,7 +15,7 @@ StartLimitBurst=3
TimeoutSec=@TIMEOUT_MIN@m
WatchdogSec=60s
RestartSec=5
-Restart=on-abnormal
+Restart=always
LimitNOFILE=1024
PIDFile=@CFG_STATE@/watchfrr.pid
ExecStart=@CFG_SBIN@/frrinit.sh start
diff --git a/tools/frr@.service.in b/tools/frr@.service.in
index 1cbef1b18c..85408a0cc7 100644
--- a/tools/frr@.service.in
+++ b/tools/frr@.service.in
@@ -15,7 +15,7 @@ StartLimitBurst=3
TimeoutSec=@TIMEOUT_MIN@m
WatchdogSec=60s
RestartSec=5
-Restart=on-abnormal
+Restart=always
LimitNOFILE=1024
PIDFile=@CFG_STATE@/%I/watchfrr.pid
ExecStart=@CFG_SBIN@/frrinit.sh start %I
diff --git a/tools/frrcommon.sh.in b/tools/frrcommon.sh.in
index b589ced965..469b9c5d8c 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 634a55dbc3..d2f25f2d40 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/vtysh/vtysh_config.c b/vtysh/vtysh_config.c
index a7ec2a93c2..d98f83dbf6 100644
--- a/vtysh/vtysh_config.c
+++ b/vtysh/vtysh_config.c
@@ -483,13 +483,21 @@ void vtysh_config_parse_line(void *arg, const char *line)
0 ||
strncmp(line, "domainname", strlen("domainname")) ==
0 ||
+ strncmp(line, "allow-reserved-ranges",
+ strlen("allow-reserved-ranges")) == 0 ||
strncmp(line, "frr", strlen("frr")) == 0 ||
strncmp(line, "agentx", strlen("agentx")) == 0 ||
strncmp(line, "no log", strlen("no log")) == 0 ||
strncmp(line, "no ip prefix-list",
strlen("no ip prefix-list")) == 0 ||
strncmp(line, "no ipv6 prefix-list",
- strlen("no ipv6 prefix-list")) == 0)
+ strlen("no ipv6 prefix-list")) == 0 ||
+ strncmp(line, "service cputime-stats",
+ strlen("service cputime-stats")) == 0 ||
+ strncmp(line, "no service cputime-stats",
+ strlen("no service cputime-stats")) == 0 ||
+ strncmp(line, "service cputime-warning",
+ strlen("service cputime-warning")) == 0)
config_add_line_uniq(config_top, line);
else
config_add_line(config_top, line);
diff --git a/watchfrr/watchfrr_vty.c b/watchfrr/watchfrr_vty.c
index 1492ee37b6..e5cc437542 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/zebra/debug.c b/zebra/debug.c
index 69aaed33ac..25102145d7 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/if_ioctl.c b/zebra/if_ioctl.c
index 2c83a7ed4c..e02f3d5624 100644
--- a/zebra/if_ioctl.c
+++ b/zebra/if_ioctl.c
@@ -199,7 +199,7 @@ static int if_getaddrs(void)
ifp = if_lookup_by_name(ifap->ifa_name, VRF_DEFAULT);
if (ifp == NULL) {
flog_err(EC_LIB_INTERFACE,
- "if_getaddrs(): Can't lookup interface %s",
+ "%s: Can't lookup interface %s", __func__,
ifap->ifa_name);
continue;
}
@@ -290,7 +290,7 @@ static void interface_info_ioctl()
void interface_list(struct zebra_ns *zns)
{
- zlog_info("interface_list: NS %u", zns->ns_id);
+ zlog_info("%s: NS %u", __func__, zns->ns_id);
/* Linux can do both proc & ioctl, ioctl is the only way to get
interface aliases in 2.2 series kernels. */
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index c7e7443a1b..b28c468a96 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -1182,13 +1182,19 @@ int interface_lookup_netlink(struct zebra_ns *zns)
if (ret < 0)
return ret;
+ /*
+ * So netlink_tunneldump_read will initiate a request
+ * per tunnel to get data. If we are on a kernel that
+ * does not support this then we will get X error messages
+ * (one per tunnel request )back which netlink_parse_info will
+ * stop after the first one. So we need to read equivalent
+ * error messages per tunnel then we can continue.
+ * if we do not gather all the read failures then
+ * later requests will not work right.
+ */
ret = netlink_tunneldump_read(zns);
if (ret < 0)
return ret;
- ret = netlink_parse_info(netlink_interface, netlink_cmd, &dp_info, 0,
- true);
- if (ret < 0)
- return ret;
/* fixup linkages */
zebra_if_update_all_links(zns);
@@ -1443,7 +1449,7 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup)
if (IS_ZEBRA_DEBUG_KERNEL) /* remove this line to see initial ifcfg */
{
char buf[BUFSIZ];
- zlog_debug("netlink_interface_addr %s %s flags 0x%x:",
+ zlog_debug("%s %s %s flags 0x%x:", __func__,
nl_msg_type_to_str(h->nlmsg_type), ifp->name,
kernel_flags);
if (tb[IFA_LOCAL])
@@ -1818,7 +1824,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
/* assume if not default zns, then new VRF */
if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)) {
/* If this is not link add/delete message so print warning. */
- zlog_debug("netlink_link_change: wrong kernel message %s",
+ zlog_debug("%s: wrong kernel message %s", __func__,
nl_msg_type_to_str(h->nlmsg_type));
return 0;
}
@@ -2322,6 +2328,7 @@ int netlink_tunneldump_read(struct zebra_ns *zns)
struct route_node *rn;
struct interface *tmp_if = NULL;
struct zebra_if *zif;
+ struct nlsock *netlink_cmd = &zns->netlink_cmd;
zebra_dplane_info_from_zns(&dp_info, zns, true /*is_cmd*/);
@@ -2337,7 +2344,14 @@ int netlink_tunneldump_read(struct zebra_ns *zns)
tmp_if->ifindex);
if (ret < 0)
return ret;
+
+ ret = netlink_parse_info(netlink_interface, netlink_cmd,
+ &dp_info, 0, true);
+
+ if (ret < 0)
+ return ret;
}
+
return 0;
}
#endif /* GNU_LINUX */
diff --git a/zebra/if_sysctl.c b/zebra/if_sysctl.c
index 38729c8d38..70d11646c3 100644
--- a/zebra/if_sysctl.c
+++ b/zebra/if_sysctl.c
@@ -97,7 +97,7 @@ void interface_list(struct zebra_ns *zns)
NET_RT_IFLIST, 0};
if (zns->ns_id != NS_DEFAULT) {
- zlog_debug("interface_list: ignore NS %u", zns->ns_id);
+ zlog_debug("%s: ignore NS %u", __func__, zns->ns_id);
return;
}
@@ -132,7 +132,7 @@ void interface_list(struct zebra_ns *zns)
ifam_read((struct ifa_msghdr *)ifm);
break;
default:
- zlog_info("interfaces_list(): unexpected message type");
+ zlog_info("%s: unexpected message type", __func__);
XFREE(MTYPE_TMP, ref);
return;
break;
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index 4c089ee194..e76d8c0cc4 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -534,7 +534,7 @@ int ifm_read(struct if_msghdr *ifm)
/* paranoia: sanity check structure */
if (ifm->ifm_msglen < sizeof(struct if_msghdr)) {
flog_err(EC_ZEBRA_NETLINK_LENGTH_ERROR,
- "ifm_read: ifm->ifm_msglen %d too short",
+ "%s: ifm->ifm_msglen %d too short", __func__,
ifm->ifm_msglen);
return -1;
}
@@ -1388,9 +1388,8 @@ static void kernel_read(struct thread *thread)
* can assume they have the whole message.
*/
if (rtm->rtm_msglen != nbytes) {
- zlog_debug(
- "kernel_read: rtm->rtm_msglen %d, nbytes %d, type %d",
- rtm->rtm_msglen, nbytes, rtm->rtm_type);
+ zlog_debug("%s: rtm->rtm_msglen %d, nbytes %d, type %d",
+ __func__, rtm->rtm_msglen, nbytes, rtm->rtm_type);
return;
}
diff --git a/zebra/main.c b/zebra/main.c
index 46cf2eea7d..3de97943fd 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/rib.h b/zebra/rib.h
index dec5b2b8d6..99f52bcd4e 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -585,6 +585,7 @@ static inline void rib_tables_iter_cleanup(rib_tables_iter_t *iter)
DECLARE_HOOK(rib_update, (struct route_node * rn, const char *reason),
(rn, reason));
+DECLARE_HOOK(rib_shutdown, (struct route_node * rn), (rn));
/*
* Access installed/fib nexthops, which may be a subset of the
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
index bf959980be..127888d655 100644
--- a/zebra/rtadv.c
+++ b/zebra/rtadv.c
@@ -227,8 +227,7 @@ static void rtadv_send_packet(int sock, struct interface *ifp,
adata = calloc(1, CMSG_SPACE(sizeof(struct in6_pktinfo)));
if (adata == NULL) {
- zlog_debug(
- "rtadv_send_packet: can't malloc control data");
+ zlog_debug("%s: can't malloc control data", __func__);
exit(-1);
}
}
@@ -665,8 +664,9 @@ static void rtadv_process_advert(uint8_t *msg, unsigned int len,
zif->rtadv.lastadvcurhoplimit.tv_sec == 0)) {
flog_warn(
EC_ZEBRA_RA_PARAM_MISMATCH,
- "%s(%u): Rx RA - our AdvCurHopLimit doesn't agree with %s",
- ifp->name, ifp->ifindex, addr_str);
+ "%s(%u): Rx RA - our AdvCurHopLimit (%u) doesn't agree with %s (%u)",
+ ifp->name, ifp->ifindex, zif->rtadv.AdvCurHopLimit,
+ addr_str, radvert->nd_ra_curhoplimit);
monotime(&zif->rtadv.lastadvcurhoplimit);
}
@@ -677,8 +677,11 @@ static void rtadv_process_advert(uint8_t *msg, unsigned int len,
zif->rtadv.lastadvmanagedflag.tv_sec == 0)) {
flog_warn(
EC_ZEBRA_RA_PARAM_MISMATCH,
- "%s(%u): Rx RA - our AdvManagedFlag doesn't agree with %s",
- ifp->name, ifp->ifindex, addr_str);
+ "%s(%u): Rx RA - our AdvManagedFlag (%u) doesn't agree with %s (%u)",
+ ifp->name, ifp->ifindex, zif->rtadv.AdvManagedFlag,
+ addr_str,
+ !!CHECK_FLAG(radvert->nd_ra_flags_reserved,
+ ND_RA_FLAG_MANAGED));
monotime(&zif->rtadv.lastadvmanagedflag);
}
@@ -689,8 +692,11 @@ static void rtadv_process_advert(uint8_t *msg, unsigned int len,
zif->rtadv.lastadvotherconfigflag.tv_sec == 0)) {
flog_warn(
EC_ZEBRA_RA_PARAM_MISMATCH,
- "%s(%u): Rx RA - our AdvOtherConfigFlag doesn't agree with %s",
- ifp->name, ifp->ifindex, addr_str);
+ "%s(%u): Rx RA - our AdvOtherConfigFlag (%u) doesn't agree with %s (%u)",
+ ifp->name, ifp->ifindex, zif->rtadv.AdvOtherConfigFlag,
+ addr_str,
+ !!CHECK_FLAG(radvert->nd_ra_flags_reserved,
+ ND_RA_FLAG_OTHER));
monotime(&zif->rtadv.lastadvotherconfigflag);
}
@@ -701,20 +707,23 @@ static void rtadv_process_advert(uint8_t *msg, unsigned int len,
zif->rtadv.lastadvreachabletime.tv_sec == 0)) {
flog_warn(
EC_ZEBRA_RA_PARAM_MISMATCH,
- "%s(%u): Rx RA - our AdvReachableTime doesn't agree with %s",
- ifp->name, ifp->ifindex, addr_str);
+ "%s(%u): Rx RA - our AdvReachableTime (%u) doesn't agree with %s (%u)",
+ ifp->name, ifp->ifindex, zif->rtadv.AdvReachableTime,
+ addr_str, ntohl(radvert->nd_ra_reachable));
monotime(&zif->rtadv.lastadvreachabletime);
}
- if ((ntohl(radvert->nd_ra_retransmit) !=
+ if ((radvert->nd_ra_retransmit && zif->rtadv.AdvRetransTimer) &&
+ (ntohl(radvert->nd_ra_retransmit) !=
(unsigned int)zif->rtadv.AdvRetransTimer) &&
(monotime_since(&zif->rtadv.lastadvretranstimer, NULL) >
SIXHOUR2USEC ||
zif->rtadv.lastadvretranstimer.tv_sec == 0)) {
flog_warn(
EC_ZEBRA_RA_PARAM_MISMATCH,
- "%s(%u): Rx RA - our AdvRetransTimer doesn't agree with %s",
- ifp->name, ifp->ifindex, addr_str);
+ "%s(%u): Rx RA - our AdvRetransTimer (%u) doesn't agree with %s (%u)",
+ ifp->name, ifp->ifindex, zif->rtadv.AdvRetransTimer,
+ addr_str, ntohl(radvert->nd_ra_retransmit));
monotime(&zif->rtadv.lastadvretranstimer);
}
diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c
index 043ea0f248..064c91b729 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_fpm.c b/zebra/zebra_fpm.c
index 21acaa823c..1b2753377b 100644
--- a/zebra/zebra_fpm.c
+++ b/zebra/zebra_fpm.c
@@ -1478,6 +1478,32 @@ static int zfpm_trigger_update(struct route_node *rn, const char *reason)
}
/*
+ * zfpm_trigger_remove
+ *
+ * The zebra code invokes this function to indicate that we should
+ * send an remove to the FPM about the given route_node.
+ */
+
+static int zfpm_trigger_remove(struct route_node *rn)
+{
+ rib_dest_t *dest;
+
+ if (!zfpm_conn_is_up())
+ return 0;
+
+ dest = rib_dest_from_rnode(rn);
+ if (!CHECK_FLAG(dest->flags, RIB_DEST_UPDATE_FPM))
+ return 0;
+
+ zfpm_debug("%pRN Removing from update queue shutting down", rn);
+
+ UNSET_FLAG(dest->flags, RIB_DEST_UPDATE_FPM);
+ TAILQ_REMOVE(&zfpm_g->dest_q, dest, fpm_q_entries);
+
+ return 0;
+}
+
+/*
* Generate Key for FPM MAC info hash entry
*/
static unsigned int zfpm_mac_info_hash_keymake(const void *p)
@@ -2036,6 +2062,7 @@ static int zfpm_fini(void)
static int zebra_fpm_module_init(void)
{
hook_register(rib_update, zfpm_trigger_update);
+ hook_register(rib_shutdown, zfpm_trigger_remove);
hook_register(zebra_rmac_update, zfpm_trigger_rmac_update);
hook_register(frr_late_init, zfpm_init);
hook_register(frr_early_fini, zfpm_fini);
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index bd7e8bbbd0..fceaaaa9f0 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -76,6 +76,8 @@ static struct dplane_ctx_q rib_dplane_q;
DEFINE_HOOK(rib_update, (struct route_node * rn, const char *reason),
(rn, reason));
+DEFINE_HOOK(rib_shutdown, (struct route_node * rn), (rn));
+
/* Meta Q's specific names */
enum meta_queue_indexes {
@@ -944,6 +946,9 @@ void zebra_rtable_node_cleanup(struct route_table *table,
if (node->info) {
rib_dest_t *dest = node->info;
+ /* Remove from update queue of FPM module */
+ hook_call(rib_shutdown, node);
+
rnh_list_fini(&dest->nht);
XFREE(MTYPE_RIB_DEST, node->info);
}
diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c
index 62ce17326c..daac4cade0 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 42d6aefa9a..2f8b5048d5 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 */