summaryrefslogtreecommitdiffstats
path: root/sys/net
diff options
context:
space:
mode:
authorqingli <qingli@FreeBSD.org>2009-10-01 20:32:29 +0000
committerqingli <qingli@FreeBSD.org>2009-10-01 20:32:29 +0000
commit42eac0e4cd282f481832c740708479326b81f790 (patch)
tree4db02a39f3df6fba7d79e3f3032208d6ad0e2bb9 /sys/net
parent81d3ae4acc9a2163ee2f7986b1e4b298bbc2d213 (diff)
downloadFreeBSD-src-42eac0e4cd282f481832c740708479326b81f790.zip
FreeBSD-src-42eac0e4cd282f481832c740708479326b81f790.tar.gz
The flow-table associates TCP/UDP flows and IP destinations with
specific routes. When the routing table changes, for example, when a new route with a more specific prefix is inserted into the routing table, the flow-table is not updated to reflect that change. As such existing connections cannot take advantage of the new path. In some cases the path is broken. This patch will update the affected flow-table entries when a more specific route is added. The route entry is properly marked when a route is deleted from the table. In this case, when the flow-table performs a search, the stale entry is updated automatically. Therefore this patch is not necessary for route deletion. Submitted by: simon, phk Reviewed by: bz, kmacy MFC after: 3 days
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/flowtable.c40
-rw-r--r--sys/net/flowtable.h2
-rw-r--r--sys/net/route.c61
3 files changed, 98 insertions, 5 deletions
diff --git a/sys/net/flowtable.c b/sys/net/flowtable.c
index 22cab54..b85ae26 100644
--- a/sys/net/flowtable.c
+++ b/sys/net/flowtable.c
@@ -830,7 +830,7 @@ fle_free(struct flentry *fle)
}
static void
-flowtable_free_stale(struct flowtable *ft)
+flowtable_free_stale(struct flowtable *ft, struct rtentry *rt)
{
int curbit = 0, count;
struct flentry *fle, **flehead, *fleprev;
@@ -866,8 +866,14 @@ flowtable_free_stale(struct flowtable *ft)
curbit);
}
#endif
- while (fle != NULL) {
- if (!flow_stale(ft, fle)) {
+ while (fle != NULL) {
+ if (rt != NULL) {
+ if (__DEVOLATILE(struct rtentry *, fle->f_rt) != rt) {
+ fleprev = fle;
+ fle = fle->f_next;
+ continue;
+ }
+ } else if (!flow_stale(ft, fle)) {
fleprev = fle;
fle = fle->f_next;
continue;
@@ -916,6 +922,30 @@ flowtable_free_stale(struct flowtable *ft)
log(LOG_DEBUG, "freed %d flow entries\n", count);
}
+void
+flowtable_route_flush(struct flowtable *ft, struct rtentry *rt)
+{
+ int i;
+ if (ft->ft_flags & FL_PCPU) {
+ for (i = 0; i <= mp_maxid; i++) {
+ if (CPU_ABSENT(i))
+ continue;
+
+ thread_lock(curthread);
+ sched_bind(curthread, i);
+ thread_unlock(curthread);
+
+ flowtable_free_stale(ft, rt);
+
+ thread_lock(curthread);
+ sched_unbind(curthread);
+ thread_unlock(curthread);
+ }
+ } else {
+ flowtable_free_stale(ft, rt);
+ }
+}
+
static void
flowtable_clean_vnet(void)
{
@@ -933,14 +963,14 @@ flowtable_clean_vnet(void)
sched_bind(curthread, i);
thread_unlock(curthread);
- flowtable_free_stale(ft);
+ flowtable_free_stale(ft, NULL);
thread_lock(curthread);
sched_unbind(curthread);
thread_unlock(curthread);
}
} else {
- flowtable_free_stale(ft);
+ flowtable_free_stale(ft, NULL);
}
ft = ft->ft_next;
}
diff --git a/sys/net/flowtable.h b/sys/net/flowtable.h
index afc8fb7..7d7abdf 100644
--- a/sys/net/flowtable.h
+++ b/sys/net/flowtable.h
@@ -51,5 +51,7 @@ struct flowtable *flowtable_alloc(int nentry, int flags);
int flowtable_lookup(struct flowtable *ft, struct mbuf *m,
struct route *ro, uint32_t fibnum);
+void flowtable_route_flush(struct flowtable *ft, struct rtentry *rt);
+
#endif /* _KERNEL */
#endif
diff --git a/sys/net/route.c b/sys/net/route.c
index fc76c92..1ab039f 100644
--- a/sys/net/route.c
+++ b/sys/net/route.c
@@ -56,6 +56,7 @@
#include <net/if_dl.h>
#include <net/route.h>
#include <net/vnet.h>
+#include <net/flowtable.h>
#ifdef RADIX_MPATH
#include <net/radix_mpath.h>
@@ -996,6 +997,9 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt,
{
int error = 0, needlock = 0;
register struct rtentry *rt;
+#ifdef FLOWTABLE
+ register struct rtentry *rt0;
+#endif
register struct radix_node *rn;
register struct radix_node_head *rnh;
struct ifaddr *ifa;
@@ -1153,6 +1157,53 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt,
}
#endif
+#ifdef FLOWTABLE
+ rt0 = NULL;
+ /* XXX
+ * "flow-table" only support IPv4 at the moment.
+ */
+ if (dst->sa_family == AF_INET) {
+ rn = rnh->rnh_matchaddr(dst, rnh);
+ if (rn && ((rn->rn_flags & RNF_ROOT) == 0)) {
+ struct sockaddr *mask;
+ u_char *m, *n;
+ int len;
+
+ /*
+ * compare mask to see if the new route is
+ * more specific than the existing one
+ */
+ rt0 = RNTORT(rn);
+ RT_LOCK(rt0);
+ RT_ADDREF(rt0);
+ RT_UNLOCK(rt0);
+ /*
+ * A host route is already present, so
+ * leave the flow-table entries as is.
+ */
+ if (rt0->rt_flags & RTF_HOST) {
+ RTFREE(rt0);
+ rt0 = NULL;
+ } else if (!(flags & RTF_HOST) && netmask) {
+ mask = rt_mask(rt0);
+ len = mask->sa_len;
+ m = (u_char *)mask;
+ n = (u_char *)netmask;
+ while (len-- > 0) {
+ if (*n != *m)
+ break;
+ n++;
+ m++;
+ }
+ if (len == 0 || (*n < *m)) {
+ RTFREE(rt0);
+ rt0 = NULL;
+ }
+ }
+ }
+ }
+#endif
+
/* XXX mtu manipulation will be done in rnh_addaddr -- itojun */
rn = rnh->rnh_addaddr(ndst, netmask, rnh, rt->rt_nodes);
/*
@@ -1165,8 +1216,18 @@ rtrequest1_fib(int req, struct rt_addrinfo *info, struct rtentry **ret_nrt,
Free(rt_key(rt));
RT_LOCK_DESTROY(rt);
uma_zfree(V_rtzone, rt);
+#ifdef FLOWTABLE
+ if (rt0 != NULL)
+ RTFREE(rt0);
+#endif
senderr(EEXIST);
+ }
+#ifdef FLOWTABLE
+ else if (rt0 != NULL) {
+ flowtable_route_flush(V_ip_ft, rt0);
+ RTFREE(rt0);
}
+#endif
/*
* If this protocol has something to add to this then
OpenPOWER on IntegriCloud