From 5b885bf70848908c7fed07c8efba18ea316379d4 Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Tue, 16 Nov 2010 03:47:07 +0100 Subject: BGP: Allow receiving multicast routes --- proto/bgp/attrs.c | 124 ++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 79 insertions(+), 45 deletions(-) (limited to 'proto/bgp/attrs.c') 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; icount * 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; icount; 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 -- cgit v1.2.3