Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

bgpd draft-ietf-idr-large-community

4 views
Skip to first unread message

Peter Hessler

unread,
Oct 10, 2016, 6:01:47 PM10/10/16
to te...@openbsd.org, hen...@openbsd.org, cla...@openbsd.org, be...@openbsd.org
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?



Index: usr.sbin/bgpd.large-communities//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.large-communities//bgpd.8 14 Aug 2013 06:32:36 -0000 1.48
+++ usr.sbin/bgpd.large-communities//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.large-communities//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.large-communities//bgpd.conf.5 5 Oct 2016 07:38:06 -0000 1.147
+++ usr.sbin/bgpd.large-communities//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.large-communities//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.large-communities//bgpd.h 5 Oct 2016 07:38:06 -0000 1.296
+++ usr.sbin/bgpd.large-communities//bgpd.h 10 Oct 2016 19:14:41 -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,12 @@ struct filter_community {
int type;
};

+struct filter_largecommunity {
+ uint32_t as;
+ uint32_t ld1;
+ uint32_t ld2;
+};
+
struct filter_extcommunity {
u_int16_t flags;
u_int8_t type;
@@ -675,6 +682,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 +801,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 +843,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 +863,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.large-communities//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.large-communities//control.c 5 Dec 2015 18:28:04 -0000 1.82
+++ usr.sbin/bgpd.large-communities//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.large-communities//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.large-communities//parse.y 5 Oct 2016 07:38:06 -0000 1.289
+++ usr.sbin/bgpd.large-communities//parse.y 10 Oct 2016 21:49:58 -0000
@@ -138,6 +138,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 +187,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 +1714,12 @@ filter_as : as4number_any {
filter_match_h : /* empty */ {
bzero(&$$, sizeof($$));
$$.m.community.as = COMMUNITY_UNSET;
+ $$.m.large_community.as = (uint32_t)COMMUNITY_UNSET;
}
| {
bzero(&fmopts, sizeof(fmopts));
fmopts.m.community.as = COMMUNITY_UNSET;
+ fmopts.m.large_community.as = (uint32_t)COMMUNITY_UNSET;
}
filter_match {
memcpy(&$$, &fmopts, sizeof($$));
@@ -1776,6 +1780,18 @@ filter_elm : filter_prefix_h {
}
free($2);
}
+ | LARGECOMMUNITY STRING {
+ if (fmopts.m.large_community.as != (uint32_t)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 +2147,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 == (uint32_t)COMMUNITY_ANY ||
+ $$->action.large_community.ld1 == (uint32_t)COMMUNITY_ANY ||
+ $$->action.large_community.ld2 == (uint32_t)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 +2307,7 @@ lookup(char *s)
{ "inet6", IPV6},
{ "ipsec", IPSEC},
{ "key", KEY},
+ { "large-community", LARGECOMMUNITY},
{ "listen", LISTEN},
{ "local-address", LOCALADDR},
{ "localpref", LOCALPREF},
@@ -2911,6 +2953,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 +3622,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 +3657,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 +3745,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 = (uint32_t)COMMUNITY_UNSET;
TAILQ_INIT(&r->set);
if (curpeer == curgroup) {
/* group */
Index: usr.sbin/bgpd.large-communities//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.large-communities//printconf.c 5 Oct 2016 07:38:06 -0000 1.98
+++ usr.sbin/bgpd.large-communities//printconf.c 10 Oct 2016 21:40:47 -0000
@@ -28,6 +28,7 @@

void print_op(enum comp_ops);
void print_community(int, int);
+void print_largecommunity(uint32_t , uint32_t, uint32_t);
void print_extcommunity(struct filter_extcommunity *);
void print_origin(u_int8_t);
void print_set(struct filter_set_head *);
@@ -102,6 +103,33 @@ print_community(int as, int type)
}

void
+print_largecommunity(uint32_t as, uint32_t ld1, uint32_t ld2)
+{
+ if (as == (uint32_t)COMMUNITY_ANY)
+ printf("*:");
+ else if (as == (uint32_t)COMMUNITY_NEIGHBOR_AS)
+ printf("neighbor-as:");
+ else
+ printf("%u:", as);
+
+ if (ld1 == (uint32_t)COMMUNITY_ANY)
+ printf("*:");
+ else if (ld1 == (uint32_t)COMMUNITY_NEIGHBOR_AS)
+ printf("neighbor-as:");
+ else
+ printf("%u:", ld1);
+
+ if (ld2 == (uint32_t)COMMUNITY_ANY)
+ printf("* ");
+ else if (ld2 == (uint32_t)COMMUNITY_NEIGHBOR_AS)
+ printf("neighbor-as ");
+ else
+ printf("%u ", ld2);
+
+}
+
+
+void
print_extcommunity(struct filter_extcommunity *c)
{
switch (c->type & EXT_COMMUNITY_VALUE) {
@@ -200,6 +228,20 @@ print_set(struct filter_set_head *set)
printf("community ");
print_community(s->action.community.as,
s->action.community.type);
+ printf(" ");
+ break;
+ case ACTION_DEL_LARGE_COMMUNITY:
+ printf("large-community delete ");
+ print_largecommunity(s->action.large_community.as,
+ s->action.large_community.ld1,
+ s->action.large_community.ld2);
+ printf(" ");
+ break;
+ case ACTION_SET_LARGE_COMMUNITY:
+ printf("large-community ");
+ print_largecommunity(s->action.large_community.as,
+ s->action.large_community.ld1,
+ s->action.large_community.ld2);
printf(" ");
break;
case ACTION_PFTABLE:
Index: usr.sbin/bgpd.large-communities//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.large-communities//rde.c 3 Sep 2016 16:22:17 -0000 1.350
+++ usr.sbin/bgpd.large-communities//rde.c 5 Sep 2016 14:44:09 -0000
@@ -559,6 +559,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 +1578,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 +2284,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 +2370,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.large-communities//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.large-communities//rde.h 6 Nov 2015 16:23:26 -0000 1.149
+++ usr.sbin/bgpd.large-communities//rde.h 10 Oct 2016 19:10:01 -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 *, uint32_t, uint32_t,
+ uint32_t);
+int community_large_set(struct rde_aspath *, uint32_t, uint32_t,
+ uint32_t);
+void community_large_delete(struct rde_aspath *, uint32_t,
+ uint32_t, uint32_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.large-communities//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.large-communities//rde_attr.c 24 Oct 2015 08:00:42 -0000 1.95
+++ usr.sbin/bgpd.large-communities//rde_attr.c 10 Oct 2016 21:34:08 -0000
@@ -1352,3 +1352,147 @@ community_ext_matchone(struct filter_ext

return (0);
}
+
+int
+community_large_match(struct rde_aspath *asp, uint32_t as, uint32_t ld1,
+ uint32_t ld2)
+{
+ struct filter_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 filter_largecommunity *)p;
+ p += 12;
+ eas = betoh32(bar->as);
+ eld1 = betoh32(bar->ld1);
+ eld2 = betoh32(bar->ld2);
+
+ if ((as == (uint32_t)COMMUNITY_ANY || as == eas) &&
+ (ld1 == (uint32_t)COMMUNITY_ANY || ld1 == eld1) &&
+ (ld2 == (uint32_t)COMMUNITY_ANY || ld2 == eld2))
+ return (1);
+ }
+ return (0);
+}
+
+int
+community_large_set(struct rde_aspath *asp, uint32_t as, uint32_t ld1,
+ uint32_t ld2)
+{
+ struct filter_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 filter_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 filter_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, uint32_t as, uint32_t ld1,
+ uint32_t ld2)
+{
+ struct filter_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 filter_largecommunity *)p;
+ p += 12;
+ eas = betoh32(bar->as);
+ eld1 = betoh32(bar->ld1);
+ eld2 = betoh32(bar->ld2);
+
+ if ((as == (uint32_t)COMMUNITY_ANY || as == eas) &&
+ (ld1 == (uint32_t)COMMUNITY_ANY || ld1 == eld1) &&
+ (ld2 == (uint32_t)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 filter_largecommunity *)p;
+ p += 12;
+ eas = betoh32(bar->as);
+ eld1 = betoh32(bar->ld1);
+ eld2 = betoh32(bar->ld2);
+
+ if ((as == (uint32_t)COMMUNITY_ANY || as == eas) &&
+ (ld1 == (uint32_t)COMMUNITY_ANY || ld1 == eld1) &&
+ (ld2 == (uint32_t)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.large-communities//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.large-communities//rde_filter.c 3 Jun 2016 17:36:37 -0000 1.77
+++ usr.sbin/bgpd.large-communities//rde_filter.c 10 Oct 2016 21:53:24 -0000
@@ -35,7 +35,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 +181,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 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 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 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);
@@ -547,6 +625,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 +716,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");
Index: usr.sbin/bgpctl.large-communities//Makefile
===================================================================
RCS file: /cvs/openbsd/src/usr.sbin/bgpctl/Makefile,v
retrieving revision 1.12
diff -u -p -u -p -r1.12 Makefile
--- usr.sbin/bgpctl.large-communities//Makefile 21 Sep 2011 10:37:51 -0000 1.12
+++ usr.sbin/bgpctl.large-communities//Makefile 1 Oct 2016 20:49:22 -0000
@@ -11,7 +11,7 @@ CFLAGS+= -Wstrict-prototypes -Wmissing-p
CFLAGS+= -Wmissing-declarations
CFLAGS+= -Wshadow -Wpointer-arith -Wcast-qual
CFLAGS+= -Wsign-compare
-CFLAGS+= -I${.CURDIR} -I${.CURDIR}/../bgpd
+CFLAGS+= -I${.CURDIR} -I${.CURDIR}/../bgpd.large-communities
MAN= bgpctl.8
LDADD= -lutil
DPADD+= ${LIBUTIL}
Index: usr.sbin/bgpctl.large-communities//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.large-communities//bgpctl.8 25 May 2016 14:15:59 -0000 1.69
+++ usr.sbin/bgpctl.large-communities//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.large-communities//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.large-communities//bgpctl.c 3 Jun 2016 17:36:37 -0000 1.188
+++ usr.sbin/bgpctl.large-communities//bgpctl.c 10 Oct 2016 21:03:12 -0000
@@ -82,6 +82,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 +255,13 @@ main(int argc, char *argv[])
sizeof(res->community));
type = IMSG_CTL_SHOW_RIB_COMMUNITY;
}
+ if (res->large_community.as != (uint32_t)COMMUNITY_UNSET &&
+ res->large_community.ld1 != (uint32_t)COMMUNITY_UNSET &&
+ res->large_community.ld2 != (uint32_t)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 +283,11 @@ main(int argc, char *argv[])
res->community.type != COMMUNITY_UNSET)
memcpy(&ribreq.community, &res->community,
sizeof(res->community));
+ if (res->large_community.as != (uint32_t)COMMUNITY_UNSET &&
+ res->large_community.ld1 != (uint32_t)COMMUNITY_UNSET &&
+ res->large_community.ld2 != (uint32_t)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 +390,11 @@ main(int argc, char *argv[])
res->community.type != COMMUNITY_UNSET)
memcpy(&ribreq.community, &res->community,
sizeof(res->community));
+ if (res->large_community.as != (uint32_t)COMMUNITY_UNSET &&
+ res->large_community.ld1 != (uint32_t)COMMUNITY_UNSET &&
+ res->large_community.ld2 != (uint32_t)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 +1442,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));
@@ -1496,6 +1519,30 @@ show_community(u_char *data, u_int16_t l
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(" ");
+ }
+}
+

void
show_ext_community(u_char *data, u_int16_t len)
Index: usr.sbin/bgpctl.large-communities//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.large-communities//parser.c 11 Oct 2015 19:53:57 -0000 1.73
+++ usr.sbin/bgpctl.large-communities//parser.c 10 Oct 2016 21:24:33 -0000
@@ -44,6 +44,7 @@ enum token_type {
PEERDESC,
RIBNAME,
COMMUNITY,
+ LARGE_COMMUNITY,
LOCALPREF,
MED,
NEXTHOP,
@@ -90,11 +91,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 +163,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 +279,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 +308,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 +327,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 +406,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 +420,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 +576,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 +695,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:
@@ -960,6 +990,58 @@ done:
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 ((int32_t)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];
+ u_int32_t as, ld1, ld2;
+ int i = 0;
+
+ while (p != NULL) {
+ array[i++] = p;
+ p = strchr(p, ':');
+ if (p)
+ *p++ = NULL;
+ }
+
+ 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);
+}
+

int
parse_nexthop(const char *word, struct parse_result *r)
Index: usr.sbin/bgpctl.large-communities//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.large-communities//parser.h 17 Apr 2015 07:51:09 -0000 1.27
+++ usr.sbin/bgpctl.large-communities//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;



--
Lockwood's Long Shot:
The chances of getting eaten up by a lion on Main Street aren't
one in a million, but once would be enough.

Peter Hessler

unread,
Oct 13, 2016, 11:35:27 AM10/13/16
to te...@openbsd.org, hen...@openbsd.org, cla...@openbsd.org, be...@openbsd.org
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 <hen...@openbsd.org>
+ * Copyright (c) 2016 Job Snijders <j...@instituut.net>
+ * Copyright (c) 2016 Peter Hessler <phes...@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 <hen...@openbsd.org>
+ * Copyright (c) 2016 Job Snijders <j...@instituut.net>
+ * Copyright (c) 2016 Peter Hessler <phes...@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
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 <phes...@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 *
@@ -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 <hen...@openbsd.org>
+ * Copyright (c) 2016 Job Snijders <j...@instituut.net>
+ * Copyright (c) 2016 Peter Hessler <phes...@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 <hen...@openbsd.org>
+ * Copyright (c) 2016 Job Snijders <j...@instituut.net>
+ * Copyright (c) 2016 Peter Hessler <phes...@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 <cla...@openbsd.org>
+ * Copyright (c) 2016 Job Snijders <j...@instituut.net>
+ * Copyright (c) 2016 Peter Hessler <phes...@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 <cla...@openbsd.org>
+ * Copyright (c) 2016 Job Snijders <j...@instituut.net>
+ * Copyright (c) 2016 Peter Hessler <phes...@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_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

0 new messages