]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #12539 from donaldsharp/bgp_debug_prefix_mem_leak
authorRuss White <russ@riw.us>
Tue, 20 Dec 2022 16:20:19 +0000 (11:20 -0500)
committerGitHub <noreply@github.com>
Tue, 20 Dec 2022 16:20:19 +0000 (11:20 -0500)
bgpd: When allocating prefix, free it when we are already tracking it

13 files changed:
bgpd/bgp_attr.c
bgpd/bgp_snmp_bgp4v2.c
ospf6d/ospf6_neighbor.c
ospfd/ospf_spf.c
ospfd/ospf_vty.c
ospfd/ospfd.c
tests/topotests/bgp_snmp_bgp4v2mib/r1/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_snmp_bgp4v2mib/r1/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_snmp_bgp4v2mib/r2/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_snmp_bgp4v2mib/r2/snmpd.conf [new file with mode: 0644]
tests/topotests/bgp_snmp_bgp4v2mib/r2/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_snmp_bgp4v2mib/test_bgp_snmp_bgp4v2mib.py [new file with mode: 0755]
tests/topotests/lib/snmptest.py

index 72905a6acb6f21da00728018ac0789e6bb17a116..f3848db072df765de6f1e149a85c824c6d7efb3b 100644 (file)
@@ -4682,7 +4682,7 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
        }
 
        /* AIGP */
