]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
IPv6 BGP support finished. Also simplified the BGP stuff a bit.
authorMartin Mares <mj@ucw.cz>
Thu, 4 May 2000 20:02:56 +0000 (20:02 +0000)
committerMartin Mares <mj@ucw.cz>
Thu, 4 May 2000 20:02:56 +0000 (20:02 +0000)
proto/bgp/attrs.c
proto/bgp/bgp.h
proto/bgp/packets.c

index 3d79efd9581f4cfa6bb04057d4ca5426bab2fee0..ff434e56734108eab98834233043cca37cf7a27f 100644 (file)
@@ -93,10 +93,8 @@ bgp_check_reach_nlri(struct bgp_proto *p, byte *a, int len)
 #ifdef IPV6
   p->mp_reach_start = a;
   p->mp_reach_len = len;
-  return 0;
-#else
-  return -1;
 #endif
+  return -1;
 }
 
 static int
@@ -105,10 +103,8 @@ bgp_check_unreach_nlri(struct bgp_proto *p, byte *a, int len)
 #ifdef IPV6
   p->mp_unreach_start = a;
   p->mp_unreach_len = len;
-  return 0;
-#else
-  return -1;
 #endif
+  return -1;
 }
 
 static struct attr_desc bgp_attr_table[] = {
@@ -143,20 +139,54 @@ static struct attr_desc bgp_attr_table[] = {
 
 #define ATTR_KNOWN(code) ((code) < ARRAY_SIZE(bgp_attr_table) && bgp_attr_table[code].name)
 
+static byte *
+bgp_set_attr(eattr *e, struct linpool *pool, unsigned attr, unsigned val)
+{
+  ASSERT(ATTR_KNOWN(attr));
+  e->id = EA_CODE(EAP_BGP, attr);
+  e->type = bgp_attr_table[attr].type;
+  e->flags = bgp_attr_table[attr].expected_flags;
+  if (e->type & EAF_EMBEDDED)
+    {
+      e->u.data = val;
+      return NULL;
+    }
+  else
+    {
+      e->u.ptr = lp_alloc(pool, sizeof(struct adata) + val);
+      e->u.ptr->length = val;
+      return e->u.ptr->data;
+    }
+}
+
 byte *
-bgp_encode_attrs(byte *w, struct bgp_bucket *buck)
+bgp_attach_attr(ea_list **to, struct linpool *pool, unsigned attr, unsigned val)
+{
+  ea_list *a = lp_alloc(pool, sizeof(ea_list) + sizeof(eattr));
+  a->next = *to;
+  *to = a;
+  a->flags = EALF_SORTED;
+  a->count = 1;
+  return bgp_set_attr(a->attrs, pool, attr, val);
+}
+
+unsigned int
+bgp_encode_attrs(byte *w, ea_list *attrs, int remains)
 {
-  int remains = 1024;
   unsigned int i, code, flags;
   byte *start = w;
   int len;
 
-  w += 2;
-  for(i=0; i<buck->eattrs->count; i++)
+  for(i=0; i<attrs->count; i++)
     {
-      eattr *a = &buck->eattrs->attrs[i];
+      eattr *a = &attrs->attrs[i];
       ASSERT(EA_PROTO(a->id) == EAP_BGP);
       code = EA_ID(a->id);
+#ifdef IPV6
+      /* When talking multiprotocol BGP, the NEXT_HOP attributes are used only temporarily. */
+      if (code == BA_NEXT_HOP)
+       continue;
+#endif
       flags = a->flags & (BAF_OPTIONAL | BAF_TRANSITIVE | BAF_PARTIAL);
       if (ATTR_KNOWN(code))
        {
@@ -228,8 +258,7 @@ bgp_encode_attrs(byte *w, struct bgp_bucket *buck)
       remains -= len;
       w += len;
     }
-  put_u16(start, w-start-2);
-  return w;
+  return w - start;
 }
 
 static void
@@ -523,60 +552,36 @@ static int
 bgp_create_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *pool)
 {
   ea_list *ea = lp_alloc(pool, sizeof(ea_list) + 4*sizeof(eattr));
-  eattr *a = ea->attrs;
   rta *rta = e->attrs;
+  byte *z;
 
   ea->next = *attrs;
   *attrs = ea;
   ea->flags = EALF_SORTED;
   ea->count = 4;
 
-  a->id = EA_CODE(EAP_BGP, BA_ORIGIN);
-  a->flags = BAF_TRANSITIVE;
-  a->type = EAF_TYPE_INT;
-  if (rta->source == RTS_RIP_EXT || rta->source == RTS_OSPF_EXT)
-    a->u.data = ORIGIN_INCOMPLETE;
-  else
-    a->u.data = ORIGIN_IGP;
-  a++;
+  bgp_set_attr(ea->attrs, pool, BA_ORIGIN,
+       (rta->source == RTS_RIP_EXT || rta->source == RTS_OSPF_EXT) ? ORIGIN_INCOMPLETE : ORIGIN_IGP);
 
-  a->id = EA_CODE(EAP_BGP, BA_AS_PATH);
-  a->flags = BAF_TRANSITIVE;
-  a->type = EAF_TYPE_AS_PATH;
   if (p->is_internal)
-    {
-      a->u.ptr = lp_alloc(pool, sizeof(struct adata));
-      a->u.ptr->length = 0;
-    }
+    bgp_set_attr(ea->attrs+1, pool, BA_AS_PATH, 0);
   else
     {
-      byte *z;
-      a->u.ptr = lp_alloc(pool, sizeof(struct adata) + 4);
-      a->u.ptr->length = 4;
-      z = a->u.ptr->data;
+      z = bgp_set_attr(ea->attrs+1, pool, BA_AS_PATH, 4);
       z[0] = AS_PATH_SEQUENCE;
       z[1] = 1;                                /* 1 AS */
       put_u16(z+2, p->local_as);
     }
-  a++;
 
-  a->id = EA_CODE(EAP_BGP, BA_NEXT_HOP);
-  a->flags = BAF_TRANSITIVE;
-  a->type = EAF_TYPE_IP_ADDRESS;
-  a->u.ptr = lp_alloc(pool, sizeof(struct adata) + sizeof(ip_addr));
-  a->u.ptr->length = sizeof(ip_addr);
+  z = bgp_set_attr(ea->attrs+2, pool, BA_NEXT_HOP, sizeof(ip_addr));
   if (p->cf->next_hop_self ||
       !p->is_internal ||
       rta->dest != RTD_ROUTER)
-    *(ip_addr *)a->u.ptr->data = p->local_addr;
+    *(ip_addr *)z = p->local_addr;
   else
-    *(ip_addr *)a->u.ptr->data = e->attrs->gw;
-  a++;
+    *(ip_addr *)z = e->attrs->gw;
 
-  a->id = EA_CODE(EAP_BGP, BA_LOCAL_PREF);
-  a->flags = BAF_OPTIONAL;
-  a->type = EAF_TYPE_INT;
-  a->u.data = 0;
+  bgp_set_attr(ea->attrs+3, pool, BA_LOCAL_PREF, 0);
 
   return 0;                            /* Leave decision to the filters */
 }
@@ -602,8 +607,8 @@ bgp_update_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *p
 {
   eattr *a;
 
-  if (!p->is_internal)
-    *attrs = bgp_path_prepend(pool, ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH)), *attrs, p->local_as);
+  if (!p->is_internal && (a = ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH))))
+    *attrs = bgp_path_prepend(pool, a, *attrs, p->local_as);
 
   a = ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP));
   if (a && (p->is_internal || (!p->is_internal && e->attrs->iface == p->neigh->iface)))
@@ -613,18 +618,7 @@ bgp_update_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *p
   else
     {
       /* Need to create new one */
-      ea_list *ea = lp_alloc(pool, sizeof(ea_list) + sizeof(eattr));
-      ea->next = *attrs;
-      *attrs = ea;
-      ea->flags = EALF_SORTED;
-      ea->count = 1;
-      a = ea->attrs;
-      a->id = EA_CODE(EAP_BGP, BA_NEXT_HOP);
-      a->flags = BAF_TRANSITIVE;
-      a->type = EAF_TYPE_IP_ADDRESS;
-      a->u.ptr = lp_alloc(pool, sizeof(struct adata) + sizeof(ip_addr));
-      a->u.ptr->length = sizeof(ip_addr);
-      *(ip_addr *)a->u.ptr->data = p->local_addr;
+      *(ip_addr *) bgp_attach_attr(attrs, pool, BA_NEXT_HOP, sizeof(ip_addr)) = p->local_addr;
     }
 
   return 0;                            /* Leave decision to the filters */
@@ -884,17 +878,7 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct lin
 
   /* If there's no local preference, define one */
   if (!(seen[0] && (1 << BA_LOCAL_PREF)))
-    {
-      ea = lp_alloc(pool, sizeof(ea_list) + sizeof(eattr));
-      ea->next = a->eattrs;
-      a->eattrs = ea;
-      ea->flags = 0;
-      ea->count = 1;
-      ea->attrs[0].id = EA_CODE(EAP_BGP, BA_LOCAL_PREF);
-      ea->attrs[0].flags = BAF_OPTIONAL;
-      ea->attrs[0].type = EAF_TYPE_INT;
-      ea->attrs[0].u.data = 0;
-    }
+    bgp_attach_attr(&a->eattrs, pool, BA_LOCAL_PREF, 0);
   return a;
 
 malformed:
