Skip to content

Instantly share code, notes, and snippets.

@upa
Created January 20, 2015 19:35
Show Gist options
  • Save upa/b08b32ee5ba14da95578 to your computer and use it in GitHub Desktop.
Save upa/b08b32ee5ba14da95578 to your computer and use it in GitHub Desktop.
hashbase-mpath-select-patch
*** linux-source-3.13.0-original/net/ipv4/fib_semantics.c Tue Dec 16 09:23:29 2014
--- linux-source-3.13.0/net/ipv4/fib_semantics.c Wed Jan 21 03:02:27 2015
***************
*** 33,38 ****
--- 33,42 ----
#include <linux/init.h>
#include <linux/slab.h>
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH_HASHONLY
+ #include <linux/hash.h> /* hash_32() */
+ #endif
+
#include <net/arp.h>
#include <net/ip.h>
#include <net/protocol.h>
*************** void fib_select_multipath(struct fib_res
*** 1329,1332 ****
--- 1333,1365 ----
res->nh_sel = 0;
spin_unlock_bh(&fib_multipath_lock);
}
+
+ #endif
+
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH_HASHONLY
+ /* added by [email protected]
+ * If hash-only decides next hop for a flow by hash of 5 tuple. there
+ * is no weight based balancing (like commodity hardware routers).
+ */
+
+ static inline unsigned long fib_calculate_hash (struct flowi4 * fl4)
+ {
+ return hash_32 (fl4->saddr + fl4->daddr + fl4->flowi4_proto +
+ fl4->fl4_sport + fl4->fl4_dport, 8);
+ }
+
+ void
+ fib_select_multipath_hashonly(struct fib_result *res,
+ const struct flowi4 * fl4)
+ {
+ unsigned long key;
+ struct fib_info *fi = res->fi;
+
+ key = fib_calculate_hash (fl4);
+ res->nh_sel = key % fi->fib_nhs;
+
+ return;
+ }
+
#endif
+
*** linux-source-3.13.0-original/net/ipv4/ip_output.c Tue Dec 16 09:23:29 2014
--- linux-source-3.13.0/net/ipv4/ip_output.c Wed Jan 21 03:48:14 2015
*************** int ip_queue_xmit(struct sk_buff *skb, s
*** 335,340 ****
--- 335,350 ----
if (rt != NULL)
goto packet_routed;
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH_HASHONLY
+ iph = ip_hdr (skb);
+ if (iph->protocol == IPPROTO_TCP) {
+ fl4->fl4_sport = tcp_hdr (skb)->source;
+ fl4->fl4_dport = tcp_hdr (skb)->dest;
+ } else if (iph->protocol == IPPROTO_UDP) {
+ fl4->fl4_sport = udp_hdr (skb)->source;
+ fl4->fl4_dport = udp_hdr (skb)->dest;
+ }
+ #endif
/* Make sure we can route this packet. */
rt = (struct rtable *)__sk_dst_check(sk, 0);
if (rt == NULL) {
*** linux-source-3.13.0-original/net/ipv4/Kconfig Mon Jan 20 11:40:07 2014
--- linux-source-3.13.0/net/ipv4/Kconfig Wed Jan 21 01:05:44 2015
*************** config IP_ROUTE_MULTIPATH
*** 90,95 ****
--- 90,106 ----
equal "cost" and chooses one of them in a non-deterministic fashion
if a matching packet arrives.
+ config IP_ROUTE_MULTIPATH_HASHONLY
+ bool "IP: equal cost multipath without load balancing for flows"
+ depends on IP_ROUTE_MULTIPATH
+ help
+ normally, IP_ROUTE_MULTIPATH load balance single flow to multiple
+ next hops. However, it causes packet reodering so that commodity
+ hardware routers using only hash to decide next hop for individual
+ flows. This option emulates this behavior. A next hop for a flow
+ is decided by hash value for 5-tuple of the flow, and the next hop
+ have been never changed.
+
config IP_ROUTE_VERBOSE
bool "IP: verbose route monitoring"
depends on IP_ADVANCED_ROUTER
*** linux-source-3.13.0-original/net/ipv4/route.c Tue Dec 16 09:23:29 2014
--- linux-source-3.13.0/net/ipv4/route.c Wed Jan 21 04:03:29 2015
*************** static int ip_mkroute_input(struct sk_bu
*** 1632,1645 ****
__be32 daddr, __be32 saddr, u32 tos)
{
#ifdef CONFIG_IP_ROUTE_MULTIPATH
! if (res->fi && res->fi->fib_nhs > 1)
fib_select_multipath(res);
#endif
/* create a routing cache entry */
return __mkroute_input(skb, res, in_dev, daddr, saddr, tos);
}
/*
* NOTE. We drop all the packets that has local source
* addresses, because every properly looped back packet
--- 1632,1667 ----
__be32 daddr, __be32 saddr, u32 tos)
{
#ifdef CONFIG_IP_ROUTE_MULTIPATH
! if (res->fi && res->fi->fib_nhs > 1) {
! #ifndef CONFIG_IP_ROUTE_MULTIPATH_HASHONLY
fib_select_multipath(res);
+ #else
+ fib_select_multipath_hashonly(res, fl4);
#endif
+ #endif
+ }
/* create a routing cache entry */
return __mkroute_input(skb, res, in_dev, daddr, saddr, tos);
}
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH_HASHONLY
+ static inline void
+ ip_rt_build_fl4_port (struct sk_buff *skb, struct flowi4 * fl4)
+ {
+ struct iphdr *ip = (struct iphdr *) skb_network_header (skb);
+
+ if (ip->protocol == IPPROTO_TCP) {
+ fl4->fl4_sport = tcp_hdr (skb)->source;
+ fl4->fl4_dport = tcp_hdr (skb)->dest;
+ } else if (ip->protocol == IPPROTO_UDP) {
+ fl4->fl4_sport = udp_hdr (skb)->source;
+ fl4->fl4_dport = udp_hdr (skb)->dest;
+ }
+ return;
+ }
+ #endif
+
/*
* NOTE. We drop all the packets that has local source
* addresses, because every properly looped back packet
*************** static int ip_route_input_slow(struct sk
*** 1710,1715 ****
--- 1732,1740 ----
fl4.flowi4_scope = RT_SCOPE_UNIVERSE;
fl4.daddr = daddr;
fl4.saddr = saddr;
+ #ifdef CONFIG_IP_ROUTE_MULTIPATH_HASHONLY
+ ip_rt_build_fl4_port (skb, &fl4);
+ #endif
err = fib_lookup(net, &fl4, &res);
if (err != 0)
goto no_route;
*************** struct rtable *__ip_route_output_key(str
*** 2159,2167 ****
}
#ifdef CONFIG_IP_ROUTE_MULTIPATH
! if (res.fi->fib_nhs > 1 && fl4->flowi4_oif == 0)
fib_select_multipath(&res);
! else
#endif
if (!res.prefixlen &&
res.table->tb_num_default > 1 &&
--- 2184,2196 ----
}
#ifdef CONFIG_IP_ROUTE_MULTIPATH
! if (res.fi->fib_nhs > 1 && fl4->flowi4_oif == 0) {
! #ifndef CONFIG_IP_ROUTE_MULTIPATH_HASHONLY
fib_select_multipath(&res);
! #else
! fib_select_multipath_hashonly(&res, fl4);
! #endif
! } else
#endif
if (!res.prefixlen &&
res.table->tb_num_default > 1 &&
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment