Netdev List
 help / color / mirror / Atom feed
* [PATCH v2] netfilter: ebtables: Use %pM conversion specifier
From: Tobias Klauser @ 2009-07-16  7:25 UTC (permalink / raw)
  To: bart.de.schuymer, shemminger, kaber, davem, netfilter-devel
  Cc: netdev, Tobias Klauser
In-Reply-To: <1247655306-21337-1-git-send-email-klto@zhaw.ch>

ebt_log uses its own implementation of print_mac to print MAC addresses.
This patch converts it to use the %pM conversion specifier for printk.

Signed-off-by: Tobias Klauser <klto@zhaw.ch>
---
 net/bridge/netfilter/ebt_log.c |   29 +++++++----------------------
 1 files changed, 7 insertions(+), 22 deletions(-)

diff --git a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c
index a94f3cc..e4ea3fd 100644
--- a/net/bridge/netfilter/ebt_log.c
+++ b/net/bridge/netfilter/ebt_log.c
@@ -50,14 +50,6 @@ struct arppayload
 	unsigned char ip_dst[4];
 };
 
-static void print_MAC(const unsigned char *p)
-{
-	int i;
-
-	for (i = 0; i < ETH_ALEN; i++, p++)
-		printk("%02x%c", *p, i == ETH_ALEN - 1 ? ' ':':');
-}
-
 static void
 print_ports(const struct sk_buff *skb, uint8_t protocol, int offset)
 {
@@ -88,14 +80,11 @@ ebt_log_packet(u_int8_t pf, unsigned int hooknum,
 	unsigned int bitmask;
 
 	spin_lock_bh(&ebt_log_lock);
-	printk("<%c>%s IN=%s OUT=%s MAC source = ", '0' + loginfo->u.log.level,
-	       prefix, in ? in->name : "", out ? out->name : "");
-
-	print_MAC(eth_hdr(skb)->h_source);
-	printk("MAC dest = ");
-	print_MAC(eth_hdr(skb)->h_dest);
-
-	printk("proto = 0x%04x", ntohs(eth_hdr(skb)->h_proto));
+	printk("<%c>%s IN=%s OUT=%s MAC source = %pM MAC dest = %pM proto = 0x%04x",
+	       '0' + loginfo->u.log.level, prefix,
+	       in ? in->name : "", out ? out->name : "",
+	       eth_hdr(skb)->h_source, eth_hdr(skb)->h_dest,
+	       ntohs(eth_hdr(skb)->h_proto));
 
 	if (loginfo->type == NF_LOG_TYPE_LOG)
 		bitmask = loginfo->u.log.logflags;
@@ -171,12 +160,8 @@ ebt_log_packet(u_int8_t pf, unsigned int hooknum,
 				printk(" INCOMPLETE ARP payload");
 				goto out;
 			}
-			printk(" ARP MAC SRC=");
-			print_MAC(ap->mac_src);
-			printk(" ARP IP SRC=%pI4", ap->ip_src);
-			printk(" ARP MAC DST=");
-			print_MAC(ap->mac_dst);
-			printk(" ARP IP DST=%pI4", ap->ip_dst);
+			printk(" ARP MAC SRC=%pM ARP IP SRC=%pI4 ARP MAC DST=%pM ARP IP DST=%pI4",
+					ap->mac_src, ap->ip_src, ap->mac_dst, ap->ip_dst);
 		}
 	}
 out:
-- 
1.6.0.4


^ permalink raw reply related

* Re: e1000e 2.6.30.1 massive packet loss
From: Eric Dumazet @ 2009-07-16  8:04 UTC (permalink / raw)
  To: Caleb Cushing; +Cc: Linux Kernel Mailing List, Linux Netdev List
In-Reply-To: <81bfc67a0907160049q3d43093cy52276f0fe1157d89@mail.gmail.com>

Caleb Cushing a écrit :
> So from 2.6.30 to .1 I noticed that via an icmp test (mtr) 20-50%
> packet loss web browsing became impractical (downgrading fixed the
> issue). I'm wondering if the change to the driver (w/ msi) is the
> cause? also wondering if this is known and will be fixed in .2 I can
> provide more information if necessary.
> 

Added netdev to get more attention to this.

What do you call 20-50% packet loss ?
(Losses to icmp flood itself, or tcp losses ?
Is the machine answering to icmp flood, or is it the origin ?

Are you saying packet loss was not occurring with 2.6.30 ?

Could you describe your methodology ?

You could give us results of "cat /proc/interrupts" from both
versions, because it sounds as an interrupt affinity problem.

# cat /proc/interrupts
# tc -s -d qdisc
# ifconfig -a

^ permalink raw reply

* Re: e1000e 2.6.30.1 massive packet loss
From: Caleb Cushing @ 2009-07-16  8:20 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: Linux Kernel Mailing List, Linux Netdev List
In-Reply-To: <4A5EDEF7.7090303@cosmosbay.com>

> What do you call 20-50% packet loss ?

sorry that's just the approximate average loss mtr was reporting. I
realize it's not the most accurate test, but I have no problems before
changing to .1 or after downgrading from it.

> (Losses to icmp flood itself, or tcp losses ?
> Is the machine answering to icmp flood, or is it the origin ?

mtr uses all icmp, but considering web browsing and I'm sure even dns
was affected I'd say all of it. I haven't done further investigation.
it was the origin and the losses occured between my desktop
machine(2.6.31.x) and my linksys wrt54gl(on openwrt) router. Since I
know the cable is good, and the losses haven't happened before or
since, and I even tried rebooting the router, I'm fairly confident
that it's a result of changes between the 2 kernel versions.

> Are you saying packet loss was not occurring with 2.6.30 ?

yes.

> Could you describe your methodology ?
>
> You could give us results of "cat /proc/interrupts" from both
> versions, because it sounds as an interrupt affinity problem.

these are from 2.6.30 I'll send .1 in a bit.
> # cat /proc/interrupts


           CPU0       CPU1       CPU2       CPU3
  0:       1605          0          0          0    XT-PIC-XT        timer
  1:          2          0          0          0    XT-PIC-XT        i8042
  2:          0          0          0          0    XT-PIC-XT        cascade
  4:          3          0          0          0    XT-PIC-XT        ohci1394
  5:   40347741          0          0          0    XT-PIC-XT
uhci_hcd:usb3, EMU10K1
  6:          2          0          0          0    XT-PIC-XT        floppy
  8:       4738          0          0          0    XT-PIC-XT        rtc0
  9:          0          0          0          0    XT-PIC-XT
acpi, ehci_hcd:usb2, uhci_hcd:usb6
 10:          0          0          0          0    XT-PIC-XT
uhci_hcd:usb4
 11:     923781          0          0          0    XT-PIC-XT
ehci_hcd:usb1, uhci_hcd:usb5, uhci_hcd:usb7, uhci_hcd:usb8
 12:          4          0          0          0    XT-PIC-XT        i8042
 25:     428267     425244     423627     427244   PCI-MSI-edge      i915
 26:    1194972    1211065    1191149    1200914   PCI-MSI-edge      ahci
 27:    7287597    7270695    7291505    7280533   PCI-MSI-edge      eth0
NMI:          0          0          0          0   Non-maskable interrupts
LOC:   66007880   72160316   45190647   33707930   Local timer interrupts
SPU:          0          0          0          0   Spurious interrupts
RES:      67599      68493      54742      53268   Rescheduling interrupts
CAL:        288        295        363        323   Function call interrupts
TLB:     133835      49505      43942      48309   TLB shootdowns
TRM:          0          0          0          0   Thermal event interrupts
THR:          0          0          0          0   Threshold APIC interrupts
ERR:          0
MIS:          0

> # tc -s -d qdisc

qdisc pfifo_fast 0: dev eth0 root bands 3 priomap  1 2 2 2 1 2 0 0 1 1
1 1 1 1 1 1
 Sent 33951429966 bytes 12436885 pkt (dropped 0, overlimits 0 requeues 1375)
 rate 0bit 0pps backlog 0b 0p requeues 1375

> # ifconfig -a

eth0      Link encap:Ethernet  HWaddr 00:21:9B:06:4C:C9
          inet addr:192.168.1.3  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: fe80::221:9bff:fe06:4cc9/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:16135626 errors:0 dropped:0 overruns:0 frame:0
          TX packets:28308711 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:100
          RX bytes:2181880167 (2080.8 Mb)  TX bytes:34811667228 (33198.9 Mb)
          Memory:fdfc0000-fdfe0000

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:92471 errors:0 dropped:0 overruns:0 frame:0
          TX packets:92471 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:11927979 (11.3 Mb)  TX bytes:11927979 (11.3 Mb)




-- 
Caleb Cushing

http://xenoterracide.blogspot.com

^ permalink raw reply

* [PATCH 1/8] gianfar: Remove unused DECLARE_MAC_BUF
From: Tobias Klauser @ 2009-07-16  8:51 UTC (permalink / raw)
  To: davem, afleming, galak, netdev; +Cc: Tobias Klauser

Is not needed anymore because of the %pM printk conversion specifier.

Signed-off-by: Tobias Klauser <klto@zhaw.ch>
---
 drivers/net/gianfar.c |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index 4ae1d25..21f5b0a 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -304,7 +304,6 @@ static int gfar_probe(struct of_device *ofdev,
 	u32 tempval;
 	struct net_device *dev = NULL;
 	struct gfar_private *priv = NULL;
-	DECLARE_MAC_BUF(mac);
 	int err = 0;
 	int len_devname;
 
-- 
1.6.0.4


^ permalink raw reply related

* [PATCH 2/8] ar9170: Remove unused DECLARE_MAC_BUF
From: Tobias Klauser @ 2009-07-16  8:53 UTC (permalink / raw)
  To: chunkeey, linville, johannes, lrodriguez, yi.zhu, linux-wireless,
	netdev
  Cc: Tobias Klauser

Is not needed anymore because of the %pM printk conversion specifier.

Signed-off-by: Tobias Klauser <klto@zhaw.ch>
---
 drivers/net/wireless/ath/ar9170/main.c |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)

diff --git a/drivers/net/wireless/ath/ar9170/main.c b/drivers/net/wireless/ath/ar9170/main.c
index 9d38cf6..3d6373a 100644
--- a/drivers/net/wireless/ath/ar9170/main.c
+++ b/drivers/net/wireless/ath/ar9170/main.c
@@ -2085,7 +2085,6 @@ static int ar9170_read_eeprom(struct ar9170 *ar)
 {
 #define RW	8	/* number of words to read at once */
 #define RB	(sizeof(u32) * RW)
-	DECLARE_MAC_BUF(mbuf);
 	u8 *eeprom = (void *)&ar->eeprom;
 	u8 *addr = ar->eeprom.mac_address;
 	__le32 offsets[RW];
-- 
1.6.0.4


^ permalink raw reply related

* [PATCH 3/8] b43: Use %pM conversion specifier
From: Tobias Klauser @ 2009-07-16  8:56 UTC (permalink / raw)
  To: stefano.brivio, mb, linville, johannes, linux-wireless, netdev
  Cc: Tobias Klauser

Use the %pM conversion specifier for printk instead of print_mac.

Signed-off-by: Tobias Klauser <klto@zhaw.ch>
---
 drivers/net/wireless/b43/main.c |    4 +---
 1 files changed, 1 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index e71c8d9..3f4360a 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -938,7 +938,6 @@ static void b43_clear_keys(struct b43_wldev *dev)
 static void b43_dump_keymemory(struct b43_wldev *dev)
 {
 	unsigned int i, index, offset;
-	DECLARE_MAC_BUF(macbuf);
 	u8 mac[ETH_ALEN];
 	u16 algo;
 	u32 rcmta0;
@@ -973,8 +972,7 @@ static void b43_dump_keymemory(struct b43_wldev *dev)
 						((index - 4) * 2) + 1);
 			*((__le32 *)(&mac[0])) = cpu_to_le32(rcmta0);
 			*((__le16 *)(&mac[4])) = cpu_to_le16(rcmta1);
-			printk("   MAC: %s",
-			       print_mac(macbuf, mac));
+			printk("   MAC: %pM", mac);
 		} else
 			printk("   DEFAULT KEY");
 		printk("\n");
-- 
1.6.0.4


^ permalink raw reply related

* [PATCH 4/8] libertas: Use %pM conversion specifier
From: Tobias Klauser @ 2009-07-16  8:56 UTC (permalink / raw)
  To: dcbw, linville, johannes, proski, davem, libertas-dev, netdev
  Cc: Tobias Klauser

Use the %pM conversion specifier for printk instead of print_mac.

Signed-off-by: Tobias Klauser <klto@zhaw.ch>
---
 drivers/net/wireless/libertas/assoc.c |   10 +++-------
 1 files changed, 3 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c
index b9b3741..a953647 100644
--- a/drivers/net/wireless/libertas/assoc.c
+++ b/drivers/net/wireless/libertas/assoc.c
@@ -129,7 +129,6 @@ static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth
 {
 	struct cmd_ds_802_11_authenticate cmd;
 	int ret = -1;
-	DECLARE_MAC_BUF(mac);
 
 	lbs_deb_enter(LBS_DEB_JOIN);
 
@@ -138,8 +137,7 @@ static int lbs_set_authentication(struct lbs_private *priv, u8 bssid[6], u8 auth
 
 	cmd.authtype = iw_auth_to_ieee_auth(auth);
 
-	lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n",
-		print_mac(mac, bssid), cmd.authtype);
+	lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n", bssid, cmd.authtype);
 
 	ret = lbs_cmd_with_response(priv, CMD_802_11_AUTHENTICATE, &cmd);
 
@@ -342,8 +340,6 @@ static int lbs_associate(struct lbs_private *priv,
 
 	/* Firmware v9+ indicate authentication suites as a TLV */
 	if (priv->fwrelease >= 0x09000000) {
-		DECLARE_MAC_BUF(mac);
-
 		auth = (struct mrvl_ie_auth_type *) pos;
 		auth->header.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
 		auth->header.len = cpu_to_le16(2);
@@ -351,8 +347,8 @@ static int lbs_associate(struct lbs_private *priv,
 		auth->auth = cpu_to_le16(tmpauth);
 		pos += sizeof(auth->header) + 2;
 
-		lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n",
-			print_mac(mac, bss->bssid), priv->secinfo.auth_mode);
+		lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n",
+			bss->bssid, priv->secinfo.auth_mode);
 	}
 
 	/* WPA/WPA2 IEs */
-- 
1.6.0.4


^ permalink raw reply related

* [PATCH 5/8] mac80211_hwsim: Remove unused DECLARE_MAC_BUF
From: Tobias Klauser @ 2009-07-16  8:57 UTC (permalink / raw)
  To: linville, johannes, jouni.malinen, lrodriguez, davem, netdev
  Cc: Tobias Klauser

Is not needed anymore because of the %pM printk conversion specifier.

Signed-off-by: Tobias Klauser <klto@zhaw.ch>
---
 drivers/net/wireless/mac80211_hwsim.c |    2 --
 1 files changed, 0 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index a111bda..08cfd4b 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -757,7 +757,6 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)
 {
 	struct mac80211_hwsim_data *data = dat;
 	struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
-	DECLARE_MAC_BUF(buf);
 	struct sk_buff *skb;
 	struct ieee80211_pspoll *pspoll;
 
@@ -787,7 +786,6 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,
 				struct ieee80211_vif *vif, int ps)
 {
 	struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
-	DECLARE_MAC_BUF(buf);
 	struct sk_buff *skb;
 	struct ieee80211_hdr *hdr;
 
-- 
1.6.0.4


^ permalink raw reply related

* [PATCH 6/8] mwl8k: Use %pM conversion specifier
From: Tobias Klauser @ 2009-07-16  8:58 UTC (permalink / raw)
  To: linville, johannes, ramirose, buytenh, jal2, netdev; +Cc: Tobias Klauser

Use the %pM conversion specifier for printk instead of print_mac.

Also remove an unused DECLARE_MAC_BUF declaration.

Signed-off-by: Tobias Klauser <klto@zhaw.ch>
---
 drivers/net/wireless/mwl8k.c |    6 ++----
 1 files changed, 2 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index a263d5c..43dcfaf 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -2270,7 +2270,6 @@ static int mwl8k_cmd_update_sta_db(struct ieee80211_hw *hw,
 	struct mwl8k_cmd_update_sta_db *cmd;
 	struct peer_capability_info *peer_info;
 	struct ieee80211_rate *bitrates = mv_vif->legacy_rates;
-	DECLARE_MAC_BUF(mac);
 	int rc;
 	__u8 count, *rates;
 
@@ -3479,7 +3478,6 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 {
 	struct ieee80211_hw *hw;
 	struct mwl8k_priv *priv;
-	DECLARE_MAC_BUF(mac);
 	int rc;
 	int i;
 	u8 *fw;
@@ -3668,8 +3666,8 @@ static int __devinit mwl8k_probe(struct pci_dev *pdev,
 		MWL8K_DESC);
 	printk(KERN_INFO "%s: Driver Ver:%s  Firmware Ver:%u.%u.%u.%u\n",
 		priv->name, MWL8K_VERSION, fw[3], fw[2], fw[1], fw[0]);
-	printk(KERN_INFO "%s: MAC Address: %s\n", priv->name,
-	       print_mac(mac, hw->wiphy->perm_addr));
+	printk(KERN_INFO "%s: MAC Address: %pM\n", priv->name,
+		hw->wiphy->perm_addr);
 
 	return 0;
 
-- 
1.6.0.4


^ permalink raw reply related

* [PATCH 7/8] rt2x00: Use %pM conversion specifier
From: Tobias Klauser @ 2009-07-16  9:00 UTC (permalink / raw)
  To: linville, IvDoorn, netdev, linux-wireless, users; +Cc: Tobias Klauser

Use the %pM conversion specifier for printk instead of print_mac.

Signed-off-by: Tobias Klauser <klto@zhaw.ch>
---
 drivers/net/wireless/rt2x00/rt2800usb.c |    4 +---
 1 files changed, 1 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 3756166..da84afb 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -2224,10 +2224,8 @@ static int rt2800usb_validate_eeprom(struct rt2x00_dev *rt2x00dev)
 	 */
 	mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0);
 	if (!is_valid_ether_addr(mac)) {
-		DECLARE_MAC_BUF(macbuf);
-
 		random_ether_addr(mac);
-		EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac));
+		EEPROM(rt2x00dev, "MAC: %pM\n", mac);
 	}
 
 	rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word);
-- 
1.6.0.4


^ permalink raw reply related

* [PATCH 8/8] wl12xx: Use %pM conversion specifier
From: Tobias Klauser @ 2009-07-16  9:01 UTC (permalink / raw)
  To: linville, kalle.valo, me, netdev; +Cc: Tobias Klauser

Use the %pM conversion specifier for printk instead of print_mac.

Signed-off-by: Tobias Klauser <klto@zhaw.ch>
---
 drivers/net/wireless/wl12xx/main.c |    5 ++---
 1 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 603d611..5962c4f 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -423,11 +423,10 @@ static int wl12xx_op_add_interface(struct ieee80211_hw *hw,
 				   struct ieee80211_if_init_conf *conf)
 {
 	struct wl12xx *wl = hw->priv;
-	DECLARE_MAC_BUF(mac);
 	int ret = 0;
 
-	wl12xx_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %s",
-		     conf->type, print_mac(mac, conf->mac_addr));
+	wl12xx_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
+		     conf->type, conf->mac_addr);
 
 	mutex_lock(&wl->mutex);
 
