aboutsummaryrefslogtreecommitdiff
path: root/sys/net
diff options
context:
space:
mode:
authorGleb Smirnoff <glebius@FreeBSD.org>2012-07-04 07:37:53 +0000
committerGleb Smirnoff <glebius@FreeBSD.org>2012-07-04 07:37:53 +0000
commitbf9840512a016f8a2b02f1de5f23104cc62d614f (patch)
tree5a6dfb251b44f09882eafc14a986f989520add8e /sys/net
parente3d6ef0b030463b20db2e7b364bb3a4824ffdc08 (diff)
downloadsrc-bf9840512a016f8a2b02f1de5f23104cc62d614f.tar.gz
src-bf9840512a016f8a2b02f1de5f23104cc62d614f.zip
When ip_output()/ip6_output() is supplied a struct route *ro argument,
it skips FLOWTABLE lookup. However, the non-NULL ro has dual meaning here: it may be supplied to provide route, and it may be supplied to store and return to caller the route that ip_output()/ip6_output() finds. In the latter case skipping FLOWTABLE lookup is pessimisation. The difference between struct route filled by FLOWTABLE and filled by rtalloc() family is that the former doesn't hold a reference on its rtentry. Reference is hold by flow entry, and it is about to be released in future. Thus, route filled by FLOWTABLE shouldn't be passed to RTFREE() macro. - Introduce new flag for struct route/route_in6, that marks route not holding a reference on rtentry. - Introduce new macro RO_RTFREE() that cleans up a struct route depending on its kind. - All callers to ip_output()/ip6_output() that do supply non-NULL but empty route should use RO_RTFREE() to free results of lookup. - ip_output()/ip6_output() now do FLOWTABLE lookup always when ro->ro_rt == NULL. Tested by: tuexen (SCTP part)
Notes
Notes: svn path=/head/; revision=238092
Diffstat (limited to 'sys/net')
-rw-r--r--sys/net/flowtable.c3
-rw-r--r--sys/net/route.h15
2 files changed, 16 insertions, 2 deletions
diff --git a/sys/net/flowtable.c b/sys/net/flowtable.c
index 8501b1875d85..0e50377d9941 100644
--- a/sys/net/flowtable.c
+++ b/sys/net/flowtable.c
@@ -619,6 +619,7 @@ flow_to_route(struct flentry *fle, struct route *ro)
sin->sin_addr.s_addr = hashkey[2];
ro->ro_rt = __DEVOLATILE(struct rtentry *, fle->f_rt);
ro->ro_lle = __DEVOLATILE(struct llentry *, fle->f_lle);
+ ro->ro_flags |= RT_NORTREF;
}
#endif /* INET */
@@ -826,7 +827,7 @@ flow_to_route_in6(struct flentry *fle, struct route_in6 *ro)
memcpy(&sin6->sin6_addr, &hashkey[5], sizeof (struct in6_addr));
ro->ro_rt = __DEVOLATILE(struct rtentry *, fle->f_rt);
ro->ro_lle = __DEVOLATILE(struct llentry *, fle->f_lle);
-
+ ro->ro_flags |= RT_NORTREF;
}
#endif /* INET6 */
diff --git a/sys/net/route.h b/sys/net/route.h
index 1de222a06b1d..f12ed810d552 100644
--- a/sys/net/route.h
+++ b/sys/net/route.h
@@ -54,7 +54,8 @@ struct route {
struct sockaddr ro_dst;
};
-#define RT_CACHING_CONTEXT 0x1
+#define RT_CACHING_CONTEXT 0x1 /* XXX: not used anywhere */
+#define RT_NORTREF 0x2 /* doesn't hold reference on ro_rt */
/*
* These numbers are used by reliable protocols for determining
@@ -341,6 +342,18 @@ struct rt_addrinfo {
RTFREE_LOCKED(_rt); \
} while (0)
+#define RO_RTFREE(_ro) do { \
+ if ((_ro)->ro_rt) { \
+ if ((_ro)->ro_flags & RT_NORTREF) { \
+ (_ro)->ro_flags &= ~RT_NORTREF; \
+ (_ro)->ro_rt = NULL; \
+ } else { \
+ RT_LOCK((_ro)->ro_rt); \
+ RTFREE_LOCKED((_ro)->ro_rt); \
+ } \
+ } \
+} while (0)
+
struct radix_node_head *rt_tables_get_rnh(int, int);
struct ifmultiaddr;