Peter Hessler(phess...@openbsd.org) on 2016.10.13 17:34:28 +0200:
> On 2016 Oct 11 (Tue) at 00:00:53 +0200 (+0200), Peter Hessler wrote:
> :Here is an initial implementation of draft-ietf-idr-large-community for
> :OpenBGPD.  I can connect and exchange routes with these attributes
> :against exabgp.
> :
> :Normal communities are two 16bit numbers.  With the addition of
> :32bit ASNs, those will not work if you wish to control one of
> :them.
> :
> :Large Communities are 32bit:32bit:32bit.  It seems the convention will be
> :<control ASN>:<verb>:<noun>, with <verb> and <noun> being locally
> :defined.
> :
> :RFC status: currently accepted by the IDR-WG, is at version -02, the
> :wire format is set, the attribute codepoint is assigned by IANA, and it
> :seems that only trivial details need to be addressed.  Very likely to be
> :accepted.
> :
> :This was based on a partial implementation from Job Snijders, many
> :thanks!
> :
> :Comments?  OK?
> :
> 
> Updated diff:
>  - assert copyright for the non-trivial changes
>  - since the magic ASN matching canaries use valid bits, seperate the
> filter storage and a wire storage
>  - clean up warnings
>  - fix a few printing issues
> 
> OK?

nice, just a few questions below 

