summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--babeld/babeld.h1
-rw-r--r--bfdd/bfdd.c2
-rw-r--r--bgpd/bgp_advertise.c2
-rw-r--r--bgpd/bgp_attr.c1
-rw-r--r--bgpd/bgp_attr.h96
-rw-r--r--bgpd/bgp_damp.h4
-rw-r--r--bgpd/bgp_memory.c1
-rw-r--r--bgpd/bgp_memory.h1
-rw-r--r--bgpd/bgp_mplsvpn.c37
-rw-r--r--bgpd/bgp_nht.c44
-rw-r--r--bgpd/bgp_rd.h2
-rw-r--r--bgpd/bgp_route.c10
-rw-r--r--bgpd/bgp_route.h81
-rw-r--r--bgpd/bgp_routemap.c1
-rw-r--r--bgpd/bgpd.h11
-rw-r--r--bgpd/rfapi/rfapi.c59
-rw-r--r--bgpd/rfapi/rfapi_import.c233
-rw-r--r--bgpd/rfapi/rfapi_monitor.c2
-rw-r--r--bgpd/rfapi/rfapi_rib.c29
-rw-r--r--bgpd/rfapi/rfapi_vty.c54
-rw-r--r--bgpd/rfapi/vnc_import_bgp.c32
-rw-r--r--configure.ac7
-rw-r--r--debian/frr.pam2
-rw-r--r--doc/developer/northbound/retrofitting-configuration-commands.rst28
-rw-r--r--doc/developer/topotests.rst1
-rw-r--r--doc/user/basic.rst5
-rw-r--r--eigrpd/eigrp_const.h3
-rw-r--r--fpm/fpm.h5
-rw-r--r--isisd/isis_main.c3
-rw-r--r--ldpd/ldpd.c1
-rw-r--r--lib/bitfield.h1
-rw-r--r--lib/event.c5
-rw-r--r--lib/hash.h6
-rw-r--r--lib/libfrr.c2
-rw-r--r--lib/libfrr.h43
-rw-r--r--lib/mgmt.proto5
-rw-r--r--lib/mgmt_be_client.c314
-rw-r--r--lib/mgmt_be_client.h40
-rw-r--r--lib/mgmt_fe_client.c203
-rw-r--r--lib/mgmt_fe_client.h20
-rw-r--r--lib/mgmt_msg_native.c1
-rw-r--r--lib/mgmt_msg_native.h67
-rw-r--r--lib/northbound.c17
-rw-r--r--lib/northbound.h17
-rw-r--r--lib/routing_nb.h2
-rw-r--r--lib/routing_nb_config.c5
-rw-r--r--lib/vrf.c12
-rw-r--r--lib/vty.c84
-rw-r--r--lib/vty.h5
-rw-r--r--lib/yang.c28
-rw-r--r--lib/yang.h16
-rw-r--r--lib/zebra.h3
-rw-r--r--mgmtd/mgmt.h1
-rw-r--r--mgmtd/mgmt_be_adapter.c234
-rw-r--r--mgmtd/mgmt_be_adapter.h10
-rw-r--r--mgmtd/mgmt_ds.c30
-rw-r--r--mgmtd/mgmt_fe_adapter.c372
-rw-r--r--mgmtd/mgmt_fe_adapter.h12
-rw-r--r--mgmtd/mgmt_main.c13
-rw-r--r--mgmtd/mgmt_testc.c219
-rw-r--r--mgmtd/mgmt_txn.c380
-rw-r--r--mgmtd/mgmt_txn.h8
-rw-r--r--mgmtd/mgmt_vty.c31
-rw-r--r--mgmtd/subdir.am9
-rw-r--r--nhrpd/nhrpd.h1
-rw-r--r--ospf6d/ospf6_main.c3
-rw-r--r--ospfd/ospf_api.h4
-rw-r--r--ospfd/ospfd.h3
-rw-r--r--pathd/path_main.c2
-rw-r--r--pbrd/pbr_main.c2
-rw-r--r--pimd/pimd.h3
-rw-r--r--redhat/frr.pam4
-rw-r--r--redhat/frr.spec.in7
-rw-r--r--ripd/ripd.h1
-rw-r--r--ripngd/ripngd.h1
-rw-r--r--sharpd/sharp_main.c2
-rw-r--r--staticd/static_bfd.c16
-rw-r--r--staticd/static_main.c8
-rw-r--r--staticd/static_nb.h5
-rw-r--r--staticd/static_nb_config.c81
-rw-r--r--staticd/static_routes.c152
-rw-r--r--staticd/static_routes.h7
-rw-r--r--staticd/static_vrf.c110
-rw-r--r--staticd/static_vrf.h14
-rw-r--r--staticd/static_vty.c37
-rw-r--r--staticd/static_zebra.c7
-rw-r--r--tests/lib/test_grpc.cpp6
-rw-r--r--tests/topotests/bgp_aggregate_address_route_map/test_bgp_aggregate-address_route-map.py37
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py2
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf16
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/zebra.conf4
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py16
-rw-r--r--tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_down.py2
-rwxr-xr-xtests/topotests/lib/fe_client.py414
-rw-r--r--tests/topotests/mgmt_fe_client/fe_client.py103
-rw-r--r--tests/topotests/mgmt_fe_client/test_client.py1
l---------tests/topotests/mgmt_notif/oper.py1
-rw-r--r--tests/topotests/mgmt_notif/r1/frr.conf27
-rw-r--r--tests/topotests/mgmt_notif/r2/frr.conf27
-rw-r--r--tests/topotests/mgmt_notif/test_notif.py102
-rw-r--r--tests/topotests/mgmt_oper/r1/frr-simple.conf1
-rw-r--r--tests/topotests/mgmt_oper/simple-results/result-intf-eth0-only-config.json5
-rw-r--r--tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-all-tag.json13
-rw-r--r--tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-all.json7
-rw-r--r--tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-explicit.json5
-rw-r--r--tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-trim.json3
-rw-r--r--tests/topotests/mgmt_oper/simple-results/result-intf-eth0-with-config.json3
-rw-r--r--tests/topotests/mgmt_oper/test_simple.py21
-rw-r--r--tools/gen_northbound_callbacks.c177
-rw-r--r--vrrpd/vrrp_main.c2
-rw-r--r--vtysh/vtysh.c2
-rw-r--r--yang/ietf/ietf-netconf-acm.yang464
-rw-r--r--yang/ietf/ietf-netconf-with-defaults.yang139
-rw-r--r--yang/ietf/ietf-netconf.yang933
-rw-r--r--yang/subdir.am3
-rw-r--r--zebra/dplane_fpm_nl.c9
-rw-r--r--zebra/zebra_cli.c7
-rw-r--r--zebra/zebra_rib.c1
-rw-r--r--zebra/zserv.h3
120 files changed, 4462 insertions, 1538 deletions
diff --git a/.gitignore b/.gitignore
index a66e3ccd3c..07cdb11a21 100644
--- a/.gitignore
+++ b/.gitignore
@@ -117,3 +117,4 @@ refix
/test-suite.log
pceplib/test/*.log
pceplib/test/*.trs
+/tests/topotests/lib/mgmt_pb2.py
diff --git a/babeld/babeld.h b/babeld/babeld.h
index 619550f651..5573719ab3 100644
--- a/babeld/babeld.h
+++ b/babeld/babeld.h
@@ -53,7 +53,6 @@ Copyright 2011 by Matthieu Boutier and Juliusz Chroboczek
#endif
-#define BABEL_VTY_PORT 2609
#define BABEL_DEFAULT_CONFIG "babeld.conf"
/* Values in milliseconds */
diff --git a/bfdd/bfdd.c b/bfdd/bfdd.c
index 1a89b9b351..243cf5c129 100644
--- a/bfdd/bfdd.c
+++ b/bfdd/bfdd.c
@@ -119,7 +119,7 @@ static const struct frr_yang_module_info *const bfdd_yang_modules[] = {
/* clang-format off */
FRR_DAEMON_INFO(bfdd, BFD,
- .vty_port = 2617,
+ .vty_port = BFDD_VTY_PORT,
.proghelp = "Implementation of the BFD protocol.",
.signals = bfd_signals,
diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c
index 2ca3ffaa1a..a81f288c7a 100644
--- a/bgpd/bgp_advertise.c
+++ b/bgpd/bgp_advertise.c
@@ -169,7 +169,7 @@ void bgp_adj_in_set(struct bgp_dest *dest, struct peer *peer, struct attr *attr,
for (adj = dest->adj_in; adj; adj = adj->next) {
if (adj->peer == peer && adj->addpath_rx_id == addpath_id) {
- if (adj->attr != attr) {
+ if (!attrhash_cmp(adj->attr, attr)) {
bgp_attr_unintern(&adj->attr);
adj->attr = bgp_attr_intern(attr);
}
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index 75aa2ac7cc..edfbc6c835 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -864,6 +864,7 @@ bool attrhash_cmp(const void *p1, const void *p2)
attr1->df_alg == attr2->df_alg &&
attr1->nh_ifindex == attr2->nh_ifindex &&
attr1->nh_lla_ifindex == attr2->nh_lla_ifindex &&
+ attr1->nh_flags == attr2->nh_flags &&
attr1->distance == attr2->distance &&
srv6_l3vpn_same(attr1->srv6_l3vpn, attr2->srv6_l3vpn) &&
srv6_vpn_same(attr1->srv6_vpn, attr2->srv6_vpn) &&
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index d30155e6db..d78f04c6dd 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -155,10 +155,56 @@ struct attr {
uint32_t med;
uint32_t local_pref;
ifindex_t nh_ifindex;
+ uint8_t nh_flags;
+
+#define BGP_ATTR_NH_VALID 0x01
/* Path origin attribute */
uint8_t origin;
+ /* ES info */
+ uint8_t es_flags;
+ /* Path is not "locally-active" on the advertising VTEP. This is
+ * translated into an ARP-ND ECOM.
+ */
+#define ATTR_ES_PROXY_ADVERT (1 << 0)
+ /* Destination ES is present locally. This flag is set on local
+ * paths and sync paths
+ */
+#define ATTR_ES_IS_LOCAL (1 << 1)
+ /* There are one or more non-best paths from ES peers. Note that
+ * this flag is only set on the local MAC-IP paths in the VNI
+ * route table (not set in the global routing table). And only
+ * non-proxy advertisements from an ES peer can result in this
+ * flag being set.
+ */
+#define ATTR_ES_PEER_ACTIVE (1 << 2)
+ /* There are one or more non-best proxy paths from ES peers */
+#define ATTR_ES_PEER_PROXY (1 << 3)
+ /* An ES peer has router bit set - only applicable if
+ * ATTR_ES_PEER_ACTIVE is set
+ */
+#define ATTR_ES_PEER_ROUTER (1 << 4)
+
+ /* These two flags are only set on L3 routes installed in a
+ * VRF as a result of EVPN MAC-IP route
+ * XXX - while splitting up per-family attrs these need to be
+ * classified as non-EVPN
+ */
+#define ATTR_ES_L3_NHG_USE (1 << 5)
+#define ATTR_ES_L3_NHG_ACTIVE (1 << 6)
+#define ATTR_ES_L3_NHG (ATTR_ES_L3_NHG_USE | ATTR_ES_L3_NHG_ACTIVE)
+
+ /* NA router flag (R-bit) support in EVPN */
+ uint8_t router_flag;
+
+ /* Distance as applied by Route map */
+ uint8_t distance;
+
+ /* EVPN DF preference for DF election on local ESs */
+ uint8_t df_alg;
+ uint16_t df_pref;
+
/* PMSI tunnel type (RFC 6514). */
enum pta_type pmsi_tnl_type;
@@ -173,6 +219,9 @@ struct attr {
/* ifIndex corresponding to mp_nexthop_local. */
ifindex_t nh_lla_ifindex;
+ /* MPLS label */
+ mpls_label_t label;
+
/* Extended Communities attribute. */
struct ecommunity *ecommunity;
@@ -214,58 +263,18 @@ struct attr {
/* Flag for default gateway extended community in EVPN */
uint8_t default_gw;
- /* NA router flag (R-bit) support in EVPN */
- uint8_t router_flag;
-
- /* ES info */
- uint8_t es_flags;
- /* Path is not "locally-active" on the advertising VTEP. This is
- * translated into an ARP-ND ECOM.
- */
-#define ATTR_ES_PROXY_ADVERT (1 << 0)
- /* Destination ES is present locally. This flag is set on local
- * paths and sync paths
- */
-#define ATTR_ES_IS_LOCAL (1 << 1)
- /* There are one or more non-best paths from ES peers. Note that
- * this flag is only set on the local MAC-IP paths in the VNI
- * route table (not set in the global routing table). And only
- * non-proxy advertisements from an ES peer can result in this
- * flag being set.
- */
-#define ATTR_ES_PEER_ACTIVE (1 << 2)
- /* There are one or more non-best proxy paths from ES peers */
-#define ATTR_ES_PEER_PROXY (1 << 3)
- /* An ES peer has router bit set - only applicable if
- * ATTR_ES_PEER_ACTIVE is set
- */
-#define ATTR_ES_PEER_ROUTER (1 << 4)
-
- /* These two flags are only set on L3 routes installed in a
- * VRF as a result of EVPN MAC-IP route
- * XXX - while splitting up per-family attrs these need to be
- * classified as non-EVPN
- */
-#define ATTR_ES_L3_NHG_USE (1 << 5)
-#define ATTR_ES_L3_NHG_ACTIVE (1 << 6)
-#define ATTR_ES_L3_NHG (ATTR_ES_L3_NHG_USE | ATTR_ES_L3_NHG_ACTIVE)
-
/* route tag */
route_tag_t tag;
/* Label index */
uint32_t label_index;
- /* MPLS label */
- mpls_label_t label;
-
/* SRv6 VPN SID */
struct bgp_attr_srv6_vpn *srv6_vpn;
/* SRv6 L3VPN SID */
struct bgp_attr_srv6_l3vpn *srv6_l3vpn;
- uint16_t encap_tunneltype; /* grr */
struct bgp_attr_encap_subtlv *encap_subtlvs; /* rfc5512 */
#ifdef ENABLE_BGP_VNC
@@ -287,8 +296,7 @@ struct attr {
/* EVPN local router-mac */
struct ethaddr rmac;
- /* Distance as applied by Route map */
- uint8_t distance;
+ uint16_t encap_tunneltype;
/* rmap set table */
uint32_t rmap_table_id;
@@ -302,10 +310,6 @@ struct attr {
/* SR-TE Color */
uint32_t srte_color;
- /* EVPN DF preference and algorithm for DF election on local ESs */
- uint16_t df_pref;
- uint8_t df_alg;
-
/* Nexthop type */
enum nexthop_types_t nh_type;
diff --git a/bgpd/bgp_damp.h b/bgpd/bgp_damp.h
index 4aff52c09c..6033c34bfd 100644
--- a/bgpd/bgp_damp.h
+++ b/bgpd/bgp_damp.h
@@ -74,8 +74,8 @@ struct bgp_damp_config {
unsigned int ceiling; /* Max value a penalty can attain */
unsigned int decay_rate_per_tick; /* Calculated from half-life */
unsigned int decay_array_size; /* Calculated using config parameters */
- double scale_factor;
unsigned int reuse_scale_factor;
+ double scale_factor;
/* Decay array per-set based. */
double *decay_array;
@@ -86,6 +86,7 @@ struct bgp_damp_config {
/* Reuse list array per-set based. */
struct bgp_damp_info **reuse_list;
int reuse_offset;
+ safi_t safi;
/* All dampening information which is not on reuse list. */
struct bgp_damp_info *no_reuse_list;
@@ -94,7 +95,6 @@ struct bgp_damp_config {
struct event *t_reuse;
afi_t afi;
- safi_t safi;
};
#define BGP_DAMP_NONE 0
diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c
index 38aa4f1c38..0764f1ed18 100644
--- a/bgpd/bgp_memory.c
+++ b/bgpd/bgp_memory.c
@@ -42,6 +42,7 @@ DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA, "BGP ancillary route info");
DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA_EVPN, "BGP extra info for EVPN");
DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA_FS, "BGP extra info for flowspec");
DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA_VRFLEAK, "BGP extra info for vrf leaking");
+DEFINE_MTYPE(BGPD, BGP_ROUTE_EXTRA_VNC, "BGP extra info for vnc");
DEFINE_MTYPE(BGPD, BGP_CONN, "BGP connected");
DEFINE_MTYPE(BGPD, BGP_STATIC, "BGP static");
DEFINE_MTYPE(BGPD, BGP_ADVERTISE_ATTR, "BGP adv attr");
diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h
index 8c9524e2ad..29584cd780 100644
--- a/bgpd/bgp_memory.h
+++ b/bgpd/bgp_memory.h
@@ -38,6 +38,7 @@ DECLARE_MTYPE(BGP_ROUTE_EXTRA);
DECLARE_MTYPE(BGP_ROUTE_EXTRA_EVPN);
DECLARE_MTYPE(BGP_ROUTE_EXTRA_FS);
DECLARE_MTYPE(BGP_ROUTE_EXTRA_VRFLEAK);
+DECLARE_MTYPE(BGP_ROUTE_EXTRA_VNC);
DECLARE_MTYPE(BGP_CONN);
DECLARE_MTYPE(BGP_STATIC);
DECLARE_MTYPE(BGP_ADVERTISE_ATTR);
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index 5aa752d6e7..32436861f4 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -1034,13 +1034,19 @@ static bool leak_update_nexthop_valid(struct bgp *to_bgp, struct bgp_dest *bn,
else if (bpi_ultimate->type == ZEBRA_ROUTE_BGP &&
bpi_ultimate->sub_type == BGP_ROUTE_STATIC && table &&
(table->safi == SAFI_UNICAST ||
- table->safi == SAFI_LABELED_UNICAST) &&
- !CHECK_FLAG(bgp_nexthop->flags, BGP_FLAG_IMPORT_CHECK)) {
- /* if the route is defined with the "network <prefix>" command
- * and "no bgp network import-check" is set,
- * then mark the nexthop as valid.
- */
- nh_valid = true;
+ table->safi == SAFI_LABELED_UNICAST)) {
+ /* the route is defined with the "network <prefix>" command */
+
+ if (CHECK_FLAG(bgp_nexthop->flags, BGP_FLAG_IMPORT_CHECK))
+ nh_valid = bgp_find_or_add_nexthop(to_bgp, bgp_nexthop,
+ afi, SAFI_UNICAST,
+ bpi_ultimate, NULL,
+ 0, p);
+ else
+ /* if "no bgp network import-check" is set,
+ * then mark the nexthop as valid.
+ */
+ nh_valid = true;
} else
/*
* TBD do we need to do anything about the
@@ -2084,6 +2090,7 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
uint32_t num_labels = 0;
int nexthop_self_flag = 1;
struct bgp_path_info *bpi_ultimate = NULL;
+ struct bgp_path_info *bpi;
int origin_local = 0;
struct bgp *src_vrf;
struct interface *ifp;
@@ -2173,6 +2180,20 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
community_strip_accept_own(&static_attr);
+ bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p, NULL);
+
+ for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) {
+ if (bpi->extra && bpi->extra->vrfleak &&
+ bpi->extra->vrfleak->parent == path_vpn)
+ break;
+ }
+
+ if (bpi && leak_update_nexthop_valid(to_bgp, bn, &static_attr, afi, safi,
+ path_vpn, bpi, src_vrf, p, debug))
+ SET_FLAG(static_attr.nh_flags, BGP_ATTR_NH_VALID);
+ else
+ UNSET_FLAG(static_attr.nh_flags, BGP_ATTR_NH_VALID);
+
/*
* Nexthop: stash and clear
*
@@ -2265,8 +2286,6 @@ static void vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
new_attr = bgp_attr_intern(&static_attr);
bgp_attr_flush(&static_attr);
- bn = bgp_afi_node_get(to_bgp->rib[afi][safi], afi, safi, p, NULL);
-
/*
* ensure labels are copied
*
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c
index 05fd0dc4e7..e2c103bb52 100644
--- a/bgpd/bgp_nht.c
+++ b/bgpd/bgp_nht.c
@@ -406,7 +406,7 @@ int bgp_find_or_add_nexthop(struct bgp *bgp_route, struct bgp *bgp_nexthop,
if (pi && is_route_parent_evpn(pi))
bnc->is_evpn_gwip_nexthop = true;
- if (is_bgp_static_route) {
+ if (is_bgp_static_route && !CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE)) {
SET_FLAG(bnc->flags, BGP_STATIC_ROUTE);
/* If we're toggling the type, re-register */
@@ -903,7 +903,10 @@ void bgp_nexthop_update(struct vrf *vrf, struct prefix *match,
{
struct bgp_nexthop_cache_head *tree = NULL;
struct bgp_nexthop_cache *bnc_nhc, *bnc_import;
- struct bgp *bgp;
+ struct bgp *bgp, *bgp_default;
+ struct bgp_path_info *pi;
+ struct bgp_dest *dest;
+ safi_t safi;
afi_t afi;
if (!vrf->info) {
@@ -918,25 +921,38 @@ void bgp_nexthop_update(struct vrf *vrf, struct prefix *match,
tree = &bgp->nexthop_cache_table[afi];
bnc_nhc = bnc_find(tree, match, nhr->srte_color, 0);
- if (!bnc_nhc) {
- if (BGP_DEBUG(nht, NHT))
- zlog_debug("parse nexthop update %pFX(%u)(%s): bnc info not found for nexthop cache",
- &nhr->prefix, nhr->srte_color,
- bgp->name_pretty);
- } else
+ if (bnc_nhc)
bgp_process_nexthop_update(bnc_nhc, nhr, false);
+ else if (BGP_DEBUG(nht, NHT))
+ zlog_debug("parse nexthop update %pFX(%u)(%s): bnc info not found for nexthop cache",
+ &nhr->prefix, nhr->srte_color,
+ bgp->name_pretty);
tree = &bgp->import_check_table[afi];
bnc_import = bnc_find(tree, match, nhr->srte_color, 0);
- if (!bnc_import) {
- if (BGP_DEBUG(nht, NHT))
- zlog_debug("parse nexthop update %pFX(%u)(%s): bnc info not found for import check",
- &nhr->prefix, nhr->srte_color,
- bgp->name_pretty);
- } else
+ if (bnc_import) {
bgp_process_nexthop_update(bnc_import, nhr, true);
+ bgp_default = bgp_get_default();
+ safi = nhr->safi;
+ if (bgp != bgp_default && bgp->rib[afi][safi]) {
+ dest = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi,
+ match, NULL);
+
+ for (pi = bgp_dest_get_bgp_path_info(dest); pi;
+ pi = pi->next)
+ if (pi->peer == bgp->peer_self &&
+ pi->type == ZEBRA_ROUTE_BGP &&
+ pi->sub_type == BGP_ROUTE_STATIC)
+ vpn_leak_from_vrf_update(bgp_default,
+ bgp, pi);
+ }
+ } else if (BGP_DEBUG(nht, NHT))
+ zlog_debug("parse nexthop update %pFX(%u)(%s): bnc info not found for import check",
+ &nhr->prefix, nhr->srte_color,
+ bgp->name_pretty);
+
/*
* HACK: if any BGP route is dependant on an SR-policy that doesn't
* exist, zebra will never send NH updates relative to that policy. In
diff --git a/bgpd/bgp_rd.h b/bgpd/bgp_rd.h
index e38c2fad3b..93dda17236 100644
--- a/bgpd/bgp_rd.h
+++ b/bgpd/bgp_rd.h
@@ -41,8 +41,8 @@ struct rd_as {
struct rd_ip {
uint16_t type;
- struct in_addr ip;
uint16_t val;
+ struct in_addr ip;
};
#ifdef ENABLE_BGP_VNC
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 8bcbd3dd8c..b8d6c660b7 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -263,6 +263,10 @@ void bgp_path_info_extra_free(struct bgp_path_info_extra **extra)
XFREE(MTYPE_BGP_ROUTE_EXTRA_FS, e->flowspec);
if (e->vrfleak)
XFREE(MTYPE_BGP_ROUTE_EXTRA_VRFLEAK, e->vrfleak);
+#ifdef ENABLE_BGP_VNC
+ if (e->vnc)
+ XFREE(MTYPE_BGP_ROUTE_EXTRA_VNC, e->vnc);
+#endif
XFREE(MTYPE_BGP_ROUTE_EXTRA, *extra);
}
@@ -7369,8 +7373,9 @@ static void bgp_aggregate_install(
* If the aggregate information has not changed
* no need to re-install it again.
*/
- if (pi && bgp_aggregate_info_same(pi, origin, aspath, community,
- ecommunity, lcommunity)) {
+ if (pi && (!aggregate->rmap.changed &&
+ bgp_aggregate_info_same(pi, origin, aspath, community,
+ ecommunity, lcommunity))) {
bgp_dest_unlock_node(dest);
if (aspath)
@@ -8377,6 +8382,7 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi,
aggregate->rmap.name =
XSTRDUP(MTYPE_ROUTE_MAP_NAME, rmap);
aggregate->rmap.map = route_map_lookup_by_name(rmap);
+ aggregate->rmap.changed = true;
route_map_counter_increment(aggregate->rmap.map);
}
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index 0599e8dce1..2d82f0f206 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -193,33 +193,9 @@ struct bgp_path_info_extra_vrfleak {
struct prefix nexthop_orig;
};
-/* Ancillary information to struct bgp_path_info,
- * used for uncommonly used data (aggregation, MPLS, etc.)
- * and lazily allocated to save memory.
- */
-struct bgp_path_info_extra {
- /* Pointer to dampening structure. */
- struct bgp_damp_info *damp_info;
-
- /** List of aggregations that suppress this path. */
- struct list *aggr_suppressors;
-
- /* Nexthop reachability check. */
- uint32_t igpmetric;
-
- /* MPLS label(s) - VNI(s) for EVPN-VxLAN */
- mpls_label_t label[BGP_MAX_LABELS];
- uint32_t num_labels;
-
- /* timestamp of the rib installation */
- time_t bgp_rib_uptime;
-
- /*For EVPN*/
- struct bgp_path_info_extra_evpn *evpn;
-
#ifdef ENABLE_BGP_VNC
+struct bgp_path_info_extra_vnc {
union {
-
struct {
void *rfapi_handle; /* export: NVE advertising this
route */
@@ -242,8 +218,36 @@ struct bgp_path_info_extra {
struct prefix aux_prefix; /* AFI_L2VPN: the IP addr,
if family set */
} import;
-
} vnc;
+};
+#endif
+
+/* Ancillary information to struct bgp_path_info,
+ * used for uncommonly used data (aggregation, MPLS, etc.)
+ * and lazily allocated to save memory.
+ */
+struct bgp_path_info_extra {
+ /* Pointer to dampening structure. */
+ struct bgp_damp_info *damp_info;
+
+ /** List of aggregations that suppress this path. */
+ struct list *aggr_suppressors;
+
+ /* Nexthop reachability check. */
+ uint32_t igpmetric;
+
+ /* MPLS label(s) - VNI(s) for EVPN-VxLAN */
+ mpls_label_t label[BGP_MAX_LABELS];
+ uint32_t num_labels;
+
+ /* timestamp of the rib installation */
+ time_t bgp_rib_uptime;
+
+ /*For EVPN*/
+ struct bgp_path_info_extra_evpn *evpn;
+
+#ifdef ENABLE_BGP_VNC
+ struct bgp_path_info_extra_vnc *vnc;
#endif
/* For flowspec*/
@@ -369,6 +373,8 @@ struct bgp_static {
/* Import check status. */
uint8_t valid;
+ uint16_t encap_tunneltype;
+
/* IGP metric. */
uint32_t igpmetric;
@@ -394,7 +400,6 @@ struct bgp_static {
/* EVPN */
esi_t *eth_s_id;
struct ethaddr *router_mac;
- uint16_t encap_tunneltype;
struct prefix gatewayIp;
};
@@ -415,10 +420,22 @@ struct bgp_aggregate {
/* AS set generation. */
uint8_t as_set;
+ /* Optional modify flag to override ORIGIN */
+ uint8_t origin;
+
+ /** Are there MED mismatches? */
+ bool med_mismatched;
+ /* MED matching state. */
+ /** Did we get the first MED value? */
+ bool med_initialized;
+ /** Match only equal MED. */
+ bool match_med;
+
/* Route-map for aggregated route. */
struct {
char *name;
struct route_map *map;
+ bool changed;
} rmap;
/* Suppress-count. */
@@ -430,9 +447,6 @@ struct bgp_aggregate {
/* Count of routes of origin type egp under this aggregate. */
unsigned long egp_origin_count;
- /* Optional modify flag to override ORIGIN */
- uint8_t origin;
-
/* Hash containing the communities of all the
* routes under this aggregate.
*/
@@ -468,13 +482,6 @@ struct bgp_aggregate {
/* SAFI configuration. */
safi_t safi;
- /** Match only equal MED. */
- bool match_med;
- /* MED matching state. */
- /** Did we get the first MED value? */
- bool med_initialized;
- /** Are there MED mismatches? */
- bool med_mismatched;
/** MED value found in current group. */
uint32_t med_matched_value;
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 382e8ae409..36e04c5e68 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -4596,6 +4596,7 @@ static void bgp_route_map_process_update(struct bgp *bgp, const char *rmap_name,
route_map_counter_increment(map);
aggregate->rmap.map = map;
+ aggregate->rmap.changed = true;
matched = true;
}
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index a1593421be..9005169769 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -888,10 +888,10 @@ struct peer_group {
struct bgp_notify {
uint8_t code;
uint8_t subcode;
- char *data;
bgp_size_t length;
- uint8_t *raw_data;
bool hard_reset;
+ char *data;
+ uint8_t *raw_data;
};
/* Next hop self address. */
@@ -1890,11 +1890,11 @@ struct bgp_nlri {
/* SAFI. */
uint8_t safi; /* iana_safi_t */
- /* Pointer to NLRI byte stream. */
- uint8_t *nlri;
-
/* Length of whole NLRI. */
bgp_size_t length;
+
+ /* Pointer to NLRI byte stream. */
+ uint8_t *nlri;
};
/* BGP versions. */
@@ -2064,7 +2064,6 @@ struct bgp_nlri {
#define BGP_UPTIME_LEN 25
/* Default configuration settings for bgpd. */
-#define BGP_VTY_PORT 2605
#define BGP_DEFAULT_CONFIG "bgpd.conf"
/* BGP Dynamic Neighbors feature */
diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c
index a2c86d1eae..382af05c24 100644
--- a/bgpd/rfapi/rfapi.c
+++ b/bgpd/rfapi/rfapi.c
@@ -366,20 +366,19 @@ void del_vnc_route(struct rfapi_descriptor *rfd,
for (bpi = (bn ? bgp_dest_get_bgp_path_info(bn) : NULL); bpi;
bpi = bpi->next) {
-
vnc_zlog_debug_verbose(
"%s: trying bpi=%p, bpi->peer=%p, bpi->type=%d, bpi->sub_type=%d, bpi->extra->vnc.export.rfapi_handle=%p, local_pref=%" PRIu64,
__func__, bpi, bpi->peer, bpi->type, bpi->sub_type,
- (bpi->extra ? bpi->extra->vnc.export.rfapi_handle
+ (bpi->extra ? bpi->extra->vnc->vnc.export.rfapi_handle
: NULL),
CHECK_FLAG(bpi->attr->flag,
ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF)
- ? bpi->attr->local_pref : 0));
-
- if (bpi->peer == peer && bpi->type == type
- && bpi->sub_type == sub_type && bpi->extra
- && bpi->extra->vnc.export.rfapi_handle == (void *)rfd) {
+ ? bpi->attr->local_pref
+ : 0));
+ if (bpi->peer == peer && bpi->type == type &&
+ bpi->sub_type == sub_type && bpi->extra &&
+ bpi->extra->vnc->vnc.export.rfapi_handle == (void *)rfd) {
vnc_zlog_debug_verbose("%s: matched it", __func__);
break;
@@ -392,8 +391,8 @@ void del_vnc_route(struct rfapi_descriptor *rfd,
* route. Leave the route itself in place.
* TBD add return code reporting of success/failure
*/
- if (!bpi || !bpi->extra
- || !bpi->extra->vnc.export.local_nexthops) {
+ if (!bpi || !bpi->extra ||
+ !bpi->extra->vnc->vnc.export.local_nexthops) {
/*
* no local nexthops
*/
@@ -409,16 +408,16 @@ void del_vnc_route(struct rfapi_descriptor *rfd,
struct listnode *node;
struct rfapi_nexthop *pLnh = NULL;
- for (ALL_LIST_ELEMENTS_RO(bpi->extra->vnc.export.local_nexthops,
+ for (ALL_LIST_ELEMENTS_RO(bpi->extra->vnc->vnc.export
+ .local_nexthops,
node, pLnh)) {
-
if (prefix_same(&pLnh->addr, &lnh->addr)) {
break;
}
}
if (pLnh) {
- listnode_delete(bpi->extra->vnc.export.local_nexthops,
+ listnode_delete(bpi->extra->vnc->vnc.export.local_nexthops,
pLnh);
/* silly rabbit, listnode_delete doesn't invoke
@@ -459,8 +458,8 @@ void del_vnc_route(struct rfapi_descriptor *rfd,
/*
* Delete local_nexthops list
*/
- if (bpi->extra && bpi->extra->vnc.export.local_nexthops)
- list_delete(&bpi->extra->vnc.export.local_nexthops);
+ if (bpi->extra && bpi->extra->vnc->vnc.export.local_nexthops)
+ list_delete(&bpi->extra->vnc->vnc.export.local_nexthops);
bgp_aggregate_decrement(bgp, p, bpi, afi, safi);
bgp_path_info_delete(bn, bpi);
@@ -902,11 +901,10 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
*/
for (bpi = bgp_dest_get_bgp_path_info(bn); bpi; bpi = bpi->next) {
/* probably only need to check
- * bpi->extra->vnc.export.rfapi_handle */
- if (bpi->peer == rfd->peer && bpi->type == type
- && bpi->sub_type == sub_type && bpi->extra
- && bpi->extra->vnc.export.rfapi_handle == (void *)rfd) {
-
+ * bpi->extra->vnc->vnc.export.rfapi_handle */
+ if (bpi->peer == rfd->peer && bpi->type == type &&
+ bpi->sub_type == sub_type && bpi->extra &&
+ bpi->extra->vnc->vnc.export.rfapi_handle == (void *)rfd) {
break;
}
}
@@ -918,11 +916,11 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
* what is advertised via BGP
*/
if (lnh) {
- if (!bpi->extra->vnc.export.local_nexthops) {
+ if (!bpi->extra->vnc->vnc.export.local_nexthops) {
/* TBD make arrangements to free when needed */
- bpi->extra->vnc.export.local_nexthops =
+ bpi->extra->vnc->vnc.export.local_nexthops =
list_new();
- bpi->extra->vnc.export.local_nexthops->del =
+ bpi->extra->vnc->vnc.export.local_nexthops->del =
rfapi_nexthop_free;
}
@@ -932,10 +930,9 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
struct listnode *node;
struct rfapi_nexthop *pLnh = NULL;
- for (ALL_LIST_ELEMENTS_RO(
- bpi->extra->vnc.export.local_nexthops,
- node, pLnh)) {
-
+ for (ALL_LIST_ELEMENTS_RO(bpi->extra->vnc->vnc.export
+ .local_nexthops,
+ node, pLnh)) {
if (prefix_same(&pLnh->addr, &lnh->addr)) {
break;
}
@@ -946,9 +943,9 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
*/
if (!pLnh) {
pLnh = rfapi_nexthop_new(lnh);
- listnode_add(
- bpi->extra->vnc.export.local_nexthops,
- pLnh);
+ listnode_add(bpi->extra->vnc->vnc.export
+ .local_nexthops,
+ pLnh);
}
}
@@ -1020,7 +1017,9 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
/* save backref to rfapi handle */
bgp_path_info_extra_get(new);
- new->extra->vnc.export.rfapi_handle = (void *)rfd;
+ new->extra->vnc = XCALLOC(MTYPE_BGP_ROUTE_EXTRA_VNC,
+ sizeof(struct bgp_path_info_extra_vnc));
+ new->extra->vnc->vnc.export.rfapi_handle = (void *)rfd;
encode_label(label_val, &new->extra->label[0]);
/* debug */
diff --git a/bgpd/rfapi/rfapi_import.c b/bgpd/rfapi/rfapi_import.c
index f9789adad2..168b8e4c1e 100644
--- a/bgpd/rfapi/rfapi_import.c
+++ b/bgpd/rfapi/rfapi_import.c
@@ -397,18 +397,22 @@ int rfapiGetUnAddrOfVpnBi(struct bgp_path_info *bpi, struct prefix *p)
* advertisement
*/
if (bpi->extra) {
- switch (bpi->extra->vnc.import.un_family) {
+ switch (bpi->extra->vnc->vnc.import.un_family) {
case AF_INET:
if (p) {
- p->family = bpi->extra->vnc.import.un_family;
- p->u.prefix4 = bpi->extra->vnc.import.un.addr4;
+ p->family =
+ bpi->extra->vnc->vnc.import.un_family;
+ p->u.prefix4 =
+ bpi->extra->vnc->vnc.import.un.addr4;
p->prefixlen = IPV4_MAX_BITLEN;
}
return 0;
case AF_INET6:
if (p) {
- p->family = bpi->extra->vnc.import.un_family;
- p->u.prefix6 = bpi->extra->vnc.import.un.addr6;
+ p->family =
+ bpi->extra->vnc->vnc.import.un_family;
+ p->u.prefix6 =
+ bpi->extra->vnc->vnc.import.un.addr6;
p->prefixlen = IPV6_MAX_BITLEN;
}
return 0;
@@ -444,9 +448,11 @@ static struct bgp_path_info *rfapiBgpInfoCreate(struct attr *attr,
new->attr = bgp_attr_intern(attr);
bgp_path_info_extra_get(new);
+ new->extra->vnc = XCALLOC(MTYPE_BGP_ROUTE_EXTRA_VNC,
+ sizeof(struct bgp_path_info_extra_vnc));
if (prd) {
- new->extra->vnc.import.rd = *prd;
- new->extra->vnc.import.create_time = monotime(NULL);
+ new->extra->vnc->vnc.import.rd = *prd;
+ new->extra->vnc->vnc.import.create_time = monotime(NULL);
}
if (label)
encode_label(*label, &new->extra->label[0]);
@@ -811,13 +817,13 @@ static void rfapiBgpInfoChainFree(struct bgp_path_info *bpi)
* If there is a timer waiting to delete this bpi, cancel
* the timer and delete immediately
*/
- if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)
- && bpi->extra->vnc.import.timer) {
+ if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) &&
+ bpi->extra->vnc->vnc.import.timer) {
struct rfapi_withdraw *wcb =
- EVENT_ARG(bpi->extra->vnc.import.timer);
+ EVENT_ARG(bpi->extra->vnc->vnc.import.timer);
XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
- EVENT_OFF(bpi->extra->vnc.import.timer);
+ EVENT_OFF(bpi->extra->vnc->vnc.import.timer);
}
next = bpi->next;
@@ -1105,15 +1111,15 @@ static int rfapiVpnBiSamePtUn(struct bgp_path_info *bpi1,
*/
if (rfapiGetVncTunnelUnAddr(bpi1->attr, &pfx_un1)) {
if (bpi1->extra) {
- pfx_un1.family = bpi1->extra->vnc.import.un_family;
- switch (bpi1->extra->vnc.import.un_family) {
+ pfx_un1.family = bpi1->extra->vnc->vnc.import.un_family;
+ switch (bpi1->extra->vnc->vnc.import.un_family) {
case AF_INET:
pfx_un1.u.prefix4 =
- bpi1->extra->vnc.import.un.addr4;
+ bpi1->extra->vnc->vnc.import.un.addr4;
break;
case AF_INET6:
pfx_un1.u.prefix6 =
- bpi1->extra->vnc.import.un.addr6;
+ bpi1->extra->vnc->vnc.import.un.addr6;
break;
default:
pfx_un1.family = AF_UNSPEC;
@@ -1124,15 +1130,15 @@ static int rfapiVpnBiSamePtUn(struct bgp_path_info *bpi1,
if (rfapiGetVncTunnelUnAddr(bpi2->attr, &pfx_un2)) {
if (bpi2->extra) {
- pfx_un2.family = bpi2->extra->vnc.import.un_family;
- switch (bpi2->extra->vnc.import.un_family) {
+ pfx_un2.family = bpi2->extra->vnc->vnc.import.un_family;
+ switch (bpi2->extra->vnc->vnc.import.un_family) {
case AF_INET:
pfx_un2.u.prefix4 =
- bpi2->extra->vnc.import.un.addr4;
+ bpi2->extra->vnc->vnc.import.un.addr4;
break;
case AF_INET6:
pfx_un2.u.prefix6 =
- bpi2->extra->vnc.import.un.addr6;
+ bpi2->extra->vnc->vnc.import.un.addr6;
break;
default:
pfx_un2.family = AF_UNSPEC;
@@ -1237,9 +1243,8 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix,
new->prefix = *rprefix;
- if (bpi->extra
- && decode_rd_type(bpi->extra->vnc.import.rd.val)
- == RD_TYPE_VNC_ETH) {
+ if (bpi->extra && decode_rd_type(bpi->extra->vnc->vnc.import.rd.val) ==
+ RD_TYPE_VNC_ETH) {
/* ethernet */
struct rfapi_vn_option *vo;
@@ -1258,7 +1263,8 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix,
&vo->v.l2addr.tag_id);
/* local_nve_id comes from lower byte of RD type */
- vo->v.l2addr.local_nve_id = bpi->extra->vnc.import.rd.val[1];
+ vo->v.l2addr.local_nve_id =
+ bpi->extra->vnc->vnc.import.rd.val[1];
/* label comes from MP_REACH_NLRI label */
vo->v.l2addr.label = decode_label(&bpi->extra->label[0]);
@@ -1269,8 +1275,9 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix,
* If there is an auxiliary prefix (i.e., host IP address),
* use it as the nexthop prefix instead of the query prefix
*/
- if (bpi->extra->vnc.import.aux_prefix.family) {
- rfapiQprefix2Rprefix(&bpi->extra->vnc.import.aux_prefix,
+ if (bpi->extra->vnc->vnc.import.aux_prefix.family) {
+ rfapiQprefix2Rprefix(&bpi->extra->vnc->vnc.import
+ .aux_prefix,
&new->prefix);
}
}
@@ -1371,15 +1378,16 @@ rfapiRouteInfo2NextHopEntry(struct rfapi_ip_prefix *rprefix,
/*
* use cached UN address from ENCAP route
*/
- new->un_address.addr_family = bpi->extra->vnc.import.un_family;
+ new->un_address.addr_family =
+ bpi->extra->vnc->vnc.import.un_family;
switch (new->un_address.addr_family) {
case AF_INET:
new->un_address.addr.v4 =
- bpi->extra->vnc.import.un.addr4;
+ bpi->extra->vnc->vnc.import.un.addr4;
break;
case AF_INET6:
new->un_address.addr.v6 =
- bpi->extra->vnc.import.un.addr6;
+ bpi->extra->vnc->vnc.import.un.addr6;
break;
default:
zlog_warn("%s: invalid UN addr family (%d) for bpi %p",
@@ -1506,7 +1514,7 @@ static int rfapiNhlAddNodeRoutes(
if (is_l2) {
/* L2 routes: semantic nexthop in aux_prefix; VN addr
* ain't it */
- pfx_vn = bpi->extra->vnc.import.aux_prefix;
+ pfx_vn = bpi->extra->vnc->vnc.import.aux_prefix;
} else {
rfapiNexthop2Prefix(bpi->attr, &pfx_vn);
}
@@ -1980,9 +1988,10 @@ static int rfapi_bi_peer_rd_cmp(const void *b1, const void *b2)
/*
* compare RDs
*/
- return vnc_prefix_cmp(
- (const struct prefix *)&bpi1->extra->vnc.import.rd,
- (const struct prefix *)&bpi2->extra->vnc.import.rd);
+ return vnc_prefix_cmp((const struct prefix *)&bpi1->extra->vnc->vnc
+ .import.rd,
+ (const struct prefix *)&bpi2->extra->vnc->vnc
+ .import.rd);
}
/*
@@ -2007,8 +2016,8 @@ static int rfapi_bi_peer_rd_aux_cmp(const void *b1, const void *b2)
/*
* compare RDs
*/
- rc = vnc_prefix_cmp((struct prefix *)&bpi1->extra->vnc.import.rd,
- (struct prefix *)&bpi2->extra->vnc.import.rd);
+ rc = vnc_prefix_cmp((struct prefix *)&bpi1->extra->vnc->vnc.import.rd,
+ (struct prefix *)&bpi2->extra->vnc->vnc.import.rd);
if (rc) {
return rc;
}
@@ -2025,19 +2034,18 @@ static int rfapi_bi_peer_rd_aux_cmp(const void *b1, const void *b2)
* because there is no guarantee of the order the test key and
* the real key will be passed)
*/
- if ((bpi1->extra->vnc.import.aux_prefix.family == AF_ETHERNET
- && (bpi1->extra->vnc.import.aux_prefix.prefixlen == 1))
- || (bpi2->extra->vnc.import.aux_prefix.family == AF_ETHERNET
- && (bpi2->extra->vnc.import.aux_prefix.prefixlen == 1))) {
-
+ if ((bpi1->extra->vnc->vnc.import.aux_prefix.family == AF_ETHERNET &&
+ (bpi1->extra->vnc->vnc.import.aux_prefix.prefixlen == 1)) ||
+ (bpi2->extra->vnc->vnc.import.aux_prefix.family == AF_ETHERNET &&
+ (bpi2->extra->vnc->vnc.import.aux_prefix.prefixlen == 1))) {
/*
* wildcard aux address specified
*/
return 0;
}
- return vnc_prefix_cmp(&bpi1->extra->vnc.import.aux_prefix,
- &bpi2->extra->vnc.import.aux_prefix);
+ return vnc_prefix_cmp(&bpi1->extra->vnc->vnc.import.aux_prefix,
+ &bpi2->extra->vnc->vnc.import.aux_prefix);
}
@@ -2055,7 +2063,7 @@ static void rfapiItBiIndexAdd(struct agg_node *rn, /* Import table VPN node */
assert(bpi->extra);
vnc_zlog_debug_verbose("%s: bpi %p, peer %p, rd %pRDP", __func__, bpi,
- bpi->peer, &bpi->extra->vnc.import.rd);
+ bpi->peer, &bpi->extra->vnc->vnc.import.rd);
sl = RFAPI_RDINDEX_W_ALLOC(rn);
if (!sl) {
@@ -2092,11 +2100,10 @@ static void rfapiItBiIndexDump(struct agg_node *rn)
char buf[RD_ADDRSTRLEN];
char buf_aux_pfx[PREFIX_STRLEN];
- prefix_rd2str(
- &k->extra->vnc.import.rd, buf, sizeof(buf),
- bgp_get_asnotation(k->peer ? k->peer->bgp : NULL));
- if (k->extra->vnc.import.aux_prefix.family) {
- prefix2str(&k->extra->vnc.import.aux_prefix,
+ prefix_rd2str(&k->extra->vnc->vnc.import.rd, buf, sizeof(buf),
+ bgp_get_asnotation(k->peer ? k->peer->bgp : NULL));
+ if (k->extra->vnc->vnc.import.aux_prefix.family) {
+ prefix2str(&k->extra->vnc->vnc.import.aux_prefix,
buf_aux_pfx, sizeof(buf_aux_pfx));
} else
strlcpy(buf_aux_pfx, "(none)", sizeof(buf_aux_pfx));
@@ -2115,6 +2122,7 @@ static struct bgp_path_info *rfapiItBiIndexSearch(
int rc;
struct bgp_path_info bpi_fake = {0};
struct bgp_path_info_extra bpi_extra = {0};
+ struct bgp_path_info_extra_vnc bpi_extra_vnc = { 0 };
struct bgp_path_info *bpi_result;
sl = RFAPI_RDINDEX(rn);
@@ -2147,27 +2155,25 @@ static struct bgp_path_info *rfapiItBiIndexSearch(
for (bpi_result = rn->info; bpi_result;
bpi_result = bpi_result->next) {
#ifdef DEBUG_BI_SEARCH
- vnc_zlog_debug_verbose(
- "%s: bpi has prd=%pRDP, peer=%p", __func__,
- &bpi_result->extra->vnc.import.rd,
- bpi_result->peer);
+ vnc_zlog_debug_verbose("%s: bpi has prd=%pRDP, peer=%p",
+ __func__,
+ &bpi_result->extra->vnc->vnc
+ .import.rd,
+ bpi_result->peer);
#endif
- if (peer == bpi_result->peer
- && !prefix_cmp((struct prefix *)&bpi_result->extra
- ->vnc.import.rd,
- (struct prefix *)prd)) {
-
+ if (peer == bpi_result->peer &&
+ !prefix_cmp((struct prefix *)&bpi_result->extra->vnc
+ ->vnc.import.rd,
+ (struct prefix *)prd)) {
#ifdef DEBUG_BI_SEARCH
vnc_zlog_debug_verbose(
"%s: peer and RD same, doing aux_prefix check",
__func__);
#endif
- if (!aux_prefix
- || !prefix_cmp(
- aux_prefix,
- &bpi_result->extra->vnc.import
- .aux_prefix)) {
-
+ if (!aux_prefix ||
+ !prefix_cmp(aux_prefix,
+ &bpi_result->extra->vnc->vnc
+ .import.aux_prefix)) {
#ifdef DEBUG_BI_SEARCH
vnc_zlog_debug_verbose("%s: match",
__func__);
@@ -2181,13 +2187,14 @@ static struct bgp_path_info *rfapiItBiIndexSearch(
bpi_fake.peer = peer;
bpi_fake.extra = &bpi_extra;
- bpi_fake.extra->vnc.import.rd = *prd;
+ bpi_fake.extra->vnc = &bpi_extra_vnc;
+ bpi_fake.extra->vnc->vnc.import.rd = *prd;
if (aux_prefix) {
- bpi_fake.extra->vnc.import.aux_prefix = *aux_prefix;
+ bpi_fake.extra->vnc->vnc.import.aux_prefix = *aux_prefix;
} else {
/* wildcard */
- bpi_fake.extra->vnc.import.aux_prefix.family = AF_ETHERNET;
- bpi_fake.extra->vnc.import.aux_prefix.prefixlen = 1;
+ bpi_fake.extra->vnc->vnc.import.aux_prefix.family = AF_ETHERNET;
+ bpi_fake.extra->vnc->vnc.import.aux_prefix.prefixlen = 1;
}
rc = skiplist_search(sl, (void *)&bpi_fake, (void *)&bpi_result);
@@ -2213,7 +2220,7 @@ static void rfapiItBiIndexDel(struct agg_node *rn, /* Import table VPN node */
int rc;
vnc_zlog_debug_verbose("%s: bpi %p, peer %p, rd %pRDP", __func__, bpi,
- bpi->peer, &bpi->extra->vnc.import.rd);
+ bpi->peer, &bpi->extra->vnc->vnc.import.rd);
sl = RFAPI_RDINDEX(rn);
assert(sl);
@@ -2261,11 +2268,10 @@ rfapiMonitorEncapAdd(struct rfapi_import_table *import_table,
RFAPI_MONITOR_ENCAP_W_ALLOC(rn) = m;
/* for easy lookup when deleting vpn route */
- vpn_bpi->extra->vnc.import.hme = m;
+ vpn_bpi->extra->vnc->vnc.import.hme = m;
- vnc_zlog_debug_verbose(
- "%s: it=%p, vpn_bpi=%p, afi=%d, encap rn=%p, setting vpn_bpi->extra->vnc.import.hme=%p",
- __func__, import_table, vpn_bpi, afi, rn, m);
+ vnc_zlog_debug_verbose("%s: it=%p, vpn_bpi=%p, afi=%d, encap rn=%p, setting vpn_bpi->extra->vnc->vnc.import.hme=%p",
+ __func__, import_table, vpn_bpi, afi, rn, m);
RFAPI_CHECK_REFCOUNT(rn, SAFI_ENCAP, 0);
bgp_attr_intern(vpn_bpi->attr);
@@ -2279,7 +2285,7 @@ static void rfapiMonitorEncapDelete(struct bgp_path_info *vpn_bpi)
vnc_zlog_debug_verbose("%s: vpn_bpi=%p", __func__, vpn_bpi);
if (vpn_bpi->extra) {
struct rfapi_monitor_encap *hme =
- vpn_bpi->extra->vnc.import.hme;
+ vpn_bpi->extra->vnc->vnc.import.hme;
if (hme) {
@@ -2303,7 +2309,7 @@ static void rfapiMonitorEncapDelete(struct bgp_path_info *vpn_bpi)
agg_unlock_node(hme->rn); /* decr ref count */
XFREE(MTYPE_RFAPI_MONITOR_ENCAP, hme);
- vpn_bpi->extra->vnc.import.hme = NULL;
+ vpn_bpi->extra->vnc->vnc.import.hme = NULL;
}
}
}
@@ -2542,21 +2548,21 @@ static void rfapiCopyUnEncap2VPN(struct bgp_path_info *encap_bpi,
vnc_zlog_debug_verbose("%s: vpn_bpi->extra=%p", __func__,
vpn_bpi->extra);
- vpn_bpi->extra->vnc.import.un_family = AF_INET;
- vpn_bpi->extra->vnc.import.un.addr4 =
+ vpn_bpi->extra->vnc->vnc.import.un_family = AF_INET;
+ vpn_bpi->extra->vnc->vnc.import.un.addr4 =
encap_bpi->attr->mp_nexthop_global_in;
break;
case AF_INET6:
- vpn_bpi->extra->vnc.import.un_family = AF_INET6;
- vpn_bpi->extra->vnc.import.un.addr6 =
+ vpn_bpi->extra->vnc->vnc.import.un_family = AF_INET6;
+ vpn_bpi->extra->vnc->vnc.import.un.addr6 =
encap_bpi->attr->mp_nexthop_global;
break;
default:
zlog_warn("%s: invalid encap nexthop length: %d", __func__,
encap_bpi->attr->mp_nexthop_len);
- vpn_bpi->extra->vnc.import.un_family = AF_UNSPEC;
+ vpn_bpi->extra->vnc->vnc.import.un_family = AF_UNSPEC;
break;
}
}
@@ -2581,9 +2587,9 @@ rfapiWithdrawEncapUpdateCachedUn(struct rfapi_import_table *import_table,
__func__);
return 1;
}
- vpn_bpi->extra->vnc.import.un_family = AF_UNSPEC;
- memset(&vpn_bpi->extra->vnc.import.un, 0,
- sizeof(vpn_bpi->extra->vnc.import.un));
+ vpn_bpi->extra->vnc->vnc.import.un_family = AF_UNSPEC;
+ memset(&vpn_bpi->extra->vnc->vnc.import.un, 0,
+ sizeof(vpn_bpi->extra->vnc->vnc.import.un));
if (CHECK_FLAG(vpn_bpi->flags, BGP_PATH_VALID)) {
if (rfapiGetVncTunnelUnAddr(vpn_bpi->attr, NULL)) {
UNSET_FLAG(vpn_bpi->flags, BGP_PATH_VALID);
@@ -2754,9 +2760,9 @@ rfapiBiStartWithdrawTimer(struct rfapi_import_table *import_table,
assert(bpi->extra);
if (lifetime > UINT32_MAX / 1001) {
/* sub-optimal case, but will probably never happen */
- bpi->extra->vnc.import.timer = NULL;
+ bpi->extra->vnc->vnc.import.timer = NULL;
event_add_timer(bm->master, timer_service_func, wcb, lifetime,
- &bpi->extra->vnc.import.timer);
+ &bpi->extra->vnc->vnc.import.timer);
} else {
static uint32_t jitter;
uint32_t lifetime_msec;
@@ -2770,10 +2776,10 @@ rfapiBiStartWithdrawTimer(struct rfapi_import_table *import_table,
lifetime_msec = (lifetime * 1000) + jitter;
- bpi->extra->vnc.import.timer = NULL;
+ bpi->extra->vnc->vnc.import.timer = NULL;
event_add_timer_msec(bm->master, timer_service_func, wcb,
lifetime_msec,
- &bpi->extra->vnc.import.timer);
+ &bpi->extra->vnc->vnc.import.timer);
}
/* re-sort route list (BGP_PATH_REMOVED routes are last) */
@@ -2986,17 +2992,16 @@ static void rfapiBgpInfoFilteredImportEncap(
* Compare RDs
*
* RD of import table bpi is in
- * bpi->extra->vnc.import.rd RD of info_orig is in prd
+ * bpi->extra->vnc->vnc.import.rd RD of info_orig is in prd
*/
if (!bpi->extra) {
vnc_zlog_debug_verbose("%s: no bpi->extra",
__func__);
continue;
}
- if (prefix_cmp(
- (struct prefix *)&bpi->extra->vnc.import.rd,
- (struct prefix *)prd)) {
-
+ if (prefix_cmp((struct prefix *)&bpi->extra->vnc->vnc
+ .import.rd,
+ (struct prefix *)prd)) {
vnc_zlog_debug_verbose("%s: prd does not match",
__func__);
continue;
@@ -3040,13 +3045,14 @@ static void rfapiBgpInfoFilteredImportEncap(
* a previous withdraw, we must cancel its
* timer.
*/
- if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)
- && bpi->extra->vnc.import.timer) {
+ if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) &&
+ bpi->extra->vnc->vnc.import.timer) {
struct rfapi_withdraw *wcb = EVENT_ARG(
- bpi->extra->vnc.import.timer);
+ bpi->extra->vnc->vnc.import.timer);
XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
- EVENT_OFF(bpi->extra->vnc.import.timer);
+ EVENT_OFF(bpi->extra->vnc->vnc.import
+ .timer);
}
if (action == FIF_ACTION_UPDATE) {
@@ -3132,12 +3138,12 @@ static void rfapiBgpInfoFilteredImportEncap(
vnc_zlog_debug_verbose(
"%s: removing holddown bpi matching NVE of new route",
__func__);
- if (bpi->extra->vnc.import.timer) {
+ if (bpi->extra->vnc->vnc.import.timer) {
struct rfapi_withdraw *wcb =
- EVENT_ARG(bpi->extra->vnc.import.timer);
+ EVENT_ARG(bpi->extra->vnc->vnc.import.timer);
XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
- EVENT_OFF(bpi->extra->vnc.import.timer);
+ EVENT_OFF(bpi->extra->vnc->vnc.import.timer);
}
rfapiExpireEncapNow(import_table, rn, bpi);
}
@@ -3492,13 +3498,14 @@ void rfapiBgpInfoFilteredImportVPN(
* a previous withdraw, we must cancel its
* timer.
*/
- if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)
- && bpi->extra->vnc.import.timer) {
+ if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) &&
+ bpi->extra->vnc->vnc.import.timer) {
struct rfapi_withdraw *wcb = EVENT_ARG(
- bpi->extra->vnc.import.timer);
+ bpi->extra->vnc->vnc.import.timer);
XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
- EVENT_OFF(bpi->extra->vnc.import.timer);
+ EVENT_OFF(bpi->extra->vnc->vnc.import
+ .timer);
import_table->holddown_count[afi] -= 1;
RFAPI_UPDATE_ITABLE_COUNT(
@@ -3571,7 +3578,7 @@ void rfapiBgpInfoFilteredImportVPN(
/* Not a big deal, just means VPN route got here first */
vnc_zlog_debug_verbose("%s: no encap route for vn addr %pFX",
__func__, &vn_prefix);
- info_new->extra->vnc.import.un_family = AF_UNSPEC;
+ info_new->extra->vnc->vnc.import.un_family = AF_UNSPEC;
}
if (rn) {
@@ -3593,7 +3600,7 @@ void rfapiBgpInfoFilteredImportVPN(
vnc_zlog_debug_verbose("%s: setting BPI's aux_prefix",
__func__);
- info_new->extra->vnc.import.aux_prefix = *aux_prefix;
+ info_new->extra->vnc->vnc.import.aux_prefix = *aux_prefix;
}
vnc_zlog_debug_verbose("%s: inserting bpi %p at prefix %pRN #%d",
@@ -3711,12 +3718,12 @@ void rfapiBgpInfoFilteredImportVPN(
vnc_zlog_debug_verbose(
"%s: removing holddown bpi matching NVE of new route",
__func__);
- if (bpi->extra->vnc.import.timer) {
+ if (bpi->extra->vnc->vnc.import.timer) {
struct rfapi_withdraw *wcb =
- EVENT_ARG(bpi->extra->vnc.import.timer);
+ EVENT_ARG(bpi->extra->vnc->vnc.import.timer);
XFREE(MTYPE_RFAPI_WITHDRAW, wcb);
- EVENT_OFF(bpi->extra->vnc.import.timer);
+ EVENT_OFF(bpi->extra->vnc->vnc.import.timer);
}
rfapiExpireVpnNow(import_table, rn, bpi, 0);
}
@@ -4448,12 +4455,10 @@ static void rfapiDeleteRemotePrefixesIt(
if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED)) {
if (!delete_holddown)
continue;
- if (bpi->extra->vnc.import.timer) {
- struct rfapi_withdraw *wcb =
- EVENT_ARG(
- bpi->extra->vnc
- .import
- .timer);
+ if (bpi->extra->vnc->vnc.import.timer) {
+ struct rfapi_withdraw *wcb = EVENT_ARG(
+ bpi->extra->vnc->vnc
+ .import.timer);
wcb->import_table
->holddown_count[afi] -=
@@ -4463,8 +4468,8 @@ static void rfapiDeleteRemotePrefixesIt(
afi, 1);
XFREE(MTYPE_RFAPI_WITHDRAW,
wcb);
- EVENT_OFF(bpi->extra->vnc.import
- .timer);
+ EVENT_OFF(bpi->extra->vnc->vnc
+ .import.timer);
}
} else {
if (!delete_active)
diff --git a/bgpd/rfapi/rfapi_monitor.c b/bgpd/rfapi/rfapi_monitor.c
index 3fe957ba4d..146e0d18b5 100644
--- a/bgpd/rfapi/rfapi_monitor.c
+++ b/bgpd/rfapi/rfapi_monitor.c
@@ -354,7 +354,7 @@ struct agg_node *rfapiMonitorGetAttachNode(struct rfapi_descriptor *rfd,
* If there is a cached ENCAP UN address, it's a usable
* VPN route
*/
- if (bpi->extra && bpi->extra->vnc.import.un_family) {
+ if (bpi->extra && bpi->extra->vnc->vnc.import.un_family) {
break;
}
diff --git a/bgpd/rfapi/rfapi_rib.c b/bgpd/rfapi/rfapi_rib.c
index 5784f95b27..316904e45b 100644
--- a/bgpd/rfapi/rfapi_rib.c
+++ b/bgpd/rfapi/rfapi_rib.c
@@ -663,9 +663,8 @@ static void rfapiRibBi2Ri(struct bgp_path_info *bpi, struct rfapi_info *ri,
/*
* VN options
*/
- if (bpi->extra
- && decode_rd_type(bpi->extra->vnc.import.rd.val)
- == RD_TYPE_VNC_ETH) {
+ if (bpi->extra && decode_rd_type(bpi->extra->vnc->vnc.import.rd.val) ==
+ RD_TYPE_VNC_ETH) {
/* ethernet route */
struct rfapi_vn_option *vo;
@@ -678,8 +677,8 @@ static void rfapiRibBi2Ri(struct bgp_path_info *bpi, struct rfapi_info *ri,
/* copy from RD already stored in bpi, so we don't need it_node
*/
- memcpy(&vo->v.l2addr.macaddr, bpi->extra->vnc.import.rd.val + 2,
- ETH_ALEN);
+ memcpy(&vo->v.l2addr.macaddr,
+ bpi->extra->vnc->vnc.import.rd.val + 2, ETH_ALEN);
(void)rfapiEcommunityGetLNI(bgp_attr_get_ecommunity(bpi->attr),
&vo->v.l2addr.logical_net_id);
@@ -688,7 +687,8 @@ static void rfapiRibBi2Ri(struct bgp_path_info *bpi, struct rfapi_info *ri,
&vo->v.l2addr.tag_id);
/* local_nve_id comes from RD */
- vo->v.l2addr.local_nve_id = bpi->extra->vnc.import.rd.val[1];
+ vo->v.l2addr.local_nve_id =
+ bpi->extra->vnc->vnc.import.rd.val[1];
/* label comes from MP_REACH_NLRI label */
vo->v.l2addr.label = decode_label(&bpi->extra->label[0]);
@@ -701,8 +701,8 @@ static void rfapiRibBi2Ri(struct bgp_path_info *bpi, struct rfapi_info *ri,
/*
* If there is an auxiliary IP address (L2 can have it), copy it
*/
- if (bpi->extra && bpi->extra->vnc.import.aux_prefix.family) {
- ri->rk.aux_prefix = bpi->extra->vnc.import.aux_prefix;
+ if (bpi->extra && bpi->extra->vnc->vnc.import.aux_prefix.family) {
+ ri->rk.aux_prefix = bpi->extra->vnc->vnc.import.aux_prefix;
}
}
@@ -746,13 +746,13 @@ int rfapiRibPreloadBi(
memset((void *)&rk, 0, sizeof(rk));
rk.vn = *pfx_vn;
- rk.rd = bpi->extra->vnc.import.rd;
+ rk.rd = bpi->extra->vnc->vnc.import.rd;
/*
* If there is an auxiliary IP address (L2 can have it), copy it
*/
- if (bpi->extra->vnc.import.aux_prefix.family) {
- rk.aux_prefix = bpi->extra->vnc.import.aux_prefix;
+ if (bpi->extra->vnc->vnc.import.aux_prefix.family) {
+ rk.aux_prefix = bpi->extra->vnc->vnc.import.aux_prefix;
}
/*
@@ -1629,12 +1629,13 @@ void rfapiRibUpdatePendingNode(
ri = rfapi_info_new();
ri->rk.vn = pfx_nh;
- ri->rk.rd = bpi->extra->vnc.import.rd;
+ ri->rk.rd = bpi->extra->vnc->vnc.import.rd;
/*
* If there is an auxiliary IP address (L2 can have it), copy it
*/
- if (bpi->extra->vnc.import.aux_prefix.family) {
- ri->rk.aux_prefix = bpi->extra->vnc.import.aux_prefix;
+ if (bpi->extra->vnc->vnc.import.aux_prefix.family) {
+ ri->rk.aux_prefix =
+ bpi->extra->vnc->vnc.import.aux_prefix;
}
if (rfapiGetUnAddrOfVpnBi(bpi, &ri->un)) {
diff --git a/bgpd/rfapi/rfapi_vty.c b/bgpd/rfapi/rfapi_vty.c
index 43625b11a6..8e88550ddf 100644
--- a/bgpd/rfapi/rfapi_vty.c
+++ b/bgpd/rfapi/rfapi_vty.c
@@ -519,9 +519,10 @@ void rfapiPrintBi(void *stream, struct bgp_path_info *bpi)
if (!bpi)
return;
- if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) && bpi->extra
- && bpi->extra->vnc.import.timer) {
- struct event *t = (struct event *)bpi->extra->vnc.import.timer;
+ if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) && bpi->extra &&
+ bpi->extra->vnc->vnc.import.timer) {
+ struct event *t =
+ (struct event *)bpi->extra->vnc->vnc.import.timer;
r = snprintf(p, REMAIN, " [%4lu] ",
event_timer_remain_second(t));
@@ -534,12 +535,12 @@ void rfapiPrintBi(void *stream, struct bgp_path_info *bpi)
if (bpi->extra) {
/* TBD This valid only for SAFI_MPLS_VPN, but not for encap */
- if (decode_rd_type(bpi->extra->vnc.import.rd.val)
- == RD_TYPE_VNC_ETH) {
+ if (decode_rd_type(bpi->extra->vnc->vnc.import.rd.val) ==
+ RD_TYPE_VNC_ETH) {
has_macaddr = 1;
- memcpy(macaddr.octet, bpi->extra->vnc.import.rd.val + 2,
- 6);
- l2hid = bpi->extra->vnc.import.rd.val[1];
+ memcpy(macaddr.octet,
+ bpi->extra->vnc->vnc.import.rd.val + 2, 6);
+ l2hid = bpi->extra->vnc->vnc.import.rd.val[1];
}
}
@@ -670,11 +671,11 @@ void rfapiPrintBi(void *stream, struct bgp_path_info *bpi)
l2o_buf.label, l2o_buf.logical_net_id, l2o_buf.local_nve_id,
HVTYNL);
}
- if (bpi->extra && bpi->extra->vnc.import.aux_prefix.family) {
+ if (bpi->extra && bpi->extra->vnc->vnc.import.aux_prefix.family) {
const char *sp;
- sp = rfapi_ntop(bpi->extra->vnc.import.aux_prefix.family,
- &bpi->extra->vnc.import.aux_prefix.u.prefix,
+ sp = rfapi_ntop(bpi->extra->vnc->vnc.import.aux_prefix.family,
+ &bpi->extra->vnc->vnc.import.aux_prefix.u.prefix,
buf, BUFSIZ);
buf[BUFSIZ - 1] = 0;
if (sp) {
@@ -1097,14 +1098,14 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream,
fp(out, "%-10s ", buf_lifetime);
}
- if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) && bpi->extra
- && bpi->extra->vnc.import.timer) {
-
+ if (CHECK_FLAG(bpi->flags, BGP_PATH_REMOVED) && bpi->extra &&
+ bpi->extra->vnc->vnc.import.timer) {
uint32_t remaining;
time_t age;
char buf_age[BUFSIZ];
- struct event *t = (struct event *)bpi->extra->vnc.import.timer;
+ struct event *t =
+ (struct event *)bpi->extra->vnc->vnc.import.timer;
remaining = event_timer_remain_second(t);
#ifdef RFAPI_REGISTRATIONS_REPORT_AGE
@@ -1125,11 +1126,10 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream,
fp(out, "%-10s ", buf_age);
} else if (RFAPI_LOCAL_BI(bpi)) {
-
char buf_age[BUFSIZ];
- if (bpi->extra && bpi->extra->vnc.import.create_time) {
- rfapiFormatAge(bpi->extra->vnc.import.create_time,
+ if (bpi->extra && bpi->extra->vnc->vnc.import.create_time) {
+ rfapiFormatAge(bpi->extra->vnc->vnc.import.create_time,
buf_age, BUFSIZ);
} else {
buf_age[0] = '?';
@@ -1145,13 +1145,14 @@ static int rfapiPrintRemoteRegBi(struct bgp *bgp, void *stream,
* print that on the next line
*/
- if (bpi->extra && bpi->extra->vnc.import.aux_prefix.family) {
+ if (bpi->extra && bpi->extra->vnc->vnc.import.aux_prefix.family) {
const char *sp;
- sp = rfapi_ntop(
- bpi->extra->vnc.import.aux_prefix.family,
- &bpi->extra->vnc.import.aux_prefix.u.prefix,
- buf_ntop, BUFSIZ);
+ sp = rfapi_ntop(bpi->extra->vnc->vnc.import.aux_prefix
+ .family,
+ &bpi->extra->vnc->vnc.import.aux_prefix
+ .u.prefix,
+ buf_ntop, BUFSIZ);
buf_ntop[BUFSIZ - 1] = 0;
if (sp && strcmp(buf_vn, sp) != 0) {
@@ -1545,10 +1546,9 @@ void rfapiPrintAdvertisedInfo(struct vty *vty, struct rfapi_descriptor *rfd,
vty_out(vty, " bd=%p%s", bd, HVTYNL);
for (bpi = bgp_dest_get_bgp_path_info(bd); bpi; bpi = bpi->next) {
- if (bpi->peer == rfd->peer && bpi->type == type
- && bpi->sub_type == BGP_ROUTE_RFP && bpi->extra
- && bpi->extra->vnc.export.rfapi_handle == (void *)rfd) {
-
+ if (bpi->peer == rfd->peer && bpi->type == type &&
+ bpi->sub_type == BGP_ROUTE_RFP && bpi->extra &&
+ bpi->extra->vnc->vnc.export.rfapi_handle == (void *)rfd) {
rfapiPrintBi(vty, bpi);
printed = 1;
}
diff --git a/bgpd/rfapi/vnc_import_bgp.c b/bgpd/rfapi/vnc_import_bgp.c
index 3fcc0e6f5f..c067b7a610 100644
--- a/bgpd/rfapi/vnc_import_bgp.c
+++ b/bgpd/rfapi/vnc_import_bgp.c
@@ -1696,8 +1696,8 @@ static void vnc_import_bgp_exterior_add_route_it(
have_usable_route = 1;
if (bpi_interior->extra) {
- prd = &bpi_interior->extra->vnc.import
- .rd;
+ prd = &bpi_interior->extra->vnc->vnc
+ .import.rd;
label = decode_label(
&bpi_interior->extra->label[0]);
} else
@@ -1865,8 +1865,8 @@ void vnc_import_bgp_exterior_del_route(
have_usable_route = 1;
if (bpi_interior->extra) {
- prd = &bpi_interior->extra->vnc.import
- .rd;
+ prd = &bpi_interior->extra->vnc->vnc
+ .import.rd;
label = decode_label(
&bpi_interior->extra->label[0]);
} else
@@ -2013,7 +2013,7 @@ void vnc_import_bgp_exterior_add_route_interior(
assert(pfx_exterior);
if (bpi_interior->extra) {
- prd = &bpi_interior->extra->vnc.import.rd;
+ prd = &bpi_interior->extra->vnc->vnc.import.rd;
label = decode_label(
&bpi_interior->extra->label[0]);
} else
@@ -2126,8 +2126,8 @@ void vnc_import_bgp_exterior_add_route_interior(
for (bpi = par->info; bpi; bpi = bpi->next) {
if (bpi->extra) {
- prd = &bpi->extra->vnc.import
- .rd;
+ prd = &bpi->extra->vnc->vnc
+ .import.rd;
label = decode_label(
&bpi->extra->label[0]);
} else
@@ -2148,8 +2148,8 @@ void vnc_import_bgp_exterior_add_route_interior(
* the new interior route at longer prefix.
*/
if (bpi_interior->extra) {
- prd = &bpi_interior->extra->vnc.import
- .rd;
+ prd = &bpi_interior->extra->vnc->vnc
+ .import.rd;
label = decode_label(
&bpi_interior->extra->label[0]);
} else
@@ -2267,7 +2267,7 @@ void vnc_import_bgp_exterior_add_route_interior(
* new interior route at the longer prefix.
*/
if (bpi_interior->extra) {
- prd = &bpi_interior->extra->vnc.import.rd;
+ prd = &bpi_interior->extra->vnc->vnc.import.rd;
label = decode_label(
&bpi_interior->extra->label[0]);
} else
@@ -2375,7 +2375,7 @@ void vnc_import_bgp_exterior_del_route_interior(
uint32_t label = 0;
if (bpi_interior->extra) {
- prd = &bpi_interior->extra->vnc.import.rd;
+ prd = &bpi_interior->extra->vnc->vnc.import.rd;
label = decode_label(&bpi_interior->extra->label[0]);
} else
prd = NULL;
@@ -2452,7 +2452,7 @@ void vnc_import_bgp_exterior_del_route_interior(
continue;
if (bpi->extra) {
- prd = &bpi->extra->vnc.import.rd;
+ prd = &bpi->extra->vnc->vnc.import.rd;
label = decode_label(
&bpi->extra->label[0]);
} else
@@ -2805,14 +2805,14 @@ void vnc_import_bgp_redist_disable(struct bgp *bgp, afi_t afi)
assert(bpi->extra);
- rfd = bpi->extra->vnc.export.rfapi_handle;
+ rfd = bpi->extra->vnc->vnc.export.rfapi_handle;
vnc_zlog_debug_verbose(
- "%s: deleting bpi=%p, bpi->peer=%p, bpi->type=%d, bpi->sub_type=%d, bpi->extra->vnc.export.rfapi_handle=%p [passing rfd=%p]",
+ "%s: deleting bpi=%p, bpi->peer=%p, bpi->type=%d, bpi->sub_type=%d, bpi->extra->vnc->vnc.export.rfapi_handle=%p [passing rfd=%p]",
__func__, bpi, bpi->peer, bpi->type,
bpi->sub_type,
- (bpi->extra ? bpi->extra->vnc.export
- .rfapi_handle
+ (bpi->extra ? bpi->extra->vnc->vnc
+ .export.rfapi_handle
: NULL),
rfd);
diff --git a/configure.ac b/configure.ac
index dbfae537b1..d9fd920c7c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -701,6 +701,8 @@ AC_ARG_ENABLE([mgmtd],
AS_HELP_STRING([--disable-mgmtd], [do not build mgmtd]))
AC_ARG_ENABLE([mgmtd_local_validations],
AS_HELP_STRING([--enable-mgmtd-local-validations], [dev: unimplemented local validation]))
+AC_ARG_ENABLE([mgmtd_test_be_client],
+ AS_HELP_STRING([--enable-mgmtd-test-be-client], [build test backend client]))
AC_ARG_ENABLE([ripd],
AS_HELP_STRING([--disable-ripd], [do not build ripd]))
AC_ARG_ENABLE([ripngd],
@@ -1811,6 +1813,10 @@ AS_IF([test "$enable_mgmtd" != "no"], [
])
])
+AS_IF([test "$enable_mgmtd_test_be_client" = "yes"], [
+ AC_DEFINE([HAVE_MGMTD_TESTC], [1], [mgmtd_testc])
+])
+
AS_IF([test "$enable_ripd" != "no"], [
AC_DEFINE([HAVE_RIPD], [1], [ripd])
])
@@ -2772,6 +2778,7 @@ AM_CONDITIONAL([VTYSH], [test "$VTYSH" = "vtysh"])
AM_CONDITIONAL([ZEBRA], [test "$enable_zebra" != "no"])
AM_CONDITIONAL([BGPD], [test "$enable_bgpd" != "no"])
AM_CONDITIONAL([MGMTD], [test "$enable_mgmtd" != "no"])
+AM_CONDITIONAL([MGMTD_TESTC], [test "$enable_mgmtd_test_be_client" = "yes"])
AM_CONDITIONAL([RIPD], [test "$enable_ripd" != "no"])
AM_CONDITIONAL([OSPFD], [test "$enable_ospfd" != "no"])
AM_CONDITIONAL([LDPD], [test "$enable_ldpd" != "no"])
diff --git a/debian/frr.pam b/debian/frr.pam
index 737b88953b..1077243a12 100644
--- a/debian/frr.pam
+++ b/debian/frr.pam
@@ -1,4 +1,4 @@
# Any user may call vtysh but only those belonging to the group frrvty can
# actually connect to the socket and use the program.
auth sufficient pam_permit.so
-account sufficient pam_rootok.so
+account sufficient pam_permit.so
diff --git a/doc/developer/northbound/retrofitting-configuration-commands.rst b/doc/developer/northbound/retrofitting-configuration-commands.rst
index 4772610856..d328be9506 100644
--- a/doc/developer/northbound/retrofitting-configuration-commands.rst
+++ b/doc/developer/northbound/retrofitting-configuration-commands.rst
@@ -982,34 +982,30 @@ future.
For libfrr commands, it’s not possible to centralize all commands in a
single file because the *extract.pl* script from *vtysh* treats commands
differently depending on the file in which they are defined (e.g. DEFUNs
-from *lib/routemap.c* are installed using the ``VTYSH_RMAP`` constant,
+from *lib/routemap.c* are installed using the ``VTYSH_RMAP_SHOW`` constant,
which identifies the daemons that support route-maps). In this case, the
CLI commands should be rewritten but maintained in the same file.
Since all CLI configuration commands from FRR will need to be rewritten,
this is an excellent opportunity to rework this part of the code to make
the commands easier to maintain and extend. These are the three main
-recommendations: 1. Always use DEFPY instead of DEFUN to improve code
-readability. 2. Always try to join multiple DEFUNs into a single DEFPY
-whenever possible. As an example, there’s no need to have both
-``distance (1-255) A.B.C.D/M`` and ``distance (1-255) A.B.C.D/M WORD``
-when a single ``distance (1-255) A.B.C.D/M [WORD]`` would suffice. 3.
-When necessary, create a separate DEFPY for ``no`` commands so that part
-of the configuration command can be made optional for convenience.
-Example:
-``no timers basic [(5-2147483647) (5-2147483647) (5-2147483647)]``. In
-this example, everything after ``no timers basic`` is ignored by FRR, so
-it makes sense to accept ``no timers basic`` as a valid command. But it
-also makes sense to accept all parameters
-(``no timers basic (5-2147483647) (5-2147483647) (5-2147483647)``) to
-make it easier to remove the command just by prefixing a “no” to it.
+recommendations:
+
+#. Always use DEFPY instead of DEFUN to improve code readability
+#. Always try to join multiple DEFUNs into a single DEFPY whenever possible. As
+ an example, there’s no need to have both ``distance (1-255) A.B.C.D/M`` and
+ ``distance (1-255) A.B.C.D/M WORD`` when a single ``distance (1-255)
+ A.B.C.D/M [WORD]`` would suffice.
+#. When making a negative form of a command, put ``[no]`` in the positive form
+ and use ``![...]`` to mark portions of the command that should be optional
+ only in the ``no`` version.
To rewrite a CLI command as a dumb wrapper around the northbound
callbacks, use the ``nb_cli_cfg_change()`` function. This function
accepts as a parameter an array of ``cli_config_change`` structures that
specify the changes that need to performed on the candidate
configuration. Here’s the declaration of this structure (taken from the
-*lib/northbound_cli.h* file):
+``lib/northbound_cli.h`` file):
.. code:: c
diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst
index 7c65164b0e..3e3bd2dd21 100644
--- a/doc/developer/topotests.rst
+++ b/doc/developer/topotests.rst
@@ -33,6 +33,7 @@ Installing Topotest Requirements
tshark \
valgrind
python3 -m pip install wheel
+ python3 -m pip install protobuf
python3 -m pip install 'pytest>=6.2.4'
python3 -m pip install 'pytest-xdist>=2.3.0'
python3 -m pip install 'scapy>=2.4.5'
diff --git a/doc/user/basic.rst b/doc/user/basic.rst
index 55b836e3b8..7f9027679f 100644
--- a/doc/user/basic.rst
+++ b/doc/user/basic.rst
@@ -682,6 +682,11 @@ Terminal Mode Commands
This command displays FRR's timer data for timers that will pop in
the future.
+.. clicmd:: show configuration running [<json|xml> [translate WORD]] [with-defaults] DAEMON
+
+ This command displays the northbound/YANG configuration data for a
+ daemon in text/vty, json, or xml format.
+
.. clicmd:: show yang operational-data XPATH [{format <json|xml>|translate TRANSLATOR|with-config}] DAEMON
Display the YANG operational data starting from XPATH. The default
diff --git a/eigrpd/eigrp_const.h b/eigrpd/eigrp_const.h
index 607719d4f1..05fbae32af 100644
--- a/eigrpd/eigrp_const.h
+++ b/eigrpd/eigrp_const.h
@@ -61,9 +61,6 @@
/* IP TTL for EIGRP protocol. */
#define EIGRP_IP_TTL 1
-/* VTY port number. */
-#define EIGRP_VTY_PORT 2613
-
/* Default configuration file name for eigrp. */
#define EIGRP_DEFAULT_CONFIG "eigrpd.conf"
diff --git a/fpm/fpm.h b/fpm/fpm.h
index b08310f675..70c0df5715 100644
--- a/fpm/fpm.h
+++ b/fpm/fpm.h
@@ -63,11 +63,6 @@
#define FPM_DEFAULT_IP (htonl (INADDR_LOOPBACK))
/*
- * default port for fpm connections
- */
-#define FPM_DEFAULT_PORT 2620
-
-/*
* Largest message that can be sent to or received from the FPM.
*/
#define FPM_MAX_MSG_LEN 4096
diff --git a/isisd/isis_main.c b/isisd/isis_main.c
index 47e5f6dc93..60ec8cdad4 100644
--- a/isisd/isis_main.c
+++ b/isisd/isis_main.c
@@ -51,9 +51,6 @@
/* Default configuration file name */
#define ISISD_DEFAULT_CONFIG "isisd.conf"
-/* Default vty port */
-#define ISISD_VTY_PORT 2608
-#define FABRICD_VTY_PORT 2618
#define FABRICD_STATE_NAME "%s/fabricd.json", frr_libstatedir
#define ISISD_STATE_NAME "%s/isisd.json", frr_libstatedir
diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c
index 0d66fc70e7..da29a4f20d 100644
--- a/ldpd/ldpd.c
+++ b/ldpd/ldpd.c
@@ -104,7 +104,6 @@ void ldp_agentx_enabled(void)
enum ldpd_process ldpd_process;
#define LDP_DEFAULT_CONFIG "ldpd.conf"
-#define LDP_VTY_PORT 2612
/* Master of threads. */
struct event_loop *master;
diff --git a/lib/bitfield.h b/lib/bitfield.h
index cc8c311416..3fda627b74 100644
--- a/lib/bitfield.h
+++ b/lib/bitfield.h
@@ -116,6 +116,7 @@ DECLARE_MTYPE(BITFIELD);
(v).m = (v).m + 1; \
(v).data = XREALLOC(MTYPE_BITFIELD, (v).data, \
(v).m * sizeof(word_t)); \
+ (v).data[(v).m - 1] = 0; \
} \
} while (0)
diff --git a/lib/event.c b/lib/event.c
index a7851f6983..6427705e90 100644
--- a/lib/event.c
+++ b/lib/event.c
@@ -543,6 +543,7 @@ static void initializer(void)
pthread_key_create(&thread_current, NULL);
}
+#define STUPIDLY_LARGE_FD_SIZE 100000
struct event_loop *event_master_create(const char *name)
{
struct event_loop *rv;
@@ -569,6 +570,10 @@ struct event_loop *event_master_create(const char *name)
rv->fd_limit = (int)limit.rlim_cur;
}
+ if (rv->fd_limit > STUPIDLY_LARGE_FD_SIZE)
+ zlog_warn("FD Limit set: %u is stupidly large. Is this what you intended? Consider using --limit-fds",
+ rv->fd_limit);
+
rv->read = XCALLOC(MTYPE_EVENT_POLL,
sizeof(struct event *) * rv->fd_limit);
diff --git a/lib/hash.h b/lib/hash.h
index 810faf9030..2d00a334be 100644
--- a/lib/hash.h
+++ b/lib/hash.h
@@ -28,12 +28,12 @@ struct hash_bucket {
*/
int len;
- /* Linked list. */
- struct hash_bucket *next;
-
/* Hash key. */
unsigned int key;
+ /* Linked list. */
+ struct hash_bucket *next;
+
/* Data. */
void *data;
};
diff --git a/lib/libfrr.c b/lib/libfrr.c
index d904f6f8bb..9e472054dd 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -208,7 +208,7 @@ bool frr_zclient_addr(struct sockaddr_storage *sa, socklen_t *sa_len,
if (!strncmp(path, ZAPI_TCP_PATHNAME, strlen(ZAPI_TCP_PATHNAME))) {
/* note: this functionality is disabled at bottom */
int af;
- int port = ZEBRA_PORT;
+ int port = ZEBRA_TCP_PORT;
char *err = NULL;
struct sockaddr_in *sin = NULL;
struct sockaddr_in6 *sin6 = NULL;
diff --git a/lib/libfrr.h b/lib/libfrr.h
index 27b877da18..ee436d9f8f 100644
--- a/lib/libfrr.h
+++ b/lib/libfrr.h
@@ -55,6 +55,49 @@ struct log_arg {
};
DECLARE_DLIST(log_args, struct log_arg, itm);
+/* Registry of daemons' port defaults. Many of these are VTY ports; some
+ * daemons have default ports for other features such as ospfapi, or zebra's
+ * FPM.
+ */
+
+/* default zebra TCP port for zapi; this is currently disabled for security
+ * reasons.
+ */
+#define ZEBRA_TCP_PORT 2600
+
+#define ZEBRA_VTY_PORT 2601
+#define RIP_VTY_PORT 2602
+#define RIPNG_VTY_PORT 2603
+#define OSPF_VTY_PORT 2604
+#define BGP_VTY_PORT 2605
+#define OSPF6_VTY_PORT 2606
+
+/* Default API server port to accept connection request from client-side.
+ * This value could be overridden by "ospfapi" entry in "/etc/services".
+ */
+#define OSPF_API_SYNC_PORT 2607
+
+#define ISISD_VTY_PORT 2608
+#define BABEL_VTY_PORT 2609
+#define NHRP_VTY_PORT 2610
+#define PIMD_VTY_PORT 2611
+#define LDP_VTY_PORT 2612
+#define EIGRP_VTY_PORT 2613
+#define SHARP_VTY_PORT 2614
+#define PBR_VTY_PORT 2615
+#define STATIC_VTY_PORT 2616
+#define BFDD_VTY_PORT 2617
+#define FABRICD_VTY_PORT 2618
+#define VRRP_VTY_PORT 2619
+
+/* default port for FPM connections */
+#define FPM_DEFAULT_PORT 2620
+
+#define PATH_VTY_PORT 2621
+#define PIM6D_VTY_PORT 2622
+#define MGMTD_VTY_PORT 2623
+/* Registry of daemons' port defaults */
+
enum frr_cli_mode {
FRR_CLI_CLASSIC = 0,
FRR_CLI_TRANSACTIONAL,
diff --git a/lib/mgmt.proto b/lib/mgmt.proto
index 5d83fca347..01a99ab63b 100644
--- a/lib/mgmt.proto
+++ b/lib/mgmt.proto
@@ -76,8 +76,9 @@ message YangGetDataReq {
//
message BeSubscribeReq {
required string client_name = 1;
- required bool subscribe_xpaths = 2;
- repeated string xpath_reg = 3;
+ repeated string config_xpaths = 2;
+ repeated string oper_xpaths = 3;
+ repeated string notif_xpaths = 4;
}
message BeSubscribeReply {
diff --git a/lib/mgmt_be_client.c b/lib/mgmt_be_client.c
index 463aefdf25..6530022db8 100644
--- a/lib/mgmt_be_client.c
+++ b/lib/mgmt_be_client.c
@@ -149,7 +149,7 @@ mgmt_be_batch_create(struct mgmt_be_txn_ctx *txn)
mgmt_be_batches_add_tail(&txn->cfg_batches, batch);
- MGMTD_BE_CLIENT_DBG("Added new batch to transaction");
+ debug_be_client("Added new batch to transaction");
return batch;
}
@@ -202,8 +202,8 @@ mgmt_be_find_txn_by_id(struct mgmt_be_client *client_ctx, uint64_t txn_id,
if (txn->txn_id == txn_id)
return txn;
if (warn)
- MGMTD_BE_CLIENT_ERR("client %s unkonwn txn-id: %" PRIu64,
- client_ctx->name, txn_id);
+ log_err_be_client("client %s unkonwn txn-id: %" PRIu64,
+ client_ctx->name, txn_id);
return NULL;
}
@@ -215,8 +215,8 @@ mgmt_be_txn_create(struct mgmt_be_client *client_ctx, uint64_t txn_id)
txn = mgmt_be_find_txn_by_id(client_ctx, txn_id, false);
if (txn) {
- MGMTD_BE_CLIENT_ERR("Can't create existing txn-id: %" PRIu64,
- txn_id);
+ log_err_be_client("Can't create existing txn-id: %" PRIu64,
+ txn_id);
return NULL;
}
@@ -227,7 +227,7 @@ mgmt_be_txn_create(struct mgmt_be_client *client_ctx, uint64_t txn_id)
mgmt_be_batches_init(&txn->apply_cfgs);
mgmt_be_txns_add_tail(&client_ctx->txn_head, txn);
- MGMTD_BE_CLIENT_DBG("Created new txn-id: %" PRIu64, txn_id);
+ debug_be_client("Created new txn-id: %" PRIu64, txn_id);
return txn;
}
@@ -311,6 +311,90 @@ static int be_client_send_error(struct mgmt_be_client *client, uint64_t txn_id,
return ret;
}
+void mgmt_be_send_notification(struct lyd_node *tree)
+{
+ struct mgmt_be_client *client = __be_client;
+ struct mgmt_msg_notify_data *msg = NULL;
+ LYD_FORMAT format = LYD_JSON;
+ uint8_t **darrp;
+ LY_ERR err;
+
+ assert(tree);
+
+ debug_be_client("%s: sending YANG notification: %s", __func__,
+ tree->schema->name);
+ /*
+ * Allocate a message and append the data to it using `format`
+ */
+ msg = mgmt_msg_native_alloc_msg(struct mgmt_msg_notify_data, 0,
+ MTYPE_MSG_NATIVE_NOTIFY);
+ msg->code = MGMT_MSG_CODE_NOTIFY;
+ msg->result_type = format;
+
+ darrp = mgmt_msg_native_get_darrp(msg);
+ err = yang_print_tree_append(darrp, tree, format,
+ (LYD_PRINT_SHRINK | LYD_PRINT_WD_EXPLICIT |
+ LYD_PRINT_WITHSIBLINGS));
+ if (err) {
+ flog_err(EC_LIB_LIBYANG,
+ "%s: error creating notification data: %s", __func__,
+ ly_strerrcode(err));
+ goto done;
+ }
+
+ (void)be_client_send_native_msg(client, msg,
+ mgmt_msg_native_get_msg_len(msg), false);
+done:
+ mgmt_msg_native_free_msg(msg);
+ lyd_free_all(tree);
+}
+
+/*
+ * Convert old style NB notification data into new MGMTD YANG tree and send.
+ */
+static int mgmt_be_notification_send(void *arg, const char *xpath,
+ struct list *args)
+{
+ struct lyd_node *root = NULL;
+ struct lyd_node *dnode;
+ struct yang_data *data;
+ struct listnode *ln;
+ LY_ERR err;
+
+ debug_be_client("%s: sending notification: %s", __func__, xpath);
+
+ /*
+ * Convert yang data args list to a libyang data tree
+ */
+ for (ALL_LIST_ELEMENTS_RO(args, ln, data)) {
+ err = lyd_new_path(root, ly_native_ctx, data->xpath,
+ data->value, LYD_NEW_PATH_UPDATE, &dnode);
+ if (err != LY_SUCCESS) {
+lyerr:
+ flog_err(EC_LIB_LIBYANG,
+ "%s: error creating notification data: %s",
+ __func__, ly_strerrcode(err));
+ if (root)
+ lyd_free_all(root);
+ return 1;
+ }
+ if (!root) {
+ root = dnode;
+ while (root->parent)
+ root = lyd_parent(root);
+ }
+ }
+
+ if (!root) {
+ err = lyd_new_path(NULL, ly_native_ctx, xpath, "", 0, &root);
+ if (err)
+ goto lyerr;
+ }
+
+ mgmt_be_send_notification(root);
+ return 0;
+}
+
static int mgmt_be_send_txn_reply(struct mgmt_be_client *client_ctx,
uint64_t txn_id, bool create)
{
@@ -326,7 +410,7 @@ static int mgmt_be_send_txn_reply(struct mgmt_be_client *client_ctx,
be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_TXN_REPLY;
be_msg.txn_reply = &txn_reply;
- MGMTD_BE_CLIENT_DBG("Sending TXN_REPLY txn-id %" PRIu64, txn_id);
+ debug_be_client("Sending TXN_REPLY txn-id %" PRIu64, txn_id);
return mgmt_be_client_send_msg(client_ctx, &be_msg);
}
@@ -337,7 +421,7 @@ static int mgmt_be_process_txn_req(struct mgmt_be_client *client_ctx,
struct mgmt_be_txn_ctx *txn;
if (create) {
- MGMTD_BE_CLIENT_DBG("Creating new txn-id %" PRIu64, txn_id);
+ debug_be_client("Creating new txn-id %" PRIu64, txn_id);
txn = mgmt_be_txn_create(client_ctx, txn_id);
if (!txn)
@@ -348,7 +432,7 @@ static int mgmt_be_process_txn_req(struct mgmt_be_client *client_ctx,
client_ctx->user_data,
&txn->client_data, false);
} else {
- MGMTD_BE_CLIENT_DBG("Deleting txn-id: %" PRIu64, txn_id);
+ debug_be_client("Deleting txn-id: %" PRIu64, txn_id);
txn = mgmt_be_find_txn_by_id(client_ctx, txn_id, false);
if (txn)
mgmt_be_txn_delete(client_ctx, &txn);
@@ -378,8 +462,7 @@ static int mgmt_be_send_cfgdata_create_reply(struct mgmt_be_client *client_ctx,
be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_CFG_DATA_REPLY;
be_msg.cfg_data_reply = &cfgdata_reply;
- MGMTD_BE_CLIENT_DBG("Sending CFGDATA_CREATE_REPLY txn-id: %" PRIu64,
- txn_id);
+ debug_be_client("Sending CFGDATA_CREATE_REPLY txn-id: %" PRIu64, txn_id);
return mgmt_be_client_send_msg(client_ctx, &be_msg);
}
@@ -390,9 +473,8 @@ static void mgmt_be_txn_cfg_abort(struct mgmt_be_txn_ctx *txn)
assert(txn && txn->client);
if (txn->nb_txn) {
- MGMTD_BE_CLIENT_ERR(
- "Aborting configs after prep for txn-id: %" PRIu64,
- txn->txn_id);
+ log_err_be_client("Aborting configs after prep for txn-id: %" PRIu64,
+ txn->txn_id);
nb_candidate_commit_abort(txn->nb_txn, errmsg, sizeof(errmsg));
txn->nb_txn = 0;
}
@@ -403,9 +485,8 @@ static void mgmt_be_txn_cfg_abort(struct mgmt_be_txn_ctx *txn)
* This is one txn ctx but the candidate_config is per client ctx, how
* does that work?
*/
- MGMTD_BE_CLIENT_DBG(
- "Reset candidate configurations after abort of txn-id: %" PRIu64,
- txn->txn_id);
+ debug_be_client("Reset candidate configurations after abort of txn-id: %" PRIu64,
+ txn->txn_id);
nb_config_replace(txn->client->candidate_config,
txn->client->running_config, true);
}
@@ -453,10 +534,9 @@ static int mgmt_be_txn_cfg_prepare(struct mgmt_be_txn_ctx *txn)
NULL, true, err_buf, sizeof(err_buf), &error);
if (error) {
err_buf[sizeof(err_buf) - 1] = 0;
- MGMTD_BE_CLIENT_ERR(
- "Failed to update configs for txn-id: %" PRIu64
- " to candidate, err: '%s'",
- txn->txn_id, err_buf);
+ log_err_be_client("Failed to update configs for txn-id: %" PRIu64
+ " to candidate, err: '%s'",
+ txn->txn_id, err_buf);
return -1;
}
gettimeofday(&edit_nb_cfg_end, NULL);
@@ -494,21 +574,19 @@ static int mgmt_be_txn_cfg_prepare(struct mgmt_be_txn_ctx *txn)
if (err != NB_OK) {
err_buf[sizeof(err_buf) - 1] = 0;
if (err == NB_ERR_VALIDATION)
- MGMTD_BE_CLIENT_ERR(
- "Failed to validate configs txn-id: %" PRIu64
- " %zu batches, err: '%s'",
- txn->txn_id, num_processed, err_buf);
+ log_err_be_client("Failed to validate configs txn-id: %" PRIu64
+ " %zu batches, err: '%s'",
+ txn->txn_id, num_processed, err_buf);
else
- MGMTD_BE_CLIENT_ERR(
- "Failed to prepare configs for txn-id: %" PRIu64
- " %zu batches, err: '%s'",
- txn->txn_id, num_processed, err_buf);
+ log_err_be_client("Failed to prepare configs for txn-id: %" PRIu64
+ " %zu batches, err: '%s'",
+ txn->txn_id, num_processed, err_buf);
error = true;
SET_FLAG(txn->flags, MGMTD_BE_TXN_FLAGS_CFGPREP_FAILED);
} else
- MGMTD_BE_CLIENT_DBG("Prepared configs for txn-id: %" PRIu64
- " %zu batches",
- txn->txn_id, num_processed);
+ debug_be_client("Prepared configs for txn-id: %" PRIu64
+ " %zu batches",
+ txn->txn_id, num_processed);
gettimeofday(&prep_nb_cfg_end, NULL);
prep_nb_cfg_tm = timeval_elapsed(prep_nb_cfg_end, prep_nb_cfg_start);
@@ -530,10 +608,9 @@ static int mgmt_be_txn_cfg_prepare(struct mgmt_be_txn_ctx *txn)
mgmt_be_send_cfgdata_create_reply(client_ctx, txn->txn_id,
error ? false : true, error ? err_buf : NULL);
- MGMTD_BE_CLIENT_DBG(
- "Avg-nb-edit-duration %lu uSec, nb-prep-duration %lu (avg: %lu) uSec, batch size %u",
- client_ctx->avg_edit_nb_cfg_tm, prep_nb_cfg_tm,
- client_ctx->avg_prep_nb_cfg_tm, (uint32_t)num_processed);
+ debug_be_client("Avg-nb-edit-duration %lu uSec, nb-prep-duration %lu (avg: %lu) uSec, batch size %u",
+ client_ctx->avg_edit_nb_cfg_tm, prep_nb_cfg_tm,
+ client_ctx->avg_prep_nb_cfg_tm, (uint32_t)num_processed);
if (error)
mgmt_be_txn_cfg_abort(txn);
@@ -559,8 +636,9 @@ static int mgmt_be_update_setcfg_in_batch(struct mgmt_be_client *client_ctx,
txn_req = &batch->txn_req;
txn_req->event = MGMTD_BE_TXN_PROC_SETCFG;
- MGMTD_BE_CLIENT_DBG("Created SETCFG request for txn-id: %" PRIu64
- " cfg-items:%d", txn->txn_id, num_req);
+ debug_be_client("Created SETCFG request for txn-id: %" PRIu64
+ " cfg-items:%d",
+ txn->txn_id, num_req);
txn_req->req.set_cfg.num_cfg_changes = num_req;
for (index = 0; index < num_req; index++) {
@@ -622,7 +700,7 @@ static int mgmt_be_process_cfgdata_req(struct mgmt_be_client *client_ctx,
mgmt_be_update_setcfg_in_batch(client_ctx, txn, cfg_req, num_req);
if (txn && end_of_data) {
- MGMTD_BE_CLIENT_DBG("End of data; CFG_PREPARE_REQ processing");
+ debug_be_client("End of data; CFG_PREPARE_REQ processing");
if (mgmt_be_txn_cfg_prepare(txn))
goto failed;
}
@@ -651,7 +729,7 @@ static int mgmt_be_send_apply_reply(struct mgmt_be_client *client_ctx,
be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_CFG_APPLY_REPLY;
be_msg.cfg_apply_reply = &apply_reply;
- MGMTD_BE_CLIENT_DBG("Sending CFG_APPLY_REPLY txn-id %" PRIu64, txn_id);
+ debug_be_client("Sending CFG_APPLY_REPLY txn-id %" PRIu64, txn_id);
return mgmt_be_client_send_msg(client_ctx, &be_msg);
}
@@ -698,8 +776,8 @@ static int mgmt_be_txn_proc_cfgapply(struct mgmt_be_txn_ctx *txn)
mgmt_be_send_apply_reply(client_ctx, txn->txn_id, true, NULL);
- MGMTD_BE_CLIENT_DBG("Nb-apply-duration %lu (avg: %lu) uSec",
- apply_nb_cfg_tm, client_ctx->avg_apply_nb_cfg_tm);
+ debug_be_client("Nb-apply-duration %lu (avg: %lu) uSec",
+ apply_nb_cfg_tm, client_ctx->avg_apply_nb_cfg_tm);
return 0;
}
@@ -713,7 +791,7 @@ static int mgmt_be_process_cfg_apply(struct mgmt_be_client *client_ctx,
if (!txn)
goto failed;
- MGMTD_BE_CLIENT_DBG("Trigger CFG_APPLY_REQ processing");
+ debug_be_client("Trigger CFG_APPLY_REQ processing");
if (mgmt_be_txn_proc_cfgapply(txn))
goto failed;
@@ -736,23 +814,28 @@ static int mgmt_be_client_handle_msg(struct mgmt_be_client *client_ctx,
*/
switch ((int)be_msg->message_case) {
case MGMTD__BE_MESSAGE__MESSAGE_SUBSCR_REPLY:
- MGMTD_BE_CLIENT_DBG("Got SUBSCR_REPLY success %u",
- be_msg->subscr_reply->success);
+ debug_be_client("Got SUBSCR_REPLY success %u",
+ be_msg->subscr_reply->success);
+
+ if (client_ctx->cbs.subscr_done)
+ (*client_ctx->cbs.subscr_done)(client_ctx,
+ client_ctx->user_data,
+ be_msg->subscr_reply
+ ->success);
break;
case MGMTD__BE_MESSAGE__MESSAGE_TXN_REQ:
- MGMTD_BE_CLIENT_DBG("Got TXN_REQ %s txn-id: %" PRIu64,
- be_msg->txn_req->create ? "Create"
- : "Delete",
- be_msg->txn_req->txn_id);
+ debug_be_client("Got TXN_REQ %s txn-id: %" PRIu64,
+ be_msg->txn_req->create ? "Create" : "Delete",
+ be_msg->txn_req->txn_id);
mgmt_be_process_txn_req(client_ctx,
be_msg->txn_req->txn_id,
be_msg->txn_req->create);
break;
case MGMTD__BE_MESSAGE__MESSAGE_CFG_DATA_REQ:
- MGMTD_BE_CLIENT_DBG("Got CFG_DATA_REQ txn-id: %" PRIu64
- " end-of-data %u",
- be_msg->cfg_data_req->txn_id,
- be_msg->cfg_data_req->end_of_data);
+ debug_be_client("Got CFG_DATA_REQ txn-id: %" PRIu64
+ " end-of-data %u",
+ be_msg->cfg_data_req->txn_id,
+ be_msg->cfg_data_req->end_of_data);
mgmt_be_process_cfgdata_req(
client_ctx, be_msg->cfg_data_req->txn_id,
be_msg->cfg_data_req->data_req,
@@ -760,8 +843,8 @@ static int mgmt_be_client_handle_msg(struct mgmt_be_client *client_ctx,
be_msg->cfg_data_req->end_of_data);
break;
case MGMTD__BE_MESSAGE__MESSAGE_CFG_APPLY_REQ:
- MGMTD_BE_CLIENT_DBG("Got CFG_APPLY_REQ txn-id: %" PRIu64,
- be_msg->cfg_data_req->txn_id);
+ debug_be_client("Got CFG_APPLY_REQ txn-id: %" PRIu64,
+ be_msg->cfg_data_req->txn_id);
mgmt_be_process_cfg_apply(
client_ctx, (uint64_t)be_msg->cfg_apply_req->txn_id);
break;
@@ -824,7 +907,7 @@ static enum nb_error be_client_send_tree_data_batch(const struct lyd_node *tree,
darrp = mgmt_msg_native_get_darrp(tree_msg);
err = yang_print_tree_append(darrp, tree, args->result_type,
- (LYD_PRINT_WD_EXPLICIT |
+ (LYD_PRINT_SHRINK | LYD_PRINT_WD_EXPLICIT |
LYD_PRINT_WITHSIBLINGS));
if (err) {
ret = NB_ERR;
@@ -856,9 +939,9 @@ static void be_client_handle_get_tree(struct mgmt_be_client *client,
struct mgmt_msg_get_tree *get_tree_msg = msgbuf;
struct be_client_tree_data_batch_args *args;
- MGMTD_BE_CLIENT_DBG("Received get-tree request for client %s txn-id %" PRIu64
- " req-id %" PRIu64,
- client->name, txn_id, get_tree_msg->req_id);
+ debug_be_client("Received get-tree request for client %s txn-id %" PRIu64
+ " req-id %" PRIu64,
+ client->name, txn_id, get_tree_msg->req_id);
/* NOTE: removed the translator, if put back merge with northbound_cli
* code
@@ -874,6 +957,31 @@ static void be_client_handle_get_tree(struct mgmt_be_client *client,
}
/*
+ * Process the notification.
+ */
+static void be_client_handle_notify(struct mgmt_be_client *client, void *msgbuf,
+ size_t msg_len)
+{
+ struct mgmt_msg_notify_data *notif_msg = msgbuf;
+ struct mgmt_be_client_notification_cb *cb;
+ const char *notif;
+ uint i;
+
+ debug_be_client("Received notification for client %s", client->name);
+
+ /* "{\"modname:notification-name\": ...}" */
+ notif = (const char *)notif_msg->result + 2;
+
+ for (i = 0; i < client->cbs.nnotify_cbs; i++) {
+ cb = &client->cbs.notify_cbs[i];
+ if (strncmp(cb->xpath, notif, strlen(cb->xpath)))
+ continue;
+ cb->callback(client, client->user_data, cb,
+ (const char *)notif_msg->result);
+ }
+}
+
+/*
* Handle a native encoded message
*
* We don't create transactions with native messaging.
@@ -888,12 +996,15 @@ static void be_client_handle_native_msg(struct mgmt_be_client *client,
case MGMT_MSG_CODE_GET_TREE:
be_client_handle_get_tree(client, txn_id, msg, msg_len);
break;
+ case MGMT_MSG_CODE_NOTIFY:
+ be_client_handle_notify(client, msg, msg_len);
+ break;
default:
- MGMTD_BE_CLIENT_ERR("unknown native message txn-id %" PRIu64
- " req-id %" PRIu64 " code %u to client %s",
- txn_id, msg->req_id, msg->code,
- client->name);
- be_client_send_error(client, msg->refer_id, msg->req_id, false, -1,
+ log_err_be_client("unknown native message txn-id %" PRIu64
+ " req-id %" PRIu64 " code %u to client %s",
+ txn_id, msg->req_id, msg->code, client->name);
+ be_client_send_error(client, msg->refer_id, msg->req_id, false,
+ -1,
"BE cilent %s recv msg unknown txn-id %" PRIu64,
client->name, txn_id);
break;
@@ -916,49 +1027,61 @@ static void mgmt_be_client_process_msg(uint8_t version, uint8_t *data,
if (len >= sizeof(*msg))
be_client_handle_native_msg(client_ctx, msg, len);
else
- MGMTD_BE_CLIENT_ERR("native message to client %s too short %zu",
- client_ctx->name, len);
+ log_err_be_client("native message to client %s too short %zu",
+ client_ctx->name, len);
return;
}
be_msg = mgmtd__be_message__unpack(NULL, len, data);
if (!be_msg) {
- MGMTD_BE_CLIENT_DBG("Failed to decode %zu bytes from server",
- len);
+ debug_be_client("Failed to decode %zu bytes from server", len);
return;
}
- MGMTD_BE_CLIENT_DBG(
- "Decoded %zu bytes of message(msg: %u/%u) from server", len,
- be_msg->message_case, be_msg->message_case);
+ debug_be_client("Decoded %zu bytes of message(msg: %u/%u) from server",
+ len, be_msg->message_case, be_msg->message_case);
(void)mgmt_be_client_handle_msg(client_ctx, be_msg);
mgmtd__be_message__free_unpacked(be_msg, NULL);
}
int mgmt_be_send_subscr_req(struct mgmt_be_client *client_ctx,
- bool subscr_xpaths, int num_xpaths,
- char **reg_xpaths)
+ int n_config_xpaths, char **config_xpaths,
+ int n_oper_xpaths, char **oper_xpaths)
{
Mgmtd__BeMessage be_msg;
Mgmtd__BeSubscribeReq subscr_req;
+ const char **notif_xpaths = NULL;
+ int ret;
mgmtd__be_subscribe_req__init(&subscr_req);
subscr_req.client_name = client_ctx->name;
- subscr_req.n_xpath_reg = num_xpaths;
- if (num_xpaths)
- subscr_req.xpath_reg = reg_xpaths;
- else
- subscr_req.xpath_reg = NULL;
- subscr_req.subscribe_xpaths = subscr_xpaths;
+ subscr_req.n_config_xpaths = n_config_xpaths;
+ subscr_req.config_xpaths = config_xpaths;
+ subscr_req.n_oper_xpaths = n_oper_xpaths;
+ subscr_req.oper_xpaths = oper_xpaths;
+
+ /* See if we should register for notifications */
+ subscr_req.n_notif_xpaths = client_ctx->cbs.nnotify_cbs;
+ if (client_ctx->cbs.nnotify_cbs) {
+ struct mgmt_be_client_notification_cb *cb, *ecb;
+
+ cb = client_ctx->cbs.notify_cbs;
+ ecb = cb + client_ctx->cbs.nnotify_cbs;
+ for (; cb < ecb; cb++)
+ *darr_append(notif_xpaths) = cb->xpath;
+ }
+ subscr_req.notif_xpaths = (char **)notif_xpaths;
mgmtd__be_message__init(&be_msg);
be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_SUBSCR_REQ;
be_msg.subscr_req = &subscr_req;
- MGMTD_BE_CLIENT_DBG("Sending SUBSCR_REQ name: %s subscr_xpaths: %u num_xpaths: %zu",
- subscr_req.client_name, subscr_req.subscribe_xpaths,
- subscr_req.n_xpath_reg);
+ debug_be_client("Sending SUBSCR_REQ name: %s xpaths: config %zu oper: %zu notif: %zu",
+ subscr_req.client_name, subscr_req.n_config_xpaths,
+ subscr_req.n_oper_xpaths, subscr_req.n_notif_xpaths);
- return mgmt_be_client_send_msg(client_ctx, &be_msg);
+ ret = mgmt_be_client_send_msg(client_ctx, &be_msg);
+ darr_free(notif_xpaths);
+ return ret;
}
static int _notify_conenct_disconnect(struct msg_client *msg_client,
@@ -970,15 +1093,16 @@ static int _notify_conenct_disconnect(struct msg_client *msg_client,
if (connected) {
assert(msg_client->conn.fd != -1);
- ret = mgmt_be_send_subscr_req(client, false, 0, NULL);
+ ret = mgmt_be_send_subscr_req(client, 0, NULL, 0, NULL);
if (ret)
return ret;
}
/* Notify BE client through registered callback (if any) */
if (client->cbs.client_connect_notify)
- (void)(*client->cbs.client_connect_notify)(
- client, client->user_data, connected);
+ (void)(*client->cbs.client_connect_notify)(client,
+ client->user_data,
+ connected);
/* Cleanup any in-progress TXN on disconnect */
if (!connected)
@@ -1016,9 +1140,8 @@ static void mgmt_debug_client_be_set(uint32_t flags, bool set)
DEFPY(debug_mgmt_client_be, debug_mgmt_client_be_cmd,
"[no] debug mgmt client backend",
- NO_STR DEBUG_STR MGMTD_STR
- "client\n"
- "backend\n")
+ NO_STR DEBUG_STR MGMTD_STR "client\n"
+ "backend\n")
{
mgmt_debug_client_be_set(DEBUG_NODE2MODE(vty->node), !no);
@@ -1035,7 +1158,7 @@ static int mgmt_debug_be_client_config_write(struct vty *vty)
void mgmt_debug_be_client_show_debug(struct vty *vty)
{
- if (MGMTD_DBG_BE_CLIENT_CHECK())
+ if (debug_check_be_client())
vty_out(vty, "debug mgmt client backend\n");
}
@@ -1081,9 +1204,13 @@ struct mgmt_be_client *mgmt_be_client_create(const char *client_name,
mgmt_be_client_notify_disconenct,
mgmt_be_client_process_msg, MGMTD_BE_MAX_NUM_MSG_PROC,
MGMTD_BE_MAX_NUM_MSG_WRITE, MGMTD_BE_MAX_MSG_LEN, false,
- "BE-client", MGMTD_DBG_BE_CLIENT_CHECK());
+ "BE-client", debug_check_be_client());
+
+ /* Hook to receive notifications */
+ hook_register_arg(nb_notification_send, mgmt_be_notification_send,
+ client);
- MGMTD_BE_CLIENT_DBG("Initialized client '%s'", client_name);
+ debug_be_client("Initialized client '%s'", client_name);
return client;
}
@@ -1101,8 +1228,7 @@ void mgmt_be_client_destroy(struct mgmt_be_client *client)
{
assert(client == __be_client);
- MGMTD_BE_CLIENT_DBG("Destroying MGMTD Backend Client '%s'",
- client->name);
+ debug_be_client("Destroying MGMTD Backend Client '%s'", client->name);
nb_oper_cancel_all_walks();
msg_client_cleanup(&client->client);
diff --git a/lib/mgmt_be_client.h b/lib/mgmt_be_client.h
index 8ad482cacf..d144ebc728 100644
--- a/lib/mgmt_be_client.h
+++ b/lib/mgmt_be_client.h
@@ -60,14 +60,29 @@ struct mgmt_be_client_txn_ctx {
* Callbacks:
* client_connect_notify: called when connection is made/lost to mgmtd.
* txn_notify: called when a txn has been created
+ * notify_cbs: callbacks for notifications.
+ * nnotify_cbs: number of notification callbacks.
+ *
*/
struct mgmt_be_client_cbs {
void (*client_connect_notify)(struct mgmt_be_client *client,
uintptr_t usr_data, bool connected);
-
+ void (*subscr_done)(struct mgmt_be_client *client, uintptr_t usr_data,
+ bool success);
void (*txn_notify)(struct mgmt_be_client *client, uintptr_t usr_data,
struct mgmt_be_client_txn_ctx *txn_ctx,
bool destroyed);
+
+ struct mgmt_be_client_notification_cb *notify_cbs;
+ uint nnotify_cbs;
+};
+
+struct mgmt_be_client_notification_cb {
+ const char *xpath; /* the notification */
+ uint8_t format; /* currently only LYD_JSON supported */
+ void (*callback)(struct mgmt_be_client *client, uintptr_t usr_data,
+ struct mgmt_be_client_notification_cb *this,
+ const char *notif_data);
};
/***************************************************************
@@ -80,12 +95,12 @@ extern struct debug mgmt_dbg_be_client;
* API prototypes
***************************************************************/
-#define MGMTD_BE_CLIENT_DBG(fmt, ...) \
+#define debug_be_client(fmt, ...) \
DEBUGD(&mgmt_dbg_be_client, "BE-CLIENT: %s: " fmt, __func__, \
##__VA_ARGS__)
-#define MGMTD_BE_CLIENT_ERR(fmt, ...) \
+#define log_err_be_client(fmt, ...) \
zlog_err("BE-CLIENT: %s: ERROR: " fmt, __func__, ##__VA_ARGS__)
-#define MGMTD_DBG_BE_CLIENT_CHECK() \
+#define debug_check_be_client() \
DEBUG_MODE_CHECK(&mgmt_dbg_be_client, DEBUG_MODE_ALL)
/**
@@ -124,7 +139,7 @@ extern void mgmt_debug_be_client_show_debug(struct vty *vty);
* The client object.
*
* reg_yang_xpaths
- * Yang xpath(s) that needs to be [un]-subscribed from/to
+ * Yang xpath(s) that needs to be subscribed to
*
* num_xpaths
* Number of xpaths
@@ -132,9 +147,18 @@ extern void mgmt_debug_be_client_show_debug(struct vty *vty);
* Returns:
* MGMTD_SUCCESS on success, MGMTD_* otherwise.
*/
-extern int mgmt_be_send_subscr_req(struct mgmt_be_client *client,
- bool subscr_xpaths, int num_xpaths,
- char **reg_xpaths);
+extern int mgmt_be_send_subscr_req(struct mgmt_be_client *client_ctx,
+ int n_config_xpaths, char **config_xpaths,
+ int n_oper_xpaths, char **oper_xpaths);
+
+/**
+ * mgmt_be_notification_send() - send a YANG notification to FE clients.
+ * @tree: libyang tree for the notification. The tree will be freed by
+ * this function.
+ *
+ */
+extern void mgmt_be_send_notification(struct lyd_node *tree);
+
/*
* Destroy backend client and cleanup everything.
diff --git a/lib/mgmt_fe_client.c b/lib/mgmt_fe_client.c
index 92619f4f7f..9f98a241fe 100644
--- a/lib/mgmt_fe_client.c
+++ b/lib/mgmt_fe_client.c
@@ -79,14 +79,13 @@ mgmt_fe_find_session_by_client_id(struct mgmt_fe_client *client,
FOREACH_SESSION_IN_LIST (client, session) {
if (session->client_id == client_id) {
- MGMTD_FE_CLIENT_DBG("Found session-id %" PRIu64
- " using client-id %" PRIu64,
- session->session_id, client_id);
+ debug_fe_client("Found session-id %" PRIu64
+ " using client-id %" PRIu64,
+ session->session_id, client_id);
return session;
}
}
- MGMTD_FE_CLIENT_DBG("Session not found using client-id %" PRIu64,
- client_id);
+ debug_fe_client("Session not found using client-id %" PRIu64, client_id);
return NULL;
}
@@ -98,15 +97,14 @@ mgmt_fe_find_session_by_session_id(struct mgmt_fe_client *client,
FOREACH_SESSION_IN_LIST (client, session) {
if (session->session_id == session_id) {
- MGMTD_FE_CLIENT_DBG(
- "Found session of client-id %" PRIu64
- " using session-id %" PRIu64,
- session->client_id, session_id);
+ debug_fe_client("Found session of client-id %" PRIu64
+ " using session-id %" PRIu64,
+ session->client_id, session_id);
return session;
}
}
- MGMTD_FE_CLIENT_DBG("Session not found using session-id %" PRIu64,
- session_id);
+ debug_fe_client("Session not found using session-id %" PRIu64,
+ session_id);
return NULL;
}
@@ -133,8 +131,7 @@ static int mgmt_fe_send_register_req(struct mgmt_fe_client *client)
fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_REGISTER_REQ;
fe_msg.register_req = &rgstr_req;
- MGMTD_FE_CLIENT_DBG(
- "Sending REGISTER_REQ message to MGMTD Frontend server");
+ debug_fe_client("Sending REGISTER_REQ message to MGMTD Frontend server");
return mgmt_fe_client_send_msg(client, &fe_msg, true);
}
@@ -160,9 +157,8 @@ static int mgmt_fe_send_session_req(struct mgmt_fe_client *client,
fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_SESSION_REQ;
fe_msg.session_req = &sess_req;
- MGMTD_FE_CLIENT_DBG(
- "Sending SESSION_REQ %s message for client-id %" PRIu64,
- create ? "create" : "destroy", session->client_id);
+ debug_fe_client("Sending SESSION_REQ %s message for client-id %" PRIu64,
+ create ? "create" : "destroy", session->client_id);
return mgmt_fe_client_send_msg(client, &fe_msg, true);
}
@@ -185,9 +181,8 @@ int mgmt_fe_send_lockds_req(struct mgmt_fe_client *client, uint64_t session_id,
fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_LOCKDS_REQ;
fe_msg.lockds_req = &lockds_req;
- MGMTD_FE_CLIENT_DBG(
- "Sending LOCKDS_REQ (%sLOCK) message for DS:%s session-id %" PRIu64,
- lock ? "" : "UN", dsid2name(ds_id), session_id);
+ debug_fe_client("Sending LOCKDS_REQ (%sLOCK) message for DS:%s session-id %" PRIu64,
+ lock ? "" : "UN", dsid2name(ds_id), session_id);
return mgmt_fe_client_send_msg(client, &fe_msg, scok);
@@ -215,10 +210,9 @@ int mgmt_fe_send_setcfg_req(struct mgmt_fe_client *client, uint64_t session_id,
fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_SETCFG_REQ;
fe_msg.setcfg_req = &setcfg_req;
- MGMTD_FE_CLIENT_DBG(
- "Sending SET_CONFIG_REQ message for DS:%s session-id %" PRIu64
- " (#xpaths:%d)",
- dsid2name(ds_id), session_id, num_data_reqs);
+ debug_fe_client("Sending SET_CONFIG_REQ message for DS:%s session-id %" PRIu64
+ " (#xpaths:%d)",
+ dsid2name(ds_id), session_id, num_data_reqs);
return mgmt_fe_client_send_msg(client, &fe_msg, false);
}
@@ -245,9 +239,8 @@ int mgmt_fe_send_commitcfg_req(struct mgmt_fe_client *client,
fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_COMMCFG_REQ;
fe_msg.commcfg_req = &commitcfg_req;
- MGMTD_FE_CLIENT_DBG(
- "Sending COMMIT_CONFIG_REQ message for Src-DS:%s, Dst-DS:%s session-id %" PRIu64,
- dsid2name(src_ds_id), dsid2name(dest_ds_id), session_id);
+ debug_fe_client("Sending COMMIT_CONFIG_REQ message for Src-DS:%s, Dst-DS:%s session-id %" PRIu64,
+ dsid2name(src_ds_id), dsid2name(dest_ds_id), session_id);
return mgmt_fe_client_send_msg(client, &fe_msg, false);
}
@@ -273,10 +266,9 @@ int mgmt_fe_send_get_req(struct mgmt_fe_client *client, uint64_t session_id,
fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_GET_REQ;
fe_msg.get_req = &getcfg_req;
- MGMTD_FE_CLIENT_DBG("Sending GET_REQ (iscfg %d) message for DS:%s session-id %" PRIu64
- " (#xpaths:%d)",
- is_config, dsid2name(ds_id), session_id,
- num_data_reqs);
+ debug_fe_client("Sending GET_REQ (iscfg %d) message for DS:%s session-id %" PRIu64
+ " (#xpaths:%d)",
+ is_config, dsid2name(ds_id), session_id, num_data_reqs);
return mgmt_fe_client_send_msg(client, &fe_msg, false);
}
@@ -308,9 +300,10 @@ int mgmt_fe_send_regnotify_req(struct mgmt_fe_client *client,
/*
* Send get-data request.
*/
-int mgmt_fe_send_get_data_req(struct mgmt_fe_client *client, uint64_t session_id,
- uint64_t req_id, LYD_FORMAT result_type,
- uint8_t flags, const char *xpath)
+int mgmt_fe_send_get_data_req(struct mgmt_fe_client *client,
+ uint64_t session_id, uint64_t req_id,
+ uint8_t datastore, LYD_FORMAT result_type,
+ uint8_t flags, uint8_t defaults, const char *xpath)
{
struct mgmt_msg_get_data *msg;
size_t xplen = strlen(xpath);
@@ -323,11 +316,13 @@ int mgmt_fe_send_get_data_req(struct mgmt_fe_client *client, uint64_t session_id
msg->code = MGMT_MSG_CODE_GET_DATA;
msg->result_type = result_type;
msg->flags = flags;
+ msg->defaults = defaults;
+ msg->datastore = datastore;
strlcpy(msg->xpath, xpath, xplen + 1);
- MGMTD_FE_CLIENT_DBG("Sending GET_DATA_REQ session-id %" PRIu64
- " req-id %" PRIu64 " xpath: %s",
- session_id, req_id, xpath);
+ debug_fe_client("Sending GET_DATA_REQ session-id %" PRIu64
+ " req-id %" PRIu64 " xpath: %s",
+ session_id, req_id, xpath);
ret = mgmt_msg_native_send_msg(&client->client.conn, msg, false);
mgmt_msg_native_free_msg(msg);
@@ -348,30 +343,28 @@ static int mgmt_fe_client_handle_msg(struct mgmt_fe_client *client,
case MGMTD__FE_MESSAGE__MESSAGE_SESSION_REPLY:
if (fe_msg->session_reply->create &&
fe_msg->session_reply->has_client_conn_id) {
- MGMTD_FE_CLIENT_DBG(
- "Got SESSION_REPLY (create) for client-id %" PRIu64
- " with session-id: %" PRIu64,
- fe_msg->session_reply->client_conn_id,
- fe_msg->session_reply->session_id);
+ debug_fe_client("Got SESSION_REPLY (create) for client-id %" PRIu64
+ " with session-id: %" PRIu64,
+ fe_msg->session_reply->client_conn_id,
+ fe_msg->session_reply->session_id);
session = mgmt_fe_find_session_by_client_id(
client, fe_msg->session_reply->client_conn_id);
if (session && fe_msg->session_reply->success) {
- MGMTD_FE_CLIENT_DBG(
- "Session Created for client-id %" PRIu64,
- fe_msg->session_reply->client_conn_id);
+ debug_fe_client("Session Created for client-id %" PRIu64,
+ fe_msg->session_reply
+ ->client_conn_id);
session->session_id =
fe_msg->session_reply->session_id;
} else {
- MGMTD_FE_CLIENT_ERR(
+ log_err_fe_client(
"Session Create failed for client-id %" PRIu64,
fe_msg->session_reply->client_conn_id);
}
} else if (!fe_msg->session_reply->create) {
- MGMTD_FE_CLIENT_DBG(
- "Got SESSION_REPLY (destroy) for session-id %" PRIu64,
- fe_msg->session_reply->session_id);
+ debug_fe_client("Got SESSION_REPLY (destroy) for session-id %" PRIu64,
+ fe_msg->session_reply->session_id);
session = mgmt_fe_find_session_by_session_id(
client, fe_msg->session_req->session_id);
@@ -388,8 +381,8 @@ static int mgmt_fe_client_handle_msg(struct mgmt_fe_client *client,
session->user_ctx);
break;
case MGMTD__FE_MESSAGE__MESSAGE_LOCKDS_REPLY:
- MGMTD_FE_CLIENT_DBG("Got LOCKDS_REPLY for session-id %" PRIu64,
- fe_msg->lockds_reply->session_id);
+ debug_fe_client("Got LOCKDS_REPLY for session-id %" PRIu64,
+ fe_msg->lockds_reply->session_id);
session = mgmt_fe_find_session_by_session_id(
client, fe_msg->lockds_reply->session_id);
@@ -405,8 +398,8 @@ static int mgmt_fe_client_handle_msg(struct mgmt_fe_client *client,
fe_msg->lockds_reply->error_if_any);
break;
case MGMTD__FE_MESSAGE__MESSAGE_SETCFG_REPLY:
- MGMTD_FE_CLIENT_DBG("Got SETCFG_REPLY for session-id %" PRIu64,
- fe_msg->setcfg_reply->session_id);
+ debug_fe_client("Got SETCFG_REPLY for session-id %" PRIu64,
+ fe_msg->setcfg_reply->session_id);
session = mgmt_fe_find_session_by_session_id(
client, fe_msg->setcfg_reply->session_id);
@@ -423,8 +416,8 @@ static int mgmt_fe_client_handle_msg(struct mgmt_fe_client *client,
fe_msg->setcfg_reply->error_if_any);
break;
case MGMTD__FE_MESSAGE__MESSAGE_COMMCFG_REPLY:
- MGMTD_FE_CLIENT_DBG("Got COMMCFG_REPLY for session-id %" PRIu64,
- fe_msg->commcfg_reply->session_id);
+ debug_fe_client("Got COMMCFG_REPLY for session-id %" PRIu64,
+ fe_msg->commcfg_reply->session_id);
session = mgmt_fe_find_session_by_session_id(
client, fe_msg->commcfg_reply->session_id);
@@ -443,8 +436,8 @@ static int mgmt_fe_client_handle_msg(struct mgmt_fe_client *client,
fe_msg->commcfg_reply->error_if_any);
break;
case MGMTD__FE_MESSAGE__MESSAGE_GET_REPLY:
- MGMTD_FE_CLIENT_DBG("Got GET_REPLY for session-id %" PRIu64,
- fe_msg->get_reply->session_id);
+ debug_fe_client("Got GET_REPLY for session-id %" PRIu64,
+ fe_msg->get_reply->session_id);
session =
mgmt_fe_find_session_by_session_id(client,
@@ -507,19 +500,23 @@ static void fe_client_handle_native_msg(struct mgmt_fe_client *client,
struct mgmt_msg_header *msg,
size_t msg_len)
{
- struct mgmt_fe_client_session *session;
+ struct mgmt_fe_client_session *session = NULL;
+ struct mgmt_msg_notify_data *notify_msg;
struct mgmt_msg_tree_data *tree_msg;
struct mgmt_msg_error *err_msg;
+ char *notify_data = NULL;
- MGMTD_FE_CLIENT_DBG("Got GET_TREE reply for session-id %" PRIu64,
- msg->refer_id);
+ debug_fe_client("Got native message for session-id %" PRIu64,
+ msg->refer_id);
- session = mgmt_fe_find_session_by_session_id(client, msg->refer_id);
-
- if (!session || !session->client) {
- MGMTD_FE_CLIENT_ERR("No session for received native msg session-id %" PRIu64,
- msg->refer_id);
- return;
+ if (msg->code != MGMT_MSG_CODE_NOTIFY) {
+ session = mgmt_fe_find_session_by_session_id(client,
+ msg->refer_id);
+ if (!session || !session->client) {
+ log_err_fe_client("No session for received native msg session-id %" PRIu64,
+ msg->refer_id);
+ return;
+ }
}
switch (msg->code) {
@@ -529,7 +526,7 @@ static void fe_client_handle_native_msg(struct mgmt_fe_client *client,
err_msg = (typeof(err_msg))msg;
if (!MGMT_MSG_VALIDATE_NUL_TERM(err_msg, msg_len)) {
- MGMTD_FE_CLIENT_ERR("Corrupt error msg recv");
+ log_err_fe_client("Corrupt error msg recv");
return;
}
session->client->cbs.error_notify(client, client->user_data,
@@ -545,7 +542,7 @@ static void fe_client_handle_native_msg(struct mgmt_fe_client *client,
tree_msg = (typeof(tree_msg))msg;
if (msg_len < sizeof(*tree_msg)) {
- MGMTD_FE_CLIENT_ERR("Corrupt tree-data msg recv");
+ log_err_fe_client("Corrupt tree-data msg recv");
return;
}
session->client->cbs.get_tree_notify(client, client->user_data,
@@ -559,10 +556,48 @@ static void fe_client_handle_native_msg(struct mgmt_fe_client *client,
msg_len - sizeof(*tree_msg),
tree_msg->partial_error);
break;
+ case MGMT_MSG_CODE_NOTIFY:
+ notify_msg = (typeof(notify_msg))msg;
+ if (msg_len < sizeof(*notify_msg)) {
+ log_err_fe_client("Corrupt notify-data msg recv");
+ return;
+ }
+
+ if (notify_msg->result_type != LYD_LYB &&
+ !MGMT_MSG_VALIDATE_NUL_TERM(notify_msg, msg_len)) {
+ log_err_fe_client("Corrupt error msg recv");
+ return;
+ }
+ if (notify_msg->result_type == LYD_JSON)
+ notify_data = (char *)notify_msg->result;
+ else
+ notify_data =
+ yang_convert_lyd_format(notify_msg->result,
+ msg_len,
+ notify_msg->result_type,
+ LYD_JSON, true);
+ if (!notify_data) {
+ log_err_fe_client("Can't convert format %d to JSON",
+ notify_msg->result_type);
+ return;
+ }
+ FOREACH_SESSION_IN_LIST (client, session) {
+ if (!session->client->cbs.async_notification)
+ continue;
+
+ session->client->cbs
+ .async_notification(client, client->user_data,
+ session->client_id,
+ session->user_ctx,
+ notify_data);
+ }
+ if (notify_msg->result_type != LYD_JSON)
+ darr_free(notify_data);
+ break;
default:
- MGMTD_FE_CLIENT_ERR("unknown native message session-id %" PRIu64
- " req-id %" PRIu64 " code %u",
- msg->refer_id, msg->req_id, msg->code);
+ log_err_fe_client("unknown native message session-id %" PRIu64
+ " req-id %" PRIu64 " code %u",
+ msg->refer_id, msg->req_id, msg->code);
break;
}
}
@@ -583,20 +618,18 @@ static void mgmt_fe_client_process_msg(uint8_t version, uint8_t *data,
if (len >= sizeof(*msg))
fe_client_handle_native_msg(client, msg, len);
else
- MGMTD_FE_CLIENT_ERR("native message to FE client %s too short %zu",
- client->name, len);
+ log_err_fe_client("native message to FE client %s too short %zu",
+ client->name, len);
return;
}
fe_msg = mgmtd__fe_message__unpack(NULL, len, data);
if (!fe_msg) {
- MGMTD_FE_CLIENT_DBG("Failed to decode %zu bytes from server.",
- len);
+ debug_fe_client("Failed to decode %zu bytes from server.", len);
return;
}
- MGMTD_FE_CLIENT_DBG(
- "Decoded %zu bytes of message(msg: %u/%u) from server", len,
- fe_msg->message_case, fe_msg->message_case);
+ debug_fe_client("Decoded %zu bytes of message(msg: %u/%u) from server",
+ len, fe_msg->message_case, fe_msg->message_case);
(void)mgmt_fe_client_handle_msg(client, fe_msg);
mgmtd__fe_message__free_unpacked(fe_msg, NULL);
}
@@ -617,7 +650,7 @@ static int _notify_connect_disconnect(struct msg_client *msg_client,
/* Walk list of sessions for this FE client deleting them */
if (!connected && mgmt_sessions_count(&client->sessions)) {
- MGMTD_FE_CLIENT_DBG("Cleaning up existing sessions");
+ debug_fe_client("Cleaning up existing sessions");
FOREACH_SESSION_IN_LIST (client, session) {
assert(session->client);
@@ -688,7 +721,7 @@ static int mgmt_debug_fe_client_config_write(struct vty *vty)
void mgmt_debug_fe_client_show_debug(struct vty *vty)
{
- if (MGMTD_DBG_FE_CLIENT_CHECK())
+ if (debug_check_fe_client())
vty_out(vty, "debug mgmt client frontend\n");
}
@@ -734,9 +767,9 @@ struct mgmt_fe_client *mgmt_fe_client_create(const char *client_name,
mgmt_fe_client_notify_disconnect,
mgmt_fe_client_process_msg, MGMTD_FE_MAX_NUM_MSG_PROC,
MGMTD_FE_MAX_NUM_MSG_WRITE, MGMTD_FE_MAX_MSG_LEN, true,
- "FE-client", MGMTD_DBG_FE_CLIENT_CHECK());
+ "FE-client", debug_check_fe_client());
- MGMTD_FE_CLIENT_DBG("Initialized client '%s'", client_name);
+ debug_fe_client("Initialized client '%s'", client_name);
return client;
}
@@ -805,9 +838,8 @@ enum mgmt_result mgmt_fe_destroy_client_session(struct mgmt_fe_client *client,
if (session->session_id &&
mgmt_fe_send_session_req(client, session, false) != 0)
- MGMTD_FE_CLIENT_ERR(
- "Failed to send session destroy request for the session-id %" PRIu64,
- session->session_id);
+ log_err_fe_client("Failed to send session destroy request for the session-id %" PRIu64,
+ session->session_id);
mgmt_sessions_del(&client->sessions, session);
XFREE(MTYPE_MGMTD_FE_SESSION, session);
@@ -824,8 +856,7 @@ void mgmt_fe_client_destroy(struct mgmt_fe_client *client)
assert(client == __fe_client);
- MGMTD_FE_CLIENT_DBG("Destroying MGMTD Frontend Client '%s'",
- client->name);
+ debug_fe_client("Destroying MGMTD Frontend Client '%s'", client->name);
FOREACH_SESSION_IN_LIST (client, session)
mgmt_fe_destroy_client_session(client, session->client_id);
diff --git a/lib/mgmt_fe_client.h b/lib/mgmt_fe_client.h
index 3abe29b1cf..7af1270071 100644
--- a/lib/mgmt_fe_client.h
+++ b/lib/mgmt_fe_client.h
@@ -114,6 +114,11 @@ struct mgmt_fe_client_cbs {
LYD_FORMAT result_type, void *result, size_t len,
int partial_error);
+ /* Called with asynchronous notifications from backends */
+ int (*async_notification)(struct mgmt_fe_client *client,
+ uintptr_t user_data, uint64_t client_id,
+ uintptr_t session_ctx, const char *result);
+
/* Called when new native error is returned */
int (*error_notify)(struct mgmt_fe_client *client, uintptr_t user_data,
uint64_t client_id, uint64_t session_id,
@@ -127,12 +132,12 @@ extern struct debug mgmt_dbg_fe_client;
* API prototypes
***************************************************************/
-#define MGMTD_FE_CLIENT_DBG(fmt, ...) \
+#define debug_fe_client(fmt, ...) \
DEBUGD(&mgmt_dbg_fe_client, "FE-CLIENT: %s: " fmt, __func__, \
##__VA_ARGS__)
-#define MGMTD_FE_CLIENT_ERR(fmt, ...) \
+#define log_err_fe_client(fmt, ...) \
zlog_err("FE-CLIENT: %s: ERROR: " fmt, __func__, ##__VA_ARGS__)
-#define MGMTD_DBG_FE_CLIENT_CHECK() \
+#define debug_check_fe_client() \
DEBUG_MODE_CHECK(&mgmt_dbg_fe_client, DEBUG_MODE_ALL)
/*
@@ -379,12 +384,18 @@ extern int mgmt_fe_send_regnotify_req(struct mgmt_fe_client *client,
* req_id
* Client request ID.
*
+ * datastore
+ * Datastore for getting data.
+ *
* result_type
* The LYD_FORMAT of the result.
*
* flags
* Flags to control the behavior of the request.
*
+ * defaults
+ * Options to control the reporting of default values.
+ *
* xpath
* the xpath to get.
*
@@ -393,7 +404,8 @@ extern int mgmt_fe_send_regnotify_req(struct mgmt_fe_client *client,
*/
extern int mgmt_fe_send_get_data_req(struct mgmt_fe_client *client,
uint64_t session_id, uint64_t req_id,
- LYD_FORMAT result_type, uint8_t flags,
+ uint8_t datastore, LYD_FORMAT result_type,
+ uint8_t flags, uint8_t defaults,
const char *xpath);
/*
diff --git a/lib/mgmt_msg_native.c b/lib/mgmt_msg_native.c
index a9b26718db..d27c5d3a29 100644
--- a/lib/mgmt_msg_native.c
+++ b/lib/mgmt_msg_native.c
@@ -14,6 +14,7 @@ DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_ERROR, "native error msg");
DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_GET_TREE, "native get tree msg");
DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_TREE_DATA, "native tree data msg");
DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_GET_DATA, "native get data msg");
+DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_NOTIFY, "native get data msg");
int vmgmt_msg_native_send_error(struct msg_conn *conn, uint64_t sess_or_txn_id,
uint64_t req_id, bool short_circuit_ok,
diff --git a/lib/mgmt_msg_native.h b/lib/mgmt_msg_native.h
index 069cb9b150..7273170a13 100644
--- a/lib/mgmt_msg_native.h
+++ b/lib/mgmt_msg_native.h
@@ -143,6 +143,7 @@ DECLARE_MTYPE(MSG_NATIVE_ERROR);
DECLARE_MTYPE(MSG_NATIVE_GET_TREE);
DECLARE_MTYPE(MSG_NATIVE_TREE_DATA);
DECLARE_MTYPE(MSG_NATIVE_GET_DATA);
+DECLARE_MTYPE(MSG_NATIVE_NOTIFY);
/*
* Native message codes
@@ -151,6 +152,31 @@ DECLARE_MTYPE(MSG_NATIVE_GET_DATA);
#define MGMT_MSG_CODE_GET_TREE 1
#define MGMT_MSG_CODE_TREE_DATA 2
#define MGMT_MSG_CODE_GET_DATA 3
+#define MGMT_MSG_CODE_NOTIFY 4
+
+/*
+ * Datastores
+ */
+#define MGMT_MSG_DATASTORE_STARTUP 0
+#define MGMT_MSG_DATASTORE_CANDIDATE 1
+#define MGMT_MSG_DATASTORE_RUNNING 2
+#define MGMT_MSG_DATASTORE_OPERATIONAL 3
+
+/*
+ * Formats
+ */
+#define MGMT_MSG_FORMAT_XML 1
+#define MGMT_MSG_FORMAT_JSON 2
+#define MGMT_MSG_FORMAT_BINARY 3 /* non-standard libyang internal format */
+
+/*
+ * Now we're using LYD_FORMAT directly to avoid mapping code, but having our
+ * own definitions allows us to create such a mapping in the future if libyang
+ * makes a backwards incompatible change.
+ */
+_Static_assert(MGMT_MSG_FORMAT_XML == LYD_XML, "Format mismatch");
+_Static_assert(MGMT_MSG_FORMAT_JSON == LYD_JSON, "Format mismatch");
+_Static_assert(MGMT_MSG_FORMAT_BINARY == LYD_LYB, "Format mismatch");
/**
* struct mgmt_msg_header - Header common to all native messages.
@@ -234,22 +260,34 @@ _Static_assert(sizeof(struct mgmt_msg_tree_data) ==
"Size mismatch");
/* Flags for get-data request */
-#define GET_DATA_FLAG_STATE 0x01 /* get only "config false" data */
-#define GET_DATA_FLAG_CONFIG 0x02 /* get only "config true" data */
+#define GET_DATA_FLAG_STATE 0x01 /* include "config false" data */
+#define GET_DATA_FLAG_CONFIG 0x02 /* include "config true" data */
#define GET_DATA_FLAG_EXACT 0x04 /* get exact data node instead of the full tree */
+/*
+ * Modes of reporting default values. Non-default values are always reported.
+ * These options reflect "with-defaults" modes as defined in RFC 6243.
+ */
+#define GET_DATA_DEFAULTS_EXPLICIT 0 /* "explicit" */
+#define GET_DATA_DEFAULTS_TRIM 1 /* "trim" */
+#define GET_DATA_DEFAULTS_ALL 2 /* "report-all" */
+#define GET_DATA_DEFAULTS_ALL_ADD_TAG 3 /* "report-all-tagged" */
+
/**
* struct mgmt_msg_get_data - frontend get-data request.
*
* @result_type: ``LYD_FORMAT`` for the returned result.
* @flags: combination of ``GET_DATA_FLAG_*`` flags.
+ * @defaults: one of ``GET_DATA_DEFAULTS_*`` values.
* @xpath: the query for the data to return.
*/
struct mgmt_msg_get_data {
struct mgmt_msg_header;
uint8_t result_type;
uint8_t flags;
- uint8_t resv2[6];
+ uint8_t defaults;
+ uint8_t datastore;
+ uint8_t resv2[4];
alignas(8) char xpath[];
};
@@ -257,8 +295,29 @@ _Static_assert(sizeof(struct mgmt_msg_get_data) ==
offsetof(struct mgmt_msg_get_data, xpath),
"Size mismatch");
+/**
+ * struct mgmt_msg_notify_data - Message carrying notification data.
+ *
+ * @result_type: ``LYD_FORMAT`` for format of the @result value.
+ * @result: The tree data in @result_type format.
+ *
+ */
+struct mgmt_msg_notify_data {
+ struct mgmt_msg_header;
+ uint8_t result_type;
+ uint8_t resv2[7];
+
+ alignas(8) uint8_t result[];
+};
+_Static_assert(sizeof(struct mgmt_msg_notify_data) ==
+ offsetof(struct mgmt_msg_notify_data, result),
+ "Size mismatch");
+
+/*
+ * Validate that the message ends in a NUL terminating byte
+ */
#define MGMT_MSG_VALIDATE_NUL_TERM(msgp, len) \
- ((len) >= sizeof(*msg) + 1 && ((char *)msgp)[(len)-1] == 0)
+ ((len) >= sizeof(*msgp) + 1 && ((char *)msgp)[(len)-1] == 0)
/**
diff --git a/lib/northbound.c b/lib/northbound.c
index b1da3315d0..a0b1bd18c5 100644
--- a/lib/northbound.c
+++ b/lib/northbound.c
@@ -2068,6 +2068,23 @@ int nb_notification_send(const char *xpath, struct list *arguments)
return ret;
}
+DEFINE_HOOK(nb_notification_tree_send, (struct lyd_node *tree), (tree));
+
+int nb_notification_tree_send(struct lyd_node *tree)
+{
+ int ret;
+
+ assert(tree);
+
+ DEBUGD(&nb_dbg_notif, "northbound tree notification: %s",
+ tree->schema->name);
+
+ ret = hook_call(nb_notification_tree_send, tree);
+ lyd_free_all(tree);
+
+ return ret;
+}
+
/* Running configuration user pointers management. */
struct nb_config_entry {
char xpath[XPATH_MAXLEN];
diff --git a/lib/northbound.h b/lib/northbound.h
index 2d9643e7b4..9279122deb 100644
--- a/lib/northbound.h
+++ b/lib/northbound.h
@@ -1441,6 +1441,10 @@ extern bool nb_cb_operation_is_valid(enum nb_cb_operation operation,
const struct lysc_node *snode);
/*
+ * DEPRECATED: This call and infra should no longer be used. Instead,
+ * the mgmtd supported tree based call `nb_notification_tree_send` should be
+ * used instead
+ *
* Send a YANG notification. This is a no-op unless the 'nb_notification_send'
* hook was registered by a northbound plugin.
*
@@ -1457,6 +1461,19 @@ extern bool nb_cb_operation_is_valid(enum nb_cb_operation operation,
extern int nb_notification_send(const char *xpath, struct list *arguments);
/*
+ * Send a YANG notification from a backend . This is a no-op unless th
+ * 'nb_notification_tree_send' hook was registered by a northbound plugin.
+ *
+ * tree
+ * The libyang tree for the notification. The tree will be freed by
+ * this call.
+ *
+ * Returns:
+ * NB_OK on success, NB_ERR otherwise.
+ */
+extern int nb_notification_tree_send(struct lyd_node *tree);
+
+/*
* Associate a user pointer to a configuration node.
*
* This should be called by northbound 'create' callbacks in the NB_EV_APPLY
diff --git a/lib/routing_nb.h b/lib/routing_nb.h
index c185091a4b..cc83d8469d 100644
--- a/lib/routing_nb.h
+++ b/lib/routing_nb.h
@@ -29,6 +29,8 @@ int routing_control_plane_protocols_control_plane_protocol_destroy(
* based on the control plane protocol
*/
DECLARE_HOOK(routing_conf_event, (struct nb_cb_create_args *args), (args));
+DECLARE_HOOK(routing_create, (struct nb_cb_create_args *args), (args));
+DECLARE_KOOH(routing_destroy, (struct nb_cb_destroy_args *args), (args));
void routing_control_plane_protocols_register_vrf_dependency(void);
diff --git a/lib/routing_nb_config.c b/lib/routing_nb_config.c
index 2b20e6c14b..d532279a22 100644
--- a/lib/routing_nb_config.c
+++ b/lib/routing_nb_config.c
@@ -14,6 +14,8 @@
DEFINE_HOOK(routing_conf_event, (struct nb_cb_create_args *args), (args));
+DEFINE_HOOK(routing_create, (struct nb_cb_create_args *args), (args));
+DEFINE_KOOH(routing_destroy, (struct nb_cb_destroy_args *args), (args));
/*
* XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol
@@ -49,6 +51,7 @@ int routing_control_plane_protocols_control_plane_protocol_create(
assert(vrf);
nb_running_set_entry(args->dnode, vrf);
}
+ hook_call(routing_create, args);
break;
};
@@ -61,6 +64,8 @@ int routing_control_plane_protocols_control_plane_protocol_destroy(
if (args->event != NB_EV_APPLY)
return NB_OK;
+ hook_call(routing_destroy, args);
+
/*
* If dependency on VRF module is registered, then VRF
* pointer was stored and must be cleared.
diff --git a/lib/vrf.c b/lib/vrf.c
index 65721445ab..f8fa70bfe8 100644
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -681,18 +681,6 @@ DEFUN_YANG (no_vrf,
const char *vrfname = argv[2]->arg;
char xpath_list[XPATH_MAXLEN];
- struct vrf *vrfp;
-
- vrfp = vrf_lookup_by_name(vrfname);
-
- if (vrfp == NULL)
- return CMD_SUCCESS;
-
- if (CHECK_FLAG(vrfp->status, VRF_ACTIVE)) {
- vty_out(vty, "%% Only inactive VRFs can be deleted\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
if (vrf_get_backend() == VRF_BACKEND_VRF_LITE) {
/*
* Remove the VRF interface config when removing the VRF.
diff --git a/lib/vty.c b/lib/vty.c
index ea35c541ee..1c9cff478d 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -178,10 +178,10 @@ void vty_mgmt_resume_response(struct vty *vty, int ret)
return;
}
- MGMTD_FE_CLIENT_DBG("resuming CLI cmd after %s on vty session-id: %" PRIu64
- " with '%s'",
- vty->mgmt_req_pending_cmd, vty->mgmt_session_id,
- ret == CMD_SUCCESS ? "success" : "failed");
+ debug_fe_client("resuming CLI cmd after %s on vty session-id: %" PRIu64
+ " with '%s'",
+ vty->mgmt_req_pending_cmd, vty->mgmt_session_id,
+ ret == CMD_SUCCESS ? "success" : "failed");
vty->mgmt_req_pending_cmd = NULL;
@@ -2402,10 +2402,9 @@ static void vtysh_read(struct event *thread)
* we get response through callback.
*/
if (vty->mgmt_req_pending_cmd) {
- MGMTD_FE_CLIENT_DBG(
- "postpone CLI response pending mgmtd %s on vty session-id %" PRIu64,
- vty->mgmt_req_pending_cmd,
- vty->mgmt_session_id);
+ debug_fe_client("postpone CLI response pending mgmtd %s on vty session-id %" PRIu64,
+ vty->mgmt_req_pending_cmd,
+ vty->mgmt_session_id);
return;
}
@@ -2486,14 +2485,14 @@ void vty_close(struct vty *vty)
* so warn the user.
*/
if (vty->mgmt_num_pending_setcfg)
- MGMTD_FE_CLIENT_ERR(
+ log_err_fe_client(
"vty closed, uncommitted config will be lost.");
/* Drop out of configure / transaction if needed. */
vty_config_exit(vty);
if (mgmt_fe_client && vty->mgmt_session_id) {
- MGMTD_FE_CLIENT_DBG("closing vty session");
+ debug_fe_client("closing vty session");
mgmt_fe_destroy_client_session(mgmt_fe_client,
vty->mgmt_client_id);
vty->mgmt_session_id = 0;
@@ -3473,9 +3472,8 @@ void vty_init_vtysh(void)
static void vty_mgmt_server_connected(struct mgmt_fe_client *client,
uintptr_t usr_data, bool connected)
{
- MGMTD_FE_CLIENT_DBG("Got %sconnected %s MGMTD Frontend Server",
- !connected ? "dis: " : "",
- !connected ? "from" : "to");
+ debug_fe_client("Got %sconnected %s MGMTD Frontend Server",
+ !connected ? "dis: " : "", !connected ? "from" : "to");
/*
* We should not have any sessions for connecting or disconnecting case.
@@ -3511,8 +3509,8 @@ static void vty_mgmt_session_notify(struct mgmt_fe_client *client,
return;
}
- MGMTD_FE_CLIENT_DBG("%s session for client %" PRIu64 " successfully",
- create ? "Created" : "Destroyed", client_id);
+ debug_fe_client("%s session for client %" PRIu64 " successfully",
+ create ? "Created" : "Destroyed", client_id);
if (create) {
assert(session_id != 0);
@@ -3543,8 +3541,8 @@ static void vty_mgmt_ds_lock_notified(struct mgmt_fe_client *client,
zlog_err("%socking for DS %u failed, Err: '%s' vty %p",
lock_ds ? "L" : "Unl", ds_id, errmsg_if_any, vty);
else {
- MGMTD_FE_CLIENT_DBG("%socked DS %u successfully",
- lock_ds ? "L" : "Unl", ds_id);
+ debug_fe_client("%socked DS %u successfully",
+ lock_ds ? "L" : "Unl", ds_id);
if (ds_id == MGMTD_DS_CANDIDATE)
vty->mgmt_locked_candidate_ds = lock_ds;
else
@@ -3575,9 +3573,9 @@ static void vty_mgmt_set_config_result_notified(
vty_out(vty, "ERROR: SET_CONFIG request failed, Error: %s\n",
errmsg_if_any ? errmsg_if_any : "Unknown");
} else {
- MGMTD_FE_CLIENT_DBG("SET_CONFIG request for client 0x%" PRIx64
- " req-id %" PRIu64 " was successfull",
- client_id, req_id);
+ debug_fe_client("SET_CONFIG request for client 0x%" PRIx64
+ " req-id %" PRIu64 " was successfull",
+ client_id, req_id);
}
if (implicit_commit) {
@@ -3607,10 +3605,9 @@ static void vty_mgmt_commit_config_result_notified(
vty_out(vty, "ERROR: COMMIT_CONFIG request failed, Error: %s\n",
errmsg_if_any ? errmsg_if_any : "Unknown");
} else {
- MGMTD_FE_CLIENT_DBG(
- "COMMIT_CONFIG request for client 0x%" PRIx64
- " req-id %" PRIu64 " was successfull",
- client_id, req_id);
+ debug_fe_client("COMMIT_CONFIG request for client 0x%" PRIx64
+ " req-id %" PRIu64 " was successfull",
+ client_id, req_id);
if (errmsg_if_any)
vty_out(vty, "MGMTD: %s\n", errmsg_if_any);
}
@@ -3640,9 +3637,9 @@ static int vty_mgmt_get_data_result_notified(
return -1;
}
- MGMTD_FE_CLIENT_DBG("GET_DATA request succeeded, client 0x%" PRIx64
- " req-id %" PRIu64,
- client_id, req_id);
+ debug_fe_client("GET_DATA request succeeded, client 0x%" PRIx64
+ " req-id %" PRIu64,
+ client_id, req_id);
if (req_id != mgmt_last_req_id) {
mgmt_last_req_id = req_id;
@@ -3788,10 +3785,9 @@ static int vty_mgmt_get_tree_result_notified(
vty = (struct vty *)session_ctx;
- MGMTD_FE_CLIENT_DBG("GET_TREE request %ssucceeded, client 0x%" PRIx64
- " req-id %" PRIu64,
- partial_error ? "partially " : "", client_id,
- req_id);
+ debug_fe_client("GET_TREE request %ssucceeded, client 0x%" PRIx64
+ " req-id %" PRIu64,
+ partial_error ? "partially " : "", client_id, req_id);
assert(result_type == LYD_LYB ||
result_type == vty->mgmt_req_pending_data);
@@ -3838,21 +3834,20 @@ static int vty_mgmt_error_notified(struct mgmt_fe_client *client,
const char *cname = mgmt_fe_client_name(client);
if (!vty->mgmt_req_pending_cmd) {
- MGMTD_FE_CLIENT_DBG("Erorr with no pending command: %d returned for client %s 0x%" PRIx64
- " session-id %" PRIu64 " req-id %" PRIu64
- "error-str %s",
- error, cname, client_id, session_id, req_id,
- errstr);
+ debug_fe_client("Erorr with no pending command: %d returned for client %s 0x%" PRIx64
+ " session-id %" PRIu64 " req-id %" PRIu64
+ "error-str %s",
+ error, cname, client_id, session_id, req_id,
+ errstr);
vty_out(vty,
"%% Error %d from MGMTD for %s with no pending command: %s\n",
error, cname, errstr);
return CMD_WARNING;
}
- MGMTD_FE_CLIENT_DBG("Erorr %d returned for client %s 0x%" PRIx64
- " session-id %" PRIu64 " req-id %" PRIu64
- "error-str %s",
- error, cname, client_id, session_id, req_id, errstr);
+ debug_fe_client("Erorr %d returned for client %s 0x%" PRIx64
+ " session-id %" PRIu64 " req-id %" PRIu64 "error-str %s",
+ error, cname, client_id, session_id, req_id, errstr);
vty_out(vty, "%% %s (for %s, client %s)\n", errstr,
vty->mgmt_req_pending_cmd, cname);
@@ -4101,16 +4096,17 @@ int vty_mgmt_send_get_req(struct vty *vty, bool is_config,
return 0;
}
-int vty_mgmt_send_get_data_req(struct vty *vty, LYD_FORMAT result_type,
- uint8_t flags, const char *xpath)
+int vty_mgmt_send_get_data_req(struct vty *vty, uint8_t datastore,
+ LYD_FORMAT result_type, uint8_t flags,
+ uint8_t defaults, const char *xpath)
{
LYD_FORMAT intern_format = result_type;
vty->mgmt_req_id++;
if (mgmt_fe_send_get_data_req(mgmt_fe_client, vty->mgmt_session_id,
- vty->mgmt_req_id, intern_format, flags,
- xpath)) {
+ vty->mgmt_req_id, datastore,
+ intern_format, flags, defaults, xpath)) {
zlog_err("Failed to send GET-DATA to MGMTD session-id: %" PRIu64
" req-id %" PRIu64 ".",
vty->mgmt_session_id, vty->mgmt_req_id);
diff --git a/lib/vty.h b/lib/vty.h
index 73e0d238ad..06973da916 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -420,8 +420,9 @@ extern int vty_mgmt_send_commit_config(struct vty *vty, bool validate_only,
extern int vty_mgmt_send_get_req(struct vty *vty, bool is_config,
Mgmtd__DatastoreId datastore,
const char **xpath_list, int num_req);
-extern int vty_mgmt_send_get_data_req(struct vty *vty, LYD_FORMAT result_type,
- uint8_t flags, const char *xpath);
+extern int vty_mgmt_send_get_data_req(struct vty *vty, uint8_t datastore,
+ LYD_FORMAT result_type, uint8_t flags,
+ uint8_t defaults, const char *xpath);
extern int vty_mgmt_send_lockds_req(struct vty *vty, Mgmtd__DatastoreId ds_id,
bool lock, bool scok);
extern void vty_mgmt_resume_response(struct vty *vty, int ret);
diff --git a/lib/yang.c b/lib/yang.c
index 3dd2513a4b..2b360376d3 100644
--- a/lib/yang.c
+++ b/lib/yang.c
@@ -744,6 +744,34 @@ uint8_t *yang_print_tree(const struct lyd_node *root, LYD_FORMAT format,
return darr;
}
+char *yang_convert_lyd_format(const uint8_t *data, size_t data_len,
+ LYD_FORMAT in_format,
+ LYD_FORMAT out_format, bool shrink)
+{
+ struct lyd_node *tree = NULL;
+ uint8_t *result = NULL;
+ uint32_t options = LYD_PRINT_WD_EXPLICIT | LYD_PRINT_WITHSIBLINGS;
+
+ assert(out_format != LYD_LYB);
+
+ if (!MGMT_MSG_VALIDATE_NUL_TERM(data, data_len))
+ return NULL;
+
+ if (in_format == out_format)
+ return darr_strdup((const char *)data);
+
+ if (shrink)
+ options |= LYD_PRINT_SHRINK;
+
+ /* Take a guess at the initial capacity based on input data size */
+ darr_ensure_cap(result, data_len);
+ if (yang_print_tree_append(&result, tree, out_format, options)) {
+ darr_free(result);
+ return NULL;
+ }
+ return (char *)result;
+}
+
const char *yang_print_errors(struct ly_ctx *ly_ctx, char *buf, size_t buf_len)
{
struct ly_err_item *ei;
diff --git a/lib/yang.h b/lib/yang.h
index 431b2eee48..4ed0a39ba4 100644
--- a/lib/yang.h
+++ b/lib/yang.h
@@ -622,6 +622,22 @@ extern void yang_debugging_set(bool enable);
extern uint8_t *yang_print_tree(const struct lyd_node *root, LYD_FORMAT format,
uint32_t options);
+
+/**
+ * yang_convert_lyd_format() - convert one libyang format to darr string.
+ * @data: data to convert.
+ * @data_len: length of the data.
+ * @in_format: format of the data.
+ * @out_format: format to return.
+ * @shrink: true to avoid pretty printing.
+ *
+ * Return:
+ * A darr based string or NULL for error.
+ */
+extern char *yang_convert_lyd_format(const uint8_t *data, size_t msg_len,
+ LYD_FORMAT in_format,
+ LYD_FORMAT out_format, bool shrink);
+
/*
* "Print" the yang tree in `root` into an existing dynamic sized array.
*
diff --git a/lib/zebra.h b/lib/zebra.h
index 8b0800c257..15a54f6cdf 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -221,9 +221,6 @@ struct in_pktinfo {
#define IN6_ARE_ADDR_EQUAL IN6_IS_ADDR_EQUAL
#endif /* IN6_ARE_ADDR_EQUAL */
-/* default zebra TCP port for zclient */
-#define ZEBRA_PORT 2600
-
/* Zebra route's types are defined in route_types.h */
#include "lib/route_types.h"
diff --git a/mgmtd/mgmt.h b/mgmtd/mgmt.h
index d46b1341ec..665e8d8fd8 100644
--- a/mgmtd/mgmt.h
+++ b/mgmtd/mgmt.h
@@ -20,7 +20,6 @@
#include "mgmtd/mgmt_txn.h"
#include "mgmtd/mgmt_ds.h"
-#define MGMTD_VTY_PORT 2623
#define MGMTD_SOCKET_BUF_SIZE 65535
#define MGMTD_MAX_COMMIT_LIST 10
diff --git a/mgmtd/mgmt_be_adapter.c b/mgmtd/mgmt_be_adapter.c
index 8d7ae88555..aba02e4653 100644
--- a/mgmtd/mgmt_be_adapter.c
+++ b/mgmtd/mgmt_be_adapter.c
@@ -22,9 +22,9 @@
#include "mgmt_be_client.h"
#include "mgmtd/mgmt_be_adapter.h"
-#define MGMTD_BE_ADAPTER_DBG(fmt, ...) \
+#define __dbg(fmt, ...) \
DEBUGD(&mgmt_debug_be, "BE-ADAPTER: %s: " fmt, __func__, ##__VA_ARGS__)
-#define MGMTD_BE_ADAPTER_ERR(fmt, ...) \
+#define __log_err(fmt, ...) \
zlog_err("BE-ADAPTER: %s: ERROR: " fmt, __func__, ##__VA_ARGS__)
#define FOREACH_ADAPTER_IN_LIST(adapter) \
@@ -35,6 +35,7 @@
/* ---------- */
const char *mgmt_be_client_names[MGMTD_BE_CLIENT_ID_MAX + 1] = {
+ [MGMTD_BE_CLIENT_ID_TESTC] = "mgmtd-testc", /* always first */
[MGMTD_BE_CLIENT_ID_ZEBRA] = "zebra",
#ifdef HAVE_RIPD
[MGMTD_BE_CLIENT_ID_RIPD] = "ripd",
@@ -155,6 +156,7 @@ static const char *const *be_client_oper_xpaths[MGMTD_BE_CLIENT_ID_MAX] = {
static struct mgmt_be_xpath_map *be_cfg_xpath_map;
static struct mgmt_be_xpath_map *be_oper_xpath_map;
+static struct mgmt_be_xpath_map *be_notif_xpath_map;
static struct event_loop *mgmt_loop;
static struct msg_server mgmt_be_server = {.fd = -1};
@@ -219,11 +221,16 @@ mgmt_be_find_adapter_by_name(const char *name)
}
static void mgmt_register_client_xpath(enum mgmt_be_client_id id,
- const char *xpath, bool config)
+ const char *xpath, bool config, bool oper)
{
struct mgmt_be_xpath_map **maps, *map;
- maps = config ? &be_cfg_xpath_map : &be_oper_xpath_map;
+ if (config)
+ maps = &be_cfg_xpath_map;
+ else if (oper)
+ maps = &be_oper_xpath_map;
+ else
+ maps = &be_notif_xpath_map;
darr_foreach_p (*maps, map) {
if (!strcmp(xpath, map->xpath_prefix)) {
@@ -245,26 +252,24 @@ static void mgmt_be_xpath_map_init(void)
enum mgmt_be_client_id id;
const char *const *init;
- MGMTD_BE_ADAPTER_DBG("Init XPath Maps");
+ __dbg("Init XPath Maps");
FOREACH_MGMTD_BE_CLIENT_ID (id) {
/* Initialize the common config init map */
for (init = be_client_config_xpaths[id]; init && *init; init++) {
- MGMTD_BE_ADAPTER_DBG(" - CFG XPATH: '%s'", *init);
- mgmt_register_client_xpath(id, *init, true);
+ __dbg(" - CFG XPATH: '%s'", *init);
+ mgmt_register_client_xpath(id, *init, true, false);
}
/* Initialize the common oper init map */
for (init = be_client_oper_xpaths[id]; init && *init; init++) {
- MGMTD_BE_ADAPTER_DBG(" - OPER XPATH: '%s'", *init);
- mgmt_register_client_xpath(id, *init, false);
+ __dbg(" - OPER XPATH: '%s'", *init);
+ mgmt_register_client_xpath(id, *init, false, true);
}
}
- MGMTD_BE_ADAPTER_DBG("Total Cfg XPath Maps: %u",
- darr_len(be_cfg_xpath_map));
- MGMTD_BE_ADAPTER_DBG("Total Oper XPath Maps: %u",
- darr_len(be_oper_xpath_map));
+ __dbg("Total Cfg XPath Maps: %u", darr_len(be_cfg_xpath_map));
+ __dbg("Total Oper XPath Maps: %u", darr_len(be_oper_xpath_map));
}
static void mgmt_be_xpath_map_cleanup(void)
@@ -278,6 +283,10 @@ static void mgmt_be_xpath_map_cleanup(void)
darr_foreach_p (be_oper_xpath_map, map)
XFREE(MTYPE_MGMTD_XPATH, map->xpath_prefix);
darr_free(be_oper_xpath_map);
+
+ darr_foreach_p (be_notif_xpath_map, map)
+ XFREE(MTYPE_MGMTD_XPATH, map->xpath_prefix);
+ darr_free(be_notif_xpath_map);
}
@@ -308,7 +317,7 @@ static bool mgmt_be_xpath_prefix(const char *path, const char *xpath)
static void mgmt_be_adapter_delete(struct mgmt_be_client_adapter *adapter)
{
- MGMTD_BE_ADAPTER_DBG("deleting client adapter '%s'", adapter->name);
+ __dbg("deleting client adapter '%s'", adapter->name);
/*
* Notify about disconnect for appropriate cleanup
@@ -327,8 +336,7 @@ static int mgmt_be_adapter_notify_disconnect(struct msg_conn *conn)
{
struct mgmt_be_client_adapter *adapter = conn->user;
- MGMTD_BE_ADAPTER_DBG("notify disconnect for client adapter '%s'",
- adapter->name);
+ __dbg("notify disconnect for client adapter '%s'", adapter->name);
mgmt_be_adapter_delete(adapter);
@@ -346,10 +354,8 @@ mgmt_be_adapter_cleanup_old_conn(struct mgmt_be_client_adapter *adapter)
/*
* We have a Zombie lingering around
*/
- MGMTD_BE_ADAPTER_DBG(
- "Client '%s' (FD:%d) seems to have reconnected. Removing old connection (FD:%d)!",
- adapter->name, adapter->conn->fd,
- old->conn->fd);
+ __dbg("Client '%s' (FD:%d) seems to have reconnected. Removing old connection (FD:%d)!",
+ adapter->name, adapter->conn->fd, old->conn->fd);
/* this will/should delete old */
msg_conn_disconnect(old->conn, false);
}
@@ -378,8 +384,8 @@ static int mgmt_be_send_subscr_reply(struct mgmt_be_client_adapter *adapter,
be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_SUBSCR_REPLY;
be_msg.subscr_reply = &reply;
- MGMTD_BE_CLIENT_DBG("Sending SUBSCR_REPLY client: %s sucess: %u",
- adapter->name, success);
+ __dbg("Sending SUBSCR_REPLY client: %s sucess: %u", adapter->name,
+ success);
return mgmt_be_adapter_send_msg(adapter, &be_msg);
}
@@ -388,32 +394,30 @@ static int
mgmt_be_adapter_handle_msg(struct mgmt_be_client_adapter *adapter,
Mgmtd__BeMessage *be_msg)
{
+ const char *xpath;
+ uint i, num;
+
/*
* protobuf-c adds a max size enum with an internal, and changing by
* version, name; cast to an int to avoid unhandled enum warnings
*/
switch ((int)be_msg->message_case) {
case MGMTD__BE_MESSAGE__MESSAGE_SUBSCR_REQ:
- MGMTD_BE_ADAPTER_DBG(
- "Got SUBSCR_REQ from '%s' to %sregister %zu xpaths",
- be_msg->subscr_req->client_name,
- !be_msg->subscr_req->subscribe_xpaths &&
- be_msg->subscr_req->n_xpath_reg
- ? "de"
- : "",
- be_msg->subscr_req->n_xpath_reg);
+ __dbg("Got SUBSCR_REQ from '%s' to register xpaths config: %zu oper: %zu notif: %zu",
+ be_msg->subscr_req->client_name,
+ be_msg->subscr_req->n_config_xpaths,
+ be_msg->subscr_req->n_oper_xpaths,
+ be_msg->subscr_req->n_notif_xpaths);
if (strlen(be_msg->subscr_req->client_name)) {
strlcpy(adapter->name, be_msg->subscr_req->client_name,
sizeof(adapter->name));
adapter->id = mgmt_be_client_name2id(adapter->name);
if (adapter->id >= MGMTD_BE_CLIENT_ID_MAX) {
- MGMTD_BE_ADAPTER_ERR(
- "Unable to resolve adapter '%s' to a valid ID. Disconnecting!",
- adapter->name);
+ __log_err("Unable to resolve adapter '%s' to a valid ID. Disconnecting!",
+ adapter->name);
/* this will/should delete old */
msg_conn_disconnect(adapter->conn, false);
- zlog_err("XXX different from original code");
break;
}
mgmt_be_adapters_by_id[adapter->id] = adapter;
@@ -423,19 +427,34 @@ mgmt_be_adapter_handle_msg(struct mgmt_be_client_adapter *adapter,
mgmt_be_adapter_sched_init_event(adapter);
}
- if (be_msg->subscr_req->n_xpath_reg)
- /* we aren't handling dynamic xpaths yet */
- mgmt_be_send_subscr_reply(adapter, false);
- else
- mgmt_be_send_subscr_reply(adapter, true);
+ num = be_msg->subscr_req->n_config_xpaths;
+ for (i = 0; i < num; i++) {
+ xpath = be_msg->subscr_req->config_xpaths[i];
+ mgmt_register_client_xpath(adapter->id, xpath, true,
+ false);
+ }
+
+ num = be_msg->subscr_req->n_oper_xpaths;
+ for (i = 0; i < num; i++) {
+ xpath = be_msg->subscr_req->oper_xpaths[i];
+ mgmt_register_client_xpath(adapter->id, xpath, false,
+ true);
+ }
+
+ num = be_msg->subscr_req->n_notif_xpaths;
+ for (i = 0; i < num; i++) {
+ xpath = be_msg->subscr_req->notif_xpaths[i];
+ mgmt_register_client_xpath(adapter->id, xpath, false,
+ false);
+ }
+
+ mgmt_be_send_subscr_reply(adapter, true);
break;
case MGMTD__BE_MESSAGE__MESSAGE_TXN_REPLY:
- MGMTD_BE_ADAPTER_DBG(
- "Got %s TXN_REPLY from '%s' txn-id %" PRIx64
- " with '%s'",
- be_msg->txn_reply->create ? "Create" : "Delete",
- adapter->name, be_msg->txn_reply->txn_id,
- be_msg->txn_reply->success ? "success" : "failure");
+ __dbg("Got %s TXN_REPLY from '%s' txn-id %" PRIx64 " with '%s'",
+ be_msg->txn_reply->create ? "Create" : "Delete",
+ adapter->name, be_msg->txn_reply->txn_id,
+ be_msg->txn_reply->success ? "success" : "failure");
/*
* Forward the TXN_REPLY to txn module.
*/
@@ -445,13 +464,11 @@ mgmt_be_adapter_handle_msg(struct mgmt_be_client_adapter *adapter,
be_msg->txn_reply->success, adapter);
break;
case MGMTD__BE_MESSAGE__MESSAGE_CFG_DATA_REPLY:
- MGMTD_BE_ADAPTER_DBG(
- "Got CFGDATA_REPLY from '%s' txn-id %" PRIx64
- " err:'%s'", adapter->name,
- be_msg->cfg_data_reply->txn_id,
- be_msg->cfg_data_reply->error_if_any
- ? be_msg->cfg_data_reply->error_if_any
- : "None");
+ __dbg("Got CFGDATA_REPLY from '%s' txn-id %" PRIx64 " err:'%s'",
+ adapter->name, be_msg->cfg_data_reply->txn_id,
+ be_msg->cfg_data_reply->error_if_any
+ ? be_msg->cfg_data_reply->error_if_any
+ : "None");
/*
* Forward the CGFData-create reply to txn module.
*/
@@ -461,15 +478,13 @@ mgmt_be_adapter_handle_msg(struct mgmt_be_client_adapter *adapter,
be_msg->cfg_data_reply->error_if_any, adapter);
break;
case MGMTD__BE_MESSAGE__MESSAGE_CFG_APPLY_REPLY:
- MGMTD_BE_ADAPTER_DBG(
- "Got %s CFG_APPLY_REPLY from '%s' txn-id %" PRIx64
- " err:'%s'",
- be_msg->cfg_apply_reply->success ? "successful"
- : "failed",
- adapter->name, be_msg->cfg_apply_reply->txn_id,
- be_msg->cfg_apply_reply->error_if_any
- ? be_msg->cfg_apply_reply->error_if_any
- : "None");
+ __dbg("Got %s CFG_APPLY_REPLY from '%s' txn-id %" PRIx64
+ " err:'%s'",
+ be_msg->cfg_apply_reply->success ? "successful" : "failed",
+ adapter->name, be_msg->cfg_apply_reply->txn_id,
+ be_msg->cfg_apply_reply->error_if_any
+ ? be_msg->cfg_apply_reply->error_if_any
+ : "None");
/*
* Forward the CGFData-apply reply to txn module.
*/
@@ -514,8 +529,7 @@ int mgmt_be_send_txn_req(struct mgmt_be_client_adapter *adapter,
be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_TXN_REQ;
be_msg.txn_req = &txn_req;
- MGMTD_BE_ADAPTER_DBG("Sending TXN_REQ to '%s' txn-id: %" PRIu64,
- adapter->name, txn_id);
+ __dbg("Sending TXN_REQ to '%s' txn-id: %" PRIu64, adapter->name, txn_id);
return mgmt_be_adapter_send_msg(adapter, &be_msg);
}
@@ -538,10 +552,8 @@ int mgmt_be_send_cfgdata_req(struct mgmt_be_client_adapter *adapter,
be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_CFG_DATA_REQ;
be_msg.cfg_data_req = &cfgdata_req;
- MGMTD_BE_ADAPTER_DBG(
- "Sending CFGDATA_CREATE_REQ to '%s' txn-id: %" PRIu64
- " last: %s",
- adapter->name, txn_id, end_of_data ? "yes" : "no");
+ __dbg("Sending CFGDATA_CREATE_REQ to '%s' txn-id: %" PRIu64 " last: %s",
+ adapter->name, txn_id, end_of_data ? "yes" : "no");
return mgmt_be_adapter_send_msg(adapter, &be_msg);
}
@@ -559,8 +571,8 @@ int mgmt_be_send_cfgapply_req(struct mgmt_be_client_adapter *adapter,
be_msg.message_case = MGMTD__BE_MESSAGE__MESSAGE_CFG_APPLY_REQ;
be_msg.cfg_apply_req = &apply_req;
- MGMTD_BE_ADAPTER_DBG("Sending CFG_APPLY_REQ to '%s' txn-id: %" PRIu64,
- adapter->name, txn_id);
+ __dbg("Sending CFG_APPLY_REQ to '%s' txn-id: %" PRIu64, adapter->name,
+ txn_id);
return mgmt_be_adapter_send_msg(adapter, &be_msg);
}
@@ -575,6 +587,34 @@ int mgmt_be_send_native(enum mgmt_be_client_id id, void *msg)
return mgmt_msg_native_send_msg(adapter->conn, msg, false);
}
+static void mgmt_be_adapter_send_notify(struct mgmt_msg_notify_data *msg,
+ size_t msglen)
+{
+ struct mgmt_be_client_adapter *adapter;
+ struct mgmt_be_xpath_map *map;
+ const char *notif;
+ uint id;
+
+ if (!darr_len(be_notif_xpath_map))
+ return;
+
+ /* "{\"modname:notification-name\": ...}" */
+ notif = (const char *)msg->result + 2;
+
+ darr_foreach_p (be_notif_xpath_map, map) {
+ if (strncmp(map->xpath_prefix, notif, strlen(map->xpath_prefix)))
+ continue;
+
+ FOREACH_BE_CLIENT_BITS (id, map->clients) {
+ adapter = mgmt_be_get_adapter_by_id(id);
+ if (!adapter)
+ continue;
+ msg_conn_send_msg(adapter->conn, MGMT_MSG_VERSION_NATIVE,
+ msg, msglen, NULL, false);
+ }
+ }
+}
+
/*
* Handle a native encoded message
*/
@@ -582,6 +622,7 @@ static void be_adapter_handle_native_msg(struct mgmt_be_client_adapter *adapter,
struct mgmt_msg_header *msg,
size_t msg_len)
{
+ struct mgmt_msg_notify_data *notify_msg;
struct mgmt_msg_tree_data *tree_msg;
struct mgmt_msg_error *error_msg;
@@ -590,8 +631,8 @@ static void be_adapter_handle_native_msg(struct mgmt_be_client_adapter *adapter,
switch (msg->code) {
case MGMT_MSG_CODE_ERROR:
error_msg = (typeof(error_msg))msg;
- MGMTD_BE_ADAPTER_DBG("Got ERROR from '%s' txn-id %" PRIx64,
- adapter->name, msg->refer_id);
+ __dbg("Got ERROR from '%s' txn-id %" PRIx64, adapter->name,
+ msg->refer_id);
/* Forward the reply to the txn module */
mgmt_txn_notify_error(adapter, msg->refer_id, msg->req_id,
@@ -601,18 +642,23 @@ static void be_adapter_handle_native_msg(struct mgmt_be_client_adapter *adapter,
case MGMT_MSG_CODE_TREE_DATA:
/* tree data from a backend client */
tree_msg = (typeof(tree_msg))msg;
- MGMTD_BE_ADAPTER_DBG("Got TREE_DATA from '%s' txn-id %" PRIx64,
- adapter->name, msg->refer_id);
+ __dbg("Got TREE_DATA from '%s' txn-id %" PRIx64, adapter->name,
+ msg->refer_id);
/* Forward the reply to the txn module */
mgmt_txn_notify_tree_data_reply(adapter, tree_msg, msg_len);
break;
+ case MGMT_MSG_CODE_NOTIFY:
+ notify_msg = (typeof(notify_msg))msg;
+ __dbg("Got NOTIFY from '%s'", adapter->name);
+ mgmt_be_adapter_send_notify(notify_msg, msg_len);
+ mgmt_fe_adapter_send_notify(notify_msg, msg_len);
+ break;
default:
- MGMTD_BE_ADAPTER_ERR("unknown native message txn-id %" PRIu64
- " req-id %" PRIu64
- " code %u from BE client for adapter %s",
- msg->refer_id, msg->req_id, msg->code,
- adapter->name);
+ __log_err("unknown native message txn-id %" PRIu64
+ " req-id %" PRIu64
+ " code %u from BE client for adapter %s",
+ msg->refer_id, msg->req_id, msg->code, adapter->name);
break;
}
}
@@ -630,20 +676,19 @@ static void mgmt_be_adapter_process_msg(uint8_t version, uint8_t *data,
if (len >= sizeof(*msg))
be_adapter_handle_native_msg(adapter, msg, len);
else
- MGMTD_BE_ADAPTER_ERR("native message to adapter %s too short %zu",
- adapter->name, len);
+ __log_err("native message to adapter %s too short %zu",
+ adapter->name, len);
return;
}
be_msg = mgmtd__be_message__unpack(NULL, len, data);
if (!be_msg) {
- MGMTD_BE_ADAPTER_DBG(
- "Failed to decode %zu bytes for adapter: %s", len,
- adapter->name);
+ __dbg("Failed to decode %zu bytes for adapter: %s", len,
+ adapter->name);
return;
}
- MGMTD_BE_ADAPTER_DBG("Decoded %zu bytes of message: %u for adapter: %s",
- len, be_msg->message_case, adapter->name);
+ __dbg("Decoded %zu bytes of message: %u for adapter: %s", len,
+ be_msg->message_case, adapter->name);
(void)mgmt_be_adapter_handle_msg(adapter, be_msg);
mgmtd__be_message__free_unpacked(be_msg, NULL);
}
@@ -777,8 +822,7 @@ struct msg_conn *mgmt_be_create_adapter(int conn_fd, union sockunion *from)
adapter->conn->debug = DEBUG_MODE_CHECK(&mgmt_debug_be, DEBUG_MODE_ALL);
- MGMTD_BE_ADAPTER_DBG("Added new MGMTD Backend adapter '%s'",
- adapter->name);
+ __dbg("Added new MGMTD Backend adapter '%s'", adapter->name);
return adapter->conn;
}
@@ -845,15 +889,15 @@ uint64_t mgmt_be_interested_clients(const char *xpath, bool config)
clients = 0;
- MGMTD_BE_ADAPTER_DBG("XPATH: '%s'", xpath);
+ __dbg("XPATH: '%s'", xpath);
darr_foreach_p (maps, map)
if (mgmt_be_xpath_prefix(map->xpath_prefix, xpath))
clients |= map->clients;
if (DEBUG_MODE_CHECK(&mgmt_debug_be, DEBUG_MODE_ALL)) {
FOREACH_BE_CLIENT_BITS (id, clients)
- MGMTD_BE_ADAPTER_DBG("Cient: %s: subscribed",
- mgmt_be_client_id2name(id));
+ __dbg("Cient: %s: subscribed",
+ mgmt_be_client_id2name(id));
}
return clients;
}
@@ -877,23 +921,21 @@ static bool be_is_client_interested(const char *xpath,
assert(id < MGMTD_BE_CLIENT_ID_MAX);
- MGMTD_BE_ADAPTER_DBG("Checking client: %s for xpath: '%s'",
- mgmt_be_client_id2name(id), xpath);
+ __dbg("Checking client: %s for xpath: '%s'", mgmt_be_client_id2name(id),
+ xpath);
xpaths = config ? be_client_config_xpaths[id]
: be_client_oper_xpaths[id];
if (xpaths) {
for (; *xpaths; xpaths++) {
if (mgmt_be_xpath_prefix(*xpaths, xpath)) {
- MGMTD_BE_ADAPTER_DBG("xpath: %s: matched: %s",
- *xpaths, xpath);
+ __dbg("xpath: %s: matched: %s", *xpaths, xpath);
return true;
}
}
}
- MGMTD_BE_ADAPTER_DBG("client: %s: not interested",
- mgmt_be_client_id2name(id));
+ __dbg("client: %s: not interested", mgmt_be_client_id2name(id));
return false;
}
diff --git a/mgmtd/mgmt_be_adapter.h b/mgmtd/mgmt_be_adapter.h
index 955291b7c8..491410aa15 100644
--- a/mgmtd/mgmt_be_adapter.h
+++ b/mgmtd/mgmt_be_adapter.h
@@ -27,6 +27,8 @@
* #ifdef HAVE_COMPONENT
*/
enum mgmt_be_client_id {
+ MGMTD_BE_CLIENT_ID_TESTC, /* always first */
+ MGMTD_BE_CLIENT_ID_ZEBRA,
#ifdef HAVE_RIPD
MGMTD_BE_CLIENT_ID_RIPD,
#endif
@@ -36,7 +38,6 @@ enum mgmt_be_client_id {
#ifdef HAVE_STATICD
MGMTD_BE_CLIENT_ID_STATICD,
#endif
- MGMTD_BE_CLIENT_ID_ZEBRA,
MGMTD_BE_CLIENT_ID_MAX
};
#define MGMTD_BE_CLIENT_ID_MIN 0
@@ -244,6 +245,13 @@ extern int mgmt_be_send_native(enum mgmt_be_client_id id, void *msg);
*/
extern uint64_t mgmt_be_interested_clients(const char *xpath, bool config);
+/**
+ * mgmt_fe_adapter_send_notify() - notify FE clients of a notification.
+ * @msg: the notify message from the backend client.
+ * @msglen: the length of the notify message.
+ */
+extern void mgmt_fe_adapter_send_notify(struct mgmt_msg_notify_data *msg,
+ size_t msglen);
/*
* Dump backend client information for a given xpath to vty.
*/
diff --git a/mgmtd/mgmt_ds.c b/mgmtd/mgmt_ds.c
index 8ed15b1726..eaf52dfb29 100644
--- a/mgmtd/mgmt_ds.c
+++ b/mgmtd/mgmt_ds.c
@@ -15,10 +15,9 @@
#include "mgmtd/mgmt_txn.h"
#include "libyang/libyang.h"
-#define MGMTD_DS_DBG(fmt, ...) \
+#define __dbg(fmt, ...) \
DEBUGD(&mgmt_debug_ds, "DS: %s: " fmt, __func__, ##__VA_ARGS__)
-#define MGMTD_DS_ERR(fmt, ...) \
- zlog_err("%s: ERROR: " fmt, __func__, ##__VA_ARGS__)
+#define __log_err(fmt, ...) zlog_err("%s: ERROR: " fmt, __func__, ##__VA_ARGS__)
struct mgmt_ds_ctx {
Mgmtd__DatastoreId ds_id;
@@ -81,8 +80,8 @@ static int mgmt_ds_replace_dst_with_src_ds(struct mgmt_ds_ctx *src,
if (!src || !dst)
return -1;
- MGMTD_DS_DBG("Replacing %s with %s", mgmt_ds_id2name(dst->ds_id),
- mgmt_ds_id2name(src->ds_id));
+ __dbg("Replacing %s with %s", mgmt_ds_id2name(dst->ds_id),
+ mgmt_ds_id2name(src->ds_id));
if (src->config_ds && dst->config_ds)
nb_config_replace(dst->root.cfg_root, src->root.cfg_root, true);
@@ -104,7 +103,7 @@ static int mgmt_ds_merge_src_with_dst_ds(struct mgmt_ds_ctx *src,
if (!src || !dst)
return -1;
- MGMTD_DS_DBG("Merging DS %d with %d", dst->ds_id, src->ds_id);
+ __dbg("Merging DS %d with %d", dst->ds_id, src->ds_id);
if (src->config_ds && dst->config_ds)
ret = nb_config_merge(dst->root.cfg_root, src->root.cfg_root,
true);
@@ -114,7 +113,7 @@ static int mgmt_ds_merge_src_with_dst_ds(struct mgmt_ds_ctx *src,
src->root.dnode_root, 0);
}
if (ret != 0) {
- MGMTD_DS_ERR("merge failed with err: %d", ret);
+ __log_err("merge failed with err: %d", ret);
return ret;
}
@@ -299,7 +298,7 @@ static int mgmt_walk_ds_nodes(
assert(mgmt_ds_node_iter_fn);
- MGMTD_DS_DBG(" -- START: base xpath: '%s'", base_xpath);
+ __dbg(" -- START: base xpath: '%s'", base_xpath);
if (!base_dnode)
/*
@@ -310,9 +309,9 @@ static int mgmt_walk_ds_nodes(
if (!base_dnode)
return -1;
- MGMTD_DS_DBG(" search base schema: '%s'",
- lysc_path(base_dnode->schema, LYSC_PATH_LOG, xpath,
- sizeof(xpath)));
+ __dbg(" search base schema: '%s'",
+ lysc_path(base_dnode->schema, LYSC_PATH_LOG, xpath,
+ sizeof(xpath)));
nbnode = (struct nb_node *)base_dnode->schema->priv;
(*mgmt_ds_node_iter_fn)(base_xpath, base_dnode, nbnode, ctx);
@@ -335,7 +334,7 @@ static int mgmt_walk_ds_nodes(
(void)lyd_path(dnode, LYD_PATH_STD, xpath, sizeof(xpath));
- MGMTD_DS_DBG(" -- Child xpath: %s", xpath);
+ __dbg(" -- Child xpath: %s", xpath);
ret = mgmt_walk_ds_nodes(root, xpath, dnode,
mgmt_ds_node_iter_fn, ctx);
@@ -343,7 +342,7 @@ static int mgmt_walk_ds_nodes(
break;
}
- MGMTD_DS_DBG(" -- END: base xpath: '%s'", base_xpath);
+ __dbg(" -- END: base xpath: '%s'", base_xpath);
return ret;
}
@@ -407,8 +406,7 @@ int mgmt_ds_load_config_from_file(struct mgmt_ds_ctx *dst,
return -1;
if (mgmt_ds_load_cfg_from_file(file_path, &iter) != 0) {
- MGMTD_DS_ERR("Failed to load config from the file %s",
- file_path);
+ __log_err("Failed to load config from the file %s", file_path);
return -1;
}
@@ -451,7 +449,7 @@ int mgmt_ds_iter_data(Mgmtd__DatastoreId ds_id, struct nb_config *root,
* Oper-state should be kept in mind though for the prefix walk
*/
- MGMTD_DS_DBG(" -- START DS walk for DSid: %d", ds_id);
+ __dbg(" -- START DS walk for DSid: %d", ds_id);
/* If the base_xpath is empty then crawl the sibblings */
if (xpath[0] == 0) {
diff --git a/mgmtd/mgmt_fe_adapter.c b/mgmtd/mgmt_fe_adapter.c
index a99d92d2b6..001da7680b 100644
--- a/mgmtd/mgmt_fe_adapter.c
+++ b/mgmtd/mgmt_fe_adapter.c
@@ -23,9 +23,9 @@
#include "mgmtd/mgmt_memory.h"
#include "mgmtd/mgmt_fe_adapter.h"
-#define MGMTD_FE_ADAPTER_DBG(fmt, ...) \
+#define __dbg(fmt, ...) \
DEBUGD(&mgmt_debug_fe, "FE-ADAPTER: %s: " fmt, __func__, ##__VA_ARGS__)
-#define MGMTD_FE_ADAPTER_ERR(fmt, ...) \
+#define __log_err(fmt, ...) \
zlog_err("FE-ADAPTER: %s: ERROR: " fmt, __func__, ##__VA_ARGS__)
#define FOREACH_ADAPTER_IN_LIST(adapter) \
@@ -78,20 +78,18 @@ mgmt_fe_session_write_lock_ds(Mgmtd__DatastoreId ds_id,
session->session_id, mgmt_ds_id2name(ds_id));
else {
if (mgmt_ds_lock(ds_ctx, session->session_id)) {
- MGMTD_FE_ADAPTER_DBG(
- "Failed to lock the DS:%s for session-id: %" PRIu64
- " from %s!",
- mgmt_ds_id2name(ds_id), session->session_id,
- session->adapter->name);
+ __dbg("Failed to lock the DS:%s for session-id: %" PRIu64
+ " from %s!",
+ mgmt_ds_id2name(ds_id), session->session_id,
+ session->adapter->name);
return -1;
}
session->ds_locked[ds_id] = true;
- MGMTD_FE_ADAPTER_DBG(
- "Write-Locked the DS:%s for session-id: %" PRIu64
- " from %s",
- mgmt_ds_id2name(ds_id), session->session_id,
- session->adapter->name);
+ __dbg("Write-Locked the DS:%s for session-id: %" PRIu64
+ " from %s",
+ mgmt_ds_id2name(ds_id), session->session_id,
+ session->adapter->name);
}
return 0;
@@ -107,11 +105,10 @@ static void mgmt_fe_session_unlock_ds(Mgmtd__DatastoreId ds_id,
session->ds_locked[ds_id] = false;
mgmt_ds_unlock(ds_ctx);
- MGMTD_FE_ADAPTER_DBG(
- "Unlocked DS:%s write-locked earlier by session-id: %" PRIu64
- " from %s",
- mgmt_ds_id2name(ds_id), session->session_id,
- session->adapter->name);
+ __dbg("Unlocked DS:%s write-locked earlier by session-id: %" PRIu64
+ " from %s",
+ mgmt_ds_id2name(ds_id), session->session_id,
+ session->adapter->name);
}
static void
@@ -206,14 +203,13 @@ mgmt_fe_find_session_by_client_id(struct mgmt_fe_client_adapter *adapter,
FOREACH_SESSION_IN_LIST (adapter, session) {
if (session->client_id == client_id) {
- MGMTD_FE_ADAPTER_DBG("Found session-id %" PRIu64
- " using client-id %" PRIu64,
- session->session_id, client_id);
+ __dbg("Found session-id %" PRIu64
+ " using client-id %" PRIu64,
+ session->session_id, client_id);
return session;
}
}
- MGMTD_FE_ADAPTER_DBG("Session not found using client-id %" PRIu64,
- client_id);
+ __dbg("Session not found using client-id %" PRIu64, client_id);
return NULL;
}
@@ -330,9 +326,8 @@ static int fe_adapter_send_session_reply(struct mgmt_fe_client_adapter *adapter,
fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_SESSION_REPLY;
fe_msg.session_reply = &session_reply;
- MGMTD_FE_ADAPTER_DBG(
- "Sending SESSION_REPLY message to MGMTD Frontend client '%s'",
- adapter->name);
+ __dbg("Sending SESSION_REPLY message to MGMTD Frontend client '%s'",
+ adapter->name);
return fe_adapter_send_msg(adapter, &fe_msg, true);
}
@@ -361,9 +356,8 @@ static int fe_adapter_send_lockds_reply(struct mgmt_fe_session_ctx *session,
fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_LOCKDS_REPLY;
fe_msg.lockds_reply = &lockds_reply;
- MGMTD_FE_ADAPTER_DBG(
- "Sending LOCK_DS_REPLY message to MGMTD Frontend client '%s' scok: %d",
- session->adapter->name, scok);
+ __dbg("Sending LOCK_DS_REPLY message to MGMTD Frontend client '%s' scok: %d",
+ session->adapter->name, scok);
return fe_adapter_send_msg(session->adapter, &fe_msg, scok);
}
@@ -396,9 +390,8 @@ static int fe_adapter_send_set_cfg_reply(struct mgmt_fe_session_ctx *session,
fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_SETCFG_REPLY;
fe_msg.setcfg_reply = &setcfg_reply;
- MGMTD_FE_ADAPTER_DBG(
- "Sending SETCFG_REPLY message to MGMTD Frontend client '%s'",
- session->adapter->name);
+ __dbg("Sending SETCFG_REPLY message to MGMTD Frontend client '%s'",
+ session->adapter->name);
if (implicit_commit) {
if (mm->perf_stats_en)
@@ -442,9 +435,8 @@ static int fe_adapter_send_commit_cfg_reply(
fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_COMMCFG_REPLY;
fe_msg.commcfg_reply = &commcfg_reply;
- MGMTD_FE_ADAPTER_DBG(
- "Sending COMMIT_CONFIG_REPLY message to MGMTD Frontend client '%s'",
- session->adapter->name);
+ __dbg("Sending COMMIT_CONFIG_REPLY message to MGMTD Frontend client '%s'",
+ session->adapter->name);
/*
* Cleanup the CONFIG transaction associated with this session.
@@ -484,8 +476,8 @@ static int fe_adapter_send_get_reply(struct mgmt_fe_session_ctx *session,
fe_msg.message_case = MGMTD__FE_MESSAGE__MESSAGE_GET_REPLY;
fe_msg.get_reply = &get_reply;
- MGMTD_FE_ADAPTER_DBG("Sending GET_REPLY message to MGMTD Frontend client '%s'",
- session->adapter->name);
+ __dbg("Sending GET_REPLY message to MGMTD Frontend client '%s'",
+ session->adapter->name);
/*
* Cleanup the SHOW transaction associated with this session.
@@ -572,7 +564,7 @@ mgmt_fe_find_adapter_by_fd(int conn_fd)
static void mgmt_fe_adapter_delete(struct mgmt_fe_client_adapter *adapter)
{
struct mgmt_fe_session_ctx *session;
- MGMTD_FE_ADAPTER_DBG("deleting client adapter '%s'", adapter->name);
+ __dbg("deleting client adapter '%s'", adapter->name);
/* TODO: notify about client disconnect for appropriate cleanup */
FOREACH_SESSION_IN_LIST (adapter, session)
@@ -587,8 +579,7 @@ static int mgmt_fe_adapter_notify_disconnect(struct msg_conn *conn)
{
struct mgmt_fe_client_adapter *adapter = conn->user;
- MGMTD_FE_ADAPTER_DBG("notify disconnect for client adapter '%s'",
- adapter->name);
+ __dbg("notify disconnect for client adapter '%s'", adapter->name);
mgmt_fe_adapter_delete(adapter);
@@ -609,10 +600,8 @@ mgmt_fe_adapter_cleanup_old_conn(struct mgmt_fe_client_adapter *adapter)
if (strncmp(adapter->name, old->name, sizeof(adapter->name)))
continue;
- MGMTD_FE_ADAPTER_DBG(
- "Client '%s' (FD:%d) seems to have reconnected. Removing old connection (FD:%d)",
- adapter->name, adapter->conn->fd,
- old->conn->fd);
+ __dbg("Client '%s' (FD:%d) seems to have reconnected. Removing old connection (FD:%d)",
+ adapter->name, adapter->conn->fd, old->conn->fd);
msg_conn_disconnect(old->conn, false);
}
}
@@ -665,11 +654,10 @@ mgmt_fe_session_handle_lockds_req_msg(struct mgmt_fe_session_ctx *session,
if (fe_adapter_send_lockds_reply(session, lockds_req->ds_id,
lockds_req->req_id, lockds_req->lock,
true, NULL) != 0) {
- MGMTD_FE_ADAPTER_DBG(
- "Failed to send LOCK_DS_REPLY for DS %u session-id: %" PRIu64
- " from %s",
- lockds_req->ds_id, session->session_id,
- session->adapter->name);
+ __dbg("Failed to send LOCK_DS_REPLY for DS %u session-id: %" PRIu64
+ " from %s",
+ lockds_req->ds_id, session->session_id,
+ session->adapter->name);
}
return 0;
@@ -739,14 +727,13 @@ mgmt_fe_session_handle_setcfg_req_msg(struct mgmt_fe_session_ctx *session,
}
txn_created = true;
- MGMTD_FE_ADAPTER_DBG("Created new Config txn-id: %" PRIu64
- " for session-id %" PRIu64,
- session->cfg_txn_id, session->session_id);
+ __dbg("Created new Config txn-id: %" PRIu64
+ " for session-id %" PRIu64,
+ session->cfg_txn_id, session->session_id);
} else {
- MGMTD_FE_ADAPTER_DBG("Config txn-id: %" PRIu64
- " for session-id: %" PRIu64
- " already created",
- session->cfg_txn_id, session->session_id);
+ __dbg("Config txn-id: %" PRIu64 " for session-id: %" PRIu64
+ " already created",
+ session->cfg_txn_id, session->session_id);
if (setcfg_req->implicit_commit) {
/*
@@ -811,15 +798,15 @@ static int mgmt_fe_session_handle_get_req_msg(struct mgmt_fe_session_ctx *sessio
return -1;
}
- MGMTD_FE_ADAPTER_DBG("Created new show txn-id: %" PRIu64
- " for session-id: %" PRIu64,
- session->txn_id, session->session_id);
+ __dbg("Created new show txn-id: %" PRIu64
+ " for session-id: %" PRIu64,
+ session->txn_id, session->session_id);
} else {
fe_adapter_send_get_reply(session, ds_id, req_id, false, NULL,
"Request processing for GET failed!");
- MGMTD_FE_ADAPTER_DBG("Transaction in progress txn-id: %" PRIu64
- " for session-id: %" PRIu64,
- session->txn_id, session->session_id);
+ __dbg("Transaction in progress txn-id: %" PRIu64
+ " for session-id: %" PRIu64,
+ session->txn_id, session->session_id);
return -1;
}
@@ -906,10 +893,9 @@ static int mgmt_fe_session_handle_commit_config_req_msg(
"Failed to create a Configuration session!");
return 0;
}
- MGMTD_FE_ADAPTER_DBG("Created txn-id: %" PRIu64
- " for session-id %" PRIu64
- " for COMMIT-CFG-REQ",
- session->cfg_txn_id, session->session_id);
+ __dbg("Created txn-id: %" PRIu64 " for session-id %" PRIu64
+ " for COMMIT-CFG-REQ",
+ session->cfg_txn_id, session->session_id);
}
/*
@@ -943,8 +929,8 @@ mgmt_fe_adapter_handle_msg(struct mgmt_fe_client_adapter *adapter,
*/
switch ((int)fe_msg->message_case) {
case MGMTD__FE_MESSAGE__MESSAGE_REGISTER_REQ:
- MGMTD_FE_ADAPTER_DBG("Got REGISTER_REQ from '%s'",
- fe_msg->register_req->client_name);
+ __dbg("Got REGISTER_REQ from '%s'",
+ fe_msg->register_req->client_name);
if (strlen(fe_msg->register_req->client_name)) {
strlcpy(adapter->name,
@@ -957,11 +943,10 @@ mgmt_fe_adapter_handle_msg(struct mgmt_fe_client_adapter *adapter,
if (fe_msg->session_req->create
&& fe_msg->session_req->id_case
== MGMTD__FE_SESSION_REQ__ID_CLIENT_CONN_ID) {
- MGMTD_FE_ADAPTER_DBG(
- "Got SESSION_REQ (create) for client-id %" PRIu64
- " from '%s'",
- fe_msg->session_req->client_conn_id,
- adapter->name);
+ __dbg("Got SESSION_REQ (create) for client-id %" PRIu64
+ " from '%s'",
+ fe_msg->session_req->client_conn_id,
+ adapter->name);
session = mgmt_fe_create_session(
adapter, fe_msg->session_req->client_conn_id);
@@ -971,10 +956,9 @@ mgmt_fe_adapter_handle_msg(struct mgmt_fe_client_adapter *adapter,
!fe_msg->session_req->create
&& fe_msg->session_req->id_case
== MGMTD__FE_SESSION_REQ__ID_SESSION_ID) {
- MGMTD_FE_ADAPTER_DBG(
- "Got SESSION_REQ (destroy) for session-id %" PRIu64
- "from '%s'",
- fe_msg->session_req->session_id, adapter->name);
+ __dbg("Got SESSION_REQ (destroy) for session-id %" PRIu64
+ "from '%s'",
+ fe_msg->session_req->session_id, adapter->name);
session = mgmt_session_id2ctx(
fe_msg->session_req->session_id);
@@ -986,12 +970,11 @@ mgmt_fe_adapter_handle_msg(struct mgmt_fe_client_adapter *adapter,
case MGMTD__FE_MESSAGE__MESSAGE_LOCKDS_REQ:
session = mgmt_session_id2ctx(
fe_msg->lockds_req->session_id);
- MGMTD_FE_ADAPTER_DBG(
- "Got LOCKDS_REQ (%sLOCK) for DS:%s for session-id %" PRIu64
- " from '%s'",
- fe_msg->lockds_req->lock ? "" : "UN",
- mgmt_ds_id2name(fe_msg->lockds_req->ds_id),
- fe_msg->lockds_req->session_id, adapter->name);
+ __dbg("Got LOCKDS_REQ (%sLOCK) for DS:%s for session-id %" PRIu64
+ " from '%s'",
+ fe_msg->lockds_req->lock ? "" : "UN",
+ mgmt_ds_id2name(fe_msg->lockds_req->ds_id),
+ fe_msg->lockds_req->session_id, adapter->name);
mgmt_fe_session_handle_lockds_req_msg(
session, fe_msg->lockds_req);
break;
@@ -999,13 +982,12 @@ mgmt_fe_adapter_handle_msg(struct mgmt_fe_client_adapter *adapter,
session = mgmt_session_id2ctx(
fe_msg->setcfg_req->session_id);
session->adapter->setcfg_stats.set_cfg_count++;
- MGMTD_FE_ADAPTER_DBG(
- "Got SETCFG_REQ (%d Xpaths, Implicit:%c) on DS:%s for session-id %" PRIu64
- " from '%s'",
- (int)fe_msg->setcfg_req->n_data,
- fe_msg->setcfg_req->implicit_commit ? 'T' : 'F',
- mgmt_ds_id2name(fe_msg->setcfg_req->ds_id),
- fe_msg->setcfg_req->session_id, adapter->name);
+ __dbg("Got SETCFG_REQ (%d Xpaths, Implicit:%c) on DS:%s for session-id %" PRIu64
+ " from '%s'",
+ (int)fe_msg->setcfg_req->n_data,
+ fe_msg->setcfg_req->implicit_commit ? 'T' : 'F',
+ mgmt_ds_id2name(fe_msg->setcfg_req->ds_id),
+ fe_msg->setcfg_req->session_id, adapter->name);
mgmt_fe_session_handle_setcfg_req_msg(
session, fe_msg->setcfg_req);
@@ -1013,30 +995,28 @@ mgmt_fe_adapter_handle_msg(struct mgmt_fe_client_adapter *adapter,
case MGMTD__FE_MESSAGE__MESSAGE_COMMCFG_REQ:
session = mgmt_session_id2ctx(
fe_msg->commcfg_req->session_id);
- MGMTD_FE_ADAPTER_DBG(
- "Got COMMCFG_REQ for src-DS:%s dst-DS:%s (Abort:%c) on session-id %" PRIu64
- " from '%s'",
- mgmt_ds_id2name(fe_msg->commcfg_req->src_ds_id),
- mgmt_ds_id2name(fe_msg->commcfg_req->dst_ds_id),
- fe_msg->commcfg_req->abort ? 'T' : 'F',
- fe_msg->commcfg_req->session_id, adapter->name);
+ __dbg("Got COMMCFG_REQ for src-DS:%s dst-DS:%s (Abort:%c) on session-id %" PRIu64
+ " from '%s'",
+ mgmt_ds_id2name(fe_msg->commcfg_req->src_ds_id),
+ mgmt_ds_id2name(fe_msg->commcfg_req->dst_ds_id),
+ fe_msg->commcfg_req->abort ? 'T' : 'F',
+ fe_msg->commcfg_req->session_id, adapter->name);
mgmt_fe_session_handle_commit_config_req_msg(
session, fe_msg->commcfg_req);
break;
case MGMTD__FE_MESSAGE__MESSAGE_GET_REQ:
session = mgmt_session_id2ctx(fe_msg->get_req->session_id);
- MGMTD_FE_ADAPTER_DBG("Got GET_REQ for DS:%s (xpaths: %d) on session-id %" PRIu64
- " from '%s'",
- mgmt_ds_id2name(fe_msg->get_req->ds_id),
- (int)fe_msg->get_req->n_data,
- fe_msg->get_req->session_id, adapter->name);
+ __dbg("Got GET_REQ for DS:%s (xpaths: %d) on session-id %" PRIu64
+ " from '%s'",
+ mgmt_ds_id2name(fe_msg->get_req->ds_id),
+ (int)fe_msg->get_req->n_data, fe_msg->get_req->session_id,
+ adapter->name);
mgmt_fe_session_handle_get_req_msg(session, fe_msg->get_req);
break;
case MGMTD__FE_MESSAGE__MESSAGE_NOTIFY_DATA_REQ:
case MGMTD__FE_MESSAGE__MESSAGE_REGNOTIFY_REQ:
- MGMTD_FE_ADAPTER_ERR(
- "Got unhandled message of type %u from '%s'",
- fe_msg->message_case, adapter->name);
+ __log_err("Got unhandled message of type %u from '%s'",
+ fe_msg->message_case, adapter->name);
/*
* TODO: Add handling code in future.
*/
@@ -1080,56 +1060,44 @@ mgmt_fe_adapter_handle_msg(struct mgmt_fe_client_adapter *adapter,
*/
static int fe_adapter_send_tree_data(struct mgmt_fe_session_ctx *session,
uint64_t req_id, bool short_circuit_ok,
- uint8_t result_type,
+ uint8_t result_type, uint32_t wd_options,
const struct lyd_node *tree,
int partial_error)
{
struct mgmt_msg_tree_data *msg;
- struct lyd_node *empty = NULL;
- uint8_t *buf = NULL;
+ uint8_t **darrp = NULL;
int ret = 0;
- darr_append_n(buf, sizeof(*msg));
- msg = (typeof(msg))buf;
+ msg = mgmt_msg_native_alloc_msg(struct mgmt_msg_tree_data, 0,
+ MTYPE_MSG_NATIVE_TREE_DATA);
msg->refer_id = session->session_id;
msg->req_id = req_id;
msg->code = MGMT_MSG_CODE_TREE_DATA;
msg->partial_error = partial_error;
msg->result_type = result_type;
- if (!tree) {
- empty = yang_dnode_new(ly_native_ctx, false);
- tree = empty;
- }
-
- ret = yang_print_tree_append(&buf, tree, result_type,
- (LYD_PRINT_WD_EXPLICIT |
- LYD_PRINT_WITHSIBLINGS));
- /* buf may have been reallocated and moved */
- msg = (typeof(msg))buf;
- (void)msg; /* suppress clang-SA unused warning on safety code */
-
+ darrp = mgmt_msg_native_get_darrp(msg);
+ ret = yang_print_tree_append(darrp, tree, result_type,
+ (wd_options | LYD_PRINT_WITHSIBLINGS));
if (ret != LY_SUCCESS) {
- MGMTD_FE_ADAPTER_ERR("Error building get-tree result for client %s session-id %" PRIu64
- " req-id %" PRIu64
- " scok %d result type %u",
- session->adapter->name, session->session_id,
- req_id, short_circuit_ok, result_type);
+ __log_err("Error building get-tree result for client %s session-id %" PRIu64
+ " req-id %" PRIu64 " scok %d result type %u",
+ session->adapter->name, session->session_id, req_id,
+ short_circuit_ok, result_type);
goto done;
}
- MGMTD_FE_ADAPTER_DBG("Sending get-tree result from adapter %s to session-id %" PRIu64
- " req-id %" PRIu64 " scok %d result type %u len %u",
- session->adapter->name, session->session_id, req_id,
- short_circuit_ok, result_type, darr_len(buf));
+ __dbg("Sending get-tree result from adapter %s to session-id %" PRIu64
+ " req-id %" PRIu64 " scok %d result type %u len %u",
+ session->adapter->name, session->session_id, req_id,
+ short_circuit_ok, result_type, mgmt_msg_native_get_msg_len(msg));
- ret = fe_adapter_send_native_msg(session->adapter, buf, darr_len(buf),
+ ret = fe_adapter_send_native_msg(session->adapter, msg,
+ mgmt_msg_native_get_msg_len(msg),
short_circuit_ok);
done:
- if (empty)
- yang_dnode_free(empty);
- darr_free(buf);
+ mgmt_msg_native_free_msg(msg);
return ret;
}
@@ -1147,15 +1115,16 @@ static void fe_adapter_handle_get_data(struct mgmt_fe_session_ctx *session,
struct lysc_node **snodes = NULL;
char *xpath_resolved = NULL;
uint64_t req_id = msg->req_id;
+ Mgmtd__DatastoreId ds_id;
uint64_t clients;
+ uint32_t wd_options;
bool simple_xpath;
LY_ERR err;
int ret;
- MGMTD_FE_ADAPTER_DBG("Received get-data request from client %s for session-id %" PRIu64
- " req-id %" PRIu64,
- session->adapter->name, session->session_id,
- msg->req_id);
+ __dbg("Received get-data request from client %s for session-id %" PRIu64
+ " req-id %" PRIu64,
+ session->adapter->name, session->session_id, msg->req_id);
if (!MGMT_MSG_VALIDATE_NUL_TERM(msg, msg_len)) {
fe_adapter_send_error(session, req_id, false, -EINVAL,
@@ -1172,6 +1141,43 @@ static void fe_adapter_handle_get_data(struct mgmt_fe_session_ctx *session,
goto done;
}
+ switch (msg->defaults) {
+ case GET_DATA_DEFAULTS_EXPLICIT:
+ wd_options = LYD_PRINT_WD_EXPLICIT;
+ break;
+ case GET_DATA_DEFAULTS_TRIM:
+ wd_options = LYD_PRINT_WD_TRIM;
+ break;
+ case GET_DATA_DEFAULTS_ALL:
+ wd_options = LYD_PRINT_WD_ALL;
+ break;
+ case GET_DATA_DEFAULTS_ALL_ADD_TAG:
+ wd_options = LYD_PRINT_WD_IMPL_TAG;
+ break;
+ default:
+ fe_adapter_send_error(session, req_id, false, -EINVAL,
+ "Invalid defaults value %u for session-id: %" PRIu64,
+ msg->defaults, session->session_id);
+ goto done;
+ }
+
+ switch (msg->datastore) {
+ case MGMT_MSG_DATASTORE_CANDIDATE:
+ ds_id = MGMTD_DS_CANDIDATE;
+ break;
+ case MGMT_MSG_DATASTORE_RUNNING:
+ ds_id = MGMTD_DS_RUNNING;
+ break;
+ case MGMT_MSG_DATASTORE_OPERATIONAL:
+ ds_id = MGMTD_DS_OPERATIONAL;
+ break;
+ default:
+ fe_adapter_send_error(session, req_id, false, -EINVAL,
+ "Unsupported datastore %" PRIu8
+ " requested from session-id: %" PRIu64,
+ msg->datastore, session->session_id);
+ goto done;
+ }
err = yang_resolve_snode_xpath(ly_native_ctx, msg->xpath, &snodes,
&simple_xpath);
@@ -1185,13 +1191,12 @@ static void fe_adapter_handle_get_data(struct mgmt_fe_session_ctx *session,
clients = mgmt_be_interested_clients(msg->xpath, false);
if (!clients && !CHECK_FLAG(msg->flags, GET_DATA_FLAG_CONFIG)) {
- MGMTD_FE_ADAPTER_DBG("No backends provide xpath: %s for txn-id: %" PRIu64
- " session-id: %" PRIu64,
- msg->xpath, session->txn_id,
- session->session_id);
+ __dbg("No backends provide xpath: %s for txn-id: %" PRIu64
+ " session-id: %" PRIu64,
+ msg->xpath, session->txn_id, session->session_id);
fe_adapter_send_tree_data(session, req_id, false,
- msg->result_type, NULL, 0);
+ msg->result_type, wd_options, NULL, 0);
goto done;
}
@@ -1204,14 +1209,13 @@ static void fe_adapter_handle_get_data(struct mgmt_fe_session_ctx *session,
goto done;
}
- MGMTD_FE_ADAPTER_DBG("Created new show txn-id: %" PRIu64
- " for session-id: %" PRIu64,
- session->txn_id, session->session_id);
+ __dbg("Created new show txn-id: %" PRIu64 " for session-id: %" PRIu64,
+ session->txn_id, session->session_id);
/* Create a GET-TREE request under the transaction */
ret = mgmt_txn_send_get_tree_oper(session->txn_id, req_id, clients,
- msg->result_type, msg->flags,
- simple_xpath, msg->xpath);
+ ds_id, msg->result_type, msg->flags,
+ wd_options, simple_xpath, msg->xpath);
if (ret) {
/* destroy the just created txn */
mgmt_destroy_txn(&session->txn_id);
@@ -1234,8 +1238,8 @@ static void fe_adapter_handle_native_msg(struct mgmt_fe_client_adapter *adapter,
session = mgmt_session_id2ctx(msg->refer_id);
if (!session) {
- MGMTD_FE_ADAPTER_ERR("adapter %s: recv msg unknown session-id %" PRIu64,
- adapter->name, msg->refer_id);
+ __log_err("adapter %s: recv msg unknown session-id %" PRIu64,
+ adapter->name, msg->refer_id);
return;
}
assert(session->adapter == adapter);
@@ -1245,11 +1249,9 @@ static void fe_adapter_handle_native_msg(struct mgmt_fe_client_adapter *adapter,
fe_adapter_handle_get_data(session, msg, msg_len);
break;
default:
- MGMTD_FE_ADAPTER_ERR("unknown native message session-id %" PRIu64
- " req-id %" PRIu64
- " code %u to FE adapter %s",
- msg->refer_id, msg->req_id, msg->code,
- adapter->name);
+ __log_err("unknown native message session-id %" PRIu64
+ " req-id %" PRIu64 " code %u to FE adapter %s",
+ msg->refer_id, msg->req_id, msg->code, adapter->name);
break;
}
}
@@ -1267,25 +1269,40 @@ static void mgmt_fe_adapter_process_msg(uint8_t version, uint8_t *data,
if (len >= sizeof(*msg))
fe_adapter_handle_native_msg(adapter, msg, len);
else
- MGMTD_FE_ADAPTER_ERR("native message to adapter %s too short %zu",
- adapter->name, len);
+ __log_err("native message to adapter %s too short %zu",
+ adapter->name, len);
return;
}
fe_msg = mgmtd__fe_message__unpack(NULL, len, data);
if (!fe_msg) {
- MGMTD_FE_ADAPTER_DBG(
- "Failed to decode %zu bytes for adapter: %s", len,
- adapter->name);
+ __dbg("Failed to decode %zu bytes for adapter: %s", len,
+ adapter->name);
return;
}
- MGMTD_FE_ADAPTER_DBG(
- "Decoded %zu bytes of message: %u from adapter: %s", len,
- fe_msg->message_case, adapter->name);
+ __dbg("Decoded %zu bytes of message: %u from adapter: %s", len,
+ fe_msg->message_case, adapter->name);
(void)mgmt_fe_adapter_handle_msg(adapter, fe_msg);
mgmtd__fe_message__free_unpacked(fe_msg, NULL);
}
+void mgmt_fe_adapter_send_notify(struct mgmt_msg_notify_data *msg, size_t msglen)
+{
+ struct mgmt_fe_client_adapter *adapter;
+ struct mgmt_fe_session_ctx *session;
+
+ assert(msg->refer_id == 0);
+
+ FOREACH_ADAPTER_IN_LIST (adapter) {
+ FOREACH_SESSION_IN_LIST (adapter, session) {
+ msg->refer_id = session->session_id;
+ (void)fe_adapter_send_native_msg(adapter, msg, msglen,
+ false);
+ }
+ }
+ msg->refer_id = 0;
+}
+
void mgmt_fe_adapter_lock(struct mgmt_fe_client_adapter *adapter)
{
adapter->refcount++;
@@ -1334,11 +1351,10 @@ static void mgmt_fe_abort_if_session(void *data)
{
struct mgmt_fe_session_ctx *session = data;
- MGMTD_FE_ADAPTER_ERR("found orphaned session id %" PRIu64
- " client id %" PRIu64 " adapter %s",
- session->session_id, session->client_id,
- session->adapter ? session->adapter->name
- : "NULL");
+ __log_err("found orphaned session id %" PRIu64 " client id %" PRIu64
+ " adapter %s",
+ session->session_id, session->client_id,
+ session->adapter ? session->adapter->name : "NULL");
abort();
}
@@ -1387,8 +1403,7 @@ struct msg_conn *mgmt_fe_create_adapter(int conn_fd, union sockunion *from)
adapter->setcfg_stats.min_tm = ULONG_MAX;
adapter->cmt_stats.min_tm = ULONG_MAX;
- MGMTD_FE_ADAPTER_DBG("Added new MGMTD Frontend adapter '%s'",
- adapter->name);
+ __dbg("Added new MGMTD Frontend adapter '%s'", adapter->name);
}
return adapter->conn;
}
@@ -1404,10 +1419,9 @@ int mgmt_fe_send_set_cfg_reply(uint64_t session_id, uint64_t txn_id,
session = mgmt_session_id2ctx(session_id);
if (!session || session->cfg_txn_id != txn_id) {
if (session)
- MGMTD_FE_ADAPTER_ERR(
- "txn-id doesn't match, session txn-id is %" PRIu64
- " current txnid: %" PRIu64,
- session->cfg_txn_id, txn_id);
+ __log_err("txn-id doesn't match, session txn-id is %" PRIu64
+ " current txnid: %" PRIu64,
+ session->cfg_txn_id, txn_id);
return -1;
}
@@ -1453,6 +1467,7 @@ int mgmt_fe_send_get_reply(uint64_t session_id, uint64_t txn_id,
int mgmt_fe_adapter_send_tree_data(uint64_t session_id, uint64_t txn_id,
uint64_t req_id, LYD_FORMAT result_type,
+ uint32_t wd_options,
const struct lyd_node *tree,
int partial_error, bool short_circuit_ok)
{
@@ -1464,7 +1479,8 @@ int mgmt_fe_adapter_send_tree_data(uint64_t session_id, uint64_t txn_id,
return -1;
ret = fe_adapter_send_tree_data(session, req_id, short_circuit_ok,
- result_type, tree, partial_error);
+ result_type, wd_options, tree,
+ partial_error);
mgmt_destroy_txn(&session->txn_id);
@@ -1483,9 +1499,9 @@ int mgmt_fe_adapter_txn_error(uint64_t txn_id, uint64_t req_id,
session = fe_adapter_session_by_txn_id(txn_id);
if (!session) {
- MGMTD_FE_ADAPTER_ERR("failed sending error for txn-id %" PRIu64
- " session not found",
- txn_id);
+ __log_err("failed sending error for txn-id %" PRIu64
+ " session not found",
+ txn_id);
return -ENOENT;
}
diff --git a/mgmtd/mgmt_fe_adapter.h b/mgmtd/mgmt_fe_adapter.h
index 09d64415bc..2150f864d9 100644
--- a/mgmtd/mgmt_fe_adapter.h
+++ b/mgmtd/mgmt_fe_adapter.h
@@ -148,6 +148,7 @@ extern int mgmt_fe_send_get_reply(uint64_t session_id, uint64_t txn_id,
* txn_id: the txn_id this data pertains to
* req_id: the req id for the get_tree message
* result_type: the format of the result data.
+ * wd_options: with-defaults options.
* tree: the results.
* partial_error: if there were errors while gather results.
* short_circuit_ok: True if OK to short-circuit the call.
@@ -156,12 +157,11 @@ extern int mgmt_fe_send_get_reply(uint64_t session_id, uint64_t txn_id,
* the return value from the underlying send function.
*
*/
-extern int mgmt_fe_adapter_send_tree_data(uint64_t session_id, uint64_t txn_id,
- uint64_t req_id,
- LYD_FORMAT result_type,
- const struct lyd_node *tree,
- int partial_error,
- bool short_circuit_ok);
+extern int
+mgmt_fe_adapter_send_tree_data(uint64_t session_id, uint64_t txn_id,
+ uint64_t req_id, LYD_FORMAT result_type,
+ uint32_t wd_options, const struct lyd_node *tree,
+ int partial_error, bool short_circuit_ok);
/**
* Send an error back to the FE client using native messaging.
diff --git a/mgmtd/mgmt_main.c b/mgmtd/mgmt_main.c
index 6dbd1f2e52..5be849b63c 100644
--- a/mgmtd/mgmt_main.c
+++ b/mgmtd/mgmt_main.c
@@ -145,6 +145,16 @@ extern const struct frr_yang_module_info frr_staticd_cli_info;
#endif
/*
+ * These are modules that are only needed by mgmtd and hence not included into
+ * the lib and backend daemons.
+ */
+const struct frr_yang_module_info ietf_netconf_with_defaults_info = {
+ .name = "ietf-netconf-with-defaults",
+ .ignore_cfg_cbs = true,
+ .nodes = { { .xpath = NULL } },
+};
+
+/*
* These are stub info structs that are used to load the modules used by backend
* clients into mgmtd. The modules are used by libyang in order to support
* parsing binary data returns from the backend.
@@ -167,6 +177,9 @@ static const struct frr_yang_module_info *const mgmt_yang_modules[] = {
&frr_vrf_info,
&frr_affinity_map_cli_info,
+ /* mgmtd-only modules */
+ &ietf_netconf_with_defaults_info,
+
/*
* YANG module info used by backend clients get added here.
*/
diff --git a/mgmtd/mgmt_testc.c b/mgmtd/mgmt_testc.c
new file mode 100644
index 0000000000..02a308f328
--- /dev/null
+++ b/mgmtd/mgmt_testc.c
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * January 29 2024, Christian Hopps <chopps@labn.net>
+ *
+ * Copyright (c) 2024, LabN Consulting, L.L.C.
+ *
+ */
+
+#include <zebra.h>
+#include <lib/version.h>
+#include "darr.h"
+#include "libfrr.h"
+#include "mgmt_be_client.h"
+
+/* ---------------- */
+/* Local Prototypes */
+/* ---------------- */
+
+static void async_notification(struct mgmt_be_client *client, uintptr_t usr_data,
+ struct mgmt_be_client_notification_cb *this,
+ const char *notif_data);
+
+static void sigusr1(void);
+static void sigint(void);
+
+/* ----------- */
+/* Global Data */
+/* ----------- */
+
+/* privileges */
+static zebra_capabilities_t _caps_p[] = {};
+
+struct zebra_privs_t __privs = {
+#if defined(FRR_USER) && defined(FRR_GROUP)
+ .user = FRR_USER,
+ .group = FRR_GROUP,
+#endif
+#ifdef VTY_GROUP
+ .vty_group = VTY_GROUP,
+#endif
+ .caps_p = _caps_p,
+ .cap_num_p = array_size(_caps_p),
+ .cap_num_i = 0,
+};
+
+#define OPTION_LISTEN 2000
+#define OPTION_NOTIF_COUNT 2001
+#define OPTION_TIMEOUT 2002
+const struct option longopts[] = {
+ { "listen", no_argument, NULL, OPTION_LISTEN },
+ { "notif-count", required_argument, NULL, OPTION_NOTIF_COUNT },
+ { "timeout", required_argument, NULL, OPTION_TIMEOUT },
+ { 0 }
+};
+
+
+/* Master of threads. */
+struct event_loop *master;
+
+struct mgmt_be_client *mgmt_be_client;
+
+static struct frr_daemon_info mgmtd_testc_di;
+
+struct frr_signal_t __signals[] = {
+ {
+ .signal = SIGUSR1,
+ .handler = &sigusr1,
+ },
+ {
+ .signal = SIGINT,
+ .handler = &sigint,
+ },
+ {
+ .signal = SIGTERM,
+ .handler = &sigint,
+ },
+};
+
+#define MGMTD_TESTC_VTY_PORT 2624
+
+/* clang-format off */
+FRR_DAEMON_INFO(mgmtd_testc, MGMTD_TESTC,
+ .proghelp = "FRR Management Daemon Test Client.",
+
+ .signals = __signals,
+ .n_signals = array_size(__signals),
+
+ .privs = &__privs,
+
+ // .yang_modules = mgmt_yang_modules,
+ // .n_yang_modules = array_size(mgmt_yang_modules),
+
+ /* avoid libfrr trying to read our config file for us */
+ .flags = FRR_MANUAL_VTY_START,
+ );
+/* clang-format on */
+
+struct mgmt_be_client_notification_cb *__notify_cbs;
+
+struct mgmt_be_client_cbs __client_cbs = {};
+struct event *event_timeout;
+
+int o_notif_count = 1;
+int o_timeout;
+
+/* --------- */
+/* Functions */
+/* --------- */
+
+
+static void sigusr1(void)
+{
+ zlog_rotate();
+}
+
+static void quit(int exit_code)
+{
+ EVENT_OFF(event_timeout);
+ frr_fini();
+ darr_free(__client_cbs.notify_cbs);
+ exit(exit_code);
+}
+
+static void sigint(void)
+{
+ zlog_notice("Terminating on signal");
+ quit(0);
+}
+
+static void timeout(struct event *event)
+{
+ zlog_notice("Timeout, exiting");
+ quit(1);
+}
+
+static void async_notification(struct mgmt_be_client *client, uintptr_t usr_data,
+ struct mgmt_be_client_notification_cb *this,
+ const char *notif_data)
+{
+ zlog_notice("Received YANG notification");
+
+ printf("%s\n", notif_data);
+
+ if (o_notif_count && !--o_notif_count)
+ quit(0);
+}
+
+int main(int argc, char **argv)
+{
+ int f_listen = 0;
+ int i;
+
+ frr_preinit(&mgmtd_testc_di, argc, argv);
+ frr_opt_add("", longopts, "");
+
+ while (1) {
+ int opt;
+
+ opt = frr_getopt(argc, argv, NULL);
+
+ if (opt == EOF)
+ break;
+
+ switch (opt) {
+ case OPTION_LISTEN:
+ f_listen = 1;
+ break;
+ case OPTION_NOTIF_COUNT:
+ o_notif_count = atoi(optarg);
+ break;
+ case OPTION_TIMEOUT:
+ o_timeout = atoi(optarg);
+ break;
+ case 0:
+ break;
+ default:
+ frr_help_exit(1);
+ }
+ }
+
+ master = frr_init();
+
+ /*
+ * Setup notification listen
+ */
+ argv += optind;
+ argc -= optind;
+ if (!argc && f_listen) {
+ fprintf(stderr,
+ "Must specify at least one notification xpath to listen to\n");
+ exit(1);
+ }
+ if (argc && f_listen) {
+ struct mgmt_be_client_notification_cb *cb;
+
+ for (i = 0; i < argc; i++) {
+ zlog_notice("Listen on xpath: %s", argv[i]);
+ cb = darr_append(__notify_cbs);
+ cb->xpath = argv[i];
+ cb->format = LYD_JSON;
+ cb->callback = async_notification;
+ }
+ __client_cbs.notify_cbs = __notify_cbs;
+ __client_cbs.nnotify_cbs = darr_len(__notify_cbs);
+ }
+
+ mgmt_be_client = mgmt_be_client_create("mgmtd-testc", &__client_cbs, 0,
+ master);
+
+ frr_config_fork();
+
+ if (o_timeout)
+ event_add_timer(master, timeout, NULL, o_timeout, &event_timeout);
+
+ frr_run(master);
+
+ /* Reached. */
+ return 0;
+}
diff --git a/mgmtd/mgmt_txn.c b/mgmtd/mgmt_txn.c
index 7f88524e85..df2a1d852d 100644
--- a/mgmtd/mgmt_txn.c
+++ b/mgmtd/mgmt_txn.c
@@ -17,10 +17,9 @@
#include "mgmtd/mgmt_memory.h"
#include "mgmtd/mgmt_txn.h"
-#define MGMTD_TXN_DBG(fmt, ...) \
+#define __dbg(fmt, ...) \
DEBUGD(&mgmt_debug_txn, "TXN: %s: " fmt, __func__, ##__VA_ARGS__)
-#define MGMTD_TXN_ERR(fmt, ...) \
- zlog_err("%s: ERROR: " fmt, __func__, ##__VA_ARGS__)
+#define __log_err(fmt, ...) zlog_err("%s: ERROR: " fmt, __func__, ##__VA_ARGS__)
#define MGMTD_TXN_LOCK(txn) mgmt_txn_lock(txn, __FILE__, __LINE__)
#define MGMTD_TXN_UNLOCK(txn) mgmt_txn_unlock(txn, __FILE__, __LINE__)
@@ -175,6 +174,7 @@ struct txn_req_get_tree {
uint64_t recv_clients; /* Bitmask of clients recv reply from */
int32_t partial_error; /* an error while gather results */
uint8_t result_type; /* LYD_FORMAT for results */
+ uint8_t wd_options; /* LYD_PRINT_WD_* flags for results */
uint8_t exact; /* if exact node is requested */
uint8_t simple_xpath; /* if xpath is simple */
struct lyd_node *client_results; /* result tree from clients */
@@ -314,7 +314,7 @@ static void mgmt_txn_cfg_batch_free(struct mgmt_txn_be_cfg_batch **batch)
size_t indx;
struct mgmt_commit_cfg_req *cmtcfg_req;
- MGMTD_TXN_DBG(" freeing batch txn-id %" PRIu64, (*batch)->txn->txn_id);
+ __dbg(" freeing batch txn-id %" PRIu64, (*batch)->txn->txn_id);
assert((*batch)->txn && (*batch)->txn->type == MGMTD_TXN_TYPE_CONFIG);
@@ -371,15 +371,15 @@ static struct mgmt_txn_req *mgmt_txn_req_alloc(struct mgmt_txn_ctx *txn,
sizeof(struct mgmt_set_cfg_req));
assert(txn_req->req.set_cfg);
mgmt_txn_reqs_add_tail(&txn->set_cfg_reqs, txn_req);
- MGMTD_TXN_DBG("Added a new SETCFG req-id: %" PRIu64
- " txn-id: %" PRIu64 ", session-id: %" PRIu64,
- txn_req->req_id, txn->txn_id, txn->session_id);
+ __dbg("Added a new SETCFG req-id: %" PRIu64 " txn-id: %" PRIu64
+ ", session-id: %" PRIu64,
+ txn_req->req_id, txn->txn_id, txn->session_id);
break;
case MGMTD_TXN_PROC_COMMITCFG:
txn->commit_cfg_req = txn_req;
- MGMTD_TXN_DBG("Added a new COMMITCFG req-id: %" PRIu64
- " txn-id: %" PRIu64 " session-id: %" PRIu64,
- txn_req->req_id, txn->txn_id, txn->session_id);
+ __dbg("Added a new COMMITCFG req-id: %" PRIu64
+ " txn-id: %" PRIu64 " session-id: %" PRIu64,
+ txn_req->req_id, txn->txn_id, txn->session_id);
FOREACH_MGMTD_BE_CLIENT_ID (id) {
txn_req->req.commit_cfg.be_phase[id] =
@@ -396,17 +396,17 @@ static struct mgmt_txn_req *mgmt_txn_req_alloc(struct mgmt_txn_ctx *txn,
sizeof(struct mgmt_get_data_req));
assert(txn_req->req.get_data);
mgmt_txn_reqs_add_tail(&txn->get_cfg_reqs, txn_req);
- MGMTD_TXN_DBG("Added a new GETCFG req-id: %" PRIu64
- " txn-id: %" PRIu64 " session-id: %" PRIu64,
- txn_req->req_id, txn->txn_id, txn->session_id);
+ __dbg("Added a new GETCFG req-id: %" PRIu64 " txn-id: %" PRIu64
+ " session-id: %" PRIu64,
+ txn_req->req_id, txn->txn_id, txn->session_id);
break;
case MGMTD_TXN_PROC_GETTREE:
txn_req->req.get_tree = XCALLOC(MTYPE_MGMTD_TXN_GETTREE_REQ,
sizeof(struct txn_req_get_tree));
mgmt_txn_reqs_add_tail(&txn->get_tree_reqs, txn_req);
- MGMTD_TXN_DBG("Added a new GETTREE req-id: %" PRIu64
- " txn-id: %" PRIu64 " session-id: %" PRIu64,
- txn_req->req_id, txn->txn_id, txn->session_id);
+ __dbg("Added a new GETTREE req-id: %" PRIu64 " txn-id: %" PRIu64
+ " session-id: %" PRIu64,
+ txn_req->req_id, txn->txn_id, txn->session_id);
break;
case MGMTD_TXN_COMMITCFG_TIMEOUT:
case MGMTD_TXN_GETTREE_TIMEOUT:
@@ -425,41 +425,24 @@ static void mgmt_txn_req_free(struct mgmt_txn_req **txn_req)
enum mgmt_be_client_id id;
struct mgmt_be_client_adapter *adapter;
struct mgmt_commit_cfg_req *ccreq;
+ struct mgmt_set_cfg_req *set_cfg;
bool cleanup;
switch ((*txn_req)->req_event) {
case MGMTD_TXN_PROC_SETCFG:
- for (indx = 0; indx < (*txn_req)->req.set_cfg->num_cfg_changes;
- indx++) {
- if ((*txn_req)->req.set_cfg->cfg_changes[indx].value) {
- MGMTD_TXN_DBG("Freeing value for %s at %p ==> '%s'",
- (*txn_req)
- ->req.set_cfg
- ->cfg_changes[indx]
- .xpath,
- (*txn_req)
- ->req.set_cfg
- ->cfg_changes[indx]
- .value,
- (*txn_req)
- ->req.set_cfg
- ->cfg_changes[indx]
- .value);
- free((void *)(*txn_req)
- ->req.set_cfg->cfg_changes[indx]
- .value);
- }
+ set_cfg = (*txn_req)->req.set_cfg;
+ for (indx = 0; indx < set_cfg->num_cfg_changes; indx++) {
+ if (set_cfg->cfg_changes[indx].value)
+ free((void *)set_cfg->cfg_changes[indx].value);
}
req_list = &(*txn_req)->txn->set_cfg_reqs;
- MGMTD_TXN_DBG("Deleting SETCFG req-id: %" PRIu64
- " txn-id: %" PRIu64,
- (*txn_req)->req_id, (*txn_req)->txn->txn_id);
+ __dbg("Deleting SETCFG req-id: %" PRIu64 " txn-id: %" PRIu64,
+ (*txn_req)->req_id, (*txn_req)->txn->txn_id);
XFREE(MTYPE_MGMTD_TXN_SETCFG_REQ, (*txn_req)->req.set_cfg);
break;
case MGMTD_TXN_PROC_COMMITCFG:
- MGMTD_TXN_DBG("Deleting COMMITCFG req-id: %" PRIu64
- " txn-id: %" PRIu64,
- (*txn_req)->req_id, (*txn_req)->txn->txn_id);
+ __dbg("Deleting COMMITCFG req-id: %" PRIu64 " txn-id: %" PRIu64,
+ (*txn_req)->req_id, (*txn_req)->txn->txn_id);
ccreq = &(*txn_req)->req.commit_cfg;
cleanup = (ccreq->phase >= MGMTD_COMMIT_PHASE_TXN_CREATE &&
@@ -495,9 +478,8 @@ static void mgmt_txn_req_free(struct mgmt_txn_req **txn_req)
->req.get_data->xpaths[indx]);
}
req_list = &(*txn_req)->txn->get_cfg_reqs;
- MGMTD_TXN_DBG("Deleting GETCFG req-id: %" PRIu64
- " txn-id: %" PRIu64,
- (*txn_req)->req_id, (*txn_req)->txn->txn_id);
+ __dbg("Deleting GETCFG req-id: %" PRIu64 " txn-id: %" PRIu64,
+ (*txn_req)->req_id, (*txn_req)->txn->txn_id);
if ((*txn_req)->req.get_data->reply)
XFREE(MTYPE_MGMTD_TXN_GETDATA_REPLY,
(*txn_req)->req.get_data->reply);
@@ -508,9 +490,8 @@ static void mgmt_txn_req_free(struct mgmt_txn_req **txn_req)
XFREE(MTYPE_MGMTD_TXN_GETDATA_REQ, (*txn_req)->req.get_data);
break;
case MGMTD_TXN_PROC_GETTREE:
- MGMTD_TXN_DBG("Deleting GETTREE req-id: %" PRIu64
- " of txn-id: %" PRIu64,
- (*txn_req)->req_id, (*txn_req)->txn->txn_id);
+ __dbg("Deleting GETTREE req-id: %" PRIu64 " of txn-id: %" PRIu64,
+ (*txn_req)->req_id, (*txn_req)->txn->txn_id);
req_list = &(*txn_req)->txn->get_tree_reqs;
lyd_free_all((*txn_req)->req.get_tree->client_results);
XFREE(MTYPE_MGMTD_XPATH, (*txn_req)->req.get_tree->xpath);
@@ -523,9 +504,8 @@ static void mgmt_txn_req_free(struct mgmt_txn_req **txn_req)
if (req_list) {
mgmt_txn_reqs_del(req_list, *txn_req);
- MGMTD_TXN_DBG("Removed req-id: %" PRIu64
- " from request-list (left:%zu)",
- (*txn_req)->req_id, mgmt_txn_reqs_count(req_list));
+ __dbg("Removed req-id: %" PRIu64 " from request-list (left:%zu)",
+ (*txn_req)->req_id, mgmt_txn_reqs_count(req_list));
}
MGMTD_TXN_UNLOCK(&(*txn_req)->txn);
@@ -550,10 +530,10 @@ static void mgmt_txn_process_set_cfg(struct event *thread)
assert(txn);
cmt_stats = mgmt_fe_get_session_commit_stats(txn->session_id);
- MGMTD_TXN_DBG("Processing %zu SET_CONFIG requests txn-id:%" PRIu64
- " session-id: %" PRIu64,
- mgmt_txn_reqs_count(&txn->set_cfg_reqs), txn->txn_id,
- txn->session_id);
+ __dbg("Processing %zu SET_CONFIG requests txn-id:%" PRIu64
+ " session-id: %" PRIu64,
+ mgmt_txn_reqs_count(&txn->set_cfg_reqs), txn->txn_id,
+ txn->session_id);
FOREACH_TXN_REQ_IN_LIST (&txn->set_cfg_reqs, txn_req) {
assert(txn_req->req_event == MGMTD_TXN_PROC_SETCFG);
@@ -605,11 +585,11 @@ static void mgmt_txn_process_set_cfg(struct event *thread)
/* We expect the user to have locked the DST DS */
if (!mgmt_ds_is_locked(txn_req->req.set_cfg->dst_ds_ctx,
txn->session_id)) {
- MGMTD_TXN_ERR("DS %u not locked for implicit commit txn-id: %" PRIu64
- " session-id: %" PRIu64 " err: %s",
- txn_req->req.set_cfg->dst_ds_id,
- txn->txn_id, txn->session_id,
- strerror(ret));
+ __log_err("DS %u not locked for implicit commit txn-id: %" PRIu64
+ " session-id: %" PRIu64 " err: %s",
+ txn_req->req.set_cfg->dst_ds_id,
+ txn->txn_id, txn->session_id,
+ strerror(ret));
mgmt_fe_send_set_cfg_reply(
txn->session_id, txn->txn_id,
txn_req->req.set_cfg->ds_id,
@@ -640,9 +620,9 @@ static void mgmt_txn_process_set_cfg(struct event *thread)
txn_req->req_id,
MGMTD_SUCCESS, NULL,
false) != 0) {
- MGMTD_TXN_ERR("Failed to send SET_CONFIG_REPLY txn-id %" PRIu64
- " session-id: %" PRIu64,
- txn->txn_id, txn->session_id);
+ __log_err("Failed to send SET_CONFIG_REPLY txn-id %" PRIu64
+ " session-id: %" PRIu64,
+ txn->txn_id, txn->session_id);
}
mgmt_txn_process_set_cfg_done:
@@ -659,9 +639,8 @@ mgmt_txn_process_set_cfg_done:
left = mgmt_txn_reqs_count(&txn->set_cfg_reqs);
if (left) {
- MGMTD_TXN_DBG("Processed maximum number of Set-Config requests (%d/%d/%d). Rescheduling for rest.",
- num_processed, MGMTD_TXN_MAX_NUM_SETCFG_PROC,
- (int)left);
+ __dbg("Processed maximum number of Set-Config requests (%d/%d/%d). Rescheduling for rest.",
+ num_processed, MGMTD_TXN_MAX_NUM_SETCFG_PROC, (int)left);
mgmt_txn_register_event(txn, MGMTD_TXN_PROC_SETCFG);
}
}
@@ -692,9 +671,9 @@ static int mgmt_txn_send_commit_cfg_reply(struct mgmt_txn_ctx *txn,
txn->commit_cfg_req->req.commit_cfg
.validate_only,
result, error_if_any) != 0) {
- MGMTD_TXN_ERR("Failed to send COMMIT-CONFIG-REPLY txn-id: %" PRIu64
- " session-id: %" PRIu64,
- txn->txn_id, txn->session_id);
+ __log_err("Failed to send COMMIT-CONFIG-REPLY txn-id: %" PRIu64
+ " session-id: %" PRIu64,
+ txn->txn_id, txn->session_id);
}
if (txn->commit_cfg_req->req.commit_cfg.implicit && txn->session_id &&
@@ -706,9 +685,9 @@ static int mgmt_txn_send_commit_cfg_reply(struct mgmt_txn_ctx *txn,
success ? MGMTD_SUCCESS
: MGMTD_INTERNAL_ERROR,
error_if_any, true) != 0) {
- MGMTD_TXN_ERR("Failed to send SET-CONFIG-REPLY txn-id: %" PRIu64
- " session-id: %" PRIu64,
- txn->txn_id, txn->session_id);
+ __log_err("Failed to send SET-CONFIG-REPLY txn-id: %" PRIu64
+ " session-id: %" PRIu64,
+ txn->txn_id, txn->session_id);
}
if (success) {
@@ -791,8 +770,8 @@ mgmt_try_move_commit_to_next_phase(struct mgmt_txn_ctx *txn,
{
enum mgmt_be_client_id id;
- MGMTD_TXN_DBG("txn-id: %" PRIu64 ", Phase '%s'",
- txn->txn_id, mgmt_txn_commit_phase_str(txn));
+ __dbg("txn-id: %" PRIu64 ", Phase '%s'", txn->txn_id,
+ mgmt_txn_commit_phase_str(txn));
/*
* Check if all clients has moved to next phase or not.
@@ -818,8 +797,8 @@ mgmt_try_move_commit_to_next_phase(struct mgmt_txn_ctx *txn,
*/
cmtcfg_req->phase++;
- MGMTD_TXN_DBG("Move entire txn-id: %" PRIu64 " to phase '%s'",
- txn->txn_id, mgmt_txn_commit_phase_str(txn));
+ __dbg("Move entire txn-id: %" PRIu64 " to phase '%s'", txn->txn_id,
+ mgmt_txn_commit_phase_str(txn));
mgmt_txn_register_event(txn, MGMTD_TXN_PROC_COMMITCFG);
@@ -866,8 +845,7 @@ static int mgmt_txn_create_config_batches(struct mgmt_txn_req *txn_req,
if (!value)
value = (char *)MGMTD_BE_CONTAINER_NODE_VAL;
- MGMTD_TXN_DBG("XPATH: %s, Value: '%s'", xpath,
- value ? value : "NIL");
+ __dbg("XPATH: %s, Value: '%s'", xpath, value ? value : "NIL");
clients = mgmt_be_interested_clients(xpath, true);
@@ -925,8 +903,8 @@ static int mgmt_txn_create_config_batches(struct mgmt_txn_req *txn_req,
batch->value[batch->num_cfg_data].encoded_str_val =
value;
- MGMTD_TXN_DBG(" -- %s, batch item:%d", adapter->name,
- (int)batch->num_cfg_data);
+ __dbg(" -- %s, batch item:%d", adapter->name,
+ (int)batch->num_cfg_data);
batch->num_cfg_data++;
num_chgs++;
@@ -936,7 +914,7 @@ static int mgmt_txn_create_config_batches(struct mgmt_txn_req *txn_req,
snprintf(err_buf, sizeof(err_buf),
"No validator module found for XPATH: '%s",
xpath);
- MGMTD_TXN_ERR("***** %s", err_buf);
+ __log_err("***** %s", err_buf);
}
cmtcfg_req->clients |= chg_clients;
@@ -1157,10 +1135,8 @@ static int mgmt_txn_send_be_txn_create(struct mgmt_txn_ctx *txn)
* come back.
*/
- MGMTD_TXN_DBG("txn-id: %" PRIu64 " session-id: %" PRIu64
- " Phase '%s'",
- txn->txn_id, txn->session_id,
- mgmt_txn_commit_phase_str(txn));
+ __dbg("txn-id: %" PRIu64 " session-id: %" PRIu64 " Phase '%s'",
+ txn->txn_id, txn->session_id, mgmt_txn_commit_phase_str(txn));
return 0;
}
@@ -1193,8 +1169,9 @@ static int mgmt_txn_send_be_cfg_data(struct mgmt_txn_ctx *txn,
(void)mgmt_txn_send_commit_cfg_reply(
txn, MGMTD_INTERNAL_ERROR,
"Internal Error! Could not send config data to backend!");
- MGMTD_TXN_ERR("Could not send CFGDATA_CREATE txn-id: %" PRIu64
- " to client '%s", txn->txn_id, adapter->name);
+ __log_err("Could not send CFGDATA_CREATE txn-id: %" PRIu64
+ " to client '%s",
+ txn->txn_id, adapter->name);
return -1;
}
@@ -1238,8 +1215,8 @@ static void mgmt_txn_cfg_commit_timedout(struct event *thread)
if (!txn->commit_cfg_req)
return;
- MGMTD_TXN_ERR("Backend timeout txn-id: %" PRIu64 " aborting commit",
- txn->txn_id);
+ __log_err("Backend timeout txn-id: %" PRIu64 " aborting commit",
+ txn->txn_id);
/*
* Send a COMMIT_CONFIG_REPLY with failure.
@@ -1282,6 +1259,7 @@ static int txn_get_tree_data_done(struct mgmt_txn_ctx *txn,
txn->txn_id,
txn_req->req_id,
get_tree->result_type,
+ get_tree->wd_options,
result,
get_tree->partial_error,
false);
@@ -1290,9 +1268,9 @@ static int txn_get_tree_data_done(struct mgmt_txn_ctx *txn,
mgmt_txn_req_free(&txn_req);
if (ret) {
- MGMTD_TXN_ERR("Error sending the results of GETTREE for txn-id %" PRIu64
- " req_id %" PRIu64 " to requested type %u",
- txn->txn_id, req_id, get_tree->result_type);
+ __log_err("Error sending the results of GETTREE for txn-id %" PRIu64
+ " req_id %" PRIu64 " to requested type %u",
+ txn->txn_id, req_id, get_tree->result_type);
(void)mgmt_fe_adapter_txn_error(txn->txn_id, req_id, false, ret,
"Error converting results of GETTREE");
@@ -1314,8 +1292,8 @@ static void txn_get_tree_timeout(struct event *thread)
assert(txn->type == MGMTD_TXN_TYPE_SHOW);
- MGMTD_TXN_ERR("Backend timeout txn-id: %" PRIu64 " ending get-tree",
- txn->txn_id);
+ __log_err("Backend timeout txn-id: %" PRIu64 " ending get-tree",
+ txn->txn_id);
/*
* Send a get-tree data reply.
@@ -1388,10 +1366,9 @@ static void mgmt_txn_process_commit_cfg(struct event *thread)
txn = (struct mgmt_txn_ctx *)EVENT_ARG(thread);
assert(txn);
- MGMTD_TXN_DBG("Processing COMMIT_CONFIG for txn-id: %" PRIu64
- " session-id: %" PRIu64 " Phase '%s'",
- txn->txn_id, txn->session_id,
- mgmt_txn_commit_phase_str(txn));
+ __dbg("Processing COMMIT_CONFIG for txn-id: %" PRIu64
+ " session-id: %" PRIu64 " Phase '%s'",
+ txn->txn_id, txn->session_id, mgmt_txn_commit_phase_str(txn));
assert(txn->commit_cfg_req);
cmtcfg_req = &txn->commit_cfg_req->req.commit_cfg;
@@ -1417,13 +1394,13 @@ static void mgmt_txn_process_commit_cfg(struct event *thread)
* Backend by now.
*/
#ifndef MGMTD_LOCAL_VALIDATIONS_ENABLED
- MGMTD_TXN_DBG("txn-id: %" PRIu64 " session-id: %" PRIu64
- " trigger sending CFG_VALIDATE_REQ to all backend clients",
- txn->txn_id, txn->session_id);
+ __dbg("txn-id: %" PRIu64 " session-id: %" PRIu64
+ " trigger sending CFG_VALIDATE_REQ to all backend clients",
+ txn->txn_id, txn->session_id);
#else /* ifndef MGMTD_LOCAL_VALIDATIONS_ENABLED */
- MGMTD_TXN_DBG("txn-id: %" PRIu64 " session-id: %" PRIu64
- " trigger sending CFG_APPLY_REQ to all backend clients",
- txn->txn_id, txn->session_id);
+ __dbg("txn-id: %" PRIu64 " session-id: %" PRIu64
+ " trigger sending CFG_APPLY_REQ to all backend clients",
+ txn->txn_id, txn->session_id);
#endif /* ifndef MGMTD_LOCAL_VALIDATIONS_ENABLED */
break;
case MGMTD_COMMIT_PHASE_APPLY_CFG:
@@ -1512,8 +1489,8 @@ static void mgmt_txn_send_getcfg_reply_data(struct mgmt_txn_req *txn_req,
data_reply->next_indx = (!get_reply->last_batch ? get_req->total_reply
: -1);
- MGMTD_TXN_DBG("Sending %zu Get-Config/Data replies next-index:%" PRId64,
- data_reply->n_data, data_reply->next_indx);
+ __dbg("Sending %zu Get-Config/Data replies next-index:%" PRId64,
+ data_reply->n_data, data_reply->next_indx);
switch (txn_req->req_event) {
case MGMTD_TXN_PROC_GETCFG:
@@ -1521,11 +1498,10 @@ static void mgmt_txn_send_getcfg_reply_data(struct mgmt_txn_req *txn_req,
txn_req->txn->txn_id, get_req->ds_id,
txn_req->req_id, MGMTD_SUCCESS,
data_reply, NULL) != 0) {
- MGMTD_TXN_ERR("Failed to send GET-CONFIG-REPLY txn-id: %" PRIu64
- " session-id: %" PRIu64
- " req-id: %" PRIu64,
- txn_req->txn->txn_id,
- txn_req->txn->session_id, txn_req->req_id);
+ __log_err("Failed to send GET-CONFIG-REPLY txn-id: %" PRIu64
+ " session-id: %" PRIu64 " req-id: %" PRIu64,
+ txn_req->txn->txn_id,
+ txn_req->txn->session_id, txn_req->req_id);
}
break;
case MGMTD_TXN_PROC_SETCFG:
@@ -1533,7 +1509,7 @@ static void mgmt_txn_send_getcfg_reply_data(struct mgmt_txn_req *txn_req,
case MGMTD_TXN_PROC_GETTREE:
case MGMTD_TXN_GETTREE_TIMEOUT:
case MGMTD_TXN_COMMITCFG_TIMEOUT:
- MGMTD_TXN_ERR("Invalid Txn-Req-Event %u", txn_req->req_event);
+ __log_err("Invalid Txn-Req-Event %u", txn_req->req_event);
break;
}
@@ -1576,8 +1552,8 @@ static void txn_iter_get_config_data_cb(const char *xpath, struct lyd_node *node
get_reply->num_reply++;
get_req->total_reply++;
- MGMTD_TXN_DBG(" [%d] XPATH: '%s', Value: '%s'", get_req->total_reply,
- data->xpath, data_value->encoded_str_val);
+ __dbg(" [%d] XPATH: '%s', Value: '%s'", get_req->total_reply,
+ data->xpath, data_value->encoded_str_val);
if (get_reply->num_reply == MGMTD_MAX_NUM_DATA_REPLY_IN_BATCH)
mgmt_txn_send_getcfg_reply_data(txn_req, get_req);
@@ -1611,8 +1587,8 @@ static int mgmt_txn_get_config(struct mgmt_txn_ctx *txn,
*/
get_reply = get_data->reply;
for (indx = 0; indx < get_data->num_xpaths; indx++) {
- MGMTD_TXN_DBG("Trying to get all data under '%s'",
- get_data->xpaths[indx]);
+ __dbg("Trying to get all data under '%s'",
+ get_data->xpaths[indx]);
mgmt_init_get_data_reply(get_reply);
/*
* mgmt_ds_iter_data works on path prefixes, but the user may
@@ -1623,16 +1599,15 @@ static int mgmt_txn_get_config(struct mgmt_txn_ctx *txn,
get_data->xpaths[indx],
txn_iter_get_config_data_cb,
(void *)txn_req) == -1) {
- MGMTD_TXN_DBG("Invalid Xpath '%s",
- get_data->xpaths[indx]);
+ __dbg("Invalid Xpath '%s", get_data->xpaths[indx]);
mgmt_fe_send_get_reply(txn->session_id, txn->txn_id,
get_data->ds_id, txn_req->req_id,
MGMTD_INTERNAL_ERROR, NULL,
"Invalid xpath");
goto mgmt_txn_get_config_failed;
}
- MGMTD_TXN_DBG("Got %d remaining data-replies for xpath '%s'",
- get_reply->num_reply, get_data->xpaths[indx]);
+ __dbg("Got %d remaining data-replies for xpath '%s'",
+ get_reply->num_reply, get_data->xpaths[indx]);
get_reply->last_batch = true;
mgmt_txn_send_getcfg_reply_data(txn_req, get_data);
}
@@ -1659,10 +1634,10 @@ static void mgmt_txn_process_get_cfg(struct event *thread)
txn = (struct mgmt_txn_ctx *)EVENT_ARG(thread);
assert(txn);
- MGMTD_TXN_DBG("Processing %zu GET_CONFIG requests txn-id: %" PRIu64
- " session-id: %" PRIu64,
- mgmt_txn_reqs_count(&txn->get_cfg_reqs), txn->txn_id,
- txn->session_id);
+ __dbg("Processing %zu GET_CONFIG requests txn-id: %" PRIu64
+ " session-id: %" PRIu64,
+ mgmt_txn_reqs_count(&txn->get_cfg_reqs), txn->txn_id,
+ txn->session_id);
FOREACH_TXN_REQ_IN_LIST (&txn->get_cfg_reqs, txn_req) {
error = false;
@@ -1671,11 +1646,10 @@ static void mgmt_txn_process_get_cfg(struct event *thread)
assert(cfg_root);
if (mgmt_txn_get_config(txn, txn_req, cfg_root) != 0) {
- MGMTD_TXN_ERR("Unable to retrieve config from DS %d txn-id: %" PRIu64
- " session-id: %" PRIu64
- " req-id: %" PRIu64,
- txn_req->req.get_data->ds_id, txn->txn_id,
- txn->session_id, txn_req->req_id);
+ __log_err("Unable to retrieve config from DS %d txn-id: %" PRIu64
+ " session-id: %" PRIu64 " req-id: %" PRIu64,
+ txn_req->req.get_data->ds_id, txn->txn_id,
+ txn->session_id, txn_req->req_id);
error = true;
}
@@ -1698,8 +1672,8 @@ static void mgmt_txn_process_get_cfg(struct event *thread)
}
if (mgmt_txn_reqs_count(&txn->get_cfg_reqs)) {
- MGMTD_TXN_DBG("Processed maximum number of Get-Config requests (%d/%d). Rescheduling for rest.",
- num_processed, MGMTD_TXN_MAX_NUM_GETCFG_PROC);
+ __dbg("Processed maximum number of Get-Config requests (%d/%d). Rescheduling for rest.",
+ num_processed, MGMTD_TXN_MAX_NUM_GETCFG_PROC);
mgmt_txn_register_event(txn, MGMTD_TXN_PROC_GETCFG);
}
}
@@ -1746,8 +1720,8 @@ static struct mgmt_txn_ctx *mgmt_txn_create_new(uint64_t session_id,
txn->txn_id = mgmt_txn_mm->next_txn_id++;
hash_get(mgmt_txn_mm->txn_hash, txn, hash_alloc_intern);
- MGMTD_TXN_DBG("Added new '%s' txn-id: %" PRIu64,
- mgmt_txn_type2str(type), txn->txn_id);
+ __dbg("Added new '%s' txn-id: %" PRIu64,
+ mgmt_txn_type2str(type), txn->txn_id);
if (type == MGMTD_TXN_TYPE_CONFIG)
mgmt_txn_mm->cfg_txn = txn;
@@ -1829,9 +1803,8 @@ uint64_t mgmt_txn_get_session_id(uint64_t txn_id)
static void mgmt_txn_lock(struct mgmt_txn_ctx *txn, const char *file, int line)
{
txn->refcount++;
- MGMTD_TXN_DBG("%s:%d --> Lock %s txn-id: %" PRIu64 " refcnt: %d", file,
- line, mgmt_txn_type2str(txn->type), txn->txn_id,
- txn->refcount);
+ __dbg("%s:%d --> Lock %s txn-id: %" PRIu64 " refcnt: %d", file, line,
+ mgmt_txn_type2str(txn->type), txn->txn_id, txn->refcount);
}
static void mgmt_txn_unlock(struct mgmt_txn_ctx **txn, const char *file,
@@ -1840,9 +1813,8 @@ static void mgmt_txn_unlock(struct mgmt_txn_ctx **txn, const char *file,
assert(*txn && (*txn)->refcount);
(*txn)->refcount--;
- MGMTD_TXN_DBG("%s:%d --> Unlock %s txn-id: %" PRIu64 " refcnt: %d",
- file, line, mgmt_txn_type2str((*txn)->type),
- (*txn)->txn_id, (*txn)->refcount);
+ __dbg("%s:%d --> Unlock %s txn-id: %" PRIu64 " refcnt: %d", file, line,
+ mgmt_txn_type2str((*txn)->type), (*txn)->txn_id, (*txn)->refcount);
if (!(*txn)->refcount) {
if ((*txn)->type == MGMTD_TXN_TYPE_CONFIG)
if (mgmt_txn_mm->cfg_txn == *txn)
@@ -1855,10 +1827,9 @@ static void mgmt_txn_unlock(struct mgmt_txn_ctx **txn, const char *file,
hash_release(mgmt_txn_mm->txn_hash, *txn);
mgmt_txns_del(&mgmt_txn_mm->txn_list, *txn);
- MGMTD_TXN_DBG("Deleted %s txn-id: %" PRIu64
- " session-id: %" PRIu64,
- mgmt_txn_type2str((*txn)->type), (*txn)->txn_id,
- (*txn)->session_id);
+ __dbg("Deleted %s txn-id: %" PRIu64 " session-id: %" PRIu64,
+ mgmt_txn_type2str((*txn)->type), (*txn)->txn_id,
+ (*txn)->session_id);
XFREE(MTYPE_MGMTD_TXN, *txn);
}
@@ -1990,7 +1961,7 @@ int mgmt_txn_send_set_config_req(uint64_t txn_id, uint64_t req_id,
return -1;
if (implicit_commit && mgmt_txn_reqs_count(&txn->set_cfg_reqs)) {
- MGMTD_TXN_ERR(
+ __log_err(
"For implicit commit config only one SETCFG-REQ can be allowed!");
return -1;
}
@@ -2033,12 +2004,11 @@ int mgmt_txn_send_set_config_req(uint64_t txn_id, uint64_t req_id,
continue;
}
- MGMTD_TXN_DBG("XPath: '%s', Value: '%s'",
- cfg_req[indx]->data->xpath,
- (cfg_req[indx]->data->value &&
- cfg_req[indx]->data->value->encoded_str_val
- ? cfg_req[indx]->data->value->encoded_str_val
- : "NULL"));
+ __dbg("XPath: '%s', Value: '%s'", cfg_req[indx]->data->xpath,
+ (cfg_req[indx]->data->value &&
+ cfg_req[indx]->data->value->encoded_str_val
+ ? cfg_req[indx]->data->value->encoded_str_val
+ : "NULL"));
strlcpy(cfg_chg->xpath, cfg_req[indx]->data->xpath,
sizeof(cfg_chg->xpath));
cfg_chg->value =
@@ -2048,8 +2018,8 @@ int mgmt_txn_send_set_config_req(uint64_t txn_id, uint64_t req_id,
->data->value->encoded_str_val)
: NULL);
if (cfg_chg->value)
- MGMTD_TXN_DBG("Allocated value at %p ==> '%s'",
- cfg_chg->value, cfg_chg->value);
+ __dbg("Allocated value at %p ==> '%s'", cfg_chg->value,
+ cfg_chg->value);
(*num_chgs)++;
}
@@ -2079,9 +2049,9 @@ int mgmt_txn_send_commit_config_req(uint64_t txn_id, uint64_t req_id,
return -1;
if (txn->commit_cfg_req) {
- MGMTD_TXN_ERR("Commit already in-progress txn-id: %" PRIu64
- " session-id: %" PRIu64 ". Cannot start another",
- txn->txn_id, txn->session_id);
+ __log_err("Commit already in-progress txn-id: %" PRIu64
+ " session-id: %" PRIu64 ". Cannot start another",
+ txn->txn_id, txn->session_id);
return -1;
}
@@ -2129,15 +2099,14 @@ int mgmt_txn_notify_be_adapter_conn(struct mgmt_be_client_adapter *adapter,
*/
txn = mgmt_txn_create_new(0, MGMTD_TXN_TYPE_CONFIG);
if (!txn) {
- MGMTD_TXN_ERR("Failed to create CONFIG Transaction for downloading CONFIGs for client '%s'",
- adapter->name);
+ __log_err("Failed to create CONFIG Transaction for downloading CONFIGs for client '%s'",
+ adapter->name);
nb_config_diff_del_changes(adapter_cfgs);
return -1;
}
- MGMTD_TXN_DBG("Created initial txn-id: %" PRIu64
- " for BE client '%s'",
- txn->txn_id, adapter->name);
+ __dbg("Created initial txn-id: %" PRIu64 " for BE client '%s'",
+ txn->txn_id, adapter->name);
/*
* Set the changeset for transaction to commit and trigger the
* commit request.
@@ -2238,9 +2207,10 @@ int mgmt_txn_notify_be_cfgdata_reply(uint64_t txn_id, bool success,
cmtcfg_req = &txn->commit_cfg_req->req.commit_cfg;
if (!success) {
- MGMTD_TXN_ERR("CFGDATA_CREATE_REQ sent to '%s' failed txn-id: %" PRIu64
- " err: %s", adapter->name, txn->txn_id,
- error_if_any ? error_if_any : "None");
+ __log_err("CFGDATA_CREATE_REQ sent to '%s' failed txn-id: %" PRIu64
+ " err: %s",
+ adapter->name, txn->txn_id,
+ error_if_any ? error_if_any : "None");
mgmt_txn_send_commit_cfg_reply(
txn, MGMTD_INTERNAL_ERROR,
error_if_any
@@ -2249,9 +2219,9 @@ int mgmt_txn_notify_be_cfgdata_reply(uint64_t txn_id, bool success,
return 0;
}
- MGMTD_TXN_DBG("CFGDATA_CREATE_REQ sent to '%s' was successful txn-id: %" PRIu64
- " err: %s", adapter->name, txn->txn_id,
- error_if_any ? error_if_any : "None");
+ __dbg("CFGDATA_CREATE_REQ sent to '%s' was successful txn-id: %" PRIu64
+ " err: %s",
+ adapter->name, txn->txn_id, error_if_any ? error_if_any : "None");
cmtcfg_req->be_phase[adapter->id] = MGMTD_COMMIT_PHASE_APPLY_CFG;
@@ -2274,10 +2244,10 @@ int mgmt_txn_notify_be_cfg_apply_reply(uint64_t txn_id, bool success,
cmtcfg_req = &txn->commit_cfg_req->req.commit_cfg;
if (!success) {
- MGMTD_TXN_ERR("CFGDATA_APPLY_REQ sent to '%s' failed txn-id: %" PRIu64
- " err: %s",
- adapter->name, txn->txn_id,
- error_if_any ? error_if_any : "None");
+ __log_err("CFGDATA_APPLY_REQ sent to '%s' failed txn-id: %" PRIu64
+ " err: %s",
+ adapter->name, txn->txn_id,
+ error_if_any ? error_if_any : "None");
mgmt_txn_send_commit_cfg_reply(
txn, MGMTD_INTERNAL_ERROR,
error_if_any
@@ -2322,7 +2292,7 @@ int mgmt_txn_send_get_req(uint64_t txn_id, uint64_t req_id,
for (indx = 0;
indx < num_reqs && indx < MGMTD_MAX_NUM_DATA_REPLY_IN_BATCH;
indx++) {
- MGMTD_TXN_DBG("XPath: '%s'", data_req[indx]->data->xpath);
+ __dbg("XPath: '%s'", data_req[indx]->data->xpath);
txn_req->req.get_data->xpaths[indx] =
strdup(data_req[indx]->data->xpath);
txn_req->req.get_data->num_xpaths++;
@@ -2339,8 +2309,9 @@ int mgmt_txn_send_get_req(uint64_t txn_id, uint64_t req_id,
* has registered operational state that matches the given `xpath`
*/
int mgmt_txn_send_get_tree_oper(uint64_t txn_id, uint64_t req_id,
- uint64_t clients, LYD_FORMAT result_type,
- uint8_t flags, bool simple_xpath,
+ uint64_t clients, Mgmtd__DatastoreId ds_id,
+ LYD_FORMAT result_type, uint8_t flags,
+ uint32_t wd_options, bool simple_xpath,
const char *xpath)
{
struct mgmt_msg_get_tree *msg;
@@ -2359,13 +2330,20 @@ int mgmt_txn_send_get_tree_oper(uint64_t txn_id, uint64_t req_id,
txn_req = mgmt_txn_req_alloc(txn, req_id, MGMTD_TXN_PROC_GETTREE);
get_tree = txn_req->req.get_tree;
get_tree->result_type = result_type;
+ get_tree->wd_options = wd_options;
get_tree->exact = CHECK_FLAG(flags, GET_DATA_FLAG_EXACT);
get_tree->simple_xpath = simple_xpath;
get_tree->xpath = XSTRDUP(MTYPE_MGMTD_XPATH, xpath);
if (CHECK_FLAG(flags, GET_DATA_FLAG_CONFIG)) {
+ /*
+ * If the requested datastore is operational, get the config
+ * from running.
+ */
struct mgmt_ds_ctx *ds =
- mgmt_ds_get_ctx_by_id(mm, MGMTD_DS_RUNNING);
+ mgmt_ds_get_ctx_by_id(mm, ds_id == MGMTD_DS_OPERATIONAL
+ ? MGMTD_DS_RUNNING
+ : ds_id);
struct nb_config *config = mgmt_ds_get_nb_config(ds);
if (config) {
@@ -2411,7 +2389,8 @@ int mgmt_txn_send_get_tree_oper(uint64_t txn_id, uint64_t req_id,
}
state:
/* If we are only getting config, we are done */
- if (!CHECK_FLAG(flags, GET_DATA_FLAG_STATE) || !clients)
+ if (!CHECK_FLAG(flags, GET_DATA_FLAG_STATE) ||
+ ds_id != MGMTD_DS_OPERATIONAL || !clients)
return txn_get_tree_data_done(txn, txn_req);
msg = mgmt_msg_native_alloc_msg(struct mgmt_msg_get_tree, slen + 1,
@@ -2427,13 +2406,13 @@ state:
FOREACH_BE_CLIENT_BITS (id, clients) {
ret = mgmt_be_send_native(id, msg);
if (ret) {
- MGMTD_TXN_ERR("Could not send get-tree message to backend client %s",
- mgmt_be_client_id2name(id));
+ __log_err("Could not send get-tree message to backend client %s",
+ mgmt_be_client_id2name(id));
continue;
}
- MGMTD_TXN_DBG("Sent get-tree req to backend client %s",
- mgmt_be_client_id2name(id));
+ __dbg("Sent get-tree req to backend client %s",
+ mgmt_be_client_id2name(id));
/* record that we sent the request to the client */
get_tree->sent_clients |= (1u << id);
@@ -2467,8 +2446,8 @@ int mgmt_txn_notify_error(struct mgmt_be_client_adapter *adapter,
struct mgmt_txn_req *txn_req;
if (!txn) {
- MGMTD_TXN_ERR("Error reply from %s cannot find txn-id %" PRIu64,
- adapter->name, txn_id);
+ __log_err("Error reply from %s cannot find txn-id %" PRIu64,
+ adapter->name, txn_id);
return -1;
}
@@ -2477,15 +2456,14 @@ int mgmt_txn_notify_error(struct mgmt_be_client_adapter *adapter,
if (txn_req->req_id == req_id)
break;
if (!txn_req) {
- MGMTD_TXN_ERR("Error reply from %s for txn-id %" PRIu64
- " cannot find req_id %" PRIu64,
- adapter->name, txn_id, req_id);
+ __log_err("Error reply from %s for txn-id %" PRIu64
+ " cannot find req_id %" PRIu64,
+ adapter->name, txn_id, req_id);
return -1;
}
- MGMTD_TXN_ERR("Error reply from %s for txn-id %" PRIu64
- " req_id %" PRIu64,
- adapter->name, txn_id, req_id);
+ __log_err("Error reply from %s for txn-id %" PRIu64 " req_id %" PRIu64,
+ adapter->name, txn_id, req_id);
switch (txn_req->req_event) {
case MGMTD_TXN_PROC_GETTREE:
@@ -2528,8 +2506,8 @@ int mgmt_txn_notify_tree_data_reply(struct mgmt_be_client_adapter *adapter,
LY_ERR err;
if (!txn) {
- MGMTD_TXN_ERR("GETTREE reply from %s for a missing txn-id %" PRIu64,
- adapter->name, txn_id);
+ __log_err("GETTREE reply from %s for a missing txn-id %" PRIu64,
+ adapter->name, txn_id);
return -1;
}
@@ -2538,9 +2516,9 @@ int mgmt_txn_notify_tree_data_reply(struct mgmt_be_client_adapter *adapter,
if (txn_req->req_id == req_id)
break;
if (!txn_req) {
- MGMTD_TXN_ERR("GETTREE reply from %s for txn-id %" PRIu64
- " missing req_id %" PRIu64,
- adapter->name, txn_id, req_id);
+ __log_err("GETTREE reply from %s for txn-id %" PRIu64
+ " missing req_id %" PRIu64,
+ adapter->name, txn_id, req_id);
return -1;
}
@@ -2552,11 +2530,9 @@ int mgmt_txn_notify_tree_data_reply(struct mgmt_be_client_adapter *adapter,
LYD_PARSE_STRICT | LYD_PARSE_ONLY,
0 /*LYD_VALIDATE_OPERATIONAL*/, &tree);
if (err) {
- MGMTD_TXN_ERR("GETTREE reply from %s for txn-id %" PRIu64
- " req_id %" PRIu64
- " error parsing result of type %u",
- adapter->name, txn_id, req_id,
- data_msg->result_type);
+ __log_err("GETTREE reply from %s for txn-id %" PRIu64
+ " req_id %" PRIu64 " error parsing result of type %u",
+ adapter->name, txn_id, req_id, data_msg->result_type);
}
if (!err) {
/* TODO: we could merge ly_errs here if it's not binary */
@@ -2567,9 +2543,9 @@ int mgmt_txn_notify_tree_data_reply(struct mgmt_be_client_adapter *adapter,
err = lyd_merge_siblings(&get_tree->client_results,
tree, LYD_MERGE_DESTRUCT);
if (err) {
- MGMTD_TXN_ERR("GETTREE reply from %s for txn-id %" PRIu64
- " req_id %" PRIu64 " error merging result",
- adapter->name, txn_id, req_id);
+ __log_err("GETTREE reply from %s for txn-id %" PRIu64
+ " req_id %" PRIu64 " error merging result",
+ adapter->name, txn_id, req_id);
}
}
if (!get_tree->partial_error)
@@ -2642,12 +2618,12 @@ int mgmt_txn_rollback_trigger_cfg_apply(struct mgmt_ds_ctx *src_ds_ctx,
*/
txn = mgmt_txn_create_new(0, MGMTD_TXN_TYPE_CONFIG);
if (!txn) {
- MGMTD_TXN_ERR(
+ __log_err(
"Failed to create CONFIG Transaction for downloading CONFIGs");
return -1;
}
- MGMTD_TXN_DBG("Created rollback txn-id: %" PRIu64, txn->txn_id);
+ __dbg("Created rollback txn-id: %" PRIu64, txn->txn_id);
/*
* Set the changeset for transaction to commit and trigger the commit
diff --git a/mgmtd/mgmt_txn.h b/mgmtd/mgmt_txn.h
index 02b2baa95f..b7198326da 100644
--- a/mgmtd/mgmt_txn.h
+++ b/mgmtd/mgmt_txn.h
@@ -202,8 +202,10 @@ extern int mgmt_txn_send_get_req(uint64_t txn_id, uint64_t req_id,
* txn_id: Transaction identifier.
* req_id: FE client request identifier.
* clients: Bitmask of clients to send get-tree to.
+ * ds_id: datastore ID.
* result_type: LYD_FORMAT result format.
* flags: option flags for the request.
+ * wd_options: LYD_PRINT_WD_* flags for the result.
* simple_xpath: true if xpath is simple (only key predicates).
* xpath: The xpath to get the tree from.
*
@@ -211,8 +213,10 @@ extern int mgmt_txn_send_get_req(uint64_t txn_id, uint64_t req_id,
* 0 on success.
*/
extern int mgmt_txn_send_get_tree_oper(uint64_t txn_id, uint64_t req_id,
- uint64_t clients, LYD_FORMAT result_type,
- uint8_t flags, bool simple_xpath,
+ uint64_t clients,
+ Mgmtd__DatastoreId ds_id,
+ LYD_FORMAT result_type, uint8_t flags,
+ uint32_t wd_options, bool simple_xpath,
const char *xpath);
/*
diff --git a/mgmtd/mgmt_vty.c b/mgmtd/mgmt_vty.c
index 7135bc5547..12ea62ecef 100644
--- a/mgmtd/mgmt_vty.c
+++ b/mgmtd/mgmt_vty.c
@@ -258,14 +258,22 @@ DEFPY(show_mgmt_get_config, show_mgmt_get_config_cmd,
}
DEFPY(show_mgmt_get_data, show_mgmt_get_data_cmd,
- "show mgmt get-data WORD$path [with-config|only-config]$content [exact]$exact [json|xml]$fmt",
+ "show mgmt get-data WORD$path [datastore <candidate|running|operational>$ds] [with-config|only-config]$content [exact]$exact [with-defaults <trim|all-tag|all>$wd] [json|xml]$fmt",
SHOW_STR
MGMTD_STR
"Get a data from the operational datastore\n"
"XPath expression specifying the YANG data root\n"
+ "Specify datastore to get data from (operational by default)\n"
+ "Candidate datastore\n"
+ "Running datastore\n"
+ "Operational datastore\n"
"Include \"config true\" data\n"
"Get only \"config true\" data\n"
"Get exact node instead of the whole data tree\n"
+ "Configure 'with-defaults' mode per RFC 6243 (\"explicit\" mode by default)\n"
+ "Use \"trim\" mode\n"
+ "Use \"report-all-tagged\" mode\n"
+ "Use \"report-all\" mode\n"
"JSON output format\n"
"XML output format\n")
{
@@ -273,6 +281,8 @@ DEFPY(show_mgmt_get_data, show_mgmt_get_data_cmd,
int plen = strlen(path);
char *xpath = NULL;
uint8_t flags = content ? GET_DATA_FLAG_CONFIG : GET_DATA_FLAG_STATE;
+ uint8_t defaults = GET_DATA_DEFAULTS_EXPLICIT;
+ uint8_t datastore = MGMT_MSG_DATASTORE_OPERATIONAL;
if (content && content[0] == 'w')
flags |= GET_DATA_FLAG_STATE;
@@ -280,6 +290,22 @@ DEFPY(show_mgmt_get_data, show_mgmt_get_data_cmd,
if (exact)
flags |= GET_DATA_FLAG_EXACT;
+ if (wd) {
+ if (wd[0] == 't')
+ defaults = GET_DATA_DEFAULTS_TRIM;
+ else if (wd[3] == '-')
+ defaults = GET_DATA_DEFAULTS_ALL_ADD_TAG;
+ else
+ defaults = GET_DATA_DEFAULTS_ALL;
+ }
+
+ if (ds) {
+ if (ds[0] == 'c')
+ datastore = MGMT_MSG_DATASTORE_CANDIDATE;
+ else if (ds[0] == 'r')
+ datastore = MGMT_MSG_DATASTORE_RUNNING;
+ }
+
/* get rid of extraneous trailing slash-* or single '/' unless root */
if (plen > 2 && ((path[plen - 2] == '/' && path[plen - 1] == '*') ||
(path[plen - 2] != '/' && path[plen - 1] == '/'))) {
@@ -289,7 +315,8 @@ DEFPY(show_mgmt_get_data, show_mgmt_get_data_cmd,
path = xpath;
}
- vty_mgmt_send_get_data_req(vty, format, flags, path);
+ vty_mgmt_send_get_data_req(vty, datastore, format, flags, defaults,
+ path);
if (xpath)
XFREE(MTYPE_TMP, xpath);
diff --git a/mgmtd/subdir.am b/mgmtd/subdir.am
index a3955925ed..0af64dc0be 100644
--- a/mgmtd/subdir.am
+++ b/mgmtd/subdir.am
@@ -50,11 +50,20 @@ noinst_HEADERS += \
sbin_PROGRAMS += mgmtd/mgmtd
+if MGMTD_TESTC
+sbin_PROGRAMS += mgmtd/mgmtd_testc
+mgmtd_mgmtd_testc_SOURCES = mgmtd/mgmt_testc.c
+mgmtd_mgmtd_testc_LDADD = lib/libfrr.la
+endif
+
mgmtd_mgmtd_SOURCES = \
mgmtd/mgmt_main.c \
# end
nodist_mgmtd_mgmtd_SOURCES = \
yang/frr-zebra.yang.c \
+ yang/ietf/ietf-netconf-acm.yang.c \
+ yang/ietf/ietf-netconf.yang.c \
+ yang/ietf/ietf-netconf-with-defaults.yang.c \
# nothing
mgmtd_mgmtd_CFLAGS = $(AM_CFLAGS) -I ./
mgmtd_mgmtd_LDADD = mgmtd/libmgmtd.a lib/libfrr.la $(LIBCAP) $(LIBM) $(LIBYANG_LIBS) $(UST_LIBS)
diff --git a/nhrpd/nhrpd.h b/nhrpd/nhrpd.h
index 50653c784a..e389b7489d 100644
--- a/nhrpd/nhrpd.h
+++ b/nhrpd/nhrpd.h
@@ -16,7 +16,6 @@ DECLARE_MGROUP(NHRPD);
#define NHRPD_DEFAULT_HOLDTIME 7200
-#define NHRP_VTY_PORT 2610
#define NHRP_DEFAULT_CONFIG "nhrpd.conf"
extern struct event_loop *master;
diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c
index 6449d68453..17966e741e 100644
--- a/ospf6d/ospf6_main.c
+++ b/ospf6d/ospf6_main.c
@@ -46,9 +46,6 @@
* is excessive for just supporting a legacy compatibility file location
*/
-/* Default port values. */
-#define OSPF6_VTY_PORT 2606
-
/* ospf6d privileges */
zebra_capabilities_t _caps_p[] = {ZCAP_NET_RAW, ZCAP_BIND, ZCAP_SYS_ADMIN};
diff --git a/ospfd/ospf_api.h b/ospfd/ospf_api.h
index 6c8bed3d8f..6160a0f1fa 100644
--- a/ospfd/ospf_api.h
+++ b/ospfd/ospf_api.h
@@ -21,10 +21,6 @@
#define MTYPE_OSPF_API_MSG MTYPE_TMP
#define MTYPE_OSPF_API_FIFO MTYPE_TMP
-/* Default API server port to accept connection request from client-side. */
-/* This value could be overridden by "ospfapi" entry in "/etc/services". */
-#define OSPF_API_SYNC_PORT 2607
-
/* -----------------------------------------------------------
* Generic messages
* -----------------------------------------------------------
diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h
index 2ab7db119e..6051dff709 100644
--- a/ospfd/ospfd.h
+++ b/ospfd/ospfd.h
@@ -22,9 +22,6 @@
#define OSPF_VERSION 2
-/* VTY port number. */
-#define OSPF_VTY_PORT 2604
-
/* IP TTL for OSPF protocol. */
#define OSPF_IP_TTL 1
#define OSPF_VL_IP_TTL 100
diff --git a/pathd/path_main.c b/pathd/path_main.c
index c3409522e2..fe636c51be 100644
--- a/pathd/path_main.c
+++ b/pathd/path_main.c
@@ -95,8 +95,6 @@ static const struct frr_yang_module_info *pathd_yang_modules[] = {
&frr_pathd_info,
};
-#define PATH_VTY_PORT 2621
-
/* clang-format off */
FRR_DAEMON_INFO(pathd, PATH,
.vty_port = PATH_VTY_PORT,
diff --git a/pbrd/pbr_main.c b/pbrd/pbr_main.c
index 8cddf87a27..6695b537a8 100644
--- a/pbrd/pbr_main.c
+++ b/pbrd/pbr_main.c
@@ -103,8 +103,6 @@ struct frr_signal_t pbr_signals[] = {
},
};
-#define PBR_VTY_PORT 2615
-
static const struct frr_yang_module_info *const pbrd_yang_modules[] = {
&frr_filter_info,
&frr_interface_info,
diff --git a/pimd/pimd.h b/pimd/pimd.h
index 9ec84fc0a6..3d9318953b 100644
--- a/pimd/pimd.h
+++ b/pimd/pimd.h
@@ -19,9 +19,6 @@
#include "pim_memory.h"
#include "pim_assert.h"
-#define PIMD_VTY_PORT 2611
-#define PIM6D_VTY_PORT 2622
-
#define PIM_IP_PROTO_IGMP (2)
#define PIM_IP_PROTO_PIM (103)
#define PIM_IGMP_MIN_LEN (8)
diff --git a/redhat/frr.pam b/redhat/frr.pam
index 17a62f1999..a574c5e575 100644
--- a/redhat/frr.pam
+++ b/redhat/frr.pam
@@ -4,8 +4,8 @@
##### if running frr as root:
# Only allow root (and possibly wheel) to use this because enable access
# is unrestricted.
-auth sufficient pam_rootok.so
-account sufficient pam_rootok.so
+auth sufficient pam_permit.so
+account sufficient pam_permit.so
# Uncomment the following line to implicitly trust users in the "wheel" group.
#auth sufficient pam_wheel.so trust use_uid
diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in
index 37a2e17e8e..3371a3ed4d 100644
--- a/redhat/frr.spec.in
+++ b/redhat/frr.spec.in
@@ -16,6 +16,7 @@
%{!?with_cumulus: %global with_cumulus 0 }
%{!?with_eigrpd: %global with_eigrpd 1 }
%{!?with_fpm: %global with_fpm 1 }
+%{!?with_mgmtd_test_be_client: %global with_mgmtd_test_be_client 0 }
%{!?with_ldpd: %global with_ldpd 1 }
%{!?with_multipath: %global with_multipath 256 }
%{!?with_nhrpd: %global with_nhrpd 1 }
@@ -322,6 +323,9 @@ routing state through standard SNMP MIBs.
--localstatedir=%{_localstatedir} \
--disable-static \
--disable-werror \
+%if %{with_mgmtd_test_be_client}
+ --enable-mgmtd-test-be-client \
+%endif
%if %{with_multipath}
--enable-multipath=%{with_multipath} \
%endif
@@ -669,6 +673,9 @@ fi
%{_sbindir}/ripd
%{_sbindir}/bgpd
%{_sbindir}/mgmtd
+%if %{with_mgmtd_test_be_client}
+ %{_sbindir}/mgmtd_testc
+%endif
%exclude %{_sbindir}/ssd
%if %{with_watchfrr}
%{_sbindir}/watchfrr
diff --git a/ripd/ripd.h b/ripd/ripd.h
index b7e79332fe..08f7a2442d 100644
--- a/ripd/ripd.h
+++ b/ripd/ripd.h
@@ -51,7 +51,6 @@
/* RIP port number. */
#define RIP_PORT_DEFAULT 520
-#define RIP_VTY_PORT 2602
/* Default configuration file name. */
#define RIPD_DEFAULT_CONFIG "ripd.conf"
diff --git a/ripngd/ripngd.h b/ripngd/ripngd.h
index b4f7b4e52d..a316f2b4b5 100644
--- a/ripngd/ripngd.h
+++ b/ripngd/ripngd.h
@@ -16,7 +16,6 @@
/* RIPng version and port number. */
#define RIPNG_V1 1
#define RIPNG_PORT_DEFAULT 521
-#define RIPNG_VTY_PORT 2603
#define RIPNG_MAX_PACKET_SIZE 1500
#define RIPNG_PRIORITY_DEFAULT 0
diff --git a/sharpd/sharp_main.c b/sharpd/sharp_main.c
index 57948388b2..f4ce147978 100644
--- a/sharpd/sharp_main.c
+++ b/sharpd/sharp_main.c
@@ -120,8 +120,6 @@ struct frr_signal_t sharp_signals[] = {
},
};
-#define SHARP_VTY_PORT 2614
-
static const struct frr_yang_module_info *const sharpd_yang_modules[] = {
&frr_filter_info,
&frr_interface_info,
diff --git a/staticd/static_bfd.c b/staticd/static_bfd.c
index b0b2566150..c35751f397 100644
--- a/staticd/static_bfd.c
+++ b/staticd/static_bfd.c
@@ -263,14 +263,13 @@ static void static_bfd_show_path_json(struct vty *vty, struct json_object *jo,
static void static_bfd_show_json(struct vty *vty)
{
struct json_object *jo, *jo_path, *jo_afi_safi;
- struct vrf *vrf;
+ struct static_vrf *svrf;
jo = json_object_new_object();
jo_path = json_object_new_object();
json_object_object_add(jo, "path-list", jo_path);
- RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
- const struct static_vrf *svrf = vrf->info;
+ RB_FOREACH (svrf, svrf_name_head, &svrfs) {
struct route_table *rt;
jo_afi_safi = json_object_new_array();
@@ -346,7 +345,7 @@ static void static_bfd_show_path(struct vty *vty, struct route_table *rt)
void static_bfd_show(struct vty *vty, bool json)
{
- struct vrf *vrf;
+ struct static_vrf *svrf;
if (json) {
static_bfd_show_json(vty);
@@ -355,21 +354,20 @@ void static_bfd_show(struct vty *vty, bool json)
vty_out(vty, "Showing BFD monitored static routes:\n");
vty_out(vty, "\n Next hops:\n");
- RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
- const struct static_vrf *svrf = vrf->info;
+ RB_FOREACH (svrf, svrf_name_head, &svrfs) {
struct route_table *rt;
- vty_out(vty, " VRF %s IPv4 Unicast:\n", vrf->name);
+ vty_out(vty, " VRF %s IPv4 Unicast:\n", svrf->name);
rt = svrf->stable[AFI_IP][SAFI_UNICAST];
if (rt)
static_bfd_show_path(vty, rt);
- vty_out(vty, "\n VRF %s IPv4 Multicast:\n", vrf->name);
+ vty_out(vty, "\n VRF %s IPv4 Multicast:\n", svrf->name);
rt = svrf->stable[AFI_IP][SAFI_MULTICAST];
if (rt)
static_bfd_show_path(vty, rt);
- vty_out(vty, "\n VRF %s IPv6 Unicast:\n", vrf->name);
+ vty_out(vty, "\n VRF %s IPv6 Unicast:\n", svrf->name);
rt = svrf->stable[AFI_IP6][SAFI_UNICAST];
if (rt)
static_bfd_show_path(vty, rt);
diff --git a/staticd/static_main.c b/staticd/static_main.c
index 1953701fbb..9468a98b83 100644
--- a/staticd/static_main.c
+++ b/staticd/static_main.c
@@ -113,8 +113,6 @@ static const struct frr_yang_module_info *const staticd_yang_modules[] = {
&frr_staticd_info,
};
-#define STATIC_VTY_PORT 2616
-
/*
* NOTE: .flags == FRR_NO_SPLIT_CONFIG to avoid reading split config, mgmtd will
* do this for us now
@@ -170,8 +168,10 @@ int main(int argc, char **argv, char **envp)
hook_register(routing_conf_event,
routing_control_plane_protocols_name_validate);
-
- routing_control_plane_protocols_register_vrf_dependency();
+ hook_register(routing_create,
+ routing_control_plane_protocols_staticd_create);
+ hook_register(routing_destroy,
+ routing_control_plane_protocols_staticd_destroy);
/*
* We set FRR_NO_SPLIT_CONFIG flag to avoid reading our config, but we
diff --git a/staticd/static_nb.h b/staticd/static_nb.h
index f929997a78..be75d9d38c 100644
--- a/staticd/static_nb.h
+++ b/staticd/static_nb.h
@@ -13,6 +13,11 @@ extern "C" {
extern const struct frr_yang_module_info frr_staticd_info;
extern const struct frr_yang_module_info frr_staticd_cli_info;
+int routing_control_plane_protocols_staticd_create(
+ struct nb_cb_create_args *args);
+int routing_control_plane_protocols_staticd_destroy(
+ struct nb_cb_destroy_args *args);
+
/* Mandatory callbacks. */
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_create(
struct nb_cb_create_args *args);
diff --git a/staticd/static_nb_config.c b/staticd/static_nb_config.c
index 2fee908d5d..7de5f0474a 100644
--- a/staticd/static_nb_config.c
+++ b/staticd/static_nb_config.c
@@ -136,8 +136,7 @@ static bool static_nexthop_create(struct nb_cb_create_args *args)
switch (args->event) {
case NB_EV_VALIDATE:
ifname = yang_dnode_get_string(args->dnode, "interface");
- nh_type = yang_dnode_get_enum(args->dnode, "nh-type");
- if (ifname != NULL && nh_type != STATIC_BLACKHOLE) {
+ if (ifname != NULL) {
if (strcasecmp(ifname, "Null0") == 0
|| strcasecmp(ifname, "reject") == 0
|| strcasecmp(ifname, "blackhole") == 0) {
@@ -177,6 +176,9 @@ static bool static_nexthop_create(struct nb_cb_create_args *args)
nh_vrf = yang_dnode_get_string(args->dnode, "vrf");
pn = nb_running_get_entry(args->dnode, NULL, true);
+ if (strmatch(ifname, "(null)"))
+ ifname = "";
+
if (!static_add_nexthop_validate(nh_vrf, nh_type, &ipaddr))
flog_warn(
EC_LIB_NB_CB_CONFIG_VALIDATE,
@@ -465,33 +467,10 @@ static int static_nexthop_bh_type_modify(struct nb_cb_modify_args *args)
{
struct static_nexthop *nh;
enum static_nh_type nh_type;
- const char *nh_ifname;
- const char *nh_vrf;
switch (args->event) {
case NB_EV_VALIDATE:
nh_type = yang_dnode_get_enum(args->dnode, "../nh-type");
- nh_ifname = yang_dnode_get_string(args->dnode, "../interface");
- nh_vrf = yang_dnode_get_string(args->dnode, "../vrf");
- if (nh_ifname && nh_vrf) {
- struct vrf *vrf = vrf_lookup_by_name(nh_vrf);
-
- if (!vrf) {
- snprintf(args->errmsg, args->errmsg_len,
- "nexthop vrf %s not found", nh_vrf);
- return NB_ERR_VALIDATION;
- }
-
- struct interface *ifp = if_lookup_by_name(nh_ifname,
- vrf->vrf_id);
-
- if (ifp && (!strmatch(nh_ifname, "blackhole") ||
- !strmatch(nh_ifname, "reject"))) {
- snprintf(args->errmsg, args->errmsg_len,
- "nexthop interface name must be (reject, blackhole)");
- return NB_ERR_VALIDATION;
- }
- }
if (nh_type != STATIC_BLACKHOLE) {
snprintf(args->errmsg, args->errmsg_len,
"nexthop type is not the blackhole type");
@@ -561,6 +540,48 @@ int routing_control_plane_protocols_name_validate(
}
return NB_OK;
}
+
+/*
+ * XPath:
+ * /frr-routing:routing/control-plane-protocols/control-plane-protocol
+ */
+int routing_control_plane_protocols_staticd_create(struct nb_cb_create_args *args)
+{
+ struct static_vrf *svrf;
+ const char *vrf;
+
+ vrf = yang_dnode_get_string(args->dnode, "vrf");
+ svrf = static_vrf_alloc(vrf);
+ nb_running_set_entry(args->dnode, svrf);
+
+ return NB_OK;
+}
+
+int routing_control_plane_protocols_staticd_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ struct static_vrf *svrf;
+ struct route_table *stable;
+ struct route_node *rn;
+ afi_t afi;
+ safi_t safi;
+
+ svrf = nb_running_unset_entry(args->dnode);
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ stable = svrf->stable[afi][safi];
+ if (!stable)
+ continue;
+
+ for (rn = route_top(stable); rn; rn = route_next(rn))
+ static_del_route(rn);
+ }
+
+ static_vrf_free(svrf);
+
+ return NB_OK;
+}
+
/*
* XPath:
* /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-staticd:staticd/route-list
@@ -568,8 +589,7 @@ int routing_control_plane_protocols_name_validate(
int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_create(
struct nb_cb_create_args *args)
{
- struct vrf *vrf;
- struct static_vrf *s_vrf;
+ struct static_vrf *svrf;
struct route_node *rn;
const struct lyd_node *vrf_dnode;
struct prefix prefix;
@@ -598,15 +618,14 @@ int routing_control_plane_protocols_control_plane_protocol_staticd_route_list_cr
case NB_EV_APPLY:
vrf_dnode = yang_dnode_get_parent(args->dnode,
"control-plane-protocol");
- vrf = nb_running_get_entry(vrf_dnode, NULL, true);
- s_vrf = vrf->info;
+ svrf = nb_running_get_entry(vrf_dnode, NULL, true);
yang_dnode_get_prefix(&prefix, args->dnode, "prefix");
afi_safi = yang_dnode_get_string(args->dnode, "afi-safi");
yang_afi_safi_identity2value(afi_safi, &afi, &safi);
- rn = static_add_route(afi, safi, &prefix, NULL, s_vrf);
- if (vrf->vrf_id == VRF_UNKNOWN)
+ rn = static_add_route(afi, safi, &prefix, NULL, svrf);
+ if (!svrf->vrf || svrf->vrf->vrf_id == VRF_UNKNOWN)
snprintf(
args->errmsg, args->errmsg_len,
"Static Route to %s not installed currently because dependent config not fully available",
diff --git a/staticd/static_routes.c b/staticd/static_routes.c
index 1fbbf7e99d..db3fc32fd8 100644
--- a/staticd/static_routes.c
+++ b/staticd/static_routes.c
@@ -245,21 +245,20 @@ void static_del_path(struct static_path *pn)
XFREE(MTYPE_STATIC_PATH, pn);
}
-struct static_nexthop *static_add_nexthop(struct static_path *pn,
- enum static_nh_type type,
- struct ipaddr *ipaddr,
- const char *ifname,
- const char *nh_vrf, uint32_t color)
+struct static_nexthop *
+static_add_nexthop(struct static_path *pn, enum static_nh_type type,
+ struct ipaddr *ipaddr, const char *ifname,
+ const char *nh_vrfname, uint32_t color)
{
struct route_node *rn = pn->rn;
struct static_nexthop *nh;
- struct static_vrf *nh_svrf;
+ struct vrf *nh_vrf;
struct interface *ifp;
struct static_nexthop *cp;
route_lock_node(rn);
- nh_svrf = static_vrf_lookup_by_name(nh_vrf);
+ nh_vrf = vrf_lookup_by_name(nh_vrfname);
/* Make new static route structure. */
nh = XCALLOC(MTYPE_STATIC_NEXTHOP, sizeof(struct static_nexthop));
@@ -274,8 +273,8 @@ struct static_nexthop *static_add_nexthop(struct static_path *pn,
if (nh->type == STATIC_BLACKHOLE)
nh->bh_type = STATIC_BLACKHOLE_NULL;
- nh->nh_vrf_id = nh_svrf ? nh_svrf->vrf->vrf_id : VRF_UNKNOWN;
- strlcpy(nh->nh_vrfname, nh_vrf, sizeof(nh->nh_vrfname));
+ nh->nh_vrf_id = nh_vrf ? nh_vrf->vrf_id : VRF_UNKNOWN;
+ strlcpy(nh->nh_vrfname, nh_vrfname, sizeof(nh->nh_vrfname));
if (ifname)
strlcpy(nh->ifname, ifname, sizeof(nh->ifname));
@@ -437,14 +436,10 @@ static void static_ifindex_update_af(struct interface *ifp, bool up, afi_t afi,
struct route_node *rn;
struct static_nexthop *nh;
struct static_path *pn;
- struct vrf *vrf;
+ struct static_vrf *svrf;
struct static_route_info *si;
- RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
- struct static_vrf *svrf;
-
- svrf = vrf->info;
-
+ RB_FOREACH (svrf, svrf_name_head, &svrfs) {
stable = static_vrf_static_table(afi, safi, svrf);
if (!stable)
continue;
@@ -476,8 +471,8 @@ static void static_ifindex_update_af(struct interface *ifp, bool up, afi_t afi,
* afi -> The afi to look at
* safi -> the safi to look at
*/
-static void static_fixup_vrf(struct static_vrf *svrf,
- struct route_table *stable, afi_t afi, safi_t safi)
+static void static_fixup_vrf(struct vrf *vrf, struct route_table *stable,
+ afi_t afi, safi_t safi)
{
struct route_node *rn;
struct static_nexthop *nh;
@@ -491,13 +486,12 @@ static void static_fixup_vrf(struct static_vrf *svrf,
continue;
frr_each(static_path_list, &si->path_list, pn) {
frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
- if (strcmp(svrf->vrf->name, nh->nh_vrfname)
- != 0)
+ if (strcmp(vrf->name, nh->nh_vrfname) != 0)
continue;
- nh->nh_vrf_id = svrf->vrf->vrf_id;
+ nh->nh_vrf_id = vrf->vrf_id;
nh->nh_registered = false;
- if (nh->ifindex) {
+ if (nh->ifname[0]) {
ifp = if_lookup_by_name(nh->ifname,
nh->nh_vrf_id);
if (ifp)
@@ -521,9 +515,7 @@ static void static_fixup_vrf(struct static_vrf *svrf,
* afi -> the afi in question
* safi -> the safi in question
*/
-static void static_enable_vrf(struct static_vrf *svrf,
- struct route_table *stable, afi_t afi,
- safi_t safi)
+static void static_enable_vrf(struct route_table *stable, afi_t afi, safi_t safi)
{
struct route_node *rn;
struct static_nexthop *nh;
@@ -537,7 +529,9 @@ static void static_enable_vrf(struct static_vrf *svrf,
continue;
frr_each(static_path_list, &si->path_list, pn) {
frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
- if (nh->ifindex) {
+ if (nh->nh_vrf_id == VRF_UNKNOWN)
+ continue;
+ if (nh->ifname[0]) {
ifp = if_lookup_by_name(nh->ifname,
nh->nh_vrf_id);
if (ifp)
@@ -545,8 +539,7 @@ static void static_enable_vrf(struct static_vrf *svrf,
else
continue;
}
- if (nh->nh_vrf_id == VRF_UNKNOWN)
- continue;
+
static_install_path(pn);
}
}
@@ -560,27 +553,26 @@ static void static_enable_vrf(struct static_vrf *svrf,
*
* enable_svrf -> the vrf being enabled
*/
-void static_fixup_vrf_ids(struct static_vrf *enable_svrf)
+void static_fixup_vrf_ids(struct vrf *vrf)
{
struct route_table *stable;
- struct vrf *vrf;
+ struct static_vrf *svrf, *enable_svrf;
afi_t afi;
safi_t safi;
- RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
- struct static_vrf *svrf;
+ enable_svrf = vrf->info;
- svrf = vrf->info;
+ RB_FOREACH (svrf, svrf_name_head, &svrfs) {
/* Install any static routes configured for this VRF. */
FOREACH_AFI_SAFI (afi, safi) {
stable = svrf->stable[afi][safi];
if (!stable)
continue;
- static_fixup_vrf(enable_svrf, stable, afi, safi);
+ static_fixup_vrf(vrf, stable, afi, safi);
if (enable_svrf == svrf)
- static_enable_vrf(svrf, stable, afi, safi);
+ static_enable_vrf(stable, afi, safi);
}
}
}
@@ -595,8 +587,7 @@ void static_fixup_vrf_ids(struct static_vrf *enable_svrf)
* afi -> the afi in question
* safi -> the safi in question
*/
-static void static_cleanup_vrf(struct static_vrf *svrf,
- struct route_table *stable,
+static void static_cleanup_vrf(struct vrf *vrf, struct route_table *stable,
afi_t afi, safi_t safi)
{
struct route_node *rn;
@@ -610,11 +601,13 @@ static void static_cleanup_vrf(struct static_vrf *svrf,
continue;
frr_each(static_path_list, &si->path_list, pn) {
frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
- if (strcmp(svrf->vrf->name, nh->nh_vrfname)
- != 0)
+ if (strcmp(vrf->name, nh->nh_vrfname) != 0)
continue;
static_uninstall_path(pn);
+
+ nh->nh_vrf_id = VRF_UNKNOWN;
+ nh->ifindex = IFINDEX_INTERNAL;
}
}
}
@@ -642,6 +635,9 @@ static void static_disable_vrf(struct route_table *stable,
continue;
frr_each(static_path_list, &si->path_list, pn) {
frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
+ if (nh->nh_vrf_id == VRF_UNKNOWN)
+ continue;
+
static_uninstall_path(pn);
}
}
@@ -656,26 +652,23 @@ static void static_disable_vrf(struct route_table *stable,
*
* disable_svrf - The vrf being disabled
*/
-void static_cleanup_vrf_ids(struct static_vrf *disable_svrf)
+void static_cleanup_vrf_ids(struct vrf *vrf)
{
- struct vrf *vrf;
+ struct route_table *stable;
+ struct static_vrf *svrf, *disable_svrf;
afi_t afi;
safi_t safi;
- RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
- struct static_vrf *svrf;
-
- svrf = vrf->info;
+ disable_svrf = vrf->info;
+ RB_FOREACH (svrf, svrf_name_head, &svrfs) {
/* Uninstall any static routes configured for this VRF. */
FOREACH_AFI_SAFI (afi, safi) {
- struct route_table *stable;
-
stable = svrf->stable[afi][safi];
if (!stable)
continue;
- static_cleanup_vrf(disable_svrf, stable, afi, safi);
+ static_cleanup_vrf(vrf, stable, afi, safi);
if (disable_svrf == svrf)
static_disable_vrf(stable, afi, safi);
@@ -683,71 +676,6 @@ void static_cleanup_vrf_ids(struct static_vrf *disable_svrf)
}
}
-/*
- * This function enables static routes when an interface it relies
- * on in a different vrf is coming up.
- *
- * stable -> The stable we are looking at.
- * ifp -> interface coming up
- * afi -> the afi in question
- * safi -> the safi in question
- */
-static void static_fixup_intf_nh(struct route_table *stable,
- struct interface *ifp,
- afi_t afi, safi_t safi)
-{
- struct route_node *rn;
- struct static_nexthop *nh;
- struct static_path *pn;
- struct static_route_info *si;
-
- for (rn = route_top(stable); rn; rn = route_next(rn)) {
- si = static_route_info_from_rnode(rn);
- if (!si)
- continue;
- frr_each(static_path_list, &si->path_list, pn) {
- frr_each(static_nexthop_list, &pn->nexthop_list, nh) {
- if (nh->nh_vrf_id != ifp->vrf->vrf_id)
- continue;
-
- if (nh->ifindex != ifp->ifindex)
- continue;
-
- static_install_path(pn);
- }
- }
- }
-}
-
-/*
- * This function enables static routes that rely on an interface in
- * a different vrf when that interface comes up.
- */
-void static_install_intf_nh(struct interface *ifp)
-{
- struct route_table *stable;
- struct vrf *vrf;
- afi_t afi;
- safi_t safi;
-
- RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) {
- struct static_vrf *svrf = vrf->info;
-
- /* Not needed if same vrf since happens naturally */
- if (vrf->vrf_id == ifp->vrf->vrf_id)
- continue;
-
- /* Install any static routes configured for this interface. */
- FOREACH_AFI_SAFI (afi, safi) {
- stable = svrf->stable[afi][safi];
- if (!stable)
- continue;
-
- static_fixup_intf_nh(stable, ifp, afi, safi);
- }
- }
-}
-
/* called from if_{add,delete}_update, i.e. when ifindex becomes [in]valid */
void static_ifindex_update(struct interface *ifp, bool up)
{
diff --git a/staticd/static_routes.h b/staticd/static_routes.h
index 1231ead526..d88ed29364 100644
--- a/staticd/static_routes.h
+++ b/staticd/static_routes.h
@@ -199,7 +199,8 @@ extern uint32_t zebra_ecmp_count;
extern struct zebra_privs_t static_privs;
-void static_fixup_vrf_ids(struct static_vrf *svrf);
+extern void static_fixup_vrf_ids(struct vrf *vrf);
+extern void static_cleanup_vrf_ids(struct vrf *vrf);
extern struct static_nexthop *
static_add_nexthop(struct static_path *pn, enum static_nh_type type,
@@ -209,10 +210,6 @@ extern void static_install_nexthop(struct static_nexthop *nh);
extern void static_delete_nexthop(struct static_nexthop *nh);
-extern void static_cleanup_vrf_ids(struct static_vrf *disable_svrf);
-
-extern void static_install_intf_nh(struct interface *ifp);
-
extern void static_ifindex_update(struct interface *ifp, bool up);
extern void static_install_path(struct static_path *pn);
diff --git a/staticd/static_vrf.c b/staticd/static_vrf.c
index 7a0ff01d04..710827a9ff 100644
--- a/staticd/static_vrf.c
+++ b/staticd/static_vrf.c
@@ -18,16 +18,37 @@
DEFINE_MTYPE_STATIC(STATIC, STATIC_RTABLE_INFO, "Static Route Table Info");
-static struct static_vrf *static_vrf_alloc(void)
+static int svrf_name_compare(const struct static_vrf *a,
+ const struct static_vrf *b)
+{
+ return strcmp(a->name, b->name);
+}
+
+RB_GENERATE(svrf_name_head, static_vrf, entry, svrf_name_compare);
+
+struct svrf_name_head svrfs = RB_INITIALIZER(&svrfs);
+
+static struct static_vrf *static_vrf_lookup_by_name(const char *name)
+{
+ struct static_vrf svrf;
+
+ strlcpy(svrf.name, name, sizeof(svrf.name));
+ return RB_FIND(svrf_name_head, &svrfs, &svrf);
+}
+
+struct static_vrf *static_vrf_alloc(const char *name)
{
struct route_table *table;
struct static_vrf *svrf;
struct stable_info *info;
+ struct vrf *vrf;
safi_t safi;
afi_t afi;
svrf = XCALLOC(MTYPE_STATIC_RTABLE_INFO, sizeof(struct static_vrf));
+ strlcpy(svrf->name, name, sizeof(svrf->name));
+
for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) {
if (afi == AFI_IP6)
@@ -46,16 +67,56 @@ static struct static_vrf *static_vrf_alloc(void)
svrf->stable[afi][safi] = table;
}
}
+
+ RB_INSERT(svrf_name_head, &svrfs, svrf);
+
+ vrf = vrf_lookup_by_name(name);
+ if (vrf) {
+ svrf->vrf = vrf;
+ vrf->info = svrf;
+ }
+
return svrf;
}
+void static_vrf_free(struct static_vrf *svrf)
+{
+ struct route_table *table;
+ struct vrf *vrf;
+ safi_t safi;
+ afi_t afi;
+ void *info;
+
+ vrf = svrf->vrf;
+ if (vrf) {
+ vrf->info = NULL;
+ svrf->vrf = NULL;
+ }
+
+ RB_REMOVE(svrf_name_head, &svrfs, svrf);
+
+ for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
+ for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) {
+ table = svrf->stable[afi][safi];
+ info = route_table_get_info(table);
+ route_table_finish(table);
+ XFREE(MTYPE_STATIC_RTABLE_INFO, info);
+ svrf->stable[afi][safi] = NULL;
+ }
+ }
+
+ XFREE(MTYPE_STATIC_RTABLE_INFO, svrf);
+}
+
static int static_vrf_new(struct vrf *vrf)
{
struct static_vrf *svrf;
- svrf = static_vrf_alloc();
- vrf->info = svrf;
- svrf->vrf = vrf;
+ svrf = static_vrf_lookup_by_name(vrf->name);
+ if (svrf) {
+ vrf->info = svrf;
+ svrf->vrf = vrf;
+ }
return 0;
}
@@ -63,37 +124,27 @@ static int static_vrf_new(struct vrf *vrf)
static int static_vrf_enable(struct vrf *vrf)
{
static_zebra_vrf_register(vrf);
-
- static_fixup_vrf_ids(vrf->info);
-
+ static_fixup_vrf_ids(vrf);
return 0;
}
static int static_vrf_disable(struct vrf *vrf)
{
+ static_cleanup_vrf_ids(vrf);
static_zebra_vrf_unregister(vrf);
return 0;
}
static int static_vrf_delete(struct vrf *vrf)
{
- struct route_table *table;
struct static_vrf *svrf;
- safi_t safi;
- afi_t afi;
- void *info;
svrf = vrf->info;
- for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
- for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) {
- table = svrf->stable[afi][safi];
- info = route_table_get_info(table);
- route_table_finish(table);
- XFREE(MTYPE_STATIC_RTABLE_INFO, info);
- svrf->stable[afi][safi] = NULL;
- }
+ if (svrf) {
+ svrf->vrf = NULL;
+ vrf->info = NULL;
}
- XFREE(MTYPE_STATIC_RTABLE_INFO, svrf);
+
return 0;
}
@@ -110,20 +161,6 @@ struct route_table *static_vrf_static_table(afi_t afi, safi_t safi,
return svrf->stable[afi][safi];
}
-struct static_vrf *static_vrf_lookup_by_name(const char *name)
-{
- struct vrf *vrf;
-
- if (!name)
- name = VRF_DEFAULT_NAME;
-
- vrf = vrf_lookup_by_name(name);
- if (vrf)
- return ((struct static_vrf *)vrf->info);
-
- return NULL;
-}
-
void static_vrf_init(void)
{
vrf_init(static_vrf_new, static_vrf_enable, static_vrf_disable,
@@ -134,5 +171,10 @@ void static_vrf_init(void)
void static_vrf_terminate(void)
{
+ struct static_vrf *svrf, *svrf_next;
+
+ RB_FOREACH_SAFE (svrf, svrf_name_head, &svrfs, svrf_next)
+ static_vrf_free(svrf);
+
vrf_terminate();
}
diff --git a/staticd/static_vrf.h b/staticd/static_vrf.h
index 8f55775d3e..26ee28fd81 100644
--- a/staticd/static_vrf.h
+++ b/staticd/static_vrf.h
@@ -7,15 +7,27 @@
#ifndef __STATIC_VRF_H__
#define __STATIC_VRF_H__
+#include "openbsd-tree.h"
+
#ifdef __cplusplus
extern "C" {
#endif
struct static_vrf {
+ RB_ENTRY(static_vrf) entry;
+
+ char name[VRF_NAMSIZ + 1];
struct vrf *vrf;
struct route_table *stable[AFI_MAX][SAFI_MAX];
};
+RB_HEAD(svrf_name_head, static_vrf);
+RB_PROTOTYPE(svrf_name_head, static_vrf, entry, svrf_name_compare)
+
+extern struct svrf_name_head svrfs;
+
+struct static_vrf *static_vrf_alloc(const char *name);
+void static_vrf_free(struct static_vrf *svrf);
struct stable_info {
struct static_vrf *svrf;
@@ -25,8 +37,6 @@ struct stable_info {
#define GET_STABLE_VRF_ID(info) info->svrf->vrf->vrf_id
-struct static_vrf *static_vrf_lookup_by_name(const char *vrf_name);
-
void static_vrf_init(void);
struct route_table *static_vrf_static_table(afi_t afi, safi_t safi,
diff --git a/staticd/static_vty.c b/staticd/static_vty.c
index 05f23f54d1..a18028ed08 100644
--- a/staticd/static_vty.c
+++ b/staticd/static_vty.c
@@ -60,8 +60,6 @@ struct static_route_args {
bool bfd_multi_hop;
const char *bfd_source;
const char *bfd_profile;
-
- const char *input;
};
static int static_route_nb_run(struct vty *vty, struct static_route_args *args)
@@ -153,20 +151,9 @@ static int static_route_nb_run(struct vty *vty, struct static_route_args *args)
else
buf_gate_str = "";
- if (args->gateway == NULL && args->interface_name == NULL) {
+ if (args->gateway == NULL && args->interface_name == NULL)
type = STATIC_BLACKHOLE;
- /* If this is blackhole/reject flagged route, then
- * specify interface_name with the value of what was really
- * entered.
- * interface_name will be validated later in NB functions
- * to check if we don't create blackhole/reject routes that
- * match the real interface names.
- * E.g.: `ip route 10.0.0.1/32 bla` will create a blackhole
- * route despite the real interface named `bla` exists.
- */
- if (args->input)
- args->interface_name = args->input;
- } else if (args->gateway && args->interface_name) {
+ else if (args->gateway && args->interface_name) {
if (args->afi == AFI_IP)
type = STATIC_IPV4_GATEWAY_IFNAME;
else
@@ -553,8 +540,6 @@ DEFPY_YANG(ip_route_blackhole,
"Table to configure\n"
"The table number to configure\n")
{
- int idx_flag = 0;
-
struct static_route_args args = {
.delete = !!no,
.afi = AFI_IP,
@@ -569,9 +554,6 @@ DEFPY_YANG(ip_route_blackhole,
.vrf = vrf,
};
- if (flag && argv_find(argv, argc, flag, &idx_flag))
- args.input = argv[idx_flag]->arg;
-
return static_route_nb_run(vty, &args);
}
@@ -600,8 +582,6 @@ DEFPY_YANG(ip_route_blackhole_vrf,
"Table to configure\n"
"The table number to configure\n")
{
- int idx_flag = 0;
-
struct static_route_args args = {
.delete = !!no,
.afi = AFI_IP,
@@ -623,9 +603,6 @@ DEFPY_YANG(ip_route_blackhole_vrf,
*/
assert(args.prefix);
- if (flag && argv_find(argv, argc, flag, &idx_flag))
- args.input = argv[idx_flag]->arg;
-
return static_route_nb_run(vty, &args);
}
@@ -916,8 +893,6 @@ DEFPY_YANG(ipv6_route_blackhole,
"Table to configure\n"
"The table number to configure\n")
{
- int idx_flag = 0;
-
struct static_route_args args = {
.delete = !!no,
.afi = AFI_IP6,
@@ -932,9 +907,6 @@ DEFPY_YANG(ipv6_route_blackhole,
.vrf = vrf,
};
- if (flag && argv_find(argv, argc, flag, &idx_flag))
- args.input = argv[idx_flag]->arg;
-
return static_route_nb_run(vty, &args);
}
@@ -963,8 +935,6 @@ DEFPY_YANG(ipv6_route_blackhole_vrf,
"Table to configure\n"
"The table number to configure\n")
{
- int idx_flag = 0;
-
struct static_route_args args = {
.delete = !!no,
.afi = AFI_IP6,
@@ -986,9 +956,6 @@ DEFPY_YANG(ipv6_route_blackhole_vrf,
*/
assert(args.prefix);
- if (flag && argv_find(argv, argc, flag, &idx_flag))
- args.input = argv[idx_flag]->arg;
-
return static_route_nb_run(vty, &args);
}
diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c
index 68761c0084..697afa5156 100644
--- a/staticd/static_zebra.c
+++ b/staticd/static_zebra.c
@@ -111,8 +111,6 @@ static int interface_address_delete(ZAPI_CALLBACK_ARGS)
static int static_ifp_up(struct interface *ifp)
{
- /* Install any static reliant on this interface coming up */
- static_install_intf_nh(ifp);
static_ifindex_update(ifp, true);
return 0;
@@ -169,7 +167,7 @@ static void zebra_connected(struct zclient *zclient)
zebra_route_notify_send(ZEBRA_ROUTE_NOTIFY_REQUEST, zclient, true);
zclient_send_reg_requests(zclient, VRF_DEFAULT);
- static_fixup_vrf_ids(vrf_info_lookup(VRF_DEFAULT));
+ static_fixup_vrf_ids(vrf_lookup_by_id(VRF_DEFAULT));
}
/* API to check whether the configured nexthop address is
@@ -388,6 +386,9 @@ extern void static_zebra_route_add(struct static_path *pn, bool install)
struct zapi_route api;
uint32_t nh_num = 0;
+ if (!si->svrf->vrf)
+ return;
+
p = src_pp = NULL;
srcdest_rnode_prefixes(rn, &p, &src_pp);
diff --git a/tests/lib/test_grpc.cpp b/tests/lib/test_grpc.cpp
index 957ffdefaa..202313603d 100644
--- a/tests/lib/test_grpc.cpp
+++ b/tests/lib/test_grpc.cpp
@@ -119,8 +119,10 @@ static void static_startup(void)
hook_register(routing_conf_event,
routing_control_plane_protocols_name_validate);
-
- routing_control_plane_protocols_register_vrf_dependency();
+ hook_register(routing_create,
+ routing_control_plane_protocols_staticd_create);
+ hook_register(routing_destroy,
+ routing_control_plane_protocols_staticd_destroy);
// Add a route
vty = vty_new();
diff --git a/tests/topotests/bgp_aggregate_address_route_map/test_bgp_aggregate-address_route-map.py b/tests/topotests/bgp_aggregate_address_route_map/test_bgp_aggregate-address_route-map.py
index cec06920cb..eeac7146b1 100644
--- a/tests/topotests/bgp_aggregate_address_route_map/test_bgp_aggregate-address_route-map.py
+++ b/tests/topotests/bgp_aggregate_address_route_map/test_bgp_aggregate-address_route-map.py
@@ -74,7 +74,8 @@ def test_bgp_maximum_prefix_invalid():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- router = tgen.gears["r2"]
+ r1 = tgen.gears["r1"]
+ r2 = tgen.gears["r2"]
def _bgp_converge(router):
output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json"))
@@ -86,22 +87,30 @@ def test_bgp_maximum_prefix_invalid():
}
return topotest.json_cmp(output, expected)
- def _bgp_aggregate_address_has_metric(router):
+ def _bgp_aggregate_address_has_metric(router, metric):
output = json.loads(router.vtysh_cmd("show ip bgp 172.16.255.0/24 json"))
- expected = {"paths": [{"metric": 123}]}
+ expected = {"paths": [{"metric": metric}]}
return topotest.json_cmp(output, expected)
- test_func = functools.partial(_bgp_converge, router)
- success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
-
- assert result is None, 'Failed to see bgp convergence in "{}"'.format(router)
-
- test_func = functools.partial(_bgp_aggregate_address_has_metric, router)
- success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
-
- assert (
- result is None
- ), 'Failed to see applied metric for aggregated prefix in "{}"'.format(router)
+ test_func = functools.partial(_bgp_converge, r2)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+ assert result is None, "Failed to see bgp convergence in r2"
+
+ test_func = functools.partial(_bgp_aggregate_address_has_metric, r2, 123)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+ assert result is None, "Failed to see applied metric for aggregated prefix in r2"
+
+ r1.vtysh_cmd(
+ """
+ configure terminal
+ route-map aggr-rmap permit 10
+ set metric 666
+ """
+ )
+
+ test_func = functools.partial(_bgp_aggregate_address_has_metric, r2, 666)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+ assert result is None, "Failed to see applied metric for aggregated prefix in r2"
if __name__ == "__main__":
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py
index 23ab90794c..45c44ba5db 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/customize.py
@@ -165,6 +165,8 @@ def ltemplatePreRouterStartHook():
cmds = [
"ip link add {0}-cust4 type vrf table 30",
"ip link set dev {0}-cust4 up",
+ "ip link add {0}-cust5 type vrf table 40",
+ "ip link set dev {0}-cust5 up",
]
rtr = "r1"
for cmd in cmds:
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf
index b389eb1013..0d652dac07 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/bgpd.conf
@@ -64,5 +64,17 @@ router bgp 5227 vrf r1-cust4
import vpn
export vpn
exit-address-family
-!
-end
+
+router bgp 5227 vrf r1-cust5
+ bgp router-id 192.168.1.1
+
+ address-family ipv4 unicast
+ network 172.16.1.1/32
+
+ label vpn export 105
+ rd vpn export 10:15
+ rt vpn both 52:100
+
+ import vpn
+ export vpn
+ exit-address-family
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/zebra.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/zebra.conf
index 221bc7a839..9a5b0a605e 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/zebra.conf
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/zebra.conf
@@ -18,6 +18,10 @@ interface r1-eth4
ip address 192.168.1.1/24
no link-detect
+interface r1-cust5
+ ip address 172.16.1.1/32
+ no link-detect
+
ip forwarding
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py
index 3ab9b3f46e..28047f7b2d 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py
@@ -60,6 +60,7 @@ want_r1_cust1_routes = [
{"p": "6.0.1.0/24", "n": "99.0.0.1"},
{"p": "6.0.2.0/24", "n": "99.0.0.1"},
{"p": "172.16.0.0/24", "n": "0.0.0.0", "bp": True},
+ {"p": "172.16.1.1/32", "n": "0.0.0.0", "bp": True},
{"p": "99.0.0.1/32", "n": "192.168.1.2"},
]
bgpribRequireUnicastRoutes(
@@ -73,6 +74,13 @@ bgpribRequireUnicastRoutes(
"r1", "ipv4", "r1-cust4", "Customer 4 routes in r1 vrf", want_r1_cust4_routes
)
+want_r1_cust5_routes = [
+ {"p": "172.16.1.1/32", "n": "0.0.0.0", "bp": True},
+]
+bgpribRequireUnicastRoutes(
+ "r1", "ipv4", "r1-cust5", "Customer 5 routes in r1 vrf", want_r1_cust5_routes
+)
+
want_r3_cust1_routes = [
{"p": "5.1.0.0/24", "n": "99.0.0.2"},
{"p": "5.1.1.0/24", "n": "99.0.0.2"},
@@ -675,7 +683,7 @@ bgpribRequireUnicastRoutes(
luCommand(
"ce1",
'vtysh -c "show bgp ipv4 uni"',
- "13 routes and 13",
+ "14 routes and 14",
"wait",
"Local and remote routes",
10,
@@ -697,7 +705,7 @@ bgpribRequireUnicastRoutes(
luCommand(
"ce2",
'vtysh -c "show bgp ipv4 uni"',
- "13 routes and 16",
+ "14 routes and 17",
"wait",
"Local and remote routes",
10,
@@ -729,7 +737,7 @@ luCommand("r4", 'vtysh -c "show ip route vrf r4-cust2"')
luCommand(
"ce3",
'vtysh -c "show bgp ipv4 uni"',
- "13 routes and 14",
+ "14 routes and 15",
"wait",
"Local and remote routes",
10,
@@ -751,7 +759,7 @@ bgpribRequireUnicastRoutes(
luCommand(
"ce4",
'vtysh -c "show bgp vrf ce4-cust2 ipv4 uni"',
- "13 routes and 15",
+ "14 routes and 16",
"wait",
"Local and remote routes",
10,
diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_down.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_down.py
index 43a5245d0f..190879cc27 100644
--- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_down.py
+++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_down.py
@@ -49,7 +49,7 @@ if ret != False and found != None:
luCommand(
rtr,
'vtysh -c "show bgp ipv4 uni" | grep Display',
- " 13 route",
+ " 14 route",
"wait",
"BGP routes removed",
wait,
diff --git a/tests/topotests/lib/fe_client.py b/tests/topotests/lib/fe_client.py
new file mode 100755
index 0000000000..ec643bb0bf
--- /dev/null
+++ b/tests/topotests/lib/fe_client.py
@@ -0,0 +1,414 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 eval: (blacken-mode 1) -*-
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# November 27 2023, Christian Hopps <chopps@labn.net>
+#
+# Copyright (c) 2023, LabN Consulting, L.L.C.
+#
+# noqa: E501
+#
+import argparse
+import json
+import logging
+import os
+import socket
+import struct
+import sys
+import time
+from pathlib import Path
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+
+# This is painful but works if you have installed protobuf would be better if we
+# actually built and installed these but ... python packaging.
+try:
+ sys.path.append(os.path.dirname(CWD))
+ from munet.base import commander
+
+ commander.cmd_raises(f"protoc --python_out={CWD} -I {CWD}/../../../lib mgmt.proto")
+except Exception as error:
+ logging.error("can't create protobuf definition modules %s", error)
+ raise
+
+try:
+ sys.path[0:0] = "."
+ import mgmt_pb2
+except Exception as error:
+ logging.error("can't import proto definition modules %s", error)
+ raise
+
+CANDIDATE_DS = mgmt_pb2.DatastoreId.CANDIDATE_DS
+OPERATIONAL_DS = mgmt_pb2.DatastoreId.OPERATIONAL_DS
+RUNNING_DS = mgmt_pb2.DatastoreId.RUNNING_DS
+STARTUP_DS = mgmt_pb2.DatastoreId.STARTUP_DS
+
+# =====================
+# Native message values
+# =====================
+
+MGMT_MSG_MARKER_PROTOBUF = b"\000###"
+MGMT_MSG_MARKER_NATIVE = b"\001###"
+
+#
+# Native message formats
+#
+MSG_HDR_FMT = "=H2xIQQ"
+HDR_FIELD_CODE = 0
+HDR_FIELD_VSPLIT = 1
+HDR_FIELD_SESS_ID = 2
+HDR_FIELD_REQ_ID = 3
+
+MSG_ERROR_FMT = "=h6x"
+ERROR_FIELD_ERROR = 0
+
+# MSG_GET_TREE_FMT = "=B7x"
+# GET_TREE_FIELD_RESULT_TYPE = 0
+
+MSG_TREE_DATA_FMT = "=bBB5x"
+TREE_DATA_FIELD_PARTIAL_ERROR = 0
+TREE_DATA_FIELD_RESULT_TYPE = 1
+TREE_DATA_FIELD_MORE = 2
+
+MSG_GET_DATA_FMT = "=BB6x"
+GET_DATA_FIELD_RESULT_TYPE = 0
+GET_DATA_FIELD_FLAGS = 1
+GET_DATA_FLAG_STATE = 0x1
+GET_DATA_FLAG_CONFIG = 0x2
+GET_DATA_FLAG_EXACT = 0x4
+
+MSG_NOTIFY_FMT = "=B7x"
+NOTIFY_FIELD_RESULT_TYPE = 0
+
+#
+# Native message codes
+#
+MSG_CODE_ERROR = 0
+# MSG_CODE_GET_TREE = 1
+MSG_CODE_TREE_DATA = 2
+MSG_CODE_GET_DATA = 3
+MSG_CODE_NOTIFY = 4
+
+msg_native_formats = {
+ MSG_CODE_ERROR: MSG_ERROR_FMT,
+ # MSG_CODE_GET_TREE: MSG_GET_TREE_FMT,
+ MSG_CODE_TREE_DATA: MSG_TREE_DATA_FMT,
+ MSG_CODE_GET_DATA: MSG_GET_DATA_FMT,
+ MSG_CODE_NOTIFY: MSG_NOTIFY_FMT,
+}
+
+
+# Result formats
+MSG_FORMAT_XML = 1
+MSG_FORMAT_JSON = 2
+MSG_FORMAT_LYB = 3
+
+
+def cstr(mdata):
+ assert mdata[-1] == 0
+ return mdata[:-1]
+
+
+class FEClientError(Exception):
+ pass
+
+
+class PBMessageError(FEClientError):
+ def __init__(self, msg, errstr):
+ self.msg = msg
+ # self.sess_id = mhdr[HDR_FIELD_SESS_ID]
+ # self.req_id = mhdr[HDR_FIELD_REQ_ID]
+ self.error = -1
+ self.errstr = errstr
+ super().__init__(f"PBMessageError: {self.errstr}: {msg}")
+
+
+class NativeMessageError(FEClientError):
+ def __init__(self, mhdr, mfixed, mdata):
+ self.mhdr = mhdr
+ self.sess_id = mhdr[HDR_FIELD_SESS_ID]
+ self.req_id = mhdr[HDR_FIELD_REQ_ID]
+ self.error = mfixed[0]
+ self.errstr = cstr(mdata)
+ super().__init__(
+ "NativeMessageError: "
+ f"session {self.sess_id} reqid {self.req_id} "
+ f"error {self.error}: {self.errstr}"
+ )
+
+
+#
+# Low-level socket functions
+#
+
+
+def recv_wait(sock, size):
+ """Receive a fixed number of bytes from a stream socket."""
+ data = b""
+ while len(data) < size:
+ newdata = sock.recv(size - len(data))
+ if not newdata:
+ raise Exception("Socket closed")
+ data += newdata
+ return data
+
+
+def recv_msg(sock):
+ marker = recv_wait(sock, 4)
+ assert marker in (MGMT_MSG_MARKER_PROTOBUF, MGMT_MSG_MARKER_NATIVE)
+
+ msize = int.from_bytes(recv_wait(sock, 4), byteorder=sys.byteorder)
+ assert msize >= 8
+ mdata = recv_wait(sock, msize - 8) if msize > 8 else b""
+
+ return mdata, marker == MGMT_MSG_MARKER_NATIVE
+
+
+def send_msg(sock, marker, mdata):
+ """Send a mgmtd native message to a stream socket."""
+ msize = int.to_bytes(len(mdata) + 8, byteorder=sys.byteorder, length=4)
+ sock.send(marker)
+ sock.send(msize)
+ sock.send(mdata)
+
+
+class Session:
+ """A session to the mgmtd server."""
+
+ client_id = 1
+
+ def __init__(self, sock):
+ self.sock = sock
+ self.next_req_id = 1
+
+ req = mgmt_pb2.FeMessage()
+ req.register_req.client_name = "test-client"
+ self.send_pb_msg(req)
+ logging.debug("Sent FeRegisterReq: %s", req)
+
+ req = mgmt_pb2.FeMessage()
+ req.session_req.create = 1
+ req.session_req.client_conn_id = Session.client_id
+ Session.client_id += 1
+ self.send_pb_msg(req)
+ logging.debug("Sent FeSessionReq: %s", req)
+
+ reply = self.recv_pb_msg(mgmt_pb2.FeMessage())
+ logging.debug("Received FeSessionReply: %s", repr(reply))
+
+ assert reply.session_reply.success
+ self.sess_id = reply.session_reply.session_id
+
+ def close(self, clean=True):
+ if clean:
+ req = mgmt_pb2.FeMessage()
+ req.session_req.create = 0
+ req.session_req.sess_id = self.sess_id
+ self.send_pb_msg(req)
+ self.sock.close()
+ self.sock = None
+
+ def get_next_req_id(self):
+ req_id = self.next_req_id
+ self.next_req_id += 1
+ return req_id
+
+ # --------------------------
+ # Protobuf message functions
+ # --------------------------
+
+ def recv_pb_msg(self, msg):
+ """Receive a protobuf message."""
+ mdata, native = recv_msg(self.sock)
+ assert not native
+
+ msg.ParseFromString(mdata)
+
+ req = getattr(msg, msg.WhichOneof("message"))
+ if req.HasField("success"):
+ if not req.success:
+ raise PBMessageError(msg, req.error_if_any)
+
+ return msg
+
+ def send_pb_msg(self, msg):
+ """Send a protobuf message."""
+ mdata = msg.SerializeToString()
+ return send_msg(self.sock, MGMT_MSG_MARKER_PROTOBUF, mdata)
+
+ # ------------------------
+ # Native message functions
+ # ------------------------
+
+ def recv_native_msg(self):
+ """Send a native message."""
+ mdata, native = recv_msg(self.sock)
+ assert native
+
+ hlen = struct.calcsize(MSG_HDR_FMT)
+ hdata = mdata[:hlen]
+ mhdr = struct.unpack(MSG_HDR_FMT, hdata)
+ code = mhdr[0]
+
+ if code not in msg_native_formats:
+ raise Exception(f"Unknown native msg code {code} rcvd")
+
+ mfmt = msg_native_formats[code]
+ flen = struct.calcsize(mfmt)
+ fdata = mdata[hlen : hlen + flen]
+ mfixed = struct.unpack(mfmt, fdata)
+ mdata = mdata[hlen + flen :]
+
+ if code == MSG_ERROR_FMT:
+ raise NativeMessageError(mhdr, mfixed, mdata)
+
+ return mhdr, mfixed, mdata
+
+ def send_native_msg(self, mdata):
+ """Send a native message."""
+ return send_msg(self.sock, MGMT_MSG_MARKER_NATIVE, mdata)
+
+ def get_native_msg_header(self, msg_code):
+ req_id = self.get_next_req_id()
+ hdata = struct.pack(MSG_HDR_FMT, msg_code, 0, self.sess_id, req_id)
+ return hdata, req_id
+
+ # -----------------------
+ # Front-end API Fountains
+ # -----------------------
+
+ def lock(self, lock=True, ds_id=mgmt_pb2.CANDIDATE_DS):
+ req = mgmt_pb2.FeMessage()
+ req.lockds_req.session_id = self.sess_id
+ req.lockds_req.req_id = self.get_next_req_id()
+ req.lockds_req.ds_id = ds_id
+ req.lockds_req.lock = lock
+ self.send_pb_msg(req)
+ logging.debug("Sent LockDsReq: %s", req)
+
+ reply = self.recv_pb_msg(mgmt_pb2.FeMessage())
+ logging.debug("Received Reply: %s", repr(reply))
+ assert reply.lockds_reply.success
+
+ def get_data(self, query, data=True, config=False):
+ # Create the message
+ mdata, req_id = self.get_native_msg_header(MSG_CODE_GET_DATA)
+ flags = GET_DATA_FLAG_STATE if data else 0
+ flags |= GET_DATA_FLAG_CONFIG if config else 0
+ mdata += struct.pack(MSG_GET_DATA_FMT, MSG_FORMAT_JSON, flags)
+ mdata += query.encode("utf-8") + b"\x00"
+
+ self.send_native_msg(mdata)
+ logging.debug("Sent GET-TREE")
+
+ mhdr, mfixed, mdata = self.recv_native_msg()
+ assert mdata[-1] == 0
+ result = mdata[:-1].decode("utf-8")
+
+ logging.debug("Received GET: %s: %s", mfixed, mdata)
+ return result
+
+ # def subscribe(self, notif_xpath):
+ # # Create the message
+ # mdata, req_id = self.get_native_msg_header(MSG_CODE_SUBSCRIBE)
+ # mdata += struct.pack(MSG_SUBSCRIBE_FMT, MSG_FORMAT_JSON)
+ # mdata += notif_xpath.encode("utf-8") + b"\x00"
+
+ # self.send_native_msg(mdata)
+ # logging.debug("Sent SUBSCRIBE")
+
+ def recv_notify(self, xpaths=None):
+ while True:
+ logging.debug("Waiting for Notify Message")
+ mhdr, mfixed, mdata = self.recv_native_msg()
+ assert mdata[-1] == 0
+ result = mdata[:-1].decode("utf-8")
+ if mhdr[HDR_FIELD_CODE] == MSG_CODE_NOTIFY:
+ logging.debug("Received Notify Message: %s: %s", mfixed, mdata)
+ else:
+ raise Exception(f"Received NON-NOTIFY Message: {mfixed}: {mdata}")
+ if not xpaths:
+ return result
+ js = json.loads(result)
+ key = [x for x in js.keys()][0]
+ for xpath in xpaths:
+ if key.startswith(xpath):
+ return result
+ logging.debug("'%s' didn't match xpath filters", key)
+
+
+def __parse_args():
+ MPATH = "/var/run/frr/mgmtd_fe.sock"
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "-l", "--listen", nargs="*", metavar="XPATH", help="xpath[s] to listen for"
+ )
+ parser.add_argument(
+ "--notify-count",
+ type=int,
+ default=1,
+ help="Number of notifications to listen for 0 for infinite",
+ )
+ parser.add_argument(
+ "-b", "--both", action="store_true", help="return both config and data"
+ )
+ parser.add_argument(
+ "-c", "--config-only", action="store_true", help="return config only"
+ )
+ parser.add_argument(
+ "-q", "--query", nargs="+", metavar="XPATH", help="xpath[s] to query"
+ )
+ parser.add_argument("-s", "--server", default=MPATH, help="path to server socket")
+ parser.add_argument("-v", "--verbose", action="store_true", help="Be verbose")
+ args = parser.parse_args()
+
+ level = logging.DEBUG if args.verbose else logging.INFO
+ logging.basicConfig(level=level, format="%(asctime)s %(levelname)s: %(message)s")
+
+ return args
+
+
+def __server_connect(spath):
+ sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ logging.debug("Connecting to server on %s", spath)
+ while ec := sock.connect_ex(str(spath)):
+ logging.warn("retry server connection in .5s (%s)", os.strerror(ec))
+ time.sleep(0.5)
+ logging.info("Connected to server on %s", spath)
+ return sock
+
+
+def __main():
+ args = __parse_args()
+ sock = __server_connect(Path(args.server))
+ sess = Session(sock)
+
+ if args.query:
+ # Performa an xpath query
+ # query = "/frr-interface:lib/interface/state/mtu"
+ for query in args.query:
+ logging.info("Sending query: %s", query)
+ result = sess.get_data(
+ query, data=not args.config_only, config=(args.both or args.config_only)
+ )
+ print(result)
+
+ if args.listen is not None:
+ i = args.notify_count
+ while i > 0 or args.notify_count == 0:
+ notif = sess.recv_notify(args.listen)
+ print(notif)
+ i -= 1
+
+
+def main():
+ try:
+ __main()
+ except KeyboardInterrupt:
+ logging.info("Exiting")
+ except Exception as error:
+ logging.error("Unexpected error exiting: %s", error, exc_info=True)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tests/topotests/mgmt_fe_client/fe_client.py b/tests/topotests/mgmt_fe_client/fe_client.py
deleted file mode 100644
index 04b4184e5b..0000000000
--- a/tests/topotests/mgmt_fe_client/fe_client.py
+++ /dev/null
@@ -1,103 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 eval: (blacken-mode 1) -*-
-# SPDX-License-Identifier: GPL-2.0-or-later
-#
-# November 27 2023, Christian Hopps <chopps@labn.net>
-#
-# Copyright (c) 2023, LabN Consulting, L.L.C.
-#
-# noqa: E501
-#
-import argparse
-import errno
-import logging
-import os
-import socket
-import sys
-import time
-from pathlib import Path
-
-import mgmt_pb2
-
-MGMT_MSG_MARKER_PROTOBUF = b"\000###"
-MGMT_MSG_MARKER_NATIVE = b"\001###"
-
-
-def __parse_args():
- MPATH = "/var/run/frr/mgmtd_fe.sock"
- parser = argparse.ArgumentParser()
- parser.add_argument("--verbose", action="store_true", help="Be verbose")
- parser.add_argument("--server", default=MPATH, help="path to server socket")
- args = parser.parse_args()
-
- level = logging.DEBUG if args.verbose else logging.INFO
- logging.basicConfig(level=level, format="%(asctime)s %(levelname)s: %(message)s")
-
- return args
-
-
-def __server_connect(spath):
- sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
- logging.debug("Connecting to server on %s", spath)
- while ec := sock.connect_ex(str(spath)):
- logging.warn("retry server connection in .5s (%s)", os.strerror(ec))
- time.sleep(0.5)
- logging.info("Connected to server on %s", spath)
- return sock
-
-
-def mgmt_pb_recv_msg(sock, msg):
- """Receive a mgmtd protobuf message from a stream socket."""
- marker = sock.recv(4)
- assert marker in (MGMT_MSG_MARKER_PROTOBUF, MGMT_MSG_MARKER_NATIVE)
-
- msize = int.from_bytes(sock.recv(4), byteorder="big")
- mdata = sock.recv(msize)
-
- msg.ParseFromString(mdata)
- return msg
-
-
-def mgmt_pb_send_msg(sock, msg):
- """Send a mgmtd protobuf message from a stream socket."""
- marker = MGMT_MSG_MARKER_PROTOBUF
- mdata = msg.SerializeToString()
- msize = int.to_bytes(len(mdata), byteorder="big", length=4)
- sock.send(marker)
- sock.send(msize)
- sock.send(mdata)
-
-
-def create_session(sock):
- req = mgmt_pb2.FeRegisterReq()
- req.client_name = "test-client"
- mgmt_pb_send_msg(sock, req)
- logging.debug("Sent FeRegisterReq: %s", req)
-
- req = mgmt_pb2.FeSessionReq()
- req.create = 1
- req.client_conn_id = 1
- mgmt_pb_send_msg(sock, req)
- logging.debug("Sent FeSessionReq: %s", req)
-
- reply = mgmt_pb_recv_msg(sock, mgmt_pb2.FeSessionReply())
- logging.debug("Received FeSessionReply: %s", reply)
-
-
-def __main():
- args = __parse_args()
- sock = __server_connect(Path(args.server))
- create_session(sock)
-
-
-def main():
- try:
- __main()
- except KeyboardInterrupt:
- logging.info("Exiting")
- except Exception as error:
- logging.error("Unexpected error exiting: %s", error, exc_info=True)
-
-
-if __name__ == "__main__":
- main()
diff --git a/tests/topotests/mgmt_fe_client/test_client.py b/tests/topotests/mgmt_fe_client/test_client.py
index 8383e23bb6..b5a74c60ac 100644
--- a/tests/topotests/mgmt_fe_client/test_client.py
+++ b/tests/topotests/mgmt_fe_client/test_client.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
# -*- coding: utf-8 eval: (blacken-mode 1) -*-
# SPDX-License-Identifier: ISC
#
diff --git a/tests/topotests/mgmt_notif/oper.py b/tests/topotests/mgmt_notif/oper.py
new file mode 120000
index 0000000000..924439251a
--- /dev/null
+++ b/tests/topotests/mgmt_notif/oper.py
@@ -0,0 +1 @@
+../mgmt_oper/oper.py \ No newline at end of file
diff --git a/tests/topotests/mgmt_notif/r1/frr.conf b/tests/topotests/mgmt_notif/r1/frr.conf
new file mode 100644
index 0000000000..47e73956cf
--- /dev/null
+++ b/tests/topotests/mgmt_notif/r1/frr.conf
@@ -0,0 +1,27 @@
+log timestamp precision 6
+log file frr.log
+
+no debug memstats-at-exit
+
+debug northbound notifications
+debug northbound libyang
+debug northbound events
+debug northbound callbacks
+
+debug mgmt backend datastore frontend transaction
+debug mgmt client frontend
+debug mgmt client backend
+
+ip route 11.11.11.11/32 lo
+
+interface r1-eth0
+ ip address 1.1.1.1/24
+ ip rip authentication string foo
+ ip rip authentication mode text
+exit
+
+router rip
+ network 1.1.1.0/24
+ timers basic 5 15 10
+ redistribute static
+exit
diff --git a/tests/topotests/mgmt_notif/r2/frr.conf b/tests/topotests/mgmt_notif/r2/frr.conf
new file mode 100644
index 0000000000..cd052011e0
--- /dev/null
+++ b/tests/topotests/mgmt_notif/r2/frr.conf
@@ -0,0 +1,27 @@
+log timestamp precision 6
+log file frr.log
+
+no debug memstats-at-exit
+
+debug northbound notifications
+debug northbound libyang
+debug northbound events
+debug northbound callbacks
+
+debug mgmt backend datastore frontend transaction
+debug mgmt client frontend
+debug mgmt client backend
+
+ip route 22.22.22.22/32 lo
+
+interface r2-eth0
+ ip address 1.1.1.2/24
+ ip rip authentication string bar
+ ip rip authentication mode text
+exit
+
+router rip
+ network 1.1.1.0/24
+ timers basic 5 15 10
+ redistribute static
+exit \ No newline at end of file
diff --git a/tests/topotests/mgmt_notif/test_notif.py b/tests/topotests/mgmt_notif/test_notif.py
new file mode 100644
index 0000000000..2f923e398c
--- /dev/null
+++ b/tests/topotests/mgmt_notif/test_notif.py
@@ -0,0 +1,102 @@
+# -*- coding: utf-8 eval: (blacken-mode 1) -*-
+# SPDX-License-Identifier: ISC
+#
+# January 23 2024, Christian Hopps <chopps@labn.net>
+#
+# Copyright (c) 2024, LabN Consulting, L.L.C.
+#
+
+"""
+Test YANG Notifications
+"""
+import json
+import logging
+import os
+
+import pytest
+from lib.topogen import Topogen
+from lib.topotest import json_cmp
+from oper import check_kernel_32
+
+pytestmark = [pytest.mark.ripd, pytest.mark.staticd, pytest.mark.mgmtd]
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+
+
+@pytest.fixture(scope="module")
+def tgen(request):
+ "Setup/Teardown the environment and provide tgen argument to tests"
+
+ topodef = {
+ "s1": ("r1", "r2"),
+ }
+
+ tgen = Topogen(topodef, request.module.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+ for rname, router in router_list.items():
+ router.load_frr_config("frr.conf")
+
+ tgen.start_router()
+ yield tgen
+ tgen.stop_topology()
+
+
+def test_frontend_notification(tgen):
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"].net
+
+ check_kernel_32(r1, "11.11.11.11", 1, "")
+
+ fe_client_path = CWD + "/../lib/fe_client.py"
+ rc, _, _ = r1.cmd_status(fe_client_path + " --help")
+
+ if rc:
+ pytest.skip("No protoc or present cannot run test")
+
+ # The first notifications is a frr-ripd:authentication-type-failure
+ # So we filter to avoid that, all the rest are frr-ripd:authentication-failure
+ # making our test deterministic
+ output = r1.cmd_raises(
+ fe_client_path + " --listen frr-ripd:authentication-failure"
+ )
+ jsout = json.loads(output)
+
+ expected = {"frr-ripd:authentication-failure": {"interface-name": "r1-eth0"}}
+ result = json_cmp(jsout, expected)
+ assert result is None
+
+ output = r1.cmd_raises(fe_client_path + " --listen")
+ jsout = json.loads(output)
+
+ expected = {"frr-ripd:authentication-failure": {"interface-name": "r1-eth0"}}
+ result = json_cmp(jsout, expected)
+ assert result is None
+
+
+def test_backend_notification(tgen):
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"].net
+
+ check_kernel_32(r1, "11.11.11.11", 1, "")
+
+ be_client_path = "/usr/lib/frr/mgmtd_testc"
+ rc, _, _ = r1.cmd_status(be_client_path + " --help")
+
+ if rc:
+ pytest.skip("No mgmtd_testc")
+
+ output = r1.cmd_raises(
+ be_client_path + " --timeout 20 --log file:mgmt_testc.log --listen frr-ripd"
+ )
+
+ jsout = json.loads(output)
+
+ expected = {"frr-ripd:authentication-failure": {"interface-name": "r1-eth0"}}
+ result = json_cmp(jsout, expected)
+ assert result is None
diff --git a/tests/topotests/mgmt_oper/r1/frr-simple.conf b/tests/topotests/mgmt_oper/r1/frr-simple.conf
index d262afe359..73df6b97b2 100644
--- a/tests/topotests/mgmt_oper/r1/frr-simple.conf
+++ b/tests/topotests/mgmt_oper/r1/frr-simple.conf
@@ -15,6 +15,7 @@ debug mgmt client backend
interface r1-eth0
ip address 1.1.1.1/24
description r1-eth0-desc
+ evpn mh es-df-pref 32767
exit
interface r1-eth1 vrf red
diff --git a/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-only-config.json b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-only-config.json
index 9289759274..e48002e672 100644
--- a/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-only-config.json
+++ b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-only-config.json
@@ -10,7 +10,10 @@
"ip": "1.1.1.1",
"prefix-length": 24
}
- ]
+ ],
+ "evpn-mh": {
+ "df-preference": 32767
+ }
}
}
]
diff --git a/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-all-tag.json b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-all-tag.json
new file mode 100644
index 0000000000..caee164468
--- /dev/null
+++ b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-all-tag.json
@@ -0,0 +1,13 @@
+{
+ "frr-zebra:evpn-mh": {
+ "df-preference": 32767,
+ "bypass": false,
+ "@bypass": {
+ "ietf-netconf-with-defaults:default": true
+ },
+ "uplink": false,
+ "@uplink": {
+ "ietf-netconf-with-defaults:default": true
+ }
+ }
+}
diff --git a/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-all.json b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-all.json
new file mode 100644
index 0000000000..07ba53b8bc
--- /dev/null
+++ b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-all.json
@@ -0,0 +1,7 @@
+{
+ "frr-zebra:evpn-mh": {
+ "df-preference": 32767,
+ "bypass": false,
+ "uplink": false
+ }
+}
diff --git a/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-explicit.json b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-explicit.json
new file mode 100644
index 0000000000..1779d1cd4e
--- /dev/null
+++ b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-explicit.json
@@ -0,0 +1,5 @@
+{
+ "frr-zebra:evpn-mh": {
+ "df-preference": 32767
+ }
+}
diff --git a/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-trim.json b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-trim.json
new file mode 100644
index 0000000000..efd7e8c684
--- /dev/null
+++ b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-wd-trim.json
@@ -0,0 +1,3 @@
+{
+ "frr-zebra:evpn-mh": {}
+}
diff --git a/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-with-config.json b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-with-config.json
index ef9e005619..84ad82c058 100644
--- a/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-with-config.json
+++ b/tests/topotests/mgmt_oper/simple-results/result-intf-eth0-with-config.json
@@ -20,6 +20,9 @@
"prefix-length": 24
}
],
+ "evpn-mh": {
+ "df-preference": 32767
+ },
"state": {
"up-count": 0,
"down-count": 0
diff --git a/tests/topotests/mgmt_oper/test_simple.py b/tests/topotests/mgmt_oper/test_simple.py
index a52d125ecf..3b115f6238 100644
--- a/tests/topotests/mgmt_oper/test_simple.py
+++ b/tests/topotests/mgmt_oper/test_simple.py
@@ -146,6 +146,27 @@ def test_oper_simple(tgen):
'/frr-interface:lib/interface[name="r1-eth0"]/state/mtu',
"simple-results/result-intf-state-mtu.json",
),
+ # with-defaults
+ (
+ '/frr-interface:lib/interface[name="r1-eth0"]/frr-zebra:zebra/evpn-mh',
+ "simple-results/result-intf-eth0-wd-explicit.json",
+ "with-config exact",
+ ),
+ (
+ '/frr-interface:lib/interface[name="r1-eth0"]/frr-zebra:zebra/evpn-mh',
+ "simple-results/result-intf-eth0-wd-trim.json",
+ "with-config exact with-defaults trim",
+ ),
+ (
+ '/frr-interface:lib/interface[name="r1-eth0"]/frr-zebra:zebra/evpn-mh',
+ "simple-results/result-intf-eth0-wd-all.json",
+ "with-config exact with-defaults all",
+ ),
+ (
+ '/frr-interface:lib/interface[name="r1-eth0"]/frr-zebra:zebra/evpn-mh',
+ "simple-results/result-intf-eth0-wd-all-tag.json",
+ "with-config exact with-defaults all-tag",
+ ),
]
r1 = tgen.gears["r1"].net
diff --git a/tools/gen_northbound_callbacks.c b/tools/gen_northbound_callbacks.c
index 6188559010..a879811363 100644
--- a/tools/gen_northbound_callbacks.c
+++ b/tools/gen_northbound_callbacks.c
@@ -26,18 +26,21 @@ static void __attribute__((noreturn)) usage(int status)
static struct nb_callback_info {
int operation;
bool optional;
+ bool need_config_write;
char return_type[32];
char return_value[32];
char arguments[128];
} nb_callbacks[] = {
{
.operation = NB_CB_CREATE,
+ .need_config_write = true,
.return_type = "int ",
.return_value = "NB_OK",
.arguments = "struct nb_cb_create_args *args",
},
{
.operation = NB_CB_MODIFY,
+ .need_config_write = true,
.return_type = "int ",
.return_value = "NB_OK",
.arguments = "struct nb_cb_modify_args *args",
@@ -97,6 +100,16 @@ static struct nb_callback_info {
},
};
+/*
+ * Special-purpose info block for the cli-config-write callback. This
+ * is different enough from the config-oriented callbacks that it doesn't
+ * really fit in the array above.
+ */
+static struct nb_callback_info nb_config_write = {
+ .return_type = "void ",
+ .arguments = "struct vty *vty, const struct lyd_node *dnode, bool show_defaults",
+};
+
static void replace_hyphens_by_underscores(char *str)
{
char *p;
@@ -135,14 +148,53 @@ static void generate_callback_name(const struct lysc_node *snode,
replace_hyphens_by_underscores(buffer);
}
+static void generate_config_write_cb_name(const struct lysc_node *snode,
+ char *buffer, size_t size)
+{
+ struct list *snodes;
+ struct listnode *ln;
+
+ buffer[0] = '\0';
+
+ snodes = list_new();
+ for (; snode; snode = snode->parent) {
+ /* Skip schema-only snodes. */
+ if (CHECK_FLAG(snode->nodetype, LYS_USES | LYS_CHOICE | LYS_CASE
+ | LYS_INPUT
+ | LYS_OUTPUT))
+ continue;
+
+ listnode_add_head(snodes, (void *)snode);
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(snodes, ln, snode)) {
+ strlcat(buffer, snode->name, size);
+ strlcat(buffer, "_", size);
+ }
+
+ strlcat(buffer, "cli_write", size);
+
+ list_delete(&snodes);
+
+ replace_hyphens_by_underscores(buffer);
+}
+
static void generate_prototype(const struct nb_callback_info *ncinfo,
const char *cb_name)
{
printf("%s%s(%s);\n", ncinfo->return_type, cb_name, ncinfo->arguments);
}
+static void generate_config_write_prototype(const struct nb_callback_info *ncinfo,
+ const char *cb_name)
+{
+ printf("%s%s(%s);\n", ncinfo->return_type, cb_name, ncinfo->arguments);
+}
+
static int generate_prototypes(const struct lysc_node *snode, void *arg)
{
+ bool need_config_write = true;
+
switch (snode->nodetype) {
case LYS_CONTAINER:
case LYS_LEAF:
@@ -166,6 +218,15 @@ static int generate_prototypes(const struct lysc_node *snode, void *arg)
generate_callback_name(snode, cb->operation, cb_name,
sizeof(cb_name));
generate_prototype(cb, cb_name);
+
+ if (cb->need_config_write && need_config_write) {
+ generate_config_write_cb_name(snode, cb_name,
+ sizeof(cb_name));
+ generate_config_write_prototype(&nb_config_write,
+ cb_name);
+
+ need_config_write = false;
+ }
}
return YANG_ITER_CONTINUE;
@@ -201,9 +262,22 @@ static void generate_callback(const struct nb_callback_info *ncinfo,
printf("\treturn %s;\n}\n\n", ncinfo->return_value);
}
+static void generate_config_write_callback(const struct nb_callback_info *ncinfo,
+ const char *cb_name)
+{
+ printf("%s%s%s(%s)\n{\n", static_cbs ? "static " : "",
+ ncinfo->return_type, cb_name, ncinfo->arguments);
+
+ /* Add a comment, since these callbacks may not all be needed. */
+ printf("\t/* TODO: this cli callback is optional; the cli output may not need to be done at each node. */\n");
+
+ printf("}\n\n");
+}
+
static int generate_callbacks(const struct lysc_node *snode, void *arg)
{
bool first = true;
+ bool need_config_write = true;
switch (snode->nodetype) {
case LYS_CONTAINER:
@@ -241,6 +315,15 @@ static int generate_callbacks(const struct lysc_node *snode, void *arg)
generate_callback_name(snode, cb->operation, cb_name,
sizeof(cb_name));
generate_callback(cb, cb_name);
+
+ if (cb->need_config_write && need_config_write) {
+ generate_config_write_cb_name(snode, cb_name,
+ sizeof(cb_name));
+ generate_config_write_callback(&nb_config_write,
+ cb_name);
+
+ need_config_write = false;
+ }
}
return YANG_ITER_CONTINUE;
@@ -249,6 +332,10 @@ static int generate_callbacks(const struct lysc_node *snode, void *arg)
static int generate_nb_nodes(const struct lysc_node *snode, void *arg)
{
bool first = true;
+ char cb_name[BUFSIZ];
+ char xpath[XPATH_MAXLEN];
+ bool config_pass = *(bool *)arg;
+ bool need_config_write = true;
switch (snode->nodetype) {
case LYS_CONTAINER:
@@ -262,32 +349,53 @@ static int generate_nb_nodes(const struct lysc_node *snode, void *arg)
return YANG_ITER_CONTINUE;
}
+ /* We generate two types of structs currently; behavior is a little
+ * different between the types.
+ */
for (struct nb_callback_info *cb = &nb_callbacks[0];
cb->operation != -1; cb++) {
- char cb_name[BUFSIZ];
if (cb->optional
|| !nb_cb_operation_is_valid(cb->operation, snode))
continue;
- if (first) {
- char xpath[XPATH_MAXLEN];
+ if (config_pass) {
+ if (first) {
+ yang_snode_get_path(snode, YANG_PATH_DATA, xpath,
+ sizeof(xpath));
- yang_snode_get_path(snode, YANG_PATH_DATA, xpath,
- sizeof(xpath));
+ printf("\t\t{\n"
+ "\t\t\t.xpath = \"%s\",\n",
+ xpath);
+ printf("\t\t\t.cbs = {\n");
+ first = false;
+ }
- printf("\t\t{\n"
- "\t\t\t.xpath = \"%s\",\n",
- xpath);
- printf("\t\t\t.cbs = {\n");
- first = false;
- }
+ generate_callback_name(snode, cb->operation, cb_name,
+ sizeof(cb_name));
+ printf("\t\t\t\t.%s = %s,\n",
+ nb_cb_operation_name(cb->operation),
+ cb_name);
+ } else if (cb->need_config_write && need_config_write) {
+ if (first) {
+ yang_snode_get_path(snode,
+ YANG_PATH_DATA,
+ xpath,
+ sizeof(xpath));
+
+ printf("\t\t{\n"
+ "\t\t\t.xpath = \"%s\",\n",
+ xpath);
+ printf("\t\t\t.cbs = {\n");
+ first = false;
+ }
- generate_callback_name(snode, cb->operation, cb_name,
- sizeof(cb_name));
- printf("\t\t\t\t.%s = %s,\n",
- nb_cb_operation_name(cb->operation),
- cb_name);
+ generate_config_write_cb_name(snode, cb_name,
+ sizeof(cb_name));
+ printf("\t\t\t\t.cli_show = %s,\n", cb_name);
+
+ need_config_write = false;
+ }
}
if (!first) {
@@ -305,6 +413,7 @@ int main(int argc, char *argv[])
char module_name_underscores[64];
struct stat st;
int opt;
+ bool config_pass;
while ((opt = getopt(argc, argv, "hp:s")) != -1) {
switch (opt) {
@@ -357,6 +466,11 @@ int main(int argc, char *argv[])
/* Create a nb_node for all YANG schema nodes. */
nb_nodes_create();
+ /* Emit bare-bones license line (and fool the checkpatch regex
+ * that triggers a warning).
+ */
+ printf("// SPDX-" "License-Identifier: GPL-2.0-or-later\n\n");
+
/* Generate callback prototypes. */
if (!static_cbs) {
printf("/* prototypes */\n");
@@ -371,13 +485,38 @@ int main(int argc, char *argv[])
sizeof(module_name_underscores));
replace_hyphens_by_underscores(module_name_underscores);
- /* Generate frr_yang_module_info array. */
+ /*
+ * We're going to generate two structs here, two arrays of callbacks:
+ * first one with config-handling callbacks, then a second struct with
+ * config-output-oriented callbacks.
+ */
+
+ /* Generate frr_yang_module_info array, with config-handling callbacks */
+ config_pass = true;
printf("/* clang-format off */\n"
- "const struct frr_yang_module_info %s_info = {\n"
+ "const struct frr_yang_module_info %s_nb_info = {\n"
"\t.name = \"%s\",\n"
"\t.nodes = {\n",
module_name_underscores, module->name);
- yang_snodes_iterate(module->info, generate_nb_nodes, 0, NULL);
+ yang_snodes_iterate(module->info, generate_nb_nodes, 0, &config_pass);
+
+ /* Emit terminator element */
+ printf("\t\t{\n"
+ "\t\t\t.xpath = NULL,\n"
+ "\t\t},\n");
+ printf("\t}\n"
+ "};\n");
+
+ /* Generate second array, with output-oriented callbacks. */
+ config_pass = false;
+ printf("\n/* clang-format off */\n"
+ "const struct frr_yang_module_info %s_cli_info = {\n"
+ "\t.name = \"%s\",\n"
+ "\t.nodes = {\n",
+ module_name_underscores, module->name);
+ yang_snodes_iterate(module->info, generate_nb_nodes, 0, &config_pass);
+
+ /* Emit terminator element */
printf("\t\t{\n"
"\t\t\t.xpath = NULL,\n"
"\t\t},\n");
diff --git a/vrrpd/vrrp_main.c b/vrrpd/vrrp_main.c
index 7f859ca6d2..e9af3d92f5 100644
--- a/vrrpd/vrrp_main.c
+++ b/vrrpd/vrrp_main.c
@@ -107,8 +107,6 @@ static const struct frr_yang_module_info *const vrrp_yang_modules[] = {
&frr_vrrpd_info,
};
-#define VRRP_VTY_PORT 2619
-
/* clang-format off */
FRR_DAEMON_INFO(vrrpd, VRRP,
.vty_port = VRRP_VTY_PORT,
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 940b63b0e1..4cb46b87a5 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -3120,7 +3120,7 @@ DEFUN (vtysh_show_error_code,
}
/* Northbound. */
-DEFUN_HIDDEN (show_config_running,
+DEFUN (show_config_running,
show_config_running_cmd,
"show configuration running\
[<json|xml> [translate WORD]]\
diff --git a/yang/ietf/ietf-netconf-acm.yang b/yang/ietf/ietf-netconf-acm.yang
new file mode 100644
index 0000000000..f7e02f280e
--- /dev/null
+++ b/yang/ietf/ietf-netconf-acm.yang
@@ -0,0 +1,464 @@
+module ietf-netconf-acm {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-netconf-acm";
+
+ prefix nacm;
+
+ import ietf-yang-types {
+ prefix yang;
+ }
+
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+
+ contact
+ "WG Web: <https://datatracker.ietf.org/wg/netconf/>
+ WG List: <mailto:netconf@ietf.org>
+
+ Author: Andy Bierman
+ <mailto:andy@yumaworks.com>
+
+ Author: Martin Bjorklund
+ <mailto:mbj@tail-f.com>";
+
+ description
+ "Network Configuration Access Control Model.
+
+ Copyright (c) 2012 - 2018 IETF Trust and the persons
+ identified as authors of the code. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD
+ License set forth in Section 4.c of the IETF Trust's
+ Legal Provisions Relating to IETF Documents
+ (https://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 8341; see
+ the RFC itself for full legal notices.";
+
+ revision 2018-02-14 {
+ description
+ "Added support for YANG 1.1 actions and notifications tied to
+ data nodes. Clarified how NACM extensions can be used by
+ other data models.";
+ reference
+ "RFC 8341: Network Configuration Access Control Model";
+ }
+
+ revision 2012-02-22 {
+ description
+ "Initial version.";
+ reference
+ "RFC 6536: Network Configuration Protocol (NETCONF)
+ Access Control Model";
+ }
+
+ /*
+ * Extension statements
+ */
+
+ extension default-deny-write {
+ description
+ "Used to indicate that the data model node
+ represents a sensitive security system parameter.
+
+ If present, the NETCONF server will only allow the designated
+ 'recovery session' to have write access to the node. An
+ explicit access control rule is required for all other users.
+
+ If the NACM module is used, then it must be enabled (i.e.,
+ /nacm/enable-nacm object equals 'true'), or this extension
+ is ignored.
+
+ The 'default-deny-write' extension MAY appear within a data
+ definition statement. It is ignored otherwise.";
+ }
+
+ extension default-deny-all {
+ description
+ "Used to indicate that the data model node
+ controls a very sensitive security system parameter.
+
+ If present, the NETCONF server will only allow the designated
+ 'recovery session' to have read, write, or execute access to
+ the node. An explicit access control rule is required for all
+ other users.
+
+ If the NACM module is used, then it must be enabled (i.e.,
+ /nacm/enable-nacm object equals 'true'), or this extension
+ is ignored.
+
+ The 'default-deny-all' extension MAY appear within a data
+ definition statement, 'rpc' statement, or 'notification'
+ statement. It is ignored otherwise.";
+ }
+
+ /*
+ * Derived types
+ */
+
+ typedef user-name-type {
+ type string {
+ length "1..max";
+ }
+ description
+ "General-purpose username string.";
+ }
+
+ typedef matchall-string-type {
+ type string {
+ pattern '\*';
+ }
+ description
+ "The string containing a single asterisk '*' is used
+ to conceptually represent all possible values
+ for the particular leaf using this data type.";
+ }
+
+ typedef access-operations-type {
+ type bits {
+ bit create {
+ description
+ "Any protocol operation that creates a
+ new data node.";
+ }
+ bit read {
+ description
+ "Any protocol operation or notification that
+ returns the value of a data node.";
+ }
+ bit update {
+ description
+ "Any protocol operation that alters an existing
+ data node.";
+ }
+ bit delete {
+ description
+ "Any protocol operation that removes a data node.";
+ }
+ bit exec {
+ description
+ "Execution access to the specified protocol operation.";
+ }
+ }
+ description
+ "Access operation.";
+ }
+
+ typedef group-name-type {
+ type string {
+ length "1..max";
+ pattern '[^\*].*';
+ }
+ description
+ "Name of administrative group to which
+ users can be assigned.";
+ }
+
+ typedef action-type {
+ type enumeration {
+ enum permit {
+ description
+ "Requested action is permitted.";
+ }
+ enum deny {
+ description
+ "Requested action is denied.";
+ }
+ }
+ description
+ "Action taken by the server when a particular
+ rule matches.";
+ }
+
+ typedef node-instance-identifier {
+ type yang:xpath1.0;
+ description
+ "Path expression used to represent a special
+ data node, action, or notification instance-identifier
+ string.
+
+ A node-instance-identifier value is an
+ unrestricted YANG instance-identifier expression.
+ All the same rules as an instance-identifier apply,
+ except that predicates for keys are optional. If a key
+ predicate is missing, then the node-instance-identifier
+ represents all possible server instances for that key.
+
+ This XML Path Language (XPath) expression is evaluated in the
+ following context:
+
+ o The set of namespace declarations are those in scope on
+ the leaf element where this type is used.
+
+ o The set of variable bindings contains one variable,
+ 'USER', which contains the name of the user of the
+ current session.
+
+ o The function library is the core function library, but
+ note that due to the syntax restrictions of an
+ instance-identifier, no functions are allowed.
+
+ o The context node is the root node in the data tree.
+
+ The accessible tree includes actions and notifications tied
+ to data nodes.";
+ }
+
+ /*
+ * Data definition statements
+ */
+
+ container nacm {
+ nacm:default-deny-all;
+
+ description
+ "Parameters for NETCONF access control model.";
+
+ leaf enable-nacm {
+ type boolean;
+ default "true";
+ description
+ "Enables or disables all NETCONF access control
+ enforcement. If 'true', then enforcement
+ is enabled. If 'false', then enforcement
+ is disabled.";
+ }
+
+ leaf read-default {
+ type action-type;
+ default "permit";
+ description
+ "Controls whether read access is granted if
+ no appropriate rule is found for a
+ particular read request.";
+ }
+
+ leaf write-default {
+ type action-type;
+ default "deny";
+ description
+ "Controls whether create, update, or delete access
+ is granted if no appropriate rule is found for a
+ particular write request.";
+ }
+
+ leaf exec-default {
+ type action-type;
+ default "permit";
+ description
+ "Controls whether exec access is granted if no appropriate
+ rule is found for a particular protocol operation request.";
+ }
+
+ leaf enable-external-groups {
+ type boolean;
+ default "true";
+ description
+ "Controls whether the server uses the groups reported by the
+ NETCONF transport layer when it assigns the user to a set of
+ NACM groups. If this leaf has the value 'false', any group
+ names reported by the transport layer are ignored by the
+ server.";
+ }
+
+ leaf denied-operations {
+ type yang:zero-based-counter32;
+ config false;
+ mandatory true;
+ description
+ "Number of times since the server last restarted that a
+ protocol operation request was denied.";
+ }
+
+ leaf denied-data-writes {
+ type yang:zero-based-counter32;
+ config false;
+ mandatory true;
+ description
+ "Number of times since the server last restarted that a
+ protocol operation request to alter
+ a configuration datastore was denied.";
+ }
+
+ leaf denied-notifications {
+ type yang:zero-based-counter32;
+ config false;
+ mandatory true;
+ description
+ "Number of times since the server last restarted that
+ a notification was dropped for a subscription because
+ access to the event type was denied.";
+ }
+
+ container groups {
+ description
+ "NETCONF access control groups.";
+
+ list group {
+ key name;
+
+ description
+ "One NACM group entry. This list will only contain
+ configured entries, not any entries learned from
+ any transport protocols.";
+
+ leaf name {
+ type group-name-type;
+ description
+ "Group name associated with this entry.";
+ }
+
+ leaf-list user-name {
+ type user-name-type;
+ description
+ "Each entry identifies the username of
+ a member of the group associated with
+ this entry.";
+ }
+ }
+ }
+
+ list rule-list {
+ key name;
+ ordered-by user;
+ description
+ "An ordered collection of access control rules.";
+
+ leaf name {
+ type string {
+ length "1..max";
+ }
+ description
+ "Arbitrary name assigned to the rule-list.";
+ }
+ leaf-list group {
+ type union {
+ type matchall-string-type;
+ type group-name-type;
+ }
+ description
+ "List of administrative groups that will be
+ assigned the associated access rights
+ defined by the 'rule' list.
+
+ The string '*' indicates that all groups apply to the
+ entry.";
+ }
+
+ list rule {
+ key name;
+ ordered-by user;
+ description
+ "One access control rule.
+
+ Rules are processed in user-defined order until a match is
+ found. A rule matches if 'module-name', 'rule-type', and
+ 'access-operations' match the request. If a rule
+ matches, the 'action' leaf determines whether or not
+ access is granted.";
+
+ leaf name {
+ type string {
+ length "1..max";
+ }
+ description
+ "Arbitrary name assigned to the rule.";
+ }
+
+ leaf module-name {
+ type union {
+ type matchall-string-type;
+ type string;
+ }
+ default "*";
+ description
+ "Name of the module associated with this rule.
+
+ This leaf matches if it has the value '*' or if the
+ object being accessed is defined in the module with the
+ specified module name.";
+ }
+ choice rule-type {
+ description
+ "This choice matches if all leafs present in the rule
+ match the request. If no leafs are present, the
+ choice matches all requests.";
+ case protocol-operation {
+ leaf rpc-name {
+ type union {
+ type matchall-string-type;
+ type string;
+ }
+ description
+ "This leaf matches if it has the value '*' or if
+ its value equals the requested protocol operation
+ name.";
+ }
+ }
+ case notification {
+ leaf notification-name {
+ type union {
+ type matchall-string-type;
+ type string;
+ }
+ description
+ "This leaf matches if it has the value '*' or if its
+ value equals the requested notification name.";
+ }
+ }
+
+ case data-node {
+ leaf path {
+ type node-instance-identifier;
+ mandatory true;
+ description
+ "Data node instance-identifier associated with the
+ data node, action, or notification controlled by
+ this rule.
+
+ Configuration data or state data
+ instance-identifiers start with a top-level
+ data node. A complete instance-identifier is
+ required for this type of path value.
+
+ The special value '/' refers to all possible
+ datastore contents.";
+ }
+ }
+ }
+
+ leaf access-operations {
+ type union {
+ type matchall-string-type;
+ type access-operations-type;
+ }
+ default "*";
+ description
+ "Access operations associated with this rule.
+
+ This leaf matches if it has the value '*' or if the
+ bit corresponding to the requested operation is set.";
+ }
+
+ leaf action {
+ type action-type;
+ mandatory true;
+ description
+ "The access control action associated with the
+ rule. If a rule has been determined to match a
+ particular request, then this object is used
+ to determine whether to permit or deny the
+ request.";
+ }
+
+ leaf comment {
+ type string;
+ description
+ "A textual description of the access rule.";
+ }
+ }
+ }
+ }
+}
diff --git a/yang/ietf/ietf-netconf-with-defaults.yang b/yang/ietf/ietf-netconf-with-defaults.yang
new file mode 100644
index 0000000000..05ff399fd7
--- /dev/null
+++ b/yang/ietf/ietf-netconf-with-defaults.yang
@@ -0,0 +1,139 @@
+module ietf-netconf-with-defaults {
+
+ namespace "urn:ietf:params:xml:ns:yang:ietf-netconf-with-defaults";
+
+ prefix ncwd;
+
+ import ietf-netconf { prefix nc; }
+
+ organization
+ "IETF NETCONF (Network Configuration Protocol) Working Group";
+
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netconf/>
+
+ WG List: <netconf@ietf.org>
+
+ WG Chair: Bert Wijnen
+ <bertietf@bwijnen.net>
+
+ WG Chair: Mehmet Ersue
+ <mehmet.ersue@nsn.com>
+
+ Editor: Andy Bierman
+ <andy.bierman@brocade.com>
+
+ Editor: Balazs Lengyel
+ <balazs.lengyel@ericsson.com>";
+
+ description
+ "This module defines an extension to the NETCONF protocol
+ that allows the NETCONF client to control how default
+ values are handled by the server in particular NETCONF
+ operations.
+
+ Copyright (c) 2011 IETF Trust and the persons identified as
+ the document authors. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 6243; see
+ the RFC itself for full legal notices.";
+
+ revision 2011-06-01 {
+ description
+ "Initial version.";
+ reference
+ "RFC 6243: With-defaults Capability for NETCONF";
+ }
+
+ typedef with-defaults-mode {
+ description
+ "Possible modes to report default data.";
+ reference
+ "RFC 6243; Section 3.";
+ type enumeration {
+ enum report-all {
+ description
+ "All default data is reported.";
+ reference
+ "RFC 6243; Section 3.1";
+ }
+ enum report-all-tagged {
+ description
+ "All default data is reported.
+ Any nodes considered to be default data
+ will contain a 'default' XML attribute,
+ set to 'true' or '1'.";
+ reference
+ "RFC 6243; Section 3.4";
+ }
+ enum trim {
+ description
+ "Values are not reported if they contain the default.";
+ reference
+ "RFC 6243; Section 3.2";
+ }
+ enum explicit {
+ description
+ "Report values that contain the definition of
+ explicitly set data.";
+ reference
+ "RFC 6243; Section 3.3";
+ }
+ }
+ }
+
+ grouping with-defaults-parameters {
+ description
+ "Contains the <with-defaults> parameter for control
+ of defaults in NETCONF retrieval operations.";
+
+ leaf with-defaults {
+ description
+ "The explicit defaults processing mode requested.";
+ reference
+ "RFC 6243; Section 4.5.1";
+
+ type with-defaults-mode;
+ }
+ }
+
+ // extending the get-config operation
+ augment /nc:get-config/nc:input {
+ description
+ "Adds the <with-defaults> parameter to the
+ input of the NETCONF <get-config> operation.";
+ reference
+ "RFC 6243; Section 4.5.1";
+
+ uses with-defaults-parameters;
+ }
+
+ // extending the get operation
+ augment /nc:get/nc:input {
+ description
+ "Adds the <with-defaults> parameter to
+ the input of the NETCONF <get> operation.";
+ reference
+ "RFC 6243; Section 4.5.1";
+
+ uses with-defaults-parameters;
+ }
+
+ // extending the copy-config operation
+ augment /nc:copy-config/nc:input {
+ description
+ "Adds the <with-defaults> parameter to
+ the input of the NETCONF <copy-config> operation.";
+ reference
+ "RFC 6243; Section 4.5.1";
+
+ uses with-defaults-parameters;
+ }
+}
diff --git a/yang/ietf/ietf-netconf.yang b/yang/ietf/ietf-netconf.yang
new file mode 100644
index 0000000000..93927f1c80
--- /dev/null
+++ b/yang/ietf/ietf-netconf.yang
@@ -0,0 +1,933 @@
+module ietf-netconf {
+
+ // the namespace for NETCONF XML definitions is unchanged
+ // from RFC 4741, which this document replaces
+ namespace "urn:ietf:params:xml:ns:netconf:base:1.0";
+
+ prefix nc;
+
+ import ietf-inet-types {
+ prefix inet;
+ }
+
+ import ietf-netconf-acm { prefix nacm; }
+
+ organization
+ "IETF NETCONF (Network Configuration) Working Group";
+
+ contact
+ "WG Web: <http://tools.ietf.org/wg/netconf/>
+ WG List: <netconf@ietf.org>
+
+ WG Chair: Bert Wijnen
+ <bertietf@bwijnen.net>
+
+ WG Chair: Mehmet Ersue
+ <mehmet.ersue@nsn.com>
+
+ Editor: Martin Bjorklund
+ <mbj@tail-f.com>
+
+ Editor: Juergen Schoenwaelder
+ <j.schoenwaelder@jacobs-university.de>
+
+ Editor: Andy Bierman
+ <andy.bierman@brocade.com>";
+ description
+ "NETCONF Protocol Data Types and Protocol Operations.
+
+ Copyright (c) 2011 IETF Trust and the persons identified as
+ the document authors. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or
+ without modification, is permitted pursuant to, and subject
+ to the license terms contained in, the Simplified BSD License
+ set forth in Section 4.c of the IETF Trust's Legal Provisions
+ Relating to IETF Documents
+ (http://trustee.ietf.org/license-info).
+
+ This version of this YANG module is part of RFC 6241; see
+ the RFC itself for full legal notices.";
+
+ revision 2011-06-01 {
+ description
+ "Initial revision;
+ 2013-09-29: Updated to include NACM attributes,
+ as specified in RFC 6536: sec 3.2.5 and 3.2.8";
+ reference
+ "RFC 6241: Network Configuration Protocol";
+ }
+
+ extension get-filter-element-attributes {
+ description
+ "If this extension is present within an 'anyxml'
+ statement named 'filter', which must be conceptually
+ defined within the RPC input section for the <get>
+ and <get-config> protocol operations, then the
+ following unqualified XML attribute is supported
+ within the <filter> element, within a <get> or
+ <get-config> protocol operation:
+
+ type : optional attribute with allowed
+ value strings 'subtree' and 'xpath'.
+ If missing, the default value is 'subtree'.
+
+ If the 'xpath' feature is supported, then the
+ following unqualified XML attribute is
+ also supported:
+
+ select: optional attribute containing a
+ string representing an XPath expression.
+ The 'type' attribute must be equal to 'xpath'
+ if this attribute is present.";
+ }
+
+ // NETCONF capabilities defined as features
+ feature writable-running {
+ description
+ "NETCONF :writable-running capability;
+ If the server advertises the :writable-running
+ capability for a session, then this feature must
+ also be enabled for that session. Otherwise,
+ this feature must not be enabled.";
+ reference "RFC 6241, Section 8.2";
+ }
+
+ feature candidate {
+ description
+ "NETCONF :candidate capability;
+ If the server advertises the :candidate
+ capability for a session, then this feature must
+ also be enabled for that session. Otherwise,
+ this feature must not be enabled.";
+ reference "RFC 6241, Section 8.3";
+ }
+
+ feature confirmed-commit {
+ if-feature candidate;
+ description
+ "NETCONF :confirmed-commit:1.1 capability;
+ If the server advertises the :confirmed-commit:1.1
+ capability for a session, then this feature must
+ also be enabled for that session. Otherwise,
+ this feature must not be enabled.";
+
+ reference "RFC 6241, Section 8.4";
+ }
+
+ feature rollback-on-error {
+ description
+ "NETCONF :rollback-on-error capability;
+ If the server advertises the :rollback-on-error
+ capability for a session, then this feature must
+ also be enabled for that session. Otherwise,
+ this feature must not be enabled.";
+ reference "RFC 6241, Section 8.5";
+ }
+
+ feature validate {
+ description
+ "NETCONF :validate:1.1 capability;
+ If the server advertises the :validate:1.1
+ capability for a session, then this feature must
+ also be enabled for that session. Otherwise,
+ this feature must not be enabled.";
+ reference "RFC 6241, Section 8.6";
+ }
+
+ feature startup {
+ description
+ "NETCONF :startup capability;
+ If the server advertises the :startup
+ capability for a session, then this feature must
+ also be enabled for that session. Otherwise,
+ this feature must not be enabled.";
+ reference "RFC 6241, Section 8.7";
+ }
+
+ feature url {
+ description
+ "NETCONF :url capability;
+ If the server advertises the :url
+ capability for a session, then this feature must
+ also be enabled for that session. Otherwise,
+ this feature must not be enabled.";
+ reference "RFC 6241, Section 8.8";
+ }
+
+ feature xpath {
+ description
+ "NETCONF :xpath capability;
+ If the server advertises the :xpath
+ capability for a session, then this feature must
+ also be enabled for that session. Otherwise,
+ this feature must not be enabled.";
+ reference "RFC 6241, Section 8.9";
+ }
+
+ // NETCONF Simple Types
+
+ typedef session-id-type {
+ type uint32 {
+ range "1..max";
+ }
+ description
+ "NETCONF Session Id";
+ }
+
+ typedef session-id-or-zero-type {
+ type uint32;
+ description
+ "NETCONF Session Id or Zero to indicate none";
+ }
+ typedef error-tag-type {
+ type enumeration {
+ enum in-use {
+ description
+ "The request requires a resource that
+ already is in use.";
+ }
+ enum invalid-value {
+ description
+ "The request specifies an unacceptable value for one
+ or more parameters.";
+ }
+ enum too-big {
+ description
+ "The request or response (that would be generated) is
+ too large for the implementation to handle.";
+ }
+ enum missing-attribute {
+ description
+ "An expected attribute is missing.";
+ }
+ enum bad-attribute {
+ description
+ "An attribute value is not correct; e.g., wrong type,
+ out of range, pattern mismatch.";
+ }
+ enum unknown-attribute {
+ description
+ "An unexpected attribute is present.";
+ }
+ enum missing-element {
+ description
+ "An expected element is missing.";
+ }
+ enum bad-element {
+ description
+ "An element value is not correct; e.g., wrong type,
+ out of range, pattern mismatch.";
+ }
+ enum unknown-element {
+ description
+ "An unexpected element is present.";
+ }
+ enum unknown-namespace {
+ description
+ "An unexpected namespace is present.";
+ }
+ enum access-denied {
+ description
+ "Access to the requested protocol operation or
+ data model is denied because authorization failed.";
+ }
+ enum lock-denied {
+ description
+ "Access to the requested lock is denied because the
+ lock is currently held by another entity.";
+ }
+ enum resource-denied {
+ description
+ "Request could not be completed because of
+ insufficient resources.";
+ }
+ enum rollback-failed {
+ description
+ "Request to roll back some configuration change (via
+ rollback-on-error or <discard-changes> operations)
+ was not completed for some reason.";
+
+ }
+ enum data-exists {
+ description
+ "Request could not be completed because the relevant
+ data model content already exists. For example,
+ a 'create' operation was attempted on data that
+ already exists.";
+ }
+ enum data-missing {
+ description
+ "Request could not be completed because the relevant
+ data model content does not exist. For example,
+ a 'delete' operation was attempted on
+ data that does not exist.";
+ }
+ enum operation-not-supported {
+ description
+ "Request could not be completed because the requested
+ operation is not supported by this implementation.";
+ }
+ enum operation-failed {
+ description
+ "Request could not be completed because the requested
+ operation failed for some reason not covered by
+ any other error condition.";
+ }
+ enum partial-operation {
+ description
+ "This error-tag is obsolete, and SHOULD NOT be sent
+ by servers conforming to this document.";
+ }
+ enum malformed-message {
+ description
+ "A message could not be handled because it failed to
+ be parsed correctly. For example, the message is not
+ well-formed XML or it uses an invalid character set.";
+ }
+ }
+ description "NETCONF Error Tag";
+ reference "RFC 6241, Appendix A";
+ }
+
+ typedef error-severity-type {
+ type enumeration {
+ enum error {
+ description "Error severity";
+ }
+ enum warning {
+ description "Warning severity";
+ }
+ }
+ description "NETCONF Error Severity";
+ reference "RFC 6241, Section 4.3";
+ }
+
+ typedef edit-operation-type {
+ type enumeration {
+ enum merge {
+ description
+ "The configuration data identified by the
+ element containing this attribute is merged
+ with the configuration at the corresponding
+ level in the configuration datastore identified
+ by the target parameter.";
+ }
+ enum replace {
+ description
+ "The configuration data identified by the element
+ containing this attribute replaces any related
+ configuration in the configuration datastore
+ identified by the target parameter. If no such
+ configuration data exists in the configuration
+ datastore, it is created. Unlike a
+ <copy-config> operation, which replaces the
+ entire target configuration, only the configuration
+ actually present in the config parameter is affected.";
+ }
+ enum create {
+ description
+ "The configuration data identified by the element
+ containing this attribute is added to the
+ configuration if and only if the configuration
+ data does not already exist in the configuration
+ datastore. If the configuration data exists, an
+ <rpc-error> element is returned with an
+ <error-tag> value of 'data-exists'.";
+ }
+ enum delete {
+ description
+ "The configuration data identified by the element
+ containing this attribute is deleted from the
+ configuration if and only if the configuration
+ data currently exists in the configuration
+ datastore. If the configuration data does not
+ exist, an <rpc-error> element is returned with
+ an <error-tag> value of 'data-missing'.";
+ }
+ enum remove {
+ description
+ "The configuration data identified by the element
+ containing this attribute is deleted from the
+ configuration if the configuration
+ data currently exists in the configuration
+ datastore. If the configuration data does not
+ exist, the 'remove' operation is silently ignored
+ by the server.";
+ }
+ }
+ default "merge";
+ description "NETCONF 'operation' attribute values";
+ reference "RFC 6241, Section 7.2";
+ }
+
+ // NETCONF Standard Protocol Operations
+
+ rpc get-config {
+ description
+ "Retrieve all or part of a specified configuration.";
+
+ reference "RFC 6241, Section 7.1";
+
+ input {
+ container source {
+ description
+ "Particular configuration to retrieve.";
+
+ choice config-source {
+ mandatory true;
+ description
+ "The configuration to retrieve.";
+ leaf candidate {
+ if-feature candidate;
+ type empty;
+ description
+ "The candidate configuration is the config source.";
+ }
+ leaf running {
+ type empty;
+ description
+ "The running configuration is the config source.";
+ }
+ leaf startup {
+ if-feature startup;
+ type empty;
+ description
+ "The startup configuration is the config source.
+ This is optional-to-implement on the server because
+ not all servers will support filtering for this
+ datastore.";
+ }
+ }
+ }
+
+ anyxml filter {
+ description
+ "Subtree or XPath filter to use.";
+ nc:get-filter-element-attributes;
+ }
+ }
+
+ output {
+ anyxml data {
+ description
+ "Copy of the source datastore subset that matched
+ the filter criteria (if any). An empty data container
+ indicates that the request did not produce any results.";
+ }
+ }
+ }
+
+ rpc edit-config {
+ description
+ "The <edit-config> operation loads all or part of a specified
+ configuration to the specified target configuration.";
+
+ reference "RFC 6241, Section 7.2";
+
+ input {
+ container target {
+ description
+ "Particular configuration to edit.";
+
+ choice config-target {
+ mandatory true;
+ description
+ "The configuration target.";
+
+ leaf candidate {
+ if-feature candidate;
+ type empty;
+ description
+ "The candidate configuration is the config target.";
+ }
+ leaf running {
+ if-feature writable-running;
+ type empty;
+ description
+ "The running configuration is the config source.";
+ }
+ }
+ }
+
+ leaf default-operation {
+ type enumeration {
+ enum merge {
+ description
+ "The default operation is merge.";
+ }
+ enum replace {
+ description
+ "The default operation is replace.";
+ }
+ enum none {
+ description
+ "There is no default operation.";
+ }
+ }
+ default "merge";
+ description
+ "The default operation to use.";
+ }
+
+ leaf test-option {
+ if-feature validate;
+ type enumeration {
+ enum test-then-set {
+ description
+ "The server will test and then set if no errors.";
+ }
+ enum set {
+ description
+ "The server will set without a test first.";
+ }
+
+ enum test-only {
+ description
+ "The server will only test and not set, even
+ if there are no errors.";
+ }
+ }
+ default "test-then-set";
+ description
+ "The test option to use.";
+ }
+
+ leaf error-option {
+ type enumeration {
+ enum stop-on-error {
+ description
+ "The server will stop on errors.";
+ }
+ enum continue-on-error {
+ description
+ "The server may continue on errors.";
+ }
+ enum rollback-on-error {
+ description
+ "The server will roll back on errors.
+ This value can only be used if the 'rollback-on-error'
+ feature is supported.";
+ }
+ }
+ default "stop-on-error";
+ description
+ "The error option to use.";
+ }
+
+ choice edit-content {
+ mandatory true;
+ description
+ "The content for the edit operation.";
+
+ anyxml config {
+ description
+ "Inline Config content.";
+ }
+ leaf url {
+ if-feature url;
+ type inet:uri;
+ description
+ "URL-based config content.";
+ }
+ }
+ }
+ }
+
+ rpc copy-config {
+ description
+ "Create or replace an entire configuration datastore with the
+ contents of another complete configuration datastore.";
+
+ reference "RFC 6241, Section 7.3";
+
+ input {
+ container target {
+ description
+ "Particular configuration to copy to.";
+
+ choice config-target {
+ mandatory true;
+ description
+ "The configuration target of the copy operation.";
+
+ leaf candidate {
+ if-feature candidate;
+ type empty;
+ description
+ "The candidate configuration is the config target.";
+ }
+ leaf running {
+ if-feature writable-running;
+ type empty;
+ description
+ "The running configuration is the config target.
+ This is optional-to-implement on the server.";
+ }
+ leaf startup {
+ if-feature startup;
+ type empty;
+ description
+ "The startup configuration is the config target.";
+ }
+ leaf url {
+ if-feature url;
+ type inet:uri;
+ description
+ "The URL-based configuration is the config target.";
+ }
+ }
+ }
+
+ container source {
+ description
+ "Particular configuration to copy from.";
+
+ choice config-source {
+ mandatory true;
+ description
+ "The configuration source for the copy operation.";
+
+ leaf candidate {
+ if-feature candidate;
+ type empty;
+ description
+ "The candidate configuration is the config source.";
+ }
+ leaf running {
+ type empty;
+ description
+ "The running configuration is the config source.";
+ }
+ leaf startup {
+ if-feature startup;
+ type empty;
+ description
+ "The startup configuration is the config source.";
+ }
+ leaf url {
+ if-feature url;
+ type inet:uri;
+ description
+ "The URL-based configuration is the config source.";
+ }
+ anyxml config {
+ description
+ "Inline Config content: <config> element. Represents
+ an entire configuration datastore, not
+ a subset of the running datastore.";
+ }
+ }
+ }
+ }
+ }
+
+ rpc delete-config {
+ nacm:default-deny-all;
+ description
+ "Delete a configuration datastore.";
+
+ reference "RFC 6241, Section 7.4";
+
+ input {
+ container target {
+ description
+ "Particular configuration to delete.";
+
+ choice config-target {
+ mandatory true;
+ description
+ "The configuration target to delete.";
+
+ leaf startup {
+ if-feature startup;
+ type empty;
+ description
+ "The startup configuration is the config target.";
+ }
+ leaf url {
+ if-feature url;
+ type inet:uri;
+ description
+ "The URL-based configuration is the config target.";
+ }
+ }
+ }
+ }
+ }
+
+ rpc lock {
+ description
+ "The lock operation allows the client to lock the configuration
+ system of a device.";
+
+ reference "RFC 6241, Section 7.5";
+
+ input {
+ container target {
+ description
+ "Particular configuration to lock.";
+
+ choice config-target {
+ mandatory true;
+ description
+ "The configuration target to lock.";
+
+ leaf candidate {
+ if-feature candidate;
+ type empty;
+ description
+ "The candidate configuration is the config target.";
+ }
+ leaf running {
+ type empty;
+ description
+ "The running configuration is the config target.";
+ }
+ leaf startup {
+ if-feature startup;
+ type empty;
+ description
+ "The startup configuration is the config target.";
+ }
+ }
+ }
+ }
+ }
+
+ rpc unlock {
+ description
+ "The unlock operation is used to release a configuration lock,
+ previously obtained with the 'lock' operation.";
+
+ reference "RFC 6241, Section 7.6";
+
+ input {
+ container target {
+ description
+ "Particular configuration to unlock.";
+
+ choice config-target {
+ mandatory true;
+ description
+ "The configuration target to unlock.";
+
+ leaf candidate {
+ if-feature candidate;
+ type empty;
+ description
+ "The candidate configuration is the config target.";
+ }
+ leaf running {
+ type empty;
+ description
+ "The running configuration is the config target.";
+ }
+ leaf startup {
+ if-feature startup;
+ type empty;
+ description
+ "The startup configuration is the config target.";
+ }
+ }
+ }
+ }
+ }
+
+ rpc get {
+ description
+ "Retrieve running configuration and device state information.";
+
+ reference "RFC 6241, Section 7.7";
+
+ input {
+ anyxml filter {
+ description
+ "This parameter specifies the portion of the system
+ configuration and state data to retrieve.";
+ nc:get-filter-element-attributes;
+ }
+ }
+
+ output {
+ anyxml data {
+ description
+ "Copy of the running datastore subset and/or state
+ data that matched the filter criteria (if any).
+ An empty data container indicates that the request did not
+ produce any results.";
+ }
+ }
+ }
+
+ rpc close-session {
+ description
+ "Request graceful termination of a NETCONF session.";
+
+ reference "RFC 6241, Section 7.8";
+ }
+
+ rpc kill-session {
+ nacm:default-deny-all;
+ description
+ "Force the termination of a NETCONF session.";
+
+ reference "RFC 6241, Section 7.9";
+
+ input {
+ leaf session-id {
+ type session-id-type;
+ mandatory true;
+ description
+ "Particular session to kill.";
+ }
+ }
+ }
+
+ rpc commit {
+ if-feature candidate;
+
+ description
+ "Commit the candidate configuration as the device's new
+ current configuration.";
+
+ reference "RFC 6241, Section 8.3.4.1";
+
+ input {
+ leaf confirmed {
+ if-feature confirmed-commit;
+ type empty;
+ description
+ "Requests a confirmed commit.";
+ reference "RFC 6241, Section 8.3.4.1";
+ }
+
+ leaf confirm-timeout {
+ if-feature confirmed-commit;
+ type uint32 {
+ range "1..max";
+ }
+ units "seconds";
+ default "600"; // 10 minutes
+ description
+ "The timeout interval for a confirmed commit.";
+ reference "RFC 6241, Section 8.3.4.1";
+ }
+
+ leaf persist {
+ if-feature confirmed-commit;
+ type string;
+ description
+ "This parameter is used to make a confirmed commit
+ persistent. A persistent confirmed commit is not aborted
+ if the NETCONF session terminates. The only way to abort
+ a persistent confirmed commit is to let the timer expire,
+ or to use the <cancel-commit> operation.
+
+ The value of this parameter is a token that must be given
+ in the 'persist-id' parameter of <commit> or
+ <cancel-commit> operations in order to confirm or cancel
+ the persistent confirmed commit.
+
+ The token should be a random string.";
+ reference "RFC 6241, Section 8.3.4.1";
+ }
+
+ leaf persist-id {
+ if-feature confirmed-commit;
+ type string;
+ description
+ "This parameter is given in order to commit a persistent
+ confirmed commit. The value must be equal to the value
+ given in the 'persist' parameter to the <commit> operation.
+ If it does not match, the operation fails with an
+ 'invalid-value' error.";
+ reference "RFC 6241, Section 8.3.4.1";
+ }
+
+ }
+ }
+
+ rpc discard-changes {
+ if-feature candidate;
+
+ description
+ "Revert the candidate configuration to the current
+ running configuration.";
+ reference "RFC 6241, Section 8.3.4.2";
+ }
+
+ rpc cancel-commit {
+ if-feature confirmed-commit;
+ description
+ "This operation is used to cancel an ongoing confirmed commit.
+ If the confirmed commit is persistent, the parameter
+ 'persist-id' must be given, and it must match the value of the
+ 'persist' parameter.";
+ reference "RFC 6241, Section 8.4.4.1";
+
+ input {
+ leaf persist-id {
+ type string;
+ description
+ "This parameter is given in order to cancel a persistent
+ confirmed commit. The value must be equal to the value
+ given in the 'persist' parameter to the <commit> operation.
+ If it does not match, the operation fails with an
+ 'invalid-value' error.";
+ }
+ }
+ }
+
+ rpc validate {
+ if-feature validate;
+
+ description
+ "Validates the contents of the specified configuration.";
+
+ reference "RFC 6241, Section 8.6.4.1";
+
+ input {
+ container source {
+ description
+ "Particular configuration to validate.";
+
+ choice config-source {
+ mandatory true;
+ description
+ "The configuration source to validate.";
+
+ leaf candidate {
+ if-feature candidate;
+ type empty;
+ description
+ "The candidate configuration is the config source.";
+ }
+ leaf running {
+ type empty;
+ description
+ "The running configuration is the config source.";
+ }
+ leaf startup {
+ if-feature startup;
+ type empty;
+ description
+ "The startup configuration is the config source.";
+ }
+ leaf url {
+ if-feature url;
+ type inet:uri;
+ description
+ "The URL-based configuration is the config source.";
+ }
+ anyxml config {
+ description
+ "Inline Config content: <config> element. Represents
+ an entire configuration datastore, not
+ a subset of the running datastore.";
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/yang/subdir.am b/yang/subdir.am
index eb17c38dbc..0bdf93793f 100644
--- a/yang/subdir.am
+++ b/yang/subdir.am
@@ -38,6 +38,9 @@ dist_yangmodels_DATA += yang/frr-routing.yang
dist_yangmodels_DATA += yang/ietf/ietf-routing-types.yang
dist_yangmodels_DATA += yang/ietf/ietf-interfaces.yang
dist_yangmodels_DATA += yang/ietf/ietf-bgp-types.yang
+dist_yangmodels_DATA += yang/ietf/ietf-netconf-acm.yang
+dist_yangmodels_DATA += yang/ietf/ietf-netconf.yang
+dist_yangmodels_DATA += yang/ietf/ietf-netconf-with-defaults.yang
if BFDD
dist_yangmodels_DATA += yang/frr-bfdd.yang
diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c
index 0931cc788f..7ae1b2a090 100644
--- a/zebra/dplane_fpm_nl.c
+++ b/zebra/dplane_fpm_nl.c
@@ -45,7 +45,6 @@
#include "fpm/fpm.h"
#define SOUTHBOUND_DEFAULT_ADDR INADDR_LOOPBACK
-#define SOUTHBOUND_DEFAULT_PORT 2620
/*
* Time in seconds that if the other end is not responding
@@ -217,7 +216,7 @@ DEFUN(fpm_set_address, fpm_set_address_cmd,
memset(sin, 0, sizeof(*sin));
sin->sin_family = AF_INET;
sin->sin_port =
- port ? htons(port) : htons(SOUTHBOUND_DEFAULT_PORT);
+ port ? htons(port) : htons(FPM_DEFAULT_PORT);
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
sin->sin_len = sizeof(*sin);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
@@ -235,7 +234,7 @@ DEFUN(fpm_set_address, fpm_set_address_cmd,
sin6 = (struct sockaddr_in6 *)&gfnc->addr;
memset(sin6, 0, sizeof(*sin6));
sin6->sin6_family = AF_INET6;
- sin6->sin6_port = port ? htons(port) : htons(SOUTHBOUND_DEFAULT_PORT);
+ sin6->sin6_port = port ? htons(port) : htons(FPM_DEFAULT_PORT);
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
sin6->sin6_len = sizeof(*sin6);
#endif /* HAVE_STRUCT_SOCKADDR_SA_LEN */
@@ -402,7 +401,7 @@ static int fpm_write_config(struct vty *vty)
written = 1;
sin = (struct sockaddr_in *)&gfnc->addr;
vty_out(vty, "fpm address %pI4", &sin->sin_addr);
- if (sin->sin_port != htons(SOUTHBOUND_DEFAULT_PORT))
+ if (sin->sin_port != htons(FPM_DEFAULT_PORT))
vty_out(vty, " port %d", ntohs(sin->sin_port));
vty_out(vty, "\n");
@@ -411,7 +410,7 @@ static int fpm_write_config(struct vty *vty)
written = 1;
sin6 = (struct sockaddr_in6 *)&gfnc->addr;
vty_out(vty, "fpm address %pI6", &sin6->sin6_addr);
- if (sin6->sin6_port != htons(SOUTHBOUND_DEFAULT_PORT))
+ if (sin6->sin6_port != htons(FPM_DEFAULT_PORT))
vty_out(vty, " port %d", ntohs(sin6->sin6_port));
vty_out(vty, "\n");
diff --git a/zebra/zebra_cli.c b/zebra/zebra_cli.c
index a00698e8c7..8fedcfedc0 100644
--- a/zebra/zebra_cli.c
+++ b/zebra/zebra_cli.c
@@ -230,11 +230,12 @@ DEFUN_YANG_NOSH (link_params,
ret = nb_cli_apply_changes(vty, NULL);
if (ret == CMD_SUCCESS) {
- char xpath[XPATH_MAXLEN];
+ char *xpath;
- snprintf(xpath, sizeof(xpath), "%s/frr-zebra:zebra/link-params",
- VTY_CURR_XPATH);
+ xpath = asprintfrr(MTYPE_TMP, "%s/frr-zebra:zebra/link-params",
+ VTY_CURR_XPATH);
VTY_PUSH_XPATH(LINK_PARAMS_NODE, xpath);
+ XFREE(MTYPE_TMP, xpath);
}
return ret;
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 9e89e32d5d..5b95d8668a 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -2693,6 +2693,7 @@ static void early_route_memory_free(struct zebra_early_route *ere)
if (ere->re_nhe)
zebra_nhg_free(ere->re_nhe);
+ zapi_re_opaque_free(ere->re->opaque);
XFREE(MTYPE_RE, ere->re);
XFREE(MTYPE_WQ_WRAPPER, ere);
}
diff --git a/zebra/zserv.h b/zebra/zserv.h
index 4ab201b5ea..e1c990fb05 100644
--- a/zebra/zserv.h
+++ b/zebra/zserv.h
@@ -31,9 +31,6 @@ extern "C" {
struct zebra_vrf;
-/* Default port information. */
-#define ZEBRA_VTY_PORT 2601
-
/* Default configuration filename. */
#define DEFAULT_CONFIG_FILE "zebra.conf"