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;