summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--zebra/rt_netlink.c232
-rw-r--r--zebra/zebra_nhg.c61
-rw-r--r--zebra/zebra_rib.c25
3 files changed, 187 insertions, 131 deletions
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 3e377eb770..7917e3046e 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -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 (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);
+ if (!nhe_id) {
+ uint8_t nhop_num =
+ parse_multipath_nexthops_unicast(
+ ns_id, re, rtm, rtnh, tb,
+ prefsrc, vrf_id);
+
+ 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) {
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index 92198bad03..c698d1099a 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -145,6 +145,41 @@ zebra_nhg_depends_lookup_id(const struct nhg_hash_entry *nhe, const uint32_t id)
}
/**
+ * 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
*
* @id: ID to look for
@@ -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;
}
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index a5b939baa9..558dbd33e0 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -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++;