mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-05-03 04:03:46 +00:00
zebra: Add equivalence function for nhg_depends
Add a helper function to allow us to check if two nhg_hash_entry's dependency lists are equal. Signed-off-by: Stephen Worley <sworley@cumulusnetworks.com>
This commit is contained in:
parent
148a0103c6
commit
20822f9d2e
@ -324,13 +324,14 @@ static int parse_encap_mpls(struct rtattr *tb, mpls_label_t *labels)
|
|||||||
static struct nexthop
|
static struct nexthop
|
||||||
parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb,
|
parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb,
|
||||||
enum blackhole_type bh_type, int index, void *prefsrc,
|
enum blackhole_type bh_type, int index, void *prefsrc,
|
||||||
void *gate, afi_t afi, vrf_id_t nh_vrf_id)
|
void *gate, afi_t afi, vrf_id_t vrf_id)
|
||||||
{
|
{
|
||||||
struct interface *ifp = NULL;
|
struct interface *ifp = NULL;
|
||||||
struct nexthop nh = {0};
|
struct nexthop nh = {0};
|
||||||
mpls_label_t labels[MPLS_MAX_LABELS] = {0};
|
mpls_label_t labels[MPLS_MAX_LABELS] = {0};
|
||||||
int num_labels = 0;
|
int num_labels = 0;
|
||||||
|
|
||||||
|
vrf_id_t nh_vrf_id = vrf_id;
|
||||||
size_t sz = (afi == AFI_IP) ? 4 : 16;
|
size_t sz = (afi == AFI_IP) ? 4 : 16;
|
||||||
|
|
||||||
if (bh_type == BLACKHOLE_UNSPEC) {
|
if (bh_type == BLACKHOLE_UNSPEC) {
|
||||||
@ -378,6 +379,114 @@ parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb,
|
|||||||
return nh;
|
return nh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id,
|
||||||
|
struct route_entry *re,
|
||||||
|
struct rtmsg *rtm,
|
||||||
|
struct rtnexthop *rtnh,
|
||||||
|
struct rtattr **tb,
|
||||||
|
void *prefsrc, vrf_id_t vrf_id)
|
||||||
|
{
|
||||||
|
void *gate = NULL;
|
||||||
|
struct interface *ifp = NULL;
|
||||||
|
int index = 0;
|
||||||
|
/* MPLS labels */
|
||||||
|
mpls_label_t labels[MPLS_MAX_LABELS] = {0};
|
||||||
|
int num_labels = 0;
|
||||||
|
struct rtattr *rtnh_tb[RTA_MAX + 1] = {};
|
||||||
|
|
||||||
|
int len = RTA_PAYLOAD(tb[RTA_MULTIPATH]);
|
||||||
|
vrf_id_t nh_vrf_id = vrf_id;
|
||||||
|
|
||||||
|
re->ng = nexthop_group_new();
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
struct nexthop *nh = NULL;
|
||||||
|
|
||||||
|
if (len < (int)sizeof(*rtnh) || rtnh->rtnh_len > len)
|
||||||
|
break;
|
||||||
|
|
||||||
|
index = rtnh->rtnh_ifindex;
|
||||||
|
if (index) {
|
||||||
|
/*
|
||||||
|
* Yes we are looking this up
|
||||||
|
* for every nexthop and just
|
||||||
|
* using the last one looked
|
||||||
|
* up right now
|
||||||
|
*/
|
||||||
|
ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id),
|
||||||
|
index);
|
||||||
|
if (ifp)
|
||||||
|
nh_vrf_id = ifp->vrf_id;
|
||||||
|
else {
|
||||||
|
flog_warn(
|
||||||
|
EC_ZEBRA_UNKNOWN_INTERFACE,
|
||||||
|
"%s: Unknown interface %u specified, defaulting to VRF_DEFAULT",
|
||||||
|
__PRETTY_FUNCTION__, index);
|
||||||
|
nh_vrf_id = VRF_DEFAULT;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
nh_vrf_id = vrf_id;
|
||||||
|
|
||||||
|
if (rtnh->rtnh_len > sizeof(*rtnh)) {
|
||||||
|
memset(rtnh_tb, 0, sizeof(rtnh_tb));
|
||||||
|
|
||||||
|
netlink_parse_rtattr(rtnh_tb, RTA_MAX, RTNH_DATA(rtnh),
|
||||||
|
rtnh->rtnh_len - sizeof(*rtnh));
|
||||||
|
if (rtnh_tb[RTA_GATEWAY])
|
||||||
|
gate = RTA_DATA(rtnh_tb[RTA_GATEWAY]);
|
||||||
|
if (rtnh_tb[RTA_ENCAP] && rtnh_tb[RTA_ENCAP_TYPE]
|
||||||
|
&& *(uint16_t *)RTA_DATA(rtnh_tb[RTA_ENCAP_TYPE])
|
||||||
|
== LWTUNNEL_ENCAP_MPLS) {
|
||||||
|
num_labels = parse_encap_mpls(
|
||||||
|
rtnh_tb[RTA_ENCAP], labels);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gate) {
|
||||||
|
if (rtm->rtm_family == AF_INET) {
|
||||||
|
if (index)
|
||||||
|
nh = route_entry_nexthop_ipv4_ifindex_add(
|
||||||
|
re, gate, prefsrc, index,
|
||||||
|
nh_vrf_id);
|
||||||
|
else
|
||||||
|
nh = route_entry_nexthop_ipv4_add(
|
||||||
|
re, gate, prefsrc, nh_vrf_id);
|
||||||
|
} else if (rtm->rtm_family == AF_INET6) {
|
||||||
|
if (index)
|
||||||
|
nh = route_entry_nexthop_ipv6_ifindex_add(
|
||||||
|
re, gate, index, nh_vrf_id);
|
||||||
|
else
|
||||||
|
nh = route_entry_nexthop_ipv6_add(
|
||||||
|
re, gate, nh_vrf_id);
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
nh = route_entry_nexthop_ifindex_add(re, index,
|
||||||
|
nh_vrf_id);
|
||||||
|
|
||||||
|
if (nh) {
|
||||||
|
if (num_labels)
|
||||||
|
nexthop_add_labels(nh, ZEBRA_LSP_STATIC,
|
||||||
|
num_labels, labels);
|
||||||
|
|
||||||
|
if (rtnh->rtnh_flags & RTNH_F_ONLINK)
|
||||||
|
SET_FLAG(nh->flags, NEXTHOP_FLAG_ONLINK);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rtnh->rtnh_len == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
len -= NLMSG_ALIGN(rtnh->rtnh_len);
|
||||||
|
rtnh = RTNH_NEXT(rtnh);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t nhop_num = nexthop_group_nexthop_num(re->ng);
|
||||||
|
|
||||||
|
if (!nhop_num)
|
||||||
|
nexthop_group_delete(&re->ng);
|
||||||
|
|
||||||
|
return nhop_num;
|
||||||
|
}
|
||||||
|
|
||||||
/* Looking up routing table by netlink interface. */
|
/* Looking up routing table by netlink interface. */
|
||||||
static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
|
static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
|
||||||
int startup)
|
int startup)
|
||||||
@ -606,8 +715,6 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
|
|||||||
afi = AFI_IP6;
|
afi = AFI_IP6;
|
||||||
|
|
||||||
if (h->nlmsg_type == RTM_NEWROUTE) {
|
if (h->nlmsg_type == RTM_NEWROUTE) {
|
||||||
struct interface *ifp;
|
|
||||||
vrf_id_t nh_vrf_id = vrf_id;
|
|
||||||
|
|
||||||
if (!tb[RTA_MULTIPATH]) {
|
if (!tb[RTA_MULTIPATH]) {
|
||||||
struct nexthop nh = {0};
|
struct nexthop nh = {0};
|
||||||
@ -615,22 +722,16 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
|
|||||||
if (!nhe_id) {
|
if (!nhe_id) {
|
||||||
nh = parse_nexthop_unicast(
|
nh = parse_nexthop_unicast(
|
||||||
ns_id, rtm, tb, bh_type, index, prefsrc,
|
ns_id, rtm, tb, bh_type, index, prefsrc,
|
||||||
gate, afi, nh_vrf_id);
|
gate, afi, vrf_id);
|
||||||
}
|
}
|
||||||
rib_add(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, &p,
|
rib_add(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, &p,
|
||||||
&src_p, &nh, nhe_id, table, metric, mtu,
|
&src_p, &nh, nhe_id, table, metric, mtu,
|
||||||
distance, tag);
|
distance, tag);
|
||||||
} else {
|
} else {
|
||||||
/* This is a multipath route */
|
/* This is a multipath route */
|
||||||
uint8_t nhop_num;
|
|
||||||
struct route_entry *re;
|
struct route_entry *re;
|
||||||
struct rtnexthop *rtnh =
|
struct rtnexthop *rtnh =
|
||||||
(struct rtnexthop *)RTA_DATA(tb[RTA_MULTIPATH]);
|
(struct rtnexthop *)RTA_DATA(tb[RTA_MULTIPATH]);
|
||||||
/* MPLS labels */
|
|
||||||
mpls_label_t labels[MPLS_MAX_LABELS] = {0};
|
|
||||||
int num_labels = 0;
|
|
||||||
|
|
||||||
len = RTA_PAYLOAD(tb[RTA_MULTIPATH]);
|
|
||||||
|
|
||||||
re = XCALLOC(MTYPE_RE, sizeof(struct route_entry));
|
re = XCALLOC(MTYPE_RE, sizeof(struct route_entry));
|
||||||
re->type = proto;
|
re->type = proto;
|
||||||
@ -643,108 +744,23 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
|
|||||||
re->uptime = monotime(NULL);
|
re->uptime = monotime(NULL);
|
||||||
re->tag = tag;
|
re->tag = tag;
|
||||||
re->nhe_id = nhe_id;
|
re->nhe_id = nhe_id;
|
||||||
re->ng = nexthop_group_new();
|
|
||||||
|
|
||||||
for (;;) {
|
if (!nhe_id) {
|
||||||
struct nexthop *nh = NULL;
|
uint8_t nhop_num =
|
||||||
|
parse_multipath_nexthops_unicast(
|
||||||
|
ns_id, re, rtm, rtnh, tb,
|
||||||
|
prefsrc, vrf_id);
|
||||||
|
|
||||||
if (len < (int)sizeof(*rtnh)
|
zserv_nexthop_num_warn(
|
||||||
|| rtnh->rtnh_len > len)
|
__func__, (const struct prefix *)&p,
|
||||||
break;
|
nhop_num);
|
||||||
|
|
||||||
index = rtnh->rtnh_ifindex;
|
|
||||||
if (index) {
|
|
||||||
/*
|
|
||||||
* Yes we are looking this up
|
|
||||||
* for every nexthop and just
|
|
||||||
* using the last one looked
|
|
||||||
* up right now
|
|
||||||
*/
|
|
||||||
ifp = if_lookup_by_index_per_ns(
|
|
||||||
zebra_ns_lookup(ns_id),
|
|
||||||
index);
|
|
||||||
if (ifp)
|
|
||||||
nh_vrf_id = ifp->vrf_id;
|
|
||||||
else {
|
|
||||||
flog_warn(
|
|
||||||
EC_ZEBRA_UNKNOWN_INTERFACE,
|
|
||||||
"%s: Unknown interface %u specified, defaulting to VRF_DEFAULT",
|
|
||||||
__PRETTY_FUNCTION__,
|
|
||||||
index);
|
|
||||||
nh_vrf_id = VRF_DEFAULT;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
nh_vrf_id = vrf_id;
|
|
||||||
|
|
||||||
gate = 0;
|
|
||||||
if (rtnh->rtnh_len > sizeof(*rtnh)) {
|
|
||||||
memset(tb, 0, sizeof(tb));
|
|
||||||
netlink_parse_rtattr(
|
|
||||||
tb, RTA_MAX, RTNH_DATA(rtnh),
|
|
||||||
rtnh->rtnh_len - sizeof(*rtnh));
|
|
||||||
if (tb[RTA_GATEWAY])
|
|
||||||
gate = RTA_DATA(
|
|
||||||
tb[RTA_GATEWAY]);
|
|
||||||
if (tb[RTA_ENCAP] && tb[RTA_ENCAP_TYPE]
|
|
||||||
&& *(uint16_t *)RTA_DATA(
|
|
||||||
tb[RTA_ENCAP_TYPE])
|
|
||||||
== LWTUNNEL_ENCAP_MPLS) {
|
|
||||||
num_labels = parse_encap_mpls(
|
|
||||||
tb[RTA_ENCAP], labels);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gate) {
|
|
||||||
if (rtm->rtm_family == AF_INET) {
|
|
||||||
if (index)
|
|
||||||
nh = route_entry_nexthop_ipv4_ifindex_add(
|
|
||||||
re, gate,
|
|
||||||
prefsrc, index,
|
|
||||||
nh_vrf_id);
|
|
||||||
else
|
|
||||||
nh = route_entry_nexthop_ipv4_add(
|
|
||||||
re, gate,
|
|
||||||
prefsrc,
|
|
||||||
nh_vrf_id);
|
|
||||||
} else if (rtm->rtm_family
|
|
||||||
== AF_INET6) {
|
|
||||||
if (index)
|
|
||||||
nh = route_entry_nexthop_ipv6_ifindex_add(
|
|
||||||
re, gate, index,
|
|
||||||
nh_vrf_id);
|
|
||||||
else
|
|
||||||
nh = route_entry_nexthop_ipv6_add(
|
|
||||||
re, gate,
|
|
||||||
nh_vrf_id);
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
nh = route_entry_nexthop_ifindex_add(
|
|
||||||
re, index, nh_vrf_id);
|
|
||||||
|
|
||||||
if (nh && num_labels)
|
|
||||||
nexthop_add_labels(nh, ZEBRA_LSP_STATIC,
|
|
||||||
num_labels, labels);
|
|
||||||
|
|
||||||
if (nh && (rtnh->rtnh_flags & RTNH_F_ONLINK))
|
|
||||||
SET_FLAG(nh->flags,
|
|
||||||
NEXTHOP_FLAG_ONLINK);
|
|
||||||
|
|
||||||
if (rtnh->rtnh_len == 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
len -= NLMSG_ALIGN(rtnh->rtnh_len);
|
|
||||||
rtnh = RTNH_NEXT(rtnh);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nhop_num = nexthop_group_nexthop_num(re->ng);
|
if (nhe_id || re->ng)
|
||||||
zserv_nexthop_num_warn(
|
|
||||||
__func__, (const struct prefix *)&p, nhop_num);
|
|
||||||
if (nhop_num == 0) {
|
|
||||||
nexthop_group_delete(&re->ng);
|
|
||||||
XFREE(MTYPE_RE, re);
|
|
||||||
} else
|
|
||||||
rib_add_multipath(afi, SAFI_UNICAST, &p,
|
rib_add_multipath(afi, SAFI_UNICAST, &p,
|
||||||
&src_p, re);
|
&src_p, re);
|
||||||
|
else
|
||||||
|
XFREE(MTYPE_RE, re);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!tb[RTA_MULTIPATH]) {
|
if (!tb[RTA_MULTIPATH]) {
|
||||||
@ -2400,7 +2416,7 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
|||||||
} else {
|
} else {
|
||||||
/* This is a new nexthop group */
|
/* This is a new nexthop group */
|
||||||
nhe = zebra_nhg_find(nhg, vrf_id, afi, id, nhg_depends,
|
nhe = zebra_nhg_find(nhg, vrf_id, afi, id, nhg_depends,
|
||||||
dep_count);
|
true);
|
||||||
zebra_nhg_free_group_depends(nhg, nhg_depends);
|
zebra_nhg_free_group_depends(nhg, nhg_depends);
|
||||||
|
|
||||||
if (!nhe) {
|
if (!nhe) {
|
||||||
|
@ -144,6 +144,41 @@ zebra_nhg_depends_lookup_id(const struct nhg_hash_entry *nhe, const uint32_t id)
|
|||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* zebra_nhg_depends_equal() - Are the dependencies of these nhe's equal
|
||||||
|
*
|
||||||
|
* @nhe1: Nexthop group hash entry
|
||||||
|
* @nhe2: Nexthop group hash entry
|
||||||
|
*
|
||||||
|
* Return: True if equal
|
||||||
|
*
|
||||||
|
* We don't care about ordering of the dependencies. If they contain
|
||||||
|
* the same nhe ID's, they are equivalent.
|
||||||
|
*/
|
||||||
|
static bool zebra_nhg_depends_equal(const struct nhg_hash_entry *nhe1,
|
||||||
|
const struct nhg_hash_entry *nhe2)
|
||||||
|
{
|
||||||
|
struct listnode *ln = NULL;
|
||||||
|
struct nhg_depend *n_dp = NULL;
|
||||||
|
|
||||||
|
if (!nhe1->nhg_depends && !nhe2->nhg_depends)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if ((nhe1->nhg_depends && !nhe2->nhg_depends)
|
||||||
|
|| (nhe2->nhg_depends && !nhe1->nhg_depends))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (listcount(nhe1->nhg_depends) != listcount(nhe2->nhg_depends))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (ALL_LIST_ELEMENTS_RO(nhe1->nhg_depends, ln, n_dp)) {
|
||||||
|
if (!zebra_nhg_depends_lookup_id(nhe2, n_dp->nhe->id))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* zebra_nhg_lookup_id() - Lookup the nexthop group id in the id table
|
* zebra_nhg_lookup_id() - Lookup the nexthop group id in the id table
|
||||||
*
|
*
|
||||||
@ -212,6 +247,10 @@ static void *zebra_nhg_alloc(void *arg)
|
|||||||
zebra_nhg_insert_id(nhe);
|
zebra_nhg_insert_id(nhe);
|
||||||
|
|
||||||
|
|
||||||
|
/* Send it to the kernel */
|
||||||
|
if (!nhe->is_kernel_nh)
|
||||||
|
zebra_nhg_install_kernel(nhe);
|
||||||
|
|
||||||
return nhe;
|
return nhe;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,8 +314,6 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2)
|
|||||||
{
|
{
|
||||||
const struct nhg_hash_entry *nhe1 = arg1;
|
const struct nhg_hash_entry *nhe1 = arg1;
|
||||||
const struct nhg_hash_entry *nhe2 = arg2;
|
const struct nhg_hash_entry *nhe2 = arg2;
|
||||||
struct nexthop *nh1, *nh2;
|
|
||||||
uint32_t nh_count = 0;
|
|
||||||
|
|
||||||
if (nhe1->vrf_id != nhe2->vrf_id)
|
if (nhe1->vrf_id != nhe2->vrf_id)
|
||||||
return false;
|
return false;
|
||||||
@ -284,24 +321,8 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2)
|
|||||||
if (nhe1->afi != nhe2->afi)
|
if (nhe1->afi != nhe2->afi)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/*
|
if (!zebra_nhg_depends_equal(nhe1, nhe2))
|
||||||
* Again we are not interested in looking at any recursively
|
return false;
|
||||||
* resolved nexthops. Top level only
|
|
||||||
*/
|
|
||||||
for (nh1 = nhe1->nhg->nexthop; nh1; nh1 = nh1->next) {
|
|
||||||
uint32_t inner_nh_count = 0;
|
|
||||||
for (nh2 = nhe2->nhg->nexthop; nh2; nh2 = nh2->next) {
|
|
||||||
if (inner_nh_count == nh_count) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
inner_nh_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!nexthop_same(nh1, nh2))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
nh_count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -2638,6 +2638,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
|
|||||||
struct route_node *rn;
|
struct route_node *rn;
|
||||||
struct route_entry *same = NULL;
|
struct route_entry *same = NULL;
|
||||||
struct nhg_hash_entry *nhe = NULL;
|
struct nhg_hash_entry *nhe = NULL;
|
||||||
|
struct list *nhg_depends = NULL;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
if (!re)
|
if (!re)
|
||||||
@ -2648,7 +2649,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
|
|||||||
/* Lookup table. */
|
/* Lookup table. */
|
||||||
table = zebra_vrf_table_with_table_id(afi, safi, re->vrf_id, re->table);
|
table = zebra_vrf_table_with_table_id(afi, safi, re->vrf_id, re->table);
|
||||||
if (!table) {
|
if (!table) {
|
||||||
zebra_nhg_free_group_depends(re->ng, NULL);
|
zebra_nhg_free_group_depends(re->ng, nhg_depends);
|
||||||
XFREE(MTYPE_RE, re);
|
XFREE(MTYPE_RE, re);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -2658,11 +2659,29 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
|
|||||||
if (src_p)
|
if (src_p)
|
||||||
apply_mask_ipv6(src_p);
|
apply_mask_ipv6(src_p);
|
||||||
|
|
||||||
nhe = zebra_nhg_find(re->ng, re->vrf_id, afi, re->nhe_id, NULL, 0);
|
/* If its a group, create a dependency list */
|
||||||
|
if (re->ng && re->ng->nexthop->next) {
|
||||||
|
struct nexthop *nh = NULL;
|
||||||
|
struct nexthop lookup = {0};
|
||||||
|
struct nhg_hash_entry *depend = NULL;
|
||||||
|
|
||||||
|
nhg_depends = nhg_depend_new_list();
|
||||||
|
|
||||||
|
for (ALL_NEXTHOPS_PTR(re->ng, nh)) {
|
||||||
|
lookup = *nh;
|
||||||
|
/* Clear it, since its a group */
|
||||||
|
lookup.next = NULL;
|
||||||
|
depend = zebra_nhg_find_nexthop(&lookup, afi);
|
||||||
|
nhg_depend_add(nhg_depends, depend);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nhe = zebra_nhg_find(re->ng, re->vrf_id, afi, re->nhe_id, nhg_depends,
|
||||||
|
false);
|
||||||
|
|
||||||
if (nhe) {
|
if (nhe) {
|
||||||
// TODO: Add interface pointer
|
// TODO: Add interface pointer
|
||||||
zebra_nhg_free_group_depends(re->ng, NULL);
|
zebra_nhg_free_group_depends(re->ng, nhg_depends);
|
||||||
re->ng = nhe->nhg;
|
re->ng = nhe->nhg;
|
||||||
re->nhe_id = nhe->id;
|
re->nhe_id = nhe->id;
|
||||||
nhe->refcnt++;
|
nhe->refcnt++;
|
||||||
|
Loading…
Reference in New Issue
Block a user