summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfdd/subdir.am2
-rw-r--r--bgpd/bgp_attr.c130
-rw-r--r--bgpd/bgp_attr.h2
-rw-r--r--bgpd/bgp_open.c6
-rw-r--r--bgpd/bgp_pbr.c2
-rw-r--r--bgpd/bgp_updgrp.c1
-rw-r--r--bgpd/bgp_updgrp.h2
-rw-r--r--bgpd/bgp_updgrp_adv.c81
-rw-r--r--bgpd/bgp_updgrp_packet.c18
-rw-r--r--bgpd/bgp_vty.c87
-rw-r--r--bgpd/bgp_zebra.c16
-rw-r--r--bgpd/bgpd.h7
-rw-r--r--bgpd/subdir.am2
-rwxr-xr-xconfigure.ac36
-rw-r--r--debian/frr.logrotate2
-rw-r--r--debian/frr.manpages28
-rw-r--r--doc/developer/building-frr-for-centos6.rst8
-rw-r--r--doc/developer/building-frr-for-centos7.rst9
-rw-r--r--doc/developer/building-frr-for-centos8.rst9
-rw-r--r--doc/developer/building-frr-for-fedora.rst7
-rw-r--r--doc/developer/building.rst1
-rw-r--r--doc/developer/static-linking.rst98
-rw-r--r--doc/developer/subdir.am1
-rw-r--r--doc/developer/topotests.rst1
-rw-r--r--doc/manpages/conf.py42
-rw-r--r--doc/manpages/defines.rst2
-rw-r--r--doc/manpages/frr-bfdd.rst (renamed from doc/manpages/bfdd.rst)0
-rw-r--r--doc/manpages/frr-bgpd.rst (renamed from doc/manpages/bgpd.rst)0
-rw-r--r--doc/manpages/frr-eigrpd.rst (renamed from doc/manpages/eigrpd.rst)0
-rw-r--r--doc/manpages/frr-fabricd.rst (renamed from doc/manpages/fabricd.rst)0
-rw-r--r--doc/manpages/frr-isisd.rst (renamed from doc/manpages/isisd.rst)0
-rw-r--r--doc/manpages/frr-ldpd.rst (renamed from doc/manpages/ldpd.rst)0
-rw-r--r--doc/manpages/frr-nhrpd.rst (renamed from doc/manpages/nhrpd.rst)0
-rw-r--r--doc/manpages/frr-ospf6d.rst (renamed from doc/manpages/ospf6d.rst)0
-rw-r--r--doc/manpages/frr-ospfclient.rst (renamed from doc/manpages/ospfclient.rst)0
-rw-r--r--doc/manpages/frr-ospfd.rst (renamed from doc/manpages/ospfd.rst)0
-rw-r--r--doc/manpages/frr-pbrd.rst (renamed from doc/manpages/pbrd.rst)0
-rw-r--r--doc/manpages/frr-pimd.rst (renamed from doc/manpages/pimd.rst)0
-rw-r--r--doc/manpages/frr-ripd.rst (renamed from doc/manpages/ripd.rst)0
-rw-r--r--doc/manpages/frr-ripngd.rst (renamed from doc/manpages/ripngd.rst)0
-rw-r--r--doc/manpages/frr-sharpd.rst (renamed from doc/manpages/sharpd.rst)0
-rw-r--r--doc/manpages/frr-staticd.rst (renamed from doc/manpages/staticd.rst)0
-rw-r--r--doc/manpages/frr-vrrpd.rst (renamed from doc/manpages/vrrpd.rst)0
-rw-r--r--doc/manpages/frr-watchfrr.rst (renamed from doc/manpages/watchfrr.rst)0
-rw-r--r--doc/manpages/frr-zebra.rst (renamed from doc/manpages/zebra.rst)0
-rw-r--r--doc/manpages/index.rst40
-rw-r--r--doc/manpages/subdir.am40
-rw-r--r--doc/user/bfd.rst10
-rw-r--r--doc/user/bgp.rst5
-rw-r--r--eigrpd/subdir.am2
-rw-r--r--isisd/subdir.am2
-rw-r--r--ldpd/subdir.am2
-rw-r--r--lib/gitversion.pl2
-rw-r--r--lib/log.c1
-rw-r--r--lib/nexthop.c28
-rw-r--r--lib/nexthop.h7
-rw-r--r--lib/nexthop_group.c9
-rw-r--r--lib/zclient.c50
-rw-r--r--lib/zclient.h31
-rw-r--r--m4/ax_python.m42
-rw-r--r--nhrpd/nhrp_peer.c6
-rw-r--r--nhrpd/subdir.am2
-rw-r--r--ospf6d/ospf6_flood.c12
-rw-r--r--ospf6d/subdir.am2
-rw-r--r--ospfclient/subdir.am2
-rw-r--r--ospfd/ospf_vty.c2
-rw-r--r--ospfd/subdir.am2
-rw-r--r--pbrd/subdir.am2
-rw-r--r--pimd/pim_zlookup.c11
-rw-r--r--pimd/subdir.am2
-rw-r--r--ripd/subdir.am2
-rw-r--r--ripngd/subdir.am2
-rw-r--r--sharpd/subdir.am2
-rw-r--r--solaris/prototype.doc.in14
-rw-r--r--staticd/static_debug.c124
-rw-r--r--staticd/static_debug.h73
-rw-r--r--staticd/static_main.c2
-rw-r--r--staticd/static_vty.c36
-rw-r--r--staticd/subdir.am4
-rw-r--r--tests/bgpd/test_mp_attr.c2
-rw-r--r--tests/topotests/all-protocol-startup/r1/ipv4_routes.ref2
-rw-r--r--tests/topotests/all-protocol-startup/r1/zebra.conf5
-rwxr-xr-xtests/topotests/all-protocol-startup/test_all_protocol_startup.py31
-rw-r--r--tests/topotests/bgp_default-route_route-map/__init__.py0
-rw-r--r--tests/topotests/bgp_default-route_route-map/r1/bgpd.conf9
-rw-r--r--tests/topotests/bgp_default-route_route-map/r1/zebra.conf9
-rw-r--r--tests/topotests/bgp_default-route_route-map/r2/bgpd.conf6
-rw-r--r--tests/topotests/bgp_default-route_route-map/r2/zebra.conf6
-rw-r--r--tests/topotests/bgp_default-route_route-map/test_bgp_default-originate_route-map.py131
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_up.py11
-rw-r--r--tests/topotests/bgp_maximum_prefix_out/__init__.py0
-rw-r--r--tests/topotests/bgp_maximum_prefix_out/r1/bgpd.conf9
-rw-r--r--tests/topotests/bgp_maximum_prefix_out/r1/zebra.conf13
-rw-r--r--tests/topotests/bgp_maximum_prefix_out/r2/bgpd.conf6
-rw-r--r--tests/topotests/bgp_maximum_prefix_out/r2/zebra.conf6
-rw-r--r--tests/topotests/bgp_maximum_prefix_out/test_bgp_maximum_prefix_out.py108
-rw-r--r--tests/topotests/lib/ltemplate.py1
-rwxr-xr-xtests/topotests/lib/lutil.py8
-rw-r--r--tests/topotests/ospf6-topo1/r1/ip_6_address.nhg.ref10
-rwxr-xr-xtests/topotests/ospf6-topo1/test_ospf6_topo1.py8
-rw-r--r--tests/topotests/pim-basic/r1/bgpd.conf3
-rw-r--r--tests/topotests/pim-basic/r1/pimd.conf9
-rw-r--r--tests/topotests/pim-basic/r1/rp-info.json9
-rw-r--r--tests/topotests/pim-basic/r1/zebra.conf3
-rw-r--r--tests/topotests/pim-basic/rp/bgpd.conf3
-rw-r--r--tests/topotests/pim-basic/rp/pimd.conf9
-rw-r--r--tests/topotests/pim-basic/rp/upstream.json17
-rw-r--r--tests/topotests/pim-basic/rp/zebra.conf8
-rw-r--r--tests/topotests/pim-basic/test_pim.py54
-rwxr-xr-xtools/frr-reload.py28
-rw-r--r--vrrpd/subdir.am2
-rw-r--r--watchfrr/subdir.am2
-rw-r--r--zebra/kernel_netlink.c2
-rw-r--r--zebra/label_manager.c4
-rw-r--r--zebra/rt_netlink.c2
-rw-r--r--zebra/subdir.am2
-rw-r--r--zebra/zapi_msg.c87
-rw-r--r--zebra/zebra_nhg.c48
-rw-r--r--zebra/zebra_pbr.c10
-rw-r--r--zebra/zebra_ptm.c6
-rw-r--r--zebra/zebra_vty.c3
-rw-r--r--zebra/zebra_vxlan.c7
-rw-r--r--zebra/zserv.c4
-rw-r--r--zebra/zserv.h1
124 files changed, 1537 insertions, 300 deletions
diff --git a/bfdd/subdir.am b/bfdd/subdir.am
index ed1d3962bf..9aa522f3f0 100644
--- a/bfdd/subdir.am
+++ b/bfdd/subdir.am
@@ -8,7 +8,7 @@ sbin_PROGRAMS += bfdd/bfdd
dist_examples_DATA += bfdd/bfdd.conf.sample
vtysh_scan += $(top_srcdir)/bfdd/bfdd_vty.c
vtysh_scan += $(top_srcdir)/bfdd/bfdd_cli.c
-man8 += $(MANBUILD)/bfdd.8
+man8 += $(MANBUILD)/frr-bfdd.8
endif
bfdd_libbfd_a_SOURCES = \
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index bdac2a8dcc..16de59b72c 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -2136,8 +2136,7 @@ static int bgp_attr_encap(uint8_t type, struct peer *peer, /* IN */
* Read an individual SID value returning how much data we have read
* Returns 0 if there was an error that needs to be passed up the stack
*/
-static bgp_attr_parse_ret_t bgp_attr_psid_sub(int32_t type,
- int32_t length,
+static bgp_attr_parse_ret_t bgp_attr_psid_sub(uint8_t type, uint16_t length,
struct bgp_attr_parser_args *args,
struct bgp_nlri *mp_update)
{
@@ -2150,11 +2149,12 @@ static bgp_attr_parse_ret_t bgp_attr_psid_sub(int32_t type,
int srgb_count;
if (type == BGP_PREFIX_SID_LABEL_INDEX) {
- if (length != BGP_PREFIX_SID_LABEL_INDEX_LENGTH) {
- flog_err(
- EC_BGP_ATTR_LEN,
- "Prefix SID label index length is %d instead of %d",
- length, BGP_PREFIX_SID_LABEL_INDEX_LENGTH);
+ if (STREAM_READABLE(peer->curr) < length
+ || length != BGP_PREFIX_SID_LABEL_INDEX_LENGTH) {
+ flog_err(EC_BGP_ATTR_LEN,
+ "Prefix SID label index length is %" PRIu16
+ " instead of %u",
+ length, BGP_PREFIX_SID_LABEL_INDEX_LENGTH);
return bgp_attr_malformed(args,
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
args->total);
@@ -2186,9 +2186,11 @@ static bgp_attr_parse_ret_t bgp_attr_psid_sub(int32_t type,
/* Placeholder code for the IPv6 SID type */
else if (type == BGP_PREFIX_SID_IPV6) {
- if (length != BGP_PREFIX_SID_IPV6_LENGTH) {
+ if (STREAM_READABLE(peer->curr) < length
+ || length != BGP_PREFIX_SID_IPV6_LENGTH) {
flog_err(EC_BGP_ATTR_LEN,
- "Prefix SID IPv6 length is %d instead of %d",
+ "Prefix SID IPv6 length is %" PRIu16
+ " instead of %u",
length, BGP_PREFIX_SID_IPV6_LENGTH);
return bgp_attr_malformed(args,
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
@@ -2204,15 +2206,54 @@ static bgp_attr_parse_ret_t bgp_attr_psid_sub(int32_t type,
/* Placeholder code for the Originator SRGB type */
else if (type == BGP_PREFIX_SID_ORIGINATOR_SRGB) {
- /* Ignore flags */
- stream_getw(peer->curr);
+ /*
+ * ietf-idr-bgp-prefix-sid-05:
+ * Length is the total length of the value portion of the
+ * TLV: 2 + multiple of 6.
+ *
+ * peer->curr stream readp should be at the beginning of the 16
+ * bit flag field at this point in the code.
+ */
- length -= 2;
+ /*
+ * Check that the TLV length field is sane: at least 2 bytes of
+ * flag, and at least 1 SRGB (these are 6 bytes each)
+ */
+ if (length < (2 + BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH)) {
+ flog_err(
+ EC_BGP_ATTR_LEN,
+ "Prefix SID Originator SRGB length field claims length of %" PRIu16 " bytes, but the minimum for this TLV type is %u",
+ length,
+ 2 + BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH);
+ return bgp_attr_malformed(
+ args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
+ }
+ /*
+ * Check that we actually have at least as much data as
+ * specified by the length field
+ */
+ if (STREAM_READABLE(peer->curr) < length) {
+ flog_err(EC_BGP_ATTR_LEN,
+ "Prefix SID Originator SRGB specifies length %" PRIu16 ", but only %zu bytes remain",
+ length, STREAM_READABLE(peer->curr));
+ return bgp_attr_malformed(
+ args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
+ }
+
+ /*
+ * Check that the portion of the TLV containing the sequence of
+ * SRGBs corresponds to a multiple of the SRGB size; to get
+ * that length, we skip the 16 bit flags field
+ */
+ stream_getw(peer->curr);
+ length -= 2;
if (length % BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH) {
flog_err(
EC_BGP_ATTR_LEN,
- "Prefix SID Originator SRGB length is %d, it must be a multiple of %d ",
+ "Prefix SID Originator SRGB length field claims attribute SRGB sequence section is %" PRIu16 "bytes, but it must be a multiple of %u",
length, BGP_PREFIX_SID_ORIGINATOR_SRGB_LENGTH);
return bgp_attr_malformed(
args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
@@ -2234,12 +2275,24 @@ static bgp_attr_parse_ret_t bgp_attr_psid_sub(int32_t type,
*/
else if (type == BGP_PREFIX_SID_SRV6_L3_SERVICE
|| type == BGP_PREFIX_SID_SRV6_L2_SERVICE) {
+
+ if (STREAM_READABLE(peer->curr) < length) {
+ flog_err(
+ EC_BGP_ATTR_LEN,
+ "Prefix SID SRv6 length is %" PRIu16
+ " - too long, only %zu remaining in this UPDATE",
+ length, STREAM_READABLE(peer->curr));
+ return bgp_attr_malformed(
+ args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
+ }
+
if (bgp_debug_update(peer, NULL, NULL, 1))
zlog_debug(
"%s attr Prefix-SID sub-type=%u is not supported, skipped",
peer->host, type);
- for (int i = 0; i < length; i++)
- stream_getc(peer->curr);
+
+ stream_forward_getp(peer->curr, length);
}
return BGP_ATTR_PARSE_PROCEED;
@@ -2248,9 +2301,8 @@ static bgp_attr_parse_ret_t bgp_attr_psid_sub(int32_t type,
/* Prefix SID attribute
* draft-ietf-idr-bgp-prefix-sid-05
*/
-bgp_attr_parse_ret_t
-bgp_attr_prefix_sid(int32_t tlength, struct bgp_attr_parser_args *args,
- struct bgp_nlri *mp_update)
+bgp_attr_parse_ret_t bgp_attr_prefix_sid(struct bgp_attr_parser_args *args,
+ struct bgp_nlri *mp_update)
{
struct peer *const peer = args->peer;
struct attr *const attr = args->attr;
@@ -2258,31 +2310,40 @@ bgp_attr_prefix_sid(int32_t tlength, struct bgp_attr_parser_args *args,
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID);
- while (tlength) {
- int32_t type, length;
+ uint8_t type;
+ uint16_t length;
+ size_t headersz = sizeof(type) + sizeof(length);
- type = stream_getc(peer->curr);
- length = stream_getw(peer->curr);
+ while (STREAM_READABLE(peer->curr) > 0) {
- ret = bgp_attr_psid_sub(type, length, args, mp_update);
+ if (STREAM_READABLE(peer->curr) < headersz) {
+ flog_err(
+ EC_BGP_ATTR_LEN,
+ "Malformed Prefix SID attribute - insufficent data (need %zu for attribute header, have %zu remaining in UPDATE)",
+ headersz, STREAM_READABLE(peer->curr));
+ return bgp_attr_malformed(
+ args, BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
+ args->total);
+ }
- if (ret != BGP_ATTR_PARSE_PROCEED)
- return ret;
- /*
- * Subtract length + the T and the L
- * since length is the Vector portion
- */
- tlength -= length + 3;
+ type = stream_getc(peer->curr);
+ length = stream_getw(peer->curr);
- if (tlength < 0) {
+ if (STREAM_READABLE(peer->curr) < length) {
flog_err(
EC_BGP_ATTR_LEN,
- "Prefix SID internal length %d causes us to read beyond the total Prefix SID length",
- length);
+ "Malformed Prefix SID attribute - insufficient data (need %" PRIu8
+ " for attribute body, have %zu remaining in UPDATE)",
+ length, STREAM_READABLE(peer->curr));
return bgp_attr_malformed(args,
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR,
args->total);
}
+
+ ret = bgp_attr_psid_sub(type, length, args, mp_update);
+
+ if (ret != BGP_ATTR_PARSE_PROCEED)
+ return ret;
}
return BGP_ATTR_PARSE_PROCEED;
@@ -2678,8 +2739,7 @@ bgp_attr_parse_ret_t bgp_attr_parse(struct peer *peer, struct attr *attr,
startp);
break;
case BGP_ATTR_PREFIX_SID:
- ret = bgp_attr_prefix_sid(length,
- &attr_args, mp_update);
+ ret = bgp_attr_prefix_sid(&attr_args, mp_update);
break;
case BGP_ATTR_PMSI_TUNNEL:
ret = bgp_attr_pmsi_tunnel(&attr_args);
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index 40e87e190a..8bd527c0ff 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -319,7 +319,7 @@ extern int bgp_mp_reach_parse(struct bgp_attr_parser_args *args,
extern int bgp_mp_unreach_parse(struct bgp_attr_parser_args *args,
struct bgp_nlri *);
extern bgp_attr_parse_ret_t
-bgp_attr_prefix_sid(int32_t tlength, struct bgp_attr_parser_args *args,
+bgp_attr_prefix_sid(struct bgp_attr_parser_args *args,
struct bgp_nlri *mp_update);
extern struct bgp_attr_encap_subtlv *
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index f17bc7b8c0..23b893c1c8 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -747,6 +747,12 @@ static int bgp_capability_hostname(struct peer *peer,
if (len) {
str[len] = '\0';
+
+ if (peer->domainname != NULL) {
+ XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
+ peer->domainname = NULL;
+ }
+
peer->domainname = XSTRDUP(MTYPE_BGP_PEER_HOST, str);
}
diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c
index 83194e010a..14f5fefb20 100644
--- a/bgpd/bgp_pbr.c
+++ b/bgpd/bgp_pbr.c
@@ -1725,7 +1725,7 @@ static void bgp_pbr_policyroute_remove_from_zebra_unit(
temp.type = IPSET_NET_NET;
}
if (bpf->vrf_id == VRF_UNKNOWN) /* XXX case BGP destroy */
- temp.vrf_id = 0;
+ temp.vrf_id = VRF_DEFAULT;
else
temp.vrf_id = bpf->vrf_id;
bpme = &temp2;
diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c
index 5f3f5cde9a..5b3eb2c719 100644
--- a/bgpd/bgp_updgrp.c
+++ b/bgpd/bgp_updgrp.c
@@ -143,6 +143,7 @@ static void conf_copy(struct peer *dst, struct peer *src, afi_t afi,
dst->v_routeadv = src->v_routeadv;
dst->flags = src->flags;
dst->af_flags[afi][safi] = src->af_flags[afi][safi];
+ dst->pmax_out[afi][safi] = src->pmax_out[afi][safi];
XFREE(MTYPE_BGP_PEER_HOST, dst->host);
dst->host = XSTRDUP(MTYPE_BGP_PEER_HOST, src->host);
diff --git a/bgpd/bgp_updgrp.h b/bgpd/bgp_updgrp.h
index bb547454f2..fe654bb3e3 100644
--- a/bgpd/bgp_updgrp.h
+++ b/bgpd/bgp_updgrp.h
@@ -208,7 +208,7 @@ struct update_subgroup {
struct bgp_synchronize *sync;
/* send prefix count */
- unsigned long scount;
+ uint32_t scount;
/* announcement attribute hash */
struct hash *hash;
diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c
index 49e87adc3c..26dda8ebda 100644
--- a/bgpd/bgp_updgrp_adv.c
+++ b/bgpd/bgp_updgrp_adv.c
@@ -64,6 +64,12 @@ static int bgp_adj_out_compare(const struct bgp_adj_out *o1,
if (o1->subgroup > o2->subgroup)
return 1;
+ if (o1->addpath_tx_id < o2->addpath_tx_id)
+ return -1;
+
+ if (o1->addpath_tx_id > o2->addpath_tx_id)
+ return 1;
+
return 0;
}
RB_GENERATE(bgp_adj_out_rb, bgp_adj_out, adj_entry, bgp_adj_out_compare);
@@ -72,32 +78,17 @@ static inline struct bgp_adj_out *adj_lookup(struct bgp_node *rn,
struct update_subgroup *subgrp,
uint32_t addpath_tx_id)
{
- struct bgp_adj_out *adj, lookup;
- struct peer *peer;
- afi_t afi;
- safi_t safi;
- int addpath_capable;
+ struct bgp_adj_out lookup;
if (!rn || !subgrp)
return NULL;
- peer = SUBGRP_PEER(subgrp);
- afi = SUBGRP_AFI(subgrp);
- safi = SUBGRP_SAFI(subgrp);
- addpath_capable = bgp_addpath_encode_tx(peer, afi, safi);
-
/* update-groups that do not support addpath will pass 0 for
- * addpath_tx_id so do not both matching against it */
+ * addpath_tx_id. */
lookup.subgroup = subgrp;
- adj = RB_FIND(bgp_adj_out_rb, &rn->adj_out, &lookup);
- if (adj) {
- if (addpath_capable) {
- if (adj->addpath_tx_id == addpath_tx_id)
- return adj;
- } else
- return adj;
- }
- return NULL;
+ lookup.addpath_tx_id = addpath_tx_id;
+
+ return RB_FIND(bgp_adj_out_rb, &rn->adj_out, &lookup);
}
static void adj_free(struct bgp_adj_out *adj)
@@ -403,13 +394,14 @@ struct bgp_adj_out *bgp_adj_out_alloc(struct update_subgroup *subgrp,
adj = XCALLOC(MTYPE_BGP_ADJ_OUT, sizeof(struct bgp_adj_out));
adj->subgroup = subgrp;
+ adj->addpath_tx_id = addpath_tx_id;
+
if (rn) {
RB_INSERT(bgp_adj_out_rb, &rn->adj_out, adj);
bgp_lock_node(rn);
adj->rn = rn;
}
- adj->addpath_tx_id = addpath_tx_id;
TAILQ_INSERT_TAIL(&(subgrp->adjq), adj, subgrp_adj_train);
SUBGRP_INCR_STAT(subgrp, adj_count);
return adj;
@@ -710,12 +702,11 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
{
struct bgp *bgp;
struct attr attr;
+ struct attr *new_attr = &attr;
struct aspath *aspath;
- struct bgp_path_info tmp_info;
struct prefix p;
struct peer *from;
struct bgp_node *rn;
- struct bgp_path_info *ri;
struct peer *peer;
route_map_result_t ret = RMAP_DENYMATCH;
afi_t afi;
@@ -755,37 +746,33 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
}
if (peer->default_rmap[afi][safi].name) {
+ struct attr attr_tmp = attr;
+ struct bgp_path_info bpi_rmap = {0};
+
+ bpi_rmap.peer = bgp->peer_self;
+ bpi_rmap.attr = &attr_tmp;
+
SET_FLAG(bgp->peer_self->rmap_type, PEER_RMAP_TYPE_DEFAULT);
+
+ /* Iterate over the RIB to see if we can announce
+ * the default route. We announce the default
+ * route only if route-map has a match.
+ */
for (rn = bgp_table_top(bgp->rib[afi][safi]); rn;
rn = bgp_route_next(rn)) {
- for (ri = bgp_node_get_bgp_path_info(rn);
- ri; ri = ri->next) {
- struct attr dummy_attr;
-
- /* Provide dummy so the route-map can't modify
- * the attributes */
- dummy_attr = *ri->attr;
- tmp_info.peer = ri->peer;
- tmp_info.attr = &dummy_attr;
-
- ret = route_map_apply(
- peer->default_rmap[afi][safi].map,
- &rn->p, RMAP_BGP, &tmp_info);
-
- /* The route map might have set attributes. If
- * we don't flush them
- * here, they will be leaked. */
- bgp_attr_flush(&dummy_attr);
- if (ret != RMAP_DENYMATCH)
- break;
- }
+ ret = route_map_apply(peer->default_rmap[afi][safi].map,
+ &rn->p, RMAP_BGP, &bpi_rmap);
+
if (ret != RMAP_DENYMATCH)
break;
}
bgp->peer_self->rmap_type = 0;
+ new_attr = bgp_attr_intern(&attr_tmp);
- if (ret == RMAP_DENYMATCH)
+ if (ret == RMAP_DENYMATCH) {
+ bgp_attr_flush(&attr_tmp);
withdraw = 1;
+ }
}
if (withdraw) {
@@ -797,12 +784,12 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
SUBGRP_STATUS_DEFAULT_ORIGINATE)) {
if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN)) {
- bgp_attr_add_gshut_community(&attr);
+ bgp_attr_add_gshut_community(new_attr);
}
SET_FLAG(subgrp->sflags,
SUBGRP_STATUS_DEFAULT_ORIGINATE);
- subgroup_default_update_packet(subgrp, &attr, from);
+ subgroup_default_update_packet(subgrp, new_attr, from);
/* The 'neighbor x.x.x.x default-originate' default will
* act as an
diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c
index 9329c8d892..39eb065288 100644
--- a/bgpd/bgp_updgrp_packet.c
+++ b/bgpd/bgp_updgrp_packet.c
@@ -744,6 +744,22 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
addpath_tx_id = adj->addpath_tx_id;
path = adv->pathi;
+ /* Check if we need to add a prefix to the packet if
+ * maximum-prefix-out is set for the peer.
+ */
+ if (CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_MAX_PREFIX_OUT)
+ && subgrp->scount >= peer->pmax_out[afi][safi]) {
+ if (BGP_DEBUG(update, UPDATE_OUT)
+ || BGP_DEBUG(update, UPDATE_PREFIX)) {
+ zlog_debug(
+ "%s reached maximum prefix to be send (%" PRIu32
+ ")",
+ peer->host, peer->pmax_out[afi][safi]);
+ }
+ goto next;
+ }
+
space_remaining = STREAM_CONCAT_REMAIN(s, snlri, STREAM_SIZE(s))
- BGP_MAX_PACKET_SIZE_OVERFLOW;
space_needed =
@@ -894,7 +910,7 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
subgrp->scount++;
adj->attr = bgp_attr_intern(adv->baa->attr);
-
+next:
adv = bgp_advertise_clean_subgroup(subgrp, adj);
}
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 53d9732956..9dc6549d9c 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -6058,6 +6058,56 @@ static int peer_maximum_prefix_unset_vty(struct vty *vty, const char *ip_str,
return bgp_vty_return(vty, ret);
}
+/* Maximum number of prefix to be sent to the neighbor. */
+DEFUN(neighbor_maximum_prefix_out,
+ neighbor_maximum_prefix_out_cmd,
+ "neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix-out (1-4294967295)",
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Maximum number of prefixes to be sent to this peer\n"
+ "Maximum no. of prefix limit\n")
+{
+ int idx_peer = 1;
+ int idx_number = 3;
+ struct peer *peer;
+ uint32_t max;
+ afi_t afi = bgp_node_afi(vty);
+ safi_t safi = bgp_node_safi(vty);
+
+ peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ max = strtoul(argv[idx_number]->arg, NULL, 10);
+
+ SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_OUT);
+ peer->pmax_out[afi][safi] = max;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(no_neighbor_maximum_prefix_out,
+ no_neighbor_maximum_prefix_out_cmd,
+ "no neighbor <A.B.C.D|X:X::X:X|WORD> maximum-prefix-out",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Maximum number of prefixes to be sent to this peer\n")
+{
+ int idx_peer = 2;
+ struct peer *peer;
+ afi_t afi = bgp_node_afi(vty);
+ safi_t safi = bgp_node_safi(vty);
+
+ peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ peer->pmax_out[afi][safi] = 0;
+
+ return CMD_SUCCESS;
+}
+
/* Maximum number of prefix configuration. prefix count is different
for each peer configuration. So this configuration can be set for
each peer configuration. */
@@ -9191,6 +9241,11 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi,
(PAF_SUBGRP(paf))->scount);
/* Maximum prefix */
+ if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX_OUT))
+ json_object_int_add(json_addr, "prefixOutAllowedMax",
+ p->pmax_out[afi][safi]);
+
+ /* Maximum prefix */
if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX)) {
json_object_int_add(json_addr, "prefixAllowedMax",
p->pmax[afi][safi]);
@@ -9476,6 +9531,13 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi,
vty_out(vty, " %" PRIu32 " accepted prefixes\n",
p->pcount[afi][safi]);
+ /* maximum-prefix-out */
+ if (CHECK_FLAG(p->af_flags[afi][safi],
+ PEER_FLAG_MAX_PREFIX_OUT))
+ vty_out(vty,
+ " Maximum allowed prefixes sent %" PRIu32 "\n",
+ p->pmax_out[afi][safi]);
+
/* Maximum prefix */
if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_MAX_PREFIX)) {
vty_out(vty,
@@ -13579,6 +13641,11 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
vty_out(vty, "\n");
}
+ /* maximum-prefix-out */
+ if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_MAX_PREFIX_OUT))
+ vty_out(vty, " neighbor %s maximum-prefix-out %" PRIu32 "\n",
+ addr, peer->pmax_out[afi][safi]);
+
/* Route server client. */
if (peergroup_af_flag_check(peer, afi, safi,
PEER_FLAG_RSERVER_CLIENT)) {
@@ -15115,6 +15182,26 @@ void bgp_vty_init(void)
install_element(BGP_VPNV6_NODE, &neighbor_unsuppress_map_cmd);
install_element(BGP_VPNV6_NODE, &no_neighbor_unsuppress_map_cmd);
+ /* neighbor maximum-prefix-out commands. */
+ install_element(BGP_NODE, &neighbor_maximum_prefix_out_cmd);
+ install_element(BGP_NODE, &no_neighbor_maximum_prefix_out_cmd);
+ install_element(BGP_IPV4_NODE, &neighbor_maximum_prefix_out_cmd);
+ install_element(BGP_IPV4_NODE, &no_neighbor_maximum_prefix_out_cmd);
+ install_element(BGP_IPV4M_NODE, &neighbor_maximum_prefix_out_cmd);
+ install_element(BGP_IPV4M_NODE, &no_neighbor_maximum_prefix_out_cmd);
+ install_element(BGP_IPV4L_NODE, &neighbor_maximum_prefix_out_cmd);
+ install_element(BGP_IPV4L_NODE, &no_neighbor_maximum_prefix_out_cmd);
+ install_element(BGP_IPV6_NODE, &neighbor_maximum_prefix_out_cmd);
+ install_element(BGP_IPV6_NODE, &no_neighbor_maximum_prefix_out_cmd);
+ install_element(BGP_IPV6M_NODE, &neighbor_maximum_prefix_out_cmd);
+ install_element(BGP_IPV6M_NODE, &no_neighbor_maximum_prefix_out_cmd);
+ install_element(BGP_IPV6L_NODE, &neighbor_maximum_prefix_out_cmd);
+ install_element(BGP_IPV6L_NODE, &no_neighbor_maximum_prefix_out_cmd);
+ install_element(BGP_VPNV4_NODE, &neighbor_maximum_prefix_out_cmd);
+ install_element(BGP_VPNV4_NODE, &no_neighbor_maximum_prefix_out_cmd);
+ install_element(BGP_VPNV6_NODE, &neighbor_maximum_prefix_out_cmd);
+ install_element(BGP_VPNV6_NODE, &no_neighbor_maximum_prefix_out_cmd);
+
/* "neighbor maximum-prefix" commands. */
install_element(BGP_NODE, &neighbor_maximum_prefix_hidden_cmd);
install_element(BGP_NODE,
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 069c53d7df..c99ddaf0a6 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -1384,6 +1384,8 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
if (bgp_debug_zebra(p)) {
char prefix_buf[PREFIX_STRLEN];
char nh_buf[INET6_ADDRSTRLEN];
+ char eth_buf[ETHER_ADDR_STRLEN + 7] = {'\0'};
+ char buf1[ETHER_ADDR_STRLEN];
char label_buf[20];
int i;
@@ -1421,13 +1423,19 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
}
label_buf[0] = '\0';
+ eth_buf[0] = '\0';
if (has_valid_label
&& !CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE))
- sprintf(label_buf, "label %u",
- api_nh->labels[0]);
- zlog_debug(" nhop [%d]: %s if %u VRF %u %s",
+ snprintf(label_buf, sizeof(label_buf),
+ "label %u", api_nh->labels[0]);
+ if (CHECK_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE)
+ && !is_zero_mac(&api_nh->rmac))
+ snprintf(eth_buf, sizeof(eth_buf), " RMAC %s",
+ prefix_mac2str(&api_nh->rmac,
+ buf1, sizeof(buf1)));
+ zlog_debug(" nhop [%d]: %s if %u VRF %u %s %s",
i + 1, nh_buf, api_nh->ifindex,
- api_nh->vrf_id, label_buf);
+ api_nh->vrf_id, label_buf, eth_buf);
}
}
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 7d81579009..4c4787ed5b 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -988,6 +988,7 @@ struct peer {
#define PEER_FLAG_WEIGHT (1 << 24) /* weight */
#define PEER_FLAG_ALLOWAS_IN_ORIGIN (1 << 25) /* allowas-in origin */
#define PEER_FLAG_SEND_LARGE_COMMUNITY (1 << 26) /* Send large Communities */
+#define PEER_FLAG_MAX_PREFIX_OUT (1 << 27) /* outgoing maximum prefix */
enum bgp_addpath_strat addpath_type[AFI_MAX][SAFI_MAX];
@@ -1120,9 +1121,6 @@ struct peer {
/* timestamp when the last msg was written */
_Atomic time_t last_update;
- /* Send prefix count. */
- unsigned long scount[AFI_MAX][SAFI_MAX];
-
/* Notify data. */
struct bgp_notify notify;
@@ -1173,6 +1171,9 @@ struct peer {
uint16_t pmax_restart[AFI_MAX][SAFI_MAX];
#define MAXIMUM_PREFIX_THRESHOLD_DEFAULT 75
+ /* Send prefix count. */
+ uint32_t pmax_out[AFI_MAX][SAFI_MAX];
+
/* allowas-in. */
char allowas_in[AFI_MAX][SAFI_MAX];
diff --git a/bgpd/subdir.am b/bgpd/subdir.am
index 203cf779b9..ff15248a98 100644
--- a/bgpd/subdir.am
+++ b/bgpd/subdir.am
@@ -46,7 +46,7 @@ endif
if BGP_BMP
module_LTLIBRARIES += bgpd/bgpd_bmp.la
endif
-man8 += $(MANBUILD)/bgpd.8
+man8 += $(MANBUILD)/frr-bgpd.8
endif
bgpd_libbgp_a_SOURCES = \
diff --git a/configure.ac b/configure.ac
index 0694e3ed2c..c8371f304e 100755
--- a/configure.ac
+++ b/configure.ac
@@ -7,7 +7,7 @@
##
AC_PREREQ([2.60])
-AC_INIT([frr], [7.3-dev], [https://github.com/frrouting/frr/issues])
+AC_INIT([frr], [7.4-dev], [https://github.com/frrouting/frr/issues])
PACKAGE_URL="https://frrouting.org/"
AC_SUBST([PACKAGE_URL])
PACKAGE_FULLNAME="FRRouting"
@@ -30,7 +30,7 @@ build_clippy="true"
dnl case 1: external clippy
if test -n "$with_clippy" -a "$with_clippy" != "no" -a "$with_clippy" != "yes"; then
- if test "$enable_clippy_only" == "yes"; then
+ if test "$enable_clippy_only" = "yes"; then
AC_MSG_ERROR([--enable-clippy-only does not make sense with --with-clippy])
fi
@@ -249,7 +249,18 @@ if test "x${enable_gcov}" = "xyes"; then
fi
LDFLAGS="${LDFLAGS} -lgcov"
-elif test "x${enable_dev_build}" = "xyes"; then
+fi
+
+if test "x${enable_clang_coverage}" = "xyes"; then
+ AC_C_FLAG([-fprofile-instr-generate], [
+ AC_MSG_ERROR([$CC does not support -fprofile-instr-generate.])
+ ])
+ AC_C_FLAG([-fcoverage-mapping], [
+ AC_MSG_ERROR([$CC does not support -fcoverage-mapping.])
+ ])
+fi
+
+if test "x${enable_dev_build}" = "xyes"; then
AC_DEFINE([DEV_BUILD], [1], [Build for development])
if test "z$orig_cflags" = "z"; then
AC_C_FLAG([-g3])
@@ -574,7 +585,9 @@ AC_ARG_ENABLE([clippy-only],
AC_ARG_ENABLE([numeric_version],
AS_HELP_STRING([--enable-numeric-version], [Only numeric digits allowed in version (for Alpine)]))
AC_ARG_ENABLE([gcov],
- AS_HELP_STRING([--enable-gcov], [Add code coverage information]))
+ AS_HELP_STRING([--enable-gcov], [Collect coverage information with gcov]))
+AC_ARG_ENABLE([clang_coverage],
+ AS_HELP_STRING([--enable-clang-coverage], [Collect coverage information with Clang Coverage]))
AC_ARG_ENABLE([bfdd],
AS_HELP_STRING([--disable-bfdd], [do not build bfdd]))
AC_ARG_ENABLE([address-sanitizer],
@@ -2100,6 +2113,19 @@ if test x"${enable_backtrace}" != x"no" ; then
AC_DEFINE([HAVE_LIBUNWIND], [1], [libunwind])
backtrace_ok=yes
], [
+ true
+ ])
+
+ if test "$backtrace_ok" = "no"; then
+ AC_CHECK_HEADER([unwind.h], [
+ AC_SEARCH_LIBS([unw_getcontext], [unwind], [
+ AC_DEFINE([HAVE_LIBUNWIND], [1], [libunwind])
+ backtrace_ok=yes
+ ])
+ ])
+ fi
+
+ if test "$backtrace_ok" = "no"; then
case "$host_os" in
sunos* | solaris2*)
AC_CHECK_FUNCS([printstack], [
@@ -2116,7 +2142,7 @@ if test x"${enable_backtrace}" != x"no" ; then
],, [-lm])
])
fi
- ])
+ fi
if test x"${enable_backtrace}" = x"yes" -a x"${backtrace_ok}" = x"no"; then
dnl user explicitly requested backtrace but we failed to find support
diff --git a/debian/frr.logrotate b/debian/frr.logrotate
index 1dc9122ac4..a6b2b22f56 100644
--- a/debian/frr.logrotate
+++ b/debian/frr.logrotate
@@ -17,7 +17,7 @@
# open, as well as the daemons, so always signal the daemons.
# It's safe, a NOP if (only) syslog is being used.
for i in babeld bgpd eigrpd isisd ldpd nhrpd ospf6d ospfd \
- pimd ripd ripngd zebra staticd fabricd; do
+ pimd ripd ripngd zebra pbrd staticd bfdd fabricd vrrpd; do
if [ -e /var/run/frr/$i.pid ] ; then
pids="$pids $(cat /var/run/frr/$i.pid)"
fi
diff --git a/debian/frr.manpages b/debian/frr.manpages
index f5aa972304..5075fd763d 100644
--- a/debian/frr.manpages
+++ b/debian/frr.manpages
@@ -1,16 +1,16 @@
+doc/manpages/_build/man/frr-bgpd.8
+doc/manpages/_build/man/frr-eigrpd.8
+doc/manpages/_build/man/frr-fabricd.8
+doc/manpages/_build/man/frr-isisd.8
+doc/manpages/_build/man/frr-ldpd.8
+doc/manpages/_build/man/frr-nhrpd.8
+doc/manpages/_build/man/frr-ospf6d.8
+doc/manpages/_build/man/frr-ospfd.8
+doc/manpages/_build/man/frr-pimd.8
+doc/manpages/_build/man/frr-ripd.8
+doc/manpages/_build/man/frr-ripngd.8
+doc/manpages/_build/man/frr-watchfrr.8
+doc/manpages/_build/man/frr-zebra.8
doc/manpages/_build/man/frr.1
-doc/manpages/_build/man/bgpd.8
-doc/manpages/_build/man/pimd.8
-doc/manpages/_build/man/eigrpd.8
-doc/manpages/_build/man/ldpd.8
-doc/manpages/_build/man/nhrpd.8
-doc/manpages/_build/man/ospf6d.8
-doc/manpages/_build/man/ospfd.8
-doc/manpages/_build/man/ripd.8
-doc/manpages/_build/man/ripngd.8
-doc/manpages/_build/man/vtysh.1
-doc/manpages/_build/man/zebra.8
-doc/manpages/_build/man/isisd.8
-doc/manpages/_build/man/watchfrr.8
doc/manpages/_build/man/mtracebis.8
-doc/manpages/_build/man/fabricd.8
+doc/manpages/_build/man/vtysh.1
diff --git a/doc/developer/building-frr-for-centos6.rst b/doc/developer/building-frr-for-centos6.rst
index 3d9edbe3a1..04c6b922ce 100644
--- a/doc/developer/building-frr-for-centos6.rst
+++ b/doc/developer/building-frr-for-centos6.rst
@@ -213,7 +213,7 @@ Install daemon config file
.. code-block:: shell
- sudo install -p -m 644 redhat/daemons /etc/frr/
+ sudo install -p -m 644 tools/etc/frr/daemons /etc/frr/
sudo chown frr:frr /etc/frr/daemons
Edit /etc/frr/daemons as needed to select the required daemons
@@ -241,12 +241,12 @@ Load the modified sysctl's on the system:
sudo sysctl -p /etc/sysctl.d/90-routing-sysctl.conf
-Add init.d startup files
-^^^^^^^^^^^^^^^^^^^^^^^^
+Add init.d startup file
+^^^^^^^^^^^^^^^^^^^^^^^
.. code-block:: shell
- sudo install -p -m 755 redhat/frr.init /etc/init.d/frr
+ sudo install -p -m 755 tools/frr /etc/init.d/frr
sudo chkconfig --add frr
Enable FRR daemon at startup
diff --git a/doc/developer/building-frr-for-centos7.rst b/doc/developer/building-frr-for-centos7.rst
index cd90d41ffb..eb97150d67 100644
--- a/doc/developer/building-frr-for-centos7.rst
+++ b/doc/developer/building-frr-for-centos7.rst
@@ -104,7 +104,7 @@ Install daemon config file
::
- sudo install -p -m 644 redhat/daemons /etc/frr/
+ sudo install -p -m 644 tools/etc/frr/daemons /etc/frr/
sudo chown frr:frr /etc/frr/daemons
Edit /etc/frr/daemons as needed to select the required daemons
@@ -133,13 +133,12 @@ Load the modified sysctl's on the system:
sudo sysctl -p /etc/sysctl.d/90-routing-sysctl.conf
-Install frr Service and redhat init files
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Install frr Service
+^^^^^^^^^^^^^^^^^^^
::
- sudo install -p -m 644 redhat/frr.service /usr/lib/systemd/system/frr.service
- sudo install -p -m 755 redhat/frr.init /usr/lib/frr/frr
+ sudo install -p -m 644 tools/frr.service /usr/lib/systemd/system/frr.service
Register the systemd files
^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/doc/developer/building-frr-for-centos8.rst b/doc/developer/building-frr-for-centos8.rst
index 7751482b19..75beb53378 100644
--- a/doc/developer/building-frr-for-centos8.rst
+++ b/doc/developer/building-frr-for-centos8.rst
@@ -97,7 +97,7 @@ Install daemon config file
::
- sudo install -p -m 644 redhat/daemons /etc/frr/
+ sudo install -p -m 644 tools/etc/frr/daemons /etc/frr/
sudo chown frr:frr /etc/frr/daemons
Edit /etc/frr/daemons as needed to select the required daemons
@@ -126,13 +126,12 @@ Load the modified sysctl's on the system:
sudo sysctl -p /etc/sysctl.d/90-routing-sysctl.conf
-Install frr Service and redhat init files
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Install frr Service
+^^^^^^^^^^^^^^^^^^^
::
- sudo install -p -m 644 redhat/frr.service /usr/lib/systemd/system/frr.service
- sudo install -p -m 755 redhat/frr.init /usr/lib/frr/frr
+ sudo install -p -m 644 tools/frr.service /usr/lib/systemd/system/frr.service
Register the systemd files
^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/doc/developer/building-frr-for-fedora.rst b/doc/developer/building-frr-for-fedora.rst
index d8405eb351..4ab59490fd 100644
--- a/doc/developer/building-frr-for-fedora.rst
+++ b/doc/developer/building-frr-for-fedora.rst
@@ -110,13 +110,12 @@ And load the kernel modules on the running system:
sudo systemctl stop firewalld.service
sudo iptables -F
-Install service files
-^^^^^^^^^^^^^^^^^^^^^
+Install frr Service
+^^^^^^^^^^^^^^^^^^^
.. code-block:: console
- sudo install -p -m 644 redhat/frr.service /usr/lib/systemd/system/frr.service
- sudo install -p -m 755 redhat/frr.init /usr/lib/frr/frr
+ sudo install -p -m 644 tools/frr.service /usr/lib/systemd/system/frr.service
sudo systemctl enable frr
Enable daemons
diff --git a/doc/developer/building.rst b/doc/developer/building.rst
index b99667124f..859f612313 100644
--- a/doc/developer/building.rst
+++ b/doc/developer/building.rst
@@ -7,6 +7,7 @@ Building FRR
.. toctree::
:maxdepth: 2
+ static-linking
building-frr-for-alpine
building-frr-for-centos6
building-frr-for-centos7
diff --git a/doc/developer/static-linking.rst b/doc/developer/static-linking.rst
new file mode 100644
index 0000000000..bc33207b38
--- /dev/null
+++ b/doc/developer/static-linking.rst
@@ -0,0 +1,98 @@
+.. _static-linking:
+
+Static Linking
+==============
+
+This document describes how to build FRR without hard dependencies on shared
+libraries. Note that it's not possible to build FRR *completely* statically.
+This document just covers how to statically link the dependencies that aren't
+likely to be present on a given platform - libfrr and libyang. The resultant
+binaries should still be fairly portable. For example, here is the DSO
+dependency list for `bgpd` after using these steps:
+
+.. code-block::
+
+ $ ldd bgpd
+ linux-vdso.so.1 (0x00007ffe3a989000)
+ libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f9dc10c0000)
+ libcap.so.2 => /lib/x86_64-linux-gnu/libcap.so.2 (0x00007f9dc0eba000)
+ libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9dc0b1c000)
+ libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f9dc0918000)
+ libcrypt.so.1 => /lib/x86_64-linux-gnu/libcrypt.so.1 (0x00007f9dc06e0000)
+ libjson-c.so.3 => /lib/x86_64-linux-gnu/libjson-c.so.3 (0x00007f9dc04d5000)
+ librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f9dc02cd000)
+ libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f9dc00ae000)
+ libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f9dbfe96000)
+ libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9dbfaa5000)
+ /lib64/ld-linux-x86-64.so.2 (0x00007f9dc1449000)
+
+Procedure
+---------
+Note that these steps have only been tested with LLVM 9 / clang.
+
+Today, libfrr can already be statically linked by passing these configure
+options::
+
+ --enable-static --enable-static-bin --enable-shared
+
+libyang is more complicated. You must build and install libyang as a static
+library. To do this, follow the usual libyang build procedure as listed in the
+FRR developer docs, but set the ``ENABLE_STATIC`` option in your cmake
+invocation. You also need to build with PIC enabled, which today is disabled
+when building libyang statically.
+
+The resultant cmake command is::
+
+ cmake -DENABLE_STATIC=ON -DENABLE_LYD_PRIV=ON \
+ -DCMAKE_INSTALL_PREFIX:PATH=/usr \
+ -DCMAKE_POSITION_INDEPENDENT_CODE=TRUE \
+ -DCMAKE_BUILD_TYPE:String="Release" ..
+
+This produces a bunch of ``.a`` static archives that need to ultimately be linked
+into FRR. However, not only is it 6 archives rather than the usual ``libyang.so``,
+you will now also need to link FRR with ``libpcre.a``. Ubuntu's ``libpcre3-dev``
+package provides this, but it hasn't been built with PIC enabled, so it's not
+usable for our purposes. So download ``libpcre`` from
+`SourceForge <https://sourceforge.net/projects/pcre/>`_, and build it
+like this:
+
+.. code-block::
+
+ ./configure --with-pic
+ make
+
+Hopefully you get a nice, usable, PIC ``libpcre.a``.
+
+So now we have to link all these static libraries into FRR. Rather than modify
+FRR to accomodate this, the best option is to create an archive with all of
+libyang's dependencies. Then to avoid making any changes to FRR build foo,
+rename this ``libyang.a`` and copy it over the usual static library location.
+Ugly but it works. To do this, go into your libyang build directory, which
+should have a bunch of ``.a`` files. Copy ``libpcre.a`` into this directory.
+Write the following into a shell script and run it:
+
+.. code-block:: shell
+
+ #!/bin/bash
+ ar -M <<EOM
+ CREATE libyang_fat.a
+ ADDLIB libyang.a
+ ADDLIB libyangdata.a
+ ADDLIB libmetadata.a
+ ADDLIB libnacm.a
+ ADDLIB libuser_inet_types.a
+ ADDLIB libuser_yang_types.a
+ ADDLIB libpcre.a
+ SAVE
+ END
+ EOM
+ ranlib libyang_fat.a
+
+``libyang_fat.a`` is your archive. Now copy this over your install
+``libyang.a``, which on my machine is located at
+``/usr/lib/x86_64-linux-gnu/libyang.a`` (try ``locate libyang.a`` if not).
+
+Now when you build FRR with the static options enabled as above, clang should
+pick up the static libyang and link it, leaving you with FRR binaries that have
+no hard DSO dependencies beyond common system libraries. To verify, run ``ldd``
+over the resultant binaries.
diff --git a/doc/developer/subdir.am b/doc/developer/subdir.am
index 2c49d6b875..791f7679a6 100644
--- a/doc/developer/subdir.am
+++ b/doc/developer/subdir.am
@@ -44,6 +44,7 @@ dev_RSTFILES = \
doc/developer/packaging-redhat.rst \
doc/developer/packaging.rst \
doc/developer/rcu.rst \
+ doc/developer/static-linking.rst \
doc/developer/testing.rst \
doc/developer/topotests-snippets.rst \
doc/developer/topotests.rst \
diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst
index c2e72e2ec5..33ebe06d2f 100644
--- a/doc/developer/topotests.rst
+++ b/doc/developer/topotests.rst
@@ -79,6 +79,7 @@ If you prefer to manually build FRR, then use the following suggested config:
--sysconfdir=/etc/frr \
--enable-vtysh \
--enable-pimd \
+ --enable-sharpd \
--enable-multipath=64 \
--enable-user=frr \
--enable-group=frr \
diff --git a/doc/manpages/conf.py b/doc/manpages/conf.py
index e7813d8176..9121d38fe0 100644
--- a/doc/manpages/conf.py
+++ b/doc/manpages/conf.py
@@ -313,28 +313,28 @@ latex_documents = [
fwfrr = "{0} routing engine for use with FRRouting."
man_pages = [
- ('bgpd', 'bgpd', fwfrr.format("a BGPv4, BGPv4+, BGPv4- "), [], 8),
- ('eigrpd', 'eigrpd', fwfrr.format("an EIGRP "), [], 8),
- ('ospf6d', 'ospf6d', fwfrr.format("an OSPFv3 "), [], 8),
- ('ospfd', 'ospfd', fwfrr.format("an OSPFv2 "), [], 8),
- ('isisd', 'isisd', fwfrr.format("an IS-IS "), [], 8),
- ('ospfclient', 'ospfclient', 'an example ospf-api client', [], 8),
- ('ldpd', 'ldpd', fwfrr.format("an LDP "), [], 8),
- ('nhrpd', 'nhrpd', fwfrr.format("a Next Hop Routing Protocol "), [], 8),
- ('pimd', 'pimd', fwfrr.format("a PIM "), [], 8),
- ('pbrd', 'pbrd', fwfrr.format("a PBR "), [], 8),
- ('sharpd', 'sharpd', fwfrr.format("a SHARP "), [], 8),
- ('staticd', 'staticd', fwfrr.format("a static route manager "), [], 8),
- ('mtracebis', 'mtracebis', "a multicast trace client", [], 8),
- ('ripd', 'ripd', fwfrr.format("a RIP "), [], 8),
- ('ripngd', 'ripngd', fwfrr.format("a RIPNG "), [], 8),
- ('zebra', 'zebra', 'a routing manager for use with associated FRRouting components.', [], 8),
- ('watchfrr', 'watchfrr', 'a program to monitor the status of FRRouting daemons', [], 8),
- ('vtysh', 'vtysh', 'an integrated shell for FRRouting.', [], 1),
+ ('frr-bfdd', 'frr-bfdd', fwfrr.format("a bfd"), [], 8),
+ ('frr-bgpd', 'frr-bgpd', fwfrr.format("a BGPv4, BGPv4+, BGPv4-"), [], 8),
+ ('frr-eigrpd', 'frr-eigrpd', fwfrr.format("an EIGRP"), [], 8),
+ ('frr-fabricd', 'frr-fabricd', fwfrr.format("an OpenFabric"), [], 8),
+ ('frr-isisd', 'frr-isisd', fwfrr.format("an IS-IS"), [], 8),
+ ('frr-ldpd', 'frr-ldpd', fwfrr.format("an LDP"), [], 8),
+ ('frr-nhrpd', 'frr-nhrpd', fwfrr.format("a Next Hop Routing Protocol"), [], 8),
+ ('frr-ospf6d', 'frr-ospf6d', fwfrr.format("an OSPFv3"), [], 8),
+ ('frr-ospfclient', 'frr-ospfclient', 'an example ospf-api client', [], 8),
+ ('frr-ospfd', 'frr-ospfd', fwfrr.format("an OSPFv2"), [], 8),
+ ('frr-pbrd', 'frr-pbrd', fwfrr.format("a PBR"), [], 8),
+ ('frr-pimd', 'frr-pimd', fwfrr.format("a PIM"), [], 8),
+ ('frr-ripd', 'frr-ripd', fwfrr.format("a RIP"), [], 8),
+ ('frr-ripngd', 'frr-ripngd', fwfrr.format("a RIPNG"), [], 8),
+ ('frr-sharpd', 'frr-sharpd', fwfrr.format("a SHARP"), [], 8),
+ ('frr-staticd', 'frr-staticd', fwfrr.format("a static route manager"), [], 8),
+ ('frr-vrrpd', 'frr-vrrpd', fwfrr.format("a VRRP"), [], 8),
+ ('frr-watchfrr', 'frr-watchfrr', 'a program to monitor the status of FRRouting daemons', [], 8),
+ ('frr-zebra', 'frr-zebra', 'a routing manager for use with associated FRRouting components.', [], 8),
('frr', 'frr', 'a systemd interaction script', [], 1),
- ('bfdd', 'bfdd', fwfrr.format("a bfd"), [], 8),
- ('fabricd', 'fabricd', fwfrr.format("an OpenFabric "), [], 8),
- ('vrrpd', 'vrrpd', fwfrr.format("a VRRP"), [], 8),
+ ('mtracebis', 'mtracebis', "a multicast trace client", [], 8),
+ ('vtysh', 'vtysh', 'an integrated shell for FRRouting.', [], 1),
]
# -- Options for Texinfo output -------------------------------------------
diff --git a/doc/manpages/defines.rst b/doc/manpages/defines.rst
index 2a6a9fd1bd..ac24cfa8dc 100644
--- a/doc/manpages/defines.rst
+++ b/doc/manpages/defines.rst
@@ -1,3 +1,3 @@
.. |synopsis-options| replace:: [-d|-t|-dt] [-C] [-f config-file] [-i pid-file] [-z zclient-path] [-u user] [-g group] [-A vty-addr] [-P vty-port] [-M module[:options]] [-N pathspace] [--vty_socket vty-path] [--moduledir module-path]
.. |synopsis-options-hv| replace:: [-h] [-v]
-.. |seealso-programs| replace:: zebra(8), vtysh(1), ripd(8), ripngd(8), ospfd(8), ospf6d(8), bgpd(8), isisd(8), babeld(8), nhrpd(8), pimd(8), pbrd(8), ldpd(8), eigrpd(8), staticd(8), fabricd(8), vrrpd(8), mtracebis(8)
+.. |seealso-programs| replace:: frr-zebra(8), vtysh(1), frr-ripd(8), frr-ripngd(8), frr-ospfd(8), frr-ospf6d(8), frr-bgpd(8), frr-isisd(8), frr-babeld(8), frr-nhrpd(8), frr-pimd(8), frr-pbrd(8), frr-ldpd(8), frr-eigrpd(8), frr-staticd(8), frr-fabricd(8), frr-vrrpd(8), mtracebis(8)
diff --git a/doc/manpages/bfdd.rst b/doc/manpages/frr-bfdd.rst
index 1f8b1475f4..1f8b1475f4 100644
--- a/doc/manpages/bfdd.rst
+++ b/doc/manpages/frr-bfdd.rst
diff --git a/doc/manpages/bgpd.rst b/doc/manpages/frr-bgpd.rst
index f7e20265e5..f7e20265e5 100644
--- a/doc/manpages/bgpd.rst
+++ b/doc/manpages/frr-bgpd.rst
diff --git a/doc/manpages/eigrpd.rst b/doc/manpages/frr-eigrpd.rst
index bc824468d0..bc824468d0 100644
--- a/doc/manpages/eigrpd.rst
+++ b/doc/manpages/frr-eigrpd.rst
diff --git a/doc/manpages/fabricd.rst b/doc/manpages/frr-fabricd.rst
index c14c07661e..c14c07661e 100644
--- a/doc/manpages/fabricd.rst
+++ b/doc/manpages/frr-fabricd.rst
diff --git a/doc/manpages/isisd.rst b/doc/manpages/frr-isisd.rst
index 68761f642c..68761f642c 100644
--- a/doc/manpages/isisd.rst
+++ b/doc/manpages/frr-isisd.rst
diff --git a/doc/manpages/ldpd.rst b/doc/manpages/frr-ldpd.rst
index 113f06673e..113f06673e 100644
--- a/doc/manpages/ldpd.rst
+++ b/doc/manpages/frr-ldpd.rst
diff --git a/doc/manpages/nhrpd.rst b/doc/manpages/frr-nhrpd.rst
index cae01c677b..cae01c677b 100644
--- a/doc/manpages/nhrpd.rst
+++ b/doc/manpages/frr-nhrpd.rst
diff --git a/doc/manpages/ospf6d.rst b/doc/manpages/frr-ospf6d.rst
index cfc6860d5c..cfc6860d5c 100644
--- a/doc/manpages/ospf6d.rst
+++ b/doc/manpages/frr-ospf6d.rst
diff --git a/doc/manpages/ospfclient.rst b/doc/manpages/frr-ospfclient.rst
index c52b108767..c52b108767 100644
--- a/doc/manpages/ospfclient.rst
+++ b/doc/manpages/frr-ospfclient.rst
diff --git a/doc/manpages/ospfd.rst b/doc/manpages/frr-ospfd.rst
index 951a0229aa..951a0229aa 100644
--- a/doc/manpages/ospfd.rst
+++ b/doc/manpages/frr-ospfd.rst
diff --git a/doc/manpages/pbrd.rst b/doc/manpages/frr-pbrd.rst
index d9a80b1f84..d9a80b1f84 100644
--- a/doc/manpages/pbrd.rst
+++ b/doc/manpages/frr-pbrd.rst
diff --git a/doc/manpages/pimd.rst b/doc/manpages/frr-pimd.rst
index d7582668d2..d7582668d2 100644
--- a/doc/manpages/pimd.rst
+++ b/doc/manpages/frr-pimd.rst
diff --git a/doc/manpages/ripd.rst b/doc/manpages/frr-ripd.rst
index af4590c824..af4590c824 100644
--- a/doc/manpages/ripd.rst
+++ b/doc/manpages/frr-ripd.rst
diff --git a/doc/manpages/ripngd.rst b/doc/manpages/frr-ripngd.rst
index aedd689876..aedd689876 100644
--- a/doc/manpages/ripngd.rst
+++ b/doc/manpages/frr-ripngd.rst
diff --git a/doc/manpages/sharpd.rst b/doc/manpages/frr-sharpd.rst
index 016f3f9254..016f3f9254 100644
--- a/doc/manpages/sharpd.rst
+++ b/doc/manpages/frr-sharpd.rst
diff --git a/doc/manpages/staticd.rst b/doc/manpages/frr-staticd.rst
index ccbcf32e36..ccbcf32e36 100644
--- a/doc/manpages/staticd.rst
+++ b/doc/manpages/frr-staticd.rst
diff --git a/doc/manpages/vrrpd.rst b/doc/manpages/frr-vrrpd.rst
index 0e73b07cda..0e73b07cda 100644
--- a/doc/manpages/vrrpd.rst
+++ b/doc/manpages/frr-vrrpd.rst
diff --git a/doc/manpages/watchfrr.rst b/doc/manpages/frr-watchfrr.rst
index dceb423f82..dceb423f82 100644
--- a/doc/manpages/watchfrr.rst
+++ b/doc/manpages/frr-watchfrr.rst
diff --git a/doc/manpages/zebra.rst b/doc/manpages/frr-zebra.rst
index cfb368bf44..cfb368bf44 100644
--- a/doc/manpages/zebra.rst
+++ b/doc/manpages/frr-zebra.rst
diff --git a/doc/manpages/index.rst b/doc/manpages/index.rst
index 40f06efdfe..58a1d9e0db 100644
--- a/doc/manpages/index.rst
+++ b/doc/manpages/index.rst
@@ -6,25 +6,25 @@
.. toctree::
:maxdepth: 2
- bfdd
- bgpd
- eigrpd
- isisd
- fabricd
- ldpd
- nhrpd
- ospf6d
- ospfclient
- ospfd
- pimd
- pbrd
+ frr
+ frr-bfdd
+ frr-bgpd
+ frr-eigrpd
+ frr-isisd
+ frr-fabricd
+ frr-ldpd
+ frr-nhrpd
+ frr-ospf6d
+ frr-ospfclient
+ frr-ospfd
+ frr-pimd
+ frr-pbrd
+ frr-ripd
+ frr-ripngd
+ frr-sharpd
+ frr-staticd
+ frr-watchfrr
+ frr-zebra
+ frr-vrrpd
mtracebis
- ripd
- ripngd
- sharpd
- staticd
- watchfrr
- zebra
vtysh
- vrrpd
- frr
diff --git a/doc/manpages/subdir.am b/doc/manpages/subdir.am
index 19d2d8d6ae..9284212099 100644
--- a/doc/manpages/subdir.am
+++ b/doc/manpages/subdir.am
@@ -3,34 +3,34 @@
#
man_RSTFILES = \
- doc/manpages/bgpd.rst \
+ doc/manpages/bfd-options.rst \
doc/manpages/common-options.rst \
doc/manpages/conf.py \
doc/manpages/defines.rst \
- doc/manpages/eigrpd.rst \
doc/manpages/epilogue.rst \
- doc/manpages/fabricd.rst \
+ doc/manpages/frr-bfdd.rst \
+ doc/manpages/frr-bgpd.rst \
+ doc/manpages/frr-eigrpd.rst \
+ doc/manpages/frr-fabricd.rst \
+ doc/manpages/frr-isisd.rst \
+ doc/manpages/frr-ldpd.rst \
+ doc/manpages/frr-nhrpd.rst \
+ doc/manpages/frr-ospf6d.rst \
+ doc/manpages/frr-ospfclient.rst \
+ doc/manpages/frr-ospfd.rst \
+ doc/manpages/frr-pbrd.rst \
+ doc/manpages/frr-pimd.rst \
+ doc/manpages/frr-ripd.rst \
+ doc/manpages/frr-ripngd.rst \
+ doc/manpages/frr-sharpd.rst \
+ doc/manpages/frr-staticd.rst \
+ doc/manpages/frr-vrrpd.rst \
+ doc/manpages/frr-watchfrr.rst \
+ doc/manpages/frr-zebra.rst \
doc/manpages/frr.rst \
doc/manpages/index.rst \
- doc/manpages/isisd.rst \
- doc/manpages/ldpd.rst \
doc/manpages/mtracebis.rst \
- doc/manpages/nhrpd.rst \
- doc/manpages/ospf6d.rst \
- doc/manpages/ospfclient.rst \
- doc/manpages/ospfd.rst \
- doc/manpages/pimd.rst \
- doc/manpages/ripd.rst \
- doc/manpages/pbrd.rst \
- doc/manpages/ripngd.rst \
- doc/manpages/sharpd.rst \
- doc/manpages/staticd.rst \
doc/manpages/vtysh.rst \
- doc/manpages/watchfrr.rst \
- doc/manpages/zebra.rst \
- doc/manpages/bfdd.rst \
- doc/manpages/bfd-options.rst \
- doc/manpages/vrrpd.rst \
# end
EXTRA_DIST += $(man_RSTFILES)
diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst
index b3fc7f15a6..e6a3c4977a 100644
--- a/doc/user/bfd.rst
+++ b/doc/user/bfd.rst
@@ -476,3 +476,13 @@ You can also clear packet counters per session with the following commands, only
Session down events: 0
Zebra notifications: 4
+Logging / debugging
+===================
+
+There are no fine grained debug controls for bfdd. Just enable debug logs.
+
+::
+
+ config
+ log file /var/log/frr/frr.log debugging
+ log syslog debugging
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 2d4d0c4945..d3ac4b22ab 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -1075,6 +1075,11 @@ Configuring Peers
granular and offers much smarter matching criterion than number of received
prefixes, making it more suited to implementing policy.
+.. index:: [no] neighbor PEER maximum-prefix-out NUMBER
+.. clicmd:: [no] neighbor PEER maximum-prefix-out NUMBER
+
+ Sets a maximum number of prefixes we can send to a given peer.
+
.. index:: [no] neighbor PEER local-as AS-NUMBER [no-prepend] [replace-as]
.. clicmd:: [no] neighbor PEER local-as AS-NUMBER [no-prepend] [replace-as]
diff --git a/eigrpd/subdir.am b/eigrpd/subdir.am
index 5a65c654e9..e59c88b471 100644
--- a/eigrpd/subdir.am
+++ b/eigrpd/subdir.am
@@ -12,7 +12,7 @@ vtysh_scan += \
$(top_srcdir)/eigrpd/eigrp_vty.c \
# end
# $(top_srcdir)/eigrpd/eigrp_routemap.c
-man8 += $(MANBUILD)/eigrpd.8
+man8 += $(MANBUILD)/frr-eigrpd.8
endif
eigrpd_libeigrp_a_SOURCES = \
diff --git a/isisd/subdir.am b/isisd/subdir.am
index e77fef41dd..5dddb7d345 100644
--- a/isisd/subdir.am
+++ b/isisd/subdir.am
@@ -14,7 +14,7 @@ vtysh_scan += \
$(top_srcdir)/isisd/isis_vty_fabricd.c \
$(top_srcdir)/isisd/isisd.c \
# end
-man8 += $(MANBUILD)/isisd.8
+man8 += $(MANBUILD)/frr-isisd.8
endif
if FABRICD
diff --git a/ldpd/subdir.am b/ldpd/subdir.am
index 42c5ad024b..f464bad9e7 100644
--- a/ldpd/subdir.am
+++ b/ldpd/subdir.am
@@ -7,7 +7,7 @@ noinst_LIBRARIES += ldpd/libldp.a
sbin_PROGRAMS += ldpd/ldpd
dist_examples_DATA += ldpd/ldpd.conf.sample
vtysh_scan += $(top_srcdir)/ldpd/ldp_vty_cmds.c
-man8 += $(MANBUILD)/ldpd.8
+man8 += $(MANBUILD)/frr-ldpd.8
endif
ldpd_libldp_a_SOURCES = \
diff --git a/lib/gitversion.pl b/lib/gitversion.pl
index 2718046d0b..dd25c8976a 100644
--- a/lib/gitversion.pl
+++ b/lib/gitversion.pl
@@ -6,7 +6,7 @@ chdir $dir || die "$dir: $!\n";
my $gitdesc = `git describe --always --first-parent --tags --dirty --match 'frr-*' || echo -- \"0-gUNKNOWN\"`;
chomp $gitdesc;
-my $gitsuffix = ($gitdesc =~ /([0-9a-fA-F]{7}(-dirty)?)$/) ? "-g$1" : "-gUNKNOWN";
+my $gitsuffix = ($gitdesc =~ /-g([0-9a-fA-F]+(-dirty)?)$/) ? "-g$1" : "-gUNKNOWN";
printf STDERR "git suffix: %s\n", $gitsuffix;
printf "#define GIT_SUFFIX \"%s\"\n", $gitsuffix;
diff --git a/lib/log.c b/lib/log.c
index c777868736..798b776d00 100644
--- a/lib/log.c
+++ b/lib/log.c
@@ -1093,6 +1093,7 @@ static const struct zebra_desc_table command_types[] = {
DESC_ENTRY(ZEBRA_VXLAN_SG_ADD),
DESC_ENTRY(ZEBRA_VXLAN_SG_DEL),
DESC_ENTRY(ZEBRA_VXLAN_SG_REPLAY),
+ DESC_ENTRY(ZEBRA_ERROR),
};
#undef DESC_ENTRY
diff --git a/lib/nexthop.c b/lib/nexthop.c
index d2ab70e209..e23f8b0792 100644
--- a/lib/nexthop.c
+++ b/lib/nexthop.c
@@ -34,6 +34,7 @@
#include "jhash.h"
#include "printfrr.h"
#include "vrf.h"
+#include "nexthop_group.h"
DEFINE_MTYPE_STATIC(LIB, NEXTHOP, "Nexthop")
DEFINE_MTYPE_STATIC(LIB, NH_LABEL, "Nexthop label")
@@ -565,8 +566,9 @@ uint32_t nexthop_hash(const struct nexthop *nexthop)
return key;
}
-void nexthop_copy(struct nexthop *copy, const struct nexthop *nexthop,
- struct nexthop *rparent)
+void nexthop_copy_no_recurse(struct nexthop *copy,
+ const struct nexthop *nexthop,
+ struct nexthop *rparent)
{
copy->vrf_id = nexthop->vrf_id;
copy->ifindex = nexthop->ifindex;
@@ -583,6 +585,28 @@ void nexthop_copy(struct nexthop *copy, const struct nexthop *nexthop,
&nexthop->nh_label->label[0]);
}
+void nexthop_copy(struct nexthop *copy, const struct nexthop *nexthop,
+ struct nexthop *rparent)
+{
+ nexthop_copy_no_recurse(copy, nexthop, rparent);
+
+ /* Bit of a special case here, we need to handle the case
+ * of a nexthop resolving to agroup. Hence, we need to
+ * use a nexthop_group API.
+ */
+ if (CHECK_FLAG(copy->flags, NEXTHOP_FLAG_RECURSIVE))
+ copy_nexthops(&copy->resolved, nexthop->resolved, copy);
+}
+
+struct nexthop *nexthop_dup_no_recurse(const struct nexthop *nexthop,
+ struct nexthop *rparent)
+{
+ struct nexthop *new = nexthop_new();
+
+ nexthop_copy_no_recurse(new, nexthop, rparent);
+ return new;
+}
+
struct nexthop *nexthop_dup(const struct nexthop *nexthop,
struct nexthop *rparent)
{
diff --git a/lib/nexthop.h b/lib/nexthop.h
index 040b643a84..cb5efe00cc 100644
--- a/lib/nexthop.h
+++ b/lib/nexthop.h
@@ -187,9 +187,16 @@ extern unsigned int nexthop_level(struct nexthop *nexthop);
/* Copies to an already allocated nexthop struct */
extern void nexthop_copy(struct nexthop *copy, const struct nexthop *nexthop,
struct nexthop *rparent);
+/* Copies to an already allocated nexthop struct, not including recurse info */
+extern void nexthop_copy_no_recurse(struct nexthop *copy,
+ const struct nexthop *nexthop,
+ struct nexthop *rparent);
/* Duplicates a nexthop and returns the newly allocated nexthop */
extern struct nexthop *nexthop_dup(const struct nexthop *nexthop,
struct nexthop *rparent);
+/* Duplicates a nexthop and returns the newly allocated nexthop */
+extern struct nexthop *nexthop_dup_no_recurse(const struct nexthop *nexthop,
+ struct nexthop *rparent);
#ifdef __cplusplus
}
diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c
index 0051cba625..3005a51c71 100644
--- a/lib/nexthop_group.c
+++ b/lib/nexthop_group.c
@@ -250,8 +250,7 @@ static void _nexthop_add_sorted(struct nexthop **head,
{
struct nexthop *position, *prev;
- /* Ensure this gets set */
- nexthop->next = NULL;
+ assert(!nexthop->next);
for (position = *head, prev = NULL; position;
prev = position, position = position->next) {
@@ -281,6 +280,8 @@ void nexthop_group_add_sorted(struct nexthop_group *nhg,
{
struct nexthop *tail;
+ assert(!nexthop->next);
+
/* Try to just append to the end first;
* trust the list is already sorted
*/
@@ -363,10 +364,6 @@ void copy_nexthops(struct nexthop **tnh, const struct nexthop *nh,
for (nh1 = nh; nh1; nh1 = nh1->next) {
nexthop = nexthop_dup(nh1, rparent);
_nexthop_add(tnh, nexthop);
-
- if (CHECK_FLAG(nh1->flags, NEXTHOP_FLAG_RECURSIVE))
- copy_nexthops(&nexthop->resolved, nh1->resolved,
- nexthop);
}
}
diff --git a/lib/zclient.c b/lib/zclient.c
index fd1b181e58..b2c74cd0b9 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -143,6 +143,18 @@ void redist_del_instance(struct redist_proto *red, unsigned short instance)
}
}
+void redist_del_all_instances(struct redist_proto *red)
+{
+ struct listnode *ln, *nn;
+ unsigned short *id;
+
+ if (!red->instances)
+ return;
+
+ for (ALL_LIST_ELEMENTS(red->instances, ln, nn, id))
+ redist_del_instance(red, *id);
+}
+
/* Stop zebra client services. */
void zclient_stop(struct zclient *zclient)
{
@@ -899,8 +911,6 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh,
stream_putc(s, api_nh->bh_type);
break;
case NEXTHOP_TYPE_IPV4:
- stream_put_in_addr(s, &api_nh->gate.ipv4);
- break;
case NEXTHOP_TYPE_IPV4_IFINDEX:
stream_put_in_addr(s, &api_nh->gate.ipv4);
stream_putl(s, api_nh->ifindex);
@@ -909,9 +919,6 @@ int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh,
stream_putl(s, api_nh->ifindex);
break;
case NEXTHOP_TYPE_IPV6:
- stream_write(s, (uint8_t *)&api_nh->gate.ipv6,
- 16);
- break;
case NEXTHOP_TYPE_IPV6_IFINDEX:
stream_write(s, (uint8_t *)&api_nh->gate.ipv6,
16);
@@ -1059,9 +1066,6 @@ static int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh,
STREAM_GETC(s, api_nh->bh_type);
break;
case NEXTHOP_TYPE_IPV4:
- STREAM_GET(&api_nh->gate.ipv4.s_addr, s,
- IPV4_MAX_BYTELEN);
- break;
case NEXTHOP_TYPE_IPV4_IFINDEX:
STREAM_GET(&api_nh->gate.ipv4.s_addr, s,
IPV4_MAX_BYTELEN);
@@ -1071,8 +1075,6 @@ static int zapi_nexthop_decode(struct stream *s, struct zapi_nexthop *api_nh,
STREAM_GETL(s, api_nh->ifindex);
break;
case NEXTHOP_TYPE_IPV6:
- STREAM_GET(&api_nh->gate.ipv6, s, 16);
- break;
case NEXTHOP_TYPE_IPV6_IFINDEX:
STREAM_GET(&api_nh->gate.ipv6, s, 16);
STREAM_GETL(s, api_nh->ifindex);
@@ -1467,6 +1469,21 @@ stream_failure:
return false;
}
+bool zapi_error_decode(struct stream *s, enum zebra_error_types *error)
+{
+ memset(error, 0, sizeof(*error));
+
+ STREAM_GET(error, s, sizeof(*error));
+
+ if (zclient_debug)
+ zlog_debug("%s: type: %s", __func__,
+ zebra_error_type2str(*error));
+
+ return true;
+stream_failure:
+ return false;
+}
+
/*
* send a ZEBRA_REDISTRIBUTE_ADD or ZEBRA_REDISTRIBUTE_DELETE
* for the route type (ZEBRA_ROUTE_KERNEL etc.). The zebra server will
@@ -1706,6 +1723,17 @@ static void zclient_interface_down(struct zclient *zclient, vrf_id_t vrf_id)
if_down_via_zapi(ifp);
}
+static void zclient_handle_error(ZAPI_CALLBACK_ARGS)
+{
+ enum zebra_error_types error;
+ struct stream *s = zclient->ibuf;
+
+ zapi_error_decode(s, &error);
+
+ if (zclient->handle_error)
+ (*zclient->handle_error)(error);
+}
+
static void link_params_set_value(struct stream *s, struct if_link_params *iflp)
{
@@ -3153,6 +3181,8 @@ static int zclient_read(struct thread *thread)
case ZEBRA_MLAG_FORWARD_MSG:
zclient_mlag_handle_msg(command, zclient, length, vrf_id);
break;
+ case ZEBRA_ERROR:
+ zclient_handle_error(command, zclient, length, vrf_id);
default:
break;
}
diff --git a/lib/zclient.h b/lib/zclient.h
index 70304127a2..d1aa42da6d 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -183,8 +183,34 @@ typedef enum {
ZEBRA_MLAG_CLIENT_REGISTER,
ZEBRA_MLAG_CLIENT_UNREGISTER,
ZEBRA_MLAG_FORWARD_MSG,
+ ZEBRA_ERROR,
} zebra_message_types_t;
+enum zebra_error_types {
+ ZEBRA_UNKNOWN_ERROR, /* Error of unknown type */
+ ZEBRA_NO_VRF, /* Vrf in header was not found */
+ ZEBRA_INVALID_MSG_TYPE, /* No handler found for msg type */
+};
+
+static inline const char *zebra_error_type2str(enum zebra_error_types type)
+{
+ const char *ret = "UNKNOWN";
+
+ switch (type) {
+ case ZEBRA_UNKNOWN_ERROR:
+ ret = "ZEBRA_UNKNOWN_ERROR";
+ break;
+ case ZEBRA_NO_VRF:
+ ret = "ZEBRA_NO_VRF";
+ break;
+ case ZEBRA_INVALID_MSG_TYPE:
+ ret = "ZEBRA_INVALID_MSG_TYPE";
+ break;
+ }
+
+ return ret;
+}
+
struct redist_proto {
uint8_t enabled;
struct list *instances;
@@ -280,6 +306,7 @@ struct zclient {
int (*mlag_process_up)(void);
int (*mlag_process_down)(void);
int (*mlag_handle_msg)(struct stream *msg, int len);
+ int (*handle_error)(enum zebra_error_types error);
};
/* Zebra API message flag. */
@@ -547,6 +574,7 @@ extern unsigned short *redist_check_instance(struct redist_proto *,
unsigned short);
extern void redist_add_instance(struct redist_proto *, unsigned short);
extern void redist_del_instance(struct redist_proto *, unsigned short);
+extern void redist_del_all_instances(struct redist_proto *red);
/*
* Send to zebra that the specified vrf is using label to resolve
@@ -728,6 +756,9 @@ int zapi_nexthop_from_nexthop(struct zapi_nexthop *znh,
extern bool zapi_nexthop_update_decode(struct stream *s,
struct zapi_route *nhr);
+/* Decode the zebra error message */
+extern bool zapi_error_decode(struct stream *s, enum zebra_error_types *error);
+
static inline void zapi_route_set_blackhole(struct zapi_route *api,
enum blackhole_type bh_type)
{
diff --git a/m4/ax_python.m4 b/m4/ax_python.m4
index 66338511a3..69809184ee 100644
--- a/m4/ax_python.m4
+++ b/m4/ax_python.m4
@@ -186,7 +186,7 @@ AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
AC_MSG_RESULT([yes])
PYTHON_CFLAGS="`\"$pycfg\" --includes`"
- if test x"${py_ver}" == x"3.8" || test x"{py_ver}" == x"3.9"; then
+ if test x"${py_ver}" = x"3.8" || test x"{py_ver}" = x"3.9"; then
PYTHON_LIBS="`\"$pycfg\" --ldflags --embed`"
else
PYTHON_LIBS="`\"$pycfg\" --ldflags`"
diff --git a/nhrpd/nhrp_peer.c b/nhrpd/nhrp_peer.c
index 3a74b75696..c5e985cdac 100644
--- a/nhrpd/nhrp_peer.c
+++ b/nhrpd/nhrp_peer.c
@@ -896,8 +896,10 @@ void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb)
extoff = htons(hdr->extension_offset);
if (extoff) {
- if (extoff >= realsize) {
- info = "extoff larger than packet";
+ assert(zb->head > zb->buf);
+ uint32_t header_offset = zb->head - zb->buf;
+ if ((extoff >= realsize) || (extoff < (header_offset))) {
+ info = "extoff larger than packet, or smaller than header";
goto drop;
}
paylen = extoff - (zb->head - zb->buf);
diff --git a/nhrpd/subdir.am b/nhrpd/subdir.am
index fe76623ac3..42a6380b17 100644
--- a/nhrpd/subdir.am
+++ b/nhrpd/subdir.am
@@ -5,7 +5,7 @@
if NHRPD
sbin_PROGRAMS += nhrpd/nhrpd
vtysh_scan += $(top_srcdir)/nhrpd/nhrp_vty.c
-man8 += $(MANBUILD)/nhrpd.8
+man8 += $(MANBUILD)/frr-nhrpd.8
endif
nhrpd_nhrpd_LDADD = lib/libfrr.la lib/libfrrcares.la $(LIBCAP)
diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c
index 0828c2beb6..15dbd0716a 100644
--- a/ospf6d/ospf6_flood.c
+++ b/ospf6d/ospf6_flood.c
@@ -842,18 +842,6 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,
zlog_debug("Received is duplicated LSA");
SET_FLAG(new->flag, OSPF6_LSA_DUPLICATE);
}
- if (old->header->adv_router
- == from->ospf6_if->area->ospf6->router_id
- && OSPF6_LSA_IS_MAXAGE(new)) {
- ospf6_acknowledge_lsa(new, ismore_recent, from);
- ospf6_lsa_delete(new);
- if (is_debug)
- zlog_debug(
- "%s: Received is self orig MAXAGE LSA %s, discard (ismore_recent %d)",
- __PRETTY_FUNCTION__, old->name,
- ismore_recent);
- return;
- }
}
/* if no database copy or received is more recent */
diff --git a/ospf6d/subdir.am b/ospf6d/subdir.am
index eac0eee45f..570b077cb1 100644
--- a/ospf6d/subdir.am
+++ b/ospf6d/subdir.am
@@ -26,7 +26,7 @@ vtysh_scan += \
if SNMP
module_LTLIBRARIES += ospf6d/ospf6d_snmp.la
endif
-man8 += $(MANBUILD)/ospf6d.8
+man8 += $(MANBUILD)/frr-ospf6d.8
endif
ospf6d_libospf6_a_SOURCES = \
diff --git a/ospfclient/subdir.am b/ospfclient/subdir.am
index 94d489358c..756ad88f15 100644
--- a/ospfclient/subdir.am
+++ b/ospfclient/subdir.am
@@ -5,7 +5,7 @@
if OSPFCLIENT
lib_LTLIBRARIES += ospfclient/libfrrospfapiclient.la
noinst_PROGRAMS += ospfclient/ospfclient
-man8 += $(MANBUILD)/ospfclient.8
+#man8 += $(MANBUILD)/frr-ospfclient.8
endif
ospfclient_libfrrospfapiclient_la_LDFLAGS = -version-info 0:0:0
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index 152a7e83b7..1542ef88fb 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -9679,7 +9679,7 @@ DEFUN (show_ip_ospf_vrfs,
if (uj)
json_vrf = json_object_new_object();
- if (ospf->vrf_id == 0)
+ if (ospf->vrf_id == VRF_DEFAULT)
name = VRF_DEFAULT_NAME;
else
name = ospf->name;
diff --git a/ospfd/subdir.am b/ospfd/subdir.am
index 48dd741b24..6de4099c5b 100644
--- a/ospfd/subdir.am
+++ b/ospfd/subdir.am
@@ -19,7 +19,7 @@ vtysh_scan += \
if SNMP
module_LTLIBRARIES += ospfd/ospfd_snmp.la
endif
-man8 += $(MANBUILD)/ospfd.8
+man8 += $(MANBUILD)/frr-ospfd.8
endif
ospfd_libfrrospf_a_SOURCES = \
diff --git a/pbrd/subdir.am b/pbrd/subdir.am
index 41d0e5a0b8..c55f0b41cc 100644
--- a/pbrd/subdir.am
+++ b/pbrd/subdir.am
@@ -10,7 +10,7 @@ vtysh_scan += \
$(top_srcdir)/pbrd/pbr_vty.c \
$(top_srcdir)/pbrd/pbr_debug.c \
# end
-man8 += $(MANBUILD)/pbrd.8
+man8 += $(MANBUILD)/frr-pbrd.8
endif
pbrd_libpbr_a_SOURCES = \
diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c
index 77526281d1..0454c0d69e 100644
--- a/pimd/pim_zlookup.c
+++ b/pimd/pim_zlookup.c
@@ -180,6 +180,14 @@ static int zclient_read_nexthop(struct pim_instance *pim,
zclient_lookup_failed(zlookup);
return -1;
}
+
+ if (command == ZEBRA_ERROR) {
+ enum zebra_error_types error;
+
+ zapi_error_decode(s, &error);
+ /* Do nothing with it for now */
+ return -1;
+ }
}
raddr.s_addr = stream_get_ipv4(s);
@@ -338,7 +346,8 @@ static int zclient_lookup_nexthop_once(struct pim_instance *pim,
s = zlookup->obuf;
stream_reset(s);
- zclient_create_header(s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB, pim->vrf_id);
+ zclient_create_header(s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB,
+ pim->vrf->vrf_id);
stream_put_in_addr(s, &addr);
stream_putw_at(s, 0, stream_get_endp(s));
diff --git a/pimd/subdir.am b/pimd/subdir.am
index 5407e566a5..b5d135d032 100644
--- a/pimd/subdir.am
+++ b/pimd/subdir.am
@@ -9,7 +9,7 @@ bin_PROGRAMS += pimd/mtracebis
noinst_PROGRAMS += pimd/test_igmpv3_join
dist_examples_DATA += pimd/pimd.conf.sample
vtysh_scan += $(top_srcdir)/pimd/pim_cmd.c
-man8 += $(MANBUILD)/pimd.8
+man8 += $(MANBUILD)/frr-pimd.8
man8 += $(MANBUILD)/mtracebis.8
endif
diff --git a/ripd/subdir.am b/ripd/subdir.am
index dfdfc88a56..00984672ed 100644
--- a/ripd/subdir.am
+++ b/ripd/subdir.am
@@ -15,7 +15,7 @@ vtysh_scan += \
if SNMP
module_LTLIBRARIES += ripd/ripd_snmp.la
endif
-man8 += $(MANBUILD)/ripd.8
+man8 += $(MANBUILD)/frr-ripd.8
endif
ripd_librip_a_SOURCES = \
diff --git a/ripngd/subdir.am b/ripngd/subdir.am
index 07d0cb892c..4e219c9947 100644
--- a/ripngd/subdir.am
+++ b/ripngd/subdir.am
@@ -10,7 +10,7 @@ vtysh_scan += \
$(top_srcdir)/ripngd/ripng_debug.c \
$(top_srcdir)/ripngd/ripngd.c \
# end
-man8 += $(MANBUILD)/ripngd.8
+man8 += $(MANBUILD)/frr-ripngd.8
endif
ripngd_libripng_a_SOURCES = \
diff --git a/sharpd/subdir.am b/sharpd/subdir.am
index 4a9028f6fe..89b183d832 100644
--- a/sharpd/subdir.am
+++ b/sharpd/subdir.am
@@ -7,7 +7,7 @@ noinst_LIBRARIES += sharpd/libsharp.a
sbin_PROGRAMS += sharpd/sharpd
dist_examples_DATA += sharpd/sharpd.conf.sample
vtysh_scan += $(top_srcdir)/sharpd/sharp_vty.c
-man8 += $(MANBUILD)/sharpd.8
+man8 += $(MANBUILD)/frr-sharpd.8
endif
sharpd_libsharp_a_SOURCES = \
diff --git a/solaris/prototype.doc.in b/solaris/prototype.doc.in
index a8644b3145..9f7995350a 100644
--- a/solaris/prototype.doc.in
+++ b/solaris/prototype.doc.in
@@ -8,10 +8,10 @@ d none @mandir@=$DESTDIR/@mandir@ 0755 root bin
d none @mandir@/man1=$DESTDIR/@mandir@/man1 0755 root bin
f none @mandir@/man1/vtysh.1=$DESTDIR/@mandir@/man1/vtysh.1 0644 root bin
d none @mandir@/man8=$DESTDIR/@mandir@/man8 0755 root bin
-f none @mandir@/man8/bgpd.8=$DESTDIR/@mandir@/man8/bgpd.8 0644 root bin
-f none @mandir@/man8/ospf6d.8=$DESTDIR/@mandir@/man8/ospf6d.8 0644 root bin
-f none @mandir@/man8/ospfd.8=$DESTDIR/@mandir@/man8/ospfd.8 0644 root bin
-f none @mandir@/man8/ripd.8=$DESTDIR/@mandir@/man8/ripd.8 0644 root bin
-f none @mandir@/man8/ripngd.8=$DESTDIR/@mandir@/man8/ripngd.8 0644 root bin
-f none @mandir@/man8/zebra.8=$DESTDIR/@mandir@/man8/zebra.8 0644 root bin
-f none @mandir@/man8/isisd.8=$DESTDIR/@mandir@/man8/isisd.8 0644 root bin
+f none @mandir@/man8/frr-bgpd.8=$DESTDIR/@mandir@/man8/bgpd.8 0644 root bin
+f none @mandir@/man8/frr-ospf6d.8=$DESTDIR/@mandir@/man8/frr-ospf6d.8 0644 root bin
+f none @mandir@/man8/frr-ospfd.8=$DESTDIR/@mandir@/man8/frr-ospfd.8 0644 root bin
+f none @mandir@/man8/frr-ripd.8=$DESTDIR/@mandir@/man8/frr-ripd.8 0644 root bin
+f none @mandir@/man8/frr-ripngd.8=$DESTDIR/@mandir@/man8/frr-ripngd.8 0644 root bin
+f none @mandir@/man8/frr-zebra.8=$DESTDIR/@mandir@/man8/frr-zebra.8 0644 root bin
+f none @mandir@/man8/frr-isisd.8=$DESTDIR/@mandir@/man8/frr-isisd.8 0644 root bin
diff --git a/staticd/static_debug.c b/staticd/static_debug.c
new file mode 100644
index 0000000000..9906e805a7
--- /dev/null
+++ b/staticd/static_debug.c
@@ -0,0 +1,124 @@
+/*
+ * Staticd debug related functions
+ * Copyright (C) 2019 Volta Networks Inc.
+ * Mark Stapp
+ *
+ * This file is part of Free Range Routing (FRR).
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "lib/command.h"
+#include "lib/debug.h"
+
+#include "static_debug.h"
+
+/*
+ * Debug infra: a debug struct for each category, and a corresponding
+ * string.
+ */
+
+/* clang-format off */
+struct debug static_dbg_events = {0, "Staticd events"};
+
+struct debug *static_debug_arr[] = {
+ &static_dbg_events
+};
+
+const char *static_debugs_conflines[] = {
+ "debug static events"
+};
+/* clang-format on */
+
+
+/*
+ * Set or unset all staticd debugs
+ *
+ * flags
+ * The flags to set
+ *
+ * set
+ * Whether to set or unset the specified flags
+ */
+static void static_debug_set_all(uint32_t flags, bool set)
+{
+ for (unsigned int i = 0; i < array_size(static_debug_arr); i++) {
+ DEBUG_FLAGS_SET(static_debug_arr[i], flags, set);
+
+ /* if all modes have been turned off, don't preserve options */
+ if (!DEBUG_MODE_CHECK(static_debug_arr[i], DEBUG_MODE_ALL))
+ DEBUG_CLEAR(static_debug_arr[i]);
+ }
+}
+
+static int static_debug_config_write_helper(struct vty *vty, bool config)
+{
+ uint32_t mode = DEBUG_MODE_ALL;
+
+ if (config)
+ mode = DEBUG_MODE_CONF;
+
+ for (unsigned int i = 0; i < array_size(static_debug_arr); i++)
+ if (DEBUG_MODE_CHECK(static_debug_arr[i], mode))
+ vty_out(vty, "%s\n", static_debugs_conflines[i]);
+
+ return 0;
+}
+
+int static_config_write_debug(struct vty *vty)
+{
+ return static_debug_config_write_helper(vty, true);
+}
+
+int static_debug_status_write(struct vty *vty)
+{
+ return static_debug_config_write_helper(vty, false);
+}
+
+/*
+ * Set debugging status.
+ *
+ * vtynode
+ * vty->node
+ *
+ * onoff
+ * Whether to turn the specified debugs on or off
+ *
+ * events
+ * Debug general internal events
+ *
+ */
+void static_debug_set(int vtynode, bool onoff, bool events)
+{
+ uint32_t mode = DEBUG_NODE2MODE(vtynode);
+
+ if (events)
+ DEBUG_MODE_SET(&static_dbg_events, mode, onoff);
+}
+
+/*
+ * Debug lib initialization
+ */
+
+struct debug_callbacks static_dbg_cbs = {
+ .debug_set_all = static_debug_set_all
+};
+
+void static_debug_init(void)
+{
+ debug_init(&static_dbg_cbs);
+}
diff --git a/staticd/static_debug.h b/staticd/static_debug.h
new file mode 100644
index 0000000000..6e58118ed0
--- /dev/null
+++ b/staticd/static_debug.h
@@ -0,0 +1,73 @@
+/*
+ * Staticd debug related functions
+ * Copyright (C) 2019 Volta Networks Inc.
+ * Mark Stapp
+ *
+ * This file is part of Free Range Routing (FRR).
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _STATIC_DEBUG_H
+#define _STATIC_DEBUG_H
+
+
+#include <zebra.h>
+
+#include "lib/debug.h"
+
+/* staticd debugging records */
+struct debug static_dbg_events;
+
+/*
+ * Initialize staticd debugging.
+ *
+ * Installs VTY commands and registers callbacks.
+ */
+void static_debug_init(void);
+
+/*
+ * Print staticd debugging configuration.
+ *
+ * vty
+ * VTY to print debugging configuration to.
+ */
+int static_config_write_debug(struct vty *vty);
+
+/*
+ * Print staticd debugging configuration, human readable form.
+ *
+ * vty
+ * VTY to print debugging configuration to.
+ */
+int static_debug_status_write(struct vty *vty);
+
+/*
+ * Set debugging status.
+ *
+ * vtynode
+ * vty->node
+ *
+ * onoff
+ * Whether to turn the specified debugs on or off
+ *
+ * events
+ * Debug general internal events
+ *
+ */
+void static_debug_set(int vtynode, bool onoff, bool events);
+
+
+#endif /* _STATIC_DEBUG_H */
diff --git a/staticd/static_main.c b/staticd/static_main.c
index 18cb9638c9..43cb7db51d 100644
--- a/staticd/static_main.c
+++ b/staticd/static_main.c
@@ -36,6 +36,7 @@
#include "static_vty.h"
#include "static_routes.h"
#include "static_zebra.h"
+#include "static_debug.h"
char backup_config_file[256];
@@ -141,6 +142,7 @@ int main(int argc, char **argv, char **envp)
master = frr_init();
access_list_init();
+ static_debug_init();
static_vrf_init();
static_zebra_init();
diff --git a/staticd/static_vty.c b/staticd/static_vty.c
index 8db37589af..6390fd811f 100644
--- a/staticd/static_vty.c
+++ b/staticd/static_vty.c
@@ -32,9 +32,13 @@
#include "static_memory.h"
#include "static_vty.h"
#include "static_routes.h"
+#include "static_debug.h"
#ifndef VTYSH_EXTRACT_PL
#include "staticd/static_vty_clippy.c"
#endif
+
+#define STATICD_STR "Static route daemon\n"
+
static struct static_vrf *static_vty_get_unknown_vrf(struct vty *vty,
const char *vrf_name)
{
@@ -1439,21 +1443,43 @@ DEFPY(ipv6_route_vrf,
from_str, gate_str, ifname, flag, tag_str, distance_str, label,
table_str, false);
}
+DEFPY(debug_staticd,
+ debug_staticd_cmd,
+ "[no] debug static [{events$events}]",
+ NO_STR
+ DEBUG_STR
+ STATICD_STR
+ "Debug events\n")
+{
+ /* If no specific category, change all */
+ if (strmatch(argv[argc - 1]->text, "static"))
+ static_debug_set(vty->node, !no, true);
+ else
+ static_debug_set(vty->node, !no, !!events);
-DEFUN_NOSH (show_debugging_staticd,
- show_debugging_staticd_cmd,
+ return CMD_SUCCESS;
+}
+
+DEFUN_NOSH (show_debugging_static,
+ show_debugging_static_cmd,
"show debugging [static]",
SHOW_STR
DEBUG_STR
"Static Information\n")
{
- vty_out(vty, "Static debugging status\n");
+ vty_out(vty, "Staticd debugging status\n");
+
+ static_debug_status_write(vty);
return CMD_SUCCESS;
}
+static struct cmd_node debug_node = {DEBUG_NODE, "", 1};
+
void static_vty_init(void)
{
+ install_node(&debug_node, static_config_write_debug);
+
install_element(CONFIG_NODE, &ip_mroute_dist_cmd);
install_element(CONFIG_NODE, &ip_route_blackhole_cmd);
@@ -1470,7 +1496,9 @@ void static_vty_init(void)
install_element(CONFIG_NODE, &ipv6_route_cmd);
install_element(VRF_NODE, &ipv6_route_vrf_cmd);
- install_element(VIEW_NODE, &show_debugging_staticd_cmd);
+ install_element(VIEW_NODE, &show_debugging_static_cmd);
+ install_element(VIEW_NODE, &debug_staticd_cmd);
+ install_element(CONFIG_NODE, &debug_staticd_cmd);
static_list = list_new();
static_list->cmp = (int (*)(void *, void *))static_list_compare;
diff --git a/staticd/subdir.am b/staticd/subdir.am
index 17c4536fe9..30c69231c9 100644
--- a/staticd/subdir.am
+++ b/staticd/subdir.am
@@ -7,10 +7,11 @@ noinst_LIBRARIES += staticd/libstatic.a
sbin_PROGRAMS += staticd/staticd
dist_examples_DATA += staticd/staticd.conf.sample
vtysh_scan += $(top_srcdir)/staticd/static_vty.c
-man8 += $(MANBUILD)/staticd.8
+man8 += $(MANBUILD)/frr-staticd.8
endif
staticd_libstatic_a_SOURCES = \
+ staticd/static_debug.c \
staticd/static_memory.c \
staticd/static_nht.c \
staticd/static_routes.c \
@@ -20,6 +21,7 @@ staticd_libstatic_a_SOURCES = \
# end
noinst_HEADERS += \
+ staticd/static_debug.h \
staticd/static_memory.h \
staticd/static_nht.h \
staticd/static_zebra.h \
diff --git a/tests/bgpd/test_mp_attr.c b/tests/bgpd/test_mp_attr.c
index af9e5791b7..c97ea57150 100644
--- a/tests/bgpd/test_mp_attr.c
+++ b/tests/bgpd/test_mp_attr.c
@@ -1027,7 +1027,7 @@ static void parse_test(struct peer *peer, struct test_segment *t, int type)
parse_ret = bgp_mp_unreach_parse(&attr_args, &nlri);
break;
case BGP_ATTR_PREFIX_SID:
- parse_ret = bgp_attr_prefix_sid(t->len, &attr_args, &nlri);
+ parse_ret = bgp_attr_prefix_sid(&attr_args, &nlri);
break;
default:
printf("unknown type");
diff --git a/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref b/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref
index a7d6fe11a6..61d17a61b3 100644
--- a/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref
+++ b/tests/topotests/all-protocol-startup/r1/ipv4_routes.ref
@@ -10,6 +10,8 @@ C>* 192.168.8.0/26 is directly connected, r1-eth8, XX:XX:XX
C>* 192.168.9.0/26 is directly connected, r1-eth9, XX:XX:XX
O 192.168.0.0/24 [110/10] is directly connected, r1-eth0, XX:XX:XX
O 192.168.3.0/26 [110/10] is directly connected, r1-eth3, XX:XX:XX
+S>* 1.1.1.1/32 [1/0] is directly connected, r1-eth0, XX:XX:XX
+S>* 1.1.1.2/32 [1/0] is directly connected, r1-eth1, XX:XX:XX
S>* 4.5.6.10/32 [1/0] via 192.168.0.2, r1-eth0, XX:XX:XX
S>* 4.5.6.11/32 [1/0] via 192.168.0.2, r1-eth0, XX:XX:XX
S>* 4.5.6.12/32 [1/0] is directly connected, r1-eth0, XX:XX:XX
diff --git a/tests/topotests/all-protocol-startup/r1/zebra.conf b/tests/topotests/all-protocol-startup/r1/zebra.conf
index 85c8676964..fbf827604f 100644
--- a/tests/topotests/all-protocol-startup/r1/zebra.conf
+++ b/tests/topotests/all-protocol-startup/r1/zebra.conf
@@ -26,6 +26,11 @@ ipv6 route 4:5::6:12/128 r1-eth0
# by zebra but not installed.
ip route 4.5.6.15/32 192.168.0.2 255
ipv6 route 4:5::6:15/128 fc00:0:0:0::2 255
+
+# Routes to put into a nexthop-group
+ip route 1.1.1.1/32 r1-eth0
+ip route 1.1.1.2/32 r1-eth1
+
!
interface r1-eth0
description to sw0 - no routing protocol
diff --git a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py
index 9658c080c0..16609221c1 100755
--- a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py
+++ b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py
@@ -120,6 +120,7 @@ def setup_module(module):
if net['r%s' % i].daemon_available('ldpd'):
# Only test LDPd if it's installed and Kernel >= 4.5
net['r%s' % i].loadConf('ldpd', '%s/r%s/ldpd.conf' % (thisDir, i))
+ net['r%s' % i].loadConf('sharpd')
net['r%s' % i].startRouter()
# For debugging after starting Quagga/FRR daemons, uncomment the next line
@@ -346,6 +347,36 @@ def test_converge_protocols():
# For debugging after starting FRR/Quagga daemons, uncomment the next line
## CLI(net)
+def test_nexthop_groups():
+ global fatal_error
+ global net
+
+ # Skip if previous fatal error condition is raised
+ if (fatal_error != ""):
+ pytest.skip(fatal_error)
+
+ print("\n\n** Verifying Nexthop Groups")
+ print("******************************************\n")
+
+ # Create a lib nexthop-group
+ net["r1"].cmd('vtysh -c "c t" -c "nexthop-group red" -c "nexthop 1.1.1.1" -c "nexthop 1.1.1.2"')
+
+ # Create with sharpd using nexthop-group
+ net["r1"].cmd('vtysh -c "sharp install routes 2.2.2.1 nexthop-group red 1"')
+
+ # Verify route and that zebra created NHGs for and they are valid/installed
+ output = net["r1"].cmd('vtysh -c "show ip route 2.2.2.1/32 nexthop-group"')
+ match = re.search(r"Nexthop Group ID: (\d+)", output);
+ assert match is not None, "Nexthop Group ID not found for sharpd route 2.2.2.1/32"
+
+ nhe_id = int(match.group(1))
+
+ output = net["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhe_id)
+ match = re.search(r"Valid", output)
+ assert match is not None, "Nexthop Group ID=%d not marked Valid" % nhe_id
+
+ match = re.search(r"Installed", output)
+ assert match is not None, "Nexthop Group ID=%d not marked Installed" % nhe_id
def test_rip_status():
global fatal_error
diff --git a/tests/topotests/bgp_default-route_route-map/__init__.py b/tests/topotests/bgp_default-route_route-map/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_default-route_route-map/__init__.py
diff --git a/tests/topotests/bgp_default-route_route-map/r1/bgpd.conf b/tests/topotests/bgp_default-route_route-map/r1/bgpd.conf
new file mode 100644
index 0000000000..a9925ab661
--- /dev/null
+++ b/tests/topotests/bgp_default-route_route-map/r1/bgpd.conf
@@ -0,0 +1,9 @@
+router bgp 65000
+ neighbor 192.168.255.2 remote-as 65001
+ address-family ipv4 unicast
+ neighbor 192.168.255.2 default-originate route-map default
+ exit-address-family
+!
+route-map default permit 10
+ set metric 123
+!
diff --git a/tests/topotests/bgp_default-route_route-map/r1/zebra.conf b/tests/topotests/bgp_default-route_route-map/r1/zebra.conf
new file mode 100644
index 0000000000..0a283c06d5
--- /dev/null
+++ b/tests/topotests/bgp_default-route_route-map/r1/zebra.conf
@@ -0,0 +1,9 @@
+!
+interface lo
+ ip address 172.16.255.254/32
+!
+interface r1-eth0
+ ip address 192.168.255.1/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_default-route_route-map/r2/bgpd.conf b/tests/topotests/bgp_default-route_route-map/r2/bgpd.conf
new file mode 100644
index 0000000000..a8a6c49f4d
--- /dev/null
+++ b/tests/topotests/bgp_default-route_route-map/r2/bgpd.conf
@@ -0,0 +1,6 @@
+router bgp 65001
+ neighbor 192.168.255.1 remote-as 65000
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_default-route_route-map/r2/zebra.conf b/tests/topotests/bgp_default-route_route-map/r2/zebra.conf
new file mode 100644
index 0000000000..606c17bec9
--- /dev/null
+++ b/tests/topotests/bgp_default-route_route-map/r2/zebra.conf
@@ -0,0 +1,6 @@
+!
+interface r2-eth0
+ ip address 192.168.255.2/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_default-route_route-map/test_bgp_default-originate_route-map.py b/tests/topotests/bgp_default-route_route-map/test_bgp_default-originate_route-map.py
new file mode 100644
index 0000000000..992ee85ab1
--- /dev/null
+++ b/tests/topotests/bgp_default-route_route-map/test_bgp_default-originate_route-map.py
@@ -0,0 +1,131 @@
+#!/usr/bin/env python
+
+#
+# bgp_default-originate_route-map.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2019 by
+# Donatas Abraitis <donatas.abraitis@gmail.com>
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+bgp_default-originate_route-map.py:
+
+Test if works the following commands:
+router bgp 65031
+ address-family ipv4 unicast
+ neighbor 192.168.255.2 default-originate route-map default
+
+route-map default permit 10
+ set metric 123
+"""
+
+import os
+import sys
+import json
+import time
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+from mininet.topo import Topo
+
+class TemplateTopo(Topo):
+ def build(self, *_args, **_opts):
+ tgen = get_topogen(self)
+
+ for routern in range(1, 3):
+ tgen.add_router('r{}'.format(routern))
+
+ switch = tgen.add_switch('s1')
+ switch.add_link(tgen.gears['r1'])
+ switch.add_link(tgen.gears['r2'])
+
+def setup_module(mod):
+ tgen = Topogen(TemplateTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.iteritems(), 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_default_originate_route_map():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router = tgen.gears['r2']
+
+ def _bgp_converge(router):
+ output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json"))
+ expected = {
+ '192.168.255.1': {
+ 'bgpState': 'Established',
+ 'addressFamilyInfo': {
+ 'ipv4Unicast': {
+ 'acceptedPrefixCounter': 1
+ }
+ }
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ def _bgp_default_route_has_metric(router):
+ output = json.loads(router.vtysh_cmd("show ip bgp 0.0.0.0/0 json"))
+ expected = {
+ 'paths': [
+ {
+ 'med': 123
+ }
+ ]
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_converge, router)
+ success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+
+ assert result is None, 'Failed to see bgp convergence in "{}"'.format(router)
+
+ test_func = functools.partial(_bgp_default_route_has_metric, router)
+ success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+
+ assert result is None, 'Failed to see applied metric for default route in "{}"'.format(router)
+
+if __name__ == '__main__':
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_up.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_up.py
index 21543ab78e..4ecaa4c026 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_up.py
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_up.py
@@ -23,15 +23,16 @@ for rtr in rtrs:
mem_z[rtr] = {'value': int(found.group(1)), 'units': found.group(2)}
mem_b[rtr] = {'value': int(found.group(3)), 'units': found.group(4)}
-luCommand('ce1', 'vtysh -c "sharp data nexthop"', 'sharpd is not running', 'none','check if sharpd running')
-doSharp = True
+luCommand('ce1', 'vtysh -c "show mem"', 'qmem sharpd', 'none','check if sharpd running')
+doSharp = False
found = luLast()
if ret != False and found != None:
if len(found.group()):
- luCommand('ce1', 'vtysh -c "sharp data nexthop"', 'sharpd is not running', 'pass','sharpd NOT running, skipping test')
- doSharp = False
+ doSharp = True
-if doSharp == True:
+if doSharp != True:
+ luCommand('ce1', 'vtysh -c "sharp data nexthop"', '.', 'pass','sharpd NOT running, skipping test')
+else:
luCommand('ce1', 'vtysh -c "sharp install routes 10.0.0.0 nexthop 99.0.0.1 {}"'.format(num),'','pass','Adding {} routes'.format(num))
luCommand('ce2', 'vtysh -c "sharp install routes 10.0.0.0 nexthop 99.0.0.2 {}"'.format(num),'','pass','Adding {} routes'.format(num))
rtrs = ['ce1', 'ce2', 'ce3']
diff --git a/tests/topotests/bgp_maximum_prefix_out/__init__.py b/tests/topotests/bgp_maximum_prefix_out/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_maximum_prefix_out/__init__.py
diff --git a/tests/topotests/bgp_maximum_prefix_out/r1/bgpd.conf b/tests/topotests/bgp_maximum_prefix_out/r1/bgpd.conf
new file mode 100644
index 0000000000..9a68809631
--- /dev/null
+++ b/tests/topotests/bgp_maximum_prefix_out/r1/bgpd.conf
@@ -0,0 +1,9 @@
+!
+router bgp 65001
+ neighbor 192.168.255.1 remote-as 65002
+ address-family ipv4 unicast
+ redistribute connected
+ neighbor 192.168.255.1 maximum-prefix-out 2
+ exit-address-family
+ !
+!
diff --git a/tests/topotests/bgp_maximum_prefix_out/r1/zebra.conf b/tests/topotests/bgp_maximum_prefix_out/r1/zebra.conf
new file mode 100644
index 0000000000..24162258b7
--- /dev/null
+++ b/tests/topotests/bgp_maximum_prefix_out/r1/zebra.conf
@@ -0,0 +1,13 @@
+!
+interface lo
+ ip address 172.16.255.250/32
+ ip address 172.16.255.251/32
+ ip address 172.16.255.252/32
+ ip address 172.16.255.253/32
+ ip address 172.16.255.254/32
+!
+interface r1-eth0
+ ip address 192.168.255.2/30
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_maximum_prefix_out/r2/bgpd.conf b/tests/topotests/bgp_maximum_prefix_out/r2/bgpd.conf
new file mode 100644
index 0000000000..1659c4bec4
--- /dev/null
+++ b/tests/topotests/bgp_maximum_prefix_out/r2/bgpd.conf
@@ -0,0 +1,6 @@
+!
+router bgp 65002
+ neighbor 192.168.255.2 remote-as 65001
+ exit-address-family
+ !
+!
diff --git a/tests/topotests/bgp_maximum_prefix_out/r2/zebra.conf b/tests/topotests/bgp_maximum_prefix_out/r2/zebra.conf
new file mode 100644
index 0000000000..08dd374dee
--- /dev/null
+++ b/tests/topotests/bgp_maximum_prefix_out/r2/zebra.conf
@@ -0,0 +1,6 @@
+!
+interface r2-eth0
+ ip address 192.168.255.1/30
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_maximum_prefix_out/test_bgp_maximum_prefix_out.py b/tests/topotests/bgp_maximum_prefix_out/test_bgp_maximum_prefix_out.py
new file mode 100644
index 0000000000..d77aa5aff2
--- /dev/null
+++ b/tests/topotests/bgp_maximum_prefix_out/test_bgp_maximum_prefix_out.py
@@ -0,0 +1,108 @@
+#!/usr/bin/env python
+
+#
+# test_bgp_maximum_prefix_out.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2020 by
+# Donatas Abraitis <donatas.abraitis@gmail.com>
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+Test if `neighbor <X.X.X.X> maximum-prefix-out <Y>` is working
+correctly.
+"""
+
+import os
+import sys
+import json
+import time
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+from mininet.topo import Topo
+
+class TemplateTopo(Topo):
+ def build(self, *_args, **_opts):
+ tgen = get_topogen(self)
+
+ for routern in range(1, 3):
+ tgen.add_router('r{}'.format(routern))
+
+ switch = tgen.add_switch('s1')
+ switch.add_link(tgen.gears['r1'])
+ switch.add_link(tgen.gears['r2'])
+
+def setup_module(mod):
+ tgen = Topogen(TemplateTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.iteritems(), 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_maximum_prefix_out():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router = tgen.gears['r2']
+
+ def _bgp_converge(router):
+ output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.255.2 json"))
+ expected = {
+ '192.168.255.2': {
+ 'bgpState': 'Established',
+ 'addressFamilyInfo': {
+ 'ipv4Unicast': {
+ 'acceptedPrefixCounter': 2
+ }
+ }
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_converge, router)
+ success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+
+ assert result is None, 'Failed bgp convergence in "{}"'.format(router)
+
+if __name__ == '__main__':
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/lib/ltemplate.py b/tests/topotests/lib/ltemplate.py
index 1d12d11a26..a76d8e4b08 100644
--- a/tests/topotests/lib/ltemplate.py
+++ b/tests/topotests/lib/ltemplate.py
@@ -134,6 +134,7 @@ def teardown_module(mod):
tgen = get_topogen()
if _lt != None and _lt.scriptdir != None and _lt.prestarthooksuccess == True:
+ luShowResults(logger.info)
print(luFinish())
# This function tears down the whole topology.
diff --git a/tests/topotests/lib/lutil.py b/tests/topotests/lib/lutil.py
index 7c89ada013..4ea97a3692 100755
--- a/tests/topotests/lib/lutil.py
+++ b/tests/topotests/lib/lutil.py
@@ -336,6 +336,14 @@ def luNumPass():
def luResult(target, success, str, logstr=None):
return LUtil.result(target, success, str, logstr)
+def luShowResults(prFunction):
+ printed = 0
+ sf = open(LUtil.fsum_name, 'r')
+ for line in sf:
+ printed+=1
+ prFunction(line.rstrip())
+ sf.close()
+
def luShowFail():
printed = 0
sf = open(LUtil.fsum_name, 'r')
diff --git a/tests/topotests/ospf6-topo1/r1/ip_6_address.nhg.ref b/tests/topotests/ospf6-topo1/r1/ip_6_address.nhg.ref
new file mode 100644
index 0000000000..11fd9fe3c4
--- /dev/null
+++ b/tests/topotests/ospf6-topo1/r1/ip_6_address.nhg.ref
@@ -0,0 +1,10 @@
+fc00:1111:1111:1111::/64 nhid XXXX via fc00:1:1:1::1234 dev r1-stubnet proto XXXX metric 20 pref medium
+fc00:1:1:1::/64 dev r1-stubnet proto XXXX metric 256 pref medium
+fc00:2222:2222:2222::/64 nhid XXXX via fe80::__(r2-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
+fc00:2:2:2::/64 nhid XXXX via fe80::__(r2-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
+fc00:3333:3333:3333::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
+fc00:3:3:3::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
+fc00:4444:4444:4444::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
+fc00:4:4:4::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
+fc00:a:a:a::/64 dev r1-sw5 proto XXXX metric 256 pref medium
+fc00:b:b:b::/64 nhid XXXX via fe80::__(r3-sw5)__ dev r1-sw5 proto XXXX metric 20 pref medium
diff --git a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py
index b70ae02266..cb0c4af221 100755
--- a/tests/topotests/ospf6-topo1/test_ospf6_topo1.py
+++ b/tests/topotests/ospf6-topo1/test_ospf6_topo1.py
@@ -89,7 +89,7 @@ sys.path.append(os.path.join(CWD, '../'))
from lib import topotest
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.topolog import logger
-
+import platform
#####################################################
##
@@ -319,7 +319,10 @@ def test_linux_ipv6_kernel_routingTable():
# Now compare the routing tables (after substituting link-local addresses)
for i in range(1, 5):
- refTableFile = os.path.join(CWD, 'r{}/ip_6_address.ref'.format(i))
+ if topotest.version_cmp(platform.release(), '5.3') < 0:
+ refTableFile = os.path.join(CWD, 'r{}/ip_6_address.ref'.format(i))
+ else:
+ refTableFile = os.path.join(CWD, 'r{}/ip_6_address.nhg.ref'.format(i))
if os.path.isfile(refTableFile):
expected = open(refTableFile).read().rstrip()
@@ -333,6 +336,7 @@ def test_linux_ipv6_kernel_routingTable():
actual = actual.replace(ll[1], "fe80::__(%s)__" % ll[0])
# Mask out protocol name or number
actual = re.sub(r"[ ]+proto [0-9a-z]+ +", " proto XXXX ", actual)
+ actual = re.sub(r"[ ]+nhid [0-9]+ +", " nhid XXXX ", actual)
# Remove ff00::/8 routes (seen on some kernels - not from FRR)
actual = re.sub(r'ff00::/8.*', '', actual)
diff --git a/tests/topotests/pim-basic/r1/bgpd.conf b/tests/topotests/pim-basic/r1/bgpd.conf
new file mode 100644
index 0000000000..8acaac96a0
--- /dev/null
+++ b/tests/topotests/pim-basic/r1/bgpd.conf
@@ -0,0 +1,3 @@
+router bgp 65001
+ neighbor 10.0.30.3 remote-as external
+ redistribute connected
diff --git a/tests/topotests/pim-basic/r1/pimd.conf b/tests/topotests/pim-basic/r1/pimd.conf
index 5740c66e24..cec765699d 100644
--- a/tests/topotests/pim-basic/r1/pimd.conf
+++ b/tests/topotests/pim-basic/r1/pimd.conf
@@ -2,9 +2,12 @@ hostname r1
!
interface r1-eth0
ip igmp
- ip pim sm
+ ip pim
+!
+interface r1-eth1
+ ip pim
!
interface lo
- ip pim sm
+ ip pim
!
-ip pim rp 10.254.0.1
+ip pim rp 10.254.0.3
diff --git a/tests/topotests/pim-basic/r1/rp-info.json b/tests/topotests/pim-basic/r1/rp-info.json
new file mode 100644
index 0000000000..1f713c2d28
--- /dev/null
+++ b/tests/topotests/pim-basic/r1/rp-info.json
@@ -0,0 +1,9 @@
+{
+ "10.254.0.3":[
+ {
+ "outboundInterface":"r1-eth1",
+ "group":"224.0.0.0\/4",
+ "source":"Static"
+ }
+ ]
+}
diff --git a/tests/topotests/pim-basic/r1/zebra.conf b/tests/topotests/pim-basic/r1/zebra.conf
index 2bf71294d0..b0a25f12aa 100644
--- a/tests/topotests/pim-basic/r1/zebra.conf
+++ b/tests/topotests/pim-basic/r1/zebra.conf
@@ -3,6 +3,9 @@ hostname r1
interface r1-eth0
ip address 10.0.20.1/24
!
+interface r1-eth1
+ ip address 10.0.30.1/24
+!
interface lo
ip address 10.254.0.1/32
!
diff --git a/tests/topotests/pim-basic/rp/bgpd.conf b/tests/topotests/pim-basic/rp/bgpd.conf
new file mode 100644
index 0000000000..6b16c067a5
--- /dev/null
+++ b/tests/topotests/pim-basic/rp/bgpd.conf
@@ -0,0 +1,3 @@
+router bgp 65003
+ neighbor 10.0.30.1 remote-as external
+ redistribute connected
diff --git a/tests/topotests/pim-basic/rp/pimd.conf b/tests/topotests/pim-basic/rp/pimd.conf
new file mode 100644
index 0000000000..3f1b4d65c9
--- /dev/null
+++ b/tests/topotests/pim-basic/rp/pimd.conf
@@ -0,0 +1,9 @@
+hostname rp
+!
+interface rp-eth0
+ ip pim
+!
+interface lo
+ ip pim
+!
+ip pim rp 10.254.0.3
diff --git a/tests/topotests/pim-basic/rp/upstream.json b/tests/topotests/pim-basic/rp/upstream.json
new file mode 100644
index 0000000000..c33dea49e9
--- /dev/null
+++ b/tests/topotests/pim-basic/rp/upstream.json
@@ -0,0 +1,17 @@
+{
+ "229.1.1.1":{
+ "10.0.20.2":{
+ "sourceStream":true,
+ "inboundInterface":"rp-eth0",
+ "rpfAddress":"10.0.20.2",
+ "source":"10.0.20.2",
+ "group":"229.1.1.1",
+ "state":"NotJ",
+ "joinState":"NotJoined",
+ "regState":"RegNoInfo",
+ "resetTimer":"--:--:--",
+ "refCount":1,
+ "sptBit":0
+ }
+ }
+}
diff --git a/tests/topotests/pim-basic/rp/zebra.conf b/tests/topotests/pim-basic/rp/zebra.conf
new file mode 100644
index 0000000000..0a1359ecd0
--- /dev/null
+++ b/tests/topotests/pim-basic/rp/zebra.conf
@@ -0,0 +1,8 @@
+hostname rp
+!
+interface rp-eth0
+ ip address 10.0.30.3/24
+!
+interface lo
+ ip address 10.254.0.3/32
+!
diff --git a/tests/topotests/pim-basic/test_pim.py b/tests/topotests/pim-basic/test_pim.py
index 6d54b8f2f0..0e0569e234 100644
--- a/tests/topotests/pim-basic/test_pim.py
+++ b/tests/topotests/pim-basic/test_pim.py
@@ -28,6 +28,8 @@ test_pim.py: Test pim
import os
import sys
import pytest
+import json
+from functools import partial
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, '../'))
@@ -47,11 +49,27 @@ class PIMTopo(Topo):
for routern in range(1, 3):
tgen.add_router('r{}'.format(routern))
+ tgen.add_router('rp')
+
+ # r1 -> .1
+ # r2 -> .2
+ # rp -> .3
+ # loopback network is 10.254.0.X/32
+ #
# r1 <- sw1 -> r2
+ # r1-eth0 <-> r2-eth0
+ # 10.0.20.0/24
sw = tgen.add_switch('sw1')
sw.add_link(tgen.gears['r1'])
sw.add_link(tgen.gears['r2'])
+ # r1 <- sw2 -> rp
+ # r1-eth1 <-> rp-eth0
+ # 10.0.30.0/24
+ sw = tgen.add_switch('sw2')
+ sw.add_link(tgen.gears['r1'])
+ sw.add_link(tgen.gears['rp'])
+
def setup_module(mod):
"Sets up the pytest environment"
@@ -68,9 +86,14 @@ def setup_module(mod):
TopoRouter.RD_PIM,
os.path.join(CWD, '{}/pimd.conf'.format(rname))
)
+ router.load_config(
+ TopoRouter.RD_BGP,
+ os.path.join(CWD, '{}/bgpd.conf'.format(rname))
+ )
# After loading the configurations, this function loads configured daemons.
tgen.start_router()
+ #tgen.mininet_cli()
def teardown_module(mod):
@@ -80,6 +103,22 @@ def teardown_module(mod):
# This function tears down the whole topology.
tgen.stop_topology()
+def test_pim_rp_setup():
+ "Ensure basic routing has come up and the rp has an outgoing interface"
+ #Ensure rp and r1 establish pim neighbor ship and bgp has come up
+ #Finally ensure that the rp has an outgoing interface on r1
+ tgen = get_topogen()
+
+ r1 = tgen.gears['r1']
+ json_file = '{}/{}/rp-info.json'.format(CWD, r1.name)
+ expected = json.loads(open(json_file).read())
+
+ test_func = partial(topotest.router_json_cmp,
+ r1, 'show ip pim rp-info json', expected)
+ _, result = topotest.run_and_expect(test_func, None, count=15, wait=5)
+ assertmsg = '"{}" JSON output mismatches'.format(r1.name)
+ assert result is None, assertmsg
+ #tgen.mininet_cli()
def test_pim_send_mcast_stream():
"Establish a Multicast stream from r2 -> r1 and then ensure S,G is created as appropriate"
@@ -90,6 +129,7 @@ def test_pim_send_mcast_stream():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
+ rp = tgen.gears['rp']
r2 = tgen.gears['r2']
r1 = tgen.gears['r1']
@@ -111,7 +151,21 @@ def test_pim_send_mcast_stream():
}
assert topotest.json_cmp(out, expected) is None, 'failed to converge pim'
+ #tgen.mininet_cli()
+
+def test_pim_rp_sees_stream():
+ "Ensure that the RP sees the stream and has acted accordingly"
+ tgen = get_topogen()
+
+ rp = tgen.gears['rp']
+ json_file = '{}/{}/upstream.json'.format(CWD, rp.name)
+ expected = json.loads(open(json_file).read())
+ test_func = partial(topotest.router_json_cmp,
+ rp, 'show ip pim upstream json', expected)
+ _, result = topotest.run_and_expect(test_func, None, count=20, wait=.5)
+ assertmsg = '"{}" JSON output mismatches'.format(rp.name)
+ assert result is None, assertmsg
def test_pim_igmp_report():
"Send a igmp report from r2->r1 and ensure that the *,G state is created on r1"
diff --git a/tools/frr-reload.py b/tools/frr-reload.py
index 3e97635dfe..45843faf13 100755
--- a/tools/frr-reload.py
+++ b/tools/frr-reload.py
@@ -934,6 +934,16 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
lines_to_del_to_del.append((ctx_keys, route_target_export_line))
lines_to_add_to_del.append((ctx_keys, route_target_both_line))
+ # Deleting static routes under a vrf can lead to time-outs if each is sent
+ # as separate vtysh -c commands. Change them from being in lines_to_del and
+ # put the "no" form in lines_to_add
+ if ctx_keys[0].startswith('vrf ') and line:
+ if (line.startswith('ip route') or
+ line.startswith('ipv6 route')):
+ add_cmd = ('no ' + line)
+ lines_to_add.append((ctx_keys, add_cmd))
+ lines_to_del_to_del.append((ctx_keys, line))
+
if not deleted:
found_add_line = line_exist(lines_to_add, ctx_keys, line)
@@ -1054,6 +1064,19 @@ def compare_context_objects(newconf, running):
for line in running_ctx.lines:
lines_to_del.append((running_ctx_keys, line))
+ # Some commands can happen at higher counts that make
+ # doing vtysh -c inefficient (and can time out.) For
+ # these commands, instead of adding them to lines_to_del,
+ # add the "no " version to lines_to_add.
+ elif (running_ctx_keys[0].startswith('ip route') or
+ running_ctx_keys[0].startswith('ipv6 route') or
+ running_ctx_keys[0].startswith('access-list') or
+ running_ctx_keys[0].startswith('ipv6 access-list') or
+ running_ctx_keys[0].startswith('ip prefix-list') or
+ running_ctx_keys[0].startswith('ipv6 prefix-list')):
+ add_cmd = ('no ' + running_ctx_keys[0],)
+ lines_to_add.append((add_cmd, None))
+
# Non-global context
elif running_ctx_keys and not any("address-family" in key for key in running_ctx_keys):
lines_to_del.append((running_ctx_keys, None))
@@ -1392,6 +1415,11 @@ if __name__ == '__main__':
if line == '!':
continue
+ # Don't run "no" commands twice since they can error
+ # out the second time due to first deletion
+ if x == 1 and ctx_keys[0].startswith('no '):
+ continue
+
cmd = line_for_vtysh_file(ctx_keys, line, False)
lines_to_configure.append(cmd)
diff --git a/vrrpd/subdir.am b/vrrpd/subdir.am
index d81594ad93..07358e0383 100644
--- a/vrrpd/subdir.am
+++ b/vrrpd/subdir.am
@@ -7,7 +7,7 @@ noinst_LIBRARIES += vrrpd/libvrrp.a
sbin_PROGRAMS += vrrpd/vrrpd
# dist_examples_DATA += staticd/staticd.conf.sample
vtysh_scan += $(top_srcdir)/vrrpd/vrrp_vty.c
-man8 += $(MANBUILD)/vrrpd.8
+man8 += $(MANBUILD)/frr-vrrpd.8
endif
vrrpd_libvrrp_a_SOURCES = \
diff --git a/watchfrr/subdir.am b/watchfrr/subdir.am
index 30f606c202..36af57cf82 100644
--- a/watchfrr/subdir.am
+++ b/watchfrr/subdir.am
@@ -5,7 +5,7 @@
if WATCHFRR
sbin_PROGRAMS += watchfrr/watchfrr
vtysh_scan += $(top_srcdir)/watchfrr/watchfrr_vty.c
-man8 += $(MANBUILD)/watchfrr.8
+man8 += $(MANBUILD)/frr-watchfrr.8
endif
noinst_HEADERS += \
diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c
index c3d5bf8428..90d3aeb482 100644
--- a/zebra/kernel_netlink.c
+++ b/zebra/kernel_netlink.c
@@ -592,6 +592,7 @@ struct rtattr *addattr_nest(struct nlmsghdr *n, int maxlen, int type)
struct rtattr *nest = NLMSG_TAIL(n);
addattr_l(n, maxlen, type, NULL, 0);
+ nest->rta_type |= NLA_F_NESTED;
return nest;
}
@@ -606,6 +607,7 @@ struct rtattr *rta_nest(struct rtattr *rta, int maxlen, int type)
struct rtattr *nest = RTA_TAIL(rta);
rta_addattr_l(rta, maxlen, type, NULL, 0);
+ nest->rta_type |= NLA_F_NESTED;
return nest;
}
diff --git a/zebra/label_manager.c b/zebra/label_manager.c
index 6e58f4b925..caebdc0f08 100644
--- a/zebra/label_manager.c
+++ b/zebra/label_manager.c
@@ -262,8 +262,12 @@ assign_specific_label_chunk(uint8_t proto, unsigned short instance,
* included in the previous one */
for (node = first_node; node && (node != last_node);
node = next) {
+ struct label_manager_chunk *death;
+
next = listnextnode(node);
+ death = listgetdata(node);
list_delete_node(lbl_mgr.lc_list, node);
+ delete_label_chunk(death);
}
lmc = create_label_chunk(proto, instance, keep, base, end);
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 29a341abbd..dd6e62ee6c 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -2353,7 +2353,7 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
unsigned char family;
int type;
afi_t afi = AFI_UNSPEC;
- vrf_id_t vrf_id = 0;
+ vrf_id_t vrf_id = VRF_DEFAULT;
struct interface *ifp = NULL;
struct nhmsg *nhm = NULL;
struct nexthop nh = {};
diff --git a/zebra/subdir.am b/zebra/subdir.am
index 916f6cb5d1..77ed5a6caa 100644
--- a/zebra/subdir.am
+++ b/zebra/subdir.am
@@ -36,7 +36,7 @@ if LINUX
module_LTLIBRARIES += zebra/zebra_cumulus_mlag.la
endif
-man8 += $(MANBUILD)/zebra.8
+man8 += $(MANBUILD)/frr-zebra.8
## endif ZEBRA
endif
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index 5a63c1e4f6..db54e6f25b 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -41,6 +41,7 @@
#include "lib/vrf.h"
#include "lib/libfrr.h"
#include "lib/sockopt.h"
+#include "lib/lib_errors.h"
#include "zebra/zebra_router.h"
#include "zebra/rib.h"
@@ -147,6 +148,25 @@ static int zserv_encode_nexthop(struct stream *s, struct nexthop *nexthop)
return 1;
}
+/*
+ * Zebra error addition adds error type.
+ *
+ *
+ * 0 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | enum zebra_error_types |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ */
+static void zserv_encode_error(struct stream *s, enum zebra_error_types error)
+{
+ stream_put(s, &error, sizeof(error));
+
+ /* Write packet size. */
+ stream_putw_at(s, 0, stream_get_endp(s));
+}
+
/* Send handlers ----------------------------------------------------------- */
/* Interface is added. Send ZEBRA_INTERFACE_ADD to client. */
@@ -1397,7 +1417,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
struct nexthop *nexthop = NULL;
struct nexthop_group *ng = NULL;
int i, ret;
- vrf_id_t vrf_id = 0;
+ vrf_id_t vrf_id;
struct ipaddr vtep_ip;
s = msg;
@@ -1593,6 +1613,14 @@ static void zread_route_add(ZAPI_HANDLER_ARGS)
if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX))
src_p = &api.src_prefix;
+ if (api.safi != SAFI_UNICAST && api.safi != SAFI_MULTICAST) {
+ flog_warn(EC_LIB_ZAPI_MISSMATCH,
+ "%s: Received safi: %d but we can only accept UNICAST or MULTICAST",
+ __func__, api.safi);
+ nexthop_group_delete(&ng);
+ XFREE(MTYPE_RE, re);
+ return;
+ }
ret = rib_add_multipath(afi, api.safi, &api.prefix, src_p, re, ng);
/* Stats */
@@ -2363,14 +2391,19 @@ static inline void zread_rule(ZAPI_HANDLER_ARGS)
if (!(zpr.rule.filter.src_ip.family == AF_INET
|| zpr.rule.filter.src_ip.family == AF_INET6)) {
- zlog_warn("Unsupported PBR source IP family: %s\n",
- family2str(zpr.rule.filter.src_ip.family));
+ zlog_warn(
+ "Unsupported PBR source IP family: %s (%" PRIu8
+ ")\n",
+ family2str(zpr.rule.filter.src_ip.family),
+ zpr.rule.filter.src_ip.family);
return;
}
if (!(zpr.rule.filter.dst_ip.family == AF_INET
|| zpr.rule.filter.dst_ip.family == AF_INET6)) {
- zlog_warn("Unsupported PBR dest IP family: %s\n",
- family2str(zpr.rule.filter.dst_ip.family));
+ zlog_warn("Unsupported PBR IP family: %s (%" PRIu8
+ ")\n",
+ family2str(zpr.rule.filter.dst_ip.family),
+ zpr.rule.filter.dst_ip.family);
return;
}
@@ -2518,6 +2551,36 @@ stream_failure:
return;
}
+static void zsend_error_msg(struct zserv *client, enum zebra_error_types error,
+ struct zmsghdr *bad_hdr)
+{
+
+ struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
+
+ zclient_create_header(s, ZEBRA_ERROR, bad_hdr->vrf_id);
+
+ zserv_encode_error(s, error);
+
+ client->error_cnt++;
+ zserv_send_message(client, s);
+}
+
+static void zserv_error_no_vrf(ZAPI_HANDLER_ARGS)
+{
+ if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV)
+ zlog_debug("ZAPI message specifies unknown VRF: %d",
+ hdr->vrf_id);
+
+ return zsend_error_msg(client, ZEBRA_NO_VRF, hdr);
+}
+
+static void zserv_error_invalid_msg_type(ZAPI_HANDLER_ARGS)
+{
+ zlog_info("Zebra received unknown command %d", hdr->command);
+
+ return zsend_error_msg(client, ZEBRA_INVALID_MSG_TYPE, hdr);
+}
+
void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
[ZEBRA_ROUTER_ID_ADD] = zread_router_id_add,
[ZEBRA_ROUTER_ID_DELETE] = zread_router_id_delete,
@@ -2643,16 +2706,12 @@ void zserv_handle_commands(struct zserv *client, struct stream *msg)
/* lookup vrf */
zvrf = zebra_vrf_lookup_by_id(hdr.vrf_id);
- if (!zvrf) {
- if (IS_ZEBRA_DEBUG_PACKET && IS_ZEBRA_DEBUG_RECV)
- zlog_debug("ZAPI message specifies unknown VRF: %d",
- hdr.vrf_id);
- return;
- }
+ if (!zvrf)
+ return zserv_error_no_vrf(client, &hdr, msg, zvrf);
if (hdr.command >= array_size(zserv_handlers)
|| zserv_handlers[hdr.command] == NULL)
- zlog_info("Zebra received unknown command %d", hdr.command);
- else
- zserv_handlers[hdr.command](client, &hdr, msg, zvrf);
+ return zserv_error_invalid_msg_type(client, &hdr, msg, zvrf);
+
+ zserv_handlers[hdr.command](client, &hdr, msg, zvrf);
}
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index 4f41406a5c..7430307320 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -478,7 +478,7 @@ static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends,
struct nhg_hash_entry *depend = NULL;
struct nexthop_group resolved_ng = {};
- nexthop_group_add_sorted(&resolved_ng, nh);
+ resolved_ng.nexthop = nh;
depend = zebra_nhg_rib_find(0, &resolved_ng, afi);
depends_add(nhg_depends, depend);
@@ -507,7 +507,7 @@ static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id,
if (lookup.nhg->nexthop->next) {
/* Groups can have all vrfs and AF's in them */
lookup.afi = AFI_UNSPEC;
- lookup.vrf_id = 0;
+ lookup.vrf_id = VRF_DEFAULT;
} else {
switch (lookup.nhg->nexthop->type) {
case (NEXTHOP_TYPE_IFINDEX):
@@ -1048,25 +1048,55 @@ int zebra_nhg_kernel_del(uint32_t id)
}
/* Some dependency helper functions */
-static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi)
+static struct nhg_hash_entry *depends_find_recursive(const struct nexthop *nh,
+ afi_t afi)
{
- struct nexthop lookup;
- struct nhg_hash_entry *nhe = NULL;
+ struct nhg_hash_entry *nhe;
+ struct nexthop *lookup = NULL;
- if (!nh)
- goto done;
+ lookup = nexthop_dup(nh, NULL);
+
+ nhe = zebra_nhg_find_nexthop(0, lookup, afi, 0);
+
+ nexthops_free(lookup);
+
+ return nhe;
+}
+
+static struct nhg_hash_entry *depends_find_singleton(const struct nexthop *nh,
+ afi_t afi)
+{
+ struct nhg_hash_entry *nhe;
+ struct nexthop lookup = {};
/* Capture a snapshot of this single nh; it might be part of a list,
* so we need to make a standalone copy.
*/
- memset(&lookup, 0, sizeof(lookup));
- nexthop_copy(&lookup, nh, NULL);
+ nexthop_copy_no_recurse(&lookup, nh, NULL);
nhe = zebra_nhg_find_nexthop(0, &lookup, afi, 0);
/* The copy may have allocated labels; free them if necessary. */
nexthop_del_labels(&lookup);
+ return nhe;
+}
+
+static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi)
+{
+ struct nhg_hash_entry *nhe = NULL;
+
+ if (!nh)
+ goto done;
+
+ /* We are separating these functions out to increase handling speed
+ * in the non-recursive case (by not alloc/freeing)
+ */
+ if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE))
+ nhe = depends_find_recursive(nh, afi);
+ else
+ nhe = depends_find_singleton(nh, afi);
+
done:
return nhe;
}
diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c
index 0c3adcdfa1..fe7a93a50c 100644
--- a/zebra/zebra_pbr.c
+++ b/zebra/zebra_pbr.c
@@ -652,12 +652,22 @@ static void *pbr_iptable_alloc_intern(void *arg)
{
struct zebra_pbr_iptable *zpi;
struct zebra_pbr_iptable *new;
+ struct listnode *ln;
+ char *ifname;
zpi = (struct zebra_pbr_iptable *)arg;
new = XCALLOC(MTYPE_TMP, sizeof(struct zebra_pbr_iptable));
+ /* Deep structure copy */
memcpy(new, zpi, sizeof(*zpi));
+ new->interface_name_list = list_new();
+
+ if (zpi->interface_name_list) {
+ for (ALL_LIST_ELEMENTS_RO(zpi->interface_name_list, ln, ifname))
+ listnode_add(new->interface_name_list,
+ XSTRDUP(MTYPE_PBR_IPTABLE_IFNAME, ifname));
+ }
return new;
}
diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c
index b48756302a..d7bbe779bd 100644
--- a/zebra/zebra_ptm.c
+++ b/zebra/zebra_ptm.c
@@ -1295,6 +1295,7 @@ static void zebra_ptm_send_bfdd(struct stream *msg)
}
stream_free(msgc);
+ stream_free(msg);
}
static void zebra_ptm_send_clients(struct stream *msg)
@@ -1326,6 +1327,7 @@ static void zebra_ptm_send_clients(struct stream *msg)
}
stream_free(msgc);
+ stream_free(msg);
}
static int _zebra_ptm_bfd_client_deregister(struct zserv *zs)
@@ -1421,6 +1423,7 @@ static void _zebra_ptm_reroute(struct zserv *zs, struct zebra_vrf *zvrf,
stream_putw_at(msgc, 0, STREAM_READABLE(msgc));
zebra_ptm_send_bfdd(msgc);
+ msgc = NULL;
/* Registrate process PID for shutdown hook. */
STREAM_GETL(msg, ppid);
@@ -1429,7 +1432,8 @@ static void _zebra_ptm_reroute(struct zserv *zs, struct zebra_vrf *zvrf,
return;
stream_failure:
- stream_free(msgc);
+ if (msgc)
+ stream_free(msgc);
zlog_err("%s:%d failed to registrate client pid", __FILE__, __LINE__);
}
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index b85bf83923..c8b96011dc 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -1351,9 +1351,10 @@ DEFPY (show_interface_nexthop_group,
DEFPY (show_nexthop_group,
show_nexthop_group_cmd,
- "show nexthop-group <(0-4294967295)$id|[<ip$v4|ipv6$v6>] [vrf <NAME$vrf_name|all$vrf_all>]>",
+ "show nexthop-group rib <(0-4294967295)$id|[<ip$v4|ipv6$v6>] [vrf <NAME$vrf_name|all$vrf_all>]>",
SHOW_STR
"Show Nexthop Groups\n"
+ "RIB information\n"
"Nexthop Group ID\n"
IP_STR
IP6_STR
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index 564573dcb3..ffb2528a24 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -8624,9 +8624,8 @@ void zebra_vxlan_macvlan_down(struct interface *ifp)
struct interface *ifp;
ifp = if_lookup_by_index_all_vrf(zif->link_ifindex);
- zlog_debug("macvlan %s parent link is not found. Parent index %d ifp %s",
- ifp->name, zif->link_ifindex,
- ifp ? ifp->name : " ");
+ zlog_debug("macvlan parent link is not found. Parent index %d ifp %s",
+ zif->link_ifindex, ifp ? ifp->name : " ");
}
return;
}
@@ -9487,7 +9486,7 @@ void zebra_vxlan_advertise_subnet(ZAPI_HANDLER_ARGS)
s = msg;
STREAM_GETC(s, advertise);
- vni = stream_get3(s);
+ STREAM_GET(&vni, s, 3);
zvni = zvni_lookup(vni);
if (!zvni)
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 419f30e6d3..cca926f3b0 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -591,8 +591,10 @@ static void zserv_client_free(struct zserv *client)
/* Free bitmaps. */
for (afi_t afi = AFI_IP; afi < AFI_MAX; afi++) {
- for (int i = 0; i < ZEBRA_ROUTE_MAX; i++)
+ for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) {
vrf_bitmap_free(client->redist[afi][i]);
+ redist_del_all_instances(&client->mi_redist[afi][i]);
+ }
vrf_bitmap_free(client->redist_default[afi]);
}
diff --git a/zebra/zserv.h b/zebra/zserv.h
index ccc8d92aa2..d8d82a52ec 100644
--- a/zebra/zserv.h
+++ b/zebra/zserv.h
@@ -146,6 +146,7 @@ struct zserv {
uint32_t v6_nh_watch_rem_cnt;
uint32_t vxlan_sg_add_cnt;
uint32_t vxlan_sg_del_cnt;
+ uint32_t error_cnt;
time_t nh_reg_time;
time_t nh_dereg_time;