diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2010-05-03 13:09:39 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2010-05-03 13:09:39 +0000 |
commit | bb2e97a20c38b13f273faf0b79dff73651982b4d (patch) | |
tree | 2d2f533b8681f808a66efdb57f5974b0dbb4b0c9 /usr.sbin | |
parent | 3237932c136a2acb4eb09366a457cf3f67ca5e8e (diff) |
Make it possible to load multiple routing tables at the same time and use
those for alternate RIBs. This allows to use "rde rib TESTIT rtable 1".
NOTE: nexthop verification has changed for alternate tables. For now
nexthop will only be verified against the main routing table (id 0).
Because of this "nexthop qualify via bgp" may now compare the nexthops
against bgpd routes from a different RIB.
Tested by sthen@, OK to move on by henning@
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/bgpd/bgpd.c | 40 | ||||
-rw-r--r-- | usr.sbin/bgpd/bgpd.h | 64 | ||||
-rw-r--r-- | usr.sbin/bgpd/control.c | 19 | ||||
-rw-r--r-- | usr.sbin/bgpd/kroute.c | 796 | ||||
-rw-r--r-- | usr.sbin/bgpd/parse.y | 88 | ||||
-rw-r--r-- | usr.sbin/bgpd/printconf.c | 13 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde.c | 29 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde.h | 12 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde_decide.c | 4 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde_rib.c | 7 | ||||
-rw-r--r-- | usr.sbin/bgpd/session.c | 9 | ||||
-rw-r--r-- | usr.sbin/bgpd/session.h | 4 |
12 files changed, 741 insertions, 344 deletions
diff --git a/usr.sbin/bgpd/bgpd.c b/usr.sbin/bgpd/bgpd.c index 27523f4c257..2d34db752be 100644 --- a/usr.sbin/bgpd/bgpd.c +++ b/usr.sbin/bgpd/bgpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.c,v 1.160 2010/04/26 12:25:06 claudio Exp $ */ +/* $OpenBSD: bgpd.c,v 1.161 2010/05/03 13:09:38 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -244,10 +244,9 @@ main(int argc, char *argv[]) imsg_init(ibuf_se, pipe_m2s[0]); imsg_init(ibuf_rde, pipe_m2r[0]); mrt_init(ibuf_rde, ibuf_se); - quit = reconfigure(conffile, &conf, &mrt_l, &peer_l); - if ((rfd = kr_init(!(conf.flags & BGPD_FLAG_NO_FIB_UPDATE), - conf.rtableid)) == -1) + if ((rfd = kr_init()) == -1) quit = 1; + quit = reconfigure(conffile, &conf, &mrt_l, &peer_l); if (pftable_clear_all() != 0) quit = 1; @@ -467,9 +466,17 @@ reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_head *mrt_l, la->fd = -1; } + /* adjust fib syncing on reload */ + ktable_preload(); + /* RIBs for the RDE */ while ((rr = SIMPLEQ_FIRST(&ribnames))) { SIMPLEQ_REMOVE_HEAD(&ribnames, entry); + if (ktable_update(rr) == -1) { + log_warnx("failed to load rdomain %d", + rr->rtableid); + return (-1); + } if (imsg_compose(ibuf_rde, IMSG_RECONF_RIB, 0, 0, -1, rr, sizeof(struct rde_rib)) == -1) return (-1); @@ -491,10 +498,6 @@ reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_head *mrt_l, free(n); } - /* redistribute list needs to be reloaded too */ - if (kr_reload() == -1) - return (-1); - /* filters for the RDE */ while ((r = TAILQ_FIRST(&rules_l)) != NULL) { if (imsg_compose(ibuf_rde, IMSG_RECONF_FILTER, 0, 0, -1, @@ -512,6 +515,13 @@ reconfigure(char *conffile, struct bgpd_config *conf, struct mrt_head *mrt_l, imsg_compose(ibuf_rde, IMSG_RECONF_DONE, 0, 0, -1, NULL, 0) == -1) return (-1); + /* fix kroute information */ + ktable_postload(); + + /* redistribute list needs to be reloaded too */ + if (kr_reload() == -1) + return (-1); + /* mrt changes can be sent out of bound */ mrt_reconfigure(mrt_l); return (0); @@ -547,7 +557,7 @@ dispatch_imsg(struct imsgbuf *ibuf, int idx) else if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(struct kroute_full)) log_warnx("wrong imsg len"); - else if (kr_change(imsg.data)) + else if (kr_change(imsg.hdr.peerid, imsg.data)) rv = -1; break; case IMSG_KROUTE_DELETE: @@ -556,7 +566,7 @@ dispatch_imsg(struct imsgbuf *ibuf, int idx) else if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(struct kroute_full)) log_warnx("wrong imsg len"); - else if (kr_delete(imsg.data)) + else if (kr_delete(imsg.hdr.peerid, imsg.data)) rv = -1; break; case IMSG_NEXTHOP_ADD: @@ -565,7 +575,8 @@ dispatch_imsg(struct imsgbuf *ibuf, int idx) else if (imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(struct bgpd_addr)) log_warnx("wrong imsg len"); - else if (kr_nexthop_add(imsg.data) == -1) + else if (kr_nexthop_add(imsg.hdr.peerid, imsg.data) == + -1) rv = -1; break; case IMSG_NEXTHOP_REMOVE: @@ -575,7 +586,7 @@ dispatch_imsg(struct imsgbuf *ibuf, int idx) sizeof(struct bgpd_addr)) log_warnx("wrong imsg len"); else - kr_nexthop_delete(imsg.data); + kr_nexthop_delete(imsg.hdr.peerid, imsg.data); break; case IMSG_PFTABLE_ADD: if (idx != PFD_PIPE_ROUTE) @@ -617,18 +628,19 @@ dispatch_imsg(struct imsgbuf *ibuf, int idx) if (idx != PFD_PIPE_SESSION) log_warnx("couple request not from SE"); else - kr_fib_couple(); + kr_fib_couple(imsg.hdr.peerid); break; case IMSG_CTL_FIB_DECOUPLE: if (idx != PFD_PIPE_SESSION) log_warnx("decouple request not from SE"); else - kr_fib_decouple(); + kr_fib_decouple(imsg.hdr.peerid); break; case IMSG_CTL_KROUTE: case IMSG_CTL_KROUTE_ADDR: case IMSG_CTL_SHOW_NEXTHOP: case IMSG_CTL_SHOW_INTERFACE: + case IMSG_CTL_SHOW_FIB_TABLES: if (idx != PFD_PIPE_SESSION) log_warnx("kroute request not from SE"); else diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h index 6c6d87e3c28..9511e96d2f0 100644 --- a/usr.sbin/bgpd/bgpd.h +++ b/usr.sbin/bgpd/bgpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.h,v 1.257 2010/04/28 13:07:48 claudio Exp $ */ +/* $OpenBSD: bgpd.h,v 1.258 2010/05/03 13:09:38 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -53,7 +53,6 @@ #define BGPD_OPT_NOACTION 0x0004 #define BGPD_OPT_FORCE_DEMOTE 0x0008 -#define BGPD_FLAG_NO_FIB_UPDATE 0x0001 #define BGPD_FLAG_NO_EVALUATE 0x0002 #define BGPD_FLAG_REFLECTOR 0x0004 #define BGPD_FLAG_REDIST_STATIC 0x0008 @@ -344,6 +343,7 @@ enum imsg_type { IMSG_CTL_SHOW_TERSE, IMSG_CTL_SHOW_TIMER, IMSG_CTL_LOG_VERBOSE, + IMSG_CTL_SHOW_FIB_TABLES, IMSG_NETWORK_ADD, IMSG_NETWORK_REMOVE, IMSG_NETWORK_FLUSH, @@ -429,6 +429,31 @@ enum suberr_cease { ERR_CEASE_RSRC_EXHAUST }; +struct kroute_node; +struct kroute6_node; +struct knexthop_node; +struct redist_node; +RB_HEAD(kroute_tree, kroute_node); +RB_HEAD(kroute6_tree, kroute6_node); +RB_HEAD(knexthop_tree, knexthop_node); + +struct ktable { + char descr[PEER_DESCR_LEN]; + char ifmpe[IFNAMSIZ]; + struct kroute_tree krt; + struct kroute6_tree krt6; + struct knexthop_tree knt; + struct network_head krn; + LIST_HEAD(, redist_node) redistlist; + u_int rtableid; + u_int nhtableid; /* rdomain id for nexthop lookup */ + u_int ifindex; /* ifindex of ifmpe */ + int nhrefcnt; /* refcnt for nexthop table */ + enum reconf_action state; + u_int8_t fib_conf; /* configured FIB sync flag */ + u_int8_t fib_sync; /* is FIB synced with kernel? */ +}; + struct kroute_full { struct bgpd_addr prefix; struct bgpd_addr nexthop; @@ -509,10 +534,10 @@ struct ctl_neighbor { int show_timers; }; -#define F_RIB_ELIGIBLE 0x01 -#define F_RIB_ACTIVE 0x02 -#define F_RIB_INTERNAL 0x04 -#define F_RIB_ANNOUNCE 0x08 +#define F_PREF_ELIGIBLE 0x01 +#define F_PREF_ACTIVE 0x02 +#define F_PREF_INTERNAL 0x04 +#define F_PREF_ANNOUNCE 0x08 struct ctl_show_rib { struct bgpd_addr true_nexthop; @@ -764,12 +789,20 @@ struct filter_set { struct rde_rib { SIMPLEQ_ENTRY(rde_rib) entry; char name[PEER_DESCR_LEN]; + u_int rtableid; u_int16_t id; u_int16_t flags; }; SIMPLEQ_HEAD(rib_names, rde_rib); extern struct rib_names ribnames; +/* rde_rib flags */ +#define F_RIB_ENTRYLOCK 0x0001 +#define F_RIB_NOEVALUATE 0x0002 +#define F_RIB_NOFIB 0x0004 +#define F_RIB_NOFIBSYNC 0x0008 +#define F_RIB_HASNOFIB (F_RIB_NOFIB | F_RIB_NOEVALUATE) + /* 4-byte magic AS number */ #define AS_TRANS 23456 @@ -815,17 +848,22 @@ int cmdline_symset(char *); int host(const char *, struct bgpd_addr *, u_int8_t *); /* kroute.c */ -int kr_init(int, u_int); -int kr_change(struct kroute_full *); -int kr_delete(struct kroute_full *); +int kr_init(void); +int ktable_update(struct rde_rib *); +void ktable_preload(void); +void ktable_postload(void); +int ktable_exists(u_int, u_int *); +int kr_change(u_int, struct kroute_full *); +int kr_delete(u_int, struct kroute_full *); void kr_shutdown(void); -void kr_fib_couple(void); -void kr_fib_decouple(void); +void kr_fib_couple(u_int); +void kr_fib_decouple(u_int); int kr_dispatch_msg(void); -int kr_nexthop_add(struct bgpd_addr *); -void kr_nexthop_delete(struct bgpd_addr *); +int kr_nexthop_add(u_int32_t, struct bgpd_addr *); +void kr_nexthop_delete(u_int32_t, struct bgpd_addr *); void kr_show_route(struct imsg *); void kr_ifinfo(char *); +int kr_net_reload(u_int, struct network_head *); int kr_reload(void); struct in6_addr *prefixlen2mask6(u_int8_t prefixlen); diff --git a/usr.sbin/bgpd/control.c b/usr.sbin/bgpd/control.c index a7430a63885..cea65717937 100644 --- a/usr.sbin/bgpd/control.c +++ b/usr.sbin/bgpd/control.c @@ -1,4 +1,4 @@ -/* $OpenBSD: control.c,v 1.68 2010/01/13 06:02:37 claudio Exp $ */ +/* $OpenBSD: control.c,v 1.69 2010/05/03 13:09:38 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -306,7 +306,8 @@ control_dispatch_msg(struct pollfd *pfd, u_int *ctl_cnt) break; case IMSG_CTL_FIB_COUPLE: case IMSG_CTL_FIB_DECOUPLE: - imsg_compose_parent(imsg.hdr.type, 0, NULL, 0); + imsg_compose_parent(imsg.hdr.type, imsg.hdr.peerid, + 0, NULL, 0); break; case IMSG_CTL_NEIGHBOR_UP: case IMSG_CTL_NEIGHBOR_DOWN: @@ -359,13 +360,19 @@ control_dispatch_msg(struct pollfd *pfd, u_int *ctl_cnt) "wrong length"); break; case IMSG_CTL_RELOAD: + case IMSG_CTL_SHOW_INTERFACE: + case IMSG_CTL_SHOW_FIB_TABLES: + c->ibuf.pid = imsg.hdr.pid; + imsg_compose_parent(imsg.hdr.type, 0, imsg.hdr.pid, + imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); + break; case IMSG_CTL_KROUTE: case IMSG_CTL_KROUTE_ADDR: case IMSG_CTL_SHOW_NEXTHOP: - case IMSG_CTL_SHOW_INTERFACE: c->ibuf.pid = imsg.hdr.pid; - imsg_compose_parent(imsg.hdr.type, imsg.hdr.pid, - imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); + imsg_compose_parent(imsg.hdr.type, imsg.hdr.peerid, + imsg.hdr.pid, imsg.data, imsg.hdr.len - + IMSG_HEADER_SIZE); break; case IMSG_CTL_SHOW_RIB: case IMSG_CTL_SHOW_RIB_AS: @@ -437,7 +444,7 @@ control_dispatch_msg(struct pollfd *pfd, u_int *ctl_cnt) break; /* forward to other processes */ - imsg_compose_parent(imsg.hdr.type, imsg.hdr.pid, + imsg_compose_parent(imsg.hdr.type, 0, imsg.hdr.pid, imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); imsg_compose_rde(imsg.hdr.type, 0, imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE); diff --git a/usr.sbin/bgpd/kroute.c b/usr.sbin/bgpd/kroute.c index c2ec3c3847f..fd7984fd23b 100644 --- a/usr.sbin/bgpd/kroute.c +++ b/usr.sbin/bgpd/kroute.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kroute.c,v 1.177 2010/04/13 09:09:48 claudio Exp $ */ +/* $OpenBSD: kroute.c,v 1.178 2010/05/03 13:09:38 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -37,11 +37,12 @@ #include "bgpd.h" +struct ktable **krt; +u_int krt_size; + struct { u_int32_t rtseq; pid_t pid; - u_int rtableid; - int fib_sync; int fd; } kr_state; @@ -83,12 +84,21 @@ struct kif_node { struct kif_kr6_head kroute6_l; }; -int kr4_change(struct kroute_full *); -int kr6_change(struct kroute_full *); -int kr4_delete(struct kroute_full *); -int kr6_delete(struct kroute_full *); -int kr_redistribute(int, struct kroute *); -int kr_redistribute6(int, struct kroute6 *); +int ktable_new(u_int, u_int, char *, char *, int); +void ktable_free(u_int); +void ktable_destroy(struct ktable *); +struct ktable *ktable_get(u_int); + +int kr4_change(struct ktable *, struct kroute_full *); +int kr6_change(struct ktable *, struct kroute_full *); +int kr4_delete(struct ktable *, struct kroute_full *); +int kr6_delete(struct ktable *, struct kroute_full *); +void kr_net_delete(struct network *); +struct network *kr_net_match(struct ktable *, struct kroute *); +struct network *kr_net_match6(struct ktable *, struct kroute6 *); +struct network *kr_net_find(struct ktable *, struct network *); +int kr_redistribute(int, struct ktable *, struct kroute *); +int kr_redistribute6(int, struct ktable *, struct kroute6 *); struct kroute_full *kr_tofull(struct kroute *); struct kroute_full *kr6_tofull(struct kroute6 *); int kroute_compare(struct kroute_node *, struct kroute_node *); @@ -96,25 +106,28 @@ int kroute6_compare(struct kroute6_node *, struct kroute6_node *); int knexthop_compare(struct knexthop_node *, struct knexthop_node *); int kif_compare(struct kif_node *, struct kif_node *); -struct kroute_node *kroute_find(in_addr_t, u_int8_t, u_int8_t); +struct kroute_node *kroute_find(struct ktable *, in_addr_t, u_int8_t, + u_int8_t); struct kroute_node *kroute_matchgw(struct kroute_node *, struct sockaddr_in *); -int kroute_insert(struct kroute_node *); -int kroute_remove(struct kroute_node *); -void kroute_clear(void); +int kroute_insert(struct ktable *, struct kroute_node *); +int kroute_remove(struct ktable *, struct kroute_node *); +void kroute_clear(struct ktable *); -struct kroute6_node *kroute6_find(const struct in6_addr *, u_int8_t, - u_int8_t); +struct kroute6_node *kroute6_find(struct ktable *, const struct in6_addr *, + u_int8_t, u_int8_t); struct kroute6_node *kroute6_matchgw(struct kroute6_node *, struct sockaddr_in6 *); -int kroute6_insert(struct kroute6_node *); -int kroute6_remove(struct kroute6_node *); -void kroute6_clear(void); +int kroute6_insert(struct ktable *, struct kroute6_node *); +int kroute6_remove(struct ktable *, struct kroute6_node *); +void kroute6_clear(struct ktable *); -struct knexthop_node *knexthop_find(struct bgpd_addr *); -int knexthop_insert(struct knexthop_node *); -int knexthop_remove(struct knexthop_node *); -void knexthop_clear(void); +struct knexthop_node *knexthop_find(struct ktable *, struct bgpd_addr *); +int knexthop_insert(struct ktable *, + struct knexthop_node *); +int knexthop_remove(struct ktable *, + struct knexthop_node *); +void knexthop_clear(struct ktable *); struct kif_node *kif_find(int); int kif_insert(struct kif_node *); @@ -130,13 +143,15 @@ int kif_kr6_remove(struct kroute6_node *); int kif_validate(struct kif *); int kroute_validate(struct kroute *); int kroute6_validate(struct kroute6 *); -void knexthop_validate(struct knexthop_node *); -void knexthop_track(void *); -struct kroute_node *kroute_match(in_addr_t, int); -struct kroute6_node *kroute6_match(struct in6_addr *, int); -void kroute_detach_nexthop(struct knexthop_node *); - -int protect_lo(void); +void knexthop_validate(struct ktable *, + struct knexthop_node *); +void knexthop_track(struct ktable *, void *); +struct kroute_node *kroute_match(struct ktable *, in_addr_t, int); +struct kroute6_node *kroute6_match(struct ktable *, struct in6_addr *, int); +void kroute_detach_nexthop(struct ktable *, + struct knexthop_node *); + +int protect_lo(struct ktable *); u_int8_t prefixlen_classful(in_addr_t); u_int8_t mask2prefixlen(in_addr_t); u_int8_t mask2prefixlen6(struct sockaddr_in6 *); @@ -144,23 +159,20 @@ void get_rtaddrs(int, struct sockaddr *, struct sockaddr **); void if_change(u_short, int, struct if_data *); void if_announce(void *); -int send_rtmsg(int, int, struct kroute *); -int send_rt6msg(int, int, struct kroute6 *); +int send_rtmsg(int, int, struct ktable *, struct kroute *); +int send_rt6msg(int, int, struct ktable *, struct kroute6 *); int dispatch_rtmsg(void); -int fetchtable(u_int, int); +int fetchtable(struct ktable *); int fetchifs(int); int dispatch_rtmsg_addr(struct rt_msghdr *, - struct sockaddr *[RTAX_MAX], int); + struct sockaddr *[RTAX_MAX], struct ktable *); -RB_HEAD(kroute_tree, kroute_node) krt; RB_PROTOTYPE(kroute_tree, kroute_node, entry, kroute_compare) RB_GENERATE(kroute_tree, kroute_node, entry, kroute_compare) -RB_HEAD(kroute6_tree, kroute6_node) krt6; RB_PROTOTYPE(kroute6_tree, kroute6_node, entry, kroute6_compare) RB_GENERATE(kroute6_tree, kroute6_node, entry, kroute6_compare) -RB_HEAD(knexthop_tree, knexthop_node) knt; RB_PROTOTYPE(knexthop_tree, knexthop_node, entry, knexthop_compare) RB_GENERATE(knexthop_tree, knexthop_node, entry, knexthop_compare) @@ -168,19 +180,18 @@ RB_HEAD(kif_tree, kif_node) kit; RB_PROTOTYPE(kif_tree, kif_node, entry, kif_compare) RB_GENERATE(kif_tree, kif_node, entry, kif_compare) +#define KT2KNT(x) (&(ktable_get((x)->nhtableid)->knt)) + /* * exported functions */ int -kr_init(int fs, u_int rtableid) +kr_init(void) { int opt = 0, rcvbuf, default_rcvbuf; socklen_t optlen; - kr_state.rtableid = rtableid; - kr_state.fib_sync = fs; - if ((kr_state.fd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1) { log_warn("kr_init: socket"); return (-1); @@ -207,47 +218,253 @@ kr_init(int fs, u_int rtableid) kr_state.pid = getpid(); kr_state.rtseq = 1; - RB_INIT(&krt); - RB_INIT(&krt6); - RB_INIT(&knt); RB_INIT(&kit); if (fetchifs(0) == -1) return (-1); - if (fetchtable(kr_state.rtableid, 0) == -1) - return (-1); - if (kr_state.rtableid != 0) - if (fetchtable(0, 1) == -1) + return (kr_state.fd); +} + +int +ktable_new(u_int rtableid, u_int rdomid, char *name, char *ifname, int fs) +{ + struct ktable **xkrt; + struct ktable *kt; + size_t newsize, oldsize; + + /* resize index table if needed */ + if (rtableid >= krt_size) { + oldsize = sizeof(struct ktable *) * krt_size; + newsize = sizeof(struct ktable *) * (rtableid + 1); + if ((xkrt = realloc(krt, newsize)) == NULL) { + log_warn("ktable_new"); return (-1); + } + krt = xkrt; + krt_size = rtableid + 1; + bzero((char *)krt + oldsize, newsize - oldsize); + } + + if (krt[rtableid]) + fatalx("ktable_new: table already exists."); - if (protect_lo() == -1) + /* allocate new element */ + kt = krt[rtableid] = calloc(1, sizeof(struct ktable)); + if (kt == NULL) { + log_warn("ktable_new"); return (-1); + } - return (kr_state.fd); + /* initialize structure ... */ + strlcpy(kt->descr, name, sizeof(kt->descr)); + RB_INIT(&kt->krt); + RB_INIT(&kt->krt6); + RB_INIT(&kt->knt); + TAILQ_INIT(&kt->krn); + LIST_INIT(&kt->redistlist); + kt->fib_conf = kt->fib_sync = fs; + kt->rtableid = rtableid; + kt->nhtableid = rdomid; + /* bump refcount of rdomain table for the nexthop lookups */ + ktable_get(kt->nhtableid)->nhrefcnt++; + if (ifname) { + strlcpy(kt->ifmpe, ifname, IFNAMSIZ); + kt->ifindex = if_nametoindex(ifname); + } + kt->state = RECONF_REINIT; + + /* ... and load it */ + if (fetchtable(kt) == -1) + return (-1); + if (protect_lo(kt) == -1) + return (-1); + + /* everything is up and running */ + log_debug("new ktable %s for rtableid %d", name, rtableid); + kt->state = RECONF_KEEP; + return (0); +} + +void +ktable_free(u_int rtableid) +{ + struct ktable *kt, *nkt; + + if ((kt = ktable_get(rtableid)) == NULL) + return; + + /* decouple from kernel, no new routes will be entered from here */ + kr_fib_decouple(kt->rtableid); + + /* first unhook from the nexthop table */ + nkt = ktable_get(kt->nhtableid); + nkt->nhrefcnt--; + + /* + * Evil little details: + * If kt->nhrefcnt > 0 then kt == nkt and nothing needs to be done. + * If kt != nkt then kt->nhrefcnt must be 0 and kt must be killed. + * If nkt is no longer referenced it must be killed (possible double + * free so check that kt != nkt). + */ + if (kt != nkt && nkt->nhrefcnt <= 0) + ktable_destroy(nkt); + if (kt->nhrefcnt <= 0) + ktable_destroy(kt); +} + +void +ktable_destroy(struct ktable *kt) +{ + /* decouple just to be sure, does not hurt */ + kr_fib_decouple(kt->rtableid); + + log_debug("freeing ktable %s rtableid %u", kt->descr, kt->rtableid); + knexthop_clear(kt); + kroute_clear(kt); + kroute6_clear(kt); + + krt[kt->rtableid] = NULL; + free(kt); +} + +struct ktable * +ktable_get(u_int rtableid) +{ + if (rtableid >= krt_size) + return (NULL); + return (krt[rtableid]); +} + +int +ktable_update(struct rde_rib *rr) +{ + struct ktable *kt, *rkt; + u_int rdomid; + + if (!ktable_exists(rr->rtableid, &rdomid)) + fatalx("King Bula lost a table"); /* may not happen */ + + if (rdomid != rr->rtableid || rr->flags & F_RIB_NOFIB) { + rkt = ktable_get(rdomid); + if (rkt == NULL) { + char buf[32]; + snprintf(buf, sizeof(buf), "rdomain_%d", rdomid); + if (ktable_new(rdomid, rdomid, buf, NULL, 0)) + return (-1); + } else { + /* there is no need for full fib synchronisation if + * the table is only used for nexthop lookups. + */ + if (rkt->state == RECONF_DELETE) + rkt->fib_conf = 0; + rkt->state = RECONF_KEEP; + } + } + + if (rr->flags & (F_RIB_NOEVALUATE | F_RIB_NOFIB)) + /* only rdomain table must exist */ + return (0); + + kt = ktable_get(rr->rtableid); + if (kt == NULL) { + if (ktable_new(rr->rtableid, rdomid, rr->name, NULL, + !(rr->flags & F_RIB_NOFIBSYNC))) + return (-1); + } else { + /* fib sync has higher preference then no sync */ + if (kt->state == RECONF_DELETE) + kt->fib_conf = !(rr->flags & F_RIB_NOFIBSYNC); + else if (!kt->fib_conf) + kt->fib_conf = !(rr->flags & F_RIB_NOFIBSYNC); + + kt->state = RECONF_KEEP; + } + return (0); +} + +void +ktable_preload(void) +{ + struct ktable *kt; + u_int i; + + for (i = 0; i < krt_size; i++) { + if ((kt = ktable_get(i)) == NULL) + continue; + kt->state = RECONF_DELETE; + } +} + +void +ktable_postload(void) +{ + struct ktable *kt; + u_int i; + + for (i = krt_size; i > 0; i--) { + if ((kt = ktable_get(i - 1)) == NULL) + continue; + if (kt->state == RECONF_DELETE) + ktable_free(i - 1); + } +} + +int +ktable_exists(u_int rtableid, u_int *rdomid) +{ + size_t len; + struct rt_tableinfo info; + int mib[7]; + + mib[0] = CTL_NET; + mib[1] = AF_ROUTE; + mib[2] = 0; + mib[3] = 0; + mib[4] = NET_RT_TABLE; + mib[5] = rtableid; + + len = sizeof(info); + if (sysctl(mib, 6, &info, &len, NULL, 0) == -1) { + if (errno == ENOENT) + /* table nonexistent */ + return (0); + log_warn("sysctl"); + /* must return 0 so that the table is considered non-existent */ + return (0); + } + if (rdomid) + *rdomid = info.rti_domainid; + return (1); } int -kr_change(struct kroute_full *kl) +kr_change(u_int rtableid, struct kroute_full *kl) { + struct ktable *kt; + + if ((kt = ktable_get(rtableid)) == NULL) + /* too noisy during reloads, just ignore */ + return (0); switch (kl->prefix.aid) { case AID_INET: - return (kr4_change(kl)); + return (kr4_change(kt, kl)); case AID_INET6: - return (kr6_change(kl)); + return (kr6_change(kt, kl)); } log_warnx("kr_change: not handled AID"); return (-1); } int -kr4_change(struct kroute_full *kl) +kr4_change(struct ktable *kt, struct kroute_full *kl) { struct kroute_node *kr; int action = RTM_ADD; u_int16_t labelid; - if ((kr = kroute_find(kl->prefix.v4.s_addr, kl->prefixlen, + if ((kr = kroute_find(kt, kl->prefix.v4.s_addr, kl->prefixlen, RTP_BGP)) != NULL) action = RTM_CHANGE; @@ -274,7 +491,7 @@ kr4_change(struct kroute_full *kl) kr->r.priority = RTP_BGP; kr->r.labelid = labelid; - if (kroute_insert(kr) == -1) + if (kroute_insert(kt, kr) == -1) free(kr); } else { kr->r.nexthop.s_addr = kl->nexthop.v4.s_addr; @@ -290,21 +507,21 @@ kr4_change(struct kroute_full *kl) kr->r.flags &= ~F_REJECT; } - if (send_rtmsg(kr_state.fd, action, &kr->r) == -1) + if (send_rtmsg(kr_state.fd, action, kt, &kr->r) == -1) return (-1); return (0); } int -kr6_change(struct kroute_full *kl) +kr6_change(struct ktable *kt, struct kroute_full *kl) { struct kroute6_node *kr6; struct in6_addr lo6 = IN6ADDR_LOOPBACK_INIT; int action = RTM_ADD; u_int16_t labelid; - if ((kr6 = kroute6_find(&kl->prefix.v6, kl->prefixlen, RTP_BGP)) != + if ((kr6 = kroute6_find(kt, &kl->prefix.v6, kl->prefixlen, RTP_BGP)) != NULL) action = RTM_CHANGE; @@ -331,7 +548,7 @@ kr6_change(struct kroute_full *kl) kr6->r.priority = RTP_BGP; kr6->r.labelid = labelid; - if (kroute6_insert(kr6) == -1) + if (kroute6_insert(kt, kr6) == -1) free(kr6); } else { memcpy(&kr6->r.nexthop, &kl->nexthop.v6, @@ -348,66 +565,72 @@ kr6_change(struct kroute_full *kl) kr6->r.flags &= ~F_REJECT; } - if (send_rt6msg(kr_state.fd, action, &kr6->r) == -1) + if (send_rt6msg(kr_state.fd, action, kt, &kr6->r) == -1) return (-1); return (0); } int -kr_delete(struct kroute_full *kl) +kr_delete(u_int rtableid, struct kroute_full *kl) { + struct ktable *kt; + + if ((kt = ktable_get(rtableid)) == NULL) + /* too noisy during reloads, just ignore */ + return (0); + switch (kl->prefix.aid) { case AID_INET: - return (kr4_delete(kl)); + return (kr4_delete(kt, kl)); case AID_INET6: - return (kr6_delete(kl)); + return (kr6_delete(kt, kl)); } log_warnx("kr_change: not handled AID"); return (-1); } int -kr4_delete(struct kroute_full *kl) +kr4_delete(struct ktable *kt, struct kroute_full *kl) { struct kroute_node *kr; - if ((kr = kroute_find(kl->prefix.v4.s_addr, kl->prefixlen, + if ((kr = kroute_find(kt, kl->prefix.v4.s_addr, kl->prefixlen, RTP_BGP)) == NULL) return (0); if (!(kr->r.flags & F_BGPD_INSERTED)) return (0); - if (send_rtmsg(kr_state.fd, RTM_DELETE, &kr->r) == -1) + if (send_rtmsg(kr_state.fd, RTM_DELETE, kt, &kr->r) == -1) return (-1); rtlabel_unref(kr->r.labelid); - if (kroute_remove(kr) == -1) + if (kroute_remove(kt, kr) == -1) return (-1); return (0); } int -kr6_delete(struct kroute_full *kl) +kr6_delete(struct ktable *kt, struct kroute_full *kl) { struct kroute6_node *kr6; - if ((kr6 = kroute6_find(&kl->prefix.v6, kl->prefixlen, RTP_BGP)) == + if ((kr6 = kroute6_find(kt, &kl->prefix.v6, kl->prefixlen, RTP_BGP)) == NULL) return (0); if (!(kr6->r.flags & F_BGPD_INSERTED)) return (0); - if (send_rt6msg(kr_state.fd, RTM_DELETE, &kr6->r) == -1) + if (send_rt6msg(kr_state.fd, RTM_DELETE, kt, &kr6->r) == -1) return (-1); rtlabel_unref(kr6->r.labelid); - if (kroute6_remove(kr6) == -1) + if (kroute6_remove(kt, kr6) == -1) return (-1); return (0); @@ -416,53 +639,63 @@ kr6_delete(struct kroute_full *kl) void kr_shutdown(void) { - kr_fib_decouple(); - knexthop_clear(); - kroute_clear(); - kroute6_clear(); + u_int i; + + for (i = krt_size; i > 0; i--) + ktable_free(i - 1); kif_clear(); } void -kr_fib_couple(void) +kr_fib_couple(u_int rtableid) { + struct ktable *kt; struct kroute_node *kr; struct kroute6_node *kr6; - if (kr_state.fib_sync == 1) /* already coupled */ + if ((kt = ktable_get(rtableid)) == NULL) /* table does not exist */ return; - kr_state.fib_sync = 1; + if (kt->fib_sync) /* already coupled */ + return; - RB_FOREACH(kr, kroute_tree, &krt) + kt->fib_sync = 1; + + RB_FOREACH(kr, kroute_tree, &kt->krt) if ((kr->r.flags & F_BGPD_INSERTED)) - send_rtmsg(kr_state.fd, RTM_ADD, &kr->r); - RB_FOREACH(kr6, kroute6_tree, &krt6) + send_rtmsg(kr_state.fd, RTM_ADD, kt, &kr->r); + RB_FOREACH(kr6, kroute6_tree, &kt->krt6) if ((kr6->r.flags & F_BGPD_INSERTED)) - send_rt6msg(kr_state.fd, RTM_ADD, &kr6->r); + send_rt6msg(kr_state.fd, RTM_ADD, kt, &kr6->r); - log_info("kernel routing table coupled"); + log_info("kernel routing table %u (%s) coupled", kt->rtableid, + kt->descr); } void -kr_fib_decouple(void) +kr_fib_decouple(u_int rtableid) { + struct ktable *kt; struct kroute_node *kr; struct kroute6_node *kr6; - if (kr_state.fib_sync == 0) /* already decoupled */ + if ((kt = ktable_get(rtableid)) == NULL) /* table does not exist */ return; - RB_FOREACH(kr, kroute_tree, &krt) + if (!kt->fib_sync) /* already decoupled */ + return; + + RB_FOREACH(kr, kroute_tree, &kt->krt) if ((kr->r.flags & F_BGPD_INSERTED)) - send_rtmsg(kr_state.fd, RTM_DELETE, &kr->r); - RB_FOREACH(kr6, kroute6_tree, &krt6) + send_rtmsg(kr_state.fd, RTM_DELETE, kt, &kr->r); + RB_FOREACH(kr6, kroute6_tree, &kt->krt6) if ((kr6->r.flags & F_BGPD_INSERTED)) - send_rt6msg(kr_state.fd, RTM_DELETE, &kr6->r); + send_rt6msg(kr_state.fd, RTM_DELETE, kt, &kr6->r); - kr_state.fib_sync = 0; + kt->fib_sync = 0; - log_info("kernel routing table decoupled"); + log_info("kernel routing table %u (%s) decoupled", kt->rtableid, + kt->descr); } int @@ -472,11 +705,16 @@ kr_dispatch_msg(void) } int -kr_nexthop_add(struct bgpd_addr *addr) +kr_nexthop_add(u_int rtableid, struct bgpd_addr *addr) { + struct ktable *kt; struct knexthop_node *h; - if ((h = knexthop_find(addr)) != NULL) { + if ((kt = ktable_get(rtableid)) == NULL) { + log_warnx("kr_nexthop_add: non-existent rtableid %d", rtableid); + return (0); + } + if ((h = knexthop_find(kt, addr)) != NULL) { /* should not happen... this is actually an error path */ struct kroute_nexthop nh; struct kroute_node *k; @@ -519,7 +757,7 @@ kr_nexthop_add(struct bgpd_addr *addr) } memcpy(&h->nexthop, addr, sizeof(h->nexthop)); - if (knexthop_insert(h) == -1) + if (knexthop_insert(kt, h) == -1) return (-1); } @@ -527,19 +765,25 @@ kr_nexthop_add(struct bgpd_addr *addr) } void -kr_nexthop_delete(struct bgpd_addr *addr) +kr_nexthop_delete(u_int rtableid, struct bgpd_addr *addr) { + struct ktable *kt; struct knexthop_node *kn; - if ((kn = knexthop_find(addr)) == NULL) + if ((kt = ktable_get(rtableid)) == NULL) { + log_warnx("kr_nexthop_add: non-existent rtableid %d", rtableid); + return; + } + if ((kn = knexthop_find(kt, addr)) == NULL) return; - knexthop_remove(kn); + knexthop_remove(kt, kn); } void kr_show_route(struct imsg *imsg) { + struct ktable *kt; struct kroute_node *kr, *kn; struct kroute6_node *kr6, *kn6; struct bgpd_addr *addr; @@ -548,6 +792,7 @@ kr_show_route(struct imsg *imsg) struct ctl_show_nexthop snh; struct knexthop_node *h; struct kif_node *kif; + u_int i; u_short ifindex = 0; switch (imsg->hdr.type) { @@ -555,12 +800,18 @@ kr_show_route(struct imsg *imsg) if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(flags) + sizeof(af)) { log_warnx("kr_show_route: wrong imsg len"); - return; + break; + } + kt = ktable_get(imsg->hdr.peerid); + if (kt == NULL) { + log_warnx("kr_show_route: table %u does not exist", + imsg->hdr.peerid); + break; } memcpy(&flags, imsg->data, sizeof(flags)); memcpy(&af, (char *)imsg->data + sizeof(flags), sizeof(af)); if (!af || af == AF_INET) - RB_FOREACH(kr, kroute_tree, &krt) { + RB_FOREACH(kr, kroute_tree, &kt->krt) { if (flags && (kr->r.flags & flags) == 0) continue; kn = kr; @@ -571,7 +822,7 @@ kr_show_route(struct imsg *imsg) } while ((kn = kn->next) != NULL); } if (!af || af == AF_INET6) - RB_FOREACH(kr6, kroute6_tree, &krt6) { + RB_FOREACH(kr6, kroute6_tree, &kt->krt6) { if (flags && (kr6->r.flags & flags) == 0) continue; kn6 = kr6; @@ -586,20 +837,26 @@ kr_show_route(struct imsg *imsg) if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(struct bgpd_addr)) { log_warnx("kr_show_route: wrong imsg len"); - return; + break; + } + kt = ktable_get(imsg->hdr.peerid); + if (kt == NULL) { + log_warnx("kr_show_route: table %u does not exist", + imsg->hdr.peerid); + break; } addr = imsg->data; kr = NULL; switch (addr->aid) { case AID_INET: - kr = kroute_match(addr->v4.s_addr, 1); + kr = kroute_match(kt, addr->v4.s_addr, 1); if (kr != NULL) send_imsg_session(IMSG_CTL_KROUTE, imsg->hdr.pid, kr_tofull(&kr->r), sizeof(struct kroute_full)); break; case AID_INET6: - kr6 = kroute6_match(&addr->v6, 1); + kr6 = kroute6_match(kt, &addr->v6, 1); if (kr6 != NULL) send_imsg_session(IMSG_CTL_KROUTE, imsg->hdr.pid, kr6_tofull(&kr6->r), @@ -608,7 +865,13 @@ kr_show_route(struct imsg *imsg) } break; case IMSG_CTL_SHOW_NEXTHOP: - RB_FOREACH(h, knexthop_tree, &knt) { + kt = ktable_get(imsg->hdr.peerid); + if (kt == NULL) { + log_warnx("kr_show_route: table %u does not exist", + imsg->hdr.peerid); + break; + } + RB_FOREACH(h, knexthop_tree, KT2KNT(kt)) { bzero(&snh, sizeof(snh)); memcpy(&snh.addr, &h->nexthop, sizeof(snh.addr)); if (h->kroute != NULL) { @@ -643,6 +906,25 @@ kr_show_route(struct imsg *imsg) send_imsg_session(IMSG_CTL_SHOW_INTERFACE, imsg->hdr.pid, &kif->k, sizeof(kif->k)); break; + case IMSG_CTL_SHOW_FIB_TABLES: + for (i = 0; i < krt_size; i++) { + struct ktable ktab; + + if ((kt = ktable_get(i)) == NULL) + continue; + + ktab = *kt; + /* do not leak internal information */ + RB_INIT(&ktab.krt); + RB_INIT(&ktab.krt6); + RB_INIT(&ktab.knt); + TAILQ_INIT(&ktab.krn); + LIST_INIT(&ktab.redistlist); + + send_imsg_session(IMSG_CTL_SHOW_FIB_TABLES, + imsg->hdr.pid, &ktab, sizeof(ktab)); + } + break; default: /* nada */ break; } @@ -670,10 +952,8 @@ struct redist_node { }; -LIST_HEAD(, redist_node) redistlist; - int -kr_redistribute(int type, struct kroute *kr) +kr_redistribute(int type, struct ktable *kt, struct kroute *kr) { struct redist_node *rn; u_int32_t a; @@ -706,7 +986,7 @@ kr_redistribute(int type, struct kroute *kr) return (0); /* Add or delete kr from list ... */ - LIST_FOREACH(rn, &redistlist, entry) + LIST_FOREACH(rn, &kt->redistlist, entry) if (rn->kr == kr) break; @@ -719,7 +999,7 @@ kr_redistribute(int type, struct kroute *kr) return (-1); } rn->kr = kr; - LIST_INSERT_HEAD(&redistlist, rn, entry); + LIST_INSERT_HEAD(&kt->redistlist, rn, entry); } break; case IMSG_NETWORK_REMOVE: @@ -737,7 +1017,7 @@ kr_redistribute(int type, struct kroute *kr) } int -kr_redistribute6(int type, struct kroute6 *kr6) +kr_redistribute6(int type, struct ktable *kt, struct kroute6 *kr6) { struct redist_node *rn; @@ -779,7 +1059,7 @@ kr_redistribute6(int type, struct kroute6 *kr6) * using a linear list to store the redistributed networks will hurt * as soon as redistribute ospf comes but until then keep it simple. */ - LIST_FOREACH(rn, &redistlist, entry) + LIST_FOREACH(rn, &kt->redistlist, entry) if (rn->kr6 == kr6) break; @@ -792,7 +1072,7 @@ kr_redistribute6(int type, struct kroute6 *kr6) return (-1); } rn->kr6 = kr6; - LIST_INSERT_HEAD(&redistlist, rn, entry); + LIST_INSERT_HEAD(&kt->redistlist, rn, entry); } break; case IMSG_NETWORK_REMOVE: @@ -812,15 +1092,23 @@ kr_redistribute6(int type, struct kroute6 *kr6) int kr_reload(void) { + struct ktable *kt; struct redist_node *rn; struct knexthop_node *nh; + u_int rid; - LIST_FOREACH(rn, &redistlist, entry) - if (bgpd_redistribute(IMSG_NETWORK_ADD, rn->kr, rn->kr6) == -1) - return (-1); + for (rid = 0; rid < krt_size; rid++) { + if ((kt = ktable_get(rid)) == NULL) + continue; - RB_FOREACH(nh, knexthop_tree, &knt) - knexthop_validate(nh); + LIST_FOREACH(rn, &kt->redistlist, entry) + if (bgpd_redistribute(IMSG_NETWORK_ADD, rn->kr, + rn->kr6) == -1) + return (-1); + + RB_FOREACH(nh, knexthop_tree, KT2KNT(kt)) + knexthop_validate(kt, nh); + } return (0); } @@ -960,7 +1248,8 @@ kif_compare(struct kif_node *a, struct kif_node *b) */ struct kroute_node * -kroute_find(in_addr_t prefix, u_int8_t prefixlen, u_int8_t prio) +kroute_find(struct ktable *kt, in_addr_t prefix, u_int8_t prefixlen, + u_int8_t prio) { struct kroute_node s; struct kroute_node *kn, *tmp; @@ -969,15 +1258,15 @@ kroute_find(in_addr_t prefix, u_int8_t prefixlen, u_int8_t prio) s.r.prefixlen = prefixlen; s.r.priority = prio; - kn = RB_FIND(kroute_tree, &krt, &s); + kn = RB_FIND(kroute_tree, &kt->krt, &s); if (kn && prio == RTP_ANY) { - tmp = RB_PREV(kroute_tree, &krt, kn); + tmp = RB_PREV(kroute_tree, &kt->krt, kn); while (tmp) { if (kroute_compare(&s, tmp) == 0) kn = tmp; else break; - tmp = RB_PREV(kroute_tree, &krt, kn); + tmp = RB_PREV(kroute_tree, &kt->krt, kn); } } return (kn); @@ -1004,13 +1293,13 @@ kroute_matchgw(struct kroute_node *kr, struct sockaddr_in *sa_in) } int -kroute_insert(struct kroute_node *kr) +kroute_insert(struct ktable *kt, struct kroute_node *kr) { struct kroute_node *krm; struct knexthop_node *h; in_addr_t mask, ina; - if ((krm = RB_INSERT(kroute_tree, &krt, kr)) != NULL) { + if ((krm = RB_INSERT(kroute_tree, &kt->krt, kr)) != NULL) { /* multipath route, add at end of list */ while (krm->next != NULL) krm = krm->next; @@ -1021,10 +1310,10 @@ kroute_insert(struct kroute_node *kr) if (kr->r.flags & F_KERNEL) { mask = prefixlen2mask(kr->r.prefixlen); ina = ntohl(kr->r.prefix.s_addr); - RB_FOREACH(h, knexthop_tree, &knt) + RB_FOREACH(h, knexthop_tree, KT2KNT(kt)) if (h->nexthop.aid == AID_INET && (ntohl(h->nexthop.v4.s_addr) & mask) == ina) - knexthop_validate(h); + knexthop_validate(kt, h); if (kr->r.flags & F_CONNECTED) if (kif_kr_insert(kr) == -1) @@ -1032,19 +1321,19 @@ kroute_insert(struct kroute_node *kr) if (krm == NULL) /* redistribute multipath routes only once */ - kr_redistribute(IMSG_NETWORK_ADD, &kr->r); + kr_redistribute(IMSG_NETWORK_ADD, kt, &kr->r); } return (0); } int -kroute_remove(struct kroute_node *kr) +kroute_remove(struct ktable *kt, struct kroute_node *kr) { struct kroute_node *krm; struct knexthop_node *s; - if ((krm = RB_FIND(kroute_tree, &krt, kr)) == NULL) { + if ((krm = RB_FIND(kroute_tree, &kt->krt, kr)) == NULL) { log_warnx("kroute_remove failed to find %s/%u", inet_ntoa(kr->r.prefix), kr->r.prefixlen); return (-1); @@ -1052,13 +1341,14 @@ kroute_remove(struct kroute_node *kr) if (krm == kr) { /* head element */ - if (RB_REMOVE(kroute_tree, &krt, kr) == NULL) { + if (RB_REMOVE(kroute_tree, &kt->krt, kr) == NULL) { log_warnx("kroute_remove failed for %s/%u", inet_ntoa(kr->r.prefix), kr->r.prefixlen); return (-1); } if (kr->next != NULL) { - if (RB_INSERT(kroute_tree, &krt, kr->next) != NULL) { + if (RB_INSERT(kroute_tree, &kt->krt, kr->next) != + NULL) { log_warnx("kroute_remove failed to add %s/%u", inet_ntoa(kr->r.prefix), kr->r.prefixlen); return (-1); @@ -1079,13 +1369,13 @@ kroute_remove(struct kroute_node *kr) /* check whether a nexthop depends on this kroute */ if ((kr->r.flags & F_KERNEL) && (kr->r.flags & F_NEXTHOP)) - RB_FOREACH(s, knexthop_tree, &knt) + RB_FOREACH(s, knexthop_tree, KT2KNT(kt)) if (s->kroute == kr) - knexthop_validate(s); + knexthop_validate(kt, s); if (kr->r.flags & F_KERNEL && kr == krm && kr->next == NULL) /* again remove only once */ - kr_redistribute(IMSG_NETWORK_REMOVE, &kr->r); + kr_redistribute(IMSG_NETWORK_REMOVE, kt, &kr->r); if (kr->r.flags & F_CONNECTED) if (kif_kr_remove(kr) == -1) { @@ -1098,16 +1388,17 @@ kroute_remove(struct kroute_node *kr) } void -kroute_clear(void) +kroute_clear(struct ktable *kt) { struct kroute_node *kr; - while ((kr = RB_MIN(kroute_tree, &krt)) != NULL) - kroute_remove(kr); + while ((kr = RB_MIN(kroute_tree, &kt->krt)) != NULL) + kroute_remove(kt, kr); } struct kroute6_node * -kroute6_find(const struct in6_addr *prefix, u_int8_t prefixlen, u_int8_t prio) +kroute6_find(struct ktable *kt, const struct in6_addr *prefix, + u_int8_t prefixlen, u_int8_t prio) { struct kroute6_node s; struct kroute6_node *kn6, *tmp; @@ -1116,15 +1407,15 @@ kroute6_find(const struct in6_addr *prefix, u_int8_t prefixlen, u_int8_t prio) s.r.prefixlen = prefixlen; s.r.priority = prio; - kn6 = RB_FIND(kroute6_tree, &krt6, &s); + kn6 = RB_FIND(kroute6_tree, &kt->krt6, &s); if (kn6 && prio == RTP_ANY) { - tmp = RB_PREV(kroute6_tree, &krt6, kn6); + tmp = RB_PREV(kroute6_tree, &kt->krt6, kn6); while (tmp) { if (kroute6_compare(&s, tmp) == 0) kn6 = tmp; else break; - tmp = RB_PREV(kroute6_tree, &krt6, kn6); + tmp = RB_PREV(kroute6_tree, &kt->krt6, kn6); } } return (kn6); @@ -1151,13 +1442,13 @@ kroute6_matchgw(struct kroute6_node *kr, struct sockaddr_in6 *sa_in6) } int -kroute6_insert(struct kroute6_node *kr) +kroute6_insert(struct ktable *kt, struct kroute6_node *kr) { struct kroute6_node *krm; struct knexthop_node *h; struct in6_addr ina, inb; - if ((krm = RB_INSERT(kroute6_tree, &krt6, kr)) != NULL) { + if ((krm = RB_INSERT(kroute6_tree, &kt->krt6, kr)) != NULL) { /* multipath route, add at end of list */ while (krm->next != NULL) krm = krm->next; @@ -1167,12 +1458,12 @@ kroute6_insert(struct kroute6_node *kr) if (kr->r.flags & F_KERNEL) { inet6applymask(&ina, &kr->r.prefix, kr->r.prefixlen); - RB_FOREACH(h, knexthop_tree, &knt) + RB_FOREACH(h, knexthop_tree, KT2KNT(kt)) if (h->nexthop.aid == AID_INET6) { inet6applymask(&inb, &h->nexthop.v6, kr->r.prefixlen); if (memcmp(&ina, &inb, sizeof(ina)) == 0) - knexthop_validate(h); + knexthop_validate(kt, h); } if (kr->r.flags & F_CONNECTED) @@ -1181,19 +1472,19 @@ kroute6_insert(struct kroute6_node *kr) if (krm == NULL) /* redistribute multipath routes only once */ - kr_redistribute6(IMSG_NETWORK_ADD, &kr->r); + kr_redistribute6(IMSG_NETWORK_ADD, kt, &kr->r); } return (0); } int -kroute6_remove(struct kroute6_node *kr) +kroute6_remove(struct ktable *kt, struct kroute6_node *kr) { struct kroute6_node *krm; struct knexthop_node *s; - if ((krm = RB_FIND(kroute6_tree, &krt6, kr)) == NULL) { + if ((krm = RB_FIND(kroute6_tree, &kt->krt6, kr)) == NULL) { log_warnx("kroute6_remove failed for %s/%u", log_in6addr(&kr->r.prefix), kr->r.prefixlen); return (-1); @@ -1201,13 +1492,14 @@ kroute6_remove(struct kroute6_node *kr) if (krm == kr) { /* head element */ - if (RB_REMOVE(kroute6_tree, &krt6, kr) == NULL) { + if (RB_REMOVE(kroute6_tree, &kt->krt6, kr) == NULL) { log_warnx("kroute6_remove failed for %s/%u", log_in6addr(&kr->r.prefix), kr->r.prefixlen); return (-1); } if (kr->next != NULL) { - if (RB_INSERT(kroute6_tree, &krt6, kr->next) != NULL) { + if (RB_INSERT(kroute6_tree, &kt->krt6, kr->next) != + NULL) { log_warnx("kroute6_remove failed to add %s/%u", log_in6addr(&kr->r.prefix), kr->r.prefixlen); @@ -1229,13 +1521,13 @@ kroute6_remove(struct kroute6_node *kr) /* check whether a nexthop depends on this kroute */ if ((kr->r.flags & F_KERNEL) && (kr->r.flags & F_NEXTHOP)) - RB_FOREACH(s, knexthop_tree, &knt) + RB_FOREACH(s, knexthop_tree, KT2KNT(kt)) if (s->kroute == kr) - knexthop_validate(s); + knexthop_validate(kt, s); if (kr->r.flags & F_KERNEL && kr == krm && kr->next == NULL) /* again remove only once */ - kr_redistribute6(IMSG_NETWORK_REMOVE, &kr->r); + kr_redistribute6(IMSG_NETWORK_REMOVE, kt, &kr->r); if (kr->r.flags & F_CONNECTED) if (kif_kr6_remove(kr) == -1) { @@ -1248,46 +1540,46 @@ kroute6_remove(struct kroute6_node *kr) } void -kroute6_clear(void) +kroute6_clear(struct ktable *kt) { struct kroute6_node *kr; - while ((kr = RB_MIN(kroute6_tree, &krt6)) != NULL) - kroute6_remove(kr); + while ((kr = RB_MIN(kroute6_tree, &kt->krt6)) != NULL) + kroute6_remove(kt, kr); } struct knexthop_node * -knexthop_find(struct bgpd_addr *addr) +knexthop_find(struct ktable *kt, struct bgpd_addr *addr) { struct knexthop_node s; bzero(&s, sizeof(s)); memcpy(&s.nexthop, addr, sizeof(s.nexthop)); - return (RB_FIND(knexthop_tree, &knt, &s)); + return (RB_FIND(knexthop_tree, KT2KNT(kt), &s)); } int -knexthop_insert(struct knexthop_node *kn) +knexthop_insert(struct ktable *kt, struct knexthop_node *kn) { - if (RB_INSERT(knexthop_tree, &knt, kn) != NULL) { + if (RB_INSERT(knexthop_tree, KT2KNT(kt), kn) != NULL) { log_warnx("knexthop_tree insert failed for %s", log_addr(&kn->nexthop)); free(kn); return (-1); } - knexthop_validate(kn); + knexthop_validate(kt, kn); return (0); } int -knexthop_remove(struct knexthop_node *kn) +knexthop_remove(struct ktable *kt, struct knexthop_node *kn) { - kroute_detach_nexthop(kn); + kroute_detach_nexthop(kt, kn); - if (RB_REMOVE(knexthop_tree, &knt, kn) == NULL) { + if (RB_REMOVE(knexthop_tree, KT2KNT(kt), kn) == NULL) { log_warnx("knexthop_remove failed for %s", log_addr(&kn->nexthop)); return (-1); @@ -1298,12 +1590,12 @@ knexthop_remove(struct knexthop_node *kn) } void -knexthop_clear(void) +knexthop_clear(struct ktable *kt) { struct knexthop_node *kn; - while ((kn = RB_MIN(knexthop_tree, &knt)) != NULL) - knexthop_remove(kn); + while ((kn = RB_MIN(knexthop_tree, KT2KNT(kt))) != NULL) + knexthop_remove(kt, kn); } struct kif_node * @@ -1335,6 +1627,7 @@ kif_insert(struct kif_node *kif) int kif_remove(struct kif_node *kif) { + struct ktable *kt; struct kif_kr *kkr; struct kif_kr6 *kkr6; @@ -1343,20 +1636,23 @@ kif_remove(struct kif_node *kif) return (-1); } + if ((kt = ktable_get(/* XXX */ 0)) == NULL) + goto done; + while ((kkr = LIST_FIRST(&kif->kroute_l)) != NULL) { LIST_REMOVE(kkr, entry); kkr->kr->r.flags &= ~F_NEXTHOP; - kroute_remove(kkr->kr); + kroute_remove(kt, kkr->kr); free(kkr); } while ((kkr6 = LIST_FIRST(&kif->kroute6_l)) != NULL) { LIST_REMOVE(kkr6, entry); kkr6->kr->r.flags &= ~F_NEXTHOP; - kroute6_remove(kkr6->kr); + kroute6_remove(kt, kkr6->kr); free(kkr6); } - +done: free(kif); return (0); } @@ -1551,7 +1847,7 @@ kroute6_validate(struct kroute6 *kr) } void -knexthop_validate(struct knexthop_node *kn) +knexthop_validate(struct ktable *kt, struct knexthop_node *kn) { struct kroute_node *kr; struct kroute6_node *kr6; @@ -1565,11 +1861,11 @@ knexthop_validate(struct knexthop_node *kn) bzero(&n, sizeof(n)); memcpy(&n.nexthop, &kn->nexthop, sizeof(n.nexthop)); - kroute_detach_nexthop(kn); + kroute_detach_nexthop(kt, kn); switch (kn->nexthop.aid) { case AID_INET: - if ((kr = kroute_match(kn->nexthop.v4.s_addr, 0)) == NULL) { + if ((kr = kroute_match(kt, kn->nexthop.v4.s_addr, 0)) == NULL) { if (was_valid) send_nexthop_update(&n); } else { /* match */ @@ -1592,7 +1888,7 @@ knexthop_validate(struct knexthop_node *kn) } break; case AID_INET6: - if ((kr6 = kroute6_match(&kn->nexthop.v6, 0)) == NULL) { + if ((kr6 = kroute6_match(kt, &kn->nexthop.v6, 0)) == NULL) { if (was_valid) send_nexthop_update(&n); } else { /* match */ @@ -1622,21 +1918,21 @@ knexthop_validate(struct knexthop_node *kn) } void -knexthop_track(void *krn) +knexthop_track(struct ktable *kt, void *krp) { struct knexthop_node *kn; struct kroute_node *kr; struct kroute6_node *kr6; struct kroute_nexthop n; - RB_FOREACH(kn, knexthop_tree, &knt) - if (kn->kroute == krn) { + RB_FOREACH(kn, knexthop_tree, KT2KNT(kt)) + if (kn->kroute == krp) { bzero(&n, sizeof(n)); memcpy(&n.nexthop, &kn->nexthop, sizeof(n.nexthop)); switch (kn->nexthop.aid) { case AID_INET: - kr = krn; + kr = krp; n.valid = 1; n.connected = kr->r.flags & F_CONNECTED; if ((n.gateway.v4.s_addr = @@ -1647,7 +1943,7 @@ knexthop_track(void *krn) n.netlen = kr->r.prefixlen; break; case AID_INET6: - kr6 = krn; + kr6 = krp; n.valid = 1; n.connected = kr6->r.flags & F_CONNECTED; if (memcmp(&kr6->r.nexthop, &in6addr_any, @@ -1667,7 +1963,7 @@ knexthop_track(void *krn) } struct kroute_node * -kroute_match(in_addr_t key, int matchall) +kroute_match(struct ktable *kt, in_addr_t key, int matchall) { int i; struct kroute_node *kr; @@ -1677,13 +1973,13 @@ kroute_match(in_addr_t key, int matchall) /* we will never match the default route */ for (i = 32; i > 0; i--) - if ((kr = kroute_find(htonl(ina & prefixlen2mask(i)), i, + if ((kr = kroute_find(kt, htonl(ina & prefixlen2mask(i)), i, RTP_ANY)) != NULL) if (matchall || bgpd_filternexthop(&kr->r, NULL) == 0) return (kr); /* if we don't have a match yet, try to find a default route */ - if ((kr = kroute_find(0, 0, RTP_ANY)) != NULL) + if ((kr = kroute_find(kt, 0, 0, RTP_ANY)) != NULL) if (matchall || bgpd_filternexthop(&kr->r, NULL) == 0) return (kr); @@ -1691,7 +1987,7 @@ kroute_match(in_addr_t key, int matchall) } struct kroute6_node * -kroute6_match(struct in6_addr *key, int matchall) +kroute6_match(struct ktable *kt, struct in6_addr *key, int matchall) { int i; struct kroute6_node *kr6; @@ -1700,13 +1996,13 @@ kroute6_match(struct in6_addr *key, int matchall) /* we will never match the default route */ for (i = 128; i > 0; i--) { inet6applymask(&ina, key, i); - if ((kr6 = kroute6_find(&ina, i, RTP_ANY)) != NULL) + if ((kr6 = kroute6_find(kt, &ina, i, RTP_ANY)) != NULL) if (matchall || bgpd_filternexthop(NULL, &kr6->r) == 0) return (kr6); } /* if we don't have a match yet, try to find a default route */ - if ((kr6 = kroute6_find(&in6addr_any, 0, RTP_ANY)) != NULL) + if ((kr6 = kroute6_find(kt, &in6addr_any, 0, RTP_ANY)) != NULL) if (matchall || bgpd_filternexthop(NULL, &kr6->r) == 0) return (kr6); @@ -1714,7 +2010,7 @@ kroute6_match(struct in6_addr *key, int matchall) } void -kroute_detach_nexthop(struct knexthop_node *kn) +kroute_detach_nexthop(struct ktable *kt, struct knexthop_node *kn) { struct knexthop_node *s; struct kroute_node *k; @@ -1728,8 +2024,8 @@ kroute_detach_nexthop(struct knexthop_node *kn) if (kn->kroute == NULL) return; - for (s = RB_MIN(knexthop_tree, &knt); s != NULL && - s->kroute != kn->kroute; s = RB_NEXT(knexthop_tree, &knt, s)) + for (s = RB_MIN(knexthop_tree, KT2KNT(kt)); s != NULL && + s->kroute != kn->kroute; s = RB_NEXT(knexthop_tree, KT2KNT(kt), s)) ; /* nothing */ if (s == NULL) { @@ -1753,7 +2049,7 @@ kroute_detach_nexthop(struct knexthop_node *kn) */ int -protect_lo(void) +protect_lo(struct ktable *kt) { struct kroute_node *kr; struct kroute6_node *kr6; @@ -1767,7 +2063,7 @@ protect_lo(void) kr->r.prefixlen = 8; kr->r.flags = F_KERNEL|F_CONNECTED; - if (RB_INSERT(kroute_tree, &krt, kr) != NULL) + if (RB_INSERT(kroute_tree, &kt->krt, kr) != NULL) free(kr); /* kernel route already there, no problem */ /* special protection for loopback */ @@ -1779,7 +2075,7 @@ protect_lo(void) kr6->r.prefixlen = 128; kr6->r.flags = F_KERNEL|F_CONNECTED; - if (RB_INSERT(kroute6_tree, &krt6, kr6) != NULL) + if (RB_INSERT(kroute6_tree, &kt->krt6, kr6) != NULL) free(kr6); /* kernel route already there, no problem */ return (0); @@ -1896,6 +2192,7 @@ get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) void if_change(u_short ifindex, int flags, struct if_data *ifd) { + struct ktable *kt; struct kif_node *kif; struct kif_kr *kkr; struct kif_kr6 *kkr6; @@ -1921,13 +2218,18 @@ if_change(u_short ifindex, int flags, struct if_data *ifd) kif->k.nh_reachable = reachable; + kt = ktable_get(/* XXX */ 0); + LIST_FOREACH(kkr, &kif->kroute_l, entry) { if (reachable) kkr->kr->r.flags &= ~F_DOWN; else kkr->kr->r.flags |= F_DOWN; - RB_FOREACH(n, knexthop_tree, &knt) + if (kt == NULL) + continue; + + RB_FOREACH(n, knexthop_tree, KT2KNT(kt)) if (n->kroute == kkr->kr) { bzero(&nh, sizeof(nh)); memcpy(&nh.nexthop, &n->nexthop, @@ -1951,7 +2253,9 @@ if_change(u_short ifindex, int flags, struct if_data *ifd) else kkr6->kr->r.flags |= F_DOWN; - RB_FOREACH(n, knexthop_tree, &knt) + if (kt == NULL) + continue; + RB_FOREACH(n, knexthop_tree, KT2KNT(kt)) if (n->kroute == kkr6->kr) { bzero(&nh, sizeof(nh)); memcpy(&nh.nexthop, &n->nexthop, @@ -2008,7 +2312,7 @@ if_announce(void *msg) */ int -send_rtmsg(int fd, int action, struct kroute *kroute) +send_rtmsg(int fd, int action, struct ktable *kt, struct kroute *kroute) { struct iovec iov[5]; struct rt_msghdr hdr; @@ -2018,14 +2322,14 @@ send_rtmsg(int fd, int action, struct kroute *kroute) struct sockaddr_rtlabel label; int iovcnt = 0; - if (kr_state.fib_sync == 0) + if (!kt->fib_sync) return (0); /* initialize header */ bzero(&hdr, sizeof(hdr)); hdr.rtm_version = RTM_VERSION; hdr.rtm_type = action; - hdr.rtm_tableid = kr_state.rtableid; + hdr.rtm_tableid = kt->rtableid; hdr.rtm_priority = RTP_BGP; if (kroute->flags & F_BLACKHOLE) hdr.rtm_flags |= RTF_BLACKHOLE; @@ -2120,7 +2424,7 @@ retry: } int -send_rt6msg(int fd, int action, struct kroute6 *kroute) +send_rt6msg(int fd, int action, struct ktable *kt, struct kroute6 *kroute) { struct iovec iov[5]; struct rt_msghdr hdr; @@ -2131,14 +2435,14 @@ send_rt6msg(int fd, int action, struct kroute6 *kroute) struct sockaddr_rtlabel label; int iovcnt = 0; - if (kr_state.fib_sync == 0) + if (!kt->fib_sync) return (0); /* initialize header */ bzero(&hdr, sizeof(hdr)); hdr.rtm_version = RTM_VERSION; hdr.rtm_type = action; - hdr.rtm_tableid = kr_state.rtableid; + hdr.rtm_tableid = kt->rtableid; if (kroute->flags & F_BLACKHOLE) hdr.rtm_flags |= RTF_BLACKHOLE; if (kroute->flags & F_REJECT) @@ -2236,11 +2540,11 @@ retry: } int -fetchtable(u_int rtableid, int connected_only) +fetchtable(struct ktable *kt) { size_t len; int mib[7]; - char *buf, *next, *lim; + char *buf = NULL, *next, *lim; struct rt_msghdr *rtm; struct sockaddr *sa, *gw, *rti_info[RTAX_MAX]; struct sockaddr_in *sa_in; @@ -2254,22 +2558,25 @@ fetchtable(u_int rtableid, int connected_only) mib[3] = 0; mib[4] = NET_RT_DUMP; mib[5] = 0; - mib[6] = rtableid; + mib[6] = kt->rtableid; if (sysctl(mib, 7, NULL, &len, NULL, 0) == -1) { - if (rtableid != 0 && errno == EINVAL) /* table nonexistent */ + if (kt->rtableid != 0 && errno == EINVAL) + /* table nonexistent */ return (0); log_warn("sysctl"); return (-1); } - if ((buf = malloc(len)) == NULL) { - log_warn("fetchtable"); - return (-1); - } - if (sysctl(mib, 7, buf, &len, NULL, 0) == -1) { - log_warn("sysctl"); - free(buf); - return (-1); + if (len > 0) { + if ((buf = malloc(len)) == NULL) { + log_warn("fetchtable"); + return (-1); + } + if (sysctl(mib, 7, buf, &len, NULL, 0) == -1) { + log_warn("sysctl2"); + free(buf); + return (-1); + } } lim = buf + len; @@ -2382,22 +2689,17 @@ fetchtable(u_int rtableid, int connected_only) if (sa->sa_family == AF_INET) { if (rtm->rtm_priority == RTP_BGP) { - send_rtmsg(kr_state.fd, RTM_DELETE, &kr->r); - free(kr); - } else if (connected_only && - !(kr->r.flags & F_CONNECTED)) + send_rtmsg(kr_state.fd, RTM_DELETE, kt, &kr->r); free(kr); - else - kroute_insert(kr); + } else + kroute_insert(kt, kr); } else if (sa->sa_family == AF_INET6) { if (rtm->rtm_priority == RTP_BGP) { - send_rt6msg(kr_state.fd, RTM_DELETE, &kr6->r); - free(kr6); - } else if (connected_only && - !(kr6->r.flags & F_CONNECTED)) + send_rt6msg(kr_state.fd, RTM_DELETE, kt, + &kr6->r); free(kr6); - else - kroute6_insert(kr6); + } else + kroute6_insert(kt, kr6); } } free(buf); @@ -2418,7 +2720,7 @@ fetchifs(int ifindex) mib[0] = CTL_NET; mib[1] = AF_ROUTE; mib[2] = 0; - mib[3] = AF_INET; + mib[3] = AF_INET; /* AF does not matter but AF_INET is shorter */ mib[4] = NET_RT_IFLIST; mib[5] = ifindex; @@ -2487,7 +2789,7 @@ dispatch_rtmsg(void) struct rt_msghdr *rtm; struct if_msghdr ifm; struct sockaddr *sa, *rti_info[RTAX_MAX]; - int connected_only; + struct ktable *kt; if ((n = read(kr_state.fd, &buf, sizeof(buf))) == -1) { log_warn("dispatch_rtmsg: read error"); @@ -2521,16 +2823,10 @@ dispatch_rtmsg(void) if (rtm->rtm_flags & RTF_LLINFO) /* arp cache */ continue; - connected_only = 0; - if (rtm->rtm_tableid != kr_state.rtableid) { - if (rtm->rtm_tableid == 0) - connected_only = 1; - else - continue; - } + if ((kt = ktable_get(rtm->rtm_tableid)) == NULL) + continue; - if (dispatch_rtmsg_addr(rtm, rti_info, - connected_only) == -1) + if (dispatch_rtmsg_addr(rtm, rti_info, kt) == -1) return (-1); break; case RTM_IFINFO: @@ -2551,7 +2847,7 @@ dispatch_rtmsg(void) int dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX], - int connected_only) + struct ktable *kt) { struct sockaddr *sa; struct sockaddr_in *sa_in; @@ -2632,7 +2928,7 @@ dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX], switch (prefix.aid) { case AID_INET: sa_in = (struct sockaddr_in *)sa; - if ((kr = kroute_find(prefix.v4.s_addr, + if ((kr = kroute_find(kt, prefix.v4.s_addr, prefixlen, prio)) == NULL) return (0); if (!(kr->r.flags & F_KERNEL)) @@ -2646,12 +2942,12 @@ dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX], return (0); } - if (kroute_remove(kr) == -1) + if (kroute_remove(kt, kr) == -1) return (-1); break; case AID_INET6: sa_in6 = (struct sockaddr_in6 *)sa; - if ((kr6 = kroute6_find(&prefix.v6, prefixlen, + if ((kr6 = kroute6_find(kt, &prefix.v6, prefixlen, prio)) == NULL) return (0); if (!(kr6->r.flags & F_KERNEL)) @@ -2666,16 +2962,13 @@ dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX], return (0); } - if (kroute6_remove(kr6) == -1) + if (kroute6_remove(kt, kr6) == -1) return (-1); break; } return (0); } - if (connected_only && !(flags & F_CONNECTED)) - return (0); - if (sa == NULL && !(flags & F_CONNECTED)) { log_warnx("dispatch_rtmsg no nexthop for %s/%u", log_addr(&prefix), prefixlen); @@ -2685,7 +2978,7 @@ dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX], switch (prefix.aid) { case AID_INET: sa_in = (struct sockaddr_in *)sa; - if ((kr = kroute_find(prefix.v4.s_addr, prefixlen, + if ((kr = kroute_find(kt, prefix.v4.s_addr, prefixlen, prio)) != NULL) { if (kr->r.flags & F_KERNEL) { /* get the correct route */ @@ -2711,16 +3004,16 @@ dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct sockaddr *rti_info[RTAX_MAX], !(flags & F_CONNECTED)) { kif_kr_remove(kr); kr_redistribute(IMSG_NETWORK_REMOVE, - &kr->r); + kt, &kr->r); } if ((flags & F_CONNECTED) && !(oflags & F_CONNECTED)) { kif_kr_insert(kr); kr_redistribute(IMSG_NETWORK_ADD, - &kr->r); + kt, &kr->r); } if (kr->r.flags & F_NEXTHOP) - knexthop_track(kr); + knexthop_track(kt, kr); } } else if (rtm->rtm_type == RTM_CHANGE) { log_warnx("change req for %s/%u: not in table", @@ -2743,12 +3036,13 @@ add4: kr->r.ifindex = ifindex; kr->r.priority = prio; - kroute_insert(kr); + kroute_insert(kt, kr); } break; case AID_INET6: sa_in6 = (struct sockaddr_in6 *)sa; - if ((kr6 = kroute6_find(&prefix.v6, prefixlen, prio)) != NULL) { + if ((kr6 = kroute6_find(kt, &prefix.v6, prefixlen, prio)) != + NULL) { if (kr6->r.flags & F_KERNEL) { /* get the correct route */ if (mpath && rtm->rtm_type == RTM_CHANGE && @@ -2777,16 +3071,16 @@ add4: !(flags & F_CONNECTED)) { kif_kr6_remove(kr6); kr_redistribute6(IMSG_NETWORK_REMOVE, - &kr6->r); + kt, &kr6->r); } if ((flags & F_CONNECTED) && !(oflags & F_CONNECTED)) { kif_kr6_insert(kr6); kr_redistribute6(IMSG_NETWORK_ADD, - &kr6->r); + kt, &kr6->r); } if (kr6->r.flags & F_NEXTHOP) - knexthop_track(kr6); + knexthop_track(kt, kr6); } } else if (rtm->rtm_type == RTM_CHANGE) { log_warnx("change req for %s/%u: not in table", @@ -2812,7 +3106,7 @@ add6: kr6->r.ifindex = ifindex; kr6->r.priority = prio; - kroute6_insert(kr6); + kroute6_insert(kt, kr6); } break; } diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y index 966aa7c1e57..cc41bd888c3 100644 --- a/usr.sbin/bgpd/parse.y +++ b/usr.sbin/bgpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.252 2010/04/28 13:07:48 claudio Exp $ */ +/* $OpenBSD: parse.y,v 1.253 2010/05/03 13:09:38 claudio Exp $ */ /* * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -113,8 +113,8 @@ struct peer *new_peer(void); struct peer *new_group(void); int add_mrtconfig(enum mrt_type, char *, time_t, struct peer *, char *); -int add_rib(char *, u_int16_t); -int find_rib(char *); +int add_rib(char *, u_int, u_int16_t); +struct rde_rib *find_rib(char *); int get_id(struct peer *); int expand_rule(struct filter_rule *, struct filter_peers_l *, struct filter_match_l *, struct filter_set_head *); @@ -364,10 +364,15 @@ conf_main : AS as4number { TAILQ_INSERT_TAIL(listen_addrs, la, entry); } | FIBUPDATE yesno { + struct rde_rib *rr; + rr = find_rib("Loc-RIB"); + if (rr == NULL) + fatalx("RTABLE can not find the main RIB!"); + if ($2 == 0) - conf->flags |= BGPD_FLAG_NO_FIB_UPDATE; + rr->flags |= F_RIB_NOFIBSYNC; else - conf->flags &= ~BGPD_FLAG_NO_FIB_UPDATE; + rr->flags &= ~F_RIB_NOFIBSYNC; } | ROUTECOLL yesno { if ($2 == 1) @@ -376,7 +381,7 @@ conf_main : AS as4number { conf->flags &= ~BGPD_FLAG_NO_EVALUATE; } | RDE RIB STRING { - if (add_rib($3, F_RIB_NOFIB)) { + if (add_rib($3, 0, F_RIB_NOFIB)) { free($3); YYERROR; } @@ -385,9 +390,27 @@ conf_main : AS as4number { | RDE RIB STRING yesno EVALUATE { if ($4) { free($3); + yyerror("bad rde rib definition"); + YYERROR; + } + if (add_rib($3, 0, F_RIB_NOFIB | F_RIB_NOEVALUATE)) { + free($3); + YYERROR; + } + free($3); + } + | RDE RIB STRING RTABLE NUMBER { + if (add_rib($3, $5, 0)) { + free($3); YYERROR; } - if (!add_rib($3, F_RIB_NOFIB | F_RIB_NOEVALUATE)) { + free($3); + } + | RDE RIB STRING RTABLE NUMBER FIBUPDATE yesno { + int flags = 0; + if ($7 == 0) + flags = F_RIB_NOFIBSYNC; + if (add_rib($3, $5, flags)) { free($3); YYERROR; } @@ -553,11 +576,15 @@ conf_main : AS as4number { free($4); } | RTABLE NUMBER { - if ($2 > RT_TABLEID_MAX || $2 < 0) { - yyerror("invalid rtable id"); + struct rde_rib *rr; + if (ktable_exists($2, NULL) != 1) { + yyerror("rtable id %lld does not exist", $2); YYERROR; } - conf->rtableid = $2; + rr = find_rib("Loc-RIB"); + if (rr == NULL) + fatalx("RTABLE can not find the main RIB!"); + rr->rtableid = $2; } | CONNECTRETRY NUMBER { if ($2 > USHRT_MAX || $2 < 1) { @@ -2382,8 +2409,8 @@ parse_config(char *filename, struct bgpd_config *xconf, /* init the empty filter list for later */ TAILQ_INIT(xfilter_l); - add_rib("Adj-RIB-In", F_RIB_NOEVALUATE); - add_rib("Loc-RIB", 0); + add_rib("Adj-RIB-In", 0, F_RIB_NOEVALUATE); + add_rib("Loc-RIB", 0, 0); yyparse(); errors = file->errors; @@ -2896,39 +2923,52 @@ add_mrtconfig(enum mrt_type type, char *name, time_t timeout, struct peer *p, } int -add_rib(char *name, u_int16_t flags) +add_rib(char *name, u_int rtableid, u_int16_t flags) { struct rde_rib *rr; + u_int rdom; - if (find_rib(name)) { - yyerror("rib \"%s\" allready exists.", name); - return (-1); - } - - if ((rr = calloc(1, sizeof(*rr))) == NULL) { - log_warn("add_rib"); - return (-1); + if ((rr = find_rib(name)) == NULL) { + if ((rr = calloc(1, sizeof(*rr))) == NULL) { + log_warn("add_rib"); + return (-1); + } } if (strlcpy(rr->name, name, sizeof(rr->name)) >= sizeof(rr->name)) { yyerror("rib name \"%s\" too long: max %u", name, sizeof(rr->name) - 1); + free(rr); return (-1); } rr->flags |= flags; + if ((rr->flags & F_RIB_HASNOFIB) == 0) { + if (ktable_exists(rtableid, &rdom) != 1) { + yyerror("rtable id %lld does not exist", rtableid); + free(rr); + return (-1); + } + if (rdom != 0) { + yyerror("rtable %lld does not belong to rdomain 0", + rtableid); + free(rr); + return (-1); + } + rr->rtableid = rtableid; + } SIMPLEQ_INSERT_TAIL(&ribnames, rr, entry); return (0); } -int +struct rde_rib * find_rib(char *name) { struct rde_rib *rr; SIMPLEQ_FOREACH(rr, &ribnames, entry) { if (!strcmp(rr->name, name)) - return (1); + return (rr); } - return (0); + return (NULL); } int diff --git a/usr.sbin/bgpd/printconf.c b/usr.sbin/bgpd/printconf.c index 54d8d51626d..5a94342ddf0 100644 --- a/usr.sbin/bgpd/printconf.c +++ b/usr.sbin/bgpd/printconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: printconf.c,v 1.79 2010/03/05 15:25:00 claudio Exp $ */ +/* $OpenBSD: printconf.c,v 1.80 2010/05/03 13:09:38 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -242,11 +242,6 @@ print_mainconf(struct bgpd_config *conf) if (conf->connectretry) printf("connect-retry %u\n", conf->connectretry); - if (conf->flags & BGPD_FLAG_NO_FIB_UPDATE) - printf("fib-update no\n"); - else - printf("fib-update yes\n"); - if (conf->flags & BGPD_FLAG_NO_EVALUATE) printf("route-collector yes\n"); @@ -684,8 +679,12 @@ print_config(struct bgpd_config *conf, struct rib_names *rib_l, SIMPLEQ_FOREACH(rr, rib_l, entry) { if (rr->flags & F_RIB_NOEVALUATE) printf("rde rib %s no evaluate\n", rr->name); - else + else if (rr->flags & F_RIB_NOFIB) printf("rde rib %s\n", rr->name); + else + printf("rde rib %s rtable %u fib-update %s\n", rr->name, + rr->rtableid, rr->flags & F_RIB_NOFIBSYNC ? + "no" : "yes"); } printf("\n"); TAILQ_FOREACH(n, net_l, entry) diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c index 4700050b225..b0f72396a81 100644 --- a/usr.sbin/bgpd/rde.c +++ b/usr.sbin/bgpd/rde.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.c,v 1.291 2010/04/13 09:09:48 claudio Exp $ */ +/* $OpenBSD: rde.c,v 1.292 2010/05/03 13:09:38 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -596,8 +596,15 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf) memcpy(&rn, imsg.data, sizeof(rn)); rid = rib_find(rn.name); if (rid == RIB_FAILED) - rib_new(rn.name, rn.flags); - else + 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_FILTER: @@ -666,7 +673,7 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf) 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, AID_UNSPEC); @@ -1981,15 +1988,15 @@ rde_dump_rib_as(struct prefix *p, struct rde_aspath *asp, pid_t pid, int flags) 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, @@ -2212,7 +2219,7 @@ rde_dump_mrt_new(struct mrt *mrt, pid_t pid, int fd) * kroute specific functions */ 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_full kr; struct bgpd_addr addr; @@ -2249,7 +2256,7 @@ rde_send_kroute(struct prefix *new, struct prefix *old) strlcpy(kr.label, rtlabel_id2name(p->aspath->rtlabelid), sizeof(kr.label)); - if (imsg_compose(ibuf_main, type, 0, 0, -1, &kr, + if (imsg_compose(ibuf_main, type, ribs[ribid].rtableid, 0, -1, &kr, sizeof(kr)) == -1) fatal("imsg_compose error"); } diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h index c85a2a93a67..bf3f3a8a9f6 100644 --- a/usr.sbin/bgpd/rde.h +++ b/usr.sbin/bgpd/rde.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.h,v 1.133 2010/03/29 09:24:07 claudio Exp $ */ +/* $OpenBSD: rde.h,v 1.134 2010/05/03 13:09:38 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and @@ -276,14 +276,12 @@ struct rib_entry { struct rib { char name[PEER_DESCR_LEN]; struct rib_tree rib; - enum reconf_action state; + u_int rtableid; u_int16_t flags; u_int16_t id; + enum reconf_action state; }; -#define F_RIB_ENTRYLOCK 0x0001 -#define F_RIB_NOEVALUATE 0x0002 -#define F_RIB_NOFIB 0x0004 #define RIB_FAILED 0xffff struct prefix { @@ -298,7 +296,7 @@ extern struct rde_memstats rdemem; /* prototypes */ /* rde.c */ -void rde_send_kroute(struct prefix *, struct prefix *); +void rde_send_kroute(struct prefix *, struct prefix *, u_int16_t); void rde_send_nexthop(struct bgpd_addr *, int); void rde_send_pftable(u_int16_t, struct bgpd_addr *, u_int8_t, int); @@ -363,7 +361,7 @@ int community_ext_conv(struct filter_extcommunity *, u_int16_t, extern u_int16_t rib_size; extern struct rib *ribs; -u_int16_t rib_new(char *, u_int16_t); +u_int16_t rib_new(char *, u_int, u_int16_t); u_int16_t rib_find(char *); void rib_free(struct rib *); struct rib_entry *rib_get(struct rib *, struct bgpd_addr *, int); diff --git a/usr.sbin/bgpd/rde_decide.c b/usr.sbin/bgpd/rde_decide.c index 5dfd5dcd446..27586a72c9e 100644 --- a/usr.sbin/bgpd/rde_decide.c +++ b/usr.sbin/bgpd/rde_decide.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde_decide.c,v 1.59 2009/08/06 08:53:11 claudio Exp $ */ +/* $OpenBSD: rde_decide.c,v 1.60 2010/05/03 13:09:38 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> @@ -269,7 +269,7 @@ prefix_evaluate(struct prefix *p, struct rib_entry *re) */ rde_generate_updates(re->ribid, xp, re->active); if ((re->flags & F_RIB_NOFIB) == 0) - rde_send_kroute(xp, re->active); + rde_send_kroute(xp, re->active, re->ribid); re->active = xp; if (xp != NULL) diff --git a/usr.sbin/bgpd/rde_rib.c b/usr.sbin/bgpd/rde_rib.c index abada750b58..9a13486be06 100644 --- a/usr.sbin/bgpd/rde_rib.c +++ b/usr.sbin/bgpd/rde_rib.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde_rib.c,v 1.126 2010/04/20 09:02:12 claudio Exp $ */ +/* $OpenBSD: rde_rib.c,v 1.127 2010/05/03 13:09:38 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> @@ -50,7 +50,7 @@ RB_GENERATE(rib_tree, rib_entry, rib_e, rib_compare); /* RIB specific functions */ u_int16_t -rib_new(char *name, u_int16_t flags) +rib_new(char *name, u_int rtableid, u_int16_t flags) { struct rib *xribs; size_t newsize; @@ -80,6 +80,7 @@ rib_new(char *name, u_int16_t flags) ribs[id].state = RECONF_REINIT; ribs[id].id = id; ribs[id].flags = flags; + ribs[id].rtableid = rtableid; return (id); } @@ -897,7 +898,7 @@ prefix_updateall(struct rde_aspath *asp, enum nexthop_state state, */ if ((p->rib->flags & F_RIB_NOFIB) == 0 && p == p->rib->active) - rde_send_kroute(p, NULL); + rde_send_kroute(p, NULL, p->rib->ribid); continue; } diff --git a/usr.sbin/bgpd/session.c b/usr.sbin/bgpd/session.c index c6222e07cf6..858896adac2 100644 --- a/usr.sbin/bgpd/session.c +++ b/usr.sbin/bgpd/session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: session.c,v 1.307 2010/04/16 12:24:25 claudio Exp $ */ +/* $OpenBSD: session.c,v 1.308 2010/05/03 13:09:38 claudio Exp $ */ /* * Copyright (c) 2003, 2004, 2005 Henning Brauer <henning@openbsd.org> @@ -2361,7 +2361,6 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt) fatalx("got IMSG_RECONF_DONE but no config"); conf->flags = nconf->flags; conf->log = nconf->log; - conf->rtableid = nconf->rtableid; conf->bgpid = nconf->bgpid; conf->clusterid = nconf->clusterid; conf->as = nconf->as; @@ -2488,6 +2487,7 @@ session_dispatch_imsg(struct imsgbuf *ibuf, int idx, u_int *listener_cnt) case IMSG_CTL_KROUTE_ADDR: case IMSG_CTL_SHOW_NEXTHOP: case IMSG_CTL_SHOW_INTERFACE: + case IMSG_CTL_SHOW_FIB_TABLES: if (idx != PFD_PIPE_MAIN) fatalx("ctl kroute request not from parent"); control_imsg_relay(&imsg); @@ -2765,9 +2765,10 @@ session_up(struct peer *p) } int -imsg_compose_parent(int type, pid_t pid, void *data, u_int16_t datalen) +imsg_compose_parent(int type, u_int32_t peerid, pid_t pid, void *data, + u_int16_t datalen) { - return (imsg_compose(ibuf_main, type, 0, pid, -1, data, datalen)); + return (imsg_compose(ibuf_main, type, peerid, pid, -1, data, datalen)); } int diff --git a/usr.sbin/bgpd/session.h b/usr.sbin/bgpd/session.h index 2836e0ff23a..42229218760 100644 --- a/usr.sbin/bgpd/session.h +++ b/usr.sbin/bgpd/session.h @@ -1,4 +1,4 @@ -/* $OpenBSD: session.h,v 1.104 2009/12/31 15:34:02 claudio Exp $ */ +/* $OpenBSD: session.h,v 1.105 2010/05/03 13:09:38 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -232,7 +232,7 @@ void bgp_fsm(struct peer *, enum session_events); int session_neighbor_rrefresh(struct peer *p); struct peer *getpeerbyaddr(struct bgpd_addr *); struct peer *getpeerbydesc(const char *); -int imsg_compose_parent(int, pid_t, void *, u_int16_t); +int imsg_compose_parent(int, u_int32_t, pid_t, void *, u_int16_t); int imsg_compose_rde(int, pid_t, void *, u_int16_t); void session_stop(struct peer *, u_int8_t); |