-- 
1.6.0.4


^ permalink raw reply related

* Re: e1000e 2.6.30.1 massive packet loss
From: Caleb Cushing @ 2009-07-16  9:05 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: Linux Kernel Mailing List, Linux Netdev List
In-Reply-To: <81bfc67a0907160120i2528d9abq6c1bd6ffbae8a433@mail.gmail.com>

2.6.30.1 with the issue.

           CPU0       CPU1       CPU2       CPU3
  0:         36          0          0          0    XT-PIC-XT        timer
  1:          2          0          0          0    XT-PIC-XT        i8042
  2:          0          0          0          0    XT-PIC-XT        cascade
  4:          3          0          0          0    XT-PIC-XT        ohci1394
  5:        392          0          0          0    XT-PIC-XT
uhci_hcd:usb2, EMU10K1
  6:          2          0          0          0    XT-PIC-XT        floppy
  8:        163          0          0          0    XT-PIC-XT        rtc0
  9:          0          0          0          0    XT-PIC-XT
acpi, ehci_hcd:usb3, uhci_hcd:usb6
 10:          0          0          0          0    XT-PIC-XT
uhci_hcd:usb4
 11:       1318          0          0          0    XT-PIC-XT
ehci_hcd:usb1, uhci_hcd:usb5, uhci_hcd:usb7, uhci_hcd:usb8
 12:          4          0          0          0    XT-PIC-XT        i8042
 25:        801        812        813        785   PCI-MSI-edge      i915
 26:       3233       3217       3261       3263   PCI-MSI-edge      ahci
 27:        199        200        184        173   PCI-MSI-edge      eth0
NMI:          0          0          0          0   Non-maskable interrupts
LOC:      14886      16536      13854      15765   Local timer interrupts
SPU:          0          0          0          0   Spurious interrupts
RES:        504        515        358        397   Rescheduling interrupts
CAL:         55         79         74         44   Function call interrupts
TLB:        649       1202        685        902   TLB shootdowns
TRM:          0          0          0          0   Thermal event interrupts
THR:          0          0          0          0   Threshold APIC interrupts
ERR:          0
MIS:          0

qdisc pfifo_fast 0: dev eth0 root bands 3 priomap  1 2 2 2 1 2 0 0 1 1
1 1 1 1 1 1
 Sent 82807 bytes 499 pkt (dropped 0, overlimits 0 requeues 0)
 rate 0bit 0pps backlog 0b 0p requeues 0

eth0      Link encap:Ethernet  HWaddr 00:21:9B:06:4C:C9
          inet addr:192.168.1.3  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: fe80::221:9bff:fe06:4cc9/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:366 errors:0 dropped:0 overruns:0 frame:0
          TX packets:519 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:100
          RX bytes:130219 (127.1 Kb)  TX bytes:86900 (84.8 Kb)
          Memory:fdfc0000-fdfe0000

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:817 errors:0 dropped:0 overruns:0 frame:0
          TX packets:817 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:55043 (53.7 Kb)  TX bytes:55043 (53.7 Kb)

^ permalink raw reply

* [PATCH] net: sock_copy() fixes
From: Eric Dumazet @ 2009-07-16  9:13 UTC (permalink / raw)
  To: David Miller; +Cc: Patrick McHardy, netdev, paulmck
In-Reply-To: <4A5E33D9.2030602@gmail.com>

David, I believe following patch could be 2.6.31 candidate
(and stable (2.6.29/2.6.30) as well)

Note : Because we clear all sock fields in sk_prot_alloc(),
setting sk_refcnt to 1 in sock_init_data() is safe, even if
sock not yet added to hash table (with correct keys).
Lockless readers have to re-check their key after getting a
reference on the found object anyway, their re-check
should not catch old key values.

Next problem to fix (but it can wait 2.6.32 I believe) is
to delay sk_refcnt initialization *after* sock lookup keys
are setup for new socket, not after being set to 0.

A lockless reader could :
- find an old sock, with old keys
      (at this point, another cpu re-allocate this sock, clear fields,
       and sets sk_refcnt to 1)
