summaryrefslogtreecommitdiff
path: root/sys/net/rtable.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/net/rtable.c')
-rw-r--r--sys/net/rtable.c121
1 files changed, 89 insertions, 32 deletions
diff --git a/sys/net/rtable.c b/sys/net/rtable.c
index 2cd58309cb0..d1b18eebd9d 100644
--- a/sys/net/rtable.c
+++ b/sys/net/rtable.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rtable.c,v 1.6 2015/09/12 09:22:29 mpi Exp $ */
+/* $OpenBSD: rtable.c,v 1.7 2015/09/28 08:36:24 mpi Exp $ */
/*
* Copyright (c) 2014-2015 Martin Pieuchot
@@ -39,11 +39,14 @@ rtable_attach(void **head, int off)
{
int rv;
-#ifndef SMALL_KERNEL
- rv = rn_mpath_inithead(head, off);
-#else
rv = rn_inithead(head, off);
-#endif
+
+#ifndef SMALL_KERNEL
+ if (rv == 1) {
+ struct radix_node_head *rnh = (struct radix_node_head *)*head;
+ rnh->rnh_multipath = 1;
+ }
+#endif /* SMALL_KERNEL */
return (rv);
}
@@ -206,10 +209,34 @@ rtable_mpath_conflict(unsigned int rtableid, struct sockaddr *dst,
return (rt_mpath_conflict(rnh, dst, mask, gateway, prio, mpathok));
}
+/* Gateway selection by Hash-Threshold (RFC 2992) */
struct rtentry *
-rtable_mpath_select(struct rtentry *rt, uint32_t *src)
+rtable_mpath_select(struct rtentry *rt, uint32_t hash)
{
- return (rn_mpath_select(rt, src));
+ struct rtentry *mrt = rt;
+ int npaths, threshold;
+
+ npaths = 1;
+ while ((mrt = rt_mpath_next(mrt)) != NULL)
+ npaths++;
+
+ threshold = (0xffff / npaths) + 1;
+
+ mrt = rt;
+ while (hash > threshold && mrt != NULL) {
+ /* stay within the multipath routes */
+ mrt = rt_mpath_next(mrt);
+ hash -= threshold;
+ }
+
+ /* if gw selection fails, use the first match (default) */
+ if (mrt != NULL) {
+ rtref(mrt);
+ rtfree(rt);
+ rt = mrt;
+ }
+
+ return (rt);
}
void
@@ -391,27 +418,13 @@ rtable_insert(unsigned int rtableid, struct sockaddr *dst,
rt->rt_mask = msk;
}
-#ifndef SMALL_KERNEL
- if ((mrt = LIST_FIRST(&an->an_rtlist)) != NULL) {
- /*
- * Select the order of the MPATH routes.
- */
- while (LIST_NEXT(mrt, rt_next) != NULL) {
- if (mrt->rt_priority > prio)
- break;
- mrt = LIST_NEXT(mrt, rt_next);
- }
-
- if (mrt->rt_priority > prio)
- LIST_INSERT_BEFORE(mrt, rt, rt_next);
- else
- LIST_INSERT_AFTER(mrt, rt, rt_next);
+ LIST_INSERT_HEAD(&an->an_rtlist, rt, rt_next);
- return (0);
- }
+#ifndef SMALL_KERNEL
+ /* Put newly inserted entry at the right place. */
+ rtable_mpath_reprio(rt, rt->rt_priority);
#endif /* SMALL_KERNEL */
- LIST_INSERT_HEAD(&an->an_rtlist, rt, rt_next);
return (0);
}
@@ -602,21 +615,65 @@ rtable_mpath_conflict(unsigned int rtableid, struct sockaddr *dst,
return (0);
}
+/* Gateway selection by Hash-Threshold (RFC 2992) */
struct rtentry *
-rtable_mpath_select(struct rtentry *rt, uint32_t *src)
+rtable_mpath_select(struct rtentry *rt, uint32_t hash)
{
struct art_node *an = rt->rt_node;
+ struct rtentry *mrt;
+ int npaths, threshold;
- /*
- * XXX consider using ``src'' (8
- */
- return (LIST_FIRST(&an->an_rtlist));
+ npaths = 0;
+ LIST_FOREACH(mrt, &an->an_rtlist, rt_next) {
+ /* Only count nexthops with the same priority. */
+ if (mrt->rt_priority == rt->rt_priority)
+ npaths++;
+ }
+
+ threshold = (0xffff / npaths) + 1;
+
+ mrt = LIST_FIRST(&an->an_rtlist);
+ while (hash > threshold && mrt != NULL) {
+ if (mrt->rt_priority == rt->rt_priority)
+ hash -= threshold;
+ mrt = LIST_NEXT(mrt, rt_next);
+ }
+
+ if (mrt != NULL) {
+ rtref(mrt);
+ rtfree(rt);
+ rt = mrt;
+ }
+
+ return (rt);
}
void
-rtable_mpath_reprio(struct rtentry *rt, uint8_t newprio)
+rtable_mpath_reprio(struct rtentry *rt, uint8_t prio)
{
- /* XXX */
+ struct art_node *an = rt->rt_node;
+ struct rtentry *mrt;
+
+ LIST_REMOVE(rt, rt_next);
+ rt->rt_priority = prio;
+
+ if ((mrt = LIST_FIRST(&an->an_rtlist)) != NULL) {
+ /*
+ * Select the order of the MPATH routes.
+ */
+ while (LIST_NEXT(mrt, rt_next) != NULL) {
+ if (mrt->rt_priority > prio)
+ break;
+ mrt = LIST_NEXT(mrt, rt_next);
+ }
+
+ if (mrt->rt_priority > prio)
+ LIST_INSERT_BEFORE(mrt, rt, rt_next);
+ else
+ LIST_INSERT_AFTER(mrt, rt, rt_next);
+ } else {
+ LIST_INSERT_HEAD(&an->an_rtlist, rt, rt_next);
+ }
}
#endif /* SMALL_KERNEL */