summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPat Ruddy <pat@voltanet.io>2020-09-28 17:35:35 +0200
committerPat Ruddy <pat@voltanet.io>2021-02-02 10:37:06 +0100
commit0d020cd6d98f454f22723f404da99fa48b7b2751 (patch)
treefe2605ddf46460c25b38c03276b21b93dc049f25
parentbgpd: add MPLSVPN SNMP boilerplate (diff)
downloadfrr-0d020cd6d98f454f22723f404da99fa48b7b2751.tar.xz
frr-0d020cd6d98f454f22723f404da99fa48b7b2751.zip
bgpd, lib: add mplsL3VpnVrf table
Add SNMP support for L3vpn Vrf table as defined in [RFC4382] Keep track of vrf status for the table and for future traps. Signed-off-by: Pat Ruddy <pat@voltanet.io>
-rw-r--r--bgpd/bgp_mplsvpn_snmp.c328
-rw-r--r--bgpd/bgp_nb_config.c3
-rw-r--r--bgpd/bgp_vty.c2
-rw-r--r--bgpd/bgp_zebra.c13
-rw-r--r--bgpd/bgpd.c1
-rw-r--r--bgpd/bgpd.h53
-rw-r--r--lib/smux.h2
-rw-r--r--lib/snmp.c28
8 files changed, 407 insertions, 23 deletions
diff --git a/bgpd/bgp_mplsvpn_snmp.c b/bgpd/bgp_mplsvpn_snmp.c
index 0a8d39cb9..65fbf5413 100644
--- a/bgpd/bgp_mplsvpn_snmp.c
+++ b/bgpd/bgp_mplsvpn_snmp.c
@@ -41,8 +41,6 @@
#define BGP_mplsvpn_notif_enable_true 1
#define BGP_mplsvpn_notif_enable_false 2
-static uint8_t bgp_mplsvpn_notif_enable = SNMP_FALSE;
-
/* MPLSL3VPN MIB described in RFC4382 */
#define MPLSL3VPNMIB 1, 3, 6, 1, 2, 1, 10, 166, 11
@@ -55,6 +53,22 @@ static uint8_t bgp_mplsvpn_notif_enable = SNMP_FALSE;
#define MPLSL3VPNVRFCONFRTEMXTHRSHTIME 6
#define MPLSL3VPNILLLBLRCVTHRSH 7
+/* MPLSL3VPN VRF Table */
+#define MPLSL3VPNVRFVPNID 1
+#define MPLSL3VPNVRFDESC 2
+#define MPLSL3VPNVRFRD 3
+#define MPLSL3VPNVRFCREATIONTIME 4
+#define MPLSL3VPNVRFOPERSTATUS 5
+#define MPLSL3VPNVRFACTIVEINTERFACES 6
+#define MPLSL3VPNVRFASSOCIATEDINTERFACES 7
+#define MPLSL3VPNVRFCONFMIDRTETHRESH 8
+#define MPLSL3VPNVRFCONFHIGHRTETHRSH 9
+#define MPLSL3VPNVRFCONFMAXROUTES 10
+#define MPLSL3VPNVRFCONFLASTCHANGED 11
+#define MPLSL3VPNVRFCONFROWSTATUS 12
+#define MPLSL3VPNVRFCONFADMINSTATUS 13
+#define MPLSL3VPNVRFCONFSTORAGETYPE 14
+
/* SNMP value hack. */
#define INTEGER ASN_INTEGER
#define INTEGER32 ASN_INTEGER
@@ -62,12 +76,15 @@ static uint8_t bgp_mplsvpn_notif_enable = SNMP_FALSE;
#define OCTET_STRING ASN_OCTET_STR
#define IPADDRESS ASN_IPADDRESS
#define GAUGE32 ASN_UNSIGNED
+#define TIMETICKS ASN_TIMETICKS
/* Declare static local variables for convenience. */
SNMP_LOCAL_VARIABLES
/* BGP-MPLS-MIB innstances */
static oid mpls_l3vpn_oid[] = {MPLSL3VPNMIB};
+static char rd_buf[RD_ADDRSTRLEN];
+static uint8_t bgp_mplsvpn_notif_enable = SNMP_FALSE;
static uint8_t *mplsL3vpnConfiguredVrfs(struct variable *, oid[], size_t *, int,
size_t *, WriteMethod **);
@@ -91,6 +108,10 @@ static uint8_t *mplsL3vpnVrfConfRteMxThrshTime(struct variable *, oid[],
static uint8_t *mplsL3vpnIllLblRcvThrsh(struct variable *, oid[], size_t *, int,
size_t *, WriteMethod **);
+static uint8_t *mplsL3vpnVrfTable(struct variable *, oid[], size_t *, int,
+ size_t *, WriteMethod **);
+
+
static struct variable mpls_l3vpn_variables[] = {
/* BGP version. */
{MPLSL3VPNCONFIGUREDVRFS,
@@ -136,8 +157,168 @@ static struct variable mpls_l3vpn_variables[] = {
3,
{1, 1, 7} },
+ /* Vrf Table */
+ {MPLSL3VPNVRFVPNID,
+ OCTET_STRING,
+ RONLY,
+ mplsL3vpnVrfTable,
+ 5,
+ {1, 2, 2, 1, 2} },
+ {MPLSL3VPNVRFDESC,
+ OCTET_STRING,
+ RONLY,
+ mplsL3vpnVrfTable,
+ 5,
+ {1, 2, 2, 1, 3} },
+ {MPLSL3VPNVRFRD,
+ OCTET_STRING,
+ RONLY,
+ mplsL3vpnVrfTable,
+ 5,
+ {1, 2, 2, 1, 4} },
+ {MPLSL3VPNVRFCREATIONTIME,
+ TIMETICKS,
+ RONLY,
+ mplsL3vpnVrfTable,
+ 5,
+ {1, 2, 2, 1, 5} },
+ {MPLSL3VPNVRFOPERSTATUS,
+ INTEGER,
+ RONLY,
+ mplsL3vpnVrfTable,
+ 5,
+ {1, 2, 2, 1, 6} },
+ {MPLSL3VPNVRFACTIVEINTERFACES,
+ GAUGE32,
+ RONLY,
+ mplsL3vpnVrfTable,
+ 5,
+ {1, 2, 2, 1, 7} },
+ {MPLSL3VPNVRFASSOCIATEDINTERFACES,
+ GAUGE32,
+ RONLY,
+ mplsL3vpnVrfTable,
+ 5,
+ {1, 2, 2, 1, 8} },
+ {MPLSL3VPNVRFCONFMIDRTETHRESH,
+ GAUGE32,
+ RONLY,
+ mplsL3vpnVrfTable,
+ 5,
+ {1, 2, 2, 1, 9} },
+ {MPLSL3VPNVRFCONFHIGHRTETHRSH,
+ GAUGE32,
+ RONLY,
+ mplsL3vpnVrfTable,
+ 5,
+ {1, 2, 2, 1, 10} },
+ {MPLSL3VPNVRFCONFMAXROUTES,
+ GAUGE32,
+ RONLY,
+ mplsL3vpnVrfTable,
+ 5,
+ {1, 2, 2, 1, 11} },
+ {MPLSL3VPNVRFCONFLASTCHANGED,
+ TIMETICKS,
+ RONLY,
+ mplsL3vpnVrfTable,
+ 5,
+ {1, 2, 2, 1, 12} },
+ {MPLSL3VPNVRFCONFROWSTATUS,
+ INTEGER,
+ RONLY,
+ mplsL3vpnVrfTable,
+ 5,
+ {1, 2, 2, 1, 13} },
+ {MPLSL3VPNVRFCONFADMINSTATUS,
+ INTEGER,
+ RONLY,
+ mplsL3vpnVrfTable,
+ 5,
+ {1, 2, 2, 1, 14} },
+ {MPLSL3VPNVRFCONFSTORAGETYPE,
+ INTEGER,
+ RONLY,
+ mplsL3vpnVrfTable,
+ 5,
+ {1, 2, 2, 1, 15} },
};
+/* timeticks are in hundredths of a second */
+static void bgp_mpls_l3vpn_update_timeticks(time_t *counter)
+{
+ struct timeval tv;
+
+ monotime(&tv);
+ *counter = (tv.tv_sec * 100) + (tv.tv_usec / 10000);
+}
+
+static int bgp_mpls_l3vpn_update_last_changed(struct bgp *bgp)
+{
+ if (bgp->snmp_stats)
+ bgp_mpls_l3vpn_update_timeticks(
+ &(bgp->snmp_stats->modify_time));
+ return 0;
+}
+
+static int bgp_init_snmp_stats(struct bgp *bgp)
+{
+ if (is_bgp_vrf_mplsvpn(bgp)) {
+ if (bgp->snmp_stats == NULL) {
+ bgp->snmp_stats = XCALLOC(
+ MTYPE_BGP, sizeof(struct bgp_snmp_stats));
+ /* fix up added routes */
+ if (bgp->snmp_stats)
+ bgp_mpls_l3vpn_update_timeticks(
+ &(bgp->snmp_stats->creation_time));
+ }
+ } else {
+ if (bgp->snmp_stats) {
+ XFREE(MTYPE_BGP, bgp->snmp_stats);
+ bgp->snmp_stats = NULL;
+ }
+ }
+ /* Something changed - update the timestamp */
+ bgp_mpls_l3vpn_update_last_changed(bgp);
+ return 0;
+}
+
+static bool is_bgp_vrf_active(struct bgp *bgp)
+{
+ struct vrf *vrf;
+ struct interface *ifp;
+
+ /* if there is one interface in the vrf which is up then it is deemed
+ * active
+ */
+ vrf = vrf_lookup_by_id(bgp->vrf_id);
+ if (vrf == NULL)
+ return false;
+ RB_FOREACH (ifp, if_name_head, &vrf->ifaces_by_name) {
+ /* if we are in a vrf skip the l3mdev */
+ if (bgp->name && strncmp(ifp->name, bgp->name, VRF_NAMSIZ) == 0)
+ continue;
+
+ if (if_is_up(ifp))
+ return true;
+ }
+ return false;
+}
+
+static int bgp_vrf_check_update_active(struct bgp *bgp, struct interface *ifp)
+{
+ bool new_active = false;
+
+ if (!is_bgp_vrf_mplsvpn(bgp) || bgp->snmp_stats == NULL)
+ return 0;
+ new_active = is_bgp_vrf_active(bgp);
+ if (bgp->snmp_stats->active != new_active) {
+ /* add trap in here */
+ bgp->snmp_stats->active = new_active;
+ }
+ return 0;
+}
+
static uint8_t *mplsL3vpnConfiguredVrfs(struct variable *v, oid name[],
size_t *length, int exact,
size_t *var_len,
@@ -211,7 +392,6 @@ static int write_mplsL3vpnNotificationEnable(int action, uint8_t *var_val,
{
uint32_t intval;
- zlog_debug("PJDR: %s", __func__);
if (var_val_type != ASN_INTEGER) {
return SNMP_ERR_WRONGTYPE;
}
@@ -234,7 +414,6 @@ static uint8_t *mplsL3vpnNotificationEnable(struct variable *v, oid name[],
== MATCH_FAILED)
return NULL;
- zlog_debug("PJDR: %s", __func__);
*write_method = write_mplsL3vpnNotificationEnable;
return SNMP_INTEGER(bgp_mplsvpn_notif_enable);
}
@@ -276,8 +455,149 @@ static uint8_t *mplsL3vpnIllLblRcvThrsh(struct variable *v, oid name[],
}
+/* 1.3.6.1.2.1.10.166.11.1.2.2.1.x = 14*/
+#define VRFTAB_NAMELEN 14
+
+static struct bgp *bgp_lookup_by_name_next(const char *vrf_name)
+{
+ struct bgp *bgp, *bgp_next = NULL;
+ struct listnode *node, *nnode;
+ bool first = false;
+
+ /*
+ * the vrfs are not stored alphabetically but since we are using the
+ * vrf name as an index we need the getnext function to return them
+ * in a atrict order. Thus run through and find the best next one.
+ */
+ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
+ if (!is_bgp_vrf_mplsvpn(bgp))
+ continue;
+ if (strnlen(vrf_name, VRF_NAMSIZ) == 0 && bgp_next == NULL) {
+ first = true;
+ bgp_next = bgp;
+ continue;
+ }
+ if (first || strncmp(bgp->name, vrf_name, VRF_NAMSIZ) > 0) {
+ if (bgp_next == NULL)
+ bgp_next = bgp;
+ else if (strncmp(bgp->name, bgp_next->name, VRF_NAMSIZ)
+ < 0)
+ bgp_next = bgp;
+ }
+ }
+ return bgp_next;
+}
+
+static struct bgp *bgpL3vpnTable_lookup(struct variable *v, oid name[],
+ size_t *length, char *vrf_name,
+ int exact)
+{
+ struct bgp *bgp = NULL;
+ size_t namelen = v ? v->namelen : VRFTAB_NAMELEN;
+ int len;
+
+ if (*length - namelen > VRF_NAMSIZ)
+ return NULL;
+ oid2string(name + namelen, *length - namelen, vrf_name);
+ if (exact) {
+ /* Check the length. */
+ bgp = bgp_lookup_by_name(vrf_name);
+ if (bgp && !is_bgp_vrf_mplsvpn(bgp))
+ return NULL;
+ } else {
+ bgp = bgp_lookup_by_name_next(vrf_name);
+
+ if (bgp == NULL)
+ return NULL;
+
+ len = strnlen(bgp->name, VRF_NAMSIZ);
+ oid_copy_str(name + namelen, bgp->name, len);
+ *length = len + namelen;
+ }
+ return bgp;
+}
+
+static uint8_t *mplsL3vpnVrfTable(struct variable *v, oid name[],
+ size_t *length, int exact, size_t *var_len,
+ WriteMethod **write_method)
+{
+ char vrf_name[VRF_NAMSIZ];
+ struct bgp *l3vpn_bgp;
+
+ if (smux_header_table(v, name, length, exact, var_len, write_method)
+ == MATCH_FAILED)
+ return NULL;
+
+ memset(vrf_name, 0, VRF_NAMSIZ);
+ l3vpn_bgp = bgpL3vpnTable_lookup(v, name, length, vrf_name, exact);
+
+ if (!l3vpn_bgp)
+ return NULL;
+
+ switch (v->magic) {
+ case MPLSL3VPNVRFVPNID:
+ *var_len = 0;
+ return NULL;
+ case MPLSL3VPNVRFDESC:
+ *var_len = strnlen(l3vpn_bgp->name, VRF_NAMSIZ);
+ return (uint8_t *)l3vpn_bgp->name;
+ case MPLSL3VPNVRFRD:
+ /*
+ * this is a horror show but the MIB dicates one RD per vrf
+ * and not one RD per AFI as we (FRR) have. So this little gem
+ * returns the V4 one if it's set OR the v6 one if it's set or
+ * zero-length string id neither are set
+ */
+ memset(rd_buf, 0, RD_ADDRSTRLEN);
+ if (CHECK_FLAG(l3vpn_bgp->vpn_policy[AFI_IP].flags,
+ BGP_VPN_POLICY_TOVPN_RD_SET))
+ prefix_rd2str(&l3vpn_bgp->vpn_policy[AFI_IP].tovpn_rd,
+ rd_buf, sizeof(rd_buf));
+ else if (CHECK_FLAG(l3vpn_bgp->vpn_policy[AFI_IP6].flags,
+ BGP_VPN_POLICY_TOVPN_RD_SET))
+ prefix_rd2str(&l3vpn_bgp->vpn_policy[AFI_IP6].tovpn_rd,
+ rd_buf, sizeof(rd_buf));
+
+ *var_len = strnlen(rd_buf, RD_ADDRSTRLEN);
+ return (uint8_t *)rd_buf;
+ case MPLSL3VPNVRFCREATIONTIME:
+ return SNMP_INTEGER(
+ (uint32_t)l3vpn_bgp->snmp_stats->creation_time);
+ case MPLSL3VPNVRFOPERSTATUS:
+ if (l3vpn_bgp->snmp_stats->active)
+ return SNMP_INTEGER(1);
+ else
+ return SNMP_INTEGER(2);
+ case MPLSL3VPNVRFACTIVEINTERFACES:
+ return SNMP_INTEGER(bgp_vrf_interfaces(l3vpn_bgp, true));
+ case MPLSL3VPNVRFASSOCIATEDINTERFACES:
+ return SNMP_INTEGER(bgp_vrf_interfaces(l3vpn_bgp, false));
+ case MPLSL3VPNVRFCONFMIDRTETHRESH:
+ return SNMP_INTEGER(0);
+ case MPLSL3VPNVRFCONFHIGHRTETHRSH:
+ return SNMP_INTEGER(0);
+ case MPLSL3VPNVRFCONFMAXROUTES:
+ return SNMP_INTEGER(0);
+ case MPLSL3VPNVRFCONFLASTCHANGED:
+ return SNMP_INTEGER(
+ (uint32_t)l3vpn_bgp->snmp_stats->modify_time);
+ case MPLSL3VPNVRFCONFROWSTATUS:
+ return SNMP_INTEGER(1);
+ case MPLSL3VPNVRFCONFADMINSTATUS:
+ return SNMP_INTEGER(1);
+ case MPLSL3VPNVRFCONFSTORAGETYPE:
+ return SNMP_INTEGER(2);
+ return NULL;
+ }
+ return NULL;
+}
+
void bgp_mpls_l3vpn_module_init(void)
{
+ hook_register(bgp_vrf_status_changed, bgp_vrf_check_update_active);
+ hook_register(bgp_snmp_init_stats, bgp_init_snmp_stats);
+ hook_register(bgp_snmp_update_last_changed,
+ bgp_mpls_l3vpn_update_last_changed);
REGISTER_MIB("mplsL3VpnMIB", mpls_l3vpn_variables, variable,
mpls_l3vpn_oid);
}
diff --git a/bgpd/bgp_nb_config.c b/bgpd/bgp_nb_config.c
index 531ff4a60..f2443bd16 100644
--- a/bgpd/bgp_nb_config.c
+++ b/bgpd/bgp_nb_config.c
@@ -32,6 +32,8 @@
#include "bgpd/bgp_io.h"
#include "bgpd/bgp_damp.h"
+DEFINE_HOOK(bgp_snmp_init_stats, (struct bgp *bgp), (bgp))
+
FRR_CFG_DEFAULT_ULONG(BGP_CONNECT_RETRY,
{ .val_ulong = 10, .match_profile = "datacenter", },
{ .val_ulong = 120 },
@@ -9862,6 +9864,7 @@ static int bgp_global_afi_safi_ip_unicast_vpn_config_import_export_vpn_modify(
UNSET_FLAG(bgp->af_flags[afi][safi], flag);
}
+ hook_call(bgp_snmp_init_stats, bgp);
return NB_OK;
}
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index a89c245e2..8d06a4b37 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -127,6 +127,7 @@ FRR_CFG_DEFAULT_BOOL(BGP_SUPPRESS_DUPLICATES,
DEFINE_HOOK(bgp_inst_config_write,
(struct bgp *bgp, struct vty *vty),
(bgp, vty))
+DEFINE_HOOK(bgp_snmp_update_last_changed, (struct bgp *bgp), (bgp))
#define GR_NO_OPER \
"The Graceful Restart No Operation was executed as cmd same as previous one."
@@ -9141,6 +9142,7 @@ DEFPY (af_label_vpn_export,
vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, afi,
bgp_get_default(), bgp);
+ hook_call(bgp_snmp_update_last_changed, bgp);
return CMD_SUCCESS;
}
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index f7c4b04ad..ca7da8070 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -67,6 +67,10 @@
/* All information about zebra. */
struct zclient *zclient = NULL;
+/* hook to indicate vrf status change for SNMP */
+DEFINE_HOOK(bgp_vrf_status_changed, (struct bgp *bgp, struct interface *ifp),
+ (bgp, ifp))
+
/* Can we install into zebra? */
static inline bool bgp_install_info_to_zebra(struct bgp *bgp)
{
@@ -212,8 +216,10 @@ static int bgp_ifp_destroy(struct interface *ifp)
if (BGP_DEBUG(zebra, ZEBRA))
zlog_debug("Rx Intf del VRF %u IF %s", ifp->vrf_id, ifp->name);
- if (bgp)
+ if (bgp) {
bgp_update_interface_nbrs(bgp, ifp, NULL);
+ hook_call(bgp_vrf_status_changed, bgp, ifp);
+ }
bgp_mac_del_mac_entry(ifp);
@@ -243,6 +249,7 @@ static int bgp_ifp_up(struct interface *ifp)
for (ALL_LIST_ELEMENTS(ifp->nbr_connected, node, nnode, nc))
bgp_nbr_connected_add(bgp, nc);
+ hook_call(bgp_vrf_status_changed, bgp, ifp);
return 0;
}
@@ -297,6 +304,7 @@ static int bgp_ifp_down(struct interface *ifp)
}
}
+ hook_call(bgp_vrf_status_changed, bgp, ifp);
return 0;
}
@@ -461,6 +469,8 @@ static int bgp_interface_vrf_update(ZAPI_CALLBACK_ARGS)
for (ALL_LIST_ELEMENTS(ifp->nbr_connected, node, nnode, nc))
bgp_nbr_connected_add(bgp, nc);
+
+ hook_call(bgp_vrf_status_changed, bgp, ifp);
return 0;
}
@@ -2963,6 +2973,7 @@ static int bgp_ifp_create(struct interface *ifp)
bgp_mac_add_mac_entry(ifp);
bgp_update_interface_nbrs(bgp, ifp, ifp);
+ hook_call(bgp_vrf_status_changed, bgp, ifp);
return 0;
}
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index edd90d704..c414c93a8 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -3704,6 +3704,7 @@ void bgp_free(struct bgp *bgp)
XFREE(MTYPE_BGP, bgp->name);
XFREE(MTYPE_BGP, bgp->name_pretty);
+ XFREE(MTYPE_BGP, bgp->snmp_stats);
XFREE(MTYPE_BGP, bgp);
}
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 65c7233e0..346d904da 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -310,6 +310,13 @@ enum bgp_link_bw_handling {
RB_HEAD(bgp_es_vrf_rb_head, bgp_evpn_es_vrf);
RB_PROTOTYPE(bgp_es_vrf_rb_head, bgp_evpn_es_vrf, rb_node, bgp_es_vrf_rb_cmp);
+struct bgp_snmp_stats {
+ /* SNMP variables for mplsL3Vpn*/
+ time_t creation_time;
+ time_t modify_time;
+ bool active;
+};
+
/* BGP instance structure. */
struct bgp {
/* AS number of this BGP instance. */
@@ -363,6 +370,8 @@ struct bgp {
uint32_t subgrps_deleted;
} update_group_stats;
+ struct bgp_snmp_stats *snmp_stats;
+
/* BGP configuration. */
uint16_t config;
#define BGP_CONFIG_CLUSTER_ID (1 << 0)
@@ -2165,23 +2174,6 @@ static inline int afindex(afi_t afi, safi_t safi)
}
}
-static inline bool is_bgp_vrf_active(struct bgp *bgp)
-{
- struct vrf *vrf;
- struct interface *ifp;
-
- /* if there is one interface in the vrf which is up then it is deemed
- * active
- */
- vrf = vrf_lookup_by_name(bgp->name);
- if (vrf == NULL)
- return false;
- RB_FOREACH (ifp, if_name_head, &vrf->ifaces_by_name)
- if (if_is_up(ifp))
- return true;
- return false;
-}
-
/* If the peer is not a peer-group but is bound to a peer-group return 1 */
static inline int peer_group_active(struct peer *peer)
{
@@ -2263,6 +2255,27 @@ static inline struct vrf *bgp_vrf_lookup_by_instance_type(struct bgp *bgp)
return vrf;
}
+static inline uint32_t bgp_vrf_interfaces(struct bgp *bgp, bool active)
+{
+ struct vrf *vrf;
+ struct interface *ifp;
+ uint32_t count = 0;
+
+ /* if there is one interface in the vrf which is up then it is deemed
+ * active
+ */
+ vrf = bgp_vrf_lookup_by_instance_type(bgp);
+ if (vrf == NULL)
+ return 0;
+ RB_FOREACH (ifp, if_name_head, &vrf->ifaces_by_name) {
+ if (strncmp(ifp->name, bgp->name, VRF_NAMSIZ) == 0)
+ continue;
+ if (!active || if_is_up(ifp))
+ count++;
+ }
+ return count;
+}
+
/* Link BGP instance to VRF. */
static inline void bgp_vrf_link(struct bgp *bgp, struct vrf *vrf)
{
@@ -2300,7 +2313,11 @@ extern int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as,
enum bgp_instance_type inst_type);
/* Hooks */
-DECLARE_HOOK(peer_status_changed, (struct peer * peer), (peer))
+DECLARE_HOOK(bgp_vrf_status_changed, (struct bgp *bgp, struct interface *ifp),
+ (bgp, ifp))
+DECLARE_HOOK(peer_status_changed, (struct peer *peer), (peer))
+DECLARE_HOOK(bgp_snmp_init_stats, (struct bgp *bgp), (bgp))
+DECLARE_HOOK(bgp_snmp_update_last_changed, (struct bgp *bgp), (bgp))
void peer_nsf_stop(struct peer *peer);
#endif /* _QUAGGA_BGPD_H */
diff --git a/lib/smux.h b/lib/smux.h
index 6896f0235..0efe029d3 100644
--- a/lib/smux.h
+++ b/lib/smux.h
@@ -106,6 +106,8 @@ extern int oid_compare(const oid *, int, const oid *, int);
extern void oid2in_addr(oid[], int, struct in_addr *);
extern void *oid_copy(void *, const void *, size_t);
extern void oid_copy_addr(oid[], const struct in_addr *, int);
+extern void oid2string(oid oid[], int len, char *string);
+extern void oid_copy_str(oid oid[], const char *string, int len);
#ifdef __cplusplus
}
diff --git a/lib/snmp.c b/lib/snmp.c
index 736a3c62b..cc317d7a3 100644
--- a/lib/snmp.c
+++ b/lib/snmp.c
@@ -78,6 +78,34 @@ void oid_copy_addr(oid oid[], const struct in_addr *addr, int len)
oid[i] = *pnt++;
}
+void oid2string(oid oid[], int len, char *string)
+{
+ int i;
+ uint8_t *pnt;
+
+ if (len == 0)
+ return;
+
+ pnt = (uint8_t *)string;
+
+ for (i = 0; i < len; i++)
+ *pnt++ = oid[i];
+}
+
+void oid_copy_str(oid oid[], const char *string, int len)
+{
+ int i;
+ const uint8_t *pnt;
+
+ if (len == 0)
+ return;
+
+ pnt = (uint8_t *)string;
+
+ for (i = 0; i < len; i++)
+ oid[i] = *pnt++;
+}
+
int smux_header_generic(struct variable *v, oid *name, size_t *length,
int exact, size_t *var_len, WriteMethod **write_method)
{