]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Use neighbor cache to track direct route to the peer or multihop destination.
authorMartin Mares <mj@ucw.cz>
Mon, 10 Apr 2000 11:21:40 +0000 (11:21 +0000)
committerMartin Mares <mj@ucw.cz>
Mon, 10 Apr 2000 11:21:40 +0000 (11:21 +0000)
Calculate next_hop properly based on the local address we get from the
neighbor entry.

proto/bgp/attrs.c
proto/bgp/bgp.c
proto/bgp/bgp.h
proto/bgp/config.Y

index 0fdc3b6c595ff994c3efe58c7c5dbaa89f55b54c..841fe10321c8a95afecc0653303f3c70c04dd3fe 100644 (file)
@@ -23,16 +23,20 @@ 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);
+  /* FIXME: Normalize attributes */
+  /* FIXME: Check next hop */
+  /* FIXME: Someone might have undefined the mandatory attributes */
 }
 
-static ea_list *
-bgp_create_attrs(struct bgp_proto *p, rte *e, ea_list *old, struct linpool *pool)
+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) + 3*sizeof(eattr));
   eattr *a = ea->attrs;
   rta *rta = e->attrs;
 
-  ea->next = old;
+  ea->next = *attrs;
+  *attrs = ea;
   ea->flags = EALF_SORTED;
   ea->count = 3;
 
@@ -68,17 +72,14 @@ bgp_create_attrs(struct bgp_proto *p, rte *e, ea_list *old, struct linpool *pool
   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;
+  if (p->cf->next_hop_self ||
+      !p->is_internal ||
+      rta->dest != RTD_ROUTER)
+    *(ip_addr *)a->u.ptr->data = p->local_addr;
   else
-    {
-      /* FIXME: Next hop == self ... how to do that? */
-      *(ip_addr *)a->u.ptr->data = IPA_NONE;
-    }
+    *(ip_addr *)a->u.ptr->data = e->attrs->gw;
 
-  return ea;
+  return 0;                            /* Leave decision to the filters */
 }
 
 ea_list *
@@ -115,15 +116,37 @@ bgp_path_prepend(struct linpool *pool, eattr *a, ea_list *old, int as)
   return e;
 }
 
-static ea_list *
-bgp_update_attrs(struct bgp_proto *p, rte *e, ea_list *old, struct linpool *pool)
+static int
+bgp_update_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *pool)
 {
+  eattr *a;
+
   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);
+    *attrs = bgp_path_prepend(pool, ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH)), *attrs, p->local_as);
 
-  /* FIXME: Set NEXT_HOP to self */
+  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)))
+    {
+      /* Leave the original next hop attribute, will check later where does it point */
+    }
+  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;
+    }
 
-  return old;
+  return 0;                            /* Leave decision to the filters */
 }
 
 int
@@ -133,19 +156,16 @@ bgp_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *
   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 */
+  if (p == new_bgp)                    /* Poison reverse updates */
     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);
+      return 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 */
+    return bgp_create_attrs(p, e, attrs, pool);
 }
 
 int
@@ -284,7 +304,7 @@ static struct attr_desc bgp_attr_table[] = {
   { "aggregator", 6, BAF_OPTIONAL, EAF_TYPE_OPAQUE,            /* BA_AGGREGATOR */
     NULL, NULL },
 #if 0
-  /* FIXME: Handle community lists */
+  /* 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 */
@@ -443,19 +463,12 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct lin
   e = ea_find(a->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP));
   ASSERT(e);
   nexthop = *(ip_addr *) e->u.ptr->data;
-  neigh = neigh_find(&bgp->p, &nexthop, 0);
-  if (!neigh)
-    {
-      if (bgp->cf->multihop)
-       neigh = neigh_find(&bgp->p, &bgp->cf->multihop_via, 0);
-      else
-       neigh = neigh_find(&bgp->p, &bgp->cf->remote_ip, 0);
-    }
-  if (!neigh || !neigh->iface)
+  if (ipa_equal(nexthop, bgp->local_addr))
     {
-      DBG("BGP: No route to peer!\n"); /* FIXME */
+      DBG("BGP: Loop!\n");             /* FIXME */
       return NULL;
     }
+  neigh = neigh_find(&bgp->p, &nexthop, 0) ? : bgp->neigh;
   a->gw = neigh->addr;
   a->iface = neigh->iface;
   return rta_lookup(a);
index 11729db4f41e331dbd204a25026e1f476569165b..d9eddbd5da9f86dbd60f9d90f0e603a80de08b9c 100644 (file)
@@ -26,25 +26,6 @@ static list bgp_list;                        /* List of active BGP instances */
 static char *bgp_state_names[] = { "Idle", "Connect", "Active", "OpenSent", "OpenConfirm", "Established" };
 
 static void bgp_connect(struct bgp_proto *p);
-static void bgp_setup_sk(struct bgp_proto *p, struct bgp_conn *conn, sock *s);
-
-static struct proto *
-bgp_init(struct proto_config *C)
-{
-  struct bgp_config *c = (struct bgp_config *) C;
-  struct proto *P = proto_new(C, sizeof(struct bgp_proto));
-  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;
-  p->is_internal = (c->local_as == c->remote_as);
-  p->local_id = C->global->router_id;
-  return P;
-}
 
 void
 bgp_close(struct bgp_proto *p)
@@ -99,6 +80,27 @@ bgp_close_conn(struct bgp_conn *conn)
     }
 }
 
+static int
+bgp_graceful_close_conn(struct bgp_conn *c)
+{
+  switch (c->state)
+    {
+    case BS_IDLE:
+      return 0;
+    case BS_CONNECT:
+    case BS_ACTIVE:
+      bgp_close_conn(c);
+      return 1;
+    case BS_OPENSENT:
+    case BS_OPENCONFIRM:
+    case BS_ESTABLISHED:
+      bgp_error(c, 6, 0, 0, 0);
+      return 1;
+    default:
+      bug("bgp_graceful_close_conn: Unknown state %d", c->state);
+    }
+}
+
 static void
 bgp_send_open(struct bgp_conn *conn)
 {
@@ -152,33 +154,6 @@ bgp_sock_err(sock *sk, int err)
   bgp_close_conn(conn);
 }
 
-static int
-bgp_incoming_connection(sock *sk, int dummy)
-{
-  node *n;
-
-  DBG("BGP: Incoming connection from %I port %d\n", sk->daddr, sk->dport);
-  WALK_LIST(n, bgp_list)
-    {
-      struct bgp_proto *p = SKIP_BACK(struct bgp_proto, bgp_node, n);
-      if (ipa_equal(p->cf->remote_ip, sk->daddr) && sk->dport == BGP_PORT)
-       {
-         DBG("BGP: Authorized\n");
-         if (p->incoming_conn.sk)
-           {
-             DBG("BGP: But one incoming connection already exists, how is that possible?\n");
-             break;
-           }
-         bgp_setup_sk(p, &p->incoming_conn, sk);
-         bgp_send_open(&p->incoming_conn);
-         return 0;
-       }
-    }
-  DBG("BGP: Unauthorized\n");
-  rfree(sk);
-  return 0;
-}
-
 static void
 bgp_hold_timeout(timer *t)
 {
@@ -253,12 +228,38 @@ bgp_connect(struct bgp_proto *p)  /* Enter Connect state and start establishing c
   bgp_start_timer(conn->connect_retry_timer, p->cf->connect_retry_time);
 }
 
-static void
-bgp_start_locked(struct object_lock *lock)
+static int
+bgp_incoming_connection(sock *sk, int dummy)
 {
-  struct bgp_proto *p = lock->data;
+  node *n;
 
-  DBG("BGP: Got lock\n");
+  DBG("BGP: Incoming connection from %I port %d\n", sk->daddr, sk->dport);
+  WALK_LIST(n, bgp_list)
+    {
+      struct bgp_proto *p = SKIP_BACK(struct bgp_proto, bgp_node, n);
+      if (ipa_equal(p->cf->remote_ip, sk->daddr) && sk->dport == BGP_PORT)
+       {
+         DBG("BGP: Authorized\n");
+         if (p->incoming_conn.sk)
+           {
+             DBG("BGP: But one incoming connection already exists, how is that possible?\n");
+             break;
+           }
+         bgp_setup_sk(p, &p->incoming_conn, sk);
+         bgp_send_open(&p->incoming_conn);
+         return 0;
+       }
+    }
+  DBG("BGP: Unauthorized\n");
+  rfree(sk);
+  return 0;
+}
+
+static void
+bgp_start_neighbor(struct bgp_proto *p)
+{
+  p->local_addr = p->neigh->iface->addr->ip;
+  DBG("BGP: local=%I remote=%I\n", p->local_addr, p->next_hop);
   if (!bgp_counter++)
     init_list(&bgp_list);
   if (!bgp_listen_sk)
@@ -282,7 +283,49 @@ bgp_start_locked(struct object_lock *lock)
   if (!bgp_linpool)
     bgp_linpool = lp_new(&root_pool, 4080);
   add_tail(&bgp_list, &p->bgp_node);
-  bgp_connect(p);                      /* FIXME: Use neighbor cache for fast up/down transitions? */
+  bgp_connect(p);
+}
+
+static void
+bgp_neigh_notify(neighbor *n)
+{
+  struct bgp_proto *p = (struct bgp_proto *) n->proto;
+
+  if (n->iface)
+    {
+      DBG("BGP: Neighbor is reachable\n");
+      bgp_start_neighbor(p);
+    }
+  else
+    {
+      DBG("BGP: Neighbor is unreachable\n");
+      /* Send cease packets, but don't wait for them to be delivered */
+      bgp_graceful_close_conn(&p->outgoing_conn);
+      bgp_graceful_close_conn(&p->incoming_conn);
+      proto_notify_state(&p->p, PS_DOWN);
+      /* FIXME: Remember to delay protocol startup here! */
+    }
+}
+
+static void
+bgp_start_locked(struct object_lock *lock)
+{
+  struct bgp_proto *p = lock->data;
+  struct bgp_config *cf = p->cf;
+
+  DBG("BGP: Got lock\n");
+  p->next_hop = cf->multihop ? cf->multihop_via : cf->remote_ip;
+  p->neigh = neigh_find(&p->p, &p->next_hop, NEF_STICKY);
+  if (!p->neigh)
+    {
+      log(L_ERR "%s: Invalid next hop %I", p->p.name, p->next_hop);
+      p->p.disabled = 1;
+      proto_notify_state(&p->p, PS_DOWN);
+    }
+  else if (p->neigh->iface)
+    bgp_start_neighbor(p);
+  else
+    DBG("BGP: Waiting for neighbor\n");
 }
 
 static int
@@ -312,27 +355,6 @@ bgp_start(struct proto *P)
   return PS_START;
 }
 
-static int
-bgp_graceful_close(struct bgp_conn *c)
-{
-  switch (c->state)
-    {
-    case BS_IDLE:
-      return 0;
-    case BS_CONNECT:
-    case BS_ACTIVE:
-      bgp_close_conn(c);
-      return 1;
-    case BS_OPENSENT:
-    case BS_OPENCONFIRM:
-    case BS_ESTABLISHED:
-      bgp_error(c, 6, 0, 0, 0);
-      return 1;
-    default:
-      bug("bgp_graceful_close: Unknown state %d", c->state);
-    }
-}
-
 static int
 bgp_shutdown(struct proto *P)
 {
@@ -356,7 +378,7 @@ bgp_shutdown(struct proto *P)
       else if (p->incoming_conn.state != BS_IDLE)
        p->incoming_conn.primary = 1;
     }
-  if (bgp_graceful_close(&p->outgoing_conn) || bgp_graceful_close(&p->incoming_conn))
+  if (bgp_graceful_close_conn(&p->outgoing_conn) || bgp_graceful_close_conn(&p->incoming_conn))
     return p->p.proto_state;
   else
     {
@@ -366,6 +388,25 @@ bgp_shutdown(struct proto *P)
     }
 }
 
+static struct proto *
+bgp_init(struct proto_config *C)
+{
+  struct bgp_config *c = (struct bgp_config *) C;
+  struct proto *P = proto_new(C, sizeof(struct bgp_proto));
+  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->neigh_notify = bgp_neigh_notify;
+  p->cf = c;
+  p->local_as = c->local_as;
+  p->remote_as = c->remote_as;
+  p->is_internal = (c->local_as == c->remote_as);
+  p->local_id = C->global->router_id;
+  return P;
+}
+
 void
 bgp_error(struct bgp_conn *c, unsigned code, unsigned subcode, unsigned data, unsigned len)
 {
index 45f7e0b132a917582376068d6abf7f0085d28edf..6ae594a60c69af6d637c9a8511781d66fb2bdb02 100644 (file)
@@ -18,6 +18,7 @@ struct bgp_config {
   ip_addr remote_ip;
   int multihop;                                /* Number of hops if multihop */
   ip_addr multihop_via;                        /* Multihop: address to route to */
+  int next_hop_self;                   /* Always set next hop to local IP address */
   unsigned connect_retry_time;
   unsigned hold_time, initial_hold_time;
   unsigned keepalive_time;
@@ -49,6 +50,9 @@ struct bgp_proto {
   struct bgp_conn outgoing_conn;       /* Outgoing connection we're working with */
   struct bgp_conn incoming_conn;       /* Incoming connection we have neither accepted nor rejected yet */
   struct object_lock *lock;            /* Lock for neighbor connection */
+  ip_addr next_hop;                    /* Either the peer or multihop_via */
+  struct neighbor *neigh;              /* Neighbor entry corresponding to next_hop */
+  ip_addr local_addr;                  /* Address of the local end of the link to next_hop */
 };
 
 #define BGP_PORT               179
index f83191ad18bd6a7a9c2ba2a2e21270c38c9c8c15..f18f2bdc1786e117801c9b732774a12179c162f8 100644 (file)
@@ -15,7 +15,7 @@ CF_HDR
 CF_DECLS
 
 CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE,
-       MULTIHOP, STARTUP, VIA)
+       MULTIHOP, STARTUP, VIA, NEXT, HOP, SELF)
 
 CF_GRAMMAR
 
@@ -47,6 +47,7 @@ bgp_proto:
  | bgp_proto CONNECT RETRY TIME NUM ';' { BGP_CFG->connect_retry_time = $5; }
  | bgp_proto KEEPALIVE TIME NUM ';' { BGP_CFG->connect_retry_time = $4; }
  | bgp_proto MULTIHOP NUM VIA IPA ';' { BGP_CFG->multihop = $3; BGP_CFG->multihop_via = $5; }
+ | bgp_proto NEXT HOP SELF ';' { BGP_CFG->next_hop_self = 1; }
  ;
 
 CF_CODE