summaryrefslogtreecommitdiff
path: root/proto/bgp
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2010-01-27 17:22:57 +0100
committerOndrej Zajicek <santiago@crfreenet.org>2010-01-27 17:22:57 +0100
commit6cb8f742f1adf99881334b8ae21c398d98571aa1 (patch)
tree3e20c14d7e25002cae145ac3bdb172cb2d3eac77 /proto/bgp
parenta3062085827db3115961eacd9d945ac202728174 (diff)
Better handling of well-known communities.
Process well-known communities before the export filter (old behavior is to process these attributes after, which does not allow to send route with such community) and just for routes received from other BGP protocols. Also fixes a bug in next_hop check.
Diffstat (limited to 'proto/bgp')
-rw-r--r--proto/bgp/attrs.c82
-rw-r--r--proto/bgp/bgp.h1
-rw-r--r--proto/bgp/config.Y3
3 files changed, 44 insertions, 42 deletions
diff --git a/proto/bgp/attrs.c b/proto/bgp/attrs.c
index 5316481d..9bf6fd50 100644
--- a/proto/bgp/attrs.c
+++ b/proto/bgp/attrs.c
@@ -664,44 +664,8 @@ bgp_new_bucket(struct bgp_proto *p, ea_list *new, unsigned hash)
return b;
}
-static int
-bgp_export_check(struct bgp_proto *p, ea_list *new)
-{
- eattr *a;
- struct adata *d;
-
- /* Check if next hop is valid */
- a = ea_find(new, EA_CODE(EAP_BGP, BA_NEXT_HOP));
- if (!a || ipa_equal(p->next_hop, *(ip_addr *)a->u.ptr))
- {
- DBG("\tInvalid NEXT_HOP\n");
- return 0;
- }
-
- /* Check if we aren't forbidden to export the route by communities */
- a = ea_find(new, EA_CODE(EAP_BGP, BA_COMMUNITY));
- if (a)
- {
- d = a->u.ptr;
- if (int_set_contains(d, BGP_COMM_NO_ADVERTISE))
- {
- DBG("\tNO_ADVERTISE\n");
- return 0;
- }
- if (!p->is_internal &&
- (int_set_contains(d, BGP_COMM_NO_EXPORT) ||
- int_set_contains(d, BGP_COMM_NO_EXPORT_SUBCONFED)))
- {
- DBG("\tNO_EXPORT\n");
- return 0;
- }
- }
-
- return 1;
-}
-
static struct bgp_bucket *
-bgp_get_bucket(struct bgp_proto *p, ea_list *attrs, int originate)
+bgp_get_bucket(struct bgp_proto *p, net *n, ea_list *attrs, int originate)
{
ea_list *new;
unsigned i, cnt, hash, code;
@@ -778,12 +742,17 @@ bgp_get_bucket(struct bgp_proto *p, ea_list *attrs, int originate)
for(i=0; i<ARRAY_SIZE(bgp_mandatory_attrs); i++)
if (!(seen & (1 << bgp_mandatory_attrs[i])))
{
- log(L_ERR "%s: Mandatory attribute %s missing", p->p.name, bgp_attr_table[bgp_mandatory_attrs[i]].name);
+ log(L_ERR "%s: Mandatory attribute %s missing in route %I/%d", p->p.name, bgp_attr_table[bgp_mandatory_attrs[i]].name, n->n.prefix, n->n.pxlen);
return NULL;
}
- if (!bgp_export_check(p, new))
- return NULL;
+ /* Check if next hop is valid */
+ a = ea_find(new, EA_CODE(EAP_BGP, BA_NEXT_HOP));
+ if (!a || ipa_equal(p->next_hop, *(ip_addr *)a->u.ptr->data))
+ {
+ log(L_ERR "%s: Invalid NEXT_HOP attribute in route %I/%d", p->p.name, n->n.prefix, n->n.pxlen);
+ return NULL;
+ }
/* Create new bucket */
DBG("Creating bucket.\n");
@@ -813,7 +782,7 @@ bgp_rt_notify(struct proto *P, net *n, rte *new, rte *old UNUSED, ea_list *attrs
if (new)
{
- buck = bgp_get_bucket(p, attrs, new->attrs->source != RTS_BGP);
+ buck = bgp_get_bucket(p, n, attrs, new->attrs->source != RTS_BGP);
if (!buck) /* Inconsistent attribute list */
return;
}
@@ -963,6 +932,34 @@ bgp_update_attrs(struct bgp_proto *p, rte *e, ea_list **attrs, struct linpool *p
return 0; /* Leave decision to the filters */
}
+static int
+bgp_community_filter(struct bgp_proto *p, rte *e)
+{
+ eattr *a;
+ struct adata *d;
+
+ /* Check if we aren't forbidden to export the route by communities */
+ a = ea_find(e->attrs->eattrs, EA_CODE(EAP_BGP, BA_COMMUNITY));
+ if (a)
+ {
+ d = a->u.ptr;
+ if (int_set_contains(d, BGP_COMM_NO_ADVERTISE))
+ {
+ DBG("\tNO_ADVERTISE\n");
+ return 1;
+ }
+ if (!p->is_internal &&
+ (int_set_contains(d, BGP_COMM_NO_EXPORT) ||
+ int_set_contains(d, BGP_COMM_NO_EXPORT_SUBCONFED)))
+ {
+ DBG("\tNO_EXPORT\n");
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
int
bgp_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *pool)
{
@@ -979,6 +976,9 @@ bgp_import_control(struct proto *P, rte **new, ea_list **attrs, struct linpool *
if (bgp_cluster_list_loopy(p, e->attrs))
return -1;
+ if (!p->cf->ignore_communities && bgp_community_filter(p, e))
+ return -1;
+
if (p->local_as == new_bgp->local_as && p->is_internal && new_bgp->is_internal)
{
/* Redistribution of internal routes with IBGP */
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index 24d69741..9966d20b 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -37,6 +37,7 @@ struct bgp_config {
int advertise_ipv4; /* Whether we should add IPv4 capability advertisement to OPEN message */
u32 route_limit; /* Number of routes that may be imported, 0 means disable limit */
int passive; /* Do not initiate outgoing connection */
+ int ignore_communities; /* Skip hardwired handling of well-known communities */
unsigned connect_retry_time;
unsigned hold_time, initial_hold_time;
unsigned keepalive_time;
diff --git a/proto/bgp/config.Y b/proto/bgp/config.Y
index b2061a18..cf32cd16 100644
--- a/proto/bgp/config.Y
+++ b/proto/bgp/config.Y
@@ -23,7 +23,7 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE,
BGP_ATOMIC_AGGR, BGP_AGGREGATOR, BGP_COMMUNITY, SOURCE, ADDRESS,
PASSWORD, RR, RS, CLIENT, CLUSTER, ID, AS4, ADVERTISE, IPV4,
CAPABILITIES, LIMIT, PASSIVE, PREFER, OLDER, MISSING, LLADDR,
- DROP, IGNORE, ROUTE, REFRESH)
+ DROP, IGNORE, ROUTE, REFRESH, COMMUNITIES)
CF_GRAMMAR
@@ -86,6 +86,7 @@ bgp_proto:
| bgp_proto PASSWORD TEXT ';' { BGP_CFG->password = $3; }
| bgp_proto ROUTE LIMIT expr ';' { BGP_CFG->route_limit = $4; }
| bgp_proto PASSIVE bool ';' { BGP_CFG->passive = $3; }
+ | bgp_proto IGNORE COMMUNITIES bool ';' { BGP_CFG->ignore_communities = $4; }
;
CF_ADDTO(dynamic_attr, BGP_PATH