]> git.puffer.fish Git - matthieu/frr.git/commitdiff
bgpd, lib: add mplsL3VpnVrf table
authorPat Ruddy <pat@voltanet.io>
Mon, 28 Sep 2020 15:35:35 +0000 (16:35 +0100)
committerPat Ruddy <pat@voltanet.io>
Tue, 2 Feb 2021 09:37:06 +0000 (09:37 +0000)
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>
bgpd/bgp_mplsvpn_snmp.c
bgpd/bgp_nb_config.c
bgpd/bgp_vty.c
bgpd/bgp_zebra.c
bgpd/bgpd.c
bgpd/bgpd.h
lib/smux.h
lib/snmp.c

index 0a8d39cb95586aa6cae30168dcf6937a24737863..65fbf5413d571edb6a4d3c154827ef3379755b6f 100644 (file)
@@ -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);
 }
index 531ff4a60af2e69c43930ba72bf06490f7e71699..f2443bd164e129f29588bce872b54a60001d9963 100644 (file)
@@ -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;
 }
 
index a89c245e2a93dfabf0d984cc9f606e45919c920c..8d06a4b37428d21e6d2dde37620e8fb3d979ecc0 100644 (file)
@@ -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;
 }
 
index f7c4b04adffa5d40beb18701fab22da571d8c5dd..ca7da8070c050ee5ffae0d5e87053794576b36e9 100644 (file)
 /* 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;
 }
 
index edd90d7040351cbd6a441f9cb62119b40ba1f74c..c414c93a8327e873bdf7664f1452a5b9cee2de4b 100644 (file)
@@ -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);
 }
index 65c7233e03e76430c6c99ed071a6e262f0da9546..346d904da5aacc775fd62f2032b82689c21cdf61 100644 (file)
@@ -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 */
index 6896f02354951dbd1435a050041b0852d99e38a2..0efe029d3d9f015ab1757852be38f0e210c890c6 100644 (file)
@@ -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
 }
index 736a3c62b85f494da4d9112990dd83c4f7e0dcc2..cc317d7a3b96de20eb1c4035af7d73eaf48268e3 100644 (file)
@@ -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)
 {