3131#include "zclient.h"
3232#include "frrdistance.h"
3333#include "frregex_real.h"
34+ #include "jhash.h"
3435
3536#include "bgpd/bgpd.h"
3637#include "bgpd/bgp_nhc.h"
@@ -127,6 +128,52 @@ static const struct message bgp_pmsi_tnltype_str[] = {
127128static int clear_batch_rib_helper(struct bgp_clearing_info *cinfo);
128129static void bgp_gr_start_tier2_timer_if_required(struct bgp *bgp, afi_t afi, safi_t safi);
129130
131+ /*
132+ * Typesafe Hash Functions for bgp_path_info
133+ * hash key: prefix, peer, type, sub_type, addpath_rx_id
134+ */
135+ int bgp_pi_hash_cmp(const struct bgp_path_info *p1, const struct bgp_path_info *p2)
136+ {
137+ int ret;
138+
139+ /* Get the prefix from pi->net and compare */
140+ const struct prefix *pfx1 = bgp_dest_get_prefix(p1->net);
141+ const struct prefix *pfx2 = bgp_dest_get_prefix(p2->net);
142+
143+ ret = prefix_cmp(pfx1, pfx2);
144+ if (ret != 0)
145+ return ret;
146+
147+ if (p1->peer != p2->peer)
148+ return (p1->peer < p2->peer) ? -1 : 1;
149+
150+ if (p1->type != p2->type)
151+ return (p1->type < p2->type) ? -1 : 1;
152+
153+ if (p1->sub_type != p2->sub_type)
154+ return (p1->sub_type < p2->sub_type) ? -1 : 1;
155+
156+ if (p1->addpath_rx_id != p2->addpath_rx_id)
157+ return (p1->addpath_rx_id < p2->addpath_rx_id) ? -1 : 1;
158+
159+ /* All fields are equal */
160+ return 0;
161+ }
162+
163+ uint32_t bgp_pi_hash_hashfn(const struct bgp_path_info *pi)
164+ {
165+ uint32_t h = 0;
166+ const struct prefix *pfx = bgp_dest_get_prefix(pi->net);
167+
168+ h = prefix_hash_key(pfx);
169+ h = jhash_1word((uint32_t)(uintptr_t)pi->peer, h);
170+ h = jhash_1word(pi->addpath_rx_id, h);
171+ h = jhash_1word((uint32_t)pi->type, h);
172+ h = jhash_1word((uint32_t)pi->sub_type, h);
173+
174+ return h;
175+ }
176+
130177static inline char *bgp_route_dump_path_info_flags(struct bgp_path_info *pi,
131178 char *buf, size_t len)
132179{
@@ -544,6 +591,7 @@ void bgp_path_info_add_with_caller(const char *name, struct bgp_dest *dest,
544591{
545592 frrtrace(3, frr_bgp, bgp_path_info_add, dest, pi, name);
546593 struct bgp_path_info *top;
594+ struct bgp_table *table;
547595
548596 top = bgp_dest_get_bgp_path_info(dest);
549597
@@ -553,6 +601,11 @@ void bgp_path_info_add_with_caller(const char *name, struct bgp_dest *dest,
553601 top->prev = pi;
554602 bgp_dest_set_bgp_path_info(dest, pi);
555603
604+ /* Add this path info to global hash (per AFI/SAFI table) */
605+ table = bgp_dest_table(dest);
606+ if (table)
607+ bgp_pi_hash_add(&table->pi_hash, pi);
608+
556609 SET_FLAG(pi->flags, BGP_PATH_UNSORTED);
557610 bgp_path_info_lock(pi);
558611 bgp_dest_lock_node(dest);
@@ -568,6 +621,8 @@ void bgp_path_info_add_with_caller(const char *name, struct bgp_dest *dest,
568621struct bgp_dest *bgp_path_info_reap(struct bgp_dest *dest,
569622 struct bgp_path_info *pi)
570623{
624+ struct bgp_table *table;
625+
571626 if (pi->next)
572627 pi->next->prev = pi->prev;
573628 if (pi->prev)
@@ -578,6 +633,11 @@ struct bgp_dest *bgp_path_info_reap(struct bgp_dest *dest,
578633 pi->next = NULL;
579634 pi->prev = NULL;
580635
636+ /* Remove this path from global hash (per AFI/SAFI table) */
637+ table = bgp_dest_table(dest);
638+ if (table)
639+ bgp_pi_hash_del(&table->pi_hash, pi);
640+
581641 if (pi->peer)
582642 pi->peer->stat_pfx_loc_rib--;
583643 hook_call(bgp_snmp_update_stats, dest, pi, false);
@@ -589,9 +649,16 @@ struct bgp_dest *bgp_path_info_reap(struct bgp_dest *dest,
589649static struct bgp_dest *bgp_path_info_reap_unsorted(struct bgp_dest *dest,
590650 struct bgp_path_info *pi)
591651{
652+ struct bgp_table *table;
653+
592654 pi->next = NULL;
593655 pi->prev = NULL;
594656
657+ /* Remove this path from global hash (per AFI/SAFI table) */
658+ table = bgp_dest_table(dest);
659+ if (table)
660+ bgp_pi_hash_del(&table->pi_hash, pi);
661+
595662 if (pi->peer)
596663 pi->peer->stat_pfx_loc_rib--;
597664 hook_call(bgp_snmp_update_stats, dest, pi, false);
@@ -5547,6 +5614,7 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
55475614{
55485615 int ret;
55495616 struct bgp_dest *dest;
5617+ struct bgp_table *rib_table;
55505618 struct bgp *bgp;
55515619 struct attr new_attr = {};
55525620 struct attr *attr_new;
@@ -5580,6 +5648,7 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
55805648
55815649 bgp = peer->bgp;
55825650 dest = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, p, prd);
5651+ rib_table = bgp_dest_table(dest);
55835652
55845653 if (num_labels &&
55855654 ((afi == AFI_L2VPN && safi == SAFI_EVPN) || bgp_is_valid_label(&label[0]))) {
@@ -5606,12 +5675,14 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
56065675 bgp_adj_in_set(dest, peer, attr, addpath_id, &bgp_labels);
56075676 }
56085677
5609- /* Check previously received route. */
5610- for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
5611- if (pi->peer == peer && pi->type == type
5612- && pi->sub_type == sub_type
5613- && pi->addpath_rx_id == addpath_id)
5614- break;
5678+ /* Check previously received route using pi_hash */
5679+ struct bgp_path_info pi_lookup = { .net = dest,
5680+ .peer = peer,
5681+ .type = type,
5682+ .sub_type = sub_type,
5683+ .addpath_rx_id = addpath_id };
5684+
5685+ pi = bgp_pi_hash_find(&rib_table->pi_hash, &pi_lookup);
56155686
56165687 /* AS path local-as loop check. */
56175688 if (peer->change_local_as) {
0 commit comments