summaryrefslogtreecommitdiff
path: root/usr.sbin/bgpd
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2009-12-08 14:03:41 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2009-12-08 14:03:41 +0000
commit3035ded84a27dbb93640b134ee299e40bdfab886 (patch)
tree6dd34ebd4900befc84450301a8a4f68638a58aa9 /usr.sbin/bgpd
parent492b87f62fba2d4de8dafac43bca486a2220fcde (diff)
Big AID change part two. This changes the mp capability into an array of
flags. This makes a lot of code much easier since the comparison is now trivial. Additionally calculate the negotiated capabilities for a session in the SE and pass that and only that to the RDE. This makes the decisions in the RDE a lot easier. OK henning@
Diffstat (limited to 'usr.sbin/bgpd')
-rw-r--r--usr.sbin/bgpd/bgpd.h93
-rw-r--r--usr.sbin/bgpd/parse.y57
-rw-r--r--usr.sbin/bgpd/printconf.c24
-rw-r--r--usr.sbin/bgpd/rde.c147
-rw-r--r--usr.sbin/bgpd/rde.h7
-rw-r--r--usr.sbin/bgpd/rde_update.c28
-rw-r--r--usr.sbin/bgpd/session.c166
-rw-r--r--usr.sbin/bgpd/session.h3
-rw-r--r--usr.sbin/bgpd/util.c10
9 files changed, 282 insertions, 253 deletions
diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h
index 9d8d16e330d..e17c1bd6c5a 100644
--- a/usr.sbin/bgpd/bgpd.h
+++ b/usr.sbin/bgpd/bgpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bgpd.h,v 1.248 2009/12/01 14:28:05 claudio Exp $ */
+/* $OpenBSD: bgpd.h,v 1.249 2009/12/08 14:03:40 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -107,6 +107,44 @@ enum reconf_action {
RECONF_DELETE
};
+/* Address Family Numbers as per RFC 1700 */
+#define AFI_UNSPEC 0
+#define AFI_IPv4 1
+#define AFI_IPv6 2
+
+/* Subsequent Address Family Identifier as per RFC 4760 */
+#define SAFI_NONE 0x00
+#define SAFI_UNICAST 0x01
+#define SAFI_MULTICAST 0x02
+#define SAFI_MPLS 0x04
+
+struct aid {
+ u_int16_t afi;
+ sa_family_t af;
+ u_int8_t safi;
+ char *name;
+};
+
+extern const struct aid aid_vals[];
+
+#define AID_UNSPEC 0
+#define AID_INET 1
+#define AID_INET6 2
+#define AID_MAX 3
+
+#define AID_VALS { \
+ /* afi, af, safii, name */ \
+ { AFI_UNSPEC, AF_UNSPEC, SAFI_NONE, "unspec"}, \
+ { AFI_IPv4, AF_INET, SAFI_UNICAST, "IPv4 unicast" }, \
+ { AFI_IPv6, AF_INET6, SAFI_UNICAST, "IPv6 unicast" } \
+}
+
+#define AID_PTSIZE { \
+ 0, \
+ sizeof(struct pt_entry4), \
+ sizeof(struct pt_entry6) \
+}
+
struct bgpd_addr {
u_int8_t aid;
union {
@@ -203,11 +241,10 @@ struct peer_auth {
};
struct capabilities {
- u_int8_t mp_v4; /* multiprotocol extensions, RFC 4760 */
- u_int8_t mp_v6;
- u_int8_t refresh; /* route refresh, RFC 2918 */
- u_int8_t restart; /* graceful restart, RFC 4724 */
- u_int8_t as4byte; /* draft-ietf-idr-as4bytes-13 */
+ int8_t mp[AID_MAX]; /* multiprotocol extensions, RFC 4760 */
+ int8_t refresh; /* route refresh, RFC 2918 */
+ int8_t restart; /* graceful restart, RFC 4724 */
+ int8_t as4byte; /* draft-ietf-idr-as4bytes-13 */
};
struct peer_config {
@@ -422,8 +459,7 @@ struct kif {
struct session_up {
struct bgpd_addr local_addr;
struct bgpd_addr remote_addr;
- struct capabilities capa_announced;
- struct capabilities capa_received;
+ struct capabilities capa;
u_int32_t remote_bgpid;
u_int16_t short_as;
};
@@ -676,46 +712,6 @@ struct rde_rib {
SIMPLEQ_HEAD(rib_names, rde_rib);
extern struct rib_names ribnames;
-/* Address Family Numbers as per RFC 1700 */
-#define AFI_UNSPEC 0
-#define AFI_IPv4 1
-#define AFI_IPv6 2
-#define AFI_ALL 0xffff
-
-/* Subsequent Address Family Identifier as per RFC 4760 */
-#define SAFI_NONE 0x00
-#define SAFI_UNICAST 0x01
-#define SAFI_MULTICAST 0x02
-#define SAFI_MPLS 0x04
-#define SAFI_ALL 0xff
-
-struct aid {
- u_int16_t afi;
- sa_family_t af;
- u_int8_t safi;
- char *name;
-};
-
-extern const struct aid aid_vals[];
-
-#define AID_UNSPEC 0
-#define AID_INET 1
-#define AID_INET6 2
-#define AID_MAX 3
-
-#define AID_VALS { \
- /* afi, af, safii, name */ \
- { AFI_UNSPEC, AF_UNSPEC, SAFI_NONE, "unspec"}, \
- { AFI_IPv4, AF_INET, SAFI_UNICAST, "IPv4" }, \
- { AFI_IPv6, AF_INET6, SAFI_UNICAST, "IPv6" } \
-}
-
-#define AID_PTSIZE { \
- 0, \
- sizeof(struct pt_entry4), \
- sizeof(struct pt_entry6) \
-}
-
/* 4-byte magic AS number */
#define AS_TRANS 23456
@@ -820,6 +816,7 @@ size_t aspath_strlen(void *, u_int16_t);
in_addr_t prefixlen2mask(u_int8_t);
void inet6applymask(struct in6_addr *, const struct in6_addr *,
int);
+const char *aid2str(u_int8_t);
int aid2afi(u_int8_t, u_int16_t *, u_int8_t *);
int afi2aid(u_int16_t, u_int8_t, u_int8_t *);
sa_family_t aid2af(u_int8_t);
diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y
index e5bb067e7a2..fb5400eefcf 100644
--- a/usr.sbin/bgpd/parse.y
+++ b/usr.sbin/bgpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.242 2009/12/06 11:42:22 claudio Exp $ */
+/* $OpenBSD: parse.y,v 1.243 2009/12/08 14:03:40 claudio Exp $ */
/*
* Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -697,20 +697,10 @@ neighbor : { curpeer = new_peer(); }
if (($3.prefix.aid == AID_INET && $3.len != 32) ||
($3.prefix.aid == AID_INET6 && $3.len != 128))
curpeer->conf.template = 1;
- switch (curpeer->conf.remote_addr.aid) {
- case AID_INET:
- if (curpeer->conf.capabilities.mp_v4 !=
- SAFI_ALL)
- break;
- curpeer->conf.capabilities.mp_v4 = SAFI_UNICAST;
- break;
- case AID_INET6:
- if (curpeer->conf.capabilities.mp_v6 !=
- SAFI_ALL)
- break;
- curpeer->conf.capabilities.mp_v6 = SAFI_UNICAST;
- break;
- }
+ if (curpeer->conf.capabilities.mp[
+ curpeer->conf.remote_addr.aid] == -1)
+ curpeer->conf.capabilities.mp[
+ curpeer->conf.remote_addr.aid] = 1;
if (get_id(curpeer)) {
yyerror("get_id failed");
YYERROR;
@@ -850,11 +840,13 @@ peeropts : REMOTEAS as4number {
curpeer->conf.min_holdtime = $3;
}
| ANNOUNCE family STRING {
- u_int8_t safi;
+ u_int8_t aid, safi;
+ int8_t val = 1;
- if (!strcmp($3, "none"))
- safi = SAFI_NONE;
- else if (!strcmp($3, "unicast"))
+ if (!strcmp($3, "none")) {
+ safi = SAFI_UNICAST;
+ val = 0;
+ } else if (!strcmp($3, "unicast"))
safi = SAFI_UNICAST;
else {
yyerror("unknown/unsupported SAFI \"%s\"",
@@ -864,16 +856,11 @@ peeropts : REMOTEAS as4number {
}
free($3);
- switch ($2) {
- case AFI_IPv4:
- curpeer->conf.capabilities.mp_v4 = safi;
- break;
- case AFI_IPv6:
- curpeer->conf.capabilities.mp_v6 = safi;
- break;
- default:
- fatal("king bula sees borked AFI");
+ if (afi2aid($2, safi, &aid) == -1) {
+ yyerror("unknown AFI/SAFI pair");
+ YYERROR;
}
+ curpeer->conf.capabilities.mp[aid] = val;
}
| ANNOUNCE CAPABILITIES yesno {
curpeer->conf.announce_capa = $3;
@@ -2587,6 +2574,7 @@ struct peer *
alloc_peer(void)
{
struct peer *p;
+ u_int8_t i;
if ((p = calloc(1, sizeof(struct peer))) == NULL)
fatal("new_peer");
@@ -2597,8 +2585,8 @@ alloc_peer(void)
p->conf.distance = 1;
p->conf.announce_type = ANNOUNCE_UNDEF;
p->conf.announce_capa = 1;
- p->conf.capabilities.mp_v4 = SAFI_ALL;
- p->conf.capabilities.mp_v6 = SAFI_ALL;
+ for (i = 0; i < AID_MAX; i++)
+ p->conf.capabilities.mp[i] = -1;
p->conf.capabilities.refresh = 1;
p->conf.capabilities.restart = 0;
p->conf.capabilities.as4byte = 1;
@@ -2889,6 +2877,8 @@ str2key(char *s, char *dest, size_t max_len)
int
neighbor_consistent(struct peer *p)
{
+ u_int8_t i;
+
/* local-address and peer's address: same address family */
if (p->conf.local_addr.aid &&
p->conf.local_addr.aid != p->conf.remote_addr.aid) {
@@ -2939,10 +2929,9 @@ neighbor_consistent(struct peer *p)
}
/* the default MP capability is NONE */
- if (p->conf.capabilities.mp_v4 == SAFI_ALL)
- p->conf.capabilities.mp_v4 = SAFI_NONE;
- if (p->conf.capabilities.mp_v6 == SAFI_ALL)
- p->conf.capabilities.mp_v6 = SAFI_NONE;
+ for (i = 0; i < AID_MAX; i++)
+ if (p->conf.capabilities.mp[i] == -1)
+ p->conf.capabilities.mp[i] = 0;
return (0);
}
diff --git a/usr.sbin/bgpd/printconf.c b/usr.sbin/bgpd/printconf.c
index 6503a51fff1..2ab8f97d5bf 100644
--- a/usr.sbin/bgpd/printconf.c
+++ b/usr.sbin/bgpd/printconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: printconf.c,v 1.74 2009/12/01 14:28:05 claudio Exp $ */
+/* $OpenBSD: printconf.c,v 1.75 2009/12/08 14:03:40 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -35,7 +35,7 @@ void print_peer(struct peer_config *, struct bgpd_config *,
const char *);
const char *print_auth_alg(u_int8_t);
const char *print_enc_alg(u_int8_t);
-const char *print_safi(u_int8_t);
+void print_announce(struct peer_config *, const char *);
void print_rule(struct peer *, struct filter_rule *);
const char * mrt_type(enum mrt_type);
void print_mrt(u_int32_t, u_int32_t, const char *, const char *);
@@ -378,8 +378,7 @@ print_peer(struct peer_config *p, struct bgpd_config *conf, const char *c)
if (p->ttlsec)
printf("%s\tttl-security yes\n", c);
- printf("%s\tannounce IPv4 %s\n", c, print_safi(p->capabilities.mp_v4));
- printf("%s\tannounce IPv6 %s\n", c, print_safi(p->capabilities.mp_v6));
+ print_announce(p, c);
if (p->softreconfig_in == 1)
printf("%s\tsoftreconfig in yes\n", c);
@@ -423,17 +422,14 @@ print_enc_alg(u_int8_t alg)
}
}
-const char *
-print_safi(u_int8_t safi)
+void
+print_announce(struct peer_config *p, const char *c)
{
- switch (safi) {
- case SAFI_NONE:
- return ("none");
- case SAFI_UNICAST:
- return ("unicast");
- default:
- return ("?");
- }
+ u_int8_t aid;
+
+ for (aid = 0; aid < AID_MAX; aid++)
+ if (p->capabilities.mp[aid])
+ printf("%s\tannounce %s\n", c, aid2str(aid));
}
void
diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c
index 732a7deca43..0b7ac1c1aac 100644
--- a/usr.sbin/bgpd/rde.c
+++ b/usr.sbin/bgpd/rde.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.c,v 1.275 2009/12/01 14:28:05 claudio Exp $ */
+/* $OpenBSD: rde.c,v 1.276 2009/12/08 14:03:40 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -92,8 +92,8 @@ struct rde_peer *peer_add(u_int32_t, struct peer_config *);
struct rde_peer *peer_get(u_int32_t);
void peer_up(u_int32_t, struct session_up *);
void peer_down(u_int32_t);
-void peer_dump(u_int32_t, u_int16_t, u_int8_t);
-void peer_send_eor(struct rde_peer *, u_int16_t, u_int16_t);
+void peer_dump(u_int32_t, u_int8_t);
+void peer_send_eor(struct rde_peer *, u_int8_t);
void network_init(struct network_head *);
void network_add(struct network_config *, int);
@@ -383,7 +383,6 @@ rde_dispatch_imsg_session(struct imsgbuf *ibuf)
struct imsg imsg;
struct peer p;
struct peer_config pconf;
- struct rrefresh r;
struct rde_peer *peer;
struct session_up sup;
struct ctl_show_rib_request req;
@@ -391,6 +390,7 @@ rde_dispatch_imsg_session(struct imsgbuf *ibuf)
struct nexthop *nh;
ssize_t n;
int verbose;
+ u_int8_t aid;
if ((n = imsg_read(ibuf)) == -1)
fatal("rde_dispatch_imsg_session: imsg_read error");
@@ -429,12 +429,14 @@ rde_dispatch_imsg_session(struct imsgbuf *ibuf)
peer_down(imsg.hdr.peerid);
break;
case IMSG_REFRESH:
- if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(r)) {
+ if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(aid)) {
log_warnx("rde_dispatch: wrong imsg len");
break;
}
- memcpy(&r, imsg.data, sizeof(r));
- peer_dump(imsg.hdr.peerid, r.afi, r.safi);
+ memcpy(&aid, imsg.data, sizeof(aid));
+ if (aid >= AID_MAX)
+ fatalx("IMSG_REFRESH: bad AID");
+ peer_dump(imsg.hdr.peerid, aid);
break;
case IMSG_NETWORK_ADD:
if (imsg.hdr.len - IMSG_HEADER_SIZE !=
@@ -763,6 +765,8 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf)
int
rde_update_dispatch(struct imsg *imsg)
{
+ struct bgpd_addr prefix;
+ struct mpattr mpa;
struct rde_peer *peer;
struct rde_aspath *asp = NULL;
u_char *p, *mpp = NULL;
@@ -771,9 +775,7 @@ rde_update_dispatch(struct imsg *imsg)
u_int16_t withdrawn_len;
u_int16_t attrpath_len;
u_int16_t nlri_len;
- u_int8_t prefixlen, safi, subtype;
- struct bgpd_addr prefix;
- struct mpattr mpa;
+ u_int8_t aid, prefixlen, safi, subtype;
peer = peer_get(imsg->hdr.peerid);
if (peer == NULL) /* unknown peer, cannot happen */
@@ -872,9 +874,9 @@ rde_update_dispatch(struct imsg *imsg)
p += pos;
len -= pos;
- if (peer->capa_received.mp_v4 == SAFI_NONE &&
- peer->capa_received.mp_v6 != SAFI_NONE) {
- log_peer_warnx(&peer->conf, "bad AFI, IPv4 disabled");
+ if (peer->capa.mp[AID_INET] == 0) {
+ log_peer_warnx(&peer->conf,
+ "bad withdraw, %s disabled", aid2str(AID_INET));
rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
NULL, 0);
goto done;
@@ -904,15 +906,25 @@ rde_update_dispatch(struct imsg *imsg)
afi = ntohs(afi);
safi = *mpp++;
mplen--;
- switch (afi) {
- case AFI_IPv6:
- if (peer->capa_received.mp_v6 == SAFI_NONE) {
- log_peer_warnx(&peer->conf, "bad AFI, "
- "IPv6 disabled");
- rde_update_err(peer, ERR_UPDATE,
- ERR_UPD_OPTATTR, NULL, 0);
- goto done;
- }
+
+ if (afi2aid(afi, safi, &aid) == -1) {
+ log_peer_warnx(&peer->conf,
+ "bad AFI/SAFI pair in withdraw");
+ rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
+ NULL, 0);
+ goto done;
+ }
+
+ if (peer->capa.mp[aid] == 0) {
+ log_peer_warnx(&peer->conf,
+ "bad withdraw, %s disabled", aid2str(aid));
+ rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
+ NULL, 0);
+ goto done;
+ }
+
+ switch (aid) {
+ case AID_INET6:
while (mplen > 0) {
if ((pos = rde_update_get_prefix6(mpp, mplen,
&prefix, &prefixlen)) == -1) {
@@ -975,9 +987,9 @@ rde_update_dispatch(struct imsg *imsg)
p += pos;
nlri_len -= pos;
- if (peer->capa_received.mp_v4 == SAFI_NONE &&
- peer->capa_received.mp_v6 != SAFI_NONE) {
- log_peer_warnx(&peer->conf, "bad AFI, IPv4 disabled");
+ if (peer->capa.mp[AID_INET] == 0) {
+ log_peer_warnx(&peer->conf,
+ "bad update, %s disabled", aid2str(AID_INET));
rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
NULL, 0);
goto done;
@@ -1007,6 +1019,22 @@ rde_update_dispatch(struct imsg *imsg)
safi = *mpp++;
mplen--;
+ if (afi2aid(afi, safi, &aid) == -1) {
+ log_peer_warnx(&peer->conf,
+ "bad AFI/SAFI pair in update");
+ rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
+ NULL, 0);
+ goto done;
+ }
+
+ if (peer->capa.mp[aid] == 0) {
+ log_peer_warnx(&peer->conf,
+ "bad update, %s disabled", aid2str(aid));
+ rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
+ NULL, 0);
+ goto done;
+ }
+
/*
* this works because asp is not linked.
* But first unlock the previously locked nexthop.
@@ -1025,16 +1053,8 @@ rde_update_dispatch(struct imsg *imsg)
mpp += pos;
mplen -= pos;
- switch (afi) {
- case AFI_IPv6:
- if (peer->capa_received.mp_v6 == SAFI_NONE) {
- log_peer_warnx(&peer->conf, "bad AFI, "
- "IPv6 disabled");
- rde_update_err(peer, ERR_UPDATE,
- ERR_UPD_OPTATTR, NULL, 0);
- goto done;
- }
-
+ switch (aid) {
+ case AID_INET6:
while (mplen > 0) {
if ((pos = rde_update_get_prefix6(mpp, mplen,
&prefix, &prefixlen)) == -1) {
@@ -2513,7 +2533,7 @@ rde_decisionflags(void)
int
rde_as4byte(struct rde_peer *peer)
{
- return (peer->capa_announced.as4byte && peer->capa_received.as4byte);
+ return (peer->capa.as4byte);
}
/*
@@ -2666,6 +2686,7 @@ void
peer_up(u_int32_t id, struct session_up *sup)
{
struct rde_peer *peer;
+ u_int8_t i;
peer = peer_get(id);
if (peer == NULL) {
@@ -2679,10 +2700,7 @@ peer_up(u_int32_t id, struct session_up *sup)
peer->short_as = sup->short_as;
memcpy(&peer->remote_addr, &sup->remote_addr,
sizeof(peer->remote_addr));
- memcpy(&peer->capa_announced, &sup->capa_announced,
- sizeof(peer->capa_announced));
- memcpy(&peer->capa_received, &sup->capa_received,
- sizeof(peer->capa_received));
+ memcpy(&peer->capa, &sup->capa, sizeof(peer->capa));
peer_localaddrs(peer, &sup->local_addr);
@@ -2696,7 +2714,10 @@ peer_up(u_int32_t id, struct session_up *sup)
*/
return;
- peer_dump(id, AFI_ALL, SAFI_ALL);
+ for (i = 0; i < AID_MAX; i++) {
+ if (peer->capa.mp[i] == 1)
+ peer_dump(id, i);
+ }
}
void
@@ -2731,9 +2752,10 @@ peer_down(u_int32_t id)
}
void
-peer_dump(u_int32_t id, u_int16_t afi, u_int8_t safi)
+peer_dump(u_int32_t id, u_int8_t aid)
{
struct rde_peer *peer;
+ sa_family_t af; /* XXX needs to be replaced with aid */
peer = peer_get(id);
if (peer == NULL) {
@@ -2741,36 +2763,24 @@ peer_dump(u_int32_t id, u_int16_t afi, u_int8_t safi)
return;
}
- if (afi == AFI_ALL || afi == AFI_IPv4)
- if ((safi == SAFI_ALL || safi == SAFI_UNICAST) &&
- peer->conf.capabilities.mp_v4 != SAFI_NONE) {
- if (peer->conf.announce_type == ANNOUNCE_DEFAULT_ROUTE)
- up_generate_default(rules_l, peer, AF_INET);
- else
- rib_dump(&ribs[peer->ribid], rde_up_dump_upcall,
- peer, AF_INET);
- if (peer->capa_received.restart &&
- peer->capa_announced.restart)
- peer_send_eor(peer, AFI_IPv4, SAFI_UNICAST);
- }
- if (afi == AFI_ALL || afi == AFI_IPv6)
- if ((safi == SAFI_ALL || safi == SAFI_UNICAST)) {
- if (peer->conf.announce_type == ANNOUNCE_DEFAULT_ROUTE)
- up_generate_default(rules_l, peer, AF_INET6);
- else
- rib_dump(&ribs[peer->ribid], rde_up_dump_upcall,
- peer, AF_INET6);
- if (peer->capa_received.restart &&
- peer->capa_announced.restart)
- peer_send_eor(peer, AFI_IPv6, SAFI_UNICAST);
- }
+ af = aid2af(aid);
+
+ if (peer->conf.announce_type == ANNOUNCE_DEFAULT_ROUTE)
+ up_generate_default(rules_l, peer, aid);
+ else
+ rib_dump(&ribs[peer->ribid], rde_up_dump_upcall, peer, af);
+ if (peer->capa.restart)
+ peer_send_eor(peer, aid);
}
/* End-of-RIB marker, RFC 4724 */
void
-peer_send_eor(struct rde_peer *peer, u_int16_t afi, u_int16_t safi)
+peer_send_eor(struct rde_peer *peer, u_int8_t aid)
{
- if (afi == AFI_IPv4 && safi == SAFI_UNICAST) {
+ u_int16_t afi;
+ u_int8_t safi;
+
+ if (aid == AID_INET) {
u_char null[4];
bzero(&null, 4);
@@ -2781,6 +2791,9 @@ peer_send_eor(struct rde_peer *peer, u_int16_t afi, u_int16_t safi)
u_int16_t i;
u_char buf[10];
+ if (aid2afi(aid, &afi, &safi) == -1)
+ fatalx("peer_send_eor: bad AID");
+
i = 0; /* v4 withdrawn len */
bcopy(&i, &buf[0], sizeof(i));
i = htons(6); /* path attr len */
diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h
index 3079802dc8b..da899b1255b 100644
--- a/usr.sbin/bgpd/rde.h
+++ b/usr.sbin/bgpd/rde.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.h,v 1.123 2009/12/01 14:28:05 claudio Exp $ */
+/* $OpenBSD: rde.h,v 1.124 2009/12/08 14:03:40 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
@@ -60,8 +60,7 @@ struct rde_peer {
struct uplist_prefix withdraws;
struct uplist_attr updates6;
struct uplist_prefix withdraws6;
- struct capabilities capa_announced;
- struct capabilities capa_received;
+ struct capabilities capa;
u_int64_t prefix_rcvd_update;
u_int64_t prefix_rcvd_withdraw;
u_int64_t prefix_sent_update;
@@ -417,7 +416,7 @@ int up_generate(struct rde_peer *, struct rde_aspath *,
void up_generate_updates(struct filter_head *, struct rde_peer *,
struct prefix *, struct prefix *);
void up_generate_default(struct filter_head *, struct rde_peer *,
- sa_family_t);
+ u_int8_t);
int up_dump_prefix(u_char *, int, struct uplist_prefix *,
struct rde_peer *);
int up_dump_attrnlri(u_char *, int, struct rde_peer *);
diff --git a/usr.sbin/bgpd/rde_update.c b/usr.sbin/bgpd/rde_update.c
index 5b588f0b562..4418fc41aea 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.72 2009/12/04 13:28:34 claudio Exp $ */
+/* $OpenBSD: rde_update.c,v 1.73 2009/12/08 14:03:40 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -276,18 +276,8 @@ up_test_update(struct rde_peer *peer, struct prefix *p)
fatalx("try to send out a looped path");
pt_getaddr(p->prefix, &addr);
- switch (addr.aid) {
- case AID_INET:
- /* XXX is this correct? */
- if (peer->capa_announced.mp_v4 == SAFI_NONE &&
- peer->capa_received.mp_v6 != SAFI_NONE)
- return (-1);
- break;
- case AID_INET6:
- if (peer->capa_announced.mp_v6 == SAFI_NONE)
- return (-1);
- break;
- }
+ if (peer->capa.mp[addr.aid] == 0)
+ return (-1);
if (p->aspath->peer->conf.ebgp == 0 && peer->conf.ebgp == 0) {
/*
@@ -447,18 +437,12 @@ up_generate_updates(struct filter_head *rules, struct rde_peer *peer,
/* send a default route to the specified peer */
void
up_generate_default(struct filter_head *rules, struct rde_peer *peer,
- sa_family_t af)
+ u_int8_t aid)
{
struct rde_aspath *asp, *fasp;
struct bgpd_addr addr;
- if (peer->capa_received.mp_v4 == SAFI_NONE &&
- peer->capa_received.mp_v6 != SAFI_NONE &&
- af == AF_INET)
- return;
-
- if (peer->capa_received.mp_v6 == SAFI_NONE &&
- af == AF_INET6)
+ if (peer->capa.mp[aid] == 0)
return;
asp = path_get();
@@ -474,7 +458,7 @@ up_generate_default(struct filter_head *rules, struct rde_peer *peer,
/* filter as usual */
bzero(&addr, sizeof(addr));
- af2aid(af, 0, &addr.aid);
+ addr.aid = aid;
if (rde_filter(peer->ribid, &fasp, rules, peer, asp, &addr, 0, NULL,
DIR_OUT) == ACTION_DENY) {
diff --git a/usr.sbin/bgpd/session.c b/usr.sbin/bgpd/session.c
index e1a95c724f6..0575a229867 100644
--- a/usr.sbin/bgpd/session.c
+++ b/usr.sbin/bgpd/session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.c,v 1.301 2009/12/03 19:27:20 claudio Exp $ */
+/* $OpenBSD: session.c,v 1.302 2009/12/08 14:03:40 claudio Exp $ */
/*
* Copyright (c) 2003, 2004, 2005 Henning Brauer <henning@openbsd.org>
@@ -66,7 +66,7 @@ int session_connect(struct peer *);
void session_tcp_established(struct peer *);
void session_capa_ann_none(struct peer *);
int session_capa_add(struct buf *, u_int8_t, u_int8_t);
-int session_capa_add_mp(struct buf *, u_int16_t, u_int8_t);
+int session_capa_add_mp(struct buf *, u_int8_t);
struct bgp_msg *session_newmsg(enum msg_type, u_int16_t);
int session_sendmsg(struct bgp_msg *, struct peer *);
void session_open(struct peer *);
@@ -74,7 +74,7 @@ void session_keepalive(struct peer *);
void session_update(u_int32_t, void *, size_t);
void session_notification(struct peer *, u_int8_t, u_int8_t, void *,
ssize_t);
-void session_rrefresh(struct peer *, u_int16_t, u_int8_t);
+void session_rrefresh(struct peer *, u_int8_t);
int session_dispatch_msg(struct pollfd *, struct peer *);
int parse_header(struct peer *, u_char *, u_int16_t *, u_int8_t *);
int parse_open(struct peer *);
@@ -82,6 +82,7 @@ int parse_update(struct peer *);
int parse_refresh(struct peer *);
int parse_notification(struct peer *);
int parse_capabilities(struct peer *, u_char *, u_int16_t, u_int32_t *);
+int capa_neg_calc(struct peer *);
void session_dispatch_imsg(struct imsgbuf *, int, u_int *);
void session_up(struct peer *);
void session_down(struct peer *);
@@ -1247,11 +1248,7 @@ session_tcp_established(struct peer *peer)
void
session_capa_ann_none(struct peer *peer)
{
- peer->capa.ann.mp_v4 = SAFI_NONE;
- peer->capa.ann.mp_v4 = SAFI_NONE;
- peer->capa.ann.refresh = 0;
- peer->capa.ann.restart = 0;
- peer->capa.ann.as4byte = 0;
+ bzero(&peer->capa.ann, sizeof(peer->capa.ann));
}
int
@@ -1265,11 +1262,14 @@ session_capa_add(struct buf *opb, u_int8_t capa_code, u_int8_t capa_len)
}
int
-session_capa_add_mp(struct buf *buf, u_int16_t afi, u_int8_t safi)
+session_capa_add_mp(struct buf *buf, u_int8_t aid)
{
- u_int8_t pad = 0;
+ u_int8_t safi, pad = 0;
+ u_int16_t afi;
int errs = 0;
+ if (aid2afi(aid, &afi, &safi) == -1)
+ fatalx("session_capa_add_mp: bad afi/safi pair");
afi = htons(afi);
errs += buf_add(buf, &afi, sizeof(afi));
errs += buf_add(buf, &pad, sizeof(pad));
@@ -1337,7 +1337,7 @@ session_open(struct peer *p)
struct buf *opb;
struct msg_open msg;
u_int16_t len;
- u_int8_t op_type, optparamlen = 0;
+ u_int8_t i, op_type, optparamlen = 0;
u_int errs = 0;
@@ -1348,14 +1348,11 @@ session_open(struct peer *p)
}
/* multiprotocol extensions, RFC 4760 */
- if (p->capa.ann.mp_v4) { /* 4 bytes data */
- errs += session_capa_add(opb, CAPA_MP, 4);
- errs += session_capa_add_mp(opb, AFI_IPv4, p->capa.ann.mp_v4);
- }
- if (p->capa.ann.mp_v6) { /* 4 bytes data */
- errs += session_capa_add(opb, CAPA_MP, 4);
- errs += session_capa_add_mp(opb, AFI_IPv6, p->capa.ann.mp_v6);
- }
+ for (i = 0; i < AID_MAX; i++)
+ if (p->capa.ann.mp[i]) { /* 4 bytes data */
+ errs += session_capa_add(opb, CAPA_MP, 4);
+ errs += session_capa_add_mp(opb, i);
+ }
/* route refresh, RFC 2918 */
if (p->capa.ann.refresh) /* no data */
@@ -1523,23 +1520,29 @@ session_notification(struct peer *p, u_int8_t errcode, u_int8_t subcode,
int
session_neighbor_rrefresh(struct peer *p)
{
+ u_int8_t i;
+
if (!p->capa.peer.refresh)
return (-1);
- if (p->capa.peer.mp_v4 != SAFI_NONE)
- session_rrefresh(p, AFI_IPv4, p->capa.peer.mp_v4);
- if (p->capa.peer.mp_v6 != SAFI_NONE)
- session_rrefresh(p, AFI_IPv6, p->capa.peer.mp_v6);
+ for (i = 0; i < AID_MAX; i++) {
+ if (p->capa.peer.mp[i] != 0)
+ session_rrefresh(p, i);
+ }
return (0);
}
void
-session_rrefresh(struct peer *p, u_int16_t afi, u_int8_t safi)
+session_rrefresh(struct peer *p, u_int8_t aid)
{
struct bgp_msg *buf;
int errs = 0;
- u_int8_t null8 = 0;
+ u_int16_t afi;
+ u_int8_t safi, null8 = 0;
+
+ if (aid2afi(aid, &afi, &safi) == -1)
+ fatalx("session_rrefresh: bad afi/safi pair");
if ((buf = session_newmsg(RREFRESH, MSGSIZE_RREFRESH)) == NULL) {
bgp_fsm(p, EVNT_CON_FATAL);
@@ -1979,6 +1982,14 @@ parse_open(struct peer *peer)
return (-1);
}
+ if (capa_neg_calc(peer) == -1) {
+ log_peer_warnx(&peer->conf,
+ "capabilitiy negotiation calculation failed");
+ session_notification(peer, ERR_OPEN, 0, NULL, 0);
+ change_state(peer, STATE_IDLE, EVNT_RCVD_OPEN);
+ return (-1);
+ }
+
return (0);
}
@@ -2013,24 +2024,35 @@ int
parse_refresh(struct peer *peer)
{
u_char *p;
- struct rrefresh r;
+ u_int16_t afi;
+ u_int8_t aid, safi;
p = peer->rbuf->rptr;
p += MSGSIZE_HEADER; /* header is already checked */
+ /*
+ * We could check if we actually announced the capability but
+ * as long as the message is correctly encoded we don't care.
+ */
+
/* afi, 2 byte */
- memcpy(&r.afi, p, sizeof(r.afi));
- r.afi = ntohs(r.afi);
+ memcpy(&afi, p, sizeof(afi));
+ afi = ntohs(afi);
p += 2;
/* reserved, 1 byte */
p += 1;
/* safi, 1 byte */
- memcpy(&r.safi, p, sizeof(r.safi));
+ memcpy(&safi, p, sizeof(safi));
/* afi/safi unchecked - unrecognized values will be ignored anyway */
+ if (afi2aid(afi, safi, &aid) == -1) {
+ log_peer_warnx(&peer->conf, "peer sent bad refresh, "
+ "invalid afi/safi pair");
+ return (0);
+ }
- if (imsg_compose(ibuf_rde, IMSG_REFRESH, peer->conf.id, 0, -1, &r,
- sizeof(r)) == -1)
+ if (imsg_compose(ibuf_rde, IMSG_REFRESH, peer->conf.id, 0, -1, &aid,
+ sizeof(aid)) == -1)
return (-1);
return (0);
@@ -2040,11 +2062,12 @@ int
parse_notification(struct peer *peer)
{
u_char *p;
+ u_int16_t datalen;
u_int8_t errcode;
u_int8_t subcode;
- u_int16_t datalen;
u_int8_t capa_code;
u_int8_t capa_len;
+ u_int8_t i;
/* just log */
p = peer->rbuf->rptr;
@@ -2099,8 +2122,8 @@ parse_notification(struct peer *peer)
datalen -= capa_len;
switch (capa_code) {
case CAPA_MP:
- peer->capa.ann.mp_v4 = SAFI_NONE;
- peer->capa.ann.mp_v6 = SAFI_NONE;
+ for (i = 0; i < AID_MAX; i++)
+ peer->capa.ann.mp[i] = 0;
log_peer_warnx(&peer->conf,
"disabling multiprotocol capability");
break;
@@ -2144,13 +2167,14 @@ parse_notification(struct peer *peer)
int
parse_capabilities(struct peer *peer, u_char *d, u_int16_t dlen, u_int32_t *as)
{
+ u_char *capa_val;
+ u_int32_t remote_as;
u_int16_t len;
+ u_int16_t afi;
+ u_int8_t safi;
+ u_int8_t aid;
u_int8_t capa_code;
u_int8_t capa_len;
- u_char *capa_val;
- u_int16_t mp_afi;
- u_int8_t mp_safi;
- u_int32_t remote_as;
len = dlen;
while (len > 0) {
@@ -2187,29 +2211,16 @@ parse_capabilities(struct peer *peer, u_char *d, u_int16_t dlen, u_int32_t *as)
"expect len 4, len is %u", capa_len);
return (-1);
}
- memcpy(&mp_afi, capa_val, sizeof(mp_afi));
- mp_afi = ntohs(mp_afi);
- memcpy(&mp_safi, capa_val + 3, sizeof(mp_safi));
- switch (mp_afi) {
- case AFI_IPv4:
- if (mp_safi < 1 || mp_safi > 3)
- log_peer_warnx(&peer->conf,
- "parse_capabilities: AFI IPv4, "
- "mp_safi %u unknown", mp_safi);
- else
- peer->capa.peer.mp_v4 = mp_safi;
- break;
- case AFI_IPv6:
- if (mp_safi < 1 || mp_safi > 3)
- log_peer_warnx(&peer->conf,
- "parse_capabilities: AFI IPv6, "
- "mp_safi %u unknown", mp_safi);
- else
- peer->capa.peer.mp_v6 = mp_safi;
- break;
- default: /* ignore */
- break;
+ memcpy(&afi, capa_val, sizeof(afi));
+ afi = ntohs(afi);
+ memcpy(&safi, capa_val + 3, sizeof(safi));
+ if (afi2aid(afi, safi, &aid) == -1) {
+ log_peer_warnx(&peer->conf,
+ "parse_capabilities: AFI %u, "
+ "safi %u unknown", afi, safi);
+ return (-1);
}
+ peer->capa.peer.mp[aid] = 1;
break;
case CAPA_REFRESH:
peer->capa.peer.refresh = 1;
@@ -2237,6 +2248,37 @@ parse_capabilities(struct peer *peer, u_char *d, u_int16_t dlen, u_int32_t *as)
return (0);
}
+int
+capa_neg_calc(struct peer *p)
+{
+ u_int8_t i, hasmp = 0;
+
+ /* refresh: does not realy matter here, use peer setting */
+ p->capa.neg.refresh = p->capa.peer.refresh;
+
+ /* as4byte: both side must announce capability */
+ if (p->capa.ann.as4byte && p->capa.peer.as4byte)
+ p->capa.neg.as4byte = 1;
+ else
+ p->capa.neg.as4byte = 0;
+
+ /* MP: both side must announce capability */
+ for (i = 0; i < AID_MAX; i++) {
+ if (p->capa.ann.mp[i] && p->capa.peer.mp[i]) {
+ p->capa.neg.mp[i] = 1;
+ hasmp = 1;
+ } else
+ p->capa.neg.mp[i] = 0;
+ }
+ /* if no MP capability present for default IPv4 unicast mode */
+ if (!hasmp)
+ p->capa.neg.mp[AID_INET] = 1;
+
+ p->capa.neg.restart = p->capa.peer.restart;
+
+ return (0);
+}
+
void
session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt)
{
@@ -2715,6 +2757,7 @@ getpeerbyid(u_int32_t peerid)
void
session_down(struct peer *peer)
{
+ bzero(&peer->capa.neg, sizeof(peer->capa.neg));
peer->stats.last_updown = time(NULL);
if (imsg_compose(ibuf_rde, IMSG_SESSION_DOWN, peer->conf.id, 0, -1,
NULL, 0) == -1)
@@ -2735,8 +2778,7 @@ session_up(struct peer *p)
sup.remote_bgpid = p->remote_bgpid;
sup.short_as = p->short_as;
- memcpy(&sup.capa_announced, &p->capa.ann, sizeof(sup.capa_announced));
- memcpy(&sup.capa_received, &p->capa.peer, sizeof(sup.capa_received));
+ memcpy(&sup.capa, &p->capa.neg, sizeof(sup.capa));
p->stats.last_updown = time(NULL);
if (imsg_compose(ibuf_rde, IMSG_SESSION_UP, p->conf.id, 0, -1,
&sup, sizeof(sup)) == -1)
diff --git a/usr.sbin/bgpd/session.h b/usr.sbin/bgpd/session.h
index 11471e5dde3..5cbdbdce91b 100644
--- a/usr.sbin/bgpd/session.h
+++ b/usr.sbin/bgpd/session.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.h,v 1.102 2009/09/02 08:06:42 claudio Exp $ */
+/* $OpenBSD: session.h,v 1.103 2009/12/08 14:03:40 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -189,6 +189,7 @@ struct peer {
struct {
struct capabilities ann;
struct capabilities peer;
+ struct capabilities neg;
} capa;
struct {
struct bgpd_addr local_addr;
diff --git a/usr.sbin/bgpd/util.c b/usr.sbin/bgpd/util.c
index 3db16447dbf..0a24001e53c 100644
--- a/usr.sbin/bgpd/util.c
+++ b/usr.sbin/bgpd/util.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: util.c,v 1.7 2009/12/01 14:28:05 claudio Exp $ */
+/* $OpenBSD: util.c,v 1.8 2009/12/08 14:03:40 claudio Exp $ */
/*
* Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org>
@@ -280,6 +280,14 @@ inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen)
/* address family translation functions */
const struct aid aid_vals[AID_MAX] = AID_VALS;
+const char *
+aid2str(u_int8_t aid)
+{
+ if (aid < AID_MAX)
+ return (aid_vals[aid].name);
+ return ("unknown AID");
+}
+
int
aid2afi(u_int8_t aid, u_int16_t *afi, u_int8_t *safi)
{