Sending of update messages works!
This commit is contained in:
parent
c0668f3696
commit
f421cfdd80
3 changed files with 275 additions and 91 deletions
|
@ -31,13 +31,172 @@ struct attr_desc {
|
||||||
void (*format)(eattr *ea, byte *buf);
|
void (*format)(eattr *ea, byte *buf);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct attr_desc bgp_attr_table[];
|
static int
|
||||||
|
bgp_check_origin(struct bgp_proto *p, byte *a, int len)
|
||||||
|
{
|
||||||
|
if (len > 2)
|
||||||
|
return 6;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
bgp_format_origin(eattr *a, byte *buf)
|
||||||
|
{
|
||||||
|
static char *bgp_origin_names[] = { "IGP", "EGP", "Incomplete" };
|
||||||
|
|
||||||
|
bsprintf(buf, bgp_origin_names[a->u.data]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bgp_check_path(struct bgp_proto *p, byte *a, int len)
|
||||||
|
{
|
||||||
|
while (len)
|
||||||
|
{
|
||||||
|
DBG("Path segment %02x %02x\n", a[0], a[1]);
|
||||||
|
if (len < 2 ||
|
||||||
|
a[0] != BGP_PATH_AS_SET && a[0] != BGP_PATH_AS_SEQUENCE ||
|
||||||
|
2*a[1] + 2 > len)
|
||||||
|
return 11;
|
||||||
|
len -= 2*a[1] + 2;
|
||||||
|
a += 2*a[1] + 2;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
bgp_check_next_hop(struct bgp_proto *p, byte *a, int len)
|
||||||
|
{
|
||||||
|
ip_addr addr;
|
||||||
|
|
||||||
|
memcpy(&addr, a, len);
|
||||||
|
ipa_ntoh(addr);
|
||||||
|
if (ipa_classify(addr) & IADDR_HOST)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct attr_desc bgp_attr_table[] = {
|
||||||
|
{ NULL, -1, 0, 0, /* Undefined */
|
||||||
|
NULL, NULL },
|
||||||
|
{ "origin", 1, BAF_TRANSITIVE, EAF_TYPE_INT, /* BA_ORIGIN */
|
||||||
|
bgp_check_origin, bgp_format_origin },
|
||||||
|
{ "as_path", -1, BAF_TRANSITIVE, EAF_TYPE_AS_PATH, /* BA_AS_PATH */
|
||||||
|
bgp_check_path, NULL },
|
||||||
|
{ "next_hop", 4, BAF_TRANSITIVE, EAF_TYPE_IP_ADDRESS, /* BA_NEXT_HOP */
|
||||||
|
bgp_check_next_hop, NULL },
|
||||||
|
{ "MED", 4, BAF_OPTIONAL, EAF_TYPE_INT, /* BA_MULTI_EXIT_DISC */
|
||||||
|
NULL, NULL },
|
||||||
|
{ "local_pref", 4, BAF_OPTIONAL, EAF_TYPE_INT, /* BA_LOCAL_PREF */
|
||||||
|
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 */
|
||||||
|
NULL, NULL },
|
||||||
|
#if 0
|
||||||
|
/* FIXME: Handle community lists and remember to convert their endianity and normalize them */
|
||||||
|
{ 0, 0 }, /* BA_COMMUNITY */
|
||||||
|
{ 0, 0 }, /* BA_ORIGINATOR_ID */
|
||||||
|
{ 0, 0 }, /* BA_CLUSTER_LIST */
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
byte *
|
||||||
|
bgp_encode_attrs(byte *w, struct bgp_bucket *buck)
|
||||||
|
{
|
||||||
|
int remains = 1024;
|
||||||
|
unsigned int i, code, flags;
|
||||||
|
byte *start = w;
|
||||||
|
int len;
|
||||||
|
|
||||||
|
w += 2;
|
||||||
|
for(i=0; i<buck->eattrs->count; i++)
|
||||||
|
{
|
||||||
|
eattr *a = &buck->eattrs->attrs[i];
|
||||||
|
ASSERT(EA_PROTO(a->id) == EAP_BGP);
|
||||||
|
code = EA_ID(a->id);
|
||||||
|
if (code && code < ARRAY_SIZE(bgp_attr_table))
|
||||||
|
{
|
||||||
|
struct attr_desc *desc = &bgp_attr_table[code];
|
||||||
|
len = desc->expected_length;
|
||||||
|
if (len < 0)
|
||||||
|
{
|
||||||
|
ASSERT(!(a->type & EAF_EMBEDDED));
|
||||||
|
len = a->u.ptr->length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ASSERT((a->type & EAF_TYPE_MASK) == EAF_TYPE_OPAQUE);
|
||||||
|
len = a->u.ptr->length;
|
||||||
|
}
|
||||||
|
DBG("\tAttribute %02x (type %02x, %d bytes)\n", code, a->type, len);
|
||||||
|
/* FIXME: Partial bit for locally added transitive attributes */
|
||||||
|
if (remains < len + 4)
|
||||||
|
{
|
||||||
|
log(L_ERR "BGP: attribute list too long, ignoring the remaining attributes");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
flags = a->flags & (BAF_OPTIONAL | BAF_TRANSITIVE | BAF_PARTIAL);
|
||||||
|
if (len < 256)
|
||||||
|
{
|
||||||
|
*w++ = flags;
|
||||||
|
*w++ = code;
|
||||||
|
*w++ = len;
|
||||||
|
remains -= 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*w++ = flags | BAF_EXT_LEN;
|
||||||
|
*w++ = code;
|
||||||
|
put_u16(w, len);
|
||||||
|
w += 2;
|
||||||
|
remains -= 4;
|
||||||
|
}
|
||||||
|
switch (a->type & EAF_TYPE_MASK)
|
||||||
|
{
|
||||||
|
case EAF_TYPE_INT:
|
||||||
|
case EAF_TYPE_ROUTER_ID:
|
||||||
|
if (len == 4)
|
||||||
|
put_u32(w, a->u.data);
|
||||||
|
else
|
||||||
|
*w = a->u.data;
|
||||||
|
break;
|
||||||
|
case EAF_TYPE_IP_ADDRESS:
|
||||||
|
{
|
||||||
|
ip_addr ip = *(ip_addr *)a->u.ptr->data;
|
||||||
|
ipa_hton(ip);
|
||||||
|
memcpy(w, &ip, len);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case EAF_TYPE_OPAQUE:
|
||||||
|
case EAF_TYPE_AS_PATH:
|
||||||
|
case EAF_TYPE_INT_SET:
|
||||||
|
memcpy(w, a->u.ptr->data, len);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
bug("bgp_encode_attrs: unknown attribute type %02x", a->type);
|
||||||
|
}
|
||||||
|
remains -= len;
|
||||||
|
w += len;
|
||||||
|
}
|
||||||
|
put_u16(start, w-start-2);
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
bgp_init_prefix(struct fib_node *N)
|
bgp_init_prefix(struct fib_node *N)
|
||||||
{
|
{
|
||||||
struct bgp_prefix *p = (struct bgp_prefix *) N;
|
struct bgp_prefix *p = (struct bgp_prefix *) N;
|
||||||
/* FIXME */
|
p->bucket_node.next = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -104,6 +263,8 @@ bgp_new_bucket(struct bgp_proto *p, ea_list *new, unsigned hash)
|
||||||
p->bucket_hash[index] = b;
|
p->bucket_hash[index] = b;
|
||||||
b->hash_prev = NULL;
|
b->hash_prev = NULL;
|
||||||
b->hash = hash;
|
b->hash = hash;
|
||||||
|
add_tail(&p->bucket_queue, &b->send_node);
|
||||||
|
init_list(&b->prefixes);
|
||||||
memcpy(b->eattrs, new, ea_size);
|
memcpy(b->eattrs, new, ea_size);
|
||||||
dest = ((byte *)b->eattrs) + ea_size_aligned;
|
dest = ((byte *)b->eattrs) + ea_size_aligned;
|
||||||
|
|
||||||
|
@ -169,7 +330,7 @@ bgp_get_bucket(struct bgp_proto *p, ea_list *old, ea_list *tmp)
|
||||||
*d = *a;
|
*d = *a;
|
||||||
switch (d->type & EAF_TYPE_MASK)
|
switch (d->type & EAF_TYPE_MASK)
|
||||||
{
|
{
|
||||||
case EAF_TYPE_INT_SET:
|
case EAF_TYPE_INT_SET: /* FIXME: Normalize the other attributes? */
|
||||||
{
|
{
|
||||||
struct adata *z = alloca(sizeof(struct adata) + d->u.ptr->length);
|
struct adata *z = alloca(sizeof(struct adata) + d->u.ptr->length);
|
||||||
z->length = d->u.ptr->length;
|
z->length = d->u.ptr->length;
|
||||||
|
@ -200,27 +361,60 @@ bgp_get_bucket(struct bgp_proto *p, ea_list *old, ea_list *tmp)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check if next hop is valid */
|
||||||
|
a = ea_find(new, EA_CODE(EAP_BGP, BA_NEXT_HOP));
|
||||||
|
ASSERT(a);
|
||||||
|
if (ipa_equal(p->next_hop, *(ip_addr *)a->u.ptr))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
/* Create new bucket */
|
/* Create new bucket */
|
||||||
DBG("Creating bucket.\n");
|
DBG("Creating bucket.\n");
|
||||||
return bgp_new_bucket(p, new, hash);
|
return bgp_new_bucket(p, new, hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
bgp_free_bucket(struct bgp_proto *p, struct bgp_bucket *buck)
|
||||||
|
{
|
||||||
|
if (buck->hash_next)
|
||||||
|
buck->hash_next->hash_prev = buck->hash_prev;
|
||||||
|
if (buck->hash_prev)
|
||||||
|
buck->hash_prev->hash_next = buck->hash_next;
|
||||||
|
else
|
||||||
|
p->bucket_hash[buck->hash & (p->hash_size-1)] = buck->hash_next;
|
||||||
|
mb_free(buck);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
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)
|
||||||
{
|
{
|
||||||
struct bgp_proto *p = (struct bgp_proto *) P;
|
struct bgp_proto *p = (struct bgp_proto *) P;
|
||||||
|
struct bgp_bucket *buck;
|
||||||
|
struct bgp_prefix *px;
|
||||||
|
|
||||||
DBG("BGP: Got route %I/%d\n", n->n.prefix, n->n.pxlen);
|
DBG("BGP: Got route %I/%d %s\n", n->n.prefix, n->n.pxlen, new ? "up" : "down");
|
||||||
|
|
||||||
if (new)
|
if (new)
|
||||||
{
|
{
|
||||||
struct bgp_bucket *buck = bgp_get_bucket(p, new->attrs->eattrs, tmpa);
|
buck = bgp_get_bucket(p, new->attrs->eattrs, tmpa);
|
||||||
if (!buck) /* Inconsistent attribute list */
|
if (!buck) /* Inconsistent attribute list */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
/* FIXME: Normalize attributes */
|
{
|
||||||
/* FIXME: Check next hop */
|
if (!(buck = p->withdraw_bucket))
|
||||||
|
{
|
||||||
|
buck = p->withdraw_bucket = mb_alloc(P->pool, sizeof(struct bgp_bucket));
|
||||||
|
init_list(&buck->prefixes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
px = fib_get(&p->prefix_fib, &n->n.prefix, n->n.pxlen);
|
||||||
|
if (px->bucket_node.next)
|
||||||
|
{
|
||||||
|
DBG("\tRemoving old entry.\n");
|
||||||
|
rem_node(&px->bucket_node);
|
||||||
|
}
|
||||||
|
add_tail(&buck->prefixes, &px->bucket_node);
|
||||||
|
bgp_schedule_packet(p->conn, PKT_UPDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -404,83 +598,6 @@ bgp_path_loopy(struct bgp_proto *p, eattr *a)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
bgp_check_origin(struct bgp_proto *p, byte *a, int len)
|
|
||||||
{
|
|
||||||
if (len > 2)
|
|
||||||
return 6;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
bgp_format_origin(eattr *a, byte *buf)
|
|
||||||
{
|
|
||||||
static char *bgp_origin_names[] = { "IGP", "EGP", "Incomplete" };
|
|
||||||
|
|
||||||
bsprintf(buf, bgp_origin_names[a->u.data]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
bgp_check_path(struct bgp_proto *p, byte *a, int len)
|
|
||||||
{
|
|
||||||
while (len)
|
|
||||||
{
|
|
||||||
DBG("Path segment %02x %02x\n", a[0], a[1]);
|
|
||||||
if (len < 2 ||
|
|
||||||
a[0] != BGP_PATH_AS_SET && a[0] != BGP_PATH_AS_SEQUENCE ||
|
|
||||||
2*a[1] + 2 > len)
|
|
||||||
return 11;
|
|
||||||
len -= 2*a[1] + 2;
|
|
||||||
a += 2*a[1] + 2;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
bgp_check_next_hop(struct bgp_proto *p, byte *a, int len)
|
|
||||||
{
|
|
||||||
ip_addr addr;
|
|
||||||
|
|
||||||
memcpy(&addr, a, len);
|
|
||||||
if (ipa_classify(ipa_ntoh(addr)) & IADDR_HOST)
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct attr_desc bgp_attr_table[] = {
|
|
||||||
{ NULL, -1, 0, 0, /* Undefined */
|
|
||||||
NULL, NULL },
|
|
||||||
{ "origin", 1, BAF_TRANSITIVE, EAF_TYPE_INT, /* BA_ORIGIN */
|
|
||||||
bgp_check_origin, bgp_format_origin },
|
|
||||||
{ "as_path", -1, BAF_TRANSITIVE, EAF_TYPE_AS_PATH, /* BA_AS_PATH */
|
|
||||||
bgp_check_path, NULL },
|
|
||||||
{ "next_hop", 4, BAF_TRANSITIVE, EAF_TYPE_IP_ADDRESS, /* BA_NEXT_HOP */
|
|
||||||
bgp_check_next_hop, NULL },
|
|
||||||
{ "MED", 4, BAF_OPTIONAL, EAF_TYPE_INT, /* BA_MULTI_EXIT_DISC */
|
|
||||||
NULL, NULL },
|
|
||||||
{ "local_pref", 4, BAF_OPTIONAL, EAF_TYPE_INT, /* BA_LOCAL_PREF */
|
|
||||||
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 */
|
|
||||||
NULL, NULL },
|
|
||||||
#if 0
|
|
||||||
/* FIXME: Handle community lists and remember to convert their endianity and normalize them */
|
|
||||||
{ 0, 0 }, /* BA_COMMUNITY */
|
|
||||||
{ 0, 0 }, /* BA_ORIGINATOR_ID */
|
|
||||||
{ 0, 0 }, /* BA_CLUSTER_LIST */
|
|
||||||
#endif
|
|
||||||
};
|
|
||||||
|
|
||||||
struct rta *
|
struct rta *
|
||||||
bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct linpool *pool)
|
bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct linpool *pool)
|
||||||
{
|
{
|
||||||
|
@ -540,7 +657,7 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct lin
|
||||||
DBG("Attr %02x %02x %d\n", code, flags, l);
|
DBG("Attr %02x %02x %d\n", code, flags, l);
|
||||||
if (seen[code/8] & (1 << (code%8)))
|
if (seen[code/8] & (1 << (code%8)))
|
||||||
goto malformed;
|
goto malformed;
|
||||||
if (code && code < sizeof(bgp_attr_table)/sizeof(bgp_attr_table[0]))
|
if (code && code < ARRAY_SIZE(bgp_attr_table))
|
||||||
{
|
{
|
||||||
struct attr_desc *desc = &bgp_attr_table[code];
|
struct attr_desc *desc = &bgp_attr_table[code];
|
||||||
if (desc->expected_length >= 0 && desc->expected_length != (int) l)
|
if (desc->expected_length >= 0 && desc->expected_length != (int) l)
|
||||||
|
@ -591,7 +708,7 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct lin
|
||||||
ea->attrs[0].u.data = get_u32(z);
|
ea->attrs[0].u.data = get_u32(z);
|
||||||
break;
|
break;
|
||||||
case EAF_TYPE_IP_ADDRESS:
|
case EAF_TYPE_IP_ADDRESS:
|
||||||
*(ip_addr *)ad->data = ipa_ntoh(*(ip_addr *)ad->data);
|
ipa_ntoh(*(ip_addr *)ad->data);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,8 +68,8 @@ struct bgp_prefix {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct bgp_bucket {
|
struct bgp_bucket {
|
||||||
struct bgp_bucket *hash_next, *hash_prev; /* Node in bucket hash table */
|
|
||||||
node send_node; /* Node in send queue */
|
node send_node; /* Node in send queue */
|
||||||
|
struct bgp_bucket *hash_next, *hash_prev; /* Node in bucket hash table */
|
||||||
unsigned hash; /* Hash over extended attributes */
|
unsigned hash; /* Hash over extended attributes */
|
||||||
list prefixes; /* Prefixes in this buckets */
|
list prefixes; /* Prefixes in this buckets */
|
||||||
ea_list eattrs[0]; /* Per-bucket extended attributes */
|
ea_list eattrs[0]; /* Per-bucket extended attributes */
|
||||||
|
@ -97,6 +97,8 @@ int bgp_rte_better(struct rte *, struct rte *);
|
||||||
void bgp_rt_notify(struct proto *, struct network *, struct rte *, struct rte *, struct ea_list *);
|
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 *);
|
int bgp_import_control(struct proto *, struct rte **, struct ea_list **, struct linpool *);
|
||||||
void bgp_attr_init(struct bgp_proto *);
|
void bgp_attr_init(struct bgp_proto *);
|
||||||
|
byte *bgp_encode_attrs(byte *w, struct bgp_bucket *buck);
|
||||||
|
void bgp_free_bucket(struct bgp_proto *p, struct bgp_bucket *buck);
|
||||||
|
|
||||||
/* packets.c */
|
/* packets.c */
|
||||||
|
|
||||||
|
|
|
@ -46,12 +46,76 @@ bgp_create_open(struct bgp_conn *conn, byte *buf)
|
||||||
return buf+10;
|
return buf+10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned int
|
||||||
|
bgp_encode_prefixes(struct bgp_proto *p, byte *w, struct bgp_bucket *buck, unsigned int remains)
|
||||||
|
{
|
||||||
|
byte *start = w;
|
||||||
|
ip_addr a;
|
||||||
|
int bytes;
|
||||||
|
|
||||||
|
while (!EMPTY_LIST(buck->prefixes) && remains >= 5)
|
||||||
|
{
|
||||||
|
struct bgp_prefix *px = SKIP_BACK(struct bgp_prefix, bucket_node, HEAD(buck->prefixes));
|
||||||
|
DBG("\tDequeued route %I/%d\n", px->n.prefix, px->n.pxlen);
|
||||||
|
*w++ = px->n.pxlen;
|
||||||
|
bytes = (px->n.pxlen + 7) / 8;
|
||||||
|
a = px->n.prefix;
|
||||||
|
ipa_hton(a);
|
||||||
|
memcpy(w, &a, bytes);
|
||||||
|
w += bytes;
|
||||||
|
rem_node(&px->bucket_node);
|
||||||
|
fib_delete(&p->prefix_fib, px);
|
||||||
|
}
|
||||||
|
return w - start;
|
||||||
|
}
|
||||||
|
|
||||||
static byte *
|
static byte *
|
||||||
bgp_create_update(struct bgp_conn *conn, byte *buf)
|
bgp_create_update(struct bgp_conn *conn, byte *buf)
|
||||||
{
|
{
|
||||||
DBG("BGP: Sending update\n");
|
struct bgp_proto *bgp = conn->bgp;
|
||||||
|
struct bgp_bucket *buck;
|
||||||
|
int remains = BGP_MAX_PACKET_LENGTH - BGP_HEADER_LENGTH - 4;
|
||||||
|
byte *w, *wold;
|
||||||
|
ip_addr ip;
|
||||||
|
int wd_size = 0;
|
||||||
|
int r_size = 0;
|
||||||
|
|
||||||
bug("Don't know how to create updates");
|
DBG("BGP: Sending update\n");
|
||||||
|
w = buf+2;
|
||||||
|
if ((buck = bgp->withdraw_bucket) && !EMPTY_LIST(buck->prefixes))
|
||||||
|
{
|
||||||
|
DBG("Withdrawn routes:\n");
|
||||||
|
wd_size = bgp_encode_prefixes(bgp, w, buck, remains);
|
||||||
|
w += wd_size;
|
||||||
|
remains -= wd_size;
|
||||||
|
}
|
||||||
|
put_u16(buf, wd_size);
|
||||||
|
|
||||||
|
if (remains >= 2048)
|
||||||
|
{
|
||||||
|
while ((buck = (struct bgp_bucket *) HEAD(bgp->bucket_queue))->send_node.next)
|
||||||
|
{
|
||||||
|
if (EMPTY_LIST(buck->prefixes))
|
||||||
|
{
|
||||||
|
DBG("Deleting empty bucket %p\n", buck);
|
||||||
|
rem_node(&buck->send_node);
|
||||||
|
bgp_free_bucket(bgp, buck);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
DBG("Processing bucket %p\n", buck);
|
||||||
|
w = bgp_encode_attrs(w, buck);
|
||||||
|
remains = BGP_MAX_PACKET_LENGTH - BGP_HEADER_LENGTH - (w-buf);
|
||||||
|
r_size = bgp_encode_prefixes(bgp, w, buck, remains);
|
||||||
|
w += r_size;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
put_u16(w, 0);
|
||||||
|
w += 2;
|
||||||
|
}
|
||||||
|
return (wd_size || r_size) ? w : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -225,7 +289,8 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, int len)
|
||||||
memcpy(&prefix, pp, q); \
|
memcpy(&prefix, pp, q); \
|
||||||
pp += q; \
|
pp += q; \
|
||||||
ll -= q; \
|
ll -= q; \
|
||||||
prefix = ipa_and(ipa_ntoh(prefix), ipa_mkmask(b)); \
|
ipa_ntoh(prefix); \
|
||||||
|
prefix = ipa_and(prefix, ipa_mkmask(b)); \
|
||||||
pxlen = b; \
|
pxlen = b; \
|
||||||
} while (0)
|
} while (0)
|
||||||
/* FIXME: Check validity of prefixes */
|
/* FIXME: Check validity of prefixes */
|
||||||
|
|
Loading…
Reference in a new issue