index 37f29792081685e3ee4fadbc8b522871ecdb2f71..38baccdb76a6ff517816d6f41bbe8bd5f5a72871 100644 (file)
@@ -115,13 +115,14 @@ void bgp_close_conn(struct bgp_conn *c);
 
 /* attrs.c */
 
+byte *bgp_attach_attr(struct ea_list **to, struct linpool *, unsigned attr, unsigned val);
 struct rta *bgp_decode_attrs(struct bgp_conn *conn, byte *a, unsigned int len, struct linpool *pool, int mandatory);
 int bgp_get_attr(struct eattr *e, byte *buf);
 int bgp_rte_better(struct rte *, struct rte *);
 void bgp_rt_notify(struct proto *, struct network *, struct rte *, struct rte *, struct ea_list *);
 int bgp_import_control(struct proto *, struct rte **, struct ea_list **, struct linpool *);
 void bgp_attr_init(struct bgp_proto *);
-byte *bgp_encode_attrs(byte *w, struct bgp_bucket *buck);
+unsigned int bgp_encode_attrs(byte *w, struct ea_list *attrs, int remains);
 void bgp_free_bucket(struct bgp_proto *p, struct bgp_bucket *buck);
 
 /* packets.c */
index 45397fbf5366811970d84dfc77a368acb8d61f64..e9ba050b6ad2bcef35661c2bf1c785170a81560f 100644 (file)
@@ -76,10 +76,11 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
   struct bgp_proto *p = conn->bgp;
   struct bgp_bucket *buck;
   int remains = BGP_MAX_PACKET_LENGTH - BGP_HEADER_LENGTH - 4;
-  byte *w, *wold;
+  byte *w;
   ip_addr ip;
   int wd_size = 0;
   int r_size = 0;
+  int a_size = 0;
 
   BGP_TRACE(D_PACKETS, "Sending UPDATE");
   w = buf+2;
@@ -104,9 +105,10 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
              continue;
            }
          DBG("Processing bucket %p\n", buck);
-         w = bgp_encode_attrs(w, buck);
-         remains = BGP_MAX_PACKET_LENGTH - BGP_HEADER_LENGTH - (w-buf);
-         r_size = bgp_encode_prefixes(p, w, buck, remains);
+         a_size = bgp_encode_attrs(w+2, buck->eattrs, 1024);
+         put_u16(w, a_size);
+         w += a_size + 2;
+         r_size = bgp_encode_prefixes(p, w, buck, remains - a_size);
          w += r_size;
          break;
        }
