aboutsummaryrefslogtreecommitdiff
path: root/sys/netinet6
diff options
context:
space:
mode:
authorAlexander V. Chernikov <melifaro@FreeBSD.org>2020-10-18 17:15:47 +0000
committerAlexander V. Chernikov <melifaro@FreeBSD.org>2020-10-18 17:15:47 +0000
commit0c325f53f16731f608919a4489f96fbbe28d2344 (patch)
tree47edfa6af78113b91e7dad7f002817c6e110b01f /sys/netinet6
parent186bcdaac7c70e59eb04412ad402a6fb57b97d11 (diff)
downloadsrc-0c325f53f16731f608919a4489f96fbbe28d2344.tar.gz
src-0c325f53f16731f608919a4489f96fbbe28d2344.zip
Implement flowid calculation for outbound connections to balance
connections over multiple paths. Multipath routing relies on mbuf flowid data for both transit and outbound traffic. Current code fills mbuf flowid from inp_flowid for connection-oriented sockets. However, inp_flowid is currently not calculated for outbound connections. This change creates simple hashing functions and starts calculating hashes for TCP,UDP/UDP-Lite and raw IP if multipath routes are present in the system. Reviewed by: glebius (previous version),ae Differential Revision: https://reviews.freebsd.org/D26523
Notes
Notes: svn path=/head/; revision=366813
Diffstat (limited to 'sys/netinet6')
-rw-r--r--sys/netinet6/in6_fib.c34
-rw-r--r--sys/netinet6/in6_fib.h3
-rw-r--r--sys/netinet6/in6_pcb.c12
-rw-r--r--sys/netinet6/in6_rss.c44
-rw-r--r--sys/netinet6/in6_rss.h3
-rw-r--r--sys/netinet6/ip6_output.c6
-rw-r--r--sys/netinet6/raw_ip6.c13
-rw-r--r--sys/netinet6/udp6_usrreq.c42
8 files changed, 122 insertions, 35 deletions
diff --git a/sys/netinet6/in6_fib.c b/sys/netinet6/in6_fib.c
index 9fd869b2730b..a3fd20f8ba25 100644
--- a/sys/netinet6/in6_fib.c
+++ b/sys/netinet6/in6_fib.c
@@ -51,6 +51,7 @@ __FBSDID("$FreeBSD$");
#include <net/route/route_ctl.h>
#include <net/route/route_var.h>
#include <net/route/nhop.h>
+#include <net/toeplitz.h>
#include <net/vnet.h>
#include <netinet/in.h>
@@ -68,6 +69,39 @@ __FBSDID("$FreeBSD$");
CHK_STRUCT_ROUTE_COMPAT(struct route_in6, ro_dst);
+#ifdef ROUTE_MPATH
+struct _hash_5tuple_ipv6 {
+ struct in6_addr src;
+ struct in6_addr dst;
+ unsigned short src_port;
+ unsigned short dst_port;
+ char proto;
+ char spare[3];
+};
+_Static_assert(sizeof(struct _hash_5tuple_ipv6) == 40,
+ "_hash_5tuple_ipv6 size is wrong");
+
+uint32_t
+fib6_calc_software_hash(const struct in6_addr *src, const struct in6_addr *dst,
+ unsigned short src_port, unsigned short dst_port, char proto,
+ uint32_t *phashtype)
+{
+ struct _hash_5tuple_ipv6 data;
+
+ data.src = *src;
+ data.dst = *dst;
+ data.src_port = src_port;
+ data.dst_port = dst_port;
+ data.proto = proto;
+ data.spare[0] = data.spare[1] = data.spare[2] = 0;
+
+ *phashtype = M_HASHTYPE_OPAQUE_HASH;
+
+ return (toeplitz_hash(MPATH_ENTROPY_KEY_LEN, mpath_entropy_key,
+ sizeof(data), (uint8_t *)&data));
+}
+#endif
+
/*
* Looks up path in fib @fibnum specified by @dst.
* Assumes scope is deembedded and provided in @scopeid.
diff --git a/sys/netinet6/in6_fib.h b/sys/netinet6/in6_fib.h
index a716674bce23..78edb5e5b776 100644
--- a/sys/netinet6/in6_fib.h
+++ b/sys/netinet6/in6_fib.h
@@ -39,4 +39,7 @@ int fib6_check_urpf(uint32_t fibnum, const struct in6_addr *dst6,
uint32_t scopeid, uint32_t flags, const struct ifnet *src_if);
struct nhop_object *fib6_lookup_debugnet(uint32_t fibnum,
const struct in6_addr *dst6, uint32_t scopeid, uint32_t flags);
+uint32_t fib6_calc_software_hash(const struct in6_addr *src,
+ const struct in6_addr *dst, unsigned short src_port, unsigned short dst_port,
+ char proto, uint32_t *phashtype);
#endif
diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c
index 3444ca1b2fe7..ab498bf91734 100644
--- a/sys/netinet6/in6_pcb.c
+++ b/sys/netinet6/in6_pcb.c
@@ -73,6 +73,7 @@ __FBSDID("$FreeBSD$");
#include "opt_inet6.h"
#include "opt_ipsec.h"
#include "opt_pcbgroup.h"
+#include "opt_route.h"
#include "opt_rss.h"
#include <sys/param.h>
@@ -423,6 +424,17 @@ in6_pcbconnect_mbuf(struct inpcb *inp, struct sockaddr *nam,
INP_WLOCK_ASSERT(inp);
INP_HASH_WLOCK_ASSERT(pcbinfo);
+#ifdef ROUTE_MPATH
+ if (CALC_FLOWID_OUTBOUND) {
+ uint32_t hash_type, hash_val;
+
+ hash_val = fib6_calc_software_hash(&inp->in6p_laddr,
+ &sin6->sin6_addr, 0, sin6->sin6_port,
+ inp->inp_socket->so_proto->pr_protocol, &hash_type);
+ inp->inp_flowid = hash_val;
+ inp->inp_flowtype = hash_type;
+ }
+#endif
/*
* Call inner routine, to assign local interface address.
* in6_pcbladdr() may automatically fill in sin6_scope_id.
diff --git a/sys/netinet6/in6_rss.c b/sys/netinet6/in6_rss.c
index 72dd0a8831af..2b86d961515b 100644
--- a/sys/netinet6/in6_rss.c
+++ b/sys/netinet6/in6_rss.c
@@ -153,6 +153,50 @@ rss_proto_software_hash_v6(const struct in6_addr *s, const struct in6_addr *d,
}
/*
+ * Calculate an appropriate ipv6 2-tuple or 4-tuple given the given
+ * IPv6 source/destination address, UDP or TCP source/destination ports
+ * and the protocol type.
+ *
+ * The protocol code may wish to do a software hash of the given
+ * tuple. This depends upon the currently configured RSS hash types.
+ *
+ * It assumes the packet source/destination address
+ * are in "outgoin" packet order (ie, destination is "far" address.)
+ */
+uint32_t
+xps_proto_software_hash_v6(const struct in6_addr *s, const struct in6_addr *d,
+ u_short sp, u_short dp, int proto, uint32_t *hashtype)
+{
+
+ uint32_t hash;
+
+ /*
+ * Next, choose the hash type depending upon the protocol
+ * identifier.
+ */
+ if ((proto == IPPROTO_TCP) &&
+ (rss_gethashconfig() & RSS_HASHTYPE_RSS_TCP_IPV6)) {
+ hash = rss_hash_ip6_4tuple(d, dp, s, sp);
+ *hashtype = M_HASHTYPE_RSS_TCP_IPV6;
+ return (hash);
+ } else if ((proto == IPPROTO_UDP) &&
+ (rss_gethashconfig() & RSS_HASHTYPE_RSS_UDP_IPV6)) {
+ hash = rss_hash_ip6_4tuple(d, dp, s, sp);
+ *hashtype = M_HASHTYPE_RSS_UDP_IPV6;
+ return (hash);
+ } else if (rss_gethashconfig() & RSS_HASHTYPE_RSS_IPV6) {
+ /* RSS doesn't hash on other protocols like SCTP; so 2-tuple */
+ hash = rss_hash_ip6_2tuple(d, s);
+ *hashtype = M_HASHTYPE_RSS_IPV6;
+ return (hash);
+ }
+
+ *hashtype = M_HASHTYPE_NONE;
+ return (0);
+}
+
+
+/*
* Do a software calculation of the RSS for the given mbuf.
*
* This is typically used by the input path to recalculate the RSS after
diff --git a/sys/netinet6/in6_rss.h b/sys/netinet6/in6_rss.h
index f5b48c71408a..5846e515d185 100644
--- a/sys/netinet6/in6_rss.h
+++ b/sys/netinet6/in6_rss.h
@@ -54,5 +54,8 @@ int rss_proto_software_hash_v6(const struct in6_addr *src,
uint32_t *hashtype);
struct mbuf * rss_soft_m2cpuid_v6(struct mbuf *m, uintptr_t source,
u_int *cpuid);
+uint32_t xps_proto_software_hash_v6(const struct in6_addr *s,
+ const struct in6_addr *d, u_short sp, u_short dp,
+ int proto, uint32_t *hashtype);
#endif /* !_NETINET6_IN6_RSS_H_ */
diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c
index 59aabaa258f5..4e8f22a01b0a 100644
--- a/sys/netinet6/ip6_output.c
+++ b/sys/netinet6/ip6_output.c
@@ -419,9 +419,6 @@ done:
*
* ifpp - XXX: just for statistics
*/
-/*
- * XXX TODO: no flowid is assigned for outbound flows?
- */
int
ip6_output(struct mbuf *m0, struct ip6_pktopts *opt,
struct route_in6 *ro, int flags, struct ip6_moptions *im6o,
@@ -775,7 +772,8 @@ again:
}
}
- nh = fib6_lookup(fibnum, &kdst, scopeid, NHR_NONE, 0);
+ nh = fib6_lookup(fibnum, &kdst, scopeid, NHR_NONE,
+ m->m_pkthdr.flowid);
if (nh == NULL) {
IP6STAT_INC(ip6s_noroute);
/* No ifp in6_ifstat_inc(ifp, ifs6_out_discard); */
diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c
index 636828eb4ef4..aea99add4391 100644
--- a/sys/netinet6/raw_ip6.c
+++ b/sys/netinet6/raw_ip6.c
@@ -66,6 +66,7 @@ __FBSDID("$FreeBSD$");
#include "opt_ipsec.h"
#include "opt_inet6.h"
+#include "opt_route.h"
#include <sys/param.h>
#include <sys/errno.h>
@@ -103,6 +104,7 @@ __FBSDID("$FreeBSD$");
#include <netinet6/ip6_var.h>
#include <netinet6/nd6.h>
#include <netinet6/raw_ip6.h>
+#include <netinet6/in6_fib.h>
#include <netinet6/scope6_var.h>
#include <netinet6/send.h>
@@ -462,6 +464,17 @@ rip6_output(struct mbuf *m, struct socket *so, ...)
}
ip6 = mtod(m, struct ip6_hdr *);
+#ifdef ROUTE_MPATH
+ if (CALC_FLOWID_OUTBOUND) {
+ uint32_t hash_type, hash_val;
+
+ hash_val = fib6_calc_software_hash(&inp->in6p_laddr,
+ &dstsock->sin6_addr, 0, 0, so->so_proto->pr_protocol,
+ &hash_type);
+ inp->inp_flowid = hash_val;
+ inp->inp_flowtype = hash_type;
+ }
+#endif
/*
* Source address selection.
*/
diff --git a/sys/netinet6/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c
index 32aa21cb24a1..1535be90e1b0 100644
--- a/sys/netinet6/udp6_usrreq.c
+++ b/sys/netinet6/udp6_usrreq.c
@@ -75,6 +75,7 @@ __FBSDID("$FreeBSD$");
#include "opt_inet.h"
#include "opt_inet6.h"
#include "opt_ipsec.h"
+#include "opt_route.h"
#include "opt_rss.h"
#include <sys/param.h>
@@ -115,6 +116,7 @@ __FBSDID("$FreeBSD$");
#include <netinet6/ip6protosw.h>
#include <netinet6/ip6_var.h>
+#include <netinet6/in6_fib.h>
#include <netinet6/in6_pcb.h>
#include <netinet6/in6_rss.h>
#include <netinet6/udp6_var.h>
@@ -954,42 +956,20 @@ udp6_output(struct socket *so, int flags_arg, struct mbuf *m,
}
flags = 0;
-#ifdef RSS
- {
- uint32_t hash_val, hash_type;
+#if defined(ROUTE_MPATH) || defined(RSS)
+ if (CALC_FLOWID_OUTBOUND_SENDTO) {
+ uint32_t hash_type, hash_val;
uint8_t pr;
pr = inp->inp_socket->so_proto->pr_protocol;
- /*
- * Calculate an appropriate RSS hash for UDP and
- * UDP Lite.
- *
- * The called function will take care of figuring out
- * whether a 2-tuple or 4-tuple hash is required based
- * on the currently configured scheme.
- *
- * Later later on connected socket values should be
- * cached in the inpcb and reused, rather than constantly
- * re-calculating it.
- *
- * UDP Lite is a different protocol number and will
- * likely end up being hashed as a 2-tuple until
- * RSS / NICs grow UDP Lite protocol awareness.
- */
- if (rss_proto_software_hash_v6(faddr, laddr, fport,
- inp->inp_lport, pr, &hash_val, &hash_type) == 0) {
- m->m_pkthdr.flowid = hash_val;
- M_HASHTYPE_SET(m, hash_type);
- }
- /*
- * Don't override with the inp cached flowid.
- *
- * Until the whole UDP path is vetted, it may actually
- * be incorrect.
- */
- flags |= IP_NODEFAULTFLOWID;
+ hash_val = fib6_calc_packet_hash(laddr, faddr,
+ inp->inp_lport, fport, pr, &hash_type);
+ m->m_pkthdr.flowid = hash_val;
+ M_HASHTYPE_SET(m, hash_type);
}
+ /* do not use inp flowid */
+ flags |= IP_NODEFAULTFLOWID;
#endif
UDPSTAT_INC(udps_opackets);