[PATCH net-next] macsec: introduce default_async_crypto sysctl

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Commit ab046a5d4be4 ("net: macsec: preserve ingress frame ordering")
tried to solve an issue caused by MACsec's use of asynchronous crypto
operations, but introduced a large performance regression in cases
where async crypto isn't causing reordering of packets.

This patch introduces a per-netns sysctl that administrators can set
to allow new SAs to use async crypto, such as aesni. Existing SAs
won't be modified.

By setting default_async_crypto=1 and reconfiguring macsec, a single
netperf instance jumps from 1.4Gbps to 4.4Gbps.

Signed-off-by: Sabrina Dubroca <sd@xxxxxxxxxxxxxxx>
---
 Documentation/admin-guide/sysctl/net.rst |  39 +++++++--
 drivers/net/macsec.c                     | 101 ++++++++++++++++++++---
 2 files changed, 119 insertions(+), 21 deletions(-)

diff --git a/Documentation/admin-guide/sysctl/net.rst b/Documentation/admin-guide/sysctl/net.rst
index 4877563241f3..ce47b612c517 100644
--- a/Documentation/admin-guide/sysctl/net.rst
+++ b/Documentation/admin-guide/sysctl/net.rst
@@ -34,14 +34,14 @@ Table : Subdirectories in /proc/sys/net
  ========= =================== = ========== ===================
  Directory Content               Directory  Content
  ========= =================== = ========== ===================
- 802       E802 protocol         mptcp      Multipath TCP
- appletalk Appletalk protocol    netfilter  Network Filter
- ax25      AX25                  netrom     NET/ROM
- bridge    Bridging              rose       X.25 PLP layer
- core      General parameter     tipc       TIPC
- ethernet  Ethernet protocol     unix       Unix domain sockets
- ipv4      IP version 4          x25        X.25 protocol
- ipv6      IP version 6
+ 802       E802 protocol         macsec     MACsec
+ appletalk Appletalk protocol    mptcp      Multipath TCP
+ ax25      AX25                  netfilter  Network Filter
+ bridge    Bridging              netrom     NET/ROM
+ core      General parameter     rose       X.25 PLP layer
+ ethernet  Ethernet protocol     tipc       TIPC
+ ipv4      IP version 4          unix       Unix domain sockets
+ ipv6      IP version 6          x25        X.25 protocol
  ========= =================== = ========== ===================
 
 1. /proc/sys/net/core - Network core options
@@ -503,3 +503,26 @@ originally may have been issued in the correct sequential order.
 If named_timeout is nonzero, failed topology updates will be placed on a defer
 queue until another event arrives that clears the error, or until the timeout
 expires. Value is in milliseconds.
+
+
+6. /proc/sys/net/macsec - Parameters for MACsec
+-----------------------------------------------
+
+default_async_crypto
+--------------------
+
+The software implementation of MACsec uses the kernel cryptography
+API, which provides both asynchronous and synchronous implementations
+of algorithms. The asynchronous implementations tend to provide better
+performance, but in some cases, can cause reordering of packets.
+
+This only affects newly created Security Associations. Existing SAs
+will be unchanged. Whether a MACsec device was created before or after
+this sysctl is set has no impact.
+
+Values:
+
+	- 0 - disable asynchronous cryptography
+	- 1 - allow asynchronous cryptography (if available)
+
+Default : 0 (only synchronous)
diff --git a/drivers/net/macsec.c b/drivers/net/macsec.c
index ae60817ec5c2..88743ce5839b 100644
--- a/drivers/net/macsec.c
+++ b/drivers/net/macsec.c
@@ -138,6 +138,15 @@ struct macsec_cb {
 	bool has_sci;
 };
 
+static unsigned int macsec_net_id __read_mostly;
+
+struct macsec_net {
+#ifdef CONFIG_SYSCTL
+	struct ctl_table_header *ctl_hdr;
+#endif
+	u8 default_async;
+};
+
 static struct macsec_rx_sa *macsec_rxsa_get(struct macsec_rx_sa __rcu *ptr)
 {
 	struct macsec_rx_sa *sa = rcu_dereference_bh(ptr);
@@ -1325,14 +1334,14 @@ static rx_handler_result_t macsec_handle_frame(struct sk_buff **pskb)
 	return RX_HANDLER_PASS;
 }
 
-static struct crypto_aead *macsec_alloc_tfm(char *key, int key_len, int icv_len)
+static struct crypto_aead *macsec_alloc_tfm(const struct net *net,
+					    char *key, int key_len, int icv_len)
 {
+	struct macsec_net *macsec_net = net_generic(net, macsec_net_id);
 	struct crypto_aead *tfm;
 	int ret;
 
-	/* Pick a sync gcm(aes) cipher to ensure order is preserved. */
-	tfm = crypto_alloc_aead("gcm(aes)", 0, CRYPTO_ALG_ASYNC);
-
+	tfm = crypto_alloc_aead("gcm(aes)", 0, macsec_net->default_async ? 0 : CRYPTO_ALG_ASYNC);
 	if (IS_ERR(tfm))
 		return tfm;
 
@@ -1350,14 +1359,14 @@ static struct crypto_aead *macsec_alloc_tfm(char *key, int key_len, int icv_len)
 	return ERR_PTR(ret);
 }
 
