diff options
Diffstat (limited to 'net/openbgpd/files/patch-bgpd_rde_update.c')
-rw-r--r-- | net/openbgpd/files/patch-bgpd_rde_update.c | 706 |
1 files changed, 563 insertions, 143 deletions
diff --git a/net/openbgpd/files/patch-bgpd_rde_update.c b/net/openbgpd/files/patch-bgpd_rde_update.c index fc034a3f7429..bbd2c19ce25f 100644 --- a/net/openbgpd/files/patch-bgpd_rde_update.c +++ b/net/openbgpd/files/patch-bgpd_rde_update.c @@ -1,18 +1,18 @@ Index: bgpd/rde_update.c =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/rde_update.c,v -retrieving revision 1.1.1.1 -retrieving revision 1.4 -diff -u -p -r1.1.1.1 -r1.4 ---- bgpd/rde_update.c 30 Jun 2009 05:46:15 -0000 1.1.1.1 -+++ bgpd/rde_update.c 10 Aug 2009 21:20:05 -0000 1.4 +retrieving revision 1.1.1.7 +retrieving revision 1.6 +diff -u -p -r1.1.1.7 -r1.6 +--- bgpd/rde_update.c 14 Feb 2010 20:19:57 -0000 1.1.1.7 ++++ bgpd/rde_update.c 14 Feb 2010 19:53:36 -0000 1.6 @@ -1,4 +1,4 @@ --/* $OpenBSD: rde_update.c,v 1.61 2007/11/27 01:13:54 claudio Exp $ */ -+/* $OpenBSD: rde_update.c,v 1.69 2009/08/06 08:53:11 claudio Exp $ */ +-/* $OpenBSD: rde_update.c,v 1.68 2009/06/06 01:10:29 claudio Exp $ */ ++/* $OpenBSD: rde_update.c,v 1.77 2010/01/13 06:02:37 claudio Exp $ */ /* * Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org> -@@ -17,10 +17,17 @@ +@@ -17,19 +17,26 @@ */ #include <sys/types.h> #include <sys/queue.h> @@ -30,7 +30,120 @@ diff -u -p -r1.1.1.1 -r1.4 #include "bgpd.h" #include "rde.h" -@@ -270,6 +277,8 @@ up_test_update(struct rde_peer *peer, st + + in_addr_t up_get_nexthop(struct rde_peer *, struct rde_aspath *); + int up_generate_mp_reach(struct rde_peer *, struct update_attr *, +- struct rde_aspath *, sa_family_t); ++ struct rde_aspath *, u_int8_t); + int up_generate_attr(struct rde_peer *, struct update_attr *, +- struct rde_aspath *, sa_family_t); ++ struct rde_aspath *, u_int8_t); + + /* update stuff. */ + struct update_prefix { +@@ -65,10 +72,12 @@ RB_GENERATE(uptree_attr, update_attr, en + void + up_init(struct rde_peer *peer) + { +- TAILQ_INIT(&peer->updates); +- TAILQ_INIT(&peer->withdraws); +- TAILQ_INIT(&peer->updates6); +- TAILQ_INIT(&peer->withdraws6); ++ u_int8_t i; ++ ++ for (i = 0; i < AID_MAX; i++) { ++ TAILQ_INIT(&peer->updates[i]); ++ TAILQ_INIT(&peer->withdraws[i]); ++ } + RB_INIT(&peer->up_prefix); + RB_INIT(&peer->up_attrs); + peer->up_pcnt = 0; +@@ -103,8 +112,10 @@ up_clear(struct uplist_attr *updates, st + void + up_down(struct rde_peer *peer) + { +- up_clear(&peer->updates, &peer->withdraws); +- up_clear(&peer->updates6, &peer->withdraws6); ++ u_int8_t i; ++ ++ for (i = 0; i < AID_MAX; i++) ++ up_clear(&peer->updates[i], &peer->withdraws[i]); + + RB_INIT(&peer->up_prefix); + RB_INIT(&peer->up_attrs); +@@ -120,19 +131,19 @@ up_prefix_cmp(struct update_prefix *a, s + { + int i; + +- if (a->prefix.af < b->prefix.af) ++ if (a->prefix.aid < b->prefix.aid) + return (-1); +- if (a->prefix.af > b->prefix.af) ++ if (a->prefix.aid > b->prefix.aid) + return (1); + +- switch (a->prefix.af) { +- case AF_INET: ++ switch (a->prefix.aid) { ++ case AID_INET: + if (ntohl(a->prefix.v4.s_addr) < ntohl(b->prefix.v4.s_addr)) + return (-1); + if (ntohl(a->prefix.v4.s_addr) > ntohl(b->prefix.v4.s_addr)) + return (1); + break; +- case AF_INET6: ++ case AID_INET6: + i = memcmp(&a->prefix.v6, &b->prefix.v6, + sizeof(struct in6_addr)); + if (i > 0) +@@ -140,6 +151,25 @@ up_prefix_cmp(struct update_prefix *a, s + if (i < 0) + return (-1); + break; ++ case AID_VPN_IPv4: ++ if (betoh64(a->prefix.vpn4.rd) < betoh64(b->prefix.vpn4.rd)) ++ return (-1); ++ if (betoh64(a->prefix.vpn4.rd) > betoh64(b->prefix.vpn4.rd)) ++ return (1); ++ if (ntohl(a->prefix.v4.s_addr) < ntohl(b->prefix.v4.s_addr)) ++ return (-1); ++ if (ntohl(a->prefix.v4.s_addr) > ntohl(b->prefix.v4.s_addr)) ++ return (1); ++ if (a->prefixlen < b->prefixlen) ++ return (-1); ++ if (a->prefixlen > b->prefixlen) ++ return (1); ++ if (a->prefix.vpn4.labellen < b->prefix.vpn4.labellen) ++ return (-1); ++ if (a->prefix.vpn4.labellen > b->prefix.vpn4.labellen) ++ return (1); ++ return (memcmp(a->prefix.vpn4.labelstack, ++ b->prefix.vpn4.labelstack, a->prefix.vpn4.labellen)); + default: + fatalx("pt_prefix_cmp: unknown af"); + } +@@ -174,18 +204,8 @@ up_add(struct rde_peer *peer, struct upd + struct uplist_attr *upl = NULL; + struct uplist_prefix *wdl = NULL; + +- switch (p->prefix.af) { +- case AF_INET: +- upl = &peer->updates; +- wdl = &peer->withdraws; +- break; +- case AF_INET6: +- upl = &peer->updates6; +- wdl = &peer->withdraws6; +- break; +- default: +- fatalx("up_add: unknown AF"); +- } ++ upl = &peer->updates[p->prefix.aid]; ++ wdl = &peer->withdraws[p->prefix.aid]; + + /* 1. search for attr */ + if (a != NULL && (na = RB_FIND(uptree_attr, &peer->up_attrs, a)) == +@@ -270,21 +290,14 @@ up_test_update(struct rde_peer *peer, st /* Do not send routes back to sender */ return (0); @@ -39,154 +152,461 @@ diff -u -p -r1.1.1.1 -r1.4 if (p->aspath->flags & F_ATTR_LOOP) fatalx("try to send out a looped path"); -@@ -360,7 +369,7 @@ up_generate(struct rde_peer *peer, struc - if (asp) { - ua = calloc(1, sizeof(struct update_attr)); + pt_getaddr(p->prefix, &addr); +- switch (addr.af) { +- case AF_INET: +- if (peer->capa_announced.mp_v4 == SAFI_NONE && +- peer->capa_received.mp_v6 != SAFI_NONE) +- return (-1); +- break; +- case AF_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) { + /* +@@ -325,13 +338,13 @@ up_test_update(struct rde_peer *peer, st + } + + /* well known communities */ +- if (rde_filter_community(p->aspath, ++ if (community_match(p->aspath, + COMMUNITY_WELLKNOWN, COMMUNITY_NO_ADVERTISE)) + return (0); +- if (peer->conf.ebgp && rde_filter_community(p->aspath, ++ if (peer->conf.ebgp && community_match(p->aspath, + COMMUNITY_WELLKNOWN, COMMUNITY_NO_EXPORT)) + return (0); +- if (peer->conf.ebgp && rde_filter_community(p->aspath, ++ if (peer->conf.ebgp && community_match(p->aspath, + COMMUNITY_WELLKNOWN, COMMUNITY_NO_EXPSUBCONFED)) + return (0); + +@@ -362,7 +375,7 @@ up_generate(struct rde_peer *peer, struc if (ua == NULL) -- fatal("up_generate_updates"); -+ fatal("up_generate"); + fatal("up_generate"); - if (up_generate_attr(peer, ua, asp, addr->af) == -1) { +- if (up_generate_attr(peer, ua, asp, addr->af) == -1) { ++ if (up_generate_attr(peer, ua, asp, addr->aid) == -1) { log_warnx("generation of bgp path attributes failed"); -@@ -379,7 +388,7 @@ up_generate(struct rde_peer *peer, struc - - up = calloc(1, sizeof(struct update_prefix)); - if (up == NULL) -- fatal("up_generate_updates"); -+ fatal("up_generate"); - up->prefix = *addr; - up->prefixlen = prefixlen; - -@@ -404,9 +413,9 @@ up_generate_updates(struct filter_head * - return; - - pt_getaddr(old->prefix, &addr); -- if (rde_filter(NULL, rules, peer, old->aspath, &addr, -- old->prefix->prefixlen, old->aspath->peer, DIR_OUT) == -- ACTION_DENY) -+ if (rde_filter(peer->ribid, NULL, rules, peer, old->aspath, -+ &addr, old->prefix->prefixlen, old->aspath->peer, -+ DIR_OUT) == ACTION_DENY) - return; - - /* withdraw prefix */ -@@ -423,9 +432,9 @@ up_generate_updates(struct filter_head * - } + free(ua); + return (-1); +@@ -444,18 +457,12 @@ up_generate_updates(struct filter_head * + /* 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; - pt_getaddr(new->prefix, &addr); -- if (rde_filter(&asp, rules, peer, new->aspath, &addr, -- new->prefix->prefixlen, new->aspath->peer, DIR_OUT) == -- ACTION_DENY) { -+ if (rde_filter(peer->ribid, &asp, rules, peer, new->aspath, -+ &addr, new->prefix->prefixlen, new->aspath->peer, -+ DIR_OUT) == ACTION_DENY) { - path_put(asp); - up_generate_updates(rules, peer, NULL, old); - return; -@@ -473,8 +482,8 @@ up_generate_default(struct filter_head * - bzero(&addr, sizeof(addr)); - addr.af = af; - -- if (rde_filter(&fasp, rules, peer, asp, &addr, 0, NULL, DIR_OUT) == -- ACTION_DENY) { -+ if (rde_filter(peer->ribid, &fasp, rules, peer, asp, &addr, 0, NULL, -+ DIR_OUT) == ACTION_DENY) { - path_put(fasp); - path_put(asp); +- 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; -@@ -617,7 +626,7 @@ up_generate_attr(struct rde_peer *peer, - u_char *pdata; - u_int32_t tmp32; - in_addr_t nexthop; -- int r, ismp = 0, neednewpath = 0; -+ int flags, r, ismp = 0, neednewpath = 0; - u_int16_t len = sizeof(up_attr_buf), wlen = 0, plen; - u_int8_t l; - -@@ -629,7 +638,7 @@ up_generate_attr(struct rde_peer *peer, - - /* aspath */ - if (!peer->conf.ebgp || -- rde_decisionflags() & BGPD_FLAG_DECISION_TRANS_AS) -+ peer->conf.flags & PEERFLAG_TRANS_AS) - pdata = aspath_prepend(a->aspath, rde_local_as(), 0, &plen); - else - pdata = aspath_prepend(a->aspath, rde_local_as(), 1, &plen); -@@ -762,25 +771,29 @@ up_generate_attr(struct rde_peer *peer, - /* NEW to OLD conversion when going sending stuff to a 2byte AS peer */ - if (neednewpath) { - if (!peer->conf.ebgp || -- rde_decisionflags() & BGPD_FLAG_DECISION_TRANS_AS) -+ peer->conf.flags & PEERFLAG_TRANS_AS) - pdata = aspath_prepend(a->aspath, rde_local_as(), 0, - &plen); - else - pdata = aspath_prepend(a->aspath, rde_local_as(), 1, - &plen); -+ flags = ATTR_OPTIONAL|ATTR_TRANSITIVE; -+ if (!(a->flags & F_PREFIX_ANNOUNCED)) -+ flags |= ATTR_PARTIAL; - if (plen == 0) - r = 0; -- else if ((r = attr_write(up_attr_buf + wlen, len, -- ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_NEW_ASPATH, -- pdata, plen)) == -1) -+ else if ((r = attr_write(up_attr_buf + wlen, len, flags, -+ ATTR_AS4_PATH, pdata, plen)) == -1) - return (-1); - wlen += r; len -= r; - free(pdata); + + asp = path_get(); +@@ -471,7 +478,7 @@ up_generate_default(struct filter_head * + + /* filter as usual */ + bzero(&addr, sizeof(addr)); +- addr.af = af; ++ addr.aid = aid; + + if (rde_filter(peer->ribid, &fasp, rules, peer, asp, &addr, 0, NULL, + DIR_OUT) == ACTION_DENY) { +@@ -491,6 +498,43 @@ up_generate_default(struct filter_head * + path_put(asp); + } + ++/* generate a EoR marker in the update list. This is a horrible hack. */ ++int ++up_generate_marker(struct rde_peer *peer, u_int8_t aid) ++{ ++ struct update_attr *ua; ++ struct update_attr *na = NULL; ++ struct uplist_attr *upl = NULL; ++ ++ ua = calloc(1, sizeof(struct update_attr)); ++ if (ua == NULL) ++ fatal("up_generate_marker"); ++ ++ upl = &peer->updates[aid]; ++ ++ /* 1. search for attr */ ++ if ((na = RB_FIND(uptree_attr, &peer->up_attrs, ua)) == NULL) { ++ /* 1.1 if not found -> add */ ++ TAILQ_INIT(&ua->prefix_h); ++ if (RB_INSERT(uptree_attr, &peer->up_attrs, ua) != NULL) { ++ log_warnx("uptree_attr insert failed"); ++ /* cleanup */ ++ free(ua); ++ return (-1); ++ } ++ TAILQ_INSERT_TAIL(upl, ua, attr_l); ++ peer->up_acnt++; ++ } else { ++ /* 1.2 if found -> use that, free ua */ ++ free(ua); ++ ua = na; ++ /* move to end of update queue */ ++ TAILQ_REMOVE(upl, ua, attr_l); ++ TAILQ_INSERT_TAIL(upl, ua, attr_l); ++ } ++ return (0); ++} ++ + u_char up_attr_buf[4096]; + + /* only for IPv4 */ +@@ -551,28 +595,41 @@ up_get_nexthop(struct rde_peer *peer, st + + int + up_generate_mp_reach(struct rde_peer *peer, struct update_attr *upa, +- struct rde_aspath *a, sa_family_t af) ++ struct rde_aspath *a, u_int8_t aid) + { + u_int16_t tmp; + +- switch (af) { +- case AF_INET6: ++ switch (aid) { ++ case AID_INET6: + upa->mpattr_len = 21; /* AFI + SAFI + NH LEN + NH + Reserved */ + upa->mpattr = malloc(upa->mpattr_len); + if (upa->mpattr == NULL) + fatal("up_generate_mp_reach"); +- tmp = htons(AFI_IPv6); ++ if (aid2afi(aid, &tmp, &upa->mpattr[2])) ++ fatalx("up_generate_mp_reachi: bad AID"); ++ tmp = htons(tmp); + memcpy(upa->mpattr, &tmp, sizeof(tmp)); +- upa->mpattr[2] = SAFI_UNICAST; + upa->mpattr[3] = sizeof(struct in6_addr); + upa->mpattr[20] = 0; /* Reserved must be 0 */ + + /* nexthop dance see also up_get_nexthop() */ +- if (peer->conf.ebgp == 0) { ++ if (a->flags & F_NEXTHOP_NOMODIFY) { ++ /* no modify flag set */ ++ if (a->nexthop == NULL) ++ memcpy(&upa->mpattr[4], &peer->local_v6_addr.v6, ++ sizeof(struct in6_addr)); ++ else ++ memcpy(&upa->mpattr[4], ++ &a->nexthop->exit_nexthop.v6, ++ sizeof(struct in6_addr)); ++ } else if (a->flags & F_NEXTHOP_SELF) ++ memcpy(&upa->mpattr[4], &peer->local_v6_addr.v6, ++ sizeof(struct in6_addr)); ++ else if (!peer->conf.ebgp) { + /* ibgp */ + if (a->nexthop == NULL || +- (a->nexthop->exit_nexthop.af == AF_INET6 && +- memcmp(&a->nexthop->exit_nexthop.v6, ++ (a->nexthop->exit_nexthop.aid == AID_INET6 && ++ !memcmp(&a->nexthop->exit_nexthop.v6, + &peer->remote_addr.v6, sizeof(struct in6_addr)))) + memcpy(&upa->mpattr[4], &peer->local_v6_addr.v6, + sizeof(struct in6_addr)); +@@ -603,6 +660,68 @@ up_generate_mp_reach(struct rde_peer *pe + memcpy(&upa->mpattr[4], &peer->local_v6_addr.v6, + sizeof(struct in6_addr)); + return (0); ++ case AID_VPN_IPv4: ++ upa->mpattr_len = 17; /* AFI + SAFI + NH LEN + NH + Reserved */ ++ upa->mpattr = calloc(upa->mpattr_len, 1); ++ if (upa->mpattr == NULL) ++ fatal("up_generate_mp_reach"); ++ if (aid2afi(aid, &tmp, &upa->mpattr[2])) ++ fatalx("up_generate_mp_reachi: bad AID"); ++ tmp = htons(tmp); ++ memcpy(upa->mpattr, &tmp, sizeof(tmp)); ++ upa->mpattr[3] = sizeof(u_int64_t) + sizeof(struct in_addr); ++ ++ /* nexthop dance see also up_get_nexthop() */ ++ if (a->flags & F_NEXTHOP_NOMODIFY) { ++ /* no modify flag set */ ++ if (a->nexthop == NULL) ++ memcpy(&upa->mpattr[12], ++ &peer->local_v4_addr.v4, ++ sizeof(struct in_addr)); ++ else ++ /* nexthops are stored as IPv4 addrs */ ++ memcpy(&upa->mpattr[12], ++ &a->nexthop->exit_nexthop.v4, ++ sizeof(struct in_addr)); ++ } else if (a->flags & F_NEXTHOP_SELF) ++ memcpy(&upa->mpattr[12], &peer->local_v4_addr.v4, ++ sizeof(struct in_addr)); ++ else if (!peer->conf.ebgp) { ++ /* ibgp */ ++ if (a->nexthop == NULL || ++ (a->nexthop->exit_nexthop.aid == AID_INET && ++ !memcmp(&a->nexthop->exit_nexthop.v4, ++ &peer->remote_addr.v4, sizeof(struct in_addr)))) ++ memcpy(&upa->mpattr[12], ++ &peer->local_v4_addr.v4, ++ sizeof(struct in_addr)); ++ else ++ memcpy(&upa->mpattr[12], ++ &a->nexthop->exit_nexthop.v4, ++ sizeof(struct in_addr)); ++ } else if (peer->conf.distance == 1) { ++ /* ebgp directly connected */ ++ if (a->nexthop != NULL && ++ a->nexthop->flags & NEXTHOP_CONNECTED) ++ if (prefix_compare(&peer->remote_addr, ++ &a->nexthop->nexthop_net, ++ a->nexthop->nexthop_netlen) == 0) { ++ /* ++ * nexthop and peer are in the same ++ * subnet ++ */ ++ memcpy(&upa->mpattr[12], ++ &a->nexthop->exit_nexthop.v4, ++ sizeof(struct in_addr)); ++ return (0); ++ } ++ memcpy(&upa->mpattr[12], &peer->local_v4_addr.v4, ++ sizeof(struct in_addr)); ++ } else ++ /* ebgp multihop */ ++ memcpy(&upa->mpattr[12], &peer->local_v4_addr.v4, ++ sizeof(struct in_addr)); ++ return (0); + default: + break; } - if (newaggr) { -- if ((r = attr_write(up_attr_buf + wlen, len, -- ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_NEW_AGGREGATOR, -- newaggr->data, newaggr->len)) == -1) -+ flags = ATTR_OPTIONAL|ATTR_TRANSITIVE; -+ if (!(a->flags & F_PREFIX_ANNOUNCED)) -+ flags |= ATTR_PARTIAL; -+ if ((r = attr_write(up_attr_buf + wlen, len, flags, -+ ATTR_AS4_AGGREGATOR, newaggr->data, newaggr->len)) == -1) +@@ -611,7 +730,7 @@ up_generate_mp_reach(struct rde_peer *pe + + int + up_generate_attr(struct rde_peer *peer, struct update_attr *upa, +- struct rde_aspath *a, sa_family_t af) ++ struct rde_aspath *a, u_int8_t aid) + { + struct attr *oa, *newaggr = NULL; + u_char *pdata; +@@ -643,8 +762,8 @@ up_generate_attr(struct rde_peer *peer, + wlen += r; len -= r; + free(pdata); + +- switch (af) { +- case AF_INET: ++ switch (aid) { ++ case AID_INET: + nexthop = up_get_nexthop(peer, a); + if ((r = attr_write(up_attr_buf + wlen, len, ATTR_WELL_KNOWN, + ATTR_NEXTHOP, &nexthop, 4)) == -1) +@@ -659,9 +778,11 @@ up_generate_attr(struct rde_peer *peer, + /* + * The old MED from other peers MUST not be announced to others + * unless the MED is originating from us or the peer is an IBGP one. ++ * Only exception are routers with "transparent-as yes" set. + */ + if (a->flags & F_ATTR_MED && (peer->conf.ebgp == 0 || +- a->flags & F_ATTR_MED_ANNOUNCE)) { ++ a->flags & F_ATTR_MED_ANNOUNCE || ++ peer->conf.flags & PEERFLAG_TRANS_AS)) { + tmp32 = htonl(a->med); + if ((r = attr_write(up_attr_buf + wlen, len, ATTR_OPTIONAL, + ATTR_MED, &tmp32, 4)) == -1) +@@ -791,7 +912,7 @@ up_generate_attr(struct rde_peer *peer, + + /* write mp attribute to different buffer */ + if (ismp) +- if (up_generate_mp_reach(peer, upa, a, AF_INET6) == -1) ++ if (up_generate_mp_reach(peer, upa, a, aid) == -1) return (-1); - wlen += r; len -= r; + + /* the bgp path attributes are now stored in the global buf */ +@@ -810,6 +931,7 @@ up_dump_prefix(u_char *buf, int len, str + { + struct update_prefix *upp; + int r, wpos = 0; ++ u_int8_t i; + + while ((upp = TAILQ_FIRST(prefix_head)) != NULL) { + if ((r = prefix_write(buf + wpos, len - wpos, +@@ -820,13 +942,14 @@ up_dump_prefix(u_char *buf, int len, str + log_warnx("dequeuing update failed."); + TAILQ_REMOVE(upp->prefix_h, upp, prefix_l); + peer->up_pcnt--; +- if (upp->prefix_h == &peer->withdraws || +- upp->prefix_h == &peer->withdraws6) { +- peer->up_wcnt--; +- peer->prefix_sent_withdraw++; +- } else { +- peer->up_nlricnt--; +- peer->prefix_sent_update++; ++ for (i = 0; i < AID_MAX; i++) { ++ if (upp->prefix_h == &peer->withdraws[i]) { ++ peer->up_wcnt--; ++ peer->prefix_sent_withdraw++; ++ } else { ++ peer->up_nlricnt--; ++ peer->prefix_sent_update++; ++ } + } + free(upp); } -@@ -913,13 +926,7 @@ up_dump_mp_unreach(u_char *buf, u_int16_ +@@ -844,16 +967,21 @@ up_dump_attrnlri(u_char *buf, int len, s + * It is possible that a queued path attribute has no nlri prefix. + * Ignore and remove those path attributes. + */ +- while ((upa = TAILQ_FIRST(&peer->updates)) != NULL) ++ while ((upa = TAILQ_FIRST(&peer->updates[AID_INET])) != NULL) + if (TAILQ_EMPTY(&upa->prefix_h)) { ++ attr_len = upa->attr_len; + if (RB_REMOVE(uptree_attr, &peer->up_attrs, + upa) == NULL) + log_warnx("dequeuing update failed."); +- TAILQ_REMOVE(&peer->updates, upa, attr_l); ++ TAILQ_REMOVE(&peer->updates[AID_INET], upa, attr_l); + free(upa->attr); + free(upa->mpattr); + free(upa); + peer->up_acnt--; ++ /* XXX horrible hack, ++ * if attr_len is 0, it is a EoR marker */ ++ if (attr_len == 0) ++ return (-1); + } else + break; + +@@ -884,7 +1012,7 @@ up_dump_attrnlri(u_char *buf, int len, s + if (TAILQ_EMPTY(&upa->prefix_h)) { + if (RB_REMOVE(uptree_attr, &peer->up_attrs, upa) == NULL) + log_warnx("dequeuing update failed."); +- TAILQ_REMOVE(&peer->updates, upa, attr_l); ++ TAILQ_REMOVE(&peer->updates[AID_INET], upa, attr_l); + free(upa->attr); + free(upa->mpattr); + free(upa); +@@ -895,12 +1023,13 @@ up_dump_attrnlri(u_char *buf, int len, s + } + + u_char * +-up_dump_mp_unreach(u_char *buf, u_int16_t *len, struct rde_peer *peer) ++up_dump_mp_unreach(u_char *buf, u_int16_t *len, struct rde_peer *peer, ++ u_int8_t aid) + { + int wpos; + u_int16_t datalen, tmp; + u_int16_t attrlen = 2; /* attribute header (without len) */ +- u_int8_t flags = ATTR_OPTIONAL; ++ u_int8_t flags = ATTR_OPTIONAL, safi; + + /* + * reserve space for withdraw len, attr len, the attribute header +@@ -912,7 +1041,7 @@ up_dump_mp_unreach(u_char *buf, u_int16_ return (NULL); - datalen += 3; /* afi + safi */ -- if (datalen > 255) { -- attrlen += 2 + datalen; -- flags |= ATTR_EXTLEN; -- } else { -- attrlen += 1 + datalen; -- buf++; -- } -+ + datalen = up_dump_prefix(buf + wpos, *len - wpos, +- &peer->withdraws6, peer); ++ &peer->withdraws[aid], peer); + if (datalen == 0) + return (NULL); + +@@ -920,9 +1049,11 @@ up_dump_mp_unreach(u_char *buf, u_int16_ + /* prepend header, need to do it reverse */ /* safi & afi */ - buf[--wpos] = SAFI_UNICAST; -@@ -929,11 +936,15 @@ up_dump_mp_unreach(u_char *buf, u_int16_ +- buf[--wpos] = SAFI_UNICAST; ++ if (aid2afi(aid, &tmp, &safi)) ++ fatalx("up_dump_mp_unreach: bad AID"); ++ buf[--wpos] = safi; + wpos -= sizeof(u_int16_t); +- tmp = htons(AFI_IPv6); ++ tmp = htons(tmp); + memcpy(buf + wpos, &tmp, sizeof(u_int16_t)); /* attribute length */ - if (datalen > 255) { -+ attrlen += 2 + datalen; -+ flags |= ATTR_EXTLEN; - wpos -= sizeof(u_int16_t); - tmp = htons(datalen); - memcpy(buf + wpos, &tmp, sizeof(u_int16_t)); -- } else -+ } else { -+ attrlen += 1 + datalen; - buf[--wpos] = (u_char)datalen; -+ } +@@ -959,33 +1090,39 @@ up_dump_mp_unreach(u_char *buf, u_int16_ + return (buf + wpos); + } - /* mp attribute */ - buf[--wpos] = (u_char)ATTR_MP_UNREACH_NLRI; -@@ -954,7 +965,7 @@ up_dump_mp_unreach(u_char *buf, u_int16_ - /* total length includes the two 2-bytes length fields. */ - *len = attrlen + 2 * sizeof(u_int16_t); +-u_char * +-up_dump_mp_reach(u_char *buf, u_int16_t *len, struct rde_peer *peer) ++int ++up_dump_mp_reach(u_char *buf, u_int16_t *len, struct rde_peer *peer, ++ u_int8_t aid) + { + struct update_attr *upa; + int wpos; +- u_int16_t datalen, tmp; ++ u_int16_t attr_len, datalen, tmp; + u_int8_t flags = ATTR_OPTIONAL; -- return (buf); -+ return (buf + wpos); - } + /* + * It is possible that a queued path attribute has no nlri prefix. + * Ignore and remove those path attributes. + */ +- while ((upa = TAILQ_FIRST(&peer->updates6)) != NULL) ++ while ((upa = TAILQ_FIRST(&peer->updates[aid])) != NULL) + if (TAILQ_EMPTY(&upa->prefix_h)) { ++ attr_len = upa->attr_len; + if (RB_REMOVE(uptree_attr, &peer->up_attrs, + upa) == NULL) + log_warnx("dequeuing update failed."); +- TAILQ_REMOVE(&peer->updates6, upa, attr_l); ++ TAILQ_REMOVE(&peer->updates[aid], upa, attr_l); + free(upa->attr); + free(upa->mpattr); + free(upa); + peer->up_acnt--; ++ /* XXX horrible hack, ++ * if attr_len is 0, it is a EoR marker */ ++ if (attr_len == 0) ++ return (-1); + } else + break; - u_char * + if (upa == NULL) +- return (NULL); ++ return (-2); + + /* + * reserve space for attr len, the attributes, the +@@ -993,12 +1130,12 @@ up_dump_mp_reach(u_char *buf, u_int16_t + */ + wpos = 2 + 2 + upa->attr_len + 4 + upa->mpattr_len; + if (*len < wpos) +- return (NULL); ++ return (-2); + + datalen = up_dump_prefix(buf + wpos, *len - wpos, + &upa->prefix_h, peer); + if (datalen == 0) +- return (NULL); ++ return (-2); + + if (upa->mpattr_len == 0 || upa->mpattr == NULL) + fatalx("mulitprotocol update without MP attrs"); +@@ -1038,7 +1175,7 @@ up_dump_mp_reach(u_char *buf, u_int16_t + if (TAILQ_EMPTY(&upa->prefix_h)) { + if (RB_REMOVE(uptree_attr, &peer->up_attrs, upa) == NULL) + log_warnx("dequeuing update failed."); +- TAILQ_REMOVE(&peer->updates6, upa, attr_l); ++ TAILQ_REMOVE(&peer->updates[aid], upa, attr_l); + free(upa->attr); + free(upa->mpattr); + free(upa); +@@ -1046,6 +1183,5 @@ up_dump_mp_reach(u_char *buf, u_int16_t + } + + *len = datalen + 4; +- return (buf + wpos); ++ return (wpos); + } +- |