diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2004-11-23 13:07:02 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2004-11-23 13:07:02 +0000 |
commit | 3ecbd19bc3b00d71c40c04d62543e55cbef5df7e (patch) | |
tree | c4553ea4ef5dde0286f17884869a17d09fbf697a | |
parent | 9daf609d794b2746f640fc119c62a2d55b43344f (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.c | 32 | ||||
-rw-r--r-- | usr.sbin/bgpd/bgpd.h | 64 | ||||
-rw-r--r-- | usr.sbin/bgpd/control.c | 4 | ||||
-rw-r--r-- | usr.sbin/bgpd/parse.y | 191 | ||||
-rw-r--r-- | usr.sbin/bgpd/printconf.c | 63 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde.c | 82 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde.h | 9 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde_filter.c | 113 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde_rib.c | 17 | ||||
-rw-r--r-- | usr.sbin/bgpd/session.c | 35 |
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); |