forgot to look at bgpctl in my first reply, sry
Peter Hessler([email protected]) 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?
>
>
> 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 <[email protected]>
> + * Copyright (c) 2016 Job Snijders <[email protected]>
> + * Copyright (c) 2016 Peter Hessler <[email protected]>
> *
> * 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 <[email protected]>
> + * Copyright (c) 2016 Job Snijders <[email protected]>
> + * Copyright (c) 2016 Peter Hessler <[email protected]>
> *
> * 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 *);
returns int?
> +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)
returns int?
> +{
> + 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);
uval is unsigned
> +}
> +
> +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
> +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 <[email protected]>
> + * Copyright (c) 2016 Peter Hessler <[email protected]>
> *
> * 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 <[email protected]>
> + * Copyright (c) 2016 Job Snijders <[email protected]>
> + * Copyright (c) 2016 Peter Hessler <[email protected]>
> *
> * 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);
> 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);
> +
> + if (ld1 == COMMUNITY_ANY)
> + printf("*:");
> + else if (ld1 == COMMUNITY_NEIGHBOR_AS)
> + printf("neighbor-as:");
> + else
> + printf("%llu:", ld1);
> +
> + if (ld2 == COMMUNITY_ANY)
> + printf("* ");
> + else if (ld2 == COMMUNITY_NEIGHBOR_AS)
> + printf("neighbor-as ");
> + else
> + printf("%llu ", ld2);
> +
> +}
> +
> +
> +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 <[email protected]>
> + * Copyright (c) 2016 Job Snijders <[email protected]>
> + * Copyright (c) 2016 Peter Hessler <[email protected]>
> *
> * 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 <[email protected]>
> + * Copyright (c) 2016 Job Snijders <[email protected]>
> + * Copyright (c) 2016 Peter Hessler <[email protected]>
> *
> * 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 <[email protected]>
> + * Copyright (c) 2016 Job Snijders <[email protected]>
> + * Copyright (c) 2016 Peter Hessler <[email protected]>
> *
> * 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;
> 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;
>
> 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
>