diff options
Diffstat (limited to 'net/openbgpd/files/patch-bgpd_rde.c')
-rw-r--r-- | net/openbgpd/files/patch-bgpd_rde.c | 1016 |
1 files changed, 861 insertions, 155 deletions
diff --git a/net/openbgpd/files/patch-bgpd_rde.c b/net/openbgpd/files/patch-bgpd_rde.c index 55e10012aa47..a62bcf26fdc7 100644 --- a/net/openbgpd/files/patch-bgpd_rde.c +++ b/net/openbgpd/files/patch-bgpd_rde.c @@ -2,17 +2,25 @@ Index: bgpd/rde.c =================================================================== RCS file: /home/cvs/private/hrs/openbgpd/bgpd/rde.c,v retrieving revision 1.1.1.8 -retrieving revision 1.9 -diff -u -p -r1.1.1.8 -r1.9 +diff -u -p -r1.1.1.8 rde.c --- bgpd/rde.c 14 Feb 2010 20:19:57 -0000 1.1.1.8 -+++ bgpd/rde.c 10 Apr 2010 12:16:23 -0000 1.9 ++++ bgpd/rde.c 3 Jul 2011 04:43:59 -0000 @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.c,v 1.264 2009/06/29 12:22:16 claudio Exp $ */ +/* $OpenBSD: rde.c,v 1.290 2010/03/30 15:43:30 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> -@@ -51,12 +51,16 @@ void rde_update_withdraw(struct rde_pe +@@ -18,6 +18,8 @@ + + #include <sys/types.h> + #include <sys/socket.h> ++#include <sys/time.h> ++#include <sys/resource.h> + + #include <errno.h> + #include <ifaddrs.h> +@@ -51,12 +53,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); @@ -31,18 +39,24 @@ diff -u -p -r1.1.1.8 -r1.9 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, -@@ -81,8 +85,9 @@ void rde_dump_done(void *); +@@ -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,8 +96,8 @@ struct rde_peer *peer_add(u_int32_t, str +@@ -91,10 +101,9 @@ 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); @@ -51,9 +65,19 @@ diff -u -p -r1.1.1.8 -r1.9 +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_init(struct network_head *); void network_add(struct network_config *, int); -@@ -120,11 +125,12 @@ struct rde_dump_ctx { + void network_delete(struct network_config *, int); + void network_dump_upcall(struct rib_entry *, void *); +@@ -108,6 +117,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 +130,12 @@ struct rde_dump_ctx { }; struct rde_mrt_ctx { @@ -69,7 +93,7 @@ diff -u -p -r1.1.1.8 -r1.9 u_int rde_mrt_cnt; void -@@ -144,24 +150,17 @@ u_int32_t attrhashsize = 512; +@@ -144,24 +155,18 @@ u_int32_t attrhashsize = 512; u_int32_t nexthophashsize = 64; pid_t @@ -80,6 +104,7 @@ diff -u -p -r1.1.1.8 -r1.9 +rde_main(int pipe_m2r[2], int pipe_s2r[2], int pipe_m2s[2], int pipe_s2rctl[2], + int debug) { ++ struct rlimit rl; pid_t pid; struct passwd *pw; - struct peer *p; @@ -98,7 +123,7 @@ diff -u -p -r1.1.1.8 -r1.9 switch (pid = fork()) { case -1: -@@ -172,8 +171,6 @@ rde_main(struct bgpd_config *config, str +@@ -172,8 +177,6 @@ rde_main(struct bgpd_config *config, str return (pid); } @@ -107,7 +132,20 @@ diff -u -p -r1.1.1.8 -r1.9 if ((pw = getpwnam(BGPD_USER)) == NULL) fatal("getpwnam"); -@@ -194,6 +191,8 @@ rde_main(struct bgpd_config *config, str +@@ -185,6 +188,12 @@ rde_main(struct bgpd_config *config, str + setproctitle("route decision engine"); + bgpd_process = PROC_RDE; + ++ if (getrlimit(RLIMIT_DATA, &rl) == -1) ++ fatal("getrlimit"); ++ rl.rlim_cur = rl.rlim_max; ++ if (setrlimit(RLIMIT_DATA, &rl) == -1) ++ fatal("setrlimit"); ++ + if (setgroups(1, &pw->pw_gid) || + setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || + setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) +@@ -194,6 +203,8 @@ rde_main(struct bgpd_config *config, str signal(SIGINT, rde_sighdlr); signal(SIGPIPE, SIG_IGN); signal(SIGHUP, SIG_IGN); @@ -116,7 +154,7 @@ diff -u -p -r1.1.1.8 -r1.9 close(pipe_s2r[0]); close(pipe_s2rctl[0]); -@@ -210,50 +209,21 @@ rde_main(struct bgpd_config *config, str +@@ -210,50 +221,25 @@ rde_main(struct bgpd_config *config, str imsg_init(ibuf_se_ctl, pipe_s2rctl[1]); imsg_init(ibuf_main, pipe_m2r[1]); @@ -156,7 +194,11 @@ diff -u -p -r1.1.1.8 -r1.9 + if (rules_l == NULL) + fatal(NULL); + TAILQ_INIT(rules_l); -+ if ((conf = malloc(sizeof(struct bgpd_config))) == NULL) ++ 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"); @@ -173,20 +215,29 @@ diff -u -p -r1.1.1.8 -r1.9 while (rde_quit == 0) { 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 +@@ -287,11 +273,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; -+ LIST_FOREACH(mctx, &rde_mrts, entry) { ++ 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 +295,26 @@ rde_main(struct bgpd_config *config, str + } + +@@ -325,24 +318,17 @@ rde_main(struct bgpd_config *config, str if (pfd[PFD_PIPE_SESSION_CTL].revents & POLLIN) rde_dispatch_imsg_session(ibuf_se_ctl); @@ -196,7 +247,6 @@ diff -u -p -r1.1.1.8 -r1.9 - 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); @@ -205,17 +255,11 @@ diff -u -p -r1.1.1.8 -r1.9 - 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--; - } +- rde_mrt_cnt--; +- } - mrt = xmrt; -+ mctx = xmctx; ++ mrt_write(&mctx->mrt); ++ mctx = LIST_NEXT(mctx, entry); } rde_update_queue_runner(); @@ -225,7 +269,7 @@ diff -u -p -r1.1.1.8 -r1.9 if (ibuf_se_ctl->w.queued <= 0) rib_dump_runner(); } -@@ -351,11 +323,12 @@ rde_main(struct bgpd_config *config, str +@@ -351,11 +337,12 @@ rde_main(struct bgpd_config *config, str if (debug) rde_shutdown(); @@ -243,7 +287,7 @@ diff -u -p -r1.1.1.8 -r1.9 } msgbuf_clear(&ibuf_se->w); -@@ -378,13 +351,14 @@ rde_dispatch_imsg_session(struct imsgbuf +@@ -378,13 +365,14 @@ rde_dispatch_imsg_session(struct imsgbuf struct imsg imsg; struct peer p; struct peer_config pconf; @@ -260,7 +304,7 @@ diff -u -p -r1.1.1.8 -r1.9 if ((n = imsg_read(ibuf)) == -1) fatal("rde_dispatch_imsg_session: imsg_read error"); -@@ -423,12 +397,14 @@ rde_dispatch_imsg_session(struct imsgbuf +@@ -423,12 +411,14 @@ rde_dispatch_imsg_session(struct imsgbuf peer_down(imsg.hdr.peerid); break; case IMSG_REFRESH: @@ -278,7 +322,7 @@ diff -u -p -r1.1.1.8 -r1.9 break; case IMSG_NETWORK_ADD: if (imsg.hdr.len - IMSG_HEADER_SIZE != -@@ -446,13 +422,13 @@ rde_dispatch_imsg_session(struct imsgbuf +@@ -446,13 +436,13 @@ rde_dispatch_imsg_session(struct imsgbuf break; } session_set = NULL; @@ -295,7 +339,7 @@ diff -u -p -r1.1.1.8 -r1.9 if (netconf_s.prefixlen > 128) goto badnet; network_add(&netconf_s, 0); -@@ -544,6 +520,11 @@ badnet: +@@ -544,6 +534,11 @@ badnet: imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_RIB_MEM, 0, imsg.hdr.pid, -1, &rdemem, sizeof(rdemem)); break; @@ -307,28 +351,153 @@ diff -u -p -r1.1.1.8 -r1.9 default: break; } -@@ -587,7 +568,7 @@ rde_dispatch_imsg_parent(struct imsgbuf - fatal(NULL); - memcpy(nconf, imsg.data, sizeof(struct bgpd_config)); - for (rid = 0; rid < rib_size; rid++) -- ribs[rid].state = RIB_DELETE; -+ ribs[rid].state = RECONF_DELETE; +@@ -554,14 +549,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 +574,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)); -@@ -615,9 +596,9 @@ rde_dispatch_imsg_parent(struct imsgbuf + TAILQ_INIT(&netconf_p.attrset); + parent_set = &netconf_p.attrset; +@@ -608,6 +598,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 +625,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); -+ rib_new(rn.name, rn.flags); - else +- 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 != -@@ -644,9 +625,17 @@ rde_dispatch_imsg_parent(struct imsgbuf +@@ -631,12 +658,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 +701,27 @@ rde_dispatch_imsg_parent(struct imsgbuf nconf->flags &= ~BGPD_FLAG_NO_EVALUATE; } memcpy(conf, nconf, sizeof(struct bgpd_config)); @@ -338,19 +507,60 @@ diff -u -p -r1.1.1.8 -r1.9 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; - prefix_network_clean(peerself, reloadtime, 0); ++ ++ /* 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 */ -@@ -668,17 +657,29 @@ rde_dispatch_imsg_parent(struct imsgbuf + LIST_FOREACH(peer, &peerlist, peer_l) { +@@ -655,30 +729,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) @@ -360,7 +570,7 @@ diff -u -p -r1.1.1.8 -r1.9 + rde_softreconfig_load, &ribs[rid], + AID_UNSPEC); + } - /* sync local-RIB first */ ++ /* sync local-RIBs first */ if (reconf_in) rib_dump(&ribs[0], rde_softreconfig_in, NULL, - AF_UNSPEC); @@ -377,10 +587,17 @@ diff -u -p -r1.1.1.8 -r1.9 - 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,10 +689,6 @@ rde_dispatch_imsg_parent(struct imsgbuf +@@ -688,16 +791,16 @@ rde_dispatch_imsg_parent(struct imsgbuf } free(rules_l); rules_l = newrules; @@ -388,10 +605,20 @@ diff -u -p -r1.1.1.8 -r1.9 - if (ribs[rid].state == RIB_DELETE) - rib_free(&ribs[rid]); - } ++ log_info("RDE reconfigured"); break; case IMSG_NEXTHOP_UPDATE: -@@ -744,6 +741,8 @@ rde_dispatch_imsg_parent(struct imsgbuf + 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"); +@@ -744,6 +847,8 @@ rde_dispatch_imsg_parent(struct imsgbuf int rde_update_dispatch(struct imsg *imsg) { @@ -400,7 +627,7 @@ diff -u -p -r1.1.1.8 -r1.9 struct rde_peer *peer; struct rde_aspath *asp = NULL; u_char *p, *mpp = NULL; -@@ -752,9 +751,7 @@ rde_update_dispatch(struct imsg *imsg) +@@ -752,9 +857,8 @@ rde_update_dispatch(struct imsg *imsg) u_int16_t withdrawn_len; u_int16_t attrpath_len; u_int16_t nlri_len; @@ -408,10 +635,11 @@ diff -u -p -r1.1.1.8 -r1.9 - 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,14 +807,7 @@ rde_update_dispatch(struct imsg *imsg) +@@ -810,26 +914,21 @@ rde_update_dispatch(struct imsg *imsg) goto done; } @@ -427,7 +655,28 @@ diff -u -p -r1.1.1.8 -r1.9 /* enforce remote AS if requested */ if (asp->flags & F_ATTR_ASPATH && -@@ -860,9 +850,9 @@ rde_update_dispatch(struct imsg *imsg) +- 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 +959,9 @@ rde_update_dispatch(struct imsg *imsg) p += pos; len -= pos; @@ -440,7 +689,7 @@ diff -u -p -r1.1.1.8 -r1.9 rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR, NULL, 0); goto done; -@@ -892,15 +882,25 @@ rde_update_dispatch(struct imsg *imsg) +@@ -892,15 +991,25 @@ rde_update_dispatch(struct imsg *imsg) afi = ntohs(afi); safi = *mpp++; mplen--; @@ -475,7 +724,7 @@ diff -u -p -r1.1.1.8 -r1.9 while (mplen > 0) { if ((pos = rde_update_get_prefix6(mpp, mplen, &prefix, &prefixlen)) == -1) { -@@ -926,6 +926,32 @@ rde_update_dispatch(struct imsg *imsg) +@@ -926,6 +1035,32 @@ rde_update_dispatch(struct imsg *imsg) rde_update_withdraw(peer, &prefix, prefixlen); } break; @@ -508,7 +757,7 @@ diff -u -p -r1.1.1.8 -r1.9 default: /* silently ignore unsupported multiprotocol AF */ break; -@@ -963,9 +989,9 @@ rde_update_dispatch(struct imsg *imsg) +@@ -963,9 +1098,9 @@ rde_update_dispatch(struct imsg *imsg) p += pos; nlri_len -= pos; @@ -521,7 +770,7 @@ diff -u -p -r1.1.1.8 -r1.9 rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR, NULL, 0); goto done; -@@ -995,6 +1021,22 @@ rde_update_dispatch(struct imsg *imsg) +@@ -995,6 +1130,22 @@ rde_update_dispatch(struct imsg *imsg) safi = *mpp++; mplen--; @@ -544,7 +793,7 @@ diff -u -p -r1.1.1.8 -r1.9 /* * this works because asp is not linked. * But first unlock the previously locked nexthop. -@@ -1004,8 +1046,8 @@ rde_update_dispatch(struct imsg *imsg) +@@ -1004,8 +1155,8 @@ rde_update_dispatch(struct imsg *imsg) (void)nexthop_delete(asp->nexthop); asp->nexthop = NULL; } @@ -555,7 +804,7 @@ diff -u -p -r1.1.1.8 -r1.9 rde_update_err(peer, ERR_UPDATE, ERR_UPD_OPTATTR, mpa.reach, mpa.reach_len); goto done; -@@ -1013,16 +1055,8 @@ rde_update_dispatch(struct imsg *imsg) +@@ -1013,16 +1164,8 @@ rde_update_dispatch(struct imsg *imsg) mpp += pos; mplen -= pos; @@ -574,7 +823,7 @@ diff -u -p -r1.1.1.8 -r1.9 while (mplen > 0) { if ((pos = rde_update_get_prefix6(mpp, mplen, &prefix, &prefixlen)) == -1) { -@@ -1058,6 +1092,42 @@ rde_update_dispatch(struct imsg *imsg) +@@ -1058,6 +1201,42 @@ rde_update_dispatch(struct imsg *imsg) } break; @@ -617,7 +866,7 @@ diff -u -p -r1.1.1.8 -r1.9 default: /* silently ignore unsupported multiprotocol AF */ break; -@@ -1085,7 +1155,8 @@ rde_update_update(struct rde_peer *peer, +@@ -1085,7 +1264,8 @@ rde_update_update(struct rde_peer *peer, struct bgpd_addr *prefix, u_int8_t prefixlen) { struct rde_aspath *fasp; @@ -627,7 +876,7 @@ diff -u -p -r1.1.1.8 -r1.9 u_int16_t i; peer->prefix_rcvd_update++; -@@ -1095,18 +1166,24 @@ rde_update_update(struct rde_peer *peer, +@@ -1095,18 +1275,24 @@ rde_update_update(struct rde_peer *peer, for (i = 1; i < rib_size; i++) { /* input filter */ @@ -659,7 +908,7 @@ diff -u -p -r1.1.1.8 -r1.9 /* free modified aspath */ if (fasp != asp) path_put(fasp); -@@ -1114,6 +1191,8 @@ done: +@@ -1114,6 +1300,8 @@ done: if (r) peer->prefix_cnt++; @@ -668,7 +917,42 @@ diff -u -p -r1.1.1.8 -r1.9 } void -@@ -1248,7 +1327,7 @@ bad_flags: +@@ -1161,6 +1349,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 +1384,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 +1410,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 +1448,7 @@ bad_flags: a->flags |= F_ATTR_NEXTHOP; bzero(&nexthop, sizeof(nexthop)); @@ -677,7 +961,7 @@ diff -u -p -r1.1.1.8 -r1.9 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: +@@ -1305,9 +1505,21 @@ bad_flags: goto optattr; case ATTR_AGGREGATOR: if ((!rde_as4byte(peer) && attr_len != 6) || @@ -692,6 +976,8 @@ diff -u -p -r1.1.1.8 -r1.9 + */ + if ((flags & ATTR_PARTIAL) == 0) + goto bad_len; ++ log_peer_warnx(&peer->conf, "bad AGGREGATOR, " ++ "partial attribute ignored"); + plen += attr_len; + break; + } @@ -700,13 +986,13 @@ diff -u -p -r1.1.1.8 -r1.9 goto bad_flags; if (!rde_as4byte(peer)) { /* need to inflate aggregator AS to 4-byte */ -@@ -1323,8 +1412,33 @@ bad_flags: +@@ -1323,8 +1535,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 & 0x3) != 0) { ++ if (attr_len % 4 != 0) { + /* + * mark update as bad and withdraw all routes as per + * draft-ietf-idr-optional-transitive-00.txt @@ -714,15 +1000,16 @@ diff -u -p -r1.1.1.8 -r1.9 + */ + if ((flags & ATTR_PARTIAL) == 0) + goto bad_len; -+ else -+ a->flags |= F_ATTR_PARSE_ERR; ++ 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 & 0x7) != 0) { ++ if (attr_len % 8 != 0) { + /* + * mark update as bad and withdraw all routes as per + * draft-ietf-idr-optional-transitive-00.txt @@ -730,13 +1017,23 @@ diff -u -p -r1.1.1.8 -r1.9 + */ + if ((flags & ATTR_PARTIAL) == 0) + goto bad_len; -+ else -+ a->flags |= F_ATTR_PARSE_ERR; ++ 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; -@@ -1370,8 +1484,14 @@ bad_flags: +@@ -1336,7 +1575,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 +1609,15 @@ bad_flags: plen += attr_len; break; case ATTR_AS4_AGGREGATOR: @@ -746,14 +1043,20 @@ diff -u -p -r1.1.1.8 -r1.9 + /* see ATTR_AGGREGATOR ... */ + if ((flags & ATTR_PARTIAL) == 0) + goto bad_len; -+ /* we should add a warning here */ ++ 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; -@@ -1385,13 +1505,21 @@ bad_flags: +@@ -1381,17 +1627,28 @@ 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 @@ -767,11 +1070,14 @@ diff -u -p -r1.1.1.8 -r1.9 + * 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; -+ if (flags & ATTR_PARTIAL) { ++ 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, @@ -781,7 +1087,7 @@ diff -u -p -r1.1.1.8 -r1.9 } a->flags |= F_ATTR_AS4BYTE_NEW; goto optattr; -@@ -1440,8 +1568,8 @@ rde_attr_missing(struct rde_aspath *a, i +@@ -1440,8 +1697,8 @@ rde_attr_missing(struct rde_aspath *a, i } int @@ -792,7 +1098,7 @@ diff -u -p -r1.1.1.8 -r1.9 { struct bgpd_addr nexthop; u_int8_t totlen, nhlen; -@@ -1457,8 +1585,9 @@ rde_get_mp_nexthop(u_char *data, u_int16 +@@ -1457,8 +1714,9 @@ rde_get_mp_nexthop(u_char *data, u_int16 return (-1); bzero(&nexthop, sizeof(nexthop)); @@ -804,7 +1110,7 @@ diff -u -p -r1.1.1.8 -r1.9 /* * 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 +@@ -1471,72 +1729,143 @@ rde_get_mp_nexthop(u_char *data, u_int16 log_warnx("bad multiprotocol nexthop, bad size"); return (-1); } @@ -831,7 +1137,7 @@ diff -u -p -r1.1.1.8 -r1.9 - * 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. ++ * 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 @@ -987,7 +1293,7 @@ diff -u -p -r1.1.1.8 -r1.9 if (len < 1) return (-1); -@@ -1546,18 +1746,43 @@ rde_update_get_prefix6(u_char *p, u_int1 +@@ -1546,25 +1875,50 @@ rde_update_get_prefix6(u_char *p, u_int1 plen = 1; bzero(prefix, sizeof(struct bgpd_addr)); @@ -1041,7 +1347,15 @@ diff -u -p -r1.1.1.8 -r1.9 } void -@@ -1616,6 +1841,14 @@ rde_as4byte_fixup(struct rde_peer *peer, + 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 +1970,30 @@ rde_as4byte_fixup(struct rde_peer *peer, struct attr *nasp, *naggr, *oaggr; u_int32_t as; @@ -1056,7 +1370,25 @@ diff -u -p -r1.1.1.8 -r1.9 /* first get the attributes */ 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 + + 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 +2037,10 @@ rde_reflector(struct rde_peer *peer, str u_int16_t len; u_int32_t id; @@ -1067,7 +1399,16 @@ diff -u -p -r1.1.1.8 -r1.9 /* 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) { -@@ -1748,8 +1985,8 @@ rde_dump_rib_as(struct prefix *p, struct +@@ -1724,7 +2096,7 @@ 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; + u_int8_t l; +@@ -1748,23 +2120,23 @@ 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)); @@ -1078,7 +1419,54 @@ diff -u -p -r1.1.1.8 -r1.9 } pt_getaddr(p->prefix, &rib.prefix); rib.prefixlen = p->prefix->prefixlen; -@@ -1836,7 +2073,7 @@ rde_dump_filter(struct prefix *p, struct + rib.origin = asp->origin; + rib.flags = 0; + if (p->rib->active == p) +- rib.flags |= F_RIB_ACTIVE; ++ rib.flags |= F_PREF_ACTIVE; + if (asp->peer->conf.ebgp == 0) +- rib.flags |= F_RIB_INTERNAL; ++ 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; + rib.aspath_len = aspath_length(asp->aspath); + + if ((wbuf = imsg_create(ibuf_se_ctl, IMSG_CTL_SHOW_RIB, 0, pid, +@@ -1784,13 +2156,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,15 +2200,15 @@ 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 && ++ 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 && @@ -1087,7 +1475,7 @@ diff -u -p -r1.1.1.8 -r1.9 req->community.type)) return; rde_dump_rib_as(p, p->aspath, req->pid, req->flags); -@@ -1872,7 +2109,7 @@ rde_dump_prefix_upcall(struct rib_entry +@@ -1872,7 +2244,7 @@ rde_dump_prefix_upcall(struct rib_entry pt = re->prefix; pt_getaddr(pt, &addr); @@ -1096,7 +1484,15 @@ diff -u -p -r1.1.1.8 -r1.9 return; if (ctx->req.prefixlen > pt->prefixlen) return; -@@ -1902,6 +2139,7 @@ rde_dump_ctx_new(struct ctl_show_rib_req +@@ -1889,6 +2261,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 +2275,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)); @@ -1104,7 +1500,27 @@ diff -u -p -r1.1.1.8 -r1.9 return; } -@@ -1937,7 +2175,7 @@ rde_dump_ctx_new(struct ctl_show_rib_req +@@ -1924,7 +2298,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 +2322,7 @@ rde_dump_ctx_new(struct ctl_show_rib_req } ctx->ribctx.ctx_done = rde_dump_done; ctx->ribctx.ctx_arg = ctx; @@ -1113,7 +1529,7 @@ diff -u -p -r1.1.1.8 -r1.9 rib_dump_r(&ctx->ribctx); } -@@ -1974,10 +2212,10 @@ rde_dump_mrt_new(struct mrt *mrt, pid_t +@@ -1974,10 +2359,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; @@ -1127,38 +1543,118 @@ diff -u -p -r1.1.1.8 -r1.9 rde_mrt_cnt++; rib_dump_r(&ctx->ribctx); } -@@ -2011,8 +2249,8 @@ rde_send_kroute(struct prefix *new, stru +@@ -1985,13 +2370,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 +2408,45 @@ 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_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"); ++ case AID_VPN_IPv4: ++ if (ribid != 1) ++ /* not Loc-RIB, no update for VPNs */ ++ break; ++ ++ SIMPLEQ_FOREACH(rd, rdomains_l, entry) { ++ if (addr.vpn4.rd != rd->rd) ++ continue; ++ 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: -+ 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) +- 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; -+ case AID_VPN_IPv4: -+ break; -+ default: -+ fatal("rde_send_kroute: unhandled AID"); } - } - -@@ -2098,7 +2340,6 @@ rde_send_pftable_commit(void) +@@ -2098,7 +2497,6 @@ rde_send_pftable_commit(void) void rde_send_nexthop(struct bgpd_addr *next, int valid) { @@ -1166,7 +1662,7 @@ diff -u -p -r1.1.1.8 -r1.9 int type; if (valid) -@@ -2106,8 +2347,6 @@ rde_send_nexthop(struct bgpd_addr *next, +@@ -2106,8 +2504,6 @@ rde_send_nexthop(struct bgpd_addr *next, else type = IMSG_NEXTHOP_REMOVE; @@ -1175,7 +1671,7 @@ diff -u -p -r1.1.1.8 -r1.9 if (imsg_compose(ibuf_main, type, 0, 0, -1, next, sizeof(struct bgpd_addr)) == -1) fatal("imsg_compose error"); -@@ -2201,6 +2440,10 @@ rde_softreconfig_in(struct rib_entry *re +@@ -2201,6 +2597,10 @@ rde_softreconfig_in(struct rib_entry *re continue; for (i = 1; i < rib_size; i++) { @@ -1186,7 +1682,7 @@ diff -u -p -r1.1.1.8 -r1.9 /* 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 +@@ -2228,7 +2628,7 @@ rde_softreconfig_in(struct rib_entry *re if (path_compare(nasp, oasp) == 0) goto done; /* send update */ @@ -1195,7 +1691,7 @@ diff -u -p -r1.1.1.8 -r1.9 pt->prefixlen); } -@@ -2241,6 +2484,40 @@ done: +@@ -2241,6 +2641,104 @@ done: } } @@ -1233,10 +1729,92 @@ diff -u -p -r1.1.1.8 -r1.9 + } +} + ++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 */ -@@ -2286,7 +2563,7 @@ void +@@ -2252,7 +2750,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 +2763,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 +2784,7 @@ void rde_update_queue_runner(void) { struct rde_peer *peer; @@ -1245,7 +1823,7 @@ diff -u -p -r1.1.1.8 -r1.9 u_int16_t len, wd_len, wpos; len = sizeof(queue_buf) - MSGSIZE_HEADER; -@@ -2300,7 +2577,7 @@ rde_update_queue_runner(void) +@@ -2300,7 +2798,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, @@ -1254,7 +1832,7 @@ diff -u -p -r1.1.1.8 -r1.9 wd_len = r; /* write withdraws length filed */ wd_len = htons(wd_len); -@@ -2310,31 +2587,49 @@ rde_update_queue_runner(void) +@@ -2310,31 +2808,49 @@ rde_update_queue_runner(void) /* now bgp path attributes */ r = up_dump_attrnlri(queue_buf + wpos, len - wpos, peer); @@ -1314,7 +1892,7 @@ diff -u -p -r1.1.1.8 -r1.9 u_int16_t len; /* first withdraws ... */ -@@ -2346,7 +2641,7 @@ rde_update6_queue_runner(void) +@@ -2346,7 +2862,7 @@ rde_update6_queue_runner(void) if (peer->state != PEER_UP) continue; len = sizeof(queue_buf) - MSGSIZE_HEADER; @@ -1323,7 +1901,7 @@ diff -u -p -r1.1.1.8 -r1.9 if (b == NULL) continue; -@@ -2369,10 +2664,18 @@ rde_update6_queue_runner(void) +@@ -2369,10 +2885,18 @@ rde_update6_queue_runner(void) if (peer->state != PEER_UP) continue; len = sizeof(queue_buf) - MSGSIZE_HEADER; @@ -1333,19 +1911,19 @@ diff -u -p -r1.1.1.8 -r1.9 + r = up_dump_mp_reach(queue_buf, &len, peer, aid); + switch (r) { + case -2: - continue; ++ continue; + case -1: + peer_send_eor(peer, aid); -+ continue; + 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) +@@ -2411,7 +2935,7 @@ rde_decisionflags(void) int rde_as4byte(struct rde_peer *peer) { @@ -1354,7 +1932,7 @@ diff -u -p -r1.1.1.8 -r1.9 } /* -@@ -2429,7 +2732,6 @@ void +@@ -2429,7 +2953,6 @@ void peer_init(u_int32_t hashsize) { struct peer_config pc; @@ -1362,7 +1940,7 @@ diff -u -p -r1.1.1.8 -r1.9 u_int32_t hs, i; for (hs = 1; hs < hashsize; hs <<= 1) -@@ -2445,17 +2747,13 @@ peer_init(u_int32_t hashsize) +@@ -2445,17 +2968,13 @@ peer_init(u_int32_t hashsize) peertable.peer_hashmask = hs - 1; bzero(&pc, sizeof(pc)); @@ -1381,7 +1959,7 @@ diff -u -p -r1.1.1.8 -r1.9 } void -@@ -2534,14 +2832,10 @@ peer_localaddrs(struct rde_peer *peer, s +@@ -2534,14 +3053,10 @@ peer_localaddrs(struct rde_peer *peer, s if (ifa->ifa_addr->sa_family == match->ifa_addr->sa_family) ifa = match; @@ -1397,7 +1975,7 @@ diff -u -p -r1.1.1.8 -r1.9 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 +@@ -2559,13 +3074,7 @@ peer_localaddrs(struct rde_peer *peer, s &((struct sockaddr_in6 *)ifa-> ifa_addr)->sin6_addr)) continue; @@ -1412,7 +1990,7 @@ diff -u -p -r1.1.1.8 -r1.9 break; } } -@@ -2577,6 +2865,7 @@ void +@@ -2577,6 +3086,7 @@ void peer_up(u_int32_t id, struct session_up *sup) { struct rde_peer *peer; @@ -1420,7 +1998,7 @@ diff -u -p -r1.1.1.8 -r1.9 peer = peer_get(id); if (peer == NULL) { -@@ -2590,10 +2879,7 @@ peer_up(u_int32_t id, struct session_up +@@ -2590,10 +3100,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)); @@ -1432,7 +2010,7 @@ diff -u -p -r1.1.1.8 -r1.9 peer_localaddrs(peer, &sup->local_addr); -@@ -2607,7 +2893,10 @@ peer_up(u_int32_t id, struct session_up +@@ -2607,7 +3114,10 @@ peer_up(u_int32_t id, struct session_up */ return; @@ -1444,7 +2022,7 @@ diff -u -p -r1.1.1.8 -r1.9 } void -@@ -2642,42 +2931,32 @@ peer_down(u_int32_t id) +@@ -2642,42 +3152,32 @@ peer_down(u_int32_t id) } void @@ -1501,7 +2079,7 @@ diff -u -p -r1.1.1.8 -r1.9 u_char null[4]; bzero(&null, 4); -@@ -2688,6 +2967,9 @@ peer_send_eor(struct rde_peer *peer, u_i +@@ -2688,6 +3188,9 @@ peer_send_eor(struct rde_peer *peer, u_i u_int16_t i; u_char buf[10]; @@ -1511,50 +2089,178 @@ diff -u -p -r1.1.1.8 -r1.9 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 +@@ -2709,25 +3212,43 @@ 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; + ++ 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; ++ } ++ } ++ } ++ + asp = path_get(); + asp->aspath = aspath_get(NULL, 0); + asp->origin = ORIGIN_IGP; +@@ -2737,7 +3258,9 @@ 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, 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); -@@ -2772,9 +3054,10 @@ network_dump_upcall(struct rib_entry *re +@@ -2749,12 +3272,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 +3316,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) { -+ pt_getaddr(p->prefix, &addr); -+ switch (addr.aid) { -+ case AID_INET: - bzero(&k, sizeof(k)); +- 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) -@@ -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"); +- 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) { -+ break; -+ case AID_INET6: - bzero(&k6, sizeof(k6)); +- 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) -@@ -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; - } +- 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 +3124,10 @@ sa_cmp(struct bgpd_addr *a, struct socka + +@@ -2841,10 +3386,10 @@ sa_cmp(struct bgpd_addr *a, struct socka struct sockaddr_in *in_b; struct sockaddr_in6 *in6_b; |