summaryrefslogtreecommitdiff
path: root/usr.sbin/bgpd
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2004-08-06 12:04:09 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2004-08-06 12:04:09 +0000
commit1702f711eb5a6da7d226fd633c14c8a22cc5c448 (patch)
treef5642b4adf97d5d2f86ff168b7bbb9855f6a18b1 /usr.sbin/bgpd
parent232c877040ea69df2d195a2de71e66da045030f0 (diff)
Monster diff to get one step closer to IPv6 support.
Cleanup path attribute handling. First of all kill struct attr_flags, all those infos are now in struct rde_aspath. Second move attribute parser functions into rde.c, rde_attr.c is shared between bgpd and bgpctl. Third reimplementation of the nexthop handling. Make it IPv6 ready and fix some major bug relating to "set nexthop". henning@ OK if it breaks nothing
Diffstat (limited to 'usr.sbin/bgpd')
-rw-r--r--usr.sbin/bgpd/bgpd.h3
-rw-r--r--usr.sbin/bgpd/mrt.c26
-rw-r--r--usr.sbin/bgpd/rde.c707
-rw-r--r--usr.sbin/bgpd/rde.h127
-rw-r--r--usr.sbin/bgpd/rde_attr.c568
-rw-r--r--usr.sbin/bgpd/rde_decide.c33
-rw-r--r--usr.sbin/bgpd/rde_filter.c60
-rw-r--r--usr.sbin/bgpd/rde_rib.c521
-rw-r--r--usr.sbin/bgpd/rde_update.c213
9 files changed, 1151 insertions, 1107 deletions
diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h
index 1c12d39ee98..8fe5562dbe9 100644
--- a/usr.sbin/bgpd/bgpd.h
+++ b/usr.sbin/bgpd/bgpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bgpd.h,v 1.138 2004/08/05 15:58:21 claudio Exp $ */
+/* $OpenBSD: bgpd.h,v 1.139 2004/08/06 12:04:08 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -160,6 +160,7 @@ struct filter_set {
u_int16_t flags;
u_int32_t localpref;
u_int32_t med;
+ /*XXX this nexthop thing should be changed to one bgpd_addr */
struct in_addr nexthop;
struct in6_addr nexthop6;
u_int8_t prepend;
diff --git a/usr.sbin/bgpd/mrt.c b/usr.sbin/bgpd/mrt.c
index ddecc29a2ad..0c9b369123c 100644
--- a/usr.sbin/bgpd/mrt.c
+++ b/usr.sbin/bgpd/mrt.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mrt.c,v 1.38 2004/08/05 16:26:56 claudio Exp $ */
+/* $OpenBSD: mrt.c,v 1.39 2004/08/06 12:04:08 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
@@ -32,8 +32,9 @@
#include "mrt.h"
-static u_int16_t mrt_attr_length(struct attr_flags *);
-static int mrt_attr_dump(void *, u_int16_t, struct attr_flags *);
+static u_int16_t mrt_attr_length(struct rde_aspath *);
+static int mrt_attr_dump(void *, u_int16_t, struct rde_aspath *,
+ struct bgpd_addr *);
static int mrt_dump_entry(struct mrt *, struct prefix *,
u_int16_t, struct peer_config *);
static int mrt_dump_header(struct buf *, u_int16_t, u_int16_t,
@@ -153,7 +154,7 @@ mrt_dump_state(struct mrt *mrt, u_int16_t old_state, u_int16_t new_state,
}
static u_int16_t
-mrt_attr_length(struct attr_flags *a)
+mrt_attr_length(struct rde_aspath *a)
{
struct attr *oa;
u_int16_t alen, plen;
@@ -171,7 +172,8 @@ mrt_attr_length(struct attr_flags *a)
}
static int
-mrt_attr_dump(void *p, u_int16_t len, struct attr_flags *a)
+mrt_attr_dump(void *p, u_int16_t len, struct rde_aspath *a,
+ struct bgpd_addr *nexthop)
{
struct attr *oa;
u_char *buf = p;
@@ -194,7 +196,7 @@ mrt_attr_dump(void *p, u_int16_t len, struct attr_flags *a)
/* nexthop, already network byte order */
if ((r = attr_write(buf + wlen, len, ATTR_WELL_KNOWN, ATTR_NEXTHOP,
- &a->nexthop, 4)) == -1)
+ &nexthop->v4.s_addr, 4)) == -1)
return (-1);
wlen += r; len -= r;
@@ -231,10 +233,10 @@ mrt_dump_entry(struct mrt *mrt, struct prefix *p, u_int16_t snum,
{
struct buf *buf;
void *bptr;
- struct bgpd_addr addr;
+ struct bgpd_addr addr, *nh;
u_int16_t len, attr_len;
- attr_len = mrt_attr_length(&p->aspath->flags);
+ attr_len = mrt_attr_length(p->aspath);
len = MRT_DUMP_HEADER_SIZE + attr_len;
pt_getaddr(p->prefix, &addr);
@@ -264,7 +266,13 @@ mrt_dump_entry(struct mrt *mrt, struct prefix *p, u_int16_t snum,
return (-1);
}
- if (mrt_attr_dump(bptr, attr_len, &p->aspath->flags) == -1) {
+ if (p->aspath->nexthop == NULL) {
+ bzero(&addr, sizeof(struct bgpd_addr));
+ addr.af = AF_INET;
+ nh = &addr;
+ } else
+ nh = &p->aspath->nexthop->exit_nexthop;
+ if (mrt_attr_dump(bptr, attr_len, p->aspath, nh) == -1) {
log_warnx("mrt_dump_entry: mrt_attr_dump error");
buf_free(buf);
return (-1);
diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c
index 22f51212ceb..e56d5b78237 100644
--- a/usr.sbin/bgpd/rde.c
+++ b/usr.sbin/bgpd/rde.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.c,v 1.138 2004/08/06 11:51:19 claudio Exp $ */
+/* $OpenBSD: rde.c,v 1.139 2004/08/06 12:04:08 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -41,6 +41,13 @@ void rde_sighdlr(int);
void rde_dispatch_imsg_session(struct imsgbuf *);
void rde_dispatch_imsg_parent(struct imsgbuf *);
int rde_update_dispatch(struct imsg *);
+int rde_attr_parse(u_char *, u_int16_t, struct rde_aspath *, int,
+ enum enforce_as, u_int16_t, struct mpattr *);
+u_char *rde_attr_error(u_char *, u_int16_t, struct rde_aspath *,
+ u_int8_t *, u_int16_t *);
+u_int8_t rde_attr_missing(struct rde_aspath *, int, u_int16_t);
+int rde_get_mp_nexthop(u_char *, u_int16_t, u_int16_t,
+ struct rde_aspath *);
int rde_update_get_prefix(u_char *, u_int16_t, struct bgpd_addr *,
u_int8_t *);
int rde_update_get_prefix6(u_char *, u_int16_t, struct bgpd_addr *,
@@ -48,9 +55,9 @@ int rde_update_get_prefix6(u_char *, u_int16_t, struct bgpd_addr *,
void rde_update_err(struct rde_peer *, u_int8_t , u_int8_t,
void *, u_int16_t);
void rde_update_log(const char *,
- const struct rde_peer *, const struct attr_flags *,
+ const struct rde_peer *, const struct bgpd_addr *,
const struct bgpd_addr *, u_int8_t);
-int rde_reflector(struct rde_peer *, struct attr_flags *);
+int rde_reflector(struct rde_peer *, struct rde_aspath *);
void rde_dump_rib_as(struct prefix *, pid_t);
void rde_dump_rib_prefix(struct prefix *, pid_t);
void rde_dump_upcall(struct pt_entry *, void *);
@@ -501,16 +508,16 @@ int
rde_update_dispatch(struct imsg *imsg)
{
struct rde_peer *peer;
- u_char *p, *emsg, *mpp;
- int pos;
+ struct rde_aspath *asp = NULL, *fasp;
+ u_char *p, *emsg, *mpp = NULL;
+ int pos = 0;
u_int16_t afi, len, mplen;
u_int16_t withdrawn_len;
u_int16_t attrpath_len;
u_int16_t nlri_len, size;
u_int8_t prefixlen, safi, subtype;
struct bgpd_addr prefix;
- struct attr_flags attrs, fattrs;
- struct attr *mpattr;
+ struct mpattr mpa;
peer = peer_get(imsg->hdr.peerid);
if (peer == NULL) /* unknown peer, cannot happen */
@@ -537,18 +544,23 @@ rde_update_dispatch(struct imsg *imsg)
rde_update_err(peer, ERR_UPDATE, ERR_UPD_ATTRLIST, NULL, 0);
return (-1);
}
+
+ nlri_len =
+ imsg->hdr.len - IMSG_HEADER_SIZE - 4 - withdrawn_len - attrpath_len;
+ bzero(&mpa, sizeof(mpa));
+
if (attrpath_len != 0) { /* 0 = no NLRI information in this message */
/* parse path attributes */
- attr_init(&attrs);
+ asp = path_get();
while (len > 0) {
- if ((pos = attr_parse(p, len, &attrs,
+ if ((pos = rde_attr_parse(p, len, asp,
peer->conf.ebgp, peer->conf.enforce_as,
- peer->conf.remote_as)) < 0) {
- emsg = attr_error(p, len, &attrs,
+ peer->conf.remote_as, &mpa)) < 0) {
+ emsg = rde_attr_error(p, len, asp,
&subtype, &size);
rde_update_err(peer, ERR_UPDATE, subtype,
emsg, size);
- attr_free(&attrs);
+ path_put(asp);
return (-1);
}
p += pos;
@@ -556,15 +568,16 @@ rde_update_dispatch(struct imsg *imsg)
}
/* check for missing but necessary attributes */
- if ((subtype = attr_missing(&attrs, peer->conf.ebgp)) != 0) {
+ if ((subtype = rde_attr_missing(asp, peer->conf.ebgp,
+ nlri_len))) {
rde_update_err(peer, ERR_UPDATE, ERR_UPD_MISSNG_WK_ATTR,
&subtype, sizeof(u_int8_t));
- attr_free(&attrs);
+ path_put(asp);
return (-1);
}
- if (rde_reflector(peer, &attrs) != 1) {
- attr_free(&attrs);
+ if (rde_reflector(peer, asp) != 1) {
+ path_put(asp);
return (0);
}
}
@@ -584,7 +597,7 @@ rde_update_dispatch(struct imsg *imsg)
rde_update_err(peer, ERR_UPDATE, ERR_UPD_NETWORK,
NULL, 0);
if (attrpath_len != 0)
- attr_free(&attrs);
+ path_put(asp);
return (-1);
}
if (prefixlen > 32) {
@@ -592,7 +605,7 @@ rde_update_dispatch(struct imsg *imsg)
rde_update_err(peer, ERR_UPDATE, ERR_UPD_NETWORK,
NULL, 0);
if (attrpath_len != 0)
- attr_free(&attrs);
+ path_put(asp);
return (-1);
}
@@ -608,11 +621,13 @@ rde_update_dispatch(struct imsg *imsg)
prefix_remove(peer, &prefix, prefixlen);
}
+ if (attrpath_len == 0) /* 0 = no NLRI information in this message */
+ return (0);
+
/* withdraw MP_UNREACH_NRLI if available */
- if (attrpath_len != 0 &&
- (mpattr = attr_optget(&attrs, ATTR_MP_UNREACH_NLRI)) != NULL) {
- mpp = mpattr->data;
- mplen = mpattr->len;
+ if (mpa.unreach_len != 0) {
+ mpp = mpa.unreach;
+ mplen = mpa.unreach_len;
memcpy(&afi, mpp, 2);
mpp += 2;
mplen -= 2;
@@ -628,8 +643,8 @@ rde_update_dispatch(struct imsg *imsg)
"bad IPv6 withdraw prefix");
rde_update_err(peer, ERR_UPDATE,
ERR_UPD_OPTATTR,
- mpattr->data, mpattr->len);
- attr_free(&attrs);
+ mpa.unreach, mpa.unreach_len);
+ path_put(asp);
return (-1);
}
if (prefixlen > 128) {
@@ -637,8 +652,8 @@ rde_update_dispatch(struct imsg *imsg)
"bad IPv6 withdraw prefix");
rde_update_err(peer, ERR_UPDATE,
ERR_UPD_OPTATTR,
- mpattr->data, mpattr->len);
- attr_free(&attrs);
+ mpa.unreach, mpa.unreach_len);
+ path_put(asp);
return (-1);
}
@@ -654,28 +669,23 @@ rde_update_dispatch(struct imsg *imsg)
&prefix, prefixlen);
prefix_remove(peer, &prefix, prefixlen);
}
+ break;
default:
fatalx("unsupported multipath AF");
}
}
- if (attrpath_len == 0) /* 0 = no NLRI information in this message */
- return (0);
-
/* shift to NLRI information */
p += 2 + attrpath_len;
- nlri_len =
- imsg->hdr.len - IMSG_HEADER_SIZE - 4 - withdrawn_len - attrpath_len;
-
/* aspath needs to be loop free nota bene this is not a hard error */
- if (peer->conf.ebgp && !aspath_loopfree(attrs.aspath, conf->as)) {
- attr_free(&attrs);
+ if (peer->conf.ebgp && !aspath_loopfree(asp->aspath, conf->as)) {
+ path_put(asp);
return (0);
}
/* apply default overrides */
- rde_apply_set(&attrs, &peer->conf.attrset);
+ rde_apply_set(asp, &peer->conf.attrset);
/* parse nlri prefix */
while (nlri_len > 0) {
@@ -684,14 +694,14 @@ rde_update_dispatch(struct imsg *imsg)
log_peer_warnx(&peer->conf, "bad nlri prefix");
rde_update_err(peer, ERR_UPDATE, ERR_UPD_NETWORK,
NULL, 0);
- attr_free(&attrs);
+ path_put(asp);
return (-1);
}
if (prefixlen > 32) {
log_peer_warnx(&peer->conf, "bad nlri prefix");
rde_update_err(peer, ERR_UPDATE, ERR_UPD_NETWORK,
NULL, 0);
- attr_free(&attrs);
+ path_put(asp);
return (-1);
}
@@ -702,11 +712,11 @@ rde_update_dispatch(struct imsg *imsg)
* We need to copy attrs before calling the filter because
* the filter may change the attributes.
*/
- attr_copy(&fattrs, &attrs);
+ fasp = path_copy(asp);
/* input filter */
- if (rde_filter(peer, &fattrs, &prefix, prefixlen,
+ if (rde_filter(peer, fasp, &prefix, prefixlen,
DIR_IN) == ACTION_DENY) {
- attr_free(&fattrs);
+ path_put(fasp);
continue;
}
@@ -716,19 +726,20 @@ rde_update_dispatch(struct imsg *imsg)
log_peer_warnx(&peer->conf, "prefix limit reached");
rde_update_err(peer, ERR_CEASE, ERR_CEASE_MAX_PREFIX,
NULL, 0);
- attr_free(&attrs);
- attr_free(&fattrs);
+ path_put(asp);
+ path_put(fasp);
return (-1);
}
- rde_update_log("update", peer, &fattrs, &prefix, prefixlen);
- path_update(peer, &fattrs, &prefix, prefixlen);
+ rde_update_log("update", peer, &asp->nexthop->exit_nexthop,
+ &prefix, prefixlen);
+ path_update(peer, fasp, &prefix, prefixlen);
}
/* add MP_REACH_NLRI if available */
- if ((mpattr = attr_optget(&attrs, ATTR_MP_REACH_NLRI)) != NULL) {
- mpp = mpattr->data;
- mplen = mpattr->len;
+ if (mpa.reach_len != 0) {
+ mpp = mpa.reach;
+ mplen = mpa.reach_len;
memcpy(&afi, mpp, 2);
mpp += 2;
mplen -= 2;
@@ -736,25 +747,19 @@ rde_update_dispatch(struct imsg *imsg)
safi = *mpp++;
mplen--;
- if ((pos = attr_mp_nexthop_check(mpp, mplen, afi)) == -1) {
+ /*
+ * this works because asp is not linked.
+ */
+ if ((pos = rde_get_mp_nexthop(mpp, mplen, afi, asp)) == -1) {
log_peer_warnx(&peer->conf, "bad IPv6 nlri prefix");
rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
- mpattr->data, mpattr->len);
- attr_free(&attrs);
+ mpa.reach, mpa.reach_len);
+ path_put(asp);
return (-1);
}
-
mpp += pos;
mplen -= pos;
- if (*p++ != NULL) {
- /* XXX this is ugly */
- log_peer_warnx(&peer->conf, "SNPA are not supported");
- rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR,
- mpattr->data, mpattr->len);
- attr_free(&attrs);
- return (-1);
- }
switch (afi) {
case AFI_IPv6:
while (mplen > 0) {
@@ -764,30 +769,29 @@ rde_update_dispatch(struct imsg *imsg)
"bad IPv6 nlri prefix");
rde_update_err(peer, ERR_UPDATE,
ERR_UPD_OPTATTR,
- mpattr->data, mpattr->len);
- attr_free(&attrs);
+ mpa.reach, mpa.reach_len);
+ path_put(asp);
return (-1);
}
if (prefixlen > 128) {
rde_update_err(peer, ERR_UPDATE,
ERR_UPD_OPTATTR,
- mpattr->data, mpattr->len);
- attr_free(&attrs);
+ mpa.reach, mpa.reach_len);
+ path_put(asp);
return (-1);
}
mpp += pos;
mplen -= pos;
- attr_copy(&fattrs, &attrs);
+ fasp = path_copy(asp);
/* input filter */
- if (rde_filter(peer, &fattrs, &prefix,
+ if (rde_filter(peer, asp, &prefix,
prefixlen, DIR_IN) == ACTION_DENY) {
- attr_free(&fattrs);
+ path_put(fasp);
continue;
}
- /* XXX IPv4 and IPv6 together */
/* max prefix checker */
if (peer->conf.max_prefix &&
peer->prefix_cnt >= peer->conf.max_prefix) {
@@ -795,14 +799,15 @@ rde_update_dispatch(struct imsg *imsg)
"prefix limit reached");
rde_update_err(peer, ERR_CEASE,
ERR_CEASE_MAX_PREFIX, NULL, 0);
- attr_free(&attrs);
- attr_free(&fattrs);
+ path_put(asp);
+ path_put(fasp);
return (-1);
}
- rde_update_log("update", peer, &fattrs,
+ rde_update_log("update", peer,
+ &asp->nexthop->exit_nexthop,
&prefix, prefixlen);
- path_update(peer, &fattrs, &prefix, prefixlen);
+ path_update(peer, fasp, &prefix, prefixlen);
}
default:
fatalx("unsupported AF");
@@ -810,12 +815,437 @@ rde_update_dispatch(struct imsg *imsg)
}
/* need to free allocated attribute memory that is no longer used */
- attr_free(&attrs);
+ path_put(asp);
+
+ return (0);
+}
+
+/*
+ * BGP UPDATE parser functions
+ */
+
+/* attribute parser specific makros */
+#define UPD_READ(t, p, plen, n) \
+ do { \
+ memcpy(t, p, n); \
+ p += n; \
+ plen += n; \
+ } while (0)
+
+#define CHECK_FLAGS(s, t, m) \
+ (((s) & ~(ATTR_EXTLEN | (m))) == (t))
+
+#define WFLAG(s, t) \
+ do { \
+ if ((s) & (t)) \
+ return (-1); \
+ (s) |= (t); \
+ } while (0)
+
+int
+rde_attr_parse(u_char *p, u_int16_t len, struct rde_aspath *a, int ebgp,
+ enum enforce_as enforce_as, u_int16_t remote_as, struct mpattr *mpa)
+{
+ struct bgpd_addr nexthop;
+ u_int32_t tmp32;
+ u_int16_t attr_len;
+ u_int16_t plen = 0;
+ u_int8_t flags;
+ u_int8_t type;
+ u_int8_t tmp8;
+
+ if (len < 3)
+ return (-1);
+
+ UPD_READ(&flags, p, plen, 1);
+ UPD_READ(&type, p, plen, 1);
+
+ if (flags & ATTR_EXTLEN) {
+ if (len - plen < 2)
+ return (-1);
+ UPD_READ(&attr_len, p, plen, 2);
+ attr_len = ntohs(attr_len);
+ } else {
+ UPD_READ(&tmp8, p, plen, 1);
+ attr_len = tmp8;
+ }
+
+ if (len - plen < attr_len)
+ return (-1);
+
+ switch (type) {
+ case ATTR_UNDEF:
+ /* error! */
+ return (-1);
+ case ATTR_ORIGIN:
+ if (attr_len != 1)
+ return (-1);
+ if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
+ return (-1);
+ UPD_READ(&a->origin, p, plen, 1);
+ if (a->origin > ORIGIN_INCOMPLETE)
+ return (-1);
+ WFLAG(a->flags, F_ATTR_ORIGIN);
+ break;
+ case ATTR_ASPATH:
+ if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
+ return (-1);
+ if (aspath_verify(p, attr_len) != 0)
+ return (-1);
+ WFLAG(a->flags, F_ATTR_ASPATH);
+ a->aspath = aspath_get(p, attr_len);
+ if (enforce_as == ENFORCE_AS_ON &&
+ remote_as != aspath_neighbor(a->aspath))
+ return (-1);
+
+ plen += attr_len;
+ break;
+ case ATTR_NEXTHOP:
+ if (attr_len != 4)
+ return (-1);
+ if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
+ return (-1);
+ WFLAG(a->flags, F_ATTR_NEXTHOP);
+ bzero(&nexthop, sizeof(nexthop));
+ nexthop.af = AF_INET;
+ UPD_READ(&nexthop.v4.s_addr, p, plen, 4);
+ /*
+ * Check if the nexthop is a valid IP address. We consider
+ * multicast and experimental addresses as invalid.
+ */
+ tmp32 = ntohl(nexthop.v4.s_addr);
+ if (IN_MULTICAST(tmp32) || IN_BADCLASS(tmp32))
+ return (-1);
+
+ a->nexthop = nexthop_get(&nexthop, NULL);
+ break;
+ case ATTR_MED:
+ if (attr_len != 4)
+ return (-1);
+ if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
+ return (-1);
+ WFLAG(a->flags, F_ATTR_MED);
+ UPD_READ(&tmp32, p, plen, 4);
+ a->med = ntohl(tmp32);
+ break;
+ case ATTR_LOCALPREF:
+ if (attr_len != 4)
+ return (-1);
+ if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
+ return (-1);
+ if (ebgp) {
+ /* ignore local-pref attr for non ibgp peers */
+ a->lpref = 0; /* set a default value ... */
+ plen += 4; /* and ignore the real value */
+ break;
+ }
+ WFLAG(a->flags, F_ATTR_LOCALPREF);
+ UPD_READ(&tmp32, p, plen, 4);
+ a->lpref = ntohl(tmp32);
+ break;
+ case ATTR_ATOMIC_AGGREGATE:
+ if (attr_len != 0)
+ return (-1);
+ if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
+ return (-1);
+ goto optattr;
+ case ATTR_AGGREGATOR:
+ if (attr_len != 6)
+ return (-1);
+ if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, 0))
+ return (-1);
+ goto optattr;
+ case ATTR_COMMUNITIES:
+ if ((attr_len & 0x3) != 0)
+ return (-1);
+ if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
+ ATTR_PARTIAL))
+ return (-1);
+ goto optattr;
+ case ATTR_ORIGINATOR_ID:
+ if (attr_len != 4)
+ return (-1);
+ if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
+ return (-1);
+ goto optattr;
+ case ATTR_CLUSTER_LIST:
+ if ((attr_len & 0x3) != 0)
+ return (-1);
+ if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
+ return (-1);
+ goto optattr;
+ case ATTR_MP_REACH_NLRI:
+ if (attr_len < 4)
+ return (-1);
+ if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
+ return (-1);
+ /* the actually validity is checked in rde_update_dispatch() */
+ WFLAG(a->flags, F_ATTR_MP_REACH);
+
+ mpa->reach = p;
+ mpa->reach_len = attr_len;
+ plen += attr_len;
+ break;
+ case ATTR_MP_UNREACH_NLRI:
+ if (attr_len < 3)
+ return (-1);
+ if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
+ return (-1);
+ /* the actually validity is checked in rde_update_dispatch() */
+ WFLAG(a->flags, F_ATTR_MP_UNREACH);
+
+ mpa->unreach = p;
+ mpa->unreach_len = attr_len;
+ plen += attr_len;
+ break;
+ default:
+optattr:
+ if (attr_optadd(a, flags, type, p, attr_len) == -1)
+ return (-1);
+ plen += attr_len;
+ break;
+ }
+
+ return (plen);
+}
+
+u_char *
+rde_attr_error(u_char *p, u_int16_t len, struct rde_aspath *attr,
+ u_int8_t *suberr, u_int16_t *size)
+{
+ struct attr *a;
+ u_char *op;
+ u_int16_t attr_len;
+ u_int16_t plen = 0;
+ u_int8_t flags;
+ u_int8_t type;
+ u_int8_t tmp8;
+
+ *suberr = ERR_UPD_ATTRLEN;
+ *size = len;
+ op = p;
+ if (len < 3)
+ return (op);
+
+ UPD_READ(&flags, p, plen, 1);
+ UPD_READ(&type, p, plen, 1);
+
+ if (flags & ATTR_EXTLEN) {
+ if (len - plen < 2)
+ return (op);
+ UPD_READ(&attr_len, p, plen, 2);
+ } else {
+ UPD_READ(&tmp8, p, plen, 1);
+ attr_len = tmp8;
+ }
+
+ if (len - plen < attr_len)
+ return (op);
+ *size = attr_len;
+
+ switch (type) {
+ case ATTR_UNDEF:
+ /* error! */
+ *suberr = ERR_UPD_UNSPECIFIC;
+ *size = 0;
+ return (NULL);
+ case ATTR_ORIGIN:
+ if (attr_len != 1)
+ return (op);
+ if (attr->flags & F_ATTR_ORIGIN) {
+ *suberr = ERR_UPD_ATTRLIST;
+ *size = 0;
+ return (NULL);
+ }
+ UPD_READ(&tmp8, p, plen, 1);
+ if (tmp8 > ORIGIN_INCOMPLETE) {
+ *suberr = ERR_UPD_ORIGIN;
+ return (op);
+ }
+ break;
+ case ATTR_ASPATH:
+ if (attr->flags & F_ATTR_ASPATH) {
+ *suberr = ERR_UPD_ATTRLIST;
+ *size = 0;
+ return (NULL);
+ }
+ if (CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0)) {
+ /* malformed aspath detected by exclusion method */
+ *size = 0;
+ *suberr = ERR_UPD_ASPATH;
+ return (NULL);
+ }
+ break;
+ case ATTR_NEXTHOP:
+ if (attr_len != 4)
+ return (op);
+ if (attr->flags & F_ATTR_NEXTHOP) {
+ *suberr = ERR_UPD_ATTRLIST;
+ *size = 0;
+ return (NULL);
+ }
+ if (CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0)) {
+ /* malformed nexthop detected by exclusion method */
+ *suberr = ERR_UPD_NETWORK;
+ return (op);
+ }
+ break;
+ case ATTR_MED:
+ if (attr_len != 4)
+ return (op);
+ if (attr->flags & F_ATTR_MED) {
+ *suberr = ERR_UPD_ATTRLIST;
+ *size = 0;
+ return (NULL);
+ }
+ break;
+ case ATTR_LOCALPREF:
+ if (attr_len != 4)
+ return (op);
+ if (attr->flags & F_ATTR_LOCALPREF) {
+ *suberr = ERR_UPD_ATTRLIST;
+ *size = 0;
+ return (NULL);
+ }
+ break;
+ case ATTR_ATOMIC_AGGREGATE:
+ if (attr_len != 0)
+ return (op);
+ break;
+ case ATTR_AGGREGATOR:
+ if (attr_len != 6)
+ return (op);
+ break;
+ case ATTR_COMMUNITIES:
+ if ((attr_len & 0x3) != 0)
+ return (op);
+ goto optattr;
+ case ATTR_ORIGINATOR_ID:
+ if (attr_len != 4)
+ return (op);
+ goto optattr;
+ case ATTR_CLUSTER_LIST:
+ if ((attr_len & 0x3) != 0)
+ return (op);
+ goto optattr;
+ case ATTR_MP_REACH_NLRI:
+ if (attr_len < 4)
+ return (op);
+ if (attr->flags & F_ATTR_MP_REACH) {
+ *suberr = ERR_UPD_ATTRLIST;
+ *size = 0;
+ return (NULL);
+ }
+ break;
+ case ATTR_MP_UNREACH_NLRI:
+ if (attr_len < 3)
+ return (op);
+ if (attr->flags & F_ATTR_MP_UNREACH) {
+ *suberr = ERR_UPD_ATTRLIST;
+ *size = 0;
+ return (NULL);
+ }
+ break;
+ default:
+optattr:
+ if ((flags & ATTR_OPTIONAL) == 0) {
+ *suberr = ERR_UPD_UNKNWN_WK_ATTR;
+ return (op);
+ }
+ TAILQ_FOREACH(a, &attr->others, entry)
+ if (type == a->type) {
+ *size = 0;
+ *suberr = ERR_UPD_ATTRLIST;
+ return (NULL);
+ }
+ *suberr = ERR_UPD_OPTATTR;
+ return (op);
+ }
+ /* can only be a attribute flag error */
+ *suberr = ERR_UPD_ATTRFLAGS;
+ return (op);
+}
+#undef UPD_READ
+#undef WFLAG
+u_int8_t
+rde_attr_missing(struct rde_aspath *a, int ebgp, u_int16_t nlrilen)
+{
+ /* ATTR_MP_UNREACH_NLRI may be sent alone */
+ if (nlrilen == 0 && a->flags & F_ATTR_MP_UNREACH &&
+ (a->flags & F_ATTR_MP_REACH) == 0)
+ return (0);
+
+ if ((a->flags & F_ATTR_ORIGIN) == 0)
+ return (ATTR_ORIGIN);
+ if ((a->flags & F_ATTR_ASPATH) == 0)
+ return (ATTR_ASPATH);
+ if ((a->flags & F_ATTR_MP_REACH) == 0 &&
+ (a->flags & F_ATTR_NEXTHOP) == 0)
+ return (ATTR_NEXTHOP);
+ if (!ebgp)
+ if ((a->flags & F_ATTR_LOCALPREF) == 0)
+ return (ATTR_LOCALPREF);
return (0);
}
int
+rde_get_mp_nexthop(u_char *data, u_int16_t len, u_int16_t afi,
+ struct rde_aspath *asp)
+{
+ struct bgpd_addr nexthop, llnh, *lp;
+ u_int8_t totlen, nhlen;
+
+ if (len == 0)
+ return (-1);
+
+ nhlen = *data++;
+ totlen = 1;
+ len--;
+
+ if (nhlen > len)
+ return (-1);
+
+ bzero(&nexthop, sizeof(nexthop));
+ bzero(&llnh, sizeof(llnh));
+ switch (afi) {
+ case AFI_IPv6:
+ if (nhlen != 16 && nhlen != 32) {
+ log_warnx("bad multiprotocol nexthop, bad size");
+ return (-1);
+ }
+ nexthop.af = AF_INET6;
+ memcpy(&nexthop.v6.s6_addr, data, 16);
+ lp = NULL;
+ if (nhlen == 32) {
+ /*
+ * rfc 2545 describes that there may be a link local
+ * address carried in nexthop. Yikes.
+ */
+ llnh.af = AF_INET6;
+ memcpy(&llnh.v6.s6_addr, data, 16);
+ /* XXX we need to set the scope_id */
+ lp = &llnh;
+ }
+ asp->nexthop = nexthop_get(&nexthop, lp);
+
+ totlen += nhlen;
+ data += nhlen;
+
+ if (*data != 0) {
+ log_warnx("SNPA are not supported for IPv6");
+ return (-1);
+ }
+ return (++totlen);
+ default:
+ log_warnx("bad multiprotocol nexthop, bad AF");
+ break;
+ }
+
+ return (-1);
+}
+
+int
rde_update_get_prefix(u_char *p, u_int16_t len, struct bgpd_addr *prefix,
u_int8_t *prefixlen)
{
@@ -901,7 +1331,7 @@ rde_update_err(struct rde_peer *peer, u_int8_t error, u_int8_t suberr,
void
rde_update_log(const char *message,
- const struct rde_peer *peer, const struct attr_flags *attr,
+ const struct rde_peer *peer, const struct bgpd_addr *next,
const struct bgpd_addr *prefix, u_int8_t prefixlen)
{
char *nexthop = NULL;
@@ -910,16 +1340,10 @@ rde_update_log(const char *message,
if (!(conf->log & BGPD_LOG_UPDATES))
return;
- if (attr != NULL)
- if (attr_ismp(attr)) {
- if (asprintf(&nexthop, " via %s",
- log_addr(attr_mp_nexthop(attr))) == -1)
- nexthop = NULL;
- else
- if (asprintf(&nexthop, " via %s",
- inet_ntoa(attr->nexthop)) == -1)
- nexthop = NULL;
- }
+ if (next != NULL)
+ if (asprintf(&nexthop, " via %s",
+ log_addr(next)) == -1)
+ nexthop = NULL;
if (asprintf(&p, "%s/%u", log_addr(prefix), prefixlen) == -1)
p = NULL;
@@ -931,26 +1355,30 @@ rde_update_log(const char *message,
free(p);
}
+/*
+ * route reflector helper function
+ */
+
int
-rde_reflector(struct rde_peer *peer, struct attr_flags *attrs)
+rde_reflector(struct rde_peer *peer, struct rde_aspath *asp)
{
struct attr *a;
u_int16_t len;
/* check for originator id if eq router_id drop */
- if ((a = attr_optget(attrs, ATTR_ORIGINATOR_ID)) != NULL) {
+ if ((a = attr_optget(asp, ATTR_ORIGINATOR_ID)) != NULL) {
if (memcmp(&conf->bgpid, a->data, sizeof(conf->bgpid)) == 0)
/* this is coming from myself */
return (0);
} else if ((conf->flags & BGPD_FLAG_REFLECTOR) &&
- attr_optadd(attrs, ATTR_OPTIONAL, ATTR_ORIGINATOR_ID,
+ attr_optadd(asp, ATTR_OPTIONAL, ATTR_ORIGINATOR_ID,
peer->conf.ebgp == 0 ? &peer->remote_bgpid : &conf->bgpid,
sizeof(u_int32_t)) == -1)
fatalx("attr_optadd failed but impossible");
/* check for own id in the cluster list */
if (conf->flags & BGPD_FLAG_REFLECTOR) {
- if ((a = attr_optget(attrs, ATTR_CLUSTER_LIST)) != NULL) {
+ if ((a = attr_optget(asp, ATTR_CLUSTER_LIST)) != NULL) {
for (len = 0; len < a->len;
len += sizeof(conf->clusterid))
/* check if coming from my cluster */
@@ -967,7 +1395,7 @@ rde_reflector(struct rde_peer *peer, struct attr_flags *attrs)
a->len += sizeof(conf->clusterid);
memcpy(a->data, &conf->clusterid,
sizeof(conf->clusterid));
- } else if (attr_optadd(attrs, ATTR_OPTIONAL, ATTR_CLUSTER_LIST,
+ } else if (attr_optadd(asp, ATTR_OPTIONAL, ATTR_CLUSTER_LIST,
&conf->clusterid, sizeof(conf->clusterid)) == -1)
fatalx("attr_optadd failed but impossible");
}
@@ -984,31 +1412,38 @@ rde_dump_rib_as(struct prefix *p, pid_t pid)
struct buf *wbuf;
rib.lastchange = p->lastchange;
- rib.local_pref = p->aspath->flags.lpref;
- rib.med = p->aspath->flags.med;
+ rib.local_pref = p->aspath->lpref;
+ rib.med = p->aspath->med;
rib.prefix_cnt = p->aspath->prefix_cnt;
rib.active_cnt = p->aspath->active_cnt;
- memcpy(&rib.nexthop, &p->aspath->nexthop->true_nexthop,
- sizeof(rib.nexthop));
+ if (p->aspath->nexthop != NULL)
+ memcpy(&rib.nexthop, &p->aspath->nexthop->true_nexthop,
+ sizeof(rib.nexthop));
+ else {
+ /* announced network may have a NULL nexthop */
+ bzero(&rib.nexthop, sizeof(rib.nexthop));
+ rib.nexthop.af = p->prefix->af;
+ }
pt_getaddr(p->prefix, &rib.prefix);
rib.prefixlen = p->prefix->prefixlen;
- rib.origin = p->aspath->flags.origin;
+ rib.origin = p->aspath->origin;
rib.flags = 0;
if (p->prefix->active == p)
rib.flags |= F_RIB_ACTIVE;
if (p->peer->conf.ebgp == 0)
rib.flags |= F_RIB_INTERNAL;
- if (p->aspath->nexthop->state == NEXTHOP_REACH)
- rib.flags |= F_RIB_ELIGIBLE;
- if (p->aspath->nexthop->flags & NEXTHOP_ANNOUNCE)
+ if (p->aspath->flags & F_PREFIX_ANNOUNCED)
rib.flags |= F_RIB_ANNOUNCE;
- rib.aspath_len = aspath_length(p->aspath->flags.aspath);
+ if (p->aspath->nexthop == NULL ||
+ p->aspath->nexthop->state == NEXTHOP_REACH)
+ rib.flags |= F_RIB_ELIGIBLE;
+ rib.aspath_len = aspath_length(p->aspath->aspath);
if ((wbuf = imsg_create_pid(&ibuf_se, IMSG_CTL_SHOW_RIB, pid,
sizeof(rib) + rib.aspath_len)) == NULL)
return;
if (imsg_add(wbuf, &rib, sizeof(rib)) == -1 ||
- imsg_add(wbuf, aspath_dump(p->aspath->flags.aspath),
+ imsg_add(wbuf, aspath_dump(p->aspath->aspath),
rib.aspath_len) == -1)
return;
if (imsg_close(&ibuf_se, wbuf) == -1)
@@ -1028,10 +1463,11 @@ rde_dump_rib_prefix(struct prefix *p, pid_t pid)
prefix.flags |= F_RIB_ACTIVE;
if (p->peer->conf.ebgp == 0)
prefix.flags |= F_RIB_INTERNAL;
- if (p->aspath->nexthop->state == NEXTHOP_REACH)
- prefix.flags |= F_RIB_ELIGIBLE;
- if (p->aspath->nexthop->flags & NEXTHOP_ANNOUNCE)
+ if (p->aspath->flags & F_PREFIX_ANNOUNCED)
prefix.flags |= F_RIB_ANNOUNCE;
+ if (p->aspath->nexthop == NULL ||
+ p->aspath->nexthop->state == NEXTHOP_REACH)
+ prefix.flags |= F_RIB_ELIGIBLE;
if (imsg_compose_pid(&ibuf_se, IMSG_CTL_SHOW_RIB_PREFIX, pid,
&prefix, sizeof(prefix)) == -1)
log_warnx("rde_dump_as: imsg_compose error");
@@ -1060,7 +1496,7 @@ rde_dump_as(struct as_filter *a, pid_t pid)
i = pathtable.path_hashmask;
do {
LIST_FOREACH(asp, &pathtable.path_hashtbl[i], path_l) {
- if (!aspath_match(asp->flags.aspath, a->type, a->as))
+ if (!aspath_match(asp->aspath, a->type, a->as))
continue;
/* match found */
rde_dump_rib_as(LIST_FIRST(&asp->prefix_h), pid);
@@ -1115,6 +1551,7 @@ rde_dump_prefix(struct ctl_show_rib_prefix *pref, pid_t pid)
/*
* kroute specific functions
+ * XXX notyet IPv6 ready
*/
void
rde_send_kroute(struct prefix *new, struct prefix *old)
@@ -1129,16 +1566,17 @@ rde_send_kroute(struct prefix *new, struct prefix *old)
* On the other hand new may be UNREACH and then we should not
* generate an update.
*/
- if ((old == NULL || old->aspath->nexthop->flags & NEXTHOP_ANNOUNCE) &&
- (new == NULL || new->aspath->nexthop->state != NEXTHOP_REACH ||
- new->aspath->nexthop->flags & NEXTHOP_ANNOUNCE))
+ if ((old == NULL || old->aspath->flags & F_PREFIX_ANNOUNCED) &&
+ (new == NULL || new->aspath->nexthop == NULL ||
+ new->aspath->nexthop->state != NEXTHOP_REACH ||
+ new->aspath->flags & F_PREFIX_ANNOUNCED))
return;
bzero(&kr, sizeof(kr));
if (new == NULL || new->aspath->nexthop == NULL ||
new->aspath->nexthop->state != NEXTHOP_REACH ||
- new->aspath->nexthop->flags & NEXTHOP_ANNOUNCE) {
+ new->aspath->flags & F_PREFIX_ANNOUNCED) {
type = IMSG_KROUTE_DELETE;
p = old;
} else {
@@ -1150,9 +1588,9 @@ rde_send_kroute(struct prefix *new, struct prefix *old)
pt_getaddr(p->prefix, &addr);
kr.prefix.s_addr = addr.v4.s_addr;
kr.prefixlen = p->prefix->prefixlen;
- if (p->aspath->flags.nexthop_reject)
+ if (p->aspath->flags & F_NEXTHOP_REJECT)
kr.flags |= F_REJECT;
- if (p->aspath->flags.nexthop_blackhole)
+ if (p->aspath->flags & F_NEXTHOP_BLACKHOLE)
kr.flags |= F_BLACKHOLE;
if (imsg_compose(&ibuf_main, type, 0, &kr, sizeof(kr)) == -1)
@@ -1193,18 +1631,31 @@ rde_send_pftable_commit(void)
* nexthop specific functions
*/
void
-rde_send_nexthop(struct bgpd_addr *next, int valid)
+rde_send_nexthop(struct bgpd_addr *next, struct bgpd_addr *ll, int valid)
{
- int type;
+ struct buf *wbuf;
+ size_t size;
+ int type;
if (valid)
type = IMSG_NEXTHOP_ADD;
else
type = IMSG_NEXTHOP_REMOVE;
- if (imsg_compose(&ibuf_main, type, 0, next,
- sizeof(struct bgpd_addr)) == -1)
- fatal("imsg_compose error");
+ if (ll == NULL)
+ size = sizeof(struct bgpd_addr);
+ else
+ size = 2 * sizeof(struct bgpd_addr);
+
+ if ((wbuf = imsg_create(&ibuf_main, type, 0, size)) == NULL)
+ fatal("imsg_create error");
+ if (imsg_add(wbuf, next, sizeof(struct bgpd_addr)) == -1)
+ fatal("imsg_add error");
+ if (ll != NULL)
+ if (imsg_add(wbuf, ll, sizeof(struct bgpd_addr)) == -1)
+ fatal("imsg_add error");
+ if (imsg_close(&ibuf_main, wbuf) == -1)
+ fatal("imsg_close error");
}
/*
@@ -1222,8 +1673,8 @@ rde_generate_updates(struct prefix *new, struct prefix *old)
* On the other hand new may be UNREACH and then we should not
* generate an update.
*/
- if (old == NULL && (new == NULL ||
- new->aspath->nexthop->state != NEXTHOP_REACH))
+ if (old == NULL && (new == NULL || (new->aspath->nexthop != NULL &&
+ new->aspath->nexthop->state != NEXTHOP_REACH)))
return;
LIST_FOREACH(peer, &peerlist, peer_l) {
@@ -1500,24 +1951,22 @@ network_init(struct network_head *net_l)
void
network_add(struct network_config *nc, int flagstatic)
{
- struct attr_flags attrs;
-
- bzero(&attrs, sizeof(attrs));
+ struct rde_aspath *asp;
- attrs.aspath = aspath_get(NULL, 0);
- attrs.nexthop.s_addr = INADDR_ANY;
- /* med = 0 */
- attrs.lpref = DEFAULT_LPREF;
- attrs.origin = ORIGIN_IGP;
- TAILQ_INIT(&attrs.others);
+ asp = path_get();
+ asp->aspath = aspath_get(NULL, 0);
+ asp->origin = ORIGIN_IGP;
+ asp->flags = F_ATTR_ORIGIN | F_ATTR_ASPATH |
+ F_ATTR_LOCALPREF | F_PREFIX_ANNOUNCED;
+ /* the nexthop is unset unless a default set overrides it */
/* apply default overrides */
- rde_apply_set(&attrs, &nc->attrset);
+ rde_apply_set(asp, &nc->attrset);
if (flagstatic)
- path_update(&peerself, &attrs, &nc->prefix, nc->prefixlen);
+ path_update(&peerself, asp, &nc->prefix, nc->prefixlen);
else
- path_update(&peerdynamic, &attrs, &nc->prefix, nc->prefixlen);
+ path_update(&peerdynamic, asp, &nc->prefix, nc->prefixlen);
}
void
@@ -1540,10 +1989,10 @@ network_dump_upcall(struct pt_entry *pt, void *ptr)
memcpy(&pid, ptr, sizeof(pid));
LIST_FOREACH(p, &pt->prefix_h, prefix_l)
- if (p->aspath->nexthop->flags & NEXTHOP_ANNOUNCE) {
+ if (p->aspath->flags & F_PREFIX_ANNOUNCED) {
bzero(&k, sizeof(k));
pt_getaddr(p->prefix, &addr);
- k.prefix = addr.v4;
+ k.prefix.s_addr = addr.v4.s_addr;
k.prefixlen = p->prefix->prefixlen;
if (p->peer == &peerself)
k.flags = F_KERNEL;
diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h
index 17007e6cc8d..16612845a3b 100644
--- a/usr.sbin/bgpd/rde.h
+++ b/usr.sbin/bgpd/rde.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.h,v 1.50 2004/08/05 20:56:12 claudio Exp $ */
+/* $OpenBSD: rde.h,v 1.51 2004/08/06 12:04:08 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
@@ -63,6 +63,8 @@ struct rde_peer {
struct uptree_attr up_attrs;
struct uplist_attr updates;
struct uplist_prefix withdraws;
+ struct uplist_attr updates6;
+ struct uplist_prefix withdraws6;
};
#define AS_SET 1
@@ -105,32 +107,64 @@ enum attrtypes {
#define ATTR_WELL_KNOWN ATTR_TRANSITIVE
struct attr {
+ TAILQ_ENTRY(attr) entry;
u_int8_t flags;
u_int8_t type;
u_int16_t len;
u_char *data;
- TAILQ_ENTRY(attr) entry;
+};
+
+struct mpattr {
+ void *reach;
+ u_int16_t reach_len;
+ void *unreach;
+ u_int16_t unreach_len;
};
TAILQ_HEAD(attr_list, attr);
+struct path_table {
+ struct aspath_head *path_hashtbl;
+ u_int32_t path_hashmask;
+};
+
+LIST_HEAD(prefix_head, prefix);
+
+#define F_ATTR_ORIGIN 0x001
+#define F_ATTR_ASPATH 0x002
+#define F_ATTR_NEXTHOP 0x004
+#define F_ATTR_LOCALPREF 0x008
+#define F_ATTR_MED 0x010
+#define F_ATTR_MP_REACH 0x020
+#define F_ATTR_MP_UNREACH 0x040
+#define F_PREFIX_ANNOUNCED 0x080
+#define F_NEXTHOP_REJECT 0x100
+#define F_NEXTHOP_BLACKHOLE 0x200
+#define F_ATTR_LINKED 0x400
+
#define ORIGIN_IGP 0
#define ORIGIN_EGP 1
#define ORIGIN_INCOMPLETE 2
#define DEFAULT_LPREF 100
-struct attr_flags {
+struct rde_aspath {
+ LIST_ENTRY(rde_aspath) path_l, peer_l, nexthop_l;
+ struct prefix_head prefix_h;
+ struct rde_peer *peer;
+
+ /* path attributes */
struct aspath *aspath;
- struct in_addr nexthop; /* exit nexthop */
- u_int8_t nexthop_reject;
- u_int8_t nexthop_blackhole;
- char pftable[PFTABLE_LEN];
+ struct nexthop *nexthop; /* may be NULL */
+ struct attr_list others;
u_int32_t med; /* multi exit disc */
u_int32_t lpref; /* local pref */
u_int8_t origin;
- u_int8_t wflags; /* internally used */
- struct attr_list others;
+
+ u_int16_t flags; /* internally used */
+ u_int16_t prefix_cnt; /* # of prefixes */
+ u_int16_t active_cnt; /* # of active prefixes */
+ char pftable[PFTABLE_LEN];
};
enum nexthop_state {
@@ -141,7 +175,7 @@ enum nexthop_state {
struct nexthop {
LIST_ENTRY(nexthop) nexthop_l;
- enum nexthop_state state;
+ struct aspath_head path_h;
#if 0
/*
* currently we use the boolean nexthop state, this could be exchanged
@@ -149,31 +183,14 @@ struct nexthop {
*/
u_int32_t costs;
#endif
- struct aspath_head path_h;
+ enum nexthop_state state;
struct bgpd_addr exit_nexthop;
struct bgpd_addr true_nexthop;
struct bgpd_addr nexthop_net;
u_int8_t nexthop_netlen;
u_int8_t flags;
-#define NEXTHOP_CONNECTED 0x1
-#define NEXTHOP_ANNOUNCE 0x2
-};
-
-struct path_table {
- struct aspath_head *path_hashtbl;
- u_int32_t path_hashmask;
-};
-
-LIST_HEAD(prefix_head, prefix);
-
-struct rde_aspath {
- LIST_ENTRY(rde_aspath) peer_l, path_l, nexthop_l;
- struct prefix_head prefix_h;
- struct rde_peer *peer;
- struct nexthop *nexthop;
- u_int16_t prefix_cnt; /* # of prefixes */
- u_int16_t active_cnt; /* # of active prefixes */
- struct attr_flags flags;
+#define NEXTHOP_CONNECTED 0x01
+#define NEXTHOP_LINKLOCAL 0x02
};
/* generic entry without address specific part */
@@ -214,14 +231,12 @@ struct prefix {
struct pt_entry *prefix;
struct rde_peer *peer;
time_t lastchange;
-/* currently I can't think of additional prefix flags.
- * NOTE: the selected route is stored in prefix->active */
};
/* prototypes */
/* rde.c */
void rde_send_kroute(struct prefix *, struct prefix *);
-void rde_send_nexthop(struct bgpd_addr *, int);
+void rde_send_nexthop(struct bgpd_addr *, struct bgpd_addr *, int);
void rde_send_pftable(const char *, struct bgpd_addr *,
u_int8_t, int);
void rde_send_pftable_commit(void);
@@ -231,25 +246,15 @@ u_int16_t rde_local_as(void);
int rde_noevaluate(void);
/* rde_attr.c */
-void attr_init(struct attr_flags *);
-int attr_parse(u_char *, u_int16_t, struct attr_flags *, int,
- enum enforce_as, u_int16_t);
-u_char *attr_error(u_char *, u_int16_t, struct attr_flags *,
- u_int8_t *, u_int16_t *);
-u_int8_t attr_missing(struct attr_flags *, int);
-int attr_compare(struct attr_flags *, struct attr_flags *);
-void attr_copy(struct attr_flags *, struct attr_flags *);
-void attr_move(struct attr_flags *, struct attr_flags *);
-void attr_free(struct attr_flags *);
int attr_write(void *, u_int16_t, u_int8_t, u_int8_t, void *,
u_int16_t);
-int attr_optadd(struct attr_flags *, u_int8_t, u_int8_t,
+void attr_optcopy(struct rde_aspath *, struct rde_aspath *);
+int attr_optadd(struct rde_aspath *, u_int8_t, u_int8_t,
void *, u_int16_t);
-struct attr *attr_optget(const struct attr_flags *, u_int8_t);
-void attr_optfree(struct attr_flags *);
-int attr_ismp(const struct attr_flags *);
-int attr_mp_nexthop_check(u_char *, u_int16_t, u_int16_t);
-struct bgpd_addr *attr_mp_nexthop(const struct attr_flags *);
+struct attr *attr_optget(const struct rde_aspath *, u_int8_t);
+void attr_optfree(struct rde_aspath *);
+int attr_mp_nexthop(u_char *, u_int16_t, u_int16_t,
+ struct rde_aspath *);
int aspath_verify(void *, u_int16_t);
#define AS_ERR_LEN -1
@@ -277,18 +282,21 @@ int community_set(struct attr *, int, int);
/* rde_rib.c */
void path_init(u_int32_t);
void path_shutdown(void);
-void path_update(struct rde_peer *, struct attr_flags *,
+void path_update(struct rde_peer *, struct rde_aspath *,
struct bgpd_addr *, int);
-struct rde_aspath *path_get(struct aspath *, struct rde_peer *);
-struct rde_aspath *path_add(struct rde_peer *, struct attr_flags *);
+int path_compare(struct rde_aspath *, struct rde_aspath *);
+struct rde_aspath *path_lookup(struct rde_aspath *, struct rde_peer *);
void path_remove(struct rde_aspath *);
void path_updateall(struct rde_aspath *, enum nexthop_state);
void path_destroy(struct rde_aspath *);
int path_empty(struct rde_aspath *);
+struct rde_aspath *path_copy(struct rde_aspath *);
+struct rde_aspath *path_get(void);
+void path_put(struct rde_aspath *);
int prefix_compare(const struct bgpd_addr *,
const struct bgpd_addr *, int);
-struct prefix *prefix_get(struct rde_aspath *, struct bgpd_addr *, int);
+struct prefix *prefix_get(struct rde_peer *, struct bgpd_addr *, int);
struct pt_entry *prefix_add(struct rde_aspath *, struct bgpd_addr *, int);
struct pt_entry *prefix_move(struct rde_aspath *, struct prefix *);
void prefix_remove(struct rde_peer *, struct bgpd_addr *, int);
@@ -299,9 +307,12 @@ void prefix_network_clean(struct rde_peer *, time_t);
void nexthop_init(u_int32_t);
void nexthop_shutdown(void);
-void nexthop_add(struct rde_aspath *);
-void nexthop_remove(struct rde_aspath *);
+void nexthop_modify(struct rde_aspath *, struct bgpd_addr *, int);
+void nexthop_link(struct rde_aspath *);
+void nexthop_unlink(struct rde_aspath *);
void nexthop_update(struct kroute_nexthop *);
+struct nexthop *nexthop_get(struct bgpd_addr *, struct bgpd_addr *);
+int nexthop_compare(struct nexthop *, struct nexthop *);
/* rde_decide.c */
void prefix_evaluate(struct prefix *, struct pt_entry *);
@@ -328,9 +339,9 @@ void pt_dump(void (*)(struct pt_entry *, void *), void *,
sa_family_t);
/* rde_filter.c */
-enum filter_actions rde_filter(struct rde_peer *, struct attr_flags *,
+enum filter_actions rde_filter(struct rde_peer *, struct rde_aspath *,
struct bgpd_addr *, u_int8_t, enum directions);
-void rde_apply_set(struct attr_flags *, struct filter_set *);
-int rde_filter_community(struct attr_flags *, int, int);
+void rde_apply_set(struct rde_aspath *, struct filter_set *);
+int rde_filter_community(struct rde_aspath *, int, int);
#endif /* __RDE_H__ */
diff --git a/usr.sbin/bgpd/rde_attr.c b/usr.sbin/bgpd/rde_attr.c
index cbb7e925c35..fe1a6c1c492 100644
--- a/usr.sbin/bgpd/rde_attr.c
+++ b/usr.sbin/bgpd/rde_attr.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_attr.c,v 1.41 2004/08/05 20:56:12 claudio Exp $ */
+/* $OpenBSD: rde_attr.c,v 1.42 2004/08/06 12:04:08 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -29,457 +29,6 @@
#include "rde.h"
/* attribute specific functions */
-#define UPD_READ(t, p, plen, n) \
- do { \
- memcpy(t, p, n); \
- p += n; \
- plen += n; \
- } while (0)
-
-#define CHECK_FLAGS(s, t, m) \
- (((s) & ~(ATTR_EXTLEN | (m))) == (t))
-
-#define F_ATTR_ORIGIN 0x01
-#define F_ATTR_ASPATH 0x02
-#define F_ATTR_NEXTHOP 0x04
-#define F_ATTR_LOCALPREF 0x08
-#define F_ATTR_MED 0x10
-#define F_ATTR_MP_REACH 0x20
-#define F_ATTR_MP_UNREACH 0x40
-
-#define WFLAG(s, t) \
- do { \
- if ((s) & (t)) \
- return (-1); \
- (s) |= (t); \
- } while (0)
-void
-attr_init(struct attr_flags *a)
-{
- bzero(a, sizeof(struct attr_flags));
- a->origin = ORIGIN_INCOMPLETE;
- a->lpref = DEFAULT_LPREF;
- TAILQ_INIT(&a->others);
-}
-
-int
-attr_parse(u_char *p, u_int16_t len, struct attr_flags *a, int ebgp,
- enum enforce_as enforce_as, u_int16_t remote_as)
-{
- u_int32_t tmp32;
- u_int16_t attr_len;
- u_int16_t plen = 0;
- u_int8_t flags;
- u_int8_t type;
- u_int8_t tmp8;
-
- if (len < 3)
- return (-1);
-
- UPD_READ(&flags, p, plen, 1);
- UPD_READ(&type, p, plen, 1);
-
- if (flags & ATTR_EXTLEN) {
- if (len - plen < 2)
- return (-1);
- UPD_READ(&attr_len, p, plen, 2);
- attr_len = ntohs(attr_len);
- } else {
- UPD_READ(&tmp8, p, plen, 1);
- attr_len = tmp8;
- }
-
- if (len - plen < attr_len)
- return (-1);
-
- switch (type) {
- case ATTR_UNDEF:
- /* error! */
- return (-1);
- case ATTR_ORIGIN:
- if (attr_len != 1)
- return (-1);
- if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
- return (-1);
- UPD_READ(&a->origin, p, plen, 1);
- if (a->origin > ORIGIN_INCOMPLETE)
- return (-1);
- WFLAG(a->wflags, F_ATTR_ORIGIN);
- break;
- case ATTR_ASPATH:
- if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
- return (-1);
- if (aspath_verify(p, attr_len) != 0)
- return (-1);
- WFLAG(a->wflags, F_ATTR_ASPATH);
- a->aspath = aspath_get(p, attr_len);
- if (enforce_as == ENFORCE_AS_ON &&
- remote_as != aspath_neighbor(a->aspath))
- return (-1);
-
- plen += attr_len;
- break;
- case ATTR_NEXTHOP:
- if (attr_len != 4)
- return (-1);
- if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
- return (-1);
- WFLAG(a->wflags, F_ATTR_NEXTHOP);
- UPD_READ(&a->nexthop, p, plen, 4); /* network byte order */
- /*
- * Check if the nexthop is a valid IP address. We consider
- * multicast and experimental addresses as invalid.
- */
- tmp32 = ntohl(a->nexthop.s_addr);
- if (IN_MULTICAST(tmp32) || IN_BADCLASS(tmp32))
- return (-1);
- break;
- case ATTR_MED:
- if (attr_len != 4)
- return (-1);
- if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
- return (-1);
- WFLAG(a->wflags, F_ATTR_MED);
- UPD_READ(&tmp32, p, plen, 4);
- a->med = ntohl(tmp32);
- break;
- case ATTR_LOCALPREF:
- if (attr_len != 4)
- return (-1);
- if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
- return (-1);
- if (ebgp) {
- /* ignore local-pref attr for non ibgp peers */
- a->lpref = 0; /* set a default value ... */
- plen += 4; /* and ignore the real value */
- break;
- }
- WFLAG(a->wflags, F_ATTR_LOCALPREF);
- UPD_READ(&tmp32, p, plen, 4);
- a->lpref = ntohl(tmp32);
- break;
- case ATTR_ATOMIC_AGGREGATE:
- if (attr_len != 0)
- return (-1);
- if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
- return (-1);
- goto optattr;
- case ATTR_AGGREGATOR:
- if (attr_len != 6)
- return (-1);
- if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, 0))
- return (-1);
- goto optattr;
- case ATTR_COMMUNITIES:
- if ((attr_len & 0x3) != 0)
- return (-1);
- if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
- ATTR_PARTIAL))
- return (-1);
- goto optattr;
- case ATTR_ORIGINATOR_ID:
- if (attr_len != 4)
- return (-1);
- if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
- return (-1);
- goto optattr;
- case ATTR_CLUSTER_LIST:
- if ((attr_len & 0x3) != 0)
- return (-1);
- if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
- return (-1);
- goto optattr;
- case ATTR_MP_REACH_NLRI:
- if (attr_len < 4)
- return (-1);
- if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
- return (-1);
- /* the actually validity is checked in rde_update_dispatch() */
- WFLAG(a->wflags, F_ATTR_MP_REACH);
- goto optattr;
- case ATTR_MP_UNREACH_NLRI:
- if (attr_len < 3)
- return (-1);
- if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
- return (-1);
- /* the actually validity is checked in rde_update_dispatch() */
- WFLAG(a->wflags, F_ATTR_MP_UNREACH);
- goto optattr;
- default:
-optattr:
- if (attr_optadd(a, flags, type, p, attr_len) == -1)
- return (-1);
- plen += attr_len;
- break;
- }
-
- return (plen);
-}
-
-u_char *
-attr_error(u_char *p, u_int16_t len, struct attr_flags *attr,
- u_int8_t *suberr, u_int16_t *size)
-{
- struct attr *a;
- u_char *op;
- u_int16_t attr_len;
- u_int16_t plen = 0;
- u_int8_t flags;
- u_int8_t type;
- u_int8_t tmp8;
-
- *suberr = ERR_UPD_ATTRLEN;
- *size = len;
- op = p;
- if (len < 3)
- return (op);
-
- UPD_READ(&flags, p, plen, 1);
- UPD_READ(&type, p, plen, 1);
-
- if (flags & ATTR_EXTLEN) {
- if (len - plen < 2)
- return (op);
- UPD_READ(&attr_len, p, plen, 2);
- } else {
- UPD_READ(&tmp8, p, plen, 1);
- attr_len = tmp8;
- }
-
- if (len - plen < attr_len)
- return (op);
- *size = attr_len;
-
- switch (type) {
- case ATTR_UNDEF:
- /* error! */
- *suberr = ERR_UPD_UNSPECIFIC;
- *size = 0;
- return (NULL);
- case ATTR_ORIGIN:
- if (attr_len != 1)
- return (op);
- if (attr->wflags & F_ATTR_ORIGIN) {
- *suberr = ERR_UPD_ATTRLIST;
- *size = 0;
- return (NULL);
- }
- UPD_READ(&tmp8, p, plen, 1);
- if (tmp8 > ORIGIN_INCOMPLETE) {
- *suberr = ERR_UPD_ORIGIN;
- return (op);
- }
- break;
- case ATTR_ASPATH:
- if (attr->wflags & F_ATTR_ASPATH) {
- *suberr = ERR_UPD_ATTRLIST;
- *size = 0;
- return (NULL);
- }
- if (CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0)) {
- /* malformed aspath detected by exclusion method */
- *size = 0;
- *suberr = ERR_UPD_ASPATH;
- return (NULL);
- }
- break;
- case ATTR_NEXTHOP:
- if (attr_len != 4)
- return (op);
- if (attr->wflags & F_ATTR_NEXTHOP) {
- *suberr = ERR_UPD_ATTRLIST;
- *size = 0;
- return (NULL);
- }
- if (CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0)) {
- /* malformed nexthop detected by exclusion method */
- *suberr = ERR_UPD_NETWORK;
- return (op);
- }
- break;
- case ATTR_MED:
- if (attr_len != 4)
- return (op);
- if (attr->wflags & F_ATTR_MED) {
- *suberr = ERR_UPD_ATTRLIST;
- *size = 0;
- return (NULL);
- }
- break;
- case ATTR_LOCALPREF:
- if (attr_len != 4)
- return (op);
- if (attr->wflags & F_ATTR_LOCALPREF) {
- *suberr = ERR_UPD_ATTRLIST;
- *size = 0;
- return (NULL);
- }
- break;
- case ATTR_ATOMIC_AGGREGATE:
- if (attr_len != 0)
- return (op);
- break;
- case ATTR_AGGREGATOR:
- if (attr_len != 6)
- return (op);
- break;
- case ATTR_COMMUNITIES:
- if ((attr_len & 0x3) != 0)
- return (op);
- goto optattr;
- case ATTR_ORIGINATOR_ID:
- if (attr_len != 4)
- return (op);
- goto optattr;
- case ATTR_CLUSTER_LIST:
- if ((attr_len & 0x3) != 0)
- return (op);
- goto optattr;
- case ATTR_MP_REACH_NLRI:
- if (attr_len < 4)
- return (op);
- goto optattr;
- case ATTR_MP_UNREACH_NLRI:
- if (attr_len < 3)
- return (op);
- goto optattr;
- default:
-optattr:
- if ((flags & ATTR_OPTIONAL) == 0) {
- *suberr = ERR_UPD_UNKNWN_WK_ATTR;
- return (op);
- }
- TAILQ_FOREACH(a, &attr->others, entry)
- if (type == a->type) {
- *size = 0;
- *suberr = ERR_UPD_ATTRLIST;
- return (NULL);
- }
- *suberr = ERR_UPD_OPTATTR;
- return (op);
- }
- /* can only be a attribute flag error */
- *suberr = ERR_UPD_ATTRFLAGS;
- return (op);
-}
-#undef UPD_READ
-#undef WFLAG
-
-u_int8_t
-attr_missing(struct attr_flags *a, int ebgp)
-{
- if ((a->wflags & F_ATTR_ORIGIN) == 0)
- return (ATTR_ORIGIN);
- if ((a->wflags & F_ATTR_ASPATH) == 0)
- return (ATTR_ASPATH);
- if ((a->wflags & F_ATTR_MP_REACH) == 0 &&
- (a->wflags & F_ATTR_NEXTHOP) == 0)
- return (ATTR_NEXTHOP);
- if (!ebgp)
- if ((a->wflags & F_ATTR_LOCALPREF) == 0)
- return (ATTR_LOCALPREF);
- return (0);
-}
-
-int
-attr_compare(struct attr_flags *a, struct attr_flags *b)
-{
- struct attr *oa, *ob;
- int r;
-
- if (a->origin > b->origin)
- return (1);
- if (a->origin < b->origin)
- return (-1);
- if ((a->wflags & F_ATTR_NEXTHOP) && (b->wflags & F_ATTR_NEXTHOP) == 0)
- return (1);
- if ((b->wflags & F_ATTR_NEXTHOP) && (a->wflags & F_ATTR_NEXTHOP) == 0)
- return (-1);
- if (a->nexthop.s_addr > b->nexthop.s_addr)
- return (1);
- if (a->nexthop.s_addr < b->nexthop.s_addr)
- return (-1);
- if (a->med > b->med)
- return (1);
- if (a->med < b->med)
- return (-1);
- if (a->lpref > b->lpref)
- return (1);
- if (a->lpref < b->lpref)
- return (-1);
- r = strcmp(a->pftable, b->pftable);
- if (r == 0)
- r = aspath_compare(a->aspath, b->aspath);
- if (r > 0)
- return (1);
- if (r < 0)
- return (-1);
-
- for (oa = TAILQ_FIRST(&a->others), ob = TAILQ_FIRST(&b->others);
- oa != NULL && ob != NULL;
- oa = TAILQ_NEXT(oa, entry), ob = TAILQ_NEXT(ob, entry)) {
- if (oa->type > ob->type)
- return (1);
- if (oa->type < ob->type)
- return (-1);
- if (oa->len > ob->len)
- return (1);
- if (oa->len < ob->len)
- return (-1);
- r = memcmp(oa->data, ob->data, oa->len);
- if (r > 0)
- return (1);
- if (r < 0)
- return (-1);
- }
- if (oa != NULL)
- return (1);
- if (ob != NULL)
- return (-1);
- return (0);
-}
-
-void
-attr_copy(struct attr_flags *t, struct attr_flags *s)
-{
- struct attr *os;
- /*
- * first copy the full struct, then replace the path and tags with
- * a own copy.
- */
- memcpy(t, s, sizeof(struct attr_flags));
- t->aspath = aspath_get(s->aspath->data, s->aspath->len);
- TAILQ_INIT(&t->others);
- TAILQ_FOREACH(os, &s->others, entry)
- attr_optadd(t, os->flags, os->type, os->data, os->len);
-}
-
-void
-attr_move(struct attr_flags *t, struct attr_flags *s)
-{
- struct attr *os;
- /*
- * first copy the full struct, then move the optional attributes.
- */
- memcpy(t, s, sizeof(struct attr_flags));
- TAILQ_INIT(&t->others);
- while ((os = TAILQ_FIRST(&s->others)) != NULL) {
- TAILQ_REMOVE(&s->others, os, entry);
- TAILQ_INSERT_TAIL(&t->others, os, entry);
- }
-}
-
-void
-attr_free(struct attr_flags *a)
-{
- /*
- * free the aspath and all optional path attributes
- * but not the attr_flags struct.
- */
- aspath_put(a->aspath);
- a->aspath = NULL;
- attr_optfree(a);
-}
int
attr_write(void *p, u_int16_t p_len, u_int8_t flags, u_int8_t type,
@@ -513,7 +62,7 @@ attr_write(void *p, u_int16_t p_len, u_int8_t flags, u_int8_t type,
}
int
-attr_optadd(struct attr_flags *attr, u_int8_t flags, u_int8_t type,
+attr_optadd(struct rde_aspath *asp, u_int8_t flags, u_int8_t type,
void *data, u_int16_t len)
{
struct attr *a, *p;
@@ -522,6 +71,7 @@ attr_optadd(struct attr_flags *attr, u_int8_t flags, u_int8_t type,
a = calloc(1, sizeof(struct attr));
if (a == NULL)
fatal("attr_optadd");
+
a->flags = flags;
a->type = type;
a->len = len;
@@ -529,12 +79,13 @@ attr_optadd(struct attr_flags *attr, u_int8_t flags, u_int8_t type,
a->data = malloc(len);
if (a->data == NULL)
fatal("attr_optadd");
+
memcpy(a->data, data, len);
} else
a->data = NULL;
/* keep a sorted list */
- TAILQ_FOREACH_REVERSE(p, &attr->others, attr_list, entry) {
+ TAILQ_FOREACH_REVERSE(p, &asp->others, attr_list, entry) {
if (type == p->type) {
/* attribute only once allowed */
free(a->data);
@@ -542,20 +93,20 @@ attr_optadd(struct attr_flags *attr, u_int8_t flags, u_int8_t type,
return (-1);
}
if (type > p->type) {
- TAILQ_INSERT_AFTER(&attr->others, p, a, entry);
+ TAILQ_INSERT_AFTER(&asp->others, p, a, entry);
return (0);
}
}
- TAILQ_INSERT_HEAD(&attr->others, a, entry);
+ TAILQ_INSERT_HEAD(&asp->others, a, entry);
return (0);
}
struct attr *
-attr_optget(const struct attr_flags *attr, u_int8_t type)
+attr_optget(const struct rde_aspath *asp, u_int8_t type)
{
struct attr *a;
- TAILQ_FOREACH(a, &attr->others, entry) {
+ TAILQ_FOREACH(a, &asp->others, entry) {
if (type == a->type)
return (a);
if (type < a->type)
@@ -566,103 +117,24 @@ attr_optget(const struct attr_flags *attr, u_int8_t type)
}
void
-attr_optfree(struct attr_flags *attr)
+attr_optcopy(struct rde_aspath *t, struct rde_aspath *s)
{
- struct attr *a;
-
- while ((a = TAILQ_FIRST(&attr->others)) != NULL) {
- TAILQ_REMOVE(&attr->others, a, entry);
- free(a->data);
- free(a);
- }
-}
+ struct attr *os;
-int
-attr_ismp(const struct attr_flags *attr)
-{
- return (attr->wflags & F_ATTR_MP_REACH);
+ TAILQ_FOREACH(os, &s->others, entry)
+ attr_optadd(t, os->flags, os->type, os->data, os->len);
}
-int
-attr_mp_nexthop_check(u_char *data, u_int16_t len, u_int16_t afi)
+void
+attr_optfree(struct rde_aspath *asp)
{
- u_int8_t nh_len;
-
- if (len == 0)
- return (-1);
-
- nh_len = *data++;
- len--;
-
- if (nh_len > len)
- return (-1);
-
- switch (afi) {
- case AFI_IPv6:
- if (nh_len != 16 && nh_len != 32) {
- log_warnx("bad multiprotocol nexthop, bad size");
- return (-1);
- }
- return (nh_len + 1);
- default:
- log_warnx("bad multiprotocol nexthop, bad AF");
- break;
- }
-
- return (-1);
-}
+ struct attr *a;
-/*
- * this function may only be called after attr_mp_nexthop_check()
- */
-struct bgpd_addr *
-attr_mp_nexthop(const struct attr_flags *attrs)
-{
- static struct bgpd_addr address;
- struct attr *mpattr;
- u_int8_t *p;
- u_int16_t afi;
- u_int8_t nhlen;
-
- if ((mpattr = attr_optget(attrs, ATTR_MP_REACH_NLRI)) == NULL) {
- log_warnx("attr_mp_nexthop: no MP_REACH_NLRI available");
- return (NULL);
- }
- p = mpattr->data;
- if (mpattr->len < 4)
- fatalx("Who fucked up the code? King Bula?");
-
- memcpy(&afi, p, 2);
- afi = ntohs(afi);
- p += 3;
-
- nhlen = *p++;
- if (nhlen > mpattr->len)
- fatalx("Who fucked up the code? King Bula?");
-
- bzero(&address, sizeof(address));
- switch (afi) {
- case AFI_IPv6:
- address.af = AF_INET6;
- if (nhlen == 16) {
- memcpy(&address.v6.s6_addr, p, 16);
- return (&address);
- }
- if (nhlen == 32) {
- /*
- * XXX acctually the link lokal address should be used
- * for kroute and the global one updates.
- */
- memcpy(&address.v6.s6_addr, p, 16);
- return (&address);
- }
- fatalx("Who fucked up the code? King Bula?");
- default:
- fatalx("attr_mp_nexthop: unsupported AF");
+ while ((a = TAILQ_FIRST(&asp->others)) != NULL) {
+ TAILQ_REMOVE(&asp->others, a, entry);
+ free(a->data);
+ free(a);
}
-
- /* NOTREACHED */
- return (NULL);
}
/* aspath specific functions */
diff --git a/usr.sbin/bgpd/rde_decide.c b/usr.sbin/bgpd/rde_decide.c
index 1d116f75bb3..cbac5c3849b 100644
--- a/usr.sbin/bgpd/rde_decide.c
+++ b/usr.sbin/bgpd/rde_decide.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_decide.c,v 1.37 2004/08/05 18:44:19 claudio Exp $ */
+/* $OpenBSD: rde_decide.c,v 1.38 2004/08/06 12:04:08 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
@@ -113,8 +113,6 @@ prefix_cmp(struct prefix *p1, struct prefix *p2)
if (p1 == NULL)
return (-1);
-
- /* p2 is allowed to be NULL */
if (p2 == NULL)
return (1);
@@ -122,31 +120,28 @@ prefix_cmp(struct prefix *p1, struct prefix *p2)
asp2 = p2->aspath;
/* 1. check if prefix is eligible a.k.a reachable */
- if (asp2->nexthop->state != NEXTHOP_REACH)
+ if (asp2->nexthop != NULL && asp2->nexthop->state != NEXTHOP_REACH)
return (1);
- if (asp1->nexthop->state != NEXTHOP_REACH)
+ if (asp1->nexthop != NULL && asp1->nexthop->state != NEXTHOP_REACH)
return (-1);
/* 2. preference of prefix, bigger is better */
- if ((asp1->flags.lpref - asp2->flags.lpref) != 0)
- return (asp1->flags.lpref - asp2->flags.lpref);
+ if ((asp1->lpref - asp2->lpref) != 0)
+ return (asp1->lpref - asp2->lpref);
/* 3. aspath count, the shorter the better */
- if ((asp2->flags.aspath->ascnt -
- asp1->flags.aspath->ascnt) != 0)
- return (asp2->flags.aspath->ascnt -
- asp1->flags.aspath->ascnt);
+ if ((asp2->aspath->ascnt - asp1->aspath->ascnt) != 0)
+ return (asp2->aspath->ascnt - asp1->aspath->ascnt);
/* 4. origin, the lower the better */
- if ((asp2->flags.origin - asp1->flags.origin) != 0)
- return (asp2->flags.origin - asp1->flags.origin);
+ if ((asp2->origin - asp1->origin) != 0)
+ return (asp2->origin - asp1->origin);
/* 5. MED decision, only comparable between the same neighboring AS */
- if (aspath_neighbor(asp1->flags.aspath) ==
- aspath_neighbor(asp2->flags.aspath))
+ if (aspath_neighbor(asp1->aspath) == aspath_neighbor(asp2->aspath))
/* lowest value wins */
- if ((asp2->flags.med - asp1->flags.med) != 0)
- return (asp2->flags.med - asp1->flags.med);
+ if ((asp2->med - asp1->med) != 0)
+ return (asp2->med - asp1->med);
/*
* 6. EBGP is cooler than IBGP
@@ -231,8 +226,8 @@ prefix_evaluate(struct prefix *p, struct pt_entry *pte)
rde_generate_updates(xp, pte->active);
rde_send_kroute(xp, pte->active);
- if (xp == NULL || xp->aspath->nexthop == NULL ||
- xp->aspath->nexthop->state != NEXTHOP_REACH)
+ if (xp == NULL || (xp->aspath->nexthop != NULL &&
+ xp->aspath->nexthop->state != NEXTHOP_REACH))
pte->active = NULL;
else {
pte->active = xp;
diff --git a/usr.sbin/bgpd/rde_filter.c b/usr.sbin/bgpd/rde_filter.c
index 22d880364c5..785176d0788 100644
--- a/usr.sbin/bgpd/rde_filter.c
+++ b/usr.sbin/bgpd/rde_filter.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_filter.c,v 1.15 2004/08/05 18:44:19 claudio Exp $ */
+/* $OpenBSD: rde_filter.c,v 1.16 2004/08/06 12:04:08 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -25,11 +25,11 @@
extern struct filter_head *rules_l; /* XXX ugly */
-int rde_filter_match(struct filter_rule *, struct attr_flags *,
+int rde_filter_match(struct filter_rule *, struct rde_aspath *,
struct bgpd_addr *, u_int8_t);
enum filter_actions
-rde_filter(struct rde_peer *peer, struct attr_flags *attrs,
+rde_filter(struct rde_peer *peer, struct rde_aspath *asp,
struct bgpd_addr *prefix, u_int8_t prefixlen, enum directions dir)
{
struct filter_rule *f;
@@ -44,8 +44,8 @@ rde_filter(struct rde_peer *peer, struct attr_flags *attrs,
if (f->peer.peerid != 0 &&
f->peer.peerid != peer->conf.id)
continue;
- if (rde_filter_match(f, attrs, prefix, prefixlen)) {
- rde_apply_set(attrs, &f->set);
+ if (rde_filter_match(f, asp, prefix, prefixlen)) {
+ rde_apply_set(asp, &f->set);
if (f->action != ACTION_NONE)
action = f->action;
if (f->quick)
@@ -56,39 +56,41 @@ rde_filter(struct rde_peer *peer, struct attr_flags *attrs,
}
void
-rde_apply_set(struct attr_flags *attrs, struct filter_set *set)
+rde_apply_set(struct rde_aspath *asp, struct filter_set *set)
{
+ struct bgpd_addr addr;
struct aspath *new;
u_int16_t as;
- if (attrs == NULL)
+ if (asp == NULL)
return;
if (set->flags & SET_LOCALPREF)
- attrs->lpref = set->localpref;
+ asp->lpref = set->localpref;
if (set->flags & SET_MED)
- attrs->med = set->med;
- if (set->flags & SET_NEXTHOP)
- attrs->nexthop = set->nexthop;
- if (set->flags & SET_NEXTHOP_REJECT)
- attrs->nexthop_reject = 1;
- if (set->flags & SET_NEXTHOP_BLACKHOLE)
- attrs->nexthop_blackhole = 1;
+ asp->med = set->med;
+
+ /* XXX and uglier */
+ bzero(&addr, sizeof(addr));
+ addr.af = AF_INET;
+ addr.v4.s_addr = set->nexthop.s_addr;
+ nexthop_modify(asp, &addr, set->flags);
+
if (set->flags & SET_PREPEND) {
as = rde_local_as();
- new = aspath_prepend(attrs->aspath, as, set->prepend);
- aspath_put(attrs->aspath);
- attrs->aspath = new;
+ new = aspath_prepend(asp->aspath, as, set->prepend);
+ aspath_put(asp->aspath);
+ asp->aspath = new;
}
if (set->flags & SET_PFTABLE)
- strlcpy(attrs->pftable, set->pftable, sizeof(attrs->pftable));
+ strlcpy(asp->pftable, set->pftable, sizeof(asp->pftable));
if (set->flags & SET_COMMUNITY) {
struct attr *a;
- if ((a = attr_optget(attrs, ATTR_COMMUNITIES)) == NULL) {
- attr_optadd(attrs, ATTR_OPTIONAL|ATTR_TRANSITIVE,
+ if ((a = attr_optget(asp, ATTR_COMMUNITIES)) == NULL) {
+ attr_optadd(asp, ATTR_OPTIONAL|ATTR_TRANSITIVE,
ATTR_COMMUNITIES, NULL, 0);
- if ((a = attr_optget(attrs, ATTR_COMMUNITIES)) == NULL)
+ if ((a = attr_optget(asp, ATTR_COMMUNITIES)) == NULL)
fatalx("internal community bug");
}
community_set(a, set->community.as, set->community.type);
@@ -96,17 +98,17 @@ rde_apply_set(struct attr_flags *attrs, struct filter_set *set)
}
int
-rde_filter_match(struct filter_rule *f, struct attr_flags *attrs,
+rde_filter_match(struct filter_rule *f, struct rde_aspath *asp,
struct bgpd_addr *prefix, u_int8_t plen)
{
- if (attrs != NULL && f->match.as.type != AS_NONE)
- if (aspath_match(attrs->aspath, f->match.as.type,
+ if (asp != NULL && f->match.as.type != AS_NONE)
+ if (aspath_match(asp->aspath, f->match.as.type,
f->match.as.as) == 0)
return (0);
- if (attrs != NULL && f->match.community.as != 0)
- if (rde_filter_community(attrs, f->match.community.as,
+ if (asp != NULL && f->match.community.as != 0)
+ if (rde_filter_community(asp, f->match.community.as,
f->match.community.type) == 0)
return (0);
@@ -178,11 +180,11 @@ rde_filter_match(struct filter_rule *f, struct attr_flags *attrs,
}
int
-rde_filter_community(struct attr_flags *attr, int as, int type)
+rde_filter_community(struct rde_aspath *asp, int as, int type)
{
struct attr *a;
- a = attr_optget(attr, ATTR_COMMUNITIES);
+ a = attr_optget(asp, ATTR_COMMUNITIES);
if (a == NULL)
/* no communities, no match */
return (0);
diff --git a/usr.sbin/bgpd/rde_rib.c b/usr.sbin/bgpd/rde_rib.c
index b79ac85b514..ed127353780 100644
--- a/usr.sbin/bgpd/rde_rib.c
+++ b/usr.sbin/bgpd/rde_rib.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_rib.c,v 1.54 2004/08/05 19:23:10 claudio Exp $ */
+/* $OpenBSD: rde_rib.c,v 1.55 2004/08/06 12:04:08 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
@@ -37,12 +37,10 @@
/* path specific functions */
static void path_link(struct rde_aspath *, struct rde_peer *);
-static void path_unlink(struct rde_aspath *);
-static struct rde_aspath *path_alloc(void);
-static void path_free(struct rde_aspath *);
struct path_table pathtable;
+/* XXX the hash should also include communities and the other attrs */
#define PATH_HASH(x) \
&pathtable.path_hashtbl[aspath_hash((x)->data, (x)->len) & \
pathtable.path_hashmask]
@@ -77,65 +75,106 @@ path_shutdown(void)
}
void
-path_update(struct rde_peer *peer, struct attr_flags *attrs,
+path_update(struct rde_peer *peer, struct rde_aspath *nasp,
struct bgpd_addr *prefix, int prefixlen)
{
struct rde_aspath *asp;
struct prefix *p;
- struct pt_entry *pte;
- rde_send_pftable(attrs->pftable, prefix, prefixlen, 0);
+ rde_send_pftable(nasp->pftable, prefix, prefixlen, 0);
rde_send_pftable_commit();
- if ((asp = path_get(attrs->aspath, peer)) == NULL) {
- /* path not available */
- asp = path_add(peer, attrs);
- pte = prefix_add(asp, prefix, prefixlen);
- } else {
- if (attr_compare(&asp->flags, attrs) == 0) {
- /* path are equal, just add prefix */
- pte = prefix_add(asp, prefix, prefixlen);
- attr_free(attrs);
- } else {
+ if ((p = prefix_get(peer, prefix, prefixlen)) != NULL) {
+ if (path_compare(nasp, p->aspath) != 0) {
/* non equal path attributes create new path */
- if ((p = prefix_get(asp, prefix, prefixlen)) == NULL) {
- asp = path_add(peer, attrs);
- pte = prefix_add(asp, prefix, prefixlen);
- } else {
- asp = path_add(peer, attrs);
- pte = prefix_move(asp, p);
- }
+ path_link(nasp, peer);
+ prefix_move(nasp, p);
+ } else {
+ /* already registered */
+ path_put(nasp);
}
+ } else if ((asp = path_lookup(nasp, peer)) == NULL) {
+ /* path not available */
+ path_link(nasp, peer);
+ prefix_add(nasp, prefix, prefixlen);
+ } else {
+ /* path found, just add prefix */
+ prefix_add(asp, prefix, prefixlen);
+ path_put(nasp);
+ }
+}
+
+int
+path_compare(struct rde_aspath *a, struct rde_aspath *b)
+{
+ struct attr *oa, *ob;
+ int r;
+
+ if (a->origin > b->origin)
+ return (1);
+ if (a->origin < b->origin)
+ return (-1);
+ if ((a->flags & ~F_ATTR_LINKED) > (b->flags & ~F_ATTR_LINKED))
+ return (1);
+ if ((a->flags & ~F_ATTR_LINKED) < (b->flags & ~F_ATTR_LINKED))
+ return (-1);
+ if (a->med > b->med)
+ return (1);
+ if (a->med < b->med)
+ return (-1);
+ if (a->lpref > b->lpref)
+ return (1);
+ if (a->lpref < b->lpref)
+ return (-1);
+
+ r = strcmp(a->pftable, b->pftable);
+ if (r == 0)
+ r = aspath_compare(a->aspath, b->aspath);
+ if (r == 0)
+ r = nexthop_compare(a->nexthop, b->nexthop);
+ if (r > 0)
+ return (1);
+ if (r < 0)
+ return (-1);
+
+ for (oa = TAILQ_FIRST(&a->others), ob = TAILQ_FIRST(&b->others);
+ oa != NULL && ob != NULL;
+ oa = TAILQ_NEXT(oa, entry), ob = TAILQ_NEXT(ob, entry)) {
+ if (oa->type > ob->type)
+ return (1);
+ if (oa->type < ob->type)
+ return (-1);
+ if (oa->len > ob->len)
+ return (1);
+ if (oa->len < ob->len)
+ return (-1);
+ r = memcmp(oa->data, ob->data, oa->len);
+ if (r > 0)
+ return (1);
+ if (r < 0)
+ return (-1);
}
+ if (oa != NULL)
+ return (1);
+ if (ob != NULL)
+ return (-1);
+ return (0);
}
struct rde_aspath *
-path_get(struct aspath *aspath, struct rde_peer *peer)
+path_lookup(struct rde_aspath *aspath, struct rde_peer *peer)
{
struct aspath_head *head;
struct rde_aspath *asp;
- head = PATH_HASH(aspath);
+ head = PATH_HASH(aspath->aspath);
LIST_FOREACH(asp, head, path_l) {
- if (aspath_compare(asp->flags.aspath, aspath) == 0 &&
+ if (path_compare(aspath, asp) == 0 &&
peer == asp->peer)
- return asp;
+ return (asp);
}
- return NULL;
-}
-
-struct rde_aspath *
-path_add(struct rde_peer *peer, struct attr_flags *attr)
-{
- struct rde_aspath *asp;
-
- asp = path_alloc();
-
- attr_move(&asp->flags, attr);
-
- path_link(asp, peer);
- return asp;
+ return (NULL);
}
void
@@ -147,7 +186,7 @@ path_remove(struct rde_aspath *asp)
while ((p = LIST_FIRST(&asp->prefix_h)) != NULL) {
/* Commit is done in peer_down() */
pt_getaddr(p->prefix, &addr);
- rde_send_pftable(p->aspath->flags.pftable,
+ rde_send_pftable(p->aspath->pftable,
&addr, p->prefix->prefixlen, 1);
prefix_destroy(p);
@@ -171,9 +210,16 @@ path_destroy(struct rde_aspath *asp)
{
/* path_destroy can only unlink and free empty rde_aspath */
ENSURE(path_empty(asp));
+ ENSURE(asp->prefix_cnt == 0 && asp->active_cnt == 0);
- path_unlink(asp);
- path_free(asp);
+ nexthop_unlink(asp);
+ LIST_REMOVE(asp, path_l);
+ LIST_REMOVE(asp, peer_l);
+ asp->peer = NULL;
+ asp->nexthop = NULL;
+ asp->flags &= ~F_ATTR_LINKED;
+
+ path_put(asp);
}
int
@@ -194,33 +240,44 @@ path_link(struct rde_aspath *asp, struct rde_peer *peer)
{
struct aspath_head *head;
- head = PATH_HASH(asp->flags.aspath);
+ head = PATH_HASH(asp->aspath);
LIST_INSERT_HEAD(head, asp, path_l);
LIST_INSERT_HEAD(&peer->path_h, asp, peer_l);
asp->peer = peer;
+ asp->flags |= F_ATTR_LINKED;
- nexthop_add(asp);
+ nexthop_link(asp);
}
-static void
-path_unlink(struct rde_aspath *asp)
+/*
+ * copy asp to a new UNLINKED one manly for filtering
+ */
+struct rde_aspath *
+path_copy(struct rde_aspath *asp)
{
- ENSURE(path_empty(asp));
- ENSURE(asp->prefix_cnt == 0 && asp->active_cnt == 0);
+ struct rde_aspath *nasp;
- nexthop_remove(asp);
- LIST_REMOVE(asp, path_l);
- LIST_REMOVE(asp, peer_l);
- asp->peer = NULL;
- asp->nexthop = NULL;
+ nasp = path_get();
+ nasp->aspath = asp->aspath;
+ if (nasp->aspath != NULL)
+ nasp->aspath->refcnt++;
+ nasp->nexthop = asp->nexthop;
+ nasp->med = asp->med;
+ nasp->lpref = asp->lpref;
+ nasp->origin = asp->origin;
+
+ nasp->flags = asp->flags & ~F_ATTR_LINKED;
+
+ TAILQ_INIT(&nasp->others);
+ attr_optcopy(nasp, asp);
- attr_free(&asp->flags);
+ return (nasp);
}
/* alloc and initialize new entry. May not fail. */
-static struct rde_aspath *
-path_alloc(void)
+struct rde_aspath *
+path_get(void)
{
struct rde_aspath *asp;
@@ -228,16 +285,23 @@ path_alloc(void)
if (asp == NULL)
fatal("path_alloc");
LIST_INIT(&asp->prefix_h);
- return asp;
+ TAILQ_INIT(&asp->others);
+ asp->origin = ORIGIN_INCOMPLETE;
+ asp->lpref = DEFAULT_LPREF;
+ /* med = 0 */
+
+ return (asp);
}
/* free a unlinked element */
-static void
-path_free(struct rde_aspath *asp)
+void
+path_put(struct rde_aspath *asp)
{
- ENSURE(asp->peer == NULL &&
- asp->flags.aspath == NULL &&
- TAILQ_EMPTY(&asp->flags.others));
+ if (asp->flags & F_ATTR_LINKED)
+ fatalx("path_put: linked object");
+
+ aspath_put(asp->aspath);
+ attr_optfree(asp);
free(asp);
}
@@ -290,26 +354,17 @@ prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b,
}
/*
- * search in the path list for specified prefix. Returns NULL if not found.
+ * search for specified prefix of a peer. Returns NULL if not found.
*/
struct prefix *
-prefix_get(struct rde_aspath *asp, struct bgpd_addr *prefix, int prefixlen)
+prefix_get(struct rde_peer *peer, struct bgpd_addr *prefix, int prefixlen)
{
- struct prefix *p;
- struct bgpd_addr addr;
-
- LIST_FOREACH(p, &asp->prefix_h, path_l) {
- ENSURE(p->prefix != NULL);
- if (p->prefix->prefixlen != prefixlen)
- continue;
- pt_getaddr(p->prefix, &addr);
- if (!prefix_compare(&addr, prefix, prefixlen)) {
- ENSURE(p->aspath == asp);
- return p;
- }
- }
+ struct pt_entry *pte;
- return NULL;
+ pte = pt_get(prefix, prefixlen);
+ if (pte == NULL)
+ return (NULL);
+ return (prefix_bypeer(pte, peer));
}
/*
@@ -324,9 +379,9 @@ prefix_add(struct rde_aspath *asp, struct bgpd_addr *prefix, int prefixlen)
int needlink = 0;
pte = pt_get(prefix, prefixlen);
- if (pte == NULL) {
+ if (pte == NULL)
pte = pt_add(prefix, prefixlen);
- }
+
p = prefix_bypeer(pte, asp->peer);
if (p == NULL) {
needlink = 1;
@@ -422,7 +477,7 @@ prefix_remove(struct rde_peer *peer, struct bgpd_addr *prefix, int prefixlen)
asp = p->aspath;
- rde_send_pftable(asp->flags.pftable, prefix, prefixlen, 1);
+ rde_send_pftable(asp->pftable, prefix, prefixlen, 1);
rde_send_pftable_commit();
prefix_unlink(p);
@@ -587,20 +642,8 @@ prefix_free(struct prefix *pref)
}
/* nexthop functions */
-
-/*
- * XXX
- * Storing the nexthop info in a hash table is not optimal. The problem is
- * that updates (invalidate and validate) come in as prefixes and so storing
- * the nexthops in a hash is not optimal. An (in)validate needs to do a table
- * walk to find all candidates.
- * Currently I think that there are many more adds and removes so that a
- * hash table has more benefits and the table walk should not happen too often.
- */
-
-static struct nexthop *nexthop_get(struct in_addr);
-static struct nexthop *nexthop_alloc(void);
-static void nexthop_free(struct nexthop *);
+struct nexthop_head *nexthop_hash(struct bgpd_addr *);
+struct nexthop *nexthop_lookup(struct bgpd_addr *);
/*
* In BGP there exist two nexthops: the exit nexthop which was announced via
@@ -612,18 +655,13 @@ static void nexthop_free(struct nexthop *);
* reside in the same subnet -- directly connected.
*/
struct nexthop_table {
- LIST_HEAD(, nexthop) *nexthop_hashtbl;
- u_int32_t nexthop_hashmask;
+ LIST_HEAD(nexthop_head, nexthop) *nexthop_hashtbl;
+ u_int32_t nexthop_hashmask;
} nexthoptable;
-#define NEXTHOP_HASH(x) \
- &nexthoptable.nexthop_hashtbl[ntohl((x.s_addr)) & \
- nexthoptable.nexthop_hashmask]
-
void
nexthop_init(u_int32_t hashsize)
{
- struct nexthop *nh;
u_int32_t hs, i;
for (hs = 1; hs < hashsize; hs <<= 1)
@@ -636,169 +674,224 @@ nexthop_init(u_int32_t hashsize)
LIST_INIT(&nexthoptable.nexthop_hashtbl[i]);
nexthoptable.nexthop_hashmask = hs - 1;
-
- /* add dummy entry for connected networks */
- nh = nexthop_alloc();
- nh->state = NEXTHOP_REACH;
- nh->exit_nexthop.af = AF_INET;
- nh->exit_nexthop.v4.s_addr = INADDR_ANY;
-
- LIST_INSERT_HEAD(NEXTHOP_HASH(nh->exit_nexthop.v4), nh,
- nexthop_l);
-
- memcpy(&nh->true_nexthop, &nh->exit_nexthop,
- sizeof(nh->true_nexthop));
- nh->nexthop_netlen = 0;
- nh->nexthop_net.af = AF_INET;
- nh->nexthop_net.v4.s_addr = INADDR_ANY;
-
- nh->flags = NEXTHOP_ANNOUNCE;
}
void
nexthop_shutdown(void)
{
- struct in_addr addr;
- struct nexthop *nh;
- u_int32_t i;
-
- /* remove the dummy entry for connected networks */
- addr.s_addr = INADDR_ANY;
- nh = nexthop_get(addr);
- if (nh != NULL) {
- if (!LIST_EMPTY(&nh->path_h))
- log_warnx("nexthop_free: free non-free announce node");
- LIST_REMOVE(nh, nexthop_l);
- nexthop_free(nh);
- }
+ u_int32_t i;
for (i = 0; i <= nexthoptable.nexthop_hashmask; i++)
if (!LIST_EMPTY(&nexthoptable.nexthop_hashtbl[i]))
- log_warnx("nexthop_free: free non-free table");
+ log_warnx("nexthop_shutdown: non-free table");
free(nexthoptable.nexthop_hashtbl);
}
void
-nexthop_add(struct rde_aspath *asp)
+nexthop_update(struct kroute_nexthop *msg)
{
- struct nexthop *nh;
+ struct nexthop *nh;
+ struct rde_aspath *asp;
- if ((nh = asp->nexthop) == NULL)
- nh = nexthop_get(asp->flags.nexthop);
+ nh = nexthop_lookup(&msg->nexthop);
if (nh == NULL) {
- nh = nexthop_alloc();
- nh->state = NEXTHOP_LOOKUP;
- nh->exit_nexthop.af = AF_INET;
- nh->exit_nexthop.v4 = asp->flags.nexthop;
- LIST_INSERT_HEAD(NEXTHOP_HASH(asp->flags.nexthop), nh,
- nexthop_l);
- rde_send_nexthop(&nh->exit_nexthop, 1);
+ log_warnx("nexthop_update: non-existent nexthop");
+ return;
+ }
+
+ if (msg->valid)
+ nh->state = NEXTHOP_REACH;
+ else
+ nh->state = NEXTHOP_UNREACH;
+
+ if (msg->connected) {
+ if (!(nh->flags & NEXTHOP_LINKLOCAL))
+ /* use linklocal address if provided */
+ nh->true_nexthop = nh->exit_nexthop;
+ nh->flags |= NEXTHOP_CONNECTED;
+ } else {
+ nh->true_nexthop = msg->gateway;
+ nh->flags &= ~NEXTHOP_LINKLOCAL;
}
+
+ nh->nexthop_netlen = msg->kr.kr4.prefixlen;
+ nh->nexthop_net.af = AF_INET;
+ nh->nexthop_net.v4.s_addr = msg->kr.kr4.prefix.s_addr;
+
+ if (rde_noevaluate())
+ /*
+ * if the decision process is turned off there is no need
+ * for the aspath list walk.
+ */
+ return;
+
+ LIST_FOREACH(asp, &nh->path_h, nexthop_l) {
+ path_updateall(asp, nh->state);
+ }
+}
+
+void
+nexthop_modify(struct rde_aspath *asp, struct bgpd_addr *nexthop, int flags)
+{
+ struct nexthop *nh;
+
+ if (flags & SET_NEXTHOP_REJECT)
+ asp->flags |= F_NEXTHOP_REJECT;
+ if (flags & SET_NEXTHOP_BLACKHOLE)
+ asp->flags |= F_NEXTHOP_BLACKHOLE;
+ if (!(flags & SET_NEXTHOP))
+ return;
+ nh = nexthop_get(nexthop, NULL);
+ nexthop_unlink(asp);
asp->nexthop = nh;
- LIST_INSERT_HEAD(&nh->path_h, asp, nexthop_l);
+ nexthop_link(asp);
}
void
-nexthop_remove(struct rde_aspath *asp)
+nexthop_link(struct rde_aspath *asp)
+{
+ if (asp->nexthop == NULL)
+ return;
+
+ LIST_INSERT_HEAD(&asp->nexthop->path_h, asp, nexthop_l);
+}
+
+void
+nexthop_unlink(struct rde_aspath *asp)
{
struct nexthop *nh;
+ if (asp->nexthop == NULL)
+ return;
+
LIST_REMOVE(asp, nexthop_l);
/* see if list is empty */
nh = asp->nexthop;
-
- /* never remove the dummy announce entry */
- if (nh->flags & NEXTHOP_ANNOUNCE)
- return;
+ asp->nexthop = NULL;
if (LIST_EMPTY(&nh->path_h)) {
LIST_REMOVE(nh, nexthop_l);
- rde_send_nexthop(&nh->exit_nexthop, 0);
- nexthop_free(nh);
+ if (nh->flags & NEXTHOP_LINKLOCAL)
+ rde_send_nexthop(&nh->exit_nexthop,
+ &nh->true_nexthop, 0);
+ else
+ rde_send_nexthop(&nh->exit_nexthop, NULL, 0);
+
+ free(nh);
}
}
-static struct nexthop *
-nexthop_get(struct in_addr nexthop)
+struct nexthop *
+nexthop_get(struct bgpd_addr *nexthop, struct bgpd_addr *ll)
{
struct nexthop *nh;
- LIST_FOREACH(nh, NEXTHOP_HASH(nexthop), nexthop_l) {
- if (nh->exit_nexthop.v4.s_addr == nexthop.s_addr)
- return nh;
- }
- return NULL;
-}
+ nh = nexthop_lookup(nexthop);
+ if (nh == NULL) {
+ nh = calloc(1, sizeof(*nh));
+ if (nh == NULL)
+ fatal("nexthop_alloc");
-void
-nexthop_update(struct kroute_nexthop *msg)
-{
- struct nexthop *nh;
- struct rde_aspath *asp;
+ LIST_INIT(&nh->path_h);
+ nh->state = NEXTHOP_LOOKUP;
+ nh->exit_nexthop = *nexthop;
+ if (ll) {
+ /*
+ * The link local address should be used as nexthop
+ * if available but acctualy it does not care.
+ * There is only one link local address per nexthop
+ * if any. Therefor the key is still the nexthop.
+ */
+ /*
+ * XXX unsure if this is the correct way. BTW.
+ * For link local address the scope is needed.
+ * I think we should use some nice hack with the kroute
+ * code and the nexthop updates to fix that.
+ */
+ memcpy(&nh->true_nexthop, ll, sizeof(struct bgpd_addr));
+ nh->flags |= NEXTHOP_LINKLOCAL;
+ }
+ LIST_INSERT_HEAD(nexthop_hash(nexthop), nh,
+ nexthop_l);
- nh = nexthop_get(msg->nexthop.v4);
- if (nh == NULL) {
- log_warnx("nexthop_update: non-existent nexthop");
- return;
- }
- /* should I trust in the parent ??? */
- if (nh->exit_nexthop.af != msg->nexthop.af ||
- (nh->exit_nexthop.af == AF_INET &&
- nh->exit_nexthop.v4.s_addr != msg->nexthop.v4.s_addr)) {
- log_warnx("nexthop_update: bad nexthop returned");
- return;
+ if (nh->flags & NEXTHOP_LINKLOCAL)
+ rde_send_nexthop(&nh->exit_nexthop,
+ &nh->true_nexthop, 1);
+ else
+ rde_send_nexthop(&nh->exit_nexthop, NULL, 1);
}
- if (msg->valid)
- nh->state = NEXTHOP_REACH;
- else
- nh->state = NEXTHOP_UNREACH;
+ return (nh);
+}
- if (msg->connected)
- memcpy(&nh->true_nexthop, &nh->exit_nexthop,
- sizeof(nh->true_nexthop));
- else
- memcpy(&nh->true_nexthop, &msg->gateway,
- sizeof(nh->true_nexthop));
+int
+nexthop_compare(struct nexthop *na, struct nexthop *nb)
+{
+ struct bgpd_addr *a, *b;
- nh->nexthop_netlen = msg->kr.kr4.prefixlen;
- nh->nexthop_net.af = AF_INET;
- nh->nexthop_net.v4.s_addr = msg->kr.kr4.prefix.s_addr;
+ if (na == NULL && nb == NULL)
+ return (0);
+ if (na == NULL)
+ return (-1);
+ if (nb == NULL)
+ return (1);
- if (msg->connected)
- nh->flags |= NEXTHOP_CONNECTED;
+ a = &na->exit_nexthop;
+ b = &nb->exit_nexthop;
- if (rde_noevaluate())
- /*
- * if the decision process is turned off there is no need
- * for the aspath list walk.
- */
- return;
+ if (a->af != b->af)
+ return (a->af - b->af);
- LIST_FOREACH(asp, &nh->path_h, nexthop_l) {
- path_updateall(asp, nh->state);
+ switch (a->af) {
+ case AF_INET:
+ if (ntohl(a->v4.s_addr) > ntohl(b->v4.s_addr))
+ return (1);
+ if (ntohl(a->v4.s_addr) < ntohl(b->v4.s_addr))
+ return (-1);
+ return (0);
+ case AF_INET6:
+ return (memcmp(&a->v6, &b->v6, sizeof(struct in6_addr)));
+ default:
+ fatalx("nexthop_cmp: unknown af");
}
+ return (-1);
}
-static struct nexthop *
-nexthop_alloc(void)
+struct nexthop *
+nexthop_lookup(struct bgpd_addr *nexthop)
{
- struct nexthop *nh;
+ struct nexthop *nh;
- nh = calloc(1, sizeof(*nh));
- if (nh == NULL)
- fatal("nexthop_alloc");
- LIST_INIT(&nh->path_h);
- return nh;
+ LIST_FOREACH(nh, nexthop_hash(nexthop), nexthop_l) {
+ if (memcmp(&nh->exit_nexthop, nexthop,
+ sizeof(struct bgpd_addr)) == 0)
+ return (nh);
+ }
+ return (NULL);
}
-static void
-nexthop_free(struct nexthop *nh)
+struct nexthop_head *
+nexthop_hash(struct bgpd_addr *nexthop)
{
- ENSURE(LIST_EMPTY(&nh->path_h));
+ u_int32_t i, h = 0;
- free(nh);
+ switch (nexthop->af) {
+ case AF_INET:
+ h = (AF_INET ^ ntohl(nexthop->v4.s_addr) ^
+ ntohl(nexthop->v4.s_addr) >> 13) &
+ nexthoptable.nexthop_hashmask;
+ break;
+ case AF_INET6:
+ h = 8271;
+ for (i = 0; i < sizeof(struct in6_addr); i++)
+ h = ((h << 5) + h) ^ nexthop->v6.s6_addr[i];
+ h &= nexthoptable.nexthop_hashmask;
+ break;
+ default:
+ fatalx("nexthop_hash: unsupported AF");
+ }
+ return (&nexthoptable.nexthop_hashtbl[h]);
}
diff --git a/usr.sbin/bgpd/rde_update.c b/usr.sbin/bgpd/rde_update.c
index 8b442352305..6ba93082554 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.26 2004/08/05 18:44:19 claudio Exp $ */
+/* $OpenBSD: rde_update.c,v 1.27 2004/08/06 12:04:08 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -25,7 +25,7 @@
#include "rde.h"
int up_generate_attr(struct rde_peer *, struct update_attr *,
- struct attr_flags *, struct nexthop *);
+ struct rde_aspath *);
int up_set_prefix(u_char *, int, struct bgpd_addr *, u_int8_t);
@@ -47,6 +47,7 @@ struct update_attr {
RB_ENTRY(update_attr) entry;
};
+void up_clear(struct uplist_attr *, struct uplist_prefix *);
int up_prefix_cmp(struct update_prefix *, struct update_prefix *);
int up_attr_cmp(struct update_attr *, struct update_attr *);
int up_add(struct rde_peer *, struct update_prefix *, struct update_attr *);
@@ -62,6 +63,8 @@ up_init(struct rde_peer *peer)
{
TAILQ_INIT(&peer->updates);
TAILQ_INIT(&peer->withdraws);
+ TAILQ_INIT(&peer->updates6);
+ TAILQ_INIT(&peer->withdraws6);
RB_INIT(&peer->up_prefix);
RB_INIT(&peer->up_attrs);
peer->up_pcnt = 0;
@@ -71,13 +74,13 @@ up_init(struct rde_peer *peer)
}
void
-up_down(struct rde_peer *peer)
+up_clear(struct uplist_attr *updates, struct uplist_prefix *withdraws)
{
struct update_attr *ua;
struct update_prefix *up;
- while ((ua = TAILQ_FIRST(&peer->updates)) != NULL) {
- TAILQ_REMOVE(&peer->updates, ua, attr_l);
+ while ((ua = TAILQ_FIRST(updates)) != NULL) {
+ TAILQ_REMOVE(updates, ua, attr_l);
while ((up = TAILQ_FIRST(&ua->prefix_h)) != NULL) {
TAILQ_REMOVE(&ua->prefix_h, up, prefix_l);
free(up);
@@ -86,13 +89,18 @@ up_down(struct rde_peer *peer)
free(ua);
}
- while ((up = TAILQ_FIRST(&peer->withdraws)) != NULL) {
- TAILQ_REMOVE(&peer->withdraws, up, prefix_l);
+ while ((up = TAILQ_FIRST(withdraws)) != NULL) {
+ TAILQ_REMOVE(withdraws, up, prefix_l);
free(up);
}
+}
+
+void
+up_down(struct rde_peer *peer)
+{
+ up_clear(&peer->updates, &peer->withdraws);
+ up_clear(&peer->updates6, &peer->withdraws6);
- TAILQ_INIT(&peer->updates);
- TAILQ_INIT(&peer->withdraws);
RB_INIT(&peer->up_prefix);
RB_INIT(&peer->up_attrs);
@@ -148,7 +156,7 @@ up_attr_cmp(struct update_attr *a, struct update_attr *b)
return (-1);
if (a->attr_len > b->attr_len)
return (1);
- return memcmp(a->attr, b->attr, a->attr_len);
+ return (memcmp(a->attr, b->attr, a->attr_len));
}
int
@@ -156,6 +164,21 @@ up_add(struct rde_peer *peer, struct update_prefix *p, struct update_attr *a)
{
struct update_attr *na = NULL;
struct update_prefix *np;
+ 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");
+ }
/* 1. search for attr */
if (a != NULL && (na = RB_FIND(uptree_attr, &peer->up_attrs, a)) ==
@@ -170,7 +193,7 @@ up_add(struct rde_peer *peer, struct update_prefix *p, struct update_attr *a)
free(p);
return (-1);
}
- TAILQ_INSERT_TAIL(&peer->updates, a, attr_l);
+ TAILQ_INSERT_TAIL(upl, a, attr_l);
peer->up_acnt++;
} else {
/* 1.2 if found -> use that, free a */
@@ -179,8 +202,8 @@ up_add(struct rde_peer *peer, struct update_prefix *p, struct update_attr *a)
free(a);
a = na;
/* move to end of update queue */
- TAILQ_REMOVE(&peer->updates, a, attr_l);
- TAILQ_INSERT_TAIL(&peer->updates, a, attr_l);
+ TAILQ_REMOVE(upl, a, attr_l);
+ TAILQ_INSERT_TAIL(upl, a, attr_l);
}
}
@@ -203,15 +226,15 @@ up_add(struct rde_peer *peer, struct update_prefix *p, struct update_attr *a)
TAILQ_REMOVE(np->prefix_h, np, prefix_l);
free(p);
p = np;
- if (p->prefix_h == &peer->withdraws)
+ if (p->prefix_h == wdl)
peer->up_wcnt--;
else
peer->up_nlricnt--;
}
/* 3. link prefix to attr */
if (a == NULL) {
- TAILQ_INSERT_TAIL(&peer->withdraws, p, prefix_l);
- p->prefix_h = &peer->withdraws;
+ TAILQ_INSERT_TAIL(wdl, p, prefix_l);
+ p->prefix_h = wdl;
peer->up_wcnt++;
} else {
TAILQ_INSERT_TAIL(&a->prefix_h, p, prefix_l);
@@ -227,17 +250,17 @@ up_generate_updates(struct rde_peer *peer,
{
struct update_attr *a;
struct update_prefix *p;
- struct attr *atr;
- struct attr_flags attrs;
+ struct attr *attr;
+ struct rde_aspath *fasp;
struct bgpd_addr addr;
if (peer->state != PEER_UP)
return;
- if (new == NULL || new->aspath->nexthop == NULL ||
- new->aspath->nexthop->state != NEXTHOP_REACH) {
+ if (new == NULL || (new->aspath->nexthop != NULL &&
+ new->aspath->nexthop->state != NEXTHOP_REACH)) {
if (old == NULL)
- /* new prefix got filtered and no old prefex avail */
+ /* new prefix got filtered and no old prefix avail */
return;
if (peer == old->peer)
@@ -245,7 +268,7 @@ up_generate_updates(struct rde_peer *peer,
return;
if (peer->conf.ebgp &&
- !aspath_loopfree(old->aspath->flags.aspath,
+ !aspath_loopfree(old->aspath->aspath,
peer->conf.remote_as))
/*
* Do not send routes back to sender which would
@@ -264,8 +287,7 @@ up_generate_updates(struct rde_peer *peer,
*/
if (old->peer->conf.reflector_client == 0 &&
peer->conf.reflector_client == 0 &&
- (old->aspath->nexthop->flags &
- NEXTHOP_ANNOUNCE) == 0)
+ (old->aspath->flags & F_PREFIX_ANNOUNCED) == 0)
/* Do not redistribute updates to ibgp peers */
return;
}
@@ -283,44 +305,44 @@ up_generate_updates(struct rde_peer *peer,
* pass only prefix that have a aspath count
* of zero this is equal to the ^$ regex.
*/
- if (old->aspath->flags.aspath->ascnt != 0)
+ if (old->aspath->aspath->ascnt != 0)
return;
break;
}
/* well known communities */
- if (rde_filter_community(&old->aspath->flags,
+ if (rde_filter_community(old->aspath,
COMMUNITY_WELLKNOWN, COMMUNITY_NO_ADVERTISE))
return;
- if (peer->conf.ebgp && rde_filter_community(&old->aspath->flags,
+ if (peer->conf.ebgp && rde_filter_community(old->aspath,
COMMUNITY_WELLKNOWN, COMMUNITY_NO_EXPORT))
return;
- if (peer->conf.ebgp && rde_filter_community(&old->aspath->flags,
+ if (peer->conf.ebgp && rde_filter_community(old->aspath,
COMMUNITY_WELLKNOWN, COMMUNITY_NO_EXPSUBCONFED))
return;
/*
- * don't send messages back to originator
- * NOTE this is not specified in the RFC but seems logical.
+ * Don't send messages back to originator
+ * this is not specified in the RFC but seems logical.
*/
- if ((atr = attr_optget(&old->aspath->flags,
+ if ((attr = attr_optget(old->aspath,
ATTR_ORIGINATOR_ID)) != NULL) {
- if (memcmp(atr->data, &peer->remote_bgpid,
+ if (memcmp(attr->data, &peer->remote_bgpid,
sizeof(peer->remote_bgpid)) == 0)
/* would cause loop don't send */
return;
}
/* copy attributes for output filter */
- attr_copy(&attrs, &old->aspath->flags);
+ fasp = path_copy(old->aspath);
pt_getaddr(old->prefix, &addr);
- if (rde_filter(peer, &attrs, &addr,
+ if (rde_filter(peer, fasp, &addr,
old->prefix->prefixlen, DIR_OUT) == ACTION_DENY) {
- attr_free(&attrs);
+ path_put(fasp);
return;
}
- attr_free(&attrs);
+ path_put(fasp);
/* withdraw prefix */
p = calloc(1, sizeof(struct update_prefix));
@@ -339,7 +361,7 @@ up_generate_updates(struct rde_peer *peer,
}
if (peer->conf.ebgp &&
- !aspath_loopfree(new->aspath->flags.aspath,
+ !aspath_loopfree(new->aspath->aspath,
peer->conf.remote_as)) {
/*
* Do not send routes back to sender which would
@@ -360,8 +382,7 @@ up_generate_updates(struct rde_peer *peer,
*/
if (new->peer->conf.reflector_client == 0 &&
peer->conf.reflector_client == 0 &&
- (new->aspath->nexthop->flags &
- NEXTHOP_ANNOUNCE) == 0) {
+ (new->aspath->flags & F_PREFIX_ANNOUNCED) == 0) {
/* Do not redistribute updates to ibgp peers */
up_generate_updates(peer, NULL, old);
return;
@@ -385,7 +406,7 @@ up_generate_updates(struct rde_peer *peer,
* pass only prefix that have a aspath count
* of zero this is equal to the ^$ regex.
*/
- if (new->aspath->flags.aspath->ascnt != 0) {
+ if (new->aspath->aspath->ascnt != 0) {
up_generate_updates(peer, NULL, old);
return;
}
@@ -393,43 +414,43 @@ up_generate_updates(struct rde_peer *peer,
}
/* well known communities */
- if (rde_filter_community(&new->aspath->flags,
+ if (rde_filter_community(new->aspath,
COMMUNITY_WELLKNOWN, COMMUNITY_NO_ADVERTISE)) {
up_generate_updates(peer, NULL, old);
return;
}
- if (peer->conf.ebgp && rde_filter_community(&new->aspath->flags,
+ if (peer->conf.ebgp && rde_filter_community(new->aspath,
COMMUNITY_WELLKNOWN, COMMUNITY_NO_EXPORT)) {
up_generate_updates(peer, NULL, old);
return;
}
- if (peer->conf.ebgp && rde_filter_community(&new->aspath->flags,
+ if (peer->conf.ebgp && rde_filter_community(new->aspath,
COMMUNITY_WELLKNOWN, COMMUNITY_NO_EXPSUBCONFED)) {
up_generate_updates(peer, NULL, old);
return;
}
/* copy attributes for output filter */
- attr_copy(&attrs, &new->aspath->flags);
+ fasp = path_copy(new->aspath);
pt_getaddr(new->prefix, &addr);
- if (rde_filter(peer, &attrs, &addr,
+ if (rde_filter(peer, fasp, &addr,
new->prefix->prefixlen, DIR_OUT) == ACTION_DENY) {
- attr_free(&attrs);
+ path_put(fasp);
up_generate_updates(peer, NULL, old);
return;
}
/*
- * don't send messages back to originator
- * NOTE this is not specified in the RFC but seems logical.
+ * Don't send messages back to originator
+ * this is not specified in the RFC but seems logical.
*/
- if ((atr = attr_optget(&new->aspath->flags,
+ if ((attr = attr_optget(new->aspath,
ATTR_ORIGINATOR_ID)) != NULL) {
- if (memcmp(atr->data, &peer->remote_bgpid,
+ if (memcmp(attr->data, &peer->remote_bgpid,
sizeof(peer->remote_bgpid)) == 0) {
/* would cause loop don't send */
- attr_free(&attrs);
+ path_put(fasp);
return;
}
}
@@ -443,8 +464,7 @@ up_generate_updates(struct rde_peer *peer,
if (a == NULL)
fatal("up_generate_updates");
- if (up_generate_attr(peer, a, &attrs,
- new->aspath->nexthop) == -1) {
+ if (up_generate_attr(peer, a, fasp) == -1) {
log_warnx("generation of bgp path attributes failed");
free(a);
free(p);
@@ -455,13 +475,13 @@ up_generate_updates(struct rde_peer *peer,
* use aspath_hash as attr_hash, this may be unoptimal
* but currently I don't care.
*/
- a->attr_hash = aspath_hash(attrs.aspath->data,
- attrs.aspath->len);
+ a->attr_hash = aspath_hash(fasp->aspath->data,
+ fasp->aspath->len);
p->prefix = addr;
p->prefixlen = new->prefix->prefixlen;
/* no longer needed */
- attr_free(&attrs);
+ path_put(fasp);
if (up_add(peer, p, a) == -1)
log_warnx("queuing update failed.");
@@ -473,32 +493,21 @@ up_generate_default(struct rde_peer *peer, sa_family_t af)
{
struct update_attr *a;
struct update_prefix *p;
- struct attr_flags attrs;
+ struct rde_aspath *asp;
struct bgpd_addr addr;
- struct nexthop nexthop;
- bzero(&attrs, sizeof(attrs));
- bzero(&addr, sizeof(addr));
- bzero(&nexthop, sizeof(nexthop));
-
- attrs.aspath = aspath_get(NULL, 0);
- attrs.nexthop.s_addr = INADDR_ANY;
- /* med = 0 */
- attrs.lpref = DEFAULT_LPREF;
- attrs.origin = ORIGIN_IGP;
- TAILQ_INIT(&attrs.others);
+ asp = path_get();
+ asp->aspath = aspath_get(NULL, 0);
+ asp->origin = ORIGIN_IGP;
+ /* the other default values are OK, nexthop is once again NULL */
- nexthop.state = NEXTHOP_REACH;
- nexthop.flags = NEXTHOP_ANNOUNCE;
- nexthop.exit_nexthop.af = af;
- nexthop.true_nexthop.af = af;
-
- /* apply default overrides. Not yet possible */
+ /* XXX apply default overrides. Not yet possible */
/* filter as usual */
- addr.af = AF_INET;
- if (rde_filter(peer, &attrs, &addr, 0, DIR_OUT) == ACTION_DENY) {
- attr_free(&attrs);
+ bzero(&addr, sizeof(addr));
+ addr.af = af;
+ if (rde_filter(peer, asp, &addr, 0, DIR_OUT) == ACTION_DENY) {
+ path_put(asp);
return;
}
@@ -511,7 +520,7 @@ up_generate_default(struct rde_peer *peer, sa_family_t af)
if (a == NULL)
fatal("up_generate_default");
- if (up_generate_attr(peer, a, &attrs, &nexthop) == -1) {
+ if (up_generate_attr(peer, a, asp) == -1) {
log_warnx("generation of bgp path attributes failed");
free(a);
free(p);
@@ -522,23 +531,33 @@ up_generate_default(struct rde_peer *peer, sa_family_t af)
* use aspath_hash as attr_hash, this may be unoptimal
* but currently I don't care.
*/
- a->attr_hash = aspath_hash(attrs.aspath->data, attrs.aspath->len);
+ a->attr_hash = aspath_hash(asp->aspath->data, asp->aspath->len);
p->prefix = addr;
p->prefixlen = 0; /* default route */
/* no longer needed */
- attr_free(&attrs);
+ path_put(asp);
if (up_add(peer, p, a) == -1)
log_warnx("queuing update failed.");
}
+void
+up_dump_upcall(struct pt_entry *pt, void *ptr)
+{
+ struct rde_peer *peer = ptr;
+
+ if (pt->active == NULL)
+ return;
+ up_generate_updates(peer, pt->active, NULL);
+}
+
u_char up_attr_buf[4096];
int
up_generate_attr(struct rde_peer *peer, struct update_attr *upa,
- struct attr_flags *a, struct nexthop *nh)
+ struct rde_aspath *a)
{
struct aspath *path;
struct attr *oa;
@@ -564,11 +583,13 @@ up_generate_attr(struct rde_peer *peer, struct update_attr *upa,
/* nexthop, already network byte order */
if (peer->conf.ebgp == 0) {
/*
- * if directly connected use peer->local_addr
+ * If directly connected use peer->local_addr
+ * this is only true for announced networks.
*/
- if (nh->flags & NEXTHOP_ANNOUNCE)
+ if (a->nexthop == NULL)
nexthop = peer->local_addr.v4.s_addr;
- else if (a->nexthop.s_addr == peer->remote_addr.v4.s_addr)
+ else if (a->nexthop->exit_nexthop.v4.s_addr ==
+ peer->remote_addr.v4.s_addr)
/*
* per rfc: if remote peer address is equal to
* the nexthop set the nexthop to our local address.
@@ -576,16 +597,17 @@ up_generate_attr(struct rde_peer *peer, struct update_attr *upa,
*/
nexthop = peer->local_addr.v4.s_addr;
else
- nexthop = nh->exit_nexthop.v4.s_addr;
+ nexthop = a->nexthop->exit_nexthop.v4.s_addr;
} else if (peer->conf.distance == 1) {
/* ebgp directly connected */
- if (nh->flags & NEXTHOP_CONNECTED) {
- mask = 0xffffffff << (32 - nh->nexthop_netlen);
+ if (a->nexthop != NULL &&
+ a->nexthop->flags & NEXTHOP_CONNECTED) {
+ mask = 0xffffffff << (32 - a->nexthop->nexthop_netlen);
mask = htonl(mask);
if ((peer->remote_addr.v4.s_addr & mask) ==
- (nh->nexthop_net.v4.s_addr & mask))
+ (a->nexthop->nexthop_net.v4.s_addr & mask))
/* nexthop and peer are in the same net */
- nexthop = nh->exit_nexthop.v4.s_addr;
+ nexthop = a->nexthop->exit_nexthop.v4.s_addr;
else
nexthop = peer->local_addr.v4.s_addr;
} else
@@ -593,9 +615,9 @@ up_generate_attr(struct rde_peer *peer, struct update_attr *upa,
} else
/* ebgp multihop */
/*
- * XXX for ebgp multihop nh->flags should never have
+ * For ebgp multihop nh->flags should never have
* NEXTHOP_CONNECTED set so it should be possible to unify the
- * two ebgp cases.
+ * two ebgp cases. But this is save and RFC compliant.
*/
nexthop = peer->local_addr.v4.s_addr;
@@ -781,12 +803,3 @@ up_dump_attrnlri(u_char *buf, int len, struct rde_peer *peer)
return (wpos);
}
-void
-up_dump_upcall(struct pt_entry *pt, void *ptr)
-{
- struct rde_peer *peer = ptr;
-
- if (pt->active == NULL)
- return;
- up_generate_updates(peer, pt->active, NULL);
-}