summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2004-11-23 13:07:02 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2004-11-23 13:07:02 +0000
commit3ecbd19bc3b00d71c40c04d62543e55cbef5df7e (patch)
treec4553ea4ef5dde0286f17884869a17d09fbf697a
parent9daf609d794b2746f640fc119c62a2d55b43344f (diff)
Switch from a single filter_set to a linked list of sets. With this change
it is possible to specify multiple communities. This is also the first step to better bgpd filters. OK henning@
-rw-r--r--usr.sbin/bgpd/bgpd.c32
-rw-r--r--usr.sbin/bgpd/bgpd.h64
-rw-r--r--usr.sbin/bgpd/control.c4
-rw-r--r--usr.sbin/bgpd/parse.y191
-rw-r--r--usr.sbin/bgpd/printconf.c63
-rw-r--r--usr.sbin/bgpd/rde.c82
-rw-r--r--usr.sbin/bgpd/rde.h9
-rw-r--r--usr.sbin/bgpd/rde_filter.c113
-rw-r--r--usr.sbin/bgpd/rde_rib.c17
-rw-r--r--usr.sbin/bgpd/session.c35
10 files changed, 428 insertions, 182 deletions
diff --git a/usr.sbin/bgpd/bgpd.c b/usr.sbin/bgpd/bgpd.c
index 05d4bcf5898..f761da13ede 100644
--- a/usr.sbin/bgpd/bgpd.c
+++ b/usr.sbin/bgpd/bgpd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: bgpd.c,v 1.110 2004/10/19 12:02:49 henning Exp $ */
+/* $OpenBSD: bgpd.c,v 1.111 2004/11/23 13:07:01 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -40,6 +40,7 @@ void sighdlr(int);
void usage(void);
int main(int, char *[]);
int check_child(pid_t, const char *);
+int send_filterset(struct imsgbuf *, struct filter_set_head *, int, int);
int reconfigure(char *, struct bgpd_config *, struct mrt_head *,
struct peer **, struct filter_head *);
int dispatch_imsg(struct imsgbuf *, int);
@@ -375,6 +376,25 @@ check_child(pid_t pid, const char *pname)
}
int
+send_filterset(struct imsgbuf *i, struct filter_set_head *set, int id, int f)
+{
+ struct filter_set *s;
+
+ for (s = SIMPLEQ_FIRST(set); s != NULL; ) {
+ if (imsg_compose(i, IMSG_FILTER_SET, id, 0, -1, s,
+ sizeof(struct filter_set)) == -1)
+ return (-1);
+ if (f) {
+ SIMPLEQ_REMOVE_HEAD(set, entry);
+ free(s);
+ s = SIMPLEQ_FIRST(set);
+ } else
+ s = SIMPLEQ_NEXT(s, entry);
+ }
+ return (0);
+}
+
+int
reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_head *mrt_l,
struct peer **peer_l, struct filter_head *rules_l)
{
@@ -398,14 +418,20 @@ reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_head *mrt_l,
if (imsg_compose(ibuf_rde, IMSG_RECONF_CONF, 0, 0, -1,
conf, sizeof(struct bgpd_config)) == -1)
return (-1);
- for (p = *peer_l; p != NULL; p = p->next)
+ for (p = *peer_l; p != NULL; p = p->next) {
if (imsg_compose(ibuf_se, IMSG_RECONF_PEER, p->conf.id, 0, -1,
&p->conf, sizeof(struct peer_config)) == -1)
return (-1);
+ if (send_filterset(ibuf_se, &p->conf.attrset,
+ p->conf.id, 0) == -1)
+ return (-1);
+ }
while ((n = TAILQ_FIRST(&net_l)) != NULL) {
if (imsg_compose(ibuf_rde, IMSG_NETWORK_ADD, 0, 0, -1,
&n->net, sizeof(struct network_config)) == -1)
return (-1);
+ if (send_filterset(ibuf_rde, &n->net.attrset, 0, 1) == -1)
+ return (-1);
TAILQ_REMOVE(&net_l, n, entry);
free(n);
}
@@ -413,6 +439,8 @@ reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_head *mrt_l,
if (imsg_compose(ibuf_rde, IMSG_RECONF_FILTER, 0, 0, -1,
r, sizeof(struct filter_rule)) == -1)
return (-1);
+ if (send_filterset(ibuf_rde, &r->set, 0, 1) == -1)
+ return (-1);
TAILQ_REMOVE(rules_l, r, entry);
free(r);
}
diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h
index 78705360cc8..90c4f9972ac 100644
--- a/usr.sbin/bgpd/bgpd.h
+++ b/usr.sbin/bgpd/bgpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bgpd.h,v 1.150 2004/11/19 14:43:56 claudio Exp $ */
+/* $OpenBSD: bgpd.h,v 1.151 2004/11/23 13:07:01 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -158,20 +158,6 @@ enum enforce_as {
ENFORCE_AS_ON
};
-struct filter_set {
- u_int16_t flags;
- u_int8_t prepend_self;
- u_int8_t prepend_peer;
- u_int32_t localpref;
- u_int32_t med;
- struct bgpd_addr nexthop;
- struct {
- int as;
- int type;
- } community;
- char pftable[PFTABLE_LEN];
-};
-
enum auth_method {
AUTH_NONE,
AUTH_MD5SIG,
@@ -207,6 +193,8 @@ struct capabilities {
u_int8_t refresh; /* route refresh, RFC 2918 */
};
+SIMPLEQ_HEAD(filter_set_head, filter_set);
+
struct peer_config {
u_int32_t id;
u_int32_t groupid;
@@ -224,7 +212,7 @@ struct peer_config {
u_int8_t passive;
u_int16_t holdtime;
u_int16_t min_holdtime;
- struct filter_set attrset;
+ struct filter_set_head attrset;
enum announce_type announce_type;
enum enforce_as enforce_as;
struct peer_auth auth;
@@ -238,7 +226,7 @@ struct peer_config {
struct network_config {
struct bgpd_addr prefix;
u_int8_t prefixlen;
- struct filter_set attrset;
+ struct filter_set_head attrset;
};
TAILQ_HEAD(network_head, network);
@@ -275,6 +263,7 @@ enum imsg_type {
IMSG_RECONF_DONE,
IMSG_UPDATE,
IMSG_UPDATE_ERR,
+ IMSG_SESSION_ADD,
IMSG_SESSION_UP,
IMSG_SESSION_DOWN,
IMSG_MRT_OPEN,
@@ -291,6 +280,8 @@ enum imsg_type {
IMSG_NETWORK_ADD,
IMSG_NETWORK_REMOVE,
IMSG_NETWORK_FLUSH,
+ IMSG_NETWORK_DONE,
+ IMSG_FILTER_SET,
IMSG_CTL_SHOW_NEIGHBOR,
IMSG_CTL_END,
IMSG_CTL_RELOAD,
@@ -403,7 +394,6 @@ struct session_up {
u_int32_t remote_bgpid;
struct bgpd_addr local_addr;
struct bgpd_addr remote_addr;
- struct peer_config conf;
struct capabilities capa_announced;
struct capabilities capa_received;
};
@@ -491,17 +481,6 @@ enum comp_ops {
OP_GT
};
-/* set flags */
-#define SET_LOCALPREF 0x0001
-#define SET_MED 0x0002
-#define SET_NEXTHOP 0x0004
-#define SET_PREPEND_SELF 0x0008
-#define SET_PREPEND_PEER 0x0010
-#define SET_PFTABLE 0x0020
-#define SET_COMMUNITY 0x0040
-#define SET_NEXTHOP_REJECT 0x0080
-#define SET_NEXTHOP_BLACKHOLE 0x0100
-
struct filter_peers {
u_int32_t peerid;
u_int32_t groupid;
@@ -549,7 +528,32 @@ struct filter_rule {
u_int8_t quick;
struct filter_peers peer;
struct filter_match match;
- struct filter_set set;
+ struct filter_set_head set;
+};
+
+enum action_types {
+ ACTION_SET_LOCALPREF,
+ ACTION_SET_MED,
+ ACTION_SET_PREPEND_SELF,
+ ACTION_SET_PREPEND_PEER,
+ ACTION_SET_NEXTHOP,
+ ACTION_SET_NEXTHOP_REJECT,
+ ACTION_SET_NEXTHOP_BLACKHOLE,
+ ACTION_SET_COMMUNITY,
+/* ACTION_SCRUB_COMMUNITY, */
+ ACTION_PFTABLE
+};
+
+struct filter_set {
+ SIMPLEQ_ENTRY(filter_set) entry;
+ enum action_types type;
+ union {
+ u_int8_t prepend;
+ u_int32_t metric;
+ struct bgpd_addr nexthop;
+ struct filter_community community;
+ char pftable[PFTABLE_LEN];
+ } action;
};
struct rrefresh {
diff --git a/usr.sbin/bgpd/control.c b/usr.sbin/bgpd/control.c
index 1058aae6a8c..55d365cbc81 100644
--- a/usr.sbin/bgpd/control.c
+++ b/usr.sbin/bgpd/control.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: control.c,v 1.38 2004/09/16 17:36:29 henning Exp $ */
+/* $OpenBSD: control.c,v 1.39 2004/11/23 13:07:01 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -287,6 +287,8 @@ control_dispatch_msg(struct pollfd *pfd, u_int *ctl_cnt)
case IMSG_NETWORK_ADD:
case IMSG_NETWORK_REMOVE:
case IMSG_NETWORK_FLUSH:
+ case IMSG_NETWORK_DONE:
+ case IMSG_FILTER_SET:
imsg_compose_rde(imsg.hdr.type, 0,
imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
break;
diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y
index ff2598518ed..1ea7b2f66bb 100644
--- a/usr.sbin/bgpd/parse.y
+++ b/usr.sbin/bgpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.147 2004/11/19 14:43:57 claudio Exp $ */
+/* $OpenBSD: parse.y,v 1.148 2004/11/23 13:07:01 claudio Exp $ */
/*
* Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -89,10 +89,12 @@ struct peer *new_group(void);
int add_mrtconfig(enum mrt_type, char *, time_t, struct peer *);
int get_id(struct peer *);
int expand_rule(struct filter_rule *, struct filter_peers_l *,
- struct filter_match_l *, struct filter_set *);
+ struct filter_match_l *, struct filter_set_head *);
int str2key(char *, char *, size_t);
int neighbor_consistent(struct peer *);
-int merge_filterset(struct filter_set *, struct filter_set *);
+int merge_filterset(struct filter_set_head *, struct filter_set *);
+void copy_filterset(struct filter_set_head *,
+ struct filter_set_head *);
TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead);
struct sym {
@@ -120,7 +122,8 @@ typedef struct {
struct filter_prefix_l *filter_prefix;
struct filter_as_l *filter_as;
struct filter_prefixlen prefixlen;
- struct filter_set filter_set;
+ struct filter_set *filter_set;
+ struct filter_set_head *filter_set_head;
struct {
struct bgpd_addr prefix;
u_int8_t len;
@@ -163,7 +166,8 @@ typedef struct {
%type <v.filter_as> filter_as filter_as_l filter_as_h
%type <v.filter_as> filter_as_t filter_as_t_l filter_as_l_h
%type <v.prefixlen> prefixlenop
-%type <v.filter_set> filter_set filter_set_l filter_set_opt
+%type <v.filter_set> filter_set_opt
+%type <v.filter_set_head> filter_set filter_set_l
%type <v.filter_prefix> filter_prefix filter_prefix_l
%type <v.filter_prefix> filter_prefix_h filter_prefix_m
%type <v.u8> unaryop binaryop filter_as_type
@@ -727,12 +731,19 @@ peeropts : REMOTEAS asnumber {
curpeer->conf.announce_capa = $3;
}
| SET filter_set_opt {
- if (merge_filterset(&curpeer->conf.attrset, &$2) == -1)
+ if (merge_filterset(&curpeer->conf.attrset, $2) == -1)
YYERROR;
}
| SET optnl "{" optnl filter_set_l optnl "}" {
- if (merge_filterset(&curpeer->conf.attrset, &$5) == -1)
+ struct filter_set *s;
+
+ while ((s = SIMPLEQ_FIRST($5)) != NULL) {
+ SIMPLEQ_REMOVE_HEAD($5, entry);
+ if (merge_filterset(&curpeer->conf.attrset, s)
+ == -1)
YYERROR;
+ }
+ free($5);
}
| mrtdump
| REFLECTOR {
@@ -831,7 +842,7 @@ filterrule : action quick direction filter_peer_h filter_match_h filter_set
r.quick = $2;
r.dir = $3;
- if (expand_rule(&r, $4, &$5, &$6) == -1)
+ if (expand_rule(&r, $4, &$5, $6) == -1)
YYERROR;
}
;
@@ -1086,69 +1097,99 @@ filter_as_type : AS { $$ = AS_ALL; }
| TRANSITAS { $$ = AS_TRANSIT; }
;
-filter_set : /* empty */ {
- bzero(&$$, sizeof($$));
+filter_set : /* empty */ { $$ = NULL; }
+ | SET filter_set_opt {
+ if (($$ = calloc(1, sizeof(struct filter_set_head))) ==
+ NULL)
+ fatal(NULL);
+ SIMPLEQ_INIT($$);
+ SIMPLEQ_INSERT_TAIL($$, $2, entry);
}
- | SET filter_set_opt { $$ = $2; }
| SET optnl "{" optnl filter_set_l optnl "}" { $$ = $5; }
;
filter_set_l : filter_set_l comma filter_set_opt {
$$ = $1;
- if (merge_filterset(&$$, &$3) == 1)
+ if (merge_filterset($$, $3) == 1)
YYERROR;
}
- | filter_set_opt
+ | filter_set_opt {
+ if (($$ = calloc(1, sizeof(struct filter_set_head))) ==
+ NULL)
+ fatal(NULL);
+ SIMPLEQ_INIT($$);
+ SIMPLEQ_INSERT_TAIL($$, $1, entry);
+ }
;
filter_set_opt : LOCALPREF number {
- $$.flags = SET_LOCALPREF;
- $$.localpref = $2;
+ if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
+ fatal(NULL);
+ $$->type = ACTION_SET_LOCALPREF;
+ $$->action.metric = $2;
}
| MED number {
- $$.flags = SET_MED;
- $$.med = $2;
+ if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
+ fatal(NULL);
+ $$->type = ACTION_SET_MED;
+ $$->action.metric = $2;
}
| METRIC number { /* alias for MED */
- $$.flags = SET_MED;
- $$.med = $2;
+ if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
+ fatal(NULL);
+ $$->type = ACTION_SET_MED;
+ $$->action.metric = $2;
}
| NEXTHOP address {
- $$.flags = SET_NEXTHOP;
- memcpy(&$$.nexthop, &$2, sizeof($$.nexthop));
+ if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
+ fatal(NULL);
+ $$->type = ACTION_SET_NEXTHOP;
+ memcpy(&$$->action.nexthop, &$2,
+ sizeof($$->action.nexthop));
}
| NEXTHOP BLACKHOLE {
- $$.flags = SET_NEXTHOP_BLACKHOLE;
+ if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
+ fatal(NULL);
+ $$->type = ACTION_SET_NEXTHOP_BLACKHOLE;
}
| NEXTHOP REJECT {
- $$.flags = SET_NEXTHOP_REJECT;
+ if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
+ fatal(NULL);
+ $$->type = ACTION_SET_NEXTHOP_REJECT;
}
| PREPEND_SELF number {
- $$.flags = SET_PREPEND_SELF;
+ if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
+ fatal(NULL);
+ $$->type = ACTION_SET_PREPEND_SELF;
if ($2 > 128) {
yyerror("to many prepends");
YYERROR;
}
- $$.prepend_self = $2;
+ $$->action.prepend = $2;
}
| PREPEND_PEER number {
- $$.flags = SET_PREPEND_PEER;
+ if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
+ fatal(NULL);
+ $$->type = ACTION_SET_PREPEND_PEER;
if ($2 > 128) {
yyerror("to many prepends");
YYERROR;
}
- $$.prepend_peer = $2;
+ $$->action.prepend = $2;
}
| PFTABLE string {
- $$.flags = SET_PFTABLE;
+ if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
+ fatal(NULL);
+ $$->type = ACTION_PFTABLE;
if (!(conf->opts & BGPD_OPT_NOACTION) &&
pftable_exists($2) != 0) {
yyerror("pftable name does not exist");
free($2);
YYERROR;
}
- if (strlcpy($$.pftable, $2, sizeof($$.pftable)) >=
- sizeof($$.pftable)) {
+ if (strlcpy($$->action.pftable, $2,
+ sizeof($$->action.pftable)) >=
+ sizeof($$->action.pftable)) {
yyerror("pftable name too long");
free($2);
YYERROR;
@@ -1161,20 +1202,23 @@ filter_set_opt : LOCALPREF number {
free($2);
}
| COMMUNITY STRING {
- $$.flags = SET_COMMUNITY;
- if (parsecommunity($2, &$$.community.as,
- &$$.community.type) == -1) {
+ if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
+ fatal(NULL);
+ $$->type = ACTION_SET_COMMUNITY;
+ if (parsecommunity($2, &$$->action.community.as,
+ &$$->action.community.type) == -1) {
free($2);
YYERROR;
}
free($2);
- if ($$.community.as <= 0 || $$.community.as > 0xffff) {
+ if ($$->action.community.as <= 0 ||
+ $$->action.community.as > 0xffff) {
yyerror("Invalid community");
YYERROR;
}
/* Don't allow setting of unknown well-known types */
- if ($$.community.as == COMMUNITY_WELLKNOWN) {
- switch ($$.community.type) {
+ if ($$->action.community.as == COMMUNITY_WELLKNOWN) {
+ switch ($$->action.community.type) {
case COMMUNITY_NO_EXPORT:
case COMMUNITY_NO_ADVERTISE:
case COMMUNITY_NO_EXPSUBCONFED:
@@ -1750,6 +1794,7 @@ alloc_peer(void)
p->conf.capabilities.mp_v4 = SAFI_UNICAST;
p->conf.capabilities.mp_v6 = SAFI_NONE;
p->conf.capabilities.refresh = 1;
+ SIMPLEQ_INIT(&p->conf.attrset);
return (p);
}
@@ -1757,7 +1802,7 @@ alloc_peer(void)
struct peer *
new_peer(void)
{
- struct peer *p;
+ struct peer *p;
p = alloc_peer();
@@ -1770,6 +1815,8 @@ new_peer(void)
sizeof(p->conf.descr)) >= sizeof(p->conf.descr))
fatalx("new_peer descr strlcpy");
p->conf.groupid = curgroup->conf.id;
+ SIMPLEQ_INIT(&p->conf.attrset);
+ copy_filterset(&curgroup->conf.attrset, &p->conf.attrset);
}
p->next = NULL;
@@ -1858,7 +1905,7 @@ get_id(struct peer *newpeer)
int
expand_rule(struct filter_rule *rule, struct filter_peers_l *peer,
- struct filter_match_l *match, struct filter_set *set)
+ struct filter_match_l *match, struct filter_set_head *set)
{
struct filter_rule *r;
struct filter_peers_l *p, *pnext;
@@ -1880,7 +1927,8 @@ expand_rule(struct filter_rule *rule, struct filter_peers_l *peer,
memcpy(r, rule, sizeof(struct filter_rule));
memcpy(&r->match, match,
sizeof(struct filter_match));
- memcpy(&r->set, set, sizeof(struct filter_set));
+ SIMPLEQ_INIT(&r->set);
+ copy_filterset(set, &r->set);
if (p != NULL)
memcpy(&r->peer, &p->p,
@@ -1990,30 +2038,49 @@ neighbor_consistent(struct peer *p)
}
int
-merge_filterset(struct filter_set *a, struct filter_set *b)
+merge_filterset(struct filter_set_head *sh, struct filter_set *s)
{
- if (a->flags & b->flags) {
- yyerror("redefining set parameters is not fluffy");
- return (-1);
- }
- a->flags |= b->flags;
- if (b->flags & SET_LOCALPREF)
- a->localpref = b->localpref;
- if (b->flags & SET_MED)
- a->med = b->med;
- if (b->flags & SET_NEXTHOP)
- memcpy(&a->nexthop, &b->nexthop,
- sizeof(a->nexthop));
- if (b->flags & SET_PREPEND_SELF)
- a->prepend_self = b->prepend_self;
- if (b->flags & SET_PREPEND_PEER)
- a->prepend_peer = b->prepend_peer;
- if (b->flags & SET_PFTABLE)
- strlcpy(a->pftable, b->pftable,
- sizeof(a->pftable));
- if (b->flags & SET_COMMUNITY) {
- a->community.as = b->community.as;
- a->community.type = b->community.type;
+ struct filter_set *t;
+
+ SIMPLEQ_FOREACH(t, sh, entry) {
+ if (s->type != t->type)
+ continue;
+
+ switch (s->type) {
+ case ACTION_SET_COMMUNITY:
+ if (s->action.community.as == t->action.community.as &&
+ s->action.community.type ==
+ t->action.community.type) {
+ yyerror("community is already set");
+ return (-1);
+ }
+ break;
+ case ACTION_SET_NEXTHOP:
+ if (s->action.nexthop.af != t->action.nexthop.af)
+ break;
+ /* FALLTHROUGH */
+ default:
+ yyerror("redefining set parameters is not fluffy");
+ return (-1);
+ }
}
+ SIMPLEQ_INSERT_TAIL(sh, s, entry);
return (0);
}
+
+
+void
+copy_filterset(struct filter_set_head *source, struct filter_set_head *dest)
+{
+ struct filter_set *s, *t;
+
+ if (source == NULL)
+ return;
+
+ SIMPLEQ_FOREACH(s, source, entry) {
+ if ((t = calloc(1, sizeof(struct filter_set))) == NULL)
+ fatal(NULL);
+ memcpy(t, s, sizeof(struct filter_set));
+ SIMPLEQ_INSERT_TAIL(dest, t, entry);
+ }
+}
diff --git a/usr.sbin/bgpd/printconf.c b/usr.sbin/bgpd/printconf.c
index 564ed3e004b..7672002984c 100644
--- a/usr.sbin/bgpd/printconf.c
+++ b/usr.sbin/bgpd/printconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: printconf.c,v 1.34 2004/11/18 17:07:38 henning Exp $ */
+/* $OpenBSD: printconf.c,v 1.35 2004/11/23 13:07:01 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -25,7 +25,7 @@
#include "session.h"
void print_op(enum comp_ops);
-void print_set(struct filter_set *);
+void print_set(struct filter_set_head *);
void print_mainconf(struct bgpd_config *);
void print_network(struct network_config *);
void print_peer(struct peer_config *, struct bgpd_config *,
@@ -73,26 +73,47 @@ print_op(enum comp_ops op)
}
void
-print_set(struct filter_set *set)
+print_set(struct filter_set_head *set)
{
- if (set->flags) {
- printf("set { ");
- if (set->flags & SET_LOCALPREF)
- printf("localpref %u ", set->localpref);
- if (set->flags & SET_MED)
- printf("med %u ", set->med);
- if (set->flags & SET_NEXTHOP)
- printf("nexthop %s ", log_addr(&set->nexthop));
- if (set->flags & SET_NEXTHOP_REJECT)
+ struct filter_set *s;
+
+ if (SIMPLEQ_EMPTY(set))
+ return;
+
+ printf("set { ");
+ SIMPLEQ_FOREACH(s, set, entry) {
+ switch (s->type) {
+ case ACTION_SET_LOCALPREF:
+ printf("localpref %u ", s->action.metric);
+ break;
+ case ACTION_SET_MED:
+ printf("metric %u ", s->action.metric);
+ break;
+ case ACTION_SET_NEXTHOP:
+ printf("nexthop %s ", log_addr(&s->action.nexthop));
+ break;
+ case ACTION_SET_NEXTHOP_REJECT:
printf("nexthop reject ");
- if (set->flags & SET_NEXTHOP_BLACKHOLE)
+ break;
+ case ACTION_SET_NEXTHOP_BLACKHOLE:
printf("nexthop blackhole ");
- if (set->flags & SET_PREPEND_SELF)
- printf("prepend-self %u ", set->prepend_self);
- if (set->flags & SET_PREPEND_PEER)
- printf("prepend-neighbor %u ", set->prepend_peer);
- printf("}");
+ break;
+ case ACTION_SET_PREPEND_SELF:
+ printf("prepend-self %u ", s->action.prepend);
+ break;
+ case ACTION_SET_PREPEND_PEER:
+ printf("prepend-neighbor %u ", s->action.prepend);
+ break;
+ case ACTION_SET_COMMUNITY:
+ printf("community %u:%u ", s->action.community.as,
+ s->action.community.type);
+ break;
+ case ACTION_PFTABLE:
+ printf("pftable %s ", s->action.pftable);
+ break;
+ }
}
+ printf("}");
}
void
@@ -132,7 +153,7 @@ void
print_network(struct network_config *n)
{
printf("network %s/%u", log_addr(&n->prefix), n->prefixlen);
- if (n->attrset.flags)
+ if (!SIMPLEQ_EMPTY(&n->attrset))
printf(" ");
print_set(&n->attrset);
printf("\n");
@@ -220,10 +241,10 @@ print_peer(struct peer_config *p, struct bgpd_config *conf, const char *c)
else if (p->auth.method == AUTH_IPSEC_IKE_ESP)
printf("%s\tipsec esp ike\n", c);
- if (p->attrset.flags)
+ if (!SIMPLEQ_EMPTY(&p->attrset))
printf("%s\t", c);
print_set(&p->attrset);
- if (p->attrset.flags)
+ if (!SIMPLEQ_EMPTY(&p->attrset))
printf("\n");
print_mrt(p->id, p->groupid, c, "\t");
diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c
index 5a051ae19cc..0a2944fe6e8 100644
--- a/usr.sbin/bgpd/rde.c
+++ b/usr.sbin/bgpd/rde.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.c,v 1.152 2004/11/19 14:43:57 claudio Exp $ */
+/* $OpenBSD: rde.c,v 1.153 2004/11/23 13:07:01 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -267,14 +267,19 @@ rde_main(struct bgpd_config *config, struct peer *peer_l,
_exit(0);
}
+struct network_config netconf_s, netconf_p;
+struct filter_set_head *session_set, *parent_set;
+
void
rde_dispatch_imsg_session(struct imsgbuf *ibuf)
{
struct imsg imsg;
- struct session_up sup;
struct peer p;
+ struct peer_config pconf;
struct rrefresh r;
struct rde_peer *peer;
+ struct session_up sup;
+ struct filter_set *s;
pid_t pid;
int n;
@@ -293,11 +298,24 @@ rde_dispatch_imsg_session(struct imsgbuf *ibuf)
case IMSG_UPDATE:
rde_update_dispatch(&imsg);
break;
+ case IMSG_SESSION_ADD:
+ if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(pconf))
+ fatalx("incorrect size of session request");
+ memcpy(&pconf, imsg.data, sizeof(pconf));
+ peer = peer_add(imsg.hdr.peerid, &pconf);
+ if (peer == NULL) {
+ log_warnx("peer_up: peer id %d already exists",
+ imsg.hdr.peerid);
+ break;
+ }
+ session_set = &peer->conf.attrset;
+ break;
case IMSG_SESSION_UP:
if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(sup))
fatalx("incorrect size of session request");
memcpy(&sup, imsg.data, sizeof(sup));
peer_up(imsg.hdr.peerid, &sup);
+ session_set = NULL;
break;
case IMSG_SESSION_DOWN:
peer_down(imsg.hdr.peerid);
@@ -316,7 +334,17 @@ rde_dispatch_imsg_session(struct imsgbuf *ibuf)
log_warnx("rde_dispatch: wrong imsg len");
break;
}
- network_add(imsg.data, 0);
+ memcpy(&netconf_s, imsg.data, sizeof(netconf_s));
+ SIMPLEQ_INIT(&netconf_s.attrset);
+ session_set = &netconf_s.attrset;
+ break;
+ case IMSG_NETWORK_DONE:
+ if (imsg.hdr.len != IMSG_HEADER_SIZE) {
+ log_warnx("rde_dispatch: wrong imsg len");
+ break;
+ }
+ session_set = NULL;
+ network_add(&netconf_s, 0);
break;
case IMSG_NETWORK_REMOVE:
if (imsg.hdr.len - IMSG_HEADER_SIZE !=
@@ -324,7 +352,9 @@ rde_dispatch_imsg_session(struct imsgbuf *ibuf)
log_warnx("rde_dispatch: wrong imsg len");
break;
}
- network_delete(imsg.data, 0);
+ memcpy(&netconf_s, imsg.data, sizeof(netconf_s));
+ SIMPLEQ_INIT(&netconf_s.attrset);
+ network_delete(&netconf_s, 0);
break;
case IMSG_NETWORK_FLUSH:
if (imsg.hdr.len != IMSG_HEADER_SIZE) {
@@ -333,6 +363,22 @@ rde_dispatch_imsg_session(struct imsgbuf *ibuf)
}
network_flush(0);
break;
+ case IMSG_FILTER_SET:
+ if (imsg.hdr.len - IMSG_HEADER_SIZE !=
+ sizeof(struct filter_set)) {
+ log_warnx("rde_dispatch: wrong imsg len");
+ break;
+ }
+ if (session_set == NULL) {
+ log_warnx("rde_dispatch: "
+ "IMSG_FILTER_SET unexpected");
+ break;
+ }
+ if ((s = malloc(sizeof(struct filter_set))) == NULL)
+ fatal(NULL);
+ memcpy(s, imsg.data, sizeof(struct filter_set));
+ SIMPLEQ_INSERT_TAIL(session_set, s, entry);
+ break;
case IMSG_CTL_SHOW_NETWORK:
if (imsg.hdr.len != IMSG_HEADER_SIZE) {
log_warnx("rde_dispatch: wrong imsg len");
@@ -404,6 +450,7 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf)
{
struct imsg imsg;
struct filter_rule *r;
+ struct filter_set *s;
struct mrt *xmrt;
int n;
@@ -431,7 +478,13 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf)
memcpy(nconf, imsg.data, sizeof(struct bgpd_config));
break;
case IMSG_NETWORK_ADD:
- network_add(imsg.data, 1);
+ memcpy(&netconf_p, imsg.data, sizeof(netconf_p));
+ SIMPLEQ_INIT(&netconf_p.attrset);
+ parent_set = &netconf_p.attrset;
+ break;
+ case IMSG_NETWORK_DONE:
+ parent_set = NULL;
+ network_add(&netconf_p, 1);
break;
case IMSG_RECONF_FILTER:
if (imsg.hdr.len - IMSG_HEADER_SIZE !=
@@ -440,6 +493,8 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf)
if ((r = malloc(sizeof(struct filter_rule))) == NULL)
fatal(NULL);
memcpy(r, imsg.data, sizeof(struct filter_rule));
+ SIMPLEQ_INIT(&r->set);
+ parent_set = &r->set;
TAILQ_INSERT_TAIL(newrules, r, entry);
break;
case IMSG_RECONF_DONE:
@@ -457,6 +512,7 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf)
memcpy(conf, nconf, sizeof(struct bgpd_config));
free(nconf);
nconf = NULL;
+ parent_set = NULL;
prefix_network_clean(&peerself, reloadtime);
while ((r = TAILQ_FIRST(rules_l)) != NULL) {
TAILQ_REMOVE(rules_l, r, entry);
@@ -469,6 +525,17 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf)
case IMSG_NEXTHOP_UPDATE:
nexthop_update(imsg.data);
break;
+ case IMSG_FILTER_SET:
+ if (parent_set == NULL) {
+ log_warnx("rde_dispatch: "
+ "IMSG_FILTER_SET unexpected");
+ break;
+ }
+ if ((s = malloc(sizeof(struct filter_set))) == NULL)
+ fatal(NULL);
+ memcpy(s, imsg.data, sizeof(struct filter_set));
+ SIMPLEQ_INSERT_TAIL(parent_set, s, entry);
+ break;
case IMSG_MRT_OPEN:
case IMSG_MRT_REOPEN:
if (imsg.hdr.len > IMSG_HEADER_SIZE +
@@ -1819,6 +1886,7 @@ peer_add(u_int32_t id, struct peer_config *p_conf)
LIST_INIT(&peer->path_h);
memcpy(&peer->conf, p_conf, sizeof(struct peer_config));
+ SIMPLEQ_INIT(&peer->conf.attrset);
peer->remote_bgpid = 0;
peer->state = PEER_NONE;
up_init(peer);
@@ -1837,6 +1905,7 @@ peer_remove(struct rde_peer *peer)
LIST_REMOVE(peer, hash_l);
LIST_REMOVE(peer, peer_l);
+ rde_free_set(&peer->conf.attrset);
free(peer);
}
@@ -1907,7 +1976,7 @@ peer_up(u_int32_t id, struct session_up *sup)
{
struct rde_peer *peer;
- peer = peer_add(id, &sup->conf);
+ peer = peer_get(id);
if (peer == NULL) {
log_warnx("peer_up: peer id %d already exists", id);
return;
@@ -2038,6 +2107,7 @@ network_add(struct network_config *nc, int flagstatic)
DIR_DEFAULT_IN);
path_update(&peerdynamic, asp, &nc->prefix, nc->prefixlen);
}
+ rde_free_set(&nc->attrset);
}
void
diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h
index c8d0fc813f0..5d5c8470660 100644
--- a/usr.sbin/bgpd/rde.h
+++ b/usr.sbin/bgpd/rde.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.h,v 1.60 2004/11/11 13:06:45 claudio Exp $ */
+/* $OpenBSD: rde.h,v 1.61 2004/11/23 13:07:01 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
@@ -311,8 +311,8 @@ void prefix_network_clean(struct rde_peer *, time_t);
void nexthop_init(u_int32_t);
void nexthop_shutdown(void);
-void nexthop_modify(struct rde_aspath *, struct bgpd_addr *, int,
- sa_family_t);
+void nexthop_modify(struct rde_aspath *, struct bgpd_addr *,
+ enum action_types, sa_family_t);
void nexthop_link(struct rde_aspath *);
void nexthop_unlink(struct rde_aspath *);
void nexthop_update(struct kroute_nexthop *);
@@ -346,7 +346,8 @@ void pt_dump(void (*)(struct pt_entry *, void *), void *,
/* rde_filter.c */
enum filter_actions rde_filter(struct rde_peer *, struct rde_aspath *,
struct bgpd_addr *, u_int8_t, enum directions);
-void rde_apply_set(struct rde_aspath *, struct filter_set *,
+void rde_free_set(struct filter_set_head *);
+void rde_apply_set(struct rde_aspath *, struct filter_set_head *,
sa_family_t, struct rde_peer *, enum directions);
int rde_filter_community(struct rde_aspath *, int, int);
diff --git a/usr.sbin/bgpd/rde_filter.c b/usr.sbin/bgpd/rde_filter.c
index e29c53de664..ce37a4f3009 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.21 2004/10/08 16:36:42 claudio Exp $ */
+/* $OpenBSD: rde_filter.c,v 1.22 2004/11/23 13:07:01 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -18,6 +18,7 @@
#include <sys/types.h>
#include <sys/queue.h>
+#include <stdlib.h>
#include <string.h>
#include "bgpd.h"
@@ -58,61 +59,83 @@ rde_filter(struct rde_peer *peer, struct rde_aspath *asp,
}
void
-rde_apply_set(struct rde_aspath *asp, struct filter_set *set, sa_family_t af,
- struct rde_peer *peer, enum directions dir)
+rde_free_set(struct filter_set_head *sh)
{
- struct aspath *new;
- u_int16_t as;
- u_int8_t prepend;
+ struct filter_set *set;
+
+ while ((set = SIMPLEQ_FIRST(sh)) != NULL) {
+ SIMPLEQ_REMOVE_HEAD(sh, entry);
+ free(set);
+ }
+}
+
+void
+rde_apply_set(struct rde_aspath *asp, struct filter_set_head *sh,
+ sa_family_t af, struct rde_peer *peer, enum directions dir)
+{
+ struct filter_set *set;
+ struct aspath *new;
+ struct attr *a;
+ u_int16_t as;
+ u_int8_t prepend;
if (asp == NULL)
return;
- if (set->flags & SET_PREPEND_SELF && dir != DIR_DEFAULT_IN) {
- /* don't apply if this is a incoming default override */
- as = rde_local_as();
- prepend = set->prepend_self;
- new = aspath_prepend(asp->aspath, as, prepend);
- aspath_put(asp->aspath);
- asp->aspath = new;
- }
-
- if (dir == DIR_DEFAULT_OUT)
+ SIMPLEQ_FOREACH(set, sh, entry) {
/*
* default outgoing overrides are only allowed to
* set prepend-self
*/
- return;
-
- if (set->flags & SET_PREPEND_PEER) {
- as = peer->conf.remote_as;
- prepend = set->prepend_peer;
- new = aspath_prepend(asp->aspath, as, prepend);
- aspath_put(asp->aspath);
- asp->aspath = new;
- }
-
- if (set->flags & SET_LOCALPREF)
- asp->lpref = set->localpref;
- if (set->flags & SET_MED) {
- asp->flags |= F_ATTR_MED | F_ATTR_MED_ANNOUNCE;
- asp->med = set->med;
- }
-
- nexthop_modify(asp, &set->nexthop, set->flags, af);
-
- if (set->flags & SET_PFTABLE)
- strlcpy(asp->pftable, set->pftable, sizeof(asp->pftable));
- if (set->flags & SET_COMMUNITY) {
- struct attr *a;
+ if (dir == DIR_DEFAULT_OUT &&
+ set->type != ACTION_SET_PREPEND_SELF)
+ continue;
- if ((a = attr_optget(asp, ATTR_COMMUNITIES)) == NULL) {
- attr_optadd(asp, ATTR_OPTIONAL|ATTR_TRANSITIVE,
- ATTR_COMMUNITIES, NULL, 0);
- if ((a = attr_optget(asp, ATTR_COMMUNITIES)) == NULL)
- fatalx("internal community bug");
+ switch (set->type) {
+ case ACTION_SET_LOCALPREF:
+ asp->lpref = set->action.metric;
+ case ACTION_SET_MED:
+ asp->flags |= F_ATTR_MED | F_ATTR_MED_ANNOUNCE;
+ asp->med = set->action.metric;
+ case ACTION_SET_PREPEND_SELF:
+ /* don't apply if this is a incoming default override */
+ if (dir == DIR_DEFAULT_IN)
+ break;
+ as = rde_local_as();
+ prepend = set->action.prepend;
+ new = aspath_prepend(asp->aspath, as, prepend);
+ aspath_put(asp->aspath);
+ asp->aspath = new;
+ break;
+ case ACTION_SET_PREPEND_PEER:
+ as = peer->conf.remote_as;
+ prepend = set->action.prepend;
+ new = aspath_prepend(asp->aspath, as, prepend);
+ aspath_put(asp->aspath);
+ asp->aspath = new;
+ break;
+ case ACTION_SET_NEXTHOP:
+ case ACTION_SET_NEXTHOP_REJECT:
+ case ACTION_SET_NEXTHOP_BLACKHOLE:
+ nexthop_modify(asp, &set->action.nexthop, set->type,
+ af);
+ break;
+ case ACTION_SET_COMMUNITY:
+ if ((a = attr_optget(asp, ATTR_COMMUNITIES)) == NULL) {
+ attr_optadd(asp, ATTR_OPTIONAL|ATTR_TRANSITIVE,
+ ATTR_COMMUNITIES, NULL, 0);
+ if ((a = attr_optget(asp,
+ ATTR_COMMUNITIES)) == NULL)
+ fatalx("internal community bug");
+ }
+ community_set(a, set->action.community.as,
+ set->action.community.type);
+ break;
+ case ACTION_PFTABLE:
+ strlcpy(asp->pftable, set->action.pftable,
+ sizeof(asp->pftable));
+ break;
}
- community_set(a, set->community.as, set->community.type);
}
}
diff --git a/usr.sbin/bgpd/rde_rib.c b/usr.sbin/bgpd/rde_rib.c
index f39e7b3eafc..5e9dbc4830f 100644
--- a/usr.sbin/bgpd/rde_rib.c
+++ b/usr.sbin/bgpd/rde_rib.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_rib.c,v 1.62 2004/11/19 09:59:27 claudio Exp $ */
+/* $OpenBSD: rde_rib.c,v 1.63 2004/11/23 13:07:01 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
@@ -749,17 +749,20 @@ nexthop_update(struct kroute_nexthop *msg)
}
void
-nexthop_modify(struct rde_aspath *asp, struct bgpd_addr *nexthop, int flags,
- sa_family_t af)
+nexthop_modify(struct rde_aspath *asp, struct bgpd_addr *nexthop,
+ enum action_types type, sa_family_t af)
{
struct nexthop *nh;
- if (flags & SET_NEXTHOP_REJECT)
+ if (type == ACTION_SET_NEXTHOP_REJECT) {
asp->flags |= F_NEXTHOP_REJECT;
- if (flags & SET_NEXTHOP_BLACKHOLE)
+ return;
+ }
+ if (type == ACTION_SET_NEXTHOP_BLACKHOLE) {
asp->flags |= F_NEXTHOP_BLACKHOLE;
- if (!(flags & SET_NEXTHOP) ||
- af != nexthop->af)
+ return;
+ }
+ if (af != nexthop->af)
return;
nh = nexthop_get(nexthop);
diff --git a/usr.sbin/bgpd/session.c b/usr.sbin/bgpd/session.c
index 0035524c91d..80a6ad2ba67 100644
--- a/usr.sbin/bgpd/session.c
+++ b/usr.sbin/bgpd/session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.c,v 1.207 2004/11/18 17:17:56 henning Exp $ */
+/* $OpenBSD: session.c,v 1.208 2004/11/23 13:07:01 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -2040,6 +2040,8 @@ parse_capabilities(struct peer *peer, u_char *d, u_int16_t dlen)
return (0);
}
+struct filter_set_head *session_set;
+
void
session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt)
{
@@ -2050,6 +2052,7 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt)
struct peer *p, *next;
struct listen_addr *la, *nla;
struct kif *kif;
+ struct filter_set *s;
u_char *data;
enum reconf_action reconf;
int n, depend_ok;
@@ -2101,6 +2104,8 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt)
reconf = RECONF_KEEP;
memcpy(&p->conf, pconf, sizeof(struct peer_config));
+ SIMPLEQ_INIT(&p->conf.attrset);
+ session_set = &p->conf.attrset;
p->conf.reconf_action = reconf;
break;
case IMSG_RECONF_LISTENER:
@@ -2189,9 +2194,22 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt)
free(nconf->listen_addrs);
free(nconf);
nconf = NULL;
+ session_set = NULL;
pending_reconf = 0;
log_info("SE reconfigured");
break;
+ case IMSG_FILTER_SET:
+ if (idx != PFD_PIPE_MAIN)
+ fatalx("reconf request not from parent");
+ if (session_set == NULL) {
+ log_warnx("IMSG_FILTER_SET unexpected");
+ break;
+ }
+ if ((s = malloc(sizeof(struct filter_set))) == NULL)
+ fatal(NULL);
+ memcpy(s, imsg.data, sizeof(struct filter_set));
+ SIMPLEQ_INSERT_TAIL(session_set, s, entry);
+ break;
case IMSG_IFINFO:
if (idx != PFD_PIPE_MAIN)
fatalx("IFINFO message not from parent");
@@ -2499,9 +2517,18 @@ session_down(struct peer *peer)
void
session_up(struct peer *p)
{
- struct session_up sup;
+ struct session_up sup;
+ struct filter_set *s;
- sup.remote_bgpid = p->remote_bgpid;
+ if (imsg_compose(ibuf_rde, IMSG_SESSION_ADD, p->conf.id, 0, -1,
+ &p->conf, sizeof(p->conf)) == -1)
+ fatalx("imsg_compose error");
+
+ SIMPLEQ_FOREACH(s, &p->conf.attrset, entry) {
+ if (imsg_compose(ibuf_rde, IMSG_FILTER_SET, p->conf.id, 0, -1,
+ s, sizeof(struct filter_set)) == -1)
+ fatalx("imsg_compose error");
+ }
switch (p->sa_local.ss_family) {
case AF_INET:
@@ -2528,7 +2555,7 @@ session_up(struct peer *p)
fatalx("session_up: unsupported address family");
}
- memcpy(&sup.conf, &p->conf, sizeof(sup.conf));
+ sup.remote_bgpid = p->remote_bgpid;
memcpy(&sup.capa_announced, &p->capa.ann, sizeof(sup.capa_announced));
memcpy(&sup.capa_received, &p->capa.peer, sizeof(sup.capa_received));
p->stats.last_updown = time(NULL);