summaryrefslogtreecommitdiffstats
path: root/proto/bgp/attrs.c
diff options
context:
space:
mode:
authorMatthias Schiffer <mschiffer@universe-factory.net>2010-11-16 03:47:07 +0100
committerMatthias Schiffer <mschiffer@universe-factory.net>2010-11-16 03:47:07 +0100
commit5b885bf70848908c7fed07c8efba18ea316379d4 (patch)
treeb4a94b0b5a49d2dd075a054270c386419c42900d /proto/bgp/attrs.c
parente6eee664723aa0e1d87eac65216cdf12636e3284 (diff)
downloadbird-5b885bf70848908c7fed07c8efba18ea316379d4.tar
bird-5b885bf70848908c7fed07c8efba18ea316379d4.zip
BGP: Allow receiving multicast routes
Diffstat (limited to 'proto/bgp/attrs.c')
-rw-r--r--proto/bgp/attrs.c124
1 files changed, 79 insertions, 45 deletions
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c
index ef5d024..b9a964c 100644
--- a/proto/bgp/attrs.c
+++ b/proto/bgp/attrs.c
@@ -215,22 +215,48 @@ bgp_format_cluster_list(eattr *a, byte *buf, int buflen UNUSED)
}
static int
-bgp_check_reach_nlri(struct bgp_proto *p UNUSED, byte *a UNUSED, int len UNUSED)
+bgp_check_reach_nlri(struct bgp_proto *p, byte *a, int len)
{
-#ifdef IPV6
- p->mp_reach_start = a;
- p->mp_reach_len = len;
-#endif
+ unsigned af, sub;
+
+ if (len < 3)
+ return 5;
+
+ af = get_u16(a);
+ sub = a[2];
+
+ if (af == BGP_AF)
+ {
+ if (sub == BGP_SAF_UNICAST || (sub == BGP_SAF_MULTICAST && p->multicast_session))
+ {
+ p->mp_reach_start = a;
+ p->mp_reach_len = len;
+ }
+ }
+
return -1;
}
static int
-bgp_check_unreach_nlri(struct bgp_proto *p UNUSED, byte *a UNUSED, int len UNUSED)
+bgp_check_unreach_nlri(struct bgp_proto *p, byte *a, int len)
{
-#ifdef IPV6
- p->mp_unreach_start = a;
- p->mp_unreach_len = len;
-#endif
+ unsigned af, sub;
+
+ if (len < 3)
+ return 5;
+
+ af = get_u16(a);
+ sub = a[2];
+
+ if (af == BGP_AF)
+ {
+ if (sub == BGP_SAF_UNICAST || (sub == BGP_SAF_MULTICAST && p->multicast_session))
+ {
+ p->mp_unreach_start = a;
+ p->mp_unreach_len = len;
+ }
+ }
+
return -1;
}
@@ -585,21 +611,21 @@ bgp_normalize_set(u32 *dest, u32 *src, unsigned cnt)
}
static void
-bgp_rehash_buckets(struct bgp_proto *p)
+bgp_rehash_buckets(struct bgp_proto *p, struct bgp_bucket_info *bi)
{
- struct bgp_bucket **old = p->bucket_hash;
+ struct bgp_bucket **old = bi->bucket_hash;
struct bgp_bucket **new;
- unsigned oldn = p->hash_size;
+ unsigned oldn = bi->hash_size;
unsigned i, e, mask;
struct bgp_bucket *b;
- p->hash_size = p->hash_limit;
- DBG("BGP: Rehashing bucket table from %d to %d\n", oldn, p->hash_size);
- p->hash_limit *= 4;
- if (p->hash_limit >= 65536)
- p->hash_limit = ~0;
- new = p->bucket_hash = mb_allocz(p->p.pool, p->hash_size * sizeof(struct bgp_bucket *));
- mask = p->hash_size - 1;
+ bi->hash_size = bi->hash_limit;
+ DBG("BGP: Rehashing bucket table from %d to %d\n", oldn, bi->hash_size);
+ bi->hash_limit *= 4;
+ if (bi->hash_limit >= 65536)
+ bi->hash_limit = ~0;
+ new = bi->bucket_hash = mb_allocz(p->p.pool, bi->hash_size * sizeof(struct bgp_bucket *));
+ mask = bi->hash_size - 1;
for (i=0; i<oldn; i++)
while (b = old[i])
{
@@ -615,7 +641,7 @@ bgp_rehash_buckets(struct bgp_proto *p)
}
static struct bgp_bucket *
-bgp_new_bucket(struct bgp_proto *p, ea_list *new, unsigned hash)
+bgp_new_bucket(struct bgp_proto *p, struct bgp_bucket_info *bi, ea_list *new, unsigned hash)
{
struct bgp_bucket *b;
unsigned ea_size = sizeof(ea_list) + new->count * sizeof(eattr);
@@ -623,7 +649,7 @@ bgp_new_bucket(struct bgp_proto *p, ea_list *new, unsigned hash)
unsigned size = sizeof(struct bgp_bucket) + ea_size;
unsigned i;
byte *dest;
- unsigned index = hash & (p->hash_size - 1);
+ unsigned index = hash & (bi->hash_size - 1);
/* Gather total size of non-inline attributes */
for (i=0; i<new->count; i++)
@@ -635,13 +661,13 @@ bgp_new_bucket(struct bgp_proto *p, ea_list *new, unsigned hash)
/* Create the bucket and hash it */
b = mb_alloc(p->p.pool, size);
- b->hash_next = p->bucket_hash[index];
+ b->hash_next = bi->bucket_hash[index];
if (b->hash_next)
b->hash_next->hash_prev = b;
- p->bucket_hash[index] = b;
+ bi->bucket_hash[index] = b;
b->hash_prev = NULL;
b->hash = hash;
- add_tail(&p->bucket_queue, &b->send_node);
+ add_tail(&bi->bucket_queue, &b->send_node);
init_list(&b->prefixes);
memcpy(b->eattrs, new, ea_size);
dest = ((byte *)b->eattrs) + ea_size_aligned;
@@ -661,15 +687,15 @@ bgp_new_bucket(struct bgp_proto *p, ea_list *new, unsigned hash)
}
/* If needed, rehash */
- p->hash_count++;
- if (p->hash_count > p->hash_limit)
- bgp_rehash_buckets(p);
+ bi->hash_count++;
+ if (bi->hash_count > bi->hash_limit)
+ bgp_rehash_buckets(p, bi);
return b;
}
static struct bgp_bucket *
-bgp_get_bucket(struct bgp_proto *p, net *n, ea_list *attrs, int originate)
+bgp_get_bucket(struct bgp_proto *p, struct bgp_bucket_info *bi, net *n, ea_list *attrs, int originate)
{
ea_list *new;
unsigned i, cnt, hash, code;
@@ -735,7 +761,7 @@ bgp_get_bucket(struct bgp_proto *p, net *n, ea_list *attrs, int originate)
/* Hash */
hash = ea_hash(new);
- for(b=p->bucket_hash[hash & (p->hash_size - 1)]; b; b=b->hash_next)
+ for(b=bi->bucket_hash[hash & (bi->hash_size - 1)]; b; b=b->hash_next)
if (b->hash == hash && ea_same(b->eattrs, new))
{
DBG("Found bucket.\n");
@@ -760,18 +786,18 @@ bgp_get_bucket(struct bgp_proto *p, net *n, ea_list *attrs, int originate)
/* Create new bucket */
DBG("Creating bucket.\n");
- return bgp_new_bucket(p, new, hash);
+ return bgp_new_bucket(p, bi, new, hash);
}
void
-bgp_free_bucket(struct bgp_proto *p, struct bgp_bucket *buck)
+bgp_free_bucket(struct bgp_bucket_info *bi, 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;
+ bi->bucket_hash[buck->hash & (bi->hash_size-1)] = buck->hash_next;
mb_free(buck);
}
@@ -781,24 +807,25 @@ bgp_rt_notify(struct proto *P, rtable *tbl UNUSED, net *n, rte *new, rte *old UN
struct bgp_proto *p = (struct bgp_proto *) P;
struct bgp_bucket *buck;
struct bgp_prefix *px;
+ struct bgp_bucket_info *bi = (n->cast == RTC_MULTICAST) ? &p->multicast_buckets : &p->unicast_buckets;
DBG("BGP: Got route %I/%d %s\n", n->n.prefix, n->n.pxlen, new ? "up" : "down");
if (new)
{
- buck = bgp_get_bucket(p, n, attrs, new->attrs->source != RTS_BGP);
+ buck = bgp_get_bucket(p, bi, n, attrs, new->attrs->source != RTS_BGP);
if (!buck) /* Inconsistent attribute list */
return;
}
else
{
- if (!(buck = p->withdraw_bucket))
+ if (!(buck = bi->withdraw_bucket))
{
- buck = p->withdraw_bucket = mb_alloc(P->pool, sizeof(struct bgp_bucket));
+ buck = bi->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);
+ px = fib_get(&bi->prefix_fib, &n->n.prefix, n->n.pxlen);
if (px->bucket_node.next)
{
DBG("\tRemoving old entry.\n");
@@ -1370,6 +1397,7 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct lin
ea->attrs[0].id = EA_CODE(EAP_BGP, code);
ea->attrs[0].flags = flags;
ea->attrs[0].type = type;
+
if (type & EAF_EMBEDDED)
ad = NULL;
else
@@ -1399,13 +1427,12 @@ bgp_decode_attrs(struct bgp_conn *conn, byte *attr, unsigned int len, struct lin
break;
}
}
+
}
-#ifdef IPV6
/* If we received MP_REACH_NLRI we should check mandatory attributes */
if (bgp->mp_reach_len != 0)
mandatory = 1;
-#endif
/* If there is no (reachability) NLRI, we should exit now */
if (! mandatory)
@@ -1481,15 +1508,22 @@ bgp_get_attr(eattr *a, byte *buf, int buflen)
return GA_NAME;
}
+static void
+bgp_attr_init_buckets(struct bgp_proto *p, struct bgp_bucket_info *bi)
+{
+ bi->hash_size = 256;
+ bi->hash_limit = bi->hash_size * 4;
+ bi->bucket_hash = mb_allocz(p->p.pool, bi->hash_size * sizeof(struct bgp_bucket *));
+ init_list(&bi->bucket_queue);
+ bi->withdraw_bucket = NULL;
+ fib_init(&bi->prefix_fib, p->p.pool, sizeof(struct bgp_prefix), 0, bgp_init_prefix);
+}
+
void
bgp_attr_init(struct bgp_proto *p)
{
- p->hash_size = 256;
- p->hash_limit = p->hash_size * 4;
- p->bucket_hash = mb_allocz(p->p.pool, p->hash_size * sizeof(struct bgp_bucket *));
- init_list(&p->bucket_queue);
- p->withdraw_bucket = NULL;
- fib_init(&p->prefix_fib, p->p.pool, sizeof(struct bgp_prefix), 0, bgp_init_prefix);
+ bgp_attr_init_buckets(p, &p->unicast_buckets);
+ bgp_attr_init_buckets(p, &p->multicast_buckets);
}
void