On Mon, Apr 28, 2014 at 14:20 +0200, Mike Belopuhov wrote:
> This adds ktable code from bgpd to fetch, store and perform lookups
> in multiple routing tables. Currently it doesn't do anything useful
> but it's a prerequisite for any future work in this direction.
>
> OK to get this in?
>
Any objections?
> diff --git usr.sbin/snmpd/kroute.c usr.sbin/snmpd/kroute.c
> index e157b25..e19f924 100644
> --- usr.sbin/snmpd/kroute.c
> +++ usr.sbin/snmpd/kroute.c
> @@ -45,10 +45,13 @@
>
> #include "snmpd.h"
>
> extern struct snmpd *env;
>
> +struct ktable **krt;
> +u_int krt_size;
> +
> struct {
> struct event ks_ev;
> u_long ks_iflastchange;
> u_long ks_nroutes; /* 4 billions enough? */
> int ks_fd;
> @@ -77,24 +80,32 @@ struct kif_node {
>
> int kroute_compare(struct kroute_node *, struct kroute_node *);
> int kroute6_compare(struct kroute6_node *, struct kroute6_node *);
> int kif_compare(struct kif_node *, struct kif_node *);
>
> -struct kroute_node *kroute_find(in_addr_t, u_int8_t, u_int8_t);
> +void ktable_init(void);
> +int ktable_new(u_int, u_int);
> +void ktable_free(u_int);
> +int ktable_exists(u_int, u_int *);
> +struct ktable *ktable_get(u_int);
> +int ktable_update(u_int);
> +
> +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 kif_arp *karp_find(struct sockaddr *, u_short);
> int karp_insert(struct kif_node *, struct kif_arp *);
> int karp_remove(struct kif_node *, struct kif_arp *);
>
> @@ -121,23 +132,21 @@ void if_newaddr(u_short, struct sockaddr *,
> struct sockaddr *,
> struct sockaddr *);
> void if_deladdr(u_short, struct sockaddr *, struct sockaddr *,
> struct sockaddr *);
> void if_announce(void *);
>
> -int fetchtable(void);
> +int fetchtable(struct ktable *);
> int fetchifs(u_short);
> -int fetcharp(void);
> +int fetcharp(struct ktable *);
> void dispatch_rtmsg(int, short, void *);
> int rtmsg_process(char *, int);
> -int dispatch_rtmsg_addr(struct rt_msghdr *,
> +int dispatch_rtmsg_addr(struct ktable *, struct rt_msghdr *,
> struct sockaddr *[RTAX_MAX]);
>
> -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(kif_tree, kif_node) kit;
> RB_PROTOTYPE(kif_tree, kif_node, entry, kif_compare)
> @@ -149,10 +158,11 @@ RB_GENERATE(ka_tree, kif_addr, node, ka_compare)
>
> void
> kr_init(void)
> {
> int opt = 0, rcvbuf, default_rcvbuf;
> + unsigned int tid = RTABLE_ANY;
> socklen_t optlen;
>
> if ((kr_state.ks_ifd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
> fatal("kr_init: ioctl socket");
>
> @@ -179,31 +189,166 @@ kr_init(void)
> setsockopt(kr_state.ks_fd, SOL_SOCKET, SO_RCVBUF,
> &rcvbuf, sizeof(rcvbuf)) == -1 && errno == ENOBUFS;
> rcvbuf /= 2)
> ; /* nothing */
>
> - RB_INIT(&krt);
> - RB_INIT(&krt6);
> + if (setsockopt(kr_state.ks_fd, AF_ROUTE, ROUTE_TABLEFILTER, &tid,
> + sizeof(tid)) == -1)
> + log_warn("kr_init: setsockopt AF_ROUTE ROUTE_TABLEFILTER");
> +
> RB_INIT(&kit);
> RB_INIT(&kat);
>
> if (fetchifs(0) == -1)
> fatalx("kr_init fetchifs");
> - if (fetchtable() == -1)
> - fatalx("kr_init fetchtable");
> - if (fetcharp() == -1)
> - fatalx("kr_init fetcharp");
> +
> + ktable_init();
>
> event_set(&kr_state.ks_ev, kr_state.ks_fd, EV_READ | EV_PERSIST,
> dispatch_rtmsg, NULL);
> event_add(&kr_state.ks_ev, NULL);
> }
>
> void
> +ktable_init(void)
> +{
> + u_int i;
> +
> + for (i = 0; i < RT_TABLEID_MAX; i++)
> + if (ktable_exists(i, NULL))
> + ktable_update(i);
> +}
> +
> +int
> +ktable_new(u_int rtableid, u_int rdomid)
> +{
> + 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.");
> +
> + /* allocate new element */
> + kt = krt[rtableid] = calloc(1, sizeof(struct ktable));
> + if (kt == NULL) {
> + log_warn("ktable_new");
> + return (-1);
> + }
> +
> + /* initialize structure ... */
> + RB_INIT(&kt->krt);
> + RB_INIT(&kt->krt6);
> + kt->rtableid = rtableid;
> + kt->rdomain = rdomid;
> +
> + /* ... and load it */
> + if (fetchtable(kt) == -1)
> + return (-1);
> + /* load arp information */
> + if (fetcharp(kt) == -1)
> + return (-1);
> +
> + log_debug("new ktable for rtableid %d", rtableid);
> + return (0);
> +}
> +
> +void
> +ktable_free(u_int rtableid)
> +{
> + struct ktable *kt;
> +
> + if ((kt = ktable_get(rtableid)) == NULL)
> + return;
> +
> + log_debug("freeing ktable rtableid %u", kt->rtableid);
> + 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(u_int rtableid)
> +{
> + struct ktable *kt;
> + u_int rdomid;
> +
> + if (!ktable_exists(rtableid, &rdomid))
> + fatalx("King Bula lost a table"); /* may not happen */
> +
> + if (rdomid != rtableid) {
> + if (ktable_get(rdomid) == NULL &&
> + ktable_new(rdomid, rdomid) != 0)
> + return (-1);
> + }
> +
> + kt = ktable_get(rtableid);
> + if (kt == NULL) {
> + if (ktable_new(rtableid, rdomid))
> + return (-1);
> + }
> + return (0);
> +}
> +
> +int
> +ktable_exists(u_int rtableid, u_int *rdomid)
> +{
> + size_t len;
> + struct rt_tableinfo info;
> + int mib[6];
> +
> + 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);
> +}
> +
> +void
> kr_shutdown(void)
> {
> - kroute_clear();
> + u_int i;
> +
> + for (i = krt_size; i > 0; i--)
> + ktable_free(i - 1);
> kif_clear();
> }
>
> u_int
> kr_ifnumber(void)
> @@ -301,28 +446,29 @@ ka_compare(struct kif_addr *a, struct kif_addr *b)
> return (memcmp(&a->addr.sa, &b->addr.sa, a->addr.sa.sa_len));
> }
>
> /* tree management */
> 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;
>
> s.r.prefix.s_addr = prefix;
> 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);
> }
>
> @@ -345,15 +491,15 @@ kroute_matchgw(struct kroute_node *kr, struct
> sockaddr_in *sa_in)
>
> return (NULL);
> }
>
> int
> -kroute_insert(struct kroute_node *kr)
> +kroute_insert(struct ktable *kt, struct kroute_node *kr)
> {
> struct kroute_node *krm;
>
> - 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;
> krm->next = kr;
> kr->next = NULL; /* to be sure */
> @@ -362,29 +508,30 @@ kroute_insert(struct kroute_node *kr)
> kr_state.ks_nroutes++;
> return (0);
> }
>
> int
> -kroute_remove(struct kroute_node *kr)
> +kroute_remove(struct ktable *kt, struct kroute_node *kr)
> {
> struct kroute_node *krm;
>
> - 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);
> }
>
> 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);
> }
> }
> @@ -405,37 +552,38 @@ kroute_remove(struct kroute_node *kr)
> free(kr);
> return (0);
> }
>
> 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;
>
> memcpy(&s.r.prefix, prefix, sizeof(struct in6_addr));
> 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);
> }
>
> @@ -458,15 +606,15 @@ kroute6_matchgw(struct kroute6_node *kr, struct
> sockaddr_in6 *sa_in6)
>
> return (NULL);
> }
>
> int
> -kroute6_insert(struct kroute6_node *kr)
> +kroute6_insert(struct ktable *kt, struct kroute6_node *kr)
> {
> struct kroute6_node *krm;
>
> - 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;
> krm->next = kr;
> kr->next = NULL; /* to be sure */
> @@ -475,29 +623,30 @@ kroute6_insert(struct kroute6_node *kr)
> kr_state.ks_nroutes++;
> return (0);
> }
>
> int
> -kroute6_remove(struct kroute6_node *kr)
> +kroute6_remove(struct ktable *kt, struct kroute6_node *kr)
> {
> struct kroute6_node *krm;
>
> - 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);
> }
>
> 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);
> return (-1);
> }
> @@ -519,16 +668,16 @@ kroute6_remove(struct kroute6_node *kr)
> free(kr);
> return (0);
> }
>
> 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);
> }
>
> static inline int
> karp_compare(struct kif_arp *a, struct kif_arp *b)
> {
> @@ -1021,22 +1170,20 @@ if_announce(void *msg)
> switch (ifan->ifan_what) {
> case IFAN_ARRIVAL:
> kif = kif_insert(ifan->ifan_index);
> strlcpy(kif->k.if_name, ifan->ifan_name,
> sizeof(kif->k.if_name));
> - /* Update the ARP table */
> - fetcharp();
> break;
> case IFAN_DEPARTURE:
> kif = kif_find(ifan->ifan_index);
> kif_remove(kif);
> break;
> }
> }
>
> int
> -fetchtable(void)
> +fetchtable(struct ktable *kt)
> {
> int mib[7];
> size_t len;
> char *buf;
> int rv;
> @@ -1045,22 +1192,27 @@ fetchtable(void)
> mib[1] = AF_ROUTE;
> mib[2] = 0;
> mib[3] = AF_INET;
> mib[4] = NET_RT_DUMP;
> mib[5] = 0;
> - mib[6] = 0; /* rtableid */
> + mib[6] = kt->rtableid;
>
> if (sysctl(mib, 7, NULL, &len, NULL, 0) == -1) {
> + if (kt->rtableid != 0 && errno == EINVAL)
> + /* table nonexistent */
> + return (0);
> log_warn("sysctl");
> return (-1);
> }
> + if (len == 0)
> + return (0);
> if ((buf = malloc(len)) == NULL) {
> log_warn("fetchtable");
> return (-1);
> }
> if (sysctl(mib, 7, buf, &len, NULL, 0) == -1) {
> - log_warn("sysctl");
> + log_warn("sysctl2");
> free(buf);
> return (-1);
> }
>
> rv = rtmsg_process(buf, len);
> @@ -1103,11 +1255,11 @@ fetchifs(u_short if_index)
>
> return (rv);
> }
>
> int
> -fetcharp(void)
> +fetcharp(struct ktable *kt)
> {
> size_t len;
> int mib[7];
> char *buf;
> int rv;
> @@ -1116,11 +1268,11 @@ fetcharp(void)
> mib[1] = AF_ROUTE;
> mib[2] = 0;
> mib[3] = AF_INET;
> mib[4] = NET_RT_FLAGS;
> mib[5] = RTF_LLINFO;
> - mib[6] = 0;
> + mib[6] = kt->rtableid;
>
> if (sysctl(mib, 7, NULL, &len, NULL, 0) == -1) {
> log_warn("sysctl");
> return (-1);
> }
> @@ -1164,10 +1316,11 @@ dispatch_rtmsg(int fd, short event, void *arg)
> }
>
> int
> rtmsg_process(char *buf, int len)
> {
> + struct ktable *kt;
> struct rt_msghdr *rtm;
> struct if_msghdr ifm;
> struct ifa_msghdr *ifam;
> struct sockaddr *sa, *rti_info[RTAX_MAX];
> int offset;
> @@ -1189,11 +1342,14 @@ rtmsg_process(char *buf, int len)
> case RTM_DELETE:
> case RTM_RESOLVE:
> if (rtm->rtm_errno) /* failed attempts */
> continue;
>
> - if (dispatch_rtmsg_addr(rtm, rti_info) == -1)
> + if ((kt = ktable_get(rtm->rtm_tableid)) == NULL)
> + continue;
> +
> + if (dispatch_rtmsg_addr(kt, rtm, rti_info) == -1)
> return (-1);
> break;
> case RTM_IFINFO:
> memcpy(&ifm, next, sizeof(ifm));
> if_change(ifm.ifm_index, ifm.ifm_flags, &ifm.ifm_data,
> @@ -1228,11 +1384,12 @@ rtmsg_process(char *buf, int len)
>
> return (offset);
> }
>
> int
> -dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct sockaddr
> *rti_info[RTAX_MAX])
> +dispatch_rtmsg_addr(struct ktable *kt, struct rt_msghdr *rtm,
> + struct sockaddr *rti_info[RTAX_MAX])
> {
> struct sockaddr *sa, *psa;
> struct sockaddr_in *sa_in, *psa_in = NULL;
> struct sockaddr_in6 *sa_in6, *psa_in6 = NULL;
> struct sockaddr_dl *sa_dl;
> @@ -1319,11 +1476,11 @@ dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct
> sockaddr *rti_info[RTAX_MAX])
> /* Continue to the route section below */
> }
> switch (psa->sa_family) {
> case AF_INET:
> sa_in = (struct sockaddr_in *)sa;
> - if ((kr = kroute_find(psa_in->sin_addr.s_addr,
> + if ((kr = kroute_find(kt, psa_in->sin_addr.s_addr,
> prefixlen, prio)) == NULL)
> return (0);
>
> if (mpath)
> /* get the correct route */
> @@ -1331,17 +1488,17 @@ dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct
> sockaddr *rti_info[RTAX_MAX])
> log_warnx("dispatch_rtmsg[delete] "
> "mpath route not found");
> return (0);
> }
>
> - if (kroute_remove(kr) == -1)
> + if (kroute_remove(kt, kr) == -1)
> return (-1);
> break;
> case AF_INET6:
> sa_in6 = (struct sockaddr_in6 *)sa;
> - if ((kr6 = kroute6_find(&psa_in6->sin6_addr, prefixlen,
> - prio)) == NULL)
> + if ((kr6 = kroute6_find(kt, &psa_in6->sin6_addr,
> + prefixlen, prio)) == NULL)
> return (0);
>
> if (mpath)
> /* get the correct route */
> if ((kr6 = kroute6_matchgw(kr6, sa_in6)) ==
> @@ -1349,11 +1506,11 @@ dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct
> sockaddr *rti_info[RTAX_MAX])
> log_warnx("dispatch_rtmsg[delete] "
> "IPv6 mpath route not found");
> return (0);
> }
>
> - if (kroute6_remove(kr6) == -1)
> + if (kroute6_remove(kt, kr6) == -1)
> return (-1);
> break;
> }
> return (0);
> }
> @@ -1398,11 +1555,11 @@ dispatch_rtmsg_addr(struct rt_msghdr *rtm, struct
> sockaddr *rti_info[RTAX_MAX])
> }
>
> switch (psa->sa_family) {
> case AF_INET:
> sa_in = (struct sockaddr_in *)sa;
> - if ((kr = kroute_find(psa_in->sin_addr.s_addr, prefixlen,
> + if ((kr = kroute_find(kt, psa_in->sin_addr.s_addr, prefixlen,
> prio)) != NULL) {
> /* get the correct route */
> if (mpath && rtm->rtm_type == RTM_CHANGE &&
> (kr = kroute_matchgw(kr, sa_in)) == NULL) {
> log_warnx("dispatch_rtmsg[change] "
> @@ -1435,16 +1592,16 @@ add4:
> kr->r.flags = flags;
> kr->r.if_index = ifindex;
> kr->r.ticks = smi_getticks();
> kr->r.priority = prio;
>
> - kroute_insert(kr);
> + kroute_insert(kt, kr);
> }
> break;
> case AF_INET6:
> sa_in6 = (struct sockaddr_in6 *)sa;
> - if ((kr6 = kroute6_find(&psa_in6->sin6_addr, prefixlen,
> + if ((kr6 = kroute6_find(kt, &psa_in6->sin6_addr, prefixlen,
> prio)) != NULL) {
> /* get the correct route */
> if (mpath && rtm->rtm_type == RTM_CHANGE &&
> (kr6 = kroute6_matchgw(kr6, sa_in6)) ==
> NULL) {
> @@ -1485,11 +1642,11 @@ add6:
> kr6->r.flags = flags;
> kr6->r.if_index = ifindex;
> kr6->r.ticks = smi_getticks();
> kr6->r.priority = prio;
>
> - kroute6_insert(kr6);
> + kroute6_insert(kt, kr6);
> }
> break;
> }
>
> return (0);
> @@ -1497,23 +1654,29 @@ add6:
>
> struct kroute *
> kroute_first(void)
> {
> struct kroute_node *kn;
> + struct ktable *kt;
>
> - kn = RB_MIN(kroute_tree, &krt);
> + if ((kt = ktable_get(0)) == NULL)
> + return (NULL);
> + kn = RB_MIN(kroute_tree, &kt->krt);
> return (&kn->r);
> }
>
> struct kroute *
> kroute_getaddr(in_addr_t prefix, u_int8_t prefixlen, u_int8_t prio, int next)
> {
> struct kroute_node *kn;
> + struct ktable *kt;
>
> - kn = kroute_find(prefix, prefixlen, prio);
> + if ((kt = ktable_get(0)) == NULL)
> + return (NULL);
> + kn = kroute_find(kt, prefix, prefixlen, prio);
> if (kn != NULL && next)
> - kn = RB_NEXT(kroute_tree, &krt, kn);
> + kn = RB_NEXT(kroute_tree, &kt->krt, kn);
> if (kn != NULL)
> return (&kn->r);
> else
> return (NULL);
> }
> diff --git usr.sbin/snmpd/snmpd.h usr.sbin/snmpd/snmpd.h
> index 048ef79..61bc749 100644
> --- usr.sbin/snmpd/snmpd.h
> +++ usr.sbin/snmpd/snmpd.h
> @@ -186,10 +186,22 @@ extern struct ctl_connlist ctl_conns;
>
> /*
> * kroute
> */
>
> +struct kroute_node;
> +struct kroute6_node;
> +RB_HEAD(kroute_tree, kroute_node);
> +RB_HEAD(kroute6_tree, kroute6_node);
> +
> +struct ktable {
> + struct kroute_tree krt;
> + struct kroute6_tree krt6;
> + u_int rtableid;
> + u_int rdomain;
> +};
> +
> union kaddr {
> struct sockaddr sa;
> struct sockaddr_in sin;
> struct sockaddr_in6 sin6;
> struct sockaddr_dl sdl;