]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Receive-only IPv6 BGP.
authorMartin Mares <mj@ucw.cz>
Thu, 4 May 2000 09:03:31 +0000 (09:03 +0000)
committerMartin Mares <mj@ucw.cz>
Thu, 4 May 2000 09:03:31 +0000 (09:03 +0000)
proto/bgp/attrs.c
proto/bgp/bgp.h
proto/bgp/packets.c

index 40130c631488ab76a7426f1b9c454532cca2947f..3d79efd9581f4cfa6bb04057d4ca5426bab2fee0 100644 (file)
 
 #include "bgp.h"
 
-static byte bgp_mandatory_attrs[] = { BA_ORIGIN, BA_AS_PATH, BA_NEXT_HOP };
+static byte bgp_mandatory_attrs[] = { BA_ORIGIN, BA_AS_PATH
+#ifndef IPV6
+,BA_NEXT_HOP
+#endif
+};
 
 struct attr_desc {
   char *name;
@@ -69,6 +73,9 @@ bgp_check_path(struct bgp_proto *p, byte *a, int len)
 static int
 bgp_check_next_hop(struct bgp_proto *p, byte *a, int len)
 {
+#ifdef IPV6
+  return -1;
+#else
   ip_addr addr;
 
   memcpy(&addr, a, len);
@@ -77,31 +84,61 @@ bgp_check_next_hop(struct bgp_proto *p, byte *a, int len)
     return 0;
   else
     return 8;
+#endif
+}
+
+static int
+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
+}
+
+static int
+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
 }
 
 static struct attr_desc bgp_attr_table[] = {
-  { NULL, -1, 0, 0, 0,                                         /* Undefined */
+  { NULL, -1, 0, 0, 0,                                                         /* Undefined */
     NULL, NULL },
-  { "origin", 1, BAF_TRANSITIVE, EAF_TYPE_INT, 1,              /* BA_ORIGIN */
+  { "origin", 1, BAF_TRANSITIVE, EAF_TYPE_INT, 1,                              /* BA_ORIGIN */
     bgp_check_origin, bgp_format_origin },
-  { "as_path", -1, BAF_TRANSITIVE, EAF_TYPE_AS_PATH, 1,                /* BA_AS_PATH */
+  { "as_path", -1, BAF_TRANSITIVE, EAF_TYPE_AS_PATH, 1,                                /* BA_AS_PATH */
     bgp_check_path, NULL },
-  { "next_hop", 4, BAF_TRANSITIVE, EAF_TYPE_IP_ADDRESS, 1,     /* BA_NEXT_HOP */
+  { "next_hop", 4, BAF_TRANSITIVE, EAF_TYPE_IP_ADDRESS, 1,                     /* BA_NEXT_HOP */
     bgp_check_next_hop, NULL },
-  { "med", 4, BAF_OPTIONAL, EAF_TYPE_INT, 0,                   /* BA_MULTI_EXIT_DISC */
+  { "med", 4, BAF_OPTIONAL, EAF_TYPE_INT, 0,                                   /* BA_MULTI_EXIT_DISC */
     NULL, NULL },
-  { "local_pref", 4, BAF_OPTIONAL, EAF_TYPE_INT, 0,            /* BA_LOCAL_PREF */
+  { "local_pref", 4, BAF_OPTIONAL, EAF_TYPE_INT, 0,                            /* BA_LOCAL_PREF */
     NULL, NULL },
-  { "atomic_aggr", 0, BAF_TRANSITIVE, EAF_TYPE_OPAQUE, 1,              /* BA_ATOMIC_AGGR */
+  { "atomic_aggr", 0, BAF_TRANSITIVE, EAF_TYPE_OPAQUE, 1,                      /* BA_ATOMIC_AGGR */
     NULL, NULL },
   { "aggregator", 6, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_OPAQUE, 1,                /* BA_AGGREGATOR */
     NULL, NULL },
-  { "community", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_INT_SET, 1,  /* BA_COMMUNITY */
+  { "community", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_INT_SET, 1,       /* BA_COMMUNITY */
     NULL, NULL },
-#if 0
-  { 0, 0 },                                                                    /* BA_ORIGINATOR_ID */
-  { 0, 0 },                                                                    /* BA_CLUSTER_LIST */
-#endif
+  { NULL, },                                                                   /* BA_ORIGINATOR_ID */
+  { NULL, },                                                                   /* BA_CLUSTER_LIST */
+  { NULL, },                                                                   /* BA_DPA */
+  { NULL, },                                                                   /* BA_ADVERTISER */
+  { NULL, },                                                                   /* BA_RCID_PATH */
+  { "mp_reach_nlri", -1, BAF_OPTIONAL, EAF_TYPE_OPAQUE, 1,                     /* BA_MP_REACH_NLRI */
+    bgp_check_reach_nlri, NULL },
+  { "mp_unreach_nlri", -1, BAF_OPTIONAL, EAF_TYPE_OPAQUE, 1,                   /* BA_MP_UNREACH_NLRI */
+    bgp_check_unreach_nlri, NULL },
 };
 
 #define ATTR_KNOWN(code) ((code) < ARRAY_SIZE(bgp_attr_table) && bgp_attr_table[code].name)
@@ -708,8 +745,6 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct lin
   eattr *e;
   ea_list *ea;
   struct adata *ad;
-  neighbor *neigh;
-  ip_addr nexthop;
 
   a->proto = &bgp->p;
   a->source = RTS_BGP;
@@ -820,6 +855,11 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct lin
        }
     }
 
+#ifdef IPV6
+  if (seen[BA_MP_REACH_NLRI / 8] & (1 << (BA_MP_REACH_NLRI % 8)))
+    mandatory = 1;
+#endif
+
   /* Check if all mandatory attributes are present */
   if (mandatory)
     {
@@ -855,19 +895,6 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct lin
       ea->attrs[0].type = EAF_TYPE_INT;
       ea->attrs[0].u.data = 0;
     }
-
-  /* Fill in the remaining rta fields */
-  e = ea_find(a->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP));
-  ASSERT(e);
-  nexthop = *(ip_addr *) e->u.ptr->data;
-  if (ipa_equal(nexthop, bgp->local_addr))
-    {
-      DBG("BGP: Loop!\n");
-      return NULL;
-    }
-  neigh = neigh_find(&bgp->p, &nexthop, 0) ? : bgp->neigh;
-  a->gw = neigh->addr;
-  a->iface = neigh->iface;
   return a;
 
 malformed:
index a9f3413cb3a082f99b627344ba0762efb91075cb..37f29792081685e3ee4fadbc8b522871ecdb2f71 100644 (file)
@@ -72,6 +72,10 @@ struct bgp_proto {
   struct bgp_bucket *withdraw_bucket;  /* Withdrawn routes */
   unsigned startup_delay;              /* Time to delay protocol startup by due to errors */
   bird_clock_t last_connect;           /* Time of last connect attempt */
+#ifdef IPV6
+  byte *mp_reach_start, *mp_unreach_start; /* Multiprotocol BGP attribute notes */
+  unsigned mp_reach_len, mp_unreach_len;
+#endif
 };
 
 struct bgp_prefix {
@@ -181,4 +185,8 @@ void bgp_log_error(struct bgp_proto *p, char *msg, unsigned code, unsigned subco
 #define ORIGIN_EGP             1
 #define ORIGIN_INCOMPLETE      2
 
+/* Address families */
+
+#define BGP_AF_IPV6            2
+
 #endif
index 52e93510577bad836e4fe4d8754d5ece90a76b5d..45397fbf5366811970d84dfc77a368acb8d61f64 100644 (file)
@@ -68,6 +68,8 @@ bgp_encode_prefixes(struct bgp_proto *p, byte *w, struct bgp_bucket *buck, unsig
   return w - start;
 }
 
+#ifndef IPV6           /* IPv4 version */
+
 static byte *
 bgp_create_update(struct bgp_conn *conn, byte *buf)
 {
@@ -117,6 +119,16 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
   return (wd_size || r_size) ? w : NULL;
 }
 
+#else          /* IPv6 version */
+
+static byte *
+bgp_create_update(struct bgp_conn *conn, byte *buf)
+{
+  return NULL;
+}
+
+#endif
+
 static void
 bgp_create_header(byte *buf, unsigned int len, unsigned int type)
 {
@@ -321,9 +333,9 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, int len)
   int b = *pp++;                               \
   int q;                                       \
   ll--;                                                \
-  if (b > BITS_PER_IP_ADDRESS) { bgp_error(conn, 3, 10, NULL, 0); return; } \
+  if (b > BITS_PER_IP_ADDRESS) { err=10; goto bad; } \
   q = (b+7) / 8;                               \
-  if (ll < q) goto malformed;                  \
+  if (ll < q) { err=1; goto bad; }             \
   memcpy(&prefix, pp, q);                      \
   pp += q;                                     \
   ll -= q;                                     \
@@ -332,42 +344,40 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, int len)
   pxlen = b;                                   \
 } while (0)
 
+static inline int
+bgp_get_nexthop(struct bgp_proto *bgp, rta *a)
+{
+  neighbor *neigh;
+  ip_addr nexthop;
+  struct eattr *nh = ea_find(a->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP));
+  ASSERT(nh);
+  nexthop = *(ip_addr *) nh->u.ptr->data;
+  if (ipa_equal(nexthop, bgp->local_addr))
+    {
+      DBG("BGP: Loop!\n");
+      return 0;
+    }
+  neigh = neigh_find(&bgp->p, &nexthop, 0) ? : bgp->neigh;
+  a->gw = neigh->addr;
+  a->iface = neigh->iface;
+  return 1;
+}
+
+#ifndef IPV6           /* IPv4 version */
+
 static void
-bgp_rx_update(struct bgp_conn *conn, byte *pkt, int len)
+bgp_do_rx_update(struct bgp_conn *conn,
+                byte *withdrawn, int withdrawn_len,
+                byte *nlri, int nlri_len,
+                byte *attrs, int attr_len)
 {
   struct bgp_proto *p = conn->bgp;
-  byte *withdrawn, *attrs, *nlri;
+  rta *a0;
+  rta *a = NULL;
   ip_addr prefix;
-  int withdrawn_len, attr_len, nlri_len, pxlen;
   net *n;
   rte e;
-  rta *a0;
-  rta *a = NULL;
-
-  BGP_TRACE(D_PACKETS, "Got UPDATE");
-  if (conn->state != BS_ESTABLISHED)
-    { bgp_error(conn, 5, 0, NULL, 0); return; }
-  bgp_start_timer(conn->hold_timer, conn->hold_time);
-
-  /* Find parts of the packet and check sizes */
-  if (len < 23)
-    {
-      bgp_error(conn, 1, 2, pkt+16, 2);
-      return;
-    }
-  withdrawn = pkt + 21;
-  withdrawn_len = get_u16(pkt + 19);
-  if (withdrawn_len + 23 > len)
-    goto malformed;
-  attrs = withdrawn + withdrawn_len + 2;
-  attr_len = get_u16(attrs - 2);
-  if (withdrawn_len + attr_len + 23 > len)
-    goto malformed;
-  nlri = attrs + attr_len;
-  nlri_len = len - withdrawn_len - attr_len - 23;
-  if (!attr_len && nlri_len)
-    goto malformed;
-  DBG("Sizes: withdrawn=%d, attrs=%d, NLRI=%d\n", withdrawn_len, attr_len, nlri_len);
+  int err = 0, pxlen;
 
   /* Withdraw routes */
   while (withdrawn_len)
@@ -382,7 +392,7 @@ bgp_rx_update(struct bgp_conn *conn, byte *pkt, int len)
     return;
 
   a0 = bgp_decode_attrs(conn, attrs, attr_len, bgp_linpool, nlri_len);
-  if (a0 && nlri_len)
+  if (a0 && nlri_len && bgp_get_nexthop(p, a0))
     {
       a = rta_lookup(a0);
       while (nlri_len)
@@ -396,14 +406,166 @@ bgp_rx_update(struct bgp_conn *conn, byte *pkt, int len)
          e->pflags = 0;
          rte_update(p->p.table, n, &p->p, e);
        }
-      rta_free(a);
     }
-  lp_flush(bgp_linpool);
+bad:
+  if (a)
+    rta_free(a);
+  if (err)
+    bgp_error(conn, 3, err, NULL, 0);
   return;
+}
 
-malformed:
+#else                  /* IPv6 version */
+
+#define DO_NLRI(name)                                  \
+  start = x = p->name##_start;                         \
+  len = len0 = p->name##_len;                          \
+  if (len)                                             \
+    {                                                  \
+      if (len < 3) goto bad;                           \
+      af = get_u16(x);                                 \
+      sub = x[2];                                      \
+      x += 3;                                          \
+      len -= 3;                                                \
+      DBG("\tNLRI AF=%d sub=%d len=%d\n", af, sub, len);\
+    }                                                  \
+  else                                                 \
+    af = 0;                                            \
+  if (af == BGP_AF_IPV6)
+
+static void
+bgp_do_rx_update(struct bgp_conn *conn,
+                byte *withdrawn, int withdrawn_len,
+                byte *nlri, int nlri_len,
+                byte *attrs, int attr_len)
+{
+  struct bgp_proto *p = conn->bgp;
+  byte *start, *x;
+  int len, len0;
+  unsigned af, sub;
+  rta *a0;
+  rta *a = NULL;
+  ip_addr prefix;
+  net *n;
+  rte e;
+  int err = 0, pxlen;
+
+  p->mp_reach_len = 0;
+  p->mp_unreach_len = 0;
+  a0 = bgp_decode_attrs(conn, attrs, attr_len, bgp_linpool, 0);
+  if (!a0)
+    return;
+
+  DO_NLRI(mp_unreach)
+    {
+      while (len)
+       {
+         DECODE_PREFIX(x, len);
+         DBG("Withdraw %I/%d\n", prefix, pxlen);
+         if (n = net_find(p->p.table, prefix, pxlen))
+           rte_update(p->p.table, n, &p->p, NULL);
+       }
+    }
+
+  DO_NLRI(mp_reach)
+    {
+      ea_list *e = lp_alloc(bgp_linpool, sizeof(ea_list) + sizeof(eattr));
+      struct adata *ad = lp_alloc(bgp_linpool, sizeof(struct adata) + 16);
+      int i;
+
+      /* 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);
+      len -= *x + 1;
+      x += *x + 1;
+
+      /* Ignore SNPA info */
+      i = *x++;
+      while (i--)
+       {
+         if (len < 1 || len < 1 + *x)
+           goto bad;
+         len -= *x + 1;
+         x += *x + 1;
+       }
+
+      if (bgp_get_nexthop(p, a0))
+       {
+         a = rta_lookup(a0);
+         while (len)
+           {
+             rte *e;
+             DECODE_PREFIX(x, len);
+             DBG("Add %I/%d\n", prefix, pxlen);
+             e = rte_get_temp(rta_clone(a));
+             n = net_get(p->p.table, prefix, pxlen);
+             e->net = n;
+             e->pflags = 0;
+             rte_update(p->p.table, n, &p->p, e);
+           }
+         rta_free(a);
+       }
+    }
+
+  return;
+
+bad:
+  bgp_error(conn, 3, 9, start, len0);
   if (a)
     rta_free(a);
+  return;
+}
+
+#endif
+
+static void
+bgp_rx_update(struct bgp_conn *conn, byte *pkt, int len)
+{
+  struct bgp_proto *p = conn->bgp;
+  byte *withdrawn, *attrs, *nlri;
+  int withdrawn_len, attr_len, nlri_len;
+
+  BGP_TRACE(D_PACKETS, "Got UPDATE");
+  if (conn->state != BS_ESTABLISHED)
+    { bgp_error(conn, 5, 0, NULL, 0); return; }
+  bgp_start_timer(conn->hold_timer, conn->hold_time);
+
+  /* Find parts of the packet and check sizes */
+  if (len < 23)
+    {
+      bgp_error(conn, 1, 2, pkt+16, 2);
+      return;
+    }
+  withdrawn = pkt + 21;
+  withdrawn_len = get_u16(pkt + 19);
+  if (withdrawn_len + 23 > len)
+    goto malformed;
+  attrs = withdrawn + withdrawn_len + 2;
+  attr_len = get_u16(attrs - 2);
+  if (withdrawn_len + attr_len + 23 > len)
+    goto malformed;
+  nlri = attrs + attr_len;
+  nlri_len = len - withdrawn_len - attr_len - 23;
+  if (!attr_len && nlri_len)
+    goto malformed;
+  DBG("Sizes: withdrawn=%d, attrs=%d, NLRI=%d\n", withdrawn_len, attr_len, nlri_len);
+
+  lp_flush(bgp_linpool);
+
+  bgp_do_rx_update(conn, withdrawn, withdrawn_len, nlri, nlri_len, attrs, attr_len);
+  return;
+
+malformed:
   bgp_error(conn, 3, 1, NULL, 0);
 }