summaryrefslogtreecommitdiffstats
path: root/proto/bgp/packets.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/packets.c
parente6eee664723aa0e1d87eac65216cdf12636e3284 (diff)
downloadbird-5b885bf70848908c7fed07c8efba18ea316379d4.tar
bird-5b885bf70848908c7fed07c8efba18ea316379d4.zip
BGP: Allow receiving multicast routes
Diffstat (limited to 'proto/bgp/packets.c')
-rw-r--r--proto/bgp/packets.c72
1 files changed, 45 insertions, 27 deletions
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index 1a1e7b7..8e657cc 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -6,7 +6,7 @@
* Can be freely distributed and used under the terms of the GNU GPL.
*/
-#undef LOCAL_DEBUG
+#define LOCAL_DEBUG
#include "nest/bird.h"
#include "nest/iface.h"
@@ -228,7 +228,7 @@ bgp_create_open(struct bgp_conn *conn, byte *buf)
}
static unsigned int
-bgp_encode_prefixes(struct bgp_proto *p, byte *w, struct bgp_bucket *buck, unsigned int remains)
+bgp_encode_prefixes(struct bgp_bucket_info *bi, byte *w, struct bgp_bucket *buck, unsigned int remains)
{
byte *start = w;
ip_addr a;
@@ -246,20 +246,20 @@ bgp_encode_prefixes(struct bgp_proto *p, byte *w, struct bgp_bucket *buck, unsig
w += bytes;
remains -= bytes + 1;
rem_node(&px->bucket_node);
- fib_delete(&p->prefix_fib, px);
+ fib_delete(&bi->prefix_fib, px);
}
return w - start;
}
static void
-bgp_flush_prefixes(struct bgp_proto *p, struct bgp_bucket *buck)
+bgp_flush_prefixes(struct bgp_proto *p, struct bgp_bucket_info *bi, struct bgp_bucket *buck)
{
while (!EMPTY_LIST(buck->prefixes))
{
struct bgp_prefix *px = SKIP_BACK(struct bgp_prefix, bucket_node, HEAD(buck->prefixes));
log(L_ERR "%s: - route %I/%d skipped", p->p.name, px->n.prefix, px->n.pxlen);
rem_node(&px->bucket_node);
- fib_delete(&p->prefix_fib, px);
+ fib_delete(&bi->prefix_fib, px);
}
}
@@ -269,6 +269,7 @@ static byte *
bgp_create_update(struct bgp_conn *conn, byte *buf)
{
struct bgp_proto *p = conn->bgp;
+ struct bgp_bucket_info *bi = &p->unicast_buckets;
struct bgp_bucket *buck;
int remains = BGP_MAX_PACKET_LENGTH - BGP_HEADER_LENGTH - 4;
byte *w;
@@ -277,10 +278,10 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
int a_size = 0;
w = buf+2;
- if ((buck = p->withdraw_bucket) && !EMPTY_LIST(buck->prefixes))
+ if ((buck = bi->withdraw_bucket) && !EMPTY_LIST(buck->prefixes))
{
DBG("Withdrawn routes:\n");
- wd_size = bgp_encode_prefixes(p, w, buck, remains);
+ wd_size = bgp_encode_prefixes(bi, w, buck, remains);
w += wd_size;
remains -= wd_size;
}
@@ -288,13 +289,13 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
if (remains >= 3072)
{
- while ((buck = (struct bgp_bucket *) HEAD(p->bucket_queue))->send_node.next)
+ while ((buck = (struct bgp_bucket *) HEAD(bi->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(p, buck);
+ bgp_free_bucket(bi, buck);
continue;
}
@@ -304,15 +305,15 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
if (a_size < 0)
{
log(L_ERR "%s: Attribute list too long, skipping corresponding routes", p->p.name);
- bgp_flush_prefixes(p, buck);
+ bgp_flush_prefixes(p, bi, buck);
rem_node(&buck->send_node);
- bgp_free_bucket(p, buck);
+ bgp_free_bucket(bi, buck);
continue;
}
put_u16(w, a_size);
w += a_size + 2;
- r_size = bgp_encode_prefixes(p, w, buck, remains - a_size);
+ r_size = bgp_encode_prefixes(bi, w, buck, remains - a_size);
w += r_size;
break;
}
@@ -337,6 +338,7 @@ static byte *
bgp_create_update(struct bgp_conn *conn, byte *buf)
{
struct bgp_proto *p = conn->bgp;
+ struct bgp_bucket_info *bi = &p->unicast_buckets;
struct bgp_bucket *buck;
int size, second, rem_stored;
int remains = BGP_MAX_PACKET_LENGTH - BGP_HEADER_LENGTH - 4;
@@ -349,14 +351,14 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
put_u16(buf, 0);
w = buf+4;
- if ((buck = p->withdraw_bucket) && !EMPTY_LIST(buck->prefixes))
+ if ((buck = bi->withdraw_bucket) && !EMPTY_LIST(buck->prefixes))
{
DBG("Withdrawn routes:\n");
tmp = bgp_attach_attr_wa(&ea, bgp_linpool, BA_MP_UNREACH_NLRI, remains-8);
*tmp++ = 0;
*tmp++ = BGP_AF_IPV6;
- *tmp++ = 1;
- ea->attrs[0].u.ptr->length = 3 + bgp_encode_prefixes(p, tmp, buck, remains-11);
+ *tmp++ = BGP_SAF_UNICAST;
+ ea->attrs[0].u.ptr->length = 3 + bgp_encode_prefixes(bi, tmp, buck, remains-11);
size = bgp_encode_attrs(p, w, ea, remains);
ASSERT(size >= 0);
w += size;
@@ -365,13 +367,13 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
if (remains >= 3072)
{
- while ((buck = (struct bgp_bucket *) HEAD(p->bucket_queue))->send_node.next)
+ while ((buck = (struct bgp_bucket *) HEAD(bi->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(p, buck);
+ bgp_free_bucket(bi, buck);
continue;
}
@@ -383,9 +385,9 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
if (size < 0)
{
log(L_ERR "%s: Attribute list too long, skipping corresponding routes", p->p.name);
- bgp_flush_prefixes(p, buck);
+ bgp_flush_prefixes(p, bi, buck);
rem_node(&buck->send_node);
- bgp_free_bucket(p, buck);
+ bgp_free_bucket(bi, buck);
continue;
}
w += size;
@@ -433,9 +435,9 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
log(L_ERR "%s: Missing link-local next hop address, skipping corresponding routes", p->p.name);
w = w_stored;
remains = rem_stored;
- bgp_flush_prefixes(p, buck);
+ bgp_flush_prefixes(p, bi, buck);
rem_node(&buck->send_node);
- bgp_free_bucket(p, buck);
+ bgp_free_bucket(bi, buck);
continue;
case MLL_IGNORE:
break;
@@ -467,7 +469,7 @@ bgp_create_update(struct bgp_conn *conn, byte *buf)
}
*tmp++ = 0; /* No SNPA information */
- tmp += bgp_encode_prefixes(p, tmp, buck, remains - (8+3+32+1));
+ tmp += bgp_encode_prefixes(bi, tmp, buck, remains - (8+3+32+1));
ea->attrs[0].u.ptr->length = tmp - tstart;
size = bgp_encode_attrs(p, w, ea, remains);
ASSERT(size >= 0);
@@ -804,6 +806,7 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, int len)
conn->keepalive_time = p->cf->keepalive_time ? : conn->hold_time / 3;
p->remote_id = id;
p->as4_session = conn->want_as4_support && conn->peer_as4_support;
+ p->multicast_session = conn->want_multicast_support && conn->peer_multicast_support;
DBG("BGP: Hold timer set to %d, keepalive to %d, AS to %d, ID to %x, AS4 session to %d\n", conn->hold_time, conn->keepalive_time, p->remote_as, p->remote_id, p->as4_session);
@@ -930,7 +933,7 @@ bgp_do_rx_update(struct bgp_conn *conn,
} \
else \
af = 0; \
- if (af == BGP_AF_IPV6)
+ if (af == BGP_AF)
static void
bgp_do_rx_update(struct bgp_conn *conn,
@@ -947,6 +950,7 @@ bgp_do_rx_update(struct bgp_conn *conn,
ip_addr prefix;
net *n;
int err = 0, pxlen;
+ int multicast;
p->mp_reach_len = 0;
p->mp_unreach_len = 0;
@@ -956,17 +960,30 @@ bgp_do_rx_update(struct bgp_conn *conn,
DO_NLRI(mp_unreach)
{
+ multicast = (sub == BGP_SAF_MULTICAST);
+
+ if (multicast)
+ ASSERT(p->multicast_session);
+
while (len)
{
DECODE_PREFIX(x, len);
- DBG("Withdraw %I/%d\n", prefix, pxlen);
- if (n = net_find(p->p.table, prefix, pxlen))
+ DBG("Withdraw %I/%d%s\n", prefix, pxlen, multicast ? " MC" : "");
+ if (n = net_find_cast(p->p.table, prefix, pxlen, multicast ? RTC_MULTICAST : RTC_UNICAST))
rte_update(p->p.table, n, &p->p, &p->p, NULL);
}
}
DO_NLRI(mp_reach)
{
+ multicast = (sub == BGP_SAF_MULTICAST);
+
+ if (multicast)
+ {
+ ASSERT(p->multicast_session);
+ a0->cast = RTC_MULTICAST;
+ }
+
/* Create fake NEXT_HOP attribute */
if (len < 1 || (*x != 16 && *x != 32) || len < *x + 2)
goto bad;
@@ -991,13 +1008,14 @@ bgp_do_rx_update(struct bgp_conn *conn,
if (bgp_set_next_hop(p, a0))
{
a = rta_lookup(a0);
+
while (len)
{
rte *e;
DECODE_PREFIX(x, len);
- DBG("Add %I/%d\n", prefix, pxlen);
+ DBG("Add %I/%d%s\n", prefix, pxlen, multicast ? " MC" : "");
e = rte_get_temp(rta_clone(a));
- n = net_get(p->p.table, prefix, pxlen);
+ n = net_get_cast(p->p.table, prefix, pxlen, multicast ? RTC_MULTICAST : RTC_UNICAST);
e->net = n;
e->pflags = 0;
rte_update(p->p.table, n, &p->p, &p->p, e);