]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Fixes BGP IPv6 link local next hop handling.
authorOndrej Zajicek <santiago@crfreenet.org>
Wed, 29 Apr 2009 16:58:24 +0000 (18:58 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Wed, 29 Apr 2009 16:58:24 +0000 (18:58 +0200)
When sending 'third party' BGP update, Bird used bogus link local
addresses instead of addresses it received before.

proto/bgp/attrs.c
proto/bgp/bgp.c
proto/bgp/bgp.h
proto/bgp/packets.c

index 9a247dec90046085289c60ef9833815f62697afd..585bfd1640323cc858a4a23d0d7f0c646a546542 100644 (file)
@@ -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)
index a0bc89238bd215998ca5902e4bcfbe68f5dbb440..cbc699bb357e6d4694749013d3e50a76fe5ae4e2 100644 (file)
@@ -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
index 83ed9c7503b6f84b52a67129b795cb571d2d32c9..8477f9e5f7d537db2354202e9719200a44d6e33d 100644 (file)
@@ -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);
index 93cabbec83242eb8471c2b357a8bc6eadaf3b04a..f244e3c0317535329551601339615eb85db40e37 100644 (file)
@@ -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;