On Mon, Jan 30, 2023 at 03:29:49PM +0100, Claudio Jeker wrote: > Extended communities are annoying, especially the ASnum encodings are a > problem since the same extended community can be encoded in more than one > way. This results in strange behaviour when used with local-as and/or > neighbor-as. > > This diff changes the match function for any community with masks (either > a * or local-as/neighbor-as) to work both for two and four byte ASnum > encoding. Now this change will allow for some impossible encodings but > because these are impossible the match function will not match and on > insert the best solution is selected or the insertion fails.
Makes sense, and reads fine. ok tb > > In general I would suggest to stay away from extended communities as much > as possible. Especially since large-communities solve all these issues. > > -- > :wq Claudio > > Index: parse.y > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v > retrieving revision 1.440 > diff -u -p -r1.440 parse.y > --- parse.y 24 Jan 2023 14:13:11 -0000 1.440 > +++ parse.y 30 Jan 2023 13:57:05 -0000 > @@ -4083,11 +4083,11 @@ parseextvalue(int type, char *s, uint32_ > } else if (strcmp(s, "neighbor-as") == 0) { > *flag = COMMUNITY_NEIGHBOR_AS; > *v = 0; > - return EXT_COMMUNITY_TRANS_FOUR_AS; > + return EXT_COMMUNITY_TRANS_TWO_AS; > } else if (strcmp(s, "local-as") == 0) { > *flag = COMMUNITY_LOCAL_AS; > *v = 0; > - return EXT_COMMUNITY_TRANS_FOUR_AS; > + return EXT_COMMUNITY_TRANS_TWO_AS; > } else if ((p = strchr(s, '.')) == NULL) { > /* AS_PLAIN number (4 or 2 byte) */ > strtonum(s, 0, USHRT_MAX, &errstr); > Index: rde_community.c > =================================================================== > RCS file: /cvs/src/usr.sbin/bgpd/rde_community.c,v > retrieving revision 1.10 > diff -u -p -r1.10 rde_community.c > --- rde_community.c 28 Dec 2022 21:30:16 -0000 1.10 > +++ rde_community.c 30 Jan 2023 13:57:06 -0000 > @@ -112,6 +112,7 @@ fc2c(struct community *fc, struct rde_pe > c->data3 = type << 8 | subtype; > switch (type & EXT_COMMUNITY_VALUE) { > case EXT_COMMUNITY_TRANS_TWO_AS: > + case EXT_COMMUNITY_TRANS_FOUR_AS: > if ((fc->flags >> 8 & 0xff) == COMMUNITY_ANY) > break; > > @@ -121,11 +122,9 @@ fc2c(struct community *fc, struct rde_pe > if (apply_flag(fc->data2, fc->flags >> 16, peer, > &c->data2, m ? &m->data2 : NULL)) > return -1; > - /* check that values fit */ > - if (c->data1 > USHRT_MAX) > - return -1; > + if (m) > + m->data3 ^= EXT_COMMUNITY_TRANS_FOUR_AS << 8; > return 0; > - case EXT_COMMUNITY_TRANS_FOUR_AS: > case EXT_COMMUNITY_TRANS_IPV4: > if ((fc->flags >> 8 & 0xff) == COMMUNITY_ANY) > break; > @@ -268,7 +267,6 @@ struct rde_peer *peer) > sizeof(*fc), fast_match) != NULL); > } else { > /* slow path */ > - > if (fc2c(fc, peer, &test, &mask) == -1) > return 0; > > @@ -335,6 +333,24 @@ struct rde_peer *peer) > } else { > if (fc2c(fc, peer, &set, NULL) == -1) > return 0; > + if ((uint8_t)set.flags == COMMUNITY_TYPE_EXT) { > + int type = (int)set.data3 >> 8; > + switch (type & EXT_COMMUNITY_VALUE) { > + case EXT_COMMUNITY_TRANS_TWO_AS: > + case EXT_COMMUNITY_TRANS_FOUR_AS: > + /* check that values fit */ > + if (set.data1 > USHRT_MAX && > + set.data2 > USHRT_MAX) > + return 0; > + if (set.data1 > USHRT_MAX) > + set.data3 = (set.data3 & 0xff) | > + EXT_COMMUNITY_TRANS_FOUR_AS << 8; > + else > + set.data3 = (set.data3 & 0xff) | > + EXT_COMMUNITY_TRANS_TWO_AS << 8; > + break; > + } > + } > insert_community(comm, &set); > } > return 1; >