aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2020-11-18 20:04:54 +0900
committerKazuki Yamaguchi <k@rhe.jp>2020-11-18 20:04:54 +0900
commit8d95a298de2bc5070945755442ec99bdf75bb752 (patch)
treeb4e0abc0c170a9a8c6f5dea3b14088ae05b6ca54
parent77f4fd13f088009f9ee3486b1a4a978cd6cdbe1a (diff)
parent37589f26bae82d7860593202f7099ec649435b38 (diff)
downloadbird-8d95a298de2bc5070945755442ec99bdf75bb752.tar.gz
Merge branch 'ky/netlink-ecmp-ipv6' into master-2.0.7m
* ky/netlink-ecmp-ipv6: Netlink: Use route replace for IPv6
-rw-r--r--sysdep/linux/netlink.c61
1 files changed, 6 insertions, 55 deletions
diff --git a/sysdep/linux/netlink.c b/sysdep/linux/netlink.c
index f85bcf35..1a4d69a0 100644
--- a/sysdep/linux/netlink.c
+++ b/sysdep/linux/netlink.c
@@ -69,9 +69,6 @@
#define RTA_ENCAP 22
#endif
-#define krt_ipv4(p) ((p)->af == AF_INET)
-#define krt_ecmp6(p) ((p)->af == AF_INET6)
-
const int rt_default_ecmp = 16;
/*
@@ -97,13 +94,14 @@ const int rt_default_ecmp = 16;
*
* Whatever the kernel version is, IPv6 ECMP routes are sent as multiple routes
* for the same prefix.
+ *
+ * RHE: Modified to use RTA_MULTIPATH on IPv6 as I can ignore Linux < 4.11.
*/
struct nl_parse_state
{
struct linpool *pool;
int scan;
- int merge;
net *net;
rta *attrs;
@@ -1338,7 +1336,7 @@ dest:
{
case RTD_UNICAST:
r->r.rtm_type = RTN_UNICAST;
- if (nh->next && !krt_ecmp6(p))
+ if (nh->next)
nl_add_multipath(&r->h, rsize, nh, p->af);
else
{
@@ -1372,21 +1370,6 @@ static inline int
nl_add_rte(struct krt_proto *p, rte *e)
{
rta *a = e->attrs;
- int err = 0;
-
- if (krt_ecmp6(p) && a->nh.next)
- {
- struct nexthop *nh = &(a->nh);
-
- err = nl_send_route(p, e, NL_OP_ADD, RTD_UNICAST, nh);
- if (err < 0)
- return err;
-
- for (nh = nh->next; nh; nh = nh->next)
- err += nl_send_route(p, e, NL_OP_APPEND, RTD_UNICAST, nh);
-
- return err;
- }
return nl_send_route(p, e, NL_OP_ADD, a->dest, &(a->nh));
}
@@ -1394,14 +1377,7 @@ nl_add_rte(struct krt_proto *p, rte *e)
static inline int
nl_delete_rte(struct krt_proto *p, rte *e)
{
- int err = 0;
-
- /* For IPv6, we just repeatedly request DELETE until we get error */
- do
- err = nl_send_route(p, e, NL_OP_DELETE, RTD_NONE, NULL);
- while (krt_ecmp6(p) && !err);
-
- return err;
+ return nl_send_route(p, e, NL_OP_DELETE, RTD_NONE, NULL);
}
static inline int
@@ -1420,16 +1396,9 @@ krt_replace_rte(struct krt_proto *p, net *n UNUSED, rte *new, rte *old)
/*
* We use NL_OP_REPLACE for IPv4, it has an issue with not checking for
* matching rtm_protocol, but that is OK when dedicated priority is used.
- *
- * We do not use NL_OP_REPLACE for IPv6, as it has broken semantics for ECMP
- * and with some kernel versions ECMP replace crashes kernel. Would need more
- * testing and checks for kernel versions.
- *
- * For IPv6, we use NL_OP_DELETE and then NL_OP_ADD. We also do not trust the
- * old route value, so we do not try to optimize IPv6 ECMP reconfigurations.
*/
- if (krt_ipv4(p) && old && new)
+ if (old && new)
{
err = nl_replace_rte(p, new);
}
@@ -1451,24 +1420,6 @@ krt_replace_rte(struct krt_proto *p, net *n UNUSED, rte *new, rte *old)
}
}
-static int
-nl_mergable_route(struct nl_parse_state *s, net *net, struct krt_proto *p, uint priority, uint krt_type, uint rtm_family)
-{
- /* Route merging is used for IPv6 scans */
- if (!s->scan || (rtm_family != AF_INET6))
- return 0;
-
- /* Saved and new route must have same network, proto/table, and priority */
- if ((s->net != net) || (s->proto != p) || (s->krt_metric != priority))
- return 0;
-
- /* Both must be regular unicast routes */
- if ((s->krt_type != RTN_UNICAST) || (krt_type != RTN_UNICAST))
- return 0;
-
- return 1;
-}
-
static void
nl_announce_route(struct nl_parse_state *s)
{
@@ -1639,7 +1590,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
net *net = net_get(p->p.main_channel->table, n);
- if (s->net && !nl_mergable_route(s, net, p, priority, i->rtm_type, i->rtm_family))
+ if (s->net)
nl_announce_route(s);
rta *ra = lp_allocz(s->pool, RTA_MAX_SIZE);