summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-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