]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
More BGP progress...
authorMartin Mares <mj@ucw.cz>
Sun, 9 Apr 2000 22:05:02 +0000 (22:05 +0000)
committerMartin Mares <mj@ucw.cz>
Sun, 9 Apr 2000 22:05:02 +0000 (22:05 +0000)
For Pavel: You can use bgp_path_prepend() for prepending AS numbers to AS paths.

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

index 64281930c4bc771f4c835872eb3168a6bd2e5f9e..0fdc3b6c595ff994c3efe58c7c5dbaa89f55b54c 100644 (file)
 
 #include "bgp.h"
 
+void
+bgp_rt_notify(struct proto *P, net *n, rte *new, rte *old, ea_list *tmpa)
+{
+  DBG("BGP: Got route %I/%d\n", n->n.prefix, n->n.pxlen);
+}
+
+static ea_list *
+bgp_create_attrs(struct bgp_proto *p, rte *e, ea_list *old, struct linpool *pool)
+{
+  ea_list *ea = lp_alloc(pool, sizeof(ea_list) + 3*sizeof(eattr));
+  eattr *a = ea->attrs;
+  rta *rta = e->attrs;
+
+  ea->next = old;
+  ea->flags = EALF_SORTED;
+  ea->count = 3;
+
+  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 = 2;                     /* Incomplete */
+  else
+    a->u.data = 0;                     /* 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;
+    }
+  else
+    {
+      byte *z;
+      a->u.ptr = lp_alloc(pool, sizeof(struct adata) + 4);
+      a->u.ptr->length = 4;
+      z = a->u.ptr->data;
+      z[0] = 2;                                /* AS_SEQUENCE */
+      z[1] = 1;                                /* 1 AS */
+      put_u16(z+2, p->local_as);
+    }
+
+  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);
+
+  /* FIXME: These rules are bogus!!! */
+  if (rta->dest == RTD_ROUTER)
+    *(ip_addr *)a->u.ptr->data = e->attrs->gw;
+  else
+    {
+      /* FIXME: Next hop == self ... how to do that? */
+      *(ip_addr *)a->u.ptr->data = IPA_NONE;
+    }
+
+  return ea;
+}
+
+ea_list *
+bgp_path_prepend(struct linpool *pool, eattr *a, ea_list *old, int as)
+{
+  struct ea_list *e = lp_alloc(pool, sizeof(ea_list) + sizeof(eattr));
+  struct adata *olda = a->u.ptr;
+  struct adata *newa;
+
+  e->next = old;
+  e->flags = EALF_SORTED;
+  e->count = 1;
+  e->attrs[0].id = EA_CODE(EAP_BGP, BA_AS_PATH);
+  e->attrs[0].flags = BAF_TRANSITIVE;
+  e->attrs[0].type = EAF_TYPE_AS_PATH;
+  if (olda->length && olda->data[0] == 2 && olda->data[1] < 255) /* Starting with sequence => just prepend the AS number */
+    {
+      newa = lp_alloc(pool, sizeof(struct adata) + olda->length + 2);
+      newa->length = olda->length + 2;
+      newa->data[0] = 2;
+      newa->data[1] = olda->data[1] + 1;
+      memcpy(newa->data+4, olda->data+2, olda->length-2);
+    }
+  else                                 /* Create new path segment */
+    {
+      newa = lp_alloc(pool, sizeof(struct adata) + olda->length + 4);
+      newa->length = olda->length + 4;
+      newa->data[0] = 2;
+      newa->data[1] = 1;
+      memcpy(newa->data+4, olda->data, olda->length);
+    }
+  put_u16(newa->data+2, as);
+  e->attrs[0].u.ptr = newa;
+  return e;
+}
+
+static ea_list *
+bgp_update_attrs(struct bgp_proto *p, rte *e, ea_list *old, struct linpool *pool)
+{
+  if (!p->is_internal)
+    old = bgp_path_prepend(pool, ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH)), old, p->local_as);
+
+  /* FIXME: Set NEXT_HOP to self */
+
+  return old;
+}
+
+int
+bgp_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *pool)
+{
+  rte *e = *new;
+  struct bgp_proto *p = (struct bgp_proto *) P;
+  struct bgp_proto *new_bgp = (e->attrs->proto->proto == &proto_bgp) ? (struct bgp_proto *) e->attrs->proto : NULL;
+
+  if (e->attrs->dest != RTD_ROUTER)    /* FIXME: This is a debugging kludge, remove some day */
+    return -1;
+  if (new_bgp)
+    {
+      if (p->local_as == new_bgp->local_as && p->is_internal && new_bgp->is_internal)
+       return -1;                      /* Don't redistribute internal routes with IBGP */
+      *attrs = bgp_update_attrs(p, e, *attrs, pool);
+    }
+  else
+    *attrs = bgp_create_attrs(p, e, *attrs, pool);
+  if (p == new_bgp)                    /* FIXME: Use a more realistic check based on the NEXT_HOP attribute */
+    return 1;
+  return 0;                            /* Leave the decision to the filter */
+}
+
+int
+bgp_rte_better(rte *new, rte *old)
+{
+  struct bgp_proto *new_bgp = (struct bgp_proto *) new->attrs->proto;
+  struct bgp_proto *old_bgp = (struct bgp_proto *) old->attrs->proto;
+  eattr *new_lpref = ea_find(new->attrs->eattrs, EA_CODE(EAP_BGP, BA_LOCAL_PREF));
+  eattr *old_lpref = ea_find(old->attrs->eattrs, EA_CODE(EAP_BGP, BA_LOCAL_PREF));
+
+  /* Start with local preferences */
+  if (new_lpref && old_lpref)          /* Somebody might have undefined them */
+    {
+      if (new_lpref->u.data > old_lpref->u.data)
+       return 1;
+      if (new_lpref->u.data < old_lpref->u.data)
+       return 0;
+    }
+
+  /* A tie breaking procedure according to RFC 1771, section 9.1.2.1 */
+  /* FIXME: Look at MULTI_EXIT_DISC, take the lowest */
+  /* We don't have interior distances */
+  /* We prefer external peers */
+  if (new_bgp->is_internal > old_bgp->is_internal)
+    return 0;
+  if (new_bgp->is_internal < old_bgp->is_internal)
+    return 1;
+  /* Finally we compare BGP identifiers */
+  return (new_bgp->remote_id < old_bgp->remote_id);
+}
+
 static int
-bgp_check_origin(byte *a, int len)
+bgp_local_pref(struct bgp_proto *p, rta *a)
+{
+  return 0;                            /* FIXME (should be compatible with Cisco defaults?) */
+}
+
+static int
+bgp_path_loopy(struct bgp_proto *p, eattr *a)
+{
+  byte *path = a->u.ptr->data;
+  int len = a->u.ptr->length;
+  int i, n;
+
+  while (len > 0)
+    {
+      n = path[1];
+      len -= 2 - 2*n;
+      path += 2;
+      for(i=0; i<n; i++)
+       {
+         if (get_u16(path) == p->local_as)
+           return 1;
+         path += 2;
+       }
+    }
+  return 0;
+}
+
+static int
+bgp_check_origin(struct bgp_proto *p, byte *a, int len)
 {
   if (len > 2)
     return 6;
@@ -28,7 +214,7 @@ bgp_check_origin(byte *a, int len)
 }
 
 static void
-bgp_format_origin(struct eattr *a, byte *buf)
+bgp_format_origin(eattr *a, byte *buf)
 {
   static char *bgp_origin_names[] = { "IGP", "EGP", "Incomplete" };
 
@@ -36,7 +222,7 @@ bgp_format_origin(struct eattr *a, byte *buf)
 }
 
 static int
-bgp_check_path(byte *a, int len)
+bgp_check_path(struct bgp_proto *p, byte *a, int len)
 {
   while (len)
     {
@@ -52,7 +238,7 @@ bgp_check_path(byte *a, int len)
 }
 
 static int
-bgp_check_next_hop(byte *a, int len)
+bgp_check_next_hop(struct bgp_proto *p, byte *a, int len)
 {
   ip_addr addr;
 
@@ -63,13 +249,21 @@ bgp_check_next_hop(byte *a, int len)
     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;
+}
+
 struct attr_desc {
   char *name;                          /* FIXME: Use the same names as in filters */
   int expected_length;
   int expected_flags;
   int type;
-  int (*validate)(byte *attr, int len);
-  void (*format)(struct eattr *ea, byte *buf);
+  int (*validate)(struct bgp_proto *p, byte *attr, int len);
+  void (*format)(eattr *ea, byte *buf);
 };
 
 static struct attr_desc bgp_attr_table[] = {
@@ -84,7 +278,7 @@ static struct attr_desc bgp_attr_table[] = {
   { "MED", 4, BAF_OPTIONAL, EAF_TYPE_INT,                      /* BA_MULTI_EXIT_DISC */
     NULL, NULL },
   { "local_pref", 4, BAF_OPTIONAL, EAF_TYPE_INT,               /* BA_LOCAL_PREF */
-    NULL, NULL },
+    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 */
@@ -104,7 +298,8 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct lin
 {
   struct bgp_proto *bgp = conn->bgp;
   rta *a = lp_alloc(pool, sizeof(struct rta));
-  unsigned int flags, code, l, errcode, i, type;
+  unsigned int flags, code, l, i, type;
+  int errcode;
   byte *z, *attr_start;
   byte seen[256/8];
   eattr *e;
@@ -157,7 +352,6 @@ 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;
-      seen[code/8] |= (1 << (code%8));
       if (code && code < sizeof(bgp_attr_table)/sizeof(bgp_attr_table[0]))
        {
          struct attr_desc *desc = &bgp_attr_table[code];
@@ -165,8 +359,14 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct lin
            { errcode = 5; goto err; }
          if ((desc->expected_flags ^ flags) & (BAF_OPTIONAL | BAF_TRANSITIVE))
            { errcode = 4; goto err; }
-         if (desc->validate && (errcode = desc->validate(z, l)))
-           goto err;
+         if (desc->validate)
+           {
+             errcode = desc->validate(bgp, z, l);
+             if (errcode > 0)
+               goto err;
+             if (errcode < 0)
+               continue;
+           }
          type = desc->type;
        }
       else                             /* Unknown attribute */
@@ -175,7 +375,8 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct lin
            { errcode = 2; goto err; }
          type = EAF_TYPE_OPAQUE;
        }
-      ea = lp_alloc(pool, sizeof(struct ea_list) + sizeof(struct eattr));
+      seen[code/8] |= (1 << (code%8));
+      ea = lp_alloc(pool, sizeof(ea_list) + sizeof(eattr));
       ea->next = a->eattrs;
       a->eattrs = ea;
       ea->flags = 0;
@@ -218,6 +419,26 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct lin
        }
     }
 
+  /* Assign local preference if none defined */
+  if (!(seen[BA_LOCAL_PREF/8] & (1 << (BA_LOCAL_PREF%8))))
+    {
+      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 = bgp_local_pref(bgp, a);
+    }
+
+  /* If the AS path attribute contains our AS, reject the routes */
+  e = ea_find(a->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH));
+  ASSERT(e);
+  if (bgp_path_loopy(bgp, e))
+    return NULL;
+
   /* Fill in the remaining rta fields */
   e = ea_find(a->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP));
   ASSERT(e);
index f325aa3063c41e1117ec60374e3e4d49ae5e6b10..11729db4f41e331dbd204a25026e1f476569165b 100644 (file)
@@ -28,12 +28,6 @@ static char *bgp_state_names[] = { "Idle", "Connect", "Active", "OpenSent", "Ope
 static void bgp_connect(struct bgp_proto *p);
 static void bgp_setup_sk(struct bgp_proto *p, struct bgp_conn *conn, sock *s);
 
-static void
-bgp_rt_notify(struct proto *P, net *n, rte *new, rte *old, ea_list *tmpa)
-{
-  DBG("BGP: Got route %I/%d\n", n->n.prefix, n->n.pxlen);
-}
-
 static struct proto *
 bgp_init(struct proto_config *C)
 {
@@ -42,6 +36,8 @@ bgp_init(struct proto_config *C)
   struct bgp_proto *p = (struct bgp_proto *) P;
 
   P->rt_notify = bgp_rt_notify;
+  P->rte_better = bgp_rte_better;
+  P->import_control = bgp_import_control;
   p->cf = c;
   p->local_as = c->local_as;
   p->remote_as = c->remote_as;
index 8aaac88cd2403d5efe36fad83a66b64de97f1cad..45f7e0b132a917582376068d6abf7f0085d28edf 100644 (file)
@@ -69,6 +69,10 @@ void bgp_close_conn(struct bgp_conn *c);
 
 struct rta *bgp_decode_attrs(struct bgp_conn *conn, byte *a, unsigned int len, struct linpool *pool);
 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 *);
+struct ea_list *bgp_path_prepend(struct linpool *pool, struct eattr *a, struct ea_list *old, int as);
 
 /* packets.c */