Started work on BGP. Wrote main part of the connection handling code.
This commit is contained in:
parent
1cf716f075
commit
c01e37416d
7 changed files with 370 additions and 8 deletions
2
TODO
2
TODO
|
@ -9,6 +9,8 @@ Core
|
||||||
|
|
||||||
- tagging of external routes?
|
- tagging of external routes?
|
||||||
|
|
||||||
|
- when an identical route is received, don't trigger updates
|
||||||
|
|
||||||
Commands
|
Commands
|
||||||
~~~~~~~~
|
~~~~~~~~
|
||||||
- showing of routing table as seen by given protocol
|
- showing of routing table as seen by given protocol
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
source=bgp.c
|
source=bgp.c attrs.c
|
||||||
root-rel=../../
|
root-rel=../../
|
||||||
dir-name=proto/bgp
|
dir-name=proto/bgp
|
||||||
|
|
||||||
|
|
15
proto/bgp/attrs.c
Normal file
15
proto/bgp/attrs.c
Normal file
|
@ -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"
|
260
proto/bgp/bgp.c
260
proto/bgp/bgp.c
|
@ -12,10 +12,20 @@
|
||||||
#include "nest/iface.h"
|
#include "nest/iface.h"
|
||||||
#include "nest/protocol.h"
|
#include "nest/protocol.h"
|
||||||
#include "nest/route.h"
|
#include "nest/route.h"
|
||||||
|
#include "nest/locks.h"
|
||||||
#include "conf/conf.h"
|
#include "conf/conf.h"
|
||||||
|
#include "lib/socket.h"
|
||||||
|
|
||||||
#include "bgp.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
|
static void
|
||||||
bgp_rt_notify(struct proto *P, net *n, rte *new, rte *old, ea_list *tmpa)
|
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;
|
struct bgp_proto *p = (struct bgp_proto *) P;
|
||||||
|
|
||||||
P->rt_notify = bgp_rt_notify;
|
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;
|
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
|
static int
|
||||||
bgp_start(struct proto *P)
|
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
|
static int
|
||||||
bgp_shutdown(struct proto *P)
|
bgp_shutdown(struct proto *P)
|
||||||
{
|
{
|
||||||
|
struct bgp_proto *p = (struct bgp_proto *) P;
|
||||||
|
|
||||||
|
DBG("BGP: Explicit shutdown\n");
|
||||||
|
|
||||||
|
bgp_close(p);
|
||||||
return PS_DOWN;
|
return PS_DOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,18 +14,82 @@ struct bgp_config {
|
||||||
unsigned int local_as, remote_as;
|
unsigned int local_as, remote_as;
|
||||||
ip_addr remote_ip;
|
ip_addr remote_ip;
|
||||||
int multihop; /* Number of hops if multihop */
|
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 bgp_proto {
|
||||||
struct proto p;
|
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 {
|
#define BGP_PORT 179
|
||||||
};
|
#define BGP_RX_BUFFER_SIZE 4096
|
||||||
|
|
||||||
struct bgp_attrs {
|
|
||||||
};
|
|
||||||
|
|
||||||
void bgp_check(struct bgp_config *c);
|
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
|
#endif
|
||||||
|
|
|
@ -14,7 +14,8 @@ CF_HDR
|
||||||
|
|
||||||
CF_DECLS
|
CF_DECLS
|
||||||
|
|
||||||
CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS)
|
CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE,
|
||||||
|
MULTIHOP)
|
||||||
|
|
||||||
CF_GRAMMAR
|
CF_GRAMMAR
|
||||||
|
|
||||||
|
@ -23,6 +24,9 @@ CF_ADDTO(proto, bgp_proto '}' { bgp_check(BGP_CFG); } )
|
||||||
bgp_proto_start: proto_start BGP {
|
bgp_proto_start: proto_start BGP {
|
||||||
this_proto = proto_config_new(&proto_bgp, sizeof(struct bgp_config));
|
this_proto = proto_config_new(&proto_bgp, sizeof(struct bgp_config));
|
||||||
this_proto->preference = DEF_PREF_BGP;
|
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_ip = $3;
|
||||||
BGP_CFG->remote_as = $5;
|
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
|
CF_CODE
|
||||||
|
|
15
proto/bgp/packets.c
Normal file
15
proto/bgp/packets.c
Normal file
|
@ -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"
|
Loading…
Reference in a new issue