mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-09 20:58:44 +00:00
Receive-only IPv6 BGP.
This commit is contained in:
parent
d345cda5a1
commit
1c1da87b27
@ -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,6 +84,31 @@ 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[] = {
|
||||||
@ -98,10 +130,15 @@ static struct attr_desc bgp_attr_table[] = {
|
|||||||
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:
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user