summaryrefslogtreecommitdiffstats
path: root/contrib/bsnmp/snmp_mibII/mibII_route.c
diff options
context:
space:
mode:
authorharti <harti@FreeBSD.org>2005-10-04 14:41:06 +0000
committerharti <harti@FreeBSD.org>2005-10-04 14:41:06 +0000
commitefb2dfa1774240830b3f74b7fe4ab8050cc1cda0 (patch)
tree939b9a00cfa4d79510a088859c9352b689740218 /contrib/bsnmp/snmp_mibII/mibII_route.c
parent2b366eef52ee173d11c8c3b0570cd771e5c0044a (diff)
downloadFreeBSD-src-efb2dfa1774240830b3f74b7fe4ab8050cc1cda0.zip
FreeBSD-src-efb2dfa1774240830b3f74b7fe4ab8050cc1cda0.tar.gz
Virgin import of bsnmpd 1.11
Diffstat (limited to 'contrib/bsnmp/snmp_mibII/mibII_route.c')
-rw-r--r--contrib/bsnmp/snmp_mibII/mibII_route.c428
1 files changed, 321 insertions, 107 deletions
diff --git a/contrib/bsnmp/snmp_mibII/mibII_route.c b/contrib/bsnmp/snmp_mibII/mibII_route.c
index 9375be3..feb33c9 100644
--- a/contrib/bsnmp/snmp_mibII/mibII_route.c
+++ b/contrib/bsnmp/snmp_mibII/mibII_route.c
@@ -26,41 +26,218 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Begemot: bsnmp/snmp_mibII/mibII_route.c,v 1.6 2005/05/23 09:03:41 brandt_h Exp $
+ * $Begemot: bsnmp/snmp_mibII/mibII_route.c,v 1.7 2005/06/09 12:36:53 brandt_h Exp $
*
* Routing table
*/
+#include <sys/tree.h>
#include "mibII.h"
#include "mibII_oid.h"
struct sroute {
- TAILQ_ENTRY(sroute) link;
- struct asn_oid index;
- u_int ifindex;
- u_int type;
- u_int proto;
+ RB_ENTRY(sroute) link;
+ uint32_t ifindex;
+ uint8_t index[13];
+ uint8_t type;
+ uint8_t proto;
};
-static TAILQ_HEAD(, sroute) sroute_list = TAILQ_HEAD_INITIALIZER(sroute_list);
+RB_HEAD(sroutes, sroute) sroutes = RB_INITIALIZER(&sroutes);
+RB_PROTOTYPE(sroutes, sroute, link, sroute_compare);
+
+#define ROUTE_UPDATE_INTERVAL (100 * 60 * 10) /* 10 min */
static uint64_t route_tick;
static u_int route_total;
+/*
+ * Compare two routes
+ */
static int
-fetch_route(void)
+sroute_compare(struct sroute *s1, struct sroute *s2)
+{
+
+ return (memcmp(s1->index, s2->index, 13));
+}
+
+static void
+sroute_index_append(struct asn_oid *oid, u_int sub, const struct sroute *s)
+{
+ int i;
+
+ oid->len = sub + 13;
+ for (i = 0; i < 13; i++)
+ oid->subs[sub + i] = s->index[i];
+}
+
+#if 0
+static void
+sroute_print(const struct sroute *r)
+{
+ u_int i;
+
+ for (i = 0; i < 13 - 1; i++)
+ printf("%u.", r->index[i]);
+ printf("%u proto=%u type=%u", r->index[i], r->proto, r->type);
+}
+#endif
+
+/*
+ * process routing message
+ */
+void
+mib_sroute_process(struct rt_msghdr *rtm, struct sockaddr *gw,
+ struct sockaddr *dst, struct sockaddr *mask)
+{
+ struct sockaddr_in *in_dst, *in_gw;
+ struct in_addr in_mask;
+ struct mibif *ifp;
+ struct sroute key;
+ struct sroute *r, *r1;
+ in_addr_t ha;
+
+ if (dst == NULL || gw == NULL || dst->sa_family != AF_INET ||
+ gw->sa_family != AF_INET)
+ return;
+
+ in_dst = (struct sockaddr_in *)(void *)dst;
+ in_gw = (struct sockaddr_in *)(void *)gw;
+
+ if (rtm->rtm_flags & RTF_HOST)
+ in_mask.s_addr = 0xffffffff;
+ else if (mask == NULL || mask->sa_len == 0)
+ in_mask.s_addr = 0;
+ else
+ in_mask = ((struct sockaddr_in *)(void *)mask)->sin_addr;
+
+ /* build the index */
+ ha = ntohl(in_dst->sin_addr.s_addr);
+ key.index[0] = (ha >> 24) & 0xff;
+ key.index[1] = (ha >> 16) & 0xff;
+ key.index[2] = (ha >> 8) & 0xff;
+ key.index[3] = (ha >> 0) & 0xff;
+
+ ha = ntohl(in_mask.s_addr);
+ key.index[4] = (ha >> 24) & 0xff;
+ key.index[5] = (ha >> 16) & 0xff;
+ key.index[6] = (ha >> 8) & 0xff;
+ key.index[7] = (ha >> 0) & 0xff;
+
+ /* ToS */
+ key.index[8] = 0;
+
+ ha = ntohl(in_gw->sin_addr.s_addr);
+ key.index[9] = (ha >> 24) & 0xff;
+ key.index[10] = (ha >> 16) & 0xff;
+ key.index[11] = (ha >> 8) & 0xff;
+ key.index[12] = (ha >> 0) & 0xff;
+
+ if (rtm->rtm_type == RTM_DELETE) {
+ r = RB_FIND(sroutes, &sroutes, &key);
+ if (r == 0) {
+#ifdef DEBUG_ROUTE
+ syslog(LOG_WARNING, "%s: DELETE: %u.%u.%u.%u "
+ "%u.%u.%u.%u %u %u.%u.%u.%u not found", __func__,
+ key.index[0], key.index[1], key.index[2],
+ key.index[3], key.index[4], key.index[5],
+ key.index[6], key.index[7], key.index[8],
+ key.index[9], key.index[10], key.index[11],
+ key.index[12]);
+#endif
+ return;
+ }
+ RB_REMOVE(sroutes, &sroutes, r);
+ free(r);
+ route_total--;
+#ifdef DEBUG_ROUTE
+ printf("%s: DELETE: %u.%u.%u.%u "
+ "%u.%u.%u.%u %u %u.%u.%u.%u\n", __func__,
+ key.index[0], key.index[1], key.index[2],
+ key.index[3], key.index[4], key.index[5],
+ key.index[6], key.index[7], key.index[8],
+ key.index[9], key.index[10], key.index[11],
+ key.index[12]);
+#endif
+ return;
+ }
+
+ /* GET or ADD */
+ ifp = NULL;
+ if ((ifp = mib_find_if_sys(rtm->rtm_index)) == NULL) {
+ if (rtm->rtm_type == RTM_ADD) {
+ /* make it a get so the kernel fills the index */
+ mib_send_rtmsg(rtm, gw, dst, mask);
+ return;
+ }
+ mib_iflist_bad = 1;
+ }
+
+ if ((r = malloc(sizeof(*r))) == NULL) {
+ syslog(LOG_ERR, "%m");
+ return;
+ }
+
+ memcpy(r->index, key.index, sizeof(r->index));
+ r->ifindex = (ifp == NULL) ? 0 : ifp->index;
+
+ r->type = (rtm->rtm_flags & RTF_LLINFO) ? 3 :
+ (rtm->rtm_flags & RTF_REJECT) ? 2 : 4;
+
+ /* cannot really know, what protocol it runs */
+ r->proto = (rtm->rtm_flags & RTF_LOCAL) ? 2 :
+ (rtm->rtm_flags & RTF_STATIC) ? 3 :
+ (rtm->rtm_flags & RTF_DYNAMIC) ? 4 : 10;
+
+ r1 = RB_INSERT(sroutes, &sroutes, r);
+ if (r1 != NULL) {
+#ifdef DEBUG_ROUTE
+ syslog(LOG_WARNING, "%s: %u.%u.%u.%u "
+ "%u.%u.%u.%u %u %u.%u.%u.%u duplicate route", __func__,
+ key.index[0], key.index[1], key.index[2],
+ key.index[3], key.index[4], key.index[5],
+ key.index[6], key.index[7], key.index[8],
+ key.index[9], key.index[10], key.index[11],
+ key.index[12]);
+#endif
+ r1->ifindex = r->ifindex;
+ r1->type = r->type;
+ r1->proto = r->proto;
+ free(r);
+ return;
+ }
+
+ route_total++;
+#ifdef DEBUG_ROUTE
+ printf("%s: ADD/GET: %u.%u.%u.%u "
+ "%u.%u.%u.%u %u %u.%u.%u.%u\n", __func__,
+ key.index[0], key.index[1], key.index[2],
+ key.index[3], key.index[4], key.index[5],
+ key.index[6], key.index[7], key.index[8],
+ key.index[9], key.index[10], key.index[11],
+ key.index[12]);
+#endif
+}
+
+int
+mib_fetch_route(void)
{
u_char *rtab, *next;
size_t len;
- struct sroute *r;
+ struct sroute *r, *r1;
struct rt_msghdr *rtm;
struct sockaddr *addrs[RTAX_MAX];
- struct sockaddr_in *sa, *gw;
- struct in_addr mask, nhop;
- in_addr_t ha;
- struct mibif *ifp;
- while ((r = TAILQ_FIRST(&sroute_list)) != NULL) {
- TAILQ_REMOVE(&sroute_list, r, link);
+ if (route_tick != 0 && route_tick + ROUTE_UPDATE_INTERVAL > this_tick)
+ return (0);
+
+ /*
+ * Remove all routes
+ */
+ r = RB_MIN(sroutes, &sroutes);
+ while (r != NULL) {
+ r1 = RB_NEXT(sroutes, &sroutes, r);
+ RB_REMOVE(sroutes, &sroutes, r);
free(r);
+ r = r1;
}
route_total = 0;
@@ -75,81 +252,118 @@ fetch_route(void)
continue;
mib_extract_addrs(rtm->rtm_addrs, (u_char *)(rtm + 1), addrs);
- if (addrs[RTAX_DST] == NULL || addrs[RTAX_GATEWAY] == NULL ||
- addrs[RTAX_DST]->sa_family != AF_INET)
- continue;
-
- sa = (struct sockaddr_in *)(void *)addrs[RTAX_DST];
-
- if (rtm->rtm_flags & RTF_HOST) {
- mask.s_addr = 0xffffffff;
- } else {
- if (addrs[RTAX_NETMASK] == NULL ||
- addrs[RTAX_NETMASK]->sa_len == 0)
- mask.s_addr = 0;
- else
- mask = ((struct sockaddr_in *)(void *)
- addrs[RTAX_NETMASK])->sin_addr;
- }
- if (addrs[RTAX_GATEWAY] == NULL) {
- nhop.s_addr = 0;
- } else if (rtm->rtm_flags & RTF_LLINFO) {
- nhop = sa->sin_addr;
- } else {
- gw = (struct sockaddr_in *)(void *)addrs[RTAX_GATEWAY];
- if (gw->sin_family != AF_INET)
- continue;
- nhop = gw->sin_addr;
- }
- if ((ifp = mib_find_if_sys(rtm->rtm_index)) == NULL) {
- mib_iflist_bad = 1;
- continue;
- }
-
- if ((r = malloc(sizeof(*r))) == NULL) {
- syslog(LOG_ERR, "%m");
- continue;
- }
-
- route_total++;
+
+ mib_sroute_process(rtm, addrs[RTAX_GATEWAY], addrs[RTAX_DST],
+ addrs[RTAX_NETMASK]);
+ }
- r->index.len = 13;
- ha = ntohl(sa->sin_addr.s_addr);
- r->index.subs[0] = (ha >> 24) & 0xff;
- r->index.subs[1] = (ha >> 16) & 0xff;
- r->index.subs[2] = (ha >> 8) & 0xff;
- r->index.subs[3] = (ha >> 0) & 0xff;
- ha = ntohl(mask.s_addr);
- r->index.subs[4] = (ha >> 24) & 0xff;
- r->index.subs[5] = (ha >> 16) & 0xff;
- r->index.subs[6] = (ha >> 8) & 0xff;
- r->index.subs[7] = (ha >> 0) & 0xff;
+#if 0
+ u_int n = 0;
+ r = RB_MIN(sroutes, &sroutes);
+ while (r != NULL) {
+ printf("%u: ", n++);
+ sroute_print(r);
+ printf("\n");
+ r = RB_NEXT(sroutes, &sroutes, r);
+ }
+#endif
+ free(rtab);
+ route_tick = get_ticks();
- r->index.subs[8] = 0;
+ return (0);
+}
- ha = ntohl(nhop.s_addr);
- r->index.subs[9] = (ha >> 24) & 0xff;
- r->index.subs[10] = (ha >> 16) & 0xff;
- r->index.subs[11] = (ha >> 8) & 0xff;
- r->index.subs[12] = (ha >> 0) & 0xff;
+/**
+ * Find a route in the table.
+ */
+static struct sroute *
+sroute_get(const struct asn_oid *oid, u_int sub)
+{
+ struct sroute key;
+ int i;
+
+ if (oid->len - sub != 13)
+ return (NULL);
+ for (i = 0; i < 13; i++)
+ key.index[i] = oid->subs[sub + i];
+ return (RB_FIND(sroutes, &sroutes, &key));
+}
- r->ifindex = ifp->index;
+/**
+ * Find next route in the table. There is no such RB_ macro, so must
+ * dig into the innards of the RB stuff.
+ */
+static struct sroute *
+sroute_getnext(struct asn_oid *oid, u_int sub)
+{
+ u_int i;
+ int comp;
+ struct sroute key;
+ struct sroute *best;
+ struct sroute *s;
+
+ /*
+ * We now, that the OID is at least the tableEntry OID. If it is,
+ * the user wants the first route.
+ */
+ if (oid->len == sub)
+ return (RB_MIN(sroutes, &sroutes));
+
+ /*
+ * This is also true for any index that consists of zeros and is
+ * shorter than the full index.
+ */
+ if (oid->len < sub + 13) {
+ for (i = sub; i < oid->len; i++)
+ if (oid->subs[i] != 0)
+ break;
+ if (i == oid->len)
+ return (RB_MIN(sroutes, &sroutes));
+
+ /*
+ * Now if the index is too short, we fill it with zeros and then
+ * subtract one from the index. We can do this, because we now,
+ * that there is at least one index element that is not zero.
+ */
+ for (i = oid->len; i < sub + 13; i++)
+ oid->subs[i] = 0;
+
+ for (i = sub + 13 - 1; i >= sub; i--) {
+ if (oid->subs[i] != 0) {
+ oid->subs[i]--;
+ break;
+ }
+ oid->subs[i] = ASN_MAXID;
+ }
+ oid->len = sub + 13;
+ }
- r->type = (rtm->rtm_flags & RTF_LLINFO) ? 3 :
- (rtm->rtm_flags & RTF_REJECT) ? 2 : 4;
+ /* build the index */
+ for (i = sub; i < sub + 13; i++)
+ key.index[i - sub] = oid->subs[i];
- /* cannot really know, what protocol it runs */
- r->proto = (rtm->rtm_flags & RTF_LOCAL) ? 2 :
- (rtm->rtm_flags & RTF_STATIC) ? 3 :
- (rtm->rtm_flags & RTF_DYNAMIC) ? 4 : 10;
+ /* now find the element */
+ best = NULL;
+ s = RB_ROOT(&sroutes);
- INSERT_OBJECT_OID(r, &sroute_list);
+ while (s != NULL) {
+ comp = sroute_compare(&key, s);
+ if (comp >= 0) {
+ /* The current element is smaller than what we search.
+ * Forget about it and move to the right subtree. */
+ s = RB_RIGHT(s, link);
+ continue;
+ }
+ /* the current element is larger than what we search.
+ * forget about the right subtree (its even larger), but
+ * the current element may be what we need. */
+ if (best == NULL || sroute_compare(s, best) < 0)
+ /* this one's better */
+ best = s;
+
+ s = RB_LEFT(s, link);
}
-
- free(rtab);
- route_tick = get_ticks();
-
- return (0);
+ return (best);
}
/*
@@ -159,28 +373,27 @@ int
op_route_table(struct snmp_context *ctx __unused, struct snmp_value *value,
u_int sub, u_int iidx __unused, enum snmp_op op)
{
- static struct sroute *r;
+ struct sroute *r;
- if (route_tick < this_tick)
- if (fetch_route() == -1)
- return (SNMP_ERR_GENERR);
+ if (mib_fetch_route() == -1)
+ return (SNMP_ERR_GENERR);
switch (op) {
case SNMP_OP_GETNEXT:
- if ((r = NEXT_OBJECT_OID(&sroute_list, &value->var, sub)) == NULL)
+ if ((r = sroute_getnext(&value->var, sub)) == NULL)
return (SNMP_ERR_NOSUCHNAME);
- index_append(&value->var, sub, &r->index);
+ sroute_index_append(&value->var, sub, r);
break;
case SNMP_OP_GET:
- if ((r = FIND_OBJECT_OID(&sroute_list, &value->var, sub)) == NULL)
+ if ((r = sroute_get(&value->var, sub)) == NULL)
return (SNMP_ERR_NOSUCHNAME);
break;
case SNMP_OP_SET:
- if ((r = FIND_OBJECT_OID(&sroute_list, &value->var, sub)) == NULL)
- return (SNMP_ERR_NO_CREATION);
+ if ((r = sroute_get(&value->var, sub)) == NULL)
+ return (SNMP_ERR_NOSUCHNAME);
return (SNMP_ERR_NOT_WRITEABLE);
case SNMP_OP_ROLLBACK:
@@ -194,28 +407,28 @@ op_route_table(struct snmp_context *ctx __unused, struct snmp_value *value,
switch (value->var.subs[sub - 1]) {
case LEAF_ipCidrRouteDest:
- value->v.ipaddress[0] = r->index.subs[0];
- value->v.ipaddress[1] = r->index.subs[1];
- value->v.ipaddress[2] = r->index.subs[2];
- value->v.ipaddress[3] = r->index.subs[3];
+ value->v.ipaddress[0] = r->index[0];
+ value->v.ipaddress[1] = r->index[1];
+ value->v.ipaddress[2] = r->index[2];
+ value->v.ipaddress[3] = r->index[3];
break;
case LEAF_ipCidrRouteMask:
- value->v.ipaddress[0] = r->index.subs[4];
- value->v.ipaddress[1] = r->index.subs[5];
- value->v.ipaddress[2] = r->index.subs[6];
- value->v.ipaddress[3] = r->index.subs[7];
+ value->v.ipaddress[0] = r->index[4];
+ value->v.ipaddress[1] = r->index[5];
+ value->v.ipaddress[2] = r->index[6];
+ value->v.ipaddress[3] = r->index[7];
break;
case LEAF_ipCidrRouteTos:
- value->v.integer = r->index.subs[8];
+ value->v.integer = r->index[8];
break;
case LEAF_ipCidrRouteNextHop:
- value->v.ipaddress[0] = r->index.subs[9];
- value->v.ipaddress[1] = r->index.subs[10];
- value->v.ipaddress[2] = r->index.subs[11];
- value->v.ipaddress[3] = r->index.subs[12];
+ value->v.ipaddress[0] = r->index[9];
+ value->v.ipaddress[1] = r->index[10];
+ value->v.ipaddress[2] = r->index[11];
+ value->v.ipaddress[3] = r->index[12];
break;
case LEAF_ipCidrRouteIfIndex:
@@ -280,9 +493,8 @@ op_route(struct snmp_context *ctx __unused, struct snmp_value *value,
abort();
}
- if (route_tick < this_tick)
- if (fetch_route() == -1)
- return (SNMP_ERR_GENERR);
+ if (mib_fetch_route() == -1)
+ return (SNMP_ERR_GENERR);
switch (value->var.subs[sub - 1]) {
@@ -293,3 +505,5 @@ op_route(struct snmp_context *ctx __unused, struct snmp_value *value,
}
return (SNMP_ERR_NOERROR);
}
+
+RB_GENERATE(sroutes, sroute, link, sroute_compare);
OpenPOWER on IntegriCloud