Receive-only IPv6 BGP.

This commit is contained in:
Martin Mares 2000-05-04 09:03:31 +00:00
parent d345cda5a1
commit 1c1da87b27
3 changed files with 264 additions and 67 deletions

View file

@ -22,7 +22,11 @@
#include "bgp.h" #include "bgp.h"
static byte bgp_mandatory_attrs[] = { BA_ORIGIN, BA_AS_PATH, BA_NEXT_HOP }; static byte bgp_mandatory_attrs[] = { BA_ORIGIN, BA_AS_PATH
#ifndef IPV6
,BA_NEXT_HOP
#endif
};
struct attr_desc { struct attr_desc {
char *name; char *name;
@ -69,6 +73,9 @@ bgp_check_path(struct bgp_proto *p, byte *a, int len)
static int static int
bgp_check_next_hop(struct bgp_proto *p, byte *a, int len) bgp_check_next_hop(struct bgp_proto *p, byte *a, int len)
{ {
#ifdef IPV6
return -1;
#else
ip_addr addr; ip_addr addr;
memcpy(&addr, a, len); memcpy(&addr, a, len);
@ -77,31 +84,61 @@ bgp_check_next_hop(struct bgp_proto *p, byte *a, int len)
return 0; return 0;
else else
return 8; return 8;
#endif
}
static int
bgp_check_reach_nlri(struct bgp_proto *p, byte *a, int len)
{
#ifdef IPV6
p->mp_reach_start = a;
p->mp_reach_len = len;
return 0;
#else
return -1;
#endif
}
static int
bgp_check_unreach_nlri(struct bgp_proto *p, byte *a, int len)
{
#ifdef IPV6
p->mp_unreach_start = a;
p->mp_unreach_len = len;
return 0;
#else
return -1;
#endif
} }
static struct attr_desc bgp_attr_table[] = { static struct attr_desc bgp_attr_table[] = {
{ NULL, -1, 0, 0, 0, /* Undefined */ { NULL, -1, 0, 0, 0, /* Undefined */
NULL, NULL }, NULL, NULL },
{ "origin", 1, BAF_TRANSITIVE, EAF_TYPE_INT, 1, /* BA_ORIGIN */ { "origin", 1, BAF_TRANSITIVE, EAF_TYPE_INT, 1, /* BA_ORIGIN */
bgp_check_origin, bgp_format_origin }, bgp_check_origin, bgp_format_origin },
{ "as_path", -1, BAF_TRANSITIVE, EAF_TYPE_AS_PATH, 1, /* BA_AS_PATH */ { "as_path", -1, BAF_TRANSITIVE, EAF_TYPE_AS_PATH, 1, /* BA_AS_PATH */
bgp_check_path, NULL }, bgp_check_path, NULL },
{ "next_hop", 4, BAF_TRANSITIVE, EAF_TYPE_IP_ADDRESS, 1, /* BA_NEXT_HOP */ { "next_hop", 4, BAF_TRANSITIVE, EAF_TYPE_IP_ADDRESS, 1, /* BA_NEXT_HOP */
bgp_check_next_hop, NULL }, bgp_check_next_hop, NULL },
{ "med", 4, BAF_OPTIONAL, EAF_TYPE_INT, 0, /* BA_MULTI_EXIT_DISC */ { "med", 4, BAF_OPTIONAL, EAF_TYPE_INT, 0, /* BA_MULTI_EXIT_DISC */
NULL, NULL }, NULL, NULL },
{ "local_pref", 4, BAF_OPTIONAL, EAF_TYPE_INT, 0, /* BA_LOCAL_PREF */ { "local_pref", 4, BAF_OPTIONAL, EAF_TYPE_INT, 0, /* BA_LOCAL_PREF */
NULL, NULL }, NULL, NULL },
{ "atomic_aggr", 0, BAF_TRANSITIVE, EAF_TYPE_OPAQUE, 1, /* BA_ATOMIC_AGGR */ { "atomic_aggr", 0, BAF_TRANSITIVE, EAF_TYPE_OPAQUE, 1, /* BA_ATOMIC_AGGR */
NULL, NULL }, NULL, NULL },
{ "aggregator", 6, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_OPAQUE, 1, /* BA_AGGREGATOR */ { "aggregator", 6, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_OPAQUE, 1, /* BA_AGGREGATOR */
NULL, NULL }, NULL, NULL },
{ "community", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_INT_SET, 1, /* BA_COMMUNITY */ { "community", -1, BAF_OPTIONAL | BAF_TRANSITIVE, EAF_TYPE_INT_SET, 1, /* BA_COMMUNITY */
NULL, NULL }, NULL, NULL },
#if 0 { NULL, }, /* BA_ORIGINATOR_ID */
{ 0, 0 }, /* BA_ORIGINATOR_ID */ { NULL, }, /* BA_CLUSTER_LIST */
{ 0, 0 }, /* BA_CLUSTER_LIST */ { NULL, }, /* BA_DPA */
#endif { NULL, }, /* BA_ADVERTISER */
{ NULL, }, /* BA_RCID_PATH */
{ "mp_reach_nlri", -1, BAF_OPTIONAL, EAF_TYPE_OPAQUE, 1, /* BA_MP_REACH_NLRI */
bgp_check_reach_nlri, NULL },
{ "mp_unreach_nlri", -1, BAF_OPTIONAL, EAF_TYPE_OPAQUE, 1, /* BA_MP_UNREACH_NLRI */
bgp_check_unreach_nlri, NULL },
}; };
#define ATTR_KNOWN(code) ((code) < ARRAY_SIZE(bgp_attr_table) && bgp_attr_table[code].name) #define ATTR_KNOWN(code) ((code) < ARRAY_SIZE(bgp_attr_table) && bgp_attr_table[code].name)
@ -708,8 +745,6 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct lin
eattr *e; eattr *e;
ea_list *ea; ea_list *ea;
struct adata *ad; struct adata *ad;
neighbor *neigh;
ip_addr nexthop;
a->proto = &bgp->p; a->proto = &bgp->p;
a->source = RTS_BGP; a->source = RTS_BGP;
@ -820,6 +855,11 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct lin
} }
} }
#ifdef IPV6
if (seen[BA_MP_REACH_NLRI / 8] & (1 << (BA_MP_REACH_NLRI % 8)))
mandatory = 1;
#endif
/* Check if all mandatory attributes are present */ /* Check if all mandatory attributes are present */
if (mandatory) if (mandatory)
{ {
@ -855,19 +895,6 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct lin
ea->attrs[0].type = EAF_TYPE_INT; ea->attrs[0].type = EAF_TYPE_INT;
ea->attrs[0].u.data = 0; ea->attrs[0].u.data = 0;
} }
/* Fill in the remaining rta fields */
e = ea_find(a->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP));
ASSERT(e);
nexthop = *(ip_addr *) e->u.ptr->data;
if (ipa_equal(nexthop, bgp->local_addr))
{
DBG("BGP: Loop!\n");
return NULL;
}
neigh = neigh_find(&bgp->p, &nexthop, 0) ? : bgp->neigh;
a->gw = neigh->addr;
a->iface = neigh->iface;
return a; return a;
malformed: malformed:

