]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Sending of update messages works!
authorMartin Mares <mj@ucw.cz>
Mon, 17 Apr 2000 09:37:31 +0000 (09:37 +0000)
committerMartin Mares <mj@ucw.cz>
Mon, 17 Apr 2000 09:37:31 +0000 (09:37 +0000)
proto/bgp/attrs.c
proto/bgp/bgp.h
proto/bgp/packets.c

index 6d4fd9c8e1693229596e4ce4739c016d938c2da2..bc3de3b30dfab3d3e088c91c79a86d8c6b033d16 100644 (file)
@@ -31,13 +31,172 @@ struct attr_desc {
   void (*format)(eattr *ea, byte *buf);
 };
 
-extern struct attr_desc bgp_attr_table[];
+static int
+bgp_check_origin(struct bgp_proto *p, byte *a, int len)
+{
+  if (len > 2)
+    return 6;
+  return 0;
+}
+
+static void
+bgp_format_origin(eattr *a, byte *buf)
+{
+  static char *bgp_origin_names[] = { "IGP", "EGP", "Incomplete" };
+
+  bsprintf(buf, bgp_origin_names[a->u.data]);
+}
+
+static int
+bgp_check_path(struct bgp_proto *p, byte *a, int len)
+{
+  while (len)
+    {
+      DBG("Path segment %02x %02x\n", a[0], a[1]);
+      if (len < 2 ||
+         a[0] != BGP_PATH_AS_SET && a[0] != BGP_PATH_AS_SEQUENCE ||
+         2*a[1] + 2 > len)
+       return 11;
+      len -= 2*a[1] + 2;
+      a += 2*a[1] + 2;
+    }
+  return 0;
+}
+
+static int
+bgp_check_next_hop(struct bgp_proto *p, byte *a, int len)
+{
+  ip_addr addr;
+
+  memcpy(&addr, a, len);
+  ipa_ntoh(addr);
+  if (ipa_classify(addr) & IADDR_HOST)
+    return 0;
+  else
+    return 8;
+}
+
+static int
+bgp_check_local_pref(struct bgp_proto *p, byte *a, int len)
+{
+  if (!p->is_internal)                 /* Ignore local preference from EBGP connections */
+    return -1;
+  return 0;
+}
+
+static struct attr_desc bgp_attr_table[] = {
+  { NULL, -1, 0, 0,                                            /* Undefined */
+    NULL, NULL },
+  { "origin", 1, BAF_TRANSITIVE, EAF_TYPE_INT,                 /* BA_ORIGIN */
+    bgp_check_origin, bgp_format_origin },
+  { "as_path", -1, BAF_TRANSITIVE, EAF_TYPE_AS_PATH,           /* BA_AS_PATH */
+    bgp_check_path, NULL },
+  { "next_hop", 4, BAF_TRANSITIVE, EAF_TYPE_IP_ADDRESS,                /* BA_NEXT_HOP */
+    bgp_check_next_hop, NULL },
+  { "MED", 4, BAF_OPTIONAL, EAF_TYPE_INT,                      /* BA_MULTI_EXIT_DISC */
+    NULL, NULL },
+  { "local_pref", 4, BAF_OPTIONAL, EAF_TYPE_INT,               /* BA_LOCAL_PREF */
+    bgp_check_local_pref, NULL },
+  { "atomic_aggr", 0, BAF_OPTIONAL, EAF_TYPE_OPAQUE,           /* BA_ATOMIC_AGGR */
+    NULL, NULL },
+  { "aggregator", 6, BAF_OPTIONAL, EAF_TYPE_OPAQUE,            /* BA_AGGREGATOR */
+    NULL, NULL },
+#if 0
+  /* FIXME: Handle community lists and remember to convert their endianity and normalize them */
+  { 0, 0 },                                                                    /* BA_COMMUNITY */
+  { 0, 0 },                                                                    /* BA_ORIGINATOR_ID */
+  { 0, 0 },                                                                    /* BA_CLUSTER_LIST */
+#endif
+};
+
+byte *
+bgp_encode_attrs(byte *w, struct bgp_bucket *buck)
+{
+  int remains = 1024;
+  unsigned int i, code, flags;
+  byte *start = w;
+  int len;
+
+  w += 2;
+  for(i=0; i<buck->eattrs->count; i++)
+    {
+      eattr *a = &buck->eattrs->attrs[i];
+      ASSERT(EA_PROTO(a->id) == EAP_BGP);
+      code = EA_ID(a->id);
+      if (code && code < ARRAY_SIZE(bgp_attr_table))
+       {
+         struct attr_desc *desc = &bgp_attr_table[code];
+         len = desc->expected_length;
+         if (len < 0)
+           {
+             ASSERT(!(a->type & EAF_EMBEDDED));
+             len = a->u.ptr->length;
+           }
+       }
+      else
+       {
+         ASSERT((a->type & EAF_TYPE_MASK) == EAF_TYPE_OPAQUE);
+         len = a->u.ptr->length;
+       }
+      DBG("\tAttribute %02x (type %02x, %d bytes)\n", code, a->type, len);
+      /* FIXME: Partial bit for locally added transitive attributes */
+      if (remains < len + 4)
+       {
+         log(L_ERR "BGP: attribute list too long, ignoring the remaining attributes");
+         break;
+       }
+      flags = a->flags & (BAF_OPTIONAL | BAF_TRANSITIVE | BAF_PARTIAL);
+      if (len < 256)
+       {
+         *w++ = flags;
+         *w++ = code;
+         *w++ = len;
+         remains -= 3;
+       }
+      else
+       {
+         *w++ = flags | BAF_EXT_LEN;
+         *w++ = code;
+         put_u16(w, len);
+         w += 2;
+         remains -= 4;
+       }
+      switch (a->type & EAF_TYPE_MASK)
+       {
+       case EAF_TYPE_INT:
+       case EAF_TYPE_ROUTER_ID:
+         if (len == 4)
+           put_u32(w, a->u.data);
+         else
+           *w = a->u.data;
+         break;
+       case EAF_TYPE_IP_ADDRESS:
+         {
+           ip_addr ip = *(ip_addr *)a->u.ptr->data;
+           ipa_hton(ip);
+           memcpy(w, &ip, len);
+           break;
+         }
+       case EAF_TYPE_OPAQUE:
+       case EAF_TYPE_AS_PATH:
+       case EAF_TYPE_INT_SET:
+         memcpy(w, a->u.ptr->data, len);
+         break;
+       default:
+         bug("bgp_encode_attrs: unknown attribute type %02x", a->type);
+       }
+      remains -= len;
+      w += len;
+    }
+  put_u16(start, w-start-2);
+  return w;
+}
 
 static void
 bgp_init_prefix(struct fib_node *N)
 {
   struct bgp_prefix *p = (struct bgp_prefix *) N;
-  /* FIXME */
+  p->bucket_node.next = NULL;
 }
 
 static void
@@ -104,6 +263,8 @@ bgp_new_bucket(struct bgp_proto *p, ea_list *new, unsigned hash)
   p->bucket_hash[index] = b;
   b->hash_prev = NULL;
   b->hash = hash;
+  add_tail(&p->bucket_queue, &b->send_node);
+  init_list(&b->prefixes);
   memcpy(b->eattrs, new, ea_size);
   dest = ((byte *)b->eattrs) + ea_size_aligned;
 
@@ -169,7 +330,7 @@ bgp_get_bucket(struct bgp_proto *p, ea_list *old, ea_list *tmp)
       *d = *a;
       switch (d->type & EAF_TYPE_MASK)
        {
-       case EAF_TYPE_INT_SET:
+       case EAF_TYPE_INT_SET:          /* FIXME: Normalize the other attributes? */
          {
            struct adata *z = alloca(sizeof(struct adata) + d->u.ptr->length);
            z->length = d->u.ptr->length;
@@ -200,27 +361,60 @@ bgp_get_bucket(struct bgp_proto *p, ea_list *old, ea_list *tmp)
        return NULL;
       }
 
+  /* Check if next hop is valid */
+  a = ea_find(new, EA_CODE(EAP_BGP, BA_NEXT_HOP));
+  ASSERT(a);
+  if (ipa_equal(p->next_hop, *(ip_addr *)a->u.ptr))
+    return NULL;
+
   /* Create new bucket */
   DBG("Creating bucket.\n");
   return bgp_new_bucket(p, new, hash);
 }
 
+void
+bgp_free_bucket(struct bgp_proto *p, struct bgp_bucket *buck)
+{
+  if (buck->hash_next)
+    buck->hash_next->hash_prev = buck->hash_prev;
+  if (buck->hash_prev)
+    buck->hash_prev->hash_next = buck->hash_next;
+  else
+    p->bucket_hash[buck->hash & (p->hash_size-1)] = buck->hash_next;
+  mb_free(buck);
+}
+
 void
 bgp_rt_notify(struct proto *P, net *n, rte *new, rte *old, ea_list *tmpa)
 {
   struct bgp_proto *p = (struct bgp_proto *) P;
+  struct bgp_bucket *buck;
+  struct bgp_prefix *px;
 
-  DBG("BGP: Got route %I/%d\n", n->n.prefix, n->n.pxlen);
+  DBG("BGP: Got route %I/%d %s\n", n->n.prefix, n->n.pxlen, new ? "up" : "down");
 
   if (new)
     {
-      struct bgp_bucket *buck = bgp_get_bucket(p, new->attrs->eattrs, tmpa);
+      buck = bgp_get_bucket(p, new->attrs->eattrs, tmpa);
       if (!buck)                       /* Inconsistent attribute list */
        return;
     }
-
-  /* FIXME: Normalize attributes */
-  /* FIXME: Check next hop */
+  else
+    {
+      if (!(buck = p->withdraw_bucket))
+       {
+         buck = p->withdraw_bucket = mb_alloc(P->pool, sizeof(struct bgp_bucket));
+         init_list(&buck->prefixes);
+       }
+    }
+  px = fib_get(&p->prefix_fib, &n->n.prefix, n->n.pxlen);
+  if (px->bucket_node.next)
+    {
+      DBG("\tRemoving old entry.\n");
+      rem_node(&px->bucket_node);
+    }
+  add_tail(&buck->prefixes, &px->bucket_node);
+  bgp_schedule_packet(p->conn, PKT_UPDATE);
 }
 
 static int
@@ -404,83 +598,6 @@ bgp_path_loopy(struct bgp_proto *p, eattr *a)
   return 0;
 }
 
-static int
-bgp_check_origin(struct bgp_proto *p, byte *a, int len)
-{
-  if (len > 2)
-    return 6;
-  return 0;
-}
-
-static void
-bgp_format_origin(eattr *a, byte *buf)
-{
-  static char *bgp_origin_names[] = { "IGP", "EGP", "Incomplete" };
-
-  bsprintf(buf, bgp_origin_names[a->u.data]);
-}
-
-static int
-bgp_check_path(struct bgp_proto *p, byte *a, int len)
-{
-  while (len)
-    {
-      DBG("Path segment %02x %02x\n", a[0], a[1]);
-      if (len < 2 ||
-         a[0] != BGP_PATH_AS_SET && a[0] != BGP_PATH_AS_SEQUENCE ||
-         2*a[1] + 2 > len)
-       return 11;
-      len -= 2*a[1] + 2;
-      a += 2*a[1] + 2;
-    }
-  return 0;
-}
-
-static int
-bgp_check_next_hop(struct bgp_proto *p, byte *a, int len)
-{
-  ip_addr addr;
-
-  memcpy(&addr, a, len);
-  if (ipa_classify(ipa_ntoh(addr)) & IADDR_HOST)
-    return 0;
-  else
-    return 8;
-}
-
-static int
-bgp_check_local_pref(struct bgp_proto *p, byte *a, int len)
-{
-  if (!p->is_internal)                 /* Ignore local preference from EBGP connections */
-    return -1;
-  return 0;
-}
-
-static struct attr_desc bgp_attr_table[] = {
-  { NULL, -1, 0, 0,                                            /* Undefined */
-    NULL, NULL },
-  { "origin", 1, BAF_TRANSITIVE, EAF_TYPE_INT,                 /* BA_ORIGIN */
-    bgp_check_origin, bgp_format_origin },
-  { "as_path", -1, BAF_TRANSITIVE, EAF_TYPE_AS_PATH,           /* BA_AS_PATH */
-    bgp_check_path, NULL },
-  { "next_hop", 4, BAF_TRANSITIVE, EAF_TYPE_IP_ADDRESS,                /* BA_NEXT_HOP */
-    bgp_check_next_hop, NULL },
-  { "MED", 4, BAF_OPTIONAL, EAF_TYPE_INT,                      /* BA_MULTI_EXIT_DISC */
-    NULL, NULL },
-  { "local_pref", 4, BAF_OPTIONAL, EAF_TYPE_INT,               /* BA_LOCAL_PREF */
-    bgp_check_local_pref, NULL },
-  { "atomic_aggr", 0, BAF_OPTIONAL, EAF_TYPE_OPAQUE,           /* BA_ATOMIC_AGGR */
-    NULL, NULL },
-  { "aggregator", 6, BAF_OPTIONAL, EAF_TYPE_OPAQUE,            /* BA_AGGREGATOR */
-    NULL, NULL },
-#if 0
-  /* FIXME: Handle community lists and remember to convert their endianity and normalize them */
-  { 0, 0 },                                                                    /* BA_COMMUNITY */
-  { 0, 0 },                                                                    /* BA_ORIGINATOR_ID */
-  { 0, 0 },                                                                    /* BA_CLUSTER_LIST */
-#endif
-};
-
 struct rta *
 bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct linpool *pool)
 {
@@ -540,7 +657,7 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct lin
       DBG("Attr %02x %02x %d\n", code, flags, l);
       if (seen[code/8] & (1 << (code%8)))
        goto malformed;
-      if (code && code < sizeof(bgp_attr_table)/sizeof(bgp_attr_table[0]))
+      if (code && code < ARRAY_SIZE(bgp_attr_table))
        {
          struct attr_desc *desc = &bgp_attr_table[code];
          if (desc->expected_length >= 0 && desc->expected_length != (int) l)
@@ -591,7 +708,7 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct lin
            ea->attrs[0].u.data = get_u32(z);
          break;
        case EAF_TYPE_IP_ADDRESS:
-         *(ip_addr *)ad->data = ipa_ntoh(*(ip_addr *)ad->data);
+         ipa_ntoh(*(ip_addr *)ad->data);
          break;
        }
     }
