summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2004-05-21 15:36:41 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2004-05-21 15:36:41 +0000
commit66ad79cdaaf232c69e2c23b334663335e31c41b9 (patch)
treea6de6ef4f185bb33d75dc21e42f684238002cd31
parent7ab3008b01a67c9f78cd18812453911c9fd48581 (diff)
RFC 2796 bgp route reflector support. This is very useful in conjunction
with templates. looks good, go for it henning@
-rw-r--r--usr.sbin/bgpd/bgpd.conf.55
-rw-r--r--usr.sbin/bgpd/bgpd.h5
-rw-r--r--usr.sbin/bgpd/config.c11
-rw-r--r--usr.sbin/bgpd/parse.y31
-rw-r--r--usr.sbin/bgpd/rde.c141
-rw-r--r--usr.sbin/bgpd/rde.h8
-rw-r--r--usr.sbin/bgpd/rde_attr.c38
-rw-r--r--usr.sbin/bgpd/rde_update.c98
8 files changed, 260 insertions, 77 deletions
diff --git a/usr.sbin/bgpd/bgpd.conf.5 b/usr.sbin/bgpd/bgpd.conf.5
index 51ffdc06084..ea43798b163 100644
--- a/usr.sbin/bgpd/bgpd.conf.5
+++ b/usr.sbin/bgpd/bgpd.conf.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: bgpd.conf.5,v 1.25 2004/05/17 12:39:32 djm Exp $
+.\" $OpenBSD: bgpd.conf.5,v 1.26 2004/05/21 15:36:40 claudio Exp $
.\"
.\" Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
.\" Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -356,6 +356,9 @@ statement defines the maximum hops the neighbor may be away.
Do not attempt to actively open a TCP connection to the neighbor system.
.It Ar remote-as
Set the AS number of the remote system.
+.It Ar route-reflector
+Act as a RFC 2796 route-reflector for this neighbor.
+An optional cluster id can be specified else the own bgp id will be used.
.It Ar set
Set the
.Em AS path attributes
diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h
index ba5d5efac8f..9ddd92d22c8 100644
--- a/usr.sbin/bgpd/bgpd.h
+++ b/usr.sbin/bgpd/bgpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bgpd.h,v 1.124 2004/05/21 11:48:56 claudio Exp $ */
+/* $OpenBSD: bgpd.h,v 1.125 2004/05/21 15:36:40 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -50,6 +50,7 @@
#define BGPD_FLAG_NO_FIB_UPDATE 0x0001
#define BGPD_FLAG_NO_EVALUATE 0x0002
+#define BGPD_FLAG_REFLECTOR 0x0004
#define BGPD_LOG_UPDATES 0x0001
@@ -111,6 +112,7 @@ struct bgpd_config {
int opts;
u_int16_t as;
u_int32_t bgpid;
+ u_int32_t clusterid;
u_int16_t holdtime;
u_int16_t min_holdtime;
int flags;
@@ -203,6 +205,7 @@ struct peer_config {
enum enforce_as enforce_as;
struct peer_auth auth;
u_int8_t capabilities;
+ u_int8_t reflector_client;
enum reconf_action reconf_action;
};
diff --git a/usr.sbin/bgpd/config.c b/usr.sbin/bgpd/config.c
index 87be1d23878..56f801ca75f 100644
--- a/usr.sbin/bgpd/config.c
+++ b/usr.sbin/bgpd/config.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: config.c,v 1.36 2004/05/04 21:22:39 deraadt Exp $ */
+/* $OpenBSD: config.c,v 1.37 2004/05/21 15:36:40 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -56,6 +56,9 @@ merge_config(struct bgpd_config *xconf, struct bgpd_config *conf,
if (!conf->bgpid)
conf->bgpid = get_bgpid();
+ if ((conf->flags & BGPD_FLAG_REFLECTOR) && conf->clusterid == 0)
+ conf->clusterid = conf->bgpid;
+
for (p = peer_l; p != NULL; p = p->next) {
p->conf.ebgp = (p->conf.remote_as != conf->as);
if (p->conf.announce_type == ANNOUNCE_UNDEF)
@@ -64,6 +67,12 @@ merge_config(struct bgpd_config *xconf, struct bgpd_config *conf,
if (p->conf.enforce_as == ENFORCE_AS_UNDEF)
p->conf.enforce_as = p->conf.ebgp == 0 ?
ENFORCE_AS_OFF : ENFORCE_AS_ON;
+ if (p->conf.reflector_client && p->conf.ebgp) {
+ log_peer_warnx(&p->conf, "configuration error: "
+ "EBGP neighbors are not allowed in route "
+ "reflector clusters");
+ return (1);
+ }
}
memcpy(xconf, conf, sizeof(struct bgpd_config));
diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y
index 92f73b5ff0a..6e645c94512 100644
--- a/usr.sbin/bgpd/parse.y
+++ b/usr.sbin/bgpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.111 2004/05/17 12:39:32 djm Exp $ */
+/* $OpenBSD: parse.y,v 1.112 2004/05/21 15:36:40 claudio Exp $ */
/*
* Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -113,7 +113,7 @@ typedef struct {
%token AS ROUTERID HOLDTIME YMIN LISTEN ON FIBUPDATE
%token GROUP NEIGHBOR NETWORK
%token REMOTEAS DESCR LOCALADDR MULTIHOP PASSIVE MAXPREFIX ANNOUNCE
-%token ENFORCE NEIGHBORAS CAPABILITIES
+%token ENFORCE NEIGHBORAS CAPABILITIES REFLECTOR
%token DUMP TABLE IN OUT
%token LOG ROUTECOLL
%token TCP MD5SIG PASSWORD KEY
@@ -646,6 +646,32 @@ peeropts : REMOTEAS asnumber {
sizeof(curpeer->conf.attrset));
}
| mrtdump
+ | REFLECTOR {
+ if ((conf->flags & BGPD_FLAG_REFLECTOR) &&
+ conf->clusterid != 0) {
+ yyerror("only one route reflector "
+ "cluster allowed");
+ YYERROR;
+ }
+ conf->flags |= BGPD_FLAG_REFLECTOR;
+ curpeer->conf.reflector_client = 1;
+ }
+ | REFLECTOR address {
+ if ($2.af != AF_INET) {
+ yyerror("route reflector cluster-id must be "
+ "an IPv4 address");
+ YYERROR;
+ }
+ if ((conf->flags & BGPD_FLAG_REFLECTOR) &&
+ conf->clusterid != $2.v4.s_addr) {
+ yyerror("only one route reflector "
+ "cluster allowed");
+ YYERROR;
+ }
+ conf->flags |= BGPD_FLAG_REFLECTOR;
+ curpeer->conf.reflector_client = 1;
+ conf->clusterid = $2.v4.s_addr;
+ }
;
espah : ESP { $$ = 1; }
@@ -1028,6 +1054,7 @@ lookup(char *s)
{ "quick", QUICK},
{ "remote-as", REMOTEAS},
{ "route-collector", ROUTECOLL},
+ { "route-reflector", REFLECTOR},
{ "router-id", ROUTERID},
{ "set", SET},
{ "source-AS", SOURCEAS},
diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c
index def3f552e00..87f3c8f6fae 100644
--- a/usr.sbin/bgpd/rde.c
+++ b/usr.sbin/bgpd/rde.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.c,v 1.114 2004/05/21 12:10:22 claudio Exp $ */
+/* $OpenBSD: rde.c,v 1.115 2004/05/21 15:36:40 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -45,15 +45,16 @@ int rde_update_get_prefix(u_char *, u_int16_t, struct bgpd_addr *,
u_int8_t *);
void rde_update_err(struct rde_peer *, u_int8_t , u_int8_t,
void *, u_int16_t);
+void rde_update_log(const char *,
+ const struct rde_peer *, const struct attr_flags *,
+ const struct bgpd_addr *, u_int8_t);
+int rde_reflector(struct rde_peer *, struct attr_flags *);
void rde_dump_rib_as(struct prefix *, pid_t);
void rde_dump_rib_prefix(struct prefix *, pid_t);
void rde_dump_upcall(struct pt_entry *, void *);
void rde_dump_as(struct as_filter *, pid_t);
void rde_dump_prefix_upcall(struct pt_entry *, void *);
void rde_dump_prefix(struct ctl_show_rib_prefix *, pid_t);
-void rde_update_log(const char *,
- const struct rde_peer *, const struct attr_flags *,
- const struct bgpd_addr *, u_int8_t);
void rde_update_queue_runner(void);
void peer_init(u_int32_t);
@@ -437,13 +438,57 @@ rde_update_dispatch(struct imsg *imsg)
p = imsg->data;
memcpy(&len, p, 2);
- withdrawn_len = len = ntohs(len);
+ withdrawn_len = ntohs(len);
p += 2;
if (imsg->hdr.len < IMSG_HEADER_SIZE + 2 + withdrawn_len + 2) {
rde_update_err(peer, ERR_UPDATE, ERR_UPD_ATTRLIST, NULL, 0);
return (-1);
}
+ p += withdrawn_len;
+ memcpy(&len, p, 2);
+ attrpath_len = len = ntohs(len);
+ p += 2;
+ if (imsg->hdr.len <
+ IMSG_HEADER_SIZE + 2 + withdrawn_len + 2 + attrpath_len) {
+ rde_update_err(peer, ERR_UPDATE, ERR_UPD_ATTRLIST, NULL, 0);
+ return (-1);
+ }
+ if (attrpath_len != 0) { /* 0 = no NLRI information in this message */
+ /* parse path attributes */
+ attr_init(&attrs);
+ while (len > 0) {
+ if ((pos = attr_parse(p, len, &attrs,
+ peer->conf.ebgp, peer->conf.enforce_as,
+ peer->conf.remote_as)) < 0) {
+ emsg = attr_error(p, len, &attrs,
+ &subtype, &size);
+ rde_update_err(peer, ERR_UPDATE, subtype,
+ emsg, size);
+ attr_free(&attrs);
+ return (-1);
+ }
+ p += pos;
+ len -= pos;
+ }
+
+ /* check for missing but necessary attributes */
+ if ((subtype = attr_missing(&attrs, peer->conf.ebgp)) != 0) {
+ rde_update_err(peer, ERR_UPDATE, ERR_UPD_MISSNG_WK_ATTR,
+ &subtype, sizeof(u_int8_t));
+ attr_free(&attrs);
+ return (-1);
+ }
+
+ if (rde_reflector(peer, &attrs) != 1) {
+ attr_free(&attrs);
+ return (0);
+ }
+ }
+
+ p = imsg->data;
+ len = withdrawn_len;
+ p += 2;
/* withdraw prefix */
while (len > 0) {
if ((pos = rde_update_get_prefix(p, len, &prefix,
@@ -455,12 +500,16 @@ rde_update_dispatch(struct imsg *imsg)
log_peer_warnx(&peer->conf, "bad withdraw prefix");
rde_update_err(peer, ERR_UPDATE, ERR_UPD_NETWORK,
NULL, 0);
+ if (attrpath_len != 0)
+ attr_free(&attrs);
return (-1);
}
if (prefixlen > 32) {
log_peer_warnx(&peer->conf, "bad withdraw prefix");
rde_update_err(peer, ERR_UPDATE, ERR_UPD_NETWORK,
NULL, 0);
+ if (attrpath_len != 0)
+ attr_free(&attrs);
return (-1);
}
@@ -476,41 +525,14 @@ rde_update_dispatch(struct imsg *imsg)
prefix_remove(peer, &prefix, prefixlen);
}
- memcpy(&len, p, 2);
- attrpath_len = ntohs(len);
- p += 2;
- if (imsg->hdr.len <
- IMSG_HEADER_SIZE + 2 + withdrawn_len + 2 + attrpath_len) {
- rde_update_err(peer, ERR_UPDATE, ERR_UPD_ATTRLIST, NULL, 0);
- return (-1);
- }
- nlri_len =
- imsg->hdr.len - IMSG_HEADER_SIZE - 4 - withdrawn_len - attrpath_len;
if (attrpath_len == 0) /* 0 = no NLRI information in this message */
return (0);
- /* parse path attributes */
- attr_init(&attrs);
- while (attrpath_len > 0) {
- if ((pos = attr_parse(p, attrpath_len, &attrs, peer->conf.ebgp,
- peer->conf.enforce_as, peer->conf.remote_as)) < 0) {
- emsg = attr_error(p, attrpath_len, &attrs,
- &subtype, &size);
- rde_update_err(peer, ERR_UPDATE, subtype, emsg, size);
- attr_free(&attrs);
- return (-1);
- }
- p += pos;
- attrpath_len -= pos;
- }
+ /* shift to NLRI information */
+ p += 2 + attrpath_len;
+ nlri_len =
+ imsg->hdr.len - IMSG_HEADER_SIZE - 4 - withdrawn_len - attrpath_len;
- /* check for missing but necessary attributes */
- if ((subtype = attr_missing(&attrs, peer->conf.ebgp)) != 0) {
- rde_update_err(peer, ERR_UPDATE, ERR_UPD_MISSNG_WK_ATTR,
- &subtype, sizeof(u_int8_t));
- attr_free(&attrs);
- return (-1);
- }
/* aspath needs to be loop free nota bene this is not a hard error */
if (peer->conf.ebgp && !aspath_loopfree(attrs.aspath, conf->as)) {
@@ -518,8 +540,7 @@ rde_update_dispatch(struct imsg *imsg)
aspath_asprint(&s, attrs.aspath->data, attrs.aspath->hdr.len);
log_peer_warnx(&peer->conf, "AS path loop: %s", s);
free(s);
- aspath_destroy(attrs.aspath);
- attr_optfree(&attrs);
+ attr_free(&attrs);
return (0);
}
@@ -654,6 +675,50 @@ rde_update_log(const char *message,
free(nexthop);
}
+int
+rde_reflector(struct rde_peer *peer, struct attr_flags *attrs)
+{
+ struct attr *a;
+ u_int16_t len;
+
+ /* check for originator id if eq router_id drop */
+ if ((a = attr_optget(attrs, ATTR_ORIGINATOR_ID)) != NULL) {
+ ENSURE(a->len == 4);
+ if (memcmp(&conf->bgpid, a->data, sizeof(conf->bgpid)) == 0)
+ /* this is comming from myself */
+ return (0);
+ } else if ((conf->flags & BGPD_FLAG_REFLECTOR) &&
+ attr_optadd(attrs, ATTR_OPTIONAL, ATTR_ORIGINATOR_ID,
+ peer->conf.ebgp == 0 ? &peer->remote_bgpid : &conf->bgpid,
+ sizeof(u_int32_t)) == -1)
+ fatalx("attr_optadd failed but impossible");
+
+ /* check for own id in the cluster list */
+ if (conf->flags & BGPD_FLAG_REFLECTOR) {
+ if ((a = attr_optget(attrs, ATTR_CLUSTER_LIST)) != NULL) {
+ for (len = 0; len < a->len;
+ len += sizeof(conf->clusterid))
+ /* check if comming from my cluster */
+ if (memcmp(&conf->clusterid, a->data + len,
+ sizeof(conf->clusterid)) == 0)
+ return (0);
+
+ /* prepend own clusterid */
+ if ((a->data = realloc(a->data, a->len +
+ sizeof(conf->clusterid))) == NULL)
+ fatal("rde_reflector");
+ memmove(a->data + sizeof(conf->clusterid),
+ a->data, a->len);
+ a->len += sizeof(conf->clusterid);
+ memcpy(a->data, &conf->clusterid,
+ sizeof(conf->clusterid));
+ } else if (attr_optadd(attrs, ATTR_OPTIONAL, ATTR_CLUSTER_LIST,
+ &conf->clusterid, sizeof(conf->clusterid)) == -1)
+ fatalx("attr_optadd failed but impossible");
+ }
+ return (1);
+}
+
/*
* control specific functions
*/
diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h
index 6b37632841e..5b3a519c31d 100644
--- a/usr.sbin/bgpd/rde.h
+++ b/usr.sbin/bgpd/rde.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.h,v 1.39 2004/05/17 12:39:32 djm Exp $ */
+/* $OpenBSD: rde.h,v 1.40 2004/05/21 15:36:40 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
@@ -97,7 +97,9 @@ enum attrtypes {
ATTR_LOCALPREF,
ATTR_ATOMIC_AGGREGATE,
ATTR_AGGREGATOR,
- ATTR_COMMUNITIES
+ ATTR_COMMUNITIES,
+ ATTR_ORIGINATOR_ID,
+ ATTR_CLUSTER_LIST
};
/* attribute flags. 4 low order bits reserved */
@@ -227,7 +229,7 @@ void attr_free(struct attr_flags *);
int attr_write(void *, u_int16_t, u_int8_t, u_int8_t, void *,
u_int16_t);
int attr_optadd(struct attr_flags *, u_int8_t, u_int8_t,
- u_char *, u_int16_t);
+ void *, u_int16_t);
struct attr *attr_optget(struct attr_flags *, u_int8_t);
void attr_optfree(struct attr_flags *);
diff --git a/usr.sbin/bgpd/rde_attr.c b/usr.sbin/bgpd/rde_attr.c
index 772aa5bd2f3..511032b7a83 100644
--- a/usr.sbin/bgpd/rde_attr.c
+++ b/usr.sbin/bgpd/rde_attr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_attr.c,v 1.30 2004/05/17 12:39:32 djm Exp $ */
+/* $OpenBSD: rde_attr.c,v 1.31 2004/05/21 15:36:40 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -176,6 +176,18 @@ attr_parse(u_char *p, u_int16_t len, struct attr_flags *a, int ebgp,
ATTR_PARTIAL))
return (-1);
goto optattr;
+ case ATTR_ORIGINATOR_ID:
+ if (attr_len != 4)
+ return (-1);
+ if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, ATTR_PARTIAL))
+ return (-1);
+ goto optattr;
+ case ATTR_CLUSTER_LIST:
+ if ((attr_len & 0x3) != 0)
+ return (-1);
+ if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, ATTR_PARTIAL))
+ return (-1);
+ goto optattr;
default:
optattr:
if (attr_optadd(a, flags, type, p, attr_len) == -1)
@@ -295,8 +307,17 @@ attr_error(u_char *p, u_int16_t len, struct attr_flags *attr,
case ATTR_COMMUNITIES:
if ((attr_len & 0x3) != 0)
return (p);
- /* FALLTHROUGH */
+ goto optattr;
+ case ATTR_ORIGINATOR_ID:
+ if (attr_len != 4)
+ return (p);
+ goto optattr;
+ case ATTR_CLUSTER_LIST:
+ if ((attr_len & 0x3) != 0)
+ return (p);
+ goto optattr;
default:
+optattr:
if ((flags & ATTR_OPTIONAL) == 0) {
*suberr = ERR_UPD_UNKNWN_WK_ATTR;
return (p);
@@ -461,20 +482,11 @@ attr_write(void *p, u_int16_t p_len, u_int8_t flags, u_int8_t type,
int
attr_optadd(struct attr_flags *attr, u_int8_t flags, u_int8_t type,
- u_char *data, u_int16_t len)
+ void *data, u_int16_t len)
{
struct attr *a, *p;
- /* we need validate known optional attributes */
-
- if (flags & ATTR_OPTIONAL && ! flags & ATTR_TRANSITIVE)
- /*
- * We already know that we're not interested in this attribute.
- * Currently only the MED is optional and non-transitive but
- * MED is directly stored in struct attr_flags.
- */
- return (0);
-
+ /* known optional attributes were validated previously */
a = calloc(1, sizeof(struct attr));
if (a == NULL)
fatal("attr_optadd");
diff --git a/usr.sbin/bgpd/rde_update.c b/usr.sbin/bgpd/rde_update.c
index 1da0564a6e8..bd31894bba0 100644
--- a/usr.sbin/bgpd/rde_update.c
+++ b/usr.sbin/bgpd/rde_update.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_update.c,v 1.17 2004/04/30 05:47:50 deraadt Exp $ */
+/* $OpenBSD: rde_update.c,v 1.18 2004/05/21 15:36:40 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -211,6 +211,7 @@ up_generate_updates(struct rde_peer *peer,
{
struct update_attr *a;
struct update_prefix *p;
+ struct attr *atr;
struct attr_flags attrs;
ENSURE(peer->state == PEER_UP);
@@ -240,10 +241,22 @@ up_generate_updates(struct rde_peer *peer,
*/
return;
- if (peer->conf.ebgp == 0 && old->aspath->peer->conf.ebgp == 0 &&
- (old->aspath->nexthop->flags & NEXTHOP_ANNOUNCE) == 0)
- /* Do not redistribute updates to ibgp peers */
- return;
+ if (old->aspath->peer->conf.ebgp == 0 && peer->conf.ebgp == 0) {
+ /*
+ * redistribution rules:
+ * 1. if annouce is set -> announce
+ * 2. old non-client, new non-client -> no
+ * 3. old client, new non-client -> yes
+ * 4. old non-client, new client -> yes
+ * 5. old client, new client -> yes
+ */
+ if (old->aspath->peer->conf.reflector_client == 0 &&
+ peer->conf.reflector_client == 0 &&
+ (old->aspath->nexthop->flags &
+ NEXTHOP_ANNOUNCE) == 0)
+ /* Do not redistribute updates to ibgp peers */
+ return;
+ }
/* announce type handling */
switch (peer->conf.announce_type) {
@@ -273,6 +286,19 @@ up_generate_updates(struct rde_peer *peer,
COMMUNITY_WELLKNOWN, COMMUNITY_NO_EXPSUBCONFED))
return;
+ /*
+ * don't send messages back to originator
+ * XXX this is not specified in the RFC but seems logical.
+ */
+ if ((atr = attr_optget(&old->aspath->flags,
+ ATTR_ORIGINATOR_ID)) != NULL) {
+ ENSURE(atr->len == 4);
+ if (memcmp(atr->data, &peer->remote_bgpid,
+ sizeof(peer->remote_bgpid)) == 0)
+ /* would cause loop don't send */
+ return;
+ }
+
/* copy attributes for output filter */
attr_copy(&attrs, &old->aspath->flags);
@@ -281,7 +307,6 @@ up_generate_updates(struct rde_peer *peer,
attr_free(&attrs);
return;
}
-
attr_free(&attrs);
/* withdraw prefix */
@@ -311,11 +336,23 @@ up_generate_updates(struct rde_peer *peer,
return;
}
- if (peer->conf.ebgp == 0 && new->aspath->peer->conf.ebgp == 0 &&
- (new->aspath->nexthop->flags & NEXTHOP_ANNOUNCE) == 0) {
- /* Do not redistribute updates to ibgp peers */
- up_generate_updates(peer, NULL, old);
- return;
+ if (new->aspath->peer->conf.ebgp == 0 && peer->conf.ebgp == 0) {
+ /*
+ * redistribution rules:
+ * 1. if annouce is set -> announce
+ * 2. old non-client, new non-client -> no
+ * 3. old client, new non-client -> yes
+ * 4. old non-client, new client -> yes
+ * 5. old client, new client -> yes
+ */
+ if (new->aspath->peer->conf.reflector_client == 0 &&
+ peer->conf.reflector_client == 0 &&
+ (new->aspath->nexthop->flags &
+ NEXTHOP_ANNOUNCE) == 0) {
+ /* Do not redistribute updates to ibgp peers */
+ up_generate_updates(peer, NULL, old);
+ return;
+ }
}
/* announce type handling */
@@ -365,6 +402,21 @@ up_generate_updates(struct rde_peer *peer,
return;
}
+ /*
+ * don't send messages back to originator
+ * XXX this is not specified in the RFC but seems logical.
+ */
+ if ((atr = attr_optget(&new->aspath->flags,
+ ATTR_ORIGINATOR_ID)) != NULL) {
+ ENSURE(atr->len == 4);
+ if (memcmp(atr->data, &peer->remote_bgpid,
+ sizeof(peer->remote_bgpid)) == 0) {
+ /* would cause loop don't send */
+ attr_free(&attrs);
+ return;
+ }
+ }
+
/* generate update */
p = calloc(1, sizeof(struct update_prefix));
if (p == NULL)
@@ -485,7 +537,7 @@ up_generate_attr(struct rde_peer *peer, struct update_attr *upa,
* dump all other path attributes. Following rules apply:
* 1. well-known attrs: ATTR_ATOMIC_AGGREGATE and ATTR_AGGREGATOR
* pass unmodified (enforce flags to correct values)
- * 2. non-transitive attrs: don't re-announce
+ * 2. non-transitive attrs: don't re-announce to ebgp peers
* 3. transitive known attrs: announce unmodified
* 4. transitive unknown attrs: set partial bit and re-announce
*/
@@ -498,20 +550,30 @@ up_generate_attr(struct rde_peer *peer, struct update_attr *upa,
return (-1);
break;
case ATTR_AGGREGATOR:
- if ((r = attr_write(up_attr_buf + wlen, len,
- oa->flags, oa->type, oa->data, oa->len)) == -1)
- return (-1);
- break;
case ATTR_COMMUNITIES:
+ case ATTR_ORIGINATOR_ID:
+ case ATTR_CLUSTER_LIST:
+ if ((!(oa->flags & ATTR_TRANSITIVE)) &&
+ peer->conf.ebgp != 0) {
+ r = 0;
+ break;
+ }
if ((r = attr_write(up_attr_buf + wlen, len,
oa->flags, oa->type, oa->data, oa->len)) == -1)
return (-1);
break;
default:
/* unknown attribute */
- if (!(oa->flags & ATTR_TRANSITIVE))
- /* somehow a non-transitive slipped through */
+ if (!(oa->flags & ATTR_TRANSITIVE)) {
+ /*
+ * RFC 1771:
+ * Unrecognized non-transitive optional
+ * attributes must be quietly ignored and
+ * not passed along to other BGP peers.
+ */
+ r = 0;
break;
+ }
if ((r = attr_write(up_attr_buf + wlen, len,
oa->flags | ATTR_PARTIAL, oa->type,
oa->data, oa->len)) == -1)