Netlink: Handle IPv4 routes with IPv6 nexthops

Accept RTA_VIA attribute in all cases. The old code always used
RTA_GATEWAY for IPv4 / IPv6 and RTA_VIA for MPLS. The new code uses
RTA_VIA in cases where AF of network and AF of nexthop differs.
This commit is contained in:
Ondrej Zajicek 2019-11-12 18:13:21 +01:00
parent 0b228fca04
commit 53401bef63

View file

@ -171,6 +171,7 @@ nl_send(struct nl_sock *nl, struct nlmsghdr *nh)
sa.nl_family = AF_NETLINK; sa.nl_family = AF_NETLINK;
nh->nlmsg_pid = 0; nh->nlmsg_pid = 0;
nh->nlmsg_seq = ++(nl->seq); nh->nlmsg_seq = ++(nl->seq);
nh->nlmsg_len = NLMSG_ALIGN(nh->nlmsg_len);
if (sendto(nl->fd, nh, nh->nlmsg_len, 0, (struct sockaddr *)&sa, sizeof(sa)) < 0) if (sendto(nl->fd, nh, nh->nlmsg_len, 0, (struct sockaddr *)&sa, sizeof(sa)) < 0)
die("rtnetlink sendto: %m"); die("rtnetlink sendto: %m");
nl->last_hdr = NULL; nl->last_hdr = NULL;
@ -343,12 +344,14 @@ static struct nl_want_attrs ifa_attr_want6[BIRD_IFA_MAX] = {
static struct nl_want_attrs nexthop_attr_want4[BIRD_RTA_MAX] = { static struct nl_want_attrs nexthop_attr_want4[BIRD_RTA_MAX] = {
[RTA_GATEWAY] = { 1, 1, sizeof(ip4_addr) }, [RTA_GATEWAY] = { 1, 1, sizeof(ip4_addr) },
[RTA_VIA] = { 1, 0, 0 },
[RTA_ENCAP_TYPE]= { 1, 1, sizeof(u16) }, [RTA_ENCAP_TYPE]= { 1, 1, sizeof(u16) },
[RTA_ENCAP] = { 1, 0, 0 }, [RTA_ENCAP] = { 1, 0, 0 },
}; };
static struct nl_want_attrs nexthop_attr_want6[BIRD_RTA_MAX] = { static struct nl_want_attrs nexthop_attr_want6[BIRD_RTA_MAX] = {
[RTA_GATEWAY] = { 1, 1, sizeof(ip6_addr) }, [RTA_GATEWAY] = { 1, 1, sizeof(ip6_addr) },
[RTA_VIA] = { 1, 0, 0 },
[RTA_ENCAP_TYPE]= { 1, 1, sizeof(u16) }, [RTA_ENCAP_TYPE]= { 1, 1, sizeof(u16) },
[RTA_ENCAP] = { 1, 0, 0 }, [RTA_ENCAP] = { 1, 0, 0 },
}; };
@ -369,6 +372,7 @@ static struct nl_want_attrs rtm_attr_want4[BIRD_RTA_MAX] = {
[RTA_MULTIPATH] = { 1, 0, 0 }, [RTA_MULTIPATH] = { 1, 0, 0 },
[RTA_FLOW] = { 1, 1, sizeof(u32) }, [RTA_FLOW] = { 1, 1, sizeof(u32) },
[RTA_TABLE] = { 1, 1, sizeof(u32) }, [RTA_TABLE] = { 1, 1, sizeof(u32) },
[RTA_VIA] = { 1, 0, 0 },
[RTA_ENCAP_TYPE]= { 1, 1, sizeof(u16) }, [RTA_ENCAP_TYPE]= { 1, 1, sizeof(u16) },
[RTA_ENCAP] = { 1, 0, 0 }, [RTA_ENCAP] = { 1, 0, 0 },
}; };
@ -385,6 +389,7 @@ static struct nl_want_attrs rtm_attr_want6[BIRD_RTA_MAX] = {
[RTA_MULTIPATH] = { 1, 0, 0 }, [RTA_MULTIPATH] = { 1, 0, 0 },
[RTA_FLOW] = { 1, 1, sizeof(u32) }, [RTA_FLOW] = { 1, 1, sizeof(u32) },
[RTA_TABLE] = { 1, 1, sizeof(u32) }, [RTA_TABLE] = { 1, 1, sizeof(u32) },
[RTA_VIA] = { 1, 0, 0 },
[RTA_ENCAP_TYPE]= { 1, 1, sizeof(u16) }, [RTA_ENCAP_TYPE]= { 1, 1, sizeof(u16) },
[RTA_ENCAP] = { 1, 0, 0 }, [RTA_ENCAP] = { 1, 0, 0 },
}; };
@ -622,10 +627,12 @@ nl_add_nexthop(struct nlmsghdr *h, uint bufsize, struct nexthop *nh, int af UNUS
nl_add_attr_mpls_encap(h, bufsize, nh->labels, nh->label); nl_add_attr_mpls_encap(h, bufsize, nh->labels, nh->label);
if (ipa_nonzero(nh->gw)) if (ipa_nonzero(nh->gw))
if (af == AF_MPLS) {
nl_add_attr_via(h, bufsize, nh->gw); if (af == (ipa_is_ip4(nh->gw) ? AF_INET : AF_INET6))
else
nl_add_attr_ipa(h, bufsize, RTA_GATEWAY, nh->gw); nl_add_attr_ipa(h, bufsize, RTA_GATEWAY, nh->gw);
else
nl_add_attr_via(h, bufsize, nh->gw);
}
#else #else
if (ipa_nonzero(nh->gw)) if (ipa_nonzero(nh->gw))
@ -701,9 +708,15 @@ nl_parse_multipath(struct nl_parse_state *s, struct krt_proto *p, struct rtattr
} }
if (a[RTA_GATEWAY]) if (a[RTA_GATEWAY])
{ rv->gw = rta_get_ipa(a[RTA_GATEWAY]);
rv->gw = rta_get_ipa(a[RTA_GATEWAY]);
#ifdef HAVE_MPLS_KERNEL
if (a[RTA_VIA])
rv->gw = rta_get_via(a[RTA_VIA]);
#endif
if (ipa_nonzero(rv->gw))
{
if (nh->rtnh_flags & RTNH_F_ONLINK) if (nh->rtnh_flags & RTNH_F_ONLINK)
rv->flags |= RNF_ONLINK; rv->flags |= RNF_ONLINK;
@ -713,8 +726,6 @@ nl_parse_multipath(struct nl_parse_state *s, struct krt_proto *p, struct rtattr
if (!nbr || (nbr->scope == SCOPE_HOST)) if (!nbr || (nbr->scope == SCOPE_HOST))
return NULL; return NULL;
} }
else
rv->gw = IPA_NONE;
#ifdef HAVE_MPLS_KERNEL #ifdef HAVE_MPLS_KERNEL
if (a[RTA_ENCAP] && a[RTA_ENCAP_TYPE]) if (a[RTA_ENCAP] && a[RTA_ENCAP_TYPE])
@ -1644,19 +1655,16 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
return; return;
} }
if ((i->rtm_family != AF_MPLS) && a[RTA_GATEWAY] if (a[RTA_GATEWAY])
#ifdef HAVE_MPLS_KERNEL ra->nh.gw = rta_get_ipa(a[RTA_GATEWAY]);
|| (i->rtm_family == AF_MPLS) && a[RTA_VIA]
#endif
)
{
#ifdef HAVE_MPLS_KERNEL
if (i->rtm_family == AF_MPLS)
ra->nh.gw = rta_get_via(a[RTA_VIA]);
else
#endif
ra->nh.gw = rta_get_ipa(a[RTA_GATEWAY]);
#ifdef HAVE_MPLS_KERNEL
if (a[RTA_VIA])
ra->nh.gw = rta_get_via(a[RTA_VIA]);
#endif
if (ipa_nonzero(ra->nh.gw))
{
/* Silently skip strange 6to4 routes */ /* Silently skip strange 6to4 routes */
const net_addr_ip6 sit = NET_ADDR_IP6(IP6_NONE, 96); const net_addr_ip6 sit = NET_ADDR_IP6(IP6_NONE, 96);
if ((i->rtm_family == AF_INET6) && ipa_in_netX(ra->nh.gw, (net_addr *) &sit)) if ((i->rtm_family == AF_INET6) && ipa_in_netX(ra->nh.gw, (net_addr *) &sit))