summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/bgpd/mrt.c24
-rw-r--r--usr.sbin/bgpd/rde.h21
-rw-r--r--usr.sbin/bgpd/rde_attr.c4
-rw-r--r--usr.sbin/bgpd/rde_community.c117
4 files changed, 145 insertions, 21 deletions
diff --git a/usr.sbin/bgpd/mrt.c b/usr.sbin/bgpd/mrt.c
index 241f59d90d1..c1d744931b0 100644
--- a/usr.sbin/bgpd/mrt.c
+++ b/usr.sbin/bgpd/mrt.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mrt.c,v 1.95 2019/06/22 05:44:05 claudio Exp $ */
+/* $OpenBSD: mrt.c,v 1.96 2019/06/24 06:39:49 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
@@ -34,7 +34,8 @@
#include "mrt.h"
#include "log.h"
-int mrt_attr_dump(struct ibuf *, struct rde_aspath *, struct bgpd_addr *, int);
+int mrt_attr_dump(struct ibuf *, struct rde_aspath *, struct rde_community *,
+ struct bgpd_addr *, int);
int mrt_dump_entry_mp(struct mrt *, struct prefix *, u_int16_t,
struct rde_peer*);
int mrt_dump_entry(struct mrt *, struct prefix *, u_int16_t, struct rde_peer*);
@@ -143,8 +144,8 @@ fail:
}
int
-mrt_attr_dump(struct ibuf *buf, struct rde_aspath *a, struct bgpd_addr *nexthop,
- int v2)
+mrt_attr_dump(struct ibuf *buf, struct rde_aspath *a, struct rde_community *c,
+ struct bgpd_addr *nexthop, int v2)
{
struct attr *oa;
u_char *pdata;
@@ -188,6 +189,10 @@ mrt_attr_dump(struct ibuf *buf, struct rde_aspath *a, struct bgpd_addr *nexthop,
if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_LOCALPREF, &tmp, 4) == -1)
return (-1);
+ /* communities */
+ if (community_writebuf(buf, c) == -1)
+ return (-1);
+
/* dump all other path attributes without modification */
for (l = 0; l < a->others_len; l++) {
if ((oa = a->others[l]) == NULL)
@@ -272,7 +277,8 @@ mrt_dump_entry_mp(struct mrt *mrt, struct prefix *p, u_int16_t snum,
return (-1);
}
- if (mrt_attr_dump(buf, prefix_aspath(p), NULL, 0) == -1) {
+ if (mrt_attr_dump(buf, prefix_aspath(p), prefix_communities(p),
+ NULL, 0) == -1) {
log_warnx("mrt_dump_entry_mp: mrt_attr_dump error");
goto fail;
}
@@ -401,7 +407,8 @@ mrt_dump_entry(struct mrt *mrt, struct prefix *p, u_int16_t snum,
nh = &addr;
} else
nh = &nexthop->exit_nexthop;
- if (mrt_attr_dump(buf, prefix_aspath(p), nh, 0) == -1) {
+ if (mrt_attr_dump(buf, prefix_aspath(p), prefix_communities(p),
+ nh, 0) == -1) {
log_warnx("mrt_dump_entry: mrt_attr_dump error");
ibuf_free(buf);
return (-1);
@@ -529,7 +536,8 @@ mrt_dump_entry_v2(struct mrt *mrt, struct rib_entry *re, u_int32_t snum)
log_warn("%s: ibuf_dynamic", __func__);
return (-1);
}
- if (mrt_attr_dump(tbuf, prefix_aspath(p), nh, 1) == -1) {
+ if (mrt_attr_dump(tbuf, prefix_aspath(p), prefix_communities(p),
+ nh, 1) == -1) {
log_warnx("%s: mrt_attr_dump error", __func__);
ibuf_free(buf);
return (-1);
@@ -641,7 +649,7 @@ mrt_dump_peer(struct ibuf *buf, struct rde_peer *peer)
goto fail;
}
break;
- case AID_UNSPEC: /* XXX special handling for peer_self? */
+ case AID_UNSPEC: /* XXX special handling for peerself? */
DUMP_NLONG(buf, 0);
break;
default:
diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h
index 30d6ffe2db6..4ed581a36e2 100644
--- a/usr.sbin/bgpd/rde.h
+++ b/usr.sbin/bgpd/rde.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.h,v 1.217 2019/06/22 05:44:05 claudio Exp $ */
+/* $OpenBSD: rde.h,v 1.218 2019/06/24 06:39:49 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
@@ -395,20 +395,21 @@ u_char *aspath_override(struct aspath *, u_int32_t, u_int32_t,
u_int16_t *);
int aspath_lenmatch(struct aspath *, enum aslen_spec, u_int);
-int community_match(struct rde_community *, struct community *,
+int community_match(struct rde_community *, struct community *,
struct rde_peer *);
-int community_set(struct rde_community *, struct community *,
+int community_set(struct rde_community *, struct community *,
struct rde_peer *);
-void community_delete(struct rde_community *, struct community *,
+void community_delete(struct rde_community *, struct community *,
struct rde_peer *);
-int community_add(struct rde_community *, int, void *, size_t);
-int community_large_add(struct rde_community *, int, void *, size_t);
-int community_ext_add(struct rde_community *, int, void *, size_t);
+int community_add(struct rde_community *, int, void *, size_t);
+int community_large_add(struct rde_community *, int, void *, size_t);
+int community_ext_add(struct rde_community *, int, void *, size_t);
-int community_write(struct rde_community *, void *, u_int16_t);
-int community_large_write(struct rde_community *, void *, u_int16_t);
-int community_ext_write(struct rde_community *, int, void *, u_int16_t);
+int community_write(struct rde_community *, void *, u_int16_t);
+int community_large_write(struct rde_community *, void *, u_int16_t);
+int community_ext_write(struct rde_community *, int, void *, u_int16_t);
+int community_writebuf(struct ibuf *, struct rde_community *);
void communities_init(u_int32_t);
void communities_shutdown(void);
diff --git a/usr.sbin/bgpd/rde_attr.c b/usr.sbin/bgpd/rde_attr.c
index 95934519a1e..3aaf51bbd1a 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.122 2019/06/17 11:02:19 claudio Exp $ */
+/* $OpenBSD: rde_attr.c,v 1.123 2019/06/24 06:39:49 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -86,7 +86,7 @@ attr_writebuf(struct ibuf *buf, u_int8_t flags, u_int8_t type, void *data,
if (ibuf_add(buf, hdr, flags & ATTR_EXTLEN ? 4 : 3) == -1)
return (-1);
- if (ibuf_add(buf, data, data_len) == -1)
+ if (data && ibuf_add(buf, data, data_len) == -1)
return (-1);
return (0);
}
diff --git a/usr.sbin/bgpd/rde_community.c b/usr.sbin/bgpd/rde_community.c
index 3c074fe12a8..1897c24f489 100644
--- a/usr.sbin/bgpd/rde_community.c
+++ b/usr.sbin/bgpd/rde_community.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_community.c,v 1.1 2019/06/17 11:02:19 claudio Exp $ */
+/* $OpenBSD: rde_community.c,v 1.2 2019/06/24 06:39:49 claudio Exp $ */
/*
* Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
@@ -607,6 +607,121 @@ community_ext_write(struct rde_community *comm, int ebgp, void *buf,
}
/*
+ * Convert communities back to the wireformat and dump them into the ibuf buf.
+ * This function is used by the mrt dump code.
+ */
+int
+community_writebuf(struct ibuf *buf, struct rde_community *comm)
+{
+ size_t l, basic_n = 0, large_n = 0, ext_n = 0;
+ int flags;
+
+ /* first count how many communities will be written */
+ for (l = 0; l < comm->nentries; l++)
+ if ((u_int8_t)comm->communities[l].flags ==
+ COMMUNITY_TYPE_BASIC)
+ basic_n++;
+ else if ((u_int8_t)comm->communities[l].flags ==
+ COMMUNITY_TYPE_EXT)
+ ext_n++;
+ else if ((u_int8_t)comm->communities[l].flags ==
+ COMMUNITY_TYPE_LARGE)
+ large_n++;
+
+
+ if (basic_n != 0) {
+ /* write attribute header */
+ flags = ATTR_OPTIONAL | ATTR_TRANSITIVE;
+ if (comm->flags & PARTIAL_COMMUNITIES)
+ flags |= ATTR_PARTIAL;
+
+ if (attr_writebuf(buf, flags, ATTR_COMMUNITIES, NULL,
+ basic_n * 4) == -1)
+ return -1;
+
+ /* write out the communities */
+ for (l = 0; l < comm->nentries; l++)
+ if ((u_int8_t)comm->communities[l].flags ==
+ COMMUNITY_TYPE_BASIC) {
+ u_int16_t c;
+ c = htons(comm->communities[l].data1);
+ if (ibuf_add(buf, &c, sizeof(c)) == -1)
+ return (-1);
+ c = htons(comm->communities[l].data2);
+ if (ibuf_add(buf, &c, sizeof(c)) == -1)
+ return (-1);
+ }
+ }
+ if (ext_n != 0) {
+ /* write attribute header */
+ flags = ATTR_OPTIONAL | ATTR_TRANSITIVE;
+ if (comm->flags & PARTIAL_COMMUNITIES)
+ flags |= ATTR_PARTIAL;
+
+ if (attr_writebuf(buf, flags, ATTR_EXT_COMMUNITIES, NULL,
+ ext_n * 8) == -1)
+ return -1;
+
+ /* write out the communities */
+ for (l = 0; l < comm->nentries; l++) {
+ struct community *cp;
+ u_int64_t ext;
+
+ cp = comm->communities + l;
+ if ((u_int8_t)cp->flags != COMMUNITY_TYPE_EXT)
+ continue;
+
+ ext = (u_int64_t)cp->data3 << 48;
+ switch (cp->data3 >> 8) {
+ case EXT_COMMUNITY_TRANS_TWO_AS:
+ case EXT_COMMUNITY_TRANS_OPAQUE:
+ case EXT_COMMUNITY_TRANS_EVPN:
+ case EXT_COMMUNITY_NON_TRANS_OPAQUE:
+ ext |= ((u_int64_t)cp->data1 & 0xffff) << 32;
+ ext |= (u_int64_t)cp->data2;
+ break;
+ case EXT_COMMUNITY_TRANS_FOUR_AS:
+ case EXT_COMMUNITY_TRANS_IPV4:
+ ext |= (u_int64_t)cp->data1 << 16;
+ ext |= (u_int64_t)cp->data2 & 0xffff;
+ break;
+ }
+ ext = htobe64(ext);
+ if (ibuf_add(buf, &ext, sizeof(ext)) == -1)
+ return (-1);
+ }
+ }
+ if (large_n != 0) {
+ /* write attribute header */
+ flags = ATTR_OPTIONAL | ATTR_TRANSITIVE;
+ if (comm->flags & PARTIAL_COMMUNITIES)
+ flags |= ATTR_PARTIAL;
+
+ if (attr_writebuf(buf, flags, ATTR_LARGE_COMMUNITIES, NULL,
+ large_n * 12) == -1)
+ return -1;
+
+ /* write out the communities */
+ for (l = 0; l < comm->nentries; l++)
+ if ((u_int8_t)comm->communities[l].flags ==
+ COMMUNITY_TYPE_LARGE) {
+ u_int32_t c;
+ c = htonl(comm->communities[l].data1);
+ if (ibuf_add(buf, &c, sizeof(c)) == -1)
+ return (-1);
+ c = htonl(comm->communities[l].data2);
+ if (ibuf_add(buf, &c, sizeof(c)) == -1)
+ return (-1);
+ c = htonl(comm->communities[l].data3);
+ if (ibuf_add(buf, &c, sizeof(c)) == -1)
+ return (-1);
+ }
+ }
+
+ return 0;
+}
+
+/*
* Global RIB cache for communities
*/
LIST_HEAD(commhead, rde_community);