Commit 4827b69f authored by Ondřej Zajíček's avatar Ondřej Zajíček

Fixes BGP IPv6 link local next hop handling.

When sending 'third party' BGP update, Bird used bogus link local
addresses instead of addresses it received before.
parent ad440a57
......@@ -786,13 +786,13 @@ bgp_create_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *p
put_u16(z+2, p->local_as);
}
z = bgp_set_attr_wa(ea->attrs+2, pool, BA_NEXT_HOP, sizeof(ip_addr));
z = bgp_set_attr_wa(ea->attrs+2, pool, BA_NEXT_HOP, NEXT_HOP_LENGTH);
if (p->cf->next_hop_self ||
!p->is_internal ||
rta->dest != RTD_ROUTER)
*(ip_addr *)z = p->source_addr;
set_next_hop(z, p->source_addr);
else
*(ip_addr *)z = e->attrs->gw;
set_next_hop(z, e->attrs->gw);
bgp_set_attr(ea->attrs+3, BA_LOCAL_PREF, 0);
......@@ -862,7 +862,8 @@ bgp_update_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *p
else
{
/* Need to create new one */
bgp_attach_attr_ip(attrs, pool, BA_NEXT_HOP, p->source_addr);
byte *b = bgp_attach_attr_wa(attrs, pool, BA_NEXT_HOP, NEXT_HOP_LENGTH);
set_next_hop(b, p->source_addr);
}
if (rr)
......
......@@ -612,13 +612,17 @@ bgp_start_neighbor(struct bgp_proto *p)
#ifdef IPV6
{
struct ifa *a;
p->local_link = ipa_or(ipa_build(0xfe80,0,0,0), ipa_and(p->local_addr, ipa_build(0,0,~0,~0)));
p->local_link = IPA_NONE;
WALK_LIST(a, p->neigh->iface->addrs)
if (a->scope == SCOPE_LINK)
{
p->local_link = a->ip;
break;
}
if (! ipa_nonzero(p->local_link))
log(L_WARN "%s: Missing link local address on interface %s", p->p.name, p->neigh->iface->name);
DBG("BGP: Selected link-level address %I\n", p->local_link);
}
#endif
......
......@@ -148,6 +148,17 @@ void bgp_store_error(struct bgp_proto *p, struct bgp_conn *c, u8 class, u32 code
/* attrs.c */
/* Hack: although BA_NEXT_HOP attribute has type EAF_TYPE_IP_ADDRESS, in IPv6
* we store two addesses in it - a global address and a link local address.
*/
#ifdef IPV6
#define NEXT_HOP_LENGTH (2*sizeof(ip_addr))
static inline void set_next_hop(byte *b, ip_addr addr) { ((ip_addr *) b)[0] = addr; ((ip_addr *) b)[1] = IPA_NONE; }
#else
#define NEXT_HOP_LENGTH sizeof(ip_addr)
static inline void set_next_hop(byte *b, ip_addr addr) { ((ip_addr *) b)[0] = addr; }
#endif
void bgp_attach_attr(struct ea_list **to, struct linpool *pool, unsigned attr, uintptr_t val);
byte *bgp_attach_attr_wa(struct ea_list **to, struct linpool *pool, unsigned attr, unsigned len);
struct rta *bgp_decode_attrs(struct bgp_conn *conn, byte *a, unsigned int len, struct linpool *pool, int mandatory);
......
......@@ -234,10 +234,10 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
{
struct bgp_proto *p = conn->bgp;
struct bgp_bucket *buck;
int size, is_ll;
int size;
int remains = BGP_MAX_PACKET_LENGTH - BGP_HEADER_LENGTH - 4;
byte *w, *tmp, *tstart;
ip_addr ip, ip_ll;
ip_addr *ipp, ip, ip_ll;
ea_list *ea;
eattr *nh;
neighbor *n;
......@@ -291,26 +291,31 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
*tmp++ = 1;
nh = ea_find(buck->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP));
ASSERT(nh);
ip = *(ip_addr *) nh->u.ptr->data;
is_ll = 0;
/* We have two addresses here in 'nh'. Really. */
ipp = (ip_addr *) nh->u.ptr->data;
ip = ipp[0];
ip_ll = IPA_NONE;
if (ipa_equal(ip, p->source_addr))
{
is_ll = 1;
ip_ll = p->local_link;
}
ip_ll = p->local_link;
else
{
/* If we send a route with 'third party' next hop destinated
* in the same interface, we should also send a link local
* next hop address. We use the received one (stored in the
* other part of BA_NEXT_HOP eattr). If we didn't received
* it (for example it is a static route), we do not send link
* local next hop address. It is contrary to RFC 2545, but
* probably the only sane possibility.
*/
n = neigh_find(&p->p, &ip, 0);
if (n && n->iface == p->neigh->iface)
{
/* FIXME: We are assuming the global scope addresses use the lower 64 bits
* as an interface identifier which hasn't necessarily to be true.
*/
is_ll = 1;
ip_ll = ipa_or(ipa_build(0xfe800000,0,0,0), ipa_and(ip, ipa_build(0,0,~0,~0)));
}
ip_ll = ipp[1];
}
if (is_ll)
if (ipa_nonzero(ip_ll))
{
*tmp++ = 32;
ipa_hton(ip);
......@@ -326,6 +331,7 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
memcpy(tmp, &ip, 16);
tmp += 16;
}
*tmp++ = 0; /* No SNPA information */
tmp += bgp_encode_prefixes(p, tmp, buck, remains - (8+3+32+1));
ea->attrs[0].u.ptr->length = tmp - tstart;
......@@ -778,9 +784,18 @@ bgp_do_rx_update(struct bgp_conn *conn,
if (len < 1 || (*x != 16 && *x != 32) || len < *x + 2)
goto bad;
byte *nh = bgp_attach_attr_wa(&a0->eattrs, bgp_linpool, BA_NEXT_HOP, 16);
ip_addr *nh = (ip_addr *) bgp_attach_attr_wa(&a0->eattrs, bgp_linpool, BA_NEXT_HOP, NEXT_HOP_LENGTH);
memcpy(nh, x+1, 16);
ipa_ntoh(*(ip_addr *)nh);
ipa_ntoh(nh[0]);
/* We store received link local address in the other part of BA_NEXT_HOP eattr. */
if (*x == 32)
{
memcpy(nh+1, x+17, 16);
ipa_ntoh(nh[1]);
}
else
nh[1] = IPA_NONE;
/* Also ignore one reserved byte */
len -= *x + 2;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment