@@ -427,6 +427,61 @@ static int proc_fib_multipath_hash_fields(struct ctl_table *table, int write,
427427
428428 return ret ;
429429}
430+
431+ static u32 proc_fib_multipath_hash_rand_seed __ro_after_init ;
432+
433+ static void proc_fib_multipath_hash_init_rand_seed (void )
434+ {
435+ get_random_bytes (& proc_fib_multipath_hash_rand_seed ,
436+ sizeof (proc_fib_multipath_hash_rand_seed ));
437+ }
438+
439+ static void proc_fib_multipath_hash_set_seed (struct net * net , u32 user_seed )
440+ {
441+ struct sysctl_fib_multipath_hash_seed new = {
442+ .user_seed = user_seed ,
443+ .mp_seed = (user_seed ? user_seed :
444+ proc_fib_multipath_hash_rand_seed ),
445+ };
446+
447+ WRITE_ONCE (net -> ipv4 .sysctl_fib_multipath_hash_seed , new );
448+ }
449+
450+ static int proc_fib_multipath_hash_seed (struct ctl_table * table , int write ,
451+ void * buffer , size_t * lenp ,
452+ loff_t * ppos )
453+ {
454+ struct sysctl_fib_multipath_hash_seed * mphs ;
455+ struct net * net = table -> data ;
456+ struct ctl_table tmp ;
457+ u32 user_seed ;
458+ int ret ;
459+
460+ mphs = & net -> ipv4 .sysctl_fib_multipath_hash_seed ;
461+ user_seed = mphs -> user_seed ;
462+
463+ tmp = * table ;
464+ tmp .data = & user_seed ;
465+
466+ ret = proc_douintvec_minmax (& tmp , write , buffer , lenp , ppos );
467+
468+ if (write && ret == 0 ) {
469+ proc_fib_multipath_hash_set_seed (net , user_seed );
470+ call_netevent_notifiers (NETEVENT_IPV4_MPATH_HASH_UPDATE , net );
471+ }
472+
473+ return ret ;
474+ }
475+ #else
476+
477+ static void proc_fib_multipath_hash_init_rand_seed (void )
478+ {
479+ }
480+
481+ static void proc_fib_multipath_hash_set_seed (struct net * net , u32 user_seed )
482+ {
483+ }
484+
430485#endif
431486
432487static struct ctl_table ipv4_table [] = {
@@ -1036,6 +1091,13 @@ static struct ctl_table ipv4_net_table[] = {
10361091 .extra1 = SYSCTL_ONE ,
10371092 .extra2 = & fib_multipath_hash_fields_all_mask ,
10381093 },
1094+ {
1095+ .procname = "fib_multipath_hash_seed" ,
1096+ .data = & init_net ,
1097+ .maxlen = sizeof (u32 ),
1098+ .mode = 0644 ,
1099+ .proc_handler = proc_fib_multipath_hash_seed ,
1100+ },
10391101#endif
10401102 {
10411103 .procname = "ip_unprivileged_port_start" ,
@@ -1401,6 +1463,8 @@ static __net_init int ipv4_sysctl_init_net(struct net *net)
14011463 if (!net -> ipv4 .sysctl_local_reserved_ports )
14021464 goto err_ports ;
14031465
1466+ proc_fib_multipath_hash_set_seed (net , 0 );
1467+
14041468 return 0 ;
14051469
14061470err_ports :
@@ -1435,6 +1499,8 @@ static __init int sysctl_ipv4_init(void)
14351499 if (!hdr )
14361500 return - ENOMEM ;
14371501
1502+ proc_fib_multipath_hash_init_rand_seed ();
1503+
14381504 if (register_pernet_subsys (& ipv4_sysctl_ops )) {
14391505 unregister_net_sysctl_table (hdr );
14401506 return - ENOMEM ;
0 commit comments