summaryrefslogtreecommitdiff
path: root/usr.sbin/bgpd
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2018-09-07 05:43:34 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2018-09-07 05:43:34 +0000
commitae9a4d385acb942df3b17ec97f7295d2e6106b3f (patch)
treef1d04553a554f01060644a41855abaa31750bf79 /usr.sbin/bgpd
parent7f2f3f8766805f6ee2291486a2fc78de71fb68ed (diff)
Implement as-set a fast lookup table to be used instead of long list of
AS numbers in source-as, AS and transit-as filterstatements. These table use bsearch to quickly verify if an AS is in the set or not. The filter syntax is not fully set in stone yet. OK denis@ benno@ and previously OK deraadt@
Diffstat (limited to 'usr.sbin/bgpd')
-rw-r--r--usr.sbin/bgpd/Makefile4
-rw-r--r--usr.sbin/bgpd/bgpd.c8
-rw-r--r--usr.sbin/bgpd/bgpd.conf.534
-rw-r--r--usr.sbin/bgpd/bgpd.h52
-rw-r--r--usr.sbin/bgpd/config.c26
-rw-r--r--usr.sbin/bgpd/parse.y89
-rw-r--r--usr.sbin/bgpd/printconf.c8
-rw-r--r--usr.sbin/bgpd/rde.c60
-rw-r--r--usr.sbin/bgpd/rde.h4
-rw-r--r--usr.sbin/bgpd/rde_filter.c17
-rw-r--r--usr.sbin/bgpd/rde_sets.c239
-rw-r--r--usr.sbin/bgpd/util.c8
12 files changed, 497 insertions, 52 deletions
diff --git a/usr.sbin/bgpd/Makefile b/usr.sbin/bgpd/Makefile
index a2a5721d7fd..b57e53914f9 100644
--- a/usr.sbin/bgpd/Makefile
+++ b/usr.sbin/bgpd/Makefile
@@ -1,10 +1,10 @@
-# $OpenBSD: Makefile,v 1.32 2017/08/21 14:43:33 phessler Exp $
+# $OpenBSD: Makefile,v 1.33 2018/09/07 05:43:33 claudio Exp $
PROG= bgpd
SRCS= bgpd.c session.c log.c logmsg.c parse.y config.c \
rde.c rde_rib.c rde_decide.c rde_prefix.c mrt.c kroute.c \
control.c pfkey.c rde_update.c rde_attr.c printconf.c \
- rde_filter.c pftable.c name2id.c util.c carp.c timer.c
+ rde_filter.c rde_sets.c pftable.c name2id.c util.c carp.c timer.c
CFLAGS+= -Wall -I${.CURDIR}
CFLAGS+= -Wstrict-prototypes -Wmissing-prototypes
CFLAGS+= -Wmissing-declarations
diff --git a/usr.sbin/bgpd/bgpd.c b/usr.sbin/bgpd/bgpd.c
index 12a4e6a359c..894b3127052 100644
--- a/usr.sbin/bgpd/bgpd.c
+++ b/usr.sbin/bgpd/bgpd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: bgpd.c,v 1.194 2018/07/14 12:32:35 benno Exp $ */
+/* $OpenBSD: bgpd.c,v 1.195 2018/09/07 05:43:33 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -519,6 +519,12 @@ reconfigure(char *conffile, struct bgpd_config *conf, struct peer **peer_l)
free(ps);
}
+ /* as-sets for filters in the RDE */
+ if (as_sets_send(ibuf_rde, conf->as_sets) == -1)
+ return (-1);
+ as_sets_free(conf->as_sets);
+ conf->as_sets = NULL;
+
/* filters for the RDE */
while ((r = TAILQ_FIRST(conf->filters)) != NULL) {
TAILQ_REMOVE(conf->filters, r, entry);
diff --git a/usr.sbin/bgpd/bgpd.conf.5 b/usr.sbin/bgpd/bgpd.conf.5
index 9c0629004f1..106760ce568 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.171 2018/07/11 14:08:46 benno Exp $
+.\" $OpenBSD: bgpd.conf.5,v 1.172 2018/09/07 05:43:33 claudio 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: July 11 2018 $
+.Dd $Mdocdate: September 7 2018 $
.Dt BGPD.CONF 5
.Os
.Sh NAME
@@ -144,6 +144,20 @@ or as a large number (ASPLAIN format), for example:
AS 196618
.Ed
.Pp
+.Pp
+.It Xo
+.Ic as-set Ar name
+.Ic { Ar as-number ... Ic }
+.Xc
+An
+.Ic as-set
+holds a collection of AS numbers and can be used with the AS specific
+parameter in
+.Sx FILTER
+rules.
+Lookups against as-sets are more efficient than a large number of rules
+which differ only in the AS number.
+.Pp
.It Ic connect-retry Ar seconds
Set the number of seconds before retrying to open a connection.
This timer should be sufficiently large in EBGP configurations.
@@ -1111,21 +1125,25 @@ If a parameter is specified, the rule only applies to packets with
matching attributes.
.Pp
.Bl -tag -width Ds -compact
-.It Xo
+.It Xo
.Ar as-type Op Ar operator
.Ar as-number
.Xc
+.It Ar as-type Ic as-set Ar name
This rule applies only to
.Em UPDATES
where the
.Em AS path
matches.
The
-.Ar as-number
-is matched against a part of the
+part of the
.Em AS path
specified by the
-.Ar as-type :
+.Ar as-type
+is matched against the
+.Ar as-number
+or the
+.Ic as-set Ar name :
.Pp
.Bl -tag -width transmit-as -compact
.It Ic AS
@@ -1147,6 +1165,10 @@ which is expanded to the current neighbor remote AS number, or
.Ic local-as ,
which is expanded to the locally assigned AS number.
.Pp
+When specifying an
+.Ic as-set Ar name
+the AS path will instead be matched against all the AS numbers in the set.
+.Pp
The
.Ar operator
can be unspecified (this case is identical to the equality operator), or one of the numerical operators
diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h
index 56f9ffad1aa..91c9c8c2233 100644
--- a/usr.sbin/bgpd/bgpd.h
+++ b/usr.sbin/bgpd/bgpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bgpd.h,v 1.333 2018/09/05 09:49:57 claudio Exp $ */
+/* $OpenBSD: bgpd.h,v 1.334 2018/09/07 05:43:33 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -43,7 +43,7 @@
#define TCP_MD5_KEY_LEN 80
#define IPSEC_ENC_KEY_LEN 32
#define IPSEC_AUTH_KEY_LEN 20
-#define PREFIXSET_NAME_LEN 32
+#define SET_NAME_LEN 64
#define MAX_PKTSIZE 4096
#define MIN_HOLDTIME 3
@@ -213,6 +213,9 @@ TAILQ_HEAD(network_head, network);
struct prefixset;
SIMPLEQ_HEAD(prefixset_head, prefixset);
+struct as_set;
+SIMPLEQ_HEAD(as_set_head, as_set);
+
struct filter_rule;
TAILQ_HEAD(filter_head, filter_rule);
@@ -223,6 +226,7 @@ struct bgpd_config {
struct listen_addrs *listen_addrs;
struct mrt_head *mrt;
struct prefixset_head *prefixsets;
+ struct as_set_head *as_sets;
char *csock;
char *rcsock;
int flags;
@@ -404,8 +408,6 @@ enum imsg_type {
IMSG_NETWORK_FLUSH,
IMSG_NETWORK_DONE,
IMSG_FILTER_SET,
- IMSG_RECONF_PREFIXSET,
- IMSG_RECONF_PREFIXSETITEM,
IMSG_SOCKET_CONN,
IMSG_SOCKET_CONN_CTL,
IMSG_RECONF_CONF,
@@ -418,6 +420,11 @@ enum imsg_type {
IMSG_RECONF_RDOMAIN_EXPORT,
IMSG_RECONF_RDOMAIN_IMPORT,
IMSG_RECONF_RDOMAIN_DONE,
+ IMSG_RECONF_PREFIXSET,
+ IMSG_RECONF_PREFIXSETITEM,
+ IMSG_RECONF_AS_SET,
+ IMSG_RECONF_AS_SET_ITEMS,
+ IMSG_RECONF_AS_SET_DONE,
IMSG_RECONF_DONE,
IMSG_UPDATE,
IMSG_UPDATE_ERR,
@@ -648,12 +655,18 @@ enum aslen_spec {
ASLEN_SEQ
};
+#define AS_FLAG_NEIGHBORAS 0x01
+#define AS_FLAG_AS_SET_NAME 0x02
+#define AS_FLAG_AS_SET 0x04
+
struct filter_as {
- u_int16_t flags;
- enum as_spec type;
- u_int8_t op;
- u_int32_t as_min;
- u_int32_t as_max;
+ char name[SET_NAME_LEN];
+ struct as_set *aset;
+ u_int32_t as_min;
+ u_int32_t as_max;
+ enum as_spec type;
+ u_int8_t flags;
+ u_int8_t op;
};
struct filter_aslen {
@@ -666,12 +679,10 @@ struct filter_aslen {
struct filter_prefixset {
int flags;
- char name[PREFIXSET_NAME_LEN];
+ char name[SET_NAME_LEN];
struct prefixset *ps;
};
-#define AS_FLAG_NEIGHBORAS 0x01
-
struct filter_community {
int as;
int type;
@@ -942,7 +953,7 @@ SIMPLEQ_HEAD(prefixset_items_h, prefixset_item);
struct prefixset {
int sflags;
- char name[PREFIXSET_NAME_LEN];
+ char name[SET_NAME_LEN];
struct prefixset_items_h psitems;
SIMPLEQ_ENTRY(prefixset) entry;
};
@@ -1145,6 +1156,21 @@ void filterset_move(struct filter_set_head *,
struct filter_set_head *);
const char *filterset_name(enum action_types);
+/* rde_sets.c */
+void as_sets_insert(struct as_set_head *, struct as_set *);
+struct as_set *as_sets_lookup(struct as_set_head *, const char *);
+void as_sets_free(struct as_set_head *);
+void print_as_sets(struct as_set_head *);
+int as_sets_send(struct imsgbuf *, struct as_set_head *);
+void as_sets_mark_dirty(struct as_set_head *, struct as_set_head *);
+
+struct as_set *as_set_new(const char *, size_t);
+int as_set_add(struct as_set *, u_int32_t *, size_t);
+void as_set_prep(struct as_set *);
+int as_set_match(const struct as_set *, u_int32_t);
+int as_set_equal(const struct as_set *, const struct as_set *);
+int as_set_dirty(const struct as_set *);
+
/* util.c */
const char *log_addr(const struct bgpd_addr *);
const char *log_in6addr(const struct in6_addr *);
diff --git a/usr.sbin/bgpd/config.c b/usr.sbin/bgpd/config.c
index 73fa2b4b3bd..bf4752b7ba4 100644
--- a/usr.sbin/bgpd/config.c
+++ b/usr.sbin/bgpd/config.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: config.c,v 1.71 2018/09/04 10:48:39 claudio Exp $ */
+/* $OpenBSD: config.c,v 1.72 2018/09/07 05:43:33 claudio Exp $ */
/*
* Copyright (c) 2003, 2004, 2005 Henning Brauer <henning@openbsd.org>
@@ -67,6 +67,8 @@ new_config(void)
if ((conf->prefixsets = calloc(1, sizeof(struct prefixset_head)))
== NULL)
fatal(NULL);
+ if ((conf->as_sets = calloc(1, sizeof(struct as_set_head))) == NULL)
+ fatal(NULL);
if ((conf->filters = calloc(1, sizeof(struct filter_head))) == NULL)
fatal(NULL);
if ((conf->listen_addrs = calloc(1, sizeof(struct listen_addrs))) ==
@@ -79,6 +81,7 @@ new_config(void)
TAILQ_INIT(&conf->networks);
SIMPLEQ_INIT(&conf->rdomains);
SIMPLEQ_INIT(conf->prefixsets);
+ SIMPLEQ_INIT(conf->as_sets);
TAILQ_INIT(conf->filters);
TAILQ_INIT(conf->listen_addrs);
@@ -132,6 +135,7 @@ free_prefixsets(struct prefixset_head *psh)
SIMPLEQ_REMOVE_HEAD(psh, entry);
free(ps);
}
+ free(psh);
}
void
@@ -144,6 +148,7 @@ free_config(struct bgpd_config *conf)
free_networks(&conf->networks);
filterlist_free(conf->filters);
free_prefixsets(conf->prefixsets);
+ as_sets_free(conf->as_sets);
while ((la = TAILQ_FIRST(conf->listen_addrs)) != NULL) {
TAILQ_REMOVE(conf->listen_addrs, la, entry);
@@ -169,8 +174,6 @@ merge_config(struct bgpd_config *xconf, struct bgpd_config *conf,
{
struct listen_addr *nla, *ola, *next;
struct network *n;
- struct rdomain *rd;
- struct prefixset *ps;
/*
* merge the freshly parsed conf into the running xconf
@@ -220,10 +223,14 @@ merge_config(struct bgpd_config *xconf, struct bgpd_config *conf,
/* switch the prefixsets, first remove the old ones */
free_prefixsets(xconf->prefixsets);
- while ((ps = SIMPLEQ_FIRST(conf->prefixsets)) != NULL) {
- SIMPLEQ_REMOVE_HEAD(conf->prefixsets, entry);
- SIMPLEQ_INSERT_TAIL(xconf->prefixsets, ps, entry);
- }
+ xconf->prefixsets = conf->prefixsets;
+ conf->prefixsets = NULL;
+
+ /* switch the as_sets, first remove the old ones */
+ as_sets_free(xconf->as_sets);
+ xconf->as_sets = conf->as_sets;
+ conf->as_sets = NULL;
+
/* switch the network statements, but first remove the old ones */
free_networks(&xconf->networks);
while ((n = TAILQ_FIRST(&conf->networks)) != NULL) {
@@ -233,10 +240,7 @@ merge_config(struct bgpd_config *xconf, struct bgpd_config *conf,
/* switch the rdomain configs, first remove the old ones */
free_rdomains(&xconf->rdomains);
- while ((rd = SIMPLEQ_FIRST(&conf->rdomains)) != NULL) {
- SIMPLEQ_REMOVE_HEAD(&conf->rdomains, entry);
- SIMPLEQ_INSERT_TAIL(&xconf->rdomains, rd, entry);
- }
+ SIMPLEQ_CONCAT(&xconf->rdomains, &conf->rdomains);
/*
* merge new listeners:
diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y
index 7194e3f16e2..3554d6cada5 100644
--- a/usr.sbin/bgpd/parse.y
+++ b/usr.sbin/bgpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.333 2018/09/05 17:32:43 claudio Exp $ */
+/* $OpenBSD: parse.y,v 1.334 2018/09/07 05:43:33 claudio Exp $ */
/*
* Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -160,6 +160,9 @@ int parsesubtype(char *, int *, int *);
int parseextvalue(char *, u_int32_t *);
int parseextcommunity(struct filter_extcommunity *, char *,
char *);
+int asset_new(char *);
+void asset_add(u_int32_t);
+void asset_done(void);
typedef struct {
union {
@@ -207,9 +210,10 @@ typedef struct {
%token QUICK
%token FROM TO ANY
%token CONNECTED STATIC
-%token COMMUNITY EXTCOMMUNITY LARGECOMMUNITY
-%token PREFIX PREFIXLEN PREFIXSET SOURCEAS TRANSITAS PEERAS DELETE MAXASLEN
-%token MAXASSEQ SET LOCALPREF MED METRIC NEXTHOP REJECT BLACKHOLE NOMODIFY SELF
+%token COMMUNITY EXTCOMMUNITY LARGECOMMUNITY DELETE
+%token PREFIX PREFIXLEN PREFIXSET
+%token ASSET SOURCEAS TRANSITAS PEERAS MAXASLEN MAXASSEQ
+%token SET LOCALPREF MED METRIC NEXTHOP REJECT BLACKHOLE NOMODIFY SELF
%token PREPEND_SELF PREPEND_PEER PFTABLE WEIGHT RTLABEL ORIGIN PRIORITY
%token ERROR INCLUDE
%token IPSEC ESP AH SPI IKE
@@ -242,9 +246,10 @@ typedef struct {
grammar : /* empty */
| grammar '\n'
+ | grammar varset '\n'
| grammar include '\n'
+ | grammar asset '\n'
| grammar conf_main '\n'
- | grammar varset '\n'
| grammar rdomain '\n'
| grammar neighbor '\n'
| grammar group '\n'
@@ -396,6 +401,17 @@ include : INCLUDE STRING {
}
;
+asset : ASSET STRING '{' optnl {
+ if (asset_new($2) != 0)
+ YYERROR;
+ free($2);
+ } asset_l optnl '}' {
+ asset_done();
+ }
+
+asset_l : as4number { asset_add($1); }
+ | asset_l optnl as4number { asset_add($3); }
+
conf_main : AS as4number {
conf->as = $2;
if ($2 > USHRT_MAX)
@@ -1874,6 +1890,27 @@ filter_as_t : filter_as_type filter_as {
for (a = $$; a != NULL; a = a->next)
a->a.type = $1;
}
+ | filter_as_type ASSET STRING {
+ if (as_sets_lookup(conf->as_sets, $3) == NULL) {
+ yyerror("as-set \"%s\" not defined", $3);
+ free($3);
+ YYERROR;
+ }
+ if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
+ NULL)
+ fatal(NULL);
+ $$->a.type = $1;
+ $$->a.flags = AS_FLAG_AS_SET_NAME;
+ if (strlcpy($$->a.name, $3, sizeof($$->a.name)) >=
+ sizeof($$->a.name)) {
+ yyerror("as-set name \"%s\" too long: "
+ "max %zu", $3, sizeof($$->a.name) - 1);
+ free($3);
+ free($$);
+ YYERROR;
+ }
+ free($3);
+ }
;
filter_as_l_h : filter_as_l
@@ -1903,6 +1940,7 @@ filter_as : as4number_any {
NULL)
fatal(NULL);
$$->a.as_min = $1;
+ $$->a.as_max = $1;
$$->a.op = OP_EQ;
}
| NEIGHBORAS {
@@ -1917,6 +1955,7 @@ filter_as : as4number_any {
fatal(NULL);
$$->a.op = $1;
$$->a.as_min = $2;
+ $$->a.as_max = $2;
}
| as4number_any binaryop as4number_any {
if (($$ = calloc(1, sizeof(struct filter_as_l))) ==
@@ -2559,6 +2598,7 @@ lookup(char *s)
{ "announce", ANNOUNCE},
{ "any", ANY},
{ "as-4byte", AS4BYTE },
+ { "as-set", ASSET },
{ "blackhole", BLACKHOLE},
{ "capabilities", CAPABILITIES},
{ "community", COMMUNITY},
@@ -4099,3 +4139,42 @@ get_rule(enum action_types type)
}
return (r);
}
+
+struct as_set *curasset;
+int
+asset_new(char *name)
+{
+ struct as_set *aset;
+
+ if (curasset)
+ fatalx("%s: bad mojo jojo", __func__);
+
+ if (as_sets_lookup(conf->as_sets, name) != NULL) {
+ yyerror("as-set \"%s\" already exists", name);
+ return -1;
+ }
+
+ aset = as_set_new(name, 0);
+ if (aset == NULL)
+ fatal(NULL);
+ as_sets_insert(conf->as_sets, aset);
+
+ curasset = aset;
+ return 0;
+}
+
+void
+asset_add(u_int32_t as)
+{
+ if (curasset == NULL)
+ fatalx("%s: bad mojo jojo", __func__);
+
+ if (as_set_add(curasset, &as, 1) != 0)
+ fatal(NULL);
+}
+
+void
+asset_done(void)
+{
+ curasset = NULL;
+}
diff --git a/usr.sbin/bgpd/printconf.c b/usr.sbin/bgpd/printconf.c
index 0690679cac2..c116a3c3eea 100644
--- a/usr.sbin/bgpd/printconf.c
+++ b/usr.sbin/bgpd/printconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: printconf.c,v 1.111 2018/09/05 17:32:43 claudio Exp $ */
+/* $OpenBSD: printconf.c,v 1.112 2018/09/07 05:43:33 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -606,6 +606,10 @@ print_announce(struct peer_config *p, const char *c)
void print_as(struct filter_rule *r)
{
+ if (r->match.as.flags & AS_FLAG_AS_SET_NAME) {
+ printf("as-set \"%s\" ", r->match.as.name);
+ return;
+ }
switch(r->match.as.op) {
case OP_RANGE:
printf("%s - ", log_as(r->match.as.as_min));
@@ -862,7 +866,7 @@ print_config(struct bgpd_config *conf, struct rib_names *rib_l,
}
printf("\n");
print_prefixsets(conf->prefixsets);
- printf("\n");
+ print_as_sets(conf->as_sets);
print_mrt(conf, 0, 0, "", "");
printf("\n");
print_groups(conf, peer_l);
diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c
index 6b140783b9f..f7a077fb5fa 100644
--- a/usr.sbin/bgpd/rde.c
+++ b/usr.sbin/bgpd/rde.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.c,v 1.418 2018/09/05 09:49:57 claudio Exp $ */
+/* $OpenBSD: rde.c,v 1.419 2018/09/07 05:43:33 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -129,6 +129,7 @@ time_t reloadtime;
struct rde_peer_head peerlist;
struct rde_peer *peerself;
struct prefixset_head *prefixsets_tmp, *prefixsets_old;
+struct as_set_head *as_sets_tmp, *as_sets_old;
struct filter_head *out_rules, *out_rules_tmp;
struct rdomain_head *rdomains_l, *newdomains;
struct imsgbuf *ibuf_se;
@@ -687,6 +688,7 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf)
{
static struct rdomain *rd;
static struct prefixset *last_prefixset;
+ static struct as_set *last_as_set;
struct imsg imsg;
struct mrt xmrt;
struct rde_rib rn;
@@ -697,6 +699,8 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf)
struct rib *rib;
struct prefixset *ps;
struct prefixset_item *psi;
+ char *name;
+ size_t nmemb;
int n, fd;
u_int16_t rid;
@@ -769,6 +773,11 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf)
if (prefixsets_tmp == NULL)
fatal(NULL);
SIMPLEQ_INIT(prefixsets_tmp);
+ as_sets_tmp = calloc(1,
+ sizeof(struct as_set_head));
+ if (as_sets_tmp == NULL)
+ fatal(NULL);
+ SIMPLEQ_INIT(as_sets_tmp);
out_rules_tmp = calloc(1, sizeof(struct filter_head));
if (out_rules_tmp == NULL)
fatal(NULL);
@@ -822,8 +831,6 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf)
fatal(NULL);
memcpy(r, imsg.data, sizeof(struct filter_rule));
if (r->match.prefixset.flags != 0) {
- log_debug("%s: retrieving prefixset %s for "
- "rule", __func__, r->match.prefixset.name);
r->match.prefixset.ps =
find_prefixset(r->match.prefixset.name,
prefixsets_tmp);
@@ -831,6 +838,19 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf)
log_warnx("%s: no prefixset for %s",
__func__, r->match.prefixset.name);
}
+ if (r->match.as.flags & AS_FLAG_AS_SET_NAME) {
+ struct as_set * aset;
+
+ aset = as_sets_lookup(as_sets_tmp,
+ r->match.as.name);
+ if (aset == NULL) {
+ log_warnx("%s: no as-set for %s",
+ __func__, r->match.as.name);
+ } else {
+ r->match.as.flags = AS_FLAG_AS_SET;
+ r->match.as.aset = aset;
+ }
+ }
TAILQ_INIT(&r->set);
if ((rib = rib_find(r->rib)) == NULL) {
log_warnx("IMSG_RECONF_FILTER: filter rule "
@@ -879,6 +899,27 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf)
fatalx("King Bula has no prefixset");
SIMPLEQ_INSERT_TAIL(&last_prefixset->psitems, psi, entry);
break;
+ case IMSG_RECONF_AS_SET:
+ if (imsg.hdr.len - IMSG_HEADER_SIZE !=
+ sizeof(nmemb) + SET_NAME_LEN)
+ fatalx("IMSG_RECONF_AS_SET bad len");
+ memcpy(&nmemb, imsg.data, sizeof(nmemb));
+ name = (char *)imsg.data + sizeof(nmemb);
+ if (as_sets_lookup(as_sets_tmp, name) != NULL)
+ fatalx("duplicate as-set %s", name);
+ last_as_set = as_set_new(name, nmemb);
+ break;
+ case IMSG_RECONF_AS_SET_ITEMS:
+ nmemb = imsg.hdr.len - IMSG_HEADER_SIZE;
+ nmemb /= sizeof(u_int32_t);
+ if (as_set_add(last_as_set, imsg.data, nmemb) != 0)
+ fatal(NULL);
+ break;
+ case IMSG_RECONF_AS_SET_DONE:
+ as_set_prep(last_as_set);
+ as_sets_insert(as_sets_tmp, last_as_set);
+ last_as_set = NULL;
+ break;
case IMSG_RECONF_RDOMAIN:
if (imsg.hdr.len - IMSG_HEADER_SIZE !=
sizeof(struct rdomain))
@@ -2753,6 +2794,7 @@ rde_reload_done(void)
}
prefixsets_old = conf->prefixsets;
+ as_sets_old = conf->as_sets;
memcpy(conf, nconf, sizeof(struct bgpd_config));
conf->listen_addrs = NULL;
@@ -2782,9 +2824,14 @@ rde_reload_done(void)
/* XXX WHERE IS THE SYNC ??? */
rde_mark_prefixsets_dirty(prefixsets_old, prefixsets_tmp);
+ as_sets_mark_dirty(as_sets_old, as_sets_tmp);
+
/* swap the prefixsets */
conf->prefixsets = prefixsets_tmp;
prefixsets_tmp = NULL;
+ /* and the as_sets */
+ conf->as_sets = as_sets_tmp;
+ as_sets_tmp = NULL;
/*
* make the new filter rules the active one but keep the old for
@@ -2812,8 +2859,7 @@ rde_reload_done(void)
peer->reconf_rib = 1;
continue;
}
- if (!rde_filter_equal(out_rules, out_rules_tmp, peer,
- conf->prefixsets)) {
+ if (!rde_filter_equal(out_rules, out_rules_tmp, peer)) {
char *p = log_fmt_peer(&peer->conf);
log_debug("out filter change: reloading peer %s", p);
free(p);
@@ -2837,7 +2883,7 @@ rde_reload_done(void)
break;
case RECONF_KEEP:
if (rde_filter_equal(ribs[rid].in_rules,
- ribs[rid].in_rules_tmp, NULL, conf->prefixsets))
+ ribs[rid].in_rules_tmp, NULL))
/* rib is in sync */
break;
log_debug("in filter change: reloading RIB %s",
@@ -2974,6 +3020,8 @@ rde_softreconfig_done(void)
free_prefixsets(prefixsets_old);
prefixsets_old = NULL;
+ as_sets_free(as_sets_old);
+ as_sets_old = NULL;
log_info("RDE soft reconfiguration done");
imsg_compose(ibuf_main, IMSG_RECONF_DONE, 0, 0,
diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h
index 6049bdaa60f..f32c8b034ed 100644
--- a/usr.sbin/bgpd/rde.h
+++ b/usr.sbin/bgpd/rde.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.h,v 1.186 2018/08/08 13:08:54 claudio Exp $ */
+/* $OpenBSD: rde.h,v 1.187 2018/09/07 05:43:33 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
@@ -412,7 +412,7 @@ enum filter_actions rde_filter(struct filter_head *, struct rde_peer *,
void rde_apply_set(struct filter_set_head *, struct filterstate *,
u_int8_t, struct rde_peer *, struct rde_peer *);
int rde_filter_equal(struct filter_head *, struct filter_head *,
- struct rde_peer *, struct prefixset_head *);
+ struct rde_peer *);
void rde_filter_calc_skip_steps(struct filter_head *);
/* rde_prefix.c */
diff --git a/usr.sbin/bgpd/rde_filter.c b/usr.sbin/bgpd/rde_filter.c
index a314181ff26..3633e94b3ac 100644
--- a/usr.sbin/bgpd/rde_filter.c
+++ b/usr.sbin/bgpd/rde_filter.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_filter.c,v 1.101 2018/09/05 17:32:43 claudio Exp $ */
+/* $OpenBSD: rde_filter.c,v 1.102 2018/09/07 05:43:33 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -571,10 +571,11 @@ rde_filter_skip_rule(struct rde_peer *peer, struct filter_rule *f)
int
rde_filter_equal(struct filter_head *a, struct filter_head *b,
- struct rde_peer *peer, struct prefixset_head *psh)
+ struct rde_peer *peer)
{
struct filter_rule *fa, *fb;
struct prefixset *psa, *psb;
+ struct as_set *asa, *asb;
fa = a ? TAILQ_FIRST(a) : NULL;
fb = b ? TAILQ_FIRST(b) : NULL;
@@ -603,11 +604,16 @@ rde_filter_equal(struct filter_head *a, struct filter_head *b,
/* compare filter_rule.match without the prefixset pointer */
psa = fa->match.prefixset.ps;
psb = fb->match.prefixset.ps;
+ asa = fa->match.as.aset;
+ asb = fb->match.as.aset;
fa->match.prefixset.ps = fb->match.prefixset.ps = NULL;
+ fa->match.as.aset = fb->match.as.aset = NULL;
if (memcmp(&fa->match, &fb->match, sizeof(fa->match)))
return (0);
fa->match.prefixset.ps = psa;
fb->match.prefixset.ps = psb;
+ fa->match.as.aset = asa;
+ fb->match.as.aset = asb;
if ((fa->match.prefixset.flags != 0) &&
(fa->match.prefixset.ps != NULL) &&
@@ -618,6 +624,13 @@ rde_filter_equal(struct filter_head *a, struct filter_head *b,
return (0);
}
+ if ((fa->match.as.flags & AS_FLAG_AS_SET) &&
+ as_set_dirty(fa->match.as.aset)) {
+ log_debug("%s: as-set %s has changed",
+ __func__, fa->match.as.name);
+ return (0);
+ }
+
if (!filterset_equal(&fa->set, &fb->set))
return (0);
diff --git a/usr.sbin/bgpd/rde_sets.c b/usr.sbin/bgpd/rde_sets.c
new file mode 100644
index 00000000000..1d9e744ce50
--- /dev/null
+++ b/usr.sbin/bgpd/rde_sets.c
@@ -0,0 +1,239 @@
+/* $OpenBSD: rde_sets.c,v 1.1 2018/09/07 05:43:33 claudio Exp $ */
+
+/*
+ * Copyright (c) 2018 Claudio Jeker <claudio@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
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "rde.h"
+
+struct as_set {
+ char name[SET_NAME_LEN];
+ u_int32_t *set;
+ SIMPLEQ_ENTRY(as_set) entry;
+ size_t nmemb;
+ size_t max;
+ int dirty;
+};
+
+void
+as_sets_insert(struct as_set_head *as_sets, struct as_set *aset)
+{
+ SIMPLEQ_INSERT_TAIL(as_sets, aset, entry);
+}
+
+struct as_set *
+as_sets_lookup(struct as_set_head *as_sets, const char *name)
+{
+ struct as_set *aset;
+
+ SIMPLEQ_FOREACH(aset, as_sets, entry) {
+ if (strcmp(aset->name, name) == 0)
+ return aset;
+ }
+ return NULL;
+}
+
+static void
+as_set_free(struct as_set *aset)
+{
+ free(aset->set);
+ free(aset);
+}
+
+void
+as_sets_free(struct as_set_head *as_sets)
+{
+ struct as_set *aset;
+
+ if (as_sets == NULL)
+ return;
+ while (!SIMPLEQ_EMPTY(as_sets)) {
+ aset = SIMPLEQ_FIRST(as_sets);
+ SIMPLEQ_REMOVE_HEAD(as_sets, entry);
+ as_set_free(aset);
+ }
+ free(as_sets);
+}
+
+void
+print_as_sets(struct as_set_head *as_sets)
+{
+ struct as_set *aset;
+ size_t i;
+ int len = 0;;
+
+ if (as_sets == NULL)
+ return;
+ SIMPLEQ_FOREACH(aset, as_sets, entry) {
+ printf("as-set \"%s\" {", aset->name);
+ for (i = 0; i < aset->nmemb; i++) {
+ if (len == 0 || len > 72)
+ len = printf("\n\t");
+ len += printf("%u ", aset->set[i]);
+ }
+ printf("\n}\n\n");
+ }
+}
+
+int
+as_sets_send(struct imsgbuf *ibuf, struct as_set_head *as_sets)
+{
+ struct as_set *aset;
+ struct ibuf *wbuf;
+ size_t i, l;
+
+ if (as_sets == NULL)
+ return 0;
+ SIMPLEQ_FOREACH(aset, as_sets, entry) {
+ if ((wbuf = imsg_create(ibuf, IMSG_RECONF_AS_SET, 0, 0,
+ sizeof(aset->nmemb) + sizeof(aset->name))) == NULL)
+ return -1;
+ if (imsg_add(wbuf, &aset->nmemb, sizeof(aset->nmemb)) == -1 ||
+ imsg_add(wbuf, aset->name, sizeof(aset->name)) == -1)
+ return -1;
+ imsg_close(ibuf, wbuf);
+
+ for (i = 0; i < aset->nmemb; i += l) {
+ l = (aset->nmemb - i > 1024 ? 1024 : aset->nmemb - i);
+
+ if (imsg_compose(ibuf, IMSG_RECONF_AS_SET_ITEMS, 0, 0,
+ -1, aset->set + i, l * sizeof(*aset->set)) == -1)
+ return -1;
+ }
+
+ if (imsg_compose(ibuf, IMSG_RECONF_AS_SET_DONE, 0, 0, -1,
+ NULL, 0) == -1)
+ return -1;
+ }
+ return 0;
+}
+
+void
+as_sets_mark_dirty(struct as_set_head *old, struct as_set_head *new)
+{
+ struct as_set *n, *o;
+
+ SIMPLEQ_FOREACH(n, new, entry) {
+ if (old == NULL || (o = as_sets_lookup(old, n->name)) == NULL ||
+ !as_set_equal(n, o))
+ n->dirty = 1;
+ }
+}
+
+struct as_set *
+as_set_new(const char *name, size_t nmemb)
+{
+ struct as_set *aset;
+ size_t len;
+
+ aset = calloc(1, sizeof(*aset));
+ if (aset == NULL)
+ return NULL;
+
+ len = strlcpy(aset->name, name, sizeof(aset->name));
+ assert(len < sizeof(aset->name));
+
+ if (nmemb == 0)
+ nmemb = 16;
+
+ aset->max = nmemb;
+ aset->set = calloc(nmemb, sizeof(*aset->set));
+ if (aset->set == NULL) {
+ free(aset);
+ return NULL;
+ }
+
+ return aset;
+}
+
+int
+as_set_add(struct as_set *aset, u_int32_t *elms, size_t nelms)
+{
+ if (aset->max < nelms || aset->max - nelms < aset->nmemb) {
+ u_int32_t *s;
+ size_t new_size;
+
+ if (aset->nmemb >= SIZE_T_MAX - 4096 - nelms) {
+ errno = ENOMEM;
+ return -1;
+ }
+ for (new_size = aset->max; new_size < aset->nmemb + nelms; )
+ new_size += (new_size < 4096 ? new_size : 4096);
+
+ s = reallocarray(aset->set, new_size, sizeof(*aset->set));
+ if (s == NULL)
+ return -1;
+ aset->set = s;
+ aset->max = new_size;
+ }
+
+ memcpy(aset->set + aset->nmemb, elms, nelms * sizeof(*elms));
+ aset->nmemb += nelms;
+
+ return 0;
+}
+
+static int
+as_set_cmp(const void *ap, const void *bp)
+{
+ const u_int32_t *a = ap;
+ const u_int32_t *b = bp;
+
+ if (*a > *b)
+ return 1;
+ else if (*a < *b)
+ return -1;
+ return 0;
+}
+
+void
+as_set_prep(struct as_set *aset)
+{
+ qsort(aset->set, aset->nmemb, sizeof(*aset->set), as_set_cmp);
+}
+
+int
+as_set_match(const struct as_set *a, u_int32_t asnum)
+{
+ if (bsearch(&asnum, a->set, a->nmemb, sizeof(asnum), as_set_cmp))
+ return 1;
+ else
+ return 0;
+}
+
+int
+as_set_equal(const struct as_set *a, const struct as_set *b)
+{
+ if (a->nmemb != b->nmemb)
+ return 0;
+ if (memcmp(a->set, b->set, a->nmemb * sizeof(*a->set)) != 0)
+ return 0;
+ return 1;
+}
+
+int
+as_set_dirty(const struct as_set *a)
+{
+ return (a->dirty);
+}
diff --git a/usr.sbin/bgpd/util.c b/usr.sbin/bgpd/util.c
index 3fb491a2f70..e28e3c5d28a 100644
--- a/usr.sbin/bgpd/util.c
+++ b/usr.sbin/bgpd/util.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: util.c,v 1.33 2018/09/05 09:49:57 claudio Exp $ */
+/* $OpenBSD: util.c,v 1.34 2018/09/07 05:43:33 claudio Exp $ */
/*
* Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org>
@@ -317,6 +317,11 @@ as_compare(struct filter_as *f, u_int32_t as, u_int32_t neighas)
{
u_int32_t match;
+ if (f->flags & AS_FLAG_AS_SET_NAME) /* should not happen */
+ return (0);
+ if (f->flags & AS_FLAG_AS_SET)
+ return (as_set_match(f->aset, as));
+
if (f->flags & AS_FLAG_NEIGHBORAS)
match = neighas;
else
@@ -955,4 +960,3 @@ get_baudrate(u_int64_t baudrate, char *unit)
return (bbuf);
}
-