2009-06-30 09:35:13 +02:00
|
|
|
Index: bgpd/rde_update.c
|
|
|
|
===================================================================
|
|
|
|
RCS file: /home/cvs/private/hrs/openbgpd/bgpd/rde_update.c,v
|
2010-02-16 20:27:03 +01:00
|
|
|
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
|
2009-07-19 09:31:04 +02:00
|
|
|
@@ -1,4 +1,4 @@
|
2010-02-16 20:27:03 +01:00
|
|
|
-/* $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 $ */
|
2009-07-19 09:31:04 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
|
2010-02-16 20:27:03 +01:00
|
|
|
@@ -17,19 +17,26 @@
|
2008-12-17 16:58:32 +01:00
|
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/queue.h>
|
2009-06-30 09:35:13 +02:00
|
|
|
+#if defined(__FreeBSD__) /* sys/hash.h */
|
|
|
|
+#include "hash.h"
|
|
|
|
+#else
|
|
|
|
#include <sys/hash.h>
|
|
|
|
+#endif /* defined(__FreeBSD__) */
|
2008-12-17 16:58:32 +01:00
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
2009-06-30 09:35:13 +02:00
|
|
|
+#if defined(__FreeBSD__) /* limits.h */
|
|
|
|
+#include <limits.h>
|
|
|
|
+#endif /* defined(__FreeBSD__) */
|
2008-12-17 16:58:32 +01:00
|
|
|
|
|
|
|
#include "bgpd.h"
|
|
|
|
#include "rde.h"
|
2010-02-16 20:27:03 +01:00
|
|
|
|
|
|
|
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
|
2009-11-02 08:09:37 +01:00
|
|
|
/* Do not send routes back to sender */
|
|
|
|
return (0);
|
|
|
|
|
|
|
|
+ if (p->aspath->flags & F_ATTR_PARSE_ERR)
|
|
|
|
+ fatalx("try to send out a botched path");
|
|
|
|
if (p->aspath->flags & F_ATTR_LOOP)
|
|
|
|
fatalx("try to send out a looped path");
|
|
|
|
|
2010-02-16 20:27:03 +01:00
|
|
|
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
|
2009-07-19 09:31:04 +02:00
|
|
|
if (ua == NULL)
|
2010-02-16 20:27:03 +01:00
|
|
|
fatal("up_generate");
|
2009-07-19 09:31:04 +02:00
|
|
|
|
2010-02-16 20:27:03 +01:00
|
|
|
- if (up_generate_attr(peer, ua, asp, addr->af) == -1) {
|
|
|
|
+ if (up_generate_attr(peer, ua, asp, addr->aid) == -1) {
|
2009-07-19 09:31:04 +02:00
|
|
|
log_warnx("generation of bgp path attributes failed");
|
2010-02-16 20:27:03 +01:00
|
|
|
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;
|
2009-07-19 09:31:04 +02:00
|
|
|
|
2010-02-16 20:27:03 +01:00
|
|
|
- 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)
|
2009-07-19 09:31:04 +02:00
|
|
|
return;
|
2010-02-16 20:27:03 +01:00
|
|
|
|
|
|
|
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;
|
2009-07-19 09:31:04 +02:00
|
|
|
}
|
2010-02-16 20:27:03 +01:00
|
|
|
@@ -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)
|
2009-07-19 09:31:04 +02:00
|
|
|
return (-1);
|
2010-02-16 20:27:03 +01:00
|
|
|
|
|
|
|
/* 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);
|
2009-07-19 09:31:04 +02:00
|
|
|
}
|
2010-02-16 20:27:03 +01:00
|
|
|
@@ -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_
|
2009-07-19 09:31:04 +02:00
|
|
|
return (NULL);
|
|
|
|
|
2010-02-16 20:27:03 +01:00
|
|
|
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_
|
|
|
|
|
2009-07-19 09:31:04 +02:00
|
|
|
/* prepend header, need to do it reverse */
|
|
|
|
/* safi & afi */
|
2010-02-16 20:27:03 +01:00
|
|
|
- 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));
|
2009-07-19 09:31:04 +02:00
|
|
|
|
|
|
|
/* attribute length */
|
2010-02-16 20:27:03 +01:00
|
|
|
@@ -959,33 +1090,39 @@ up_dump_mp_unreach(u_char *buf, u_int16_
|
|
|
|
return (buf + wpos);
|
|
|
|
}
|
2009-07-19 09:31:04 +02:00
|
|
|
|
2010-02-16 20:27:03 +01:00
|
|
|
-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;
|
2009-07-19 09:31:04 +02:00
|
|
|
|
2010-02-16 20:27:03 +01:00
|
|
|
/*
|
|
|
|
* 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;
|
2009-07-19 09:31:04 +02:00
|
|
|
|
2010-02-16 20:27:03 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
-
|