소스 검색

ipv4: Add a socket release callback for datagram sockets

This implements a socket release callback function to check
if the socket cached route got invalid during the time
we owned the socket. The function is used from udp, raw
and ping sockets.

Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Steffen Klassert 13 년 전
부모
커밋
8141ed9fce
5개의 변경된 파일30개의 추가작업 그리고 0개의 파일을 삭제
  1. 2 0
      include/net/ip.h
  2. 25 0
      net/ipv4/datagram.c
  3. 1 0
      net/ipv4/ping.c
  4. 1 0
      net/ipv4/raw.c
  5. 1 0
      net/ipv4/udp.c

+ 2 - 0
include/net/ip.h

@@ -143,6 +143,8 @@ static inline struct sk_buff *ip_finish_skb(struct sock *sk, struct flowi4 *fl4)
 extern int		ip4_datagram_connect(struct sock *sk, 
 extern int		ip4_datagram_connect(struct sock *sk, 
 					     struct sockaddr *uaddr, int addr_len);
 					     struct sockaddr *uaddr, int addr_len);
 
 
+extern void ip4_datagram_release_cb(struct sock *sk);
+
 struct ip_reply_arg {
 struct ip_reply_arg {
 	struct kvec iov[1];   
 	struct kvec iov[1];   
 	int	    flags;
 	int	    flags;

+ 25 - 0
net/ipv4/datagram.c

@@ -85,3 +85,28 @@ int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
 	return err;
 	return err;
 }
 }
 EXPORT_SYMBOL(ip4_datagram_connect);
 EXPORT_SYMBOL(ip4_datagram_connect);
+
+void ip4_datagram_release_cb(struct sock *sk)
+{
+	const struct inet_sock *inet = inet_sk(sk);
+	const struct ip_options_rcu *inet_opt;
+	__be32 daddr = inet->inet_daddr;
+	struct flowi4 fl4;
+	struct rtable *rt;
+
+	if (! __sk_dst_get(sk) || __sk_dst_check(sk, 0))
+		return;
+
+	rcu_read_lock();
+	inet_opt = rcu_dereference(inet->inet_opt);
+	if (inet_opt && inet_opt->opt.srr)
+		daddr = inet_opt->opt.faddr;
+	rt = ip_route_output_ports(sock_net(sk), &fl4, sk, daddr,
+				   inet->inet_saddr, inet->inet_dport,
+				   inet->inet_sport, sk->sk_protocol,
+				   RT_CONN_FLAGS(sk), sk->sk_bound_dev_if);
+	if (!IS_ERR(rt))
+		__sk_dst_set(sk, &rt->dst);
+	rcu_read_unlock();
+}
+EXPORT_SYMBOL_GPL(ip4_datagram_release_cb);

+ 1 - 0
net/ipv4/ping.c

@@ -738,6 +738,7 @@ struct proto ping_prot = {
 	.recvmsg =	ping_recvmsg,
 	.recvmsg =	ping_recvmsg,
 	.bind =		ping_bind,
 	.bind =		ping_bind,
 	.backlog_rcv =	ping_queue_rcv_skb,
 	.backlog_rcv =	ping_queue_rcv_skb,
+	.release_cb =	ip4_datagram_release_cb,
 	.hash =		ping_v4_hash,
 	.hash =		ping_v4_hash,
 	.unhash =	ping_v4_unhash,
 	.unhash =	ping_v4_unhash,
 	.get_port =	ping_v4_get_port,
 	.get_port =	ping_v4_get_port,

+ 1 - 0
net/ipv4/raw.c

@@ -894,6 +894,7 @@ struct proto raw_prot = {
 	.recvmsg	   = raw_recvmsg,
 	.recvmsg	   = raw_recvmsg,
 	.bind		   = raw_bind,
 	.bind		   = raw_bind,
 	.backlog_rcv	   = raw_rcv_skb,
 	.backlog_rcv	   = raw_rcv_skb,
+	.release_cb	   = ip4_datagram_release_cb,
 	.hash		   = raw_hash_sk,
 	.hash		   = raw_hash_sk,
 	.unhash		   = raw_unhash_sk,
 	.unhash		   = raw_unhash_sk,
 	.obj_size	   = sizeof(struct raw_sock),
 	.obj_size	   = sizeof(struct raw_sock),

+ 1 - 0
net/ipv4/udp.c

@@ -1952,6 +1952,7 @@ struct proto udp_prot = {
 	.recvmsg	   = udp_recvmsg,
 	.recvmsg	   = udp_recvmsg,
 	.sendpage	   = udp_sendpage,
 	.sendpage	   = udp_sendpage,
 	.backlog_rcv	   = __udp_queue_rcv_skb,
 	.backlog_rcv	   = __udp_queue_rcv_skb,
+	.release_cb	   = ip4_datagram_release_cb,
 	.hash		   = udp_lib_hash,
 	.hash		   = udp_lib_hash,
 	.unhash		   = udp_lib_unhash,
 	.unhash		   = udp_lib_unhash,
 	.rehash		   = udp_v4_rehash,
 	.rehash		   = udp_v4_rehash,