More BGP progress...

For Pavel: You can use bgp_path_prepend() for prepending AS numbers to AS paths.
This commit is contained in:
Martin Mares 2000-04-09 22:05:02 +00:00
parent d3feceff10
commit ef2c708dfa
3 changed files with 239 additions and 18 deletions

View file

@ -19,8 +19,194 @@
#include "bgp.h"
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);
}
static ea_list *
bgp_create_attrs(struct bgp_proto *p, rte *e, ea_list *old, 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->flags = EALF_SORTED;
ea->count = 3;
a->id = EA_CODE(EAP_BGP, BA_ORIGIN);
a->flags = BAF_TRANSITIVE;
a->type = EAF_TYPE_INT;
if (rta->source == RTS_RIP_EXT || rta->source == RTS_OSPF_EXT)
a->u.data = 2; /* Incomplete */
else
a->u.data = 0; /* IGP */
a->id = EA_CODE(EAP_BGP, BA_AS_PATH);
a->flags = BAF_TRANSITIVE;
a->type = EAF_TYPE_AS_PATH;
if (p->is_internal)
{
a->u.ptr = lp_alloc(pool, sizeof(struct adata));
a->u.ptr->length = 0;
}
else
{
byte *z;
a->u.ptr = lp_alloc(pool, sizeof(struct adata) + 4);
a->u.ptr->length = 4;
z = a->u.ptr->data;
z[0] = 2; /* AS_SEQUENCE */
z[1] = 1; /* 1 AS */
put_u16(z+2, p->local_as);
}
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);
/* FIXME: These rules are bogus!!! */
if (rta->dest == RTD_ROUTER)
*(ip_addr *)a->u.ptr->data = e->attrs->gw;
else
{
/* FIXME: Next hop == self ... how to do that? */
*(ip_addr *)a->u.ptr->data = IPA_NONE;
}
return ea;
}
ea_list *
bgp_path_prepend(struct linpool *pool, eattr *a, ea_list *old, int as)
{
struct ea_list *e = lp_alloc(pool, sizeof(ea_list) + sizeof(eattr));
struct adata *olda = a->u.ptr;
struct adata *newa;
e->next = old;
e->flags = EALF_SORTED;
e->count = 1;
e->attrs[0].id = EA_CODE(EAP_BGP, BA_AS_PATH);
e->attrs[0].flags = BAF_TRANSITIVE;
e->attrs[0].type = EAF_TYPE_AS_PATH;
if (olda->length && olda->data[0] == 2 && olda->data[1] < 255) /* Starting with sequence => just prepend the AS number */
{
newa = lp_alloc(pool, sizeof(struct adata) + olda->length + 2);
newa->length = olda->length + 2;
newa->data[0] = 2;
newa->data[1] = olda->data[1] + 1;
memcpy(newa->data+4, olda->data+2, olda->length-2);
}
else /* Create new path segment */
{
newa = lp_alloc(pool, sizeof(struct adata) + olda->length + 4);
newa->length = olda->length + 4;
newa->data[0] = 2;
newa->data[1] = 1;
memcpy(newa->data+4, olda->data, olda->length);
}
put_u16(newa->data+2, as);
e->attrs[0].u.ptr = newa;
return e;
}
static ea_list *
bgp_update_attrs(struct bgp_proto *p, rte *e, ea_list *old, struct linpool *pool)
{
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);
/* FIXME: Set NEXT_HOP to self */
return old;
}
int
bgp_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *pool)
{
rte *e = *new;
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 */
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);
}
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 */
}
int
bgp_rte_better(rte *new, rte *old)
{
struct bgp_proto *new_bgp = (struct bgp_proto *) new->attrs->proto;
struct bgp_proto *old_bgp = (struct bgp_proto *) old->attrs->proto;
eattr *new_lpref = ea_find(new->attrs->eattrs, EA_CODE(EAP_BGP, BA_LOCAL_PREF));
eattr *old_lpref = ea_find(old->attrs->eattrs, EA_CODE(EAP_BGP, BA_LOCAL_PREF));
/* Start with local preferences */
if (new_lpref && old_lpref) /* Somebody might have undefined them */
{
if (new_lpref->u.data > old_lpref->u.data)
return 1;
if (new_lpref->u.data < old_lpref->u.data)
return 0;
}
/* A tie breaking procedure according to RFC 1771, section 9.1.2.1 */
/* FIXME: Look at MULTI_EXIT_DISC, take the lowest */
/* We don't have interior distances */
/* We prefer external peers */
if (new_bgp->is_internal > old_bgp->is_internal)
return 0;
if (new_bgp->is_internal < old_bgp->is_internal)
return 1;
/* Finally we compare BGP identifiers */
return (new_bgp->remote_id < old_bgp->remote_id);
}
static int
bgp_check_origin(byte *a, int len)
bgp_local_pref(struct bgp_proto *p, rta *a)
{
return 0; /* FIXME (should be compatible with Cisco defaults?) */
}
static int
bgp_path_loopy(struct bgp_proto *p, eattr *a)
{
byte *path = a->u.ptr->data;
int len = a->u.ptr->length;
int i, n;
while (len > 0)
{
n = path[1];
len -= 2 - 2*n;
path += 2;
for(i=0; i<n; i++)
{
if (get_u16(path) == p->local_as)
return 1;
path += 2;
}
}
return 0;
}
static int
bgp_check_origin(struct bgp_proto *p, byte *a, int len)
{
if (len > 2)
return 6;
@ -28,7 +214,7 @@ bgp_check_origin(byte *a, int len)
}
static void
bgp_format_origin(struct eattr *a, byte *buf)
bgp_format_origin(eattr *a, byte *buf)
{
static char *bgp_origin_names[] = { "IGP", "EGP", "Incomplete" };
@ -36,7 +222,7 @@ bgp_format_origin(struct eattr *a, byte *buf)
}
static int
bgp_check_path(byte *a, int len)
bgp_check_path(struct bgp_proto *p, byte *a, int len)
{
while (len)
{
@ -52,7 +238,7 @@ bgp_check_path(byte *a, int len)
}
static int
bgp_check_next_hop(byte *a, int len)
bgp_check_next_hop(struct bgp_proto *p, byte *a, int len)
{
ip_addr addr;
@ -63,13 +249,21 @@ bgp_check_next_hop(byte *a, int len)
return 8;
}
static int
bgp_check_local_pref(struct bgp_proto *p, byte *a, int len)
{
if (!p->is_internal) /* Ignore local preference from EBGP connections */
return -1;
return 0;
}
struct attr_desc {
char *name; /* FIXME: Use the same names as in filters */
int expected_length;
int expected_flags;
int type;
int (*validate)(byte *attr, int len);
void (*format)(struct eattr *ea, byte *buf);
int (*validate)(struct bgp_proto *p, byte *attr, int len);
void (*format)(eattr *ea, byte *buf);
};
static struct attr_desc bgp_attr_table[] = {
@ -84,7 +278,7 @@ static struct attr_desc bgp_attr_table[] = {
{ "MED", 4, BAF_OPTIONAL, EAF_TYPE_INT, /* BA_MULTI_EXIT_DISC */
NULL, NULL },
{ "local_pref", 4, BAF_OPTIONAL, EAF_TYPE_INT, /* BA_LOCAL_PREF */
NULL, NULL },
bgp_check_local_pref, NULL },
{ "atomic_aggr", 0, BAF_OPTIONAL, EAF_TYPE_OPAQUE, /* BA_ATOMIC_AGGR */
NULL, NULL },
{ "aggregator", 6, BAF_OPTIONAL, EAF_TYPE_OPAQUE, /* BA_AGGREGATOR */
@ -104,7 +298,8 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct lin
{
struct bgp_proto *bgp = conn->bgp;
rta *a = lp_alloc(pool, sizeof(struct rta));
unsigned int flags, code, l, errcode, i, type;
unsigned int flags, code, l, i, type;
int errcode;
byte *z, *attr_start;
byte seen[256/8];
eattr *e;
@ -157,7 +352,6 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct lin
DBG("Attr %02x %02x %d\n", code, flags, l);
if (seen[code/8] & (1 << (code%8)))
goto malformed;
seen[code/8] |= (1 << (code%8));
if (code && code < sizeof(bgp_attr_table)/sizeof(bgp_attr_table[0]))
{
struct attr_desc *desc = &bgp_attr_table[code];
@ -165,8 +359,14 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct lin
{ errcode = 5; goto err; }
if ((desc->expected_flags ^ flags) & (BAF_OPTIONAL | BAF_TRANSITIVE))
{ errcode = 4; goto err; }
if (desc->validate && (errcode = desc->validate(z, l)))
goto err;
if (desc->validate)
{
errcode = desc->validate(bgp, z, l);
if (errcode > 0)
goto err;
if (errcode < 0)
continue;
}
type = desc->type;
}
else /* Unknown attribute */
@ -175,7 +375,8 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct lin
{ errcode = 2; goto err; }
type = EAF_TYPE_OPAQUE;
}
ea = lp_alloc(pool, sizeof(struct ea_list) + sizeof(struct eattr));
seen[code/8] |= (1 << (code%8));
ea = lp_alloc(pool, sizeof(ea_list) + sizeof(eattr));
ea->next = a->eattrs;
a->eattrs = ea;
ea->flags = 0;
@ -218,6 +419,26 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct lin
}
}
/* Assign local preference if none defined */
if (!(seen[BA_LOCAL_PREF/8] & (1 << (BA_LOCAL_PREF%8))))
{
ea = lp_alloc(pool, sizeof(ea_list) + sizeof(eattr));
ea->next = a->eattrs;
a->eattrs = ea;
ea->flags = 0;
ea->count = 1;
ea->attrs[0].id = EA_CODE(EAP_BGP, BA_LOCAL_PREF);
ea->attrs[0].flags = BAF_OPTIONAL;
ea->attrs[0].type = EAF_TYPE_INT;
ea->attrs[0].u.data = bgp_local_pref(bgp, a);
}
/* If the AS path attribute contains our AS, reject the routes */
e = ea_find(a->eattrs, EA_CODE(EAP_BGP, BA_AS_PATH));
ASSERT(e);
if (bgp_path_loopy(bgp, e))
return NULL;
/* Fill in the remaining rta fields */
e = ea_find(a->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP));
ASSERT(e);

View file

@ -28,12 +28,6 @@ static char *bgp_state_names[] = { "Idle", "Connect", "Active", "OpenSent", "Ope
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)
{
DBG("BGP: Got route %I/%d\n", n->n.prefix, n->n.pxlen);
}
static struct proto *
bgp_init(struct proto_config *C)
{
@ -42,6 +36,8 @@ bgp_init(struct proto_config *C)
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;

View file

@ -69,6 +69,10 @@ void bgp_close_conn(struct bgp_conn *c);
struct rta *bgp_decode_attrs(struct bgp_conn *conn, byte *a, unsigned int len, struct linpool *pool);
int bgp_get_attr(struct eattr *e, byte *buf);
int bgp_rte_better(struct rte *, struct rte *);
void bgp_rt_notify(struct proto *, struct network *, struct rte *, struct rte *, struct ea_list *);
int bgp_import_control(struct proto *, struct rte **, struct ea_list **, struct linpool *);
struct ea_list *bgp_path_prepend(struct linpool *pool, struct eattr *a, struct ea_list *old, int as);
/* packets.c */