diff options
author | 2019-03-31 16:57:38 +0000 | |
---|---|---|
committer | 2019-03-31 16:57:38 +0000 | |
commit | 82fc6237928a854e2841e7ebcf3e3e13fffb60a7 (patch) | |
tree | 79b557fe161bfc5bd499e9679cef3ca41c96185e | |
parent | Update Jewish holiday dates for this year. While here, add Tu B'Shevat. (diff) | |
download | wireguard-openbsd-82fc6237928a854e2841e7ebcf3e3e13fffb60a7.tar.xz wireguard-openbsd-82fc6237928a854e2841e7ebcf3e3e13fffb60a7.zip |
Move the struct peer into bgpd_config and switch it to a TAILQ instead of
the hand-rolled list. This changes the way peers are reloaded since now
both parent and session engine are now merging the lists.
OK denis@
-rw-r--r-- | usr.sbin/bgpd/bgpd.c | 33 | ||||
-rw-r--r-- | usr.sbin/bgpd/bgpd.h | 7 | ||||
-rw-r--r-- | usr.sbin/bgpd/config.c | 33 | ||||
-rw-r--r-- | usr.sbin/bgpd/control.c | 21 | ||||
-rw-r--r-- | usr.sbin/bgpd/parse.y | 107 | ||||
-rw-r--r-- | usr.sbin/bgpd/printconf.c | 43 | ||||
-rw-r--r-- | usr.sbin/bgpd/session.c | 220 | ||||
-rw-r--r-- | usr.sbin/bgpd/session.h | 24 |
8 files changed, 238 insertions, 250 deletions
diff --git a/usr.sbin/bgpd/bgpd.c b/usr.sbin/bgpd/bgpd.c index a198a4f30a9..6aecc7b7fd5 100644 --- a/usr.sbin/bgpd/bgpd.c +++ b/usr.sbin/bgpd/bgpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.c,v 1.214 2019/03/31 03:36:18 yasuoka Exp $ */ +/* $OpenBSD: bgpd.c,v 1.215 2019/03/31 16:57:38 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -43,7 +43,7 @@ __dead void usage(void); int main(int, char *[]); pid_t start_child(enum bgpd_process, char *, int, int, int); int send_filterset(struct imsgbuf *, struct filter_set_head *); -int reconfigure(char *, struct bgpd_config *, struct peer **); +int reconfigure(char *, struct bgpd_config *); int dispatch_imsg(struct imsgbuf *, int, struct bgpd_config *); int control_setup(struct bgpd_config *); int imsg_send_sockets(struct imsgbuf *, struct imsgbuf *); @@ -100,7 +100,6 @@ int main(int argc, char *argv[]) { struct bgpd_config *conf; - struct peer *peer_l, *p; struct rde_rib *rr; struct pollfd pfd[POLL_MAX]; time_t timeout; @@ -125,8 +124,6 @@ main(int argc, char *argv[]) if (saved_argv0 == NULL) saved_argv0 = "bgpd"; - peer_l = NULL; - while ((ch = getopt(argc, argv, "cdD:f:nRSv")) != -1) { switch (ch) { case 'c': @@ -169,20 +166,14 @@ main(int argc, char *argv[]) usage(); if (cmd_opts & BGPD_OPT_NOACTION) { - conf = new_config(); - if (parse_config(conffile, conf, &peer_l)) + if ((conf = parse_config(conffile, NULL)) == NULL) exit(1); if (cmd_opts & BGPD_OPT_VERBOSE) - print_config(conf, &ribnames, &conf->networks, peer_l, - conf->filters, conf->mrt, &conf->l3vpns); + print_config(conf, &ribnames); else fprintf(stderr, "configuration OK\n"); - while ((p = peer_l) != NULL) { - peer_l = p->next; - free(p); - } while ((rr = SIMPLEQ_FIRST(&ribnames)) != NULL) { SIMPLEQ_REMOVE_HEAD(&ribnames, entry); free(rr); @@ -261,7 +252,7 @@ BROKEN if (pledge("stdio rpath wpath cpath fattr unix route recvfd sendfd", if (imsg_send_sockets(ibuf_se, ibuf_rde)) fatal("could not establish imsg links"); conf = new_config(); - quit = reconfigure(conffile, conf, &peer_l); + quit = reconfigure(conffile, conf); if (pftable_clear_all() != 0) quit = 1; @@ -317,7 +308,7 @@ BROKEN if (pledge("stdio rpath wpath cpath fattr unix route recvfd sendfd", u_int error; reconfig = 0; - switch (reconfigure(conffile, conf, &peer_l)) { + switch (reconfigure(conffile, conf)) { case -1: /* fatal error */ quit = 1; break; @@ -358,10 +349,6 @@ BROKEN if (pledge("stdio rpath wpath cpath fattr unix route recvfd sendfd", ibuf_rde = NULL; } - while ((p = peer_l) != NULL) { - peer_l = p->next; - free(p); - } while ((rr = SIMPLEQ_FIRST(&ribnames)) != NULL) { SIMPLEQ_REMOVE_HEAD(&ribnames, entry); free(rr); @@ -454,8 +441,9 @@ send_filterset(struct imsgbuf *i, struct filter_set_head *set) } int -reconfigure(char *conffile, struct bgpd_config *conf, struct peer **peer_l) +reconfigure(char *conffile, struct bgpd_config *conf) { + struct bgpd_config *new_conf; struct peer *p; struct filter_rule *r; struct listen_addr *la; @@ -472,12 +460,13 @@ reconfigure(char *conffile, struct bgpd_config *conf, struct peer **peer_l) reconfpending = 2; /* one per child */ log_info("rereading config"); - if (parse_config(conffile, conf, peer_l)) { + if ((new_conf = parse_config(conffile, &conf->peers)) == NULL) { log_warnx("config file %s has errors, not reloading", conffile); reconfpending = 0; return (1); } + merge_config(conf, new_conf); if (prepare_listeners(conf) == -1) { reconfpending = 0; @@ -527,7 +516,7 @@ reconfigure(char *conffile, struct bgpd_config *conf, struct peer **peer_l) } /* send peer list to the SE */ - for (p = *peer_l; p != NULL; p = p->next) { + TAILQ_FOREACH(p, &conf->peers, entry) { if (imsg_compose(ibuf_se, IMSG_RECONF_PEER, p->conf.id, 0, -1, &p->conf, sizeof(struct peer_config)) == -1) return (-1); diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h index a8480fbf88a..0909afe3b71 100644 --- a/usr.sbin/bgpd/bgpd.h +++ b/usr.sbin/bgpd/bgpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.h,v 1.377 2019/03/07 07:42:36 claudio Exp $ */ +/* $OpenBSD: bgpd.h,v 1.378 2019/03/31 16:57:38 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -231,6 +231,9 @@ struct listen_addr { TAILQ_HEAD(listen_addrs, listen_addr); TAILQ_HEAD(filter_set_head, filter_set); +struct peer; +TAILQ_HEAD(peer_head, peer); + struct l3vpn; SIMPLEQ_HEAD(l3vpn_head, l3vpn); @@ -267,6 +270,7 @@ struct filter_rule; TAILQ_HEAD(filter_head, filter_rule); struct bgpd_config { + struct peer_head peers; struct l3vpn_head l3vpns; struct network_head networks; struct filter_head *filters; @@ -376,7 +380,6 @@ struct peer_config { enum export_type export_type; enum enforce_as enforce_as; enum enforce_as enforce_local_as; - enum reconf_action reconf_action; u_int16_t max_prefix_restart; u_int16_t holdtime; u_int16_t min_holdtime; diff --git a/usr.sbin/bgpd/config.c b/usr.sbin/bgpd/config.c index e3a9a93fe61..f263fa6e202 100644 --- a/usr.sbin/bgpd/config.c +++ b/usr.sbin/bgpd/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.86 2019/03/15 09:54:54 claudio Exp $ */ +/* $OpenBSD: config.c,v 1.87 2019/03/31 16:57:38 claudio Exp $ */ /* * Copyright (c) 2003, 2004, 2005 Henning Brauer <henning@openbsd.org> @@ -54,6 +54,7 @@ new_config(void) fatal(NULL); /* init the various list for later */ + TAILQ_INIT(&conf->peers); TAILQ_INIT(&conf->networks); SIMPLEQ_INIT(&conf->l3vpns); SIMPLEQ_INIT(&conf->prefixsets); @@ -156,6 +157,7 @@ free_prefixtree(struct prefixset_tree *p) void free_config(struct bgpd_config *conf) { + struct peer *p; struct listen_addr *la; struct mrt *m; @@ -181,6 +183,11 @@ free_config(struct bgpd_config *conf) } free(conf->mrt); + while ((p = TAILQ_FIRST(&conf->peers)) != NULL) { + TAILQ_REMOVE(&conf->peers, p, entry); + free(p); + } + free(conf->csock); free(conf->rcsock); @@ -188,11 +195,11 @@ free_config(struct bgpd_config *conf) } void -merge_config(struct bgpd_config *xconf, struct bgpd_config *conf, - struct peer *peer_l) +merge_config(struct bgpd_config *xconf, struct bgpd_config *conf) { struct listen_addr *nla, *ola, *next; struct network *n; + struct peer *p, *np; /* * merge the freshly parsed conf into the running xconf @@ -299,6 +306,26 @@ merge_config(struct bgpd_config *xconf, struct bgpd_config *conf, } } + /* + * merge peers: + * - need to know which peers are new, replaced and removed + * - first mark all new peers as RECONF_REINIT + * - walk over old peers and check if there is a corresponding new + * peer if so mark it RECONF_KEEP. Remove all old peers. + * - swap lists (old peer list is actually empty). + */ + TAILQ_FOREACH(p, &conf->peers, entry) + p->reconf_action = RECONF_REINIT; + while ((p = TAILQ_FIRST(&xconf->peers)) != NULL) { + np = getpeerbyid(conf, p->conf.id); + if (np != NULL) + np->reconf_action = RECONF_KEEP; + + TAILQ_REMOVE(&xconf->peers, p, entry); + free(p); + } + TAILQ_CONCAT(&xconf->peers, &conf->peers, entry); + /* conf is merged so free it */ free_config(conf); } diff --git a/usr.sbin/bgpd/control.c b/usr.sbin/bgpd/control.c index f856ee5187c..b6684e9bfe4 100644 --- a/usr.sbin/bgpd/control.c +++ b/usr.sbin/bgpd/control.c @@ -1,4 +1,4 @@ -/* $OpenBSD: control.c,v 1.95 2019/02/12 13:30:39 claudio Exp $ */ +/* $OpenBSD: control.c,v 1.96 2019/03/31 16:57:38 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -220,7 +220,8 @@ control_close(int fd) } int -control_dispatch_msg(struct pollfd *pfd, u_int *ctl_cnt) +control_dispatch_msg(struct pollfd *pfd, u_int *ctl_cnt, + struct peer_head *peers) { struct imsg imsg; struct ctl_conn *c; @@ -294,7 +295,7 @@ control_dispatch_msg(struct pollfd *pfd, u_int *ctl_cnt) 0, NULL, 0); break; case IMSG_CTL_SHOW_TERSE: - for (p = peers; p != NULL; p = p->next) + TAILQ_FOREACH(p, peers, entry) imsg_compose(&c->ibuf, IMSG_CTL_SHOW_NEIGHBOR, 0, 0, -1, p, sizeof(struct peer)); imsg_compose(&c->ibuf, IMSG_CTL_END, 0, 0, -1, NULL, 0); @@ -309,7 +310,8 @@ control_dispatch_msg(struct pollfd *pfd, u_int *ctl_cnt) } else { neighbor = NULL; } - for (matched = 0, p = peers; p != NULL; p = p->next) { + matched = 0; + TAILQ_FOREACH(p, peers, entry) { if (!peer_matched(p, neighbor)) continue; @@ -337,7 +339,7 @@ control_dispatch_msg(struct pollfd *pfd, u_int *ctl_cnt) } } } - if (!matched && peers != NULL) { + if (!matched && TAILQ_EMPTY(peers)) { control_result(c, CTL_RES_NOSUCHPEER); } else if (!neighbor || !neighbor->show_timers) { imsg_ctl_rde(IMSG_CTL_END, imsg.hdr.pid, @@ -362,7 +364,8 @@ control_dispatch_msg(struct pollfd *pfd, u_int *ctl_cnt) neighbor = imsg.data; neighbor->descr[PEER_DESCR_LEN - 1] = 0; - for (matched = 0, p = peers; p != NULL; p = p->next) { + matched = 0; + TAILQ_FOREACH(p, peers, entry) { if (!peer_matched(p, neighbor)) continue; @@ -417,7 +420,7 @@ control_dispatch_msg(struct pollfd *pfd, u_int *ctl_cnt) * Mark as deleted, will be * collected on next poll loop. */ - p->conf.reconf_action = + p->reconf_action = RECONF_DELETE; control_result(c, CTL_RES_OK); } @@ -458,10 +461,10 @@ control_dispatch_msg(struct pollfd *pfd, u_int *ctl_cnt) neighbor->descr[PEER_DESCR_LEN - 1] = 0; /* check if at least one neighbor exists */ - for (p = peers; p != NULL; p = p->next) + TAILQ_FOREACH(p, peers, entry) if (peer_matched(p, neighbor)) break; - if (p == NULL && peers != NULL) { + if (p == NULL && TAILQ_EMPTY(peers)) { control_result(c, CTL_RES_NOSUCHPEER); break; } diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y index a0bca769d66..3ce72c061e9 100644 --- a/usr.sbin/bgpd/parse.y +++ b/usr.sbin/bgpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.384 2019/03/15 09:54:54 claudio Exp $ */ +/* $OpenBSD: parse.y,v 1.385 2019/03/31 16:57:38 claudio Exp $ */ /* * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -88,7 +88,7 @@ char *symget(const char *); static struct bgpd_config *conf; static struct network_head *netconf; -static struct peer *peer_l, *peer_l_old; +static struct peer_head *new_peers, *cur_peers; static struct peer *curpeer; static struct peer *curgroup; static struct l3vpn *curvpn; @@ -99,7 +99,6 @@ static struct filter_head *peerfilter_l; static struct filter_head *groupfilter_l; static struct filter_rule *curpeer_filter[2]; static struct filter_rule *curgroup_filter[2]; -static u_int32_t id; struct filter_rib_l { struct filter_rib_l *next; @@ -1203,8 +1202,7 @@ neighbor : { curpeer = new_peer(); } if (neighbor_consistent(curpeer) == -1) YYERROR; - curpeer->next = peer_l; - peer_l = curpeer; + TAILQ_INSERT_TAIL(new_peers, curpeer, entry); curpeer = curgroup; } ; @@ -1812,7 +1810,7 @@ filter_peer : ANY { fatal(NULL); $$->p.remote_as = $$->p.groupid = $$->p.peerid = 0; $$->next = NULL; - for (p = peer_l; p != NULL; p = p->next) + TAILQ_FOREACH(p, new_peers, entry) if (!memcmp(&p->conf.remote_addr, &$1, sizeof(p->conf.remote_addr))) { $$->p.peerid = p->conf.id; @@ -1839,7 +1837,7 @@ filter_peer : ANY { fatal(NULL); $$->p.remote_as = $$->p.peerid = 0; $$->next = NULL; - for (p = peer_l; p != NULL; p = p->next) + TAILQ_FOREACH(p, new_peers, entry) if (!strcmp(p->conf.group, $2)) { $$->p.groupid = p->conf.groupid; break; @@ -3263,11 +3261,10 @@ init_config(struct bgpd_config *c) fatal(NULL); } -int -parse_config(char *filename, struct bgpd_config *xconf, struct peer **xpeers) +struct bgpd_config * +parse_config(char *filename, struct peer_head *ph) { struct sym *sym, *next; - struct peer *p, *pnext; struct rde_rib *rr; struct network *n; int errors = 0; @@ -3285,12 +3282,11 @@ parse_config(char *filename, struct bgpd_config *xconf, struct peer **xpeers) TAILQ_INIT(peerfilter_l); TAILQ_INIT(groupfilter_l); - peer_l = NULL; - peer_l_old = *xpeers; curpeer = NULL; curgroup = NULL; - id = 1; + cur_peers = ph; + new_peers = &conf->peers; netconf = &conf->networks; add_rib("Adj-RIB-In", conf->default_tableid, @@ -3334,13 +3330,15 @@ parse_config(char *filename, struct bgpd_config *xconf, struct peer **xpeers) errors++; } + /* clear the globals */ + curpeer = NULL; + curgroup = NULL; + cur_peers = NULL; + new_peers = NULL; + netconf = NULL; + if (errors) { errors: - for (p = peer_l; p != NULL; p = pnext) { - pnext = p->next; - free(p); - } - while ((rr = SIMPLEQ_FIRST(&ribnames)) != NULL) { SIMPLEQ_REMOVE_HEAD(&ribnames, entry); free(rr); @@ -3351,7 +3349,7 @@ errors: filterlist_free(groupfilter_l); free_config(conf); - return -1; + return (NULL); } else { /* * Concatenate filter list and static group and peer filtersets @@ -3364,18 +3362,11 @@ errors: optimize_filters(conf->filters); - merge_config(xconf, conf, peer_l); - *xpeers = peer_l; - - for (p = peer_l_old; p != NULL; p = pnext) { - pnext = p->next; - free(p); - } - free(filter_l); free(peerfilter_l); free(groupfilter_l); - return 0; + + return (conf); } } @@ -3784,7 +3775,6 @@ alloc_peer(void) /* some sane defaults */ p->state = STATE_NONE; - p->next = NULL; p->conf.distance = 1; p->conf.export_type = EXPORT_UNSET; p->conf.announce_capa = 1; @@ -3796,6 +3786,9 @@ alloc_peer(void) p->conf.local_as = conf->as; p->conf.local_short_as = conf->short_as; + if (conf->flags & BGPD_FLAG_DECISION_TRANS_AS) + p->conf.flags |= PEERFLAG_TRANS_AS; + return (p); } @@ -3818,9 +3811,6 @@ new_peer(void) p->conf.local_as = curgroup->conf.local_as; p->conf.local_short_as = curgroup->conf.local_short_as; } - p->next = NULL; - if (conf->flags & BGPD_FLAG_DECISION_TRANS_AS) - p->conf.flags |= PEERFLAG_TRANS_AS; return (p); } @@ -3962,34 +3952,41 @@ find_prefixset(char *name, struct prefixset_head *p) int get_id(struct peer *newpeer) { - struct peer *p; - - for (p = peer_l_old; p != NULL; p = p->next) - if (newpeer->conf.remote_addr.aid) { - if (!memcmp(&p->conf.remote_addr, - &newpeer->conf.remote_addr, - sizeof(p->conf.remote_addr))) { - newpeer->conf.id = p->conf.id; - return (0); - } - } else { /* newpeer is a group */ - if (strcmp(newpeer->conf.group, p->conf.group) == 0) { - newpeer->conf.id = p->conf.groupid; - return (0); - } + static u_int32_t id = 1; + struct peer *p = NULL; + + /* check if the peer already existed before */ + if (newpeer->conf.remote_addr.aid) { + /* neighbor */ + if (cur_peers) + TAILQ_FOREACH(p, cur_peers, entry) + if (memcmp(&p->conf.remote_addr, + &newpeer->conf.remote_addr, + sizeof(p->conf.remote_addr)) == 0) + break; + if (p) { + newpeer->conf.id = p->conf.id; + return (0); } - - /* new one */ - for (; id < UINT_MAX / 2; id++) { - for (p = peer_l_old; p != NULL && - p->conf.id != id && p->conf.groupid != id; p = p->next) - ; /* nothing */ - if (p == NULL) { /* we found a free id */ - newpeer->conf.id = id++; + } else { + /* group */ + if (cur_peers) + TAILQ_FOREACH(p, cur_peers, entry) + if (strcmp(p->conf.group, + newpeer->conf.group) == 0) + break; + if (p) { + newpeer->conf.id = p->conf.groupid; return (0); } } + /* else new one */ + if (id < UINT_MAX / 2) { + newpeer->conf.id = id++; + return (0); + } + return (-1); } diff --git a/usr.sbin/bgpd/printconf.c b/usr.sbin/bgpd/printconf.c index 51019f1ecea..9a4e99d4785 100644 --- a/usr.sbin/bgpd/printconf.c +++ b/usr.sbin/bgpd/printconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: printconf.c,v 1.133 2019/03/15 09:54:54 claudio Exp $ */ +/* $OpenBSD: printconf.c,v 1.134 2019/03/31 16:57:38 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -49,11 +49,11 @@ const char *print_auth_alg(u_int8_t); const char *print_enc_alg(u_int8_t); void print_announce(struct peer_config *, const char *); void print_as(struct filter_rule *); -void print_rule(struct peer *, struct filter_rule *); +void print_rule(struct bgpd_config *, struct filter_rule *); const char *mrt_type(enum mrt_type); void print_mrt(struct bgpd_config *, u_int32_t, u_int32_t, const char *, const char *); -void print_groups(struct bgpd_config *, struct peer *); +void print_groups(struct bgpd_config *); int peer_compare(const void *, const void *); void @@ -759,7 +759,7 @@ print_as(struct filter_rule *r) } void -print_rule(struct peer *peer_l, struct filter_rule *r) +print_rule(struct bgpd_config *conf, struct filter_rule *r) { struct peer *p; int i; @@ -784,17 +784,17 @@ print_rule(struct peer *peer_l, struct filter_rule *r) printf("eeeeeeeps. "); if (r->peer.peerid) { - for (p = peer_l; p != NULL && p->conf.id != r->peer.peerid; - p = p->next) - ; /* nothing */ + TAILQ_FOREACH(p, &conf->peers, entry) + if (p->conf.id == r->peer.peerid) + break; if (p == NULL) printf("? "); else printf("%s ", log_addr(&p->conf.remote_addr)); } else if (r->peer.groupid) { - for (p = peer_l; p != NULL && - p->conf.groupid != r->peer.groupid; p = p->next) - ; /* nothing */ + TAILQ_FOREACH(p, &conf->peers, entry) + if (p->conf.groupid == r->peer.groupid) + break; if (p == NULL) printf("group ? "); else @@ -928,7 +928,7 @@ print_mrt(struct bgpd_config *conf, u_int32_t pid, u_int32_t gid, } void -print_groups(struct bgpd_config *conf, struct peer *peer_l) +print_groups(struct bgpd_config *conf) { struct peer_config **peerlist; struct peer *p; @@ -939,14 +939,14 @@ print_groups(struct bgpd_config *conf, struct peer *peer_l) const char *c; peer_cnt = 0; - for (p = peer_l; p != NULL; p = p->next) + TAILQ_FOREACH(p, &conf->peers, entry) peer_cnt++; if ((peerlist = calloc(peer_cnt, sizeof(struct peer_config *))) == NULL) fatal("print_groups calloc"); i = 0; - for (p = peer_l; p != NULL; p = p->next) + TAILQ_FOREACH(p, &conf->peers, entry) peerlist[i++] = &p->conf; qsort(peerlist, peer_cnt, sizeof(struct peer_config *), peer_compare); @@ -986,10 +986,7 @@ peer_compare(const void *aa, const void *bb) } void -print_config(struct bgpd_config *conf, struct rib_names *rib_l, - struct network_head *net_l, struct peer *peer_l, - struct filter_head *rules_l, struct mrt_head *mrt_l, - struct l3vpn_head *vpns_l) +print_config(struct bgpd_config *conf, struct rib_names *rib_l) { struct filter_rule *r; struct network *n; @@ -1001,11 +998,11 @@ print_config(struct bgpd_config *conf, struct rib_names *rib_l, print_as_sets(conf->as_sets); print_prefixsets(&conf->prefixsets); print_originsets(&conf->originsets); - TAILQ_FOREACH(n, net_l, entry) + TAILQ_FOREACH(n, &conf->networks, entry) print_network(&n->net, ""); - if (!SIMPLEQ_EMPTY(vpns_l)) + if (!SIMPLEQ_EMPTY(&conf->l3vpns)) printf("\n"); - SIMPLEQ_FOREACH(vpn, vpns_l, entry) + SIMPLEQ_FOREACH(vpn, &conf->l3vpns, entry) print_l3vpn(vpn); printf("\n"); SIMPLEQ_FOREACH(rr, rib_l, entry) { @@ -1020,7 +1017,7 @@ print_config(struct bgpd_config *conf, struct rib_names *rib_l, } printf("\n"); print_mrt(conf, 0, 0, "", ""); - print_groups(conf, peer_l); - TAILQ_FOREACH(r, rules_l, entry) - print_rule(peer_l, r); + print_groups(conf); + TAILQ_FOREACH(r, conf->filters, entry) + print_rule(conf, r); } diff --git a/usr.sbin/bgpd/session.c b/usr.sbin/bgpd/session.c index a4e242450fa..3844916ee39 100644 --- a/usr.sbin/bgpd/session.c +++ b/usr.sbin/bgpd/session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: session.c,v 1.376 2019/03/15 09:54:54 claudio Exp $ */ +/* $OpenBSD: session.c,v 1.377 2019/03/31 16:57:38 claudio Exp $ */ /* * Copyright (c) 2003, 2004, 2005 Henning Brauer <henning@openbsd.org> @@ -94,17 +94,15 @@ void session_up(struct peer *); void session_down(struct peer *); int imsg_rde(int, u_int32_t, void *, u_int16_t); void session_demote(struct peer *, int); +void merge_peers(struct bgpd_config *, struct bgpd_config *); int la_cmp(struct listen_addr *, struct listen_addr *); -struct peer *getpeerbyip(struct sockaddr *); -struct peer *getpeerbyid(u_int32_t); void session_template_clone(struct peer *, struct sockaddr *, u_int32_t, u_int32_t); int session_match_mask(struct peer *, struct bgpd_addr *); struct bgpd_config *conf, *nconf; struct bgpd_sysdep sysdep; -struct peer *peers, *npeers; volatile sig_atomic_t session_quit; int pending_reconf; int csock = -1, rcsock = -1; @@ -196,7 +194,7 @@ session_main(int debug, int verbose) u_int listener_cnt, ctl_cnt, mrt_cnt; u_int new_cnt; struct passwd *pw; - struct peer *p, **peer_l = NULL, *last, *next; + struct peer *p, **peer_l = NULL, *next; struct mrt *m, *xm, **mrt_l = NULL; struct pollfd *pfd = NULL; struct ctl_conn *ctl_conn; @@ -251,46 +249,43 @@ session_main(int debug, int verbose) while (session_quit == 0) { /* check for peers to be initialized or deleted */ - last = NULL; if (!pending_reconf) { - for (p = peers; p != NULL; p = next) { - next = p->next; + for (p = TAILQ_FIRST(&conf->peers); p != NULL; + p = next) { + next = TAILQ_NEXT(p, entry); /* cloned peer that idled out? */ if (p->template && (p->state == STATE_IDLE || p->state == STATE_ACTIVE) && time(NULL) - p->stats.last_updown >= INTERVAL_HOLD_CLONED) - p->conf.reconf_action = RECONF_DELETE; + p->reconf_action = RECONF_DELETE; /* new peer that needs init? */ if (p->state == STATE_NONE) init_peer(p); /* reinit due? */ - if (p->conf.reconf_action == RECONF_REINIT) { + if (p->reconf_action == RECONF_REINIT) { session_stop(p, ERR_CEASE_ADMIN_RESET); if (!p->conf.down) timer_set(p, Timer_IdleHold, 0); } /* deletion due? */ - if (p->conf.reconf_action == RECONF_DELETE) { + if (p->reconf_action == RECONF_DELETE) { if (p->demoted) session_demote(p, -1); p->conf.demote_group[0] = 0; session_stop(p, ERR_CEASE_PEER_UNCONF); log_peer_warnx(&p->conf, "removed"); - if (last != NULL) - last->next = next; - else - peers = next; + TAILQ_REMOVE(&conf->peers, p, entry); timer_remove_all(p); + pfkey_remove(p); free(p); peer_cnt--; continue; } - p->conf.reconf_action = RECONF_NONE; - last = p; + p->reconf_action = RECONF_NONE; } } @@ -375,7 +370,7 @@ session_main(int debug, int verbose) idx_listeners = i; timeout = 240; /* loop every 240s at least */ - for (p = peers; p != NULL; p = p->next) { + TAILQ_FOREACH(p, &conf->peers, entry) { time_t nextaction; struct peer_timer *pt; @@ -526,7 +521,7 @@ session_main(int debug, int verbose) session_dispatch_msg(&pfd[j], peer_l[j - idx_listeners]); - for (p = peers; p != NULL; p = p->next) + TAILQ_FOREACH(p, &conf->peers, entry) if (p->rbuf && p->rbuf->wpos) session_process_msg(p); @@ -535,11 +530,11 @@ session_main(int debug, int verbose) mrt_write(mrt_l[j - idx_peers]); for (; j < i; j++) - control_dispatch_msg(&pfd[j], &ctl_cnt); + control_dispatch_msg(&pfd[j], &ctl_cnt, &conf->peers); } - while ((p = peers) != NULL) { - peers = p->next; + while ((p = TAILQ_FIRST(&conf->peers)) != NULL) { + TAILQ_REMOVE(&conf->peers, p, entry); strlcpy(p->conf.shutcomm, "bgpd shutting down", sizeof(p->conf.shutcomm)); @@ -608,7 +603,7 @@ init_peer(struct peer *p) * do not handle new peers. they must reach ESTABLISHED beforehands. * peers added at runtime have reconf_action set to RECONF_REINIT. */ - if (p->conf.reconf_action != RECONF_REINIT && p->conf.demote_group[0]) + if (p->reconf_action != RECONF_REINIT && p->conf.demote_group[0]) session_demote(p, +1); } @@ -1008,7 +1003,7 @@ session_accept(int listenfd) return; } - p = getpeerbyip((struct sockaddr *)&cliaddr); + p = getpeerbyip(conf, (struct sockaddr *)&cliaddr); if (p != NULL && p->state == STATE_IDLE && p->errcnt < 2) { if (timer_running(p, Timer_IdleHold, NULL)) { @@ -1523,7 +1518,7 @@ session_update(u_int32_t peerid, void *data, size_t datalen) struct peer *p; struct bgp_msg *buf; - if ((p = getpeerbyid(peerid)) == NULL) { + if ((p = getpeerbyid(conf, peerid)) == NULL) { log_warnx("no such peer: id=%u", peerid); return; } @@ -2555,12 +2550,10 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt) struct mrt xmrt; struct mrt *mrt; struct imsgbuf *i; - struct peer_config *pconf; - struct peer *p, *next; + struct peer *p; struct listen_addr *la, *nla; struct kif *kif; u_char *data; - enum reconf_action reconf; int n, fd, depend_ok, restricted; u_int8_t aid, errcode, subcode; @@ -2606,7 +2599,6 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt) if (idx != PFD_PIPE_MAIN) fatalx("reconf request not from parent"); nconf = new_config(); - npeers = NULL; copy_config(nconf, imsg.data); pending_reconf = 1; @@ -2614,45 +2606,12 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt) case IMSG_RECONF_PEER: if (idx != PFD_PIPE_MAIN) fatalx("reconf request not from parent"); - pconf = imsg.data; - p = getpeerbyaddr(&pconf->remote_addr); - if (p == NULL) { - if ((p = calloc(1, sizeof(struct peer))) == - NULL) - fatal("new_peer"); - p->state = p->prev_state = STATE_NONE; - p->next = npeers; - npeers = p; - reconf = RECONF_REINIT; - } else - reconf = RECONF_KEEP; - - memcpy(&p->conf, pconf, sizeof(struct peer_config)); - p->conf.reconf_action = reconf; - - /* sync the RDE in case we keep the peer */ - if (reconf == RECONF_KEEP) { - if (imsg_rde(IMSG_SESSION_ADD, p->conf.id, - &p->conf, sizeof(struct peer_config)) == -1) - fatalx("imsg_compose error"); - if (p->conf.template) { - /* apply the conf to all clones */ - struct peer *np; - for (np = peers; np; np = np->next) { - if (np->template != p) - continue; - session_template_clone(np, - NULL, np->conf.id, - np->conf.remote_as); - if (imsg_rde(IMSG_SESSION_ADD, - np->conf.id, &np->conf, - sizeof(struct peer_config)) - == -1) - fatalx("imsg_compose" - " error"); - } - } - } + if ((p = calloc(1, sizeof(struct peer))) == NULL) + fatal("new_peer"); + memcpy(&p->conf, imsg.data, sizeof(struct peer_config)); + p->state = p->prev_state = STATE_NONE; + p->reconf_action = RECONF_REINIT; + TAILQ_INSERT_TAIL(&nconf->peers, p, entry); break; case IMSG_RECONF_LISTENER: if (idx != PFD_PIPE_MAIN) @@ -2723,23 +2682,7 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt) if (nconf == NULL) fatalx("got IMSG_RECONF_DONE but no config"); copy_config(conf, nconf); - - /* add new peers */ - for (p = npeers; p != NULL; p = next) { - next = p->next; - p->next = peers; - peers = p; - } - /* find ones that need attention */ - for (p = peers; p != NULL; p = p->next) { - /* needs to be deleted? */ - if (p->conf.reconf_action == RECONF_NONE && - !p->template) - p->conf.reconf_action = RECONF_DELETE; - /* had demotion, is demoted, demote removed? */ - if (p->demoted && !p->conf.demote_group[0]) - session_demote(p, -1); - } + merge_peers(conf, nconf); /* delete old listeners */ for (la = TAILQ_FIRST(conf->listen_addrs); la != NULL; @@ -2781,7 +2724,7 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt) kif = imsg.data; depend_ok = kif->depend_state; - for (p = peers; p != NULL; p = p->next) + TAILQ_FOREACH(p, &conf->peers, entry) if (!strcmp(p->conf.if_depend, kif->ifname)) { if (depend_ok && !p->depend_ok) { p->depend_ok = depend_ok; @@ -2876,7 +2819,7 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt) log_warnx("RDE sent invalid notification"); break; } - if ((p = getpeerbyid(imsg.hdr.peerid)) == NULL) { + if ((p = getpeerbyid(conf, imsg.hdr.peerid)) == NULL) { log_warnx("no such peer: id=%u", imsg.hdr.peerid); break; @@ -2916,7 +2859,7 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt) log_warnx("RDE sent invalid restart msg"); break; } - if ((p = getpeerbyid(imsg.hdr.peerid)) == NULL) { + if ((p = getpeerbyid(conf, imsg.hdr.peerid)) == NULL) { log_warnx("no such peer: id=%u", imsg.hdr.peerid); break; @@ -2943,7 +2886,7 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt) case IMSG_SESSION_DOWN: if (idx != PFD_PIPE_ROUTE) fatalx("update request not from RDE"); - if ((p = getpeerbyid(imsg.hdr.peerid)) == NULL) { + if ((p = getpeerbyid(conf, imsg.hdr.peerid)) == NULL) { log_warnx("no such peer: id=%u", imsg.hdr.peerid); break; @@ -2993,26 +2936,12 @@ la_cmp(struct listen_addr *a, struct listen_addr *b) } struct peer * -getpeerbyaddr(struct bgpd_addr *addr) -{ - struct peer *p; - - /* we might want a more effective way to find peers by IP */ - for (p = peers; p != NULL && - memcmp(&p->conf.remote_addr, addr, sizeof(p->conf.remote_addr)); - p = p->next) - ; /* nothing */ - - return (p); -} - -struct peer * -getpeerbydesc(const char *descr) +getpeerbydesc(struct bgpd_config *c, const char *descr) { struct peer *p, *res = NULL; int match = 0; - for (p = peers; p != NULL; p = p->next) + TAILQ_FOREACH(p, &c->peers, entry) if (!strcmp(p->conf.descr, descr)) { res = p; match++; @@ -3029,7 +2958,7 @@ getpeerbydesc(const char *descr) } struct peer * -getpeerbyip(struct sockaddr *ip) +getpeerbyip(struct bgpd_config *c, struct sockaddr *ip) { struct bgpd_addr addr; struct peer *p, *newpeer, *loose = NULL; @@ -3038,13 +2967,13 @@ getpeerbyip(struct sockaddr *ip) sa2addr(ip, &addr, NULL); /* we might want a more effective way to find peers by IP */ - for (p = peers; p != NULL; p = p->next) + TAILQ_FOREACH(p, &c->peers, entry) if (!p->conf.template && !memcmp(&addr, &p->conf.remote_addr, sizeof(addr))) return (p); /* try template matching */ - for (p = peers; p != NULL; p = p->next) + TAILQ_FOREACH(p, &c->peers, entry) if (p->conf.template && p->conf.remote_addr.aid == addr.aid && session_match_mask(p, &addr)) @@ -3058,22 +2987,20 @@ getpeerbyip(struct sockaddr *ip) fatal(NULL); memcpy(newpeer, loose, sizeof(struct peer)); for (id = UINT_MAX; id > UINT_MAX / 2; id--) { - for (p = peers; p != NULL && p->conf.id != id; - p = p->next) - ; /* nothing */ - if (p == NULL) { /* we found a free id */ + TAILQ_FOREACH(p, &c->peers, entry) + if (p->conf.id == id) + break; + if (p == NULL) /* we found a free id */ break; - } } newpeer->template = loose; session_template_clone(newpeer, ip, id, 0); newpeer->state = newpeer->prev_state = STATE_NONE; - newpeer->conf.reconf_action = RECONF_KEEP; + newpeer->reconf_action = RECONF_KEEP; newpeer->rbuf = NULL; init_peer(newpeer); bgp_fsm(newpeer, EVNT_START); - newpeer->next = peers; - peers = newpeer; + TAILQ_INSERT_TAIL(&c->peers, newpeer, entry); return (newpeer); } @@ -3081,16 +3008,15 @@ getpeerbyip(struct sockaddr *ip) } struct peer * -getpeerbyid(u_int32_t peerid) +getpeerbyid(struct bgpd_config *c, u_int32_t peerid) { struct peer *p; - /* we might want a more effective way to find peers by IP */ - for (p = peers; p != NULL && - p->conf.id != peerid; p = p->next) - ; /* nothing */ - - return (p); + /* we might want a more effective way to find peers by id */ + TAILQ_FOREACH(p, &c->peers, entry) + if (p->conf.id == peerid) + return (p); + return (NULL); } int @@ -3286,3 +3212,51 @@ session_stop(struct peer *peer, u_int8_t subcode) } bgp_fsm(peer, EVNT_STOP); } + +void +merge_peers(struct bgpd_config *c, struct bgpd_config *nc) +{ + struct peer *p, *np; + + TAILQ_FOREACH(p, &c->peers, entry) { + /* templates are handled specially */ + if (p->template != NULL) + continue; + np = getpeerbyid(nc, p->conf.id); + if (np == NULL) { + p->reconf_action = RECONF_DELETE; + continue; + } + + memcpy(&p->conf, &np->conf, sizeof(p->conf)); + TAILQ_REMOVE(&nc->peers, np, entry); + free(np); + + p->reconf_action = RECONF_KEEP; + + /* had demotion, is demoted, demote removed? */ + if (p->demoted && !p->conf.demote_group[0]) + session_demote(p, -1); + + /* sync the RDE in case we keep the peer */ + if (imsg_rde(IMSG_SESSION_ADD, p->conf.id, + &p->conf, sizeof(struct peer_config)) == -1) + fatalx("imsg_compose error"); + + /* apply the config to all clones of a template */ + if (p->conf.template) { + struct peer *xp; + TAILQ_FOREACH(xp, &conf->peers, entry) { + if (xp->template != p) + continue; + session_template_clone(xp, NULL, xp->conf.id, + xp->conf.remote_as); + if (imsg_rde(IMSG_SESSION_ADD, xp->conf.id, + &xp->conf, sizeof(xp->conf)) == -1) + fatalx("imsg_compose error"); + } + } + } + + TAILQ_CONCAT(&c->peers, &nc->peers, entry); +} diff --git a/usr.sbin/bgpd/session.h b/usr.sbin/bgpd/session.h index ead763c2711..22183e2f8e2 100644 --- a/usr.sbin/bgpd/session.h +++ b/usr.sbin/bgpd/session.h @@ -1,4 +1,4 @@ -/* $OpenBSD: session.h,v 1.134 2019/03/07 07:42:36 claudio Exp $ */ +/* $OpenBSD: session.h,v 1.135 2019/03/31 16:57:38 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -196,6 +196,7 @@ TAILQ_HEAD(peer_timer_head, peer_timer); struct peer { struct peer_config conf; struct peer_stats stats; + TAILQ_ENTRY(peer) entry; struct { struct capabilities ann; struct capabilities peer; @@ -207,13 +208,12 @@ struct peer { u_int32_t spi_out; enum auth_method method; u_int8_t established; - } auth; + } auth; struct bgpd_addr local; struct bgpd_addr remote; struct peer_timer_head timers; struct msgbuf wbuf; struct ibuf_read *rbuf; - struct peer *next; struct peer *template; int fd; int lasterr; @@ -222,6 +222,7 @@ struct peer { u_int32_t remote_bgpid; enum session_state state; enum session_state prev_state; + enum reconf_action reconf_action; u_int16_t short_as; u_int16_t holdtime; u_int16_t local_port; @@ -232,7 +233,6 @@ struct peer { u_int8_t throttled; }; -extern struct peer *peers; extern time_t pauseaccept; struct ctl_timer { @@ -247,8 +247,7 @@ int carp_demote_get(char *); int carp_demote_set(char *, int); /* config.c */ -void merge_config(struct bgpd_config *, struct bgpd_config *, - struct peer *); +void merge_config(struct bgpd_config *, struct bgpd_config *); int prepare_listeners(struct bgpd_config *); /* control.c */ @@ -256,7 +255,7 @@ int control_check(char *); int control_init(int, char *); int control_listen(int); void control_shutdown(int); -int control_dispatch_msg(struct pollfd *, u_int *); +int control_dispatch_msg(struct pollfd *, u_int *, struct peer_head *); unsigned int control_accept(int, int); /* log.c */ @@ -276,7 +275,7 @@ void mrt_dump_state(struct mrt *, u_int16_t, u_int16_t, void mrt_done(struct mrt *); /* parse.y */ -int parse_config(char *, struct bgpd_config *, struct peer **); +struct bgpd_config *parse_config(char *, struct peer_head *); /* pfkey.c */ int pfkey_read(int, struct sadb_msg *); @@ -285,9 +284,7 @@ int pfkey_remove(struct peer *); int pfkey_init(struct bgpd_sysdep *); /* printconf.c */ -void print_config(struct bgpd_config *, struct rib_names *, - struct network_head *, struct peer *, struct filter_head *, - struct mrt_head *, struct l3vpn_head *); +void print_config(struct bgpd_config *, struct rib_names *); /* rde.c */ void rde_main(int, int); @@ -296,8 +293,9 @@ void rde_main(int, int); void session_main(int, int); void bgp_fsm(struct peer *, enum session_events); int session_neighbor_rrefresh(struct peer *p); -struct peer *getpeerbyaddr(struct bgpd_addr *); -struct peer *getpeerbydesc(const char *); +struct peer *getpeerbydesc(struct bgpd_config *, const char *); +struct peer *getpeerbyip(struct bgpd_config *, struct sockaddr *); +struct peer *getpeerbyid(struct bgpd_config *, u_int32_t); int peer_matched(struct peer *, struct ctl_neighbor *); int imsg_ctl_parent(int, u_int32_t, pid_t, void *, u_int16_t); int imsg_ctl_rde(int, pid_t, void *, u_int16_t); |