net: multipath routing: configurable seed
Subsystems (5)
PATCH v4 1/1 net: multipath routing: configurable seed
Ability for a user to assign seed value to multipath route hashes. Now kernel uses random seed value to prevent hash-flooding DoS attacks; however, it disables some use cases, f.e:
+-------+ +------+ +--------+ | |-eth0---| FW0 |---eth0-| | | | +------+ | | | GW0 |ECMP ECMP| GW1 | | | +------+ | | | |-eth1---| FW1 |---eth1-| | +-------+ +------+ +--------+
In this use case, two ECMP routers balance traffic between two firewalls. If some flow transmits a response over a different channel than request, such flow will be dropped, because keep-state rules are created on the other firewall.
This patch adds sysctl variable: net.ipv4|ipv6.fib_multipath_hash_seed. User can set the same seed value on GW0 and GW1 for traffic to be mirror-balanced. By default, random value is used.
--- Documentation/networking/ip-sysctl.rst | 14 + include/net/flow_dissector.h | 4 + include/net/netns/ipv4.h | 2 + include/net/netns/ipv6.h | 3 + net/core/flow_dissector.c | 9 + net/ipv4/route.c | 10 +- net/ipv4/sysctl_net_ipv4.c | 97 +++++ net/ipv6/route.c | 10 +- net/ipv6/sysctl_net_ipv6.c | 96 +++++ .../testing/selftests/net/forwarding/Makefile | 1 + tools/testing/selftests/net/forwarding/lib.sh | 41 +++ .../net/forwarding/router_mpath_seed.sh | 347 ++++++++++++++++++ 12 files changed, 632 insertions(+), 2 deletions(-) create mode 100755 tools/testing/selftests/net/forwarding/router_mpath_seed.sh
Documentation/networking/ip-sysctl.rst +14 -0
@@ -100,6 +100,20 @@ fib_multipath_hash_policy - INTEGER - 1 - Layer 4 - 2 - Layer 3 or inner Layer 3 if present +fib_multipath_hash_seed - STRING + Controls seed value for multipath route hashes. By default + random value is used. Only valid for kernels built with + CONFIG_IP_ROUTE_MULTIPATH enabled. + + Valid format: two hex values set off with comma or "random" + keyword. + + Example to generate the seed value:: + + RAND=$(openssl rand -hex 16) && echo "${RAND:0:16},${RAND:16:16}" + + Default: "random" + fib_sync_mem - UNSIGNED INTEGER Amount of dirty memory from fib entries that can be backlogged before synchronize_rcu is forced.
include/net/flow_dissector.h +4 -0
@@ -348,6 +348,10 @@ static inline bool flow_keys_have_l4(const struct flow_keys *keys) }u32 flow_hash_from_keys (struct flow_keys *keys); +#ifdef CONFIG_IP_ROUTE_MULTIPATH +u32 flow_multipath_hash_from_keys (struct flow_keys *keys, +const siphash_key_t *seed); +#endif /* CONFIG_IP_ROUTE_MULTIPATH */ void skb_flow_get_icmp_tci (const struct sk_buff *skb,struct flow_dissector_key_icmp *key_icmp,const void *data,int thoff,int hlen);
include/net/netns/ipv4.h +2 -0
@@ -222,6 +222,8 @@ struct netns_ipv4 {#ifdef CONFIG_IP_ROUTE_MULTIPATH u8 sysctl_fib_multipath_use_neigh;u8 sysctl_fib_multipath_hash_policy; +int sysctl_fib_multipath_hash_seed; +siphash_key_t __rcu *fib_multipath_hash_seed_ctx;#endif struct fib_notifier_ops *notifier_ops;
include/net/netns/ipv6.h +3 -0
@@ -8,6 +8,7 @@#ifndef __NETNS_IPV6_H__#define __NETNS_IPV6_H__#include <net/dst_ops.h> +#include <linux/siphash.h> #include <uapi/linux/icmpv6.h> struct ctl_table_header ;
@@ -30,6 +31,7 @@ struct netns_sysctl_ipv6 {int ip6_rt_min_advmss;u8 bindv6only;u8 multipath_hash_policy; +u8 multipath_hash_seed;u8 flowlabel_consistency;u8 auto_flowlabels;int icmpv6_time;
@@ -107,6 +109,7 @@ struct netns_ipv6 {struct fib_rules_ops *mr6_rules_ops;#endif #endif +siphash_key_t __rcu *multipath_hash_seed_ctx;atomic_t dev_addr_genid;atomic_t fib6_sernum;struct seg6_pernet_data *seg6_data;
net/core/flow_dissector.c +9 -0
@@ -1560,6 +1560,15 @@ u32 flow_hash_from_keys(struct flow_keys *keys) }EXPORT_SYMBOL (flow_hash_from_keys); +#ifdef CONFIG_IP_ROUTE_MULTIPATH +u32 flow_multipath_hash_from_keys (struct flow_keys *keys, +const siphash_key_t *seed) +{ +return __flow_hash_from_keys (keys, seed); +} +EXPORT_SYMBOL (flow_multipath_hash_from_keys); +#endif /* CONFIG_IP_ROUTE_MULTIPATH */ +static inline u32 ___skb_get_hash (const struct sk_buff *skb,struct flow_keys *keys,const siphash_key_t *keyval)
net/ipv4/route.c +9 -1
@@ -1912,6 +1912,7 @@ int fib_multipath_hash(const struct net *net, const struct flowi4 *fl4, {u32 multipath_hash = fl4 ? fl4->flowi4_multipath_hash :0 ;struct flow_keys hash_keys; +siphash_key_t *seed_ctx;u32 mhash;switch (net->ipv4.sysctl_fib_multipath_hash_policy) {
@@ -1989,7 +1990,14 @@ int fib_multipath_hash(const struct net *net, const struct flowi4 *fl4, }break ; } - mhash =flow_hash_from_keys (&hash_keys); + +rcu_read_lock (); + seed_ctx =rcu_dereference (net->ipv4.fib_multipath_hash_seed_ctx); +if (seed_ctx) + mhash =flow_multipath_hash_from_keys (&hash_keys, seed_ctx); +else + mhash =flow_hash_from_keys (&hash_keys); +rcu_read_unlock ();if (multipath_hash) mhash =jhash_2words (mhash, multipath_hash,0 );
net/ipv4/sysctl_net_ipv4.c +97 -0
115 lines not on this page · raw message
net/ipv6/route.c +9 -1
@@ -2331,6 +2331,7 @@ u32 rt6_multipath_hash(const struct net *net, const struct flowi6 *fl6, const struct sk_buff *skb, struct flow_keys *flkeys) { struct flow_keys hash_keys; +siphash_key_t *seed_ctx;u32 mhash;switch (ip6_multipath_hash_policy (net)) {
@@ -2414,7 +2415,14 @@ u32 rt6_multipath_hash(const struct net *net, const struct flowi6 *fl6, }break ; } - mhash =flow_hash_from_keys (&hash_keys); + +rcu_read_lock (); + seed_ctx =rcu_dereference (net->ipv6.multipath_hash_seed_ctx); +if (seed_ctx) + mhash =flow_multipath_hash_from_keys (&hash_keys, seed_ctx); +else + mhash =flow_hash_from_keys (&hash_keys); +rcu_read_unlock ();return mhash >>1 ; }
net/ipv6/sysctl_net_ipv6.c +96 -0
108 lines not on this page · raw message
tools/testing/selftests/net/forwarding/Makefile +1 -0
@@ -38,6 +38,7 @@ TEST_PROGS = bridge_igmp.sh \ router_mpath_nh.sh \ router_multicast.sh \ router_multipath.sh \ + router_mpath_seed.sh \ router.sh \ router_vid_1.sh \ sch_ets.sh \
tools/testing/selftests/net/forwarding/lib.sh +41 -0
58 lines not on this page · raw message
tools/testing/selftests/net/forwarding/router_mpath_seed.sh new file +347 -0
347 lines not on this page · raw message
Signature · 1 line
2.31.1
Quoted 22 lines · Balaev Pavel
Ability for a user to assign seed value to multipath route hashes. Now kernel uses random seed value to prevent hash-flooding DoS attacks; however, it disables some use cases, f.e:
+-------+ +------+ +--------+ | |-eth0---| FW0 |---eth0-| | | | +------+ | | | GW0 |ECMP ECMP| GW1 | | | +------+ | | | |-eth1---| FW1 |---eth1-| | +-------+ +------+ +--------+In this use case, two ECMP routers balance traffic between two firewalls. If some flow transmits a response over a different channel than request, such flow will be dropped, because keep-state rules are created on the other firewall.
This patch adds sysctl variable: net.ipv4|ipv6.fib_multipath_hash_seed. User can set the same seed value on GW0 and GW1 for traffic to be mirror-balanced. By default, random value is used.
Signed-off-by Balaev Pavel <[email protected]>
Quoted 15 lines
--- Documentation/networking/ip-sysctl.rst | 14 + include/net/flow_dissector.h | 4 + include/net/netns/ipv4.h | 2 + include/net/netns/ipv6.h | 3 + net/core/flow_dissector.c | 9 + net/ipv4/route.c | 10 +- net/ipv4/sysctl_net_ipv4.c | 97 +++++ net/ipv6/route.c | 10 +- net/ipv6/sysctl_net_ipv6.c | 96 +++++ .../testing/selftests/net/forwarding/Makefile | 1 + tools/testing/selftests/net/forwarding/lib.sh | 41 +++ .../net/forwarding/router_mpath_seed.sh | 347 ++++++++++++++++++ 12 files changed, 632 insertions(+), 2 deletions(-) create mode 100755 tools/testing/selftests/net/forwarding/router_mpath_seed.sh
this really needs to be multiple patches. At a minimum 1 for ipv4, 1 for ipv6 and 1 for the test script (thank you for adding that).
[ cc'ed Ido since most of the tests under tools/testing/selftests/net/forwarding come from him and team ]
Quoted 31 lines
Documentation/networking/ip-sysctl.rst +14
-0@@ -100,6 +100,20 @@ fib_multipath_hash_policy - INTEGER - 1 - Layer 4 - 2 - Layer 3 or inner Layer 3 if present +fib_multipath_hash_seed - STRING + Controls seed value for multipath route hashes. By default + random value is used. Only valid for kernels built with + CONFIG_IP_ROUTE_MULTIPATH enabled. + + Valid format: two hex values set off with comma or "random" + keyword. + + Example to generate the seed value:: + + RAND=$(openssl rand -hex 16) && echo "${RAND:0:16},${RAND:16:16}" + + Default: "random" + fib_sync_mem - UNSIGNED INTEGER Amount of dirty memory from fib entries that can be backlogged before synchronize_rcu is forced.include/net/flow_dissector.h +0
-0
include/net/flow_dissector.h static inline bool flow_keys_have_l4(const struct flow_keys *keys) · line 353
Quoted 6 lines
include/net/flow_dissector.h +3
-0@@ -348,6 +348,10 @@ static inline bool flow_keys_have_l4(const struct flow_keys *keys) }u32 flow_hash_from_keys (struct flow_keys *keys); +#ifdef CONFIG_IP_ROUTE_MULTIPATH +u32 flow_multipath_hash_from_keys (struct flow_keys *keys, +const siphash_key_t *seed);
column alignment looks off here ^^^^ and a few other places; please correct in the next version.
Quoted 39 lines · David Ahern
Quoted 22 lines · Balaev Pavel
Ability for a user to assign seed value to multipath route hashes. Now kernel uses random seed value to prevent hash-flooding DoS attacks; however, it disables some use cases, f.e:
+-------+ +------+ +--------+ | |-eth0---| FW0 |---eth0-| | | | +------+ | | | GW0 |ECMP ECMP| GW1 | | | +------+ | | | |-eth1---| FW1 |---eth1-| | +-------+ +------+ +--------+In this use case, two ECMP routers balance traffic between two firewalls. If some flow transmits a response over a different channel than request, such flow will be dropped, because keep-state rules are created on the other firewall.
This patch adds sysctl variable: net.ipv4|ipv6.fib_multipath_hash_seed. User can set the same seed value on GW0 and GW1 for traffic to be mirror-balanced. By default, random value is used.
Signed-off-by Balaev Pavel <[email protected]>Quoted 15 lines
--- Documentation/networking/ip-sysctl.rst | 14 + include/net/flow_dissector.h | 4 + include/net/netns/ipv4.h | 2 + include/net/netns/ipv6.h | 3 + net/core/flow_dissector.c | 9 + net/ipv4/route.c | 10 +- net/ipv4/sysctl_net_ipv4.c | 97 +++++ net/ipv6/route.c | 10 +- net/ipv6/sysctl_net_ipv6.c | 96 +++++ .../testing/selftests/net/forwarding/Makefile | 1 + tools/testing/selftests/net/forwarding/lib.sh | 41 +++ .../net/forwarding/router_mpath_seed.sh | 347 ++++++++++++++++++ 12 files changed, 632 insertions(+), 2 deletions(-) create mode 100755 tools/testing/selftests/net/forwarding/router_mpath_seed.sh
Quoted 5 lines
this really needs to be multiple patches. At a minimum 1 for ipv4, 1 for ipv6 and 1 for the test script (thank you for adding that).
[ cc'ed Ido since most of the tests under
tools/testing/selftests/net/forwardingcome from him and team ]
OK, I will create 3 patches. Thanks for the advice.
Quoted 33 lines
Quoted 33 lines
Documentation/networking/ip-sysctl.rst +14
-0@@ -100,6 +100,20 @@ fib_multipath_hash_policy - INTEGER - 1 - Layer 4 - 2 - Layer 3 or inner Layer 3 if present +fib_multipath_hash_seed - STRING + Controls seed value for multipath route hashes. By default + random value is used. Only valid for kernels built with + CONFIG_IP_ROUTE_MULTIPATH enabled. + + Valid format: two hex values set off with comma or "random" + keyword. + + Example to generate the seed value:: + + RAND=$(openssl rand -hex 16) && echo "${RAND:0:16},${RAND:16:16}" + + Default: "random" + fib_sync_mem - UNSIGNED INTEGER Amount of dirty memory from fib entries that can be backlogged before synchronize_rcu is forced.include/net/flow_dissector.h +0
-0@@ -348,6 +348,10 @@ static inline bool flow_keys_have_l4(const struct flow_keys *keys) }
Quoted 8 lines
include/net/flow_dissector.h static inline bool flow_keys_have_l4(const struct flow_keys *keys) · line 353
Quoted 4 lines
include/net/flow_dissector.h +3
-0u32 flow_hash_from_keys (struct flow_keys *keys); +#ifdef CONFIG_IP_ROUTE_MULTIPATH +u32 flow_multipath_hash_from_keys (struct flow_keys *keys, +const siphash_key_t *seed);column alignment looks off here ^^^^ and a few other places; please correct in the next version.
After running "scripts/checkpatch.pl" I got warnings about alignment. So I run checkpatch.pl --fix and fixed alignment as a script did. So warnings goes away. I don't get the rules of alignment, can you tell me the right way?
Quoted 4 lines · Pavel Balaev
After running "
scripts/checkpatch.pl" I got warnings about alignment. So I run checkpatch.pl --fix and fixed alignment as a script did. So warnings goes away. I don't get the rules of alignment, can you tell me the right way?
I don't see any statements under Documentation/process; not sure where it is explicitly stated. You can get the general idea by following the surrounding code and then let checkpatch correct from there.
Quoted 9 lines · David Ahern
Quoted 4 lines · Pavel Balaev
After running "
scripts/checkpatch.pl" I got warnings about alignment. So I run checkpatch.pl --fix and fixed alignment as a script did. So warnings goes away. I don't get the rules of alignment, can you tell me the right way?I don't see any statements under
Documentation/process; not sure where it is explicitly stated. You can get the general idea by following the surrounding code and then let checkpatch correct from there.
I create 3 patches and check it:
./scripts/checkpatch.pl 0001-net-ipv4-multipath-routing-configurable-seed.patch
total: 0 errors, 0 warnings, 0 checks, 186 lines checked
0001-net-ipv4-multipath-routing-configurable-seed.patch has no obvious style problems and is ready for submission. ./scripts/checkpatch.pl 0002-net-ipv6-multipath-routing-configurable-seed.patch
total: 0 errors, 0 warnings, 0 checks, 151 lines checked
0002-net-ipv6-multipath-routing-configurable-seed.patch has no obvious style problems and is ready for submission. ./scripts/checkpatch.pl 0003-selftests-net-forwarding-configurable-seed-tests.patch
WARNING: added, moved or deleted file(s), does MAINTAINERS need updating?
#76:
new file mode 100755
total: 0 errors, 1 warnings, 394 lines checked
No alignment warnings at all.
kernel test robot
build botThank you for the patch! Yet something to improve:
Hi Balaev,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on net-next/master]
url: https://github.com/0day-ci/linux/commits/Balaev-Pavel/net-multipath-routing-configurable-seed/20210423-214755 base: https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git cad4162a90aeff737a16c0286987f51e927f003a config: riscv-rv32_defconfig (attached as .config) compiler: riscv32-linux-gcc (GCC) 9.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross
# https://github.com/0day-ci/linux/commit/d2127c4161e4482ac75072cfdbb27781d2a9be30
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Balaev-Pavel/net-multipath-routing-configurable-seed/20210423-214755 git checkout d2127c4161e4482ac75072cfdbb27781d2a9be30
# save the attached .config to linux build tree
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-9.3.0 make.cross W=1 ARCH=riscv
If you fix the issue, kindly add following tag as appropriate
All errors (new ones prefixed by >>):
net/ipv6/route.c: In function 'rt6_multipath_hash':
>> net/ipv6/route.c:2422:11: error: implicit declaration of function 'flow_multipath_hash_from_keys'; did you mean 'flow_hash_from_keys'? [-Werror=implicit-function-declaration]
2422 | mhash = flow_multipath_hash_from_keys(&hash_keys, seed_ctx);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| flow_hash_from_keyscc1: some warnings being treated as errors
vim +2422 net/ipv6/route.c
2328
2329 /* if skb is set it will be used and fl6 can be NULL */
2330 u32 rt6_multipath_hash(const struct net *net, const struct flowi6 *fl6,
2331 const struct sk_buff *skb, struct flow_keys *flkeys)
2332 {
2333 struct flow_keys hash_keys;
2334 siphash_key_t *seed_ctx;
2335 u32 mhash;
2336
2337 switch (ip6_multipath_hash_policy(net)) {
2338 case 0:
2339 memset(&hash_keys, 0, sizeof(hash_keys));
2340 hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2341 if (skb) {
2342 ip6_multipath_l3_keys(skb, &hash_keys, flkeys);
2343 } else {
2344 hash_keys.addrs.v6addrs.src = fl6->saddr;
2345 hash_keys.addrs.v6addrs.dst = fl6->daddr;
2346 hash_keys.tags.flow_label = (__force u32)flowi6_get_flowlabel(fl6);
2347 hash_keys.basic.ip_proto = fl6->flowi6_proto;
2348 }
2349 break;
2350 case 1:
2351 if (skb) {
2352 unsigned int flag = FLOW_DISSECTOR_F_STOP_AT_ENCAP;
2353 struct flow_keys keys;
2354
2355 /* short-circuit if we already have L4 hash present */
2356 if (skb->l4_hash)
2357 return skb_get_hash_raw(skb) >> 1;
2358
2359 memset(&hash_keys, 0, sizeof(hash_keys));
2360
2361 if (!flkeys) {
2362 skb_flow_dissect_flow_keys(skb, &keys, flag);
2363 flkeys = &keys;
2364 }
2365 hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2366 hash_keys.addrs.v6addrs.src = flkeys->addrs.v6addrs.src;
2367 hash_keys.addrs.v6addrs.dst = flkeys->addrs.v6addrs.dst;
2368 hash_keys.ports.src = flkeys->ports.src;
2369 hash_keys.ports.dst = flkeys->ports.dst;
2370 hash_keys.basic.ip_proto = flkeys->basic.ip_proto;
2371 } else {
2372 memset(&hash_keys, 0, sizeof(hash_keys));
2373 hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2374 hash_keys.addrs.v6addrs.src = fl6->saddr;
2375 hash_keys.addrs.v6addrs.dst = fl6->daddr;
2376 hash_keys.ports.src = fl6->fl6_sport;
2377 hash_keys.ports.dst = fl6->fl6_dport;
2378 hash_keys.basic.ip_proto = fl6->flowi6_proto;
2379 }
2380 break;
2381 case 2:
2382 memset(&hash_keys, 0, sizeof(hash_keys));
2383 hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2384 if (skb) {
2385 struct flow_keys keys;
2386
2387 if (!flkeys) {
2388 skb_flow_dissect_flow_keys(skb, &keys, 0);
2389 flkeys = &keys;
2390 }
2391
2392 /* Inner can be v4 or v6 */
2393 if (flkeys->control.addr_type == FLOW_DISSECTOR_KEY_IPV4_ADDRS) {
2394 hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS;
2395 hash_keys.addrs.v4addrs.src = flkeys->addrs.v4addrs.src;
2396 hash_keys.addrs.v4addrs.dst = flkeys->addrs.v4addrs.dst;
2397 } else if (flkeys->control.addr_type == FLOW_DISSECTOR_KEY_IPV6_ADDRS) {
2398 hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2399 hash_keys.addrs.v6addrs.src = flkeys->addrs.v6addrs.src;
2400 hash_keys.addrs.v6addrs.dst = flkeys->addrs.v6addrs.dst;
2401 hash_keys.tags.flow_label = flkeys->tags.flow_label;
2402 hash_keys.basic.ip_proto = flkeys->basic.ip_proto;
2403 } else {
2404 /* Same as case 0 */
2405 hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2406 ip6_multipath_l3_keys(skb, &hash_keys, flkeys);
2407 }
2408 } else {
2409 /* Same as case 0 */
2410 hash_keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS;
2411 hash_keys.addrs.v6addrs.src = fl6->saddr;
2412 hash_keys.addrs.v6addrs.dst = fl6->daddr;
2413 hash_keys.tags.flow_label = (__force u32)flowi6_get_flowlabel(fl6);
2414 hash_keys.basic.ip_proto = fl6->flowi6_proto;
2415 }
2416 break;
2417 }
2418
2419 rcu_read_lock();
2420 seed_ctx = rcu_dereference(net->ipv6.multipath_hash_seed_ctx);
2421 if (seed_ctx)
> 2422 mhash = flow_multipath_hash_from_keys(&hash_keys, seed_ctx);
2423 else
2424 mhash = flow_hash_from_keys(&hash_keys);
2425 rcu_read_unlock();
2426
2427 return mhash >> 1;
2428 }
2429
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org