Skip to content

Commit

Permalink
genetlink: make netns aware
Browse files Browse the repository at this point in the history
This makes generic netlink network namespace aware. No
generic netlink families except for the controller family
are made namespace aware, they need to be checked one by
one and then set the family->netnsok member to true.

A new function genlmsg_multicast_netns() is introduced to
allow sending a multicast message in a given namespace,
for example when it applies to an object that lives in
that namespace, a new function genlmsg_multicast_allns()
to send a message to all network namespaces (for objects
that do not have an associated netns).

The function genlmsg_multicast() is changed to multicast
the message in just init_net, which is currently correct
for all generic netlink families since they only work in
init_net right now. Some will later want to work in all
net namespaces because they do not care about the netns
at all -- those will have to be converted to use one of
the new functions genlmsg_multicast_allns() or
genlmsg_multicast_netns() whenever they are made netns
aware in some way.

After this patch families can easily decide whether or
not they should be available in all net namespaces. Many
genl families us it for objects not related to networking
and should therefore be available in all namespaces, but
that will have to be done on a per family basis.

Note that this doesn't touch on the checkpoint/restart
problem where network namespaces could be used, genl
families and multicast groups are numbered globally and
I see no easy way of changing that, especially since it
must be possible to multicast to all network namespaces
for those families that do not care about netns.

Signed-off-by: Johannes Berg <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
jmberg authored and davem330 committed Jul 12, 2009
1 parent 11a28d3 commit 134e637
Show file tree
Hide file tree
Showing 9 changed files with 223 additions and 63 deletions.
2 changes: 1 addition & 1 deletion fs/dlm/netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ static int send_data(struct sk_buff *skb)
return rv;
}

return genlmsg_unicast(skb, listener_nlpid);
return genlmsg_unicast(&init_net, skb, listener_nlpid);
}

static int user_cmd(struct sk_buff *skb, struct genl_info *info)
Expand Down
66 changes: 59 additions & 7 deletions include/net/genetlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <linux/genetlink.h>
#include <net/netlink.h>
#include <net/net_namespace.h>

/**
* struct genl_multicast_group - generic netlink multicast group
Expand All @@ -27,6 +28,8 @@ struct genl_multicast_group
* @name: name of family
* @version: protocol version
* @maxattr: maximum number of attributes supported
* @netnsok: set to true if the family can handle network
* namespaces and should be presented in all of them
* @attrbuf: buffer to store parsed attributes
* @ops_list: list of all assigned operations
* @family_list: family list
Expand All @@ -39,6 +42,7 @@ struct genl_family
char name[GENL_NAMSIZ];
unsigned int version;
unsigned int maxattr;
bool netnsok;
struct nlattr ** attrbuf; /* private */
struct list_head ops_list; /* private */
struct list_head family_list; /* private */
Expand All @@ -62,8 +66,32 @@ struct genl_info
struct genlmsghdr * genlhdr;
void * userhdr;
struct nlattr ** attrs;
#ifdef CONFIG_NET_NS
struct net * _net;
#endif
};

#ifdef CONFIG_NET_NS
static inline struct net *genl_info_net(struct genl_info *info)
{
return info->_net;
}

static inline void genl_info_net_set(struct genl_info *info, struct net *net)
{
info->_net = net;
}
#else
static inline struct net *genl_info_net(struct genl_info *info)
{
return &init_net;
}

static inline void genl_info_net_set(struct genl_info *info, struct net *net)
{
}
#endif

/**
* struct genl_ops - generic netlink operations
* @cmd: command identifier
Expand Down Expand Up @@ -98,8 +126,6 @@ extern int genl_register_mc_group(struct genl_family *family,
extern void genl_unregister_mc_group(struct genl_family *family,
struct genl_multicast_group *grp);

extern struct sock *genl_sock;

/**
* genlmsg_put - Add generic netlink header to netlink message
* @skb: socket buffer holding the message
Expand Down Expand Up @@ -170,7 +196,21 @@ static inline void genlmsg_cancel(struct sk_buff *skb, void *hdr)
}

/**
* genlmsg_multicast - multicast a netlink message
* genlmsg_multicast_netns - multicast a netlink message to a specific netns
* @net: the net namespace
* @skb: netlink message as socket buffer
* @pid: own netlink pid to avoid sending to yourself
* @group: multicast group id
* @flags: allocation flags
*/
static inline int genlmsg_multicast_netns(struct net *net, struct sk_buff *skb,
u32 pid, unsigned int group, gfp_t flags)
{
return nlmsg_multicast(net->genl_sock, skb, pid, group, flags);
}