index 9ee5b41f6aec01246926452146665986e12baba9..0f84c3bffd3e06c44ee340314074aeca4c4a8a25 100644 (file)
@@ -68,8 +68,8 @@ struct bgp_prefix {
 };
 
 struct bgp_bucket {
-  struct bgp_bucket *hash_next, *hash_prev;    /* Node in bucket hash table */
   node send_node;                      /* Node in send queue */
+  struct bgp_bucket *hash_next, *hash_prev;    /* Node in bucket hash table */
   unsigned hash;                       /* Hash over extended attributes */
   list prefixes;                       /* Prefixes in this buckets */
   ea_list eattrs[0];                   /* Per-bucket extended attributes */
@@ -97,6 +97,8 @@ 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);
+void bgp_free_bucket(struct bgp_proto *p, struct bgp_bucket *buck);
 
 /* packets.c */
 
index e85d5c07f2a827ead5d1a4f367c4766766d7f6e9..2f3f8ad94b0213b79010783a93eb306d55dcd8bb 100644 (file)
@@ -46,12 +46,76 @@ bgp_create_open(struct bgp_conn *conn, byte *buf)
   return buf+10;
 }
 
+static unsigned int
+bgp_encode_prefixes(struct bgp_proto *p, byte *w, struct bgp_bucket *buck, unsigned int remains)
+{
+  byte *start = w;
+  ip_addr a;
+  int bytes;
+
+  while (!EMPTY_LIST(buck->prefixes) && remains >= 5)
+    {
+      struct bgp_prefix *px = SKIP_BACK(struct bgp_prefix, bucket_node, HEAD(buck->prefixes));
+      DBG("\tDequeued route %I/%d\n", px->n.prefix, px->n.pxlen);
+      *w++ = px->n.pxlen;
+      bytes = (px->n.pxlen + 7) / 8;
+      a = px->n.prefix;
+      ipa_hton(a);
+      memcpy(w, &a, bytes);
+      w += bytes;
+      rem_node(&px->bucket_node);
+      fib_delete(&p->prefix_fib, px);
+    }
+  return w - start;
+}
+
 static byte *
 bgp_create_update(struct bgp_conn *conn, byte *buf)
 {
+  struct bgp_proto *bgp = conn->bgp;
+  struct bgp_bucket *buck;
+  int remains = BGP_MAX_PACKET_LENGTH - BGP_HEADER_LENGTH - 4;
+  byte *w, *wold;
+  ip_addr ip;
+  int wd_size = 0;
+  int r_size = 0;
+
   DBG("BGP: Sending update\n");
+  w = buf+2;
+  if ((buck = bgp->withdraw_bucket) && !EMPTY_LIST(buck->prefixes))
+    {
+      DBG("Withdrawn routes:\n");
+      wd_size = bgp_encode_prefixes(bgp, w, buck, remains);
+      w += wd_size;
+      remains -= wd_size;
+    }
+  put_u16(buf, wd_size);
 
-  bug("Don't know how to create updates");
+  if (remains >= 2048)
+    {
+      while ((buck = (struct bgp_bucket *) HEAD(bgp->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(bgp, buck);
+             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(bgp, w, buck, remains);
+         w += r_size;
+         break;
+       }
+    }
+  else
+    {
+      put_u16(w, 0);
+      w += 2;
+    }
+  return (wd_size || r_size) ? w : NULL;
 }
 
 static void
@@ -225,7 +289,8 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, int len)
   memcpy(&prefix, pp, q);                      \
   pp += q;                                     \
   ll -= q;                                     \
-  prefix = ipa_and(ipa_ntoh(prefix), ipa_mkmask(b)); \
+  ipa_ntoh(prefix);                            \
+  prefix = ipa_and(prefix, ipa_mkmask(b));     \
   pxlen = b;                                   \
 } while (0)
 /* FIXME: Check validity of prefixes */