-       if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AIGP) &&
+       if (bpi && attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AIGP) &&
            (CHECK_FLAG(peer->flags, PEER_FLAG_AIGP) ||
             peer->sort != BGP_PEER_EBGP)) {
                /* At the moment only AIGP Metric TLV exists for AIGP
index 2d70aa94d35b0c7ea1f4b02db03f0c296abf856b..d8d8549960a26dfaa52ad4ff6301389e94ca485f 100644 (file)
@@ -145,10 +145,24 @@ static struct peer *bgpv2PeerTable_lookup(struct variable *v, oid name[],
        size_t namelen = v ? v->namelen : BGP4V2_PEER_ENTRY_OFFSET;
        oid *offset = name + namelen;
        sa_family_t family = name[namelen - 1] == 4 ? AF_INET : AF_INET6;
+       int afi_len = IN_ADDR_SIZE;
+       size_t offsetlen = *length - namelen;
+
+       if (family == AF_INET6)
+               afi_len = IN6_ADDR_SIZE;
+
+       /* Somehow with net-snmp 5.7.3, every OID item in an array
+        * is uninitialized and has a max random value, let's zero it.
+        * With 5.8, 5.9, it works fine even without this hack.
+        */
+       if (!offsetlen) {
+               for (int i = 0; i < afi_len; i++)
+                       *(offset + i) = 0;
+       }
 
        if (exact) {
                if (family == AF_INET) {
-                       oid2in_addr(offset, IN_ADDR_SIZE, &addr->ip._v4_addr);
+                       oid2in_addr(offset, afi_len, &addr->ip._v4_addr);
                        peer = peer_lookup_all_vrf(addr);
                        return peer;
                } else if (family == AF_INET6) {
@@ -163,11 +177,11 @@ static struct peer *bgpv2PeerTable_lookup(struct variable *v, oid name[],
                switch (sockunion_family(&peer->su)) {
                case AF_INET:
                        oid_copy_in_addr(offset, &peer->su.sin.sin_addr);
-                       *length = IN_ADDR_SIZE + namelen;
+                       *length = afi_len + namelen;
                        return peer;
                case AF_INET6:
                        oid_copy_in6_addr(offset, &peer->su.sin6.sin6_addr);
-                       *length = IN6_ADDR_SIZE + namelen;
+                       *length = afi_len + namelen;
                        return peer;
                default:
                        break;
@@ -367,9 +381,10 @@ static uint8_t *bgpv2PeerErrorsTable(struct variable *v, oid name[],
                }
                return SNMP_STRING("");
        case BGP4V2_PEER_LAST_ERROR_SENT_DATA:
-               if (peer->last_reset == PEER_DOWN_NOTIFY_SEND ||
-                   peer->last_reset == PEER_DOWN_RTT_SHUTDOWN ||
-                   peer->last_reset == PEER_DOWN_USER_SHUTDOWN)
+               if ((peer->last_reset == PEER_DOWN_NOTIFY_SEND ||
+                    peer->last_reset == PEER_DOWN_RTT_SHUTDOWN ||
+                    peer->last_reset == PEER_DOWN_USER_SHUTDOWN) &&
+                   peer->notify.data)
                        return SNMP_STRING(peer->notify.data);
                else
                        return SNMP_STRING("");
@@ -420,7 +435,7 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length,
 {
        oid *offset;
        int offsetlen;
-       struct bgp_path_info *path;
+       struct bgp_path_info *path, *min;
        struct bgp_dest *dest;
        union sockunion su;
        unsigned int len;
@@ -500,6 +515,8 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length,
                else
                        addr->prefixlen = len * 8;
 
+               addr->family = family;
+
                dest = bgp_node_get(bgp->rib[afi][SAFI_UNICAST], addr);
 
                offset++;
@@ -525,8 +542,8 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length,
        if (!dest)
                return NULL;
 
-       while ((dest = bgp_route_next(dest))) {
-               struct bgp_path_info *min = NULL;
+       do {
+               min = NULL;
 
                for (path = bgp_dest_get_bgp_path_info(dest); path;
                     path = path->next) {
@@ -564,6 +581,7 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length,
 
                        offset = name + namelen;
 
+                       /* Encode prefix into OID */
                        if (family == AF_INET)
                                oid_copy_in_addr(offset, &rn_p->u.prefix4);
                        else
@@ -573,6 +591,7 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length,
                        *offset = rn_p->prefixlen;
                        offset++;
 
+                       /* Encode peer's IP into OID */
                        if (family == AF_INET) {
                                oid_copy_in_addr(offset,
                                                 &min->peer->su.sin.sin_addr);
@@ -584,6 +603,7 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length,
                        }
 
                        addr->prefixlen = rn_p->prefixlen;
+                       addr->family = rn_p->family;
 
                        bgp_dest_unlock_node(dest);
 
@@ -594,7 +614,7 @@ bgp4v2PathAttrLookup(struct variable *v, oid name[], size_t *length,
                        memset(&paddr.ip._v4_addr, 0, afi_len);
                else
                        memset(&paddr.ip._v6_addr, 0, afi_len);
-       }
+       } while ((dest = bgp_route_next(dest)));
 
        return NULL;
 }
@@ -733,7 +753,7 @@ static uint8_t *bgp4v2PathAttrTable(struct variable *v, oid name[],
        case BGP4V2_NLRI_MED:
                if (CHECK_FLAG(path->attr->flag,
                               ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)))
-                       return SNMP_INTEGER(path->attr->local_pref);
+                       return SNMP_INTEGER(path->attr->med);
                else
                        return SNMP_INTEGER(0);
        case BGP4V2_NLRI_ATOMIC_AGGREGATE:
index 439b94c9af039d76f3b6c3bcdcfa968bdc265fd9..a4ba1fb5696bf72fc927e9b1da97bbabfb986b2c 100644 (file)
@@ -106,6 +106,23 @@ struct ospf6_neighbor *ospf6_area_neighbor_lookup(struct ospf6_area *area,
        return NULL;
 }
 
+static void ospf6_neighbor_clear_ls_lists(struct ospf6_neighbor *on)
+{
+       struct ospf6_lsa *lsa;
+       struct ospf6_lsa *lsanext;
+
+       ospf6_lsdb_remove_all(on->summary_list);
+       if (on->last_ls_req) {
+               ospf6_lsa_unlock(on->last_ls_req);
+               on->last_ls_req = NULL;
+       }
+       ospf6_lsdb_remove_all(on->request_list);
+       for (ALL_LSDB(on->retrans_list, lsa, lsanext)) {
+               ospf6_decrement_retrans_count(lsa);
+               ospf6_lsdb_remove(lsa, on->retrans_list);
+       }
+}
+
 /* create ospf6_neighbor */
 struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id,
                                             struct ospf6_interface *oi)
@@ -147,14 +164,7 @@ struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id,
 
 void ospf6_neighbor_delete(struct ospf6_neighbor *on)
 {
-       struct ospf6_lsa *lsa, *lsanext;
-
-       ospf6_lsdb_remove_all(on->summary_list);
-       ospf6_lsdb_remove_all(on->request_list);
-       for (ALL_LSDB(on->retrans_list, lsa, lsanext)) {
-               ospf6_decrement_retrans_count(lsa);
-               ospf6_lsdb_remove(lsa, on->retrans_list);
-       }
+       ospf6_neighbor_clear_ls_lists(on);
 
        ospf6_lsdb_remove_all(on->dbdesc_list);
        ospf6_lsdb_remove_all(on->lsupdate_list);
@@ -339,12 +349,7 @@ void negotiation_done(struct thread *thread)
                zlog_debug("Neighbor Event %s: *NegotiationDone*", on->name);
 
        /* clear ls-list */
-       ospf6_lsdb_remove_all(on->summary_list);
-       ospf6_lsdb_remove_all(on->request_list);
-       for (ALL_LSDB(on->retrans_list, lsa, lsanext)) {
-               ospf6_decrement_retrans_count(lsa);
-               ospf6_lsdb_remove(lsa, on->retrans_list);
-       }
+       ospf6_neighbor_clear_ls_lists(on);
 
        /* Interface scoped LSAs */
        for (ALL_LSDB(on->ospf6_if->lsdb, lsa, lsanext)) {
@@ -464,7 +469,6 @@ void loading_done(struct thread *thread)
 void adj_ok(struct thread *thread)
 {
        struct ospf6_neighbor *on;
-       struct ospf6_lsa *lsa, *lsanext;
 
        on = (struct ospf6_neighbor *)THREAD_ARG(thread);
        assert(on);
@@ -486,19 +490,13 @@ void adj_ok(struct thread *thread)
        } else if (on->state >= OSPF6_NEIGHBOR_EXSTART && !need_adjacency(on)) {
                ospf6_neighbor_state_change(OSPF6_NEIGHBOR_TWOWAY, on,
                                            OSPF6_NEIGHBOR_EVENT_ADJ_OK);
-               ospf6_lsdb_remove_all(on->summary_list);
-               ospf6_lsdb_remove_all(on->request_list);
-               for (ALL_LSDB(on->retrans_list, lsa, lsanext)) {
-                       ospf6_decrement_retrans_count(lsa);
-                       ospf6_lsdb_remove(lsa, on->retrans_list);
-               }
+               ospf6_neighbor_clear_ls_lists(on);
        }
 }
 
 void seqnumber_mismatch(struct thread *thread)
 {
        struct ospf6_neighbor *on;
-       struct ospf6_lsa *lsa, *lsanext;
 
        on = (struct ospf6_neighbor *)THREAD_ARG(thread);
        assert(on);
@@ -515,12 +513,7 @@ void seqnumber_mismatch(struct thread *thread)
        SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT);
        SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT);
 
-       ospf6_lsdb_remove_all(on->summary_list);
-       ospf6_lsdb_remove_all(on->request_list);
-       for (ALL_LSDB(on->retrans_list, lsa, lsanext)) {
-               ospf6_decrement_retrans_count(lsa);
-               ospf6_lsdb_remove(lsa, on->retrans_list);
-       }
+       ospf6_neighbor_clear_ls_lists(on);
 
        THREAD_OFF(on->thread_send_dbdesc);
        on->dbdesc_seqnum++; /* Incr seqnum as per RFC2328, sec 10.3 */
@@ -532,7 +525,6 @@ void seqnumber_mismatch(struct thread *thread)
 void bad_lsreq(struct thread *thread)
 {
        struct ospf6_neighbor *on;
-       struct ospf6_lsa *lsa, *lsanext;
 
        on = (struct ospf6_neighbor *)THREAD_ARG(thread);
        assert(on);
@@ -549,12 +541,7 @@ void bad_lsreq(struct thread *thread)
        SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT);
        SET_FLAG(on->dbdesc_bits, OSPF6_DBDESC_IBIT);
 
-       ospf6_lsdb_remove_all(on->summary_list);
-       ospf6_lsdb_remove_all(on->request_list);
-       for (ALL_LSDB(on->retrans_list, lsa, lsanext)) {
-               ospf6_decrement_retrans_count(lsa);
-               ospf6_lsdb_remove(lsa, on->retrans_list);
-       }
+       ospf6_neighbor_clear_ls_lists(on);
 
        THREAD_OFF(on->thread_send_dbdesc);
        on->dbdesc_seqnum++; /* Incr seqnum as per RFC2328, sec 10.3 */
@@ -567,7 +554,6 @@ void bad_lsreq(struct thread *thread)
 void oneway_received(struct thread *thread)
 {
        struct ospf6_neighbor *on;
-       struct ospf6_lsa *lsa, *lsanext;
 
        on = (struct ospf6_neighbor *)THREAD_ARG(thread);
        assert(on);
@@ -582,12 +568,7 @@ void oneway_received(struct thread *thread)
                                    OSPF6_NEIGHBOR_EVENT_ONEWAY_RCVD);
        thread_add_event(master, neighbor_change, on->ospf6_if, 0, NULL);
 
-       ospf6_lsdb_remove_all(on->summary_list);
-       ospf6_lsdb_remove_all(on->request_list);
-       for (ALL_LSDB(on->retrans_list, lsa, lsanext)) {
-               ospf6_decrement_retrans_count(lsa);
-               ospf6_lsdb_remove(lsa, on->retrans_list);
-       }
+       ospf6_neighbor_clear_ls_lists(on);
 
        THREAD_OFF(on->thread_send_dbdesc);
        THREAD_OFF(on->thread_send_lsreq);
index 4f60ce22a9ecbbb5200be837e72df77d3265749e..58fcbfa4a98f080fbc3d12d0fe734aad5de03249 100644 (file)
@@ -1956,9 +1956,10 @@ static void ospf_spf_calculate_schedule_worker(struct thread *thread)
        rt_time = monotime_since(&start_time, NULL);
 
        /* Free old all routers routing table */
-       if (ospf->oall_rtrs)
-               /* ospf_route_delete (ospf->old_rtrs); */
+       if (ospf->oall_rtrs) {
                ospf_rtrs_free(ospf->oall_rtrs);
+               ospf->oall_rtrs = NULL;
+       }
 
        /* Update all routers routing table */
        ospf->oall_rtrs = ospf->all_rtrs;
@@ -1967,9 +1968,10 @@ static void ospf_spf_calculate_schedule_worker(struct thread *thread)
        ospf_apiserver_notify_reachable(ospf->oall_rtrs, ospf->all_rtrs);
 #endif
        /* Free old ABR/ASBR routing table */
-       if (ospf->old_rtrs)
-               /* ospf_route_delete (ospf->old_rtrs); */
+       if (ospf->old_rtrs) {
                ospf_rtrs_free(ospf->old_rtrs);
+               ospf->old_rtrs = NULL;
+       }
 
        /* Update ABR/ASBR routing table */
        ospf->old_rtrs = ospf->new_rtrs;
index 4c10597872ab4c05b0dbc320f407d1b710d87b13..43b7de552ad1c1addd4a2442fb19b8c62ca9eeb7 100644 (file)
@@ -6614,14 +6614,17 @@ static void show_lsa_detail_proc(struct vty *vty, struct route_table *rt,
                route_lock_node(start);
                for (rn = start; rn; rn = route_next_until(rn, start))
                        if ((lsa = rn->info)) {
-                               if (json) {
-                                       json_lsa = json_object_new_object();
-                                       json_object_array_add(json, json_lsa);
-                               }
+                               if (show_function[lsa->data->type] != NULL) {
+                                       if (json) {
+                                               json_lsa =
+                                                       json_object_new_object();
+                                               json_object_array_add(json,
+                                                                     json_lsa);
+                                       }
 
-                               if (show_function[lsa->data->type] != NULL)
                                        show_function[lsa->data->type](
                                                vty, lsa, json_lsa);
+                               }
                        }
                route_unlock_node(start);
        }
@@ -6640,9 +6643,6 @@ static void show_lsa_detail(struct vty *vty, struct ospf *ospf, int type,
        json_object *json_areas = NULL;
        json_object *json_lsa_array = NULL;
 
-       if (json)
-               json_lsa_type = json_object_new_object();
-
        switch (type) {
        case OSPF_AS_EXTERNAL_LSA:
        case OSPF_OPAQUE_AS_LSA:
@@ -6685,6 +6685,7 @@ static void show_lsa_detail(struct vty *vty, struct ospf *ospf, int type,
                }
 
                if (json) {
+                       json_lsa_type = json_object_new_object();
                        json_object_object_add(json_lsa_type, "areas",
                                               json_areas);
                        json_object_object_add(json,
@@ -7158,6 +7159,9 @@ DEFUN (show_ip_ospf_database_max,
                                vty_out(vty,
                                        "%% OSPF is not enabled in vrf %s\n",
                                        vrf_name);
+                               if (uj)
+                                       json_object_free(json);
+
                                return CMD_SUCCESS;
                        }
                        ret = (show_ip_ospf_database_common(
@@ -7169,6 +7173,9 @@ DEFUN (show_ip_ospf_database_max,
                ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
                if (ospf == NULL || !ospf->oi_running) {
                        vty_out(vty, "%% OSPF is not enabled in vrf default\n");
+                       if (uj)
+                               json_object_free(json);
+
                        return CMD_SUCCESS;
                }
 
index 2403b567a5744144008c0679f39af7a1290ffdbe..a5d40ad176ee599b0c2bb115503ab72168aa0f4d 100644 (file)
@@ -852,6 +852,10 @@ static void ospf_finish_final(struct ospf *ospf)
                        ospf_route_delete(ospf, ospf->new_table);
                ospf_route_table_free(ospf->new_table);
        }
+       if (ospf->oall_rtrs)
+               ospf_rtrs_free(ospf->oall_rtrs);
+       if (ospf->all_rtrs)
+               ospf_rtrs_free(ospf->all_rtrs);
        if (ospf->old_rtrs)
                ospf_rtrs_free(ospf->old_rtrs);
        if (ospf->new_rtrs)
diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/r1/bgpd.conf b/tests/topotests/bgp_snmp_bgp4v2mib/r1/bgpd.conf
new file mode 100644 (file)
index 0000000..d82a21e
--- /dev/null
@@ -0,0 +1,31 @@
+!
+router bgp 65001
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ no bgp default ipv4-unicast
+ neighbor 192.168.12.2 remote-as external
+ neighbor 192.168.12.2 timers 1 3
+ neighbor 192.168.12.2 timers connect 1
+ neighbor 2001:db8::12:2 remote-as external
+ neighbor 2001:db8::12:2 timers 1 3
+ neighbor 2001:db8::12:2 timers connect 1
+ !
+ address-family ipv4 unicast
+  network 10.0.0.0/31 route-map p1
+  network 10.0.0.2/32 route-map p2
+  neighbor 192.168.12.2 activate
+ exit-address-family
+ address-family ipv6 unicast
+  network 2001:db8::1/128 route-map p1
+  network 2001:db8:1::/56 route-map p2
+  neighbor 2001:db8::12:2 activate
+ exit-address-family
+!
+route-map p1 permit 10
+ set metric 1
+exit
+route-map p2 permit 10
+ set metric 2
+ set origin incomplete
+exit
+!
diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/r1/zebra.conf b/tests/topotests/bgp_snmp_bgp4v2mib/r1/zebra.conf
new file mode 100644 (file)
index 0000000..0807e89
--- /dev/null
@@ -0,0 +1,5 @@
+!
+interface r1-eth0
+ ip address 192.168.12.1/24
+ ipv6 address 2001:db8::12:1/64
+!
diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/r2/bgpd.conf b/tests/topotests/bgp_snmp_bgp4v2mib/r2/bgpd.conf
new file mode 100644 (file)
index 0000000..3512e66
--- /dev/null
@@ -0,0 +1,23 @@
+!
+debug bgp updates
+!
+router bgp 65002
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ no bgp default ipv4-unicast
+ neighbor 192.168.12.1 remote-as external
+ neighbor 192.168.12.1 timers 1 3
+ neighbor 192.168.12.1 timers connect 1
+ neighbor 2001:db8::12:1 remote-as external
+ neighbor 2001:db8::12:1 timers 1 3
+ neighbor 2001:db8::12:1 timers connect 1
+ !
+ address-family ipv4 unicast
+  neighbor 192.168.12.1 activate
+ exit-address-family
+ address-family ipv6 unicast
+  neighbor 2001:db8::12:1 activate
+ exit-address-family
+!
+agentx
+!
diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/r2/snmpd.conf b/tests/topotests/bgp_snmp_bgp4v2mib/r2/snmpd.conf
new file mode 100644 (file)
index 0000000..032b93b
--- /dev/null
@@ -0,0 +1,17 @@
+agentAddress 127.0.0.1,[::1]
+
+group public_group v1 public
+group public_group v2c public
+access public_group "" any noauth prefix all all none
+
+rocommunity public default
+
+view all included .1
+
+iquerySecName frr
+rouser frr
+
+master agentx
+
+agentXSocket /etc/frr/agentx
+agentXPerms 777 755 root frr
diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/r2/zebra.conf b/tests/topotests/bgp_snmp_bgp4v2mib/r2/zebra.conf
new file mode 100644 (file)
index 0000000..db6d700
--- /dev/null
@@ -0,0 +1,5 @@
+!
+interface r2-eth0
+ ip address 192.168.12.2/24
+ ipv6 address 2001:db8::12:2/64
+!
diff --git a/tests/topotests/bgp_snmp_bgp4v2mib/test_bgp_snmp_bgp4v2mib.py b/tests/topotests/bgp_snmp_bgp4v2mib/test_bgp_snmp_bgp4v2mib.py
new file mode 100755 (executable)
index 0000000..53ca109
--- /dev/null
@@ -0,0 +1,248 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2022 Donatas Abraitis <donatas@opensourcerouting.org>
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+Test some of the BGP4V2-MIB entries.
+"""
+
+import os
+import sys
+import json
+from time import sleep
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.snmptest import SnmpTester
+from lib import topotest
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.snmp]
+
+
+def build_topo(tgen):
+    tgen.add_router("r1")
+    tgen.add_router("r2")
+
+    switch = tgen.add_switch("s1")
+    switch.add_link(tgen.gears["r1"])
+    switch.add_link(tgen.gears["r2"])
+
+
+def setup_module(mod):
+    snmpd = os.system("which snmpd")
+    if snmpd:
+        error_msg = "SNMP not installed - skipping"
+        pytest.skip(error_msg)
+
+    tgen = Topogen(build_topo, mod.__name__)
+    tgen.start_topology()
+
+    for rname, router in tgen.routers().items():
+        router.load_config(
+            TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+        )
+        router.load_config(
+            TopoRouter.RD_BGP,
+            os.path.join(CWD, "{}/bgpd.conf".format(rname)),
+            "-M snmp",
+        )
+        router.load_config(
+            TopoRouter.RD_SNMP,
+            os.path.join(CWD, "{}/snmpd.conf".format(rname)),
+            "-Le -Ivacm_conf,usmConf,iquery -V -DAgentX",
+        )
+
+    tgen.start_router()
+
+
+def teardown_module(mod):
+    tgen = get_topogen()
+    tgen.stop_topology()
+
+
+def test_bgp_snmp_bgp4v2():
+    tgen = get_topogen()
+
+    r2 = tgen.gears["r2"]
+
+    def _bgp_converge_summary():
+        output = json.loads(r2.vtysh_cmd("show bgp summary json"))
+        expected = {
+            "ipv4Unicast": {
+                "peers": {
+                    "192.168.12.1": {
+                        "state": "Established",
+                        "pfxRcd": 2,
+                    }
+                }
+            },
+            "ipv6Unicast": {
+                "peers": {
+                    "2001:db8::12:1": {
+                        "state": "Established",
+                        "pfxRcd": 2,
+                    }
+                }
+            },
+        }
+        return topotest.json_cmp(output, expected)
+
+    test_func = functools.partial(_bgp_converge_summary)
+    _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+    assert result is None, "Can't see connections established"
+
+    def _bgp_converge_prefixes():
+        output = json.loads(r2.vtysh_cmd("show bgp all json"))
+        expected = {
+            "ipv4Unicast": {
+                "routes": {
+                    "10.0.0.0/31": [
+                        {
+                            "metric": 1,
+                            "origin": "IGP",
+                        }
+                    ],
+                    "10.0.0.2/32": [
+                        {
+                            "metric": 2,
+                            "origin": "incomplete",
+                        }
+                    ],
+                }
+            },
+            "ipv6Unicast": {
+                "routes": {
+                    "2001:db8::1/128": [
+                        {
+                            "metric": 1,
+                            "origin": "IGP",
+                        }
+                    ],
+                    "2001:db8:1::/56": [
+                        {
+                            "metric": 2,
+                            "origin": "incomplete",
+                        }
+                    ],
+                }
+            },
+        }
+        return topotest.json_cmp(output, expected)
+
+    test_func = functools.partial(_bgp_converge_prefixes)
+    _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+    assert result is None, "Can't see prefixes from R1"
+
+    snmp = SnmpTester(r2, "localhost", "public", "2c", "-Ln -On")
+
+    def _snmpwalk_remote_addr():
+        expected = {
+            "1.3.6.1.3.5.1.1.2.1.5.1.4.192.168.12.1": "C0 A8 0C 01",
+            "1.3.6.1.3.5.1.1.2.1.5.2.16.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "20 01 0D B8 00 00 00 00 00 00 00 00 00 12 00 01",
+        }
+
+        # bgp4V2PeerRemoteAddr
+        output, _ = snmp.walk(".1.3.6.1.3.5.1.1.2.1.5")
+        return output == expected
+
+    _, result = topotest.run_and_expect(_snmpwalk_remote_addr, True, count=10, wait=1)
+    assertmsg = "Can't fetch SNMP for bgp4V2PeerRemoteAddr"
+    assert result, assertmsg
+
+    def _snmpwalk_peer_state():
+        expected = {
+            "1.3.6.1.3.5.1.1.2.1.13.1.4.192.168.12.1": "6",
+            "1.3.6.1.3.5.1.1.2.1.13.2.16.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "6",
+        }
+
+        # bgp4V2PeerState
+        output, _ = snmp.walk(".1.3.6.1.3.5.1.1.2.1.13")
+        return output == expected
+
+    _, result = topotest.run_and_expect(_snmpwalk_peer_state, True, count=10, wait=1)
+    assertmsg = "Can't fetch SNMP for bgp4V2PeerState"
+    assert result, assertmsg
+
+    def _snmpwalk_peer_last_error_code_received():
+        expected = {
+            "1.3.6.1.3.5.1.1.3.1.1.1.4.192.168.12.1": "0",
+            "1.3.6.1.3.5.1.1.3.1.1.2.16.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "0",
+        }
+
+        # bgp4V2PeerLastErrorCodeReceived
+        output, _ = snmp.walk(".1.3.6.1.3.5.1.1.3.1.1")
+        return output == expected
+
+    _, result = topotest.run_and_expect(
+        _snmpwalk_peer_last_error_code_received, True, count=10, wait=1
+    )
+    assertmsg = "Can't fetch SNMP for bgp4V2PeerLastErrorCodeReceived"
+    assert result, assertmsg
+
+    def _snmpwalk_origin():
+        expected = {
+            "1.3.6.1.3.5.1.1.9.1.9.1.4.10.0.0.0.31.192.168.12.1": "1",
+            "1.3.6.1.3.5.1.1.9.1.9.1.4.10.0.0.2.32.192.168.12.1": "3",
+            "1.3.6.1.3.5.1.1.9.1.9.2.16.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "1",
+            "1.3.6.1.3.5.1.1.9.1.9.2.16.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "3",
+        }
+
+        # bgp4V2NlriOrigin
+        output, _ = snmp.walk(".1.3.6.1.3.5.1.1.9.1.9")
+        return output == expected
+
+    _, result = topotest.run_and_expect(_snmpwalk_origin, True, count=10, wait=1)
+    assertmsg = "Can't fetch SNMP for bgp4V2NlriOrigin"
+    assert result, assertmsg
+
+    def _snmpwalk_med():
+        expected = {
+            "1.3.6.1.3.5.1.1.9.1.17.1.4.10.0.0.0.31.192.168.12.1": "1",
+            "1.3.6.1.3.5.1.1.9.1.17.1.4.10.0.0.2.32.192.168.12.1": "2",
+            "1.3.6.1.3.5.1.1.9.1.17.2.16.32.1.13.184.0.0.0.0.0.0.0.0.0.0.0.1.128.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "1",
+            "1.3.6.1.3.5.1.1.9.1.17.2.16.32.1.13.184.0.1.0.0.0.0.0.0.0.0.0.0.56.32.1.13.184.0.0.0.0.0.0.0.0.0.18.0.1": "2",
+        }
+
+        # bgp4V2NlriMed
+        output, _ = snmp.walk(".1.3.6.1.3.5.1.1.9.1.17")
+        return output == expected
+
+    _, result = topotest.run_and_expect(_snmpwalk_med, True, count=10, wait=1)
+    assertmsg = "Can't fetch SNMP for bgp4V2NlriMed"
+    assert result, assertmsg
+
+
+def test_memory_leak():
+    "Run the memory leak test and report results."
+    tgen = get_topogen()
+    if not tgen.is_memleak_enabled():
+        pytest.skip("Memory leak test/report is disabled")
+
+    tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+    args = ["-s"] + sys.argv[1:]
+    sys.exit(pytest.main(args))
index fe5ff28979402b00b165a2b24b5dace385ff93ff..d695443906309903ff76846e95dc723442ca538d 100644 (file)
@@ -36,11 +36,12 @@ from lib.topolog import logger
 class SnmpTester(object):
     "A helper class for testing SNMP"
 
-    def __init__(self, router, iface, community, version):
+    def __init__(self, router, iface, community, version, options=""):
         self.community = community
         self.version = version
         self.router = router
         self.iface = iface
+        self.options = options
         logger.info(
             "created SNMP tester: SNMPv{0} community:{1}".format(
                 self.version, self.community
@@ -52,7 +53,9 @@ class SnmpTester(object):
         Helper function to build a string with SNMP
         configuration for commands.
         """
-        return "-v {0} -c {1} {2}".format(self.version, self.community, self.iface)
+        return "-v {0} -c {1} {2} {3}".format(
+            self.version, self.community, self.options, self.iface
+        )
 
     @staticmethod
     def _get_snmp_value(snmp_output):