summaryrefslogtreecommitdiffstats
path: root/proto/bgp/bgp.c
diff options
context:
space:
mode:
authorMartin Mares <mj@ucw.cz>2000-04-10 13:21:40 +0200
committerMartin Mares <mj@ucw.cz>2000-04-10 13:21:40 +0200
commit48e842cc98b1436da57c8682c6c8414ba379ed7c (patch)
tree59bfccdddf0837f0031aaf94fc4cb81e7a6f651c /proto/bgp/bgp.c
parent287111fed1c8e9eb135df1108ea747e02b30e9e9 (diff)
downloadbird-48e842cc98b1436da57c8682c6c8414ba379ed7c.tar
bird-48e842cc98b1436da57c8682c6c8414ba379ed7c.zip
Use neighbor cache to track direct route to the peer or multihop destination.
Calculate next_hop properly based on the local address we get from the neighbor entry.
Diffstat (limited to 'proto/bgp/bgp.c')
-rw-r--r--proto/bgp/bgp.c187
1 files changed, 114 insertions, 73 deletions
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index 11729db..d9eddbd 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -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
@@ -313,27 +356,6 @@ bgp_start(struct proto *P)
}
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)
{
struct bgp_proto *p = (struct bgp_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)
{