- succeed to increment sk_refcnt
      (at this point, other cpu is filling lookup fields (remote address/port, local address...)
- re-check keys and find a match, while socket still being initialized by other cpu.

Only way to fix this is to set sk_refcnt to a non null value only at the
point it is safe for a reader to find the socket and use it.

Thanks

[PATCH] net: sock_copy() fixes

Commit e912b1142be8f1e2c71c71001dc992c6e5eb2ec1
(net: sk_prot_alloc() should not blindly overwrite memory)
took care of not zeroing whole new socket at allocation time.

sock_copy() is another spot where we should be very careful.
We should not set refcnt to a non null value, until
we are sure other fields are correctly setup, or
a lockless reader could catch this socket by mistake,
while not fully (re)initialized.

This patch puts sk_node & sk_refcnt to the very beginning
of struct sock to ease sock_copy() & sk_prot_alloc() job.

We add appropriate smp_wmb() before sk_refcnt initializations
to match our RCU requirements (changes to sock keys should
be committed to memory before sk_refcnt setting)

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
 include/net/sock.h |   32 +++++++++++++++++++-------------
 net/core/sock.c    |   20 ++++++++++++++++++--
 2 files changed, 37 insertions(+), 15 deletions(-)

diff --git a/include/net/sock.h b/include/net/sock.h
index 2c0da92..ae0906e 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -104,15 +104,15 @@ struct net;
 
 /**
  *	struct sock_common - minimal network layer representation of sockets
+ *	@skc_node: main hash linkage for various protocol lookup tables
+ *	@skc_nulls_node: main hash linkage for UDP/UDP-Lite protocol
+ *	@skc_refcnt: reference count
+ *	@skc_hash: hash value used with various protocol lookup tables
  *	@skc_family: network address family
  *	@skc_state: Connection state
  *	@skc_reuse: %SO_REUSEADDR setting
  *	@skc_bound_dev_if: bound device index if != 0
- *	@skc_node: main hash linkage for various protocol lookup tables
- *	@skc_nulls_node: main hash linkage for UDP/UDP-Lite protocol
  *	@skc_bind_node: bind hash linkage for various protocol lookup tables
- *	@skc_refcnt: reference count
- *	@skc_hash: hash value used with various protocol lookup tables
  *	@skc_prot: protocol handlers inside a network family
  *	@skc_net: reference to the network namespace of this socket
  *
@@ -120,17 +120,21 @@ struct net;
  *	for struct sock and struct inet_timewait_sock.
  */
 struct sock_common {
-	unsigned short		skc_family;
-	volatile unsigned char	skc_state;
-	unsigned char		skc_reuse;
-	int			skc_bound_dev_if;
+	/*
+	 * first fields are not copied in sock_copy()
+	 */
 	union {
 		struct hlist_node	skc_node;
 		struct hlist_nulls_node skc_nulls_node;
 	};
-	struct hlist_node	skc_bind_node;
 	atomic_t		skc_refcnt;
+
 	unsigned int		skc_hash;
+	unsigned short		skc_family;
+	volatile unsigned char	skc_state;
+	unsigned char		skc_reuse;
+	int			skc_bound_dev_if;
+	struct hlist_node	skc_bind_node;
 	struct proto		*skc_prot;
 #ifdef CONFIG_NET_NS
 	struct net	 	*skc_net;
@@ -208,15 +212,17 @@ struct sock {
 	 * don't add nothing before this first member (__sk_common) --acme
 	 */
 	struct sock_common	__sk_common;
+#define sk_node			__sk_common.skc_node
+#define sk_nulls_node		__sk_common.skc_nulls_node
+#define sk_refcnt		__sk_common.skc_refcnt
+
+#define sk_copy_start		__sk_common.skc_hash
+#define sk_hash			__sk_common.skc_hash
 #define sk_family		__sk_common.skc_family
 #define sk_state		__sk_common.skc_state
 #define sk_reuse		__sk_common.skc_reuse
 #define sk_bound_dev_if		__sk_common.skc_bound_dev_if
-#define sk_node			__sk_common.skc_node
-#define sk_nulls_node		__sk_common.skc_nulls_node
 #define sk_bind_node		__sk_common.skc_bind_node
-#define sk_refcnt		__sk_common.skc_refcnt
-#define sk_hash			__sk_common.skc_hash
 #define sk_prot			__sk_common.skc_prot
 #define sk_net			__sk_common.skc_net
 	kmemcheck_bitfield_begin(flags);
diff --git a/net/core/sock.c b/net/core/sock.c
index ba5d211..d9eec15 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -919,13 +919,19 @@ static inline void sock_lock_init(struct sock *sk)
 			af_family_keys + sk->sk_family);
 }
 
+/*
+ * Copy all fields from osk to nsk but nsk->sk_refcnt must not change yet,
+ * even temporarly, because of RCU lookups. sk_node should also be left as is.
+ */
 static void sock_copy(struct sock *nsk, const struct sock *osk)
 {
 #ifdef CONFIG_SECURITY_NETWORK
 	void *sptr = nsk->sk_security;
 #endif
-
-	memcpy(nsk, osk, osk->sk_prot->obj_size);
+	BUILD_BUG_ON(offsetof(struct sock, sk_copy_start) !=
+		     sizeof(osk->sk_node) + sizeof(osk->sk_refcnt));
+	memcpy(&nsk->sk_copy_start, &osk->sk_copy_start,
+	       osk->sk_prot->obj_size - offsetof(struct sock, sk_copy_start));
 #ifdef CONFIG_SECURITY_NETWORK
 	nsk->sk_security = sptr;
 	security_sk_clone(osk, nsk);
@@ -1140,6 +1146,11 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority)
 
 		newsk->sk_err	   = 0;
 		newsk->sk_priority = 0;
+		/*
+		 * Before updating sk_refcnt, we must commit prior changes to memory
+		 * (Documentation/RCU/rculist_nulls.txt for details)
+		 */
+		smp_wmb();
 		atomic_set(&newsk->sk_refcnt, 2);
 
 		/*
@@ -1855,6 +1866,11 @@ void sock_init_data(struct socket *sock, struct sock *sk)
 
 	sk->sk_stamp = ktime_set(-1L, 0);
 
+	/*
+	 * Before updating sk_refcnt, we must commit prior changes to memory
+	 * (Documentation/RCU/rculist_nulls.txt for details)
+	 */
+	smp_wmb();
 	atomic_set(&sk->sk_refcnt, 1);
 	atomic_set(&sk->sk_wmem_alloc, 1);
 	atomic_set(&sk->sk_drops, 0);

^ permalink raw reply related

* Re: Achieved 10Gbit/s bidirectional routing
From: Jesper Dangaard Brouer @ 2009-07-16  9:39 UTC (permalink / raw)
  To: Bill Fink
  Cc: netdev@vger.kernel.org, David S. Miller, Robert Olsson,
	Waskiewicz Jr, Peter P, Ronciak, John, jesse.brandeburg,
	Stephen Hemminger, Linux Kernel Mailing List
In-Reply-To: <20090715232253.91d9f264.billfink@mindspring.com>

On Wed, 2009-07-15 at 23:22 -0400, Bill Fink wrote:
> On Wed, 15 Jul 2009, Jesper Dangaard Brouer wrote:
> 
> > I'm giving a talk at LinuxCon, about 10Gbit/s routing on standard
> > hardware running Linux.
> > 
> >   http://linuxcon.linuxfoundation.org/meetings/1585
> >   https://events.linuxfoundation.org/lc09o17
> > 
> > I'm getting some really good 10Gbit/s bidirectional routing results
> > with Intels latest 82599 chip. (I got two pre-release engineering
> > samples directly from Intel, thanks Peter)
> > 
> > Using a Core i7-920, and tuning the memory according to the RAMs
> > X.M.P. settings DDR3-1600MHz, notice this also increases the QPI to
> > 6.4GT/s.  (Motherboard P6T6 WS revolution)
> > 
> > With big 1514 bytes packets, I can basically do 10Gbit/s wirespeed
> > bidirectional routing.
> > 
> > Notice bidirectional routing means that we actually has to move approx
> > 40Gbit/s through memory and in-and-out of the interfaces.
> > 
> > Formatted quick view using 'ifstat -b'
> > 
> >   eth31-in   eth31-out   eth32-in  eth32-out
> >     9.57  +    9.52  +     9.51 +     9.60  = 38.20 Gbit/s
> >     9.60  +    9.55  +     9.52 +     9.62  = 38.29 Gbit/s
> >     9.61  +    9.53  +     9.52 +     9.62  = 38.28 Gbit/s
> >     9.61  +    9.53  +     9.54 +     9.62  = 38.30 Gbit/s
> > 
> > [Adding an extra NIC]
> > 
> > Another observation is that I'm hitting some kind of bottleneck on the
> > PCI-express switch.  Adding an extra NIC in a PCIe slot connected to
> > the same PCIe switch, does not scale beyond 40Gbit/s collective
> > throughput.

Correcting my self, according to Bill's info below.

It does not scale when adding an extra NIC to the same NVIDIA NF200 PCIe
switch chip (reason explained below by Bill)

 
> > But, I happened to have a special motherboard ASUS P6T6 WS revolution,
> > which has an additional PCIe switch chip NVIDIA's NF200.
> > 
> > Connecting two dual port 10GbE NICs via two different PCI-express
> > switch chips, makes things scale again!  I have achieved a collective
> > throughput of 66.25 Gbit/s.  This results is also influenced by my
> > pktgen machines cannot keep up, and I'm getting closer to the memory
> > bandwidth limits.
> > 
> > FYI: I found a really good reference explaining the PCI-express
> > architecture, written by Intel:
> > 
> >  http://download.intel.com/design/intarch/papers/321071.pdf
> > 
> > I'm not sure how to explain the PCI-express chip bottleneck I'm
> > seeing, but my guess is that I'm limited by the number of outstanding
> > packets/DMA-transfers and the latency for the DMA operations.
> > 
> > Does any one have datasheets on the X58 and NVIDIA's NF200 PCI-express
> > chips, that can tell me the number of outstanding transfers they
> > support?
> 
> We've achieved 70 Gbps aggregate unidirectional TCP performance from
> one P6T6 based system to another.  We figured out in our case that
> we were being limited by the interconnect between the Intel X58 and
> Nvidia N200 chips.  The first 2 PCIe 2.0 slots are directly off the
> Intel X58 and get the full 40 Gbps throughput from the dual-port
> Myricom 10-GigE NICs we have installed in them.  But the other
> 3 PCIe 2.0 slots are on the Nvidia N200 chip, and I discovered
> through googling that the link between the X58 and N200 chips
> only operates at PCIe x16 _1.0_ speed, which limits the possible
> aggregate throughput of the last 3 PCIe 2.0 slots to only 32 Gbps.

This definitly explains the bottlenecks I have seen! Thanks!

Yes, it seems to scale when installing the two NICs in the first two
slots, both connected to the X58.  If overclocking the RAM and CPU a
bit, I can match my pktgen machines speed which gives a collective
throughput of 67.95 Gbit/s.

   eth33          eth34          eth31         eth32
 in     out     in     out     in    out     in    out 
7.54 + 9.58  + 9.56 + 7.56  + 7.33 + 9.53 + 9.50 + 7.35  = 67.95 Gbit/s

Now I just need a faster generator machine, to find the next bottleneck ;-)


> This was clearly seen in our nuttcp testing:
> 
> [root@i7raid-1 ~]# ./nuttcp-6.2.6 -In2 -xc0/0 -p5001 192.168.1.11 & ./nuttcp-6.2.6 -In3 -xc0/0 -p5002 192.168.2.11 & ./nuttcp-6.2.6 -In4 -xc1/1 -p5003 192.168.3.11 & ./nuttcp-6.2.6 -In5 -xc1/1 -p5004 192.168.4.11 & ./nuttcp-6.2.6 -In6 -xc2/2 -p5005 192.168.5.11 & ./nuttcp-6.2.6 -In7 -xc2/2 -p5006 192.168.6.11 & ./nuttcp-6.2.6 -In8 -xc3/3 -p5007 192.168.7.11 & ./nuttcp-6.2.6 -In9 -xc3/3 -p5008 192.168.8.11
> n2: 11505.2648 MB /  10.09 sec = 9566.2298 Mbps 37 %TX 55 %RX 0 retrans 0.10 msRTT
> n3: 11727.4489 MB /  10.02 sec = 9815.7570 Mbps 39 %TX 44 %RX 0 retrans 0.10 msRTT
> n4: 11770.1250 MB /  10.07 sec = 9803.9901 Mbps 39 %TX 51 %RX 0 retrans 0.10 msRTT
> n5: 11837.9320 MB /  10.05 sec = 9876.5725 Mbps 39 %TX 47 %RX 0 retrans 0.10 msRTT
> n6:  9096.8125 MB /  10.09 sec = 7559.3310 Mbps 30 %TX 32 %RX 0 retrans 0.10 msRTT
> n7:  9100.1211 MB /  10.10 sec = 7559.7790 Mbps 30 %TX 44 %RX 0 retrans 0.10 msRTT
> n8:  9095.6179 MB /  10.10 sec = 7557.9983 Mbps 31 %TX 33 %RX 0 retrans 0.10 msRTT
> n9:  9075.5472 MB /  10.08 sec = 7551.0234 Mbps 31 %TX 33 %RX 0 retrans 0.11 msRTT
> 
> This used 4 dual-port Myricom 10-GigE NICs.  We also tested with
> a fifth dual-port 10-GigE NIC, but the aggregate throughput stayed
> at about 70 Gbps, due to the performance bottleneck between the
> X58 and N200 chips.

This is also very excellent results!

Thanks a lot Bill !!!
-- 
Med venlig hilsen / Best regards
  Jesper Brouer
  ComX Networks A/S
  Linux Network developer
  Cand. Scient Datalog / MSc.
  Author of http://adsl-optimizer.dk
  LinkedIn: http://www.linkedin.com/in/brouer

^ permalink raw reply

* Re: weird problem
From: Jarek Poplawski @ 2009-07-16 11:01 UTC (permalink / raw)
  To: Paweł Staszewski
  Cc: Eric Dumazet, Eric Dumazet, Linux Network Development list
In-Reply-To: <4A5E38EE.2090405@itcare.pl>

On Wed, Jul 15, 2009 at 10:15:42PM +0200, Paweł Staszewski wrote:
...
> With the same settings and 2.6.28 there was always cpu load from 1% to 3%
> with gc_timeout = 15
...
> So is there some patch or there will be patch that turn off definitely  
> route cache ?
>
>
> For now i use
> gc_timeout = 1  in my routers and all is working fine - there is only 1  
> second of 20% of cpu load after every 20 sec.

I guess, I misunderstood your intention; it looks like there are some
slowdowns in route cache handling vs. 2.6.28, which probably could be
partly tuned up with config parameters or fixed with some patch, but
it needs more testing/debugging, including additional data from 2.6.28
for comparison (I'm not sure if you're using this kernel yet).

But if you think turning off route cache works better for you (btw,
2.6.29.6 lacks at least 2 patches fixing this which 2.6.30.1 has) then
of course we can stop this thread, no problem.

Regards,
Jarek P.

^ permalink raw reply

* [RFC] [PATCH 0/7] IPsec: convert to ahash
From: Steffen Klassert @ 2009-07-16 11:15 UTC (permalink / raw)
  To: Herbert Xu; +Cc: linux-crypto, netdev

This patchset converts IPsec over to the new ahash interface.
The pachset applies to cryptodev-2.6. I was able to test the synchronous
codepaths, the asynchronous ones are untested.

I'm still somewhat unhappy with the ahash version of authenc, but I decided
to post anyway as a base for discussion.

Since the calls to the hash algorithms can now return asynchronous, I'd like
to avoid multiple calls to the hash update functions. I'd rather like to do
all the hashing with one call to crypto_ahash_digest(). As it is, this
requires chaining of all the involved scatterlists. Since we still can't use
sg_chain() to chain up the lists, I added an additional scatterlist entry to
the scatterlist of the assoc data (esp) to be able to chain later in the
crypto layer. To keep compatibility I set the termination bit at the first
entry and remove it later in authenc. In fact to rely on this additional
entry and just to remove the termintation bit later makes me a bit nervous
and I'm not sure whether this is acceptable, so better ideas are very welcome.

Steffen


^ permalink raw reply

* [RFC] [PATCH 1/7] esp: Add an additional scatterlist entry for the assoc data
From: Steffen Klassert @ 2009-07-16 11:16 UTC (permalink / raw)
  To: Herbert Xu; +Cc: linux-crypto, netdev
In-Reply-To: <20090716111548.GP20288@secunet.com>

To be able to chain all the scatterlists we add an additional
scatterlist entry to the scatterlist of the associated data.
To keep compatibility we set the termination bit at the first
entry. This can be reverted as soon as we can use sg_chain().

Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
 net/ipv4/esp4.c |   23 +++++++++++++++++------
 net/ipv6/esp6.c |   25 +++++++++++++++++++------
 2 files changed, 36 insertions(+), 12 deletions(-)

diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index 18bb383..dbb1a33 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -139,14 +139,14 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
 		goto error;
 	nfrags = err;
 
-	tmp = esp_alloc_tmp(aead, nfrags + 1);
+	tmp = esp_alloc_tmp(aead, nfrags + 2);
 	if (!tmp)
 		goto error;
 
 	iv = esp_tmp_iv(aead, tmp);
 	req = esp_tmp_givreq(aead, iv);
 	asg = esp_givreq_sg(aead, req);
-	sg = asg + 1;
+	sg = asg + 2;
 
 	/* Fill padding... */
 	tail = skb_tail_pointer(trailer);
@@ -205,7 +205,16 @@ static int esp_output(struct xfrm_state *x, struct sk_buff *skb)
 	skb_to_sgvec(skb, sg,
 		     esph->enc_data + crypto_aead_ivsize(aead) - skb->data,
 		     clen + alen);
-	sg_init_one(asg, esph, sizeof(*esph));
+
+	/*
+	 * We add an additional scatterlist entry to be able to chain up
+	 * the scatterlists in the crypto layer. To keep compatibility we
+	 * set the termination bit at the first entry. This can be removed
+	 * as soon as as architectures support scatterlist chaining.
+	 */
+	sg_init_table(asg, 2);
+	sg_mark_end(asg);
+	sg_set_buf(asg, esph, sizeof(*esph));
 
 	aead_givcrypt_set_callback(req, 0, esp_output_done, skb);
 	aead_givcrypt_set_crypt(req, sg, sg, clen, iv);
@@ -347,7 +356,7 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
 	nfrags = err;
 
 	err = -ENOMEM;
-	tmp = esp_alloc_tmp(aead, nfrags + 1);
+	tmp = esp_alloc_tmp(aead, nfrags + 2);
 	if (!tmp)
 		goto out;
 
@@ -355,7 +364,7 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
 	iv = esp_tmp_iv(aead, tmp);
 	req = esp_tmp_req(aead, iv);
 	asg = esp_req_sg(aead, req);
-	sg = asg + 1;
+	sg = asg + 2;
 
 	skb->ip_summed = CHECKSUM_NONE;
 
@@ -366,7 +375,9 @@ static int esp_input(struct xfrm_state *x, struct sk_buff *skb)
 
 	sg_init_table(sg, nfrags);
 	skb_to_sgvec(skb, sg, sizeof(*esph) + crypto_aead_ivsize(aead), elen);
-	sg_init_one(asg, esph, sizeof(*esph));
+	sg_init_table(asg, 2);
+	sg_mark_end(asg);
+	sg_set_buf(asg, esph, sizeof(*esph));
 
 	aead_request_set_callback(req, 0, esp_input_done, skb);
 	aead_request_set_crypt(req, sg, sg, elen, iv);
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index 678bb95..6ba707a 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -163,14 +163,14 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
 		goto error;
 	nfrags = err;
 
-	tmp = esp_alloc_tmp(aead, nfrags + 1);
+	tmp = esp_alloc_tmp(aead, nfrags + 2);
 	if (!tmp)
 		goto error;
 
 	iv = esp_tmp_iv(aead, tmp);
 	req = esp_tmp_givreq(aead, iv);
 	asg = esp_givreq_sg(aead, req);
-	sg = asg + 1;
+	sg = asg + 2;
 
 	/* Fill padding... */
 	tail = skb_tail_pointer(trailer);
@@ -194,7 +194,17 @@ static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
 	skb_to_sgvec(skb, sg,
 		     esph->enc_data + crypto_aead_ivsize(aead) - skb->data,
 		     clen + alen);
-	sg_init_one(asg, esph, sizeof(*esph));
+
+
+	/*
+	 * We add an additional scatterlist entry to be able to chain up
+	 * the scatterlists in the crypto layer. To keep compatibility we
+	 * set the termination bit at the first entry. This can be removed
+	 * as soon as as architectures support scatterlist chaining.
+	 */
+	sg_init_table(asg, 2);
+	sg_mark_end(asg);
+	sg_set_buf(asg, esph, sizeof(*esph));
 
 	aead_givcrypt_set_callback(req, 0, esp_output_done, skb);
 	aead_givcrypt_set_crypt(req, sg, sg, clen, iv);
@@ -298,7 +308,7 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
 	}
 
 	ret = -ENOMEM;
-	tmp = esp_alloc_tmp(aead, nfrags + 1);
+	tmp = esp_alloc_tmp(aead, nfrags + 2);
 	if (!tmp)
 		goto out;
 
@@ -306,7 +316,7 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
 	iv = esp_tmp_iv(aead, tmp);
 	req = esp_tmp_req(aead, iv);
 	asg = esp_req_sg(aead, req);
-	sg = asg + 1;
+	sg = asg + 2;
 
 	skb->ip_summed = CHECKSUM_NONE;
 
@@ -317,7 +327,10 @@ static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
 
 	sg_init_table(sg, nfrags);
 	skb_to_sgvec(skb, sg, sizeof(*esph) + crypto_aead_ivsize(aead), elen);
-	sg_init_one(asg, esph, sizeof(*esph));
+
+	sg_init_table(asg, 2);
+	sg_mark_end(asg);
+	sg_set_buf(asg, esph, sizeof(*esph));
 
 	aead_request_set_callback(req, 0, esp_input_done, skb);
 	aead_request_set_crypt(req, sg, sg, elen, iv);
-- 
1.5.4.2


^ permalink raw reply related

* [RFC] [PATCH 2/7] crypto: authenc - convert to ahash
From: Steffen Klassert @ 2009-07-16 11:17 UTC (permalink / raw)
  To: Herbert Xu; +Cc: linux-crypto, netdev
In-Reply-To: <20090716111548.GP20288@secunet.com>

This patch converts authenc to the new ahash interface.

Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
 crypto/authenc.c |  215 +++++++++++++++++++++++++++++++++++++----------------
 1 files changed, 150 insertions(+), 65 deletions(-)

diff --git a/crypto/authenc.c b/crypto/authenc.c
index 2e16ce0..bd456e3 100644
--- a/crypto/authenc.c
+++ b/crypto/authenc.c
@@ -24,23 +24,29 @@
 #include <linux/spinlock.h>
 
 struct authenc_instance_ctx {
-	struct crypto_spawn auth;
+	struct crypto_ahash_spawn auth;
 	struct crypto_skcipher_spawn enc;
 };
 
 struct crypto_authenc_ctx {
-	spinlock_t auth_lock;
-	struct crypto_hash *auth;
+	unsigned int reqoff;
+	struct crypto_ahash *auth;
 	struct crypto_ablkcipher *enc;
 };
 
+struct authenc_ahash_request_ctx {
+	struct scatterlist sg[2];
+	crypto_completion_t complete;
+	char tail[];
+};
+
 static int crypto_authenc_setkey(struct crypto_aead *authenc, const u8 *key,
 				 unsigned int keylen)
 {
 	unsigned int authkeylen;
 	unsigned int enckeylen;
 	struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
-	struct crypto_hash *auth = ctx->auth;
+	struct crypto_ahash *auth = ctx->auth;
 	struct crypto_ablkcipher *enc = ctx->enc;
 	struct rtattr *rta = (void *)key;
 	struct crypto_authenc_key_param *param;
@@ -64,11 +70,11 @@ static int crypto_authenc_setkey(struct crypto_aead *authenc, const u8 *key,
 
 	authkeylen = keylen - enckeylen;
 
-	crypto_hash_clear_flags(auth, CRYPTO_TFM_REQ_MASK);
-	crypto_hash_set_flags(auth, crypto_aead_get_flags(authenc) &
+	crypto_ahash_clear_flags(auth, CRYPTO_TFM_REQ_MASK);
+	crypto_ahash_set_flags(auth, crypto_aead_get_flags(authenc) &
 				    CRYPTO_TFM_REQ_MASK);
-	err = crypto_hash_setkey(auth, key, authkeylen);
-	crypto_aead_set_flags(authenc, crypto_hash_get_flags(auth) &
+	err = crypto_ahash_setkey(auth, key, authkeylen);
+	crypto_aead_set_flags(authenc, crypto_ahash_get_flags(auth) &
 				       CRYPTO_TFM_RES_MASK);
 
 	if (err)
@@ -92,6 +98,13 @@ badkey:
 static void authenc_chain(struct scatterlist *head, struct scatterlist *sg,
 			  int chain)
 {
+	/* 
+	 * head must be a scatterlist with two entries.
+	 * We remove a potentially set termination bit
+	 * on the first enty.
+	 */
+	head->page_link &= ~0x02;
+
 	if (chain) {
 		head->length += sg->length;
 		sg = scatterwalk_sg_next(sg);
@@ -103,40 +116,85 @@ static void authenc_chain(struct scatterlist *head, struct scatterlist *sg,
 		sg_mark_end(head);
 }
 
-static u8 *crypto_authenc_hash(struct aead_request *req, unsigned int flags,
-			       struct scatterlist *cipher,
-			       unsigned int cryptlen)
+static void crypto_authenc_ahash_geniv_done(
+			struct crypto_async_request *areq, int err)
 {
+	struct aead_request *req = areq->data;
 	struct crypto_aead *authenc = crypto_aead_reqtfm(req);
 	struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
-	struct crypto_hash *auth = ctx->auth;
-	struct hash_desc desc = {
-		.tfm = auth,
-		.flags = aead_request_flags(req) & flags,
-	};
-	u8 *hash = aead_request_ctx(req);
-	int err;
-
-	hash = (u8 *)ALIGN((unsigned long)hash + crypto_hash_alignmask(auth), 
-			   crypto_hash_alignmask(auth) + 1);
+	struct authenc_ahash_request_ctx *ahreq_ctx = aead_request_ctx(req);
+	struct ahash_request *ahreq = (void *)(ahreq_ctx->tail + ctx->reqoff);
 
-	spin_lock_bh(&ctx->auth_lock);
-	err = crypto_hash_init(&desc);
 	if (err)
-		goto auth_unlock;
+		goto out;
+
+	scatterwalk_map_and_copy(ahreq->result, ahreq->src, ahreq->nbytes,
+				 crypto_aead_authsize(authenc), 1);
+
+out:
+	aead_request_complete(req, err);
+}
+
+static void crypto_authenc_ahash_verify_done(
+			struct crypto_async_request *areq, int err)
+{
+	u8 *ihash;
+	unsigned int authsize;
+	struct ablkcipher_request *abreq;
+	struct aead_request *req = areq->data;
+	struct crypto_aead *authenc = crypto_aead_reqtfm(req);
+	struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
+	struct authenc_ahash_request_ctx *ahreq_ctx = aead_request_ctx(req);
+	struct ahash_request *ahreq = (void *)(ahreq_ctx->tail + ctx->reqoff);
 
-	err = crypto_hash_update(&desc, req->assoc, req->assoclen);
 	if (err)
-		goto auth_unlock;
+		goto out;
+
+	authsize = crypto_aead_authsize(authenc);
+	ihash = ahreq->result + authsize;
+	scatterwalk_map_and_copy(ihash, ahreq->src, ahreq->nbytes, authsize, 0);
+	err = memcmp(ihash, ahreq->result, authsize) ? -EBADMSG: 0;
 
-	err = crypto_hash_update(&desc, cipher, cryptlen);
 	if (err)
-		goto auth_unlock;
+		goto out;
 
-	err = crypto_hash_final(&desc, hash);
-auth_unlock:
-	spin_unlock_bh(&ctx->auth_lock);
+	abreq = aead_request_ctx(req);
+	ablkcipher_request_set_tfm(abreq, ctx->enc);
+	ablkcipher_request_set_callback(abreq, aead_request_flags(req),
+					req->base.complete, req->base.data);
+	ablkcipher_request_set_crypt(abreq, req->src, req->dst,
+						req->cryptlen, req->iv);
+
+	err = crypto_ablkcipher_decrypt(abreq);
+
+	if (err == -EINPROGRESS)
+		return;
+
+out:
+	aead_request_complete(req, err);
+}
+
+static u8 *crypto_authenc_ahash(struct aead_request *req, unsigned int flags,
+			       struct scatterlist *cipher,
+			       unsigned int cryptlen)
+{
+	struct crypto_aead *authenc = crypto_aead_reqtfm(req);
+	struct crypto_authenc_ctx *ctx = crypto_aead_ctx(authenc);
+	struct crypto_ahash *auth = ctx->auth;
+	struct authenc_ahash_request_ctx *ahreq_ctx = aead_request_ctx(req);
+	struct ahash_request *ahreq = (void *)(ahreq_ctx->tail + ctx->reqoff);
+	u8 *hash = ahreq_ctx->tail;
+	int err;
+
+	hash = (u8 *)ALIGN((unsigned long)hash + crypto_ahash_alignmask(auth),
+			   crypto_ahash_alignmask(auth) + 1);
+
+	ahash_request_set_tfm(ahreq, auth);
+	ahash_request_set_crypt(ahreq, cipher, hash, cryptlen);
+	ahash_request_set_callback(ahreq, aead_request_flags(req) & flags,
+				   ahreq_ctx->complete, req);
 
+	err = crypto_ahash_digest(ahreq);
 	if (err)
 		return ERR_PTR(err);
 
@@ -147,8 +205,9 @@ static int crypto_authenc_genicv(struct aead_request *req, u8 *iv,
 				 unsigned int flags)
 {
 	struct crypto_aead *authenc = crypto_aead_reqtfm(req);
+	struct authenc_ahash_request_ctx *ahreq_ctx = aead_request_ctx(req);
 	struct scatterlist *dst = req->dst;
-	struct scatterlist cipher[2];
+	struct scatterlist *cipher = ahreq_ctx->sg;
 	struct page *dstp;
 	unsigned int ivsize = crypto_aead_ivsize(authenc);
 	unsigned int cryptlen;
@@ -165,8 +224,13 @@ static int crypto_authenc_genicv(struct aead_request *req, u8 *iv,
 		dst = cipher;
 	}
 
-	cryptlen = req->cryptlen + ivsize;
-	hash = crypto_authenc_hash(req, flags, dst, cryptlen);
+	authenc_chain(req->assoc, dst, 0);
+	dst = req->assoc;
+
+	cryptlen = req->cryptlen + ivsize + req->assoclen;
+	ahreq_ctx->complete = crypto_authenc_ahash_geniv_done;
+
+	hash = crypto_authenc_ahash(req, flags, dst, cryptlen);
 	if (IS_ERR(hash))
 		return PTR_ERR(hash);
 
@@ -188,6 +252,9 @@ static void crypto_authenc_encrypt_done(struct crypto_async_request *req,
 			 crypto_ablkcipher_reqsize(ctx->enc);
 
 		err = crypto_authenc_genicv(areq, iv, 0);
+
+		if (err == -EINPROGRESS)
+			return;
 	}
 
 	aead_request_complete(areq, err);
@@ -227,6 +294,9 @@ static void crypto_authenc_givencrypt_done(struct crypto_async_request *req,
 		struct skcipher_givcrypt_request *greq = aead_request_ctx(areq);
 
 		err = crypto_authenc_genicv(areq, greq->giv, 0);
+
+		if (err == -EINPROGRESS)
+			return;
 	}
 
 	aead_request_complete(areq, err);
@@ -260,12 +330,15 @@ static int crypto_authenc_verify(struct aead_request *req,
 				 unsigned int cryptlen)
 {
 	struct crypto_aead *authenc = crypto_aead_reqtfm(req);
+	struct authenc_ahash_request_ctx *ahreq_ctx = aead_request_ctx(req);
 	u8 *ohash;
 	u8 *ihash;
 	unsigned int authsize;
 
-	ohash = crypto_authenc_hash(req, CRYPTO_TFM_REQ_MAY_SLEEP, cipher,
-				    cryptlen);
+	ahreq_ctx->complete = crypto_authenc_ahash_verify_done;
+
+	ohash = crypto_authenc_ahash(req, CRYPTO_TFM_REQ_MAY_SLEEP, cipher,
+				     cryptlen);
 	if (IS_ERR(ohash))
 		return PTR_ERR(ohash);
 
@@ -279,8 +352,9 @@ static int crypto_authenc_iverify(struct aead_request *req, u8 *iv,
 				  unsigned int cryptlen)
 {
 	struct crypto_aead *authenc = crypto_aead_reqtfm(req);
+	struct authenc_ahash_request_ctx *ahreq_ctx = aead_request_ctx(req);
 	struct scatterlist *src = req->src;
-	struct scatterlist cipher[2];
+	struct scatterlist *cipher = ahreq_ctx->sg;
 	struct page *srcp;
 	unsigned int ivsize = crypto_aead_ivsize(authenc);
 	u8 *vsrc;
@@ -295,7 +369,11 @@ static int crypto_authenc_iverify(struct aead_request *req, u8 *iv,
 		src = cipher;
 	}
 
-	return crypto_authenc_verify(req, src, cryptlen + ivsize);
+	authenc_chain(req->assoc, src, 0);
+	src = req->assoc;
+
+	cryptlen += ivsize + req->assoclen;
+	return crypto_authenc_verify(req, src, cryptlen);
 }
 
 static int crypto_authenc_decrypt(struct aead_request *req)
@@ -326,38 +404,41 @@ static int crypto_authenc_decrypt(struct aead_request *req)
 
 static int crypto_authenc_init_tfm(struct crypto_tfm *tfm)
 {
-	struct crypto_instance *inst = (void *)tfm->__crt_alg;
+	struct crypto_instance *inst = crypto_tfm_alg_instance(tfm);
 	struct authenc_instance_ctx *ictx = crypto_instance_ctx(inst);
 	struct crypto_authenc_ctx *ctx = crypto_tfm_ctx(tfm);
-	struct crypto_hash *auth;
+	struct crypto_ahash *auth;
 	struct crypto_ablkcipher *enc;
 	int err;
 
-	auth = crypto_spawn_hash(&ictx->auth);
+	auth = crypto_spawn_ahash(&ictx->auth);
 	if (IS_ERR(auth))
 		return PTR_ERR(auth);
 
+	ctx->reqoff = ALIGN(2 * crypto_ahash_digestsize(auth) +
+			    crypto_ahash_alignmask(auth),
+			    crypto_ahash_alignmask(auth) + 1);
+
 	enc = crypto_spawn_skcipher(&ictx->enc);
 	err = PTR_ERR(enc);
 	if (IS_ERR(enc))
-		goto err_free_hash;
+		goto err_free_ahash;
 
 	ctx->auth = auth;
 	ctx->enc = enc;
+	
 	tfm->crt_aead.reqsize = max_t(unsigned int,
-				      (crypto_hash_alignmask(auth) &
-				       ~(crypto_tfm_ctx_alignment() - 1)) +
-				      crypto_hash_digestsize(auth) * 2,
-				      sizeof(struct skcipher_givcrypt_request) +
-				      crypto_ablkcipher_reqsize(enc) +
-				      crypto_ablkcipher_ivsize(enc));
-
-	spin_lock_init(&ctx->auth_lock);
+				crypto_ahash_reqsize(auth) + ctx->reqoff +
+				sizeof(struct authenc_ahash_request_ctx) +
+				sizeof(struct ahash_request), 
+				sizeof(struct skcipher_givcrypt_request) +
+				crypto_ablkcipher_reqsize(enc) +
+				crypto_ablkcipher_ivsize(enc));
 
 	return 0;
 
-err_free_hash:
-	crypto_free_hash(auth);
+err_free_ahash:
+	crypto_free_ahash(auth);
 	return err;
 }
 
@@ -365,7 +446,7 @@ static void crypto_authenc_exit_tfm(struct crypto_tfm *tfm)
 {
 	struct crypto_authenc_ctx *ctx = crypto_tfm_ctx(tfm);
 
-	crypto_free_hash(ctx->auth);
+	crypto_free_ahash(ctx->auth);
 	crypto_free_ablkcipher(ctx->enc);
 }
 
@@ -373,7 +454,8 @@ static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb)
 {
 	struct crypto_attr_type *algt;
 	struct crypto_instance *inst;
-	struct crypto_alg *auth;
+	struct hash_alg_common *auth;
+	struct crypto_alg *auth_base;
 	struct crypto_alg *enc;
 	struct authenc_instance_ctx *ctx;
 	const char *enc_name;
@@ -387,11 +469,13 @@ static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb)
 	if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask)
 		return ERR_PTR(-EINVAL);
 
-	auth = crypto_attr_alg(tb[1], CRYPTO_ALG_TYPE_HASH,
-			       CRYPTO_ALG_TYPE_HASH_MASK);
+	auth = ahash_attr_alg(tb[1], CRYPTO_ALG_TYPE_HASH,
+			       CRYPTO_ALG_TYPE_AHASH_MASK);
 	if (IS_ERR(auth))
 		return ERR_PTR(PTR_ERR(auth));
 
+	auth_base = &auth->base;
+
 	enc_name = crypto_attr_alg_name(tb[2]);
 	err = PTR_ERR(enc_name);
 	if (IS_ERR(enc_name))
@@ -404,7 +488,7 @@ static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb)
 
 	ctx = crypto_instance_ctx(inst);
 
-	err = crypto_init_spawn(&ctx->auth, auth, inst, CRYPTO_ALG_TYPE_MASK);
+	err = crypto_init_ahash_spawn(&ctx->auth, auth, inst);
 	if (err)
 		goto err_free_inst;
 
@@ -419,24 +503,25 @@ static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb)
 
 	err = -ENAMETOOLONG;
 	if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME,
-		     "authenc(%s,%s)", auth->cra_name, enc->cra_name) >=
+		     "authenc(%s,%s)", auth_base->cra_name, enc->cra_name) >=
 	    CRYPTO_MAX_ALG_NAME)
 		goto err_drop_enc;
 
 	if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME,
-		     "authenc(%s,%s)", auth->cra_driver_name,
+		     "authenc(%s,%s)", auth_base->cra_driver_name,
 		     enc->cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
 		goto err_drop_enc;
 
 	inst->alg.cra_flags = CRYPTO_ALG_TYPE_AEAD;
 	inst->alg.cra_flags |= enc->cra_flags & CRYPTO_ALG_ASYNC;
-	inst->alg.cra_priority = enc->cra_priority * 10 + auth->cra_priority;
+	inst->alg.cra_priority = enc->cra_priority *
+				 10 + auth_base->cra_priority;
 	inst->alg.cra_blocksize = enc->cra_blocksize;
-	inst->alg.cra_alignmask = auth->cra_alignmask | enc->cra_alignmask;
+	inst->alg.cra_alignmask = auth_base->cra_alignmask | enc->cra_alignmask;
 	inst->alg.cra_type = &crypto_aead_type;
 
 	inst->alg.cra_aead.ivsize = enc->cra_ablkcipher.ivsize;
-	inst->alg.cra_aead.maxauthsize = __crypto_shash_alg(auth)->digestsize;
+	inst->alg.cra_aead.maxauthsize = auth->digestsize;
 
 	inst->alg.cra_ctxsize = sizeof(struct crypto_authenc_ctx);
 
@@ -449,13 +534,13 @@ static struct crypto_instance *crypto_authenc_alloc(struct rtattr **tb)
 	inst->alg.cra_aead.givencrypt = crypto_authenc_givencrypt;
 
 out:
-	crypto_mod_put(auth);
+	crypto_mod_put(auth_base);
 	return inst;
 
 err_drop_enc:
 	crypto_drop_skcipher(&ctx->enc);
 err_drop_auth:
-	crypto_drop_spawn(&ctx->auth);
+	crypto_drop_ahash(&ctx->auth);
 err_free_inst:
 	kfree(inst);
 out_put_auth:
@@ -468,7 +553,7 @@ static void crypto_authenc_free(struct crypto_instance *inst)
 	struct authenc_instance_ctx *ctx = crypto_instance_ctx(inst);
 
 	crypto_drop_skcipher(&ctx->enc);
-	crypto_drop_spawn(&ctx->auth);
+	crypto_drop_ahash(&ctx->auth);
 	kfree(inst);
 }
 
-- 
1.5.4.2


^ permalink raw reply related

* [RFC] [PATCH 3/7] ah: Add struct crypto_ahash to ah_data
From: Steffen Klassert @ 2009-07-16 11:18 UTC (permalink / raw)
  To: Herbert Xu; +Cc: linux-crypto, netdev
In-Reply-To: <20090716111548.GP20288@secunet.com>

To support for ahash algorithms, we add a pointer to a
crypto_ahash to ah_data.

Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
 include/net/ah.h |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/include/net/ah.h b/include/net/ah.h
index ae1c322..7ac5221 100644
--- a/include/net/ah.h
+++ b/include/net/ah.h
@@ -14,6 +14,7 @@ struct ah_data
 	int			icv_trunc_len;
 
 	struct crypto_hash	*tfm;
