summaryrefslogtreecommitdiff
path: root/net/openbgpd/files/patch-bgpd_rde.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/openbgpd/files/patch-bgpd_rde.c')
-rw-r--r--net/openbgpd/files/patch-bgpd_rde.c2614
1 files changed, 0 insertions, 2614 deletions
diff --git a/net/openbgpd/files/patch-bgpd_rde.c b/net/openbgpd/files/patch-bgpd_rde.c
deleted file mode 100644
index 76761d859f1d..000000000000
--- a/net/openbgpd/files/patch-bgpd_rde.c
+++ /dev/null
@@ -1,2614 +0,0 @@
-Index: bgpd/rde.c
-===================================================================
-RCS file: /home/cvs/private/hrs/openbgpd/bgpd/rde.c,v
-retrieving revision 1.1.1.8
-retrieving revision 1.12
-diff -u -p -r1.1.1.8 -r1.12
---- bgpd/rde.c 14 Feb 2010 20:19:57 -0000 1.1.1.8
-+++ bgpd/rde.c 16 May 2014 00:36:26 -0000 1.12
-@@ -1,4 +1,4 @@
--/* $OpenBSD: rde.c,v 1.264 2009/06/29 12:22:16 claudio Exp $ */
-+/* $OpenBSD: rde.c,v 1.320 2012/09/18 09:45:51 claudio Exp $ */
-
- /*
- * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
-@@ -18,10 +18,11 @@
-
- #include <sys/types.h>
- #include <sys/socket.h>
-+#include <sys/time.h>
-+#include <sys/resource.h>
-
- #include <errno.h>
- #include <ifaddrs.h>
--#include <limits.h>
- #include <pwd.h>
- #include <poll.h>
- #include <signal.h>
-@@ -50,13 +51,18 @@ void rde_update_withdraw(struct rde_pe
- u_int8_t);
- int rde_attr_parse(u_char *, u_int16_t, struct rde_peer *,
- struct rde_aspath *, struct mpattr *);
-+int rde_attr_add(struct rde_aspath *, u_char *, u_int16_t);
- 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,
-- 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 *, u_int16_t,
-@@ -78,11 +84,15 @@ void rde_dump_ctx_new(struct ctl_show_
- void rde_dump_mrt_new(struct mrt *, pid_t, int);
- void rde_dump_done(void *);
-
-+int rde_rdomain_import(struct rde_aspath *, struct rdomain *);
- 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_softreconfig_load_peer(struct rib_entry *, void *);
-+void rde_softreconfig_unload_peer(struct rib_entry *, void *);
- void rde_update_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,10 +101,12 @@ 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_flush(struct rde_peer *, u_int8_t);
-+void peer_stale(u_int32_t, u_int8_t);
-+void peer_recv_eor(struct rde_peer *, u_int8_t);
-+void peer_dump(u_int32_t, u_int8_t);
-+void peer_send_eor(struct rde_peer *, u_int8_t);
-
--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 rib_entry *, void *);
-@@ -108,6 +120,7 @@ time_t reloadtime;
- struct rde_peer_head peerlist;
- struct rde_peer *peerself;
- struct filter_head *rules_l, *newrules;
-+struct rdomain_head *rdomains_l, *newdomains;
- struct imsgbuf *ibuf_se;
- struct imsgbuf *ibuf_se_ctl;
- struct imsgbuf *ibuf_main;
-@@ -120,11 +133,12 @@ struct rde_dump_ctx {
- };
-
- 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
-@@ -144,24 +158,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, 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 = 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:
-@@ -172,8 +179,6 @@ rde_main(struct bgpd_config *config, str
- return (pid);
- }
-
-- conf = config;
--
- if ((pw = getpwnam(BGPD_USER)) == NULL)
- fatal("getpwnam");
-
-@@ -194,6 +199,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 +217,25 @@ 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);
-- }
- path_init(pathhashsize);
- aspath_init(pathhashsize);
- attr_init(attrhashsize);
- 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);
-+ rdomains_l = calloc(1, sizeof(struct rdomain_head));
-+ if (rdomains_l == NULL)
-+ fatal(NULL);
-+ SIMPLEQ_INIT(rdomains_l);
-+ if ((conf = calloc(1, 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);
-- nh->refcnt++;
-- }
-- }
-- }
--
- while (rde_quit == 0) {
- if (pfd_elms < PFD_PIPE_COUNT + rde_mrt_cnt) {
- if ((newp = realloc(pfd, sizeof(struct pollfd) *
-@@ -287,11 +269,18 @@ rde_main(struct bgpd_config *config, str
- timeout = 0;
-
- i = PFD_PIPE_COUNT;
-- LIST_FOREACH(mrt, &rde_mrts, entry) {
-- if (mrt->wbuf.queued) {
-- pfd[i].fd = mrt->wbuf.fd;
-+ for (mctx = LIST_FIRST(&rde_mrts); mctx != 0; mctx = xmctx) {
-+ xmctx = LIST_NEXT(mctx, entry);
-+ if (mctx->mrt.wbuf.queued) {
-+ pfd[i].fd = mctx->mrt.wbuf.fd;
- pfd[i].events = POLLOUT;
- i++;
-+ } else if (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--;
- }
- }
-
-@@ -325,24 +314,17 @@ rde_main(struct bgpd_config *config, str
- if (pfd[PFD_PIPE_SESSION_CTL].revents & POLLIN)
- rde_dispatch_imsg_session(ibuf_se_ctl);
-
-- 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++) {
-+ 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);
-- rde_mrt_cnt--;
-- }
-- mrt = xmrt;
-+ mrt_write(&mctx->mrt);
-+ mctx = LIST_NEXT(mctx, entry);
- }
-
- rde_update_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)
- rib_dump_runner();
- }
-@@ -351,11 +333,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 ((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);
-@@ -378,13 +361,18 @@ 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 csr;
- struct ctl_show_rib_request req;
-+ struct rde_peer *peer;
-+ struct rde_aspath *asp;
- struct filter_set *s;
- struct nexthop *nh;
-- int n;
-+ u_int8_t *asdata;
-+ ssize_t n;
-+ int verbose;
-+ u_int16_t len;
-+ u_int8_t aid;
-
- if ((n = imsg_read(ibuf)) == -1)
- fatal("rde_dispatch_imsg_session: imsg_read error");
-@@ -422,13 +410,56 @@ rde_dispatch_imsg_session(struct imsgbuf
- case IMSG_SESSION_DOWN:
- peer_down(imsg.hdr.peerid);
- break;
-+ case IMSG_SESSION_STALE:
-+ if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(aid)) {
-+ log_warnx("rde_dispatch: wrong imsg len");
-+ break;
-+ }
-+ memcpy(&aid, imsg.data, sizeof(aid));
-+ if (aid >= AID_MAX)
-+ fatalx("IMSG_SESSION_STALE: bad AID");
-+ peer_stale(imsg.hdr.peerid, aid);
-+ break;
-+ case IMSG_SESSION_FLUSH:
-+ if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(aid)) {
-+ log_warnx("rde_dispatch: wrong imsg len");
-+ break;
-+ }
-+ memcpy(&aid, imsg.data, sizeof(aid));
-+ if (aid >= AID_MAX)
-+ fatalx("IMSG_SESSION_FLUSH: bad AID");
-+ if ((peer = peer_get(imsg.hdr.peerid)) == NULL) {
-+ log_warnx("rde_dispatch: unknown peer id %d",
-+ imsg.hdr.peerid);
-+ break;
-+ }
-+ peer_flush(peer, aid);
-+ break;
-+ case IMSG_SESSION_RESTARTED:
-+ if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(aid)) {
-+ log_warnx("rde_dispatch: wrong imsg len");
-+ break;
-+ }
-+ memcpy(&aid, imsg.data, sizeof(aid));
-+ if (aid >= AID_MAX)
-+ fatalx("IMSG_SESSION_RESTARTED: bad AID");
-+ if ((peer = peer_get(imsg.hdr.peerid)) == NULL) {
-+ log_warnx("rde_dispatch: unknown peer id %d",
-+ imsg.hdr.peerid);
-+ break;
-+ }
-+ if (peer->staletime[aid])
-+ peer_flush(peer, aid);
-+ 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;
- }
-- 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_NETWORK_ADD:
- if (imsg.hdr.len - IMSG_HEADER_SIZE !=
-@@ -440,23 +471,68 @@ rde_dispatch_imsg_session(struct imsgbuf
- TAILQ_INIT(&netconf_s.attrset);
- session_set = &netconf_s.attrset;
- break;
-+ case IMSG_NETWORK_ASPATH:
-+ if (imsg.hdr.len - IMSG_HEADER_SIZE <
-+ sizeof(struct ctl_show_rib)) {
-+ log_warnx("rde_dispatch: wrong imsg len");
-+ bzero(&netconf_s, sizeof(netconf_s));
-+ break;
-+ }
-+ asdata = imsg.data;
-+ asdata += sizeof(struct ctl_show_rib);
-+ memcpy(&csr, imsg.data, sizeof(csr));
-+ if (csr.aspath_len + sizeof(csr) > imsg.hdr.len -
-+ IMSG_HEADER_SIZE) {
-+ log_warnx("rde_dispatch: wrong aspath len");
-+ bzero(&netconf_s, sizeof(netconf_s));
-+ break;
-+ }
-+ asp = path_get();
-+ asp->lpref = csr.local_pref;
-+ asp->med = csr.med;
-+ asp->weight = csr.weight;
-+ asp->flags = csr.flags;
-+ asp->origin = csr.origin;
-+ asp->flags |= F_PREFIX_ANNOUNCED | F_ANN_DYNAMIC;
-+ asp->aspath = aspath_get(asdata, csr.aspath_len);
-+ netconf_s.asp = asp;
-+ break;
-+ case IMSG_NETWORK_ATTR:
-+ if (imsg.hdr.len <= IMSG_HEADER_SIZE) {
-+ log_warnx("rde_dispatch: wrong imsg len");
-+ break;
-+ }
-+ /* parse path attributes */
-+ len = imsg.hdr.len - IMSG_HEADER_SIZE;
-+ asp = netconf_s.asp;
-+ if (rde_attr_add(asp, imsg.data, len) == -1) {
-+ log_warnx("rde_dispatch: bad network "
-+ "attribute");
-+ path_put(asp);
-+ bzero(&netconf_s, sizeof(netconf_s));
-+ break;
-+ }
-+ break;
- case IMSG_NETWORK_DONE:
- if (imsg.hdr.len != IMSG_HEADER_SIZE) {
- log_warnx("rde_dispatch: wrong imsg len");
- break;
- }
- 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);
- break;
-+ case 0:
-+ /* something failed beforehands */
-+ break;
- default:
- badnet:
- log_warnx("rde_dispatch: bad network");
-@@ -528,10 +604,14 @@ badnet:
- peer->prefix_rcvd_update;
- p.stats.prefix_rcvd_withdraw =
- peer->prefix_rcvd_withdraw;
-+ p.stats.prefix_rcvd_eor =
-+ peer->prefix_rcvd_eor;
- p.stats.prefix_sent_update =
- peer->prefix_sent_update;
- p.stats.prefix_sent_withdraw =
- peer->prefix_sent_withdraw;
-+ p.stats.prefix_sent_eor =
-+ peer->prefix_sent_eor;
- }
- imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_NEIGHBOR, 0,
- imsg.hdr.pid, -1, &p, sizeof(struct peer));
-@@ -544,6 +624,11 @@ badnet:
- imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_RIB_MEM, 0,
- imsg.hdr.pid, -1, &rdemem, sizeof(rdemem));
- break;
-+ case IMSG_CTL_LOG_VERBOSE:
-+ /* already checked by SE */
-+ memcpy(&verbose, imsg.data, sizeof(verbose));
-+ log_verbose(verbose);
-+ break;
- default:
- break;
- }
-@@ -554,14 +639,17 @@ badnet:
- void
- rde_dispatch_imsg_parent(struct imsgbuf *ibuf)
- {
-+ static struct rdomain *rd;
- struct imsg imsg;
- struct mrt xmrt;
- struct rde_rib rn;
- struct rde_peer *peer;
-+ struct peer_config *pconf;
- struct filter_rule *r;
- struct filter_set *s;
- struct nexthop *nh;
-- int n, fd, reconf_in = 0, reconf_out = 0;
-+ int n, fd, reconf_in = 0, reconf_out = 0,
-+ reconf_rib = 0;
- u_int16_t rid;
-
- if ((n = imsg_read(ibuf)) == -1)
-@@ -576,20 +664,12 @@ rde_dispatch_imsg_parent(struct imsgbuf
- break;
-
- switch (imsg.hdr.type) {
-- case IMSG_RECONF_CONF:
-- reloadtime = time(NULL);
-- newrules = calloc(1, sizeof(struct filter_head));
-- if (newrules == NULL)
-- fatal(NULL);
-- TAILQ_INIT(newrules);
-- if ((nconf = malloc(sizeof(struct bgpd_config))) ==
-- 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:
-+ if (imsg.hdr.len - IMSG_HEADER_SIZE !=
-+ sizeof(struct network_config)) {
-+ log_warnx("rde_dispatch: wrong imsg len");
-+ break;
-+ }
- memcpy(&netconf_p, imsg.data, sizeof(netconf_p));
- TAILQ_INIT(&netconf_p.attrset);
- parent_set = &netconf_p.attrset;
-@@ -608,6 +688,26 @@ rde_dispatch_imsg_parent(struct imsgbuf
- TAILQ_INIT(&netconf_p.attrset);
- network_delete(&netconf_p, 1);
- break;
-+ case IMSG_RECONF_CONF:
-+ if (imsg.hdr.len - IMSG_HEADER_SIZE !=
-+ sizeof(struct bgpd_config))
-+ fatalx("IMSG_RECONF_CONF bad len");
-+ reloadtime = time(NULL);
-+ newrules = calloc(1, sizeof(struct filter_head));
-+ if (newrules == NULL)
-+ fatal(NULL);
-+ TAILQ_INIT(newrules);
-+ newdomains = calloc(1, sizeof(struct rdomain_head));
-+ if (newdomains == NULL)
-+ fatal(NULL);
-+ SIMPLEQ_INIT(newdomains);
-+ if ((nconf = malloc(sizeof(struct bgpd_config))) ==
-+ NULL)
-+ fatal(NULL);
-+ memcpy(nconf, imsg.data, sizeof(struct bgpd_config));
-+ for (rid = 0; rid < rib_size; rid++)
-+ ribs[rid].state = RECONF_DELETE;
-+ break;
- case IMSG_RECONF_RIB:
- if (imsg.hdr.len - IMSG_HEADER_SIZE !=
- sizeof(struct rde_rib))
-@@ -615,9 +715,26 @@ rde_dispatch_imsg_parent(struct imsgbuf
- 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;
-+ rib_new(rn.name, rn.rtableid, rn.flags);
-+ else if (ribs[rid].rtableid != rn.rtableid ||
-+ (ribs[rid].flags & F_RIB_HASNOFIB) !=
-+ (rn.flags & F_RIB_HASNOFIB)) {
-+ /* Big hammer in the F_RIB_NOFIB case but
-+ * not often enough used to optimise it more. */
-+ rib_free(&ribs[rid]);
-+ rib_new(rn.name, rn.rtableid, rn.flags);
-+ } else
-+ ribs[rid].state = RECONF_KEEP;
-+ break;
-+ case IMSG_RECONF_PEER:
-+ if (imsg.hdr.len - IMSG_HEADER_SIZE !=
-+ sizeof(struct peer_config))
-+ fatalx("IMSG_RECONF_PEER bad len");
-+ if ((peer = peer_get(imsg.hdr.peerid)) == NULL)
-+ break;
-+ pconf = imsg.data;
-+ strlcpy(peer->conf.rib, pconf->rib,
-+ sizeof(peer->conf.rib));
- break;
- case IMSG_RECONF_FILTER:
- if (imsg.hdr.len - IMSG_HEADER_SIZE !=
-@@ -631,12 +748,42 @@ rde_dispatch_imsg_parent(struct imsgbuf
- parent_set = &r->set;
- TAILQ_INSERT_TAIL(newrules, r, entry);
- break;
-+ case IMSG_RECONF_RDOMAIN:
-+ if (imsg.hdr.len - IMSG_HEADER_SIZE !=
-+ sizeof(struct rdomain))
-+ fatalx("IMSG_RECONF_RDOMAIN bad len");
-+ if ((rd = malloc(sizeof(struct rdomain))) == NULL)
-+ fatal(NULL);
-+ memcpy(rd, imsg.data, sizeof(struct rdomain));
-+ TAILQ_INIT(&rd->import);
-+ TAILQ_INIT(&rd->export);
-+ SIMPLEQ_INSERT_TAIL(newdomains, rd, entry);
-+ break;
-+ case IMSG_RECONF_RDOMAIN_EXPORT:
-+ if (rd == NULL) {
-+ log_warnx("rde_dispatch_imsg_parent: "
-+ "IMSG_RECONF_RDOMAIN_EXPORT unexpected");
-+ break;
-+ }
-+ parent_set = &rd->export;
-+ break;
-+ case IMSG_RECONF_RDOMAIN_IMPORT:
-+ if (rd == NULL) {
-+ log_warnx("rde_dispatch_imsg_parent: "
-+ "IMSG_RECONF_RDOMAIN_IMPORT unexpected");
-+ break;
-+ }
-+ parent_set = &rd->import;
-+ break;
-+ case IMSG_RECONF_RDOMAIN_DONE:
-+ parent_set = NULL;
-+ break;
- case IMSG_RECONF_DONE:
- if (nconf == NULL)
- fatalx("got IMSG_RECONF_DONE but no config");
- if ((nconf->flags & BGPD_FLAG_NO_EVALUATE)
- != (conf->flags & BGPD_FLAG_NO_EVALUATE)) {
-- log_warnx( "change to/from route-collector "
-+ log_warnx("change to/from route-collector "
- "mode ignored");
- if (conf->flags & BGPD_FLAG_NO_EVALUATE)
- nconf->flags |= BGPD_FLAG_NO_EVALUATE;
-@@ -644,10 +791,27 @@ 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, 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;
-+
-+ /* apply new set of rdomain, sync will be done later */
-+ while ((rd = SIMPLEQ_FIRST(rdomains_l)) != NULL) {
-+ SIMPLEQ_REMOVE_HEAD(rdomains_l, entry);
-+ filterset_free(&rd->import);
-+ filterset_free(&rd->export);
-+ free(rd);
-+ }
-+ free(rdomains_l);
-+ rdomains_l = newdomains;
-
- /* check if filter changed */
- LIST_FOREACH(peer, &peerlist, peer_l) {
-@@ -655,30 +819,59 @@ rde_dispatch_imsg_parent(struct imsgbuf
- continue;
- peer->reconf_out = 0;
- peer->reconf_in = 0;
-- if (peer->conf.softreconfig_out &&
-- !rde_filter_equal(rules_l, newrules, peer,
-- DIR_OUT)) {
-- peer->reconf_out = 1;
-- reconf_out = 1;
-- }
-+ peer->reconf_rib = 0;
- if (peer->conf.softreconfig_in &&
- !rde_filter_equal(rules_l, newrules, peer,
- DIR_IN)) {
- peer->reconf_in = 1;
- reconf_in = 1;
- }
-+ if (peer->ribid != rib_find(peer->conf.rib)) {
-+ rib_dump(&ribs[peer->ribid],
-+ rde_softreconfig_unload_peer, peer,
-+ AID_UNSPEC);
-+ peer->ribid = rib_find(peer->conf.rib);
-+ peer->reconf_rib = 1;
-+ reconf_rib = 1;
-+ continue;
-+ }
-+ if (peer->conf.softreconfig_out &&
-+ !rde_filter_equal(rules_l, newrules, peer,
-+ DIR_OUT)) {
-+ peer->reconf_out = 1;
-+ reconf_out = 1;
-+ }
- }
-- /* XXX this needs rework anyway */
-- /* sync local-RIB first */
-+ /* bring ribs in sync before softreconfig dance */
-+ for (rid = 0; rid < rib_size; rid++) {
-+ if (ribs[rid].state == RECONF_DELETE)
-+ rib_free(&ribs[rid]);
-+ else if (ribs[rid].state == RECONF_REINIT)
-+ rib_dump(&ribs[0],
-+ rde_softreconfig_load, &ribs[rid],
-+ AID_UNSPEC);
-+ }
-+ /* sync local-RIBs first */
- if (reconf_in)
- rib_dump(&ribs[0], rde_softreconfig_in, NULL,
-- AF_UNSPEC);
-+ AID_UNSPEC);
- /* then sync peers */
- if (reconf_out) {
- int i;
-- for (i = 1; i < rib_size; i++)
-+ for (i = 1; i < rib_size; i++) {
-+ if (ribs[i].state == RECONF_REINIT)
-+ /* already synced by _load */
-+ continue;
- rib_dump(&ribs[i], rde_softreconfig_out,
-- NULL, AF_UNSPEC);
-+ NULL, AID_UNSPEC);
-+ }
-+ }
-+ if (reconf_rib) {
-+ LIST_FOREACH(peer, &peerlist, peer_l) {
-+ rib_dump(&ribs[peer->ribid],
-+ rde_softreconfig_load_peer,
-+ peer, AID_UNSPEC);
-+ }
- }
-
- while ((r = TAILQ_FIRST(rules_l)) != NULL) {
-@@ -688,16 +881,18 @@ rde_dispatch_imsg_parent(struct imsgbuf
- }
- free(rules_l);
- rules_l = newrules;
-- for (rid = 0; rid < rib_size; rid++) {
-- if (ribs[rid].state == RIB_DELETE)
-- rib_free(&ribs[rid]);
-- }
-+
- log_info("RDE reconfigured");
-+ imsg_compose(ibuf_main, IMSG_RECONF_DONE, 0, 0,
-+ -1, NULL, 0);
- break;
- case IMSG_NEXTHOP_UPDATE:
- nexthop_update(imsg.data);
- break;
- case IMSG_FILTER_SET:
-+ if (imsg.hdr.len > IMSG_HEADER_SIZE +
-+ sizeof(struct filter_set))
-+ fatalx("IMSG_RECONF_CONF bad len");
- if (parent_set == NULL) {
- log_warnx("rde_dispatch_imsg_parent: "
- "IMSG_FILTER_SET unexpected");
-@@ -725,7 +920,8 @@ rde_dispatch_imsg_parent(struct imsgbuf
- log_warnx("expected to receive fd for mrt dump "
- "but didn't receive any");
- else if (xmrt.type == MRT_TABLE_DUMP ||
-- xmrt.type == MRT_TABLE_DUMP_MP) {
-+ xmrt.type == MRT_TABLE_DUMP_MP ||
-+ xmrt.type == MRT_TABLE_DUMP_V2) {
- rde_dump_mrt_new(&xmrt, imsg.hdr.pid, fd);
- } else
- close(fd);
-@@ -744,6 +940,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;
- u_char *p, *mpp = NULL;
-@@ -752,9 +950,8 @@ 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;
-+ u_int32_t fas;
-
- peer = peer_get(imsg->hdr.peerid);
- if (peer == NULL) /* unknown peer, cannot happen */
-@@ -810,26 +1007,21 @@ rde_update_dispatch(struct imsg *imsg)
- goto done;
- }
-
-- /*
-- * 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.
-- */
-- if (asp->flags & F_ATTR_AS4BYTE_NEW &&
-- !(asp->flags & F_ATTR_LOOP))
-- rde_as4byte_fixup(peer, asp);
-+ rde_as4byte_fixup(peer, asp);
-
- /* 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,
-+ peer->conf.enforce_as == ENFORCE_AS_ON) {
-+ fas = aspath_neighbor(asp->aspath);
-+ if (peer->conf.remote_as != fas) {
-+ log_peer_warnx(&peer->conf, "bad path, "
-+ "starting with %s, "
-+ "enforce neighbor-as enabled", log_as(fas));
-+ rde_update_err(peer, ERR_UPDATE, ERR_UPD_ASPATH,
- NULL, 0);
-- goto done;
-+ goto done;
- }
-+ }
-
- rde_reflector(peer, asp);
- }
-@@ -860,9 +1052,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;
-@@ -879,6 +1071,10 @@ rde_update_dispatch(struct imsg *imsg)
- ERR_UPD_ATTRLIST, NULL, 0);
- return (-1);
- }
-+ if (withdrawn_len == 0) {
-+ /* EoR marker */
-+ peer_recv_eor(peer, AID_INET);
-+ }
- return (0);
- }
-
-@@ -892,15 +1088,30 @@ 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;
-+ }
-+
-+ 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;
-+ }
-+
-+ if ((asp->flags & ~F_ATTR_MP_UNREACH) == 0 && mplen == 0) {
-+ /* EoR marker */
-+ peer_recv_eor(peer, aid);
-+ }
-+
-+ switch (aid) {
-+ case AID_INET6:
- while (mplen > 0) {
- if ((pos = rde_update_get_prefix6(mpp, mplen,
- &prefix, &prefixlen)) == -1) {
-@@ -926,6 +1137,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:
- /* silently ignore unsupported multiprotocol AF */
- break;
-@@ -963,9 +1200,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);
- goto done;
-@@ -995,6 +1232,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 +1257,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) {
-- 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);
- goto done;
-@@ -1013,16 +1266,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;
-- }
--
-+ switch (aid) {
-+ case AID_INET6:
- while (mplen > 0) {
- if ((pos = rde_update_get_prefix6(mpp, mplen,
- &prefix, &prefixlen)) == -1) {
-@@ -1058,6 +1303,42 @@ rde_update_dispatch(struct imsg *imsg)
-
- }
- 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 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;
-+ }
-+
-+ mpp += pos;
-+ mplen -= pos;
-+
-+ rde_update_update(peer, asp, &prefix,
-+ prefixlen);
-+
-+ /* 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 +1366,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 +1377,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;
-
-- 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);
-+ r += path_update(&ribs[i], peer, fasp, prefix,
-+ prefixlen);
-+ } else if (prefix_remove(&ribs[i], peer, prefix, prefixlen,
-+ 0)) {
-+ rde_update_log("filtered withdraw", i, peer,
-+ NULL, prefix, prefixlen);
-+ f++;
-+ }
-
--done:
- /* free modified aspath */
- if (fasp != asp)
- path_put(fasp);
-@@ -1114,6 +1402,8 @@ done:
-
- if (r)
- peer->prefix_cnt++;
-+ else if (f)
-+ peer->prefix_cnt--;
- }
-
- void
-@@ -1152,7 +1442,7 @@ rde_update_withdraw(struct rde_peer *pee
- } while (0)
-
- #define CHECK_FLAGS(s, t, m) \
-- (((s) & ~(ATTR_EXTLEN | (m))) == (t))
-+ (((s) & ~(ATTR_DEFMASK | (m))) == (t))
-
- int
- rde_attr_parse(u_char *p, u_int16_t len, struct rde_peer *peer,
-@@ -1161,6 +1451,7 @@ rde_attr_parse(u_char *p, u_int16_t len,
- struct bgpd_addr nexthop;
- u_char *op = p, *npath;
- u_int32_t tmp32;
-+ int err;
- u_int16_t attr_len, nlen;
- u_int16_t plen = 0;
- u_int8_t flags;
-@@ -1195,6 +1486,7 @@ bad_len:
- switch (type) {
- case ATTR_UNDEF:
- /* ignore and drop path attributes with a type code of 0 */
-+ plen += attr_len;
- break;
- case ATTR_ORIGIN:
- if (attr_len != 1)
-@@ -1220,7 +1512,17 @@ bad_flags:
- case ATTR_ASPATH:
- if (!CHECK_FLAGS(flags, ATTR_WELL_KNOWN, 0))
- goto bad_flags;
-- if (aspath_verify(p, attr_len, rde_as4byte(peer)) != 0) {
-+ err = aspath_verify(p, attr_len, rde_as4byte(peer));
-+ if (err == AS_ERR_SOFT) {
-+ /*
-+ * soft errors like unexpected segment types are
-+ * not considered fatal and the path is just
-+ * marked invalid.
-+ */
-+ a->flags |= F_ATTR_PARSE_ERR;
-+ log_peer_warnx(&peer->conf, "bad ASPATH, "
-+ "path invalidated and prefix withdrawn");
-+ } else if (err != 0) {
- rde_update_err(peer, ERR_UPDATE, ERR_UPD_ASPATH,
- NULL, 0);
- return (-1);
-@@ -1248,7 +1550,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 +1607,21 @@ bad_flags:
- goto optattr;
- case ATTR_AGGREGATOR:
- if ((!rde_as4byte(peer) && attr_len != 6) ||
-- (rde_as4byte(peer) && attr_len != 8))
-- goto bad_len;
-- if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE, 0))
-+ (rde_as4byte(peer) && attr_len != 8)) {
-+ /*
-+ * ignore attribute in case of error as per
-+ * draft-ietf-idr-optional-transitive-00.txt
-+ * but only if partial bit is set
-+ */
-+ if ((flags & ATTR_PARTIAL) == 0)
-+ goto bad_len;
-+ log_peer_warnx(&peer->conf, "bad AGGREGATOR, "
-+ "partial attribute ignored");
-+ plen += attr_len;
-+ break;
-+ }
-+ if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
-+ ATTR_PARTIAL))
- goto bad_flags;
- if (!rde_as4byte(peer)) {
- /* need to inflate aggregator AS to 4-byte */
-@@ -1323,8 +1637,35 @@ bad_flags:
- /* 4-byte ready server take the default route */
- goto optattr;
- case ATTR_COMMUNITIES:
-- if ((attr_len & 0x3) != 0)
-- goto bad_len;
-+ if (attr_len % 4 != 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;
-+ a->flags |= F_ATTR_PARSE_ERR;
-+ log_peer_warnx(&peer->conf, "bad COMMUNITIES, "
-+ "path invalidated and prefix withdrawn");
-+ }
-+ if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
-+ ATTR_PARTIAL))
-+ goto bad_flags;
-+ goto optattr;
-+ case ATTR_EXT_COMMUNITIES:
-+ if (attr_len % 8 != 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;
-+ a->flags |= F_ATTR_PARSE_ERR;
-+ log_peer_warnx(&peer->conf, "bad EXT_COMMUNITIES, "
-+ "path invalidated and prefix withdrawn");
-+ }
- if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
- ATTR_PARTIAL))
- goto bad_flags;
-@@ -1336,7 +1677,7 @@ bad_flags:
- goto bad_flags;
- goto optattr;
- case ATTR_CLUSTER_LIST:
-- if ((attr_len & 0x3) != 0)
-+ if (attr_len % 4 != 0)
- goto bad_len;
- if (!CHECK_FLAGS(flags, ATTR_OPTIONAL, 0))
- goto bad_flags;
-@@ -1370,8 +1711,15 @@ bad_flags:
- plen += attr_len;
- break;
- case ATTR_AS4_AGGREGATOR:
-- if (attr_len != 8)
-- goto bad_len;
-+ if (attr_len != 8) {
-+ /* see ATTR_AGGREGATOR ... */
-+ if ((flags & ATTR_PARTIAL) == 0)
-+ goto bad_len;
-+ log_peer_warnx(&peer->conf, "bad AS4_AGGREGATOR, "
-+ "partial attribute ignored");
-+ plen += attr_len;
-+ break;
-+ }
- if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
- ATTR_PARTIAL))
- goto bad_flags;
-@@ -1381,20 +1729,31 @@ bad_flags:
- if (!CHECK_FLAGS(flags, ATTR_OPTIONAL|ATTR_TRANSITIVE,
- ATTR_PARTIAL))
- goto bad_flags;
-- if (aspath_verify(p, attr_len, 1) != 0) {
-+ if ((err = aspath_verify(p, attr_len, 1)) != 0) {
- /*
- * XXX RFC does not specify how to handle errors.
- * XXX Instead of dropping the session because of a
-- * XXX bad path just mark the full update as not
-- * XXX loop-free the update is no longer eligible and
-- * XXX will not be considered for routing or
-- * XXX redistribution. Something better is needed.
-+ * XXX bad path just mark the full update as having
-+ * XXX a parse error which makes the update no longer
-+ * XXX eligible and will not be considered for routing
-+ * XXX or redistribution.
-+ * XXX We follow draft-ietf-idr-optional-transitive
-+ * XXX by looking at the partial bit.
-+ * XXX Consider soft errors similar to a partial attr.
- */
-- a->flags |= F_ATTR_LOOP;
-- goto optattr;
-- }
-- a->flags |= F_ATTR_AS4BYTE_NEW;
-- goto optattr;
-+ if (flags & ATTR_PARTIAL || err == AS_ERR_SOFT) {
-+ a->flags |= F_ATTR_PARSE_ERR;
-+ log_peer_warnx(&peer->conf, "bad AS4_PATH, "
-+ "path invalidated and prefix withdrawn");
-+ goto optattr;
-+ } else {
-+ rde_update_err(peer, ERR_UPDATE, ERR_UPD_ASPATH,
-+ NULL, 0);
-+ return (-1);
-+ }
-+ }
-+ a->flags |= F_ATTR_AS4BYTE_NEW;
-+ goto optattr;
- default:
- if ((flags & ATTR_OPTIONAL) == 0) {
- rde_update_err(peer, ERR_UPDATE, ERR_UPD_UNKNWN_WK_ATTR,
-@@ -1415,6 +1774,42 @@ bad_list:
-
- return (plen);
- }
-+
-+int
-+rde_attr_add(struct rde_aspath *a, u_char *p, u_int16_t len)
-+{
-+ u_int16_t attr_len;
-+ u_int16_t plen = 0;
-+ u_int8_t flags;
-+ u_int8_t type;
-+ u_int8_t tmp8;
-+
-+ if (a == NULL) /* no aspath, nothing to do */
-+ return (0);
-+ if (len < 3)
-+ return (-1);
-+
-+ UPD_READ(&flags, p, plen, 1);
-+ UPD_READ(&type, p, plen, 1);
-+
-+ if (flags & ATTR_EXTLEN) {
-+ if (len - plen < 2)
-+ return (-1);
-+ UPD_READ(&attr_len, p, plen, 2);
-+ attr_len = ntohs(attr_len);
-+ } else {
-+ UPD_READ(&tmp8, p, plen, 1);
-+ attr_len = tmp8;
-+ }
-+
-+ if (len - plen < attr_len)
-+ return (-1);
-+
-+ if (attr_optadd(a, flags, type, p, attr_len) == -1)
-+ return (-1);
-+ return (0);
-+}
-+
- #undef UPD_READ
- #undef CHECK_FLAGS
-
-@@ -1440,8 +1835,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,
-- 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;
-@@ -1457,8 +1852,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 +1867,144 @@ rde_get_mp_nexthop(u_char *data, u_int16
- log_warnx("bad multiprotocol nexthop, bad size");
- return (-1);
- }
-- 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]) {
-+ int ifindex;
-+
-+ ifindex = if_nametoindex(peer->conf.lliface);
-+ if (ifindex != 0) {
-+ SET_IN6_LINKLOCAL_IFINDEX(nexthop.v6, ifindex);
-+ nexthop.scope_id = ifindex;
-+ } else
-+ log_warnx("bad interface: %s", peer->conf.lliface);
-+ }
-+#endif
-+ break;
-+ case AID_VPN_IPv4:
- /*
-- * 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 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);
- }
-
- int
- rde_update_get_prefix(u_char *p, u_int16_t len, struct bgpd_addr *prefix,
- u_int8_t *prefixlen)
- {
-- 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,25 +2014,50 @@ 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
- rde_update_err(struct rde_peer *peer, u_int8_t error, u_int8_t suberr,
- void *data, u_int16_t size)
- {
-- struct buf *wbuf;
-+ struct ibuf *wbuf;
-
- if ((wbuf = imsg_create(ibuf_se, IMSG_UPDATE_ERR, peer->conf.id, 0,
- size + sizeof(error) + sizeof(suberr))) == NULL)
-@@ -1616,16 +2109,30 @@ rde_as4byte_fixup(struct rde_peer *peer,
- struct attr *nasp, *naggr, *oaggr;
- u_int32_t as;
-
-+ /*
-+ * if either ATTR_AS4_AGGREGATOR or ATTR_AS4_PATH is present
-+ * try to fixup the attributes.
-+ * Do not fixup if F_ATTR_PARSE_ERR is set.
-+ */
-+ if (!(a->flags & F_ATTR_AS4BYTE_NEW) || a->flags & F_ATTR_PARSE_ERR)
-+ return;
-+
- /* first get the attributes */
- nasp = attr_optget(a, ATTR_AS4_PATH);
- naggr = attr_optget(a, ATTR_AS4_AGGREGATOR);
-
- if (rde_as4byte(peer)) {
- /* NEW session using 4-byte ASNs */
-- if (nasp)
-+ if (nasp) {
-+ log_peer_warnx(&peer->conf, "uses 4-byte ASN "
-+ "but sent AS4_PATH attribute.");
- attr_free(a, nasp);
-- if (naggr)
-+ }
-+ if (naggr) {
-+ log_peer_warnx(&peer->conf, "uses 4-byte ASN "
-+ "but sent AS4_AGGREGATOR attribute.");
- attr_free(a, naggr);
-+ }
- return;
- }
- /* OLD session using 2-byte ASNs */
-@@ -1669,6 +2176,10 @@ rde_reflector(struct rde_peer *peer, str
- u_int16_t len;
- u_int32_t id;
-
-+ /* do not consider updates with parse errors */
-+ if (asp->flags & F_ATTR_PARSE_ERR)
-+ return;
-+
- /* 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) {
-@@ -1677,10 +2188,10 @@ rde_reflector(struct rde_peer *peer, str
- return;
- }
- } else if (conf->flags & BGPD_FLAG_REFLECTOR) {
-- if (peer->conf.ebgp == 0)
-- id = htonl(peer->remote_bgpid);
-- else
-+ if (peer->conf.ebgp)
- id = conf->bgpid;
-+ else
-+ id = htonl(peer->remote_bgpid);
- if (attr_optadd(asp, ATTR_OPTIONAL, ATTR_ORIGINATOR_ID,
- &id, sizeof(u_int32_t)) == -1)
- fatalx("attr_optadd failed but impossible");
-@@ -1724,17 +2235,17 @@ void
- rde_dump_rib_as(struct prefix *p, struct rde_aspath *asp, pid_t pid, int flags)
- {
- struct ctl_show_rib rib;
-- struct buf *wbuf;
-+ struct ibuf *wbuf;
- struct attr *a;
- void *bp;
-+ time_t staletime;
- u_int8_t l;
-
- bzero(&rib, sizeof(rib));
- rib.lastchange = p->lastchange;
- rib.local_pref = asp->lpref;
- rib.med = asp->med;
-- rib.prefix_cnt = asp->prefix_cnt;
-- rib.active_cnt = asp->active_cnt;
-+ rib.weight = asp->weight;
- strlcpy(rib.descr, asp->peer->conf.descr, sizeof(rib.descr));
- memcpy(&rib.remote_addr, &asp->peer->remote_addr,
- sizeof(rib.remote_addr));
-@@ -1748,23 +2259,26 @@ 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->rib->active == p)
-- rib.flags |= F_RIB_ACTIVE;
-- if (asp->peer->conf.ebgp == 0)
-- rib.flags |= F_RIB_INTERNAL;
-+ rib.flags |= F_PREF_ACTIVE;
-+ if (!asp->peer->conf.ebgp)
-+ rib.flags |= F_PREF_INTERNAL;
- if (asp->flags & F_PREFIX_ANNOUNCED)
-- rib.flags |= F_RIB_ANNOUNCE;
-+ rib.flags |= F_PREF_ANNOUNCE;
- if (asp->nexthop == NULL || asp->nexthop->state == NEXTHOP_REACH)
-- rib.flags |= F_RIB_ELIGIBLE;
-+ rib.flags |= F_PREF_ELIGIBLE;
- if (asp->flags & F_ATTR_LOOP)
-- rib.flags &= ~F_RIB_ELIGIBLE;
-+ rib.flags &= ~F_PREF_ELIGIBLE;
-+ staletime = asp->peer->staletime[p->prefix->aid];
-+ if (staletime && p->lastchange <= staletime)
-+ rib.flags |= F_PREF_STALE;
- rib.aspath_len = aspath_length(asp->aspath);
-
- if ((wbuf = imsg_create(ibuf_se_ctl, IMSG_CTL_SHOW_RIB, 0, pid,
-@@ -1784,13 +2298,13 @@ rde_dump_rib_as(struct prefix *p, struct
- IMSG_CTL_SHOW_RIB_ATTR, 0, pid,
- attr_optlen(a))) == NULL)
- return;
-- if ((bp = buf_reserve(wbuf, attr_optlen(a))) == NULL) {
-- buf_free(wbuf);
-+ if ((bp = ibuf_reserve(wbuf, attr_optlen(a))) == NULL) {
-+ ibuf_free(wbuf);
- return;
- }
- if (attr_write(bp, attr_optlen(a), a->flags,
- a->type, a->data, a->len) == -1) {
-- buf_free(wbuf);
-+ ibuf_free(wbuf);
- return;
- }
- imsg_close(ibuf_se_ctl, wbuf);
-@@ -1828,17 +2342,20 @@ rde_dump_filter(struct prefix *p, struct
- {
- struct rde_peer *peer;
-
-- if (req->flags & F_CTL_ADJ_IN ||
-+ 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))
-+ if (req->type == IMSG_CTL_SHOW_RIB_AS &&
-+ !aspath_match(p->aspath->aspath->data,
-+ p->aspath->aspath->len, req->as.type, req->as.as))
- return;
- 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;
-+ if ((req->flags & F_CTL_ACTIVE) && p->rib->active != p)
-+ return;
- rde_dump_rib_as(p, p->aspath, req->pid, req->flags);
- } else if (req->flags & F_CTL_ADJ_OUT) {
- if (p->rib->active != p)
-@@ -1872,7 +2389,7 @@ rde_dump_prefix_upcall(struct rib_entry
-
- pt = re->prefix;
- pt_getaddr(pt, &addr);
-- if (addr.af != ctx->req.prefix.af)
-+ if (addr.aid != ctx->req.prefix.aid)
- return;
- if (ctx->req.prefixlen > pt->prefixlen)
- return;
-@@ -1889,6 +2406,7 @@ rde_dump_ctx_new(struct ctl_show_rib_req
- struct rib_entry *re;
- u_int error;
- u_int16_t id;
-+ u_int8_t hostplen = 0;
-
- if ((ctx = calloc(1, sizeof(*ctx))) == NULL) {
- log_warn("rde_dump_ctx_new");
-@@ -1902,6 +2420,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;
- }
-
-@@ -1924,7 +2443,18 @@ rde_dump_ctx_new(struct ctl_show_rib_req
- ctx->ribctx.ctx_upcall = rde_dump_prefix_upcall;
- break;
- }
-- if (req->prefixlen == 32)
-+ switch (req->prefix.aid) {
-+ case AID_INET:
-+ case AID_VPN_IPv4:
-+ hostplen = 32;
-+ break;
-+ case AID_INET6:
-+ hostplen = 128;
-+ break;
-+ default:
-+ fatalx("rde_dump_ctx_new: unknown af");
-+ }
-+ if (req->prefixlen == hostplen)
- re = rib_lookup(&ribs[id], &req->prefix);
- else
- re = rib_get(&ribs[id], &req->prefix, req->prefixlen);
-@@ -1937,7 +2467,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);
- }
-
-@@ -1971,13 +2501,17 @@ rde_dump_mrt_new(struct mrt *mrt, pid_t
- free(ctx);
- return;
- }
-+
-+ if (ctx->mrt.type == MRT_TABLE_DUMP_V2)
-+ mrt_dump_v2_hdr(&ctx->mrt, conf, &peerlist);
-+
- 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);
- }
-@@ -1985,13 +2519,25 @@ rde_dump_mrt_new(struct mrt *mrt, pid_t
- /*
- * kroute specific functions
- */
-+int
-+rde_rdomain_import(struct rde_aspath *asp, struct rdomain *rd)
-+{
-+ struct filter_set *s;
-+
-+ TAILQ_FOREACH(s, &rd->import, entry) {
-+ if (community_ext_match(asp, &s->action.ext_community, 0))
-+ return (1);
-+ }
-+ return (0);
-+}
-+
- void
--rde_send_kroute(struct prefix *new, struct prefix *old)
-+rde_send_kroute(struct prefix *new, struct prefix *old, u_int16_t ribid)
- {
-- struct kroute_label kl;
-- struct kroute6_label kl6;
-+ struct kroute_full kr;
- struct bgpd_addr addr;
- struct prefix *p;
-+ struct rdomain *rd;
- enum imsg_type type;
-
- /*
-@@ -2011,43 +2557,43 @@ rde_send_kroute(struct prefix *new, stru
- }
-
- pt_getaddr(p->prefix, &addr);
-- switch (addr.af) {
-- case AF_INET:
-- bzero(&kl, sizeof(kl));
-- kl.kr.prefix.s_addr = addr.v4.s_addr;
-- kl.kr.prefixlen = p->prefix->prefixlen;
-- if (p->aspath->flags & F_NEXTHOP_REJECT)
-- kl.kr.flags |= F_REJECT;
-- if (p->aspath->flags & F_NEXTHOP_BLACKHOLE)
-- kl.kr.flags |= F_BLACKHOLE;
-- if (type == IMSG_KROUTE_CHANGE)
-- kl.kr.nexthop.s_addr =
-- p->aspath->nexthop->true_nexthop.v4.s_addr;
-- strlcpy(kl.label, rtlabel_id2name(p->aspath->rtlabelid),
-- sizeof(kl.label));
-- if (imsg_compose(ibuf_main, type, 0, 0, -1, &kl,
-- sizeof(kl)) == -1)
-- fatal("imsg_compose error");
-+ bzero(&kr, sizeof(kr));
-+ memcpy(&kr.prefix, &addr, sizeof(kr.prefix));
-+ kr.prefixlen = p->prefix->prefixlen;
-+ if (p->aspath->flags & F_NEXTHOP_REJECT)
-+ kr.flags |= F_REJECT;
-+ if (p->aspath->flags & F_NEXTHOP_BLACKHOLE)
-+ kr.flags |= F_BLACKHOLE;
-+ if (type == IMSG_KROUTE_CHANGE)
-+ memcpy(&kr.nexthop, &p->aspath->nexthop->true_nexthop,
-+ sizeof(kr.nexthop));
-+ strlcpy(kr.label, rtlabel_id2name(p->aspath->rtlabelid),
-+ sizeof(kr.label));
-+
-+ switch (addr.aid) {
-+ case AID_VPN_IPv4:
-+ if (ribid != 1)
-+ /* not Loc-RIB, no update for VPNs */
-+ break;
-+
-+ SIMPLEQ_FOREACH(rd, rdomains_l, entry) {
-+ if (!rde_rdomain_import(p->aspath, rd))
-+ continue;
-+ /* must send exit_nexthop so that correct MPLS tunnel
-+ * is chosen
-+ */
-+ if (type == IMSG_KROUTE_CHANGE)
-+ memcpy(&kr.nexthop,
-+ &p->aspath->nexthop->exit_nexthop,
-+ sizeof(kr.nexthop));
-+ if (imsg_compose(ibuf_main, type, rd->rtableid, 0, -1,
-+ &kr, sizeof(kr)) == -1)
-+ fatal("imsg_compose error");
-+ }
- break;
-- case AF_INET6:
-- bzero(&kl6, sizeof(kl6));
-- memcpy(&kl6.kr.prefix, &addr.v6, sizeof(struct in6_addr));
-- kl6.kr.prefixlen = p->prefix->prefixlen;
-- if (p->aspath->flags & F_NEXTHOP_REJECT)
-- kl6.kr.flags |= F_REJECT;
-- if (p->aspath->flags & F_NEXTHOP_BLACKHOLE)
-- kl6.kr.flags |= F_BLACKHOLE;
-- if (type == IMSG_KROUTE_CHANGE) {
-- type = IMSG_KROUTE6_CHANGE;
-- memcpy(&kl6.kr.nexthop,
-- &p->aspath->nexthop->true_nexthop.v6,
-- sizeof(struct in6_addr));
-- } else
-- type = IMSG_KROUTE6_DELETE;
-- strlcpy(kl6.label, rtlabel_id2name(p->aspath->rtlabelid),
-- sizeof(kl6.label));
-- if (imsg_compose(ibuf_main, type, 0, 0, -1, &kl6,
-- sizeof(kl6)) == -1)
-+ default:
-+ if (imsg_compose(ibuf_main, type, ribs[ribid].rtableid, 0, -1,
-+ &kr, sizeof(kr)) == -1)
- fatal("imsg_compose error");
- break;
- }
-@@ -2098,7 +2644,6 @@ rde_send_pftable_commit(void)
- void
- rde_send_nexthop(struct bgpd_addr *next, int valid)
- {
-- size_t size;
- int type;
-
- if (valid)
-@@ -2106,8 +2651,6 @@ rde_send_nexthop(struct bgpd_addr *next,
- else
- type = IMSG_NEXTHOP_REMOVE;
-
-- size = sizeof(struct bgpd_addr);
--
- if (imsg_compose(ibuf_main, type, 0, 0, -1, next,
- sizeof(struct bgpd_addr)) == -1)
- fatal("imsg_compose error");
-@@ -2201,6 +2744,10 @@ rde_softreconfig_in(struct rib_entry *re
- continue;
-
- for (i = 1; i < rib_size; i++) {
-+ /* only active ribs need a softreconfig rerun */
-+ if (ribs[i].state != RECONF_KEEP)
-+ continue;
-+
- /* check if prefix changed */
- oa = rde_filter(i, &oasp, rules_l, peer, asp, &addr,
- pt->prefixlen, peer, DIR_IN);
-@@ -2228,7 +2775,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);
- }
-
-@@ -2241,6 +2788,104 @@ done:
- }
- }
-
-+void
-+rde_softreconfig_load(struct rib_entry *re, void *ptr)
-+{
-+ struct rib *rib = ptr;
-+ struct prefix *p, *np;
-+ struct pt_entry *pt;
-+ struct rde_peer *peer;
-+ struct rde_aspath *asp, *nasp;
-+ enum filter_actions action;
-+ struct bgpd_addr addr;
-+
-+ pt = re->prefix;
-+ pt_getaddr(pt, &addr);
-+ 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;
-+
-+ action = rde_filter(rib->id, &nasp, newrules, peer, asp, &addr,
-+ pt->prefixlen, peer, DIR_IN);
-+ nasp = nasp != NULL ? nasp : asp;
-+
-+ if (action == ACTION_ALLOW) {
-+ /* update Local-RIB */
-+ path_update(rib, peer, nasp, &addr, pt->prefixlen);
-+ }
-+
-+ if (nasp != asp)
-+ path_put(nasp);
-+ }
-+}
-+
-+void
-+rde_softreconfig_load_peer(struct rib_entry *re, void *ptr)
-+{
-+ struct rde_peer *peer = ptr;
-+ struct prefix *p = re->active;
-+ struct pt_entry *pt;
-+ struct rde_aspath *nasp;
-+ enum filter_actions na;
-+ struct bgpd_addr addr;
-+
-+ pt = re->prefix;
-+ pt_getaddr(pt, &addr);
-+
-+ /* check if prefix was announced */
-+ if (up_test_update(peer, p) != 1)
-+ return;
-+
-+ na = rde_filter(re->ribid, &nasp, newrules, peer, p->aspath,
-+ &addr, pt->prefixlen, p->aspath->peer, DIR_OUT);
-+ nasp = nasp != NULL ? nasp : p->aspath;
-+
-+ if (na == ACTION_DENY)
-+ /* nothing todo */
-+ goto done;
-+
-+ /* send update */
-+ up_generate(peer, nasp, &addr, pt->prefixlen);
-+done:
-+ if (nasp != p->aspath)
-+ path_put(nasp);
-+}
-+
-+void
-+rde_softreconfig_unload_peer(struct rib_entry *re, void *ptr)
-+{
-+ struct rde_peer *peer = ptr;
-+ struct prefix *p = re->active;
-+ struct pt_entry *pt;
-+ struct rde_aspath *oasp;
-+ enum filter_actions oa;
-+ struct bgpd_addr addr;
-+
-+ pt = re->prefix;
-+ pt_getaddr(pt, &addr);
-+
-+ /* check if prefix was announced */
-+ if (up_test_update(peer, p) != 1)
-+ return;
-+
-+ oa = rde_filter(re->ribid, &oasp, rules_l, peer, p->aspath,
-+ &addr, pt->prefixlen, p->aspath->peer, DIR_OUT);
-+ oasp = oasp != NULL ? oasp : p->aspath;
-+
-+ if (oa == ACTION_DENY)
-+ /* nothing todo */
-+ goto done;
-+
-+ /* send withdraw */
-+ up_generate(peer, NULL, &addr, pt->prefixlen);
-+done:
-+ if (oasp != p->aspath)
-+ path_put(oasp);
-+}
-+
- /*
- * update specific functions
- */
-@@ -2252,7 +2897,7 @@ rde_up_dump_upcall(struct rib_entry *re,
- struct rde_peer *peer = ptr;
-
- if (re->ribid != peer->ribid)
-- fatalx("King Bula: monsterous evil horror.");
-+ fatalx("King Bula: monstrous evil horror.");
- if (re->active == NULL)
- return;
- up_generate_updates(rules_l, peer, re->active, NULL);
-@@ -2265,7 +2910,7 @@ rde_generate_updates(u_int16_t ribid, st
-
- /*
- * If old is != NULL we know it was active and should be removed.
-- * If new is != NULL we know it is reachable and then we should
-+ * If new is != NULL we know it is reachable and then we should
- * generate an update.
- */
- if (old == NULL && new == NULL)
-@@ -2286,7 +2931,7 @@ void
- rde_update_queue_runner(void)
- {
- 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;
-
- len = sizeof(queue_buf) - MSGSIZE_HEADER;
-@@ -2300,7 +2945,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 +2955,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_update6_queue_runner(void)
-+rde_update6_queue_runner(u_int8_t aid)
- {
- 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;
-
- /* first withdraws ... */
-@@ -2346,7 +3009,7 @@ rde_update6_queue_runner(void)
- if (peer->state != PEER_UP)
- continue;
- len = sizeof(queue_buf) - MSGSIZE_HEADER;
-- 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 +3032,18 @@ rde_update6_queue_runner(void)
- if (peer->state != PEER_UP)
- continue;
- len = sizeof(queue_buf) - MSGSIZE_HEADER;
-- 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 +3082,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 +3100,6 @@ void
- peer_init(u_int32_t hashsize)
- {
- struct peer_config pc;
-- struct in_addr id;
- u_int32_t hs, i;
-
- for (hs = 1; hs < hashsize; hs <<= 1)
-@@ -2445,17 +3115,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));
-+ 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
-@@ -2534,14 +3200,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 +3221,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;
- }
- }
-@@ -2577,23 +3233,22 @@ void
- peer_up(u_int32_t id, struct session_up *sup)
- {
- struct rde_peer *peer;
-+ u_int8_t i;
-
- peer = peer_get(id);
- if (peer == NULL) {
-- log_warnx("peer_up: peer id %d already exists", id);
-+ log_warnx("peer_up: unknown peer id %d", id);
- return;
- }
-
-- if (peer->state != PEER_DOWN && peer->state != PEER_NONE)
-+ if (peer->state != PEER_DOWN && peer->state != PEER_NONE &&
-+ peer->state != PEER_UP)
- fatalx("peer_up: bad state");
- peer->remote_bgpid = ntohl(sup->remote_bgpid);
- 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 +3262,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
-@@ -2641,43 +3299,90 @@ peer_down(u_int32_t id)
- free(peer);
- }
-
-+/*
-+ * Flush all routes older then staletime. If staletime is 0 all routes will
-+ * be flushed.
-+ */
-+void
-+peer_flush(struct rde_peer *peer, u_int8_t aid)
-+{
-+ struct rde_aspath *asp, *nasp;
-+
-+ /* walk through per peer RIB list and remove all stale prefixes. */
-+ for (asp = LIST_FIRST(&peer->path_h); asp != NULL; asp = nasp) {
-+ nasp = LIST_NEXT(asp, peer_l);
-+ path_remove_stale(asp, aid);
-+ }
-+
-+ /* Deletions are performed in path_remove() */
-+ rde_send_pftable_commit();
-+
-+ /* flushed no need to keep staletime */
-+ peer->staletime[aid] = 0;
-+}
-+
- void
--peer_dump(u_int32_t id, u_int16_t afi, u_int8_t safi)
-+peer_stale(u_int32_t id, u_int8_t aid)
- {
- struct rde_peer *peer;
-+ time_t now;
-
- peer = peer_get(id);
- if (peer == NULL) {
-- log_warnx("peer_down: unknown peer id %d", id);
-+ log_warnx("peer_stale: unknown peer id %d", id);
- return;
- }
-
-- if (afi == AFI_ALL || afi == AFI_IPv4)
-- if (safi == SAFI_ALL || safi == SAFI_UNICAST) {
-- 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)
-- up_generate_default(rules_l, peer, AF_INET6);
-- else
-- rib_dump(&ribs[peer->ribid], rde_up_dump_upcall,
-- peer, AF_INET6);
-- }
-+ if (peer->staletime[aid])
-+ peer_flush(peer, aid);
-+ peer->staletime[aid] = now = time(NULL);
-
-- if (peer->capa_received.restart && peer->capa_announced.restart)
-- peer_send_eor(peer, afi, safi);
-+ /* make sure new prefixes start on a higher timestamp */
-+ do {
-+ sleep(1);
-+ } while (now >= time(NULL));
- }
-
--/* End-of-RIB marker, draft-ietf-idr-restart-13.txt */
- void
--peer_send_eor(struct rde_peer *peer, u_int16_t afi, u_int16_t safi)
-+peer_dump(u_int32_t id, u_int8_t aid)
- {
-- if (afi == AFI_IPv4 && safi == SAFI_UNICAST) {
-+ struct rde_peer *peer;
-+
-+ peer = peer_get(id);
-+ if (peer == NULL) {
-+ log_warnx("peer_dump: unknown peer id %d", id);
-+ return;
-+ }
-+
-+ 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.grestart.restart)
-+ up_generate_marker(peer, aid);
-+}
-+
-+/* End-of-RIB marker, RFC 4724 */
-+void
-+peer_recv_eor(struct rde_peer *peer, u_int8_t aid)
-+{
-+ peer->prefix_rcvd_eor++;
-+
-+ /* First notify SE to remove possible race with the timeout. */
-+ if (imsg_compose(ibuf_se, IMSG_SESSION_RESTARTED, peer->conf.id,
-+ 0, -1, &aid, sizeof(aid)) == -1)
-+ fatal("imsg_compose error");
-+}
-+
-+void
-+peer_send_eor(struct rde_peer *peer, u_int8_t aid)
-+{
-+ u_int16_t afi;
-+ u_int8_t safi;
-+
-+ peer->prefix_sent_eor++;
-+
-+ if (aid == AID_INET) {
- u_char null[4];
-
- bzero(&null, 4);
-@@ -2688,6 +3393,9 @@ peer_send_eor(struct rde_peer *peer, u_i
- u_int16_t i;
- u_char buf[10];
-
-+ 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 */
-@@ -2709,39 +3417,61 @@ peer_send_eor(struct rde_peer *peer, u_i
- * network announcement stuff
- */
- void
--network_init(struct network_head *net_l)
--{
-- struct network *n;
--
-- reloadtime = time(NULL);
--
-- while ((n = TAILQ_FIRST(net_l)) != NULL) {
-- TAILQ_REMOVE(net_l, n, entry);
-- network_add(&n->net, 1);
-- free(n);
-- }
--}
--
--void
- network_add(struct network_config *nc, int flagstatic)
- {
-+ struct rdomain *rd;
- struct rde_aspath *asp;
-+ struct filter_set_head *vpnset = NULL;
-+ in_addr_t prefix4;
- u_int16_t i;
-
-- asp = path_get();
-- asp->aspath = aspath_get(NULL, 0);
-- asp->origin = ORIGIN_IGP;
-- 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 (nc->rtableid) {
-+ SIMPLEQ_FOREACH(rd, rdomains_l, entry) {
-+ if (rd->rtableid != nc->rtableid)
-+ continue;
-+ switch (nc->prefix.aid) {
-+ case AID_INET:
-+ prefix4 = nc->prefix.v4.s_addr;
-+ bzero(&nc->prefix, sizeof(nc->prefix));
-+ nc->prefix.aid = AID_VPN_IPv4;
-+ nc->prefix.vpn4.rd = rd->rd;
-+ nc->prefix.vpn4.addr.s_addr = prefix4;
-+ nc->prefix.vpn4.labellen = 3;
-+ nc->prefix.vpn4.labelstack[0] =
-+ (rd->label >> 12) & 0xff;
-+ nc->prefix.vpn4.labelstack[1] =
-+ (rd->label >> 4) & 0xff;
-+ nc->prefix.vpn4.labelstack[2] =
-+ (rd->label << 4) & 0xf0;
-+ nc->prefix.vpn4.labelstack[2] |= BGP_MPLS_BOS;
-+ vpnset = &rd->export;
-+ break;
-+ default:
-+ log_warnx("unable to VPNize prefix");
-+ filterset_free(&nc->attrset);
-+ return;
-+ }
-+ }
-+ }
-+
-+ if (nc->type == NETWORK_MRTCLONE) {
-+ asp = nc->asp;
-+ } else {
-+ asp = path_get();
-+ asp->aspath = aspath_get(NULL, 0);
-+ asp->origin = ORIGIN_IGP;
-+ 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;
--
-- rde_apply_set(asp, &nc->attrset, nc->prefix.af, peerself, peerself);
-+ rde_apply_set(asp, &nc->attrset, nc->prefix.aid, peerself, peerself);
-+ if (vpnset)
-+ rde_apply_set(asp, vpnset, nc->prefix.aid, 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);
- }
-@@ -2749,12 +3479,41 @@ network_add(struct network_config *nc, i
- void
- network_delete(struct network_config *nc, int flagstatic)
- {
-- u_int32_t flags = F_PREFIX_ANNOUNCED;
-- u_int32_t i;
-+ struct rdomain *rd;
-+ in_addr_t prefix4;
-+ u_int32_t flags = F_PREFIX_ANNOUNCED;
-+ u_int32_t i;
-
- if (!flagstatic)
- flags |= F_ANN_DYNAMIC;
-
-+ if (nc->rtableid) {
-+ SIMPLEQ_FOREACH(rd, rdomains_l, entry) {
-+ if (rd->rtableid != nc->rtableid)
-+ continue;
-+ switch (nc->prefix.aid) {
-+ case AID_INET:
-+ prefix4 = nc->prefix.v4.s_addr;
-+ bzero(&nc->prefix, sizeof(nc->prefix));
-+ nc->prefix.aid = AID_VPN_IPv4;
-+ nc->prefix.vpn4.rd = rd->rd;
-+ nc->prefix.vpn4.addr.s_addr = prefix4;
-+ nc->prefix.vpn4.labellen = 3;
-+ nc->prefix.vpn4.labelstack[0] =
-+ (rd->label >> 12) & 0xff;
-+ nc->prefix.vpn4.labelstack[1] =
-+ (rd->label >> 4) & 0xff;
-+ nc->prefix.vpn4.labelstack[2] =
-+ (rd->label << 4) & 0xf0;
-+ nc->prefix.vpn4.labelstack[2] |= BGP_MPLS_BOS;
-+ break;
-+ default:
-+ log_warnx("unable to VPNize prefix");
-+ return;
-+ }
-+ }
-+ }
-+
- for (i = rib_size - 1; i > 0; i--)
- prefix_remove(&ribs[i], peerself, &nc->prefix, nc->prefixlen,
- flags);
-@@ -2764,38 +3523,31 @@ void
- network_dump_upcall(struct rib_entry *re, void *ptr)
- {
- struct prefix *p;
-- struct kroute k;
-- struct kroute6 k6;
-+ struct kroute_full k;
- struct bgpd_addr addr;
- struct rde_dump_ctx *ctx = ptr;
-
- LIST_FOREACH(p, &re->prefix_h, rib_l) {
- if (!(p->aspath->flags & F_PREFIX_ANNOUNCED))
- continue;
-- if (p->prefix->af == AF_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)
-- k.flags = F_KERNEL;
-- if (imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_NETWORK, 0,
-- ctx->req.pid, -1, &k, sizeof(k)) == -1)
-- log_warnx("network_dump_upcall: "
-- "imsg_compose error");
-- }
-- if (p->prefix->af == AF_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)
-- k6.flags = F_KERNEL;
-- if (imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_NETWORK6, 0,
-- ctx->req.pid, -1, &k6, sizeof(k6)) == -1)
-- log_warnx("network_dump_upcall: "
-- "imsg_compose error");
-- }
-+ pt_getaddr(p->prefix, &addr);
-+
-+ bzero(&k, sizeof(k));
-+ memcpy(&k.prefix, &addr, sizeof(k.prefix));
-+ if (p->aspath->nexthop == NULL ||
-+ p->aspath->nexthop->state != NEXTHOP_REACH)
-+ k.nexthop.aid = k.prefix.aid;
-+ else
-+ memcpy(&k.nexthop, &p->aspath->nexthop->true_nexthop,
-+ sizeof(k.nexthop));
-+ k.prefixlen = p->prefix->prefixlen;
-+ k.flags = F_KERNEL;
-+ if ((p->aspath->flags & F_ANN_DYNAMIC) == 0)
-+ k.flags = F_STATIC;
-+ if (imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_NETWORK, 0,
-+ ctx->req.pid, -1, &k, sizeof(k)) == -1)
-+ log_warnx("network_dump_upcall: "
-+ "imsg_compose error");
- }
- }
-
-@@ -2841,10 +3593,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)
-@@ -2855,10 +3607,11 @@ sa_cmp(struct bgpd_addr *a, struct socka
- #ifdef __KAME__
- /* directly stolen from sbin/ifconfig/ifconfig.c */
- if (IN6_IS_ADDR_LINKLOCAL(&in6_b->sin6_addr)) {
-- in6_b->sin6_scope_id =
-- ntohs(*(u_int16_t *)&in6_b->sin6_addr.s6_addr[2]);
-- in6_b->sin6_addr.s6_addr[2] =
-- in6_b->sin6_addr.s6_addr[3] = 0;
-+ if (in6_b->sin6_scope_id == 0) {
-+ in6_b->sin6_scope_id =
-+ IN6_LINKLOCAL_IFINDEX(in6_b->sin6_addr);
-+ }
-+ SET_IN6_LINKLOCAL_IFINDEX(in6_b->sin6_addr, 0);
- }
- #endif
- if (bcmp(&a->v6, &in6_b->sin6_addr,