This introduces max-communities, max-ext-communities and
max-large-communities for filters which allows to limit the number of
communities in a path.

The 3 filters can all be used together and also with other match filters
including community X:Y.
-- 
:wq Claudio

Index: bgpd.conf.5
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.conf.5,v
retrieving revision 1.219
diff -u -p -r1.219 bgpd.conf.5
--- bgpd.conf.5 31 Mar 2022 17:27:29 -0000      1.219
+++ bgpd.conf.5 25 May 2022 07:33:06 -0000
@@ -1609,6 +1609,19 @@ is repeated more than
 .Ar len
 times.
 .Pp
+.It Ic max-communities Ns | Ns Ic max-large-communities Ns | \
+Ns Ic max-ext-communities Ar num
+This rule applies only to
+.Em UPDATES
+where the
+.Em Basic, 
+.Em Large ,
+or
+.Em Extended Community
+attribute has more than
+.Ar num
+elements.
+.Pp
 .It Ic nexthop Ar address
 This rule applies only to
 .Em UPDATES
Index: bgpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
retrieving revision 1.424
diff -u -p -r1.424 bgpd.h
--- bgpd.h      25 May 2022 16:03:34 -0000      1.424
+++ bgpd.h      25 May 2022 16:59:01 -0000
@@ -1053,6 +1053,9 @@ struct filter_match {
        struct filter_prefixset         prefixset;
        struct filter_originset         originset;
        struct filter_ovs               ovs;
+       int                             maxcomm;
+       int                             maxextcomm;
+       int                             maxlargecomm;
 };
 
 struct filter_rule {
Index: parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v
retrieving revision 1.424
diff -u -p -r1.424 parse.y
--- parse.y     23 May 2022 13:40:12 -0000      1.424
+++ parse.y     25 May 2022 12:29:12 -0000
@@ -220,6 +220,7 @@ typedef struct {
 %token FROM TO ANY
 %token CONNECTED STATIC
 %token COMMUNITY EXTCOMMUNITY LARGECOMMUNITY DELETE
+%token MAXCOMMUNITIES MAXEXTCOMMUNITIES MAXLARGECOMMUNITIES
 %token PREFIX PREFIXLEN PREFIXSET
 %token ROASET ORIGINSET OVS EXPIRES
 %token ASSET SOURCEAS TRANSITAS PEERAS MAXASLEN MAXASSEQ
@@ -2338,6 +2339,46 @@ filter_elm       : filter_prefix_h       {
                        }
                        free($3);
                }
+               | MAXCOMMUNITIES NUMBER {
+                       if ($2 < 0 || $2 > INT16_MAX) {
+                               yyerror("bad max-comunities %lld", $2);
+                               YYERROR;
+                       }
+                       if (fmopts.m.maxcomm != 0) {
+                               yyerror("%s already specified",
+                                   "max-communities");
+                               YYERROR;
+                       }
+                       /*
+                        * Offset by 1 since 0 means not used.
+                        * The match function then uses >= to compensate.
+                        */
+                       fmopts.m.maxcomm = $2 + 1;
+               }
+               | MAXEXTCOMMUNITIES NUMBER {
+                       if ($2 < 0 || $2 > INT16_MAX) {
+                               yyerror("bad max-ext-communities %lld", $2);
+                               YYERROR;
+                       }
+                       if (fmopts.m.maxextcomm != 0) {
+                               yyerror("%s already specified",
+                                   "max-ext-communities");
+                               YYERROR;
+                       }
+                       fmopts.m.maxextcomm = $2 + 1;
+               }
+               | MAXLARGECOMMUNITIES NUMBER {
+                       if ($2 < 0 || $2 > INT16_MAX) {
+                               yyerror("bad max-large-communities %lld", $2);
+                               YYERROR;
+                       }
+                       if (fmopts.m.maxlargecomm != 0) {
+                               yyerror("%s already specified",
+                                   "max-large-communities");
+                               YYERROR;
+                       }
+                       fmopts.m.maxlargecomm = $2 + 1;
+               }
                | NEXTHOP address       {
                        if (fmopts.m.nexthop.flags) {
                                yyerror("nexthop already specified");
@@ -2999,6 +3040,9 @@ lookup(char *s)
                { "match",              MATCH},
                { "max-as-len",         MAXASLEN},
                { "max-as-seq",         MAXASSEQ},
+               { "max-communities",    MAXCOMMUNITIES},
+               { "max-ext-communities",        MAXEXTCOMMUNITIES},
+               { "max-large-communities",      MAXLARGECOMMUNITIES},
                { "max-prefix",         MAXPREFIX},
                { "maxlen",             MAXLEN},
                { "md5sig",             MD5SIG},
Index: printconf.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/printconf.c,v
retrieving revision 1.151
diff -u -p -r1.151 printconf.c
--- printconf.c 25 May 2022 16:03:34 -0000      1.151
+++ printconf.c 25 May 2022 16:59:01 -0000
@@ -925,6 +925,13 @@ print_rule(struct bgpd_config *conf, str
                }
        }
 
+       if (r->match.maxcomm != 0)
+               printf("max-communities %d ", r->match.maxcomm - 1);
+       if (r->match.maxextcomm != 0)
+               printf("max-ext-communities %d ", r->match.maxextcomm - 1);
+       if (r->match.maxlargecomm != 0)
+               printf("max-large-communities %d ", r->match.maxlargecomm - 1);
+
        print_set(&r->set);
 
        printf("\n");
Index: rde.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v
retrieving revision 1.252
diff -u -p -r1.252 rde.h
--- rde.h       25 May 2022 16:03:34 -0000      1.252
+++ rde.h       25 May 2022 16:59:01 -0000
@@ -452,6 +452,7 @@ int          aspath_lenmatch(struct aspath *, e
 /* rde_community.c */
 int    community_match(struct rde_community *, struct community *,
            struct rde_peer *);
+int    community_count(struct rde_community *, uint8_t type);
 int    community_set(struct rde_community *, struct community *,
            struct rde_peer *);
 void   community_delete(struct rde_community *, struct community *,
Index: rde_community.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_community.c,v
retrieving revision 1.5
diff -u -p -r1.5 rde_community.c
--- rde_community.c     25 May 2022 16:03:34 -0000      1.5
+++ rde_community.c     25 May 2022 16:59:24 -0000
@@ -283,6 +283,45 @@ struct rde_peer *peer)
 }
 
 /*
+ * Count the number of communities of type type.
+ */
+int
+community_count(struct rde_community *comm, uint8_t type)
+{
+       size_t l;
+       int count = 0;
+       
+       /* use the fact that the array is ordered by type */
+       switch (type) {
+       case COMMUNITY_TYPE_BASIC:
+               for (l = 0; l < comm->nentries; l++) {
+                       if ((uint8_t)comm->communities[l].flags == type)
+                               count++;
+                       else
+                               break;
+               }
+               break;
+       case COMMUNITY_TYPE_EXT:
+               for (l = 0; l < comm->nentries; l++) {
+                       if ((uint8_t)comm->communities[l].flags == type)
+                               count++;
+                       else if ((uint8_t)comm->communities[l].flags > type)
+                               break;
+               }
+               break;
+       case COMMUNITY_TYPE_LARGE:
+               for (l = comm->nentries; l > 0; l--) {
+                       if ((uint8_t)comm->communities[l - 1].flags == type)
+                               count++;
+                       else
+                               break;
+               }
+               break;
+       }
+       return count;
+}
+
+/*
  * Insert a community, expanding local-as and neighbor-as if needed.
  */
 int
Index: rde_filter.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_filter.c,v
retrieving revision 1.127
diff -u -p -r1.127 rde_filter.c
--- rde_filter.c        6 Feb 2022 09:51:19 -0000       1.127
+++ rde_filter.c        25 May 2022 10:03:38 -0000
@@ -246,6 +246,22 @@ rde_filter_match(struct filter_rule *f, 
                        return (0);
        }
 
+       if (f->match.maxcomm != 0) {
+               if (f->match.maxcomm >
+                   community_count(&state->communities, COMMUNITY_TYPE_BASIC))
+                       return (0);
+       }
+       if (f->match.maxextcomm != 0) {
+               if (f->match.maxextcomm >
+                   community_count(&state->communities, COMMUNITY_TYPE_EXT))
+                       return (0);
+       }
+       if (f->match.maxlargecomm != 0) {
+               if (f->match.maxlargecomm >
+                   community_count(&state->communities, COMMUNITY_TYPE_LARGE))
+                       return (0);
+       }
+
        if (f->match.nexthop.flags != 0) {
                struct bgpd_addr *nexthop, *cmpaddr;
                if (state->nexthop == NULL)

Reply via email to