@@ -124,7 +126,94 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
 static byte *
 bgp_create_update(struct bgp_conn *conn, byte *buf)
 {
-  return NULL;
+  struct bgp_proto *p = conn->bgp;
+  struct bgp_bucket *buck;
+  int size, is_ll;
+  int remains = BGP_MAX_PACKET_LENGTH - BGP_HEADER_LENGTH - 4;
+  byte *w, *tmp, *tstart;
+  ip_addr ip, ip_ll;
+  ea_list *ea;
+  eattr *nh;
+  neighbor *n;
+
+  BGP_TRACE(D_PACKETS, "Sending UPDATE");
+  put_u16(buf, 0);
+  w = buf+4;
+
+  if ((buck = p->withdraw_bucket) && !EMPTY_LIST(buck->prefixes))
+    {
+      DBG("Withdrawn routes:\n");
+      tmp = bgp_attach_attr(&ea, bgp_linpool, BA_MP_UNREACH_NLRI, remains-8);
+      *tmp++ = 0;
+      *tmp++ = BGP_AF_IPV6;
+      *tmp++ = 1;
+      ea->attrs[0].u.ptr->length = bgp_encode_prefixes(p, tmp, buck, remains-11);
+      size = bgp_encode_attrs(w, ea, remains);
+      w += size;
+      remains -= size;
+    }
+
+  if (remains >= 2048)
+    {
+      while ((buck = (struct bgp_bucket *) HEAD(p->bucket_queue))->send_node.next)
+       {
+         if (EMPTY_LIST(buck->prefixes))
+           {
+             DBG("Deleting empty bucket %p\n", buck);
+             rem_node(&buck->send_node);
+             bgp_free_bucket(p, buck);
+             continue;
+           }
+         DBG("Processing bucket %p\n", buck);
+         size = bgp_encode_attrs(w, buck->eattrs, 1024);
+         w += size;
+         remains -= size;
+         tstart = tmp = bgp_attach_attr(&ea, bgp_linpool, BA_MP_REACH_NLRI, remains-8);
+         *tmp++ = 0;
+         *tmp++ = BGP_AF_IPV6;
+         *tmp++ = 1;
+         nh = ea_find(buck->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP));
+         ASSERT(nh);
+         ip = *(ip_addr *) nh->u.ptr->data;
+         if (ipa_equal(ip, p->local_addr))
+           is_ll = 1;
+         else
+           {
+             n = neigh_find(&p->p, &ip, 0);
+             if (n && n->iface == p->neigh->iface)
+               is_ll = 1;
+             else
+               is_ll = 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);
+             memcpy(tmp+16, &ip_ll, 16);
+             tmp += 32;
+           }
+         else
+           {
+             *tmp++ = 16;
+             ipa_hton(ip);
+             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;
+         w += bgp_encode_attrs(w, ea, remains);
+         break;
+       }
+    }
+
+  size = w - (buf+4);
+  put_u16(buf+2, size);
+  lp_flush(bgp_linpool);
+  return size ? w : NULL;
 }
 
 #endif
@@ -476,16 +565,7 @@ bgp_do_rx_update(struct bgp_conn *conn,
       /* Create fake NEXT_HOP attribute */
       if (len < 1 || (*x != 16 && *x != 32) || len < *x + 2)
        goto bad;
-      e->next = a0->eattrs;
-      a0->eattrs = e;
-      e->flags = EALF_SORTED;
-      e->count = 1;
-      e->attrs[0].id = EA_CODE(EAP_BGP, BA_NEXT_HOP);
-      e->attrs[0].flags = BAF_TRANSITIVE;
-      e->attrs[0].type = EAF_TYPE_IP_ADDRESS;
-      e->attrs[0].u.ptr = ad;
-      ad->length = 16;
-      memcpy(ad->data, x+1, 16);
+      memcpy(bgp_attach_attr(&a0->eattrs, bgp_linpool, BA_NEXT_HOP, 16), x+1, 16);
       len -= *x + 1;
       x += *x + 1;