> Index: usr.sbin/bgpctl/bgpctl.8
> ===================================================================
> RCS file: /cvs/openbsd/src/usr.sbin/bgpctl/bgpctl.8,v
> retrieving revision 1.69
> diff -u -p -u -p -r1.69 bgpctl.8
> --- usr.sbin/bgpctl/bgpctl.8  25 May 2016 14:15:59 -0000      1.69
> +++ usr.sbin/bgpctl/bgpctl.8  5 Sep 2016 13:41:29 -0000
> @@ -300,6 +300,9 @@ anywhere in the AS path.
>  .It Cm community Ar community
>  Show all entries with community
>  .Ar community .
> +.It Cm large-community Ar large-community
> +Show all entries with large-community
> +.Ar large-community .
>  .It Cm empty-as
>  Show all entries that are internal routes with no AS's in the AS path.
>  .It Cm memory
> Index: usr.sbin/bgpctl/bgpctl.c
> ===================================================================
> RCS file: /cvs/openbsd/src/usr.sbin/bgpctl/bgpctl.c,v
> retrieving revision 1.188
> diff -u -p -u -p -r1.188 bgpctl.c
> --- usr.sbin/bgpctl/bgpctl.c  3 Jun 2016 17:36:37 -0000       1.188
> +++ usr.sbin/bgpctl/bgpctl.c  13 Oct 2016 15:32:30 -0000
> @@ -2,6 +2,8 @@
>  
>  /*
>   * Copyright (c) 2003 Henning Brauer <henn...@openbsd.org>
> + * Copyright (c) 2016 Job Snijders <j...@instituut.net>
> + * Copyright (c) 2016 Peter Hessler <phess...@openbsd.org>
>   *
>   * Permission to use, copy, modify, and distribute this software for any
>   * purpose with or without fee is hereby granted, provided that the above
> @@ -82,6 +84,7 @@ void                 show_rib_brief(struct ctl_show_ri
>  void          show_rib_detail(struct ctl_show_rib *, u_char *, int);
>  void          show_attr(void *, u_int16_t);
>  void          show_community(u_char *, u_int16_t);
> +void          show_large_community(u_char *, u_int16_t);
>  void          show_ext_community(u_char *, u_int16_t);
>  char         *fmt_mem(int64_t);
>  int           show_rib_memory_msg(struct imsg *);
> @@ -254,6 +257,13 @@ main(int argc, char *argv[])
>                           sizeof(res->community));
>                       type = IMSG_CTL_SHOW_RIB_COMMUNITY;
>               }
> +             if (res->large_community.as != COMMUNITY_UNSET &&
> +                 res->large_community.ld1 != COMMUNITY_UNSET &&
> +                 res->large_community.ld2 != COMMUNITY_UNSET) {
> +                     memcpy(&ribreq.large_community, &res->large_community,
> +                         sizeof(res->large_community));
> +                     type = IMSG_CTL_SHOW_RIB_LARGECOMMUNITY;
> +             }
>               memcpy(&ribreq.neighbor, &neighbor, sizeof(ribreq.neighbor));
>               strlcpy(ribreq.rib, res->rib, sizeof(ribreq.rib));
>               ribreq.aid = res->aid;
> @@ -275,6 +285,11 @@ main(int argc, char *argv[])
>                   res->community.type != COMMUNITY_UNSET)
>                       memcpy(&ribreq.community, &res->community,
>                           sizeof(res->community));
> +             if (res->large_community.as != COMMUNITY_UNSET &&
> +                 res->large_community.ld1 != COMMUNITY_UNSET &&
> +                 res->large_community.ld2 != COMMUNITY_UNSET)
> +                     memcpy(&ribreq.large_community, &res->large_community,
> +                         sizeof(res->large_community));
>               memcpy(&ribreq.neighbor, &neighbor, sizeof(ribreq.neighbor));
>               ribreq.aid = res->aid;
>               ribreq.flags = res->flags;
> @@ -377,6 +392,11 @@ main(int argc, char *argv[])
>                   res->community.type != COMMUNITY_UNSET)
>                       memcpy(&ribreq.community, &res->community,
>                           sizeof(res->community));
> +             if (res->large_community.as != COMMUNITY_UNSET &&
> +                 res->large_community.ld1 != COMMUNITY_UNSET &&
> +                 res->large_community.ld2 != COMMUNITY_UNSET)
> +                     memcpy(&ribreq.large_community, &res->large_community,
> +                         sizeof(res->large_community));
>               memcpy(&ribreq.neighbor, &neighbor, sizeof(ribreq.neighbor));
>               ribreq.aid = res->aid;
>               ribreq.flags = res->flags;
> @@ -1424,6 +1444,11 @@ show_attr(void *b, u_int16_t len)
>               show_community(data, alen);
>               printf("\n");
>               break;
> +     case ATTR_LARGE_COMMUNITIES:
> +             printf("    Large Communities: ");
> +             show_large_community(data, alen);
> +             printf("\n");
> +             break;
>       case ATTR_AGGREGATOR:
>               memcpy(&as, data, sizeof(as));
>               memcpy(&id, data + sizeof(as), sizeof(id));
> @@ -1493,6 +1518,29 @@ show_community(u_char *data, u_int16_t l
>                       printf("%hu:%hu", a, v);
>  
>               if (i + 4 < len)
> +                     printf(" ");
> +     }
> +}
> +
> +void
> +show_large_community(u_char *data, u_int16_t len)
> +{
> +     u_int32_t       a, l1, l2;
> +     u_int16_t       i;
> +
> +     if (len % 12)
> +             return;
> +
> +     for (i = 0; i < len; i += 12) {
> +             memcpy(&a, data + i, sizeof(a));
> +             memcpy(&l1, data + i + 4, sizeof(l1));
> +             memcpy(&l2, data + i + 8, sizeof(l2));
> +             a = ntohl(a);
> +             l1 = ntohl(l1);
> +             l2 = ntohl(l2);
> +             printf("%u:%u:%u", a, l1, l2);
> +
> +             if (i + 12 < len)
>                       printf(" ");
>       }
>  }
> Index: usr.sbin/bgpctl/parser.c
> ===================================================================
> RCS file: /cvs/openbsd/src/usr.sbin/bgpctl/parser.c,v
> retrieving revision 1.73
> diff -u -p -u -p -r1.73 parser.c
> --- usr.sbin/bgpctl/parser.c  11 Oct 2015 19:53:57 -0000      1.73
> +++ usr.sbin/bgpctl/parser.c  13 Oct 2016 15:32:35 -0000
> @@ -2,6 +2,8 @@
>  
>  /*
>   * Copyright (c) 2003, 2004 Henning Brauer <henn...@openbsd.org>
> + * Copyright (c) 2016 Job Snijders <j...@instituut.net>
> + * Copyright (c) 2016 Peter Hessler <phess...@openbsd.org>
>   *
>   * Permission to use, copy, modify, and distribute this software for any
>   * purpose with or without fee is hereby granted, provided that the above
> @@ -44,6 +46,7 @@ enum token_type {
>       PEERDESC,
>       RIBNAME,
>       COMMUNITY,
> +     LARGE_COMMUNITY,
>       LOCALPREF,
>       MED,
>       NEXTHOP,
> @@ -90,11 +93,13 @@ static const struct token t_show_mrt_as[
>  static const struct token t_show_prefix[];
>  static const struct token t_show_ip[];
>  static const struct token t_show_community[];
> +static const struct token t_show_largecommunity[];
>  static const struct token t_network[];
>  static const struct token t_network_show[];
>  static const struct token t_prefix[];
>  static const struct token t_set[];
>  static const struct token t_community[];
> +static const struct token t_largecommunity[];
>  static const struct token t_localpref[];
>  static const struct token t_med[];
>  static const struct token t_nexthop[];
> @@ -160,6 +165,7 @@ static const struct token t_show_rib[] =
>       { ASTYPE,       "peer-as",      AS_PEER,        t_show_rib_as},
>       { ASTYPE,       "empty-as",     AS_EMPTY,       t_show_rib},
>       { KEYWORD,      "community",    NONE,           t_show_community},
> +     { KEYWORD,      "large-community", NONE,        t_show_largecommunity},
>       { FLAG,         "best",         F_CTL_ACTIVE,   t_show_rib},
>       { FLAG,         "selected",     F_CTL_ACTIVE,   t_show_rib},
>       { FLAG,         "detail",       F_CTL_DETAIL,   t_show_rib},
> @@ -275,6 +281,11 @@ static const struct token t_show_communi
>       { ENDTOKEN,     "",             NONE,           NULL}
>  };
>  
> +static const struct token t_show_largecommunity[] = {
> +     { LARGE_COMMUNITY,      "",     NONE,           t_show_rib},
> +     { ENDTOKEN,     "",             NONE,           NULL}
> +};
> +
>  static const struct token t_network[] = {
>       { KEYWORD,      "add",          NETWORK_ADD,    t_prefix},
>       { KEYWORD,      "delete",       NETWORK_REMOVE, t_prefix},
> @@ -299,6 +310,7 @@ static const struct token t_network_show
>  static const struct token t_set[] = {
>       { NOTOKEN,      "",                     NONE,   NULL},
>       { KEYWORD,      "community",            NONE,   t_community},
> +     { KEYWORD,      "large-community",      NONE,   t_largecommunity},
>       { KEYWORD,      "localpref",            NONE,   t_localpref},
>       { KEYWORD,      "med",                  NONE,   t_med},
>       { KEYWORD,      "metric",               NONE,   t_med},
> @@ -317,6 +329,11 @@ static const struct token t_community[] 
>       { ENDTOKEN,     "",                     NONE,   NULL}
>  };
>  
> +static const struct token t_largecommunity[] = {
> +     { LARGE_COMMUNITY,      "",             NONE,   t_set},
> +     { ENDTOKEN,     "",                     NONE,   NULL}
> +};
> +
>  static const struct token t_localpref[] = {
>       { LOCALPREF,    "",                     NONE,   t_set},
>       { ENDTOKEN,     "",                     NONE,   NULL}
> @@ -391,6 +408,8 @@ int                        parse_number(const char *, 
> struct
>                            enum token_type);
>  int                   getcommunity(const char *);
>  int                   parse_community(const char *, struct parse_result *);
> +int                   getlargecommunity(const char *);
> +int                   parse_largecommunity(const char *, struct parse_result 
> *);
>  int                   parse_nexthop(const char *, struct parse_result *);
>  int                   bgpctl_getopt(int *, char **[], int);
>  
> @@ -403,6 +422,9 @@ parse(int argc, char *argv[])
>       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;
>       TAILQ_INIT(&res.set);
>       if ((res.irr_outdir = getcwd(NULL, 0)) == NULL) {
>               fprintf(stderr, "getcwd failed: %s\n", strerror(errno));
> @@ -556,6 +578,13 @@ match_token(int *argc, char **argv[], co
>                               t = &table[i];
>                       }
>                       break;
> +             case LARGE_COMMUNITY:
> +                     if (word != NULL && wordlen > 0 &&
> +                         parse_largecommunity(word, &res)) {
> +                             match++;
> +                             t = &table[i];
> +                     }
> +                     break;
>               case LOCALPREF:
>               case MED:
>               case PREPNBR:
> @@ -668,6 +697,9 @@ show_valid_args(const struct token table
>               case COMMUNITY:
>                       fprintf(stderr, "  <community>\n");
>                       break;
> +             case LARGE_COMMUNITY:
> +                     fprintf(stderr, "  <large-community>\n");
> +                     break;
>               case LOCALPREF:
>               case MED:
>               case PREPNBR:
> @@ -956,6 +988,57 @@ done:
>  
>       r->community.as = as;
>       r->community.type = type;
> +
> +     TAILQ_INSERT_TAIL(&r->set, fs, entry);
> +     return (1);
> +}
> +
> +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)
> +{
> +     struct filter_set *fs;
> +     char            *p = strdup(word);
> +     char            *array[3];
> +     int64_t          as, ld1, ld2;
> +     int              i = 0;
> +
> +     while (p != NULL) {
> +             array[i++] = p;
> +             p = strchr(p, ':');
> +             if (p)
> +                     *p++ = 0;
> +     }
> +
> +     as   = getlargecommunity(array[0]);
> +     ld1  = getlargecommunity(array[1]);
> +     ld2  = getlargecommunity(array[2]);
> +
> +     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;
>  
>       TAILQ_INSERT_TAIL(&r->set, fs, entry);
>       return (1);
> Index: usr.sbin/bgpctl/parser.h
> ===================================================================
> RCS file: /cvs/openbsd/src/usr.sbin/bgpctl/parser.h,v
> retrieving revision 1.27
> diff -u -p -u -p -r1.27 parser.h
> --- usr.sbin/bgpctl/parser.h  17 Apr 2015 07:51:09 -0000      1.27
> +++ usr.sbin/bgpctl/parser.h  5 Sep 2016 13:41:29 -0000
> @@ -63,6 +63,7 @@ struct parse_result {
>       struct filter_as         as;
>       struct filter_set_head   set;
>       struct filter_community  community;
> +     struct filter_largecommunity  large_community;
>       char                     peerdesc[PEER_DESCR_LEN];
>       char                     rib[PEER_DESCR_LEN];
>       char                    *irr_outdir;
> Index: usr.sbin/bgpd/bgpd.8
> ===================================================================
> RCS file: /cvs/openbsd/src/usr.sbin/bgpd/bgpd.8,v
> retrieving revision 1.48
> diff -u -p -u -p -r1.48 bgpd.8
> --- usr.sbin/bgpd/bgpd.8      14 Aug 2013 06:32:36 -0000      1.48
> +++ usr.sbin/bgpd/bgpd.8      2 Oct 2016 13:39:54 -0000
> @@ -238,6 +238,17 @@ control socket
>  .Re
>  .Pp
>  .Rs
> +.%A J. Snijders
> +.%A J. Heitz
> +.%A K. Patel
> +.%A I. Bagdonas
> +.%A A. Simpson
> +.%D September 2016
> +.%R draft-ietf-idr-large-community
> +.%T Large BGP Communities Attribute
> +.Re
> +.Pp
> +.Rs
>  .%A A. Heffernan
>  .%D August 1998
>  .%R RFC 2385
> Index: usr.sbin/bgpd/bgpd.conf.5
> ===================================================================
> RCS file: /cvs/openbsd/src/usr.sbin/bgpd/bgpd.conf.5,v
> retrieving revision 1.147
> diff -u -p -u -p -r1.147 bgpd.conf.5
> --- usr.sbin/bgpd/bgpd.conf.5 5 Oct 2016 07:38:06 -0000       1.147
> +++ usr.sbin/bgpd/bgpd.conf.5 10 Oct 2016 20:05:40 -0000
> @@ -1143,6 +1143,39 @@ may be set to
>  which is expanded to the current neighbor remote AS number.
>  .Pp
>  .It Xo
> +.Ic large-community
> +.Ar as-number : Ns Ar local : Ns Ar local
> +.Xc
> +.It Ic large-community Ar name

no names yet, so dont document that

> +This rule applies only to
> +.Em UPDATES
> +where the
> +.Ic Large community
> +path attribute is present and matches.
> +Communities are specified as
> +.Ar as-number : Ns Ar local : Ns Ar local ,
> +where
> +.Ar as-number
> +is an AS number and
> +.Ar local
> +is a locally significant number between zero and
> +.Li 4294967295.
> +Both
> +.Ar as-number
> +and
> +.Ar local
> +may be set to
> +.Sq *
> +to do wildcard matching.
> +Both
> +.Ar as-number
> +and
> +.Ar local
> +may be set to
> +.Ic neighbor-as ,
> +which is expanded to the current neighbor remote AS number.
> +.Pp
> +.It Xo
>  .Ic ext-community
>  .Ar subtype Ar as-number : Ns Ar local
>  .Xc
> @@ -1364,6 +1397,35 @@ Alternately, well-known communities may 
>  .Ic NO_EXPORT_SUBCONFED ,
>  or
>  .Ic NO_PEER .
> +For
> +.Cm delete ,
> +both
> +.Ar as-number
> +and
> +.Ar local
> +may be set to
> +.Sq *
> +to do wildcard matching.
> +.Pp
> +.It Xo
> +.Ic large-community Op Ar delete
> +.Ar as-number : Ns Ar local : Ns Ar local
> +.Xc
> +.It Xo
> +.Ic large-community Op Ar delete
> +.Ar name
> +.Xc
> +Set or delete the
> +.Em Large Communities
> +path attribute.
> +Communities are specified as
> +.Ar as-number : Ns Ar local : Ns Ar local ,
> +where
> +.Ar as-number
> +is an AS number and
> +.Ar local
> +is a locally-significant number between zero and
> +.Li 4294967295 .
>  For
>  .Cm delete ,
>  both
> Index: usr.sbin/bgpd/bgpd.h
> ===================================================================
> RCS file: /cvs/openbsd/src/usr.sbin/bgpd/bgpd.h,v
> retrieving revision 1.296
> diff -u -p -u -p -r1.296 bgpd.h
> --- usr.sbin/bgpd/bgpd.h      5 Oct 2016 07:38:06 -0000       1.296
> +++ usr.sbin/bgpd/bgpd.h      13 Oct 2016 14:41:12 -0000
> @@ -377,6 +377,7 @@ enum imsg_type {
>       IMSG_CTL_SHOW_RIB_PREFIX,
>       IMSG_CTL_SHOW_RIB_ATTR,
>       IMSG_CTL_SHOW_RIB_COMMUNITY,
> +     IMSG_CTL_SHOW_RIB_LARGECOMMUNITY,
>       IMSG_CTL_SHOW_NETWORK,
>       IMSG_CTL_SHOW_RIB_MEM,
>       IMSG_CTL_SHOW_TERSE,
> @@ -648,6 +649,18 @@ struct filter_community {
>       int             type;
>  };
>  
> +struct filter_largecommunity {
> +     int64_t         as;
> +     int64_t         ld1;
> +     int64_t         ld2;
> +};
> +
> +struct wire_largecommunity {
> +     uint32_t        as;
> +     uint32_t        ld1;
> +     uint32_t        ld2;
> +};
> +
>  struct filter_extcommunity {
>       u_int16_t       flags;
>       u_int8_t        type;
> @@ -675,6 +688,7 @@ struct ctl_show_rib_request {
>       struct bgpd_addr        prefix;
>       struct filter_as        as;
>       struct filter_community community;
> +     struct filter_largecommunity large_community;
>       u_int32_t               peerid;
>       pid_t                   pid;
>       u_int16_t               flags;
> @@ -793,6 +807,7 @@ struct filter_match {
>       struct filter_as                as;
>       struct filter_aslen             aslen;
>       struct filter_community         community;
> +     struct filter_largecommunity    large_community;
>       struct filter_extcommunity      ext_community;
>  };
>  
> @@ -834,6 +849,8 @@ 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,
> @@ -852,6 +869,7 @@ struct filter_set {
>               int32_t                 relative;
>               struct bgpd_addr        nexthop;
>               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/openbsd/src/usr.sbin/bgpd/control.c,v
> retrieving revision 1.82
> diff -u -p -u -p -r1.82 control.c
> --- usr.sbin/bgpd/control.c   5 Dec 2015 18:28:04 -0000       1.82
> +++ usr.sbin/bgpd/control.c   5 Sep 2016 13:41:29 -0000
> @@ -244,6 +244,7 @@ control_dispatch_msg(struct pollfd *pfd,
>                       case IMSG_CTL_SHOW_RIB_PREFIX:
>                       case IMSG_CTL_SHOW_RIB_MEM:
>                       case IMSG_CTL_SHOW_RIB_COMMUNITY:
> +                     case IMSG_CTL_SHOW_RIB_LARGECOMMUNITY:
>                       case IMSG_CTL_SHOW_NETWORK:
>                       case IMSG_CTL_SHOW_TERSE:
>                       case IMSG_CTL_SHOW_TIMER:
> @@ -462,6 +463,7 @@ control_dispatch_msg(struct pollfd *pfd,
>                       break;
>               case IMSG_CTL_SHOW_RIB_MEM:
>               case IMSG_CTL_SHOW_RIB_COMMUNITY:
> +             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/openbsd/src/usr.sbin/bgpd/parse.y,v
> retrieving revision 1.289
> diff -u -p -u -p -r1.289 parse.y
> --- usr.sbin/bgpd/parse.y     5 Oct 2016 07:38:06 -0000       1.289
> +++ usr.sbin/bgpd/parse.y     13 Oct 2016 15:31:31 -0000
> @@ -5,6 +5,8 @@
>   * Copyright (c) 2001 Markus Friedl.  All rights reserved.
>   * Copyright (c) 2001 Daniel Hartmeier.  All rights reserved.
>   * Copyright (c) 2001 Theo de Raadt.  All rights reserved.
> + * Copyright (c) 2016 Job Snijders <j...@instituut.net>
> + * Copyright (c) 2016 Peter Hessler <phess...@openbsd.org>
>   *
>   * Permission to use, copy, modify, and distribute this software for any
>   * purpose with or without fee is hereby granted, provided that the above
> @@ -138,6 +140,8 @@ struct filter_rule        *get_rule(enum action
>  
>  int           getcommunity(char *);
>  int           parsecommunity(struct filter_community *, char *);
> +int           getlargecommunity(char *);
> +int           parselargecommunity(struct filter_largecommunity *, char *);
>  int           parsesubtype(char *);
>  int           parseextvalue(char *, u_int32_t *);
>  int           parseextcommunity(struct filter_extcommunity *, char *,
> @@ -185,7 +189,7 @@ typedef struct {
>  %token       QUICK
>  %token       FROM TO ANY
>  %token       CONNECTED STATIC
> -%token       COMMUNITY EXTCOMMUNITY
> +%token       COMMUNITY EXTCOMMUNITY LARGECOMMUNITY
>  %token       PREFIX PREFIXLEN SOURCEAS TRANSITAS PEERAS DELETE MAXASLEN 
> MAXASSEQ
>  %token       SET LOCALPREF MED METRIC NEXTHOP REJECT BLACKHOLE NOMODIFY SELF
>  %token       PREPEND_SELF PREPEND_PEER PFTABLE WEIGHT RTLABEL ORIGIN
> @@ -1712,10 +1716,12 @@ 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($$));
> @@ -1776,6 +1782,18 @@ filter_elm     : filter_prefix_h       {
>                       }
>                       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) {
> +                             free($2);
> +                             YYERROR;
> +                     }
> +                     free($2);
> +             }
>               | EXTCOMMUNITY STRING STRING {
>                       if (fmopts.m.ext_community.flags &
>                           EXT_COMMUNITY_FLAG_VALID) {
> @@ -2131,6 +2149,31 @@ filter_set_opt : LOCALPREF NUMBER              {
>                               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) {
> +                             free($3);
> +                             free($$);
> +                             YYERROR;
> +                     }
> +                     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)) {
> +                             yyerror("'*' is not allowed in set community");
> +                             free($$);
> +                             YYERROR;
> +                     }
> +             }
>               | EXTCOMMUNITY delete STRING STRING {
>                       if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
>                               fatal(NULL);
> @@ -2266,6 +2309,7 @@ lookup(char *s)
>               { "inet6",              IPV6},
>               { "ipsec",              IPSEC},
>               { "key",                KEY},
> +             { "large-community",    LARGECOMMUNITY},
>               { "listen",             LISTEN},
>               { "local-address",      LOCALADDR},
>               { "localpref",          LOCALPREF},
> @@ -2911,6 +2955,59 @@ parsecommunity(struct filter_community *
>  }
>  
>  int
> +getlargecommunity(char *s)
> +{
> +     int              val;
> +     const char      *errstr;
> +
> +     if (strcmp(s, "*") == 0)
> +             return (COMMUNITY_ANY);
> +     if (strcmp(s, "neighbor-as") == 0)
> +             return (COMMUNITY_NEIGHBOR_AS);
> +     val = strtonum(s, 0, UINT_MAX, &errstr);
> +     if (errstr) {
> +             yyerror("Large Community %s is %s (max: %u)",
> +                 s, errstr, UINT_MAX);
> +             return (COMMUNITY_ERROR);
> +     }
> +     return (val);
> +}
> +
> +int
> +parselargecommunity(struct filter_largecommunity *c, char *s)
> +{
> +     char *p, *q;
> +     int 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 = getlargecommunity(s)) == COMMUNITY_ERROR)
> +             return (-1);
> +
> +     if ((ld1 = getlargecommunity(p)) == COMMUNITY_ERROR)
> +             return (-1);
> +
> +     if ((ld2 = getlargecommunity(q)) == COMMUNITY_ERROR)
> +             return (-1);
> +
> +     c->as = as;
> +     c->ld1 = ld1;
> +     c->ld2 = ld2;
> +
> +     return (0);
> +}
> +
> +int
>  parsesubtype(char *type)
>  {
>       /* this has to be sorted always */
> @@ -3527,6 +3624,10 @@ 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)
> @@ -3558,6 +3659,18 @@ merge_filterset(struct filter_set_head *
>                                       return (0);
>                               }
>                               break;
> +                     case ACTION_SET_LARGE_COMMUNITY:
> +                     case ACTION_DEL_LARGE_COMMUNITY:
> +                             if (s->action.large_community.as <
> +                                 t->action.large_community.as ||
> +                                 (s->action.large_community.as ==
> +                                 t->action.large_community.as &&
> +                                 s->action.large_community.ld1 <
> +                                 t->action.large_community.ld2 )) {
> +                                     TAILQ_INSERT_BEFORE(t, s, entry);
> +                                     return (0);
> +                             }
> +                             break;
>                       case ACTION_SET_EXT_COMMUNITY:
>                       case ACTION_DEL_EXT_COMMUNITY:
>                               if (memcmp(&s->action.ext_community,
> @@ -3634,6 +3747,7 @@ get_rule(enum action_types type)
>               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/openbsd/src/usr.sbin/bgpd/printconf.c,v
> retrieving revision 1.98
> diff -u -p -u -p -r1.98 printconf.c
> --- usr.sbin/bgpd/printconf.c 5 Oct 2016 07:38:06 -0000       1.98
> +++ usr.sbin/bgpd/printconf.c 13 Oct 2016 15:31:27 -0000
> @@ -2,6 +2,8 @@
>  
>  /*
>   * Copyright (c) 2003, 2004 Henning Brauer <henn...@openbsd.org>
> + * Copyright (c) 2016 Job Snijders <j...@instituut.net>
> + * Copyright (c) 2016 Peter Hessler <phess...@openbsd.org>
>   *
>   * Permission to use, copy, modify, and distribute this software for any
>   * purpose with or without fee is hereby granted, provided that the above
> @@ -28,6 +30,7 @@
>  
>  void          print_op(enum comp_ops);
>  void          print_community(int, int);
> +void          print_largecommunity(int64_t , int64_t, int64_t);

whitespace ,

>  void          print_extcommunity(struct filter_extcommunity *);
>  void          print_origin(u_int8_t);
>  void          print_set(struct filter_set_head *);
> @@ -102,6 +105,33 @@ print_community(int as, int type)
>  }
>  
>  void
> +print_largecommunity(int64_t as, int64_t ld1, int64_t ld2)
> +{
> +     if (as == COMMUNITY_ANY)
> +             printf("*:");
> +     else if (as == COMMUNITY_NEIGHBOR_AS)
> +             printf("neighbor-as:");
> +     else
> +             printf("%llu:", as);

as is signed (compare print_community())

> +
> +     if (ld1 == COMMUNITY_ANY)
> +             printf("*:");
> +     else if (ld1 == COMMUNITY_NEIGHBOR_AS)
> +             printf("neighbor-as:");
> +     else
> +             printf("%llu:", ld1);

same  

> +     if (ld2 == COMMUNITY_ANY)
> +             printf("* ");
> +     else if (ld2 == COMMUNITY_NEIGHBOR_AS)
> +             printf("neighbor-as ");
> +     else
> +             printf("%llu ", ld2);

same

> +}
> +
> +
> +void
>  print_extcommunity(struct filter_extcommunity *c)
>  {
>       switch (c->type & EXT_COMMUNITY_VALUE) {
> @@ -202,6 +232,20 @@ print_set(struct filter_set_head *set)
>                           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(" ");
> +                     break;
>               case ACTION_PFTABLE:
>                       printf("pftable %s ", s->action.pftable);
>                       break;
> @@ -627,6 +671,12 @@ print_rule(struct peer *peer_l, struct f
>       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/openbsd/src/usr.sbin/bgpd/rde.c,v
> retrieving revision 1.350
> diff -u -p -u -p -r1.350 rde.c
> --- usr.sbin/bgpd/rde.c       3 Sep 2016 16:22:17 -0000       1.350
> +++ usr.sbin/bgpd/rde.c       13 Oct 2016 15:31:23 -0000
> @@ -2,6 +2,8 @@
>  
>  /*
>   * Copyright (c) 2003, 2004 Henning Brauer <henn...@openbsd.org>
> + * Copyright (c) 2016 Job Snijders <j...@instituut.net>
> + * Copyright (c) 2016 Peter Hessler <phess...@openbsd.org>
>   *
>   * Permission to use, copy, modify, and distribute this software for any
>   * purpose with or without fee is hereby granted, provided that the above
> @@ -559,6 +561,7 @@ badnet:
>               case IMSG_CTL_SHOW_RIB:
>               case IMSG_CTL_SHOW_RIB_AS:
>               case IMSG_CTL_SHOW_RIB_COMMUNITY:
> +             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");
> @@ -1577,6 +1580,23 @@ bad_flags:
>                   ATTR_PARTIAL))
>                       goto bad_flags;
>               goto optattr;
> +     case ATTR_LARGE_COMMUNITIES:
> +             if (attr_len % 12 != 0) {
> +                     /*
> +                      * mark update as bad and withdraw all routes as per
> +                      * draft-ietf-idr-optional-transitive-00.txt
> +                      * but only if partial bit is set
> +                      */
> +                     if ((flags & ATTR_PARTIAL) == 0)
> +                             goto bad_len;
> +                     a->flags |= F_ATTR_PARSE_ERR;
> +                     log_peer_warnx(&peer->conf, "bad LARGE COMMUNITIES, "
> +                         "path invalidated and prefix withdrawn");
> +             }
> +             if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
> +                 ATTR_PARTIAL))
> +                     goto bad_flags;
> +             goto optattr;
>       case ATTR_EXT_COMMUNITIES:
>               if (attr_len % 8 != 0) {
>                       /*
> @@ -2266,6 +2286,10 @@ rde_dump_filter(struct prefix *p, struct
>                   !community_match(p->aspath, req->community.as,
>                   req->community.type))
>                       return;
> +             if (req->type == IMSG_CTL_SHOW_RIB_LARGECOMMUNITY &&
> +                 !community_large_match(p->aspath, req->large_community.as,
> +                 req->large_community.ld1, req->large_community.ld2))
> +                     return;
>               if ((req->flags & F_CTL_ACTIVE) && p->rib->active != p)
>                       return;
>               rde_dump_rib_as(p, p->aspath, req->pid, req->flags);
> @@ -2348,6 +2372,7 @@ rde_dump_ctx_new(struct ctl_show_rib_req
>       case IMSG_CTL_SHOW_RIB:
>       case IMSG_CTL_SHOW_RIB_AS:
>       case IMSG_CTL_SHOW_RIB_COMMUNITY:
> +     case IMSG_CTL_SHOW_RIB_LARGECOMMUNITY:
>               ctx->ribctx.ctx_upcall = rde_dump_upcall;
>               break;
>       case IMSG_CTL_SHOW_RIB_PREFIX:
> Index: usr.sbin/bgpd/rde.h
> ===================================================================
> RCS file: /cvs/openbsd/src/usr.sbin/bgpd/rde.h,v
> retrieving revision 1.149
> diff -u -p -u -p -r1.149 rde.h
> --- usr.sbin/bgpd/rde.h       6 Nov 2015 16:23:26 -0000       1.149
> +++ usr.sbin/bgpd/rde.h       13 Oct 2016 14:10:00 -0000
> @@ -112,7 +112,8 @@ enum attrtypes {
>       ATTR_MP_UNREACH_NLRI=15,
>       ATTR_EXT_COMMUNITIES=16,
>       ATTR_AS4_PATH=17,
> -     ATTR_AS4_AGGREGATOR=18
> +     ATTR_AS4_AGGREGATOR=18,
> +     ATTR_LARGE_COMMUNITIES=30,
>  };
>  
>  /* attribute flags. 4 low order bits reserved */
> @@ -367,6 +368,12 @@ int               aspath_lenmatch(struct aspath *, e
>  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 *,
> Index: usr.sbin/bgpd/rde_attr.c
> ===================================================================
> RCS file: /cvs/openbsd/src/usr.sbin/bgpd/rde_attr.c,v
> retrieving revision 1.95
> diff -u -p -u -p -r1.95 rde_attr.c
> --- usr.sbin/bgpd/rde_attr.c  24 Oct 2015 08:00:42 -0000      1.95
> +++ usr.sbin/bgpd/rde_attr.c  13 Oct 2016 15:31:21 -0000
> @@ -2,6 +2,8 @@
>  
>  /*
>   * Copyright (c) 2004 Claudio Jeker <clau...@openbsd.org>
> + * Copyright (c) 2016 Job Snijders <j...@instituut.net>
> + * Copyright (c) 2016 Peter Hessler <phess...@openbsd.org>
>   *
>   * Permission to use, copy, modify, and distribute this software for any
>   * purpose with or without fee is hereby granted, provided that the above
> @@ -1351,4 +1353,148 @@ community_ext_matchone(struct filter_ext
>       }
>  
>       return (0);
> +}
> +
> +int
> +community_large_match(struct rde_aspath *asp, int64_t as, int64_t ld1,
> +    int64_t ld2)
> +{
> +     struct wire_largecommunity      *bar;
> +     struct attr     *a;
> +     u_int8_t        *p;
> +     u_int16_t        len;
> +     u_int32_t        eas, eld1, eld2;
> +
> +     a = attr_optget(asp, ATTR_LARGE_COMMUNITIES);
> +     if (a == NULL)
> +             /* no communities, no match */
> +             return (0);
> +
> +     p = a->data;
> +     for (len = a->len / 12; len > 0; len--) {
> +             bar = (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))
> +                     return (1);
> +     }
> +     return (0);
> +}
> +
> +int
> +community_large_set(struct rde_aspath *asp, int64_t as, int64_t ld1,
> +    int64_t ld2)
> +{
> +     struct wire_largecommunity      *bar;
> +     struct attr     *attr;
> +     u_int8_t        *p = NULL;
> +     unsigned int     i, ncommunities = 0;
> +     u_int8_t         f = ATTR_OPTIONAL|ATTR_TRANSITIVE;
> +
> +     attr = attr_optget(asp, ATTR_LARGE_COMMUNITIES);
> +     if (attr != NULL) {
> +             p = attr->data;
> +             ncommunities = attr->len / 12;
> +     }
> +
> +     /* first check if the community is not already set */
> +     for (i = 0; i < ncommunities; i++) {
> +             bar = (struct wire_largecommunity *)p;
> +             if (bar->as == as && bar->ld1 == ld1 && bar->ld2 == ld2)
> +                     /* already present, nothing todo */
> +                     return (1);
> +             p += 12;
> +     }
> +
> +     if (ncommunities++ >= USHRT_MAX / 12)
> +             /* overflow */
> +             return (0);
> +
> +     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);
> +
> +     if (attr != NULL) {
> +             memcpy(p + 12, attr->data, attr->len);
> +             f = attr->flags;
> +             attr_free(asp, attr);
> +     }
> +
> +     attr_optadd(asp, f, ATTR_LARGE_COMMUNITIES, p, ncommunities * 12);
> +
> +     free(p);
> +     return (1);
> +}
> +
> +void
> +community_large_delete(struct rde_aspath *asp, int64_t as, int64_t ld1,
> +    int64_t ld2)
> +{
> +     struct wire_largecommunity      *bar;
> +     struct attr     *attr;
> +     u_int8_t        *p, *n;
> +     u_int16_t        l = 0, len = 0;
> +     u_int32_t        eas, eld1, eld2;
> +     u_int8_t         f;
> +
> +     attr = attr_optget(asp, ATTR_LARGE_COMMUNITIES);
> +     if (attr == NULL)
> +             /* no attr nothing to do */
> +             return;
> +
> +     p = attr->data;
> +     for (len = 0; l < attr->len; l += 12) {
> +             bar = (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))
> +                     /* match */
> +                     continue;
> +             len += 12;
> +     }
> +
> +     if (len == 0) {
> +             attr_free(asp, attr);
> +             return;
> +     }
> +
> +     if ((n = malloc(len)) == NULL)
> +             fatal("community_delete");
> +
> +     p = attr->data;
> +     for (l = 0; l < len && p < attr->data + attr->len; ) {
> +             bar = (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))
> +                     /* match */
> +                     continue;
> +             memcpy(n + l, bar, sizeof(*bar));
> +             l += 12;
> +     }
> +
> +     f = attr->flags;
> +
> +     attr_free(asp, attr);
> +     attr_optadd(asp, f, ATTR_LARGE_COMMUNITIES, n, len);
> +     free(n);
>  }
> Index: usr.sbin/bgpd/rde_filter.c
> ===================================================================
> RCS file: /cvs/openbsd/src/usr.sbin/bgpd/rde_filter.c,v
> retrieving revision 1.77
> diff -u -p -u -p -r1.77 rde_filter.c
> --- usr.sbin/bgpd/rde_filter.c        3 Jun 2016 17:36:37 -0000       1.77
> +++ usr.sbin/bgpd/rde_filter.c        13 Oct 2016 15:31:13 -0000
> @@ -2,6 +2,8 @@
>  
>  /*
>   * Copyright (c) 2004 Claudio Jeker <clau...@openbsd.org>
> + * Copyright (c) 2016 Job Snijders <j...@instituut.net>
> + * Copyright (c) 2016 Peter Hessler <phess...@openbsd.org>
>   *
>   * Permission to use, copy, modify, and distribute this software for any
>   * purpose with or without fee is hereby granted, provided that the above
> @@ -35,7 +37,7 @@ rde_apply_set(struct rde_aspath *asp, st
>  {
>       struct filter_set       *set;
>       u_char                  *np;
> -     int                      as, type;
> +     int                      as, type, ld1, ld2;

int?

>       u_int32_t                prep_as;
>       u_int16_t                nl;
>       u_int8_t                 prepend;
> @@ -181,6 +183,84 @@ rde_apply_set(struct rde_aspath *asp, st
>  
>                       community_delete(asp, as, type);
>                       break;
> +             case ACTION_SET_LARGE_COMMUNITY:
> +                     switch (set->action.large_community.as) {
> +                     case COMMUNITY_ERROR:
> +                             fatalx("rde_apply_set bad large community 
> string");
> +                     case COMMUNITY_NEIGHBOR_AS:
> +                             as = peer->conf.remote_as;
> +                             break;
> +                     case COMMUNITY_ANY:
> +                     default:
> +                             as = set->action.large_community.as;
> +                             break;
> +                     }
> +
> +                     switch (set->action.large_community.ld1) {
> +                     case COMMUNITY_ERROR:
> +                             fatalx("rde_apply_set bad large community 
> string");
> +                     case COMMUNITY_NEIGHBOR_AS:
> +                             ld1 = peer->conf.remote_as;
> +                             break;
> +                     case COMMUNITY_ANY:
> +                     default:
> +                             ld1 = set->action.large_community.ld1;
> +                             break;
> +                     }
> +
> +                     switch (set->action.large_community.ld2) {
> +                     case COMMUNITY_ERROR:
> +                             fatalx("rde_apply_set bad large community 
> string");
> +                     case COMMUNITY_NEIGHBOR_AS:
> +                             ld2 = peer->conf.remote_as;
> +                             break;
> +                     case COMMUNITY_ANY:
> +                     default:
> +                             ld2 = set->action.large_community.ld2;
> +                             break;
> +                     }
> +
> +                     community_large_set(asp, as, ld1, ld2);
> +                     break;
> +             case ACTION_DEL_LARGE_COMMUNITY:
> +                     switch (set->action.large_community.as) {
> +                     case COMMUNITY_ERROR:
> +                             fatalx("rde_apply_set bad large community 
> string");
> +                     case COMMUNITY_NEIGHBOR_AS:
> +                             as = peer->conf.remote_as;
> +                             break;
> +                     case COMMUNITY_ANY:
> +                     default:
> +                             as = set->action.large_community.as;
> +                             break;
> +                     }
> +
> +                     switch (set->action.large_community.ld1) {
> +                     case COMMUNITY_ERROR:
> +                             fatalx("rde_apply_set bad large community 
> string");
> +                     case COMMUNITY_NEIGHBOR_AS:
> +                             ld1 = peer->conf.remote_as;
> +                             break;
> +                     case COMMUNITY_ANY:
> +                     default:
> +                             ld1 = set->action.large_community.ld1;
> +                             break;
> +                     }
> +
> +                     switch (set->action.large_community.ld2) {
> +                     case COMMUNITY_ERROR:
> +                             fatalx("rde_apply_set bad large community 
> string");
> +                     case COMMUNITY_NEIGHBOR_AS:
> +                             ld2 = peer->conf.remote_as;
> +                             break;
> +                     case COMMUNITY_ANY:
> +                     default:
> +                             ld2 = set->action.large_community.ld2;
> +                             break;
> +                     }
> +
> +                     community_large_delete(asp, as, ld1, ld2);
> +                     break;
>               case ACTION_PFTABLE:
>                       /* convert pftable name to an id */
>                       set->action.id = pftable_name2id(set->action.pftable);
> @@ -222,7 +302,7 @@ rde_filter_match(struct filter_rule *f, 
>      struct rde_peer *from)
>  {
>       u_int32_t       pas;
> -     int             cas, type;
> +     int             cas, type, ld1, ld2;

int?

>       if (asp != NULL && f->match.as.type != AS_NONE) {
>               if (f->match.as.flags & AS_FLAG_NEIGHBORAS)
> @@ -270,6 +350,44 @@ rde_filter_match(struct filter_rule *f, 
>               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_apply_set bad community string");
> +             case COMMUNITY_NEIGHBOR_AS:
> +                     cas = peer->conf.remote_as;
> +                     break;
> +             default:
> +                     cas = f->match.large_community.as;
> +                     break;
> +             }
> +
> +             switch (f->match.large_community.ld1) {
> +             case COMMUNITY_ERROR:
> +                     fatalx("rde_apply_set bad community string");
> +             case COMMUNITY_NEIGHBOR_AS:
> +                     ld1 = peer->conf.remote_as;
> +                     break;
> +             default:
> +                     ld1 = f->match.large_community.ld1;
> +                     break;
> +             }
> +
> +             switch (f->match.large_community.ld2) {
> +             case COMMUNITY_ERROR:
> +                     fatalx("rde_apply_set bad community string");
> +             case COMMUNITY_NEIGHBOR_AS:
> +                     ld2 = peer->conf.remote_as;
> +                     break;
> +             default:
> +                     ld2 = f->match.large_community.ld2;
> +                     break;
> +             }
> +
> +             if (community_large_match(asp, cas, ld1, ld2) == 0)
> +                     return (0);
> +     }
>  
>       if (f->match.prefix.addr.aid != 0) {
>               if (f->match.prefix.addr.aid != prefix->aid)
> @@ -547,6 +665,14 @@ 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)
> @@ -630,6 +756,10 @@ 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");
> 
> 
> 
> 
> -- 
> What I've done, of course, is total garbage.
>               -- R. Willard, Pure Math 430a
> 

Reply via email to