This is a large diff that changes the way communities are stored in
filters and filter_sets. Both standard communities and large communities
now share the same data structure for lookups and at the same time the
filters are extended to allow more then one community to match per rule
(currently the maximum is 3). I did leave extended communities outside for
now since this diff is already big enough but they will follow in a second
step.

So now filters like
        deny to any large-community 196618:0:666 large-community 196618:0:3
        deny to any community 13030:1016 community 13030:50000
will work and match only if both communities are matched.

As a side effect the bgpctl show rib code is changed and there is no
longer a limitation that only one of the filter is allowed to be used.
In other words 'bgpctl show rib as 13030 community 1303:1036' will
work now.

Apart from that there should be no other visible change.

Please test and report back
-- 
:wq Claudio

PS: diff is against /usr/src since both bgpd and bgpctl need to be patched

Index: usr.sbin/bgpctl/bgpctl.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.c,v
retrieving revision 1.223
diff -u -p -r1.223 bgpctl.c
--- usr.sbin/bgpctl/bgpctl.c    1 Nov 2018 10:09:52 -0000       1.223
+++ usr.sbin/bgpctl/bgpctl.c    13 Nov 2018 13:43:04 -0000
@@ -173,14 +173,7 @@ main(int argc, char *argv[])
                        ribreq.prefix = res->addr;
                        ribreq.prefixlen = res->prefixlen;
                }
-               if (res->community.as != COMMUNITY_UNSET &&
-                   res->community.type != COMMUNITY_UNSET)
-                       ribreq.community = res->community;
-               if (res->large_community.as != COMMUNITY_UNSET &&
-                   res->large_community.ld1 != COMMUNITY_UNSET &&
-                   res->large_community.ld2 != COMMUNITY_UNSET)
-                       ribreq.large_community = res->large_community;
-               /* XXX extended communities missing? */
+               /* XXX currently no communities support */
                ribreq.neighbor = neighbor;
                ribreq.aid = res->aid;
                ribreq.flags = res->flags;
@@ -277,30 +270,17 @@ main(int argc, char *argv[])
        case SHOW_RIB:
                bzero(&ribreq, sizeof(ribreq));
                type = IMSG_CTL_SHOW_RIB;
-               if (res->as.type != AS_UNDEF) {
-                       ribreq.as = res->as;
-                       type = IMSG_CTL_SHOW_RIB_AS;
-               }
                if (res->addr.aid) {
                        ribreq.prefix = res->addr;
                        ribreq.prefixlen = res->prefixlen;
                        type = IMSG_CTL_SHOW_RIB_PREFIX;
                }
-               if (res->community.as != COMMUNITY_UNSET &&
-                   res->community.type != COMMUNITY_UNSET) {
+               if (res->as.type != AS_UNDEF)
+                       ribreq.as = res->as;
+               if (res->community.type != COMMUNITY_TYPE_NONE)
                        ribreq.community = res->community;
-                       type = IMSG_CTL_SHOW_RIB_COMMUNITY;
-               }
-               if (res->extcommunity.flags == EXT_COMMUNITY_FLAG_VALID) {
+               if (res->extcommunity.flags == EXT_COMMUNITY_FLAG_VALID)
                        ribreq.extcommunity = res->extcommunity;
-                       type = IMSG_CTL_SHOW_RIB_EXTCOMMUNITY;
-               }
-               if (res->large_community.as != COMMUNITY_UNSET &&
-                   res->large_community.ld1 != COMMUNITY_UNSET &&
-                   res->large_community.ld2 != COMMUNITY_UNSET) {
-                       ribreq.large_community = res->large_community;
-                       type = IMSG_CTL_SHOW_RIB_LARGECOMMUNITY;
-               }
                ribreq.neighbor = neighbor;
                strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib));
                ribreq.aid = res->aid;
@@ -399,14 +379,7 @@ main(int argc, char *argv[])
                        ribreq.prefix = res->addr;
                        ribreq.prefixlen = res->prefixlen;
                }
-               if (res->community.as != COMMUNITY_UNSET &&
-                   res->community.type != COMMUNITY_UNSET)
-                       ribreq.community = res->community;
-               if (res->large_community.as != COMMUNITY_UNSET &&
-                   res->large_community.ld1 != COMMUNITY_UNSET &&
-                   res->large_community.ld2 != COMMUNITY_UNSET)
-                       ribreq.large_community = res->large_community;
-               /* XXX ext communities missing? */
+               /* XXX currently no community support */
                ribreq.neighbor = neighbor;
                ribreq.aid = res->aid;
                ribreq.flags = res->flags;
