summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/size-label.yml25
-rw-r--r--bfdd/bfd_packet.c2
-rw-r--r--bgpd/bgp_attr.c40
-rw-r--r--bgpd/bgp_debug.c13
-rw-r--r--bgpd/bgp_ecommunity.c9
-rw-r--r--bgpd/bgp_evpn_mh.c4
-rw-r--r--bgpd/bgp_evpn_vty.c14
-rw-r--r--bgpd/bgp_flowspec_vty.c12
-rw-r--r--bgpd/bgp_mpath.c4
-rw-r--r--bgpd/bgp_nexthop.c19
-rw-r--r--bgpd/bgp_packet.c15
-rw-r--r--bgpd/bgp_pbr.c5
-rw-r--r--bgpd/bgp_route.c92
-rw-r--r--bgpd/bgp_routemap.c18
-rw-r--r--bgpd/bgp_snmp_bgp4v2.c225
-rw-r--r--bgpd/bgp_vty.c157
-rw-r--r--bgpd/bgp_zebra.c22
-rw-r--r--bgpd/bgpd.c1
-rw-r--r--bgpd/bgpd.h1
-rw-r--r--bgpd/rfapi/rfapi.c8
-rw-r--r--bgpd/rfapi/rfapi_import.c3
-rw-r--r--bgpd/rfapi/rfapi_vty.c52
-rw-r--r--doc/developer/workflow.rst26
-rw-r--r--doc/user/bgp.rst5
-rw-r--r--doc/user/setup.rst10
-rw-r--r--doc/user/zebra.rst3
-rw-r--r--lib/vty.c3
-rw-r--r--ospf6d/ospf6_abr.c2
-rw-r--r--ospf6d/ospf6_route.c41
-rw-r--r--ospf6d/ospf6_route.h12
-rw-r--r--ospfd/ospf_api.h2
-rw-r--r--ospfd/ospf_ism.c12
-rw-r--r--ospfd/ospf_network.c11
-rw-r--r--ospfd/ospfd.c21
-rw-r--r--pimd/pim_cmd_common.c81
-rw-r--r--staticd/static_nb_config.c2
-rw-r--r--staticd/static_vty.c652
-rw-r--r--tests/topotests/bgp_comm_list_delete/test_bgp_comm-list_delete.py54
-rw-r--r--tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py63
-rw-r--r--tests/topotests/bgp_maximum_prefix_invalid_update/r1/bgpd.conf17
-rw-r--r--tests/topotests/bgp_maximum_prefix_invalid_update/r1/zebra.conf1
-rw-r--r--tests/topotests/bgp_maximum_prefix_invalid_update/r2/bgpd.conf13
-rw-r--r--tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py40
-rw-r--r--tests/topotests/bgp_peer_graceful_shutdown/__init__.py0
-rw-r--r--tests/topotests/bgp_peer_graceful_shutdown/r1/bgpd.conf8
-rw-r--r--tests/topotests/bgp_peer_graceful_shutdown/r1/zebra.conf7
-rw-r--r--tests/topotests/bgp_peer_graceful_shutdown/r2/bgpd.conf8
-rw-r--r--tests/topotests/bgp_peer_graceful_shutdown/r2/zebra.conf7
-rw-r--r--tests/topotests/bgp_peer_graceful_shutdown/r3/bgpd.conf5
-rw-r--r--tests/topotests/bgp_peer_graceful_shutdown/r3/zebra.conf4
-rw-r--r--tests/topotests/bgp_peer_graceful_shutdown/test_bgp_peer_graceful_shutdown.py120
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/bgpd.conf2
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/bgpd.conf2
-rwxr-xr-xtests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py2
-rwxr-xr-xtests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py12
-rw-r--r--tests/topotests/lib/topotest.py20
-rwxr-xr-xtests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py4
-rw-r--r--tests/topotests/ospf6_topo2/test_ospf6_topo2.py2
-rwxr-xr-xtests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py4
-rw-r--r--tests/topotests/pim_basic/test_pim.py2
-rw-r--r--tests/topotests/pim_basic_topo2/test_pim_basic_topo2.py4
-rwxr-xr-xtests/topotests/srv6_locator/test_srv6_locator.py4
-rwxr-xr-xtests/topotests/srv6_locator_custom_bits_length/test_srv6_locator.py6
-rw-r--r--tests/topotests/srv6_locator_usid/r1/zebra.conf2
-rwxr-xr-xtests/topotests/srv6_locator_usid/test_srv6_locator_usid.py20
-rw-r--r--tools/etc/frr/daemons5
-rwxr-xr-xtools/frrcommon.sh.in4
-rw-r--r--zebra/interface.c2
-rw-r--r--zebra/zebra_rnh.c185
-rw-r--r--zebra/zebra_rnh.h3
-rw-r--r--zebra/zebra_srv6_vty.c10
-rw-r--r--zebra/zebra_trace.h43
-rw-r--r--zebra/zebra_vty.c57
73 files changed, 1584 insertions, 782 deletions
diff --git a/.github/workflows/size-label.yml b/.github/workflows/size-label.yml
new file mode 100644
index 0000000000..a37700342c
--- /dev/null
+++ b/.github/workflows/size-label.yml
@@ -0,0 +1,25 @@
+name: Add PRs size label
+
+on: pull_request_target
+
+jobs:
+ size-label:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ pull-requests: write
+ steps:
+ - name: size-label
+ uses: "pascalgn/size-label-action@v0.4.2"
+ env:
+ GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
+ with:
+ sizes: >
+ {
+ "0": "XS",
+ "20": "S",
+ "50": "M",
+ "200": "L",
+ "800": "XL",
+ "2000": "XXL"
+ }
diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c
index 382f78a0f6..6397aa5747 100644
--- a/bfdd/bfd_packet.c
+++ b/bfdd/bfd_packet.c
@@ -1397,8 +1397,6 @@ int bp_peer_socket(const struct bfd_session *bs)
sin.sin_len = sizeof(sin);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
memcpy(&sin.sin_addr, &bs->key.local, sizeof(sin.sin_addr));
- if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH) == 0)
- sin.sin_addr.s_addr = INADDR_ANY;
pcount = 0;
do {
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index b8010364a7..1f8c7dc098 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -904,20 +904,16 @@ static void attrhash_finish(void)
static void attr_show_all_iterator(struct hash_bucket *bucket, struct vty *vty)
{
struct attr *attr = bucket->data;
- char sid_str[BUFSIZ];
vty_out(vty, "attr[%ld] nexthop %pI4\n", attr->refcnt, &attr->nexthop);
- sid_str[0] = '\0';
- if (attr->srv6_l3vpn)
- inet_ntop(AF_INET6, &attr->srv6_l3vpn->sid, sid_str, BUFSIZ);
- else if (attr->srv6_vpn)
- inet_ntop(AF_INET6, &attr->srv6_vpn->sid, sid_str, BUFSIZ);
-
vty_out(vty,
- "\tflags: %" PRIu64" distance: %u med: %u local_pref: %u origin: %u weight: %u label: %u sid: %s\n",
+ "\tflags: %" PRIu64
+ " distance: %u med: %u local_pref: %u origin: %u weight: %u label: %u sid: %pI6\n",
attr->flag, attr->distance, attr->med, attr->local_pref,
- attr->origin, attr->weight, attr->label, sid_str);
+ attr->origin, attr->weight, attr->label,
+ attr->srv6_l3vpn ? &attr->srv6_l3vpn->sid
+ : &attr->srv6_vpn->sid);
}
void attr_show_all(struct vty *vty)
@@ -1746,12 +1742,9 @@ enum bgp_attr_parse_ret bgp_attr_nexthop_valid(struct peer *peer,
if (ipv4_martian(&attr->nexthop) && !bgp->allow_martian) {
uint8_t data[7]; /* type(2) + length(1) + nhop(4) */
- char buf[INET_ADDRSTRLEN];
- inet_ntop(AF_INET, &attr->nexthop.s_addr, buf,
- INET_ADDRSTRLEN);
- flog_err(EC_BGP_ATTR_MARTIAN_NH, "Martian nexthop %s",
- buf);
+ flog_err(EC_BGP_ATTR_MARTIAN_NH, "Martian nexthop %pI4",
+ &attr->nexthop);
data[0] = BGP_ATTR_FLAG_TRANS;
data[1] = BGP_ATTR_NEXT_HOP;
data[2] = BGP_ATTR_NHLEN_IPV4;
@@ -2758,7 +2751,6 @@ bgp_attr_srv6_service(struct bgp_attr_parser_args *args)
uint16_t length, endpoint_behavior;
size_t headersz = sizeof(type) + sizeof(length);
enum bgp_attr_parse_ret err;
- char buf[BUFSIZ];
if (STREAM_READABLE(peer->curr) < headersz) {
flog_err(
@@ -2789,12 +2781,11 @@ bgp_attr_srv6_service(struct bgp_attr_parser_args *args)
stream_getc(peer->curr);
/* Log SRv6 Service Sub-TLV */
- if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) {
- inet_ntop(AF_INET6, &ipv6_sid, buf, sizeof(buf));
+ if (BGP_DEBUG(vpn, VPN_LEAK_LABEL))
zlog_debug(
- "%s: srv6-l3-srv sid %s, sid-flags 0x%02x, end-behaviour 0x%04x",
- __func__, buf, sid_flags, endpoint_behavior);
- }
+ "%s: srv6-l3-srv sid %pI6, sid-flags 0x%02x, end-behaviour 0x%04x",
+ __func__, &ipv6_sid, sid_flags,
+ endpoint_behavior);
/* Configure from Info */
if (attr->srv6_l3vpn) {
@@ -2855,7 +2846,6 @@ bgp_attr_psid_sub(uint8_t type, uint16_t length,
uint32_t srgb_range;
int srgb_count;
uint8_t sid_type, sid_flags;
- char buf[BUFSIZ];
if (type == BGP_PREFIX_SID_LABEL_INDEX) {
if (STREAM_READABLE(peer->curr) < length
@@ -2986,12 +2976,10 @@ bgp_attr_psid_sub(uint8_t type, uint16_t length,
sizeof(ipv6_sid)); /* sid_value */
/* Log VPN-SID Sub-TLV */
- if (BGP_DEBUG(vpn, VPN_LEAK_LABEL)) {
- inet_ntop(AF_INET6, &ipv6_sid, buf, sizeof(buf));
+ if (BGP_DEBUG(vpn, VPN_LEAK_LABEL))
zlog_debug(
- "%s: vpn-sid: sid %s, sid-type 0x%02x sid-flags 0x%02x",
- __func__, buf, sid_type, sid_flags);
- }
+ "%s: vpn-sid: sid %pI6, sid-type 0x%02x sid-flags 0x%02x",
+ __func__, &ipv6_sid, sid_type, sid_flags);
/* Configure from Info */
if (attr->srv6_vpn) {
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index 92a22d71b3..bfde1c127e 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -378,8 +378,6 @@ bool bgp_debug_peer_updout_enabled(char *host)
/* Dump attribute. */
bool bgp_dump_attr(struct attr *attr, char *buf, size_t size)
{
- char addrbuf[BUFSIZ];
-
if (!attr)
return false;
@@ -395,15 +393,12 @@ bool bgp_dump_attr(struct attr *attr, char *buf, size_t size)
/* Add MP case. */
if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL
|| attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
- snprintf(buf + strlen(buf), size - strlen(buf),
- ", mp_nexthop %s",
- inet_ntop(AF_INET6, &attr->mp_nexthop_global, addrbuf,
- BUFSIZ));
+ snprintfrr(buf + strlen(buf), size - strlen(buf),
+ ", mp_nexthop %pI6", &attr->mp_nexthop_global);
if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL)
- snprintf(buf + strlen(buf), size - strlen(buf), "(%s)",
- inet_ntop(AF_INET6, &attr->mp_nexthop_local, addrbuf,
- BUFSIZ));
+ snprintfrr(buf + strlen(buf), size - strlen(buf), "(%pI6)",
+ &attr->mp_nexthop_local);
if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV4)
snprintfrr(buf, size, "nexthop %pI4", &attr->nexthop);
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c
index 589d9af1e5..62fba1f58e 100644
--- a/bgpd/bgp_ecommunity.c
+++ b/bgpd/bgp_ecommunity.c
@@ -988,13 +988,8 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
type == ECOMMUNITY_ENCODE_IP) {
struct in_addr *ipv4 =
(struct in_addr *)pnt;
- char ipv4str[INET_ADDRSTRLEN];
-
- inet_ntop(AF_INET, ipv4,
- ipv4str,
- INET_ADDRSTRLEN);
- snprintf(encbuf, sizeof(encbuf),
- "NH:%s:%d", ipv4str, pnt[5]);
+ snprintfrr(encbuf, sizeof(encbuf),
+ "NH:%pI4:%d", ipv4, pnt[5]);
} else if (sub_type ==
ECOMMUNITY_LINK_BANDWIDTH &&
type == ECOMMUNITY_ENCODE_AS) {
diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c
index 2a5c5d7ec4..77656dae34 100644
--- a/bgpd/bgp_evpn_mh.c
+++ b/bgpd/bgp_evpn_mh.c
@@ -2435,7 +2435,7 @@ static char *bgp_evpn_es_vteps_str(char *vtep_str, struct bgp_evpn_es *es,
struct listnode *node;
struct bgp_evpn_es_vtep *es_vtep;
bool first = true;
- char ip_buf[INET6_ADDRSTRLEN];
+ char ip_buf[INET_ADDRSTRLEN];
vtep_str[0] = '\0';
for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) {
@@ -3903,7 +3903,7 @@ static char *bgp_evpn_es_evi_vteps_str(char *vtep_str,
struct listnode *node;
struct bgp_evpn_es_evi_vtep *evi_vtep;
bool first = true;
- char ip_buf[INET6_ADDRSTRLEN];
+ char ip_buf[INET_ADDRSTRLEN];
vtep_str[0] = '\0';
for (ALL_LIST_ELEMENTS_RO(es_evi->es_evi_vtep_list, node, evi_vtep)) {
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index 88c1329f48..00545c96ae 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -372,7 +372,6 @@ static void bgp_evpn_show_route_header(struct vty *vty, struct bgp *bgp,
static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
json_object *json)
{
- char buf1[INET6_ADDRSTRLEN];
char *ecom_str;
struct listnode *node, *nnode;
struct vrf_route_target *l3rt;
@@ -419,9 +418,8 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
vty_out(vty, " Advertise-svi-macip : %s\n", "n/a");
vty_out(vty, " Advertise-pip: %s\n",
bgp_vrf->evpn_info->advertise_pip ? "Yes" : "No");
- vty_out(vty, " System-IP: %s\n",
- inet_ntop(AF_INET, &bgp_vrf->evpn_info->pip_ip,
- buf1, INET_ADDRSTRLEN));
+ vty_out(vty, " System-IP: %pI4\n",
+ &bgp_vrf->evpn_info->pip_ip);
vty_out(vty, " System-MAC: %s\n",
prefix_mac2str(&bgp_vrf->evpn_info->pip_rmac,
buf2, sizeof(buf2)));
@@ -7071,8 +7069,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 buf2[INET6_ADDRSTRLEN];
-
if (bgp->advertise_all_vni)
vty_out(vty, " advertise-all-vni\n");
@@ -7217,10 +7213,8 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
if (bgp->evpn_info->advertise_pip) {
if (bgp->evpn_info->pip_ip_static.s_addr
!= INADDR_ANY) {
- vty_out(vty, " advertise-pip ip %s",
- inet_ntop(AF_INET,
- &bgp->evpn_info->pip_ip_static,
- buf2, INET_ADDRSTRLEN));
+ vty_out(vty, " advertise-pip ip %pI4",
+ &bgp->evpn_info->pip_ip_static);
if (!is_zero_mac(&(
bgp->evpn_info->pip_rmac_static))) {
char buf[ETHER_ADDR_STRLEN];
diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c
index 02dcdfcaa3..626e980346 100644
--- a/bgpd/bgp_flowspec_vty.c
+++ b/bgpd/bgp_flowspec_vty.c
@@ -338,18 +338,14 @@ void route_vty_out_flowspec(struct vty *vty, const struct prefix *p,
local_buff[0] = '\0';
if (p->u.prefix_flowspec.family == AF_INET
&& attr->nexthop.s_addr != INADDR_ANY)
- inet_ntop(AF_INET,
- &attr->nexthop.s_addr,
- local_buff,
- INET6_ADDRSTRLEN);
+ inet_ntop(AF_INET, &attr->nexthop.s_addr,
+ local_buff, sizeof(local_buff));
else if (p->u.prefix_flowspec.family == AF_INET6 &&
attr->mp_nexthop_len != 0 &&
attr->mp_nexthop_len != BGP_ATTR_NHLEN_IPV4 &&
attr->mp_nexthop_len != BGP_ATTR_NHLEN_VPNV4)
- inet_ntop(AF_INET6,
- &attr->mp_nexthop_global,
- local_buff,
- INET6_ADDRSTRLEN);
+ inet_ntop(AF_INET6, &attr->mp_nexthop_global,
+ local_buff, sizeof(local_buff));
if (local_buff[0] != '\0')
vty_out(vty, "\tNLRI NH %s\n",
local_buff);
diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c
index 64af8a5411..52f6b64c2c 100644
--- a/bgpd/bgp_mpath.c
+++ b/bgpd/bgp_mpath.c
@@ -278,8 +278,10 @@ void bgp_mp_list_add(struct list *mp_list, struct bgp_path_info *mpinfo)
static struct bgp_path_info_mpath *bgp_path_info_mpath_new(void)
{
struct bgp_path_info_mpath *new_mpath;
+
new_mpath = XCALLOC(MTYPE_BGP_MPATH_INFO,
sizeof(struct bgp_path_info_mpath));
+
return new_mpath;
}
@@ -313,8 +315,6 @@ bgp_path_info_mpath_get(struct bgp_path_info *path)
if (!path->mpath) {
mpath = bgp_path_info_mpath_new();
- if (!mpath)
- return NULL;
path->mpath = mpath;
mpath->mp_info = path;
}
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c
index 075350cd2b..25a4a1b521 100644
--- a/bgpd/bgp_nexthop.c
+++ b/bgpd/bgp_nexthop.c
@@ -768,28 +768,22 @@ static void bgp_show_nexthop_paths(struct vty *vty, struct bgp *bgp,
static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp,
struct bgp_nexthop_cache *bnc)
{
- char buf[PREFIX2STR_BUFFER];
struct nexthop *nexthop;
for (nexthop = bnc->nexthop; nexthop; nexthop = nexthop->next) {
switch (nexthop->type) {
case NEXTHOP_TYPE_IPV6:
- vty_out(vty, " gate %s\n",
- inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf,
- sizeof(buf)));
+ vty_out(vty, " gate %pI6\n", &nexthop->gate.ipv6);
break;
case NEXTHOP_TYPE_IPV6_IFINDEX:
- vty_out(vty, " gate %s, if %s\n",
- inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf,
- sizeof(buf)),
+ vty_out(vty, " gate %pI6, if %s\n",
+ &nexthop->gate.ipv6,
ifindex2ifname(bnc->ifindex ? bnc->ifindex
: nexthop->ifindex,
bgp->vrf_id));
break;
case NEXTHOP_TYPE_IPV4:
- vty_out(vty, " gate %s\n",
- inet_ntop(AF_INET, &nexthop->gate.ipv4, buf,
- sizeof(buf)));
+ vty_out(vty, " gate %pI4\n", &nexthop->gate.ipv4);
break;
case NEXTHOP_TYPE_IFINDEX:
vty_out(vty, " if %s\n",
@@ -798,9 +792,8 @@ static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp,
bgp->vrf_id));
break;
case NEXTHOP_TYPE_IPV4_IFINDEX:
- vty_out(vty, " gate %s, if %s\n",
- inet_ntop(AF_INET, &nexthop->gate.ipv4, buf,
- sizeof(buf)),
+ vty_out(vty, " gate %pI4, if %s\n",
+ &nexthop->gate.ipv4,
ifindex2ifname(bnc->ifindex ? bnc->ifindex
: nexthop->ifindex,
bgp->vrf_id));
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index f3ca3bba0a..5d4cf2a6aa 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -979,10 +979,11 @@ static void bgp_notify_send_internal(struct peer *peer, uint8_t code,
peer->notify.code = bgp_notify.code;
peer->notify.subcode = bgp_notify.subcode;
+ peer->notify.length = bgp_notify.length;
if (bgp_notify.length && data) {
- bgp_notify.data =
- XMALLOC(MTYPE_TMP, bgp_notify.length * 3);
+ bgp_notify.data = XMALLOC(MTYPE_BGP_NOTIFICATION,
+ bgp_notify.length * 3);
for (i = 0; i < bgp_notify.length; i++)
if (first) {
snprintf(c, sizeof(c), " %02x",
@@ -1002,7 +1003,15 @@ static void bgp_notify_send_internal(struct peer *peer, uint8_t code,
bgp_notify_print(peer, &bgp_notify, "sending", hard_reset);
if (bgp_notify.data) {
- XFREE(MTYPE_TMP, bgp_notify.data);
+ if (data) {
+ XFREE(MTYPE_BGP_NOTIFICATION,
+ peer->notify.data);
+ peer->notify.data = XCALLOC(
+ MTYPE_BGP_NOTIFICATION, datalen);
+ memcpy(peer->notify.data, data, datalen);
+ }
+
+ XFREE(MTYPE_BGP_NOTIFICATION, bgp_notify.data);
bgp_notify.length = 0;
}
}
diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c
index b71e19ab33..807c4cd5a4 100644
--- a/bgpd/bgp_pbr.c
+++ b/bgpd/bgp_pbr.c
@@ -1636,9 +1636,8 @@ void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api)
ptr_ip = &api->actions[i].u.zr.redirect_ip_v4;
else
ptr_ip = &api->actions[i].u.zr.redirect_ip_v6;
- if (inet_ntop(afi2family(api->afi),
- ptr_ip, local_buff,
- INET6_ADDRSTRLEN) != NULL) {
+ if (inet_ntop(afi2family(api->afi), ptr_ip, local_buff,
+ sizeof(local_buff)) != NULL) {
delta = snprintf(ptr, len,
"@redirect ip nh %s", local_buff);
len -= delta;
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index d6e6fc952f..027cb20e41 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -4237,9 +4237,11 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
new_attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);
new_attr.local_pref = BGP_GSHUT_LOCAL_PREF;
- /* If graceful-shutdown is configured then add the GSHUT
- * community to all paths received from eBGP peers */
- } else if (bgp_in_graceful_shutdown(peer->bgp))
+ /* If graceful-shutdown is configured globally or
+ * per neighbor, then add the GSHUT community to
+ * all paths received from eBGP peers. */
+ } else if (bgp_in_graceful_shutdown(peer->bgp) ||
+ CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_SHUTDOWN))
bgp_attr_add_gshut_community(&new_attr);
}
@@ -4279,14 +4281,6 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
&& (!CHECK_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED)))
SET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING);
- /* If maximum prefix count is configured and current prefix
- * count exeed it.
- */
- if (bgp_maximum_prefix_overflow(peer, afi, safi, 0)) {
- bgp_attr_flush(&new_attr);
- return -1;
- }
-
/* If neighbor soo is configured, tag all incoming routes with
* this SoO tag and then filter out advertisements in
* subgroup_announce_check() if it matches the configured SoO
@@ -4789,14 +4783,9 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD))
bgp_path_info_set_flag(dest, new, BGP_PATH_VALID);
else {
- if (BGP_DEBUG(nht, NHT)) {
- char buf1[INET6_ADDRSTRLEN];
- inet_ntop(AF_INET,
- (const void *)&attr_new->nexthop,
- buf1, INET6_ADDRSTRLEN);
- zlog_debug("%s(%s): NH unresolved", __func__,
- buf1);
- }
+ if (BGP_DEBUG(nht, NHT))
+ zlog_debug("%s(%pI4): NH unresolved", __func__,
+ &attr_new->nexthop);
bgp_path_info_unset_flag(dest, new, BGP_PATH_VALID);
}
} else {
@@ -4806,6 +4795,17 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
bgp_path_info_set_flag(dest, new, BGP_PATH_VALID);
}
+ /* If maximum prefix count is configured and current prefix
+ * count exeed it.
+ */
+ if (bgp_maximum_prefix_overflow(peer, afi, safi, 0)) {
+ reason = "maximum-prefix overflow";
+ bgp_attr_flush(&new_attr);
+ bgp_unlink_nexthop(new);
+ bgp_path_info_delete(dest, new);
+ goto filtered;
+ }
+
/* Addpath ID */
new->addpath_rx_id = addpath_id;
@@ -6296,7 +6296,7 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p,
char buf1[INET6_ADDRSTRLEN];
inet_ntop(p->family,
&p->u.prefix, buf1,
- INET6_ADDRSTRLEN);
+ sizeof(buf1));
zlog_debug(
"%s(%s): Route not in table, not advertising",
__func__, buf1);
@@ -6346,8 +6346,9 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p,
else {
if (BGP_DEBUG(nht, NHT)) {
char buf1[INET6_ADDRSTRLEN];
+
inet_ntop(p->family, &p->u.prefix, buf1,
- INET6_ADDRSTRLEN);
+ sizeof(buf1));
zlog_debug(
"%s(%s): Route not in table, not advertising",
__func__, buf1);
@@ -8910,7 +8911,7 @@ static void route_vty_out_route(struct bgp_dest *dest, const struct prefix *p,
struct vty *vty, json_object *json, bool wide)
{
int len = 0;
- char buf[BUFSIZ];
+ char buf[INET6_ADDRSTRLEN];
if (p->family == AF_INET) {
if (!json) {
@@ -8919,7 +8920,7 @@ static void route_vty_out_route(struct bgp_dest *dest, const struct prefix *p,
json_object_string_add(json, "prefix",
inet_ntop(p->family,
&p->u.prefix, buf,
- BUFSIZ));
+ sizeof(buf)));
json_object_int_add(json, "prefixLen", p->prefixlen);
json_object_string_addf(json, "network", "%pFX", p);
json_object_int_add(json, "version", dest->version);
@@ -8941,9 +8942,9 @@ static void route_vty_out_route(struct bgp_dest *dest, const struct prefix *p,
len = vty_out(vty, "%pFX", p);
else {
json_object_string_add(json, "prefix",
- inet_ntop(p->family,
- &p->u.prefix, buf,
- BUFSIZ));
+ inet_ntop(p->family,
+ &p->u.prefix, buf,
+ sizeof(buf)));
json_object_int_add(json, "prefixLen", p->prefixlen);
json_object_string_addf(json, "network", "%pFX", p);
json_object_int_add(json, "version", dest->version);
@@ -9212,20 +9213,17 @@ void route_vty_out(struct vty *vty, const struct prefix *p,
* attr->mp_nexthop_global_in
*/
if ((safi == SAFI_ENCAP) || (safi == SAFI_MPLS_VPN)) {
- char buf[BUFSIZ];
char nexthop[128];
int af = NEXTHOP_FAMILY(attr->mp_nexthop_len);
switch (af) {
case AF_INET:
- snprintf(nexthop, sizeof(nexthop), "%s",
- inet_ntop(af, &attr->mp_nexthop_global_in, buf,
- BUFSIZ));
+ snprintfrr(nexthop, sizeof(nexthop), "%pI4",
+ &attr->mp_nexthop_global_in);
break;
case AF_INET6:
- snprintf(nexthop, sizeof(nexthop), "%s",
- inet_ntop(af, &attr->mp_nexthop_global, buf,
- BUFSIZ));
+ snprintfrr(nexthop, sizeof(nexthop), "%pI6",
+ &attr->mp_nexthop_global);
break;
default:
snprintf(nexthop, sizeof(nexthop), "?");
@@ -9696,13 +9694,8 @@ void route_vty_out_tmp(struct vty *vty, struct bgp_dest *dest,
vty_out(vty, "%-16pI4", &attr->nexthop);
} else if (p->family == AF_INET6 ||
BGP_ATTR_MP_NEXTHOP_LEN_IP6(attr)) {
- char buf[BUFSIZ];
-
- len = vty_out(
- vty, "%s",
- inet_ntop(AF_INET6,
- &attr->mp_nexthop_global, buf,
- BUFSIZ));
+ len = vty_out(vty, "%pI6",
+ &attr->mp_nexthop_global);
len = wide ? (41 - len) : (16 - len);
if (len < 1)
vty_out(vty, "\n%*s", 36, " ");
@@ -10216,7 +10209,6 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
json_object *json_paths)
{
char buf[INET6_ADDRSTRLEN];
- char buf1[BUFSIZ];
char tag_buf[30];
struct attr *attr = path->attr;
time_t tbuf;
@@ -10596,10 +10588,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID))
vty_out(vty, " (%pI4)", &attr->originator_id);
else
- vty_out(vty, " (%s)",
- inet_ntop(AF_INET,
- &path->peer->remote_id, buf1,
- sizeof(buf1)));
+ vty_out(vty, " (%pI4)", &path->peer->remote_id);
}
}
@@ -11012,11 +11001,12 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
/* Remote SID */
if (path->extra && path->extra->num_sids > 0 && safi != SAFI_EVPN) {
- inet_ntop(AF_INET6, &path->extra->sid[0].sid, buf, sizeof(buf));
if (json_paths)
- json_object_string_add(json_path, "remoteSid", buf);
+ json_object_string_addf(json_path, "remoteSid", "%pI6",
+ &path->extra->sid[0].sid);
else
- vty_out(vty, " Remote SID: %s\n", buf);
+ vty_out(vty, " Remote SID: %pI6\n",
+ &path->extra->sid[0].sid);
}
/* Label Index */
@@ -15517,13 +15507,15 @@ static void bgp_config_write_network_evpn(struct vty *vty, struct bgp *bgp,
/* "network" configuration display. */
if (p->u.prefix_evpn.route_type == 5) {
char local_buf[PREFIX_STRLEN];
+
uint8_t family = is_evpn_prefix_ipaddr_v4((
struct prefix_evpn *)p)
? AF_INET
: AF_INET6;
inet_ntop(family,
- &p->u.prefix_evpn.prefix_addr.ip.ip.addr,
- local_buf, PREFIX_STRLEN);
+ &p->u.prefix_evpn.prefix_addr.ip.ip
+ .addr,
+ local_buf, sizeof(local_buf));
snprintf(buf, sizeof(buf), "%s/%u", local_buf,
p->u.prefix_evpn.prefix_addr
.ip_prefix_length);
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 9422469bca..1ce2eb4352 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -4145,7 +4145,7 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,
safi2str(safi),
inet_ntop(bn_p->family,
&bn_p->u.prefix, buf,
- INET6_ADDRSTRLEN));
+ sizeof(buf)));
bgp_static_update(bgp, bn_p, bgp_static, afi,
safi);
}
@@ -4197,7 +4197,7 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,
safi2str(safi),
inet_ntop(bn_p->family,
&bn_p->u.prefix, buf,
- INET6_ADDRSTRLEN));
+ sizeof(buf)));
bgp_aggregate_route(bgp, bn_p, afi, safi,
aggregate);
}
@@ -6852,9 +6852,9 @@ DEFUN_YANG (no_set_vpn_nexthop,
}
#endif /* KEEP_OLD_VPN_COMMANDS */
-DEFUN_YANG (set_ipx_vpn_nexthop,
+DEFPY_YANG (set_ipx_vpn_nexthop,
set_ipx_vpn_nexthop_cmd,
- "set <ipv4|ipv6> vpn next-hop <A.B.C.D|X:X::X:X>",
+ "set <ipv4|ipv6> vpn next-hop <A.B.C.D$addrv4|X:X::X:X$addrv6>",
SET_STR
"IPv4 information\n"
"IPv6 information\n"
@@ -6870,6 +6870,11 @@ DEFUN_YANG (set_ipx_vpn_nexthop,
if (argv_find_and_parse_afi(argv, argc, &idx, &afi)) {
if (afi == AFI_IP) {
+ if (addrv6_str) {
+ vty_out(vty, "%% IPv4 next-hop expected\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
const char *xpath =
"./set-action[action='frr-bgp-route-map:ipv4-vpn-address']";
@@ -6879,6 +6884,11 @@ DEFUN_YANG (set_ipx_vpn_nexthop,
"%s/rmap-set-action/frr-bgp-route-map:ipv4-address",
xpath);
} else {
+ if (addrv4_str) {
+ vty_out(vty, "%% IPv6 next-hop expected\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
const char *xpath =
"./set-action[action='frr-bgp-route-map:ipv6-vpn-address']";
diff --git a/bgpd/bgp_snmp_bgp4v2.c b/bgpd/bgp_snmp_bgp4v2.c
index d59e63d7e0..1be28e0b2d 100644
--- a/bgpd/bgp_snmp_bgp4v2.c
+++ b/bgpd/bgp_snmp_bgp4v2.c
@@ -39,6 +39,7 @@
#include "bgpd/bgp_table.h"
#include "bgpd/bgp_aspath.h"
#include "bgpd/bgp_attr.h"
+#include "bgpd/bgp_debug.h"
#include "bgpd/bgp_route.h"
#include "bgpd/bgp_fsm.h"
#include "bgpd/bgp_snmp.h"
@@ -270,6 +271,108 @@ static uint8_t *bgpv2PeerTable(struct variable *v, oid name[], size_t *length,
case BGP4V2_PEER_DESCRIPTION:
if (peer->desc)
return SNMP_STRING(peer->desc);
+ break;
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+static uint8_t *bgpv2PeerErrorsTable(struct variable *v, oid name[],
+ size_t *length, int exact, size_t *var_len,
+ WriteMethod **write_method)
+{
+ struct peer *peer;
+ struct ipaddr addr = {};
+
+ if (smux_header_table(v, name, length, exact, var_len, write_method) ==
+ MATCH_FAILED)
+ return NULL;
+
+ peer = bgpv2PeerTable_lookup(v, name, length, exact, &addr);
+ if (!peer)
+ return NULL;
+
+ switch (v->magic) {
+ case BGP4V2_PEER_LAST_ERROR_CODE_RECEIVED:
+ if (peer->last_reset == PEER_DOWN_NOTIFY_RECEIVED)
+ return SNMP_INTEGER(peer->notify.code);
+ else
+ return SNMP_INTEGER(0);
+ case BGP4V2_PEER_LAST_ERROR_SUBCODE_RECEIVED:
+ if (peer->last_reset == PEER_DOWN_NOTIFY_RECEIVED)
+ return SNMP_INTEGER(peer->notify.subcode);
+ else
+ return SNMP_INTEGER(0);
+ case BGP4V2_PEER_LAST_ERROR_RECEIVED_TIME:
+ if (peer->last_reset == PEER_DOWN_NOTIFY_RECEIVED)
+ return SNMP_INTEGER(peer->resettime);
+ else
+ return SNMP_INTEGER(0);
+ case BGP4V2_PEER_LAST_ERROR_RECEIVED_TEXT:
+ if (peer->last_reset == PEER_DOWN_NOTIFY_RECEIVED) {
+ struct bgp_notify notify = peer->notify;
+ char msg_buf[255];
+ const char *msg_str = NULL;
+
+ if (notify.code == BGP_NOTIFY_CEASE &&
+ (notify.subcode ==
+ BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN ||
+ notify.subcode == BGP_NOTIFY_CEASE_ADMIN_RESET)) {
+ msg_str = bgp_notify_admin_message(
+ msg_buf, sizeof(msg_buf),
+ (uint8_t *)notify.data, notify.length);
+ return SNMP_STRING(msg_str);
+ }
+ }
+ return SNMP_STRING("");
+ case BGP4V2_PEER_LAST_ERROR_RECEIVED_DATA:
+ if (peer->last_reset == PEER_DOWN_NOTIFY_RECEIVED)
+ return SNMP_STRING(peer->notify.data);
+ else
+ return SNMP_STRING("");
+ case BGP4V2_PEER_LAST_ERROR_CODE_SENT:
+ if (peer->last_reset != PEER_DOWN_NOTIFY_RECEIVED)
+ return SNMP_INTEGER(peer->notify.code);
+ else
+ return SNMP_INTEGER(0);
+ case BGP4V2_PEER_LAST_ERROR_SUBCODE_SENT:
+ if (peer->last_reset != PEER_DOWN_NOTIFY_RECEIVED)
+ return SNMP_INTEGER(peer->notify.subcode);
+ else
+ return SNMP_INTEGER(0);
+ case BGP4V2_PEER_LAST_ERROR_SENT_TIME:
+ if (peer->last_reset != PEER_DOWN_NOTIFY_RECEIVED)
+ return SNMP_INTEGER(peer->resettime);
+ else
+ return SNMP_INTEGER(0);
+ case BGP4V2_PEER_LAST_ERROR_SENT_TEXT:
+ if (peer->last_reset == PEER_DOWN_NOTIFY_SEND ||
+ peer->last_reset == PEER_DOWN_RTT_SHUTDOWN ||
+ peer->last_reset == PEER_DOWN_USER_SHUTDOWN) {
+ struct bgp_notify notify = peer->notify;
+ char msg_buf[255];
+ const char *msg_str = NULL;
+
+ if (notify.code == BGP_NOTIFY_CEASE &&
+ (notify.subcode ==
+ BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN ||
+ notify.subcode == BGP_NOTIFY_CEASE_ADMIN_RESET)) {
+ msg_str = bgp_notify_admin_message(
+ msg_buf, sizeof(msg_buf),
+ (uint8_t *)notify.data, notify.length);
+ return SNMP_STRING(msg_str);
+ }
+ }
+ return SNMP_STRING("");
+ case BGP4V2_PEER_LAST_ERROR_SENT_DATA:
+ if (peer->last_reset == PEER_DOWN_NOTIFY_SEND ||
+ peer->last_reset == PEER_DOWN_RTT_SHUTDOWN ||
+ peer->last_reset == PEER_DOWN_USER_SHUTDOWN)
+ return SNMP_STRING(peer->notify.data);
+ else
+ return SNMP_STRING("");
default:
break;
}
@@ -278,6 +381,7 @@ static uint8_t *bgpv2PeerTable(struct variable *v, oid name[], size_t *length,
}
static struct variable bgpv2_variables[] = {
+ /* bgp4V2PeerEntry */
{BGP4V2_PEER_INSTANCE,
ASN_UNSIGNED,
RONLY,
@@ -446,6 +550,127 @@ static struct variable bgpv2_variables[] = {
bgpv2PeerTable,
6,
{1, 2, 1, BGP4V2_PEER_DESCRIPTION, 2, 16}},
+ /* bgp4V2PeerErrorsEntry */
+ {BGP4V2_PEER_LAST_ERROR_CODE_RECEIVED,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_CODE_RECEIVED, 1, 4}},
+ {BGP4V2_PEER_LAST_ERROR_CODE_RECEIVED,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_CODE_RECEIVED, 2, 16}},
+ {BGP4V2_PEER_LAST_ERROR_SUBCODE_RECEIVED,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SUBCODE_RECEIVED, 1, 4}},
+ {BGP4V2_PEER_LAST_ERROR_SUBCODE_RECEIVED,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SUBCODE_RECEIVED, 2, 16}},
+ {BGP4V2_PEER_LAST_ERROR_RECEIVED_TIME,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_TIME, 1, 4}},
+ {BGP4V2_PEER_LAST_ERROR_RECEIVED_TIME,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_TIME, 2, 16}},
+ {BGP4V2_PEER_LAST_ERROR_RECEIVED_TEXT,
+ ASN_OCTET_STR,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_TEXT, 1, 4}},
+ {BGP4V2_PEER_LAST_ERROR_RECEIVED_TEXT,
+ ASN_OCTET_STR,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_TEXT, 2, 16}},
+ {BGP4V2_PEER_LAST_ERROR_RECEIVED_DATA,
+ ASN_OCTET_STR,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_DATA, 1, 4}},
+ {BGP4V2_PEER_LAST_ERROR_RECEIVED_DATA,
+ ASN_OCTET_STR,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_RECEIVED_DATA, 2, 16}},
+ {BGP4V2_PEER_LAST_ERROR_CODE_SENT,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_CODE_SENT, 1, 4}},
+ {BGP4V2_PEER_LAST_ERROR_CODE_SENT,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_CODE_SENT, 2, 16}},
+ {BGP4V2_PEER_LAST_ERROR_SUBCODE_SENT,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SUBCODE_SENT, 1, 4}},
+ {BGP4V2_PEER_LAST_ERROR_SUBCODE_SENT,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SUBCODE_SENT, 2, 16}},
+ {BGP4V2_PEER_LAST_ERROR_SENT_TIME,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_TIME, 1, 4}},
+ {BGP4V2_PEER_LAST_ERROR_SENT_TIME,
+ ASN_UNSIGNED,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_TIME, 2, 16}},
+ {BGP4V2_PEER_LAST_ERROR_SENT_TEXT,
+ ASN_OCTET_STR,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_TEXT, 1, 4}},
+ {BGP4V2_PEER_LAST_ERROR_SENT_TEXT,
+ ASN_OCTET_STR,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_TEXT, 2, 16}},
+ {BGP4V2_PEER_LAST_ERROR_SENT_DATA,
+ ASN_OCTET_STR,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_DATA, 1, 4}},
+ {BGP4V2_PEER_LAST_ERROR_SENT_DATA,
+ ASN_OCTET_STR,
+ RONLY,
+ bgpv2PeerErrorsTable,
+ 6,
+ {1, 3, 1, BGP4V2_PEER_LAST_ERROR_SENT_DATA, 2, 16}},
};
int bgp_snmp_bgp4v2_init(struct thread_master *tm)
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 4b17d28968..1f532d4990 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -1308,6 +1308,49 @@ void bgp_clear_soft_in(struct bgp *bgp, afi_t afi, safi_t safi)
bgp_clear(NULL, bgp, afi, safi, clear_all, BGP_CLEAR_SOFT_IN, NULL);
}
+static int peer_flag_modify_vty(struct vty *vty, const char *ip_str,
+ uint64_t flag, int set)
+{
+ int ret;
+ struct peer *peer;
+
+ peer = peer_and_group_lookup_vty(vty, ip_str);
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ /*
+ * If 'neighbor <interface>', then this is for directly connected peers,
+ * we should not accept disable-connected-check.
+ */
+ if (peer->conf_if && (flag == PEER_FLAG_DISABLE_CONNECTED_CHECK)) {
+ vty_out(vty,
+ "%s is directly connected peer, cannot accept disable-connected-check\n",
+ ip_str);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (!set && flag == PEER_FLAG_SHUTDOWN)
+ peer_tx_shutdown_message_unset(peer);
+
+ if (set)
+ ret = peer_flag_set(peer, flag);
+ else
+ ret = peer_flag_unset(peer, flag);
+
+ return bgp_vty_return(vty, ret);
+}
+
+static int peer_flag_set_vty(struct vty *vty, const char *ip_str, uint64_t flag)
+{
+ return peer_flag_modify_vty(vty, ip_str, flag, 1);
+}
+
+static int peer_flag_unset_vty(struct vty *vty, const char *ip_str,
+ uint64_t flag)
+{
+ return peer_flag_modify_vty(vty, ip_str, flag, 0);
+}
+
#include "bgpd/bgp_vty_clippy.c"
DEFUN_HIDDEN (bgp_local_mac,
@@ -3326,6 +3369,42 @@ DEFUN (no_bgp_neighbor_graceful_restart_disable,
return bgp_vty_return(vty, ret);
}
+DEFPY (neighbor_graceful_shutdown,
+ neighbor_graceful_shutdown_cmd,
+ "[no$no] neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor graceful-shutdown",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Graceful shutdown\n")
+{
+ afi_t afi;
+ safi_t safi;
+ struct peer *peer;
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ int ret;
+
+ peer = peer_and_group_lookup_vty(vty, neighbor);
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ if (no)
+ ret = peer_flag_unset_vty(vty, neighbor,
+ PEER_FLAG_GRACEFUL_SHUTDOWN);
+ else
+ ret = peer_flag_set_vty(vty, neighbor,
+ PEER_FLAG_GRACEFUL_SHUTDOWN);
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (!peer->afc[afi][safi])
+ continue;
+
+ bgp_clear(vty, bgp, afi, safi, clear_peer, BGP_CLEAR_SOFT_IN,
+ neighbor);
+ }
+
+ return ret;
+}
+
DEFUN_HIDDEN (bgp_graceful_restart_disable_eor,
bgp_graceful_restart_disable_eor_cmd,
"bgp graceful-restart disable-eor",
@@ -5251,51 +5330,6 @@ ALIAS_HIDDEN(no_neighbor_set_peer_group, no_neighbor_set_peer_group_hidden_cmd,
"Member of the peer-group\n"
"Peer-group name\n")
-static int peer_flag_modify_vty(struct vty *vty, const char *ip_str,
- uint64_t flag, int set)
-{
- int ret;
- struct peer *peer;
-
- peer = peer_and_group_lookup_vty(vty, ip_str);
- if (!peer)
- return CMD_WARNING_CONFIG_FAILED;
-
- /*
- * If 'neighbor <interface>', then this is for directly connected peers,
- * we should not accept disable-connected-check.
- */
- if (peer->conf_if && (flag == PEER_FLAG_DISABLE_CONNECTED_CHECK)) {
- vty_out(vty,
- "%s is directly connected peer, cannot accept disable-connected-check\n",
- ip_str);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (!set && flag == PEER_FLAG_SHUTDOWN) {
- peer_tx_shutdown_message_unset(peer);
- UNSET_FLAG(peer->sflags, PEER_STATUS_RTT_SHUTDOWN);
- }
-
- if (set)
- ret = peer_flag_set(peer, flag);
- else
- ret = peer_flag_unset(peer, flag);
-
- return bgp_vty_return(vty, ret);
-}
-
-static int peer_flag_set_vty(struct vty *vty, const char *ip_str, uint64_t flag)
-{
- return peer_flag_modify_vty(vty, ip_str, flag, 1);
-}
-
-static int peer_flag_unset_vty(struct vty *vty, const char *ip_str,
- uint64_t flag)
-{
- return peer_flag_modify_vty(vty, ip_str, flag, 0);
-}
-
/* neighbor passive. */
DEFUN (neighbor_passive,
neighbor_passive_cmd,
@@ -9884,7 +9918,6 @@ DEFPY (show_bgp_srv6,
struct listnode *node;
struct srv6_locator_chunk *chunk;
struct bgp_srv6_function *func;
- char buf[256];
bgp = bgp_get_default();
if (!bgp)
@@ -9903,8 +9936,7 @@ DEFPY (show_bgp_srv6,
vty_out(vty, "functions:\n");
for (ALL_LIST_ELEMENTS_RO(bgp->srv6_functions, node, func)) {
- inet_ntop(AF_INET6, &func->sid, buf, sizeof(buf));
- vty_out(vty, "- sid: %s\n", buf);
+ vty_out(vty, "- sid: %pI6\n", &func->sid);
vty_out(vty, " locator: %s\n", func->locator_name);
}
@@ -12850,7 +12882,6 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
json_object *json)
{
struct bgp *bgp;
- char buf1[PREFIX2STR_BUFFER];
char timebuf[BGP_UPTIME_LEN];
char dn_flag[2];
afi_t afi;
@@ -13174,11 +13205,8 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
/* BGP Version. */
vty_out(vty, " BGP version 4");
- vty_out(vty, ", remote router ID %s",
- inet_ntop(AF_INET, &p->remote_id, buf1, sizeof(buf1)));
- vty_out(vty, ", local router ID %s\n",
- inet_ntop(AF_INET, &bgp->router_id, buf1,
- sizeof(buf1)));
+ vty_out(vty, ", remote router ID %pI4", &p->remote_id);
+ vty_out(vty, ", local router ID %pI4\n", &bgp->router_id);
/* Confederation */
if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)
@@ -14548,15 +14576,11 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
"bgpConnection",
"nonSharedNetwork");
} else {
- vty_out(vty, "Nexthop: %s\n",
- inet_ntop(AF_INET, &p->nexthop.v4, buf1,
- sizeof(buf1)));
- vty_out(vty, "Nexthop global: %s\n",
- inet_ntop(AF_INET6, &p->nexthop.v6_global, buf1,
- sizeof(buf1)));
- vty_out(vty, "Nexthop local: %s\n",
- inet_ntop(AF_INET6, &p->nexthop.v6_local, buf1,
- sizeof(buf1)));
+ vty_out(vty, "Nexthop: %pI4\n", &p->nexthop.v4);
+ vty_out(vty, "Nexthop global: %pI6\n",
+ &p->nexthop.v6_global);
+ vty_out(vty, "Nexthop local: %pI6\n",
+ &p->nexthop.v6_local);
vty_out(vty, "BGP connection: %s\n",
p->shared_network ? "shared network"
: "non shared network");
@@ -17220,6 +17244,10 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
if (peergroup_flag_check(peer, PEER_FLAG_AIGP))
vty_out(vty, " neighbor %s aigp\n", addr);
+ /* graceful-shutdown */
+ if (peergroup_flag_check(peer, PEER_FLAG_GRACEFUL_SHUTDOWN))
+ vty_out(vty, " neighbor %s graceful-shutdown\n", addr);
+
/* role */
if (peergroup_flag_check(peer, PEER_FLAG_ROLE) &&
peer->local_role != ROLE_UNDEFINED)
@@ -18666,6 +18694,9 @@ void bgp_vty_init(void)
/* "neighbor aigp" commands. */
install_element(BGP_NODE, &neighbor_aigp_cmd);
+ /* "neighbor graceful-shutdown" command */
+ install_element(BGP_NODE, &neighbor_graceful_shutdown_cmd);
+
/* bgp disable-ebgp-connected-nh-check */
install_element(BGP_NODE, &bgp_disable_connected_route_check_cmd);
install_element(BGP_NODE, &no_bgp_disable_connected_route_check_cmd);
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 2badc25cd8..5ab1a6afa6 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -3682,35 +3682,33 @@ void bgp_zebra_announce_default(struct bgp *bgp, struct nexthop *nh,
/* redirect IP */
if (afi == AFI_IP && nh->gate.ipv4.s_addr != INADDR_ANY) {
- char buff[PREFIX_STRLEN];
-
api_nh->vrf_id = nh->vrf_id;
api_nh->gate.ipv4 = nh->gate.ipv4;
api_nh->type = NEXTHOP_TYPE_IPV4;
- inet_ntop(AF_INET, &(nh->gate.ipv4), buff, INET_ADDRSTRLEN);
if (BGP_DEBUG(zebra, ZEBRA))
- zlog_debug("BGP: %s default route to %s table %d (redirect IP)",
- announce ? "adding" : "withdrawing",
- buff, table_id);
+ zlog_debug(
+ "BGP: %s default route to %pI4 table %d (redirect IP)",
+ announce ? "adding" : "withdrawing",
+ &nh->gate.ipv4, table_id);
+
zclient_route_send(announce ? ZEBRA_ROUTE_ADD
: ZEBRA_ROUTE_DELETE,
zclient, &api);
} else if (afi == AFI_IP6 &&
memcmp(&nh->gate.ipv6,
&in6addr_any, sizeof(struct in6_addr))) {
- char buff[PREFIX_STRLEN];
-
api_nh->vrf_id = nh->vrf_id;
memcpy(&api_nh->gate.ipv6, &nh->gate.ipv6,
sizeof(struct in6_addr));
api_nh->type = NEXTHOP_TYPE_IPV6;
- inet_ntop(AF_INET6, &(nh->gate.ipv6), buff, INET_ADDRSTRLEN);
if (BGP_DEBUG(zebra, ZEBRA))
- zlog_debug("BGP: %s default route to %s table %d (redirect IP)",
- announce ? "adding" : "withdrawing",
- buff, table_id);
+ zlog_debug(
+ "BGP: %s default route to %pI6 table %d (redirect IP)",
+ announce ? "adding" : "withdrawing",
+ &nh->gate.ipv6, table_id);
+
zclient_route_send(announce ? ZEBRA_ROUTE_ADD
: ZEBRA_ROUTE_DELETE,
zclient, &api);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 6ad1cf2c06..12ee96ff45 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -4289,6 +4289,7 @@ static const struct peer_flag_action peer_flag_action_list[] = {
{PEER_FLAG_ROLE, 0, peer_change_reset},
{PEER_FLAG_PORT, 0, peer_change_reset},
{PEER_FLAG_AIGP, 0, peer_change_none},
+ {PEER_FLAG_GRACEFUL_SHUTDOWN, 0, peer_change_none},
{0, 0, 0}};
static const struct peer_flag_action peer_af_flag_action_list[] = {
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 8a0ec5ad2d..b7a329fdcd 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -1413,6 +1413,7 @@ struct peer {
#define PEER_FLAG_ROLE (1ULL << 32)
#define PEER_FLAG_PORT (1ULL << 33)
#define PEER_FLAG_AIGP (1ULL << 34)
+#define PEER_FLAG_GRACEFUL_SHUTDOWN (1ULL << 35)
/*
*GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART
diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c
index a5d57748b7..80d0b3e269 100644
--- a/bgpd/rfapi/rfapi.c
+++ b/bgpd/rfapi/rfapi.c
@@ -1273,13 +1273,15 @@ static int rfapi_open_inner(struct rfapi_descriptor *rfd, struct bgp *bgp,
}
{ /* base code assumes have valid host pointer */
- char buf[BUFSIZ];
+ char buf[INET6_ADDRSTRLEN];
buf[0] = 0;
if (rfd->vn_addr.addr_family == AF_INET) {
- inet_ntop(AF_INET, &rfd->vn_addr.addr.v4, buf, BUFSIZ);
+ inet_ntop(AF_INET, &rfd->vn_addr.addr.v4, buf,
+ sizeof(buf));
} else if (rfd->vn_addr.addr_family == AF_INET6) {
- inet_ntop(AF_INET6, &rfd->vn_addr.addr.v6, buf, BUFSIZ);
+ inet_ntop(AF_INET6, &rfd->vn_addr.addr.v6, buf,
+ sizeof(buf));
}
rfd->peer->host = XSTRDUP(MTYPE_BGP_PEER_HOST, buf);
}
diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c
index 1dd623d3f3..2aae0bc616 100644
--- a/bgpd/rfapi/rfapi_import.c
+++ b/bgpd/rfapi/rfapi_import.c
@@ -2908,7 +2908,8 @@ static void rfapiBgpInfoFilteredImportEncap(
vnc_zlog_debug_verbose(
"%s: entry: %s: prefix %s/%d", __func__, action_str,
- inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ), p->prefixlen);
+ inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf)),
+ p->prefixlen);
memset(&p_firstbpi_old, 0, sizeof(p_firstbpi_old));
memset(&p_firstbpi_new, 0, sizeof(p_firstbpi_new));
diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c
index 23f43fa7d3..719d898e3c 100644
--- a/bgpd/rfapi/rfapi_vty.c
+++ b/bgpd/rfapi/rfapi_vty.c
@@ -411,9 +411,10 @@ void rfapi_vty_out_vncinfo(struct vty *vty, const struct prefix *p,
if (!rfapiGetVncTunnelUnAddr(bpi->attr, &pfx_un)) {
char buf[BUFSIZ];
+
vty_out(vty, "UN=%s",
inet_ntop(pfx_un.family, pfx_un.u.val, buf,
- BUFSIZ));
+ sizeof(buf)));
}
}
@@ -432,11 +433,7 @@ void rfapi_vty_out_vncinfo(struct vty *vty, const struct prefix *p,
decode_label(&bpi->extra->label[0]));
if (bpi->extra->num_sids) {
- char buf[BUFSIZ];
-
- vty_out(vty, " sid=%s",
- inet_ntop(AF_INET6, &bpi->extra->sid[0].sid,
- buf, sizeof(buf)));
+ vty_out(vty, " sid=%pI6", &bpi->extra->sid[0].sid);
if (bpi->extra->sid[0].loc_block_len != 0) {
vty_out(vty, " sid_structure=[%d,%d,%d,%d]",
@@ -466,7 +463,6 @@ void rfapiPrintAttrPtrs(void *stream, struct attr *attr)
const char *vty_newline;
struct transit *transit;
struct cluster_list *cluster;
- char buf[BUFSIZ];
struct ecommunity *ecomm;
struct community *comm;
@@ -478,8 +474,7 @@ void rfapiPrintAttrPtrs(void *stream, struct attr *attr)
return;
/* IPv4 Nexthop */
- inet_ntop(AF_INET, &attr->nexthop, buf, BUFSIZ);
- fp(out, " nexthop=%s%s", buf, HVTYNL);
+ fp(out, " nexthop=%pI4%s", &attr->nexthop, HVTYNL);
fp(out, " aspath=%p, refcnt=%d%s", attr->aspath,
(attr->aspath ? attr->aspath->refcnt : 0), HVTYNL);
@@ -571,15 +566,12 @@ void rfapiPrintBi(void *stream, struct bgp_path_info *bpi)
/* Nexthop */
if (af == AF_INET) {
- r = snprintf(p, REMAIN, "%s",
- inet_ntop(AF_INET,
- &bpi->attr->mp_nexthop_global_in, buf,
- BUFSIZ));
+ r = snprintfrr(p, REMAIN, "%pI4",
+ &bpi->attr->mp_nexthop_global_in);
INCP;
} else if (af == AF_INET6) {
- r = snprintf(p, REMAIN, "%s",
- inet_ntop(AF_INET6, &bpi->attr->mp_nexthop_global,
- buf, BUFSIZ));
+ r = snprintfrr(p, REMAIN, "%pI6",
+ &bpi->attr->mp_nexthop_global);
INCP;
} else {
r = snprintf(p, REMAIN, "?");
@@ -590,9 +582,9 @@ void rfapiPrintBi(void *stream, struct bgp_path_info *bpi)
* VNC tunnel subtlv, if present, contains UN address
*/
if (!rfapiGetVncTunnelUnAddr(bpi->attr, &pfx_un)) {
- r = snprintf(
- p, REMAIN, " un=%s",
- inet_ntop(pfx_un.family, pfx_un.u.val, buf, BUFSIZ));
+ r = snprintf(p, REMAIN, " un=%s",
+ inet_ntop(pfx_un.family, pfx_un.u.val, buf,
+ sizeof(buf)));
INCP;
}
@@ -719,7 +711,8 @@ char *rfapiMonitorVpn2Str(struct rfapi_monitor_vpn *m, char *buf, int size)
rc = snprintf(buf, size,
"m=%p, next=%p, rfd=%p(vn=%s un=%s), p=%s/%d, node=%p", m,
m->next, m->rfd, buf_vn, buf_un,
- inet_ntop(m->p.family, &m->p.u.prefix, buf_pfx, BUFSIZ),
+ inet_ntop(m->p.family, &m->p.u.prefix, buf_pfx,
+ sizeof(buf_pfx)),
m->p.prefixlen, m->node);
buf[size - 1] = 0;
if (rc >= size)
@@ -800,9 +793,9 @@ void rfapiShowImportTable(void *stream, const char *label, struct agg_table *rt,
const struct prefix *p = agg_node_get_prefix(rn);
if (p->family == AF_ETHERNET) {
- rfapiEthAddr2Str(&p->u.prefix_eth, buf, BUFSIZ);
+ rfapiEthAddr2Str(&p->u.prefix_eth, buf, sizeof(buf));
} else {
- inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ);
+ inet_ntop(p->family, &p->u.prefix, buf, sizeof(buf));
}
fp(out, "%s/%d @%p #%d%s", buf, p->prefixlen, rn,
@@ -933,7 +926,7 @@ int rfapiShowVncQueries(void *stream, struct prefix *pfx_match)
buf_remain, BUFSIZ);
fp(out, " %-15s %-10s\n",
inet_ntop(m->p.family, &m->p.u.prefix,
- buf_pfx, BUFSIZ),
+ buf_pfx, sizeof(buf_pfx)),
buf_remain);
}
}
@@ -1052,9 +1045,10 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream,
* Prefix
*/
buf_pfx[0] = 0;
- snprintf(buf_pfx, sizeof(buf_pfx), "%s/%d",
- rfapi_ntop(p->family, &p->u.prefix, buf_ntop, BUFSIZ),
- p->prefixlen);
+ snprintf(
+ buf_pfx, sizeof(buf_pfx), "%s/%d",
+ rfapi_ntop(p->family, &p->u.prefix, buf_ntop, sizeof(buf_ntop)),
+ p->prefixlen);
buf_pfx[BUFSIZ - 1] = 0;
nlines++;
@@ -1065,7 +1059,7 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream,
if (!rfapiGetUnAddrOfVpnBi(bpi, &pfx_un)) {
snprintf(buf_un, sizeof(buf_un), "%s",
inet_ntop(pfx_un.family, &pfx_un.u.prefix, buf_ntop,
- BUFSIZ));
+ sizeof(buf_ntop)));
}
bgp_attr_extcom_tunnel_type(bpi->attr, &tun_type);
@@ -1079,7 +1073,7 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream,
*/
snprintf(buf_un, sizeof(buf_un), "%s",
inet_ntop(pfx_vn.family, &pfx_vn.u.prefix, buf_ntop,
- BUFSIZ));
+ sizeof(buf_ntop)));
if (bpi->extra) {
uint32_t l = decode_label(&bpi->extra->label[0]);
snprintf(buf_vn, sizeof(buf_vn), "Label: %d", l);
@@ -1090,7 +1084,7 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream,
} else {
snprintf(buf_vn, sizeof(buf_vn), "%s",
inet_ntop(pfx_vn.family, &pfx_vn.u.prefix, buf_ntop,
- BUFSIZ));
+ sizeof(buf_ntop)));
}
buf_vn[BUFSIZ - 1] = 0;
buf_un[BUFSIZ - 1] = 0;
diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst
index 688ce545fb..b8e298dd3c 100644
--- a/doc/developer/workflow.rst
+++ b/doc/developer/workflow.rst
@@ -139,6 +139,10 @@ March/July/November. Walking backwards from this date:
version. Once the release is done, whatever updates we make to changelog
files on the release branch need to be cherry-picked to the master branch.
+ Update essential dates in advance for reference table (below) when
+ the next freeze, dev/X.Y, RC, and release phases are scheduled. This should
+ go in the ``master`` branch.
+
- 2 weeks earlier, a ``frr-X.Y-rc`` release candidate is tagged.
.. code-block:: console
@@ -163,15 +167,29 @@ as early as possible, i.e. the first 2-week window.
For reference, the expected release schedule according to the above is:
+---------+------------+------------+------------+------------+------------+
-| Release | 2022-07-05 | 2022-11-01 | 2023-03-07 | 2023-07-04 | 2023-10-31 |
+| Release | 2023-03-07 | 2023-07-04 | 2023-10-31 | 2024-02-27 | 2024-06-25 |
+---------+------------+------------+------------+------------+------------+
-| RC | 2022-06-21 | 2022-10-18 | 2023-02-21 | 2023-06-20 | 2023-10-17 |
+| RC | 2023-02-21 | 2023-06-20 | 2023-10-17 | 2024-02-13 | 2024-06-11 |
+---------+------------+------------+------------+------------+------------+
-| dev/X.Y | 2022-06-07 | 2022-10-04 | 2023-02-07 | 2023-06-06 | 2023-10-03 |
+| dev/X.Y | 2023-02-07 | 2023-06-06 | 2023-10-03 | 2024-01-30 | 2024-05-28 |
+---------+------------+------------+------------+------------+------------+
-| freeze | 2022-05-24 | 2022-09-20 | 2023-01-24 | 2023-05-23 | 2023-09-19 |
+| freeze | 2023-01-24 | 2023-05-23 | 2023-09-19 | 2024-01-16 | 2024-05-14 |
+---------+------------+------------+------------+------------+------------+
+Here is the hint on how to get the dates easily:
+
+ .. code-block:: console
+
+ ~$ # Last freeze date was 2023-09-19
+ ~$ date +%F --date='2023-09-19 +119 days' # Next freeze date
+ 2024-01-16
+ ~$ date +%F --date='2024-01-16 +14 days' # Next dev/X.Y date
+ 2024-01-30
+ ~$ date +%F --date='2024-01-30 +14 days' # Next RC date
+ 2024-02-13
+ ~$ date +%F --date='2024-02-13 +14 days' # Next Release date
+ 2024-02-27
+
Each release is managed by one or more volunteer release managers from the FRR
community. These release managers are expected to handle the branch for a period
of one year. To spread and distribute this workload, this should be rotated for
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 4a812a75e9..98338ebf32 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -1704,6 +1704,11 @@ Configuring Peers
Default: disabled.
+.. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> graceful-shutdown
+
+ Mark all routes from this neighbor as less preferred by setting ``graceful-shutdown``
+ community, and local-preference to 0.
+
.. clicmd:: bgp fast-external-failover
This command causes bgp to take down ebgp peers immediately
diff --git a/doc/user/setup.rst b/doc/user/setup.rst
index dcc7607e48..372494fbce 100644
--- a/doc/user/setup.rst
+++ b/doc/user/setup.rst
@@ -116,6 +116,16 @@ allow this to happen.
::
+ FRR_NO_ROOT="yes"
+
+This option allows you to run FRR as a non-root user. Use this option
+only when you know what you are doing since most of the daemons
+in FRR will not be able to run under a regular user. This option
+is useful for example when you run FRR in a container with a designated
+user instead of root.
+
+::
+
zebra_options=" -s 90000000 --daemon -A 127.0.0.1"
bgpd_options=" --daemon -A 127.0.0.1"
...
diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst
index c44642a788..a78731ca94 100644
--- a/doc/user/zebra.rst
+++ b/doc/user/zebra.rst
@@ -305,7 +305,8 @@ the default route.
indicates that the operator wants to see the multicast rib address resolution
table. An alternative form of the command is ``show ip import-check`` and this
form of the command is deprecated at this point in time.
- If the ``json`` option is specified, output is displayed in JSON format.
+ User can get that information as JSON string when ``json`` key word
+ at the end of cli is presented.
PBR dataplane programming
=========================
diff --git a/lib/vty.c b/lib/vty.c
index 5fe8d82473..352080e580 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -447,7 +447,8 @@ static int vty_command(struct vty *vty, char *buf)
/*
* Log non empty command lines
*/
- if (do_log_commands)
+ if (do_log_commands &&
+ strncmp(buf, "echo PING", strlen("echo PING")) != 0)
cp = buf;
if (cp != NULL) {
/* Skip white spaces. */
diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c
index e9c42bb80c..e007709f99 100644
--- a/ospf6d/ospf6_abr.c
+++ b/ospf6d/ospf6_abr.c
@@ -1322,7 +1322,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
ospf6_copy_nexthops(tmp_route->nh_list,
o_path->nh_list);
- if (ospf6_route_cmp_nexthops(tmp_route, route) != 0) {
+ if (!ospf6_route_cmp_nexthops(tmp_route, route)) {
/* adv. router exists in the list, update nhs */
list_delete_all_node(o_path->nh_list);
ospf6_copy_nexthops(o_path->nh_list,
diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c
index db94b85b1b..9603c91a9a 100644
--- a/ospf6d/ospf6_route.c
+++ b/ospf6d/ospf6_route.c
@@ -246,7 +246,10 @@ void ospf6_merge_nexthops(struct list *dst, struct list *src)
}
}
-int ospf6_route_cmp_nexthops(struct ospf6_route *a, struct ospf6_route *b)
+/*
+ * If the nexthops are the same return true
+ */
+bool ospf6_route_cmp_nexthops(struct ospf6_route *a, struct ospf6_route *b)
{
struct listnode *anode, *bnode;
struct ospf6_nexthop *anh, *bnh;
@@ -264,14 +267,14 @@ int ospf6_route_cmp_nexthops(struct ospf6_route *a, struct ospf6_route *b)
/* Currnet List A element not found List B
* Non-Identical lists return */
if (identical == false)
- return 1;
+ return false;
}
- return 0;
+ return true;
} else
- return 1;
+ return false;
}
/* One of the routes doesn't exist ? */
- return (1);
+ return false;
}
int ospf6_num_nexthops(struct list *nh_list)
@@ -577,12 +580,7 @@ ospf6_route_lookup_identical(struct ospf6_route *route,
for (target = ospf6_route_lookup(&route->prefix, table); target;
target = target->next) {
- if (target->type == route->type
- && prefix_same(&target->prefix, &route->prefix)
- && target->path.type == route->path.type
- && target->path.cost == route->path.cost
- && target->path.u.cost_e2 == route->path.u.cost_e2
- && ospf6_route_cmp_nexthops(target, route) == 0)
+ if (ospf6_route_is_identical(target, route))
return target;
}
return NULL;
@@ -702,6 +700,27 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route,
}
if (old) {
+ /* if route does not actually change, return unchanged */
+ if (ospf6_route_is_identical(old, route)) {
+ if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
+ zlog_debug(
+ "%s %p: route add %p: needless update of %p old cost %u",
+ ospf6_route_table_name(table),
+ (void *)table, (void *)route,
+ (void *)old, old->path.cost);
+ else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
+ zlog_debug("%s: route add: needless update",
+ ospf6_route_table_name(table));
+
+ ospf6_route_delete(route);
+ SET_FLAG(old->flag, OSPF6_ROUTE_ADD);
+ ospf6_route_table_assert(table);
+
+ /* to free the lookup lock */
+ route_unlock_node(node);
+ return old;
+ }
+
if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
zlog_debug(
"%s %p: route add %p cost %u paths %u nh %u: update of %p cost %u paths %u nh %u",
diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h
index bb5827a176..71a84a5c5d 100644
--- a/ospf6d/ospf6_route.h
+++ b/ospf6d/ospf6_route.h
@@ -297,6 +297,14 @@ extern const char *const ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX];
&& (ra)->path.origin.type == (rb)->path.origin.type \
&& (ra)->path.origin.id == (rb)->path.origin.id \
&& (ra)->path.origin.adv_router == (rb)->path.origin.adv_router)
+#define ospf6_route_is_identical(ra, rb) \
+ ((ra)->type == (rb)->type && \
+ prefix_same(&(ra)->prefix, &(rb)->prefix) && \
+ (ra)->path.type == (rb)->path.type && \
+ (ra)->path.cost == (rb)->path.cost && \
+ (ra)->path.u.cost_e2 == (rb)->path.u.cost_e2 && \
+ listcount(ra->paths) == listcount(rb->paths) && \
+ ospf6_route_cmp_nexthops(ra, rb))
#define ospf6_route_is_best(r) (CHECK_FLAG ((r)->flag, OSPF6_ROUTE_BEST))
@@ -322,8 +330,8 @@ extern void ospf6_add_nexthop(struct list *nh_list, int ifindex,
struct in6_addr *addr);
extern void ospf6_add_route_nexthop_blackhole(struct ospf6_route *route);
extern int ospf6_num_nexthops(struct list *nh_list);
-extern int ospf6_route_cmp_nexthops(struct ospf6_route *a,
- struct ospf6_route *b);
+extern bool ospf6_route_cmp_nexthops(struct ospf6_route *a,
+ struct ospf6_route *b);
extern void ospf6_route_zebra_copy_nexthops(struct ospf6_route *route,
struct zapi_nexthop nexthops[],
int entries, vrf_id_t vrf_id);
diff --git a/ospfd/ospf_api.h b/ospfd/ospf_api.h
index 6f569e962d..fd741c3c48 100644
--- a/ospfd/ospf_api.h
+++ b/ospfd/ospf_api.h
@@ -298,7 +298,7 @@ struct apimsg {
} u;
};
-#define OSPF_API_MAX_MSG_SIZE (sizeof(struct apimsg) + OSPF_MAX_LSA_SIZE)
+#define OSPF_API_MAX_MSG_SIZE (sizeof(struct apimsg) + OSPF_MAX_PACKET_SIZE)
/* -----------------------------------------------------------
* Prototypes for specific messages
diff --git a/ospfd/ospf_ism.c b/ospfd/ospf_ism.c
index ab75ab9a1a..d4565b6651 100644
--- a/ospfd/ospf_ism.c
+++ b/ospfd/ospf_ism.c
@@ -223,8 +223,10 @@ int ospf_dr_election(struct ospf_interface *oi)
new_state = ospf_ism_state(oi);
- zlog_debug("DR-Election[1st]: Backup %pI4", &BDR(oi));
- zlog_debug("DR-Election[1st]: DR %pI4", &DR(oi));
+ if (IS_DEBUG_OSPF(ism, ISM_STATUS)) {
+ zlog_debug("DR-Election[1st]: Backup %pI4", &BDR(oi));
+ zlog_debug("DR-Election[1st]: DR %pI4", &DR(oi));
+ }
if (new_state != old_state
&& !(new_state == ISM_DROther && old_state < ISM_DROther)) {
@@ -233,8 +235,10 @@ int ospf_dr_election(struct ospf_interface *oi)
new_state = ospf_ism_state(oi);
- zlog_debug("DR-Election[2nd]: Backup %pI4", &BDR(oi));
- zlog_debug("DR-Election[2nd]: DR %pI4", &DR(oi));
+ if (IS_DEBUG_OSPF(ism, ISM_STATUS)) {
+ zlog_debug("DR-Election[2nd]: Backup %pI4", &BDR(oi));
+ zlog_debug("DR-Election[2nd]: DR %pI4", &DR(oi));
+ }
}
list_delete(&el_list);
diff --git a/ospfd/ospf_network.c b/ospfd/ospf_network.c
index be06afe532..a8c9493ec8 100644
--- a/ospfd/ospf_network.c
+++ b/ospfd/ospf_network.c
@@ -104,11 +104,12 @@ int ospf_if_add_alldrouters(struct ospf *top, struct prefix *p,
"can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %pI4, ifindex %u, AllDRouters): %s; perhaps a kernel limit on # of multicast group memberships has been exceeded?",
top->fd, &p->u.prefix4, ifindex,
safe_strerror(errno));
- else
- zlog_debug(
- "interface %pI4 [%u] join AllDRouters Multicast group.",
- &p->u.prefix4, ifindex);
-
+ else {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug(
+ "interface %pI4 [%u] join AllDRouters Multicast group.",
+ &p->u.prefix4, ifindex);
+ }
return ret;
}
diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c
index 3f82d86921..2403b567a5 100644
--- a/ospfd/ospfd.c
+++ b/ospfd/ospfd.c
@@ -89,6 +89,25 @@ static int ospf_network_match_iface(const struct connected *,
const struct prefix *);
static void ospf_finish_final(struct ospf *);
+/* API to clean refresh queues and LSAs */
+static void ospf_free_refresh_queue(struct ospf *ospf)
+{
+ for (int i = 0; i < OSPF_LSA_REFRESHER_SLOTS; i++) {
+ struct list *list = ospf->lsa_refresh_queue.qs[i];
+ struct listnode *node, *nnode;
+ struct ospf_lsa *lsa;
+
+ if (list) {
+ for (ALL_LIST_ELEMENTS(list, node, nnode, lsa)) {
+ listnode_delete(list, lsa);
+ lsa->refresh_list = -1;
+ ospf_lsa_unlock(&lsa);
+ }
+ list_delete(&list);
+ ospf->lsa_refresh_queue.qs[i] = NULL;
+ }
+ }
+}
#define OSPF_EXTERNAL_LSA_ORIGINATE_DELAY 1
int p_spaces_compare_func(const struct p_space *a, const struct p_space *b)
@@ -895,6 +914,8 @@ static void ospf_finish_final(struct ospf *ospf)
route_table_finish(ospf->rt_aggr_tbl);
+ ospf_free_refresh_queue(ospf);
+
list_delete(&ospf->areas);
list_delete(&ospf->oi_write_q);
diff --git a/pimd/pim_cmd_common.c b/pimd/pim_cmd_common.c
index b39f688cdb..28e4c488f3 100644
--- a/pimd/pim_cmd_common.c
+++ b/pimd/pim_cmd_common.c
@@ -2824,21 +2824,35 @@ static int pim_print_vty_pnc_cache_walkcb(struct hash_bucket *bucket, void *arg)
struct nexthop *nh_node = NULL;
ifindex_t first_ifindex;
struct interface *ifp = NULL;
+ struct ttable *tt = NULL;
+ char *table = NULL;
+
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(tt, "Address|Interface|Nexthop");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next) {
first_ifindex = nh_node->ifindex;
ifp = if_lookup_by_index(first_ifindex, pim->vrf->vrf_id);
- vty_out(vty, "%-15pPA ", &pnc->rpf.rpf_addr);
- vty_out(vty, "%-16s ", ifp ? ifp->name : "NULL");
#if PIM_IPV == 4
- vty_out(vty, "%pI4 ", &nh_node->gate.ipv4);
+ ttable_add_row(tt, "%pPA|%s|%pI4", &pnc->rpf.rpf_addr,
+ ifp ? ifp->name : "NULL", &nh_node->gate.ipv4);
#else
- vty_out(vty, "%pI6 ", &nh_node->gate.ipv6);
+ ttable_add_row(tt, "%pPA|%s|%pI6", &pnc->rpf.rpf_addr,
+ ifp ? ifp->name : "NULL", &nh_node->gate.ipv6);
#endif
- vty_out(vty, "\n");
}
+ /* Dump the generated table. */
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+ ttable_del(tt);
+
return CMD_SUCCESS;
}
@@ -2966,8 +2980,6 @@ void pim_show_nexthop(struct pim_instance *pim, struct vty *vty, bool uj)
} else {
vty_out(vty, "Number of registered addresses: %lu\n",
pim->rpf_hash->count);
- vty_out(vty, "Address Interface Nexthop\n");
- vty_out(vty, "---------------------------------------------\n");
}
if (uj) {
@@ -5355,6 +5367,7 @@ static void pim_show_group_rp_mappings_info(struct pim_instance *pim,
json_object *json = NULL;
json_object *json_group = NULL;
json_object *json_row = NULL;
+ struct ttable *tt = NULL;
if (uj) {
json = json_object_new_object();
@@ -5385,10 +5398,15 @@ static void pim_show_group_rp_mappings_info(struct pim_instance *pim,
} else {
vty_out(vty, "Group Address %pFX\n", &bsgrp->group);
vty_out(vty, "--------------------------\n");
- vty_out(vty, "%-15s %-15s %-15s %-15s\n", "Rp Address",
- "priority", "Holdtime", "Hash");
-
- vty_out(vty, "(ACTIVE)\n");
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(tt, "Rp Address|priority|Holdtime|Hash");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
+
+ ttable_add_row(tt, "%s|%c|%c|%c", "(ACTIVE)", ' ', ' ',
+ ' ');
}
frr_each (bsm_rpinfos, bsgrp->bsrp_list, bsm_rp) {
@@ -5408,11 +5426,22 @@ static void pim_show_group_rp_mappings_info(struct pim_instance *pim,
&bsm_rp->rp_address);
} else {
- vty_out(vty, "%-15pPA %-15u %-15u %-15u\n",
+ ttable_add_row(
+ tt, "%pPA|%u|%u|%u",
&bsm_rp->rp_address, bsm_rp->rp_prio,
bsm_rp->rp_holdtime, bsm_rp->hash);
}
}
+ /* Dump the generated table. */
+ if (tt) {
+ char *table = NULL;
+
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+ ttable_del(tt);
+ tt = NULL;
+ }
if (!bsm_rpinfos_count(bsgrp->bsrp_list) && !uj)
vty_out(vty, "Active List is empty.\n");
@@ -5423,10 +5452,16 @@ static void pim_show_group_rp_mappings_info(struct pim_instance *pim,
vty_out(vty, "(PENDING)\n");
vty_out(vty, "Pending RP count :%d\n",
bsgrp->pend_rp_cnt);
- if (bsgrp->pend_rp_cnt)
- vty_out(vty, "%-15s %-15s %-15s %-15s\n",
- "Rp Address", "priority", "Holdtime",
- "Hash");
+ if (bsgrp->pend_rp_cnt) {
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(
+ tt,
+ "Rp Address|priority|Holdtime|Hash");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
+ }
}
frr_each (bsm_rpinfos, bsgrp->partial_bsrp_list, bsm_rp) {
@@ -5445,11 +5480,21 @@ static void pim_show_group_rp_mappings_info(struct pim_instance *pim,
"%pPA",
&bsm_rp->rp_address);
} else {
- vty_out(vty, "%-15pPA %-15u %-15u %-15u\n",
+ ttable_add_row(
+ tt, "%pPA|%u|%u|%u",
&bsm_rp->rp_address, bsm_rp->rp_prio,
bsm_rp->rp_holdtime, bsm_rp->hash);
}
}
+ /* Dump the generated table. */
+ if (tt) {
+ char *table = NULL;
+
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+ ttable_del(tt);
+ }
if (!bsm_rpinfos_count(bsgrp->partial_bsrp_list) && !uj)
vty_out(vty, "Partial List is empty\n");
@@ -5610,7 +5655,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);
diff --git a/staticd/static_nb_config.c b/staticd/static_nb_config.c
index 5a7044e9f9..4a3d9e17a4 100644
--- a/staticd/static_nb_config.c
+++ b/staticd/static_nb_config.c
@@ -370,7 +370,7 @@ static int static_nexthop_color_destroy(struct nb_cb_destroy_args *args)
struct static_nexthop *nh;
uint32_t old_color;
- nh = nb_running_unset_entry(args->dnode);
+ nh = nb_running_get_entry(args->dnode, NULL, true);
old_color = nh->color;
nh->color = 0;
diff --git a/staticd/static_vty.c b/staticd/static_vty.c
index 94a3493477..efae3c53da 100644
--- a/staticd/static_vty.c
+++ b/staticd/static_vty.c
@@ -41,15 +41,33 @@
#define STATICD_STR "Static route daemon\n"
-static int static_route_leak(struct vty *vty, const char *svrf,
- const char *nh_svrf, afi_t afi, safi_t safi,
- const char *negate, const char *dest_str,
- const char *mask_str, const char *src_str,
- const char *gate_str, const char *ifname,
- const char *flag_str, const char *tag_str,
- const char *distance_str, const char *label_str,
- const char *table_str, bool onlink,
- const char *color_str)
+/** All possible route parameters available in CLI. */
+struct static_route_args {
+ /** "no" command? */
+ bool delete;
+ /** Is VRF obtained from XPath? */
+ bool xpath_vrf;
+
+ bool onlink;
+ afi_t afi;
+ safi_t safi;
+
+ const char *vrf;
+ const char *nexthop_vrf;
+ const char *prefix;
+ const char *prefix_mask;
+ const char *source;
+ const char *gateway;
+ const char *interface_name;
+ const char *flag;
+ const char *tag;
+ const char *distance;
+ const char *label;
+ const char *table;
+ const char *color;
+};
+
+static int static_route_nb_run(struct vty *vty, struct static_route_args *args)
{
int ret;
struct prefix p, src;
@@ -62,8 +80,8 @@ static int static_route_leak(struct vty *vty, const char *svrf,
char xpath_label[XPATH_MAXLEN];
char ab_xpath[XPATH_MAXLEN];
char buf_prefix[PREFIX_STRLEN];
- char buf_src_prefix[PREFIX_STRLEN];
- char buf_nh_type[PREFIX_STRLEN];
+ char buf_src_prefix[PREFIX_STRLEN] = {};
+ char buf_nh_type[PREFIX_STRLEN] = {};
char buf_tag[PREFIX_STRLEN];
uint8_t label_stack_id = 0;
const char *buf_gate_str;
@@ -71,37 +89,46 @@ static int static_route_leak(struct vty *vty, const char *svrf,
route_tag_t tag = 0;
uint32_t table_id = 0;
const struct lyd_node *dnode;
+ const struct lyd_node *vrf_dnode;
- memset(buf_src_prefix, 0, PREFIX_STRLEN);
- memset(buf_nh_type, 0, PREFIX_STRLEN);
+ if (args->xpath_vrf) {
+ vrf_dnode = yang_dnode_get(vty->candidate_config->dnode,
+ VTY_CURR_XPATH);
+ if (vrf_dnode == NULL) {
+ vty_out(vty,
+ "%% Failed to get vrf dnode in candidate db\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ args->vrf = yang_dnode_get_string(vrf_dnode, "./name");
+ } else {
+ if (args->vrf == NULL)
+ args->vrf = VRF_DEFAULT_NAME;
+ }
+ if (args->nexthop_vrf == NULL)
+ args->nexthop_vrf = args->vrf;
- ret = str2prefix(dest_str, &p);
- if (ret <= 0) {
- vty_out(vty, "%% Malformed address\n");
- return CMD_WARNING_CONFIG_FAILED;
+ if (args->interface_name &&
+ !strcasecmp(args->interface_name, "Null0")) {
+ args->flag = "Null0";
+ args->interface_name = NULL;
}
- switch (afi) {
+ assert(!!str2prefix(args->prefix, &p));
+
+ switch (args->afi) {
case AFI_IP:
/* Cisco like mask notation. */
- if (mask_str) {
- ret = inet_aton(mask_str, &mask);
- if (ret == 0) {
- vty_out(vty, "%% Malformed address\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
+ if (args->prefix_mask) {
+ assert(inet_pton(AF_INET, args->prefix_mask, &mask) ==
+ 1);
p.prefixlen = ip_masklen(mask);
}
break;
case AFI_IP6:
/* srcdest routing */
- if (src_str) {
- ret = str2prefix(src_str, &src);
- if (ret <= 0 || src.family != AF_INET6) {
- vty_out(vty, "%% Malformed source address\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- }
+ if (args->source)
+ assert(!!str2prefix(args->source, &src));
break;
default:
break;
@@ -109,62 +136,64 @@ static int static_route_leak(struct vty *vty, const char *svrf,
/* Apply mask for given prefix. */
apply_mask(&p);
-
prefix2str(&p, buf_prefix, sizeof(buf_prefix));
- if (src_str)
+ if (args->source)
prefix2str(&src, buf_src_prefix, sizeof(buf_src_prefix));
- if (gate_str)
- buf_gate_str = gate_str;
+ if (args->gateway)
+ buf_gate_str = args->gateway;
else
buf_gate_str = "";
- if (gate_str == NULL && ifname == NULL)
+ if (args->gateway == NULL && args->interface_name == NULL)
type = STATIC_BLACKHOLE;
- else if (gate_str && ifname) {
- if (afi == AFI_IP)
+ else if (args->gateway && args->interface_name) {
+ if (args->afi == AFI_IP)
type = STATIC_IPV4_GATEWAY_IFNAME;
else
type = STATIC_IPV6_GATEWAY_IFNAME;
- } else if (ifname)
+ } else if (args->interface_name)
type = STATIC_IFNAME;
else {
- if (afi == AFI_IP)
+ if (args->afi == AFI_IP)
type = STATIC_IPV4_GATEWAY;
else
type = STATIC_IPV6_GATEWAY;
}
/* Administrative distance. */
- if (distance_str)
- distance = atoi(distance_str);
+ if (args->distance)
+ distance = strtol(args->distance, NULL, 10);
/* tag */
- if (tag_str)
- tag = strtoul(tag_str, NULL, 10);
+ if (args->tag)
+ tag = strtoul(args->tag, NULL, 10);
/* TableID */
- if (table_str)
- table_id = atol(table_str);
+ if (args->table)
+ table_id = strtol(args->table, NULL, 10);
- static_get_nh_type(type, buf_nh_type, PREFIX_STRLEN);
- if (!negate) {
- if (src_str)
+ static_get_nh_type(type, buf_nh_type, sizeof(buf_nh_type));
+ if (!args->delete) {
+ if (args->source)
snprintf(ab_xpath, sizeof(ab_xpath),
FRR_DEL_S_ROUTE_SRC_NH_KEY_NO_DISTANCE_XPATH,
- "frr-staticd:staticd", "staticd", svrf,
+ "frr-staticd:staticd", "staticd", args->vrf,
buf_prefix,
- yang_afi_safi_value2identity(afi, safi),
- buf_src_prefix, table_id, buf_nh_type, nh_svrf,
- buf_gate_str, ifname);
+ yang_afi_safi_value2identity(args->afi,
+ args->safi),
+ buf_src_prefix, table_id, buf_nh_type,
+ args->nexthop_vrf, buf_gate_str,
+ args->interface_name);
else
snprintf(ab_xpath, sizeof(ab_xpath),
FRR_DEL_S_ROUTE_NH_KEY_NO_DISTANCE_XPATH,
- "frr-staticd:staticd", "staticd", svrf,
+ "frr-staticd:staticd", "staticd", args->vrf,
buf_prefix,
- yang_afi_safi_value2identity(afi, safi),
- table_id, buf_nh_type, nh_svrf, buf_gate_str,
- ifname);
+ yang_afi_safi_value2identity(args->afi,
+ args->safi),
+ table_id, buf_nh_type, args->nexthop_vrf,
+ buf_gate_str, args->interface_name);
/*
* If there's already the same nexthop but with a different
@@ -181,19 +210,21 @@ static int static_route_leak(struct vty *vty, const char *svrf,
}
/* route + path procesing */
- if (src_str)
+ if (args->source)
snprintf(xpath_prefix, sizeof(xpath_prefix),
FRR_S_ROUTE_SRC_INFO_KEY_XPATH,
- "frr-staticd:staticd", "staticd", svrf,
+ "frr-staticd:staticd", "staticd", args->vrf,
buf_prefix,
- yang_afi_safi_value2identity(afi, safi),
+ yang_afi_safi_value2identity(args->afi,
+ args->safi),
buf_src_prefix, table_id, distance);
else
snprintf(xpath_prefix, sizeof(xpath_prefix),
FRR_STATIC_ROUTE_INFO_KEY_XPATH,
- "frr-staticd:staticd", "staticd", svrf,
+ "frr-staticd:staticd", "staticd", args->vrf,
buf_prefix,
- yang_afi_safi_value2identity(afi, safi),
+ yang_afi_safi_value2identity(args->afi,
+ args->safi),
table_id, distance);
nb_cli_enqueue_change(vty, xpath_prefix, NB_OP_CREATE, NULL);
@@ -208,8 +239,8 @@ static int static_route_leak(struct vty *vty, const char *svrf,
/* nexthop processing */
snprintf(ab_xpath, sizeof(ab_xpath),
- FRR_STATIC_ROUTE_NH_KEY_XPATH, buf_nh_type, nh_svrf,
- buf_gate_str, ifname);
+ FRR_STATIC_ROUTE_NH_KEY_XPATH, buf_nh_type,
+ args->nexthop_vrf, buf_gate_str, args->interface_name);
strlcpy(xpath_nexthop, xpath_prefix, sizeof(xpath_nexthop));
strlcat(xpath_nexthop, ab_xpath, sizeof(xpath_nexthop));
nb_cli_enqueue_change(vty, xpath_nexthop, NB_OP_CREATE, NULL);
@@ -220,8 +251,8 @@ static int static_route_leak(struct vty *vty, const char *svrf,
sizeof(ab_xpath));
/* Route flags */
- if (flag_str) {
- switch (flag_str[0]) {
+ if (args->flag) {
+ switch (args->flag[0]) {
case 'r':
bh_type = "reject";
break;
@@ -248,7 +279,7 @@ static int static_route_leak(struct vty *vty, const char *svrf,
strlcat(ab_xpath, FRR_STATIC_ROUTE_NH_ONLINK_XPATH,
sizeof(ab_xpath));
- if (onlink)
+ if (args->onlink)
nb_cli_enqueue_change(vty, ab_xpath,
NB_OP_MODIFY, "true");
else
@@ -262,11 +293,12 @@ static int static_route_leak(struct vty *vty, const char *svrf,
strlcpy(ab_xpath, xpath_nexthop, sizeof(ab_xpath));
strlcat(ab_xpath, FRR_STATIC_ROUTE_NH_COLOR_XPATH,
sizeof(ab_xpath));
- if (color_str)
+ if (args->color)
nb_cli_enqueue_change(vty, ab_xpath,
- NB_OP_MODIFY, color_str);
+ NB_OP_MODIFY,
+ args->color);
}
- if (label_str) {
+ if (args->label) {
/* copy of label string (start) */
char *ostr;
/* pointer to next segment */
@@ -279,7 +311,7 @@ static int static_route_leak(struct vty *vty, const char *svrf,
nb_cli_enqueue_change(vty, xpath_mpls, NB_OP_DESTROY,
NULL);
- ostr = XSTRDUP(MTYPE_TMP, label_str);
+ ostr = XSTRDUP(MTYPE_TMP, args->label);
while ((nump = strsep(&ostr, "/")) != NULL) {
snprintf(ab_xpath, sizeof(ab_xpath),
FRR_STATIC_ROUTE_NHLB_KEY_XPATH,
@@ -302,22 +334,25 @@ static int static_route_leak(struct vty *vty, const char *svrf,
}
ret = nb_cli_apply_changes(vty, xpath_prefix);
} else {
- if (src_str)
+ if (args->source)
snprintf(ab_xpath, sizeof(ab_xpath),
FRR_DEL_S_ROUTE_SRC_NH_KEY_NO_DISTANCE_XPATH,
- "frr-staticd:staticd", "staticd", svrf,
+ "frr-staticd:staticd", "staticd", args->vrf,
buf_prefix,
- yang_afi_safi_value2identity(afi, safi),
- buf_src_prefix, table_id, buf_nh_type, nh_svrf,
- buf_gate_str, ifname);
+ yang_afi_safi_value2identity(args->afi,
+ args->safi),
+ buf_src_prefix, table_id, buf_nh_type,
+ args->nexthop_vrf, buf_gate_str,
+ args->interface_name);
else
snprintf(ab_xpath, sizeof(ab_xpath),
FRR_DEL_S_ROUTE_NH_KEY_NO_DISTANCE_XPATH,
- "frr-staticd:staticd", "staticd", svrf,
+ "frr-staticd:staticd", "staticd", args->vrf,
buf_prefix,
- yang_afi_safi_value2identity(afi, safi),
- table_id, buf_nh_type, nh_svrf, buf_gate_str,
- ifname);
+ yang_afi_safi_value2identity(args->afi,
+ args->safi),
+ table_id, buf_nh_type, args->nexthop_vrf,
+ buf_gate_str, args->interface_name);
dnode = yang_dnode_get(vty->candidate_config->dnode, ab_xpath);
if (!dnode) {
@@ -336,22 +371,6 @@ static int static_route_leak(struct vty *vty, const char *svrf,
return ret;
}
-static int static_route(struct vty *vty, afi_t afi, safi_t safi,
- const char *negate, const char *dest_str,
- const char *mask_str, const char *src_str,
- const char *gate_str, const char *ifname,
- const char *flag_str, const char *tag_str,
- const char *distance_str, const char *vrf_name,
- const char *label_str, const char *table_str)
-{
- if (!vrf_name)
- vrf_name = VRF_DEFAULT_NAME;
-
- return static_route_leak(vty, vrf_name, vrf_name, afi, safi, negate,
- dest_str, mask_str, src_str, gate_str, ifname,
- flag_str, tag_str, distance_str, label_str,
- table_str, false, NULL);
-}
/* Static unicast routes for multicast RPF lookup. */
DEFPY_YANG (ip_mroute_dist,
@@ -365,9 +384,17 @@ DEFPY_YANG (ip_mroute_dist,
"Nexthop interface name\n"
"Distance\n")
{
- return static_route(vty, AFI_IP, SAFI_MULTICAST, no, prefix_str,
- NULL, NULL, gate_str, ifname, NULL, NULL,
- distance_str, NULL, NULL, NULL);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP,
+ .safi = SAFI_MULTICAST,
+ .prefix = prefix_str,
+ .gateway = gate_str,
+ .interface_name = ifname,
+ .distance = distance_str,
+ };
+
+ return static_route_nb_run(vty, &args);
}
/* Static route configuration. */
@@ -398,9 +425,21 @@ DEFPY_YANG(ip_route_blackhole,
"Table to configure\n"
"The table number to configure\n")
{
- return static_route(vty, AFI_IP, SAFI_UNICAST, no, prefix,
- mask_str, NULL, NULL, NULL, flag, tag_str,
- distance_str, vrf, label, table_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix,
+ .prefix_mask = mask_str,
+ .flag = flag,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .vrf = vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ip_route_blackhole_vrf,
@@ -428,26 +467,28 @@ DEFPY_YANG(ip_route_blackhole_vrf,
"Table to configure\n"
"The table number to configure\n")
{
- const struct lyd_node *vrf_dnode;
- const char *vrfname;
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix,
+ .prefix_mask = mask_str,
+ .flag = flag,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .xpath_vrf = true,
+ };
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
/*
* Coverity is complaining that prefix could
* be dereferenced, but we know that prefix will
* valid. Add an assert to make it happy
*/
- assert(prefix);
- return static_route_leak(vty, vrfname, vrfname, AFI_IP, SAFI_UNICAST,
- no, prefix, mask_str, NULL, NULL, NULL, flag,
- tag_str, distance_str, label, table_str,
- false, NULL);
+ assert(args.prefix);
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ip_route_address_interface,
@@ -486,25 +527,25 @@ DEFPY_YANG(ip_route_address_interface,
"SR-TE color\n"
"The SR-TE color to configure\n")
{
- const char *nh_vrf;
- const char *flag = NULL;
-
- if (ifname && !strncasecmp(ifname, "Null0", 5)) {
- flag = "Null0";
- ifname = NULL;
- }
- if (!vrf)
- vrf = VRF_DEFAULT_NAME;
-
- if (nexthop_vrf)
- nh_vrf = nexthop_vrf;
- else
- nh_vrf = vrf;
-
- return static_route_leak(vty, vrf, nh_vrf, AFI_IP, SAFI_UNICAST, no,
- prefix, mask_str, NULL, gate_str, ifname, flag,
- tag_str, distance_str, label, table_str,
- !!onlink, color_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix,
+ .prefix_mask = mask_str,
+ .gateway = gate_str,
+ .interface_name = ifname,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .color = color_str,
+ .onlink = !!onlink,
+ .vrf = vrf,
+ .nexthop_vrf = nexthop_vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ip_route_address_interface_vrf,
@@ -541,32 +582,25 @@ DEFPY_YANG(ip_route_address_interface_vrf,
"SR-TE color\n"
"The SR-TE color to configure\n")
{
- const char *nh_vrf;
- const char *flag = NULL;
- const struct lyd_node *vrf_dnode;
- const char *vrfname;
-
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
-
- if (ifname && !strncasecmp(ifname, "Null0", 5)) {
- flag = "Null0";
- ifname = NULL;
- }
- if (nexthop_vrf)
- nh_vrf = nexthop_vrf;
- else
- nh_vrf = vrfname;
-
- return static_route_leak(vty, vrfname, nh_vrf, AFI_IP, SAFI_UNICAST, no,
- prefix, mask_str, NULL, gate_str, ifname, flag,
- tag_str, distance_str, label, table_str,
- !!onlink, color_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix,
+ .prefix_mask = mask_str,
+ .gateway = gate_str,
+ .interface_name = ifname,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .color = color_str,
+ .onlink = !!onlink,
+ .xpath_vrf = true,
+ .nexthop_vrf = nexthop_vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ip_route,
@@ -602,26 +636,24 @@ DEFPY_YANG(ip_route,
"SR-TE color\n"
"The SR-TE color to configure\n")
{
- const char *nh_vrf;
- const char *flag = NULL;
-
- if (ifname && !strncasecmp(ifname, "Null0", 5)) {
- flag = "Null0";
- ifname = NULL;
- }
-
- if (!vrf)
- vrf = VRF_DEFAULT_NAME;
-
- if (nexthop_vrf)
- nh_vrf = nexthop_vrf;
- else
- nh_vrf = vrf;
-
- return static_route_leak(vty, vrf, nh_vrf, AFI_IP, SAFI_UNICAST, no,
- prefix, mask_str, NULL, gate_str, ifname, flag,
- tag_str, distance_str, label, table_str,
- false, color_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix,
+ .prefix_mask = mask_str,
+ .gateway = gate_str,
+ .interface_name = ifname,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .color = color_str,
+ .vrf = vrf,
+ .nexthop_vrf = nexthop_vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ip_route_vrf,
@@ -655,33 +687,24 @@ DEFPY_YANG(ip_route_vrf,
"SR-TE color\n"
"The SR-TE color to configure\n")
{
- const char *nh_vrf;
- const char *flag = NULL;
- const struct lyd_node *vrf_dnode;
- const char *vrfname;
-
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
-
- if (ifname && !strncasecmp(ifname, "Null0", 5)) {
- flag = "Null0";
- ifname = NULL;
- }
- if (nexthop_vrf)
- nh_vrf = nexthop_vrf;
- else
- nh_vrf = vrfname;
-
- return static_route_leak(vty, vrfname, nh_vrf, AFI_IP, SAFI_UNICAST, no,
- prefix, mask_str, NULL, gate_str, ifname, flag,
- tag_str, distance_str, label, table_str,
- false, color_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix,
+ .prefix_mask = mask_str,
+ .gateway = gate_str,
+ .interface_name = ifname,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .color = color_str,
+ .xpath_vrf = true,
+ .nexthop_vrf = nexthop_vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ipv6_route_blackhole,
@@ -711,9 +734,21 @@ DEFPY_YANG(ipv6_route_blackhole,
"Table to configure\n"
"The table number to configure\n")
{
- return static_route(vty, AFI_IP6, SAFI_UNICAST, no, prefix_str,
- NULL, from_str, NULL, NULL, flag, tag_str,
- distance_str, vrf, label, table_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP6,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix_str,
+ .source = from_str,
+ .flag = flag,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .vrf = vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ipv6_route_blackhole_vrf,
@@ -741,28 +776,28 @@ DEFPY_YANG(ipv6_route_blackhole_vrf,
"Table to configure\n"
"The table number to configure\n")
{
- const struct lyd_node *vrf_dnode;
- const char *vrfname;
-
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP6,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix_str,
+ .source = from_str,
+ .flag = flag,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .xpath_vrf = true,
+ };
/*
* Coverity is complaining that prefix could
* be dereferenced, but we know that prefix will
* valid. Add an assert to make it happy
*/
- assert(prefix);
+ assert(args.prefix);
- return static_route_leak(vty, vrfname, vrfname, AFI_IP6, SAFI_UNICAST,
- no, prefix_str, NULL, from_str, NULL, NULL,
- flag, tag_str, distance_str, label, table_str,
- false, NULL);
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ipv6_route_address_interface,
@@ -801,26 +836,25 @@ DEFPY_YANG(ipv6_route_address_interface,
"SR-TE color\n"
"The SR-TE color to configure\n")
{
- const char *nh_vrf;
- const char *flag = NULL;
-
- if (ifname && !strncasecmp(ifname, "Null0", 5)) {
- flag = "Null0";
- ifname = NULL;
- }
-
- if (!vrf)
- vrf = VRF_DEFAULT_NAME;
-
- if (nexthop_vrf)
- nh_vrf = nexthop_vrf;
- else
- nh_vrf = vrf;
-
- return static_route_leak(vty, vrf, nh_vrf, AFI_IP6, SAFI_UNICAST, no,
- prefix_str, NULL, from_str, gate_str, ifname,
- flag, tag_str, distance_str, label, table_str,
- !!onlink, color_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP6,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix_str,
+ .source = from_str,
+ .gateway = gate_str,
+ .interface_name = ifname,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .color = color_str,
+ .onlink = !!onlink,
+ .vrf = vrf,
+ .nexthop_vrf = nexthop_vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ipv6_route_address_interface_vrf,
@@ -857,32 +891,25 @@ DEFPY_YANG(ipv6_route_address_interface_vrf,
"SR-TE color\n"
"The SR-TE color to configure\n")
{
- const char *nh_vrf;
- const char *flag = NULL;
- const struct lyd_node *vrf_dnode;
- const char *vrfname;
-
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
-
- if (nexthop_vrf)
- nh_vrf = nexthop_vrf;
- else
- nh_vrf = vrfname;
-
- if (ifname && !strncasecmp(ifname, "Null0", 5)) {
- flag = "Null0";
- ifname = NULL;
- }
- return static_route_leak(vty, vrfname, nh_vrf, AFI_IP6, SAFI_UNICAST,
- no, prefix_str, NULL, from_str, gate_str,
- ifname, flag, tag_str, distance_str, label,
- table_str, !!onlink, color_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP6,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix_str,
+ .source = from_str,
+ .gateway = gate_str,
+ .interface_name = ifname,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .color = color_str,
+ .onlink = !!onlink,
+ .xpath_vrf = true,
+ .nexthop_vrf = nexthop_vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ipv6_route,
@@ -918,25 +945,24 @@ DEFPY_YANG(ipv6_route,
"SR-TE color\n"
"The SR-TE color to configure\n")
{
- const char *nh_vrf;
- const char *flag = NULL;
-
- if (!vrf)
- vrf = VRF_DEFAULT_NAME;
-
- if (nexthop_vrf)
- nh_vrf = nexthop_vrf;
- else
- nh_vrf = vrf;
-
- if (ifname && !strncasecmp(ifname, "Null0", 5)) {
- flag = "Null0";
- ifname = NULL;
- }
- return static_route_leak(vty, vrf, nh_vrf, AFI_IP6, SAFI_UNICAST, no,
- prefix_str, NULL, from_str, gate_str, ifname,
- flag, tag_str, distance_str, label, table_str,
- false, color_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP6,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix_str,
+ .source = from_str,
+ .gateway = gate_str,
+ .interface_name = ifname,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .color = color_str,
+ .vrf = vrf,
+ .nexthop_vrf = nexthop_vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ipv6_route_vrf,
@@ -970,32 +996,24 @@ DEFPY_YANG(ipv6_route_vrf,
"SR-TE color\n"
"The SR-TE color to configure\n")
{
- const char *nh_vrf;
- const char *flag = NULL;
- const struct lyd_node *vrf_dnode;
- const char *vrfname;
-
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
-
- if (nexthop_vrf)
- nh_vrf = nexthop_vrf;
- else
- nh_vrf = vrfname;
-
- if (ifname && !strncasecmp(ifname, "Null0", 5)) {
- flag = "Null0";
- ifname = NULL;
- }
- return static_route_leak(vty, vrfname, nh_vrf, AFI_IP6, SAFI_UNICAST,
- no, prefix_str, NULL, from_str, gate_str,
- ifname, flag, tag_str, distance_str, label,
- table_str, false, color_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP6,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix_str,
+ .source = from_str,
+ .gateway = gate_str,
+ .interface_name = ifname,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .color = color_str,
+ .xpath_vrf = true,
+ .nexthop_vrf = nexthop_vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
void static_cli_show(struct vty *vty, const struct lyd_node *dnode,
diff --git a/tests/topotests/bgp_comm_list_delete/test_bgp_comm-list_delete.py b/tests/topotests/bgp_comm_list_delete/test_bgp_comm-list_delete.py
index 4db4e37f7f..a2904e6e1e 100644
--- a/tests/topotests/bgp_comm_list_delete/test_bgp_comm-list_delete.py
+++ b/tests/topotests/bgp_comm_list_delete/test_bgp_comm-list_delete.py
@@ -34,11 +34,13 @@ 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]
@@ -81,30 +83,34 @@ def test_bgp_maximum_prefix_invalid():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- def _bgp_converge(router):
- while True:
- output = json.loads(
- tgen.gears[router].vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")
- )
- if output["192.168.255.1"]["bgpState"] == "Established":
- if (
- output["192.168.255.1"]["addressFamilyInfo"]["ipv4Unicast"][
- "acceptedPrefixCounter"
- ]
- == 2
- ):
- return True
-
- def _bgp_comm_list_delete(router):
- output = json.loads(
- tgen.gears[router].vtysh_cmd("show ip bgp 172.16.255.254/32 json")
- )
- if "333:333" in output["paths"][0]["community"]["list"]:
- return False
- return True
-
- if _bgp_converge("r2"):
- assert _bgp_comm_list_delete("r2") == True
+ r2 = tgen.gears["r2"]
+
+ def _bgp_converge():
+ output = json.loads(r2.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json"))
+ expected = {
+ "192.168.255.1": {
+ "bgpState": "Established",
+ "addressFamilyInfo": {
+ "ipv4Unicast": {
+ "acceptedPrefixCounter": 2,
+ }
+ },
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_converge)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Can't converge initially"
+
+ def _bgp_comm_list_delete():
+ output = json.loads(r2.vtysh_cmd("show ip bgp 172.16.255.254/32 json"))
+ expected = {"paths": [{"community": {"list": ["333:333"]}}]}
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_comm_list_delete)
+ _, result = topotest.run_and_expect(test_func, not None, count=60, wait=0.5)
+ assert result is not None, "333:333 community SHOULD be stripped from r1"
if __name__ == "__main__":
diff --git a/tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py b/tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py
index bb2c43d1fc..2b4c4e816b 100644
--- a/tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py
+++ b/tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py
@@ -31,13 +31,14 @@ used together with `remove-private-AS`.
import os
import sys
import json
-import time
import pytest
+import functools
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
# pylint: disable=C0413
+from lib import topotest
from lib.topogen import Topogen, TopoRouter, get_topogen
pytestmark = [pytest.mark.bgpd]
@@ -84,29 +85,43 @@ def test_bgp_remove_private_as():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- def _bgp_converge(router):
- while True:
- output = json.loads(
- tgen.gears[router].vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")
- )
- if output["192.168.255.1"]["bgpState"] == "Established":
- time.sleep(1)
- return True
-
- def _bgp_as_path(router):
- output = json.loads(
- tgen.gears[router].vtysh_cmd("show ip bgp 172.16.255.254/32 json")
- )
- if output["prefix"] == "172.16.255.254/32":
- return output["paths"][0]["aspath"]["segments"][0]["list"]
-
- if _bgp_converge("r2"):
- assert len(_bgp_as_path("r2")) == 1
- assert 65000 not in _bgp_as_path("r2")
-
- if _bgp_converge("r4"):
- assert len(_bgp_as_path("r4")) == 2
- assert 3000 in _bgp_as_path("r4")
+ r2 = tgen.gears["r2"]
+ r4 = tgen.gears["r4"]
+
+ def _bgp_converge():
+ output = json.loads(r2.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json"))
+ expected = {
+ "192.168.255.1": {
+ "bgpState": "Established",
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_converge)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Can't converge initially"
+
+ def _bgp_as_path(router, asn_path, asn_length):
+ output = json.loads(router.vtysh_cmd("show ip bgp 172.16.255.254/32 json"))
+ expected = {
+ "paths": [
+ {
+ "aspath": {
+ "string": asn_path,
+ "length": asn_length,
+ }
+ }
+ ]
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_as_path, r2, "500", 1)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Private ASNs not stripped"
+
+ test_func = functools.partial(_bgp_as_path, r4, "500 3000", 2)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Private ASNs not stripped"
if __name__ == "__main__":
diff --git a/tests/topotests/bgp_maximum_prefix_invalid_update/r1/bgpd.conf b/tests/topotests/bgp_maximum_prefix_invalid_update/r1/bgpd.conf
index 62110429cf..271a5bb1b1 100644
--- a/tests/topotests/bgp_maximum_prefix_invalid_update/r1/bgpd.conf
+++ b/tests/topotests/bgp_maximum_prefix_invalid_update/r1/bgpd.conf
@@ -1,6 +1,13 @@
router bgp 65000
- 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
+ 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
+ neighbor 192.168.255.2 prefix-list r2 out
+ exit-address-family
+ !
+!
+ip prefix-list r2 seq 5 permit 172.16.255.253/32
+ip prefix-list r2 seq 10 permit 172.16.255.254/32
+!
diff --git a/tests/topotests/bgp_maximum_prefix_invalid_update/r1/zebra.conf b/tests/topotests/bgp_maximum_prefix_invalid_update/r1/zebra.conf
index 0a283c06d5..68c5021636 100644
--- a/tests/topotests/bgp_maximum_prefix_invalid_update/r1/zebra.conf
+++ b/tests/topotests/bgp_maximum_prefix_invalid_update/r1/zebra.conf
@@ -1,6 +1,7 @@
!
interface lo
ip address 172.16.255.254/32
+ ip address 172.16.255.253/32
!
interface r1-eth0
ip address 192.168.255.1/24
diff --git a/tests/topotests/bgp_maximum_prefix_invalid_update/r2/bgpd.conf b/tests/topotests/bgp_maximum_prefix_invalid_update/r2/bgpd.conf
index 005425e850..cb30808f41 100644
--- a/tests/topotests/bgp_maximum_prefix_invalid_update/r2/bgpd.conf
+++ b/tests/topotests/bgp_maximum_prefix_invalid_update/r2/bgpd.conf
@@ -1,6 +1,9 @@
router bgp 65001
- no bgp ebgp-requires-policy
- neighbor 192.168.255.1 remote-as 65000
- neighbor 192.168.255.1 timers 3 10
- address-family ipv4
- neighbor 192.168.255.1 maximum-prefix 1
+ no bgp ebgp-requires-policy
+ neighbor 192.168.255.1 remote-as 65000
+ neighbor 192.168.255.1 timers 3 10
+ address-family ipv4
+ neighbor 192.168.255.1 maximum-prefix 1
+ exit-address-family
+ !
+!
diff --git a/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py b/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py
index 5c34ebf919..ee68ecd7b6 100644
--- a/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py
+++ b/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py
@@ -36,11 +36,13 @@ 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]
@@ -83,29 +85,21 @@ def test_bgp_maximum_prefix_invalid():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- def _bgp_converge(router):
- while True:
- output = json.loads(
- tgen.gears[router].vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")
- )
- if output["192.168.255.1"]["connectionsEstablished"] > 0:
- return True
-
- def _bgp_parsing_nlri(router):
- cmd_max_exceeded = (
- 'grep "%MAXPFXEXCEED: No. of IPv4 Unicast prefix received" bgpd.log'
- )
- cmdt_error_parsing_nlri = 'grep "Error parsing NLRI" bgpd.log'
- output_max_exceeded = tgen.gears[router].run(cmd_max_exceeded)
- output_error_parsing_nlri = tgen.gears[router].run(cmdt_error_parsing_nlri)
-
- if len(output_max_exceeded) > 0:
- if len(output_error_parsing_nlri) > 0:
- return False
- return True
-
- if _bgp_converge("r2"):
- assert _bgp_parsing_nlri("r2") == True
+ r2 = tgen.gears["r2"]
+
+ def _bgp_parsing_nlri():
+ output = json.loads(r2.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json"))
+ expected = {
+ "192.168.255.1": {
+ "lastNotificationReason": "Cease/Maximum Number of Prefixes Reached",
+ "lastResetDueTo": "BGP Notification send",
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_parsing_nlri)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+ assert result is None, "Didn't send NOTIFICATION when hitting maximum-prefix"
if __name__ == "__main__":
diff --git a/tests/topotests/bgp_peer_graceful_shutdown/__init__.py b/tests/topotests/bgp_peer_graceful_shutdown/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_peer_graceful_shutdown/__init__.py
diff --git a/tests/topotests/bgp_peer_graceful_shutdown/r1/bgpd.conf b/tests/topotests/bgp_peer_graceful_shutdown/r1/bgpd.conf
new file mode 100644
index 0000000000..8e5909839a
--- /dev/null
+++ b/tests/topotests/bgp_peer_graceful_shutdown/r1/bgpd.conf
@@ -0,0 +1,8 @@
+!
+router bgp 65001
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.2 remote-as external
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_peer_graceful_shutdown/r1/zebra.conf b/tests/topotests/bgp_peer_graceful_shutdown/r1/zebra.conf
new file mode 100644
index 0000000000..376a19a808
--- /dev/null
+++ b/tests/topotests/bgp_peer_graceful_shutdown/r1/zebra.conf
@@ -0,0 +1,7 @@
+!
+int lo
+ ip address 10.10.10.1/32
+!
+int r1-eth0
+ ip address 192.168.1.1/24
+!
diff --git a/tests/topotests/bgp_peer_graceful_shutdown/r2/bgpd.conf b/tests/topotests/bgp_peer_graceful_shutdown/r2/bgpd.conf
new file mode 100644
index 0000000000..0ee1821003
--- /dev/null
+++ b/tests/topotests/bgp_peer_graceful_shutdown/r2/bgpd.conf
@@ -0,0 +1,8 @@
+router bgp 65002
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.1 remote-as external
+ neighbor 192.168.2.2 remote-as internal
+ address-family ipv4 unicast
+ neighbor 192.168.2.2 next-hop-self
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_peer_graceful_shutdown/r2/zebra.conf b/tests/topotests/bgp_peer_graceful_shutdown/r2/zebra.conf
new file mode 100644
index 0000000000..67ca02f10a
--- /dev/null
+++ b/tests/topotests/bgp_peer_graceful_shutdown/r2/zebra.conf
@@ -0,0 +1,7 @@
+!
+int r2-eth0
+ ip address 192.168.1.2/24
+!
+int r2-eth1
+ ip address 192.168.2.1/24
+!
diff --git a/tests/topotests/bgp_peer_graceful_shutdown/r3/bgpd.conf b/tests/topotests/bgp_peer_graceful_shutdown/r3/bgpd.conf
new file mode 100644
index 0000000000..5945a024b9
--- /dev/null
+++ b/tests/topotests/bgp_peer_graceful_shutdown/r3/bgpd.conf
@@ -0,0 +1,5 @@
+!
+router bgp 65002
+ no bgp ebgp-requires-policy
+ neighbor 192.168.2.1 remote-as internal
+!
diff --git a/tests/topotests/bgp_peer_graceful_shutdown/r3/zebra.conf b/tests/topotests/bgp_peer_graceful_shutdown/r3/zebra.conf
new file mode 100644
index 0000000000..e5a37c98ca
--- /dev/null
+++ b/tests/topotests/bgp_peer_graceful_shutdown/r3/zebra.conf
@@ -0,0 +1,4 @@
+!
+int r3-eth0
+ ip address 192.168.2.2/24
+!
diff --git a/tests/topotests/bgp_peer_graceful_shutdown/test_bgp_peer_graceful_shutdown.py b/tests/topotests/bgp_peer_graceful_shutdown/test_bgp_peer_graceful_shutdown.py
new file mode 100644
index 0000000000..de62889a0e
--- /dev/null
+++ b/tests/topotests/bgp_peer_graceful_shutdown/test_bgp_peer_graceful_shutdown.py
@@ -0,0 +1,120 @@
+#!/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.
+#
+
+"""
+Check if routes from R1 has local-preference set to 0 and graceful-shutdown
+community.
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+pytestmark = pytest.mark.bgpd
+
+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 setup_module(mod):
+ topodef = {"s1": ("r1", "r2"), "s2": ("r2", "r3")}
+ tgen = Topogen(topodef, 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_orf():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r2 = tgen.gears["r2"]
+ r3 = tgen.gears["r3"]
+
+ def _bgp_converge():
+ output = json.loads(
+ r2.vtysh_cmd(
+ "show bgp ipv4 unicast neighbor 192.168.2.2 advertised-routes json"
+ )
+ )
+ expected = {"advertisedRoutes": {"10.10.10.1/32": {"locPrf": 100}}}
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_converge)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Can't converge at R2"
+
+ step("Mark routes from R1 as graceful-shutdown")
+ r2.vtysh_cmd(
+ """
+ configure terminal
+ router bgp
+ neighbor 192.168.1.1 graceful-shutdown
+ """
+ )
+
+ def _bgp_check_peer_graceful_shutdown():
+ output = json.loads(r3.vtysh_cmd("show bgp ipv4 unicast 10.10.10.1/32 json"))
+ expected = {
+ "paths": [
+ {
+ "locPrf": 0,
+ "community": {"string": "graceful-shutdown"},
+ }
+ ]
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_check_peer_graceful_shutdown)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert (
+ result is None
+ ), "local-preference is not 0 and/or graceful-shutdown community missing"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/bgpd.conf
index c06175193e..30a0f8fe78 100644
--- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/bgpd.conf
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/bgpd.conf
@@ -1,5 +1,7 @@
frr defaults traditional
!
+bgp send-extra-data zebra
+!
hostname r1
password zebra
!
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/bgpd.conf
index 05170572a4..7ca23002ac 100644
--- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/bgpd.conf
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/bgpd.conf
@@ -1,5 +1,7 @@
frr defaults traditional
!
+bgp send-extra-data zebra
+!
hostname r2
password zebra
!
diff --git a/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py b/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py
index 61caf257eb..012814919d 100755
--- a/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py
+++ b/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py
@@ -1054,7 +1054,7 @@ def test_rib_ipv6_step24():
rname,
"show ipv6 route isis json",
outputs[rname][15]["show_ipv6_route.ref"],
- count=5,
+ count=10,
)
diff --git a/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py b/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py
index fa76072b4a..213439d3f5 100755
--- a/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py
+++ b/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py
@@ -831,19 +831,19 @@ def test_rt6_step11():
rname,
"show ip route isis json",
outputs[rname][11]["show_ip_route.ref"],
- count=5,
+ count=10,
)
router_compare_json_output(
rname,
"show ipv6 route isis json",
outputs[rname][11]["show_ipv6_route.ref"],
- count=5,
+ count=10,
)
router_compare_json_output(
rname,
"show mpls table json",
outputs[rname][11]["show_mpls_table.ref"],
- count=5,
+ count=10,
)
@@ -1028,19 +1028,19 @@ def test_rt6_step14():
rname,
"show ip route isis json",
outputs[rname][11]["show_ip_route.ref"],
- count=5,
+ count=10,
)
router_compare_json_output(
rname,
"show ipv6 route isis json",
outputs[rname][11]["show_ipv6_route.ref"],
- count=5,
+ count=10,
)
router_compare_json_output(
rname,
"show mpls table json",
outputs[rname][11]["show_mpls_table.ref"],
- count=5,
+ count=10,
)
diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py
index 5a3f586f82..61cf16944f 100644
--- a/tests/topotests/lib/topotest.py
+++ b/tests/topotests/lib/topotest.py
@@ -355,6 +355,16 @@ def run_and_expect(func, what, count=20, wait=3):
else:
func_name = func.__name__
+ # Just a safety-check to avoid running topotests with very
+ # small wait/count arguments.
+ wait_time = wait * count
+ if wait_time < 5:
+ assert (
+ wait_time >= 5
+ ), "Waiting time is too small (count={}, wait={}), adjust timer values".format(
+ count, wait
+ )
+
logger.info(
"'{}' polling started (interval {} secs, maximum {} tries)".format(
func_name, wait, count
@@ -402,6 +412,16 @@ def run_and_expect_type(func, etype, count=20, wait=3, avalue=None):
else:
func_name = func.__name__
+ # Just a safety-check to avoid running topotests with very
+ # small wait/count arguments.
+ wait_time = wait * count
+ if wait_time < 5:
+ assert (
+ wait_time >= 5
+ ), "Waiting time is too small (count={}, wait={}), adjust timer values".format(
+ count, wait
+ )
+
logger.info(
"'{}' polling started (interval {} secs, maximum wait {} secs)".format(
func_name, wait, int(wait * count)
diff --git a/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py b/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py
index e59333ebd2..1876dabed7 100755
--- a/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py
+++ b/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py
@@ -224,7 +224,7 @@ def check_routers(initial_convergence=False, exiting=None, restarting=None):
if restarting != None:
tries = 40
else:
- tries = 1
+ tries = 10
router_compare_json_output(
rname, "show ipv6 route ospf json", "show_ipv6_route.json", tries
)
@@ -246,7 +246,7 @@ def check_routers(initial_convergence=False, exiting=None, restarting=None):
if initial_convergence == True or restarting == rname:
tries = 240
else:
- tries = 1
+ tries = 10
router_compare_json_output(
rname,
"show ipv6 ospf database json",
diff --git a/tests/topotests/ospf6_topo2/test_ospf6_topo2.py b/tests/topotests/ospf6_topo2/test_ospf6_topo2.py
index d17aeda3ea..f16e8f396e 100644
--- a/tests/topotests/ospf6_topo2/test_ospf6_topo2.py
+++ b/tests/topotests/ospf6_topo2/test_ospf6_topo2.py
@@ -243,7 +243,7 @@ def test_ospf6_default_route():
"show ipv6 route json",
{route: [{"metric": metric}]},
)
- _, result = topotest.run_and_expect(test_func, None, count=4, wait=1)
+ _, result = topotest.run_and_expect(test_func, None, count=5, wait=1)
assertmsg = '"{}" convergence failure'.format(router)
assert result is None, assertmsg
diff --git a/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py b/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py
index debf7ad766..429b7dc96d 100755
--- a/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py
+++ b/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py
@@ -233,7 +233,7 @@ def check_routers(initial_convergence=False, exiting=None, restarting=None):
if restarting != None:
tries = 60
else:
- tries = 1
+ tries = 10
router_compare_json_output(
rname, "show ip route ospf json", "show_ip_route.json", tries
)
@@ -252,7 +252,7 @@ def check_routers(initial_convergence=False, exiting=None, restarting=None):
if initial_convergence == True or restarting == rname:
tries = 240
else:
- tries = 1
+ tries = 10
router_compare_json_output(
rname, "show ip ospf database json", "show_ip_ospf_database.json", tries
)
diff --git a/tests/topotests/pim_basic/test_pim.py b/tests/topotests/pim_basic/test_pim.py
index 6cea521aa9..2c1bc52d09 100644
--- a/tests/topotests/pim_basic/test_pim.py
+++ b/tests/topotests/pim_basic/test_pim.py
@@ -225,7 +225,7 @@ def test_pim_igmp_report():
test_func = partial(
topotest.router_json_cmp, r1, "show ip pim upstream json", expected
)
- _, result = topotest.run_and_expect(test_func, None, count=5, wait=0.5)
+ _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
assertmsg = '"{}" JSON output mismatches'.format(r1.name)
assert result is None, assertmsg
finally:
diff --git a/tests/topotests/pim_basic_topo2/test_pim_basic_topo2.py b/tests/topotests/pim_basic_topo2/test_pim_basic_topo2.py
index 9506c3c6d1..5aa313137f 100644
--- a/tests/topotests/pim_basic_topo2/test_pim_basic_topo2.py
+++ b/tests/topotests/pim_basic_topo2/test_pim_basic_topo2.py
@@ -175,7 +175,7 @@ def test_pim_reconvergence():
"show ip pim neighbor json",
{interface: {peer: None}},
)
- _, result = topotest.run_and_expect(test_func, None, count=4, wait=1)
+ _, result = topotest.run_and_expect(test_func, None, count=5, wait=1)
assertmsg = '"{}" PIM convergence failure'.format(router)
assert result is None, assertmsg
@@ -201,7 +201,7 @@ def test_pim_bfd_profile():
"show bfd peers json",
[settings],
)
- _, result = topotest.run_and_expect(test_func, None, count=4, wait=1)
+ _, result = topotest.run_and_expect(test_func, None, count=5, wait=1)
assertmsg = '"{}" BFD convergence failure'.format(router)
assert result is None, assertmsg
diff --git a/tests/topotests/srv6_locator/test_srv6_locator.py b/tests/topotests/srv6_locator/test_srv6_locator.py
index bc5fa409d2..b918da0655 100755
--- a/tests/topotests/srv6_locator/test_srv6_locator.py
+++ b/tests/topotests/srv6_locator/test_srv6_locator.py
@@ -94,12 +94,12 @@ def test_srv6():
def check_srv6_locator(router, expected_file):
func = functools.partial(_check_srv6_locator, router, expected_file)
- success, result = topotest.run_and_expect(func, None, count=5, wait=0.5)
+ success, result = topotest.run_and_expect(func, None, count=10, wait=0.5)
assert result is None, "Failed"
def check_sharpd_chunk(router, expected_file):
func = functools.partial(_check_sharpd_chunk, router, expected_file)
- success, result = topotest.run_and_expect(func, None, count=5, wait=0.5)
+ success, result = topotest.run_and_expect(func, None, count=10, wait=0.5)
assert result is None, "Failed"
# FOR DEVELOPER:
diff --git a/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator.py b/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator.py
index ecc0856371..4bd0682bde 100755
--- a/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator.py
+++ b/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator.py
@@ -90,12 +90,12 @@ def test_srv6():
def check_srv6_locator(router, expected_file):
func = functools.partial(_check_srv6_locator, router, expected_file)
- success, result = topotest.run_and_expect(func, None, count=5, wait=0.5)
+ success, result = topotest.run_and_expect(func, None, count=10, wait=0.5)
assert result is None, "Failed"
def check_sharpd_chunk(router, expected_file):
func = functools.partial(_check_sharpd_chunk, router, expected_file)
- success, result = topotest.run_and_expect(func, None, count=5, wait=0.5)
+ success, result = topotest.run_and_expect(func, None, count=10, wait=0.5)
assert result is None, "Failed"
# FOR DEVELOPER:
@@ -124,7 +124,7 @@ def test_srv6():
srv6
locators
locator loc3
- prefix 2001:db8:3::/48 func-bits 16 block-len 32 node-len 16
+ prefix 2001:db8:3::/48 block-len 32 node-len 16 func-bits 16
"""
)
check_srv6_locator(router, "expected_locators4.json")
diff --git a/tests/topotests/srv6_locator_usid/r1/zebra.conf b/tests/topotests/srv6_locator_usid/r1/zebra.conf
index 78ef1e9d40..190e831ac1 100644
--- a/tests/topotests/srv6_locator_usid/r1/zebra.conf
+++ b/tests/topotests/srv6_locator_usid/r1/zebra.conf
@@ -12,7 +12,7 @@ segment-routing
srv6
locators
locator loc1
- prefix fc00:0:1::/48 func-bits 16 block-len 32 node-len 16
+ prefix fc00:0:1::/48 block-len 32 node-len 16 func-bits 16
behavior usid
!
!
diff --git a/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py b/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py
index 37fd736d2b..4023555524 100755
--- a/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py
+++ b/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py
@@ -54,12 +54,10 @@ def setup_module(mod):
for rname, router in tgen.routers().items():
router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname))
router.load_config(
- TopoRouter.RD_ZEBRA, os.path.join(
- CWD, "{}/zebra.conf".format(rname))
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
router.load_config(
- TopoRouter.RD_SHARP, os.path.join(
- CWD, "{}/sharpd.conf".format(rname))
+ TopoRouter.RD_SHARP, os.path.join(CWD, "{}/sharpd.conf".format(rname))
)
tgen.start_router()
@@ -71,18 +69,14 @@ def teardown_module(mod):
def _check_srv6_locator(router, expected_locator_file):
logger.info("checking zebra locator status")
- output = json.loads(
- router.vtysh_cmd("show segment-routing srv6 locator json")
- )
+ output = json.loads(router.vtysh_cmd("show segment-routing srv6 locator json"))
expected = open_json_file("{}/{}".format(CWD, expected_locator_file))
return topotest.json_cmp(output, expected)
def _check_sharpd_chunk(router, expected_chunk_file):
logger.info("checking sharpd locator chunk status")
- output = json.loads(
- router.vtysh_cmd("show sharp segment-routing srv6 json")
- )
+ output = json.loads(router.vtysh_cmd("show sharp segment-routing srv6 json"))
expected = open_json_file("{}/{}".format(CWD, expected_chunk_file))
return topotest.json_cmp(output, expected)
@@ -164,7 +158,7 @@ def test_srv6_usid_locator_create_locator():
srv6
locators
locator loc2
- prefix fc00:0:2::/48 func-bits 16 block-len 32 node-len 16
+ prefix fc00:0:2::/48 block-len 32 node-len 16 func-bits 16
"""
)
check_srv6_locator(router, "expected_locators_4.json")
@@ -181,9 +175,7 @@ def test_srv6_usid_locator_set_behavior_usid():
# If you want to stop some specific line and start interactive shell,
# please use tgen.mininet_cli() to start it.
- logger.info(
- "Specify the SRv6 Locator loc2 as a Micro-segment (uSID) Locator"
- )
+ logger.info("Specify the SRv6 Locator loc2 as a Micro-segment (uSID) Locator")
router.vtysh_cmd(
"""
configure terminal
diff --git a/tools/etc/frr/daemons b/tools/etc/frr/daemons
index 8aa08871e3..2427bfff77 100644
--- a/tools/etc/frr/daemons
+++ b/tools/etc/frr/daemons
@@ -91,6 +91,11 @@ pathd_options=" -A 127.0.0.1"
#
#MAX_FDS=1024
+# Uncomment this option if you want to run FRR as a non-root user. Note that
+# you should know what you are doing since most of the daemons need root
+# to work. This could be useful if you want to run FRR in a container
+# for instance.
+# FRR_NO_ROOT="yes"
# For any daemon, you can specify a "wrap" command to start instead of starting
# the daemon directly. This will simply be prepended to the daemon invocation.
diff --git a/tools/frrcommon.sh.in b/tools/frrcommon.sh.in
index 3c16c27c6d..4f095a176e 100755
--- a/tools/frrcommon.sh.in
+++ b/tools/frrcommon.sh.in
@@ -43,6 +43,10 @@ RELOAD_SCRIPT="$D_PATH/frr-reload.py"
#
is_user_root () {
+ if [[ ! -z $FRR_NO_ROOT && "${FRR_NO_ROOT}" == "yes" ]]; then
+ return 0
+ fi
+
[ "${EUID:-$(id -u)}" -eq 0 ] || {
log_failure_msg "Only users having EUID=0 can start/stop daemons"
return 1
diff --git a/zebra/interface.c b/zebra/interface.c
index d61d3620f1..81ee995dd7 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -4646,7 +4646,7 @@ static int if_config_write(struct vty *vty)
? ""
: "no ");
if (if_data->mpls == IF_ZEBRA_DATA_ON)
- vty_out(vty, " mpls\n");
+ vty_out(vty, " mpls enable\n");
}
hook_call(zebra_if_config_wr, vty, ifp);
diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c
index 7934a9d206..599c679864 100644
--- a/zebra/zebra_rnh.c
+++ b/zebra/zebra_rnh.c
@@ -62,7 +62,8 @@ static void free_state(vrf_id_t vrf_id, struct route_entry *re,
static void copy_state(struct rnh *rnh, const struct route_entry *re,
struct route_node *rn);
static bool compare_state(struct route_entry *r1, struct route_entry *r2);
-static void print_rnh(struct route_node *rn, struct vty *vty);
+static void print_rnh(struct route_node *rn, struct vty *vty,
+ json_object *json);
static int zebra_client_cleanup_rnh(struct zserv *client);
void zebra_rnh_init(void)
@@ -803,7 +804,8 @@ void zebra_evaluate_rnh(struct zebra_vrf *zvrf, afi_t afi, int force,
}
void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, safi_t safi,
- struct vty *vty, const struct prefix *p)
+ struct vty *vty, const struct prefix *p,
+ json_object *json)
{
struct route_table *table;
struct route_node *rn;
@@ -820,7 +822,7 @@ void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, safi_t safi,
continue;
if (rn->info)
- print_rnh(rn, vty);
+ print_rnh(rn, vty, json);
}
}
@@ -1268,73 +1270,178 @@ failure:
return -1;
}
-static void print_nh(struct nexthop *nexthop, struct vty *vty)
+static void print_nh(struct nexthop *nexthop, struct vty *vty,
+ json_object *json)
{
- char buf[BUFSIZ];
struct zebra_ns *zns = zebra_ns_lookup(nexthop->vrf_id);
switch (nexthop->type) {
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
- vty_out(vty, " via %pI4", &nexthop->gate.ipv4);
- if (nexthop->ifindex)
- vty_out(vty, ", %s",
- ifindex2ifname_per_ns(zns, nexthop->ifindex));
+ if (json) {
+ json_object_string_addf(json, "ip", "%pI4",
+ &nexthop->gate.ipv4);
+ if (nexthop->ifindex)
+ json_object_string_add(
+ json, "interface",
+ ifindex2ifname_per_ns(
+ zns, nexthop->ifindex));
+ } else {
+ vty_out(vty, " via %pI4", &nexthop->gate.ipv4);
+ if (nexthop->ifindex)
+ vty_out(vty, ", %s",
+ ifindex2ifname_per_ns(
+ zns, nexthop->ifindex));
+ }
break;
case NEXTHOP_TYPE_IPV6:
case NEXTHOP_TYPE_IPV6_IFINDEX:
- vty_out(vty, " %s",
- inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
- if (nexthop->ifindex)
- vty_out(vty, ", via %s",
- ifindex2ifname_per_ns(zns, nexthop->ifindex));
+ if (json) {
+ json_object_string_addf(json, "ip", "%pI6",
+ &nexthop->gate.ipv6);
+ if (nexthop->ifindex)
+ json_object_string_add(
+ json, "interface",
+ ifindex2ifname_per_ns(
+ zns, nexthop->ifindex));
+ } else {
+ vty_out(vty, " %pI6", &nexthop->gate.ipv6);
+ if (nexthop->ifindex)
+ vty_out(vty, ", via %s",
+ ifindex2ifname_per_ns(
+ zns, nexthop->ifindex));
+ }
break;
case NEXTHOP_TYPE_IFINDEX:
- vty_out(vty, " is directly connected, %s",
- ifindex2ifname_per_ns(zns, nexthop->ifindex));
+ if (json) {
+ json_object_string_add(
+ json, "interface",
+ ifindex2ifname_per_ns(zns, nexthop->ifindex));
+ json_object_boolean_true_add(json, "directlyConnected");
+ } else {
+ vty_out(vty, " is directly connected, %s",
+ ifindex2ifname_per_ns(zns, nexthop->ifindex));
+ }
break;
case NEXTHOP_TYPE_BLACKHOLE:
- vty_out(vty, " is directly connected, Null0");
+ if (json) {
+ json_object_string_add(json, "interface", "Null0");
+ json_object_boolean_true_add(json, "directlyConnected");
+ } else {
+ vty_out(vty, " is directly connected, Null0");
+ }
break;
default:
break;
}
- vty_out(vty, "\n");
+
+ if (!json)
+ vty_out(vty, "\n");
}
-static void print_rnh(struct route_node *rn, struct vty *vty)
+static void print_rnh(struct route_node *rn, struct vty *vty, json_object *json)
{
struct rnh *rnh;
struct nexthop *nexthop;
struct listnode *node;
struct zserv *client;
char buf[BUFSIZ];
+ json_object *json_nht = NULL;
+ json_object *json_client_array = NULL;
+ json_object *json_client = NULL;
+ json_object *json_nexthop_array = NULL;
+ json_object *json_nexthop = NULL;
rnh = rn->info;
- vty_out(vty, "%s%s\n",
- inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
- CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED) ? "(Connected)"
- : "");
- if (rnh->state) {
- vty_out(vty, " resolved via %s\n",
- zebra_route_string(rnh->state->type));
- for (nexthop = rnh->state->nhe->nhg.nexthop; nexthop;
- nexthop = nexthop->next)
- print_nh(nexthop, vty);
- } else
- vty_out(vty, " unresolved%s\n",
+
+ if (json) {
+ json_nht = json_object_new_object();
+ json_nexthop_array = json_object_new_array();
+ json_client_array = json_object_new_array();
+
+ json_object_object_add(
+ json,
+ inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
+ json_nht);
+ json_object_boolean_add(
+ json_nht, "nhtConnected",
+ CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED));
+ json_object_object_add(json_nht, "clientList",
+ json_client_array);
+ json_object_object_add(json_nht, "gates", json_nexthop_array);
+ } else {
+ vty_out(vty, "%s%s\n",
+ inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)
? "(Connected)"
: "");
+ }
+
+ if (rnh->state) {
+ if (json)
+ json_object_string_add(
+ json_nht, "resolvedProtocol",
+ zebra_route_string(rnh->state->type));
+ else
+ vty_out(vty, " resolved via %s\n",
+ zebra_route_string(rnh->state->type));
+
+ for (nexthop = rnh->state->nhe->nhg.nexthop; nexthop;
+ nexthop = nexthop->next) {
+ if (json) {
+ json_nexthop = json_object_new_object();
+ json_object_array_add(json_nexthop_array,
+ json_nexthop);
+ }
+ print_nh(nexthop, vty, json_nexthop);
+ }
+ } else {
+ if (json)
+ json_object_boolean_add(
+ json_nht, "unresolved",
+ CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED));
+ else
+ vty_out(vty, " unresolved%s\n",
+ CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)
+ ? "(Connected)"
+ : "");
+ }
+
+ if (!json)
+ vty_out(vty, " Client list:");
+
+ for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) {
+ if (json) {
+ json_client = json_object_new_object();
+ json_object_array_add(json_client_array, json_client);
+
+ json_object_string_add(
+ json_client, "protocol",
+ zebra_route_string(client->proto));
+ json_object_int_add(json_client, "socket",
+ client->sock);
+ json_object_string_add(json_client, "protocolFiltered",
+ (rnh->filtered[client->proto]
+ ? "(filtered)"
+ : "none"));
+ } else {
+ vty_out(vty, " %s(fd %d)%s",
+ zebra_route_string(client->proto), client->sock,
+ rnh->filtered[client->proto] ? "(filtered)"
+ : "");
+ }
+ }
+
+ if (!list_isempty(rnh->zebra_pseudowire_list)) {
+ if (json)
+ json_object_boolean_true_add(json_nht,
+ "zebraPseudowires");
+ else
+ vty_out(vty, " zebra[pseudowires]");
+ }
- vty_out(vty, " Client list:");
- for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client))
- vty_out(vty, " %s(fd %d)%s", zebra_route_string(client->proto),
- client->sock,
- rnh->filtered[client->proto] ? "(filtered)" : "");
- if (!list_isempty(rnh->zebra_pseudowire_list))
- vty_out(vty, " zebra[pseudowires]");
- vty_out(vty, "\n");
+ if (!json)
+ vty_out(vty, "\n");
}
static int zebra_cleanup_rnh_client(vrf_id_t vrf_id, afi_t afi, safi_t safi,
diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h
index 70eda725c4..44ce65b4b6 100644
--- a/zebra/zebra_rnh.h
+++ b/zebra/zebra_rnh.h
@@ -46,7 +46,8 @@ extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client);
extern void zebra_evaluate_rnh(struct zebra_vrf *zvrf, afi_t afi, int force,
const struct prefix *p, safi_t safi);
extern void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, safi_t safi,
- struct vty *vty, const struct prefix *p);
+ struct vty *vty, const struct prefix *p,
+ json_object *json);
extern int rnh_resolve_via_default(struct zebra_vrf *zvrf, int family);
diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c
index 1221365d4d..13ad9d71bb 100644
--- a/zebra/zebra_srv6_vty.c
+++ b/zebra/zebra_srv6_vty.c
@@ -276,16 +276,16 @@ DEFUN (no_srv6_locator,
DEFPY (locator_prefix,
locator_prefix_cmd,
- "prefix X:X::X:X/M$prefix [func-bits (0-64)$func_bit_len] \
- [block-len (16-64)$block_bit_len] [node-len (16-64)$node_bit_len]",
+ "prefix X:X::X:X/M$prefix [block-len (16-64)$block_bit_len] \
+ [node-len (16-64)$node_bit_len] [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"
- "Specify SRv6 locator function length in bits\n"
"Configure SRv6 locator block length in bits\n"
"Specify SRv6 locator block length in bits\n"
"Configure SRv6 locator node length in bits\n"
- "Specify SRv6 locator node length in bits\n")
+ "Specify SRv6 locator node length in bits\n"
+ "Configure SRv6 locator function length in bits\n"
+ "Specify SRv6 locator function length in bits\n")
{
VTY_DECLVAR_CONTEXT(srv6_locator, locator);
struct srv6_locator_chunk *chunk = NULL;
diff --git a/zebra/zebra_trace.h b/zebra/zebra_trace.h
index 49a0c8e793..374305fcda 100644
--- a/zebra/zebra_trace.h
+++ b/zebra/zebra_trace.h
@@ -123,6 +123,49 @@ TRACEPOINT_EVENT(
)
)
+TRACEPOINT_EVENT(
+ frr_zebra,
+ netlink_tc_qdisc_change,
+ TP_ARGS(
+ struct nlmsghdr *, header,
+ ns_id_t, ns_id,
+ int, startup),
+ TP_FIELDS(
+ ctf_integer_hex(intptr_t, header, header)
+ ctf_integer(uint32_t, ns_id, ns_id)
+ ctf_integer(uint32_t, startup, startup)
+ )
+ )
+
+TRACEPOINT_EVENT(
+ frr_zebra,
+ netlink_tc_class_change,
+ TP_ARGS(
+ struct nlmsghdr *, header,
+ ns_id_t, ns_id,
+ int, startup),
+ TP_FIELDS(
+ ctf_integer_hex(intptr_t, header, header)
+ ctf_integer(uint32_t, ns_id, ns_id)
+ ctf_integer(uint32_t, startup, startup)
+ )
+ )
+
+
+TRACEPOINT_EVENT(
+ frr_zebra,
+ netlink_tc_filter_change,
+ TP_ARGS(
+ struct nlmsghdr *, header,
+ ns_id_t, ns_id,
+ int, startup),
+ TP_FIELDS(
+ ctf_integer_hex(intptr_t, header, header)
+ ctf_integer(uint32_t, ns_id, ns_id)
+ ctf_integer(uint32_t, startup, startup)
+ )
+ )
+
#include <lttng/tracepoint-event.h>
#endif /* HAVE_LTTNG */
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 6561ac95fa..91a0c1dd31 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -1370,7 +1370,7 @@ static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi,
DEFPY (show_ip_nht,
show_ip_nht_cmd,
- "show <ip$ipv4|ipv6$ipv6> <nht|import-check>$type [<A.B.C.D|X:X::X:X>$addr|vrf NAME$vrf_name [<A.B.C.D|X:X::X:X>$addr]|vrf all$vrf_all] [mrib$mrib]",
+ "show <ip$ipv4|ipv6$ipv6> <nht|import-check>$type [<A.B.C.D|X:X::X:X>$addr|vrf NAME$vrf_name [<A.B.C.D|X:X::X:X>$addr]|vrf all$vrf_all] [mrib$mrib] [json]",
SHOW_STR
IP_STR
IP6_STR
@@ -1382,23 +1382,48 @@ DEFPY (show_ip_nht,
"IPv4 Address\n"
"IPv6 Address\n"
VRF_ALL_CMD_HELP_STR
- "Show Multicast (MRIB) NHT state\n")
+ "Show Multicast (MRIB) NHT state\n"
+ JSON_STR)
{
afi_t afi = ipv4 ? AFI_IP : AFI_IP6;
vrf_id_t vrf_id = VRF_DEFAULT;
struct prefix prefix, *p = NULL;
safi_t safi = mrib ? SAFI_MULTICAST : SAFI_UNICAST;
+ bool uj = use_json(argc, argv);
+ json_object *json = NULL;
+ json_object *json_vrf = NULL;
+ json_object *json_nexthop = NULL;
+
+ if (uj)
+ json = json_object_new_object();
if (vrf_all) {
struct vrf *vrf;
struct zebra_vrf *zvrf;
- RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
if ((zvrf = vrf->info) != NULL) {
- vty_out(vty, "\nVRF %s:\n", zvrf_name(zvrf));
+ if (uj) {
+ json_vrf = json_object_new_object();
+ json_nexthop = json_object_new_object();
+ json_object_object_add(json,
+ zvrf_name(zvrf),
+ json_vrf);
+ json_object_object_add(json_vrf,
+ "nexthops",
+ json_nexthop);
+ } else {
+ vty_out(vty, "\nVRF %s:\n",
+ zvrf_name(zvrf));
+ }
zebra_print_rnh_table(zvrf_id(zvrf), afi, safi,
- vty, NULL);
+ vty, NULL, json_nexthop);
}
+ }
+
+ if (uj)
+ vty_json(vty, json);
+
return CMD_SUCCESS;
}
if (vrf_name)
@@ -1407,11 +1432,29 @@ DEFPY (show_ip_nht,
memset(&prefix, 0, sizeof(prefix));
if (addr) {
p = sockunion2hostprefix(addr, &prefix);
- if (!p)
+ if (!p) {
+ if (uj)
+ json_object_free(json);
return CMD_WARNING;
+ }
}
- zebra_print_rnh_table(vrf_id, afi, safi, vty, p);
+ if (uj) {
+ json_vrf = json_object_new_object();
+ json_nexthop = json_object_new_object();
+ if (vrf_name)
+ json_object_object_add(json, vrf_name, json_vrf);
+ else
+ json_object_object_add(json, "default", json_vrf);
+
+ json_object_object_add(json_vrf, "nexthops", json_nexthop);
+ }
+
+ zebra_print_rnh_table(vrf_id, afi, safi, vty, p, json_nexthop);
+
+ if (uj)
+ vty_json(vty, json);
+
return CMD_SUCCESS;
}