summaryrefslogtreecommitdiff
path: root/usr.sbin/bgpd
diff options
context:
space:
mode:
authorPeter Hessler <phessler@cvs.openbsd.org>2016-10-14 16:05:37 +0000
committerPeter Hessler <phessler@cvs.openbsd.org>2016-10-14 16:05:37 +0000
commit01b441ff7f82f081c867c730843a20ced322c69a (patch)
treeca0453d28e3be1dd47c8ca80ee1921b62665f03a /usr.sbin/bgpd
parentab11fdd7396c99faa03965917bfae604b99150fb (diff)
Add support for draft-ietf-idr-large-community
Joint work with Job Snijders, many thanks! OK benno@ deraadt@
Diffstat (limited to 'usr.sbin/bgpd')
-rw-r--r--usr.sbin/bgpd/bgpd.815
-rw-r--r--usr.sbin/bgpd/bgpd.conf.564
-rw-r--r--usr.sbin/bgpd/bgpd.h20
-rw-r--r--usr.sbin/bgpd/control.c4
-rw-r--r--usr.sbin/bgpd/parse.y118
-rw-r--r--usr.sbin/bgpd/printconf.c52
-rw-r--r--usr.sbin/bgpd/rde.c27
-rw-r--r--usr.sbin/bgpd/rde.h11
-rw-r--r--usr.sbin/bgpd/rde_attr.c148
-rw-r--r--usr.sbin/bgpd/rde_filter.c134
10 files changed, 579 insertions, 14 deletions
diff --git a/usr.sbin/bgpd/bgpd.8 b/usr.sbin/bgpd/bgpd.8
index aab3d517dd9..89f34fc0d81 100644
--- a/usr.sbin/bgpd/bgpd.8
+++ b/usr.sbin/bgpd/bgpd.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: bgpd.8,v 1.48 2013/08/14 06:32:36 jmc Exp $
+.\" $OpenBSD: bgpd.8,v 1.49 2016/10/14 16:05:35 phessler Exp $
.\"
.\" Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
.\"
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: August 14 2013 $
+.Dd $Mdocdate: October 14 2016 $
.Dt BGPD 8
.Os
.Sh NAME
@@ -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
diff --git a/usr.sbin/bgpd/bgpd.conf.5 b/usr.sbin/bgpd/bgpd.conf.5
index a4b9613951c..987c2b3a712 100644
--- a/usr.sbin/bgpd/bgpd.conf.5
+++ b/usr.sbin/bgpd/bgpd.conf.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: bgpd.conf.5,v 1.147 2016/10/05 07:38:06 phessler Exp $
+.\" $OpenBSD: bgpd.conf.5,v 1.148 2016/10/14 16:05:35 phessler Exp $
.\"
.\" Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
.\" Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -16,7 +16,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: October 5 2016 $
+.Dd $Mdocdate: October 14 2016 $
.Dt BGPD.CONF 5
.Os
.Sh NAME
@@ -1143,6 +1143,37 @@ 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
+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
@@ -1375,6 +1406,35 @@ may be set to
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
+.Ar as-number
+and
+.Ar local
+may be set to
+.Sq *
+to do wildcard matching.
+.Pp
+.It Xo
.Ic ext-community Op Ar delete
.Ar subtype Ar as-number : Ns Ar local
.Xc
diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h
index 1531dac3bd9..87dd2d891b2 100644
--- a/usr.sbin/bgpd/bgpd.h
+++ b/usr.sbin/bgpd/bgpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bgpd.h,v 1.296 2016/10/05 07:38:06 phessler Exp $ */
+/* $OpenBSD: bgpd.h,v 1.297 2016/10/14 16:05:35 phessler Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -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];
diff --git a/usr.sbin/bgpd/control.c b/usr.sbin/bgpd/control.c
index 38fde685290..b65fed6406f 100644
--- a/usr.sbin/bgpd/control.c
+++ b/usr.sbin/bgpd/control.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: control.c,v 1.82 2015/12/05 18:28:04 benno Exp $ */
+/* $OpenBSD: control.c,v 1.83 2016/10/14 16:05:35 phessler Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -244,6 +244,7 @@ control_dispatch_msg(struct pollfd *pfd, u_int *ctl_cnt)
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, u_int *ctl_cnt)
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,
diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y
index 524ec1fa07a..f3f17d3ed8d 100644
--- a/usr.sbin/bgpd/parse.y
+++ b/usr.sbin/bgpd/parse.y
@@ -1,10 +1,12 @@
-/* $OpenBSD: parse.y,v 1.289 2016/10/05 07:38:06 phessler Exp $ */
+/* $OpenBSD: parse.y,v 1.290 2016/10/14 16:05:36 phessler Exp $ */
/*
* Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
* 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 <job@instituut.net>
+ * Copyright (c) 2016 Peter Hessler <phessler@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_types);
int getcommunity(char *);
int parsecommunity(struct filter_community *, char *);
+u_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},
@@ -2910,6 +2954,59 @@ parsecommunity(struct filter_community *c, char *s)
return (0);
}
+u_int
+getlargecommunity(char *s)
+{
+ u_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;
+ int64_t as, ld1, ld2;
+
+ if ((p = strchr(s, ':')) == NULL) {
+ yyerror("Bad community syntax");
+ return (-1);
+ }
+ *p++ = 0;
+
+ if ((q = strchr(p, ':')) == NULL) {
+ yyerror("Bad community syntax");
+ return (-1);
+ }
+ *q++ = 0;
+
+ if ((as = 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)
{
@@ -3527,6 +3624,10 @@ merge_filterset(struct filter_set_head *sh, struct filter_set *s)
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 *sh, struct filter_set *s)
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 */
diff --git a/usr.sbin/bgpd/printconf.c b/usr.sbin/bgpd/printconf.c
index a5f9d15443f..06a5e234d5e 100644
--- a/usr.sbin/bgpd/printconf.c
+++ b/usr.sbin/bgpd/printconf.c
@@ -1,7 +1,9 @@
-/* $OpenBSD: printconf.c,v 1.98 2016/10/05 07:38:06 phessler Exp $ */
+/* $OpenBSD: printconf.c,v 1.99 2016/10/14 16:05:36 phessler Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
+ * Copyright (c) 2016 Job Snijders <job@instituut.net>
+ * Copyright (c) 2016 Peter Hessler <phessler@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("%lld:", as);
+
+ if (ld1 == COMMUNITY_ANY)
+ printf("*:");
+ else if (ld1 == COMMUNITY_NEIGHBOR_AS)
+ printf("neighbor-as:");
+ else
+ printf("%lld:", ld1);
+
+ if (ld2 == COMMUNITY_ANY)
+ printf("* ");
+ else if (ld2 == COMMUNITY_NEIGHBOR_AS)
+ printf("neighbor-as ");
+ else
+ printf("%lld ", 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;
@@ -628,6 +672,12 @@ print_rule(struct peer *peer_l, struct filter_rule *r)
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);
diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c
index 53fd307816b..6b468104f41 100644
--- a/usr.sbin/bgpd/rde.c
+++ b/usr.sbin/bgpd/rde.c
@@ -1,7 +1,9 @@
-/* $OpenBSD: rde.c,v 1.350 2016/09/03 16:22:17 renato Exp $ */
+/* $OpenBSD: rde.c,v 1.351 2016/10/14 16:05:36 phessler Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
+ * Copyright (c) 2016 Job Snijders <job@instituut.net>
+ * Copyright (c) 2016 Peter Hessler <phessler@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 ctl_show_rib_request *req)
!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_request *req, pid_t pid,
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:
diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h
index 1ff890a1a0c..edb49c81eca 100644
--- a/usr.sbin/bgpd/rde.h
+++ b/usr.sbin/bgpd/rde.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.h,v 1.149 2015/11/06 16:23:26 phessler Exp $ */
+/* $OpenBSD: rde.h,v 1.150 2016/10/14 16:05:36 phessler Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
@@ -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 *, enum aslen_spec, u_int);
int community_match(struct rde_aspath *, int, int);
int community_set(struct rde_aspath *, int, int);
void community_delete(struct rde_aspath *, int, int);
+int community_large_match(struct rde_aspath *, int64_t, int64_t,
+ int64_t);
+int community_large_set(struct rde_aspath *, int64_t, int64_t,
+ int64_t);
+void community_large_delete(struct rde_aspath *, int64_t,
+ int64_t, int64_t);
int community_ext_match(struct rde_aspath *,
struct filter_extcommunity *, u_int16_t);
int community_ext_set(struct rde_aspath *,
diff --git a/usr.sbin/bgpd/rde_attr.c b/usr.sbin/bgpd/rde_attr.c
index 5aa4f02bb45..c629f9d34df 100644
--- a/usr.sbin/bgpd/rde_attr.c
+++ b/usr.sbin/bgpd/rde_attr.c
@@ -1,7 +1,9 @@
-/* $OpenBSD: rde_attr.c,v 1.95 2015/10/24 08:00:42 claudio Exp $ */
+/* $OpenBSD: rde_attr.c,v 1.96 2016/10/14 16:05:36 phessler Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
+ * Copyright (c) 2016 Job Snijders <job@instituut.net>
+ * Copyright (c) 2016 Peter Hessler <phessler@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
@@ -1352,3 +1354,147 @@ community_ext_matchone(struct filter_extcommunity *c, u_int16_t neighas,
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);
+}
diff --git a/usr.sbin/bgpd/rde_filter.c b/usr.sbin/bgpd/rde_filter.c
index 83a45d5a591..bd6be859d3c 100644
--- a/usr.sbin/bgpd/rde_filter.c
+++ b/usr.sbin/bgpd/rde_filter.c
@@ -1,7 +1,9 @@
-/* $OpenBSD: rde_filter.c,v 1.77 2016/06/03 17:36:37 benno Exp $ */
+/* $OpenBSD: rde_filter.c,v 1.78 2016/10/14 16:05:36 phessler Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
+ * Copyright (c) 2016 Job Snijders <job@instituut.net>
+ * Copyright (c) 2016 Peter Hessler <phessler@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
@@ -36,6 +38,7 @@ rde_apply_set(struct rde_aspath *asp, struct filter_set_head *sh,
struct filter_set *set;
u_char *np;
int as, type;
+ int64_t las, ld1, ld2;
u_int32_t prep_as;
u_int16_t nl;
u_int8_t prepend;
@@ -181,6 +184,84 @@ rde_apply_set(struct rde_aspath *asp, struct filter_set_head *sh,
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:
+ las = peer->conf.remote_as;
+ break;
+ case COMMUNITY_ANY:
+ default:
+ las = 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, las, 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:
+ las = peer->conf.remote_as;
+ break;
+ case COMMUNITY_ANY:
+ default:
+ las = 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, las, ld1, ld2);
+ break;
case ACTION_PFTABLE:
/* convert pftable name to an id */
set->action.id = pftable_name2id(set->action.pftable);
@@ -223,6 +304,7 @@ rde_filter_match(struct filter_rule *f, struct rde_aspath *asp,
{
u_int32_t pas;
int cas, type;
+ int64_t las, ld1, ld2;
if (asp != NULL && f->match.as.type != AS_NONE) {
if (f->match.as.flags & AS_FLAG_NEIGHBORAS)
@@ -270,6 +352,44 @@ rde_filter_match(struct filter_rule *f, struct rde_aspath *asp,
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:
+ las = peer->conf.remote_as;
+ break;
+ default:
+ las = 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, las, ld1, ld2) == 0)
+ return (0);
+ }
if (f->match.prefix.addr.aid != 0) {
if (f->match.prefix.addr.aid != prefix->aid)
@@ -547,6 +667,14 @@ filterset_equal(struct filter_set_head *ah, struct filter_set_head *bh)
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 +758,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");