+	struct crypto_ahash	*ahash;
 };
 
 static inline int ah_mac_digest(struct ah_data *ahp, struct sk_buff *skb,
-- 
1.5.4.2


^ permalink raw reply related

* [RFC] [PATCH 4/7] ah4: convert to ahash
From: Steffen Klassert @ 2009-07-16 11:19 UTC (permalink / raw)
  To: Herbert Xu; +Cc: linux-crypto, netdev
In-Reply-To: <20090716111548.GP20288@secunet.com>

This patch converts ah4 to the new ahash interface.

Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
 net/ipv4/ah4.c |  295 ++++++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 236 insertions(+), 59 deletions(-)

diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index e878e49..68436fd 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -1,3 +1,4 @@
+#include <crypto/hash.h>
 #include <linux/err.h>
 #include <linux/module.h>
 #include <net/ip.h>
@@ -5,10 +6,67 @@
 #include <net/ah.h>
 #include <linux/crypto.h>
 #include <linux/pfkeyv2.h>
-#include <linux/spinlock.h>
+#include <linux/scatterlist.h>
 #include <net/icmp.h>
 #include <net/protocol.h>
 
+struct ah_skb_cb {
+	struct xfrm_skb_cb xfrm;
+	void *tmp;
+};
+
+#define AH_SKB_CB(__skb) ((struct ah_skb_cb *)&((__skb)->cb[0]))
+
+static void *ah_alloc_tmp(struct crypto_ahash *ahash, int nfrags,
+			  unsigned int size)
+{
+	unsigned int len;
+
+	len = size + crypto_ahash_digestsize(ahash) +
+	      (crypto_ahash_alignmask(ahash) &
+	       ~(crypto_tfm_ctx_alignment() - 1));
+
+	len = ALIGN(len, crypto_tfm_ctx_alignment());
+
+	len += sizeof(struct ahash_request) + crypto_ahash_reqsize(ahash);
+	len = ALIGN(len, __alignof__(struct scatterlist));
+
+	len += sizeof(struct scatterlist) * nfrags;
+
+	return kmalloc(len, GFP_ATOMIC);
+}
+
+static inline u8 *ah_tmp_auth(void *tmp, unsigned int offset)
+{
+	return tmp + offset;
+}
+
+static inline u8 *ah_tmp_icv(struct crypto_ahash *ahash, void *tmp,
+			     unsigned int offset)
+{
+	return PTR_ALIGN((u8 *)tmp + offset, crypto_ahash_alignmask(ahash) + 1);
+}
+
+static inline struct ahash_request *ah_tmp_req(struct crypto_ahash *ahash,
+					       u8 *icv)
+{
+	struct ahash_request *req;
+
+	req = (void *)PTR_ALIGN(icv + crypto_ahash_digestsize(ahash),
+				crypto_tfm_ctx_alignment());
+
+	ahash_request_set_tfm(req, ahash);
+
+	return req;
+}
+
+static inline struct scatterlist *ah_req_sg(struct crypto_ahash *ahash,
+					     struct ahash_request *req)
+{
+	return (void *)ALIGN((unsigned long)(req + 1) +
+			     crypto_ahash_reqsize(ahash),
+			     __alignof__(struct scatterlist));
+}
 
 /* Clear mutable options and find final destination to substitute
  * into IP header for icv calculation. Options are already checked
@@ -54,20 +112,72 @@ static int ip_clear_mutable_options(struct iphdr *iph, __be32 *daddr)
 	return 0;
 }
 
+static void ah_output_done(struct crypto_async_request *base, int err)
+{
+	u8 *icv;
+	struct iphdr *iph;
+	struct sk_buff *skb = base->data;
+	struct xfrm_state *x = skb_dst(skb)->xfrm;
+	struct ah_data *ahp = x->data;
+	struct iphdr *top_iph = ip_hdr(skb);
+	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
+	int ihl = ip_hdrlen(skb);
+
+	iph = AH_SKB_CB(skb)->tmp;
+	icv = ah_tmp_icv(ahp->ahash, iph, ihl);
+	memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
+
+	top_iph->tos = iph->tos;
+	top_iph->ttl = iph->ttl;
+	top_iph->frag_off = iph->frag_off;
+	if (top_iph->ihl != 5) {
+		top_iph->daddr = iph->daddr;
+		memcpy(top_iph+1, iph+1, top_iph->ihl*4 - sizeof(struct iphdr));
+	}
+
+	err = ah->nexthdr;
+
+	kfree(AH_SKB_CB(skb)->tmp);
+	xfrm_output_resume(skb, err);
+}
+
 static int ah_output(struct xfrm_state *x, struct sk_buff *skb)
 {
 	int err;
+	int nfrags;
+	int ihl;
+	u8 *icv;
+	struct sk_buff *trailer;
+	struct crypto_ahash *ahash;
+	struct ahash_request *req;
+	struct scatterlist *sg;
 	struct iphdr *iph, *top_iph;
 	struct ip_auth_hdr *ah;
 	struct ah_data *ahp;
-	union {
-		struct iphdr	iph;
-		char 		buf[60];
-	} tmp_iph;
+
+	ahp = x->data;
+	ahash = ahp->ahash;
+
+	if ((err = skb_cow_data(skb, 0, &trailer)) < 0)
+		goto out;
+	nfrags = err;
 
 	skb_push(skb, -skb_network_offset(skb));
+	ah = ip_auth_hdr(skb);
+	ihl = ip_hdrlen(skb);
+
+	err = -ENOMEM;
+	iph = ah_alloc_tmp(ahash, nfrags, ihl);
+	if (!iph)
+		goto out;
+
+	icv = ah_tmp_icv(ahash, iph, ihl);
+	req = ah_tmp_req(ahash, icv);
+	sg = ah_req_sg(ahash, req);
+
+	memset(ah->auth_data, 0, ahp->icv_trunc_len);
+
 	top_iph = ip_hdr(skb);
-	iph = &tmp_iph.iph;
 
 	iph->tos = top_iph->tos;
 	iph->ttl = top_iph->ttl;
@@ -78,10 +188,9 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb)
 		memcpy(iph+1, top_iph+1, top_iph->ihl*4 - sizeof(struct iphdr));
 		err = ip_clear_mutable_options(top_iph, &top_iph->daddr);
 		if (err)
-			goto error;
+			goto out_free;
 	}
 
-	ah = ip_auth_hdr(skb);
 	ah->nexthdr = *skb_mac_header(skb);
 	*skb_mac_header(skb) = IPPROTO_AH;
 
@@ -91,20 +200,31 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb)
 	top_iph->ttl = 0;
 	top_iph->check = 0;
 
-	ahp = x->data;
 	ah->hdrlen  = (XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len) >> 2) - 2;
 
 	ah->reserved = 0;
 	ah->spi = x->id.spi;
 	ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output);
 
-	spin_lock_bh(&x->lock);
-	err = ah_mac_digest(ahp, skb, ah->auth_data);
-	memcpy(ah->auth_data, ahp->work_icv, ahp->icv_trunc_len);
-	spin_unlock_bh(&x->lock);
+	sg_init_table(sg, nfrags);
+	skb_to_sgvec(skb, sg, 0, skb->len);
+	
+	ahash_request_set_crypt(req, sg, icv, skb->len);
+	ahash_request_set_callback(req, 0, ah_output_done, skb);
 
-	if (err)
-		goto error;
+	AH_SKB_CB(skb)->tmp = iph;
+
+	err = crypto_ahash_digest(req);
+	if (err) {
+		if (err == -EINPROGRESS)
+			goto out;
+
+		if (err == -EBUSY)
+			err = NET_XMIT_DROP;
+		goto out_free;
+	}
+
+	memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
 
 	top_iph->tos = iph->tos;
 	top_iph->ttl = iph->ttl;
@@ -114,28 +234,67 @@ static int ah_output(struct xfrm_state *x, struct sk_buff *skb)
 		memcpy(top_iph+1, iph+1, top_iph->ihl*4 - sizeof(struct iphdr));
 	}
 
-	err = 0;
-
-error:
+out_free:
+	kfree(iph);
+out:
 	return err;
 }
 
+static void ah_input_done(struct crypto_async_request *base, int err)
+{
+	u8 *auth_data;
+	u8 *icv;
+	struct iphdr *work_iph;
+	struct sk_buff *skb = base->data;
+	struct xfrm_state *x = xfrm_input_state(skb);
+	struct ah_data *ahp = x->data;
+	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
+	int ihl = ip_hdrlen(skb);
+	int ah_hlen = (ah->hdrlen + 2) << 2;
+
+	work_iph = AH_SKB_CB(skb)->tmp;
+	auth_data = ah_tmp_auth(work_iph, ihl);
+	icv = ah_tmp_icv(ahp->ahash, auth_data, ahp->icv_trunc_len);
+
+	err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG: 0;
+	if (err)
+		goto out;
+
+	skb->network_header += ah_hlen;
+	memcpy(skb_network_header(skb), work_iph, ihl);
+	__skb_pull(skb, ah_hlen + ihl);
+	skb_set_transport_header(skb, -ihl);
+	
+	err = ah->nexthdr;
+out:
+	kfree(AH_SKB_CB(skb)->tmp);
+	xfrm_input_resume(skb, err);
+}
+
 static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
 {
 	int ah_hlen;
 	int ihl;
 	int nexthdr;
-	int err = -EINVAL;
-	struct iphdr *iph;
+	int nfrags;
+	u8 *auth_data;
+	u8 *icv;
+	struct sk_buff *trailer;
+	struct crypto_ahash *ahash;
+	struct ahash_request *req;
+	struct scatterlist *sg;
+	struct iphdr *iph, *work_iph;
 	struct ip_auth_hdr *ah;
 	struct ah_data *ahp;
-	char work_buf[60];
+	int err = -ENOMEM;
 
 	if (!pskb_may_pull(skb, sizeof(*ah)))
 		goto out;
 
 	ah = (struct ip_auth_hdr *)skb->data;
 	ahp = x->data;
+	ahash = ahp->ahash;
+
 	nexthdr = ah->nexthdr;
 	ah_hlen = (ah->hdrlen + 2) << 2;
 
@@ -156,9 +315,24 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
 
 	ah = (struct ip_auth_hdr *)skb->data;
 	iph = ip_hdr(skb);
+	ihl = ip_hdrlen(skb);
+
+	if ((err = skb_cow_data(skb, 0, &trailer)) < 0)
+		goto out;
+	nfrags = err;
+
+	work_iph = ah_alloc_tmp(ahash, nfrags, ihl + ahp->icv_trunc_len);
+	if (!work_iph)
+		goto out;
+
+	auth_data = ah_tmp_auth(work_iph, ihl);
+	icv = ah_tmp_icv(ahash, auth_data, ahp->icv_trunc_len);
+	req = ah_tmp_req(ahash, icv);
+	sg = ah_req_sg(ahash, req);
 
-	ihl = skb->data - skb_network_header(skb);
-	memcpy(work_buf, iph, ihl);
+	memcpy(work_iph, iph, ihl);
+	memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);
+	memset(ah->auth_data, 0, ahp->icv_trunc_len);
 
 	iph->ttl = 0;
 	iph->tos = 0;
@@ -166,35 +340,44 @@ static int ah_input(struct xfrm_state *x, struct sk_buff *skb)
 	iph->check = 0;
 	if (ihl > sizeof(*iph)) {
 		__be32 dummy;
-		if (ip_clear_mutable_options(iph, &dummy))
-			goto out;
+		err = ip_clear_mutable_options(iph, &dummy);
+		if (err)
+			goto out_free;
 	}
 
-	spin_lock(&x->lock);
-	{
-		u8 auth_data[MAX_AH_AUTH_LEN];
+	skb_push(skb, ihl);
 
-		memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);
-		skb_push(skb, ihl);
-		err = ah_mac_digest(ahp, skb, ah->auth_data);
-		if (err)
-			goto unlock;
-		if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len))
-			err = -EBADMSG;
+	sg_init_table(sg, nfrags);
+	skb_to_sgvec(skb, sg, 0, skb->len);
+	
+	ahash_request_set_crypt(req, sg, icv, skb->len);
+	ahash_request_set_callback(req, 0, ah_input_done, skb);
+
+	AH_SKB_CB(skb)->tmp = work_iph;
+
+	err = crypto_ahash_digest(req);
+	if (err) {
+		if (err == -EINPROGRESS)
+			goto out;
+
+		if (err == -EBUSY)
+			err = NET_XMIT_DROP;
+		goto out_free;
 	}
-unlock:
-	spin_unlock(&x->lock);
 
+	err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG: 0;
 	if (err)
-		goto out;
+		goto out_free;
 
 	skb->network_header += ah_hlen;
-	memcpy(skb_network_header(skb), work_buf, ihl);
-	skb->transport_header = skb->network_header;
+	memcpy(skb_network_header(skb), work_iph, ihl);
 	__skb_pull(skb, ah_hlen + ihl);
+	skb_set_transport_header(skb, -ihl);
 
-	return nexthdr;
+	err = nexthdr;
 
+out_free:
+	kfree (work_iph);
 out:
 	return err;
 }
@@ -222,7 +405,7 @@ static int ah_init_state(struct xfrm_state *x)
 {
 	struct ah_data *ahp = NULL;
 	struct xfrm_algo_desc *aalg_desc;
-	struct crypto_hash *tfm;
+	struct crypto_ahash *ahash;
 
 	if (!x->aalg)
 		goto error;
@@ -231,31 +414,31 @@ static int ah_init_state(struct xfrm_state *x)
 		goto error;
 
 	ahp = kzalloc(sizeof(*ahp), GFP_KERNEL);
-	if (ahp == NULL)
+	if (!ahp)
 		return -ENOMEM;
 
-	tfm = crypto_alloc_hash(x->aalg->alg_name, 0, CRYPTO_ALG_ASYNC);
-	if (IS_ERR(tfm))
+	ahash = crypto_alloc_ahash(x->aalg->alg_name, 0, 0);
+	if (IS_ERR(ahash))
 		goto error;
 
-	ahp->tfm = tfm;
-	if (crypto_hash_setkey(tfm, x->aalg->alg_key,
-			       (x->aalg->alg_key_len + 7) / 8))
+	ahp->ahash = ahash;
+	if (crypto_ahash_setkey(ahash, x->aalg->alg_key,
+				(x->aalg->alg_key_len + 7) / 8))
 		goto error;
 
 	/*
 	 * Lookup the algorithm description maintained by xfrm_algo,
 	 * verify crypto transform properties, and store information
 	 * we need for AH processing.  This lookup cannot fail here
-	 * after a successful crypto_alloc_hash().
+	 * after a successful crypto_alloc_ahash().
 	 */
 	aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
 	BUG_ON(!aalg_desc);
 
 	if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
-	    crypto_hash_digestsize(tfm)) {
+	    crypto_ahash_digestsize(ahash)) {
 		printk(KERN_INFO "AH: %s digestsize %u != %hu\n",
-		       x->aalg->alg_name, crypto_hash_digestsize(tfm),
+		       x->aalg->alg_name, crypto_ahash_digestsize(ahash),
 		       aalg_desc->uinfo.auth.icv_fullbits/8);
 		goto error;
 	}
@@ -265,10 +448,6 @@ static int ah_init_state(struct xfrm_state *x)
 
 	BUG_ON(ahp->icv_trunc_len > MAX_AH_AUTH_LEN);
 
-	ahp->work_icv = kmalloc(ahp->icv_full_len, GFP_KERNEL);
-	if (!ahp->work_icv)
-		goto error;
-
 	x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) +
 					  ahp->icv_trunc_len);
 	if (x->props.mode == XFRM_MODE_TUNNEL)
@@ -279,8 +458,7 @@ static int ah_init_state(struct xfrm_state *x)
 
 error:
 	if (ahp) {
-		kfree(ahp->work_icv);
-		crypto_free_hash(ahp->tfm);
+		crypto_free_ahash(ahp->ahash);
 		kfree(ahp);
 	}
 	return -EINVAL;
@@ -293,8 +471,7 @@ static void ah_destroy(struct xfrm_state *x)
 	if (!ahp)
 		return;
 
-	kfree(ahp->work_icv);
-	crypto_free_hash(ahp->tfm);
+	crypto_free_ahash(ahp->ahash);
 	kfree(ahp);
 }
 
-- 
1.5.4.2


^ permalink raw reply related

* [RFC] [PATCH 5/7] ah6: convert to ahash
From: Steffen Klassert @ 2009-07-16 11:19 UTC (permalink / raw)
  To: Herbert Xu; +Cc: linux-crypto, netdev
In-Reply-To: <20090716111548.GP20288@secunet.com>

This patch converts ah6 to the new ahash interface.

Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
 net/ipv6/ah6.c |  352 +++++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 272 insertions(+), 80 deletions(-)

diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c
index 86f42a2..9fb063c 100644
--- a/net/ipv6/ah6.c
+++ b/net/ipv6/ah6.c
@@ -24,18 +24,92 @@
  * 	This file is derived from net/ipv4/ah.c.
  */
 
+#include <crypto/hash.h>
 #include <linux/module.h>
 #include <net/ip.h>
 #include <net/ah.h>
 #include <linux/crypto.h>
 #include <linux/pfkeyv2.h>
-#include <linux/spinlock.h>
 #include <linux/string.h>
+#include <linux/scatterlist.h>
 #include <net/icmp.h>
 #include <net/ipv6.h>
 #include <net/protocol.h>
 #include <net/xfrm.h>
 
+#define IPV6HDR_BASELEN 8
+
+struct tmp_ext {
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
+		struct in6_addr saddr;
+#endif
+		struct in6_addr daddr;
+		char hdrs[0];
+};
+
+struct ah_skb_cb {
+	struct xfrm_skb_cb xfrm;
+	void *tmp;
+};
+
+#define AH_SKB_CB(__skb) ((struct ah_skb_cb *)&((__skb)->cb[0]))
+
+static void *ah_alloc_tmp(struct crypto_ahash *ahash, int nfrags,
+			  unsigned int size)
+{
+	unsigned int len;
+
+	len = size + crypto_ahash_digestsize(ahash) +
+	      (crypto_ahash_alignmask(ahash) &
+	       ~(crypto_tfm_ctx_alignment() - 1));
+
+	len = ALIGN(len, crypto_tfm_ctx_alignment());
+
+	len += sizeof(struct ahash_request) + crypto_ahash_reqsize(ahash);
+	len = ALIGN(len, __alignof__(struct scatterlist));
+
+	len += sizeof(struct scatterlist) * nfrags;
+
+	return kmalloc(len, GFP_ATOMIC);
+}
+
+static inline struct tmp_ext *ah_tmp_ext(void *base)
+{
+	return base + IPV6HDR_BASELEN;
+}
+
+static inline u8 *ah_tmp_auth(u8 *tmp, unsigned int offset)
+{
+	return tmp + offset;
+}
+
+static inline u8 *ah_tmp_icv(struct crypto_ahash *ahash, void *tmp,
+			     unsigned int offset)
+{
+	return PTR_ALIGN((u8 *)tmp + offset, crypto_ahash_alignmask(ahash) + 1);
+}
+
+static inline struct ahash_request *ah_tmp_req(struct crypto_ahash *ahash,
+					       u8 *icv)
+{
+	struct ahash_request *req;
+
+	req = (void *)PTR_ALIGN(icv + crypto_ahash_digestsize(ahash),
+				crypto_tfm_ctx_alignment());
+
+	ahash_request_set_tfm(req, ahash);
+
+	return req;
+}
+
+static inline struct scatterlist *ah_req_sg(struct crypto_ahash *ahash,
+					     struct ahash_request *req)
+{
+	return (void *)ALIGN((unsigned long)(req + 1) +
+			     crypto_ahash_reqsize(ahash),
+			     __alignof__(struct scatterlist));
+}
+
 static int zero_out_mutable_opts(struct ipv6_opt_hdr *opthdr)
 {
 	u8 *opt = (u8 *)opthdr;
@@ -218,24 +292,85 @@ static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir)
 	return 0;
 }
 
+static void ah6_output_done(struct crypto_async_request *base, int err)
+{
+	int extlen;
+	u8 *iph_base;
+	u8 *icv;
+	struct sk_buff *skb = base->data;
+	struct xfrm_state *x = skb_dst(skb)->xfrm;
+	struct ah_data *ahp = x->data;
+	struct ipv6hdr *top_iph = ipv6_hdr(skb);
+	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
+	struct tmp_ext *iph_ext;
+
+	extlen = skb_network_header_len(skb) - sizeof(struct ipv6hdr);
+	if (extlen)
+		extlen += sizeof(*iph_ext);
+
+	iph_base = AH_SKB_CB(skb)->tmp;
+	iph_ext = ah_tmp_ext(iph_base);
+	icv = ah_tmp_icv(ahp->ahash, iph_ext, extlen);
+
+	memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
+	memcpy(top_iph, iph_base, IPV6HDR_BASELEN);
+
+	if (extlen) {
+#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
+		memcpy(&top_iph->saddr, iph_ext, extlen);
+#else
+		memcpy(&top_iph->daddr, iph_ext, extlen);
+#endif
+	}
+
+	err = ah->nexthdr;
+
+	kfree(AH_SKB_CB(skb)->tmp);
+	xfrm_output_resume(skb, err);
+}
+
 static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
 {
 	int err;
+	int nfrags;
 	int extlen;
+	u8 *iph_base;
+	u8 *icv;
+	u8 nexthdr;
+	struct sk_buff *trailer;
+	struct crypto_ahash *ahash;
+	struct ahash_request *req;
+	struct scatterlist *sg;
 	struct ipv6hdr *top_iph;
 	struct ip_auth_hdr *ah;
 	struct ah_data *ahp;
-	u8 nexthdr;
-	char tmp_base[8];
-	struct {
-#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
-		struct in6_addr saddr;
-#endif
-		struct in6_addr daddr;
-		char hdrs[0];
-	} *tmp_ext;
+	struct tmp_ext *iph_ext;
+
+	ahp = x->data;
+	ahash = ahp->ahash;
+
+	if ((err = skb_cow_data(skb, 0, &trailer)) < 0)
+		goto out;
+	nfrags = err;
 
 	skb_push(skb, -skb_network_offset(skb));
+	extlen = skb_network_header_len(skb) - sizeof(struct ipv6hdr);
+	if (extlen)
+		extlen += sizeof(*iph_ext);
+
+	err = -ENOMEM;
+	iph_base = ah_alloc_tmp(ahash, nfrags, IPV6HDR_BASELEN + extlen);
+	if (!iph_base)
+		goto out;
+
+	iph_ext = ah_tmp_ext(iph_base);
+	icv = ah_tmp_icv(ahash, iph_ext, extlen);
+	req = ah_tmp_req(ahash, icv);
+	sg = ah_req_sg(ahash, req);
+
+	ah = ip_auth_hdr(skb);
+	memset(ah->auth_data, 0, ahp->icv_trunc_len);
+
 	top_iph = ipv6_hdr(skb);
 	top_iph->payload_len = htons(skb->len - sizeof(*top_iph));
 
@@ -245,31 +380,22 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
 	/* When there are no extension headers, we only need to save the first
 	 * 8 bytes of the base IP header.
 	 */
-	memcpy(tmp_base, top_iph, sizeof(tmp_base));
+	memcpy(iph_base, top_iph, IPV6HDR_BASELEN);
 
-	tmp_ext = NULL;
-	extlen = skb_transport_offset(skb) - sizeof(struct ipv6hdr);
 	if (extlen) {
-		extlen += sizeof(*tmp_ext);
-		tmp_ext = kmalloc(extlen, GFP_ATOMIC);
-		if (!tmp_ext) {
-			err = -ENOMEM;
-			goto error;
-		}
 #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
-		memcpy(tmp_ext, &top_iph->saddr, extlen);
+		memcpy(iph_ext, &top_iph->saddr, extlen);
 #else
-		memcpy(tmp_ext, &top_iph->daddr, extlen);
+		memcpy(iph_ext, &top_iph->daddr, extlen);
 #endif
 		err = ipv6_clear_mutable_options(top_iph,
-						 extlen - sizeof(*tmp_ext) +
+						 extlen - sizeof(*iph_ext) +
 						 sizeof(*top_iph),
 						 XFRM_POLICY_OUT);
 		if (err)
-			goto error_free_iph;
+			goto out_free;
 	}
 
-	ah = ip_auth_hdr(skb);
 	ah->nexthdr = nexthdr;
 
 	top_iph->priority    = 0;
@@ -278,36 +404,80 @@ static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
 	top_iph->flow_lbl[2] = 0;
 	top_iph->hop_limit   = 0;
 
-	ahp = x->data;
 	ah->hdrlen  = (XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len) >> 2) - 2;
 
 	ah->reserved = 0;
 	ah->spi = x->id.spi;
 	ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output);
 
-	spin_lock_bh(&x->lock);
-	err = ah_mac_digest(ahp, skb, ah->auth_data);
-	memcpy(ah->auth_data, ahp->work_icv, ahp->icv_trunc_len);
-	spin_unlock_bh(&x->lock);
+	sg_init_table(sg, nfrags);
+	skb_to_sgvec(skb, sg, 0, skb->len);
+	
+	ahash_request_set_crypt(req, sg, icv, skb->len);
+	ahash_request_set_callback(req, 0, ah6_output_done, skb);
 
-	if (err)
-		goto error_free_iph;
+	AH_SKB_CB(skb)->tmp = iph_base;
+
+	err = crypto_ahash_digest(req);
+	if (err) {
+		if (err == -EINPROGRESS)
+			goto out;
+
+		if (err == -EBUSY)
+			err = NET_XMIT_DROP;
+		goto out_free;
+	}
 
-	memcpy(top_iph, tmp_base, sizeof(tmp_base));
-	if (tmp_ext) {
+	memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
+	memcpy(top_iph, iph_base, IPV6HDR_BASELEN);
+
+	if (extlen) {
 #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
-		memcpy(&top_iph->saddr, tmp_ext, extlen);
+		memcpy(&top_iph->saddr, iph_ext, extlen);
 #else
-		memcpy(&top_iph->daddr, tmp_ext, extlen);
+		memcpy(&top_iph->daddr, iph_ext, extlen);
 #endif
-error_free_iph:
-		kfree(tmp_ext);
 	}
 
-error:
+out_free:
+	kfree(iph_base);
+out:
 	return err;
 }
 
+static void ah6_input_done(struct crypto_async_request *base, int err)
+{
+	u8 *auth_data;
+	u8 *icv;
+	u8 *work_iph;
+	struct sk_buff *skb = base->data;
+	struct xfrm_state *x = xfrm_input_state(skb);
+	struct ah_data *ahp = x->data;
+	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
+	int hdr_len = skb_network_header_len(skb);
+	int ah_hlen = (ah->hdrlen + 2) << 2;
+
+	work_iph = AH_SKB_CB(skb)->tmp;
+	auth_data = ah_tmp_auth(work_iph, hdr_len);
+	icv = ah_tmp_icv(ahp->ahash, auth_data, ahp->icv_trunc_len);
+
+	err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG: 0;
+	if (err)
+		goto out;
+
+	skb->network_header += ah_hlen;
+	memcpy(skb_network_header(skb), work_iph, hdr_len);
+	__skb_pull(skb, ah_hlen + hdr_len);
+	skb_set_transport_header(skb, -hdr_len);
+	
+	err = ah->nexthdr;
+out:
+	kfree(AH_SKB_CB(skb)->tmp);
+	xfrm_input_resume(skb, err);
+}
+
+
+
 static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
 {
 	/*
@@ -325,14 +495,21 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
 	 * There is offset of AH before IPv6 header after the process.
 	 */
 
+	u8 *auth_data;
+	u8 *icv;
+	u8 *work_iph;
+	struct sk_buff *trailer;
+	struct crypto_ahash *ahash;
+	struct ahash_request *req;
+	struct scatterlist *sg;
 	struct ip_auth_hdr *ah;
 	struct ipv6hdr *ip6h;
 	struct ah_data *ahp;
-	unsigned char *tmp_hdr = NULL;
 	u16 hdr_len;
 	u16 ah_hlen;
 	int nexthdr;
-	int err = -EINVAL;
+	int nfrags;
+	int err = -ENOMEM;
 
 	if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr)))
 		goto out;
@@ -345,9 +522,11 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
 
 	skb->ip_summed = CHECKSUM_NONE;
 
-	hdr_len = skb->data - skb_network_header(skb);
+	hdr_len = skb_network_header_len(skb);
 	ah = (struct ip_auth_hdr *)skb->data;
 	ahp = x->data;
+	ahash = ahp->ahash;
+
 	nexthdr = ah->nexthdr;
 	ah_hlen = (ah->hdrlen + 2) << 2;
 
