diff options
author | Nicolas Dichtel <nicolas.dichtel@6wind.com> | 2015-05-07 05:02:53 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-05-09 22:15:31 -0400 |
commit | 59324cf35aba5336b611074028777838a963d03b (patch) | |
tree | 67e6903c5a0204281060493d301b62640cb9a066 /net/netlink | |
parent | cc3a572fe6cf586f478546215bc5d3694357d71e (diff) |
netlink: allow to listen "all" netns
More accurately, listen all netns that have a nsid assigned into the netns
where the netlink socket is opened.
For this purpose, a netlink socket option is added:
NETLINK_LISTEN_ALL_NSID. When this option is set on a netlink socket, this
socket will receive netlink notifications from all netns that have a nsid
assigned into the netns where the socket has been opened. The nsid is sent
to userland via an anscillary data.
With this patch, a daemon needs only one socket to listen many netns. This
is useful when the number of netns is high.
Because 0 is a valid value for a nsid, the field nsid_is_set indicates if
the field nsid is valid or not. skb->cb is initialized to 0 on skb
allocation, thus we are sure that we will never send a nsid 0 by error to
the userland.
Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com>
Acked-by: Thomas Graf <tgraf@suug.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/netlink')
-rw-r--r-- | net/netlink/af_netlink.c | 52 |
1 files changed, 47 insertions, 5 deletions
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index bf7f56d7a9aa..a5fff75accf8 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c | |||
@@ -83,6 +83,7 @@ struct listeners { | |||
83 | #define NETLINK_F_RECV_PKTINFO 0x2 | 83 | #define NETLINK_F_RECV_PKTINFO 0x2 |
84 | #define NETLINK_F_BROADCAST_SEND_ERROR 0x4 | 84 | #define NETLINK_F_BROADCAST_SEND_ERROR 0x4 |
85 | #define NETLINK_F_RECV_NO_ENOBUFS 0x8 | 85 | #define NETLINK_F_RECV_NO_ENOBUFS 0x8 |
86 | #define NETLINK_F_LISTEN_ALL_NSID 0x10 | ||
86 | 87 | ||
87 | static inline int netlink_is_kernel(struct sock *sk) | 88 | static inline int netlink_is_kernel(struct sock *sk) |
88 | { | 89 | { |
@@ -1932,8 +1933,17 @@ static void do_one_broadcast(struct sock *sk, | |||
1932 | !test_bit(p->group - 1, nlk->groups)) | 1933 | !test_bit(p->group - 1, nlk->groups)) |
1933 | return; | 1934 | return; |
1934 | 1935 | ||
1935 | if (!net_eq(sock_net(sk), p->net)) | 1936 | if (!net_eq(sock_net(sk), p->net)) { |
1936 | return; | 1937 | if (!(nlk->flags & NETLINK_F_LISTEN_ALL_NSID)) |
1938 | return; | ||
1939 | |||
1940 | if (!peernet_has_id(sock_net(sk), p->net)) | ||
1941 | return; | ||
1942 | |||
1943 | if (!file_ns_capable(sk->sk_socket->file, p->net->user_ns, | ||
1944 | CAP_NET_BROADCAST)) | ||
1945 | return; | ||
1946 | } | ||
1937 | 1947 | ||
1938 | if (p->failure) { | 1948 | if (p->failure) { |
1939 | netlink_overrun(sk); | 1949 | netlink_overrun(sk); |
@@ -1959,13 +1969,22 @@ static void do_one_broadcast(struct sock *sk, | |||
1959 | p->failure = 1; | 1969 | p->failure = 1; |
1960 | if (nlk->flags & NETLINK_F_BROADCAST_SEND_ERROR) | 1970 | if (nlk->flags & NETLINK_F_BROADCAST_SEND_ERROR) |
1961 | p->delivery_failure = 1; | 1971 | p->delivery_failure = 1; |
1962 | } else if (p->tx_filter && p->tx_filter(sk, p->skb2, p->tx_data)) { | 1972 | goto out; |
1973 | } | ||
1974 | if (p->tx_filter && p->tx_filter(sk, p->skb2, p->tx_data)) { | ||
1963 | kfree_skb(p->skb2); | 1975 | kfree_skb(p->skb2); |
1964 | p->skb2 = NULL; | 1976 | p->skb2 = NULL; |
1965 | } else if (sk_filter(sk, p->skb2)) { | 1977 | goto out; |
1978 | } | ||
1979 | if (sk_filter(sk, p->skb2)) { | ||
1966 | kfree_skb(p->skb2); | 1980 | kfree_skb(p->skb2); |
1967 | p->skb2 = NULL; | 1981 | p->skb2 = NULL; |
1968 | } else if ((val = netlink_broadcast_deliver(sk, p->skb2)) < 0) { | 1982 | goto out; |
1983 | } | ||
1984 | NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net); | ||
1985 | NETLINK_CB(p->skb2).nsid_is_set = true; | ||
1986 | val = netlink_broadcast_deliver(sk, p->skb2); | ||
1987 | if (val < 0) { | ||
1969 | netlink_overrun(sk); | 1988 | netlink_overrun(sk); |
1970 | if (nlk->flags & NETLINK_F_BROADCAST_SEND_ERROR) | 1989 | if (nlk->flags & NETLINK_F_BROADCAST_SEND_ERROR) |
1971 | p->delivery_failure = 1; | 1990 | p->delivery_failure = 1; |
@@ -1974,6 +1993,7 @@ static void do_one_broadcast(struct sock *sk, | |||
1974 | p->delivered = 1; | 1993 | p->delivered = 1; |
1975 | p->skb2 = NULL; | 1994 | p->skb2 = NULL; |
1976 | } | 1995 | } |
1996 | out: | ||
1977 | sock_put(sk); | 1997 | sock_put(sk); |
1978 | } | 1998 | } |
1979 | 1999 | ||
@@ -2202,6 +2222,16 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname, | |||
2202 | break; | 2222 | break; |
2203 | } | 2223 | } |
2204 | #endif /* CONFIG_NETLINK_MMAP */ | 2224 | #endif /* CONFIG_NETLINK_MMAP */ |
2225 | case NETLINK_LISTEN_ALL_NSID: | ||
2226 | if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_BROADCAST)) | ||
2227 | return -EPERM; | ||
2228 | |||
2229 | if (val) | ||
2230 | nlk->flags |= NETLINK_F_LISTEN_ALL_NSID; | ||
2231 | else | ||
2232 | nlk->flags &= ~NETLINK_F_LISTEN_ALL_NSID; | ||
2233 | err = 0; | ||
2234 | break; | ||
2205 | default: | 2235 | default: |
2206 | err = -ENOPROTOOPT; | 2236 | err = -ENOPROTOOPT; |
2207 | } | 2237 | } |
@@ -2268,6 +2298,16 @@ static void netlink_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb) | |||
2268 | put_cmsg(msg, SOL_NETLINK, NETLINK_PKTINFO, sizeof(info), &info); | 2298 | put_cmsg(msg, SOL_NETLINK, NETLINK_PKTINFO, sizeof(info), &info); |
2269 | } | 2299 | } |
2270 | 2300 | ||
2301 | static void netlink_cmsg_listen_all_nsid(struct sock *sk, struct msghdr *msg, | ||
2302 | struct sk_buff *skb) | ||
2303 | { | ||
2304 | if (!NETLINK_CB(skb).nsid_is_set) | ||
2305 | return; | ||
2306 | |||
2307 | put_cmsg(msg, SOL_NETLINK, NETLINK_LISTEN_ALL_NSID, sizeof(int), | ||
2308 | &NETLINK_CB(skb).nsid); | ||
2309 | } | ||
2310 | |||
2271 | static int netlink_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) | 2311 | static int netlink_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) |
2272 | { | 2312 | { |
2273 | struct sock *sk = sock->sk; | 2313 | struct sock *sk = sock->sk; |
@@ -2421,6 +2461,8 @@ static int netlink_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, | |||
2421 | 2461 | ||
2422 | if (nlk->flags & NETLINK_F_RECV_PKTINFO) | 2462 | if (nlk->flags & NETLINK_F_RECV_PKTINFO) |
2423 | netlink_cmsg_recv_pktinfo(msg, skb); | 2463 | netlink_cmsg_recv_pktinfo(msg, skb); |
2464 | if (nlk->flags & NETLINK_F_LISTEN_ALL_NSID) | ||
2465 | netlink_cmsg_listen_all_nsid(sk, msg, skb); | ||
2424 | 2466 | ||
2425 | memset(&scm, 0, sizeof(scm)); | 2467 | memset(&scm, 0, sizeof(scm)); |
2426 | scm.creds = *NETLINK_CREDS(skb); | 2468 | scm.creds = *NETLINK_CREDS(skb); |