Hi,
the attached patch adds support for using link-local v6 addresses for
BGP peerings by adding an interface attribute to the BGP protocol.
It has been succesfully tested in a Bird<->Quagga configuration on
Linux, and with Bird<->Bird using Linux<->Linux and Linux<->FreeBSD.

I know the BGP RFCs (especially 2545) are a bit unclear if this should
be allowed, but RFC 4659 suggests it should, and also describes how to
set the NEXT_HOP attribute when no global addresses are used.

Anyways, I'd love to see this patch included in Bird. It shouldn't make
any difference when you don't use the interface attribute, so it won't have
bad influence on people not using this feature, and it makes Bird an
alternative to Quagga when you need link-local peering support. :-)

Matthias Schiffer
From 993d07798e10f41c258c2a485650507c564e6990 Mon Sep 17 00:00:00 2001
From: Matthias Schiffer <mschif...@universe-factory.net>
Date: Tue, 14 Dec 2010 03:26:51 +0100
Subject: [PATCH] BGP: Add support for peering with link-local IPv6 addresses

---
 nest/iface.c          |    2 +-
 proto/bgp/bgp.c       |   13 ++++++++++++-
 proto/bgp/bgp.h       |    1 +
 proto/bgp/config.Y    |    3 ++-
 proto/bgp/packets.c   |    3 +++
 sysdep/bsd/krt-sock.c |    2 +-
 6 files changed, 20 insertions(+), 4 deletions(-)

diff --git a/nest/iface.c b/nest/iface.c
index c523678..2b0b9c6 100644
--- a/nest/iface.c
+++ b/nest/iface.c
@@ -483,7 +483,7 @@ ifa_update(struct ifa *a)
        break;
       }
 
-  if (!(i->flags & IF_MULTIACCESS) && a->pxlen < BITS_PER_IP_ADDRESS - 2)
+  if (!(i->flags & IF_MULTIACCESS) && !ipa_has_link_scope(a->ip) && a->pxlen < 
BITS_PER_IP_ADDRESS - 2)
     log(L_WARN "Strange prefix length %d for point-to-point interface %s", 
a->pxlen, i->name);
 #ifndef IPV6
   if ((i->flags & IF_BROADCAST) && !ipa_nonzero(a->brd))
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index 327292a..84c353e 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -574,6 +574,7 @@ bgp_connect(struct bgp_proto *p)    /* Enter Connect state 
and start establishing c
   s->saddr = p->source_addr;
   s->daddr = p->cf->remote_ip;
   s->dport = BGP_PORT;
+  s->iface = p->neigh->iface;
   s->ttl = p->cf->multihop ? : 1;
   s->rbsize = BGP_RX_BUFFER_SIZE;
   s->tbsize = BGP_TX_BUFFER_SIZE;
@@ -743,6 +744,7 @@ bgp_start_locked(struct object_lock *lock)
 {
   struct bgp_proto *p = lock->data;
   struct bgp_config *cf = p->cf;
+  struct iface *interface = NULL;
 
   if (p->p.proto_state != PS_START)
     {
@@ -759,7 +761,16 @@ bgp_start_locked(struct object_lock *lock)
       return;
     }
 
-  p->neigh = neigh_find(&p->p, &cf->remote_ip, NEF_STICKY);
+  if (*cf->interface) {
+    interface = if_find_by_name(cf->interface);
+
+    if (!interface) {
+      BGP_TRACE(D_EVENTS, "Waiting for interface %s", cf->interface);
+      return;
+    }
+  }
+
+  p->neigh = neigh_find2(&p->p, &cf->remote_ip, interface, NEF_STICKY);
   if (!p->neigh || (p->neigh->scope == SCOPE_HOST))
     {
       log(L_ERR "%s: Invalid remote address %I", p->p.name, cf->remote_ip);
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index b06f20a..c8acb25 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -47,6 +47,7 @@ struct bgp_config {
   unsigned error_delay_time_min;       /* Time to wait after an error is 
detected */
   unsigned error_delay_time_max;
   unsigned disable_after_error;                /* Disable the protocol when 
error is detected */
+  char interface[16];                  /* Interface to use */
   char *password;                      /* Password used for MD5 authentication 
*/
   struct rtable_config *igp_table;     /* Table used for recursive next hop 
lookups */
 };
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y
index e932a7f..6ea94d6 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -25,7 +25,7 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, 
RETRY,
        ADVERTISE, IPV4, CAPABILITIES, LIMIT, PASSIVE, PREFER, OLDER,
        MISSING, LLADDR, DROP, IGNORE, ROUTE, REFRESH, INTERPRET,
        COMMUNITIES, BGP_ORIGINATOR_ID, BGP_CLUSTER_LIST, IGP, TABLE,
-       GATEWAY, DIRECT, RECURSIVE)
+       GATEWAY, DIRECT, RECURSIVE, INTERFACE)
 
 CF_GRAMMAR
 
@@ -92,6 +92,7 @@ bgp_proto:
  | bgp_proto ENABLE AS4 bool ';' { BGP_CFG->enable_as4 = $4; }
  | bgp_proto CAPABILITIES bool ';' { BGP_CFG->capabilities = $3; }
  | bgp_proto ADVERTISE IPV4 bool ';' { BGP_CFG->advertise_ipv4 = $4; }
+ | bgp_proto INTERFACE TEXT ';' { strncpy(BGP_CFG->interface, $3, 
sizeof(BGP_CFG->interface)-1); }
  | bgp_proto PASSWORD TEXT ';' { BGP_CFG->password = $3; }
  | bgp_proto ROUTE LIMIT expr ';' { BGP_CFG->route_limit = $4; }
  | bgp_proto PASSIVE bool ';' { BGP_CFG->passive = $3; }
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index bf98640..7816c1d 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -434,6 +434,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;
diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c
index 53b30ca..fc73be8 100644
--- a/sysdep/bsd/krt-sock.c
+++ b/sysdep/bsd/krt-sock.c
@@ -541,7 +541,7 @@ krt_read_addr(struct ks_msg *msg)
     _I0(ifa.ip) = 0xfe800000;
 #endif
 
-  if (iface->flags & IF_MULTIACCESS)
+  if ((iface->flags & IF_MULTIACCESS) || ipa_has_link_scope(ifa.ip))
   {
     ifa.prefix = ipa_and(ifa.ip, ipa_mkmask(masklen));
 
-- 
1.7.3.3

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to