mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-05-02 14:43:23 +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
|
||||
parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb,
|
||||
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 nexthop nh = {0};
|
||||
mpls_label_t labels[MPLS_MAX_LABELS] = {0};
|
||||
int num_labels = 0;
|
||||
|
||||
vrf_id_t nh_vrf_id = vrf_id;
|
||||
size_t sz = (afi == AFI_IP) ? 4 : 16;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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. */
|
||||
static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
|
||||
int startup)
|
||||
@ -606,8 +715,6 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
|
||||
afi = AFI_IP6;
|
||||
|
||||
if (h->nlmsg_type == RTM_NEWROUTE) {
|
||||
struct interface *ifp;
|
||||
vrf_id_t nh_vrf_id = vrf_id;
|
||||
|
||||
if (!tb[RTA_MULTIPATH]) {
|
||||
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) {
|
||||
nh = parse_nexthop_unicast(
|
||||
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,
|
||||
&src_p, &nh, nhe_id, table, metric, mtu,
|
||||
distance, tag);
|
||||
} else {
|
||||
/* This is a multipath route */
|
||||
uint8_t nhop_num;
|
||||
struct route_entry *re;
|
||||
struct rtnexthop *rtnh =
|
||||
(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->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->tag = tag;
|
||||
re->nhe_id = nhe_id;
|
||||
re->ng = nexthop_group_new();
|
||||
|
||||
for (;;) {
|
||||
struct nexthop *nh = NULL;
|
||||
if (!nhe_id) {
|
||||
uint8_t nhop_num =
|
||||
parse_multipath_nexthops_unicast(
|
||||
ns_id, re, rtm, rtnh, tb,
|
||||
prefsrc, vrf_id);
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
zserv_nexthop_num_warn(
|
||||
__func__, (const struct prefix *)&p,
|
||||
nhop_num);
|
||||
}
|
||||
|
||||
nhop_num = nexthop_group_nexthop_num(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
|
||||
if (nhe_id || re->ng)
|
||||
rib_add_multipath(afi, SAFI_UNICAST, &p,
|
||||
&src_p, re);
|
||||
else
|
||||
XFREE(MTYPE_RE, re);
|
||||
}
|
||||
} else {
|
||||
if (!tb[RTA_MULTIPATH]) {
|
||||
@ -2400,7 +2416,7 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
|
||||
} else {
|
||||
/* This is a new nexthop group */
|
||||
nhe = zebra_nhg_find(nhg, vrf_id, afi, id, nhg_depends,
|
||||
dep_count);
|
||||
true);
|
||||
zebra_nhg_free_group_depends(nhg, nhg_depends);
|
||||
|
||||
if (!nhe) {
|
||||
|
@ -144,6 +144,41 @@ zebra_nhg_depends_lookup_id(const struct nhg_hash_entry *nhe, const uint32_t id)
|
||||
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
|
||||
*
|
||||
@ -212,6 +247,10 @@ static void *zebra_nhg_alloc(void *arg)
|
||||
zebra_nhg_insert_id(nhe);
|
||||
|
||||
|
||||
/* Send it to the kernel */
|
||||
if (!nhe->is_kernel_nh)
|
||||
zebra_nhg_install_kernel(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 *nhe2 = arg2;
|
||||
struct nexthop *nh1, *nh2;
|
||||
uint32_t nh_count = 0;
|
||||
|
||||
if (nhe1->vrf_id != nhe2->vrf_id)
|
||||
return false;
|
||||
@ -284,24 +321,8 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2)
|
||||
if (nhe1->afi != nhe2->afi)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Again we are not interested in looking at any recursively
|
||||
* 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++;
|
||||
}
|
||||
if (!zebra_nhg_depends_equal(nhe1, nhe2))
|
||||
return false;
|
||||
|
||||
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_entry *same = NULL;
|
||||
struct nhg_hash_entry *nhe = NULL;
|
||||
struct list *nhg_depends = NULL;
|
||||
int ret = 0;
|
||||
|
||||
if (!re)
|
||||
@ -2648,7 +2649,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
|
||||
/* Lookup table. */
|
||||
table = zebra_vrf_table_with_table_id(afi, safi, re->vrf_id, re->table);
|
||||
if (!table) {
|
||||
zebra_nhg_free_group_depends(re->ng, NULL);
|
||||
zebra_nhg_free_group_depends(re->ng, nhg_depends);
|
||||
XFREE(MTYPE_RE, re);
|
||||
return 0;
|
||||
}
|
||||
@ -2658,11 +2659,29 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p,
|
||||
if (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) {
|
||||
// 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->nhe_id = nhe->id;
|
||||
nhe->refcnt++;
|
||||
|
Loading…
Reference in New Issue
Block a user