From 7af1fb9faafbc842fc727c49108f5fc4edc08601 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Mon, 13 Aug 2018 16:24:17 +0200 Subject: [PATCH] kernel: add a RPS balancer By default the RPS delegation will happen by masking the last few bits of skb->hash. This patch adds an inermediate hash bucket that maps the masked hash to a RPS core. This makes RPS results much more deterministic on SMP systems. Signed-off-by: John Crispin --- .../600-net-core-add-RPS-balancer.patch | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 target/linux/generic/hack-4.14/600-net-core-add-RPS-balancer.patch diff --git a/target/linux/generic/hack-4.14/600-net-core-add-RPS-balancer.patch b/target/linux/generic/hack-4.14/600-net-core-add-RPS-balancer.patch new file mode 100644 index 0000000000..6fc52ee25c --- /dev/null +++ b/target/linux/generic/hack-4.14/600-net-core-add-RPS-balancer.patch @@ -0,0 +1,93 @@ +From 3e969c9695b45e1a052d43b367096ec99f2f0aac Mon Sep 17 00:00:00 2001 +From: John Crispin +Date: Thu, 10 Aug 2017 15:58:29 +0200 +Subject: [PATCH] net: core: add RPS balancer + +This patch adds a hash bucket based rps hash balancer. + +Signed-off-by: John Crispin +--- + net/core/dev.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 56 insertions(+), 1 deletion(-) + +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -3626,6 +3626,58 @@ set_rps_cpu(struct net_device *dev, stru + return rflow; + } + ++#define RPS_TBL_SIZE_SHIFT 10 ++#define RPS_TBL_SIZE (1 << RPS_TBL_SIZE_SHIFT) ++struct rps_table { ++ int core; ++ struct timer_list expire; ++}; ++static struct rps_table rps_table[RPS_TBL_SIZE]; ++static int rps_table_last_core; ++ ++static void rps_table_expire(unsigned long data) ++{ ++ struct rps_table *entry = (struct rps_table *) data; ++ ++ entry->core = -1; ++} ++ ++static int rps_table_core(struct rps_map *map) ++{ ++ int i; ++ ++ for (i = 0; i < map->len; i++) { ++ int cpu = map->cpus[(rps_table_last_core + i + 1) % map->len]; ++ if (cpu_online(cpu)) { ++ rps_table_last_core = cpu; ++ return cpu; ++ } ++ } ++ return map->cpus[0]; ++} ++ ++static int rps_table_lookup(struct rps_map *map, u32 hash) ++{ ++ int bucket = hash & 0x3ff; ++ ++ if (rps_table[bucket].core < 0) ++ rps_table[bucket].core = rps_table_core(map); ++ mod_timer(&rps_table[bucket].expire, jiffies + HZ); ++ ++ return rps_table[bucket].core; ++} ++ ++static void rps_table_init(void) ++{ ++ int i; ++ ++ for (i = 0; i < RPS_TBL_SIZE; i++) { ++ rps_table[i].core = -1; ++ setup_timer(&rps_table[i].expire, rps_table_expire, ++ (unsigned long) &rps_table[i]); ++ } ++} ++ + /* + * get_rps_cpu is called from netif_receive_skb and returns the target + * CPU from the RPS map of the receiving queue for a given skb. +@@ -3715,7 +3767,7 @@ static int get_rps_cpu(struct net_device + try_rps: + + if (map) { +- tcpu = map->cpus[reciprocal_scale(hash, map->len)]; ++ tcpu = rps_table_lookup(map, hash); + if (cpu_online(tcpu)) { + cpu = tcpu; + goto done; +@@ -8800,6 +8852,10 @@ static int __init net_dev_init(void) + sd->backlog.weight = weight_p; + } + ++#ifdef CONFIG_RPS ++ rps_table_init(); ++#endif ++ + dev_boot_phase = 0; + + /* The loopback device is special if any other network devices