Noticed this morning working on something else. The non-transitive
extended community support is fairly messed up. In my case (set
ext-community rt 1:1) it causes the community to be skipped.
First of all the check in non_transitive_community() is messed up. It uses
the wrong data field, does a unneccessary ntohl and the logic seems also
to be reversed.
While looking at this I decided to fix the various switch statements on
type to mask out the two high bits with this extending ext community types
should be a bit easier.
While there be strict from where bgpd accepts non-transitive
ext-communities. Now non-transitive ext communities are filtered in and out
for ebgp sessions. So non-transitive ext communities only pass on ibgp
sessions.
For the rde_attr_add() the system defaults to ibgp since this is for
network announcements.
There is also a trivial fix to the bgpd unittests that I excluded here.
With this ext-communities are properly sent on updates.
OK?
--
:wq Claudio
Index: rde.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v
retrieving revision 1.545
diff -u -p -r1.545 rde.c
--- rde.c 6 May 2022 15:51:09 -0000 1.545
+++ rde.c 25 May 2022 12:30:44 -0000
@@ -1917,8 +1917,8 @@ bad_flags:
if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
ATTR_PARTIAL))
goto bad_flags;
- if (community_ext_add(&state->communities, flags, p,
- attr_len) == -1) {
+ if (community_ext_add(&state->communities, flags,
+ peer->conf.ebgp, p, attr_len) == -1) {
/*
* mark update as bad and withdraw all routes as per
* RFC 7606
@@ -2062,8 +2062,8 @@ rde_attr_add(struct filterstate *state,
return community_large_add(&state->communities, flags, p,
attr_len);
case ATTR_EXT_COMMUNITIES:
- return community_ext_add(&state->communities, flags, p,
- attr_len);
+ return community_ext_add(&state->communities, flags, 0,
+ p, attr_len);
}
if (attr_optadd(&state->aspath, flags, type, p, attr_len) == -1)
Index: rde.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v
retrieving revision 1.251
diff -u -p -r1.251 rde.h
--- rde.h 22 Mar 2022 10:53:08 -0000 1.251
+++ rde.h 25 May 2022 12:30:44 -0000
@@ -459,7 +459,7 @@ void community_delete(struct rde_communi
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_ext_add(struct rde_community *, int, int, void *, size_t);
int community_write(struct rde_community *, void *, uint16_t);
int community_large_write(struct rde_community *, void *, uint16_t);
Index: rde_community.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_community.c,v
retrieving revision 1.4
diff -u -p -r1.4 rde_community.c
--- rde_community.c 6 Feb 2022 09:51:19 -0000 1.4
+++ rde_community.c 25 May 2022 12:30:44 -0000
@@ -99,7 +99,7 @@ fc2c(struct community *fc, struct rde_pe
subtype = fc->data3 & 0xff;
c->data3 = type << 8 | subtype;
- switch (type) {
+ switch (type & EXT_COMMUNITY_VALUE) {
case -1:
/* special case for 'ext-community rt *' */
if ((fc->flags >> 8 & 0xff) != COMMUNITY_ANY ||
@@ -141,7 +141,6 @@ fc2c(struct community *fc, struct rde_pe
return 0;
case EXT_COMMUNITY_TRANS_OPAQUE:
case EXT_COMMUNITY_TRANS_EVPN:
- case EXT_COMMUNITY_NON_TRANS_OPAQUE:
if ((fc->flags >> 8 & 0xff) == COMMUNITY_ANY)
break;
@@ -244,10 +243,9 @@ insert_community(struct rde_community *c
}
static int
-non_transitive_community(struct community *c)
+non_transitive_ext_community(struct community *c)
{
- if ((uint8_t)c->flags == COMMUNITY_TYPE_EXT &&
- !((ntohl(c->data1) >> 24) & EXT_COMMUNITY_NON_TRANSITIVE))
+ if ((c->data3 >> 8) & EXT_COMMUNITY_NON_TRANSITIVE)
return 1;
return 0;
}
@@ -404,7 +402,8 @@ community_large_add(struct rde_community
}
int
-community_ext_add(struct rde_community *comm, int flags, void *buf, size_t len)
+community_ext_add(struct rde_community *comm, int flags, int ebgp,
+ void *buf, size_t len)
{
struct community set = { .flags = COMMUNITY_TYPE_EXT };
uint8_t *b = buf, type;
@@ -422,11 +421,13 @@ community_ext_add(struct rde_community *
c = be64toh(c);
type = c >> 56;
- switch (type) {
+ /* filter out non-transitive ext communuties from ebgp peers */
+ if (ebgp && (type & EXT_COMMUNITY_NON_TRANSITIVE))
+ continue;
+ switch (type & EXT_COMMUNITY_VALUE) {
case EXT_COMMUNITY_TRANS_TWO_AS:
case EXT_COMMUNITY_TRANS_OPAQUE:
case EXT_COMMUNITY_TRANS_EVPN:
- case EXT_COMMUNITY_NON_TRANS_OPAQUE:
set.data1 = c >> 32 & 0xffff;
set.data2 = c;
break;
@@ -564,7 +565,7 @@ community_ext_write(struct rde_community
for (l = 0; l < comm->nentries; l++)
if ((uint8_t)comm->communities[l].flags ==
COMMUNITY_TYPE_EXT && !(ebgp &&
- non_transitive_community(&comm->communities[l])))
+ non_transitive_ext_community(&comm->communities[l])))
n++;
if (n == 0)
@@ -580,13 +581,12 @@ community_ext_write(struct rde_community
for (l = 0; l < comm->nentries; l++) {
cp = comm->communities + l;
if ((uint8_t)cp->flags == COMMUNITY_TYPE_EXT && !(ebgp &&
- non_transitive_community(cp))) {
+ non_transitive_ext_community(cp))) {
ext = (uint64_t)cp->data3 << 48;
- switch (cp->data3 >> 8) {
+ switch ((cp->data3 >> 8) & EXT_COMMUNITY_VALUE) {
case EXT_COMMUNITY_TRANS_TWO_AS:
case EXT_COMMUNITY_TRANS_OPAQUE:
case EXT_COMMUNITY_TRANS_EVPN:
- case EXT_COMMUNITY_NON_TRANS_OPAQUE:
ext |= ((uint64_t)cp->data1 & 0xffff) << 32;
ext |= (uint64_t)cp->data2;
break;
@@ -672,11 +672,10 @@ community_writebuf(struct ibuf *buf, str
continue;
ext = (uint64_t)cp->data3 << 48;
- switch (cp->data3 >> 8) {
+ switch ((cp->data3 >> 8) & EXT_COMMUNITY_VALUE) {
case EXT_COMMUNITY_TRANS_TWO_AS:
case EXT_COMMUNITY_TRANS_OPAQUE:
case EXT_COMMUNITY_TRANS_EVPN:
- case EXT_COMMUNITY_NON_TRANS_OPAQUE:
ext |= ((uint64_t)cp->data1 & 0xffff) << 32;
ext |= (uint64_t)cp->data2;
break;
@@ -919,7 +918,7 @@ community_to_rd(struct community *fc, ui
if (fc2c(fc, NULL, &c, NULL) == -1)
return -1;
- switch (c.data3 >> 8) {
+ switch ((c.data3 >> 8) & EXT_COMMUNITY_VALUE) {
case EXT_COMMUNITY_TRANS_TWO_AS:
rd = (0ULL << 48);
rd |= ((uint64_t)c.data1 & 0xffff) << 32;