diff options
author | Hiroki Sato <hrs@FreeBSD.org> | 2010-02-16 19:27:03 +0000 |
---|---|---|
committer | Hiroki Sato <hrs@FreeBSD.org> | 2010-02-16 19:27:03 +0000 |
commit | 7ab9a19af615666cef45e1b4538c8460d19e1ec0 (patch) | |
tree | 301a68c22691daf3b616754a383cd1730c23dae7 /net/openbgpd/files/patch-bgpd_rde.c | |
parent | Add updating instructions for sysutils/bacula-{server,client}. (diff) |
Update to 4.6.20100215.
Feature safe: yes
Notes
Notes:
svn path=/head/; revision=249966
Diffstat (limited to 'net/openbgpd/files/patch-bgpd_rde.c')
-rw-r--r-- | net/openbgpd/files/patch-bgpd_rde.c | 2505 |
1 files changed, 1145 insertions, 1360 deletions
diff --git a/net/openbgpd/files/patch-bgpd_rde.c b/net/openbgpd/files/patch-bgpd_rde.c index f31d1d4c5ec2..7a2e01710e95 100644 --- a/net/openbgpd/files/patch-bgpd_rde.c +++ b/net/openbgpd/files/patch-bgpd_rde.c @@ -1,411 +1,335 @@ Index: bgpd/rde.c =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/rde.c,v -retrieving revision 1.1.1.1 -retrieving revision 1.6 -diff -u -p -r1.1.1.1 -r1.6 ---- bgpd/rde.c 30 Jun 2009 05:46:15 -0000 1.1.1.1 -+++ bgpd/rde.c 22 Oct 2009 15:10:02 -0000 1.6 +retrieving revision 1.1.1.8 +retrieving revision 1.8 +diff -u -p -r1.1.1.8 -r1.8 +--- bgpd/rde.c 14 Feb 2010 20:19:57 -0000 1.1.1.8 ++++ bgpd/rde.c 14 Feb 2010 19:53:36 -0000 1.8 @@ -1,4 +1,4 @@ --/* $OpenBSD: rde.c,v 1.232.2.1 2009/01/30 22:37:34 claudio Exp $ */ -+/* $OpenBSD: rde.c,v 1.265 2009/08/06 08:53:11 claudio Exp $ */ +-/* $OpenBSD: rde.c,v 1.264 2009/06/29 12:22:16 claudio Exp $ */ ++/* $OpenBSD: rde.c,v 1.284 2010/01/13 06:02:37 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> -@@ -38,24 +38,28 @@ - #define PFD_PIPE_MAIN 0 - #define PFD_PIPE_SESSION 1 - #define PFD_PIPE_SESSION_CTL 2 --#define PFD_MRT_FILE 3 -+#define PFD_PIPE_COUNT 3 - - void rde_sighdlr(int); - void rde_dispatch_imsg_session(struct imsgbuf *); - void rde_dispatch_imsg_parent(struct imsgbuf *); - int rde_update_dispatch(struct imsg *); -+void rde_update_update(struct rde_peer *, struct rde_aspath *, -+ struct bgpd_addr *, u_int8_t); -+void rde_update_withdraw(struct rde_peer *, struct bgpd_addr *, -+ u_int8_t); +@@ -51,12 +51,16 @@ void rde_update_withdraw(struct rde_pe int rde_attr_parse(u_char *, u_int16_t, struct rde_peer *, struct rde_aspath *, struct mpattr *); u_int8_t rde_attr_missing(struct rde_aspath *, int, u_int16_t); - int rde_get_mp_nexthop(u_char *, u_int16_t, u_int16_t, +-int rde_get_mp_nexthop(u_char *, u_int16_t, u_int16_t, - struct rde_aspath *); ++int rde_get_mp_nexthop(u_char *, u_int16_t, u_int8_t, + struct rde_aspath *, struct rde_peer *); ++int rde_update_extract_prefix(u_char *, u_int16_t, void *, ++ u_int8_t, u_int8_t); int rde_update_get_prefix(u_char *, u_int16_t, struct bgpd_addr *, u_int8_t *); int rde_update_get_prefix6(u_char *, u_int16_t, struct bgpd_addr *, u_int8_t *); ++int rde_update_get_vpn4(u_char *, u_int16_t, struct bgpd_addr *, ++ u_int8_t *); void rde_update_err(struct rde_peer *, u_int8_t , u_int8_t, void *, u_int16_t); --void rde_update_log(const char *, -+void rde_update_log(const char *, u_int16_t, - const struct rde_peer *, const struct bgpd_addr *, - const struct bgpd_addr *, u_int8_t); - void rde_as4byte_fixup(struct rde_peer *, struct rde_aspath *); -@@ -67,19 +71,17 @@ void rde_dump_filter(struct prefix *, - struct ctl_show_rib_request *); - void rde_dump_filterout(struct rde_peer *, struct prefix *, - struct ctl_show_rib_request *); --void rde_dump_upcall(struct pt_entry *, void *); --void rde_dump_as(struct ctl_show_rib_request *); --void rde_dump_prefix_upcall(struct pt_entry *, void *); --void rde_dump_prefix(struct ctl_show_rib_request *); --void rde_dump_community(struct ctl_show_rib_request *); -+void rde_dump_upcall(struct rib_entry *, void *); -+void rde_dump_prefix_upcall(struct rib_entry *, void *); - void rde_dump_ctx_new(struct ctl_show_rib_request *, pid_t, - enum imsg_type); --void rde_dump_runner(void); --int rde_dump_pending(void); -+void rde_dump_mrt_new(struct mrt *, pid_t, int); -+void rde_dump_done(void *); - --void rde_up_dump_upcall(struct pt_entry *, void *); --void rde_softreconfig_out(struct pt_entry *, void *); --void rde_softreconfig_in(struct pt_entry *, void *); -+void rde_up_dump_upcall(struct rib_entry *, void *); -+void rde_softreconfig_out(struct rib_entry *, void *); -+void rde_softreconfig_in(struct rib_entry *, void *); + void rde_update_log(const char *, u_int16_t, +@@ -81,8 +85,9 @@ void rde_dump_done(void *); + void rde_up_dump_upcall(struct rib_entry *, void *); + void rde_softreconfig_out(struct rib_entry *, void *); + void rde_softreconfig_in(struct rib_entry *, void *); +void rde_softreconfig_load(struct rib_entry *, void *); void rde_update_queue_runner(void); - void rde_update6_queue_runner(void); +-void rde_update6_queue_runner(void); ++void rde_update6_queue_runner(u_int8_t); + + void peer_init(u_int32_t); + void peer_shutdown(void); +@@ -91,8 +96,8 @@ struct rde_peer *peer_add(u_int32_t, str + struct rde_peer *peer_get(u_int32_t); + void peer_up(u_int32_t, struct session_up *); + void peer_down(u_int32_t); +-void peer_dump(u_int32_t, u_int16_t, u_int8_t); +-void peer_send_eor(struct rde_peer *, u_int16_t, u_int16_t); ++void peer_dump(u_int32_t, u_int8_t); ++void peer_send_eor(struct rde_peer *, u_int8_t); -@@ -96,8 +98,7 @@ void peer_send_eor(struct rde_peer *, void network_init(struct network_head *); void network_add(struct network_config *, int); - void network_delete(struct network_config *, int); --void network_dump_upcall(struct pt_entry *, void *); --void network_flush(int); -+void network_dump_upcall(struct rib_entry *, void *); - - void rde_shutdown(void); - int sa_cmp(struct bgpd_addr *, struct sockaddr *); -@@ -106,23 +107,26 @@ volatile sig_atomic_t rde_quit = 0; - struct bgpd_config *conf, *nconf; - time_t reloadtime; - struct rde_peer_head peerlist; --struct rde_peer peerself; --struct rde_peer peerdynamic; -+struct rde_peer *peerself; - struct filter_head *rules_l, *newrules; - struct imsgbuf *ibuf_se; - struct imsgbuf *ibuf_se_ctl; - struct imsgbuf *ibuf_main; --struct mrt *mrt; - struct rde_memstats rdemem; - - struct rde_dump_ctx { -- TAILQ_ENTRY(rde_dump_ctx) entry; -- struct pt_context ptc; -+ struct rib_context ribctx; - struct ctl_show_rib_request req; - sa_family_t af; +@@ -120,11 +125,12 @@ struct rde_dump_ctx { }; --TAILQ_HEAD(, rde_dump_ctx) rde_dump_h = TAILQ_HEAD_INITIALIZER(rde_dump_h); -+struct rde_mrt_ctx { -+ struct mrt mrt; -+ struct rib_context ribctx; -+}; -+ -+struct mrt_head rde_mrts = LIST_HEAD_INITIALIZER(rde_mrts); -+u_int rde_mrt_cnt; + struct rde_mrt_ctx { +- struct mrt mrt; +- struct rib_context ribctx; ++ struct mrt mrt; ++ struct rib_context ribctx; ++ LIST_ENTRY(rde_mrt_ctx) entry; + }; + +-struct mrt_head rde_mrts = LIST_HEAD_INITIALIZER(rde_mrts); ++LIST_HEAD(, rde_mrt_ctx) rde_mrts = LIST_HEAD_INITIALIZER(rde_mrts); + u_int rde_mrt_cnt; void - rde_sighdlr(int sig) -@@ -143,18 +147,22 @@ u_int32_t nexthophashsize = 64; +@@ -144,24 +150,17 @@ u_int32_t attrhashsize = 512; + u_int32_t nexthophashsize = 64; + pid_t - rde_main(struct bgpd_config *config, struct peer *peer_l, - struct network_head *net_l, struct filter_head *rules, -- struct mrt_head *mrt_l, int pipe_m2r[2], int pipe_s2r[2], int pipe_m2s[2], -- int pipe_s2rctl[2], int debug) -+ struct mrt_head *mrt_l, struct rib_names *rib_n, int pipe_m2r[2], -+ int pipe_s2r[2], int pipe_m2s[2], int pipe_s2rctl[2], int debug) +-rde_main(struct bgpd_config *config, struct peer *peer_l, +- struct network_head *net_l, struct filter_head *rules, +- struct mrt_head *mrt_l, struct rib_names *rib_n, int pipe_m2r[2], +- int pipe_s2r[2], int pipe_m2s[2], int pipe_s2rctl[2], int debug) ++rde_main(int pipe_m2r[2], int pipe_s2r[2], int pipe_m2s[2], int pipe_s2rctl[2], ++ int debug) { pid_t pid; struct passwd *pw; - struct peer *p; - struct listen_addr *la; -- struct pollfd pfd[4]; -+ struct pollfd *pfd = NULL; - struct filter_rule *f; - struct filter_set *set; - struct nexthop *nh; -- int i, timeout; -+ struct rde_rib *rr; -+ struct mrt *mrt, *xmrt; -+ void *newp; -+ u_int pfd_elms = 0, i, j; -+ int timeout; +- struct peer *p; +- struct listen_addr *la; + struct pollfd *pfd = NULL; +- struct filter_rule *f; +- struct filter_set *set; +- struct nexthop *nh; +- struct rde_rib *rr; +- struct mrt *mrt, *xmrt; ++ struct rde_mrt_ctx *mctx, *xmctx; + void *newp; + u_int pfd_elms = 0, i, j; + int timeout; ++ u_int8_t aid; switch (pid = fork()) { case -1: -@@ -213,7 +221,6 @@ rde_main(struct bgpd_config *config, str - LIST_REMOVE(mrt, entry); - free(mrt); +@@ -172,8 +171,6 @@ rde_main(struct bgpd_config *config, str + return (pid); } -- mrt = NULL; - - while ((la = TAILQ_FIRST(config->listen_addrs)) != NULL) { - TAILQ_REMOVE(config->listen_addrs, la, entry); -@@ -223,6 +230,11 @@ rde_main(struct bgpd_config *config, str - free(config->listen_addrs); +- conf = config; +- + if ((pw = getpwnam(BGPD_USER)) == NULL) + fatal("getpwnam"); + +@@ -194,6 +191,8 @@ rde_main(struct bgpd_config *config, str + signal(SIGINT, rde_sighdlr); + signal(SIGPIPE, SIG_IGN); + signal(SIGHUP, SIG_IGN); ++ signal(SIGALRM, SIG_IGN); ++ signal(SIGUSR1, SIG_IGN); + + close(pipe_s2r[0]); + close(pipe_s2rctl[0]); +@@ -210,50 +209,21 @@ rde_main(struct bgpd_config *config, str + imsg_init(ibuf_se_ctl, pipe_s2rctl[1]); + imsg_init(ibuf_main, pipe_m2r[1]); + +- /* peer list, mrt list and listener list are not used in the RDE */ +- while ((p = peer_l) != NULL) { +- peer_l = p->next; +- free(p); +- } +- +- while ((mrt = LIST_FIRST(mrt_l)) != NULL) { +- LIST_REMOVE(mrt, entry); +- free(mrt); +- } +- +- while ((la = TAILQ_FIRST(config->listen_addrs)) != NULL) { +- TAILQ_REMOVE(config->listen_addrs, la, entry); +- close(la->fd); +- free(la); +- } +- free(config->listen_addrs); +- pt_init(); -+ while ((rr = SIMPLEQ_FIRST(&ribnames))) { -+ SIMPLEQ_REMOVE_HEAD(&ribnames, entry); -+ rib_new(-1, rr->name, rr->flags); -+ free(rr); -+ } +- while ((rr = SIMPLEQ_FIRST(&ribnames))) { +- SIMPLEQ_REMOVE_HEAD(&ribnames, entry); +- rib_new(-1, rr->name, rr->flags); +- free(rr); +- } path_init(pathhashsize); aspath_init(pathhashsize); attr_init(attrhashsize); -@@ -234,6 +246,7 @@ rde_main(struct bgpd_config *config, str + nexthop_init(nexthophashsize); + peer_init(peerhashsize); +- rules_l = rules; +- network_init(net_l); + ++ rules_l = calloc(1, sizeof(struct filter_head)); ++ if (rules_l == NULL) ++ fatal(NULL); ++ TAILQ_INIT(rules_l); ++ if ((conf = malloc(sizeof(struct bgpd_config))) == NULL) ++ fatal(NULL); log_info("route decision engine ready"); - TAILQ_FOREACH(f, rules, entry) { -+ f->peer.ribid = rib_find(f->rib); - TAILQ_FOREACH(set, &f->set, entry) { - if (set->type == ACTION_SET_NEXTHOP) { - nh = nexthop_get(&set->action.nexthop); -@@ -243,8 +256,20 @@ rde_main(struct bgpd_config *config, str - } - +- TAILQ_FOREACH(f, rules, entry) { +- f->peer.ribid = rib_find(f->rib); +- TAILQ_FOREACH(set, &f->set, entry) { +- if (set->type == ACTION_SET_NEXTHOP) { +- nh = nexthop_get(&set->action.nexthop); +- nh->refcnt++; +- } +- } +- } +- while (rde_quit == 0) { -+ if (pfd_elms < PFD_PIPE_COUNT + rde_mrt_cnt) { -+ if ((newp = realloc(pfd, sizeof(struct pollfd) * -+ (PFD_PIPE_COUNT + rde_mrt_cnt))) == NULL) { -+ /* panic for now */ -+ log_warn("could not resize pfd from %u -> %u" -+ " entries", pfd_elms, PFD_PIPE_COUNT + -+ rde_mrt_cnt); -+ fatalx("exiting"); -+ } -+ pfd = newp; -+ pfd_elms = PFD_PIPE_COUNT + rde_mrt_cnt; -+ } - timeout = INFTIM; -- bzero(pfd, sizeof(pfd)); -+ bzero(pfd, sizeof(struct pollfd) * pfd_elms); - pfd[PFD_PIPE_MAIN].fd = ibuf_main->fd; - pfd[PFD_PIPE_MAIN].events = POLLIN; - if (ibuf_main->w.queued > 0) -@@ -259,14 +284,16 @@ rde_main(struct bgpd_config *config, str - pfd[PFD_PIPE_SESSION_CTL].events = POLLIN; - if (ibuf_se_ctl->w.queued > 0) - pfd[PFD_PIPE_SESSION_CTL].events |= POLLOUT; -- else if (rde_dump_pending()) -+ else if (rib_dump_pending()) + if (pfd_elms < PFD_PIPE_COUNT + rde_mrt_cnt) { + if ((newp = realloc(pfd, sizeof(struct pollfd) * +@@ -287,9 +257,9 @@ rde_main(struct bgpd_config *config, str timeout = 0; -- i = 3; -- if (mrt && mrt->queued) { -- pfd[PFD_MRT_FILE].fd = mrt->fd; -- pfd[PFD_MRT_FILE].events = POLLOUT; -- i++; -+ i = PFD_PIPE_COUNT; -+ LIST_FOREACH(mrt, &rde_mrts, entry) { -+ if (mrt->wbuf.queued) { -+ pfd[i].fd = mrt->wbuf.fd; -+ pfd[i].events = POLLOUT; -+ i++; -+ } - } - - if (poll(pfd, i, timeout) == -1) { -@@ -299,24 +326,39 @@ rde_main(struct bgpd_config *config, str + i = PFD_PIPE_COUNT; +- LIST_FOREACH(mrt, &rde_mrts, entry) { +- if (mrt->wbuf.queued) { +- pfd[i].fd = mrt->wbuf.fd; ++ LIST_FOREACH(mctx, &rde_mrts, entry) { ++ if (mctx->mrt.wbuf.queued) { ++ pfd[i].fd = mctx->mrt.wbuf.fd; + pfd[i].events = POLLOUT; + i++; + } +@@ -325,24 +295,26 @@ rde_main(struct bgpd_config *config, str if (pfd[PFD_PIPE_SESSION_CTL].revents & POLLIN) rde_dispatch_imsg_session(ibuf_se_ctl); -- if (pfd[PFD_MRT_FILE].revents & POLLOUT) { -- if (mrt_write(mrt) == -1) { -+ for (j = PFD_PIPE_COUNT, mrt = LIST_FIRST(&rde_mrts); -+ j < i && mrt != 0; j++) { -+ xmrt = LIST_NEXT(mrt, entry); -+ if (pfd[j].fd == mrt->wbuf.fd && -+ pfd[j].revents & POLLOUT) -+ mrt_write(mrt); -+ if (mrt->wbuf.queued == 0 && -+ mrt->state == MRT_STATE_REMOVE) { -+ close(mrt->wbuf.fd); -+ LIST_REMOVE(mrt, entry); - free(mrt); -- mrt = NULL; -- } else if (mrt->queued == 0) -- close(mrt->fd); -+ rde_mrt_cnt--; -+ } -+ mrt = xmrt; +- for (j = PFD_PIPE_COUNT, mrt = LIST_FIRST(&rde_mrts); +- j < i && mrt != 0; j++) { +- xmrt = LIST_NEXT(mrt, entry); +- if (pfd[j].fd == mrt->wbuf.fd && ++ for (j = PFD_PIPE_COUNT, mctx = LIST_FIRST(&rde_mrts); ++ j < i && mctx != 0; j++) { ++ xmctx = LIST_NEXT(mctx, entry); ++ if (pfd[j].fd == mctx->mrt.wbuf.fd && + pfd[j].revents & POLLOUT) +- mrt_write(mrt); +- if (mrt->wbuf.queued == 0 && +- mrt->state == MRT_STATE_REMOVE) { +- close(mrt->wbuf.fd); +- LIST_REMOVE(mrt, entry); +- free(mrt); ++ mrt_write(&mctx->mrt); ++ if (mctx->mrt.wbuf.queued == 0 && ++ mctx->mrt.state == MRT_STATE_REMOVE) { ++ close(mctx->mrt.wbuf.fd); ++ LIST_REMOVE(&mctx->ribctx, entry); ++ LIST_REMOVE(mctx, entry); ++ free(mctx); + rde_mrt_cnt--; + } +- mrt = xmrt; ++ mctx = xmctx; } rde_update_queue_runner(); - rde_update6_queue_runner(); +- rde_update6_queue_runner(); ++ for (aid = AID_INET6; aid < AID_MAX; aid++) ++ rde_update6_queue_runner(aid); if (ibuf_se_ctl->w.queued <= 0) -- rde_dump_runner(); -+ rib_dump_runner(); + rib_dump_runner(); } - - /* do not clean up on shutdown on production, it takes ages. */ +@@ -351,11 +323,12 @@ rde_main(struct bgpd_config *config, str if (debug) rde_shutdown(); -+ while ((mrt = LIST_FIRST(&rde_mrts)) != NULL) { -+ msgbuf_clear(&mrt->wbuf); -+ close(mrt->wbuf.fd); -+ LIST_REMOVE(mrt, entry); -+ free(mrt); -+ } -+ +- while ((mrt = LIST_FIRST(&rde_mrts)) != NULL) { +- msgbuf_clear(&mrt->wbuf); +- close(mrt->wbuf.fd); +- LIST_REMOVE(mrt, entry); +- free(mrt); ++ while ((mctx = LIST_FIRST(&rde_mrts)) != NULL) { ++ msgbuf_clear(&mctx->mrt.wbuf); ++ close(mctx->mrt.wbuf.fd); ++ LIST_REMOVE(&mctx->ribctx, entry); ++ LIST_REMOVE(mctx, entry); ++ free(mctx); + } + msgbuf_clear(&ibuf_se->w); - free(ibuf_se); - msgbuf_clear(&ibuf_se_ctl->w); -@@ -344,7 +386,6 @@ rde_dispatch_imsg_session(struct imsgbuf +@@ -378,13 +351,14 @@ rde_dispatch_imsg_session(struct imsgbuf + struct imsg imsg; + struct peer p; + struct peer_config pconf; +- struct rrefresh r; + struct rde_peer *peer; + struct session_up sup; + struct ctl_show_rib_request req; struct filter_set *s; struct nexthop *nh; - int n; -- sa_family_t af = AF_UNSPEC; +- int n; ++ ssize_t n; ++ int verbose; ++ u_int8_t aid; if ((n = imsg_read(ibuf)) == -1) fatal("rde_dispatch_imsg_session: imsg_read error"); -@@ -438,7 +479,8 @@ badnet: +@@ -423,12 +397,14 @@ rde_dispatch_imsg_session(struct imsgbuf + peer_down(imsg.hdr.peerid); + break; + case IMSG_REFRESH: +- if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(r)) { ++ if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(aid)) { log_warnx("rde_dispatch: wrong imsg len"); break; } -- network_flush(0); -+ prefix_network_clean(peerself, time(NULL), -+ F_ANN_DYNAMIC); +- memcpy(&r, imsg.data, sizeof(r)); +- peer_dump(imsg.hdr.peerid, r.afi, r.safi); ++ memcpy(&aid, imsg.data, sizeof(aid)); ++ if (aid >= AID_MAX) ++ fatalx("IMSG_REFRESH: bad AID"); ++ peer_dump(imsg.hdr.peerid, aid); break; - case IMSG_FILTER_SET: + case IMSG_NETWORK_ADD: if (imsg.hdr.len - IMSG_HEADER_SIZE != -@@ -462,54 +504,16 @@ badnet: - } - break; - case IMSG_CTL_SHOW_NETWORK: -- if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(af)) { -- log_warnx("rde_dispatch: wrong imsg len"); -- break; -- } -- bzero(&req, sizeof(req)); -- memcpy(&req.af, imsg.data, sizeof(af)); -- rde_dump_ctx_new(&req, imsg.hdr.pid, imsg.hdr.type); -- break; - case IMSG_CTL_SHOW_RIB: -- if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(req)) { -- log_warnx("rde_dispatch: wrong imsg len"); -- break; -- } -- memcpy(&req, imsg.data, sizeof(req)); -- rde_dump_ctx_new(&req, imsg.hdr.pid, imsg.hdr.type); -- break; - case IMSG_CTL_SHOW_RIB_AS: -- if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(req)) { -- log_warnx("rde_dispatch: wrong imsg len"); -- break; -- } -- memcpy(&req, imsg.data, sizeof(req)); -- req.pid = imsg.hdr.pid; -- rde_dump_as(&req); -- imsg_compose(ibuf_se_ctl, IMSG_CTL_END, 0, req.pid, -1, -- NULL, 0); -- break; -- case IMSG_CTL_SHOW_RIB_PREFIX: -- if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(req)) { -- log_warnx("rde_dispatch: wrong imsg len"); -- break; -- } -- memcpy(&req, imsg.data, sizeof(req)); -- req.pid = imsg.hdr.pid; -- rde_dump_prefix(&req); -- imsg_compose(ibuf_se_ctl, IMSG_CTL_END, 0, req.pid, -1, -- NULL, 0); -- break; - case IMSG_CTL_SHOW_RIB_COMMUNITY: -+ case IMSG_CTL_SHOW_RIB_PREFIX: - if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(req)) { - log_warnx("rde_dispatch: wrong imsg len"); +@@ -446,13 +422,13 @@ rde_dispatch_imsg_session(struct imsgbuf break; } - memcpy(&req, imsg.data, sizeof(req)); -- req.pid = imsg.hdr.pid; -- rde_dump_community(&req); -- imsg_compose(ibuf_se_ctl, IMSG_CTL_END, 0, req.pid, -1, -- NULL, 0); -+ rde_dump_ctx_new(&req, imsg.hdr.pid, imsg.hdr.type); - break; - case IMSG_CTL_SHOW_NEIGHBOR: - if (imsg.hdr.len - IMSG_HEADER_SIZE != -@@ -552,12 +556,14 @@ void - rde_dispatch_imsg_parent(struct imsgbuf *ibuf) - { - struct imsg imsg; -+ struct mrt xmrt; -+ struct rde_rib rn; - struct rde_peer *peer; - struct filter_rule *r; - struct filter_set *s; -- struct mrt *xmrt; - struct nexthop *nh; -- int n, reconf_in = 0, reconf_out = 0; -+ int n, fd, reconf_in = 0, reconf_out = 0; -+ u_int16_t rid; - - if ((n = imsg_read(ibuf)) == -1) - fatal("rde_dispatch_imsg_parent: imsg_read error"); -@@ -581,6 +587,8 @@ rde_dispatch_imsg_parent(struct imsgbuf - NULL) - fatal(NULL); - memcpy(nconf, imsg.data, sizeof(struct bgpd_config)); -+ for (rid = 0; rid < rib_size; rid++) -+ ribs[rid].state = RIB_DELETE; - break; - case IMSG_NETWORK_ADD: - memcpy(&netconf_p, imsg.data, sizeof(netconf_p)); -@@ -601,6 +609,17 @@ rde_dispatch_imsg_parent(struct imsgbuf - TAILQ_INIT(&netconf_p.attrset); - network_delete(&netconf_p, 1); + session_set = NULL; +- switch (netconf_s.prefix.af) { +- case AF_INET: ++ switch (netconf_s.prefix.aid) { ++ case AID_INET: + if (netconf_s.prefixlen > 32) + goto badnet; + network_add(&netconf_s, 0); + break; +- case AF_INET6: ++ case AID_INET6: + if (netconf_s.prefixlen > 128) + goto badnet; + network_add(&netconf_s, 0); +@@ -544,6 +520,11 @@ badnet: + imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_RIB_MEM, 0, + imsg.hdr.pid, -1, &rdemem, sizeof(rdemem)); break; -+ case IMSG_RECONF_RIB: -+ if (imsg.hdr.len - IMSG_HEADER_SIZE != -+ sizeof(struct rde_rib)) -+ fatalx("IMSG_RECONF_RIB bad len"); -+ memcpy(&rn, imsg.data, sizeof(rn)); -+ rid = rib_find(rn.name); -+ if (rid == RIB_FAILED) -+ rib_new(-1, rn.name, rn.flags); -+ else -+ ribs[rid].state = RIB_ACTIVE; ++ case IMSG_CTL_LOG_VERBOSE: ++ /* already checked by SE */ ++ memcpy(&verbose, imsg.data, sizeof(verbose)); ++ log_verbose(verbose); + break; - case IMSG_RECONF_FILTER: - if (imsg.hdr.len - IMSG_HEADER_SIZE != - sizeof(struct filter_rule)) -@@ -609,6 +628,7 @@ rde_dispatch_imsg_parent(struct imsgbuf - fatal(NULL); - memcpy(r, imsg.data, sizeof(struct filter_rule)); - TAILQ_INIT(&r->set); -+ r->peer.ribid = rib_find(r->rib); - parent_set = &r->set; - TAILQ_INSERT_TAIL(newrules, r, entry); + default: break; -@@ -628,10 +648,12 @@ rde_dispatch_imsg_parent(struct imsgbuf + } +@@ -644,9 +625,17 @@ rde_dispatch_imsg_parent(struct imsgbuf + nconf->flags &= ~BGPD_FLAG_NO_EVALUATE; + } + memcpy(conf, nconf, sizeof(struct bgpd_config)); ++ conf->listen_addrs = NULL; ++ conf->csock = NULL; ++ conf->rcsock = NULL; free(nconf); nconf = NULL; parent_set = NULL; -- prefix_network_clean(&peerself, reloadtime); -+ prefix_network_clean(peerself, reloadtime, 0); ++ /* sync peerself with conf */ ++ peerself->remote_bgpid = ntohl(conf->bgpid); ++ peerself->conf.local_as = conf->as; ++ peerself->conf.remote_as = conf->as; ++ peerself->short_as = conf->short_as; + prefix_network_clean(peerself, reloadtime, 0); /* check if filter changed */ - LIST_FOREACH(peer, &peerlist, peer_l) { -+ if (peer->conf.id == 0) -+ continue; - peer->reconf_out = 0; - peer->reconf_in = 0; - if (peer->conf.softreconfig_out && -@@ -647,12 +669,30 @@ rde_dispatch_imsg_parent(struct imsgbuf +@@ -668,17 +657,29 @@ rde_dispatch_imsg_parent(struct imsgbuf reconf_in = 1; } } +- /* XXX this needs rework anyway */ + /* bring ribs in sync before softreconfig dance */ + for (rid = 0; rid < rib_size; rid++) { + if (ribs[rid].state == RIB_DELETE) @@ -413,82 +337,65 @@ diff -u -p -r1.1.1.1 -r1.6 + else if (ribs[rid].state == RIB_NEW) + rib_dump(&ribs[0], + rde_softreconfig_load, &ribs[rid], -+ AF_UNSPEC); ++ AID_UNSPEC); + } /* sync local-RIB first */ if (reconf_in) -- pt_dump(rde_softreconfig_in, NULL, AF_UNSPEC); -+ rib_dump(&ribs[0], rde_softreconfig_in, NULL, -+ AF_UNSPEC); + rib_dump(&ribs[0], rde_softreconfig_in, NULL, +- AF_UNSPEC); ++ AID_UNSPEC); /* then sync peers */ -- if (reconf_out) -- pt_dump(rde_softreconfig_out, NULL, AF_UNSPEC); -+ if (reconf_out) { -+ int i; + if (reconf_out) { + int i; +- for (i = 1; i < rib_size; i++) + for (i = 1; i < rib_size; i++) { + if (ribs[i].state == RIB_NEW) + /* already synced by _load */ + continue; -+ rib_dump(&ribs[i], rde_softreconfig_out, -+ NULL, AF_UNSPEC); + rib_dump(&ribs[i], rde_softreconfig_out, +- NULL, AF_UNSPEC); ++ NULL, AID_UNSPEC); + } -+ } + } while ((r = TAILQ_FIRST(rules_l)) != NULL) { - TAILQ_REMOVE(rules_l, r, entry); -@@ -689,30 +729,15 @@ rde_dispatch_imsg_parent(struct imsgbuf - log_warnx("wrong imsg len"); - break; +@@ -688,10 +689,6 @@ rde_dispatch_imsg_parent(struct imsgbuf } -- -- xmrt = calloc(1, sizeof(struct mrt)); -- if (xmrt == NULL) -- fatal("rde_dispatch_imsg_parent"); -- memcpy(xmrt, imsg.data, sizeof(struct mrt)); -- TAILQ_INIT(&xmrt->bufs); -- -- if ((xmrt->fd = imsg_get_fd(ibuf)) == -1) -+ memcpy(&xmrt, imsg.data, sizeof(xmrt)); -+ if ((fd = imsg.fd) == -1) - log_warnx("expected to receive fd for mrt dump " - "but didn't receive any"); -- -- if (xmrt->type == MRT_TABLE_DUMP) { -- /* do not dump if another is still running */ -- if (mrt == NULL || mrt->queued == 0) { -- free(mrt); -- mrt = xmrt; -- mrt_clear_seq(); -- pt_dump(mrt_dump_upcall, mrt, -- AF_UNSPEC); -- break; -- } + free(rules_l); + rules_l = newrules; +- for (rid = 0; rid < rib_size; rid++) { +- if (ribs[rid].state == RIB_DELETE) +- rib_free(&ribs[rid]); - } -- close(xmrt->fd); -- free(xmrt); -+ else if (xmrt.type == MRT_TABLE_DUMP || -+ xmrt.type == MRT_TABLE_DUMP_MP) { -+ rde_dump_mrt_new(&xmrt, imsg.hdr.pid, fd); -+ } else -+ close(fd); + log_info("RDE reconfigured"); break; - case IMSG_MRT_CLOSE: - /* ignore end message because a dump is atomic */ -@@ -729,7 +754,7 @@ int + case IMSG_NEXTHOP_UPDATE: +@@ -744,6 +741,8 @@ rde_dispatch_imsg_parent(struct imsgbuf + int rde_update_dispatch(struct imsg *imsg) { ++ struct bgpd_addr prefix; ++ struct mpattr mpa; struct rde_peer *peer; -- struct rde_aspath *asp = NULL, *fasp; -+ struct rde_aspath *asp = NULL; + struct rde_aspath *asp = NULL; u_char *p, *mpp = NULL; - int error = -1, pos = 0; - u_int16_t afi, len, mplen; -@@ -794,20 +819,15 @@ rde_update_dispatch(struct imsg *imsg) +@@ -752,9 +751,7 @@ rde_update_dispatch(struct imsg *imsg) + u_int16_t withdrawn_len; + u_int16_t attrpath_len; + u_int16_t nlri_len; +- u_int8_t prefixlen, safi, subtype; +- struct bgpd_addr prefix; +- struct mpattr mpa; ++ u_int8_t aid, prefixlen, safi, subtype; + + peer = peer_get(imsg->hdr.peerid); + if (peer == NULL) /* unknown peer, cannot happen */ +@@ -810,14 +807,7 @@ rde_update_dispatch(struct imsg *imsg) goto done; } - /* -- * if either ATTR_NEW_AGGREGATOR or ATTR_NEW_ASPATH is present +- * if either ATTR_AS4_AGGREGATOR or ATTR_AS4_PATH is present - * try to fixup the attributes. - * XXX do not fixup if F_ATTR_LOOP is set. - */ @@ -499,176 +406,222 @@ diff -u -p -r1.1.1.1 -r1.6 /* enforce remote AS if requested */ if (asp->flags & F_ATTR_ASPATH && - peer->conf.enforce_as == ENFORCE_AS_ON) - if (peer->conf.remote_as != - aspath_neighbor(asp->aspath)) { -+ log_peer_warnx(&peer->conf, "bad path, " -+ "enforce remote-as enabled"); - rde_update_err(peer, ERR_UPDATE, ERR_UPD_ASPATH, - NULL, 0); - goto done; -@@ -850,14 +870,19 @@ rde_update_dispatch(struct imsg *imsg) +@@ -860,9 +850,9 @@ rde_update_dispatch(struct imsg *imsg) + p += pos; + len -= pos; + +- if (peer->capa_received.mp_v4 == SAFI_NONE && +- peer->capa_received.mp_v6 != SAFI_NONE) { +- log_peer_warnx(&peer->conf, "bad AFI, IPv4 disabled"); ++ if (peer->capa.mp[AID_INET] == 0) { ++ log_peer_warnx(&peer->conf, ++ "bad withdraw, %s disabled", aid2str(AID_INET)); + rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR, + NULL, 0); goto done; - } - -- peer->prefix_rcvd_withdraw++; -- rde_update_log("withdraw", peer, NULL, &prefix, prefixlen); -- prefix_remove(peer, &prefix, prefixlen, F_LOCAL); -- prefix_remove(peer, &prefix, prefixlen, F_ORIGINAL); -+ rde_update_withdraw(peer, &prefix, prefixlen); - } - -- if (attrpath_len == 0) /* 0 = no NLRI information in this message */ -+ if (attrpath_len == 0) { -+ /* 0 = no NLRI information in this message */ -+ if (nlri_len != 0) { -+ /* crap at end of update which should not be there */ -+ rde_update_err(peer, ERR_UPDATE, -+ ERR_UPD_ATTRLIST, NULL, 0); -+ return (-1); +@@ -892,15 +882,25 @@ rde_update_dispatch(struct imsg *imsg) + afi = ntohs(afi); + safi = *mpp++; + mplen--; +- switch (afi) { +- case AFI_IPv6: +- if (peer->capa_received.mp_v6 == SAFI_NONE) { +- log_peer_warnx(&peer->conf, "bad AFI, " +- "IPv6 disabled"); +- rde_update_err(peer, ERR_UPDATE, +- ERR_UPD_OPTATTR, NULL, 0); +- goto done; +- } ++ ++ if (afi2aid(afi, safi, &aid) == -1) { ++ log_peer_warnx(&peer->conf, ++ "bad AFI/SAFI pair in withdraw"); ++ rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR, ++ NULL, 0); ++ goto done; + } - return (0); -+ } - - /* withdraw MP_UNREACH_NLRI if available */ - if (mpa.unreach_len != 0) { -@@ -900,13 +925,7 @@ rde_update_dispatch(struct imsg *imsg) - mpp += pos; - mplen -= pos; - -- peer->prefix_rcvd_withdraw++; -- rde_update_log("withdraw", peer, NULL, -- &prefix, prefixlen); -- prefix_remove(peer, &prefix, prefixlen, -- F_LOCAL); -- prefix_remove(peer, &prefix, prefixlen, -- F_ORIGINAL); -+ rde_update_withdraw(peer, &prefix, prefixlen); ++ ++ if (peer->capa.mp[aid] == 0) { ++ log_peer_warnx(&peer->conf, ++ "bad withdraw, %s disabled", aid2str(aid)); ++ rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR, ++ NULL, 0); ++ goto done; ++ } ++ ++ switch (aid) { ++ case AID_INET6: + while (mplen > 0) { + if ((pos = rde_update_get_prefix6(mpp, mplen, + &prefix, &prefixlen)) == -1) { +@@ -926,6 +926,32 @@ rde_update_dispatch(struct imsg *imsg) + rde_update_withdraw(peer, &prefix, prefixlen); } break; ++ case AID_VPN_IPv4: ++ while (mplen > 0) { ++ if ((pos = rde_update_get_vpn4(mpp, mplen, ++ &prefix, &prefixlen)) == -1) { ++ log_peer_warnx(&peer->conf, ++ "bad VPNv4 withdraw prefix"); ++ rde_update_err(peer, ERR_UPDATE, ++ ERR_UPD_OPTATTR, ++ mpa.unreach, mpa.unreach_len); ++ goto done; ++ } ++ if (prefixlen > 32) { ++ log_peer_warnx(&peer->conf, ++ "bad VPNv4 withdraw prefix"); ++ rde_update_err(peer, ERR_UPDATE, ++ ERR_UPD_OPTATTR, ++ mpa.unreach, mpa.unreach_len); ++ goto done; ++ } ++ ++ mpp += pos; ++ mplen -= pos; ++ ++ rde_update_withdraw(peer, &prefix, prefixlen); ++ } ++ break; default: -@@ -954,17 +973,7 @@ rde_update_dispatch(struct imsg *imsg) - goto done; - } - -- peer->prefix_rcvd_update++; -- /* add original path to the Adj-RIB-In */ -- if (peer->conf.softreconfig_in) -- path_update(peer, asp, &prefix, prefixlen, F_ORIGINAL); -- -- /* input filter */ -- if (rde_filter(&fasp, rules_l, peer, asp, &prefix, prefixlen, -- peer, DIR_IN) == ACTION_DENY) { -- path_put(fasp); -- continue; -- } -+ rde_update_update(peer, asp, &prefix, prefixlen); - - /* max prefix checker */ - if (peer->conf.max_prefix && -@@ -972,20 +981,9 @@ rde_update_dispatch(struct imsg *imsg) - log_peer_warnx(&peer->conf, "prefix limit reached"); - rde_update_err(peer, ERR_CEASE, ERR_CEASE_MAX_PREFIX, + /* silently ignore unsupported multiprotocol AF */ + break; +@@ -963,9 +989,9 @@ rde_update_dispatch(struct imsg *imsg) + p += pos; + nlri_len -= pos; + +- if (peer->capa_received.mp_v4 == SAFI_NONE && +- peer->capa_received.mp_v6 != SAFI_NONE) { +- log_peer_warnx(&peer->conf, "bad AFI, IPv4 disabled"); ++ if (peer->capa.mp[AID_INET] == 0) { ++ log_peer_warnx(&peer->conf, ++ "bad update, %s disabled", aid2str(AID_INET)); + rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR, NULL, 0); -- path_put(fasp); goto done; - } - -- if (fasp == NULL) -- fasp = asp; -- -- rde_update_log("update", peer, &fasp->nexthop->exit_nexthop, -- &prefix, prefixlen); -- path_update(peer, fasp, &prefix, prefixlen, F_LOCAL); -- -- /* free modified aspath */ -- if (fasp != asp) -- path_put(fasp); - } - - /* add MP_REACH_NLRI if available */ -@@ -1008,7 +1006,7 @@ rde_update_dispatch(struct imsg *imsg) +@@ -995,6 +1021,22 @@ rde_update_dispatch(struct imsg *imsg) + safi = *mpp++; + mplen--; + ++ if (afi2aid(afi, safi, &aid) == -1) { ++ log_peer_warnx(&peer->conf, ++ "bad AFI/SAFI pair in update"); ++ rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR, ++ NULL, 0); ++ goto done; ++ } ++ ++ if (peer->capa.mp[aid] == 0) { ++ log_peer_warnx(&peer->conf, ++ "bad update, %s disabled", aid2str(aid)); ++ rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR, ++ NULL, 0); ++ goto done; ++ } ++ + /* + * this works because asp is not linked. + * But first unlock the previously locked nexthop. +@@ -1004,8 +1046,8 @@ rde_update_dispatch(struct imsg *imsg) (void)nexthop_delete(asp->nexthop); asp->nexthop = NULL; } - if ((pos = rde_get_mp_nexthop(mpp, mplen, afi, asp)) == -1) { -+ if ((pos = rde_get_mp_nexthop(mpp, mplen, afi, asp, peer)) == -1) { - log_peer_warnx(&peer->conf, "bad IPv6 nlri prefix"); +- log_peer_warnx(&peer->conf, "bad IPv6 nlri prefix"); ++ if ((pos = rde_get_mp_nexthop(mpp, mplen, aid, asp, peer)) == -1) { ++ log_peer_warnx(&peer->conf, "bad nlri prefix"); rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR, mpa.reach, mpa.reach_len); -@@ -1047,19 +1045,8 @@ rde_update_dispatch(struct imsg *imsg) - mpp += pos; - mplen -= pos; - -- peer->prefix_rcvd_update++; -- /* add original path to the Adj-RIB-In */ -- if (peer->conf.softreconfig_in) -- path_update(peer, asp, &prefix, -- prefixlen, F_ORIGINAL); + goto done; +@@ -1013,16 +1055,8 @@ rde_update_dispatch(struct imsg *imsg) + mpp += pos; + mplen -= pos; + +- switch (afi) { +- case AFI_IPv6: +- if (peer->capa_received.mp_v6 == SAFI_NONE) { +- log_peer_warnx(&peer->conf, "bad AFI, " +- "IPv6 disabled"); +- rde_update_err(peer, ERR_UPDATE, +- ERR_UPD_OPTATTR, NULL, 0); +- goto done; +- } - -- /* input filter */ -- if (rde_filter(&fasp, rules_l, peer, asp, -- &prefix, prefixlen, peer, DIR_IN) == -- ACTION_DENY) { -- path_put(fasp); -- continue; -- } -+ rde_update_update(peer, asp, &prefix, -+ prefixlen); - - /* max prefix checker */ - if (peer->conf.max_prefix && -@@ -1068,22 +1055,9 @@ rde_update_dispatch(struct imsg *imsg) - "prefix limit reached"); - rde_update_err(peer, ERR_CEASE, - ERR_CEASE_MAX_PREFIX, NULL, 0); -- path_put(fasp); - goto done; - } ++ switch (aid) { ++ case AID_INET6: + while (mplen > 0) { + if ((pos = rde_update_get_prefix6(mpp, mplen, + &prefix, &prefixlen)) == -1) { +@@ -1058,6 +1092,42 @@ rde_update_dispatch(struct imsg *imsg) -- if (fasp == NULL) -- fasp = asp; -- -- rde_update_log("update", peer, -- &asp->nexthop->exit_nexthop, -- &prefix, prefixlen); -- path_update(peer, fasp, &prefix, prefixlen, -- F_LOCAL); -- -- /* free modified aspath */ -- if (fasp != asp) -- path_put(fasp); } break; - default: -@@ -1106,6 +1080,76 @@ done: - return (error); - } - -+extern u_int16_t rib_size; ++ case AID_VPN_IPv4: ++ while (mplen > 0) { ++ if ((pos = rde_update_get_vpn4(mpp, mplen, ++ &prefix, &prefixlen)) == -1) { ++ log_peer_warnx(&peer->conf, ++ "bad VPNv4 nlri prefix"); ++ rde_update_err(peer, ERR_UPDATE, ++ ERR_UPD_OPTATTR, ++ mpa.reach, mpa.reach_len); ++ goto done; ++ } ++ if (prefixlen > 32) { ++ rde_update_err(peer, ERR_UPDATE, ++ ERR_UPD_OPTATTR, ++ mpa.reach, mpa.reach_len); ++ goto done; ++ } + -+void -+rde_update_update(struct rde_peer *peer, struct rde_aspath *asp, -+ struct bgpd_addr *prefix, u_int8_t prefixlen) -+{ -+ struct rde_aspath *fasp; -+ enum filter_actions action; -+ int r = 0, f = 0; -+ u_int16_t i; ++ mpp += pos; ++ mplen -= pos; + -+ peer->prefix_rcvd_update++; -+ /* add original path to the Adj-RIB-In */ -+ if (peer->conf.softreconfig_in) -+ r += path_update(&ribs[0], peer, asp, prefix, prefixlen); ++ rde_update_update(peer, asp, &prefix, ++ prefixlen); + -+ for (i = 1; i < rib_size; i++) { -+ /* input filter */ ++ /* max prefix checker */ ++ if (peer->conf.max_prefix && ++ peer->prefix_cnt >= peer->conf.max_prefix) { ++ log_peer_warnx(&peer->conf, ++ "prefix limit reached"); ++ rde_update_err(peer, ERR_CEASE, ++ ERR_CEASE_MAX_PREFIX, NULL, 0); ++ goto done; ++ } ++ ++ } ++ break; + default: + /* silently ignore unsupported multiprotocol AF */ + break; +@@ -1085,7 +1155,8 @@ rde_update_update(struct rde_peer *peer, + struct bgpd_addr *prefix, u_int8_t prefixlen) + { + struct rde_aspath *fasp; +- int r = 0; ++ enum filter_actions action; ++ int r = 0, f = 0; + u_int16_t i; + + peer->prefix_rcvd_update++; +@@ -1095,18 +1166,24 @@ rde_update_update(struct rde_peer *peer, + + for (i = 1; i < rib_size; i++) { + /* input filter */ +- if (rde_filter(i, &fasp, rules_l, peer, asp, prefix, prefixlen, +- peer, DIR_IN) == ACTION_DENY) +- goto done; + action = rde_filter(i, &fasp, rules_l, peer, asp, prefix, + prefixlen, peer, DIR_IN); -+ -+ if (fasp == NULL) -+ fasp = asp; -+ + + if (fasp == NULL) + fasp = asp; + +- rde_update_log("update", i, peer, &fasp->nexthop->exit_nexthop, +- prefix, prefixlen); +- r += path_update(&ribs[i], peer, fasp, prefix, prefixlen); + if (action == ACTION_ALLOW) { + rde_update_log("update", i, peer, + &fasp->nexthop->exit_nexthop, prefix, prefixlen); @@ -680,45 +633,30 @@ diff -u -p -r1.1.1.1 -r1.6 + NULL, prefix, prefixlen); + f++; + } -+ -+ /* free modified aspath */ -+ if (fasp != asp) -+ path_put(fasp); -+ } -+ -+ if (r) -+ peer->prefix_cnt++; + +-done: + /* free modified aspath */ + if (fasp != asp) + path_put(fasp); +@@ -1114,6 +1191,8 @@ done: + + if (r) + peer->prefix_cnt++; + else if (f) + peer->prefix_cnt--; -+} -+ -+void -+rde_update_withdraw(struct rde_peer *peer, struct bgpd_addr *prefix, -+ u_int8_t prefixlen) -+{ -+ int r = 0; -+ u_int16_t i; -+ -+ peer->prefix_rcvd_withdraw++; -+ -+ for (i = rib_size - 1; ; i--) { -+ if (prefix_remove(&ribs[i], peer, prefix, prefixlen, 0)) { -+ rde_update_log("withdraw", i, peer, NULL, prefix, -+ prefixlen); -+ r++; -+ } -+ if (i == 0) -+ break; -+ } -+ -+ if (r) -+ peer->prefix_cnt--; -+} -+ - /* - * BGP UPDATE parser functions - */ -@@ -1272,9 +1316,19 @@ bad_flags: + } + + void +@@ -1248,7 +1327,7 @@ bad_flags: + a->flags |= F_ATTR_NEXTHOP; + + bzero(&nexthop, sizeof(nexthop)); +- nexthop.af = AF_INET; ++ nexthop.aid = AID_INET; + UPD_READ(&nexthop.v4.s_addr, p, plen, 4); + /* + * Check if the nexthop is a valid IP address. We consider +@@ -1305,9 +1384,19 @@ bad_flags: goto optattr; case ATTR_AGGREGATOR: if ((!rde_as4byte(peer) && attr_len != 6) || @@ -741,7 +679,7 @@ diff -u -p -r1.1.1.1 -r1.6 goto bad_flags; if (!rde_as4byte(peer)) { /* need to inflate aggregator AS to 4-byte */ -@@ -1290,8 +1344,17 @@ bad_flags: +@@ -1323,8 +1412,33 @@ bad_flags: /* 4-byte ready server take the default route */ goto optattr; case ATTR_COMMUNITIES: @@ -758,17 +696,31 @@ diff -u -p -r1.1.1.1 -r1.6 + else + a->flags |= F_ATTR_PARSE_ERR; + } ++ if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ++ ATTR_PARTIAL)) ++ goto bad_flags; ++ goto optattr; ++ case ATTR_EXT_COMMUNITIES: ++ if ((attr_len & 0x7) != 0) { ++ /* ++ * mark update as bad and withdraw all routes as per ++ * draft-ietf-idr-optional-transitive-00.txt ++ * but only if partial bit is set ++ */ ++ if ((flags & ATTR_PARTIAL) == 0) ++ goto bad_len; ++ else ++ a->flags |= F_ATTR_PARSE_ERR; ++ } if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL)) goto bad_flags; -@@ -1336,15 +1399,21 @@ bad_flags: - mpa->unreach_len = attr_len; +@@ -1370,8 +1484,14 @@ bad_flags: plen += attr_len; break; -- case ATTR_NEW_AGGREGATOR: + case ATTR_AS4_AGGREGATOR: - if (attr_len != 8) - goto bad_len; -+ case ATTR_AS4_AGGREGATOR: + if (attr_len != 8) { + /* see ATTR_AGGREGATOR ... */ + if ((flags & ATTR_PARTIAL) == 0) @@ -780,14 +732,7 @@ diff -u -p -r1.1.1.1 -r1.6 if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, ATTR_PARTIAL)) goto bad_flags; - a->flags |= F_ATTR_AS4BYTE_NEW; - goto optattr; -- case ATTR_NEW_ASPATH: -+ case ATTR_AS4_PATH: - if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, - ATTR_PARTIAL)) - goto bad_flags; -@@ -1352,13 +1421,21 @@ bad_flags: +@@ -1385,13 +1505,21 @@ bad_flags: /* * XXX RFC does not specify how to handle errors. * XXX Instead of dropping the session because of a @@ -815,19 +760,36 @@ diff -u -p -r1.1.1.1 -r1.6 } a->flags |= F_ATTR_AS4BYTE_NEW; goto optattr; -@@ -1408,7 +1485,7 @@ rde_attr_missing(struct rde_aspath *a, i +@@ -1440,8 +1568,8 @@ rde_attr_missing(struct rde_aspath *a, i + } int - rde_get_mp_nexthop(u_char *data, u_int16_t len, u_int16_t afi, +-rde_get_mp_nexthop(u_char *data, u_int16_t len, u_int16_t afi, - struct rde_aspath *asp) ++rde_get_mp_nexthop(u_char *data, u_int16_t len, u_int8_t aid, + struct rde_aspath *asp, struct rde_peer *peer) { struct bgpd_addr nexthop; u_int8_t totlen, nhlen; -@@ -1440,6 +1517,18 @@ rde_get_mp_nexthop(u_char *data, u_int16 +@@ -1457,8 +1585,9 @@ rde_get_mp_nexthop(u_char *data, u_int16 + return (-1); + + bzero(&nexthop, sizeof(nexthop)); +- switch (afi) { +- case AFI_IPv6: ++ nexthop.aid = aid; ++ switch (aid) { ++ case AID_INET6: + /* + * RFC2545 describes that there may be a link-local + * address carried in nexthop. Yikes! +@@ -1471,72 +1600,143 @@ rde_get_mp_nexthop(u_char *data, u_int16 + log_warnx("bad multiprotocol nexthop, bad size"); + return (-1); } - nexthop.af = AF_INET6; +- nexthop.af = AF_INET6; memcpy(&nexthop.v6.s6_addr, data, 16); +- asp->nexthop = nexthop_get(&nexthop); +#if defined(__KAME__) && defined(IPV6_LINKLOCAL_PEER) + if (IN6_IS_ADDR_LINKLOCAL(&nexthop.v6) && + peer->conf.lliface[0]) { @@ -840,35 +802,225 @@ diff -u -p -r1.1.1.1 -r1.6 + log_warnx("bad interface: %s", peer->conf.lliface); + } +#endif - asp->nexthop = nexthop_get(&nexthop); ++ break; ++ case AID_VPN_IPv4: /* - * lock the nexthop because it is not yet linked else -@@ -1540,13 +1629,12 @@ rde_update_err(struct rde_peer *peer, u_ - imsg_add(wbuf, &suberr, sizeof(suberr)) == -1 || - imsg_add(wbuf, data, size) == -1) - fatal("imsg_add error"); -- if (imsg_close(ibuf_se, wbuf) == -1) -- fatal("imsg_close error"); -+ imsg_close(ibuf_se, wbuf); - peer->state = PEER_ERR; +- * lock the nexthop because it is not yet linked else +- * withdraws may remove this nexthop which in turn would +- * cause a use after free error. ++ * Neither RFC4364 nor RFC3107 specify the format of the ++ * nexthop in an explicit way. The quality of RFC went down ++ * the toilet the larger the the number got. ++ * RFC4364 is very confusing about VPN-IPv4 address and the ++ * VPN-IPv4 prefix that carries also a MPLS label. ++ * So the nexthop is a 12-byte address with a 64bit RD and ++ * an IPv4 address following. In the nexthop case the RD can ++ * be ignored. ++ * Since the nexthop has to be in the main IPv4 table just ++ * create an AID_INET nexthop. So we don't need to handle ++ * AID_VPN_IPv4 in nexthop and kroute. + */ +- asp->nexthop->refcnt++; +- +- /* ignore reserved (old SNPA) field as per RFC 4760 */ +- totlen += nhlen + 1; +- data += nhlen + 1; +- +- return (totlen); +- default: +- log_warnx("bad multiprotocol nexthop, bad AF"); ++ if (nhlen != 12) { ++ log_warnx("bad multiprotocol nexthop, bad size"); ++ return (-1); ++ } ++ data += sizeof(u_int64_t); ++ nexthop.aid = AID_INET; ++ memcpy(&nexthop.v4, data, sizeof(nexthop.v4)); + break; ++ default: ++ log_warnx("bad multiprotocol nexthop, bad AID"); ++ return (-1); + } + +- return (-1); ++ asp->nexthop = nexthop_get(&nexthop); ++ /* ++ * lock the nexthop because it is not yet linked else ++ * withdraws may remove this nexthop which in turn would ++ * cause a use after free error. ++ */ ++ asp->nexthop->refcnt++; ++ ++ /* ignore reserved (old SNPA) field as per RFC4760 */ ++ totlen += nhlen + 1; ++ data += nhlen + 1; ++ ++ return (totlen); ++} ++ ++int ++rde_update_extract_prefix(u_char *p, u_int16_t len, void *va, ++ u_int8_t pfxlen, u_int8_t max) ++{ ++ static u_char addrmask[] = { ++ 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; ++ u_char *a = va; ++ int i; ++ u_int16_t plen = 0; ++ ++ for (i = 0; pfxlen && i < max; i++) { ++ if (len <= plen) ++ return (-1); ++ if (pfxlen < 8) { ++ a[i] = *p++ & addrmask[pfxlen]; ++ plen++; ++ break; ++ } else { ++ a[i] = *p++; ++ plen++; ++ pfxlen -= 8; ++ } ++ } ++ return (plen); } - void --rde_update_log(const char *message, -+rde_update_log(const char *message, u_int16_t rid, - const struct rde_peer *peer, const struct bgpd_addr *next, - const struct bgpd_addr *prefix, u_int8_t prefixlen) + int + rde_update_get_prefix(u_char *p, u_int16_t len, struct bgpd_addr *prefix, + u_int8_t *prefixlen) { -@@ -1563,7 +1651,7 @@ rde_update_log(const char *message, - if (asprintf(&p, "%s/%u", log_addr(prefix), prefixlen) == -1) - p = NULL; - l = log_fmt_peer(&peer->conf); -- log_info("%s AS%s: %s %s%s", -+ log_info("Rib %s: %s AS%s: %s %s%s", ribs[rid].name, - l, log_as(peer->conf.remote_as), message, - p ? p : "out of memory", n ? n : ""); - -@@ -1584,9 +1672,17 @@ rde_as4byte_fixup(struct rde_peer *peer, +- int i; +- u_int8_t pfxlen; +- u_int16_t plen; +- union { +- struct in_addr a32; +- u_int8_t a8[4]; +- } addr; ++ u_int8_t pfxlen; ++ int plen; + + if (len < 1) + return (-1); + +- memcpy(&pfxlen, p, 1); +- p += 1; +- plen = 1; ++ pfxlen = *p++; ++ len--; + + bzero(prefix, sizeof(struct bgpd_addr)); +- addr.a32.s_addr = 0; +- for (i = 0; i <= 3; i++) { +- if (pfxlen > i * 8) { +- if (len - plen < 1) +- return (-1); +- memcpy(&addr.a8[i], p++, 1); +- plen++; +- } +- } +- prefix->af = AF_INET; +- prefix->v4.s_addr = addr.a32.s_addr; ++ prefix->aid = AID_INET; + *prefixlen = pfxlen; + +- return (plen); ++ if ((plen = rde_update_extract_prefix(p, len, &prefix->v4, pfxlen, ++ sizeof(prefix->v4))) == -1) ++ return (-1); ++ ++ return (plen + 1); /* pfxlen needs to be added */ + } + + int + rde_update_get_prefix6(u_char *p, u_int16_t len, struct bgpd_addr *prefix, + u_int8_t *prefixlen) + { +- int i; ++ int plen; + u_int8_t pfxlen; +- u_int16_t plen; ++ ++ if (len < 1) ++ return (-1); ++ ++ pfxlen = *p++; ++ len--; ++ ++ bzero(prefix, sizeof(struct bgpd_addr)); ++ prefix->aid = AID_INET6; ++ *prefixlen = pfxlen; ++ ++ if ((plen = rde_update_extract_prefix(p, len, &prefix->v6, pfxlen, ++ sizeof(prefix->v6))) == -1) ++ return (-1); ++ ++ return (plen + 1); /* pfxlen needs to be added */ ++} ++ ++int ++rde_update_get_vpn4(u_char *p, u_int16_t len, struct bgpd_addr *prefix, ++ u_int8_t *prefixlen) ++{ ++ int rv, done = 0; ++ u_int8_t pfxlen; ++ u_int16_t plen; + + if (len < 1) + return (-1); +@@ -1546,18 +1746,43 @@ rde_update_get_prefix6(u_char *p, u_int1 + plen = 1; + + bzero(prefix, sizeof(struct bgpd_addr)); +- for (i = 0; i <= 15; i++) { +- if (pfxlen > i * 8) { +- if (len - plen < 1) +- return (-1); +- memcpy(&prefix->v6.s6_addr[i], p++, 1); +- plen++; +- } +- } +- prefix->af = AF_INET6; ++ ++ /* label stack */ ++ do { ++ if (len - plen < 3 || pfxlen < 3 * 8) ++ return (-1); ++ if (prefix->vpn4.labellen + 3U > ++ sizeof(prefix->vpn4.labelstack)) ++ return (-1); ++ prefix->vpn4.labelstack[prefix->vpn4.labellen++] = *p++; ++ prefix->vpn4.labelstack[prefix->vpn4.labellen++] = *p++; ++ prefix->vpn4.labelstack[prefix->vpn4.labellen] = *p++; ++ if (prefix->vpn4.labelstack[prefix->vpn4.labellen] & ++ BGP_MPLS_BOS) ++ done = 1; ++ prefix->vpn4.labellen++; ++ plen += 3; ++ pfxlen -= 3 * 8; ++ } while (!done); ++ ++ /* RD */ ++ if (len - plen < (int)sizeof(u_int64_t) || ++ pfxlen < sizeof(u_int64_t) * 8) ++ return (-1); ++ memcpy(&prefix->vpn4.rd, p, sizeof(u_int64_t)); ++ pfxlen -= sizeof(u_int64_t) * 8; ++ p += sizeof(u_int64_t); ++ plen += sizeof(u_int64_t); ++ ++ /* prefix */ ++ prefix->aid = AID_VPN_IPv4; + *prefixlen = pfxlen; + +- return (plen); ++ if ((rv = rde_update_extract_prefix(p, len, &prefix->vpn4.addr, ++ pfxlen, sizeof(prefix->vpn4.addr))) == -1) ++ return (-1); ++ ++ return (plen + rv); + } + + void +@@ -1616,6 +1841,14 @@ rde_as4byte_fixup(struct rde_peer *peer, struct attr *nasp, *naggr, *oaggr; u_int32_t as; @@ -881,37 +1033,9 @@ diff -u -p -r1.1.1.1 -r1.6 + return; + /* first get the attributes */ -- nasp = attr_optget(a, ATTR_NEW_ASPATH); -- naggr = attr_optget(a, ATTR_NEW_AGGREGATOR); -+ nasp = attr_optget(a, ATTR_AS4_PATH); -+ naggr = attr_optget(a, ATTR_AS4_AGGREGATOR); - - if (rde_as4byte(peer)) { - /* NEW session using 4-byte ASNs */ -@@ -1601,7 +1697,7 @@ rde_as4byte_fixup(struct rde_peer *peer, - if ((oaggr = attr_optget(a, ATTR_AGGREGATOR))) { - memcpy(&as, oaggr->data, sizeof(as)); - if (ntohl(as) != AS_TRANS) { -- /* per RFC draft ignore NEW_ASPATH and NEW_AGGREGATOR */ -+ /* per RFC ignore AS4_PATH and AS4_AGGREGATOR */ - if (nasp) - attr_free(a, nasp); - if (naggr) -@@ -1616,11 +1712,11 @@ rde_as4byte_fixup(struct rde_peer *peer, - fatalx("attr_optadd failed but impossible"); - } - } -- /* there is no need for NEW_AGGREGATOR any more */ -+ /* there is no need for AS4_AGGREGATOR any more */ - if (naggr) - attr_free(a, naggr); - -- /* merge NEW_ASPATH with ASPATH */ -+ /* merge AS4_PATH with ASPATH */ - if (nasp) - aspath_merge(a, nasp); - } -@@ -1637,6 +1733,10 @@ rde_reflector(struct rde_peer *peer, str + nasp = attr_optget(a, ATTR_AS4_PATH); + naggr = attr_optget(a, ATTR_AS4_AGGREGATOR); +@@ -1669,6 +1902,10 @@ rde_reflector(struct rde_peer *peer, str u_int16_t len; u_int32_t id; @@ -922,323 +1046,98 @@ diff -u -p -r1.1.1.1 -r1.6 /* check for originator id if eq router_id drop */ if ((a = attr_optget(asp, ATTR_ORIGINATOR_ID)) != NULL) { if (memcmp(&conf->bgpid, a->data, sizeof(conf->bgpid)) == 0) { -@@ -1703,7 +1803,6 @@ rde_dump_rib_as(struct prefix *p, struct - rib.med = asp->med; - rib.prefix_cnt = asp->prefix_cnt; - rib.active_cnt = asp->active_cnt; -- rib.adjrib_cnt = asp->adjrib_cnt; - strlcpy(rib.descr, asp->peer->conf.descr, sizeof(rib.descr)); - memcpy(&rib.remote_addr, &asp->peer->remote_addr, - sizeof(rib.remote_addr)); -@@ -1724,7 +1823,7 @@ rde_dump_rib_as(struct prefix *p, struct +@@ -1748,8 +1985,8 @@ rde_dump_rib_as(struct prefix *p, struct + /* announced network may have a NULL nexthop */ + bzero(&rib.true_nexthop, sizeof(rib.true_nexthop)); + bzero(&rib.exit_nexthop, sizeof(rib.exit_nexthop)); +- rib.true_nexthop.af = p->prefix->af; +- rib.exit_nexthop.af = p->prefix->af; ++ rib.true_nexthop.aid = p->prefix->aid; ++ rib.exit_nexthop.aid = p->prefix->aid; + } + pt_getaddr(p->prefix, &rib.prefix); rib.prefixlen = p->prefix->prefixlen; - rib.origin = asp->origin; - rib.flags = 0; -- if (p->prefix->active == p) -+ if (p->rib->active == p) - rib.flags |= F_RIB_ACTIVE; - if (asp->peer->conf.ebgp == 0) - rib.flags |= F_RIB_INTERNAL; -@@ -1743,8 +1842,7 @@ rde_dump_rib_as(struct prefix *p, struct - imsg_add(wbuf, aspath_dump(asp->aspath), - rib.aspath_len) == -1) - return; -- if (imsg_close(ibuf_se_ctl, wbuf) == -1) -- return; -+ imsg_close(ibuf_se_ctl, wbuf); - - if (flags & F_CTL_DETAIL) - for (l = 0; l < asp->others_len; l++) { -@@ -1763,8 +1861,7 @@ rde_dump_rib_as(struct prefix *p, struct - buf_free(wbuf); - return; - } -- if (imsg_close(ibuf_se_ctl, wbuf) == -1) -- return; -+ imsg_close(ibuf_se_ctl, wbuf); - } - } - -@@ -1780,7 +1877,7 @@ rde_dump_filterout(struct rde_peer *peer - return; - - pt_getaddr(p->prefix, &addr); -- a = rde_filter(&asp, rules_l, peer, p->aspath, &addr, -+ a = rde_filter(1 /* XXX */, &asp, rules_l, peer, p->aspath, &addr, - p->prefix->prefixlen, p->aspath->peer, DIR_OUT); - if (asp) - asp->peer = p->aspath->peer; -@@ -1799,108 +1896,57 @@ rde_dump_filter(struct prefix *p, struct - { - struct rde_peer *peer; - -- if ((req->flags & F_CTL_ADJ_IN && p->flags & F_ORIGINAL) || -- (!(req->flags & (F_CTL_ADJ_IN|F_CTL_ADJ_OUT)) && -- p->flags & F_LOCAL)) { -+ if (req->flags & F_CTL_ADJ_IN || -+ !(req->flags & (F_CTL_ADJ_IN|F_CTL_ADJ_OUT))) { - if (req->peerid && req->peerid != p->aspath->peer->conf.id) - return; -+ if (req->type == IMSG_CTL_SHOW_RIB_AS && -+ !aspath_match(p->aspath->aspath, req->as.type, req->as.as)) -+ return; -+ if (req->type == IMSG_CTL_SHOW_RIB_COMMUNITY && -+ !rde_filter_community(p->aspath, req->community.as, -+ req->community.type)) -+ return; - rde_dump_rib_as(p, p->aspath, req->pid, req->flags); -- } else if (req->flags & F_CTL_ADJ_OUT && p->flags & F_LOCAL) { -- if (p->prefix->active != p) -+ } else if (req->flags & F_CTL_ADJ_OUT) { -+ if (p->rib->active != p) - /* only consider active prefix */ +@@ -1836,7 +2073,7 @@ rde_dump_filter(struct prefix *p, struct + !aspath_match(p->aspath->aspath, req->as.type, req->as.as)) return; -- - if (req->peerid) { - if ((peer = peer_get(req->peerid)) != NULL) - rde_dump_filterout(peer, p, req); + if (req->type == IMSG_CTL_SHOW_RIB_COMMUNITY && +- !rde_filter_community(p->aspath, req->community.as, ++ !community_match(p->aspath, req->community.as, + req->community.type)) return; - } -- LIST_FOREACH(peer, &peerlist, peer_l) -- rde_dump_filterout(peer, p, req); - } - } - - void --rde_dump_upcall(struct pt_entry *pt, void *ptr) -+rde_dump_upcall(struct rib_entry *re, void *ptr) - { - struct prefix *p; -- struct ctl_show_rib_request *req = ptr; -- -- LIST_FOREACH(p, &pt->prefix_h, prefix_l) -- rde_dump_filter(p, req); --} -+ struct rde_dump_ctx *ctx = ptr; - --void --rde_dump_as(struct ctl_show_rib_request *req) --{ -- extern struct path_table pathtable; -- struct rde_aspath *asp; -- struct prefix *p; -- u_int32_t i; -- -- for (i = 0; i <= pathtable.path_hashmask; i++) { -- LIST_FOREACH(asp, &pathtable.path_hashtbl[i], path_l) { -- if (!aspath_match(asp->aspath, req->as.type, -- req->as.as)) -- continue; -- /* match found */ -- LIST_FOREACH(p, &asp->prefix_h, path_l) -- rde_dump_filter(p, req); -- } -- } -+ LIST_FOREACH(p, &re->prefix_h, rib_l) -+ rde_dump_filter(p, &ctx->req); - } - - void --rde_dump_prefix_upcall(struct pt_entry *pt, void *ptr) -+rde_dump_prefix_upcall(struct rib_entry *re, void *ptr) - { -- struct ctl_show_rib_request *req = ptr; -- struct prefix *p; -- struct bgpd_addr addr; -+ struct rde_dump_ctx *ctx = ptr; -+ struct prefix *p; -+ struct pt_entry *pt; -+ struct bgpd_addr addr; + rde_dump_rib_as(p, p->aspath, req->pid, req->flags); +@@ -1872,7 +2109,7 @@ rde_dump_prefix_upcall(struct rib_entry -+ pt = re->prefix; + pt = re->prefix; pt_getaddr(pt, &addr); -- if (addr.af != req->prefix.af) -+ if (addr.af != ctx->req.prefix.af) +- if (addr.af != ctx->req.prefix.af) ++ if (addr.aid != ctx->req.prefix.aid) return; -- if (req->prefixlen > pt->prefixlen) -+ if (ctx->req.prefixlen > pt->prefixlen) + if (ctx->req.prefixlen > pt->prefixlen) return; -- if (!prefix_compare(&req->prefix, &addr, req->prefixlen)) -- LIST_FOREACH(p, &pt->prefix_h, prefix_l) -- rde_dump_filter(p, req); --} -- --void --rde_dump_prefix(struct ctl_show_rib_request *req) --{ -- struct pt_entry *pt; -- -- if (req->prefixlen == 32) { -- if ((pt = pt_lookup(&req->prefix)) != NULL) -- rde_dump_upcall(pt, req); -- } else if (req->flags & F_LONGER) { -- pt_dump(rde_dump_prefix_upcall, req, req->prefix.af); -- } else { -- if ((pt = pt_get(&req->prefix, req->prefixlen)) != NULL) -- rde_dump_upcall(pt, req); -- } --} -- --void --rde_dump_community(struct ctl_show_rib_request *req) --{ -- extern struct path_table pathtable; -- struct rde_aspath *asp; -- struct prefix *p; -- u_int32_t i; -- -- for (i = 0; i <= pathtable.path_hashmask; i++) { -- LIST_FOREACH(asp, &pathtable.path_hashtbl[i], path_l) { -- if (!rde_filter_community(asp, req->community.as, -- req->community.type)) -- continue; -- /* match found */ -- LIST_FOREACH(p, &asp->prefix_h, path_l) -- rde_dump_filter(p, req); -- } -- } -+ if (!prefix_compare(&ctx->req.prefix, &addr, ctx->req.prefixlen)) -+ LIST_FOREACH(p, &re->prefix_h, rib_l) -+ rde_dump_filter(p, &ctx->req); - } - - void -@@ -1908,7 +1954,9 @@ rde_dump_ctx_new(struct ctl_show_rib_req - enum imsg_type type) - { - struct rde_dump_ctx *ctx; -+ struct rib_entry *re; - u_int error; -+ u_int16_t id; - - if ((ctx = calloc(1, sizeof(*ctx))) == NULL) { - log_warn("rde_dump_ctx_new"); -@@ -1917,52 +1965,89 @@ rde_dump_ctx_new(struct ctl_show_rib_req +@@ -1902,6 +2139,7 @@ rde_dump_ctx_new(struct ctl_show_rib_req + error = CTL_RES_NOSUCHPEER; + imsg_compose(ibuf_se_ctl, IMSG_CTL_RESULT, 0, pid, -1, &error, sizeof(error)); ++ free(ctx); return; } -+ if ((id = rib_find(req->rib)) == RIB_FAILED) { -+ log_warnx("rde_dump_ctx_new: no such rib %s", req->rib); -+ error = CTL_RES_NOSUCHPEER; -+ imsg_compose(ibuf_se_ctl, IMSG_CTL_RESULT, 0, pid, -1, &error, -+ sizeof(error)); -+ return; -+ } -+ - memcpy(&ctx->req, req, sizeof(struct ctl_show_rib_request)); - ctx->req.pid = pid; - ctx->req.type = type; -- ctx->ptc.count = RDE_RUNNER_ROUNDS; -- ctx->af = ctx->req.af; -- if (ctx->af == AF_UNSPEC) -- ctx->af = AF_INET; -- -- TAILQ_INSERT_TAIL(&rde_dump_h, ctx, entry); -+ ctx->ribctx.ctx_count = RDE_RUNNER_ROUNDS; -+ ctx->ribctx.ctx_rib = &ribs[id]; -+ switch (ctx->req.type) { -+ case IMSG_CTL_SHOW_NETWORK: -+ ctx->ribctx.ctx_upcall = network_dump_upcall; -+ break; -+ case IMSG_CTL_SHOW_RIB: -+ case IMSG_CTL_SHOW_RIB_AS: -+ case IMSG_CTL_SHOW_RIB_COMMUNITY: -+ ctx->ribctx.ctx_upcall = rde_dump_upcall; -+ break; -+ case IMSG_CTL_SHOW_RIB_PREFIX: -+ if (req->flags & F_LONGER) { -+ ctx->ribctx.ctx_upcall = rde_dump_prefix_upcall; -+ break; -+ } -+ if (req->prefixlen == 32) -+ re = rib_lookup(&ribs[id], &req->prefix); -+ else -+ re = rib_get(&ribs[id], &req->prefix, req->prefixlen); -+ if (re) -+ rde_dump_upcall(re, ctx); -+ rde_dump_done(ctx); -+ return; -+ default: -+ fatalx("rde_dump_ctx_new: unsupported imsg type"); -+ } -+ ctx->ribctx.ctx_done = rde_dump_done; -+ ctx->ribctx.ctx_arg = ctx; -+ ctx->ribctx.ctx_af = ctx->req.af; -+ rib_dump_r(&ctx->ribctx); + +@@ -1937,7 +2175,7 @@ rde_dump_ctx_new(struct ctl_show_rib_req + } + ctx->ribctx.ctx_done = rde_dump_done; + ctx->ribctx.ctx_arg = ctx; +- ctx->ribctx.ctx_af = ctx->req.af; ++ ctx->ribctx.ctx_aid = ctx->req.aid; + rib_dump_r(&ctx->ribctx); } - void --rde_dump_runner(void) -+rde_dump_done(void *arg) - { -- struct rde_dump_ctx *ctx, *next; -+ struct rde_dump_ctx *ctx = arg; - -- for (ctx = TAILQ_FIRST(&rde_dump_h); ctx != NULL; ctx = next) { -- next = TAILQ_NEXT(ctx, entry); -- if (ctx->ptc.done) { -- imsg_compose(ibuf_se_ctl, IMSG_CTL_END, 0, ctx->req.pid, -- -1, NULL, 0); -- TAILQ_REMOVE(&rde_dump_h, ctx, entry); -- free(ctx); -- continue; -- } -- switch (ctx->req.type) { -- case IMSG_CTL_SHOW_NETWORK: -- pt_dump_r(network_dump_upcall, &ctx->req.pid, -- ctx->af, &ctx->ptc); -- break; -- case IMSG_CTL_SHOW_RIB: -- pt_dump_r(rde_dump_upcall, &ctx->req, ctx->af, -- &ctx->ptc); -- break; -- default: -- fatalx("rde_dump_runner: unsupported imsg type"); -- } -- if (ctx->ptc.done && ctx->req.af == AF_UNSPEC) -- ctx->af = AF_INET6; -- } -+ imsg_compose(ibuf_se_ctl, IMSG_CTL_END, 0, ctx->req.pid, -+ -1, NULL, 0); -+ free(ctx); +@@ -1974,10 +2212,10 @@ rde_dump_mrt_new(struct mrt *mrt, pid_t + ctx->ribctx.ctx_count = RDE_RUNNER_ROUNDS; + ctx->ribctx.ctx_rib = &ribs[id]; + ctx->ribctx.ctx_upcall = mrt_dump_upcall; +- ctx->ribctx.ctx_done = mrt_dump_done; ++ ctx->ribctx.ctx_done = mrt_done; + ctx->ribctx.ctx_arg = &ctx->mrt; +- ctx->ribctx.ctx_af = AF_UNSPEC; +- LIST_INSERT_HEAD(&rde_mrts, &ctx->mrt, entry); ++ ctx->ribctx.ctx_aid = AID_UNSPEC; ++ LIST_INSERT_HEAD(&rde_mrts, ctx, entry); + rde_mrt_cnt++; + rib_dump_r(&ctx->ribctx); } +@@ -2011,8 +2249,8 @@ rde_send_kroute(struct prefix *new, stru + } --int --rde_dump_pending(void) -+void -+rde_dump_mrt_new(struct mrt *mrt, pid_t pid, int fd) - { -- return (!TAILQ_EMPTY(&rde_dump_h)); -+ struct rde_mrt_ctx *ctx; -+ u_int16_t id; -+ -+ if ((ctx = calloc(1, sizeof(*ctx))) == NULL) { -+ log_warn("rde_dump_mrt_new"); -+ return; -+ } -+ memcpy(&ctx->mrt, mrt, sizeof(struct mrt)); -+ TAILQ_INIT(&ctx->mrt.wbuf.bufs); -+ ctx->mrt.wbuf.fd = fd; -+ ctx->mrt.state = MRT_STATE_RUNNING; -+ id = rib_find(ctx->mrt.rib); -+ if (id == RIB_FAILED) { -+ log_warnx("non existing RIB %s for mrt dump", ctx->mrt.rib); -+ free(ctx); -+ return; -+ } -+ ctx->ribctx.ctx_count = RDE_RUNNER_ROUNDS; -+ ctx->ribctx.ctx_rib = &ribs[id]; -+ ctx->ribctx.ctx_upcall = mrt_dump_upcall; -+ ctx->ribctx.ctx_done = mrt_dump_done; -+ ctx->ribctx.ctx_arg = &ctx->mrt; -+ ctx->ribctx.ctx_af = AF_UNSPEC; -+ LIST_INSERT_HEAD(&rde_mrts, &ctx->mrt, entry); -+ rde_mrt_cnt++; -+ rib_dump_r(&ctx->ribctx); + pt_getaddr(p->prefix, &addr); +- switch (addr.af) { +- case AF_INET: ++ switch (addr.aid) { ++ case AID_INET: + bzero(&kl, sizeof(kl)); + kl.kr.prefix.s_addr = addr.v4.s_addr; + kl.kr.prefixlen = p->prefix->prefixlen; +@@ -2029,7 +2267,7 @@ rde_send_kroute(struct prefix *new, stru + sizeof(kl)) == -1) + fatal("imsg_compose error"); + break; +- case AF_INET6: ++ case AID_INET6: + bzero(&kl6, sizeof(kl6)); + memcpy(&kl6.kr.prefix, &addr.v6, sizeof(struct in6_addr)); + kl6.kr.prefixlen = p->prefix->prefixlen; +@@ -2050,6 +2288,10 @@ rde_send_kroute(struct prefix *new, stru + sizeof(kl6)) == -1) + fatal("imsg_compose error"); + break; ++ case AID_VPN_IPv4: ++ break; ++ default: ++ fatal("rde_send_kroute: unhandled AID"); + } } - /* -@@ -2081,7 +2166,6 @@ rde_send_pftable_commit(void) +@@ -2098,7 +2340,6 @@ rde_send_pftable_commit(void) void rde_send_nexthop(struct bgpd_addr *next, int valid) { @@ -1246,7 +1145,7 @@ diff -u -p -r1.1.1.1 -r1.6 int type; if (valid) -@@ -2089,8 +2173,6 @@ rde_send_nexthop(struct bgpd_addr *next, +@@ -2106,8 +2347,6 @@ rde_send_nexthop(struct bgpd_addr *next, else type = IMSG_NEXTHOP_REMOVE; @@ -1255,127 +1154,30 @@ diff -u -p -r1.1.1.1 -r1.6 if (imsg_compose(ibuf_main, type, 0, 0, -1, next, sizeof(struct bgpd_addr)) == -1) fatal("imsg_compose error"); -@@ -2100,9 +2182,10 @@ rde_send_nexthop(struct bgpd_addr *next, - * soft reconfig specific functions - */ - void --rde_softreconfig_out(struct pt_entry *pt, void *ptr) -+rde_softreconfig_out(struct rib_entry *re, void *ptr) - { -- struct prefix *p = pt->active; -+ struct prefix *p = re->active; -+ struct pt_entry *pt; - struct rde_peer *peer; - struct rde_aspath *oasp, *nasp; - enum filter_actions oa, na; -@@ -2111,17 +2194,22 @@ rde_softreconfig_out(struct pt_entry *pt - if (p == NULL) - return; - -+ pt = re->prefix; - pt_getaddr(pt, &addr); - LIST_FOREACH(peer, &peerlist, peer_l) { -+ if (peer->conf.id == 0) -+ continue; -+ if (peer->ribid != re->ribid) -+ continue; - if (peer->reconf_out == 0) - continue; - if (up_test_update(peer, p) != 1) +@@ -2201,6 +2440,10 @@ rde_softreconfig_in(struct rib_entry *re continue; -- oa = rde_filter(&oasp, rules_l, peer, p->aspath, &addr, -- pt->prefixlen, p->aspath->peer, DIR_OUT); -- na = rde_filter(&nasp, newrules, peer, p->aspath, &addr, -- pt->prefixlen, p->aspath->peer, DIR_OUT); -+ oa = rde_filter(re->ribid, &oasp, rules_l, peer, p->aspath, -+ &addr, pt->prefixlen, p->aspath->peer, DIR_OUT); -+ na = rde_filter(re->ribid, &nasp, newrules, peer, p->aspath, -+ &addr, pt->prefixlen, p->aspath->peer, DIR_OUT); - oasp = oasp != NULL ? oasp : p->aspath; - nasp = nasp != NULL ? nasp : p->aspath; - -@@ -2154,58 +2242,103 @@ done: - } - - void --rde_softreconfig_in(struct pt_entry *pt, void *ptr) -+rde_softreconfig_in(struct rib_entry *re, void *ptr) - { - struct prefix *p, *np; -+ struct pt_entry *pt; - struct rde_peer *peer; - struct rde_aspath *asp, *oasp, *nasp; - enum filter_actions oa, na; - struct bgpd_addr addr; -+ u_int16_t i; - -+ pt = re->prefix; - pt_getaddr(pt, &addr); -- for (p = LIST_FIRST(&pt->prefix_h); p != NULL; p = np) { -- np = LIST_NEXT(p, prefix_l); -- if (!(p->flags & F_ORIGINAL)) -- continue; -+ for (p = LIST_FIRST(&re->prefix_h); p != NULL; p = np) { -+ np = LIST_NEXT(p, rib_l); - - /* store aspath as prefix may change till we're done */ - asp = p->aspath; - peer = asp->peer; - -+ /* XXX how can this happen ??? */ - if (peer->reconf_in == 0) - continue; - -- /* check if prefix changed */ -- oa = rde_filter(&oasp, rules_l, peer, asp, &addr, -- pt->prefixlen, peer, DIR_IN); -- na = rde_filter(&nasp, newrules, peer, asp, &addr, -+ for (i = 1; i < rib_size; i++) { + for (i = 1; i < rib_size; i++) { + /* only active ribs need a softreconfig rerun */ + if (ribs[i].state != RIB_ACTIVE) + continue; + -+ /* check if prefix changed */ -+ oa = rde_filter(i, &oasp, rules_l, peer, asp, &addr, -+ pt->prefixlen, peer, DIR_IN); -+ na = rde_filter(i, &nasp, newrules, peer, asp, &addr, -+ pt->prefixlen, peer, DIR_IN); -+ oasp = oasp != NULL ? oasp : asp; -+ nasp = nasp != NULL ? nasp : asp; -+ -+ if (oa == ACTION_DENY && na == ACTION_DENY) -+ /* nothing todo */ -+ goto done; -+ if (oa == ACTION_DENY && na == ACTION_ALLOW) { -+ /* update Local-RIB */ -+ path_update(&ribs[i], peer, nasp, &addr, -+ pt->prefixlen); -+ goto done; -+ } -+ if (oa == ACTION_ALLOW && na == ACTION_DENY) { -+ /* remove from Local-RIB */ -+ prefix_remove(&ribs[i], peer, &addr, -+ pt->prefixlen, 0); -+ goto done; -+ } -+ if (oa == ACTION_ALLOW && na == ACTION_ALLOW) { -+ if (path_compare(nasp, oasp) == 0) -+ goto done; -+ /* send update */ + /* check if prefix changed */ + oa = rde_filter(i, &oasp, rules_l, peer, asp, &addr, + pt->prefixlen, peer, DIR_IN); +@@ -2228,7 +2471,7 @@ rde_softreconfig_in(struct rib_entry *re + if (path_compare(nasp, oasp) == 0) + goto done; + /* send update */ +- path_update(&ribs[1], peer, nasp, &addr, + path_update(&ribs[i], peer, nasp, &addr, -+ pt->prefixlen); -+ } -+ -+done: -+ if (oasp != asp) -+ path_put(oasp); -+ if (nasp != asp) -+ path_put(nasp); -+ } -+ } -+} -+ + pt->prefixlen); + } + +@@ -2241,6 +2484,40 @@ done: + } + } + +void +rde_softreconfig_load(struct rib_entry *re, void *ptr) +{ @@ -1397,146 +1199,238 @@ diff -u -p -r1.1.1.1 -r1.6 + peer = asp->peer; + + action = rde_filter(rib->id, &nasp, newrules, peer, asp, &addr, - pt->prefixlen, peer, DIR_IN); -- oasp = oasp != NULL ? oasp : asp; - nasp = nasp != NULL ? nasp : asp; - -- if (oa == ACTION_DENY && na == ACTION_DENY) -- /* nothing todo */ -- goto done; -- if (oa == ACTION_DENY && na == ACTION_ALLOW) { ++ pt->prefixlen, peer, DIR_IN); ++ nasp = nasp != NULL ? nasp : asp; ++ + if (action == ACTION_ALLOW) { - /* update Local-RIB */ -- path_update(peer, nasp, &addr, pt->prefixlen, F_LOCAL); -- goto done; -- } -- if (oa == ACTION_ALLOW && na == ACTION_DENY) { -- /* remove from Local-RIB */ -- prefix_remove(peer, &addr, pt->prefixlen, F_LOCAL); -- goto done; -- } -- if (oa == ACTION_ALLOW && na == ACTION_ALLOW) { -- if (path_compare(nasp, oasp) == 0) -- goto done; -- /* send update */ -- path_update(peer, nasp, &addr, pt->prefixlen, F_LOCAL); ++ /* update Local-RIB */ + path_update(rib, peer, nasp, &addr, pt->prefixlen); - } - --done: -- if (oasp != asp) -- path_put(oasp); - if (nasp != asp) - path_put(nasp); - } -@@ -2217,17 +2350,19 @@ done: - u_char queue_buf[4096]; - - void --rde_up_dump_upcall(struct pt_entry *pt, void *ptr) -+rde_up_dump_upcall(struct rib_entry *re, void *ptr) ++ } ++ ++ if (nasp != asp) ++ path_put(nasp); ++ } ++} ++ + /* + * update specific functions + */ +@@ -2286,7 +2563,7 @@ void + rde_update_queue_runner(void) { - struct rde_peer *peer = ptr; + struct rde_peer *peer; +- int r, sent, max = RDE_RUNNER_ROUNDS; ++ int r, sent, max = RDE_RUNNER_ROUNDS, eor = 0; + u_int16_t len, wd_len, wpos; -- if (pt->active == NULL) -+ if (re->ribid != peer->ribid) -+ fatalx("King Bula: monsterous evil horror."); -+ if (re->active == NULL) - return; -- up_generate_updates(rules_l, peer, pt->active, NULL); -+ up_generate_updates(rules_l, peer, re->active, NULL); + len = sizeof(queue_buf) - MSGSIZE_HEADER; +@@ -2300,7 +2577,7 @@ rde_update_queue_runner(void) + /* first withdraws */ + wpos = 2; /* reserve space for the length field */ + r = up_dump_prefix(queue_buf + wpos, len - wpos - 2, +- &peer->withdraws, peer); ++ &peer->withdraws[AID_INET], peer); + wd_len = r; + /* write withdraws length filed */ + wd_len = htons(wd_len); +@@ -2310,31 +2587,49 @@ rde_update_queue_runner(void) + /* now bgp path attributes */ + r = up_dump_attrnlri(queue_buf + wpos, len - wpos, + peer); +- wpos += r; +- +- if (wpos == 4) +- /* +- * No packet to send. The 4 bytes are the +- * needed withdraw and path attribute length. +- */ +- continue; ++ switch (r) { ++ case -1: ++ eor = 1; ++ if (wd_len == 0) { ++ /* no withdraws queued just send EoR */ ++ peer_send_eor(peer, AID_INET); ++ continue; ++ } ++ break; ++ case 2: ++ if (wd_len == 0) { ++ /* ++ * No packet to send. No withdraws and ++ * no path attributes. Skip. ++ */ ++ continue; ++ } ++ /* FALLTHROUGH */ ++ default: ++ wpos += r; ++ break; ++ } + + /* finally send message to SE */ + if (imsg_compose(ibuf_se, IMSG_UPDATE, peer->conf.id, + 0, -1, queue_buf, wpos) == -1) + fatal("imsg_compose error"); + sent++; ++ if (eor) { ++ eor = 0; ++ peer_send_eor(peer, AID_INET); ++ } + } + max -= sent; + } while (sent != 0 && max > 0); } void --rde_generate_updates(struct prefix *new, struct prefix *old) -+rde_generate_updates(u_int16_t ribid, struct prefix *new, struct prefix *old) +-rde_update6_queue_runner(void) ++rde_update6_queue_runner(u_int8_t aid) { - struct rde_peer *peer; - -@@ -2240,6 +2375,10 @@ rde_generate_updates(struct prefix *new, - return; + struct rde_peer *peer; + u_char *b; +- int sent, max = RDE_RUNNER_ROUNDS / 2; ++ int r, sent, max = RDE_RUNNER_ROUNDS / 2; + u_int16_t len; - LIST_FOREACH(peer, &peerlist, peer_l) { -+ if (peer->conf.id == 0) -+ continue; -+ if (peer->ribid != ribid) -+ continue; - if (peer->state != PEER_UP) - continue; - up_generate_updates(rules_l, peer, new, old); -@@ -2257,6 +2396,8 @@ rde_update_queue_runner(void) - do { - sent = 0; - LIST_FOREACH(peer, &peerlist, peer_l) { -+ if (peer->conf.id == 0) -+ continue; - if (peer->state != PEER_UP) - continue; - /* first withdraws */ -@@ -2303,6 +2444,8 @@ rde_update6_queue_runner(void) - do { - sent = 0; - LIST_FOREACH(peer, &peerlist, peer_l) { -+ if (peer->conf.id == 0) -+ continue; + /* first withdraws ... */ +@@ -2346,7 +2641,7 @@ rde_update6_queue_runner(void) if (peer->state != PEER_UP) continue; len = sizeof(queue_buf) - MSGSIZE_HEADER; -@@ -2324,6 +2467,8 @@ rde_update6_queue_runner(void) - do { - sent = 0; - LIST_FOREACH(peer, &peerlist, peer_l) { -+ if (peer->conf.id == 0) -+ continue; +- b = up_dump_mp_unreach(queue_buf, &len, peer); ++ b = up_dump_mp_unreach(queue_buf, &len, peer, aid); + + if (b == NULL) + continue; +@@ -2369,10 +2664,18 @@ rde_update6_queue_runner(void) if (peer->state != PEER_UP) continue; len = sizeof(queue_buf) - MSGSIZE_HEADER; -@@ -2386,6 +2531,8 @@ struct peer_table { - void +- b = up_dump_mp_reach(queue_buf, &len, peer); +- +- if (b == NULL) ++ r = up_dump_mp_reach(queue_buf, &len, peer, aid); ++ switch (r) { ++ case -2: + continue; ++ case -1: ++ peer_send_eor(peer, aid); ++ continue; ++ default: ++ b = queue_buf + r; ++ break; ++ } ++ + /* finally send message to SE */ + if (imsg_compose(ibuf_se, IMSG_UPDATE, peer->conf.id, + 0, -1, b, len) == -1) +@@ -2411,7 +2714,7 @@ rde_decisionflags(void) + int + rde_as4byte(struct rde_peer *peer) + { +- return (peer->capa_announced.as4byte && peer->capa_received.as4byte); ++ return (peer->capa.as4byte); + } + + /* +@@ -2429,7 +2732,6 @@ void peer_init(u_int32_t hashsize) { -+ struct peer_config pc; -+ struct in_addr id; + struct peer_config pc; +- struct in_addr id; u_int32_t hs, i; for (hs = 1; hs < hashsize; hs <<= 1) -@@ -2399,6 +2546,19 @@ peer_init(u_int32_t hashsize) - LIST_INIT(&peerlist); - +@@ -2445,17 +2747,13 @@ peer_init(u_int32_t hashsize) peertable.peer_hashmask = hs - 1; -+ -+ bzero(&pc, sizeof(pc)); -+ pc.remote_as = conf->as; -+ id.s_addr = conf->bgpid; -+ snprintf(pc.descr, sizeof(pc.descr), "LOCAL: ID %s", inet_ntoa(id)); -+ -+ peerself = peer_add(0, &pc); -+ if (peerself == NULL) -+ fatalx("peer_init add self"); -+ -+ peerself->state = PEER_UP; -+ peerself->remote_bgpid = ntohl(conf->bgpid); -+ peerself->short_as = conf->short_as; + + bzero(&pc, sizeof(pc)); +- pc.remote_as = conf->as; +- id.s_addr = conf->bgpid; +- snprintf(pc.descr, sizeof(pc.descr), "LOCAL: ID %s", inet_ntoa(id)); ++ snprintf(pc.descr, sizeof(pc.descr), "LOCAL"); + + peerself = peer_add(0, &pc); + if (peerself == NULL) + fatalx("peer_init add self"); + + peerself->state = PEER_UP; +- peerself->remote_bgpid = ntohl(conf->bgpid); +- peerself->short_as = conf->short_as; } void -@@ -2444,6 +2604,7 @@ peer_add(u_int32_t id, struct peer_confi - LIST_INIT(&peer->path_h); - memcpy(&peer->conf, p_conf, sizeof(struct peer_config)); - peer->remote_bgpid = 0; -+ peer->ribid = rib_find(peer->conf.rib); - peer->state = PEER_NONE; - up_init(peer); - -@@ -2573,6 +2734,7 @@ peer_down(u_int32_t id) - path_remove(asp); +@@ -2534,14 +2832,10 @@ peer_localaddrs(struct rde_peer *peer, s + if (ifa->ifa_addr->sa_family == + match->ifa_addr->sa_family) + ifa = match; +- peer->local_v4_addr.af = AF_INET; +- peer->local_v4_addr.v4.s_addr = +- ((struct sockaddr_in *)ifa->ifa_addr)-> +- sin_addr.s_addr; ++ sa2addr(ifa->ifa_addr, &peer->local_v4_addr); + break; + } + } +- + for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { + if (ifa->ifa_addr->sa_family == AF_INET6 && + strcmp(ifa->ifa_name, match->ifa_name) == 0) { +@@ -2559,13 +2853,7 @@ peer_localaddrs(struct rde_peer *peer, s + &((struct sockaddr_in6 *)ifa-> + ifa_addr)->sin6_addr)) + continue; +- peer->local_v6_addr.af = AF_INET6; +- memcpy(&peer->local_v6_addr.v6, +- &((struct sockaddr_in6 *)ifa->ifa_addr)-> +- sin6_addr, sizeof(struct in6_addr)); +- peer->local_v6_addr.scope_id = +- ((struct sockaddr_in6 *)ifa->ifa_addr)-> +- sin6_scope_id; ++ sa2addr(ifa->ifa_addr, &peer->local_v6_addr); + break; + } } - LIST_INIT(&peer->path_h); -+ peer->prefix_cnt = 0; +@@ -2577,6 +2865,7 @@ void + peer_up(u_int32_t id, struct session_up *sup) + { + struct rde_peer *peer; ++ u_int8_t i; - /* Deletions are performed in path_remove() */ - rde_send_pftable_commit(); -@@ -2589,32 +2751,38 @@ peer_dump(u_int32_t id, u_int16_t afi, u + peer = peer_get(id); + if (peer == NULL) { +@@ -2590,10 +2879,7 @@ peer_up(u_int32_t id, struct session_up + peer->short_as = sup->short_as; + memcpy(&peer->remote_addr, &sup->remote_addr, + sizeof(peer->remote_addr)); +- memcpy(&peer->capa_announced, &sup->capa_announced, +- sizeof(peer->capa_announced)); +- memcpy(&peer->capa_received, &sup->capa_received, +- sizeof(peer->capa_received)); ++ memcpy(&peer->capa, &sup->capa, sizeof(peer->capa)); + + peer_localaddrs(peer, &sup->local_addr); + +@@ -2607,7 +2893,10 @@ peer_up(u_int32_t id, struct session_up + */ + return; + +- peer_dump(id, AFI_ALL, SAFI_ALL); ++ for (i = 0; i < AID_MAX; i++) { ++ if (peer->capa.mp[i] == 1) ++ peer_dump(id, i); ++ } + } + + void +@@ -2642,42 +2931,32 @@ peer_down(u_int32_t id) + } + + void +-peer_dump(u_int32_t id, u_int16_t afi, u_int8_t safi) ++peer_dump(u_int32_t id, u_int8_t aid) + { + struct rde_peer *peer; peer = peer_get(id); if (peer == NULL) { @@ -1545,219 +1439,110 @@ diff -u -p -r1.1.1.1 -r1.6 return; } - if (afi == AFI_ALL || afi == AFI_IPv4) +- if (afi == AFI_ALL || afi == AFI_IPv4) - if (safi == SAFI_ALL || safi == SAFI_UNICAST) { -- if (peer->conf.announce_type == -- ANNOUNCE_DEFAULT_ROUTE) -+ if ((safi == SAFI_ALL || safi == SAFI_UNICAST) && -+ peer->conf.capabilities.mp_v4 != SAFI_NONE) { -+ if (peer->conf.announce_type == ANNOUNCE_DEFAULT_ROUTE) - up_generate_default(rules_l, peer, AF_INET); - else -- pt_dump(rde_up_dump_upcall, peer, AF_INET); -+ rib_dump(&ribs[peer->ribid], rde_up_dump_upcall, -+ peer, AF_INET); -+ if (peer->capa_received.restart && -+ peer->capa_announced.restart) -+ peer_send_eor(peer, AFI_IPv4, SAFI_UNICAST); - } - if (afi == AFI_ALL || afi == AFI_IPv6) +- if (peer->conf.announce_type == ANNOUNCE_DEFAULT_ROUTE) +- up_generate_default(rules_l, peer, AF_INET); +- else +- rib_dump(&ribs[peer->ribid], rde_up_dump_upcall, +- peer, AF_INET); +- } +- if (afi == AFI_ALL || afi == AFI_IPv6) - if (safi == SAFI_ALL || safi == SAFI_UNICAST) { -- if (peer->conf.announce_type == -- ANNOUNCE_DEFAULT_ROUTE) -+ if ((safi == SAFI_ALL || safi == SAFI_UNICAST) && -+ peer->capa_announced.mp_v6 != SAFI_NONE && -+ peer->capa_received.mp_v6 != SAFI_NONE) { -+ if (peer->conf.announce_type == ANNOUNCE_DEFAULT_ROUTE) - up_generate_default(rules_l, peer, AF_INET6); - else -- pt_dump(rde_up_dump_upcall, peer, AF_INET6); -+ rib_dump(&ribs[peer->ribid], rde_up_dump_upcall, -+ peer, AF_INET6); -+ if (peer->capa_received.restart && -+ peer->capa_announced.restart) -+ peer_send_eor(peer, AFI_IPv6, SAFI_UNICAST); - } +- if (peer->conf.announce_type == ANNOUNCE_DEFAULT_ROUTE) +- up_generate_default(rules_l, peer, AF_INET6); +- else +- rib_dump(&ribs[peer->ribid], rde_up_dump_upcall, +- peer, AF_INET6); +- } - - if (peer->capa_received.restart && peer->capa_announced.restart) - peer_send_eor(peer, afi, safi); ++ if (peer->conf.announce_type == ANNOUNCE_DEFAULT_ROUTE) ++ up_generate_default(rules_l, peer, aid); ++ else ++ rib_dump(&ribs[peer->ribid], rde_up_dump_upcall, peer, aid); ++ if (peer->capa.restart) ++ up_generate_marker(peer, aid); } -/* End-of-RIB marker, draft-ietf-idr-restart-13.txt */ +/* End-of-RIB marker, RFC 4724 */ void - peer_send_eor(struct rde_peer *peer, u_int16_t afi, u_int16_t safi) - { -@@ -2653,24 +2821,8 @@ void - network_init(struct network_head *net_l) - { - struct network *n; -- struct in_addr id; - - reloadtime = time(NULL); -- bzero(&peerself, sizeof(peerself)); -- peerself.state = PEER_UP; -- peerself.remote_bgpid = ntohl(conf->bgpid); -- id.s_addr = conf->bgpid; -- peerself.conf.remote_as = conf->as; -- peerself.short_as = conf->short_as; -- snprintf(peerself.conf.descr, sizeof(peerself.conf.descr), -- "LOCAL: ID %s", inet_ntoa(id)); -- bzero(&peerdynamic, sizeof(peerdynamic)); -- peerdynamic.state = PEER_UP; -- peerdynamic.remote_bgpid = ntohl(conf->bgpid); -- peerdynamic.conf.remote_as = conf->as; -- peerdynamic.short_as = conf->short_as; -- snprintf(peerdynamic.conf.descr, sizeof(peerdynamic.conf.descr), -- "LOCAL: ID %s", inet_ntoa(id)); - - while ((n = TAILQ_FIRST(net_l)) != NULL) { - TAILQ_REMOVE(net_l, n, entry); -@@ -2683,7 +2835,7 @@ void - network_add(struct network_config *nc, int flagstatic) - { - struct rde_aspath *asp; -- struct rde_peer *p; -+ u_int16_t i; - - asp = path_get(); - asp->aspath = aspath_get(NULL, 0); -@@ -2691,15 +2843,13 @@ network_add(struct network_config *nc, i - asp->flags = F_ATTR_ORIGIN | F_ATTR_ASPATH | - F_ATTR_LOCALPREF | F_PREFIX_ANNOUNCED; - /* the nexthop is unset unless a default set overrides it */ -+ if (!flagstatic) -+ asp->flags |= F_ANN_DYNAMIC; - -- if (flagstatic) -- p = &peerself; -- else -- p = &peerdynamic; -- -- rde_apply_set(asp, &nc->attrset, nc->prefix.af, p, p); -- path_update(p, asp, &nc->prefix, nc->prefixlen, F_ORIGINAL); -- path_update(p, asp, &nc->prefix, nc->prefixlen, F_LOCAL); -+ rde_apply_set(asp, &nc->attrset, nc->prefix.af, peerself, peerself); -+ for (i = 1; i < rib_size; i++) -+ path_update(&ribs[i], peerself, asp, &nc->prefix, -+ nc->prefixlen); - - path_put(asp); - filterset_free(&nc->attrset); -@@ -2708,29 +2858,27 @@ network_add(struct network_config *nc, i - void - network_delete(struct network_config *nc, int flagstatic) +-peer_send_eor(struct rde_peer *peer, u_int16_t afi, u_int16_t safi) ++peer_send_eor(struct rde_peer *peer, u_int8_t aid) { -- struct rde_peer *p; -+ u_int32_t flags = F_PREFIX_ANNOUNCED; -+ u_int32_t i; - -- if (flagstatic) -- p = &peerself; -- else -- p = &peerdynamic; -+ if (!flagstatic) -+ flags |= F_ANN_DYNAMIC; - -- prefix_remove(p, &nc->prefix, nc->prefixlen, F_LOCAL); -- prefix_remove(p, &nc->prefix, nc->prefixlen, F_ORIGINAL); -+ for (i = rib_size - 1; i > 0; i--) -+ prefix_remove(&ribs[i], peerself, &nc->prefix, nc->prefixlen, -+ flags); - } +- if (afi == AFI_IPv4 && safi == SAFI_UNICAST) { ++ u_int16_t afi; ++ u_int8_t safi; ++ ++ if (aid == AID_INET) { + u_char null[4]; - void --network_dump_upcall(struct pt_entry *pt, void *ptr) -+network_dump_upcall(struct rib_entry *re, void *ptr) - { - struct prefix *p; - struct kroute k; - struct kroute6 k6; - struct bgpd_addr addr; -- pid_t pid; -- -- memcpy(&pid, ptr, sizeof(pid)); -+ struct rde_dump_ctx *ctx = ptr; + bzero(&null, 4); +@@ -2688,6 +2967,9 @@ peer_send_eor(struct rde_peer *peer, u_i + u_int16_t i; + u_char buf[10]; -- LIST_FOREACH(p, &pt->prefix_h, prefix_l) { -+ LIST_FOREACH(p, &re->prefix_h, rib_l) { ++ if (aid2afi(aid, &afi, &safi) == -1) ++ fatalx("peer_send_eor: bad AID"); ++ + i = 0; /* v4 withdrawn len */ + bcopy(&i, &buf[0], sizeof(i)); + i = htons(6); /* path attr len */ +@@ -2737,7 +3019,7 @@ network_add(struct network_config *nc, i + if (!flagstatic) + asp->flags |= F_ANN_DYNAMIC; + +- rde_apply_set(asp, &nc->attrset, nc->prefix.af, peerself, peerself); ++ rde_apply_set(asp, &nc->attrset, aid2af(nc->prefix.aid), peerself, peerself); + for (i = 1; i < rib_size; i++) + path_update(&ribs[i], peerself, asp, &nc->prefix, + nc->prefixlen); +@@ -2772,9 +3054,10 @@ network_dump_upcall(struct rib_entry *re + LIST_FOREACH(p, &re->prefix_h, rib_l) { if (!(p->aspath->flags & F_PREFIX_ANNOUNCED)) continue; - if (p->prefix->af == AF_INET) { -@@ -2738,10 +2886,10 @@ network_dump_upcall(struct pt_entry *pt, - pt_getaddr(p->prefix, &addr); +- if (p->prefix->af == AF_INET) { ++ pt_getaddr(p->prefix, &addr); ++ switch (addr.aid) { ++ case AID_INET: + bzero(&k, sizeof(k)); +- pt_getaddr(p->prefix, &addr); k.prefix.s_addr = addr.v4.s_addr; k.prefixlen = p->prefix->prefixlen; -- if (p->aspath->peer == &peerself) -+ if (p->aspath->peer == peerself) - k.flags = F_KERNEL; - if (imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_NETWORK, 0, -- pid, -1, &k, sizeof(k)) == -1) -+ ctx->req.pid, -1, &k, sizeof(k)) == -1) + if (p->aspath->peer == peerself) +@@ -2783,10 +3066,9 @@ network_dump_upcall(struct rib_entry *re + ctx->req.pid, -1, &k, sizeof(k)) == -1) log_warnx("network_dump_upcall: " "imsg_compose error"); - } -@@ -2750,31 +2898,21 @@ network_dump_upcall(struct pt_entry *pt, - pt_getaddr(p->prefix, &addr); +- } +- if (p->prefix->af == AF_INET6) { ++ break; ++ case AID_INET6: + bzero(&k6, sizeof(k6)); +- pt_getaddr(p->prefix, &addr); memcpy(&k6.prefix, &addr.v6, sizeof(k6.prefix)); k6.prefixlen = p->prefix->prefixlen; -- if (p->aspath->peer == &peerself) -+ if (p->aspath->peer == peerself) - k6.flags = F_KERNEL; - if (imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_NETWORK6, 0, -- pid, -1, &k6, sizeof(k6)) == -1) -+ ctx->req.pid, -1, &k6, sizeof(k6)) == -1) + if (p->aspath->peer == peerself) +@@ -2795,6 +3077,7 @@ network_dump_upcall(struct rib_entry *re + ctx->req.pid, -1, &k6, sizeof(k6)) == -1) log_warnx("network_dump_upcall: " "imsg_compose error"); ++ break; } } } - --void --network_flush(int flagstatic) --{ -- if (flagstatic) -- prefix_network_clean(&peerself, time(NULL)); -- else -- prefix_network_clean(&peerdynamic, time(NULL)); --} -- - /* clean up */ - void - rde_shutdown(void) - { - struct rde_peer *p; -- struct rde_aspath *asp, *nasp; - struct filter_rule *r; - u_int32_t i; - -@@ -2790,21 +2928,6 @@ rde_shutdown(void) - while ((p = LIST_FIRST(&peertable.peer_hashtbl[i])) != NULL) - peer_down(p->conf.id); - -- /* free announced network prefixes */ -- peerself.remote_bgpid = 0; -- peerself.state = PEER_DOWN; -- for (asp = LIST_FIRST(&peerself.path_h); asp != NULL; asp = nasp) { -- nasp = LIST_NEXT(asp, peer_l); -- path_remove(asp); -- } -- -- peerdynamic.remote_bgpid = 0; -- peerdynamic.state = PEER_DOWN; -- for (asp = LIST_FIRST(&peerdynamic.path_h); asp != NULL; asp = nasp) { -- nasp = LIST_NEXT(asp, peer_l); -- path_remove(asp); -- } -- - /* free filters */ - while ((r = TAILQ_FIRST(rules_l)) != NULL) { - TAILQ_REMOVE(rules_l, r, entry); -@@ -2819,7 +2942,6 @@ rde_shutdown(void) - attr_shutdown(); - pt_shutdown(); - peer_shutdown(); -- free(mrt); - } - - int +@@ -2841,10 +3124,10 @@ sa_cmp(struct bgpd_addr *a, struct socka + struct sockaddr_in *in_b; + struct sockaddr_in6 *in6_b; + +- if (a->af != b->sa_family) ++ if (aid2af(a->aid) != b->sa_family) + return (1); + +- switch (a->af) { ++ switch (b->sa_family) { + case AF_INET: + in_b = (struct sockaddr_in *)b; + if (a->v4.s_addr != in_b->sin_addr.s_addr) |