diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2009-12-08 14:03:41 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2009-12-08 14:03:41 +0000 |
commit | 3035ded84a27dbb93640b134ee299e40bdfab886 (patch) | |
tree | 6dd34ebd4900befc84450301a8a4f68638a58aa9 /usr.sbin/bgpd | |
parent | 492b87f62fba2d4de8dafac43bca486a2220fcde (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.h | 93 | ||||
-rw-r--r-- | usr.sbin/bgpd/parse.y | 57 | ||||
-rw-r--r-- | usr.sbin/bgpd/printconf.c | 24 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde.c | 147 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde.h | 7 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde_update.c | 28 | ||||
-rw-r--r-- | usr.sbin/bgpd/session.c | 166 | ||||
-rw-r--r-- | usr.sbin/bgpd/session.h | 3 | ||||
-rw-r--r-- | usr.sbin/bgpd/util.c | 10 |
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) { |