]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Started work on BGP. Wrote main part of the connection handling code.
authorMartin Mares <mj@ucw.cz>
Mon, 20 Mar 2000 21:50:17 +0000 (21:50 +0000)
committerMartin Mares <mj@ucw.cz>
Mon, 20 Mar 2000 21:50:17 +0000 (21:50 +0000)
TODO
proto/bgp/Makefile
proto/bgp/attrs.c [new file with mode: 0644]
proto/bgp/bgp.c
proto/bgp/bgp.h
proto/bgp/config.Y
proto/bgp/packets.c [new file with mode: 0644]

diff --git a/TODO b/TODO
index 5bca22e037a5bbde7d37286376521830b93ba42f..55f943056536a8f0617b4689eba5ecaa052da290 100644 (file)
--- a/TODO
+++ b/TODO
@@ -9,6 +9,8 @@ Core
 
 - tagging of external routes?
 
+- when an identical route is received, don't trigger updates
+
 Commands
 ~~~~~~~~
 - showing of routing table as seen by given protocol
index 8358bc8a979a679579c409c0b5701912920a9ff8..0f0ba278f7b9b5e948053a18549bdbcb5436df63 100644 (file)
@@ -1,4 +1,4 @@
-source=bgp.c
+source=bgp.c attrs.c
 root-rel=../../
 dir-name=proto/bgp
 
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c
new file mode 100644 (file)
index 0000000..bf747cb
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ *     BIRD -- BGP Attributes
+ *
+ *     (c) 2000 Martin Mares <mj@ucw.cz>
+ *
+ *     Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "nest/bird.h"
+#include "nest/iface.h"
+#include "nest/protocol.h"
+#include "nest/route.h"
+#include "conf/conf.h"
+
+#include "bgp.h"
index 26e39061c543ea9a222a0cf1a236122320e52c51..40915a40871a6dc97c03c0d38f13fc29339cc8c8 100644 (file)
 #include "nest/iface.h"
 #include "nest/protocol.h"
 #include "nest/route.h"
+#include "nest/locks.h"
 #include "conf/conf.h"
+#include "lib/socket.h"
 
 #include "bgp.h"
 
+static sock *bgp_listen_sk;            /* Global listening socket */
+static int bgp_counter;                        /* Number of protocol instances using the listening socket */
+static list bgp_list;                  /* List of active BGP instances */
+
+static void bgp_close_conn(struct bgp_conn *conn);
+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)
 {
@@ -29,18 +39,266 @@ bgp_init(struct proto_config *C)
   struct bgp_proto *p = (struct bgp_proto *) P;
 
   P->rt_notify = bgp_rt_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->conn.state = BS_IDLE;
+  p->incoming_conn.state = BS_IDLE;
+  p->local_id = C->global->router_id;
   return P;
 }
 
+static void
+bgp_close(struct bgp_proto *p)
+{
+  rem_node(&p->bgp_node);
+  ASSERT(bgp_counter);
+  bgp_counter--;
+  if (!bgp_counter)
+    {
+      rfree(bgp_listen_sk);
+      bgp_listen_sk = NULL;
+    }
+  /* FIXME: Automatic restart after errors? */
+}
+
+static void
+bgp_reset(struct bgp_proto *p)
+{
+  bgp_close(p);
+  proto_notify_state(&p->p, PS_DOWN);
+}
+
+static void
+bgp_start_timer(timer *t, int value)
+{
+  /* FIXME: Randomize properly */
+  /* FIXME: Check if anybody uses tm_start directly */
+  tm_start(t, value);
+}
+
+static int
+bgp_rx(sock *sk, int size)
+{
+  DBG("BGP: Got %d bytes\n", size);
+
+  return 1;                            /* Start from the beginning */
+}
+
+static void
+bgp_send_open(struct bgp_conn *conn)
+{
+  DBG("BGP: Sending open\n");
+  conn->sk->rx_hook = bgp_rx;
+  tm_stop(conn->connect_retry_timer);
+  /* FIXME */
+  conn->state = BS_OPENSENT;
+}
+
+static int
+bgp_connected(sock *sk, int dummy)
+{
+  struct bgp_conn *conn = sk->data;
+
+  DBG("BGP: Connected\n");
+  bgp_send_open(conn);
+  return 0;
+}
+
+static void
+bgp_connect_timeout(timer *t)
+{
+  struct bgp_proto *p = t->data;
+  struct bgp_conn *conn = &p->conn;
+
+  DBG("BGP: Connect timeout, retrying\n");
+  bgp_close_conn(conn);
+  bgp_connect(p);
+}
+
+static void
+bgp_err(sock *sk, int err)
+{
+  struct bgp_conn *conn = sk->data;
+
+  DBG("BGP: Socket error %d in state %d\n", err, conn->state);
+  sk->type = SK_DELETED;               /* FIXME: Need to do this always! */
+  switch (conn->state)
+    {
+    case BS_CONNECT:
+    case BS_OPENSENT:
+      conn->state = BS_ACTIVE;
+      bgp_start_timer(conn->connect_retry_timer, conn->bgp->cf->connect_retry_time);
+      break;
+    case BS_OPENCONFIRM:
+    case BS_ESTABLISHED:
+      /* FIXME: Should close the connection and go to Idle state */
+    default:
+      bug("bgp_err called in invalid state %d", conn->state);
+    }
+}
+
+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_setup_sk(struct bgp_proto *p, struct bgp_conn *conn, sock *s)
+{
+  timer *t;
+
+  s->data = conn;
+  s->ttl = p->cf->multihop ? : 1;
+  s->rbsize = BGP_RX_BUFFER_SIZE;
+#if 0
+  s->tx_hook = bgp_tx;
+#endif
+  s->err_hook = bgp_err;
+  s->tos = IP_PREC_INTERNET_CONTROL;
+
+  conn->bgp = p;
+  conn->sk = s;
+
+  t = conn->connect_retry_timer = tm_new(p->p.pool);
+  t->hook = bgp_connect_timeout;
+  t->data = p;
+#if 0
+  t = p->hold_timer = tm_new(p->p.pool);
+  t->hook = bgp_hold_timeout;
+  t->data = p;
+  t = p->keepalive_timer = tm_new(p->p.pool);
+  t->hook = bgp_keepalive_timeout;
+  t->data = p;
+#endif
+}
+
+static void
+bgp_close_conn(struct bgp_conn *conn)
+{
+  rfree(conn->connect_retry_timer);
+  conn->connect_retry_timer = NULL;
+  rfree(conn->keepalive_timer);
+  conn->keepalive_timer = NULL;
+  rfree(conn->hold_timer);
+  conn->hold_timer = NULL;
+  rfree(conn->sk);
+  conn->sk = NULL;
+  conn->state = BS_IDLE;
+}
+
+static void
+bgp_connect(struct bgp_proto *p)       /* Enter Connect state and start establishing connection */
+{
+  sock *s;
+  struct bgp_conn *conn = &p->conn;
+
+  DBG("BGP: Connecting\n");
+  s = sk_new(p->p.pool);
+  s->type = SK_TCP_ACTIVE;
+  s->saddr = _MI(0x3ea80001);          /* FIXME: Hack */
+  s->daddr = p->cf->remote_ip;
+#if 0
+  s->sport =                           /* FIXME */
+#endif
+  s->dport = BGP_PORT;
+  s->rx_hook = bgp_connected;
+  bgp_setup_sk(p, conn, s);
+  conn->state = BS_CONNECT;
+  if (sk_open(s))
+    {
+      bgp_err(s, 0);
+      return;
+    }
+  DBG("BGP: Waiting for connect success\n");
+  bgp_start_timer(conn->connect_retry_timer, p->cf->connect_retry_time);
+}
+
+static void
+bgp_start_locked(struct object_lock *lock)
+{
+  struct bgp_proto *p = lock->data;
+
+  DBG("BGP: Got lock\n");
+  if (!bgp_counter++)
+    init_list(&bgp_list);
+  if (!bgp_listen_sk)
+    {
+      sock *s = sk_new(&root_pool);
+      DBG("BGP: Creating incoming socket\n");
+      s->type = SK_TCP_PASSIVE;
+      s->sport = BGP_PORT;
+      s->tos = IP_PREC_INTERNET_CONTROL;
+      s->ttl = 1;
+      s->rbsize = BGP_RX_BUFFER_SIZE;
+      s->rx_hook = bgp_incoming_connection;
+      if (sk_open(s))
+       {
+         log(L_ERR "Unable to open incoming BGP socket");
+         rfree(s);
+       }
+      else
+       bgp_listen_sk = s;
+    }
+  add_tail(&bgp_list, &p->bgp_node);
+  bgp_connect(p);                      /* FIXME: Use neighbor cache for fast up/down transitions? */
+}
+
 static int
 bgp_start(struct proto *P)
 {
-  return PS_UP;
+  struct bgp_proto *p = (struct bgp_proto *) P;
+  struct object_lock *lock;
+
+  /*
+   *  Before attempting to create the connection, we need to lock the
+   *  port, so that are sure we're the only instance attempting to talk
+   *  with that neighbor.
+   */
+
+  DBG("BGP: Startup. Acquiring lock.\n");
+  lock = p->lock = olock_new(P->pool);
+  lock->addr = p->cf->remote_ip;
+  lock->type = OBJLOCK_TCP;
+  lock->port = BGP_PORT;
+  lock->iface = NULL;
+  lock->hook = bgp_start_locked;
+  lock->data = p;
+  olock_acquire(lock);
+  return PS_START;
 }
 
 static int
 bgp_shutdown(struct proto *P)
 {
+  struct bgp_proto *p = (struct bgp_proto *) P;
+
+  DBG("BGP: Explicit shutdown\n");
+
+  bgp_close(p);
   return PS_DOWN;
 }
 
