diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index f6cbed4c..7069d982 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -434,6 +434,19 @@ bgp_start_neighbor(struct bgp_proto *p) { p->local_addr = p->neigh->iface->addr->ip; DBG("BGP: local=%I remote=%I\n", p->local_addr, p->next_hop); +#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))); + WALK_LIST(a, p->neigh->iface->addrs) + if (a->scope == SCOPE_LINK) + { + p->local_link = a->ip; + break; + } + DBG("BGP: Selected link-level address %I\n", p->local_link); + } +#endif bgp_initiate(p); } diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 03f47f99..6519db85 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -74,6 +74,7 @@ struct bgp_proto { #ifdef IPV6 byte *mp_reach_start, *mp_unreach_start; /* Multiprotocol BGP attribute notes */ unsigned mp_reach_len, mp_unreach_len; + ip_addr local_link; /* Link-level version of local_addr */ #endif }; diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index bf893436..03b22117 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -193,20 +193,27 @@ bgp_create_update(struct bgp_conn *conn, byte *buf) nh = ea_find(buck->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP)); ASSERT(nh); ip = *(ip_addr *) nh->u.ptr->data; + is_ll = 0; if (ipa_equal(ip, p->local_addr)) - is_ll = 1; + { + is_ll = 1; + ip_ll = p->local_link; + } else { n = neigh_find(&p->p, &ip, 0); if (n && n->iface == p->neigh->iface) - is_ll = 1; - else - is_ll = 0; + { + /* 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))); + } } if (is_ll) { *tmp++ = 32; - ip_ll = ipa_or(ipa_build(0xfe80,0,0,0), ipa_and(ip, ipa_build(0,0,~0,~0))); ipa_hton(ip); memcpy(tmp, &ip, 16); ipa_hton(ip_ll);