diff options
author | Ondrej Zajicek <santiago@crfreenet.org> | 2012-01-08 15:28:27 +0100 |
---|---|---|
committer | Ondrej Zajicek <santiago@crfreenet.org> | 2012-01-08 15:31:34 +0100 |
commit | 53ffbff39f054e1302fb296327b9bb1b4f88226c (patch) | |
tree | 6e0f21ac671dd1cf35d7a3322a89ebb304b0c2c6 /proto/bgp/packets.c | |
parent | eb1451a3a0c45a4cc62dd0f1f3c3157ec38e2f8e (diff) |
Implements support for link-local addresses in BGP.
Thanks Matthias Schiffer for the original patch.
Diffstat (limited to 'proto/bgp/packets.c')
-rw-r--r-- | proto/bgp/packets.c | 41 |
1 files changed, 36 insertions, 5 deletions
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index c3a86731..bbb0865f 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -318,6 +318,13 @@ bgp_create_update(struct bgp_conn *conn, byte *buf) #else /* IPv6 version */ +static inline int +same_iface(struct bgp_proto *p, ip_addr *ip) +{ + neighbor *n = neigh_find(&p->p, ip, 0); + return n && p->neigh && n->iface == p->neigh->iface; +} + static byte * bgp_create_update(struct bgp_conn *conn, byte *buf) { @@ -329,7 +336,6 @@ bgp_create_update(struct bgp_conn *conn, byte *buf) ip_addr *ipp, ip, ip_ll; ea_list *ea; eattr *nh; - neighbor *n; put_u16(buf, 0); w = buf+4; @@ -399,10 +405,13 @@ bgp_create_update(struct bgp_conn *conn, byte *buf) * link local address seems to be a natural way to solve that * problem, but it is contrary to RFC 2545 and Quagga does not * accept such routes. + * + * There are two cases, either we have global IP, or + * IPA_NONE if the neighbor is link-local. For IPA_NONE, + * we suppose it is on the same iface, see bgp_update_attrs(). */ - n = neigh_find(&p->p, &ip, 0); - if (n && p->neigh && n->iface == p->neigh->iface) + if (ipa_zero(ip) || same_iface(p, &ip)) { if (second && ipa_nonzero(ipp[1])) ip_ll = ipp[1]; @@ -434,6 +443,9 @@ bgp_create_update(struct bgp_conn *conn, byte *buf) *tmp++ = BGP_AF_IPV6; *tmp++ = 1; + if (ipa_has_link_scope(ip)) + ip = IPA_NONE; + if (ipa_nonzero(ip_ll)) { *tmp++ = 32; @@ -809,13 +821,27 @@ bgp_set_next_hop(struct bgp_proto *p, rta *a) #ifdef IPV6 int second = (nh->u.ptr->length == NEXT_HOP_LENGTH); + + /* First address should not be link-local, but may be zero in direct mode */ + if (ipa_has_link_scope(*nexthop)) + *nexthop = IPA_NONE; #else int second = 0; #endif if (p->cf->gw_mode == GW_DIRECT) { - neighbor *ng = neigh_find(&p->p, nexthop, 0) ? : p->neigh; + neighbor *ng; + + if (ipa_nonzero(*nexthop)) + ng = neigh_find(&p->p, nexthop, 0); + else if (second) /* GW_DIRECT -> single_hop -> p->neigh != NULL */ + ng = neigh_find2(&p->p, nexthop + 1, p->neigh->iface, 0); + + /* Fallback */ + if (!ng) + ng = p->neigh; + if (ng->scope == SCOPE_HOST) return 0; @@ -826,7 +852,12 @@ bgp_set_next_hop(struct bgp_proto *p, rta *a) a->igp_metric = 0; } else /* GW_RECURSIVE */ - rta_set_recursive_next_hop(p->p.table, a, p->igp_table, nexthop, nexthop + second); + { + if (ipa_zero(*nexthop)) + return 0; + + rta_set_recursive_next_hop(p->p.table, a, p->igp_table, nexthop, nexthop + second); + } return 1; } |