-# $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
-/* $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>
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);
-.\" $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>
.\" 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
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.
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
.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
-/* $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>
#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
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);
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;
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,
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,
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 {
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;
struct prefixset {
int sflags;
- char name[PREFIXSET_NAME_LEN];
+ char name[SET_NAME_LEN];
struct prefixset_items_h psitems;
SIMPLEQ_ENTRY(prefixset) entry;
};
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 *);
-/* $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>
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))) ==
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);
SIMPLEQ_REMOVE_HEAD(psh, entry);
free(ps);
}
+ free(psh);
}
void
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);
{
struct listen_addr *nla, *ola, *next;
struct network *n;
- struct rdomain *rd;
- struct prefixset *ps;
/*
* merge the freshly parsed conf into the running xconf
/* 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) {
/* 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:
-/* $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>
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 {
%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
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'
}
;
+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)
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
NULL)
fatal(NULL);
$$->a.as_min = $1;
+ $$->a.as_max = $1;
$$->a.op = OP_EQ;
}
| NEIGHBORAS {
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))) ==
{ "announce", ANNOUNCE},
{ "any", ANY},
{ "as-4byte", AS4BYTE },
+ { "as-set", ASSET },
{ "blackhole", BLACKHOLE},
{ "capabilities", CAPABILITIES},
{ "community", COMMUNITY},
}
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;
+}
-/* $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>
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));
}
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);
-/* $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>
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;
{
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;
struct rib *rib;
struct prefixset *ps;
struct prefixset_item *psi;
+ char *name;
+ size_t nmemb;
int n, fd;
u_int16_t rid;
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);
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);
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 "
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))
}
prefixsets_old = conf->prefixsets;
+ as_sets_old = conf->as_sets;
memcpy(conf, nconf, sizeof(struct bgpd_config));
conf->listen_addrs = NULL;
/* 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
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);
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",
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,
-/* $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
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 */
-/* $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>
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;
/* 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) &&
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);
--- /dev/null
+/* $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);
+}
-/* $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>
{
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
return (bbuf);
}
-