1
0
mirror of https://gitlab.labs.nic.cz/labs/bird.git synced 2024-05-11 16:54:54 +00:00

Merge commit 'f15f2fcee7eeb5a100bd204a0e67018e25953420' into haugesund

This commit is contained in:
Maria Matejka
2022-05-30 17:36:36 +02:00
19 changed files with 720 additions and 559 deletions

View File

@@ -827,12 +827,12 @@ nl_add_nexthop(struct nlmsghdr *h, uint bufsize, struct nexthop *nh, int af UNUS
}
static void
nl_add_multipath(struct nlmsghdr *h, uint bufsize, struct nexthop *nh, int af, ea_list *eattrs)
nl_add_multipath(struct nlmsghdr *h, uint bufsize, struct nexthop_adata *nhad, int af, ea_list *eattrs)
{
struct rtattr *a = nl_open_attr(h, bufsize, RTA_MULTIPATH);
eattr *flow = ea_find(eattrs, &ea_krt_realm);
for (; nh; nh = nh->next)
NEXTHOP_WALK(nh, nhad)
{
struct rtnexthop *rtnh = nl_open_nexthop(h, bufsize);
@@ -856,31 +856,44 @@ nl_add_multipath(struct nlmsghdr *h, uint bufsize, struct nexthop *nh, int af, e
nl_close_attr(h, a);
}
static struct nexthop *
static struct nexthop_adata *
nl_parse_multipath(struct nl_parse_state *s, struct krt_proto *p, const net_addr *n, struct rtattr *ra, int af, int krt_src)
{
struct rtattr *a[BIRD_RTA_MAX];
struct rtnexthop *nh = RTA_DATA(ra);
struct nexthop *rv, *first, **last;
unsigned len = RTA_PAYLOAD(ra);
struct rtnexthop *nh, *orig_nh = RTA_DATA(ra);
unsigned len, orig_len = RTA_PAYLOAD(ra);
uint cnt = 0;
first = NULL;
last = &first;
while (len)
/* First count the nexthops */
for (len = orig_len, nh = orig_nh; len; len -= NLMSG_ALIGN(nh->rtnh_len), nh = RTNH_NEXT(nh))
{
/* Use RTNH_OK(nh,len) ?? */
if ((len < sizeof(*nh)) || (len < nh->rtnh_len))
goto err;
if ((nh->rtnh_flags & RTNH_F_DEAD) && (krt_src != KRT_SRC_BIRD))
goto next;
;
else
cnt++;
}
*last = rv = lp_allocz(s->pool, NEXTHOP_MAX_SIZE);
last = &(rv->next);
struct nexthop_adata *nhad = lp_allocz(s->pool, cnt * NEXTHOP_MAX_SIZE + sizeof *nhad);
struct nexthop *rv = &nhad->nh;
for (len = orig_len, nh = orig_nh; len; len -= NLMSG_ALIGN(nh->rtnh_len), nh = RTNH_NEXT(nh))
{
/* Use RTNH_OK(nh,len) ?? */
if ((len < sizeof(*nh)) || (len < nh->rtnh_len))
goto err;
if ((nh->rtnh_flags & RTNH_F_DEAD) && (krt_src != KRT_SRC_BIRD))
continue;
*rv = (struct nexthop) {
.weight = nh->rtnh_hops,
.iface = if_find_by_index(nh->rtnh_ifindex),
};
rv->weight = nh->rtnh_hops;
rv->iface = if_find_by_index(nh->rtnh_ifindex);
if (!rv->iface)
{
log(L_ERR "KRT: Received route %N with unknown ifindex %u", n, nh->rtnh_ifindex);
@@ -959,16 +972,14 @@ nl_parse_multipath(struct nl_parse_state *s, struct krt_proto *p, const net_addr
}
#endif
next:
len -= NLMSG_ALIGN(nh->rtnh_len);
nh = RTNH_NEXT(nh);
rv = NEXTHOP_NEXT(rv);
}
/* Ensure nexthops are sorted to satisfy nest invariant */
if (!nexthop_is_sorted(first))
first = nexthop_sort(first);
/* Store final length */
nhad->ad.length = (void *) rv - (void *) nhad->ad.data;
return first;
/* Ensure nexthops are sorted to satisfy nest invariant */
return nexthop_is_sorted(nhad) ? nhad : nexthop_sort(nhad, s->pool);
err:
log(L_ERR "KRT: Received strange multipath route %N", n);
@@ -1412,21 +1423,22 @@ krt_capable(rte *e)
}
static inline int
nh_bufsize(struct nexthop *nh)
nh_bufsize(struct nexthop_adata *nhad)
{
int rv = 0;
for (; nh != NULL; nh = nh->next)
NEXTHOP_WALK(nh, nhad)
rv += RTNH_LENGTH(RTA_LENGTH(sizeof(ip_addr)));
return rv;
}
static int
nl_send_route(struct krt_proto *p, const rte *e, int op, int dest, struct nexthop *nh)
nl_send_route(struct krt_proto *p, const rte *e, int op, int dest, struct nexthop_adata *nh)
{
eattr *ea;
rta *a = e->attrs;
ea_list *eattrs = a->eattrs;
int bufsize = 128 + KRT_METRICS_MAX*8 + nh_bufsize(&(a->nh));
int bufsize = 128 + KRT_METRICS_MAX*8 + (nh ? nh_bufsize(nh) : 0);
u32 priority = 0;
struct {
@@ -1510,7 +1522,7 @@ nl_send_route(struct krt_proto *p, const rte *e, int op, int dest, struct nextho
else if (ea = ea_find(eattrs, &ea_krt_scope))
r->r.rtm_scope = ea->u.data;
else
r->r.rtm_scope = (dest == RTD_UNICAST && ipa_zero(nh->gw)) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE;
r->r.rtm_scope = (dest == RTD_UNICAST && ipa_zero(nh->nh.gw)) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE;
if (ea = ea_find(eattrs, &ea_krt_prefsrc))
nl_add_attr_ipa(&r->h, rsize, RTA_PREFSRC, *(ip_addr *)ea->u.ptr->data);
@@ -1539,14 +1551,14 @@ dest:
{
case RTD_UNICAST:
r->r.rtm_type = RTN_UNICAST;
if (nh->next && !krt_ecmp6(p))
if (!NEXTHOP_ONE(nh) && !krt_ecmp6(p))
nl_add_multipath(&r->h, rsize, nh, p->af, eattrs);
else
{
nl_add_attr_u32(&r->h, rsize, RTA_OIF, nh->iface->index);
nl_add_nexthop(&r->h, rsize, nh, p->af);
nl_add_attr_u32(&r->h, rsize, RTA_OIF, nh->nh.iface->index);
nl_add_nexthop(&r->h, rsize, &nh->nh, p->af);
if (nh->flags & RNF_ONLINK)
if (nh->nh.flags & RNF_ONLINK)
r->r.rtm_flags |= RTNH_F_ONLINK;
}
break;
@@ -1575,21 +1587,35 @@ nl_add_rte(struct krt_proto *p, rte *e)
rta *a = e->attrs;
int err = 0;
if (krt_ecmp6(p) && a->nh.next)
eattr *nhea = ea_find(a->eattrs, &ea_gen_nexthop);
struct nexthop_adata *nhad = nhea ? (struct nexthop_adata *) nhea->u.ptr : NULL;
if (krt_ecmp6(p) && nhad && !NEXTHOP_ONE(nhad))
{
struct nexthop *nh = &(a->nh);
uint cnt = 0;
NEXTHOP_WALK(nh, nhad)
{
struct {
struct nexthop_adata nhad;
u32 labels[MPLS_MAX_LABEL_STACK];
} nhx;
memcpy(&nhx.nhad.nh, nh, NEXTHOP_SIZE(nh));
nhx.nhad.ad.length = (void *) NEXTHOP_NEXT(&nhx.nhad.nh) - (void *) nhx.nhad.ad.data;
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);
if (!cnt++)
{
err = nl_send_route(p, e, NL_OP_ADD, RTD_UNICAST, &nhx.nhad);
if (err < 0)
return err;
}
else
err += nl_send_route(p, e, NL_OP_APPEND, RTD_UNICAST, &nhx.nhad);
}
return err;
}
return nl_send_route(p, e, NL_OP_ADD, a->dest, &(a->nh));
return nl_send_route(p, e, NL_OP_ADD, a->dest, nhad);
}
static inline int
@@ -1609,7 +1635,9 @@ static inline int
nl_replace_rte(struct krt_proto *p, rte *e)
{
rta *a = e->attrs;
return nl_send_route(p, e, NL_OP_REPLACE, a->dest, &(a->nh));
eattr *nhea = ea_find(a->eattrs, &ea_gen_nexthop);
struct nexthop_adata *nhad = nhea ? (struct nexthop_adata *) nhea->u.ptr : NULL;
return nl_send_route(p, e, NL_OP_REPLACE, a->dest, nhad);
}
@@ -1860,6 +1888,15 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
else
s->rta_flow = 0;
union {
struct {
struct adata ad;
struct nexthop nh;
u32 labels[MPLS_MAX_LABEL_STACK];
};
struct nexthop_adata nhad;
} nhad = {};
switch (i->rtm_type)
{
case RTN_UNICAST:
@@ -1867,48 +1904,50 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
if (a[RTA_MULTIPATH])
{
struct nexthop *nh = nl_parse_multipath(s, p, net, a[RTA_MULTIPATH], i->rtm_family, krt_src);
struct nexthop_adata *nh = nl_parse_multipath(s, p, net, a[RTA_MULTIPATH], i->rtm_family, krt_src);
if (!nh)
SKIP("strange RTA_MULTIPATH\n");
nexthop_link(ra, nh);
ea_set_attr(&ra->eattrs, EA_LITERAL_DIRECT_ADATA(
&ea_gen_nexthop, 0, &nh->ad));
break;
}
if ((i->rtm_flags & RTNH_F_DEAD) && (krt_src != KRT_SRC_BIRD))
SKIP("ignore RTNH_F_DEAD\n");
ra->nh.iface = if_find_by_index(oif);
if (!ra->nh.iface)
nhad.nh.iface = if_find_by_index(oif);
if (!nhad.nh.iface)
{
log(L_ERR "KRT: Received route %N with unknown ifindex %u", net, oif);
return;
}
if (a[RTA_GATEWAY])
ra->nh.gw = rta_get_ipa(a[RTA_GATEWAY]);
nhad.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]);
nhad.nh.gw = rta_get_via(a[RTA_VIA]);
#endif
if (ipa_nonzero(ra->nh.gw))
if (ipa_nonzero(nhad.nh.gw))
{
/* Silently skip strange 6to4 routes */
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(nhad.nh.gw, (net_addr *) &sit))
return;
if (i->rtm_flags & RTNH_F_ONLINK)
ra->nh.flags |= RNF_ONLINK;
nhad.nh.flags |= RNF_ONLINK;
neighbor *nbr;
nbr = neigh_find(&p->p, ra->nh.gw, ra->nh.iface,
(ra->nh.flags & RNF_ONLINK) ? NEF_ONLINK : 0);
nbr = neigh_find(&p->p, nhad.nh.gw, nhad.nh.iface,
(nhad.nh.flags & RNF_ONLINK) ? NEF_ONLINK : 0);
if (!nbr || (nbr->scope == SCOPE_HOST))
{
log(L_ERR "KRT: Received route %N with strange next-hop %I", net, ra->nh.gw);
log(L_ERR "KRT: Received route %N with strange next-hop %I", net,
nhad.nh.gw);
return;
}
}
@@ -1930,10 +1969,10 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
}
#ifdef HAVE_MPLS_KERNEL
if ((i->rtm_family == AF_MPLS) && a[RTA_NEWDST] && !ra->nh.next)
ra->nh.labels = rta_get_mpls(a[RTA_NEWDST], ra->nh.label);
if ((i->rtm_family == AF_MPLS) && a[RTA_NEWDST] && !a[RTA_MULTIPATH])
nhad.nh.labels = rta_get_mpls(a[RTA_NEWDST], nhad.nh.label);
if (a[RTA_ENCAP] && a[RTA_ENCAP_TYPE] && !ra->nh.next)
if (a[RTA_ENCAP] && a[RTA_ENCAP_TYPE] && !a[RTA_MULTIPATH])
{
switch (rta_get_u16(a[RTA_ENCAP_TYPE]))
{
@@ -1942,7 +1981,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
struct rtattr *enca[BIRD_RTA_MAX];
nl_attr_len = RTA_PAYLOAD(a[RTA_ENCAP]);
nl_parse_attrs(RTA_DATA(a[RTA_ENCAP]), encap_mpls_want, enca, sizeof(enca));
ra->nh.labels = rta_get_mpls(enca[RTA_DST], ra->nh.label);
nhad.nh.labels = rta_get_mpls(enca[RTA_DST], nhad.nh.label);
break;
}
default:
@@ -1952,6 +1991,9 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
}
#endif
/* Finalize the nexthop */
nhad.ad.length = (void *) NEXTHOP_NEXT(&nhad.nh) - (void *) nhad.ad.data;
if (i->rtm_scope != def_scope)
ea_set_attr(&ra->eattrs,
EA_LITERAL_EMBEDDED(&ea_krt_scope, 0, i->rtm_scope));
@@ -1999,6 +2041,10 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
net_copy(s->net, net);
s->attrs = ra;
ea_set_attr_data(&ra->eattrs, &ea_gen_nexthop, 0,
nhad.ad.data, nhad.ad.length);
s->proto = p;
s->new = new;
s->krt_src = krt_src;
@@ -2009,20 +2055,18 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
else
{
/* Merge next hops with the stored route */
rta *oa = s->attrs;
eattr *nhea = ea_find(s->attrs->eattrs, &ea_gen_nexthop);
struct nexthop_adata *nhad_old = nhea ? (struct nexthop_adata *) nhea->u.ptr : NULL;
struct nexthop *nhs = &oa->nh;
nexthop_insert(&nhs, &ra->nh);
/* Perhaps new nexthop is inserted at the first position */
if (nhs == &ra->nh)
{
/* Swap rtas */
s->attrs = ra;
/* Keep old eattrs */
ra->eattrs = oa->eattrs;
}
if (nhad_old)
ea_set_attr(&s->attrs->eattrs,
EA_LITERAL_DIRECT_ADATA(&ea_gen_nexthop, 0,
&(nexthop_merge(nhad_old, &nhad.nhad,
KRT_CF->merge_paths, s->pool)->ad)
));
else
ea_set_attr_data(&s->attrs->eattrs, &ea_gen_nexthop, 0,
nhad.ad.data, nhad.ad.length);
}
}