index 2e352be49603678d7b7b8753a7bb05a06a01957f..8e2e8dfec646e94dae8ebf779e970bbdc956fa2d 100644 (file)
@@ -14,18 +14,82 @@ struct bgp_config {
   unsigned int local_as, remote_as;
   ip_addr remote_ip;
   int multihop;                                /* Number of hops if multihop */
+  int connect_retry_time;
+  int hold_time;
+  int keepalive_time;
+};
+
+struct bgp_conn {
+  struct bgp_proto *bgp;
+  struct birdsock *sk;
+  int state;                           /* State of connection state machine */
+  struct timer *connect_retry_timer;
+  struct timer *hold_timer;
+  struct timer *keepalive_timer;
 };
 
 struct bgp_proto {
   struct proto p;
+  struct bgp_config *cf;               /* Shortcut to BGP configuration */
+  node bgp_node;                       /* Node in global BGP protocol list */
+  int local_as, remote_as;
+  int is_internal;                     /* Internal BGP connection (local_as == remote_as) */
+  u32 local_id;                                /* BGP identifier of this router */
+  u32 remote_id;                       /* BGP identifier of the neighbor */
+  int hold_time;                       /* Hold time calculated from my and neighbor's requirements */
+  struct bgp_conn conn;                        /* Our primary connection */
+  struct bgp_conn incoming_conn;       /* Incoming connection we have neither accepted nor rejected yet */
+  struct object_lock *lock;            /* Lock for neighbor connection */
 };
 
-struct bgp_route {
-};
-
-struct bgp_attrs {
-};
+#define BGP_PORT 179
+#define BGP_RX_BUFFER_SIZE 4096
 
 void bgp_check(struct bgp_config *c);
 
+/* attrs.c */
+
+/* packets.c */
+
+/* Packet types */
+
+#define PKT_OPEN               0x01
+#define PKT_UPDATE             0x02
+#define PKT_NOTIFICATION       0x03
+#define PKT_KEEPALIVE          0x04
+
+/* Attributes */
+
+#define BAF_OPTIONAL           0x80
+#define BAF_TRANSITIVE         0x40
+#define BAF_PARTIAL            0x20
+#define BAF_EXT_LEN            0x10
+
+#define BA_ORIGIN              0x01    /* [RFC1771] */         /* WM */
+#define BA_AS_PATH             0x02                            /* WM */
+#define BA_NEXT_HOP            0x03                            /* WM */
+#define BA_MULTI_EXIT_DISC     0x04                            /* ON */
+#define BA_LOCAL_PREF          0x05                            /* WM */
+#define BA_ATOMIC_AGGR         0x06                            /* WD */
+#define BA_AGGREGATOR          0x07                            /* OT */
+#define BA_COMMUNITY           0x08    /* [RFC1997] */         /* OT */
+#define BA_ORIGINATOR_ID       0x09    /* [RFC1966] */         /* ON */
+#define BA_CLUSTER_LIST                0x0a                            /* ON */
+/* We don't support these: */
+#define BA_DPA                 0x0b    /* ??? */
+#define BA_ADVERTISER          0x0c    /* [RFC1863] */
+#define BA_RCID_PATH           0x0d
+#define BA_MP_REACH_NLRI       0x0e    /* [RFC2283] */
+#define BA_MP_UNREACH_NLRI     0x0f
+#define BA_EXTENDED_COMM       0x10    /* draft-ramachandra-bgp-ext-communities */
+
+/* BGP states */
+
+#define BS_IDLE                        0
+#define BS_CONNECT             1       /* Attempting to connect */
+#define BS_ACTIVE              2       /* Waiting for connection retry & listening */
+#define BS_OPENSENT            3
+#define BS_OPENCONFIRM         4
+#define BS_ESTABLISHED         5
+
 #endif
index f66f3588bb6055799326fc3a58b78b9792bf0b79..f50b060244ea025e7323b1eebe292fda43c12be8 100644 (file)
@@ -14,7 +14,8 @@ CF_HDR
 
 CF_DECLS
 
-CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS)
+CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE,
+       MULTIHOP)
 
 CF_GRAMMAR
 
@@ -23,6 +24,9 @@ CF_ADDTO(proto, bgp_proto '}' { bgp_check(BGP_CFG); } )
 bgp_proto_start: proto_start BGP {
      this_proto = proto_config_new(&proto_bgp, sizeof(struct bgp_config));
      this_proto->preference = DEF_PREF_BGP;
+     BGP_CFG->hold_time = 240;
+     BGP_CFG->connect_retry_time = 120;
+     BGP_CFG->keepalive_time = 30;
   }
  ;
 
@@ -38,6 +42,10 @@ bgp_proto:
      BGP_CFG->remote_ip = $3;
      BGP_CFG->remote_as = $5;
    }
+ | bgp_proto HOLD TIME NUM ';' { BGP_CFG->hold_time = $4; }
+ | 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 ';' { BGP_CFG->multihop = $3; }
  ;
 
 CF_CODE
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
new file mode 100644 (file)
index 0000000..a5f52b8
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ *     BIRD -- BGP Packet Processing
+ *
+ *     (c) 2000 Martin Mares <mj@ucw.cz>
+ *
+ *     Can be freely distributed and used under the terms of the GNU GPL.
+ */
+
+#include "nest/bird.h"
+#include "nest/iface.h"
+#include "nest/protocol.h"
+#include "nest/route.h"
+#include "conf/conf.h"
+
+#include "bgp.h"