Skip to content

Instantly share code, notes, and snippets.

@neutronth
Created April 10, 2016 11:04
Show Gist options
  • Save neutronth/45c210cc3a44600692d67b51e3dd7bf0 to your computer and use it in GitHub Desktop.
Save neutronth/45c210cc3a44600692d67b51e3dd7bf0 to your computer and use it in GitHub Desktop.
Linux 4.4 multipath routing with src_ip, dst_ip, src_port, dst_port hash flow-based
--- include/net/ip_fib.h.orig 2016-04-10 11:44:40.342768815 +0700
+++ include/net/ip_fib.h 2016-04-10 15:28:42.217868332 +0700
@@ -331,6 +331,12 @@
return jhash_2words(saddr, daddr, fib_multipath_secret) >> 1;
}
+static inline int fib_multipath_hash_ip_port(__be32 saddr, __be32 daddr,
+ __be32 ports)
+{
+ return jhash_3words(saddr, daddr, ports, fib_multipath_secret) >> 1;
+}
+
void fib_select_multipath(struct fib_result *res, int hash);
void fib_select_path(struct net *net, struct fib_result *res,
struct flowi4 *fl4, int mp_hash);
--- net/ipv4/route.c.orig 2016-04-10 11:53:31.219926652 +0700
+++ net/ipv4/route.c 2016-04-10 15:33:28.934174428 +0700
@@ -113,6 +113,9 @@
#include <net/secure_seq.h>
#include <net/ip_tunnels.h>
#include <net/l3mdev.h>
+#ifdef CONFIG_IP_ROUTE_MULTIPATH
+#include <linux/sctp.h>
+#endif
#define RT_FL_TOS(oldflp4) \
((oldflp4)->flowi4_tos & (IPTOS_RT_MASK | RTO_ONLINK))
@@ -1745,8 +1748,59 @@
if (unlikely(ip_hdr(skb)->protocol == IPPROTO_ICMP))
h = ip_multipath_icmp_hash(skb);
- else
- h = fib_multipath_hash(saddr, daddr);
+ else {
+ const struct iphdr *iph = ip_hdr(skb);
+ unsigned int protooff = skb_network_offset(skb) + ip_hdrlen(skb);
+ int protocol = iph->protocol;
+ __be32 ports = 0;
+ __be16 *p_port = &ports;
+
+ if (protocol > 0 && !(ntohs(iph->frag_off) & IP_OFFSET)) {
+ switch (protocol) {
+ case IPPROTO_TCP: {
+ struct tcphdr _tcph;
+ const struct tcphdr *th;
+
+ th = skb_header_pointer(skb, protooff, sizeof(_tcph), &_tcph);
+ if (!th)
+ break;
+
+ *p_port = th->source;
+ *(p_port + 1) = th->dest;
+ break;
+ }
+ case IPPROTO_SCTP: {
+ sctp_sctphdr_t _sh;
+ const sctp_sctphdr_t *sh;
+
+ sh = skb_header_pointer(skb, protooff, sizeof(_sh), &_sh);
+ if (!sh)
+ break;
+
+ *p_port = sh->source;
+ *(p_port + 1) = sh->dest;
+ break;
+ }
+ case IPPROTO_UDP:
+ case IPPROTO_UDPLITE: {
+ struct udphdr _udph;
+ const struct udphdr *uh;
+
+ uh = skb_header_pointer(skb, protooff, sizeof(_udph), &_udph);
+ if (!uh)
+ break;
+
+ *p_port = uh->source;
+ *(p_port + 1) = uh->dest;
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ h = fib_multipath_hash_ip_port(saddr, daddr, ports);
+ }
fib_select_multipath(res, h);
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment