forgot to look at bgpctl in my first reply, sry 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? > > > 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 *);
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 <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); > 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 <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; > 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 >