/**
* genlmsg_multicast - multicast a netlink message to the default netns
* @skb: netlink message as socket buffer
* @pid: own netlink pid to avoid sending to yourself
* @group: multicast group id
Expand All @@ -179,17 +219,29 @@ static inline void genlmsg_cancel(struct sk_buff *skb, void *hdr)
static inline int genlmsg_multicast(struct sk_buff *skb, u32 pid,
unsigned int group, gfp_t flags)
{
return nlmsg_multicast(genl_sock, skb, pid, group, flags);
return genlmsg_multicast_netns(&init_net, skb, pid, group, flags);
}

/**
* genlmsg_multicast_allns - multicast a netlink message to all net namespaces
* @skb: netlink message as socket buffer
* @pid: own netlink pid to avoid sending to yourself
* @group: multicast group id
* @flags: allocation flags
*
* This function must hold the RTNL or rcu_read_lock().
*/
int genlmsg_multicast_allns(struct sk_buff *skb, u32 pid,
unsigned int group, gfp_t flags);

/**
* genlmsg_unicast - unicast a netlink message
* @skb: netlink message as socket buffer
* @pid: netlink pid of the destination socket
*/
static inline int genlmsg_unicast(struct sk_buff *skb, u32 pid)
static inline int genlmsg_unicast(struct net *net, struct sk_buff *skb, u32 pid)
{
return nlmsg_unicast(genl_sock, skb, pid);
return nlmsg_unicast(net->genl_sock, skb, pid);
}

/**
Expand All @@ -199,7 +251,7 @@ static inline int genlmsg_unicast(struct sk_buff *skb, u32 pid)
*/
static inline int genlmsg_reply(struct sk_buff *skb, struct genl_info *info)
{
return genlmsg_unicast(skb, info->snd_pid);
return genlmsg_unicast(genl_info_net(info), skb, info->snd_pid);
}

/**
Expand Down
2 changes: 2 additions & 0 deletions include/net/net_namespace.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ struct net_device;
struct sock;
struct ctl_table_header;
struct net_generic;
struct sock;

struct net {
atomic_t count; /* To decided when the network
Expand Down Expand Up @@ -57,6 +58,7 @@ struct net {
spinlock_t rules_mod_lock;

struct sock *rtnl; /* rtnetlink socket */
struct sock *genl_sock;

struct netns_core core;
struct netns_mib mib;
Expand Down
10 changes: 5 additions & 5 deletions kernel/taskstats.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ static int prepare_reply(struct genl_info *info, u8 cmd, struct sk_buff **skbp,
/*
* Send taskstats data in @skb to listener with nl_pid @pid
*/
static int send_reply(struct sk_buff *skb, pid_t pid)
static int send_reply(struct sk_buff *skb, struct genl_info *info)
{
struct genlmsghdr *genlhdr = nlmsg_data(nlmsg_hdr(skb));
void *reply = genlmsg_data(genlhdr);
Expand All @@ -120,7 +120,7 @@ static int send_reply(struct sk_buff *skb, pid_t pid)
return rc;
}

return genlmsg_unicast(skb, pid);
return genlmsg_reply(skb, info);
}

/*
Expand Down Expand Up @@ -150,7 +150,7 @@ static void send_cpu_listeners(struct sk_buff *skb,
if (!skb_next)
break;
}
rc = genlmsg_unicast(skb_cur, s->pid);
rc = genlmsg_unicast(&init_net, skb_cur, s->pid);
if (rc == -ECONNREFUSED) {
s->valid = 0;
delcount++;
Expand Down Expand Up @@ -418,7 +418,7 @@ static int cgroupstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
goto err;
}

rc = send_reply(rep_skb, info->snd_pid);
rc = send_reply(rep_skb, info);

err:
fput_light(file, fput_needed);
Expand Down Expand Up @@ -487,7 +487,7 @@ static int taskstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
} else
goto err;

return send_reply(rep_skb, info->snd_pid);
return send_reply(rep_skb, info);
err:
nlmsg_free(rep_skb);
return rc;
Expand Down
2 changes: 1 addition & 1 deletion net/irda/irnetlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ static int irda_nl_get_mode(struct sk_buff *skb, struct genl_info *info)

genlmsg_end(msg, hdr);

return genlmsg_unicast(msg, info->snd_pid);
return genlmsg_reply(msg, info);

err_out:
nlmsg_free(msg);
Expand Down
2 changes: 1 addition & 1 deletion net/netfilter/ipvs/ip_vs_ctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -3231,7 +3231,7 @@ static int ip_vs_genl_get_cmd(struct sk_buff *skb, struct genl_info *info)
}

genlmsg_end(msg, reply);
ret = genlmsg_unicast(msg, info->snd_pid);
ret = genlmsg_reply(msg, info);
goto out;

nla_put_failure:
Expand Down
Loading

0 comments on commit 134e637

Please sign in to comment.