Index: usr.sbin/bgpctl/parser.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/parser.c,v
retrieving revision 1.86
diff -u -p -r1.86 parser.c
--- usr.sbin/bgpctl/parser.c    3 Oct 2018 11:36:39 -0000       1.86
+++ usr.sbin/bgpctl/parser.c    13 Nov 2018 09:13:35 -0000
@@ -478,12 +478,10 @@ int                        parse_addr(const char *, 
struct b
 int                     parse_asnum(const char *, size_t, u_int32_t *);
 int                     parse_number(const char *, struct parse_result *,
                             enum token_type);
-int                     getcommunity(const char *);
 int                     parse_community(const char *, struct parse_result *);
 int                     parsesubtype(const char *, u_int8_t *, u_int8_t *);
 int                     parseextvalue(const char *, u_int32_t *);
 u_int                   parseextcommunity(const char *, struct parse_result *);
-u_int                   getlargecommunity(const char *);
 int                     parse_largecommunity(const char *,
                             struct parse_result *);
 int                     parse_nexthop(const char *, struct parse_result *);
@@ -496,11 +494,6 @@ parse(int argc, char *argv[])
        const struct token      *match;
 
        bzero(&res, sizeof(res));
-       res.community.as = COMMUNITY_UNSET;
-       res.community.type = COMMUNITY_UNSET;
-       res.large_community.as = COMMUNITY_UNSET;
-       res.large_community.ld1 = COMMUNITY_UNSET;
-       res.large_community.ld2 = COMMUNITY_UNSET;
        res.rtableid = getrtable();
        TAILQ_INIT(&res.set);
        if ((res.irr_outdir = getcwd(NULL, 0)) == NULL) {
@@ -1019,19 +1012,26 @@ parse_number(const char *word, struct pa
        return (1);
 }
 
-int
-getcommunity(const char *s)
+static u_int32_t
+getcommunity(const char *s, int large, u_int8_t *flag)
 {
+       int64_t          max = USHRT_MAX;
        const char      *errstr;
-       u_int16_t        uval;
+       u_int32_t        uval;
+
+       if (strcmp(s, "*") == 0) {
+               *flag = COMMUNITY_ANY;
+               return (0);
+       }
 
-       if (strcmp(s, "*") == 0)
-               return (COMMUNITY_ANY);
+       if (large)
+               max = UINT_MAX;
 
-       uval = strtonum(s, 0, USHRT_MAX, &errstr);
+       uval = strtonum(s, 0, max, &errstr);
        if (errstr)
                errx(1, "Community is %s: %s", errstr, s);
 
+       *flag = 0;
        return (uval);
 }
 
@@ -1040,7 +1040,8 @@ parse_community(const char *word, struct
 {
        struct filter_set       *fs;
        char                    *p;
-       int                      as, type;
+       u_int32_t                as, type;
+       u_int8_t                 asflag, tflag;
 
        /* Well-known communities */
        if (strcasecmp(word, "GRACEFUL_SHUTDOWN") == 0) {
@@ -1075,33 +1076,20 @@ parse_community(const char *word, struct
        }
        *p++ = 0;
 
-       as = getcommunity(word);
-       type = getcommunity(p);
+       as = getcommunity(word, 0, &asflag);
+       type = getcommunity(p, 0, &tflag);
 
 done:
-       if (as == 0) {
-               fprintf(stderr, "Invalid community\n");
-               return (0);
-       }
-       if (as == COMMUNITY_WELLKNOWN)
-               switch (type) {
-               case COMMUNITY_GRACEFUL_SHUTDOWN:
-               case COMMUNITY_NO_EXPORT:
-               case COMMUNITY_NO_ADVERTISE:
-               case COMMUNITY_NO_EXPSUBCONFED:
-               case COMMUNITY_BLACKHOLE:
-                       /* valid */
-                       break;
-               }
-
        if ((fs = calloc(1, sizeof(struct filter_set))) == NULL)
                err(1, NULL);
        fs->type = ACTION_SET_COMMUNITY;
-       fs->action.community.as = as;
-       fs->action.community.type = type;
+       fs->action.community.type = COMMUNITY_TYPE_BASIC;
+       fs->action.community.data1 = as;
+       fs->action.community.data2 = type;
+       fs->action.community.dflag1 = asflag;
+       fs->action.community.dflag2 = tflag;
 
-       r->community.as = as;
-       r->community.type = type;
+       r->community = fs->action.community;
 
        TAILQ_INSERT_TAIL(&r->set, fs, entry);
        return (1);
@@ -1285,22 +1273,6 @@ parseextcommunity(const char *word, stru
        return (0);
 }
 
-u_int
-getlargecommunity(const char *s)
-{
-       const char      *errstr;
-       u_int32_t        uval;
-
-       if (strcmp(s, "*") == 0)
-               return (COMMUNITY_ANY);
-
-       uval = strtonum(s, 0, UINT_MAX, &errstr);
-       if (errstr)
-               errx(1, "Large Community is %s: %s", errstr, s);
-
-       return (uval);
-}
-
 int
 parse_largecommunity(const char *word, struct parse_result *r)
 {
@@ -1308,7 +1280,8 @@ parse_largecommunity(const char *word, s
        char            *p, *po = strdup(word);
        char            *array[3] = { NULL, NULL, NULL };
        char            *val;
-       int64_t          as, ld1, ld2;
+       u_int32_t        as, ld1, ld2;
+       u_int8_t         asflag, ld1flag, ld2flag;
        int              i = 0;
 
        p = po;
@@ -1320,22 +1293,24 @@ parse_largecommunity(const char *word, s
        if ((p != NULL) || !(array[0] && array[1] && array[2]))
                errx(1, "Invalid Large-Community syntax");
 
-       as   = getlargecommunity(array[0]);
-       ld1  = getlargecommunity(array[1]);
-       ld2  = getlargecommunity(array[2]);
+       as = getcommunity(array[0], 1, &asflag);
+       ld1 = getcommunity(array[1], 1, &ld1flag);
+       ld2 = getcommunity(array[2], 1, &ld2flag);
 
        free(po);
 
        if ((fs = calloc(1, sizeof(struct filter_set))) == NULL)
                err(1, NULL);
-       fs->type = ACTION_SET_LARGE_COMMUNITY;
-       fs->action.large_community.as = as;
-       fs->action.large_community.ld1 = ld1;
-       fs->action.large_community.ld2 = ld2;
-
-       r->large_community.as = as;
-       r->large_community.ld1 = ld1;
-       r->large_community.ld2 = ld2;
+       fs->type = ACTION_SET_COMMUNITY;
+       fs->action.community.type = COMMUNITY_TYPE_LARGE;
+       fs->action.community.data1 = as;
+       fs->action.community.data2 = ld1;
+       fs->action.community.data3 = ld2;
+       fs->action.community.dflag1 = asflag;
+       fs->action.community.dflag2 = ld1flag;
+       fs->action.community.dflag3 = ld2flag;
+
+       r->community = fs->action.community;
 
        TAILQ_INSERT_TAIL(&r->set, fs, entry);
        return (1);
Index: usr.sbin/bgpctl/parser.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/parser.h,v
retrieving revision 1.31
diff -u -p -r1.31 parser.h
--- usr.sbin/bgpctl/parser.h    1 Oct 2018 23:09:53 -0000       1.31
+++ usr.sbin/bgpctl/parser.h    12 Nov 2018 14:49:31 -0000
@@ -64,7 +64,6 @@ struct parse_result {
        struct filter_set_head   set;
        struct filter_community  community;
        struct filter_extcommunity extcommunity;
-       struct filter_largecommunity  large_community;
        char                     peerdesc[PEER_DESCR_LEN];
        char                     rib[PEER_DESCR_LEN];
        char                     shutcomm[SHUT_COMM_LEN];
Index: usr.sbin/bgpd/bgpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
retrieving revision 1.353
diff -u -p -r1.353 bgpd.h
--- usr.sbin/bgpd/bgpd.h        10 Nov 2018 11:19:01 -0000      1.353
+++ usr.sbin/bgpd/bgpd.h        13 Nov 2018 09:18:58 -0000
@@ -50,6 +50,7 @@
 #define        READ_BUF_SIZE                   65535
 #define        RT_BUF_SIZE                     16384
 #define        MAX_RTSOCK_BUF                  (2 * 1024 * 1024)
+#define MAX_COMM_MATCH                 3
 
 #define        BGPD_OPT_VERBOSE                0x0001
 #define        BGPD_OPT_VERBOSE2               0x0002
@@ -427,12 +428,8 @@ enum imsg_type {
        IMSG_CTL_SHOW_NEXTHOP,
        IMSG_CTL_SHOW_INTERFACE,
        IMSG_CTL_SHOW_RIB,
-       IMSG_CTL_SHOW_RIB_AS,
        IMSG_CTL_SHOW_RIB_PREFIX,
        IMSG_CTL_SHOW_RIB_ATTR,
-       IMSG_CTL_SHOW_RIB_COMMUNITY,
-       IMSG_CTL_SHOW_RIB_EXTCOMMUNITY,
-       IMSG_CTL_SHOW_RIB_LARGECOMMUNITY,
        IMSG_CTL_SHOW_NETWORK,
        IMSG_CTL_SHOW_RIB_MEM,
        IMSG_CTL_SHOW_RIB_HASH,
@@ -741,14 +738,13 @@ struct filter_ovs {
 };
 
 struct filter_community {
-       int             as;
-       int             type;
-};
-
-struct filter_largecommunity {
-       int64_t         as;
-       int64_t         ld1;
-       int64_t         ld2;
+       u_int8_t        type;
+       u_int8_t        dflag1; /* one of set, any, local-as, neighbor-as */
+       u_int8_t        dflag2;
+       u_int8_t        dflag3;
+       u_int32_t       data1;
+       u_int32_t       data2;
+       u_int32_t       data3;
 };
 
 struct filter_extcommunity {
@@ -779,7 +775,6 @@ struct ctl_show_rib_request {
        struct filter_as        as;
        struct filter_community community;
        struct filter_extcommunity extcommunity;
-       struct filter_largecommunity large_community;
        u_int32_t               peerid;
        u_int32_t               flags;
        u_int8_t                validation_state;
@@ -829,11 +824,16 @@ struct filter_peers {
 };
 
 /* special community type */
-#define        COMMUNITY_ERROR                 -1
-#define        COMMUNITY_ANY                   -2
-#define        COMMUNITY_NEIGHBOR_AS           -3
-#define        COMMUNITY_LOCAL_AS              -4
-#define        COMMUNITY_UNSET                 -5
+#define        COMMUNITY_TYPE_NONE             0
+#define        COMMUNITY_TYPE_BASIC            1
+#define        COMMUNITY_TYPE_EXT              2
+#define        COMMUNITY_TYPE_LARGE            3
+
+#define        COMMUNITY_ANY                   1
+#define        COMMUNITY_NEIGHBOR_AS           2
+#define        COMMUNITY_LOCAL_AS              3
+
+/* wellknown community definitions */
 #define        COMMUNITY_WELLKNOWN             0xffff
 #define        COMMUNITY_GRACEFUL_SHUTDOWN     0x0000  /* RFC 8326 */
 #define        COMMUNITY_BLACKHOLE             0x029A  /* RFC 7999 */
@@ -928,8 +928,7 @@ struct filter_match {
        struct filter_nexthop           nexthop;
        struct filter_as                as;
        struct filter_aslen             aslen;
-       struct filter_community         community;
-       struct filter_largecommunity    large_community;
+       struct filter_community         community[MAX_COMM_MATCH];
        struct filter_extcommunity      ext_community;
        struct filter_prefixset         prefixset;
        struct filter_originset         originset;
@@ -974,8 +973,6 @@ enum action_types {
        ACTION_SET_NEXTHOP_SELF,
        ACTION_SET_COMMUNITY,
        ACTION_DEL_COMMUNITY,
-       ACTION_DEL_LARGE_COMMUNITY,
-       ACTION_SET_LARGE_COMMUNITY,
        ACTION_SET_EXT_COMMUNITY,
        ACTION_DEL_EXT_COMMUNITY,
        ACTION_PFTABLE,
@@ -996,7 +993,6 @@ struct filter_set {
                struct bgpd_addr                 nexthop;
                struct nexthop                  *nh;
                struct filter_community          community;
-               struct filter_largecommunity     large_community;
                struct filter_extcommunity       ext_community;
                char                             pftable[PFTABLE_LEN];
                char                             rtlabel[RTLABEL_LEN];
Index: usr.sbin/bgpd/control.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/control.c,v
retrieving revision 1.90
diff -u -p -r1.90 control.c
--- usr.sbin/bgpd/control.c     11 Aug 2017 16:02:53 -0000      1.90
+++ usr.sbin/bgpd/control.c     13 Nov 2018 09:22:56 -0000
@@ -248,12 +248,8 @@ control_dispatch_msg(struct pollfd *pfd,
                        case IMSG_CTL_SHOW_NEXTHOP:
                        case IMSG_CTL_SHOW_INTERFACE:
                        case IMSG_CTL_SHOW_RIB:
-                       case IMSG_CTL_SHOW_RIB_AS:
                        case IMSG_CTL_SHOW_RIB_PREFIX:
                        case IMSG_CTL_SHOW_RIB_MEM:
-                       case IMSG_CTL_SHOW_RIB_COMMUNITY:
-                       case IMSG_CTL_SHOW_RIB_EXTCOMMUNITY:
-                       case IMSG_CTL_SHOW_RIB_LARGECOMMUNITY:
                        case IMSG_CTL_SHOW_NETWORK:
                        case IMSG_CTL_SHOW_TERSE:
                        case IMSG_CTL_SHOW_TIMER:
@@ -421,7 +417,6 @@ control_dispatch_msg(struct pollfd *pfd,
                            IMSG_HEADER_SIZE);
                        break;
                case IMSG_CTL_SHOW_RIB:
-               case IMSG_CTL_SHOW_RIB_AS:
                case IMSG_CTL_SHOW_RIB_PREFIX:
                        if (imsg.hdr.len == IMSG_HEADER_SIZE +
                            sizeof(struct ctl_show_rib_request)) {
@@ -471,9 +466,6 @@ control_dispatch_msg(struct pollfd *pfd,
                                    "wrong length");
                        break;
                case IMSG_CTL_SHOW_RIB_MEM:
-               case IMSG_CTL_SHOW_RIB_COMMUNITY:
-               case IMSG_CTL_SHOW_RIB_EXTCOMMUNITY:
-               case IMSG_CTL_SHOW_RIB_LARGECOMMUNITY:
                case IMSG_CTL_SHOW_NETWORK:
                        c->ibuf.pid = imsg.hdr.pid;
                        imsg_ctl_rde(imsg.hdr.type, imsg.hdr.pid,
Index: usr.sbin/bgpd/parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v
retrieving revision 1.362
diff -u -p -r1.362 parse.y
--- usr.sbin/bgpd/parse.y       1 Nov 2018 00:18:44 -0000       1.362
+++ usr.sbin/bgpd/parse.y       12 Nov 2018 13:20:59 -0000
@@ -153,9 +153,7 @@ int          merge_filterset(struct filter_set_
 void            merge_filter_lists(struct filter_head *, struct filter_head *);
 struct filter_rule     *get_rule(enum action_types);
 
-int64_t                 getcommunity(char *, int);
-int             parsecommunity(struct filter_community *, char *);
-int             parselargecommunity(struct filter_largecommunity *, char *);
+int             parsecommunity(struct filter_community *, int, char *);
 int             parsesubtype(char *, int *, int *);
 int             parseextvalue(char *, u_int32_t *);
 int             parseextcommunity(struct filter_extcommunity *, char *,
@@ -232,7 +230,7 @@ typedef struct {
 %type  <v.addr>                address
 %type  <v.prefix>              prefix addrspec
 %type  <v.prefixset_item>      prefixset_item
-%type  <v.u8>                  action quick direction delete
+%type  <v.u8>                  action quick direction delete community
 %type  <v.filter_rib>          filter_rib_h filter_rib_l filter_rib
 %type  <v.filter_peers>        filter_peer filter_peer_l filter_peer_h
 %type  <v.filter_match>        filter_match filter_elm filter_match_h
@@ -2085,13 +2083,9 @@ filter_as        : as4number_any         {
 
 filter_match_h : /* empty */                   {
                        bzero(&$$, sizeof($$));
-                       $$.m.community.as = COMMUNITY_UNSET;
-                       $$.m.large_community.as = COMMUNITY_UNSET;
                }
                | {
                        bzero(&fmopts, sizeof(fmopts));
-                       fmopts.m.community.as = COMMUNITY_UNSET;
-                       fmopts.m.large_community.as = COMMUNITY_UNSET;
                }
                    filter_match                {
                        memcpy(&$$, &fmopts, sizeof($$));
@@ -2146,25 +2140,20 @@ filter_elm      : filter_prefix_h       {
                        fmopts.m.aslen.type = ASLEN_SEQ;
                        fmopts.m.aslen.aslen = $2;
                }
-               | COMMUNITY STRING      {
-                       if (fmopts.m.community.as != COMMUNITY_UNSET) {
-                               yyerror("\"community\" already specified");
-                               free($2);
-                               YYERROR;
+               | community STRING      {
+                       int i;
+                       for (i = 0; i < MAX_COMM_MATCH; i++) {
+                               if (fmopts.m.community[i].type ==
+                                   COMMUNITY_TYPE_NONE)
+                                       break;
                        }
-                       if (parsecommunity(&fmopts.m.community, $2) == -1) {
+                       if (i >= MAX_COMM_MATCH) {
+                               yyerror("too many \"community\" filters "
+                                   "specified");
                                free($2);
                                YYERROR;
                        }
-                       free($2);
-               }
-               | LARGECOMMUNITY STRING {
-                       if (fmopts.m.large_community.as != COMMUNITY_UNSET) {
-                               yyerror("\"large-community\" already 
specified");
-                               free($2);
-                               YYERROR;
-                       }
-                       if (parselargecommunity(&fmopts.m.large_community, $2) 
== -1) {
+                       if (parsecommunity(&fmopts.m.community[i], $1, $2) == 
-1) {
                                free($2);
                                YYERROR;
                        }
@@ -2405,6 +2394,10 @@ filter_set_l     : filter_set_l comma filter
                }
                ;
 
+community      : COMMUNITY             { $$ = COMMUNITY_TYPE_BASIC; }
+               | LARGECOMMUNITY        { $$ = COMMUNITY_TYPE_LARGE; }
+               ;
+
 delete         : /* empty */   { $$ = 0; }
                | DELETE        { $$ = 1; }
                ;
@@ -2637,7 +2630,7 @@ filter_set_opt    : LOCALPREF NUMBER              {
                        }
                        free($2);
                }
-               | COMMUNITY delete STRING       {
+               | community delete STRING       {
                        if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
                                fatal(NULL);
                        if ($2)
@@ -2645,30 +2638,8 @@ filter_set_opt   : LOCALPREF NUMBER              {
                        else
                                $$->type = ACTION_SET_COMMUNITY;
 
-                       if (parsecommunity(&$$->action.community, $3) == -1) {
-                               free($3);
-                               free($$);
-                               YYERROR;
-                       }
-                       free($3);
-                       /* Don't allow setting of any match */
-                       if (!$2 && ($$->action.community.as == COMMUNITY_ANY ||
-                           $$->action.community.type == COMMUNITY_ANY)) {
-                               yyerror("'*' is not allowed in set community");
-                               free($$);
-                               YYERROR;
-                       }
-               }
-               | LARGECOMMUNITY delete STRING  {
-                       if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
-                               fatal(NULL);
-                       if ($2)
-                               $$->type = ACTION_DEL_LARGE_COMMUNITY;
-                       else
-                               $$->type = ACTION_SET_LARGE_COMMUNITY;
-
-                       if (parselargecommunity(&$$->action.large_community,
-                           $3) == -1) {
+                       if (parsecommunity(&$$->action.community, $1, $3) ==
+                           -1) {
                                free($3);
                                free($$);
                                YYERROR;
@@ -2676,9 +2647,9 @@ filter_set_opt    : LOCALPREF NUMBER              {
                        free($3);
                        /* Don't allow setting of any match */
                        if (!$2 &&
-                           ($$->action.large_community.as == COMMUNITY_ANY ||
-                           $$->action.large_community.ld1 == COMMUNITY_ANY ||
-                           $$->action.large_community.ld2 == COMMUNITY_ANY)) {
+                           ($$->action.community.dflag1 == COMMUNITY_ANY ||
+                           $$->action.community.dflag2 == COMMUNITY_ANY ||
+                           $$->action.community.dflag3 == COMMUNITY_ANY)) {
                                yyerror("'*' is not allowed in set community");
                                free($$);
                                YYERROR;
@@ -3470,60 +3441,105 @@ symget(const char *nam)
        return (NULL);
 }
 
-int64_t
-getcommunity(char *s, int large)
+static int
+getcommunity(char *s, int large, u_int32_t *val, u_int8_t *flag)
 {
        int64_t          max = USHRT_MAX;
-       u_int            val;
        const char      *errstr;
 
-       if (strcmp(s, "*") == 0)
-               return (COMMUNITY_ANY);
-       if (strcmp(s, "neighbor-as") == 0)
-               return (COMMUNITY_NEIGHBOR_AS);
-       if (strcmp(s, "local-as") == 0)
-               return (COMMUNITY_LOCAL_AS);
+       *flag = 0;
+       *val = 0;
+       if (strcmp(s, "*") == 0) {
+               *flag = COMMUNITY_ANY;
+               return 0;
+       } else if (strcmp(s, "neighbor-as") == 0) {
+               *flag = COMMUNITY_NEIGHBOR_AS;
+               return 0;
+       } else if (strcmp(s, "local-as") == 0) {
+               *flag =  COMMUNITY_LOCAL_AS;
+               return 0;
+       }
        if (large)
                max = UINT_MAX;
-       val = strtonum(s, 0, max, &errstr);
+       *val = strtonum(s, 0, max, &errstr);
        if (errstr) {
                yyerror("Community %s is %s (max: %llu)", s, errstr, max);
-               return (COMMUNITY_ERROR);
+               return -1;
        }
-       return (val);
+       return 0;
 }
 
+static void
+setcommunity(struct filter_community *c, u_int32_t as, u_int32_t data,
+    u_int8_t asflag, u_int8_t dataflag)
+{
+       memset(c, 0, sizeof(*c));
+       c->type = COMMUNITY_TYPE_BASIC;
+       c->dflag1 = asflag;
+       c->dflag2 = dataflag;
+       c->data1 = as;
+       c->data2 = data;
+}
+
+static int
+parselargecommunity(struct filter_community *c, char *s)
+{
+       char *p, *q;
+
+       if ((p = strchr(s, ':')) == NULL) {
+               yyerror("Bad community syntax");
+               return (-1);
+       }
+       *p++ = 0;
+
+       if ((q = strchr(p, ':')) == NULL) {
+               yyerror("Bad community syntax");
+               return (-1);
+       }
+       *q++ = 0;
+
+       if (getcommunity(s, 1, &c->data1, &c->dflag1) == -1 ||
+           getcommunity(p, 1, &c->data2, &c->dflag2) == -1 ||
+           getcommunity(q, 1, &c->data3, &c->dflag3) == -1)
+               return (-1);
+       c->type = COMMUNITY_TYPE_LARGE;
+       return (0);
+}
 
 int
-parsecommunity(struct filter_community *c, char *s)
+parsecommunity(struct filter_community *c, int type, char *s)
 {
        char *p;
-       int i, as;
+       u_int32_t as, data;
+       u_int8_t asflag, dataflag;
+
+       if (type == COMMUNITY_TYPE_LARGE)
+               return parselargecommunity(c, s);
 
        /* Well-known communities */
        if (strcasecmp(s, "GRACEFUL_SHUTDOWN") == 0) {
-               c->as = COMMUNITY_WELLKNOWN;
-               c->type = COMMUNITY_GRACEFUL_SHUTDOWN;
+               setcommunity(c, COMMUNITY_WELLKNOWN,
+                   COMMUNITY_GRACEFUL_SHUTDOWN, 0, 0);
                return (0);
        } else if (strcasecmp(s, "NO_EXPORT") == 0) {
-               c->as = COMMUNITY_WELLKNOWN;
-               c->type = COMMUNITY_NO_EXPORT;
+               setcommunity(c, COMMUNITY_WELLKNOWN,
+                   COMMUNITY_NO_EXPORT, 0, 0);
                return (0);
        } else if (strcasecmp(s, "NO_ADVERTISE") == 0) {
-               c->as = COMMUNITY_WELLKNOWN;
-               c->type = COMMUNITY_NO_ADVERTISE;
+               setcommunity(c, COMMUNITY_WELLKNOWN,
+                   COMMUNITY_NO_ADVERTISE, 0, 0);
                return (0);
        } else if (strcasecmp(s, "NO_EXPORT_SUBCONFED") == 0) {
-               c->as = COMMUNITY_WELLKNOWN;
-               c->type = COMMUNITY_NO_EXPSUBCONFED;
+               setcommunity(c, COMMUNITY_WELLKNOWN,
+                   COMMUNITY_NO_EXPSUBCONFED, 0, 0);
                return (0);
        } else if (strcasecmp(s, "NO_PEER") == 0) {
-               c->as = COMMUNITY_WELLKNOWN;
-               c->type = COMMUNITY_NO_PEER;
+               setcommunity(c, COMMUNITY_WELLKNOWN,
+                   COMMUNITY_NO_PEER, 0, 0);
                return (0);
        } else if (strcasecmp(s, "BLACKHOLE") == 0) {
-               c->as = COMMUNITY_WELLKNOWN;
-               c->type = COMMUNITY_BLACKHOLE;
+               setcommunity(c, COMMUNITY_WELLKNOWN,
+                   COMMUNITY_BLACKHOLE, 0, 0);
                return (0);
        }
 
@@ -3533,49 +3549,10 @@ parsecommunity(struct filter_community *
        }
        *p++ = 0;
 
-       if ((i = getcommunity(s, 0)) == COMMUNITY_ERROR)
+       if (getcommunity(s, 0, &as, &asflag) == -1 ||
+           getcommunity(p, 0, &data, &dataflag) == -1)
                return (-1);
-       as = i;
-
-       if ((i = getcommunity(p, 0)) == COMMUNITY_ERROR)
-               return (-1);
-       c->as = as;
-       c->type = i;
-
-       return (0);
-}
-
-int
-parselargecommunity(struct filter_largecommunity *c, char *s)
-{
-       char *p, *q;
-       int64_t as, ld1, ld2;
-
-       if ((p = strchr(s, ':')) == NULL) {
-               yyerror("Bad community syntax");
-               return (-1);
-       }
-       *p++ = 0;
-
-       if ((q = strchr(p, ':')) == NULL) {
-               yyerror("Bad community syntax");
-               return (-1);
-       }
-       *q++ = 0;
-
-       if ((as = getcommunity(s, 1)) == COMMUNITY_ERROR)
-               return (-1);
-
-       if ((ld1 = getcommunity(p, 1)) == COMMUNITY_ERROR)
-               return (-1);
-
-       if ((ld2 = getcommunity(q, 1)) == COMMUNITY_ERROR)
-               return (-1);
-
-       c->as = as;
-       c->ld1 = ld1;
-       c->ld2 = ld2;
-
+       setcommunity(c, as, data, asflag, dataflag);
        return (0);
 }
 
@@ -4218,10 +4195,6 @@ merge_filterset(struct filter_set_head *
                                yyerror("community is already set");
                        else if (s->type == ACTION_DEL_COMMUNITY)
                                yyerror("community will already be deleted");
-                       else if (s->type == ACTION_SET_LARGE_COMMUNITY)
-                               yyerror("large-community is already set");
-                       else if (s->type == ACTION_DEL_LARGE_COMMUNITY)
-                               yyerror("large-community will already be 
deleted");
                        else if (s->type == ACTION_SET_EXT_COMMUNITY)
                                yyerror("ext-community is already set");
                        else if (s->type == ACTION_DEL_EXT_COMMUNITY)
@@ -4243,21 +4216,9 @@ merge_filterset(struct filter_set_head *
                        switch (s->type) {
                        case ACTION_SET_COMMUNITY:
                        case ACTION_DEL_COMMUNITY:
-                               if (s->action.community.as <
-                                   t->action.community.as ||
-                                   (s->action.community.as ==
-                                   t->action.community.as &&
-                                   s->action.community.type <
-                                   t->action.community.type)) {
-                                       TAILQ_INSERT_BEFORE(t, s, entry);
-                                       return (0);
-                               }
-                               break;
-                       case ACTION_SET_LARGE_COMMUNITY:
-                       case ACTION_DEL_LARGE_COMMUNITY:
-                               if (memcmp(&s->action.large_community,
-                                   &t->action.large_community,
-                                   sizeof(s->action.large_community)) < 0) {
+                               if (memcmp(&s->action.community,
+                                   &t->action.community,
+                                   sizeof(s->action.community)) < 0) {
                                        TAILQ_INSERT_BEFORE(t, s, entry);
                                        return (0);
                                }
@@ -4321,8 +4282,6 @@ get_rule(enum action_types type)
                r->quick = 0;
                r->dir = out ? DIR_OUT : DIR_IN;
                r->action = ACTION_NONE;
-               r->match.community.as = COMMUNITY_UNSET;
-               r->match.large_community.as = COMMUNITY_UNSET;
                TAILQ_INIT(&r->set);
                if (curpeer == curgroup) {
                        /* group */
Index: usr.sbin/bgpd/printconf.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/printconf.c,v
retrieving revision 1.123
diff -u -p -r1.123 printconf.c
--- usr.sbin/bgpd/printconf.c   29 Sep 2018 08:11:11 -0000      1.123
+++ usr.sbin/bgpd/printconf.c   12 Nov 2018 13:26:07 -0000
@@ -30,7 +30,8 @@
 #include "log.h"
 
 void            print_prefix(struct filter_prefix *p);
-void            print_community(int, int);
+const char     *community_type(struct filter_community *c);
+void            print_community(struct filter_community *c);
 void            print_largecommunity(int64_t, int64_t, int64_t);
 void            print_extcommunity(struct filter_extcommunity *);
 void            print_origin(u_int8_t);
@@ -104,61 +105,100 @@ print_prefix(struct filter_prefix *p)
        }
 }
 
-void
-print_community(int as, int type)
+const char *
+community_type(struct filter_community *c)
 {
-       if (as == COMMUNITY_ANY)
-               printf("*:");
-       else if (as == COMMUNITY_NEIGHBOR_AS)
-               printf("neighbor-as:");
-       else if (as == COMMUNITY_LOCAL_AS)
-               printf("local-as:");
-       else
-               printf("%u:", (unsigned int)as);
-
-       if (type == COMMUNITY_ANY)
-               printf("* ");
-       else if (type == COMMUNITY_NEIGHBOR_AS)
-               printf("neighbor-as ");
-       else if (type == COMMUNITY_LOCAL_AS)
-               printf("local-as");
-       else
-               printf("%d ", type);
+       switch (c->type) {
+       case COMMUNITY_TYPE_BASIC:
+               return "community";
+       case COMMUNITY_TYPE_LARGE:
+               return "large-community";
+       default:
+               return "???";
+       }
 }
 
 void
-print_largecommunity(int64_t as, int64_t ld1, int64_t ld2)
+print_community(struct filter_community *c)
 {
-       if (as == COMMUNITY_ANY)
-               printf("*:");
-       else if (as == COMMUNITY_NEIGHBOR_AS)
-               printf("neighbor-as:");
-       else if (as == COMMUNITY_LOCAL_AS)
-               printf("local-as:");
-       else
-               printf("%lld:", as);
-
-       if (ld1 == COMMUNITY_ANY)
-               printf("*:");
-       else if (ld1 == COMMUNITY_NEIGHBOR_AS)
-               printf("neighbor-as:");
-       else if (ld1 == COMMUNITY_LOCAL_AS)
-               printf("local-as:");
-       else
-               printf("%lld:", ld1);
-
-       if (ld2 == COMMUNITY_ANY)
-               printf("* ");
-       else if (ld2 == COMMUNITY_NEIGHBOR_AS)
-               printf("neighbor-as ");
-       else if (ld2 == COMMUNITY_LOCAL_AS)
-               printf("local-as ");
-       else
-               printf("%lld ", ld2);
-
+       switch (c->type) {
+       case COMMUNITY_TYPE_BASIC:
+               switch (c->dflag1) {
+               case COMMUNITY_ANY:
+                       printf("*:");
+                       break;
+               case COMMUNITY_NEIGHBOR_AS:
+                       printf("neighbor-as:");
+                       break;
+               case COMMUNITY_LOCAL_AS:
+                       printf("local-as:");
+                       break;
+               default:
+                       printf("%u:", c->data1);
+                       break;
+               }
+               switch (c->dflag2) {
+               case COMMUNITY_ANY:
+                       printf("* ");
+                       break;
+               case COMMUNITY_NEIGHBOR_AS:
+                       printf("neighbor-as ");
+                       break;
+               case COMMUNITY_LOCAL_AS:
+                       printf("local-as ");
+                       break;
+               default:
+                       printf("%u ", c->data2);
+                       break;
+               }
+               break;
+       case COMMUNITY_TYPE_LARGE:
+               switch (c->dflag1) {
+               case COMMUNITY_ANY:
+                       printf("*:");
+                       break;
+               case COMMUNITY_NEIGHBOR_AS:
+                       printf("neighbor-as:");
+                       break;
+               case COMMUNITY_LOCAL_AS:
+                       printf("local-as:");
+                       break;
+               default:
+                       printf("%u:", c->data1);
+                       break;
+               }
+               switch (c->dflag2) {
+               case COMMUNITY_ANY:
+                       printf("*:");
+                       break;
+               case COMMUNITY_NEIGHBOR_AS:
+                       printf("neighbor-as:");
+                       break;
+               case COMMUNITY_LOCAL_AS:
+                       printf("local-as:");
+                       break;
+               default:
+                       printf("%u:", c->data2);
+                       break;
+               }
+               switch (c->dflag3) {
+               case COMMUNITY_ANY:
+                       printf("* ");
+                       break;
+               case COMMUNITY_NEIGHBOR_AS:
+                       printf("neighbor-as ");
+                       break;
+               case COMMUNITY_LOCAL_AS:
+                       printf("local-as ");
+                       break;
+               default:
+                       printf("%u ", c->data3);
+                       break;
+               }
+               break;
+       }
 }
 
-
 void
 print_extcommunity(struct filter_extcommunity *c)
 {
@@ -263,30 +303,13 @@ print_set(struct filter_set_head *set)
                        printf("prepend-neighbor %u ", s->action.prepend);
                        break;
                case ACTION_DEL_COMMUNITY:
-                       printf("community delete ");
-                       print_community(s->action.community.as,
-                           s->action.community.type);
-                       printf(" ");
+                       printf("%s delete ",
+                           community_type(&s->action.community));
+                       print_community(&s->action.community);
                        break;
                case ACTION_SET_COMMUNITY:
-                       printf("community ");
-                       print_community(s->action.community.as,
-                           s->action.community.type);
-                       printf(" ");
-                       break;
-               case ACTION_DEL_LARGE_COMMUNITY:
-                       printf("large-community delete ");
-                       print_largecommunity(s->action.large_community.as,
-                           s->action.large_community.ld1,
-                           s->action.large_community.ld2);
-                       printf(" ");
-                       break;
-               case ACTION_SET_LARGE_COMMUNITY:
-                       printf("large-community ");
-                       print_largecommunity(s->action.large_community.as,
-                           s->action.large_community.ld1,
-                           s->action.large_community.ld2);
-                       printf(" ");
+                       printf("%s ", community_type(&s->action.community));
+                       print_community(&s->action.community);
                        break;
                case ACTION_PFTABLE:
                        printf("pftable %s ", s->action.pftable);
@@ -715,7 +738,8 @@ void print_as(struct filter_rule *r)
 void
 print_rule(struct peer *peer_l, struct filter_rule *r)
 {
-       struct peer     *p;
+       struct peer *p;
+       int i;
 
        if (r->action == ACTION_ALLOW)
                printf("allow ");
@@ -817,20 +841,16 @@ print_rule(struct peer *peer_l, struct f
                    "max-as-len" : "max-as-seq", r->match.aslen.aslen);
        }
 
-       if (r->match.community.as != COMMUNITY_UNSET) {
-               printf("community ");
-               print_community(r->match.community.as,
-                   r->match.community.type);
+       for (i = 0; i < MAX_COMM_MATCH; i++) {
+               struct filter_community *c = &r->match.community[i];
+               if (c->type != COMMUNITY_TYPE_NONE) {
+                       printf("%s ", community_type(c));
+                       print_community(c);
+               }
        }
        if (r->match.ext_community.flags & EXT_COMMUNITY_FLAG_VALID) {
                printf("ext-community ");
                print_extcommunity(&r->match.ext_community);
-       }
-       if (r->match.large_community.as != COMMUNITY_UNSET) {
-               printf("large-community ");
-               print_largecommunity(r->match.large_community.as,
-                   r->match.large_community.ld1,
-                   r->match.large_community.ld2);
        }
 
        print_set(&r->set);
Index: usr.sbin/bgpd/rde.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v
retrieving revision 1.449
diff -u -p -r1.449 rde.c
--- usr.sbin/bgpd/rde.c 10 Nov 2018 11:19:01 -0000      1.449
+++ usr.sbin/bgpd/rde.c 13 Nov 2018 09:38:08 -0000
@@ -583,10 +583,6 @@ badnetdel:
                        break;
                case IMSG_CTL_SHOW_NETWORK:
                case IMSG_CTL_SHOW_RIB:
-               case IMSG_CTL_SHOW_RIB_AS:
-               case IMSG_CTL_SHOW_RIB_COMMUNITY:
-               case IMSG_CTL_SHOW_RIB_EXTCOMMUNITY:
-               case IMSG_CTL_SHOW_RIB_LARGECOMMUNITY:
                case IMSG_CTL_SHOW_RIB_PREFIX:
                        if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(req)) {
                                log_warnx("rde_dispatch: wrong imsg len");
@@ -2224,21 +2220,24 @@ rde_dump_filter(struct prefix *p, struct
        if ((req->flags & F_CTL_INVALID) &&
            (asp->flags & F_ATTR_PARSE_ERR) == 0)
                return;
-       if (req->type == IMSG_CTL_SHOW_RIB_AS &&
-           !aspath_match(asp->aspath->data, asp->aspath->len,
-           &req->as, 0))
+       if (req->as.type != AS_UNDEF && !aspath_match(asp->aspath->data,
+           asp->aspath->len, &req->as, 0))
                return;
-       if (req->type == IMSG_CTL_SHOW_RIB_COMMUNITY &&
-           !community_match(asp, req->community.as,
-           req->community.type))
-               return;
-       if (req->type == IMSG_CTL_SHOW_RIB_EXTCOMMUNITY &&
+       switch (req->community.type) {
+       case COMMUNITY_TYPE_NONE:
+               break;
+       case COMMUNITY_TYPE_BASIC:
+               if (!community_match(asp, &req->community, NULL))
+                       return;
+               break;
+       case COMMUNITY_TYPE_LARGE:
+               if (!community_large_match(asp, &req->community, NULL))
+                       return;
+               break;
+       }
+       if (req->extcommunity.flags == EXT_COMMUNITY_FLAG_VALID &&
            !community_ext_match(asp, &req->extcommunity, 0))
                return;
-       if (req->type == IMSG_CTL_SHOW_RIB_LARGECOMMUNITY &&
-           !community_large_match(asp, req->large_community.as,
-           req->large_community.ld1, req->large_community.ld2))
-               return;
        if (!ovs_match(p, req->flags))
                return;
        rde_dump_rib_as(p, asp, req->pid, req->flags);
@@ -2334,10 +2333,6 @@ rde_dump_ctx_new(struct ctl_show_rib_req
                        goto nomem;
                break;
        case IMSG_CTL_SHOW_RIB:
-       case IMSG_CTL_SHOW_RIB_AS:
-       case IMSG_CTL_SHOW_RIB_COMMUNITY:
-       case IMSG_CTL_SHOW_RIB_EXTCOMMUNITY:
-       case IMSG_CTL_SHOW_RIB_LARGECOMMUNITY:
                if (rib_dump_new(rid, ctx->req.aid, CTL_MSG_HIGH_MARK, ctx,
                    rde_dump_upcall, rde_dump_done, rde_dump_throttled) == -1)
                        goto nomem;
Index: usr.sbin/bgpd/rde.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v
retrieving revision 1.202
diff -u -p -r1.202 rde.h
--- usr.sbin/bgpd/rde.h 4 Nov 2018 12:34:54 -0000       1.202
+++ usr.sbin/bgpd/rde.h 12 Nov 2018 13:39:09 -0000
@@ -361,25 +361,28 @@ int                aspath_loopfree(struct aspath *, u
 int             aspath_compare(struct aspath *, struct aspath *);
 u_char         *aspath_prepend(struct aspath *, u_int32_t, int, u_int16_t *);
 int             aspath_lenmatch(struct aspath *, enum aslen_spec, u_int);
-int             community_match(struct rde_aspath *, int, int);
-int             community_set(struct rde_aspath *, int, int);
-void            community_delete(struct rde_aspath *, int, int);
-int             community_large_match(struct rde_aspath *, int64_t, int64_t,
-                   int64_t);
-int             community_large_set(struct rde_aspath *, int64_t, int64_t,
-                   int64_t);
-void            community_large_delete(struct rde_aspath *, int64_t,
-                   int64_t, int64_t);
-int             community_ext_match(struct rde_aspath *,
-                   struct filter_extcommunity *, u_int16_t);
-int             community_ext_set(struct rde_aspath *,
-                   struct filter_extcommunity *, u_int16_t);
-void            community_ext_delete(struct rde_aspath *,
-                   struct filter_extcommunity *, u_int16_t);
-int             community_ext_conv(struct filter_extcommunity *, u_int16_t,
-                   u_int64_t *);
-u_char         *community_ext_delete_non_trans(u_char *, u_int16_t,
-                   u_int16_t *);
+
+int     community_match(struct rde_aspath *, struct filter_community *,
+           struct rde_peer *);
+int     community_set(struct rde_aspath *, struct filter_community *,
+           struct rde_peer *);
+void    community_delete(struct rde_aspath *, struct filter_community *,
+           struct rde_peer *);
+int     community_large_match(struct rde_aspath *, struct filter_community *,
+           struct rde_peer *);
+int     community_large_set(struct rde_aspath *, struct filter_community *,
+           struct rde_peer *);
+void    community_large_delete(struct rde_aspath *, struct filter_community *,
+           struct rde_peer *);
+int     community_ext_match(struct rde_aspath *,
+           struct filter_extcommunity *, u_int16_t);
+int     community_ext_set(struct rde_aspath *,
+           struct filter_extcommunity *, u_int16_t);
+void    community_ext_delete(struct rde_aspath *,
+           struct filter_extcommunity *, u_int16_t);
+int     community_ext_conv(struct filter_extcommunity *, u_int16_t,
+           u_int64_t *);
+u_char *community_ext_delete_non_trans(u_char *, u_int16_t, u_int16_t *);
 
 /* rde_decide.c */
 void            prefix_evaluate(struct prefix *, struct rib_entry *);
Index: usr.sbin/bgpd/rde_attr.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_attr.c,v
retrieving revision 1.112
diff -u -p -r1.112 rde_attr.c
--- usr.sbin/bgpd/rde_attr.c    10 Oct 2018 06:21:47 -0000      1.112
+++ usr.sbin/bgpd/rde_attr.c    13 Nov 2018 13:51:59 -0000
@@ -995,18 +995,65 @@ aspath_lenmatch(struct aspath *a, enum a
 
 int community_ext_matchone(struct filter_extcommunity *, u_int16_t, u_int64_t);
 
+static int
+community_extract(struct filter_community *fc, struct rde_peer *peer,
+     int field, int large, u_int32_t *value)
+{
+       u_int32_t data;
+       u_int8_t flag;
+       switch (field) {
+       case 1:
+               flag = fc->dflag1;
+               data = fc->data1;
+               break;
+       case 2:
+               flag = fc->dflag2;
+               data = fc->data2;
+               break;
+       case 3:
+               flag = fc->dflag3;
+               data = fc->data3;
+               break;
+       default:
+               fatalx("%s: unknown field %d", __func__, field);
+       }
+
+       switch (flag) {
+       case COMMUNITY_NEIGHBOR_AS:
+               if (peer == NULL)
+                       return -1;
+               *value = peer->conf.remote_as;
+       case COMMUNITY_LOCAL_AS:
+               if (peer == NULL)
+                       return -1;
+               *value = peer->conf.local_as;
+       default:
+               *value = data;
+       }
+       if (!large && *value > USHRT_MAX)
+               return -1;
+       return 0;
+}
+
 int
-community_match(struct rde_aspath *asp, int as, int type)
+community_match(struct rde_aspath *asp, struct filter_community *fc,
+    struct rde_peer *peer)
 {
        struct attr     *a;
        u_int8_t        *p;
-       u_int16_t        eas, etype, len;
+       u_int32_t        as, type, eas, etype;
+       u_int16_t        len;
 
        a = attr_optget(asp, ATTR_COMMUNITIES);
        if (a == NULL)
                /* no communities, no match */
                return (0);
 
+       if (community_extract(fc, peer, 1, 0, &as) == -1 ||
+           community_extract(fc, peer, 2, 0, &type) == -1)
+               /* can't match community */
+               return (0);
+
        p = a->data;
        for (len = a->len / 4; len > 0; len--) {
                eas = *p++;
@@ -1015,21 +1062,29 @@ community_match(struct rde_aspath *asp, 
                etype = *p++;
                etype <<= 8;
                etype |= *p++;
-               if ((as == COMMUNITY_ANY || (u_int16_t)as == eas) &&
-                   (type == COMMUNITY_ANY || (u_int16_t)type == etype))
+               if ((fc->dflag1 == COMMUNITY_ANY || as == eas) &&
+                   (fc->dflag2 == COMMUNITY_ANY || type == etype))
                        return (1);
        }
        return (0);
 }
 
 int
-community_set(struct rde_aspath *asp, int as, int type)
+community_set(struct rde_aspath *asp, struct filter_community *fc,
+    struct rde_peer *peer)
 {
        struct attr     *attr;
        u_int8_t        *p = NULL;
        unsigned int     i, ncommunities = 0;
+       u_int32_t        as, type;
        u_int8_t         f = ATTR_OPTIONAL|ATTR_TRANSITIVE;
 
+       if (fc->dflag1 == COMMUNITY_ANY || fc->dflag2 == COMMUNITY_ANY ||
+           community_extract(fc, peer, 1, 0, &as) == -1 ||
+           community_extract(fc, peer, 2, 0, &type) == -1)
+               /* bad community */
+               return (0);
+
        attr = attr_optget(asp, ATTR_COMMUNITIES);
        if (attr != NULL) {
                p = attr->data;
@@ -1070,12 +1125,13 @@ community_set(struct rde_aspath *asp, in
 }
 
 void
-community_delete(struct rde_aspath *asp, int as, int type)
+community_delete(struct rde_aspath *asp, struct filter_community *fc,
+    struct rde_peer *peer)
 {
        struct attr     *attr;
        u_int8_t        *p, *n;
        u_int16_t        l, len = 0;
-       u_int16_t        eas, etype;
+       u_int32_t        as, type, eas, etype;
        u_int8_t         f;
 
        attr = attr_optget(asp, ATTR_COMMUNITIES);
@@ -1083,6 +1139,11 @@ community_delete(struct rde_aspath *asp,
                /* no attr nothing to do */
                return;
 
+       if (community_extract(fc, peer, 1, 0, &as) == -1 ||
+           community_extract(fc, peer, 2, 0, &type) == -1)
+               /* bad community, nothing to do */
+               return;
+
        p = attr->data;
        for (l = 0; l < attr->len; l += 4) {
                eas = *p++;
@@ -1092,8 +1153,8 @@ community_delete(struct rde_aspath *asp,
                etype <<= 8;
                etype |= *p++;
 
-               if ((as == COMMUNITY_ANY || (u_int16_t)as == eas) &&
-                   (type == COMMUNITY_ANY || (u_int16_t)type == etype))
+               if ((fc->dflag1 == COMMUNITY_ANY || as == eas) &&
+                   (fc->dflag2 == COMMUNITY_ANY || type == etype))
                        /* match */
                        continue;
                len += 4;
@@ -1116,8 +1177,8 @@ community_delete(struct rde_aspath *asp,
                etype <<= 8;
                etype |= *p++;
 
-               if ((as == COMMUNITY_ANY || (u_int16_t)as == eas) &&
-                   (type == COMMUNITY_ANY || (u_int16_t)type == etype))
+               if ((fc->dflag1 == COMMUNITY_ANY || as == eas) &&
+                   (fc->dflag2 == COMMUNITY_ANY || type == etype))
                        /* match */
                        continue;
                n[l++] = eas >> 8;
@@ -1382,46 +1443,66 @@ struct wire_largecommunity {
 };
 
 int
-community_large_match(struct rde_aspath *asp, int64_t as, int64_t ld1,
-    int64_t ld2)
+community_large_match(struct rde_aspath *asp, struct filter_community *fc,
+    struct rde_peer *peer)
 {
-       struct wire_largecommunity      *bar;
+       struct wire_largecommunity      *wlc;
        struct attr     *a;
        u_int8_t        *p;
        u_int16_t        len;
-       u_int32_t        eas, eld1, eld2;
+       u_int32_t        as, ld1, ld2;
 
        a = attr_optget(asp, ATTR_LARGE_COMMUNITIES);
        if (a == NULL)
                /* no communities, no match */
                return (0);
 
+       if (community_extract(fc, peer, 1, 1, &as) == -1 ||
+           community_extract(fc, peer, 2, 1, &ld1) == -1 ||
+           community_extract(fc, peer, 3, 1, &ld2) == -1)
+               /* can't match community */
+               return (0);
+       
+       as = htonl(as);
+       ld1 = htonl(ld1);
+       ld2 = htonl(ld2);
+
        p = a->data;
        for (len = a->len / 12; len > 0; len--) {
-               bar = (struct wire_largecommunity *)p;
+               wlc = (struct wire_largecommunity *)p;
                p += 12;
-               eas = betoh32(bar->as);
-               eld1 = betoh32(bar->ld1);
-               eld2 = betoh32(bar->ld2);
-
-               if ((as == COMMUNITY_ANY || as == eas) &&
-                   (ld1 == COMMUNITY_ANY || ld1 == eld1) &&
-                   (ld2 == COMMUNITY_ANY || ld2 == eld2))
+
+               if ((fc->dflag1 == COMMUNITY_ANY || as == wlc->as) &&
+                   (fc->dflag2 == COMMUNITY_ANY || ld1 == wlc->ld1) &&
+                   (fc->dflag3 == COMMUNITY_ANY || ld2 == wlc->ld2))
                        return (1);
        }
        return (0);
 }
 
 int
-community_large_set(struct rde_aspath *asp, int64_t as, int64_t ld1,
-    int64_t ld2)
+community_large_set(struct rde_aspath *asp, struct filter_community *fc,
+    struct rde_peer *peer)
 {
-       struct wire_largecommunity      *bar;
+       struct wire_largecommunity      *wlc;
        struct attr     *attr;
        u_int8_t        *p = NULL;
        unsigned int     i, ncommunities = 0;
+       u_int32_t        as, ld1, ld2;
        u_int8_t         f = ATTR_OPTIONAL|ATTR_TRANSITIVE;
 
+       if (fc->dflag1 == COMMUNITY_ANY || fc->dflag2 == COMMUNITY_ANY ||
+           fc->dflag3 == COMMUNITY_ANY ||
+           community_extract(fc, peer, 1, 1, &as) == -1 ||
+           community_extract(fc, peer, 2, 1, &ld1) == -1 ||
+           community_extract(fc, peer, 3, 1, &ld2) == -1)
+               /* can't match community */
+               return (0);
+
+       as = htonl(as);
+       ld1 = htonl(ld1);
+       ld2 = htonl(ld2);
+
        attr = attr_optget(asp, ATTR_LARGE_COMMUNITIES);
        if (attr != NULL) {
                p = attr->data;
@@ -1430,9 +1511,8 @@ community_large_set(struct rde_aspath *a
 
        /* first check if the community is not already set */
        for (i = 0; i < ncommunities; i++) {
-               bar = (struct wire_largecommunity *)p;
-               if (bar->as == htobe32(as) && bar->ld1 == htobe32(ld1) &&
-                   bar->ld2 == htobe32(ld2))
+               wlc = (struct wire_largecommunity *)p;
+               if (wlc->as == as && wlc->ld1 == ld1 && wlc->ld2 == ld2)
                        /* already present, nothing todo */
                        return (1);
                p += 12;
@@ -1445,10 +1525,10 @@ community_large_set(struct rde_aspath *a
        if ((p = reallocarray(NULL, ncommunities, 12)) == NULL)
                fatal("community_set");
 
-       bar = (struct wire_largecommunity *)p;
-       bar->as = htobe32(as);
-       bar->ld1 = htobe32(ld1);
-       bar->ld2 = htobe32(ld2);
+       wlc = (struct wire_largecommunity *)p;
+       wlc->as = as;
+       wlc->ld1 = ld1;
+       wlc->ld2 = ld2;
 
        if (attr != NULL) {
                memcpy(p + 12, attr->data, attr->len);
@@ -1463,14 +1543,14 @@ community_large_set(struct rde_aspath *a
 }
 
 void
-community_large_delete(struct rde_aspath *asp, int64_t as, int64_t ld1,
-    int64_t ld2)
+community_large_delete(struct rde_aspath *asp, struct filter_community *fc,
+    struct rde_peer *peer)
 {
-       struct wire_largecommunity      *bar;
+       struct wire_largecommunity      *wlc;
        struct attr     *attr;
        u_int8_t        *p, *n;
        u_int16_t        l = 0, len = 0;
-       u_int32_t        eas, eld1, eld2;
+       u_int32_t        as, ld1, ld2;
        u_int8_t         f;
 
        attr = attr_optget(asp, ATTR_LARGE_COMMUNITIES);
@@ -1478,17 +1558,24 @@ community_large_delete(struct rde_aspath
                /* no attr nothing to do */
                return;
 
+       if (community_extract(fc, peer, 1, 1, &as) == -1 ||
+           community_extract(fc, peer, 2, 1, &ld1) == -1 ||
+           community_extract(fc, peer, 3, 1, &ld2) == -1)
+               /* can't match community */
+               return;
+
+       as = htonl(as);
+       ld1 = htonl(ld1);
+       ld2 = htonl(ld2);
+
        p = attr->data;
        for (len = 0; l < attr->len; l += 12) {
-               bar = (struct wire_largecommunity *)p;
+               wlc = (struct wire_largecommunity *)p;
                p += 12;
-               eas = betoh32(bar->as);
-               eld1 = betoh32(bar->ld1);
-               eld2 = betoh32(bar->ld2);
-
-               if ((as == COMMUNITY_ANY || as == eas) &&
-                   (ld1 == COMMUNITY_ANY || ld1 == eld1) &&
-                   (ld2 == COMMUNITY_ANY || ld2 == eld2))
+
+               if ((fc->dflag1 == COMMUNITY_ANY || as == wlc->as) &&
+                   (fc->dflag2 == COMMUNITY_ANY || ld1 == wlc->ld1) &&
+                   (fc->dflag3 == COMMUNITY_ANY || ld2 == wlc->ld2))
                        /* match */
                        continue;
                len += 12;
@@ -1504,18 +1591,15 @@ community_large_delete(struct rde_aspath
 
        p = attr->data;
        for (l = 0; l < len && p < attr->data + attr->len; ) {
-               bar = (struct wire_largecommunity *)p;
+               wlc = (struct wire_largecommunity *)p;
                p += 12;
-               eas = betoh32(bar->as);
-               eld1 = betoh32(bar->ld1);
-               eld2 = betoh32(bar->ld2);
-
-               if ((as == COMMUNITY_ANY || as == eas) &&
-                   (ld1 == COMMUNITY_ANY || ld1 == eld1) &&
-                   (ld2 == COMMUNITY_ANY || ld2 == eld2))
+
+               if ((fc->dflag1 == COMMUNITY_ANY || as == wlc->as) &&
+                   (fc->dflag2 == COMMUNITY_ANY || ld1 == wlc->ld1) &&
+                   (fc->dflag3 == COMMUNITY_ANY || ld2 == wlc->ld2))
                        /* match */
                        continue;
-               memcpy(n + l, bar, sizeof(*bar));
+               memcpy(n + l, wlc, sizeof(*wlc));
                l += 12;
        }
 
@@ -1525,7 +1609,6 @@ community_large_delete(struct rde_aspath
        attr_optadd(asp, f, ATTR_LARGE_COMMUNITIES, n, len);
        free(n);
 }
-
 
 u_char *
 community_ext_delete_non_trans(u_char *data, u_int16_t len, u_int16_t *newlen)
Index: usr.sbin/bgpd/rde_filter.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_filter.c,v
retrieving revision 1.112
diff -u -p -r1.112 rde_filter.c
--- usr.sbin/bgpd/rde_filter.c  29 Sep 2018 08:11:11 -0000      1.112
+++ usr.sbin/bgpd/rde_filter.c  12 Nov 2018 13:38:30 -0000
@@ -40,8 +40,6 @@ rde_apply_set(struct filter_set_head *sh
 {
        struct filter_set       *set;
        u_char                  *np;
-       int                      as, type;
-       int64_t                  las, ld1, ld2;
        u_int32_t                prep_as;
        u_int16_t                nl;
        u_int8_t                 prepend;
@@ -142,172 +140,28 @@ rde_apply_set(struct filter_set_head *sh
                            &state->nexthop, &state->nhflags);
                        break;
                case ACTION_SET_COMMUNITY:
-                       switch (set->action.community.as) {
-                       case COMMUNITY_ERROR:
-                       case COMMUNITY_ANY:
-                               fatalx("%s: bad community string", __func__);
-                       case COMMUNITY_NEIGHBOR_AS:
-                               as = peer->conf.remote_as;
-                               break;
-                       case COMMUNITY_LOCAL_AS:
-                               as = peer->conf.local_as;
-                               break;
-                       default:
-                               as = set->action.community.as;
-                               break;
-                       }
-
                        switch (set->action.community.type) {
-                       case COMMUNITY_ERROR:
-                       case COMMUNITY_ANY:
-                               fatalx("%s: bad community string", __func__);
-                       case COMMUNITY_NEIGHBOR_AS:
-                               type = peer->conf.remote_as;
-                               break;
-                       case COMMUNITY_LOCAL_AS:
-                               type = peer->conf.local_as;
-                               break;
-                       default:
-                               type = set->action.community.type;
+                       case COMMUNITY_TYPE_BASIC:
+                               community_set(&state->aspath,
+                                   &set->action.community, peer);
+                               break;
+                       case COMMUNITY_TYPE_LARGE:
+                               community_large_set(&state->aspath,
+                                   &set->action.community, peer);
                                break;
                        }
-
-                       community_set(&state->aspath, as, type);
                        break;
                case ACTION_DEL_COMMUNITY:
-                       switch (set->action.community.as) {
-                       case COMMUNITY_ERROR:
-                               fatalx("%s: bad community string", __func__);
-                       case COMMUNITY_NEIGHBOR_AS:
-                               as = peer->conf.remote_as;
-                               break;
-                       case COMMUNITY_LOCAL_AS:
-                               as = peer->conf.local_as;
-                               break;
-                       case COMMUNITY_ANY:
-                       default:
-                               as = set->action.community.as;
-                               break;
-                       }
-
                        switch (set->action.community.type) {
-                       case COMMUNITY_ERROR:
-                               fatalx("%s: bad community string", __func__);
-                       case COMMUNITY_NEIGHBOR_AS:
-                               type = peer->conf.remote_as;
-                               break;
-                       case COMMUNITY_LOCAL_AS:
-                               type = peer->conf.local_as;
-                               break;
-                       case COMMUNITY_ANY:
-                       default:
-                               type = set->action.community.type;
+                       case COMMUNITY_TYPE_BASIC:
+                               community_delete(&state->aspath,
+                                   &set->action.community, peer);
+                               break;
+                       case COMMUNITY_TYPE_LARGE:
+                               community_large_delete(&state->aspath,
+                                   &set->action.community, peer);
                                break;
                        }
-
-                       community_delete(&state->aspath, as, type);
-                       break;
-               case ACTION_SET_LARGE_COMMUNITY:
-                       switch (set->action.large_community.as) {
-                       case COMMUNITY_ERROR:
-                               fatalx("%s: bad large community string",
-                                   __func__);
-                       case COMMUNITY_NEIGHBOR_AS:
-                               las = peer->conf.remote_as;
-                               break;
-                       case COMMUNITY_LOCAL_AS:
-                               las = peer->conf.local_as;
-                               break;
-                       case COMMUNITY_ANY:
-                       default:
-                               las = set->action.large_community.as;
-                               break;
-                       }
-
-                       switch (set->action.large_community.ld1) {
-                       case COMMUNITY_ERROR:
-                               fatalx("%s: bad large community string",
-                                   __func__);
-                       case COMMUNITY_NEIGHBOR_AS:
-                               ld1 = peer->conf.remote_as;
-                               break;
-                       case COMMUNITY_LOCAL_AS:
-                               ld1 = peer->conf.local_as;
-                               break;
-                       case COMMUNITY_ANY:
-                       default:
-                               ld1 = set->action.large_community.ld1;
-                               break;
-                       }
-
-                       switch (set->action.large_community.ld2) {
-                       case COMMUNITY_ERROR:
-                               fatalx("%s: bad large community string",
-                                   __func__);
-                       case COMMUNITY_NEIGHBOR_AS:
-                               ld2 = peer->conf.remote_as;
-                               break;
-                       case COMMUNITY_LOCAL_AS:
-                               ld2 = peer->conf.local_as;
-                               break;
-                       case COMMUNITY_ANY:
-                       default:
-                               ld2 = set->action.large_community.ld2;
-                               break;
-                       }
-
-                       community_large_set(&state->aspath, las, ld1, ld2);
-                       break;
-               case ACTION_DEL_LARGE_COMMUNITY:
-                       switch (set->action.large_community.as) {
-                       case COMMUNITY_ERROR:
-                               fatalx("%s: bad large community string",
-                                   __func__);
-                       case COMMUNITY_NEIGHBOR_AS:
-                               las = peer->conf.remote_as;
-                               break;
-                       case COMMUNITY_LOCAL_AS:
-                               las = peer->conf.local_as;
-                               break;
-                       case COMMUNITY_ANY:
-                       default:
-                               las = set->action.large_community.as;
-                               break;
-                       }
-
-                       switch (set->action.large_community.ld1) {
-                       case COMMUNITY_ERROR:
-                               fatalx("%s: bad large community string",
-                                   __func__);
-                       case COMMUNITY_NEIGHBOR_AS:
-                               ld1 = peer->conf.remote_as;
-                               break;
-                       case COMMUNITY_LOCAL_AS:
-                               ld1 = peer->conf.local_as;
-                               break;
-                       case COMMUNITY_ANY:
-                       default:
-                               ld1 = set->action.large_community.ld1;
-                               break;
-                       }
-
-                       switch (set->action.large_community.ld2) {
-                       case COMMUNITY_ERROR:
-                               fatalx("%s: bad large community string",
-                                   __func__);
-                       case COMMUNITY_NEIGHBOR_AS:
-                               ld2 = peer->conf.remote_as;
-                               break;
-                       case COMMUNITY_LOCAL_AS:
-                               ld2 = peer->conf.local_as;
-                               break;
-                       case COMMUNITY_ANY:
-                       default:
-                               ld2 = set->action.large_community.ld2;
-                               break;
-                       }
-
-                       community_large_delete(&state->aspath, las, ld1, ld2);
                        break;
                case ACTION_PFTABLE:
                        /* convert pftable name to an id */
@@ -348,9 +202,8 @@ int
 rde_filter_match(struct filter_rule *f, struct rde_peer *peer,
     struct filterstate *state, struct prefix *p)
 {
-       int             cas, type;
-       int64_t         las, ld1, ld2;
-       struct rde_aspath       *asp = NULL;
+       struct rde_aspath *asp = NULL;
+       int i;
 
        if (state != NULL)
                asp = &state->aspath;
@@ -376,89 +229,28 @@ rde_filter_match(struct filter_rule *f, 
                    f->match.aslen.aslen) == 0)
                        return (0);
 
-       if (asp != NULL && f->match.community.as != COMMUNITY_UNSET) {
-               switch (f->match.community.as) {
-               case COMMUNITY_ERROR:
-                       fatalx("rde_filter_match bad community string");
-               case COMMUNITY_NEIGHBOR_AS:
-                       cas = peer->conf.remote_as;
-                       break;
-               case COMMUNITY_LOCAL_AS:
-                       cas = peer->conf.local_as;
-                       break;
-               default:
-                       cas = f->match.community.as;
-                       break;
-               }
-
-               switch (f->match.community.type) {
-               case COMMUNITY_ERROR:
-                       fatalx("rde_filter_match bad community string");
-               case COMMUNITY_NEIGHBOR_AS:
-                       type = peer->conf.remote_as;
-                       break;
-               case COMMUNITY_LOCAL_AS:
-                       type = peer->conf.local_as;
+       for (i = 0; asp != NULL && i < MAX_COMM_MATCH; i++) {
+               switch (f->match.community[i].type) {
+               case COMMUNITY_TYPE_NONE:
+                       i = MAX_COMM_MATCH;
+                       break;
+               case COMMUNITY_TYPE_BASIC:
+                       if (community_match(asp, &f->match.community[i],
+                           peer) == 0)
+                               return (0);
                        break;
-               default:
-                       type = f->match.community.type;
+               case COMMUNITY_TYPE_LARGE:
+                       if (community_large_match(asp, &f->match.community[i],
+                           peer) == 0)
+                               return (0);
                        break;
                }
-
-               if (community_match(asp, cas, type) == 0)
-                       return (0);
        }
        if (asp != NULL &&
            (f->match.ext_community.flags & EXT_COMMUNITY_FLAG_VALID))
                if (community_ext_match(asp, &f->match.ext_community,
                    peer->conf.remote_as) == 0)
                        return (0);
-       if (asp != NULL && f->match.large_community.as != COMMUNITY_UNSET) {
-               switch (f->match.large_community.as) {
-               case COMMUNITY_ERROR:
-                       fatalx("rde_filter_match bad community string");
-               case COMMUNITY_NEIGHBOR_AS:
-                       las = peer->conf.remote_as;
-                       break;
-               case COMMUNITY_LOCAL_AS:
-                       las = peer->conf.local_as;
-                       break;
-               default:
-                       las = f->match.large_community.as;
-                       break;
-               }
-
-               switch (f->match.large_community.ld1) {
-               case COMMUNITY_ERROR:
-                       fatalx("rde_filter_match bad community string");
-               case COMMUNITY_NEIGHBOR_AS:
-                       ld1 = peer->conf.remote_as;
-                       break;
-               case COMMUNITY_LOCAL_AS:
-                       ld1 = peer->conf.local_as;
-                       break;
-               default:
-                       ld1 = f->match.large_community.ld1;
-                       break;
-               }
-
-               switch (f->match.large_community.ld2) {
-               case COMMUNITY_ERROR:
-                       fatalx("rde_filter_match bad community string");
-               case COMMUNITY_NEIGHBOR_AS:
-                       ld2 = peer->conf.remote_as;
-                       break;
-               case COMMUNITY_LOCAL_AS:
-                       ld2 = peer->conf.local_as;
-                       break;
-               default:
-                       ld2 = f->match.large_community.ld2;
-                       break;
-               }
-
-               if (community_large_match(asp, las, ld1, ld2) == 0)
-                       return (0);
-       }
 
        if (state != NULL && f->match.nexthop.flags != 0) {
                struct bgpd_addr *nexthop, *cmpaddr;
@@ -744,11 +536,8 @@ filterset_cmp(struct filter_set *a, stru
 
        if (a->type == ACTION_SET_COMMUNITY ||
            a->type == ACTION_DEL_COMMUNITY) {  /* a->type == b->type */
-               /* compare community */
-               if (a->action.community.as - b->action.community.as != 0)
-                       return (a->action.community.as -
-                           b->action.community.as);
-               return (a->action.community.type - b->action.community.type);
+               return (memcmp(&a->action.community, &b->action.community,
+                   sizeof(a->action.community)));
        }
 
        if (a->type == ACTION_SET_EXT_COMMUNITY ||
@@ -757,21 +546,6 @@ filterset_cmp(struct filter_set *a, stru
                    &b->action.ext_community, sizeof(a->action.ext_community)));
        }
 
-       if (a->type == ACTION_SET_LARGE_COMMUNITY ||
-           a->type == ACTION_DEL_LARGE_COMMUNITY) {    /* a->type == b->type */
-               /* compare community */
-               if (a->action.large_community.as -
-                   b->action.large_community.as != 0)
-                       return (a->action.large_community.as -
-                           b->action.large_community.as);
-               if (a->action.large_community.ld1 -
-                   b->action.large_community.ld1 != 0)
-                       return (a->action.large_community.ld1 -
-                           b->action.large_community.ld1);
-               return (a->action.large_community.ld2 -
-                   b->action.large_community.ld2);
-       }
-
        if (a->type == ACTION_SET_NEXTHOP && b->type == ACTION_SET_NEXTHOP) {
                /*
                 * This is the only interesting case, all others are considered
@@ -845,14 +619,6 @@ filterset_equal(struct filter_set_head *
                            sizeof(a->action.community)) == 0)
                                continue;
                        break;
-               case ACTION_DEL_LARGE_COMMUNITY:
-               case ACTION_SET_LARGE_COMMUNITY:
-                       if (a->type == b->type &&
-                           memcmp(&a->action.large_community,
-                           &b->action.large_community,
-                           sizeof(a->action.large_community)) == 0)
-                               continue;
-                       break;
                case ACTION_PFTABLE:
                case ACTION_PFTABLE_ID:
                        if (b->type == ACTION_PFTABLE)
@@ -936,10 +702,6 @@ filterset_name(enum action_types type)
                return ("community");
        case ACTION_DEL_COMMUNITY:
                return ("community delete");
-       case ACTION_SET_LARGE_COMMUNITY:
-               return ("large-community");
-       case ACTION_DEL_LARGE_COMMUNITY:
-               return ("large-community delete");
        case ACTION_PFTABLE:
        case ACTION_PFTABLE_ID:
                return ("pftable");
Index: usr.sbin/bgpd/rde_update.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_update.c,v
retrieving revision 1.103
diff -u -p -r1.103 rde_update.c
--- usr.sbin/bgpd/rde_update.c  4 Nov 2018 12:34:54 -0000       1.103
+++ usr.sbin/bgpd/rde_update.c  7 Nov 2018 17:45:29 -0000
@@ -66,6 +66,22 @@ RB_GENERATE(uptree_attr, update_attr, en
 
 SIPHASH_KEY uptree_key;
 
+static struct filter_community comm_no_advertise = {
+       .type = COMMUNITY_TYPE_BASIC,
+       .data1 = COMMUNITY_WELLKNOWN,
+       .data2 = COMMUNITY_NO_ADVERTISE
+};
+static struct filter_community comm_no_export = {
+       .type = COMMUNITY_TYPE_BASIC,
+       .data1 = COMMUNITY_WELLKNOWN,
+       .data2 = COMMUNITY_NO_EXPORT
+};
+static struct filter_community comm_no_expsubconfed = {
+       .type = COMMUNITY_TYPE_BASIC,
+       .data1 = COMMUNITY_WELLKNOWN,
+       .data2 = COMMUNITY_NO_EXPSUBCONFED
+};
+
 void
 up_init(struct rde_peer *peer)
 {
@@ -329,14 +345,14 @@ up_test_update(struct rde_peer *peer, st
        }
 
        /* well known communities */
-       if (community_match(asp, COMMUNITY_WELLKNOWN, COMMUNITY_NO_ADVERTISE))
-               return (0);
-       if (peer->conf.ebgp && community_match(asp, COMMUNITY_WELLKNOWN,
-           COMMUNITY_NO_EXPORT))
-               return (0);
-       if (peer->conf.ebgp && community_match(asp, COMMUNITY_WELLKNOWN,
-           COMMUNITY_NO_EXPSUBCONFED))
+       if (community_match(asp, &comm_no_advertise, NULL))
                return (0);
+       if (peer->conf.ebgp) {
+               if (community_match(asp, &comm_no_export, NULL))
+                       return (0);
+               if (community_match(asp, &comm_no_expsubconfed, NULL))
+                       return (0);
+       }
 
        /*
         * Don't send messages back to originator

Reply via email to