View file

@ -72,6 +72,10 @@ struct bgp_proto {
struct bgp_bucket *withdraw_bucket; /* Withdrawn routes */ struct bgp_bucket *withdraw_bucket; /* Withdrawn routes */
unsigned startup_delay; /* Time to delay protocol startup by due to errors */ unsigned startup_delay; /* Time to delay protocol startup by due to errors */
bird_clock_t last_connect; /* Time of last connect attempt */ bird_clock_t last_connect; /* Time of last connect attempt */
#ifdef IPV6
byte *mp_reach_start, *mp_unreach_start; /* Multiprotocol BGP attribute notes */
unsigned mp_reach_len, mp_unreach_len;
#endif
}; };
struct bgp_prefix { struct bgp_prefix {
@ -181,4 +185,8 @@ void bgp_log_error(struct bgp_proto *p, char *msg, unsigned code, unsigned subco
#define ORIGIN_EGP 1 #define ORIGIN_EGP 1
#define ORIGIN_INCOMPLETE 2 #define ORIGIN_INCOMPLETE 2
/* Address families */
#define BGP_AF_IPV6 2
#endif #endif

View file

@ -68,6 +68,8 @@ bgp_encode_prefixes(struct bgp_proto *p, byte *w, struct bgp_bucket *buck, unsig
return w - start; return w - start;
} }
#ifndef IPV6 /* IPv4 version */
static byte * static byte *
bgp_create_update(struct bgp_conn *conn, byte *buf) bgp_create_update(struct bgp_conn *conn, byte *buf)
{ {
@ -117,6 +119,16 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
return (wd_size || r_size) ? w : NULL; return (wd_size || r_size) ? w : NULL;
} }
#else /* IPv6 version */
static byte *
bgp_create_update(struct bgp_conn *conn, byte *buf)
{
return NULL;
}
#endif
static void static void
bgp_create_header(byte *buf, unsigned int len, unsigned int type) bgp_create_header(byte *buf, unsigned int len, unsigned int type)
{ {
@ -321,9 +333,9 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, int len)
int b = *pp++; \ int b = *pp++; \
int q; \ int q; \
ll--; \ ll--; \
if (b > BITS_PER_IP_ADDRESS) { bgp_error(conn, 3, 10, NULL, 0); return; } \ if (b > BITS_PER_IP_ADDRESS) { err=10; goto bad; } \
q = (b+7) / 8; \ q = (b+7) / 8; \
if (ll < q) goto malformed; \ if (ll < q) { err=1; goto bad; } \
memcpy(&prefix, pp, q); \ memcpy(&prefix, pp, q); \
pp += q; \ pp += q; \
ll -= q; \ ll -= q; \
@ -332,17 +344,196 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, int len)
pxlen = b; \ pxlen = b; \
} while (0) } while (0)
static inline int
bgp_get_nexthop(struct bgp_proto *bgp, rta *a)
{
neighbor *neigh;
ip_addr nexthop;
struct eattr *nh = ea_find(a->eattrs, EA_CODE(EAP_BGP, BA_NEXT_HOP));
ASSERT(nh);
nexthop = *(ip_addr *) nh->u.ptr->data;
if (ipa_equal(nexthop, bgp->local_addr))
{
DBG("BGP: Loop!\n");
return 0;
}
neigh = neigh_find(&bgp->p, &nexthop, 0) ? : bgp->neigh;
a->gw = neigh->addr;
a->iface = neigh->iface;
return 1;
}
#ifndef IPV6 /* IPv4 version */
static void
bgp_do_rx_update(struct bgp_conn *conn,
byte *withdrawn, int withdrawn_len,
byte *nlri, int nlri_len,
byte *attrs, int attr_len)
{
struct bgp_proto *p = conn->bgp;
rta *a0;
rta *a = NULL;
ip_addr prefix;
net *n;
rte e;
int err = 0, pxlen;
/* Withdraw routes */
while (withdrawn_len)
{
DECODE_PREFIX(withdrawn, withdrawn_len);
DBG("Withdraw %I/%d\n", prefix, pxlen);
if (n = net_find(p->p.table, prefix, pxlen))
rte_update(p->p.table, n, &p->p, NULL);
}
if (!attr_len && !nlri_len) /* shortcut */
return;
a0 = bgp_decode_attrs(conn, attrs, attr_len, bgp_linpool, nlri_len);
if (a0 && nlri_len && bgp_get_nexthop(p, a0))
{
a = rta_lookup(a0);
while (nlri_len)
{
rte *e;
DECODE_PREFIX(nlri, nlri_len);
DBG("Add %I/%d\n", prefix, pxlen);
e = rte_get_temp(rta_clone(a));
n = net_get(p->p.table, prefix, pxlen);
e->net = n;
e->pflags = 0;
rte_update(p->p.table, n, &p->p, e);
}
}
bad:
if (a)
rta_free(a);
if (err)
bgp_error(conn, 3, err, NULL, 0);
return;
}
#else /* IPv6 version */
#define DO_NLRI(name) \
start = x = p->name##_start; \
len = len0 = p->name##_len; \
if (len) \
{ \
if (len < 3) goto bad; \
af = get_u16(x); \
sub = x[2]; \
x += 3; \
len -= 3; \
DBG("\tNLRI AF=%d sub=%d len=%d\n", af, sub, len);\
} \
else \
af = 0; \
if (af == BGP_AF_IPV6)
static void
bgp_do_rx_update(struct bgp_conn *conn,
byte *withdrawn, int withdrawn_len,
byte *nlri, int nlri_len,
byte *attrs, int attr_len)
{
struct bgp_proto *p = conn->bgp;
byte *start, *x;
int len, len0;
unsigned af, sub;
rta *a0;
rta *a = NULL;
ip_addr prefix;
net *n;
rte e;
int err = 0, pxlen;
p->mp_reach_len = 0;
p->mp_unreach_len = 0;
a0 = bgp_decode_attrs(conn, attrs, attr_len, bgp_linpool, 0);
if (!a0)
return;
DO_NLRI(mp_unreach)
{
while (len)
{
DECODE_PREFIX(x, len);
DBG("Withdraw %I/%d\n", prefix, pxlen);
if (n = net_find(p->p.table, prefix, pxlen))
rte_update(p->p.table, n, &p->p, NULL);
}
}
DO_NLRI(mp_reach)
{
ea_list *e = lp_alloc(bgp_linpool, sizeof(ea_list) + sizeof(eattr));
struct adata *ad = lp_alloc(bgp_linpool, sizeof(struct adata) + 16);
int i;
/* Create fake NEXT_HOP attribute */
if (len < 1 || (*x != 16 && *x != 32) || len < *x + 2)
goto bad;
e->next = a0->eattrs;
a0->eattrs = e;
e->flags = EALF_SORTED;
e->count = 1;
e->attrs[0].id = EA_CODE(EAP_BGP, BA_NEXT_HOP);
e->attrs[0].flags = BAF_TRANSITIVE;
e->attrs[0].type = EAF_TYPE_IP_ADDRESS;
e->attrs[0].u.ptr = ad;
ad->length = 16;
memcpy(ad->data, x+1, 16);
len -= *x + 1;
x += *x + 1;
/* Ignore SNPA info */
i = *x++;
while (i--)
{
if (len < 1 || len < 1 + *x)
goto bad;
len -= *x + 1;
x += *x + 1;
}
if (bgp_get_nexthop(p, a0))
{
a = rta_lookup(a0);
while (len)
{
rte *e;
DECODE_PREFIX(x, len);
DBG("Add %I/%d\n", prefix, pxlen);
e = rte_get_temp(rta_clone(a));
n = net_get(p->p.table, prefix, pxlen);
e->net = n;
e->pflags = 0;
rte_update(p->p.table, n, &p->p, e);
}
rta_free(a);
}
}
return;
bad:
bgp_error(conn, 3, 9, start, len0);
if (a)
rta_free(a);
return;
}
#endif
static void static void
bgp_rx_update(struct bgp_conn *conn, byte *pkt, int len) bgp_rx_update(struct bgp_conn *conn, byte *pkt, int len)
{ {
struct bgp_proto *p = conn->bgp; struct bgp_proto *p = conn->bgp;
byte *withdrawn, *attrs, *nlri; byte *withdrawn, *attrs, *nlri;
ip_addr prefix; int withdrawn_len, attr_len, nlri_len;
int withdrawn_len, attr_len, nlri_len, pxlen;
net *n;
rte e;
rta *a0;
rta *a = NULL;
BGP_TRACE(D_PACKETS, "Got UPDATE"); BGP_TRACE(D_PACKETS, "Got UPDATE");
if (conn->state != BS_ESTABLISHED) if (conn->state != BS_ESTABLISHED)
@ -369,41 +560,12 @@ bgp_rx_update(struct bgp_conn *conn, byte *pkt, int len)
goto malformed; goto malformed;
DBG("Sizes: withdrawn=%d, attrs=%d, NLRI=%d\n", withdrawn_len, attr_len, nlri_len); DBG("Sizes: withdrawn=%d, attrs=%d, NLRI=%d\n", withdrawn_len, attr_len, nlri_len);
/* Withdraw routes */
while (withdrawn_len)
{
DECODE_PREFIX(withdrawn, withdrawn_len);
DBG("Withdraw %I/%d\n", prefix, pxlen);
if (n = net_find(p->p.table, prefix, pxlen))
rte_update(p->p.table, n, &p->p, NULL);
}
if (!attr_len && !nlri_len) /* shortcut */
return;
a0 = bgp_decode_attrs(conn, attrs, attr_len, bgp_linpool, nlri_len);
if (a0 && nlri_len)
{
a = rta_lookup(a0);
while (nlri_len)
{
rte *e;
DECODE_PREFIX(nlri, nlri_len);
DBG("Add %I/%d\n", prefix, pxlen);
e = rte_get_temp(rta_clone(a));
n = net_get(p->p.table, prefix, pxlen);
e->net = n;
e->pflags = 0;
rte_update(p->p.table, n, &p->p, e);
}
rta_free(a);
}
lp_flush(bgp_linpool); lp_flush(bgp_linpool);
bgp_do_rx_update(conn, withdrawn, withdrawn_len, nlri, nlri_len, attrs, attr_len);
return; return;
malformed: malformed:
if (a)
rta_free(a);
bgp_error(conn, 3, 1, NULL, 0); bgp_error(conn, 3, 1, NULL, 0);
} }