@@ -358,48 +537,67 @@ static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
 	if (!pskb_may_pull(skb, ah_hlen))
 		goto out;
 
-	tmp_hdr = kmemdup(skb_network_header(skb), hdr_len, GFP_ATOMIC);
-	if (!tmp_hdr)
-		goto out;
 	ip6h = ipv6_hdr(skb);
+
+	skb_push(skb, hdr_len);
+
+	if ((err = skb_cow_data(skb, 0, &trailer)) < 0)
+		goto out;
+	nfrags = err;
+
+	work_iph = ah_alloc_tmp(ahash, nfrags, hdr_len + ahp->icv_trunc_len);
+	if (!work_iph)
+		goto out;
+
+	auth_data = ah_tmp_auth(work_iph, hdr_len);
+	icv = ah_tmp_icv(ahash, auth_data, ahp->icv_trunc_len);
+	req = ah_tmp_req(ahash, icv);
+	sg = ah_req_sg(ahash, req);
+
+	memcpy(work_iph, ip6h, hdr_len);
+	memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);
+	memset(ah->auth_data, 0, ahp->icv_trunc_len);
+
 	if (ipv6_clear_mutable_options(ip6h, hdr_len, XFRM_POLICY_IN))
-		goto free_out;
+		goto out_free;
+
 	ip6h->priority    = 0;
 	ip6h->flow_lbl[0] = 0;
 	ip6h->flow_lbl[1] = 0;
 	ip6h->flow_lbl[2] = 0;
 	ip6h->hop_limit   = 0;
 
-	spin_lock(&x->lock);
-	{
-		u8 auth_data[MAX_AH_AUTH_LEN];
+	sg_init_table(sg, nfrags);
+	skb_to_sgvec(skb, sg, 0, skb->len);
+	
+	ahash_request_set_crypt(req, sg, icv, skb->len);
+	ahash_request_set_callback(req, 0, ah6_input_done, skb);
 
-		memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);
-		memset(ah->auth_data, 0, ahp->icv_trunc_len);
-		skb_push(skb, hdr_len);
-		err = ah_mac_digest(ahp, skb, ah->auth_data);
-		if (err)
-			goto unlock;
-		if (memcmp(ahp->work_icv, auth_data, ahp->icv_trunc_len))
-			err = -EBADMSG;
+	AH_SKB_CB(skb)->tmp = work_iph;
+
+	err = crypto_ahash_digest(req);
+	if (err) {
+		if (err == -EINPROGRESS)
+			goto out;
+
+		if (err == -EBUSY)
+			err = NET_XMIT_DROP;
+		goto out_free;
 	}
-unlock:
-	spin_unlock(&x->lock);
 
+	err = memcmp(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG: 0;
 	if (err)
-		goto free_out;
+		goto out_free;
 
 	skb->network_header += ah_hlen;
-	memcpy(skb_network_header(skb), tmp_hdr, hdr_len);
+	memcpy(skb_network_header(skb), work_iph, hdr_len);
 	skb->transport_header = skb->network_header;
 	__skb_pull(skb, ah_hlen + hdr_len);
 
-	kfree(tmp_hdr);
+	err = nexthdr;
 
-	return nexthdr;
-
-free_out:
-	kfree(tmp_hdr);
+out_free:
+	kfree(work_iph);
 out:
 	return err;
 }
@@ -430,7 +628,7 @@ static int ah6_init_state(struct xfrm_state *x)
 {
 	struct ah_data *ahp = NULL;
 	struct xfrm_algo_desc *aalg_desc;
-	struct crypto_hash *tfm;
+	struct crypto_ahash *ahash;
 
 	if (!x->aalg)
 		goto error;
@@ -442,12 +640,12 @@ static int ah6_init_state(struct xfrm_state *x)
 	if (ahp == NULL)
 		return -ENOMEM;
 
-	tfm = crypto_alloc_hash(x->aalg->alg_name, 0, CRYPTO_ALG_ASYNC);
-	if (IS_ERR(tfm))
+	ahash = crypto_alloc_ahash(x->aalg->alg_name, 0, 0);
+	if (IS_ERR(ahash))
 		goto error;
 
-	ahp->tfm = tfm;
-	if (crypto_hash_setkey(tfm, x->aalg->alg_key,
+	ahp->ahash = ahash;
+	if (crypto_ahash_setkey(ahash, x->aalg->alg_key,
 			       (x->aalg->alg_key_len + 7) / 8))
 		goto error;
 
@@ -461,9 +659,9 @@ static int ah6_init_state(struct xfrm_state *x)
 	BUG_ON(!aalg_desc);
 
 	if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
-	    crypto_hash_digestsize(tfm)) {
+	    crypto_ahash_digestsize(ahash)) {
 		printk(KERN_INFO "AH: %s digestsize %u != %hu\n",
-		       x->aalg->alg_name, crypto_hash_digestsize(tfm),
+		       x->aalg->alg_name, crypto_ahash_digestsize(ahash),
 		       aalg_desc->uinfo.auth.icv_fullbits/8);
 		goto error;
 	}
@@ -473,10 +671,6 @@ static int ah6_init_state(struct xfrm_state *x)
 
 	BUG_ON(ahp->icv_trunc_len > MAX_AH_AUTH_LEN);
 
-	ahp->work_icv = kmalloc(ahp->icv_full_len, GFP_KERNEL);
-	if (!ahp->work_icv)
-		goto error;
-
 	x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) +
 					  ahp->icv_trunc_len);
 	switch (x->props.mode) {
@@ -495,8 +689,7 @@ static int ah6_init_state(struct xfrm_state *x)
 
 error:
 	if (ahp) {
-		kfree(ahp->work_icv);
-		crypto_free_hash(ahp->tfm);
+		crypto_free_ahash(ahp->ahash);
 		kfree(ahp);
 	}
 	return -EINVAL;
@@ -509,8 +702,7 @@ static void ah6_destroy(struct xfrm_state *x)
 	if (!ahp)
 		return;
 
-	kfree(ahp->work_icv);
-	crypto_free_hash(ahp->tfm);
+	crypto_free_ahash(ahp->ahash);
 	kfree(ahp);
 }
 
-- 
1.5.4.2


^ permalink raw reply related

* [RFC] [PATCH 6/7] ah: Remove obsolete code
From: Steffen Klassert @ 2009-07-16 11:20 UTC (permalink / raw)
  To: Herbert Xu; +Cc: linux-crypto, netdev
In-Reply-To: <20090716111548.GP20288@secunet.com>

ah4 and ah6 are converted to ahash now, so we can remove the
code for the obsolete hash algorithm.

Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
 include/net/ah.h |   29 +++--------------------------
 1 files changed, 3 insertions(+), 26 deletions(-)

diff --git a/include/net/ah.h b/include/net/ah.h
index 7ac5221..7573a71 100644
--- a/include/net/ah.h
+++ b/include/net/ah.h
@@ -1,44 +1,21 @@
 #ifndef _NET_AH_H
 #define _NET_AH_H
 
-#include <linux/crypto.h>
-#include <net/xfrm.h>
+#include <linux/skbuff.h>
 
 /* This is the maximum truncated ICV length that we know of. */
 #define MAX_AH_AUTH_LEN	12
 
+struct crypto_ahash;
+
 struct ah_data
 {
-	u8			*work_icv;
 	int			icv_full_len;
 	int			icv_trunc_len;
 
-	struct crypto_hash	*tfm;
 	struct crypto_ahash	*ahash;
 };
 
-static inline int ah_mac_digest(struct ah_data *ahp, struct sk_buff *skb,
-				u8 *auth_data)
-{
-	struct hash_desc desc;
-	int err;
-
-	desc.tfm = ahp->tfm;
-	desc.flags = 0;
-
-	memset(auth_data, 0, ahp->icv_trunc_len);
-	err = crypto_hash_init(&desc);
-	if (unlikely(err))
-		goto out;
-	err = skb_icv_walk(skb, &desc, 0, skb->len, crypto_hash_update);
-	if (unlikely(err))
-		goto out;
-	err = crypto_hash_final(&desc, ahp->work_icv);
-
-out:
-	return err;
-}

^ permalink raw reply related

* [RFC] [PATCH 7/7] xfrm: remove skb_icv_walk
From: Steffen Klassert @ 2009-07-16 11:21 UTC (permalink / raw)
  To: Herbert Xu; +Cc: linux-crypto, netdev
In-Reply-To: <20090716111548.GP20288@secunet.com>

The last users of skb_icv_walk are converted to ahash now,
so skb_icv_walk is unused and can be removed.

Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
 include/net/xfrm.h   |    3 --
 net/xfrm/xfrm_algo.c |   78 --------------------------------------------------
 2 files changed, 0 insertions(+), 81 deletions(-)

diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 9e3a3f4..8181541 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -1500,9 +1500,6 @@ struct scatterlist;
 typedef int (icv_update_fn_t)(struct hash_desc *, struct scatterlist *,
 			      unsigned int);
 
-extern int skb_icv_walk(const struct sk_buff *skb, struct hash_desc *tfm,
-			int offset, int len, icv_update_fn_t icv_update);
-
 static inline int xfrm_addr_cmp(xfrm_address_t *a, xfrm_address_t *b,
 				int family)
 {
diff --git a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c
index faf54c6..b393410 100644
--- a/net/xfrm/xfrm_algo.c
+++ b/net/xfrm/xfrm_algo.c
@@ -689,84 +689,6 @@ int xfrm_count_enc_supported(void)
 }
 EXPORT_SYMBOL_GPL(xfrm_count_enc_supported);
 
-/* Move to common area: it is shared with AH. */
-
-int skb_icv_walk(const struct sk_buff *skb, struct hash_desc *desc,
-		 int offset, int len, icv_update_fn_t icv_update)
-{
-	int start = skb_headlen(skb);
-	int i, copy = start - offset;
-	struct sk_buff *frag_iter;
-	struct scatterlist sg;
-	int err;
-
-	/* Checksum header. */
-	if (copy > 0) {
-		if (copy > len)
-			copy = len;
-
-		sg_init_one(&sg, skb->data + offset, copy);
-
-		err = icv_update(desc, &sg, copy);
-		if (unlikely(err))
-			return err;
-
-		if ((len -= copy) == 0)
-			return 0;
-		offset += copy;
-	}
-
-	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-		int end;
-
-		WARN_ON(start > offset + len);
-
-		end = start + skb_shinfo(skb)->frags[i].size;
-		if ((copy = end - offset) > 0) {
-			skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-
-			if (copy > len)
-				copy = len;
-
-			sg_init_table(&sg, 1);
-			sg_set_page(&sg, frag->page, copy,
-				    frag->page_offset + offset-start);
-
-			err = icv_update(desc, &sg, copy);
-			if (unlikely(err))
-				return err;
-
-			if (!(len -= copy))
-				return 0;
-			offset += copy;
-		}
-		start = end;
-	}
-
-	skb_walk_frags(skb, frag_iter) {
-		int end;
-
-		WARN_ON(start > offset + len);
-
-		end = start + frag_iter->len;
-		if ((copy = end - offset) > 0) {
-			if (copy > len)
-				copy = len;
-			err = skb_icv_walk(frag_iter, desc, offset-start,
-					   copy, icv_update);
-			if (unlikely(err))
-				return err;
-			if ((len -= copy) == 0)
-				return 0;
-			offset += copy;
-		}
-		start = end;
-	}
-	BUG_ON(len);
-	return 0;
-}
-EXPORT_SYMBOL_GPL(skb_icv_walk);

^ permalink raw reply related

* Re: [PATCH] net: nf_conntrack_alloc() fixes
From: Patrick McHardy @ 2009-07-16 12:05 UTC (permalink / raw)
  To: Eric Dumazet; +Cc: David Miller, netdev, paulmck
In-Reply-To: <4A5E33D9.2030602@gmail.com>

Eric Dumazet wrote:
> [PATCH] net: nf_conntrack_alloc() fixes
> 
> When a slab cache uses SLAB_DESTROY_BY_RCU, we must be careful when allocating
> objects, since slab allocator could give a freed object still used by lockless
> readers.
> 
> In particular, nf_conntrack RCU lookups rely on ct->tuplehash[xxx].hnnode.next
> being always valid (ie containing a valid 'nulls' value, or a valid pointer to next
> object in hash chain.)
> 
> kmem_cache_zalloc() setups object with NULL values, but a NULL value is not valid
> for ct->tuplehash[xxx].hnnode.next.
> 
> Fix is to call kmem_cache_alloc() and do the zeroing ourself.
> 
> As spotted by Patrick, we also need to make sure lookup keys are committed to
> memory before setting refcount to 1, or a lockless reader could get a reference
> on the old version of the object. Its key re-check could then pass the barrier. 

Looks good to me. Applied, thanks Eric. I'll push it to -stable
with the other fixes in a couple of days.

^ permalink raw reply

* RE: [PATCH] imwc3200: move iwmc3200 SDIO ids to sdio_ids.h
From: Zhu, Yi @ 2009-07-16 12:23 UTC (permalink / raw)
  To: Zhu, Yi, Winkler, Tomas, drzeus-list@drzeus.cx,
	netdev@vger.kernel.org, "linux-w
  Cc: Winkler, Tomas
In-Reply-To: <AFAB8585072C7E48BC5C6F9C87F9B79703BA8388BB@pdsmsx502.ccr.corp.intel.com>

> Subject: RE: [PATCH] imwc3200: move iwmc3200 SDIO ids to sdio_ids.h

BTW, subject should be "iwmc3200".

Thanks,
-yi

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox