Re: EAGAIN and Linux 2.6 IPsec patch

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

 



On Mon, Sep 29, 2003 at 09:25:04AM -0400, D. Hugh Redelmeier wrote:
> 
> Here's an extract from an strace of a ping to a new IP address, with
> OE on 2.6.  Note: no packet has been sent
> 
> socket(PF_INET, SOCK_RAW, IPPROTO_ICMP) = 3
> socket(PF_INET, SOCK_DGRAM, IPPROTO_IP) = 4
> connect(4, {sin_family=AF_INET, sin_port=htons(1025), sin_addr=inet_addr("216.239.41.99")}}, 16) = -1 EAGAIN (Resource temporarily unavailable)
> 
> To me, this EAGAIN is very odd.  Notice that the program is not yet
> attempting to send a packet.  (Will this generate an ACQUIRE?)

OK, this looks like a bug that is independent of the packet queueing issue.

TCP/UDP connects do a route/IPSEC lookup to determine information
about the connection.  The IPSEC lookup can fail with EAGAIN if the
policy is in place without any SAs.

Since connect already has an O_NONBLOCK bit we should make it try
harder if it is clear.

The following (untested) patch tries to do that.

Cheers,
-- 
Debian GNU/Linux 3.0 is out! ( http://www.debian.org/ )
Email:  Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
Index: kernel-source-2.5/include/net/ipv6.h
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/include/net/ipv6.h,v
retrieving revision 1.1.1.10
diff -u -r1.1.1.10 ipv6.h
--- kernel-source-2.5/include/net/ipv6.h	27 Sep 2003 00:02:02 -0000	1.1.1.10
+++ kernel-source-2.5/include/net/ipv6.h	30 Sep 2003 11:29:14 -0000
@@ -355,7 +355,7 @@
 
 extern int			ip6_dst_lookup(struct sock *sk,
 					       struct dst_entry **dst,
-					       struct flowi *fl);
+					       struct flowi *fl, int block);
 
 /*
  *	skb processing functions
Index: kernel-source-2.5/include/net/route.h
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/include/net/route.h,v
retrieving revision 1.1.1.5
diff -u -r1.1.1.5 route.h
--- kernel-source-2.5/include/net/route.h	17 Jun 2003 04:19:37 -0000	1.1.1.5
+++ kernel-source-2.5/include/net/route.h	30 Sep 2003 11:26:58 -0000
@@ -148,7 +148,8 @@
 
 static inline int ip_route_connect(struct rtable **rp, u32 dst,
 				   u32 src, u32 tos, int oif, u8 protocol,
-				   u16 sport, u16 dport, struct sock *sk)
+				   u16 sport, u16 dport, struct sock *sk,
+				   int block)
 {
 	struct flowi fl = { .oif = oif,
 			    .nl_u = { .ip4_u = { .daddr = dst,
@@ -169,7 +170,7 @@
 		ip_rt_put(*rp);
 		*rp = NULL;
 	}
-	return ip_route_output_flow(rp, &fl, sk, 0);
+	return ip_route_output_flow(rp, &fl, sk, block);
 }
 
 static inline int ip_route_newports(struct rtable **rp, u16 sport, u16 dport,
Index: kernel-source-2.5/include/net/sock.h
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/include/net/sock.h,v
retrieving revision 1.1.1.9
diff -u -r1.1.1.9 sock.h
--- kernel-source-2.5/include/net/sock.h	2 Jul 2003 20:51:53 -0000	1.1.1.9
+++ kernel-source-2.5/include/net/sock.h	30 Sep 2003 10:40:14 -0000
@@ -402,7 +402,7 @@
 					long timeout);
 	int			(*connect)(struct sock *sk,
 				        struct sockaddr *uaddr, 
-					int addr_len);
+					int addr_len, int flags);
 	int			(*disconnect)(struct sock *sk, int flags);
 
 	struct sock *		(*accept) (struct sock *sk, int flags, int *err);
Index: kernel-source-2.5/include/net/tcp.h
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/include/net/tcp.h,v
retrieving revision 1.1.1.9
diff -u -r1.1.1.9 tcp.h
--- kernel-source-2.5/include/net/tcp.h	11 Jul 2003 10:53:05 -0000	1.1.1.9
+++ kernel-source-2.5/include/net/tcp.h	30 Sep 2003 11:11:02 -0000
@@ -852,7 +852,7 @@
 
 extern int			tcp_v4_connect(struct sock *sk,
 					       struct sockaddr *uaddr,
-					       int addr_len);
+					       int addr_len, int flags);
 
 extern int			tcp_connect(struct sock *sk);
 
Index: kernel-source-2.5/include/net/transp_v6.h
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/include/net/transp_v6.h,v
retrieving revision 1.1.1.3
diff -u -r1.1.1.3 transp_v6.h
--- kernel-source-2.5/include/net/transp_v6.h	27 May 2003 08:38:39 -0000	1.1.1.3
+++ kernel-source-2.5/include/net/transp_v6.h	30 Sep 2003 11:16:35 -0000
@@ -28,7 +28,7 @@
 
 extern int				udpv6_connect(struct sock *sk,
 						      struct sockaddr *uaddr,
-						      int addr_len);
+						      int addr_len, int flags);
 
 extern int			datagram_recv_ctl(struct sock *sk,
 						  struct msghdr *msg,
Index: kernel-source-2.5/include/net/udp.h
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/include/net/udp.h,v
retrieving revision 1.1.1.5
diff -u -r1.1.1.5 udp.h
--- kernel-source-2.5/include/net/udp.h	17 Jun 2003 04:20:20 -0000	1.1.1.5
+++ kernel-source-2.5/include/net/udp.h	30 Sep 2003 10:47:09 -0000
@@ -65,7 +65,7 @@
 
 extern void	udp_err(struct sk_buff *, u32);
 extern int	udp_connect(struct sock *sk,
-			    struct sockaddr *usin, int addr_len);
+			    struct sockaddr *usin, int addr_len, int flags);
 
 extern int	udp_sendmsg(struct kiocb *iocb, struct sock *sk,
 			    struct msghdr *msg, int len);
Index: kernel-source-2.5/net/ipv4/af_inet.c
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/ipv4/af_inet.c,v
retrieving revision 1.1.1.11
diff -u -r1.1.1.11 af_inet.c
--- kernel-source-2.5/net/ipv4/af_inet.c	27 Sep 2003 00:02:03 -0000	1.1.1.11
+++ kernel-source-2.5/net/ipv4/af_inet.c	30 Sep 2003 10:41:56 -0000
@@ -558,7 +558,7 @@
 
 	if (!inet_sk(sk)->num && inet_autobind(sk))
 		return -EAGAIN;
-	return sk->sk_prot->connect(sk, (struct sockaddr *)uaddr, addr_len);
+	return sk->sk_prot->connect(sk, uaddr, addr_len, flags);
 }
 
 static long inet_wait_for_connect(struct sock *sk, long timeo)
@@ -619,7 +619,7 @@
 		if (sk->sk_state != TCP_CLOSE)
 			goto out;
 
-		err = sk->sk_prot->connect(sk, uaddr, addr_len);
+		err = sk->sk_prot->connect(sk, uaddr, addr_len, flags);
 		if (err < 0)
 			goto out;
 
Index: kernel-source-2.5/net/ipv4/tcp_ipv4.c
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/ipv4/tcp_ipv4.c,v
retrieving revision 1.1.1.12
diff -u -r1.1.1.12 tcp_ipv4.c
--- kernel-source-2.5/net/ipv4/tcp_ipv4.c	28 Sep 2003 04:44:22 -0000	1.1.1.12
+++ kernel-source-2.5/net/ipv4/tcp_ipv4.c	30 Sep 2003 11:27:42 -0000
@@ -747,7 +747,8 @@
 }
 
 /* This will initiate an outgoing connection. */
-int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len,
+		   int flags)
 {
 	struct inet_opt *inet = inet_sk(sk);
 	struct tcp_opt *tp = tcp_sk(sk);
@@ -773,7 +774,8 @@
 	tmp = ip_route_connect(&rt, nexthop, inet->saddr,
 			       RT_CONN_FLAGS(sk), sk->sk_bound_dev_if,
 			       IPPROTO_TCP,
-			       inet->sport, usin->sin_port, sk);
+			       inet->sport, usin->sin_port, sk,
+			       !(flags&O_NONBLOCK));
 	if (tmp < 0)
 		return tmp;
 
@@ -1878,7 +1880,7 @@
 			       RT_TOS(inet->tos) | sk->sk_localroute,
 			       sk->sk_bound_dev_if,
 			       IPPROTO_TCP,
-			       inet->sport, inet->dport, sk);
+			       inet->sport, inet->dport, sk, 0);
 	if (err)
 		return err;
 
Index: kernel-source-2.5/net/ipv4/udp.c
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/ipv4/udp.c,v
retrieving revision 1.1.1.13
diff -u -r1.1.1.13 udp.c
--- kernel-source-2.5/net/ipv4/udp.c	28 Sep 2003 04:44:22 -0000	1.1.1.13
+++ kernel-source-2.5/net/ipv4/udp.c	30 Sep 2003 11:28:29 -0000
@@ -856,7 +856,8 @@
 	return -EAGAIN;	
 }
 
-int udp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+int udp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len,
+		int flags)
 {
 	struct inet_opt *inet = inet_sk(sk);
 	struct sockaddr_in *usin = (struct sockaddr_in *) uaddr;
@@ -885,7 +886,8 @@
 	err = ip_route_connect(&rt, usin->sin_addr.s_addr, saddr,
 			       RT_CONN_FLAGS(sk), oif,
 			       IPPROTO_UDP,
-			       inet->sport, usin->sin_port, sk);
+			       inet->sport, usin->sin_port, sk,
+			       !(flags&O_NONBLOCK));
 	if (err)
 		return err;
 	if ((rt->rt_flags & RTCF_BROADCAST) && !sock_flag(sk, SOCK_BROADCAST)) {
Index: kernel-source-2.5/net/ipv6/icmp.c
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/ipv6/icmp.c,v
retrieving revision 1.1.1.11
diff -u -r1.1.1.11 icmp.c
--- kernel-source-2.5/net/ipv6/icmp.c	27 Sep 2003 00:02:03 -0000	1.1.1.11
+++ kernel-source-2.5/net/ipv6/icmp.c	30 Sep 2003 11:00:06 -0000
@@ -366,7 +366,7 @@
 	if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst))
 		fl.oif = np->mcast_oif;
 
-	err = ip6_dst_lookup(sk, &dst, &fl);
+	err = ip6_dst_lookup(sk, &dst, &fl, 0);
 	if (err)
 		goto out;
 
@@ -449,7 +449,7 @@
 	if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst))
 		fl.oif = np->mcast_oif;
 
-	err = ip6_dst_lookup(sk, &dst, &fl);
+	err = ip6_dst_lookup(sk, &dst, &fl, 0);
 	if (err)
 		goto out;
 
Index: kernel-source-2.5/net/ipv6/ip6_output.c
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/ipv6/ip6_output.c,v
retrieving revision 1.1.1.13
diff -u -r1.1.1.13 ip6_output.c
--- kernel-source-2.5/net/ipv6/ip6_output.c	27 Sep 2003 00:02:03 -0000	1.1.1.13
+++ kernel-source-2.5/net/ipv6/ip6_output.c	30 Sep 2003 11:29:43 -0000
@@ -1136,7 +1136,8 @@
 	return err;
 }
 
-int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl)
+int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl,
+		   int block)
 {
 	int err = 0;
 
@@ -1193,7 +1194,7 @@
 			goto out_err_release;
 		}
 	}
-	if ((err = xfrm_lookup(dst, fl, sk, 0)) < 0) {
+	if ((err = xfrm_lookup(dst, fl, sk, block)) < 0) {
 		err = -ENETUNREACH;
 		goto out_err_release;
         }
Index: kernel-source-2.5/net/ipv6/raw.c
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/ipv6/raw.c,v
retrieving revision 1.1.1.11
diff -u -r1.1.1.11 raw.c
--- kernel-source-2.5/net/ipv6/raw.c	28 Sep 2003 04:44:23 -0000	1.1.1.11
+++ kernel-source-2.5/net/ipv6/raw.c	30 Sep 2003 11:01:15 -0000
@@ -658,7 +658,7 @@
 	if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst))
 		fl.oif = np->mcast_oif;
 
-	err = ip6_dst_lookup(sk, &dst, &fl);
+	err = ip6_dst_lookup(sk, &dst, &fl, !(msg->msg_flags&MSG_DONTWAIT));
 	if (err)
 		goto out;
 
Index: kernel-source-2.5/net/ipv6/tcp_ipv6.c
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/ipv6/tcp_ipv6.c,v
retrieving revision 1.1.1.13
diff -u -r1.1.1.13 tcp_ipv6.c
--- kernel-source-2.5/net/ipv6/tcp_ipv6.c	28 Sep 2003 04:44:23 -0000	1.1.1.13
+++ kernel-source-2.5/net/ipv6/tcp_ipv6.c	30 Sep 2003 11:31:23 -0000
@@ -537,7 +537,7 @@
 }
 
 static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, 
-			  int addr_len)
+			  int addr_len, int flags)
 {
 	struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr;
 	struct inet_opt *inet = inet_sk(sk);
@@ -630,7 +630,8 @@
 		tp->af_specific = &ipv6_mapped;
 		sk->sk_backlog_rcv = tcp_v4_do_rcv;
 
-		err = tcp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin));
+		err = tcp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin),
+				     flags);
 
 		if (err) {
 			tp->ext_header_len = exthdrlen;
@@ -663,7 +664,7 @@
 		ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
 	}
 
-	err = ip6_dst_lookup(sk, &dst, &fl);
+	err = ip6_dst_lookup(sk, &dst, &fl, !(flags & O_NONBLOCK));
 
 	if (err)
 		goto failure;
@@ -783,7 +784,7 @@
 			fl.fl_ip_dport = inet->dport;
 			fl.fl_ip_sport = inet->sport;
 
-			if ((err = ip6_dst_lookup(sk, &dst, &fl))) {
+			if ((err = ip6_dst_lookup(sk, &dst, &fl, 0))) {
 				sk->sk_err_soft = -err;
 				goto out;
 			}
@@ -885,7 +886,7 @@
 			ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
 		}
 
-		err = ip6_dst_lookup(sk, &dst, &fl);
+		err = ip6_dst_lookup(sk, &dst, &fl, 0);
 		if (err)
 			goto done;
 	}
@@ -1014,7 +1015,7 @@
 	fl.fl_ip_sport = t1->source;
 
 	/* sk = NULL, but it is safe for now. RST socket required. */
-	if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
+	if (!ip6_dst_lookup(NULL, &buff->dst, &fl, 0)) {
 		ip6_xmit(NULL, buff, &fl, NULL, 0);
 		TCP_INC_STATS_BH(TcpOutSegs);
 		TCP_INC_STATS_BH(TcpOutRsts);
@@ -1075,7 +1076,7 @@
 	fl.fl_ip_dport = t1->dest;
 	fl.fl_ip_sport = t1->source;
 
-	if (!ip6_dst_lookup(NULL, &buff->dst, &fl)) {
+	if (!ip6_dst_lookup(NULL, &buff->dst, &fl, 0)) {
 		ip6_xmit(NULL, buff, &fl, NULL, 0);
 		TCP_INC_STATS_BH(TcpOutSegs);
 		return;
@@ -1321,7 +1322,7 @@
 		fl.fl_ip_dport = req->rmt_port;
 		fl.fl_ip_sport = inet_sk(sk)->sport;
 
-		if (ip6_dst_lookup(sk, &dst, &fl))
+		if (ip6_dst_lookup(sk, &dst, &fl, 0))
 			goto out;
 	} 
 
@@ -1718,7 +1719,7 @@
 			ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
 		}
 
-		err = ip6_dst_lookup(sk, &dst, &fl);
+		err = ip6_dst_lookup(sk, &dst, &fl, 0);
 
 		if (err) {
 			sk->sk_route_caps = 0;
@@ -1760,7 +1761,7 @@
 	dst = __sk_dst_check(sk, np->dst_cookie);
 
 	if (dst == NULL) {
-		int err = ip6_dst_lookup(sk, &dst, &fl);
+		int err = ip6_dst_lookup(sk, &dst, &fl, 0);
 
 		if (err) {
 			sk->sk_err_soft = -err;
Index: kernel-source-2.5/net/ipv6/udp.c
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/ipv6/udp.c,v
retrieving revision 1.1.1.11
diff -u -r1.1.1.11 udp.c
--- kernel-source-2.5/net/ipv6/udp.c	28 Sep 2003 04:44:23 -0000	1.1.1.11
+++ kernel-source-2.5/net/ipv6/udp.c	30 Sep 2003 10:52:04 -0000
@@ -201,7 +201,8 @@
  *
  */
 
-int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
+int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len,
+		  int flags)
 {
 	struct sockaddr_in6	*usin = (struct sockaddr_in6 *) uaddr;
 	struct inet_opt      	*inet = inet_sk(sk);
@@ -216,7 +217,7 @@
 	if (usin->sin6_family == AF_INET) {
 		if (__ipv6_only_sock(sk))
 			return -EAFNOSUPPORT;
-		err = udp_connect(sk, uaddr, addr_len);
+		err = udp_connect(sk, uaddr, addr_len, flags);
 		goto ipv4_connected;
 	}
 
@@ -259,7 +260,8 @@
 		sin.sin_addr.s_addr = daddr->s6_addr32[3];
 		sin.sin_port = usin->sin6_port;
 
-		err = udp_connect(sk, (struct sockaddr*) &sin, sizeof(sin));
+		err = udp_connect(sk, (struct sockaddr*) &sin, sizeof(sin),
+				  flags);
 
 ipv4_connected:
 		if (err)
@@ -330,7 +332,7 @@
 		ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
 	}
 
-	err = ip6_dst_lookup(sk, &dst, &fl);
+	err = ip6_dst_lookup(sk, &dst, &fl, !(flags&O_NONBLOCK));
 	if (err)
 		goto out;
 
@@ -921,7 +923,7 @@
 	if (!fl.oif && ipv6_addr_is_multicast(&fl.fl6_dst))
 		fl.oif = np->mcast_oif;
 
-	err = ip6_dst_lookup(sk, &dst, &fl);
+	err = ip6_dst_lookup(sk, &dst, &fl, !(msg->msg_flags&MSG_DONTWAIT));
 	if (err)
 		goto out;
 
Index: kernel-source-2.5/net/sctp/socket.c
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/sctp/socket.c,v
retrieving revision 1.1.1.13
diff -u -r1.1.1.13 socket.c
--- kernel-source-2.5/net/sctp/socket.c	27 Sep 2003 00:02:03 -0000	1.1.1.13
+++ kernel-source-2.5/net/sctp/socket.c	30 Sep 2003 10:40:58 -0000
@@ -1868,7 +1868,7 @@
  * len: the size of the address.
  */
 SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr,
-			     int addr_len)
+			     int addr_len, int flags)
 {
 	struct sctp_opt *sp;
 	struct sctp_endpoint *ep;

[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux 802.1Q VLAN]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Git]     [Bugtraq]     [Yosemite News and Information]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux PCI]     [Linux Admin]     [Samba]

  Powered by Linux