-static int init_rx_sa(struct macsec_rx_sa *rx_sa, char *sak, int key_len,
-		      int icv_len)
+static int init_rx_sa(const struct net *net, struct macsec_rx_sa *rx_sa,
+		      char *sak, int key_len, int icv_len)
 {
 	rx_sa->stats = alloc_percpu(struct macsec_rx_sa_stats);
 	if (!rx_sa->stats)
 		return -ENOMEM;
 
-	rx_sa->key.tfm = macsec_alloc_tfm(sak, key_len, icv_len);
+	rx_sa->key.tfm = macsec_alloc_tfm(net, sak, key_len, icv_len);
 	if (IS_ERR(rx_sa->key.tfm)) {
 		free_percpu(rx_sa->stats);
 		return PTR_ERR(rx_sa->key.tfm);
@@ -1450,14 +1459,14 @@ static struct macsec_rx_sc *create_rx_sc(struct net_device *dev, sci_t sci,
 	return rx_sc;
 }
 
-static int init_tx_sa(struct macsec_tx_sa *tx_sa, char *sak, int key_len,
-		      int icv_len)
+static int init_tx_sa(const struct net *net, struct macsec_tx_sa *tx_sa,
+		      char *sak, int key_len, int icv_len)
 {
 	tx_sa->stats = alloc_percpu(struct macsec_tx_sa_stats);
 	if (!tx_sa->stats)
 		return -ENOMEM;
 
-	tx_sa->key.tfm = macsec_alloc_tfm(sak, key_len, icv_len);
+	tx_sa->key.tfm = macsec_alloc_tfm(net, sak, key_len, icv_len);
 	if (IS_ERR(tx_sa->key.tfm)) {
 		free_percpu(tx_sa->stats);
 		return PTR_ERR(tx_sa->key.tfm);
@@ -1795,7 +1804,7 @@ static int macsec_add_rxsa(struct sk_buff *skb, struct genl_info *info)
 		return -ENOMEM;
 	}
 
-	err = init_rx_sa(rx_sa, nla_data(tb_sa[MACSEC_SA_ATTR_KEY]),
+	err = init_rx_sa(dev_net(dev), rx_sa, nla_data(tb_sa[MACSEC_SA_ATTR_KEY]),
 			 secy->key_len, secy->icv_len);
 	if (err < 0) {
 		kfree(rx_sa);
@@ -2038,7 +2047,7 @@ static int macsec_add_txsa(struct sk_buff *skb, struct genl_info *info)
 		return -ENOMEM;
 	}
 
-	err = init_tx_sa(tx_sa, nla_data(tb_sa[MACSEC_SA_ATTR_KEY]),
+	err = init_tx_sa(dev_net(dev), tx_sa, nla_data(tb_sa[MACSEC_SA_ATTR_KEY]),
 			 secy->key_len, secy->icv_len);
 	if (err < 0) {
 		kfree(tx_sa);
@@ -4168,7 +4177,7 @@ static int macsec_validate_attr(struct nlattr *tb[], struct nlattr *data[],
 			char dummy_key[DEFAULT_SAK_LEN] = { 0 };
 			struct crypto_aead *dummy_tfm;
 
-			dummy_tfm = macsec_alloc_tfm(dummy_key,
+			dummy_tfm = macsec_alloc_tfm(&init_net, dummy_key,
 						     DEFAULT_SAK_LEN,
 						     icv_len);
 			if (IS_ERR(dummy_tfm))
@@ -4380,6 +4389,65 @@ static struct notifier_block macsec_notifier = {
 	.notifier_call = macsec_notify,
 };
 
+#ifdef CONFIG_SYSCTL
+static struct ctl_table macsec_table[] = {
+	{
+		.procname = "default_async_crypto",
+		.maxlen = sizeof(u8),
+		.mode = 0644,
+		.proc_handler = proc_dou8vec_minmax,
+		.extra1 = SYSCTL_ZERO,
+		.extra2 = SYSCTL_ONE,
+	},
+	{ },
+};
+
+static int __net_init macsec_init_net(struct net *net)
+{
+	struct ctl_table *table = macsec_table;
+	struct macsec_net *macsec_net;
+
+	if (!net_eq(net, &init_net)) {
+		table = kmemdup(table, sizeof(macsec_table), GFP_KERNEL);
+		if (!table)
+			return -ENOMEM;
+	}
+
+	macsec_net = net_generic(net, macsec_net_id);
+	table[0].data = &macsec_net->default_async;
+	macsec_net->default_async = 0;
+
+	macsec_net->ctl_hdr = register_net_sysctl(net, "net/macsec", table);
+	if (!macsec_net->ctl_hdr)
+		goto free;
+
+	return 0;
+
+free:
+	if (!net_eq(net, &init_net))
+		kfree(table);
+	return -ENOMEM;
+}
+
+static void __net_exit macsec_exit_net(struct net *net)
+{
+	struct macsec_net *macsec_net = net_generic(net, macsec_net_id);
+
+	unregister_net_sysctl_table(macsec_net->ctl_hdr);
+	if (!net_eq(net, &init_net))
+		kfree(macsec_net->ctl_hdr->ctl_table_arg);
+}
+#endif
+
+static struct pernet_operations macsec_net_ops __read_mostly = {
+#ifdef CONFIG_SYSCTL
+	.init = macsec_init_net,
+	.exit = macsec_exit_net,
+#endif
+	.id   = &macsec_net_id,
+	.size = sizeof(struct macsec_net),
+};
+
 static int __init macsec_init(void)
 {
 	int err;
@@ -4397,8 +4465,14 @@ static int __init macsec_init(void)
 	if (err)
 		goto rtnl;
 
+	err = register_pernet_subsys(&macsec_net_ops);
+	if (err)
+		goto genl;
+
 	return 0;
 
+genl:
+	genl_unregister_family(&macsec_fam);
 rtnl:
 	rtnl_link_unregister(&macsec_link_ops);
 notifier:
@@ -4408,6 +4482,7 @@ static int __init macsec_init(void)
 
 static void __exit macsec_exit(void)
 {
+	unregister_pernet_subsys(&macsec_net_ops);
 	genl_unregister_family(&macsec_fam);
 	rtnl_link_unregister(&macsec_link_ops);
 	unregister_netdevice_notifier(&macsec_notifier);
-- 
2.40.1




[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux FS]     [Yosemite Forum]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux