On Wed, May 25, 2022 at 04:27:46PM +0200, Claudio Jeker wrote:
> On Wed, May 25, 2022 at 03:50:38PM +0200, Theo Buehler wrote:
> > On Wed, May 25, 2022 at 02:46:55PM +0200, Claudio Jeker wrote:
> > > 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?
> > 
> > Makes sense, one comment below.
> > 
> > > -- 
> > > :wq Claudio
> > > 
> > > 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:
> > 
> > Should that '-1' not be changed to 'EXT_COMMUNITY_VALUE'?  Since you now
> > mask out the high two bits, it is no longer possible to reach this case.
> 
> Good point. I decided to refactor the code a but and move the -1 case into
> its own if statement above the switch. I think this is the best solution
> here. I also did tidy up some types. 

parseextcommunity(), parseextvalue() and parsesubtype() still use an int
for type and log_ext_subtype() uses a short. Not sure if you want to
adjust them as well.

The diff reads ok now.

> 
> -- 
> :wq Claudio
> 
> Index: bgpd.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
> retrieving revision 1.423
> diff -u -p -r1.423 bgpd.h
> --- bgpd.h    23 May 2022 13:40:11 -0000      1.423
> +++ bgpd.h    25 May 2022 14:14:24 -0000
> @@ -989,7 +989,7 @@ struct filter_peers {
>  #define EXT_COMMUNITY_FLAG_VALID     0x01
>  
>  struct ext_comm_pairs {
> -     short           type;
> +     uint8_t         type;
>       uint8_t         subtype;
>       const char      *subname;
>  };
> 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 14:19:39 -0000
> @@ -61,7 +61,7 @@ static int
>  fc2c(struct community *fc, struct rde_peer *peer, struct community *c,
>      struct community *m)
>  {
> -     short type;
> +     int type;
>       uint8_t subtype;
>  
>       memset(c, 0, sizeof(*c));
> @@ -98,9 +98,7 @@ fc2c(struct community *fc, struct rde_pe
>               type = (int32_t)fc->data3 >> 8;
>               subtype = fc->data3 & 0xff;
>  
> -             c->data3 = type << 8 | subtype;
> -             switch (type) {
> -             case -1:
> +             if (type == -1) {
>                       /* special case for 'ext-community rt *' */
>                       if ((fc->flags >> 8 & 0xff) != COMMUNITY_ANY ||
>                           m == NULL)
> @@ -110,6 +108,10 @@ fc2c(struct community *fc, struct rde_pe
>                       m->data2 = 0;
>                       m->data3 = 0xff;
>                       return 0;
> +             }
> +
> +             c->data3 = type << 8 | subtype;
> +             switch (type & EXT_COMMUNITY_VALUE) {
>               case EXT_COMMUNITY_TRANS_TWO_AS:
>                       if ((fc->flags >> 8 & 0xff) == COMMUNITY_ANY)
>                               break;
> @@ -141,7 +143,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 +245,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 +404,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 +423,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 +567,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 +583,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 +674,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 +920,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;

Reply via email to