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;
>