Commit fa4d3c62 authored by Pavel Emelyanov's avatar Pavel Emelyanov Committed by David S. Miller

[NETNS]: Udp sockets per-net lookup.

Add the net parameter to udp_get_port family of calls and
udp_lookup one and use it to filter sockets.
Signed-off-by: default avatarPavel Emelyanov <xemul@openvz.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d86e0dac
...@@ -130,14 +130,14 @@ EXPORT_SYMBOL(sysctl_udp_wmem_min); ...@@ -130,14 +130,14 @@ EXPORT_SYMBOL(sysctl_udp_wmem_min);
atomic_t udp_memory_allocated; atomic_t udp_memory_allocated;
EXPORT_SYMBOL(udp_memory_allocated); EXPORT_SYMBOL(udp_memory_allocated);
static inline int __udp_lib_lport_inuse(__u16 num, static inline int __udp_lib_lport_inuse(struct net *net, __u16 num,
const struct hlist_head udptable[]) const struct hlist_head udptable[])
{ {
struct sock *sk; struct sock *sk;
struct hlist_node *node; struct hlist_node *node;
sk_for_each(sk, node, &udptable[num & (UDP_HTABLE_SIZE - 1)]) sk_for_each(sk, node, &udptable[num & (UDP_HTABLE_SIZE - 1)])
if (sk->sk_hash == num) if (sk->sk_net == net && sk->sk_hash == num)
return 1; return 1;
return 0; return 0;
} }
...@@ -159,6 +159,7 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum, ...@@ -159,6 +159,7 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
struct hlist_head *head; struct hlist_head *head;
struct sock *sk2; struct sock *sk2;
int error = 1; int error = 1;
struct net *net = sk->sk_net;
write_lock_bh(&udp_hash_lock); write_lock_bh(&udp_hash_lock);
...@@ -198,7 +199,7 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum, ...@@ -198,7 +199,7 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
/* 2nd pass: find hole in shortest hash chain */ /* 2nd pass: find hole in shortest hash chain */
rover = best; rover = best;
for (i = 0; i < (1 << 16) / UDP_HTABLE_SIZE; i++) { for (i = 0; i < (1 << 16) / UDP_HTABLE_SIZE; i++) {
if (! __udp_lib_lport_inuse(rover, udptable)) if (! __udp_lib_lport_inuse(net, rover, udptable))
goto gotit; goto gotit;
rover += UDP_HTABLE_SIZE; rover += UDP_HTABLE_SIZE;
if (rover > high) if (rover > high)
...@@ -218,6 +219,7 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum, ...@@ -218,6 +219,7 @@ int __udp_lib_get_port(struct sock *sk, unsigned short snum,
sk_for_each(sk2, node, head) sk_for_each(sk2, node, head)
if (sk2->sk_hash == snum && if (sk2->sk_hash == snum &&
sk2 != sk && sk2 != sk &&
sk2->sk_net == net &&
(!sk2->sk_reuse || !sk->sk_reuse) && (!sk2->sk_reuse || !sk->sk_reuse) &&
(!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if
|| sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && || sk2->sk_bound_dev_if == sk->sk_bound_dev_if) &&
...@@ -261,9 +263,9 @@ static inline int udp_v4_get_port(struct sock *sk, unsigned short snum) ...@@ -261,9 +263,9 @@ static inline int udp_v4_get_port(struct sock *sk, unsigned short snum)
/* UDP is nearly always wildcards out the wazoo, it makes no sense to try /* UDP is nearly always wildcards out the wazoo, it makes no sense to try
* harder than this. -DaveM * harder than this. -DaveM
*/ */
static struct sock *__udp4_lib_lookup(__be32 saddr, __be16 sport, static struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
__be32 daddr, __be16 dport, __be16 sport, __be32 daddr, __be16 dport,
int dif, struct hlist_head udptable[]) int dif, struct hlist_head udptable[])
{ {
struct sock *sk, *result = NULL; struct sock *sk, *result = NULL;
struct hlist_node *node; struct hlist_node *node;
...@@ -274,7 +276,8 @@ static struct sock *__udp4_lib_lookup(__be32 saddr, __be16 sport, ...@@ -274,7 +276,8 @@ static struct sock *__udp4_lib_lookup(__be32 saddr, __be16 sport,
sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) {
struct inet_sock *inet = inet_sk(sk); struct inet_sock *inet = inet_sk(sk);
if (sk->sk_hash == hnum && !ipv6_only_sock(sk)) { if (sk->sk_net == net && sk->sk_hash == hnum &&
!ipv6_only_sock(sk)) {
int score = (sk->sk_family == PF_INET ? 1 : 0); int score = (sk->sk_family == PF_INET ? 1 : 0);
if (inet->rcv_saddr) { if (inet->rcv_saddr) {
if (inet->rcv_saddr != daddr) if (inet->rcv_saddr != daddr)
...@@ -361,8 +364,8 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct hlist_head udptable[]) ...@@ -361,8 +364,8 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct hlist_head udptable[])
int harderr; int harderr;
int err; int err;
sk = __udp4_lib_lookup(iph->daddr, uh->dest, iph->saddr, uh->source, sk = __udp4_lib_lookup(skb->dev->nd_net, iph->daddr, uh->dest,
skb->dev->ifindex, udptable ); iph->saddr, uh->source, skb->dev->ifindex, udptable);
if (sk == NULL) { if (sk == NULL) {
ICMP_INC_STATS_BH(ICMP_MIB_INERRORS); ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
return; /* No socket for error */ return; /* No socket for error */
...@@ -1185,8 +1188,8 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], ...@@ -1185,8 +1188,8 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
if (rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST)) if (rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST))
return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable); return __udp4_lib_mcast_deliver(skb, uh, saddr, daddr, udptable);
sk = __udp4_lib_lookup(saddr, uh->source, daddr, uh->dest, sk = __udp4_lib_lookup(skb->dev->nd_net, saddr, uh->source, daddr,
inet_iif(skb), udptable); uh->dest, inet_iif(skb), udptable);
if (sk != NULL) { if (sk != NULL) {
int ret = 0; int ret = 0;
......
...@@ -56,7 +56,8 @@ static inline int udp_v6_get_port(struct sock *sk, unsigned short snum) ...@@ -56,7 +56,8 @@ static inline int udp_v6_get_port(struct sock *sk, unsigned short snum)
return udp_get_port(sk, snum, ipv6_rcv_saddr_equal); return udp_get_port(sk, snum, ipv6_rcv_saddr_equal);
} }
static struct sock *__udp6_lib_lookup(struct in6_addr *saddr, __be16 sport, static struct sock *__udp6_lib_lookup(struct net *net,
struct in6_addr *saddr, __be16 sport,
struct in6_addr *daddr, __be16 dport, struct in6_addr *daddr, __be16 dport,
int dif, struct hlist_head udptable[]) int dif, struct hlist_head udptable[])
{ {
...@@ -69,7 +70,8 @@ static struct sock *__udp6_lib_lookup(struct in6_addr *saddr, __be16 sport, ...@@ -69,7 +70,8 @@ static struct sock *__udp6_lib_lookup(struct in6_addr *saddr, __be16 sport,
sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) { sk_for_each(sk, node, &udptable[hnum & (UDP_HTABLE_SIZE - 1)]) {
struct inet_sock *inet = inet_sk(sk); struct inet_sock *inet = inet_sk(sk);
if (sk->sk_hash == hnum && sk->sk_family == PF_INET6) { if (sk->sk_net == net && sk->sk_hash == hnum &&
sk->sk_family == PF_INET6) {
struct ipv6_pinfo *np = inet6_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk);
int score = 0; int score = 0;
if (inet->dport) { if (inet->dport) {
...@@ -233,7 +235,7 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, ...@@ -233,7 +235,7 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
struct sock *sk; struct sock *sk;
int err; int err;
sk = __udp6_lib_lookup(daddr, uh->dest, sk = __udp6_lib_lookup(skb->dev->nd_net, daddr, uh->dest,
saddr, uh->source, inet6_iif(skb), udptable); saddr, uh->source, inet6_iif(skb), udptable);
if (sk == NULL) if (sk == NULL)
return; return;
...@@ -478,7 +480,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], ...@@ -478,7 +480,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[],
* check socket cache ... must talk to Alan about his plans * check socket cache ... must talk to Alan about his plans
* for sock caches... i'll skip this for now. * for sock caches... i'll skip this for now.
*/ */
sk = __udp6_lib_lookup(saddr, uh->source, sk = __udp6_lib_lookup(skb->dev->nd_net, saddr, uh->source,
daddr, uh->dest, inet6_iif(skb), udptable); daddr, uh->dest, inet6_iif(skb), udptable);
if (sk == NULL) { if (sk == NULL) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment